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 {