22 #define FATAL "fastforward: fatal: "
26 strerr_die1x(100,"fastforward: usage: fastforward [ -nNpP ] data.cdb");
30 strerr_die2x(111,FATAL,"out of memory");
38 substdio_put(subfderr,&ch,1);
47 if (ch < 32) ch = '_';
48 substdio_put(subfderr,&ch,1);
56 int qqwrite(fd,buf,len) int fd; char *buf; int len;
58 qmail_put(&qq,buf,len);
62 substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof qqbuf);
65 substdio ssmess = SUBSTDIO_FDBUF(read,0,messbuf,sizeof messbuf);
68 int flagpassthrough = 0;
71 stralloc sender = {0};
72 stralloc programs = {0};
73 stralloc forward = {0};
78 stralloc mailinglist = {0};
88 if (!stralloc_copys(&mailinglist,"")) nomem();
92 strerr_die4sys(111,FATAL,"unable to read ",fn,": ");
93 if (fstat(fd,&st) == -1)
94 strerr_die4sys(111,FATAL,"unable to stat ",fn,": ");
95 if ((st.st_mode & 0444) != 0444)
96 strerr_die3x(111,FATAL,fn," is not world-readable");
97 if (slurpclose(fd,&mailinglist,1024) == -1)
98 strerr_die4sys(111,FATAL,"unable to read ",fn,": ");
101 for (j = 0;j < mailinglist.len;++j)
102 if (!mailinglist.s[j]) {
103 if ((mailinglist.s[i] == '.') || (mailinglist.s[i] == '/')) {
104 if (!stralloc_cats(&todo,mailinglist.s + i)) nomem();
105 if (!stralloc_0(&todo)) nomem();
107 else if ((mailinglist.s[i] == '&') && (j - i < 900)) {
108 if (!stralloc_cats(&todo,mailinglist.s + i)) nomem();
109 if (!stralloc_0(&todo)) nomem();
123 strerr_die4sys(111,FATAL,"unable to read ",fncdb,": ");
126 int findtarget(flagwild,prepend,addr)
134 if (!stralloc_copys(&key,prepend)) nomem();
135 if (!stralloc_cats(&key,addr)) nomem();
136 case_lowerb(key.s,key.len);
138 r = cdb_seek(fdcdb,key.s,key.len,&dlen);
139 if (r == -1) cdbreaderror();
142 if (!flagwild) return 0;
143 at = str_rchr(addr,'@');
144 if (!addr[at]) return 0;
146 if (!stralloc_copys(&key,prepend)) nomem();
147 if (!stralloc_cats(&key,addr + at)) nomem();
148 case_lowerb(key.s,key.len);
150 r = cdb_seek(fdcdb,key.s,key.len,&dlen);
151 if (r == -1) cdbreaderror();
154 if (!stralloc_copys(&key,prepend)) nomem();
155 if (!stralloc_catb(&key,addr,at + 1)) nomem();
156 case_lowerb(key.s,key.len);
158 r = cdb_seek(fdcdb,key.s,key.len,&dlen);
159 if (r == -1) cdbreaderror();
165 int gettarget(flagwild,prepend,addr)
170 if (!findtarget(flagwild,prepend,addr)) return 0;
172 if (!stralloc_ready(&data,(unsigned int) dlen)) nomem();
174 if (cdb_bread(fdcdb,data.s,data.len) == -1) cdbreaderror();
190 substdio_flush(subfderr);
208 switch(child = vfork()) {
210 strerr_die2sys(111,FATAL,"unable to fork: ");
214 strerr_die4sys(111,FATAL,"unable to run ",arg,": ");
217 wait_pid(&wstat,child);
218 if (wait_crashed(wstat))
219 strerr_die4sys(111,FATAL,"child crashed in ",arg,": ");
221 switch(wait_exitcode(wstat)) {
222 case 64: case 65: case 70: case 76: case 77: case 78: case 112:
223 case 100: _exit(100);
228 if (seek_begin(0) == -1)
229 strerr_die2sys(111,FATAL,"unable to rewind input: ");
237 for (j = 0;j < data.len;++j)
239 if ((data.s[i] == '|') || (data.s[i] == '!'))
240 doprogram(data.s + i);
241 else if ((data.s[i] == '.') || (data.s[i] == '/')) {
242 if (!stralloc_cats(&todo,data.s + i)) nomem();
243 if (!stralloc_0(&todo)) nomem();
245 else if ((data.s[i] == '&') && (j - i < 900)) {
246 if (!stralloc_cats(&todo,data.s + i)) nomem();
247 if (!stralloc_0(&todo)) nomem();
257 if (!findtarget(0,"?",addr))
258 if (gettarget(0,":",addr)) {
262 if (!stralloc_cats(&forward,addr)) nomem();
263 if (!stralloc_0(&forward)) nomem();
266 void doorigrecip(addr)
270 if ((sender.len != 4) || byte_diff(sender.s,4,"#@[]"))
271 if (gettarget(1,"?",addr))
272 if (!stralloc_copy(&sender,&data)) nomem();
273 if (!gettarget(1,":",addr))
277 strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)");
281 stralloc recipient = {0};
294 dtline = env_get("DTLINE");
295 if (!dtline) dtline = "";
297 x = env_get("SENDER");
298 if (!x) x = "original envelope sender";
299 if (!stralloc_copys(&sender,x)) nomem();
301 if (!stralloc_copys(&forward,"")) nomem();
302 if (!strset_init(&done)) nomem();
304 while ((opt = getopt(argc,argv,"nNpPdD")) != opteof)
306 case 'n': flagdeliver = 0; break;
307 case 'N': flagdeliver = 1; break;
308 case 'p': flagpassthrough = 1; break;
309 case 'P': flagpassthrough = 0; break;
310 case 'd': flagdefault = 1; break;
311 case 'D': flagdefault = 0; break;
318 fdcdb = open_read(fncdb);
319 if (fdcdb == -1) cdbreaderror();
323 x = env_get("DEFAULT");
324 if (!x) x = env_get("EXT");
325 if (!x) strerr_die2x(100,FATAL,"$DEFAULT or $EXT must be set");
326 if (!stralloc_copys(&recipient,x)) nomem();
327 if (!stralloc_cats(&recipient,"@")) nomem();
329 if (!x) strerr_die2x(100,FATAL,"$HOST must be set");
330 if (!stralloc_cats(&recipient,x)) nomem();
331 if (!stralloc_0(&recipient)) nomem();
335 x = env_get("RECIPIENT");
336 if (!x) strerr_die2x(100,FATAL,"$RECIPIENT must be set");
338 if (!strset_add(&done,x)) nomem();
343 while ((i > 0) && todo.s[i - 1]) --i;
346 if (strset_in(&done,todo.s + i)) continue;
348 x = alloc(str_len(todo.s + i) + 1);
350 str_copy(x,todo.s + i);
351 if (!strset_add(&done,x)) nomem();
356 else if ((*x == '.') || (*x == '/'))
364 print("no forwarding\n");
365 substdio_flush(subfderr);
367 _exit(flagpassthrough ? 99 : 0);
370 if (!stralloc_0(&sender)) nomem();
376 while (forward.len) {
378 while ((i > 0) && forward.s[i - 1]) --i;
381 printsafe(forward.s + i);
384 substdio_flush(subfderr);
385 _exit(flagpassthrough ? 99 : 0);
388 if (qmail_open(&qq) == -1)
389 strerr_die2sys(111,FATAL,"unable to fork: ");
390 qmail_puts(&qq,dtline);
391 if (substdio_copy(&ssqq,&ssmess) != 0)
392 strerr_die2sys(111,FATAL,"unable to read message: ");
393 substdio_flush(&ssqq);
394 qp[fmt_ulong(qp,qmail_qp(&qq))] = 0;
396 qmail_from(&qq,sender.s);
398 while (forward.len) {
400 while ((i > 0) && forward.s[i - 1]) --i;
402 qmail_to(&qq,forward.s + i);
405 x = qmail_close(&qq);
406 if (*x) strerr_die2x(*x == 'D' ? 100 : 111,FATAL,x + 1);
407 strerr_die2x(flagpassthrough ? 99 : 0,"fastforward: qp ",qp);