]> code.citadel.org Git - citadel.git/blob - citadel/imap_store.c
31a14e1f07f5ad8b2fa1c346f4cbec8e92371f99
[citadel.git] / citadel / imap_store.c
1 /*
2  * $Id$
3  *
4  * Implements the STORE command in IMAP.
5  *
6  */
7
8
9 #include "sysdep.h"
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <stdio.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <pwd.h>
16 #include <errno.h>
17 #include <sys/types.h>
18
19 #if TIME_WITH_SYS_TIME
20 # include <sys/time.h>
21 # include <time.h>
22 #else
23 # if HAVE_SYS_TIME_H
24 #  include <sys/time.h>
25 # else
26 #  include <time.h>
27 # endif
28 #endif
29
30 #include <sys/wait.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <limits.h>
34 #include "citadel.h"
35 #include "server.h"
36 #include "sysdep_decls.h"
37 #include "citserver.h"
38 #include "support.h"
39 #include "config.h"
40 #include "serv_extensions.h"
41 #include "room_ops.h"
42 #include "user_ops.h"
43 #include "policy.h"
44 #include "database.h"
45 #include "msgbase.h"
46 #include "tools.h"
47 #include "internet_addressing.h"
48 #include "serv_imap.h"
49 #include "imap_tools.h"
50 #include "imap_fetch.h"
51 #include "imap_store.h"
52 #include "genstamp.h"
53
54
55
56
57
58
59 /*
60  * imap_do_store() calls imap_do_store_msg() to tweak the settings of
61  * an individual message.
62  *
63  * We also implement the ".SILENT" protocol option here.  :(
64  */
65 void imap_do_store_msg(int seq, char *oper, unsigned int bits_to_twiddle) {
66         int silent = 0;
67
68         if (!strncasecmp(oper, "FLAGS", 5)) {
69                 IMAP->flags[seq] &= IMAP_MASK_SYSTEM;
70                 IMAP->flags[seq] |= bits_to_twiddle;
71                 silent = strncasecmp(&oper[5], ".SILENT", 7);
72         }
73         else if (!strncasecmp(oper, "+FLAGS", 6)) {
74                 IMAP->flags[seq] |= bits_to_twiddle;
75                 silent = strncasecmp(&oper[6], ".SILENT", 7);
76         }
77         else if (!strncasecmp(oper, "-FLAGS", 6)) {
78                 IMAP->flags[seq] &= (~bits_to_twiddle);
79                 silent = strncasecmp(&oper[6], ".SILENT", 7);
80         }
81
82         if (bits_to_twiddle & IMAP_SEEN) {
83                 CtdlSetSeen(IMAP->msgids[seq],
84                         ((IMAP->flags[seq] & IMAP_SEEN) ? 1 : 0),
85                         ctdlsetseen_seen,
86                         NULL, NULL
87                 );
88         }
89         if (bits_to_twiddle & IMAP_ANSWERED) {
90                 CtdlSetSeen(IMAP->msgids[seq],
91                         ((IMAP->flags[seq] & IMAP_ANSWERED) ? 1 : 0),
92                         ctdlsetseen_answered,
93                         NULL, NULL
94                 );
95         }
96
97         /* 'silent' is actually the value returned from a strncasecmp() so
98          * we want that option only if its value is zero.  Seems backwards
99          * but that's the way it's supposed to be.
100          */
101         if (silent) {
102                 cprintf("* %d FETCH (", seq+1);
103                 imap_fetch_flags(seq);
104                 cprintf(")\r\n");
105         }
106 }
107
108
109
110 /*
111  * imap_store() calls imap_do_store() to perform the actual bit twiddling
112  * on the flags.
113  */
114 void imap_do_store(int num_items, char **itemlist) {
115         int i, j;
116         unsigned int bits_to_twiddle = 0;
117         char *oper;
118         char flag[32];
119         char whichflags[256];
120         char num_flags;
121
122         if (num_items < 2) return;
123         oper = itemlist[0];
124
125         for (i=1; i<num_items; ++i) {
126                 strcpy(whichflags, itemlist[i]);
127                 if (whichflags[0]=='(') safestrncpy(whichflags, &whichflags[1], sizeof whichflags);
128                 if (whichflags[strlen(whichflags)-1]==')') {
129                         whichflags[strlen(whichflags)-1]=0;
130                 }
131                 striplt(whichflags);
132
133                 /* A client might twiddle more than one bit at a time.
134                  * Note that we check for the flag names without the leading
135                  * backslash because imap_parameterize() strips them out.
136                  */
137                 num_flags = num_tokens(whichflags, ' ');
138                 for (j=0; j<num_flags; ++j) {
139                         extract_token(flag, whichflags, j, ' ', sizeof flag);
140
141                         if ((!strcasecmp(flag, "\\Deleted"))
142                            || (!strcasecmp(flag, "Deleted"))) {
143                                 if (CtdlDoIHavePermissionToDeleteMessagesFromThisRoom()) {
144                                         bits_to_twiddle |= IMAP_DELETED;
145                                 }
146                         }
147                         if ((!strcasecmp(flag, "\\Seen"))
148                            || (!strcasecmp(flag, "Seen"))) {
149                                 bits_to_twiddle |= IMAP_SEEN;
150                         }
151                         if ((!strcasecmp(flag, "\\Answered")) 
152                            || (!strcasecmp(flag, "\\Answered"))) {
153                                 bits_to_twiddle |= IMAP_ANSWERED;
154                         }
155                 }
156         }
157
158         if (IMAP->num_msgs > 0) {
159                 for (i = 0; i < IMAP->num_msgs; ++i) {
160                         if (IMAP->flags[i] & IMAP_SELECTED) {
161                                 imap_do_store_msg(i, oper, bits_to_twiddle);
162                         }
163                 }
164         }
165 }
166
167
168 /*
169  * This function is called by the main command loop.
170  */
171 void imap_store(int num_parms, char *parms[]) {
172         char items[1024];
173         char *itemlist[256];
174         int num_items;
175         int i;
176
177         if (num_parms < 3) {
178                 cprintf("%s BAD invalid parameters\r\n", parms[0]);
179                 return;
180         }
181
182         if (imap_is_message_set(parms[2])) {
183                 imap_pick_range(parms[2], 0);
184         }
185         else {
186                 cprintf("%s BAD invalid parameters\r\n", parms[0]);
187                 return;
188         }
189
190         strcpy(items, "");
191         for (i=3; i<num_parms; ++i) {
192                 strcat(items, parms[i]);
193                 if (i < (num_parms-1)) strcat(items, " ");
194         }
195
196         num_items = imap_extract_data_items(itemlist, items);
197         if (num_items < 1) {
198                 cprintf("%s BAD invalid data item list\r\n", parms[0]);
199                 return;
200         }
201
202         imap_do_store(num_items, itemlist);
203
204 #ifdef INSTANT_EXPUNGE
205         /*
206          * The following two commands implement "instant expunge"
207          * which is experimental.
208          */
209         imap_do_expunge();
210         imap_rescan_msgids();
211 #endif /* INSTANT_EXPUNGE */
212
213         cprintf("%s OK STORE completed\r\n", parms[0]);
214 }
215
216 /*
217  * This function is called by the main command loop.
218  */
219 void imap_uidstore(int num_parms, char *parms[]) {
220         char items[1024];
221         char *itemlist[256];
222         int num_items;
223         int i;
224
225         if (num_parms < 4) {
226                 cprintf("%s BAD invalid parameters\r\n", parms[0]);
227                 return;
228         }
229
230         if (imap_is_message_set(parms[3])) {
231                 imap_pick_range(parms[3], 1);
232         }
233         else {
234                 cprintf("%s BAD invalid parameters\r\n", parms[0]);
235                 return;
236         }
237
238         strcpy(items, "");
239         for (i=4; i<num_parms; ++i) {
240                 strcat(items, parms[i]);
241                 if (i < (num_parms-1)) strcat(items, " ");
242         }
243
244         num_items = imap_extract_data_items(itemlist, items);
245         if (num_items < 1) {
246                 cprintf("%s BAD invalid data item list\r\n", parms[0]);
247                 return;
248         }
249
250         imap_do_store(num_items, itemlist);
251         cprintf("%s OK UID STORE completed\r\n", parms[0]);
252 }
253
254