Frederik Vermeulen <qmail-outbox akrul inoa.net> 20060108

Documentation: http://inoa.net/qmail-outbox
Copyright: GPL
Bug reports: mailto:<qmail-outbox akrul inoa.net>


diff -urN ../netqmail-1.05/FILES ../netqmail-1.05-outbox/FILES
--- ../netqmail-1.05/FILES	Sat Apr 17 09:57:24 2004
+++ ../netqmail-1.05-outbox/FILES	Tue Nov  1 10:55:59 2005
@@ -91,6 +91,7 @@
 qmail-qread.8
 qmail-qstat.8
 qmail-queue.8
+qmail-outbox-queue.8
 qmail-remote.8
 qmail-rspawn.8
 qmail-send.9
@@ -122,6 +123,7 @@
 qmail-qread.c
 qmail-qstat.sh
 qmail-queue.c
+qmail-outbox-queue.c
 qmail-remote.c
 qmail-rspawn.c
 qmail-send.c
diff -urN ../netqmail-1.05/Makefile ../netqmail-1.05-outbox/Makefile
--- ../netqmail-1.05/Makefile	Sat Apr 17 09:57:24 2004
+++ ../netqmail-1.05-outbox/Makefile	Sat Oct 29 16:28:59 2005
@@ -799,7 +799,7 @@
 
 it: \
 qmail-local qmail-lspawn qmail-getpw qmail-remote qmail-rspawn \
-qmail-clean qmail-send qmail-start splogger qmail-queue qmail-inject \
+qmail-clean qmail-send qmail-start splogger qmail-queue qmail-outbox-queue qmail-inject \
 predate datemail mailsubj qmail-upq qmail-showctl qmail-newu \
 qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \
 qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \
@@ -927,7 +927,7 @@
 man: \
 qmail-local.0 qmail-lspawn.0 qmail-getpw.0 qmail-remote.0 \
 qmail-rspawn.0 qmail-clean.0 qmail-send.0 qmail-start.0 splogger.0 \
-qmail-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newu.0 \
+qmail-queue.0 qmail-outbox-queue.0 qmail-inject.0 mailsubj.0 qmail-showctl.0 qmail-newu.0 \
 qmail-pw2u.0 qmail-qread.0 qmail-qstat.0 qmail-tcpto.0 qmail-tcpok.0 \
 qmail-pop3d.0 qmail-popup.0 qmail-qmqpc.0 qmail-qmqpd.0 qmail-qmtpd.0 \
 qmail-smtpd.0 tcp-env.0 qmail-newmrh.0 qreceipt.0 qbiff.0 forward.0 \
@@ -1437,6 +1437,26 @@
 auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h
 	./compile qmail-queue.c
 
+qmail-outbox-queue: \
+load qmail-outbox-queue.o triggerpull.o fmtqfn.o now.o date822fmt.o \
+datetime.a seek.a ndelay.a open.a sig.a alloc.a substdio.a error.a \
+str.a fs.a auto_qmail.o auto_split.o auto_uids.o \
+stralloc.a getln.a case_diffb.o control.o fd.a wait.a
+	./load qmail-outbox-queue triggerpull.o fmtqfn.o now.o control.o \
+	date822fmt.o datetime.a seek.a ndelay.a open.a sig.a \
+	getln.a stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o \
+	auto_split.o auto_uids.o case_diffb.o fd.a wait.a
+
+qmail-outbox-queue.0: \
+qmail-outbox-queue.8
+	nroff -man qmail-outbox-queue.8 > qmail-outbox-queue.0
+
+qmail-outbox-queue.o: \
+compile qmail-outbox-queue.c readwrite.h sig.h exit.h open.h seek.h fmt.h \
+alloc.h substdio.h datetime.h now.h datetime.h triggerpull.h extra.h \
+auto_qmail.h auto_uids.h date822fmt.h fmtqfn.h
+	./compile qmail-outbox-queue.c
+
 qmail-remote: \
 load qmail-remote.o control.o constmap.o timeoutread.o timeoutwrite.o \
 timeoutconn.o tcpto.o now.o dns.o ip.o ipalloc.o ipme.o quote.o \
