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)  

Loading...
Searching...
No Matches
imap_store.c
Go to the documentation of this file.
1// Implements the STORE command in IMAP.
2//
3// Copyright (c) 1987-2022 by the citadel.org team
4//
5// This program is open source software. Use, duplication, or disclosure
6// is subject to the terms of the GNU General Public License, version 3.
7
8#include "../../ctdl_module.h"
9
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#include <time.h>
19#include <sys/wait.h>
20#include <ctype.h>
21#include <string.h>
22#include <limits.h>
23#include <libcitadel.h>
24#include "../../citadel.h"
25#include "../../server.h"
26#include "../../sysdep_decls.h"
27#include "../../citserver.h"
28#include "../../support.h"
29#include "../../config.h"
30#include "../../user_ops.h"
31#include "../../database.h"
32#include "../../room_ops.h"
33#include "../../msgbase.h"
34#include "../../internet_addressing.h"
35#include "serv_imap.h"
36#include "imap_tools.h"
37#include "imap_fetch.h"
38#include "imap_store.h"
39#include "../../genstamp.h"
40
41
42// imap_do_store() calls imap_do_store_msg() to tweak the settings of
43// an individual message.
44//
45// We also implement the ".SILENT" protocol option here. :(
46void imap_do_store_msg(int seq, const char *oper, unsigned int bits_to_twiddle) {
47 citimap *Imap = IMAP;
48
49 if (!strncasecmp(oper, "FLAGS", 5)) {
50 Imap->flags[seq] &= IMAP_MASK_SYSTEM;
51 Imap->flags[seq] |= bits_to_twiddle;
52 }
53 else if (!strncasecmp(oper, "+FLAGS", 6)) {
54 Imap->flags[seq] |= bits_to_twiddle;
55 }
56 else if (!strncasecmp(oper, "-FLAGS", 6)) {
57 Imap->flags[seq] &= (~bits_to_twiddle);
58 }
59}
60
61
62// imap_store() calls imap_do_store() to perform the actual bit twiddling
63// on the flags.
65 int i, j;
66 unsigned int bits_to_twiddle = 0;
67 const char *oper;
68 char flag[32];
69 char whichflags[256];
70 char num_flags;
71 int silent = 0;
72 long *ss_msglist;
73 int num_ss = 0;
74 int last_item_twiddled = (-1);
75 citimap *Imap = IMAP;
76
77 if (Cmd->num_parms < 2) return;
78 oper = Cmd->Params[0].Key;
79 if (cbmstrcasestr(oper, ".SILENT")) {
80 silent = 1;
81 }
82
83 // ss_msglist is an array of message numbers to manipulate. We are going to supply this array to CtdlSetSeen() later.
84 ss_msglist = malloc(Imap->num_msgs * sizeof(long));
85 if (ss_msglist == NULL) return;
86
87 // Ok, go ahead and parse the flags.
88 for (i=1; i<Cmd->num_parms; ++i) {
89 strcpy(whichflags, Cmd->Params[i].Key);
90 if (whichflags[0]=='(') {
91 safestrncpy(whichflags, &whichflags[1],
92 sizeof whichflags);
93 }
94 if (whichflags[strlen(whichflags)-1]==')') {
95 whichflags[strlen(whichflags)-1]=0;
96 }
97 string_trim(whichflags);
98
99 // A client might twiddle more than one bit at a time.
100 // Note that we check for the flag names without the leading
101 // backslash because imap_parameterize() strips them out.
102 num_flags = num_tokens(whichflags, ' ');
103 for (j=0; j<num_flags; ++j) {
104 extract_token(flag, whichflags, j, ' ', sizeof flag);
105
106 if ((!strcasecmp(flag, "\\Deleted"))
107 || (!strcasecmp(flag, "Deleted"))) {
109 bits_to_twiddle |= IMAP_DELETED;
110 }
111 }
112 if ((!strcasecmp(flag, "\\Seen"))
113 || (!strcasecmp(flag, "Seen"))) {
114 bits_to_twiddle |= IMAP_SEEN;
115 }
116 if ((!strcasecmp(flag, "\\Answered"))
117 || (!strcasecmp(flag, "Answered"))) {
118 bits_to_twiddle |= IMAP_ANSWERED;
119 }
120 }
121 }
122
123 if (Imap->num_msgs > 0) {
124 for (i = 0; i < Imap->num_msgs; ++i) {
125 if (Imap->flags[i] & IMAP_SELECTED) {
126 last_item_twiddled = i;
127
128 ss_msglist[num_ss++] = Imap->msgids[i];
129 imap_do_store_msg(i, oper, bits_to_twiddle);
130
131 if (!silent) {
132 IAPrintf("* %d FETCH (", i+1);
134 IAPuts(")\r\n");
135 }
136
137 }
138 }
139 }
140
141 // Now manipulate the database -- all in one shot.
142 if ( (last_item_twiddled >= 0) && (num_ss > 0) ) {
143
144 if (bits_to_twiddle & IMAP_SEEN) {
145 CtdlSetSeen(ss_msglist, num_ss,
146 ((Imap->flags[last_item_twiddled] & IMAP_SEEN) ? 1 : 0),
148 NULL, NULL
149 );
150 }
151
152 if (bits_to_twiddle & IMAP_ANSWERED) {
153 CtdlSetSeen(ss_msglist, num_ss,
154 ((Imap->flags[last_item_twiddled] & IMAP_ANSWERED) ? 1 : 0),
156 NULL, NULL
157 );
158 }
159
160 }
161
162 free(ss_msglist);
163 imap_do_expunge(); // Citadel always expunges immediately.
165}
166
167
168// This function is called by the main command loop.
169void imap_store(int num_parms, ConstStr *Params) {
170 citimap_command Cmd;
171 int num_items;
172
173 if (num_parms < 3) {
174 IReply("BAD invalid parameters");
175 return;
176 }
177
178 if (imap_is_message_set(Params[2].Key)) {
179 imap_pick_range(Params[2].Key, 0);
180 }
181 else {
182 IReply("BAD invalid parameters");
183 return;
184 }
185
186 memset(&Cmd, 0, sizeof(citimap_command));
187 Cmd.CmdBuf = NewStrBufPlain(NULL, StrLength(IMAP->Cmd.CmdBuf));
188 MakeStringOf(Cmd.CmdBuf, 3);
189
190 num_items = imap_extract_data_items(&Cmd);
191 if (num_items < 1) {
192 IReply("BAD invalid data item list");
193 FreeStrBuf(&Cmd.CmdBuf);
194 free(Cmd.Params);
195 return;
196 }
197
198 imap_do_store(&Cmd);
199 IReply("OK STORE completed");
200 FreeStrBuf(&Cmd.CmdBuf);
201 free(Cmd.Params);
202}
203
204// This function is called by the main command loop.
205void imap_uidstore(int num_parms, ConstStr *Params) {
206 citimap_command Cmd;
207 int num_items;
208
209 if (num_parms < 4) {
210 IReply("BAD invalid parameters");
211 return;
212 }
213
214 if (imap_is_message_set(Params[3].Key)) {
215 imap_pick_range(Params[3].Key, 1);
216 }
217 else {
218 IReply("BAD invalid parameters");
219 return;
220 }
221
222 memset(&Cmd, 0, sizeof(citimap_command));
223 Cmd.CmdBuf = NewStrBufPlain(NULL, StrLength(IMAP->Cmd.CmdBuf));
224 MakeStringOf(Cmd.CmdBuf, 4);
225
226 num_items = imap_extract_data_items(&Cmd);
227 if (num_items < 1) {
228 IReply("BAD invalid data item list");
229 FreeStrBuf(&Cmd.CmdBuf);
230 free(Cmd.Params);
231 return;
232 }
233
234 imap_do_store(&Cmd);
235 IReply("OK UID STORE completed");
236 FreeStrBuf(&Cmd.CmdBuf);
237 free(Cmd.Params);
238}
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:169
void imap_do_store(citimap_command *Cmd)
Definition: imap_store.c:64
void imap_do_store_msg(int seq, const char *oper, unsigned int bits_to_twiddle)
Definition: imap_store.c:46
void imap_uidstore(int num_parms, ConstStr *Params)
Definition: imap_store.c:205
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:404
@ ctdlsetseen_seen
Definition: msgbase.h:176
@ ctdlsetseen_answered
Definition: msgbase.h:177
void * malloc(unsigned)
void free(void *)
int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void)
Definition: room_ops.c:88
void imap_rescan_msgids(void)
Definition: serv_imap.c:294
int imap_do_expunge(void)
Definition: serv_imap.c:864
#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