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