@@ -1769,14 +1789,14 @@
 qmail-inject.8 qmail-limits.9 qmail-local.8 qmail-log.5 \
 qmail-lspawn.8 qmail-newmrh.9 qmail-newu.9 qmail-pop3d.8 \
 qmail-popup.8 qmail-pw2u.9 qmail-qmqpc.8 qmail-qmqpd.8 qmail-qmtpd.8 \
-qmail-qread.8 qmail-qstat.8 qmail-queue.8 qmail-remote.8 \
+qmail-qread.8 qmail-qstat.8 qmail-queue.8 qmail-outbox-queue.8 qmail-remote.8 \
 qmail-rspawn.8 qmail-send.9 qmail-showctl.8 qmail-smtpd.8 \
 qmail-start.9 qmail-tcpok.8 qmail-tcpto.8 qmail-users.9 qmail.7 \
 qreceipt.1 splogger.8 tcp-env.1 config.sh config-fast.sh \
 qmail-clean.c qmail-getpw.c qmail-inject.c qmail-local.c \
 qmail-lspawn.c qmail-newmrh.c qmail-newu.c qmail-pop3d.c \
 qmail-popup.c qmail-pw2u.c qmail-qmqpc.c qmail-qmqpd.c qmail-qmtpd.c \
-qmail-qread.c qmail-qstat.sh qmail-queue.c qmail-remote.c \
+qmail-qread.c qmail-qstat.sh qmail-queue.c qmail-outbox-queue.c qmail-remote.c \
 qmail-rspawn.c qmail-send.c qmail-showctl.c qmail-smtpd.c \
 qmail-start.c qmail-tcpok.c qmail-tcpto.c spawn.c dnscname.c dnsfq.c \
 dnsip.c dnsmxip.c dnsptr.c hostname.c ipmeprint.c tcp-env.c \
diff -urN ../netqmail-1.05/TARGETS ../netqmail-1.05-outbox/TARGETS
--- ../netqmail-1.05/TARGETS	Mon Jun 15 10:53:16 1998
+++ ../netqmail-1.05-outbox/TARGETS	Tue Nov  1 10:55:19 2005
@@ -206,8 +206,10 @@
 syslog.lib
 splogger
 qmail-queue.o
+qmail-outbox-queue.o
 triggerpull.o
 qmail-queue
+qmail-outbox-queue
 qmail-inject.o
 headerbody.o
 hfield.o
@@ -334,6 +336,7 @@
 qmail-start.0
 splogger.0
 qmail-queue.0
+qmail-outbox-queue.0
 qmail-inject.0
 mailsubj.0
 qmail-showctl.0
diff -urN ../netqmail-1.05/hier.c ../netqmail-1.05-outbox/hier.c
--- ../netqmail-1.05/hier.c	Mon Jun 15 10:53:16 1998
+++ ../netqmail-1.05-outbox/hier.c	Tue Nov  1 10:54:36 2005
@@ -100,6 +100,7 @@
   c(auto_qmail,"doc","PIC.rem2local",auto_uido,auto_gidq,0644);
 
   c(auto_qmail,"bin","qmail-queue",auto_uidq,auto_gidq,04711);
+  c(auto_qmail,"bin","qmail-outbox-queue",auto_uidq,auto_gidq,04711);
   c(auto_qmail,"bin","qmail-lspawn",auto_uido,auto_gidq,0700);
   c(auto_qmail,"bin","qmail-start",auto_uido,auto_gidq,0700);
   c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711);
@@ -216,7 +217,9 @@
   c(auto_qmail,"man/man8","splogger.8",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat8","splogger.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-queue.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-outbox-queue.8",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat8","qmail-queue.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-outbox-queue.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-inject.8",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644);
diff -urN ../netqmail-1.05/install-big.c ../netqmail-1.05-outbox/install-big.c
--- ../netqmail-1.05/install-big.c	Mon Jun 15 10:53:16 1998
+++ ../netqmail-1.05-outbox/install-big.c	Tue Nov  1 10:56:42 2005
@@ -100,6 +100,7 @@
   c(auto_qmail,"doc","PIC.rem2local",auto_uido,auto_gidq,0644);
 
   c(auto_qmail,"bin","qmail-queue",auto_uidq,auto_gidq,04711);
