citadel
About: Citadel is an advanced messaging and collaboration system for groupware and BBS applications (preferred OS: Linux).
  Fossies Dox: citadel.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

imap_store.c
Go to the documentation of this file.
1/*
2 * Implements the STORE command in IMAP.
3 *
4 * Copyright (c) 2001-2009 by the citadel.org team
5 *
6 * This program is open source software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "ctdl_module.h"
22
23#include <stdlib.h>
24#include <unistd.h>
25#include <stdio.h>
26#include <fcntl.h>
27#include <signal.h>
28#include <pwd.h>
29#include <errno.h>
30#include <sys/types.h>
31#include <time.h>
32#include <sys/wait.h>
33#include <ctype.h>
34#include <string.h>
35#include <limits.h>
36#include <libcitadel.h>
37#include "citadel.h"
38#include "server.h"
39#include "sysdep_decls.h"
40#include "citserver.h"
41#include "support.h"
42#include "config.h"
43#include "user_ops.h"
44#include "database.h"
45#include "room_ops.h"
46#include "msgbase.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 * imap_do_store() calls imap_do_store_msg() to tweak the settings of
57 * an individual message.
58 *
59 * We also implement the ".SILENT" protocol option here. :(
60 */
61void imap_do_store_msg(int seq, const char *oper, unsigned int bits_to_twiddle) {
62 citimap *Imap = IMAP;
63
64 if (!strncasecmp(oper, "FLAGS", 5)) {
65 Imap->flags[seq] &= IMAP_MASK_SYSTEM;
66 Imap->flags[seq] |= bits_to_twiddle;
67 }
68 else if (!strncasecmp(oper, "+FLAGS", 6)) {
69 Imap->flags[seq] |= bits_to_twiddle;
70 }
71 else if (!strncasecmp(oper, "-FLAGS", 6)) {
72 Imap->flags[seq] &= (~bits_to_twiddle);
73 }
74}
75
76
77/*
78 * imap_store() calls imap_do_store() to perform the actual bit twiddling
79 * on the flags.
80 */
82 int i, j;
83 unsigned int bits_to_twiddle = 0;
84 const char *oper;
85 char flag[32];
86 char whichflags[256];
87 char num_flags;
88 int silent = 0;
89 long *ss_msglist;
90 int num_ss = 0;
91 int last_item_twiddled = (-1);
92 citimap *Imap = IMAP;
93
94 if (Cmd->num_parms < 2) return;
95 oper = Cmd->Params[0].Key;
96 if (cbmstrcasestr(oper, ".SILENT")) {
97 silent = 1;
98 }
99
100 /*
101 * ss_msglist is an array of message numbers to manipulate. We
102 * are going to supply this array to CtdlSetSeen() later.
103 */
104 ss_msglist = malloc(Imap->num_msgs * sizeof(long));
105 if (ss_msglist == NULL) return;
106
107 /*
108 * Ok, go ahead and parse the flags.
109 */
110 for (i=1; i<Cmd->num_parms; ++i) {///TODO: why strcpy?
111 strcpy(whichflags, Cmd->Params[i].Key);
112 if (whichflags[0]=='(') {
113 safestrncpy(whichflags, &whichflags[1],
114 sizeof whichflags);
115 }
116 if (whichflags[strlen(whichflags)-1]==')') {
117 whichflags[strlen(whichflags)-1]=0;
118 }
119 striplt(whichflags);
120
121 /* A client might twiddle more than one bit at a time.
122 * Note that we check for the flag names without the leading
123 * backslash because imap_parameterize() strips them out.
124 */
125 num_flags = num_tokens(whichflags, ' ');
126 for (j=0; j<num_flags; ++j) {
127 extract_token(flag, whichflags, j, ' ', sizeof flag);
128
129 if ((!strcasecmp(flag, "\\Deleted"))
130 || (!strcasecmp(flag, "Deleted"))) {
132 bits_to_twiddle |= IMAP_DELETED;
133 }
134 }
135 if ((!strcasecmp(flag, "\\Seen"))
136 || (!strcasecmp(flag, "Seen"))) {
137 bits_to_twiddle |= IMAP_SEEN;
138 }
139 if ((!strcasecmp(flag, "\\Answered"))
140 || (!strcasecmp(flag, "Answered"))) {
141 bits_to_twiddle |= IMAP_ANSWERED;
142 }
143 }
144 }
145
146 if (Imap->num_msgs > 0) {
147 for (i = 0; i < Imap->num_msgs; ++i) {
148 if (Imap->flags[i] & IMAP_SELECTED) {
149 last_item_twiddled = i;
150
151 ss_msglist[num_ss++] = Imap->msgids[i];
152 imap_do_store_msg(i, oper, bits_to_twiddle);
153
154 if (!silent) {
155 IAPrintf("* %d FETCH (", i+1);
157 IAPuts(")\r\n");
158 }
159
160 }
161 }
162 }
163
164 /*
165 * Now manipulate the database -- all in one shot.
166 */
167 if ( (last_item_twiddled >= 0) && (num_ss > 0) ) {
168
169 if (bits_to_twiddle & IMAP_SEEN) {
170 CtdlSetSeen(ss_msglist, num_ss,
171 ((Imap->flags[last_item_twiddled] & IMAP_SEEN) ? 1 : 0),
173 NULL, NULL
174 );
175 }
176
177 if (bits_to_twiddle & IMAP_ANSWERED) {
178 CtdlSetSeen(ss_msglist, num_ss,
179 ((Imap->flags[last_item_twiddled] & IMAP_ANSWERED) ? 1 : 0),
181 NULL, NULL
182 );
183 }
184
185 }
186
187 free(ss_msglist);
188 imap_do_expunge(); // Citadel always expunges immediately.
190}
191
192
193/*
194 * This function is called by the main command loop.
195 */
196void imap_store(int num_parms, ConstStr *Params) {
197 citimap_command Cmd;
198 int num_items;
199
200 if (num_parms < 3) {
201 IReply("BAD invalid parameters");
202 return;
203 }
204
205 if (imap_is_message_set(Params[2].Key)) {
206 imap_pick_range(Params[2].Key, 0);
207 }
208 else {
209 IReply("BAD invalid parameters");
210 return;
211 }
212
213 memset(&Cmd, 0, sizeof(citimap_command));
214 Cmd.CmdBuf = NewStrBufPlain(NULL, StrLength(IMAP->Cmd.CmdBuf));
215 MakeStringOf(Cmd.CmdBuf, 3);
216
217 num_items = imap_extract_data_items(&Cmd);
218 if (num_items < 1) {
219 IReply("BAD invalid data item list");
220 FreeStrBuf(&Cmd.CmdBuf);
221 free(Cmd.Params);
222 return;
223 }
224
225 imap_do_store(&Cmd);
226 IReply("OK STORE completed");
227 FreeStrBuf(&Cmd.CmdBuf);
228 free(Cmd.Params);
229}
230
231/*
232 * This function is called by the main command loop.
233 */
234void imap_uidstore(int num_parms, ConstStr *Params) {
235 citimap_command Cmd;
236 int num_items;
237
238 if (num_parms < 4) {
239 IReply("BAD invalid parameters");
240 return;
241 }
242
243 if (imap_is_message_set(Params[3].Key)) {
244 imap_pick_range(Params[3].Key, 1);
245 }
246 else {
247 IReply("BAD invalid parameters");
248 return;
249 }
250
251 memset(&Cmd, 0, sizeof(citimap_command));
252 Cmd.CmdBuf = NewStrBufPlain(NULL, StrLength(IMAP->Cmd.CmdBuf));
253 MakeStringOf(Cmd.CmdBuf, 4);
254
255 num_items = imap_extract_data_items(&Cmd);
256 if (num_items < 1) {
257 IReply("BAD invalid data item list");
258 FreeStrBuf(&Cmd.CmdBuf);
259 free(Cmd.Params);
260 return;
261 }
262
263 imap_do_store(&Cmd);
264 IReply("OK UID STORE completed");
265 FreeStrBuf(&Cmd.CmdBuf);
266 free(Cmd.Params);
267}
268
269
void imap_pick_range(const char *supplied_range, int is_uid)
Definition: imap_fetch.c:1314
int imap_extract_data_items(citimap_command *Cmd)
Definition: imap_fetch.c:1218
void imap_fetch_flags(int seq)
Definition: imap_fetch.c:60
void imap_store(int num_parms, ConstStr *Params)
Definition: imap_store.c:196
void imap_do_store(citimap_command *Cmd)
Definition: imap_store.c:81
void imap_do_store_msg(int seq, const char *oper, unsigned int bits_to_twiddle)
Definition: imap_store.c:61
void imap_uidstore(int num_parms, ConstStr *Params)
Definition: imap_store.c:234
int imap_is_message_set(const char *buf)
Definition: imap_tools.c:690
void MakeStringOf(StrBuf *Buf, int skip)
Definition: imap_tools.c:383
void IAPrintf(const char *Format,...)
Definition: imap_tools.c:898
#define IAPuts(Msg)
Definition: imap_tools.h:39
#define IReply(msg)
Definition: imap_tools.h:45
void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, int target_setting, int which_set, struct ctdluser *which_user, struct ctdlroom *which_room)
Definition: msgbase.c:409
@ ctdlsetseen_seen
Definition: msgbase.h:176
@ ctdlsetseen_answered
Definition: msgbase.h:177
void * malloc(size_t)
void free(void *)
int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void)
Definition: room_ops.c:109
void imap_rescan_msgids(void)
Definition: serv_imap.c:321
int imap_do_expunge(void)
Definition: serv_imap.c:922
#define IMAP_SELECTED
Definition: serv_imap.h:90
#define IMAP_ANSWERED
Definition: serv_imap.h:81
#define IMAP_DELETED
Definition: serv_imap.h:83
#define IMAP_MASK_SYSTEM
Definition: serv_imap.h:88
#define IMAP
Definition: serv_imap.h:104
#define IMAP_SEEN
Definition: serv_imap.h:85
ConstStr * Params
Definition: serv_imap.h:30
StrBuf * CmdBuf
Definition: serv_imap.h:29
unsigned int * flags
Definition: serv_imap.h:47
int num_msgs
Definition: serv_imap.h:43
long * msgids
Definition: serv_imap.h:46