This is the third release of this patch, dated 2001-01-10. It will now log smtp and qmtp transactions with similar syntax. It will also use smtproutes if mailroutes doesn't exist. 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. You may sipmly copy the smtproutes file to mailroutes. 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. control/smtproutes will be read if, and only if, control/mailroutes doesn't exist. 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/ 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 Tue Jan 9 12:33:57 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); @@ -222,21 +228,21 @@ int flagbother; int i; - if (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); + if (smtpcode() != 220) quit("Zsmtp: Connected 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"); + if (smtpcode() != 250) quit("Zsmtp: Connected 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"); + if (code >= 500) quit("Dsmtp: Connected to "," but sender was rejected"); + if (code >= 400) quit("Zsmtp: Connected to "," but sender was rejected"); flagbother = 0; for (i = 0;i < reciplist.len;++i) { @@ -246,11 +252,11 @@ substdio_flush(&smtpto); code = smtpcode(); if (code >= 500) { - out("h"); outhost(); out(" does not like recipient.\n"); + out("hsmtp: "); outhost(); out(" does not like recipient.\n"); outsmtptext(); zero(); } else if (code >= 400) { - out("s"); outhost(); out(" does not like recipient.\n"); + out("ssmtp:"); outhost(); out(" does not like recipient.\n"); outsmtptext(); zero(); } else { @@ -262,15 +268,123 @@ 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"); + if (code >= 500) quit("Dsmtp: "," failed on DATA command"); + if (code >= 400) quit("Zsmtp: "," 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"); + if (code >= 500) quit("Dsmtp: "," failed after I sent the message"); + if (code >= 400) quit("Zsmtp: "," failed after I sent the message"); + quit("Ksmtp: "," 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,"Remote host said: ")) 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("Dqmtp: Giving up on ");outhost();out("\n"); + } else { + out("Kqmtp: ");outhost();out(" accepted message.\n"); + } + if (substdio_put(subfdoutsmall,smtptext.s+1,smtptext.len-1) == -1) temp_noconn(); + zerodie(); } stralloc canonhost = {0}; @@ -316,11 +430,19 @@ 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: - if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); break; + case 0: /* file there but empty? */ + // if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); break; + switch(control_readfile(&routes,"control/smtproutes",0)) { + case -1: + temp_control(); + case 0: /* both files there but emtpy */ + if (!constmap_init(&maproutes,"",0,1)) temp_nomem(); break; /* never mind */ + case 1: + if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break; + } case 1: if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break; } @@ -353,14 +475,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 +546,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 */