1 /*$Id: ezmlm-request.c,v 1.34 1999/08/18 01:50:04 lindberg Exp $*/
2 /*$Name: ezmlm-idx-040 $*/
15 #include "date822fmt.h"
18 #include "readwrite.h"
31 #define FATAL "ezmlm-request: fatal: "
32 #define INFO "ezmlm-request: info: "
36 strerr_die1x(100,"ezmlm-request: usage: ezmlm-request [-f lists.cfg] dir");
41 strerr_die2x(111,FATAL,ERR_NOMEM);
46 strerr_die2x(100,FATAL,ERR_BAD_ADDRESS);
49 char strnum[FMT_ULONG];
51 void *psql = (void *) 0;
53 char *userlocal = (char *) 0;
54 char *userhost = (char *) 0;
55 char *listlocal = (char *) 0;
56 char *listhost = (char *) 0;
57 char *cfname = (char *) 0;
58 char *command = "help";
63 stralloc subject = {0};
64 stralloc inlocal = {0};
65 stralloc outlocal = {0};
66 stralloc listname = {0};
67 stralloc hostname = {0};
68 stralloc outhost = {0};
69 stralloc headerremove = {0};
70 stralloc mailinglist = {0};
74 stralloc charset = {0};
75 char *boundary = "zxcaeedrqcrtrvthbdty"; /* cheap "rnd" MIME boundary */
76 int flagcd = '\0'; /* no encoding by default */
78 struct constmap headerremovemap;
79 struct constmap commandmap;
80 int flaggotsub = 0; /* Found a subject */
81 /* cmdstring has all commands seperated by '\'. cmdxlate maps each */
82 /* command alias to the basic command, which is used to construct */
83 /* the command address (positive numbers) or handled by this */
84 /* program (negative numbers). Note: Any command not matched is */
85 /* used to make a command address, so ezmlm request can handle */
86 /* ("transmit") user-added commands. */
87 const char *cmdstring =
88 "system\\help\\" /* 1,2 */
89 "subscribe\\unsubscribe\\index\\" /* 3,4,5 */
90 "info\\list\\query\\" /* 6,7,8 */
91 "sub\\unsub\\remove\\signoff\\" /* 9,10,11,12 */
92 "lists\\which\\" /* 13,14 */
93 "ind\\rev\\review\\recipients\\" /* 15,16,17,18 */
94 "who\\showdist\\" /* 19,20 */
95 "put\\set"; /* 21,22 */
97 /* map aliases. -> 0 not recognized. -> 1 recognized will be made */
98 /* help and arguments scrapped. < 0 handled locally. HELP without */
99 /* args also handled locally */
100 /* the last are not supported -> help */
101 const int cmdxlate[] = { 0,1,2,3,4,5,6,7,8,3,4,4,4,-13,-14,5,7,7,7,7,7,
104 /* If there are no arguments (listlocal = 0) then commands are mapped*/
105 /* through this. This way, help, list, query, ... can mean something */
106 /* here even though they have local funcions at the lists if used */
107 /* with arguments. (Made same lengh as cmdxlate in case of bugs.) */
108 /* Note: This is used ONLY for the global interface */
109 const int noargsxlate[] = { 0,1,-2,3,4,5,-2,-13,-14,9,10,11,12,13,14,15,16,17,
112 /* these need to be defined as the index of the corresponding */
113 /* commands. They are handled by ezmlm-request. NOTE: Help is >0! */
114 #define EZREQ_LISTS 13
115 #define EZREQ_WHICH 14
123 char date[DATE822FMT];
127 int qqwrite(fd,buf,len) int fd; char *buf; unsigned int len;
129 qmail_put(&qq,buf,len);
134 substdio ssqq = SUBSTDIO_FDBUF(qqwrite,-1,qqbuf,(int) sizeof(qqbuf));
137 substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf));
138 substdio ssin2 = SUBSTDIO_FDBUF(read,0,inbuf,(int) sizeof(inbuf));
143 stralloc mydtline = {0};
148 qmail_puts(&qq,"\n--");
149 qmail_puts(&qq,boundary);
150 qmail_puts(&qq,"\nContent-Type: text/plain; charset=");
151 qmail_puts(&qq,charset.s);
152 qmail_puts(&qq,"\nContent-Transfer-Encoding: ");
154 qmail_puts(&qq,"quoted-printable\n\n");
156 qmail_puts(&qq,"base64\n\n");
168 encodeB(s,n,&qline,0,FATAL);
170 encodeQ(s,n,&qline,FATAL);
171 qmail_put(&qq,qline.s,qline.len);
173 return 0; /* always succeeds */
176 /* Checks the argument. Only us-ascii letters, numbers, ".+-_" are ok. */
177 /* NOTE: For addresses this is more restrictive than rfc821/822. */
184 if (!cp) return; /* undef is ok */
185 while ((ch = *cp++)) {
186 if (ch >= 'a' && ch <= 'z')
187 continue; /* lc letters */
188 if (ch >= '0' && ch <='9') /* digits */
190 if (ch == '.' || ch == '-' || ch == '_' || ch == '+')
191 continue; /* ok chars */
192 if (ch >= 'A' && ch <= 'Z') continue; /* UC LETTERS */
193 strerr_die4x(100,ERR_NOT_CLEAN,": \"",s,"\"");
198 /* parses line poited to by cp into sz:s as per: */
199 /* 1. listlocal-command-userlocal=userhost@listhost */
200 /* 2. command userlocal@userhost */
201 /* 3. command userlocal@userhost listlocal@listhost */
202 /* 4. command listlocal@listhost */
203 /* 5. command listlocal[@listhost] userlocal@userhost */
204 /* 6. which [userlocal@userhost] */
205 /* The first 3 are valid only if !cfname, i.e. -request operation and */
206 /* listlocal and listhost are always set to outlocal@outhost. Options */
207 /* 4-5 are for the global address (cfname is set). Here listhost is */
208 /* taken from the first list in *cfname matching listlocal, or set to */
209 /* outhost, if not specified. If specified, it's accepted if it matches */
210 /* a list in *cfname and silently set to outhost otherwise. Pointers to */
211 /* unspecified parts are set to NULL in this routine to be dealt with */
212 /* elsewhere. "Which" special argument order (6) is fixed elsewhere. */
213 /* If listhost is not given, "@outhost" is added. Absence of 'userhost' */
214 /* is accepted to allow commands that take arguments that are not */
215 /* addresses (e.g. -get12-34). */
221 register char *cp1, *cp2;
225 while (*cp1) { /* make tabs into spaces */
226 if (*cp1 == '\t') *cp1 = ' ';
229 /* NOTE: outlocal has '\0' added! */
230 if (outlocal.len < str_len(cp) && cp[outlocal.len -1] == '-' &&
231 case_starts(cp,outlocal.s)) { /* normal ezmlm cmd */
232 command = cp + outlocal.len; /* after the '-' */
233 listlocal = outlocal.s;
234 listhost = outhost.s;
236 while (*cp1 && *cp1 != '-') ++cp1; /* find next '-' */
239 userlocal = ++cp1; /* after '-' */
240 cp1 = cp1 + str_rchr(cp1,'@'); /* @ _or_ end */
241 *cp1 = '\0'; /* last '=' in userlocal */
242 cp1 = userlocal + str_rchr(userlocal,'=');
243 if (*cp1) { /* found '=' */
244 *cp1 = '\0'; /* zap */
245 userhost = cp1 + 1; /* char after '=' */
248 } else { /* '@' before ' ' means complete cmd */
249 if (str_chr(cp,'@') < str_chr(cp,' ')) /* addr where inlocal failed */
250 strerr_die2x(100,FATAL,ERR_REQ_LOCAL);
253 cp1 = cp + str_chr(cp,' ');
256 while (*cp1 && *cp1 == ' ') ++cp1; /* skip spaces */
259 if (*cp1) { /* argument */
260 cp2 = cp1 + str_chr(cp1,' ');
262 while (*cp2 && *cp2 == ' ') ++cp2; /* skip spaces */
268 cp3 = cp2 + str_chr(cp2,' ');
274 if (!cfname && !cp2) { /* the single arg is user if we serve a */
275 cp2 = cp1; /* list. It's list if we serve "domo@" */
280 cp2 += str_chr(cp2,'@');
288 cp1 += str_chr(cp1,'@');
295 checkarg(command); /* better safe than sorry */
296 checkarg(userlocal); checkarg(userhost);
297 checkarg(listlocal); checkarg(listhost);
318 int flagmultipart = 0;
321 unsigned int pos,pos1,len,last;
326 while ((opt = getopt(argc,argv,"f:F:vV")) != opteof)
329 case 'f': if (optarg) cfname = optarg; break;
331 case 'V': strerr_die2x(0,"ezmlm-request version: ",EZIDX_VERSION);
337 if (!dir) die_usage();
339 if (chdir(dir) == -1)
340 strerr_die4sys(111,FATAL,ERR_SWITCH,dir,": ");
342 /* do minimum to identify request for this program in case */
343 /* it's invoked in line with e.g. ezmlm-manage */
345 def = env_get("DEFAULT");
346 if (def) { /* qmail>=1.02 */
348 } else if (cfname) { /* older qmail OR just list-mdomo */
349 local = env_get("LOCAL");
350 if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
351 len = str_len(local);
352 if (len >= 8 && !case_diffb(local + len - 8,8,"-return-")) {
353 action = "return-"; /* our bounce with qmail<1.02 */
355 action = ""; /* list-mdomo-xxx won't work for older lists */
356 } else { /* older qmail versions */
357 local = env_get("LOCAL");
358 if (!local) strerr_die2x(100,FATAL,ERR_NOLOCAL);
359 getconf_line(&inlocal,"inlocal",1,FATAL,dir);
360 if (inlocal.len > str_len(local)) die_badaddr();
361 if (case_diffb(inlocal.s,inlocal.len,local)) die_badaddr();
362 action = local + inlocal.len;
364 if (*(action++) != '-') die_badaddr(); /* check anyway */
366 /* at this point action = "request" or "request-..." for std use; */
367 /* "" for majordomo@ */
368 if (!cfname) { /* expect request */
369 if (case_starts(action,ACTION_REQUEST))
370 action += str_len(ACTION_REQUEST);
371 else if (case_starts(action,ALT_REQUEST))
372 action += str_len(ALT_REQUEST);
374 _exit(0); /* not for us */
376 getconf_line(&outlocal,"outlocal",1,FATAL,dir);
377 getconf_line(&outhost,"outhost",1,FATAL,dir);
379 if (!stralloc_copy(&listname,&outlocal)) die_nomem();
380 if (!stralloc_copy(&hostname,&outhost)) die_nomem();
381 if (!stralloc_0(&outlocal)) die_nomem();
382 if (!stralloc_0(&outhost)) die_nomem();
384 sender = env_get("SENDER");
385 if (!sender) strerr_die2x(99,INFO,ERR_NOSENDER);
387 strerr_die2x(99,INFO,ERR_BOUNCE);
388 if (!sender[str_chr(sender,'@')])
389 strerr_die2x(99,INFO,ERR_ANONYMOUS);
390 if (str_equal(sender,"#@[]"))
391 strerr_die2x(99,INFO,ERR_BOUNCE);
393 getconf(&headerremove,"headerremove",1,FATAL,dir);
394 constmap_init(&headerremovemap,headerremove.s,headerremove.len,0);
396 if (!stralloc_copys(&mydtline,
397 "Delivered-To: request processor for ")) die_nomem();
398 if (!stralloc_cats(&mydtline,outlocal.s)) die_nomem();
399 if (!stralloc_cats(&mydtline,"@")) die_nomem();
400 if (!stralloc_cats(&mydtline,outhost.s)) die_nomem();
401 if (!stralloc_cats(&mydtline,"\n")) die_nomem();
404 if (action[0]) { /* mainly to allow ezmlm-lists or ezmlm-which with */
405 flagnosubject = 0; /* a command address rather than a complete msg */
407 if (str_start(action,"return")) /* kill bounces */
408 strerr_die2x(0,INFO,ERR_BOUNCE);
409 pos = 1 + str_chr(action + 1,'-');
410 if (action[pos]) { /* start of target */
412 userlocal = action + pos + 1;
413 pos = str_rchr(userlocal,'='); /* the "pseudo-@" */
414 if (userlocal[pos]) {
415 userlocal[pos] = '\0';
416 userhost = userlocal + pos + 1;
420 for (;;) { /* Get Subject: */
421 if (getln(&ssin,&line,&match,'\n') == -1)
422 strerr_die2sys(111,FATAL,ERR_READ_INPUT);
425 if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
428 if (case_startb(line.s,line.len,"mailing-list:"))
429 strerr_die2x(100,FATAL,ERR_MAILING_LIST);
430 else if (case_startb(line.s,line.len,"Subject:")) {
433 last = line.len - 2; /* skip terminal '\n' */
434 while (line.s[last] == ' ' || line.s[last] == '\t') --last;
435 while (pos <= last &&
436 (line.s[pos] == ' ' || line.s[pos] == '\t')) ++pos;
437 if (!stralloc_copyb(&subject,line.s+pos,last-pos+1)) die_nomem();
438 } else if (case_startb(line.s,line.len,"content-type:")) {
439 pos = 13; last = line.len - 2; /* not cont-line - ok */
440 while (pos <= last &&
441 (line.s[pos] == ' ' || line.s[pos] == '\t')) ++pos;
442 if (case_startb(line.s+pos,line.len - pos,"multipart/"))
444 } else if (line.len == mydtline.len)
445 if (!byte_diff(line.s,line.len,mydtline.s))
446 strerr_die2x(100,FATAL,ERR_LOOPING);
447 } else if (flagsub) { /* Continuation line */
449 len = line.len - 2; /* skip terminal '\n' */
450 while (line.s[len] == ' ' || line.s[len] == '\t') --len;
452 (line.s[pos] == ' ' || line.s[pos] == '\t')) ++pos;
453 if (!stralloc_append(&subject," ")) die_nomem();
454 if (!stralloc_copy(&subject,line.s+pos,len-pos+1)) die_nomem();
459 if (!cfname) { /* listserv@/majordomo@ ignore */
461 if (!stralloc_0(&subject)) die_nomem();
462 ch = *subject.s; /* valid commands/list names start w letter */
463 if ((ch <= 'z' && ch >= 'a') || (ch <= 'Z' && ch >= 'A')) {
464 parseline(subject.s);
468 if (cfname || flagnosubject) {
469 for (;;) { /* parse body */
470 if (getln(&ssin,&line,&match,'\n') == -1)
471 strerr_die2sys(111,FATAL,ERR_READ_INPUT);
473 if (line.len == 1 && flagmultipart != 2) continue;
474 /* lazy MIME cludge assumes first '--...' is start border */
475 /* which is virtually always true */
476 if (flagmultipart == 1) { /* skip to first border */
477 if (*line.s != '-' || line.s[1] != '-') continue;
480 } else if (flagmultipart == 2) { /* skip content info */
481 if (line.len != 1) continue;
482 flagmultipart = 3; /* may be part within part */
483 continue; /* and blank line */
484 } else if (flagmultipart == 3) {
485 if (*line.s == '-' && line.s[1] == '-') {
486 flagmultipart = 2; /* part within part */
494 !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')))
495 continue; /* skip if not letter pos 1 */
497 /* Here we have a body line with something */
498 if (!stralloc_copy(&subject,&line)) die_nomem(); /* save it */
499 subject.s[subject.len-1] = '\0';
500 parseline(subject.s);
505 /* Do command substitution */
506 if (!stralloc_copys(&cmds,cmdstring)) die_nomem();
507 if (!stralloc_0(&cmds)) die_nomem();
510 if (*psz == '\\') *psz = '\0';
513 if (!constmap_init(&commandmap,cmds.s,cmds.len,0)) die_nomem();
514 cmdidx = cmdxlate[constmap_index(&commandmap,command,str_len(command))];
515 if (cmdidx == EZREQ_BAD) { /* recognized, but not supported -> help */
516 listlocal = 0; /* needed 'cause arguments are who-knows-what */
522 if (cfname && !listlocal && !userlocal && cmdidx > 0)
523 cmdidx = noargsxlate[cmdidx]; /* some done differently if no args */
525 /* =0 not found. This is treated as a list command! */
526 if (cmdidx < 0 && !cfname) {
529 if (qmail_open(&qq,(stralloc *) 0) == -1)
530 strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
533 /* Things handled elsewhere. We do want to handle a simple HELP */
534 /* without arguments for e.g. majordomo@ from our own help file */
536 if (!stralloc_copys(&from,sender)) die_nomem();
537 if (!stralloc_0(&from)) die_nomem();
540 strerr_die1x(100,ERR_REQ_LISTNAME);
542 listlocal = outlocal.s; /* This is at the -request address */
544 /* if !cfname listhost is made outhost. If cfname, listhost=outhost */
545 /* is ok. listhost=0 => first match in config. Other listhost is ok */
546 /* only if match is found. Otherwise it's set to outhost. */
548 if (!cfname || (listhost && !case_diffs(listhost,outhost.s)))
549 listhost = outhost.s;
550 else { /* Check listhost against config file */
551 pos = str_len(listlocal);
552 fd = open_read(cfname);
554 strerr_die4sys(111,FATAL,ERR_OPEN,cfname,": ");
555 substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
556 flagok = 0; /* got listhost match */
558 if (getln(&sstext,&line,&match,'\n') == -1)
559 strerr_die3sys(111,FATAL,ERR_READ,cfname);
562 if (line.len <= 1 || line.s[0] == '#')
564 if ((pos < line.len) && (line.s[pos] == '@') &&
565 !byte_diff(line.s,pos,listlocal)) {
566 last = byte_chr(line.s,line.len,':');
567 if (!stralloc_copyb(&lhost,line.s+pos+1,last-pos-1)) die_nomem();
568 if (!stralloc_0(&lhost)) die_nomem();
570 if (!case_diffs(listhost,lhost.s)) {
572 break; /* host did match */
574 continue; /* host didn't match */
575 } else { /* none given - grab first */
583 listhost = outhost.s;
587 listhost = outhost.s;
589 if (!stralloc_copys(&usr,sender)) die_nomem();
590 if (!stralloc_0(&usr)) die_nomem();
592 userhost = usr.s + byte_rchr(usr.s,usr.len-1,'@');
601 if (!stralloc_copys(&to,listlocal)) die_nomem();
602 if (!stralloc_cats(&to,"-")) die_nomem();
603 if (cmdidx) { /* recognized - substitute */
604 if (!stralloc_cats(&to,constmap_get(&commandmap,cmdidx)))
606 } else /* not recognized - use as is */
607 if (!stralloc_cats(&to,command)) die_nomem();
609 if (!stralloc_cats(&to,"-")) die_nomem();
610 if (!stralloc_cats(&to,userlocal)) die_nomem();
611 if (userhost) { /* doesn't exist for e.g. -get */
612 if (!stralloc_cats(&to,"=")) die_nomem();
613 if (!stralloc_cats(&to,userhost)) die_nomem();
615 if (!stralloc_cats(&to,"@")) die_nomem();
616 if (!stralloc_cats(&to,listhost)) die_nomem();
617 if (!stralloc_0(&to)) die_nomem();
619 qmail_put(&qq,mydtline.s,mydtline.len);
624 if (seek_begin(0) == -1)
625 strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);
626 substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
629 if (getln(&ssin,&line,&match,'\n') == -1)
630 strerr_die2sys(111,FATAL,ERR_READ_INPUT);
632 if (flaginheader && match) {
635 if ((line.s[0] != ' ') && (line.s[0] != '\t')) {
637 if (constmap(&headerremovemap,line.s,byte_chr(line.s,line.len,':')))
641 if (!(flaginheader && flagbadfield))
642 qmail_put(&qq,line.s,line.len);
646 } else { /* commands we deal with */
647 cmdidx = - cmdidx; /* now positive */
648 if (cmdidx == EZREQ_WHICH) { /* arg is user, not list */
649 userlocal = listlocal; listlocal = 0;
650 userhost = listhost; listhost = 0;
652 if (!stralloc_copys(&from,outlocal.s)) die_nomem();
653 if (!stralloc_cats(&from,"-return-@")) die_nomem();
654 if (!stralloc_cats(&from,outhost.s)) die_nomem();
655 if (!stralloc_0(&from)) die_nomem();
658 if (!stralloc_copys(&to,userlocal)) die_nomem();
659 if (!stralloc_cats(&to,"@")) die_nomem();
661 if (!stralloc_cats(&to,userhost)) die_nomem();
663 if (!stralloc_cats(&to,outhost.s)) die_nomem();
666 if (!stralloc_copys(&to,sender)) die_nomem();
667 if (!stralloc_0(&to)) die_nomem();
669 /* now we need to look for charset and set flagcd appropriately */
671 if (getconf_line(&charset,"charset",0,FATAL,dir)) {
672 if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
673 if (charset.s[charset.len - 1] == 'B' ||
674 charset.s[charset.len - 1] == 'Q') {
675 flagcd = charset.s[charset.len - 1];
676 charset.s[charset.len - 2] = '\0';
680 if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
681 if (!stralloc_0(&charset)) die_nomem();
682 set_cpoutlocal(&listname); /* necessary in case there are <#l#> */
683 set_cpouthost(&hostname); /* necessary in case there are <#h#> */
684 /* we don't want to be send to a list*/
685 qmail_puts(&qq,"Mailing-List: ezmlm-request");
686 if (getconf(&line,"listid",0,FATAL)) {
687 qmail_puts(&qq,"List-ID: ");
688 qmail_put(&qq,line.s,line.len);
690 qmail_puts(&qq,"\nDate: ");
692 datetime_tai(&dt,when);
693 qmail_put(&qq,date,date822fmt(date,&dt));
694 qmail_puts(&qq,"Message-ID: <");
695 if (!stralloc_copyb(&line,strnum,fmt_ulong(strnum,(unsigned long) when)))
697 if (!stralloc_append(&line,".")) die_nomem();
698 if (!stralloc_catb(&line,strnum,
699 fmt_ulong(strnum,(unsigned long) getpid()))) die_nomem();
700 if (!stralloc_cats(&line,".ezmlm@")) die_nomem();
701 if (!stralloc_cats(&line,outhost.s)) die_nomem();
702 if (!stralloc_0(&line)) die_nomem();
703 qmail_puts(&qq,line.s);
704 qmail_puts(&qq,">\nFrom: ");
705 if (!quote2(&line,outlocal.s)) die_nomem();
706 qmail_put(&qq,line.s,line.len);
707 if (cmdidx == EZREQ_HELP)
708 qmail_puts(&qq,"-return-@");
710 qmail_puts(&qq,"-help@");
711 qmail_puts(&qq,outhost.s);
712 qmail_puts(&qq,"\n");
713 qmail_put(&qq,mydtline.s,mydtline.len);
714 qmail_puts(&qq,"To: ");
715 if (!quote2(&line,to.s)) die_nomem();
716 qmail_put(&qq,line.s,line.len);
717 qmail_puts(&qq,"\n");
718 qmail_puts(&qq,"MIME-Version: 1.0\n");
720 qmail_puts(&qq,"Content-Type: multipart/mixed; charset=");
721 qmail_puts(&qq,charset.s);
722 qmail_puts(&qq,";\n\tboundary=");
723 qmail_puts(&qq,boundary);
725 qmail_puts(&qq,"Content-type: text/plain; charset=");
726 qmail_puts(&qq,charset.s);
728 qmail_puts(&qq,"\nSubject: ");
729 if (!quote2(&line,outlocal.s)) die_nomem();
730 qmail_put(&qq,line.s,line.len);
731 qmail_puts(&qq,TXT_RESULTS);
733 copy(&qq,"text/top",flagcd,FATAL);
734 if (cmdidx == EZREQ_LISTS || cmdidx == EZREQ_WHICH) {
737 code_qput("LISTS:",6);
740 code_qput("WHICH (",7);
741 code_qput(to.s,to.len - 1);
742 code_qput("):\n\n",4);
746 fd = open_read(cfname);
748 strerr_die4sys(111,FATAL,ERR_OPEN,cfname,": ");
749 substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
751 if (getln(&sstext,&line,&match,'\n') == -1)
752 strerr_die3sys(111,FATAL,ERR_READ,cfname);
755 if (line.len <= 1 || line.s[0] == '#')
757 if (!stralloc_0(&line)) die_nomem();
758 pos = str_chr(line.s,':');
763 pos1 = pos + str_chr(line.s + pos,':');
772 code_qput("\n\n\t",3);
773 code_qput(line.s,pos-1);
776 code_qput(line.s+pos1,line.len-2-pos1);
780 if (issub(line.s+pos,to.s,(char *) 0,FATAL)) {
781 code_qput(line.s,pos-1);
784 closesql(); /* likely different dbs for different lists */
791 copy(&qq,"text/help",flagcd,FATAL);
793 copy(&qq,"text/bottom",flagcd,FATAL);
796 encodeB("",0,&line,2,FATAL); /* flush */
797 qmail_put(&qq,line.s,line.len);
799 qmail_puts(&qq,"\n--");
800 qmail_puts(&qq,boundary);
801 qmail_puts(&qq,"\nContent-Type: message/rfc822");
803 "\nContent-Disposition: inline; filename=request.msg\n\n");
805 qmail_puts(&qq,"Return-Path: <");
806 if (!quote2(&line,sender)) die_nomem();
807 qmail_put(&qq,line.s,line.len);
808 qmail_puts(&qq,">\n");
809 if (seek_begin(0) == -1)
810 strerr_die2sys(111,FATAL,ERR_SEEK_INPUT);
811 if (substdio_copy(&ssqq,&ssin2) != 0)
812 strerr_die2sys(111,FATAL,ERR_READ_INPUT);
814 qmail_puts(&qq,"\n--");
815 qmail_puts(&qq,boundary);
816 qmail_puts(&qq,"--\n");
819 qmail_from(&qq,from.s);
821 if (*(err = qmail_close(&qq)) != '\0')
822 strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);
824 strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
825 strerr_die3x(99,INFO, "qp ",strnum);