mutt stable branch with some hacks
at jcs 822 lines 20 kB view raw
1/* 2 * Copyright (C) 1996-2000,2010,2013 Michael R. Elkins <me@mutt.org> 3 * Copyright (C) 2016-2017 Kevin J. McCarthy <kevin@8t8.us> 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 "buffy.h" 26#include "mailbox.h" 27#include "mx.h" 28 29#include "mutt_curses.h" 30#include "mutt_menu.h" 31 32#ifdef USE_SIDEBAR 33#include "sidebar.h" 34#endif 35 36#ifdef USE_IMAP 37#include "imap.h" 38#endif 39 40#ifdef USE_INOTIFY 41#include "monitor.h" 42#endif 43 44#include <string.h> 45#include <sys/stat.h> 46#include <dirent.h> 47#include <utime.h> 48#include <ctype.h> 49#include <unistd.h> 50 51#include <stdio.h> 52 53static time_t BuffyTime = 0; /* last time we started checking for mail */ 54static time_t BuffyStatsTime = 0; /* last time we check performed mail_check_stats */ 55time_t BuffyDoneTime = 0; /* last time we knew for sure how much mail there was. */ 56static short BuffyCount = 0; /* how many boxes with new mail */ 57static short BuffyNotify = 0; /* # of unnotified new boxes */ 58 59static BUFFY* buffy_get (const char *path); 60 61/* Find the last message in the file. 62 * upon success return 0. If no message found - return -1 */ 63 64static int fseek_last_message (FILE * f) 65{ 66 LOFF_T pos; 67 char buffer[BUFSIZ + 9]; /* 7 for "\n\nFrom " */ 68 int bytes_read; 69 int i; /* Index into `buffer' for scanning. */ 70 71 memset (buffer, 0, sizeof(buffer)); 72 fseek (f, 0, SEEK_END); 73 pos = ftello (f); 74 75 /* Set `bytes_read' to the size of the last, probably partial, buffer; 0 < 76 * `bytes_read' <= `BUFSIZ'. */ 77 bytes_read = pos % BUFSIZ; 78 if (bytes_read == 0) 79 bytes_read = BUFSIZ; 80 /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all 81 * reads will be on block boundaries, which might increase efficiency. */ 82 while ((pos -= bytes_read) >= 0) 83 { 84 /* we save in the buffer at the end the first 7 chars from the last read */ 85 strncpy (buffer + BUFSIZ, buffer, 5+2); /* 2 == 2 * mutt_strlen(CRLF) */ 86 fseeko (f, pos, SEEK_SET); 87 bytes_read = fread (buffer, sizeof (char), bytes_read, f); 88 if (bytes_read == -1) 89 return -1; 90 for (i = bytes_read; --i >= 0;) 91 if (!mutt_strncmp (buffer + i, "\n\nFrom ", mutt_strlen ("\n\nFrom "))) 92 { /* found it - go to the beginning of the From */ 93 fseeko (f, pos + i + 2, SEEK_SET); 94 return 0; 95 } 96 bytes_read = BUFSIZ; 97 } 98 99 /* here we are at the beginning of the file */ 100 if (!mutt_strncmp ("From ", buffer, 5)) 101 { 102 fseek (f, 0, 0); 103 return (0); 104 } 105 106 return (-1); 107} 108 109/* Return 1 if the last message is new */ 110static int test_last_status_new (FILE * f) 111{ 112 HEADER *hdr; 113 ENVELOPE* tmp_envelope; 114 int result = 0; 115 116 if (fseek_last_message (f) == -1) 117 return (0); 118 119 hdr = mutt_new_header (); 120 tmp_envelope = mutt_read_rfc822_header (f, hdr, 0, 0); 121 if (!(hdr->read || hdr->old)) 122 result = 1; 123 124 mutt_free_envelope(&tmp_envelope); 125 mutt_free_header (&hdr); 126 127 return result; 128} 129 130static int test_new_folder (const char *path) 131{ 132 FILE *f; 133 int rc = 0; 134 int typ; 135 136 typ = mx_get_magic (path); 137 138 if (typ != MUTT_MBOX && typ != MUTT_MMDF) 139 return 0; 140 141 if ((f = fopen (path, "rb"))) 142 { 143 rc = test_last_status_new (f); 144 safe_fclose (&f); 145 } 146 147 return rc; 148} 149 150void mutt_buffy_cleanup (const char *buf, struct stat *st) 151{ 152#ifdef HAVE_UTIMENSAT 153 struct timespec ts[2]; 154#else 155 struct utimbuf ut; 156#endif 157 BUFFY *tmp; 158 159 if (option(OPTCHECKMBOXSIZE)) 160 { 161 tmp = mutt_find_mailbox (buf); 162 if (tmp && !tmp->new) 163 mutt_update_mailbox (tmp); 164 } 165 else 166 { 167 /* fix up the times so buffy won't get confused */ 168 if (st->st_mtime > st->st_atime) 169 { 170#ifdef HAVE_UTIMENSAT 171 ts[0].tv_sec = 0; 172 ts[0].tv_nsec = UTIME_OMIT; 173 ts[1].tv_sec = 0; 174 ts[1].tv_nsec = UTIME_NOW; 175 utimensat (0, buf, ts, 0); 176#else 177 ut.actime = st->st_atime; 178 ut.modtime = time (NULL); 179 utime (buf, &ut); 180#endif 181 } 182 else 183 { 184#ifdef HAVE_UTIMENSAT 185 ts[0].tv_sec = 0; 186 ts[0].tv_nsec = UTIME_NOW; 187 ts[1].tv_sec = 0; 188 ts[1].tv_nsec = UTIME_NOW; 189 utimensat (0, buf, ts, 0); 190#else 191 utime (buf, NULL); 192#endif 193 } 194 } 195} 196 197BUFFY *mutt_find_mailbox (const char *path) 198{ 199 BUFFY *tmp = NULL; 200 struct stat sb; 201 struct stat tmp_sb; 202 203 if (stat (path,&sb) != 0) 204 return NULL; 205 206 for (tmp = Incoming; tmp; tmp = tmp->next) 207 { 208 if (stat (mutt_b2s (tmp->pathbuf), &tmp_sb) ==0 && 209 sb.st_dev == tmp_sb.st_dev && sb.st_ino == tmp_sb.st_ino) 210 break; 211 } 212 return tmp; 213} 214 215void mutt_update_mailbox (BUFFY * b) 216{ 217 struct stat sb; 218 219 if (!b) 220 return; 221 222 if (stat (mutt_b2s (b->pathbuf), &sb) == 0) 223 b->size = (off_t) sb.st_size; 224 else 225 b->size = 0; 226 return; 227} 228 229static BUFFY *buffy_new (const char *path) 230{ 231 BUFFY* buffy; 232 char rp[PATH_MAX] = ""; 233 char *r = NULL; 234 235 buffy = (BUFFY *) safe_calloc (1, sizeof (BUFFY)); 236 buffy->pathbuf = mutt_buffer_new (); 237 mutt_buffer_strcpy (buffy->pathbuf, path); 238 r = realpath (path, rp); 239 buffy->realpath = safe_strdup (r ? rp : path); 240 buffy->next = NULL; 241 buffy->magic = 0; 242 243 return buffy; 244} 245 246static void buffy_free (BUFFY **mailbox) 247{ 248 if (!(mailbox && *mailbox)) 249 return; 250 251 mutt_buffer_free (&((*mailbox)->pathbuf)); 252 FREE (&((*mailbox)->realpath)); 253 FREE (mailbox); /* __FREE_CHECKED__ */ 254} 255 256int mutt_parse_mailboxes (BUFFER *path, BUFFER *s, union pointer_long_t udata, BUFFER *err) 257{ 258 BUFFY **tmp,*tmp1; 259 struct stat sb; 260 char f1[PATH_MAX]; 261 char *p; 262 long data = udata.l; 263 264 while (MoreArgs (s)) 265 { 266 mutt_extract_token (path, s, 0); 267 268 if (data == MUTT_UNMAILBOXES && mutt_strcmp(mutt_b2s (path),"*") == 0) 269 { 270 for (tmp = &Incoming; *tmp;) 271 { 272 tmp1=(*tmp)->next; 273#ifdef USE_SIDEBAR 274 mutt_sb_notify_mailbox (*tmp, 0); 275#endif 276#ifdef USE_INOTIFY 277 mutt_monitor_remove (*tmp); 278#endif 279 buffy_free (tmp); 280 *tmp=tmp1; 281 } 282 return 0; 283 } 284 285 mutt_buffer_expand_path (path); 286 287 /* Skip empty tokens. */ 288 if (!mutt_buffer_len (path)) continue; 289 290 /* avoid duplicates */ 291 p = realpath (mutt_b2s (path), f1); 292 for (tmp = &Incoming; *tmp; tmp = &((*tmp)->next)) 293 { 294 if (mutt_strcmp (p ? p : mutt_b2s (path), (*tmp)->realpath) == 0) 295 { 296 dprint(3,(debugfile,"mailbox '%s' already registered as '%s'\n", mutt_b2s (path), 297 mutt_b2s ((*tmp)->pathbuf))); 298 break; 299 } 300 } 301 302 if (data == MUTT_UNMAILBOXES) 303 { 304 if (*tmp) 305 { 306 tmp1=(*tmp)->next; 307#ifdef USE_SIDEBAR 308 mutt_sb_notify_mailbox (*tmp, 0); 309#endif 310#ifdef USE_INOTIFY 311 mutt_monitor_remove (*tmp); 312#endif 313 buffy_free (tmp); 314 *tmp=tmp1; 315 } 316 continue; 317 } 318 319 if (!*tmp) 320 { 321 *tmp = buffy_new (mutt_b2s (path)); 322#ifdef USE_SIDEBAR 323 mutt_sb_notify_mailbox (*tmp, 1); 324#endif 325#ifdef USE_INOTIFY 326 (*tmp)->magic = mx_get_magic (mutt_b2s ((*tmp)->pathbuf)); 327 mutt_monitor_add (*tmp); 328#endif 329 } 330 331 (*tmp)->new = 0; 332 (*tmp)->notified = 1; 333 (*tmp)->newly_created = 0; 334 335 /* for check_mbox_size, it is important that if the folder is new (tested by 336 * reading it), the size is set to 0 so that later when we check we see 337 * that it increased . without check_mbox_size we probably don't care. 338 */ 339 if (option(OPTCHECKMBOXSIZE) && 340 stat (mutt_b2s ((*tmp)->pathbuf), &sb) == 0 && 341 !test_new_folder (mutt_b2s ((*tmp)->pathbuf))) 342 { 343 /* some systems out there don't have an off_t type */ 344 (*tmp)->size = (off_t) sb.st_size; 345 } 346 else 347 (*tmp)->size = 0; 348 } 349 return 0; 350} 351 352/* Checks the specified maildir subdir (cur or new) for new mail or mail counts. 353 * check_new: if true, check for new mail. 354 * check_stats: if true, count total, new, and flagged messages. 355 * Returns 1 if the dir has new mail. 356 */ 357static int buffy_maildir_check_dir (BUFFY* mailbox, const char *dir_name, int check_new, 358 int check_stats) 359{ 360 BUFFER *path = NULL; 361 BUFFER *msgpath = NULL; 362 DIR *dirp; 363 struct dirent *de; 364 char *p; 365 int rc = 0; 366 struct stat sb; 367 368 path = mutt_buffer_pool_get (); 369 msgpath = mutt_buffer_pool_get (); 370 mutt_buffer_printf (path, "%s/%s", mutt_b2s (mailbox->pathbuf), dir_name); 371 372 /* when $mail_check_recent is set, if the new/ directory hasn't been modified since 373 * the user last exited the mailbox, then we know there is no recent mail. 374 */ 375 if (check_new && option(OPTMAILCHECKRECENT)) 376 { 377 if (stat(mutt_b2s (path), &sb) == 0 && 378 mutt_stat_timespec_compare (&sb, MUTT_STAT_MTIME, &mailbox->last_visited) < 0) 379 { 380 rc = 0; 381 check_new = 0; 382 } 383 } 384 385 if (! (check_new || check_stats)) 386 goto cleanup; 387 388 if ((dirp = opendir (mutt_b2s (path))) == NULL) 389 { 390 mailbox->magic = 0; 391 rc = 0; 392 goto cleanup; 393 } 394 395 while ((de = readdir (dirp)) != NULL) 396 { 397 if (*de->d_name == '.') 398 continue; 399 400 p = strstr (de->d_name, ":2,"); 401 if (p && strchr (p + 3, 'T')) 402 continue; 403 404 if (check_stats) 405 { 406 mailbox->msg_count++; 407 if (p && strchr (p + 3, 'F')) 408 mailbox->msg_flagged++; 409 } 410 if (!p || !strchr (p + 3, 'S')) 411 { 412 if (check_stats) 413 mailbox->msg_unread++; 414 if (check_new) 415 { 416 if (option(OPTMAILCHECKRECENT)) 417 { 418 mutt_buffer_printf (msgpath, "%s/%s", mutt_b2s (path), de->d_name); 419 /* ensure this message was received since leaving this mailbox */ 420 if (stat(mutt_b2s (msgpath), &sb) == 0 && 421 (mutt_stat_timespec_compare (&sb, MUTT_STAT_CTIME, &mailbox->last_visited) <= 0)) 422 continue; 423 } 424 mailbox->new = 1; 425 rc = 1; 426 check_new = 0; 427 if (!check_stats) 428 break; 429 } 430 } 431 } 432 433 closedir (dirp); 434 435cleanup: 436 mutt_buffer_pool_release (&path); 437 mutt_buffer_pool_release (&msgpath); 438 439 return rc; 440} 441 442/* Checks new mail for a maildir mailbox. 443 * check_stats: if true, also count total, new, and flagged messages. 444 * Returns 1 if the mailbox has new mail. 445 */ 446static int buffy_maildir_check (BUFFY* mailbox, int check_stats) 447{ 448 int rc, check_new = 1; 449 450 if (check_stats) 451 { 452 mailbox->msg_count = 0; 453 mailbox->msg_unread = 0; 454 mailbox->msg_flagged = 0; 455 } 456 457 rc = buffy_maildir_check_dir (mailbox, "new", check_new, check_stats); 458 459 check_new = !rc && option (OPTMAILDIRCHECKCUR); 460 if (check_new || check_stats) 461 if (buffy_maildir_check_dir (mailbox, "cur", check_new, check_stats)) 462 rc = 1; 463 464 return rc; 465} 466 467/* Checks new mail for an mbox mailbox 468 * check_stats: if true, also count total, new, and flagged messages. 469 * Returns 1 if the mailbox has new mail. 470 */ 471static int buffy_mbox_check (BUFFY* mailbox, struct stat *sb, int check_stats) 472{ 473 int rc = 0; 474 int new_or_changed; 475 CONTEXT ctx; 476 477 if (option (OPTCHECKMBOXSIZE)) 478 new_or_changed = sb->st_size > mailbox->size; 479 else 480 new_or_changed = (mutt_stat_compare (sb, MUTT_STAT_MTIME, sb, MUTT_STAT_ATIME) > 0) 481 || (mailbox->newly_created && 482 (mutt_stat_compare (sb, MUTT_STAT_CTIME, sb, MUTT_STAT_MTIME) == 0) && 483 (mutt_stat_compare (sb, MUTT_STAT_CTIME, sb, MUTT_STAT_ATIME) == 0)); 484 485 if (new_or_changed) 486 { 487 if (!option(OPTMAILCHECKRECENT) || 488 (mutt_stat_timespec_compare (sb, MUTT_STAT_MTIME, &mailbox->last_visited) > 0)) 489 { 490 rc = 1; 491 mailbox->new = 1; 492 } 493 } 494 else if (option(OPTCHECKMBOXSIZE)) 495 { 496 /* some other program has deleted mail from the folder */ 497 mailbox->size = (off_t) sb->st_size; 498 } 499 500 if (mailbox->newly_created && 501 (sb->st_ctime != sb->st_mtime || sb->st_ctime != sb->st_atime)) 502 mailbox->newly_created = 0; 503 504 if (check_stats && 505 (mutt_stat_timespec_compare (sb, MUTT_STAT_MTIME, &mailbox->stats_last_checked) > 0)) 506 { 507 if (mx_open_mailbox (mutt_b2s (mailbox->pathbuf), 508 MUTT_READONLY | MUTT_QUIET | MUTT_NOSORT | MUTT_PEEK, 509 &ctx) != NULL) 510 { 511 mailbox->msg_count = ctx.msgcount; 512 mailbox->msg_unread = ctx.unread; 513 mailbox->msg_flagged = ctx.flagged; 514 mailbox->stats_last_checked = ctx.mtime; 515 mx_close_mailbox (&ctx, 0); 516 } 517 } 518 519 return rc; 520} 521 522/* Check all Incoming for new mail and total/new/flagged messages 523 * The force argument may be any combination of the following values: 524 * MUTT_BUFFY_CHECK_FORCE ignore BuffyTimeout and check for new mail 525 * MUTT_BUFFY_CHECK_FORCE_STATS ignore BuffyTimeout and calculate statistics 526 */ 527int mutt_buffy_check (int force) 528{ 529 BUFFY *tmp; 530 struct stat sb; 531 struct stat contex_sb; 532 time_t t; 533 int check_stats = 0; 534#ifdef USE_SIDEBAR 535 short orig_new; 536 int orig_count, orig_unread, orig_flagged; 537#endif 538 539 sb.st_size=0; 540 contex_sb.st_dev=0; 541 contex_sb.st_ino=0; 542 543#ifdef USE_IMAP 544 /* update postponed count as well, on force */ 545 if (force & MUTT_BUFFY_CHECK_FORCE) 546 mutt_update_num_postponed (); 547#endif 548 549 /* fastest return if there are no mailboxes */ 550 if (!Incoming) 551 return 0; 552 t = time (NULL); 553 if (!force && (t - BuffyTime < BuffyTimeout)) 554 return BuffyCount; 555 556 if ((force & MUTT_BUFFY_CHECK_FORCE_STATS) || 557 (option (OPTMAILCHECKSTATS) && 558 (t - BuffyStatsTime >= BuffyCheckStatsInterval))) 559 { 560 check_stats = 1; 561 BuffyStatsTime = t; 562 } 563 564 BuffyTime = t; 565 BuffyCount = 0; 566 BuffyNotify = 0; 567 568#ifdef USE_IMAP 569 BuffyCount += imap_buffy_check (force, check_stats); 570#endif 571 572 /* check device ID and serial number instead of comparing paths */ 573 if (!Context || Context->magic == MUTT_IMAP || Context->magic == MUTT_POP 574 || stat (Context->path, &contex_sb) != 0) 575 { 576 contex_sb.st_dev=0; 577 contex_sb.st_ino=0; 578 } 579 580 for (tmp = Incoming; tmp; tmp = tmp->next) 581 { 582#ifdef USE_SIDEBAR 583 orig_new = tmp->new; 584 orig_count = tmp->msg_count; 585 orig_unread = tmp->msg_unread; 586 orig_flagged = tmp->msg_flagged; 587#endif 588 589 if (tmp->magic != MUTT_IMAP) 590 { 591 tmp->new = 0; 592#ifdef USE_POP 593 if (mx_is_pop (mutt_b2s (tmp->pathbuf))) 594 tmp->magic = MUTT_POP; 595 else 596#endif 597 if (stat (mutt_b2s (tmp->pathbuf), &sb) != 0 || 598 (S_ISREG(sb.st_mode) && sb.st_size == 0) || 599 (!tmp->magic && 600 (tmp->magic = mx_get_magic (mutt_b2s (tmp->pathbuf))) <= 0)) 601 { 602 /* if the mailbox still doesn't exist, set the newly created flag to 603 * be ready for when it does. */ 604 tmp->newly_created = 1; 605 tmp->magic = 0; 606 tmp->size = 0; 607 continue; 608 } 609 } 610 611 /* check to see if the folder is the currently selected folder 612 * before polling */ 613 if (!Context || !Context->path || 614 (( tmp->magic == MUTT_IMAP || tmp->magic == MUTT_POP ) 615 ? mutt_strcmp (mutt_b2s (tmp->pathbuf), Context->path) : 616 (sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino))) 617 { 618 switch (tmp->magic) 619 { 620 case MUTT_MBOX: 621 case MUTT_MMDF: 622 if (buffy_mbox_check (tmp, &sb, check_stats) > 0) 623 BuffyCount++; 624 break; 625 626 case MUTT_MAILDIR: 627 if (buffy_maildir_check (tmp, check_stats) > 0) 628 BuffyCount++; 629 break; 630 631 case MUTT_MH: 632 if (mh_buffy (tmp, check_stats) > 0) 633 BuffyCount++; 634 break; 635 } 636 } 637 else if (option(OPTCHECKMBOXSIZE) && Context && Context->path) 638 tmp->size = (off_t) sb.st_size; /* update the size of current folder */ 639 640#ifdef USE_SIDEBAR 641 if ((orig_new != tmp->new) || 642 (orig_count != tmp->msg_count) || 643 (orig_unread != tmp->msg_unread) || 644 (orig_flagged != tmp->msg_flagged)) 645 mutt_set_current_menu_redraw (REDRAW_SIDEBAR); 646#endif 647 648 if (!tmp->new) 649 tmp->notified = 0; 650 else if (!tmp->notified) 651 BuffyNotify++; 652 } 653 654 BuffyDoneTime = BuffyTime; 655 return (BuffyCount); 656} 657 658int mutt_buffy_list (void) 659{ 660 BUFFY *tmp; 661 BUFFER *path = NULL; 662 char buffylist[2*STRING]; 663 size_t pos = 0; 664 int first = 1; 665 666 int have_unnotified = BuffyNotify; 667 668 path = mutt_buffer_pool_get (); 669 670 buffylist[0] = 0; 671 pos += strlen (strncat (buffylist, _("New mail in "), sizeof (buffylist) - 1 - pos)); /* __STRNCAT_CHECKED__ */ 672 for (tmp = Incoming; tmp; tmp = tmp->next) 673 { 674 /* Is there new mail in this mailbox? */ 675 if (!tmp->new || (have_unnotified && tmp->notified)) 676 continue; 677 678 mutt_buffer_strcpy (path, mutt_b2s (tmp->pathbuf)); 679 mutt_buffer_pretty_mailbox (path); 680 681 if (!first && (MuttMessageWindow->cols >= 7) && 682 (pos + mutt_buffer_len (path) >= (size_t)MuttMessageWindow->cols - 7)) 683 break; 684 685 if (!first) 686 pos += strlen (strncat(buffylist + pos, ", ", sizeof(buffylist)-1-pos)); /* __STRNCAT_CHECKED__ */ 687 688 /* Prepend an asterisk to mailboxes not already notified */ 689 if (!tmp->notified) 690 { 691 /* pos += strlen (strncat(buffylist + pos, "*", sizeof(buffylist)-1-pos)); __STRNCAT_CHECKED__ */ 692 tmp->notified = 1; 693 BuffyNotify--; 694 } 695 pos += strlen (strncat(buffylist + pos, mutt_b2s (path), sizeof(buffylist)-1-pos)); /* __STRNCAT_CHECKED__ */ 696 first = 0; 697 } 698 if (!first && tmp) 699 { 700 strncat (buffylist + pos, ", ...", sizeof (buffylist) - 1 - pos); /* __STRNCAT_CHECKED__ */ 701 } 702 703 mutt_buffer_pool_release (&path); 704 705 if (!first) 706 { 707 mutt_message ("%s", buffylist); 708 return (1); 709 } 710 else 711 { 712 /* there were no mailboxes needing to be notified, so clean up since 713 * BuffyNotify has somehow gotten out of sync 714 */ 715 BuffyNotify = 0; 716 return (0); 717 } 718} 719 720void mutt_buffy_setnotified (const char *path) 721{ 722 BUFFY *buffy; 723 724 buffy = buffy_get(path); 725 if (!buffy) 726 return; 727 728 buffy->notified = 1; 729#if HAVE_CLOCK_GETTIME 730 clock_gettime (CLOCK_REALTIME, &buffy->last_visited); 731#else 732 buffy->last_visited.tv_nsec = 0; 733 time(&buffy->last_visited.tv_sec); 734#endif 735} 736 737int mutt_buffy_notify (void) 738{ 739 if (mutt_buffy_check (0) && BuffyNotify) 740 { 741 return (mutt_buffy_list ()); 742 } 743 return (0); 744} 745 746void mutt_buffy (char *s, size_t slen) 747{ 748 BUFFER *s_buf; 749 750 s_buf = mutt_buffer_pool_get (); 751 752 mutt_buffer_addstr (s_buf, NONULL (s)); 753 mutt_buffer_buffy (s_buf); 754 strfcpy (s, mutt_b2s (s_buf), slen); 755 756 mutt_buffer_pool_release (&s_buf); 757} 758 759/* 760 * mutt_buffy() -- incoming folders completion routine 761 * 762 * given a folder name, this routine gives the next incoming folder with new 763 * mail. 764 */ 765void mutt_buffer_buffy (BUFFER *s) 766{ 767 BUFFY *tmp = Incoming; 768 int pass, found = 0; 769 770 mutt_buffer_expand_path (s); 771 772 if (mutt_buffy_check (0)) 773 { 774 for (pass = 0; pass < 2; pass++) 775 for (tmp = Incoming; tmp; tmp = tmp->next) 776 { 777 mutt_buffer_expand_path (tmp->pathbuf); 778 if ((found || pass) && tmp->new) 779 { 780 mutt_buffer_strcpy (s, mutt_b2s (tmp->pathbuf)); 781 mutt_buffer_pretty_mailbox (s); 782 return; 783 } 784 if (mutt_strcmp (mutt_b2s (s), mutt_b2s (tmp->pathbuf)) == 0) 785 found = 1; 786 } 787 788 mutt_buffy_check (MUTT_BUFFY_CHECK_FORCE); /* buffy was wrong - resync 789 things */ 790 } 791 792 /* no folders with new mail */ 793 mutt_buffer_clear (s); 794} 795 796/* fetch buffy object for given path, if present */ 797static BUFFY* buffy_get (const char *path) 798{ 799 BUFFY *cur; 800 BUFFER *epath; 801 802 if (!path) 803 return NULL; 804 805 epath = mutt_buffer_pool_get (); 806 mutt_buffer_strcpy (epath, NONULL (path)); 807 mutt_buffer_expand_path (epath); 808 809 for (cur = Incoming; cur; cur = cur->next) 810 { 811 /* must be done late because e.g. IMAP delimiter may change */ 812 mutt_buffer_expand_path (cur->pathbuf); 813 if (!mutt_strcmp (mutt_b2s (cur->pathbuf), mutt_b2s (epath))) 814 { 815 mutt_buffer_pool_release (&epath); 816 return cur; 817 } 818 } 819 820 mutt_buffer_pool_release (&epath); 821 return NULL; 822}