/** * cs_free - Free a Config Set * @param[out] cs Config items */ void cs_free(struct ConfigSet **cs) { if (!cs || !*cs) return; mutt_hash_free(&(*cs)->hash); FREE(cs); }
/** * cs_free - Free a Config Set * @param[out] cs Config items */ void cs_free(struct ConfigSet **cs) { if (!cs || !*cs) return; /* LCOV_EXCL_LINE */ mutt_hash_free(&(*cs)->hash); FREE(cs); }
/** * reopen_mailbox - Close and reopen a mailbox * @param m Mailbox * @param index_hint Current email * @retval >0 Success, e.g. #MUTT_REOPENED, #MUTT_NEW_MAIL * @retval -1 Error */ static int reopen_mailbox(struct Mailbox *m, int *index_hint) { if (!m) return -1; struct MboxAccountData *adata = mbox_adata_get(m); if (!adata) return -1; bool (*cmp_headers)(const struct Email *, const struct Email *) = NULL; struct Email **old_hdrs = NULL; int old_msg_count; bool msg_mod = false; int rc = -1; /* silent operations */ m->quiet = true; if (!m->quiet) mutt_message(_("Reopening mailbox...")); /* our heuristics require the old mailbox to be unsorted */ if (C_Sort != SORT_ORDER) { short old_sort = C_Sort; C_Sort = SORT_ORDER; mutt_mailbox_changed(m, MBN_RESORT); C_Sort = old_sort; } old_hdrs = NULL; old_msg_count = 0; /* simulate a close */ mutt_mailbox_changed(m, MBN_CLOSED); mutt_hash_free(&m->id_hash); mutt_hash_free(&m->subj_hash); mutt_hash_free(&m->label_hash); FREE(&m->v2r); if (m->readonly) { for (int i = 0; i < m->msg_count; i++) mutt_email_free(&(m->emails[i])); /* nothing to do! */ FREE(&m->emails); } else { /* save the old headers */ old_msg_count = m->msg_count; old_hdrs = m->emails; m->emails = NULL; } m->email_max = 0; /* force allocation of new headers */ m->msg_count = 0; m->vcount = 0; m->msg_tagged = 0; m->msg_deleted = 0; m->msg_new = 0; m->msg_unread = 0; m->msg_flagged = 0; m->changed = false; m->id_hash = NULL; m->subj_hash = NULL; mutt_make_label_hash(m); switch (m->magic) { case MUTT_MBOX: case MUTT_MMDF: cmp_headers = mutt_email_cmp_strict; mutt_file_fclose(&adata->fp); adata->fp = mutt_file_fopen(m->path, "r"); if (!adata->fp) rc = -1; else if (m->magic == MUTT_MBOX) rc = mbox_parse_mailbox(m); else rc = mmdf_parse_mailbox(m); break; default: rc = -1; break; } if (rc == -1) { /* free the old headers */ for (int i = 0; i < old_msg_count; i++) mutt_email_free(&(old_hdrs[i])); FREE(&old_hdrs); m->quiet = false; return -1; } mutt_file_touch_atime(fileno(adata->fp)); /* now try to recover the old flags */ if (!m->readonly) { for (int i = 0; i < m->msg_count; i++) { bool found = false; /* some messages have been deleted, and new messages have been * appended at the end; the heuristic is that old messages have then * "advanced" towards the beginning of the folder, so we begin the * search at index "i" */ int j; for (j = i; j < old_msg_count; j++) { if (!old_hdrs[j]) continue; if (cmp_headers(m->emails[i], old_hdrs[j])) { found = true; break; } } if (!found) { for (j = 0; (j < i) && (j < old_msg_count); j++) { if (!old_hdrs[j]) continue; if (cmp_headers(m->emails[i], old_hdrs[j])) { found = true; break; } } } if (found) { /* this is best done here */ if (index_hint && (*index_hint == j)) *index_hint = i; if (old_hdrs[j]->changed) { /* Only update the flags if the old header was changed; * otherwise, the header may have been modified externally, * and we don't want to lose _those_ changes */ mutt_set_flag(m, m->emails[i], MUTT_FLAG, old_hdrs[j]->flagged); mutt_set_flag(m, m->emails[i], MUTT_REPLIED, old_hdrs[j]->replied); mutt_set_flag(m, m->emails[i], MUTT_OLD, old_hdrs[j]->old); mutt_set_flag(m, m->emails[i], MUTT_READ, old_hdrs[j]->read); } mutt_set_flag(m, m->emails[i], MUTT_DELETE, old_hdrs[j]->deleted); mutt_set_flag(m, m->emails[i], MUTT_PURGE, old_hdrs[j]->purge); mutt_set_flag(m, m->emails[i], MUTT_TAG, old_hdrs[j]->tagged); /* we don't need this header any more */ mutt_email_free(&(old_hdrs[j])); } } /* free the remaining old headers */ for (int j = 0; j < old_msg_count; j++) { if (old_hdrs[j]) { mutt_email_free(&(old_hdrs[j])); msg_mod = true; } } FREE(&old_hdrs); } m->quiet = false; return (m->changed || msg_mod) ? MUTT_REOPENED : MUTT_NEW_MAIL; }
/** * mh_mbox_check - Implements MxOps::mbox_check() * * This function handles arrival of new mail and reopening of mh/maildir * folders. Things are getting rather complex because we don't have a * well-defined "mailbox order", so the tricks from mbox.c and mx.c won't work * here. * * Don't change this code unless you _really_ understand what happens. */ int mh_mbox_check(struct Mailbox *m, int *index_hint) { if (!m) return -1; char buf[PATH_MAX]; struct stat st, st_cur; bool modified = false, occult = false, flags_changed = false; int num_new = 0; struct Maildir *md = NULL, *p = NULL; struct Maildir **last = NULL; struct MhSequences mhs = { 0 }; int count = 0; struct Hash *fnames = NULL; struct MaildirMboxData *mdata = maildir_mdata_get(m); if (!C_CheckNew) return 0; mutt_str_strfcpy(buf, m->path, sizeof(buf)); if (stat(buf, &st) == -1) return -1; /* create .mh_sequences when there isn't one. */ snprintf(buf, sizeof(buf), "%s/.mh_sequences", m->path); int i = stat(buf, &st_cur); if ((i == -1) && (errno == ENOENT)) { char *tmp = NULL; FILE *fp = NULL; if (mh_mkstemp(m, &fp, &tmp) == 0) { mutt_file_fclose(&fp); if (mutt_file_safe_rename(tmp, buf) == -1) unlink(tmp); FREE(&tmp); } } if ((i == -1) && (stat(buf, &st_cur) == -1)) modified = true; if ((mutt_file_stat_timespec_compare(&st, MUTT_STAT_MTIME, &m->mtime) > 0) || (mutt_file_stat_timespec_compare(&st_cur, MUTT_STAT_MTIME, &mdata->mtime_cur) > 0)) { modified = true; } if (!modified) return 0; /* Update the modification times on the mailbox. * * The monitor code notices changes in the open mailbox too quickly. * In practice, this sometimes leads to all the new messages not being * noticed during the SAME group of mtime stat updates. To work around * the problem, don't update the stat times for a monitor caused check. */ #ifdef USE_INOTIFY if (MonitorContextChanged) MonitorContextChanged = 0; else #endif { mutt_file_get_stat_timespec(&mdata->mtime_cur, &st_cur, MUTT_STAT_MTIME); mutt_file_get_stat_timespec(&m->mtime, &st, MUTT_STAT_MTIME); } md = NULL; last = &md; maildir_parse_dir(m, &last, NULL, &count, NULL); maildir_delayed_parsing(m, &md, NULL); if (mh_read_sequences(&mhs, m->path) < 0) return -1; mh_update_maildir(md, &mhs); mhs_free_sequences(&mhs); /* check for modifications and adjust flags */ fnames = mutt_hash_new(count, MUTT_HASH_NO_FLAGS); for (p = md; p; p = p->next) { /* the hash key must survive past the header, which is freed below. */ p->canon_fname = mutt_str_strdup(p->email->path); mutt_hash_insert(fnames, p->canon_fname, p); } for (i = 0; i < m->msg_count; i++) { m->emails[i]->active = false; p = mutt_hash_find(fnames, m->emails[i]->path); if (p && p->email && mutt_email_cmp_strict(m->emails[i], p->email)) { m->emails[i]->active = true; /* found the right message */ if (!m->emails[i]->changed) if (maildir_update_flags(m, m->emails[i], p->email)) flags_changed = true; mutt_email_free(&p->email); } else /* message has disappeared */ occult = true; } /* destroy the file name hash */ mutt_hash_free(&fnames); /* If we didn't just get new mail, update the tables. */ if (occult) mutt_mailbox_changed(m, MBN_RESORT); /* Incorporate new messages */ num_new = maildir_move_to_mailbox(m, &md); if (num_new > 0) { mutt_mailbox_changed(m, MBN_INVALID); m->changed = true; } if (occult) return MUTT_REOPENED; if (num_new > 0) return MUTT_NEW_MAIL; if (flags_changed) return MUTT_FLAGS; return 0; }