1 /*$Id: ezmlm-get.c,v 1.113 1999/11/22 01:47:45 lindberg Exp $*/
2 /*$Name: ezmlm-idx-040 $*/
20 #include "readwrite.h"
25 #include "date822fmt.h"
32 #include "subscribe.h"
33 #include "idxthread.h"
38 int flagdo
= 1; /* React to commands (doesn't affect -dig)*/
39 int flagbottom
= 1; /* copy text/bottom + request */
40 int flagpublic
= 2; /* 0 = non-public, 1 = public, 2 = respect*/
42 char flagcd
= '\0'; /* default: don't use quoted-printable */
43 int flagsub
= 0; /* =1 subscribers only for get/index/thread */
45 "from\\to\\subject\\reply-to\\date\\message-id\\cc\\"
46 "mime-version\\content-type\\content-transfer-encoding";
48 #define FATAL "ezmlm-get: fatal: "
53 "ezmlm-get [-bBcClLpPsSvV] [-f fmt] [digestcode]");
56 void die_nomem() { strerr_die2x(111,FATAL
,ERR_NOMEM
); }
60 strerr_die2x(100,FATAL
,ERR_BAD_ADDRESS
);
63 stralloc inhost
= {0};
64 stralloc outhost
= {0};
65 stralloc inlocal
= {0};
66 stralloc outlocal
= {0};
67 stralloc listname
= {0};
68 stralloc mailinglist
= {0};
69 stralloc qmqpservers
= {0};
71 stralloc moddir
= {0};
72 stralloc charset
= {0};
73 stralloc mydtline
= {0};
74 stralloc digheaders
= {0};
76 struct constmap digheadersmap
;
79 stralloc listno
= {0};
80 void *psql
= (void *) 0;
84 unsigned long cumsize
= 0L; /* cumulative msgs / 256 */
85 unsigned long cumsizen
= 0L; /* new cumulative msgs / 256 */
86 unsigned long max
= 0L; /* Last message in archive */
87 unsigned long msgsize
= 0L; /* for digest accounting */
88 datetime_sec digwhen
; /* last digest */
90 char strnum
[FMT_ULONG
];
91 char szmsgnum
[FMT_ULONG
];
92 char date
[DATE822FMT
];
93 char boundary
[COOKIE
];
98 stralloc quoted
= {0};
99 stralloc msgnum
= {0};
101 stralloc subject
= {0};
103 /* for copy archive */
104 stralloc archdate
= {0};
105 stralloc archfrom
= {0};
106 stralloc archto
= {0};
107 stralloc archcc
= {0};
108 stralloc archsubject
= {0};
109 stralloc archmessageid
= {0};
110 stralloc archkeywords
= {0};
111 stralloc archblanklines
= {0};
114 /* for mods on non-public lists (needed for future fuzzy sub dbs) */
115 stralloc mod
= {0}; /* moderator addr for non-public lists */
116 char *pmod
= (char *) 0; /* pointer to above */
122 int act
= AC_NONE
; /* Action we do */
123 int flageditor
= 0; /* if we're invoked for within dir/editor */
126 int flaglocked
= 0; /* if directory is locked */
127 int flagarchived
; /* if list is archived */
128 int flagindexed
; /* if list is indexed */
129 int flagq
= 0; /* don't use 'quoted-printable' */
137 int qqwrite(fd
,buf
,len
) int fd
; char *buf
; unsigned int len
;
139 qmail_put(&qq
,buf
,len
);
147 qmail_put(&qq
,"T",1);
154 substdio ssqq
= SUBSTDIO_FDBUF(qqwrite
,-1,qqbuf
,sizeof(qqbuf
));
157 substdio ssin
= SUBSTDIO_FDBUF(read
,0,inbuf
,sizeof(inbuf
));
158 substdio ssin2
= SUBSTDIO_FDBUF(read
,0,inbuf
,sizeof(inbuf
));
172 /* lock unless locked */
175 fdlock
= open_append("lock");
177 strerr_die2sys(111,FATAL
,ERR_OPEN_LOCK
);
178 if (lock_ex(fdlock
) == -1) {
180 strerr_die2sys(111,FATAL
,ERR_OBTAIN_LOCK
);
187 /* unlock if locked */
203 encodeB(s
,n
,&qline
,0,FATAL
);
205 encodeQ(s
,n
,&qline
,FATAL
);
206 qmail_put(&qq
,qline
.s
,qline
.len
);
207 msgsize
+= qline
.len
;
214 qmail_puts(&qq
,"\nContent-Transfer-Encoding: ");
216 qmail_puts(&qq
,"Quoted-printable\n\n");
218 qmail_puts(&qq
,"base64\n\n");
220 qmail_puts(&qq
,"\n\n");
223 void zapnonsub(szerr
)
224 /* fatal error if flagsub is set and sender is not a subscriber */
225 /* expects the current dir to be the list dir. Error is szerr */
226 /* added check for undefined sender as a precaution */
229 if (sender
&& *sender
) { /* "no sender" is not a subscriber */
232 if (issub(dir
,sender
,(char *) 0,FATAL
))
233 return; /* subscriber */
234 if (issub(ddir
.s
,sender
,(char *) 0,FATAL
))
235 return; /* digest subscriber */
236 if (issub(edir
.s
,sender
,(char *) 0,FATAL
))
237 return; /* allow addresses */
239 strerr_die4x(100,FATAL
,ERR_SUBSCRIBER_CAN
,szerr
,ERR_571
);
244 qmail_puts(&qq
,"To: ");
245 if (!quote2("ed
,sender
)) die_nomem();
246 qmail_put(&qq
,quoted
.s
,quoted
.len
);
247 qmail_puts(&qq
,"\n");
252 /* read dir/num -> max. max/cumsizen left alone if not present */
253 /* Both of these should have been initialized to 0L */
256 if (getconf_line(&num
,"num",0,FATAL
,dir
)) {
257 if(!stralloc_0(&num
)) die_nomem();
258 pos
= scan_ulong(num
.s
,&max
);
259 if (num
.s
[pos
] == ':') pos
++;
260 scan_ulong(num
.s
+pos
,&cumsizen
);
264 unsigned long dignum()
266 /* return dignum if exists, 0 otherwise. */
268 unsigned long retval
;
269 if (!stralloc_copys(&num
,"")) die_nomem(); /* zap */
270 getconf_line(&num
,"dignum",0,FATAL
,dir
);
271 if(!stralloc_0(&num
)) die_nomem();
272 scan_ulong(num
.s
,&retval
);
276 void write_ulong(num
,cum
,dat
,fn
,fnn
)
277 /* write num to "fnn" add ':' & cum if cum <>0, then move "fnn" to "fn" */
279 unsigned long num
,cum
,dat
;
283 fd
= open_trunc(fnn
);
285 strerr_die6sys(111,FATAL
,ERR_CREATE
,dir
,"/",fnn
,": ");
286 substdio_fdbuf(&ssnum
,write
,fd
,numbuf
,sizeof(numbuf
));
287 if (substdio_put(&ssnum
,strnum
,fmt_ulong(strnum
,num
)) == -1)
288 strerr_die6sys(111,FATAL
,ERR_WRITE
,dir
,"/",fnn
,": ");
289 if (substdio_puts(&ssnum
,":") == -1)
290 strerr_die6sys(111,FATAL
,ERR_WRITE
,dir
,"/",fnn
,": ");
291 if (substdio_put(&ssnum
,strnum
,fmt_ulong(strnum
,cum
)) == -1)
292 strerr_die6sys(111,FATAL
,ERR_WRITE
,dir
,"/",fnn
,": ");
294 if (substdio_puts(&ssnum
,":") == -1)
295 strerr_die6sys(111,FATAL
,ERR_WRITE
,dir
,"/",fnn
,": ");
296 if (substdio_put(&ssnum
,strnum
,fmt_ulong(strnum
,dat
)) == -1)
297 strerr_die6sys(111,FATAL
,ERR_WRITE
,dir
,"/",fnn
,": ");
299 if (substdio_puts(&ssnum
,"\n") == -1)
300 strerr_die6sys(111,FATAL
,ERR_WRITE
,dir
,"/",fnn
,": ");
301 if (substdio_flush(&ssnum
) == -1)
302 strerr_die6sys(111,FATAL
,ERR_FLUSH
,dir
,"/",fnn
,": ");
304 strerr_die6sys(111,FATAL
,ERR_SYNC
,dir
,"/",fnn
,": ");
306 strerr_die6sys(111,FATAL
,ERR_CLOSE
,dir
,"/",fnn
,": ");
307 if (rename(fnn
,fn
) == -1)
308 strerr_die4sys(111,FATAL
,ERR_MOVE
,fnn
,": ");
311 void normal_bottom(format
)
313 /* Copies bottom text and the original message to the new message */
316 copy(&qq
,"text/bottom",flagcd
,FATAL
);
317 if (flagcd
&& format
!= RFC1153
) {
319 encodeB("",0,&line
,2,FATAL
); /* flush */
320 qmail_put(&qq
,line
.s
,line
.len
);
322 qmail_puts(&qq
,"\n--");
323 qmail_put(&qq
,boundary
,COOKIE
);
324 qmail_puts(&qq
,"\nContent-Type: message/rfc822");
325 qmail_puts(&qq
,"\nContent-Disposition: inline; filename=request.msg\n\n");
327 qmail_puts(&qq
,"Return-Path: <");
328 if (!quote2("ed
,sender
)) die_nomem();
329 qmail_put(&qq
,quoted
.s
,quoted
.len
);
330 qmail_puts(&qq
,">\n");
331 if (seek_begin(0) == -1)
332 strerr_die2sys(111,FATAL
,ERR_SEEK_INPUT
);
333 if (substdio_copy(&ssqq
,&ssin2
) != 0)
334 strerr_die2sys(111,FATAL
,ERR_READ_INPUT
);
336 if (flagcd
== 'B' && format
!= RFC1153
) {
337 encodeB("",0,&line
,2,FATAL
); /* flush */
338 qmail_put(&qq
,line
.s
,line
.len
);
343 void presub(from
,to
,subject
,factype
,format
)
344 /* Starts within header, outputs "subject" and optional headers, terminates*/
345 /* header and handles output before table-of-contents */
346 unsigned long from
,to
;
348 int factype
; /* action type (AC_THREAD, AC_GET, AC_DIGEST) */
349 char format
; /* output format type (see idx.h) */
351 qmail_puts(&qq
,"MIME-Version: 1.0\n");
357 qmail_puts(&qq
,"Content-Type: multipart/");
359 qmail_puts(&qq
,"mixed");
361 qmail_puts(&qq
,"digest");
362 qmail_puts(&qq
,"; boundary=");
363 qmail_put(&qq
,boundary
,COOKIE
);
364 qmail_puts(&qq
,"\nSubject: ");
365 qmail_put(&qq
,subject
->s
,subject
->len
);
366 qmail_puts(&qq
,"\n\n\n--");
367 qmail_put(&qq
,boundary
,COOKIE
);
368 qmail_puts(&qq
,"\nContent-Type: text/plain; charset=");
369 qmail_puts(&qq
,charset
.s
);
370 transferenc(); /* content-transfer-enc header if needed */
371 qmail_puts(&qq
,"\n");
374 qmail_puts(&qq
,"Content-type: text/plain; charset=");
375 qmail_puts(&qq
,charset
.s
);
376 qmail_puts(&qq
,"\nSubject: ");
377 qmail_put(&qq
,subject
->s
,subject
->len
);
378 qmail_puts(&qq
,"\n\n");
379 flagcd
= '\0'; /* We make 8-bit messages, not QP/bas64 for rfc1153 */
380 break; /* Since messages themselves aren't encoded */
382 if (!stralloc_cats(subject
,"\n\n")) die_nomem();
383 code_qput(subject
->s
,subject
->len
);
384 if (format
!= NATIVE
&& factype
!= AC_THREAD
&& factype
!= AC_INDEX
) {
385 if (!stralloc_copys(&line
,TXT_TOP_TOPICS
)) die_nomem();
386 if (!stralloc_cats(&line
,TXT_TOP_MESSAGES
)) die_nomem();
387 if (!stralloc_catb(&line
,strnum
,fmt_ulong(strnum
,from
))) die_nomem();
388 if (!stralloc_cats(&line
,TXT_TOP_THROUGH
)) die_nomem();
389 if (!stralloc_catb(&line
,strnum
,fmt_ulong(strnum
,to
))) die_nomem();
390 if (!stralloc_cats(&line
,TXT_TOP_LAST
)) die_nomem();
391 code_qput(line
.s
,line
.len
);
395 void postsub(factype
,format
)
396 /* output after TOC and before first message. */
397 int factype
; /* action type (AC_THREAD, AC_GET, AC_DIGEST) */
398 char format
; /* output format type (see idx.h) */
400 code_qput(TXT_ADMINISTRIVIA
,str_len(TXT_ADMINISTRIVIA
));
401 if(factype
== AC_DIGEST
) {
402 copy(&qq
,"text/digest",flagcd
,FATAL
);
404 encodeB("",0,&line
,2,FATAL
); /* flush */
405 qmail_put(&qq
,line
.s
,line
.len
);
408 normal_bottom(format
);
409 if (!flagcd
|| format
== RFC1153
)
410 qmail_puts(&qq
,"\n----------------------------------------------------------------------\n");
412 qmail_puts(&qq
,"\n");
423 qmail_puts(&qq
,"\n--");
424 qmail_put(&qq
,boundary
,COOKIE
); /* digest boundary */
425 qmail_puts(&qq
,"--\n");
428 qmail_puts(&qq
,"End of ");
429 qmail_put(&qq
,listname
.s
,listname
.len
);
430 qmail_puts(&qq
," Digest");
431 qmail_puts(&qq
,"\n***********************************\n");
436 void copymsg(msg
,fd
,format
)
437 /* Copy archive message "msg" itself from open file handle fd, in "format" */
438 unsigned long msg
; int fd
; char format
;
448 substdio_fdbuf(&sstext
,read
,fd
,textbuf
,sizeof(textbuf
));
450 if (getln(&sstext
,&line
,&match
,'\n') == -1)
451 strerr_die4sys(111,FATAL
,ERR_READ
,line
.s
,": ");
453 qmail_put(&qq
,line
.s
,line
.len
);
463 substdio_fdbuf(&sstext
,read
,fd
,textbuf
,sizeof(textbuf
));
465 if (getln(&sstext
,&line
,&match
,'\n') == -1)
466 strerr_die4sys(111,FATAL
,ERR_READ
,line
.s
,": ");
472 } else if (line
.s
[0] != ' ' && line
.s
[0] != '\t') {
474 if (constmap(&digheadersmap
,line
.s
,
475 byte_chr(line
.s
,line
.len
,':')))
479 qmail_put(&qq
,line
.s
,line
.len
); /* header */
483 qmail_put(&qq
,line
.s
,line
.len
); /* body */
490 case RFC1153
: /* Not worth optimizing. Rarely used */
492 flagskipblanks
= 1; /* must skip terminal blanks acc to rfc1153 */
493 archtype
= ' '; /* rfc1153 requires ordered headers */
494 if (!stralloc_copys(&archblanklines
,"")) die_nomem();
495 substdio_fdbuf(&sstext
,read
,fd
,textbuf
,sizeof(textbuf
));
497 if (getln(&sstext
,&line
,&match
,'\n') == -1)
498 strerr_die4sys(111,FATAL
,ERR_READ
,line
.s
,": ");
504 qmail_put(&qq
,archdate
.s
,archdate
.len
);
506 msgsize
+= archdate
.len
;
509 qmail_put(&qq
,archto
.s
,archto
.len
);
510 msgsize
+= archto
.len
;
514 qmail_put(&qq
,archfrom
.s
,archfrom
.len
);
515 msgsize
+= archfrom
.len
;
519 qmail_put(&qq
,archcc
.s
,archcc
.len
);
520 msgsize
+= archcc
.len
;
523 if (archsubject
.len
) {
524 qmail_put(&qq
,archsubject
.s
,archsubject
.len
);
525 msgsize
+= archsubject
.len
;
528 if (archmessageid
.len
) {
529 qmail_put(&qq
,archmessageid
.s
,archmessageid
.len
);
530 msgsize
+= archmessageid
.len
;
531 archmessageid
.len
= 0;
533 if (archkeywords
.len
) {
534 qmail_put(&qq
,archkeywords
.s
,archkeywords
.len
);
535 msgsize
+= archkeywords
.len
;
536 archkeywords
.len
= 0;
538 qmail_puts(&qq
,"\n");
539 } else if (line
.s
[0] == ' ' || line
.s
[0] == '\t') {
540 switch (archtype
) { /* continuation lines */
544 if (!stralloc_cat(&archdate
,&line
)) die_nomem(); break;
546 if (!stralloc_cat(&archfrom
,&line
)) die_nomem(); break;
548 if (!stralloc_cat(&archto
,&line
)) die_nomem(); break;
550 if (!stralloc_cat(&archcc
,&line
)) die_nomem(); break;
552 if (!stralloc_cat(&archsubject
,&line
)) die_nomem(); break;
554 if (!stralloc_cat(&archmessageid
,&line
)) die_nomem(); break;
556 if (!stralloc_cat(&archkeywords
,&line
)) die_nomem(); break;
558 strerr_die2x(111,FATAL
,
559 "Program error: Bad archive header type");
563 if (case_startb(line
.s
,line
.len
,"cc:")) {
565 if (!stralloc_copy(&archcc
,&line
)) die_nomem();
567 else if (case_startb(line
.s
,line
.len
,"date:")) {
569 if (!stralloc_copy(&archdate
,&line
)) die_nomem();
571 else if (case_startb(line
.s
,line
.len
,"from:")) {
573 if (!stralloc_copy(&archfrom
,&line
)) die_nomem();
575 else if (case_startb(line
.s
,line
.len
,"keywords:")) {
577 if (!stralloc_copy(&archkeywords
,&line
)) die_nomem();
579 else if (case_startb(line
.s
,line
.len
,"message-id:")) {
581 if (!stralloc_copy(&archmessageid
,&line
)) die_nomem();
583 else if (case_startb(line
.s
,line
.len
,"subject:")) {
585 if (!stralloc_copy(&archsubject
,&line
)) die_nomem();
587 else if (case_startb(line
.s
,line
.len
,"to:")) {
589 if (!stralloc_copy(&archto
,&line
)) die_nomem();
592 } else if (line
.len
== 1) {
594 if (!stralloc_copys(&archblanklines
,"\n")) die_nomem();
596 if (archblanklines
.len
) {
597 qmail_put(&qq
,archblanklines
.s
,archblanklines
.len
);
598 archblanklines
.len
= 0;
601 qmail_put(&qq
,line
.s
,line
.len
);
609 strerr_die2x(100,FATAL
,"Program error: bad format in copymsg()");
613 void mime_getbad(msg
)
614 /* Message not found as a MIME multipart */
617 qmail_puts(&qq
,"\n--");
618 qmail_put(&qq
,boundary
,COOKIE
);
619 qmail_puts(&qq
,"\nContent-Type: text/plain; charset=");
620 qmail_puts(&qq
,charset
.s
);
621 qmail_puts(&qq
,"\nContent-Disposition: inline; filename=\"");
622 qmail_put(&qq
,listname
.s
,listname
.len
);
624 qmail_put(&qq
,strnum
,fmt_ulong(strnum
,msg
));
625 qmail_puts(&qq
,".ezm\"\n");
627 copy(&qq
,"text/get-bad",flagcd
,FATAL
);
630 void msgout(msg
,format
)
631 /* Outputs message (everything that's needed per message) */
632 unsigned long msg
; char format
;
637 if (!stralloc_copys(&fn
,"archive/")) die_nomem();
639 len
= fmt_ulong(strnum
, msg
/ 100);
640 if (!stralloc_catb(&fn
,strnum
,len
)) die_nomem();
641 if (!stralloc_cats(&fn
,"/")) die_nomem();
642 len
= fmt_uint0(strnum
, (unsigned int) (msg
% 100),2);
643 if (!stralloc_catb(&fn
,strnum
,len
)) die_nomem();
644 if (!stralloc_0(&fn
)) die_nomem();
651 fd
= open_read(fn
.s
);
653 if (errno
!= error_noent
)
654 strerr_die4sys(111,FATAL
,ERR_OPEN
,fn
.s
,": ");
657 } else if (fstat(fd
,&st
) == -1 || (!(st
.st_mode
& 0100))) {
661 qmail_puts(&qq
,"\n--");
662 qmail_put(&qq
,boundary
,COOKIE
);
663 qmail_puts(&qq
,"\nContent-Type: message/rfc822");
664 qmail_puts(&qq
,"\nContent-Disposition: inline; filename=\"");
665 qmail_put(&qq
,listname
.s
,listname
.len
);
667 qmail_put(&qq
,strnum
,fmt_ulong(strnum
,msg
));
668 qmail_puts(&qq
,".ezm\"\n\n");
669 copymsg(msg
,fd
,format
);
674 fd
= open_read(fn
.s
);
676 if (errno
!= error_noent
)
677 strerr_die4sys(111,FATAL
,ERR_OPEN
,fn
.s
,": ");
679 qmail_puts(&qq
,"\n== ");
680 qmail_put(&qq
,strnum
,fmt_ulong(strnum
,msg
));
681 qmail_puts(&qq
," ==\n\n");
682 copy(&qq
,"text/get-bad",flagcd
,FATAL
);
685 if (fstat(fd
,&st
) == -1 || (!(st
.st_mode
& 0100))) {
687 qmail_puts(&qq
,"\n== ");
688 qmail_put(&qq
,strnum
,fmt_ulong(strnum
,msg
));
689 qmail_puts(&qq
," ==\n\n");
690 copy(&qq
,"text/get-bad",flagcd
,FATAL
);
692 copymsg(msg
,fd
,format
);
696 qmail_puts(&qq
,"\n------------------------------\n\n");
699 strerr_die2x(100,FATAL
,"Program error: Unrecognized format in msgout");
704 void digest(msgtable
,subtable
,authtable
,from
,to
,subj
,factype
,format
)
705 /* Output digest range from-to as per msgtable/subtable (from mkthread(s)). */
706 /* "Subject is the subject of the _entire_ digest/set. */
707 msgentry
*msgtable
; subentry
*subtable
; authentry
*authtable
;
708 unsigned long from
,to
; stralloc
*subj
; int factype
; char format
;
716 unsigned long subnum
;
719 presub(from
,to
,subj
,factype
,format
);
721 if (format
!= NATIVE
) {
724 /* ptr to first message with this subject */
725 pmsgt
= msgtable
+ psubt
->firstmsg
- from
;
726 subnum
= (unsigned long) (psubt
- subtable
+1);
727 for (msg
=psubt
->firstmsg
; msg
<=to
; msg
++) {
728 if (pmsgt
->subnum
== subnum
) {
731 if (!stralloc_copys(&line
,"\n")) die_nomem();
732 if (psubt
->sublen
<= HASHLEN
+ 2) {
733 if (!stralloc_cats(&line
,"(null)\n")) die_nomem();
735 if (!stralloc_catb(&line
,psubt
->sub
+ HASHLEN
+ 1,
736 psubt
->sublen
- HASHLEN
- 1)) die_nomem();
738 if (!stralloc_copys(&line
,"")) die_nomem();
739 if (!stralloc_cats(&line
,"\t")) die_nomem();
740 if (!stralloc_catb(&line
,strnum
,fmt_ulong(strnum
,msg
))) die_nomem();
741 if (!stralloc_cats(&line
,TXT_BY
)) die_nomem();
742 if (pmsgt
->authnum
) {
743 cp
= authtable
[pmsgt
->authnum
- 1].auth
;
744 len
= authtable
[pmsgt
->authnum
- 1].authlen
;
746 if (!stralloc_catb(&line
,cp
+ HASHLEN
+ 1,
747 len
- HASHLEN
- 1)) die_nomem();
749 if (!stralloc_catb(&line
,cp
,len
)) die_nomem();
751 if (!stralloc_cats(&line
,"\n")) die_nomem();
752 code_qput(line
.s
,line
.len
);
759 postsub(factype
,format
);
763 pmsgt
= msgtable
+ psubt
->firstmsg
- from
;
764 subnum
= (unsigned long) (psubt
- subtable
+1);
765 for (msg
=psubt
->firstmsg
; msg
<=to
; msg
++) {
766 if (pmsgt
->subnum
== subnum
)
773 idx_destroythread(msgtable
,subtable
,authtable
);
778 int flaggoodfield
,match
;
780 if (act
== AC_DIGEST
)
781 copy(&qq
,"headeradd",'H',FATAL
);
783 qmail_puts(&qq
,"Mailing-List: ");
784 qmail_put(&qq
,mailinglist
.s
,mailinglist
.len
);
785 if (getconf_line(&line
,"listid",0,FATAL
,dir
)) {
786 qmail_puts(&qq
,"\nList-ID: ");
787 qmail_put(&qq
,line
.s
,line
.len
);
789 qmail_puts(&qq
,"\nDate: ");
790 qmail_put(&qq
,date
,date822fmt(date
,&dt
));
791 qmail_puts(&qq
,"Message-ID: <");
792 if (!stralloc_copyb(&line
,strnum
,fmt_ulong(strnum
,(unsigned long) when
)))
794 if (!stralloc_append(&line
,".")) die_nomem();
795 if (!stralloc_catb(&line
,strnum
,
796 fmt_ulong(strnum
,(unsigned long) getpid()))) die_nomem();
797 if (!stralloc_cats(&line
,".ezmlm@")) die_nomem();
798 if (!stralloc_cat(&line
,&outhost
)) die_nomem();
799 if (!stralloc_0(&line
)) die_nomem();
800 qmail_puts(&qq
,line
.s
);
801 /* "unique" MIME boundary as hash of messageid */
802 makehash(line
.s
,line
.len
,boundary
);
803 qmail_puts(&qq
,">\nFrom: ");
804 if (!quote("ed
,&outlocal
)) die_nomem();
805 qmail_put(&qq
,quoted
.s
,quoted
.len
);
806 qmail_puts(&qq
,"-help@");
807 qmail_put(&qq
,outhost
.s
,outhost
.len
);
808 qmail_puts(&qq
,"\n");
809 if (!stralloc_copys(&mydtline
,"Delivered-To: responder for ")) die_nomem();
810 if (!stralloc_catb(&mydtline
,outlocal
.s
,outlocal
.len
)) die_nomem();
811 if (!stralloc_cats(&mydtline
,"@")) die_nomem();
812 if (!stralloc_catb(&mydtline
,outhost
.s
,outhost
.len
)) die_nomem();
813 if (!stralloc_cats(&mydtline
,"\n")) die_nomem();
815 qmail_put(&qq
,mydtline
.s
,mydtline
.len
);
818 if (act
!= AC_DIGEST
)
820 if (getln(&ssin
,&line
,&match
,'\n') == -1)
821 strerr_die2sys(111,FATAL
,ERR_READ_INPUT
);
823 if (line
.len
== 1) break;
824 if ((line
.s
[0] != ' ') && (line
.s
[0] != '\t')) {
826 if (case_startb(line
.s
,line
.len
,"mailing-list:"))
827 if (flageditor
) /* we may be running from a sublist */
830 strerr_die2x(100,FATAL
,ERR_MAILING_LIST
);
831 if (line
.len
== mydtline
.len
)
832 if (byte_equal(line
.s
,line
.len
,mydtline
.s
))
833 strerr_die2x(100,FATAL
,ERR_LOOPING
);
834 if (case_startb(line
.s
,line
.len
,"delivered-to:"))
836 if (case_startb(line
.s
,line
.len
,"received:"))
840 qmail_put(&qq
,line
.s
,line
.len
);
859 int goodexit
= 0; /* exit code for normal exit */
860 /* in manager this will be set to 0 */
861 unsigned long from
,u
,to
,issue
,prevmax
,mno
;
864 unsigned int pos
,pos1
;
867 char outformat
= DEFAULT_FORMAT
; /* default output format */
870 authentry
*authtable
;
871 dateentry
*datetable
;
876 datetime_tai(&dt
,when
);
878 while ((opt
= getopt(argc
,argv
,"bBcCf:pPsSt:vV")) != opteof
)
880 case 'b': flagbottom
= 1; break; /* add text/bottom (default) */
881 case 'B': flagbottom
= 0; break; /* suppress text/bottom */
882 case 'c': flagdo
= 1; break; /* do commands */
883 case 'C': flagdo
= 0; break; /* ignore commands X dig */
884 case 'f': if (FORMATS
[str_chr(FORMATS
,optarg
[0])])
885 outformat
= optarg
[0];
887 case 'p': flagpublic
= 1; break; /* always public */
888 case 'P': flagpublic
= 0; break; /* never public = only mods do cmd*/
889 /* def = 2: respect DIR/public */
890 case 's': flagsub
= 1; break; /* only subs have archive access */
891 case 'S': flagsub
= 0; break; /* everyone has archive access */
893 case 'V': strerr_die2x(0,"ezmlm-get version: ",EZIDX_VERSION
);
898 dir
= argv
[optind
++];
899 if (!dir
) die_usage();
900 if (chdir(dir
) == -1)
901 strerr_die4x(111,FATAL
,ERR_SWITCH
,dir
,": ");
903 digestcode
= argv
[optind
]; /* code to activate digest (-digest-code)*/
904 /* ignore any extra args */
906 getconf_line(&outlocal
,"outlocal",1,FATAL
,dir
);
907 if (!stralloc_copy(&subject
,&outlocal
)) die_nomem(); /* for subjects */
908 if (!stralloc_copy(&listname
,&outlocal
)) die_nomem(); /* for content disp */
910 local
= env_get("LOCAL");
911 def
= env_get("DEFAULT");
912 sender
= env_get("SENDER");
913 if (local
&& *local
) { /* in editor local = inlocal */
914 if (!sender
) strerr_die2x(100,FATAL
,ERR_NOSENDER
);
916 strerr_die2x(100,FATAL
,ERR_BOUNCE
);
917 if (str_equal(sender
,"#@[]"))
918 strerr_die2x(100,FATAL
,ERR_BOUNCE
);
919 if (!sender
[str_chr(sender
,'@')])
920 strerr_die2x(100,FATAL
,ERR_ANONYMOUS
);
921 if (def
) { /* qmail>=1.02 support only */
926 _exit(0); /* list-@host should do -help from manager */
927 } else { /* editor */
928 act
= AC_DIGEST
; /* on list-@host ! */
929 flageditor
= 1; /* to avoid Mailing-list error on sublists */
930 /* when running out of dir/editor. */
932 if (case_starts(action
,"dig")) {
934 if (action
[0] == '-' || action
[0] == '.') {
937 strerr_die2x(100,FATAL
,ERR_BAD_DIGCODE
);
938 len
= str_len(digestcode
);
939 if (len
<= str_len(action
) && case_startb(action
,len
,digestcode
)) {
940 if (FORMATS
[str_chr(FORMATS
,*(action
+len
))])
941 outformat
= *(action
+len
);
944 strerr_die2x(100,FATAL
,ERR_BAD_DIGCODE
);
947 } else /* Command line operation */
950 /* Things we deal with. If anything else just die with success! */
951 /* At the moment this is -index, -thread, and -get. */
952 /* If flagdo = 0 we only service -dig commands. This is to support*/
953 /* "secret" lists that are still archived and digested. -c on */
956 if (act
== AC_NONE
) {
957 if (case_equals(action
,ACTION_DIGEST
)) {
958 act
= AC_GET
; /* list-digest@ => msg since last digest */
960 } else if (case_starts(action
,ACTION_GET
) || case_starts(action
,ALT_GET
))
962 else if (case_starts(action
,ACTION_INDEX
) || case_starts(action
,ALT_INDEX
))
964 else if (case_starts(action
,ACTION_THREAD
) ||
965 case_starts(action
,ALT_THREAD
))
968 if (act
== AC_NONE
) /* not for us. Pass the buck. */
970 if (act
!= AC_INDEX
) { /* need to do header processing */
971 if(!getconf(&digheaders
,"digheaders",0,FATAL
,dir
)) {
972 if(!stralloc_copys(&digheaders
,digsz
)) die_nomem();
973 if (!stralloc_0(&digheaders
)) die_nomem();
976 if (*psz
== '\\') *psz
= '\0';
980 if (!constmap_init(&digheadersmap
,digheaders
.s
,digheaders
.len
,0))
983 if (act
!= AC_DIGEST
) {
984 if (!flagdo
) /* only do digests */
985 strerr_die2x(100,FATAL
,ERR_NOCMD
);
987 flagpublic
= getconf_line(&line
,"public",0,FATAL
,dir
);
989 /* This all to take care of non-public lists. They should*/
990 /* still do digests, but do other things only for */
991 /* moderators that have remote access. Since this is rare*/
992 /* efforts have been made to keep everything that's not */
993 /* needed elsewhere in here. */
994 getconf_line(&moddir
,"modsub",0,FATAL
,dir
);
995 flagremote
= getconf_line(&line
,"remote",0,FATAL
,dir
);
997 strerr_die2x(100,FATAL
,ERR_NOT_PUBLIC
);
998 if (!moddir
.len
|| moddir
.s
[0] != '/') {
999 if (line
.len
&& line
.s
[0] == '/') {
1000 if (!stralloc_copy(&moddir
,&line
)) die_nomem();
1002 if (!stralloc_copys(&moddir
,dir
)) die_nomem();
1003 if (!stralloc_cats(&moddir
,"/mod")) die_nomem();
1006 if (!stralloc_0(&moddir
)) die_nomem();
1007 pmod
= issub(moddir
.s
,sender
,(char *) 0,FATAL
);
1008 if (!pmod
) /* sender = moderator? */
1009 strerr_die2x(100,FATAL
,ERR_NOT_PUBLIC
);
1011 if (!stralloc_copys(&mod
,pmod
)) die_nomem();
1012 if (!stralloc_0(&mod
)) die_nomem();
1013 pmod
= mod
.s
; /* send to address in list not matching bait */
1018 flagindexed
= getconf_line(&line
,"indexed",0,FATAL
,dir
);
1019 flagarchived
= getconf_line(&line
,"archived",0,FATAL
,dir
);
1021 if (getconf_line(&charset
,"charset",0,FATAL
,dir
)) {
1022 if (charset
.len
>= 2 && charset
.s
[charset
.len
- 2] == ':') {
1023 if (charset
.s
[charset
.len
- 1] == 'B' ||
1024 charset
.s
[charset
.len
- 1] == 'Q') {
1025 flagcd
= charset
.s
[charset
.len
- 1];
1026 charset
.s
[charset
.len
- 2] = '\0';
1030 if (!stralloc_copys(&charset
,TXT_DEF_CHARSET
)) die_nomem();
1031 if (!stralloc_0(&charset
)) die_nomem();
1032 getconf_line(&mailinglist
,"mailinglist",1,FATAL
,dir
);
1033 getconf_line(&outhost
,"outhost",1,FATAL
,dir
);
1034 set_cpouthost(&outhost
);
1036 if (!stralloc_copys(&ddir
,dir
)) die_nomem();
1037 if (!stralloc_cats(&ddir
,"/digest")) die_nomem();
1038 if (!stralloc_0(&ddir
)) die_nomem();
1039 if (act
== AC_DIGEST
) {
1041 if (!stralloc_cats(&outlocal
,"-digest")) die_nomem();
1042 if (getconf_line(&line
,"chunk",0,FATAL
,dir
)) {
1043 if (!stralloc_0(&line
)) die_nomem();
1044 (void) scan_ulong(line
.s
,&chunk
); /* same chunk as main list */
1045 if (chunk
== 0) /* limit range to 1-53 */
1047 else if (chunk
> 52)
1050 chunk
= 0L; /* maybe direct qmqp? */
1051 if (!stralloc_copys(&line
,QMQPSERVERS
)) die_nomem();
1052 if (!stralloc_cats(&line
,"/0")) die_nomem();
1053 if (!stralloc_0(&line
)) die_nomem();
1054 flagqmqp
= getconf(&qmqpservers
,line
.s
,0,FATAL
,dir
);
1059 if (!stralloc_copys(&edir
,dir
)) die_nomem(); /* not needed for -dig, but */
1060 if (!stralloc_cats(&edir
,"/allow")) die_nomem(); /* be safe */
1061 if (!stralloc_0(&edir
)) die_nomem();
1062 set_cpoutlocal(&outlocal
); /* needed for copy */
1065 if (qmail_open(&qq
,&qmqpservers
) == -1) /* open qmail */
1066 strerr_die2sys(111,FATAL
,ERR_QMAIL_QUEUE
);
1067 } else if (qmail_open(&qq
,(stralloc
*) 0) == -1) /* open qmail */
1068 strerr_die2sys(111,FATAL
,ERR_QMAIL_QUEUE
);
1070 set_cpnum(""); /* default for <#n#> replacement */
1072 if (act
== AC_DIGEST
) {
1073 /* -dig{.|-}'digestcode'[f] returns an rfc1153 digest */
1074 /* of messages from the archive. Messages */
1075 /* dignum+1 through the last message received by the list are processed and */
1076 /* dignum is updated to the last message processed. digissue is advanced. */
1079 strerr_die2x(100,FATAL
,ERR_NOT_ARCHIVED
);
1081 get_num(); /* max = last successful message */
1083 lockup(); /* another digest could corrupt dignum */
1084 /* but will be saved only if flagdigrange==0 */
1085 if(getconf_line(&num
,"dignum",0,FATAL
,dir
)) {
1086 if(!stralloc_0(&num
)) die_nomem();
1087 pos
= scan_ulong(num
.s
,&prevmax
);
1088 if (num
.s
[pos
] == ':') pos
++;
1089 pos
+= 1 + scan_ulong(num
.s
+pos
,&cumsize
); /* last cumsize */
1090 if (num
.s
[pos
] == ':') pos
++;
1091 scan_ulong(num
.s
+pos
,&digwhen
); /* last reg dig */
1098 if(!max
|| mno
> max
) /* if a digest-list is "sending" the request, */
1099 /* don't make noise: errors go to postmaster!*/
1100 strerr_die2x(goodexit
,FATAL
,ERR_EMPTY_DIGEST
);
1101 szmsgnum
[fmt_ulong(szmsgnum
,mno
)] = '\0';
1102 set_cpnum(szmsgnum
); /* for copy */
1103 /* prepare subject to get entropy for tagmsg*/
1104 if (!stralloc_cats(&subject
," Digest ")) die_nomem();
1105 if (!stralloc_catb(&subject
,date
,date822fmt(date
,&dt
)-1))
1106 die_nomem(); /* skip trailing in date '\n' */
1107 if (!stralloc_cats(&subject
," Issue ")) die_nomem();
1108 if (getconf_line(&num
,"digissue",0,FATAL
,dir
)) {
1109 if(!stralloc_0(&num
)) die_nomem();
1110 scan_ulong(num
.s
,&issue
);
1115 if (!stralloc_catb(&subject
,strnum
,fmt_ulong(strnum
,issue
)))
1117 /* use the subject as entropy */
1118 if (!stralloc_copy(&line
,&subject
)) die_nomem();
1119 if (!stralloc_0(&line
)) die_nomem();
1121 if (!stralloc_ready(&seed
,HASHLEN
+1)) die_nomem();
1122 seed
.len
= HASHLEN
+ 1;
1123 seed
.s
[HASHLEN
] = '\0';
1124 makehash(line
.s
,line
.len
,seed
.s
);
1125 if (chunk
) { /* only if slaves are used */
1126 qmail_puts(&qq
,"Ezauth: ");
1127 qmail_put(&qq
,seed
.s
,HASHLEN
);
1128 qmail_puts(&qq
,"\n");
1132 qmail_puts(&qq
,"To: ");
1133 if (!quote("ed
,&listname
)) die_nomem();
1134 qmail_put(&qq
,quoted
.s
,quoted
.len
);
1135 qmail_puts(&qq
,"@");
1136 qmail_put(&qq
,outhost
.s
,outhost
.len
);
1137 qmail_puts(&qq
,"\n");
1138 if (flagindexed
&& (outformat
!= NATIVE
))
1139 idx_mkthreads(&msgtable
,&subtable
,&authtable
,&datetable
,
1140 mno
,to
,max
,flaglocked
,FATAL
);
1142 idx_mklist(&msgtable
,&subtable
,&authtable
,mno
,to
,FATAL
);
1143 digest(msgtable
,subtable
,authtable
,mno
,to
,&subject
,AC_DIGEST
,outformat
);
1145 write_ulong(issue
,0L,0L,"digissue","digissuen");
1146 write_ulong(max
,cumsizen
, (unsigned long) when
,"dignum","dignumn");
1149 else if (act
== AC_GET
) {
1151 /* -get[-|\.][[num].num2] copies archive num-num2. num & num2 are adjusted */
1152 /* to be > 0 and <= last message, to num2 >= num and to num2-num <= MAXGET. */
1155 strerr_die2x(100,FATAL
,ERR_NOT_ARCHIVED
);
1156 zapnonsub(ACTION_GET
); /* restrict to subs if requested */
1159 if (!stralloc_cats(&subject
," Digest of: ")) die_nomem();
1160 if (!stralloc_cats(&subject
,action
)) die_nomem();
1163 pos
= str_len(ACTION_GET
);
1164 if (!case_starts(action
,ACTION_GET
))
1165 pos
= str_len(ALT_GET
);
1166 if (FORMATS
[str_chr(FORMATS
,action
[pos
])]) {
1167 outformat
= action
[pos
];
1170 /* optional - or . after '-get' */
1171 if (action
[pos
] == '-' || action
[pos
] == '.') pos
++;
1172 get_num(); /* max = last successful message */
1173 /* accept any separator. It may be */
1174 /* the terminal '\n', but then */
1175 /* scan will = 0 on the \0 so should*/
1178 strerr_die2x(100,FATAL
,ERR_EMPTY_LIST
);
1179 szmsgnum
[fmt_ulong(szmsgnum
,max
)] = '\0';
1180 set_cpnum(szmsgnum
); /* for copy this is the latest message arch'd*/
1182 if(action
[pos
+= scan_ulong(action
+ pos
,&u
)])
1183 scan_ulong(action
+ pos
+ 1, &to
);
1184 if (u
== 0 && to
== 0) { /* default: messages since last */
1185 /* digest, or last MAXGET if too many */
1188 if (u
== 0) { /* no digest => last up to HISTGET msgs */
1190 if (max
> HISTGET
) u
= max
- HISTGET
; else u
= 1;
1192 if (to
- u
>= MAXGET
) u
= to
- MAXGET
+ 1; /* max MAXGET */
1193 } else if (u
> max
) {
1194 if (to
) { /* -get.999999_x returns 30 and msg since last*/
1195 to
= max
; /* digest 30*/
1197 if (u
> HISTGET
) u
-= HISTGET
; else u
= 1;
1198 if (to
- u
>= MAXGET
) u
= to
- MAXGET
+ 1;
1202 if (u
== 0) u
= 1; /* -get.5 => 1-5 */
1203 if (to
< u
) to
= u
; /* -get23_2 => 23 */
1204 if (to
>= u
+ MAXGET
) to
= u
+ MAXGET
- 1;
1205 /* no more than MAXGET at a time */
1206 if (to
> max
) to
= max
;
1207 if (flagindexed
&& (outformat
!= NATIVE
)) /* fake out threading */
1208 idx_mkthreads(&msgtable
,&subtable
,&authtable
,&datetable
,
1211 idx_mklist(&msgtable
,&subtable
,&authtable
,u
,to
,FATAL
);
1212 digest(msgtable
,subtable
,authtable
,u
,to
,&subject
,AC_GET
,outformat
);
1215 else if (act
== AC_INDEX
) {
1217 /* -index[f][#|-|\.][[num][.num2] Show subject index for messages num-num2 in*/
1219 /* Default last 2 sets. num and num2 are made reasonable as for get. num2 is */
1220 /* limited to num+MAXINDEX to limit the amount of data sent. */
1223 strerr_die2x(100,FATAL
,ERR_NOT_INDEXED
);
1225 zapnonsub(ACTION_INDEX
); /* restrict to subs if requested */
1227 pos
= str_len(ACTION_INDEX
);
1228 if (!case_starts(action
,ACTION_INDEX
))
1229 pos
= str_len(ALT_INDEX
);
1230 if (FORMATS
[str_chr(FORMATS
,action
[pos
])]) {
1231 outformat
= action
[pos
]; /* ignored, but be nice ... */
1234 get_num(); /* max = last successful message */
1236 strerr_die2x(100,FATAL
,ERR_EMPTY_LIST
);
1237 szmsgnum
[fmt_ulong(szmsgnum
,max
)] = '\0';
1238 set_cpnum(szmsgnum
); /* for copy this is the latest message arch'd*/
1242 if (!stralloc_cats(&subject
," Result of: ")) die_nomem();
1243 if (!stralloc_cats(&subject
,action
)) die_nomem();
1244 presub(1,1,&subject
,AC_INDEX
,outformat
);
1246 if (action
[pos
] == '-' || action
[pos
] == '.') pos
++;
1247 if(action
[pos
+= scan_ulong(action
+ pos
,&u
)])
1248 scan_ulong(action
+ pos
+ 1, &to
);
1250 if (u
== 0 && to
== 0) { to
= max
; u
= max
- 100; }
1252 if (u
> max
) u
= max
;
1254 if (to
> u
+ MAXINDEX
) to
= u
+MAXINDEX
; /* max MAXINDEX index files */
1255 if (to
> max
) to
= max
;
1259 if (!stralloc_copys(&fn
,"archive/")) die_nomem();
1260 if (!stralloc_catb(&fn
,strnum
,fmt_ulong(strnum
,u
))) die_nomem();
1261 if (!stralloc_cats(&fn
,"/index")) die_nomem();
1262 if (!stralloc_0(&fn
)) die_nomem();
1264 if (u
== max
/100) /* lock if last index file in archive */
1267 fd
= open_read(fn
.s
);
1269 if (errno
!= error_noent
)
1270 strerr_die4sys(111,FATAL
,ERR_OPEN
,fn
.s
,": ");
1272 code_qput(TXT_NOINDEX
,str_len(TXT_NOINDEX
));
1274 substdio_fdbuf(&sstext
,read
,fd
,textbuf
,sizeof(textbuf
));
1276 if (getln(&sstext
,&line
,&match
,'\n') == -1)
1277 strerr_die4sys(111,FATAL
,ERR_READ
,fn
.s
,": ");
1279 if (line
.s
[0] != '\t') { /* subject line */
1280 pos
= byte_chr(line
.s
,line
.len
,' ');
1281 if (pos
&& pos
!= line
.len
&& line
.s
[pos
- 1] == ':')
1282 pos1
= pos
+ HASHLEN
+ 1; /* after hash */
1283 if (pos1
>= line
.len
) { /* bad! */
1285 pos1
= 0; /* output as is */
1287 if (!stralloc_copyb(&line2
,line
.s
,pos
)) die_nomem();
1288 if (!stralloc_catb(&line2
,line
.s
+pos1
,line
.len
-pos1
)) die_nomem();
1290 pos
= byte_chr(line
.s
,line
.len
,';');
1291 if (pos
+ HASHLEN
+ 1 < line
.len
&& pos
> 15 &&
1292 line
.s
[pos
+ 1] != ' ') {
1293 if (!stralloc_copyb(&line2
,line
.s
,pos
- 15)) die_nomem();
1295 if (!stralloc_catb(&line2
,line
.s
+ pos
+ HASHLEN
,
1296 line
.len
- pos
- HASHLEN
)) die_nomem();
1297 } else /* old format - no author hash */
1298 if (!stralloc_copyb(&line2
,line
.s
,line
.len
)) die_nomem();
1300 code_qput(line2
.s
,line2
.len
);
1307 if (u
== max
/100) /* unlock if last index in archive file */
1312 normal_bottom(outformat
);
1316 else if (act
== AC_THREAD
) {
1318 /* -thread[f][-|.]num returns messages with subject matching message */
1319 /* 'num' in the subject index. If 'num' is not in[1..last_message] an error */
1320 /* message is returned. */
1323 strerr_die2x(100,FATAL
,ERR_NOT_ARCHIVED
);
1325 strerr_die2x(100,FATAL
,ERR_NOT_INDEXED
);
1327 zapnonsub(ACTION_THREAD
); /* restrict to subs if requested*/
1329 get_num(); /* max = last successful message */
1331 strerr_die2x(100,FATAL
,ERR_EMPTY_LIST
);
1332 szmsgnum
[fmt_ulong(szmsgnum
,max
)] = '\0';
1333 set_cpnum(szmsgnum
); /* for copy this is the latest message arch'd*/
1338 if (!stralloc_cats(&subject
," Digest of: ")) die_nomem();
1339 if (!stralloc_cats(&subject
,action
)) die_nomem();
1342 pos
= str_len(ACTION_THREAD
);
1343 if (!case_starts(action
,ACTION_THREAD
))
1344 pos
= str_len(ALT_THREAD
);
1345 if (FORMATS
[str_chr(FORMATS
,action
[pos
])]) {
1346 outformat
= action
[pos
];
1349 if (action
[pos
] == '-' || action
[pos
] == '.') pos
++;
1350 if(action
[pos
+= scan_ulong(action
+ pos
,&u
)])
1351 scan_ulong(action
+ pos
+ 1, &to
);
1353 if(u
== 0 || u
> max
) {
1354 if (!stralloc_cats(&subject
,"\n\n")) die_nomem();
1355 qmail_puts(&qq
,"Subject: ");
1356 qmail_put(&qq
,subject
.s
,subject
.len
);
1357 copy(&qq
,"text/get-bad",flagcd
,FATAL
);
1358 } else { /* limit range to at most u-THREAD_BEFORE to u+THREAD_AFTER */
1359 if (u
> THREAD_BEFORE
)
1360 from
= u
-THREAD_BEFORE
;
1363 if (u
+ THREAD_AFTER
> max
) {
1364 idx_mkthread(&msgtable
,&subtable
,&authtable
,from
,max
,u
,max
,0,FATAL
);
1365 digest(msgtable
,subtable
,authtable
,from
,max
,&subject
,
1366 AC_THREAD
,outformat
);
1368 idx_mkthread(&msgtable
,&subtable
,&authtable
,
1369 from
,u
+THREAD_AFTER
,u
,max
,0,FATAL
);
1370 digest(msgtable
,subtable
,authtable
,from
,u
+THREAD_AFTER
,
1371 &subject
,AC_THREAD
,outformat
);
1377 /* This happens if the initial check at the beginning of 'main' */
1378 /* matches something that isn't matched here. Conversely, just */
1379 /* adding an action here is not enough - it has to be added to the */
1380 /* initial check as well. */
1382 strerr_die2x(100,FATAL
,
1383 "Program error: I'm supposed to deal with this but I didn't");
1385 if (!stralloc_copy(&line
,&outlocal
)) die_nomem();
1386 if (act
== AC_DIGEST
) {
1388 if (!stralloc_cats(&line
,"-return-g-")) die_nomem();
1390 if (!stralloc_cats(&line
,"-return-")) die_nomem();
1391 strnum
[fmt_ulong(strnum
,mno
)] = '\0';
1392 if (!stralloc_cats(&line
,strnum
)) die_nomem();
1393 if (!stralloc_cats(&line
,"-@")) die_nomem();
1395 if (!stralloc_cat(&line
,&outhost
)) die_nomem();
1396 if (!stralloc_cats(&line
,"-@[]")) die_nomem();
1398 if (!stralloc_cats(&line
,"-return-@")) die_nomem();
1399 if (!stralloc_cat(&line
,&outhost
)) die_nomem();
1401 if (!stralloc_0(&line
)) die_nomem();
1403 qmail_from(&qq
,line
.s
);
1404 if (act
== AC_DIGEST
) { /* Do recipients */
1405 tagmsg(workdir
,mno
,seed
.s
,"d",hashout
,qq
.msgbytes
,chunk
,FATAL
);
1407 if (!stralloc_copys(&line
,"T")) die_nomem();
1408 if (!stralloc_cat(&line
,&outlocal
)) die_nomem();
1409 if (!stralloc_cats(&line
,"-s-d-")) die_nomem();
1410 if (!stralloc_catb(&line
,hashout
,COOKIE
)) die_nomem();
1411 if (!stralloc_cats(&line
,"-")) die_nomem();
1412 if (!stralloc_cats(&line
,strnum
)) die_nomem();
1413 if (!stralloc_cats(&line
,"-")) die_nomem();
1414 if (!stralloc_copys(&line2
,"@")) die_nomem();
1415 if (!stralloc_cat(&line2
,&outhost
)) die_nomem();
1416 if (!stralloc_0(&line2
)) die_nomem();
1418 for (i
= 0; i
<= 52; i
+= chunk
) { /* To slaves */
1419 qmail_put(&qq
,line
.s
,line
.len
);
1420 schar
[0] = '0' + i
/ 10;
1421 schar
[1] = '0' + (i
% 10);
1422 qmail_put(&qq
,schar
,3);
1425 schar
[0] = '0' + j
/ 10;
1426 schar
[1] = '0' + (j
% 10);
1427 qmail_put(&qq
,schar
,2);
1428 qmail_put(&qq
,line2
.s
,line2
.len
);
1431 subs
= putsubs(workdir
,0L,52L,&subto
,1,FATAL
);
1432 } else { /* if local is set, sender is checked */
1436 qmail_to(&qq
,sender
);
1439 if (*(err
= qmail_close(&qq
)) == '\0') { /* Done. Skip rest. */
1440 if (act
== AC_DIGEST
) {
1442 (void) logmsg(workdir
,mno
,0L,0L,2);
1444 (void) logmsg(workdir
,mno
,0L,subs
,4);
1446 closesql(); /* close db connection */
1447 unlock(); /* NOP if nothing locked */
1448 strnum
[fmt_ulong(strnum
,qmail_qp(&qq
))] = 0;
1449 strerr_die2x(goodexit
,"ezmlm-get: info: qp ",strnum
);
1450 } else { /* failed. Reset last msg & issue for digest */
1451 if(act
== AC_DIGEST
) {
1453 write_ulong(issue
,0L,0L,"digissue","digissuen");
1454 write_ulong(prevmax
,cumsize
,(unsigned long) digwhen
,"dignum","dignumn");
1456 unlock(); /* NOP if nothing locked */
1457 strerr_die3x(111,FATAL
,ERR_TMP_QMAIL_QUEUE
,err
+ 1);