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