CtdlCheckExpress() now accepts a session context.
[citadel.git] / citadel / server / room_ops.c
index 7fefdbbf3d4b51b8ceb888823c4327635ce1700d..d6288c9871b65db59537e0dd8c83493d40c00773 100644 (file)
@@ -1,6 +1,6 @@
 // Server functions which perform operations on room objects.
 //
-// Copyright (c) 1987-2023 by the citadel.org team
+// Copyright (c) 1987-2024 by the citadel.org team
 //
 // This program is open source software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License, version 3.
@@ -212,14 +212,12 @@ void CtdlRoomAccess(struct ctdlroom *roombuf, struct ctdluser *userbuf, int *res
                        retval = retval | UA_REPLYALLOWED;
                }
 
-               // If "collaborative deletion" is active for this room, any user who can post
-               // is also allowed to delete
+               // If "collaborative deletion" is active for this room, any user who can post is also allowed to delete
                if (roombuf->QRflags2 & QR2_COLLABDEL) {
                        if (retval & UA_POSTALLOWED) {
                                retval = retval | UA_DELETEALLOWED;
                        }
                }
-
        }
 
        // Check to see if the user has forgotten this room
@@ -302,7 +300,7 @@ void room_sanity_check(struct ctdlroom *qrbuf) {
 
 // CtdlGetRoom()  -  retrieve room data from disk
 int CtdlGetRoom(struct ctdlroom *qrbuf, const char *room_name) {
-       struct cdbdata *cdbqr;
+       struct cdbdata cdbqr;
        char lowercase_name[ROOMNAMELEN];
        char personal_lowercase_name[ROOMNAMELEN];
        long len;
@@ -322,13 +320,12 @@ int CtdlGetRoom(struct ctdlroom *qrbuf, const char *room_name) {
        cdbqr = cdb_fetch(CDB_ROOMS, lowercase_name, strlen(lowercase_name));
 
        // If that didn't work, try the user's personal namespace
-       if (cdbqr == NULL) {
+       if (cdbqr.ptr == NULL) {
                snprintf(personal_lowercase_name, sizeof personal_lowercase_name, "%010ld.%s", CC->user.usernum, lowercase_name);
                cdbqr = cdb_fetch(CDB_ROOMS, personal_lowercase_name, strlen(personal_lowercase_name));
        }
-       if (cdbqr != NULL) {
-               memcpy(qrbuf, cdbqr->ptr, ((cdbqr->len > sizeof(struct ctdlroom)) ?  sizeof(struct ctdlroom) : cdbqr->len));
-               cdb_free(cdbqr);
+       if (cdbqr.ptr != NULL) {
+               memcpy(qrbuf, cdbqr.ptr, ((cdbqr.len > sizeof(struct ctdlroom)) ?  sizeof(struct ctdlroom) : cdbqr.len));
                room_sanity_check(qrbuf);
                return (0);
        }
@@ -342,7 +339,9 @@ int CtdlGetRoom(struct ctdlroom *qrbuf, const char *room_name) {
 int CtdlGetRoomLock(struct ctdlroom *qrbuf, const char *room_name) {
        register int retval;
        retval = CtdlGetRoom(qrbuf, room_name);
-       if (retval == 0) begin_critical_section(S_ROOMS);
+       if (retval == 0) {
+               begin_critical_section(S_ROOMS);
+       }
        return(retval);
 }
 
@@ -384,6 +383,7 @@ void b_deleteroom(char *room_name) {
 void CtdlPutRoomLock(struct ctdlroom *qrbuf) {
        CtdlPutRoom(qrbuf);
        end_critical_section(S_ROOMS);
+       //syslog(LOG_ERR, "\033[32mCtdlGetRoomLock(%p) released\033[0m", CC);
 }
 
 
@@ -432,13 +432,12 @@ int CtdlGetAvailableFloor(void) {
 
 // CtdlGetFloor()  -  retrieve floor data from disk
 void CtdlGetFloor(struct floor *flbuf, int floor_num) {
-       struct cdbdata *cdbfl;
+       struct cdbdata cdbfl;
 
        memset(flbuf, 0, sizeof(struct floor));
        cdbfl = cdb_fetch(CDB_FLOORTAB, &floor_num, sizeof(int));
-       if (cdbfl != NULL) {
-               memcpy(flbuf, cdbfl->ptr, ((cdbfl->len > sizeof(struct floor)) ?  sizeof(struct floor) : cdbfl->len));
-               cdb_free(cdbfl);
+       if (cdbfl.ptr != NULL) {
+               memcpy(flbuf, cdbfl.ptr, ((cdbfl.len > sizeof(struct floor)) ?  sizeof(struct floor) : cdbfl.len));
        }
        else {
                if (floor_num == 0) {
@@ -470,7 +469,7 @@ struct floor *CtdlGetCachedFloor(int floor_num) {
                for (i=0; i<MAXFLOORS; ++i) {
                        floorcache[floor_num] = NULL;
                }
-       initialized = 1;
+               initialized = 1;
        }
        if (floorcache[floor_num] == NULL) {
                fetch_new = 1;
@@ -502,9 +501,7 @@ void CtdlPutFloor(struct floor *flbuf, int floor_num) {
                memcpy(floorcache[floor_num], flbuf, sizeof(struct floor));
        }
        end_critical_section(S_FLOORCACHE);
-
-       cdb_store(CDB_FLOORTAB, &floor_num, sizeof(int),
-                 flbuf, sizeof(struct floor));
+       cdb_store(CDB_FLOORTAB, &floor_num, sizeof(int), flbuf, sizeof(struct floor));
 }
 
 
@@ -525,13 +522,12 @@ void lputfloor(struct floor *flbuf, int floor_num) {
 // Iterate through the room table, performing a callback for each room.
 void CtdlForEachRoom(ForEachRoomCallBack callback_func, void *in_data) {
        struct ctdlroom qrbuf;
-       struct cdbdata *cdbqr;
+       struct cdbkeyval cdbqr;
 
        cdb_rewind(CDB_ROOMS);
-       while (cdbqr = cdb_next_item(CDB_ROOMS), cdbqr != NULL) {
+       while (cdbqr = cdb_next_item(CDB_ROOMS), cdbqr.val.ptr!=NULL) {         // always read through to the end
                memset(&qrbuf, 0, sizeof(struct ctdlroom));
-               memcpy(&qrbuf, cdbqr->ptr, ((cdbqr->len > sizeof(struct ctdlroom)) ?  sizeof(struct ctdlroom) : cdbqr->len) );
-               cdb_free(cdbqr);
+               memcpy(&qrbuf, cdbqr.val.ptr, ((cdbqr.val.len > sizeof(struct ctdlroom)) ? sizeof(struct ctdlroom) : cdbqr.val.len) );
                room_sanity_check(&qrbuf);
                if (qrbuf.QRflags & QR_INUSE) {
                        callback_func(&qrbuf, in_data);
@@ -542,15 +538,12 @@ void CtdlForEachRoom(ForEachRoomCallBack callback_func, void *in_data) {
 
 // delete_msglist()  -  delete room message pointers
 void delete_msglist(struct ctdlroom *whichroom) {
-        struct cdbdata *cdbml;
+        struct cdbdata cdbml;
 
-       // Make sure the msglist we're deleting actually exists, otherwise
-       // libdb will complain when we try to delete an invalid record
+       // Make sure the msglist we're deleting actually exists; don't try to delete an invalid record
         cdbml = cdb_fetch(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
-        if (cdbml != NULL) {
-               cdb_free(cdbml);
-
-               // Go ahead and delete it
+        if (cdbml.ptr != NULL) {
+               // ok it exists, go ahead and delete it
                cdb_delete(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
        }
 }
@@ -600,6 +593,33 @@ int CtdlIsNonEditable(struct ctdlroom *qrbuf) {
 }
 
 
+// Retrieve a list of all messages (message numbers) in the specified room.
+// Returns the number of messages in the room, allocates a pointer to the array and stuffs it in the supplied location.
+// Caller must free that memory.
+// If no messages in room, returns 0 and msgs is set to NULL.
+int CtdlFetchMsgList(long roomnum, long **msgs) {
+       int num_msgs = 0;
+        struct cdbdata cdbfr;
+
+        cdbfr = cdb_fetch(CDB_MSGLISTS, &roomnum, sizeof(long));
+       if (cdbfr.ptr == NULL) {
+               *msgs = malloc(sizeof(long));   // dummy buffer
+               *msgs[0] = 0;
+               return (0);
+       }
+
+               num_msgs = cdbfr.len / sizeof(long);
+       if (num_msgs > 0) {
+               *msgs = malloc(cdbfr.len);
+               memcpy(*msgs, cdbfr.ptr, cdbfr.len);
+       }
+       else {
+               *msgs = NULL;
+       }
+       return(num_msgs);
+}
+
+
 // Make the specified room the current room for this session.  No validation
 // or access control is done here -- the caller should make sure that the
 // specified room exists and is ok to access.
@@ -615,7 +635,6 @@ void CtdlUserGoto(char *where, int display_result, int transiently, int *retmsgs
        int raideflag;
        struct visit vbuf;
        char truncated_roomname[ROOMNAMELEN];
-        struct cdbdata *cdbfr;
        long *msglist = NULL;
        int num_msgs = 0;
        unsigned int original_v_flags;
@@ -666,13 +685,7 @@ void CtdlUserGoto(char *where, int display_result, int transiently, int *retmsgs
                info = 1;
        }
 
-        cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
-        if (cdbfr != NULL) {
-               msglist = (long *) cdbfr->ptr;
-               cdbfr->ptr = NULL;                      // CtdlUserGoto() now owns this memory (this requires attention if we move to LMDB)
-               num_msgs = cdbfr->len / sizeof(long);
-               cdb_free(cdbfr);
-       }
+       num_msgs = CtdlFetchMsgList(CC->room.QRnumber, &msglist);
 
        total_messages = 0;
        for (a=0; a<num_msgs; ++a) {
@@ -743,7 +756,7 @@ void CtdlUserGoto(char *where, int display_result, int transiently, int *retmsgs
 
        if (display_result) {
                cprintf("%d%c%s|%d|%d|%d|%d|%ld|%ld|%d|%d|%d|%d|%d|%d|%d|%d|%ld|\n",
-                       CIT_OK, CtdlCheckExpress(),
+                       CIT_OK, CtdlCheckExpress(CC),
                        truncated_roomname,
                        (int)new_messages,
                        (int)total_messages,
@@ -872,17 +885,6 @@ int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
                qrbuf.QRfloor = new_floor;
                CtdlPutRoom(&qrbuf);
 
-               begin_critical_section(S_CONFIG);
-       
-               // If baseroom/aideroom name changes, update config
-               if (!strncasecmp(old_name, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN)) {
-                       CtdlSetConfigStr("c_baseroom", new_name);
-               }
-               if (!strncasecmp(old_name, CtdlGetConfigStr("c_aideroom"), ROOMNAMELEN)) {
-                       CtdlSetConfigStr("c_aideroom", new_name);
-               }
-       
-               end_critical_section(S_CONFIG);
        
                // If the room name changed, then there are now two room
                // records, so we have to delete the old one.
@@ -895,6 +897,16 @@ int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
 
        end_critical_section(S_ROOMS);
 
+       // If baseroom/aideroom name changes, update config
+       begin_critical_section(S_CONFIG);
+       if (!strncasecmp(old_name, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN)) {
+               CtdlSetConfigStr("c_baseroom", new_name);
+       }
+       if (!strncasecmp(old_name, CtdlGetConfigStr("c_aideroom"), ROOMNAMELEN)) {
+               CtdlSetConfigStr("c_aideroom", new_name);
+       }
+       end_critical_section(S_CONFIG);
+
        // Adjust the floor reference counts if necessary
        if (new_floor != old_floor) {
                lgetfloor(&flbuf, old_floor);