14 #include "gen_alloc.h"
15 #include "gen_allocdefs.h"
21 #include "headerbody.h"
22 #include "auto_qmail.h"
27 datetime_sec starttime;
30 int flagdeletesender = 0;
31 int flagdeletefrom = 0;
32 int flagdeletemessid = 0;
33 int flagnamecomment = 0;
35 int flaghackrecip = 0;
38 int mailusertokentype;
42 stralloc control_idhost = {0};
43 stralloc control_defaultdomain = {0};
44 stralloc control_defaulthost = {0};
45 stralloc control_plusdomain = {0};
47 stralloc sender = {0};
48 stralloc envsbuf = {0};
49 token822_alloc envs = {0};
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)); }
59 void perm() { _exit(100); }
60 void temp() { _exit(111); }
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(); }
67 substdio_putsflush(subfderr,"qmail-inject: fatal: unable to exec qmail-queue\n"); temp(); }
69 substdio_putsflush(subfderr,"qmail-inject: fatal: unable to run qmail-queue\n"); temp(); }
71 substdio_putsflush(subfderr,"qmail-inject: fatal: internal bug\n"); temp(); }
73 substdio_putsflush(subfderr,"qmail-inject: fatal: internal bug\n"); temp(); }
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(); }
83 substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue lost communications link\n"); temp(); }
85 substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue died\n"); temp(); }
87 substdio_putsflush(subfderr,"qmail-inject: fatal: qmail-queue unable to write message to disk; disk full?\n"); temp(); }
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(); }
95 GEN_ALLOC_typedef(saa,stralloc,sa,len,a)
96 GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus)
98 static stralloc sauninit = {0};
108 if (!flagqueue) substdio_flush(subfdout);
114 if (!stralloc_0(&sender)) die_nomem();
115 qmail_from(&qqt,sender.s);
117 for (i = 0;i < reciplist.len;++i)
119 if (!stralloc_0(&reciplist.sa[i])) die_nomem();
120 qmail_to(&qqt,reciplist.sa[i].s);
124 for (i = 0;i < hrrlist.len;++i)
126 if (!stralloc_0(&hrrlist.sa[i])) die_nomem();
127 qmail_to(&qqt,hrrlist.sa[i].s);
130 for (i = 0;i < hrlist.len;++i)
132 if (!stralloc_0(&hrlist.sa[i])) die_nomem();
133 qmail_to(&qqt,hrlist.sa[i].s);
136 switch(qmail_close(&qqt))
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();
154 void savedh_append(h)
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();
167 for (i = 0;i < savedh.len;++i)
168 put(savedh.sa[i].s,savedh.sa[i].len);
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};
179 token822_alloc *addr;
181 if (addr->t[addr->len - 1].type == TOKEN822_AT)
183 if (addr->t[--addr->len].type == TOKEN822_COLON)
188 token822_alloc *addr;
191 if (addr->t[0].type == TOKEN822_AT)
194 for (i = 0;i < addr->len;++i)
195 addr->t[i] = addr->t[i + 1];
199 void rwextradot(addr)
200 token822_alloc *addr;
203 if (addr->t[0].type == TOKEN822_DOT)
206 for (i = 0;i < addr->len;++i)
207 addr->t[i] = addr->t[i + 1];
212 token822_alloc *addr;
217 for (i = 0;i < addr->len;++i)
218 if (addr->t[i].type == TOKEN822_AT)
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];
225 for (i = 0;i < shift;++i)
226 addr->t[i] = defaulthost.t[shift - 1 - i];
230 token822_alloc *addr;
234 for (i = 0;i < addr->len;++i)
236 if (addr->t[i].type == TOKEN822_DOT)
238 if (addr->t[i].type == TOKEN822_AT)
241 for (i = 0;i < addr->len;++i)
243 if (addr->t[i].type == TOKEN822_LITERAL)
245 if (addr->t[i].type == TOKEN822_AT)
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];
253 for (i = 0;i < shift;++i)
254 addr->t[i] = defaultdomain.t[shift - 1 - i];
258 token822_alloc *addr;
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;
267 --addr->t[0].slen; /* remove + */
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];
274 for (i = 0;i < shift;++i)
275 addr->t[i] = plusdomain.t[shift - 1 - i];
279 token822_alloc *addr;
281 if (!addr->len) return; /* don't rewrite <> */
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@[]> */
288 if (!addr->len) return; /* <@foo:> -> <> */
290 if (!addr->len) return; /* <.> -> <> */
292 if (!addr->len) return; /* <@> -> <> */
299 token822_alloc *addr;
303 token822_reverse(addr);
304 if (token822_unquote(&sender,addr) != 1) die_nomem();
306 if (!stralloc_cats(&sender,"-@[]")) die_nomem();
307 token822_reverse(addr);
313 token822_alloc *addr;
321 token822_alloc *addr;
327 void rwrecip(addr,xl)
328 token822_alloc *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();
337 token822_reverse(addr);
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; }
345 int htypeseen[H_NUM];
346 stralloc hfbuf = {0};
347 token822_alloc hfin = {0};
348 token822_alloc hfrewrite = {0};
349 token822_alloc hfaddr = {0};
351 void doheaderfield(h)
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;
365 htypeseen[htype] = 1;
367 if (!hfield_valid(h->s,h->len))
375 case H_R_TO: case H_R_CC: case H_R_BCC:
377 case H_TO: case H_CC: case H_BCC: case H_APPARENTLYTO:
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:
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)
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 */
407 stralloc torecip = {0};
408 token822_alloc tr = {0};
413 if (!quote2(&torecip,s)) die_nomem();
414 switch(token822_parse(&tr,&torecip,&hfbuf))
416 case -1: die_nomem();
418 substdio_puts(subfderr,"qmail-inject: fatal: unable to parse address: ");
419 substdio_puts(subfderr,s);
420 substdio_putsflush(subfderr,"\n");
423 token822_reverse(&tr);
424 rwrecip(&tr,&reciplist);
427 stralloc defaultfrom = {0};
428 token822_alloc df = {0};
430 void defaultfrommake()
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();
438 df.t[df.len].type = TOKEN822_ATOM;
439 df.t[df.len].s = "From";
440 df.t[df.len].slen = 4;
442 df.t[df.len].type = TOKEN822_COLON;
444 if (fullname && !flagnamecomment)
446 df.t[df.len].type = TOKEN822_QUOTE;
447 df.t[df.len].s = fullname;
448 df.t[df.len].slen = str_len(fullname);
450 df.t[df.len].type = TOKEN822_LEFT;
453 df.t[df.len].type = mailusertokentype;
454 df.t[df.len].s = mailuser;
455 df.t[df.len].slen = str_len(mailuser);
459 df.t[df.len].type = TOKEN822_AT;
461 df.t[df.len].type = TOKEN822_ATOM;
462 df.t[df.len].s = mailhost;
463 df.t[df.len].slen = str_len(mailhost);
466 if (fullname && !flagnamecomment)
468 df.t[df.len].type = TOKEN822_RIGHT;
471 if (fullname && flagnamecomment)
473 df.t[df.len].type = TOKEN822_COMMENT;
474 df.t[df.len].s = fullname;
475 df.t[df.len].slen = str_len(fullname);
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();
484 stralloc defaultreturnpath = {0};
485 token822_alloc drp = {0};
486 stralloc hackedruser = {0};
487 char strnum[FMT_ULONG];
489 void dodefaultreturnpath()
491 if (!stralloc_copys(&hackedruser,mailruser)) die_nomem();
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();
500 if (!stralloc_cats(&hackedruser,"-")) die_nomem();
501 if (!token822_ready(&drp,10)) die_nomem();
503 drp.t[drp.len].type = TOKEN822_ATOM;
504 drp.t[drp.len].s = "Return-Path";
505 drp.t[drp.len].slen = 11;
507 drp.t[drp.len].type = TOKEN822_COLON;
509 drp.t[drp.len].type = TOKEN822_QUOTE;
510 drp.t[drp.len].s = hackedruser.s;
511 drp.t[drp.len].slen = hackedruser.len;
515 drp.t[drp.len].type = TOKEN822_AT;
517 drp.t[drp.len].type = TOKEN822_ATOM;
518 drp.t[drp.len].s = mailrhost;
519 drp.t[drp.len].slen = str_len(mailrhost);
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();
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];
537 dodefaultreturnpath();
541 static stralloc sa = {0};
542 static stralloc sa2 = {0};
544 if (!stralloc_copy(&sa,&sender)) die_nomem();
545 if (!stralloc_0(&sa)) die_nomem();
546 if (!quote2(&sa2,sa.s)) die_nomem();
548 puts("Return-Path: <");
553 /* could check at this point whether there are any recipients */
555 if (qmail_open(&qqt) == -1) die_qqt();
559 if (!htypeseen[H_R_DATE])
561 if (!newfield_datemake(starttime)) die_nomem();
563 put(newfield_date.s,newfield_date.len);
565 if (!htypeseen[H_R_MESSAGEID])
567 if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem();
569 put(newfield_msgid.s,newfield_msgid.len);
571 if (!htypeseen[H_R_FROM])
575 put(defaultfrom.s,defaultfrom.len);
577 if (!htypeseen[H_R_TO] && !htypeseen[H_R_CC])
578 puts("Resent-Cc: recipient list not shown: ;\n");
582 if (!htypeseen[H_DATE])
584 if (!newfield_datemake(starttime)) die_nomem();
585 put(newfield_date.s,newfield_date.len);
587 if (!htypeseen[H_MESSAGEID])
589 if (!newfield_msgidmake(control_idhost.s,control_idhost.len,starttime)) die_nomem();
590 put(newfield_msgid.s,newfield_msgid.len);
592 if (!htypeseen[H_FROM])
595 put(defaultfrom.s,defaultfrom.len);
597 if (!htypeseen[H_TO] && !htypeseen[H_CC])
598 puts("Cc: recipient list not shown: ;\n");
606 static stralloc sa = {0};
609 if (control_init() == -1) die_read();
611 if (control_rldef(&control_defaultdomain,"control/defaultdomain",1,"defaultdomain") != 1)
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));
619 if (control_rldef(&control_defaulthost,"control/defaulthost",1,"defaulthost") != 1)
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));
627 if (control_rldef(&control_plusdomain,"control/plusdomain",1,"plusdomain") != 1)
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));
635 if (control_rldef(&control_idhost,"control/idhost",1,"idhost") != 1)
637 x = env_get("QMAILIDHOST");
638 if (x) if (!stralloc_copys(&control_idhost,x)) die_nomem();
641 #define RECIP_DEFAULT 1
643 #define RECIP_HEADER 3
658 qmopts = env_get("QMAILINJECT");
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;
671 mailhost = env_get("QMAILHOST");
672 if (!mailhost) mailhost = env_get("MAILHOST");
673 mailrhost = env_get("QMAILSHOST");
674 if (!mailrhost) mailrhost = mailhost;
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;
686 for (i = 0;i < H_NUM;++i) htypeseen[i] = 0;
688 recipstrategy = RECIP_DEFAULT;
691 if (chdir(auto_qmail) == -1)
695 if (!saa_readyplus(&hrlist,1)) die_nomem();
696 if (!saa_readyplus(&hrrlist,1)) die_nomem();
697 if (!saa_readyplus(&reciplist,1)) die_nomem();
699 while ((opt = getopt(argc,argv,"aAhHnNf:")) != opteof)
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;
709 if (!quote2(&sender,optarg)) die_nomem();
710 doordie(&sender,token822_parse(&envs,&sender,&envsbuf));
711 token822_reverse(&envs);
713 token822_reverse(&envs);
714 if (token822_unquote(&sender,&envs) != 1) die_nomem();
723 if (recipstrategy == RECIP_DEFAULT)
724 recipstrategy = (*argv ? RECIP_ARGS : RECIP_HEADER);
726 if (recipstrategy != RECIP_HEADER)
730 flagrh = (recipstrategy != RECIP_ARGS);
732 if (headerbody(subfdin,doheaderfield,finishheader,dobody) == -1)