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