s/qmail 4.3.23
Next generation secure email transport
Loading...
Searching...
No Matches
qmail-local.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/time.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <unistd.h>
6#include "sig.h"
7#include "env.h"
8#include "byte.h"
9#include "exit.h"
10#include "open.h"
11#include "wait.h"
12#include "lock.h"
13#include "seek.h"
14#include "buffer.h"
15#include "getln.h"
16#include "getoptb.h"
17#include "alloc.h"
18#include "logmsg.h"
19#include "stralloc.h"
20#include "fmt.h"
21#include "str.h"
22#include "now.h"
23#include "case.h"
24#include "quote.h"
25#include "qmail.h"
26#include "readclose.h"
27#include "myctime.h"
28#include "gfrom.h"
29#include "auto_break.h"
30#include "auto_patrn.h"
31
38
39#define WHO "qmail-local"
40
41static void usage() { logmsg(WHO,100,USAGE,"qmail-local [ -nN ] user homedir local dash ext domain sender aliasempty"); }
42
43static void temp_nomem() { logmsg(WHO,111,FATAL,"Out of memory. (#4.3.0)"); }
44static void temp_rewind() { logmsg(WHO,111,FATAL,"Unable to rewind message. (#4.3.0)"); }
45static void temp_childcrashed() { logmsg(WHO,111,FATAL,"Aack, child crashed. (#4.3.0)"); }
46static void temp_fork() { logmsg(WHO,111,FATAL,B("Unable to fork: ",error_str(errno),". (#4.3.0)")); }
47static void temp_read() { logmsg(WHO,111,ERROR,B("Unable to read message: ",error_str(errno),". (#4.3.0)")); }
48static void temp_slowlock(int d) { logmsg(WHO,111,ERROR,"File has been locked for 30 seconds straight. (#4.3.0)"); }
49static void temp_qmail(char *fn) { logmsg(WHO,111,FATAL,B("Unable to open: ",fn," ",error_str(errno),". (#4.3.0)")); }
50
53
54char *user;
55char *homedir;
56char *local;
57char *dash;
58char *ext;
59char *host;
60char *sender;
62
63stralloc safeext = {0};
64stralloc ufline = {0};
65stralloc rpline = {0};
66stralloc envrecip = {0};
67stralloc dtline = {0};
68stralloc qme = {0};
69stralloc ueo = {0};
70stralloc cmds = {0};
71stralloc messline = {0};
72stralloc foo = {0};
73stralloc hostname = {0};
74
77
78/* child process */
79
80char fntmptph[80 + FMT_ULONG * 2];
81char fnnewtph[80 + FMT_ULONG * 2];
82void tryunlinktmp() { unlink(fntmptph); }
83void sigalrm(int d) { tryunlinktmp(); _exit(3); }
84
85static void maildir_child(char *dir)
86{
87 unsigned long pid;
88 struct timeval time;
89 char host[64];
90 char *s;
91 int loop;
92 struct stat st;
93 int fd;
94 buffer bi;
95 buffer bo;
96
97 sig_alarmcatch(sigalrm);
98 if (chdir(dir) == -1) { if (errno != ENOENT) _exit(1); _exit(2); }
99 pid = getpid();
100 host[0] = 0;
101 gethostname(host,sizeof(host));
102
103 s = host;
104 for (loop = 0; loop < str_len(host); ++loop) {
105 if (host[loop] == '/') {
106 if (!stralloc_cats(&hostname,"\\057")) temp_nomem();
107 continue;
108 }
109 if (host[loop] == ':') {
110 if (!stralloc_cats(&hostname,"\\072")) temp_nomem();
111 continue;
112 }
113 if (!stralloc_append(&hostname,s+loop)) temp_nomem();
114 }
115
116 for (loop = 0 ;; ++loop) {
117 gettimeofday(&time,0);
118 s = fntmptph;
119 s += fmt_str(s,"tmp/");
120 s += fmt_ulong(s,time.tv_sec); *s++ = '.';
121 *s++ = 'M'; s += fmt_ulong(s,time.tv_usec);
122 *s++ = 'P'; s += fmt_ulong(s,pid); *s++ = '.';
123 s += fmt_strn(s,hostname.s,hostname.len); *s++ = 0;
124
125 if (stat(fntmptph,&st) == -1) if (errno == ENOENT) break;
126 /* really should never get to this point */
127 if (loop == 2) _exit(1);
128 sleep(2);
129 }
130
131 alarm(86400);
132 fd = open_excl(fntmptph);
133 if (fd == -1) _exit(1);
134
135 buffer_init(&bi,buffer_unixread,0,inbuf,sizeof(inbuf));
136 buffer_init(&bo,buffer_unixwrite,fd,outbuf,sizeof(outbuf));
137 if (buffer_put(&bo,rpline.s,rpline.len) == -1) goto FAIL;
138 if (buffer_put(&bo,dtline.s,dtline.len) == -1) goto FAIL;
139
140 switch (buffer_copy(&bo,&bi)) {
141 case -2: tryunlinktmp(); _exit(4);
142 case -3: goto FAIL;
143 }
144
145 if (buffer_flush(&bo) == -1) goto FAIL;
146 if (fstat(fd,&st) == -1) goto FAIL;
147 if (fsync(fd) == -1) goto FAIL;
148 if (close(fd) == -1) goto FAIL; /* NFS dorks */
149
150 s = fnnewtph;
151 s += fmt_str(s,"new/");
152 s += fmt_ulong(s,time.tv_sec); *s++ = '.';
153
154 /* in hexadecimal */
155 *s++ = 'I'; s += fmt_xlong(s,st.st_ino);
156 *s++ = 'V'; s += fmt_xlong(s,st.st_dev);
157
158 /* in decimal */
159 *s++ = 'M'; s += fmt_ulong(s,time.tv_usec);
160 *s++ = 'P'; s += fmt_ulong(s,pid); *s++ = '.';
161
162 s += fmt_strn(s,hostname.s,hostname.len); *s++ = 0;
163
164 if (link(fntmptph,fnnewtph) == -1) goto FAIL;
165 if ((fd = open(fnnewtph,O_RDONLY)) < 0 || fsync(fd) < 0 || close(fd)) goto FAIL;
166 /* DJB: if it was error_exist, almost certainly successful; i hate NFS -- FEH: Reiser patch */
167 tryunlinktmp(); _exit(0);
168
169 FAIL: tryunlinktmp(); _exit(1);
170}
171
172/* end child process */
173
174static void maildir(char *fn)
175{
176 int child;
177 int wstat;
178
179 if (seek_begin(0) == -1) temp_rewind();
180
181 switch (child = fork()) {
182 case -1:
183 temp_fork();
184 case 0:
185 maildir_child(fn);
186 _exit(111);
187 }
188
189 wait_pid(&wstat,child);
190 if (wait_crashed(wstat))
191 temp_childcrashed();
192
193 switch (wait_exitcode(wstat)) {
194 case 0: break;
195 case 2: logmsg(WHO,111,ERROR,"Unable to chdir to maildir. (#4.2.1)");
196 case 3: logmsg(WHO,111,ERROR,"Timeout on maildir delivery. (#4.3.0)");
197 case 4: logmsg(WHO,111,ERROR,"Unable to read message. (#4.3.0)");
198 default: logmsg(WHO,111,ERROR,"Temporary error on maildir delivery. (#4.3.0)");
199 }
200}
201
202static void mailfile(char *fn)
203{
204 int fd;
205 buffer bi;
206 buffer bo;
207 int match;
208 seek_pos pos;
209 int flaglocked;
210
211 if (seek_begin(0) == -1) temp_rewind();
212
213 fd = open_append(fn);
214 if (fd == -1)
215 logmsg(WHO,111,ERROR,B("Unable to open:",fn," ",error_str(errno),". (#4.2.1)"));
216
217 sig_alarmcatch(temp_slowlock);
218 alarm(30);
219 flaglocked = (lock_ex(fd) != -1);
220 alarm(0);
221 sig_alarmdefault();
222
223 seek_end(fd);
224 pos = seek_cur(fd);
225
226 buffer_init(&bi,buffer_unixread,0,inbuf,sizeof(inbuf));
227 buffer_init(&bo,buffer_unixwrite,fd,outbuf,sizeof(outbuf));
228 if (buffer_put(&bo,ufline.s,ufline.len)) goto WRITERRS;
229 if (buffer_put(&bo,rpline.s,rpline.len)) goto WRITERRS;
230 if (buffer_put(&bo,dtline.s,dtline.len)) goto WRITERRS;
231
232 for (;;) {
233 if (getln(&bi,&messline,&match,'\n') != 0) {
234 logmsg(WHO,0,WARN,B("Unable to read message: ",error_str(errno),". (#4.3.0)"));
235 if (flaglocked) seek_trunc(fd,pos);
236 close(fd);
237 _exit(111);
238 }
239 if (!match && !messline.len) break;
240 if (gfrom(messline.s,messline.len))
241 if (buffer_puts(&bo,">")) goto WRITERRS;
242 if (buffer_put(&bo,messline.s,messline.len)) goto WRITERRS;
243 if (!match) {
244 if (buffer_puts(&bo,"\n")) goto WRITERRS;
245 break;
246 }
247 }
248
249 if (buffer_puts(&bo,"\n")) goto WRITERRS;
250 if (buffer_flush(&bo)) goto WRITERRS;
251 if (fsync(fd) == -1) goto WRITERRS;
252 close(fd);
253 return;
254
255 WRITERRS:
256 logmsg(WHO,0,WARN,B("Unable to write ",fn,": ",error_str(errno),". (#4.3.0)"));
257 if (flaglocked) seek_trunc(fd,pos);
258 close(fd);
259 _exit(111);
260}
261
262static void mailprogram(char *prog)
263{
264 int child;
265 char *(args[4]);
266 int wstat;
267
268 if (seek_begin(0) == -1) temp_rewind();
269
270 switch (child = fork()) {
271 case -1:
272 temp_fork();
273 case 0:
274 args[0] = "/bin/sh";
275 args[1] = "-c";
276 args[2] = prog;
277 args[3] = 0;
278 sig_pipedefault();
279 execv(*args,args);
280 logmsg(WHO,0,ERROR,B("Unable to run /bin/sh: ",error_str(errno),". (#4.3.0)"));
281 }
282
283 wait_pid(&wstat,child);
284 if (wait_crashed(wstat))
285 temp_childcrashed();
286
287 switch (wait_exitcode(wstat)) {
288 case 100:
289 case 64: case 65: case 70: case 76: case 77: case 78: case 112: _exit(100);
290 case 0: break;
291 case 99: flag99 = 1; break;
292 default: _exit(111);
293 }
294}
295
296unsigned long mailforward_qp = 0;
297
298static void mailforward(char **recips)
299{
300 struct qmail qqt;
301 char *qqx;
302 buffer bi;
303 int match;
304
305 if (seek_begin(0) == -1) temp_rewind();
306 buffer_init(&bi,buffer_unixread,0,inbuf,sizeof(inbuf));
307
308 if (qmail_open(&qqt) == -1) temp_fork();
310 qmail_put(&qqt,dtline.s,dtline.len);
311
312 do {
313 if (getln(&bi,&messline,&match,'\n') != 0) { qmail_fail(&qqt); break; }
315 } while (match);
316
317 qmail_from(&qqt,ueo.s);
318 while (*recips) qmail_to(&qqt,*recips++);
319 qqx = qmail_close(&qqt);
320 if (!*qqx) return;
321 logmsg(WHO,*qqx == 'D' ? 100 : 111,ERROR,B("Unable to forward message: ",qqx + 1,"."));
322}
323
324static void bouncexf()
325{
326 int match;
327 buffer bi;
328
329 if (seek_begin(0) == -1) temp_rewind();
330 buffer_init(&bi,buffer_unixread,0,inbuf,sizeof(inbuf));
331
332 for (;;) {
333 if (getln(&bi,&messline,&match,'\n') != 0) temp_read();
334 if (!match) break;
335 if (messline.len <= 1)
336 break;
337 if (messline.len == dtline.len)
338 if (!str_diffn(messline.s,dtline.s,dtline.len))
339 logmsg(WHO,100,ERROR,"This message is looping: it already has my Delivered-To line. (#5.4.6)");
340 }
341}
342
343static void checkhome()
344{
345 struct stat st;
346
347 if (stat(".",&st) == -1)
348 logmsg(WHO,111,ERROR,B("Unable to stat home directory: ",error_str(errno),". (#4.3.0)"));
349 if (st.st_mode & auto_patrn)
350 logmsg(WHO,111,ERROR,"Uh-oh: home directory is writable. (#4.7.0)");
351 if (st.st_mode & 01000)
352 if (flagdoit)
353 logmsg(WHO,111,ERROR,"Home directory is sticky: user is editing his .qmail file. (#4.2.1)");
354 else
355 logmsg(WHO,0,WARN,"Warning: home directory is sticky.");
356}
357
358static int qmeox(char *dashowner)
359{
360 struct stat st;
361
362 if (!stralloc_copys(&qme,".qmail")) temp_nomem();
363 if (!stralloc_cats(&qme,dash)) temp_nomem();
364 if (!stralloc_cat(&qme,&safeext)) temp_nomem();
365 if (!stralloc_cats(&qme,dashowner)) temp_nomem();
366 if (!stralloc_0(&qme)) temp_nomem();
367
368 if (stat(qme.s,&st) == -1) {
369 if (errno != ENOENT) temp_qmail(qme.s);
370 return -1;
371 }
372 return 0;
373}
374
375static int qmeexists(int *fd,int *cutable)
376{
377 struct stat st;
378
379 if (!stralloc_0(&qme)) temp_nomem();
380
381 *fd = open_read(qme.s);
382 if (*fd == -1) {
383 if (errno != ENOENT) temp_qmail(qme.s);
384 if (errno == EPERM) temp_qmail(qme.s);
385 if (errno == EACCES) temp_qmail(qme.s);
386 return 0;
387 }
388
389 if (fstat(*fd,&st) == -1) temp_qmail(qme.s);
390 if ((st.st_mode & S_IFMT) == S_IFREG) {
391 if (st.st_mode & auto_patrn)
392 logmsg(WHO,111,ERROR,"Uh-oh: .qmail file is writable. (#4.7.0)");
393 *cutable = !!(st.st_mode & 0100);
394 return 1;
395 }
396 close(*fd);
397 return 0;
398}
399
400/* "" "": "" */
401/* "-/" "": "-/" "-/default" */
402/* "-/" "a": "-/a" "-/default" */
403/* "-/" "a-": "-/a-" "-/a-default" "-/default" */
404/* "-/" "a-b": "-/a-b" "-/a-default" "-/default" */
405/* "-/" "a-b-": "-/a-b-" "-/a-b-default" "-/a-default" "-/default" */
406/* "-/" "a-b-c": "-/a-b-c" "-/a-b-default" "-/a-default" "-/default" */
407
408static void qmesearch(int *fd,int *cutable)
409{
410 int i;
411
412 if (!stralloc_copys(&qme,".qmail")) temp_nomem();
413 if (!stralloc_cats(&qme,dash)) temp_nomem();
414 if (!stralloc_cat(&qme,&safeext)) temp_nomem();
415 if (qmeexists(fd,cutable)) {
416 if (safeext.len >= 7) {
417 i = safeext.len - 7;
418 if (!byte_diff("default",7,safeext.s + i))
419 if (i <= str_len(ext)) /* paranoia */
420 if (!env_put("DEFAULT",ext + i)) temp_nomem();
421 }
422 return;
423 }
424
425 for (i = safeext.len; i >= 0 ;--i)
426 if (!i || (safeext.s[i - 1] == '-')) {
427 if (!stralloc_copys(&qme,".qmail")) temp_nomem();
428 if (!stralloc_cats(&qme,dash)) temp_nomem();
429 if (!stralloc_catb(&qme,safeext.s,i)) temp_nomem();
430 if (!stralloc_cats(&qme,"default")) temp_nomem();
431 if (qmeexists(fd,cutable)) {
432 if (i <= str_len(ext)) /* paranoia */
433 if (!env_put("DEFAULT",ext + i)) temp_nomem();
434 return;
435 }
436 }
437
438 *fd = -1;
439}
440
441unsigned long count_file = 0;
442unsigned long count_forward = 0;
443unsigned long count_program = 0;
444char count_buf[FMT_ULONG];
446buffer bl = BUFFER_INIT(buffer_unixwrite,1,buflog,sizeof(buflog));
447
448static void count_print()
449{
450 buffer_puts(&bl,"did ");
451 buffer_put(&bl,count_buf,fmt_ulong(count_buf,count_file));
452 buffer_puts(&bl,"+");
453 buffer_put(&bl,count_buf,fmt_ulong(count_buf,count_forward));
454 buffer_puts(&bl,"+");
455 buffer_put(&bl,count_buf,fmt_ulong(count_buf,count_program));
456 buffer_puts(&bl,"\n");
457
458 if (mailforward_qp) {
459 buffer_puts(&bl,"qp ");
460 buffer_put(&bl,count_buf,fmt_ulong(count_buf,mailforward_qp));
461 buffer_puts(&bl,"\n");
462 }
463 buffer_flush(&bl);
464}
465
466static void sayit(char *type,char *cmd,int len)
467{
468 buffer_puts(&bl,type);
469 buffer_put(&bl,cmd,len);
470 buffer_putsflush(&bl,"\n");
471}
472
473int main(int argc,char * const *argv)
474{
475 int opt;
476 int i, j, k;
477 int fd;
478 int numforward;
479 char **recips;
481 int flagforwardonly;
482 char *x;
483
484 umask(077);
485 sig_pipeignore();
486
487 if (!env_init()) temp_nomem();
488
489 flagdoit = 1;
490 while ((opt = getoptb(argc,(char **)argv,"nN")) != opteof)
491 switch (opt) {
492 case 'n': flagdoit = 0; break;
493 case 'N': flagdoit = 1; break;
494 default: usage();
495 }
496 argc -= optind;
497 argv += optind;
498
499 if (!(user = *argv++)) usage();
500 if (!(homedir = *argv++)) usage();
501 if (!(local = *argv++)) usage();
502 if (!(dash = *argv++)) usage();
503 if (!(ext = *argv++)) usage();
504 if (!(host = *argv++)) usage();
505 if (!(sender = *argv++)) usage();
506 if (!(aliasempty = *argv++)) usage();
507 if (*argv) usage();
508
509 if (homedir[0] != '/') usage();
510 if (chdir(homedir) == -1)
511 logmsg(WHO,111,ERROR,B("Unable to switch to: ",homedir," ",error_str(errno),". (#4.3.0)"));
512 checkhome();
513
514 if (!env_put("HOST",host)) temp_nomem();
515 if (!env_put("HOME",homedir)) temp_nomem();
516 if (!env_put("USER",user)) temp_nomem();
517 if (!env_put("LOCAL",local)) temp_nomem();
518
519#ifdef HIDEVIRTUALUSER
520 if (str_len(ext) > 1) {
521 i = str_chr(local,*auto_break);
522 if (!stralloc_copys(&envrecip,local + i + 1)) temp_nomem();
523 } else
524#endif
526 if (!stralloc_cats(&envrecip,"@")) temp_nomem();
527 if (!stralloc_cats(&envrecip,host)) temp_nomem();
528
529 if (!stralloc_copy(&foo,&envrecip)) temp_nomem();
530 if (!stralloc_0(&foo)) temp_nomem();
531 if (!env_put("RECIPIENT",foo.s)) temp_nomem();
532
533 if (!stralloc_copys(&dtline,"Delivered-To: ")) temp_nomem();
534 if (!stralloc_cat(&dtline,&envrecip)) temp_nomem();
535
536 for (i = 0; i < dtline.len; ++i)
537 if (dtline.s[i] == '\n') dtline.s[i] = '_';
538 if (!stralloc_cats(&dtline,"\n")) temp_nomem();
539
540 if (!stralloc_copy(&foo,&dtline)) temp_nomem();
541 if (!stralloc_0(&foo)) temp_nomem();
542 if (!env_put("DTLINE",foo.s)) temp_nomem();
543
544 if (flagdoit) bouncexf();
545
546 if (!env_put("SENDER",sender)) temp_nomem();
547
548 if (!quote2(&foo,sender)) temp_nomem();
549 if (!stralloc_copys(&rpline,"Return-Path: <")) temp_nomem();
550 if (!stralloc_cat(&rpline,&foo)) temp_nomem();
551 for (i = 0;i < rpline.len;++i) if (rpline.s[i] == '\n') rpline.s[i] = '_';
552 if (!stralloc_cats(&rpline,">\n")) temp_nomem();
553
554 if (!stralloc_copy(&foo,&rpline)) temp_nomem();
555 if (!stralloc_0(&foo)) temp_nomem();
556 if (!env_put("RPLINE",foo.s)) temp_nomem();
557
558 if (!stralloc_copys(&ufline,"From ")) temp_nomem();
559
560 if (*sender) {
561 int len; int i; char ch;
562
563 len = str_len(sender);
564 if (!stralloc_readyplus(&ufline,len)) temp_nomem();
565
566 for (i = 0;i < len;++i) {
567 ch = sender[i];
568 if ((ch == ' ') || (ch == '\t') || (ch == '\n')) ch = '-';
569 ufline.s[ufline.len + i] = ch;
570 }
571 ufline.len += len;
572 } else
573 if (!stralloc_cats(&ufline,"MAILER-DAEMON")) temp_nomem();
574
575 if (!stralloc_cats(&ufline," ")) temp_nomem();
576 starttime = now();
577 if (!stralloc_cats(&ufline,myctime(starttime))) temp_nomem();
578
579 if (!stralloc_copy(&foo,&ufline)) temp_nomem();
580 if (!stralloc_0(&foo)) temp_nomem();
581 if (!env_put("UFLINE",foo.s)) temp_nomem();
582
583 x = ext;
584 if (!env_put("EXT",x)) temp_nomem();
585 x += str_chr(x,'-'); if (*x) ++x;
586 if (!env_put("EXT2",x)) temp_nomem();
587 x += str_chr(x,'-'); if (*x) ++x;
588 if (!env_put("EXT3",x)) temp_nomem();
589 x += str_chr(x,'-'); if (*x) ++x;
590 if (!env_put("EXT4",x)) temp_nomem();
591
593 case_lowerb(safeext.s,safeext.len);
594
595 for (i = 0; i < safeext.len; ++i)
596 if (safeext.s[i] == '.')
597 safeext.s[i] = ':';
598
599 i = str_len(host);
600 i = byte_rchr(host,i,'.');
601 if (!stralloc_copyb(&foo,host,i)) temp_nomem();
602 if (!stralloc_0(&foo)) temp_nomem();
603 if (!env_put("HOST2",foo.s)) temp_nomem();
604 i = byte_rchr(host,i,'.');
605 if (!stralloc_copyb(&foo,host,i)) temp_nomem();
606 if (!stralloc_0(&foo)) temp_nomem();
607 if (!env_put("HOST3",foo.s)) temp_nomem();
608 i = byte_rchr(host,i,'.');
609 if (!stralloc_copyb(&foo,host,i)) temp_nomem();
610 if (!stralloc_0(&foo)) temp_nomem();
611 if (!env_put("HOST4",foo.s)) temp_nomem();
612
613 flagforwardonly = 0;
614 qmesearch(&fd,&flagforwardonly);
615
616 if (fd == -1)
617 if (*dash)
618 logmsg(WHO,100,ERROR,"Sorry, no mailbox here by that name. (#5.1.1)");
619
621 if (str_diff(sender,""))
622 if (str_diff(sender,"#@[]"))
623 if (qmeox("-owner") == 0) {
624 if (qmeox("-owner-default") == 0) {
626 if (!stralloc_cats(&ueo,"-owner-@")) temp_nomem();
627 if (!stralloc_cats(&ueo,host)) temp_nomem();
628 if (!stralloc_cats(&ueo,"-@[]")) temp_nomem();
629 } else {
631 if (!stralloc_cats(&ueo,"-owner@")) temp_nomem();
632 if (!stralloc_cats(&ueo,host)) temp_nomem();
633 }
634 }
635 if (!stralloc_0(&ueo)) temp_nomem();
636 if (!env_put("NEWSENDER",ueo.s)) temp_nomem();
637
638 if (!stralloc_ready(&cmds,0)) temp_nomem();
639 cmds.len = 0;
640
641 if (fd != -1)
642 if (readclose_append(fd,&cmds,256) == -1) temp_nomem();
643
644 if (!cmds.len) {
646 flagforwardonly = 0;
647 }
648 if (!cmds.len || (cmds.s[cmds.len - 1] != '\n'))
649 if (!stralloc_cats(&cmds,"\n")) temp_nomem();
650
651 numforward = 0;
652 i = 0;
653
654 for (j = 0; j < cmds.len; ++j)
655 if (cmds.s[j] == '\n') {
656 switch (cmds.s[i]) {
657 case '#': case '.': case '/': case '|': break;
658 default: ++numforward;
659 }
660 i = j + 1;
661 }
662
663 recips = (char **) alloc((numforward + 1) * sizeof(char *));
664 if (!recips) temp_nomem();
665 numforward = 0;
666
667 flag99 = 0;
668
669 i = 0;
670 for (j = 0; j < cmds.len; ++j)
671 if (cmds.s[j] == '\n') {
672 cmds.s[j] = 0;
673 k = j;
674 /* Patch contributed by Erik Sjolund <erik.sjolund@gmail.com>. */
675 while ((k > i) && ((cmds.s[k - 1] == ' ') || (cmds.s[k - 1] == '\t')))
676 cmds.s[--k] = 0;
677 switch (cmds.s[i]) {
678 case 0: /* k == i */
679 if (i) break;
680 logmsg(WHO,111,ERROR,"Uh-oh: first line of .qmail file is blank. (#4.2.1)");
681 case '#':
682 break;
683 case '.':
684 case '/':
685 ++count_file;
686 if (flagforwardonly) logmsg(WHO,111,ERROR,"Uh-oh: .qmail has file delivery but has x bit set. (#4.7.0)");
687 if (cmds.s[k - 1] == '/')
688 if (flagdoit) maildir(cmds.s + i);
689 else sayit("maildir ",cmds.s + i,k - i);
690 else
691 if (flagdoit) mailfile(cmds.s + i);
692 else sayit("mbox ",cmds.s + i,k - i);
693 break;
694 case '|':
696 if (flagforwardonly) logmsg(WHO,111,ERROR,"Uh-oh: .qmail has prog delivery but has x bit set. (#4.7.0)");
697 if (flagdoit) mailprogram(cmds.s + i + 1);
698 else sayit("program ",cmds.s + i + 1,k - i - 1);
699 break;
700 case '+':
701 if (str_equal(cmds.s + i + 1,"list"))
702 flagforwardonly = 1;
703 break;
704 case '&':
705 ++i;
706 default:
708 if (flagdoit) recips[numforward++] = cmds.s + i;
709 else sayit("forward ",cmds.s + i,k - i);
710 break;
711 }
712 i = j + 1;
713 if (flag99) break;
714 }
715
716 if (numforward) if (flagdoit) {
717 recips[numforward] = 0;
718 mailforward(recips);
719 }
720
721 count_print();
722 _exit(0);
723}
char inbuf[BUFFER_SMALL]
Definition auto-gid.c:9
char auto_break[]
int auto_patrn
#define WHO
Definition bouncesaying.c:8
int main()
Definition chkshsgr.c:6
char outbuf[BUFSIZE_MESS]
Definition columnt.c:12
buffer bo
Definition columnt.c:13
struct qmail qqt
buffer bi
long datetime_sec
Definition datetime.h:15
int stralloc_copys(stralloc *, char const *)
void _exit(int)
stralloc sender
Definition fastforward.c:71
char * dtline
Definition fastforward.c:70
int gfrom(char *s, int len)
Definition gfrom.c:4
char host[256]
Definition hostname.c:5
stralloc ufline
int match
Definition matchup.c:196
char * myctime(datetime_sec)
Definition myctime.c:14
datetime_sec now()
Definition now.c:5
char * rpline
Definition preline.c:20
stralloc homedir
stralloc user
void usage()
char * local
Definition qmail-getpw.c:18
char * dash
Definition qmail-getpw.c:20
datetime_sec starttime
unsigned long count_forward
stralloc qme
Definition qmail-local.c:68
unsigned long mailforward_qp
char fntmptph[80+FMT_ULONG *2]
Definition qmail-local.c:80
stralloc ueo
Definition qmail-local.c:69
void tryunlinktmp()
Definition qmail-local.c:82
char fnnewtph[80+FMT_ULONG *2]
Definition qmail-local.c:81
unsigned long count_program
stralloc safeext
Definition qmail-local.c:63
int flag99
Definition qmail-local.c:52
stralloc messline
Definition qmail-local.c:71
stralloc foo
Definition qmail-local.c:72
char buflog[BUFSIZE_LOG]
char * ext
Definition qmail-local.c:58
int flagdoit
Definition qmail-local.c:51
buffer bl
unsigned long count_file
stralloc cmds
Definition qmail-local.c:70
void sigalrm(int d)
Definition qmail-local.c:83
stralloc envrecip
Definition qmail-local.c:66
stralloc hostname
Definition qmail-local.c:73
char count_buf[FMT_ULONG]
char * aliasempty
Definition qmail-local.c:61
stralloc fn
void sigalrm()
Definition qmail-queue.c:65
void temp_read()
int j
Definition qmail-send.c:926
struct del * d[CHANNELS]
Definition qmail-send.c:726
#define BUFSIZE_LOG
Definition qmail.h:11
void qmail_to(struct qmail *, char *)
Definition qmail.c:83
#define BUFSIZE_LINE
Definition qmail.h:8
void qmail_from(struct qmail *, char *)
Definition qmail.c:73
void qmail_put(struct qmail *, char *, int)
Definition qmail.c:63
char * qmail_close(struct qmail *)
Definition qmail.c:90
unsigned long qmail_qp(struct qmail *)
Definition qmail.c:53
int qmail_open(struct qmail *)
Definition qmail.c:21
void qmail_fail(struct qmail *)
Definition qmail.c:58
int quote2(stralloc *, char *)
Definition quote.c:70
uint32_t k[64]
Definition sha256.c:26
Definition qmail.h:14
void temp_nomem(void)