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