Simplify pop code further.
[apps/madmutt.git] / flags.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #include <lib-lib/lib-lib.h>
11
12 #include <lib-ui/curses.h>
13 #include <lib-ui/menu.h>
14 #include <lib-ui/sidebar.h>
15 #include <lib-mx/mx.h>
16
17 #include "mutt.h"
18 #include "sort.h"
19
20 #include <imap/imap_private.h>
21
22
23 void _mutt_set_flag (CONTEXT * ctx, HEADER * h, int flag, int bf, int upd_ctx)
24 {
25   int changed = h->changed;
26   int deleted = ctx->deleted;
27   int tagged = ctx->tagged;
28   int flagged = ctx->flagged;
29
30   if (ctx->readonly && flag != M_TAG)
31     return;                     /* don't modify anything if we are read-only */
32
33   switch (flag) {
34   case M_DELETE:
35
36     if (!mx_acl_check (ctx, ACL_DELETE))
37       return;
38
39     if (bf) {
40       if (!h->deleted && !ctx->readonly) {
41         h->deleted = 1;
42         if (upd_ctx)
43           ctx->deleted++;
44         /* deleted messages aren't treated as changed elsewhere so that the
45          * purge-on-sync option works correctly. This isn't applicable here */
46         if (ctx && ctx->magic == M_IMAP) {
47           h->changed = 1;
48           if (upd_ctx)
49             ctx->changed = 1;
50         }
51       }
52     }
53     else if (h->deleted) {
54       h->deleted = 0;
55       if (upd_ctx) {
56         ctx->deleted--;
57         if (h->appended)
58           ctx->appended--;
59       }
60       h->appended = 0;          /* when undeleting, also reset the appended flag */
61       /* see my comment above */
62       if (ctx->magic == M_IMAP) {
63         h->changed = 1;
64         if (upd_ctx)
65           ctx->changed = 1;
66       }
67       /* 
68        * If the user undeletes a message which is marked as
69        * "trash" in the maildir folder on disk, the folder has
70        * been changed, and is marked accordingly.  However, we do
71        * _not_ mark the message itself changed, because trashing
72        * is checked in specific code in the maildir folder
73        * driver. 
74        */
75       if (ctx->magic == M_MAILDIR && upd_ctx && h->trash)
76         ctx->changed = 1;
77     }
78     break;
79
80   case M_APPENDED:
81     if (bf) {
82       if (!h->appended) {
83         h->appended = 1;
84         if (upd_ctx)
85           ctx->appended++;
86       }
87     }
88     break;
89
90   case M_PURGED:
91     if (bf) {
92       if (!h->purged)
93         h->purged = 1;
94     }
95     else if (h->purged)
96       h->purged = 0;
97     break;
98
99   case M_NEW:
100
101     if (!mx_acl_check (ctx, ACL_SEEN))
102       return;
103
104     if (bf) {
105       if (h->read || h->old) {
106         h->old = 0;
107         if (upd_ctx)
108           ctx->new++;
109         if (h->read) {
110           h->read = 0;
111           if (upd_ctx)
112             ctx->unread++;
113         }
114         h->changed = 1;
115         if (upd_ctx)
116           ctx->changed = 1;
117       }
118     }
119     else if (!h->read) {
120       if (!h->old)
121         if (upd_ctx)
122           ctx->new--;
123       h->read = 1;
124       if (upd_ctx)
125         ctx->unread--;
126       h->changed = 1;
127       if (upd_ctx)
128         ctx->changed = 1;
129     }
130     break;
131
132   case M_OLD:
133
134     if (!mx_acl_check (ctx, ACL_SEEN))
135       return;
136
137     if (bf) {
138       if (!h->old) {
139         h->old = 1;
140         if (!h->read)
141           if (upd_ctx)
142             ctx->new--;
143         h->changed = 1;
144         if (upd_ctx)
145           ctx->changed = 1;
146       }
147     }
148     else if (h->old) {
149       h->old = 0;
150       if (!h->read)
151         if (upd_ctx)
152           ctx->new++;
153       h->changed = 1;
154       if (upd_ctx)
155         ctx->changed = 1;
156     }
157     break;
158
159   case M_READ:
160
161     if (!mx_acl_check (ctx, ACL_SEEN))
162       return;
163
164     if (bf) {
165       if (!h->read) {
166         h->read = 1;
167         if (upd_ctx)
168           ctx->unread--;
169         if (!h->old)
170           if (upd_ctx)
171             ctx->new--;
172         h->changed = 1;
173         if (upd_ctx)
174           ctx->changed = 1;
175       }
176     }
177     else if (h->read) {
178       h->read = 0;
179       if (upd_ctx)
180         ctx->unread++;
181       if (!h->old)
182         if (upd_ctx)
183           ctx->new++;
184       h->changed = 1;
185       if (upd_ctx)
186         ctx->changed = 1;
187     }
188     break;
189
190   case M_REPLIED:
191
192     if (!mx_acl_check (ctx, ACL_WRITE))
193       return;
194
195     if (bf) {
196       if (!h->replied) {
197         h->replied = 1;
198         if (!h->read) {
199           h->read = 1;
200           if (upd_ctx)
201             ctx->unread--;
202           if (!h->old)
203             if (upd_ctx)
204               ctx->new--;
205         }
206         h->changed = 1;
207         if (upd_ctx)
208           ctx->changed = 1;
209       }
210     }
211     else if (h->replied) {
212       h->replied = 0;
213       h->changed = 1;
214       if (upd_ctx)
215         ctx->changed = 1;
216     }
217     break;
218
219   case M_FLAG:
220
221     if (!mx_acl_check (ctx, ACL_WRITE))
222       return;
223
224     if (bf) {
225       if (!h->flagged) {
226         h->flagged = bf;
227         if (upd_ctx)
228           ctx->flagged++;
229         h->changed = 1;
230         if (upd_ctx)
231           ctx->changed = 1;
232       }
233     }
234     else if (h->flagged) {
235       h->flagged = 0;
236       if (upd_ctx)
237         ctx->flagged--;
238       h->changed = 1;
239       if (upd_ctx)
240         ctx->changed = 1;
241     }
242     break;
243
244   case M_TAG:
245     if (bf) {
246       if (!h->tagged) {
247         h->tagged = 1;
248         if (upd_ctx)
249           ctx->tagged++;
250       }
251     }
252     else if (h->tagged) {
253       h->tagged = 0;
254       if (upd_ctx)
255         ctx->tagged--;
256     }
257     break;
258   }
259
260   mutt_set_header_color (ctx, h);
261
262   /* if the message status has changed, we need to invalidate the cached
263    * search results so that any future search will match the current status
264    * of this message and not what it was at the time it was last searched.
265    */
266   if (h->searched && (changed != h->changed || deleted != ctx->deleted ||
267                       tagged != ctx->tagged || flagged != ctx->flagged))
268     h->searched = 0;
269   sidebar_draw ();
270 }
271
272 void mutt_tag_set_flag (int flag, int bf)
273 {
274   int j;
275
276   for (j = 0; j < Context->vcount; j++)
277     if (Context->hdrs[Context->v2r[j]]->tagged)
278       mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], flag, bf);
279 }
280 int mutt_thread_set_flag (HEADER * hdr, int flag, int bf, int subthread)
281 {
282   THREAD *start, *cur = hdr->thread;
283
284   if ((Sort & SORT_MASK) != SORT_THREADS) {
285     mutt_error _("Threading is not enabled.");
286
287     return (-1);
288   }
289
290   if (!subthread)
291     while (cur->parent)
292       cur = cur->parent;
293   start = cur;
294
295   if (cur->message)
296     mutt_set_flag (Context, cur->message, flag, bf);
297
298   if ((cur = cur->child) == NULL)
299     return (0);
300
301   for (;;) {
302     if (cur->message)
303       mutt_set_flag (Context, cur->message, flag, bf);
304
305     if (cur->child)
306       cur = cur->child;
307     else if (cur->next)
308       cur = cur->next;
309     else {
310       while (!cur->next) {
311         cur = cur->parent;
312         if (cur == start)
313           return (0);
314       }
315       cur = cur->next;
316     }
317   }
318   /* not reached */
319 }
320
321 int mutt_change_flag(HEADER * h, int bf)
322 {
323     static char const actions[] = {
324         ['d'] = M_DELETE,       ['D'] = M_DELETE,
325         ['n'] = M_NEW,          ['N'] = M_NEW,
326         ['o'] = M_OLD,          ['O'] = M_OLD,
327         ['r'] = M_REPLIED,      ['R'] = M_REPLIED,
328         ['*'] = M_TAG,
329         ['!'] = M_FLAG,
330     };
331
332     int c;
333
334     mvprintw(LINES - 1, 0, "%s? (D/N/O/r/*/!): ",
335              bf ? _("Set flag") : _("Clear flag"));
336     clrtoeol();
337
338     c = mutt_getch().ch;
339     if (c == -1) {
340         CLEARLINE (LINES - 1);
341         return (-1);
342     }
343
344     CLEARLINE (LINES - 1);
345
346     if (c < 0 || c > countof(actions) || !actions[c]) {
347         BEEP();
348         return -1;
349     }
350
351     if (actions[c] == M_OLD) {
352         if (h) {
353             mutt_set_flag(Context, h, M_READ, !bf);
354         } else {
355             mutt_tag_set_flag(M_READ, !bf);
356         }
357     }
358
359     if (h) {
360         mutt_set_flag(Context, h, actions[c], bf);
361     } else {
362         mutt_tag_set_flag(actions[c], bf);
363     }
364
365     return 0;
366 }