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