diff options
-rw-r--r-- | NEWS | 7 | ||||
-rw-r--r-- | driver.c | 96 | ||||
-rw-r--r-- | fetchmail-FAQ.html | 11 | ||||
-rw-r--r-- | fetchmail.h | 8 | ||||
-rwxr-xr-x | fetchmailconf | 7 | ||||
-rw-r--r-- | imap.c | 103 | ||||
-rw-r--r-- | pop3.c | 27 | ||||
-rw-r--r-- | rcfile_l.l | 2 | ||||
-rw-r--r-- | sink.c | 30 | ||||
-rw-r--r-- | smtp.c | 12 | ||||
-rw-r--r-- | smtp.h | 4 | ||||
-rw-r--r-- | socket.c | 7 | ||||
-rw-r--r-- | transact.c | 101 | ||||
-rw-r--r-- | uid.c | 19 |
14 files changed, 274 insertions, 160 deletions
@@ -2,9 +2,14 @@ (The `lines' figures total .c, .h, .l, and .y files under version control.) -* Updated German and Turkish translations. +* Updated German, Spanish, Catalan, and Turkish translations. * IDLE is now supported using no-ops even if the server doesn't support the IMAP IDLE extension. +* Sunil Shetye's patch to do better password shrouding. +* Sunil Shetye's bug-fix rollup patch. +* Introduce a translation item for the word "seen". +* Back out the hack to deal with lack of byte stuffing on some POP3 servers. +* Thomas Steudten's patch to improve SMTP handling of 550 errors. fetchmail-6.2.3 (Thu Jul 17 14:53:00 EDT 2003), 22490 lines: @@ -69,8 +69,8 @@ int batchcount; /* count of messages sent in current batch */ flag peek_capable; /* can we peek for better error recovery? */ int mailserver_socket_temp = -1; /* socket to free if connect timeout */ -static int timeoutcount; /* count consecutive timeouts */ -static int idletimeout; /* timeout occured in idle stage? */ +volatile static int timeoutcount = 0; /* count consecutive timeouts */ +volatile static int idletimeout = 0; /* timeout occured in idle stage? */ static jmp_buf restart; @@ -80,6 +80,11 @@ int isidletimeout(void) return idletimeout; } +void resetidletimeout(void) +{ + idletimeout = 0; +} + void set_timeout(int timeleft) /* reset the nonresponse-timeout */ { @@ -89,8 +94,6 @@ void set_timeout(int timeleft) if (timeleft == 0) timeoutcount = 0; - idletimeout = 1; - ntimeout.it_interval.tv_sec = ntimeout.it_interval.tv_usec = 0; ntimeout.it_value.tv_sec = timeleft; ntimeout.it_value.tv_usec = 0; @@ -428,7 +431,10 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, if (msgcodes[num-1] < 0) { if ((msgcodes[num-1] == MSGLEN_TOOLARGE) && !check_only) + { mark_oversized(ctl, num, msgsizes[num-1]); + suppress_delete = TRUE; + } /* To avoid flooding the syslog when using --keep, * report "Skipped message" only when: * 1) --verbose is on, or @@ -468,6 +474,7 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, else { flag wholesize = !ctl->server.base_protocol->fetch_body; + flag separatefetchbody = (ctl->server.base_protocol->fetch_body) ? TRUE : FALSE; /* request a message */ err = (ctl->server.base_protocol->fetch_headers)(mailserver_socket,ctl,num, &len); @@ -509,39 +516,23 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, * output sink. */ err = readheaders(mailserver_socket, len, msgsizes[num-1], - ctl, num); + ctl, num, + /* pass the suppress_readbody flag only if the underlying + * protocol does not fetch the body separately */ + separatefetchbody ? 0 : &suppress_readbody); if (err == PS_RETAINED) - { suppress_forward = suppress_delete = retained = TRUE; - suppress_readbody = TRUE; - } else if (err == PS_TRANSIENT) - { suppress_delete = suppress_forward = TRUE; - suppress_readbody = TRUE; - } else if (err == PS_REFUSED) - { suppress_forward = TRUE; - suppress_readbody = TRUE; - } else if (err == PS_TRUNCATED) - { suppress_readbody = TRUE; - len = 0; /* suppress body processing */ - } else if (err) return(err); - /* - * If we're using IMAP4 or something else that - * can fetch headers separately from bodies, - * it's time to request the body now. This - * fetch may be skipped if we got an anti-spam - * or other PS_REFUSED error response during - * readheaders. - */ - if (ctl->server.base_protocol->fetch_body && !suppress_readbody) + /* tell server we got it OK and resynchronize */ + if (separatefetchbody && ctl->server.base_protocol->trail) { if (outlevel >= O_VERBOSE && !isafile(1)) { @@ -551,9 +542,27 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, if ((err = (ctl->server.base_protocol->trail)(mailserver_socket, ctl, num))) return(err); - len = 0; - if (!suppress_forward) + } + + /* do not read the body which is not being forwarded only if + * the underlying protocol allows the body to be fetched + * separately */ + if (separatefetchbody && suppress_forward) + suppress_readbody = TRUE; + + /* + * If we're using IMAP4 or something else that + * can fetch headers separately from bodies, + * it's time to request the body now. This + * fetch may be skipped if we got an anti-spam + * or other PS_REFUSED error response during + * readheaders. + */ + if (!suppress_readbody) + { + if (separatefetchbody) { + len = -1; if ((err=(ctl->server.base_protocol->fetch_body)(mailserver_socket,ctl,num,&len))) return(err); /* @@ -569,22 +578,12 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, report_complete(stdout, GT_(" (%d body octets) "), len); } - } - /* process the body now */ - if (len > 0) - { - if (suppress_readbody) - { - err = PS_SUCCESS; - } - else - { - err = readbody(mailserver_socket, - ctl, - !suppress_forward, - len); - } + /* process the body now */ + err = readbody(mailserver_socket, + ctl, + !suppress_forward, + len); if (err == PS_TRANSIENT) suppress_delete = suppress_forward = TRUE; else if (err) @@ -669,7 +668,8 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, } else if (ctl->server.base_protocol->delete && !suppress_delete - && ((msgcodes[num-1] >= 0) ? !ctl->keep : ctl->flush)) + && ((msgcodes[num-1] >= 0 && !ctl->keep) + || (msgcodes[num-1] == MSGLEN_OLD && ctl->flush))) { (*deletions)++; if (outlevel > O_SILENT) @@ -704,7 +704,7 @@ static int fetch_messages(int mailserver_socket, struct query *ctl, } /* perhaps this as many as we're ready to handle */ - if (maxfetch && maxfetch <= *fetches && *fetches < count) + if (maxfetch && maxfetch <= *fetches && num < count) { report(stdout, GT_("fetchlimit %d reached; %d messages left on server %s account %s\n"), maxfetch, count - *fetches, ctl->server.truename, ctl->remotename); @@ -1260,10 +1260,12 @@ is restored.")); else if (count != 0) { if (new != -1 && (count - new) > 0) - report_build(stdout, GT_("%d %s (%d seen) for %s"), + report_build(stdout, GT_("%d %s (%d %s) for %s"), count, count > 1 ? GT_("messages") : GT_("message"), - count-new, buf); + count-new, + GT_("seen"), + buf); else report_build(stdout, GT_("%d %s for %s"), count, count > 1 ? GT_("messages") : diff --git a/fetchmail-FAQ.html b/fetchmail-FAQ.html index 20db7abf..21f2346e 100644 --- a/fetchmail-FAQ.html +++ b/fetchmail-FAQ.html @@ -16,7 +16,7 @@ content="Frequently asked questions about fetchmail."/> Page</a></td> <td width="30%" align="center">To <a href="/~esr/sitemap.html">Site Map</a></td> -<td width="30%" align="right">$Date: 2003/07/22 02:09:43 $</td> +<td width="30%" align="right">$Date: 2003/08/06 04:31:10 $</td> </tr> </table> @@ -2002,9 +2002,12 @@ next cycle.</p> <h2><a id="I8" name="I8">I8. How can I use fetchmail with comcast.net?</a></h2> <p>Stock fetchmail will work with a comcast.net server...<em>but</em> -they seem to have an 80K limit on the length of downloaded messages. +the Maillennium POP3 server comcat uses seems to have an 80K limit on +the length of downloaded messages if you use POP3 TOP to retrieve. Anything larger is silently truncated. Don't mistake this for a -fetchmail bug.</p> +fetchmail bug. (Reported July 2003.)</p> + +<p>Workaround: use the <tt>fetchall</tt> option.</p> <hr/> <h2><a id="K1" name="K1">K1. How can I use fetchmail with SOCKS?</a></h2> @@ -3473,7 +3476,7 @@ does something like "date >> $HOME/Procmail/fetchmail.log".</p> Page</a></td> <td width="30%" align="center">To <a href="/~esr/sitemap.html">Site Map</a></td> -<td width="30%" align="right">$Date: 2003/07/22 02:09:43 $</td> +<td width="30%" align="right">$Date: 2003/08/06 04:31:10 $</td> </tr> </table> diff --git a/fetchmail.h b/fetchmail.h index 627048f4..edcb57c8 100644 --- a/fetchmail.h +++ b/fetchmail.h @@ -94,7 +94,6 @@ #define PS_BSMTP 12 /* output batch could not be opened */ #define PS_MAXFETCH 13 /* poll ended by fetch limit */ #define PS_SERVBUSY 14 /* server is busy */ -#define PS_IDLETIMEOUT 15 /* timeout on imap IDLE */ /* leave space for more codes */ #define PS_UNDEFINED 23 /* something I hadn't thought of */ #define PS_TRANSIENT 24 /* transient failure (internal use) */ @@ -102,6 +101,7 @@ #define PS_RETAINED 26 /* message retained (internal use) */ #define PS_TRUNCATED 27 /* headers incomplete (internal use) */ #define PS_REPOLL 28 /* repoll immediately with changed parameters (internal use) */ +#define PS_IDLETIMEOUT 29 /* timeout on imap IDLE (internal use) */ /* output noise level */ #define O_SILENT 0 /* mute, max squelch, etc. */ @@ -391,7 +391,7 @@ extern int pass; /* number of re-polling pass */ extern flag configdump; /* dump control blocks as Python dictionary */ extern char *fetchmailhost; /* either "localhost" or an FQDN */ extern int suppress_tags; /* suppress tags in tagged protocols? */ -extern char shroud[PASSWORDLEN*2+1]; /* string to shroud in debug output */ +extern char shroud[PASSWORDLEN*2+3]; /* string to shroud in debug output */ #ifdef SDPS_ENABLE extern char *sdps_envfrom; extern char *sdps_envto; @@ -429,6 +429,7 @@ void report_at_line (); /* driver.c -- main driver loop */ void set_timeout(int); int isidletimeout(void); +void resetidletimeout(void); int do_protocol(struct query *, const struct method *); /* transact.c: transaction support */ @@ -437,7 +438,8 @@ int readheaders(int sock, long fetchlen, long reallen, struct query *ctl, - int num); + int num, + flag *suppress_readbody); int readbody(int sock, struct query *ctl, flag forward, int len); #if defined(HAVE_STDARG_H) void gen_send(int sock, const char *, ... ) diff --git a/fetchmailconf b/fetchmailconf index 86ab9445..88564c56 100755 --- a/fetchmailconf +++ b/fetchmailconf @@ -1236,6 +1236,13 @@ It is strongly recommended that you find a better POP3 server. The fetchmail FAQ includes pointers to good ones. """ + if string.find(greetline, "comcast.net") > 0: + warnings = warnings + """ +The Comcast Maillennium POP3 server only returns the first 80K of a long +message retrieved with TOP. Its response to RETR is normal, so use the +`fetchall' option. + +""" # Steve VanDevender <stevev@efn.org> writes: # The only system I have seen this happen with is cucipop-1.31 # under SunOS 4.1.4. cucipop-1.31 runs fine on at least Solaris @@ -306,6 +306,8 @@ static void capa_probe(int sock, struct query *ctl) if (outlevel >= O_VERBOSE) report(stdout, GT_("will idle after poll\n")); } + + peek_capable = (imap_version >= IMAP4); } static int imap_getauth(int sock, struct query *ctl, char *greeting) @@ -316,6 +318,15 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) flag did_stls = FALSE; #endif /* SSL_ENABLE */ + /* + * Assumption: expunges are cheap, so we want to do them + * after every message unless user said otherwise. + */ + if (NUM_SPECIFIED(ctl->expunge)) + expunge_period = NUM_VALUE_OUT(ctl->expunge); + else + expunge_period = 1; + capa_probe(sock, ctl); /* @@ -327,44 +338,6 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) preauth = FALSE; /* reset for the next session */ return(PS_SUCCESS); } - /* - * Time to authenticate the user. - * Try the protocol variants that don't require passwords first. - */ - ok = PS_AUTHFAIL; - -#ifdef GSSAPI - if ((ctl->server.authenticate == A_ANY - || ctl->server.authenticate == A_GSSAPI) - && strstr(capabilities, "AUTH=GSSAPI")) - if(ok = do_gssauth(sock, "AUTHENTICATE", ctl->server.truename, ctl->remotename)) - { - /* SASL cancellation of authentication */ - gen_send(sock, "*"); - if(ctl->server.authenticate != A_ANY) - return ok; - } - else - return ok; -#endif /* GSSAPI */ - -#ifdef KERBEROS_V4 - if ((ctl->server.authenticate == A_ANY - || ctl->server.authenticate == A_KERBEROS_V4 - || ctl->server.authenticate == A_KERBEROS_V5) - && strstr(capabilities, "AUTH=KERBEROS_V4")) - { - if ((ok = do_rfc1731(sock, "AUTHENTICATE", ctl->server.truename))) - { - /* SASL cancellation of authentication */ - gen_send(sock, "*"); - if(ctl->server.authenticate != A_ANY) - return ok; - } - else - return ok; - } -#endif /* KERBEROS_V4 */ #ifdef SSL_ENABLE if ((!ctl->sslproto || !strcmp(ctl->sslproto,"tls1")) @@ -408,16 +381,44 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) } #endif /* SSL_ENABLE */ - peek_capable = (imap_version >= IMAP4); - - /* - * Assumption: expunges are cheap, so we want to do them - * after every message unless user said otherwise. + /* + * Time to authenticate the user. + * Try the protocol variants that don't require passwords first. */ - if (NUM_SPECIFIED(ctl->expunge)) - expunge_period = NUM_VALUE_OUT(ctl->expunge); - else - expunge_period = 1; + ok = PS_AUTHFAIL; + +#ifdef GSSAPI + if ((ctl->server.authenticate == A_ANY + || ctl->server.authenticate == A_GSSAPI) + && strstr(capabilities, "AUTH=GSSAPI")) + if(ok = do_gssauth(sock, "AUTHENTICATE", ctl->server.truename, ctl->remotename)) + { + /* SASL cancellation of authentication */ + gen_send(sock, "*"); + if(ctl->server.authenticate != A_ANY) + return ok; + } + else + return ok; +#endif /* GSSAPI */ + +#ifdef KERBEROS_V4 + if ((ctl->server.authenticate == A_ANY + || ctl->server.authenticate == A_KERBEROS_V4 + || ctl->server.authenticate == A_KERBEROS_V5) + && strstr(capabilities, "AUTH=KERBEROS_V4")) + { + if ((ok = do_rfc1731(sock, "AUTHENTICATE", ctl->server.truename))) + { + /* SASL cancellation of authentication */ + gen_send(sock, "*"); + if(ctl->server.authenticate != A_ANY) + return ok; + } + else + return ok; + } +#endif /* KERBEROS_V4 */ /* * No such luck. OK, now try the variants that mask your password @@ -506,7 +507,13 @@ static int imap_getauth(int sock, struct query *ctl, char *greeting) imap_canonicalize(remotename, ctl->remotename, NAMELEN); imap_canonicalize(password, ctl->password, PASSWORDLEN); - strcpy(shroud, password); +#ifdef HAVE_SNPRINTF + snprintf(shroud, sizeof (shroud), "\"%s\"", password); +#else + strcpy(shroud, "\""); + strcat(shroud, password); + strcat(shroud, "\""); +#endif ok = gen_transact(sock, "LOGIN \"%s\" \"%s\"", remotename, password); shroud[0] = '\0'; #ifdef SSL_ENABLE @@ -224,6 +224,17 @@ static int capa_probe(sock) { int ok; +#if defined(GSSAPI) + has_gssapi = FALSE; +#endif /* defined(GSSAPI) */ +#if defined(KERBEROS_V4) || defined(KERBEROS_V5) + has_kerberos = FALSE; +#endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */ + has_cram = FALSE; +#ifdef OPIE_ENABLE + has_otp = FALSE; +#endif /* OPIE_ENABLE */ + ok = gen_transact(sock, "CAPA"); if (ok == PS_SUCCESS) { @@ -270,6 +281,20 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) flag did_stls = FALSE; #endif /* SSL_ENABLE */ +#if defined(GSSAPI) + has_gssapi = FALSE; +#endif /* defined(GSSAPI) */ +#if defined(KERBEROS_V4) || defined(KERBEROS_V5) + has_kerberos = FALSE; +#endif /* defined(KERBEROS_V4) || defined(KERBEROS_V5) */ + has_cram = FALSE; +#ifdef OPIE_ENABLE + has_otp = FALSE; +#endif /* OPIE_ENABLE */ +#ifdef SSL_ENABLE + has_ssl = FALSE; +#endif /* SSL_ENABLE */ + if (ctl->server.authenticate == A_SSH) { return PS_SUCCESS; } @@ -342,7 +367,7 @@ static int pop3_getauth(int sock, struct query *ctl, char *greeting) */ if (ctl->server.authenticate == A_ANY) { - if (capa_probe(sock) != PS_SUCCESS) + if ((ok = capa_probe(sock)) != PS_SUCCESS) /* we are in STAGE_GETAUTH! */ if (ok == PS_AUTHFAIL || /* Some servers directly close the socket. However, if we @@ -199,7 +199,7 @@ options {/* EMPTY */} (#.*)?\\?\n { prc_lineno++; } /* newline is ignored */ --?[0-9]+/[^a-zA-Z] { yylval.number = atoi(yytext); return NUMBER; } +-?[0-9]+ { yylval.number = atoi(yytext); return NUMBER; } [^=;:, \t\r\n]+ { char buf[MSGBUFSIZE]; @@ -73,6 +73,11 @@ int smtp_open(struct query *ctl) char *parsed_host = NULL; /* maybe it's time to close the socket in order to force delivery */ + if (last_smtp_ok > 0 && time((time_t *)NULL) - last_smtp_ok > mytimeout) + { + smtp_close(ctl, 1); + last_smtp_ok = 0; + } if (NUM_NONZERO(ctl->batchlimit)) { if (batchcount == ctl->batchlimit) smtp_close(ctl, 1); @@ -270,7 +275,7 @@ static int send_bouncemail(struct query *ctl, struct msgblk *msg, strcmp(msg->return_path, "<>") == 0 || strcasecmp(msg->return_path, md1) == 0 || strncasecmp(msg->return_path, md2, strlen(md2)) == 0) - return(FALSE); + return(TRUE); bounce_to = (run.bouncemail ? msg->return_path : run.postmaster); @@ -406,6 +411,8 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg) { int smtperr = atoi(smtp_response); char *responses[1]; + struct idlist *walk; + int found = 0; xalloca(responses[0], char *, strlen(smtp_response)+1); strcpy(responses[0], smtp_response); @@ -430,7 +437,15 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg) * messages, which are probably in English (none of the * MTAs I know about are internationalized). */ - if (str_find(&ctl->antispam, smtperr)) + for( walk = ctl->antispam; walk; walk = walk->next ) + if ( walk->val.status.num == smtperr ) + { + found=1; + break; + } + + /* if (str_find(&ctl->antispam, smtperr)) */ + if ( found ) { /* * SMTP listener explicitly refuses to deliver mail @@ -511,10 +526,12 @@ static int handle_smtp_report(struct query *ctl, struct msgblk *msg) default: /* bounce non-transient errors back to the sender */ if (smtperr >= 500 && smtperr <= 599) - if (send_bouncemail(ctl, msg, XMIT_ACCEPT, + { + send_bouncemail(ctl, msg, XMIT_ACCEPT, "General SMTP/ESMTP error.\r\n", - 1, responses)) - return(run.bouncemail ? PS_REFUSED : PS_TRANSIENT); + 1, responses); + return(PS_REFUSED); + } /* * We're going to end up here on 4xx errors, like: * @@ -847,6 +864,9 @@ static int open_smtp_sink(struct query *ctl, struct msgblk *msg, } else if (strchr(msg->return_path,'@') || strchr(msg->return_path,'!')) ap = msg->return_path; + /* in case Return-Path was "<>" we want to preserve that */ + else if (strcmp(msg->return_path,"<>") == 0) + ap = msg->return_path; else /* in case Return-Path existed but was local */ { if (is_dottedquad(ctl->server.truename)) @@ -87,7 +87,7 @@ static void SMTP_auth(int sock, char *username, char *password, char *buf) SockPrintf(sock, "AUTH CRAM-MD5\r\n"); SockRead(sock, smtp_response, sizeof(smtp_response) - 1); strncpy(tmp, smtp_response, sizeof(tmp)); - tmp[sizeof(tmp)-1] == '\0'; + tmp[sizeof(tmp)-1] = '\0'; if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */ SMTP_auth_error(sock, GT_("Server rejected the AUTH command.\n")); @@ -147,7 +147,7 @@ static void SMTP_auth(int sock, char *username, char *password, char *buf) SockPrintf(sock, "AUTH LOGIN\r\n"); SockRead(sock, smtp_response, sizeof(smtp_response) - 1); strncpy(tmp, smtp_response, sizeof(tmp)); - tmp[sizeof(tmp)-1] == '\0'; + tmp[sizeof(tmp)-1] = '\0'; if (strncmp(tmp, "334 ", 4)) { /* Server rejects AUTH */ SMTP_auth_error(sock, GT_("Server rejected the AUTH command.\n")); @@ -164,7 +164,7 @@ static void SMTP_auth(int sock, char *username, char *password, char *buf) SockPrintf(sock, "%s\r\n", b64buf); SockRead(sock, smtp_response, sizeof(smtp_response) - 1); strncpy(tmp, smtp_response, sizeof(tmp)); - tmp[sizeof(tmp)-1] == '\0'; + tmp[sizeof(tmp)-1] = '\0'; p = strchr(tmp, ' '); if (!p) { SMTP_auth_error(sock, GT_("Bad base64 reply from server.\n")); @@ -213,7 +213,7 @@ int SMTP_ehlo(int sock, const char *host, char *name, char *password, int *opt) *opt |= hp->value; if (strncmp(hp->name, "AUTH ", 5) == 0) strncpy(auth_response, smtp_response, sizeof(auth_response)); - auth_response[sizeof(auth_response)-1] == '\0'; + auth_response[sizeof(auth_response)-1] = '\0'; } if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && smtp_response[3] == ' ') { if (*opt & ESMTP_AUTH) @@ -327,6 +327,8 @@ int SMTP_eom(int sock) return ok; } +time_t last_smtp_ok = 0; + int SMTP_ok(int sock) /* returns status of SMTP connection */ { @@ -360,6 +362,8 @@ int SMTP_ok(int sock) return SM_UNRECOVERABLE; } + last_smtp_ok = time((time_t *) NULL); + if ((smtp_response[0] == '1' || smtp_response[0] == '2' || smtp_response[0] == '3') && smtp_response[3] == ' ') return SM_OK; @@ -7,6 +7,8 @@ #ifndef _POPSMTP_ #define _POPSMTP_ +#include <time.h> + #define SMTPBUFSIZE 256 /* SMTP error values */ @@ -21,6 +23,8 @@ #define ESMTP_ATRN 0x08 /* used with ODMR, RFC 2645 */ #define ESMTP_AUTH 0x10 +extern time_t last_smtp_ok; + void SMTP_setmode(char); int SMTP_helo(int socket,const char *host); int SMTP_ehlo(int socket,const char *host, char *name, char *passwd, int *opt); @@ -637,8 +637,10 @@ int SockRead(int sock, char *buf, int len) } while (!newline && len); *bp = '\0'; + +#ifdef FORCE_STUFFING /* too ugly to live -- besides, there's IMAP */ /* OK, very weird hack coming up here: - * When POP and IMAP servers send us a message, they're supposed to + * When POP3 servers send us a message, they're supposed to * terminate the message with a line containing only a dot. To protect * against lines in the real message that might contain only a dot, * they're supposed to preface any line that starts with a dot with @@ -675,6 +677,7 @@ int SockRead(int sock, char *buf, int len) buf[0] = '.'; bp++; } +#endif /* FORCE_STUFFING */ return bp - buf; } @@ -973,7 +976,7 @@ int SSLOpen(int sock, char *mycert, char *mykey, char *myproto, int certck, char SSL_set_fd(_ssl_context[sock], sock); - if(SSL_connect(_ssl_context[sock]) == -1) { + if(SSL_connect(_ssl_context[sock]) < 1) { ERR_print_errors_fp(stderr); return(-1); } @@ -40,7 +40,7 @@ extern char *strstr(); /* needed on sysV68 R3V7.1. */ int mytimeout; /* value of nonreponse timeout */ int suppress_tags; /* emit tags? */ -char shroud[PASSWORDLEN*2+1]; /* string to shroud in debug output */ +char shroud[PASSWORDLEN*2+3]; /* string to shroud in debug output */ struct msgblk msgblk; char tag[TAGLEN]; @@ -352,13 +352,15 @@ int readheaders(int sock, long fetchlen, long reallen, struct query *ctl, - int num) + int num, + flag *suppress_readbody) /* read message headers and ship to SMTP or MDA */ /* sock: to which the server is connected */ /* fetchlen: length of message according to fetch response */ /* reallen: length of message according to getsizes */ /* ctl: query control record */ /* num: index of message */ +/* suppress_readbody: whether call to readbody() should be supressed */ { struct addrblk { @@ -379,13 +381,13 @@ int readheaders(int sock, int n, linelen, oldlen, ch, remaining, skipcount; struct idlist *idp; flag no_local_matches = FALSE; - flag headers_ok, has_nuls; + flag has_nuls; int olderrs, good_addresses, bad_addresses; - int retain_mail = 0; + int retain_mail = 0, refuse_mail = 0; flag already_has_return_path = FALSE; sizeticker = 0; - has_nuls = headers_ok = FALSE; + has_nuls = FALSE; msgblk.return_path[0] = '\0'; olderrs = ctl->errcount; @@ -419,7 +421,7 @@ int readheaders(int sock, for (remaining = fetchlen; remaining > 0 || protocol->delimited; ) { - char *line; + char *line, *rline; int overlong = FALSE; line = xmalloc(sizeof(buf)); @@ -446,7 +448,13 @@ int readheaders(int sock, */ if ( n && buf[n-1] != '\n' ) { overlong = TRUE; - line = realloc(line, linelen); + rline = (char *) realloc(line, linelen); + if (rline == NULL) + { + free (line); + return(PS_IOERR); + } + line = rline; memcpy(line + linelen - n, buf, n); ch = ' '; /* So the next iteration starts */ continue; @@ -458,7 +466,13 @@ int readheaders(int sock, if (ctl->forcecr && buf[n-1] == '\n' && (n == 1 || buf[n-2] != '\r')) { char * tcp; - line = (char *) realloc(line, linelen + 2); + rline = (char *) realloc(line, linelen + 2); + if (rline == NULL) + { + free (line); + return(PS_IOERR); + } + line = rline; memcpy(line + linelen - n, buf, n - 1); tcp = line + linelen - 1; *tcp++ = '\r'; @@ -469,15 +483,21 @@ int readheaders(int sock, } else { - line = (char *) realloc(line, linelen + 1); + rline = (char *) realloc(line, linelen + 1); + if (rline == NULL) + { + free (line); + return(PS_IOERR); + } + line = rline; memcpy(line + linelen - n, buf, n + 1); } /* check for end of headers */ if (end_of_header(line)) { - headers_ok = TRUE; - has_nuls = (linelen != strlen(line)); + if (linelen != strlen (line)) + has_nuls = TRUE; free(line); goto process_headers; } @@ -489,8 +509,13 @@ int readheaders(int sock, */ if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1)) { - headers_ok = FALSE; - has_nuls = (linelen != strlen(line)); + if (outlevel > O_SILENT) + report(stdout, + GT_("message delimiter found while scanning headers\n")); + if (suppress_readbody) + *suppress_readbody = TRUE; + if (linelen != strlen (line)) + has_nuls = TRUE; free(line); goto process_headers; } @@ -499,17 +524,18 @@ int readheaders(int sock, * At least one brain-dead website (netmind.com) is known to * send out robotmail that's missing the RFC822 delimiter blank * line before the body! Without this check fetchmail segfaults. - * With it, we treat such messages as though they had the missing - * blank line. + * With it, we treat such messages as spam and refuse them. */ - if (!isspace(line[0]) && !strchr(line, ':')) + if (!refuse_mail && !isspace(line[0]) && !strchr(line, ':')) { - headers_ok = FALSE; - has_nuls = (linelen != strlen(line)); + if (linelen != strlen (line)) + has_nuls = TRUE; if (outlevel > O_SILENT) report(stdout, GT_("incorrect header line found while scanning headers\n")); - goto process_headers; + if (outlevel >= O_VERBOSE) + report (stdout, GT_("line: %s"), line); + refuse_mail = 1; } /* check for RFC822 continuations */ @@ -550,8 +576,16 @@ int readheaders(int sock, } + /* skip processing if we are going to retain or refuse this mail */ + if (retain_mail || refuse_mail) + { + free(line); + continue; + } + /* we see an ordinary (non-header, non-message-delimiter line */ - has_nuls = (linelen != strlen(line)); + if (linelen != strlen (line)) + has_nuls = TRUE; /* save the message's ID, we may use it for killing duplicates later */ if (MULTIDROP(ctl) && !strncasecmp(line, "Message-ID:", 11)) @@ -691,6 +725,8 @@ int readheaders(int sock, if ((already_has_return_path==FALSE) && !strncasecmp("Return-Path:", line, 12) && (cp = nxtaddr(line))) { already_has_return_path = TRUE; + if (cp[0]=='\0') /* nxtaddr() strips the brackets... */ + cp="<>"; strncpy(msgblk.return_path, cp, sizeof(msgblk.return_path)); msgblk.return_path[sizeof(msgblk.return_path)-1] = '\0'; if (!ctl->mda) { @@ -701,9 +737,10 @@ int readheaders(int sock, if (!msgblk.headers) { - oldlen = strlen(line); + oldlen = linelen; msgblk.headers = xmalloc(oldlen + 1); - (void) strcpy(msgblk.headers, line); + (void) memcpy(msgblk.headers, line, linelen); + msgblk.headers[oldlen] = '\0'; free(line); line = msgblk.headers; } @@ -712,14 +749,15 @@ int readheaders(int sock, char *newhdrs; int newlen; - newlen = oldlen + strlen(line); + newlen = oldlen + linelen; newhdrs = (char *) realloc(msgblk.headers, newlen + 1); if (newhdrs == NULL) { free(line); return(PS_IOERR); } msgblk.headers = newhdrs; - strcpy(msgblk.headers + oldlen, line); + memcpy(msgblk.headers + oldlen, line, linelen); + msgblk.headers[newlen] = '\0'; free(line); line = msgblk.headers + oldlen; oldlen = newlen; @@ -831,6 +869,8 @@ int readheaders(int sock, msgblk.headers = NULL; return(PS_RETAINED); } + if (refuse_mail) + return(PS_REFUSED); /* * When mail delivered to a multidrop mailbox on the server is * addressed to multiple people on the client machine, there will @@ -1255,14 +1295,6 @@ int readheaders(int sock, *cp++ = '\0'; stuffline(ctl, buf); - if (!headers_ok) - { - if (outlevel > O_SILENT) - report(stdout, - GT_("message delimiter found while scanning headers\n")); - return(PS_TRUNCATED); - } - return(PS_SUCCESS); } @@ -1390,7 +1422,7 @@ static void enshroud(char *buf) char *sp; sp = cp + strlen(shroud); - *cp = '*'; + *cp++ = '*'; while (*sp) *cp++ = *sp++; *cp = '\0'; @@ -1457,7 +1489,10 @@ int size; /* length of buffer */ set_timeout(0); phase = oldphase; if(isidletimeout()) + { + resetidletimeout(); return(PS_IDLETIMEOUT); + } else return(PS_SOCKET); } @@ -135,19 +135,16 @@ void initialize_saved_lists(struct query *hostlist, const char *idfile) * espescially if the POP server returns an X-UIDL header * instead of a Message-ID, as GMX's (www.gmx.net) POP3 * StreamProxy V1.0 does. + * + * this is one other trick. The userhost part + * may contain ' ' in the user part, at least in + * the lotus notes case. + * So we start looking for the '@' after which the + * host will follow with the ' ' seperator finaly id. */ - if ((id = strchr(user, ' ')) != NULL ) + if ((delimp1 = strchr(user, '@')) != NULL && + (id = strchr(delimp1,' ')) != NULL) { - - /* - * this is one other trick. The userhost part - * may contain ' ' in the user part, at least in - * the lotus notes case. - * So we start looking for the '@' after which the - * host will follow with the ' ' seperator finaly id. - */ - delimp1 = strchr(user, '@'); - id = strchr(delimp1,' '); for (delimp1 = id; delimp1 >= user; delimp1--) if ((*delimp1 != ' ') && (*delimp1 != '\t')) break; |