root/lib-src/pop.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pop_open
  2. pop_stat
  3. pop_list
  4. pop_retrieve
  5. pop_retrieve_first
  6. pop_retrieve_next
  7. pop_retrieve_flush
  8. pop_top_first
  9. pop_top_next
  10. pop_top_flush
  11. pop_multi_first
  12. pop_multi_next
  13. pop_multi_flush
  14. pop_delete
  15. pop_noop
  16. pop_last
  17. pop_reset
  18. pop_quit
  19. socket_connection
  20. pop_getline
  21. sendline
  22. fullwrite
  23. getok
  24. gettermination
  25. pop_close
  26. pop_trash
  27. find_crlf
  28. load_ws2
  29. sys_getaddrinfo
  30. sys_freeaddrinfo

     1 /* pop.c: client routines for talking to a POP3-protocol post-office server
     2 
     3 Copyright (C) 1991, 1993, 1996-1997, 1999, 2001-2023 Free Software
     4 Foundation, Inc.
     5 
     6 Author: Jonathan Kamens <jik@security.ov.com>
     7 
     8 This file is part of GNU Emacs.
     9 
    10 GNU Emacs is free software: you can redistribute it and/or modify
    11 it under the terms of the GNU General Public License as published by
    12 the Free Software Foundation, either version 3 of the License, or (at
    13 your option) any later version.
    14 
    15 GNU Emacs is distributed in the hope that it will be useful,
    16 but WITHOUT ANY WARRANTY; without even the implied warranty of
    17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    18 GNU General Public License for more details.
    19 
    20 You should have received a copy of the GNU General Public License
    21 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    22 
    23 
    24 #include <config.h>
    25 
    26 #ifdef MAIL_USE_POP
    27 
    28 #include <sys/types.h>
    29 #ifdef WINDOWSNT
    30 #include "ntlib.h"
    31 #undef _WIN32_WINNT
    32 #define _WIN32_WINNT 0x0501     /* for getaddrinfo stuff */
    33 #if defined __MINGW32_VERSION && __MINGW32_VERSION >= 5000002L
    34 # include <windows.h>
    35 #else
    36 # include <winsock2.h>
    37 #endif
    38 # include <ws2tcpip.h>
    39 #undef getaddrinfo
    40 #define getaddrinfo  sys_getaddrinfo
    41 #undef freeaddrinfo
    42 #define freeaddrinfo sys_freeaddrinfo
    43 int sys_getaddrinfo (const char * node, const char * service,
    44                      const struct addrinfo * hints, struct addrinfo ** res);
    45 void sys_freeaddrinfo (struct addrinfo * ai);
    46 #undef SOCKET_ERROR
    47 #define RECV(s,buf,len,flags) recv (s,buf,len,flags)
    48 #define SEND(s,buf,len,flags) send (s,buf,len,flags)
    49 #define CLOSESOCKET(s) closesocket (s)
    50 #else
    51 #include <netinet/in.h>
    52 #include <sys/socket.h>
    53 #define RECV(s,buf,len,flags) read (s,buf,len)
    54 #define SEND(s,buf,len,flags) write (s,buf,len)
    55 #define CLOSESOCKET(s) close (s)
    56 #endif
    57 #include <pop.h>
    58 
    59 #ifdef HESIOD
    60 #include <hesiod.h>
    61 /*
    62  * It really shouldn't be necessary to put this declaration here, but
    63  * the version of hesiod.h that Athena has installed in release 7.2
    64  * doesn't declare this function; I don't know if the 7.3 version of
    65  * hesiod.h does.
    66  */
    67 extern struct servent *hes_getservbyname (/* char *, char * */);
    68 #endif
    69 
    70 #include <alloca.h>
    71 #include <pwd.h>
    72 #include <netdb.h>
    73 #include <errno.h>
    74 #include <stdio.h>
    75 #include <stdlib.h>
    76 #include <string.h>
    77 #include <unistd.h>
    78 
    79 #ifdef KERBEROS
    80 # ifdef HAVE_KRB5_H
    81 #  include <krb5.h>
    82 # endif
    83 # ifdef HAVE_KRB_H
    84 #  include <krb.h>
    85 # else
    86 #  ifdef HAVE_KERBEROSIV_KRB_H
    87 #   include <kerberosIV/krb.h>
    88 #  else
    89 #   ifdef HAVE_KERBEROS_KRB_H
    90 #    include <kerberos/krb.h>
    91 #   endif
    92 #  endif
    93 # endif
    94 # ifdef HAVE_COM_ERR_H
    95 #  include <com_err.h>
    96 # endif
    97 #endif /* KERBEROS */
    98 
    99 #include <c-ctype.h>
   100 #include <min-max.h>
   101 
   102 #ifdef KERBEROS
   103 #ifndef KERBEROS5
   104 extern int krb_sendauth (/* long, int, KTEXT, char *, char *, char *,
   105                             u_long, MSG_DAT *, CREDENTIALS *, Key_schedule,
   106                             struct sockaddr_in *, struct sockaddr_in *,
   107                             char * */);
   108 extern char *krb_realmofhost (/* char * */);
   109 #endif /* ! KERBEROS5 */
   110 #endif /* KERBEROS */
   111 
   112 static int socket_connection (char *, int);
   113 static int pop_getline (popserver, char **);
   114 static int sendline (popserver, const char *);
   115 static int fullwrite (int, char *, int);
   116 static int getok (popserver);
   117 #if 0
   118 static int gettermination (popserver);
   119 #endif
   120 static void pop_trash (popserver);
   121 static char *find_crlf (char *, int);
   122 
   123 #define ERROR_MAX 160           /* a pretty arbitrary size, but needs
   124                                    to be bigger than the original
   125                                    value of 80 */
   126 #define POP_PORT 110
   127 #define POP_SERVICE "pop3"      /* we don't want the POP2 port! */
   128 #ifdef KERBEROS
   129 #define KPOP_PORT 1109
   130 #define KPOP_SERVICE "kpop"     /* never used: look for 20060515 to see why */
   131 #endif
   132 
   133 char pop_error[ERROR_MAX];
   134 bool pop_debug = false;
   135 
   136 /*
   137  * Function: pop_open (char *host, char *username, char *password,
   138  *                     int flags)
   139  *
   140  * Purpose: Establishes a connection with a post-office server, and
   141  *      completes the authorization portion of the session.
   142  *
   143  * Arguments:
   144  *      host    The server host with which the connection should be
   145  *              established.  Optional.  If omitted, internal
   146  *              heuristics will be used to determine the server host,
   147  *              if possible.
   148  *      username
   149  *              The username of the mail-drop to access.  Optional.
   150  *              If omitted, internal heuristics will be used to
   151  *              determine the username, if possible.
   152  *      password
   153  *              The password to use for authorization.  If omitted,
   154  *              internal heuristics will be used to determine the
   155  *              password, if possible.
   156  *      flags   A bit mask containing flags controlling certain
   157  *              functions of the routine.  Valid flags are defined in
   158  *              the file pop.h
   159  *
   160  * Return value: Upon successful establishment of a connection, a
   161  *      non-null popserver will be returned.  Otherwise, null will be
   162  *      returned, and the string variable pop_error will contain an
   163  *      explanation of the error.
   164  */
   165 popserver
   166 pop_open (char *host, char *username, char *password, int flags)
   167 {
   168   int sock;
   169   popserver server;
   170 
   171   /* Determine the user name */
   172   if (! username)
   173     {
   174       username = getenv ("USER");
   175       if (! (username && *username))
   176         {
   177           username = getlogin ();
   178           if (! (username && *username))
   179             {
   180               struct passwd *passwd;
   181               passwd = getpwuid (getuid ());
   182               if (passwd && passwd->pw_name && *passwd->pw_name)
   183                 {
   184                   username = passwd->pw_name;
   185                 }
   186               else
   187                 {
   188                   strcpy (pop_error, "Could not determine username");
   189                   return (0);
   190                 }
   191             }
   192         }
   193     }
   194 
   195   /*
   196    *  Determine the mail host.
   197    */
   198 
   199   if (! host)
   200     {
   201       host = getenv ("MAILHOST");
   202     }
   203 
   204 #ifdef HESIOD
   205   if ((! host) && (! (flags & POP_NO_HESIOD)))
   206     {
   207       struct hes_postoffice *office;
   208       office = hes_getmailhost (username);
   209       if (office && office->po_type && (! strcmp (office->po_type, "POP"))
   210           && office->po_name && *office->po_name && office->po_host
   211           && *office->po_host)
   212         {
   213           host = office->po_host;
   214           username = office->po_name;
   215         }
   216     }
   217 #endif
   218 
   219 #ifdef MAILHOST
   220   if (! host)
   221     {
   222       host = MAILHOST;
   223     }
   224 #endif
   225 
   226   if (! host)
   227     {
   228       strcpy (pop_error, "Could not determine POP server");
   229       return (0);
   230     }
   231 
   232   /* Determine the password */
   233 #ifdef KERBEROS
   234 #define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS))
   235 #else
   236 #define DONT_NEED_PASSWORD 0
   237 #endif
   238 
   239   if ((! password) && (! DONT_NEED_PASSWORD))
   240     {
   241       if (! (flags & POP_NO_GETPASS))
   242         {
   243           password = getpass ("Enter POP password:");
   244         }
   245       if (! password)
   246         {
   247           strcpy (pop_error, "Could not determine POP password");
   248           return (0);
   249         }
   250     }
   251   if (password)                 /* always true, detected 20060515 */
   252     flags |= POP_NO_KERBEROS;
   253   else
   254     password = username;        /* dead code, detected 20060515 */
   255   /** "kpop" service is  never used: look for 20060515 to see why **/
   256 
   257   sock = socket_connection (host, flags);
   258   if (sock == -1)
   259     return (0);
   260 
   261   server = (popserver) malloc (sizeof (struct _popserver));
   262   if (! server)
   263     {
   264       strcpy (pop_error, "Out of memory in pop_open");
   265       return (0);
   266     }
   267   server->buffer = (char *) malloc (GETLINE_MIN);
   268   if (! server->buffer)
   269     {
   270       strcpy (pop_error, "Out of memory in pop_open");
   271       free ((char *) server);
   272       return (0);
   273     }
   274 
   275   server->file = sock;
   276   server->data = 0;
   277   server->buffer_index = 0;
   278   server->buffer_size = GETLINE_MIN;
   279   server->in_multi = false;
   280   server->trash_started = false;
   281 
   282   if (getok (server))
   283     return (0);
   284 
   285   /*
   286    * I really shouldn't use the pop_error variable like this, but....
   287    */
   288   if (strnlen (username, ERROR_MAX - 6 + 1) == ERROR_MAX - 6 + 1)
   289     {
   290       pop_close (server);
   291       strcpy (pop_error,
   292               "Username too long; recompile pop.c with larger ERROR_MAX");
   293       return (0);
   294     }
   295   sprintf (pop_error, "USER %s", username);
   296 
   297   if (sendline (server, pop_error) || getok (server))
   298     {
   299       return (0);
   300     }
   301 
   302   if (strnlen (password, ERROR_MAX - 6 + 1) == ERROR_MAX - 6 + 1)
   303     {
   304       pop_close (server);
   305       strcpy (pop_error,
   306               "Password too long; recompile pop.c with larger ERROR_MAX");
   307       return (0);
   308     }
   309   sprintf (pop_error, "PASS %s", password);
   310 
   311   if (sendline (server, pop_error) || getok (server))
   312     {
   313       return (0);
   314     }
   315 
   316   return (server);
   317 }
   318 
   319 /*
   320  * Function: pop_stat
   321  *
   322  * Purpose: Issue the STAT command to the server and return (in the
   323  *      value parameters) the number of messages in the maildrop and
   324  *      the total size of the maildrop.
   325  *
   326  * Return value: 0 on success, or non-zero with an error in pop_error
   327  *      in failure.
   328  *
   329  * Side effects: On failure, may make further operations on the
   330  *      connection impossible.
   331  */
   332 int
   333 pop_stat (popserver server, int *count, int *size)
   334 {
   335   char *fromserver;
   336   char *end_ptr;
   337 
   338   if (server->in_multi)
   339     {
   340       strcpy (pop_error, "In multi-line query in pop_stat");
   341       return (-1);
   342     }
   343 
   344   if (sendline (server, "STAT") || (pop_getline (server, &fromserver) < 0))
   345     return (-1);
   346 
   347   if (strncmp (fromserver, "+OK ", 4))
   348     {
   349       if (0 == strncmp (fromserver, "-ERR", 4))
   350         snprintf (pop_error, ERROR_MAX, "%s", fromserver);
   351       else
   352         {
   353           strcpy (pop_error,
   354                   "Unexpected response from POP server in pop_stat");
   355           pop_trash (server);
   356         }
   357       return (-1);
   358     }
   359 
   360   errno = 0;
   361   *count = strtol (&fromserver[4], &end_ptr, 10);
   362   /* Check validity of string-to-integer conversion. */
   363   if (fromserver + 4 == end_ptr || *end_ptr != ' ' || errno)
   364     {
   365       strcpy (pop_error, "Unexpected response from POP server in pop_stat");
   366       pop_trash (server);
   367       return (-1);
   368     }
   369 
   370   fromserver = end_ptr;
   371 
   372   errno = 0;
   373   *size = strtol (fromserver + 1, &end_ptr, 10);
   374   if (fromserver + 1 == end_ptr || errno)
   375     {
   376       strcpy (pop_error, "Unexpected response from POP server in pop_stat");
   377       pop_trash (server);
   378       return (-1);
   379     }
   380 
   381   return (0);
   382 }
   383 
   384 /*
   385  * Function: pop_list
   386  *
   387  * Purpose: Performs the POP "list" command and returns (in value
   388  *      parameters) two malloc'd zero-terminated arrays -- one of
   389  *      message IDs, and a parallel one of sizes.
   390  *
   391  * Arguments:
   392  *      server  The pop connection to talk to.
   393  *      message The number of the one message about which to get
   394  *              information, or 0 to get information about all
   395  *              messages.
   396  *
   397  * Return value: 0 on success, non-zero with error in pop_error on
   398  *      failure.
   399  *
   400  * Side effects: On failure, may make further operations on the
   401  *      connection impossible.
   402  */
   403 int
   404 pop_list (popserver server, int message, int **IDs, int **sizes)
   405 {
   406   int how_many, i;
   407   char *fromserver;
   408 
   409   if (server->in_multi)
   410     {
   411       strcpy (pop_error, "In multi-line query in pop_list");
   412       return (-1);
   413     }
   414 
   415   if (message)
   416     how_many = 1;
   417   else
   418     {
   419       int count, size;
   420       if (pop_stat (server, &count, &size))
   421         return (-1);
   422       how_many = count;
   423     }
   424 
   425   *IDs = (int *) malloc ((how_many + 1) * sizeof (int));
   426   *sizes = (int *) malloc ((how_many + 1) * sizeof (int));
   427   if (! (*IDs && *sizes))
   428     {
   429       strcpy (pop_error, "Out of memory in pop_list");
   430       return (-1);
   431     }
   432 
   433   if (message)
   434     {
   435       sprintf (pop_error, "LIST %d", message);
   436       if (sendline (server, pop_error))
   437         {
   438           free ((char *) *IDs);
   439           free ((char *) *sizes);
   440           return (-1);
   441         }
   442       if (pop_getline (server, &fromserver) < 0)
   443         {
   444           free ((char *) *IDs);
   445           free ((char *) *sizes);
   446           return (-1);
   447         }
   448       if (strncmp (fromserver, "+OK ", 4))
   449         {
   450           if (! strncmp (fromserver, "-ERR", 4))
   451             snprintf (pop_error, ERROR_MAX, "%s", fromserver);
   452           else
   453             {
   454               strcpy (pop_error,
   455                       "Unexpected response from server in pop_list");
   456               pop_trash (server);
   457             }
   458           free ((char *) *IDs);
   459           free ((char *) *sizes);
   460           return (-1);
   461         }
   462       (*IDs)[0] = atoi (&fromserver[4]);
   463       fromserver = strchr (&fromserver[4], ' ');
   464       if (! fromserver)
   465         {
   466           strcpy (pop_error,
   467                   "Badly formatted response from server in pop_list");
   468           pop_trash (server);
   469           free ((char *) *IDs);
   470           free ((char *) *sizes);
   471           return (-1);
   472         }
   473       (*sizes)[0] = atoi (fromserver);
   474       (*IDs)[1] = (*sizes)[1] = 0;
   475       return (0);
   476     }
   477   else
   478     {
   479       if (pop_multi_first (server, "LIST", &fromserver))
   480         {
   481           free ((char *) *IDs);
   482           free ((char *) *sizes);
   483           return (-1);
   484         }
   485       for (i = 0; i < how_many; i++)
   486         {
   487           if (pop_multi_next (server, &fromserver) <= 0)
   488             {
   489               free ((char *) *IDs);
   490               free ((char *) *sizes);
   491               return (-1);
   492             }
   493           (*IDs)[i] = atoi (fromserver);
   494           fromserver = strchr (fromserver, ' ');
   495           if (! fromserver)
   496             {
   497               strcpy (pop_error,
   498                       "Badly formatted response from server in pop_list");
   499               free ((char *) *IDs);
   500               free ((char *) *sizes);
   501               pop_trash (server);
   502               return (-1);
   503             }
   504           (*sizes)[i] = atoi (fromserver);
   505         }
   506       if (pop_multi_next (server, &fromserver) < 0)
   507         {
   508           free ((char *) *IDs);
   509           free ((char *) *sizes);
   510           return (-1);
   511         }
   512       else if (fromserver)
   513         {
   514           strcpy (pop_error,
   515                   "Too many response lines from server in pop_list");
   516           free ((char *) *IDs);
   517           free ((char *) *sizes);
   518           return (-1);
   519         }
   520       (*IDs)[i] = (*sizes)[i] = 0;
   521       return (0);
   522     }
   523 }
   524 
   525 /*
   526  * Function: pop_retrieve
   527  *
   528  * Purpose: Retrieve a specified message from the maildrop.
   529  *
   530  * Arguments:
   531  *      server  The server to retrieve from.
   532  *      message The message number to retrieve.
   533  *      markfrom
   534  *              If true, then mark the string "From " at the beginning
   535  *              of lines with '>'.
   536  *      msg_buf Output parameter to which a buffer containing the
   537  *              message is assigned.
   538  *
   539  * Return value: The number of bytes in msg_buf, which may contain
   540  *      embedded nulls, not including its final null, or -1 on error
   541  *      with pop_error set.
   542  *
   543  * Side effects: May kill connection on error.
   544  */
   545 int
   546 pop_retrieve (popserver server, int message, int markfrom, char **msg_buf)
   547 {
   548   int *IDs, *sizes, bufsize, fromcount = 0, cp = 0;
   549   char *ptr, *fromserver;
   550   int ret;
   551 
   552   if (server->in_multi)
   553     {
   554       strcpy (pop_error, "In multi-line query in pop_retrieve");
   555       return (-1);
   556     }
   557 
   558   if (pop_list (server, message, &IDs, &sizes))
   559     return (-1);
   560 
   561   if (pop_retrieve_first (server, message, &fromserver))
   562     {
   563       return (-1);
   564     }
   565 
   566   /*
   567    * The "5" below is an arbitrary constant -- I assume that if
   568    * there are "From" lines in the text to be marked, there
   569    * probably won't be more than 5 of them.  If there are, I
   570    * allocate more space for them below.
   571    */
   572   bufsize = sizes[0] + (markfrom ? 5 : 0);
   573   ptr = (char *)malloc (bufsize);
   574   free ((char *) IDs);
   575   free ((char *) sizes);
   576 
   577   if (! ptr)
   578     {
   579       strcpy (pop_error, "Out of memory in pop_retrieve");
   580       pop_retrieve_flush (server);
   581       return (-1);
   582     }
   583 
   584   while ((ret = pop_retrieve_next (server, &fromserver)) >= 0)
   585     {
   586       if (! fromserver)
   587         {
   588           ptr[cp] = '\0';
   589           *msg_buf = ptr;
   590           return (cp);
   591         }
   592       if (markfrom && fromserver[0] == 'F' && fromserver[1] == 'r' &&
   593           fromserver[2] == 'o' && fromserver[3] == 'm' &&
   594           fromserver[4] == ' ')
   595         {
   596           if (++fromcount == 5)
   597             {
   598               bufsize += 5;
   599               ptr = (char *)realloc (ptr, bufsize);
   600               if (! ptr)
   601                 {
   602                   strcpy (pop_error, "Out of memory in pop_retrieve");
   603                   pop_retrieve_flush (server);
   604                   return (-1);
   605                 }
   606               fromcount = 0;
   607             }
   608           ptr[cp++] = '>';
   609         }
   610       memcpy (&ptr[cp], fromserver, ret);
   611       cp += ret;
   612       ptr[cp++] = '\n';
   613     }
   614 
   615   free (ptr);
   616   return (-1);
   617 }
   618 
   619 int
   620 pop_retrieve_first (popserver server, int message, char **response)
   621 {
   622   sprintf (pop_error, "RETR %d", message);
   623   return (pop_multi_first (server, pop_error, response));
   624 }
   625 
   626 /*
   627   Returns a negative number on error, 0 to indicate that the data has
   628   all been read (i.e., the server has returned a "." termination
   629   line), or a positive number indicating the number of bytes in the
   630   returned buffer (which is null-terminated and may contain embedded
   631   nulls, but the returned bytecount doesn't include the final null).
   632   */
   633 
   634 int
   635 pop_retrieve_next (popserver server, char **line)
   636 {
   637   return (pop_multi_next (server, line));
   638 }
   639 
   640 int
   641 pop_retrieve_flush (popserver server)
   642 {
   643   return (pop_multi_flush (server));
   644 }
   645 
   646 int
   647 pop_top_first (popserver server, int message, int lines, char **response)
   648 {
   649   sprintf (pop_error, "TOP %d %d", message, lines);
   650   return (pop_multi_first (server, pop_error, response));
   651 }
   652 
   653 /*
   654   Returns a negative number on error, 0 to indicate that the data has
   655   all been read (i.e., the server has returned a "." termination
   656   line), or a positive number indicating the number of bytes in the
   657   returned buffer (which is null-terminated and may contain embedded
   658   nulls, but the returned bytecount doesn't include the final null).
   659   */
   660 
   661 int
   662 pop_top_next (popserver server, char **line)
   663 {
   664   return (pop_multi_next (server, line));
   665 }
   666 
   667 int
   668 pop_top_flush (popserver server)
   669 {
   670   return (pop_multi_flush (server));
   671 }
   672 
   673 int
   674 pop_multi_first (popserver server, const char *command, char **response)
   675 {
   676   if (server->in_multi)
   677     {
   678       strcpy (pop_error,
   679               "Already in multi-line query in pop_multi_first");
   680       return (-1);
   681     }
   682 
   683   if (sendline (server, command) || (pop_getline (server, response) < 0))
   684     {
   685       return (-1);
   686     }
   687 
   688   if (0 == strncmp (*response, "-ERR", 4))
   689     {
   690       snprintf (pop_error, ERROR_MAX, "%s", *response);
   691       return (-1);
   692     }
   693   else if (0 == strncmp (*response, "+OK", 3))
   694     {
   695       for (*response += 3; **response == ' '; (*response)++) /* empty */;
   696       server->in_multi = true;
   697       return (0);
   698     }
   699   else
   700     {
   701       strcpy (pop_error,
   702               "Unexpected response from server in pop_multi_first");
   703       return (-1);
   704     }
   705 }
   706 
   707 /*
   708   Read the next line of data from SERVER and place a pointer to it
   709   into LINE.  Return -1 on error, 0 if there are no more lines to read
   710   (i.e., the server has returned a line containing only "."), or a
   711   positive number indicating the number of bytes in the LINE buffer
   712   (not including the final null).  The data in that buffer may contain
   713   embedded nulls, but does not contain the final CRLF. When returning
   714   0, LINE is set to null. */
   715 
   716 int
   717 pop_multi_next (popserver server, char **line)
   718 {
   719   char *fromserver;
   720   int ret;
   721 
   722   if (! server->in_multi)
   723     {
   724       strcpy (pop_error, "Not in multi-line query in pop_multi_next");
   725       return (-1);
   726     }
   727 
   728   ret = pop_getline (server, &fromserver);
   729   if (ret < 0)
   730     {
   731       return (-1);
   732     }
   733 
   734   if (fromserver[0] == '.')
   735     {
   736       if (! fromserver[1])
   737         {
   738           *line = 0;
   739           server->in_multi = false;
   740           return (0);
   741         }
   742       else
   743         {
   744           *line = fromserver + 1;
   745           return (ret - 1);
   746         }
   747     }
   748   else
   749     {
   750       *line = fromserver;
   751       return (ret);
   752     }
   753 }
   754 
   755 int
   756 pop_multi_flush (popserver server)
   757 {
   758   char *line;
   759   int ret;
   760 
   761   if (! server->in_multi)
   762     {
   763       return (0);
   764     }
   765 
   766   while ((ret = pop_multi_next (server, &line)))
   767     {
   768       if (ret < 0)
   769         return (-1);
   770     }
   771 
   772   return (0);
   773 }
   774 
   775 /* Function: pop_delete
   776  *
   777  * Purpose: Delete a specified message.
   778  *
   779  * Arguments:
   780  *      server  Server from which to delete the message.
   781  *      message Message to delete.
   782  *
   783  * Return value: 0 on success, non-zero with error in pop_error
   784  *      otherwise.
   785  */
   786 int
   787 pop_delete (popserver server, int message)
   788 {
   789   if (server->in_multi)
   790     {
   791       strcpy (pop_error, "In multi-line query in pop_delete");
   792       return (-1);
   793     }
   794 
   795   sprintf (pop_error, "DELE %d", message);
   796 
   797   if (sendline (server, pop_error) || getok (server))
   798     return (-1);
   799 
   800   return (0);
   801 }
   802 
   803 /*
   804  * Function: pop_noop
   805  *
   806  * Purpose: Send a noop command to the server.
   807  *
   808  * Argument:
   809  *      server  The server to send to.
   810  *
   811  * Return value: 0 on success, non-zero with error in pop_error
   812  *      otherwise.
   813  *
   814  * Side effects: Closes connection on error.
   815  */
   816 int
   817 pop_noop (popserver server)
   818 {
   819   if (server->in_multi)
   820     {
   821       strcpy (pop_error, "In multi-line query in pop_noop");
   822       return (-1);
   823     }
   824 
   825   if (sendline (server, "NOOP") || getok (server))
   826     return (-1);
   827 
   828   return (0);
   829 }
   830 
   831 /*
   832  * Function: pop_last
   833  *
   834  * Purpose: Find out the highest seen message from the server.
   835  *
   836  * Arguments:
   837  *      server  The server.
   838  *
   839  * Return value: If successful, the highest seen message, which is
   840  *      greater than or equal to 0.  Otherwise, a negative number with
   841  *      the error explained in pop_error.
   842  *
   843  * Side effects: Closes the connection on error.
   844  */
   845 int
   846 pop_last (popserver server)
   847 {
   848   char *fromserver;
   849 
   850   if (server->in_multi)
   851     {
   852       strcpy (pop_error, "In multi-line query in pop_last");
   853       return (-1);
   854     }
   855 
   856   if (sendline (server, "LAST"))
   857     return (-1);
   858 
   859   if (pop_getline (server, &fromserver) < 0)
   860     return (-1);
   861 
   862   if (! strncmp (fromserver, "-ERR", 4))
   863     {
   864       snprintf (pop_error, ERROR_MAX, "%s", fromserver);
   865       return (-1);
   866     }
   867   else if (strncmp (fromserver, "+OK ", 4))
   868     {
   869       strcpy (pop_error, "Unexpected response from server in pop_last");
   870       pop_trash (server);
   871       return (-1);
   872     }
   873   else
   874     {
   875       char *end_ptr;
   876       int count;
   877       errno = 0;
   878       count = strtol (&fromserver[4], &end_ptr, 10);
   879       if (fromserver + 4 == end_ptr || errno)
   880         {
   881           strcpy (pop_error, "Unexpected response from server in pop_last");
   882           pop_trash (server);
   883           return (-1);
   884         }
   885       return count;
   886     }
   887 }
   888 
   889 /*
   890  * Function: pop_reset
   891  *
   892  * Purpose: Reset the server to its initial connect state
   893  *
   894  * Arguments:
   895  *      server  The server.
   896  *
   897  * Return value: 0 for success, non-0 with error in pop_error
   898  *      otherwise.
   899  *
   900  * Side effects: Closes the connection on error.
   901  */
   902 int
   903 pop_reset (popserver server)
   904 {
   905   if (pop_retrieve_flush (server))
   906     {
   907       return (-1);
   908     }
   909 
   910   if (sendline (server, "RSET") || getok (server))
   911     return (-1);
   912 
   913   return (0);
   914 }
   915 
   916 /*
   917  * Function: pop_quit
   918  *
   919  * Purpose: Quit the connection to the server,
   920  *
   921  * Arguments:
   922  *      server  The server to quit.
   923  *
   924  * Return value: 0 for success, non-zero otherwise with error in
   925  *      pop_error.
   926  *
   927  * Side Effects: The popserver passed in is unusable after this
   928  *      function is called, even if an error occurs.
   929  */
   930 int
   931 pop_quit (popserver server)
   932 {
   933   int ret = 0;
   934 
   935   if (server->file >= 0)
   936     {
   937       if (pop_retrieve_flush (server))
   938         {
   939           ret = -1;
   940         }
   941 
   942       if (sendline (server, "QUIT") || getok (server))
   943         {
   944           ret = -1;
   945         }
   946 
   947       close (server->file);
   948     }
   949 
   950   free (server->buffer);
   951   free ((char *) server);
   952 
   953   return (ret);
   954 }
   955 
   956 #ifdef WINDOWSNT
   957 static int have_winsock = 0;
   958 #endif
   959 
   960 /*
   961  * Function: socket_connection
   962  *
   963  * Purpose: Opens the network connection with the mail host, without
   964  *      doing any sort of I/O with it or anything.
   965  *
   966  * Arguments:
   967  *      host    The host to which to connect.
   968  *      flags   Option flags.
   969  *
   970  * Return value: A file descriptor indicating the connection, or -1
   971  *      indicating failure, in which case an error has been copied
   972  *      into pop_error.
   973  */
   974 static int
   975 socket_connection (char *host, int flags)
   976 {
   977   struct addrinfo *res, *it;
   978   struct addrinfo hints;
   979   int ret;
   980   struct servent *servent;
   981   struct sockaddr_in addr;
   982   char found_port = 0;
   983   const char *service;
   984   int sock;
   985   char *realhost;
   986 #ifdef KERBEROS
   987 #ifdef KERBEROS5
   988   krb5_error_code rem;
   989   krb5_context kcontext = 0;
   990   krb5_auth_context auth_context = 0;
   991   krb5_ccache ccdef;
   992   krb5_principal client, server;
   993   krb5_error *err_ret;
   994   register char *cp;
   995 #else
   996   KTEXT ticket;
   997   MSG_DAT msg_data;
   998   CREDENTIALS cred;
   999   Key_schedule schedule;
  1000   int rem;
  1001 #endif /* KERBEROS5 */
  1002 #endif /* KERBEROS */
  1003 
  1004   int try_count = 0;
  1005   int connect_ok;
  1006 
  1007 #ifdef WINDOWSNT
  1008   {
  1009     WSADATA winsockData;
  1010     if (WSAStartup (0x101, &winsockData) == 0)
  1011       have_winsock = 1;
  1012   }
  1013 #endif
  1014 
  1015   memset (&addr, 0, sizeof (addr));
  1016   addr.sin_family = AF_INET;
  1017 
  1018   /** "kpop" service is  never used: look for 20060515 to see why **/
  1019 #ifdef KERBEROS
  1020   service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE;
  1021 #else
  1022   service = POP_SERVICE;
  1023 #endif
  1024 
  1025 #ifdef HESIOD
  1026   if (! (flags & POP_NO_HESIOD))
  1027     {
  1028       servent = hes_getservbyname (service, "tcp");
  1029       if (servent)
  1030         {
  1031           addr.sin_port = servent->s_port;
  1032           found_port = 1;
  1033         }
  1034     }
  1035 #endif
  1036   if (! found_port)
  1037     {
  1038       servent = getservbyname (service, "tcp");
  1039       if (servent)
  1040         {
  1041           addr.sin_port = servent->s_port;
  1042         }
  1043       else
  1044         {
  1045   /** "kpop" service is  never used: look for 20060515 to see why **/
  1046 #ifdef KERBEROS
  1047           addr.sin_port = htons ((flags & POP_NO_KERBEROS) ?
  1048                                 POP_PORT : KPOP_PORT);
  1049 #else
  1050           addr.sin_port = htons (POP_PORT);
  1051 #endif
  1052         }
  1053     }
  1054 
  1055 #define POP_SOCKET_ERROR "Could not create socket for POP connection: "
  1056 
  1057   sock = socket (PF_INET, SOCK_STREAM, 0);
  1058   if (sock < 0)
  1059     {
  1060       snprintf (pop_error, ERROR_MAX, "%s%s",
  1061                 POP_SOCKET_ERROR, strerror (errno));
  1062       return (-1);
  1063 
  1064     }
  1065 
  1066   memset (&hints, 0, sizeof (hints));
  1067   hints.ai_socktype = SOCK_STREAM;
  1068   hints.ai_flags = AI_CANONNAME;
  1069   hints.ai_family = AF_INET;
  1070   do
  1071     {
  1072       ret = getaddrinfo (host, service, &hints, &res);
  1073       try_count++;
  1074       if (ret != 0 && (ret != EAI_AGAIN || try_count == 5))
  1075         {
  1076           strcpy (pop_error, "Could not determine POP server's address");
  1077           return (-1);
  1078         }
  1079     } while (ret != 0);
  1080 
  1081   for (it = res; it; it = it->ai_next)
  1082     if (it->ai_addrlen == sizeof addr)
  1083       {
  1084         struct sockaddr_in *in_a = (struct sockaddr_in *) it->ai_addr;
  1085         addr.sin_addr = in_a->sin_addr;
  1086         if (! connect (sock, (struct sockaddr *) &addr, sizeof addr))
  1087           break;
  1088       }
  1089   connect_ok = it != NULL;
  1090   if (connect_ok)
  1091     {
  1092       realhost = alloca (strlen (it->ai_canonname) + 1);
  1093       strcpy (realhost, it->ai_canonname);
  1094     }
  1095   freeaddrinfo (res);
  1096 
  1097 #define CONNECT_ERROR "Could not connect to POP server: "
  1098 
  1099   if (! connect_ok)
  1100     {
  1101       CLOSESOCKET (sock);
  1102       snprintf (pop_error, ERROR_MAX, "%s%s", CONNECT_ERROR, strerror (errno));
  1103       return (-1);
  1104 
  1105     }
  1106 
  1107 #ifdef KERBEROS
  1108 
  1109 #define KRB_ERROR "Kerberos error connecting to POP server: "
  1110   if (! (flags & POP_NO_KERBEROS))
  1111     {
  1112 #ifdef KERBEROS5
  1113       rem = krb5_init_context (&kcontext);
  1114       if (rem)
  1115         {
  1116         krb5error:
  1117           if (auth_context)
  1118             krb5_auth_con_free (kcontext, auth_context);
  1119           if (kcontext)
  1120             krb5_free_context (kcontext);
  1121           snprintf (pop_error, ERROR_MAX, "%s%s",
  1122                     KRB_ERROR, error_message (rem));
  1123           CLOSESOCKET (sock);
  1124           return (-1);
  1125         }
  1126 
  1127       rem = krb5_auth_con_init (kcontext, &auth_context);
  1128       if (rem)
  1129         goto krb5error;
  1130 
  1131       rem = krb5_cc_default (kcontext, &ccdef);
  1132       if (rem)
  1133         goto krb5error;
  1134 
  1135       rem = krb5_cc_get_principal (kcontext, ccdef, &client);
  1136       if (rem)
  1137         goto krb5error;
  1138 
  1139       for (cp = realhost; *cp; cp++)
  1140         *cp = c_tolower (*cp);
  1141 
  1142       rem = krb5_sname_to_principal (kcontext, realhost,
  1143                                      POP_SERVICE, FALSE, &server);
  1144       if (rem)
  1145         goto krb5error;
  1146 
  1147       rem = krb5_sendauth (kcontext, &auth_context,
  1148                            (krb5_pointer) &sock, (char *) "KPOPV1.0",
  1149                            client, server,
  1150                           AP_OPTS_MUTUAL_REQUIRED,
  1151                           0,    /* no checksum */
  1152                           0,    /* no creds, use ccache instead */
  1153                           ccdef,
  1154                           &err_ret,
  1155                           0,    /* don't need subsession key */
  1156                           0);   /* don't need reply */
  1157       krb5_free_principal (kcontext, server);
  1158       if (rem)
  1159         {
  1160           int pop_error_len = snprintf (pop_error, ERROR_MAX, "%s%s",
  1161                                         KRB_ERROR, error_message (rem));
  1162 #if defined HAVE_KRB5_ERROR_TEXT
  1163           if (err_ret && err_ret->text.length)
  1164             {
  1165               int errlen = err_ret->text.length;
  1166               snprintf (pop_error + pop_error_len, ERROR_MAX - pop_error_len,
  1167                         " [server says '%.*s']", errlen, err_ret->text.data);
  1168             }
  1169 #elif defined HAVE_KRB5_ERROR_E_TEXT
  1170           if (err_ret && err_ret->e_text && **err_ret->e_text)
  1171             snprintf (pop_error + pop_error_len, ERROR_MAX - pop_error_len,
  1172                       " [server says '%s']", *err_ret->e_text);
  1173 #endif
  1174           if (err_ret)
  1175             krb5_free_error (kcontext, err_ret);
  1176           krb5_auth_con_free (kcontext, auth_context);
  1177           krb5_free_context (kcontext);
  1178 
  1179           CLOSESOCKET (sock);
  1180           return (-1);
  1181         }
  1182 #else  /* ! KERBEROS5 */
  1183       ticket = (KTEXT) malloc (sizeof (KTEXT_ST));
  1184       rem = krb_sendauth (0L, sock, ticket, "pop", realhost,
  1185                           (char *) krb_realmofhost (realhost),
  1186                           (unsigned long) 0, &msg_data, &cred, schedule,
  1187                           (struct sockaddr_in *) 0,
  1188                           (struct sockaddr_in *) 0,
  1189                           "KPOPV0.1");
  1190       free ((char *) ticket);
  1191       if (rem != KSUCCESS)
  1192         {
  1193           snprintf (pop_error, ERROR_MAX, "%s%s", KRB_ERROR, krb_err_txt[rem]);
  1194           CLOSESOCKET (sock);
  1195           return (-1);
  1196         }
  1197 #endif /* KERBEROS5 */
  1198     }
  1199 #endif /* KERBEROS */
  1200 
  1201   return (sock);
  1202 } /* socket_connection */
  1203 
  1204 /*
  1205  * Function: pop_getline
  1206  *
  1207  * Purpose: Get a line of text from the connection and return a
  1208  *      pointer to it.  The carriage return and linefeed at the end of
  1209  *      the line are stripped, but periods at the beginnings of lines
  1210  *      are NOT dealt with in any special way.
  1211  *
  1212  * Arguments:
  1213  *      server  The server from which to get the line of text.
  1214  *
  1215  * Returns: The number of characters in the line, which is returned in
  1216  *      LINE, not including the final null.  A return value of 0
  1217  *      indicates a blank line.  A negative return value indicates an
  1218  *      error (in which case the contents of LINE are undefined.  In
  1219  *      case of error, an error message is copied into pop_error.
  1220  *
  1221  * Notes: The line returned is overwritten with each call to pop_getline.
  1222  *
  1223  * Side effects: Closes the connection on error.
  1224  *
  1225  * THE RETURNED LINE MAY CONTAIN EMBEDDED NULLS!
  1226  */
  1227 static int
  1228 pop_getline (popserver server, char **line)
  1229 {
  1230 #define GETLINE_ERROR "Error reading from server: "
  1231 
  1232   int ret;
  1233   int search_offset = 0;
  1234 
  1235   if (server->data)
  1236     {
  1237       char *cp = find_crlf (server->buffer + server->buffer_index,
  1238                             server->data);
  1239       if (cp)
  1240         {
  1241           int found;
  1242           int data_used;
  1243 
  1244           found = server->buffer_index;
  1245           data_used = (cp + 2) - server->buffer - found;
  1246 
  1247           *cp = '\0';           /* terminate the string to be returned */
  1248           server->data -= data_used;
  1249           server->buffer_index += data_used;
  1250 
  1251           if (pop_debug)
  1252             /* Embedded nulls will truncate this output prematurely,
  1253                but that's OK because it's just for debugging anyway. */
  1254             fprintf (stderr, "<<< %s\n", server->buffer + found);
  1255           *line = server->buffer + found;
  1256           return (data_used - 2);
  1257         }
  1258       else
  1259         {
  1260           memmove (server->buffer, server->buffer + server->buffer_index,
  1261                    server->data);
  1262           /* Record the fact that we've searched the data already in
  1263              the buffer for a CRLF, so that when we search below, we
  1264              don't have to search the same data twice.  There's a "-
  1265              1" here to account for the fact that the last character
  1266              of the data we have may be the CR of a CRLF pair, of
  1267              which we haven't read the second half yet, so we may have
  1268              to search it again when we read more data. */
  1269           search_offset = server->data - 1;
  1270           server->buffer_index = 0;
  1271         }
  1272     }
  1273   else
  1274     {
  1275       server->buffer_index = 0;
  1276     }
  1277 
  1278   while (true)
  1279     {
  1280       /* There's a "- 1" here to leave room for the null that we put
  1281          at the end of the read data below.  We put the null there so
  1282          that find_crlf knows where to stop when we call it. */
  1283       if (server->data == server->buffer_size - 1)
  1284         {
  1285           server->buffer_size += GETLINE_INCR;
  1286           server->buffer = (char *)realloc (server->buffer, server->buffer_size);
  1287           if (! server->buffer)
  1288             {
  1289               strcpy (pop_error, "Out of memory in pop_getline");
  1290               pop_trash (server);
  1291               break;
  1292             }
  1293         }
  1294       ret = RECV (server->file, server->buffer + server->data,
  1295                   server->buffer_size - server->data - 1, 0);
  1296       if (ret < 0)
  1297         {
  1298           snprintf (pop_error, ERROR_MAX, "%s%s",
  1299                     GETLINE_ERROR, strerror (errno));
  1300           pop_trash (server);
  1301           break;
  1302         }
  1303       else if (ret == 0)
  1304         {
  1305           strcpy (pop_error, "Unexpected EOF from server in pop_getline");
  1306           pop_trash (server);
  1307           break;
  1308         }
  1309       else
  1310         {
  1311           char *cp;
  1312           server->data += ret;
  1313           server->buffer[server->data] = '\0';
  1314 
  1315           cp = find_crlf (server->buffer + search_offset,
  1316                           server->data - search_offset);
  1317           if (cp)
  1318             {
  1319               int data_used = (cp + 2) - server->buffer;
  1320               *cp = '\0';
  1321               server->data -= data_used;
  1322               server->buffer_index = data_used;
  1323 
  1324               if (pop_debug)
  1325                 fprintf (stderr, "<<< %s\n", server->buffer);
  1326               *line = server->buffer;
  1327               return (data_used - 2);
  1328             }
  1329           /* As above, the "- 1" here is to account for the fact that
  1330              we may have read a CR without its accompanying LF. */
  1331           search_offset += ret - 1;
  1332         }
  1333     }
  1334 
  1335   return -1;
  1336 }
  1337 
  1338 /*
  1339  * Function: sendline
  1340  *
  1341  * Purpose: Sends a line of text to the POP server.  The line of text
  1342  *      passed into this function should NOT have the carriage return
  1343  *      and linefeed on the end of it.  Periods at beginnings of lines
  1344  *      will NOT be treated specially by this function.
  1345  *
  1346  * Arguments:
  1347  *      server  The server to which to send the text.
  1348  *      line    The line of text to send.
  1349  *
  1350  * Return value: Upon successful completion, a value of 0 will be
  1351  *      returned.  Otherwise, a non-zero value will be returned, and
  1352  *      an error will be copied into pop_error.
  1353  *
  1354  * Side effects: Closes the connection on error.
  1355  */
  1356 static int
  1357 sendline (popserver server, const char *line)
  1358 {
  1359 #define SENDLINE_ERROR "Error writing to POP server: "
  1360   int ret;
  1361   char *buf;
  1362 
  1363   /* Combine the string and the CR-LF into one buffer.  Otherwise, two
  1364      reasonable network stack optimizations, Nagle's algorithm and
  1365      delayed acks, combine to delay us a fraction of a second on every
  1366      message we send.  (Movemail writes line without \r\n, client
  1367      kernel sends packet, server kernel delays the ack to see if it
  1368      can combine it with data, movemail writes \r\n, client kernel
  1369      waits because it has unacked data already in its outgoing queue,
  1370      client kernel eventually times out and sends.)
  1371 
  1372      This can be something like 0.2s per command, which can add up
  1373      over a few dozen messages, and is a big chunk of the time we
  1374      spend fetching mail from a server close by.  */
  1375   buf = alloca (strlen (line) + 3);
  1376   strcpy (stpcpy (buf, line), "\r\n");
  1377   ret = fullwrite (server->file, buf, strlen (buf));
  1378 
  1379   if (ret < 0)
  1380     {
  1381       pop_trash (server);
  1382       snprintf (pop_error, ERROR_MAX, "%s%s", SENDLINE_ERROR, strerror (errno));
  1383       return (ret);
  1384     }
  1385 
  1386   if (pop_debug)
  1387     fprintf (stderr, ">>> %s\n", line);
  1388 
  1389   return (0);
  1390 }
  1391 
  1392 /*
  1393  * Procedure: fullwrite
  1394  *
  1395  * Purpose: Just like write, but keeps trying until the entire string
  1396  *      has been written.
  1397  *
  1398  * Return value: Same as write.  Pop_error is not set.
  1399  */
  1400 static int
  1401 fullwrite (int fd, char *buf, int nbytes)
  1402 {
  1403   char *cp;
  1404   int ret = 0;
  1405 
  1406   cp = buf;
  1407   while (nbytes && ((ret = SEND (fd, cp, nbytes, 0)) > 0))
  1408     {
  1409       cp += ret;
  1410       nbytes -= ret;
  1411     }
  1412 
  1413   return (ret);
  1414 }
  1415 
  1416 /*
  1417  * Procedure getok
  1418  *
  1419  * Purpose: Reads a line from the server.  If the return indicator is
  1420  *      positive, return with a zero exit status.  If not, return with
  1421  *      a negative exit status.
  1422  *
  1423  * Arguments:
  1424  *      server  The server to read from.
  1425  *
  1426  * Returns: 0 for success, else for failure and puts error in pop_error.
  1427  *
  1428  * Side effects: On failure, may make the connection unusable.
  1429  */
  1430 static int
  1431 getok (popserver server)
  1432 {
  1433   char *fromline;
  1434 
  1435   if (pop_getline (server, &fromline) < 0)
  1436     {
  1437       return (-1);
  1438     }
  1439 
  1440   if (! strncmp (fromline, "+OK", 3))
  1441     return (0);
  1442   else if (! strncmp (fromline, "-ERR", 4))
  1443     {
  1444       snprintf (pop_error, ERROR_MAX, "%s", fromline);
  1445       return (-1);
  1446     }
  1447   else
  1448     {
  1449       strcpy (pop_error,
  1450               "Unexpected response from server; expecting +OK or -ERR");
  1451       pop_trash (server);
  1452       return (-1);
  1453     }
  1454 }
  1455 
  1456 #if 0
  1457 /*
  1458  * Function: gettermination
  1459  *
  1460  * Purpose: Gets the next line and verifies that it is a termination
  1461  *      line (nothing but a dot).
  1462  *
  1463  * Return value: 0 on success, non-zero with pop_error set on error.
  1464  *
  1465  * Side effects: Closes the connection on error.
  1466  */
  1467 static int
  1468 gettermination (server)
  1469      popserver server;
  1470 {
  1471   char *fromserver;
  1472 
  1473   if (pop_getline (server, &fromserver) < 0)
  1474     return (-1);
  1475 
  1476   if (strcmp (fromserver, "."))
  1477     {
  1478       strcpy (pop_error,
  1479               "Unexpected response from server in gettermination");
  1480       pop_trash (server);
  1481       return (-1);
  1482     }
  1483 
  1484   return (0);
  1485 }
  1486 #endif
  1487 
  1488 /*
  1489  * Function pop_close
  1490  *
  1491  * Purpose: Close a pop connection, sending a "RSET" command to try to
  1492  *      preserve any changes that were made and a "QUIT" command to
  1493  *      try to get the server to quit, but ignoring any responses that
  1494  *      are received.
  1495  *
  1496  * Side effects: The server is unusable after this function returns.
  1497  *      Changes made to the maildrop since the session was started (or
  1498  *      since the last pop_reset) may be lost.
  1499  */
  1500 void
  1501 pop_close (popserver server)
  1502 {
  1503   pop_trash (server);
  1504   free ((char *) server);
  1505 
  1506   return;
  1507 }
  1508 
  1509 /*
  1510  * Function: pop_trash
  1511  *
  1512  * Purpose: Like pop_close or pop_quit, but doesn't deallocate the
  1513  *      memory associated with the server.  It is valid to call
  1514  *      pop_close or pop_quit after this function has been called.
  1515  */
  1516 static void
  1517 pop_trash (popserver server)
  1518 {
  1519   if (server->file >= 0)
  1520     {
  1521       /* avoid recursion; sendline can call pop_trash */
  1522       if (server->trash_started)
  1523         return;
  1524       server->trash_started = true;
  1525 
  1526       sendline (server, "RSET");
  1527       sendline (server, "QUIT");
  1528 
  1529       CLOSESOCKET (server->file);
  1530       server->file = -1;
  1531       if (server->buffer)
  1532         {
  1533           free (server->buffer);
  1534           server->buffer = 0;
  1535         }
  1536     }
  1537 
  1538 #ifdef WINDOWSNT
  1539   if (have_winsock)
  1540     WSACleanup ();
  1541 #endif
  1542 }
  1543 
  1544 /* Return a pointer to the first CRLF in IN_STRING, which can contain
  1545    embedded nulls and has LEN characters in it not including the final
  1546    null, or 0 if it does not contain one.  */
  1547 
  1548 static char *
  1549 find_crlf (char *in_string, int len)
  1550 {
  1551   while (len--)
  1552     {
  1553       if (*in_string == '\r')
  1554         {
  1555           if (*++in_string == '\n')
  1556             return (in_string - 1);
  1557         }
  1558       else
  1559         in_string++;
  1560     }
  1561   return (0);
  1562 }
  1563 
  1564 #ifdef WINDOWSNT
  1565 /* The following 2 functions are only available since XP, so we load
  1566    them dynamically and provide fallbacks.  */
  1567 
  1568 int (WINAPI *pfn_getaddrinfo) (const char *, const char *,
  1569                                const struct addrinfo *, struct addrinfo **);
  1570 void (WINAPI *pfn_freeaddrinfo) (struct addrinfo *);
  1571 
  1572 static int
  1573 load_ws2 (void)
  1574 {
  1575   static int ws2_loaded = 0;
  1576 
  1577   if (!ws2_loaded)
  1578     {
  1579       HANDLE ws2_lib = LoadLibrary ("Ws2_32.dll");
  1580 
  1581       if (ws2_lib != NULL)
  1582         {
  1583           ws2_loaded = 1;
  1584           pfn_getaddrinfo = (void *) GetProcAddress (ws2_lib, "getaddrinfo");
  1585           pfn_freeaddrinfo = (void *) GetProcAddress (ws2_lib, "freeaddrinfo");
  1586           /* Paranoia: these two functions should go together, so if
  1587              one is absent, we cannot use the other.  */
  1588           if (pfn_getaddrinfo == NULL)
  1589             pfn_freeaddrinfo = NULL;
  1590           else if (pfn_freeaddrinfo == NULL)
  1591             pfn_getaddrinfo = NULL;
  1592         }
  1593     }
  1594   if (!ws2_loaded)
  1595     {
  1596       errno = ENETDOWN;
  1597       return -1;
  1598     }
  1599   return 0;
  1600 }
  1601 
  1602 
  1603 int
  1604 sys_getaddrinfo (const char *node, const char *service,
  1605                  const struct addrinfo *hints, struct addrinfo **res)
  1606 {
  1607   int rc;
  1608 
  1609   if (load_ws2 () != 0)
  1610     {
  1611       errno = ENETDOWN;
  1612       return WSANO_RECOVERY;
  1613     }
  1614 
  1615   if (pfn_getaddrinfo)
  1616     rc = pfn_getaddrinfo (node, service, hints, res);
  1617   else
  1618     {
  1619       int port = 0;
  1620       struct hostent *host_info;
  1621       struct gai_storage {
  1622         struct addrinfo addrinfo;
  1623         struct sockaddr_in sockaddr_in;
  1624       } *gai_storage;
  1625 
  1626       /* We don't support any flags besides AI_CANONNAME.  */
  1627       if (hints && (hints->ai_flags & ~(AI_CANONNAME)) != 0)
  1628         return WSAEINVAL;
  1629       /* NODE cannot be NULL, since pop.c has fallbacks for that.  */
  1630       if (!node)
  1631         return WSAHOST_NOT_FOUND;
  1632 
  1633       if (service)
  1634         {
  1635           const char *protocol =
  1636             (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
  1637           struct servent *srv = getservbyname (service, protocol);
  1638 
  1639           if (srv)
  1640             port = srv->s_port;
  1641           else
  1642             return WSAHOST_NOT_FOUND;
  1643         }
  1644 
  1645       gai_storage = calloc (1, sizeof *gai_storage);
  1646       gai_storage->sockaddr_in.sin_port = port;
  1647       host_info = gethostbyname (node);
  1648       if (host_info)
  1649         {
  1650           memcpy (&gai_storage->sockaddr_in.sin_addr,
  1651                   host_info->h_addr, host_info->h_length);
  1652           gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
  1653         }
  1654       else
  1655         {
  1656           free (gai_storage);
  1657           return WSAHOST_NOT_FOUND;
  1658         }
  1659 
  1660       gai_storage->addrinfo.ai_addr =
  1661         (struct sockaddr *)&gai_storage->sockaddr_in;
  1662       gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
  1663       if (hints && (hints->ai_flags & AI_CANONNAME) != 0)
  1664         {
  1665           gai_storage->addrinfo.ai_canonname = strdup (host_info->h_name);
  1666           if (!gai_storage->addrinfo.ai_canonname)
  1667             {
  1668               free (gai_storage);
  1669               return WSA_NOT_ENOUGH_MEMORY;
  1670             }
  1671         }
  1672       gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
  1673       gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
  1674       gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
  1675       gai_storage->addrinfo.ai_next = NULL;
  1676 
  1677       *res = &gai_storage->addrinfo;
  1678       rc = 0;
  1679     }
  1680 
  1681   return rc;
  1682 }
  1683 
  1684 void
  1685 sys_freeaddrinfo (struct addrinfo *ai)
  1686 {
  1687   if (load_ws2 () != 0)
  1688     {
  1689       errno = ENETDOWN;
  1690       return;
  1691     }
  1692 
  1693   if (pfn_freeaddrinfo)
  1694     pfn_freeaddrinfo (ai);
  1695   else
  1696     {
  1697       if (ai->ai_canonname)
  1698         free (ai->ai_canonname);
  1699       free (ai);
  1700     }
  1701 }
  1702 #endif  /* WINDOWSNT */
  1703 #endif /* MAIL_USE_POP */

/* [<][>][^][v][top][bottom][index][help] */