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