NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
flags.c
Go to the documentation of this file.
1
26
32
33#include "config.h"
34#include <stdbool.h>
35#include <stdio.h>
36#include "mutt/lib.h"
37#include "config/lib.h"
38#include "email/lib.h"
39#include "core/lib.h"
40#include "gui/lib.h"
41#include "mutt.h"
42#include "color/lib.h"
43#include "index/lib.h"
44#include "key/lib.h"
45#include "mutt_thread.h"
46#include "protos.h"
47
56void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag,
57 bool bf, bool upd_mbox)
58{
59 if (!m || !e)
60 return;
61
62 bool changed = e->changed;
63 int deleted = m->msg_deleted;
64 int tagged = m->msg_tagged;
65 int flagged = m->msg_flagged;
66 int update = false;
67
68 if (m->readonly && (flag != MUTT_TAG))
69 return; /* don't modify anything if we are read-only */
70
71 switch (flag)
72 {
73 case MUTT_DELETE:
74 {
75 if (!(m->rights & MUTT_ACL_DELETE))
76 return;
77
78 if (bf)
79 {
80 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
81 if (!e->deleted && !m->readonly && (!e->flagged || !c_flag_safe))
82 {
83 e->deleted = true;
84 update = true;
85 if (upd_mbox)
86 m->msg_deleted++;
87 /* deleted messages aren't treated as changed elsewhere so that the
88 * purge-on-sync option works correctly. This isn't applicable here */
89 if (m->type == MUTT_IMAP)
90 {
91 e->changed = true;
92 if (upd_mbox)
93 m->changed = true;
94 }
95 }
96 }
97 else if (e->deleted)
98 {
99 e->deleted = false;
100 update = true;
101 if (upd_mbox)
102 m->msg_deleted--;
103 /* see my comment above */
104 if (m->type == MUTT_IMAP)
105 {
106 e->changed = true;
107 if (upd_mbox)
108 m->changed = true;
109 }
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 {
133 e->purge = false;
134 }
135 break;
136 }
137 case MUTT_NEW:
138 {
139 if (!(m->rights & MUTT_ACL_SEEN))
140 return;
141
142 if (bf)
143 {
144 if (e->read || e->old)
145 {
146 update = true;
147 e->old = false;
148 if (upd_mbox)
149 m->msg_new++;
150 if (e->read)
151 {
152 e->read = false;
153 if (upd_mbox)
154 m->msg_unread++;
155 }
156 e->changed = true;
157 if (upd_mbox)
158 m->changed = true;
159 }
160 }
161 else if (!e->read)
162 {
163 update = true;
164 if (!e->old)
165 if (upd_mbox)
166 m->msg_new--;
167 e->read = true;
168 if (upd_mbox)
169 m->msg_unread--;
170 e->changed = true;
171 if (upd_mbox)
172 m->changed = true;
173 }
174 break;
175 }
176 case MUTT_OLD:
177 {
178 if (!(m->rights & MUTT_ACL_SEEN))
179 return;
180
181 if (bf)
182 {
183 if (!e->old)
184 {
185 update = true;
186 e->old = true;
187 if (!e->read)
188 if (upd_mbox)
189 m->msg_new--;
190 e->changed = true;
191 if (upd_mbox)
192 m->changed = true;
193 }
194 }
195 else if (e->old)
196 {
197 update = true;
198 e->old = false;
199 if (!e->read)
200 if (upd_mbox)
201 m->msg_new++;
202 e->changed = true;
203 if (upd_mbox)
204 m->changed = true;
205 }
206 break;
207 }
208 case MUTT_READ:
209 {
210 if (!(m->rights & MUTT_ACL_SEEN))
211 return;
212
213 if (bf)
214 {
215 if (!e->read)
216 {
217 update = true;
218 e->read = true;
219 if (upd_mbox)
220 m->msg_unread--;
221 if (!e->old)
222 if (upd_mbox)
223 m->msg_new--;
224 e->changed = true;
225 if (upd_mbox)
226 m->changed = true;
227 }
228 }
229 else if (e->read)
230 {
231 update = true;
232 e->read = false;
233 if (upd_mbox)
234 m->msg_unread++;
235 if (!e->old)
236 if (upd_mbox)
237 m->msg_new++;
238 e->changed = true;
239 if (upd_mbox)
240 m->changed = true;
241 }
242 break;
243 }
244 case MUTT_REPLIED:
245 {
246 if (!(m->rights & MUTT_ACL_WRITE))
247 return;
248
249 if (bf)
250 {
251 if (!e->replied)
252 {
253 update = true;
254 e->replied = true;
255 if (!e->read)
256 {
257 e->read = true;
258 if (upd_mbox)
259 m->msg_unread--;
260 if (!e->old)
261 if (upd_mbox)
262 m->msg_new--;
263 }
264 e->changed = true;
265 if (upd_mbox)
266 m->changed = true;
267 }
268 }
269 else if (e->replied)
270 {
271 update = true;
272 e->replied = false;
273 e->changed = true;
274 if (upd_mbox)
275 m->changed = true;
276 }
277 break;
278 }
279 case MUTT_FLAG:
280 {
281 if (!(m->rights & MUTT_ACL_WRITE))
282 return;
283
284 if (bf)
285 {
286 if (!e->flagged)
287 {
288 update = true;
289 e->flagged = bf;
290 if (upd_mbox)
291 m->msg_flagged++;
292 e->changed = true;
293 if (upd_mbox)
294 m->changed = true;
295 }
296 }
297 else if (e->flagged)
298 {
299 update = true;
300 e->flagged = false;
301 if (upd_mbox)
302 m->msg_flagged--;
303 e->changed = true;
304 if (upd_mbox)
305 m->changed = true;
306 }
307 break;
308 }
309 case MUTT_TAG:
310 {
311 if (bf)
312 {
313 if (!e->tagged)
314 {
315 update = true;
316 e->tagged = true;
317 if (upd_mbox)
318 m->msg_tagged++;
319 }
320 }
321 else if (e->tagged)
322 {
323 update = true;
324 e->tagged = false;
325 if (upd_mbox)
326 m->msg_tagged--;
327 }
328 break;
329 }
330 default:
331 {
332 break;
333 }
334 }
335
336 if (update)
337 {
338 email_set_color(m, e);
339 struct EventMailbox ev_m = { m };
341 }
342
343 /* if the message status has changed, we need to invalidate the cached
344 * search results so that any future search will match the current status
345 * of this message and not what it was at the time it was last searched. */
346 if (e->searched && ((changed != e->changed) || (deleted != m->msg_deleted) ||
347 (tagged != m->msg_tagged) || (flagged != m->msg_flagged)))
348 {
349 e->searched = false;
350 }
351}
352
360void mutt_emails_set_flag(struct Mailbox *m, struct EmailArray *ea,
361 enum MessageType flag, bool bf)
362{
363 if (!m || !ea || ARRAY_EMPTY(ea))
364 return;
365
366 struct Email **ep = NULL;
367 ARRAY_FOREACH(ep, ea)
368 {
369 struct Email *e = *ep;
370 mutt_set_flag(m, e, flag, bf, true);
371 }
372}
373
384int mutt_thread_set_flag(struct Mailbox *m, struct Email *e,
385 enum MessageType flag, bool bf, bool subthread)
386{
387 struct MuttThread *start = NULL;
388 struct MuttThread *cur = e->thread;
389
390 if (!mutt_using_threads())
391 {
392 mutt_error(_("Threading is not enabled"));
393 return -1;
394 }
395
396 if (!subthread)
397 while (cur->parent)
398 cur = cur->parent;
399
400 start = cur;
401
402 if (cur->message && (cur != e->thread))
403 mutt_set_flag(m, cur->message, flag, bf, true);
404
405 cur = cur->child;
406 if (!cur)
407 goto done;
408
409 while (true)
410 {
411 if (cur->message && (cur != e->thread))
412 mutt_set_flag(m, cur->message, flag, bf, true);
413
414 if (cur->child)
415 {
416 cur = cur->child;
417 }
418 else if (cur->next)
419 {
420 cur = cur->next;
421 }
422 else
423 {
424 while (!cur->next)
425 {
426 cur = cur->parent;
427 if (cur == start)
428 goto done;
429 }
430 cur = cur->next;
431 }
432 }
433done:
434 cur = e->thread;
435 if (cur->message)
436 mutt_set_flag(m, cur->message, flag, bf, true);
437 return 0;
438}
439
453int mw_change_flag(struct Mailbox *m, struct EmailArray *ea, bool bf)
454{
455 if (!m || !ea || ARRAY_EMPTY(ea))
456 return -1;
457
458 // blank window (0, 0)
459 struct MuttWindow *win = msgwin_new(true);
460 if (!win)
461 return -1;
462
463 char prompt[256] = { 0 };
464 snprintf(prompt, sizeof(prompt),
465 "%s? (D/N/O/r/*/!): ", bf ? _("Set flag") : _("Clear flag"));
466 msgwin_set_text(win, prompt, MT_COLOR_PROMPT);
467
469 struct MuttWindow *old_focus = window_set_focus(win);
470 window_redraw(win);
471
472 struct KeyEvent event = { 0, OP_NULL };
473 do
474 {
475 window_redraw(NULL);
476 event = mutt_getch(GETCH_NO_FLAGS);
477 } while ((event.op == OP_TIMEOUT) || (event.op == OP_REPAINT));
478
479 win = msgcont_pop_window();
480 window_set_focus(old_focus);
481 mutt_window_free(&win);
482
483 if (event.op == OP_ABORT)
484 return -1;
485
486 enum MessageType flag = MUTT_NONE;
487 switch (event.ch)
488 {
489 case 'd':
490 case 'D':
491 if (!bf)
493 flag = MUTT_DELETE;
494 break;
495
496 case 'N':
497 case 'n':
498 flag = MUTT_NEW;
499 break;
500
501 case 'o':
502 case 'O':
503 mutt_emails_set_flag(m, ea, MUTT_READ, !bf);
504 flag = MUTT_OLD;
505 break;
506
507 case 'r':
508 case 'R':
509 flag = MUTT_REPLIED;
510 break;
511
512 case '*':
513 flag = MUTT_TAG;
514 break;
515
516 case '!':
517 flag = MUTT_FLAG;
518 break;
519
520 default:
521 mutt_beep(false);
522 return -1;
523 }
524
525 mutt_emails_set_flag(m, ea, flag, bf);
526 return 0;
527}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:214
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
Color and attribute parsing.
@ MT_COLOR_PROMPT
Question/user input.
Definition color.h:57
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.
@ NT_MAILBOX_CHANGE
Mailbox has been changed.
Definition mailbox.h:185
#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
void mutt_beep(bool force)
Irritate the user.
Definition curs_lib.c:69
void email_set_color(struct Mailbox *m, struct Email *e)
Select an Index colour for an Email.
Definition dlg_index.c:1405
Structs that make up an email.
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:56
void mutt_emails_set_flag(struct Mailbox *m, struct EmailArray *ea, enum MessageType flag, bool bf)
Set flag on messages.
Definition flags.c:360
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:384
struct KeyEvent mutt_getch(GetChFlags flags)
Read a character from the input buffer.
Definition get.c:210
int mw_change_flag(struct Mailbox *m, struct EmailArray *ea, bool bf)
Change the flag on a Message -.
Definition flags.c:453
#define mutt_error(...)
Definition logging2.h:93
Convenience wrapper for the gui headers.
GUI manage the main index (list of emails)
Manage keymappings.
#define GETCH_NO_FLAGS
No flags are set.
Definition lib.h:53
void msgcont_push_window(struct MuttWindow *win)
Add a window to the Container Stack.
Definition msgcont.c:93
struct MuttWindow * msgcont_pop_window(void)
Remove the last Window from the Container Stack.
Definition msgcont.c:57
struct MuttWindow * msgwin_new(bool interactive)
Create the Message Window.
Definition msgwin.c:370
void msgwin_set_text(struct MuttWindow *win, const char *text, enum ColorId color)
Set the text for the Message Window.
Definition msgwin.c:483
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:173
Many unsorted constants and some structs.
MessageType
To set flags or match patterns.
Definition mutt.h:67
@ MUTT_READ
Messages that have been read.
Definition mutt.h:73
@ MUTT_OLD
Old messages.
Definition mutt.h:71
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition mutt.h:77
@ MUTT_NONE
No messages.
Definition mutt.h:69
@ MUTT_TAG
Tagged messages.
Definition mutt.h:80
@ MUTT_FLAG
Flagged messages.
Definition mutt.h:79
@ MUTT_DELETE
Messages to be deleted.
Definition mutt.h:75
@ MUTT_NEW
New messages.
Definition mutt.h:70
@ MUTT_REPLIED
Messages that have been replied to.
Definition mutt.h:72
Create/manipulate threading in emails.
#define mutt_using_threads()
void window_redraw(struct MuttWindow *win)
Reflow, recalc and repaint a tree of Windows.
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
struct MuttWindow * window_set_focus(struct MuttWindow *win)
Set the Window focus.
@ NT_MAILBOX
Mailbox has changed, NotifyMailbox, EventMailbox.
Definition notify_type.h:49
#define OP_TIMEOUT
1 second with no events
Definition opcodes.h:35
#define OP_REPAINT
Repaint is needed.
Definition opcodes.h:34
#define OP_ABORT
$abort_key pressed (Ctrl-G)
Definition opcodes.h:36
Prototypes for many functions.
The envelope/body of an email.
Definition email.h:39
bool searched
Email has been searched.
Definition email.h:105
bool read
Email is read.
Definition email.h:50
bool purge
Skip trash folder when deleting.
Definition email.h:79
bool old
Email is seen, but unread.
Definition email.h:49
bool changed
Email has been edited.
Definition email.h:77
bool flagged
Marked important?
Definition email.h:47
bool replied
Email has been replied to.
Definition email.h:51
bool deleted
Email is deleted.
Definition email.h:78
bool trash
Message is marked as trashed on disk (used by the maildir_trash option)
Definition email.h:53
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:199
An event such as a keypress.
Definition lib.h:82
int op
Function opcode, e.g. OP_HELP.
Definition lib.h:84
int ch
Raw key pressed.
Definition lib.h:83
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:119
enum MailboxType type
Mailbox type.
Definition mailbox.h:102
struct Notify * notify
Notifications: NotifyMailbox, EventMailbox.
Definition mailbox.h:145
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:116
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:34
struct MuttThread * parent
Parent of this Thread.
Definition thread.h:44
struct MuttThread * child
Child of this Thread.
Definition thread.h:45
struct Email * message
Email this Thread refers to.
Definition thread.h:49
struct MuttThread * next
Next sibling Thread.
Definition thread.h:46
Container for Accounts, Notifications.
Definition neomutt.h:43
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:47