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