4 * Implements the STORE command in IMAP.
17 #include <sys/types.h>
19 #if TIME_WITH_SYS_TIME
20 # include <sys/time.h>
24 # include <sys/time.h>
34 #include <libcitadel.h>
37 #include "sysdep_decls.h"
38 #include "citserver.h"
46 #include "internet_addressing.h"
47 #include "serv_imap.h"
48 #include "imap_tools.h"
49 #include "imap_fetch.h"
50 #include "imap_store.h"
59 * imap_do_store() calls imap_do_store_msg() to tweak the settings of
60 * an individual message.
62 * We also implement the ".SILENT" protocol option here. :(
64 void imap_do_store_msg(int seq, char *oper, unsigned int bits_to_twiddle) {
67 if (!strncasecmp(oper, "FLAGS", 5)) {
68 IMAP->flags[seq] &= IMAP_MASK_SYSTEM;
69 IMAP->flags[seq] |= bits_to_twiddle;
71 else if (!strncasecmp(oper, "+FLAGS", 6)) {
72 IMAP->flags[seq] |= bits_to_twiddle;
74 else if (!strncasecmp(oper, "-FLAGS", 6)) {
75 IMAP->flags[seq] &= (~bits_to_twiddle);
82 * imap_store() calls imap_do_store() to perform the actual bit twiddling
85 void imap_do_store(int num_items, char **itemlist) {
87 unsigned int bits_to_twiddle = 0;
95 int last_item_twiddled = (-1);
97 if (num_items < 2) return;
99 if (bmstrcasestr(oper, ".SILENT")) {
104 * ss_msglist is an array of message numbers to manipulate. We
105 * are going to supply this array to CtdlSetSeen() later.
107 ss_msglist = malloc(IMAP->num_msgs * sizeof(long));
108 if (ss_msglist == NULL) return;
111 * Ok, go ahead and parse the flags.
113 for (i=1; i<num_items; ++i) {
114 strcpy(whichflags, itemlist[i]);
115 if (whichflags[0]=='(') {
116 safestrncpy(whichflags, &whichflags[1],
119 if (whichflags[strlen(whichflags)-1]==')') {
120 whichflags[strlen(whichflags)-1]=0;
124 /* A client might twiddle more than one bit at a time.
125 * Note that we check for the flag names without the leading
126 * backslash because imap_parameterize() strips them out.
128 num_flags = num_tokens(whichflags, ' ');
129 for (j=0; j<num_flags; ++j) {
130 extract_token(flag, whichflags, j, ' ', sizeof flag);
132 if ((!strcasecmp(flag, "\\Deleted"))
133 || (!strcasecmp(flag, "Deleted"))) {
134 if (CtdlDoIHavePermissionToDeleteMessagesFromThisRoom()) {
135 bits_to_twiddle |= IMAP_DELETED;
138 if ((!strcasecmp(flag, "\\Seen"))
139 || (!strcasecmp(flag, "Seen"))) {
140 bits_to_twiddle |= IMAP_SEEN;
142 if ((!strcasecmp(flag, "\\Answered"))
143 || (!strcasecmp(flag, "Answered"))) {
144 bits_to_twiddle |= IMAP_ANSWERED;
149 if (IMAP->num_msgs > 0) {
150 for (i = 0; i < IMAP->num_msgs; ++i) {
151 if (IMAP->flags[i] & IMAP_SELECTED) {
152 last_item_twiddled = i;
154 ss_msglist[num_ss++] = IMAP->msgids[i];
155 imap_do_store_msg(i, oper, bits_to_twiddle);
158 cprintf("* %d FETCH (", i+1);
168 * Now manipulate the database -- all in one shot.
170 if ( (last_item_twiddled >= 0) && (num_ss > 0) ) {
172 if (bits_to_twiddle & IMAP_SEEN) {
173 CtdlSetSeen(ss_msglist, num_ss,
174 ((IMAP->flags[last_item_twiddled] & IMAP_SEEN) ? 1 : 0),
180 if (bits_to_twiddle & IMAP_ANSWERED) {
181 CtdlSetSeen(ss_msglist, num_ss,
182 ((IMAP->flags[last_item_twiddled] & IMAP_ANSWERED) ? 1 : 0),
183 ctdlsetseen_answered,
193 * The following two commands implement "instant expunge" if enabled.
195 if (config.c_instant_expunge) {
197 imap_rescan_msgids();
204 * This function is called by the main command loop.
206 void imap_store(int num_parms, char *parms[]) {
213 cprintf("%s BAD invalid parameters\r\n", parms[0]);
217 if (imap_is_message_set(parms[2])) {
218 imap_pick_range(parms[2], 0);
221 cprintf("%s BAD invalid parameters\r\n", parms[0]);
226 for (i=3; i<num_parms; ++i) {
227 strcat(items, parms[i]);
228 if (i < (num_parms-1)) strcat(items, " ");
231 num_items = imap_extract_data_items(itemlist, items);
233 cprintf("%s BAD invalid data item list\r\n", parms[0]);
237 imap_do_store(num_items, itemlist);
238 cprintf("%s OK STORE completed\r\n", parms[0]);
242 * This function is called by the main command loop.
244 void imap_uidstore(int num_parms, char *parms[]) {
251 cprintf("%s BAD invalid parameters\r\n", parms[0]);
255 if (imap_is_message_set(parms[3])) {
256 imap_pick_range(parms[3], 1);
259 cprintf("%s BAD invalid parameters\r\n", parms[0]);
264 for (i=4; i<num_parms; ++i) {
265 strcat(items, parms[i]);
266 if (i < (num_parms-1)) strcat(items, " ");
269 num_items = imap_extract_data_items(itemlist, items);
271 cprintf("%s BAD invalid data item list\r\n", parms[0]);
275 imap_do_store(num_items, itemlist);
276 cprintf("%s OK UID STORE completed\r\n", parms[0]);