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