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