Thanks to visit codestin.com
Credit goes to code.neomutt.org

NeoMutt  2025-12-11-189-gceedb6
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
54void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag,
55 bool bf, bool upd_mbox)
56{
57 if (!m || !e)
58 return;
59
60 bool changed = e->changed;
61 int deleted = m->msg_deleted;
62 int tagged = m->msg_tagged;
63 int flagged = m->msg_flagged;
64 int update = false;
65
66 if (m->readonly && (flag != MUTT_TAG))
67 return; /* don't modify anything if we are read-only */
68
69 switch (flag)
70 {
71 case MUTT_DELETE:
72 {
73 if (!(m->rights & MUTT_ACL_DELETE))
74 return;
75
76 if (bf)
77 {
78 const bool c_flag_safe = cs_subset_bool(NeoMutt->sub, "flag_safe");
79 if (!e->deleted && !m->readonly && (!e->flagged || !c_flag_safe))
80 {
81 e->deleted = true;
82 update = true;
83 if (upd_mbox)
84 m->msg_deleted++;
85 /* deleted messages aren't treated as changed elsewhere so that the
86 * purge-on-sync option works correctly. This isn't applicable here */
87 if (m->type == MUTT_IMAP)
88 {
89 e->changed = true;
90 if (upd_mbox)
91 m->changed = true;
92 }
93 }
94 }
95 else if (e->deleted)
96 {
97 e->deleted = false;
98 update = true;
99 if (upd_mbox)
100 m->msg_deleted--;
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 /* If the user undeletes a message which is marked as
109 * "trash" in the maildir folder on disk, the folder has
110 * been changed, and is marked accordingly. However, we do
111 * _not_ mark the message itself changed, because trashing
112 * is checked in specific code in the maildir folder
113 * driver. */
114 if ((m->type == MUTT_MAILDIR) && upd_mbox && e->trash)
115 m->changed = true;
116 }
117 break;
118 }
119 case MUTT_PURGE:
120 {
121 if (!(m->rights & MUTT_ACL_DELETE))
122 return;
123
124 if (bf)
125 {
126 if (!e->purge && !m->readonly)
127 e->purge = true;
128 }
129 else if (e->purge)
130 {
131 e->purge = false;
132 }
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 {
309 if (bf)
310 {
311 if (!e->tagged)
312 {
313 update = true;
314 e->tagged = true;
315 if (upd_mbox)
316 m->msg_tagged++;
317 }
318 }
319 else if (e->tagged)
320 {
321 update = true;
322 e->tagged = false;
323 if (upd_mbox)
324 m->msg_tagged--;
325 }
326 break;
327 }
328 default:
329 {
330 break;
331 }
332 }
333
334 if (update)
335 {
336 email_set_color(m, e);
337 struct EventMailbox ev_m = { m };
339 }
340
341 /* if the message status has changed, we need to invalidate the cached
342 * search results so that any future search will match the current status
343 * of this message and not what it was at the time it was last searched. */
344 if (e->searched && ((changed != e->changed) || (deleted != m->msg_deleted) ||
345 (tagged != m->msg_tagged) || (flagged != m->msg_flagged)))
346 {
347 e->searched = false;
348 }
349}
350
358void mutt_emails_set_flag(struct Mailbox *m, struct EmailArray *ea,
359 enum MessageType flag, bool bf)
360{
361 if (!m || !ea || ARRAY_EMPTY(ea))
362 return;
363
364 struct Email **ep = NULL;
365 ARRAY_FOREACH(ep, ea)
366 {
367 struct Email *e = *ep;
368 mutt_set_flag(m, e, flag, bf, true);
369 }
370}
371
382int mutt_thread_set_flag(struct Mailbox *m, struct Email *e,
383 enum MessageType flag, bool bf, bool subthread)
384{
385 struct MuttThread *start = NULL;
386 struct MuttThread *cur = e->thread;
387
388 if (!mutt_using_threads())
389 {
390 mutt_error(_("Threading is not enabled"));
391 return -1;
392 }
393
394 if (!subthread)
395 while (cur->parent)
396 cur = cur->parent;
397
398 start = cur;
399
400 if (cur->message && (cur != e->thread))
401 mutt_set_flag(m, cur->message, flag, bf, true);
402
403 cur = cur->child;
404 if (!cur)
405 goto done;
406
407 while (true)
408 {
409 if (cur->message && (cur != e->thread))
410 mutt_set_flag(m, cur->message, flag, bf, true);
411
412 if (cur->child)
413 {
414 cur = cur->child;
415 }
416 else if (cur->next)
417 {
418 cur = cur->next;
419 }
420 else
421 {
422 while (!cur->next)
423 {
424 cur = cur->parent;
425 if (cur == start)
426 goto done;
427 }
428 cur = cur->next;
429 }
430 }
431done:
432 cur = e->thread;
433 if (cur->message)
434 mutt_set_flag(m, cur->message, flag, bf, true);
435 return 0;
436}
437
451int mw_change_flag(struct Mailbox *m, struct EmailArray *ea, bool bf)
452{
453 if (!m || !ea || ARRAY_EMPTY(ea))
454 return -1;
455
456 // blank window (0, 0)
457 struct MuttWindow *win = msgwin_new(true);
458 if (!win)
459 return -1;
460
461 char prompt[256] = { 0 };
462 snprintf(prompt, sizeof(prompt),
463 "%s? (D/N/O/r/*/!): ", bf ? _("Set flag") : _("Clear flag"));
464 msgwin_set_text(win, prompt, MT_COLOR_PROMPT);
465
467 struct MuttWindow *old_focus = window_set_focus(win);
468 window_redraw(win);
469
470 struct KeyEvent event = { 0, OP_NULL };
471 do
472 {
473 window_redraw(NULL);
474 event = mutt_getch(GETCH_NO_FLAGS);
475 } while ((event.op == OP_TIMEOUT) || (event.op == OP_REPAINT));
476
477 win = msgcont_pop_window();
478 window_set_focus(old_focus);
479 mutt_window_free(&win);
480
481 if (event.op == OP_ABORT)
482 return -1;
483
484 enum MessageType flag = MUTT_NONE;
485 switch (event.ch)
486 {
487 case 'd':
488 case 'D':
489 if (!bf)
491 flag = MUTT_DELETE;
492 break;
493
494 case 'N':
495 case 'n':
496 flag = MUTT_NEW;
497 break;
498
499 case 'o':
500 case 'O':
501 mutt_emails_set_flag(m, ea, MUTT_READ, !bf);
502 flag = MUTT_OLD;
503 break;
504
505 case 'r':
506 case 'R':
507 flag = MUTT_REPLIED;
508 break;
509
510 case '*':
511 flag = MUTT_TAG;
512 break;
513
514 case '!':
515 flag = MUTT_FLAG;
516 break;
517
518 default:
519 mutt_beep(false);
520 return -1;
521 }
522
523 mutt_emails_set_flag(m, ea, flag, bf);
524 return 0;
525}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#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:176
#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:68
void email_set_color(struct Mailbox *m, struct Email *e)
Select an Index colour for an Email.
Definition dlg_index.c:1404
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:54
void mutt_emails_set_flag(struct Mailbox *m, struct EmailArray *ea, enum MessageType flag, bool bf)
Set flag on messages.
Definition flags.c:358
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:382
struct KeyEvent mutt_getch(GetChFlags flags)
Read a character from the input buffer.
Definition get.c:201
#define GETCH_NO_FLAGS
No flags are set.
Definition get.h:34
int mw_change_flag(struct Mailbox *m, struct EmailArray *ea, bool bf)
Change the flag on a Message -.
Definition flags.c:451
#define mutt_error(...)
Definition logging2.h:94
Convenience wrapper for the gui headers.
#define mutt_using_threads()
Definition thread.h:113
GUI manage the main index (list of emails)
Manage keymappings.
void msgcont_push_window(struct MuttWindow *win)
Add a window to the Container Stack.
Definition msgcont.c:100
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:86
@ MUTT_READ
Messages that have been read.
Definition mutt.h:92
@ MUTT_OLD
Old messages.
Definition mutt.h:90
@ MUTT_PURGE
Messages to be purged (bypass trash)
Definition mutt.h:96
@ MUTT_NONE
No messages.
Definition mutt.h:88
@ MUTT_TAG
Tagged messages.
Definition mutt.h:99
@ MUTT_FLAG
Flagged messages.
Definition mutt.h:98
@ MUTT_DELETE
Messages to be deleted.
Definition mutt.h:94
@ MUTT_NEW
New messages.
Definition mutt.h:89
@ MUTT_REPLIED
Messages that have been replied to.
Definition mutt.h:91
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
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:190
An event such as a keypress.
Definition get.h:50
int op
Function opcode, e.g. OP_HELP.
Definition get.h:52
int ch
Raw key pressed.
Definition get.h:51
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:128
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:134