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
);