diff options
Diffstat (limited to 'sqmail-4.3.07/src/qmail-todo.c')
-rw-r--r-- | sqmail-4.3.07/src/qmail-todo.c | 642 |
1 files changed, 0 insertions, 642 deletions
diff --git a/sqmail-4.3.07/src/qmail-todo.c b/sqmail-4.3.07/src/qmail-todo.c deleted file mode 100644 index 6b6e1d4..0000000 --- a/sqmail-4.3.07/src/qmail-todo.c +++ /dev/null @@ -1,642 +0,0 @@ -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include "alloc.h" -#include "auto_qmail.h" -#include "byte.h" -#include "constmap.h" -#include "control.h" -#include "direntry.h" -#include "error.h" -#include "exit.h" -#include "fmt.h" -#include "fmtqfn.h" -#include "getln.h" -#include "open.h" -#include "ndelay.h" -#include "now.h" -#include "readsubdir.h" -#include "buffer.h" -#include "scan.h" -#include "select.h" -#include "str.h" -#include "sig.h" -#include "stralloc.h" -#include "trigger.h" -#include "qsutil.h" -#include "sendtodo.h" -#include "qmail.h" - -stralloc percenthack = {0}; -struct constmap mappercenthack; -stralloc locals = {0}; -struct constmap maplocals; -stralloc vdoms = {0}; -struct constmap mapvdoms; -stralloc envnoathost = {0}; - -char strnum[FMT_ULONG]; - -/* XXX not good, if qmail-send.c changes this has to be updated */ -#define CHANNELS 2 -char *chanaddr[CHANNELS] = { "local/", "remote/" }; - -datetime_sec recent; -int flagquitasap = 0; - -void sendlog1(char *x); -void sendlog3(char *x,char *y,char *z); - -void sigterm(void) -{ - if (flagquitasap == 0) - sendlog1("status: qmail-todo stop processing asap\n"); - flagquitasap = 1; -} - -int flagreadasap = 0; void sighup(void) { flagreadasap = 1; } -int flagsendalive = 1; void senddied(void) { flagsendalive = 0; } - -void cleandied() -{ - sendlog1("alert: qmail-todo lost connection to qmail-clean ... exiting\n"); - flagquitasap = 1; -} - - -/* this file is not so long ------------------------------------- FILENAMES */ - -stralloc fn = {0}; - -void fnmake_init(void) -{ - while (!stralloc_ready(&fn,FMTQFN)) nomem(); -} - -void fnmake_info(unsigned long id) { fn.len = fmtqfn(fn.s,"info/",id,1); } -void fnmake_todo(unsigned long id) { fn.len = fmtqfn(fn.s,"todo/",id,1); } -void fnmake_mess(unsigned long id) { fn.len = fmtqfn(fn.s,"mess/",id,1); } -void fnmake_chanaddr(unsigned long id,int c) { fn.len = fmtqfn(fn.s,chanaddr[c],id,1); } - - -/* this file is not so long ------------------------------------- REWRITING */ - -stralloc rwline = {0}; - -/* 1 if by land, 2 if by sea, 0 if out of memory. not allowed to barf. */ -/* may trash recip. must set up rwline, between a T and a \0. */ - -int rewrite(char *recip) -{ - int i; - int j; - char *x; - static stralloc addr = {0}; - int at; - - if (!stralloc_copys(&rwline,"T")) return 0; - if (!stralloc_copys(&addr,recip)) return 0; - - i = byte_rchr(addr.s,addr.len,'@'); - if (i == addr.len) { - if (!stralloc_cats(&addr,"@")) return 0; - if (!stralloc_cat(&addr,&envnoathost)) return 0; - } - - while (constmap(&mappercenthack,addr.s + i + 1,addr.len - i - 1)) { - j = byte_rchr(addr.s,i,'%'); - if (j == i) break; - addr.len = i; - i = j; - addr.s[i] = '@'; - } - - at = byte_rchr(addr.s,addr.len,'@'); - - if (constmap(&maplocals,addr.s + at + 1,addr.len - at - 1)) { - if (!stralloc_cat(&rwline,&addr)) return 0; - if (!stralloc_0(&rwline)) return 0; - return 1; - } - - for (i = 0; i <= addr.len; ++i) - if (!i || (i == at + 1) || (i == addr.len) || ((i > at) && (addr.s[i] == '.'))) - if ((x = constmap(&mapvdoms,addr.s + i,addr.len - i))) { - if (!*x) break; - if (!stralloc_cats(&rwline,x)) return 0; - if (!stralloc_cats(&rwline,"-")) return 0; - if (!stralloc_cat(&rwline,&addr)) return 0; - if (!stralloc_0(&rwline)) return 0; - return 1; - } - - if (!stralloc_cat(&rwline,&addr)) return 0; - if (!stralloc_0(&rwline)) return 0; - return 2; -} - -/* this file is not so long --------------------------------- COMMUNICATION */ - -buffer toqc; char toqcbuf[1024]; -buffer fromqc; char fromqcbuf[1024]; -stralloc comm_buf = {0}; -int comm_pos; -int fdout = -1; -int fdin = -1; - -void sendlog1(char* x) -{ - int pos; - - pos = comm_buf.len; - if (!stralloc_cats(&comm_buf,"L")) goto FAIL; - if (!stralloc_cats(&comm_buf,x)) goto FAIL; - if (!stralloc_0(&comm_buf)) goto FAIL; - return; - - FAIL: - /* either all or nothing */ - comm_buf.len = pos; -} - -void sendlog3(char* x, char *y, char *z) -{ - int pos; - - pos = comm_buf.len; - if (!stralloc_cats(&comm_buf,"L")) goto FAIL; - if (!stralloc_cats(&comm_buf,x)) goto FAIL; - if (!stralloc_cats(&comm_buf,y)) goto FAIL; - if (!stralloc_cats(&comm_buf,z)) goto FAIL; - if (!stralloc_0(&comm_buf)) goto FAIL; - return; - - FAIL: - /* either all or nothing */ - comm_buf.len = pos; -} - -void comm_init(void) -{ - buffer_init(&toqc,write,2,toqcbuf,sizeof(toqcbuf)); - buffer_init(&fromqc,read,3,fromqcbuf,sizeof(fromqcbuf)); - - fdout = 1; /* stdout */ - fdin = 0; /* stdin */ - if (ndelay_on(fdout) == -1) - /* this is so stupid: NDELAY semantics should be default on write */ - senddied(); /* drastic, but better than risking deadlock */ - - while (!stralloc_ready(&comm_buf,1024)) nomem(); -} - -int comm_canwrite(void) -{ - /* XXX: could allow a bigger buffer; say 10 recipients */ - /* XXX: returns true if there is something in the buffer */ - if (!flagsendalive) return 0; - if (comm_buf.s && comm_buf.len) return 1; - return 0; -} - -void comm_write(unsigned long id, int local, int remote) -{ - int pos; - char *s; - - if (local && remote) s="B"; - else if (local) s="L"; - else if (remote) s="R"; - else s="X"; - - pos = comm_buf.len; - strnum[fmt_ulong(strnum,id)] = 0; - if (!stralloc_cats(&comm_buf,"D")) goto FAIL; - if (!stralloc_cats(&comm_buf,s)) goto FAIL; - if (!stralloc_cats(&comm_buf,strnum)) goto FAIL; - if (!stralloc_0(&comm_buf)) goto FAIL; - return; - - FAIL: - /* either all or nothing */ - comm_buf.len = pos; -} - -void comm_info(unsigned long id, unsigned long size, char* from, unsigned long pid, unsigned long uid) -{ - int pos; - int i; - - pos = comm_buf.len; - if (!stralloc_cats(&comm_buf,"Linfo msg ")) goto FAIL; - strnum[fmt_ulong(strnum,id)] = 0; - if (!stralloc_cats(&comm_buf,strnum)) goto FAIL; - if (!stralloc_cats(&comm_buf,": bytes ")) goto FAIL; - strnum[fmt_ulong(strnum,size)] = 0; - if (!stralloc_cats(&comm_buf,strnum)) goto FAIL; - if (!stralloc_cats(&comm_buf," from <")) goto FAIL; - i = comm_buf.len; - if (!stralloc_cats(&comm_buf,from)) goto FAIL; - - for (; i < comm_buf.len; ++i) - if (comm_buf.s[i] == '\n') - comm_buf.s[i] = '/'; - else - if (!issafe(comm_buf.s[i])) - comm_buf.s[i] = '_'; - - if (!stralloc_cats(&comm_buf,"> qp ")) goto FAIL; - strnum[fmt_ulong(strnum,pid)] = 0; - if (!stralloc_cats(&comm_buf,strnum)) goto FAIL; - if (!stralloc_cats(&comm_buf," uid ")) goto FAIL; - strnum[fmt_ulong(strnum,uid)] = 0; - if (!stralloc_cats(&comm_buf,strnum)) goto FAIL; - if (!stralloc_cats(&comm_buf,"\n")) goto FAIL; - if (!stralloc_0(&comm_buf)) goto FAIL; - return; - - FAIL: - /* either all or nothing */ - comm_buf.len = pos; -} - -void comm_exit(void) -{ - /* if it FAILs exit, we have already stoped */ - if (!stralloc_cats(&comm_buf,"X")) _exit(1); - if (!stralloc_0(&comm_buf)) _exit(1); -} - -void comm_selprep(int *nfds, fd_set *wfds, fd_set *rfds) -{ - if (flagsendalive) { - if (flagquitasap && comm_canwrite() == 0) - comm_exit(); - if (comm_canwrite()) { - FD_SET(fdout,wfds); - if (*nfds <= fdout) - *nfds = fdout + 1; - } - FD_SET(fdin,rfds); - if (*nfds <= fdin) - *nfds = fdin + 1; - } -} - -void comm_do(fd_set *wfds, fd_set *rfds) -{ - /* first write then read */ - if (flagsendalive) - if (comm_canwrite()) - if (FD_ISSET(fdout,wfds)) { - int w; - int len; - len = comm_buf.len; - w = write(fdout,comm_buf.s + comm_pos,len - comm_pos); - if (w <= 0) { - if ((w == -1) && (errno == EPIPE)) - senddied(); - } else { - comm_pos += w; - if (comm_pos == len) { - comm_buf.len = 0; - comm_pos = 0; - } - } - } - if (flagsendalive) - if (FD_ISSET(fdin,rfds)) { - /* there are only two messages 'H' and 'X' */ - char c; - int r; - r = read(fdin, &c, 1); - if (r <= 0) { - if ((r == -1) && (errno != EINTR)) - senddied(); - } else { - switch (c) { - case 'H': - sighup(); - break; - case 'X': - sigterm(); - break; - default: - sendlog1("warning: qmail-todo: qmail-send speaks an obscure dialect\n"); - break; - } - } - } -} - -/* this file is not so long ------------------------------------------ TODO */ - -datetime_sec nexttodorun; -int flagtododir; /* if 0, have to opendir again */ -readsubdir todosubdir; -stralloc todoline = {0}; -char todobuf[BUFSIZE_MESS]; -char todobufinfo[BUFSIZE_MESS]; -char todobufchan[CHANNELS][1024]; - -void todo_init(void) -{ - flagtododir = 0; - nexttodorun = now(); - trigger_set(); -} - -void todo_selprep(int *nfds, fd_set *rfds, datetime_sec *wakeup) -{ - if (flagquitasap) return; - trigger_selprep(nfds,rfds); - if (flagtododir) *wakeup = 0; - if (*wakeup > nexttodorun) *wakeup = nexttodorun; -} - -void todo_do(fd_set *rfds) -{ - struct stat st; - buffer bi; - int fd; - buffer bo; - int fdnumber; - buffer bchan[CHANNELS]; - int fdchan[CHANNELS]; - int flagchan[CHANNELS]; - char ch; - int match; - unsigned long id; - int c; - unsigned long uid; - unsigned long pid; - - fd = -1; - fdnumber = -1; - for (c = 0; c < CHANNELS; ++c) - fdchan[c] = -1; - - if (flagquitasap) return; - - if (!flagtododir) { - if (!trigger_pulled(rfds)) { - if (recent < nexttodorun) return; - } - trigger_set(); - readsubdir_init(&todosubdir,"todo",pausedir); - flagtododir = 1; - nexttodorun = recent + SLEEP_TODO; - } - - switch (readsubdir_next(&todosubdir,&id)) { - case 1: break; - case 0: flagtododir = 0; - default: return; - } - - fnmake_todo(id); - - fd = open_read(fn.s); - if (fd == -1) { sendlog3("warning: qmail-todo: unable to open ",fn.s,"\n"); return; } - - fnmake_mess(id); - /* just for the statistics */ - if (stat(fn.s,&st) == -1) - { sendlog3("warning: qmail-todo: unable to stat ",fn.s," for mess\n"); goto FAIL; } - - for (c = 0; c < CHANNELS; ++c) { - fnmake_chanaddr(id,c); - if (unlink(fn.s) == -1) if (errno != ENOENT) - { sendlog3("warning: qmail-todo: unable to unlink ",fn.s," for mess\n"); goto FAIL; } - } - - fnmake_info(id); - if (unlink(fn.s) == -1) if (errno != ENOENT) - { sendlog3("warning: qmail-todo: unable to unlink ",fn.s," for info\n"); goto FAIL; } - - fdnumber = open_excl(fn.s); - if (fdnumber == -1) - { sendlog3("warning: qmail-todo: unable to create ",fn.s," for info\n"); goto FAIL; } - - strnum[fmt_ulong(strnum,id)] = 0; - sendlog3("new msg ",strnum,"\n"); - - for (c = 0; c < CHANNELS; ++c) - flagchan[c] = 0; - - buffer_init(&bi,read,fd,todobuf,sizeof(todobuf)); - buffer_init(&bo,write,fdnumber,todobufinfo,sizeof(todobufinfo)); - - uid = 0; - pid = 0; - - for (;;) { - if (getln(&bi,&todoline,&match,'\0') == -1) { - /* perhaps we're out of memory, perhaps an I/O error */ - fnmake_todo(id); - sendlog3("warning: qmail-todo: trouble reading ",fn.s,"\n"); goto FAIL; - } - if (!match) break; - - switch (todoline.s[0]) { - case 'u': - scan_ulong(todoline.s + 1,&uid); break; - case 'p': - scan_ulong(todoline.s + 1,&pid); break; - case 'F': - if (buffer_putflush(&bo,todoline.s,todoline.len) == -1) { - fnmake_info(id); - sendlog3("warning: qmail-todo: trouble writing to ",fn.s," for todo\n"); goto FAIL; - } - comm_info(id,(unsigned long) st.st_size,todoline.s + 1,pid,uid); - break; - case 'T': - switch (rewrite(todoline.s + 1)) { - case 0: nomem(); goto FAIL; - case 2: c = 1; break; - default: c = 0; break; - } - if (fdchan[c] == -1) { - fnmake_chanaddr(id,c); - fdchan[c] = open_excl(fn.s); - if (fdchan[c] == -1) - { sendlog3("warning: qmail-todo: unable to create ",fn.s," for delivery\n"); goto FAIL; } - buffer_init(&bchan[c],write,fdchan[c],todobufchan[c],sizeof(todobufchan[c])); - flagchan[c] = 1; - } - if (buffer_put(&bchan[c],rwline.s,rwline.len) == -1) { - fnmake_chanaddr(id,c); - sendlog3("warning: qmail-todo: trouble writing to ",fn.s," for delivery\n"); goto FAIL; - } - break; - default: - fnmake_todo(id); - sendlog3("warning: qmail-todo: unknown record type in ",fn.s,"\n"); goto FAIL; - } - } - - close(fd); fd = -1; - - fnmake_info(id); - if (buffer_flush(&bo) == -1) - { sendlog3("warning: qmail-todo: trouble writing to ",fn.s," for info\n"); goto FAIL; } - if (fsync(fdnumber) == -1) - { sendlog3("warning: qmail-todo: trouble fsyncing ",fn.s," for info\n"); goto FAIL; } - close(fdnumber); fdnumber = -1; - - for (c = 0; c < CHANNELS; ++c) - if (fdchan[c] != -1) { - fnmake_chanaddr(id,c); - if (buffer_flush(&bchan[c]) == -1) { sendlog3("warning: qmail-todo: trouble writing to ",fn.s," in channel\n"); goto FAIL; } - if (fsync(fdchan[c]) == -1) { sendlog3("warning: qmail-todo: trouble fsyncing ",fn.s," in channel\n"); goto FAIL; } - close(fdchan[c]); fdchan[c] = -1; - } - - fnmake_todo(id); - if (buffer_putflush(&toqc,fn.s,fn.len) == -1) { cleandied(); return; } - if (buffer_get(&fromqc,&ch,1) != 1) { cleandied(); return; } - - if (ch != '+') { - sendlog3("warning: qmail-clean unable to clean up ",fn.s,"\n"); - return; - } - - comm_write(id,flagchan[0],flagchan[1]); - return; - - FAIL: - if (fd != -1) close(fd); - if (fdnumber != -1) close(fdnumber); - for (c = 0; c < CHANNELS; ++c) - if (fdchan[c] != -1) close(fdchan[c]); -} - -/* this file is too long ---------------------------------------------- MAIN */ - -int getcontrols(void) -{ - if (control_init() == -1) return 0; - if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1) return 0; - if (control_readfile(&locals,"control/locals",1) != 1) return 0; - if (!constmap_init(&maplocals,locals.s,locals.len,0)) return 0; - switch (control_readfile(&percenthack,"control/percenthack",0)) { - case -1: return 0; - case 0: if (!constmap_init(&mappercenthack,"",0,0)) return 0; break; - case 1: if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0)) return 0; break; - } - switch (control_readfile(&vdoms,"control/virtualdomains",0)) { - case -1: return 0; - case 0: if (!constmap_init(&mapvdoms,"",0,1)) return 0; break; - case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) return 0; break; - } - return 1; -} - -stralloc newlocals = {0}; -stralloc newvdoms = {0}; - -void regetcontrols(void) -{ - int r; - - if (control_readfile(&newlocals,"control/locals",1) != 1) - { sendlog1("alert: qmail-todo: unable to reread control/locals\n"); return; } - r = control_readfile(&newvdoms,"control/virtualdomains",0); - if (r == -1) - { sendlog1("alert: qmail-todo: unable to reread control/virtualdomains\n"); return; } - - constmap_free(&maplocals); - constmap_free(&mapvdoms); - - while (!stralloc_copy(&locals,&newlocals)) nomem(); - while (!constmap_init(&maplocals,locals.s,locals.len,0)) nomem(); - - if (r) { - while (!stralloc_copy(&vdoms,&newvdoms)) nomem(); - while (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) nomem(); - } - else - while (!constmap_init(&mapvdoms,"",0,1)) nomem(); -} - -void reread(void) -{ - if (chdir(auto_qmail) == -1) { - sendlog1("alert: qmail-todo: unable to reread controls: unable to switch to home directory\n"); - return; - } - - regetcontrols(); - while (chdir("queue") == -1) { - sendlog1("alert: qmail-todo: unable to switch back to queue directory; HELP! sleeping...\n"); - sleep(10); - } -} - -int main() -{ - datetime_sec wakeup; - fd_set rfds; - fd_set wfds; - int nfds; - struct timeval tv; - int r; - char c; - - if (chdir(auto_qmail) == -1) - { sendlog1("alert: qmail-todo: cannot start: unable to switch to home directory\n"); _exit(110); } - if (!getcontrols()) - { sendlog1("alert: qmail-todo: cannot start: unable to read controls\n"); _exit(112); } - if (chdir("queue") == -1) - { sendlog1("alert: qmail-todo: cannot start: unable to switch to queue directory\n"); _exit(110); } - sig_pipeignore(); - umask(077); - - fnmake_init(); - todo_init(); - comm_init(); - - do { - r = read(fdin, &c, 1); - if ((r == -1) && (errno != EINTR)) - _exit(100); /* read failed probably qmail-send died */ - } while ((r =! 1)); /* we assume it is a 'S' */ - - for (;;) { - recent = now(); - if (flagreadasap) { flagreadasap = 0; reread(); } - if (!flagsendalive) { - /* qmail-send finaly exited, so do the same. */ - if (flagquitasap) _exit(0); - /* qmail-send died. We can not log and we can not work therefor _exit(1). */ - _exit(1); - } - - wakeup = recent + SLEEP_FOREVER; - FD_ZERO(&rfds); - FD_ZERO(&wfds); - nfds = 1; - - todo_selprep(&nfds,&rfds,&wakeup); - comm_selprep(&nfds,&wfds,&rfds); - - if (wakeup <= recent) tv.tv_sec = 0; - else tv.tv_sec = wakeup - recent + SLEEP_FUZZ; - tv.tv_usec = 0; - - if (select(nfds,&rfds,&wfds,(fd_set *) 0,&tv) == -1) - if (errno == EINTR) - ; - else - sendlog1("warning: qmail-todo: trouble in select\n"); - else { - recent = now(); - - todo_do(&rfds); - comm_do(&wfds, &rfds); - } - } - /* NOTREACHED */ - _exit(1); -} - |