From 1cafb5eab0b30e5f5a05737a075123af53153cb1 Mon Sep 17 00:00:00 2001 From: manuel Date: Thu, 17 Aug 2017 13:17:22 +0200 Subject: add support for SMTPUTF8 --- qmail-remote.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 5 deletions(-) (limited to 'qmail-remote.c') diff --git a/qmail-remote.c b/qmail-remote.c index 94c6c0d..f8e60ad 100644 --- a/qmail-remote.c +++ b/qmail-remote.c @@ -46,6 +46,7 @@ stralloc helohost = {0}; stralloc routes = {0}; struct constmap maproutes; stralloc host = {0}; +stralloc idnhost = {0}; stralloc sender = {0}; stralloc auth_smtp_user = {0}; stralloc auth_smtp_pass = {0}; @@ -77,13 +78,19 @@ struct val_danestatus *dane_status = NULL; struct val_ssl_data *dane_ssl_data = NULL; #endif +#ifdef SMTPUTF8 +# include +int flagutf8 = 0; +stralloc header = {0}; +#endif + 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 zeroflush() { zero(); substdio_flush(subfdoutsmall); } void zerodie() { zeroflush(); _exit(0); } -void outsafe(sa) stralloc *sa; { int i; char ch; +void outsafe(sa) stralloc *sa; { int i; unsigned char ch; for (i = 0;i < sa->len;++i) { -ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?'; +ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126 && ch <= 127) ch = '?'; if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } } void temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); } @@ -346,6 +353,10 @@ void blast() int r; char ch; +#ifdef SMTPUTF8 + substdio_put(&smtpto,header.s,header.len); +#endif + for (;;) { r = substdio_get(&ssin,&ch,1); if (r == 0) break; @@ -634,11 +645,60 @@ int tls_init() stralloc recip = {0}; +#ifdef SMTPUTF8 +int utf8string(unsigned char *ch, int len) +{ + int i = 0; + while (i < len) + if (ch[i++] > 127) return 1; + return 0; +} + +int utf8received() +{ + int r, i, received = 0; + char ch; + stralloc receivedline = {0}; + + for (;;) { /* we consider only our own last written header */ + r = substdio_get(&ssin,&ch,1); + if (r == 0) break; + if (r == -1) temp_read(); + + if (ch == '\n') { + if (!stralloc_append(&header,"\r")) temp_nomem(); /* received.c does not add '\r' */ + if (!stralloc_append(&header,"\n")) temp_nomem(); + if (case_startb(receivedline.s,5,"Date:")) return 0; /* header to quit asap */ + if (case_startb(receivedline.s,14,"Received: from")) received++; /* found Received header */ + if (received) { + if (case_startb(receivedline.s,5," by ")) { + for (i = 6; i < receivedline.len-6; ++i) + if (*(receivedline.s+i) == ' ') + if (case_startb(receivedline.s+i+1,9,"with UTF8")) return 1; + return 0; + } + } + if (!stralloc_copys(&receivedline,"")) temp_nomem(); + receivedline.len = 0; + } else { + if (!stralloc_append(&header,&ch)) temp_nomem(); + if (!stralloc_catb(&receivedline,&ch,1)) temp_nomem(); + } + } + return 0; +} +#endif + void mail_without_auth() { substdio_puts(&smtpto,"MAIL FROM:<"); substdio_put(&smtpto,sender.s,sender.len); - substdio_puts(&smtpto,">\r\n"); + substdio_put(&smtpto,">",1); +#ifdef SMTPUTF8 + if (flagutf8 || utf8received()) + substdio_puts(&smtpto, " SMTPUTF8"); +#endif + substdio_puts(&smtpto,"\r\n"); substdio_flush(&smtpto); } @@ -730,7 +790,12 @@ void smtp() substdio_put(&smtpto,sender.s,sender.len); substdio_puts(&smtpto,"> AUTH=<"); substdio_put(&smtpto,sender.s,sender.len); - substdio_puts(&smtpto,">\r\n"); + substdio_put(&smtpto,">",1); +#ifdef SMTPUTF8 + if (flagutf8 || utf8received()) + substdio_puts(&smtpto, " SMTPUTF8"); +#endif + substdio_puts(&smtpto,"\r\n"); substdio_flush(&smtpto); if(!stralloc_copys(&auth_status, "Delivered with authenticated connection to \n")) temp_nomem(); if(!stralloc_0(&auth_status)) temp_nomem(); @@ -902,7 +967,12 @@ stralloc *saout; /* host has to be canonical, box has to be quoted */ char *s; { int j; - + +#ifdef SMTPUTF8 + if (!flagutf8) + flagutf8 = utf8string(s, str_len(s)); +#endif + j = str_rchr(s,'@'); if (!s[j]) { if (!stralloc_copys(saout,s)) temp_nomem(); @@ -983,6 +1053,18 @@ char **argv; relayhost[i] = 0; } if (!stralloc_copys(&host,relayhost)) temp_nomem(); + } else { +#ifdef SMTPUTF8 + char *asciihost = 0; + if (!stralloc_0(&host)) temp_nomem(); + switch (idn2_lookup_u8(host.s,(uint8_t**)&asciihost,IDN2_NFC_INPUT)) { + case IDN2_OK: break; + case IDN2_MALLOC: temp_nomem(); + default: perm_dns(); + } + if (!stralloc_copys(&idnhost,asciihost)) temp_nomem(); + if (!stralloc_0(&idnhost)) temp_nomem(); +#endif } @@ -1002,7 +1084,11 @@ char **argv; random = now() + (getpid() << 16); +#ifdef SMTPUTF8 + switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&idnhost,random)) { +#else switch (relayhost ? dns_ip(&ip,&host) : dns_mxip(&ip,&host,random)) { +#endif case DNS_MEM: temp_nomem(); case DNS_SOFT: temp_dns(); case DNS_HARD: perm_dns(); -- cgit v1.2.3