--- /dev/null
+/*$Id: ezmlm-moderate.c,v 1.42 1999/10/09 16:49:56 lindberg Exp $*/
+/*$Name: ezmlm-idx-040 $*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "error.h"
+#include "case.h"
+#include "stralloc.h"
+#include "str.h"
+#include "env.h"
+#include "error.h"
+#include "sig.h"
+#include "fork.h"
+#include "wait.h"
+#include "slurp.h"
+#include "getconf.h"
+#include "strerr.h"
+#include "byte.h"
+#include "getln.h"
+#include "qmail.h"
+#include "substdio.h"
+#include "readwrite.h"
+#include "seek.h"
+#include "quote.h"
+#include "datetime.h"
+#include "now.h"
+#include "date822fmt.h"
+#include "fmt.h"
+#include "sgetopt.h"
+#include "auto_bin.h"
+#include "cookie.h"
+#include "errtxt.h"
+#include "copy.h"
+#include "idx.h"
+
+int flagmime = MOD_MIME; /* default is message as attachment */
+char flagcd = '\0'; /* default: do not use transfer encoding */
+
+#define FATAL "ezmlm-moderate: fatal: "
+#define INFO "ezmlm-moderate: info: "
+
+void die_usage() { strerr_die1x(100,
+ "ezmlm-moderate: usage: ezmlm-moderate [-cCmMrRvV] [-t replyto] "
+ "dir [/path/ezmlm-send]"); }
+
+void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); }
+
+void die_badformat() { strerr_die2x(100,FATAL,ERR_BAD_REQUEST); }
+
+void die_badaddr() {
+ strerr_die2x(100,FATAL,ERR_BAD_ADDRESS);
+}
+
+stralloc outhost = {0};
+stralloc inlocal = {0};
+stralloc outlocal = {0};
+stralloc key = {0};
+stralloc mydtline = {0};
+stralloc mailinglist = {0};
+stralloc accept = {0};
+stralloc reject = {0};
+stralloc to = {0};
+stralloc send = {0};
+stralloc sendopt = {0};
+stralloc comment = {0};
+stralloc charset = {0};
+datetime_sec when;
+struct datetime dt;
+
+char strnum[FMT_ULONG];
+char date[DATE822FMT];
+char hash[COOKIE];
+char boundary[COOKIE];
+stralloc line = {0};
+stralloc qline = {0};
+stralloc text = {0};
+stralloc quoted = {0};
+stralloc fnbase = {0};
+stralloc fnmsg = {0};
+stralloc fnnew = {0};
+stralloc fnsub = {0};
+char subbuf[256];
+substdio sssub;
+
+char *dir;
+
+struct stat st;
+
+struct qmail qq;
+
+void code_qput(s,n)
+char *s;
+unsigned int n;
+{
+ if (!flagcd)
+ qmail_put(&qq,s,n);
+ else {
+ if (flagcd == 'B')
+ encodeB(s,n,&qline,0,FATAL);
+ else
+ encodeQ(s,n,&qline,FATAL);
+ qmail_put(&qq,qline.s,qline.len);
+ }
+}
+
+void transferenc()
+{
+ if (flagcd) {
+ qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
+ if (flagcd == 'Q')
+ qmail_puts(&qq,"Quoted-printable\n\n");
+ else
+ qmail_puts(&qq,"base64\n\n");
+ } else
+ qmail_puts(&qq,"\n\n");
+}
+
+int checkfile(fn)
+char *fn;
+/* looks for DIR/mod/{pending|rejected|accept}/fn.*/
+/* Returns: */
+/* 1 found in pending */
+/* 0 not found */
+/* -1 found in accepted */
+/* -2 found in rejected */
+/* Handles errors. */
+/* ALSO: if found, fnmsg contains the o-terminated*/
+/* file name. */
+{
+
+ if (!stralloc_copys(&fnmsg,"mod/pending/")) die_nomem();
+ if (!stralloc_cats(&fnmsg,fn)) die_nomem();
+ if (!stralloc_0(&fnmsg)) die_nomem();
+ if (stat(fnmsg.s,&st) == -1) {
+ if (errno != error_noent)
+ strerr_die6sys(111,FATAL,ERR_STAT,dir,"/",fnmsg.s,": ");
+ } else
+ return 1;
+
+ if (!stralloc_copys(&fnmsg,"mod/accepted/")) die_nomem();
+ if (!stralloc_cats(&fnmsg,fn)) die_nomem();
+ if (!stralloc_0(&fnmsg)) die_nomem();
+ if (stat(fnmsg.s,&st) == -1) {
+ if (errno != error_noent)
+ strerr_die6sys(111,FATAL,ERR_STAT,dir,"/",fnmsg.s,": ");
+ } else
+ return -1;
+
+ if (!stralloc_copys(&fnmsg,"mod/rejected/")) die_nomem();
+ if (!stralloc_cats(&fnmsg,fn)) die_nomem();
+ if (!stralloc_0(&fnmsg)) die_nomem();
+ if (stat(fnmsg.s,&st) == -1) {
+ if (errno != error_noent)
+ strerr_die6sys(111,FATAL,ERR_STAT,dir,"/",fnmsg.s,": ");
+ } else
+ return -2;
+ return 0;
+}
+
+int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
+{
+ qmail_put(&qq,buf,len);
+ return len;
+}
+char qqbuf[1];
+substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf));
+
+char inbuf[512];
+substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf));
+
+substdio sstext;
+char textbuf[1024];
+
+void maketo()
+/* expects line to be a return-path line. If it is and the format is valid */
+/* to is set to to the sender. Otherwise, to is left untouched. Assuming */
+/* to is empty to start with, it will remain empty if no sender is found. */
+{
+ unsigned int x, y;
+
+ if (case_startb(line.s,line.len,"return-path:")) {
+ x = 12 + byte_chr(line.s + 12,line.len-12,'<');
+ if (x != line.len) {
+ y = byte_rchr(line.s + x,line.len-x,'>');
+ if (y + x != line.len) {
+ if (!stralloc_copyb(&to,line.s+x+1,y-1)) die_nomem();
+ if (!stralloc_0(&to)) die_nomem();
+ } /* no return path-> no addressee. A NUL in the sender */
+ } /* is no worse than a faked sender, so no problem */
+ }
+}
+
+void main(argc,argv)
+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;
+ char *err;
+ char encin = '\0';
+ char szchar[2] = "-";
+ char *replyto = (char *) 0;
+ unsigned int start,confnum;
+ unsigned int pos,i;
+ int child;
+ int opt;
+ char *sendargs[4];
+ char *cp,*cpnext,*cpfirst,*cplast,*cpafter;
+ int wstat;
+
+ (void) umask(022);
+ sig_pipeignore();
+ when = now();
+
+ if (!stralloc_copys(&sendopt," -")) die_nomem();
+ while ((opt = getopt(argc,argv,"cCmMrRt:T:vV")) != opteof)
+ switch(opt) { /* pass on ezmlm-send options */
+ case 'c': /* ezmlm-send flags */
+ case 'C':
+ case 'r':
+ case 'R':
+ szchar[0] = (char) opt & 0xff;
+ if (!stralloc_append(&sendopt,szchar)) die_nomem();
+ break;
+ case 'm': flagmime = 1; break;
+ case 'M': flagmime = 0; break;
+ case 't':
+ case 'T': if (optarg) replyto = optarg; break;
+ case 'v':
+ case 'V': strerr_die2x(0,"ezmlm-moderate version: ",EZIDX_VERSION);
+ default:
+ die_usage();
+ }
+
+ dir = argv[optind++];
+ if (!dir) die_usage();
+
+ sender = env_get("SENDER");
+ if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
+ local = env_get("LOCAL");
+ if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
+ def = env_get("DEFAULT");
+
+ if (!*sender)
+ strerr_die2x(100,FATAL,ERR_BOUNCE);
+ if (!sender[str_chr(sender,'@')])
+ strerr_die2x(100,FATAL,ERR_ANONYMOUS);
+ if (str_equal(sender,"#@[]"))
+ strerr_die2x(100,FATAL,ERR_BOUNCE);
+
+ if (chdir(dir) == -1)
+ strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
+
+ switch(slurp("key",&key,32)) {
+ case -1:
+ strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
+ case 0:
+ strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST);
+ }
+ getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
+ getconf_line(&outhost,"outhost",1,FATAL,dir);
+ getconf_line(&outlocal,"outlocal",1,FATAL,dir);
+ set_cpoutlocal(&outlocal); /* for copy() */
+ set_cpouthost(&outhost); /* for copy() */
+
+ if (def) { /* qmail>=1.02 */
+ /* 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++;
+ } else { /* older versions of qmail */
+ getconf_line(&inlocal,"inlocal",1,FATAL,dir);
+ if (inlocal.len > str_len(local)) die_badaddr();
+ if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
+ action = local + inlocal.len;
+ if (*(action++) != '-') die_badaddr();
+ }
+
+ 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 = open_append("mod/lock");
+ if (fdlock == -1)
+ strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/mod/lock: ");
+ if (lock_ex(fdlock) == -1)
+ strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/mod/lock: ");
+
+ switch(checkfile(fnbase.s)) {
+ case 0:
+ strerr_die2x(100,FATAL,ERR_MOD_TIMEOUT);
+ case -1: /* only error if new request != action taken */
+ if (str_start(action,ACTION_ACCEPT))
+ strerr_die2x(0,INFO,ERR_MOD_ACCEPTED);
+ else
+ strerr_die2x(100,FATAL,ERR_MOD_ACCEPTED);
+ case -2:
+ if (str_start(action,ACTION_REJECT))
+ strerr_die2x(0,INFO,ERR_MOD_REJECTED);
+ else
+ strerr_die2x(100,FATAL,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,ERR_QMAIL_QUEUE);
+
+
+ /* Build recipient from msg return-path */
+ fd = open_read(fnmsg.s);
+ if (fd == -1) {
+ if (errno != error_noent)
+ strerr_die4sys(111,FATAL,ERR_OPEN,fnmsg.s,": ");
+ else
+ strerr_die2x(100,FATAL,ERR_MOD_TIMEOUT);
+ }
+ substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+
+ if (getln(&sstext,&line,&match,'\n') == -1 || !match)
+ strerr_die2sys(111,FATAL,ERR_READ_INPUT);
+ maketo(); /* extract SENDER from return-path */
+ /* Build message */
+ qmail_puts(&qq,"Mailing-List: ");
+ qmail_put(&qq,mailinglist.s,mailinglist.len);
+ if(getconf_line(&line,"listid",0,FATAL,dir)) {
+ qmail_puts(&qq,"\nList-ID: ");
+ qmail_put(&qq,line.s,line.len);
+ }
+ qmail_puts(&qq,"\nDate: ");
+ datetime_tai(&dt,when);
+ qmail_put(&qq,date,date822fmt(date,&dt));
+ qmail_puts(&qq,"Message-ID: <");
+ if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,(unsigned long) when)))
+ die_nomem();
+ if (!stralloc_append(&line,".")) die_nomem();
+ if (!stralloc_catb(&line,strnum,
+ fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
+ if (!stralloc_cats(&line,".ezmlm@")) die_nomem();
+ if (!stralloc_cat(&line,&outhost)) die_nomem();
+ if (!stralloc_0(&line)) die_nomem();
+ qmail_puts(&qq,line.s);
+ /* "unique" MIME boundary as hash of messageid */
+ cookie(boundary,"",0,"",line.s,"");
+ qmail_puts(&qq,">\nFrom: ");
+ if (!quote("ed,&outlocal)) die_nomem();
+ qmail_put(&qq,quoted.s,quoted.len);
+ qmail_puts(&qq,"-owner@");
+ qmail_put(&qq,outhost.s,outhost.len);
+ if (replyto) {
+ qmail_puts(&qq,"\nReply-To: ");
+ qmail_puts(&qq,replyto);
+ }
+ qmail_puts(&qq, "\nTo: ");
+ qmail_puts(&qq,to.s);
+ qmail_puts(&qq,"\nSubject: ");
+ qmail_puts(&qq,TXT_RETURNED_POST);
+ qmail_put(&qq,quoted.s,quoted.len);
+ qmail_puts(&qq,"@");
+ qmail_put(&qq,outhost.s,outhost.len);
+
+ if (flagmime) {
+ if (getconf_line(&charset,"charset",0,FATAL,dir)) {
+ if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
+ if (charset.s[charset.len - 1] == 'B' ||
+ charset.s[charset.len - 1] == 'Q') {
+ flagcd = charset.s[charset.len - 1];
+ charset.s[charset.len - 2] = '\0';
+ }
+ }
+ } else
+ if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
+ if (!stralloc_0(&charset)) die_nomem();
+ qmail_puts(&qq,"\nMIME-Version: 1.0\n");
+ qmail_puts(&qq,"Content-Type: multipart/mixed;\n\tboundary=");
+ qmail_put(&qq,boundary,COOKIE);
+ qmail_puts(&qq,"\n\n--");
+ qmail_put(&qq,boundary,COOKIE);
+ qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
+ qmail_puts(&qq,charset.s);
+ transferenc();
+ }
+ copy(&qq,"text/top",flagcd,FATAL);
+ copy(&qq,"text/mod-reject",flagcd,FATAL);
+
+ 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(&ssin,&line,&match,'\n') == -1)
+ strerr_die2sys(111,FATAL,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,FATAL);
+ else
+ decodeQ(text.s,text.len,&line,FATAL);
+ 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 >= 8) {
+ /* 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,FATAL);
+ qmail_put(&qq,line.s,line.len);
+ }
+ if (flagmime) {
+ qmail_puts(&qq,"\n--");
+ qmail_put(&qq,boundary,COOKIE);
+ qmail_puts(&qq,"\nContent-Type: message/rfc822\n\n");
+ } else
+ qmail_puts(&qq,"\n");
+ if (seek_begin(fd) == -1)
+ strerr_die4sys(111,FATAL,ERR_SEEK,fnmsg.s,": ");
+
+ substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
+ if (substdio_copy(&ssqq,&sstext) != 0)
+ strerr_die4sys(111,FATAL,ERR_READ,fnmsg.s,": ");
+ close(fd);
+
+ if (flagmime) {
+ qmail_puts(&qq,"\n--");
+ qmail_put(&qq,boundary,COOKIE);
+ qmail_puts(&qq,"--\n");
+ }
+
+ 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_die3x(111,FATAL,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_die4sys(111,FATAL,ERR_OPEN,fnmsg.s,": ");
+ else /* shouldn't happen since we've got lock */
+ strerr_die3x(100,FATAL,fnmsg.s,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,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_die4sys(111,FATAL,ERR_SEEK,fnmsg.s,": ");
+
+/* ##### NO REASON TO USE SH HERE ##### */
+ sendargs[0] = "/bin/sh";
+ sendargs[1] = "-c";
+ if (argc > optind) {
+ sendargs[2] = argv[optind];
+ } else {
+ if (!stralloc_copys(&send,auto_bin)) die_nomem();
+ if (!stralloc_cats(&send,"/ezmlm-send")) die_nomem();
+ if (sendopt.len > 2)
+ if (!stralloc_cat(&send,&sendopt)) die_nomem();
+ if (!stralloc_cats(&send," '")) die_nomem();
+ if (!stralloc_cats(&send,dir)) die_nomem();
+ if (!stralloc_cats(&send,"'")) die_nomem();
+ if (!stralloc_0(&send)) die_nomem();
+ sendargs[2] = send.s;
+ }
+ sendargs[3] = 0;
+
+ switch(child = fork()) {
+ case -1:
+ strerr_die2sys(111,FATAL,ERR_FORK);
+ case 0: /* child */
+ close(0);
+ dup(fd); /* make fnmsg.s stdin */
+ execv(*sendargs,sendargs);
+ if (errno == error_txtbsy || errno == error_nomem ||
+ errno == error_io)
+ strerr_die5sys(111,FATAL,ERR_EXECUTE,"/bin/sh -c ",sendargs[2],": ");
+ else
+ strerr_die5sys(100,FATAL,ERR_EXECUTE,"/bin/sh -c ",sendargs[2],": ");
+ }
+ /* parent */
+ wait_pid(&wstat,child);
+ close(fd);
+ if (wait_crashed(wstat))
+ strerr_die3x(111,FATAL,sendargs[2],ERR_CHILD_CRASHED);
+ switch(wait_exitcode(wstat)) {
+ case 100:
+ strerr_die2x(100,FATAL,"Fatal error from child");
+ case 111:
+ strerr_die2x(111,FATAL,"Temporary error from child");
+ case 0:
+ break;
+ default:
+ strerr_die2x(111,FATAL,"Unknown temporary error from 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);
+ }
+}