changeset 20418:7e1538a45702

Allow messages retrieved from the POP server to contain embedded nulls.
author Karl Heuer <kwzh@gnu.org>
date Thu, 04 Dec 1997 06:44:56 +0000
parents 01d602ca5dcf
children 28110a85d23e
files lib-src/movemail.c lib-src/pop.c lib-src/pop.h
diffstat 3 files changed, 116 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/lib-src/movemail.c	Thu Dec 04 06:14:04 1997 +0000
+++ b/lib-src/movemail.c	Thu Dec 04 06:44:56 1997 +0000
@@ -795,12 +795,12 @@
       return (NOTOK);
     }
 
-  while (! (ret = pop_retrieve_next (server, &line)))
+  while ((ret = pop_retrieve_next (server, &line)) >= 0)
     {
       if (! line)
 	break;
 
-      if (mbx_write (line, arg) != OK)
+      if (mbx_write (line, ret, arg) != OK)
 	{
 	  strcpy (Errmsg, strerror (errno));
 	  pop_close (server);
@@ -826,8 +826,9 @@
 			 && (a[4] == ' '))
 
 int
-mbx_write (line, mbf)
+mbx_write (line, len, mbf)
      char *line;
+     int len;
      FILE *mbf;
 {
 #ifdef MOVEMAIL_QUOTE_POP_FROM_LINES
@@ -844,7 +845,7 @@
       line++;
       len--;
     }
-  if (fputs (line, mbf) == EOF) 
+  if (fwrite (line, 1, len, mbf) != len) 
     return (NOTOK);
   if (fputc (0x0a, mbf) == EOF)
     return (NOTOK);
--- a/lib-src/pop.c	Thu Dec 04 06:14:04 1997 +0000
+++ b/lib-src/pop.c	Thu Dec 04 06:44:56 1997 +0000
@@ -130,16 +130,24 @@
 #endif
 #endif
 
-static int socket_connection (/* char *, int */);
-static char *getline (/* popserver */);
-static int sendline (/* popserver, char * */);
-static int fullwrite (/* int, char *, int */);
-static int getok (/* popserver */);
+#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 getline _P((popserver, char **));
+static int sendline _P((popserver, char *));
+static int fullwrite _P((int, char *, int));
+static int getok _P((popserver));
 #if 0
-static int gettermination (/* popserver */);
+static int gettermination _P((popserver));
 #endif
-static void pop_trash (/* popserver */);
-static char *find_crlf (/* char * */);
+static void pop_trash _P((popserver));
+static char *find_crlf _P((char *, int));
 
 #define ERROR_MAX 80		/* a pretty arbitrary size */
 #define POP_PORT 110
@@ -373,7 +381,7 @@
       return (-1);
     }
      
-  if (sendline (server, "STAT") || (! (fromserver = getline (server))))
+  if (sendline (server, "STAT") || (getline (server, &fromserver) < 0))
     return (-1);
 
   if (strncmp (fromserver, "+OK ", 4))
@@ -469,7 +477,7 @@
 	  free ((char *) *sizes);
 	  return (-1);
 	}
-      if (! (fromserver = getline (server)))
+      if (getline (server, &fromserver) < 0)
 	{
 	  free ((char *) *IDs);
 	  free ((char *) *sizes);
@@ -514,7 +522,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);
@@ -533,7 +541,7 @@
 	    }
 	  (*sizes)[i] = atoi (fromserver);
 	}
