(byte-optimize-approx-equal): Use <=, not <.
[bpt/emacs.git] / lib-src / pop.c
index 3acacaa..9292998 100644 (file)
@@ -1,5 +1,5 @@
 /* pop.c: client routines for talking to a POP3-protocol post-office server
-   Copyright (c) 1991,1993 Free Software Foundation, Inc.
+   Copyright (c) 1991, 1993, 1996 Free Software Foundation, Inc.
    Written by Jonathan Kamens, jik@security.ov.com.
 
 This file is part of GNU Emacs.
@@ -16,26 +16,47 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
-#define NO_SHORTNAMES   /* Tell config not to load remap.h */
+#ifdef HAVE_CONFIG_H
+#define NO_SHORTNAMES  /* Tell config not to load remap.h */
 #include <../src/config.h>
+#else
+#define MAIL_USE_POP
+#endif
 
-#under open
-#undef close
+#ifdef MAIL_USE_POP
+
+#ifdef HAVE_CONFIG_H
+/* Cancel these substitutions made in config.h */
+#undef open
 #undef read
 #undef write
-
-#ifdef MAIL_USE_POP
+#undef close
+#endif
 
 #include <sys/types.h>
+#ifdef WINDOWSNT
+#include "ntlib.h"
+#include <winsock.h>
+#undef SOCKET_ERROR
+#define RECV(s,buf,len,flags) recv(s,buf,len,flags)
+#define SEND(s,buf,len,flags) send(s,buf,len,flags)
+#define CLOSESOCKET(s) closesocket(s)
+#else
 #include <netinet/in.h>
 #include <sys/socket.h>
+#define RECV(s,buf,len,flags) read(s,buf,len)
+#define SEND(s,buf,len,flags) write(s,buf,len)
+#define CLOSESOCKET(s) close(s)
+#endif
 #include <pop.h>
+
 #ifdef sun
 #include <malloc.h>
-#endif
-#endif
+#endif /* sun */
+
 #ifdef HESIOD
 #include <hesiod.h>
 /*
@@ -46,36 +67,49 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  */
 extern struct servent *hes_getservbyname (/* char *, char * */);
 #endif
+
 #include <pwd.h>
 #include <netdb.h>
 #include <errno.h>
 #include <stdio.h>
+
 #ifdef KERBEROS
 #ifndef KRB5
+#ifndef SOLARIS2
 #include <des.h>
 #include <krb.h>
+#else /* not SOLARIS2 */
+#include <kerberos/des.h>
+#include <kerberos/krb.h>
+#endif /* not SOLARIS2 */
 #else /* KRB5 */
 #include <krb5/krb5.h>
 #include <krb5/ext-proto.h>
 #include <ctype.h>
 #endif /* KRB5 */
+#endif /* KERBEROS */
 
 extern char *getenv (/* char * */);
 extern char *getlogin (/* void */);
 extern char *getpass (/* char * */);
 extern char *strerror (/* int */);
+extern char *index ();
 
 #ifdef KERBEROS
+#ifndef KRB5
 extern int krb_sendauth (/* long, int, KTEXT, char *, char *, char *,
-                        u_long, MSG_DAT *, CREDENTIALS *, Key_schedule,
-                        struct sockaddr_in *, struct sockaddr_in *,
-                        char * */);
+                           u_long, MSG_DAT *, CREDENTIALS *, Key_schedule,
+                           struct sockaddr_in *, struct sockaddr_in *,
+                           char * */);
 extern char *krb_realmofhost (/* char * */);
-#endif
+#endif /* ! KRB5 */
+#endif /* KERBEROS */
 
-#ifndef HAVE_H_ERRNO
+#ifndef WINDOWSNT
+#if !defined(HAVE_H_ERRNO) || !defined(HAVE_CONFIG_H)
 extern int h_errno;
 #endif
+#endif
 
 static int socket_connection (/* char *, int */);
 static char *getline (/* popserver */);
@@ -86,13 +120,16 @@ static int getok (/* popserver */);
 static int gettermination (/* popserver */);
 #endif
 static void pop_trash (/* popserver */);
-
-static char *my_strstr ();
+static char *find_crlf (/* char * */);
 
 #define ERROR_MAX 80           /* a pretty arbitrary size */
 #define POP_PORT 110
 #define KPOP_PORT 1109
