Fix package.el handling of local variables on first line.
[emacs.git] / lib-src / pop.c
blobc4c7f2b4e2f0360fff2ff2c0c2724625685e478a
1 /* pop.c: client routines for talking to a POP3-protocol post-office server
3 Copyright (C) 1991, 1993, 1996-1997, 1999, 2001-2012
4 Free Software 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
13 (at 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 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #else
27 #define MAIL_USE_POP
28 #endif
30 #ifdef MAIL_USE_POP
32 #include <sys/types.h>
33 #ifdef WINDOWSNT
34 #include "ntlib.h"
35 #include <winsock.h>
36 #undef SOCKET_ERROR
37 #define RECV(s,buf,len,flags) recv (s,buf,len,flags)
38 #define SEND(s,buf,len,flags) send (s,buf,len,flags)
39 #define CLOSESOCKET(s) closesocket (s)
40 #else
41 #include <netinet/in.h>
42 #include <sys/socket.h>
43 #define RECV(s,buf,len,flags) read (s,buf,len)
44 #define SEND(s,buf,len,flags) write (s,buf,len)
45 #define CLOSESOCKET(s) close (s)
46 #endif
47 #include <pop.h>
49 #ifdef sun
50 #include <malloc.h>
51 #endif /* sun */
53 #ifdef HESIOD
54 #include <hesiod.h>
56 * It really shouldn't be necessary to put this declaration here, but
57 * the version of hesiod.h that Athena has installed in release 7.2
58 * doesn't declare this function; I don't know if the 7.3 version of
59 * hesiod.h does.
61 extern struct servent *hes_getservbyname (/* char *, char * */);
62 #endif
64 #include <pwd.h>
65 #include <netdb.h>
66 #include <errno.h>
67 #include <stdio.h>
68 #include <string.h>
69 #include <unistd.h>
71 #ifdef KERBEROS
72 # ifdef HAVE_KRB5_H
73 # include <krb5.h>
74 # endif
75 # ifdef HAVE_KRB_H
76 # include <krb.h>
77 # else
78 # ifdef HAVE_KERBEROSIV_KRB_H
79 # include <kerberosIV/krb.h>
80 # else
81 # ifdef HAVE_KERBEROS_KRB_H
82 # include <kerberos/krb.h>
83 # endif
84 # endif
85 # endif
86 # ifdef HAVE_COM_ERR_H
87 # include <com_err.h>
88 # endif
89 #endif /* KERBEROS */
91 #include <min-max.h>
93 #ifdef KERBEROS
94 #ifndef KERBEROS5
95 extern int krb_sendauth (/* long, int, KTEXT, char *, char *, char *,
96 u_long, MSG_DAT *, CREDENTIALS *, Key_schedule,
97 struct sockaddr_in *, struct sockaddr_in *,
98 char * */);
99 extern char *krb_realmofhost (/* char * */);
100 #endif /* ! KERBEROS5 */
101 #endif /* KERBEROS */
103 #ifndef WINDOWSNT
104 #if !defined (HAVE_H_ERRNO) || !defined (HAVE_CONFIG_H)
105 extern int h_errno;
106 #endif
107 #endif
109 static int socket_connection (char *, int);
110 static int pop_getline (popserver, char **);
111 static int sendline (popserver, const char *);
112 static int fullwrite (int, char *, int);
113 static int getok (popserver);
114 #if 0
115 static int gettermination (popserver);
116 #endif
117 static void pop_trash (popserver);
118 static char *find_crlf (char *, int);
120 #define ERROR_MAX 160 /* a pretty arbitrary size, but needs
121 to be bigger than the original
122 value of 80 */
123 #define POP_PORT 110
124 #define POP_SERVICE "pop3" /* we don't want the POP2 port! */
125 #ifdef KERBEROS
126 #define KPOP_PORT 1109
127 #define KPOP_SERVICE "kpop" /* never used: look for 20060515 to see why */
128 #endif
130 char pop_error[ERROR_MAX];
131 int pop_debug = 0;
134 * Function: pop_open (char *host, char *username, char *password,
135 * int flags)
137 * Purpose: Establishes a connection with a post-office server, and
138 * completes the authorization portion of the session.
140 * Arguments:
141 * host The server host with which the connection should be
142 * established. Optional. If omitted, internal
143 * heuristics will be used to determine the server host,
144 * if possible.
145 * username
146 * The username of the mail-drop to access. Optional.
147 * If omitted, internal heuristics will be used to
148 * determine the username, if possible.
149 * password
150 * The password to use for authorization. If omitted,
151 * internal heuristics will be used to determine the
152 * password, if possible.
153 * flags A bit mask containing flags controlling certain
154 * functions of the routine. Valid flags are defined in
155 * the file pop.h
157 * Return value: Upon successful establishment of a connection, a
158 * non-null popserver will be returned. Otherwise, null will be
159 * returned, and the string variable pop_error will contain an
160 * explanation of the error.
162 popserver
163 pop_open (char *host, char *username, char *password, int flags)
165 int sock;
166 popserver server;
168 /* Determine the user name */
169 if (! username)
171 username = getenv ("USER");
172 if (! (username && *username))
174 username = getlogin ();
175 if (! (username && *username))
177 struct passwd *passwd;
178 passwd = getpwuid (getuid ());
179 if (passwd && passwd->pw_name && *passwd->pw_name)
181 username = passwd->pw_name;
183 else
185 strcpy (pop_error, "Could not determine username");
186 return (0);
193 * Determine the mail host.
196 if (! host)
198 host = getenv ("MAILHOST");
201 #ifdef HESIOD
202 if ((! host) && (! (flags & POP_NO_HESIOD)))
204 struct hes_postoffice *office;
205 office = hes_getmailhost (username);
206 if (office && office->po_type && (! strcmp (office->po_type, "POP"))
207 && office->po_name && *office->po_name && office->po_host
208 && *office->po_host)
210 host = office->po_host;
211 username = office->po_name;
214 #endif
216 #ifdef MAILHOST
217 if (! host)
219 host = MAILHOST;
221 #endif
223 if (! host)
225 strcpy (pop_error, "Could not determine POP server");
226 return (0);
229 /* Determine the password */
230 #ifdef KERBEROS
231 #define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS))
232 #else
233 #define DONT_NEED_PASSWORD 0
234 #endif
236 if ((! password) && (! DONT_NEED_PASSWORD))
238 if (! (flags & POP_NO_GETPASS))
240 password = getpass ("Enter POP password:");
242 if (! password)
244 strcpy (pop_error, "Could not determine POP password");
245 return (0);
248 if (password) /* always true, detected 20060515 */
249 flags |= POP_NO_KERBEROS;
250 else
251 password = username; /* dead code, detected 20060515 */
252 /** "kpop" service is never used: look for 20060515 to see why **/
254 sock = socket_connection (host, flags);
255 if (sock == -1)
256 return (0);
258 server = (popserver) malloc (sizeof (struct _popserver));
259 if (! server)
261 strcpy (pop_error, "Out of memory in pop_open");
262 return (0);
264 server->buffer = (char *) malloc (GETLINE_MIN);
265 if (! server->buffer)
267 strcpy (pop_error, "Out of memory in pop_open");
268 free ((char *) server);
269 return (0);
272 server->file = sock;
273 server->data = 0;
274 server->buffer_index = 0;
275 server->buffer_size = GETLINE_MIN;
276 server->in_multi = 0;
277 server->trash_started = 0;
279 if (getok (server))
280 return (0);
283 * I really shouldn't use the pop_error variable like this, but....
285 if (strlen (username) > ERROR_MAX - 6)
287 pop_close (server);
288 strcpy (pop_error,
289 "Username too long; recompile pop.c with larger ERROR_MAX");
290 return (0);
292 sprintf (pop_error, "USER %s", username);
294 if (sendline (server, pop_error) || getok (server))
296 return (0);
299 if (strlen (password) > ERROR_MAX - 6)
301 pop_close (server);
302 strcpy (pop_error,
303 "Password too long; recompile pop.c with larger ERROR_MAX");
304 return (0);
306 sprintf (pop_error, "PASS %s", password);
308 if (sendline (server, pop_error) || getok (server))
310 return (0);
313 return (server);
317 * Function: pop_stat
319 * Purpose: Issue the STAT command to the server and return (in the
320 * value parameters) the number of messages in the maildrop and
321 * the total size of the maildrop.
323 * Return value: 0 on success, or non-zero with an error in pop_error
324 * in failure.
326 * Side effects: On failure, may make further operations on the
327 * connection impossible.
330 pop_stat (popserver server, int *count, int *size)
332 char *fromserver;
333 char *end_ptr;
335 if (server->in_multi)
337 strcpy (pop_error, "In multi-line query in pop_stat");
338 return (-1);
341 if (sendline (server, "STAT") || (pop_getline (server, &fromserver) < 0))
342 return (-1);
344 if (strncmp (fromserver, "+OK ", 4))
346 if (0 == strncmp (fromserver, "-ERR", 4))
348 strncpy (pop_error, fromserver, ERROR_MAX);
349 pop_error[ERROR_MAX-1] = '\0';
351 else
353 strcpy (pop_error,
354 "Unexpected response from POP server in pop_stat");
355 pop_trash (server);
357 return (-1);
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)
365 strcpy (pop_error, "Unexpected response from POP server in pop_stat");
366 pop_trash (server);
367 return (-1);
370 fromserver = end_ptr;
372 errno = 0;
373 *size = strtol (fromserver + 1, &end_ptr, 10);
374 if (fromserver + 1 == end_ptr || errno)
376 strcpy (pop_error, "Unexpected response from POP server in pop_stat");
377 pop_trash (server);
378 return (-1);
381 return (0);
385 * Function: pop_list
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.
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.
397 * Return value: 0 on success, non-zero with error in pop_error on
398 * failure.
400 * Side effects: On failure, may make further operations on the
401 * connection impossible.
404 pop_list (popserver server, int message, int **IDs, int **sizes)
406 int how_many, i;
407 char *fromserver;
409 if (server->in_multi)
411 strcpy (pop_error, "In multi-line query in pop_list");
412 return (-1);
415 if (message)
416 how_many = 1;
417 else
419 int count, size;
420 if (pop_stat (server, &count, &size))
421 return (-1);
422 how_many = count;
425 *IDs = (int *) malloc ((how_many + 1) * sizeof (int));
426 *sizes = (int *) malloc ((how_many + 1) * sizeof (int));
427 if (! (*IDs && *sizes))
429 strcpy (pop_error, "Out of memory in pop_list");
430 return (-1);
433 if (message)
435 sprintf (pop_error, "LIST %d", message);
436 if (sendline (server, pop_error))
438 free ((char *) *IDs);
439 free ((char *) *sizes);
440 return (-1);
442 if (pop_getline (server, &fromserver) < 0)
444 free ((char *) *IDs);
445 free ((char *) *sizes);
446 return (-1);
448 if (strncmp (fromserver, "+OK ", 4))
450 if (! strncmp (fromserver, "-ERR", 4))
452 strncpy (pop_error, fromserver, ERROR_MAX);
453 pop_error[ERROR_MAX-1] = '\0';
455 else
457 strcpy (pop_error,
458 "Unexpected response from server in pop_list");
459 pop_trash (server);
461 free ((char *) *IDs);
462 free ((char *) *sizes);
463 return (-1);
465 (*IDs)[0] = atoi (&fromserver[4]);
466 fromserver = strchr (&fromserver[4], ' ');
467 if (! fromserver)
469 strcpy (pop_error,
470 "Badly formatted response from server in pop_list");
471 pop_trash (server);
472 free ((char *) *IDs);
473 free ((char *) *sizes);
474 return (-1);
476 (*sizes)[0] = atoi (fromserver);
477 (*IDs)[1] = (*sizes)[1] = 0;
478 return (0);
480 else
482 if (pop_multi_first (server, "LIST", &fromserver))
484 free ((char *) *IDs);
485 free ((char *) *sizes);
486 return (-1);
488 for (i = 0; i < how_many; i++)
490 if (pop_multi_next (server, &fromserver) <= 0)
492 free ((char *) *IDs);
493 free ((char *) *sizes);
494 return (-1);
496 (*IDs)[i] = atoi (fromserver);
497 fromserver = strchr (fromserver, ' ');
498 if (! fromserver)
500 strcpy (pop_error,
501 "Badly formatted response from server in pop_list");
502 free ((char *) *IDs);
503 free ((char *) *sizes);
504 pop_trash (server);
505 return (-1);
507 (*sizes)[i] = atoi (fromserver);
509 if (pop_multi_next (server, &fromserver) < 0)
511 free ((char *) *IDs);
512 free ((char *) *sizes);
513 return (-1);
515 else if (fromserver)
517 strcpy (pop_error,
518 "Too many response lines from server in pop_list");
519 free ((char *) *IDs);
520 free ((char *) *sizes);
521 return (-1);
523 (*IDs)[i] = (*sizes)[i] = 0;
524 return (0);
529 * Function: pop_retrieve
531 * Purpose: Retrieve a specified message from the maildrop.
533 * Arguments:
534 * server The server to retrieve from.
535 * message The message number to retrieve.
536 * markfrom
537 * If true, then mark the string "From " at the beginning
538 * of lines with '>'.
539 * msg_buf Output parameter to which a buffer containing the
540 * message is assigned.
542 * Return value: The number of bytes in msg_buf, which may contain
543 * embedded nulls, not including its final null, or -1 on error
544 * with pop_error set.
546 * Side effects: May kill connection on error.
549 pop_retrieve (popserver server, int message, int markfrom, char **msg_buf)
551 int *IDs, *sizes, bufsize, fromcount = 0, cp = 0;
552 char *ptr, *fromserver;
553 int ret;
555 if (server->in_multi)
557 strcpy (pop_error, "In multi-line query in pop_retrieve");
558 return (-1);
561 if (pop_list (server, message, &IDs, &sizes))
562 return (-1);
564 if (pop_retrieve_first (server, message, &fromserver))
566 return (-1);
570 * The "5" below is an arbitrary constant -- I assume that if
571 * there are "From" lines in the text to be marked, there
572 * probably won't be more than 5 of them. If there are, I
573 * allocate more space for them below.
575 bufsize = sizes[0] + (markfrom ? 5 : 0);
576 ptr = (char *)malloc (bufsize);
577 free ((char *) IDs);
578 free ((char *) sizes);
580 if (! ptr)
582 strcpy (pop_error, "Out of memory in pop_retrieve");
583 pop_retrieve_flush (server);
584 return (-1);
587 while ((ret = pop_retrieve_next (server, &fromserver)) >= 0)
589 if (! fromserver)
591 ptr[cp] = '\0';
592 *msg_buf = ptr;
593 return (cp);
595 if (markfrom && fromserver[0] == 'F' && fromserver[1] == 'r' &&
596 fromserver[2] == 'o' && fromserver[3] == 'm' &&
597 fromserver[4] == ' ')
599 if (++fromcount == 5)
601 bufsize += 5;
602 ptr = (char *)realloc (ptr, bufsize);
603 if (! ptr)
605 strcpy (pop_error, "Out of memory in pop_retrieve");
606 pop_retrieve_flush (server);
607 return (-1);
609 fromcount = 0;
611 ptr[cp++] = '>';
613 memcpy (&ptr[cp], fromserver, ret);
614 cp += ret;
615 ptr[cp++] = '\n';
618 free (ptr);
619 return (-1);
623 pop_retrieve_first (popserver server, int message, char **response)
625 sprintf (pop_error, "RETR %d", message);
626 return (pop_multi_first (server, pop_error, response));
630 Returns a negative number on error, 0 to indicate that the data has
631 all been read (i.e., the server has returned a "." termination
632 line), or a positive number indicating the number of bytes in the
633 returned buffer (which is null-terminated and may contain embedded
634 nulls, but the returned bytecount doesn't include the final null).
638 pop_retrieve_next (popserver server, char **line)
640 return (pop_multi_next (server, line));
644 pop_retrieve_flush (popserver server)
646 return (pop_multi_flush (server));
650 pop_top_first (popserver server, int message, int lines, char **response)
652 sprintf (pop_error, "TOP %d %d", message, lines);
653 return (pop_multi_first (server, pop_error, response));
657 Returns a negative number on error, 0 to indicate that the data has
658 all been read (i.e., the server has returned a "." termination
659 line), or a positive number indicating the number of bytes in the
660 returned buffer (which is null-terminated and may contain embedded
661 nulls, but the returned bytecount doesn't include the final null).
665 pop_top_next (popserver server, char **line)
667 return (pop_multi_next (server, line));
671 pop_top_flush (popserver server)
673 return (pop_multi_flush (server));
677 pop_multi_first (popserver server, const char *command, char **response)
679 if (server->in_multi)
681 strcpy (pop_error,
682 "Already in multi-line query in pop_multi_first");
683 return (-1);
686 if (sendline (server, command) || (pop_getline (server, response) < 0))
688 return (-1);
691 if (0 == strncmp (*response, "-ERR", 4))
693 strncpy (pop_error, *response, ERROR_MAX);
694 pop_error[ERROR_MAX-1] = '\0';
695 return (-1);
697 else if (0 == strncmp (*response, "+OK", 3))
699 for (*response += 3; **response == ' '; (*response)++) /* empty */;
700 server->in_multi = 1;
701 return (0);
703 else
705 strcpy (pop_error,
706 "Unexpected response from server in pop_multi_first");
707 return (-1);
712 Read the next line of data from SERVER and place a pointer to it
713 into LINE. Return -1 on error, 0 if there are no more lines to read
714 (i.e., the server has returned a line containing only "."), or a
715 positive number indicating the number of bytes in the LINE buffer
716 (not including the final null). The data in that buffer may contain
717 embedded nulls, but does not contain the final CRLF. When returning
718 0, LINE is set to null. */
721 pop_multi_next (popserver server, char **line)
723 char *fromserver;
724 int ret;
726 if (! server->in_multi)
728 strcpy (pop_error, "Not in multi-line query in pop_multi_next");
729 return (-1);
732 if ((ret = pop_getline (server, &fromserver)) < 0)
734 return (-1);
737 if (fromserver[0] == '.')
739 if (! fromserver[1])
741 *line = 0;
742 server->in_multi = 0;
743 return (0);
745 else
747 *line = fromserver + 1;
748 return (ret - 1);
751 else
753 *line = fromserver;
754 return (ret);
759 pop_multi_flush (popserver server)
761 char *line;
762 int ret;
764 if (! server->in_multi)
766 return (0);
769 while ((ret = pop_multi_next (server, &line)))
771 if (ret < 0)
772 return (-1);
775 return (0);
778 /* Function: pop_delete
780 * Purpose: Delete a specified message.
782 * Arguments:
783 * server Server from which to delete the message.
784 * message Message to delete.
786 * Return value: 0 on success, non-zero with error in pop_error
787 * otherwise.
790 pop_delete (popserver server, int message)
792 if (server->in_multi)
794 strcpy (pop_error, "In multi-line query in pop_delete");
795 return (-1);
798 sprintf (pop_error, "DELE %d", message);
800 if (sendline (server, pop_error) || getok (server))
801 return (-1);
803 return (0);
807 * Function: pop_noop
809 * Purpose: Send a noop command to the server.
811 * Argument:
812 * server The server to send to.
814 * Return value: 0 on success, non-zero with error in pop_error
815 * otherwise.
817 * Side effects: Closes connection on error.
820 pop_noop (popserver server)
822 if (server->in_multi)
824 strcpy (pop_error, "In multi-line query in pop_noop");
825 return (-1);
828 if (sendline (server, "NOOP") || getok (server))
829 return (-1);
831 return (0);
835 * Function: pop_last
837 * Purpose: Find out the highest seen message from the server.
839 * Arguments:
840 * server The server.
842 * Return value: If successful, the highest seen message, which is
843 * greater than or equal to 0. Otherwise, a negative number with
844 * the error explained in pop_error.
846 * Side effects: Closes the connection on error.
849 pop_last (popserver server)
851 char *fromserver;
853 if (server->in_multi)
855 strcpy (pop_error, "In multi-line query in pop_last");
856 return (-1);
859 if (sendline (server, "LAST"))
860 return (-1);
862 if (pop_getline (server, &fromserver) < 0)
863 return (-1);
865 if (! strncmp (fromserver, "-ERR", 4))
867 strncpy (pop_error, fromserver, ERROR_MAX);
868 pop_error[ERROR_MAX-1] = '\0';
869 return (-1);
871 else if (strncmp (fromserver, "+OK ", 4))
873 strcpy (pop_error, "Unexpected response from server in pop_last");
874 pop_trash (server);
875 return (-1);
877 else
879 char *end_ptr;
880 int count;
881 errno = 0;
882 count = strtol (&fromserver[4], &end_ptr, 10);
883 if (fromserver + 4 == end_ptr || errno)
885 strcpy (pop_error, "Unexpected response from server in pop_last");
886 pop_trash (server);
887 return (-1);
889 return count;
894 * Function: pop_reset
896 * Purpose: Reset the server to its initial connect state
898 * Arguments:
899 * server The server.
901 * Return value: 0 for success, non-0 with error in pop_error
902 * otherwise.
904 * Side effects: Closes the connection on error.
907 pop_reset (popserver server)
909 if (pop_retrieve_flush (server))
911 return (-1);
914 if (sendline (server, "RSET") || getok (server))
915 return (-1);
917 return (0);
921 * Function: pop_quit
923 * Purpose: Quit the connection to the server,
925 * Arguments:
926 * server The server to quit.
928 * Return value: 0 for success, non-zero otherwise with error in
929 * pop_error.
931 * Side Effects: The popserver passed in is unusable after this
932 * function is called, even if an error occurs.
935 pop_quit (popserver server)
937 int ret = 0;
939 if (server->file >= 0)
941 if (pop_retrieve_flush (server))
943 ret = -1;
946 if (sendline (server, "QUIT") || getok (server))
948 ret = -1;
951 close (server->file);
954 free (server->buffer);
955 free ((char *) server);
957 return (ret);
960 #ifdef WINDOWSNT
961 static int have_winsock = 0;
962 #endif
965 * Function: socket_connection
967 * Purpose: Opens the network connection with the mail host, without
968 * doing any sort of I/O with it or anything.
970 * Arguments:
971 * host The host to which to connect.
972 * flags Option flags.
974 * Return value: A file descriptor indicating the connection, or -1
975 * indicating failure, in which case an error has been copied
976 * into pop_error.
978 static int
979 socket_connection (char *host, int flags)
981 #ifdef HAVE_GETADDRINFO
982 struct addrinfo *res, *it;
983 struct addrinfo hints;
984 int ret;
985 #else /* !HAVE_GETADDRINFO */
986 struct hostent *hostent;
987 #endif
988 struct servent *servent;
989 struct sockaddr_in addr;
990 char found_port = 0;
991 const char *service;
992 int sock;
993 char *realhost;
994 #ifdef KERBEROS
995 #ifdef KERBEROS5
996 krb5_error_code rem;
997 krb5_context kcontext = 0;
998 krb5_auth_context auth_context = 0;
999 krb5_ccache ccdef;
1000 krb5_principal client, server;
1001 krb5_error *err_ret;
1002 register char *cp;
1003 #else
1004 KTEXT ticket;
1005 MSG_DAT msg_data;
1006 CREDENTIALS cred;
1007 Key_schedule schedule;
1008 int rem;
1009 #endif /* KERBEROS5 */
1010 #endif /* KERBEROS */
1012 int try_count = 0;
1013 int connect_ok;
1015 #ifdef WINDOWSNT
1017 WSADATA winsockData;
1018 if (WSAStartup (0x101, &winsockData) == 0)
1019 have_winsock = 1;
1021 #endif
1023 memset (&addr, 0, sizeof (addr));
1024 addr.sin_family = AF_INET;
1026 /** "kpop" service is never used: look for 20060515 to see why **/
1027 #ifdef KERBEROS
1028 service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE;
1029 #else
1030 service = POP_SERVICE;
1031 #endif
1033 #ifdef HESIOD
1034 if (! (flags & POP_NO_HESIOD))
1036 servent = hes_getservbyname (service, "tcp");
1037 if (servent)
1039 addr.sin_port = servent->s_port;
1040 found_port = 1;
1043 #endif
1044 if (! found_port)
1046 servent = getservbyname (service, "tcp");
1047 if (servent)
1049 addr.sin_port = servent->s_port;
1051 else
1053 /** "kpop" service is never used: look for 20060515 to see why **/
1054 #ifdef KERBEROS
1055 addr.sin_port = htons ((flags & POP_NO_KERBEROS) ?
1056 POP_PORT : KPOP_PORT);
1057 #else
1058 addr.sin_port = htons (POP_PORT);
1059 #endif
1063 #define POP_SOCKET_ERROR "Could not create socket for POP connection: "
1065 sock = socket (PF_INET, SOCK_STREAM, 0);
1066 if (sock < 0)
1068 strcpy (pop_error, POP_SOCKET_ERROR);
1069 strncat (pop_error, strerror (errno),
1070 ERROR_MAX - sizeof (POP_SOCKET_ERROR));
1071 return (-1);
1075 #ifdef HAVE_GETADDRINFO
1076 memset (&hints, 0, sizeof (hints));
1077 hints.ai_socktype = SOCK_STREAM;
1078 hints.ai_flags = AI_CANONNAME;
1079 hints.ai_family = AF_INET;
1082 ret = getaddrinfo (host, service, &hints, &res);
1083 try_count++;
1084 if (ret != 0 && (ret != EAI_AGAIN || try_count == 5))
1086 strcpy (pop_error, "Could not determine POP server's address");
1087 return (-1);
1089 } while (ret != 0);
1091 if (ret == 0)
1093 it = res;
1094 while (it)
1096 if (it->ai_addrlen == sizeof (addr))
1098 struct sockaddr_in *in_a = (struct sockaddr_in *) it->ai_addr;
1099 memcpy (&addr.sin_addr, &in_a->sin_addr, sizeof (addr.sin_addr));
1100 if (! connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
1101 break;
1103 it = it->ai_next;
1105 connect_ok = it != NULL;
1106 if (connect_ok)
1108 realhost = alloca (strlen (it->ai_canonname) + 1);
1109 strcpy (realhost, it->ai_canonname);
1111 freeaddrinfo (res);
1113 #else /* !HAVE_GETADDRINFO */
1116 hostent = gethostbyname (host);
1117 try_count++;
1118 if ((! hostent) && ((h_errno != TRY_AGAIN) || (try_count == 5)))
1120 strcpy (pop_error, "Could not determine POP server's address");
1121 return (-1);
1123 } while (! hostent);
1125 while (*hostent->h_addr_list)
1127 memcpy (&addr.sin_addr, *hostent->h_addr_list, hostent->h_length);
1128 if (! connect (sock, (struct sockaddr *) &addr, sizeof (addr)))
1129 break;
1130 hostent->h_addr_list++;
1132 connect_ok = *hostent->h_addr_list != NULL;
1133 if (! connect_ok)
1135 realhost = alloca (strlen (hostent->h_name) + 1);
1136 strcpy (realhost, hostent->h_name);
1139 #endif /* !HAVE_GETADDRINFO */
1141 #define CONNECT_ERROR "Could not connect to POP server: "
1143 if (! connect_ok)
1145 CLOSESOCKET (sock);
1146 strcpy (pop_error, CONNECT_ERROR);
1147 strncat (pop_error, strerror (errno),
1148 ERROR_MAX - sizeof (CONNECT_ERROR));
1149 return (-1);
1153 #ifdef KERBEROS
1155 #define KRB_ERROR "Kerberos error connecting to POP server: "
1156 if (! (flags & POP_NO_KERBEROS))
1158 #ifdef KERBEROS5
1159 if ((rem = krb5_init_context (&kcontext)))
1161 krb5error:
1162 if (auth_context)
1163 krb5_auth_con_free (kcontext, auth_context);
1164 if (kcontext)
1165 krb5_free_context (kcontext);
1166 strcpy (pop_error, KRB_ERROR);
1167 strncat (pop_error, error_message (rem),
1168 ERROR_MAX - sizeof (KRB_ERROR));
1169 CLOSESOCKET (sock);
1170 return (-1);
1173 if ((rem = krb5_auth_con_init (kcontext, &auth_context)))
1174 goto krb5error;
1176 if (rem = krb5_cc_default (kcontext, &ccdef))
1177 goto krb5error;
1179 if (rem = krb5_cc_get_principal (kcontext, ccdef, &client))
1180 goto krb5error;
1182 for (cp = realhost; *cp; cp++)
1184 if (isupper (*cp))
1186 *cp = tolower (*cp);
1190 if (rem = krb5_sname_to_principal (kcontext, realhost,
1191 POP_SERVICE, FALSE, &server))
1192 goto krb5error;
1194 rem = krb5_sendauth (kcontext, &auth_context,
1195 (krb5_pointer) &sock, "KPOPV1.0", client, server,
1196 AP_OPTS_MUTUAL_REQUIRED,
1197 0, /* no checksum */
1198 0, /* no creds, use ccache instead */
1199 ccdef,
1200 &err_ret,
1201 0, /* don't need subsession key */
1202 0); /* don't need reply */
1203 krb5_free_principal (kcontext, server);
1204 if (rem)
1206 strcpy (pop_error, KRB_ERROR);
1207 strncat (pop_error, error_message (rem),
1208 ERROR_MAX - sizeof (KRB_ERROR));
1209 #if defined HAVE_KRB5_ERROR_TEXT
1210 if (err_ret && err_ret->text.length)
1212 strncat (pop_error, " [server says '",
1213 ERROR_MAX - strlen (pop_error) - 1);
1214 strncat (pop_error, err_ret->text.data,
1215 min (ERROR_MAX - strlen (pop_error) - 1,
1216 err_ret->text.length));
1217 strncat (pop_error, "']",
1218 ERROR_MAX - strlen (pop_error) - 1);
1220 #elif defined HAVE_KRB5_ERROR_E_TEXT
1221 if (err_ret && err_ret->e_text && strlen (*err_ret->e_text))
1223 strncat (pop_error, " [server says '",
1224 ERROR_MAX - strlen (pop_error) - 1);
1225 strncat (pop_error, *err_ret->e_text,
1226 ERROR_MAX - strlen (pop_error) - 1);
1227 strncat (pop_error, "']",
1228 ERROR_MAX - strlen (pop_error) - 1);
1230 #endif
1231 if (err_ret)
1232 krb5_free_error (kcontext, err_ret);
1233 krb5_auth_con_free (kcontext, auth_context);
1234 krb5_free_context (kcontext);
1236 CLOSESOCKET (sock);
1237 return (-1);
1239 #else /* ! KERBEROS5 */
1240 ticket = (KTEXT) malloc (sizeof (KTEXT_ST));
1241 rem = krb_sendauth (0L, sock, ticket, "pop", realhost,
1242 (char *) krb_realmofhost (realhost),
1243 (unsigned long) 0, &msg_data, &cred, schedule,
1244 (struct sockaddr_in *) 0,
1245 (struct sockaddr_in *) 0,
1246 "KPOPV0.1");
1247 free ((char *) ticket);
1248 if (rem != KSUCCESS)
1250 strcpy (pop_error, KRB_ERROR);
1251 strncat (pop_error, krb_err_txt[rem],
1252 ERROR_MAX - sizeof (KRB_ERROR));
1253 CLOSESOCKET (sock);
1254 return (-1);
1256 #endif /* KERBEROS5 */
1258 #endif /* KERBEROS */
1260 return (sock);
1261 } /* socket_connection */
1264 * Function: pop_getline
1266 * Purpose: Get a line of text from the connection and return a
1267 * pointer to it. The carriage return and linefeed at the end of
1268 * the line are stripped, but periods at the beginnings of lines
1269 * are NOT dealt with in any special way.
1271 * Arguments:
1272 * server The server from which to get the line of text.
1274 * Returns: The number of characters in the line, which is returned in
1275 * LINE, not including the final null. A return value of 0
1276 * indicates a blank line. A negative return value indicates an
1277 * error (in which case the contents of LINE are undefined. In
1278 * case of error, an error message is copied into pop_error.
1280 * Notes: The line returned is overwritten with each call to pop_getline.
1282 * Side effects: Closes the connection on error.
1284 * THE RETURNED LINE MAY CONTAIN EMBEDDED NULLS!
1286 static int
1287 pop_getline (popserver server, char **line)
1289 #define GETLINE_ERROR "Error reading from server: "
1291 int ret;
1292 int search_offset = 0;
1294 if (server->data)
1296 char *cp = find_crlf (server->buffer + server->buffer_index,
1297 server->data);
1298 if (cp)
1300 int found;
1301 int data_used;
1303 found = server->buffer_index;
1304 data_used = (cp + 2) - server->buffer - found;
1306 *cp = '\0'; /* terminate the string to be returned */
1307 server->data -= data_used;
1308 server->buffer_index += data_used;
1310 if (pop_debug)
1311 /* Embedded nulls will truncate this output prematurely,
1312 but that's OK because it's just for debugging anyway. */
1313 fprintf (stderr, "<<< %s\n", server->buffer + found);
1314 *line = server->buffer + found;
1315 return (data_used - 2);
1317 else
1319 memmove (server->buffer, server->buffer + server->buffer_index,
1320 server->data);
1321 /* Record the fact that we've searched the data already in
1322 the buffer for a CRLF, so that when we search below, we
1323 don't have to search the same data twice. There's a "-
1324 1" here to account for the fact that the last character
1325 of the data we have may be the CR of a CRLF pair, of
1326 which we haven't read the second half yet, so we may have
1327 to search it again when we read more data. */
1328 search_offset = server->data - 1;
1329 server->buffer_index = 0;
1332 else
1334 server->buffer_index = 0;
1337 while (1)
1339 /* There's a "- 1" here to leave room for the null that we put
1340 at the end of the read data below. We put the null there so
1341 that find_crlf knows where to stop when we call it. */
1342 if (server->data == server->buffer_size - 1)
1344 server->buffer_size += GETLINE_INCR;
1345 server->buffer = (char *)realloc (server->buffer, server->buffer_size);
1346 if (! server->buffer)
1348 strcpy (pop_error, "Out of memory in pop_getline");
1349 pop_trash (server);
1350 return (-1);
1353 ret = RECV (server->file, server->buffer + server->data,
1354 server->buffer_size - server->data - 1, 0);
1355 if (ret < 0)
1357 strcpy (pop_error, GETLINE_ERROR);
1358 strncat (pop_error, strerror (errno),
1359 ERROR_MAX - sizeof (GETLINE_ERROR));
1360 pop_trash (server);
1361 return (-1);
1363 else if (ret == 0)
1365 strcpy (pop_error, "Unexpected EOF from server in pop_getline");
1366 pop_trash (server);
1367 return (-1);
1369 else
1371 char *cp;
1372 server->data += ret;
1373 server->buffer[server->data] = '\0';
1375 cp = find_crlf (server->buffer + search_offset,
1376 server->data - search_offset);
1377 if (cp)
1379 int data_used = (cp + 2) - server->buffer;
1380 *cp = '\0';
1381 server->data -= data_used;
1382 server->buffer_index = data_used;
1384 if (pop_debug)
1385 fprintf (stderr, "<<< %s\n", server->buffer);
1386 *line = server->buffer;
1387 return (data_used - 2);
1389 /* As above, the "- 1" here is to account for the fact that
1390 we may have read a CR without its accompanying LF. */
1391 search_offset += ret - 1;
1395 /* NOTREACHED */
1399 * Function: sendline
1401 * Purpose: Sends a line of text to the POP server. The line of text
1402 * passed into this function should NOT have the carriage return
1403 * and linefeed on the end of it. Periods at beginnings of lines
1404 * will NOT be treated specially by this function.
1406 * Arguments:
1407 * server The server to which to send the text.
1408 * line The line of text to send.
1410 * Return value: Upon successful completion, a value of 0 will be
1411 * returned. Otherwise, a non-zero value will be returned, and
1412 * an error will be copied into pop_error.
1414 * Side effects: Closes the connection on error.
1416 static int
1417 sendline (popserver server, const char *line)
1419 #define SENDLINE_ERROR "Error writing to POP server: "
1420 int ret;
1421 char *buf;
1423 /* Combine the string and the CR-LF into one buffer. Otherwise, two
1424 reasonable network stack optimizations, Nagle's algorithm and
1425 delayed acks, combine to delay us a fraction of a second on every
1426 message we send. (Movemail writes line without \r\n, client
1427 kernel sends packet, server kernel delays the ack to see if it
1428 can combine it with data, movemail writes \r\n, client kernel
1429 waits because it has unacked data already in its outgoing queue,
1430 client kernel eventually times out and sends.)
1432 This can be something like 0.2s per command, which can add up
1433 over a few dozen messages, and is a big chunk of the time we
1434 spend fetching mail from a server close by. */
1435 buf = alloca (strlen (line) + 3);
1436 strcpy (buf, line);
1437 strcat (buf, "\r\n");
1438 ret = fullwrite (server->file, buf, strlen (buf));
1440 if (ret < 0)
1442 pop_trash (server);
1443 strcpy (pop_error, SENDLINE_ERROR);
1444 strncat (pop_error, strerror (errno),
1445 ERROR_MAX - sizeof (SENDLINE_ERROR));
1446 return (ret);
1449 if (pop_debug)
1450 fprintf (stderr, ">>> %s\n", line);
1452 return (0);
1456 * Procedure: fullwrite
1458 * Purpose: Just like write, but keeps trying until the entire string
1459 * has been written.
1461 * Return value: Same as write. Pop_error is not set.
1463 static int
1464 fullwrite (int fd, char *buf, int nbytes)
1466 char *cp;
1467 int ret = 0;
1469 cp = buf;
1470 while (nbytes && ((ret = SEND (fd, cp, nbytes, 0)) > 0))
1472 cp += ret;
1473 nbytes -= ret;
1476 return (ret);
1480 * Procedure getok
1482 * Purpose: Reads a line from the server. If the return indicator is
1483 * positive, return with a zero exit status. If not, return with
1484 * a negative exit status.
1486 * Arguments:
1487 * server The server to read from.
1489 * Returns: 0 for success, else for failure and puts error in pop_error.
1491 * Side effects: On failure, may make the connection unusable.
1493 static int
1494 getok (popserver server)
1496 char *fromline;
1498 if (pop_getline (server, &fromline) < 0)
1500 return (-1);
1503 if (! strncmp (fromline, "+OK", 3))
1504 return (0);
1505 else if (! strncmp (fromline, "-ERR", 4))
1507 strncpy (pop_error, fromline, ERROR_MAX);
1508 pop_error[ERROR_MAX-1] = '\0';
1509 return (-1);
1511 else
1513 strcpy (pop_error,
1514 "Unexpected response from server; expecting +OK or -ERR");
1515 pop_trash (server);
1516 return (-1);
1520 #if 0
1522 * Function: gettermination
1524 * Purpose: Gets the next line and verifies that it is a termination
1525 * line (nothing but a dot).
1527 * Return value: 0 on success, non-zero with pop_error set on error.
1529 * Side effects: Closes the connection on error.
1531 static int
1532 gettermination (server)
1533 popserver server;
1535 char *fromserver;
1537 if (pop_getline (server, &fromserver) < 0)
1538 return (-1);
1540 if (strcmp (fromserver, "."))
1542 strcpy (pop_error,
1543 "Unexpected response from server in gettermination");
1544 pop_trash (server);
1545 return (-1);
1548 return (0);
1550 #endif
1553 * Function pop_close
1555 * Purpose: Close a pop connection, sending a "RSET" command to try to
1556 * preserve any changes that were made and a "QUIT" command to
1557 * try to get the server to quit, but ignoring any responses that
1558 * are received.
1560 * Side effects: The server is unusable after this function returns.
1561 * Changes made to the maildrop since the session was started (or
1562 * since the last pop_reset) may be lost.
1564 void
1565 pop_close (popserver server)
1567 pop_trash (server);
1568 free ((char *) server);
1570 return;
1574 * Function: pop_trash
1576 * Purpose: Like pop_close or pop_quit, but doesn't deallocate the
1577 * memory associated with the server. It is valid to call
1578 * pop_close or pop_quit after this function has been called.
1580 static void
1581 pop_trash (popserver server)
1583 if (server->file >= 0)
1585 /* avoid recursion; sendline can call pop_trash */
1586 if (server->trash_started)
1587 return;
1588 server->trash_started = 1;
1590 sendline (server, "RSET");
1591 sendline (server, "QUIT");
1593 CLOSESOCKET (server->file);
1594 server->file = -1;
1595 if (server->buffer)
1597 free (server->buffer);
1598 server->buffer = 0;
1602 #ifdef WINDOWSNT
1603 if (have_winsock)
1604 WSACleanup ();
1605 #endif
1608 /* Return a pointer to the first CRLF in IN_STRING, which can contain
1609 embedded nulls and has LEN characters in it not including the final
1610 null, or 0 if it does not contain one. */
1612 static char *
1613 find_crlf (char *in_string, int len)
1615 while (len--)
1617 if (*in_string == '\r')
1619 if (*++in_string == '\n')
1620 return (in_string - 1);
1622 else
1623 in_string++;
1625 return (0);
1628 #endif /* MAIL_USE_POP */