1 /* pop.c: client routines for talking to a POP3-protocol post-office server
2 Copyright (C) 1991, 1993, 1996-1997, 1999, 2001-2011 Free Software Foundation, Inc.
4 Author: Jonathan Kamens <jik@security.ov.com>
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
30 #include <sys/types.h>
35 #define RECV(s,buf,len,flags) recv(s,buf,len,flags)
36 #define SEND(s,buf,len,flags) send(s,buf,len,flags)
37 #define CLOSESOCKET(s) closesocket(s)
39 #include <netinet/in.h>
40 #include <sys/socket.h>
41 #define RECV(s,buf,len,flags) read(s,buf,len)
42 #define SEND(s,buf,len,flags) write(s,buf,len)
43 #define CLOSESOCKET(s) close(s)
54 * It really shouldn't be necessary to put this declaration here, but
55 * the version of hesiod.h that Athena has installed in release 7.2
56 * doesn't declare this function; I don't know if the 7.3 version of
59 extern struct servent
*hes_getservbyname (/* char *, char * */);
79 # ifdef HAVE_KERBEROSIV_KRB_H
80 # include <kerberosIV/krb.h>
82 # ifdef HAVE_KERBEROS_KRB_H
83 # include <kerberos/krb.h>
87 # ifdef HAVE_COM_ERR_H
94 extern int krb_sendauth (/* long, int, KTEXT, char *, char *, char *,
95 u_long, MSG_DAT *, CREDENTIALS *, Key_schedule,
96 struct sockaddr_in *, struct sockaddr_in *,
98 extern char *krb_realmofhost (/* char * */);
99 #endif /* ! KERBEROS5 */
100 #endif /* KERBEROS */
103 #if !defined(HAVE_H_ERRNO) || !defined(HAVE_CONFIG_H)
108 static int socket_connection (char *, int);
109 static int pop_getline (popserver
, char **);
110 static int sendline (popserver
, const char *);
111 static int fullwrite (int, char *, int);
112 static int getok (popserver
);
114 static int gettermination (popserver
);
116 static void pop_trash (popserver
);
117 static char *find_crlf (char *, int);
119 #define ERROR_MAX 160 /* a pretty arbitrary size, but needs
120 to be bigger than the original
123 #define KPOP_PORT 1109
124 #define POP_SERVICE "pop3" /* we don't want the POP2 port! */
126 #define KPOP_SERVICE "kpop" /* never used: look for 20060515 to see why */
129 char pop_error
[ERROR_MAX
];
133 #define min(a,b) (((a) < (b)) ? (a) : (b))
137 * Function: pop_open (char *host, char *username, char *password,
140 * Purpose: Establishes a connection with a post-office server, and
141 * completes the authorization portion of the session.
144 * host The server host with which the connection should be
145 * established. Optional. If omitted, internal
146 * heuristics will be used to determine the server host,
149 * The username of the mail-drop to access. Optional.
150 * If omitted, internal heuristics will be used to
151 * determine the username, if possible.
153 * The password to use for authorization. If omitted,
154 * internal heuristics will be used to determine the
155 * password, if possible.
156 * flags A bit mask containing flags controlling certain
157 * functions of the routine. Valid flags are defined in
160 * Return value: Upon successful establishment of a connection, a
161 * non-null popserver will be returned. Otherwise, null will be
162 * returned, and the string variable pop_error will contain an
163 * explanation of the error.
166 pop_open (char *host
, char *username
, char *password
, int flags
)
171 /* Determine the user name */
174 username
= getenv ("USER");
175 if (! (username
&& *username
))
177 username
= getlogin ();
178 if (! (username
&& *username
))
180 struct passwd
*passwd
;
181 passwd
= getpwuid (getuid ());
182 if (passwd
&& passwd
->pw_name
&& *passwd
->pw_name
)
184 username
= passwd
->pw_name
;
188 strcpy (pop_error
, "Could not determine username");
196 * Determine the mail host.
201 host
= getenv ("MAILHOST");
205 if ((! host
) && (! (flags
& POP_NO_HESIOD
)))
207 struct hes_postoffice
*office
;
208 office
= hes_getmailhost (username
);
209 if (office
&& office
->po_type
&& (! strcmp (office
->po_type
, "POP"))
210 && office
->po_name
&& *office
->po_name
&& office
->po_host
213 host
= office
->po_host
;
214 username
= office
->po_name
;
228 strcpy (pop_error
, "Could not determine POP server");
232 /* Determine the password */
234 #define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS))
236 #define DONT_NEED_PASSWORD 0
239 if ((! password
) && (! DONT_NEED_PASSWORD
))
241 if (! (flags
& POP_NO_GETPASS
))
243 password
= getpass ("Enter POP password:");
247 strcpy (pop_error
, "Could not determine POP password");
251 if (password
) /* always true, detected 20060515 */
252 flags
|= POP_NO_KERBEROS
;
254 password
= username
; /* dead code, detected 20060515 */
255 /** "kpop" service is never used: look for 20060515 to see why **/
257 sock
= socket_connection (host
, flags
);
261 server
= (popserver
) malloc (sizeof (struct _popserver
));
264 strcpy (pop_error
, "Out of memory in pop_open");
267 server
->buffer
= (char *) malloc (GETLINE_MIN
);
268 if (! server
->buffer
)
270 strcpy (pop_error
, "Out of memory in pop_open");
271 free ((char *) server
);
277 server
->buffer_index
= 0;
278 server
->buffer_size
= GETLINE_MIN
;
279 server
->in_multi
= 0;
280 server
->trash_started
= 0;
286 * I really shouldn't use the pop_error variable like this, but....
288 if (strlen (username
) > ERROR_MAX
- 6)
292 "Username too long; recompile pop.c with larger ERROR_MAX");
295 sprintf (pop_error
, "USER %s", username
);
297 if (sendline (server
, pop_error
) || getok (server
))
302 if (strlen (password
) > ERROR_MAX
- 6)
306 "Password too long; recompile pop.c with larger ERROR_MAX");
309 sprintf (pop_error
, "PASS %s", password
);
311 if (sendline (server
, pop_error
) || getok (server
))
322 * Purpose: Issue the STAT command to the server and return (in the
323 * value parameters) the number of messages in the maildrop and
324 * the total size of the maildrop.
326 * Return value: 0 on success, or non-zero with an error in pop_error
329 * Side effects: On failure, may make further operations on the
330 * connection impossible.
333 pop_stat (popserver server
, int *count
, int *size
)
338 if (server
->in_multi
)
340 strcpy (pop_error
, "In multi-line query in pop_stat");
344 if (sendline (server
, "STAT") || (pop_getline (server
, &fromserver
) < 0))
347 if (strncmp (fromserver
, "+OK ", 4))
349 if (0 == strncmp (fromserver
, "-ERR", 4))
351 strncpy (pop_error
, fromserver
, ERROR_MAX
);
356 "Unexpected response from POP server in pop_stat");
363 *count
= strtol (&fromserver
[4], &end_ptr
, 10);
364 /* Check validity of string-to-integer conversion. */
365 if (fromserver
+ 4 == end_ptr
|| *end_ptr
!= ' ' || errno
)
367 strcpy (pop_error
, "Unexpected response from POP server in pop_stat");
372 fromserver
= end_ptr
;
375 *size
= strtol (fromserver
+ 1, &end_ptr
, 10);
376 if (fromserver
+ 1 == end_ptr
|| errno
)
378 strcpy (pop_error
, "Unexpected response from POP server in pop_stat");
389 * Purpose: Performs the POP "list" command and returns (in value
390 * parameters) two malloc'd zero-terminated arrays -- one of
391 * message IDs, and a parallel one of sizes.
394 * server The pop connection to talk to.
395 * message The number of the one message about which to get
396 * information, or 0 to get information about all
399 * Return value: 0 on success, non-zero with error in pop_error on
402 * Side effects: On failure, may make further operations on the
403 * connection impossible.
406 pop_list (popserver server
, int message
, int **IDs
, int **sizes
)
411 if (server
->in_multi
)
413 strcpy (pop_error
, "In multi-line query in pop_list");
422 if (pop_stat (server
, &count
, &size
))
427 *IDs
= (int *) malloc ((how_many
+ 1) * sizeof (int));
428 *sizes
= (int *) malloc ((how_many
+ 1) * sizeof (int));
429 if (! (*IDs
&& *sizes
))
431 strcpy (pop_error
, "Out of memory in pop_list");
437 sprintf (pop_error
, "LIST %d", message
);
438 if (sendline (server
, pop_error
))
440 free ((char *) *IDs
);
441 free ((char *) *sizes
);
444 if (pop_getline (server
, &fromserver
) < 0)
446 free ((char *) *IDs
);
447 free ((char *) *sizes
);
450 if (strncmp (fromserver
, "+OK ", 4))
452 if (! strncmp (fromserver
, "-ERR", 4))
453 strncpy (pop_error
, fromserver
, ERROR_MAX
);
457 "Unexpected response from server in pop_list");
460 free ((char *) *IDs
);
461 free ((char *) *sizes
);
464 (*IDs
)[0] = atoi (&fromserver
[4]);
465 fromserver
= strchr (&fromserver
[4], ' ');
469 "Badly formatted response from server in pop_list");
471 free ((char *) *IDs
);
472 free ((char *) *sizes
);
475 (*sizes
)[0] = atoi (fromserver
);
476 (*IDs
)[1] = (*sizes
)[1] = 0;
481 if (pop_multi_first (server
, "LIST", &fromserver
))
483 free ((char *) *IDs
);
484 free ((char *) *sizes
);
487 for (i
= 0; i
< how_many
; i
++)
489 if (pop_multi_next (server
, &fromserver
) <= 0)
491 free ((char *) *IDs
);
492 free ((char *) *sizes
);
495 (*IDs
)[i
] = atoi (fromserver
);
496 fromserver
= strchr (fromserver
, ' ');
500 "Badly formatted response from server in pop_list");
501 free ((char *) *IDs
);
502 free ((char *) *sizes
);
506 (*sizes
)[i
] = atoi (fromserver
);
508 if (pop_multi_next (server
, &fromserver
) < 0)
510 free ((char *) *IDs
);
511 free ((char *) *sizes
);
517 "Too many response lines from server in pop_list");
518 free ((char *) *IDs
);
519 free ((char *) *sizes
);
522 (*IDs
)[i
] = (*sizes
)[i
] = 0;
528 * Function: pop_retrieve
530 * Purpose: Retrieve a specified message from the maildrop.
533 * server The server to retrieve from.
534 * message The message number to retrieve.
536 * If true, then mark the string "From " at the beginning
538 * msg_buf Output parameter to which a buffer containing the
539 * message is assigned.
541 * Return value: The number of bytes in msg_buf, which may contain
542 * embedded nulls, not including its final null, or -1 on error
543 * with pop_error set.
545 * Side effects: May kill connection on error.
548 pop_retrieve (popserver server
, int message
, int markfrom
, char **msg_buf
)
550 int *IDs
, *sizes
, bufsize
, fromcount
= 0, cp
= 0;
551 char *ptr
, *fromserver
;
554 if (server
->in_multi
)
556 strcpy (pop_error
, "In multi-line query in pop_retrieve");
560 if (pop_list (server
, message
, &IDs
, &sizes
))
563 if (pop_retrieve_first (server
, message
, &fromserver
))
569 * The "5" below is an arbitrary constant -- I assume that if
570 * there are "From" lines in the text to be marked, there
571 * probably won't be more than 5 of them. If there are, I
572 * allocate more space for them below.
574 bufsize
= sizes
[0] + (markfrom
? 5 : 0);
575 ptr
= (char *)malloc (bufsize
);
577 free ((char *) sizes
);
581 strcpy (pop_error
, "Out of memory in pop_retrieve");
582 pop_retrieve_flush (server
);
586 while ((ret
= pop_retrieve_next (server
, &fromserver
)) >= 0)
594 if (markfrom
&& fromserver
[0] == 'F' && fromserver
[1] == 'r' &&
595 fromserver
[2] == 'o' && fromserver
[3] == 'm' &&
596 fromserver
[4] == ' ')
598 if (++fromcount
== 5)
601 ptr
= (char *)realloc (ptr
, bufsize
);
604 strcpy (pop_error
, "Out of memory in pop_retrieve");
605 pop_retrieve_flush (server
);
612 memcpy (&ptr
[cp
], fromserver
, ret
);
622 pop_retrieve_first (popserver server
, int message
, char **response
)
624 sprintf (pop_error
, "RETR %d", message
);
625 return (pop_multi_first (server
, pop_error
, response
));
629 Returns a negative number on error, 0 to indicate that the data has
630 all been read (i.e., the server has returned a "." termination
631 line), or a positive number indicating the number of bytes in the
632 returned buffer (which is null-terminated and may contain embedded
633 nulls, but the returned bytecount doesn't include the final null).
637 pop_retrieve_next (popserver server
, char **line
)
639 return (pop_multi_next (server
, line
));
643 pop_retrieve_flush (popserver server
)
645 return (pop_multi_flush (server
));
649 pop_top_first (popserver server
, int message
, int lines
, char **response
)
651 sprintf (pop_error
, "TOP %d %d", message
, lines
);
652 return (pop_multi_first (server
, pop_error
, response
));
656 Returns a negative number on error, 0 to indicate that the data has
657 all been read (i.e., the server has returned a "." termination
658 line), or a positive number indicating the number of bytes in the
659 returned buffer (which is null-terminated and may contain embedded
660 nulls, but the returned bytecount doesn't include the final null).
664 pop_top_next (popserver server
, char **line
)
666 return (pop_multi_next (server
, line
));
670 pop_top_flush (popserver server
)
672 return (pop_multi_flush (server
));
676 pop_multi_first (popserver server
, const char *command
, char **response
)
678 if (server
->in_multi
)
681 "Already in multi-line query in pop_multi_first");
685 if (sendline (server
, command
) || (pop_getline (server
, response
) < 0))
690 if (0 == strncmp (*response
, "-ERR", 4))
692 strncpy (pop_error
, *response
, ERROR_MAX
);
695 else if (0 == strncmp (*response
, "+OK", 3))
697 for (*response
+= 3; **response
== ' '; (*response
)++) /* empty */;
698 server
->in_multi
= 1;
704 "Unexpected response from server in pop_multi_first");
710 Read the next line of data from SERVER and place a pointer to it
711 into LINE. Return -1 on error, 0 if there are no more lines to read
712 (i.e., the server has returned a line containing only "."), or a
713 positive number indicating the number of bytes in the LINE buffer
714 (not including the final null). The data in that buffer may contain
715 embedded nulls, but does not contain the final CRLF. When returning
716 0, LINE is set to null. */
719 pop_multi_next (popserver server
, char **line
)
724 if (! server
->in_multi
)
726 strcpy (pop_error
, "Not in multi-line query in pop_multi_next");
730 if ((ret
= pop_getline (server
, &fromserver
)) < 0)
735 if (fromserver
[0] == '.')
740 server
->in_multi
= 0;
745 *line
= fromserver
+ 1;
757 pop_multi_flush (popserver server
)
762 if (! server
->in_multi
)
767 while ((ret
= pop_multi_next (server
, &line
)))
776 /* Function: pop_delete
778 * Purpose: Delete a specified message.
781 * server Server from which to delete the message.
782 * message Message to delete.
784 * Return value: 0 on success, non-zero with error in pop_error
788 pop_delete (popserver server
, int message
)
790 if (server
->in_multi
)
792 strcpy (pop_error
, "In multi-line query in pop_delete");
796 sprintf (pop_error
, "DELE %d", message
);
798 if (sendline (server
, pop_error
) || getok (server
))
807 * Purpose: Send a noop command to the server.
810 * server The server to send to.
812 * Return value: 0 on success, non-zero with error in pop_error
815 * Side effects: Closes connection on error.
818 pop_noop (popserver server
)
820 if (server
->in_multi
)
822 strcpy (pop_error
, "In multi-line query in pop_noop");
826 if (sendline (server
, "NOOP") || getok (server
))
835 * Purpose: Find out the highest seen message from the server.
840 * Return value: If successful, the highest seen message, which is
841 * greater than or equal to 0. Otherwise, a negative number with
842 * the error explained in pop_error.
844 * Side effects: Closes the connection on error.
847 pop_last (popserver server
)
851 if (server
->in_multi
)
853 strcpy (pop_error
, "In multi-line query in pop_last");
857 if (sendline (server
, "LAST"))
860 if (pop_getline (server
, &fromserver
) < 0)
863 if (! strncmp (fromserver
, "-ERR", 4))
865 strncpy (pop_error
, fromserver
, ERROR_MAX
);
868 else if (strncmp (fromserver
, "+OK ", 4))
870 strcpy (pop_error
, "Unexpected response from server in pop_last");
879 count
= strtol (&fromserver
[4], &end_ptr
, 10);
880 if (fromserver
+ 4 == end_ptr
|| errno
)
882 strcpy (pop_error
, "Unexpected response from server in pop_last");
891 * Function: pop_reset
893 * Purpose: Reset the server to its initial connect state
898 * Return value: 0 for success, non-0 with error in pop_error
901 * Side effects: Closes the connection on error.
904 pop_reset (popserver server
)
906 if (pop_retrieve_flush (server
))
911 if (sendline (server
, "RSET") || getok (server
))
920 * Purpose: Quit the connection to the server,
923 * server The server to quit.
925 * Return value: 0 for success, non-zero otherwise with error in
928 * Side Effects: The popserver passed in is unusable after this
929 * function is called, even if an error occurs.
932 pop_quit (popserver server
)
936 if (server
->file
>= 0)
938 if (pop_retrieve_flush (server
))
943 if (sendline (server
, "QUIT") || getok (server
))
948 close (server
->file
);
951 free (server
->buffer
);
952 free ((char *) server
);
958 static int have_winsock
= 0;
962 * Function: socket_connection
964 * Purpose: Opens the network connection with the mail host, without
965 * doing any sort of I/O with it or anything.
968 * host The host to which to connect.
969 * flags Option flags.
971 * Return value: A file descriptor indicating the connection, or -1
972 * indicating failure, in which case an error has been copied
976 socket_connection (char *host
, int flags
)
978 #ifdef HAVE_GETADDRINFO
979 struct addrinfo
*res
, *it
;
980 struct addrinfo hints
;
982 #else /* !HAVE_GETADDRINFO */
983 struct hostent
*hostent
;
985 struct servent
*servent
;
986 struct sockaddr_in addr
;
994 krb5_context kcontext
= 0;
995 krb5_auth_context auth_context
= 0;
997 krb5_principal client
, server
;
1004 Key_schedule schedule
;
1006 #endif /* KERBEROS5 */
1007 #endif /* KERBEROS */
1014 WSADATA winsockData
;
1015 if (WSAStartup (0x101, &winsockData
) == 0)
1020 memset (&addr
, 0, sizeof (addr
));
1021 addr
.sin_family
= AF_INET
;
1023 /** "kpop" service is never used: look for 20060515 to see why **/
1025 service
= (flags
& POP_NO_KERBEROS
) ? POP_SERVICE
: KPOP_SERVICE
;
1027 service
= POP_SERVICE
;
1031 if (! (flags
& POP_NO_HESIOD
))
1033 servent
= hes_getservbyname (service
, "tcp");
1036 addr
.sin_port
= servent
->s_port
;
1043 servent
= getservbyname (service
, "tcp");
1046 addr
.sin_port
= servent
->s_port
;
1050 /** "kpop" service is never used: look for 20060515 to see why **/
1052 addr
.sin_port
= htons ((flags
& POP_NO_KERBEROS
) ?
1053 POP_PORT
: KPOP_PORT
);
1055 addr
.sin_port
= htons (POP_PORT
);
1060 #define POP_SOCKET_ERROR "Could not create socket for POP connection: "
1062 sock
= socket (PF_INET
, SOCK_STREAM
, 0);
1065 strcpy (pop_error
, POP_SOCKET_ERROR
);
1066 strncat (pop_error
, strerror (errno
),
1067 ERROR_MAX
- sizeof (POP_SOCKET_ERROR
));
1072 #ifdef HAVE_GETADDRINFO
1073 memset (&hints
, 0, sizeof(hints
));
1074 hints
.ai_socktype
= SOCK_STREAM
;
1075 hints
.ai_flags
= AI_CANONNAME
;
1076 hints
.ai_family
= AF_INET
;
1079 ret
= getaddrinfo (host
, service
, &hints
, &res
);
1081 if (ret
!= 0 && (ret
!= EAI_AGAIN
|| try_count
== 5))
1083 strcpy (pop_error
, "Could not determine POP server's address");
1093 if (it
->ai_addrlen
== sizeof (addr
))
1095 struct sockaddr_in
*in_a
= (struct sockaddr_in
*) it
->ai_addr
;
1096 memcpy (&addr
.sin_addr
, &in_a
->sin_addr
, sizeof (addr
.sin_addr
));
1097 if (! connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)))
1102 connect_ok
= it
!= NULL
;
1105 realhost
= alloca (strlen (it
->ai_canonname
) + 1);
1106 strcpy (realhost
, it
->ai_canonname
);
1110 #else /* !HAVE_GETADDRINFO */
1113 hostent
= gethostbyname (host
);
1115 if ((! hostent
) && ((h_errno
!= TRY_AGAIN
) || (try_count
== 5)))
1117 strcpy (pop_error
, "Could not determine POP server's address");
1120 } while (! hostent
);
1122 while (*hostent
->h_addr_list
)
1124 memcpy (&addr
.sin_addr
, *hostent
->h_addr_list
, hostent
->h_length
);
1125 if (! connect (sock
, (struct sockaddr
*) &addr
, sizeof (addr
)))
1127 hostent
->h_addr_list
++;
1129 connect_ok
= *hostent
->h_addr_list
!= NULL
;
1132 realhost
= alloca (strlen (hostent
->h_name
) + 1);
1133 strcpy (realhost
, hostent
->h_name
);
1136 #endif /* !HAVE_GETADDRINFO */
1138 #define CONNECT_ERROR "Could not connect to POP server: "
1143 strcpy (pop_error
, CONNECT_ERROR
);
1144 strncat (pop_error
, strerror (errno
),
1145 ERROR_MAX
- sizeof (CONNECT_ERROR
));
1152 #define KRB_ERROR "Kerberos error connecting to POP server: "
1153 if (! (flags
& POP_NO_KERBEROS
))
1156 if ((rem
= krb5_init_context (&kcontext
)))
1160 krb5_auth_con_free (kcontext
, auth_context
);
1162 krb5_free_context (kcontext
);
1163 strcpy (pop_error
, KRB_ERROR
);
1164 strncat (pop_error
, error_message (rem
),
1165 ERROR_MAX
- sizeof(KRB_ERROR
));
1170 if ((rem
= krb5_auth_con_init (kcontext
, &auth_context
)))
1173 if (rem
= krb5_cc_default (kcontext
, &ccdef
))
1176 if (rem
= krb5_cc_get_principal (kcontext
, ccdef
, &client
))
1179 for (cp
= realhost
; *cp
; cp
++)
1183 *cp
= tolower (*cp
);
1187 if (rem
= krb5_sname_to_principal (kcontext
, realhost
,
1188 POP_SERVICE
, FALSE
, &server
))
1191 rem
= krb5_sendauth (kcontext
, &auth_context
,
1192 (krb5_pointer
) &sock
, "KPOPV1.0", client
, server
,
1193 AP_OPTS_MUTUAL_REQUIRED
,
1194 0, /* no checksum */
1195 0, /* no creds, use ccache instead */
1198 0, /* don't need subsession key */
1199 0); /* don't need reply */
1200 krb5_free_principal (kcontext
, server
);
1203 strcpy (pop_error
, KRB_ERROR
);
1204 strncat (pop_error
, error_message (rem
),
1205 ERROR_MAX
- sizeof (KRB_ERROR
));
1206 #if defined HAVE_KRB5_ERROR_TEXT
1207 if (err_ret
&& err_ret
->text
.length
)
1209 strncat (pop_error
, " [server says '",
1210 ERROR_MAX
- strlen (pop_error
) - 1);
1211 strncat (pop_error
, err_ret
->text
.data
,
1212 min (ERROR_MAX
- strlen (pop_error
) - 1,
1213 err_ret
->text
.length
));
1214 strncat (pop_error
, "']",
1215 ERROR_MAX
- strlen (pop_error
) - 1);
1217 #elif defined HAVE_KRB5_ERROR_E_TEXT
1218 if (err_ret
&& err_ret
->e_text
&& strlen(*err_ret
->e_text
))
1220 strncat (pop_error
, " [server says '",
1221 ERROR_MAX
- strlen (pop_error
) - 1);
1222 strncat (pop_error
, *err_ret
->e_text
,
1223 ERROR_MAX
- strlen (pop_error
) - 1);
1224 strncat (pop_error
, "']",
1225 ERROR_MAX
- strlen (pop_error
) - 1);
1229 krb5_free_error (kcontext
, err_ret
);
1230 krb5_auth_con_free (kcontext
, auth_context
);
1231 krb5_free_context (kcontext
);
1236 #else /* ! KERBEROS5 */
1237 ticket
= (KTEXT
) malloc (sizeof (KTEXT_ST
));
1238 rem
= krb_sendauth (0L, sock
, ticket
, "pop", realhost
,
1239 (char *) krb_realmofhost (realhost
),
1240 (unsigned long) 0, &msg_data
, &cred
, schedule
,
1241 (struct sockaddr_in
*) 0,
1242 (struct sockaddr_in
*) 0,
1244 free ((char *) ticket
);
1245 if (rem
!= KSUCCESS
)
1247 strcpy (pop_error
, KRB_ERROR
);
1248 strncat (pop_error
, krb_err_txt
[rem
],
1249 ERROR_MAX
- sizeof (KRB_ERROR
));
1253 #endif /* KERBEROS5 */
1255 #endif /* KERBEROS */
1258 } /* socket_connection */
1261 * Function: pop_getline
1263 * Purpose: Get a line of text from the connection and return a
1264 * pointer to it. The carriage return and linefeed at the end of
1265 * the line are stripped, but periods at the beginnings of lines
1266 * are NOT dealt with in any special way.
1269 * server The server from which to get the line of text.
1271 * Returns: The number of characters in the line, which is returned in
1272 * LINE, not including the final null. A return value of 0
1273 * indicates a blank line. A negative return value indicates an
1274 * error (in which case the contents of LINE are undefined. In
1275 * case of error, an error message is copied into pop_error.
1277 * Notes: The line returned is overwritten with each call to pop_getline.
1279 * Side effects: Closes the connection on error.
1281 * THE RETURNED LINE MAY CONTAIN EMBEDDED NULLS!
1284 pop_getline (popserver server
, char **line
)
1286 #define GETLINE_ERROR "Error reading from server: "
1289 int search_offset
= 0;
1293 char *cp
= find_crlf (server
->buffer
+ server
->buffer_index
,
1300 found
= server
->buffer_index
;
1301 data_used
= (cp
+ 2) - server
->buffer
- found
;
1303 *cp
= '\0'; /* terminate the string to be returned */
1304 server
->data
-= data_used
;
1305 server
->buffer_index
+= data_used
;
1308 /* Embedded nulls will truncate this output prematurely,
1309 but that's OK because it's just for debugging anyway. */
1310 fprintf (stderr
, "<<< %s\n", server
->buffer
+ found
);
1311 *line
= server
->buffer
+ found
;
1312 return (data_used
- 2);
1316 memmove (server
->buffer
, server
->buffer
+ server
->buffer_index
,
1318 /* Record the fact that we've searched the data already in
1319 the buffer for a CRLF, so that when we search below, we
1320 don't have to search the same data twice. There's a "-
1321 1" here to account for the fact that the last character
1322 of the data we have may be the CR of a CRLF pair, of
1323 which we haven't read the second half yet, so we may have
1324 to search it again when we read more data. */
1325 search_offset
= server
->data
- 1;
1326 server
->buffer_index
= 0;
1331 server
->buffer_index
= 0;
1336 /* There's a "- 1" here to leave room for the null that we put
1337 at the end of the read data below. We put the null there so
1338 that find_crlf knows where to stop when we call it. */
1339 if (server
->data
== server
->buffer_size
- 1)
1341 server
->buffer_size
+= GETLINE_INCR
;
1342 server
->buffer
= (char *)realloc (server
->buffer
, server
->buffer_size
);
1343 if (! server
->buffer
)
1345 strcpy (pop_error
, "Out of memory in pop_getline");
1350 ret
= RECV (server
->file
, server
->buffer
+ server
->data
,
1351 server
->buffer_size
- server
->data
- 1, 0);
1354 strcpy (pop_error
, GETLINE_ERROR
);
1355 strncat (pop_error
, strerror (errno
),
1356 ERROR_MAX
- sizeof (GETLINE_ERROR
));
1362 strcpy (pop_error
, "Unexpected EOF from server in pop_getline");
1369 server
->data
+= ret
;
1370 server
->buffer
[server
->data
] = '\0';
1372 cp
= find_crlf (server
->buffer
+ search_offset
,
1373 server
->data
- search_offset
);
1376 int data_used
= (cp
+ 2) - server
->buffer
;
1378 server
->data
-= data_used
;
1379 server
->buffer_index
= data_used
;
1382 fprintf (stderr
, "<<< %s\n", server
->buffer
);
1383 *line
= server
->buffer
;
1384 return (data_used
- 2);
1386 /* As above, the "- 1" here is to account for the fact that
1387 we may have read a CR without its accompanying LF. */
1388 search_offset
+= ret
- 1;
1396 * Function: sendline
1398 * Purpose: Sends a line of text to the POP server. The line of text
1399 * passed into this function should NOT have the carriage return
1400 * and linefeed on the end of it. Periods at beginnings of lines
1401 * will NOT be treated specially by this function.
1404 * server The server to which to send the text.
1405 * line The line of text to send.
1407 * Return value: Upon successful completion, a value of 0 will be
1408 * returned. Otherwise, a non-zero value will be returned, and
1409 * an error will be copied into pop_error.
1411 * Side effects: Closes the connection on error.
1414 sendline (popserver server
, const char *line
)
1416 #define SENDLINE_ERROR "Error writing to POP server: "
1420 /* Combine the string and the CR-LF into one buffer. Otherwise, two
1421 reasonable network stack optimizations, Nagle's algorithm and
1422 delayed acks, combine to delay us a fraction of a second on every
1423 message we send. (Movemail writes line without \r\n, client
1424 kernel sends packet, server kernel delays the ack to see if it
1425 can combine it with data, movemail writes \r\n, client kernel
1426 waits because it has unacked data already in its outgoing queue,
1427 client kernel eventually times out and sends.)
1429 This can be something like 0.2s per command, which can add up
1430 over a few dozen messages, and is a big chunk of the time we
1431 spend fetching mail from a server close by. */
1432 buf
= alloca (strlen (line
) + 3);
1434 strcat (buf
, "\r\n");
1435 ret
= fullwrite (server
->file
, buf
, strlen (buf
));
1440 strcpy (pop_error
, SENDLINE_ERROR
);
1441 strncat (pop_error
, strerror (errno
),
1442 ERROR_MAX
- sizeof (SENDLINE_ERROR
));
1447 fprintf (stderr
, ">>> %s\n", line
);
1453 * Procedure: fullwrite
1455 * Purpose: Just like write, but keeps trying until the entire string
1458 * Return value: Same as write. Pop_error is not set.
1461 fullwrite (int fd
, char *buf
, int nbytes
)
1467 while (nbytes
&& ((ret
= SEND (fd
, cp
, nbytes
, 0)) > 0))
1479 * Purpose: Reads a line from the server. If the return indicator is
1480 * positive, return with a zero exit status. If not, return with
1481 * a negative exit status.
1484 * server The server to read from.
1486 * Returns: 0 for success, else for failure and puts error in pop_error.
1488 * Side effects: On failure, may make the connection unusable.
1491 getok (popserver server
)
1495 if (pop_getline (server
, &fromline
) < 0)
1500 if (! strncmp (fromline
, "+OK", 3))
1502 else if (! strncmp (fromline
, "-ERR", 4))
1504 strncpy (pop_error
, fromline
, ERROR_MAX
);
1505 pop_error
[ERROR_MAX
-1] = '\0';
1511 "Unexpected response from server; expecting +OK or -ERR");
1519 * Function: gettermination
1521 * Purpose: Gets the next line and verifies that it is a termination
1522 * line (nothing but a dot).
1524 * Return value: 0 on success, non-zero with pop_error set on error.
1526 * Side effects: Closes the connection on error.
1529 gettermination (server
)
1534 if (pop_getline (server
, &fromserver
) < 0)
1537 if (strcmp (fromserver
, "."))
1540 "Unexpected response from server in gettermination");
1550 * Function pop_close
1552 * Purpose: Close a pop connection, sending a "RSET" command to try to
1553 * preserve any changes that were made and a "QUIT" command to
1554 * try to get the server to quit, but ignoring any responses that
1557 * Side effects: The server is unusable after this function returns.
1558 * Changes made to the maildrop since the session was started (or
1559 * since the last pop_reset) may be lost.
1562 pop_close (popserver server
)
1565 free ((char *) server
);
1571 * Function: pop_trash
1573 * Purpose: Like pop_close or pop_quit, but doesn't deallocate the
1574 * memory associated with the server. It is valid to call
1575 * pop_close or pop_quit after this function has been called.
1578 pop_trash (popserver server
)
1580 if (server
->file
>= 0)
1582 /* avoid recursion; sendline can call pop_trash */
1583 if (server
->trash_started
)
1585 server
->trash_started
= 1;
1587 sendline (server
, "RSET");
1588 sendline (server
, "QUIT");
1590 CLOSESOCKET (server
->file
);
1594 free (server
->buffer
);
1605 /* Return a pointer to the first CRLF in IN_STRING, which can contain
1606 embedded nulls and has LEN characters in it not including the final
1607 null, or 0 if it does not contain one. */
1610 find_crlf (char *in_string
, int len
)
1614 if (*in_string
== '\r')
1616 if (*++in_string
== '\n')
1617 return (in_string
- 1);
1625 #endif /* MAIL_USE_POP */