summaryrefslogtreecommitdiff
path: root/sqmail-4.3.07/src/qmail-qmaint.c
diff options
context:
space:
mode:
authorErwin Hoffmann <feh@fehcom.de>2024-01-14 17:55:54 +0100
committerErwin Hoffmann <feh@fehcom.de>2024-01-14 17:55:54 +0100
commita293489ee83c8b05d845a162dc2a4de026f3775d (patch)
treed50ab15afde698ad2d32bfc251753e5e89204f25 /sqmail-4.3.07/src/qmail-qmaint.c
s/qmail 4.3.07
Diffstat (limited to 'sqmail-4.3.07/src/qmail-qmaint.c')
-rw-r--r--sqmail-4.3.07/src/qmail-qmaint.c594
1 files changed, 594 insertions, 0 deletions
diff --git a/sqmail-4.3.07/src/qmail-qmaint.c b/sqmail-4.3.07/src/qmail-qmaint.c
new file mode 100644
index 0000000..e83ab6f
--- /dev/null
+++ b/sqmail-4.3.07/src/qmail-qmaint.c
@@ -0,0 +1,594 @@
+/*
+ Based on an implementation of queue-fix 1.2 by Eric Huss
+*/
+#include <unistd.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <grp.h>
+#include "stralloc.h"
+#include "direntry.h"
+#include "fmt.h"
+#include "fmtqfn.h"
+#include "error.h"
+#include "buffer.h"
+#include "getln.h"
+#include "str.h"
+#include "open.h"
+#include "fifo.h"
+#include "scan.h"
+#include "readsubdir.h"
+#include "logmsg.h"
+#include "exit.h"
+#include "auto_qmail.h"
+#include "auto_split.h"
+#include "auto_uids.h"
+
+#define WHO "qmail-qmaint"
+
+stralloc queue_dir = {0}; /*the root queue dir with trailing slash*/
+stralloc check_dir = {0}; /*the current directory being checked*/
+stralloc temp_dirname = {0}; /*temporary used for checking directories */
+stralloc temp_filename = {0}; /*temporary used for checking individuals*/
+stralloc old_name = {0}; /*used in rename*/
+stralloc new_name = {0}; /*used in rename*/
+stralloc mess_dir = {0}; /*used for renaming in mess dir*/
+stralloc query = {0}; /*used in interactive query function*/
+
+char strnum[FMT_ULONG];
+int flag_interactive = 0;
+int flag_dircreate = 0;
+int flag_filecreate = 0;
+int flag_permfix = 0;
+int flag_namefix = 0;
+int flag_delete = 0;
+
+int qmailq_uid;
+int qmails_uid;
+int qmailr_uid;
+int qmail_gid;
+int split_num;
+
+void die_make(char *name)
+{
+ logmsg(WHO,111,ERROR,B("Failed to make: ",name));
+}
+
+void die_user(char *user)
+{
+ logmsg(WHO,111,ERROR,B("Failed to determine uid of: ",user));
+}
+
+void die_group(char *group)
+{
+ logmsg(WHO,111,ERROR,B("Failed to determine gid of: ",group));
+}
+
+void die_check()
+{
+ logmsg(WHO,111,ERROR,"Failed while checking directory structure. \nEnsure the given queue exists and you have permission to access it.");
+}
+
+void die_recon()
+{
+ logmsg(WHO,110,ERROR,"Failed to reconstruct queue. \nEnsure the queue exists and you have permission to modify it.");
+}
+
+void die_nomem()
+{
+ logmsg(WHO,110,ERROR,"Out of memory.");
+}
+
+/*returns 1==yes, 0==no*/
+
+int confirm()
+{
+ int match;
+
+ if (getln(buffer_0,&query,&match,'\n')) return 0;
+ if (!match) return 0;
+ if (query.s[0] == 'y' || query.s[0] == 'Y' || query.s[0] == '\n') return 1;
+ return 0;
+}
+
+/*gid may be -1 on files for "unknown*/
+
+#define DIRS logmsg(WHO,0,WARN,"It looks like some directories don't exist, should I create them? (Y/n)")
+#define FILES logmsg(WHO,0,WARN,"It looks like some files don't exist, should I create them? (Y/n)")
+
+#define PERMS logmsg(WHO,0,WARN,B("It looks like permissions are wrong for ",name," should I fix them? (Y/n)"))
+#define CPERMS logmsg(WHO,0,WARN,B("Changing permissions: ",name," => ",pnum))
+
+#define OWNER logmsg(WHO,0,WARN,B("It looks like ownerships are wrong for ",name," should I fix them? (Y/n)"))
+#define COWNER logmsg(WHO,0,WARN,B("Changing ownership: ",name," => ",unum,"/",gnum))
+
+int check_item(char *name,int uid,int gid,int perm,char type,int size)
+{
+ struct stat st;
+ int fd;
+ char num[12];
+ char unum[12];
+ char gnum[12];
+ char pnum[12];
+
+ /*check for existence and proper credentials*/
+
+ strnum[fmt_ulong(unum,uid)] = 0;
+ strnum[fmt_ulong(gnum,gid)] = 0;
+ strnum[fmt_ulong(pnum,perm)] = 0;
+
+ switch (type) {
+ case 'd': /*directory*/
+ if (stat(name,&st)) {
+ if (errno != ENOENT) return -1;
+ if (!flag_dircreate && flag_interactive) {
+ DIRS; if (!confirm()) return -1;
+ flag_dircreate = 1;
+ }
+ /*create it*/
+ logmsg(WHO,0,INFO,B("Creating directory: ",name));
+ if (mkdir(name,perm)) die_make(name);
+ CPERMS; if (chmod(name,perm)) die_make(name);
+ COWNER; if (chown(name,uid,gid)) die_make(name);
+ return 0;
+ }
+ /*check the values*/
+ if (st.st_uid != uid || st.st_gid != gid) {
+ if (!flag_permfix && flag_interactive) { OWNER; if (!confirm()) return -1; flag_permfix = 1; }
+ COWNER; if (chown(name,uid,gid)) die_make(name);
+ }
+ if ((st.st_mode & 07777) != perm) {
+ if (!flag_permfix && flag_interactive) { PERMS; if (!confirm()) return -1; flag_permfix = 1; }
+ CPERMS; if (chmod(name,perm)) die_make(name);
+ }
+ return 0;
+ case 'f': /*regular file*/
+ if (stat(name,&st)) return -1;
+ /*check the values*/
+ if (st.st_uid != uid || (st.st_gid != gid && gid != -1)) {
+ if (!flag_permfix && flag_interactive) { OWNER; if (!confirm()) return -1; flag_permfix = 1; }
+ COWNER; if (chown(name,uid,gid)) die_make(name);
+ }
+ if ((st.st_mode & 07777) != perm) {
+ if (!flag_permfix && flag_interactive) { PERMS; if (!confirm()) return -1; flag_permfix = 1; }
+ CPERMS; if (chmod(name,perm)) die_make(name);
+ }
+ return 0;
+ case 'z': /*regular file with a size*/
+ if (stat(name,&st)) {
+ if (errno != ENOENT) return -1;
+ if (!flag_filecreate && flag_interactive) {
+ FILES; if (!confirm()) return -1;
+ flag_filecreate = 1;
+ }
+ /*create it*/
+
+ strnum[fmt_ulong(num,size)] = 0;
+ logmsg(WHO,0,INFO,B("Creating: ",name," with size ",num));
+ fd = open_trunc(name);
+ if (fd == -1) die_make(name);
+ while (size--) { if (write(fd,"",1)!=1) die_make(name); }
+ close(fd);
+ CPERMS; if (chmod(name,perm)) die_make(name);
+ COWNER; if (chown(name,uid,gid)) die_make(name);
+ return 0;
+ }
+ /*check the values*/
+ if (st.st_uid != uid || (st.st_gid != gid && gid != -1)) {
+ if (!flag_permfix && flag_interactive) { OWNER; if (!confirm()) return -1; flag_permfix = 1; }
+ COWNER; if (chown(name,uid,gid)) die_make(name);
+ }
+ if ((st.st_mode & 07777) != perm) {
+ if (!flag_permfix && flag_interactive) { PERMS; if (!confirm()) return -1; flag_permfix = 1; }
+ CPERMS; if (chmod(name,perm)) die_make(name);
+ }
+ if (st.st_size != size) {
+ logmsg(WHO,0,WARN,B("File ",name," has not the right size. I will not fix it, please investigate."));
+ }
+ return 0;
+ case 'p': /*a named pipe*/
+ if (stat(name,&st)) {
+ if (errno != ENOENT) return -1;
+ if (!flag_filecreate && flag_interactive) {
+ FILES; if (!confirm()) return -1;
+ flag_filecreate = 1;
+ }
+ /*create it*/
+ logmsg(WHO,INFO,0,B("Creating fifo: ",name));
+ if (fifo_make(name,perm)) die_make(name);
+ CPERMS; if (chmod(name,perm)) die_make(name);
+ COWNER; if (chown(name,uid,gid)) die_make(name);
+ return 0;
+ }
+ /*check the values*/
+ if (st.st_uid != uid || (st.st_gid != gid && gid != -1)) {
+ if (!flag_permfix && flag_interactive) { OWNER; if (!confirm()) return -1; flag_permfix = 1; }
+ COWNER; if (chown(name,uid,gid)) die_make(name);
+ }
+ if ((st.st_mode & 07777) != perm) {
+ if (!flag_permfix && flag_interactive) { PERMS; if (!confirm()) return -1; flag_permfix = 1; }
+ CPERMS; if (chmod(name,perm)) die_make(name);
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
+int check_files(char * directory,int uid,int gid,int perm)
+{
+ DIR *dir;
+ direntry *d;
+
+ dir = opendir(directory);
+
+ if (!dir) return -1;
+ while ((d = readdir(dir))) {
+ if (d->d_name[0] == '.') continue;
+ if (!stralloc_copys(&temp_filename,directory)) die_nomem();
+ if (!stralloc_append(&temp_filename,"/")) die_nomem();
+ if (!stralloc_cats(&temp_filename,d->d_name)) die_nomem();
+ if (!stralloc_0(&temp_filename)) die_nomem();
+ if (check_item(temp_filename.s,uid,gid,perm,'f',0)) { closedir(dir); return -1; }
+ }
+ closedir(dir);
+ return 0;
+}
+
+void warn_files(char * directory)
+{
+ DIR *dir;
+ direntry *d;
+ int found = 0;
+
+ dir = opendir(directory);
+ if (!dir) return;
+
+ while ((d = readdir(dir))) {
+ if (d->d_name[0] == '.') continue;
+ found = 1;
+ break;
+ }
+
+ closedir(dir);
+
+ if (found)
+ logmsg(WHO,0,WARN,B("Found files in ",directory," that shouldn't be there. I will not remove them. You should consider checking it out."));
+}
+
+int check_splits(char * directory,int dir_uid,int dir_gid,int dir_perm,int file_gid,int file_perm)
+{
+ DIR *dir;
+ direntry *d;
+ int i;
+
+ for (i = 0; i < split_num ; i++) {
+ strnum[fmt_ulong(strnum,i)] = 0;
+ if (!stralloc_copys(&temp_dirname,directory)) die_nomem();
+ if (!stralloc_append(&temp_dirname,"/")) die_nomem();
+ if (!stralloc_cats(&temp_dirname,strnum)) die_nomem();
+ if (!stralloc_0(&temp_dirname)) die_nomem();
+
+ /*check the split dir*/
+ if (check_item(temp_dirname.s,dir_uid,dir_gid,dir_perm,'d',0)) return -1;
+
+ /*check its contents*/
+ dir = opendir(temp_dirname.s);
+ if (!dir) return -1;
+ while ((d = readdir(dir))) {
+ if (d->d_name[0] == '.') continue;
+ if (!stralloc_copys(&temp_filename,temp_dirname.s)) die_nomem();
+ if (!stralloc_append(&temp_filename,"/")) die_nomem();
+ if (!stralloc_cats(&temp_filename,d->d_name)) die_nomem();
+ if (!stralloc_0(&temp_filename)) die_nomem();
+ if (check_item(temp_filename.s,dir_uid,file_gid,file_perm,'f',0)) { closedir(dir); return -1; }
+ }
+ closedir(dir);
+ }
+
+ return 0;
+}
+
+int rename_mess(char *dir, char *part, char *new_part, char *old_filename, char *new_filename)
+{
+
+ if (flag_interactive && !flag_namefix) {
+ logmsg(WHO,0,INFO,"It looks like some files need to be renamed, should I rename them? (Y/n)\n");
+ if (!confirm()) return -1;
+ flag_namefix = 1;
+ }
+
+ /*prepare the old filename*/
+ if (!stralloc_copy(&old_name,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&old_name,dir)) die_nomem();
+ if (!stralloc_cats(&old_name,part)) die_nomem();
+ if (!stralloc_append(&old_name,"/")) die_nomem();
+ if (!stralloc_cats(&old_name,old_filename)) die_nomem();
+ if (!stralloc_0(&old_name)) die_nomem();
+
+ /*prepare the new filename*/
+ if (!stralloc_copy(&new_name,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&new_name,dir)) die_nomem();
+ if (!stralloc_cats(&new_name,new_part)) die_nomem();
+ if (!stralloc_append(&new_name,"/")) die_nomem();
+ if (!stralloc_cats(&new_name,new_filename)) die_nomem();
+ if (!stralloc_0(&new_name)) die_nomem();
+
+ logmsg(WHO,0,INFO,B("Renaming ",old_name.s," to ",new_name.s));
+ if (rename(old_name.s,new_name.s)) {
+ if (errno != ENOENT) return -1;
+ }
+
+ return 0;
+}
+
+int fix_part(char *part)
+{
+ DIR *dir;
+ direntry *d;
+ struct stat st;
+ char inode[FMT_ULONG];
+ char new_part[FMT_ULONG];
+ int old_inode;
+ int part_num;
+ int correct_part_num;
+
+ scan_uint(part,&part_num);
+
+ if (!stralloc_copy(&mess_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&mess_dir,"mess/")) die_nomem();
+ if (!stralloc_cats(&mess_dir,part)) die_nomem();
+ if (!stralloc_0(&mess_dir)) die_nomem();
+
+ dir = opendir(mess_dir.s);
+ if (!dir) return -1;
+
+ while ((d = readdir(dir))) {
+ if (d->d_name[0] == '.') continue;
+ /*check from mess*/
+ if (!stralloc_copys(&temp_filename,mess_dir.s)) die_nomem();
+ if (!stralloc_append(&temp_filename,"/")) die_nomem();
+ if (!stralloc_cats(&temp_filename,d->d_name)) die_nomem();
+ if (!stralloc_0(&temp_filename)) die_nomem();
+ if (stat(temp_filename.s,&st)) { closedir(dir); return -1; }
+
+ /*check that filename == inode number*/
+ /*check that inode%auto_split == part_num*/
+ scan_uint(d->d_name,&old_inode);
+ correct_part_num = st.st_ino % split_num;
+ if (st.st_ino != old_inode || part_num != correct_part_num) {
+ /*rename*/
+ inode[fmt_ulong(inode,st.st_ino)] = 0;
+ new_part[fmt_ulong(new_part,correct_part_num)] = 0;
+ if (rename_mess("mess/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; }
+ if (rename_mess("info/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; }
+ if (rename_mess("local/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; }
+ if (rename_mess("remote/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; }
+ if (rename_mess("todo/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; }
+ if (rename_mess("intd/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; }
+
+ if (rename_mess("bounce","","",d->d_name,inode)) { closedir(dir); return -1; }
+ }
+ }
+
+ closedir(dir);
+ return 0;
+}
+
+int fix_names()
+{
+ int i;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"mess")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+
+ for (i = 0; i < split_num; i++) {
+ strnum[fmt_ulong(strnum,i)] = 0;
+ if (fix_part(strnum)) return -1;
+ }
+
+ return 0;
+}
+
+int check_dirs()
+{
+ /*check root existence*/
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1;
+
+ /*check the bigtodo queue */
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"info")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1;
+ if (check_splits(check_dir.s,qmails_uid,qmail_gid,0700,qmail_gid,0600)) return -1;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"mess")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1;
+ if (check_splits(check_dir.s,qmailq_uid,qmail_gid,0750,-1,0644)) return -1;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"remote")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1;
+ if (check_splits(check_dir.s,qmails_uid,qmail_gid,0700,qmail_gid,0600)) return -1;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"local")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1;
+ if (check_splits(check_dir.s,qmails_uid,qmail_gid,0700,qmail_gid,0600)) return -1;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"intd")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmailq_uid,qmail_gid,0700,'d',0)) return -1;
+ if (check_splits(check_dir.s,qmailq_uid,qmail_gid,0700,qmail_gid,0600)) return -1;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"todo")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1;
+ if (check_splits(check_dir.s,qmailq_uid,qmail_gid,0750,-1,0644)) return -1;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"dkim")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1;
+ if (check_splits(check_dir.s,qmailq_uid,qmail_gid,0750,qmail_gid,0644)) return -1;
+
+ /*check the others*/
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"bounce")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1;
+ if (check_files(check_dir.s,qmails_uid,qmail_gid,0600)) return -1;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"pid")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmailq_uid,qmail_gid,0700,'d',0)) return -1;
+
+ warn_files(check_dir.s);
+
+ /*lock has special files that must exist*/
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"lock")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"lock/sendmutex")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmails_uid,qmail_gid,0600,'z',0)) return -1;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"lock/tcpto")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmailr_uid,qmail_gid,0644,'z',1024)) return -1;
+
+ if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem();
+ if (!stralloc_cats(&check_dir,"lock/trigger")) die_nomem();
+ if (!stralloc_0(&check_dir)) die_nomem();
+ if (check_item(check_dir.s,qmails_uid,qmail_gid,0622,'p',0)) return -1;
+
+ return 0;
+}
+
+/* stolen from qmail-send */
+
+stralloc fn = {0};
+
+void fnmake_init() { while (!stralloc_ready(&fn,FMTQFN)) die_nomem(); }
+void fnmake_local(unsigned long id) { fn.len = fmtqfn(fn.s,"local/",id,1); }
+void fnmake_remote(unsigned long id) { fn.len = fmtqfn(fn.s,"remote/",id,1); }
+void fnmake_mess(unsigned long id) { fn.len = fmtqfn(fn.s,"mess/",id,1); }
+void fnmake_dkim(unsigned long id) { fn.len = fmtqfn(fn.s,"dkim/",id,1); }
+void fnmake_info(unsigned long id) { fn.len = fmtqfn(fn.s,"info/",id,1); }
+void fnmake_bounce(unsigned long id) { fn.len = fmtqfn(fn.s,"bounce/",id,0); }
+
+void warn_unlink(unsigned long id)
+{
+ char foo[FMT_ULONG];
+ foo[fmt_ulong(foo,id)] = 0;
+ logmsg(WHO,99,WARN,B("no such file to unlink #",foo));
+}
+
+void err_unlink(unsigned long id)
+{
+ char foo[FMT_ULONG];
+ foo[fmt_ulong(foo,id)] = 0;
+ logmsg(WHO,100,ERROR,B("trouble with unlinking #",foo));
+}
+
+void err_chdir()
+{
+ logmsg(WHO,110,FATAL,"unable to chdir");
+}
+
+int delete_msg(unsigned long id)
+{
+ struct stat st;
+ int bounce = 1;
+
+ if (chdir(auto_qmail) == -1) err_chdir();
+ if (chdir("queue") == -1) err_chdir();
+ fnmake_init();
+
+ fnmake_mess(id); // regular message pre-processed
+ if (stat(fn.s,&st) == -1) err_unlink(id);
+ else bounce = 0;
+ if (!bounce && unlink(fn.s) == -1)
+ if (errno != ENOENT) err_unlink(id);
+
+ fnmake_info(id); // not delivered yet
+ if (!stat(fn.s,&st))
+ if (unlink(fn.s) == -1)
+ if (errno != ENOENT) err_unlink(id);
+
+ if (bounce) {
+ fnmake_bounce(id);
+ if (!stat(fn.s,&st)) { warn_unlink(id); return 1; }
+ if (unlink(fn.s) == -1)
+ if (errno != ENOENT) err_unlink(id);
+ }
+
+ fnmake_remote(id);
+ if (!stat(fn.s,&st))
+ if (unlink(fn.s) == -1)
+ if (errno != ENOENT) err_unlink(id);
+
+ fnmake_local(id);
+ if (!stat(fn.s,&st))
+ if (unlink(fn.s) == -1)
+ if (errno != ENOENT) err_unlink(id);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ char *mess = 0;
+ unsigned long id = 0;
+
+ if (argc > 1) {
+ if (!str_diff(argv[1],"-i")) {
+ flag_interactive = 1;
+ } else if (!str_diff(argv[1],"-d")) {
+ if (!argv[2]) logmsg(WHO,111,USAGE,"qmail-qmaint [-i] || [-d messid]");
+ mess = argv[2];
+ flag_delete = 1;
+ scan_ulong(mess,&id);
+ }
+ }
+
+ if (!stralloc_copys(&queue_dir,auto_qmail)) die_nomem();
+ if (!stralloc_cats(&queue_dir,"/queue/")) die_nomem();
+
+ logmsg(WHO,0,INFO,B("Checking s/qmail queue at: ",auto_qmail,"/queue/"));
+
+ /* get constants */
+
+ qmailq_uid = auto_uidq;
+ qmails_uid = auto_uids;
+ qmailr_uid = auto_uidr;
+ qmail_gid = auto_gidq;
+ split_num = auto_split;
+
+ /*check that all the proper directories exist with proper credentials*/
+
+ if (check_dirs()) die_check();
+
+ if (flag_delete) {
+ if (!delete_msg(id))
+ logmsg(WHO,0,INFO,B("file ",mess," from queue deleted."));
+ } else
+ if (fix_names()) die_check();
+
+ logmsg(WHO,0,INFO,"done.");
+
+ _exit (0);
+}