diff -aurbB orig/Makefile remote-tmp/Makefile --- orig/Makefile 1998-06-15 12:53:16.000000000 +0200 +++ remote-tmp/Makefile 2004-12-08 11:45:08.000000000 +0100 @@ -1463,11 +1463,11 @@ qmail-rspawn: \ load qmail-rspawn.o spawn.o tcpto_clean.o now.o coe.o sig.a open.a \ seek.a lock.a wait.a fd.a stralloc.a alloc.a substdio.a error.a str.a \ -auto_qmail.o auto_uids.o auto_spawn.o +auto_qmail.o auto_uids.o auto_spawn.o fmt_ulong.o ./load qmail-rspawn spawn.o tcpto_clean.o now.o coe.o \ sig.a open.a seek.a lock.a wait.a fd.a stralloc.a alloc.a \ substdio.a error.a str.a auto_qmail.o auto_uids.o \ - auto_spawn.o + auto_spawn.o fmt_ulong.o qmail-rspawn.0: \ qmail-rspawn.8 diff -aurbB orig/qmail-lspawn.c remote-tmp/qmail-lspawn.c --- orig/qmail-lspawn.c 1998-06-15 12:53:16.000000000 +0200 +++ remote-tmp/qmail-lspawn.c 2004-12-08 11:45:08.000000000 +0100 @@ -165,9 +165,8 @@ } } -int spawn(fdmess,fdout,s,r,at) -int fdmess; int fdout; -char *s; char *r; int at; +int +spawn(int fdmess, int fdout, const unsigned long msgsize, char *s, char *r, const unsigned int at) { int f; diff -aurbB orig/qmail-remote.8 remote-tmp/qmail-remote.8 --- orig/qmail-remote.8 1998-06-15 12:53:16.000000000 +0200 +++ remote-tmp/qmail-remote.8 2004-12-08 11:45:08.000000000 +0100 @@ -1,10 +1,11 @@ .TH qmail-remote 8 .SH NAME -qmail-remote \- send mail via SMTP +qmail-remote \- send mail via SMTP or ESMTP .SH SYNOPSIS .B qmail-remote .I host .I sender +.I size .I recip [ .I recip ... @@ -40,6 +41,11 @@ [128.32.183.163] .EE +The size parameter is only used if the remote host uses the ESMTP SIZE extension defined in +.I RFC 1870\fP. It gives the size of the message in bytes. +.BR qmail-remote +does not use this value to process the mail, the value is only passed to the remote mailserver. + The envelope recipient addresses are listed as .I recip arguments to diff -aurbB orig/qmail-remote.c remote-tmp/qmail-remote.c --- orig/qmail-remote.c 1998-06-15 12:53:16.000000000 +0200 +++ remote-tmp/qmail-remote.c 2004-12-09 14:00:06.554866880 +0100 @@ -2,6 +2,7 @@ #include #include #include +#include #include "sig.h" #include "stralloc.h" #include "substdio.h" @@ -214,25 +215,142 @@ substdio_flush(&smtpto); } +void +do_helo(char *cmd) +{ + substdio_puts(&smtpto,cmd); + substdio_put(&smtpto,helohost.s,helohost.len); + substdio_put(&smtpto,"\r\n",2); + substdio_flush(&smtpto); +} + +/** + * esmtp_ehlo - find out which ESMTP extensions the remote server supports + * + * returns: a bitmask of the supported extensions on success + * does not return on failure (logs error and quits the process) + */ +unsigned int +esmtp_ehlo(void) +{ + int search = 0; + int is_esmtp = 1; + int extensions = 0; + int code; + int i; + struct smtpext { + char *name; + int params; /* 1: lineend after this name allowed, 2: space after name is allowed */ + unsigned int len; /* strlen(name): no need to call strlen at runtime if we know it here */ + } exts[] = { + {.name = "SIZE", .params = 3, .len = 4}, + {.name = "PIPELINING", .params = 1, .len = 10}, + {.name = "STARTTLS", .params = 1, .len = 8} + }; + const int maxmask = (1 << (sizeof(exts)/sizeof(struct smtpext))) - 1; + + /* Ok, remote host will talk to us. Let's look if we can use ESMTP */ + do_helo("EHLO "); + + code = smtpcode(); + /* remote host does not like our EHLO. Maybe HELO is better? */ + if (code != 250) { + is_esmtp = 0; + do_helo("HELO "); + code = smtpcode(); + } + if (code != 250) + quit("ZConnected to "," but my name was rejected"); + + if (!is_esmtp) + return 0; + + /* if this is a one line answer there will be no extensions */ + if (smtptext.s[0] == ' ') + return 0; + + /* go through all lines of the multi line answer until we found all + known extensions or we reach the last line */ + do { + /* set search to the index of the next extension in the answer: + it's always 5 characters after the '\n' (the other 4 are + normally "250-") */ + search += 5 + str_chr(smtptext.s + search, '\n'); + + for (i = (sizeof(exts)/sizeof(struct smtpext)) - 1; i >= 0; i--) { + if (!case_diffb(smtptext.s + search, exts[i].len, exts[i].name)) { + if ( ((smtptext.s[search + exts[i].len] == '\n') && (exts[i].params & 1)) || + ((smtptext.s[search + exts[i].len] == ' ') && (exts[i].params & 2)) ) { + extensions |= (1<\r\n"); + if (extensions & 1) { + substdio_put(&smtpto, "> SIZE=", 7); + substdio_puts(&smtpto, msgsize); + substdio_put(&smtpto, "\r\n", 2); + } else { + substdio_put(&smtpto, ">\r\n", 3); + } + if (extensions & 2) { + for (i = 0;i < reciplist.len;++i) { + substdio_put(&smtpto,"RCPT TO:<", 9); + substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len); + substdio_put(&smtpto,">\r\n", 3); + } + substdio_putsflush(&smtpto,"DATA\r\n"); + + code = smtpcode(); + if (code >= 500) quit("DConnected to "," but sender was rejected"); + if (code >= 400) quit("ZConnected to "," but sender was rejected"); + + flagbother = 0; + for (i = 0;i < reciplist.len;++i) { + code = smtpcode(); + if (code >= 500) { + out("h"); outhost(); out(" does not like recipient.\n"); + outsmtptext(); zero(); + } else if (code >= 400) { + out("s"); outhost(); out(" does not like recipient.\n"); + outsmtptext(); zero(); + } else { + out("r"); zero(); + flagbother = 1; + } + } + if (!flagbother) quit("DGiving up on ",""); + } else { substdio_flush(&smtpto); code = smtpcode(); if (code >= 500) quit("DConnected to "," but sender was rejected"); @@ -240,9 +358,9 @@ flagbother = 0; for (i = 0;i < reciplist.len;++i) { - substdio_puts(&smtpto,"RCPT TO:<"); + substdio_put(&smtpto,"RCPT TO:<", 9); substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len); - substdio_puts(&smtpto,">\r\n"); + substdio_put(&smtpto,">\r\n", 3); substdio_flush(&smtpto); code = smtpcode(); if (code >= 500) { @@ -261,6 +379,8 @@ if (!flagbother) quit("DGiving up on ",""); 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"); @@ -340,7 +460,7 @@ char *relayhost; sig_pipeignore(); - if (argc < 4) perm_usage(); + if (argc < 5) perm_usage(); if (chdir(auto_qmail) == -1) temp_chdir(); getcontrols(); @@ -370,7 +490,7 @@ if (ipme_init() != 1) temp_oserr(); flagallaliases = 1; - recips = argv + 3; + recips = argv + 4; while (*recips) { if (!saa_readyplus(&reciplist,1)) temp_nomem(); reciplist.sa[reciplist.len] = sauninit; @@ -417,7 +537,7 @@ if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) { tcpto_err(&ip.ix[i].ip,0); partner = ip.ix[i].ip; - smtp(); /* does not return */ + smtp(argv[3]); /* does not return */ } tcpto_err(&ip.ix[i].ip,errno == error_timeout); close(smtpfd); diff -aurbB orig/qmail-rspawn.c remote-tmp/qmail-rspawn.c --- orig/qmail-rspawn.c 1998-06-15 12:53:16.000000000 +0200 +++ remote-tmp/qmail-rspawn.c 2004-12-08 11:45:08.000000000 +0100 @@ -5,6 +5,7 @@ #include "fork.h" #include "error.h" #include "tcpto.h" +#include "fmt.h" void initialize(argc,argv) int argc; @@ -77,18 +78,20 @@ } } -int spawn(fdmess,fdout,s,r,at) -int fdmess; int fdout; -char *s; char *r; int at; +int +spawn(int fdmess, int fdout, const unsigned long msgsize, char *s, char *r, const unsigned int at) { int f; - char *(args[5]); + char *(args[6]); + char size_buf[FMT_ULONG]; + size_buf[fmt_ulong(size_buf, msgsize)] = 0; args[0] = "qmail-remote"; args[1] = r + at + 1; args[2] = s; - args[3] = r; - args[4] = 0; + args[3] = size_buf; + args[4] = r; + args[5] = 0; if (!(f = vfork())) { diff -aurbB orig/spawn.c remote-tmp/spawn.c --- orig/spawn.c 1998-06-15 12:53:16.000000000 +0200 +++ remote-tmp/spawn.c 2004-12-08 11:45:08.000000000 +0100 @@ -80,7 +80,7 @@ { int f; int i; - int j; + unsigned int j; int fdmess; int pi[2]; struct stat st; @@ -119,7 +119,7 @@ coe(pi[0]); - f = spawn(fdmess,pi[1],sender.s,recip.s,j); + f = spawn(fdmess,pi[1],st.st_size,sender.s,recip.s,j); close(fdmess); if (f == -1) { close(pi[0]); close(pi[1]); err("Zqmail-spawn unable to fork. (#4.3.0)\n"); return; }