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