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