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