mutt stable branch with some hacks
at master 948 lines 22 kB view raw
1/* 2 * Copyright (C) 2000-2002 Vsevolod Volkov <vvv@mutt.org.ua> 3 * Copyright (C) 2006-2007,2009 Rocco Rutte <pdmef@gmx.net> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 */ 19 20#if HAVE_CONFIG_H 21# include "config.h" 22#endif 23 24#include "mutt.h" 25#include "mutt_curses.h" 26#include "mx.h" 27#include "pop.h" 28#include "mutt_crypt.h" 29#include "bcache.h" 30#if USE_HCACHE 31#include "hcache.h" 32#endif 33 34#include <string.h> 35#include <unistd.h> 36#include <errno.h> 37 38#ifdef USE_HCACHE 39#define HC_FNAME "mutt" /* filename for hcache as POP lacks paths */ 40#define HC_FEXT "hcache" /* extension for hcache as POP lacks paths */ 41#endif 42 43/* write line to file */ 44static int fetch_message (char *line, void *file) 45{ 46 FILE *f = (FILE *) file; 47 48 fputs (line, f); 49 if (fputc ('\n', f) == EOF) 50 return -1; 51 52 return 0; 53} 54 55/* 56 * Read header 57 * returns: 58 * 0 on success 59 * -1 - connection lost, 60 * -2 - invalid command or execution error, 61 * -3 - error writing to tempfile 62 */ 63static int pop_read_header (POP_DATA *pop_data, HEADER *h) 64{ 65 FILE *f; 66 int ret, index; 67 long length; 68 char buf[LONG_STRING]; 69 char tempfile[_POSIX_PATH_MAX]; 70 71 mutt_mktemp (tempfile, sizeof (tempfile)); 72 if (!(f = safe_fopen (tempfile, "w+"))) 73 { 74 mutt_perror (tempfile); 75 return -3; 76 } 77 78 snprintf (buf, sizeof (buf), "LIST %d\r\n", h->refno); 79 ret = pop_query (pop_data, buf, sizeof (buf)); 80 if (ret == 0) 81 { 82 sscanf (buf, "+OK %d %ld", &index, &length); 83 84 snprintf (buf, sizeof (buf), "TOP %d 0\r\n", h->refno); 85 ret = pop_fetch_data (pop_data, buf, NULL, fetch_message, f); 86 87 if (pop_data->cmd_top == 2) 88 { 89 if (ret == 0) 90 { 91 pop_data->cmd_top = 1; 92 93 dprint (1, (debugfile, "pop_read_header: set TOP capability\n")); 94 } 95 96 if (ret == -2) 97 { 98 pop_data->cmd_top = 0; 99 100 dprint (1, (debugfile, "pop_read_header: unset TOP capability\n")); 101 snprintf (pop_data->err_msg, sizeof (pop_data->err_msg), 102 _("Command TOP is not supported by server.")); 103 } 104 } 105 } 106 107 switch (ret) 108 { 109 case 0: 110 { 111 rewind (f); 112 h->env = mutt_read_rfc822_header (f, h, 0, 0); 113 h->content->length = length - h->content->offset + 1; 114 rewind (f); 115 while (!feof (f)) 116 { 117 h->content->length--; 118 fgets (buf, sizeof (buf), f); 119 } 120 break; 121 } 122 case -2: 123 { 124 mutt_error ("%s", pop_data->err_msg); 125 break; 126 } 127 case -3: 128 { 129 mutt_error _("Can't write header to temporary file!"); 130 break; 131 } 132 } 133 134 safe_fclose (&f); 135 unlink (tempfile); 136 return ret; 137} 138 139/* parse UIDL */ 140static int fetch_uidl (char *line, void *data) 141{ 142 int i, index; 143 CONTEXT *ctx = (CONTEXT *)data; 144 POP_DATA *pop_data = (POP_DATA *)ctx->data; 145 char *endp; 146 147 errno = 0; 148 index = strtol(line, &endp, 10); 149 if (errno) 150 return -1; 151 while (*endp == ' ') 152 endp++; 153 memmove(line, endp, strlen(endp) + 1); 154 155 for (i = 0; i < ctx->msgcount; i++) 156 if (!mutt_strcmp (line, ctx->hdrs[i]->data)) 157 break; 158 159 if (i == ctx->msgcount) 160 { 161 dprint (1, (debugfile, "pop_fetch_headers: new header %d %s\n", index, line)); 162 163 if (i >= ctx->hdrmax) 164 mx_alloc_memory(ctx); 165 166 ctx->msgcount++; 167 ctx->hdrs[i] = mutt_new_header (); 168 ctx->hdrs[i]->data = safe_strdup (line); 169 } 170 else if (ctx->hdrs[i]->index != index - 1) 171 pop_data->clear_cache = 1; 172 173 ctx->hdrs[i]->refno = index; 174 ctx->hdrs[i]->index = index - 1; 175 176 return 0; 177} 178 179static int msg_cache_check (const char *id, body_cache_t *bcache, void *data) 180{ 181 CONTEXT *ctx; 182 POP_DATA *pop_data; 183 int i; 184 185 if (!(ctx = (CONTEXT *)data)) 186 return -1; 187 if (!(pop_data = (POP_DATA *)ctx->data)) 188 return -1; 189 190#ifdef USE_HCACHE 191 /* keep hcache file if hcache == bcache */ 192 if (strcmp (HC_FNAME "." HC_FEXT, id) == 0) 193 return 0; 194#endif 195 196 for (i = 0; i < ctx->msgcount; i++) 197 /* if the id we get is known for a header: done (i.e. keep in cache) */ 198 if (ctx->hdrs[i]->data && mutt_strcmp (ctx->hdrs[i]->data, id) == 0) 199 return 0; 200 201 /* message not found in context -> remove it from cache 202 * return the result of bcache, so we stop upon its first error 203 */ 204 return mutt_bcache_del (bcache, id); 205} 206 207#ifdef USE_HCACHE 208static int pop_hcache_namer (const char *path, char *dest, size_t destlen) 209{ 210 return snprintf (dest, destlen, "%s." HC_FEXT, path); 211} 212 213static header_cache_t *pop_hcache_open (POP_DATA *pop_data, const char *path) 214{ 215 ciss_url_t url; 216 char p[LONG_STRING]; 217 218 if (!pop_data || !pop_data->conn) 219 return mutt_hcache_open (HeaderCache, path, NULL); 220 221 mutt_account_tourl (&pop_data->conn->account, &url); 222 url.path = HC_FNAME; 223 url_ciss_tostring (&url, p, sizeof (p), U_PATH); 224 return mutt_hcache_open (HeaderCache, p, pop_hcache_namer); 225} 226#endif 227 228/* 229 * Read headers 230 * returns: 231 * 0 on success 232 * -1 - connection lost, 233 * -2 - invalid command or execution error, 234 * -3 - error writing to tempfile 235 */ 236static int pop_fetch_headers (CONTEXT *ctx) 237{ 238 int i, ret, old_count, new_count, deleted; 239 unsigned short hcached = 0, bcached; 240 POP_DATA *pop_data = (POP_DATA *)ctx->data; 241 progress_t progress; 242 243#ifdef USE_HCACHE 244 header_cache_t *hc = NULL; 245 void *data; 246 247 hc = pop_hcache_open (pop_data, ctx->path); 248#endif 249 250 time (&pop_data->check_time); 251 pop_data->clear_cache = 0; 252 253 for (i = 0; i < ctx->msgcount; i++) 254 ctx->hdrs[i]->refno = -1; 255 256 old_count = ctx->msgcount; 257 ret = pop_fetch_data (pop_data, "UIDL\r\n", NULL, fetch_uidl, ctx); 258 new_count = ctx->msgcount; 259 ctx->msgcount = old_count; 260 261 if (pop_data->cmd_uidl == 2) 262 { 263 if (ret == 0) 264 { 265 pop_data->cmd_uidl = 1; 266 267 dprint (1, (debugfile, "pop_fetch_headers: set UIDL capability\n")); 268 } 269 270 if (ret == -2 && pop_data->cmd_uidl == 2) 271 { 272 pop_data->cmd_uidl = 0; 273 274 dprint (1, (debugfile, "pop_fetch_headers: unset UIDL capability\n")); 275 snprintf (pop_data->err_msg, sizeof (pop_data->err_msg), 276 _("Command UIDL is not supported by server.")); 277 } 278 } 279 280 if (!ctx->quiet) 281 mutt_progress_init (&progress, _("Fetching message headers..."), 282 MUTT_PROGRESS_MSG, ReadInc, new_count - old_count); 283 284 if (ret == 0) 285 { 286 for (i = 0, deleted = 0; i < old_count; i++) 287 { 288 if (ctx->hdrs[i]->refno == -1) 289 { 290 ctx->hdrs[i]->deleted = 1; 291 deleted++; 292 } 293 } 294 if (deleted > 0) 295 { 296 mutt_error (_("%d messages have been lost. Try reopening the mailbox."), 297 deleted); 298 mutt_sleep (2); 299 } 300 301 for (i = old_count; i < new_count; i++) 302 { 303 if (!ctx->quiet) 304 mutt_progress_update (&progress, i + 1 - old_count, -1); 305#if USE_HCACHE 306 if ((data = mutt_hcache_fetch (hc, ctx->hdrs[i]->data, strlen))) 307 { 308 char *uidl = safe_strdup (ctx->hdrs[i]->data); 309 int refno = ctx->hdrs[i]->refno; 310 int index = ctx->hdrs[i]->index; 311 /* 312 * - POP dynamically numbers headers and relies on h->refno 313 * to map messages; so restore header and overwrite restored 314 * refno with current refno, same for index 315 * - h->data needs to a separate pointer as it's driver-specific 316 * data freed separately elsewhere 317 * (the old h->data should point inside a malloc'd block from 318 * hcache so there shouldn't be a memleak here) 319 */ 320 HEADER *h = mutt_hcache_restore ((unsigned char *) data, NULL); 321 mutt_free_header (&ctx->hdrs[i]); 322 ctx->hdrs[i] = h; 323 ctx->hdrs[i]->refno = refno; 324 ctx->hdrs[i]->index = index; 325 ctx->hdrs[i]->data = uidl; 326 ret = 0; 327 hcached = 1; 328 } 329 else 330#endif 331 if ((ret = pop_read_header (pop_data, ctx->hdrs[i])) < 0) 332 break; 333#if USE_HCACHE 334 else 335 { 336 mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen, MUTT_GENERATE_UIDVALIDITY); 337 } 338 339 FREE(&data); 340#endif 341 342 /* 343 * faked support for flags works like this: 344 * - if 'hcached' is 1, we have the message in our hcache: 345 * - if we also have a body: read 346 * - if we don't have a body: old 347 * (if $mark_old is set which is maybe wrong as 348 * $mark_old should be considered for syncing the 349 * folder and not when opening it XXX) 350 * - if 'hcached' is 0, we don't have the message in our hcache: 351 * - if we also have a body: read 352 * - if we don't have a body: new 353 */ 354 bcached = mutt_bcache_exists (pop_data->bcache, ctx->hdrs[i]->data) == 0; 355 ctx->hdrs[i]->old = 0; 356 ctx->hdrs[i]->read = 0; 357 if (hcached) 358 { 359 if (bcached) 360 ctx->hdrs[i]->read = 1; 361 else if (option (OPTMARKOLD)) 362 ctx->hdrs[i]->old = 1; 363 } 364 else 365 { 366 if (bcached) 367 ctx->hdrs[i]->read = 1; 368 } 369 370 ctx->msgcount++; 371 } 372 373 if (i > old_count) 374 mx_update_context (ctx, i - old_count); 375 } 376 377#if USE_HCACHE 378 mutt_hcache_close (hc); 379#endif 380 381 if (ret < 0) 382 { 383 for (i = ctx->msgcount; i < new_count; i++) 384 mutt_free_header (&ctx->hdrs[i]); 385 return ret; 386 } 387 388 /* after putting the result into our structures, 389 * clean up cache, i.e. wipe messages deleted outside 390 * the availability of our cache 391 */ 392 if (option (OPTMESSAGECACHECLEAN)) 393 mutt_bcache_list (pop_data->bcache, msg_cache_check, (void*)ctx); 394 395 mutt_clear_error (); 396 return (new_count - old_count); 397} 398 399/* open POP mailbox - fetch only headers */ 400static int pop_open_mailbox (CONTEXT *ctx) 401{ 402 int ret; 403 char buf[LONG_STRING]; 404 CONNECTION *conn; 405 ACCOUNT acct; 406 POP_DATA *pop_data; 407 ciss_url_t url; 408 409 if (pop_parse_path (ctx->path, &acct)) 410 { 411 mutt_error (_("%s is an invalid POP path"), ctx->path); 412 mutt_sleep (2); 413 return -1; 414 } 415 416 mutt_account_tourl (&acct, &url); 417 url.path = NULL; 418 url_ciss_tostring (&url, buf, sizeof (buf), 0); 419 conn = mutt_conn_find (NULL, &acct); 420 if (!conn) 421 return -1; 422 423 FREE (&ctx->path); 424 FREE (&ctx->realpath); 425 ctx->path = safe_strdup (buf); 426 ctx->realpath = safe_strdup (ctx->path); 427 428 pop_data = safe_calloc (1, sizeof (POP_DATA)); 429 pop_data->conn = conn; 430 ctx->data = pop_data; 431 432 if (pop_open_connection (pop_data) < 0) 433 return -1; 434 435 conn->data = pop_data; 436 pop_data->bcache = mutt_bcache_open (&acct, NULL); 437 438 /* init (hard-coded) ACL rights */ 439 memset (ctx->rights, 0, sizeof (ctx->rights)); 440 mutt_bit_set (ctx->rights, MUTT_ACL_SEEN); 441 mutt_bit_set (ctx->rights, MUTT_ACL_DELETE); 442#if USE_HCACHE 443 /* flags are managed using header cache, so it only makes sense to 444 * enable them in that case */ 445 mutt_bit_set (ctx->rights, MUTT_ACL_WRITE); 446#endif 447 448 FOREVER 449 { 450 if (pop_reconnect (ctx) < 0) 451 return -1; 452 453 ctx->size = pop_data->size; 454 455 mutt_message _("Fetching list of messages..."); 456 457 ret = pop_fetch_headers (ctx); 458 459 if (ret >= 0) 460 return 0; 461 462 if (ret < -1) 463 { 464 mutt_sleep (2); 465 return -1; 466 } 467 } 468} 469 470/* delete all cached messages */ 471static void pop_clear_cache (POP_DATA *pop_data) 472{ 473 int i; 474 475 if (!pop_data->clear_cache) 476 return; 477 478 dprint (1, (debugfile, "pop_clear_cache: delete cached messages\n")); 479 480 for (i = 0; i < POP_CACHE_LEN; i++) 481 { 482 if (pop_data->cache[i].path) 483 { 484 unlink (pop_data->cache[i].path); 485 FREE (&pop_data->cache[i].path); 486 } 487 } 488} 489 490/* close POP mailbox */ 491int pop_close_mailbox (CONTEXT *ctx) 492{ 493 POP_DATA *pop_data = (POP_DATA *)ctx->data; 494 495 if (!pop_data) 496 return 0; 497 498 pop_logout (ctx); 499 500 if (pop_data->status != POP_NONE) 501 mutt_socket_close (pop_data->conn); 502 503 pop_data->status = POP_NONE; 504 505 pop_data->clear_cache = 1; 506 pop_clear_cache (pop_data); 507 508 if (!pop_data->conn->data) 509 mutt_socket_free (pop_data->conn); 510 511 mutt_bcache_close (&pop_data->bcache); 512 513 return 0; 514} 515 516/* fetch message from POP server */ 517static int pop_fetch_message (CONTEXT* ctx, MESSAGE* msg, int msgno) 518{ 519 int ret; 520 void *uidl; 521 char buf[LONG_STRING]; 522 char path[_POSIX_PATH_MAX]; 523 progress_t progressbar; 524 POP_DATA *pop_data = (POP_DATA *)ctx->data; 525 POP_CACHE *cache; 526 HEADER *h = ctx->hdrs[msgno]; 527 unsigned short bcache = 1; 528 529 /* see if we already have the message in body cache */ 530 if ((msg->fp = mutt_bcache_get (pop_data->bcache, h->data))) 531 return 0; 532 533 /* 534 * see if we already have the message in our cache in 535 * case $message_cachedir is unset 536 */ 537 cache = &pop_data->cache[h->index % POP_CACHE_LEN]; 538 539 if (cache->path) 540 { 541 if (cache->index == h->index) 542 { 543 /* yes, so just return a pointer to the message */ 544 msg->fp = fopen (cache->path, "r"); 545 if (msg->fp) 546 return 0; 547 548 mutt_perror (cache->path); 549 mutt_sleep (2); 550 return -1; 551 } 552 else 553 { 554 /* clear the previous entry */ 555 unlink (cache->path); 556 FREE (&cache->path); 557 } 558 } 559 560 FOREVER 561 { 562 if (pop_reconnect (ctx) < 0) 563 return -1; 564 565 /* verify that massage index is correct */ 566 if (h->refno < 0) 567 { 568 mutt_error _("The message index is incorrect. Try reopening the mailbox."); 569 mutt_sleep (2); 570 return -1; 571 } 572 573 mutt_progress_init (&progressbar, _("Fetching message..."), 574 MUTT_PROGRESS_SIZE, NetInc, h->content->length + h->content->offset - 1); 575 576 /* see if we can put in body cache; use our cache as fallback */ 577 if (!(msg->fp = mutt_bcache_put (pop_data->bcache, h->data, 1))) 578 { 579 /* no */ 580 bcache = 0; 581 mutt_mktemp (path, sizeof (path)); 582 if (!(msg->fp = safe_fopen (path, "w+"))) 583 { 584 mutt_perror (path); 585 mutt_sleep (2); 586 return -1; 587 } 588 } 589 590 snprintf (buf, sizeof (buf), "RETR %d\r\n", h->refno); 591 592 ret = pop_fetch_data (pop_data, buf, &progressbar, fetch_message, msg->fp); 593 if (ret == 0) 594 break; 595 596 safe_fclose (&msg->fp); 597 598 /* if RETR failed (e.g. connection closed), be sure to remove either 599 * the file in bcache or from POP's own cache since the next iteration 600 * of the loop will re-attempt to put() the message */ 601 if (!bcache) 602 unlink (path); 603 604 if (ret == -2) 605 { 606 mutt_error ("%s", pop_data->err_msg); 607 mutt_sleep (2); 608 return -1; 609 } 610 611 if (ret == -3) 612 { 613 mutt_error _("Can't write message to temporary file!"); 614 mutt_sleep (2); 615 return -1; 616 } 617 } 618 619 /* Update the header information. Previously, we only downloaded a 620 * portion of the headers, those required for the main display. 621 */ 622 if (bcache) 623 mutt_bcache_commit (pop_data->bcache, h->data); 624 else 625 { 626 cache->index = h->index; 627 cache->path = safe_strdup (path); 628 } 629 rewind (msg->fp); 630 uidl = h->data; 631 632 /* we replace envelop, key in subj_hash has to be updated as well */ 633 if (ctx->subj_hash && h->env->real_subj) 634 hash_delete (ctx->subj_hash, h->env->real_subj, h, NULL); 635 mutt_free_envelope (&h->env); 636 h->env = mutt_read_rfc822_header (msg->fp, h, 0, 0); 637 if (ctx->subj_hash && h->env->real_subj) 638 hash_insert (ctx->subj_hash, h->env->real_subj, h, 1); 639 640 h->data = uidl; 641 h->lines = 0; 642 fgets (buf, sizeof (buf), msg->fp); 643 while (!feof (msg->fp)) 644 { 645 ctx->hdrs[msgno]->lines++; 646 fgets (buf, sizeof (buf), msg->fp); 647 } 648 649 h->content->length = ftello (msg->fp) - h->content->offset; 650 651 /* This needs to be done in case this is a multipart message */ 652 if (!WithCrypto) 653 h->security = crypt_query (h->content); 654 655 mutt_clear_error(); 656 rewind (msg->fp); 657 658 return 0; 659} 660 661static int pop_close_message (CONTEXT *ctx, MESSAGE *msg) 662{ 663 return safe_fclose (&msg->fp); 664} 665 666/* update POP mailbox - delete messages from server */ 667static int pop_sync_mailbox (CONTEXT *ctx, int *index_hint) 668{ 669 int i, j, ret = 0; 670 char buf[LONG_STRING]; 671 POP_DATA *pop_data = (POP_DATA *)ctx->data; 672 progress_t progress; 673#ifdef USE_HCACHE 674 header_cache_t *hc = NULL; 675#endif 676 677 pop_data->check_time = 0; 678 679 FOREVER 680 { 681 if (pop_reconnect (ctx) < 0) 682 return -1; 683 684 mutt_progress_init (&progress, _("Marking messages deleted..."), 685 MUTT_PROGRESS_MSG, WriteInc, ctx->deleted); 686 687#if USE_HCACHE 688 hc = pop_hcache_open (pop_data, ctx->path); 689#endif 690 691 for (i = 0, j = 0, ret = 0; ret == 0 && i < ctx->msgcount; i++) 692 { 693 if (ctx->hdrs[i]->deleted && ctx->hdrs[i]->refno != -1) 694 { 695 j++; 696 if (!ctx->quiet) 697 mutt_progress_update (&progress, j, -1); 698 snprintf (buf, sizeof (buf), "DELE %d\r\n", ctx->hdrs[i]->refno); 699 if ((ret = pop_query (pop_data, buf, sizeof (buf))) == 0) 700 { 701 mutt_bcache_del (pop_data->bcache, ctx->hdrs[i]->data); 702#if USE_HCACHE 703 mutt_hcache_delete (hc, ctx->hdrs[i]->data, strlen); 704#endif 705 } 706 } 707 708#if USE_HCACHE 709 if (ctx->hdrs[i]->changed) 710 { 711 mutt_hcache_store (hc, ctx->hdrs[i]->data, ctx->hdrs[i], 0, strlen, MUTT_GENERATE_UIDVALIDITY); 712 } 713#endif 714 715 } 716 717#if USE_HCACHE 718 mutt_hcache_close (hc); 719#endif 720 721 if (ret == 0) 722 { 723 strfcpy (buf, "QUIT\r\n", sizeof (buf)); 724 ret = pop_query (pop_data, buf, sizeof (buf)); 725 } 726 727 if (ret == 0) 728 { 729 pop_data->clear_cache = 1; 730 pop_clear_cache (pop_data); 731 pop_data->status = POP_DISCONNECTED; 732 return 0; 733 } 734 735 if (ret == -2) 736 { 737 mutt_error ("%s", pop_data->err_msg); 738 mutt_sleep (2); 739 return -1; 740 } 741 } 742} 743 744/* Check for new messages and fetch headers */ 745static int pop_check_mailbox (CONTEXT *ctx, int *index_hint) 746{ 747 int ret; 748 POP_DATA *pop_data = (POP_DATA *)ctx->data; 749 750 if ((pop_data->check_time + PopCheckTimeout) > time (NULL)) 751 return 0; 752 753 pop_logout (ctx); 754 755 mutt_socket_close (pop_data->conn); 756 757 if (pop_open_connection (pop_data) < 0) 758 return -1; 759 760 ctx->size = pop_data->size; 761 762 mutt_message _("Checking for new messages..."); 763 764 ret = pop_fetch_headers (ctx); 765 pop_clear_cache (pop_data); 766 767 if (ret < 0) 768 return -1; 769 770 if (ret > 0) 771 return MUTT_NEW_MAIL; 772 773 return 0; 774} 775 776/* Fetch messages and save them in $spoolfile */ 777void pop_fetch_mail (void) 778{ 779 char buffer[LONG_STRING]; 780 char msgbuf[SHORT_STRING]; 781 char *url, *p; 782 int i, delanswer, last = 0, msgs, bytes, rset = 0, ret; 783 CONNECTION *conn; 784 CONTEXT ctx; 785 MESSAGE *msg = NULL; 786 ACCOUNT acct; 787 POP_DATA *pop_data; 788 789 if (!PopHost) 790 { 791 mutt_error _("POP host is not defined."); 792 return; 793 } 794 795 url = p = safe_calloc (strlen (PopHost) + 7, sizeof (char)); 796 if (url_check_scheme (PopHost) == U_UNKNOWN) 797 { 798 strcpy (url, "pop://"); /* __STRCPY_CHECKED__ */ 799 p = strchr (url, '\0'); 800 } 801 strcpy (p, PopHost); /* __STRCPY_CHECKED__ */ 802 803 ret = pop_parse_path (url, &acct); 804 FREE (&url); 805 if (ret) 806 { 807 mutt_error (_("%s is an invalid POP path"), PopHost); 808 return; 809 } 810 811 conn = mutt_conn_find (NULL, &acct); 812 if (!conn) 813 return; 814 815 pop_data = safe_calloc (1, sizeof (POP_DATA)); 816 pop_data->conn = conn; 817 818 if (pop_open_connection (pop_data) < 0) 819 { 820 mutt_socket_free (pop_data->conn); 821 FREE (&pop_data); 822 return; 823 } 824 825 conn->data = pop_data; 826 827 mutt_message _("Checking for new messages..."); 828 829 /* find out how many messages are in the mailbox. */ 830 strfcpy (buffer, "STAT\r\n", sizeof (buffer)); 831 ret = pop_query (pop_data, buffer, sizeof (buffer)); 832 if (ret == -1) 833 goto fail; 834 if (ret == -2) 835 { 836 mutt_error ("%s", pop_data->err_msg); 837 goto finish; 838 } 839 840 sscanf (buffer, "+OK %d %d", &msgs, &bytes); 841 842 /* only get unread messages */ 843 if (msgs > 0 && option (OPTPOPLAST)) 844 { 845 strfcpy (buffer, "LAST\r\n", sizeof (buffer)); 846 ret = pop_query (pop_data, buffer, sizeof (buffer)); 847 if (ret == -1) 848 goto fail; 849 if (ret == 0) 850 sscanf (buffer, "+OK %d", &last); 851 } 852 853 if (msgs <= last) 854 { 855 mutt_message _("No new mail in POP mailbox."); 856 goto finish; 857 } 858 859 if (mx_open_mailbox (NONULL (Spoolfile), MUTT_APPEND, &ctx) == NULL) 860 goto finish; 861 862 delanswer = query_quadoption (OPT_POPDELETE, _("Delete messages from server?")); 863 864 snprintf (msgbuf, sizeof (msgbuf), _("Reading new messages (%d bytes)..."), bytes); 865 mutt_message ("%s", msgbuf); 866 867 for (i = last + 1 ; i <= msgs ; i++) 868 { 869 if ((msg = mx_open_new_message (&ctx, NULL, MUTT_ADD_FROM)) == NULL) 870 ret = -3; 871 else 872 { 873 snprintf (buffer, sizeof (buffer), "RETR %d\r\n", i); 874 ret = pop_fetch_data (pop_data, buffer, NULL, fetch_message, msg->fp); 875 if (ret == -3) 876 rset = 1; 877 878 if (ret == 0 && mx_commit_message (msg, &ctx) != 0) 879 { 880 rset = 1; 881 ret = -3; 882 } 883 884 mx_close_message (&ctx, &msg); 885 } 886 887 if (ret == 0 && delanswer == MUTT_YES) 888 { 889 /* delete the message on the server */ 890 snprintf (buffer, sizeof (buffer), "DELE %d\r\n", i); 891 ret = pop_query (pop_data, buffer, sizeof (buffer)); 892 } 893 894 if (ret == -1) 895 { 896 mx_close_mailbox (&ctx, NULL); 897 goto fail; 898 } 899 if (ret == -2) 900 { 901 mutt_error ("%s", pop_data->err_msg); 902 break; 903 } 904 if (ret == -3) 905 { 906 mutt_error _("Error while writing mailbox!"); 907 break; 908 } 909 910 mutt_message (_("%s [%d of %d messages read]"), msgbuf, i - last, msgs - last); 911 } 912 913 mx_close_mailbox (&ctx, NULL); 914 915 if (rset) 916 { 917 /* make sure no messages get deleted */ 918 strfcpy (buffer, "RSET\r\n", sizeof (buffer)); 919 if (pop_query (pop_data, buffer, sizeof (buffer)) == -1) 920 goto fail; 921 } 922 923finish: 924 /* exit gracefully */ 925 strfcpy (buffer, "QUIT\r\n", sizeof (buffer)); 926 if (pop_query (pop_data, buffer, sizeof (buffer)) == -1) 927 goto fail; 928 mutt_socket_close (conn); 929 FREE (&pop_data); 930 return; 931 932fail: 933 mutt_error _("Server closed connection!"); 934 mutt_socket_close (conn); 935 FREE (&pop_data); 936} 937 938struct mx_ops mx_pop_ops = { 939 .open = pop_open_mailbox, 940 .open_append = NULL, 941 .close = pop_close_mailbox, 942 .open_msg = pop_fetch_message, 943 .close_msg = pop_close_message, 944 .check = pop_check_mailbox, 945 .commit_msg = NULL, 946 .open_new_msg = NULL, 947 .sync = pop_sync_mailbox, 948};