Experimental changes to the default theme. Gradient
[citadel.git] / citadel / imap_store.c
index 0cddb669e2dd40b0c38c982e3a68fc27f53f5462..7e163787b227a2880ff548426e23721fdaf61edc 100644 (file)
@@ -37,7 +37,6 @@
 #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;
@@ -72,57 +74,129 @@ void imap_do_store_msg(int seq, char *oper, unsigned int 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();
+       }
+
 }