#include <pwd.h>
#include <errno.h>
#include <sys/types.h>
-#include <sys/time.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
#include <sys/wait.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include "citadel.h"
#include "server.h"
-#include <time.h>
#include "sysdep_decls.h"
#include "citserver.h"
#include "support.h"
#include "config.h"
-#include "dynloader.h"
+#include "serv_extensions.h"
#include "room_ops.h"
#include "user_ops.h"
#include "policy.h"
#include "genstamp.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 num, int num_items, char **itemlist) {
- int i;
- int flagbucket = 0;
-
- /* at this point it should be down to "item (flags)" */
- if (num_items < 2) return;
+void imap_do_store_msg(int seq, char *oper, unsigned int bits_to_twiddle) {
+ int silent = 0;
- /* put together the flag bucket */
- for (i=0; i<strlen(itemlist[1]); ++i) {
- if (!strncasecmp(&itemlist[1][i], "\\Deleted", 8))
- flagbucket |= IMAP_DELETED;
+ if (!strncasecmp(oper, "FLAGS", 5)) {
+ IMAP->flags[seq] &= IMAP_MASK_SYSTEM;
+ IMAP->flags[seq] |= bits_to_twiddle;
+ silent = strncasecmp(&oper[5], ".SILENT", 7);
}
-
- /*
- * Figure out what to do and do it. Brazenly IGnore the ".SILENT"
- * option, since it is not illegal to output the data anyway.
- */
- if (!strncasecmp(itemlist[0], "FLAGS", 5)) {
- IMAP->flags[num] &= IMAP_INTERNAL_MASK;
- IMAP->flags[num] |= flagbucket;
+ else if (!strncasecmp(oper, "+FLAGS", 6)) {
+ IMAP->flags[seq] |= bits_to_twiddle;
+ silent = strncasecmp(&oper[6], ".SILENT", 7);
}
-
- if (!strncasecmp(itemlist[0], "+FLAGS", 6)) {
- IMAP->flags[num] |= flagbucket;
+ else if (!strncasecmp(oper, "-FLAGS", 6)) {
+ IMAP->flags[seq] &= (~bits_to_twiddle);
+ silent = strncasecmp(&oper[6], ".SILENT", 7);
}
- if (!strncasecmp(itemlist[0], "-FLAGS", 6)) {
- IMAP->flags[num] &= ~flagbucket;
+ if (bits_to_twiddle & IMAP_SEEN) {
+ CtdlSetSeen(IMAP->msgids[seq],
+ ((IMAP->flags[seq] & IMAP_SEEN) ? 1 : 0),
+ ctdlsetseen_seen,
+ NULL, NULL
+ );
+ }
+ if (bits_to_twiddle & IMAP_ANSWERED) {
+ CtdlSetSeen(IMAP->msgids[seq],
+ ((IMAP->flags[seq] & IMAP_ANSWERED) ? 1 : 0),
+ ctdlsetseen_answered,
+ NULL, NULL
+ );
}
- /*
- * Tell the client what happen (someone set up us the bomb!)
+ /* 'silent' is actually the value returned from a strncasecmp() so
+ * we want that option only if its value is zero. Seems backwards
+ * but that's the way it's supposed to be.
*/
- cprintf("* %d FETCH ", num+1); /* output sequence number */
- imap_output_flags(num);
- cprintf("\r\n");
+ if (silent) {
+ cprintf("* %d FETCH (", seq+1);
+ imap_fetch_flags(seq);
+ cprintf(")\r\n");
+ }
}
/*
- * imap_store() calls imap_do_store() to do its actual work, once it's
- * validated and boiled down the request a bit.
+ * imap_store() calls imap_do_store() to perform the actual bit twiddling
+ * on the flags.
*/
-void imap_do_store(int num_items, char **itemlist, int is_uid) {
- int i;
+void imap_do_store(int num_items, char **itemlist) {
+ int i, j;
+ unsigned int bits_to_twiddle = 0;
+ char *oper;
+ char flag[32];
+ char whichflags[256];
+ char num_flags;
+
+ if (num_items < 2) return;
+ oper = itemlist[0];
+
+ for (i=1; i<num_items; ++i) {
+ strcpy(whichflags, itemlist[i]);
+ if (whichflags[0]=='(') safestrncpy(whichflags, &whichflags[1], sizeof whichflags);
+ 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) {
- imap_do_store_msg(i, num_items, itemlist);
+ if (IMAP->flags[i] & IMAP_SELECTED) {
+ imap_do_store_msg(i, oper, bits_to_twiddle);
}
}
}
+
+ /*
+ * The following two commands implement "instant expunge" if enabled.
+ */
+ if (config.c_instant_expunge) {
+ imap_do_expunge();
+ imap_rescan_msgids();
+ }
+
}
int num_items;
int i;
- if (num_parms < 4) {
+ if (num_parms < 3) {
cprintf("%s BAD invalid parameters\r\n", parms[0]);
return;
}
imap_pick_range(parms[2], 0);
}
else {
- cprintf("%s BAD No message set specified to STORE\r\n",
- parms[0]);
+ cprintf("%s BAD invalid parameters\r\n", parms[0]);
return;
}
return;
}
- imap_do_store(num_items, itemlist, 0);
+ imap_do_store(num_items, itemlist);
cprintf("%s OK STORE completed\r\n", parms[0]);
}
int num_items;
int i;
- if (num_parms < 5) {
+ if (num_parms < 4) {
cprintf("%s BAD invalid parameters\r\n", parms[0]);
return;
}
imap_pick_range(parms[3], 1);
}
else {
- cprintf("%s BAD No message set specified to STORE\r\n",
- parms[0]);
+ cprintf("%s BAD invalid parameters\r\n", parms[0]);
return;
}
return;
}
- imap_do_store(num_items, itemlist, 1);
+ imap_do_store(num_items, itemlist);
cprintf("%s OK UID STORE completed\r\n", parms[0]);
}