4 * Implements the STORE command in IMAP.
6 * Copyright (c) 2001-2009 by the citadel.org team
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "ctdl_module.h"
32 #include <sys/types.h>
34 #if TIME_WITH_SYS_TIME
35 # include <sys/time.h>
39 # include <sys/time.h>
49 #include <libcitadel.h>
52 #include "sysdep_decls.h"
53 #include "citserver.h"
59 #include "internet_addressing.h"
60 #include "imap_tools.h"
61 #include "serv_imap.h"
62 #include "imap_fetch.h"
63 #include "imap_store.h"
68 * imap_do_store() calls imap_do_store_msg() to tweak the settings of
69 * an individual message.
71 * We also implement the ".SILENT" protocol option here. :(
73 void imap_do_store_msg(int seq, const char *oper, unsigned int bits_to_twiddle) {
76 if (!strncasecmp(oper, "FLAGS", 5)) {
77 IMAP->flags[seq] &= IMAP_MASK_SYSTEM;
78 IMAP->flags[seq] |= bits_to_twiddle;
80 else if (!strncasecmp(oper, "+FLAGS", 6)) {
81 IMAP->flags[seq] |= bits_to_twiddle;
83 else if (!strncasecmp(oper, "-FLAGS", 6)) {
84 IMAP->flags[seq] &= (~bits_to_twiddle);
90 * imap_store() calls imap_do_store() to perform the actual bit twiddling
93 void imap_do_store(citimap_command *Cmd) {
95 unsigned int bits_to_twiddle = 0;
103 int last_item_twiddled = (-1);
104 citimap *Imap = IMAP;
106 if (Cmd->num_parms < 2) return;
107 oper = Cmd->Params[0].Key;
108 if (cbmstrcasestr(oper, ".SILENT")) {
113 * ss_msglist is an array of message numbers to manipulate. We
114 * are going to supply this array to CtdlSetSeen() later.
116 ss_msglist = malloc(Imap->num_msgs * sizeof(long));
117 if (ss_msglist == NULL) return;
120 * Ok, go ahead and parse the flags.
122 for (i=1; i<Cmd->num_parms; ++i) {///TODO: why strcpy?
123 strcpy(whichflags, Cmd->Params[i].Key);
124 if (whichflags[0]=='(') {
125 safestrncpy(whichflags, &whichflags[1],
128 if (whichflags[strlen(whichflags)-1]==')') {
129 whichflags[strlen(whichflags)-1]=0;
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.
137 num_flags = num_tokens(whichflags, ' ');
138 for (j=0; j<num_flags; ++j) {
139 extract_token(flag, whichflags, j, ' ', sizeof flag);
141 if ((!strcasecmp(flag, "\\Deleted"))
142 || (!strcasecmp(flag, "Deleted"))) {
143 if (CtdlDoIHavePermissionToDeleteMessagesFromThisRoom()) {
144 bits_to_twiddle |= IMAP_DELETED;
147 if ((!strcasecmp(flag, "\\Seen"))
148 || (!strcasecmp(flag, "Seen"))) {
149 bits_to_twiddle |= IMAP_SEEN;
151 if ((!strcasecmp(flag, "\\Answered"))
152 || (!strcasecmp(flag, "Answered"))) {
153 bits_to_twiddle |= IMAP_ANSWERED;
158 if (Imap->num_msgs > 0) {
159 for (i = 0; i < Imap->num_msgs; ++i) {
160 if (Imap->flags[i] & IMAP_SELECTED) {
161 last_item_twiddled = i;
163 ss_msglist[num_ss++] = Imap->msgids[i];
164 imap_do_store_msg(i, oper, bits_to_twiddle);
167 cprintf("* %d FETCH (", i+1);
177 * Now manipulate the database -- all in one shot.
179 if ( (last_item_twiddled >= 0) && (num_ss > 0) ) {
181 if (bits_to_twiddle & IMAP_SEEN) {
182 CtdlSetSeen(ss_msglist, num_ss,
183 ((Imap->flags[last_item_twiddled] & IMAP_SEEN) ? 1 : 0),
189 if (bits_to_twiddle & IMAP_ANSWERED) {
190 CtdlSetSeen(ss_msglist, num_ss,
191 ((Imap->flags[last_item_twiddled] & IMAP_ANSWERED) ? 1 : 0),
192 ctdlsetseen_answered,
202 * The following two commands implement "instant expunge" if enabled.
204 if (config.c_instant_expunge) {
206 imap_rescan_msgids();
213 * This function is called by the main command loop.
215 void imap_store(int num_parms, ConstStr *Params) {
220 cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
224 if (imap_is_message_set(Params[2].Key)) {
225 imap_pick_range(Params[2].Key, 0);
228 cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
232 memset(&Cmd, 0, sizeof(citimap_command));
233 Cmd.CmdBuf = NewStrBufPlain(NULL, StrLength(IMAP->Cmd.CmdBuf));
234 MakeStringOf(Cmd.CmdBuf, 3);
236 num_items = imap_extract_data_items(&Cmd);
238 cprintf("%s BAD invalid data item list\r\n", Params[0].Key);
239 FreeStrBuf(&Cmd.CmdBuf);
245 cprintf("%s OK STORE completed\r\n", Params[0].Key);
246 FreeStrBuf(&Cmd.CmdBuf);
251 * This function is called by the main command loop.
253 void imap_uidstore(int num_parms, ConstStr *Params) {
258 cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
262 if (imap_is_message_set(Params[3].Key)) {
263 imap_pick_range(Params[3].Key, 1);
266 cprintf("%s BAD invalid parameters\r\n", Params[0].Key);
270 memset(&Cmd, 0, sizeof(citimap_command));
271 Cmd.CmdBuf = NewStrBufPlain(NULL, StrLength(IMAP->Cmd.CmdBuf));
272 MakeStringOf(Cmd.CmdBuf, 4);
274 num_items = imap_extract_data_items(&Cmd);
276 cprintf("%s BAD invalid data item list\r\n", Params[0].Key);
277 FreeStrBuf(&Cmd.CmdBuf);
283 cprintf("%s OK UID STORE completed\r\n", Params[0].Key);
284 FreeStrBuf(&Cmd.CmdBuf);