14 #include "gen_alloc.h"
15 #include "gen_allocdefs.h"
21 #include "headerbody.h"
22 #include "auto_qmail.h"
28 datetime_sec starttime;
31 int flagdeletesender = 0;
32 int flagdeletefrom = 0;
33 int flagdeletemessid = 0;
34 int flagnamecomment = 0;
36 int flaghackrecip = 0;
39 int mailusertokentype;
43 stralloc control_idhost = {0};
44 stralloc control_defaultdomain = {0};
45 stralloc control_defaulthost = {0};
46 stralloc control_plusdomain = {0};
48 stralloc sender = {0};
49 stralloc envsbuf = {0};
50 token822_alloc envs = {0};
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)); }
60 void perm() { _exit(100); }
61 void temp() { _exit(111); }
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(); }
68 substdio_putsflush(subfderr,"qmail-inject: fatal: unable to run qmail-queue\n"); temp(); }
70 substdio_putsflush(subfderr,"qmail-inject: fatal: internal bug\n"); temp(); }
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(); }
79 GEN_ALLOC_typedef(saa,stralloc,sa,len,a)
80 GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus)
82 static stralloc sauninit = {0};
95 if (!flagqueue) substdio_flush(subfdout);
101 if (!stralloc_0(&sender)) die_nomem();
102 qmail_from(&qqt,sender.s);
104 for (i = 0;i < reciplist.len;++i)
106 if (!stralloc_0(&reciplist.sa[i])) die_nomem();
107 qmail_to(&qqt,reciplist.sa[i].s);
111 for (i = 0;i < hrrlist.len;++i)
113 if (!stralloc_0(&hrrlist.sa[i])) die_nomem();
114 qmail_to(&qqt,hrrlist.sa[i].s);
117 for (i = 0;i < hrlist.len;++i)
119 if (!stralloc_0(&hrlist.sa[i])) die_nomem();
120 qmail_to(&qqt,hrlist.sa[i].s);
123 qqx = qmail_close(&qqt);
126 substdio_puts(subfderr,"qmail-inject: fatal: ");
127 substdio_puts(subfderr,qqx + 1);
128 substdio_puts(subfderr,"\n");
129 substdio_flush(subfderr);
133 substdio_puts(subfderr,"qmail-inject: fatal: ");
134 substdio_puts(subfderr,qqx + 1);
135 substdio_puts(subfderr,"\n");
136 substdio_flush(subfderr);
144 void savedh_append(h)
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();
157 for (i = 0;i < savedh.len;++i)
158 put(savedh.sa[i].s,savedh.sa[i].len);
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};
169 token822_alloc *addr;
171 if (addr->t[addr->len - 1].type == TOKEN822_AT)
173 if (addr->t[--addr->len].type == TOKEN822_COLON)
178 token822_alloc *addr;
181 if (addr->t[0].type == TOKEN822_AT)
184 for (i = 0;i < addr->len;++i)
185 addr->t[i] = addr->t[i + 1];
189 void rwextradot(addr)
190 token822_alloc *addr;
193 if (addr->t[0].type == TOKEN822_DOT)
196 for (i = 0;i < addr->len;++i)
197 addr->t[i] = addr->t[i + 1];
202 token822_alloc *addr;
207 for (i = 0;i < addr->len;++i)
208 if (addr->t[i].type == TOKEN822_AT)
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];
215 for (i = 0;i < shift;++i)
216 addr->t[i] = defaulthost.t[shift - 1 - i];
220 token822_alloc *addr;
224 for (i = 0;i < addr->len;++i)
226 if (addr->t[i].type == TOKEN822_DOT)
228 if (addr->t[i].type == TOKEN822_AT)
231 for (i = 0;i < addr->len;++i)
233 if (addr->t[i].type == TOKEN822_LITERAL)
235 if (addr->t[i].type == TOKEN822_AT)
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];
243 for (i = 0;i < shift;++i)
244 addr->t[i] = defaultdomain.t[shift - 1 - i];
248 token822_alloc *addr;
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;
257 --addr->t[0].slen; /* remove + */
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];
264 for (i = 0;i < shift;++i)
265 addr->t[i] = plusdomain.t[shift - 1 - i];
269 token822_alloc *addr;
271 if (!addr->len) return; /* don't rewrite <> */
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@[]> */
278 if (!addr->len) return; /* <@foo:> -> <> */
280 if (!addr->len) return; /* <.> -> <> */
282 if (!addr->len) return; /* <@> -> <> */
289 token822_alloc *addr;
293 token822_reverse(addr);
294 if (token822_unquote(&sender,addr) != 1) die_nomem();
296 if (!stralloc_cats(&sender,"-@[]")) die_nomem();
297 token822_reverse(addr);
303 token822_alloc *addr;
311 token822_alloc *addr;
317 void rwappend(addr,xl)
318 token822_alloc *addr;
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();
326 token822_reverse(addr);
329 int rwhrr(addr) token822_alloc *addr;
330 { rwgeneric(addr); rwappend(addr,&hrrlist); return 1; }
331 int rwhr(addr) token822_alloc *addr;
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; }
336 int htypeseen[H_NUM];
337 stralloc hfbuf = {0};
338 token822_alloc hfin = {0};
339 token822_alloc hfrewrite = {0};
340 token822_alloc hfaddr = {0};
342 void doheaderfield(h)
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;
354 htypeseen[htype] = 1;
356 if (!hfield_valid(h->s,h->len))
360 case H_TO: case H_CC:
362 case H_BCC: case H_APPARENTLYTO:
364 case H_R_TO: case H_R_CC: case H_R_BCC:
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;
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)
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 */
394 stralloc torecip = {0};
395 token822_alloc tr = {0};
400 if (!quote2(&torecip,s)) die_nomem();
401 switch(token822_parse(&tr,&torecip,&hfbuf))
403 case -1: die_nomem();
405 substdio_puts(subfderr,"qmail-inject: fatal: unable to parse address: ");
406 substdio_puts(subfderr,s);
407 substdio_putsflush(subfderr,"\n");
410 token822_reverse(&tr);
412 rwappend(&tr,&reciplist);
415 stralloc defaultfrom = {0};
416 token822_alloc df = {0};
418 void defaultfrommake()
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();
426 df.t[df.len].type = TOKEN822_ATOM;
427 df.t[df.len].s = "From";
428 df.t[df.len].slen = 4;
430 df.t[df.len].type = TOKEN822_COLON;
432 if (fullname && !flagnamecomment)
434 df.t[df.len].type = TOKEN822_QUOTE;
435 df.t[df.len].s = fullname;
436 df.t[df.len].slen = str_len(fullname);
438 df.t[df.len].type = TOKEN822_LEFT;
441 df.t[df.len].type = mailusertokentype;
442 df.t[df.len].s = mailuser;
443 df.t[df.len].slen = str_len(mailuser);
447 df.t[df.len].type = TOKEN822_AT;
449 df.t[df.len].type = TOKEN822_ATOM;
450 df.t[df.len].s = mailhost;
451 df.t[df.len].slen = str_len(mailhost);
454 if (fullname && !flagnamecomment)
456 df.t[df.len].type = TOKEN822_RIGHT;
459 if (fullname && flagnamecomment)
461 df.t[df.len].type = TOKEN822_COMMENT;
462 df.t[df.len].s = fullname;
463 df.t[df.len].slen = str_len(fullname);
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();
472 stralloc defaultreturnpath = {0};
473 token822_alloc drp = {0};
474 stralloc hackedruser = {0};
475 char strnum[FMT_ULONG];
477 void dodefaultreturnpath()
479 if (!stralloc_copys(&hackedruser,mailruser)) die_nomem();
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();
488 if (!stralloc_cats(&hackedruser,"-")) die_nomem();
489 if (!token822_ready(&drp,10)) die_nomem();
491 drp.t[drp.len].type = TOKEN822_ATOM;
492 drp.t[drp.len].s = "Return-Path";
493 drp.t[drp.len].slen = 11;
495 drp.t[drp.len].type = TOKEN822_COLON;
497 drp.t[drp.len].type = TOKEN822_QUOTE;
498 drp.t[drp.len].s = hackedruser.s;
499 drp.t[drp.len].slen = hackedruser.len;
503 drp.t[drp.len].type = TOKEN822_AT;
505 drp.t[drp.len].type = TOKEN822_ATOM;
506 drp.t[drp.len].s = mailrhost;
507 drp.t[drp.len].slen = str_len(mailrhost);
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();
519 struct constmap mapmft;
526 x = env_get("QMAILMFTFILE");
529 r = control_readfile(&mft,x,0);
530 if (r == -1) die_read(); /*XXX*/
533 if (!constmap_init(&mapmft,mft.s,mft.len,0)) die_nomem();
540 static stralloc sa = {0};
541 static stralloc sa2 = {0};
543 if (!flagmft) return;
544 if (htypeseen[H_MAILFOLLOWUPTO]) return;
546 for (i = 0;i < tocclist.len;++i)
547 if (constmap(&mapmft,tocclist.sa[i].s,tocclist.sa[i].len))
550 if (i == tocclist.len) return;
552 puts("Mail-Followup-To: ");
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();
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];
572 dodefaultreturnpath();
576 static stralloc sa = {0};
577 static stralloc sa2 = {0};
579 if (!stralloc_copy(&sa,&sender)) die_nomem();
580 if (!stralloc_0(&sa)) die_nomem();
581 if (!quote2(&sa2,sa.s)) die_nomem();
583 puts("Return-Path: <");
588 /* could check at this point whether there are any recipients */
590 if (qmail_open(&qqt) == -1) die_qqt();
594 if (!htypeseen[H_R_DATE])
596 if (!newfield_datemake(starttime)) die_nomem();
598 put(newfield_date.s,newfield_date.len);
600 if (!htypeseen[H_R_MESSAGEID])
602 if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem();
604 put(newfield_msgid.s,newfield_msgid.len);
606 if (!htypeseen[H_R_FROM])
610 put(defaultfrom.s,defaultfrom.len);
612 if (!htypeseen[H_R_TO] && !htypeseen[H_R_CC])
613 puts("Resent-Cc: recipient list not shown: ;\n");
617 if (!htypeseen[H_DATE])
619 if (!newfield_datemake(starttime)) die_nomem();
620 put(newfield_date.s,newfield_date.len);
622 if (!htypeseen[H_MESSAGEID])
624 if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem();
625 put(newfield_msgid.s,newfield_msgid.len);
627 if (!htypeseen[H_FROM])
630 put(defaultfrom.s,defaultfrom.len);
632 if (!htypeseen[H_TO] && !htypeseen[H_CC])
633 puts("Cc: recipient list not shown: ;\n");
642 static stralloc sa = {0};
647 if (chdir(auto_qmail) == -1) die_chdir();
648 if (control_init() == -1) die_read();
650 if (control_rldef(&control_defaultdomain,"control/defaultdomain",1,"defaultdomain") != 1)
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));
658 if (control_rldef(&control_defaulthost,"control/defaulthost",1,"defaulthost") != 1)
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));
666 if (control_rldef(&control_plusdomain,"control/plusdomain",1,"plusdomain") != 1)
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));
674 if (control_rldef(&control_idhost,"control/idhost",1,"idhost") != 1)
676 x = env_get("QMAILIDHOST");
677 if (x) if (!stralloc_copys(&control_idhost,x)) die_nomem();
680 #define RECIP_DEFAULT 1
682 #define RECIP_HEADER 3
697 qmopts = env_get("QMAILINJECT");
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;
710 mailhost = env_get("QMAILHOST");
711 if (!mailhost) mailhost = env_get("MAILHOST");
712 mailrhost = env_get("QMAILSHOST");
713 if (!mailrhost) mailrhost = mailhost;
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;
725 for (i = 0;i < H_NUM;++i) htypeseen[i] = 0;
727 recipstrategy = RECIP_DEFAULT;
732 if (!saa_readyplus(&hrlist,1)) die_nomem();
733 if (!saa_readyplus(&tocclist,1)) die_nomem();
734 if (!saa_readyplus(&hrrlist,1)) die_nomem();
735 if (!saa_readyplus(&reciplist,1)) die_nomem();
737 while ((opt = getopt(argc,argv,"aAhHnNf:")) != opteof)
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;
747 if (!quote2(&sender,optarg)) die_nomem();
748 doordie(&sender,token822_parse(&envs,&sender,&envsbuf));
749 token822_reverse(&envs);
751 token822_reverse(&envs);
752 if (token822_unquote(&sender,&envs) != 1) die_nomem();
761 if (recipstrategy == RECIP_DEFAULT)
762 recipstrategy = (*argv ? RECIP_ARGS : RECIP_HEADER);
764 if (recipstrategy != RECIP_HEADER)
768 flagrh = (recipstrategy != RECIP_ARGS);
770 if (headerbody(subfdin,doheaderfield,finishheader,dobody) == -1)