I had some time while waiting for paint to dry, so I whipped up this quick patch for shared seen state, based on our previous discussions. It uses a "/vendor/cmu/cyrus-imapd/sharedseen" mailbox annotation, stored as a mailbox option in the index header, to enable/disable shared seen state, and stores the shared seen state in "anyone.seen". Note that this patch is completely untested, although it compiles against CVS. I also didn't consider replication yet.

Feel free to try this and see if it has the intended behavior. Remember that the 's' ACL right controls whether a person can change the \Seen flag on a message.


Boris Lytochkin wrote:
Hello!

I need an advice in implementing per-mailbox \Seen flag (or 'shared'
\Seen flag in per-user basis).

For now I want to implement it this way:
1) add a new mailbox attribute, say 'sharedseen'
2) switch path for .seen file in imap/seen_*.c:seen_getpath() if
   'sharedseen' flag is set on mailbox.
3) changes in replication module?

So, setting 'sharedseen' attribute to mailbox will cause using
per-mailbox seen-file.

What are weak points of this implementation?
Is there more correct way to make per-mailbox \Seen flag?




--
Kenneth Murchison
Systems Programmer
Project Cyrus Developer/Maintainer
Carnegie Mellon University
Index: annotate.c
===================================================================
RCS file: /afs/andrew/system/cvs/src/cyrus/imap/annotate.c,v
retrieving revision 1.36
diff -u -r1.36 annotate.c
--- annotate.c	15 Aug 2007 17:20:55 -0000	1.36
+++ annotate.c	1 Sep 2007 18:00:26 -0000
@@ -869,20 +869,20 @@
     output_entryatt(ext_mboxname, entry, "", &attrib, fdata);
 }
 
