18 #include "auto_qmail.h"
20 #define FATAL "dot-forward: fatal: "
21 #define INFO "dot-forward: info: "
24 { strerr_die2x(111,FATAL,"out of memory"); }
26 { strerr_die2sys(111,FATAL,"unable to read controls: "); }
28 { strerr_die2sys(111,FATAL,"unable to run qq: "); }
30 { strerr_die2sys(111,FATAL,"unable to read message: "); }
36 if (!stralloc_0(&line)) die_nomem();
37 strerr_die3x(111,FATAL,"unable to parse this line: ",line.s);
58 int blindwrite(fd,buf,len)
59 int fd; char *buf; int len;
74 strerr_warn2("pipe through ",cmd,0);
79 strerr_die2sys(111,FATAL,"unable to create pipe: ");
81 switch (child = fork()) {
83 strerr_die2sys(111,FATAL,"unable to fork: ");
86 if (fd_move(0,pi[0]) == -1)
87 strerr_die2sys(111,FATAL,"unable to set fd: ");
88 args[0] = "/bin/sh"; args[1] = "-c"; args[2] = cmd; args[3] = 0;
91 strerr_die2sys(111,FATAL,"unable to run /bin/sh: ");
96 substdio_fdbuf(&ssmess,read,0,messbuf,sizeof messbuf);
97 substdio_fdbuf(&sschild,blindwrite,pi[1],childbuf,sizeof childbuf);
99 substdio_puts(&sschild,ufline);
100 substdio_puts(&sschild,rpline);
101 substdio_puts(&sschild,dtline);
102 if (substdio_copy(&sschild,&ssmess) != 0) die_readmess();
103 substdio_flush(&sschild);
107 wait_pid(&wstat,child);
108 if (wait_crashed(wstat))
109 strerr_die2x(111,FATAL,"child crashed");
111 switch(wait_exitcode(wstat)) {
113 case 64: case 65: case 70: case 76: case 77: case 78: case 112:
121 if (seek_begin(0) == -1)
122 strerr_die2sys(111,FATAL,"unable to rewind input: ");
125 stralloc targets = {0};
128 stralloc defaulthost = {0};
129 stralloc defaultdomain = {0};
130 stralloc plusdomain = {0};
137 fddir = open_read(".");
139 strerr_die2sys(111,FATAL,"unable to open current directory: ");
141 if (chdir(auto_qmail) == -1)
142 strerr_die4sys(111,FATAL,"unable to chdir to ",auto_qmail,": ");
144 r = control_readline(&me,"control/me");
145 if (r == -1) die_control();
146 if (!r) if (!stralloc_copys(&me,"me")) die_nomem();
148 r = control_readline(&defaultdomain,"control/defaultdomain");
149 if (r == -1) die_control();
150 if (!r) if (!stralloc_copy(&defaultdomain,&me)) die_nomem();
152 r = control_readline(&defaulthost,"control/defaulthost");
153 if (r == -1) die_control();
154 if (!r) if (!stralloc_copy(&defaulthost,&me)) die_nomem();
156 r = control_readline(&plusdomain,"control/plusdomain");
157 if (r == -1) die_control();
158 if (!r) if (!stralloc_copy(&plusdomain,&me)) die_nomem();
160 if (fchdir(fddir) == -1)
161 strerr_die2sys(111,FATAL,"unable to set current directory: ");
165 token822_alloc toks = {0};
166 token822_alloc tokaddr = {0};
167 stralloc address = {0};
175 token822_reverse(&tokaddr);
176 if (token822_unquote(&address,&tokaddr) != 1) die_nomem();
179 for (i = 0;i < tokaddr.len;++i)
180 if (tokaddr.t[i].type == TOKEN822_AT)
185 if (!address.len) return;
188 if (address.len == userlen)
189 if (!case_diffb(address.s,address.len,user)) {
196 if (address.len == userlen + 1 + hostlen)
197 if (!case_diffb(address.s,userlen,user))
198 if (address.s[userlen] == '@')
199 if (!case_diffb(address.s + userlen + 1,hostlen,host)) {
206 if (address.s[0] == '/') {
207 if (!stralloc_0(&address)) die_nomem();
208 strerr_die4x(111,FATAL,"file delivery ",address.s," not supported");
212 if (address.s[0] == '|') {
213 if (!stralloc_0(&address)) die_nomem();
220 if (!stralloc_cats(&address,"@")) die_nomem();
221 if (!stralloc_cat(&address,&defaulthost)) die_nomem();
223 if (address.s[address.len - 1] == '+') {
224 address.s[address.len - 1] = '.';
225 if (!stralloc_cat(&address,&plusdomain)) die_nomem();
228 for (i = 0;i < address.len;++i) if (address.s[i] == '@') j = i;
229 for (i = j;i < address.len;++i) if (address.s[i] == '.') break;
230 if (i == address.len) {
231 if (!stralloc_cats(&address,".")) die_nomem();
232 if (!stralloc_cat(&address,&defaultdomain)) die_nomem();
235 if (!stralloc_0(&address)) die_nomem();
237 if (!stralloc_cats(&targets,"T")) die_nomem();
238 if (!stralloc_cats(&targets,address.s)) die_nomem();
239 if (!stralloc_0(&targets)) die_nomem();
242 strerr_warn2("forward ",address.s,0);
249 struct token822 *beginning;
252 r = token822_parse(&toks,&line,&cbuf);
253 if (r == -1) die_nomem();
254 if (r == 0) die_parse();
257 t = toks.t + toks.len;
260 if (!token822_readyplus(&tokaddr,1)) die_nomem();
263 while (t > beginning)
264 switch((--t)->type) {
270 if (tokaddr.len) gotaddr();
271 while ((t > beginning) && (t[-1].type != TOKEN822_LEFT))
272 if (!token822_append(&tokaddr,--t)) die_nomem();
274 if (t <= beginning) die_parse();
276 while ((t > beginning) && ((t[-1].type == TOKEN822_COMMENT) || (t[-1].type == TOKEN822_ATOM) || (t[-1].type == TOKEN822_QUOTE) || (t[-1].type == TOKEN822_AT) || (t[-1].type == TOKEN822_DOT)))
280 case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL:
281 if (!wordok) if (tokaddr.len) gotaddr();
283 if (!token822_append(&tokaddr,t)) die_nomem();
285 case TOKEN822_COMMENT:
286 /* comment is lexically a space; shouldn't affect wordok */
289 if (tokaddr.len) gotaddr();
294 if (!token822_append(&tokaddr,t)) die_nomem();
297 if (tokaddr.len) gotaddr();
303 char strnum[FMT_ULONG];
305 int mywrite(fd,buf,len)
306 int fd; char *buf; int len;
308 qmail_put(&qq,buf,len);
313 substdio ssqq = SUBSTDIO_FDBUF(mywrite,-1,qqbuf,sizeof qqbuf);
326 if (errno == error_noent) return;
327 strerr_die4sys(111,FATAL,"unable to open ",fn,": ");
330 if (!stralloc_copys(&targets,"")) die_nomem();
334 substdio_fdbuf(&ss,read,fd,inbuf,sizeof inbuf);
337 if (getln(&ss,&line,&match,'\n') == -1)
338 strerr_die4sys(111,FATAL,"unable to read ",fn,": ");
339 if (!line.len) break;
340 if (line.s[0] != '#') parseline();
349 if (qmail_open(&qq) == -1)
350 strerr_die2sys(111,FATAL,"unable to run qmail-queue: ");
352 qmail_puts(&qq,dtline);
354 substdio_fdbuf(&ssmess,read,0,messbuf,sizeof messbuf);
355 if (substdio_copy(&ssqq,&ssmess) != 0) die_readmess();
356 substdio_flush(&ssqq);
358 qmail_from(&qq,sender);
359 qmail_put(&qq,targets.s,targets.len);
361 qqx = qmail_close(&qq);
363 strerr_die3x(100,FATAL,"unable to forward message: ",qqx + 1);
365 strerr_die3x(111,FATAL,"unable to forward message: ",qqx + 1);
366 strnum[fmt_ulong(strnum,qp)] = 0;
367 strerr_warn3(INFO,"qp ",strnum,0);
372 if (!flagdoit) strerr_warn1("direct delivery",0);
376 if (!flagdoit) strerr_warn2("skipping empty file ",fn,0);
391 while ((opt = getopt(argc,argv,"nN")) != opteof)
398 strerr_die1x(100,"dot-forward: usage: dot-forward [ -nN ] file ...");
402 ufline = env_get("UFLINE"); if (!ufline) ufline = "";
403 rpline = env_get("RPLINE"); if (!rpline) rpline = "";
404 dtline = env_get("DTLINE"); if (!dtline) dtline = "";
405 sender = env_get("NEWSENDER"); if (!sender) sender = "";
407 user = env_get("USER"); if (!user) user = "";
408 userlen = str_len(user);
409 host = env_get("HOST"); if (!host) host = "";
410 hostlen = str_len(host);
417 if (!flagdoit) strerr_warn1("direct delivery",0);