+  c(auto_qmail,"bin","qmail-outbox-queue",auto_uidq,auto_gidq,04711);
   c(auto_qmail,"bin","qmail-lspawn",auto_uido,auto_gidq,0700);
   c(auto_qmail,"bin","qmail-start",auto_uido,auto_gidq,0700);
   c(auto_qmail,"bin","qmail-getpw",auto_uido,auto_gidq,0711);
@@ -216,7 +217,9 @@
   c(auto_qmail,"man/man8","splogger.8",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat8","splogger.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-queue.8",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/man8","qmail-outbox-queue.8",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat8","qmail-queue.0",auto_uido,auto_gidq,0644);
+  c(auto_qmail,"man/cat8","qmail-outbox-queue.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-inject.8",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/cat8","qmail-inject.0",auto_uido,auto_gidq,0644);
   c(auto_qmail,"man/man8","qmail-showctl.8",auto_uido,auto_gidq,0644);
diff -urN ../netqmail-1.05/qmail-outbox-queue.8 ../netqmail-1.05-outbox/qmail-outbox-queue.8
--- ../netqmail-1.05/qmail-outbox-queue.8	Thu Jan  1 00:00:00 1970
+++ ../netqmail-1.05-outbox/qmail-outbox-queue.8	Tue Nov  8 19:55:34 2005
@@ -0,0 +1,170 @@
+.TH qmail-outbox-queue 8
+.SH NAME
+qmail-outbox-queue \- queue a mail message for delivery
+.SH SYNOPSIS
+.B qmail-outbox-queue
+.SH DESCRIPTION
+.B qmail-outbox-queue
+reads a mail message from descriptor 0.
+It then reads envelope information from descriptor 1.
+It places the message into the outgoing queue
+for future delivery by
+BR qmail-send .
+
+The envelope information is
+an envelope sender address
+followed by a list of envelope recipient addresses.
+The sender address is preceded by the letter F
+and terminated by a 0 byte.
+Each recipient address is preceded by the letter T
+and terminated by a 0 byte.
+The list of recipient addresses is terminated by an extra 0 byte.
+If
+.B qmail-outbox-queue
+sees end-of-file before the extra 0 byte,
+it aborts without placing the message into the queue.
+
+Every envelope recipient address
+should contain a username,
+an @ sign,
+and a fully qualified domain name.
+
+.B qmail-outbox-queue
+always adds a
+.B Received
+line to the top of the message.
+In contrast to qmail-queue,
+.B qmail-outbox-queue
+inspects the message, looking for large attachments
+and piping them to
+.I bin/outboxer.
+The stdout of
+.I bin/outboxer 
+is expected to be a URL where the attachment can be 
+retrieved by the mail recipient.
+
+.SH "CONTROL FILES"
+.I maxattachlen
+Length of maximum attachment left alone by
+.B qmail-outbox-queue. 
+Absence of this file or a value 0 means outboxing is
+deactivated.
+
+.SH "FILESYSTEM RESTRICTIONS"
+.B qmail-outbox-queue
+imposes two constraints on the queue structure:
+each
+.B mess
+subdirectory must be in the same filesystem as the
+.B pid
+directory; and each
+.B todo
+subdirectory must be in the same filesystem as the
+.B intd
+directory.
+.SH "EXIT CODES"
+.B qmail-outbox-queue
+does not print diagnostics.
+It exits
+0 if
+it has successfully queued the message.
+It exits between 1 and 99 if
+it has failed to queue the message.
+
+All
+.B qmail-outbox-queue
+error codes between 11 and 40
+indicate permanent errors:
+.TP 5
+.B 11
+Address too long.
+.TP
+.B 31
+Mail server permanently refuses to send the message to any recipients.
+(Not used by
+.BR qmail-outbox-queue ,
+but can be used by programs offering the same interface.)
+.PP
+All other
+.B qmail-outbox-queue
+error codes indicate temporary errors:
+.TP 5
+.B 51
+Out of memory.
+.TP
+.B 52
+Timeout.
+.TP
+.B 53
+Write error; e.g., disk full.
+.TP
+.B 54
+Unable to read the message or envelope.
+.TP
+.B 55
+Unable to read a configuration file.
+(Not used by
+.BR qmail-outbox-queue .)
+.TP
+.B 56
+Problem making a network connection from this host.
+(Not used by
+.BR qmail-outbox-queue .)
+.TP
+.B 61
+Problem with the qmail home directory.
+.TP
+.B 62
+Problem with the queue directory.
+.TP
+.B 63
+Problem with queue/pid.
+.TP
+.B 64
+Problem with queue/mess.
+.TP
+.B 65
+Problem with queue/intd.
+.TP
+.B 66
+Problem with queue/todo.
+.TP
+.TP
+.B 68
+Problem with outboxing.
+.TP
+.B 71
+Mail server temporarily refuses to send the message to any recipients.
+(Not used by
+.BR qmail-outbox-queue .)
+.TP
+.B 72
+Connection to mail server timed out.
+(Not used by
+.BR qmail-outbox-queue .)
+.TP
+.B 73
+Connection to mail server rejected.
+(Not used by
+.BR qmail-outbox-queue .)
+.TP
+.B 74
+Connection to mail server succeeded,
+but communication failed.
+(Not used by
+.BR qmail-outbox-queue .)
+.TP
+.B 81
+Internal bug; e.g., segmentation fault.
+.TP
+.B 91
+Envelope format error.
+.SH "SEE ALSO"
+addresses(5),
+envelopes(5),
+qmail-header(5),
+qmail-inject(8),
+qmail-qmqpc(8),
+qmail-send(8),
+qmail-smtpd(8),
+qmail-queue(8)
diff -urN ../netqmail-1.05/qmail-outbox-queue.c ../netqmail-1.05-outbox/qmail-outbox-queue.c
--- ../netqmail-1.05/qmail-outbox-queue.c	Thu Jan  1 00:00:00 1970
+++ ../netqmail-1.05-outbox/qmail-outbox-queue.c	Fri Jan  6 21:43:30 2006
@@ -0,0 +1,404 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "readwrite.h"
+#include "sig.h"
+#include "exit.h"
+#include "open.h"
+#include "seek.h"
+#include "fmt.h"
+#include "alloc.h"
+#include "substdio.h"
+#include "datetime.h"
+#include "now.h"
+#include "triggerpull.h"
+#include "extra.h"
+#include "auto_qmail.h"
+#include "auto_uids.h"
+#include "date822fmt.h"
+#include "fmtqfn.h"
+#include "stralloc.h"
+#include "control.h"
+#include "wait.h"
+
+#define DEATH 86400 /* 24 hours; _must_ be below q-s's OSSIFIED (36 hours) */
+#define ADDR 1003
+
+int maxattachlen = 0;
+
+char inbuf[2048];
+struct substdio ssin;
+char outbuf[256];
+struct substdio ssout;
+char tempbuf[256];
+struct substdio sstemp;
+
+datetime_sec starttime;
+struct datetime dt;
+unsigned long mypid;
+unsigned long uid;
+char *pidfn;
+struct stat pidst;
+unsigned long messnum;
+char *messfn;
+char *todofn;
+char *intdfn;
+int messfd;
+int intdfd;
+int flagmademess = 0;
+int flagmadeintd = 0;
+
+void cleanup()
+{
+ if (flagmadeintd)
+  {
+   seek_trunc(intdfd,0);
+   if (unlink(intdfn) == -1) return;
+  }
+ if (flagmademess)
+  {
+   seek_trunc(messfd,0);
+   if (unlink(messfn) == -1) return;
+  }
+}
+
+void die(e) int e; { _exit(e); }
+void die_write() { cleanup(); die(53); }
+void die_read() { cleanup(); die(54); }
+void die_outbox() { cleanup(); die(68); }
+void sigalrm() { /* thou shalt not clean up here */ die(52); }
+void sigbug() { die(81); }
+
+unsigned int receivedlen;
+char *received;
+/* "Received: (qmail-queue invoked by alias); 26 Sep 1995 04:46:54 -0000\n" */
+
+static unsigned int receivedfmt(s)
+char *s;
+{
+ unsigned int i;
+ unsigned int len;
+ len = 0;
+ i = fmt_str(s,"Received: (qmail "); len += i; if (s) s += i;
+ i = fmt_ulong(s,mypid); len += i; if (s) s += i;
+ i = fmt_str(s," invoked "); len += i; if (s) s += i;
+ if (uid == auto_uida)
+  { i = fmt_str(s,"by alias"); len += i; if (s) s += i; }
+ else if (uid == auto_uidd)
+  { i = fmt_str(s,"from network"); len += i; if (s) s += i; }
+ else if (uid == auto_uids)
+  { i = fmt_str(s,"for bounce"); len += i; if (s) s += i; }
+ else
+  {
+   i = fmt_str(s,"by uid "); len += i; if (s) s += i;
+   i = fmt_ulong(s,uid); len += i; if (s) s += i;
+  }
+ i = fmt_str(s,"); "); len += i; if (s) s += i;
+ i = date822fmt(s,&dt); len += i; if (s) s += i;
+ return len;
+}
+
+void received_setup()
+{
+ receivedlen = receivedfmt((char *) 0);
+ received = alloc(receivedlen + 1);
+ if (!received) die(51);
+ receivedfmt(received);
+}
+
+unsigned int pidfmt(s,seq)
+char *s;
+unsigned long seq;
+{
+ unsigned int i;
+ unsigned int len;
+
+ len = 0;
+ i = fmt_str(s,"pid/"); len += i; if (s) s += i;
+ i = fmt_ulong(s,mypid); len += i; if (s) s += i;
+ i = fmt_str(s,"."); len += i; if (s) s += i;
+ i = fmt_ulong(s,starttime); len += i; if (s) s += i;
+ i = fmt_str(s,"."); len += i; if (s) s += i;
+ i = fmt_ulong(s,seq); len += i; if (s) s += i;
+ ++len; if (s) *s++ = 0;
+
+ return len;
+}
+
+char *fnnum(dirslash,flagsplit)
+char *dirslash;
+int flagsplit;
+{
+ char *s;
+
+ s = alloc(fmtqfn((char *) 0,dirslash,messnum,flagsplit));
+ if (!s) die(51);
+ fmtqfn(s,dirslash,messnum,flagsplit);
+ return s;
+}
+
+void pidopen()
+{
+ unsigned int len;
+ unsigned long seq;
+
+ seq = 1;
+ len = pidfmt((char *) 0,seq);
+ pidfn = alloc(len);
+ if (!pidfn) die(51);
+
+ for (seq = 1;seq < 10;++seq)
+  {
+   if (pidfmt((char *) 0,seq) > len) die(81); /* paranoia */
+   pidfmt(pidfn,seq);
+   messfd = open_excl(pidfn);
+   if (messfd != -1) return;
+  }
+
+ die(63);
+}
+
+char tmp[FMT_ULONG];
+
+void main()
+{
+ unsigned int len, match, mimefsm = 0;
+ char ch;
+ stralloc messline = {0};
+ stralloc boundary = {0};
+ int tempfd;
+
+ sig_blocknone();
+ sig_pipeignore();
+
+ umask(033);
+ if (chdir(auto_qmail) == -1) die(61);
+ control_readint(&maxattachlen,"control/maxattachlen");
+ if (chdir("queue") == -1) die(62);
+
+ mypid = getpid();
+ uid = getuid();
+ starttime = now();
+ datetime_tai(&dt,starttime);
+
+ received_setup();
+
+ sig_pipeignore();
+ sig_miscignore();
+ sig_alarmcatch(sigalrm);
+ sig_bugcatch(sigbug);
+
+ alarm(DEATH);
+
+ pidopen();
+ if (fstat(messfd,&pidst) == -1) die(63);
+
+ messnum = pidst.st_ino;
+ messfn = fnnum("mess/",1);
+ todofn = fnnum("todo/",0);
+ intdfn = fnnum("intd/",0);
+
+ if (link(pidfn,messfn) == -1) die(64);
+ if (unlink(pidfn) == -1) die(63);
+ flagmademess = 1;
+
+ substdio_fdbuf(&ssout,write,messfd,outbuf,sizeof(outbuf));
+ substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
+
+ if (substdio_bput(&ssout,received,receivedlen) == -1) die_write();
+
+ for (;;){
+   if (getln(&ssin,&messline,&match,'\n') != 0) die_read();
+   if (maxattachlen && match){ /* the attachmentsniffer */
+     if ((messline.len > 2) && !str_diffn(messline.s,"--",2)){               
+       if (!stralloc_copyb(&boundary,messline.s,messline.len)) die_write();
+       mimefsm = 1;
+     }else{
+      if ((mimefsm==1) && (messline.len > 14) && !str_diffn(messline.s,"Content-Type: ",14)){
+        int seenbase64 = 0; 
+        int seencontdisp = 0; 
+        int attachlen = messline.len;
+
+        if ((tempfd = open_excl(pidfn)) != -1){
+          substdio_fdbuf(&sstemp,write,tempfd,tempbuf,sizeof(tempbuf));
+          if (substdio_put(&sstemp,messline.s,messline.len)) die_write();
+          for (;;){
+            if (getln(&ssin,&messline,&match,'\n') != 0) die_read();
+            attachlen += messline.len;
+            if (!match){
+              mimefsm = 99;
+            }else{
+              if (mimefsm == 1){/* in header */
+                if (messline.s[0] == '\n'){
+                  if (seenbase64 && seencontdisp){
+                    mimefsm = 2;
+                  }else{
+                    mimefsm = 99;
+                  }
+                } 
+                if ((messline.len > 2) && !str_diffn(messline.s,"--",2)){
+                  mimefsm = 99;
+                }
+                if ((messline.len > 33) && !case_diffb(messline.s,33,"Content-Transfer-Encoding: base64")){
+                  seenbase64 = 1;
+                }
+                if ((messline.len > 32) && !case_diffb(messline.s,32,"Content-Disposition: attachment;")) {
+                  seencontdisp = 1;
+                } 
+              }else{ /* not in header anymore */
+                if ((messline.len >= boundary.len - 1) && !str_diffn(messline.s,boundary.s,boundary.len - 1)){
+                  if (attachlen >= maxattachlen){
+                    int pii[2];
+                    int pio[2];
+                    int pid, wstat;
+                    char *ch;
+                    char *outboxargs[2] = { "bin/outboxer", 0 };
+
+                    if (pipe(pii) == -1) die_outbox();
+                    if (pipe(pio) == -1) die_outbox();
+                    switch(pid = vfork()) {
+
+                      case -1: die_outbox();
+                      case 0:
+                             close(pii[1]);
+                             close(pio[0]);
+                             if (fd_move(0,pii[0]) == -1) die(70);
+                             if (fd_move(1,pio[1]) == -1) die(70);
+                             if (chdir(auto_qmail) == -1) die(61);
+                             execv(*outboxargs, outboxargs);
+                             die(68); 
+                    }
+                    close(pii[0]); close(pio[1]);
+                    substdio_flush(&sstemp);
+                    close(tempfd); 
+                    if ((tempfd = open_read(pidfn)) != -1){
+                      substdio_fdbuf(&sstemp,read,tempfd,tempbuf,sizeof(tempbuf));
+                      substdio_flush(&ssout);
+                      substdio_fdbuf(&ssout,write,pii[1],outbuf,sizeof(outbuf));
+                      substdio_flush(&ssout);
+                      switch(substdio_copy(&ssout,&sstemp)){
+                       case -2: die_read();
+                       case -3: die_write();
+                      }
+                      substdio_flush(&ssout);
+                    }else{
+                      die_read(); 
+                    }
+                    close(pii[1]);
+                    substdio_fdbuf(&ssout,write,messfd,outbuf,sizeof(outbuf));
+                    substdio_fdbuf(&sstemp,read,pio[0],tempbuf,sizeof(tempbuf));
+                    substdio_puts(&ssout, "Content-Type: text/plain\n\
+Content-Disposition: inline\n\
+\n\
+This location contained an attachment that has been detached by the\n\
+mail software and put for download at:\n\
+     "); 
+                    while (substdio_get(&sstemp,&ch,1) > 0){
+                      substdio_put(&ssout,&ch,1);
+                    }
+                    if ((wait_pid(&wstat,pid) != pid) || wait_crashed(wstat) || wait_exitcode(wstat)){
+                      die_outbox();
+                    }
+                    close(pio[0]);
+                    substdio_puts(&ssout, "\n\
+Beware that detaching the attachment may have impacted mail\n\
+signatures, virus scanning etc. This document is available at this\n\
+location for a limited amount of time. Make sure to save a local copy.\n\n");
+                     mimefsm = 100;
+                   }else{ /*if (attachlen >= maxattachlen)*/
+                     mimefsm = 99;
+                   }
+                 }
+               }/* if (mimefsm == 1) else*/
+             }
+            if (mimefsm < 99){
+              if (substdio_put(&sstemp,messline.s,messline.len) == -1) die_write();
+             }else{
+               if (mimefsm == 99){
+                 substdio_flush(&sstemp);
+                 close(tempfd); 
+                 if ((tempfd = open_read(pidfn)) != -1){
+                   substdio_fdbuf(&sstemp,read,tempfd,tempbuf,sizeof(tempbuf));
+                   switch(substdio_copy(&ssout,&sstemp)){
+                     case -2: die_read();
+                     case -3: die_write();
+                   }
+                 }else{
+                   die_read();
+                 }
+               } 
+               mimefsm = 0;
+               if ((messline.len > 2) && !str_diffn(messline.s,"--",2)){               
+                 if (!stralloc_copyb(&boundary,messline.s,messline.len)) die_write();
+                 mimefsm = 1;
+               }
+               break; 
+             }
+           } /* for (;;) */
+           if (unlink(pidfn) == -1) die(68);
+         }else{ /* no tempfd */
+           mimefsm = 0; /* nothing happened yet */
+         }
+        }else{ /* nothing happened yet */
+          mimefsm = 0;
+        }/* mimefsm == 1*/
+      } /* messline.s -- */
+    } /* if (match) */
+
+   if (substdio_put(&ssout,messline.s,messline.len) == -1) die_write();
+   if (!match) break;
+  }
+
+ if (substdio_flush(&ssout) == -1) die_write();
+ if (fsync(messfd) == -1) die_write();
+
+ intdfd = open_excl(intdfn);
+ if (intdfd == -1) die(65);
+ flagmadeintd = 1;
+
+ substdio_fdbuf(&ssout,write,intdfd,outbuf,sizeof(outbuf));
+ substdio_fdbuf(&ssin,read,1,inbuf,sizeof(inbuf));
+
+ if (substdio_bput(&ssout,"u",1) == -1) die_write();
+ if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,uid)) == -1) die_write();
+ if (substdio_bput(&ssout,"",1) == -1) die_write();
+
+ if (substdio_bput(&ssout,"p",1) == -1) die_write();
+ if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,mypid)) == -1) die_write();
+ if (substdio_bput(&ssout,"",1) == -1) die_write();
+
+ if (substdio_get(&ssin,&ch,1) < 1) die_read();
+ if (ch != 'F') die(91);
+ if (substdio_bput(&ssout,&ch,1) == -1) die_write();
+ for (len = 0;len < ADDR;++len)
+  {
+   if (substdio_get(&ssin,&ch,1) < 1) die_read();
+   if (substdio_put(&ssout,&ch,1) == -1) die_write();
+   if (!ch) break;
+  }
+ if (len >= ADDR) die(11);
+
+ if (substdio_bput(&ssout,QUEUE_EXTRA,QUEUE_EXTRALEN) == -1) die_write();
+
+ for (;;)
+  {
+   if (substdio_get(&ssin,&ch,1) < 1) die_read();
+   if (!ch) break;
+   if (ch != 'T') die(91);
+   if (substdio_bput(&ssout,&ch,1) == -1) die_write();
+   for (len = 0;len < ADDR;++len)
+    {
+     if (substdio_get(&ssin,&ch,1) < 1) die_read();
+     if (substdio_bput(&ssout,&ch,1) == -1) die_write();
+     if (!ch) break;
+    }
+   if (len >= ADDR) die(11);
+  }
+
+ if (substdio_flush(&ssout) == -1) die_write();
+ if (fsync(intdfd) == -1) die_write();
+
+ if (link(intdfn,todofn) == -1) die(66);
+
+ triggerpull();
+ die(0);
+}
