9 #include "mutt_mailbox.h"
11 #include "mutt_menu.h"
12 #include "mutt_window.h"
17 static time_t MailboxTime = 0; /**< last time we started checking for mail */
18 static time_t MailboxStatsTime = 0; /**< last time we check performed mail_check_stats */
19 static short MailboxCount = 0; /**< how many boxes with new mail */
20 static short MailboxNotify = 0; /**< # of unnotified new boxes */
22 /* These Config Variables are only used in mutt_mailbox.c */
23 short C_MailCheck; ///< Config: Number of seconds before NeoMutt checks for new mail
24 bool C_MailCheckStats; ///< Config: Periodically check for new mail
25 short C_MailCheckStatsInterval; ///< Config: How often to check for new mail
28 * mailbox_check - Check a mailbox for new mail
29 * @param m_cur Current Mailbox
30 * @param m_check Mailbox to check
31 * @param ctx_sb stat() info for the current Mailbox
32 * @param check_stats If true, also count the total, new and flagged messages
34 static void mailbox_check(struct Mailbox *m_cur, struct Mailbox *m_check,
35 struct stat *ctx_sb, bool check_stats)
37 struct stat sb = { 0 };
40 short orig_new = m_check->has_new;
41 int orig_count = m_check->msg_count;
42 int orig_unread = m_check->msg_unread;
43 int orig_flagged = m_check->msg_flagged;
46 enum MailboxType mb_magic = mx_path_probe(mailbox_path(m_check), NULL);
54 if (mb_magic != MUTT_IMAP)
55 m_check->has_new = false;
56 m_check->magic = mb_magic;
60 m_check->has_new = false;
62 if ((stat(mailbox_path(m_check), &sb) != 0) ||
63 (S_ISREG(sb.st_mode) && (sb.st_size == 0)) ||
64 ((m_check->magic == MUTT_UNKNOWN) &&
65 ((m_check->magic = mx_path_probe(mailbox_path(m_check), NULL)) <= 0)))
67 /* if the mailbox still doesn't exist, set the newly created flag to be
68 * ready for when it does. */
69 m_check->newly_created = true;
70 m_check->magic = MUTT_UNKNOWN;
74 break; // kept for consistency.
77 /* check to see if the folder is the currently selected folder before polling */
78 if (!m_cur || mutt_buffer_is_empty(&m_cur->pathbuf) ||
79 (((m_check->magic == MUTT_IMAP) || (m_check->magic == MUTT_NNTP) ||
80 (m_check->magic == MUTT_NOTMUCH) || (m_check->magic == MUTT_POP)) ?
81 (mutt_str_strcmp(mailbox_path(m_check), mailbox_path(m_cur)) != 0) :
82 ((sb.st_dev != ctx_sb->st_dev) || (sb.st_ino != ctx_sb->st_ino))))
84 switch (m_check->magic)
92 if ((mx_mbox_check_stats(m_check, check_stats) > 0) && m_check->has_new)
95 default:; /* do nothing */
98 else if (C_CheckMboxSize && m_cur && mutt_buffer_is_empty(&m_cur->pathbuf))
99 m_check->size = (off_t) sb.st_size; /* update the size of current folder */
102 if ((orig_new != m_check->has_new) || (orig_count != m_check->msg_count) ||
103 (orig_unread != m_check->msg_unread) || (orig_flagged != m_check->msg_flagged))
105 mutt_menu_set_current_redraw(REDRAW_SIDEBAR);
109 if (!m_check->has_new)
110 m_check->notified = false;
111 else if (!m_check->notified)
116 * mutt_mailbox_check - Check all all Mailboxes for new mail
117 * @param m_cur Current Mailbox
118 * @param force Force flags, see below
119 * @retval num Number of mailboxes with new mail
121 * The force argument may be any combination of the following values:
122 * - MUTT_MAILBOX_CHECK_FORCE ignore MailboxTime and check for new mail
123 * - MUTT_MAILBOX_CHECK_FORCE_STATS ignore MailboxTime and calculate statistics
125 * Check all all Mailboxes for new mail and total/new/flagged messages
127 int mutt_mailbox_check(struct Mailbox *m_cur, int force)
129 struct stat contex_sb;
131 bool check_stats = false;
132 contex_sb.st_dev = 0;
133 contex_sb.st_ino = 0;
136 /* update postponed count as well, on force */
137 if (force & MUTT_MAILBOX_CHECK_FORCE)
138 mutt_update_num_postponed();
141 /* fastest return if there are no mailboxes */
142 if (TAILQ_EMPTY(&NeoMutt->accounts))
145 t = mutt_date_epoch();
146 if (!force && (t - MailboxTime < C_MailCheck))
149 if ((force & MUTT_MAILBOX_CHECK_FORCE_STATS) ||
150 (C_MailCheckStats && ((t - MailboxStatsTime) >= C_MailCheckStatsInterval)))
153 MailboxStatsTime = t;
160 /* check device ID and serial number instead of comparing paths */
161 if (!m_cur || (m_cur->magic == MUTT_IMAP) || (m_cur->magic == MUTT_POP)
163 || (m_cur->magic == MUTT_NNTP)
165 || stat(mailbox_path(m_cur), &contex_sb) != 0)
167 contex_sb.st_dev = 0;
168 contex_sb.st_ino = 0;
171 struct MailboxList ml = neomutt_mailboxlist_get_all(NeoMutt, MUTT_MAILBOX_ANY);
172 struct MailboxNode *np = NULL;
173 STAILQ_FOREACH(np, &ml, entries)
175 mailbox_check(m_cur, np->mailbox, &contex_sb,
176 check_stats || (!np->mailbox->first_check_stats_done && C_MailCheckStats));
177 np->mailbox->first_check_stats_done = true;
179 neomutt_mailboxlist_clear(&ml);
185 * mutt_mailbox_notify - Notify the user if there's new mail
186 * @param m_cur Current Mailbox
187 * @retval true If there is new mail
189 bool mutt_mailbox_notify(struct Mailbox *m_cur)
191 if ((mutt_mailbox_check(m_cur, 0) > 0) && MailboxNotify)
193 return mutt_mailbox_list();
199 * mutt_mailbox_list - List the mailboxes with new mail
200 * @retval true If there is new mail
202 bool mutt_mailbox_list(void)
204 char mailboxlist[512];
208 int have_unnotified = MailboxNotify;
210 struct Buffer *path = mutt_buffer_pool_get();
212 mailboxlist[0] = '\0';
213 pos += strlen(strncat(mailboxlist, _("New mail in "), sizeof(mailboxlist) - 1 - pos));
214 struct MailboxList ml = neomutt_mailboxlist_get_all(NeoMutt, MUTT_MAILBOX_ANY);
215 struct MailboxNode *np = NULL;
216 STAILQ_FOREACH(np, &ml, entries)
218 /* Is there new mail in this mailbox? */
219 if (!np->mailbox->has_new || (have_unnotified && np->mailbox->notified))
222 mutt_buffer_strcpy(path, mailbox_path(np->mailbox));
223 mutt_buffer_pretty_mailbox(path);
225 if (!first && (MuttMessageWindow->cols >= 7) &&
226 ((pos + mutt_buffer_len(path)) >= ((size_t) MuttMessageWindow->cols - 7)))
232 pos += strlen(strncat(mailboxlist + pos, ", ", sizeof(mailboxlist) - 1 - pos));
234 /* Prepend an asterisk to mailboxes not already notified */
235 if (!np->mailbox->notified)
237 /* pos += strlen (strncat(mailboxlist + pos, "*", sizeof(mailboxlist)-1-pos)); */
238 np->mailbox->notified = true;
241 pos += strlen(strncat(mailboxlist + pos, mutt_b2s(path), sizeof(mailboxlist) - 1 - pos));
244 neomutt_mailboxlist_clear(&ml);
248 strncat(mailboxlist + pos, ", ...", sizeof(mailboxlist) - 1 - pos);
251 mutt_buffer_pool_release(&path);
255 mutt_message("%s", mailboxlist);
260 /* there were no mailboxes needing to be notified, so clean up since
261 * MailboxNotify has somehow gotten out of sync */
268 * mutt_mailbox_set_notified - Note when the user was last notified of new mail
271 void mutt_mailbox_set_notified(struct Mailbox *m)
277 #if HAVE_CLOCK_GETTIME
278 clock_gettime(CLOCK_REALTIME, &m->last_visited);
280 m->last_visited.tv_sec = mutt_date_epoch();
281 m->last_visited.tv_nsec = 0;
286 * mutt_mailbox_next_buffer - incoming folders completion routine
287 * @param m_cur Current Mailbox
288 * @param s Buffer containing name of current mailbox
290 * Given a folder name, find the next incoming folder with new mail.
292 void mutt_mailbox_next_buffer(struct Mailbox *m_cur, struct Buffer *s)
294 mutt_buffer_expand_path(s);
296 if (mutt_mailbox_check(m_cur, 0) > 0)
299 for (int pass = 0; pass < 2; pass++)
301 struct MailboxList ml = neomutt_mailboxlist_get_all(NeoMutt, MUTT_MAILBOX_ANY);
302 struct MailboxNode *np = NULL;
303 STAILQ_FOREACH(np, &ml, entries)
305 if (np->mailbox->magic == MUTT_NOTMUCH) /* only match real mailboxes */
307 mutt_buffer_expand_path(&np->mailbox->pathbuf);
308 if ((found || (pass > 0)) && np->mailbox->has_new)
310 mutt_buffer_strcpy(s, mailbox_path(np->mailbox));
311 mutt_buffer_pretty_mailbox(s);
314 if (mutt_str_strcmp(mutt_b2s(s), mailbox_path(np->mailbox)) == 0)
317 neomutt_mailboxlist_clear(&ml);
320 mutt_mailbox_check(m_cur, MUTT_MAILBOX_CHECK_FORCE); /* mailbox was wrong - resync things */
323 /* no folders with new mail */
324 mutt_buffer_reset(s);
328 * mutt_mailbox_next - incoming folders completion routine
329 * @param m_cur Current Mailbox
330 * @param s Buffer containing name of current mailbox
331 * @param slen Buffer length
333 * Given a folder name, find the next incoming folder with new mail.
335 void mutt_mailbox_next(struct Mailbox *m_cur, char *s, size_t slen)
337 struct Buffer *s_buf = mutt_buffer_pool_get();
339 mutt_buffer_addstr(s_buf, NONULL(s));
340 mutt_mailbox_next_buffer(m_cur, s_buf);
341 mutt_str_strfcpy(s, mutt_b2s(s_buf), slen);
343 mutt_buffer_pool_release(&s_buf);
347 * mutt_mailbox_cleanup - Restore the timestamp of a mailbox
348 * @param path Path to the mailbox
349 * @param st Timestamp info from stat()
351 * Fix up the atime and mtime after mbox/mmdf mailbox was modified according to
352 * stat() info taken before a modification.
354 void mutt_mailbox_cleanup(const char *path, struct stat *st)
356 #ifdef HAVE_UTIMENSAT
357 struct timespec ts[2];
364 struct Mailbox *m = mailbox_find(path);
365 if (m && !m->has_new)
370 /* fix up the times so mailbox won't get confused */
371 if (st->st_mtime > st->st_atime)
373 #ifdef HAVE_UTIMENSAT
375 ts[0].tv_nsec = UTIME_OMIT;
377 ts[1].tv_nsec = UTIME_NOW;
378 utimensat(0, buf, ts, 0);
380 ut.actime = st->st_atime;
381 ut.modtime = mutt_date_epoch();
387 #ifdef HAVE_UTIMENSAT
389 ts[0].tv_nsec = UTIME_NOW;
391 ts[1].tv_nsec = UTIME_NOW;
392 utimensat(0, buf, ts, 0);