This is the second release of this patch, dated 2001-01-08. It is more careful about checking memory allocation success. This patch is based on Russell Nelsons' patch (qmail-1.03-qmtpc.patch) which he released 2001-01-05. It is available from http://qmail.org/qmail-1.03-qmtpc.patch This patch introduces a file named control/mailroutes which replaces control/smtproutes from the original qmail. The format is the same, exept for a last field, specifying the protocol. Two example lines looks like this: almqvist.net:beta.lunds.lu.se:209:qmtp propellerheads.org:mail-relay.df.lth.se In the first case, QMTP will be used to transfer messages for the almqvist.net domain to beta.lunds.lu.se, port 209. In the second case, SMTP will be used to transfer messages for the propellerheads.org domain to mail-relay.df.lth.se, port 25. PLEASE NOTE that SMTP will be assumed as protocol even if you specify 209 as the port, but no protocol. In fact, SMTP will be used in all cases except if the last field is exactly 'qmtp'. PLEASE NOTE that you cannot specify only a protocol. If you wish to specify a protocol, you MUST specify a port. Bad things may happen. YMMV and UAYOR. To report success: % (echo 'First M. Last';echo 'qmail-remote-qmtp-mailroutes';uname -a)|mail johan-qmail@almqvist.net Replace First M. Last with your name. No warranties whatsoever. Written by Johan Almqvist, johan-qmail@almqvist.net http://www.almqvist.net/johan/qmail/ You will also find info about the qmtptest autoresponder at the URI above. diff -u qmail-1.03/qmail-remote.c qmail-1.03-qmtp/qmail-remote.c --- qmail-1.03/qmail-remote.c Mon Jun 15 12:53:16 1998 +++ qmail-1.03-qmtp/qmail-remote.c Mon Jan 8 02:21:52 2001 @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -14,6 +15,7 @@ #include "dns.h" #include "alloc.h" #include "quote.h" +#include "fmt.h" #include "ip.h" #include "ipalloc.h" #include "ipme.h" @@ -31,8 +33,10 @@ #define HUGESMTPTEXT 5000 -#define PORT_SMTP 25 /* silly rabbit, /etc/services is for users */ -unsigned long port = PORT_SMTP; +unsigned long smtp_port = 25; /* silly rabbit, /etc/services is for users */ +unsigned long qmtp_port = 209; + +stralloc protocol = {0}; GEN_ALLOC_typedef(saa,stralloc,sa,len,a) GEN_ALLOC_readyplus(saa,stralloc,sa,len,a,i,n,x,10,saa_readyplus) @@ -70,6 +74,8 @@ Unable to switch to home directory. (#4.3.0)\n"); zerodie(); } void temp_control() { out("Z\ Unable to read control files. (#4.3.0)\n"); zerodie(); } +void temp_proto() { out("Z\ +recipient did not talk proper QMTP (#4.3.0)\n"); zerodie(); } void perm_partialline() { out("D\ SMTP cannot transfer messages with partial final lines. (#5.6.2)\n"); zerodie(); } void perm_usage() { out("D\ @@ -122,9 +128,9 @@ return r; } -char inbuf[1024]; +char inbuf[1500]; substdio ssin = SUBSTDIO_FDBUF(read,0,inbuf,sizeof inbuf); -char smtptobuf[1024]; +char smtptobuf[1500]; substdio smtpto = SUBSTDIO_FDBUF(safewrite,-1,smtptobuf,sizeof smtptobuf); char smtpfrombuf[128]; substdio smtpfrom = SUBSTDIO_FDBUF(saferead,-1,smtpfrombuf,sizeof smtpfrombuf); @@ -273,6 +279,113 @@ quit("K"," accepted message"); } +int qmtp_priority(int pref) +{ + if (pref < 12800) return 0; + if (pref > 13055) return 0; + if (pref % 16 == 1) return 1; + return 0; +} + +void qmtp() +{ + struct stat st; + unsigned long len; + int len2; + char *x; + int i; + int n; + unsigned char ch; + char num[FMT_ULONG]; + int flagallok; + + if (fstat(0,&st) == -1) quit("Z", " unable to fstat stdin"); + len = st.st_size; + + /* the following code was substantially taken from serialmail'ss serialqmtp.c */ + substdio_put(&smtpto,num,fmt_ulong(num,len+1)); + substdio_put(&smtpto,":\n",2); + while (len > 0) { + n = substdio_feed(&ssin); + if (n <= 0) _exit(32); /* wise guy again */ + x = substdio_PEEK(&ssin); + substdio_put(&smtpto,x,n); + substdio_SEEK(&ssin,n); + len -= n; + } + substdio_put(&smtpto,",",1); + + len = sender.len; + substdio_put(&smtpto,num,fmt_ulong(num,len)); + substdio_put(&smtpto,":",1); + substdio_put(&smtpto,sender.s,sender.len); + substdio_put(&smtpto,",",1); + + len = 0; + for (i = 0;i < reciplist.len;++i) + len += fmt_ulong(num,reciplist.sa[i].len) + 1 + reciplist.sa[i].len + 1; + substdio_put(&smtpto,num,fmt_ulong(num,len)); + substdio_put(&smtpto,":",1); + for (i = 0;i < reciplist.len;++i) { + substdio_put(&smtpto,num,fmt_ulong(num,reciplist.sa[i].len)); + substdio_put(&smtpto,":",1); + substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len); + substdio_put(&smtpto,",",1); + } + substdio_put(&smtpto,",",1); + substdio_flush(&smtpto); + + flagallok = 1; + + for (i = 0;i < reciplist.len;++i) { + len = 0; + for (;;) { + get(&ch); + if (ch == ':') break; + if (len > 200000000) temp_proto(); + if (ch - '0' > 9) temp_proto(); + len = 10 * len + (ch - '0'); + } + if (!len) temp_proto(); + get(&ch); --len; + if ((ch != 'Z') && (ch != 'D') && (ch != 'K')) temp_proto(); + + if (!stralloc_copyb(&smtptext,&ch,1)) temp_proto(); + if (!stralloc_cats(&smtptext,"qmtp: ")) temp_nomem(); + + while (len > 0) { + get(&ch); + --len; + } + + for (len = 0;len < smtptext.len;++len) { + ch = smtptext.s[len]; + if ((ch < 32) || (ch > 126)) smtptext.s[len] = '?'; + } + get(&ch); + if (ch != ',') temp_proto(); + smtptext.s[smtptext.len-1] = '\n'; + + if (smtptext.s[0] == 'K') out("r"); + else if (smtptext.s[0] == 'D') { + out("h"); + flagallok = 0; + } + else { /* if (smtptext.s[0] == 'Z') */ + out("s"); + flagallok = 0; + } + if (substdio_put(subfdoutsmall,smtptext.s+1,smtptext.len-1) == -1) temp_noconn(); + zero(); + } + if (!flagallok) { + out("DGiving up on ");outhost();out("\n"); + } else { + out("KAll received okay by ");outhost();out("\n"); + } + zerodie(); +} + stralloc canonhost = {0}; stralloc canonbox = {0}; @@ -316,7 +429,7 @@ temp_control(); if (control_rldef(&helohost,"control/helohost",1,(char *) 0) != 1) temp_control(); - switch(control_readfile(&routes,"control/smtproutes",0)) { + switch(control_readfile(&routes,"control/mailroutes",0)) { case -1: temp_control(); case 0: @@ -353,14 +466,24 @@ if (relayhost = constmap(&maproutes,host.s + i,host.len - i)) break; if (relayhost && !*relayhost) relayhost = 0; - + + if (!stralloc_copys(&protocol,"smtp")) temp_nomem(); /* smtp is the default */ + if (relayhost) { i = str_chr(relayhost,':'); if (relayhost[i]) { - scan_ulong(relayhost + i + 1,&port); - relayhost[i] = 0; + if (!stralloc_copyb(&host,relayhost,i)) temp_nomem(); + scan_ulong(relayhost + i + 1,&smtp_port); + qmtp_port = smtp_port; /* it is in the route file */ + i += str_chr(relayhost+i+1,':'); + if (relayhost[i++]) { + stralloc_copys(&protocol,""); + } + while (relayhost[i++]) { + if (!stralloc_append(&protocol,relayhost + i)) temp_nomem(); /* let the route file set the protol */ + } } - if (!stralloc_copys(&host,relayhost)) temp_nomem(); + else if (!stralloc_copys(&host,relayhost)) temp_nomem(); } @@ -414,7 +537,14 @@ smtpfd = socket(AF_INET,SOCK_STREAM,0); if (smtpfd == -1) temp_oserr(); - if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) { + if (qmtp_priority(ip.ix[i].pref) || stralloc_starts(&protocol,"qmtp")) { + if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) qmtp_port,timeoutconnect) == 0) { + tcpto_err(&ip.ix[i].ip,0); + partner = ip.ix[i].ip; + qmtp(); /* does not return */ + } + } + if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) smtp_port,timeoutconnect) == 0) { tcpto_err(&ip.ix[i].ip,0); partner = ip.ix[i].ip; smtp(); /* does not return */