NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
mview.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <string.h>
32#include "mutt/lib.h"
33#include "config/lib.h"
34#include "email/lib.h"
35#include "core/lib.h"
36#include "mview.h"
37#include "imap/lib.h"
38#include "ncrypt/lib.h"
39#include "pattern/lib.h"
40#include "mx.h"
41#include "thread.h"
42
47void mview_free(struct MailboxView **ptr)
48{
49 if (!ptr || !*ptr)
50 return;
51
52 struct MailboxView *mv = *ptr;
53
54 struct EventMview ev_m = { mv };
55 mutt_debug(LL_NOTIFY, "NT_MVIEW_DELETE: %p\n", (void *) mv);
57
58 if (mv->mailbox)
59 {
61
62 // Disconnect the Emails before freeing the Threads
63 for (int i = 0; i < mv->mailbox->msg_count; i++)
64 {
65 struct Email *e = mv->mailbox->emails[i];
66 if (!e)
67 continue;
68 e->thread = NULL;
69 e->threaded = false;
70 }
71 }
72
74 notify_free(&mv->notify);
75 FREE(&mv->pattern);
77
78 *ptr = NULL;
79 FREE(&mv);
80}
81
88struct MailboxView *mview_new(struct Mailbox *m, struct Notify *parent)
89{
90 if (!m)
91 return NULL;
92
93 struct MailboxView *mv = MUTT_MEM_CALLOC(1, struct MailboxView);
94
95 mv->notify = notify_new();
96 notify_set_parent(mv->notify, parent);
97 struct EventMview ev_m = { mv };
98 mutt_debug(LL_NOTIFY, "NT_MVIEW_ADD: %p\n", (void *) mv);
100 // If the Mailbox is closed, mv->mailbox must be set to NULL
102
103 mv->mailbox = m;
105 mv->msg_in_pager = -1;
106 mv->collapsed = false;
108
109 return mv;
110}
111
116static void mview_clean(struct MailboxView *mv)
117{
118 FREE(&mv->pattern);
120 if (mv->mailbox)
122
123 struct Notify *notify = mv->notify;
124 struct Mailbox *m = mv->mailbox;
125 memset(mv, 0, sizeof(struct MailboxView));
126 mv->notify = notify;
127 mv->mailbox = m;
128}
129
136void mview_update(struct MailboxView *mv)
137{
138 if (!mv || !mv->mailbox)
139 return;
140
141 struct Mailbox *m = mv->mailbox;
142
145
146 /* reset counters */
147 m->msg_unread = 0;
148 m->msg_flagged = 0;
149 m->msg_new = 0;
150 m->msg_deleted = 0;
151 m->msg_tagged = 0;
152 m->vcount = 0;
153 m->changed = false;
154
156
157 const bool c_score = cs_subset_bool(NeoMutt->sub, "score");
158 struct Email *e = NULL;
159 for (int msgno = 0; msgno < m->msg_count; msgno++)
160 {
161 e = m->emails[msgno];
162 if (!e)
163 continue;
164
165 if (WithCrypto)
166 {
167 /* NOTE: this _must_ be done before the check for mailcap! */
168 e->security = crypt_query(e->body);
169 }
170
171 if (mview_has_limit(mv))
172 {
173 e->vnum = -1;
174 }
175 else
176 {
177 m->v2r[m->vcount] = msgno;
178 e->vnum = m->vcount++;
179 }
180 e->msgno = msgno;
181
182 if (e->env->supersedes)
183 {
184 struct Email *e2 = NULL;
185
186 if (!m->id_hash)
188
189 e2 = mutt_hash_find(m->id_hash, e->env->supersedes);
190 if (e2)
191 {
192 e2->superseded = true;
193 if (c_score)
194 mutt_score_message(mv->mailbox, e2, true);
195 }
196 }
197
198 /* add this message to the hash tables */
199 if (m->id_hash && e->env->message_id)
201 if (m->subj_hash && e->env->real_subj)
204
205 if (c_score)
206 mutt_score_message(mv->mailbox, e, false);
207
208 if (e->changed)
209 m->changed = true;
210 if (e->flagged)
211 m->msg_flagged++;
212 if (e->deleted)
213 m->msg_deleted++;
214 if (e->tagged)
215 m->msg_tagged++;
216 if (!e->read)
217 {
218 m->msg_unread++;
219 if (!e->old)
220 m->msg_new++;
221 }
222 }
223
224 /* rethread from scratch */
225 mutt_sort_headers(mv, true);
226}
227
232static void update_tables(struct MailboxView *mv)
233{
234 if (!mv || !mv->mailbox)
235 return;
236
237 struct Mailbox *m = mv->mailbox;
238
239 int i, j, padding;
240
241 /* update memory to reflect the new state of the mailbox */
242 m->vcount = 0;
243 mv->vsize = 0;
244 m->msg_tagged = 0;
245 m->msg_deleted = 0;
246 m->msg_new = 0;
247 m->msg_unread = 0;
248 m->changed = false;
249 m->msg_flagged = 0;
250 padding = mx_msg_padding_size(m);
251 const bool c_maildir_trash = cs_subset_bool(NeoMutt->sub, "maildir_trash");
252 for (i = 0, j = 0; i < m->msg_count; i++)
253 {
254 if (!m->emails[i])
255 break;
256 if (!m->emails[i]->quasi_deleted &&
257 (!m->emails[i]->deleted || ((m->type == MUTT_MAILDIR) && c_maildir_trash)))
258 {
259 if (i != j)
260 {
261 m->emails[j] = m->emails[i];
262 m->emails[i] = NULL;
263 }
264 m->emails[j]->msgno = j;
265 if (m->emails[j]->vnum != -1)
266 {
267 m->v2r[m->vcount] = j;
268 m->emails[j]->vnum = m->vcount++;
269 struct Body *b = m->emails[j]->body;
270 mv->vsize += b->length + b->offset - b->hdr_offset + padding;
271 }
272
273 m->emails[j]->changed = false;
274 m->emails[j]->env->changed = false;
275
276 if ((m->type == MUTT_MAILDIR) && c_maildir_trash)
277 {
278 if (m->emails[j]->deleted)
279 m->msg_deleted++;
280 }
281
282 if (m->emails[j]->tagged)
283 m->msg_tagged++;
284 if (m->emails[j]->flagged)
285 m->msg_flagged++;
286 if (!m->emails[j]->read)
287 {
288 m->msg_unread++;
289 if (!m->emails[j]->old)
290 m->msg_new++;
291 }
292
293 j++;
294 }
295 else
296 {
297 if ((m->type == MUTT_NOTMUCH) || (m->type == MUTT_MH) ||
298 (m->type == MUTT_MAILDIR) || (m->type == MUTT_IMAP))
299 {
300 mailbox_size_sub(m, m->emails[i]);
301 }
302 /* remove message from the hash tables */
303 if (m->subj_hash && m->emails[i]->env->real_subj)
305 if (m->id_hash && m->emails[i]->env->message_id)
308
309 if (m->type == MUTT_IMAP)
311
312 mailbox_gc_add(m->emails[i]);
313 m->emails[i] = NULL;
314 }
315 }
316 m->msg_count = j;
317}
318
323{
324 if (nc->event_type != NT_MAILBOX)
325 return 0;
326 if (!nc->global_data)
327 return -1;
328
329 struct MailboxView *mv = nc->global_data;
330
331 switch (nc->event_subtype)
332 {
335 mview_clean(mv);
336 break;
338 mview_update(mv);
339 break;
341 update_tables(mv);
342 break;
344 mutt_sort_headers(mv, true);
345 break;
346 default:
347 return 0;
348 }
349
350 mutt_debug(LL_DEBUG5, "mailbox done\n");
351 return 0;
352}
353
362{
363 return e->visible && e->tagged;
364}
365
375int ea_add_tagged(struct EmailArray *ea, struct MailboxView *mv, struct Email *e, bool use_tagged)
376{
377 if (use_tagged)
378 {
379 if (!mv || !mv->mailbox || !mv->mailbox->emails)
380 return -1;
381
382 struct Mailbox *m = mv->mailbox;
383 for (int i = 0; i < m->msg_count; i++)
384 {
385 e = m->emails[i];
386 if (!e)
387 break;
388 if (!message_is_tagged(e))
389 continue;
390
391 ARRAY_ADD(ea, e);
392 }
393 }
394 else
395 {
396 if (!e)
397 return -1;
398
399 ARRAY_ADD(ea, e);
400 }
401
402 return ARRAY_SIZE(ea);
403}
404
415struct Email *mutt_get_virt_email(struct Mailbox *m, int vnum)
416{
417 if (!m || !m->emails || !m->v2r)
418 return NULL;
419
420 if ((vnum < 0) || (vnum >= m->vcount))
421 return NULL;
422
423 int inum = m->v2r[vnum];
424 if ((inum < 0) || (inum >= m->msg_count))
425 return NULL;
426
427 return m->emails[inum];
428}
429
436bool mview_has_limit(const struct MailboxView *mv)
437{
438 return mv && mv->pattern;
439}
440
448{
449 return mv ? mv->mailbox : NULL;
450}
451
458static struct MuttThread *top_of_thread(struct Email *e)
459{
460 if (!e)
461 return NULL;
462
463 struct MuttThread *t = e->thread;
464
465 while (t && t->parent)
466 t = t->parent;
467
468 return t;
469}
470
478bool mutt_limit_current_thread(struct MailboxView *mv, struct Email *e)
479{
480 if (!mv || !mv->mailbox || !e)
481 return false;
482
483 struct Mailbox *m = mv->mailbox;
484
485 struct MuttThread *me = top_of_thread(e);
486 if (!me)
487 return false;
488
489 m->vcount = 0;
490 mv->vsize = 0;
491 mv->collapsed = false;
492
493 for (int i = 0; i < m->msg_count; i++)
494 {
495 e = m->emails[i];
496 if (!e)
497 break;
498
499 e->vnum = -1;
500 e->visible = false;
501 e->collapsed = false;
502 e->num_hidden = 0;
503
504 if (top_of_thread(e) == me)
505 {
506 struct Body *body = e->body;
507
508 e->vnum = m->vcount;
509 e->visible = true;
510 m->v2r[m->vcount] = i;
511 m->vcount++;
512 mv->vsize += (body->length + body->offset - body->hdr_offset);
513 }
514 }
515 return true;
516}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition compile.c:826
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void mailbox_size_sub(struct Mailbox *m, const struct Email *e)
Subtract an email's size from the total size of a Mailbox.
Definition mailbox.c:258
void mailbox_gc_add(struct Email *e)
Add an Email to the garbage-collection set.
Definition mailbox.c:297
@ NT_MAILBOX_RESORT
Email list needs resorting.
Definition mailbox.h:180
@ NT_MAILBOX_DELETE
Mailbox is about to be deleted.
Definition mailbox.h:173
@ NT_MAILBOX_INVALID
Email list was changed.
Definition mailbox.h:179
@ NT_MAILBOX_UPDATE
Update internal tables.
Definition mailbox.h:181
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition mailbox.h:50
@ MUTT_MH
'MH' Mailbox type
Definition mailbox.h:46
@ MUTT_IMAP
'IMAP' Mailbox type
Definition mailbox.h:49
@ MUTT_MAILDIR
'Maildir' Mailbox type
Definition mailbox.h:47
SecurityFlags crypt_query(struct Body *b)
Check out the type of encryption used.
Definition crypt.c:687
void mutt_label_hash_remove(struct Mailbox *m, struct Email *e)
Remove a message's labels from the Hash Table.
Definition header.c:430
void mutt_label_hash_add(struct Mailbox *m, struct Email *e)
Add a message's labels to the Hash Table.
Definition header.c:417
Structs that make up an email.
void mutt_sort_headers(struct MailboxView *mv, bool init)
Sort emails by their headers.
Definition sort.c:354
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
int mview_mailbox_observer(struct NotifyCallback *nc)
Notification that a Mailbox has changed - Implements observer_t -.
Definition mview.c:322
void mutt_clear_threads(struct ThreadsContext *tctx)
Clear the threading of message in a mailbox.
Definition thread.c:797
struct ThreadsContext * mutt_thread_ctx_init(struct MailboxView *mv)
Initialize a threading context.
Definition thread.c:370
void mutt_thread_ctx_free(struct ThreadsContext **ptr)
Finalize a threading context.
Definition thread.c:381
struct HashTable * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for Message-IDs.
Definition thread.c:1781
Create/manipulate threading in emails.
struct HashElem * mutt_hash_insert(struct HashTable *table, const char *strkey, void *data)
Add a new element to the Hash Table (with string keys)
Definition hash.c:337
void mutt_hash_delete(struct HashTable *table, const char *strkey, const void *data)
Remove an element from a Hash Table.
Definition hash.c:429
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition hash.c:364
void mutt_hash_free(struct HashTable **ptr)
Free a hash table.
Definition hash.c:459
IMAP network mailbox.
void imap_notify_delete_email(struct Mailbox *m, struct Email *e)
Inform IMAP that an Email has been deleted.
Definition imap.c:828
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:50
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
Convenience wrapper for the library headers.
bool notify_observer_remove(struct Notify *notify, const observer_t callback, const void *global_data)
Remove an observer from an object.
Definition notify.c:230
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition notify.c:191
struct Notify * notify_new(void)
Create a new notifications handler.
Definition notify.c:62
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition notify.c:173
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition notify.c:95
void notify_free(struct Notify **ptr)
Free a notification handler.
Definition notify.c:75
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition mview.c:415
static void mview_clean(struct MailboxView *mv)
Release memory and initialize a MailboxView.
Definition mview.c:116
struct Mailbox * mview_mailbox(struct MailboxView *mv)
Wrapper to get the mailbox in a MailboxView, or NULL.
Definition mview.c:447
static void update_tables(struct MailboxView *mv)
Update a MailboxView's internal tables.
Definition mview.c:232
bool mutt_limit_current_thread(struct MailboxView *mv, struct Email *e)
Limit the email view to the current thread.
Definition mview.c:478
void mview_free(struct MailboxView **ptr)
Free a MailboxView.
Definition mview.c:47
static struct MuttThread * top_of_thread(struct Email *e)
Find the first email in the current thread.
Definition mview.c:458
int ea_add_tagged(struct EmailArray *ea, struct MailboxView *mv, struct Email *e, bool use_tagged)
Get an array of the tagged Emails.
Definition mview.c:375
bool message_is_tagged(struct Email *e)
Is a message in the index tagged (and within limit)
Definition mview.c:361
void mview_update(struct MailboxView *mv)
Update the MailboxView's message counts.
Definition mview.c:136
bool mview_has_limit(const struct MailboxView *mv)
Is a limit active?
Definition mview.c:436
struct MailboxView * mview_new(struct Mailbox *m, struct Notify *parent)
Create a new MailboxView.
Definition mview.c:88
View of a Mailbox.
@ NT_MVIEW_DELETE
The Mview is about to be destroyed.
Definition mview.h:63
@ NT_MVIEW_ADD
The Mview has been opened.
Definition mview.h:62
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition mx.c:1507
API for mailboxes.
API for encryption/signing of emails.
#define WithCrypto
Definition lib.h:124
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition notify_type.h:49
@ NT_MVIEW
MailboxView has changed, NotifyMview, EventMview.
Definition notify_type.h:50
Match patterns to emails.
void mutt_score_message(struct Mailbox *m, struct Email *e, bool upd_mbox)
Apply scoring to an email.
Definition score.c:229
The body of an email.
Definition body.h:36
LOFF_T offset
offset where the actual data begins
Definition body.h:52
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
long hdr_offset
Offset in stream where the headers begin.
Definition body.h:81
The envelope/body of an email.
Definition email.h:39
bool read
Email is read.
Definition email.h:50
bool visible
Is this message part of the view?
Definition email.h:121
struct Envelope * env
Envelope information.
Definition email.h:68
bool collapsed
Is this message part of a collapsed thread?
Definition email.h:120
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
struct Body * body
List of MIME parts.
Definition email.h:69
bool old
Email is seen, but unread.
Definition email.h:49
size_t num_hidden
Number of hidden messages in this view (only valid when collapsed is set)
Definition email.h:123
bool changed
Email has been edited.
Definition email.h:77
bool flagged
Marked important?
Definition email.h:47
bool threaded
Used for threading.
Definition email.h:108
int vnum
Virtual message number.
Definition email.h:114
int msgno
Number displayed to the user.
Definition email.h:111
bool deleted
Email is deleted.
Definition email.h:78
bool quasi_deleted
Deleted from neomutt, but not modified on disk.
Definition email.h:103
bool tagged
Email is tagged.
Definition email.h:107
bool superseded
Got superseded?
Definition email.h:52
struct MuttThread * thread
Thread of Emails.
Definition email.h:119
char * supersedes
Supersedes header.
Definition envelope.h:74
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition envelope.h:90
char * message_id
Message ID.
Definition envelope.h:73
char *const real_subj
Offset of the real subject.
Definition envelope.h:71
An Event that happened to an MailboxView.
Definition mview.h:71
struct MailboxView * mv
The MailboxView this Event relates to.
Definition mview.h:72
View of a Mailbox.
Definition mview.h:40
bool collapsed
Are all threads collapsed?
Definition mview.h:49
off_t vsize
Size (in bytes) of the messages shown.
Definition mview.h:41
struct Notify * notify
Notifications: NotifyMview, EventMview.
Definition mview.h:52
struct PatternList * limit_pattern
Compiled limit pattern.
Definition mview.h:43
struct ThreadsContext * threads
Threads context.
Definition mview.h:44
int msg_in_pager
Message currently shown in the pager.
Definition mview.h:45
struct Mailbox * mailbox
Current Mailbox.
Definition mview.h:51
char * pattern
Limit pattern string.
Definition mview.h:42
A mailbox.
Definition mailbox.h:78
int vcount
The number of virtual messages.
Definition mailbox.h:98
bool changed
Mailbox has been modified.
Definition mailbox.h:109
int * v2r
Mapping from virtual to real msgno.
Definition mailbox.h:97
int msg_new
Number of new messages.
Definition mailbox.h:91
int msg_count
Total number of messages.
Definition mailbox.h:87
enum MailboxType type
Mailbox type.
Definition mailbox.h:101
struct HashTable * subj_hash
Hash Table: "Subject" -> Email.
Definition mailbox.h:123
struct Email ** emails
Array of Emails.
Definition mailbox.h:95
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition mailbox.h:144
struct HashTable * id_hash
Hash Table: "Message-ID" -> Email.
Definition mailbox.h:122
int msg_deleted
Number of deleted messages.
Definition mailbox.h:92
int msg_flagged
Number of flagged messages.
Definition mailbox.h:89
int msg_tagged
How many messages are tagged?
Definition mailbox.h:93
int msg_unread
Number of unread messages.
Definition mailbox.h:88
An Email conversation.
Definition thread.h:34
struct MuttThread * parent
Parent of this Thread.
Definition thread.h:44
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Data passed to a notification function.
Definition observer.h:34
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition observer.h:36
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition observer.h:37
void * global_data
Data from notify_observer_add()
Definition observer.h:39
Notification API.
Definition notify.c:53