4 * Implements the STORE command in IMAP.
7 * Copyright (c) 2001-2009 by the citadel.org team
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include <sys/types.h>
35 #if TIME_WITH_SYS_TIME
36 # include <sys/time.h>
40 # include <sys/time.h>
50 #include <libcitadel.h>
53 #include "sysdep_decls.h"
54 #include "citserver.h"
61 #include "internet_addressing.h"
62 #include "serv_imap.h"
63 #include "imap_tools.h"
64 #include "imap_fetch.h"
65 #include "imap_store.h"
74 * imap_do_store() calls imap_do_store_msg() to tweak the settings of
75 * an individual message.
77 * We also implement the ".SILENT" protocol option here. :(
79 void imap_do_store_msg(int seq, char *oper, unsigned int bits_to_twiddle) {
82 if (!strncasecmp(oper, "FLAGS", 5)) {
83 IMAP->flags[seq] &= IMAP_MASK_SYSTEM;
84 IMAP->flags[seq] |= bits_to_twiddle;
86 else if (!strncasecmp(oper, "+FLAGS", 6)) {
87 IMAP->flags[seq] |= bits_to_twiddle;
89 else if (!strncasecmp(oper, "-FLAGS", 6)) {
90 IMAP->flags[seq] &= (~bits_to_twiddle);
97 * imap_store() calls imap_do_store() to perform the actual bit twiddling
100 void imap_do_store(int num_items, char **itemlist) {
102 unsigned int bits_to_twiddle = 0;
105 char whichflags[256];
110 int last_item_twiddled = (-1);
112 if (num_items < 2) return;
114 if (bmstrcasestr(oper, ".SILENT")) {
119 * ss_msglist is an array of message numbers to manipulate. We
120 * are going to supply this array to CtdlSetSeen() later.
122 ss_msglist = malloc(IMAP->num_msgs * sizeof(long));
123 if (ss_msglist == NULL) return;
126 * Ok, go ahead and parse the flags.
128 for (i=1; i<num_items; ++i) {
129 strcpy(whichflags, itemlist[i]);
130 if (whichflags[0]=='(') {
131 safestrncpy(whichflags, &whichflags[1],
134 if (whichflags[strlen(whichflags)-1]==')') {
135 whichflags[strlen(whichflags)-1]=0;
139 /* A client might twiddle more than one bit at a time.
140 * Note that we check for the flag names without the leading
141 * backslash because imap_parameterize() strips them out.
143 num_flags = num_tokens(whichflags, ' ');
144 for (j=0; j<num_flags; ++j) {
145 extract_token(flag, whichflags, j, ' ', sizeof flag);
147 if ((!strcasecmp(flag, "\\Deleted"))
148 || (!strcasecmp(flag, "Deleted"))) {
149 if (CtdlDoIHavePermissionToDeleteMessagesFromThisRoom()) {
150 bits_to_twiddle |= IMAP_DELETED;
153 if ((!strcasecmp(flag, "\\Seen"))
154 || (!strcasecmp(flag, "Seen"))) {
155 bits_to_twiddle |= IMAP_SEEN;
157 if ((!strcasecmp(flag, "\\Answered"))
158 || (!strcasecmp(flag, "Answered"))) {
159 bits_to_twiddle |= IMAP_ANSWERED;
164 if (IMAP->num_msgs > 0) {
165 for (i = 0; i < IMAP->num_msgs; ++i) {
166 if (IMAP->flags[i] & IMAP_SELECTED) {
167 last_item_twiddled = i;
169 ss_msglist[num_ss++] = IMAP->msgids[i];
170 imap_do_store_msg(i, oper, bits_to_twiddle);
173 cprintf("* %d FETCH (", i+1);
183 * Now manipulate the database -- all in one shot.
185 if ( (last_item_twiddled >= 0) && (num_ss > 0) ) {
187 if (bits_to_twiddle & IMAP_SEEN) {
188 CtdlSetSeen(ss_msglist, num_ss,
189 ((IMAP->flags[last_item_twiddled] & IMAP_SEEN) ? 1 : 0),
195 if (bits_to_twiddle & IMAP_ANSWERED) {
196 CtdlSetSeen(ss_msglist, num_ss,
197 ((IMAP->flags[last_item_twiddled] & IMAP_ANSWERED) ? 1 : 0),
198 ctdlsetseen_answered,
208 * The following two commands implement "instant expunge" if enabled.
210 if (config.c_instant_expunge) {
212 imap_rescan_msgids();
219 * This function is called by the main command loop.
221 void imap_store(int num_parms, char *parms[]) {
228 cprintf("%s BAD invalid parameters\r\n", parms[0]);
232 if (imap_is_message_set(parms[2])) {
233 imap_pick_range(parms[2], 0);
236 cprintf("%s BAD invalid parameters\r\n", parms[0]);
241 for (i=3; i<num_parms; ++i) {
242 strcat(items, parms[i]);
243 if (i < (num_parms-1)) strcat(items, " ");
246 num_items = imap_extract_data_items(itemlist, items);
248 cprintf("%s BAD invalid data item list\r\n", parms[0]);
252 imap_do_store(num_items, itemlist);
253 cprintf("%s OK STORE completed\r\n", parms[0]);
257 * This function is called by the main command loop.
259 void imap_uidstore(int num_parms, char *parms[]) {
266 cprintf("%s BAD invalid parameters\r\n", parms[0]);
270 if (imap_is_message_set(parms[3])) {
271 imap_pick_range(parms[3], 1);
274 cprintf("%s BAD invalid parameters\r\n", parms[0]);
279 for (i=4; i<num_parms; ++i) {
280 strcat(items, parms[i]);
281 if (i < (num_parms-1)) strcat(items, " ");
284 num_items = imap_extract_data_items(itemlist, items);
286 cprintf("%s BAD invalid data item list\r\n", parms[0]);
290 imap_do_store(num_items, itemlist);
291 cprintf("%s OK UID STORE completed\r\n", parms[0]);