Nico Golde:
[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
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 #ifdef USE_IMAP
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 #endif
56       }
57     }
58     else if (h->deleted) {
59       h->deleted = 0;
60       if (upd_ctx) {
61         ctx->deleted--;
62         if (h->appended)
63           ctx->appended--;
64       }
65       h->appended = 0;          /* when undeleting, also reset the appended flag */
66 #ifdef USE_IMAP
67       /* see my comment above */
68       if (ctx->magic == M_IMAP) {
69         h->changed = 1;
70         if (upd_ctx)
71           ctx->changed = 1;
72       }
73 #endif
74       /* 
75        * If the user undeletes a message which is marked as
76        * "trash" in the maildir folder on disk, the folder has
77        * been changed, and is marked accordingly.  However, we do
78        * _not_ mark the message itself changed, because trashing
79        * is checked in specific code in the maildir folder
80        * driver. 
81        */
82       if (ctx->magic == M_MAILDIR && upd_ctx && h->trash)
83         ctx->changed = 1;
84     }
85     break;
86
87   case M_APPENDED:
88     if (bf) {
89       if (!h->appended) {
90         h->appended = 1;
91         if (upd_ctx)
92           ctx->appended++;
93       }
94     }
95     break;
96
97   case M_PURGED:
98     if (bf) {
99       if (!h->purged)
100         h->purged = 1;
101     }
102     else if (h->purged)
103       h->purged = 0;
104     break;
105
106   case M_NEW:
107
108     if (!mx_acl_check (ctx, ACL_SEEN))
109       return;
110
111     if (bf) {
112       if (h->read || h->old) {
113         h->old = 0;
114         if (upd_ctx)
115           ctx->new++;
116         if (h->read) {
117           h->read = 0;
118           if (upd_ctx)
119             ctx->unread++;
120         }
121         h->changed = 1;
122         if (upd_ctx)
123           ctx->changed = 1;
124       }
125     }
126     else if (!h->read) {
127       if (!h->old)
128         if (upd_ctx)
129           ctx->new--;
130       h->read = 1;
131       if (upd_ctx)
132         ctx->unread--;
133       h->changed = 1;
134       if (upd_ctx)
135         ctx->changed = 1;
136     }
137     break;
138
139   case M_OLD:
140
141     if (!mx_acl_check (ctx, ACL_SEEN))
142       return;
143
144     if (bf) {
145       if (!h->old) {
146         h->old = 1;
147         if (!h->read)
148           if (upd_ctx)
149             ctx->new--;
150         h->changed = 1;
151         if (upd_ctx)
152           ctx->changed = 1;
153       }
154     }
155     else if (h->old) {
156       h->old = 0;
157       if (!h->read)
158         if (upd_ctx)
159           ctx->new++;
160       h->changed = 1;
161       if (upd_ctx)
162         ctx->changed = 1;
163     }
164     break;
165
166   case M_READ:
167
168     if (!mx_acl_check (ctx, ACL_SEEN))
169       return;
170
171     if (bf) {
172       if (!h->read) {
173         h->read = 1;
174         if (upd_ctx)
175           ctx->unread--;
176         if (!h->old)
177           if (upd_ctx)
178             ctx->new--;
179         h->changed = 1;
180         if (upd_ctx)
181           ctx->changed = 1;
182       }
183     }
184     else if (h->read) {
185       h->read = 0;
186       if (upd_ctx)
187         ctx->unread++;
188       if (!h->old)
189         if (upd_ctx)
190           ctx->new++;
191       h->changed = 1;
192       if (upd_ctx)
193         ctx->changed = 1;
194     }
195     break;
196
197   case M_REPLIED:
198
199     if (!mx_acl_check (ctx, ACL_WRITE))
200       return;
201
202     if (bf) {
203       if (!h->replied) {
204         h->replied = 1;
205         if (!h->read) {
206           h->read = 1;
207           if (upd_ctx)
208             ctx->unread--;
209           if (!h->old)
210             if (upd_ctx)
211               ctx->new--;
212         }
213         h->changed = 1;
214         if (upd_ctx)
215           ctx->changed = 1;
216       }
217     }
218     else if (h->replied) {
219       h->replied = 0;
220       h->changed = 1;
221       if (upd_ctx)
222         ctx->changed = 1;
223     }
224     break;
225
226   case M_FLAG:
227
228     if (!mx_acl_check (ctx, ACL_WRITE))
229       return;
230
231     if (bf) {
232       if (!h->flagged) {
233         h->flagged = bf;
234         if (upd_ctx)
235           ctx->flagged++;
236         h->changed = 1;
237         if (upd_ctx)
238           ctx->changed = 1;
239       }
240     }
241     else if (h->flagged) {
242       h->flagged = 0;
243       if (upd_ctx)
244         ctx->flagged--;
245       h->changed = 1;
246       if (upd_ctx)
247         ctx->changed = 1;
248     }
249     break;
250
251   case M_TAG:
252     if (bf) {
253       if (!h->tagged) {
254         h->tagged = 1;
255         if (upd_ctx)
256           ctx->tagged++;
257       }
258     }
259     else if (h->tagged) {
260       h->tagged = 0;
261       if (upd_ctx)
262         ctx->tagged--;
263     }
264     break;
265   }
266
267   mutt_set_header_color (ctx, h);
268
269   /* if the message status has changed, we need to invalidate the cached
270    * search results so that any future search will match the current status
271    * of this message and not what it was at the time it was last searched.
272    */
273   if (h->searched
274       && (changed != h->changed || deleted != ctx->deleted
275           || tagged != ctx->tagged))
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 }