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