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