mutt stable branch with some hacks
at master 851 lines 19 kB view raw
1/* 2 * Copyright (C) 1996-1998,2010,2012-2013 Michael R. Elkins <me@mutt.org> 3 * Copyright (C) 1996-1999 Brandon Long <blong@fiction.net> 4 * Copyright (C) 1999-2009,2012 Brendan Cully <brendan@kublai.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 21/* general IMAP utility functions */ 22 23#include "config.h" 24 25#include "mutt.h" 26#include "mx.h" /* for MUTT_IMAP */ 27#include "url.h" 28#include "imap_private.h" 29#ifdef USE_HCACHE 30#include "hcache.h" 31#endif 32 33#include <stdlib.h> 34#include <ctype.h> 35 36#include <sys/types.h> 37#include <sys/wait.h> 38#include <signal.h> 39#include <netdb.h> 40#include <netinet/in.h> 41 42#include <errno.h> 43 44/* -- public functions -- */ 45 46/* imap_expand_path: IMAP implementation of mutt_expand_path. Rewrite 47 * an IMAP path in canonical and absolute form. 48 * Inputs: a buffer containing an IMAP path, and the number of bytes in 49 * that buffer. 50 * Outputs: The buffer is rewritten in place with the canonical IMAP path. 51 * Returns 0 on success, or -1 if imap_parse_path chokes or url_ciss_tostring 52 * fails, which it might if there isn't enough room in the buffer. */ 53int imap_expand_path (char* path, size_t len) 54{ 55 IMAP_MBOX mx; 56 IMAP_DATA* idata; 57 ciss_url_t url; 58 char fixedpath[LONG_STRING]; 59 int rc; 60 61 if (imap_parse_path (path, &mx) < 0) 62 return -1; 63 64 idata = imap_conn_find (&mx.account, MUTT_IMAP_CONN_NONEW); 65 mutt_account_tourl (&mx.account, &url); 66 imap_fix_path (idata, mx.mbox, fixedpath, sizeof (fixedpath)); 67 url.path = fixedpath; 68 69 rc = url_ciss_tostring (&url, path, len, U_DECODE_PASSWD); 70 FREE (&mx.mbox); 71 72 return rc; 73} 74 75#ifdef USE_HCACHE 76static int imap_hcache_namer (const char* path, char* dest, size_t dlen) 77{ 78 return snprintf (dest, dlen, "%s.hcache", path); 79} 80 81header_cache_t* imap_hcache_open (IMAP_DATA* idata, const char* path) 82{ 83 IMAP_MBOX mx; 84 ciss_url_t url; 85 char cachepath[LONG_STRING]; 86 char mbox[LONG_STRING]; 87 88 if (path) 89 imap_cachepath (idata, path, mbox, sizeof (mbox)); 90 else 91 { 92 if (!idata->ctx || imap_parse_path (idata->ctx->path, &mx) < 0) 93 return NULL; 94 95 imap_cachepath (idata, mx.mbox, mbox, sizeof (mbox)); 96 FREE (&mx.mbox); 97 } 98 99 mutt_account_tourl (&idata->conn->account, &url); 100 url.path = mbox; 101 url_ciss_tostring (&url, cachepath, sizeof (cachepath), U_PATH); 102 103 return mutt_hcache_open (HeaderCache, cachepath, imap_hcache_namer); 104} 105 106void imap_hcache_close (IMAP_DATA* idata) 107{ 108 if (!idata->hcache) 109 return; 110 111 mutt_hcache_close (idata->hcache); 112 idata->hcache = NULL; 113} 114 115HEADER* imap_hcache_get (IMAP_DATA* idata, unsigned int uid) 116{ 117 char key[16]; 118 unsigned int* uv; 119 HEADER* h = NULL; 120 121 if (!idata->hcache) 122 return NULL; 123 124 sprintf (key, "/%u", uid); 125 uv = (unsigned int*)mutt_hcache_fetch (idata->hcache, key, 126 imap_hcache_keylen); 127 if (uv) 128 { 129 if (*uv == idata->uid_validity) 130 h = mutt_hcache_restore ((unsigned char*)uv, NULL); 131 else 132 dprint (3, (debugfile, "hcache uidvalidity mismatch: %u", *uv)); 133 FREE (&uv); 134 } 135 136 return h; 137} 138 139int imap_hcache_put (IMAP_DATA* idata, HEADER* h) 140{ 141 char key[16]; 142 143 if (!idata->hcache) 144 return -1; 145 146 sprintf (key, "/%u", HEADER_DATA (h)->uid); 147 return mutt_hcache_store (idata->hcache, key, h, idata->uid_validity, 148 imap_hcache_keylen, 0); 149} 150 151int imap_hcache_del (IMAP_DATA* idata, unsigned int uid) 152{ 153 char key[16]; 154 155 if (!idata->hcache) 156 return -1; 157 158 sprintf (key, "/%u", uid); 159 return mutt_hcache_delete (idata->hcache, key, imap_hcache_keylen); 160} 161#endif 162 163/* imap_parse_path: given an IMAP mailbox name, return host, port 164 * and a path IMAP servers will recognize. 165 * mx.mbox is malloc'd, caller must free it */ 166int imap_parse_path (const char* path, IMAP_MBOX* mx) 167{ 168 static unsigned short ImapPort = 0; 169 static unsigned short ImapsPort = 0; 170 struct servent* service; 171 char tmp[128]; 172 ciss_url_t url; 173 char *c; 174 int n; 175 176 if (!ImapPort) 177 { 178 service = getservbyname ("imap", "tcp"); 179 if (service) 180 ImapPort = ntohs (service->s_port); 181 else 182 ImapPort = IMAP_PORT; 183 dprint (3, (debugfile, "Using default IMAP port %d\n", ImapPort)); 184 } 185 if (!ImapsPort) 186 { 187 service = getservbyname ("imaps", "tcp"); 188 if (service) 189 ImapsPort = ntohs (service->s_port); 190 else 191 ImapsPort = IMAP_SSL_PORT; 192 dprint (3, (debugfile, "Using default IMAPS port %d\n", ImapsPort)); 193 } 194 195 /* Defaults */ 196 memset(&mx->account, 0, sizeof(mx->account)); 197 mx->account.port = ImapPort; 198 mx->account.type = MUTT_ACCT_TYPE_IMAP; 199 200 c = safe_strdup (path); 201 url_parse_ciss (&url, c); 202 if (url.scheme == U_IMAP || url.scheme == U_IMAPS) 203 { 204 if (mutt_account_fromurl (&mx->account, &url) < 0 || !*mx->account.host) 205 { 206 FREE (&c); 207 return -1; 208 } 209 210 mx->mbox = safe_strdup (url.path); 211 212 if (url.scheme == U_IMAPS) 213 mx->account.flags |= MUTT_ACCT_SSL; 214 215 FREE (&c); 216 } 217 /* old PINE-compatibility code */ 218 else 219 { 220 FREE (&c); 221 if (sscanf (path, "{%127[^}]}", tmp) != 1) 222 return -1; 223 224 c = strchr (path, '}'); 225 if (!c) 226 return -1; 227 else 228 /* walk past closing '}' */ 229 mx->mbox = safe_strdup (c+1); 230 231 if ((c = strrchr (tmp, '@'))) 232 { 233 *c = '\0'; 234 strfcpy (mx->account.user, tmp, sizeof (mx->account.user)); 235 strfcpy (tmp, c+1, sizeof (tmp)); 236 mx->account.flags |= MUTT_ACCT_USER; 237 } 238 239 if ((n = sscanf (tmp, "%127[^:/]%127s", mx->account.host, tmp)) < 1) 240 { 241 dprint (1, (debugfile, "imap_parse_path: NULL host in %s\n", path)); 242 FREE (&mx->mbox); 243 return -1; 244 } 245 246 if (n > 1) { 247 if (sscanf (tmp, ":%hu%127s", &(mx->account.port), tmp) >= 1) 248 mx->account.flags |= MUTT_ACCT_PORT; 249 if (sscanf (tmp, "/%s", tmp) == 1) 250 { 251 if (!ascii_strncmp (tmp, "ssl", 3)) 252 mx->account.flags |= MUTT_ACCT_SSL; 253 else 254 { 255 dprint (1, (debugfile, "imap_parse_path: Unknown connection type in %s\n", path)); 256 FREE (&mx->mbox); 257 return -1; 258 } 259 } 260 } 261 } 262 263 if ((mx->account.flags & MUTT_ACCT_SSL) && !(mx->account.flags & MUTT_ACCT_PORT)) 264 mx->account.port = ImapsPort; 265 266 return 0; 267} 268 269/* silly helper for mailbox name string comparisons, because of INBOX */ 270int imap_mxcmp (const char* mx1, const char* mx2) 271{ 272 char* b1; 273 char* b2; 274 int rc; 275 276 if (!mx1 || !*mx1) 277 mx1 = "INBOX"; 278 if (!mx2 || !*mx2) 279 mx2 = "INBOX"; 280 if (!ascii_strcasecmp (mx1, "INBOX") && !ascii_strcasecmp (mx2, "INBOX")) 281 return 0; 282 283 b1 = safe_malloc (strlen (mx1) + 1); 284 b2 = safe_malloc (strlen (mx2) + 1); 285 286 imap_fix_path (NULL, mx1, b1, strlen (mx1) + 1); 287 imap_fix_path (NULL, mx2, b2, strlen (mx2) + 1); 288 289 rc = mutt_strcmp (b1, b2); 290 FREE (&b1); 291 FREE (&b2); 292 293 return rc; 294} 295 296/* imap_pretty_mailbox: called by mutt_pretty_mailbox to make IMAP paths 297 * look nice. */ 298void imap_pretty_mailbox (char* path) 299{ 300 IMAP_MBOX home, target; 301 ciss_url_t url; 302 char* delim; 303 int tlen; 304 int hlen = 0; 305 char home_match = 0; 306 307 if (imap_parse_path (path, &target) < 0) 308 return; 309 310 tlen = mutt_strlen (target.mbox); 311 /* check whether we can do '=' substitution */ 312 if (mx_is_imap(Maildir) && !imap_parse_path (Maildir, &home)) 313 { 314 hlen = mutt_strlen (home.mbox); 315 if (tlen && mutt_account_match (&home.account, &target.account) && 316 !mutt_strncmp (home.mbox, target.mbox, hlen)) 317 { 318 if (! hlen) 319 home_match = 1; 320 else if (ImapDelimChars) 321 for (delim = ImapDelimChars; *delim != '\0'; delim++) 322 if (target.mbox[hlen] == *delim) 323 home_match = 1; 324 } 325 FREE (&home.mbox); 326 } 327 328 /* do the '=' substitution */ 329 if (home_match) { 330 *path++ = '='; 331 /* copy remaining path, skipping delimiter */ 332 if (! hlen) 333 hlen = -1; 334 memcpy (path, target.mbox + hlen + 1, tlen - hlen - 1); 335 path[tlen - hlen - 1] = '\0'; 336 } 337 else 338 { 339 mutt_account_tourl (&target.account, &url); 340 url.path = target.mbox; 341 /* FIXME: That hard-coded constant is bogus. But we need the actual 342 * size of the buffer from mutt_pretty_mailbox. And these pretty 343 * operations usually shrink the result. Still... */ 344 url_ciss_tostring (&url, path, 1024, 0); 345 } 346 347 FREE (&target.mbox); 348} 349 350/* -- library functions -- */ 351 352/* imap_continue: display a message and ask the user if she wants to 353 * go on. */ 354int imap_continue (const char* msg, const char* resp) 355{ 356 imap_error (msg, resp); 357 return mutt_yesorno (_("Continue?"), 0); 358} 359 360/* imap_error: show an error and abort */ 361void imap_error (const char *where, const char *msg) 362{ 363 mutt_error ("%s [%s]\n", where, msg); 364 mutt_sleep (2); 365} 366 367/* imap_new_idata: Allocate and initialise a new IMAP_DATA structure. 368 * Returns NULL on failure (no mem) */ 369IMAP_DATA* imap_new_idata (void) 370{ 371 IMAP_DATA* idata = safe_calloc (1, sizeof (IMAP_DATA)); 372 373 if (!idata) 374 return NULL; 375 376 if (!(idata->cmdbuf = mutt_buffer_new ())) 377 FREE (&idata); 378 379 idata->cmdslots = ImapPipelineDepth + 2; 380 if (!(idata->cmds = safe_calloc(idata->cmdslots, sizeof(*idata->cmds)))) 381 { 382 mutt_buffer_free(&idata->cmdbuf); 383 FREE (&idata); 384 } 385 386 return idata; 387} 388 389/* imap_free_idata: Release and clear storage in an IMAP_DATA structure. */ 390void imap_free_idata (IMAP_DATA** idata) 391{ 392 if (!idata) 393 return; 394 395 FREE (&(*idata)->capstr); 396 mutt_free_list (&(*idata)->flags); 397 imap_mboxcache_free (*idata); 398 mutt_buffer_free(&(*idata)->cmdbuf); 399 FREE (&(*idata)->buf); 400 mutt_bcache_close (&(*idata)->bcache); 401 FREE (&(*idata)->cmds); 402 FREE (idata); /* __FREE_CHECKED__ */ 403} 404 405/* 406 * Fix up the imap path. This is necessary because the rest of mutt 407 * assumes a hierarchy delimiter of '/', which is not necessarily true 408 * in IMAP. Additionally, the filesystem converts multiple hierarchy 409 * delimiters into a single one, ie "///" is equal to "/". IMAP servers 410 * are not required to do this. 411 * Moreover, IMAP servers may dislike the path ending with the delimiter. 412 */ 413char *imap_fix_path (IMAP_DATA *idata, const char *mailbox, char *path, 414 size_t plen) 415{ 416 int i = 0; 417 char delim = '\0'; 418 419 if (idata) 420 delim = idata->delim; 421 422 while (mailbox && *mailbox && i < plen - 1) 423 { 424 if ((ImapDelimChars && strchr(ImapDelimChars, *mailbox)) 425 || (delim && *mailbox == delim)) 426 { 427 /* use connection delimiter if known. Otherwise use user delimiter */ 428 if (!idata) 429 delim = *mailbox; 430 431 while (*mailbox 432 && ((ImapDelimChars && strchr(ImapDelimChars, *mailbox)) 433 || (delim && *mailbox == delim))) 434 mailbox++; 435 path[i] = delim; 436 } 437 else 438 { 439 path[i] = *mailbox; 440 mailbox++; 441 } 442 i++; 443 } 444 if (i && path[--i] != delim) 445 i++; 446 path[i] = '\0'; 447 448 return path; 449} 450 451void imap_cachepath(IMAP_DATA* idata, const char* mailbox, char* dest, 452 size_t dlen) 453{ 454 char* s; 455 const char* p = mailbox; 456 457 for (s = dest; p && *p && dlen; dlen--) 458 { 459 if (*p == idata->delim) 460 { 461 *s = '/'; 462 /* simple way to avoid collisions with UIDs */ 463 if (*(p + 1) >= '0' && *(p + 1) <= '9') 464 { 465 if (--dlen) 466 *++s = '_'; 467 } 468 } 469 else 470 *s = *p; 471 p++; 472 s++; 473 } 474 *s = '\0'; 475} 476 477/* imap_get_literal_count: write number of bytes in an IMAP literal into 478 * bytes, return 0 on success, -1 on failure. */ 479int imap_get_literal_count(const char *buf, long *bytes) 480{ 481 char *pc; 482 char *pn; 483 484 if (!buf || !(pc = strchr (buf, '{'))) 485 return -1; 486 487 pc++; 488 pn = pc; 489 while (isdigit ((unsigned char) *pc)) 490 pc++; 491 *pc = 0; 492 *bytes = atoi(pn); 493 494 return 0; 495} 496 497/* imap_get_qualifier: in a tagged response, skip tag and status for 498 * the qualifier message. Used by imap_copy_message for TRYCREATE */ 499char* imap_get_qualifier (char* buf) 500{ 501 char *s = buf; 502 503 /* skip tag */ 504 s = imap_next_word (s); 505 /* skip OK/NO/BAD response */ 506 s = imap_next_word (s); 507 508 return s; 509} 510 511/* imap_next_word: return index into string where next IMAP word begins */ 512char *imap_next_word (char *s) 513{ 514 int quoted = 0; 515 516 while (*s) { 517 if (*s == '\\') { 518 s++; 519 if (*s) 520 s++; 521 continue; 522 } 523 if (*s == '\"') 524 quoted = quoted ? 0 : 1; 525 if (!quoted && ISSPACE (*s)) 526 break; 527 s++; 528 } 529 530 SKIPWS (s); 531 return s; 532} 533 534/* imap_parse_date: date is of the form: DD-MMM-YYYY HH:MM:SS +ZZzz */ 535time_t imap_parse_date (char *s) 536{ 537 struct tm t; 538 time_t tz; 539 540 t.tm_mday = (s[0] == ' '? s[1] - '0' : (s[0] - '0') * 10 + (s[1] - '0')); 541 s += 2; 542 if (*s != '-') 543 return 0; 544 s++; 545 t.tm_mon = mutt_check_month (s); 546 s += 3; 547 if (*s != '-') 548 return 0; 549 s++; 550 t.tm_year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0') - 1900; 551 s += 4; 552 if (*s != ' ') 553 return 0; 554 s++; 555 556 /* time */ 557 t.tm_hour = (s[0] - '0') * 10 + (s[1] - '0'); 558 s += 2; 559 if (*s != ':') 560 return 0; 561 s++; 562 t.tm_min = (s[0] - '0') * 10 + (s[1] - '0'); 563 s += 2; 564 if (*s != ':') 565 return 0; 566 s++; 567 t.tm_sec = (s[0] - '0') * 10 + (s[1] - '0'); 568 s += 2; 569 if (*s != ' ') 570 return 0; 571 s++; 572 573 /* timezone */ 574 tz = ((s[1] - '0') * 10 + (s[2] - '0')) * 3600 + 575 ((s[3] - '0') * 10 + (s[4] - '0')) * 60; 576 if (s[0] == '+') 577 tz = -tz; 578 579 return (mutt_mktime (&t, 0) + tz); 580} 581 582/* format date in IMAP style: DD-MMM-YYYY HH:MM:SS +ZZzz. 583 * Caller should provide a buffer of IMAP_DATELEN bytes */ 584void imap_make_date (char *buf, time_t timestamp) 585{ 586 struct tm* tm = localtime (&timestamp); 587 time_t tz = mutt_local_tz (timestamp); 588 589 tz /= 60; 590 591 snprintf (buf, IMAP_DATELEN, "%02d-%s-%d %02d:%02d:%02d %+03d%02d", 592 tm->tm_mday, Months[tm->tm_mon], tm->tm_year + 1900, 593 tm->tm_hour, tm->tm_min, tm->tm_sec, 594 (int) tz / 60, (int) abs ((int) tz) % 60); 595} 596 597/* imap_qualify_path: make an absolute IMAP folder target, given IMAP_MBOX 598 * and relative path. */ 599void imap_qualify_path (char *dest, size_t len, IMAP_MBOX *mx, char* path) 600{ 601 ciss_url_t url; 602 603 mutt_account_tourl (&mx->account, &url); 604 url.path = path; 605 606 url_ciss_tostring (&url, dest, len, 0); 607} 608 609 610/* imap_quote_string: quote string according to IMAP rules: 611 * surround string with quotes, escape " and \ with \ */ 612void imap_quote_string (char *dest, size_t dlen, const char *src) 613{ 614 static const char quote[] = "\"\\"; 615 char *pt; 616 const char *s; 617 618 pt = dest; 619 s = src; 620 621 *pt++ = '"'; 622 /* save room for trailing quote-char */ 623 dlen -= 2; 624 625 for (; *s && dlen; s++) 626 { 627 if (strchr (quote, *s)) 628 { 629 dlen -= 2; 630 if (!dlen) 631 break; 632 *pt++ = '\\'; 633 *pt++ = *s; 634 } 635 else 636 { 637 *pt++ = *s; 638 dlen--; 639 } 640 } 641 *pt++ = '"'; 642 *pt = 0; 643} 644 645/* imap_unquote_string: equally stupid unquoting routine */ 646void imap_unquote_string (char *s) 647{ 648 char *d = s; 649 650 if (*s == '\"') 651 s++; 652 else 653 return; 654 655 while (*s) 656 { 657 if (*s == '\"') 658 { 659 *d = '\0'; 660 return; 661 } 662 if (*s == '\\') 663 { 664 s++; 665 } 666 if (*s) 667 { 668 *d = *s; 669 d++; 670 s++; 671 } 672 } 673 *d = '\0'; 674} 675 676 677/* 678 * Quoting and UTF-7 conversion 679 */ 680 681void imap_munge_mbox_name (IMAP_DATA *idata, char *dest, size_t dlen, const char *src) 682{ 683 char *buf; 684 685 buf = safe_strdup (src); 686 imap_utf_encode (idata, &buf); 687 688 imap_quote_string (dest, dlen, buf); 689 690 FREE (&buf); 691} 692 693void imap_unmunge_mbox_name (IMAP_DATA *idata, char *s) 694{ 695 char *buf; 696 697 imap_unquote_string(s); 698 699 buf = safe_strdup (s); 700 if (buf) 701 { 702 imap_utf_decode (idata, &buf); 703 strncpy (s, buf, strlen (s)); 704 } 705 706 FREE (&buf); 707} 708 709/* imap_wordcasecmp: find word a in word list b */ 710int imap_wordcasecmp(const char *a, const char *b) 711{ 712 char tmp[SHORT_STRING]; 713 char *s = (char *)b; 714 int i; 715 716 tmp[SHORT_STRING-1] = 0; 717 for(i=0;i < SHORT_STRING-2;i++,s++) 718 { 719 if (!*s || ISSPACE(*s)) 720 { 721 tmp[i] = 0; 722 break; 723 } 724 tmp[i] = *s; 725 } 726 tmp[i+1] = 0; 727 728 return ascii_strcasecmp(a, tmp); 729} 730 731/* 732 * Imap keepalive: poll the current folder to keep the 733 * connection alive. 734 * 735 */ 736 737static void alrm_handler (int sig) 738{ 739 /* empty */ 740} 741 742void imap_keepalive (void) 743{ 744 CONNECTION *conn; 745 CONTEXT *ctx = NULL; 746 IMAP_DATA *idata; 747 748 conn = mutt_socket_head (); 749 while (conn) 750 { 751 if (conn->account.type == MUTT_ACCT_TYPE_IMAP) 752 { 753 int need_free = 0; 754 755 idata = (IMAP_DATA*) conn->data; 756 757 if (idata->state >= IMAP_AUTHENTICATED 758 && time(NULL) >= idata->lastread + ImapKeepalive) 759 { 760 if (idata->ctx) 761 ctx = idata->ctx; 762 else 763 { 764 ctx = safe_calloc (1, sizeof (CONTEXT)); 765 ctx->data = idata; 766 /* imap_close_mailbox will set ctx->iadata->ctx to NULL, so we can't 767 * rely on the value of iadata->ctx to determine if this placeholder 768 * context needs to be freed. 769 */ 770 need_free = 1; 771 } 772 /* if the imap connection closes during this call, ctx may be invalid 773 * after this point, and thus should not be read. 774 */ 775 imap_check_mailbox (ctx, NULL, 1); 776 if (need_free) 777 FREE (&ctx); 778 } 779 } 780 781 conn = conn->next; 782 } 783} 784 785int imap_wait_keepalive (pid_t pid) 786{ 787 struct sigaction oldalrm; 788 struct sigaction act; 789 sigset_t oldmask; 790 int rc; 791 792 short imap_passive = option (OPTIMAPPASSIVE); 793 794 set_option (OPTIMAPPASSIVE); 795 set_option (OPTKEEPQUIET); 796 797 sigprocmask (SIG_SETMASK, NULL, &oldmask); 798 799 sigemptyset (&act.sa_mask); 800 act.sa_handler = alrm_handler; 801#ifdef SA_INTERRUPT 802 act.sa_flags = SA_INTERRUPT; 803#else 804 act.sa_flags = 0; 805#endif 806 807 sigaction (SIGALRM, &act, &oldalrm); 808 809 alarm (ImapKeepalive); 810 while (waitpid (pid, &rc, 0) < 0 && errno == EINTR) 811 { 812 alarm (0); /* cancel a possibly pending alarm */ 813 imap_keepalive (); 814 alarm (ImapKeepalive); 815 } 816 817 alarm (0); /* cancel a possibly pending alarm */ 818 819 sigaction (SIGALRM, &oldalrm, NULL); 820 sigprocmask (SIG_SETMASK, &oldmask, NULL); 821 822 unset_option (OPTKEEPQUIET); 823 if (!imap_passive) 824 unset_option (OPTIMAPPASSIVE); 825 826 return rc; 827} 828 829/* Allow/disallow re-opening a folder upon expunge. */ 830 831void imap_allow_reopen (CONTEXT *ctx) 832{ 833 if (ctx && ctx->magic == MUTT_IMAP && CTX_DATA->ctx == ctx) 834 CTX_DATA->reopen |= IMAP_REOPEN_ALLOW; 835} 836 837void imap_disallow_reopen (CONTEXT *ctx) 838{ 839 if (ctx && ctx->magic == MUTT_IMAP && CTX_DATA->ctx == ctx) 840 CTX_DATA->reopen &= ~IMAP_REOPEN_ALLOW; 841} 842 843int imap_account_match (const ACCOUNT* a1, const ACCOUNT* a2) 844{ 845 IMAP_DATA* a1_idata = imap_conn_find (a1, MUTT_IMAP_CONN_NONEW); 846 IMAP_DATA* a2_idata = imap_conn_find (a2, MUTT_IMAP_CONN_NONEW); 847 const ACCOUNT* a1_canon = a1_idata == NULL ? a1 : &a1_idata->conn->account; 848 const ACCOUNT* a2_canon = a2_idata == NULL ? a2 : &a2_idata->conn->account; 849 850 return mutt_account_match (a1_canon, a2_canon); 851}