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