]> code.citadel.org Git - citadel.git/blobdiff - citadel/room_ops.c
* Every user gets a Trash folder. Clients can also use _TRASH_
[citadel.git] / citadel / room_ops.c
index cc6111b695a5674f3e69bac8aebeb3bc58092061..46490bd9dd0702c783681ec3f83aff7cc3746e91 100644 (file)
@@ -357,7 +357,6 @@ struct floor *cgetfloor(int floor_num) {
        end_critical_section(S_FLOORCACHE);
 
        if (fetch_new) {
-               lprintf(CTDL_DEBUG, "fetch_new is active ... going to disk\n");
                fl = malloc(sizeof(struct floor));
                getfloor(fl, floor_num);
                begin_critical_section(S_FLOORCACHE);
@@ -767,6 +766,7 @@ void usergoto(char *where, int display_result, int transiently,
 {
        int a;
        int new_messages = 0;
+       int old_messages = 0;
        int total_messages = 0;
        int info = 0;
        int rmailflag;
@@ -778,6 +778,10 @@ void usergoto(char *where, int display_result, int transiently,
        long *msglist = NULL;
        int num_msgs = 0;
        unsigned int original_v_flags;
+       int num_sets;
+       int s;
+       char setstr[128], lostr[64], histr[64];
+       long lo, hi;
 
        /* If the supplied room name is NULL, the caller wants us to know that
         * it has already copied the room record into CC->room, so
@@ -820,20 +824,42 @@ void usergoto(char *where, int display_result, int transiently,
        get_mm();
         cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
         if (cdbfr != NULL) {
-               msglist = malloc(cdbfr->len);
-               memcpy(msglist, cdbfr->ptr, cdbfr->len);
+               msglist = (long *) cdbfr->ptr;
+               cdbfr->ptr = NULL;      /* usergoto() now owns this memory */
                num_msgs = cdbfr->len / sizeof(long);
                cdb_free(cdbfr);
        }
 
-       if (num_msgs > 0) for (a = 0; a < num_msgs; ++a) {
-               if (msglist[a] > 0L) {
-                       ++total_messages;
-                       if (is_msg_in_sequence_set(vbuf.v_seen, msglist[a]) == 0) {
-                               ++new_messages;
+       total_messages = 0;
+       for (a=0; a<num_msgs; ++a) {
+               if (msglist[a] > 0L) ++total_messages;
+       }
+       new_messages = num_msgs;
+       num_sets = num_tokens(vbuf.v_seen, ',');
+       for (s=0; s<num_sets; ++s) {
+               extract_token(setstr, vbuf.v_seen, s, ',', sizeof setstr);
+
+               extract_token(lostr, setstr, 0, ':', sizeof lostr);
+               if (num_tokens(setstr, ':') >= 2) {
+                       extract_token(histr, setstr, 1, ':', sizeof histr);
+                       if (!strcmp(histr, "*")) {
+                               snprintf(histr, sizeof histr, "%ld", LONG_MAX);
+                       }
+               } 
+               else {
+                       strcpy(histr, lostr);
+               }
+               lo = atol(lostr);
+               hi = atol(histr);
+
+               for (a=0; a<num_msgs; ++a) if (msglist[a] > 0L) {
+                       if ((msglist[a] >= lo) && (msglist[a] <= hi)) {
+                               ++old_messages;
+                               msglist[a] = 0L;
                        }
                }
        }
+       new_messages = total_messages - old_messages;
 
        if (msglist != NULL) free(msglist);
 
@@ -906,15 +932,33 @@ void cmd_goto(char *gargs)
 
        getuser(&CC->user, CC->curr_user);
 
-       if (!strcasecmp(towhere, "_BASEROOM_"))
+       /*
+        * Handle some of the macro named rooms
+        */
+       if (!strcasecmp(towhere, "_BASEROOM_")) {
                safestrncpy(towhere, config.c_baseroom, sizeof towhere);
-
-       if (!strcasecmp(towhere, "_MAIL_"))
+       }
+       else if (!strcasecmp(towhere, "_MAIL_")) {
                safestrncpy(towhere, MAILROOM, sizeof towhere);
-
-       if (!strcasecmp(towhere, "_BITBUCKET_"))
+       }
+       else if (!strcasecmp(towhere, "_TRASH_")) {
+               safestrncpy(towhere, USERTRASHROOM, sizeof towhere);
+       }
+       else if (!strcasecmp(towhere, "_BITBUCKET_")) {
                safestrncpy(towhere, config.c_twitroom, sizeof towhere);
-
+       }
+       else if (!strcasecmp(towhere, "_CALENDAR_")) {
+               safestrncpy(towhere, USERCALENDARROOM, sizeof towhere);
+       }
+       else if (!strcasecmp(towhere, "_TASKS_")) {
+               safestrncpy(towhere, USERTASKSROOM, sizeof towhere);
+       }
+       else if (!strcasecmp(towhere, "_CONTACTS_")) {
+               safestrncpy(towhere, USERCONTACTSROOM, sizeof towhere);
+       }
+       else if (!strcasecmp(towhere, "_NOTES_")) {
+               safestrncpy(towhere, USERNOTESROOM, sizeof towhere);
+       }
 
        /* First try a regular match */
        c = getroom(&QRscratch, towhere);
@@ -1050,14 +1094,32 @@ void cmd_rdir(void)
                cprintf("%d not here.\n", ERROR + HIGHER_ACCESS_REQUIRED);
                return;
        }
-       cprintf("%d %s|%s/files/%s\n",
-       LISTING_FOLLOWS, config.c_fqdn, CTDLDIR, CC->room.QRdirname);
+       cprintf("%d %s|"
+#ifndef HAVE_DATA_DIR
+                       "."
+#else
+                       DATA_DIR
+#endif
+                       "/files/%s\n",
+                       LISTING_FOLLOWS, config.c_fqdn, CC->room.QRdirname);
 
-        snprintf(buf, sizeof buf, "ls %s/files/%s  >%s 2> /dev/null",
-                CTDLDIR, CC->room.QRdirname, tempfilename);
-        system(buf);
+       snprintf(buf, sizeof buf, "ls "
+#ifndef HAVE_DATA_DIR
+                        "."
+#else
+                        DATA_DIR
+#endif
+                        "/files/%s  >%s 2> /dev/null",
+                        CC->room.QRdirname, tempfilename);
+       system(buf);
 
-       snprintf(buf, sizeof buf, "%s/files/%s/filedir", CTDLDIR, CC->room.QRdirname);
+       snprintf(buf, sizeof buf, 
+#ifndef HAVE_DATA_DIR
+                        "."
+#else
+                        DATA_DIR
+#endif
+                        "/files/%s/filedir", CC->room.QRdirname);
        fd = fopen(buf, "r");
        if (fd == NULL)
                fd = fopen("/dev/null", "r");
@@ -1066,8 +1128,14 @@ void cmd_rdir(void)
        while (fgets(flnm, sizeof flnm, ls) != NULL) {
                flnm[strlen(flnm) - 1] = 0;
                if (strcasecmp(flnm, "filedir")) {
-                       snprintf(buf, sizeof buf, "%s/files/%s/%s",
-                               CTDLDIR, CC->room.QRdirname, flnm);
+                       snprintf(buf, sizeof buf, 
+#ifndef HAVE_DATA_DIR
+                                        "."
+#else
+                                        DATA_DIR
+#endif
+                                        "/files/%s/%s",
+                                        CC->room.QRdirname, flnm);
                        stat(buf, &statbuf);
                        safestrncpy(comment, "", sizeof comment);
                        fseek(fd, 0L, 0);
@@ -1373,7 +1441,13 @@ void cmd_setr(char *args)
 
        /* Create a room directory if necessary */
        if (CC->room.QRflags & QR_DIRECTORY) {
-               snprintf(buf, sizeof buf, "./files/%s", CC->room.QRdirname);
+               snprintf(buf, sizeof buf, 
+#ifndef HAVE_DATA_DIR
+                                "."
+#else
+                                DATA_DIR
+#endif
+                                "/files/%s", CC->room.QRdirname);
                mkdir(buf, 0755);
        }
        snprintf(buf, sizeof buf, "%s> edited by %s\n", CC->room.QRname, CC->curr_user);
@@ -1479,8 +1553,47 @@ void cmd_rinf(void)
        fclose(info_fp);
 }
 
+/*
+ * Asynchronously schedule a room for deletion.  The room will appear
+ * deleted to the user(s), but it won't actually get purged from the
+ * database until THE DREADED AUTO-PURGER makes its next run.
+ */
+void schedule_room_for_deletion(struct ctdlroom *qrbuf)
+{
+       char old_name[ROOMNAMELEN];
+       static int seq = 0;
+
+       lprintf(CTDL_NOTICE, "Scheduling room <%s> for deletion\n",
+               qrbuf->QRname);
+
+       safestrncpy(old_name, qrbuf->QRname, sizeof old_name);
+
+       getroom(qrbuf, qrbuf->QRname);
+
+       /* Turn the room into a private mailbox owned by a user who doesn't
+        * exist.  This will immediately make the room invisible to everyone,
+        * and qualify the room for purging.
+        */
+       snprintf(qrbuf->QRname, sizeof qrbuf->QRname, "9999999999.%08lx.%04d.%s",
+               time(NULL),
+               ++seq,
+               old_name
+       );
+       qrbuf->QRflags |= QR_MAILBOX;
+       time(&qrbuf->QRgen);    /* Use a timestamp as the new generation number  */
+
+       putroom(qrbuf);
+
+       b_deleteroom(old_name);
+}
+
+
+
 /*
  * Back end processing to delete a room and everything associated with it
+ * (This one is synchronous and should only get called by THE DREADED
+ * AUTO-PURGER in serv_expire.c.  All user-facing code should call
+ * the asynchronous schedule_room_for_deletion() instead.)
  */
 void delete_room(struct ctdlroom *qrbuf)
 {
@@ -1504,7 +1617,7 @@ void delete_room(struct ctdlroom *qrbuf)
        /* Delete the messages in the room
         * (Careful: this opens an S_ROOMS critical section!)
         */
-       CtdlDeleteMessages(qrbuf->QRname, 0L, "");
+       CtdlDeleteMessages(qrbuf->QRname, 0L, "", 0);
 
        /* Flag the room record as not in use */
        lgetroom(qrbuf, qrbuf->QRname);
@@ -1583,7 +1696,7 @@ void cmd_kill(char *argbuf)
                }
 
                /* Do the dirty work */
-               delete_room(&CC->room);
+               schedule_room_for_deletion(&CC->room);
 
                /* Return to the Lobby */
                usergoto(config.c_baseroom, 0, 0, NULL, NULL);