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