Commit | Line | Data |
---|---|---|
2117e02e MW |
1 | #include "sig.h" |
2 | #include "substdio.h" | |
3 | #include "stralloc.h" | |
4 | #include "subfd.h" | |
5 | #include "sgetopt.h" | |
6 | #include "getln.h" | |
7 | #include "alloc.h" | |
8 | #include "str.h" | |
9 | #include "fmt.h" | |
10 | #include "hfield.h" | |
11 | #include "token822.h" | |
12 | #include "control.h" | |
13 | #include "env.h" | |
14 | #include "gen_alloc.h" | |
15 | #include "gen_allocdefs.h" | |
16 | #include "error.h" | |
17 | #include "qmail.h" | |
18 | #include "now.h" | |
19 | #include "exit.h" | |
20 | #include "quote.h" | |
21 | #include "headerbody.h" | |
22 | #include "auto_qmail.h" | |
23 | #include "newfield.h" | |
212b6f5d | 24 | #include "constmap.h" |
2117e02e MW |
25 | |
26 | #define LINELEN 80 | |
27 | ||
28 | datetime_sec starttime; | |
29 | ||
30 | char *qmopts; | |
31 | int flagdeletesender = 0; | |
32 | int flagdeletefrom = 0; | |
33 | int flagdeletemessid = 0; | |
34 | int flagnamecomment = 0; | |
35 | int flaghackmess = 0; | |
36 | int flaghackrecip = 0; | |
37 | char *mailhost; | |
38 | char *mailuser; | |
39 | int mailusertokentype; | |
40 | char *mailrhost; | |
41 | char *mailruser; | |
42 | ||
43 | stralloc control_idhost = {0}; | |
44 | stralloc control_defaultdomain = {0}; | |
45 | stralloc control_defaulthost = {0}; | |
46 | stralloc control_plusdomain = {0}; | |
47 | ||
48 | stralloc sender = {0}; | |
49 | stralloc envsbuf = {0}; | |
50 | token822_alloc envs = {0}; | |
51 | int flagrh; | |
52 | ||
53 | int flagqueue; | |
54 | struct qmail qqt; | |
55 | ||
56 | void put(s,len) char *s; int len; | |
57 | { if (flagqueue) qmail_put(&qqt,s,len); else substdio_put(subfdout,s,len); } | |
58 | void puts(s) char *s; { put(s,str_len(s)); } | |
59 | ||
60 | void perm() { _exit(100); } | |
61 | void temp() { _exit(111); } | |
62 | void die_nomem() { | |
63 | substdio_putsflush(subfderr,"qmail-inject: fatal: out of memory\n"); temp(); } | |
64 | void die_invalid(sa) stralloc *sa; { | |
65 | substdio_putsflush(subfderr,"qmail-inject: fatal: invalid header field: "); | |
66 | substdio_putflush(subfderr,sa->s,sa->len); perm(); } | |
2117e02e MW |
67 | void die_qqt() { |
68 | substdio_putsflush(subfderr,"qmail-inject: fatal: unable to run qmail-queue\n"); temp(); } | |
69 | void die_chdir() { | |
70 | substdio_putsflush(subfderr,"qmail-inject: fatal: internal bug\n"); temp(); } | |
2117e02e MW |
71 | void die_read() { |
72 | if (errno == error_nomem) die_nomem(); | |
73 | substdio_putsflush(subfderr,"qmail-inject: fatal: read error\n"); temp(); } | |
74 | void doordie(sa,r) stralloc *sa; int r; { | |
75 | if (r == 1) return; if (r == -1) die_nomem(); | |
76 | substdio_putsflush(subfderr,"qmail-inject: fatal: unable to parse this line:\n"); | |
77 | substdio_putflush(subfderr,sa->s,sa->len); perm(); } | |
78 | ||
2117e02e MW |
79 | GEN_ALLOC_typedef(saa,stralloc,sa,len,a) |
80 | GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus) | |
81 | ||
82 | static stralloc sauninit = {0}; | |
83 | ||
84 | saa savedh = {0}; | |
85 | saa hrlist = {0}; | |
212b6f5d | 86 | saa tocclist = {0}; |
2117e02e MW |
87 | saa hrrlist = {0}; |
88 | saa reciplist = {0}; | |
89 | int flagresent; | |
90 | ||
91 | void exitnicely() | |
92 | { | |
212b6f5d MW |
93 | char *qqx; |
94 | ||
2117e02e MW |
95 | if (!flagqueue) substdio_flush(subfdout); |
96 | ||
97 | if (flagqueue) | |
98 | { | |
99 | int i; | |
100 | ||
101 | if (!stralloc_0(&sender)) die_nomem(); | |
102 | qmail_from(&qqt,sender.s); | |
103 | ||
104 | for (i = 0;i < reciplist.len;++i) | |
105 | { | |
106 | if (!stralloc_0(&reciplist.sa[i])) die_nomem(); | |
107 | qmail_to(&qqt,reciplist.sa[i].s); | |
108 | } | |
109 | if (flagrh) | |
110 | if (flagresent) | |
111 | for (i = 0;i < hrrlist.len;++i) | |
112 | { | |
113 | if (!stralloc_0(&hrrlist.sa[i])) die_nomem(); | |
114 | qmail_to(&qqt,hrrlist.sa[i].s); | |
115 | } | |
116 | else | |
117 | for (i = 0;i < hrlist.len;++i) | |
118 | { | |
119 | if (!stralloc_0(&hrlist.sa[i])) die_nomem(); | |
120 | qmail_to(&qqt,hrlist.sa[i].s); | |
121 | } | |
122 | ||
212b6f5d MW |
123 | qqx = qmail_close(&qqt); |
124 | if (*qqx) | |
125 | if (*qqx == 'D') { | |
126 | substdio_puts(subfderr,"qmail-inject: fatal: "); | |
127 | substdio_puts(subfderr,qqx + 1); | |
128 | substdio_puts(subfderr,"\n"); | |
129 | substdio_flush(subfderr); | |
130 | perm(); | |
131 | } | |
132 | else { | |
133 | substdio_puts(subfderr,"qmail-inject: fatal: "); | |
134 | substdio_puts(subfderr,qqx + 1); | |
135 | substdio_puts(subfderr,"\n"); | |
136 | substdio_flush(subfderr); | |
137 | temp(); | |
138 | } | |
2117e02e MW |
139 | } |
140 | ||
141 | _exit(0); | |
142 | } | |
143 | ||
144 | void savedh_append(h) | |
145 | stralloc *h; | |
146 | { | |
147 | if (!saa_readyplus(&savedh,1)) die_nomem(); | |
148 | savedh.sa[savedh.len] = sauninit; | |
149 | if (!stralloc_copy(savedh.sa + savedh.len,h)) die_nomem(); | |
150 | ++savedh.len; | |
151 | } | |
152 | ||
153 | void savedh_print() | |
154 | { | |
155 | int i; | |
156 | ||
157 | for (i = 0;i < savedh.len;++i) | |
158 | put(savedh.sa[i].s,savedh.sa[i].len); | |
159 | } | |
160 | ||
161 | stralloc defaultdomainbuf = {0}; | |
162 | token822_alloc defaultdomain = {0}; | |
163 | stralloc defaulthostbuf = {0}; | |
164 | token822_alloc defaulthost = {0}; | |
165 | stralloc plusdomainbuf = {0}; | |
166 | token822_alloc plusdomain = {0}; | |
167 | ||
168 | void rwroute(addr) | |
169 | token822_alloc *addr; | |
170 | { | |
171 | if (addr->t[addr->len - 1].type == TOKEN822_AT) | |
172 | while (addr->len) | |
173 | if (addr->t[--addr->len].type == TOKEN822_COLON) | |
174 | return; | |
175 | } | |
176 | ||
177 | void rwextraat(addr) | |
178 | token822_alloc *addr; | |
179 | { | |
180 | int i; | |
181 | if (addr->t[0].type == TOKEN822_AT) | |
182 | { | |
183 | --addr->len; | |
184 | for (i = 0;i < addr->len;++i) | |
185 | addr->t[i] = addr->t[i + 1]; | |
186 | } | |
187 | } | |
188 | ||
189 | void rwextradot(addr) | |
190 | token822_alloc *addr; | |
191 | { | |
192 | int i; | |
193 | if (addr->t[0].type == TOKEN822_DOT) | |
194 | { | |
195 | --addr->len; | |
196 | for (i = 0;i < addr->len;++i) | |
197 | addr->t[i] = addr->t[i + 1]; | |
198 | } | |
199 | } | |
200 | ||
201 | void rwnoat(addr) | |
202 | token822_alloc *addr; | |
203 | { | |
204 | int i; | |
205 | int shift; | |
206 | ||
207 | for (i = 0;i < addr->len;++i) | |
208 | if (addr->t[i].type == TOKEN822_AT) | |
209 | return; | |
210 | shift = defaulthost.len; | |
211 | if (!token822_readyplus(addr,shift)) die_nomem(); | |
212 | for (i = addr->len - 1;i >= 0;--i) | |
213 | addr->t[i + shift] = addr->t[i]; | |
214 | addr->len += shift; | |
215 | for (i = 0;i < shift;++i) | |
216 | addr->t[i] = defaulthost.t[shift - 1 - i]; | |
217 | } | |
218 | ||
219 | void rwnodot(addr) | |
220 | token822_alloc *addr; | |
221 | { | |
222 | int i; | |
223 | int shift; | |
224 | for (i = 0;i < addr->len;++i) | |
225 | { | |
226 | if (addr->t[i].type == TOKEN822_DOT) | |
227 | return; | |
228 | if (addr->t[i].type == TOKEN822_AT) | |
229 | break; | |
230 | } | |
231 | for (i = 0;i < addr->len;++i) | |
232 | { | |
233 | if (addr->t[i].type == TOKEN822_LITERAL) | |
234 | return; | |
235 | if (addr->t[i].type == TOKEN822_AT) | |
236 | break; | |
237 | } | |
238 | shift = defaultdomain.len; | |
239 | if (!token822_readyplus(addr,shift)) die_nomem(); | |
240 | for (i = addr->len - 1;i >= 0;--i) | |
241 | addr->t[i + shift] = addr->t[i]; | |
242 | addr->len += shift; | |
243 | for (i = 0;i < shift;++i) | |
244 | addr->t[i] = defaultdomain.t[shift - 1 - i]; | |
245 | } | |
246 | ||
247 | void rwplus(addr) | |
248 | token822_alloc *addr; | |
249 | { | |
250 | int i; | |
251 | int shift; | |
252 | ||
253 | if (addr->t[0].type != TOKEN822_ATOM) return; | |
254 | if (!addr->t[0].slen) return; | |
255 | if (addr->t[0].s[addr->t[0].slen - 1] != '+') return; | |
256 | ||
257 | --addr->t[0].slen; /* remove + */ | |
258 | ||
259 | shift = plusdomain.len; | |
260 | if (!token822_readyplus(addr,shift)) die_nomem(); | |
261 | for (i = addr->len - 1;i >= 0;--i) | |
262 | addr->t[i + shift] = addr->t[i]; | |
263 | addr->len += shift; | |
264 | for (i = 0;i < shift;++i) | |
265 | addr->t[i] = plusdomain.t[shift - 1 - i]; | |
266 | } | |
267 | ||
268 | void rwgeneric(addr) | |
269 | token822_alloc *addr; | |
270 | { | |
271 | if (!addr->len) return; /* don't rewrite <> */ | |
272 | if (addr->len >= 2) | |
273 | if (addr->t[1].type == TOKEN822_AT) | |
274 | if (addr->t[0].type == TOKEN822_LITERAL) | |
275 | if (!addr->t[0].slen) /* don't rewrite <foo@[]> */ | |
276 | return; | |
277 | rwroute(addr); | |
278 | if (!addr->len) return; /* <@foo:> -> <> */ | |
279 | rwextradot(addr); | |
280 | if (!addr->len) return; /* <.> -> <> */ | |
281 | rwextraat(addr); | |
282 | if (!addr->len) return; /* <@> -> <> */ | |
283 | rwnoat(addr); | |
284 | rwplus(addr); | |
285 | rwnodot(addr); | |
286 | } | |
287 | ||
288 | int setreturn(addr) | |
289 | token822_alloc *addr; | |
290 | { | |
291 | if (!sender.s) | |
292 | { | |
293 | token822_reverse(addr); | |
294 | if (token822_unquote(&sender,addr) != 1) die_nomem(); | |
295 | if (flaghackrecip) | |
296 | if (!stralloc_cats(&sender,"-@[]")) die_nomem(); | |
297 | token822_reverse(addr); | |
298 | } | |
299 | return 1; | |
300 | } | |
301 | ||
302 | int rwreturn(addr) | |
303 | token822_alloc *addr; | |
304 | { | |
305 | rwgeneric(addr); | |
306 | setreturn(addr); | |
307 | return 1; | |
308 | } | |
309 | ||
310 | int rwsender(addr) | |
311 | token822_alloc *addr; | |
312 | { | |
313 | rwgeneric(addr); | |
314 | return 1; | |
315 | } | |
316 | ||
212b6f5d | 317 | void rwappend(addr,xl) |
2117e02e MW |
318 | token822_alloc *addr; |
319 | saa *xl; | |
320 | { | |
2117e02e MW |
321 | token822_reverse(addr); |
322 | if (!saa_readyplus(xl,1)) die_nomem(); | |
323 | xl->sa[xl->len] = sauninit; | |
324 | if (token822_unquote(&xl->sa[xl->len],addr) != 1) die_nomem(); | |
325 | ++xl->len; | |
326 | token822_reverse(addr); | |
327 | } | |
328 | ||
329 | int rwhrr(addr) token822_alloc *addr; | |
212b6f5d | 330 | { rwgeneric(addr); rwappend(addr,&hrrlist); return 1; } |
2117e02e | 331 | int rwhr(addr) token822_alloc *addr; |
212b6f5d MW |
332 | { rwgeneric(addr); rwappend(addr,&hrlist); return 1; } |
333 | int rwtocc(addr) token822_alloc *addr; | |
334 | { rwgeneric(addr); rwappend(addr,&hrlist); rwappend(addr,&tocclist); return 1; } | |
2117e02e MW |
335 | |
336 | int htypeseen[H_NUM]; | |
337 | stralloc hfbuf = {0}; | |
338 | token822_alloc hfin = {0}; | |
339 | token822_alloc hfrewrite = {0}; | |
340 | token822_alloc hfaddr = {0}; | |
341 | ||
342 | void doheaderfield(h) | |
343 | stralloc *h; | |
344 | { | |
212b6f5d MW |
345 | int htype; |
346 | int (*rw)() = 0; | |
347 | ||
348 | htype = hfield_known(h->s,h->len); | |
349 | if (flagdeletefrom) if (htype == H_FROM) return; | |
350 | if (flagdeletemessid) if (htype == H_MESSAGEID) return; | |
351 | if (flagdeletesender) if (htype == H_RETURNPATH) return; | |
352 | ||
353 | if (htype) | |
354 | htypeseen[htype] = 1; | |
355 | else | |
356 | if (!hfield_valid(h->s,h->len)) | |
357 | die_invalid(h); | |
358 | ||
359 | switch(htype) { | |
360 | case H_TO: case H_CC: | |
361 | rw = rwtocc; break; | |
362 | case H_BCC: case H_APPARENTLYTO: | |
363 | rw = rwhr; break; | |
364 | case H_R_TO: case H_R_CC: case H_R_BCC: | |
365 | rw = rwhrr; break; | |
366 | case H_RETURNPATH: | |
367 | rw = rwreturn; break; | |
368 | case H_SENDER: case H_FROM: case H_REPLYTO: | |
369 | case H_RETURNRECEIPTTO: case H_ERRORSTO: | |
370 | case H_R_SENDER: case H_R_FROM: case H_R_REPLYTO: | |
371 | rw = rwsender; break; | |
2117e02e MW |
372 | } |
373 | ||
212b6f5d MW |
374 | if (rw) { |
375 | doordie(h,token822_parse(&hfin,h,&hfbuf)); | |
376 | doordie(h,token822_addrlist(&hfrewrite,&hfaddr,&hfin,rw)); | |
377 | if (token822_unparse(h,&hfrewrite,LINELEN) != 1) | |
378 | die_nomem(); | |
2117e02e | 379 | } |
212b6f5d MW |
380 | |
381 | if (htype == H_BCC) return; | |
382 | if (htype == H_R_BCC) return; | |
383 | if (htype == H_RETURNPATH) return; | |
384 | if (htype == H_CONTENTLENGTH) return; /* some things are just too stupid */ | |
385 | savedh_append(h); | |
2117e02e MW |
386 | } |
387 | ||
388 | void dobody(h) | |
389 | stralloc *h; | |
390 | { | |
391 | put(h->s,h->len); | |
392 | } | |
393 | ||
394 | stralloc torecip = {0}; | |
395 | token822_alloc tr = {0}; | |
396 | ||
397 | void dorecip(s) | |
398 | char *s; | |
399 | { | |
400 | if (!quote2(&torecip,s)) die_nomem(); | |
401 | switch(token822_parse(&tr,&torecip,&hfbuf)) | |
402 | { | |
403 | case -1: die_nomem(); | |
404 | case 0: | |
405 | substdio_puts(subfderr,"qmail-inject: fatal: unable to parse address: "); | |
406 | substdio_puts(subfderr,s); | |
407 | substdio_putsflush(subfderr,"\n"); | |
408 | perm(); | |
409 | } | |
410 | token822_reverse(&tr); | |
212b6f5d MW |
411 | rwgeneric(&tr); |
412 | rwappend(&tr,&reciplist); | |
2117e02e MW |
413 | } |
414 | ||
415 | stralloc defaultfrom = {0}; | |
416 | token822_alloc df = {0}; | |
417 | ||
418 | void defaultfrommake() | |
419 | { | |
420 | char *fullname; | |
421 | fullname = env_get("QMAILNAME"); | |
422 | if (!fullname) fullname = env_get("MAILNAME"); | |
423 | if (!fullname) fullname = env_get("NAME"); | |
424 | if (!token822_ready(&df,20)) die_nomem(); | |
425 | df.len = 0; | |
426 | df.t[df.len].type = TOKEN822_ATOM; | |
427 | df.t[df.len].s = "From"; | |
428 | df.t[df.len].slen = 4; | |
429 | ++df.len; | |
430 | df.t[df.len].type = TOKEN822_COLON; | |
431 | ++df.len; | |
432 | if (fullname && !flagnamecomment) | |
433 | { | |
434 | df.t[df.len].type = TOKEN822_QUOTE; | |
435 | df.t[df.len].s = fullname; | |
436 | df.t[df.len].slen = str_len(fullname); | |
437 | ++df.len; | |
438 | df.t[df.len].type = TOKEN822_LEFT; | |
439 | ++df.len; | |
440 | } | |
441 | df.t[df.len].type = mailusertokentype; | |
442 | df.t[df.len].s = mailuser; | |
443 | df.t[df.len].slen = str_len(mailuser); | |
444 | ++df.len; | |
445 | if (mailhost) | |
446 | { | |
447 | df.t[df.len].type = TOKEN822_AT; | |
448 | ++df.len; | |
449 | df.t[df.len].type = TOKEN822_ATOM; | |
450 | df.t[df.len].s = mailhost; | |
451 | df.t[df.len].slen = str_len(mailhost); | |
452 | ++df.len; | |
453 | } | |
454 | if (fullname && !flagnamecomment) | |
455 | { | |
456 | df.t[df.len].type = TOKEN822_RIGHT; | |
457 | ++df.len; | |
458 | } | |
459 | if (fullname && flagnamecomment) | |
460 | { | |
461 | df.t[df.len].type = TOKEN822_COMMENT; | |
462 | df.t[df.len].s = fullname; | |
463 | df.t[df.len].slen = str_len(fullname); | |
464 | ++df.len; | |
465 | } | |
466 | if (token822_unparse(&defaultfrom,&df,LINELEN) != 1) die_nomem(); | |
467 | doordie(&defaultfrom,token822_parse(&df,&defaultfrom,&hfbuf)); | |
468 | doordie(&defaultfrom,token822_addrlist(&hfrewrite,&hfaddr,&df,rwsender)); | |
469 | if (token822_unparse(&defaultfrom,&hfrewrite,LINELEN) != 1) die_nomem(); | |
470 | } | |
471 | ||
472 | stralloc defaultreturnpath = {0}; | |
473 | token822_alloc drp = {0}; | |
474 | stralloc hackedruser = {0}; | |
475 | char strnum[FMT_ULONG]; | |
476 | ||
477 | void dodefaultreturnpath() | |
478 | { | |
479 | if (!stralloc_copys(&hackedruser,mailruser)) die_nomem(); | |
480 | if (flaghackmess) | |
481 | { | |
482 | if (!stralloc_cats(&hackedruser,"-")) die_nomem(); | |
483 | if (!stralloc_catb(&hackedruser,strnum,fmt_ulong(strnum,(unsigned long) starttime))) die_nomem(); | |
484 | if (!stralloc_cats(&hackedruser,".")) die_nomem(); | |
485 | if (!stralloc_catb(&hackedruser,strnum,fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem(); | |
486 | } | |
487 | if (flaghackrecip) | |
488 | if (!stralloc_cats(&hackedruser,"-")) die_nomem(); | |
489 | if (!token822_ready(&drp,10)) die_nomem(); | |
490 | drp.len = 0; | |
491 | drp.t[drp.len].type = TOKEN822_ATOM; | |
492 | drp.t[drp.len].s = "Return-Path"; | |
493 | drp.t[drp.len].slen = 11; | |
494 | ++drp.len; | |
495 | drp.t[drp.len].type = TOKEN822_COLON; | |
496 | ++drp.len; | |
497 | drp.t[drp.len].type = TOKEN822_QUOTE; | |
498 | drp.t[drp.len].s = hackedruser.s; | |
499 | drp.t[drp.len].slen = hackedruser.len; | |
500 | ++drp.len; | |
501 | if (mailrhost) | |
502 | { | |
503 | drp.t[drp.len].type = TOKEN822_AT; | |
504 | ++drp.len; | |
505 | drp.t[drp.len].type = TOKEN822_ATOM; | |
506 | drp.t[drp.len].s = mailrhost; | |
507 | drp.t[drp.len].slen = str_len(mailrhost); | |
508 | ++drp.len; | |
509 | } | |
510 | if (token822_unparse(&defaultreturnpath,&drp,LINELEN) != 1) die_nomem(); | |
511 | doordie(&defaultreturnpath,token822_parse(&drp,&defaultreturnpath,&hfbuf)); | |
512 | doordie(&defaultreturnpath | |
513 | ,token822_addrlist(&hfrewrite,&hfaddr,&drp,rwreturn)); | |
514 | if (token822_unparse(&defaultreturnpath,&hfrewrite,LINELEN) != 1) die_nomem(); | |
515 | } | |
516 | ||
212b6f5d MW |
517 | int flagmft = 0; |
518 | stralloc mft = {0}; | |
519 | struct constmap mapmft; | |
520 | ||
521 | void mft_init() | |
522 | { | |
523 | char *x; | |
524 | int r; | |
525 | ||
526 | x = env_get("QMAILMFTFILE"); | |
527 | if (!x) return; | |
528 | ||
529 | r = control_readfile(&mft,x,0); | |
530 | if (r == -1) die_read(); /*XXX*/ | |
531 | if (!r) return; | |
532 | ||
533 | if (!constmap_init(&mapmft,mft.s,mft.len,0)) die_nomem(); | |
534 | flagmft = 1; | |
535 | } | |
536 | ||
537 | void finishmft() | |
538 | { | |
539 | int i; | |
540 | static stralloc sa = {0}; | |
541 | static stralloc sa2 = {0}; | |
542 | ||
543 | if (!flagmft) return; | |
544 | if (htypeseen[H_MAILFOLLOWUPTO]) return; | |
545 | ||
546 | for (i = 0;i < tocclist.len;++i) | |
547 | if (constmap(&mapmft,tocclist.sa[i].s,tocclist.sa[i].len)) | |
548 | break; | |
549 | ||
550 | if (i == tocclist.len) return; | |
551 | ||
552 | puts("Mail-Followup-To: "); | |
553 | i = tocclist.len; | |
554 | while (i--) { | |
555 | if (!stralloc_copy(&sa,&tocclist.sa[i])) die_nomem(); | |
556 | if (!stralloc_0(&sa)) die_nomem(); | |
557 | if (!quote2(&sa2,sa.s)) die_nomem(); | |
558 | put(sa2.s,sa2.len); | |
559 | if (i) puts(",\n "); | |
560 | } | |
561 | puts("\n"); | |
562 | } | |
563 | ||
2117e02e MW |
564 | void finishheader() |
565 | { | |
566 | flagresent = | |
567 | htypeseen[H_R_SENDER] || htypeseen[H_R_FROM] || htypeseen[H_R_REPLYTO] | |
568 | || htypeseen[H_R_TO] || htypeseen[H_R_CC] || htypeseen[H_R_BCC] | |
569 | || htypeseen[H_R_DATE] || htypeseen[H_R_MESSAGEID]; | |
570 | ||
571 | if (!sender.s) | |
572 | dodefaultreturnpath(); | |
573 | ||
574 | if (!flagqueue) | |
575 | { | |
576 | static stralloc sa = {0}; | |
577 | static stralloc sa2 = {0}; | |
578 | ||
579 | if (!stralloc_copy(&sa,&sender)) die_nomem(); | |
580 | if (!stralloc_0(&sa)) die_nomem(); | |
581 | if (!quote2(&sa2,sa.s)) die_nomem(); | |
582 | ||
583 | puts("Return-Path: <"); | |
584 | put(sa2.s,sa2.len); | |
585 | puts(">\n"); | |
586 | } | |
587 | ||
588 | /* could check at this point whether there are any recipients */ | |
589 | if (flagqueue) | |
590 | if (qmail_open(&qqt) == -1) die_qqt(); | |
591 | ||
592 | if (flagresent) | |
593 | { | |
594 | if (!htypeseen[H_R_DATE]) | |
595 | { | |
596 | if (!newfield_datemake(starttime)) die_nomem(); | |
597 | puts("Resent-"); | |
598 | put(newfield_date.s,newfield_date.len); | |
599 | } | |
600 | if (!htypeseen[H_R_MESSAGEID]) | |
601 | { | |
602 | if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem(); | |
603 | puts("Resent-"); | |
604 | put(newfield_msgid.s,newfield_msgid.len); | |
605 | } | |
606 | if (!htypeseen[H_R_FROM]) | |
607 | { | |
608 | defaultfrommake(); | |
609 | puts("Resent-"); | |
610 | put(defaultfrom.s,defaultfrom.len); | |
611 | } | |
612 | if (!htypeseen[H_R_TO] && !htypeseen[H_R_CC]) | |
613 | puts("Resent-Cc: recipient list not shown: ;\n"); | |
614 | } | |
615 | else | |
616 | { | |
617 | if (!htypeseen[H_DATE]) | |
618 | { | |
619 | if (!newfield_datemake(starttime)) die_nomem(); | |
620 | put(newfield_date.s,newfield_date.len); | |
621 | } | |
622 | if (!htypeseen[H_MESSAGEID]) | |
623 | { | |
624 | if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem(); | |
625 | put(newfield_msgid.s,newfield_msgid.len); | |
626 | } | |
627 | if (!htypeseen[H_FROM]) | |
628 | { | |
629 | defaultfrommake(); | |
630 | put(defaultfrom.s,defaultfrom.len); | |
631 | } | |
632 | if (!htypeseen[H_TO] && !htypeseen[H_CC]) | |
633 | puts("Cc: recipient list not shown: ;\n"); | |
212b6f5d | 634 | finishmft(); |
2117e02e MW |
635 | } |
636 | ||
637 | savedh_print(); | |
638 | } | |
639 | ||
640 | void getcontrols() | |
641 | { | |
642 | static stralloc sa = {0}; | |
643 | char *x; | |
644 | ||
212b6f5d MW |
645 | mft_init(); |
646 | ||
647 | if (chdir(auto_qmail) == -1) die_chdir(); | |
2117e02e MW |
648 | if (control_init() == -1) die_read(); |
649 | ||
650 | if (control_rldef(&control_defaultdomain,"control/defaultdomain",1,"defaultdomain") != 1) | |
651 | die_read(); | |
652 | x = env_get("QMAILDEFAULTDOMAIN"); | |
653 | if (x) if (!stralloc_copys(&control_defaultdomain,x)) die_nomem(); | |
654 | if (!stralloc_copys(&sa,".")) die_nomem(); | |
655 | if (!stralloc_cat(&sa,&control_defaultdomain)) die_nomem(); | |
656 | doordie(&sa,token822_parse(&defaultdomain,&sa,&defaultdomainbuf)); | |
657 | ||
658 | if (control_rldef(&control_defaulthost,"control/defaulthost",1,"defaulthost") != 1) | |
659 | die_read(); | |
660 | x = env_get("QMAILDEFAULTHOST"); | |
661 | if (x) if (!stralloc_copys(&control_defaulthost,x)) die_nomem(); | |
662 | if (!stralloc_copys(&sa,"@")) die_nomem(); | |
663 | if (!stralloc_cat(&sa,&control_defaulthost)) die_nomem(); | |
664 | doordie(&sa,token822_parse(&defaulthost,&sa,&defaulthostbuf)); | |
665 | ||
666 | if (control_rldef(&control_plusdomain,"control/plusdomain",1,"plusdomain") != 1) | |
667 | die_read(); | |
668 | x = env_get("QMAILPLUSDOMAIN"); | |
669 | if (x) if (!stralloc_copys(&control_plusdomain,x)) die_nomem(); | |
670 | if (!stralloc_copys(&sa,".")) die_nomem(); | |
671 | if (!stralloc_cat(&sa,&control_plusdomain)) die_nomem(); | |
672 | doordie(&sa,token822_parse(&plusdomain,&sa,&plusdomainbuf)); | |
673 | ||
674 | if (control_rldef(&control_idhost,"control/idhost",1,"idhost") != 1) | |
675 | die_read(); | |
676 | x = env_get("QMAILIDHOST"); | |
677 | if (x) if (!stralloc_copys(&control_idhost,x)) die_nomem(); | |
678 | } | |
679 | ||
680 | #define RECIP_DEFAULT 1 | |
681 | #define RECIP_ARGS 2 | |
682 | #define RECIP_HEADER 3 | |
683 | #define RECIP_AH 4 | |
684 | ||
685 | void main(argc,argv) | |
686 | int argc; | |
687 | char **argv; | |
688 | { | |
689 | int i; | |
690 | int opt; | |
691 | int recipstrategy; | |
692 | ||
693 | sig_pipeignore(); | |
694 | ||
695 | starttime = now(); | |
696 | ||
697 | qmopts = env_get("QMAILINJECT"); | |
698 | if (qmopts) | |
699 | while (*qmopts) | |
700 | switch(*qmopts++) | |
701 | { | |
702 | case 'c': flagnamecomment = 1; break; | |
703 | case 's': flagdeletesender = 1; break; | |
704 | case 'f': flagdeletefrom = 1; break; | |
705 | case 'i': flagdeletemessid = 1; break; | |
706 | case 'r': flaghackrecip = 1; break; | |
707 | case 'm': flaghackmess = 1; break; | |
708 | } | |
709 | ||
710 | mailhost = env_get("QMAILHOST"); | |
711 | if (!mailhost) mailhost = env_get("MAILHOST"); | |
712 | mailrhost = env_get("QMAILSHOST"); | |
713 | if (!mailrhost) mailrhost = mailhost; | |
714 | ||
715 | mailuser = env_get("QMAILUSER"); | |
716 | if (!mailuser) mailuser = env_get("MAILUSER"); | |
717 | if (!mailuser) mailuser = env_get("USER"); | |
718 | if (!mailuser) mailuser = env_get("LOGNAME"); | |
719 | if (!mailuser) mailuser = "anonymous"; | |
720 | mailusertokentype = TOKEN822_ATOM; | |
721 | if (quote_need(mailuser,str_len(mailuser))) mailusertokentype = TOKEN822_QUOTE; | |
722 | mailruser = env_get("QMAILSUSER"); | |
723 | if (!mailruser) mailruser = mailuser; | |
724 | ||
725 | for (i = 0;i < H_NUM;++i) htypeseen[i] = 0; | |
726 | ||
727 | recipstrategy = RECIP_DEFAULT; | |
728 | flagqueue = 1; | |
729 | ||
2117e02e MW |
730 | getcontrols(); |
731 | ||
732 | if (!saa_readyplus(&hrlist,1)) die_nomem(); | |
212b6f5d | 733 | if (!saa_readyplus(&tocclist,1)) die_nomem(); |
2117e02e MW |
734 | if (!saa_readyplus(&hrrlist,1)) die_nomem(); |
735 | if (!saa_readyplus(&reciplist,1)) die_nomem(); | |
736 | ||
737 | while ((opt = getopt(argc,argv,"aAhHnNf:")) != opteof) | |
738 | switch(opt) | |
739 | { | |
740 | case 'a': recipstrategy = RECIP_ARGS; break; | |
741 | case 'A': recipstrategy = RECIP_DEFAULT; break; | |
742 | case 'h': recipstrategy = RECIP_HEADER; break; | |
743 | case 'H': recipstrategy = RECIP_AH; break; | |
744 | case 'n': flagqueue = 0; break; | |
745 | case 'N': flagqueue = 1; break; | |
746 | case 'f': | |
747 | if (!quote2(&sender,optarg)) die_nomem(); | |
748 | doordie(&sender,token822_parse(&envs,&sender,&envsbuf)); | |
749 | token822_reverse(&envs); | |
750 | rwgeneric(&envs); | |
751 | token822_reverse(&envs); | |
752 | if (token822_unquote(&sender,&envs) != 1) die_nomem(); | |
753 | break; | |
754 | case '?': | |
755 | default: | |
756 | perm(); | |
757 | } | |
758 | argc -= optind; | |
759 | argv += optind; | |
760 | ||
761 | if (recipstrategy == RECIP_DEFAULT) | |
762 | recipstrategy = (*argv ? RECIP_ARGS : RECIP_HEADER); | |
763 | ||
764 | if (recipstrategy != RECIP_HEADER) | |
765 | while (*argv) | |
766 | dorecip(*argv++); | |
767 | ||
768 | flagrh = (recipstrategy != RECIP_ARGS); | |
769 | ||
770 | if (headerbody(subfdin,doheaderfield,finishheader,dobody) == -1) | |
771 | die_read(); | |
772 | exitnicely(); | |
773 | } |