debian/rules: Use `git' potty wrapper.
[qmail] / qsmhook.c
CommitLineData
2117e02e
MW
1#include "fd.h"
2#include "stralloc.h"
3#include "readwrite.h"
4#include "sgetopt.h"
5#include "wait.h"
6#include "env.h"
7#include "byte.h"
8#include "str.h"
9#include "alloc.h"
10#include "exit.h"
11#include "fork.h"
12#include "case.h"
13#include "subfd.h"
14#include "error.h"
15#include "substdio.h"
16#include "sig.h"
17
18void die(e,s) int e; char *s; { substdio_putsflush(subfderr,s); _exit(e); }
19void die_usage() { die(100,"qsmhook: fatal: incorrect usage\n"); }
20void die_temp() { die(111,"qsmhook: fatal: temporary problem\n"); }
21void die_read() { die(111,"qsmhook: fatal: unable to read message\n"); }
22void die_badcmd() { die(100,"qsmhook: fatal: command not found\n"); }
23
24int flagrpline = 0; char *rpline;
25int flagufline = 1; char *ufline;
26int flagdtline = 0; char *dtline;
27char *host;
28char *sender;
29char *recip;
30
31stralloc newarg = {0};
32
33substdio ssout;
34char outbuf[SUBSTDIO_OUTSIZE];
35substdio ssin;
36char inbuf[SUBSTDIO_INSIZE];
37
38void main(argc,argv)
39int argc;
40char **argv;
41{
42 int pid;
43 int wstat;
44 int pi[2];
45 int opt;
46 char **arg;
47 char *x;
48 int i;
49 int flagesc;
50
51 sig_pipeignore();
52
53 if (!(dtline = env_get("DTLINE"))) die_usage();
54 if (!(rpline = env_get("RPLINE"))) die_usage();
55 if (!(ufline = env_get("UFLINE"))) die_usage();
56 if (!(recip = env_get("LOCAL"))) die_usage();
57 if (!(host = env_get("HOST"))) die_usage();
58 if (!(sender = env_get("SENDER"))) die_usage();
59
60 while ((opt = getopt(argc,argv,"DFlMmnPsx:")) != opteof)
61 switch(opt)
62 {
63 case 'D': case 'F': case 'M': break; /* be serious */
64 case 'l': flagdtline = 1; break; /* also return-receipt-to? blech */
65 case 'm': break; /* we only handle one recipient anyway */
66 case 'n': flagufline = 0; break;
67 case 's': break; /* could call quote() otherwise, i suppose... */
68 case 'P': flagrpline = 1; break;
69 case 'x':
70 if (case_starts(recip,optarg))
71 recip += str_len(optarg);
72 break;
73 default:
74 _exit(100);
75 }
76 argc -= optind;
77 argv += optind;
78
79 if (!*argv) die_usage();
80
81 for (arg = argv;x = *arg;++arg)
82 {
83 if (!stralloc_copys(&newarg,"")) die_temp();
84 flagesc = 0;
85 for (i = 0;x[i];++i)
86 if (flagesc)
87 {
88 switch(x[i])
89 {
90 case '%': if (!stralloc_cats(&newarg,"%")) die_temp(); break;
91 case 'g': if (!stralloc_cats(&newarg,sender)) die_temp(); break;
92 case 'h': if (!stralloc_cats(&newarg,host)) die_temp(); break;
93 case 'u': if (!stralloc_cats(&newarg,recip)) die_temp(); break;
94 }
95 flagesc = 0;
96 }
97 else
98 if (x[i] == '%')
99 flagesc = 1;
100 else
101 if (!stralloc_append(&newarg,&x[i])) die_temp();
102 if (!stralloc_0(&newarg)) die_temp();
103 i = str_len(newarg.s) + 1;
104 if (!(x = alloc(i))) die_temp();
105 byte_copy(x,i,newarg.s);
106 *arg = x;
107 }
108
109 if (pipe(pi) == -1) die_temp();
110
111 switch(pid = fork())
112 {
113 case -1:
114 die_temp();
115 case 0:
116 close(pi[1]);
117 if (fd_move(0,pi[0]) == -1) die_temp();
118 sig_pipedefault();
119 execvp(*argv,argv);
120 if (error_temp(errno)) die_temp();
121 die_badcmd();
122 }
123 close(pi[0]);
124
125 substdio_fdbuf(&ssout,write,pi[1],outbuf,sizeof(outbuf));
126 substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
127 if (flagufline) substdio_bputs(&ssout,ufline);
128 if (flagrpline) substdio_bputs(&ssout,rpline);
129 if (flagdtline) substdio_bputs(&ssout,dtline);
130 if (substdio_copy(&ssout,&ssin) == -2) die_read();
131 substdio_flush(&ssout);
132 close(pi[1]);
133
134 if (wait_pid(&wstat,pid) == -1) die_temp();
135 if (wait_crashed(wstat)) die_temp();
136 _exit(wait_exitcode(wstat));
137}