NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
flags.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <stddef.h>
31 #include <stdbool.h>
32 #include "mutt/lib.h"
33 #include "config/lib.h"
34 #include "email/lib.h"
35 #include "core/lib.h"
36 #include "gui/lib.h"
37 #include "mutt.h"
38 #include "index/lib.h"
39 #include "keymap.h"
40 #include "mutt_thread.h"
41 #include "protos.h"
42 
51 void mutt_set_flag_update(struct Mailbox *m, struct Email *e,
52  enum MessageType flag, bool bf, bool upd_mbox)
53 {
54  if (!m || !e)
55  return;
56 
57  bool changed = e->changed;
58  int deleted = m->msg_deleted;
59  int tagged = m->msg_tagged;
60  int flagged = m->msg_flagged;
61  int update = false;
62 
63  if (m->readonly && (flag != MUTT_TAG))
64  return; /* don't modify anything if we are read-only */
65 
66  switch (flag)
67  {
68  case MUTT_DELETE:
69 
70  if (!(m->rights & MUTT_ACL_DELETE))
71  return;
72 
73  if (bf)
74  {
75  const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
76  if (!e->deleted && !m->readonly && (!e->flagged || !c_flag_safe))
77  {
78  e->deleted = true;
79  update = true;
80  if (upd_mbox)
81  m->msg_deleted++;
82 #ifdef USE_IMAP
83  /* deleted messages aren't treated as changed elsewhere so that the
84  * purge-on-sync option works correctly. This isn't applicable here */
85  if (m->type == MUTT_IMAP)
86  {
87  e->changed = true;
88  if (upd_mbox)
89  m->changed = true;
90  }
91 #endif
92  }
93  }
94  else if (e->deleted)
95  {
96  e->deleted = false;
97  update = true;
98  if (upd_mbox)
99  m->msg_deleted--;
100 #ifdef USE_IMAP
101  /* see my comment above */
102  if (m->type == MUTT_IMAP)
103  {
104  e->changed = true;
105  if (upd_mbox)
106  m->changed = true;
107  }
108 #endif
109  /* If the user undeletes a message which is marked as
110  * "trash" in the maildir folder on disk, the folder has
111  * been changed, and is marked accordingly. However, we do
112  * _not_ mark the message itself changed, because trashing
113  * is checked in specific code in the maildir folder
114  * driver. */
115  if ((m->type == MUTT_MAILDIR) && upd_mbox && e->trash)
116  m->changed = true;
117  }
118  break;
119 
120  case MUTT_PURGE:
121 
122  if (!(m->rights & MUTT_ACL_DELETE))
123  return;
124 
125  if (bf)
126  {
127  if (!e->purge && !m->readonly)
128  e->purge = true;
129  }
130  else if (e->purge)
131  e->purge = false;
132  break;
133 
134  case MUTT_NEW:
135 
136  if (!(m->rights & MUTT_ACL_SEEN))
137  return;
138 
139  if (bf)
140  {
141  if (e->read || e->old)
142  {
143  update = true;
144  e->old = false;
145  if (upd_mbox)
146  m->msg_new++;
147  if (e->read)
148  {
149  e->read = false;
150  if (upd_mbox)
151  m->msg_unread++;
152  }
153  e->changed = true;
154  if (upd_mbox)
155  m->changed = true;
156  }
157  }
158  else if (!e->read)
159  {
160  update = true;
161  if (!e->old)
162  if (upd_mbox)
163  m->msg_new--;
164  e->read = true;
165  if (upd_mbox)
166  m->msg_unread--;
167  e->changed = true;
168  if (upd_mbox)
169  m->changed = true;
170  }
171  break;
172 
173  case MUTT_OLD:
174 
175  if (!(m->rights & MUTT_ACL_SEEN))
176  return;
177 
178  if (bf)
179  {
180  if (!e->old)
181  {
182  update = true;
183  e->old = true;
184  if (!e->read)
185  if (upd_mbox)
186  m->msg_new--;
187  e->changed = true;
188  if (upd_mbox)
189  m->changed = true;
190  }
191  }
192  else if (e->old)
193  {
194  update = true;
195  e->old = false;
196  if (!e->read)
197  if (upd_mbox)
198  m->msg_new++;
199  e->changed = true;
200  if (upd_mbox)
201  m->changed = true;
202  }
203  break;
204 
205  case MUTT_READ:
206 
207  if (!(m->rights & MUTT_ACL_SEEN))
208  return;
209 
210  if (bf)
211  {
212  if (!e->read)
213  {
214  update = true;
215  e->read = true;
216  if (upd_mbox)
217  m->msg_unread--;
218  if (!e->old)
219  if (upd_mbox)
220  m->msg_new--;
221  e->changed = true;
222  if (upd_mbox)
223  m->changed = true;
224  }
225  }
226  else if (e->read)
227  {
228  update = true;
229  e->read = false;
230  if (upd_mbox)
231  m->msg_unread++;
232  if (!e->old)
233  if (upd_mbox)
234  m->msg_new++;
235  e->changed = true;
236  if (upd_mbox)
237  m->changed = true;
238  }
239  break;
240 
241  case MUTT_REPLIED:
242 
243  if (!(m->rights & MUTT_ACL_WRITE))
244  return;
245 
246  if (bf)
247  {
248  if (!e->replied)
249  {
250  update = true;
251  e->replied = true;
252  if (!e->read)
253  {
254  e->read = true;
255  if (upd_mbox)
256  m->msg_unread--;
257  if (!e->old)
258  if (upd_mbox)
259  m->msg_new--;
260  }
261  e->changed = true;
262  if (upd_mbox)
263  m->changed = true;
264  }
265  }
266  else if (e->replied)
267  {
268  update = true;
269  e->replied = false;
270  e->changed = true;
271  if (upd_mbox)
272  m->changed = true;
273  }
274  break;
275 
276  case MUTT_FLAG:
277 
278  if (!(m->rights & MUTT_ACL_WRITE))
279  return;
280 
281  if (bf)
282  {
283  if (!e->flagged)
284  {
285  update = true;
286  e->flagged = bf;
287  if (upd_mbox)
288  m->msg_flagged++;
289  e->changed = true;
290  if (upd_mbox)
291  m->changed = true;
292  }
293  }
294  else if (e->flagged)
295  {
296  update = true;
297  e->flagged = false;
298  if (upd_mbox)
299  m->msg_flagged--;
300  e->changed = true;
301  if (upd_mbox)
302  m->changed = true;
303  }
304  break;
305 
306  case MUTT_TAG:
307  if (bf)
308  {
309  if (!e->tagged)
310  {
311  update = true;
312  e->tagged = true;
313  if (upd_mbox)
314  m->msg_tagged++;
315  }
316  }
317  else if (e->tagged)
318  {
319  update = true;
320  e->tagged = false;
321  if (upd_mbox)
322  m->msg_tagged--;
323  }
324  break;
325 
326  default:
327  break;
328  }
329 
330  if (update)
331  {
332  mutt_set_header_color(m, e);
333  }
334 
335  /* if the message status has changed, we need to invalidate the cached
336  * search results so that any future search will match the current status
337  * of this message and not what it was at the time it was last searched. */
338  if (e->searched && ((changed != e->changed) || (deleted != m->msg_deleted) ||
339  (tagged != m->msg_tagged) || (flagged != m->msg_flagged)))
340  {
341  e->searched = false;
342  }
343 }
344 
352 void mutt_emails_set_flag(struct Mailbox *m, struct EmailList *el,
353  enum MessageType flag, bool bf)
354 {
355  if (!m || !el || STAILQ_EMPTY(el))
356  return;
357 
358  struct EmailNode *en = NULL;
359  STAILQ_FOREACH(en, el, entries)
360  {
361  mutt_set_flag(m, en->email, flag, bf);
362  }
363 }
364 
375 int mutt_thread_set_flag(struct Mailbox *m, struct Email *e,
376  enum MessageType flag, bool bf, bool subthread)
377 {
378  struct MuttThread *start = NULL;
379  struct MuttThread *cur = e->thread;
380 
381  if (!mutt_using_threads())
382  {
383  mutt_error(_("Threading is not enabled"));
384  return -1;
385  }
386 
387  if (!subthread)
388  while (cur->parent)
389  cur = cur->parent;
390  start = cur;
391 
392  if (cur->message && (cur != e->thread))
393  mutt_set_flag(m, cur->message, flag, bf);
394 
395  cur = cur->child;
396  if (!cur)
397  goto done;
398 
399  while (true)
400  {
401  if (cur->message && (cur != e->thread))
402  mutt_set_flag(m, cur->message, flag, bf);
403 
404  if (cur->child)
405  cur = cur->child;
406  else if (cur->next)
407  cur = cur->next;
408  else
409  {
410  while (!cur->next)
411  {
412  cur = cur->parent;
413  if (cur == start)
414  goto done;
415  }
416  cur = cur->next;
417  }
418  }
419 done:
420  cur = e->thread;
421  if (cur->message)
422  mutt_set_flag(m, cur->message, flag, bf);
423  return 0;
424 }
425 
434 int mutt_change_flag(struct Mailbox *m, struct EmailList *el, bool bf)
435 {
436  struct MuttWindow *win = msgwin_get_window();
437  if (!win)
438  return -1;
439 
440  if (!m || !el || STAILQ_EMPTY(el))
441  return -1;
442 
443  enum MessageType flag = MUTT_NONE;
444  struct KeyEvent event;
445 
446  struct MuttWindow *old_focus = window_set_focus(win);
447 
448  mutt_window_mvprintw(win, 0, 0, "%s? (D/N/O/r/*/!): ", bf ? _("Set flag") : _("Clear flag"));
450  window_redraw(NULL);
451 
452  do
453  {
454  event = mutt_getch();
455  } while (event.ch == -2); // Timeout
456 
458  window_set_focus(old_focus);
459 
460  if (event.ch < 0) // SIGINT, Abort key (Ctrl-G)
461  return -1;
462 
463  switch (event.ch)
464  {
465  case 'd':
466  case 'D':
467  if (!bf)
468  mutt_emails_set_flag(m, el, MUTT_PURGE, bf);
469  flag = MUTT_DELETE;
470  break;
471 
472  case 'N':
473  case 'n':
474  flag = MUTT_NEW;
475  break;
476 
477  case 'o':
478  case 'O':
479  mutt_emails_set_flag(m, el, MUTT_READ, !bf);
480  flag = MUTT_OLD;
481  break;
482 
483  case 'r':
484  case 'R':
485  flag = MUTT_REPLIED;
486  break;
487 
488  case '*':
489  flag = MUTT_TAG;
490  break;
491 
492  case '!':
493  flag = MUTT_FLAG;
494  break;
495 
496  default:
497  mutt_beep(false);
498  return -1;
499  }
500 
501  mutt_emails_set_flag(m, el, flag, bf);
502  return 0;
503 }
Convenience wrapper for the gui headers.
struct MuttThread * next
Next sibling Thread.
Definition: thread.h:47
Manage keymappings.
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:66
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
The envelope/body of an email.
Definition: email.h:37
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.
#define mutt_error(...)
Definition: logging.h:88
void mutt_emails_set_flag(struct Mailbox *m, struct EmailList *el, enum MessageType flag, bool bf)
Set flag on messages.
Definition: flags.c:352
int msg_flagged
Number of flagged messages.
Definition: mailbox.h:93
struct MuttThread * thread
Thread of Emails.
Definition: email.h:95
void mutt_set_header_color(struct Mailbox *m, struct Email *e)
Select a colour for a message.
Definition: dlg_index.c:1382
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:259
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
Definition: mutt_window.c:680
Flagged messages.
Definition: mutt.h:98
#define _(a)
Definition: message.h:28
bool changed
Email has been edited.
Definition: email.h:48
No messages.
Definition: mutt.h:88
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
Definition: mutt_window.c:632
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
int ch
raw key pressed
Definition: keymap.h:66
Messages to be purged (bypass trash)
Definition: mutt.h:96
bool searched
Email has been searched.
Definition: email.h:67
void msgwin_clear_text(void)
Clear the text in the Message Window.
Definition: msgwin.c:242
Container for Accounts, Notifications.
Definition: neomutt.h:36
#define MUTT_ACL_DELETE
Delete a message.
Definition: mailbox.h:66
Messages that have been replied to.
Definition: mutt.h:91
Convenience wrapper for the config headers.
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:105
bool tagged
Email is tagged.
Definition: email.h:44
bool read
Email is read.
Definition: email.h:51
void mutt_set_flag_update(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition: flags.c:51
MessageType
To set flags or match patterns.
Definition: mutt.h:85
Many unsorted constants and some structs.
bool old
Email is seen, but unread.
Definition: email.h:50
bool readonly
Don&#39;t allow changes to the mailbox.
Definition: mailbox.h:119
struct MuttWindow * msgwin_get_window(void)
Get the Message Window pointer.
Definition: msgwin.c:253
Convenience wrapper for the core headers.
#define MUTT_ACL_WRITE
Write to a message (for flagging or linking threads)
Definition: mailbox.h:74
&#39;Maildir&#39; Mailbox type
Definition: mailbox.h:51
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition: email.h:60
Old messages.
Definition: mutt.h:90
struct MuttThread * child
Child of this Thread.
Definition: thread.h:46
Prototypes for many functions.
Create/manipulate threading in emails.
Messages to be deleted.
Definition: mutt.h:94
A mailbox.
Definition: mailbox.h:81
Tagged messages.
Definition: mutt.h:99
New messages.
Definition: mutt.h:89
Messages that have been read.
Definition: mutt.h:92
bool purge
Skip trash folder when deleting.
Definition: email.h:46
int msg_tagged
How many messages are tagged?
Definition: mailbox.h:97
An event such as a keypress.
Definition: keymap.h:64
AclFlags rights
ACL bits, see AclFlags.
Definition: mailbox.h:121
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
struct KeyEvent mutt_getch(void)
Read a character from the input buffer.
Definition: curs_lib.c:196
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
#define mutt_using_threads()
Definition: mutt_thread.h:95
An Email conversation.
Definition: thread.h:34
bool flagged
Marked important?
Definition: email.h:43
int msg_new
Number of new messages.
Definition: mailbox.h:95
bool deleted
Email is deleted.
Definition: email.h:45
struct Email * email
Email in the list.
Definition: email.h:131
bool replied
Email has been replied to.
Definition: email.h:54
#define MUTT_ACL_SEEN
Change the &#39;seen&#39; status of a message.
Definition: mailbox.h:73
#define STAILQ_EMPTY(head)
Definition: queue.h:348
int mutt_window_mvprintw(struct MuttWindow *win, int col, int row, const char *fmt,...)
Move the cursor and write a formatted string to a Window.
Definition: mutt_window.c:343
List of Emails.
Definition: email.h:129
bool changed
Mailbox has been modified.
Definition: mailbox.h:114
int mutt_change_flag(struct Mailbox *m, struct EmailList *el, bool bf)
Change the flag on a Message.
Definition: flags.c:434
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Convenience wrapper for the library headers.
GUI manage the main index (list of emails)
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
int mutt_thread_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool subthread)
Set a flag on an entire thread.
Definition: flags.c:375