-      if (pop_multi_next (server, &fromserver))
+      if (pop_multi_next (server, &fromserver) < 0)
 	{
 	  free ((char *) *IDs);
 	  free ((char *) *sizes);
@@ -563,17 +571,21 @@
  *	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 (server, message, markfrom)
+int
+pop_retrieve (server, message, markfrom, msg_buf)
      popserver server;
      int message;
      int markfrom;
+     char **msg_buf;
 {
   int *IDs, *sizes, bufsize, fromcount = 0, cp = 0;
   char *ptr, *fromserver;
@@ -582,15 +594,15 @@
   if (server->in_multi)
     {
       strcpy (pop_error, "In multi-line query in pop_retrieve");
-      return (0);
+      return (-1);
     }
 
   if (pop_list (server, message, &IDs, &sizes))
-    return (0);
+    return (-1);
 
   if (pop_retrieve_first (server, message, &fromserver))
     {
-      return (0);
+      return (-1);
     }
 
   /*
@@ -608,17 +620,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' &&
@@ -632,23 +643,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);
-      bcopy (fromserver, &ptr[cp], linesize);
-      cp += linesize;
+      bcopy (fromserver, &ptr[cp], ret);
+      cp += ret;
       ptr[cp++] = '\n';
     }
 
-  if (ret)
-    {
-      free (ptr);
-      return (0);
-    }
+  free (ptr);
+  return (-1);
 }     
 
 int
@@ -661,6 +668,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 (server, line)
      popserver server;
@@ -686,6 +701,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 (server, line)
      popserver server;
@@ -714,7 +737,7 @@
       return (-1);
     }
 
-  if (sendline (server, command) || (! (*response = getline (server))))
+  if (sendline (server, command) || (getline (server, response) < 0))
     {
       return (-1);
     }
@@ -738,12 +761,22 @@
     }
 }
 
+/*
+  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 (server, line)
      popserver server;
      char **line;
 {
   char *fromserver;
+  int ret;
 
   if (! server->in_multi)
     {
@@ -751,8 +784,7 @@
       return (-1);
     }
 
-  fromserver = getline (server);
-  if (! fromserver)
+  if ((ret = getline (server, &fromserver)) < 0)
     {
       return (-1);
     }
@@ -768,13 +800,13 @@
       else
 	{
 	  *line = fromserver + 1;
-	  return (0);
+	  return (ret - 1);
 	}
     }
   else
     {
       *line = fromserver;
-      return (0);
+      return (ret);
     }
 }
 
@@ -783,21 +815,20 @@
      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)
-	{
-	  return (0);
-	}
+      if (ret < 0)
+	return (-1);
     }
 
-  return (-1);
+  return (0);
 }
 
 /* Function: pop_delete
@@ -888,7 +919,7 @@
   if (sendline (server, "LAST"))
     return (-1);
 
-  if (! (fromserver = getline (server)))
+  if (getline (server, &fromserver) < 0)
     return (-1);
 
   if (! strncmp (fromserver, "-ERR", 4))
@@ -1234,16 +1265,22 @@
  * 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 getline.
  *
  * Side effects: Closes the connection on error.
+ *
+ * THE RETURNED LINE MAY CONTAIN EMBEDDED NULLS!
  */
-static char *
-getline (server)
+static int
+getline (server, line)
      popserver server;
+     char **line;
 {
 #define GETLINE_ERROR "Error reading from server: "
 
@@ -1252,7 +1289,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;
@@ -1266,8 +1304,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
 	{
@@ -1302,7 +1343,7 @@
 	    {
 	      strcpy (pop_error, "Out of memory in getline");
 	      pop_trash (server);
-	      return (0);
+	      return (-1);
 	    }
 	}
       ret = RECV (server->file, server->buffer + server->data,
@@ -1313,13 +1354,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 getline");
 	  pop_trash (server);
-	  return (0);
+	  return (-1);
 	}
       else
 	{
@@ -1327,7 +1368,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;
@@ -1337,7 +1379,8 @@
 
 	      if (pop_debug)
 		fprintf (stderr, "<<< %s\n", server->buffer);
-	      return (server->buffer);
+	      *line = server->buffer;
+	      return (data_used - 2);
 	    }
 	  /* As above, the "- 1" here is to account for the fact that
 	     we may have read a CR without its accompanying LF. */
@@ -1442,7 +1485,7 @@
 {
   char *fromline;
 
-  if (! (fromline = getline (server)))
+  if (getline (server, &fromline) < 0)
     {
       return (-1);
     }
@@ -1481,8 +1524,7 @@
 {
   char *fromserver;
 
-  fromserver = getline (server);
-  if (! fromserver)
+  if (getline (server, &fromserver) < 0)
     return (-1);
 
   if (strcmp (fromserver, "."))
@@ -1555,18 +1597,18 @@
 #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 (in_string)
+find_crlf (in_string, len)
      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);
@@ -1574,7 +1616,7 @@
       else
 	in_string++;
     }
-  /* NOTREACHED */
+  return (0);
 }
 
 #endif /* MAIL_USE_POP */
--- a/lib-src/pop.h	Thu Dec 04 06:14:04 1997 +0000
+++ b/lib-src/pop.h	Thu Dec 04 06:44:56 1997 +0000
@@ -59,7 +59,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));