| 1 | /*$Id: ezmlm-store.c,v 1.52 1999/10/09 16:49:56 lindberg Exp $*/ |
| 2 | /*$Name: ezmlm-idx-040 $*/ |
| 3 | |
| 4 | #include <sys/types.h> |
| 5 | #include <sys/stat.h> |
| 6 | #include "stralloc.h" |
| 7 | #include "subfd.h" |
| 8 | #include "strerr.h" |
| 9 | #include "error.h" |
| 10 | #include "qmail.h" |
| 11 | #include "env.h" |
| 12 | #include "lock.h" |
| 13 | #include "sig.h" |
| 14 | #include "open.h" |
| 15 | #include "getln.h" |
| 16 | #include "str.h" |
| 17 | #include "fmt.h" |
| 18 | #include "readwrite.h" |
| 19 | #include "auto_bin.h" |
| 20 | #include "fork.h" |
| 21 | #include "wait.h" |
| 22 | #include "exit.h" |
| 23 | #include "substdio.h" |
| 24 | #include "getconf.h" |
| 25 | #include "datetime.h" |
| 26 | #include "now.h" |
| 27 | #include "date822fmt.h" |
| 28 | #include "cookie.h" |
| 29 | #include "sgetopt.h" |
| 30 | #include "errtxt.h" |
| 31 | #include "idx.h" |
| 32 | #include "copy.h" |
| 33 | #include "subscribe.h" |
| 34 | #include "mime.h" |
| 35 | |
| 36 | int flagmime = MOD_MIME; /* default is message as attachment */ |
| 37 | int flagpublic = 1; /* default anyone can post */ |
| 38 | /* =0 for only moderators can */ |
| 39 | int flagself = 0; /* `modpost` mods approve own posts */ |
| 40 | /* but mod/ is used for moderators */ |
| 41 | /* of other posts. Def=no=0 */ |
| 42 | char flagcd = '\0'; /* default: don't use quoted-printable */ |
| 43 | int flagbody = 1; /* body of message enclosed with mod request */ |
| 44 | /* 0 => headers only */ |
| 45 | |
| 46 | #define FATAL "ezmlm-store: fatal: " |
| 47 | |
| 48 | void die_usage() |
| 49 | { |
| 50 | strerr_die1x(100,"ezmlm-store: usage: ezmlm-store [-cCmMpPrRsSvV] dir"); |
| 51 | } |
| 52 | void die_nomem() { strerr_die2x(111,FATAL,ERR_NOMEM); } |
| 53 | |
| 54 | stralloc fnmsg = {0}; |
| 55 | |
| 56 | void die_msg() { strerr_die4sys(111,FATAL,ERR_WRITE,fnmsg.s,": "); } |
| 57 | |
| 58 | int fdmsg; |
| 59 | int fdmod; |
| 60 | int pid; |
| 61 | int match; |
| 62 | |
| 63 | char strnum[FMT_ULONG]; |
| 64 | char date[DATE822FMT]; |
| 65 | char hash[COOKIE]; |
| 66 | char boundary[COOKIE]; |
| 67 | datetime_sec when; |
| 68 | struct datetime dt; |
| 69 | struct stat st; |
| 70 | |
| 71 | void *psql = (void *) 0; |
| 72 | |
| 73 | stralloc fnbase = {0}; |
| 74 | stralloc line = {0}; |
| 75 | stralloc mailinglist = {0}; |
| 76 | stralloc outlocal = {0}; |
| 77 | stralloc outhost = {0}; |
| 78 | stralloc mydtline = {0}; |
| 79 | stralloc returnpath = {0}; |
| 80 | stralloc accept = {0}; |
| 81 | stralloc action = {0}; |
| 82 | stralloc reject = {0}; |
| 83 | stralloc quoted = {0}; |
| 84 | stralloc key = {0}; |
| 85 | stralloc subject = {0}; |
| 86 | stralloc moderators = {0}; |
| 87 | stralloc charset = {0}; |
| 88 | stralloc sendopt = {0}; |
| 89 | |
| 90 | struct qmail qq; |
| 91 | int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len; |
| 92 | { |
| 93 | qmail_put(&qq,buf,len); |
| 94 | return len; |
| 95 | } |
| 96 | |
| 97 | int subto(s,l) |
| 98 | char *s; |
| 99 | unsigned int l; |
| 100 | { |
| 101 | qmail_put(&qq,"T",1); |
| 102 | qmail_put(&qq,s,l); |
| 103 | qmail_put(&qq,"",1); |
| 104 | return (int) l; |
| 105 | } |
| 106 | |
| 107 | char qqbuf[1]; |
| 108 | substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,sizeof(qqbuf)); |
| 109 | |
| 110 | substdio ssin; |
| 111 | char inbuf[1024]; |
| 112 | |
| 113 | substdio ssmsg; |
| 114 | char msgbuf[1024]; |
| 115 | |
| 116 | substdio sstext; |
| 117 | char textbuf[512]; |
| 118 | |
| 119 | substdio sssub; |
| 120 | char subbuf[512]; |
| 121 | |
| 122 | void transferenc() |
| 123 | { |
| 124 | if (flagcd) { |
| 125 | qmail_puts(&qq,"\nContent-Transfer-Encoding: "); |
| 126 | if (flagcd == 'Q') |
| 127 | qmail_puts(&qq,"Quoted-Printable\n\n"); |
| 128 | else |
| 129 | qmail_puts(&qq,"base64\n\n"); |
| 130 | } else |
| 131 | qmail_puts(&qq,"\n\n"); |
| 132 | } |
| 133 | |
| 134 | void makehash(act) |
| 135 | stralloc *act; /* has to be 0-terminated */ |
| 136 | /* act is expected to be -reject-ddddd.ttttt or -accept-ddddd.ttttt */ |
| 137 | /* The routine will add .hash@outhost to act. act will NOT be 0-terminated */ |
| 138 | { |
| 139 | int d; |
| 140 | |
| 141 | d = 2 + str_chr(act->s + 1,'-'); |
| 142 | cookie(hash,key.s,key.len,act->s + d,"","a"); |
| 143 | *(act->s + act->len - 1) = '.'; /* we put a '.' Bad, but works */ |
| 144 | if (!stralloc_catb(act,hash,COOKIE)) die_nomem(); |
| 145 | if (!stralloc_cats(act,"@")) die_nomem(); |
| 146 | if (!stralloc_cat(act,&outhost)) die_nomem(); |
| 147 | } |
| 148 | |
| 149 | void main(argc,argv) |
| 150 | int argc; |
| 151 | char **argv; |
| 152 | { |
| 153 | char *dir; |
| 154 | int fdlock; |
| 155 | char *sender; |
| 156 | int match; |
| 157 | int flaginheader; |
| 158 | int flagmodpost; |
| 159 | int flagremote; |
| 160 | char *pmod; |
| 161 | char *err; |
| 162 | int opt; |
| 163 | unsigned int i; |
| 164 | char szchar[2] = "-"; |
| 165 | char *sendargs[4]; |
| 166 | int child,wstat; |
| 167 | |
| 168 | (void) umask(022); |
| 169 | sig_pipeignore(); |
| 170 | |
| 171 | if (!stralloc_copys(&sendopt," -")) die_nomem(); |
| 172 | while ((opt = getopt(argc,argv,"bBcCmMpPrRsSvV")) != opteof) |
| 173 | switch(opt) { |
| 174 | case 'b': flagbody = 1; break; |
| 175 | case 'B': flagbody = 0; break; |
| 176 | case 'm': flagmime = 1; break; |
| 177 | case 'M': flagmime = 0; break; |
| 178 | case 'p': flagpublic = 1; break; /* anyone can post (still moderated)*/ |
| 179 | case 'P': flagpublic = 0; break; /* only moderators can post */ |
| 180 | case 's': flagself = 1; break; /* modpost and DIR/mod diff fxns */ |
| 181 | case 'S': flagself = 0; break; /* same fxn */ |
| 182 | case 'c': /* ezmlm-send flags */ |
| 183 | case 'C': |
| 184 | case 'r': |
| 185 | case 'R': |
| 186 | szchar[0] = (char) opt & 0xff; |
| 187 | if (!stralloc_append(&sendopt,szchar)) die_nomem(); |
| 188 | break; |
| 189 | case 'v': |
| 190 | case 'V': strerr_die2x(0,"ezmlm-store version: ",EZIDX_VERSION); |
| 191 | default: |
| 192 | die_usage(); |
| 193 | } |
| 194 | |
| 195 | sender = env_get("SENDER"); |
| 196 | |
| 197 | if (sender) { |
| 198 | if (!*sender || str_equal(sender,"#@[]")) |
| 199 | strerr_die2x(100,FATAL,ERR_BOUNCE); |
| 200 | } |
| 201 | |
| 202 | dir = argv[optind]; |
| 203 | if (!dir) die_usage(); |
| 204 | |
| 205 | if (chdir(dir) == -1) |
| 206 | strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": "); |
| 207 | |
| 208 | flagmodpost = getconf_line(&moderators,"modpost",0,FATAL,dir); |
| 209 | flagremote = getconf_line(&line,"remote",0,FATAL,dir); |
| 210 | if (!flagmodpost) { /* not msg-mod. Pipe to ezmlm-send */ |
| 211 | sendargs[0] = "/bin/sh"; |
| 212 | sendargs[1] = "-c"; |
| 213 | if (!stralloc_copys(&line,auto_bin)) die_nomem(); |
| 214 | if (!stralloc_cats(&line,"/ezmlm-send")) die_nomem(); |
| 215 | if (sendopt.len > 2) |
| 216 | if (!stralloc_cat(&line,&sendopt)) die_nomem(); |
| 217 | if (!stralloc_cats(&line," '")) die_nomem(); |
| 218 | if (!stralloc_cats(&line,dir)) die_nomem(); |
| 219 | if (!stralloc_cats(&line,"'")) die_nomem(); |
| 220 | if (!stralloc_0(&line)) die_nomem(); |
| 221 | sendargs[2] = line.s; |
| 222 | sendargs[3] = 0; |
| 223 | switch(child = fork()) { |
| 224 | case -1: |
| 225 | strerr_die2sys(111,FATAL,ERR_FORK); |
| 226 | case 0: |
| 227 | execvp(*sendargs,sendargs); |
| 228 | if (errno == error_txtbsy || errno == error_nomem || |
| 229 | errno == error_io) |
| 230 | strerr_die5sys(111,FATAL,ERR_EXECUTE,"/bin/sh -c ",sendargs[2],": "); |
| 231 | else |
| 232 | strerr_die5sys(100,FATAL,ERR_EXECUTE,"/bin/sh -c ",sendargs[2],": "); |
| 233 | } |
| 234 | /* parent */ |
| 235 | wait_pid(&wstat,child); |
| 236 | if (wait_crashed(wstat)) |
| 237 | strerr_die2x(111,FATAL,ERR_CHILD_CRASHED); |
| 238 | switch(wait_exitcode(wstat)) { |
| 239 | case 100: |
| 240 | strerr_die2x(100,FATAL,"Fatal error from child"); |
| 241 | case 111: |
| 242 | strerr_die2x(111,FATAL,"Temporary error from child"); |
| 243 | case 0: |
| 244 | _exit(0); |
| 245 | default: |
| 246 | strerr_die2x(111,FATAL,"Unknown temporary error from child"); |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | if (!moderators.len || !(moderators.s[0] == '/')) { |
| 251 | if (!stralloc_copys(&moderators,dir)) die_nomem(); |
| 252 | if (!stralloc_cats(&moderators,"/mod")) die_nomem(); |
| 253 | } |
| 254 | if (!stralloc_0(&moderators)) die_nomem(); |
| 255 | |
| 256 | if (sender) { |
| 257 | pmod = issub(moderators.s,sender,(char *) 0,FATAL); |
| 258 | closesql(); |
| 259 | /* sender = moderator? */ |
| 260 | } else |
| 261 | pmod = 0; |
| 262 | |
| 263 | if (!pmod && !flagpublic) |
| 264 | strerr_die2x(100,FATAL,ERR_NO_POST); |
| 265 | |
| 266 | switch(slurp("key",&key,32)) { |
| 267 | case -1: |
| 268 | strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: "); |
| 269 | case 0: |
| 270 | strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST); |
| 271 | } |
| 272 | |
| 273 | getconf_line(&outhost,"outhost",1,FATAL,dir); |
| 274 | getconf_line(&outlocal,"outlocal",1,FATAL,dir); |
| 275 | getconf_line(&mailinglist,"mailinglist",1,FATAL,dir); |
| 276 | |
| 277 | fdlock = open_append("mod/lock"); |
| 278 | if (fdlock == -1) |
| 279 | strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/mod/lock: "); |
| 280 | if (lock_ex(fdlock) == -1) |
| 281 | strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/mod/lock: "); |
| 282 | |
| 283 | if (!stralloc_copys(&mydtline,"Delivered-To: moderator for ")) die_nomem(); |
| 284 | if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem(); |
| 285 | if (!stralloc_append(&mydtline,"@")) die_nomem(); |
| 286 | if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem(); |
| 287 | if (!stralloc_cats(&mydtline,"\n")) die_nomem(); |
| 288 | |
| 289 | if (!stralloc_copys(&returnpath,"Return-Path: <")) die_nomem(); |
| 290 | if (sender) { |
| 291 | if (!stralloc_cats(&returnpath,sender)) die_nomem(); |
| 292 | for (i = 14; i < returnpath.len;++i) |
| 293 | if (returnpath.s[i] == '\n' || !returnpath.s[i] ) |
| 294 | returnpath.s[i] = '_'; |
| 295 | /* NUL and '\n' are bad, but we don't quote since this is */ |
| 296 | /* only for ezmlm-moderate, NOT for SMTP */ |
| 297 | } |
| 298 | if (!stralloc_cats(&returnpath,">\n")) die_nomem(); |
| 299 | |
| 300 | pid = getpid(); /* unique file name */ |
| 301 | for (i = 0;;++i) /* got lock - nobody else can add files */ |
| 302 | { |
| 303 | when = now(); /* when is also used later for date! */ |
| 304 | if (!stralloc_copys(&fnmsg,"mod/pending/")) die_nomem(); |
| 305 | if (!stralloc_copyb(&fnbase,strnum,fmt_ulong(strnum,when))) die_nomem(); |
| 306 | if (!stralloc_append(&fnbase,".")) die_nomem(); |
| 307 | if (!stralloc_catb(&fnbase,strnum,fmt_ulong(strnum,pid))) die_nomem(); |
| 308 | if (!stralloc_cat(&fnmsg,&fnbase)) die_nomem(); |
| 309 | if (!stralloc_0(&fnmsg)) die_nomem(); |
| 310 | if (stat(fnmsg.s,&st) == -1) if (errno == error_noent) break; |
| 311 | /* really should never get to this point */ |
| 312 | if (i == 2) |
| 313 | strerr_die2x(111,FATAL,ERR_UNIQUE); |
| 314 | sleep(2); |
| 315 | } |
| 316 | |
| 317 | if (!stralloc_copys(&action,"-")) die_nomem(); |
| 318 | if (!stralloc_cats(&action,ACTION_REJECT)) die_nomem(); |
| 319 | if (!stralloc_cat(&action,&fnbase)) die_nomem(); |
| 320 | if (!stralloc_0(&action)) die_nomem(); |
| 321 | makehash(&action); |
| 322 | if (!quote("ed,&outlocal)) die_nomem(); |
| 323 | if (!stralloc_copy(&reject,"ed)) die_nomem(); |
| 324 | if (!stralloc_cat(&reject,&action)) die_nomem(); |
| 325 | if (!stralloc_0(&reject)) die_nomem(); |
| 326 | |
| 327 | if (!stralloc_copys(&action,"-")) die_nomem(); |
| 328 | if (!stralloc_cats(&action,ACTION_ACCEPT)) die_nomem(); |
| 329 | if (!stralloc_cat(&action,&fnbase)) die_nomem(); |
| 330 | if (!stralloc_0(&action)) die_nomem(); |
| 331 | makehash(&action); |
| 332 | if (!stralloc_copy(&accept,"ed)) die_nomem(); |
| 333 | if (!stralloc_cat(&accept,&action)) die_nomem(); |
| 334 | if (!stralloc_0(&accept)) die_nomem(); |
| 335 | |
| 336 | set_cpoutlocal(&outlocal); |
| 337 | set_cpouthost(&outhost); |
| 338 | set_cptarget(accept.s); /* for copy () */ |
| 339 | set_cpconfirm(reject.s); |
| 340 | |
| 341 | fdmsg = open_trunc(fnmsg.s); |
| 342 | if (fdmsg == -1) |
| 343 | strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnmsg.s,": "); |
| 344 | substdio_fdbuf(&ssmsg,write,fdmsg,msgbuf,sizeof(msgbuf)); |
| 345 | |
| 346 | if (qmail_open(&qq, (stralloc *) 0) == -1) /* Open mailer */ |
| 347 | strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE); |
| 348 | |
| 349 | qmail_puts(&qq,"Mailing-List: "); |
| 350 | qmail_put(&qq,mailinglist.s,mailinglist.len); |
| 351 | if (getconf_line(&line,"listid",0,FATAL,dir)) { |
| 352 | qmail_puts(&qq,"List-ID: "); |
| 353 | qmail_put(&qq,line.s,line.len); |
| 354 | } |
| 355 | qmail_puts(&qq,"\nDate: "); |
| 356 | datetime_tai(&dt,when); |
| 357 | qmail_put(&qq,date,date822fmt(date,&dt)); |
| 358 | qmail_puts(&qq,"Message-ID: <"); |
| 359 | if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,(unsigned long) when))) |
| 360 | die_nomem(); |
| 361 | if (!stralloc_append(&line,".")) die_nomem(); |
| 362 | if (!stralloc_catb(&line,strnum, |
| 363 | fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem(); |
| 364 | if (!stralloc_cats(&line,".ezmlm@")) die_nomem(); |
| 365 | if (!stralloc_cat(&line,&outhost)) die_nomem(); |
| 366 | if (!stralloc_0(&line)) die_nomem(); |
| 367 | qmail_puts(&qq,line.s); |
| 368 | /* "unique" MIME boundary as hash of messageid */ |
| 369 | cookie(boundary,"",0,"",line.s,""); |
| 370 | qmail_puts(&qq,">\nFrom: "); |
| 371 | qmail_puts(&qq,reject.s); |
| 372 | qmail_puts(&qq,"\nReply-To: "); |
| 373 | qmail_puts(&qq,accept.s); |
| 374 | if (!pmod && flagremote) { /* if remote admin add -allow- address */ |
| 375 | qmail_puts(&qq,"\nCc: "); /* for ezmlm-gate users */ |
| 376 | strnum[fmt_ulong(strnum,(unsigned long) when)] = 0; |
| 377 | cookie(hash,key.s,key.len-FLD_ALLOW,strnum,sender,"t"); |
| 378 | if (!stralloc_copy(&line,&outlocal)) die_nomem(); |
| 379 | if (!stralloc_cats(&line,"-allow-tc.")) die_nomem(); |
| 380 | if (!stralloc_cats(&line,strnum)) die_nomem(); |
| 381 | if (!stralloc_append(&line,".")) die_nomem(); |
| 382 | if (!stralloc_catb(&line,hash,COOKIE)) die_nomem(); |
| 383 | if (!stralloc_append(&line,"-")) die_nomem(); |
| 384 | i = str_rchr(sender,'@'); |
| 385 | if (!stralloc_catb(&line,sender,i)) die_nomem(); |
| 386 | if (sender[i]) { |
| 387 | if (!stralloc_append(&line,"=")) die_nomem(); |
| 388 | if (!stralloc_cats(&line,sender + i + 1)) die_nomem(); |
| 389 | } |
| 390 | qmail_put(&qq,line.s,line.len); |
| 391 | qmail_puts(&qq,"@"); |
| 392 | qmail_put(&qq,outhost.s,outhost.len); |
| 393 | } |
| 394 | qmail_puts(&qq,"\nTo: Recipient list not shown: ;"); |
| 395 | if (!stralloc_copys(&subject,"\nSubject: ")) die_nomem(); |
| 396 | if (!stralloc_cats(&subject,TXT_MODERATE)) die_nomem(); |
| 397 | if (!quote("ed,&outlocal)) die_nomem(); |
| 398 | if (!stralloc_cat(&subject,"ed)) die_nomem(); |
| 399 | if (!stralloc_append(&subject,"@")) die_nomem(); |
| 400 | if (!stralloc_cat(&subject,&outhost)) die_nomem(); |
| 401 | if (flagmime) { |
| 402 | if (getconf_line(&charset,"charset",0,FATAL,dir)) { |
| 403 | if (charset.len >= 2 && charset.s[charset.len - 2] == ':') { |
| 404 | if (charset.s[charset.len - 1] == 'B' || |
| 405 | charset.s[charset.len - 1] == 'Q') { |
| 406 | flagcd = charset.s[charset.len - 1]; |
| 407 | charset.s[charset.len - 2] = '\0'; |
| 408 | } |
| 409 | } |
| 410 | } else |
| 411 | if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem(); |
| 412 | if (!stralloc_0(&charset)) die_nomem(); |
| 413 | qmail_puts(&qq,"\nMIME-Version: 1.0\n"); |
| 414 | qmail_puts(&qq,"Content-Type: multipart/mixed;\n\tboundary="); |
| 415 | qmail_put(&qq,boundary,COOKIE); |
| 416 | qmail_put(&qq,subject.s,subject.len); |
| 417 | qmail_puts(&qq,"\n\n--"); |
| 418 | qmail_put(&qq,boundary,COOKIE); |
| 419 | qmail_puts(&qq,"\nContent-Type: text/plain; charset="); |
| 420 | qmail_puts(&qq,charset.s); |
| 421 | transferenc(); |
| 422 | } else { |
| 423 | qmail_put(&qq,subject.s,subject.len); |
| 424 | qmail_puts(&qq,"\n\n"); |
| 425 | } |
| 426 | copy(&qq,"text/mod-request",flagcd,FATAL); |
| 427 | if (flagcd == 'B') { |
| 428 | encodeB("",0,&line,2,FATAL); |
| 429 | qmail_put(&qq,line.s,line.len); |
| 430 | } |
| 431 | if (substdio_put(&ssmsg,returnpath.s,returnpath.len) == -1) die_msg(); |
| 432 | if (substdio_put(&ssmsg,mydtline.s,mydtline.len) == -1) die_msg(); |
| 433 | substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf)); |
| 434 | |
| 435 | if (flagmime) { |
| 436 | qmail_puts(&qq,"\n--"); |
| 437 | qmail_put(&qq,boundary,COOKIE); |
| 438 | qmail_puts(&qq,"\nContent-Type: message/rfc822\n\n"); |
| 439 | } |
| 440 | |
| 441 | qmail_put(&qq,returnpath.s,returnpath.len); |
| 442 | qmail_put(&qq,mydtline.s,mydtline.len); |
| 443 | flaginheader = 1; |
| 444 | for (;;) { |
| 445 | if (getln(&ssin,&line,&match,'\n') == -1) |
| 446 | strerr_die2sys(111,FATAL,ERR_READ_INPUT); |
| 447 | if (!match) break; |
| 448 | if (line.len == 1) flaginheader = 0; |
| 449 | if (flaginheader) { |
| 450 | if ((line.len == mydtline.len) && |
| 451 | !byte_diff(line.s,line.len,mydtline.s)) { |
| 452 | close(fdmsg); /* be nice - clean up */ |
| 453 | unlink(fnmsg.s); |
| 454 | strerr_die2x(100,FATAL,ERR_LOOPING); |
| 455 | } |
| 456 | if (case_startb(line.s,line.len,"mailing-list:")) { |
| 457 | close(fdmsg); /* be nice - clean up */ |
| 458 | unlink(fnmsg.s); |
| 459 | strerr_die2x(100,FATAL,ERR_MAILING_LIST); |
| 460 | } |
| 461 | } |
| 462 | |
| 463 | if (flagbody || flaginheader) /* skip body if !flagbody */ |
| 464 | qmail_put(&qq,line.s,line.len); |
| 465 | if (substdio_put(&ssmsg,line.s,line.len) == -1) die_msg(); |
| 466 | } |
| 467 | |
| 468 | if (flagmime) { |
| 469 | qmail_puts(&qq,"\n--"); |
| 470 | qmail_put(&qq,boundary,COOKIE); |
| 471 | qmail_puts(&qq,"--\n"); |
| 472 | } |
| 473 | |
| 474 | /* close archive before qmail. Loss of qmail will result in re-run, and */ |
| 475 | /* worst case this results in a duplicate msg sitting orphaned until it's */ |
| 476 | /* cleaned out. */ |
| 477 | |
| 478 | if (substdio_flush(&ssmsg) == -1) die_msg(); |
| 479 | if (fsync(fdmsg) == -1) die_msg(); |
| 480 | if (fchmod(fdmsg,MODE_MOD_MSG | 0700) == -1) die_msg(); |
| 481 | if (close(fdmsg) == -1) die_msg(); /* NFS stupidity */ |
| 482 | |
| 483 | close(fdlock); |
| 484 | |
| 485 | if (!stralloc_copy(&line,&outlocal)) die_nomem(); |
| 486 | if (!stralloc_cats(&line,"-return-@")) die_nomem(); |
| 487 | if (!stralloc_cat(&line,&outhost)) die_nomem(); |
| 488 | if (!stralloc_0(&line)) die_nomem(); |
| 489 | qmail_from(&qq,line.s); /* envelope sender */ |
| 490 | if (pmod) /* to moderator only */ |
| 491 | qmail_to(&qq,pmod); |
| 492 | else { |
| 493 | if (flagself) { /* to all moderators */ |
| 494 | if (!stralloc_copys(&moderators,dir)) die_nomem(); |
| 495 | if (!stralloc_cats(&moderators,"/mod")) die_nomem(); |
| 496 | if (!stralloc_0(&moderators)) die_nomem(); |
| 497 | } |
| 498 | putsubs(moderators.s,0,52,subto,1,FATAL); |
| 499 | } |
| 500 | |
| 501 | if (*(err = qmail_close(&qq)) == '\0') { |
| 502 | strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0; |
| 503 | strerr_die2x(0,"ezmlm-store: info: qp ",strnum); |
| 504 | } else |
| 505 | strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err+1); |
| 506 | } |