]> code.citadel.org Git - citadel.git/blobdiff - citadel/room_ops.c
* Any "delete message" operation which is synchronous to a client is now
[citadel.git] / citadel / room_ops.c
index b49d7ed179d73127037f245b4ed09eb2b8b0ce3e..682adddaba5afbe61d88076a8b3d246b809f3a9d 100644 (file)
@@ -152,7 +152,7 @@ void CtdlRoomAccess(struct ctdlroom *roombuf, struct ctdluser *userbuf,
        }
 
 NEWMSG:        /* By the way, we also check for the presence of new messages */
-       if (is_msg_in_mset(vbuf.v_seen, roombuf->QRhighest) == 0) {
+       if (is_msg_in_sequence_set(vbuf.v_seen, roombuf->QRhighest) == 0) {
                retval = retval | UA_HASNEWMSGS;
        }
 
@@ -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);
@@ -514,8 +513,8 @@ void list_roomname(struct ctdlroom *qrbuf, int ra, int view)
        /* For my own mailbox rooms, chop off the owner prefix */
        if ( (qrbuf->QRflags & QR_MAILBOX)
             && (atol(qrbuf->QRname) == CC->user.usernum) ) {
-               strcpy(truncated_roomname, qrbuf->QRname);
-               strcpy(truncated_roomname, &truncated_roomname[11]);
+               safestrncpy(truncated_roomname, qrbuf->QRname, sizeof truncated_roomname);
+               safestrncpy(truncated_roomname, &truncated_roomname[11], sizeof truncated_roomname);
                cprintf("%s", truncated_roomname);
        }
        /* For all other rooms, just display the name in its entirety */
@@ -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
@@ -826,14 +830,36 @@ void usergoto(char *where, int display_result, int transiently,
                cdb_free(cdbfr);
        }
 
-       if (num_msgs > 0) for (a = 0; a < num_msgs; ++a) {
-               if (msglist[a] > 0L) {
-                       ++total_messages;
-                       if (is_msg_in_mset(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);
 
@@ -848,10 +874,10 @@ void usergoto(char *where, int display_result, int transiently,
        else
                raideflag = 0;
 
-       strcpy(truncated_roomname, CC->room.QRname);
+       safestrncpy(truncated_roomname, CC->room.QRname, sizeof truncated_roomname);
        if ( (CC->room.QRflags & QR_MAILBOX)
           && (atol(CC->room.QRname) == CC->user.usernum) ) {
-               strcpy(truncated_roomname, &truncated_roomname[11]);
+               safestrncpy(truncated_roomname, &truncated_roomname[11], sizeof truncated_roomname);
        }
 
        if (retmsgs != NULL) *retmsgs = total_messages;
@@ -1027,13 +1053,15 @@ void cmd_whok(void)
  */
 void cmd_rdir(void)
 {
-       char buf[SIZ];
-       char flnm[SIZ];
-       char comment[SIZ];
+       char buf[256];
+       char flnm[256];
+       char comment[256];
        FILE *ls, *fd;
        struct stat statbuf;
+       char tempfilename[PATH_MAX];
 
        if (CtdlAccessCheck(ac_logged_in)) return;
+       tmpnam(tempfilename);
        
        getroom(&CC->room, CC->room.QRname);
        getuser(&CC->user, CC->curr_user);
@@ -1048,26 +1076,50 @@ 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, BBSDIR, 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",
-                BBSDIR, CC->room.QRdirname, CC->temp);
-        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", BBSDIR, 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");
 
-       ls = fopen(CC->temp, "r");
+       ls = fopen(tempfilename, "r");
        while (fgets(flnm, sizeof flnm, ls) != NULL) {
                flnm[strlen(flnm) - 1] = 0;
                if (strcasecmp(flnm, "filedir")) {
-                       snprintf(buf, sizeof buf, "%s/files/%s/%s",
-                               BBSDIR, 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);
-                       strcpy(comment, "");
+                       safestrncpy(comment, "", sizeof comment);
                        fseek(fd, 0L, 0);
                        while ((fgets(buf, sizeof buf, fd) != NULL)
                               && (strlen(comment) == 0)) {
@@ -1083,7 +1135,7 @@ void cmd_rdir(void)
        }
        fclose(ls);
        fclose(fd);
-       unlink(CC->temp);
+       unlink(tempfilename);
 
        cprintf("000\n");
 }
@@ -1135,7 +1187,7 @@ int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
        struct floor *fl;
        struct floor flbuf;
        long owner = 0L;
-       char actual_old_name[SIZ];
+       char actual_old_name[ROOMNAMELEN];
 
        lprintf(CTDL_DEBUG, "CtdlRenameRoom(%s, %s, %d)\n",
                old_name, new_name, new_floor);
@@ -1170,7 +1222,7 @@ int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
 
        else {
                /* Rename it */
-               strcpy(actual_old_name, qrbuf.QRname);
+               safestrncpy(actual_old_name, qrbuf.QRname, sizeof actual_old_name);
                if (qrbuf.QRflags & QR_MAILBOX) {
                        owner = atol(qrbuf.QRname);
                }
@@ -1265,7 +1317,7 @@ void cmd_setr(char *args)
        if (CC->room.QRflags & QR_MAILBOX) {
                sprintf(new_name, "%010ld.", atol(CC->room.QRname) );
        } else {
-               strcpy(new_name, "");
+               safestrncpy(new_name, "", sizeof new_name);
        }
        extract_token(&new_name[strlen(new_name)], args, 0, '|', (sizeof new_name - strlen(new_name)));
 
@@ -1371,7 +1423,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);
@@ -1477,8 +1535,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)
 {
@@ -1502,7 +1599,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);
@@ -1574,14 +1671,14 @@ void cmd_kill(char *argbuf)
        }
        if (kill_ok) {
                if (CC->room.QRflags & QR_MAILBOX) {
-                       strcpy(deleted_room_name, &CC->room.QRname[11]);
+                       safestrncpy(deleted_room_name, &CC->room.QRname[11], sizeof deleted_room_name);
                }
                else {
-                       strcpy(deleted_room_name, CC->room.QRname);
+                       safestrncpy(deleted_room_name, CC->room.QRname, sizeof deleted_room_name);
                }
 
                /* 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);