NeoMutt  2020-04-24
Teaching an old dog new tricks
DOXYGEN
context.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <string.h>
31 #include "mutt/lib.h"
32 #include "email/lib.h"
33 #include "core/lib.h"
34 #include "context.h"
35 #include "globals.h"
36 #include "mutt_header.h"
37 #include "mutt_thread.h"
38 #include "mx.h"
39 #include "pattern.h"
40 #include "score.h"
41 #include "sort.h"
42 #include "ncrypt/lib.h"
43 
48 void ctx_free(struct Context **ptr)
49 {
50  if (!ptr || !*ptr)
51  return;
52 
53  struct Context *ctx = *ptr;
54 
55  struct EventContext ev_ctx = { ctx };
57 
58  if (ctx->mailbox)
60 
62  notify_free(&ctx->notify);
63 
64  FREE(ptr);
65 }
66 
71 struct Context *ctx_new(void)
72 {
73  struct Context *ctx = mutt_mem_calloc(1, sizeof(struct Context));
74 
75  ctx->notify = notify_new();
77 
78  return ctx;
79 }
80 
85 static void ctx_cleanup(struct Context *ctx)
86 {
87  FREE(&ctx->pattern);
89  if (ctx->mailbox)
91 
92  struct Notify *notify = ctx->notify;
93  struct Mailbox *m = ctx->mailbox;
94  memset(ctx, 0, sizeof(struct Context));
95  ctx->notify = notify;
96  ctx->mailbox = m;
97 }
98 
105 void ctx_update(struct Context *ctx)
106 {
107  if (!ctx || !ctx->mailbox)
108  return;
109 
110  struct Mailbox *m = ctx->mailbox;
111 
113  mutt_hash_free(&m->id_hash);
114 
115  /* reset counters */
116  m->msg_unread = 0;
117  m->msg_flagged = 0;
118  m->msg_new = 0;
119  m->msg_deleted = 0;
120  m->msg_tagged = 0;
121  m->vcount = 0;
122  m->changed = false;
123 
124  mutt_clear_threads(ctx);
125 
126  struct Email *e = NULL;
127  for (int msgno = 0; msgno < m->msg_count; msgno++)
128  {
129  e = m->emails[msgno];
130  if (!e)
131  continue;
132 
133  if (WithCrypto)
134  {
135  /* NOTE: this _must_ be done before the check for mailcap! */
136  e->security = crypt_query(e->content);
137  }
138 
139  if (ctx->pattern)
140  {
141  e->vnum = -1;
142  }
143  else
144  {
145  m->v2r[m->vcount] = msgno;
146  e->vnum = m->vcount++;
147  }
148  e->msgno = msgno;
149 
150  if (e->env->supersedes)
151  {
152  struct Email *e2 = NULL;
153 
154  if (!m->id_hash)
155  m->id_hash = mutt_make_id_hash(m);
156 
157  e2 = mutt_hash_find(m->id_hash, e->env->supersedes);
158  if (e2)
159  {
160  e2->superseded = true;
161  if (C_Score)
162  mutt_score_message(ctx->mailbox, e2, true);
163  }
164  }
165 
166  /* add this message to the hash tables */
167  if (m->id_hash && e->env->message_id)
169  if (m->subj_hash && e->env->real_subj)
171  mutt_label_hash_add(m, e);
172 
173  if (C_Score)
174  mutt_score_message(ctx->mailbox, e, false);
175 
176  if (e->changed)
177  m->changed = true;
178  if (e->flagged)
179  m->msg_flagged++;
180  if (e->deleted)
181  m->msg_deleted++;
182  if (!e->read)
183  {
184  m->msg_unread++;
185  if (!e->old)
186  m->msg_new++;
187  }
188  }
189 
190  mutt_sort_headers(ctx, true); /* rethread from scratch */
191 }
192 
198 void ctx_update_tables(struct Context *ctx, bool committing)
199 {
200  if (!ctx || !ctx->mailbox)
201  return;
202 
203  struct Mailbox *m = ctx->mailbox;
204 
205  int i, j, padding;
206 
207  /* update memory to reflect the new state of the mailbox */
208  m->vcount = 0;
209  ctx->vsize = 0;
210  m->msg_tagged = 0;
211  m->msg_deleted = 0;
212  m->msg_new = 0;
213  m->msg_unread = 0;
214  m->changed = false;
215  m->msg_flagged = 0;
216  padding = mx_msg_padding_size(m);
217  for (i = 0, j = 0; i < m->msg_count; i++)
218  {
219  if (!m->emails[i])
220  break;
221  if (!m->emails[i]->quasi_deleted &&
222  ((committing && (!m->emails[i]->deleted || ((m->type == MUTT_MAILDIR) && C_MaildirTrash))) ||
223  (!committing && m->emails[i]->active)))
224  {
225  if (i != j)
226  {
227  m->emails[j] = m->emails[i];
228  m->emails[i] = NULL;
229  }
230  m->emails[j]->msgno = j;
231  if (m->emails[j]->vnum != -1)
232  {
233  m->v2r[m->vcount] = j;
234  m->emails[j]->vnum = m->vcount++;
235  struct Body *b = m->emails[j]->content;
236  ctx->vsize += b->length + b->offset - b->hdr_offset + padding;
237  }
238 
239  if (committing)
240  {
241  m->emails[j]->changed = false;
242  m->emails[j]->env->changed = false;
243  }
244  else if (m->emails[j]->changed)
245  m->changed = true;
246 
247  if (!committing || ((m->type == MUTT_MAILDIR) && C_MaildirTrash))
248  {
249  if (m->emails[j]->deleted)
250  m->msg_deleted++;
251  }
252 
253  if (m->emails[j]->tagged)
254  m->msg_tagged++;
255  if (m->emails[j]->flagged)
256  m->msg_flagged++;
257  if (!m->emails[j]->read)
258  {
259  m->msg_unread++;
260  if (!m->emails[j]->old)
261  m->msg_new++;
262  }
263 
264  j++;
265  }
266  else
267  {
268  if ((m->type == MUTT_NOTMUCH) || (m->type == MUTT_MH) ||
269  (m->type == MUTT_MAILDIR) || (m->type == MUTT_IMAP))
270  {
271  mailbox_size_sub(m, m->emails[i]);
272  }
273  /* remove message from the hash tables */
274  if (m->subj_hash && m->emails[i]->env->real_subj)
275  mutt_hash_delete(m->subj_hash, m->emails[i]->env->real_subj, m->emails[i]);
276  if (m->id_hash && m->emails[i]->env->message_id)
277  mutt_hash_delete(m->id_hash, m->emails[i]->env->message_id, m->emails[i]);
278  mutt_label_hash_remove(m, m->emails[i]);
279  /* The path mx_mbox_check() -> imap_check_mailbox() ->
280  * imap_expunge_mailbox() -> ctx_update_tables()
281  * can occur before a call to mx_mbox_sync(), resulting in
282  * last_tag being stale if it's not reset here. */
283  if (ctx->last_tag == m->emails[i])
284  ctx->last_tag = NULL;
285  email_free(&m->emails[i]);
286  }
287  }
288  m->msg_count = j;
289 }
290 
295 {
296  if (!nc->global_data)
297  return -1;
298  if (nc->event_type != NT_MAILBOX)
299  return 0;
300 
301  struct Context *ctx = nc->global_data;
302 
303  switch (nc->event_subtype)
304  {
305  case NT_MAILBOX_CLOSED:
306  mutt_clear_threads(ctx);
307  ctx_cleanup(ctx);
308  break;
309  case NT_MAILBOX_INVALID:
310  ctx_update(ctx);
311  break;
312  case NT_MAILBOX_UPDATE:
313  ctx_update_tables(ctx, true);
314  break;
315  case NT_MAILBOX_RESORT:
316  mutt_sort_headers(ctx, true);
317  break;
318  case NT_MAILBOX_UNTAG:
319  if (ctx->last_tag && ctx->last_tag->deleted)
320  ctx->last_tag = NULL;
321  break;
322  }
323 
324  return 0;
325 }
326 
335 bool message_is_visible(struct Context *ctx, struct Email *e)
336 {
337  if (!ctx || !e)
338  return false;
339 
340  return !ctx->pattern || e->limited;
341 }
342 
351 bool message_is_tagged(struct Context *ctx, struct Email *e)
352 {
353  return message_is_visible(ctx, e) && e->tagged;
354 }
355 
365 int el_add_tagged(struct EmailList *el, struct Context *ctx, struct Email *e, bool use_tagged)
366 {
367  int count = 0;
368 
369  if (use_tagged)
370  {
371  if (!ctx || !ctx->mailbox || !ctx->mailbox->emails)
372  return -1;
373 
374  struct Mailbox *m = ctx->mailbox;
375  for (size_t i = 0; i < m->msg_count; i++)
376  {
377  e = m->emails[i];
378  if (!e)
379  break;
380  if (!message_is_tagged(ctx, e))
381  continue;
382 
383  struct EmailNode *en = mutt_mem_calloc(1, sizeof(*en));
384  en->email = e;
385  STAILQ_INSERT_TAIL(el, en, entries);
386  count++;
387  }
388  }
389  else
390  {
391  if (!e)
392  return -1;
393 
394  struct EmailNode *en = mutt_mem_calloc(1, sizeof(*en));
395  en->email = e;
396  STAILQ_INSERT_TAIL(el, en, entries);
397  count = 1;
398  }
399 
400  return count;
401 }
402 
413 struct Email *mutt_get_virt_email(struct Mailbox *m, int vnum)
414 {
415  if (!m || !m->emails || !m->v2r)
416  return NULL;
417 
418  if ((vnum < 0) || (vnum >= m->vcount))
419  return NULL;
420 
421  int inum = m->v2r[vnum];
422  if ((inum < 0) || (inum >= m->msg_count))
423  return NULL;
424 
425  return m->emails[inum];
426 }
void ctx_update_tables(struct Context *ctx, bool committing)
Update a Context structure&#39;s internal tables.
Definition: context.c:198
struct Email ** emails
Array of Emails.
Definition: mailbox.h:99
The "current" mailbox.
Definition: context.h:37
int ctx_mailbox_observer(struct NotifyCallback *nc)
Watch for changes affecting the Context - Implements observer_t.
Definition: context.c:294
void mutt_hash_delete(struct Hash *table, const char *strkey, const void *data)
Remove an element from a Hash table.
Definition: hash.c:443
bool message_is_tagged(struct Context *ctx, struct Email *e)
Is a message in the index tagged (and within limit)
Definition: context.c:351
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
int msg_count
Total number of messages.
Definition: mailbox.h:91
Representation of the email&#39;s header.
#define WithCrypto
Definition: lib.h:163
The envelope/body of an email.
Definition: email.h:37
struct Email * mutt_get_virt_email(struct Mailbox *m, int vnum)
Get a virtual Email.
Definition: context.c:413
Clear the &#39;last-tagged&#39; pointer.
Definition: mailbox.h:174
Data passed to a notification function.
Definition: observer.h:39
Update internal tables.
Definition: mailbox.h:173
int msg_deleted
Number of deleted messages.
Definition: mailbox.h:96
int msg_unread
Number of unread messages.
Definition: mailbox.h:92
Structs that make up an email.
The "currently-open" mailbox.
char * supersedes
Supersedes header.
Definition: envelope.h:70
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:93
void notify_free(struct Notify **ptr)
Free a notification handler.
Definition: notify.c:62
struct Body * content
List of MIME parts.
Definition: email.h:90
void * mutt_hash_find(const struct Hash *table, const char *strkey)
Find the HashElem data in a Hash table element using a key.
Definition: hash.c:378
void mutt_score_message(struct Mailbox *m, struct Email *e, bool upd_mbox)
Apply scoring to an email.
Definition: score.c:174
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
char * real_subj
Offset of the real subject.
Definition: envelope.h:67
bool changed
Email has been edited.
Definition: email.h:48
void mutt_label_hash_add(struct Mailbox *m, struct Email *e)
Add a message&#39;s labels to the Hash Table.
Definition: mutt_header.c:371
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:386
Email list was changed.
Definition: mailbox.h:171
void mutt_label_hash_remove(struct Mailbox *m, struct Email *e)
Remove a message&#39;s labels from the Hash Table.
Definition: mutt_header.c:384
Container for Accounts, Notifications.
Definition: neomutt.h:35
Mailbox was closed.
Definition: mailbox.h:170
struct Context * ctx_new(void)
Create a new Context.
Definition: context.c:71
int vcount
The number of virtual messages.
Definition: mailbox.h:102
The body of an email.
Definition: body.h:34
Hundreds of global variables to back the user variables.
unsigned char changed
Changed fields, e.g. MUTT_ENV_CHANGED_SUBJECT.
Definition: envelope.h:88
Assorted sorting methods.
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:42
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:41
bool tagged
Email is tagged.
Definition: email.h:44
bool read
Email is read.
Definition: email.h:51
char * message_id
Message ID.
Definition: envelope.h:69
struct Mailbox * mailbox
Definition: context.h:51
API for mailboxes.
bool old
Email is seen, but unread.
Definition: email.h:50
struct Envelope * env
Envelope information.
Definition: email.h:89
Convenience wrapper for the core headers.
struct Notify * notify
Notifications handler.
Definition: context.h:52
bool superseded
Got superseded?
Definition: email.h:53
bool limited
Is this message in a limited view?
Definition: email.h:74
bool message_is_visible(struct Context *ctx, struct Email *e)
Is a message in the index within limit.
Definition: context.c:335
void * global_data
Data from notify_observer_add()
Definition: observer.h:44
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
bool quasi_deleted
Deleted from neomutt, but not modified on disk.
Definition: email.h:47
off_t vsize
Definition: context.h:39
Email list needs resorting.
Definition: mailbox.h:172
struct Notify * notify_new(void)
Create a new notifications handler.
Definition: notify.c:49
struct Hash * thread_hash
Hash table for threading.
Definition: context.h:44
bool active
Message is not to be removed.
Definition: email.h:59
static void ctx_cleanup(struct Context *ctx)
Release memory and initialize a Context object.
Definition: context.c:85
void mutt_sort_headers(struct Context *ctx, bool init)
Sort emails by their headers.
Definition: sort.c:364
Create/manipulate threading in emails.
void ctx_update(struct Context *ctx)
Update the Context&#39;s message counts.
Definition: context.c:105
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:81
WHERE bool C_MaildirTrash
Config: Use the maildir &#39;trashed&#39; flag, rather than deleting.
Definition: globals.h:237
struct PatternList * limit_pattern
Compiled limit pattern.
Definition: context.h:41
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition: pattern.c:1383
API for encryption/signing of emails.
&#39;MH&#39; Mailbox type
Definition: mailbox.h:50
Notification API.
Definition: notify.c:39
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:97
int vnum
Virtual message number.
Definition: email.h:87
struct Notify * notify
Notifications handler.
Definition: neomutt.h:37
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
struct Hash * mutt_make_id_hash(struct Mailbox *m)
Create a Hash Table for message-ids.
Definition: mutt_thread.c:1456
void mutt_clear_threads(struct Context *ctx)
Clear the threading of message in a mailbox.
Definition: mutt_thread.c:601
Routines for adding user scores to emails.
The Context is about to be destroyed.
Definition: context.h:69
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
int * v2r
Mapping from virtual to real msgno.
Definition: mailbox.h:101
Context has changed.
Definition: notify_type.h:35
bool flagged
Marked important?
Definition: email.h:43
int msg_new
Number of new messages.
Definition: mailbox.h:95
struct Hash * subj_hash
Hash table by subject.
Definition: mailbox.h:128
bool deleted
Email is deleted.
Definition: email.h:45
struct Email * email
Email in the list.
Definition: email.h:116
#define FREE(x)
Definition: memory.h:40
Mailbox has changed.
Definition: notify_type.h:38
WHERE bool C_Score
Config: Use message scoring.
Definition: globals.h:247
bool notify_observer_remove(struct Notify *notify, observer_t callback, void *global_data)
Remove an observer from an object.
Definition: notify.c:185
void notify_set_parent(struct Notify *notify, struct Notify *parent)
Set the parent notification handler.
Definition: notify.c:82
List of Emails.
Definition: email.h:114
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
void ctx_free(struct Context **ptr)
Free a Context.
Definition: context.c:48
int mx_msg_padding_size(struct Mailbox *m)
Bytes of padding between messages - Wrapper for MxOps::msg_padding_size()
Definition: mx.c:1528
struct Notify * notify
Notifications handler.
Definition: mailbox.h:139
long hdr_offset
Offset in stream where the headers begin.
Definition: body.h:42
An Event that happened to an Context.
Definition: context.h:58
void mailbox_size_sub(struct Mailbox *m, const struct Email *e)
Subtract an email&#39;s size from the total size of a Mailbox.
Definition: mailbox.c:193
int el_add_tagged(struct EmailList *el, struct Context *ctx, struct Email *e, bool use_tagged)
Get a list of the tagged Emails.
Definition: context.c:365
Convenience wrapper for the library headers.
void mutt_hash_free(struct Hash **ptr)
Free a hash table.
Definition: hash.c:471
struct HashElem * mutt_hash_insert(struct Hash *table, const char *strkey, void *data)
Add a new element to the Hash table (with string keys)
Definition: hash.c:351
Match patterns to emails.
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
char * pattern
Limit pattern string.
Definition: context.h:40
SecurityFlags crypt_query(struct Body *m)
Check out the type of encryption used.
Definition: crypt.c:700
struct Hash * id_hash
Hash table by msg id.
Definition: mailbox.h:127
struct Email * last_tag
Last tagged msg (used to link threads)
Definition: context.h:42
int msgno
Number displayed to the user.
Definition: email.h:86
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:137