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