32 r = timeoutwrite(
timeout,fd,buf,len);
40static void flush() { buffer_flush(&
bo); }
41static void out(
char *s) { buffer_puts(&
bo,s); }
43static void die_read() { _exit(1); }
44static void nomem() {
out(
"451 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }
45static void die_config() {
out(
"451 unable to read configuration (#4.3.0)\r\n"); flush(); _exit(1); }
46static void smtp_quit() {
out(
"221 ofmipd.local\r\n"); flush(); _exit(0); }
47static void smtp_help() {
out(
"214 s/qmail home page: https://fehcom.de/sqmail/sqmail.html\r\n"); }
48static void smtp_noop() {
out(
"250 ok\r\n"); }
49static void smtp_vrfy() {
out(
"252 send some mail, i'll try my best\r\n"); }
50static void smtp_unimpl() {
out(
"502 unimplemented (#5.5.1)\r\n"); }
51static void err_syntax() {
out(
"555 syntax error (#5.5.4)\r\n"); }
52static void err_wantmail() {
out(
"503 MAIL first (#5.5.1)\r\n"); }
53static void err_wantrcpt() {
out(
"503 RCPT first (#5.5.1)\r\n"); }
54static void err_qqt() {
out(
"451 qqt failure (#4.3.0)\r\n"); }
55static void err_cdb() {
out(
"451 unable to read cdb (#4.3.0)\r\n"); }
63static int addrparse(
char *arg)
77 arg += str_chr(arg,
':');
78 if (*arg ==
':') ++arg;
79 while (*arg ==
' ') ++arg;
82 if (*arg ==
'@')
while (*arg)
if (*arg++ ==
':')
break;
84 if (!stralloc_copys(&
addr,
"")) nomem();
87 for (i = 0; (ch = arg[i]); ++i) {
89 if (!stralloc_append(&
addr,&ch)) nomem();
93 if (!flagquoted && (ch == terminator))
break;
95 case '\\': flagesc = 1;
break;
96 case '"': flagquoted = !flagquoted;
break;
97 default:
if (!stralloc_append(&
addr,&ch)) nomem();
110static struct cdb cdb;
118static void smtp_helo(
char *arg)
121 out(
"250 ofmipd.local\r\n");
123static void smtp_ehlo(
char *arg)
126 out(
"250-ofmipd.local\r\n250-PIPELINING\r\n250 8BITMIME\r\n");
128static void smtp_rset()
131 out(
"250 flushed\r\n");
133static void smtp_mail(
char *arg)
136 unsigned int datalen;
138 if (!addrparse(arg)) { err_syntax();
return; }
145 cdb_init(&cdb,fdcdb);
147 if (r == -1) { err_cdb();
return; }
149 datalen = cdb_datalen(&cdb);
150 data = alloc(datalen);
151 if (!
data || !datalen) { err_cdb();
return; }
152 if (!stralloc_ready(&
cdbresult,(
unsigned int) dlen)) nomem();
155 if (cdb_read(&cdb,
name,
cdbresult.len,cdb_datapos(&cdb)) == -1) { err_cdb();
return; }
157 if (r ==
cdbresult.len) { err_cdb();
return; }
163 if (!stralloc_0(&
mailfrom)) nomem();
164 if (!stralloc_copys(&
rcptto,
"")) nomem();
168static void smtp_rcpt(
char *arg)
170 if (!
seenmail) { err_wantmail();
return; }
171 if (!addrparse(arg)) { err_syntax();
return; }
172 if (!stralloc_0(&
rwaddr)) nomem();
173 if (!stralloc_cats(&
rcptto,
"T")) nomem();
175 if (!stralloc_0(&
rcptto)) nomem();
186static void rewritelist(stralloc *list)
189 if (!stralloc_copy(list,&
tmp)) nomem();
192static void putlist(
char *
name,stralloc *list)
194 if (!list->len)
return;
219 {
"date", 0, 0, 0, 0, &
date, 0 }
220, {
"to", 0, 0, 0, &
to, 0, 0 }
221, {
"cc", 0, 0, 0, &
cc, 0, 0 }
222, {
"notice-requested-upon-delivery-to", 0, 0, 0, &
nrudt, 0, 0 }
223, {
"from", 0, 0, 0, &
from, 0, 0 }
225, {
"reply-to", 0, 0, 0, &
replyto, 0, 0 }
227, {
"mail-followup-to", 0, 0, 0, &
followupto, 0, 0 }
228, {
"message-id", 0, &
msgid, 0, 0, 0, 0 }
229, {
"received", 0, &
top, 0, 0, 0, 0 }
230, {
"delivered-to", 0, &
top, 0, 0, 0, 0 }
231, {
"errors-to", 0, &
top, 0, 0, 0, 0 }
232, {
"return-receipt-to", 0, &
top, 0, 0, 0, 0 }
233, {
"resent-sender", 0, &
top, 0, 0, 0, 0 }
234, {
"resent-from", 0, &
top, 0, 0, 0, 0 }
235, {
"resent-reply-to", 0, &
top, 0, 0, 0, 0 }
236, {
"resent-to", 0, &
top, 0, 0, 0, 0 }
237, {
"resent-cc", 0, &
top, 0, 0, 0, 0 }
238, {
"resent-bcc", 0, &
top, 0, 0, 0, 0 }
239, {
"resent-date", 0, &
top, 0, 0, 0, 0 }
240, {
"resent-message-id", 0, &
top, 0, 0, 0, 0 }
241, {
"bcc", 0, 0, 0, 0, 0, 0 }
242, {
"return-path", 0, 0, 0, 0, 0, 0 }
243, {
"apparently-to", 0, 0, 0, 0, 0, 0 }
244, {
"content-length", 0, 0, 0, 0, 0, 0 }
245, { 0, 0, &
bottom, 0, 0, 0, 0 }
248static void finishheader()
272 static int idcounter = 0;
274 if (!stralloc_copys(&
msgid,
"Message-ID: <")) nomem();
281 if (!stralloc_cats(&
msgid,
".")) nomem();
282 if (!stralloc_catint(&
msgid,++idcounter)) nomem();
284 if (!stralloc_cats(&
msgid,
">\n")) nomem();
288 putlist(
"From: ",&
from);
297 putlist(
"Reply-To: ",&
replyto);
300 if (!
to.len && !
cc.len)
301 spit(
"Cc: recipient list not shown: ;\n");
304 putlist(
"Notice-Requested-Upon-Delivery-To: ",&
nrudt);
309static ssize_t saferead(
int fd,
char *
buf,
int len)
314 if (r <= 0) die_read();
333 if (!
match) die_read();
337 if (
line.len && (
line.s[0] ==
'.')) {
339 if (!
line.len)
break;
340 for (i = 0; i <
line.len; ++i)
line.s[i] =
line.s[i + 1];
348 if (
line.len > 1) put(
"\n",1);
362static void smtp_data() {
371 if (!
seenmail) { err_wantmail();
return; }
372 if (!
rcptto.len) { err_wantrcpt();
return; }
375 out(
"354 go ahead\r\n");
385 if (!*qqx) {
out(
"250 ok\r\n");
return; }
386 if (*qqx ==
'D')
out(
"554 ");
else out(
"451 ");
391static void safecats(stralloc *
out,
char *in)
395 while ((ch = *in++)) {
396 if (ch < 33) ch =
'?';
397 if (ch > 126) ch =
'?';
398 if (ch ==
'(') ch =
'?';
399 if (ch ==
')') ch =
'?';
400 if (ch ==
'@') ch =
'?';
401 if (ch ==
'\\') ch =
'?';
402 if (!stralloc_append(
out,&ch)) nomem();
406static void received_init()
410 if (!stralloc_copys(&
received,
"Received: (ofmipd ")) nomem();
411 x = env_get(
"TCPREMOTEINFO");
414 if (!stralloc_append(&
received,
"@")) nomem();
416 x = env_get(
"TCPREMOTEIP");
417 if (!x) x =
"unknown";
419 if (!stralloc_cats(&
received,
"); ")) nomem();
423 {
"rcpt", smtp_rcpt, 0 }
424, {
"mail", smtp_mail, 0 }
425, {
"data", smtp_data,
flush }
426, {
"quit", smtp_quit,
flush }
427, {
"helo", smtp_helo,
flush }
428, {
"ehlo", smtp_ehlo,
flush }
429, {
"rset", smtp_rset, 0 }
430, {
"help", smtp_help,
flush }
431, {
"noop", smtp_noop,
flush }
432, {
"vrfy", smtp_vrfy,
flush }
433, { 0, smtp_unimpl,
flush }
442 fdcdb = open_read(fncdb);
443 if (fdcdb == -1) die_config();
451 out(
"220 ofmipd.local ESMTP\r\n");
struct commands smtpcommands[]
ssize_t safewrite(int fd, char *buf, int len)
int rewritehost_list(stralloc *, char *, unsigned int, stralloc *)
int rewritehost_addr(stralloc *, char *, unsigned int, stralloc *)
int mess822_quote(stralloc *, char *, char *)
int mess822_line(mess822_header *, stralloc *)
int mess822_end(mess822_header *)
int mess822_ok(stralloc *)
int mess822_fold(stralloc *, stralloc *, char *, int)
int mess822_date(stralloc *, mess822_time *)
int mess822_begin(mess822_header *, mess822_action *)
int mess822_quotelist(stralloc *, stralloc *)
int rwhconfig(config_str *, stralloc *)
void qmail_from(struct qmail *, char *)
void qmail_put(struct qmail *, char *, int)
char * qmail_close(struct qmail *)
void qmail_puts(struct qmail *, char *)
int qmail_open(struct qmail *)
void caltime_utc(struct caltime *ct, struct tai *t, int *pwday, int *pyday)