1 /* pop.c: client routines for talking to a POP3-protocol post-office server
2 Copyright (C) 1991, 1993, 1996, 1997, 1999, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 Author: Jonathan Kamens <jik@security.ov.com>
7 This file is part of GNU Emacs.
9 GNU Emacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
31 #include <sys/types.h>
36 #define RECV(s,buf,len,flags) recv(s,buf,len,flags)
37 #define SEND(s,buf,len,flags) send(s,buf,len,flags)
38 #define CLOSESOCKET(s) closesocket(s)
40 #include <netinet/in.h>
41 #include <sys/socket.h>
42 #define RECV(s,buf,len,flags) read(s,buf,len)
43 #define SEND(s,buf,len,flags) write(s,buf,len)
44 #define CLOSESOCKET(s) close(s)
55 * It really shouldn't be necessary to put this declaration here, but
56 * the version of hesiod.h that Athena has installed in release 7.2
57 * doesn't declare this function; I don't know if the 7.3 version of
60 extern struct servent
*hes_getservbyname (/* char *, char * */);
82 # ifdef HAVE_KERBEROSIV_KRB_H
83 # include <kerberosIV/krb.h>
85 # ifdef HAVE_KERBEROS_KRB_H
86 # include <kerberos/krb.h>
90 # ifdef HAVE_COM_ERR_H
97 extern int krb_sendauth (/* long, int, KTEXT, char *, char *, char *,
98 u_long, MSG_DAT *, CREDENTIALS *, Key_schedule,
99 struct sockaddr_in *, struct sockaddr_in *,
101 extern char *krb_realmofhost (/* char * */);
102 #endif /* ! KERBEROS5 */
103 #endif /* KERBEROS */
106 #if !defined(HAVE_H_ERRNO) || !defined(HAVE_CONFIG_H)
111 static int socket_connection (char *, int);
112 static int pop_getline (popserver
, char **);
113 static int sendline (popserver
, const char *);
114 static int fullwrite (int, char *, int);
115 static int getok (popserver
);
117 static int gettermination (popserver
);
119 static void pop_trash (popserver
);
120 static char *find_crlf (char *, int);
122 #define ERROR_MAX 160 /* a pretty arbitrary size, but needs
123 to be bigger than the original
126 #define KPOP_PORT 1109
127 #define POP_SERVICE "pop3" /* we don't want the POP2 port! */
129 #define KPOP_SERVICE "kpop" /* never used: look for 20060515 to see why */
132 char pop_error
[ERROR_MAX
];
136 #define min(a,b) (((a) < (b)) ? (a) : (b))
140 * Function: pop_open (char *host, char *username, char *password,
143 * Purpose: Establishes a connection with a post-office server, and
144 * completes the authorization portion of the session.
147 * host The server host with which the connection should be
148 * established. Optional. If omitted, internal
149 * heuristics will be used to determine the server host,
152 * The username of the mail-drop to access. Optional.
153 * If omitted, internal heuristics will be used to
154 * determine the username, if possible.
156 * The password to use for authorization. If omitted,
157 * internal heuristics will be used to determine the
158 * password, if possible.
159 * flags A bit mask containing flags controlling certain
160 * functions of the routine. Valid flags are defined in
163 * Return value: Upon successful establishment of a connection, a
164 * non-null popserver will be returned. Otherwise, null will be
165 * returned, and the string variable pop_error will contain an
166 * explanation of the error.
169 pop_open (char *host
, char *username
, char *password
, int flags
)
174 /* Determine the user name */
177 username
= getenv ("USER");
178 if (! (username
&& *username
))
180 username
= getlogin ();
181 if (! (username
&& *username
))
183 struct passwd
*passwd
;
184 passwd
= getpwuid (getuid ());
185 if (passwd
&& passwd
->pw_name
&& *passwd
->pw_name
)
187 username
= passwd
->pw_name
;
191 strcpy (pop_error
, "Could not determine username");
199 * Determine the mail host.
204 host
= getenv ("MAILHOST");
208 if ((! host
) && (! (flags
& POP_NO_HESIOD
)))
210 struct hes_postoffice
*office
;
211 office
= hes_getmailhost (username
);
212 if (office
&& office
->po_type
&& (! strcmp (office
->po_type
, "POP"))
213 && office
->po_name
&& *office
->po_name
&& office
->po_host
216 host
= office
->po_host
;
217 username
= office
->po_name
;
231 strcpy (pop_error
, "Could not determine POP server");
235 /* Determine the password */
237 #define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS))
239 #define DONT_NEED_PASSWORD 0
242 if ((! password
) && (! DONT_NEED_PASSWORD
))
244 if (! (flags
& POP_NO_GETPASS
))
246 password
= getpass ("Enter POP password:");
250 strcpy (pop_error
, "Could not determine POP password");
254 if (password
) /* always true, detected 20060515 */
255 flags
|= POP_NO_KERBEROS
;
257 password
= username
; /* dead code, detected 20060515 */
258 /** "kpop" service is never used: look for 20060515 to see why **/
260 sock
= socket_connection (host
, flags
);
264 server
= (popserver
) malloc (sizeof (struct _popserver
));
267 strcpy (pop_error
, "Out of memory in pop_open");
270 server
->buffer
= (char *) malloc (GETLINE_MIN
);
271 if (! server
->buffer
)
273 strcpy (pop_error
, "Out of memory in pop_open");
274 free ((char *) server
);
280 server
->buffer_index
= 0;
281 server
->buffer_size
= GETLINE_MIN
;
282 server
->in_multi
= 0;
283 server
->trash_started
= 0;
289 * I really shouldn't use the pop_error variable like this, but....
291 if (strlen (username
) > ERROR_MAX
- 6)
295 "Username too long; recompile pop.c with larger ERROR_MAX");
298 sprintf (pop_error
, "USER %s", username
);
300 if (sendline (server
, pop_error
) || getok (server
))
305 if (strlen (password
) > ERROR_MAX
- 6)
309 "Password too long; recompile pop.c with larger ERROR_MAX");
312 sprintf (pop_error
, "PASS %s", password
);
314 if (sendline (server
, pop_error
) || getok (server
))
325 * Purpose: Issue the STAT command to the server and return (in the
326 * value parameters) the number of messages in the maildrop and
327 * the total size of the maildrop.
329 * Return value: 0 on success, or non-zero with an error in pop_error
332 * Side effects: On failure, may make further operations on the
333 * connection impossible.
336 pop_stat (popserver server
, int *count
, int *size
)
341 if (server
->in_multi
)
343 strcpy (pop_error
, "In multi-line query in pop_stat");
347 if (sendline (server
, "STAT") || (pop_getline (server
, &fromserver
) < 0))
350 if (strncmp (fromserver
, "+OK ", 4))
352 if (0 == strncmp (fromserver
, "-ERR", 4))
354 strncpy (pop_error
, fromserver
, ERROR_MAX
);
359 "Unexpected response from POP server in pop_stat");
366 *count
= strtol (&fromserver
[4], &end_ptr
, 10);
367 /* Check validity of string-to-integer conversion. */
368 if (fromserver
+ 4 == end_ptr
|| *end_ptr
!= ' ' || errno
)
370 strcpy (pop_error
, "Unexpected response from POP server in pop_stat");
375 fromserver
= end_ptr
;
378 *size
= strtol (fromserver
+ 1, &end_ptr
, 10);
379 if (fromserver
+ 1 == end_ptr
|| errno
)
381 strcpy (pop_error
, "Unexpected response from POP server in pop_stat");
392 * Purpose: Performs the POP "list" command and returns (in value
393 * parameters) two malloc'd zero-terminated arrays -- one of
394 * message IDs, and a parallel one of sizes.
397 * server The pop connection to talk to.
398 * message The number of the one message about which to get
399 * information, or 0 to get information about all
402 * Return value: 0 on success, non-zero with error in pop_error on
405 * Side effects: On failure, may make further operations on the
406 * connection impossible.
409 pop_list (popserver server
, int message
, int **IDs
, int **sizes
)
414 if (server
->in_multi
)
416 strcpy (pop_error
, "In multi-line query in pop_list");
425 if (pop_stat (server
, &count
, &size
))
430 *IDs
= (int *) malloc ((how_many
+ 1) * sizeof (int));
431 *sizes
= (int *) malloc ((how_many
+ 1) * sizeof (int));
432 if (! (*IDs
&& *sizes
))
434 strcpy (pop_error
, "Out of memory in pop_list");
440 sprintf (pop_error
, "LIST %d", message
);
441 if (sendline (server
, pop_error
))
443 free ((char *) *IDs
);
444 free ((char *) *sizes
);
447 if (pop_getline (server
, &fromserver
) < 0)
449 free ((char *) *IDs
);
450 free ((char *) *sizes
);
453 if (strncmp (fromserver
, "+OK ", 4))
455 if (! strncmp (fromserver
, "-ERR", 4))
456 strncpy (pop_error
, fromserver
, ERROR_MAX
);
460 "Unexpected response from server in pop_list");
463 free ((char *) *IDs
);
464 free ((char *) *sizes
);
467 (*IDs
)[0] = atoi (&fromserver
[4]);
468 fromserver
= strchr (&fromserver
[4], ' ');
472 "Badly formatted response from server in pop_list");
474 free ((char *) *IDs
);
475 free ((char *) *sizes
);
478 (*sizes
)[0] = atoi (fromserver
);
479 (*IDs
)[1] = (*sizes
)[1] = 0;
484 if (pop_multi_first (server
, "LIST", &fromserver
))
486 free ((char *) *IDs
);
487 free ((char *) *sizes
);
490 for (i
= 0; i
< how_many
; i
++)
492 if (pop_multi_next (server
, &fromserver
) <= 0)
494 free ((char *) *IDs
);
495 free ((char *) *sizes
);
498 (*IDs
)[i
] = atoi (fromserver
);
499 fromserver
= strchr (fromserver
, ' ');
503 "Badly formatted response from server in pop_list");
504 free ((char *) *IDs
);
505 free ((char *) *sizes
);
509 (*sizes
)[i
] = atoi (fromserver
);
511 if (pop_multi_next (server
, &fromserver
) < 0)
513 free ((char *) *IDs
);
514 free ((char *) *sizes
);
520 "Too many response lines from server in pop_list");
521 free ((char *) *IDs
);
522 free ((char *) *sizes
);
525 (*IDs
)[i
] = (*sizes
)[i
] = 0;
531 * Function: pop_retrieve
533 * Purpose: Retrieve a specified message from the maildrop.
536 * server The server to retrieve from.
537 * message The message number to retrieve.
539 * If true, then mark the string "From " at the beginning
541 * msg_buf Output parameter to which a buffer containing the
542 * message is assigned.
544 * Return value: The number of bytes in msg_buf, which may contain
545 * embedded nulls, not including its final null, or -1 on error
546 * with pop_error set.
548 * Side effects: May kill connection on error.
551 pop_retrieve (popserver server
, int message
, int markfrom
, char **msg_buf
)
553 int *IDs
, *sizes
, bufsize
, fromcount
= 0, cp
= 0;
554 char *ptr
, *fromserver
;
557 if (server
->in_multi
)
559 strcpy (pop_error
, "In multi-line query in pop_retrieve");
563 if (pop_list (server
, message
, &IDs
, &sizes
))
566 if (pop_retrieve_first (server
, message
, &fromserver
))
572 * The "5" below is an arbitrary constant -- I assume that if
573 * there are "From" lines in the text to be marked, there
574 * probably won't be more than 5 of them. If there are, I
575 * allocate more space for them below.
577 bufsize
= sizes
[0] + (markfrom
? 5 : 0);
578 ptr
= (char *)malloc (bufsize
);
580 free ((char *) sizes
);
584 strcpy (pop_error
, "Out of memory in pop_retrieve");
585 pop_retrieve_flush (server
);
589 while ((ret
= pop_retrieve_next (server
, &fromserver
)) >= 0)
597 if (markfrom
&& fromserver
[0] == 'F' && fromserver
[1] == 'r' &&
598 fromserver
[2] == 'o' && fromserver
[3] == 'm' &&
599 fromserver
[4] == ' ')
601 if (++fromcount
== 5)
604 ptr
= (char *)realloc (ptr
, bufsize
);
607 strcpy (pop_error
, "Out of memory in pop_retrieve");
608 pop_retrieve_flush (server
);
615 memcpy (&ptr
[cp
], fromserver
, ret
);
625 pop_retrieve_first (popserver server
, int message
, char **response
)
627 sprintf (pop_error
, "RETR %d", message
);
628 return (pop_multi_first (server
, pop_error
, response
));
632 Returns a negative number on error, 0 to indicate that the data has
633 all been read (i.e., the server has returned a "." termination
634 line), or a positive number indicating the number of bytes in the
635 returned buffer (which is null-terminated and may contain embedded
636 nulls, but the returned bytecount doesn't include the final null).
640 pop_retrieve_next (popserver server
, char **line
)
642 return (pop_multi_next (server
, line
));
646 pop_retrieve_flush (popserver server
)
648 return (pop_multi_flush (server
));
652 pop_top_first (popserver server
, int message
, int lines
, char **response
)
654 sprintf (pop_error
, "TOP %d %d", message
, lines
);
655 return (pop_multi_first (server
, pop_error
, response
));
659 Returns a negative number on error, 0 to indicate that the data has
660 all been read (i.e., the server has returned a "." termination
661 line), or a positive number indicating the number of bytes in the
662 returned buffer (which is null-terminated and may contain embedded
663 nulls, but the returned bytecount doesn't include the final null).
667 pop_top_next (popserver server
, char **line
)
669 return (pop_multi_next (server
, line
));
673 pop_top_flush (popserver server
)
675 return (pop_multi_flush (server
));
679 pop_multi_first (popserver server
, const char *command
, char **response
)
681 if (server
->in_multi
)
684 "Already in multi-line query in pop_multi_first");
688 if (sendline (server
, command
) || (pop_getline (server
, response
) < 0))
693 if (0 == strncmp (*response
, "-ERR", 4))
695 strncpy (pop_error
, *response
, ERROR_MAX
);
698 else if (0 == strncmp (*response
, "+OK", 3))
700 for (*response
+= 3; **response
== ' '; (*response
)++) /* empty */;
701 server
->in_multi
= 1;
707 "Unexpected response from server in pop_multi_first");
713 Read the next line of data from SERVER and place a pointer to it
714 into LINE. Return -1 on error, 0 if there are no more lines to read
715 (i.e., the server has returned a line containing only "."), or a
716 positive number indicating the number of bytes in the LINE buffer
717 (not including the final null). The data in that buffer may contain
718 embedded nulls, but does not contain the final CRLF. When returning
719 0, LINE is set to null. */
722 pop_multi_next (popserver server
, char **line
)
727 if (! server
->in_multi
)
729 strcpy (pop_error
, "Not in multi-line query in pop_multi_next");
733 if ((ret
= pop_getline (server
, &fromserver
)) < 0)
738 if (fromserver
[0] == '.')
743 server
->in_multi
= 0;
748 *line
= fromserver
+ 1;
760 pop_multi_flush (popserver server
)
765 if (! server
->in_multi
)
770 while ((ret
= pop_multi_next (server
, &line
)))
779 /* Function: pop_delete
781 * Purpose: Delete a specified message.
784 * server Server from which to delete the message.
785 * message Message to delete.
787 * Return value: 0 on success, non-zero with error in pop_error
791 pop_delete (popserver server
, int message
)
793 if (server
->in_multi
)
795 strcpy (pop_error
, "In multi-line query in pop_delete");
799 sprintf (pop_error
, "DELE %d", message
);
801 if (sendline (server
, pop_error
) || getok (server
))
810 * Purpose: Send a noop command to the server.
813 * server The server to send to.
815 * Return value: 0 on success, non-zero with error in pop_error
818 * Side effects: Closes connection on error.
821 pop_noop (popserver server
)
823 if (server
->in_multi
)
825 strcpy (pop_error
, "In multi-line query in pop_noop");
829 if (sendline (server
, "NOOP") || getok (server
))
838 * Purpose: Find out the highest seen message from the server.
843 * Return value: If successful, the highest seen message, which is
844 * greater than or equal to 0. Otherwise, a negative number with
845 * the error explained in pop_error.
847 * Side effects: Closes the connection on error.
850 pop_last (popserver server
)
854 if (server
->in_multi
)
856 strcpy (pop_error
, "In multi-line query in pop_last");
860 if (sendline (server
, "LAST"))
863 if (pop_getline (server
, &fromserver
) < 0)
866 if (! strncmp (fromserver
, "-ERR", 4))
868 strncpy (pop_error
, fromserver
, ERROR_MAX
);
871 else if (strncmp (fromserver
, "+OK ", 4))
873 strcpy (pop_error
, "Unexpected response from server in pop_last");
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");
894 * Function: pop_reset
896 * Purpose: Reset the server to its initial connect state
901 * Return value: 0 for success, non-0 with error in pop_error
904 * Side effects: Closes the connection on error.
907 pop_reset (popserver server
)
909 if (pop_retrieve_flush (server
))
914 if (sendline (server
, "RSET") || getok (server
))
923 * Purpose: Quit the connection to the server,
926 * server The server to quit.
928 * Return value: 0 for success, non-zero otherwise with error in
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
)
939 if (server
->file
>= 0)
941 if (pop_retrieve_flush (server
))
946 if (sendline (server
, "QUIT") || getok (server
))
951 close (server
->file
);
954 free (server
->buffer
);
955 free ((char *) server
);
961 static int have_winsock
= 0;
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.
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
979 socket_connection (char *host
, int flags
)
981 #ifdef HAVE_GETADDRINFO
982 struct addrinfo
*res
, *it
;
983 struct addrinfo hints
;
985 #else /* !HAVE_GETADDRINFO */
986 struct hostent
*hostent
;
988 struct servent
*servent
;
989 struct sockaddr_in addr
;
997 krb5_context kcontext
= 0;
998 krb5_auth_context auth_context
= 0;
1000 krb5_principal client
, server
;
1001 krb5_error
*err_ret
;
1007 Key_schedule schedule
;
1009 #endif /* KERBEROS5 */
1010 #endif /* KERBEROS */
1017 WSADATA winsockData
;
1018 if (WSAStartup (0x101, &winsockData
) == 0)
1023 memset (&addr
, 0, sizeof (addr
));
1024 addr
.sin_family
= AF_INET
;
1026 /** "kpop" service is never used: look for 20060515 to see why **/
1028 service
= (flags
& POP_NO_KERBEROS
) ? POP_SERVICE
: KPOP_SERVICE
;
1030 service
= POP_SERVICE
;
1034 if (! (flags
& POP_NO_HESIOD
))
1036 servent
= hes_getservbyname (service
, "tcp");
1039 addr
.sin_port
= servent
->s_port
;
1046 servent
= getservbyname (service
, "tcp");
1049 addr
.sin_port
= servent
->s_port
;
1053 /** "kpop" service is never used: look for 20060515 to see why **/
1055 addr
.sin_port
= htons ((flags
& POP_NO_KERBEROS
) ?
1056 POP_PORT
: KPOP_PORT
);
1058 addr
.sin_port
= htons (POP_PORT
);
1063 #define POP_SOCKET_ERROR "Could not create socket for POP connection: "
1065 sock
= socket (PF_INET
, SOCK_STREAM
, 0);
1068 strcpy (pop_error
, POP_SOCKET_ERROR
);
1069 strncat (pop_error
, strerror (errno
),
1070 ERROR_MAX
- sizeof (POP_SOCKET_ERROR
));
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
);
1084 if (ret
!= 0 && (ret
!= EAI_AGAIN
|| try_count
== 5))
1086 strcpy (pop_error
, "Could not determine POP server's address");
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
)))
1105 connect_ok
= it
!= NULL
;
1108 realhost
= alloca (strlen (it
->ai_canonname
) + 1);
1109 strcpy (realhost
, it
->ai_canonname
);
1113 #else /* !HAVE_GETADDRINFO */
1116 hostent
= gethostbyname (host
);
1118 if ((! hostent
) && ((h_errno
!= TRY_AGAIN
) || (try_count
== 5)))
1120 strcpy (pop_error
, "Could not determine POP server's address");
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
)))
1130 hostent
->h_addr_list
++;
1132 connect_ok
= *hostent
->h_addr_list
!= NULL
;
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: "
1146 strcpy (pop_error
, CONNECT_ERROR
);
1147 strncat (pop_error
, strerror (errno
),
1148 ERROR_MAX
- sizeof (CONNECT_ERROR
));
1155 #define KRB_ERROR "Kerberos error connecting to POP server: "
1156 if (! (flags
& POP_NO_KERBEROS
))
1159 if ((rem
= krb5_init_context (&kcontext
)))
1163 krb5_auth_con_free (kcontext
, auth_context
);
1165 krb5_free_context (kcontext
);
1166 strcpy (pop_error
, KRB_ERROR
);
1167 strncat (pop_error
, error_message (rem
),
1168 ERROR_MAX
- sizeof(KRB_ERROR
));
1173 if ((rem
= krb5_auth_con_init (kcontext
, &auth_context
)))
1176 if (rem
= krb5_cc_default (kcontext
, &ccdef
))
1179 if (rem
= krb5_cc_get_principal (kcontext
, ccdef
, &client
))
1182 for (cp
= realhost
; *cp
; cp
++)
1186 *cp
= tolower (*cp
);
1190 if (rem
= krb5_sname_to_principal (kcontext
, realhost
,
1191 POP_SERVICE
, FALSE
, &server
))
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 */
1201 0, /* don't need subsession key */
1202 0); /* don't need reply */
1203 krb5_free_principal (kcontext
, server
);
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);
1232 krb5_free_error (kcontext
, err_ret
);
1233 krb5_auth_con_free (kcontext
, auth_context
);
1234 krb5_free_context (kcontext
);
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,
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
));
1256 #endif /* KERBEROS5 */
1258 #endif /* KERBEROS */
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.
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!
1287 pop_getline (popserver server
, char **line
)
1289 #define GETLINE_ERROR "Error reading from server: "
1292 int search_offset
= 0;
1296 char *cp
= find_crlf (server
->buffer
+ server
->buffer_index
,
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
;
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);
1319 memmove (server
->buffer
, server
->buffer
+ server
->buffer_index
,
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;
1334 server
->buffer_index
= 0;
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");
1353 ret
= RECV (server
->file
, server
->buffer
+ server
->data
,
1354 server
->buffer_size
- server
->data
- 1, 0);
1357 strcpy (pop_error
, GETLINE_ERROR
);
1358 strncat (pop_error
, strerror (errno
),
1359 ERROR_MAX
- sizeof (GETLINE_ERROR
));
1365 strcpy (pop_error
, "Unexpected EOF from server in pop_getline");
1372 server
->data
+= ret
;
1373 server
->buffer
[server
->data
] = '\0';
1375 cp
= find_crlf (server
->buffer
+ search_offset
,
1376 server
->data
- search_offset
);
1379 int data_used
= (cp
+ 2) - server
->buffer
;
1381 server
->data
-= data_used
;
1382 server
->buffer_index
= data_used
;
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;
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.
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.
1417 sendline (popserver server
, const char *line
)
1419 #define SENDLINE_ERROR "Error writing to POP server: "
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);
1437 strcat (buf
, "\r\n");
1438 ret
= fullwrite (server
->file
, buf
, strlen (buf
));
1443 strcpy (pop_error
, SENDLINE_ERROR
);
1444 strncat (pop_error
, strerror (errno
),
1445 ERROR_MAX
- sizeof (SENDLINE_ERROR
));
1450 fprintf (stderr
, ">>> %s\n", line
);
1456 * Procedure: fullwrite
1458 * Purpose: Just like write, but keeps trying until the entire string
1461 * Return value: Same as write. Pop_error is not set.
1464 fullwrite (int fd
, char *buf
, int nbytes
)
1470 while (nbytes
&& ((ret
= SEND (fd
, cp
, nbytes
, 0)) > 0))
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.
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.
1494 getok (popserver server
)
1498 if (pop_getline (server
, &fromline
) < 0)
1503 if (! strncmp (fromline
, "+OK", 3))
1505 else if (! strncmp (fromline
, "-ERR", 4))
1507 strncpy (pop_error
, fromline
, ERROR_MAX
);
1508 pop_error
[ERROR_MAX
-1] = '\0';
1514 "Unexpected response from server; expecting +OK or -ERR");
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.
1532 gettermination (server
)
1537 if (pop_getline (server
, &fromserver
) < 0)
1540 if (strcmp (fromserver
, "."))
1543 "Unexpected response from server in gettermination");
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
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.
1565 pop_close (popserver server
)
1568 free ((char *) server
);
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.
1581 pop_trash (popserver server
)
1583 if (server
->file
>= 0)
1585 /* avoid recursion; sendline can call pop_trash */
1586 if (server
->trash_started
)
1588 server
->trash_started
= 1;
1590 sendline (server
, "RSET");
1591 sendline (server
, "QUIT");
1593 CLOSESOCKET (server
->file
);
1597 free (server
->buffer
);
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. */
1613 find_crlf (char *in_string
, int len
)
1617 if (*in_string
== '\r')
1619 if (*++in_string
== '\n')
1620 return (in_string
- 1);
1628 #endif /* MAIL_USE_POP */
1630 /* arch-tag: ceb37041-b7ad-49a8-a63d-286618b8367d
1631 (do not change this comment) */