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