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