New way to connect a job_t.
[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 #include <lib-lib/lib-lib.h>
11
12 #include <lib-ui/lib-ui.h>
13 #include <lib-ui/menu.h>
14 #include <lib-mx/mx.h>
15 #include <imap/imap.h>
16
17 #include "mutt.h"
18 #include "sort.h"
19
20
21 void _mutt_set_flag (CONTEXT * ctx, HEADER * h, int flag, int bf, int upd_ctx)
22 {
23   int changed = h->changed;
24   int deleted = ctx->deleted;
25   int tagged = ctx->tagged;
26   int flagged = ctx->flagged;
27
28   if (ctx->readonly && flag != M_TAG)
29     return;                     /* don't modify anything if we are read-only */
30
31   switch (flag) {
32   case M_DELETE:
33
34     if (!mx_acl_check (ctx, ACL_DELETE))
35       return;
36
37     if (bf) {
38       if (!h->deleted && !ctx->readonly) {
39         h->deleted = 1;
40         if (upd_ctx)
41           ctx->deleted++;
42         /* deleted messages aren't treated as changed elsewhere so that the
43          * purge-on-sync option works correctly. This isn't applicable here */
44         if (ctx && ctx->magic == M_IMAP) {
45           h->changed = 1;
46           if (upd_ctx)
47             ctx->changed = 1;
48         }
49       }
50     }
51     else if (h->deleted) {
52       h->deleted = 0;
53       if (upd_ctx) {
54         ctx->deleted--;
55         if (h->appended)
56           ctx->appended--;
57       }
58       h->appended = 0;          /* when undeleting, also reset the appended flag */
59       /* see my comment above */
60       if (ctx->magic == M_IMAP) {
61         h->changed = 1;
62         if (upd_ctx)
63           ctx->changed = 1;
64       }
65       /* 
66        * If the user undeletes a message which is marked as
67        * "trash" in the maildir folder on disk, the folder has
68        * been changed, and is marked accordingly.  However, we do
69        * _not_ mark the message itself changed, because trashing
70        * is checked in specific code in the maildir folder
71        * driver. 
72        */
73       if (ctx->magic == M_MAILDIR && upd_ctx && h->trash)
74         ctx->changed = 1;
75     }
76     break;
77
78   case M_APPENDED:
79     if (bf) {
80       if (!h->appended) {
81         h->appended = 1;
82         if (upd_ctx)
83           ctx->appended++;
84       }
85     }
86     break;
87
88   case M_PURGED:
89     if (bf) {
90       if (!h->purged)
91         h->purged = 1;
92     }
93     else if (h->purged)
94       h->purged = 0;
95     break;
96
97   case M_NEW:
98
99     if (!mx_acl_check (ctx, ACL_SEEN))
100       return;
101
102     if (bf) {
103       if (h->read || h->old) {
104         h->old = 0;
105         if (upd_ctx)
106           ctx->new++;
107         if (h->read) {
108           h->read = 0;
109           if (upd_ctx)
110             ctx->unread++;
111         }
112         h->changed = 1;
113         if (upd_ctx)
114           ctx->changed = 1;
115       }
116     }
117     else if (!h->read) {
118       if (!h->old)
119         if (upd_ctx)
120           ctx->new--;
121       h->read = 1;
122       if (upd_ctx)
123         ctx->unread--;
124       h->changed = 1;
125       if (upd_ctx)
126         ctx->changed = 1;
127     }
128     break;
129
130   case M_OLD:
131
132     if (!mx_acl_check (ctx, ACL_SEEN))
133       return;
134
135     if (bf) {
136       if (!h->old) {
137         h->old = 1;
138         if (!h->read)
139           if (upd_ctx)
140             ctx->new--;
141         h->changed = 1;
142         if (upd_ctx)
143           ctx->changed = 1;
144       }
145     }
146     else if (h->old) {
147       h->old = 0;
148       if (!h->read)
149         if (upd_ctx)
150           ctx->new++;
151       h->changed = 1;
152       if (upd_ctx)
153         ctx->changed = 1;
154     }
155     break;
156
157   case M_READ:
158
159     if (!mx_acl_check (ctx, ACL_SEEN))
160       return;
161
162     if (bf) {
163       if (!h->read) {
164         h->read = 1;
165         if (upd_ctx)
166           ctx->unread--;
167         if (!h->old)
168           if (upd_ctx)
169             ctx->new--;
170         h->changed = 1;
171         if (upd_ctx)
172           ctx->changed = 1;
173       }
174     }
175     else if (h->read) {
176       h->read = 0;
177       if (upd_ctx)
178         ctx->unread++;
179       if (!h->old)
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_REPLIED:
189
190     if (!mx_acl_check (ctx, ACL_WRITE))
191       return;
192
193     if (bf) {
194       if (!h->replied) {
195         h->replied = 1;
196         if (!h->read) {
197           h->read = 1;
198           if (upd_ctx)
199             ctx->unread--;
200           if (!h->old)
201             if (upd_ctx)
202               ctx->new--;
203         }
204         h->changed = 1;
205         if (upd_ctx)
206           ctx->changed = 1;
207       }
208     }
209     else if (h->replied) {
210       h->replied = 0;
211       h->changed = 1;
212       if (upd_ctx)
213         ctx->changed = 1;
214     }
215     break;
216
217   case M_FLAG:
218
219     if (!mx_acl_check (ctx, ACL_WRITE))
220       return;
221
222     if (bf) {
223       if (!h->flagged) {
224         h->flagged = bf;
225         if (upd_ctx)
226           ctx->flagged++;
227         h->changed = 1;
228         if (upd_ctx)
229           ctx->changed = 1;
230       }
231     }
232     else if (h->flagged) {
233       h->flagged = 0;
234       if (upd_ctx)
235         ctx->flagged--;
236       h->changed = 1;
237       if (upd_ctx)
238         ctx->changed = 1;
239     }
240     break;
241
242   case M_TAG:
243     if (bf) {
244       if (!h->tagged) {
245         h->tagged = 1;
246         if (upd_ctx)
247           ctx->tagged++;
248       }
249     }
250     else if (h->tagged) {
251       h->tagged = 0;
252       if (upd_ctx)
253         ctx->tagged--;
254     }
255     break;
256   }
257
258   mutt_set_header_color (ctx, h);
259
260   /* if the message status has changed, we need to invalidate the cached
261    * search results so that any future search will match the current status
262    * of this message and not what it was at the time it was last searched.
263    */
264   if (h->searched && (changed != h->changed || deleted != ctx->deleted ||
265                       tagged != ctx->tagged || flagged != ctx->flagged))
266     h->searched = 0;
267   sidebar_draw ();
268 }
269
270 void mutt_tag_set_flag (int flag, int bf)
271 {
272   int j;
273
274   for (j = 0; j < Context->vcount; j++)
275     if (Context->hdrs[Context->v2r[j]]->tagged)
276       mutt_set_flag (Context, Context->hdrs[Context->v2r[j]], flag, bf);
277 }
278 int mutt_thread_set_flag (HEADER * hdr, int flag, int bf, int subthread)
279 {
280   THREAD *start, *cur = hdr->thread;
281
282   if ((Sort & SORT_MASK) != SORT_THREADS) {
283     mutt_error _("Threading is not enabled.");
284
285     return -1;
286   }
287
288   if (!subthread)
289     while (cur->parent)
290       cur = cur->parent;
291   start = cur;
292
293   if (cur->message)
294     mutt_set_flag (Context, cur->message, flag, bf);
295
296   if ((cur = cur->child) == NULL)
297     return 0;
298
299   for (;;) {
300     if (cur->message)
301       mutt_set_flag (Context, cur->message, flag, bf);
302
303     if (cur->child)
304       cur = cur->child;
305     else if (cur->next)
306       cur = cur->next;
307     else {
308       while (!cur->next) {
309         cur = cur->parent;
310         if (cur == start)
311           return 0;
312       }
313       cur = cur->next;
314     }
315   }
316   /* not reached */
317 }
318
319 int mutt_change_flag(HEADER * h, int bf)
320 {
321     char buf[STRING];
322     const char letters[] = "dDnNoOrR*!";
323     static char const actions[] = {
324         ['d'] = M_DELETE,       ['D'] = M_DELETE,
325         ['n'] = M_NEW,          ['N'] = M_NEW,
326         ['o'] = M_OLD,          ['O'] = M_OLD,
327         ['r'] = M_REPLIED,      ['R'] = M_REPLIED,
328         ['*'] = M_TAG,
329         ['!'] = M_FLAG,
330     };
331
332     int c;
333
334     snprintf(buf, sizeof(buf), "%s? (D/N/O/r/*/!): ",
335              bf ? _("Set flag") : _("Clear flag"));
336     c = mutt_multi_choice(buf, letters);
337     if (c <= 0)
338         return -1;
339     c = letters[c - 1];
340     if (actions[c] == M_OLD) {
341         if (h) {
342             mutt_set_flag(Context, h, M_READ, !bf);
343         } else {
344             mutt_tag_set_flag(M_READ, !bf);
345         }
346     }
347
348     if (h) {
349         mutt_set_flag(Context, h, actions[c], bf);
350     } else {
351         mutt_tag_set_flag(actions[c], bf);
352     }
353
354     return 0;
355 }