summaryrefslogtreecommitdiff
path: root/qsmhook.c
diff options
context:
space:
mode:
authorJohn Denker <jsd@av8n.com>2012-06-01 18:58:45 -0700
committerJohn Denker <jsd@av8n.com>2012-06-01 18:58:45 -0700
commitb732a73bc773789894466b0e5320b2f1fe42c7e9 (patch)
tree385358983f064a1f10a5080b33a3ba13010886db /qsmhook.c
parent634d365a03cb0581a062cd3cf4db9ae69f1cde26 (diff)
original, as downloaded from http://www.qmail.org/netqmail-1.06.tar.gz
Diffstat (limited to 'qsmhook.c')
-rw-r--r--qsmhook.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/qsmhook.c b/qsmhook.c
new file mode 100644
index 0000000..d5b38aa
--- /dev/null
+++ b/qsmhook.c
@@ -0,0 +1,137 @@
+#include "fd.h"
+#include "stralloc.h"
+#include "readwrite.h"
+#include "sgetopt.h"
+#include "wait.h"
+#include "env.h"
+#include "byte.h"
+#include "str.h"
+#include "alloc.h"
+#include "exit.h"
+#include "fork.h"
+#include "case.h"
+#include "subfd.h"
+#include "error.h"
+#include "substdio.h"
+#include "sig.h"
+
+void die(e,s) int e; char *s; { substdio_putsflush(subfderr,s); _exit(e); }
+void die_usage() { die(100,"qsmhook: fatal: incorrect usage\n"); }
+void die_temp() { die(111,"qsmhook: fatal: temporary problem\n"); }
+void die_read() { die(111,"qsmhook: fatal: unable to read message\n"); }
+void die_badcmd() { die(100,"qsmhook: fatal: command not found\n"); }
+
+int flagrpline = 0; char *rpline;
+int flagufline = 1; char *ufline;
+int flagdtline = 0; char *dtline;
+char *host;
+char *sender;
+char *recip;
+
+stralloc newarg = {0};
+
+substdio ssout;
+char outbuf[SUBSTDIO_OUTSIZE];
+substdio ssin;
+char inbuf[SUBSTDIO_INSIZE];
+
+void main(argc,argv)
+int argc;
+char **argv;
+{
+ int pid;
+ int wstat;
+ int pi[2];
+ int opt;
+ char **arg;
+ char *x;
+ int i;
+ int flagesc;
+
+ sig_pipeignore();
+
+ if (!(dtline = env_get("DTLINE"))) die_usage();
+ if (!(rpline = env_get("RPLINE"))) die_usage();
+ if (!(ufline = env_get("UFLINE"))) die_usage();
+ if (!(recip = env_get("LOCAL"))) die_usage();
+ if (!(host = env_get("HOST"))) die_usage();
+ if (!(sender = env_get("SENDER"))) die_usage();
+
+ while ((opt = getopt(argc,argv,"DFlMmnPsx:")) != opteof)
+ switch(opt)
+ {
+ case 'D': case 'F': case 'M': break; /* be serious */
+ case 'l': flagdtline = 1; break; /* also return-receipt-to? blech */
+ case 'm': break; /* we only handle one recipient anyway */
+ case 'n': flagufline = 0; break;
+ case 's': break; /* could call quote() otherwise, i suppose... */
+ case 'P': flagrpline = 1; break;
+ case 'x':
+ if (case_starts(recip,optarg))
+ recip += str_len(optarg);
+ break;
+ default:
+ _exit(100);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!*argv) die_usage();
+
+ for (arg = argv;x = *arg;++arg)
+ {
+ if (!stralloc_copys(&newarg,"")) die_temp();
+ flagesc = 0;
+ for (i = 0;x[i];++i)
+ if (flagesc)
+ {
+ switch(x[i])
+ {
+ case '%': if (!stralloc_cats(&newarg,"%")) die_temp(); break;
+ case 'g': if (!stralloc_cats(&newarg,sender)) die_temp(); break;
+ case 'h': if (!stralloc_cats(&newarg,host)) die_temp(); break;
+ case 'u': if (!stralloc_cats(&newarg,recip)) die_temp(); break;
+ }
+ flagesc = 0;
+ }
+ else
+ if (x[i] == '%')
+ flagesc = 1;
+ else
+ if (!stralloc_append(&newarg,&x[i])) die_temp();
+ if (!stralloc_0(&newarg)) die_temp();
+ i = str_len(newarg.s) + 1;
+ if (!(x = alloc(i))) die_temp();
+ byte_copy(x,i,newarg.s);
+ *arg = x;
+ }
+
+ if (pipe(pi) == -1) die_temp();
+
+ switch(pid = fork())
+ {
+ case -1:
+ die_temp();
+ case 0:
+ close(pi[1]);
+ if (fd_move(0,pi[0]) == -1) die_temp();
+ sig_pipedefault();
+ execvp(*argv,argv);
+ if (error_temp(errno)) die_temp();
+ die_badcmd();
+ }
+ close(pi[0]);
+
+ substdio_fdbuf(&ssout,write,pi[1],outbuf,sizeof(outbuf));
+ substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
+ if (flagufline) substdio_bputs(&ssout,ufline);
+ if (flagrpline) substdio_bputs(&ssout,rpline);
+ if (flagdtline) substdio_bputs(&ssout,dtline);
+ if (substdio_copy(&ssout,&ssin) == -2) die_read();
+ substdio_flush(&ssout);
+ close(pi[1]);
+
+ if (wait_pid(&wstat,pid) == -1) die_temp();
+ if (wait_crashed(wstat)) die_temp();
+ _exit(wait_exitcode(wstat));
+}