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