commit 7d8b5c08a9e5e1a792650fb945ed9efc1b104ec0
parent 7347f3a3a5b9163b3904c004b2a825db89a852ec
Author: Ellenor Bjornsdottir <ellenor@umbrellix.net>
Date: Tue, 25 Oct 2022 15:53:35 +0000
text changes, indent roughshodding
Diffstat:
24 files changed, 3257 insertions(+), 2064 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -384,3 +384,4 @@ src/mxf-remote/mxf-remote
src/netstrings.o
src/nmail-smtpd.o
nmail-smtpd
+*.BAK
diff --git a/Makefile.legacy b/Makefile.legacy
@@ -1339,11 +1339,11 @@ doc/man/qmail-qstat.0: \
doc/man/qmail-qstat.8
qmail-queue: \
-load src/qmail-queue.o src/triggerpull.o src/fmtqfn.o src/date822fmt.o \
+load src/qmail-queue.o src/triggerpull.o src/fmtqfn.o src/date822fmt.o src/stralloc.a \
src/datetime.a src/ndelay.a src/open.a src/sig.a src/substdio.a src/error.a \
src/str.a src/fs.a src/auto_qmail.o src/auto_split.o src/ids.a
./load qmail-queue src/triggerpull.o src/fmtqfn.o \
- src/date822fmt.o src/datetime.a src/ndelay.a src/open.a src/sig.a \
+ src/date822fmt.o src/stralloc.a src/datetime.a src/ndelay.a src/open.a src/sig.a \
src/auto_qmail.o src/auto_split.o src/ids.a \
src/substdio.a src/error.a src/str.a src/fs.a
diff --git a/include/alloc.h b/include/alloc.h
@@ -2,10 +2,20 @@
#define ALLOC_H
#include <stdlib.h>
+#include <string.h>
#include "deprecated.h"
-#define alloc(x) malloc(x)
+//#define alloc(x) malloc(x)
+
+// secure alloc(): zero bytes before use.
+// prevents heartbleed. Hilda
+static inline void *alloc(size_t x)
+{
+ void *y = malloc(x);
+ if (!(y == NULL)) memset(y, 0, x);
+ return y;
+}
#define alloc_free(x) free(x)
#ifdef DEPRECATED_FUNCTIONS_AVAILABLE
diff --git a/src/fmtqfn.c b/src/fmtqfn.c
@@ -1,25 +1,49 @@
#include "fmtqfn.h"
-
+#include "stralloc.h"
+#include <errno.h>
+#define AMNESIAC (errno = ENOMEM, -1)
#include "fmt.h"
#include "auto_split.h"
-unsigned int fmtqfn(s,dirslash,id,flagsplit)
-char *s;
-char *dirslash;
-unsigned long id;
-int flagsplit;
+/* ForMaT Queue FileName
+ * The bleak Bernstein original.
+ * Requires a buffer long enough for it.
+ * Always no more than FMTQFN bytes (40 if
+ * len(dirslash) le 10)
+ * given inode numbers generally can't exceed 18446744073709551616,
+ * a 20 character string at any rate, this is futureproof.
+ */
+unsigned int fmtqfn(char *s, char *dirslash,
+ unsigned long id, int flagsplit)
{
unsigned int len;
unsigned int i;
len = 0;
i = fmt_str(s,dirslash); len += i; if (s) s += i;
- if (flagsplit)
- {
- i = fmt_ulong(s,id % auto_split); len += i; if (s) s += i;
- i = fmt_str(s,"/"); len += i; if (s) s += i;
+ if (0 != flagsplit) {
+ i = fmt_ulong(s,id % auto_split); // generate the hash
+ len += i;
+ if (s) s += i; // slide the pointer cursor up one byte
+ i = fmt_str(s,"/");
+ len += i;
+ if (s) s += i; // CURSOR
}
- i = fmt_ulong(s,id); len += i; if (s) s += i;
+ i = fmt_ulong(s,id);
+ len += i;
+ if (s) s += i;
if (s) *s++ = 0; ++len;
return len;
}
+
+/* ForMaT Queue FileName StrAlloc
+ * This allows passing in a SA to write the filename to.
+ * This unavoidably calls fmtqfn twice.
+ */
+int fmtqfnsa (stralloc *sa, char *dirslash,
+ unsigned long id, int flagsplit)
+{
+ if (!stralloc_ready(sa, fmtqfn(NULL, dirslash, id, flagsplit))) return AMNESIAC;
+ if (!fmtqfn(sa->s, dirslash, id, flagsplit)) return AMNESIAC;
+ return sa->len;
+}
diff --git a/src/hier.c b/src/hier.c
@@ -133,6 +133,7 @@ void hier()
c(auto_qmail,"bin",/*"src"*/".","qmail-qmqpd",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin",/*"src"*/".","qmail-qmtpd",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin",/*"src"*/".","qmail-smtpd",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"bin",/*"src"*/".","nmail-smtpd",auto_uido,auto_gidq,0755); // the alternative SMTPD
c(auto_qmail,"bin",/*"src"*/".","sendmail",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin",/*"src"*/".","tcp-env",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin",/*"src"*/".","qreceipt",auto_uido,auto_gidq,0755);
diff --git a/src/mxf-send/cleanup.c b/src/mxf-send/cleanup.c
@@ -1,60 +1,76 @@
#include "mxf-send.h"
/* this file is too long ------------------------------------------ CLEANUPS */
-int flagcleanup; /* if 1, cleanupdir is initialized and ready */
+int flagcleanup; /* if 1, cleanupdir is initialized and ready */
readsubdir cleanupdir;
datetime_sec cleanuptime;
-void cleanup_init()
+void
+cleanup_init()
{
- flagcleanup = 0;
- cleanuptime = now();
+ flagcleanup = 0;
+ cleanuptime = now();
}
-void cleanup_selprep(datetime_sec *wakeup)
+void
+cleanup_selprep(datetime_sec * wakeup)
{
- if (flagcleanup) *wakeup = 0;
- if (*wakeup > cleanuptime) *wakeup = cleanuptime;
+ if (flagcleanup)
+ *wakeup = 0;
+ if (*wakeup > cleanuptime)
+ *wakeup = cleanuptime;
}
-void cleanup_do()
+void
+cleanup_do()
{
- char ch;
- struct stat st;
- unsigned long id;
-
- if (!flagcleanup)
- {
- if (recent < cleanuptime) return;
- readsubdir_init(&cleanupdir,"mess",pausedir);
- flagcleanup = 1;
- }
-
- switch(readsubdir_next(&cleanupdir,&id))
- {
- case 1:
- break;
- case 0:
- flagcleanup = 0;
- cleanuptime = recent + SLEEP_CLEANUP;
- default:
- return;
- }
-
- fnmake_mess(id);
- if (stat(fn.s,&st) == -1) return; /* probably qmail-queue deleted it */
- if (recent <= st.st_atime + OSSIFIED) return;
-
- fnmake_info(id);
- if (stat(fn.s,&st) == 0) return;
- if (errno != error_noent) return;
- fnmake_todo(id);
- if (stat(fn.s,&st) == 0) return;
- if (errno != error_noent) return;
-
- fnmake_foop(id);
- if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; }
- if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; }
- if (ch != '+')
- log3("warning: qmail-clean unable to clean up ",fn.s,"\n");
+ char ch;
+ struct stat st;
+ unsigned long id;
+
+ if (!flagcleanup) {
+ if (recent < cleanuptime)
+ return;
+ readsubdir_init(&cleanupdir, "mess", pausedir);
+ flagcleanup = 1;
+ }
+
+ switch (readsubdir_next(&cleanupdir, &id)) {
+ case 1:
+ break;
+ case 0:
+ flagcleanup = 0;
+ cleanuptime = recent + SLEEP_CLEANUP;
+ default:
+ return;
+ }
+
+ fnmake_mess(id);
+ if (stat(fn.s, &st) == -1)
+ return; /* probably qmail-queue deleted it */
+ if (recent <= st.st_atime + OSSIFIED)
+ return;
+
+ fnmake_info(id);
+ if (stat(fn.s, &st) == 0)
+ return;
+ if (errno != error_noent)
+ return;
+ fnmake_todo(id);
+ if (stat(fn.s, &st) == 0)
+ return;
+ if (errno != error_noent)
+ return;
+
+ fnmake_foop(id);
+ if (substdio_putflush(&sstoqc, fn.s, fn.len) == -1) {
+ cleandied();
+ return;
+ }
+ if (substdio_get(&ssfromqc, &ch, 1) != 1) {
+ cleandied();
+ return;
+ }
+ if (ch != '+')
+ log3("warning: qmail-clean unable to clean up ", fn.s, "\n");
}
diff --git a/src/mxf-send/comm.c b/src/mxf-send/comm.c
@@ -1,83 +1,104 @@
#include "mxf-send.h"
/* this file is too long ------------------------------------- COMMUNICATION */
-substdio sstoqc; char sstoqcbuf[1024];
-substdio ssfromqc; char ssfromqcbuf[1024];
-stralloc comm_buf[CHANNELS] = { {0}, {0} };
+// Why's cleanup a separate function? it should just be a channel...
+substdio sstoqc;
+char sstoqcbuf[1024];
+substdio ssfromqc;
+char ssfromqcbuf[1024];
+
+stralloc comm_buf[CHANNELS] = {{0}, {0}};
int comm_pos[CHANNELS];
-void comm_init()
+void
+comm_init()
{
- int c;
- substdio_fdbuf(&sstoqc,write,5,sstoqcbuf,sizeof(sstoqcbuf));
- substdio_fdbuf(&ssfromqc,read,6,ssfromqcbuf,sizeof(ssfromqcbuf));
- for (c = 0;c < CHANNELS;++c)
- if (ndelay_on(chanfdout[c]) == -1)
- /* this is so stupid: NDELAY semantics should be default on write */
- spawndied(c); /* drastic, but better than risking deadlock */
+ int c;
+ // special casing...
+ // this also relies on those FDs being, well...
+ substdio_fdbuf(&sstoqc, write, 5, sstoqcbuf, sizeof(sstoqcbuf));
+ substdio_fdbuf(&ssfromqc, read, 6, ssfromqcbuf, sizeof(ssfromqcbuf));
+ for (c = 0; c < CHANNELS; ++c)
+ if (ndelay_on(chanfdout[c]) == -1)
+ /*
+ * this is so stupid: NDELAY semantics should be
+ * default on write
+ */
+ spawndied(c); /* drastic, but better than risking
+ * deadlock */
}
-int comm_canwrite(int c)
+int
+comm_canwrite(int c)
{
- /* XXX: could allow a bigger buffer; say 10 recipients */
- if (comm_buf[c].s && comm_buf[c].len) return 0;
- return 1;
+ /* XXX: could allow a bigger buffer; say 10 recipients */
+ if (comm_buf[c].s && comm_buf[c].len)
+ return 0;
+ return 1;
}
-void comm_write(int c, int delnum, unsigned long id, char *sender, char *recip)
+void
+comm_write(int c, int delnum, unsigned long id, char *sender, char *recip)
{
- char ch;
- if (comm_buf[c].s && comm_buf[c].len) return;
- while (!stralloc_copys(&comm_buf[c],"")) nomem();
- ch = delnum;
- while (!stralloc_append(&comm_buf[c],&ch)) nomem();
- fnmake_split(id);
- while (!stralloc_cats(&comm_buf[c],fn.s)) nomem();
- while (!stralloc_0(&comm_buf[c])) nomem();
- senderadd(&comm_buf[c],sender,recip);
- while (!stralloc_0(&comm_buf[c])) nomem();
- while (!stralloc_cats(&comm_buf[c],recip)) nomem();
- while (!stralloc_0(&comm_buf[c])) nomem();
- comm_pos[c] = 0;
+ char ch;
+ if (comm_buf[c].s && comm_buf[c].len)
+ return;
+ while (!stralloc_copys(&comm_buf[c], ""))
+ nomem();
+ ch = delnum;
+ while (!stralloc_append(&comm_buf[c], &ch))
+ nomem();
+ fnmake_split(id);
+ while (!stralloc_cats(&comm_buf[c], fn.s))
+ nomem();
+ while (!stralloc_0(&comm_buf[c]))
+ nomem();
+ senderadd(&comm_buf[c], sender, recip);
+ while (!stralloc_0(&comm_buf[c]))
+ nomem();
+ while (!stralloc_cats(&comm_buf[c], recip))
+ nomem();
+ while (!stralloc_0(&comm_buf[c]))
+ nomem();
+ comm_pos[c] = 0;
}
-void comm_selprep(int *nfds, fd_set *wfds)
+void
+comm_selprep(int *nfds, fd_set * wfds)
{
- int c;
- for (c = 0;c < CHANNELS;++c)
- if (flagspawnalive[c])
- if (comm_buf[c].s && comm_buf[c].len)
- {
- FD_SET(chanfdout[c],wfds);
- if (*nfds <= chanfdout[c])
- *nfds = chanfdout[c] + 1;
- }
+ int c;
+ for (c = 0; c < CHANNELS; ++c)
+ if (flagspawnalive[c])
+ if (comm_buf[c].s && comm_buf[c].len) {
+ FD_SET(chanfdout[c], wfds); // if we had iolib, we could do this better.
+ if (*nfds <= chanfdout[c])
+ *nfds = chanfdout[c] + 1;
+ }
}
-void comm_do(fd_set *wfds)
+void
+comm_do(fd_set * wfds)
{
- int c;
- for (c = 0;c < CHANNELS;++c)
- if (flagspawnalive[c])
- if (comm_buf[c].s && comm_buf[c].len)
- if (FD_ISSET(chanfdout[c],wfds))
- {
- int w;
- int len;
- len = comm_buf[c].len;
- w = write(chanfdout[c],comm_buf[c].s + comm_pos[c],len - comm_pos[c]);
- if (w == 0 || w == -1)
- {
- if ((w == -1) && (errno == error_pipe))
- spawndied(c);
- else
- continue; /* kernel select() bug; can't avoid busy-looping */
- }
- else
- {
- comm_pos[c] += w;
- if (comm_pos[c] == len)
- comm_buf[c].len = 0;
- }
- }
+ int c;
+ for (c = 0; c < CHANNELS; ++c)
+ if (flagspawnalive[c])
+ if (comm_buf[c].s && comm_buf[c].len)
+ if (FD_ISSET(chanfdout[c], wfds)) {
+ int w; // isn't this just a nonblocking substdio?!
+ int len;
+ len = comm_buf[c].len;
+ w = write(chanfdout[c], comm_buf[c].s + comm_pos[c], len - comm_pos[c]);
+ if (w == 0 || w == -1) {
+ if ((w == -1) && (errno == error_pipe))
+ spawndied(c);
+ else
+ continue; /* kernel select() bug;
+ * can't avoid
+ * busy-looping */
+ } else {
+ comm_pos[c] += w;
+ if (comm_pos[c] == len)
+ comm_buf[c].len = 0;
+ }
+ }
}
diff --git a/src/mxf-send/deliveries.c b/src/mxf-send/deliveries.c
@@ -1,201 +1,245 @@
#include "mxf-send.h"
/* this file is too long ---------------------------------------- DELIVERIES */
-struct del
- {
- int used;
- int j;
- unsigned long delid;
- seek_pos mpos;
- stralloc recip;
- }
+struct del {
+ int used;
+ int j;
+ unsigned long delid;
+ seek_pos mpos;
+ stralloc recip;
+}
;
unsigned long masterdelid = 1;
-unsigned int concurrency[CHANNELS] = { 10, 20 };
-unsigned int concurrencyused[CHANNELS] = { 0, 0 };
+unsigned int concurrency[CHANNELS] = {10, 20};
+unsigned int concurrencyused[CHANNELS] = {0, 0};
struct del *d[CHANNELS];
stralloc dline[CHANNELS];
char delbuf[2048];
-void del_status()
+void
+del_status()
{
- int c;
-
- log1("status:");
- for (c = 0;c < CHANNELS;++c) {
- strnum2[fmt_ulong(strnum2,(unsigned long) concurrencyused[c])] = 0;
- strnum3[fmt_ulong(strnum3,(unsigned long) concurrency[c])] = 0;
- qslog2(chanstatusmsg[c],strnum2);
- qslog2("/",strnum3);
- }
- if (flagexitasap) log1(" exitasap");
- log1("\n");
+ int c;
+
+ log1("status:");
+ for (c = 0; c < CHANNELS; ++c) {
+ strnum2[fmt_ulong(strnum2, (unsigned long)concurrencyused[c])] = 0;
+ strnum3[fmt_ulong(strnum3, (unsigned long)concurrency[c])] = 0;
+ qslog2(chanstatusmsg[c], strnum2);
+ qslog2("/", strnum3);
+ }
+ if (flagexitasap)
+ log1(" exitasap");
+ log1("\n");
}
-void del_init()
+void
+del_init()
{
- int c;
- unsigned int i;
- for (c = 0;c < CHANNELS;++c)
- {
- flagspawnalive[c] = 1;
- while (!(d[c] = (struct del *) alloc(concurrency[c] * sizeof(struct del))))
- nomem();
- for (i = 0;i < concurrency[c];++i)
- { d[c][i].used = 0; d[c][i].recip.s = 0; }
- dline[c].s = 0;
- while (!stralloc_copys(&dline[c],"")) nomem();
- }
- del_status();
+ int c;
+ unsigned int i;
+ for (c = 0; c < CHANNELS; ++c) {
+ flagspawnalive[c] = 1;
+ while (!(d[c] = (struct del *)alloc(concurrency[c] * sizeof(struct del))))
+ nomem();
+ for (i = 0; i < concurrency[c]; ++i) {
+ d[c][i].used = 0;
+ d[c][i].recip.s = 0;
+ }
+ dline[c].s = 0;
+ while (!stralloc_copys(&dline[c], ""))
+ nomem();
+ }
+ del_status();
}
-int del_canexit()
+int
+del_canexit()
{
- int c;
- for (c = 0;c < CHANNELS;++c)
- if (flagspawnalive[c]) /* if dead, nothing we can do about its jobs */
- if (concurrencyused[c]) return 0;
- return 1;
+ int c;
+ for (c = 0; c < CHANNELS; ++c)
+ if (flagspawnalive[c]) /* if dead, nothing we can do about
+ * its jobs */
+ if (concurrencyused[c])
+ return 0;
+ return 1;
}
-int del_avail(int c) {
- return flagspawnalive[c] && comm_canwrite(c) && (concurrencyused[c] < concurrency[c]);
+int
+del_avail(int c)
+{
+ return flagspawnalive[c] && comm_canwrite(c) && (concurrencyused[c] < concurrency[c]);
}
-void del_start(int j, seek_pos mpos, char *recip)
+void
+del_start(int j, seek_pos mpos, char *recip)
{
- unsigned int i;
- int c;
-
- c = jo[j].channel;
- if (!flagspawnalive[c]) return;
- if (!comm_canwrite(c)) return;
-
- for (i = 0;i < concurrency[c];++i) if (!d[c][i].used) break;
- if (i == concurrency[c]) return;
-
- if (!stralloc_copys(&d[c][i].recip,recip)) { nomem(); return; }
- if (!stralloc_0(&d[c][i].recip)) { nomem(); return; }
- d[c][i].j = j; ++jo[j].refs;
- d[c][i].delid = masterdelid++;
- d[c][i].mpos = mpos;
- d[c][i].used = 1; ++concurrencyused[c];
-
- comm_write(c,i,jo[j].id,jo[j].sender.s,recip);
-
- strnum2[fmt_ulong(strnum2,d[c][i].delid)] = 0;
- strnum3[fmt_ulong(strnum3,jo[j].id)] = 0;
- qslog2("starting delivery ",strnum2);
- log3(": msg ",strnum3,tochan[c]);
- logsafe(recip);
- log1("\n");
- del_status();
+ unsigned int i;
+ int c;
+
+ c = jo[j].channel;
+ if (!flagspawnalive[c])
+ return;
+ if (!comm_canwrite(c))
+ return;
+
+ for (i = 0; i < concurrency[c]; ++i)
+ if (!d[c][i].used)
+ break;
+ if (i == concurrency[c])
+ return;
+
+ if (!stralloc_copys(&d[c][i].recip, recip)) {
+ nomem();
+ return;
+ }
+ if (!stralloc_0(&d[c][i].recip)) {
+ nomem();
+ return;
+ }
+ d[c][i].j = j;
+ ++jo[j].refs;
+ d[c][i].delid = masterdelid++;
+ d[c][i].mpos = mpos;
+ d[c][i].used = 1;
+ ++concurrencyused[c];
+
+ comm_write(c, i, jo[j].id, jo[j].sender.s, recip);
+
+ strnum2[fmt_ulong(strnum2, d[c][i].delid)] = 0;
+ strnum3[fmt_ulong(strnum3, jo[j].id)] = 0;
+ qslog2("starting delivery ", strnum2);
+ log3(": msg ", strnum3, tochan[c]);
+ logsafe(recip);
+ log1("\n");
+ del_status();
}
-void markdone(int c, unsigned long id, seek_pos pos)
+void
+markdone(int c, unsigned long id, seek_pos pos)
{
- struct stat st;
- int fd;
- fnmake_chanaddr(id,c);
- for (;;)
- {
- fd = open_write(fn.s);
- if (fd == -1) break;
- if (fstat(fd,&st) == -1) { close(fd); break; }
- if (seek_set(fd,pos) == -1) { close(fd); break; }
- if (write(fd,"D",1) != 1) { close(fd); break; }
- /* further errors -> double delivery without us knowing about it, oh well */
- close(fd);
- return;
- }
- log3("warning: trouble marking ",fn.s,"; message will be delivered twice!\n");
+ struct stat st;
+ int fd;
+ fnmake_chanaddr(id, c);
+ for (;;) {
+ fd = open_write(fn.s);
+ if (fd == -1)
+ break;
+ if (fstat(fd, &st) == -1) {
+ close(fd);
+ break;
+ }
+ if (seek_set(fd, pos) == -1) {
+ close(fd);
+ break;
+ }
+ if (write(fd, "D", 1) != 1) {
+ close(fd);
+ break;
+ }
+ /*
+ * further errors -> double delivery without us knowing about
+ * it, oh well
+ */
+ close(fd);
+ return;
+ }
+ log3("warning: trouble marking ", fn.s, "; message will be delivered twice!\n");
}
-void del_dochan(int c)
+void
+del_dochan(int c)
{
- int r;
- char ch;
- int i;
- int delnum;
- r = read(chanfdin[c],delbuf,sizeof(delbuf));
- if (r == -1) return;
- if (r == 0) { spawndied(c); return; }
- for (i = 0;i < r;++i)
- {
- ch = delbuf[i];
- while (!stralloc_append(&dline[c],&ch)) nomem();
- if (dline[c].len > REPORTMAX)
- dline[c].len = REPORTMAX;
- /* qmail-lspawn and qmail-rspawn are responsible for keeping it short */
- /* but from a security point of view, we don't trust rspawn */
- if (!ch && (dline[c].len > 1))
- {
- delnum = (unsigned int) (unsigned char) dline[c].s[0];
- if ((delnum < 0) || (delnum >= concurrency[c]) || !d[c][delnum].used)
- log1("warning: internal error: delivery report out of range\n");
- else
- {
- strnum3[fmt_ulong(strnum3,d[c][delnum].delid)] = 0;
- if (dline[c].s[1] == 'Z')
- if (jo[d[c][delnum].j].flagdying)
- {
- dline[c].s[1] = 'D';
- --dline[c].len;
- while (!stralloc_cats(&dline[c],"I'm not going to try again; this message has been in the queue too long.\n")) nomem();
- while (!stralloc_0(&dline[c])) nomem();
- }
- switch(dline[c].s[1])
- {
- case 'K':
- log3("delivery ",strnum3,": success: ");
- logsafe(dline[c].s + 2);
- log1("\n");
- markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos);
- --jo[d[c][delnum].j].numtodo;
- break;
- case 'Z':
- log3("delivery ",strnum3,": deferral: ");
- logsafe(dline[c].s + 2);
- log1("\n");
- break;
- case 'D':
- log3("delivery ",strnum3,": failure: ");
- logsafe(dline[c].s + 2);
- log1("\n");
- addbounce(jo[d[c][delnum].j].id,d[c][delnum].recip.s,dline[c].s + 2);
- markdone(c,jo[d[c][delnum].j].id,d[c][delnum].mpos);
- --jo[d[c][delnum].j].numtodo;
- break;
- default:
- log3("delivery ",strnum3,": report mangled, will defer\n");
+ int r;
+ char ch;
+ int i;
+ int delnum;
+ r = read(chanfdin[c], delbuf, sizeof(delbuf));
+ if (r == -1)
+ return;
+ if (r == 0) {
+ spawndied(c);
+ return;
+ }
+ for (i = 0; i < r; ++i) {
+ ch = delbuf[i];
+ while (!stralloc_append(&dline[c], &ch))
+ nomem();
+ if (dline[c].len > REPORTMAX)
+ dline[c].len = REPORTMAX;
+ /*
+ * qmail-lspawn and qmail-rspawn are responsible for keeping
+ * it short
+ */
+ /* but from a security point of view, we don't trust rspawn */
+ if (!ch && (dline[c].len > 1)) {
+ delnum = (unsigned int)(unsigned char)dline[c].s[0];
+ if ((delnum < 0) || (delnum >= concurrency[c]) || !d[c][delnum].used)
+ log1("warning: internal error: delivery report out of range\n");
+ else {
+ strnum3[fmt_ulong(strnum3, d[c][delnum].delid)] = 0;
+ if (dline[c].s[1] == 'Z')
+ if (jo[d[c][delnum].j].flagdying) {
+ dline[c].s[1] = 'D';
+ --dline[c].len;
+ while (!stralloc_cats(&dline[c], "I'm not going to try again; this message has been in the queue too long.\n"))
+ nomem();
+ while (!stralloc_0(&dline[c]))
+ nomem();
+ }
+ switch (dline[c].s[1]) {
+ case 'K':
+ log3("delivery ", strnum3, ": success: ");
+ logsafe(dline[c].s + 2);
+ log1("\n");
+ markdone(c, jo[d[c][delnum].j].id, d[c][delnum].mpos);
+ --jo[d[c][delnum].j].numtodo;
+ break;
+ case 'Z':
+ log3("delivery ", strnum3, ": deferral: ");
+ logsafe(dline[c].s + 2);
+ log1("\n");
+ break;
+ case 'D':
+ log3("delivery ", strnum3, ": failure: ");
+ logsafe(dline[c].s + 2);
+ log1("\n");
+ addbounce(jo[d[c][delnum].j].id, d[c][delnum].recip.s, dline[c].s + 2);
+ markdone(c, jo[d[c][delnum].j].id, d[c][delnum].mpos);
+ --jo[d[c][delnum].j].numtodo;
+ break;
+ default:
+ log3("delivery ", strnum3, ": report mangled, will defer\n");
+ }
+ job_close(d[c][delnum].j);
+ d[c][delnum].used = 0;
+ --concurrencyused[c];
+ del_status();
+ }
+ dline[c].len = 0;
+ }
}
- job_close(d[c][delnum].j);
- d[c][delnum].used = 0; --concurrencyused[c];
- del_status();
- }
- dline[c].len = 0;
- }
- }
}
-void del_selprep(int *nfds, fd_set *rfds)
+void
+del_selprep(int *nfds, fd_set * rfds)
{
- int c;
- for (c = 0;c < CHANNELS;++c)
- if (flagspawnalive[c])
- {
- FD_SET(chanfdin[c],rfds);
- if (*nfds <= chanfdin[c])
- *nfds = chanfdin[c] + 1;
- }
+ int c;
+ for (c = 0; c < CHANNELS; ++c)
+ if (flagspawnalive[c]) {
+ FD_SET(chanfdin[c], rfds);
+ if (*nfds <= chanfdin[c])
+ *nfds = chanfdin[c] + 1;
+ }
}
-void del_do(fd_set *rfds)
+void
+del_do(fd_set * rfds)
{
- int c;
- for (c = 0;c < CHANNELS;++c)
- if (flagspawnalive[c])
- if (FD_ISSET(chanfdin[c],rfds))
- del_dochan(c);
+ int c;
+ for (c = 0; c < CHANNELS; ++c)
+ if (flagspawnalive[c])
+ if (FD_ISSET(chanfdin[c], rfds))
+ del_dochan(c);
}
diff --git a/src/mxf-send/fnmake.c b/src/mxf-send/fnmake.c
@@ -0,0 +1,51 @@
+#include "mxf-send.h"
+#include "mxf-send-protos.h"
+/* this file is too long ----------------------------------------- FILENAMES */
+
+stralloc fn = {0};
+stralloc fn2 = {0};
+char fnmake_strnum[FMT_ULONG];
+
+/* Daniel, if you're up in my source code and reading this, I want to
+ * look you straight in the eyes and tell you this:
+ * All of these procedures, to a letter, should not have used globals.
+ * Macros should then have been defined to define the default stralloc
+ * to use in a particular file.
+ * When it comes to chanaddr, I understand why you'd use a global. That
+ * makes perfect sense - chanaddr is effectively write-once memory for
+ * channels.
+ */
+void
+fnmake_init()
+{
+ while (!stralloc_ready(&fn, FMTQFN))
+ nomem();
+ while (!stralloc_ready(&fn2, FMTQFN))
+ nomem();
+}
+
+void fnmake_info(unsigned long id){
+ fn.len = fmtqfn(fn.s, "info/", id, 1);
+}
+void fnmake_todo(unsigned long id){
+ fn.len = fmtqfn(fn.s, "todo/", id, 0);
+}
+void fnmake_mess(unsigned long id){
+ fn.len = fmtqfn(fn.s, "mess/", id, 1);
+}
+void fnmake_foop(unsigned long id){
+ fn.len = fmtqfn(fn.s, "foop/", id, 0);
+}
+void fnmake_split(unsigned long id){
+ fn.len = fmtqfn(fn.s, "", id, 1);
+}
+void
+fnmake2_bounce(unsigned long id)
+{
+ fn2.len = fmtqfn(fn2.s, "bounce/", id, 0);
+}
+void
+fnmake_chanaddr(unsigned long id, int c)
+{
+ fn.len = fmtqfn(fn.s, chanaddr[c], id, 1);
+}
diff --git a/src/mxf-send/mxf-send-globals.h b/src/mxf-send/mxf-send-globals.h
@@ -0,0 +1,10 @@
+#ifndef MXFSENDGLOBALS_H
+#define MXFSENDGLOBALS_H
+
+// FILENAMES (fnmake.c)
+extern stralloc fn, fn2;
+extern char fnmake_strnum[FMT_ULONG];
+
+// REWRITE (rewrite.c)
+extern stralloc rwline;
+#endif // MXFSENDGLOBALS_H
diff --git a/src/mxf-send/mxf-send-protos.h b/src/mxf-send/mxf-send-protos.h
@@ -1,3 +1,5 @@
+#ifndef MXFSEND_PROTOTYPES
+#define MXFSEND_PROTOTYPES
extern void fnmake_init();
extern void fnmake_info(unsigned long id);
extern void fnmake_todo(unsigned long id);
@@ -65,3 +67,4 @@ extern void todo_init();
extern void todo_selprep(int *nfds, fd_set *rfds, datetime_sec *wakeup);
extern void todo_do(fd_set *rfds);
extern void todo_dochan(int c);
+#endif // MXFSEND_PROTOTYPES
diff --git a/src/mxf-send/mxf-send.c b/src/mxf-send/mxf-send.c
@@ -48,12 +48,13 @@
/* critical timing feature #1: if not triggered, do not busy-loop */
/* critical timing feature #2: if triggered, respond within fixed time */
/* important timing feature: when triggered, respond instantly */
-#define SLEEP_TODO 1500 /* check todo/ every 25 minutes in any case */
-#define SLEEP_FUZZ 1 /* slop a bit on sleeps to avoid zeno effect */
-#define SLEEP_FOREVER 86400 /* absolute maximum time spent in iopause() */
-#define SLEEP_CLEANUP 76431 /* time between cleanups */
+#define SLEEP_TODO 1500 /* check todo/ every 25 minutes in any case */
+#define SLEEP_FUZZ 1 /* slop a bit on sleeps to avoid zeno effect */
+#define SLEEP_FOREVER 86400 /* absolute maximum time spent in iopause() */
+#define SLEEP_CLEANUP 76431 /* time between cleanups */
#define SLEEP_SYSFAIL 123
-#define OSSIFIED 129600 /* 36 hours; _must_ exceed q-q's DEATH (24 hours) */
+#define OSSIFIED 129600 /* 36 hours; _must_ exceed q-q's DEATH (24
+ * hours) */
int lifetime = 604800;
@@ -73,480 +74,499 @@ char strnum2[FMT_ULONG];
char strnum3[FMT_ULONG];
#define CHANNELS 2
-char *chanaddr[CHANNELS] = { "local/", "remote/" };
-char *chanstatusmsg[CHANNELS] = { " local ", " remote " };
-char *tochan[CHANNELS] = { " to local ", " to remote " };
-int chanfdout[CHANNELS] = { 1, 3 };
-int chanfdin[CHANNELS] = { 2, 4 };
-int chanskip[CHANNELS] = { 10, 20 };
-
-int flagexitasap = 0; void sigterm() { flagexitasap = 1; }
-int flagrunasap = 0; void sigalrm() { flagrunasap = 1; }
-int flagreadasap = 0; void sighup() { flagreadasap = 1; }
+char *chanaddr[CHANNELS] = {"local/", "remote/"};
+char *chanstatusmsg[CHANNELS] = {" local ", " remote "};
+char *tochan[CHANNELS] = {" to local ", " to remote "};
+int chanfdout[CHANNELS] = {1, 3};
+int chanfdin[CHANNELS] = {2, 4};
+int chanskip[CHANNELS] = {10, 20};
+
+int flagexitasap = 0;
+void
+sigterm()
+{
+ flagexitasap = 1;
+}
+int flagrunasap = 0;
+void
+sigalrm()
+{
+ flagrunasap = 1;
+}
+int flagreadasap = 0;
+void
+sighup()
+{
+ flagreadasap = 1;
+}
-void cleandied() { log1("alert: oh no! lost qmail-clean connection! dying...\n");
- flagexitasap = 1; }
+void cleandied() {
+ log1("alert: oh no! lost qmail-clean connection! dying...\n");
+ flagexitasap = 1;
+}
int flagspawnalive[CHANNELS];
-void spawndied(int c) { log1("alert: oh no! lost spawn connection! dying...\n");
- flagspawnalive[c] = 0; flagexitasap = 1; }
+void spawndied(int c){
+ log1("alert: oh no! lost spawn connection! dying...\n");
+ flagspawnalive[c] = 0;
+ flagexitasap = 1;
+}
#define REPORTMAX 10000
datetime_sec recent;
-/* this file is too long ----------------------------------------- FILENAMES */
+/* this file is too long ----------------------------------------- FILENAMES
stralloc fn = {0};
stralloc fn2 = {0};
char fnmake_strnum[FMT_ULONG];
-void fnmake_init()
+void
+fnmake_init()
{
- while (!stralloc_ready(&fn,FMTQFN)) nomem();
- while (!stralloc_ready(&fn2,FMTQFN)) nomem();
+ while (!stralloc_ready(&fn, FMTQFN))
+ nomem();
+ while (!stralloc_ready(&fn2, FMTQFN))
+ nomem();
}
-void fnmake_info(unsigned long id) { fn.len = fmtqfn(fn.s,"info/",id,1); }
-void fnmake_todo(unsigned long id) { fn.len = fmtqfn(fn.s,"todo/",id,0); }
-void fnmake_mess(unsigned long id) { fn.len = fmtqfn(fn.s,"mess/",id,1); }
-void fnmake_foop(unsigned long id) { fn.len = fmtqfn(fn.s,"foop/",id,0); }
-void fnmake_split(unsigned long id) { fn.len = fmtqfn(fn.s,"",id,1); }
-void fnmake2_bounce(unsigned long id)
-{ fn2.len = fmtqfn(fn2.s,"bounce/",id,0); }
-void fnmake_chanaddr(unsigned long id, int c)
-{ fn.len = fmtqfn(fn.s,chanaddr[c],id,1); }
-
-
-/* this file is too long ----------------------------------------- REWRITING */
-
-stralloc rwline = {0};
-
-/* 1 if by land, 2 if by sea, 0 if out of memory. not allowed to barf. */
-/* may trash recip. must set up rwline, between a T and a \0. */
-int rewrite(char *recip)
+void fnmake_info(unsigned long id){
+ fn.len = fmtqfn(fn.s, "info/", id, 1);
+}
+void fnmake_todo(unsigned long id){
+ fn.len = fmtqfn(fn.s, "todo/", id, 0);
+}
+void fnmake_mess(unsigned long id){
+ fn.len = fmtqfn(fn.s, "mess/", id, 1);
+}
+void fnmake_foop(unsigned long id){
+ fn.len = fmtqfn(fn.s, "foop/", id, 0);
+}
+void fnmake_split(unsigned long id){
+ fn.len = fmtqfn(fn.s, "", id, 1);
+}
+void
+fnmake2_bounce(unsigned long id)
{
- unsigned int i;
- char *x;
- static stralloc addr = {0};
- unsigned int at;
-
- if (!stralloc_copys(&rwline,"T")) return 0;
- if (!stralloc_copys(&addr,recip)) return 0;
-
- i = byte_rchr(addr.s,addr.len,'@');
- if (i == addr.len) {
- if (!stralloc_cats(&addr,"@")) return 0;
- if (!stralloc_cat(&addr,&envnoathost)) return 0;
- }
-
- while (constmap(&mappercenthack,addr.s + i + 1,addr.len - i - 1)) {
- unsigned int j = byte_rchr(addr.s,i,'%');
- if (j == i) break;
- addr.len = i;
- i = j;
- addr.s[i] = '@';
- }
-
- at = byte_rchr(addr.s,addr.len,'@');
-
- if (constmap(&maplocals,addr.s + at + 1,addr.len - at - 1)) {
- if (!stralloc_cat(&rwline,&addr)) return 0;
- if (!stralloc_0(&rwline)) return 0;
- return 1;
- }
-
- for (i = 0;i <= addr.len;++i)
- if (!i || (i == at + 1) || (i == addr.len) || ((i > at) && (addr.s[i] == '.')))
- if ((x = constmap(&mapvdoms,addr.s + i,addr.len - i))) {
- if (!*x) break;
- if (!stralloc_cats(&rwline,x)) return 0;
- if (!stralloc_cats(&rwline,"-")) return 0;
- if (!stralloc_cat(&rwline,&addr)) return 0;
- if (!stralloc_0(&rwline)) return 0;
- return 1;
- }
-
- if (!stralloc_cat(&rwline,&addr)) return 0;
- if (!stralloc_0(&rwline)) return 0;
- return 2;
+ fn2.len = fmtqfn(fn2.s, "bounce/", id, 0);
}
-
-void senderadd(stralloc *sa, char *sender, char *recip)
+void
+fnmake_chanaddr(unsigned long id, int c)
{
- unsigned int i;
-
- i = str_len(sender);
- if (i >= 4)
- if (str_equal(sender + i - 4,"-@[]"))
- {
- unsigned int j = byte_rchr(sender,i - 4,'@');
- unsigned int k = str_rchr(recip,'@');
- if (recip[k] && (j + 5 <= i))
- {
- /* owner-@host-@[] -> owner-recipbox=reciphost@host */
- while (!stralloc_catb(sa,sender,j)) nomem();
- while (!stralloc_catb(sa,recip,k)) nomem();
- while (!stralloc_cats(sa,"=")) nomem();
- while (!stralloc_cats(sa,recip + k + 1)) nomem();
- while (!stralloc_cats(sa,"@")) nomem();
- while (!stralloc_catb(sa,sender + j + 1,i - 5 - j)) nomem();
- return;
- }
- }
- while (!stralloc_cats(sa,sender)) nomem();
+ fn.len = fmtqfn(fn.s, chanaddr[c], id, 1);
}
+*/
+/* this file is too long ----------------------------------------- REWRITING */
+/* the future is here! the rewriting routines have been moved to rewrite.c. */
/* this file is too long ---------------------------------------------- INFO */
-int getinfo(stralloc *sa, datetime_sec *dt, unsigned long id)
+int
+getinfo(stralloc * sa, datetime_sec * dt, unsigned long id)
{
- int fdinfo;
- struct stat st;
- static stralloc line = {0};
- int match;
- substdio ss;
- char buf[128];
-
- fnmake_info(id);
- fdinfo = open_read(fn.s);
- if (fdinfo == -1) return 0;
- if (fstat(fdinfo,&st) == -1) { close(fdinfo); return 0; }
- substdio_fdbuf(&ss,read,fdinfo,buf,sizeof(buf));
- if (getln(&ss,&line,&match,'\0') == -1) { close(fdinfo); return 0; }
- close(fdinfo);
- if (!match) return 0;
- if (line.s[0] != 'F') return 0;
-
- *dt = st.st_mtime;
- while (!stralloc_copys(sa,line.s + 1)) nomem();
- while (!stralloc_0(sa)) nomem();
- return 1;
+ int fdinfo;
+ struct stat st;
+ static stralloc line = {
+ 0
+ };
+ int match;
+ substdio ss;
+ char buf[128];
+
+ fnmake_info(id);
+ fdinfo = open_read(fn.s);
+ if (fdinfo == -1)
+ return 0;
+ if (fstat(fdinfo, &st) == -1) {
+ close(fdinfo);
+ return 0;
+ }
+ substdio_fdbuf(&ss, read, fdinfo, buf, sizeof(buf));
+ if (getln(&ss, &line, &match, '\0') == -1) {
+ close(fdinfo);
+ return 0;
+ }
+ close(fdinfo);
+ if (!match)
+ return 0;
+ if (line.s[0] != 'F')
+ return 0;
+
+ *dt = st.st_mtime;
+ while (!stralloc_copys(sa, line.s + 1))
+ nomem();
+ while (!stralloc_0(sa))
+ nomem();
+ return 1;
}
/* this file is too long ----------------------------------- PRIORITY QUEUES */
-prioq pqdone = {0}; /* -todo +info; HOPEFULLY -local -remote */
-prioq pqchan[CHANNELS] = { {0}, {0} };
+prioq pqdone = {0}; /* -todo +info; HOPEFULLY -local -remote */
+prioq pqchan[CHANNELS] = {{0}, {0}};
/* pqchan 0: -todo +info +local ?remote */
/* pqchan 1: -todo +info ?local +remote */
-prioq pqfail = {0}; /* stat() failure; has to be pqadded again */
+prioq pqfail = {0}; /* stat() failure; has to be pqadded again */
-void pqadd(unsigned long id)
+void
+pqadd(unsigned long id)
{
- struct prioq_elt pe;
- struct prioq_elt pechan[CHANNELS];
- int flagchan[CHANNELS];
- struct stat st;
- int c;
+ struct prioq_elt pe;
+ struct prioq_elt pechan[CHANNELS];
+ int flagchan[CHANNELS];
+ struct stat st;
+ int c;
#define CHECKSTAT if (errno != error_noent) goto fail;
- fnmake_info(id);
- if (stat(fn.s,&st) == -1)
- {
- CHECKSTAT
- return; /* someone yanking our chain */
- }
-
- fnmake_todo(id);
- if (stat(fn.s,&st) != -1) return; /* look, ma, dad crashed writing info! */
- CHECKSTAT
-
- for (c = 0;c < CHANNELS;++c)
- {
- fnmake_chanaddr(id,c);
- if (stat(fn.s,&st) == -1) { flagchan[c] = 0; CHECKSTAT }
- else { flagchan[c] = 1; pechan[c].id = id; pechan[c].dt = st.st_mtime; }
- }
-
- for (c = 0;c < CHANNELS;++c)
- if (flagchan[c])
- while (!prioq_insert(&pqchan[c],&pechan[c])) nomem();
-
- for (c = 0;c < CHANNELS;++c) if (flagchan[c]) break;
- if (c == CHANNELS)
- {
- pe.id = id; pe.dt = now();
- while (!prioq_insert(&pqdone,&pe)) nomem();
- }
-
- return;
-
- fail:
- log3("warning: unable to stat ",fn.s,"; will try again later\n");
- pe.id = id; pe.dt = now() + SLEEP_SYSFAIL;
- while (!prioq_insert(&pqfail,&pe)) nomem();
+ fnmake_info(id);
+ if (stat(fn.s, &st) == -1) {
+ CHECKSTAT
+ return; /* someone yanking our chain */
+ }
+
+ fnmake_todo(id);
+ if (stat(fn.s, &st) != -1)
+ return; /* look, ma, dad crashed writing info! */
+ CHECKSTAT
+
+ for (c = 0; c < CHANNELS; ++c) {
+ fnmake_chanaddr(id, c);
+ if (stat(fn.s, &st) == -1) {
+ flagchan[c] = 0;
+ CHECKSTAT
+ } else {
+ flagchan[c] = 1;
+ pechan[c].id = id;
+ pechan[c].dt = st.st_mtime;
+ }
+ }
+
+ for (c = 0; c < CHANNELS; ++c)
+ if (flagchan[c])
+ while (!prioq_insert(&pqchan[c], &pechan[c]))
+ nomem();
+
+ for (c = 0; c < CHANNELS; ++c)
+ if (flagchan[c])
+ break;
+ if (c == CHANNELS) {
+ pe.id = id;
+ pe.dt = now();
+ while (!prioq_insert(&pqdone, &pe))
+ nomem();
+ }
+
+ return;
+
+fail:
+ log3("warning: unable to stat ", fn.s, "; will try again later\n");
+ pe.id = id;
+ pe.dt = now() + SLEEP_SYSFAIL;
+ while (!prioq_insert(&pqfail, &pe))
+ nomem();
}
-void pqstart()
+void
+pqstart()
{
- readsubdir rs;
- int x;
- unsigned long id;
+ readsubdir rs;
+ int x;
+ unsigned long id;
- readsubdir_init(&rs,"info",pausedir);
+ readsubdir_init(&rs, "info", pausedir);
- while ((x = readsubdir_next(&rs,&id)))
- if (x > 0)
- pqadd(id);
+ while ((x = readsubdir_next(&rs, &id)))
+ if (x > 0)
+ pqadd(id);
}
-void pqfinish()
+void
+pqfinish()
{
- int c;
- struct prioq_elt pe;
- struct timeval ut[2] = { 0 };
-
- for (c = 0;c < CHANNELS;++c)
- while (prioq_min(&pqchan[c],&pe))
- {
- prioq_delmin(&pqchan[c]);
- fnmake_chanaddr(pe.id,c);
- ut[0].tv_sec = ut[1].tv_sec = pe.dt;
- if (utimes(fn.s,ut) == -1)
- log3("warning: unable to utime ",fn.s,"; message will be retried too soon\n");
- }
+ int c;
+ struct prioq_elt pe;
+ struct timeval ut[2] = {0};
+
+ for (c = 0; c < CHANNELS; ++c)
+ while (prioq_min(&pqchan[c], &pe)) {
+ prioq_delmin(&pqchan[c]);
+ fnmake_chanaddr(pe.id, c);
+ ut[0].tv_sec = ut[1].tv_sec = pe.dt;
+ if (utimes(fn.s, ut) == -1)
+ log3("warning: unable to utime ", fn.s, "; message will be retried too soon\n");
+ }
}
-void pqrun()
+void
+pqrun()
{
- int c;
- unsigned int i;
- for (c = 0;c < CHANNELS;++c)
- if (pqchan[c].p)
- if (pqchan[c].len)
- for (i = 0;i < pqchan[c].len;++i)
- pqchan[c].p[i].dt = recent;
+ int c;
+ unsigned int i;
+ for (c = 0; c < CHANNELS; ++c)
+ if (pqchan[c].p)
+ if (pqchan[c].len)
+ for (i = 0; i < pqchan[c].len; ++i)
+ pqchan[c].p[i].dt = recent;
}
/* this file is too long ---------------------------------------------- JOBS */
-struct job
- {
- int refs; /* if 0, this struct is unused */
- unsigned long id;
- int channel;
- datetime_sec retry;
- stralloc sender;
- int numtodo;
- int flaghiteof;
- int flagdying;
- }
+struct job {
+ int refs; /* if 0, this struct is unused */
+ unsigned long id;
+ int channel;
+ datetime_sec retry;
+ stralloc sender;
+ int numtodo;
+ int flaghiteof;
+ int flagdying;
+}
;
int numjobs;
struct job *jo;
-void job_init()
+void
+job_init()
{
- int j;
- while (!(jo = (struct job *) alloc(numjobs * sizeof(struct job)))) nomem();
- for (j = 0;j < numjobs;++j)
- {
- jo[j].refs = 0;
- jo[j].sender.s = 0;
- }
+ int j;
+ while (!(jo = (struct job *)alloc(numjobs * sizeof(struct job))))
+ nomem();
+ for (j = 0; j < numjobs; ++j) {
+ jo[j].refs = 0;
+ jo[j].sender.s = 0;
+ }
}
-int job_avail()
+int
+job_avail()
{
- int j;
- for (j = 0;j < numjobs;++j) if (!jo[j].refs) return 1;
- return 0;
+ int j;
+ for (j = 0; j < numjobs; ++j)
+ if (!jo[j].refs)
+ return 1;
+ return 0;
}
-int job_open(unsigned long id, int channel)
+int
+job_open(unsigned long id, int channel)
{
- int j;
- for (j = 0;j < numjobs;++j) if (!jo[j].refs) break;
- if (j == numjobs) return -1;
- jo[j].refs = 1;
- jo[j].id = id;
- jo[j].channel = channel;
- jo[j].numtodo = 0;
- jo[j].flaghiteof = 0;
- return j;
+ int j;
+ for (j = 0; j < numjobs; ++j)
+ if (!jo[j].refs)
+ break;
+ if (j == numjobs)
+ return -1;
+ jo[j].refs = 1;
+ jo[j].id = id;
+ jo[j].channel = channel;
+ jo[j].numtodo = 0;
+ jo[j].flaghiteof = 0;
+ return j;
}
-void job_close(int j)
+void
+job_close(int j)
{
- struct prioq_elt pe;
- struct stat st;
-
- if (0 < --jo[j].refs) return;
-
- pe.id = jo[j].id;
- pe.dt = jo[j].retry;
- if (jo[j].flaghiteof && !jo[j].numtodo)
- {
- fnmake_chanaddr(jo[j].id,jo[j].channel);
- if (unlink(fn.s) == -1)
- {
- log3("warning: unable to unlink ",fn.s,"; will try again later\n");
- pe.dt = now() + SLEEP_SYSFAIL;
- }
- else
- {
- int c;
- for (c = 0;c < CHANNELS;++c) if (c != jo[j].channel)
- {
- fnmake_chanaddr(jo[j].id,c);
- if (stat(fn.s,&st) == 0) return; /* more channels going */
- if (errno != error_noent)
- {
- log3("warning: unable to stat ",fn.s,"\n");
- break; /* this is the only reason for HOPEFULLY */
+ struct prioq_elt pe;
+ struct stat st;
+
+ if (0 < --jo[j].refs)
+ return;
+
+ pe.id = jo[j].id;
+ pe.dt = jo[j].retry;
+ if (jo[j].flaghiteof && !jo[j].numtodo) {
+ fnmake_chanaddr(jo[j].id, jo[j].channel);
+ if (unlink(fn.s) == -1) {
+ log3("warning: unable to unlink ", fn.s, "; will try again later\n");
+ pe.dt = now() + SLEEP_SYSFAIL;
+ } else {
+ int c;
+ for (c = 0; c < CHANNELS; ++c)
+ if (c != jo[j].channel) {
+ fnmake_chanaddr(jo[j].id, c);
+ if (stat(fn.s, &st) == 0)
+ return; /* more channels going */
+ if (errno != error_noent) {
+ log3("warning: unable to stat ", fn.s, "\n");
+ break; /* this is the only
+ * reason for HOPEFULLY */
+ }
+ }
+ pe.dt = now();
+ while (!prioq_insert(&pqdone, &pe))
+ nomem();
+ return;
+ }
}
- }
- pe.dt = now();
- while (!prioq_insert(&pqdone,&pe)) nomem();
- return;
- }
- }
-
- while (!prioq_insert(&pqchan[jo[j].channel],&pe)) nomem();
+
+ while (!prioq_insert(&pqchan[jo[j].channel], &pe))
+ nomem();
}
/* this file is too long ------------------------------------------- BOUNCES */
-char *stripvdomprepend(char *recip)
+char *
+stripvdomprepend(char *recip)
{
- unsigned int i;
- char *domain;
- unsigned int domainlen;
- char *prepend;
-
- i = str_rchr(recip,'@');
- if (!recip[i]) return recip;
- domain = recip + i + 1;
- domainlen = str_len(domain);
-
- for (i = 0;i <= domainlen;++i)
- if ((i == 0) || (i == domainlen) || (domain[i] == '.'))
- if ((prepend = constmap(&mapvdoms,domain + i,domainlen - i)))
- {
- if (!*prepend) break;
- i = str_len(prepend);
- if (str_diffn(recip,prepend,i)) break;
- if (recip[i] != '-') break;
- return recip + i + 1;
- }
- return recip;
+ unsigned int i;
+ char *domain;
+ unsigned int domainlen;
+ char *prepend;
+
+ i = str_rchr(recip, '@');
+ if (!recip[i])
+ return recip;
+ domain = recip + i + 1;
+ domainlen = str_len(domain);
+
+ for (i = 0; i <= domainlen; ++i)
+ if ((i == 0) || (i == domainlen) || (domain[i] == '.'))
+ if ((prepend = constmap(&mapvdoms, domain + i, domainlen - i))) {
+ if (!*prepend)
+ break;
+ i = str_len(prepend);
+ if (str_diffn(recip, prepend, i))
+ break;
+ if (recip[i] != '-')
+ break;
+ return recip + i + 1;
+ }
+ return recip;
}
stralloc bouncetext = {0};
-void addbounce(unsigned long id, char *recip, char *report)
+void
+addbounce(unsigned long id, char *recip, char *report)
{
- int fd;
- unsigned int pos;
- int w;
- while (!stralloc_copys(&bouncetext,"<")) nomem();
- while (!stralloc_cats(&bouncetext,stripvdomprepend(recip))) nomem();
- for (pos = 0;pos < bouncetext.len;++pos)
- if (bouncetext.s[pos] == '\n')
- bouncetext.s[pos] = '_';
- while (!stralloc_cats(&bouncetext,">:\n")) nomem();
- while (!stralloc_cats(&bouncetext,report)) nomem();
- if (report[0])
- if (report[str_len(report) - 1] != '\n')
- while (!stralloc_cats(&bouncetext,"\n")) nomem();
- for (pos = bouncetext.len - 2;pos > 0;--pos)
- if (bouncetext.s[pos] == '\n')
- if (bouncetext.s[pos - 1] == '\n')
- bouncetext.s[pos] = '/';
- while (!stralloc_cats(&bouncetext,"\n")) nomem();
- fnmake2_bounce(id);
- for (;;)
- {
- fd = open_append(fn2.s);
- if (fd != -1) break;
- log1("alert: unable to append to bounce message; HELP! sleeping...\n");
- sleep(10);
- }
- pos = 0;
- while (pos < bouncetext.len)
- {
- w = write(fd,bouncetext.s + pos,bouncetext.len - pos);
- if (w == 0 || w == -1)
- {
- log1("alert: unable to append to bounce message; HELP! sleeping...\n");
- sleep(10);
- }
- else
- pos += w;
- }
- close(fd);
+ int fd;
+ unsigned int pos;
+ int w;
+ while (!stralloc_copys(&bouncetext, "<"))
+ nomem();
+ while (!stralloc_cats(&bouncetext, stripvdomprepend(recip)))
+ nomem();
+ for (pos = 0; pos < bouncetext.len; ++pos)
+ if (bouncetext.s[pos] == '\n')
+ bouncetext.s[pos] = '_';
+ while (!stralloc_cats(&bouncetext, ">:\n"))
+ nomem();
+ while (!stralloc_cats(&bouncetext, report))
+ nomem();
+ if (report[0])
+ if (report[str_len(report) - 1] != '\n')
+ while (!stralloc_cats(&bouncetext, "\n"))
+ nomem();
+ for (pos = bouncetext.len - 2; pos > 0; --pos)
+ if (bouncetext.s[pos] == '\n')
+ if (bouncetext.s[pos - 1] == '\n')
+ bouncetext.s[pos] = '/';
+ while (!stralloc_cats(&bouncetext, "\n"))
+ nomem();
+ fnmake2_bounce(id);
+ for (;;) {
+ fd = open_append(fn2.s);
+ if (fd != -1)
+ break;
+ log1("alert: unable to append to bounce message; HELP! sleeping...\n");
+ sleep(10);
+ }
+ pos = 0;
+ while (pos < bouncetext.len) {
+ w = write(fd, bouncetext.s + pos, bouncetext.len - pos);
+ if (w == 0 || w == -1) {
+ log1("alert: unable to append to bounce message; HELP! sleeping...\n");
+ sleep(10);
+ } else
+ pos += w;
+ }
+ close(fd);
}
-int injectbounce(unsigned long id)
+int
+injectbounce(unsigned long id)
{
- struct qmail qqt;
- struct stat st;
- char *bouncesender;
- char *bouncerecip;
- int r;
- int fd;
- substdio ssread;
- char buf[128];
- char inbuf[128];
- static stralloc sender = {0};
- static stralloc quoted = {0};
- datetime_sec birth;
- unsigned long qp;
-
- if (!getinfo(&sender,&birth,id)) return 0; /* XXX: print warning */
-
- /* owner-@host-@[] -> owner-@host */
- if (sender.len >= 5)
- if (str_equal(sender.s + sender.len - 5,"-@[]"))
- {
- sender.len -= 4;
- sender.s[sender.len - 1] = 0;
- }
-
- fnmake2_bounce(id);
- fnmake_mess(id);
- if (stat(fn2.s,&st) == -1)
- {
- if (errno == error_noent)
- return 1;
- log3("warning: unable to stat ",fn2.s,"\n");
- return 0;
- }
- if (str_equal(sender.s,"#@[]"))
- log3("triple bounce: discarding ",fn2.s,"\n");
- else
- {
- if (qmail_open(&qqt) == -1)
- { log1("warning: unable to start qmail-queue, will try later\n"); return 0; }
- qp = qmail_qp(&qqt);
-
- if (*sender.s) { bouncesender = ""; bouncerecip = sender.s; }
- else { bouncesender = "#@[]"; bouncerecip = doublebounceto.s; }
-
- while (!newfield_datemake(now())) nomem();
- qmail_put(&qqt,newfield_date.s,newfield_date.len);
- qmail_puts(&qqt,"From: ");
- while (!quote("ed,&bouncefrom)) nomem();
- qmail_put(&qqt,quoted.s,quoted.len);
- qmail_puts(&qqt,"@");
- qmail_put(&qqt,bouncehost.s,bouncehost.len);
- qmail_puts(&qqt,"\nTo: ");
- while (!quote2("ed,bouncerecip)) nomem();
- qmail_put(&qqt,quoted.s,quoted.len);
- qmail_puts(&qqt,"\n\
+ struct qmail qqt;
+ struct stat st;
+ char *bouncesender;
+ char *bouncerecip;
+ int r;
+ int fd;
+ substdio ssread;
+ char buf[128];
+ char inbuf[128];
+ static stralloc sender = {
+ 0
+ };
+ static stralloc quoted = {
+ 0
+ };
+ datetime_sec birth;
+ unsigned long qp;
+
+ if (!getinfo(&sender, &birth, id))
+ return 0; /* XXX: print warning */
+
+ /* owner-@host-@[] -> owner-@host */
+ if (sender.len >= 5)
+ if (str_equal(sender.s + sender.len - 5, "-@[]")) {
+ sender.len -= 4;
+ sender.s[sender.len - 1] = 0;
+ }
+
+ fnmake2_bounce(id);
+ fnmake_mess(id);
+ if (stat(fn2.s, &st) == -1) {
+ if (errno == error_noent)
+ return 1;
+ log3("warning: unable to stat ", fn2.s, "\n");
+ return 0;
+ }
+ if (str_equal(sender.s, "#@[]"))
+ log3("triple bounce: discarding ", fn2.s, "\n");
+ else {
+ if (qmail_open(&qqt) == -1) {
+ log1("warning: unable to start qmail-queue, will try later\n");
+ return 0;
+ }
+ qp = qmail_qp(&qqt);
+
+ if (*sender.s) {
+ bouncesender = "";
+ bouncerecip = sender.s;
+ } else {
+ bouncesender = "#@[]";
+ bouncerecip = doublebounceto.s;
+ }
+
+ while (!newfield_datemake(now()))
+ nomem();
+ qmail_put(&qqt, newfield_date.s, newfield_date.len);
+ qmail_puts(&qqt, "From: ");
+ while (!quote("ed, &bouncefrom))
+ nomem();
+ qmail_put(&qqt, quoted.s, quoted.len);
+ qmail_puts(&qqt, "@");
+ qmail_put(&qqt, bouncehost.s, bouncehost.len);
+ qmail_puts(&qqt, "\nTo: ");
+ while (!quote2("ed, bouncerecip))
+ nomem();
+ qmail_put(&qqt, quoted.s, quoted.len);
+ qmail_puts(&qqt, "\n\
Subject: Failure Notice\n\
\n\
Hi. This is the qmail-send (NightmareMail queue manager) program at ");
- qmail_put(&qqt,bouncehost.s,bouncehost.len);
- qmail_puts(&qqt,*sender.s ? ".\n\
+ qmail_put(&qqt, bouncehost.s, bouncehost.len);
+ qmail_puts(&qqt, *sender.s ? ".\n\
I'm afraid I wasn't able to deliver your message to the following addresses.\n\
This is a permanent error. I've given up. Sorry it didn't work out.\n\
For further assistance, mail the postmaster.\n\
@@ -556,225 +576,281 @@ I tried to deliver a bounce message to this address, but the bounce bounced!\n\
\n\
");
- fd = open_read(fn2.s);
- if (fd == -1)
- qmail_fail(&qqt);
- else
- {
- substdio_fdbuf(&ssread,read,fd,inbuf,sizeof(inbuf));
- while ((r = substdio_get(&ssread,buf,sizeof(buf))) > 0)
- qmail_put(&qqt,buf,r);
- close(fd);
- if (r == -1)
- qmail_fail(&qqt);
- }
-
- 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");
- qmail_puts(&qqt,"Return-Path: <");
- while (!quote2("ed,sender.s)) nomem();
- qmail_put(&qqt,quoted.s,quoted.len);
- qmail_puts(&qqt,">\n");
-
- fd = open_read(fn.s);
- if (fd == -1)
- qmail_fail(&qqt);
- else
- {
- substdio_fdbuf(&ssread,read,fd,inbuf,sizeof(inbuf));
- while ((r = substdio_get(&ssread,buf,sizeof(buf))) > 0)
- qmail_put(&qqt,buf,r);
- close(fd);
- if (r == -1)
- qmail_fail(&qqt);
- }
-
- qmail_from(&qqt,bouncesender);
- qmail_to(&qqt,bouncerecip);
- if (*qmail_close(&qqt))
- { log1("warning: trouble injecting bounce message, will try later\n"); return 0; }
-
- strnum2[fmt_ulong(strnum2,id)] = 0;
- qslog2("bounce msg ",strnum2);
- strnum2[fmt_ulong(strnum2,qp)] = 0;
- log3(" qp ",strnum2,"\n");
- }
- if (unlink(fn2.s) == -1)
- {
- log3("warning: unable to unlink ",fn2.s,"\n");
- return 0;
- }
- return 1;
+ fd = open_read(fn2.s);
+ if (fd == -1)
+ qmail_fail(&qqt);
+ else {
+ substdio_fdbuf(&ssread, read, fd, inbuf, sizeof(inbuf));
+ while ((r = substdio_get(&ssread, buf, sizeof(buf))) > 0)
+ qmail_put(&qqt, buf, r);
+ close(fd);
+ if (r == -1)
+ qmail_fail(&qqt);
+ }
+
+ 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");
+ qmail_puts(&qqt, "Return-Path: <");
+ while (!quote2("ed, sender.s))
+ nomem();
+ qmail_put(&qqt, quoted.s, quoted.len);
+ qmail_puts(&qqt, ">\n");
+
+ fd = open_read(fn.s);
+ if (fd == -1)
+ qmail_fail(&qqt);
+ else {
+ substdio_fdbuf(&ssread, read, fd, inbuf, sizeof(inbuf));
+ while ((r = substdio_get(&ssread, buf, sizeof(buf))) > 0)
+ qmail_put(&qqt, buf, r);
+ close(fd);
+ if (r == -1)
+ qmail_fail(&qqt);
+ }
+
+ qmail_from(&qqt, bouncesender);
+ qmail_to(&qqt, bouncerecip);
+ if (*qmail_close(&qqt)) {
+ log1("warning: trouble injecting bounce message, will try later\n");
+ return 0;
+ }
+
+ strnum2[fmt_ulong(strnum2, id)] = 0;
+ qslog2("bounce msg ", strnum2);
+ strnum2[fmt_ulong(strnum2, qp)] = 0;
+ log3(" qp ", strnum2, "\n");
+ }
+ if (unlink(fn2.s) == -1) {
+ log3("warning: unable to unlink ", fn2.s, "\n");
+ return 0;
+ }
+ return 1;
}
/* this file is too long ---------------------------------------------- MAIN */
-int getcontrols() { if (control_init() == -1) return 0;
- if (control_readint(&lifetime,"control/queuelifetime") == -1) return 0;
- if (control_readint(&concurrency[0],"control/concurrencylocal") == -1) return 0;
- if (control_readint(&concurrency[1],"control/concurrencyremote") == -1) return 0;
- if (control_rldef(&envnoathost,"control/envnoathost",1,"envnoathost") != 1) return 0;
- if (control_rldef(&bouncefrom,"control/bouncefrom",0,"MAILER-DAEMON") != 1) return 0;
- if (control_rldef(&bouncehost,"control/bouncehost",1,"bouncehost") != 1) return 0;
- if (control_rldef(&doublebouncehost,"control/doublebouncehost",1,"doublebouncehost") != 1) return 0;
- if (control_rldef(&doublebounceto,"control/doublebounceto",0,"postmaster") != 1) return 0;
- if (!stralloc_cats(&doublebounceto,"@")) return 0;
- if (!stralloc_cat(&doublebounceto,&doublebouncehost)) return 0;
- if (!stralloc_0(&doublebounceto)) return 0;
- if (control_readfile(&locals,"control/locals",1) != 1) return 0;
- if (!constmap_init(&maplocals,locals.s,locals.len,0)) return 0;
- switch(control_readfile(&percenthack,"control/percenthack",0))
- {
- case -1: return 0;
- case 0: if (!constmap_init(&mappercenthack,"",0,0)) return 0; break;
- case 1: if (!constmap_init(&mappercenthack,percenthack.s,percenthack.len,0)) return 0; break;
- }
- switch(control_readfile(&vdoms,"control/virtualdomains",0))
- {
- case -1: return 0;
- case 0: if (!constmap_init(&mapvdoms,"",0,1)) return 0; break;
- case 1: if (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) return 0; break;
- }
- return 1; }
+int
+getcontrols()
+{
+ if (control_init() == -1)
+ return 0;
+ if (control_readint(&lifetime, "control/queuelifetime") == -1)
+ return 0;
+ if (control_readint(&concurrency[0], "control/concurrencylocal") == -1)
+ return 0;
+ if (control_readint(&concurrency[1], "control/concurrencyremote") == -1)
+ return 0;
+ if (control_rldef(&envnoathost, "control/envnoathost", 1, "envnoathost") != 1)
+ return 0;
+ if (control_rldef(&bouncefrom, "control/bouncefrom", 0, "MAILER-DAEMON") != 1)
+ return 0;
+ if (control_rldef(&bouncehost, "control/bouncehost", 1, "bouncehost") != 1)
+ return 0;
+ if (control_rldef(&doublebouncehost, "control/doublebouncehost", 1, "doublebouncehost") != 1)
+ return 0;
+ if (control_rldef(&doublebounceto, "control/doublebounceto", 0, "postmaster") != 1)
+ return 0;
+ if (!stralloc_cats(&doublebounceto, "@"))
+ return 0;
+ if (!stralloc_cat(&doublebounceto, &doublebouncehost))
+ return 0;
+ if (!stralloc_0(&doublebounceto))
+ return 0;
+ if (control_readfile(&locals, "control/locals", 1) != 1)
+ return 0;
+ if (!constmap_init(&maplocals, locals.s, locals.len, 0))
+ return 0;
+ switch (control_readfile(&percenthack, "control/percenthack", 0)) {
+ case -1:
+ return 0;
+ case 0:
+ if (!constmap_init(&mappercenthack, "", 0, 0))
+ return 0;
+ break;
+ case 1:
+ if (!constmap_init(&mappercenthack, percenthack.s, percenthack.len, 0))
+ return 0;
+ break;
+ }
+ switch (control_readfile(&vdoms, "control/virtualdomains", 0)) {
+ case -1:
+ return 0;
+ case 0:
+ if (!constmap_init(&mapvdoms, "", 0, 1))
+ return 0;
+ break;
+ case 1:
+ if (!constmap_init(&mapvdoms, vdoms.s, vdoms.len, 1))
+ return 0;
+ break;
+ }
+ return 1;
+}
stralloc newlocals = {0};
stralloc newvdoms = {0};
-void regetcontrols()
+void
+regetcontrols()
{
- int r;
-
- if (control_readfile(&newlocals,"control/locals",1) != 1)
- { log1("alert: unable to reread control/locals\n"); return; }
- r = control_readfile(&newvdoms,"control/virtualdomains",0);
- if (r == -1)
- { log1("alert: unable to reread control/virtualdomains\n"); return; }
-
- constmap_free(&maplocals);
- constmap_free(&mapvdoms);
-
- while (!stralloc_copy(&locals,&newlocals)) nomem();
- while (!constmap_init(&maplocals,locals.s,locals.len,0)) nomem();
-
- if (r)
- {
- while (!stralloc_copy(&vdoms,&newvdoms)) nomem();
- while (!constmap_init(&mapvdoms,vdoms.s,vdoms.len,1)) nomem();
- }
- else
- while (!constmap_init(&mapvdoms,"",0,1)) nomem();
+ int r;
+
+ if (control_readfile(&newlocals, "control/locals", 1) != 1) {
+ log1("alert: unable to reread control/locals\n");
+ return;
+ }
+ r = control_readfile(&newvdoms, "control/virtualdomains", 0);
+ if (r == -1) {
+ log1("alert: unable to reread control/virtualdomains\n");
+ return;
+ }
+
+ constmap_free(&maplocals);
+ constmap_free(&mapvdoms);
+
+ while (!stralloc_copy(&locals, &newlocals))
+ nomem();
+ while (!constmap_init(&maplocals, locals.s, locals.len, 0))
+ nomem();
+
+ if (r) {
+ while (!stralloc_copy(&vdoms, &newvdoms))
+ nomem();
+ while (!constmap_init(&mapvdoms, vdoms.s, vdoms.len, 1))
+ nomem();
+ } else
+ while (!constmap_init(&mapvdoms, "", 0, 1))
+ nomem();
}
-void reread()
+void
+reread()
{
- if (chdir(auto_qmail) == -1)
- {
- log1("alert: unable to reread controls: unable to switch to home directory\n");
- return;
- }
- regetcontrols();
- while (chdir("queue") == -1)
- {
- log1("alert: unable to switch back to queue directory; HELP! sleeping...\n");
- sleep(10);
- }
+ if (chdir(auto_qmail) == -1) {
+ log1("alert: unable to reread controls: unable to switch to home directory\n");
+ return;
+ }
+ regetcontrols();
+ while (chdir("queue") == -1) {
+ log1("alert: unable to switch back to queue directory; HELP! sleeping...\n");
+ sleep(10);
+ }
}
-int main(void)
+int
+main(void)
{
- int fd;
- datetime_sec wakeup;
- fd_set rfds;
- fd_set wfds;
- int nfds;
- struct timeval tv;
- int c;
-
- if (chdir(auto_qmail) == -1)
- { log1("alert: cannot start: unable to switch to home directory\n"); _exit(111); }
- if (!getcontrols())
- { log1("alert: cannot start: unable to read controls\n"); _exit(111); }
- if (chdir("queue") == -1)
- { log1("alert: cannot start: unable to switch to queue directory\n"); _exit(111); }
- sig_pipeignore();
- sig_termcatch(sigterm);
- sig_alarmcatch(sigalrm);
- sig_hangupcatch(sighup);
- sig_childdefault();
- umask(077);
-
- fd = open_write("lock/sendmutex");
- if (fd == -1)
- { log1("alert: cannot start: unable to open mutex\n"); _exit(111); }
- if (lock_exnb(fd) == -1)
- { log1("alert: cannot start: qmail-send is already running\n"); _exit(111); }
-
- numjobs = 0;
- for (c = 0;c < CHANNELS;++c)
- {
- char ch;
- int u;
- int r;
- do
- r = read(chanfdin[c],&ch,1);
- while ((r == -1) && (errno == error_intr));
- if (r < 1)
- { log1("alert: cannot start: hath the daemon spawn no fire?\n"); _exit(111); }
- u = (unsigned int) (unsigned char) ch;
- if (concurrency[c] > u) concurrency[c] = u;
- numjobs += concurrency[c];
- }
-
- fnmake_init();
-
- comm_init();
-
- pqstart();
- job_init();
- del_init();
- pass_init();
- todo_init();
- cleanup_init();
-
- while (!flagexitasap || !del_canexit())
- {
- recent = now();
-
- if (flagrunasap) { flagrunasap = 0; pqrun(); }
- if (flagreadasap) { flagreadasap = 0; reread(); }
-
- wakeup = recent + SLEEP_FOREVER;
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- nfds = 1;
-
- comm_selprep(&nfds,&wfds);
- del_selprep(&nfds,&rfds);
- pass_selprep(&wakeup);
- todo_selprep(&nfds,&rfds,&wakeup);
- cleanup_selprep(&wakeup);
-
- if (wakeup <= recent) tv.tv_sec = 0;
- else tv.tv_sec = wakeup - recent + SLEEP_FUZZ;
- tv.tv_usec = 0;
-
- if (select(nfds,&rfds,&wfds,NULL,&tv) == -1)
- if (errno == error_intr)
- ;
- else
- log1("warning: trouble in select\n");
- else
- {
- recent = now();
-
- // XXX: should have a queue structure
- comm_do(&wfds);
- del_do(&rfds);
- todo_do(&rfds);
- pass_do();
- cleanup_do();
- }
- }
- pqfinish();
- log1("status: exiting\n");
- _exit(0);
+ int fd;
+ datetime_sec wakeup;
+ fd_set rfds;
+ fd_set wfds;
+ int nfds;
+ struct timeval tv;
+ int c;
+
+ if (chdir(auto_qmail) == -1) {
+ log1("alert: cannot start: unable to switch to home directory\n");
+ _exit(111);
+ }
+ if (!getcontrols()) {
+ log1("alert: cannot start: unable to read controls\n");
+ _exit(111);
+ }
+ if (chdir("queue") == -1) {
+ log1("alert: cannot start: unable to switch to queue directory\n");
+ _exit(111);
+ }
+ sig_pipeignore();
+ sig_termcatch(sigterm);
+ sig_alarmcatch(sigalrm);
+ sig_hangupcatch(sighup);
+ sig_childdefault();
+ umask(077);
+
+ fd = open_write("lock/sendmutex");
+ if (fd == -1) {
+ log1("alert: cannot start: unable to open mutex\n");
+ _exit(111);
+ }
+ if (lock_exnb(fd) == -1) {
+ log1("alert: cannot start: qmail-send is already running\n");
+ _exit(111);
+ }
+
+ numjobs = 0;
+ for (c = 0; c < CHANNELS; ++c) {
+ char ch;
+ int u;
+ int r;
+ do
+ r = read(chanfdin[c], &ch, 1);
+ while ((r == -1) && (errno == error_intr));
+ if (r < 1) {
+ log1("alert: cannot start: hath the daemon spawn no fire?\n");
+ _exit(111);
+ }
+ u = (unsigned int)(unsigned char)ch;
+ if (concurrency[c] > u)
+ concurrency[c] = u;
+ numjobs += concurrency[c];
+ }
+
+ fnmake_init();
+
+ comm_init();
+
+ pqstart();
+ job_init();
+ del_init();
+ pass_init();
+ todo_init();
+ cleanup_init();
+
+ while (!flagexitasap || !del_canexit()) {
+ recent = now();
+
+ if (flagrunasap) {
+ flagrunasap = 0;
+ pqrun();
+ }
+ if (flagreadasap) {
+ flagreadasap = 0;
+ reread();
+ }
+
+ wakeup = recent + SLEEP_FOREVER;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ nfds = 1;
+
+ comm_selprep(&nfds, &wfds);
+ del_selprep(&nfds, &rfds);
+ pass_selprep(&wakeup);
+ todo_selprep(&nfds, &rfds, &wakeup);
+ cleanup_selprep(&wakeup);
+
+ if (wakeup <= recent)
+ tv.tv_sec = 0;
+ else
+ tv.tv_sec = wakeup - recent + SLEEP_FUZZ;
+ tv.tv_usec = 0;
+
+ if (select(nfds, &rfds, &wfds, NULL, &tv) == -1)
+ if (errno == error_intr)
+ ;
+ else
+ log1("warning: trouble in select\n");
+ else {
+ recent = now();
+
+ //XXX: should have a queue structure
+ comm_do(&wfds);
+ del_do(&rfds);
+ todo_do(&rfds);
+ pass_do();
+ cleanup_do();
+ }
+ }
+ pqfinish();
+ log1("status: exiting\n");
+ _exit(0);
};
diff --git a/src/mxf-send/mxf-send.h b/src/mxf-send/mxf-send.h
@@ -1,3 +1,5 @@
+#ifndef MXFSEND_H
+#define MXFSEND_H
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -40,6 +42,7 @@
#include "fmtqfn.h"
#include "readsubdir.h"
+#define AMNESIAC (errno = ENOMEM, -1)
#define SLEEP_TODO 1500 /* check todo/ every 25 minutes in any case */
#define SLEEP_FUZZ 1 /* slop a bit on sleeps to avoid zeno effect */
#define SLEEP_FOREVER 86400 /* absolute maximum time spent in iopause() */
@@ -49,3 +52,7 @@
#define CHANNELS 2
#define REPORTMAX 10000
#define CHECKSTAT if (errno != error_noent) goto fail;
+
+#include "mxf-send-protos.h"
+#include "mxf-send-globals.h"
+#endif // MXFSEND_H
diff --git a/src/mxf-send/pass.c b/src/mxf-send/pass.c
@@ -2,227 +2,255 @@
/* this file is too long -------------------------------------------- PASSES */
-struct
- {
- unsigned long id; /* if 0, need a new pass */
- int j; /* defined if id; job number */
- int fd; /* defined if id; reading from {local,remote} */
- seek_pos mpos; /* defined if id; mark position */
- substdio ss;
- char buf[128];
- }
-pass[CHANNELS];
-
-void pass_init()
-{
- int c;
- for (c = 0;c < CHANNELS;++c) pass[c].id = 0;
+struct {
+ unsigned long id; /* if 0, need a new pass */
+ int j; /* defined if id; job number */
+ int fd; /* defined if id; reading from {local,remote} */
+ seek_pos mpos; /* defined if id; mark position */
+ substdio ss;
+ char buf[128];
}
+ pass[CHANNELS];
-void pass_selprep(datetime_sec *wakeup)
+void
+pass_init()
{
- int c;
- struct prioq_elt pe;
- if (flagexitasap) return;
- for (c = 0;c < CHANNELS;++c)
- if (pass[c].id)
- if (del_avail(c))
- { *wakeup = 0; return; }
- if (job_avail())
- for (c = 0;c < CHANNELS;++c)
- if (!pass[c].id)
- if (prioq_min(&pqchan[c],&pe))
- if (*wakeup > pe.dt)
- *wakeup = pe.dt;
- if (prioq_min(&pqfail,&pe))
- if (*wakeup > pe.dt)
- *wakeup = pe.dt;
- if (prioq_min(&pqdone,&pe))
- if (*wakeup > pe.dt)
- *wakeup = pe.dt;
+ int c;
+ for (c = 0; c < CHANNELS; ++c)
+ pass[c].id = 0;
}
-static datetime_sec squareroot(datetime_sec x)
-/* result^2 <= x < (result + 1)^2 */
-/* assuming: >= 0 */
+void
+pass_selprep(datetime_sec * wakeup)
{
- datetime_sec y;
- datetime_sec yy;
- datetime_sec y21;
- int j;
-
- y = 0; yy = 0;
- for (j = 15;j >= 0;--j)
- {
- y21 = (y << (j + 1)) + (1 << (j + j));
- if (y21 <= x - yy) { y += (1 << j); yy += y21; }
- }
- return y;
+ int c;
+ struct prioq_elt pe;
+ if (flagexitasap)
+ return;
+ for (c = 0; c < CHANNELS; ++c)
+ if (pass[c].id)
+ if (del_avail(c)) {
+ *wakeup = 0;
+ return;
+ }
+ if (job_avail())
+ for (c = 0; c < CHANNELS; ++c)
+ if (!pass[c].id)
+ if (prioq_min(&pqchan[c], &pe))
+ if (*wakeup > pe.dt)
+ *wakeup = pe.dt;
+ if (prioq_min(&pqfail, &pe))
+ if (*wakeup > pe.dt)
+ *wakeup = pe.dt;
+ if (prioq_min(&pqdone, &pe))
+ if (*wakeup > pe.dt)
+ *wakeup = pe.dt;
+}
+
+static datetime_sec squareroot(datetime_sec x) {
+ /* result^2 <= x < (result + 1)^2 */
+ /* assuming: >= 0 */
+ datetime_sec y;
+ datetime_sec yy;
+ datetime_sec y21;
+ int j;
+
+ y = 0;
+ yy = 0;
+ for (j = 15; j >= 0; --j) {
+ y21 = (y << (j + 1)) + (1 << (j + j));
+ if (y21 <= x - yy) {
+ y += (1 << j);
+ yy += y21;
+ }
+ }
+ return y;
}
-datetime_sec nextretry(datetime_sec birth, int c)
+datetime_sec
+nextretry(datetime_sec birth, int c)
{
- datetime_sec n;
+ datetime_sec n;
- if (birth > recent) n = 0;
- else n = squareroot(recent - birth); /* no need to add fuzz to recent */
- n += chanskip[c];
- return birth + n * n;
+ if (birth > recent)
+ n = 0;
+ else
+ n = squareroot(recent - birth); /* no need to add fuzz to
+ * recent */
+ n += chanskip[c];
+ return birth + n * n;
}
-void pass_dochan(int c)
+void
+pass_dochan(int c)
{
- datetime_sec birth;
- struct prioq_elt pe;
- static stralloc line = {0};
- int match;
-
- if (flagexitasap) return;
-
- if (!pass[c].id)
- {
- if (!job_avail()) return;
- if (!prioq_min(&pqchan[c],&pe)) return;
- if (pe.dt > recent) return;
- fnmake_chanaddr(pe.id,c);
-
- prioq_delmin(&pqchan[c]);
- pass[c].mpos = 0;
- pass[c].fd = open_read(fn.s);
- if (pass[c].fd == -1) goto trouble;
- if (!getinfo(&line,&birth,pe.id)) { close(pass[c].fd); goto trouble; }
- pass[c].id = pe.id;
- substdio_fdbuf(&pass[c].ss,read,pass[c].fd,pass[c].buf,sizeof(pass[c].buf));
- pass[c].j = job_open(pe.id,c);
- jo[pass[c].j].retry = nextretry(birth,c);
- jo[pass[c].j].flagdying = (recent > birth + lifetime);
- while (!stralloc_copy(&jo[pass[c].j].sender,&line)) nomem();
- }
-
- if (!del_avail(c)) return;
-
- if (getln(&pass[c].ss,&line,&match,'\0') == -1)
- {
- fnmake_chanaddr(pass[c].id,c);
- log3("warning: trouble reading ",fn.s,"; will try again later\n");
- close(pass[c].fd);
- job_close(pass[c].j);
- pass[c].id = 0;
- return;
- }
- if (!match)
- {
- close(pass[c].fd);
- jo[pass[c].j].flaghiteof = 1;
- job_close(pass[c].j);
- pass[c].id = 0;
- return;
- }
- switch(line.s[0])
- {
- case 'T':
- ++jo[pass[c].j].numtodo;
- del_start(pass[c].j,pass[c].mpos,line.s + 1);
- break;
- case 'D':
- break;
- default:
- fnmake_chanaddr(pass[c].id,c);
- log3("warning: unknown record type in ",fn.s,"!\n");
- close(pass[c].fd);
- job_close(pass[c].j);
- pass[c].id = 0;
- return;
- }
-
- pass[c].mpos += line.len;
- return;
-
- trouble:
- log3("warning: trouble opening ",fn.s,"; will try again later\n");
- pe.dt = recent + SLEEP_SYSFAIL;
- while (!prioq_insert(&pqchan[c],&pe)) nomem();
+ datetime_sec birth;
+ struct prioq_elt pe;
+ static stralloc line = {
+ 0
+ };
+ int match;
+
+ if (flagexitasap)
+ return;
+
+ if (!pass[c].id) {
+ if (!job_avail())
+ return;
+ if (!prioq_min(&pqchan[c], &pe))
+ return;
+ if (pe.dt > recent)
+ return;
+ fnmake_chanaddr(pe.id, c);
+
+ prioq_delmin(&pqchan[c]);
+ pass[c].mpos = 0;
+ pass[c].fd = open_read(fn.s);
+ if (pass[c].fd == -1)
+ goto trouble;
+ if (!getinfo(&line, &birth, pe.id)) {
+ close(pass[c].fd);
+ goto trouble;
+ }
+ pass[c].id = pe.id;
+ substdio_fdbuf(&pass[c].ss, read, pass[c].fd, pass[c].buf, sizeof(pass[c].buf));
+ pass[c].j = job_open(pe.id, c);
+ jo[pass[c].j].retry = nextretry(birth, c);
+ jo[pass[c].j].flagdying = (recent > birth + lifetime);
+ while (!stralloc_copy(&jo[pass[c].j].sender, &line))
+ nomem();
+ }
+
+ if (!del_avail(c))
+ return;
+
+ if (getln(&pass[c].ss, &line, &match, '\0') == -1) {
+ fnmake_chanaddr(pass[c].id, c);
+ log3("warning: trouble reading ", fn.s, "; will try again later\n");
+ close(pass[c].fd);
+ job_close(pass[c].j);
+ pass[c].id = 0;
+ return;
+ }
+ if (!match) {
+ close(pass[c].fd);
+ jo[pass[c].j].flaghiteof = 1;
+ job_close(pass[c].j);
+ pass[c].id = 0;
+ return;
+ }
+ switch (line.s[0]) {
+ case 'T':
+ ++jo[pass[c].j].numtodo;
+ del_start(pass[c].j, pass[c].mpos, line.s + 1);
+ break;
+ case 'D':
+ break;
+ default:
+ fnmake_chanaddr(pass[c].id, c);
+ log3("warning: unknown record type in ", fn.s, "!\n");
+ close(pass[c].fd);
+ job_close(pass[c].j);
+ pass[c].id = 0;
+ return;
+ }
+
+ pass[c].mpos += line.len;
+ return;
+
+trouble:
+ log3("warning: trouble opening ", fn.s, "; will try again later\n");
+ pe.dt = recent + SLEEP_SYSFAIL;
+ while (!prioq_insert(&pqchan[c], &pe))
+ nomem();
}
-void messdone(unsigned long id)
+void
+messdone(unsigned long id)
{
- char ch;
- int c;
- struct prioq_elt pe;
- struct stat st;
-
- for (c = 0;c < CHANNELS;++c)
- {
- fnmake_chanaddr(id,c);
- if (stat(fn.s,&st) == 0) return; /* false alarm; consequence of HOPEFULLY */
- if (errno != error_noent)
- {
- log3("warning: unable to stat ",fn.s,"; will try again later\n");
- goto fail;
- }
- }
-
- fnmake_todo(id);
- if (stat(fn.s,&st) == 0) return;
- if (errno != error_noent)
- {
- log3("warning: unable to stat ",fn.s,"; will try again later\n");
- goto fail;
- }
-
- fnmake_info(id);
- if (stat(fn.s,&st) == -1)
- {
- if (errno == error_noent) return;
- log3("warning: unable to stat ",fn.s,"; will try again later\n");
- goto fail;
- }
-
- /* -todo +info -local -remote ?bounce */
- if (!injectbounce(id))
- goto fail; /* injectbounce() produced error message */
-
- strnum3[fmt_ulong(strnum3,id)] = 0;
- log3("end msg ",strnum3,"\n");
-
- /* -todo +info -local -remote -bounce */
- fnmake_info(id);
- if (unlink(fn.s) == -1)
- {
- log3("warning: unable to unlink ",fn.s,"; will try again later\n");
- goto fail;
- }
-
- /* -todo -info -local -remote -bounce; we can relax */
- fnmake_foop(id);
- if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; }
- if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; }
- if (ch != '+')
- log3("warning: qmail-clean unable to clean up ",fn.s,"\n");
-
- return;
-
- fail:
- pe.id = id; pe.dt = now() + SLEEP_SYSFAIL;
- while (!prioq_insert(&pqdone,&pe)) nomem();
+ char ch;
+ int c;
+ struct prioq_elt pe;
+ struct stat st;
+
+ for (c = 0; c < CHANNELS; ++c) {
+ fnmake_chanaddr(id, c);
+ if (stat(fn.s, &st) == 0)
+ return; /* false alarm; consequence of HOPEFULLY */
+ if (errno != error_noent) {
+ log3("warning: unable to stat ", fn.s, "; will try again later\n");
+ goto fail;
+ }
+ }
+
+ fnmake_todo(id);
+ if (stat(fn.s, &st) == 0)
+ return;
+ if (errno != error_noent) {
+ log3("warning: unable to stat ", fn.s, "; will try again later\n");
+ goto fail;
+ }
+
+ fnmake_info(id);
+ if (stat(fn.s, &st) == -1) {
+ if (errno == error_noent)
+ return;
+ log3("warning: unable to stat ", fn.s, "; will try again later\n");
+ goto fail;
+ }
+
+ /* -todo +info -local -remote ?bounce */
+ if (!injectbounce(id))
+ goto fail; /* injectbounce() produced error message */
+
+ strnum3[fmt_ulong(strnum3, id)] = 0;
+ log3("end msg ", strnum3, "\n");
+
+ /* -todo +info -local -remote -bounce */
+ fnmake_info(id);
+ if (unlink(fn.s) == -1) {
+ log3("warning: unable to unlink ", fn.s, "; will try again later\n");
+ goto fail;
+ }
+
+ /* -todo -info -local -remote -bounce; we can relax */
+ fnmake_foop(id);
+ if (substdio_putflush(&sstoqc, fn.s, fn.len) == -1) {
+ cleandied();
+ return;
+ }
+ if (substdio_get(&ssfromqc, &ch, 1) != 1) {
+ cleandied();
+ return;
+ }
+ if (ch != '+')
+ log3("warning: qmail-clean unable to clean up ", fn.s, "\n");
+
+ return;
+
+fail:
+ pe.id = id;
+ pe.dt = now() + SLEEP_SYSFAIL;
+ while (!prioq_insert(&pqdone, &pe))
+ nomem();
}
-void pass_do()
+void
+pass_do()
{
- int c;
- struct prioq_elt pe;
-
- for (c = 0;c < CHANNELS;++c) pass_dochan(c);
- if (prioq_min(&pqfail,&pe))
- if (pe.dt <= recent)
- {
- prioq_delmin(&pqfail);
- pqadd(pe.id);
- }
- if (prioq_min(&pqdone,&pe))
- if (pe.dt <= recent)
- {
- prioq_delmin(&pqdone);
- messdone(pe.id);
- }
+ int c;
+ struct prioq_elt pe;
+
+ for (c = 0; c < CHANNELS; ++c)
+ pass_dochan(c);
+ if (prioq_min(&pqfail, &pe))
+ if (pe.dt <= recent) {
+ prioq_delmin(&pqfail);
+ pqadd(pe.id);
+ }
+ if (prioq_min(&pqdone, &pe))
+ if (pe.dt <= recent) {
+ prioq_delmin(&pqdone);
+ messdone(pe.id);
+ }
}
diff --git a/src/mxf-send/rewrite.c b/src/mxf-send/rewrite.c
@@ -0,0 +1,133 @@
+#include "mxf-send.h"
+/* this file is too long ----------------------------------------- REWRITING */
+
+stralloc rwline = {0}; // XXX should be passed into rewrite, not a global
+
+#define AMNESIAC (errno = ENOMEM, -1)
+/* MXF TODO: change semantics to
+ * -1 ENOMEM if forgetful,
+ * -1 ENOENT if can't find channel,
+ * channel number if going to a channel. currently just 0 for local and 1 for remote
+ * MXF TODO: if slots are available, callers should automatically
+ * try to reach that channel to schedule a delivery after calling
+ * this.
+ * MXF TODO: callers should barf if -1 and errno isn't enomem or enoent.
+ */
+/* may trash recip. must set up rwline, between a T and a \0. */
+int
+rewrite(char *recip)
+{
+ unsigned int i;
+ char *x;
+ static stralloc addr = TA_ZERO;
+ unsigned int at;
+
+ if (!stralloc_copys(&rwline, "T"))
+ return AMNESIAC;
+ if (!stralloc_copys(&addr, recip))
+ return AMNESIAC;
+
+ i = byte_rchr(addr.s, addr.len, '@');
+ if (i == addr.len) {
+ if (!stralloc_cats(&addr, "@"))
+ return AMNESIAC;
+ if (!stralloc_cat(&addr, &envnoathost))
+ return AMNESIAC;
+ }
+
+ /* MXF NOTE: Double tap now if you'd scrunkly the when!
+ * This makes no sense. This is a crock. Nobody actually uses the
+ * percent hack.
+ * A respectable site with UUCP source routing allows local parts
+ * to contain exclamatories.
+ */
+ while (constmap(&mappercenthack, addr.s + i + 1, addr.len - i - 1)) {
+ unsigned int j = byte_rchr(addr.s, i, '%');
+ if (j == i)
+ break;
+ addr.len = i;
+ i = j;
+ addr.s[i] = '@';
+ }
+
+ at = byte_rchr(addr.s, addr.len, '@');
+
+ /* MXF NOTE: so what's happening here is that addr, our static,
+ * the value to the right of @ is being checked against
+ * constmap maplocals. Return 1 if "by land" (local).
+ */
+ if (constmap(&maplocals, addr.s + at + 1, addr.len - at - 1)) {
+ if (!stralloc_cat(&rwline, &addr))
+ return AMNESIAC;
+ if (!stralloc_0(&rwline))
+ return AMNESIAC;
+ return 0;
+ }
+
+ /* MXF NOTE: so what's happening here is that addr, our static,
+ * if start of addrlen, or if one after the @, or if at end,
+ * or if cursor>at and addr.s[cursor] is an ascii dot,
+ * then if constmap returns anything useful,
+ * prepend the virtual prepend (XXX uses "-" even if different
+ * dash is used), and return 1 since by land (local).
+ * TODO: turn to different channel idea
+ */
+ for (i = 0; i <= addr.len; ++i)
+ if (!i || (i == at + 1) || (i == addr.len) || ((i > at) && (addr.s[i] == '.')))
+ if ((x = constmap(&mapvdoms, addr.s + i, addr.len - i))) {
+ if (!*x)
+ break;
+ if (!stralloc_cats(&rwline, x))
+ return AMNESIAC;
+ if (!stralloc_cats(&rwline, "-"))
+ return AMNESIAC;
+ if (!stralloc_cat(&rwline, &addr))
+ return AMNESIAC;
+ if (!stralloc_0(&rwline))
+ return AMNESIAC;
+ return 0;
+ }
+
+ if (!stralloc_cat(&rwline, &addr))
+ return AMNESIAC;
+ if (!stralloc_0(&rwline))
+ return AMNESIAC;
+ /* MXF NOTE: it isn't going down channel 0, so it's going down channel 1.
+ */
+ return 1;
+}
+
+// QUERY should return AMNESIAC?
+void
+senderadd(stralloc * sa, char *sender, char *recip)
+{
+ unsigned int i;
+
+ i = str_len(sender);
+ if (i >= 4)
+ if (str_equal(sender + i - 4, "-@[]")) {
+ unsigned int j = byte_rchr(sender, i - 4, '@');
+ unsigned int k = str_rchr(recip, '@');
+ if (recip[k] && (j + 5 <= i)) {
+ /*
+ * owner-@host-@[] ->
+ * owner-recipbox=reciphost@host
+ */
+ while (!stralloc_catb(sa, sender, j))
+ nomem();
+ while (!stralloc_catb(sa, recip, k))
+ nomem();
+ while (!stralloc_cats(sa, "="))
+ nomem();
+ while (!stralloc_cats(sa, recip + k + 1))
+ nomem();
+ while (!stralloc_cats(sa, "@"))
+ nomem();
+ while (!stralloc_catb(sa, sender + j + 1, i - 5 - j))
+ nomem();
+ return;
+ }
+ }
+ while (!stralloc_cats(sa, sender))
+ nomem();
+}
diff --git a/src/mxf-send/todo.c b/src/mxf-send/todo.c
@@ -2,221 +2,271 @@
/* this file is too long ---------------------------------------------- TODO */
datetime_sec nexttodorun;
-DIR *tododir; /* if 0, have to opendir again */
+DIR *tododir; /* if 0, have to opendir again */
stralloc todoline = {0};
char todobuf[SUBSTDIO_INSIZE];
char todobufinfo[512];
char todobufchan[CHANNELS][1024];
-void todo_init()
+void
+todo_init()
{
- tododir = 0;
- nexttodorun = now();
- trigger_set();
+ tododir = 0;
+ nexttodorun = now();
+ trigger_set();
}
-void todo_selprep(int *nfds, fd_set *rfds, datetime_sec *wakeup)
+void
+todo_selprep(int *nfds, fd_set * rfds, datetime_sec * wakeup)
{
- if (flagexitasap) return;
- trigger_selprep(nfds,rfds);
- if (tododir) *wakeup = 0;
- if (*wakeup > nexttodorun) *wakeup = nexttodorun;
+ if (flagexitasap)
+ return;
+ trigger_selprep(nfds, rfds);
+ if (tododir)
+ *wakeup = 0;
+ if (*wakeup > nexttodorun)
+ *wakeup = nexttodorun;
}
-// XXX XXX - need to refactor this into a todo_dochan
-void todo_do(fd_set *rfds)
+//XXX XXX - need to refactor this into a todo_doone
+void
+todo_do(fd_set * rfds)
{
- struct stat st;
- substdio ss; int fd;
- substdio ssinfo; int fdinfo;
- substdio sschan[CHANNELS];
- int fdchan[CHANNELS];
- int flagchan[CHANNELS];
- struct prioq_elt pe;
- char ch;
- int match;
- unsigned long id;
- unsigned int len;
- direntry *dent;
- int c;
- unsigned long uid;
- unsigned long pid;
-
- fd = -1;
- fdinfo = -1;
- for (c = 0;c < CHANNELS;++c) fdchan[c] = -1;
-
- if (flagexitasap) return;
-
- if (!tododir)
- {
- if (!trigger_pulled(rfds))
- if (recent < nexttodorun)
- return;
- trigger_set();
- tododir = opendir("todo");
- if (!tododir)
- {
- pausedir("todo");
- return;
- }
- nexttodorun = recent + SLEEP_TODO;
- }
-
- dent = readdir(tododir);
- if (!dent)
- {
- closedir(tododir);
- tododir = 0;
- return;
- }
- if (str_equal(dent->d_name,".")) return;
- if (str_equal(dent->d_name,"..")) return;
- len = scan_ulong(dent->d_name,&id);
- if (!len || dent->d_name[len]) return;
-
- fnmake_todo(id);
-
- fd = open_read(fn.s);
- if (fd == -1) { log3("warning: unable to open ",fn.s,"\n"); return; }
-
- fnmake_mess(id);
- /* just for the statistics */
- if (stat(fn.s,&st) == -1)
- { log3("warning: unable to stat ",fn.s,"\n"); goto fail; }
-
- for (c = 0;c < CHANNELS;++c)
- {
- fnmake_chanaddr(id,c);
- if (unlink(fn.s) == -1) if (errno != error_noent)
- { log3("warning: unable to unlink ",fn.s,"\n"); goto fail; }
- }
-
- fnmake_info(id);
- if (unlink(fn.s) == -1) if (errno != error_noent)
- { log3("warning: unable to unlink ",fn.s,"\n"); goto fail; }
-
- fdinfo = open_excl(fn.s);
- if (fdinfo == -1)
- { log3("warning: unable to create ",fn.s,"\n"); goto fail; }
-
- strnum3[fmt_ulong(strnum3,id)] = 0;
- log3("new msg ",strnum3,"\n");
-
- for (c = 0;c < CHANNELS;++c) flagchan[c] = 0;
-
- substdio_fdbuf(&ss,read,fd,todobuf,sizeof(todobuf));
- substdio_fdbuf(&ssinfo,write,fdinfo,todobufinfo,sizeof(todobufinfo));
-
- uid = 0;
- pid = 0;
-
- for (;;)
- {
- if (getln(&ss,&todoline,&match,'\0') == -1)
- {
- /* perhaps we're out of memory, perhaps an I/O error */
- fnmake_todo(id);
- log3("warning: trouble reading ",fn.s,"\n"); goto fail;
- }
- if (!match) break;
-
- switch(todoline.s[0])
- {
- case 'u':
- scan_ulong(todoline.s + 1,&uid);
- break;
- case 'p':
- scan_ulong(todoline.s + 1,&pid);
- break;
- case 'F':
- if (substdio_putflush(&ssinfo,todoline.s,todoline.len) == -1)
- {
- fnmake_info(id);
- log3("warning: trouble writing to ",fn.s,"\n"); goto fail;
+ struct stat st;
+ substdio ss;
+ int fd;
+ substdio ssinfo;
+ int fdinfo;
+ substdio sschan[CHANNELS];
+ int fdchan[CHANNELS];
+ int flagchan[CHANNELS];
+ struct prioq_elt pe;
+ char ch;
+ int match;
+ unsigned long id;
+ unsigned int len;
+ direntry *dent;
+ int c;
+ unsigned long uid;
+ unsigned long pid;
+
+ fd = -1;
+ fdinfo = -1;
+ for (c = 0; c < CHANNELS; ++c)
+ fdchan[c] = -1;
+
+ if (flagexitasap)
+ return;
+
+ if (!tododir) {
+ if (!trigger_pulled(rfds))
+ if (recent < nexttodorun)
+ return;
+ trigger_set();
+ tododir = opendir("todo");
+ if (!tododir) {
+ pausedir("todo");
+ return;
+ }
+ nexttodorun = recent + SLEEP_TODO;
+ }
+
+ dent = readdir(tododir);
+ if (!dent) {
+ closedir(tododir);
+ tododir = 0;
+ return;
+ }
+ if (str_equal(dent->d_name, "."))
+ return;
+ if (str_equal(dent->d_name, ".."))
+ return;
+ len = scan_ulong(dent->d_name, &id);
+ if (!len || dent->d_name[len])
+ return;
+
+ fnmake_todo(id);
+
+ fd = open_read(fn.s);
+ if (fd == -1) {
+ log3("warning: unable to open ", fn.s, "\n");
+ return;
+ }
+
+ fnmake_mess(id);
+ /* just for the statistics */
+ if (stat(fn.s, &st) == -1) {
+ log3("warning: unable to stat ", fn.s, "\n");
+ goto fail;
+ }
+
+ for (c = 0; c < CHANNELS; ++c) {
+ fnmake_chanaddr(id, c);
+ if (unlink(fn.s) == -1)
+ if (errno != error_noent) {
+ log3("warning: unable to unlink ", fn.s, "\n");
+ goto fail;
+ }
+ }
+
+ fnmake_info(id);
+ if (unlink(fn.s) == -1)
+ if (errno != error_noent) {
+ log3("warning: unable to unlink ", fn.s, "\n");
+ goto fail;
+ }
+
+ fdinfo = open_excl(fn.s);
+ if (fdinfo == -1) {
+ log3("warning: unable to create ", fn.s, "\n");
+ goto fail;
+ }
+
+ strnum3[fmt_ulong(strnum3, id)] = 0;
+ log3("new msg ", strnum3, "\n");
+
+ for (c = 0; c < CHANNELS; ++c)
+ flagchan[c] = 0;
+
+ substdio_fdbuf(&ss, read, fd, todobuf, sizeof(todobuf));
+ substdio_fdbuf(&ssinfo, write, fdinfo, todobufinfo, sizeof(todobufinfo));
+
+ uid = 0;
+ pid = 0;
+
+ for (;;) {
+ if (getln(&ss, &todoline, &match, '\0') == -1) {
+ /* perhaps we're out of memory, perhaps an I/O error */
+ fnmake_todo(id);
+ log3("warning: trouble reading ", fn.s, "\n");
+ goto fail;
+ }
+ if (!match)
+ break;
+
+ switch (todoline.s[0]) {
+ case 'u':
+ scan_ulong(todoline.s + 1, &uid);
+ break;
+ case 'p':
+ scan_ulong(todoline.s + 1, &pid);
+ break;
+ case 'F':
+ if (substdio_putflush(&ssinfo, todoline.s, todoline.len) == -1) {
+ fnmake_info(id);
+ log3("warning: trouble writing to ", fn.s, "\n");
+ goto fail;
+ }
+ qslog2("info msg ", strnum3);
+ strnum2[fmt_ulong(strnum2, (unsigned long)st.st_size)] = 0;
+ qslog2(": bytes ", strnum2);
+ log1(" from <");
+ logsafe(todoline.s + 1);
+ strnum2[fmt_ulong(strnum2, pid)] = 0;
+ qslog2("> qp ", strnum2);
+ strnum2[fmt_ulong(strnum2, uid)] = 0;
+ qslog2(" uid ", strnum2);
+ log1("\n");
+ break;
+ case 'T':
+ switch (c = rewrite(todoline.s + 1)) {
+ case -1:
+ if (errno == ENOMEM) nomem();
+ goto fail;
+ default:
+ //c = 0;
+ break;
+ }
+ if (fdchan[c] == -1) {
+ fnmake_chanaddr(id, c);
+ fdchan[c] = open_excl(fn.s);
+ if (fdchan[c] == -1) {
+ log3("warning: unable to create ", fn.s, "\n");
+ goto fail;
+ }
+ substdio_fdbuf(&sschan[c]
+ ,write, fdchan[c], todobufchan[c], sizeof(todobufchan[c]));
+ flagchan[c] = 1;
+ }
+ if (substdio_bput(&sschan[c], rwline.s, rwline.len) == -1) {
+ fnmake_chanaddr(id, c);
+ log3("warning: trouble writing to ", fn.s, "\n");
+ goto fail;
+ }
+ break;
+ default:
+ fnmake_todo(id);
+ log3("warning: unknown record type in ", fn.s, "\n");
+ goto fail;
+ }
}
- qslog2("info msg ",strnum3);
- strnum2[fmt_ulong(strnum2,(unsigned long) st.st_size)] = 0;
- qslog2(": bytes ",strnum2);
- log1(" from <"); logsafe(todoline.s + 1);
- strnum2[fmt_ulong(strnum2,pid)] = 0;
- qslog2("> qp ",strnum2);
- strnum2[fmt_ulong(strnum2,uid)] = 0;
- qslog2(" uid ",strnum2);
- log1("\n");
- break;
- case 'T':
- switch(rewrite(todoline.s + 1))
- {
- case 0: nomem(); goto fail;
- case 2: c = 1; break;
- default: c = 0; break;
- }
- if (fdchan[c] == -1)
- {
- fnmake_chanaddr(id,c);
- fdchan[c] = open_excl(fn.s);
- if (fdchan[c] == -1)
- { log3("warning: unable to create ",fn.s,"\n"); goto fail; }
- substdio_fdbuf(&sschan[c]
- ,write,fdchan[c],todobufchan[c],sizeof(todobufchan[c]));
- flagchan[c] = 1;
+
+ close(fd);
+ fd = -1;
+
+ fnmake_info(id);
+ if (substdio_flush(&ssinfo) == -1) {
+ log3("warning: trouble writing to ", fn.s, "\n");
+ goto fail;
}
- if (substdio_bput(&sschan[c],rwline.s,rwline.len) == -1)
- {
- fnmake_chanaddr(id,c);
- log3("warning: trouble writing to ",fn.s,"\n"); goto fail;
- }
- break;
- default:
- fnmake_todo(id);
- log3("warning: unknown record type in ",fn.s,"\n"); goto fail;
- }
- }
-
- close(fd); fd = -1;
-
- fnmake_info(id);
- if (substdio_flush(&ssinfo) == -1)
- { log3("warning: trouble writing to ",fn.s,"\n"); goto fail; }
- if (fsync(fdinfo) == -1)
- { log3("warning: trouble fsyncing ",fn.s,"\n"); goto fail; }
- close(fdinfo); fdinfo = -1;
-
- for (c = 0;c < CHANNELS;++c)
- if (fdchan[c] != -1)
- {
- fnmake_chanaddr(id,c);
- if (substdio_flush(&sschan[c]) == -1)
- { log3("warning: trouble writing to ",fn.s,"\n"); goto fail; }
- if (fsync(fdchan[c]) == -1)
- { log3("warning: trouble fsyncing ",fn.s,"\n"); goto fail; }
- close(fdchan[c]); fdchan[c] = -1;
- }
-
- fnmake_todo(id);
- if (substdio_putflush(&sstoqc,fn.s,fn.len) == -1) { cleandied(); return; }
- if (substdio_get(&ssfromqc,&ch,1) != 1) { cleandied(); return; }
- if (ch != '+')
- {
- log3("warning: qmail-clean unable to clean up ",fn.s,"\n");
- return;
- }
-
- pe.id = id; pe.dt = now();
- for (c = 0;c < CHANNELS;++c)
- if (flagchan[c])
- while (!prioq_insert(&pqchan[c],&pe)) nomem();
-
- for (c = 0;c < CHANNELS;++c) if (flagchan[c]) break;
- if (c == CHANNELS)
- while (!prioq_insert(&pqdone,&pe)) nomem();
-
- return;
-
- fail:
- if (fd != -1) close(fd);
- if (fdinfo != -1) close(fdinfo);
- for (c = 0;c < CHANNELS;++c)
- if (fdchan[c] != -1) close(fdchan[c]);
+ if (fsync(fdinfo) == -1) {
+ log3("warning: trouble fsyncing ", fn.s, "\n");
+ goto fail;
+ }
+ close(fdinfo);
+ fdinfo = -1;
+
+ for (c = 0; c < CHANNELS; ++c)
+ if (fdchan[c] != -1) {
+ fnmake_chanaddr(id, c);
+ if (substdio_flush(&sschan[c]) == -1) {
+ log3("warning: trouble writing to ", fn.s, "\n");
+ goto fail;
+ }
+ if (fsync(fdchan[c]) == -1) {
+ log3("warning: trouble fsyncing ", fn.s, "\n");
+ goto fail;
+ }
+ close(fdchan[c]);
+ fdchan[c] = -1;
+ }
+
+ fnmake_todo(id);
+ if (substdio_putflush(&sstoqc, fn.s, fn.len) == -1) {
+ cleandied();
+ return;
+ }
+ if (substdio_get(&ssfromqc, &ch, 1) != 1) {
+ cleandied();
+ return;
+ }
+ if (ch != '+') {
+ log3("warning: qmail-clean unable to clean up ", fn.s, "\n");
+ return;
+ }
+
+ pe.id = id;
+ pe.dt = now();
+ for (c = 0; c < CHANNELS; ++c)
+ if (flagchan[c])
+ while (!prioq_insert(&pqchan[c], &pe))
+ nomem();
+
+ for (c = 0; c < CHANNELS; ++c)
+ if (flagchan[c])
+ break;
+ if (c == CHANNELS)
+ while (!prioq_insert(&pqdone, &pe))
+ nomem();
+
+ return;
+
+fail:
+ if (fd != -1)
+ close(fd);
+ if (fdinfo != -1)
+ close(fdinfo);
+ for (c = 0; c < CHANNELS; ++c)
+ if (fdchan[c] != -1)
+ close(fdchan[c]);
}
diff --git a/src/nmail-smtpd.c b/src/nmail-smtpd.c
@@ -33,66 +33,170 @@
unsigned int databytes = 0;
int timeout = 1200;
-GEN_SAFE_TIMEOUTWRITE(safewrite,timeout,fd,_exit(10))
+GEN_SAFE_TIMEOUTWRITE(safewrite, timeout, fd, _exit(10))
char ssoutbuf[512];
-substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof(ssoutbuf));
+substdio ssout = SUBSTDIO_FDBUF(safewrite, 1, ssoutbuf, sizeof(ssoutbuf));
-void flush() { substdio_flush(&ssout); }
-void out(s) char *s; { substdio_puts(&ssout,s); }
+void flush() {
+ substdio_flush(&ssout);
+}
+void out(s)
+char *s; {
+ substdio_puts(&ssout, s);
+}
-void die_read() { _exit(1); }
-void die_alarm() { out("451 4.4.2 Timeout\r\n"); flush(); _exit(2); }
-void die_nomem() { out("421 4.3.0 Out of memory\r\n"); flush(); _exit(3); }
-void die_control() { out("421 4.3.0 Unable to read controls\r\n"); flush(); _exit(4); }
-void die_ipme() { out("421 4.3.0 Unable to figure out my IP addresses\r\n"); flush(); _exit(5); }
-void die_ip6me() { out("421 4.3.0 Unable to figure out my IPv6 addresses\r\n"); flush(); _exit(6); }
-void straynewline() { out("451 You sent a stray newline. See https://cr.yp.to/docs/smtplf.html.\r\n"); flush(); _exit(1); }
+void die_read() {
+ _exit(1);
+}
+void die_alarm() {
+ out("451 4.4.2 Timeout\r\n");
+ flush();
+ _exit(2);
+}
+void die_nomem() {
+ out("421 4.3.0 Out of memory\r\n");
+ flush();
+ _exit(3);
+}
+void die_control() {
+ out("421 4.3.0 Unable to read controls\r\n");
+ flush();
+ _exit(4);
+}
+void die_ipme() {
+ out("421 4.3.0 Unable to figure out my IP addresses\r\n");
+ flush();
+ _exit(5);
+}
+void die_ip6me() {
+ out("421 4.3.0 Unable to figure out my IPv6 addresses\r\n");
+ flush();
+ _exit(6);
+}
+void straynewline() {
+ out("451-You sent a stray newline. See https://cr.yp.to/docs/smtplf.html.\r\n451 This error should be going away soon.");
+ flush();
+ _exit(1);
+}
char ssebuf[1024];
-substdio sse = SUBSTDIO_FDBUF(write,2,ssebuf,sizeof(ssebuf));
-void err(char *s) { substdio_putsflush(&sse,s); }
-
-void err_bmf() { out("553 5.7.1 Sorry, your envelope sender is in my badmailfrom list.\r\n"); }
-void err_nogateway() { out("553 5.7.1 Sorry, that domain isn't in my list of allowed rcpthosts\r\n"); }
-void err_unimpl(char *arg) { out("502 5.5.1 Unimplemented\r\n"); }
-void err_syntax() { out("555 5.5.4 Syntax error\r\n"); }
-void die_wtf(int d, char *arg) { out("421 4.3.2 inconsistent state: "); out(arg); out(" - shutting down!\r\n"); flush();
-err("421 4.3.2 inconsistent state: "); err(arg); err(" - shutting down!\r\n"); _exit(d); }
-void err_wantmail() { out("503 5.5.1 You must execute MAIL first\r\n"); }
-void err_wantrcpt() { out("503 5.5.1 You must execute RCPT first\r\n"); }
-void err_notlshere() { out("454 4.7.6 STARTTLS is not available at this site.\r\n"); }
-void err_alreadytlshere() { out("454 5.7.6 STARTTLS is already active on this connection.\r\n"); }
-void die_cdb() { out("421 4.3.0 Unable to read cdb user database\r\n"); flush(); _exit(7); }
-void die_sys() { out("421 4.3.0 Unable to read system user database\r\n"); flush(); _exit(8); }
-void err_noop(char *arg) { out("250 As requested, no operation performed.\r\n"); }
-void err_vrfy(char *arg) { out("252 Send something and we'll give it a shot.\r\n"); }
-void err_qqt() { out("451 4.3.0 Temporarily unavailable: cannot inject message into queue.\r\n"); }
-void die_dnsbl(char *arg)
+substdio sse = SUBSTDIO_FDBUF(write, 2, ssebuf, sizeof(ssebuf));
+void err(char *s){
+ substdio_putsflush(&sse, s);
+}
+
+void err_bmf() {
+ out("553 5.7.1 Sorry, your envelope sender is in my badmailfrom list.\r\n");
+ flush();
+}
+void err_nogateway() {
+ out("553 5.7.1 Sorry, that domain isn't in my list of allowed rcpthosts\r\n");
+ flush();
+}
+void err_unimpl(char *arg){
+ out("502 5.5.1 Unimplemented\r\n");
+ flush();
+}
+void err_syntax() {
+ out("555 5.5.4 Syntax error\r\n");
+ flush();
+}
+void die_wtf(int d, char *arg){
+ out("421 4.3.2 inconsistent state: ");
+ out(arg);
+ out(" - shutting down!\r\n");
+ flush();
+ err("421 4.3.2 inconsistent state: ");
+ err(arg);
+ err(" - shutting down!\r\n");
+ _exit(d);
+}
+void err_wantmail() {
+ out("503 5.5.1 You must execute MAIL first\r\n");
+ flush();
+}
+void err_wantrcpt() {
+ out("503 5.5.1 You must execute RCPT first\r\n");
+ flush();
+}
+void err_notlshere() {
+ out("454 4.7.6 STARTTLS is not available at this site.\r\n");
+ flush();
+}
+void err_alreadytlshere() {
+ out("454 5.7.6 STARTTLS is already active on this connection.\r\n");
+ flush();
+}
+void die_cdb() {
+ out("421 4.3.0 Unable to read cdb user database\r\n");
+ flush();
+ _exit(7);
+}
+void die_sys() {
+ out("421 4.3.0 Unable to read system user database\r\n");
+ flush();
+ _exit(8);
+}
+void die_addresses() {
+ out("501 5.3.0 That's too many addresses!\r\n");
+ flush();
+ _exit(11);
+}
+void err_addresses() {
+ out("501 5.3.0 That's too many addresses!\r\n");
+ flush();
+}
+void err_noop(char *arg){
+ out("250 As requested, no operation performed.\r\n");
+ flush();
+}
+void err_vrfy(char *arg){
+ out("252 Send something and we'll give it a shot.\r\n");
+ flush();
+}
+void err_qqt() {
+ out("451 4.3.0 Temporarily unavailable: cannot inject message into queue.\r\n");
+ flush();
+}
+void
+die_dnsbl(char *arg)
{
- out("421 Your IP is currently blacklisted. If available at this site, auth first. ("); out(arg); out(")\r\n");
- flush();
- _exit(9);
+ out("421 Your IP is currently blacklisted. If available at this site, auth first. (");
+ out(arg);
+ out(")\r\n");
+ flush();
+ _exit(9);
}
stralloc greeting = {0};
int starttlsready = 0, sslctlfd = -1, sslrfd = -1, sslwfd = -1, isstarttls = 0, isesmtp = 0;
-void smtp_greet(code) char *code;
+void
+smtp_greet(code)
+ char *code;
{
- substdio_puts(&ssout,code);
- substdio_put(&ssout,greeting.s,greeting.len);
+ substdio_puts(&ssout, code);
+ substdio_put(&ssout, greeting.s, greeting.len);
}
-void smtp_help(char *arg)
+void
+smtp_help(char *arg)
{
- out("214-NightmareMail home page: <https://umbrellix.net./software/nightmaremail/index.html>\r\n");
- out("214-NightmareMail is based on notqmail. notqmail home page: <https://notqmail.org>\r\n");
- out("214-We accept the following commands: HELO, EHLO, (SEND/SOML/SAML/MAIL) FROM:<, RCPT TO:<, DATA, RSET"); if (starttlsready) out(", STARTTLS"); out("\r\n");
- out("214 Note that SMTP is not a user interface. It should only be used thus to verify correct operation of the mail system.\r\n");
+ out("214-NightmareMail home page: <https://umbrellix.net./software/nightmaremail/index.html>\r\n");
+ out("214-NightmareMail is based on notqmail. notqmail home page: <https://notqmail.org>\r\n");
+ out("214-We accept the following commands: HELO, EHLO, (SEND/SOML/SAML/MAIL) FROM:<, RCPT TO:<, DATA, RSET");
+ if (starttlsready)
+ out(", STARTTLS");
+ out("\r\n");
+ out("214 Note that SMTP is not a user interface. It should only be used thus to verify correct operation of the mail system.\r\n");
}
-void smtp_quit(char *arg)
+void
+smtp_quit(char *arg)
{
- smtp_greet("221 "); out("\r\n"); flush(); _exit(0);
+ smtp_greet("221 ");
+ out("\r\n");
+ flush();
+ _exit(0);
}
char *remoteip;
@@ -103,12 +207,16 @@ char *relayclient;
char *dnsblskip;
stralloc helohost = {0};
-char *fakehelo; /* pointer into helohost, or 0 */
+char *fakehelo; /* pointer into helohost, or 0 */
-void dohelo(char *arg) {
- if (!stralloc_copys(&helohost,arg)) die_nomem();
- if (!stralloc_0(&helohost)) die_nomem();
- fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;
+void
+dohelo(char *arg)
+{
+ if (!stralloc_copys(&helohost, arg))
+ die_nomem();
+ if (!stralloc_0(&helohost))
+ die_nomem();
+ fakehelo = case_diffs(remotehost, helohost.s) ? helohost.s : 0;
}
int liphostok = 0;
@@ -117,64 +225,102 @@ int bmfok = 0;
stralloc bmf = {0};
struct constmap mapbmf;
-void setuptls()
+void
+setuptls()
{
- char *x;
- unsigned long u;
-
- x = env_get("SSLCTLFD");
- if (x) { scan_ulong(x,&u); sslctlfd = u; } else return;
- x = env_get("SSLREADFD");
- if (x) { scan_ulong(x,&u); sslrfd = u; } else return;
- x = env_get("SSLWRITEFD");
- if (x) { scan_ulong(x,&u); sslwfd = u; } else return;
- ndelay_on(sslctlfd);
- //ndelay_on(sslrfd);
- //ndelay_on(sslwfd);
- starttlsready = 1; // if reached, then we can do starttls
- return;
-}
-
-void setup()
+ char *x;
+ unsigned long u;
+
+ x = env_get("SSLCTLFD");
+ if (x) {
+ scan_ulong(x, &u);
+ sslctlfd = u;
+ } else
+ return;
+ x = env_get("SSLREADFD");
+ if (x) {
+ scan_ulong(x, &u);
+ sslrfd = u;
+ } else
+ return;
+ x = env_get("SSLWRITEFD");
+ if (x) {
+ scan_ulong(x, &u);
+ sslwfd = u;
+ } else
+ return;
+ ndelay_on(sslctlfd);
+ /* ndelay_on(sslrfd); */
+ /* ndelay_on(sslwfd); */
+ starttlsready = 1; /* when reached, then we can do starttls */
+ return;
+}
+
+int seenmail = 0;
+int flagbarf; /* defined when seenmail */
+stralloc mailfrom = {0};
+stralloc rcptto = {0};
+int rcpttos = 0, maxrcpttos = 5;
+
+void
+setup()
{
- char *x;
- unsigned long u;
-
- if (control_init() == -1) die_control();
- if (control_rldef(&greeting,"control/smtpgreeting",1,NULL) != 1)
- die_control();
- liphostok = control_rldef(&liphost,"control/localiphost",1,NULL);
- if (liphostok == -1) die_control();
- if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();
- if (timeout <= 0) timeout = 1;
-
- if (rcpthosts_init() == -1) die_control();
-
- bmfok = control_readfile(&bmf,"control/badmailfrom",0);
- if (bmfok == -1) die_control();
- if (bmfok)
- if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
-
- // manually merged from prj's realrcptto patch
- realrcptto_init();
-
- if (control_readint(&databytes,"control/databytes") == -1) die_control();
- x = env_get("DATABYTES");
- if (x) { scan_ulong(x,&u); databytes = u; }
- if (!(databytes + 1)) --databytes;
- setuptls();
-
- remoteip = env_get("TCPREMOTEIP");
- if (!remoteip) remoteip = "unknown";
- local = env_get("TCPLOCALHOST");
- if (!local) local = env_get("TCPLOCALIP");
- if (!local) local = "unknown";
- remotehost = env_get("TCPREMOTEHOST");
- if (!remotehost) remotehost = "unknown";
- remoteinfo = env_get("TCPREMOTEINFO");
- relayclient = env_get("RELAYCLIENT");
- dnsblskip = env_get("DNSBLSKIP");
- dohelo(remotehost);
+ char *x;
+ unsigned long u;
+
+ if (control_init() == -1)
+ die_control();
+ if (control_rldef(&greeting, "control/smtpgreeting", 1, NULL) != 1)
+ die_control();
+ liphostok = control_rldef(&liphost, "control/localiphost", 1, NULL);
+ if (liphostok == -1)
+ die_control();
+ if (control_readint(&timeout, "control/timeoutsmtpd") == -1)
+ die_control();
+ if (timeout <= 0)
+ timeout = 1;
+
+ if (rcpthosts_init() == -1)
+ die_control();
+
+ bmfok = control_readfile(&bmf, "control/badmailfrom", 0);
+ if (bmfok == -1)
+ die_control();
+ if (bmfok)
+ if (!constmap_init(&mapbmf, bmf.s, bmf.len, 0))
+ die_nomem();
+
+ /* manually merged from prj's realrcptto patch */
+ realrcptto_init();
+
+ if (control_readint(&databytes, "control/databytes") == -1)
+ die_control();
+ if (control_readint(&maxrcpttos, "control/maxrcpts") == -1)
+ maxrcpttos = 128; /* proceed with this limit */
+ x = env_get("DATABYTES");
+ if (x) {
+ scan_ulong(x, &u);
+ databytes = u;
+ }
+ if (!(databytes + 1))
+ --databytes;
+ setuptls();
+
+ remoteip = env_get("TCPREMOTEIP");
+ if (!remoteip)
+ remoteip = "unknown";
+ local = env_get("TCPLOCALHOST");
+ if (!local)
+ local = env_get("TCPLOCALIP");
+ if (!local)
+ local = "unknown";
+ remotehost = env_get("TCPREMOTEHOST");
+ if (!remotehost)
+ remotehost = "unknown";
+ remoteinfo = env_get("TCPREMOTEINFO");
+ relayclient = env_get("RELAYCLIENT");
+ dnsblskip = env_get("DNSBLSKIP");
+ dohelo(remotehost);
}
extern void realrcptto_init();
@@ -182,405 +328,590 @@ extern void realrcptto_start();
extern int realrcptto();
extern int realrcptto_deny();
-stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
+stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */
-int addrparse(char *arg)
+int
+addrparse(char *arg)
{
- int i;
- char ch;
- char terminator;
- struct ip_address ip;
- int flagesc;
- int flagquoted;
-
- terminator = '>';
- i = str_chr(arg,'<');
- if (arg[i])
- arg += i + 1;
- else { /* partner should go read rfc 821 */
- terminator = ' ';
- arg += str_chr(arg,':');
- if (*arg == ':') ++arg;
- while (*arg == ' ') ++arg;
- }
-
- /* strip source route */
- if (*arg == '@') while (*arg) if (*arg++ == ':') break;
-
- if (!stralloc_copys(&addr,"")) die_nomem();
- flagesc = 0;
- flagquoted = 0;
- for (i = 0;(ch = arg[i]);++i) { /* copy arg to addr, stripping quotes */
- if (flagesc) {
- if (!stralloc_append(&addr,&ch)) die_nomem();
- flagesc = 0;
- }
- else {
- if (!flagquoted && (ch == terminator)) break;
- switch(ch) {
- case '\\': flagesc = 1; break;
- case '"': flagquoted = !flagquoted; break;
- default: if (!stralloc_append(&addr,&ch)) die_nomem();
- }
- }
- }
- /* could check for termination failure here, but why bother? */
- if (!stralloc_append(&addr,"")) die_nomem();
-
- if (liphostok) {
- i = byte_rchr(addr.s,addr.len,'@');
- if (i < addr.len) /* if not, partner should go read rfc 821 */
- if (addr.s[i + 1] == '[')
- if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1,&ip)])
- if (ipme_is(&ip)) {
- addr.len = i + 1;
- if (!stralloc_cat(&addr,&liphost)) die_nomem();
- if (!stralloc_0(&addr)) die_nomem();
- }
- }
-
- if (addr.len > 900) return 0;
- return 1;
+ int i;
+ char ch;
+ char terminator;
+ struct ip_address ip;
+ int flagesc;
+ int flagquoted;
+
+ terminator = '>';
+ i = str_chr(arg, '<');
+ if (arg[i])
+ arg += i + 1;
+ else { /* partner should go read rfc 821 */
+ terminator = ' ';
+ arg += str_chr(arg, ':');
+ if (*arg == ':')
+ ++arg;
+ while (*arg == ' ')
+ ++arg;
+ }
+
+ /* strip source route */
+ if (*arg == '@')
+ while (*arg)
+ if (*arg++ == ':')
+ break;
+
+ if (!stralloc_copys(&addr, ""))
+ die_nomem();
+ flagesc = 0;
+ flagquoted = 0;
+ for (i = 0; (ch = arg[i]); ++i) { /* copy arg to addr, stripping quotes */
+ if (flagesc) {
+ if (!stralloc_append(&addr, &ch))
+ die_nomem();
+ flagesc = 0;
+ } else {
+ if (!flagquoted && (ch == terminator))
+ break;
+ switch (ch) {
+ case '\\':
+ flagesc = 1;
+ break;
+ case '"':
+ flagquoted = !flagquoted;
+ break;
+ default:
+ if (!stralloc_append(&addr, &ch))
+ die_nomem();
+ }
+ }
+ }
+ /* could check for termination failure here, but why bother? */
+ if (!stralloc_append(&addr, ""))
+ die_nomem();
+
+ if (liphostok) {
+ i = byte_rchr(addr.s, addr.len, '@');
+ if (i < addr.len) /* if not, partner should go read rfc 821 */
+ if (addr.s[i + 1] == '[')
+ if (!addr.s[i + 1 + ip_scanbracket(addr.s + i + 1, &ip)])
+ if (ipme_is(&ip)) {
+ addr.len = i + 1;
+ if (!stralloc_cat(&addr, &liphost))
+ die_nomem();
+ if (!stralloc_0(&addr))
+ die_nomem();
+ }
+ }
+
+ if (addr.len > 900)
+ return 0;
+ return 1;
}
-int bmfcheck()
+int
+bmfcheck()
{
- int j;
- if (!bmfok) return 0;
- if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;
- j = byte_rchr(addr.s,addr.len,'@');
- if (j < addr.len)
- if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
- return 0;
+ int j;
+ if (!bmfok)
+ return 0;
+ if (constmap(&mapbmf, addr.s, addr.len - 1))
+ return 1;
+ j = byte_rchr(addr.s, addr.len, '@');
+ if (j < addr.len)
+ if (constmap(&mapbmf, addr.s + j, addr.len - j - 1))
+ return 1;
+ return 0;
}
-int addrallowed()
+int
+addrallowed()
{
- int r;
- r = rcpthosts(addr.s,str_len(addr.s));
- if (r == -1) die_control();
- return r;
+ int r;
+ r = rcpthosts(addr.s, str_len(addr.s));
+ if (r == -1)
+ die_control();
+ return r;
}
int flagdnsbl = 0;
stralloc dnsblhost = {0};
-int dnsblcheck()
+int
+dnsblcheck()
{
- char *ch;
- static stralloc dnsblbyte = {0};
- static stralloc dnsblrev = {0};
- static ipalloc dnsblip = {0};
- static ip6alloc dnsblip6 = {0};
- static stralloc dnsbllist = {0};
-
- ch = remoteip;
- if(control_readfile(&dnsbllist,"control/dnsbllist",0) != 1) return 0;
-
- if (!stralloc_copys(&dnsblrev,"")) return 0;
- for (;;) {
- if (!stralloc_copys(&dnsblbyte,"")) return 0;
- while (ch[0] && (ch[0] != '.')) {
- if (!stralloc_append(&dnsblbyte,ch)) return 0;
- ch++;
- }
- if (!stralloc_append(&dnsblbyte,".")) return 0;
- if (!stralloc_cat(&dnsblbyte,&dnsblrev)) return 0;
- if (!stralloc_copy(&dnsblrev,&dnsblbyte)) return 0;
-
- if (!ch[0]) break;
- ch++;
- }
-
- flagdnsbl = 1;
- ch = dnsbllist.s;
- while (ch < (dnsbllist.s + dnsbllist.len)) {
- if (!stralloc_copy(&dnsblhost,&dnsblrev)) return 0;
- if (!stralloc_cats(&dnsblhost,ch)) return 0;
- if (!stralloc_0(&dnsblhost)) return 0;
-
- if (!dns_ip(&dnsblip,&dnsblhost)) return 1;
- while (*ch++);
- }
-
- return 0;
+ char *ch;
+ static stralloc dnsblbyte = {
+ 0
+ };
+ static stralloc dnsblrev = {
+ 0
+ };
+ static ipalloc dnsblip = {
+ 0
+ };
+ static ip6alloc dnsblip6 = {
+ 0
+ };
+ static stralloc dnsbllist = {
+ 0
+ };
+
+ ch = remoteip;
+ if (control_readfile(&dnsbllist, "control/dnsbllist", 0) != 1)
+ return 0;
+
+ if (!stralloc_copys(&dnsblrev, ""))
+ return 0;
+ for (;;) {
+ if (!stralloc_copys(&dnsblbyte, ""))
+ return 0;
+ while (ch[0] && (ch[0] != '.')) {
+ if (!stralloc_append(&dnsblbyte, ch))
+ return 0;
+ ch++;
+ }
+ if (!stralloc_append(&dnsblbyte, "."))
+ return 0;
+ if (!stralloc_cat(&dnsblbyte, &dnsblrev))
+ return 0;
+ if (!stralloc_copy(&dnsblrev, &dnsblbyte))
+ return 0;
+
+ if (!ch[0])
+ break;
+ ch++;
+ }
+
+ flagdnsbl = 1;
+ ch = dnsbllist.s;
+ while (ch < (dnsbllist.s + dnsbllist.len)) {
+ if (!stralloc_copy(&dnsblhost, &dnsblrev))
+ return 0;
+ if (!stralloc_cats(&dnsblhost, ch))
+ return 0;
+ if (!stralloc_0(&dnsblhost))
+ return 0;
+
+ if (!dns_ip(&dnsblip, &dnsblhost))
+ return 1;
+ while (*ch++);
+ }
+
+ return 0;
}
-int seenmail = 0;
-int flagbarf; /* defined if seenmail */
-stralloc mailfrom = {0};
-stralloc rcptto = {0};
-
-ssize_t saferead(int fd, void *buf, size_t len)
+ssize_t
+saferead(int fd, void *buf, size_t len)
{
- ssize_t r;
- r = timeoutread(timeout,fd,buf,len);
- if (r == -1) if (errno == error_timeout) die_alarm();
- if (r == 0 || r == -1) die_read();
- return r;
+ ssize_t r;
+ r = timeoutread(timeout, fd, buf, len);
+ if (r == -1)
+ if (errno == error_timeout)
+ die_alarm();
+ if (r == 0 || r == -1)
+ die_read();
+ return r;
}
char ssinbuf[1024];
-substdio ssin = SUBSTDIO_FDBUF(saferead,0,ssinbuf,sizeof(ssinbuf));
+substdio ssin = SUBSTDIO_FDBUF(saferead, 0, ssinbuf, sizeof(ssinbuf));
-void smtp_starttls(char *arg)
+void
+smtp_starttls(char *arg)
{
- char fdou[1920]; // compare skarnet s-s-proxy: OUTSIZE 1920. Me thinks I cribbed too much.
- ssize_t hsread = 0, hsr = 0;
- if (str_len(arg) != 0) { err_syntax(); return; }
- if (!starttlsready) { err_notlshere(); return; }
- if (timeoutwrite(1, sslctlfd, "Y", 1) != 1) { die_wtf(errno, "could not cut over to TLS in one second"); }
- out("220 2.7.0 Ready to start TLS\r\n");
- substdio_flush(&ssout);
- for (;;) {
- hsread += (hsr = timeoutread(1, sslctlfd, fdou, 1920));
- if (hsr < 0) { if (errno != EAGAIN) die_wtf(errno, "could not cut over to TLS in 1 second"); }
- if (!hsr) break;
- isstarttls = 1; // just use the global variable (TODO: make TL when npthread)
- }
- if (!isstarttls) { _exit(10); }
- // At this point, we are starttls. We must now cut sslwfd to fd 1 and sslrfd to fd 0.
- ssout.fd = sslwfd;
- ssin.fd = sslrfd;
- substdio_flush(&ssout);
- substdio_flush(&sse);
-}
-void smtp_helo(char *arg)
+ char fdou[1920]; /* compare skarnet s-s-proxy: OUTSIZE 1920. Me thinks I cribbed too much. */
+ ssize_t hsread = 0, hsr = 0;
+ if (str_len(arg) != 0) {
+ err_syntax();
+ return;
+ }
+ if (!starttlsready) {
+ err_notlshere();
+ return;
+ }
+ if (timeoutwrite(1, sslctlfd, "Y", 1) != 1) {
+ die_wtf(errno, "could not cut over to TLS in one second");
+ }
+ out("220 2.7.0 Ready to start TLS\r\n");
+ substdio_flush(&ssout);
+ for (;;) {
+ hsread += (hsr = timeoutread(1, sslctlfd, fdou, 1920));
+ if (hsr < 0) {
+ if (errno != EAGAIN)
+ die_wtf(errno, "could not cut over to TLS in 1 second");
+ }
+ if (!hsr)
+ break;
+ isstarttls = 1; /* just use the global variable (TODO: make TL when npthread) */
+ }
+ if (!isstarttls) {
+ _exit(10);
+ }
+ /* At this point, we are starttls. We must now cut sslwfd to fd 1 and sslrfd to fd 0. */
+ ssout.fd = sslwfd;
+ ssin.fd = sslrfd;
+ substdio_flush(&ssout);
+ substdio_flush(&sse);
+}
+void
+smtp_helo(char *arg)
+{
+ smtp_greet("250 ");
+ out("\r\n");
+ seenmail = 0;
+ dohelo(arg);
+}
+void
+smtp_ehlo(char *arg)
{
- smtp_greet("250 "); out("\r\n");
- seenmail = 0; dohelo(arg);
+ isesmtp = 1;
+ smtp_greet("250-");
+ out("\r\n");
+ out("250-PIPELINING\r\n");
+ out("250-ENHANCEDSTATUSCODES\r\n");
+ /* TODO: add startTLS cutover support */
+ if (starttlsready && !isstarttls) {
+ out("250-8BITMIME\r\n");
+ out("250 STARTTLS\r\n");
+ } else
+ out("250 8BITMIME\r\n");
+ seenmail = 0;
+ dohelo(arg);
}
-void smtp_ehlo(char *arg)
+void
+smtp_rset(char *arg)
{
- isesmtp = 1;
- smtp_greet("250-"); out("\r\n");
- out("250-PIPELINING\r\n");
- out("250-ENHANCEDSTATUSCODES\r\n");
- // TODO: add startTLS cutover support
- if (starttlsready && !isstarttls) {
- out("250-8BITMIME\r\n");
- out("250 STARTTLS\r\n");
- } else out("250 8BITMIME\r\n");
- seenmail = 0; dohelo(arg);
-}
-void smtp_rset(char *arg)
+ seenmail = 0;
+ out("250 Envelope flushed\r\n");
+}
+void
+smtp_mail(char *arg)
{
- seenmail = 0;
- out("250 Envelope flushed\r\n");
+ if (!addrparse(arg)) {
+ err_syntax();
+ return;
+ }
+ flagbarf = bmfcheck();
+ seenmail = 1;
+ if (!stralloc_copys(&rcptto, ""))
+ die_nomem();
+ if (!stralloc_copys(&mailfrom, addr.s))
+ die_nomem();
+ if (!stralloc_0(&mailfrom))
+ die_nomem();
+ realrcptto_start();
+ out("250 Go on...\r\n");
}
-void smtp_mail(char *arg)
+void
+smtp_rcpt(char *arg)
{
- if (!addrparse(arg)) { err_syntax(); return; }
- flagbarf = bmfcheck();
- seenmail = 1;
- if (!stralloc_copys(&rcptto,"")) die_nomem();
- if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
- if (!stralloc_0(&mailfrom)) die_nomem();
- realrcptto_start();
- out("250 Go on...\r\n");
-}
-void smtp_rcpt(char *arg) {
- if (!seenmail) { err_wantmail(); return; }
- if (!addrparse(arg)) { err_syntax(); return; }
- if (flagbarf) { err_bmf(); return; }
- if (relayclient) {
- --addr.len;
- if (!stralloc_cats(&addr,relayclient)) die_nomem();
- if (!stralloc_0(&addr)) die_nomem();
- }
- else
- if (!addrallowed()) { err_nogateway(); return; }
- if (!realrcptto(addr.s)) {
- out("550 5.1.1 That user has elected not to receive emails.\r\n");
- return;
- }
- if (!(relayclient || dnsblskip || flagdnsbl))
- if (dnsblcheck()) die_dnsbl(dnsblhost.s);
- if (!stralloc_cats(&rcptto,"T")) die_nomem();
- if (!stralloc_cats(&rcptto,addr.s)) die_nomem();
- if (!stralloc_0(&rcptto)) die_nomem();
- out("250 Go on...\r\n");
+ if (!seenmail) {
+ err_wantmail();
+ return;
+ }
+ if (!addrparse(arg)) {
+ err_syntax();
+ return;
+ }
+ if (flagbarf) {
+ err_bmf();
+ return;
+ }
+ if (relayclient) {
+ --addr.len;
+ if (!stralloc_cats(&addr, relayclient))
+ die_nomem();
+ if (!stralloc_0(&addr))
+ die_nomem();
+ } else if (!addrallowed()) {
+ err_nogateway();
+ return;
+ }
+ if (rcpttos > maxrcpttos) {
+ err_addresses();
+ return;
+ }
+ if (!realrcptto(addr.s)) {
+ out("550 5.1.1 That user has elected not to receive emails.\r\n");
+ return;
+ }
+ if (!(relayclient || dnsblskip || flagdnsbl))
+ if (dnsblcheck())
+ die_dnsbl(dnsblhost.s);
+ if (!stralloc_cats(&rcptto, "T"))
+ die_nomem();
+ if (!stralloc_cats(&rcptto, addr.s))
+ die_nomem();
+ if (!stralloc_0(&rcptto))
+ die_nomem();
+ ++rcpttos;
+ out("250 Go on...\r\n");
}
struct qmail qqt;
unsigned int bytestooverflow = 0;
-void put(ch)
-char *ch;
+void
+put(char *ch)
{
- if (bytestooverflow)
- if (!--bytestooverflow)
- qmail_fail(&qqt);
- qmail_put(&qqt,ch,1);
+ if (bytestooverflow)
+ if (!--bytestooverflow)
+ qmail_fail(&qqt);
+ qmail_put(&qqt, ch, 1);
}
-void blast(hops)
-int *hops;
+void
+blast(int *hops)
{
- char ch;
- int state;
- int flaginheader;
- int pos; /* number of bytes since most recent \n, if fih */
- int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
- int flagmaybey; /* 1 if this line might match \r\n, if fih */
- int flagmaybez; /* 1 if this line might match DELIVERED, if fih */
-
- state = 1;
- *hops = 0;
- flaginheader = 1;
- pos = 0; flagmaybex = flagmaybey = flagmaybez = 1;
- for (;;) {
- /* This isn't very optimized -- Amelia B */
- substdio_get(&ssin,&ch,1);
- if (flaginheader) {
- if (pos < 9) { // something about method and madness?
- if (ch != "delivered"[pos]) if (ch != "DELIVERED"[pos]) flagmaybez = 0;
- if (flagmaybez) if (pos == 8) ++*hops;
- if (pos < 8)
- if (ch != "received"[pos]) if (ch != "RECEIVED"[pos]) flagmaybex = 0;
- if (flagmaybex) if (pos == 7) ++*hops;
- if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0;
- if (flagmaybey) if (pos == 1) flaginheader = 0;
- ++pos;
- }
- if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; }
- }
- switch(state) {
- case 0:
- if (ch == '\n') straynewline();
- if (ch == '\r') { state = 4; continue; }
- break;
- case 1: /* \r\n */
- if (ch == '\n') straynewline();
- if (ch == '.') { state = 2; continue; }
- if (ch == '\r') { state = 4; continue; }
- state = 0;
- break;
- case 2: /* \r\n + . */
- if (ch == '\n') straynewline();
- if (ch == '\r') { state = 3; continue; }
- state = 0;
- break;
- case 3: /* \r\n + .\r */
- if (ch == '\n') return;
- put(".");
- put("\r");
- if (ch == '\r') { state = 4; continue; }
- state = 0;
- break;
- case 4: /* + \r */
- if (ch == '\n') { state = 1; break; }
- if (ch != '\r') { put("\r"); state = 0; }
- }
- put(&ch);
- }
+ char ch;
+ int state;
+ int flaginheader;
+ int pos; /* number of bytes since most recent \n, if fih */
+ int flagmaybex; /* 1 if this line might match RECEIVED, if fih */
+ int flagmaybey; /* 1 if this line might match \r\n, if fih */
+ int flagmaybez; /* 1 if this line might match DELIVERED, if fih */
+
+ state = 1;
+ *hops = 0;
+ flaginheader = 1;
+ pos = 0;
+ flagmaybex = flagmaybey = flagmaybez = 1;
+ for (;;) {
+ /* This isn't very optimized -- Amelia B */
+ substdio_get(&ssin, &ch, 1);
+ if (flaginheader) {
+ if (pos >= 0 && pos < 9) { /* something about method and madness? bro literally just use strcmp it won't hurt you */
+ if (ch != "delivered"[pos])
+ if (ch != "DELIVERED"[pos])
+ flagmaybez = 0;
+ if (flagmaybez)
+ if (pos == 8)
+ ++* hops;
+ if (pos < 8)
+ if (ch != "received"[pos])
+ if (ch != "RECEIVED"[pos])
+ flagmaybex = 0;
+ if (flagmaybex)
+ if (pos == 7)
+ ++* hops;
+ if (pos < 2)
+ if (ch != "\r\n"[pos])
+ flagmaybey = 0;
+ if (flagmaybey)
+ if (pos == 1)
+ flaginheader = 0;
+ ++pos;
+ }
+ if (ch == '\n') {
+ pos = 0;
+ flagmaybex = flagmaybey = flagmaybez = 1;
+ }
+ }
+ switch (state) {
+ case 0:
+ if (ch == '\n')
+ straynewline();
+ if (ch == '\r') {
+ state = 4;
+ continue;
+ }
+ break;
+ case 1: /* \r\n */
+ if (ch == '\n')
+ straynewline();
+ if (ch == '.') {
+ state = 2;
+ continue;
+ }
+ if (ch == '\r') {
+ state = 4;
+ continue;
+ }
+ state = 0;
+ break;
+ case 2: /* \r\n + . */
+ if (ch == '\n')
+ straynewline();
+ if (ch == '\r') {
+ state = 3;
+ continue;
+ }
+ state = 0;
+ break;
+ case 3: /* \r\n + .\r */
+ if (ch == '\n')
+ return;
+ put(".");
+ put("\r");
+ if (ch == '\r') {
+ state = 4;
+ continue;
+ }
+ state = 0;
+ break;
+ case 4: /* + \r */
+ if (ch == '\n') {
+ state = 1;
+ break;
+ }
+ if (ch != '\r') {
+ put("\r");
+ state = 0;
+ }
+ }
+ put(&ch);
+ }
}
char accept_buf[FMT_ULONG];
-void acceptmessage(qp) unsigned long qp;
+void
+acceptmessage(qp)
+ unsigned long qp;
{
- datetime_sec when;
- when = now();
- out("250 Accepted responsibility at time ");
- accept_buf[fmt_ulong(accept_buf,(unsigned long) when)] = 0;
- out(accept_buf);
- out(" queue process ");
- accept_buf[fmt_ulong(accept_buf,qp)] = 0;
- out(accept_buf);
- out(" - we'll do our best!\r\n");
- flush();
+ datetime_sec when;
+ when = now();
+ out("250 Accepted responsibility at time ");
+ accept_buf[fmt_ulong(accept_buf, (unsigned long)when)] = 0;
+ out(accept_buf);
+ out(" queue process ");
+ accept_buf[fmt_ulong(accept_buf, qp)] = 0;
+ out(accept_buf);
+ out(" - we'll do our best!\r\n");
+ flush();
}
/*
unsigned long alen, plen, len;
if (databytes && ((alen = str_len(arg)) != 0)) {
- // We now accept the optional argument to DATA which is a ulong which must < databytes + 1.
+ / We now accept the optional argument to DATA which is a ulong which must < databytes + 1.
plen = scan_ulong(arg, &len);
if (alen != plen) { err_syntax(); return; } // crap at the end of the argument
if (len > databytes) { out("552 5.3.4 This message is too big for me (rapid rejection).\r\n"); return; }
}
*/
-void smtp_data(char *arg) {
- int hops;
- unsigned long qp;
- char *qqx;
- char *esmtps;
-
- if (!seenmail) { err_wantmail(); return; }
- if (!rcptto.len) { err_wantrcpt(); return; }
- if (realrcptto_deny()) { out("554 5.1.1 That user has elected not to receive emails.\r\n"); return; }
- seenmail = 0;
- if (databytes) bytestooverflow = databytes + 1;
- if (qmail_open(&qqt) == -1) { err_qqt(); return; }
- qp = qmail_qp(&qqt);
- out("354 go ahead\r\n");
- substdio_flush(&ssout);
-
- switch ((isesmtp & 1)+((isstarttls & 1) << 1)+((relayclient != NULL) << 2)) {
- case 7: esmtps = "ESMTPSA";
- break;
- case 6: esmtps = "SMTPSA"; // Compliant clients should never do this, but it's not pathological.
- break;
- case 5: esmtps = "ESMTPA";
- break;
- case 4: esmtps = "SMTPA"; // Clients, at all, will never do this, as we don't process SMTP AUTH.
- break;
- case 3: esmtps = "ESMTPS";
- break;
- case 2: esmtps = "SMTPS"; // Compliant clients should never do this, but it's not pathological.
- break;
- case 1: esmtps = "ESMTP";
- break;
- default: esmtps = "SMTP";
- }
- received(&qqt,esmtps,local,remoteip,remotehost,remoteinfo,fakehelo);
- blast(&hops);
- hops = (hops >= MAXHOPS);
- if (hops) qmail_fail(&qqt);
- qmail_from(&qqt,mailfrom.s);
- qmail_put(&qqt,rcptto.s,rcptto.len);
-
- qqx = qmail_close(&qqt);
- if (!*qqx) { acceptmessage(qp); return; }
- if (hops) { out("554 5.4.6 This message has gone through too many SMTP, QMTP or other mail protocol servers; it may be looping. It ends with me.\r\n"); return; }
- if (databytes) if (!bytestooverflow) { out("552 5.3.4 This message is too big for me.\r\n"); return; }
- if (*qqx == 'D') out("554 "); else out("451 ");
- out(qqx + 1);
- out("\r\n");
+void
+smtp_data(char *arg)
+{
+ int hops;
+ unsigned long qp;
+ char *qqx;
+ char *esmtps;
+
+ if (!seenmail) {
+ err_wantmail();
+ return;
+ }
+ if (!rcptto.len) {
+ err_wantrcpt();
+ return;
+ }
+ if (realrcptto_deny()) {
+ out("554 5.1.1 That user has elected not to receive emails.\r\n");
+ return;
+ }
+ seenmail = 0;
+ if (databytes)
+ bytestooverflow = databytes + 1;
+ if (qmail_open(&qqt) == -1) {
+ err_qqt();
+ return;
+ }
+ qp = qmail_qp(&qqt);
+ out("354 go ahead\r\n");
+ substdio_flush(&ssout);
+
+ switch ((isesmtp & 1) + ((isstarttls & 1) << 1) + ((relayclient != NULL) << 2)) {
+ case 7:
+ esmtps = "ESMTPSA";
+ break;
+ case 6:
+ esmtps = "SMTPSA"; /* Compliant clients should never do this, but it's not pathological. */
+ break;
+ case 5:
+ esmtps = "ESMTPA";
+ break;
+ case 4:
+ esmtps = "SMTPA"; /* Clients, at all, will never do this, as we don't process SMTP AUTH. */
+ break;
+ case 3:
+ esmtps = "ESMTPS";
+ break;
+ case 2:
+ esmtps = "SMTPS"; /* Compliant clients should never do this, but it's not pathological. */
+ break;
+ case 1:
+ esmtps = "ESMTP";
+ break;
+ default:
+ esmtps = "SMTP";
+ }
+ received(&qqt, esmtps, local, remoteip, remotehost, remoteinfo, fakehelo);
+ blast(&hops);
+ hops = (hops >= MAXHOPS);
+ if (hops)
+ qmail_fail(&qqt);
+ qmail_from(&qqt, mailfrom.s);
+ qmail_put(&qqt, rcptto.s, rcptto.len);
+
+ qqx = qmail_close(&qqt);
+ if (!*qqx) {
+ acceptmessage(qp);
+ return;
+ }
+ if (hops) {
+ out("554 5.4.6 This message has gone through too many SMTP, QMTP or other mail protocol servers; it may be looping. It ends with me.\r\n");
+ return;
+ }
+ if (databytes)
+ if (!bytestooverflow) {
+ out("552 5.3.4 This message is too big for me.\r\n");
+ return;
+ }
+ if (*qqx == 'D')
+ out("554 ");
+ else
+ out("451 ");
+ out(qqx + 1);
+ out("\r\n");
}
struct commands smtpcommands[] = {
- { "rcpt", smtp_rcpt, flush }
-, { "mail", smtp_mail, flush }
-, { "send", smtp_mail, flush } // not recommended
-, { "soml", smtp_mail, flush } // not recommended
-, { "saml", smtp_mail, flush } // not recommended
-, { "data", smtp_data, flush }
-, { "quit", smtp_quit, flush }
-, { "helo", smtp_helo, flush }
-, { "ehlo", smtp_ehlo, flush }
-, { "rset", smtp_rset, flush }
-, { "help", smtp_help, flush }
-, { "starttls", smtp_starttls, flush }
-, { "noop", err_noop, flush }
-, { "vrfy", err_vrfy, flush }
-, { 0, err_unimpl, flush }
-} ;
-
-int main(void)
+ {"rcpt", smtp_rcpt, flush}
+ ,{"mail", smtp_mail, flush}
+ ,{"send", smtp_mail, flush} /* not recommended */
+ ,{"soml", smtp_mail, flush} /* not recommended */
+ ,{"saml", smtp_mail, flush} /* not recommended */
+ ,{"data", smtp_data, flush}
+ ,{"quit", smtp_quit, flush}
+ ,{"helo", smtp_helo, flush}
+ ,{"ehlo", smtp_ehlo, flush}
+ ,{"rset", smtp_rset, flush}
+ ,{"help", smtp_help, flush}
+ ,{"starttls", smtp_starttls, flush}
+ ,{"noop", err_noop, flush}
+ ,{"vrfy", err_vrfy, flush}
+ ,{0, err_unimpl, flush}
+};
+
+int
+main(void)
{
- //ndelay_on(0);
- //ndelay_on(1);
- sig_pipeignore();
- if (chdir(auto_qmail) == -1) die_control();
- setup();
- if (ipme_init() != 1) die_ipme();
- if (ip6me_init() != 1) die_ip6me();
- smtp_greet("220 ");
- out(" ESMTP\r\n");
- substdio_flush(&ssout);
- if (commands(&ssin,&smtpcommands) == 0) die_read();
- die_nomem();
+ /* ndelay_on(0); */
+ /* ndelay_on(1); */
+ maxrcpttos = 5; // will be overwritten
+ sig_pipeignore();
+ if (chdir(auto_qmail) == -1)
+ die_control();
+ setup();
+ if (ipme_init() != 1)
+ die_ipme();
+ if (ip6me_init() != 1)
+ die_ip6me();
+ smtp_greet("220 ");
+ out(" ESMTP\r\n");
+ substdio_flush(&ssout);
+ if (commands(&ssin, &smtpcommands) == 0)
+ die_read();
+ die_nomem();
}
diff --git a/src/qmail-clean.c b/src/qmail-clean.c
@@ -69,14 +69,14 @@ int main(void)
for (;;)
{
if (cleanuploop) --cleanuploop; else { cleanuppid(); cleanuploop = 30; }
- if (getln(subfdinsmall,&line,&match,'\0') == -1) break;
+ if (getln(subfdinsmall,&line,&match,'\0') == -1) break; //blocking read stdin because we do nowt else
if (!match) break;
- if (line.len < 7) { respond("x"); continue; }
- if (line.len > 100) { respond("x"); continue; }
+ if (line.len < 7) { respond("x"); continue; } // must be at least 7 chars
+ if (line.len > 100) { respond("x"); continue; } // must be under 101 chars
if (line.s[line.len - 1]) { respond("x"); continue; } /* impossible */
for (i = 5;i < line.len - 1;++i)
if ((unsigned char) (line.s[i] - '0') > 9)
- { respond("x"); continue; }
+ { respond("x"); continue; } // NaN
if (!scan_ulong(line.s + 5,&id)) { respond("x"); continue; }
if (byte_equal(line.s,5,"foop/"))
{
diff --git a/src/qmail-local.c b/src/qmail-local.c
@@ -43,7 +43,7 @@ void _noreturn_ temp_slowlock()
void _noreturn_ temp_qmail(char *fn)
{ strerr_die5x(111,"4.3.0 Unable to open ",fn,": ",error_str(errno)," ."); }
-int flagdoit = 0;
+int flagdoit = 0, flagprobe = 0;
int flag99;
char *user;
diff --git a/src/qmail-queue.c b/src/qmail-queue.c
@@ -203,7 +203,7 @@ int main(void)
die(64);
}
if (unlink(pidfn) == -1) die(63);
- flagmademess = 1;
+ flagmademess = 1; // created pid file, linked it to mesg file, unlinked pid file.
substdio_fdbuf(&ssout,write,messfd,outbuf,sizeof(outbuf));
substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));
@@ -233,6 +233,8 @@ int main(void)
if (substdio_bput(&ssout,"p",1) == -1) die_write();
if (substdio_bput(&ssout,tmp,fmt_ulong(tmp,mypid)) == -1) die_write();
if (substdio_bput(&ssout,"",1) == -1) die_write();
+ // it's not immediately clear that fmt_ulong actually runs first out of
+ // each invokation of bput containing it
if (substdio_get(&ssin,&ch,1) < 1) die_read();
if (ch != 'F') die(91);
@@ -267,6 +269,6 @@ int main(void)
if (link(intdfn,todofn) == -1) die(66);
- triggerpull();
+ triggerpull(); // xxx should be a triggerpull on the appropriate queue.
return 0;
}
diff --git a/src/qmail-remote.c b/src/qmail-remote.c
@@ -35,381 +35,554 @@
#define HUGESMTPTEXT 5000
-#define PORT_SMTP 25 /* silly rabbit, /etc/services is for users */
+#define PORT_SMTP 25 /* silly rabbit, /etc/services is for users */
unsigned long port = PORT_SMTP;
-GEN_ALLOC_typedef(saa,stralloc,sa,len,a)
-GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,10,saa_readyplus)
-static stralloc sauninit = {0};
+GEN_ALLOC_typedef(saa, stralloc, sa, len, a)
+GEN_ALLOC_readyplus(saa, stralloc, sa, len, a, 10, saa_readyplus)
+static stralloc sauninit = STRALLOC_ZERO;
stralloc helohost = {0};
stralloc routes = {0};
struct constmap maproutes;
stralloc host = {0};
stralloc sender = {0};
+int pedanticsmtp = 1;
saa reciplist = {0};
struct ip_address partner;
-void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
-void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
-void _noreturn_ zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); }
-void outsafe(sa) stralloc *sa; { int i; char ch;
-for (i = 0;i < sa->len;++i) {
-ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?';
-if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } }
-
-void _noreturn_ temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); }
-void _noreturn_ temp_oserr() { out("Z\
-System resources temporarily unavailable. (#4.3.0)\n"); zerodie(); }
-void _noreturn_ temp_noconn() { out("Z\
-Sorry, I wasn't able to establish an SMTP connection. (#4.4.1)\n"); zerodie(); }
-void _noreturn_ temp_read() { out("ZUnable to read message. (#4.3.0)\n"); zerodie(); }
-void _noreturn_ temp_dnscanon() { out("Z\
-CNAME lookup failed temporarily. (#4.4.3)\n"); zerodie(); }
-void _noreturn_ temp_dns() { out("Z\
-Sorry, I couldn't find any host by that name. (#4.1.2)\n"); zerodie(); }
-void _noreturn_ temp_chdir() { out("Z\
-Unable to switch to home directory. (#4.3.0)\n"); zerodie(); }
-void _noreturn_ temp_control() { out("Z\
-Unable to read control files. (#4.3.0)\n"); zerodie(); }
-void _noreturn_ perm_partialline() { out("D\
-SMTP cannot transfer messages with partial final lines. (#5.6.2)\n"); zerodie(); }
-void _noreturn_ perm_usage() { out("D\
-I (qmail-remote) was invoked improperly. (#5.3.5)\n"); zerodie(); }
-void _noreturn_ perm_dns() { out("D\
-Sorry, I couldn't find any host named ");
-outsafe(&host);
-out(". (#5.1.2)\n"); zerodie(); }
-void _noreturn_ perm_nomx() { out("D\
-Sorry, I couldn't find a mail exchanger or IP address. (#5.4.4)\n");
-zerodie(); }
-void _noreturn_ perm_ambigmx() { out("D\
+void out(s)
+char *s; {
+ if (substdio_puts(subfdoutsmall, s) == -1)
+ _exit(0);
+}
+void zero() {
+ if (substdio_put(subfdoutsmall, "\0", 1) == -1)
+ _exit(0);
+}
+void _noreturn_ zerodie() {
+ zero();
+ substdio_flush(subfdoutsmall);
+ _exit(0);
+}
+void
+outsafe(sa) stralloc * sa;
+{
+ int i;
+ char ch;
+ for (i = 0; i < sa->len; ++i) {
+ ch = sa->s[i];
+ if (ch < 33)
+ ch = '?';
+ if (ch > 126)
+ ch = '?';
+ if (substdio_put(subfdoutsmall, &ch, 1) == -1)
+ _exit(0);
+ }
+}
+
+void _noreturn_ temp_nomem() {
+ out("ZOut of memory. (#4.3.0)\n");
+ zerodie();
+}
+void _noreturn_
+temp_oserr()
+{
+ out("ZSystem resources temporarily unavailable. (#4.3.0)\n");
+ zerodie();
+}
+void _noreturn_
+temp_noconn()
+{
+ out("ZSorry, I wasn't able to establish an SMTP connection. (#4.4.1)\n");
+ zerodie();
+}
+void _noreturn_ temp_read() {
+ out("ZUnable to read message. (#4.3.0)\n");
+ zerodie();
+}
+void _noreturn_
+temp_dnscanon()
+{
+ out("ZCNAME lookup failed temporarily. (#4.4.3)\n");
+ zerodie();
+}
+void _noreturn_
+temp_dns()
+{
+ out("ZSorry, I couldn't find any host by that name. (#4.1.2)\n");
+ zerodie();
+}
+void _noreturn_
+temp_chdir()
+{
+ out("ZUnable to switch to home directory. (#4.3.0)\n");
+ zerodie();
+}
+void _noreturn_
+temp_control()
+{
+ out("ZUnable to read control files. (#4.3.0)\n");
+ zerodie();
+}
+void _noreturn_
+perm_partialline()
+{
+ out("DSMTP cannot transfer messages with partial final lines. (#5.6.2)\n");
+ zerodie();
+}
+void _noreturn_
+perm_usage()
+{
+ out("DI (qmail-remote) was invoked improperly. (#5.3.5)\n");
+ zerodie();
+}
+void _noreturn_
+perm_dns()
+{
+ out("D5.1.2 Sorry, I couldn't find any host named ");
+ outsafe(&host);
+ out(".\n");
+ zerodie();
+}
+void _noreturn_
+perm_nomx()
+{
+ out("D5.4.4 Sorry, I couldn't find a mail exchanger or IP address.\n");
+ zerodie();
+}
+void _noreturn_
+perm_ambigmx()
+{
+ out("D\
Sorry. Although I'm listed as a best-preference MX or A for that host,\n\
it isn't in my control/locals file, so I don't treat it as local. (#5.4.6)\n");
-zerodie(); }
+ zerodie();
+}
-void outhost()
+void
+outhost()
{
- char x[IPFMT];
- if (substdio_put(subfdoutsmall,x,ip_fmt(x,&partner)) == -1) _exit(0);
+ char x[IPFMT];
+ if (substdio_put(subfdoutsmall, x, ip_fmt(x, &partner)) == -1)
+ _exit(0);
}
int flagcritical = 0;
-void _noreturn_ dropped() {
- out("ZConnected to ");
- outhost();
- out(" but connection died. ");
- if (flagcritical) out("Possible duplicate! ");
- out("(#4.4.2)\n");
- zerodie();
+void _noreturn_
+dropped()
+{
+ out("ZConnected to ");
+ outhost();
+ out(" but connection died. ");
+ if (flagcritical)
+ out("Possible duplicate! ");
+ out("(#4.4.2)\n");
+ zerodie();
}
int timeoutconnect = 60;
int smtpfd;
int timeout = 1200;
-GEN_SAFE_TIMEOUTREAD(saferead,timeout,smtpfd,dropped())
-GEN_SAFE_TIMEOUTWRITE(safewrite,timeout,smtpfd,dropped())
+GEN_SAFE_TIMEOUTREAD(saferead, timeout, smtpfd, dropped())
+GEN_SAFE_TIMEOUTWRITE(safewrite, timeout, smtpfd, dropped())
char inbuf[1024];
-substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof(inbuf));
+substdio ssin = SUBSTDIO_FDBUF(read, 0, inbuf, sizeof(inbuf));
char smtptobuf[1024];
-substdio smtpto = SUBSTDIO_FDBUF(safewrite,-1,smtptobuf,sizeof(smtptobuf));
+substdio smtpto = SUBSTDIO_FDBUF(safewrite, -1, smtptobuf, sizeof(smtptobuf));
char smtpfrombuf[128];
-substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof(smtpfrombuf));
+substdio smtpfrom = SUBSTDIO_FDBUF(saferead, -1, smtpfrombuf, sizeof(smtpfrombuf));
stralloc smtptext = {0};
-static void get(unsigned char *uc)
+static void
+get(unsigned char *uc)
{
- char *ch = (char *)uc;
- substdio_get(&smtpfrom,ch,1);
- if (*ch != '\r')
- if (smtptext.len < HUGESMTPTEXT)
+ char *ch = (char *)uc;
+ substdio_get(&smtpfrom, ch, 1);
+ if (*ch != '\r')
+ if (smtptext.len < HUGESMTPTEXT)
#ifdef USING_SKALIBS
- // skalibs is different on this
- if (!stralloc_append(&smtptext,*ch)) temp_nomem();
+ //skalibs is different on this
+ if (!stralloc_append(&smtptext, *ch))
+ temp_nomem();
#else
- if (!stralloc_append(&smtptext,ch)) temp_nomem();
+ if (!stralloc_append(&smtptext, ch))
+ temp_nomem();
#endif
}
-unsigned long smtpcode()
+unsigned long
+smtpcode()
{
- unsigned char ch;
- unsigned long code;
-
- if (!stralloc_copys(&smtptext,"")) temp_nomem();
-
- get(&ch); code = ch - '0';
- get(&ch); code = code * 10 + (ch - '0');
- get(&ch); code = code * 10 + (ch - '0');
- for (;;) {
- get(&ch);
- if (ch != '-') break;
- while (ch != '\n') get(&ch);
- get(&ch);
- get(&ch);
- get(&ch);
- }
- while (ch != '\n') get(&ch);
-
- return code;
+ unsigned char ch = 0;
+ unsigned long code = 0;
+
+ if (!stralloc_copys(&smtptext, ""))
+ temp_nomem();
+
+ get(&ch);
+ code = ch - '0';
+ get(&ch);
+ code = code * 10 + (ch - '0');
+ get(&ch);
+ code = code * 10 + (ch - '0');
+ for (;;) {
+ get(&ch);
+ if (ch != '-')
+ break;
+ while (ch != '\n')
+ get(&ch);
+ get(&ch);
+ get(&ch);
+ get(&ch);
+ }
+ while (ch != '\n')
+ get(&ch);
+
+ return code;
}
-void outsmtptext()
+void
+outsmtptext()
{
- int i;
- if (smtptext.s) if (smtptext.len) {
- out("Remote host said: ");
- for (i = 0;i < smtptext.len;++i)
- if (!smtptext.s[i]) smtptext.s[i] = '?';
- if (substdio_put(subfdoutsmall,smtptext.s,smtptext.len) == -1) _exit(0);
- smtptext.len = 0;
- }
+ int i;
+ if (smtptext.s)
+ if (smtptext.len) {
+ out("Remote host said: ");
+ for (i = 0; i < smtptext.len; ++i)
+ if (!smtptext.s[i])
+ smtptext.s[i] = '?';
+ if (substdio_put(subfdoutsmall, smtptext.s, smtptext.len) == -1)
+ _exit(0);
+ smtptext.len = 0;
+ }
}
-void quit(prepend,append)
-char *prepend;
-char *append;
+void
+quit(char *prepend,
+ char *append)
{
- substdio_putsflush(&smtpto,"QUIT\r\n");
- /* waiting for remote side is just too ridiculous */
- out(prepend);
- outhost();
- out(append);
- out(".\n");
- outsmtptext();
- zerodie();
+ substdio_putsflush(&smtpto, "QUIT\r\n");
+ /* waiting for remote side is just too ridiculous
+ * do it anyway if we are pedanticsmtp (the default) */
+ out(prepend);
+ outhost();
+ out(append);
+ out(".\n");
+ outsmtptext();
+ if (pedanticsmtp) smtpcode(); /* Discard */
+ zerodie();
}
-void blast()
+void
+blastsmtp()
{
- int r;
- char ch;
-
- for (;;) {
- r = substdio_get(&ssin,&ch,1);
- if (r == 0) break;
- if (r == -1) temp_read();
- if (ch == '.')
- substdio_put(&smtpto,".",1);
- while (ch != '\n') {
- if (ch == '\r') {
- r = substdio_get(&ssin, &ch, 1);
- if (r == 0)
- break;
- if (r == -1) temp_read();
- if (ch != '\n') {
- substdio_put(&smtpto, "\r\n", 2);
- } else
- break;
- }
- substdio_put(&smtpto,&ch,1);
- r = substdio_get(&ssin,&ch,1);
- if (r == 0) perm_partialline();
- if (r == -1) temp_read();
- }
- substdio_put(&smtpto,"\r\n",2);
- }
-
- flagcritical = 1;
- substdio_put(&smtpto,".\r\n",3);
- substdio_flush(&smtpto);
+ int r;
+ char ch;
+
+ for (;;) {
+ r = substdio_get(&ssin, &ch, 1);
+ if (r == 0)
+ break;
+ if (r == -1)
+ temp_read();
+ if (ch == '.')
+ substdio_put(&smtpto, ".", 1);
+ while (ch != '\n') {
+ if (ch == '\r') {
+ r = substdio_get(&ssin, &ch, 1);
+ if (r == 0)
+ break;
+ if (r == -1)
+ temp_read();
+ if (ch != '\n') {
+ substdio_put(&smtpto, "\r\n", 2);
+ } else
+ break;
+ }
+ substdio_put(&smtpto, &ch, 1);
+ r = substdio_get(&ssin, &ch, 1);
+ if (r == 0)
+ perm_partialline();
+ if (r == -1)
+ temp_read();
+ }
+ substdio_put(&smtpto, "\r\n", 2);
+ }
+
+ flagcritical = 1;
+ substdio_put(&smtpto, ".\r\n", 3);
+ substdio_flush(&smtpto);
}
stralloc recip = {0};
+int esmtp = 1;
-void smtp()
+void
+smtp()
{
- unsigned long code;
- int flagbother;
- int i;
-
- if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
-
- substdio_puts(&smtpto,"HELO ");
- substdio_put(&smtpto,helohost.s,helohost.len);
- substdio_puts(&smtpto,"\r\n");
- substdio_flush(&smtpto);
- if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
-
- substdio_puts(&smtpto,"MAIL FROM:<");
- substdio_put(&smtpto,sender.s,sender.len);
- substdio_puts(&smtpto,">\r\n");
- substdio_flush(&smtpto);
- code = smtpcode();
- if (code >= 500) quit("DConnected to "," but sender was rejected");
- if (code >= 400) quit("ZConnected to "," but sender was rejected");
-
- flagbother = 0;
- for (i = 0;i < reciplist.len;++i) {
- substdio_puts(&smtpto,"RCPT TO:<");
- substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len);
- substdio_puts(&smtpto,">\r\n");
- substdio_flush(&smtpto);
- code = smtpcode();
- if (code >= 500) {
- out("h"); outhost(); out(" does not like recipient.\n");
- outsmtptext(); zero();
- }
- else if (code >= 400) {
- out("s"); outhost(); out(" does not like recipient.\n");
- outsmtptext(); zero();
- }
- else {
- out("r"); zero();
- flagbother = 1;
- }
- }
- if (!flagbother) quit("DGiving up on ","");
-
- substdio_putsflush(&smtpto,"DATA\r\n");
- code = smtpcode();
- if (code >= 500) quit("D"," failed on DATA command");
- if (code >= 400) quit("Z"," failed on DATA command");
-
- blast();
- code = smtpcode();
- flagcritical = 0;
- if (code >= 500) quit("D"," failed after I sent the message");
- if (code >= 400) quit("Z"," failed after I sent the message");
- quit("K"," accepted message");
+ unsigned long code;
+ int flagbother;
+ int i;
+
+ //XXX commented example(straight BER flow) is RFC non-compliant.
+ // if (smtpcode() != 220) quit("ZConnected to ", " but greeting failed");
+ //Use theory of codes instead - any 2xx code is fine
+ code = smtpcode();
+ if (code < 200 || code > 299) {
+ substdio_putsflush(&smtpto, "QUIT\r\n");
+ smtpcode(); /* Return value deliberately unused; just get us to EPIPE. Hildie */
+ close(smtpfd);
+ return;
+ }
+
+ substdio_puts(&smtpto, "EHLO ");
+ substdio_put(&smtpto, helohost.s, helohost.len);
+ substdio_puts(&smtpto, "\r\n");
+ substdio_flush(&smtpto);
+ code = smtpcode();
+ if (code < 250 || code > 259) {
+ esmtp = 0;
+ /* Old far side doesn't understand EHLO. That's fine, we don't use any ESMTP extensions anyway. */
+ substdio_puts(&smtpto, "HELO ");
+ substdio_put(&smtpto, helohost.s, helohost.len);
+ substdio_puts(&smtpto, "\r\n");
+ substdio_flush(&smtpto);
+ code = smtpcode();
+ if (code < 250 || code > 259)
+ quit("ZConnected to ", " but my name was rejected");
+ }
+
+ substdio_puts(&smtpto, "MAIL FROM:<");
+ substdio_put(&smtpto, sender.s, sender.len);
+ substdio_puts(&smtpto, ">\r\n");
+ substdio_flush(&smtpto);
+ code = smtpcode();
+ if (code >= 500)
+ quit("DConnected to ", " but sender was rejected");
+ if (code >= 400)
+ quit("ZConnected to ", " but sender was rejected");
+
+ flagbother = 0;
+ for (i = 0; i < reciplist.len; ++i) {
+ substdio_puts(&smtpto, "RCPT TO:<");
+ substdio_put(&smtpto, reciplist.sa[i].s, reciplist.sa[i].len);
+ substdio_puts(&smtpto, ">\r\n");
+ substdio_flush(&smtpto);
+ code = smtpcode();
+ if (code >= 500) {
+ out("h");
+ outhost();
+ out(" does not like recipient.\n");
+ outsmtptext();
+ zero();
+ } else if (code >= 400) {
+ out("s");
+ outhost();
+ out(" does not like recipient.\n");
+ outsmtptext();
+ zero();
+ } else {
+ out("r");
+ zero();
+ flagbother = 1;
+ }
+ }
+ if (!flagbother)
+ quit("DGiving up on ", "");
+
+ substdio_putsflush(&smtpto, "DATA\r\n");
+ code = smtpcode();
+ if (code >= 500)
+ quit("D", " failed on DATA command");
+ if (code >= 400)
+ quit("Z", " failed on DATA command");
+
+ blastsmtp();
+ code = smtpcode();
+ flagcritical = 0;
+ if (code >= 500)
+ quit("D", " failed after I sent the message");
+ if (code >= 400)
+ quit("Z", " failed after I sent the message");
+ if (esmtp)
+ quit("K", " accepted message with ESMTP");
+ else quit("K", " accepted message with standard SMTP");
}
stralloc canonhost = {0};
stralloc canonbox = {0};
-void addrmangle(stralloc *saout, char *s)
+void
+addrmangle(stralloc * saout, char *s)
{
- int j;
-
- j = str_rchr(s,'@');
- if (!s[j]) {
- if (!stralloc_copys(saout,s)) temp_nomem();
- return;
- }
- if (!stralloc_copys(&canonbox,s)) temp_nomem();
- canonbox.len = j;
- /* box has to be quoted */
- if (!quote(saout,&canonbox)) temp_nomem();
- if (!stralloc_cats(saout,"@")) temp_nomem();
-
- if (!stralloc_copys(&canonhost,s + j + 1)) temp_nomem();
-
- if (!stralloc_cat(saout,&canonhost)) temp_nomem();
+ int j;
+
+ j = str_rchr(s, '@');
+ if (!s[j]) {
+ if (!stralloc_copys(saout, s))
+ temp_nomem();
+ return;
+ }
+ if (!stralloc_copys(&canonbox, s))
+ temp_nomem();
+ canonbox.len = j;
+ /* box has to be quoted */
+ if (!quote(saout, &canonbox))
+ temp_nomem();
+ if (!stralloc_cats(saout, "@"))
+ temp_nomem();
+
+ if (!stralloc_copys(&canonhost, s + j + 1))
+ temp_nomem();
+
+ if (!stralloc_cat(saout, &canonhost))
+ temp_nomem();
}
-void getcontrols()
+void
+getcontrols()
{
- if (control_init() == -1) temp_control();
- if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control();
- if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1)
- temp_control();
- if (control_rldef(&helohost,"control/helohost",1,NULL) != 1)
- temp_control();
- switch(control_readfile(&routes,"control/smtproutes",0)) {
- case -1:
- temp_control();
- case 0:
- if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); break;
- case 1:
- if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
- }
+ if (control_init() == -1)
+ temp_control();
+ if (control_readint(&pedanticsmtp, "control/pedanticsmtp") == -1)
+ pedanticsmtp = 1; // default to pedantic
+ if (control_readint(&timeout, "control/timeoutremote") == -1)
+ temp_control();
+ if (control_readint(&timeoutconnect, "control/timeoutconnect") == -1)
+ temp_control();
+ if (control_rldef(&helohost, "control/helohost", 1, NULL) != 1)
+ temp_control();
+ switch (control_readfile(&routes, "control/smtproutes", 0)) {
+ case -1:
+ temp_control();
+ case 0:
+ if (!constmap_init(&maproutes, "", 0, 1))
+ temp_nomem();
+ break;
+ case 1:
+ if (!constmap_init(&maproutes, routes.s, routes.len, 1))
+ temp_nomem();
+ break;
+ }
}
-int main(int argc, char **argv)
+int
+main(int argc, char **argv)
{
- static ipalloc ip = {0};
- int i;
- unsigned long random;
- char **recips;
- unsigned long prefme;
- char *relayhost;
-
- sig_pipeignore();
- if (argc < 4) perm_usage();
- if (chdir(auto_qmail) == -1) temp_chdir();
- getcontrols();
-
-
- if (!stralloc_copys(&host,argv[1])) temp_nomem();
-
- relayhost = 0;
- for (i = 0;i <= host.len;++i)
- if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
- if ((relayhost = constmap(&maproutes,host.s + i,host.len - i)))
- break;
- if (relayhost && !*relayhost) relayhost = 0;
-
- if (relayhost) {
- i = str_chr(relayhost,':');
- if (relayhost[i]) {
- scan_ulong(relayhost + i + 1,&port);
- relayhost[i] = 0;
- }
- if (!stralloc_copys(&host,relayhost)) temp_nomem();
- }
-
-
- addrmangle(&sender,argv[2]);
-
- if (!saa_readyplus(&reciplist,0)) temp_nomem();
- if (ipme_init() != 1) temp_oserr();
-
- recips = argv + 3;
- while (*recips) {
- if (!saa_readyplus(&reciplist,1)) temp_nomem();
- reciplist.sa[reciplist.len] = sauninit;
- addrmangle(reciplist.sa + reciplist.len,*recips);
- ++reciplist.len;
- ++recips;
- }
-
-
- random = now() + (getpid() << 16);
- switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&host,random)) {
- case DNS_MEM: temp_nomem();
- case DNS_SOFT: temp_dns();
- case DNS_HARD: perm_dns();
- case 1:
- if (ip.len <= 0) temp_dns();
- }
-
- if (ip.len <= 0) perm_nomx();
-
- prefme = 100000;
- for (i = 0;i < ip.len;++i)
- if (ipme_is(&ip.ix[i].ip))
- if (ip.ix[i].pref < prefme)
- prefme = ip.ix[i].pref;
-
- if (relayhost) prefme = 300000;
-
- for (i = 0;i < ip.len;++i)
- if (ip.ix[i].pref < prefme)
- break;
-
- if (i >= ip.len)
- perm_ambigmx();
-
- for (i = 0;i < ip.len;++i) if (ip.ix[i].pref < prefme) {
- if (tcpto(&ip.ix[i].ip)) continue;
-
- smtpfd = socket(AF_INET,SOCK_STREAM,0);
- if (smtpfd == -1) temp_oserr();
-
- if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
- tcpto_err(&ip.ix[i].ip,0);
- partner = ip.ix[i].ip;
- smtp(); /* does not return */
- }
- tcpto_err(&ip.ix[i].ip,errno == error_timeout);
- close(smtpfd);
- }
-
- temp_noconn();
+ static ipalloc ip = {
+ 0
+ };
+ int i;
+ unsigned long random;
+ char **recips;
+ unsigned long prefme;
+ char *relayhost;
+
+ sig_pipeignore();
+ if (argc < 4)
+ perm_usage();
+ if (chdir(auto_qmail) == -1)
+ temp_chdir();
+ getcontrols();
+
+
+ if (!stralloc_copys(&host, argv[1]))
+ temp_nomem();
+
+ relayhost = 0;
+ for (i = 0; i <= host.len; ++i)
+ if ((i == 0) || (i == host.len) || (host.s[i] == '.'))
+ if ((relayhost = constmap(&maproutes, host.s + i, host.len - i)))
+ break;
+ if (relayhost && !*relayhost)
+ relayhost = 0;
+
+ if (relayhost) {
+ i = str_chr(relayhost, ':');
+ if (relayhost[i]) {
+ scan_ulong(relayhost + i + 1, &port);
+ relayhost[i] = 0;
+ }
+ if (!stralloc_copys(&host, relayhost))
+ temp_nomem();
+ }
+
+
+ addrmangle(&sender, argv[2]);
+
+ if (!saa_readyplus(&reciplist, 0))
+ temp_nomem();
+ if (ipme_init() != 1)
+ temp_oserr();
+
+ recips = argv + 3;
+ while (*recips) {
+ if (!saa_readyplus(&reciplist, 1))
+ temp_nomem();
+ reciplist.sa[reciplist.len] = sauninit;
+ addrmangle(reciplist.sa + reciplist.len, *recips);
+ ++reciplist.len;
+ ++recips;
+ }
+
+
+ random = now() + (getpid() << 16);
+ switch (relayhost ? dns_ip(&ip, &host) : dns_mxip(&ip, &host, random)) {
+ case DNS_MEM:
+ temp_nomem();
+ case DNS_SOFT:
+ temp_dns();
+ case DNS_HARD:
+ perm_dns();
+ case 1:
+ if (ip.len <= 0)
+ temp_dns();
+ }
+
+ if (ip.len <= 0)
+ perm_nomx();
+
+ prefme = 100000;
+ for (i = 0; i < ip.len; ++i)
+ if (ipme_is(&ip.ix[i].ip))
+ if (ip.ix[i].pref < prefme)
+ prefme = ip.ix[i].pref;
+
+ if (relayhost)
+ prefme = 300000;
+
+ for (i = 0; i < ip.len; ++i)
+ if (ip.ix[i].pref < prefme)
+ break;
+
+ if (i >= ip.len)
+ perm_ambigmx();
+
+ for (i = 0; i < ip.len; ++i)
+ if (ip.ix[i].pref < prefme) {
+ if (tcpto(&ip.ix[i].ip))
+ continue;
+
+ smtpfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (smtpfd == -1)
+ temp_oserr();
+
+ if (timeoutconn(smtpfd, &ip.ix[i].ip, (unsigned int)port, timeoutconnect) == 0) {
+ tcpto_err(&ip.ix[i].ip, 0);
+ partner = ip.ix[i].ip;
+ smtp(); /* does not return, unless greeting
+ * wrong */
+ }
+ tcpto_err(&ip.ix[i].ip, errno == error_timeout);
+ close(smtpfd);
+ }
+
+ temp_noconn();
}
diff --git a/src/qmail-send.c b/src/qmail-send.c
@@ -112,6 +112,7 @@ void fnmake_chanaddr(id,c) unsigned long id; int c;
stralloc rwline = {0};
/* 1 if by land, 2 if by sea, 0 if out of memory. not allowed to barf. */
+/* Daniel.. by sea? Don't you mean by air? */
/* may trash recip. must set up rwline, between a T and a \0. */
int rewrite(recip)
char *recip;
diff --git a/src/qmail-start-np.c b/src/qmail-start-np.c
@@ -0,0 +1,206 @@
+#include <sys/stat.h>
+#include <unistd.h>
+#include "fd.h"
+#include "prot.h"
+#include "exit.h"
+#include "fork.h"
+#include "noreturn.h"
+#include "uidgid.h"
+#include "auto_uids.h"
+#include "auto_users.h"
+#include "auto_qmail.h" // auto_qmail.o
+#include "select.h" // ...?
+#include "fifo.h" // fifo.something
+#include "open.h" // open.a
+#include "hasnpbg1.h"
+
+/* MXF NOTES:
+ * This qmail-start is special. It creates named pipes for channel
+ * drivers (to wit, lspawn and rspawn) and the logger, and fires off
+ * an extra process that creates a triggerpull which qmsend should
+ * yank when it has picked up the stdin pipes of clean, logger and
+ * channel drivers.
+ */
+
+#define RDEND 0
+#define WREND 1
+
+char *(qsargs[]) = { "qmail-send", 0 };
+char *(qcargs[]) = { "qmail-clean", 0 };
+char *(qlargs[]) = { "qmail-lspawn", "./Mailbox", 0 };
+char *(qrargs[]) = { "qmail-rspawn", 0 };
+
+void _noreturn_ die() { _exit(111); }
+
+int pi0[2];
+int pi1[2];
+int pi2[2];
+int pi3[2];
+int pi4[2];
+int pi5[2];
+int pi6[2];
+
+uid_t auto_uidl;
+uid_t auto_uidq;
+uid_t auto_uidr;
+uid_t auto_uids;
+
+gid_t auto_gidn;
+gid_t auto_gidq;
+
+void close23456() { close(2); close(3); close(4); close(5); close(6); }
+
+// sort of same semantics as pipe() except that it returns the pipe instead of setting memory
+int makeorusenp(char *n, int *f) {
+ if (fifo_make(n, 0600) == -1) {
+ if (errno != EEXIST) {
+ return -1;
+ }
+ }
+ f[0] = open_read(n);
+ if (f[0] == -1) return -1;
+ fchown(f[0], auto_uids);
+ fchown(f[0], auto_gidq);
+ fchmod(f[0], 0600);
+ f[1] = open_write(n);
+ if (f[1] == -1) return -1;
+ return 0;
+}
+
+void closepipes() {
+ close(pi1[RDEND]); close(pi1[WREND]); close(pi2[RDEND]); close(pi2[WREND]);
+ close(pi3[RDEND]); close(pi3[WREND]); close(pi4[RDEND]); close(pi4[WREND]);
+ close(pi5[RDEND]); close(pi5[WREND]); close(pi6[RDEND]); close(pi6[WREND]);
+}
+
+int main(int argc, char **argv)
+{
+ if (chdir("/") == -1) die();
+ umask(077);
+
+ auto_uidl = inituid(auto_userl);
+ auto_uidq = inituid(auto_userq);
+ auto_uidr = inituid(auto_userr);
+ auto_uids = inituid(auto_users);
+
+ auto_gidn = initgid(auto_groupn);
+ auto_gidq = initgid(auto_groupq);
+
+ if (prot_gid(auto_gidq) == -1) die();
+
+ if (fd_copy(2,0) == -1) die();
+ if (fd_copy(3,0) == -1) die();
+ if (fd_copy(4,0) == -1) die();
+ if (fd_copy(5,0) == -1) die();
+ if (fd_copy(6,0) == -1) die();
+
+ if (argv[1]) {
+ qlargs[1] = argv[1];
+ ++argv;
+ }
+
+ if (chdir(auto_qmail) == -1) die();
+
+ // logger
+ if (argv[1]) {
+ if (makeorusenp("queue/lock/loggersin", &pi0) == -1) die();
+ switch(fork()) {
+ case -1:
+ die();
+ case 0:
+ if (prot_gid(auto_gidn) == -1) die();
+ if (prot_uid(auto_uidl) == -1) die();
+ close(pi0[WREND]);
+ if (fd_move(0,pi0[RDEND]) == -1) die();
+ close23456();
+ execvp(argv[1],argv + 1);
+ die();
+ }
+ close(pi0[RDEND]);
+ if (fd_move(1,pi0[WREND]) == -1) die();
+ }
+
+ if (makeorusenp("queue/lock/chan0sin", &pi1) == -1) die(); // si [
+ if (makeorusenp("queue/lock/chan0sout", &pi2) == -1) die(); // so ] lspawn
+ if (makeorusenp("queue/lock/chan1sin", &pi3) == -1) die(); // si [
+ if (makeorusenp("queue/lock/chan1sout", &pi4) == -1) die(); // so ] rspawn
+ if (makeorusenp("queue/lock/cleansin", &pi5) == -1) die(); // si [
+ if (makeorusenp("queue/lock/cleansout", &pi6) == -1) die(); // so ] cleanup
+
+ // channelspawn: local
+ switch(fork()) {
+ case -1: die();
+ case 0:
+ if (fd_copy(0,pi1[RDEND]) == -1) die();
+ if (fd_copy(1,pi2[WREND]) == -1) die();
+ close23456();
+ closepipes();
+ execvp(*qlargs,qlargs);
+ die();
+ }
+
+ // channelspawn: remote
+ switch(fork()) {
+ case -1: die();
+ case 0:
+ if (prot_uid(auto_uidr) == -1) die();
+ if (fd_copy(0,pi3[RDEND]) == -1) die();
+ if (fd_copy(1,pi4[WREND]) == -1) die();
+ close23456();
+ closepipes();
+ execvp(*qrargs,qrargs);
+ die();
+ }
+
+ // cleanup
+ switch(fork()) {
+ case -1: die();
+ case 0:
+ if (prot_uid(auto_uidq) == -1) die();
+ if (fd_copy(0,pi5[RDEND]) == -1) die();
+ if (fd_copy(1,pi6[WREND]) == -1) die();
+ close23456();
+ closepipes();
+ execvp(*qcargs,qcargs);
+ die();
+ }
+
+ // readiness
+ switch (fork()) {
+ case -1: die();
+ case 0:
+ close23456();
+#ifdef HASNAMEDPIPEBUG1
+ if (fd_copy(2,pi1[WREND]) == -1) die();
+ if (fd_copy(3,pi3[WREND]) == -1) die();
+ if (fd_copy(4,pi5[WREND]) == -1) die();
+ // on some systems, named pipes that are only open at one end
+ // constantly check readability. This turns their selects into
+ // a spinlock. Prevent this by keeping the WRENDs of pipes whose
+ // RDENDs are passed into the above processes open.
+#endif
+ closepipes();
+ if (makeorusenp("queue/lock/sendready", &pi0) == -1) die()
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(pi0[0], &rfds);
+ if (select(pi0[0] + 1, &rfds, NULL, NULL, NULL) > 0) {
+ // this can only mean one thing: someone wrote to our readiness FD.
+ // that means they now have the WRENDs of the loggersin and chanNsin
+ // pipes.
+ }
+ }
+
+ // exec into qmsend
+ if (prot_uid(auto_uids) == -1) die();
+ if (fd_copy(0,1) == -1) die();
+ if (fd_copy(1,pi1[WREND]) == -1) die();
+ if (fd_copy(2,pi2[RDEND]) == -1) die();
+ if (fd_copy(3,pi3[WREND]) == -1) die();
+ if (fd_copy(4,pi4[RDEND]) == -1) die();
+ if (fd_copy(5,pi5[WREND]) == -1) die();
+ if (fd_copy(6,pi6[RDEND]) == -1) die();
+ closepipes();
+ execvp(*qsargs,qsargs);
+ die();
+}
diff --git a/src/qmail-start.c b/src/qmail-start.c
@@ -65,6 +65,7 @@ int main(int argc, char **argv)
++argv;
}
+ // logger
if (argv[1]) {
if (pipe(pi0) == -1) die();
switch(fork()) {
@@ -82,14 +83,15 @@ int main(int argc, char **argv)
close(pi0[0]);
if (fd_move(1,pi0[1]) == -1) die();
}
-
+
if (pipe(pi1) == -1) die();
if (pipe(pi2) == -1) die();
if (pipe(pi3) == -1) die();
if (pipe(pi4) == -1) die();
if (pipe(pi5) == -1) die();
if (pipe(pi6) == -1) die();
-
+
+ // channelspawn: local
switch(fork()) {
case -1: die();
case 0:
@@ -100,7 +102,8 @@ int main(int argc, char **argv)
execvp(*qlargs,qlargs);
die();
}
-
+
+ // channelspawn: remote
switch(fork()) {
case -1: die();
case 0:
@@ -112,7 +115,8 @@ int main(int argc, char **argv)
execvp(*qrargs,qrargs);
die();
}
-
+
+ // cleanup
switch(fork()) {
case -1: die();
case 0:
@@ -124,7 +128,8 @@ int main(int argc, char **argv)
execvp(*qcargs,qcargs);
die();
}
-
+
+ // exec into qmsend
if (prot_uid(auto_uids) == -1) die();
if (fd_copy(0,1) == -1) die();
if (fd_copy(1,pi1[1]) == -1) die();