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