#include "citserver.h"
#include "support.h"
#include "config.h"
-#include "serv_extensions.h"
#include "room_ops.h"
#include "user_ops.h"
#include "policy.h"
/*
- * imap_do_store() calls imap_do_store_msg() to output the deta of an
- * individual message, once it has been successfully loaded from disk.
+ * imap_do_store() calls imap_do_store_msg() to tweak the settings of
+ * an individual message.
+ *
+ * We also implement the ".SILENT" protocol option here. :(
*/
void imap_do_store_msg(int seq, char *oper, unsigned int bits_to_twiddle) {
-
+
+
if (!strncasecmp(oper, "FLAGS", 5)) {
IMAP->flags[seq] &= IMAP_MASK_SYSTEM;
IMAP->flags[seq] |= bits_to_twiddle;
else if (!strncasecmp(oper, "-FLAGS", 6)) {
IMAP->flags[seq] &= (~bits_to_twiddle);
}
-
- if (bits_to_twiddle & IMAP_SEEN) {
- CtdlSetSeen(IMAP->msgids[seq],
- ((IMAP->flags[seq] & IMAP_SEEN) ? 1 : 0) );
- }
-
- cprintf("* %d FETCH (", seq+1);
- imap_fetch_flags(seq);
- cprintf(")\r\n");
}
/*
* imap_store() calls imap_do_store() to perform the actual bit twiddling
- * on flags. We brazenly ignore the ".silent" protocol option because it's not
- * harmful to send the data anyway. Fix it yourself if you don't like that.
+ * on the flags.
*/
void imap_do_store(int num_items, char **itemlist) {
- int i;
+ int i, j;
unsigned int bits_to_twiddle = 0;
char *oper;
- char flag[SIZ];
+ char flag[32];
+ char whichflags[256];
+ char num_flags;
+ int silent = 0;
+ long *ss_msglist;
+ int num_ss = 0;
+ int last_item_twiddled = (-1);
if (num_items < 2) return;
oper = itemlist[0];
+ if (bmstrcasestr(oper, ".SILENT")) {
+ silent = 1;
+ }
+
+ /*
+ * ss_msglist is an array of message numbers to manipulate. We
+ * are going to supply this array to CtdlSetSeen() later.
+ */
+ ss_msglist = malloc(IMAP->num_msgs * sizeof(long));
+ if (ss_msglist == NULL) return;
+ /*
+ * Ok, go ahead and parse the flags.
+ */
for (i=1; i<num_items; ++i) {
- strcpy(flag, itemlist[i]);
- if (flag[0]=='(') strcpy(flag, &flag[1]);
- if (flag[strlen(flag)-1]==')') flag[strlen(flag)-1]=0;
- striplt(flag);
-
- if (!strcasecmp(flag, "\\Deleted")) {
- if (CtdlDoIHavePermissionToDeleteMessagesFromThisRoom()) {
- bits_to_twiddle |= IMAP_DELETED;
- }
+ strcpy(whichflags, itemlist[i]);
+ if (whichflags[0]=='(') {
+ safestrncpy(whichflags, &whichflags[1],
+ sizeof whichflags);
}
-
- if (!strcasecmp(flag, "\\Seen")) {
- bits_to_twiddle |= IMAP_SEEN;
+ if (whichflags[strlen(whichflags)-1]==')') {
+ whichflags[strlen(whichflags)-1]=0;
+ }
+ striplt(whichflags);
+
+ /* A client might twiddle more than one bit at a time.
+ * Note that we check for the flag names without the leading
+ * backslash because imap_parameterize() strips them out.
+ */
+ num_flags = num_tokens(whichflags, ' ');
+ for (j=0; j<num_flags; ++j) {
+ extract_token(flag, whichflags, j, ' ', sizeof flag);
+
+ if ((!strcasecmp(flag, "\\Deleted"))
+ || (!strcasecmp(flag, "Deleted"))) {
+ if (CtdlDoIHavePermissionToDeleteMessagesFromThisRoom()) {
+ bits_to_twiddle |= IMAP_DELETED;
+ }
+ }
+ if ((!strcasecmp(flag, "\\Seen"))
+ || (!strcasecmp(flag, "Seen"))) {
+ bits_to_twiddle |= IMAP_SEEN;
+ }
+ if ((!strcasecmp(flag, "\\Answered"))
+ || (!strcasecmp(flag, "\\Answered"))) {
+ bits_to_twiddle |= IMAP_ANSWERED;
+ }
}
}
-
+
if (IMAP->num_msgs > 0) {
for (i = 0; i < IMAP->num_msgs; ++i) {
if (IMAP->flags[i] & IMAP_SELECTED) {
+ last_item_twiddled = i;
+
+ ss_msglist[num_ss++] = IMAP->msgids[i];
imap_do_store_msg(i, oper, bits_to_twiddle);
+
+ if (!silent) {
+ cprintf("* %d FETCH (", i+1);
+ imap_fetch_flags(i);
+ cprintf(")\r\n");
+ }
+
}
}
}
+
+ /*
+ * Now manipulate the database -- all in one shot.
+ */
+ if ( (last_item_twiddled >= 0) && (num_ss > 0) ) {
+
+ if (bits_to_twiddle & IMAP_SEEN) {
+ CtdlSetSeen(ss_msglist, num_ss,
+ ((IMAP->flags[last_item_twiddled] & IMAP_SEEN) ? 1 : 0),
+ ctdlsetseen_seen,
+ NULL, NULL
+ );
+ }
+
+ if (bits_to_twiddle & IMAP_ANSWERED) {
+ CtdlSetSeen(ss_msglist, num_ss,
+ ((IMAP->flags[last_item_twiddled] & IMAP_ANSWERED) ? 1 : 0),
+ ctdlsetseen_answered,
+ NULL, NULL
+ );
+ }
+
+ }
+
+ free(ss_msglist);
+
+ /*
+ * The following two commands implement "instant expunge" if enabled.
+ */
+ if (config.c_instant_expunge) {
+ imap_do_expunge();
+ imap_rescan_msgids();
+ }
+
}