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