1 /* $Id: ezmlm-send.c,v 1.77 1999/10/29 02:49:14 lindberg Exp $*/
2 /* $Name: ezmlm-idx-040 $*/
17 #include "readwrite.h"
25 #include "subscribe.h"
33 int flagnoreceived = 1; /* suppress received headers by default. They*/
34 /* are still archived. =0 => archived and */
36 int flaglog = 1; /* for lists with mysql support, use tags */
37 /* and log traffic to the database */
38 #define FATAL "ezmlm-send: fatal: "
42 strerr_die1x(100,"ezmlm-send: usage: ezmlm-send [-cClLqQrR] [-h header] dir");
46 strerr_die2x(111,FATAL,ERR_NOMEM);
49 /* for writing new index file indexn later moved to index. */
53 char strnum[FMT_ULONG];
54 char szmsgnum[FMT_ULONG];
57 stralloc fnadir = {0};
65 stralloc subject = {0};
67 stralloc received = {0};
68 stralloc prefix = {0};
69 stralloc content = {0};
70 stralloc boundary = {0};
71 stralloc charset = {0};
72 stralloc dcprefix = {0};
74 stralloc qmqpservers = {0};
78 strerr_die4x(111,FATAL,ERR_WRITE,fnifn.s,": ");
81 void *psql = (void *) 0;
86 unsigned long hash_lo = 0L;
87 unsigned long hash_hi = 52L;
88 unsigned long msgsize = 0L;
89 unsigned long cumsize = 0L; /* cumulative archive size bytes / 256 */
90 char flagcd = '\0'; /* no transfer-encoding for trailer */
93 int flagfoundokpart; /* Found something to pass on. If multipart */
94 /* we set to 0 and then set to 1 for any */
95 /* acceptable mime part. If 0 -> reject */
98 unsigned int serial = 0;
103 char hashout[COOKIE+1];
106 char archivebuf[1024];
109 stralloc sublist = {0};
110 stralloc mailinglist = {0};
111 stralloc outlocal = {0};
112 stralloc outhost = {0};
113 stralloc headerremove = {0};
114 struct constmap headerremovemap;
115 stralloc mimeremove = {0};
116 struct constmap mimeremovemap;
128 unsigned int mywrite(fd,buf,len)
133 qmail_put(&qq,buf,len);
141 qmail_put(&qq,"T",1);
149 strerr_die4sys(111,FATAL,ERR_WRITE,fnaf.s,": ");
153 strerr_die3sys(111,FATAL,ERR_CREATE,"numnew: ");
156 void qa_put(buf,len) char *buf; unsigned int len;
158 qmail_put(&qq,buf,len);
160 if (substdio_put(&ssarchive,buf,len) == -1) die_archive();
163 void qa_puts(buf) char *buf;
167 if (substdio_puts(&ssarchive,buf) == -1) die_archive();
170 int sublistmatch(sender)
177 if (j < sublist.len) return 0;
179 i = byte_rchr(sublist.s,sublist.len,'@');
180 if (i == sublist.len) return 1;
182 if (byte_diff(sublist.s,i,sender)) return 0;
183 if (case_diffb(sublist.s + i,sublist.len - i,sender + j - (sublist.len - i)))
193 substdio ss0 = SUBSTDIO_FDBUF(read,0,buf0,sizeof(buf0));
196 { /* this one deals with msgnum, not outnum! */
199 fd = open_trunc("numnew");
200 if (fd == -1) die_numnew();
201 substdio_fdbuf(&ssnumnew,write,fd,numnewbuf,sizeof(numnewbuf));
202 if (substdio_put(&ssnumnew,strnum,fmt_ulong(strnum,msgnum)) == -1)
204 if (substdio_puts(&ssnumnew,":") == -1) die_numnew();
205 if (substdio_put(&ssnumnew,strnum,fmt_ulong(strnum,cumsize)) == -1)
208 if (substdio_puts(&ssnumnew,"\n") == -1) die_numnew();
209 if (substdio_flush(&ssnumnew) == -1) die_numnew();
210 if (fsync(fd) == -1) die_numnew();
211 if (close(fd) == -1) die_numnew(); /* NFS stupidity */
212 if (rename("numnew","num") == -1)
213 strerr_die3sys(111,FATAL,ERR_MOVE,"numnew: ");
216 stralloc mydtline = {0};
218 int idx_copy_insertsubject()
219 /* copies old index file up to but not including msg, then adds a line with */
220 /* 'sub' trimmed of reply indicators, then closes the new index and moves it*/
221 /* to the name 'index'. Errors are dealt with directly, and if the routine */
222 /* returns, it was successful. 'fatal' points to a program-specific error */
223 /* string. Sub is not destroyed, but from is!!! */
224 /* returns 1 if reply-indicators were found, 0 otherwise. */
225 /* no terminal \n or \0 in any of the strallocs! */
233 if (!stralloc_copys(&fnadir,"archive/")) die_nomem();
234 if (!stralloc_catb(&fnadir,strnum,fmt_ulong(strnum,outnum / 100)))
236 if (!stralloc_copy(&fnif,&fnadir)) die_nomem();
237 if (!stralloc_copy(&fnifn,&fnif)) die_nomem();
238 if (!stralloc_cats(&fnif,"/index")) die_nomem();
239 if (!stralloc_cats(&fnifn,"/indexn")) die_nomem();
240 if (!stralloc_0(&fnif)) die_nomem();
241 if (!stralloc_0(&fnifn)) die_nomem();
242 if (!stralloc_0(&fnadir)) die_nomem();
244 /* may not exists since we run before ezmlm-send */
245 if (mkdir(fnadir.s,0755) == -1)
246 if (errno != error_exist)
247 strerr_die4x(111,FATAL,ERR_CREATE,fnadir.s,": ");
250 fdindexn = open_trunc(fnifn.s);
252 strerr_die4x(111,FATAL,ERR_WRITE,fnifn.s,": ");
254 /* set up buffers for indexn */
255 substdio_fdbuf(&ssindexn,write,fdindexn,indexnbuf,sizeof(indexnbuf));
257 concatHDR(subject.s,subject.len,&lines,FATAL); /* make 1 line */
258 decodeHDR(lines.s,lines.len,&qline,charset.s,FATAL); /* decode mime */
259 r = unfoldHDR(qline.s,qline.len,&lines,charset.s,&dcprefix,1,FATAL);
262 fdindex = open_read(fnif.s);
264 if (errno != error_noent)
265 strerr_die4x(111,FATAL,ERR_OPEN, fnif.s, ": ");
267 substdio_fdbuf(&ssin,read,fdindex,inbuf,sizeof(inbuf));
269 if (getln(&ssin,&qline,&match,'\n') == -1)
270 strerr_die4sys(111,FATAL,ERR_READ, fnif.s, ": ");
273 pos = scan_ulong(qline.s,&idx);
274 if (!idx) /* "impossible!" */
275 strerr_die2x(111,FATAL,ERR_BAD_INDEX);
277 break; /* messages always come in order */
278 if (substdio_put(&ssindexn,qline.s,qline.len) == -1)
280 if (qline.s[pos] == ':') { /* has author line */
281 if (getln(&ssin,&qline,&match,'\n') == -1)
282 strerr_die4x(111,FATAL,ERR_READ, fnif.s, ": ");
283 if (!match && qline.s[0] != '\t') /* "impossible! */
284 strerr_die2x(111,FATAL,ERR_BAD_INDEX);
285 if (substdio_put(&ssindexn,qline.s,qline.len) == -1)
291 if (!stralloc_copyb(&qline,strnum,fmt_ulong(strnum,outnum))) die_nomem();
292 if (!stralloc_cats(&qline,": ")) die_nomem(); /* ':' for new ver */
293 makehash(lines.s,lines.len,hash);
294 if (!stralloc_catb(&qline,hash,HASHLEN)) die_nomem();
295 if (!stralloc_cats(&qline," ")) die_nomem();
296 if (r & 1) /* reply */
297 if (!stralloc_cats(&qline,"Re: ")) die_nomem();
298 if (!stralloc_cat(&qline,&lines)) die_nomem();
299 if (!stralloc_cats(&qline,"\n\t")) die_nomem();
300 if (!stralloc_cat(&qline,&received)) die_nomem();
301 if (!stralloc_cats(&qline,";")) die_nomem();
303 concatHDR(from.s,from.len,&lines,FATAL);
304 mkauthhash(lines.s,lines.len,hash);
306 if (!stralloc_catb(&qline,hash,HASHLEN)) die_nomem();
307 if (!stralloc_cats(&qline," ")) die_nomem();
309 decodeHDR(cp,author_name(&cp,lines.s,lines.len),&from,charset.s,FATAL);
310 (void) unfoldHDR(from.s,from.len,&lines,charset.s,&dcprefix,0,FATAL);
311 if (!stralloc_cat(&qline,&lines)) die_nomem();
313 if (!stralloc_cats(&qline,"\n")) die_nomem();
314 if (substdio_put(&ssindexn,qline.s,qline.len) == -1) die_indexn();
315 if (substdio_flush(&ssindexn) == -1) die_indexn();
316 if (fsync(fdindexn) == -1) die_indexn();
317 if (fchmod(fdindexn,MODE_ARCHIVE | 0700) == -1) die_indexn();
318 if (close(fdindexn) == -1) die_indexn(); /* NFS stupidity */
319 if (rename(fnifn.s,fnif.s) == -1)
320 strerr_die4x(111,FATAL,ERR_MOVE,fnifn.s,": ");
327 qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
329 qmail_puts(&qq,"Quoted-printable\n\n");
331 qmail_puts(&qq,"base64\n\n");
333 qmail_puts(&qq,"\n\n");
338 if (getconf_line(&charset,"charset",0,FATAL,dir)) {
339 if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
340 if (charset.s[charset.len - 1] == 'B' ||
341 charset.s[charset.len - 1] == 'Q') {
342 flagcd = charset.s[charset.len - 1];
343 charset.s[charset.len - 2] = '\0';
347 if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
349 if (!stralloc_0(&charset)) die_nomem();
359 char *mlheader = (char *) 0;
363 int flagqmqp = 0; /* don't use qmqp by default */
364 int flaglistid = 0; /* no listid header added */
379 char *cp, *cpstart, *cpafter;
384 while ((opt = getopt(argc,argv,"cCh:H:lLrRqQs:S:vV")) != opteof)
386 case 'c': case 'C': break; /* ignore for backwards compat */
388 case 'H': mlheader = optarg; /* Alternative sublist check header */
389 mlheader[str_chr(mlheader,':')] = '\0';
391 case 'l': flaglog = 1; break;
392 case 'L': flaglog = 0; break;
393 case 'r': flagnoreceived = 0; break;
394 case 'R': flagnoreceived = 1; break;
396 case 'S': pos = scan_ulong(optarg,&hash_lo);
397 if (!optarg[pos++]) break;
398 (void) scan_ulong(optarg+pos,&hash_hi);
399 if (hash_hi > 52L) hash_hi = 52L;
400 if (hash_lo > hash_hi) hash_lo = hash_hi;
403 case 'q': flagqmqp = 0; break;
404 case 'Q': flagqmqp = 1; break;
406 case 'V': strerr_die2x(0,
407 "ezmlm-send version: ezmlm-0.53+",EZIDX_VERSION);
413 dir = argv[optind++];
414 if (!dir) die_usage();
416 sender = env_get("SENDER");
418 if (chdir(dir) == -1)
419 strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
421 fdlock = open_append("lock");
423 strerr_die4sys(111,FATAL,ERR_OPEN,dir,"/lock: ");
424 if (lock_ex(fdlock) == -1)
425 strerr_die4sys(111,FATAL,ERR_OBTAIN,dir,"/lock: ");
427 flagarchived = getconf_line(&line,"archived",0,FATAL,dir);
428 flagindexed = getconf_line(&line,"indexed",0,FATAL,dir);
430 flagprefixed = getconf_line(&prefix,"prefix",0,FATAL,dir);
431 if (prefix.len) { /* encoding and serial # support */
432 /* no sanity checks - you put '\n' or '\0' */
433 /* into the coded string, you pay */
435 decodeHDR(prefix.s,prefix.len,&line,charset.s,FATAL);
436 (void) unfoldHDR(line.s,line.len,&dcprefix,charset.s,&dummy,0,FATAL);
437 if (!stralloc_copy(&dcprefix,&line)) die_nomem();
438 serial = byte_rchr(prefix.s,prefix.len,'#');
440 if ((fd = open_read("text/trailer")) == -1) { /* see if there is a trailer */
441 if (errno == error_noent) flagtrailer = 0;
442 else strerr_die2sys(111,ERR_OPEN,"text/trailer: ");
448 getconf(&mimeremove,"mimeremove",0,FATAL,dir);
450 if (getconf_line(&line,"num",0,FATAL,dir)) { /* Now non-FATAL, def=0 */
451 if (!stralloc_0(&line)) die_nomem();
452 cp = line.s + scan_ulong(line.s,&msgnum);
455 scan_ulong(cp,&cumsize);
457 msgnum = 1L; /* if num not there */
459 getconf_line(&outhost,"outhost",1,FATAL,dir);
460 getconf_line(&outlocal,"outlocal",1,FATAL,dir);
461 set_cpoutlocal(&outlocal);
462 set_cpouthost(&outhost);
463 flagsublist = getconf_line(&sublist,"sublist",0,FATAL,dir);
465 if (flagqmqp) { /* forward compatibility ;-) */
466 if (!stralloc_copys(&line,QMQPSERVERS)) die_nomem();
467 if (!stralloc_cats(&line,"/0")) die_nomem();
468 if (!stralloc_0(&line)) die_nomem();
469 (void) getconf_line(&qmqpservers,line.s,0,FATAL,dir);
472 getconf(&headerremove,"headerremove",1,FATAL,dir);
473 if (!constmap_init(&headerremovemap,headerremove.s,headerremove.len,0))
476 if (!stralloc_copys(&mydtline,"Delivered-To: mailing list ")) die_nomem();
477 if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
478 if (!stralloc_cats(&mydtline,"@")) die_nomem();
479 if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
480 if (!stralloc_cats(&mydtline,"\n")) die_nomem();
484 strerr_die2x(100,FATAL,ERR_BOUNCE);
485 if (str_equal(sender,"#@[]"))
486 strerr_die2x(100,FATAL,ERR_BOUNCE);
488 if (!sublistmatch(sender))
489 strerr_die2x(100,FATAL,ERR_NOT_PARENT);
491 innum = msgnum; /* innum = incoming */
492 outnum = msgnum; /* outnum = outgoing */
493 if (flagsublist && !flagarchived) { /* msgnum = archive */
494 pos = byte_rchr(sublist.s,sublist.len,'@'); /* checked in sublistmatch */
495 if (str_start(sender+pos,"-return-"))
497 pos += scan_ulong(sender+pos,&innum);
498 if (!flagarchived && innum && sender[pos] == '-')
501 szmsgnum[fmt_ulong(szmsgnum,outnum)] = '\0';
502 set_cpnum(szmsgnum); /* for copy */
505 if (!stralloc_copys(&fnadir,"archive/")) die_nomem();
506 if (!stralloc_catb(&fnadir,strnum,
507 fmt_ulong(strnum,outnum / 100))) die_nomem();
508 if (!stralloc_copy(&fnaf,&fnadir)) die_nomem();
509 if (!stralloc_cats(&fnaf,"/")) die_nomem();
510 if (!stralloc_catb(&fnaf,strnum,fmt_uint0(strnum,
511 (unsigned int) (outnum % 100),2))) die_nomem();
512 if (!stralloc_0(&fnadir)) die_nomem();
513 if (!stralloc_0(&fnaf)) die_nomem();
515 if (mkdir(fnadir.s,0755) == -1)
516 if (errno != error_exist)
517 strerr_die4sys(111,FATAL,ERR_CREATE,fnadir.s,": ");
518 fdarchive = open_trunc(fnaf.s);
520 strerr_die4sys(111,FATAL,ERR_WRITE,fnaf.s,": ");
522 substdio_fdbuf(&ssarchive,write,fdarchive,archivebuf,sizeof(archivebuf));
523 /* return-path to archive */
524 if (!stralloc_copys(&line,"Return-Path: <")) die_nomem();
525 if (sender) { /* same as qmail-local */
526 if (!quote2(&qline,sender)) die_nomem();
527 for (i = 0;i < qline.len;++i) if (qline.s[i] == '\n') qline.s[i] = '_';
528 if (!stralloc_cat(&line,&qline)) die_nomem();
530 if (!stralloc_cats(&line,">\n")) die_nomem();
531 if (substdio_put(&ssarchive,line.s,line.len) == -1) die_archive();
535 if (qmail_open(&qq,&qmqpservers) == -1) /* open qmqp */
536 strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
537 } else if (qmail_open(&qq,(stralloc *) 0) == -1) /* open queue */
538 strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
541 getconf_line(&mailinglist,"mailinglist",1,FATAL,dir);
542 qa_puts("Mailing-List: ");
543 qa_put(mailinglist.s,mailinglist.len);
544 if (getconf_line(&line,"listid",0,FATAL,dir)) {
546 qmail_puts(&qq,"\nList-ID: ");
547 qmail_put(&qq,line.s,line.len);
551 copy(&qq,"headeradd",'H',FATAL);
552 qa_put(mydtline.s,mydtline.len);
564 if (getln(&ss0,&line,&match,'\n') == -1)
565 strerr_die2sys(111,FATAL,ERR_READ_INPUT);
566 if (flaginheader && match) {
567 if (line.len == 1) { /* end of header */
569 if (flagindexed) /* std entry */
570 r = idx_copy_insertsubject(); /* all indexed lists */
571 if (flagprefixed && !flagsublist) {
573 if (!flagindexed) { /* non-indexed prefixed lists */
574 concatHDR(subject.s,subject.len,&lines,FATAL);
575 decodeHDR(lines.s,lines.len,&qline,charset.s,FATAL);
576 r = unfoldHDR(qline.s,qline.len,&lines,
577 charset.s,&dcprefix,1,FATAL);
581 if (serial == prefix.len)
582 qmail_put(&qq,prefix.s,prefix.len);
584 qmail_put(&qq,prefix.s,serial);
585 qmail_puts(&qq,szmsgnum);
586 qmail_put(&qq,prefix.s+serial+1,prefix.len-serial-1);
589 qa_put(subject.s,subject.len);
591 /* do other stuff to do with post header processing here */
592 if (content.len) { /* get MIME boundary, if exists */
593 concatHDR(content.s,content.len,&qline,FATAL);
594 if (!stralloc_copy(&content,&qline)) die_nomem();
596 if (flagtrailer && /* trailer only for some multipart */
597 case_startb(content.s,content.len,"multipart/"))
598 if (!case_startb(content.s+10,content.len-10,"mixed") &&
599 !case_startb(content.s+10,content.len-10,"digest") &&
600 !case_startb(content.s+10,content.len-10,"parallel"))
604 cpafter = cp + content.len; /* check after each ';' */
605 while ((cp += byte_chr(cp,cpafter-cp,';')) != cpafter) {
607 while (cp < cpafter &&
608 (*cp == ' ' || *cp == '\t' || *cp == '\n')) ++cp;
609 if (case_startb(cp,cpafter-cp,"boundary=")) {
610 cp += 9; /* after boundary= */
611 if (*cp == '"') { /* quoted boundary */
614 while (cp < cpafter && *cp != '"') ++cp;
616 strerr_die1x(100,ERR_MIME_QUOTE);
617 } else { /* non-quoted boundary */
618 cpstart = cp; /* find terminator of boundary */
619 while (cp < cpafter && *cp != ';' &&
620 *cp != ' ' && *cp != '\t' && *cp != '\n') ++cp;
622 if (!stralloc_copys(&boundary,"--")) die_nomem();
623 if (!stralloc_catb(&boundary,cpstart,cp-cpstart))
626 if (!constmap_init(&mimeremovemap,mimeremove.s,mimeremove.len,0))
628 flagbadpart = 1; /* skip before first boundary */
629 qa_puts("\n"); /* to make up for the lost '\n' */
633 } else if ((*line.s != ' ') && (*line.s != '\t')) {
639 if (constmap(&headerremovemap,line.s,byte_chr(line.s,line.len,':')))
641 if ((flagnoreceived || !flagreceived) &&
642 case_startb(line.s,line.len,"Received:")) {
643 if (!flagreceived) { /* get date from first rec'd */
644 flagreceived = 1; /* line (done by qmail) */
645 pos = byte_chr(line.s,line.len,';');
646 if (pos != line.len) /* has '\n' */
647 if (!stralloc_copyb(&received,line.s+pos+2,line.len - pos - 3))
649 } else { /* suppress, but archive */
650 flagarchiveonly = 1; /* but do not suppress the */
651 flagbadfield = 1; /* top one added by qmail */
653 } else if (case_startb(line.s,line.len,"Mailing-List:"))
654 flagmlwasthere = 1; /* sublists always ok ezmlm masters */
655 else if (mlheader && case_startb(line.s,line.len,mlheader))
656 flagmlwasthere = 1; /* mlheader treated as ML */
657 else if ((mimeremove.len || flagtrailer) && /* else no MIME need*/
658 case_startb(line.s,line.len,"Content-Type:")) {
659 if (!stralloc_copyb(&content,line.s+13,line.len-13)) die_nomem();
661 } else if (case_startb(line.s,line.len,"Subject:")) {
662 if (!stralloc_copyb(&subject,line.s+8,line.len-8)) die_nomem();
664 if (flagprefixed && !flagsublist) /* don't prefix for sublists */
665 flagbadfield = 1; /* we'll print our own */
666 } else if (flagtrailer &&
667 case_startb(line.s,line.len,"Content-Transfer-Encoding:")) {
669 cpafter = cp + line.len;
670 while (cp < cpafter && (*cp == ' ' || *cp == '\t')) ++cp;
671 if (case_startb(cp,cpafter-cp,"base64")) encin = 'B';
672 else if (case_startb(cp,cpafter-cp,"Quoted-Printable")) encin = 'Q';
673 } else if (flaglistid && case_startb(line.s,line.len,"list-id:"))
674 flagbadfield = 1; /* suppress if we added our own */
675 else if (flagindexed) {
677 if (case_startb(line.s,line.len,"From:")) {
679 if (!stralloc_copyb(&from,line.s+5,line.len-5)) die_nomem();
681 } else if (line.len == mydtline.len)
682 if (!byte_diff(line.s,line.len,mydtline.s))
683 strerr_die2x(100,FATAL,ERR_LOOPING);
684 } else { /* continuation lines */
686 if (!stralloc_cat(&subject,&line)) die_nomem();
687 } else if (flagfromline) {
688 if (!stralloc_cat(&from,&line)) die_nomem();
689 } else if (flagcontline) {
690 if (!stralloc_cat(&content,&line)) die_nomem();
694 msgsize += line.len; /* always for tstdig support */
696 if (!(flaginheader && flagbadfield)) {
697 if (boundary.len && line.len > boundary.len &&
698 !str_diffn(line.s,boundary.s,boundary.len)) {
699 if (line.s[boundary.len] == '-' && line.s[boundary.len+1] == '-') {
700 flagbadpart = 0; /* end boundary should be output */
702 qmail_puts(&qq,"\n");
703 qmail_put(&qq,boundary.s,boundary.len);
704 qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
705 qmail_puts(&qq,charset.s);
706 transferenc(); /* trailer for multipart message */
707 copy(&qq,"text/trailer",flagcd,FATAL);
708 if (flagcd == 'B') { /* need to do our own flushing */
709 encodeB("",0,&qline,2,FATAL);
710 qmail_put(&qq,qline.s,qline.len);
713 } else { /* new part */
714 flagbadpart = 1; /* skip lines */
715 if (!stralloc_copy(&lines,&line)) die_nomem(); /* but save */
716 flagseenext = 1; /* need to check Cont-type */
718 } else if (flagseenext) { /* last was boundary, now stored */
719 if (case_startb(line.s,line.len,"content-type:")) {
720 flagseenext = 0; /* done thinking about it */
721 cp = line.s + 13; /* start of type */
722 while (*cp == ' ' || *cp == '\t') ++cp;
723 cpstart = cp; /* end of type */
724 while (*cp != '\n' && *cp != '\t' && *cp != ' ' && *cp != ';') ++cp;
725 if (constmap(&mimeremovemap,cpstart,cp-cpstart)) {
729 qa_put(lines.s,lines.len); /* saved lines */
730 flagbadpart = 0; /* do this part */
732 } else if (line.len == 1) { /* end of content desc */
733 flagbadpart = 0; /* default type, so ok */
734 flagseenext = 0; /* done thinking about it */
735 } else /* save line in cont desc */
736 if (!stralloc_cat(&lines,&line)) die_nomem();
739 qa_put(line.s,line.len);
741 } else if (flagarchiveonly && flagarchived) /* received headers */
742 if (substdio_put(&ssarchive,line.s,line.len) == -1) die_archive();
746 if (!boundary.len && flagtrailer) {
747 qmail_puts(&qq,"\n"); /* trailer for non-multipart message */
748 if (!encin || encin == 'Q') { /* can add for QP, but not for base64 */
749 copy(&qq,"text/trailer",encin,FATAL);
750 qmail_puts(&qq,"\n"); /* no need to flush for plain/QP */
754 cumsize += (msgsize + 128L) >> 8; /* round to 256 byte 'records' */
755 /* check message tag */
756 if (flagsublist) { /* sublists need tag if selected/suppt*/
758 if ((ret = checktag(dir,innum,hash_lo+1L,"m",(char *) 0,hashout))) {
759 if (*ret) strerr_die2x(111,FATAL,ret);
760 else strerr_die2x(100,FATAL,ERR_NOT_PARENT);
762 if (!flagmlwasthere) /* sublists need ML header */
763 strerr_die2x(100,FATAL,ERR_SUBLIST);
764 } else /* others are not allowed to have one */
766 strerr_die2x(100,FATAL,ERR_MAILING_LIST);
767 if (!flagfoundokpart) /* all parts were on the strip list */
768 strerr_die2x(100,FATAL,ERR_BAD_ALL);
771 if (substdio_flush(&ssarchive) == -1) die_archive();
772 if (fsync(fdarchive) == -1) die_archive();
773 if (fchmod(fdarchive,MODE_ARCHIVE | 0700) == -1) die_archive();
774 if (close(fdarchive) == -1) die_archive(); /* NFS stupidity */
778 tagmsg(dir,innum,sender,"m",hashout,qq.msgbytes,53L,FATAL);
779 hashout[COOKIE] = '\0';
783 if (!stralloc_copy(&line,&outlocal)) die_nomem();
784 if (!stralloc_cats(&line,"-return-")) die_nomem();
785 if (!stralloc_cats(&line,szmsgnum)) die_nomem();
786 if (!stralloc_cats(&line,"-@")) die_nomem();
787 if (!stralloc_cat(&line,&outhost)) die_nomem();
788 if (!stralloc_cats(&line,"-@[]")) die_nomem();
789 if (!stralloc_0(&line)) die_nomem();
790 qmail_from(&qq,line.s); /* envelope sender */
791 subs = putsubs(dir,hash_lo,hash_hi,subto,1,FATAL); /* subscribers */
792 if (flagsublist) hash_lo++;
794 if (*(err = qmail_close(&qq)) == '\0') {
795 if (flaglog) /* mysql logging */
796 (void) logmsg(dir,outnum,hash_lo,subs,flagsublist ? 3 : 4);
798 strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
799 strerr_die2x(0,"ezmlm-send: info: qp ",strnum);
802 cumsize -= (msgsize + 128L) >> 8;
804 strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);