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