root/trunk/lib-src/pop.c

Revision 4220, 37.4 kB (checked in by miyoshi, 5 months ago)

Sync up with Emacs22.2.

  • Property svn:eol-style set to native
Line 
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, 2008  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   char *end_ptr;
356
357   if (server->in_multi)
358     {
359       strcpy (pop_error, "In multi-line query in pop_stat");
360       return (-1);
361     }
362
363   if (sendline (server, "STAT") || (pop_getline (server, &fromserver) < 0))
364     return (-1);
365
366   if (strncmp (fromserver, "+OK ", 4))
367     {
368       if (0 == strncmp (fromserver, "-ERR", 4))
369         {
370           strncpy (pop_error, fromserver, ERROR_MAX);
371         }
372       else
373         {
374           strcpy (pop_error,
375                   "Unexpected response from POP server in pop_stat");
376           pop_trash (server);
377         }
378       return (-1);
379     }
380
381   errno = 0;
382   *count = strtol (&fromserver[4], &end_ptr, 10);
383   /* Check validity of string-to-integer conversion. */
384   if (fromserver + 4 == end_ptr || *end_ptr != ' ' || errno)
385     {
386       strcpy (pop_error, "Unexpected response from POP server in pop_stat");
387       pop_trash (server);
388       return (-1);
389     }
390
391   fromserver = end_ptr;
392
393   errno = 0;
394   *size = strtol (fromserver + 1, &end_ptr, 10);
395   if (fromserver + 1 == end_ptr || errno)
396     {
397       strcpy (pop_error, "Unexpected response from POP server in pop_stat");
398       pop_trash (server);
399       return (-1);
400     }
401
402   return (0);
403 }
404
405 /*
406  * Function: pop_list
407  *
408  * Purpose: Performs the POP "list" command and returns (in value
409  *      parameters) two malloc'd zero-terminated arrays -- one of
410  *      message IDs, and a parallel one of sizes.
411  *
412  * Arguments:
413  *      server  The pop connection to talk to.
414  *      message The number of the one message about which to get
415  *              information, or 0 to get information about all
416  *              messages.
417  *
418  * Return value: 0 on success, non-zero with error in pop_error on
419  *      failure.
420  *
421  * Side effects: On failure, may make further operations on the
422  *      connection impossible.
423  */
424 int
425 pop_list (server, message, IDs, sizes)
426      popserver server;
427      int message;
428      int **IDs;
429      int **sizes;
430 {
431   int how_many, i;
432   char *fromserver;
433
434   if (server->in_multi)
435     {
436       strcpy (pop_error, "In multi-line query in pop_list");
437       return (-1);
438     }
439
440   if (message)
441     how_many = 1;
442   else
443     {
444       int count, size;
445       if (pop_stat (server, &count, &size))
446         return (-1);
447       how_many = count;
448     }
449
450   *IDs = (int *) malloc ((how_many + 1) * sizeof (int));
451   *sizes = (int *) malloc ((how_many + 1) * sizeof (int));
452   if (! (*IDs && *sizes))
453     {
454       strcpy (pop_error, "Out of memory in pop_list");
455       return (-1);
456     }
457
458   if (message)
459     {
460       sprintf (pop_error, "LIST %d", message);
461       if (sendline (server, pop_error))
462         {
463           free ((char *) *IDs);
464           free ((char *) *sizes);
465           return (-1);
466         }
467       if (pop_getline (server, &fromserver) < 0)
468         {
469           free ((char *) *IDs);
470           free ((char *) *sizes);
471           return (-1);
472         }
473       if (strncmp (fromserver, "+OK ", 4))
474         {
475           if (! strncmp (fromserver, "-ERR", 4))
476             strncpy (pop_error, fromserver, ERROR_MAX);
477           else
478             {
479               strcpy (pop_error,
480                       "Unexpected response from server in pop_list");
481               pop_trash (server);
482             }
483           free ((char *) *IDs);
484           free ((char *) *sizes);
485           return (-1);
486         }
487       (*IDs)[0] = atoi (&fromserver[4]);
488       fromserver = index (&fromserver[4], ' ');
489       if (! fromserver)
490         {
491           strcpy (pop_error,
492                   "Badly formatted response from server in pop_list");
493           pop_trash (server);
494           free ((char *) *IDs);
495           free ((char *) *sizes);
496           return (-1);
497         }
498       (*sizes)[0] = atoi (fromserver);
499       (*IDs)[1] = (*sizes)[1] = 0;
500       return (0);
501     }
502   else
503     {
504       if (pop_multi_first (server, "LIST", &fromserver))
505         {
506           free ((char *) *IDs);
507           free ((char *) *sizes);
508           return (-1);
509         }
510       for (i = 0; i < how_many; i++)
511         {
512           if (pop_multi_next (server, &fromserver) <= 0)
513             {
514               free ((char *) *IDs);
515               free ((char *) *sizes);
516               return (-1);
517             }
518           (*IDs)[i] = atoi (fromserver);
519           fromserver = index (fromserver, ' ');
520           if (! fromserver)
521             {
522               strcpy (pop_error,
523                       "Badly formatted response from server in pop_list");
524               free ((char *) *IDs);
525               free ((char *) *sizes);
526               pop_trash (server);
527               return (-1);
528             }
529           (*sizes)[i] = atoi (fromserver);
530         }
531       if (pop_multi_next (server, &fromserver) < 0)
532         {
533           free ((char *) *IDs);
534           free ((char *) *sizes);
535           return (-1);
536         }
537       else if (fromserver)
538         {
539           strcpy (pop_error,
540                   "Too many response lines from server in pop_list");
541           free ((char *) *IDs);
542           free ((char *) *sizes);
543           return (-1);
544         }
545       (*IDs)[i] = (*sizes)[i] = 0;
546       return (0);
547     }
548 }
549
550 /*
551  * Function: pop_retrieve
552  *
553  * Purpose: Retrieve a specified message from the maildrop.
554  *
555  * Arguments:
556  *      server  The server to retrieve from.
557  *      message The message number to retrieve.
558  *      markfrom
559  *              If true, then mark the string "From " at the beginning
560  *              of lines with '>'.
561  *      msg_buf Output parameter to which a buffer containing the
562  *              message is assigned.
563  *
564  * Return value: The number of bytes in msg_buf, which may contain
565  *      embedded nulls, not including its final null, or -1 on error
566  *      with pop_error set.
567  *
568  * Side effects: May kill connection on error.
569  */
570 int
571 pop_retrieve (server, message, markfrom, msg_buf)
572      popserver server;
573      int message;
574      int markfrom;
575      char **msg_buf;
576 {
577   int *IDs, *sizes, bufsize, fromcount = 0, cp = 0;
578   char *ptr, *fromserver;
579   int ret;
580
581   if (server->in_multi)
582     {
583       strcpy (pop_error, "In multi-line query in pop_retrieve");
584       return (-1);
585     }
586
587   if (pop_list (server, message, &IDs, &sizes))
588     return (-1);
589
590   if (pop_retrieve_first (server, message, &fromserver))
591     {
592       return (-1);
593     }
594
595   /*
596    * The "5" below is an arbitrary constant -- I assume that if
597    * there are "From" lines in the text to be marked, there
598    * probably won't be more than 5 of them.  If there are, I
599    * allocate more space for them below.
600    */
601   bufsize = sizes[0] + (markfrom ? 5 : 0);
602   ptr = (char *)malloc (bufsize);
603   free ((char *) IDs);
604   free ((char *) sizes);
605
606   if (! ptr)
607     {
608       strcpy (pop_error, "Out of memory in pop_retrieve");
609       pop_retrieve_flush (server);
610       return (-1);
611     }
612
613   while ((ret = pop_retrieve_next (server, &fromserver)) >= 0)
614     {
615       if (! fromserver)
616         {
617           ptr[cp] = '\0';
618           *msg_buf = ptr;
619           return (cp);
620         }
621       if (markfrom && fromserver[0] == 'F' && fromserver[1] == 'r' &&
622           fromserver[2] == 'o' && fromserver[3] == 'm' &&
623           fromserver[4] == ' ')
624         {
625           if (++fromcount == 5)
626             {
627               bufsize += 5;
628               ptr =