X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/e468b87f91f26e66a8cde087c1a9c89c67b96d12..1e91d0eb709bbceac93ad9418ba453d74d4221b0:/lib-src/pop.c diff --git a/lib-src/pop.c b/lib-src/pop.c index 9fcbe4b370..9eabbd2041 100644 --- a/lib-src/pop.c +++ b/lib-src/pop.c @@ -1,14 +1,15 @@ /* pop.c: client routines for talking to a POP3-protocol post-office server Copyright (C) 1991, 1993, 1996, 1997, 1999, 2001, 2002, 2003, 2004, - 2005, 2006, 2007 Free Software Foundation, Inc. - Written by Jonathan Kamens, jik@security.ov.com. + 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + +Author: Jonathan Kamens This file is part of GNU Emacs. -GNU Emacs is free software; you can redistribute it and/or modify +GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,12 +17,10 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ +along with GNU Emacs. If not, see . */ + #ifdef HAVE_CONFIG_H -#define NO_SHORTNAMES /* Tell config not to load remap.h */ #include #else #define MAIL_USE_POP @@ -109,24 +108,16 @@ extern int h_errno; #endif #endif -#ifndef __P -# ifdef __STDC__ -# define __P(a) a -# else -# define __P(a) () -# endif /* __STDC__ */ -#endif /* ! __P */ - -static int socket_connection __P((char *, int)); -static int pop_getline __P((popserver, char **)); -static int sendline __P((popserver, char *)); -static int fullwrite __P((int, char *, int)); -static int getok __P((popserver)); +static int socket_connection (char *, int); +static int pop_getline (popserver, char **); +static int sendline (popserver, const char *); +static int fullwrite (int, char *, int); +static int getok (popserver); #if 0 -static int gettermination __P((popserver)); +static int gettermination (popserver); #endif -static void pop_trash __P((popserver)); -static char *find_crlf __P((char *, int)); +static void pop_trash (popserver); +static char *find_crlf (char *, int); #define ERROR_MAX 160 /* a pretty arbitrary size, but needs to be bigger than the original @@ -175,11 +166,7 @@ int pop_debug = 0; * explanation of the error. */ popserver -pop_open (host, username, password, flags) - char *host; - char *username; - char *password; - int flags; +pop_open (char *host, char *username, char *password, int flags) { int sock; popserver server; @@ -346,12 +333,10 @@ pop_open (host, username, password, flags) * connection impossible. */ int -pop_stat (server, count, size) - popserver server; - int *count; - int *size; +pop_stat (popserver server, int *count, int *size) { char *fromserver; + char *end_ptr; if (server->in_multi) { @@ -377,18 +362,26 @@ pop_stat (server, count, size) return (-1); } - *count = atoi (&fromserver[4]); - - fromserver = index (&fromserver[4], ' '); - if (! fromserver) + errno = 0; + *count = strtol (&fromserver[4], &end_ptr, 10); + /* Check validity of string-to-integer conversion. */ + if (fromserver + 4 == end_ptr || *end_ptr != ' ' || errno) { - strcpy (pop_error, - "Badly formatted response from server in pop_stat"); + strcpy (pop_error, "Unexpected response from POP server in pop_stat"); pop_trash (server); return (-1); } - *size = atoi (fromserver + 1); + fromserver = end_ptr; + + errno = 0; + *size = strtol (fromserver + 1, &end_ptr, 10); + if (fromserver + 1 == end_ptr || errno) + { + strcpy (pop_error, "Unexpected response from POP server in pop_stat"); + pop_trash (server); + return (-1); + } return (0); } @@ -413,11 +406,7 @@ pop_stat (server, count, size) * connection impossible. */ int -pop_list (server, message, IDs, sizes) - popserver server; - int message; - int **IDs; - int **sizes; +pop_list (popserver server, int message, int **IDs, int **sizes) { int how_many, i; char *fromserver; @@ -476,7 +465,7 @@ pop_list (server, message, IDs, sizes) return (-1); } (*IDs)[0] = atoi (&fromserver[4]); - fromserver = index (&fromserver[4], ' '); + fromserver = strchr (&fromserver[4], ' '); if (! fromserver) { strcpy (pop_error, @@ -507,7 +496,7 @@ pop_list (server, message, IDs, sizes) return (-1); } (*IDs)[i] = atoi (fromserver); - fromserver = index (fromserver, ' '); + fromserver = strchr (fromserver, ' '); if (! fromserver) { strcpy (pop_error, @@ -559,11 +548,7 @@ pop_list (server, message, IDs, sizes) * Side effects: May kill connection on error. */ int -pop_retrieve (server, message, markfrom, msg_buf) - popserver server; - int message; - int markfrom; - char **msg_buf; +pop_retrieve (popserver server, int message, int markfrom, char **msg_buf) { int *IDs, *sizes, bufsize, fromcount = 0, cp = 0; char *ptr, *fromserver; @@ -627,7 +612,7 @@ pop_retrieve (server, message, markfrom, msg_buf) } ptr[cp++] = '>'; } - bcopy (fromserver, &ptr[cp], ret); + memcpy (&ptr[cp], fromserver, ret); cp += ret; ptr[cp++] = '\n'; } @@ -637,10 +622,7 @@ pop_retrieve (server, message, markfrom, msg_buf) } int -pop_retrieve_first (server, message, response) - popserver server; - int message; - char **response; +pop_retrieve_first (popserver server, int message, char **response) { sprintf (pop_error, "RETR %d", message); return (pop_multi_first (server, pop_error, response)); @@ -655,25 +637,19 @@ pop_retrieve_first (server, message, response) */ int -pop_retrieve_next (server, line) - popserver server; - char **line; +pop_retrieve_next (popserver server, char **line) { return (pop_multi_next (server, line)); } int -pop_retrieve_flush (server) - popserver server; +pop_retrieve_flush (popserver server) { return (pop_multi_flush (server)); } int -pop_top_first (server, message, lines, response) - popserver server; - int message, lines; - char **response; +pop_top_first (popserver server, int message, int lines, char **response) { sprintf (pop_error, "TOP %d %d", message, lines); return (pop_multi_first (server, pop_error, response)); @@ -688,25 +664,19 @@ pop_top_first (server, message, lines, response) */ int -pop_top_next (server, line) - popserver server; - char **line; +pop_top_next (popserver server, char **line) { return (pop_multi_next (server, line)); } int -pop_top_flush (server) - popserver server; +pop_top_flush (popserver server) { return (pop_multi_flush (server)); } int -pop_multi_first (server, command, response) - popserver server; - char *command; - char **response; +pop_multi_first (popserver server, const char *command, char **response) { if (server->in_multi) { @@ -749,9 +719,7 @@ pop_multi_first (server, command, response) 0, LINE is set to null. */ int -pop_multi_next (server, line) - popserver server; - char **line; +pop_multi_next (popserver server, char **line) { char *fromserver; int ret; @@ -789,8 +757,7 @@ pop_multi_next (server, line) } int -pop_multi_flush (server) - popserver server; +pop_multi_flush (popserver server) { char *line; int ret; @@ -821,9 +788,7 @@ pop_multi_flush (server) * otherwise. */ int -pop_delete (server, message) - popserver server; - int message; +pop_delete (popserver server, int message) { if (server->in_multi) { @@ -853,8 +818,7 @@ pop_delete (server, message) * Side effects: Closes connection on error. */ int -pop_noop (server) - popserver server; +pop_noop (popserver server) { if (server->in_multi) { @@ -883,8 +847,7 @@ pop_noop (server) * Side effects: Closes the connection on error. */ int -pop_last (server) - popserver server; +pop_last (popserver server) { char *fromserver; @@ -913,7 +876,17 @@ pop_last (server) } else { - return (atoi (&fromserver[4])); + char *end_ptr; + int count; + errno = 0; + count = strtol (&fromserver[4], &end_ptr, 10); + if (fromserver + 4 == end_ptr || errno) + { + strcpy (pop_error, "Unexpected response from server in pop_last"); + pop_trash (server); + return (-1); + } + return count; } } @@ -931,8 +904,7 @@ pop_last (server) * Side effects: Closes the connection on error. */ int -pop_reset (server) - popserver server; +pop_reset (popserver server) { if (pop_retrieve_flush (server)) { @@ -960,8 +932,7 @@ pop_reset (server) * function is called, even if an error occurs. */ int -pop_quit (server) - popserver server; +pop_quit (popserver server) { int ret = 0; @@ -980,8 +951,7 @@ pop_quit (server) close (server->file); } - if (server->buffer) - free (server->buffer); + free (server->buffer); free ((char *) server); return (ret); @@ -1006,16 +976,21 @@ static int have_winsock = 0; * into pop_error. */ static int -socket_connection (host, flags) - char *host; - int flags; +socket_connection (char *host, int flags) { +#ifdef HAVE_GETADDRINFO + struct addrinfo *res, *it; + struct addrinfo hints; + int ret; +#else /* !HAVE_GETADDRINFO */ struct hostent *hostent; +#endif struct servent *servent; struct sockaddr_in addr; char found_port = 0; - char *service; + const char *service; int sock; + char *realhost; #ifdef KERBEROS #ifdef KERBEROS5 krb5_error_code rem; @@ -1031,11 +1006,11 @@ socket_connection (host, flags) CREDENTIALS cred; Key_schedule schedule; int rem; - char *realhost; #endif /* KERBEROS5 */ #endif /* KERBEROS */ int try_count = 0; + int connect_ok; #ifdef WINDOWSNT { @@ -1045,7 +1020,7 @@ socket_connection (host, flags) } #endif - bzero ((char *) &addr, sizeof (addr)); + memset (&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; /** "kpop" service is never used: look for 20060515 to see why **/ @@ -1097,6 +1072,45 @@ socket_connection (host, flags) } +#ifdef HAVE_GETADDRINFO + memset (&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_INET; + do + { + ret = getaddrinfo (host, service, &hints, &res); + try_count++; + if (ret != 0 && (ret != EAI_AGAIN || try_count == 5)) + { + strcpy (pop_error, "Could not determine POP server's address"); + return (-1); + } + } while (ret != 0); + + if (ret == 0) + { + it = res; + while (it) + { + if (it->ai_addrlen == sizeof (addr)) + { + struct sockaddr_in *in_a = (struct sockaddr_in *) it->ai_addr; + memcpy (&addr.sin_addr, &in_a->sin_addr, sizeof (addr.sin_addr)); + if (! connect (sock, (struct sockaddr *) &addr, sizeof (addr))) + break; + } + it = it->ai_next; + } + connect_ok = it != NULL; + if (connect_ok) + { + realhost = alloca (strlen (it->ai_canonname) + 1); + strcpy (realhost, it->ai_canonname); + } + freeaddrinfo (res); + } +#else /* !HAVE_GETADDRINFO */ do { hostent = gethostbyname (host); @@ -1110,16 +1124,23 @@ socket_connection (host, flags) while (*hostent->h_addr_list) { - bcopy (*hostent->h_addr_list, (char *) &addr.sin_addr, - hostent->h_length); + memcpy (&addr.sin_addr, *hostent->h_addr_list, hostent->h_length); if (! connect (sock, (struct sockaddr *) &addr, sizeof (addr))) break; hostent->h_addr_list++; } + connect_ok = *hostent->h_addr_list != NULL; + if (! connect_ok) + { + realhost = alloca (strlen (hostent->h_name) + 1); + strcpy (realhost, hostent->h_name); + } + +#endif /* !HAVE_GETADDRINFO */ #define CONNECT_ERROR "Could not connect to POP server: " - if (! *hostent->h_addr_list) + if (! connect_ok) { CLOSESOCKET (sock); strcpy (pop_error, CONNECT_ERROR); @@ -1130,6 +1151,7 @@ socket_connection (host, flags) } #ifdef KERBEROS + #define KRB_ERROR "Kerberos error connecting to POP server: " if (! (flags & POP_NO_KERBEROS)) { @@ -1157,7 +1179,7 @@ socket_connection (host, flags) if (rem = krb5_cc_get_principal (kcontext, ccdef, &client)) goto krb5error; - for (cp = hostent->h_name; *cp; cp++) + for (cp = realhost; *cp; cp++) { if (isupper (*cp)) { @@ -1165,7 +1187,7 @@ socket_connection (host, flags) } } - if (rem = krb5_sname_to_principal (kcontext, hostent->h_name, + if (rem = krb5_sname_to_principal (kcontext, realhost, POP_SERVICE, FALSE, &server)) goto krb5error; @@ -1181,11 +1203,12 @@ socket_connection (host, flags) krb5_free_principal (kcontext, server); if (rem) { + strcpy (pop_error, KRB_ERROR); + strncat (pop_error, error_message (rem), + ERROR_MAX - sizeof (KRB_ERROR)); +#if defined HAVE_KRB5_ERROR_TEXT if (err_ret && err_ret->text.length) { - strcpy (pop_error, KRB_ERROR); - strncat (pop_error, error_message (rem), - ERROR_MAX - sizeof (KRB_ERROR)); strncat (pop_error, " [server says '", ERROR_MAX - strlen (pop_error) - 1); strncat (pop_error, err_ret->text.data, @@ -1194,12 +1217,17 @@ socket_connection (host, flags) strncat (pop_error, "']", ERROR_MAX - strlen (pop_error) - 1); } - else +#elif defined HAVE_KRB5_ERROR_E_TEXT + if (err_ret && err_ret->e_text && strlen(*err_ret->e_text)) { - strcpy (pop_error, KRB_ERROR); - strncat (pop_error, error_message (rem), - ERROR_MAX - sizeof (KRB_ERROR)); + strncat (pop_error, " [server says '", + ERROR_MAX - strlen (pop_error) - 1); + strncat (pop_error, *err_ret->e_text, + ERROR_MAX - strlen (pop_error) - 1); + strncat (pop_error, "']", + ERROR_MAX - strlen (pop_error) - 1); } +#endif if (err_ret) krb5_free_error (kcontext, err_ret); krb5_auth_con_free (kcontext, auth_context); @@ -1210,7 +1238,6 @@ socket_connection (host, flags) } #else /* ! KERBEROS5 */ ticket = (KTEXT) malloc (sizeof (KTEXT_ST)); - realhost = strdup (hostent->h_name); rem = krb_sendauth (0L, sock, ticket, "pop", realhost, (char *) krb_realmofhost (realhost), (unsigned long) 0, &msg_data, &cred, schedule, @@ -1218,7 +1245,6 @@ socket_connection (host, flags) (struct sockaddr_in *) 0, "KPOPV0.1"); free ((char *) ticket); - free (realhost); if (rem != KSUCCESS) { strcpy (pop_error, KRB_ERROR); @@ -1258,9 +1284,7 @@ socket_connection (host, flags) * THE RETURNED LINE MAY CONTAIN EMBEDDED NULLS! */ static int -pop_getline (server, line) - popserver server; - char **line; +pop_getline (popserver server, char **line) { #define GETLINE_ERROR "Error reading from server: " @@ -1292,8 +1316,8 @@ pop_getline (server, line) } else { - bcopy (server->buffer + server->buffer_index, - server->buffer, server->data); + memmove (server->buffer, server->buffer + server->buffer_index, + server->data); /* Record the fact that we've searched the data already in the buffer for a CRLF, so that when we search below, we don't have to search the same data twice. There's a "- @@ -1390,9 +1414,7 @@ pop_getline (server, line) * Side effects: Closes the connection on error. */ static int -sendline (server, line) - popserver server; - char *line; +sendline (popserver server, const char *line) { #define SENDLINE_ERROR "Error writing to POP server: " int ret; @@ -1439,10 +1461,7 @@ sendline (server, line) * Return value: Same as write. Pop_error is not set. */ static int -fullwrite (fd, buf, nbytes) - int fd; - char *buf; - int nbytes; +fullwrite (int fd, char *buf, int nbytes) { char *cp; int ret = 0; @@ -1472,8 +1491,7 @@ fullwrite (fd, buf, nbytes) * Side effects: On failure, may make the connection unusable. */ static int -getok (server) - popserver server; +getok (popserver server) { char *fromline; @@ -1544,8 +1562,7 @@ gettermination (server) * since the last pop_reset) may be lost. */ void -pop_close (server) - popserver server; +pop_close (popserver server) { pop_trash (server); free ((char *) server); @@ -1557,12 +1574,11 @@ pop_close (server) * Function: pop_trash * * Purpose: Like pop_close or pop_quit, but doesn't deallocate the - * memory associated with the server. It is legal to call + * memory associated with the server. It is valid to call * pop_close or pop_quit after this function has been called. */ static void -pop_trash (server) - popserver server; +pop_trash (popserver server) { if (server->file >= 0) { @@ -1594,9 +1610,7 @@ pop_trash (server) null, or 0 if it does not contain one. */ static char * -find_crlf (in_string, len) - char *in_string; - int len; +find_crlf (char *in_string, int len) { while (len--) {