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