int getoff(const char *action) { int r; r = subscribe(workdir,target.s,0,"",(*action == ACTION_WC[0]) ? "-mod" : "-",-1); if (flagdig == FLD_DENY || flagdig == FLD_ALLOW) strerr_die2x(0,INFO,MSG1(ERR_EXTRA_UNSUB,target.s)); switch (r) { /* no comment for unsubscribe */ case 1: hdr_subject(MSG(SUB_GOODBYE)); qmail_puts(&qq,"\n"); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/unsub-ok"); break; default: hdr_subject(MSG(SUB_UNSUBSCRIBE_NOP)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/unsub-nop"); break; } return r; }
int geton(const char *action) { const char *fl; int r; unsigned int i; unsigned char ch; fl = get_from(target.s,action); /* try to match up */ r = subscribe(workdir,target.s,1,fl,(*action == ACTION_RC[0]) ? "+mod" : "+",-1); if (flagdig == FLD_DENY || flagdig == FLD_ALLOW) strerr_die2x(0,INFO,MSG1(ERR_EXTRA_SUB,target.s)); switch (r) { case 1: qmail_puts(&qq,"List-Unsubscribe: <mailto:"); /*rfc2369 */ qmail_put(&qq,outlocal.s,outlocal.len); qmail_puts(&qq,"-unsubscribe-"); /* url-encode since verptarget is controlled by sender */ /* note &verptarget ends in '\0', hence len - 1! */ for (i = 0; i < verptarget.len - 1; i++) { ch = verptarget.s[i]; if (str_chr("\"?;<>&/:%+#",ch) < 10 || (ch <= ' ') || (ch & 0x80)) { urlstr[1] = hex[ch / 16]; urlstr[2] = hex[ch & 0xf]; qmail_put(&qq,urlstr,3); } else { qmail_put(&qq,verptarget.s + i, 1); } } qmail_puts(&qq,"@"); qmail_put(&qq,outhost.s,outhost.len); /* safe */ qmail_puts(&qq,">\n"); hdr_subject(MSG(SUB_WELCOME)); hdr_ctboundary(); stralloc_copy(&confirm,&outlocal); stralloc_cats(&confirm,"-unsubscribe-"); stralloc_cats(&confirm,verptarget.s); stralloc_append(&confirm,'@'); stralloc_cat(&confirm,&outhost); stralloc_0(&confirm); set_cpconfirm(confirm.s,outlocal.len); /* for !R in copy */ copy(&qq,"text/top",flagcd); copy_act("text/sub-ok"); break; default: if (str_start(action,ACTION_TC)) strerr_die2x(0,INFO,MSG(ERR_SUB_NOP)); hdr_subject(MSG(SUB_SUBSCRIBE_NOP)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/sub-nop"); break; } return r; }
static void do_list(int act) { unsigned int i; if (!flaglist || (modsub.s == 0 && remote.s == 0)) strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE)); if (!ismod) strerr_die2x(100,FATAL,MSG(ERR_NOT_ALLOWED)); hdr_subject(MSG(SUB_LIST)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); if (act == AC_LIST) { showsend("list"); (void) code_qputs(""); (void) code_qputs(MSG(TXT_LISTMEMBERS)); (void) code_qputs("\n"); i = putsubs(workdir,0L,52L,code_subto); } else { /* listn */ showsend("listn"); i = putsubs(workdir,0L,52L,dummy_to); } (void) code_qput("\n ======> ",11); (void) code_qput(strnum,fmt_ulong(strnum,i)); (void) code_qput("\n",1); copybottom(0); qmail_to(&qq,mod.s); }
static void do_help(void) { hdr_subject(MSG(SUB_HELP)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/help"); copybottom(1); qmail_to(&qq,sender); }
static void do_faq(void) { hdr_subject(MSG(SUB_FAQ)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/faq"); copybottom(0); qmail_to(&qq,target.s); }
static void do_info(void) { hdr_subject(MSG(SUB_INFO)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/info"); copybottom(0); qmail_to(&qq,target.s); }
static void do_get(const char *action) { unsigned long u; struct stat st; char ch; int r; unsigned int pos; int fd; if (!flagget) strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE)); hdr_subject(MSG(SUB_GET_MSG)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); pos = str_len(ACTION_GET); if (!case_starts(action,ACTION_GET)) pos = str_len(ALT_GET); if (action[pos] == '.' || action [pos] == '_') pos++; scan_ulong(action + pos,&u); stralloc_copys(&line,"archive/"); stralloc_catb(&line,strnum,fmt_ulong(strnum,u / 100)); stralloc_cats(&line,"/"); stralloc_catb(&line,strnum,fmt_uint0(strnum,(unsigned int) (u % 100),2)); stralloc_0(&line); fd = open_read(line.s); if (fd == -1) if (errno != error_noent) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,line.s)); else copy_act("text/get-bad"); else { if (fstat(fd,&st) == -1) copy_act("text/get-bad"); else if (!(st.st_mode & 0100)) copy_act("text/get-bad"); else { showsend("get"); substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); qmail_puts(&qq,"> "); for (;;) { r = substdio_get(&sstext,&ch,1); if (r == -1) strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s)); if (r == 0) break; qmail_put(&qq,&ch,1); if (ch == '\n') qmail_puts(&qq,"> "); } qmail_puts(&qq,"\n"); } close(fd); } copybottom(0); qmail_to(&qq,target.s); }
static void do_mod_help(void) { hdr_subject(MSG(SUB_MOD_HELP)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/mod-help"); copy(&qq,"text/help",flagcd); copybottom(0); qmail_to(&qq,mod.s); }
static void do_query(void) { hdr_subject(MSG(SUB_STATUS)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); if (issub(workdir,target.s,0)) copy_act("text/sub-nop"); else copy_act("text/unsub-nop"); copybottom(0); qmail_to(&qq,ismod ? mod.s : target.s); }
static void do_log(char *action,unsigned int actlen) { action += actlen; if (*action == '.' || *action == '_') ++action; if (!flaglist || remote.s == 0) strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE)); if (!ismod) strerr_die2x(100,FATAL,MSG(ERR_NOT_ALLOWED)); showsend("log"); hdr_subject((*action == 0) ? MSG(SUB_LOG) : MSG(SUB_LOG_SEARCH)); hdr_ctboundary(); searchlog(workdir,action,code_subto); copybottom(0); qmail_to(&qq,mod.s); }
void doconfirm(const char *act) /* This should only be called with valid act for sub/unsub confirms. If act */ /* is not ACTION_[RST]C, it is assumed to be an unsubscribe conf.*/ /* "act" is the first letter of desired confirm request only as STRING! */ { strnum[fmt_ulong(strnum,when)] = 0; cookie(hash,key.s,key.len-flagdig,strnum,target.s,act); stralloc_copy(&confirm,&outlocal); stralloc_append(&confirm,'-'); stralloc_catb(&confirm,act,1); stralloc_cats(&confirm,"c."); stralloc_cats(&confirm,strnum); stralloc_append(&confirm,'.'); stralloc_catb(&confirm,hash,COOKIE); stralloc_append(&confirm,'-'); stralloc_cats(&confirm,verptarget.s); stralloc_append(&confirm,'@'); stralloc_cat(&confirm,&outhost); stralloc_0(&confirm); set_cpconfirm(confirm.s,outlocal.len); /* for copy */ set_cpaction(act); set_cphash(hash); set_cpwhen(when); qmail_puts(&qq,"Reply-To: "); quote2("ed,confirm.s); qmail_put(&qq,quoted.s,quoted.len); qmail_puts(&qq,"\n"); hdr_subject((*act == ACTION_SC[0]) ? MSG(SUB_USR_SUBSCRIBE) : (*act == ACTION_UC[0]) ? MSG(SUB_USR_UNSUBSCRIBE) : (*act == ACTION_TC[0] || *act == ACTION_RC[0]) ? MSG(SUB_MOD_SUBSCRIBE) : MSG(SUB_MOD_UNSUBSCRIBE)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); }
static void do_ed(char *action) { datetime_sec u; int flaggoodfield; int fd; char *x, *y; char *cp,*cplast,*cpnext,*cpafter; int flagdone; unsigned int len; const char *fname; unsigned int i; x = action + LENGTH_ED; x += scan_ulong(x,&u); if ((u > when) || (u < when - 100000)) die_cookie(); if (*x == '.') ++x; fname = x; x += str_chr(x,'.'); if (!*x) die_cookie(); *x = (char) 0; ++x; stralloc_copys(&fnedit,"text/"); stralloc_cats(&fnedit,fname); stralloc_0(&fnedit); y = fnedit.s + 5; /* after "text/" */ while (*++y) { /* Name should be guaranteed by the cookie, */ /* but better safe than sorry ... */ if (((*y > 'z') || (*y < 'a')) && (*y != '_')) strerr_die2x(100,FATAL,MSG(ERR_BAD_NAME)); if (*y == '_') *y = '-'; } lock(); /* file must not change while here */ switch (slurp(fnedit.s,&text,1024)) { case -1: strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnedit.s)); case 0: strerr_die5x(100,FATAL,dir,"/",fnedit.s,MSG(ERR_NOEXIST)); } stralloc_copy(&line,&text); subst_nuls(&line); stralloc_cat(&line,&fnedit); /* including '\0' */ strnum[fmt_ulong(strnum,(unsigned long) u)] = 0; cookie(hash,key.s,key.len,strnum,line.s,"-e"); if (str_len(x) != COOKIE) die_cookie(); if (byte_diff(hash,COOKIE,x)) die_cookie(); /* cookie is ok, file exists, lock's on, new file ends in '_' */ stralloc_copys(&fneditn,fnedit.s); stralloc_append(&fneditn,'_'); stralloc_0(&fneditn); fd = open_trunc(fneditn.s); if (fd == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s)); substdio_fdbuf(&sstext,write,fd,textbuf,sizeof(textbuf)); stralloc_copys("ed,""); /* clear */ stralloc_copys(&text,""); for (;;) { /* get message body */ if (getln(&ssin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); if (!match) break; stralloc_cat(&text,&line); } if (encin) { /* decode if necessary */ if (encin == 'B') decodeB(text.s,text.len,&line); else decodeQ(text.s,text.len,&line); stralloc_copy(&text,&line); } cp = text.s; cpafter = text.s+text.len; flaggoodfield = 0; flagdone = 0; len = 0; while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) { i = byte_chr(cp,cpnext-cp,'%'); if (i != (unsigned int) (cpnext - cp)) { if (!flaggoodfield) { /* MSG(TXT_EDIT_START)/END */ if (case_startb(cp+i,cpnext-cp-i,MSG(TXT_EDIT_START))) { /* start tag. Store users 'quote characters', e.g. '> ' */ stralloc_copyb("ed,cp,i); flaggoodfield = 1; cp = cpnext + 1; continue; } } else if (case_startb(cp+i,cpnext-cp-i,MSG(TXT_EDIT_END))) { flagdone = 1; break; } } if (flaggoodfield) { if ((len += cpnext - cp - quoted.len + 1) > MAXEDIT) strerr_die1x(100,MSG(ERR_EDSIZE)); if (quoted.len && cpnext-cp >= (int) quoted.len && !str_diffn(cp,quoted.s,quoted.len)) cp += quoted.len; /* skip quoting characters */ cplast = cpnext - 1; if (*cplast == '\r') /* CRLF -> '\n' for base64 encoding */ *cplast = '\n'; else ++cplast; if (substdio_put(&sstext,cp,cplast-cp+1) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s)); } cp = cpnext + 1; } if (!flagdone) strerr_die2x(100,FATAL,MSG(ERR_NO_MARK)); if (substdio_flush(&sstext) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,fneditn.s)); if (fsync(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,fneditn.s)); if (fchmod(fd, 0600) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CHMOD,fneditn.s)); if (close(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,fneditn.s)); wrap_rename(fneditn.s,fnedit.s); unlock(); hdr_subject(MSG1(SUB_EDIT_SUCCESS,fname)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/edit-done"); copybottom(0); qmail_to(&qq,sender); /* not necessarily from mod */ }
static void do_edit(const char *action) { unsigned int i; unsigned int len; char ch; /* only remote admins and only if -e is specified may edit */ if (!flagedit || remote.s == 0) strerr_die2x(100,FATAL,MSG(ERR_NOT_AVAILABLE)); if (!ismod) strerr_die2x(100,FATAL,MSG(ERR_NOT_ALLOWED)); len = str_len(ACTION_EDIT); if (!case_starts(action,ACTION_EDIT)) len = str_len(ALT_EDIT); if (action[len]) { /* -edit.file, not just -edit */ if (action[len] != '.') strerr_die2x(100,FATAL,MSG(ERR_BAD_REQUEST)); showsend2("edit ",action+len+1); stralloc_copys(&fnedit,"text/"); stralloc_cats(&fnedit,action+len+1); stralloc_0(&fnedit); case_lowerb(fnedit.s,fnedit.len); i = 5; /* after the "text/" */ while ((ch = fnedit.s[i++])) { if (((ch > 'z') || (ch < 'a')) && (ch != '_')) strerr_die2x(100,FATAL,MSG(ERR_BAD_NAME)); if (ch == '_') fnedit.s[i-1] = '-'; } switch(slurp(fnedit.s,&text,1024)) { /* entire file! */ case -1: strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnedit.s)); case 0: strerr_die5x(100,FATAL,dir,"/",fnedit.s,MSG(ERR_NOEXIST)); } stralloc_copy(&line,&text); subst_nuls(&line); stralloc_cat(&line,&fnedit); /* including '\0' */ strnum[fmt_ulong(strnum,(unsigned long) when)] = 0; cookie(hash,key.s,key.len,strnum,line.s,"-e"); stralloc_copy(&confirm,&outlocal); stralloc_append(&confirm,'-'); stralloc_catb(&confirm,ACTION_ED,LENGTH_ED); stralloc_cats(&confirm,strnum); stralloc_append(&confirm,'.'); /* action part has been checked for bad chars */ stralloc_cats(&confirm,action + len + 1); stralloc_append(&confirm,'.'); stralloc_catb(&confirm,hash,COOKIE); stralloc_append(&confirm,'@'); stralloc_cat(&confirm,&outhost); stralloc_0(&confirm); set_cpconfirm(confirm.s,outlocal.len); set_cpaction(ACTION_ED); set_cphash(hash); set_cpwhen(when); qmail_puts(&qq,"Reply-To: "); quote2("ed,confirm.s); qmail_put(&qq,quoted.s,quoted.len); qmail_puts(&qq,"\n"); hdr_subject(MSG1(SUB_EDIT_REQUEST,action+len+1)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy(&qq,"text/edit-do",flagcd); (void) code_qputs(MSG(TXT_EDIT_START)); (void) code_qput(text.s,text.len); (void) code_qputs(MSG(TXT_EDIT_END)); } else { /* -edit only, so output list of editable files */ hdr_subject(MSG(SUB_EDIT_LIST)); hdr_ctboundary(); copy(&qq,"text/top",flagcd); copy_act("text/edit-list"); } qmail_puts(&qq,"\n\n"); copybottom(0); qmail_to(&qq,mod.s); }
void main(int argc,char **argv) { char *sender; char *def; char *local; char *action; int flaginheader; int flagcomment; int flaggoodfield; int flagdone; int fd, fdlock; int match; const char *err; char encin = '\0'; unsigned int start,confnum; unsigned int pos,i; int child; int opt; char *cp,*cpnext,*cpfirst,*cplast,*cpafter; (void) umask(022); sig_pipeignore(); when = now(); if (!stralloc_copys(&sendopt,"-")) die_nomem(); opt = getconfopt(argc,argv,options,1,&dir); sender = get_sender(); if (!sender) strerr_die2x(100,FATAL,MSG(ERR_NOSENDER)); local = env_get("LOCAL"); if (!local) strerr_die2x(100,FATAL,MSG(ERR_NOLOCAL)); def = env_get("DEFAULT"); if (!def) strerr_die2x(100,FATAL,MSG(ERR_NODEFAULT)); if (!*sender) strerr_die2x(100,FATAL,MSG(ERR_BOUNCE)); if (!sender[str_chr(sender,'@')]) strerr_die2x(100,FATAL,MSG(ERR_ANONYMOUS)); if (str_equal(sender,"#@[]")) strerr_die2x(100,FATAL,MSG(ERR_BOUNCE)); /* local should be >= def, but who knows ... */ cp = local + str_len(local) - str_len(def) - 2; if (cp < local) die_badformat(); action = local + byte_rchr(local,cp - local,'-'); if (action == cp) die_badformat(); action++; if (!action[0]) die_badformat(); if (!str_start(action,ACTION_ACCEPT) && !str_start(action,ACTION_REJECT)) die_badformat(); start = str_chr(action,'-'); if (!action[start]) die_badformat(); confnum = 1 + start + str_chr(action + start + 1,'.'); if (!action[confnum]) die_badformat(); confnum += 1 + str_chr(action + confnum + 1,'.'); if (!action[confnum]) die_badformat(); if (!stralloc_copyb(&fnbase,action+start+1,confnum-start-1)) die_nomem(); if (!stralloc_0(&fnbase)) die_nomem(); cookie(hash,key.s,key.len,fnbase.s,"","a"); if (byte_diff(hash,COOKIE,action+confnum+1)) die_badformat(); fdlock = lockfile("mod/lock"); switch(checkfile(fnbase.s)) { case 0: strerr_die2x(100,FATAL,MSG(ERR_MOD_TIMEOUT)); case -1: /* only error if new request != action taken */ if (str_start(action,ACTION_ACCEPT)) strerr_die2x(0,INFO,MSG(ERR_MOD_ACCEPTED)); else strerr_die2x(100,FATAL,MSG(ERR_MOD_ACCEPTED)); case -2: if (str_start(action,ACTION_REJECT)) strerr_die2x(0,INFO,MSG(ERR_MOD_REJECTED)); else strerr_die2x(100,FATAL,MSG(ERR_MOD_REJECTED)); default: break; } /* Here, we have an existing filename in fnbase with the complete path */ /* from the current dir in fnmsg. */ if (str_start(action,ACTION_REJECT)) { if (qmail_open(&qq, (stralloc *) 0) == -1) strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE)); /* Build recipient from msg return-path */ fd = open_read(fnmsg.s); if (fd == -1) { if (errno != error_noent) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fnmsg.s)); else strerr_die2x(100,FATAL,MSG(ERR_MOD_TIMEOUT)); } substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); if (getln(&sstext,&line,&match,'\n') == -1 || !match) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); maketo(); /* extract SENDER from return-path */ /* Build message */ hdr_add2s("Mailing-List: ",MSG(TXT_MAILING_LIST)); if (listid.len > 0) hdr_add2("List-ID: ",listid.s,listid.len); hdr_datemsgid(when); hdr_from("-owner"); if (replyto) hdr_add2s("Reply-To: ",replyto); hdr_add2s("To: ",to.s); hdr_subject(MSG(SUB_RETURNED_POST)); if (flagmime) { hdr_mime(CTYPE_MULTIPART); hdr_boundary(0); hdr_ctype(CTYPE_TEXT); hdr_transferenc(); } copy(&qq,"text/top",flagcd); copy(&qq,"text/mod-reject",flagcd); flagcomment = 0; flaginheader = 1; if (!stralloc_copys(&text,"")) die_nomem(); if (!stralloc_ready(&text,1024)) die_nomem(); for (;;) { /* copy moderator's rejection comment */ if (getln(subfdin,&line,&match,'\n') == -1) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); if (!match) break; if (flaginheader) { if (case_startb(line.s,line.len,"Content-Transfer-Encoding:")) { pos = 26; while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos; if (case_startb(line.s+pos,line.len-pos,"base64")) encin = 'B'; else if (case_startb(line.s+pos,line.len-pos,"quoted-printable")) encin = 'Q'; } if (line.len == 1) flaginheader = 0; } else if (!stralloc_cat(&text,&line)) die_nomem(); } /* got body */ if (encin) { if (encin == 'B') decodeB(text.s,text.len,&line); else decodeQ(text.s,text.len,&line); if (!stralloc_copy(&text,&line)) die_nomem(); } cp = text.s; cpafter = text.s + text.len; if (!stralloc_copys(&line,"\n>>>>> -------------------- >>>>>\n")) die_nomem(); flaggoodfield = 0; flagdone = 0; while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) { i = byte_chr(cp,cpnext-cp,'%'); if (i <= 5 && cpnext-cp-i >= 3) { /* max 5 "quote characters" and space for %%% */ if (cp[i+1] == '%' && cp[i+2] == '%') { if (!flaggoodfield) { /* Start tag */ if (!stralloc_copyb("ed,cp,i)) die_nomem(); /* quote chars*/ flaggoodfield = 1; cp = cpnext + 1; cpfirst = cp; continue; } else { /* end tag */ if (flagdone) /* 0 no comment lines, 1 comment line */ flagdone = 2; /* 2 at least 1 comment line & end tag */ break; } } } if (flaggoodfield) { cplast = cpnext - 1; if (*cplast == '\r') /* CRLF -> '\n' for base64 encoding */ *cplast = '\n'; else ++cplast; /* NUL is now ok, so the test for it was removed */ flagdone = 1; i = cplast - cp + 1; if (quoted.len && quoted.len <= i && !str_diffn(cp,quoted.s,quoted.len)) { /* quote chars */ if (!stralloc_catb(&line,cp+quoted.len,i-quoted.len)) die_nomem(); } else if (!stralloc_catb(&line,cp,i)) die_nomem(); /* no quote chars */ } cp = cpnext + 1; } if (flagdone == 2) { if (!stralloc_cats(&line,"<<<<< -------------------- <<<<<\n")) die_nomem(); code_qput(line.s,line.len); } if (flagcd == 'B') { encodeB("",0,&line,2); qmail_put(&qq,line.s,line.len); } if (flagmime) { hdr_boundary(0); hdr_ctype(CTYPE_MESSAGE); } qmail_puts(&qq,"\n"); if (seek_begin(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,fnmsg.s)); substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); if (qmail_copy(&qq,&sstext,-1) != 0) strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnmsg.s)); close(fd); if (flagmime) hdr_boundary(1); if (!stralloc_copy(&line,&outlocal)) die_nomem(); if (!stralloc_cats(&line,"-return-@")) die_nomem(); if (!stralloc_cat(&line,&outhost)) die_nomem(); if (!stralloc_0(&line)) die_nomem(); qmail_from(&qq,line.s); if (to.len) qmail_to(&qq,to.s); if (!stralloc_copys(&fnnew,"mod/rejected/")) die_nomem(); if (!stralloc_cats(&fnnew,fnbase.s)) die_nomem(); if (!stralloc_0(&fnnew)) die_nomem(); /* this is strictly to track what happended to a message to give informative */ /* messages to the 2nd-nth moderator that acts on the same message. Since */ /* this isn't vital we ignore errors. Also, it is no big ideal if unlinking */ /* the old file fails. In the worst case it gets acted on again. If we issue */ /* a temp error the reject will be redone, which is slightly worse. */ if (*(err = qmail_close(&qq)) == '\0') { fd = open_trunc(fnnew.s); if (fd != -1) close(fd); unlink(fnmsg.s); strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; strerr_die2x(0,"ezmlm-moderate: info: qp ",strnum); } else strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1); } else if (str_start(action,ACTION_ACCEPT)) { fd = open_read(fnmsg.s); if (fd == -1) { if (errno !=error_noent) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fnmsg.s)); else /* shouldn't happen since we've got lock */ strerr_die3x(100,FATAL,fnmsg.s,MSG(ERR_MOD_TIMEOUT)); } substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); /* read "Return-Path:" line */ if (getln(&sstext,&line,&match,'\n') == -1 || !match) strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT)); maketo(); /* extract SENDER to "to" */ env_put2("SENDER",to.s); /* set SENDER */ if (seek_begin(fd) == -1) /* rewind, since we read an entire buffer */ strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,fnmsg.s)); if ((child = wrap_fork()) == 0) { close(0); dup(fd); /* make fnmsg.s stdin */ if (argc > opt + 1) wrap_execvp((const char **)argv + opt); else if (argc > opt) wrap_execsh(argv[opt]); else wrap_execbin("/ezmlm-send", &sendopt, dir); } /* parent */ close(fd); wrap_exitcode(child); if (!stralloc_copys(&fnnew,"mod/accepted/")) die_nomem(); if (!stralloc_cats(&fnnew,fnbase.s)) die_nomem(); if (!stralloc_0(&fnnew)) die_nomem(); /* ignore errors */ fd = open_trunc(fnnew.s); if (fd != -1) close(fd); unlink(fnmsg.s); _exit(0); } }
void sendnotice(const char *d) /* sends file pointed to by d to the address in the return-path of the */ /* message. */ { unsigned int x,y; const char *err; if (qmail_open(&qq, (stralloc *) 0) == -1) strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE)); fd = open_read(d); if (fd == -1) strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,d)); substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); if (getln(&sstext,&line,&match,'\n') == -1) die_read(); if (!match) die_read(); if (!case_startb(line.s,line.len,"return-path:")) die_read(); x = 12 + byte_chr(line.s + 12,line.len-12,'<'); y = byte_rchr(line.s + x,line.len-x,'>'); if (x != line.len && x+y != line.len) { if (!stralloc_copyb(&to,line.s+x+1, y-1)) die_nomem(); if (!stralloc_0(&to)) die_nomem(); } else die_read(); hdr_add2s("Mailing-List: ",MSG(TXT_MAILING_LIST)); if (listid.len > 0) hdr_add2("List-ID: ",listid.s,listid.len); hdr_datemsgid(when+msgnum++); hdr_from("-help"); hdr_subject(MSG(SUB_RETURNED_POST)); hdr_add2s("To: ",to.s); if (flagmime) { hdr_mime(CTYPE_MULTIPART); hdr_boundary(0); hdr_ctype(CTYPE_TEXT); hdr_transferenc(); } else qmail_puts(&qq,"\n\n"); copy(&qq,"text/top",flagcd); copy(&qq,"text/mod-timeout",flagcd); if (flagcd == 'B') { encodeB("",0,&line,2); qmail_put(&qq,line.s,line.len); } if (flagmime) { hdr_boundary(0); hdr_ctype(CTYPE_MESSAGE); qmail_puts(&qq,"\n"); } if (seek_begin(fd) == -1) strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,d)); substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf)); if (qmail_copy(&qq,&sstext,-1) != 0) die_read(); close (fd); if (flagmime) hdr_boundary(1); if (!stralloc_copy(&line,&outlocal)) die_nomem(); if (!stralloc_cats(&line,"-return-@")) die_nomem(); if (!stralloc_cat(&line,&outhost)) die_nomem(); if (!stralloc_0(&line)) die_nomem(); qmail_from(&qq,line.s); /* sender */ qmail_to(&qq,to.s); if (*(err = qmail_close(&qq)) != '\0') strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ", err + 1); strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; strerr_warn2("ezmlm-clean: info: qp ",strnum,0); }