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