* Finished the implementation of per-message seen/unseen logic, both in the
authorArt Cancro <ajc@citadel.org>
Thu, 26 Apr 2001 03:31:03 +0000 (03:31 +0000)
committerArt Cancro <ajc@citadel.org>
Thu, 26 Apr 2001 03:31:03 +0000 (03:31 +0000)
  server proper and in IMAP.  Citadel protocol uses new "seen" command.

citadel/ChangeLog
citadel/citserver.c
citadel/imap_store.c
citadel/msgbase.c
citadel/msgbase.h
citadel/techdoc/session.txt
citadel/user_ops.c
citadel/user_ops.h

index 014b9851690d6ce14c93086db24fc6f7c02dbe3d..a78654c52b1abd9294e0eb917aee43f53ebe1a11 100644 (file)
@@ -1,4 +1,8 @@
  $Log$
+ Revision 573.130  2001/04/26 03:31:00  ajc
+ * Finished the implementation of per-message seen/unseen logic, both in the
+   server proper and in IMAP.  Citadel protocol uses new "seen" command.
+
  Revision 573.129  2001/04/21 04:55:51  ajc
  * Began implementation of per-message seen/unseen attribute
 
@@ -2509,3 +2513,4 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
        * Initial CVS import 
+
index d63c092cf93be00bc0ebd262d8ccd79cc3fa7c3e..c39c817eed4ca9924c6b2c56e1e1859537b1ada2 100644 (file)
@@ -1191,6 +1191,10 @@ void do_command_loop(void) {
                cmd_conf(&cmdbuf[5]);
                }
 
+       else if (!strncasecmp(cmdbuf, "SEEN", 4)) {
+               cmd_seen(&cmdbuf[5]);
+               }
+
 #ifdef DEBUG_MEMORY_LEAKS
        else if (!strncasecmp(cmdbuf, "LEAK", 4)) {
                dump_tracked();
index d688bcc2304719714e15c0421408156ab3278f53..171b1f26cd2dcec8301beaa296315f8c52ca9fe8 100644 (file)
@@ -63,6 +63,11 @@ void imap_do_store_msg(int seq, char *oper, unsigned int bits_to_twiddle) {
                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");
@@ -95,6 +100,10 @@ void imap_do_store(int num_items, char **itemlist) {
                        bits_to_twiddle |= IMAP_DELETED;
                  }
                }
+
+               if (!strcasecmp(flag, "\\Seen")) {
+                       bits_to_twiddle |= IMAP_SEEN;
+               }
        }
        
        if (IMAP->num_msgs > 0) {
index b7533685ce112792aea83b66041b8f849f7b9544..fed836cbd1b2e65f082601daed5f87a4aba523bd 100644 (file)
@@ -266,6 +266,81 @@ int CtdlMsgCmp(struct CtdlMessage *msg, struct CtdlMessage *template) {
 }
 
 
+/*
+ * Manipulate the "seen msgs" string.
+ */
+void CtdlSetSeen(long target_msgnum, int target_setting) {
+       char newseen[SIZ];
+       struct cdbdata *cdbfr;
+       int i;
+       int is_seen = 0;
+       int was_seen = 1;
+       long lo = (-1L);
+       long hi = (-1L);
+       struct visit vbuf;
+       long *msglist;
+       int num_msgs = 0;
+
+       /* Learn about the user and room in question */
+       get_mm();
+       getuser(&CC->usersupp, CC->curr_user);
+       CtdlGetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
+
+       /* Load the message list */
+       cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->quickroom.QRnumber, sizeof(long));
+       if (cdbfr != NULL) {
+               msglist = mallok(cdbfr->len);
+               memcpy(msglist, cdbfr->ptr, cdbfr->len);
+               num_msgs = cdbfr->len / sizeof(long);
+               cdb_free(cdbfr);
+       } else {
+               return; /* No messages at all?  No further action. */
+       }
+
+       lprintf(9, "before optimize: %s\n", vbuf.v_seen);
+       strcpy(newseen, "");
+
+       for (i=0; i<num_msgs; ++i) {
+               is_seen = 0;
+
+               if (msglist[i] == target_msgnum) {
+                       is_seen = target_setting;
+               }
+               else {
+                       if (is_msg_in_mset(vbuf.v_seen, msglist[i])) {
+                               is_seen = 1;
+                       }
+               }
+
+               if (is_seen == 1) {
+                       if (lo < 0L) lo = msglist[i];
+                       hi = msglist[i];
+               }
+               if (  ((is_seen == 0) && (was_seen == 1))
+                  || ((is_seen == 1) && (i == num_msgs-1)) ) {
+                       if ( (strlen(newseen) + 20) > SIZ) {
+                               strcpy(newseen, &newseen[20]);
+                               newseen[0] = '*';
+                       }
+                       if (strlen(newseen) > 0) strcat(newseen, ",");
+                       if (lo == hi) {
+                               sprintf(&newseen[strlen(newseen)], "%ld", lo);
+                       }
+                       else {
+                               sprintf(&newseen[strlen(newseen)], "%ld:%ld",
+                                       lo, hi);
+                       }
+                       lo = (-1L);
+                       hi = (-1L);
+               }
+               was_seen = is_seen;
+       }
+
+       safestrncpy(vbuf.v_seen, newseen, SIZ);
+       lprintf(9, " after optimize: %s\n", vbuf.v_seen);
+       phree(msglist);
+       CtdlSetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
+}
 
 
 /*
@@ -308,6 +383,9 @@ int CtdlForEachMessage(int mode, long ref,
        }
 
 
+       /*
+        * Now begin the traversal.
+        */
        if (num_msgs > 0) for (a = 0; a < num_msgs; ++a) {
                GetSuppMsgInfo(&smi, msglist[a]);
 
index f515e188cc147cc19ed08dbb4cb283bc36c4711d..26201d17ecc994b2ecdb4e7049875d284b4a7b6b 100644 (file)
@@ -103,3 +103,4 @@ int CtdlOutputPreLoadedMsg(struct CtdlMessage *,
 int CtdlCopyMsgToRoom(long msgnum, char *dest);
 int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void);
 int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf);
