Mercurial > hg > xemacs-beta
changeset 3650:bdfcf05f635b
[xemacs-hg @ 2006-11-01 20:55:09 by adrian]
From: Jerry James <james@xemacs.org>
Subject: [PATCH 21.5] POP sync
To: XEmacs Patches <xemacs-patches@xemacs.org>
Date: Fri, 11 Aug 2006 12:24:54 -0600
Message-ID: <m3k65fb05l.fsf@jerrypc.cs.usu.edu>
author | adrian |
---|---|
date | Wed, 01 Nov 2006 20:55:14 +0000 |
parents | 60b01bffb67f |
children | edbb1ff43fe0 |
files | lib-src/pop.c lib-src/pop.h lisp/ChangeLog |
diffstat | 3 files changed, 180 insertions(+), 113 deletions(-) [+] |
line wrap: on
line diff
--- a/lib-src/pop.c Wed Nov 01 20:41:09 2006 +0000 +++ b/lib-src/pop.c Wed Nov 01 20:55:14 2006 +0000 @@ -1,5 +1,6 @@ /* pop.c: client routines for talking to a POP3-protocol post-office server - Copyright (c) 1991, 1993, 1996 Free Software Foundation, Inc. + Copyright (C) 1991, 1993, 1996, 1997, 1999, 2002, 2003, 2004, + 2005, 2006 Free Software Foundation, Inc. Copyright (C) 2001 Ben Wing. Written by Jonathan Kamens, jik@security.ov.com. @@ -17,8 +18,10 @@ You should have received a copy of the GNU General Public License along with XEmacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* Synched up with: FSF 22.0.50. */ #ifdef HAVE_CONFIG_H #define NO_SHORTNAMES /* Tell config not to load remap.h */ @@ -96,7 +99,7 @@ #ifdef KERBEROS #ifndef KRB5 extern int krb_sendauth (/* long, int, KTEXT, char *, char *, char *, - unsigned long, MSG_DAT *, CREDENTIALS *, Key_schedule, + u_long, MSG_DAT *, CREDENTIALS *, Key_schedule, struct sockaddr_in *, struct sockaddr_in *, char * */); extern char *krb_realmofhost (/* char * */); @@ -110,7 +113,7 @@ #endif static int socket_connection (char *, int); -static char *pop_getline (popserver); +static int pop_getline (popserver, char **); static int sendline (popserver, char *); static int fullwrite (int, char *, int); static int getok (popserver); @@ -118,9 +121,11 @@ static int gettermination (popserver); #endif static void pop_trash (popserver); -static char *find_crlf (char *); +static char *find_crlf (char *, int); -#define ERROR_MAX 80 /* a pretty arbitrary size */ +#define ERROR_MAX 160 /* a pretty arbitrary size, but needs + to be bigger than the original + value of 80 */ #define POP_PORT 110 #define KPOP_PORT 1109 #if defined(WIN32_NATIVE) || defined(CYGWIN) @@ -130,7 +135,7 @@ #endif #ifdef KERBEROS #ifdef KRB5 -#define KPOP_SERVICE "k5pop"; +#define KPOP_SERVICE "k5pop" #else #define KPOP_SERVICE "kpop" #endif @@ -356,7 +361,7 @@ return (-1); } - if (sendline (server, "STAT") || (! (fromserver = pop_getline (server)))) + if (sendline (server, "STAT") || (pop_getline (server, &fromserver) < 0)) return (-1); if (strncmp (fromserver, "+OK ", 4)) @@ -448,7 +453,7 @@ free ((char *) *sizes); return (-1); } - if (! (fromserver = pop_getline (server))) + if (pop_getline (server, &fromserver) < 0) { free ((char *) *IDs); free ((char *) *sizes); @@ -493,7 +498,7 @@ } for (i = 0; i < how_many; i++) { - if (pop_multi_next (server, &fromserver)) + if (pop_multi_next (server, &fromserver) <= 0) { free ((char *) *IDs); free ((char *) *sizes); @@ -512,7 +517,7 @@ } (*sizes)[i] = atoi (fromserver); } - if (pop_multi_next (server, &fromserver)) + if (pop_multi_next (server, &fromserver) < 0) { free ((char *) *IDs); free ((char *) *sizes); @@ -542,14 +547,17 @@ * markfrom * If true, then mark the string "From " at the beginning * of lines with '>'. + * msg_buf Output parameter to which a buffer containing the + * message is assigned. * - * Return value: A string pointing to the message, if successful, or - * null with pop_error set if not. + * Return value: The number of bytes in msg_buf, which may contain + * embedded nulls, not including its final null, or -1 on error + * with pop_error set. * * Side effects: May kill connection on error. */ -char * -pop_retrieve (popserver server, int message, int markfrom) +int +pop_retrieve (popserver server, int message, int markfrom, char **msg_buf) { int *IDs, *sizes, bufsize, fromcount = 0, cp = 0; char *ptr, *fromserver; @@ -562,11 +570,11 @@ } if (pop_list (server, message, &IDs, &sizes)) - return (0); + return (-1); if (pop_retrieve_first (server, message, &fromserver)) { - return (0); + return (-1); } /* @@ -584,17 +592,16 @@ { strcpy (pop_error, "Out of memory in pop_retrieve"); pop_retrieve_flush (server); - return (0); + return (-1); } - while (! (ret = pop_retrieve_next (server, &fromserver))) + while ((ret = pop_retrieve_next (server, &fromserver)) >= 0) { - int linesize; - if (! fromserver) { ptr[cp] = '\0'; - return (ptr); + *msg_buf = ptr; + return (cp); } if (markfrom && fromserver[0] == 'F' && fromserver[1] == 'r' && fromserver[2] == 'o' && fromserver[3] == 'm' && @@ -608,25 +615,19 @@ { strcpy (pop_error, "Out of memory in pop_retrieve"); pop_retrieve_flush (server); - return (0); + return (-1); } fromcount = 0; } ptr[cp++] = '>'; } - linesize = strlen (fromserver); - memcpy (&ptr[cp], fromserver, linesize); - cp += linesize; + memcpy (&ptr[cp], fromserver, ret); + cp += ret; ptr[cp++] = '\n'; } - if (ret) - { - free (ptr); - /* return (0); */ - } - /* This function used to fall off the end, but that doesn't make any sense */ - return (0); + free (ptr); + return (-1); } int @@ -636,6 +637,14 @@ return (pop_multi_first (server, pop_error, response)); } +/* + Returns a negative number on error, 0 to indicate that the data has + all been read (i.e., the server has returned a "." termination + line), or a positive number indicating the number of bytes in the + returned buffer (which is null-terminated and may contain embedded + nulls, but the returned bytecount doesn't include the final null). + */ + int pop_retrieve_next (popserver server, char **line) { @@ -655,6 +664,14 @@ return (pop_multi_first (server, pop_error, response)); } +/* + Returns a negative number on error, 0 to indicate that the data has + all been read (i.e., the server has returned a "." termination + line), or a positive number indicating the number of bytes in the + returned buffer (which is null-terminated and may contain embedded + nulls, but the returned bytecount doesn't include the final null). + */ + int pop_top_next (popserver server, char **line) { @@ -677,7 +694,7 @@ return (-1); } - if (sendline (server, command) || (! (*response = pop_getline (server)))) + if (sendline (server, command) || (pop_getline (server, response) < 0)) { return (-1); } @@ -701,10 +718,20 @@ } } +/* + Read the next line of data from SERVER and place a pointer to it + into LINE. Return -1 on error, 0 if there are no more lines to read + (i.e., the server has returned a line containing only "."), or a + positive number indicating the number of bytes in the LINE buffer + (not including the final null). The data in that buffer may contain + embedded nulls, but does not contain the final CRLF. When returning + 0, LINE is set to null. */ + int pop_multi_next (popserver server, char **line) { char *fromserver; + int ret; if (! server->in_multi) { @@ -712,8 +739,7 @@ return (-1); } - fromserver = pop_getline (server); - if (! fromserver) + if ((ret = pop_getline (server, &fromserver)) < 0) { return (-1); } @@ -729,13 +755,13 @@ else { *line = fromserver + 1; - return (0); + return (ret - 1); } } else { *line = fromserver; - return (0); + return (ret); } } @@ -743,21 +769,22 @@ pop_multi_flush (popserver server) { char *line; + int ret; if (! server->in_multi) { return (0); } - while (! pop_multi_next (server, &line)) + while ((ret = pop_multi_next (server, &line))) { - if (! line) + if (ret < 0) { - return (0); + return (-1); } } - return (-1); + return (0); } /* Function: pop_delete @@ -844,7 +871,7 @@ if (sendline (server, "LAST")) return (-1); - if (! (fromserver = pop_getline (server))) + if (pop_getline (server, &fromserver) < 0) return (-1); if (! strncmp (fromserver, "-ERR", 4)) @@ -968,6 +995,8 @@ #ifdef KERBEROS #ifdef KRB5 krb5_error_code rem; + krb5_context kcontext = 0; + krb5_auth_context auth_context = 0; krb5_ccache ccdef; krb5_principal client, server; krb5_error *err_ret; @@ -978,6 +1007,7 @@ CREDENTIALS cred; Key_schedule schedule; int rem; + char *realhost; #endif /* KRB5 */ #endif /* KERBEROS */ @@ -991,19 +1021,6 @@ } #endif - do - { - hostent = gethostbyname (host); - try_count++; - if ((! hostent) - && ((h_errno != TRY_AGAIN) || (try_count == 5)) - ) - { - strcpy (pop_error, "Could not determine POP server's address"); - return (-1); - } - } while (! hostent); - memset (&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; @@ -1042,18 +1059,29 @@ } } -#define SOCKET_ERROR "Could not create socket for POP connection: " +#define POP_SOCKET_ERROR "Could not create socket for POP connection: " sock = socket (PF_INET, SOCK_STREAM, 0); if (sock < 0) { - strcpy (pop_error, SOCKET_ERROR); + strcpy (pop_error, POP_SOCKET_ERROR); strncat (pop_error, strerror (errno), - ERROR_MAX - sizeof (SOCKET_ERROR)); + ERROR_MAX - sizeof (POP_SOCKET_ERROR)); return (-1); } + do + { + hostent = gethostbyname (host); + try_count++; + if ((! hostent) && ((h_errno != TRY_AGAIN) || (try_count == 5))) + { + strcpy (pop_error, "Could not determine POP server's address"); + return (-1); + } + } while (! hostent); + while (*hostent->h_addr_list) { memcpy (&addr.sin_addr, *hostent->h_addr_list, hostent->h_length); @@ -1079,11 +1107,13 @@ if (! (flags & POP_NO_KERBEROS)) { #ifdef KRB5 - krb5_init_ets (); - - if (rem = krb5_cc_default (&ccdef)) + if ((rem = krb5_init_context (&kcontext))) { krb5error: + if (auth_context) + krb5_auth_con_free (kcontext, auth_context); + if (kcontext) + krb5_free_context (kcontext); strcpy (pop_error, KRB_ERROR); strncat (pop_error, error_message (rem), ERROR_MAX - sizeof(KRB_ERROR)); @@ -1091,10 +1121,14 @@ return (-1); } - if (rem = krb5_cc_get_principal (ccdef, &client)) - { - goto krb5error; - } + if ((rem = krb5_auth_con_init (kcontext, &auth_context))) + goto krb5error; + + if (rem = krb5_cc_default (kcontext, &ccdef)) + goto krb5error; + + if (rem = krb5_cc_get_principal (kcontext, ccdef, &client)) + goto krb5error; for (cp = hostent->h_name; *cp; cp++) { @@ -1104,22 +1138,20 @@ } } - if (rem = krb5_sname_to_principal (hostent->h_name, POP_SERVICE, - FALSE, &server)) - { - goto krb5error; - } + if (rem = krb5_sname_to_principal (kcontext, hostent->h_name, + POP_SERVICE, FALSE, &server)) + goto krb5error; - rem = krb5_sendauth ((krb5_pointer) &sock, "KPOPV1.0", client, server, + rem = krb5_sendauth (kcontext, &auth_context, + (krb5_pointer) &sock, "KPOPV1.0", client, server, AP_OPTS_MUTUAL_REQUIRED, 0, /* no checksum */ 0, /* no creds, use ccache instead */ ccdef, - 0, /* don't need seq # */ + &err_ret, 0, /* don't need subsession key */ - &err_ret, 0); /* don't need reply */ - krb5_free_principal (server); + krb5_free_principal (kcontext, server); if (rem) { if (err_ret && err_ret->text.length) @@ -1142,20 +1174,23 @@ ERROR_MAX - sizeof (KRB_ERROR)); } if (err_ret) - krb5_free_error (err_ret); + krb5_free_error (kcontext, err_ret); + krb5_auth_con_free (kcontext, auth_context); + krb5_free_context (kcontext); CLOSESOCKET (sock); return (-1); } #else /* ! KRB5 */ ticket = (KTEXT) malloc (sizeof (KTEXT_ST)); - rem = krb_sendauth (0L, sock, ticket, "pop", hostent->h_name, - (char *) krb_realmofhost (hostent->h_name), + rem = krb_sendauth (0L, sock, ticket, "pop", realhost, + (char *) krb_realmofhost (realhost), (unsigned long) 0, &msg_data, &cred, schedule, (struct sockaddr_in *) 0, (struct sockaddr_in *) 0, "KPOPV0.1"); free ((char *) ticket); + free (realhost); if (rem != KSUCCESS) { strcpy (pop_error, KRB_ERROR); @@ -1182,15 +1217,20 @@ * Arguments: * server The server from which to get the line of text. * - * Returns: A non-null pointer if successful, or a null pointer on any - * error, with an error message copied into pop_error. + * Returns: The number of characters in the line, which is returned in + * LINE, not including the final null. A return value of 0 + * indicates a blank line. A negative return value indicates an + * error (in which case the contents of LINE are undefined. In + * case of error, an error message is copied into pop_error. * * Notes: The line returned is overwritten with each call to pop_getline. * * Side effects: Closes the connection on error. + * + * THE RETURNED LINE MAY CONTAIN EMBEDDED NULLS! */ -static char * -pop_getline (popserver server) +static int +pop_getline (popserver server, char **line) { #define GETLINE_ERROR "Error reading from server: " @@ -1199,7 +1239,8 @@ if (server->data) { - char *cp = find_crlf (server->buffer + server->buffer_index); + char *cp = find_crlf (server->buffer + server->buffer_index, + server->data); if (cp) { int found; @@ -1213,8 +1254,11 @@ server->buffer_index += data_used; if (pop_debug) + /* Embedded nulls will truncate this output prematurely, + but that's OK because it's just for debugging anyway. */ fprintf (stderr, "<<< %s\n", server->buffer + found); - return (server->buffer + found); + *line = server->buffer + found; + return (data_used - 2); } else { @@ -1250,7 +1294,7 @@ { strcpy (pop_error, "Out of memory in pop_getline"); pop_trash (server); - return (0); + return (-1); } } ret = RECV (server->file, server->buffer + server->data, @@ -1261,13 +1305,13 @@ strncat (pop_error, strerror (errno), ERROR_MAX - sizeof (GETLINE_ERROR)); pop_trash (server); - return (0); + return (-1); } else if (ret == 0) { strcpy (pop_error, "Unexpected EOF from server in pop_getline"); pop_trash (server); - return (0); + return (-1); } else { @@ -1275,7 +1319,8 @@ server->data += ret; server->buffer[server->data] = '\0'; - cp = find_crlf (server->buffer + search_offset); + cp = find_crlf (server->buffer + search_offset, + server->data - search_offset); if (cp) { int data_used = (cp + 2) - server->buffer; @@ -1285,9 +1330,12 @@ if (pop_debug) fprintf (stderr, "<<< %s\n", server->buffer); - return (server->buffer); + *line = server->buffer; + return (data_used - 2); } - search_offset += ret; + /* As above, the "- 1" here is to account for the fact that + we may have read a CR without its accompanying LF. */ + search_offset += ret - 1; } } @@ -1317,12 +1365,24 @@ { #define SENDLINE_ERROR "Error writing to POP server: " int ret; + char *buf; + /* Combine the string and the CR-LF into one buffer. Otherwise, two + reasonable network stack optimizations, Nagle's algorithm and + delayed acks, combine to delay us a fraction of a second on every + message we send. (Movemail writes line without \r\n, client + kernel sends packet, server kernel delays the ack to see if it + can combine it with data, movemail writes \r\n, client kernel + waits because it has unacked data already in its outgoing queue, + client kernel eventually times out and sends.) + + This can be something like 0.2s per command, which can add up + over a few dozen messages, and is a big chunk of the time we + spend fetching mail from a server close by. */ + buf = alloca (strlen (line) + 3); + strcpy (buf, line); + strcat (buf, "\r\n"); ret = fullwrite (server->file, line, strlen (line)); - if (ret >= 0) - { /* 0 indicates that a blank line was written */ - ret = fullwrite (server->file, "\r\n", 2); - } if (ret < 0) { @@ -1351,10 +1411,10 @@ fullwrite (int fd, char *buf, int nbytes) { char *cp; - int ret; + int ret = 0; cp = buf; - while ((ret = SEND (fd, cp, nbytes, 0)) > 0) + while (nbytes && ((ret = SEND (fd, cp, nbytes, 0)) > 0)) { cp += ret; nbytes -= ret; @@ -1382,7 +1442,7 @@ { char *fromline; - if (! (fromline = pop_getline (server))) + if (pop_getline (server, &fromline) < 0) { return (-1); } @@ -1420,8 +1480,7 @@ { char *fromserver; - fromserver = pop_getline (server); - if (! fromserver) + if (pop_getline (server, &fromserver) < 0) return (-1); if (strcmp (fromserver, ".")) @@ -1492,17 +1551,16 @@ #endif } -/* Return a pointer to the first CRLF in IN_STRING, - or 0 if it does not contain one. */ +/* Return a pointer to the first CRLF in IN_STRING, which can contain + embedded nulls and has LEN characters in it not including the final + null, or 0 if it does not contain one. */ static char * -find_crlf (char *in_string) +find_crlf (char *in_string, int len) { - while (1) + while (len--) { - if (! *in_string) - return (0); - else if (*in_string == '\r') + if (*in_string == '\r') { if (*++in_string == '\n') return (in_string - 1); @@ -1510,7 +1568,7 @@ else in_string++; } - /* NOTREACHED */ + return (0); } #endif /* MAIL_USE_POP */
--- a/lib-src/pop.h Wed Nov 01 20:41:09 2006 +0000 +++ b/lib-src/pop.h Wed Nov 01 20:55:14 2006 +0000 @@ -1,5 +1,6 @@ /* pop.h: Header file for the "pop.c" client POP3 protocol. - Copyright (c) 1991,1993 Free Software Foundation, Inc. + Copyright (C) 1991, 1993, 2002, 2003, 2004, + 2005, 2006 Free Software Foundation, Inc. Written by Jonathan Kamens, jik@security.ov.com. This file is part of XEmacs. @@ -16,8 +17,10 @@ You should have received a copy of the GNU General Public License along with XEmacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* Synched up with: FSF 22.0.50. */ #include <stdio.h> @@ -59,7 +62,8 @@ extern int pop_stat _ARGS((popserver server, int *count, int *size)); extern int pop_list _ARGS((popserver server, int message, int **IDs, int **size)); -extern char *pop_retrieve _ARGS((popserver server, int message, int markfrom)); +extern int pop_retrieve _ARGS((popserver server, int message, int markfrom, + char **)); extern int pop_retrieve_first _ARGS((popserver server, int message, char **response)); extern int pop_retrieve_next _ARGS((popserver server, char **line));
--- a/lisp/ChangeLog Wed Nov 01 20:41:09 2006 +0000 +++ b/lisp/ChangeLog Wed Nov 01 20:55:14 2006 +0000 @@ -1,3 +1,8 @@ +2006-10-28 Adrian Aichner <adrian@xemacs.org> + + * simple.el (raw-append-message): Implement minibuffer resizing + based on requirements filled echo area content. + 2006-10-28 Nix <nix@esperi.org.uk> * window-xemacs.el (window-configuration-includes-position): New. @@ -15122,7 +15127,7 @@ * info.el (Info-exit): `toolbar-info-frame' doesn't necessarily exist. -1998-4-20 Stephen J. Turnbull <turnbull@sk.tsukuba.ac.jp> +1998-04-20 Stephen J. Turnbull <turnbull@sk.tsukuba.ac.jp> * package-get.el (package-get-all): add `\n' separator to interactive specification so that both variables are read