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