+#ifdef WINDOWSNT
+#define POP_SERVICE "pop3"     /* we don't want the POP2 port! */
+#else
 #define POP_SERVICE "pop"
+#endif
 #ifdef KERBEROS
 #ifdef KRB5
 #define KPOP_SERVICE "k5pop";
@@ -255,6 +292,7 @@ pop_open (host, username, password, flags)
   server->buffer_index = 0;
   server->buffer_size = GETLINE_MIN;
   server->in_multi = 0;
+  server->trash_started = 0;
 
   if (getok (server))
     return (0);
@@ -547,7 +585,7 @@ pop_retrieve (server, message, markfrom)
    * allocate more space for them below.
    */
   bufsize = sizes[0] + (markfrom ? 5 : 0);
-  ptr = malloc (bufsize);
+  ptr = (char *)malloc (bufsize);
   free ((char *) IDs);
   free ((char *) sizes);
 
@@ -574,7 +612,7 @@ pop_retrieve (server, message, markfrom)
          if (++fromcount == 5)
            {
              bufsize += 5;
-             ptr = realloc (ptr, bufsize);
+             ptr = (char *)realloc (ptr, bufsize);
              if (! ptr)
                {
                  strcpy (pop_error, "Out of memory in pop_retrieve");
@@ -894,7 +932,7 @@ pop_reset (server)
  * Return value: 0 for success, non-zero otherwise with error in
  *     pop_error.
  *
- * Side Effects: The popserver passed in is unuseable after this
+ * Side Effects: The popserver passed in is unusable after this
  *     function is called, even if an error occurs.
  */
 int
@@ -925,6 +963,10 @@ pop_quit (server)
   return (ret);
 }
 
+#ifdef WINDOWSNT
+static int have_winsock = 0;
+#endif
+
 /*
  * Function: socket_connection
  *
@@ -963,11 +1005,20 @@ socket_connection (host, flags)
   CREDENTIALS cred;
   Key_schedule schedule;
   int rem;
+  char *realhost;
 #endif /* KRB5 */
 #endif /* KERBEROS */
 
   int try_count = 0;
 
+#ifdef WINDOWSNT
+  {
+    WSADATA winsockData;
+    if (WSAStartup (0x101, &winsockData) == 0)
+      have_winsock = 1;
+  }
+#endif
+
   do
     {
       hostent = gethostbyname (host);
@@ -1042,7 +1093,7 @@ socket_connection (host, flags)
      
   if (! *hostent->h_addr_list)
     {
-      (void) close (sock);
+      CLOSESOCKET (sock);
       strcpy (pop_error, CONNECT_ERROR);
       strncat (pop_error, strerror (errno),
               ERROR_MAX - sizeof (CONNECT_ERROR));
@@ -1063,7 +1114,7 @@ socket_connection (host, flags)
          strcpy (pop_error, KRB_ERROR);
          strncat (pop_error, error_message (rem),
                   ERROR_MAX - sizeof(KRB_ERROR));
-         (void) close (sock);
+         CLOSESOCKET (sock);
          return (-1);
        }
 
@@ -1120,24 +1171,26 @@ socket_connection (host, flags)
          if (err_ret)
            krb5_free_error (err_ret);
 
-         (void) close (sock);
+         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),
+      realhost = strdup (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);
          strncat (pop_error, krb_err_txt[rem],
                   ERROR_MAX - sizeof (KRB_ERROR));
-         (void) close (sock);
+         CLOSESOCKET (sock);
          return (-1);
        }
 #endif /* KRB5 */
@@ -1172,10 +1225,11 @@ getline (server)
 #define GETLINE_ERROR "Error reading from server: "
 
   int ret;
