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
);