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