-     
+  int search_offset = 0;
+
   if (server->data)
     {
-      char *cp = my_strstr (server->buffer + server->buffer_index, "\r\n");
+      char *cp = find_crlf (server->buffer + server->buffer_index);
       if (cp)
        {
          int found;
@@ -1196,6 +1250,14 @@ getline (server)
        {
          bcopy (server->buffer + server->buffer_index,
                 server->buffer, 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 "-
+             1" here to account for the fact that the last character
+             of the data we have may be the CR of a CRLF pair, of
+             which we haven't read the second half yet, so we may have
+             to search it again when we read more data. */
+         search_offset = server->data - 1;
          server->buffer_index = 0;
        }
     }
@@ -1206,10 +1268,13 @@ getline (server)
 
   while (1)
     {
-      if (server->data == server->buffer_size)
+      /* There's a "- 1" here to leave room for the null that we put
+         at the end of the read data below.  We put the null there so
+         that find_crlf knows where to stop when we call it. */
+      if (server->data == server->buffer_size - 1)
        {
          server->buffer_size += GETLINE_INCR;
-         server->buffer = realloc (server->buffer, server->buffer_size);
+         server->buffer = (char *)realloc (server->buffer, server->buffer_size);
          if (! server->buffer)
            {
              strcpy (pop_error, "Out of memory in getline");
@@ -1217,8 +1282,8 @@ getline (server)
              return (0);
            }
        }
-      ret = read (server->file, server->buffer + server->data,
-                 server->buffer_size - server->data - 1);
+      ret = RECV (server->file, server->buffer + server->data,
+                 server->buffer_size - server->data - 1, 0);
       if (ret < 0)
        {
          strcpy (pop_error, GETLINE_ERROR);
@@ -1239,7 +1304,7 @@ getline (server)
          server->data += ret;
          server->buffer[server->data] = '\0';
               
-         cp = my_strstr (server->buffer, "\r\n");
+         cp = find_crlf (server->buffer + search_offset);
          if (cp)
            {
              int data_used = (cp + 2) - server->buffer;
@@ -1251,6 +1316,7 @@ getline (server)
                fprintf (stderr, "<<< %s\n", server->buffer);
              return (server->buffer);
            }
+         search_offset += ret;
        }
     }
 
@@ -1322,7 +1388,7 @@ fullwrite (fd, buf, nbytes)
   int ret;
 
   cp = buf;
-  while ((ret = write (fd, cp, nbytes)) > 0)
+  while ((ret = SEND (fd, cp, nbytes, 0)) > 0)
     {
       cp += ret;
       nbytes -= ret;
@@ -1343,7 +1409,7 @@ fullwrite (fd, buf, nbytes)
  * 
  * Returns: 0 for success, else for failure and puts error in pop_error.
  *
- * Side effects: On failure, may make the connection unuseable.
+ * Side effects: On failure, may make the connection unusable.
  */
 static int
 getok (server)
@@ -1414,7 +1480,7 @@ gettermination (server)
  *     try to get the server to quit, but ignoring any responses that
  *     are received.
  *
- * Side effects: The server is unuseable after this function returns.
+ * Side effects: The server is unusable after this function returns.
  *     Changes made to the maildrop since the session was started (or
  *     since the last pop_reset) may be lost.
  */
@@ -1441,10 +1507,15 @@ pop_trash (server)
 {
   if (server->file >= 0)
     {
+      /* avoid recursion; sendline can call pop_trash */
+      if (server->trash_started)
+       return;
+      server->trash_started = 1;
+
       sendline (server, "RSET");
       sendline (server, "QUIT");
 
-      close (server->file);
+      CLOSESOCKET (server->file);
       server->file = -1;
       if (server->buffer)
        {
@@ -1452,25 +1523,33 @@ pop_trash (server)
          server->buffer = 0;
        }
     }
+
+#ifdef WINDOWSNT
+  if (have_winsock)
+    WSACleanup ();
+#endif
 }
 
-/* Search in STRING for an occurrence of SUBSTRING
-   and return a pointer to that occurrence.
-   Return 0 if SUBSTRING does not occur in STRING.  */
+/* Return a pointer to the first CRLF in IN_STRING,
+   or 0 if it does not contain one.  */
 
 static char *
-my_strstr (string, substring)
-     char *string, *substring;
+find_crlf (in_string)
+     char *in_string;
 {
-  char *p = string;
-
-  while (*p)
+  while (1)
     {
-      if (!strcmp (p, substring))
-       return p;
-      p++;
+      if (! *in_string)
+       return (0);
+      else if (*in_string == '\r')
+       {
+         if (*++in_string == '\n')
+           return (in_string - 1);
+       }
+      else
+       in_string++;
     }
-  return 0;
+  /* NOTREACHED */
 }
 
 #endif /* MAIL_USE_POP */