+void CtdlSetSeen(long target_msgnum, int target_setting);
index 6df534eb73d4a921a12c70ba1bba5f98341508e6..eda0ff0421fedd7066a77e9191c40e86039152a8 100644 (file)
@@ -1825,7 +1825,22 @@ issue a REQT command, then wait a little while (from 30 seconds up to a few
 minutes) for well-behaved clients to voluntarily terminate, and then issue a
 TERM command to forcibly disconnect the client (or perhaps a DOWN command, if
 you are logging off users for the purpose of shutting down the server).
-    
+ SEEN   (set or clear the SEEN flag for a message)
+ Beginning with version 5.80, Citadel supports the concept of setting or
+clearing the "seen" flag for each individual message, instead of only allowing
+a "last seen" pointer.  In fact, the old semantics are implemented in terms
+of the new semantics.  This command requires two arguments: the number of the
+message to be set, and a 1 or 0 to set or clear the "seen" bit.
+ This command returns OK, unless the user is not logged in or a usage error
+occurred, in which case it returns ERROR.  Please note that no checking is
+done on the supplied data; if the requested message does not exist, the SEEN
+command simply returns OK without doing anything.
+  
+   
   
  ASYN   (ASYNchronous message support)
  
index cbc39e68b6d87f8bdcc254df784e8de3236cca29..ec7888c278dcaf9e329e05b8ffbdf7db57d05db9 100644 (file)
@@ -861,6 +861,27 @@ void cmd_slrp(char *new_ptr)
 }
 
 
+void cmd_seen(char *argbuf) {
+       long target_msgnum = 0L;
+       int target_setting = 0;
+
+       if (CtdlAccessCheck(ac_logged_in)) {
+               return;
+       }
+
+       if (num_parms(argbuf) != 2) {
+               cprintf("%d Invalid parameters\n", ERROR);
+               return;
+       }
+
+       target_msgnum = extract_long(argbuf, 0);
+       target_setting = extract_int(argbuf, 1);
+
+       CtdlSetSeen(target_msgnum, target_setting);
+       cprintf("%d OK\n", OK);
+}
+
+
 /*
  * INVT and KICK commands
  */
index f1edb51f09b4aa4afe7eb59a4225319f8a5fe0b9..f63bbfa39d19bd1c4a3a1b059ddf0d7a55c51a22 100644 (file)
@@ -74,5 +74,5 @@ enum {
 };
 
 
-
 int CtdlForgetThisRoom(void);
+void cmd_seen(char *argbuf);