ezmlmx 0.68
ezmlmx
Loading...
Searching...
No Matches
ezmlm-manage.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <stdio.h>
4#include <unistd.h>
5#include "error.h"
6#include "stralloc.h"
7#include "str.h"
8#include "env.h"
9#include "sig.h"
10#include "readclose.h"
11#include "getconf.h"
12#include "byte.h"
13#include "getln.h"
14#include "case.h"
15#include "qmail.h"
16#include "buffer.h"
17#include "readwrite.h"
18#include "seek.h"
19#include "quote.h"
20#include "datetime.h"
21#include "now.h"
22#include "fmt.h"
23#include "subscribe.h"
24#include "cookie.h"
25#include "getoptb.h"
26#include "ezcopy.h"
27#include "errtxt.h"
28#include "open.h"
29#include "lock.h"
30#include "scan.h"
31#include "mime.h"
32#include "hdr.h"
33#include "idx.h"
34#include "auto_version.h"
35#include "logmsg.h"
36#include "lockfile.h"
37#include "makehash.h"
38#include "ezmlm.h"
39
40#define WHO "ezmlm-manage"
41
47
48int flagverbose = 0; /* default: Owner not informed about subdb changes */
49 /* 1 => notified for failed unsub, 2 => for all */
50int flagnotify = 1; /* notify subscriber of completed events. 0 also */
51 /* suppresses all subscriber communication for */
52 /* [un]sub if -U/-S is used */
53int flagbottom = 1; /* default: copy request & admin info to message */
54int flaglist = 0; /* default: do not reply to -list */
55int flagget = 1; /* default: service -get requests */
56int flagsubconf = 1; /* default: require user-confirm for subscribe */
57int flagunsubconf = 1; /* default: require user-confirm for unsubscribe */
58int flagunsubismod = 0; /* default: do not require moderator approval to */
59 /* unsubscribe from moderated list */
60int flagedit = 0; /* default: text file edit not allowed */
61int flagstorefrom = 1; /* default: store from: line for subscribes */
62char flagcd = '\0'; /* default: do not use _Q_uoted printable or _B_ase64 */
63char encin = '\0'; /* encoding of incoming message */
64int flagdig = 0; /* request is not for digest list */
65
66static const char hex[]="0123456789ABCDEF";
67char urlstr[] = "%00"; /* to build a url-encoded version of a char */
68
69int act = AC_NONE; /* desired action */
70unsigned int actlen = 0; /* str_len of above */
71char *dir;
72char *workdir;
73char *sender;
74
75static void die_usage(void) { logmsg(WHO,100,USAGE,"ezmlm-manage [-bBcCdDeEfFlLmMnNqQsSuUvV] dir"); }
76static void die_nomem(void) { logmsg(WHO,111,FATAL,ERR_NOMEM); }
77static void die_badaddr(void) { logmsg(WHO,100,FATAL,ERR_BAD_ADDRESS); }
78static void die_cookie(void) { logmsg(WHO,100,FATAL,ERR_MOD_COOKIE); }
79
80stralloc outhost = {0};
81stralloc outlocal = {0};
82
83stralloc key = {0};
84stralloc mailinglist = {0};
85stralloc mydtline = {0};
86stralloc target = {0};
87stralloc verptarget = {0};
88stralloc confirm = {0};
89stralloc line = {0};
90stralloc qline = {0};
91stralloc quoted = {0};
92stralloc moddir = {0};
93stralloc ddir = {0};
94stralloc modsub = {0};
95stralloc remote = {0};
96stralloc from = {0};
97stralloc to = {0};
98stralloc owner = {0};
99stralloc fromline = {0};
100stralloc text = {0};
101stralloc fnedit = {0};
102stralloc fneditn = {0};
103stralloc charset = {0};
104
107unsigned int max;
108
109static char strnum[FMT_ULONG];
110char hash[COOKIE];
113
114char inbuf[1024];
115buffer bi = BUFFER_INIT(read,0,inbuf,(int) sizeof(inbuf));
116buffer bj = BUFFER_INIT(read,0,inbuf,(int) sizeof(inbuf));
117
118buffer bt; /* editing texts and reading "from" */
119char textbuf[512];
120
121buffer bf; /* writing "from" */
122char frombuf[512];
123
125
126void lock() { fdlock = lockfile("lock"); }
127void unlock() { close(fdlock); }
128
134
136{
137 unsigned int i;
138
139 i = str_rchr(target.s,'@');
140 if (!stralloc_copyb(&verptarget,target.s,i)) die_nomem();
141 if (target.s[i]) {
142 if (!stralloc_append(&verptarget,"=")) die_nomem();
143 if (!stralloc_cats(&verptarget,target.s + i + 1)) die_nomem();
144 }
145 if (!stralloc_0(&verptarget)) die_nomem();
146 set_cpverptarget(verptarget.s);
147}
148
156
157void store_from(stralloc *frl,char *adr)
158{
159 int fdin;
160 int fdout;
161 unsigned long linetime;
162
163 if (!flagstorefrom || !frl->len) return; /* nothing to store */
164 lock();
165 if ((fdout = open_trunc("fromn")) == -1)
166 logmsg(WHO,111,FATAL,B(ERR_OPEN," from "));
167 buffer_init(&bf,buffer_unixwrite,fdout,frombuf,(int) sizeof(frombuf));
168 if ((fdin = open_read("from")) == -1) {
169 if (errno != ENOENT)
170 logmsg(WHO,111,FATAL,B(ERR_OPEN," from"));
171 } else {
172 buffer_init(&bt,buffer_unixread,fdin,textbuf,(int) sizeof(textbuf));
173 for (;;) {
174 if (getln(&bt,&line,&match,'\n') == -1)
175 logmsg(WHO,111,FATAL,B(ERR_READ,"from"));
176 if (!match) break;
177 scan_ulong(line.s,&linetime);
178 if (linetime + 1000000 > when && linetime <= when)
179 if (buffer_put(&bf,line.s,line.len))
180 logmsg(WHO,111,FATAL,B(ERR_WRITE,"fromn"));
181 }
182 close(fdin);
183 }
184
185 /* build new entry */
186 if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,when))) die_nomem();
187 if (!stralloc_append(&line," ")) die_nomem();
188 if (!stralloc_cats(&line,adr)) die_nomem();
189 if (!stralloc_0(&line)) die_nomem();
190 if (!stralloc_catb(&line,frl->s,frl->len)) die_nomem();
191 if (!stralloc_append(&line,"\n")) die_nomem();
192 if (buffer_put(&bf,line.s,line.len) == -1)
193 logmsg(WHO,111,FATAL,B(ERR_WRITE,"fromn"));
194 if (buffer_flush(&bf) == -1)
195 logmsg(WHO,111,FATAL,B(ERR_WRITE,"from"));
196 if (fsync(fdout) == -1)
197 logmsg(WHO,111,FATAL,B(ERR_SYNC,"fromn"));
198 if (close(fdout) == -1)
199 logmsg(WHO,111,FATAL,B(ERR_CLOSE,"fromn"));
200 if (rename("fromn","from") == -1)
201 logmsg(WHO,111,FATAL,B(ERR_MOVE,"from"));
202 unlock();
203}
204
220
221char *get_from(char *adr,char *act)
222{
223 int fd;
224 char *fl;
225 unsigned int pos;
226 unsigned long thistime;
227 unsigned long linetime;
228
229 if (!flagstorefrom) return 0;
230 if (fromline.len) { /* easy! We got it in this message */
231 if (!stralloc_0(&fromline)) die_nomem();
232 return fromline.s;
233 } /* need to recover it from DIR/from */
234
235 fl = 0;
236 scan_ulong(act+3,&thistime);
237 if ((fd = open_read("from")) == -1)
238 if (errno == ENOENT)
239 return 0;
240 else
241 logmsg(WHO,111,FATAL,B(ERR_READ,"from"));
242
243 buffer_init(&bt,buffer_unixread,fd,textbuf,(int) sizeof(textbuf));
244
245 for (;;) {
246 if (getln(&bt,&fromline,&match,'\n') == -1)
247 logmsg(WHO,111,FATAL,B(ERR_READ,"from"));
248 if (!match) break;
249 fromline.s[fromline.len - 1] = (char) 0;
250
251 /* now:time addr\0fromline\0 read all. They can be out of order! */
252 pos = scan_ulong(fromline.s,&linetime);
253 if (linetime != thistime) continue;
254 if (!str_diff(fromline.s + pos + 1,adr)) {
255 pos = str_len(fromline.s);
256 if (pos < fromline.len) {
257 fl = fromline.s + pos + 1;
258 break;
259 }
260 }
261 }
262 close(fd);
263 return fl;
264}
265
266int hashok(char *action,char *ac)
267{
268 char *x;
269 datetime_sec u;
270
271 x = action + 3;
272 x += scan_ulong(x,&u);
273 hashdate = u;
274 if (hashdate > when) return 0;
275 if (hashdate < when - 1000000) return 0;
276
277 u = hashdate;
278 strnum[fmt_ulong(strnum,(unsigned long) u)] = 0;
279 cookie(hash,key.s,key.len - flagdig,strnum,target.s,ac);
280
281 if (*x == '.') ++x;
282 if (str_len(x) != COOKIE) return 0;
283 return byte_equal(hash,COOKIE,x);
284}
285
286struct qmail qq;
287ssize_t qqwrite(int fd,char *buf,unsigned int len)
288{
290 return len;
291}
292
293char qqbuf[1];
294buffer bq = BUFFER_INIT(qqwrite,-1,qqbuf,(int) sizeof(qqbuf));
295
296int code_qput(char *s,unsigned int n)
297{
298 if (!flagcd)
299 qmail_put(&qq,s,n);
300 else {
301 if (flagcd == 'B')
302 encode_b64(s,n,&qline,0);
303 else
304 encode_qp(s,n,&qline);
305 qmail_put(&qq,qline.s,qline.len);
306 }
307 return 0; /* always succeeds */
308}
309
310int subto(char *s,unsigned int l)
311{
312 qmail_put(&qq,"T",1);
313 qmail_put(&qq,s,l);
314 qmail_put(&qq,"",1);
315 return (int) l;
316}
317
318int code_subto(char *s,unsigned int l)
319{
320 code_qput(s,l);
321 code_qput("\n",1);
322 return (int) l;
323}
324
325int dummy_to(char *s,unsigned int l)
326{
327 return (int) l;
328}
329
331{
332 if (!stralloc_copy(&owner,&outlocal)) die_nomem();
333 if (!stralloc_cats(&owner,"-owner@")) die_nomem();
334 if (!stralloc_cat(&owner,&outhost)) die_nomem();
335 if (!stralloc_0(&owner)) die_nomem();
336 qmail_to(&qq,owner.s);
337}
338
340{
341 ezcopy(&qq,"text/mod-sub",flagcd);
342 ezcopy(&qq,"text/bottom",flagcd);
344 if (flagcd)
345 hdr_boundary(1);
346 if (flagcd == 'B') {
347 encode_b64("",0,&line,2); /* flush */
348 qmail_put(&qq,line.s,line.len);
349 }
350 qmail_from(&qq,from.s);
351}
352
357
359{
360 int flaggoodfield;
361 int flagfromline;
362 int flaggetfrom;
363 unsigned int pos;
364
365 hdr_add2("Mailing-List: ",mailinglist.s,mailinglist.len);
366 if(getconf_line(&line,"listid",0,dir))
367 hdr_add2("List-ID: ",line.s,line.len);
368 if (!quote(&quoted,&outlocal)) die_nomem(); /* quoted has outlocal */
369 qmail_puts(&qq,"List-Help: <mailto:"); /* General rfc2369 headers */
370 qmail_put(&qq,quoted.s,quoted.len);
371 qmail_puts(&qq,"-help@");
372 qmail_put(&qq,outhost.s,outhost.len);
373 qmail_puts(&qq,">\nList-Post: <mailto:");
374 qmail_put(&qq,quoted.s,quoted.len);
375 qmail_puts(&qq,"@");
376 qmail_put(&qq,outhost.s,outhost.len);
377 qmail_puts(&qq,">\nList-Subscribe: <mailto:");
378 qmail_put(&qq,quoted.s,quoted.len);
379 qmail_puts(&qq,"-subscribe@");
380 qmail_put(&qq,outhost.s,outhost.len);
381 qmail_puts(&qq,">\n");
383 /* differnt "From:" for help to break auto-responder loops */
384 hdr_from((act == AC_HELP) ? "-return-" : "-help");
385 if (!quote2(&quoted,target.s)) die_nomem();
386 hdr_add2("To: ",quoted.s,quoted.len);
387 if (!stralloc_copys(&mydtline,"Delivered-To: responder for ")) die_nomem();
388 if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
389 if (!stralloc_cats(&mydtline,"@")) die_nomem();
390 if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
391 if (!stralloc_cats(&mydtline,"\n")) die_nomem();
393
394 flaggoodfield = 0;
395 flagfromline = 0;
396
397 /* do it for -sc, but if the -S flag is used, do it for -subscribe */
398 flaggetfrom = flagstorefrom &&
399 ((act == AC_SC) || ((act == AC_SUBSCRIBE) && !flagsubconf));
400 for (;;) {
401 if (getln(&bi,&line,&match,'\n') == -1)
402 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
403 if (!match) break;
404 if (line.len == 1) break;
405 if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
406 flagfromline = 0;
407 flaggoodfield = 0;
408 if (case_startb(line.s,line.len,"mailing-list:"))
409 logmsg(WHO,100,FATAL,ERR_MAILING_LIST);
410 if (line.len == mydtline.len)
411 if (byte_equal(line.s,line.len,mydtline.s))
412 logmsg(WHO,100,FATAL,ERR_LOOPING);
413 if (case_startb(line.s,line.len,"delivered-to:"))
414 flaggoodfield = 1;
415 else if (case_startb(line.s,line.len,"received:"))
416 flaggoodfield = 1;
417 else if (case_startb(line.s,line.len,"content-transfer-encoding:")) {
418 pos = 26;
419 while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos;
420 if (case_startb(line.s+pos,line.len-pos,"base64"))
421 encin = 'B';
422 else if (case_startb(line.s+pos,line.len-pos,"quoted-printable"))
423 encin = 'Q';
424 } else if (flaggetfrom && case_startb(line.s,line.len,"from:")) {
425 flagfromline = 1; /* for logging subscriber data */
426 pos = 5;
427 while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos;
428 if (!stralloc_copyb(&fromline,line.s + pos,line.len - pos - 1))
429 die_nomem();
430 }
431 } else {
432 if (flagfromline == 1) /* scrap terminal '\n' */
433 if (!stralloc_catb(&fromline,line.s,line.len - 1)) die_nomem();
434 }
435 if (flaggoodfield)
436 qmail_put(&qq,line.s,line.len);
437 }
439}
440
441int geton(char *action)
442{
443 char *fl;
444 int r;
445 unsigned int i;
446 unsigned char ch;
447
448 fl = get_from(target.s,action); /* try to match up */
449 switch ((r = subscribe(workdir,target.s,1,fl,"+",1,-1,(char *) 0))) {
450 case 1: qmail_puts(&qq,"List-Unsubscribe: <mailto:"); /*rfc2369 */
451 qmail_put(&qq,outlocal.s,outlocal.len);
452 qmail_puts(&qq,"-unsubscribe-");
453 /* url-encode since verptarget is controlled by sender */
454 /* note &verptarget ends in '\0', hence len - 1! */
455 for (i = 0; i < verptarget.len - 1; i++) {
456 ch = verptarget.s[i];
457 if (str_chr("\"?;<>&/:%+#",ch) < 10 || (ch <= ' ') || (ch & 0x80)) {
458 urlstr[1] = hex[ch / 16];
459 urlstr[2] = hex[ch & 0xf];
460 qmail_put(&qq,urlstr,3);
461 } else {
462 qmail_put(&qq,verptarget.s + i, 1);
463 }
464 }
465 qmail_puts(&qq,"@");
466 qmail_put(&qq,outhost.s,outhost.len); /* safe */
467 qmail_puts(&qq,">\n");
470 if (!stralloc_copy(&confirm,&outlocal)) die_nomem();
471 if (!stralloc_append(&confirm,"unsubscribe-")) die_nomem();
472 if (!stralloc_cats(&confirm,verptarget.s)) die_nomem();
473 if (!stralloc_append(&confirm,"@")) die_nomem();
474 if (!stralloc_cat(&confirm,&outhost)) die_nomem();
475 if (!stralloc_0(&confirm)) die_nomem();
476 set_cpconfirm(confirm.s); /* for !R in copy */
477 ezcopy(&qq,"text/top",flagcd);
478 ezcopy(&qq,"text/sub-ok",flagcd);
479 break;
480 default: if (str_start(action,ACTION_TC))
481 logmsg(WHO,0,INFO,ERR_SUB_NOP);
484 ezcopy(&qq,"text/top",flagcd);
485 ezcopy(&qq,"text/sub-nop",flagcd);
486 break;
487 }
488 if (flagdig == FLD_DENY || flagdig == FLD_ALLOW)
489 logmsg(WHO,0,INFO,B(ERR_EXTRA_SUB,target.s));
490
491 return r;
492}
493
494int getoff(char *action)
495{
496 int r;
497
498 switch ((r = subscribe(workdir,target.s,0,"","-",1,-1,(char *) 0))) {
499 case 1: hdr_listsubject1(TXT_GOODBYE); /* no comment for unsubscribe */
500 qmail_puts(&qq,"\n");
502 ezcopy(&qq,"text/top",flagcd);
503 ezcopy(&qq,"text/unsub-ok",flagcd);
504 break;
505 default:
508 ezcopy(&qq,"text/top",flagcd);
509 ezcopy(&qq,"text/unsub-nop",flagcd);
510 break;
511 }
512 if (flagdig == FLD_DENY || flagdig == FLD_ALLOW)
513 logmsg(WHO,0,INFO,B(ERR_EXTRA_UNSUB,target.s));
514 return r;
515}
516
523
524void doconfirm(char *act)
525{
526 strnum[fmt_ulong(strnum,(unsigned long) when)] = 0;
527 cookie(hash,key.s,key.len-flagdig,strnum,target.s,act);
528 if (!stralloc_copy(&confirm,&outlocal)) die_nomem();
529 if (!stralloc_append(&confirm,"-")) die_nomem();
530 if (!stralloc_catb(&confirm,act,1)) die_nomem();
531 if (!stralloc_cats(&confirm,"c.")) die_nomem();
532 if (!stralloc_cats(&confirm,strnum)) die_nomem();
533 if (!stralloc_append(&confirm,".")) die_nomem();
534 if (!stralloc_catb(&confirm,hash,COOKIE)) die_nomem();
535 if (!stralloc_append(&confirm,"-")) die_nomem();
536 if (!stralloc_cats(&confirm,verptarget.s)) die_nomem();
537 if (!stralloc_append(&confirm,"@")) die_nomem();
538 if (!stralloc_cat(&confirm,&outhost)) die_nomem();
539 if (!stralloc_0(&confirm)) die_nomem();
540 set_cpconfirm(confirm.s); /* for copy */
541
542 qmail_puts(&qq,"Reply-To: ");
543 if (!quote2(&quoted,confirm.s)) die_nomem();
544 qmail_put(&qq,quoted.s,quoted.len);
545 qmail_puts(&qq,"\n");
546
547 hdr_listsubject2((*act == ACTION_SC[0] || *act == ACTION_UC[0])
549 (*act == ACTION_SC[0] || *act == ACTION_TC[0])
552 ezcopy(&qq,"text/top",flagcd);
553}
554
556{
557 putsubs(moddir.s,0L,52L,subto,1);
558}
559
561{
562 if (flagbottom || act == AC_HELP) {
563 ezcopy(&qq,"text/bottom",flagcd);
564 if (flagcd) {
565 if (flagcd == 'B') {
566 encode_b64("",0,&line,2); /* flush */
567 qmail_put(&qq,line.s,line.len);
568 }
569 hdr_boundary(0);
571 hdr_adds("Content-Disposition: inline; filename=request.msg");
572 qmail_puts(&qq,"\n");
573 }
574 qmail_puts(&qq,"Return-Path: <");
575 if (!quote2(&quoted,sender)) die_nomem();
576 qmail_put(&qq,quoted.s,quoted.len);
577 qmail_puts(&qq,">\n");
578 if (seek_begin(0) == -1)
579 logmsg(WHO,111,FATAL,ERR_SEEK_INPUT);
580 if (buffer_copy(&bq,&bj) != 0)
581 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
582 if (flagcd)
583 hdr_boundary(1);
584 } else {
585 if (flagcd == 'B') {
586 encode_b64("",0,&line,2); /* flush even if no bottom */
587 qmail_put(&qq,line.s,line.len);
588 }
589 }
590
591 qmail_from(&qq,from.s);
592}
593
594int main(int argc,char **argv)
595{
596 char *action;
597 char *x, *y;
598 char *fname;
599 const char *pmod;
600 const char *err;
601 char *cp, *cpfirst, *cplast, *cpnext, *cpafter;
602 int flagmod;
603 int flagremote;
604 int flagpublic;
605 int opt,r;
606 unsigned int i;
607 unsigned int len;
608 int fd;
609 int flagdone;
610 char ch;
611
612 (void) umask(022);
613 sig_pipeignore();
614 when = now();
615
616 while ((opt = getoptb(argc,argv,"bBcCdDeEfFlLmMnNqQsSuUvV")) != opteof)
617 switch (opt) {
618 case 'b': flagbottom = 1; break;
619 case 'B': flagbottom = 0; break;
620 case 'c': flagget = 1; break;
621 case 'C': flagget = 0; break;
622 case 'd':
623 case 'e': flagedit = 1; break;
624 case 'D':
625 case 'E': flagedit = 0; break;
626 case 'f': flagstorefrom = 1; break;
627 case 'F': flagstorefrom = 0; break;
628 case 'l': flaglist = 1; break;
629 case 'L': flaglist = 0; break;
630 case 'm': flagunsubismod = 1; break;
631 case 'M': flagunsubismod = 0; break;
632 case 'n': flagnotify = 1; break;
633 case 'N': flagnotify = 0; break;
634 case 's': flagsubconf = 1; break;
635 case 'S': flagsubconf = 0; break;
636 case 'q': flagverbose = 0; break;
637 case 'Q': flagverbose++; break;
638 case 'u': flagunsubconf = 1; break;
639 case 'U': flagunsubconf = 0; break;
640 case 'v':
641 case 'V': logmsg(WHO,0,VERSION,auto_version);
642 default: die_usage();
643 }
644
645 dir = argv[optind];
646 if (!dir) die_usage();
647
648 sender = env_get("SENDER");
649 if (!sender) logmsg(WHO,100,FATAL,ERR_NOSENDER);
650 action = env_get("DEFAULT");
651 if (!action) logmsg(WHO,100,FATAL,ERR_NODEFAULT);
652
653 if (!*sender)
654 logmsg(WHO,100,FATAL,ERR_BOUNCE);
655 if (!sender[str_chr(sender,'@')])
656 logmsg(WHO,100,FATAL,ERR_ANONYMOUS);
657 if (str_equal(sender,"#@[]"))
658 logmsg(WHO,100,FATAL,ERR_BOUNCE);
659
660 if (chdir(dir) == -1)
661 logmsg(WHO,111,FATAL,B(ERR_SWITCH,dir));
662
663 switch (openreadclose("key",&key,32)) {
664 case -1:
665 logmsg(WHO,111,FATAL,B(ERR_READ,"/key: ",dir));
666 case 0:
667 logmsg(WHO,100,FATAL,B(ERR_NOEXIST,"/key",dir));
668 }
669 getconf_line(&mailinglist,"mailinglist",1,dir);
670 getconf_line(&outhost,"outhost",1,dir);
671 getconf_line(&outlocal,"outlocal",1,dir);
672 set_cpouthost(&outhost);
673 if (getconf_line(&charset,"charset",0,dir)) {
674 if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
675 if (charset.s[charset.len - 1] == 'B' ||
676 charset.s[charset.len - 1] == 'Q') {
677 flagcd = charset.s[charset.len - 1];
678 charset.s[charset.len - 2] = '\0';
679 }
680 }
681 } else
682 if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
683 if (!stralloc_0(&charset)) die_nomem();
684
685 if (!stralloc_copys(&ddir,dir)) die_nomem();
686
687 if (case_starts(action,"digest")) { /* digest */
688 action += 6;
689 if (!stralloc_cats(&outlocal,"-digest")) die_nomem();
690 if (!stralloc_cats(&ddir,"/digest")) die_nomem();
692 } else if (case_starts(action,ACTION_ALLOW)) { /* allow */
693 action += str_len(ACTION_ALLOW);
694 if (!stralloc_append(&outlocal,"-")) die_nomem();
695 if (!stralloc_cats(&outlocal,ACTION_ALLOW)) die_nomem();
696 if (!stralloc_cats(&ddir,"/allow")) die_nomem();
698 } else if (case_starts(action,ACTION_DENY)) { /* deny */
699 action += str_len(ACTION_DENY);
700 if (!stralloc_append(&outlocal,"-")) die_nomem();
701 if (!stralloc_cats(&outlocal,ACTION_DENY)) die_nomem();
702 if (!stralloc_cats(&ddir,"/deny")) die_nomem();
704 }
705 if (flagdig) /* zap '-' after db specifier */
706 if (*(action++) != '-') die_badaddr();
707
708 if (!stralloc_0(&ddir)) die_nomem();
709 workdir = ddir.s;
710 set_cpoutlocal(&outlocal);
711
712 if (!stralloc_copys(&target,sender)) die_nomem();
713 if (action[0]) {
714 i = str_chr(action,'-');
715 if (action[i]) {
716 action[i] = 0;
717 if (!stralloc_copys(&target,action + i + 1)) die_nomem();
718 i = byte_rchr(target.s,target.len,'=');
719 if (i < target.len)
720 target.s[i] = '@';
721 }
722 }
723 if (!stralloc_0(&target)) die_nomem();
724 set_cptarget(target.s); /* for ezcopy() */
726
727 flagmod = getconf_line(&modsub,"modsub",0,dir);
728 flagremote = getconf_line(&remote,"remote",0,dir);
729
730 if (case_equals(action,ACTION_LISTN) || case_equals(action,ALT_LISTN))
731 act = AC_LISTN;
732 else if (case_equals(action,ACTION_LIST) || case_equals(action,ALT_LIST))
733 act = AC_LIST;
734 else if (case_starts(action,ACTION_GET) || case_starts(action,ALT_GET))
735 act = AC_GET;
736 else if (case_equals(action,ACTION_HELP) || case_equals(action,ALT_HELP))
737 act = AC_HELP;
738 else if (case_starts(action,ACTION_EDIT) || case_starts(action,ALT_EDIT))
739 act = AC_EDIT;
740 else if (case_starts(action,ACTION_LOG))
741 { act = AC_LOG; actlen = str_len(ACTION_LOG); }
742 else if (case_starts(action,ALT_LOG))
743 { act = AC_LOG; actlen = str_len(ALT_LOG); }
744
745 /* NOTE: act is needed in msg_headers(). */
746 /* Yes, this needs to be cleaned up! */
747
748 if (flagmod || flagremote) {
749 if (modsub.len && modsub.s[0] == '/') {
750 if (!stralloc_copy(&moddir,&modsub)) die_nomem();
751 } else if (remote.len && remote.s[0] == '/') {
752 if (!stralloc_copy(&moddir,&remote)) die_nomem();
753 } else {
754 if (!stralloc_copys(&moddir,dir)) die_nomem();
755 if (!stralloc_cats(&moddir,"/mod")) die_nomem();
756 }
757 if (!stralloc_0(&moddir)) die_nomem();
758
759 /* for these the reply is 'secret' and goes to sender */
760 /* This means that they can be triggered from a SENDER */
761 /* that is not a mod, but never send to a non-mod */
762
763 if (act == AC_NONE || flagdig == FLD_DENY) /* None of the above */
764 pmod = issub(moddir.s,sender,(char *) 0); /* sender = moderator? */
765 else
766 pmod = issub(moddir.s,target.s,(char *) 0);/* target = moderator? */
767 } else
768 pmod = 0;
769 /* always 0 for non-mod/remote lists */
770 /* if DIR/public is mibig, we still respond*/
771 /* to requests from moderators for remote */
772 /* admin and modsub lists. Since pmod */
773 /* is false for all non-mod lists, only it */
774 /* needs to be tested. */
775
776 if ((flagpublic = openreadclose("public",&line,1)) == -1)
777 logmsg(WHO,111,FATAL,B(ERR_READ,"/public:",dir));
778 if (!flagpublic && !(pmod && flagremote) && !case_equals(action,ACTION_HELP))
779 logmsg(WHO,100,FATAL,ERR_NOT_PUBLIC);
780
781 if (flagdig == FLD_DENY)
782 if (!pmod || !flagremote) /* only mods can do */
783 logmsg(WHO,100,ERROR,ERR_NOT_ALLOWED);
784
785 if (act == AC_NONE) { /* none of the above */
786 if (case_equals(action,ACTION_SUBSCRIBE) || case_equals(action,ALT_SUBSCRIBE))
788 else if (case_equals(action,ACTION_UNSUBSCRIBE) || case_equals(action,ALT_UNSUBSCRIBE))
790 else if (str_start(action,ACTION_SC)) act = AC_SC;
791 }
792
793 if (!stralloc_copy(&from,&outlocal)) die_nomem();
794 if (!stralloc_cats(&from,"-return-@")) die_nomem();
795 if (!stralloc_cat(&from,&outhost)) die_nomem();
796 if (!stralloc_0(&from)) die_nomem();
797
798 if (qmail_open(&qq,(stralloc *) 0) == -1)
799 logmsg(WHO,111,FATAL,ERR_QMAIL_QUEUE);
800 msg_headers();
801
802 if (act == AC_SUBSCRIBE) {
803 if (pmod && flagremote) {
805 ezcopy(&qq,"text/mod-sub-confirm",flagcd);
806 copybottom();
807 qmail_to(&qq,pmod);
808 } else if (flagsubconf) {
810 ezcopy(&qq,"text/sub-confirm",flagcd);
811 copybottom();
812 qmail_to(&qq,target.s);
813 } else if (flagmod) {
814 store_from(&fromline,target.s);
816 ezcopy(&qq,"text/mod-sub-confirm",flagcd);
817 copybottom();
818 sendtomods();
819 } else { /* normal subscribe, no confirm */
820 r = geton(action); /* should be rarely used. */
821 copybottom();
822 if (flagnotify) qmail_to(&qq,target.s);
823 if (r && flagverbose > 1) to_owner();
824 }
825
826 } else if (act == AC_SC) {
827 if (hashok(action,ACTION_SC)) {
828 if (flagmod && !(pmod && str_equal(sender,target.s))) {
829 store_from(&fromline,target.s); /* save from line, if requested */
830 /* since transaction not complete */
832 ezcopy(&qq,"text/mod-sub-confirm",flagcd);
833 copybottom();
834 sendtomods();
835 } else {
836 r = geton(action);
837 copybottom();
838 qmail_to(&qq,target.s);
839 if (r && flagverbose > 1) to_owner();
840 }
841 } else {
843 ezcopy(&qq,"text/sub-bad",flagcd);
844 copybottom();
845 qmail_to(&qq,target.s);
846 }
847
848 } else if (str_start(action,ACTION_TC)) {
849 if (hashok(action,ACTION_TC)) {
850 r = geton(action);
851 mod_bottom();
852 if (flagnotify) qmail_to(&qq,target.s); /* unless suppressed */
853 if (r && flagverbose > 1) to_owner();
854 } else {
855 if (!pmod || !flagremote) /* else anyone can get a good -tc. */
856 die_cookie();
858 ezcopy(&qq,"text/sub-bad",flagcd);
859 copybottom();
860 qmail_to(&qq,pmod);
861 }
862
863 } else if (act == AC_UNSUBSCRIBE) {
864 if (flagunsubconf) {
865 if (pmod && flagremote) {
867 ezcopy(&qq,"text/mod-unsub-confirm",flagcd);
868 copybottom();
869 qmail_to(&qq,pmod);
870 } else {
872 ezcopy(&qq,"text/unsub-confirm",flagcd);
873 copybottom();
874 qmail_to(&qq,target.s);
875 }
876 } else if (flagunsubismod && flagmod) {
878 ezcopy(&qq,"text/mod-unsub-confirm",flagcd);
879 copybottom();
880 sendtomods();
881 } else {
882 r = getoff(action);
883 copybottom();
884 if (!r || flagnotify) qmail_to(&qq,target.s);
885 /* tell owner if problems (-Q) or anyway (-QQ) */
886 if (flagverbose && (!r || flagverbose > 1)) to_owner();
887 }
888
889 } else if (str_start(action,ACTION_UC)) {
890 if (hashok(action,ACTION_UC)) {
891 /* unsub is moderated only on moderated list if -m unless the */
892 /* target == sender == a moderator */
893 if (flagunsubismod && flagmod) {
895 ezcopy(&qq,"text/mod-unsub-confirm",flagcd);
896 copybottom();
897 sendtomods();
898 } else {
899 r = getoff(action);
900 copybottom();
901 if (!r || flagnotify) qmail_to(&qq,target.s);
902 /* tell owner if problems (-Q) or anyway (-QQ) */
903 if (flagverbose && (!r || flagverbose > 1)) to_owner();
904 }
905 } else {
907 ezcopy(&qq,"text/unsub-bad",flagcd);
908 copybottom();
909 qmail_to(&qq,target.s);
910 }
911
912 } else if (str_start(action,ACTION_VC)) {
913 if (hashok(action,ACTION_VC)) {
914 r = getoff(action);
915 if (!r && flagmod)
916 logmsg(WHO,0,INFO,ERR_UNSUB_NOP);
917 mod_bottom();
918 if (r) { /* success to target */
919 qmail_to(&qq,target.s);
920 if (flagverbose > 1) to_owner();
921 } else /* NOP to sender = admin. Will take */
922 qmail_to(&qq,sender); /* care of it. No need to tell owner */
923 /* if list is moderated skip - otherwise bad with > 1 mod */
924 } else {
925 if (!pmod || !flagremote) /* else anyone can get a good -vc. */
926 die_cookie();
928 ezcopy(&qq,"text/unsub-bad",flagcd);
929 copybottom();
930 qmail_to(&qq,pmod);
931 }
932
933 } else if (act == AC_LIST || act == AC_LISTN) {
934
935 if (!flaglist || (!flagmod && !flagremote))
936 logmsg(WHO,100,FATAL,ERR_NOT_AVAILABLE);
937 if (!pmod)
938 logmsg(WHO,100,FATAL,ERR_NOT_ALLOWED);
941 ezcopy(&qq,"text/top",flagcd);
942
943 if (act == AC_LIST) {
945 i = putsubs(workdir,0L,52L,code_subto,1);
946 } else /* listn */
947 i = putsubs(workdir,0L,52L,dummy_to,1);
948
949 code_qput("\n ======> ",11);
950 code_qput(strnum,fmt_ulong(strnum,i));
951 code_qput("\n",1);
952 copybottom();
953 qmail_to(&qq,pmod);
954
955 } else if (act == AC_LOG) {
956 action += actlen;
957 if (*action == '.' || *action == '_') ++action;
958 if (!flaglist || !flagremote)
959 logmsg(WHO,100,FATAL,ERR_NOT_AVAILABLE);
960 if (!pmod)
961 logmsg(WHO,100,FATAL,ERR_NOT_ALLOWED);
965 copybottom();
966 qmail_to(&qq,pmod);
967
968 } else if (act == AC_EDIT) {
969 /* only remote admins and only if -e is specified may edit */
970 if (!flagedit || !flagremote)
971 logmsg(WHO,100,FATAL,ERR_NOT_AVAILABLE);
972 if (!pmod)
973 logmsg(WHO,100,FATAL,ERR_NOT_ALLOWED);
974 len = str_len(ACTION_EDIT);
975 if (!case_starts(action,ACTION_EDIT))
976 len = str_len(ALT_EDIT);
977 if (action[len]) { /* -edit.file, not just -edit */
978 if (action[len] != '.')
979 logmsg(WHO,100,FATAL,ERR_BAD_REQUEST);
980 if (!stralloc_copys(&fnedit,"text/")) die_nomem();
981 if (!stralloc_cats(&fnedit,action+len+1)) die_nomem();
982 if (!stralloc_0(&fnedit)) die_nomem();
983 case_lowerb(fnedit.s,fnedit.len);
984 i = 5; /* after the "text/" */
985 while ((ch = fnedit.s[i++])) {
986 if (((ch > 'z') || (ch < 'a')) && (ch != '_'))
987 logmsg(WHO,100,FATAL,ERR_BAD_NAME);
988 if (ch == '_') fnedit.s[i-1] = '-';
989 }
990 switch (openreadclose(fnedit.s,&text,1024)) { /* entire file! */
991 case -1:
992 logmsg(WHO,111,FATAL,B(ERR_READ,dir,"/",fnedit.s));
993 case 0:
994 logmsg(WHO,100,FATAL,B(dir,"/",fnedit.s,ERR_NOEXIST));
995 }
996 if (!stralloc_copy(&line,&text)) die_nomem();
997 { /* get rid of nulls to use cookie */
998 char *s;
999 unsigned int n;
1000 s = line.s; n = line.len;
1001 while(n--) { if (!*s) *s = '_'; ++s; }
1002 }
1003 if (!stralloc_cat(&line,&fnedit)) die_nomem(); /* including '\0' */
1004 strnum[fmt_ulong(strnum,(unsigned long) when)] = 0;
1005 cookie(hash,key.s,key.len,strnum,line.s,"-e");
1006 if (!stralloc_copy(&confirm,&outlocal)) die_nomem();
1007 if (!stralloc_append(&confirm,"-")) die_nomem();
1008 if (!stralloc_catb(&confirm,ACTION_ED,LENGTH_ED)) die_nomem();
1009 if (!stralloc_cats(&confirm,strnum)) die_nomem();
1010 if (!stralloc_append(&confirm,".")) die_nomem();
1011 /* action part has been checked for bad chars */
1012 if (!stralloc_cats(&confirm,action + len + 1)) die_nomem();
1013 if (!stralloc_append(&confirm,".")) die_nomem();
1014 if (!stralloc_catb(&confirm,hash,COOKIE)) die_nomem();
1015 if (!stralloc_append(&confirm,"@")) die_nomem();
1016 if (!stralloc_cat(&confirm,&outhost)) die_nomem();
1017 if (!stralloc_0(&confirm)) die_nomem();
1018 set_cpconfirm(confirm.s);
1019
1020 qmail_puts(&qq,"Reply-To: ");
1021 if (!quote2(&quoted,confirm.s)) die_nomem();
1022 qmail_put(&qq,quoted.s,quoted.len);
1023 qmail_puts(&qq,"\n");
1024
1027 ezcopy(&qq,"text/top",flagcd);
1028 ezcopy(&qq,"text/edit-do",flagcd);
1030 code_qput("\n",1);
1031 code_qput(text.s,text.len);
1033 code_qput("\n",1);
1034
1035 } else { /* -edit only, so output list of editable files */
1038 ezcopy(&qq,"text/top",flagcd);
1039 ezcopy(&qq,"text/edit-list",flagcd);
1040 }
1041 qmail_puts(&qq,"\n\n");
1042 copybottom();
1043 qmail_to(&qq,pmod);
1044
1045 } else if (str_start(action,ACTION_ED)) {
1046 datetime_sec u;
1047 int flaggoodfield;
1048 x = action + LENGTH_ED;
1049 x += scan_ulong(x,&u);
1050 if ((u > when) || (u < when - 100000)) die_cookie();
1051 if (*x == '.') ++x;
1052 fname = x;
1053 x += str_chr(x,'.');
1054 if (!*x) die_cookie();
1055 *x = (char) 0;
1056 ++x;
1057 if (!stralloc_copys(&fnedit,"text/")) die_nomem();
1058 if (!stralloc_cats(&fnedit,fname)) die_nomem();
1059 if (!stralloc_0(&fnedit)) die_nomem();
1060 y = fnedit.s + 5; /* after "text/" */
1061 while (*++y) { /* Name should be guaranteed by the cookie, */
1062 /* but better safe than sorry ... */
1063 if (((*y > 'z') || (*y < 'a')) && (*y != '_'))
1064 logmsg(WHO,100,FATAL,ERR_BAD_NAME);
1065 if (*y == '_') *y = '-';
1066 }
1067
1068 lock(); /* file must not change while here */
1069
1070 switch (openreadclose(fnedit.s,&text,1024)) {
1071 case -1:
1072 logmsg(WHO,111,FATAL,B(ERR_READ,dir,"/",fnedit.s));
1073 case 0:
1074 logmsg(WHO,100,FATAL,B(dir,"/",fnedit.s,ERR_NOEXIST));
1075 }
1076 if (!stralloc_copy(&line,&text)) die_nomem(); { /* get rid of nulls to use cookie */
1077 char *s;
1078 unsigned int n;
1079 s = line.s; n = line.len;
1080 while(n--) { if (!*s) *s = '_'; ++s; }
1081 }
1082 if (!stralloc_cat(&line,&fnedit)) die_nomem(); /* including '\0' */
1083 strnum[fmt_ulong(strnum,(unsigned long) u)] = 0;
1084 cookie(hash,key.s,key.len,strnum,line.s,"-e");
1085 if (str_len(x) != COOKIE) die_cookie();
1086 if (byte_diff(hash,COOKIE,x)) die_cookie();
1087 /* cookie is ok, file exists, lock's on, new file ends in '_' */
1088 if (!stralloc_copys(&fneditn,fnedit.s)) die_nomem();
1089 if (!stralloc_append(&fneditn,"_")) die_nomem();
1090 if (!stralloc_0(&fneditn)) die_nomem();
1091 fd = open_trunc(fneditn.s);
1092 if (fd == -1)
1093 logmsg(WHO,111,FATAL,B(ERR_WRITE,dir,"/",fneditn.s));
1094 buffer_init(&bt,buffer_unixwrite,fd,textbuf,sizeof(textbuf));
1095 if (!stralloc_copys(&quoted,"")) die_nomem(); /* clear */
1096 if (!stralloc_copys(&text,"")) die_nomem();
1097
1098 for (;;) { /* get message body */
1099 if (getln(&bi,&line,&match,'\n') == -1)
1100 logmsg(WHO,111,FATAL,ERR_READ_INPUT);
1101 if (!match) break;
1102 if (!stralloc_cat(&text,&line)) die_nomem();
1103 }
1104 if (encin) { /* decode if necessary */
1105 if (encin == 'B')
1106 decode_b64(text.s,text.len,&line);
1107 else
1108 decode_qp(text.s,text.len,&line);
1109 if (!stralloc_copy(&text,&line)) die_nomem();
1110 }
1111 cp = text.s;
1112 cpafter = text.s+text.len;
1113 flaggoodfield = 0;
1114 flagdone = 0;
1115 len = 0;
1116 while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) {
1117 i = byte_chr(cp,cpnext-cp,'%');
1118 if (i != (unsigned int) (cpnext - cp)) {
1119 if (!flaggoodfield) { /* TXT_EDIT_START/END */
1120 if (case_startb(cp+i,cpnext-cp-i,TXT_EDIT_START)) {
1121 /* start tag. Store users 'quote characters', e.g. '> ' */
1122 if (!stralloc_copyb(&quoted,cp,i)) die_nomem();
1123 flaggoodfield = 1;
1124 cp = cpnext + 1;
1125 cpfirst = cp;
1126 continue;
1127 }
1128 } else
1129 if (case_startb(cp+i,cpnext-cp-i,TXT_EDIT_END)) {
1130 flagdone = 1;
1131 break;
1132 }
1133 }
1134 if (flaggoodfield) {
1135 if ((len += cpnext - cp - quoted.len + 1) > MAXEDIT)
1136 logmsg(WHO,100,FATAL,ERR_EDSIZE);
1137
1138 if (quoted.len && cpnext-cp >= (int) quoted.len &&
1139 !str_diffn(cp,quoted.s,quoted.len))
1140 cp += quoted.len; /* skip quoting characters */
1141 cplast = cpnext - 1;
1142 if (*cplast == '\r') /* CRLF -> '\n' for base64 encoding */
1143 *cplast = '\n';
1144 else
1145 ++cplast;
1146 if (buffer_put(&bt,cp,cplast-cp+1) == -1)
1147 logmsg(WHO,111,FATAL,B(ERR_WRITE,dir,"/",fneditn.s));
1148 }
1149 cp = cpnext + 1;
1150 }
1151 if (!flagdone)
1152 logmsg(WHO,100,FATAL,ERR_NO_MARK);
1153 if (buffer_flush(&bt) == -1)
1154 logmsg(WHO,111,FATAL,B(ERR_WRITE,dir,"/",fneditn.s));
1155 if (fsync(fd) == -1)
1156 logmsg(WHO,111,FATAL,B(ERR_SYNC,dir,"/",fneditn.s));
1157 if (fchmod(fd, 0600) == -1)
1158 logmsg(WHO,111,FATAL,B(ERR_CHMOD,dir,"/",fneditn.s));
1159 if (close(fd) == -1)
1160 logmsg(WHO,111,FATAL,B(ERR_CLOSE,dir,"/",fneditn.s));
1161 if (rename(fneditn.s,fnedit.s) == -1)
1162 logmsg(WHO,111,FATAL,B(ERR_MOVE,dir,"/",fneditn.s));
1163
1164 unlock();
1167 ezcopy(&qq,"text/top",flagcd);
1168 ezcopy(&qq,"text/edit-done",flagcd);
1169 copybottom();
1170 qmail_to(&qq,sender); /* not necessarily from mod */
1171
1172 } else if (act == AC_GET) {
1173
1174 unsigned long u;
1175 struct stat st;
1176 char ch;
1177 int r;
1178 unsigned int pos;
1179
1180 if (!flagget)
1181 logmsg(WHO,100,FATAL,ERR_NOT_AVAILABLE);
1184 ezcopy(&qq,"text/top",flagcd);
1185
1186 pos = str_len(ACTION_GET);
1187 if (!case_starts(action,ACTION_GET))
1188 pos = str_len(ALT_GET);
1189
1190 if (action[pos] == '.' || action [pos] == '_') pos++;
1191 scan_ulong(action + pos,&u);
1192
1193 if (!stralloc_copys(&line,"archive/")) die_nomem();
1194 if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,u / 100))) die_nomem();
1195 if (!stralloc_cats(&line,"/")) die_nomem();
1196 if (!stralloc_catb(&line,strnum,fmt_uint0(strnum,(unsigned int) (u % 100),2))) die_nomem();
1197 if (!stralloc_0(&line)) die_nomem();
1198
1199 fd = open_read(line.s);
1200 if (fd == -1)
1201 if (errno != ENOENT)
1202 logmsg(WHO,111,FATAL,B(ERR_OPEN,line.s));
1203 else
1204 ezcopy(&qq,"text/get-bad",flagcd);
1205 else {
1206 if (fstat(fd,&st) == -1)
1207 ezcopy(&qq,"text/get-bad",flagcd);
1208 else if (!(st.st_mode & 0100))
1209 ezcopy(&qq,"text/get-bad",flagcd);
1210 else {
1211 buffer_init(&bt,buffer_unixread,fd,textbuf,sizeof(textbuf));
1212 qmail_puts(&qq,"> ");
1213 for (;;) {
1214 r = buffer_get(&bt,&ch,1);
1215 if (r == -1) logmsg(WHO,111,FATAL,B(ERR_READ,line.s));
1216 if (r == 0) break;
1217 qmail_put(&qq,&ch,1);
1218 if (ch == '\n') qmail_puts(&qq,"> ");
1219 }
1220 qmail_puts(&qq,"\n");
1221 }
1222 close(fd);
1223 }
1224 copybottom();
1225 qmail_to(&qq,target.s);
1226
1227 } else if (case_starts(action,ACTION_QUERY) || case_starts(action,ALT_QUERY)) {
1230 ezcopy(&qq,"text/top",flagcd);
1231 if (pmod) { /* pmod points to static storage in issub(). */
1232 /* Need to do this before calling issub() again */
1233 if (!stralloc_copys(&to,pmod)) die_nomem();
1234 if (!stralloc_0(&to)) die_nomem();
1235 } else {
1236 if (!stralloc_copy(&to,&target)) die_nomem();
1237 }
1238 if (issub(workdir,target.s,(char *) 0))
1239 ezcopy(&qq,"text/sub-nop",flagcd);
1240 else
1241 ezcopy(&qq,"text/unsub-nop",flagcd);
1242 copybottom();
1243 qmail_to(&qq,to.s);
1244
1245 } else if (case_starts(action,ACTION_INFO) || case_starts(action,ALT_INFO)) {
1248 ezcopy(&qq,"text/top",flagcd);
1249 ezcopy(&qq,"text/info",flagcd);
1250 copybottom();
1251 qmail_to(&qq,target.s);
1252
1253 } else if (case_starts(action,ACTION_FAQ) || case_starts(action,ALT_FAQ)) {
1256 ezcopy(&qq,"text/top",flagcd);
1257 ezcopy(&qq,"text/faq",flagcd);
1258 copybottom();
1259 qmail_to(&qq,target.s);
1260
1261 } else if (pmod && (act == AC_HELP)) {
1264 ezcopy(&qq,"text/top",flagcd);
1265 ezcopy(&qq,"text/mod-help",flagcd);
1266 ezcopy(&qq,"text/help",flagcd);
1267 copybottom();
1268 qmail_to(&qq,pmod);
1269
1270 } else {
1271 act = AC_HELP;
1274 ezcopy(&qq,"text/top",flagcd);
1275 ezcopy(&qq,"text/help",flagcd);
1276 copybottom();
1277 qmail_to(&qq,sender);
1278 }
1279
1280 if (*(err = qmail_close(&qq)) == '\0') {
1281 strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
1282 closesql();
1283 logmsg(WHO,0,INFO,B("qp ",strnum));
1284 } else {
1285 closesql();
1286 logmsg(WHO,111,FATAL,B(ERR_TMP_QMAIL_QUEUE,err + 1));
1287 }
1288
1289 return 0;
1290}
datetime_sec now(void)
Definition now.c:5
#define COOKIE
Definition cookie.h:4
#define TXT_EDIT_FOR
Definition idx.h:141
#define ALT_EDIT
Definition idx.h:46
#define TXT_WELCOME
Definition idx.h:118
#define ACTION_FAQ
Definition idx.h:206
#define ALT_SUBSCRIBE
Definition idx.h:54
#define TXT_DEF_CHARSET
Definition idx.h:93
#define FLD_DIGEST
Definition idx.h:308
#define TXT_EDIT_SUCCESS
Definition idx.h:151
#define TXT_FAQ_FOR
Definition idx.h:132
#define TXT_GET_MSG
Definition idx.h:129
#define ACTION_GET
Definition idx.h:186
#define ACTION_ALLOW
Definition idx.h:234
#define FLD_DENY
Definition idx.h:310
#define FLD_ALLOW
Definition idx.h:309
#define ACTION_VC
Definition idx.h:228
#define TXT_LISTMEMBERS
Definition idx.h:154
#define AC_EDIT
Definition idx.h:319
#define AC_UNSUBSCRIBE
Definition idx.h:323
#define ACTION_SUBSCRIBE
Definition idx.h:208
#define ACTION_LIST
Definition idx.h:202
#define AC_LOG
Definition idx.h:321
#define TXT_SUB_LIST
Definition idx.h:126
#define ACTION_TC
Definition idx.h:224
#define TXT_SUPPRESSED
Definition idx.h:85
#define ALT_GET
Definition idx.h:48
#define TXT_STATUS
Definition idx.h:130
#define LENGTH_ED
Definition idx.h:214
#define ACTION_LOG
Definition idx.h:207
#define ALT_UNSUBSCRIBE
Definition idx.h:56
#define TXT_UNSUBSCRIBE_FROM
Definition idx.h:115
#define AC_HELP
Definition idx.h:318
#define MAXEDIT
Definition idx.h:25
#define AC_NONE
Definition idx.h:312
#define ALT_QUERY
Definition idx.h:57
#define AC_LISTN
Definition idx.h:325
#define ALT_HELP
Definition idx.h:49
#define TXT_HELP_FOR
Definition idx.h:134
#define ACTION_HELP
Definition idx.h:204
#define AC_LIST
Definition idx.h:317
#define ACTION_DENY
Definition idx.h:236
#define TXT_EDIT_START
Definition idx.h:148
#define AC_SUBSCRIBE
Definition idx.h:322
#define ACTION_ED
Definition idx.h:213
#define ALT_LISTN
Definition idx.h:45
#define TXT_SUB_NOP
Definition idx.h:124
#define ACTION_INFO
Definition idx.h:205
#define TXT_EDIT_END
Definition idx.h:149
#define AC_GET
Definition idx.h:313
#define ACTION_UC
Definition idx.h:226
#define ACTION_EDIT
Definition idx.h:211
#define ALT_FAQ
Definition idx.h:47
#define TXT_MODCONFIRM
Definition idx.h:113
#define ACTION_LISTN
Definition idx.h:203
#define AC_SC
Definition idx.h:324
#define ACTION_QUERY
Definition idx.h:210
#define TXT_EDIT_RESPONSE
Definition idx.h:140
#define ACTION_SC
Definition idx.h:222
#define TXT_INFO_FOR
Definition idx.h:131
#define TXT_GOODBYE
Definition idx.h:121
#define TXT_SUBSCRIBE_TO
Definition idx.h:114
#define TXT_MOD_HELP
Definition idx.h:133
#define ALT_INFO
Definition idx.h:51
#define TXT_UNSUB_NOP
Definition idx.h:125
#define ALT_LOG
Definition idx.h:52
#define TXT_EDIT_LIST
Definition idx.h:144
#define TXT_SUB_LOG
Definition idx.h:127
#define TXT_USRCONFIRM
Definition idx.h:112
#define ALT_LIST
Definition idx.h:44
#define TXT_SUB_LOG_SEARCH
Definition idx.h:128
#define ACTION_UNSUBSCRIBE
Definition idx.h:209
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 hdr_listsubject1(a)
Definition hdr.h:27
@ CTYPE_TEXT
Definition hdr.h:13
@ CTYPE_MULTIPART
Definition hdr.h:14
@ CTYPE_MESSAGE
Definition hdr.h:16
#define hdr_listsubject2(a, b)
Definition hdr.h:28
Error messages. If you translate these, I would urge you to keep the English version as well....
#define ERR_NOMEM
Definition errtxt.h:14
#define ERR_SYNC
Definition errtxt.h:22
#define ERR_OPEN
Definition errtxt.h:30
#define ERR_MOVE
Definition errtxt.h:29
#define ERR_BAD_REQUEST
Definition errtxt.h:52
#define ERR_NOEXIST
Definition errtxt.h:40
#define ERR_EDSIZE
Definition errtxt.h:92
#define ERR_UNSUB_NOP
Definition errtxt.h:89
#define ERR_ANONYMOUS
Definition errtxt.h:44
#define ERR_READ_INPUT
Definition errtxt.h:26
#define ERR_NOT_ALLOWED
Definition errtxt.h:49
#define ERR_MAILING_LIST
Definition errtxt.h:57
#define ERR_BAD_NAME
Definition errtxt.h:90
#define ERR_NO_MARK
Definition errtxt.h:91
#define ERR_READ
Definition errtxt.h:18
#define ERR_LOOPING
Definition errtxt.h:58
#define ERR_EXTRA_UNSUB
Definition errtxt.h:95
#define ERR_CHMOD
Definition errtxt.h:23
#define ERR_BAD_ADDRESS
Definition errtxt.h:50
#define ERR_QMAIL_QUEUE
Definition errtxt.h:53
#define ERR_NODEFAULT
Definition errtxt.h:35
#define ERR_NOT_AVAILABLE
Definition errtxt.h:48
#define ERR_SUB_NOP
Definition errtxt.h:88
#define ERR_SWITCH
Definition errtxt.h:42
#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_MOD_COOKIE
Definition errtxt.h:102
#define ERR_EXTRA_SUB
Definition errtxt.h:94
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
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
int subscribe(const char *dir, const char *username, int flagadd, const char *from, const char *event, int flagmysql, int forcehash, const char *table_override)
Definition subscribe.c:76
void searchlog(const char *dir, char *search, int subwrite())
Definition searchlog.c:60
void die_nomem()
Definition getconf.c:17
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_cpverptarget(const char *tg)
Definition ezcopy.c:84
void set_cptarget(const char *tg)
Definition ezcopy.c:79
void set_cpouthost(const stralloc *ln)
Definition ezcopy.c:73
void set_cpconfirm(const char *cf)
Definition ezcopy.c:89
#define WHO
Definition author.c:1
void encode_qp(const char *indata, unsigned int n, stralloc *outdata)
Definition encode_qp.c:21
int flagbottom
Definition ezmlm-get.c:51
stralloc mydtline
Definition ezmlm-get.c:72
int act
Definition ezmlm-get.c:119
int flagpublic
Definition ezmlm-get.c:52
int subto(char *s, unsigned int l)
Definition ezmlm-get.c:141
char * workdir
Definition ezmlm-get.c:129
stralloc moddir
Definition ezmlm-get.c:71
buffer bj
Definition ezmlm-get.c:154
stralloc ddir
Definition ezmlm-get.c:116
unsigned long max
Definition ezmlm-get.c:83
void hdr_listsubject3(const char *a, const char *b, const char *c)
void hdr_from(const char *append)
Definition hdr_from.c:23
char inbuf[1024]
char * dir
buffer bi
int flagunsubismod
void to_owner()
int flagsubconf
char frombuf[512]
int flagunsubconf
char * get_from(char *adr, char *act)
void doconfirm(char *act)
int flagstorefrom
int flagdig
void copybottom()
void msg_headers()
Writes all the headers up to but not including subject.
stralloc modsub
stralloc fnedit
char urlstr[]
int subto(char *s, unsigned int l)
stralloc remote
int geton(char *action)
stralloc text
void mod_bottom()
int flagget
ssize_t qqwrite(int fd, char *buf, unsigned int len)
stralloc fneditn
void unlock()
char encin
void sendtomods()
unsigned int actlen
stralloc from
void lock()
int hashok(char *action, char *ac)
int flagedit
int getoff(char *action)
int dummy_to(char *s, unsigned int l)
buffer bf
int flagnotify
int code_subto(char *s, unsigned int l)
void store_from(stralloc *frl, char *adr)
stralloc fromline
void make_verptarget()
puts target with '=' instead of last '@' into stralloc verptarget and does set_cpverptarget
int flagverbose
stralloc owner
int code_qput(char *s, unsigned int n)
int main()
Definition ezmlm-weed.c:69
void decode_b64(const char *cpfrom, unsigned int n, stralloc *outdata)
Definition decode_b64.c:33
void hdr_boundary(int last)
void hdr_datemsgid(unsigned long when)
void cookie(char *hash, const char *key, unsigned int keylen, const char *date, const char *addr, const char *action)
Definition cookie.c:14
int opt
Definition ezmlm-cron.c:53
const char * cp
Definition ezmlm-cron.c:76
int fdin
Definition ezmlm-cron.c:71
int flaglist
Definition ezmlm-cron.c:61
int fdout
Definition ezmlm-cron.c:71
unsigned int len
Definition ezmlm-cron.c:68
int fdlock
Definition ezmlm-cron.c:71
const char * pmod
Definition ezmlm-gate.c:42
char buf[256]
Definition install.c:113
stralloc fname
Definition ezmlm-cgi.c:124
int fd
Definition ezmlm-cgi.c:141
datetime_sec when
Definition ezmlm-cgi.c:173
const char * charset
Definition ezmlm-cgi.c:110
int match
Definition ezmlm-cgi.c:140
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
datetime_sec hashdate
Definition ezmlm-clean.c:85
stralloc to
Definition ezmlm-clean.c:97
struct qmail qq
Definition ezmlm-clean.c:73
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 hdr_ctboundary(void)
int flagmod
Definition ezmlm-limit.c:33
void encode_b64(const unsigned char *indata, unsigned int n, stralloc *outdata, int control)
Definition encode_b64.c:75
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
void decode_qp(const char *cpfrom, unsigned int n, stralloc *outdata)
Definition decode_qp.c:35
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