3 * The "currently-open" mailbox
6 * Copyright (C) 2018 Richard Russon <rich@flatcap.org>
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 2 of the License, or (at your option) any later
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
24 * @page ctx The "currently-open" mailbox
26 * The "currently-open" mailbox
31 #include "mutt/mutt.h"
32 #include "config/lib.h"
33 #include "email/lib.h"
37 #include "mutt_header.h"
38 #include "mutt_thread.h"
40 #include "ncrypt/ncrypt.h"
46 * ctx_free - Free a Context
47 * @param[out] ptr Context to free
49 void ctx_free(struct Context **ptr)
54 struct Context *ctx = *ptr;
56 struct EventContext ev_ctx = { ctx };
57 notify_send(ctx->notify, NT_CONTEXT, NT_CONTEXT_CLOSE, IP & ev_ctx);
60 notify_observer_remove(ctx->mailbox->notify, ctx_mailbox_observer, IP ctx);
62 notify_free(&ctx->notify);
68 * ctx_new - Create a new Context
69 * @retval ptr New Context
71 struct Context *ctx_new(void)
73 struct Context *ctx = mutt_mem_calloc(1, sizeof(struct Context));
75 ctx->notify = notify_new(ctx, NT_CONTEXT);
76 notify_set_parent(ctx->notify, NeoMutt->notify);
82 * ctx_cleanup - Release memory and initialize a Context object
83 * @param ctx Context to cleanup
85 void ctx_cleanup(struct Context *ctx)
88 mutt_pattern_free(&ctx->limit_pattern);
90 notify_observer_remove(ctx->mailbox->notify, ctx_mailbox_observer, IP ctx);
92 struct Notify *notify = ctx->notify;
93 memset(ctx, 0, sizeof(struct Context));
98 * ctx_update - Update the Context's message counts
101 * this routine is called to update the counts in the context structure
103 void ctx_update(struct Context *ctx)
105 if (!ctx || !ctx->mailbox)
108 struct Mailbox *m = ctx->mailbox;
110 mutt_hash_free(&m->subj_hash);
111 mutt_hash_free(&m->id_hash);
122 mutt_clear_threads(ctx);
124 struct Email *e = NULL;
125 for (int msgno = 0; msgno < m->msg_count; msgno++)
127 e = m->emails[msgno];
131 /* NOTE: this _must_ be done before the check for mailcap! */
132 e->security = crypt_query(e->content);
137 m->v2r[m->vcount] = msgno;
138 e->vnum = m->vcount++;
144 if (e->env->supersedes)
146 struct Email *e2 = NULL;
149 m->id_hash = mutt_make_id_hash(m);
151 e2 = mutt_hash_find(m->id_hash, e->env->supersedes);
154 e2->superseded = true;
156 mutt_score_message(ctx->mailbox, e2, true);
160 /* add this message to the hash tables */
161 if (m->id_hash && e->env->message_id)
162 mutt_hash_insert(m->id_hash, e->env->message_id, e);
163 if (m->subj_hash && e->env->real_subj)
164 mutt_hash_insert(m->subj_hash, e->env->real_subj, e);
165 mutt_label_hash_add(m, e);
168 mutt_score_message(ctx->mailbox, e, false);
184 mutt_sort_headers(ctx, true); /* rethread from scratch */
188 * ctx_update_tables - Update a Context structure's internal tables
190 * @param committing Commit the changes?
192 void ctx_update_tables(struct Context *ctx, bool committing)
194 if (!ctx || !ctx->mailbox)
197 struct Mailbox *m = ctx->mailbox;
201 /* update memory to reflect the new state of the mailbox */
210 padding = mx_msg_padding_size(m);
211 for (i = 0, j = 0; i < m->msg_count; i++)
213 if (!m->emails[i]->quasi_deleted &&
214 ((committing && (!m->emails[i]->deleted || ((m->magic == MUTT_MAILDIR) && C_MaildirTrash))) ||
215 (!committing && m->emails[i]->active)))
219 m->emails[j] = m->emails[i];
222 m->emails[j]->msgno = j;
223 if (m->emails[j]->vnum != -1)
225 m->v2r[m->vcount] = j;
226 m->emails[j]->vnum = m->vcount++;
227 struct Body *b = m->emails[j]->content;
228 ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
233 m->emails[j]->changed = false;
234 m->emails[j]->env->changed = false;
236 else if (m->emails[j]->changed)
239 if (!committing || ((m->magic == MUTT_MAILDIR) && C_MaildirTrash))
241 if (m->emails[j]->deleted)
245 if (m->emails[j]->tagged)
247 if (m->emails[j]->flagged)
249 if (!m->emails[j]->read)
252 if (!m->emails[j]->old)
260 if ((m->magic == MUTT_NOTMUCH) || (m->magic == MUTT_MH) ||
261 (m->magic == MUTT_MAILDIR) || (m->magic == MUTT_IMAP))
263 mailbox_size_sub(m, m->emails[i]);
265 /* remove message from the hash tables */
266 if (m->subj_hash && m->emails[i]->env->real_subj)
267 mutt_hash_delete(m->subj_hash, m->emails[i]->env->real_subj, m->emails[i]);
268 if (m->id_hash && m->emails[i]->env->message_id)
269 mutt_hash_delete(m->id_hash, m->emails[i]->env->message_id, m->emails[i]);
270 mutt_label_hash_remove(m, m->emails[i]);
271 /* The path mx_mbox_check() -> imap_check_mailbox() ->
272 * imap_expunge_mailbox() -> ctx_update_tables()
273 * can occur before a call to mx_mbox_sync(), resulting in
274 * last_tag being stale if it's not reset here. */
275 if (ctx->last_tag == m->emails[i])
276 ctx->last_tag = NULL;
277 email_free(&m->emails[i]);
284 * ctx_mailbox_observer - Watch for changes affecting the Context - Implements ::observer_t
286 int ctx_mailbox_observer(struct NotifyCallback *nc)
290 if ((nc->obj_type != NT_MAILBOX) || (nc->event_type != NT_MAILBOX))
292 struct Context *ctx = (struct Context *) nc->data;
296 switch (nc->event_subtype)
299 mutt_clear_threads(ctx);
306 ctx_update_tables(ctx, true);
309 mutt_sort_headers(ctx, true);
312 if (ctx->last_tag && ctx->last_tag->deleted)
313 ctx->last_tag = NULL;
321 * message_is_visible - Is a message in the index within limit
322 * @param ctx Open mailbox
323 * @param index Message ID (index into `ctx->emails[]`
324 * @retval true The message is within limit
326 * If no limit is in effect, all the messages are visible.
328 bool message_is_visible(struct Context *ctx, int index)
330 if (!ctx || !ctx->mailbox->emails || (index >= ctx->mailbox->msg_count))
333 return !ctx->pattern || ctx->mailbox->emails[index]->limited;
337 * message_is_tagged - Is a message in the index tagged (and within limit)
338 * @param ctx Open mailbox
339 * @param index Message ID (index into `ctx->emails[]`
340 * @retval true The message is both tagged and within limit
342 * If a limit is in effect, the message must be visible within it.
344 bool message_is_tagged(struct Context *ctx, int index)
346 return message_is_visible(ctx, index) && ctx->mailbox->emails[index]->tagged;
350 * el_add_tagged - Get a list of the tagged Emails
351 * @param el Empty EmailList to populate
352 * @param ctx Current Mailbox
353 * @param e Current Email
354 * @param use_tagged Use tagged Emails
355 * @retval num Number of selected emails
358 int el_add_tagged(struct EmailList *el, struct Context *ctx, struct Email *e, bool use_tagged)
364 if (!ctx || !ctx->mailbox || !ctx->mailbox->emails)
367 for (size_t i = 0; i < ctx->mailbox->msg_count; i++)
369 if (!message_is_tagged(ctx, i))
372 struct EmailNode *en = mutt_mem_calloc(1, sizeof(*en));
373 en->email = ctx->mailbox->emails[i];
374 STAILQ_INSERT_TAIL(el, en, entries);
383 struct EmailNode *en = mutt_mem_calloc(1, sizeof(*en));
385 STAILQ_INSERT_TAIL(el, en, entries);
393 * el_add_email - Get a list of the selected Emails
394 * @param e Current Email
395 * @param el EmailList to add to
399 int el_add_email(struct EmailList *el, struct Email *e)
404 struct EmailNode *en = mutt_mem_calloc(1, sizeof(*en));
406 STAILQ_INSERT_TAIL(el, en, entries);