-static void annotation_get_condstore(const char *int_mboxname,
-				     const char *ext_mboxname,
-				     const char *entry,
-				     struct fetchdata *fdata,
-				     struct mailbox_annotation_rock *mbrock,
-				     void *rock __attribute__((unused)))
+static void annotation_get_mailboxopt(const char *int_mboxname,
+				      const char *ext_mboxname,
+				      const char *entry,
+				      struct fetchdata *fdata,
+				      struct mailbox_annotation_rock *mbrock,
+				      void *rock __attribute__((unused)))
 { 
     struct mailbox mailbox;
-    int r = 0;
+    int flag, r = 0;
     char value[40];
     struct annotation_data attrib;
   
-    if(!int_mboxname || !ext_mboxname || !fdata || !mbrock)
-      fatal("annotation_get_condstore called with bad parameters",
+    if(!int_mboxname || !ext_mboxname || !entry || !fdata || !mbrock)
+      fatal("annotation_get_mailboxopt called with bad parameters",
               EC_TEMPFAIL);
 
     get_mb_data(int_mboxname, mbrock);
@@ -890,6 +890,15 @@
     /* Make sure its a local mailbox */
     if (mbrock->server) return;
 
+    /* Check entry */
+    if (!strcmp(entry, "/vendor/cmu/cyrus-imapd/condstore")) {
+	flag = OPT_IMAP_CONDSTORE;
+    } else if (!strcmp(entry, "/vendor/cmu/cyrus-imapd/sharedseen")) {
+	flag = OPT_IMAP_SHAREDSEEN;
+    } else {
+	return;
+    }
+  
     /* Check ACL */
     if(!fdata->isadmin &&
        (!mbrock->acl ||
@@ -906,7 +915,7 @@
     }
 
     if (!r) {
-      if (mailbox.options & OPT_IMAP_CONDSTORE) {
+      if (mailbox.options & flag) {
           strcpy(value, "true");
       } else {
           strcpy(value, "false");
@@ -1017,7 +1026,9 @@
     { "/vendor/cmu/cyrus-imapd/lastpop", BACKEND_ONLY,
       annotation_get_lastpop, NULL },
     { "/vendor/cmu/cyrus-imapd/condstore", BACKEND_ONLY,
-      annotation_get_condstore, NULL },
+      annotation_get_mailboxopt, NULL },
+    { "/vendor/cmu/cyrus-imapd/sharedseen", BACKEND_ONLY,
+      annotation_get_mailboxopt, NULL },
     { NULL, ANNOTATION_PROXY_T_INVALID, NULL, NULL }
 };
 
@@ -1694,14 +1705,23 @@
     return r;
 }
 
-static int annotation_set_condstore(const char *int_mboxname,
-				    struct annotate_st_entry_list *entry,
-				    struct storedata *sdata,
-				    struct mailbox_annotation_rock *mbrock,
-				    void *rock __attribute__((unused)))
+static int annotation_set_mailboxopt(const char *int_mboxname,
+				     struct annotate_st_entry_list *entry,
+				     struct storedata *sdata,
+				     struct mailbox_annotation_rock *mbrock,
+				     void *rock __attribute__((unused)))
 {
     struct mailbox mailbox;
-    int r = 0;
+    int flag, r = 0;
+
+    /* Check entry */
+    if (!strcmp(entry->entry->name, "/vendor/cmu/cyrus-imapd/condstore")) {
+	flag = OPT_IMAP_CONDSTORE;
+    } else if (!strcmp(entry->entry->name, "/vendor/cmu/cyrus-imapd/sharedseen")) {
+	flag = OPT_IMAP_SHAREDSEEN;
+    } else {
+	return IMAP_PERMISSION_DENIED;
+    }
   
     /* Check ACL */
     if(!sdata->isadmin &&
@@ -1717,9 +1737,9 @@
 
     if (!r) {
 	if (!strcmp(entry->shared.value, "true")) {
-	    mailbox.options |= OPT_IMAP_CONDSTORE;
+	    mailbox.options |= flag;
 	} else {
-	    mailbox.options &= ~OPT_IMAP_CONDSTORE;
+	    mailbox.options &= ~flag;
 	}
 
 	r = mailbox_write_index_header(&mailbox);
@@ -1793,7 +1813,10 @@
       ACL_ADMIN, annotation_set_todb, NULL },
     { "/vendor/cmu/cyrus-imapd/condstore", ATTRIB_TYPE_BOOLEAN, BACKEND_ONLY,
       ATTRIB_VALUE_SHARED | ATTRIB_CONTENTTYPE_SHARED,
-      ACL_ADMIN, annotation_set_condstore, NULL },
+      ACL_ADMIN, annotation_set_mailboxopt, NULL },
+    { "/vendor/cmu/cyrus-imapd/sharedseen", ATTRIB_TYPE_BOOLEAN, BACKEND_ONLY,
+      ATTRIB_VALUE_SHARED | ATTRIB_CONTENTTYPE_SHARED,
+      ACL_ADMIN, annotation_set_mailboxopt, NULL },
     { NULL, 0, ANNOTATION_PROXY_T_INVALID, 0, 0, NULL, NULL }
 };
 
Index: append.c
===================================================================
RCS file: /afs/andrew/system/cvs/src/cyrus/imap/append.c,v
retrieving revision 1.110
diff -u -r1.110 append.c
--- append.c	5 Feb 2007 18:41:45 -0000	1.110
+++ append.c	1 Sep 2007 18:00:26 -0000
@@ -1091,7 +1091,9 @@
     /* what's the first uid in our new list? */
     start = atoi(msgrange);
 
-    r = seen_open(mailbox, userid, SEEN_CREATE, &seendb);
+    r = seen_open(mailbox,
+		  (mailbox->options & OPT_IMAP_SHAREDSEEN) ? "anyone" : userid,
+		  SEEN_CREATE, &seendb);
     if (r) return r;
     
     r = seen_lockread(seendb, &last_read, &last_uid, &last_change, &seenuids);
Index: index.c
===================================================================
RCS file: /afs/andrew/system/cvs/src/cyrus/imap/index.c,v
retrieving revision 1.226
diff -u -r1.226 index.c
--- index.c	2 Aug 2007 14:18:52 -0000	1.226
+++ index.c	1 Sep 2007 18:00:26 -0000
@@ -367,7 +367,10 @@
 
     /* If opening mailbox, get \Recent info */
     if (oldexists == -1 && mailbox->keepingseen) {
-	r = seen_open(mailbox, imapd_userid, SEEN_CREATE, &seendb);
+	r = seen_open(mailbox,
+		      (mailbox->options & OPT_IMAP_SHAREDSEEN) ? "anyone" :
+		      imapd_userid,
+		      SEEN_CREATE, &seendb);
 	if (!r) {
 	    free(seenuids);
 	    seenuids = NULL;
@@ -1481,7 +1484,10 @@
     if (mailbox->exists != 0 &&
 	(statusitems &
 	 (STATUS_RECENT | STATUS_UNSEEN))) {
-	r = seen_open(mailbox, imapd_userid, SEEN_CREATE, &status_seendb);
+	r = seen_open(mailbox,
+		      (mailbox->options & OPT_IMAP_SHAREDSEEN) ? "anyone" :
+		      imapd_userid,
+		      SEEN_CREATE, &status_seendb);
 	if (r) return r;
 
 	r = seen_lockread(status_seendb, &last_read, &last_uid,
Index: mailbox.h
===================================================================
RCS file: /afs/andrew/system/cvs/src/cyrus/imap/mailbox.h,v
retrieving revision 1.83
diff -u -r1.83 mailbox.h
--- mailbox.h	30 Aug 2007 14:25:08 -0000	1.83
+++ mailbox.h	1 Sep 2007 18:00:27 -0000
@@ -255,6 +255,7 @@
 
 #define OPT_POP3_NEW_UIDL (1<<0)	/* added for Outlook stupidity */
 #define OPT_IMAP_CONDSTORE (1<<1)	/* added for CONDSTORE extension */
+#define OPT_IMAP_SHAREDSEEN (1<<2)	/* added for shared \Seen state */
 
 
 struct mailbox_header_cache {

Reply via email to