Don’t create fd >= FD_SETSIZE
[emacs.git] / lib-src / pop.c
blob99ec1cf824aace256c29d70e5eca7c866acacbfe
1 /* pop.c: client routines for talking to a POP3-protocol post-office server
3 Copyright (C) 1991, 1993, 1996-1997, 1999, 2001-2016 Free Software
4 Foundation, Inc.
6 Author: Jonathan Kamens <jik@security.ov.com>
8 This file is part of GNU Emacs.
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.
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.
20 You should have received a copy of the GNU General Public License
21 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
24 #include <config.h>
26 #ifdef MAIL_USE_POP
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 #include <winsock2.h>
34 #include <ws2tcpip.h>
35 #undef getaddrinfo
36 #define getaddrinfo sys_getaddrinfo
37 #undef freeaddrinfo
38 #define freeaddrinfo sys_freeaddrinfo
39 int sys_getaddrinfo (const char * node, const char * service,
40 const struct addrinfo * hints, struct addrinfo ** res);
41 void sys_freeaddrinfo (struct addrinfo * ai);
42 #undef SOCKET_ERROR
43 #define RECV(s,buf,len,flags) recv (s,buf,len,flags)
44 #define SEND(s,buf,len,flags) send (s,buf,len,flags)
45 #define CLOSESOCKET(s) closesocket (s)
46 #else
47 #include <netinet/in.h>
48 #include <sys/socket.h>
49 #define RECV(s,buf,len,flags) read (s,buf,len)
50 #define SEND(s,buf,len,flags) write (s,buf,len)
51 #define CLOSESOCKET(s) close (s)
52 #endif
53 #include <pop.h>
55 #ifdef HESIOD
56 #include <hesiod.h>
58 * It really shouldn't be necessary to put this declaration here, but
59 * the version of hesiod.h that Athena has installed in release 7.2
60 * doesn't declare this function; I don't know if the 7.3 version of
61 * hesiod.h does.
63 extern struct servent *hes_getservbyname (/* char *, char * */);
64 #endif
66 #include <pwd.h>
67 #include <netdb.h>
68 #include <errno.h>
69 #include <stdio.h>
70 #include <string.h>
71 #include <unistd.h>
73 #ifdef KERBEROS
74 # ifdef HAVE_KRB5_H
75 # include <krb5.h>
76 # endif
77 # ifdef HAVE_KRB_H
78 # include <krb.h>
79 # else
80 # ifdef HAVE_KERBEROSIV_KRB_H
81 # include <kerberosIV/krb.h>
82 # else
83 # ifdef HAVE_KERBEROS_KRB_H
84 # include <kerberos/krb.h>
85 # endif
86 # endif
87 # endif
88 # ifdef HAVE_COM_ERR_H
89 # include <com_err.h>
90 # endif
91 #endif /* KERBEROS */
93 #include <c-ctype.h>
94 #include <min-max.h>
96 #ifdef KERBEROS
97 #ifndef KERBEROS5
98 extern int krb_sendauth (/* long, int, KTEXT, char *, char *, char *,
99 u_long, MSG_DAT *, CREDENTIALS *, Key_schedule,
100 struct sockaddr_in *, struct sockaddr_in *,
101 char * */);
102 extern char *krb_realmofhost (/* char * */);
103 #endif /* ! KERBEROS5 */
104 #endif /* KERBEROS */
106 static int socket_connection (char *, int);
107 static int pop_getline (popserver, char **);
108 static int sendline (popserver, const char *);
109 static int fullwrite (int, char *, int);
110 static int getok (popserver);
111 #if 0
112 static int gettermination (popserver);
113 #endif
114 static void pop_trash (popserver);
115 static char *find_crlf (char *, int);
117 #define ERROR_MAX 160 /* a pretty arbitrary size, but needs
118 to be bigger than the original
119 value of 80 */
120 #define POP_PORT 110
121 #define POP_SERVICE "pop3" /* we don't want the POP2 port! */
122 #ifdef KERBEROS
123 #define KPOP_PORT 1109
124 #define KPOP_SERVICE "kpop" /* never used: look for 20060515 to see why */
125 #endif
127 char pop_error[ERROR_MAX];
128 bool pop_debug = false;
131 * Function: pop_open (char *host, char *username, char *password,
132 * int flags)
134 * Purpose: Establishes a connection with a post-office server, and
135 * completes the authorization portion of the session.
137 * Arguments:
138 * host The server host with which the connection should be
139 * established. Optional. If omitted, internal
140 * heuristics will be used to determine the server host,
141 * if possible.
142 * username
143 * The username of the mail-drop to access. Optional.
144 * If omitted, internal heuristics will be used to
145 * determine the username, if possible.
146 * password
147 * The password to use for authorization. If omitted,
148 * internal heuristics will be used to determine the
149 * password, if possible.
150 * flags A bit mask containing flags controlling certain
151 * functions of the routine. Valid flags are defined in
152 * the file pop.h
154 * Return value: Upon successful establishment of a connection, a
155 * non-null popserver will be returned. Otherwise, null will be
156 * returned, and the string variable pop_error will contain an
157 * explanation of the error.
159 popserver
160 pop_open (char *host, char *username, char *password, int flags)
162 int sock;
163 popserver server;
165 /* Determine the user name */
166 if (! username)
168 username = getenv ("USER");
169 if (! (username && *username))
171 username = getlogin ();
172 if (! (username && *username))
174 struct passwd *passwd;
175 passwd = getpwuid (getuid ());
176 if (passwd && passwd->pw_name && *passwd->pw_name)
178 username = passwd->pw_name;
180 else
182 strcpy (pop_error, "Could not determine username");
183 return (0);
190 * Determine the mail host.
193 if (! host)
195 host = getenv ("MAILHOST");
198 #ifdef HESIOD
199 if ((! host) && (! (flags & POP_NO_HESIOD)))
201 struct hes_postoffice *office;
202 office = hes_getmailhost (username);
203 if (office && office->po_type && (! strcmp (office->po_type, "POP"))
204 && office->po_name && *office->po_name && office->po_host
205 && *office->po_host)
207 host = office->po_host;
208 username = office->po_name;
211 #endif
213 #ifdef MAILHOST
214 if (! host)
216 host = MAILHOST;
218 #endif
220 if (! host)
222 strcpy (pop_error, "Could not determine POP server");
223 return (0);
226 /* Determine the password */
227 #ifdef KERBEROS
228 #define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS))
229 #else
230 #define DONT_NEED_PASSWORD 0
231 #endif
233 if ((! password) && (! DONT_NEED_PASSWORD))
235 if (! (flags & POP_NO_GETPASS))
237 password = getpass ("Enter POP password:");
239 if (! password)
241 strcpy (pop_error, "Could not determine POP password");
242 return (0);
245 if (password) /* always true, detected 20060515 */
246 flags |= POP_NO_KERBEROS;
247 else
248 password = username; /* dead code, detected 20060515 */
249 /** "kpop" service is never used: look for 20060515 to see why **/
251 sock = socket_connection (host, flags);
252 if (sock == -1)
253 return (0);
255 server = (popserver) malloc (sizeof (struct _popserver));
256 if (! server)
258 strcpy (pop_error, "Out of memory in pop_open");
259 return (0);
261 server->buffer = (char *) malloc (GETLINE_MIN);
262 if (! server->buffer)
264 strcpy (pop_error, "Out of memory in pop_open");
265 free ((char *) server);
266 return (0);
269 server->file = sock;
270 server->data = 0;
271 server->buffer_index = 0;
272 server->buffer_size = GETLINE_MIN;
273 server->in_multi = false;
274 server->trash_started = false;
276 if (getok (server))
277 return (0);
280 * I really shouldn't use the pop_error variable like this, but....
282 if (strlen (username) > ERROR_MAX - 6)
284 pop_close (server);
285 strcpy (pop_error,
286 "Username too long; recompile pop.c with larger ERROR_MAX");
287 return (0);
289 sprintf (pop_error, "USER %s", username);
291 if (sendline (server, pop_error) || getok (server))
293 return (0);
296 if (strlen (password) > ERROR_MAX - 6)
298 pop_close (server);
299 strcpy (pop_error,
300 "Password too long; recompile pop.c with larger ERROR_MAX");
301 return (0);
303 sprintf (pop_error, "PASS %s", password);
305 if (sendline (server, pop_error) || getok (server))
307 return (0);
310 return (server);
314 * Function: pop_stat
316 * Purpose: Issue the STAT command to the server and return (in the
317 * value parameters) the number of messages in the maildrop and
318 * the total size of the maildrop.
320 * Return value: 0 on success, or non-zero with an error in pop_error
321 * in failure.
323 * Side effects: On failure, may make further operations on the
324 * connection impossible.
327 pop_stat (popserver server, int *count, int *size)
329 char *fromserver;
330 char *end_ptr;
332 if (server->in_multi)
334 strcpy (pop_error, "In multi-line query in pop_stat");
335 return (-1);
338 if (sendline (server, "STAT") || (pop_getline (server, &fromserver) < 0))
339 return (-1);
341 if (strncmp (fromserver, "+OK ", 4))
343 if (0 == strncmp (fromserver, "-ERR", 4))
344 snprintf (pop_error, ERROR_MAX, "%s", fromserver);
345 else
347 strcpy (pop_error,
348 "Unexpected response from POP server in pop_stat");
349 pop_trash (server);
351 return (-1);
354 errno = 0;
355 *count = strtol (&fromserver[4], &end_ptr, 10);
356 /* Check validity of string-to-integer conversion. */
357 if (fromserver + 4 == end_ptr || *end_ptr != ' ' || errno)
359 strcpy (pop_error, "Unexpected response from POP server in pop_stat");
360 pop_trash (server);
361 return (-1);
364 fromserver = end_ptr;
366 errno = 0;
367 *size = strtol (fromserver + 1, &end_ptr, 10);
368 if (fromserver + 1 == end_ptr || errno)
370 strcpy (pop_error, "Unexpected response from POP server in pop_stat");
371 pop_trash (server);
372 return (-1);
375 return (0);
379 * Function: pop_list
381 * Purpose: Performs the POP "list" command and returns (in value
382 * parameters) two malloc'd zero-terminated arrays -- one of
383 * message IDs, and a parallel one of sizes.
385 * Arguments:
386 * server The pop connection to talk to.
387 * message The number of the one message about which to get
388 * information, or 0 to get information about all
389 * messages.
391 * Return value: 0 on success, non-zero with error in pop_error on
392 * failure.
394 * Side effects: On failure, may make further operations on the
395 * connection impossible.
398 pop_list (popserver server, int message, int **IDs, int **sizes)
400 int how_many, i;
401 char *fromserver;
403 if (server->in_multi)
405 strcpy (pop_error, "In multi-line query in pop_list");
406 return (-1);
409 if (message)
410 how_many = 1;
411 else
413 int count, size;
414 if (pop_stat (server, &count, &size))
415 return (-1);
416 how_many = count;
419 *IDs = (int *) malloc ((how_many + 1) * sizeof (int));
420 *sizes = (int *) malloc ((how_many + 1) * sizeof (int));
421 if (! (*IDs && *sizes))
423 strcpy (pop_error, "Out of memory in pop_list");
424 return (-1);
427 if (message)
429 sprintf (pop_error, "LIST %d", message);
430 if (sendline (server, pop_error))
432 free ((char *) *IDs);
433 free ((char *) *sizes);
434 return (-1);
436 if (pop_getline (server, &fromserver) < 0)
438 free ((char *) *IDs);
439 free ((char *) *sizes);
440 return (-1);
442 if (strncmp (fromserver, "+OK ", 4))
444 if (! strncmp (fromserver, "-ERR", 4))
445 snprintf (pop_error, ERROR_MAX, "%s", fromserver);
446 else
448 strcpy (pop_error,
449 "Unexpected response from server in pop_list");
450 pop_trash (server);
452 free ((char *) *IDs);
453 free ((char *) *sizes);
454 return (-1);
456 (*IDs)[0] = atoi (&fromserver[4]);
457 fromserver = strchr (&fromserver[4], ' ');
458 if (! fromserver)
460 strcpy (pop_error,
461 "Badly formatted response from server in pop_list");
462 pop_trash (server);
463 free ((char *) *IDs);
464 free ((char *) *sizes);
465 return (-1);
467 (*sizes)[0] = atoi (fromserver);
468 (*IDs)[1] = (*sizes)[1] = 0;
469 return (0);
471 else
473 if (pop_multi_first (server, "LIST", &fromserver))
475 free ((char *) *IDs);
476 free ((char *) *sizes);
477 return (-1);
479 for (i = 0; i < how_many; i++)
481 if (pop_multi_next (server, &fromserver) <= 0)
483 free ((char *) *IDs);
484 free ((char *) *sizes);
485 return (-1);
487 (*IDs)[i] = atoi (fromserver);
488 fromserver = strchr (fromserver, ' ');
489 if (! fromserver)
491 strcpy (pop_error,
492 "Badly formatted response from server in pop_list");
493 free ((char *) *IDs);
494 free ((char *) *sizes);
495 pop_trash (server);
496 return (-1);
498 (*sizes)[i] = atoi (fromserver);
500 if (pop_multi_next (server, &fromserver) < 0)
502 free ((char *) *IDs);
503 free ((char *) *sizes);
504 return (-1);
506 else if (fromserver)
508 strcpy (pop_error,
509 "Too many response lines from server in pop_list");
510 free ((char *) *IDs);
511 free ((char *) *sizes);
512 return (-1);
514 (*IDs)[i] = (*sizes)[i] = 0;
515 return (0);
520 * Function: pop_retrieve
522 * Purpose: Retrieve a specified message from the maildrop.
524 * Arguments:
525 * server The server to retrieve from.
526 * message The message number to retrieve.
527 * markfrom
528 * If true, then mark the string "From " at the beginning
529 * of lines with '>'.
530 * msg_buf Output parameter to which a buffer containing the
531 * message is assigned.
533 * Return value: The number of bytes in msg_buf, which may contain
534 * embedded nulls, not including its final null, or -1 on error
535 * with pop_error set.
537 * Side effects: May kill connection on error.
540 pop_retrieve (popserver server, int message, int markfrom, char **msg_buf)
542 int *IDs, *sizes, bufsize, fromcount = 0, cp = 0;
543 char *ptr, *fromserver;
544 int ret;
546 if (server->in_multi)
548 strcpy (pop_error, "In multi-line query in pop_retrieve");
549 return (-1);
552 if (pop_list (server, message, &IDs, &sizes))
553 return (-1);
555 if (pop_retrieve_first (server, message, &fromserver))
557 return (-1);
561 * The "5" below is an arbitrary constant -- I assume that if
562 * there are "From" lines in the text to be marked, there
563 * probably won't be more than 5 of them. If there are, I
564 * allocate more space for them below.
566 bufsize = sizes[0] + (markfrom ? 5 : 0);
567 ptr = (char *)malloc (bufsize);
568 free ((char *) IDs);
569 free ((char *) sizes);
571 if (! ptr)
573 strcpy (pop_error, "Out of memory in pop_retrieve");
574 pop_retrieve_flush (server);
575 return (-1);
578 while ((ret = pop_retrieve_next (server, &fromserver)) >= 0)
580 if (! fromserver)
582 ptr[cp] = '\0';
583 *msg_buf = ptr;
584 return (cp);
586 if (markfrom && fromserver[0] == 'F' && fromserver[1] == 'r' &&
587 fromserver[2] == 'o' && fromserver[3] == 'm' &&
588 fromserver[4] == ' ')
590 if (++fromcount == 5)
592 bufsize += 5;
593 ptr = (char *)realloc (ptr, bufsize);
594 if (! ptr)
596 strcpy (pop_error, "Out of memory in pop_retrieve");
597 pop_retrieve_flush (server);
598 return (-1);
600 fromcount = 0;
602 ptr[cp++] = '>';
604 memcpy (&ptr[cp], fromserver, ret);
605 cp += ret;
606 ptr[cp++] = '\n';
609 free (ptr);
610 return (-1);
614 pop_retrieve_first (popserver server, int message, char **response)
616 sprintf (pop_error, "RETR %d", message);
617 return (pop_multi_first (server, pop_error, response));
621 Returns a negative number on error, 0 to indicate that the data has
622 all been read (i.e., the server has returned a "." termination
623 line), or a positive number indicating the number of bytes in the
624 returned buffer (which is null-terminated and may contain embedded
625 nulls, but the returned bytecount doesn't include the final null).
629 pop_retrieve_next (popserver server, char **line)
631 return (pop_multi_next (server, line));
635 pop_retrieve_flush (popserver server)
637 return (pop_multi_flush (server));
641 pop_top_first (popserver server, int message, int lines, char **response)
643 sprintf (pop_error, "TOP %d %d", message, lines);
644 return (pop_multi_first (server, pop_error, response));
648 Returns a negative number on error, 0 to indicate that the data has
649 all been read (i.e., the server has returned a "." termination
650 line), or a positive number indicating the number of bytes in the
651 returned buffer (which is null-terminated and may contain embedded
652 nulls, but the returned bytecount doesn't include the final null).
656 pop_top_next (popserver server, char **line)
658 return (pop_multi_next (server, line));
662 pop_top_flush (popserver server)
664 return (pop_multi_flush (server));
668 pop_multi_first (popserver server, const char *command, char **response)
670 if (server->in_multi)
672 strcpy (pop_error,
673 "Already in multi-line query in pop_multi_first");
674 return (-1);
677 if (sendline (server, command) || (pop_getline (server, response) < 0))
679 return (-1);
682 if (0 == strncmp (*response, "-ERR", 4))
684 snprintf (pop_error, ERROR_MAX, "%s", *response);
685 return (-1);
687 else if (0 == strncmp (*response, "+OK", 3))
689 for (*response += 3; **response == ' '; (*response)++) /* empty */;
690 server->in_multi = true;
691 return (0);
693 else
695 strcpy (pop_error,
696 "Unexpected response from server in pop_multi_first");
697 return (-1);
702 Read the next line of data from SERVER and place a pointer to it
703 into LINE. Return -1 on error, 0 if there are no more lines to read
704 (i.e., the server has returned a line containing only "."), or a
705 positive number indicating the number of bytes in the LINE buffer
706 (not including the final null). The data in that buffer may contain
707 embedded nulls, but does not contain the final CRLF. When returning
708 0, LINE is set to null. */
711 pop_multi_next (popserver server, char **line)
713 char *fromserver;
714 int ret;
716 if (! server->in_multi)
718 strcpy (pop_error, "Not in multi-line query in pop_multi_next");
719 return (-1);
722 ret = pop_getline (server, &fromserver);
723 if (ret < 0)
725 return (-1);
728 if (fromserver[0] == '.')
730 if (! fromserver[1])
732 *line = 0;
733 server->in_multi = false;
734 return (0);
736 else
738 *line = fromserver + 1;
739 return (ret - 1);
742 else
744 *line = fromserver;
745 return (ret);
750 pop_multi_flush (popserver server)
752 char *line;
753 int ret;
755 if (! server->in_multi)
757 return (0);
760 while ((ret = pop_multi_next (server, &line)))
762 if (ret < 0)
763 return (-1);
766 return (0);
769 /* Function: pop_delete
771 * Purpose: Delete a specified message.
773 * Arguments:
774 * server Server from which to delete the message.
775 * message Message to delete.
777 * Return value: 0 on success, non-zero with error in pop_error
778 * otherwise.
781 pop_delete (popserver server, int message)
783 if (server->in_multi)
785 strcpy (pop_error, "In multi-line query in pop_delete");
786 return (-1);
789 sprintf (pop_error, "DELE %d", message);
791 if (sendline (server, pop_error) || getok (server))
792 return (-1);
794 return (0);
798 * Function: pop_noop
800 * Purpose: Send a noop command to the server.
802 * Argument:
803 * server The server to send to.
805 * Return value: 0 on success, non-zero with error in pop_error
806 * otherwise.
808 * Side effects: Closes connection on error.
811 pop_noop (popserver server)
813 if (server->in_multi)
815 strcpy (pop_error, "In multi-line query in pop_noop");
816 return (-1);
819 if (sendline (server, "NOOP") || getok (server))
820 return (-1);
822 return (0);
826 * Function: pop_last
828 * Purpose: Find out the highest seen message from the server.
830 * Arguments:
831 * server The server.
833 * Return value: If successful, the highest seen message, which is
834 * greater than or equal to 0. Otherwise, a negative number with
835 * the error explained in pop_error.
837 * Side effects: Closes the connection on error.
840 pop_last (popserver server)
842 char *fromserver;
844 if (server->in_multi)
846 strcpy (pop_error, "In multi-line query in pop_last");
847 return (-1);
850 if (sendline (server, "LAST"))
851 return (-1);
853 if (pop_getline (server, &fromserver) < 0)
854 return (-1);
856 if (! strncmp (fromserver, "-ERR", 4))
858 snprintf (pop_error, ERROR_MAX, "%s", fromserver);
859 return (-1);
861 else if (strncmp (fromserver, "+OK ", 4))
863 strcpy (pop_error, "Unexpected response from server in pop_last");
864 pop_trash (server);
865 return (-1);
867 else
869 char *end_ptr;
870 int count;
871 errno = 0;
872 count = strtol (&fromserver[4], &end_ptr, 10);
873 if (fromserver + 4 == end_ptr || errno)
875 strcpy (pop_error, "Unexpected response from server in pop_last");
876 pop_trash (server);
877 return (-1);
879 return count;
884 * Function: pop_reset
886 * Purpose: Reset the server to its initial connect state
888 * Arguments:
889 * server The server.
891 * Return value: 0 for success, non-0 with error in pop_error
892 * otherwise.
894 * Side effects: Closes the connection on error.
897 pop_reset (popserver server)
899 if (pop_retrieve_flush (server))
901 return (-1);
904 if (sendline (server, "RSET") || getok (server))
905 return (-1);
907 return (0);
911 * Function: pop_quit
913 * Purpose: Quit the connection to the server,
915 * Arguments:
916 * server The server to quit.
918 * Return value: 0 for success, non-zero otherwise with error in
919 * pop_error.
921 * Side Effects: The popserver passed in is unusable after this
922 * function is called, even if an error occurs.
925 pop_quit (popserver server)
927 int ret = 0;
929 if (server->file >= 0)
931 if (pop_retrieve_flush (server))
933 ret = -1;
936 if (sendline (server, "QUIT") || getok (server))
938 ret = -1;
941 close (server->file);
944 free (server->buffer);
945 free ((char *) server);
947 return (ret);
950 #ifdef WINDOWSNT
951 static int have_winsock = 0;
952 #endif
955 * Function: socket_connection
957 * Purpose: Opens the network connection with the mail host, without
958 * doing any sort of I/O with it or anything.
960 * Arguments:
961 * host The host to which to connect.
962 * flags Option flags.
964 * Return value: A file descriptor indicating the connection, or -1
965 * indicating failure, in which case an error has been copied
966 * into pop_error.
968 static int
969 socket_connection (char *host, int flags)
971 struct addrinfo *res, *it;
972 struct addrinfo hints;
973 int ret;
974 struct servent *servent;
975 struct sockaddr_in addr;
976 char found_port = 0;
977 const char *service;
978 int sock;
979 char *realhost;
980 #ifdef KERBEROS
981 #ifdef KERBEROS5
982 krb5_error_code rem;
983 krb5_context kcontext = 0;
984 krb5_auth_context auth_context = 0;
985 krb5_ccache ccdef;
986 krb5_principal client, server;
987 krb5_error *err_ret;
988 register char *cp;
989 #else
990 KTEXT ticket;
991 MSG_DAT msg_data;
992 CREDENTIALS cred;
993 Key_schedule schedule;
994 int rem;
995 #endif /* KERBEROS5 */
996 #endif /* KERBEROS */
998 int try_count = 0;
999 int connect_ok;
1001 #ifdef WINDOWSNT
1003 WSADATA winsockData;
1004 if (WSAStartup (0x101, &winsockData) == 0)
1005 have_winsock = 1;
1007 #endif
1009 memset (&addr, 0, sizeof (addr));
1010 addr.sin_family = AF_INET;
1012 /** "kpop" service is never used: look for 20060515 to see why **/
1013 #ifdef KERBEROS
1014 service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE;
1015 #else
1016 service = POP_SERVICE;
1017 #endif
1019 #ifdef HESIOD
1020 if (! (flags & POP_NO_HESIOD))
1022 servent = hes_getservbyname (service, "tcp");
1023 if (servent)
1025 addr.sin_port = servent->s_port;
1026 found_port = 1;
1029 #endif
1030 if (! found_port)
1032 servent = getservbyname (service, "tcp");
1033 if (servent)
1035 addr.sin_port = servent->s_port;
1037 else
1039 /** "kpop" service is never used: look for 20060515 to see why **/
1040 #ifdef KERBEROS
1041 addr.sin_port = htons ((flags & POP_NO_KERBEROS) ?
1042 POP_PORT : KPOP_PORT);
1043 #else
1044 addr.sin_port = htons (POP_PORT);
1045 #endif
1049 #define POP_SOCKET_ERROR "Could not create socket for POP connection: "
1051 sock = socket (PF_INET, SOCK_STREAM, 0);
1052 if (sock < 0)
1054 snprintf (pop_error, ERROR_MAX, "%s%s",
1055 POP_SOCKET_ERROR, strerror (errno));
1056 return (-1);
1060 memset (&hints, 0, sizeof (hints));
1061 hints.ai_socktype = SOCK_STREAM;
1062 hints.ai_flags = AI_CANONNAME;
1063 hints.ai_family = AF_INET;
1066 ret = getaddrinfo (host, service, &hints, &res);
1067 try_count++;
1068 if (ret != 0 && (ret != EAI_AGAIN || try_count == 5))
1070 strcpy (pop_error, "Could not determine POP server's address");
1071 return (-1);
1073 } while (ret != 0);
1075 for (it = res; it; it = it->ai_next)
1076 if (it->ai_addrlen == sizeof addr)
1078 struct sockaddr_in *in_a = (struct sockaddr_in *) it->ai_addr;
1079 addr.sin_addr = in_a->sin_addr;
1080 if (! connect (sock, (struct sockaddr *) &addr, sizeof addr))
1081 break;
1083 connect_ok = it != NULL;
1084 if (connect_ok)
1086 realhost = alloca (strlen (it->ai_canonname) + 1);
1087 strcpy (realhost, it->ai_canonname);
1089 freeaddrinfo (res);
1091 #define CONNECT_ERROR "Could not connect to POP server: "
1093 if (! connect_ok)
1095 CLOSESOCKET (sock);
1096 snprintf (pop_error, ERROR_MAX, "%s%s", CONNECT_ERROR, strerror (errno));
1097 return (-1);
1101 #ifdef KERBEROS
1103 #define KRB_ERROR "Kerberos error connecting to POP server: "
1104 if (! (flags & POP_NO_KERBEROS))
1106 #ifdef KERBEROS5
1107 rem = krb5_init_context (&kcontext);
1108 if (rem)
1110 krb5error:
1111 if (auth_context)
1112 krb5_auth_con_free (kcontext, auth_context);
1113 if (kcontext)
1114 krb5_free_context (kcontext);
1115 snprintf (pop_error, ERROR_MAX, "%s%s",
1116 KRB_ERROR, error_message (rem));
1117 CLOSESOCKET (sock);
1118 return (-1);
1121 rem = krb5_auth_con_init (kcontext, &auth_context);
1122 if (rem)
1123 goto krb5error;
1125 rem = krb5_cc_default (kcontext, &ccdef);
1126 if (rem)
1127 goto krb5error;
1129 rem = krb5_cc_get_principal (kcontext, ccdef, &client);
1130 if (rem)
1131 goto krb5error;
1133 for (cp = realhost; *cp; cp++)
1134 *cp = c_tolower (*cp);
1136 rem = krb5_sname_to_principal (kcontext, realhost,
1137 POP_SERVICE, FALSE, &server);
1138 if (rem)
1139 goto krb5error;
1141 rem = krb5_sendauth (kcontext, &auth_context,
1142 (krb5_pointer) &sock, (char *) "KPOPV1.0",
1143 client, server,
1144 AP_OPTS_MUTUAL_REQUIRED,
1145 0, /* no checksum */
1146 0, /* no creds, use ccache instead */
1147 ccdef,
1148 &err_ret,
1149 0, /* don't need subsession key */
1150 0); /* don't need reply */
1151 krb5_free_principal (kcontext, server);
1152 if (rem)
1154 int pop_error_len = snprintf (pop_error, ERROR_MAX, "%s%s",
1155 KRB_ERROR, error_message (rem));
1156 #if defined HAVE_KRB5_ERROR_TEXT
1157 if (err_ret && err_ret->text.length)
1159 int errlen = err_ret->text.length;
1160 snprintf (pop_error + pop_error_len, ERROR_MAX - pop_error_len,
1161 " [server says '%.*s']", errlen, err_ret->text.data);
1163 #elif defined HAVE_KRB5_ERROR_E_TEXT
1164 if (err_ret && err_ret->e_text && **err_ret->e_text)
1165 snprintf (pop_error + pop_error_len, ERROR_MAX - pop_error_len,
1166 " [server says '%s']", *err_ret->e_text);
1167 #endif
1168 if (err_ret)
1169 krb5_free_error (kcontext, err_ret);
1170 krb5_auth_con_free (kcontext, auth_context);
1171 krb5_free_context (kcontext);
1173 CLOSESOCKET (sock);
1174 return (-1);
1176 #else /* ! KERBEROS5 */
1177 ticket = (KTEXT) malloc (sizeof (KTEXT_ST));
1178 rem = krb_sendauth (0L, sock, ticket, "pop", realhost,
1179 (char *) krb_realmofhost (realhost),
1180 (unsigned long) 0, &msg_data, &cred, schedule,
1181 (struct sockaddr_in *) 0,
1182 (struct sockaddr_in *) 0,
1183 "KPOPV0.1");
1184 free ((char *) ticket);
1185 if (rem != KSUCCESS)
1187 snprintf (pop_error, ERROR_MAX, "%s%s", KRB_ERROR, krb_err_txt[rem]);
1188 CLOSESOCKET (sock);
1189 return (-1);
1191 #endif /* KERBEROS5 */
1193 #endif /* KERBEROS */
1195 return (sock);
1196 } /* socket_connection */
1199 * Function: pop_getline
1201 * Purpose: Get a line of text from the connection and return a
1202 * pointer to it. The carriage return and linefeed at the end of
1203 * the line are stripped, but periods at the beginnings of lines
1204 * are NOT dealt with in any special way.
1206 * Arguments:
1207 * server The server from which to get the line of text.
1209 * Returns: The number of characters in the line, which is returned in
1210 * LINE, not including the final null. A return value of 0
1211 * indicates a blank line. A negative return value indicates an
1212 * error (in which case the contents of LINE are undefined. In
1213 * case of error, an error message is copied into pop_error.
1215 * Notes: The line returned is overwritten with each call to pop_getline.
1217 * Side effects: Closes the connection on error.
1219 * THE RETURNED LINE MAY CONTAIN EMBEDDED NULLS!
1221 static int
1222 pop_getline (popserver server, char **line)
1224 #define GETLINE_ERROR "Error reading from server: "
1226 int ret;
1227 int search_offset = 0;
1229 if (server->data)
1231 char *cp = find_crlf (server->buffer + server->buffer_index,
1232 server->data);
1233 if (cp)
1235 int found;
1236 int data_used;
1238 found = server->buffer_index;
1239 data_used = (cp + 2) - server->buffer - found;
1241 *cp = '\0'; /* terminate the string to be returned */
1242 server->data -= data_used;
1243 server->buffer_index += data_used;
1245 if (pop_debug)
1246 /* Embedded nulls will truncate this output prematurely,
1247 but that's OK because it's just for debugging anyway. */
1248 fprintf (stderr, "<<< %s\n", server->buffer + found);
1249 *line = server->buffer + found;
1250 return (data_used - 2);
1252 else
1254 memmove (server->buffer, server->buffer + server->buffer_index,
1255 server->data);
1256 /* Record the fact that we've searched the data already in
1257 the buffer for a CRLF, so that when we search below, we
1258 don't have to search the same data twice. There's a "-
1259 1" here to account for the fact that the last character
1260 of the data we have may be the CR of a CRLF pair, of
1261 which we haven't read the second half yet, so we may have
1262 to search it again when we read more data. */
1263 search_offset = server->data - 1;
1264 server->buffer_index = 0;
1267 else
1269 server->buffer_index = 0;
1272 while (1)
1274 /* There's a "- 1" here to leave room for the null that we put
1275 at the end of the read data below. We put the null there so
1276 that find_crlf knows where to stop when we call it. */
1277 if (server->data == server->buffer_size - 1)
1279 server->buffer_size += GETLINE_INCR;
1280 server->buffer = (char *)realloc (server->buffer, server->buffer_size);
1281 if (! server->buffer)
1283 strcpy (pop_error, "Out of memory in pop_getline");
1284 pop_trash (server);
1285 return (-1);
1288 ret = RECV (server->file, server->buffer + server->data,
1289 server->buffer_size - server->data - 1, 0);
1290 if (ret < 0)
1292 snprintf (pop_error, ERROR_MAX, "%s%s",
1293 GETLINE_ERROR, strerror (errno));
1294 pop_trash (server);
1295 return (-1);
1297 else if (ret == 0)
1299 strcpy (pop_error, "Unexpected EOF from server in pop_getline");
1300 pop_trash (server);
1301 return (-1);
1303 else
1305 char *cp;
1306 server->data += ret;
1307 server->buffer[server->data] = '\0';
1309 cp = find_crlf (server->buffer + search_offset,
1310 server->data - search_offset);
1311 if (cp)
1313 int data_used = (cp + 2) - server->buffer;
1314 *cp = '\0';
1315 server->data -= data_used;
1316 server->buffer_index = data_used;
1318 if (pop_debug)
1319 fprintf (stderr, "<<< %s\n", server->buffer);
1320 *line = server->buffer;
1321 return (data_used - 2);
1323 /* As above, the "- 1" here is to account for the fact that
1324 we may have read a CR without its accompanying LF. */
1325 search_offset += ret - 1;
1329 /* NOTREACHED */
1333 * Function: sendline
1335 * Purpose: Sends a line of text to the POP server. The line of text
1336 * passed into this function should NOT have the carriage return
1337 * and linefeed on the end of it. Periods at beginnings of lines
1338 * will NOT be treated specially by this function.
1340 * Arguments:
1341 * server The server to which to send the text.
1342 * line The line of text to send.
1344 * Return value: Upon successful completion, a value of 0 will be
1345 * returned. Otherwise, a non-zero value will be returned, and
1346 * an error will be copied into pop_error.
1348 * Side effects: Closes the connection on error.
1350 static int
1351 sendline (popserver server, const char *line)
1353 #define SENDLINE_ERROR "Error writing to POP server: "
1354 int ret;
1355 char *buf;
1357 /* Combine the string and the CR-LF into one buffer. Otherwise, two
1358 reasonable network stack optimizations, Nagle's algorithm and
1359 delayed acks, combine to delay us a fraction of a second on every
1360 message we send. (Movemail writes line without \r\n, client
1361 kernel sends packet, server kernel delays the ack to see if it
1362 can combine it with data, movemail writes \r\n, client kernel
1363 waits because it has unacked data already in its outgoing queue,
1364 client kernel eventually times out and sends.)
1366 This can be something like 0.2s per command, which can add up
1367 over a few dozen messages, and is a big chunk of the time we
1368 spend fetching mail from a server close by. */
1369 buf = alloca (strlen (line) + 3);
1370 strcpy (stpcpy (buf, line), "\r\n");
1371 ret = fullwrite (server->file, buf, strlen (buf));
1373 if (ret < 0)
1375 pop_trash (server);
1376 snprintf (pop_error, ERROR_MAX, "%s%s", SENDLINE_ERROR, strerror (errno));
1377 return (ret);
1380 if (pop_debug)
1381 fprintf (stderr, ">>> %s\n", line);
1383 return (0);
1387 * Procedure: fullwrite
1389 * Purpose: Just like write, but keeps trying until the entire string
1390 * has been written.
1392 * Return value: Same as write. Pop_error is not set.
1394 static int
1395 fullwrite (int fd, char *buf, int nbytes)
1397 char *cp;
1398 int ret = 0;
1400 cp = buf;
1401 while (nbytes && ((ret = SEND (fd, cp, nbytes, 0)) > 0))
1403 cp += ret;
1404 nbytes -= ret;
1407 return (ret);
1411 * Procedure getok
1413 * Purpose: Reads a line from the server. If the return indicator is
1414 * positive, return with a zero exit status. If not, return with
1415 * a negative exit status.
1417 * Arguments:
1418 * server The server to read from.
1420 * Returns: 0 for success, else for failure and puts error in pop_error.
1422 * Side effects: On failure, may make the connection unusable.
1424 static int
1425 getok (popserver server)
1427 char *fromline;
1429 if (pop_getline (server, &fromline) < 0)
1431 return (-1);
1434 if (! strncmp (fromline, "+OK", 3))
1435 return (0);
1436 else if (! strncmp (fromline, "-ERR", 4))
1438 snprintf (pop_error, ERROR_MAX, "%s", fromline);
1439 return (-1);
1441 else
1443 strcpy (pop_error,
1444 "Unexpected response from server; expecting +OK or -ERR");
1445 pop_trash (server);
1446 return (-1);
1450 #if 0
1452 * Function: gettermination
1454 * Purpose: Gets the next line and verifies that it is a termination
1455 * line (nothing but a dot).
1457 * Return value: 0 on success, non-zero with pop_error set on error.
1459 * Side effects: Closes the connection on error.
1461 static int
1462 gettermination (server)
1463 popserver server;
1465 char *fromserver;
1467 if (pop_getline (server, &fromserver) < 0)
1468 return (-1);
1470 if (strcmp (fromserver, "."))
1472 strcpy (pop_error,
1473 "Unexpected response from server in gettermination");
1474 pop_trash (server);
1475 return (-1);
1478 return (0);
1480 #endif
1483 * Function pop_close
1485 * Purpose: Close a pop connection, sending a "RSET" command to try to
1486 * preserve any changes that were made and a "QUIT" command to
1487 * try to get the server to quit, but ignoring any responses that
1488 * are received.
1490 * Side effects: The server is unusable after this function returns.
1491 * Changes made to the maildrop since the session was started (or
1492 * since the last pop_reset) may be lost.
1494 void
1495 pop_close (popserver server)
1497 pop_trash (server);
1498 free ((char *) server);
1500 return;
1504 * Function: pop_trash
1506 * Purpose: Like pop_close or pop_quit, but doesn't deallocate the
1507 * memory associated with the server. It is valid to call
1508 * pop_close or pop_quit after this function has been called.
1510 static void
1511 pop_trash (popserver server)
1513 if (server->file >= 0)
1515 /* avoid recursion; sendline can call pop_trash */
1516 if (server->trash_started)
1517 return;
1518 server->trash_started = true;
1520 sendline (server, "RSET");
1521 sendline (server, "QUIT");
1523 CLOSESOCKET (server->file);
1524 server->file = -1;
1525 if (server->buffer)
1527 free (server->buffer);
1528 server->buffer = 0;
1532 #ifdef WINDOWSNT
1533 if (have_winsock)
1534 WSACleanup ();
1535 #endif
1538 /* Return a pointer to the first CRLF in IN_STRING, which can contain
1539 embedded nulls and has LEN characters in it not including the final
1540 null, or 0 if it does not contain one. */
1542 static char *
1543 find_crlf (char *in_string, int len)
1545 while (len--)
1547 if (*in_string == '\r')
1549 if (*++in_string == '\n')
1550 return (in_string - 1);
1552 else
1553 in_string++;
1555 return (0);
1558 #ifdef WINDOWSNT
1559 /* The following 2 functions are only available since XP, so we load
1560 them dynamically and provide fallbacks. */
1562 int (WINAPI *pfn_getaddrinfo) (const char *, const char *,
1563 const struct addrinfo *, struct addrinfo **);
1564 void (WINAPI *pfn_freeaddrinfo) (struct addrinfo *);
1566 static int
1567 load_ws2 (void)
1569 static int ws2_loaded = 0;
1571 if (!ws2_loaded)
1573 HANDLE ws2_lib = LoadLibrary ("Ws2_32.dll");
1575 if (ws2_lib != NULL)
1577 ws2_loaded = 1;
1578 pfn_getaddrinfo = (void *) GetProcAddress (ws2_lib, "getaddrinfo");
1579 pfn_freeaddrinfo = (void *) GetProcAddress (ws2_lib, "freeaddrinfo");
1580 /* Paranoia: these two functions should go together, so if
1581 one is absent, we cannot use the other. */
1582 if (pfn_getaddrinfo == NULL)
1583 pfn_freeaddrinfo = NULL;
1584 else if (pfn_freeaddrinfo == NULL)
1585 pfn_getaddrinfo = NULL;
1588 if (!ws2_loaded)
1590 errno = ENETDOWN;
1591 return -1;
1593 return 0;
1598 sys_getaddrinfo (const char *node, const char *service,
1599 const struct addrinfo *hints, struct addrinfo **res)
1601 int rc;
1603 if (load_ws2 () != 0)
1605 errno = ENETDOWN;
1606 return WSANO_RECOVERY;
1609 if (pfn_getaddrinfo)
1610 rc = pfn_getaddrinfo (node, service, hints, res);
1611 else
1613 int port = 0;
1614 struct hostent *host_info;
1615 struct gai_storage {
1616 struct addrinfo addrinfo;
1617 struct sockaddr_in sockaddr_in;
1618 } *gai_storage;
1620 /* We don't support any flags besides AI_CANONNAME. */
1621 if (hints && (hints->ai_flags & ~(AI_CANONNAME)) != 0)
1622 return WSAEINVAL;
1623 /* NODE cannot be NULL, since pop.c has fallbacks for that. */
1624 if (!node)
1625 return WSAHOST_NOT_FOUND;
1627 if (service)
1629 const char *protocol =
1630 (hints && hints->ai_socktype == SOCK_DGRAM) ? "udp" : "tcp";
1631 struct servent *srv = getservbyname (service, protocol);
1633 if (srv)
1634 port = srv->s_port;
1635 else
1636 return WSAHOST_NOT_FOUND;
1639 gai_storage = calloc (1, sizeof *gai_storage);
1640 gai_storage->sockaddr_in.sin_port = port;
1641 host_info = gethostbyname (node);
1642 if (host_info)
1644 memcpy (&gai_storage->sockaddr_in.sin_addr,
1645 host_info->h_addr, host_info->h_length);
1646 gai_storage->sockaddr_in.sin_family = host_info->h_addrtype;
1648 else
1650 free (gai_storage);
1651 return WSAHOST_NOT_FOUND;
1654 gai_storage->addrinfo.ai_addr =
1655 (struct sockaddr *)&gai_storage->sockaddr_in;
1656 gai_storage->addrinfo.ai_addrlen = sizeof (gai_storage->sockaddr_in);
1657 if (hints && (hints->ai_flags & AI_CANONNAME) != 0)
1659 gai_storage->addrinfo.ai_canonname = strdup (host_info->h_name);
1660 if (!gai_storage->addrinfo.ai_canonname)
1662 free (gai_storage);
1663 return WSA_NOT_ENOUGH_MEMORY;
1666 gai_storage->addrinfo.ai_protocol = (hints) ? hints->ai_protocol : 0;
1667 gai_storage->addrinfo.ai_socktype = (hints) ? hints->ai_socktype : 0;
1668 gai_storage->addrinfo.ai_family = gai_storage->sockaddr_in.sin_family;
1669 gai_storage->addrinfo.ai_next = NULL;
1671 *res = &gai_storage->addrinfo;
1672 rc = 0;
1675 return rc;
1678 void
1679 sys_freeaddrinfo (struct addrinfo *ai)
1681 if (load_ws2 () != 0)
1683 errno = ENETDOWN;
1684 return;
1687 if (pfn_freeaddrinfo)
1688 pfn_freeaddrinfo (ai);
1689 else
1691 if (ai->ai_canonname)
1692 free (ai->ai_canonname);
1693 free (ai);
1696 #endif /* WINDOWSNT */
1697 #endif /* MAIL_USE_POP */