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