qmail-inject.c
changeset 0 068428edee47
equal deleted inserted replaced
-1:000000000000 0:068428edee47
       
     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 #include "constmap.h"
       
    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(); }
       
    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(); }
       
    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 
       
    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};
       
    86 saa tocclist = {0};
       
    87 saa hrrlist = {0};
       
    88 saa reciplist = {0};
       
    89 int flagresent;
       
    90 
       
    91 void exitnicely()
       
    92 {
       
    93  char *qqx;
       
    94 
       
    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 
       
   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      }
       
   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 
       
   317 void rwappend(addr,xl)
       
   318 token822_alloc *addr;
       
   319 saa *xl;
       
   320 {
       
   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;
       
   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; }
       
   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 {
       
   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;
       
   372   }
       
   373 
       
   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();
       
   379   }
       
   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);
       
   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);
       
   411  rwgeneric(&tr);
       
   412  rwappend(&tr,&reciplist);
       
   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 
       
   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 
       
   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");
       
   634    finishmft();
       
   635   }
       
   636 
       
   637  savedh_print();
       
   638 }
       
   639 
       
   640 void getcontrols()
       
   641 {
       
   642  static stralloc sa = {0};
       
   643  char *x;
       
   644 
       
   645  mft_init();
       
   646 
       
   647  if (chdir(auto_qmail) == -1) die_chdir();
       
   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 
       
   730  getcontrols();
       
   731 
       
   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();
       
   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 }