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