--- qmail-1.03/qmail-remote.c Mon Jun 15 12:53:16 1998 +++ qmail-1.03-qmtp/qmail-remote.c Tue Jan 9 17:47:33 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) @@ -61,6 +65,8 @@ System resources temporarily unavailable. (#4.3.0)\n"); zerodie(); } void temp_noconn() { out("Z\ Sorry, I wasn't able to establish an SMTP connection. (#4.4.1)\n"); zerodie(); } +void temp_noconn_qmtp() { out("Z\ +Sorry, I wasn't able to establish an QMTP connection. (#4.4.1)\n"); zerodie(); } void temp_read() { out("ZUnable to read message. (#4.3.0)\n"); zerodie(); } void temp_dnscanon() { out("Z\ CNAME lookup failed temporarily. (#4.4.3)\n"); zerodie(); } @@ -70,6 +76,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 +130,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 +230,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 +254,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 +270,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) _exit(0); + zerodie(); } stralloc canonhost = {0}; @@ -316,11 +432,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 +477,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 +548,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 */ @@ -422,6 +563,6 @@ tcpto_err(&ip.ix[i].ip,errno == error_timeout); close(smtpfd); } - - temp_noconn(); + if (stralloc_starts(&protocol,"qmtp")) temp_noconn_qmtp(); + else temp_noconn(); }