s/qmail 4.3.20
Next generation secure email transport
Loading...
Searching...
No Matches
qmail-send.c
Go to the documentation of this file.
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <string.h>
4#include <unistd.h>
5#include <utime.h>
6#include "error.h"
7#include "sig.h"
8#include "direntry.h"
9#include "control.h"
10#include "select.h"
11#include "open.h"
12#include "seek.h"
13#include "exit.h"
14#include "lock.h"
15#include "ndelay.h"
16#include "now.h"
17#include "getln.h"
18#include "buffer.h"
19#include "alloc.h"
20#include "genalloc.h"
21#include "stralloc.h"
22#include "logmsg.h"
23#include "str.h"
24#include "byte.h"
25#include "fmt.h"
26#include "scan.h"
27#include "case.h"
28#include "auto_qmail.h"
29#include "auto_queue.h"
30#include "trigger.h"
31#include "newfield.h"
32#include "quote.h"
33#include "qmail.h"
34#include "qsutil.h"
35#include "prioq.h"
36#include "constmap.h"
37#include "fmtqfn.h"
38#include "readsubdir.h"
39#include "sendtodo.h"
40
41long lifetime = 604800;
43
44stralloc queuedir = {0};
45
46stralloc percenthack = {0};
48stralloc locals = {0};
50stralloc vdoms = {0};
52stralloc envnoathost = {0};
53stralloc bouncefrom = {0};
54stralloc bouncehost = {0};
55stralloc doublebounceto = {0};
56stralloc doublebouncehost = {0};
57
58char strnum2[FMT_ULONG];
59char strnum3[FMT_ULONG];
60
61#define CHANNELS 2
62char *chanaddr[CHANNELS] = { "local/", "remote/" };
63char *chanstatusmsg[CHANNELS] = { " local ", " remote " };
64char *tochan[CHANNELS] = { " to local ", " to remote " };
65int chanfdout[CHANNELS] = { 1, 3 };
66int chanfdin[CHANNELS] = { 2, 4 };
67int chanskip[CHANNELS] = { 10, 20 };
68
69int flagexitasap = 0; void sigterm() { flagexitasap = 1; }
70int flagrunasap = 0; void sigalrm() { flagrunasap = 1; }
71int flagreadasap = 0; void sighup() { flagreadasap = 1; }
72
73void cleandied()
74{
75 log1s("alert: qmail-send lost connection to qmail-clean ... exiting\n");
76 flagexitasap = 1;
77}
78
80
81void spawndied(int c)
82{
83 log1s("alert: oh no! qmail-send lost spawn connection! dying...\n");
84 flagspawnalive[c] = 0;
85 flagexitasap = 1;
86}
87
88#define REPORTMAX 10000
89
91
92
93/* this file is too long ---------------------------------------- FILE CREATE */
94
95stralloc fn = {0};
96stralloc fn2 = {0};
97char fnmake_strnum[FMT_ULONG];
98
100{
101 while (!stralloc_ready(&fn,FMTQFN)) nomem();
102 while (!stralloc_ready(&fn2,FMTQFN)) nomem();
103}
104
105void fnmake_info(unsigned long id) { fn.len = fmtqfn(fn.s,"info/",id,1); }
106void fnmake_todo(unsigned long id) { fn.len = fmtqfn(fn.s,"todo/",id,1); }
107void fnmake_mess(unsigned long id) { fn.len = fmtqfn(fn.s,"mess/",id,1); }
108void fnmake_foop(unsigned long id) { fn.len = fmtqfn(fn.s,"foop/",id,0); }
109void fnmake_split(unsigned long id) { fn.len = fmtqfn(fn.s,"",id,1); }
110void fnmake2_bounce(unsigned long id) { fn2.len = fmtqfn(fn2.s,"bounce/",id,0); }
111void fnmake_chanaddr(unsigned long id,int c) { fn.len = fmtqfn(fn.s,chanaddr[c],id,1); }
112
113
114/* this file is too long ----------------------------------------- REWRITING */
115
116void senderadd(stralloc *sa,char *sender,char *recip)
117{
118 int i;
119 int j;
120 int k;
121
122 i = str_len(sender);
123 if (i >= 4)
124 if (str_equal(sender + i - 4,"-@[]")) {
125 j = byte_rchr(sender,i - 4,'@');
126 k = str_rchr(recip,'@');
127 if (recip[k] && (j + 5 <= i)) {
128 /* owner-@host-@[] -> owner-recipbox=reciphost@host */
129 while (!stralloc_catb(sa,sender,j)) nomem();
130 while (!stralloc_catb(sa,recip,k)) nomem();
131 while (!stralloc_cats(sa,"=")) nomem();
132 while (!stralloc_cats(sa,recip + k + 1)) nomem();
133 while (!stralloc_cats(sa,"@")) nomem();
134 while (!stralloc_catb(sa,sender + j + 1,i - 5 - j)) nomem();
135 return;
136 }
137 }
138 while (!stralloc_cats(sa,sender)) nomem();
139}
140
141
142/* this file is too long ---------------------------------------------- INFO */
143
144int getinfo(stralloc *sa,datetime_sec *dt,unsigned long id)
145{
146 int fdnumber;
147 struct stat st;
148 static stralloc line = {0};
149 int match;
150 char buf[BUFSIZE_SMALL];
151 buffer b;
152
153 fnmake_info(id);
154 fdnumber = open_read(fn.s);
155 if (fdnumber == -1) return 0;
156 if (fstat(fdnumber,&st) == -1) { close(fdnumber); return 0; }
157 buffer_init(&b,buffer_unixread,fdnumber,buf,sizeof(buf));
158 if (getln(&b,&line,&match,'\0') == -1) { close(fdnumber); return 0; }
159 close(fdnumber);
160 if (!match) return 0;
161 if (line.s[0] != 'F') return 0;
162
163 *dt = st.st_mtime;
164 while (!stralloc_copys(sa,line.s + 1)) nomem();
165 while (!stralloc_0(sa)) nomem();
166 return 1;
167}
168
169
170/* this file is too long ------------------------------------- COMMUNICATION */
171
172buffer toqc;
174buffer fromqc;
176stralloc comm_buf[CHANNELS] = { {0}, {0} };
178
180{
181 int c;
182
183 buffer_init(&toqc,buffer_unixwrite,5,toqcbuf,sizeof(toqcbuf));
184 buffer_init(&fromqc,buffer_unixread,6,fromqcbuf,sizeof(fromqcbuf));
185 for (c = 0; c < CHANNELS; ++c)
186 if (ndelay_on(chanfdout[c]) == -1)
187 /* this is so stupid: NDELAY semantics should be default on write */
188 spawndied(c); /* drastic, but better than risking deadlock */
189}
190
192{
193 /* XXX: could allow a bigger buffer; say 10 recipients */
194 if (comm_buf[c].s && comm_buf[c].len) return 0;
195 return 1;
196}
197
198void comm_write(int c,int delnum,unsigned long id,char *sender,char *recip)
199{
200 char ch;
201
202 if (comm_buf[c].s && comm_buf[c].len) return;
203 while (!stralloc_copys(&comm_buf[c],"")) nomem();
204 ch = delnum;
205 while (!stralloc_append(&comm_buf[c],&ch)) nomem();
206 fnmake_split(id);
207 while (!stralloc_cats(&comm_buf[c],fn.s)) nomem();
208 while (!stralloc_0(&comm_buf[c])) nomem();
210 while (!stralloc_0(&comm_buf[c])) nomem();
211 while (!stralloc_cats(&comm_buf[c],recip)) nomem();
212 while (!stralloc_0(&comm_buf[c])) nomem();
213 comm_pos[c] = 0;
214}
215
216void comm_selprep(int *nfds,fd_set *wfds)
217{
218 int c;
219
220 for (c = 0; c < CHANNELS; ++c)
221 if (flagspawnalive[c])
222 if (comm_buf[c].s && comm_buf[c].len) {
223 FD_SET(chanfdout[c],wfds);
224 if (*nfds <= chanfdout[c])
225 *nfds = chanfdout[c] + 1;
226 }
227}
228
229void comm_do(fd_set *wfds)
230{
231 int c;
232
233 for (c = 0; c < CHANNELS; ++c)
234 if (flagspawnalive[c])
235 if (comm_buf[c].s && comm_buf[c].len)
236 if (FD_ISSET(chanfdout[c],wfds)) {
237 int w;
238 int len;
239 len = comm_buf[c].len;
240
241 w = write(chanfdout[c],comm_buf[c].s + comm_pos[c],len - comm_pos[c]);
242 if (w <= 0) {
243 if ((w == -1) && (errno == EPIPE))
244 spawndied(c);
245 else
246 continue; /* kernel select() bug; can't avoid busy-looping */
247 } else {
248 comm_pos[c] += w;
249 if (comm_pos[c] == len)
250 comm_buf[c].len = 0;
251 }
252 }
253}
254
255
256/* this file is too long ------------------------------------------ CLEANUPS */
257
258int flagcleanup; /* if 1, cleanupdir is initialized and ready */
261
263{
264 flagcleanup = 0;
265 cleanuptime = now();
266}
267
269{
270 if (flagcleanup) *wakeup = 0;
271 if (*wakeup > cleanuptime) *wakeup = cleanuptime;
272}
273
275{
276 char ch;
277 struct stat st;
278 unsigned long id;
279
280 if (!flagcleanup) {
281 if (recent < cleanuptime) return;
283 flagcleanup = 1;
284 }
285
286 switch (readsubdir_next(&cleanupdir,&id)) {
287 case 1: break;
289 default: return;
290 }
291
292 fnmake_mess(id);
293 if (stat(fn.s,&st) == -1) return; /* probably qmail-queue deleted it */
294 if (recent <= st.st_atime + OSSIFIED) return;
295
296 fnmake_info(id);
297 if (stat(fn.s,&st) == 0) return;
298 if (errno != ENOENT) return;
299
300 fnmake_todo(id);
301 if (stat(fn.s,&st) == 0) return;
302 if (errno != ENOENT) return;
303
304 fnmake_foop(id);
305 if (buffer_putflush(&toqc,fn.s,fn.len) == -1) { cleandied(); return; }
306 if (buffer_get(&fromqc,&ch,1) != 1) { cleandied(); return; }
307 if (ch != '+')
308 log3s("warning: qmail-clean is unable to clean up ",fn.s,"\n");
309}
310
311
312/* this file is too long ----------------------------------- PRIORITY QUEUES */
313
314prioq pqdone = {0}; /* -todo +info; HOPEFULLY -local -remote */
315prioq pqchan[CHANNELS] = { {0}, {0} };
316/* pqchan 0: -todo +info +local ?remote */
317/* pqchan 1: -todo +info ?local +remote */
318prioq pqfail = {0}; /* stat() failure; has to be pqadded again */
319
320void pqadd(unsigned long id)
321{
322 struct prioq_elt pe;
323 struct prioq_elt pechan[CHANNELS];
324 int flagchan[CHANNELS];
325 struct stat st;
326 int c;
327
328#define CHECKSTAT if (errno != ENOENT) goto FAIL;
329
330 fnmake_info(id);
331 if (stat(fn.s,&st) == -1) {
333 return; /* someone yanking our chain */
334 }
335
336 fnmake_todo(id);
337 if (stat(fn.s,&st) != -1) return; /* look, ma, dad crashed writing info! */
339
340 for (c = 0; c < CHANNELS; ++c) {
341 fnmake_chanaddr(id,c);
342 if (stat(fn.s,&st) == -1) { flagchan[c] = 0; CHECKSTAT }
343 else { flagchan[c] = 1; pechan[c].id = id; pechan[c].dt = st.st_mtime; }
344 }
345
346 for (c = 0; c < CHANNELS; ++c)
347 if (flagchan[c])
348 while (!prioq_insert(&pqchan[c],&pechan[c])) nomem();
349
350 for (c = 0; c < CHANNELS; ++c)
351 if (flagchan[c]) break;
352
353 if (c == CHANNELS) {
354 pe.id = id; pe.dt = now();
355 while (!prioq_insert(&pqdone,&pe)) nomem();
356 }
357
358 return;
359
360 FAIL:
361 log3s("warning: qmail-send send is unable to stat ",fn.s,"; will try again later\n");
362 pe.id = id; pe.dt = now() + SLEEP_SYSFAIL;
363 while (!prioq_insert(&pqfail,&pe)) nomem();
364}
365
367{
369 int x;
370 unsigned long id;
371
372 readsubdir_init(&rs,"info",pausedir);
373
374 while ((x = readsubdir_next(&rs,&id)))
375 if (x > 0) pqadd(id);
376}
377
379{
380 int c;
381 struct prioq_elt pe;
382 // time_t ut[2]; /* XXX: more portable than utimbuf, but still worrisome */
383 struct utimbuf ut;
384
385 for (c = 0; c < CHANNELS; ++c)
386 while (prioq_min(&pqchan[c],&pe)) {
388 fnmake_chanaddr(pe.id,c);
389 ut.actime = ut.modtime = pe.dt;
390 if (utime(fn.s,&ut) == -1)
391 log3s("warning: qmail-send is unable to utime ",fn.s,"; message will be retried too soon\n");
392 }
393}
394
395void pqrun()
396{
397 int c;
398 int i;
399
400 for (c = 0; c < CHANNELS; ++c)
401 if (pqchan[c].p)
402 if (pqchan[c].len)
403 for (i = 0; i < pqchan[c].len; ++i)
404 pqchan[c].p[i].dt = recent;
405}
406
407
408/* this file is too long ---------------------------------------------- JOBS */
409
410struct job
411{
412 int refs; /* if 0, this struct is unused */
413 unsigned long id;
416 stralloc sender;
420};
421
423struct job *jo;
424
426{
427 int j;
428
429 while (!(jo = (struct job *) alloc(numjobs * sizeof(struct job)))) nomem();
430 for (j = 0; j < numjobs; ++j) {
431 jo[j].refs = 0;
432 jo[j].sender.s = 0;
433 }
434}
435
437{
438 int j;
439
440 for (j = 0; j < numjobs; ++j)
441 if (!jo[j].refs) return 1;
442 return 0;
443}
444
445int job_open(unsigned long id,int channel)
446{
447 int j;
448
449 for (j = 0; j < numjobs; ++j)
450 if (!jo[j].refs) break;
451 if (j == numjobs) return -1;
452 jo[j].refs = 1;
453 jo[j].id = id;
454 jo[j].channel = channel;
455 jo[j].numtodo = 0;
456 jo[j].flaghiteof = 0;
457 return j;
458}
459
460void job_close(int j)
461{
462 struct prioq_elt pe;
463 struct stat st;
464 int c;
465
466 if (0 < --jo[j].refs) return;
467
468 pe.id = jo[j].id;
469 pe.dt = jo[j].retry;
470
471 if (jo[j].flaghiteof && !jo[j].numtodo) {
472 fnmake_chanaddr(jo[j].id,jo[j].channel);
473 if (unlink(fn.s) == -1) {
474 log3s("warning: qmail-send is unable to unlink ",fn.s,"; will try again later\n");
475 pe.dt = now() + SLEEP_SYSFAIL;
476 } else {
477 for (c = 0; c < CHANNELS; ++c) if (c != jo[j].channel) {
478 fnmake_chanaddr(jo[j].id,c);
479 if (stat(fn.s,&st) == 0) return; /* more channels going */
480 if (errno != ENOENT) {
481 log3s("warning: qmail-send is unable to stat ",fn.s,"\n");
482 break; /* this is the only reason for HOPEFULLY */
483 }
484 }
485 pe.dt = now();
486 while (!prioq_insert(&pqdone,&pe)) nomem();
487 return;
488 }
489 }
490
491 while (!prioq_insert(&pqchan[jo[j].channel],&pe)) nomem();
492}
493
494
495/* this file is too long ------------------------------------------- BOUNCES */
496
498{
499 int i;
500 char *domain;
501 int domainlen;
502 char *prepend;
503
504 i = str_rchr(recip,'@');
505 if (!recip[i]) return recip;
506 domain = recip + i + 1;
507 domainlen = str_len(domain);
508
509 for (i = 0; i <= domainlen; ++i)
510 if ((i == 0) || (i == domainlen) || (domain[i] == '.'))
511 if ((prepend = constmap(&mapvdoms,domain + i,domainlen - i))) {
512 if (!*prepend) break;
513 i = str_len(prepend);
514 if (str_diffn(recip,prepend,i)) break;
515 if (recip[i] != '-') break;
516 return recip + i + 1;
517 }
518
519 return recip;
520}
521
522stralloc bouncetext = {0};
523
524void addbounce(unsigned long id,char *recip,char *report)
525{
526 int fd;
527 int pos;
528 int w;
529
530 while (!stralloc_copys(&bouncetext,"<")) nomem();
531 while (!stralloc_cats(&bouncetext,stripvdomprepend(recip))) nomem();
532
533 for (pos = 0; pos < bouncetext.len; ++pos)
534 if (bouncetext.s[pos] == '\n')
535 bouncetext.s[pos] = '_';
536
537 while (!stralloc_cats(&bouncetext,">:\n")) nomem();
538 while (!stralloc_cats(&bouncetext,report)) nomem();
539
540 if (report[0])
541 if (report[str_len(report) - 1] != '\n')
542 while (!stralloc_cats(&bouncetext,"\n")) nomem();
543
544 for (pos = bouncetext.len - 2; pos > 0; --pos)
545 if (bouncetext.s[pos] == '\n')
546 if (bouncetext.s[pos - 1] == '\n')
547 bouncetext.s[pos] = '/';
548
549 while (!stralloc_cats(&bouncetext,"\n")) nomem();
550 fnmake2_bounce(id);
551
552 for (;;) {
553 fd = open_append(fn2.s);
554 if (fd != -1) break;
555 log1s("alert: qmail-send is unable to append to bounce message; HELP! sleeping...\n");
556 sleep(10);
557 }
558
559 pos = 0;
560
561 while (pos < bouncetext.len) {
562 w = write(fd,bouncetext.s + pos,bouncetext.len - pos);
563 if (w <= 0) {
564 log1s("alert: qmail-send is unable to append to bounce message; HELP! sleeping...\n");
565 sleep(10);
566 }
567 else
568 pos += w;
569 }
570 close(fd);
571}
572
573int injectbounce(unsigned long id)
574{
575 struct qmail qqt;
576 struct stat st;
577 char *bouncesender;
578 char *bouncerecip;
579 int r;
580 int fd;
581 buffer bi;
582 char buf[BUFSIZE_SMALL];
583 char inbuf[BUFSIZE_SMALL];
584 static stralloc sender = {0};
585 static stralloc quoted = {0};
587 unsigned long qp;
588 int bytestogo;
589 int bytestoget;
590
591 if (!getinfo(&sender,&birth,id)) return 0; /* XXX: print warning */
592
593 /* owner-@host-@[] -> owner-@host */
594 if (sender.len >= 5)
595 if (str_equal(sender.s + sender.len - 5,"-@[]")) {
596 sender.len -= 4;
597 sender.s[sender.len - 1] = 0;
598 }
599
600 fnmake2_bounce(id);
601 fnmake_mess(id);
602
603 if (stat(fn2.s,&st) == -1) {
604 if (errno == ENOENT) return 1;
605 log3s("warning: qmail-send is unable to stat ",fn2.s,"\n");
606 return 0;
607 }
608
609 if (str_equal(sender.s,"#@[]"))
610 log3s("triple bounce: discarding ",fn2.s,"\n");
611 else if (!*sender.s && *doublebounceto.s == '@')
612 log3s("double bounce: discarding ",fn2.s,"\n");
613 else {
614 if (qmail_open(&qqt) == -1)
615 { log1s("warning: qmail-send is unable to start qmail-queue, will try later\n"); return 0; }
616 qp = qmail_qp(&qqt);
617
618 if (*sender.s) { bouncesender = ""; bouncerecip = sender.s; }
619 else { bouncesender = "#@[]"; bouncerecip = doublebounceto.s; }
620
621 while (!newfield_datemake(now())) nomem();
623 qmail_puts(&qqt,"From: ");
624 while (!quote(&quoted,&bouncefrom)) nomem();
625 qmail_put(&qqt,quoted.s,quoted.len);
626 qmail_puts(&qqt,"@");
628 qmail_puts(&qqt,"\nTo: ");
629 while (!quote2(&quoted,bouncerecip)) nomem();
630 qmail_put(&qqt,quoted.s,quoted.len);
631 qmail_puts(&qqt,"\n\
632Subject: failure notice\n\
633\n\
634Hi. This is the qmail-send program at ");
636 qmail_puts(&qqt,*sender.s ? ".\n\
637I'm afraid I wasn't able to deliver your message to the following addresses.\n\
638This is a permanent error; I've given up. Sorry it didn't work out.\n\
639\n\
640" : ".\n\
641I tried to deliver a bounce message to this address, but the bounce bounced!\n\
642\n\
643");
644
645 fd = open_read(fn2.s);
646 if (fd == -1)
647 qmail_fail(&qqt);
648 else {
649 buffer_init(&bi,buffer_unixread,fd,inbuf,sizeof(inbuf));
650 while ((r = buffer_get(&bi,buf,sizeof(buf))) > 0)
651 qmail_put(&qqt,buf,r);
652
653 close(fd);
654 if (r == -1) qmail_fail(&qqt);
655 }
656
657 qmail_puts(&qqt,*sender.s ? "--- Below this line is a copy of the message.\n\n" : "--- Below this line is the original bounce.\n\n");
658 qmail_puts(&qqt,"Return-Path: <");
659 while (!quote2(&quoted,sender.s)) nomem();
660 qmail_put(&qqt,quoted.s,quoted.len);
661 qmail_puts(&qqt,">\n");
662
663 fd = open_read(fn.s);
664 if (fd == -1)
665 qmail_fail(&qqt);
666 else {
667 if (bouncemaxbytes) {
668 bytestogo = bouncemaxbytes;
669 bytestoget = (bytestogo < sizeof(buf)) ? bytestogo : sizeof(buf);
670
671 buffer_init(&bi,buffer_unixread,fd,inbuf,sizeof(inbuf));
672
673 while (bytestoget > 0 && (r = buffer_get(&bi,buf,bytestoget)) > 0) {
674 qmail_put(&qqt,buf,r);
675 bytestogo -= bytestoget;
676 bytestoget = (bytestogo < sizeof(buf)) ? bytestogo : sizeof(buf);
677 }
678 if (r > 0)
679 qmail_puts(&qqt,"\n\n--- Rest of message truncated.\n");
680 } else { /* preserve default behavior */
681 buffer_init(&bi,read,fd,inbuf,sizeof(inbuf));
682
683 while ((r = buffer_get(&bi,buf,sizeof(buf))) > 0)
684 qmail_put(&qqt,buf,r);
685 }
686 close(fd);
687 if (r == -1) qmail_fail(&qqt);
688 }
689
690 qmail_from(&qqt,bouncesender);
691 qmail_to(&qqt,bouncerecip);
692
693 if (*qmail_close(&qqt)) {
694 log1s("warning: qmail-send has trouble injecting bounce message, will try later\n");
695 return 0;
696 }
697
698 strnum2[fmt_ulong(strnum2,id)] = 0;
699 log2s("bounce msg ",strnum2);
700 strnum2[fmt_ulong(strnum2,qp)] = 0;
701 log3s(" qp ",strnum2,"\n");
702 }
703
704 if (unlink(fn2.s) != 0) {
705 log3s("warning: qmail-send is unable to unlink ",fn2.s,"\n");
706 return 0;
707 }
708
709 return 1;
710}
711
712
713/* this file is too long ---------------------------------------- DELIVERIES */
714
715struct del {
716 int used;
717 int j;
718 unsigned long delid;
719 seek_pos mpos;
720 stralloc recip;
721};
722
723unsigned long masterdelid = 1;
724unsigned long concurrency[CHANNELS] = { 10, 20 };
725unsigned long concurrencyused[CHANNELS] = { 0, 0 };
726struct del *d[CHANNELS];
727stralloc dline[CHANNELS];
728char delbuf[2048];
729
731{
732 int c;
733
734 log1s("status:");
735 for (c = 0; c < CHANNELS; ++c) {
736 strnum2[fmt_ulong(strnum2,(unsigned long) concurrencyused[c])] = 0;
737 strnum3[fmt_ulong(strnum3,(unsigned long) concurrency[c])] = 0;
739 log2s("/",strnum3);
740 }
741 if (flagexitasap) log1s(" exitasap");
742 log1s("\n");
743}
744
746{
747 int c;
748 int i;
749
750 for (c = 0; c < CHANNELS; ++c) {
751 flagspawnalive[c] = 1;
752 while (!(d[c] = (struct del *) alloc(concurrency[c] * sizeof(struct del))))
753 nomem();
754 for (i = 0; i < concurrency[c]; ++i)
755 { d[c][i].used = 0; d[c][i].recip.s = 0; }
756 dline[c].s = 0;
757 while (!stralloc_copys(&dline[c],"")) nomem();
758 }
759
760 del_status();
761}
762
764{
765 int c;
766
767 for (c = 0; c < CHANNELS; ++c)
768 if (flagspawnalive[c]) /* if dead, nothing we can do about its jobs */
769 if (concurrencyused[c]) return 0;
770 return 1;
771}
772
773int del_avail(int c)
774{
776}
777
778void del_start(int j,seek_pos mpos,char *recip)
779{
780 int i;
781 int c;
782
783 c = jo[j].channel;
784 if (!flagspawnalive[c]) return;
785 if (!comm_canwrite(c)) return;
786
787 for (i = 0; i < concurrency[c]; ++i)
788 if (!d[c][i].used) break;
789 if (i == concurrency[c]) return;
790
791 if (!stralloc_copys(&d[c][i].recip,recip)) { nomem(); return; }
792 if (!stralloc_0(&d[c][i].recip)) { nomem(); return; }
793 d[c][i].j = j; ++jo[j].refs;
794 d[c][i].delid = masterdelid++;
795 d[c][i].mpos = mpos;
796 d[c][i].used = 1; ++concurrencyused[c];
797
798 comm_write(c,i,jo[j].id,jo[j].sender.s,recip);
799
800 strnum2[fmt_ulong(strnum2,d[c][i].delid)] = 0;
801 strnum3[fmt_ulong(strnum3,jo[j].id)] = 0;
802 log2s("starting delivery ",strnum2);
803 log3s(": msg ",strnum3,tochan[c]);
804 logsafe(recip);
805 log1s("\n");
806 del_status();
807}
808
809void markdone(int c,unsigned long id,seek_pos pos)
810{
811 struct stat st;
812 int fd;
813
814 fnmake_chanaddr(id,c);
815
816 for (;;) {
817 fd = open_write(fn.s);
818 if (fd == -1) break;
819 if (fstat(fd,&st) == -1) { close(fd); break; }
820 if (seek_set(fd,pos) == -1) { close(fd); break; }
821 if (write(fd,"D",1) != 1) { close(fd); break; }
822 /* further errors -> double delivery without us knowing about it, oh well */
823 close(fd);
824 return;
825 }
826 log3s("warning: qmail-send has trouble marking ",fn.s,"; message will be delivered twice!\n");
827}
828
829void del_dochan(int c)
830{
831 int r;
832 char ch;
833 int i;
834 int delnum;
835
836 r = read(chanfdin[c],delbuf,sizeof(delbuf));
837 if (r == -1) return;
838 if (r == 0) { spawndied(c); return; }
839
840 for (i = 0; i < r; ++i) {
841 ch = delbuf[i];
842 while (!stralloc_append(&dline[c],&ch)) nomem();
843
844 if (dline[c].len > REPORTMAX)
845 dline[c].len = REPORTMAX;
846 /* qmail-lspawn and qmail-rspawn are responsible for keeping it short */
847 /* but from a security point of view, we don't trust rspawn */
848
849 if (!ch && (dline[c].len > 1)) {
850 delnum = (unsigned int) (unsigned char) dline[c].s[0];
851 if ((delnum < 0) || (delnum >= concurrency[c]) || !d[c][delnum].used)
852 log1s("warning: qmail-send's internal error: delivery report out of range\n");
853 else {
854 strnum3[fmt_ulong(strnum3,d[c][delnum].delid)] = 0;
855 if (dline[c].s[1] == 'Z')
856 if (jo[d[c][delnum].j].flagdying) {
857 dline[c].s[1] = 'D';
858 --dline[c].len;
859 while (!stralloc_cats(&dline[c],"I'm not going to try again; this message has been in the queue too long.\n")) nomem();
860 while (!stralloc_0(&dline[c])) nomem();
861 }
862
863 switch (dline[c].s[1]) {
864 case 'K':
865 log3s("delivery ",strnum3,": success: ");
866 logsafe(dline[c].s + 2);
867 log1s("\n");
868 markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos);
869 --jo[d[c][delnum].j].numtodo;
870 break;
871 case 'Z':
872 log3s("delivery ",strnum3,": deferral: ");
873 logsafe(dline[c].s + 2);
874 log1s("\n");
875 break;
876 case 'D':
877 log3s("delivery ",strnum3,": failure: ");
878 logsafe(dline[c].s + 2);
879 log1s("\n");
880 addbounce(jo[d[c][delnum].j].id,d[c][delnum].recip.s,dline[c].s + 2);
881 markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos);
882 --jo[d[c][delnum].j].numtodo;
883 break;
884 default:
885 log3s("delivery ",strnum3,": report mangled, will defer\n");
886 }
887
888 job_close(d[c][delnum].j);
889 d[c][delnum].used = 0; --concurrencyused[c];
890 del_status();
891
892 }
893 dline[c].len = 0;
894 }
895 }
896}
897
898void del_selprep(int *nfds,fd_set *rfds)
899{
900 int c;
901
902 for (c = 0; c < CHANNELS; ++c)
903 if (flagspawnalive[c]) {
904 FD_SET(chanfdin[c],rfds);
905 if (*nfds <= chanfdin[c])
906 *nfds = chanfdin[c] + 1;
907 }
908}
909
910void del_do(fd_set *rfds)
911{
912 int c;
913
914 for (c = 0; c < CHANNELS; ++c)
915 if (flagspawnalive[c])
916 if (FD_ISSET(chanfdin[c],rfds))
917 del_dochan(c);
918}
919
920
921/* this file is too long -------------------------------------------- PASSES */
922
923struct
924{
925 unsigned long id; /* if 0, need a new pass */
926 int j; /* defined if id; job number */
927 int fd; /* defined if id; reading from {local,remote} */
928 seek_pos mpos; /* defined if id; mark position */
929 buffer b;
931}
933
935{
936 int c;
937
938 for (c = 0; c < CHANNELS; ++c) pass[c].id = 0;
939}
940
942{
943 int c;
944 struct prioq_elt pe;
945 if (flagexitasap) return;
946
947 for (c = 0; c < CHANNELS; ++c)
948 if (pass[c].id)
949 if (del_avail(c))
950 { *wakeup = 0; return; }
951
952 if (job_avail())
953 for (c = 0; c < CHANNELS; ++c)
954 if (!pass[c].id)
955 if (prioq_min(&pqchan[c],&pe))
956 if (*wakeup > pe.dt) *wakeup = pe.dt;
957
958 if (prioq_min(&pqfail,&pe))
959 if (*wakeup > pe.dt)
960 *wakeup = pe.dt;
961
962 if (prioq_min(&pqdone,&pe))
963 if (*wakeup > pe.dt)*wakeup = pe.dt;
964}
965
966static datetime_sec squareroot(datetime_sec x) /* result^2 <= x < (result + 1)^2 ; assuming: >= 0 */
967{
968 datetime_sec y;
969 datetime_sec yy;
970 datetime_sec y21;
971 int j;
972
973 y = 0; yy = 0;
974 for (j = 15; j >= 0; --j) {
975 y21 = (y << (j + 1)) + (1 << (j + j));
976 if (y21 <= x - yy) { y += (1 << j); yy += y21; }
977 }
978 return y;
979}
980
982{
983 int n;
984
985 if (birth > recent) n = 0;
986 else n = squareroot(recent - birth); /* no need to add fuzz to recent */
987
988 n += chanskip[c];
989 return birth + n * n;
990}
991
992void pass_dochan(int c)
993{
995 struct prioq_elt pe;
996 static stralloc line = {0};
997 int match;
998
999 if (flagexitasap) return;
1000
1001 if (!pass[c].id) {
1002 if (!job_avail()) return;
1003 if (!prioq_min(&pqchan[c],&pe)) return;
1004 if (pe.dt > recent) return;
1005 fnmake_chanaddr(pe.id,c);
1006
1008 pass[c].mpos = 0;
1009 pass[c].fd = open_read(fn.s);
1010 if (pass[c].fd == -1) goto trouble;
1011 if (!getinfo(&line,&birth,pe.id)) { close(pass[c].fd); goto trouble; }
1012 pass[c].id = pe.id;
1013 buffer_init(&pass[c].b,buffer_unixread,pass[c].fd,pass[c].buf,sizeof(pass[c].buf));
1014 pass[c].j = job_open(pe.id,c);
1015 jo[pass[c].j].retry = nextretry(birth,c);
1016 jo[pass[c].j].flagdying = (recent > birth + lifetime);
1017 while (!stralloc_copy(&jo[pass[c].j].sender,&line)) nomem();
1018 }
1019
1020 if (!del_avail(c)) return;
1021
1022 if (getln(&pass[c].b,&line,&match,'\0') == -1) {
1023 fnmake_chanaddr(pass[c].id,c);
1024 log3s("warning: qmail-send has trouble reading ",fn.s,"; will try again later\n");
1025 close(pass[c].fd);
1026 job_close(pass[c].j);
1027 pass[c].id = 0;
1028 return;
1029 }
1030
1031 if (!match) {
1032 close(pass[c].fd);
1033 jo[pass[c].j].flaghiteof = 1;
1034 job_close(pass[c].j);
1035 pass[c].id = 0;
1036 return;
1037 }
1038
1039 switch (line.s[0]) {
1040 case 'T':
1041 ++jo[pass[c].j].numtodo;
1042 del_start(pass[c].j,pass[c].mpos,line.s + 1);
1043 break;
1044 case 'D':
1045 break;
1046 default:
1047 fnmake_chanaddr(pass[c].id,c);
1048 log3s("warning: qmail-send recognizes unknown record type in ",fn.s,"!\n");
1049 close(pass[c].fd);
1050 job_close(pass[c].j);
1051 pass[c].id = 0;
1052 return;
1053 }
1054
1055 pass[c].mpos += line.len;
1056 return;
1057
1058 trouble:
1059 log3s("warning: qmail-send has trouble opening ",fn.s,"; will try again later\n");
1060 pe.dt = recent + SLEEP_SYSFAIL;
1061 while (!prioq_insert(&pqchan[c],&pe)) nomem();
1062}
1063
1064void messdone(unsigned long id)
1065{
1066 char ch;
1067 int c;
1068 struct prioq_elt pe;
1069 struct stat st;
1070
1071 for (c = 0; c < CHANNELS; ++c) {
1072 fnmake_chanaddr(id,c);
1073 if (stat(fn.s,&st) == 0) return; /* false alarm; consequence of HOPEFULLY */
1074 if (errno != ENOENT) {
1075 log3s("warning: qmail-send is unable to stat ",fn.s,"; will try again later\n");
1076 goto FAIL;
1077 }
1078 }
1079
1080 fnmake_todo(id);
1081 if (stat(fn.s,&st) == 0) return;
1082 if (errno != ENOENT) {
1083 log3s("warning: qmail-send is unable to stat ",fn.s,"; will try again later\n");
1084 goto FAIL;
1085 }
1086
1087 fnmake_info(id);
1088 if (stat(fn.s,&st) == -1) {
1089 if (errno == ENOENT) return;
1090 log3s("warning: qmail-send is unable to stat ",fn.s,"; will try again later\n");
1091 goto FAIL;
1092 }
1093
1094 /* -todo +info -local -remote ?bounce */
1095 if (!injectbounce(id))
1096 goto FAIL; /* injectbounce() produced error message */
1097
1098 strnum3[fmt_ulong(strnum3,id)] = 0;
1099 log3s("end msg ",strnum3,"\n");
1100
1101 /* -todo +info -local -remote -bounce */
1102 fnmake_info(id);
1103 if (unlink(fn.s) == -1) {
1104 log3s("warning: qmail-send is unable to unlink ",fn.s,"; will try again later\n");
1105 goto FAIL;
1106 }
1107
1108 /* -todo -info -local -remote -bounce; we can relax */
1109 fnmake_foop(id);
1110 if (buffer_putflush(&toqc,fn.s,fn.len) == -1) { cleandied(); return; }
1111 if (buffer_get(&fromqc,&ch,1) != 1) { cleandied(); return; }
1112 if (ch != '+') log3s("warning: qmail-clean unable to clean up ",fn.s,"\n");
1113
1114 return;
1115
1116 FAIL:
1117 pe.id = id; pe.dt = now() + SLEEP_SYSFAIL;
1118 while (!prioq_insert(&pqdone,&pe)) nomem();
1119}
1120
1122{
1123 int c;
1124 struct prioq_elt pe;
1125
1126 for (c = 0; c < CHANNELS; ++c)
1127 pass_dochan(c);
1128
1129 if (prioq_min(&pqfail,&pe))
1130 if (pe.dt <= recent) {
1132 pqadd(pe.id);
1133 }
1134
1135 if (prioq_min(&pqdone,&pe))
1136 if (pe.dt <= recent) {
1138 messdone(pe.id);
1139 }
1140}
1141
1142
1143/* this file is too long ------------------------------------- EXTERNAL TODO */
1144
1145stralloc todoline = {0};
1146char todobuf[2048];
1150
1151void tododied() {
1152 log1s("alert: qmail-send lost connection to qmail-todo ... exiting\n");
1153 flagexitasap = 1;
1154 flagtodoalive = 0;
1155}
1156
1158{
1159 todofdout = 7;
1160 todofdin = 8;
1161 flagtodoalive = 1;
1162 /* sync with external todo */
1163 if (write(todofdout,"S",1) != 1) tododied();
1164
1165 return;
1166}
1167
1168void todo_selprep(int *nfds,fd_set *rfds,datetime_sec *wakeup)
1169{
1170 if (flagexitasap) {
1171 if (flagtodoalive) {
1172 write(todofdout,"X",1);
1173 }
1174 }
1175 if (flagtodoalive) {
1176 FD_SET(todofdin,rfds);
1177 if (*nfds <= todofdin)
1178 *nfds = todofdin + 1;
1179 }
1180}
1181
1182void todo_del(char* s)
1183{
1184 int flagchan[CHANNELS];
1185 struct prioq_elt pe;
1186 unsigned long id;
1187 unsigned int len;
1188 int c;
1189
1190 for (c = 0; c < CHANNELS; ++c)
1191 flagchan[c] = 0;
1192
1193 switch (*s++) {
1194 case 'L':
1195 flagchan[0] = 1;
1196 break;
1197 case 'R':
1198 flagchan[1] = 1;
1199 break;
1200 case 'B':
1201 flagchan[0] = 1;
1202 flagchan[1] = 1;
1203 break;
1204 case 'X':
1205 break;
1206 default:
1207 log1s("warning: qmail-send is unable to understand qmail-todo\n");
1208 return;
1209 }
1210
1211 len = scan_ulong(s,&id);
1212 if (!len || s[len]) {
1213 log1s("warning: qmail-send is unable to understand qmail-todo\n");
1214 return;
1215 }
1216
1217 pe.id = id; pe.dt = now();
1218 for (c = 0; c < CHANNELS; ++c)
1219 if (flagchan[c])
1220 while (!prioq_insert(&pqchan[c],&pe)) nomem();
1221
1222 for (c = 0; c < CHANNELS; ++c)
1223 if (flagchan[c]) break;
1224
1225 if (c == CHANNELS)
1226 while (!prioq_insert(&pqdone,&pe)) nomem();
1227
1228 return;
1229}
1230
1231void todo_do(fd_set *rfds)
1232{
1233 int r;
1234 char ch;
1235 int i;
1236
1237 if (!flagtodoalive) return;
1238 if (!FD_ISSET(todofdin,rfds)) return;
1239
1240 r = read(todofdin,todobuf,sizeof(todobuf));
1241 if (r == -1) return;
1242 if (r == 0) {
1243 if (flagexitasap)
1244 flagtodoalive = 0;
1245 else
1246 tododied();
1247 return;
1248 }
1249
1250 for (i = 0; i < r; ++i) {
1251 ch = todobuf[i];
1252 while (!stralloc_append(&todoline,&ch)) nomem();
1253 if (todoline.len > REPORTMAX)
1254 todoline.len = REPORTMAX;
1255 /* qmail-todo is responsible for keeping it short */
1256 if (!ch && (todoline.len > 1)) {
1257 switch (todoline.s[0]) {
1258 case 'D':
1259 if (flagexitasap) break;
1260 todo_del(todoline.s + 1);
1261 break;
1262 case 'L':
1263 log1s(todoline.s + 1);
1264 break;
1265 case 'X':
1266 if (flagexitasap)
1267 flagtodoalive = 0;
1268 else
1269 tododied();
1270 break;
1271 default:
1272 log1s("warning: qmail-send is unable to understand qmail-todo: report mangled\n");
1273 break;
1274 }
1275 todoline.len = 0;
1276 }
1277 }
1278}
1279
1280/* this file is too long ---------------------------------------------- MAIN */
1281
1283{
1284 if (control_init() == -1) return 0;
1285 if (control_readint(&lifetime,"control/queuelifetime") == -1) return 0;
1286 if (control_readint(&concurrency[0],"control/concurrencylocal") == -1) return 0;
1287 if (control_readint(&concurrency[1],"control/concurrencyremote") == -1) return 0;
1288 if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1) return 0;
1289 if (control_rldef(&bouncefrom,"control/bouncefrom",0,"MAILER-DAEMON") != 1) return 0;
1290 if (control_rldef(&bouncehost,"control/bouncehost",1,"bouncehost") != 1) return 0;
1291 if (control_readint(&bouncemaxbytes,"control/bouncemaxbytes") == -1) return 0;
1292 if (control_rldef(&doublebouncehost,"control/doublebouncehost",1,"doublebouncehost") != 1) return 0;
1293 if (control_rldef(&doublebounceto,"control/doublebounceto",0,"postmaster") != 1) return 0;
1294 if (!stralloc_cats(&doublebounceto,"@")) return 0;
1295 if (!stralloc_cat(&doublebounceto,&doublebouncehost)) return 0;
1296 if (!stralloc_0(&doublebounceto)) return 0;
1297 if (control_readfile(&locals,"control/locals",1) != 1) return 0;
1298 if (!constmap_init(&maplocals,locals.s,locals.len,0)) return 0;
1299 switch (control_readfile(&percenthack,"control/percenthack",0)) {
1300 case -1: return 0;
1301 case 0: if (!constmap_init(&mappercenthack,"",0,0)) return 0; break;
1302 case 1: if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0)) return 0; break;
1303 }
1304 switch (control_readfile(&vdoms,"control/virtualdomains",0)) {
1305 case -1: return 0;
1306 case 0: if (!constmap_init(&mapvdoms,"",0,1)) return 0; break;
1307 case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) return 0; break;
1308 }
1309 return 1;
1310}
1311
1312stralloc newlocals = {0};
1313stralloc newvdoms = {0};
1314
1316{
1317 int r;
1318
1319 if (control_readfile(&newlocals,"control/locals",1) != 1)
1320 { log1s("alert: qmail-send is unable to reread control/locals\n"); return; }
1321 if (control_readint(&concurrency[0],"control/concurrencylocal") == -1)
1322 { log1s("alert: qmail-send is unable to reread control/concurrencylocal\n"); return; }
1323 if (control_readint(&concurrency[1],"control/concurrencyremote") == -1)
1324 { log1s("alert: qmail-send is unable to reread control/concurrencyremote\n"); return; }
1325 if (control_readint(&lifetime,"control/queuelifetime") == -1)
1326 { log1s("alert: qmail-send is unable to reread control/queuelifetime\n"); return; }
1327
1328 r = control_readfile(&newvdoms,"control/virtualdomains",0);
1329 if (r == -1) { log1s("alert: qmail-send is unable to reread control/virtualdomains\n"); return; }
1330
1333
1334 while (!stralloc_copy(&locals,&newlocals)) nomem();
1335 while (!constmap_init(&maplocals,locals.s,locals.len,0)) nomem();
1336
1337 if (r) {
1338 while (!stralloc_copy(&vdoms,&newvdoms)) nomem();
1339 while (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) nomem();
1340 } else
1341 while (!constmap_init(&mapvdoms,"",0,1)) nomem();
1342}
1343
1345{
1346 if (chdir(auto_qmail) == -1) {
1347 log1s("alert: qmail-send is unable to reread controls: unable to switch to home directory\n");
1348 return;
1349 }
1350 write(todofdout,"H",1);
1351 regetcontrols();
1352
1353 while (chdir(queuedir.s) == -1) {
1354 log1s("alert: qmail-send is unable to switch back to queue directory; HELP! sleeping...\n");
1355 sleep(10);
1356 }
1357}
1358
1359int main()
1360{
1361 int fd;
1362 datetime_sec wakeup;
1363 fd_set rfds;
1364 fd_set wfds;
1365 int nfds;
1366 struct timeval tv;
1367 int c;
1368 int u;
1369 int r;
1370 char ch;
1371
1373 if (!stralloc_cats(&queuedir,"/queue")) _exit(110);
1374 if (!stralloc_0(&queuedir)) _exit(110);
1375
1376 if (chdir(auto_qmail) == -1) { log3s("alert: qmail-send is unable to switch to home directory ",auto_qmail,"\n"); _exit(110); }
1377 if (!getcontrols()) { log1s("alert: qmail-send is unable to read controls\n"); _exit(111); }
1378 if (chdir(queuedir.s) == -1) { log3s("alert: qmail-send cannot start and is unable to switch to queue directory ",queuedir.s,"\n"); _exit(110); }
1379 sig_pipeignore();
1380 sig_termcatch(sigterm);
1381 sig_alarmcatch(sigalrm);
1382 sig_hangupcatch(sighup);
1383 sig_childdefault();
1384 umask(077);
1385
1386 fd = open_write("lock/sendmutex");
1387 if (fd == -1) { log1s("alert: qmail-send is unable to open mutex\n"); _exit(111); }
1388 if (lock_exnb(fd) == -1) { log1s("alert: qmail-send is already running\n"); _exit(111); }
1389
1390 numjobs = 0;
1391 for (c = 0;c < CHANNELS;++c) {
1392 do
1393 r = read(chanfdin[c],&ch,1);
1394
1395 while ((r == -1) && (errno == EINTR));
1396 if (r < 1) { log1s("alert: cannot start: hath the daemon spawn no fire?\n"); _exit(111); }
1397
1398 u = (unsigned int) (unsigned char) ch;
1399 if (concurrency[c] > u) concurrency[c] = u;
1400 numjobs += concurrency[c];
1401 }
1402
1403 fnmake_init();
1404
1405 comm_init();
1406
1407 pqstart();
1408 job_init();
1409 del_init();
1410 pass_init();
1411 todo_init();
1412 cleanup_init();
1413
1414 while (!flagexitasap || !del_canexit() || flagtodoalive) {
1415 recent = now();
1416
1417 if (flagrunasap) { flagrunasap = 0; pqrun(); }
1418 if (flagreadasap) { flagreadasap = 0; reread(); }
1419
1420 wakeup = recent + SLEEP_FOREVER;
1421 FD_ZERO(&rfds);
1422 FD_ZERO(&wfds);
1423 nfds = 1;
1424
1425 comm_selprep(&nfds,&wfds);
1426 del_selprep(&nfds,&rfds);
1427 pass_selprep(&wakeup);
1428 todo_selprep(&nfds,&rfds,&wakeup);
1429 cleanup_selprep(&wakeup);
1430
1431 if (wakeup <= recent) tv.tv_sec = 0;
1432 else tv.tv_sec = wakeup - recent + SLEEP_FUZZ;
1433 tv.tv_usec = 0;
1434
1435 if (select(nfds,&rfds,&wfds,(fd_set *) 0,&tv) == -1)
1436 if (errno == EINTR)
1437 ;
1438 else
1439 log1s("warning: qmail-send has trouble in select\n");
1440 else {
1441 recent = now();
1442
1443 comm_do(&wfds);
1444 del_do(&rfds);
1445 todo_do(&rfds);
1446 pass_do();
1447 cleanup_do();
1448 }
1449 }
1450
1451 pqfinish();
1452 log1s("status: qmail-send exiting\n");
1453 _exit(0);
1454}
char inbuf[BUFFER_SMALL]
Definition: auto-gid.c:9
char auto_qmail[]
char auto_queue[]
void nomem()
Definition: columnt.c:15
struct qmail qqt
Definition: condredirect.c:14
buffer bi
Definition: condredirect.c:23
void constmap_free(struct constmap *cm)
Definition: constmap.c:161
int constmap_init(struct constmap *cm, char *s, int len, int flagcolon)
Definition: constmap.c:35
int control_readint(unsigned long *i, char *fn)
Definition: control.c:72
int control_rldef(stralloc *sa, char *fn, int flagme, char *def)
Definition: control.c:42
int control_readfile(stralloc *sa, char *fn, int flagme)
Definition: control.c:87
int control_init(void)
Definition: control.c:33
long datetime_sec
Definition: datetime.h:15
int stralloc_copys(stralloc *, char const *)
stralloc sa
Definition: dnscname.c:11
void _exit(int)
char qp[FMT_ULONG]
Definition: fastforward.c:53
stralloc sender
Definition: fastforward.c:71
unsigned int fmtqfn(char *s, char *dirslash, unsigned long id, int flagsplit)
Definition: fmtqfn.c:5
#define FMTQFN
Definition: fmtqfn.h:6
void c(char *, char *, char *, int, int, int)
Definition: install.c:67
void p(char *, char *, int, int, int)
Definition: install.c:49
stralloc line
Definition: maildir2mbox.c:27
ulongalloc birth
Definition: matchup.c:64
int match
Definition: matchup.c:196
stralloc newfield_date
Definition: newfield.c:9
int newfield_datemake(datetime_sec newfield_date)
Definition: newfield.c:47
datetime_sec now()
Definition: now.c:5
struct prioq_elt *int prioq_min(prioq *, struct prioq_elt *)
Definition: prioq.c:24
void prioq_delmin(prioq *)
Definition: prioq.c:32
struct utmpx * ut
Definition: qbiff.c:40
void report(buffer *log, int wstat, char *s, int len)
Definition: qmail-lspawn.c:29
int
Definition: qmail-mrtg.c:27
readsubdir rs
Definition: qmail-qread.c:18
struct datetime dt
Definition: qmail-queue.c:35
stralloc recip
Definition: qmail-remote.c:101
long bouncemaxbytes
Definition: qmail-send.c:42
datetime_sec recent
Definition: qmail-send.c:90
char fnmake_strnum[FMT_ULONG]
Definition: qmail-send.c:97
prioq pqdone
Definition: qmail-send.c:314
void pqfinish()
Definition: qmail-send.c:378
char strnum2[FMT_ULONG]
Definition: qmail-send.c:58
void cleandied()
Definition: qmail-send.c:73
void pqadd(unsigned long id)
Definition: qmail-send.c:320
void todo_init()
Definition: qmail-send.c:1157
prioq pqfail
Definition: qmail-send.c:318
#define CHANNELS
Definition: qmail-send.c:61
int flagreadasap
Definition: qmail-send.c:71
char buf[BUFSIZE_SMALL]
Definition: qmail-send.c:930
int del_avail(int c)
Definition: qmail-send.c:773
void fnmake_todo(unsigned long id)
Definition: qmail-send.c:106
void fnmake_foop(unsigned long id)
Definition: qmail-send.c:108
void messdone(unsigned long id)
Definition: qmail-send.c:1064
void fnmake_info(unsigned long id)
Definition: qmail-send.c:105
int job_open(unsigned long id, int channel)
Definition: qmail-send.c:445
buffer toqc
Definition: qmail-send.c:172
stralloc fn
Definition: qmail-send.c:95
void sigalrm()
Definition: qmail-send.c:70
int getinfo(stralloc *sa, datetime_sec *dt, unsigned long id)
Definition: qmail-send.c:144
int j
Definition: qmail-send.c:926
stralloc dline[CHANNELS]
Definition: qmail-send.c:727
void markdone(int c, unsigned long id, seek_pos pos)
Definition: qmail-send.c:809
stralloc bouncehost
Definition: qmail-send.c:54
stralloc doublebouncehost
Definition: qmail-send.c:56
unsigned long concurrencyused[CHANNELS]
Definition: qmail-send.c:725
char * chanaddr[CHANNELS]
Definition: qmail-send.c:62
stralloc queuedir
Definition: qmail-send.c:44
void pqstart()
Definition: qmail-send.c:366
stralloc vdoms
Definition: qmail-send.c:50
void fnmake_split(unsigned long id)
Definition: qmail-send.c:109
int getcontrols()
Definition: qmail-send.c:1282
int flagexitasap
Definition: qmail-send.c:69
void pass_do()
Definition: qmail-send.c:1121
struct job * jo
Definition: qmail-send.c:423
void cleanup_selprep(datetime_sec *wakeup)
Definition: qmail-send.c:268
void tododied()
Definition: qmail-send.c:1151
void todo_del(char *s)
Definition: qmail-send.c:1182
void pass_dochan(int c)
Definition: qmail-send.c:992
int injectbounce(unsigned long id)
Definition: qmail-send.c:573
void addbounce(unsigned long id, char *recip, char *report)
Definition: qmail-send.c:524
void job_close(int j)
Definition: qmail-send.c:460
void regetcontrols()
Definition: qmail-send.c:1315
stralloc envnoathost
Definition: qmail-send.c:52
buffer b
Definition: qmail-send.c:929
stralloc todoline
Definition: qmail-send.c:1145
int flagrunasap
Definition: qmail-send.c:70
int fd
Definition: qmail-send.c:927
stralloc locals
Definition: qmail-send.c:48
char toqcbuf[BUFSIZE_LINE]
Definition: qmail-send.c:173
void spawndied(int c)
Definition: qmail-send.c:81
void cleanup_do()
Definition: qmail-send.c:274
void del_status()
Definition: qmail-send.c:730
char todobuf[2048]
Definition: qmail-send.c:1146
stralloc percenthack
Definition: qmail-send.c:46
char fromqcbuf[BUFSIZE_LINE]
Definition: qmail-send.c:175
struct @1 pass[CHANNELS]
stralloc bouncetext
Definition: qmail-send.c:522
stralloc fn2
Definition: qmail-send.c:96
struct constmap mappercenthack
Definition: qmail-send.c:47
void del_do(fd_set *rfds)
Definition: qmail-send.c:910
seek_pos mpos
Definition: qmail-send.c:928
void del_init()
Definition: qmail-send.c:745
void comm_write(int c, int delnum, unsigned long id, char *sender, char *recip)
Definition: qmail-send.c:198
int chanfdin[CHANNELS]
Definition: qmail-send.c:66
datetime_sec cleanuptime
Definition: qmail-send.c:260
int job_avail()
Definition: qmail-send.c:436
int chanskip[CHANNELS]
Definition: qmail-send.c:67
void sighup()
Definition: qmail-send.c:71
void fnmake_mess(unsigned long id)
Definition: qmail-send.c:107
void todo_do(fd_set *rfds)
Definition: qmail-send.c:1231
void pass_selprep(datetime_sec *wakeup)
Definition: qmail-send.c:941
stralloc doublebounceto
Definition: qmail-send.c:55
int flagspawnalive[CHANNELS]
Definition: qmail-send.c:79
int flagcleanup
Definition: qmail-send.c:258
unsigned long concurrency[CHANNELS]
Definition: qmail-send.c:724
void comm_do(fd_set *wfds)
Definition: qmail-send.c:229
void comm_selprep(int *nfds, fd_set *wfds)
Definition: qmail-send.c:216
stralloc newlocals
Definition: qmail-send.c:1312
int del_canexit()
Definition: qmail-send.c:763
char strnum3[FMT_ULONG]
Definition: qmail-send.c:59
void comm_init()
Definition: qmail-send.c:179
buffer fromqc
Definition: qmail-send.c:174
void todo_selprep(int *nfds, fd_set *rfds, datetime_sec *wakeup)
Definition: qmail-send.c:1168
void reread()
Definition: qmail-send.c:1344
stralloc newvdoms
Definition: qmail-send.c:1313
void job_init()
Definition: qmail-send.c:425
void senderadd(stralloc *sa, char *sender, char *recip)
Definition: qmail-send.c:116
struct del * d[CHANNELS]
Definition: qmail-send.c:726
readsubdir cleanupdir
Definition: qmail-send.c:259
long lifetime
Definition: qmail-send.c:41
char * stripvdomprepend(char *recip)
Definition: qmail-send.c:497
char * tochan[CHANNELS]
Definition: qmail-send.c:64
unsigned long masterdelid
Definition: qmail-send.c:723
void del_start(int j, seek_pos mpos, char *recip)
Definition: qmail-send.c:778
void pqrun()
Definition: qmail-send.c:395
char * chanstatusmsg[CHANNELS]
Definition: qmail-send.c:63
datetime_sec nextretry(datetime_sec birth, int c)
Definition: qmail-send.c:981
int comm_pos[CHANNELS]
Definition: qmail-send.c:177
struct constmap maplocals
Definition: qmail-send.c:49
stralloc comm_buf[CHANNELS]
Definition: qmail-send.c:176
void fnmake_init()
Definition: qmail-send.c:99
prioq pqchan[CHANNELS]
Definition: qmail-send.c:315
void del_dochan(int c)
Definition: qmail-send.c:829
int numjobs
Definition: qmail-send.c:422
void fnmake_chanaddr(unsigned long id, int c)
Definition: qmail-send.c:111
void pass_init()
Definition: qmail-send.c:934
stralloc bouncefrom
Definition: qmail-send.c:53
int main()
Definition: qmail-send.c:1359
void cleanup_init()
Definition: qmail-send.c:262
int todofdout
Definition: qmail-send.c:1148
#define REPORTMAX
Definition: qmail-send.c:88
unsigned long id
Definition: qmail-send.c:925
void del_selprep(int *nfds, fd_set *rfds)
Definition: qmail-send.c:898
char delbuf[2048]
Definition: qmail-send.c:728
struct constmap mapvdoms
Definition: qmail-send.c:51
void fnmake2_bounce(unsigned long id)
Definition: qmail-send.c:110
int chanfdout[CHANNELS]
Definition: qmail-send.c:65
#define CHECKSTAT
int todofdin
Definition: qmail-send.c:1147
int flagtodoalive
Definition: qmail-send.c:1149
void sigterm()
Definition: qmail-send.c:69
int comm_canwrite(void)
Definition: qmail-todo.c:200
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
#define BUFSIZE_SMALL
Definition: qmail.h:12
unsigned long qmail_qp(struct qmail *)
Definition: qmail.c:53
void qmail_puts(struct qmail *, char *)
Definition: qmail.c:68
int qmail_open(struct qmail *)
Definition: qmail.c:21
void qmail_fail(struct qmail *)
Definition: qmail.c:58
stralloc quoted
Definition: qreceipt.c:63
void log1s(char *)
Definition: qsutil.c:17
void logsafe(char *)
Definition: qsutil.c:72
void pausedir(char *)
Definition: qsutil.c:58
void log2s(char *, char *)
Definition: qsutil.c:22
void log3s(char *, char *, char *)
Definition: qsutil.c:28
int quote(stralloc *, stralloc *)
Definition: quote.c:62
int quote2(stralloc *, char *)
Definition: quote.c:70
void readsubdir_init(readsubdir *, char *, void(*)())
Definition: readsubdir.c:7
int readsubdir_next(readsubdir *, unsigned long *)
Definition: readsubdir.c:17
#define SLEEP_FOREVER
Definition: sendtodo.h:9
#define SLEEP_CLEANUP
Definition: sendtodo.h:10
#define SLEEP_SYSFAIL
Definition: sendtodo.h:11
#define OSSIFIED
Definition: sendtodo.h:12
#define SLEEP_FUZZ
Definition: sendtodo.h:8
uint32_t k[64]
Definition: sha256.c:26
int delnum
Definition: spawn.c:78
stralloc domain
Definition: spf.c:34
stralloc recip
Definition: qmail-send.c:720
int j
Definition: qmail-send.c:717
int used
Definition: qmail-send.c:716
seek_pos mpos
Definition: qmail-send.c:719
unsigned long delid
Definition: qmail-send.c:718
datetime_sec retry
Definition: qmail-send.c:415
int refs
Definition: qmail-send.c:412
int numtodo
Definition: qmail-send.c:417
stralloc sender
Definition: qmail-send.c:416
int flagdying
Definition: qmail-send.c:419
int channel
Definition: qmail-send.c:414
int flaghiteof
Definition: qmail-send.c:418
unsigned long id
Definition: qmail-send.c:413
Definition: prioq.h:7
datetime_sec dt
Definition: prioq.h:7
unsigned long id
Definition: prioq.h:7
Definition: qmail.h:14
void write()