ezmlmx 0.68
ezmlmx
Loading...
Searching...
No Matches
ezmlm-get.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include "alloc.h"
5#include "error.h"
6#include "stralloc.h"
7#include "str.h"
8#include "env.h"
9#include "sig.h"
10#include "getconf.h"
11#include "byte.h"
12#include "getln.h"
13#include "case.h"
14#include "qmail.h"
15#include "buffer.h"
16#include "readwrite.h"
17#include "seek.h"
18#include "quote.h"
19#include "datetime.h"
20#include "now.h"
21#include "date822fmt.h"
22#include "fmt.h"
23#include "getoptb.h"
24#include "cookie.h"
25#include "makehash.h"
26#include "ezcopy.h"
27#include "constmap.h"
28#include "subscribe.h"
29#include "hdr.h"
30#include "open.h"
31#include "lock.h"
32#include "scan.h"
33#include "idxthread.h"
34#include "idx.h"
35#include "mime.h"
36#include "errtxt.h"
37#include "auto_version.h"
38#include "logmsg.h"
39#include "lockfile.h"
40#include "ezmlm.h"
41
42#define WHO "ezmlm-get"
43
49
50int flagdo = 1; /* React to commands (doesn't affect -dig) */
51int flagbottom = 1; /* copy text/bottom + request */
52int flagpublic = 2; /* 0 = non-public, 1 = public, 2 = respect dir/public. */
53char flagcd = '\0'; /* default: don't use quoted-printable */
54int flagsub = 0; /* =1 subscribers only for get/index/thread */
55const char *digsz =
56 "from\\to\\subject\\reply-to\\date\\message-id\\cc\\"
57 "mime-version\\content-type\\content-transfer-encoding";
58
59static void die_usage() { logmsg(WHO,100,USAGE,"ezmlm-get [-bBcClLpPsSvV] [-f fmt] [digestcode]"); }
60static void die_nomem() { logmsg(WHO,111,FATAL,ERR_NOMEM); }
61
62stralloc outhost = {0};
63stralloc outlocal = {0};
64stralloc charset = {0};
66
67stralloc listname = {0};
68stralloc mailinglist = {0};
69stralloc qmqpservers = {0};
70stralloc fn = {0};
71stralloc moddir = {0};
72stralloc mydtline = {0};
73stralloc digheaders = {0};
74stralloc seed = {0};
75struct constmap digheadersmap;
76
77char schar[] = "00_";
78stralloc listno = {0};
79
81unsigned long cumsize = 0L; /* cumulative msgs / 256 */
82unsigned long cumsizen = 0L; /* new cumulative msgs / 256 */
83unsigned long max = 0L; /* Last message in archive */
84unsigned long msgsize = 0L; /* for digest accounting */
85datetime_sec digwhen; /* last digest */
86
87static char strnum[FMT_ULONG];
88char szmsgnum[FMT_ULONG];
91stralloc line = {0};
92stralloc line2 = {0};
93stralloc qline = {0};
94stralloc quoted = {0};
95stralloc msgnum = {0};
96stralloc num = {0};
97stralloc subject = {0};
98
99/* for copy archive */
100stralloc archdate = {0};
101stralloc archfrom = {0};
102stralloc archto = {0};
103stralloc archcc = {0};
104stralloc archsubject = {0};
105stralloc archmessageid = {0};
106stralloc archkeywords = {0};
107stralloc archblanklines = {0};
108char archtype=' ';
109
110/* for mods on non-public lists (needed for future fuzzy sub dbs) */
111
112stralloc mod = {0}; /* moderator addr for non-public lists */
113const char *pmod = (char *) 0; /* pointer to above */
114
115/* for digest */
116stralloc ddir = {0};
117stralloc edir = {0};
118
119int act = AC_NONE; /* Action we do */
120int flageditor = 0; /* if we're invoked for within dir/editor */
121struct stat st;
122
123int flaglocked = 0; /* if directory is locked */
124int flagarchived; /* if list is archived */
125int flagindexed; /* if list is indexed */
126int flagq = 0; /* don't use 'quoted-printable' */
127
128char *dir;
130char *sender;
132
133struct qmail qq;
134
135ssize_t qqwrite(int fd,char *buf,unsigned int len)
136{
138 return len;
139}
140
141int subto(char *s,unsigned int l)
142{
143 qmail_put(&qq,"T",1);
144 qmail_put(&qq,s,l);
145 qmail_put(&qq,"",1);
146 return (int) l;
147}
148
149char qqbuf[1];
150buffer bq = BUFFER_INIT(qqwrite,-1,qqbuf,sizeof(qqbuf));
151
152char inbuf[1024];
153buffer bi = BUFFER_INIT(read,0,inbuf,sizeof(inbuf));
154buffer bj = BUFFER_INIT(read,0,inbuf,sizeof(inbuf));
155
156buffer bn;
157char numbuf[16];
158
159buffer bt;
160char textbuf[1024];
161
162buffer bx;
163char indexbuf[1024];
164
166
167/* lock unless locked */
168
169void lockup()
170{
171 if (!flaglocked) {
172 fdlock = lockfile("lock");
173 flaglocked = 1;
174 }
175}
176
177/* unlock if locked */
178
179void unlock()
180{
181 if (flaglocked) {
182 close(fdlock);
183 flaglocked = 0;
184 }
185}
186
187void code_qput(char *s,unsigned int n)
188{
189 if (!flagcd)
190 qmail_put(&qq,s,n);
191 else {
192 if (flagcd == 'B')
193 encode_b64(s,n,&qline,0);
194 else
195 encode_qp(s,n,&qline);
196
197 qmail_put(&qq,qline.s,qline.len);
198 msgsize += qline.len;
199 }
200}
201
208
209void zapnonsub( char *szerr)
210{
211 if (sender && *sender) { /* "no sender" is not a subscriber */
212 if (!flagsub)
213 return;
214 if (issub(dir,sender,(char *) 0))
215 return; /* subscriber */
216 if (issub(ddir.s,sender,(char *) 0))
217 return; /* digest subscriber */
218 if (issub(edir.s,sender,(char *) 0))
219 return; /* allow addresses */
220 }
221 logmsg(WHO,100,FATAL,B(ERR_SUBSCRIBER_CAN,szerr,ERR_571));
222}
223
225{
226 qmail_puts(&qq,"To: ");
227 if (!quote2(&quoted,sender)) die_nomem();
228 qmail_put(&qq,quoted.s,quoted.len);
229 qmail_puts(&qq,"\n");
230}
231
237
239{
240 unsigned int pos;
241
242 if (getconf_line(&num,"num",0,dir)) {
243 if(!stralloc_0(&num)) die_nomem();
244 pos = scan_ulong(num.s,&max);
245 if (num.s[pos] == ':') pos++;
246 scan_ulong(num.s+pos,&cumsizen);
247 }
248}
249
250/* return dignum if exists, 0 otherwise. */
251unsigned long dignum()
252{
253 unsigned long retval;
254
255 if (!stralloc_copys(&num,"")) die_nomem(); /* zap */
256 getconf_line(&num,"dignum",0,dir);
257 if(!stralloc_0(&num)) die_nomem();
258 scan_ulong(num.s,&retval);
259 return retval;
260}
261
267
268void write_ulong(unsigned long num,unsigned long cum,unsigned long dat,char *fn,char *fnn)
269{
270 int fd;
271
272 fd = open_trunc(fnn);
273 if (fd == -1)
274 logmsg(WHO,111,FATAL,B(ERR_CREATE,dir,"/",fnn));
275 buffer_init(&bn,buffer_unixwrite,fd,numbuf,sizeof(numbuf));
276 if (buffer_put(&bn,strnum,fmt_ulong(strnum,num)) == -1)
277 logmsg(WHO,111,FATAL,B(ERR_WRITE,dir,"/",fnn));
278 if (buffer_puts(&bn,":") == -1)
279 logmsg(WHO,111,FATAL,B(ERR_WRITE,dir,"/",fnn));
280 if (buffer_put(&bn,strnum,fmt_ulong(strnum,cum)) == -1)
281 logmsg(WHO,111,FATAL,B(ERR_WRITE,dir,"/",fnn));
282 if (dat) {
283 if (buffer_puts(&bn,":") == -1)
284 logmsg(WHO,111,FATAL,B(ERR_WRITE,dir,"/",fnn));
285 if (buffer_put(&bn,strnum,fmt_ulong(strnum,dat)) == -1)
286 logmsg(WHO,111,FATAL,B(ERR_WRITE,dir,"/",fnn));
287 }
288 if (buffer_puts(&bn,"\n") == -1)
289 logmsg(WHO,111,FATAL,B(ERR_WRITE,dir,"/",fnn));
290 if (buffer_flush(&bn) == -1)
291 logmsg(WHO,111,FATAL,B(ERR_FLUSH,dir,"/",fnn));
292 if (fsync(fd) == -1)
293 logmsg(WHO,111,FATAL,B(ERR_SYNC,dir,"/",fnn));
294 if (close(fd) == -1)
295 logmsg(WHO,111,FATAL,B(ERR_CLOSE,dir,"/",fnn));
296 if (rename(fnn,fn) == -1)
297 logmsg(WHO,111,FATAL,B(ERR_MOVE,fnn));
298}
299
300/* Copies bottom text and the original message to the new message */
301
302void normal_bottom(char format)
303{
304 if (flagbottom) {
305 ezcopy(&qq,"text/bottom",flagcd);
306 if (flagcd && format != RFC1153) {
307 if (flagcd == 'B') {
308 encode_b64("",0,&line,2); /* flush */
309 qmail_put(&qq,line.s,line.len);
310 }
311 hdr_boundary(0);
313 hdr_adds("Content-Disposition: inline; filename=request.msg");
314 qmail_puts(&qq,"\n");
315 }
316 qmail_puts(&qq,"Return-Path: <");
317 if (!quote2(&quoted,sender)) die_nomem();
318 qmail_put(&qq,quoted.s,quoted.len);
319 qmail_puts(&qq,">\n");
320 if (seek_begin(0) == -1)
321 logmsg(WHO,111,FATAL,ERR_SEEK_INPUT);
322 if (buffer_copy(&bq,&bj) != 0)
323 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
324 } else {
325 if (flagcd == 'B' && format != RFC1153) {
326 encode_b64("",0,&line,2); /* flush */
327 qmail_put(&qq,line.s,line.len);
328 }
329 }
330}
331
339
340void presub(unsigned long from,unsigned long to,stralloc *subject,int factype,char format)
341{
342 switch(format) {
343 case MIME:
344 case VIRGIN:
345 case NATIVE:
346 case MIXED: hdr_mime((format == MIXED) ? CTYPE_MULTIPART : CTYPE_DIGEST);
347 hdr_add2("Subject: ",subject->s,subject->len);
348 hdr_boundary(0);
350 hdr_transferenc(); /* content-transfer-enc header if needed */
351 break;
353 hdr_add2("Subject: ",subject->s,subject->len);
354 qmail_puts(&qq,"\n");
355 flagcd = '\0'; /* We make 8-bit messages, not QP/base64 for rfc1153 */
356 break; /* Since messages themselves aren't encoded */
357 }
358
359 if (!stralloc_cats(subject,"\n\n")) die_nomem();
360 code_qput(subject->s,subject->len);
361 if (format != NATIVE && factype != AC_THREAD && factype != AC_INDEX) {
362 if (!stralloc_copys(&line,TXT_TOP_TOPICS)) die_nomem();
363 if (!stralloc_cats(&line,TXT_TOP_MESSAGES)) die_nomem();
364 if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,from))) die_nomem();
365 if (!stralloc_cats(&line,TXT_TOP_THROUGH)) die_nomem();
366 if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,to))) die_nomem();
367 if (!stralloc_cats(&line,TXT_TOP_LAST)) die_nomem();
368 code_qput(line.s,line.len);
369 }
370}
371
378
379void postsub(int factype,char format)
380{
382 if (factype == AC_DIGEST) {
383 ezcopy(&qq,"text/digest",flagcd);
384 if (flagcd == 'B') {
385 encode_b64("",0,&line,2); /* flush */
386 qmail_put(&qq,line.s,line.len);
387 }
388 } else
389 normal_bottom(format);
390 if (!flagcd || format == RFC1153)
391 qmail_puts(&qq,"\n----------------------------------------------------------------------\n");
392 else
393 qmail_puts(&qq,"\n");
394}
395
396void postmsg(char format)
397{
398 switch(format) {
399 case MIME:
400 case VIRGIN:
401 case NATIVE: case MIXED:
402 hdr_boundary(1);
403 break;
404 case RFC1153: qmail_puts(&qq,"End of ");
406 qmail_puts(&qq," Digest");
407 qmail_puts(&qq,"\n***********************************\n");
408 break;
409 }
410}
411
416
417void copymsg(unsigned long msg,int fd,char format)
418{
419 int match;
420 int flaginheader;
421 int flagskipblanks;
422 int flaggoodfield;
423
424 switch(format) {
425 case VIRGIN:
426 case NATIVE: buffer_init(&bt,buffer_unixread,fd,textbuf,sizeof(textbuf));
427 for (;;) {
428 if (getln(&bt,&line,&match,'\n') == -1)
429 logmsg(WHO,111,FATAL,B(ERR_READ,line.s));
430 if (match) {
431 qmail_put(&qq,line.s,line.len);
432 msgsize += line.len;
433 } else
434 break;
435 }
436 break;
437 case MIME:
438 case MIXED: flaginheader = 1; flaggoodfield = 0;
439 buffer_init(&bt,buffer_unixread,fd,textbuf,sizeof(textbuf));
440 for (;;) {
441 if (getln(&bt,&line,&match,'\n') == -1)
442 logmsg(WHO,111,FATAL,B(ERR_READ,line.s));
443 if (match) {
444 if (flaginheader) {
445 if (line.len == 1) {
446 flaginheader = 0;
447 flaggoodfield = 1;
448 } else if (line.s[0] != ' ' && line.s[0] != '\t') {
449 flaggoodfield = 0;
450 if (constmap(&digheadersmap,line.s,byte_chr(line.s,line.len,':')))
451 flaggoodfield = 1;
452 }
453 if (flaggoodfield) {
454 qmail_put(&qq,line.s,line.len); /* header */
455 msgsize += line.len;
456 }
457 } else {
458 qmail_put(&qq,line.s,line.len); /* body */
459 msgsize += line.len;
460 }
461 } else
462 break;
463 }
464 break;
465 case RFC1153: flaginheader = 1; /* Not worth optimizing. Rarely used */
466 flagskipblanks = 1; /* must skip terminal blanks acc to rfc1153 */
467 archtype = ' '; /* rfc1153 requires ordered headers */
468 if (!stralloc_copys(&archblanklines,"")) die_nomem();
469 buffer_init(&bt,buffer_unixread,fd,textbuf,sizeof(textbuf));
470 for (;;) {
471 if (getln(&bt,&line,&match,'\n') == -1)
472 logmsg(WHO,111,FATAL,B(ERR_READ,line.s));
473 if (match) {
474 if (flaginheader) {
475 if (line.len == 1) {
476 flaginheader = 0;
477 if (archdate.len) {
479 archdate.len = 0;
480 msgsize += archdate.len;
481 }
482 if (archto.len) {
483 qmail_put(&qq,archto.s,archto.len);
484 msgsize += archto.len;
485 archto.len = 0;
486 }
487 if (archfrom.len) {
489 msgsize += archfrom.len;
490 archfrom.len = 0;
491 }
492 if (archcc.len) {
493 qmail_put(&qq,archcc.s,archcc.len);
494 msgsize += archcc.len;
495 archcc.len = 0;
496 }
497 if (archsubject.len) {
499 msgsize += archsubject.len;
500 archsubject.len = 0;
501 }
502 if (archmessageid.len) {
504 msgsize += archmessageid.len;
505 archmessageid.len = 0;
506 }
507 if (archkeywords.len) {
509 msgsize += archkeywords.len;
510 archkeywords.len = 0;
511 }
512 qmail_puts(&qq,"\n");
513 } else if (line.s[0] == ' ' || line.s[0] == '\t') {
514 switch (archtype) { /* continuation lines */
515 case ' ': break;
516 case 'D': if (!stralloc_cat(&archdate,&line)) die_nomem(); break;
517 case 'F': if (!stralloc_cat(&archfrom,&line)) die_nomem(); break;
518 case 'T': if (!stralloc_cat(&archto,&line)) die_nomem(); break;
519 case 'C': if (!stralloc_cat(&archcc,&line)) die_nomem(); break;
520 case 'S': if (!stralloc_cat(&archsubject,&line)) die_nomem(); break;
521 case 'M': if (!stralloc_cat(&archmessageid,&line)) die_nomem(); break;
522 case 'K': if (!stralloc_cat(&archkeywords,&line)) die_nomem(); break;
523 default: logmsg(WHO,111,FATAL,"Program error: Bad archive header type");
524 }
525 } else {
526 archtype = ' ';
527 if (case_startb(line.s,line.len,"cc:")) {
528 archtype = 'C';
529 if (!stralloc_copy(&archcc,&line)) die_nomem();
530 } else if (case_startb(line.s,line.len,"date:")) {
531 archtype = 'D';
532 if (!stralloc_copy(&archdate,&line)) die_nomem();
533 } else if (case_startb(line.s,line.len,"from:")) {
534 archtype = 'F';
535 if (!stralloc_copy(&archfrom,&line)) die_nomem();
536 } else if (case_startb(line.s,line.len,"keywords:")) {
537 archtype = 'K';
538 if (!stralloc_copy(&archkeywords,&line)) die_nomem();
539 } else if (case_startb(line.s,line.len,"message-id:")) {
540 archtype = 'M';
541 if (!stralloc_copy(&archmessageid,&line)) die_nomem();
542 } else if (case_startb(line.s,line.len,"subject:")) {
543 archtype = 'S';
544 if (!stralloc_copy(&archsubject,&line)) die_nomem();
545 } else if (case_startb(line.s,line.len,"to:")) {
546 archtype = 'T';
547 if (!stralloc_copy(&archto,&line)) die_nomem();
548 }
549 }
550 } else if (line.len == 1) {
551 if (!flagskipblanks)
552 if (!stralloc_copys(&archblanklines,"\n")) die_nomem();
553 } else {
554 if (archblanklines.len) {
556 archblanklines.len = 0;
557 }
558 flagskipblanks = 0;
559 qmail_put(&qq,line.s,line.len);
560 msgsize += line.len;
561 }
562 } else // no match
563 break;
564 } // end for loop
565 break;
566 default: logmsg(WHO,100,FATAL,"Program error: bad format in copymsg()");
567 }
568}
569
574
575void mime_getbad(unsigned long msg)
576{
577 hdr_boundary(0);
579 qmail_puts(&qq,"Content-Disposition: inline; filename=\"");
581 qmail_puts(&qq,"_");
582 qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
583 qmail_puts(&qq,".ezm\"\n");
585 ezcopy(&qq,"text/get-bad",flagcd);
586}
587
592
593void msgout(unsigned long msg,char format)
594{
595 int fd;
596 unsigned int len;
597
598 if (!stralloc_copys(&fn,"archive/")) die_nomem();
599
600 len = fmt_ulong(strnum, msg / 100);
601 if (!stralloc_catb(&fn,strnum,len)) die_nomem();
602 if (!stralloc_cats(&fn,"/")) die_nomem();
603 len = fmt_uint0(strnum, (unsigned int) (msg % 100),2);
604 if (!stralloc_catb(&fn,strnum,len)) die_nomem();
605 if (!stralloc_0(&fn)) die_nomem();
606
607 switch (format) {
608 case MIME:
609 case VIRGIN:
610 case NATIVE:
611 case MIXED: fd = open_read(fn.s);
612 if (fd == -1) {
613 if (errno != ENOENT)
614 logmsg(WHO,111,FATAL,B(ERR_OPEN,fn.s));
615 else
616 mime_getbad(msg);
617 } else if (fstat(fd,&st) == -1 || (!(st.st_mode & 0100))) {
618 close(fd);
619 mime_getbad(msg);
620 } else {
621 hdr_boundary(0);
623 qmail_puts(&qq,"Content-Disposition: inline; filename=\"");
625 qmail_puts(&qq,"_");
626 qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
627 qmail_puts(&qq,".ezm\"\n\n");
628 copymsg(msg,fd,format);
629 close(fd);
630 }
631 break;
632 case RFC1153: fd = open_read(fn.s);
633 if (fd == -1) {
634 if (errno != ENOENT)
635 logmsg(WHO,111,FATAL,B(ERR_OPEN,fn.s));
636 else {
637 qmail_puts(&qq,"\n== ");
638 qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
639 qmail_puts(&qq," ==\n\n");
640 ezcopy(&qq,"text/get-bad",flagcd);
641 }
642 } else {
643 if (fstat(fd,&st) == -1 || (!(st.st_mode & 0100))) {
644 close(fd);
645 qmail_puts(&qq,"\n== ");
646 qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
647 qmail_puts(&qq," ==\n\n");
648 ezcopy(&qq,"text/get-bad",flagcd);
649 } else {
650 copymsg(msg,fd,format);
651 close(fd);
652 }
653 }
654 qmail_puts(&qq,"\n------------------------------\n\n");
655 break;
656 default: logmsg(WHO,100,FATAL,"Program error: Unrecognized format in msgout"); break;
657 }
658}
659
665
666void digest(msgentry *msgtable,subentry *subtable,authentry *authtable,
667 unsigned long from,unsigned long to,stralloc *subj,int factype,char format)
668{
669 msgentry *pmsgt;
670 subentry *psubt;
671 const char *cp;
672 int ffirstmsg;
673 unsigned int len;
674 unsigned long msg;
675 unsigned long subnum;
676
677 psubt = subtable;
678 presub(from,to,subj,factype,format);
679
680 if (format != NATIVE) {
681 while (psubt->sub) {
682 ffirstmsg = 1;
683 pmsgt = msgtable + psubt->firstmsg - from; /* ptr to first message with this subject */
684 subnum = (unsigned long) (psubt - subtable +1);
685 for (msg=psubt->firstmsg; msg<=to; msg++) {
686 if (pmsgt->subnum == subnum) {
687 if(ffirstmsg) {
688 ffirstmsg = 0;
689 if (!stralloc_copys(&line,"\n")) die_nomem();
690 if (psubt->sublen <= HASHLEN + 2) {
691 if (!stralloc_cats(&line,"(null)\n")) die_nomem();
692 } else
693 if (!stralloc_catb(&line,psubt->sub + HASHLEN + 1,psubt->sublen - HASHLEN - 1)) die_nomem();
694 } else
695 if (!stralloc_copys(&line,"")) die_nomem();
696 if (!stralloc_cats(&line,"\t")) die_nomem();
697 if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msg))) die_nomem();
698 if (!stralloc_cats(&line,TXT_BY)) die_nomem();
699 if (pmsgt->authnum) {
700 cp = authtable[pmsgt->authnum - 1].auth;
701 len = authtable[pmsgt->authnum - 1].authlen;
702 if (len > HASHLEN) {
703 if (!stralloc_catb(&line,cp + HASHLEN + 1,len - HASHLEN - 1)) die_nomem();
704 } else
705 if (!stralloc_catb(&line,cp,len)) die_nomem();
706 } else
707 if (!stralloc_cats(&line,"\n")) die_nomem();
708 code_qput(line.s,line.len);
709 }
710 pmsgt++;
711 }
712 psubt++;
713 }
714 }
715 postsub(factype,format);
716
717 psubt = subtable;
718 while (psubt->sub) {
719 pmsgt = msgtable + psubt->firstmsg - from;
720 subnum = (unsigned long) (psubt - subtable +1);
721 for (msg=psubt->firstmsg; msg<=to; msg++) {
722 if (pmsgt->subnum == subnum)
723 msgout(msg,format);
724 pmsgt++;
725 }
726 psubt++;
727 }
728 postmsg(format);
729 idx_destroythread(msgtable,subtable,authtable);
730}
731
733{
734 int flaggoodfield,match;
735
736 if (act == AC_DIGEST)
737 ezcopy(&qq,"headeradd",'H');
738
739 hdr_add2("Mailing-List: ",mailinglist.s,mailinglist.len);
740 if (getconf_line(&line,"listid",0,dir))
741 hdr_add2("List-ID: ",line.s,line.len);
743 hdr_from("-help");
744 if (!stralloc_copys(&mydtline,"Delivered-To: responder for ")) die_nomem();
745 if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
746 if (!stralloc_cats(&mydtline,"@")) die_nomem();
747 if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
748 if (!stralloc_cats(&mydtline,"\n")) die_nomem();
749
751
752 flaggoodfield = 0;
753 if (act != AC_DIGEST)
754 for (;;) {
755 if (getln(&bi,&line,&match,'\n') == -1)
756 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
757 if (!match) break;
758 if (line.len == 1) break;
759 if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
760 flaggoodfield = 0;
761 if (case_startb(line.s,line.len,"mailing-list:"))
762 if (flageditor) /* we may be running from a sublist */
763 flaggoodfield = 0;
764 else
765 logmsg(WHO,100,FATAL,ERR_MAILING_LIST);
766 if (line.len == mydtline.len)
767 if (byte_equal(line.s,line.len,mydtline.s))
768 logmsg(WHO,100,FATAL,ERR_LOOPING);
769 if (case_startb(line.s,line.len,"delivered-to:"))
770 flaggoodfield = 1;
771 if (case_startb(line.s,line.len,"received:"))
772 flaggoodfield = 1;
773 }
774 if (flaggoodfield)
775 qmail_put(&qq,line.s,line.len);
776 }
777}
778
779
780int main(int argc,char **argv)
781{
782 char *def;
783 char *local;
784 const char *action = "";
785 char *psz;
786 const char *err;
787 int fd;
788 unsigned int i,j;
789 int flagremote;
790 int flagqmqp = 0;
791 int match;
792 int goodexit = 0; /* exit code for normal exit in manager this will be set to 0 */
793 unsigned long from, u, to, issue, prevmax, mno;
794 unsigned long chunk;
795 unsigned long subs;
796 unsigned int pos,pos1;
797 unsigned int len;
798 int opt;
799 char outformat = DEFAULT_FORMAT; /* default output format */
800 msgentry *msgtable;
801 subentry *subtable;
802 authentry *authtable;
803 dateentry *datetable;
804 struct datetime dt;
805 char date[DATE822FMT];
806
807 umask(022);
808 sig_pipeignore();
809 when = now();
811
812 while ((opt = getoptb(argc,argv,"bBcCf:pPsSt:vV")) != opteof)
813 switch (opt) {
814 case 'b': flagbottom = 1; break; /* add text/bottom (default) */
815 case 'B': flagbottom = 0; break; /* suppress text/bottom */
816 case 'c': flagdo = 1; break; /* do commands */
817 case 'C': flagdo = 0; break; /* ignore commands X dig */
818 case 'f': if (FORMATS[str_chr(FORMATS,optarg[0])])
819 outformat = optarg[0];
820 break;
821 case 'p': flagpublic = 1; break; /* always public */
822 case 'P': flagpublic = 0; break; /* never public = only mods do cmd; def = 2: respect DIR/public */
823 case 's': flagsub = 1; break; /* only subs have archive access */
824 case 'S': flagsub = 0; break; /* everyone has archive access */
825 case 'v':
826 case 'V': logmsg(WHO,0,VERSION,auto_version);
827 default: die_usage();
828 }
829
830 dir = argv[optind++];
831 if (!dir) die_usage();
832 if (chdir(dir) == -1)
833 logmsg(WHO,111,FATAL,B(ERR_SWITCH,dir));
834
835 digestcode = argv[optind]; /* code to activate digest (-digest-code); ignore any extra args */
836
837 getconf_line(&outlocal,"outlocal",1,dir);
838 if (!stralloc_copy(&subject,&outlocal)) die_nomem(); /* for subjects */
839 if (!stralloc_copy(&listname,&outlocal)) die_nomem(); /* for content disp */
840
841 local = env_get("LOCAL");
842 def = env_get("DEFAULT");
843 sender = env_get("SENDER");
844
845 if (local && *local) { /* in editor local = outlocal */
846 if (!sender) logmsg(WHO,100,FATAL,ERR_NOSENDER);
847 if (!*sender)
848 logmsg(WHO,100,FATAL,ERR_BOUNCE);
849 if (str_equal(sender,"#@[]"))
850 logmsg(WHO,100,FATAL,ERR_BOUNCE);
851 if (!sender[str_chr(sender,'@')])
852 logmsg(WHO,100,FATAL,ERR_ANONYMOUS);
853 if (def) {
854 if (*def) {
855 action = def;
856 goodexit = 99;
857 } else
858 _exit(0); /* list-@host should do -help from manager */
859 } else { /* editor */
860 act = AC_DIGEST; /* on list-@host ! */
861 flageditor = 1; /* to avoid Mailing-list error on sublists when running out of dir/editor. */
862 }
863
864 if (case_starts(action,"dig")) {
865 action += 3;
866 if (action[0] == '-' || action [0] == '.') {
867 action++;
868 if (!digestcode)
869 logmsg(WHO,100,FATAL,ERR_BAD_DIGCODE);
870 len = str_len(digestcode);
871 if (len <= str_len(action) && case_startb(action,len,digestcode)) {
872 if (FORMATS[str_chr(FORMATS,*(action+len))])
873 outformat = *(action+len);
874 act = AC_DIGEST;
875 } else
876 logmsg(WHO,100,FATAL,ERR_BAD_DIGCODE);
877 }
878 }
879 } else /* no local; Command line operation */
880 act = AC_DIGEST;
881
882 /* Things we deal with. If anything else just die with success! */
883 /* At the moment this is -index, -thread, and -get. */
884 /* If flagdo = 0 we only service -dig commands. This is to support*/
885 /* "secret" lists that are still archived and digested. -c on */
886 /* cmd line. */
887
888 if (act == AC_NONE) {
889 if (case_equals(action,ACTION_DIGEST)) {
890 act = AC_GET; /* list-digest@ => msg since last digest */
892 } else if (case_starts(action,ACTION_GET) || case_starts(action,ALT_GET))
893 act = AC_GET;
894 else if (case_starts(action,ACTION_INDEX) || case_starts(action,ALT_INDEX))
895 act = AC_INDEX;
896 else if (case_starts(action,ACTION_THREAD) || case_starts(action,ALT_THREAD))
897 act = AC_THREAD;
898 }
899 if (act == AC_NONE) /* not for us. Pass the buck. */
900 _exit(0);
901 if (act != AC_INDEX) { /* need to do header processing */
902 if(!getconf(&digheaders,"digheaders",0,dir)) {
903 if(!stralloc_copys(&digheaders,digsz)) die_nomem();
904 if (!stralloc_0(&digheaders)) die_nomem();
905 psz = digheaders.s;
906 while (*psz) {
907 if (*psz == '\\') *psz = '\0';
908 ++psz;
909 }
910 }
911 if (!constmap_init(&digheadersmap,digheaders.s,digheaders.len,0))
912 die_nomem();
913 }
914 if (act != AC_DIGEST) {
915 if (!flagdo) /* only do digests */
916 logmsg(WHO,100,FATAL,ERR_NOCMD);
917 if (flagpublic == 2)
918 flagpublic = getconf_line(&line,"public",0,dir);
919 if (!flagpublic) {
920 /* This all to take care of non-public lists. They should*/
921 /* still do digests, but do other things only for */
922 /* moderators that have remote access. Since this is rare*/
923 /* efforts have been made to keep everything that's not */
924 /* needed elsewhere in here. */
925 getconf_line(&moddir,"modsub",0,dir);
926 flagremote = getconf_line(&line,"remote",0,dir);
927 if (!flagremote)
928 logmsg(WHO,100,FATAL,ERR_NOT_PUBLIC);
929 if (!moddir.len || moddir.s[0] != '/') {
930 if (line.len && line.s[0] == '/') {
931 if (!stralloc_copy(&moddir,&line)) die_nomem();
932 } else {
933 if (!stralloc_copys(&moddir,dir)) die_nomem();
934 if (!stralloc_cats(&moddir,"/mod")) die_nomem();
935 }
936 }
937 if (!stralloc_0(&moddir)) die_nomem();
938 pmod = issub(moddir.s,sender,(char *) 0);
939 if (!pmod) /* sender = moderator? */
940 logmsg(WHO,100,FATAL,ERR_NOT_PUBLIC);
941 else {
942 if (!stralloc_copys(&mod,pmod)) die_nomem();
943 if (!stralloc_0(&mod)) die_nomem();
944 pmod = mod.s; /* send to address in list not matching bait */
945 }
946 }
947 }
948
949 flagindexed = getconf_line(&line,"indexed",0,dir);
950 flagarchived = getconf_line(&line,"archived",0,dir);
951
952 if (getconf_line(&charset,"charset",0,dir)) {
953 if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
954 if (charset.s[charset.len - 1] == 'B' ||
955 charset.s[charset.len - 1] == 'Q') {
956 flagcd = charset.s[charset.len - 1];
957 charset.s[charset.len - 2] = '\0';
958 }
959 }
960 } else
961 if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
962
963 if (!stralloc_0(&charset)) die_nomem();
964 getconf_line(&mailinglist,"mailinglist",1,dir);
965 getconf_line(&outhost,"outhost",1,dir);
966 set_cpouthost(&outhost);
967
968 if (!stralloc_copys(&ddir,dir)) die_nomem();
969 if (!stralloc_cats(&ddir,"/digest")) die_nomem();
970 if (!stralloc_0(&ddir)) die_nomem();
971
972 if (act == AC_DIGEST) {
973 workdir = ddir.s;
974 if (!stralloc_cats(&outlocal,"-digest")) die_nomem();
975 if (getconf_line(&line,"chunk",0,dir)) {
976 if (!stralloc_0(&line)) die_nomem();
977 scan_ulong(line.s,&chunk); /* same chunk as main list */
978 if (chunk == 0) /* limit range to 1-53 */
979 chunk = 1L;
980 else if (chunk > 52)
981 chunk = 52L;
982 } else {
983 chunk = 0L; /* maybe direct qmqp? */
984 if (!stralloc_copys(&line,QMQPSERVERS)) die_nomem();
985 if (!stralloc_cats(&line,"/0")) die_nomem();
986 if (!stralloc_0(&line)) die_nomem();
987 flagqmqp = getconf(&qmqpservers,line.s,0,dir);
988 }
989 } else
990 workdir = dir;
991
992 if (!stralloc_copys(&edir,dir)) die_nomem(); /* not needed for -dig, but */
993 if (!stralloc_cats(&edir,"/allow")) die_nomem(); /* be safe */
994 if (!stralloc_0(&edir)) die_nomem();
995 set_cpoutlocal(&outlocal); /* needed for copy */
996
997 if (flagqmqp) {
998 if (qmail_open(&qq,&qmqpservers) == -1) /* open qmail */
999 logmsg(WHO,111,FATAL,ERR_QMAIL_QUEUE);
1000 } else if (qmail_open(&qq,(stralloc *) 0) == -1) /* open qmail */
1001 logmsg(WHO,111,FATAL,ERR_QMAIL_QUEUE);
1002
1003 set_cpnum(""); /* default for <#n#> replacement */
1004
1005/* -dig{.|-}'digestcode'[f] returns an rfc1153 digest */
1006/* of messages from the archive. Messages */
1007/* dignum+1 through the last message received by the list are processed and */
1008/* dignum is updated to the last message processed. digissue is advanced. */
1009
1010 if (act == AC_DIGEST) {
1011 if (!flagarchived)
1012 logmsg(WHO,100,FATAL,ERR_NOT_ARCHIVED);
1013
1014 get_num(); /* max = last successful message */
1015 to = max;
1016 lockup(); /* another digest could corrupt dignum */
1017 /* but will be saved only if flagdigrange==0 */
1018 if (getconf_line(&num,"dignum",0,dir)) {
1019 if(!stralloc_0(&num)) die_nomem();
1020 pos = scan_ulong(num.s,&prevmax);
1021 if (num.s[pos] == ':') pos++;
1022 pos += 1 + scan_ulong(num.s+pos,&cumsize); /* last cumsize */
1023 if (num.s[pos] == ':') pos++;
1024 scan_ulong(num.s+pos,&digwhen); /* last reg dig */
1025 } else {
1026 prevmax = 0L;
1027 cumsize = 0L;
1028 digwhen = 0L;
1029 }
1030 mno = prevmax + 1L;
1031 if(!max || mno > max) /* if a digest-list is "sending" the request, */
1032 /* don't make noise: errors go to postmaster!*/
1033 logmsg(WHO,goodexit,ERROR,ERR_EMPTY_DIGEST);
1034 szmsgnum[fmt_ulong(szmsgnum,mno)] = '\0';
1035 set_cpnum(szmsgnum); /* for copy prepare subject to get entropy for tagmsg*/
1036 if (!stralloc_cats(&subject," Digest ")) die_nomem();
1037 if (!stralloc_catb(&subject,date,date822fmt(date,&dt)-1))
1038 die_nomem(); /* skip trailing in date '\n' */
1039
1040 if (!stralloc_cats(&subject," Issue ")) die_nomem();
1041 if (getconf_line(&num,"digissue",0,dir)) {
1042 if (!stralloc_0(&num)) die_nomem();
1043 scan_ulong(num.s,&issue);
1044 issue++;
1045 } else {
1046 issue = 1;
1047 }
1048 if (!stralloc_catb(&subject,strnum,fmt_ulong(strnum,issue))) die_nomem();
1049 if (!stralloc_copy(&line,&subject)) die_nomem(); /* use the subject as entropy */
1050 if (!stralloc_0(&line)) die_nomem();
1051
1052 if (!stralloc_ready(&seed,HASHLEN+1)) die_nomem();
1053 seed.len = HASHLEN + 1;
1054 seed.s[HASHLEN] = '\0';
1055 makehash(line.s,line.len,seed.s);
1056 if (chunk) { /* only if slaves are used */
1057 qmail_puts(&qq,"Ezauth: ");
1059 qmail_puts(&qq,"\n");
1060 }
1061
1062 doheaders();
1063 qmail_puts(&qq,"To: ");
1064 if (!quote(&quoted,&listname)) die_nomem();
1065 qmail_put(&qq,quoted.s,quoted.len);
1066 qmail_puts(&qq,"@");
1067 qmail_put(&qq,outhost.s,outhost.len);
1068 qmail_puts(&qq,"\n");
1069 if (flagindexed && (outformat != NATIVE))
1070 idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,mno,to,max,flaglocked);
1071 else
1072 idx_mklist(&msgtable,&subtable,&authtable,mno,to);
1073 digest(msgtable,subtable,authtable,mno,to,&subject,AC_DIGEST,outformat);
1074
1075 write_ulong(issue,0L,0L,"digissue","digissuen");
1076 write_ulong(max,cumsizen, (unsigned long) when,"dignum","dignumn");
1077 }
1078
1079/* -get[-|\.][[num].num2] copies archive num-num2. num & num2 are adjusted */
1080/* to be > 0 and <= last message, to num2 >= num and to num2-num <= MAXGET. */
1081
1082 else if (act == AC_GET) {
1083 if (!flagarchived)
1084 logmsg(WHO,100,FATAL,ERR_NOT_ARCHIVED);
1085 zapnonsub(ACTION_GET); /* restrict to subs if requested */
1086 tosender(); /* for rfc1153 */
1087 if (!stralloc_cats(&subject," Digest of: ")) die_nomem();
1088 if (!stralloc_cats(&subject,action)) die_nomem();
1089
1090 to = 0;
1091 pos = str_len(ACTION_GET);
1092 if (!case_starts(action,ACTION_GET))
1093 pos = str_len(ALT_GET);
1094 if (FORMATS[str_chr(FORMATS,action[pos])]) {
1095 outformat = action[pos];
1096 ++pos;
1097 }
1098 /* optional - or . after '-get' */
1099 if (action[pos] == '-' || action[pos] == '.') pos++;
1100 get_num(); /* max = last successful message */
1101 /* accept any separator. It may be */
1102 /* the terminal '\n', but then */
1103 /* scan will = 0 on the \0 so should*/
1104 /* be safe */
1105 if (!max)
1106 logmsg(WHO,100,FATAL,ERR_EMPTY_LIST);
1107 szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
1108 set_cpnum(szmsgnum); /* for copy this is the latest message arch'd*/
1109 doheaders();
1110 if(action[pos += scan_ulong(action + pos,&u)])
1111 scan_ulong(action + pos + 1, &to);
1112 if (u == 0 && to == 0) { /* default: messages since last */
1113 /* digest, or last MAXGET if too many */
1114 to= max;
1115 u = dignum();
1116 if (u == 0) { /* no digest => last up to HISTGET msgs */
1117 to = max;
1118 if (max > HISTGET) u = max - HISTGET; else u = 1;
1119 }
1120 if (to - u >= MAXGET) u = to - MAXGET + 1; /* max MAXGET */
1121 } else if (u > max) {
1122 if (to) { /* -get.999999_x returns 30 and msg since last*/
1123 to = max; /* digest 30*/
1124 u = dignum();
1125 if (u > HISTGET) u -= HISTGET; else u = 1;
1126 if (to - u >= MAXGET) u = to - MAXGET + 1;
1127 } else
1128 u = max;
1129 }
1130 if (u == 0) u = 1; /* -get.5 => 1-5 */
1131 if (to < u) to = u; /* -get23_2 => 23 */
1132 if (to >= u + MAXGET) to = u + MAXGET - 1;
1133 if (to > max) to = max; /* no more than MAXGET at a time */
1134 if (flagindexed && (outformat != NATIVE)) /* fake out threading */
1135 idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,u,to,max,0);
1136 else
1137 idx_mklist(&msgtable,&subtable,&authtable,u,to);
1138 digest(msgtable,subtable,authtable,u,to,&subject,AC_GET,outformat);
1139 }
1140
1141/* -index[f][#|-|\.][[num][.num2] Show subject index for messages num-num2 in*/
1142/* sets of 100. */
1143/* Default last 2 sets. num and num2 are made reasonable as for get. num2 is */
1144/* limited to num+MAXINDEX to limit the amount of data sent. */
1145
1146 else if (act == AC_INDEX) {
1147 if (!flagindexed)
1148 logmsg(WHO,100,FATAL,ERR_NOT_INDEXED);
1149 if (flagsub)
1150 zapnonsub(ACTION_INDEX); /* restrict to subs if requested */
1151 to = 0;
1152 pos = str_len(ACTION_INDEX);
1153 if (!case_starts(action,ACTION_INDEX))
1154 pos = str_len(ALT_INDEX);
1155 if (FORMATS[str_chr(FORMATS,action[pos])]) {
1156 outformat = action[pos]; /* ignored, but be nice ... */
1157 ++pos;
1158 }
1159 get_num(); /* max = last successful message */
1160 if (!max)
1161 logmsg(WHO,100,FATAL,ERR_EMPTY_LIST);
1162 szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
1163 set_cpnum(szmsgnum); /* for copy this is the latest message arch'd*/
1164
1165 doheaders();
1166 tosender();
1167 if (!stralloc_cats(&subject," Result of: ")) die_nomem();
1168 if (!stralloc_cats(&subject,action)) die_nomem();
1169 presub(1,1,&subject,AC_INDEX,outformat);
1170
1171 if (action[pos] == '-' || action[pos] == '.') pos++;
1172 if(action[pos += scan_ulong(action + pos,&u)])
1173 scan_ulong(action + pos + 1, &to);
1174
1175 if (u == 0 && to == 0) { to = max; u = max - 100; }
1176 if (u <= 0) u = 1;
1177 if (u > max) u = max;
1178 if (to < u) to = u;
1179 if (to > u + MAXINDEX) to = u+MAXINDEX; /* max MAXINDEX index files */
1180 if (to > max) to = max;
1181 u /= 100;
1182 to /= 100;
1183 while (u <= to) {
1184 if (!stralloc_copys(&fn,"archive/")) die_nomem();
1185 if (!stralloc_catb(&fn,strnum,fmt_ulong(strnum,u))) die_nomem();
1186 if (!stralloc_cats(&fn,"/index")) die_nomem();
1187 if (!stralloc_0(&fn)) die_nomem();
1188
1189 if (u == max/100) /* lock if last index file in archive */
1190 lockup();
1191
1192 fd = open_read(fn.s);
1193 if (fd == -1)
1194 if (errno != ENOENT)
1195 logmsg(WHO,111,FATAL,B(ERR_OPEN,fn.s));
1196 else
1198 else {
1199 buffer_init(&bt,buffer_unixread,fd,textbuf,sizeof(textbuf));
1200
1201 for (;;) {
1202 if (getln(&bt,&line,&match,'\n') == -1)
1203 logmsg(WHO,111,FATAL,B(ERR_READ,fn.s));
1204 if (match) {
1205 if (line.s[0] != '\t') { /* subject line */
1206 pos = byte_chr(line.s,line.len,' ');
1207 if (pos && pos != line.len && line.s[pos - 1] == ':')
1208 pos1 = pos + HASHLEN + 1; /* after hash */
1209 if (pos1 >= line.len) { /* bad! */
1210 pos = 0;
1211 pos1 = 0; /* output as is */
1212 }
1213 if (!stralloc_copyb(&line2,line.s,pos)) die_nomem();
1214 if (!stralloc_catb(&line2,line.s + pos1,line.len - pos1)) die_nomem();
1215 } else {
1216 pos = byte_chr(line.s,line.len,';');
1217 if (pos + HASHLEN + 1 < line.len && pos > 15 && line.s[pos + 1] != ' ') {
1218 if (!stralloc_copyb(&line2,line.s,pos - 15)) die_nomem();
1219 pos++;
1220 if (!stralloc_catb(&line2,line.s + pos + HASHLEN,line.len - pos - HASHLEN)) die_nomem();
1221 } else /* old format - no author hash */
1222 if (!stralloc_copyb(&line2,line.s,line.len)) die_nomem();
1223 }
1224 code_qput(line2.s,line2.len);
1225 } else
1226 break;
1227 }
1228 close(fd);
1229 }
1230
1231 if (u == max/100) /* unlock if last index in archive file */
1232 unlock();
1233
1234 u++;
1235 }
1236 normal_bottom(outformat);
1237 postmsg(outformat);
1238 }
1239
1240/* -thread[f][-|.]num returns messages with subject matching message */
1241/* 'num' in the subject index. If 'num' is not in[1..last_message] an error */
1242/* message is returned. */
1243
1244 else if (act == AC_THREAD) {
1245 if (!flagarchived)
1246 logmsg(WHO,100,FATAL,ERR_NOT_ARCHIVED);
1247 if (!flagindexed)
1248 logmsg(WHO,100,FATAL,ERR_NOT_INDEXED);
1249
1250 zapnonsub(ACTION_THREAD); /* restrict to subs if requested*/
1251
1252 get_num(); /* max = last successful message */
1253 if (!max)
1254 logmsg(WHO,100,FATAL,ERR_EMPTY_LIST);
1255 szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
1256 set_cpnum(szmsgnum); /* for copy this is the latest message arch'd*/
1257
1258 doheaders();
1259 tosender();
1260 if (!stralloc_cats(&subject," Digest of: ")) die_nomem(); /* for rfc1153 */
1261 if (!stralloc_cats(&subject,action)) die_nomem();
1262
1263 to = 0;
1264 pos = str_len(ACTION_THREAD);
1265 if (!case_starts(action,ACTION_THREAD))
1266 pos = str_len(ALT_THREAD);
1267 if (FORMATS[str_chr(FORMATS,action[pos])]) {
1268 outformat = action[pos];
1269 ++pos;
1270 }
1271 if (action[pos] == '-' || action[pos] == '.') pos++;
1272 if(action[pos += scan_ulong(action + pos,&u)])
1273 scan_ulong(action + pos + 1, &to);
1274
1275 if(u == 0 || u > max) {
1276 hdr_add2("Subject: ",subject.s,subject.len);
1277 qmail_puts(&qq,"\n");
1278 ezcopy(&qq,"text/get-bad",flagcd);
1279 } else { /* limit range to at most u-THREAD_BEFORE to u+THREAD_AFTER */
1280 if (u > THREAD_BEFORE)
1281 from = u-THREAD_BEFORE;
1282 else
1283 from = 1L;
1284 if (u + THREAD_AFTER > max) {
1285 idx_mkthread(&msgtable,&subtable,&authtable,from,max,u,max,0);
1286 digest(msgtable,subtable,authtable,from,max,&subject,
1287 AC_THREAD,outformat);
1288 } else {
1289 idx_mkthread(&msgtable,&subtable,&authtable,
1290 from,u+THREAD_AFTER,u,max,0);
1291 digest(msgtable,subtable,authtable,from,u+THREAD_AFTER,
1292 &subject,AC_THREAD,outformat);
1293 }
1294 }
1295 }
1296
1297 /* This happens if the initial check at the beginning of 'main' */
1298 /* matches something that isn't matched here. Conversely, just */
1299 /* adding an action here is not enough - it has to be added to the */
1300 /* initial check as well. */
1301
1302 else
1303 logmsg(WHO,100,FATAL,"Program error: I'm supposed to deal with this but I didn't");
1304
1305 if (!stralloc_copy(&line,&outlocal)) die_nomem();
1306 if (act == AC_DIGEST) {
1307 if (chunk) {
1308 if (!stralloc_cats(&line,"-return-g-")) die_nomem();
1309 } else
1310 if (!stralloc_cats(&line,"-return-")) die_nomem();
1311 strnum[fmt_ulong(strnum,mno)] = '\0';
1312 if (!stralloc_cats(&line,strnum)) die_nomem();
1313 if (!stralloc_cats(&line,"-@")) die_nomem();
1314
1315 if (!stralloc_cat(&line,&outhost)) die_nomem();
1316 if (!stralloc_cats(&line,"-@[]")) die_nomem();
1317 } else {
1318 if (!stralloc_cats(&line,"-return-@")) die_nomem();
1319 if (!stralloc_cat(&line,&outhost)) die_nomem();
1320 }
1321 if (!stralloc_0(&line)) die_nomem();
1322
1323 qmail_from(&qq,line.s);
1324 if (act == AC_DIGEST) { /* Do recipients */
1325 tagmsg(workdir,mno,seed.s,"d",hashout,qq.msgsize,chunk);
1326
1327 if (chunk) {
1328 if (!stralloc_copys(&line,"T")) die_nomem();
1329 if (!stralloc_cat(&line,&outlocal)) die_nomem();
1330 if (!stralloc_cats(&line,"-s-d-")) die_nomem();
1331 if (!stralloc_catb(&line,hashout,COOKIE)) die_nomem();
1332 if (!stralloc_cats(&line,"-")) die_nomem();
1333 if (!stralloc_cats(&line,strnum)) die_nomem();
1334 if (!stralloc_cats(&line,"-")) die_nomem();
1335 if (!stralloc_copys(&line2,"@")) die_nomem();
1336 if (!stralloc_cat(&line2,&outhost)) die_nomem();
1337 if (!stralloc_0(&line2)) die_nomem();
1338
1339 j = 0;
1340 for (i = 0; i <= 52; i += chunk) { /* To slaves */
1341 qmail_put(&qq,line.s,line.len);
1342 schar[0] = '0' + i / 10;
1343 schar[1] = '0' + (i % 10);
1344 qmail_put(&qq,schar,3);
1345 j += (chunk - 1);
1346 if (j > 52) j = 52;
1347 schar[0] = '0' + j / 10;
1348 schar[1] = '0' + (j % 10);
1349 qmail_put(&qq,schar,2);
1350 qmail_put(&qq,line2.s,line2.len);
1351 }
1352 } else
1353 subs = putsubs(workdir,0L,52L,&subto,1);
1354 } else { /* if local is set, sender is checked */
1355 if (pmod)
1356 qmail_to(&qq,pmod);
1357 else
1358 qmail_to(&qq,sender);
1359 }
1360
1361 if (*(err = qmail_close(&qq)) == '\0') { /* Done. Skip rest. */
1362 if (act == AC_DIGEST) {
1363 if (chunk) loginfo(workdir,mno,0L,0L,2);
1364 else
1365 loginfo(workdir,mno,0L,subs,4);
1366 }
1367 closesql(); /* close db connection */
1368 unlock(); /* NOP if nothing locked */
1369 strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
1370 logmsg(WHO,goodexit,INFO,B("qp ",strnum));
1371 } else { /* failed. Reset last msg & issue for digest */
1372 if(act == AC_DIGEST) {
1373 issue--;
1374 write_ulong(issue,0L,0L,"digissue","digissuen");
1375 write_ulong(prevmax,cumsize,(unsigned long) digwhen,"dignum","dignumn");
1376 }
1377 unlock(); /* NOP if nothing locked */
1378 logmsg(WHO,111,FATAL,B(ERR_TMP_QMAIL_QUEUE,err + 1));
1379 }
1380
1381 return 0;
1382}
datetime_sec now(void)
Definition now.c:5
#define COOKIE
Definition cookie.h:4
#define FORMATS
Definition idx.h:157
#define THREAD_BEFORE
Definition idx.h:8
#define TXT_BY
Definition idx.h:89
#define TXT_DEF_CHARSET
Definition idx.h:93
#define ACTION_GET
Definition idx.h:186
#define ACTION_DIGEST
Definition idx.h:231
#define ALT_GET
Definition idx.h:48
#define AC_NONE
Definition idx.h:312
#define AC_THREAD
Definition idx.h:315
#define QMQPSERVERS
Definition idx.h:306
#define TXT_ADMINISTRIVIA
Definition idx.h:84
#define DEFAULT_FORMAT
Definition idx.h:169
#define ALT_INDEX
Definition idx.h:50
#define TXT_TOP_TOPICS
Definition idx.h:78
#define ACTION_INDEX
Definition idx.h:187
#define MAXGET
Definition idx.h:13
#define TXT_NOINDEX
Definition idx.h:96
#define ALT_THREAD
Definition idx.h:55
#define ACTION_THREAD
Definition idx.h:188
#define AC_INDEX
Definition idx.h:316
#define MIME
Definition idx.h:158
#define AC_GET
Definition idx.h:313
#define MAXINDEX
Definition idx.h:22
#define NATIVE
Definition idx.h:163
#define TXT_TOP_MESSAGES
Definition idx.h:79
#define TXT_TOP_THROUGH
Definition idx.h:80
#define HISTGET
Definition idx.h:17
#define TXT_TOP_LAST
Definition idx.h:81
#define THREAD_AFTER
Definition idx.h:9
#define AC_DIGEST
Definition idx.h:314
#define VIRGIN
Definition idx.h:161
#define MIXED
Definition idx.h:167
#define RFC1153
Definition idx.h:159
void makehash(const char *indata, unsigned int inlen, char *hash)
Definition makehash.c:104
int issub()
Returns (char *) to match if userhost is in the subscriber database dbname, 0 otherwise....
int quote2(stralloc *sa, const char *s)
Definition quote.c:65
int quote(stralloc *saout, const stralloc *sain)
Definition quote.c:57
const char auto_version[]
#define DATE822FMT
Definition date822fmt.h:4
@ CTYPE_TEXT
Definition hdr.h:13
@ CTYPE_DIGEST
Definition hdr.h:15
@ CTYPE_MULTIPART
Definition hdr.h:14
@ CTYPE_MESSAGE
Definition hdr.h:16
Error messages. If you translate these, I would urge you to keep the English version as well....
#define ERR_FLUSH
Definition errtxt.h:20
#define ERR_NOMEM
Definition errtxt.h:14
#define ERR_SYNC
Definition errtxt.h:22
#define ERR_EMPTY_DIGEST
Definition errtxt.h:61
#define ERR_OPEN
Definition errtxt.h:30
#define ERR_MOVE
Definition errtxt.h:29
#define ERR_ANONYMOUS
Definition errtxt.h:44
#define ERR_READ_INPUT
Definition errtxt.h:26
#define ERR_NOCMD
Definition errtxt.h:15
#define ERR_NOT_ARCHIVED
Definition errtxt.h:46
#define ERR_MAILING_LIST
Definition errtxt.h:57
#define ERR_571
Definition errtxt.h:60
#define ERR_SUBSCRIBER_CAN
Definition errtxt.h:59
#define ERR_READ
Definition errtxt.h:18
#define ERR_BAD_DIGCODE
Definition errtxt.h:65
#define ERR_LOOPING
Definition errtxt.h:58
#define ERR_CREATE
Definition errtxt.h:28
#define ERR_QMAIL_QUEUE
Definition errtxt.h:53
#define ERR_SWITCH
Definition errtxt.h:42
#define ERR_EMPTY_LIST
Definition errtxt.h:62
#define ERR_WRITE
Definition errtxt.h:17
#define ERR_NOT_PUBLIC
Definition errtxt.h:45
#define ERR_SEEK_INPUT
Definition errtxt.h:27
#define ERR_NOSENDER
Definition errtxt.h:37
#define ERR_CLOSE
Definition errtxt.h:16
#define ERR_TMP_QMAIL_QUEUE
Definition errtxt.h:54
#define ERR_BOUNCE
Definition errtxt.h:38
#define ERR_NOT_INDEXED
Definition errtxt.h:47
int lockfile(const char *)
Definition lockfile.c:15
long datetime_sec
Definition datetime.h:15
const char * qmail_close(struct qmail *)
Definition qmail.c:120
void qmail_puts(struct qmail *, const char *)
Definition qmail.c:94
void qmail_put(struct qmail *, const char *, int)
Definition qmail.c:87
void qmail_from(struct qmail *, const char *)
Definition qmail.c:103
void qmail_to(struct qmail *, const char *)
Definition qmail.c:113
unsigned long qmail_qp(struct qmail *)
Definition qmail.c:77
int qmail_open(struct qmail *, const stralloc *)
Definition qmail.c:25
charset, outhost, outlocal and flagcd are shared
const char * loginfo(const char *dir, unsigned long msgnum, unsigned long, unsigned long subs, int done)
Definition loginfo.c:12
void tagmsg(const char *dir, unsigned long msgnum, const char *seed, const char *action, char *hashout, unsigned long bodysize, unsigned long chunk)
Definition tagmsg.c:45
void closesql(void)
close connection to SQL server, if open
Definition opensql.c:21
unsigned long putsubs(const char *dir, unsigned long hash_lo, unsigned long hash_hi, int subwrite(), int flagsql)
Definition putsubs.c:49
void die_nomem()
Definition getconf.c:17
int getconf(stralloc *sa, const char *fn, int flagrequired, const char *dir)
Definition getconf.c:21
int getconf_line(stralloc *sa, const char *fn, int flagrequired, const char *dir)
Definition getconf.c:53
void ezcopy(struct qmail *qqp, const char *fn, char q)
Definition ezcopy.c:128
void set_cpoutlocal(const stralloc *ln)
Definition ezcopy.c:67
void set_cpnum(const char *cf)
Definition ezcopy.c:95
void set_cpouthost(const stralloc *ln)
Definition ezcopy.c:73
#define WHO
Definition author.c:1
void encode_qp(const char *indata, unsigned int n, stralloc *outdata)
Definition encode_qp.c:21
stralloc archcc
Definition ezmlm-get.c:103
int flagbottom
Definition ezmlm-get.c:51
char boundary[COOKIE]
Definition ezmlm-get.c:89
void get_num()
Definition ezmlm-get.c:238
stralloc archmessageid
Definition ezmlm-get.c:105
stralloc archblanklines
Definition ezmlm-get.c:107
void digest(msgentry *msgtable, subentry *subtable, authentry *authtable, unsigned long from, unsigned long to, stralloc *subj, int factype, char format)
Definition ezmlm-get.c:666
void postmsg(char format)
Definition ezmlm-get.c:396
void msgout(unsigned long msg, char format)
Definition ezmlm-get.c:593
unsigned long cumsizen
Definition ezmlm-get.c:82
int flagindexed
Definition ezmlm-get.c:125
void doheaders()
Definition ezmlm-get.c:732
stralloc mydtline
Definition ezmlm-get.c:72
void mime_getbad(unsigned long msg)
Definition ezmlm-get.c:575
unsigned long cumsize
Definition ezmlm-get.c:81
void normal_bottom(char format)
Definition ezmlm-get.c:302
stralloc archto
Definition ezmlm-get.c:102
int flagdo
Definition ezmlm-get.c:50
const char * digsz
Definition ezmlm-get.c:55
int act
Definition ezmlm-get.c:119
void copymsg(unsigned long msg, int fd, char format)
Definition ezmlm-get.c:417
int flagpublic
Definition ezmlm-get.c:52
int subto(char *s, unsigned int l)
Definition ezmlm-get.c:141
char * digestcode
Definition ezmlm-get.c:131
stralloc line2
Definition ezmlm-get.c:92
void zapnonsub(char *szerr)
Definition ezmlm-get.c:209
stralloc archfrom
Definition ezmlm-get.c:101
void write_ulong(unsigned long num, unsigned long cum, unsigned long dat, char *fn, char *fnn)
Definition ezmlm-get.c:268
stralloc archdate
Definition ezmlm-get.c:100
char * workdir
Definition ezmlm-get.c:129
ssize_t qqwrite(int fd, char *buf, unsigned int len)
Definition ezmlm-get.c:135
void tosender()
Definition ezmlm-get.c:224
stralloc listno
Definition ezmlm-get.c:78
int flagarchived
Definition ezmlm-get.c:124
stralloc digheaders
Definition ezmlm-get.c:73
void unlock()
Definition ezmlm-get.c:179
struct constmap digheadersmap
Definition ezmlm-get.c:75
stralloc moddir
Definition ezmlm-get.c:71
stralloc edir
Definition ezmlm-get.c:117
void lockup()
Definition ezmlm-get.c:169
datetime_sec digwhen
Definition ezmlm-get.c:85
stralloc mod
Definition ezmlm-get.c:112
buffer bj
Definition ezmlm-get.c:154
char schar[]
Definition ezmlm-get.c:77
unsigned long msgsize
Definition ezmlm-get.c:84
stralloc archsubject
Definition ezmlm-get.c:104
stralloc seed
Definition ezmlm-get.c:74
int flaglocked
Definition ezmlm-get.c:123
void postsub(int factype, char format)
Definition ezmlm-get.c:379
unsigned long dignum()
Definition ezmlm-get.c:251
char indexbuf[1024]
Definition ezmlm-get.c:163
char archtype
Definition ezmlm-get.c:108
stralloc ddir
Definition ezmlm-get.c:116
int flagsub
Definition ezmlm-get.c:54
stralloc archkeywords
Definition ezmlm-get.c:106
int flagq
Definition ezmlm-get.c:126
char hashout[COOKIE]
Definition ezmlm-get.c:90
unsigned long max
Definition ezmlm-get.c:83
int flageditor
Definition ezmlm-get.c:120
void presub(unsigned long from, unsigned long to, stralloc *subject, int factype, char format)
Definition ezmlm-get.c:340
buffer bx
Definition ezmlm-get.c:162
stralloc qmqpservers
Definition ezmlm-get.c:69
void code_qput(char *s, unsigned int n)
Definition ezmlm-get.c:187
void hdr_from(const char *append)
Definition hdr_from.c:23
stralloc fn
char inbuf[1024]
buffer bn
stralloc fnn
stralloc num
char numbuf[16]
char * dir
buffer bi
stralloc from
int main()
Definition ezmlm-weed.c:69
void hdr_boundary(int last)
void hdr_datemsgid(unsigned long when)
int opt
Definition ezmlm-cron.c:53
const char * cp
Definition ezmlm-cron.c:76
unsigned int len
Definition ezmlm-cron.c:68
int fdlock
Definition ezmlm-cron.c:71
const char * pmod
Definition ezmlm-gate.c:42
unsigned int date822fmt(char *s, const struct datetime *dt)
Definition date822fmt.c:9
char buf[256]
Definition install.c:113
char * local
Definition ezmlm-cgi.c:106
int fd
Definition ezmlm-cgi.c:141
stralloc listname
Definition ezmlm-cgi.c:132
datetime_sec when
Definition ezmlm-cgi.c:173
const char * charset
Definition ezmlm-cgi.c:110
struct datetime dt
Definition ezmlm-cgi.c:174
int match
Definition ezmlm-cgi.c:140
stralloc subject
Definition ezmlm-cgi.c:119
void idx_mkthread(msgentry **pmsgtable, subentry **psubtable, authentry **pauthtable, unsigned long msg_from, unsigned long msg_to, unsigned long msg_master, unsigned long msg_latest, int locked)
Definition idxthread.c:424
#define HASHLEN
Definition idxthread.c:25
void idx_destroythread(msgentry *msgtable, subentry *subtable, authentry *authtable)
Definition idxthread.c:683
void idx_mklist(msgentry **pmsgtable, subentry **psubtable, authentry **pauthtable, unsigned long msg_from, unsigned long msg_to)
Definition idxthread.c:636
void idx_mkthreads(msgentry **pmsgtable, subentry **psubtable, authentry **pauthtable, dateentry **pdatetable, unsigned long msg_from, unsigned long msg_to, unsigned long msg_latest, int locked)
Definition idxthread.c:156
unsigned long msgnum
stralloc quoted
Definition ezmlm-clean.c:90
buffer bq
Definition ezmlm-clean.c:81
stralloc mailinglist
Definition ezmlm-clean.c:93
ssize_t qqwrite(int fd, char *buf, unsigned int len)
Definition ezmlm-clean.c:75
char hboundary[HASHLEN]
Definition ezmlm-clean.c:86
char flagcd
Definition ezmlm-clean.c:59
stralloc to
Definition ezmlm-clean.c:97
struct qmail qq
Definition ezmlm-clean.c:73
void hdr_transferenc(void)
void hdr_add2(const char *start, const char *value, unsigned int len)
Definition hdr_add.c:25
void hdr_adds(const char *line)
Definition hdr_add.c:19
void encode_b64(const unsigned char *indata, unsigned int n, stralloc *outdata, int control)
Definition encode_b64.c:75
void datetime_tai(struct datetime *dt, datetime_sec t)
Definition datetime.c:9
void hdr_ctype(enum ctype ctype)
Definition hdr_mime.c:24
void hdr_mime(enum ctype ctype)
Definition hdr_mime.c:43
stralloc action
Definition ezmlm-store.c:84
unsigned long authnum
Definition idx.h:329
unsigned long subnum
Definition idx.h:328
unsigned long firstmsg
Definition idx.h:342
char * sub
Definition idx.h:336
unsigned int sublen
Definition idx.h:341
unsigned long authlen
Definition idx.h:355
char * auth
Definition idx.h:350
Definition qmail.h:10
const char * logmsg(const char *dir, unsigned long num, unsigned long listno, unsigned long subs, int done)
Definition loginfo.c:32