logging changes
[citadel.git] / citadel / room_ops.c
index 0d90bc3b300ea0eb7bb73dce6565f95e8fd56bdc..b895fc67dba4adfd7485c2330fed857c5d214770 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * Server functions which perform operations on room objects.
  *
- * Copyright (c) 1987-2012 by the citadel.org team
+ * Copyright (c) 1987-2017 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.
  * GNU General Public License for more details.
  */
 
-#include "sysdep.h"
-#include <stdlib.h>
-#include <unistd.h>
 #include <stdio.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <string.h>
-#include <dirent.h>    /* for cmd_rdir to read contents of the directory */
-
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-#  include <sys/time.h>
-# else
-#  include <time.h>
-# endif
-#endif
-
-#include <limits.h>
-#include <errno.h>
-#include "citadel.h"
 #include <libcitadel.h>
-#include "server.h"
-#include "database.h"
-#include "config.h"
-#include "room_ops.h"
-#include "sysdep_decls.h"
-#include "support.h"
-#include "msgbase.h"
-#include "citserver.h"
-#include "control.h"
-#include "citadel_dirs.h"
-#include "threads.h"
 
+#include "citserver.h"
 #include "ctdl_module.h"
+#include "config.h"
+#include "control.h"
 #include "user_ops.h"
+#include "room_ops.h"
 
 struct floor *floorcache[MAXFLOORS];
 
@@ -60,13 +31,14 @@ struct floor *floorcache[MAXFLOORS];
 int CtdlDoIHavePermissionToReadMessagesInThisRoom(void) {
        if (    (!(CC->logged_in))
                && (!(CC->internal_pgm))
-               && (!config.c_guest_logins)
+               && (!CtdlGetConfigInt("c_guest_logins"))
        ) {
                return(om_not_logged_in);
        }
        return(om_ok);
 }
 
+
 /*
  * Check to see whether we have permission to post a message in the current
  * room.  Returns a *CITADEL ERROR CODE* and puts a message in errmsgbuf, or
@@ -107,8 +79,8 @@ int CtdlDoIHavePermissionToPostInThisRoom(
 
        }
 
-       if ((CC->user.axlevel < AxProbU)
-           && ((CC->room.QRflags & QR_MAILBOX) == 0)) {
+       if ((CC->user.axlevel < AxProbU) && ((CC->room.QRflags & QR_MAILBOX) == 0))
+       {
                snprintf(errmsgbuf, n, "Need to be validated to enter (except in %s> to sysop)", MAILROOM);
                return (ERROR + HIGHER_ACCESS_REQUIRED);
        }
@@ -141,6 +113,7 @@ int CtdlDoIHavePermissionToPostInThisRoom(
 
 }
 
+
 /*
  * Check whether the current user has permission to delete messages from
  * the current room (returns 1 for yes, 0 for no)
@@ -152,8 +125,10 @@ int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void) {
        return(0);
 }
 
+
 /*
- * Retrieve access control information for any user/room pair
+ * Retrieve access control information for any user/room pair.
+ * Yes, it has a couple of gotos.  If you don't like that, go die in a car fire.
  */
 void CtdlRoomAccess(struct ctdlroom *roombuf, struct ctdluser *userbuf,
                int *result, int *view)
@@ -167,7 +142,7 @@ void CtdlRoomAccess(struct ctdlroom *roombuf, struct ctdluser *userbuf,
                is_me = 1;
        }
 
-       if ((is_me) && (config.c_guest_logins) && (!CC->logged_in)) {
+       if ((is_me) && (CtdlGetConfigInt("c_guest_logins")) && (!CC->logged_in)) {
                is_guest = 1;
        }
 
@@ -194,7 +169,7 @@ void CtdlRoomAccess(struct ctdlroom *roombuf, struct ctdluser *userbuf,
        }
 
        /* Force the properties of the Aide room */
-       if (!strcasecmp(roombuf->QRname, config.c_aideroom)) {
+       if (!strcasecmp(roombuf->QRname, CtdlGetConfigStr("c_aideroom"))) {
                if (userbuf->axlevel >= AxAideU) {
                        retval = UA_KNOWN | UA_GOTOALLOWED | UA_POSTALLOWED | UA_DELETEALLOWED | UA_REPLYALLOWED;
                } else {
@@ -366,11 +341,12 @@ void room_sanity_check(struct ctdlroom *qrbuf)
        }
        /* Listing order of 0 is illegal except for base rooms */
        if (qrbuf->QRorder == 0)
-               if (!(qrbuf->QRflags & QR_MAILBOX) &&
-                   strncasecmp(qrbuf->QRname, config.c_baseroom, ROOMNAMELEN)
-                   &&
-                   strncasecmp(qrbuf->QRname, config.c_aideroom, ROOMNAMELEN))
+               if (    !(qrbuf->QRflags & QR_MAILBOX)
+                       && strncasecmp(qrbuf->QRname, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN)
+                       && strncasecmp(qrbuf->QRname, CtdlGetConfigStr("c_aideroom"), ROOMNAMELEN)
+               ) {
                        qrbuf->QRorder = 64;
+               }
 }
 
 
@@ -423,10 +399,11 @@ int CtdlGetRoom(struct ctdlroom *qrbuf, const char *room_name)
        }
 }
 
+
 /*
  * CtdlGetRoomLock()  -  same as getroom() but locks the record (if supported)
  */
-int CtdlGetRoomLock(struct ctdlroom *qrbuf, char *room_name)
+int CtdlGetRoomLock(struct ctdlroom *qrbuf, const char *room_name)
 {
        register int retval;
        retval = CtdlGetRoom(qrbuf, room_name);
@@ -486,10 +463,8 @@ void b_deleteroom(char *room_name) {
  */
 void CtdlPutRoomLock(struct ctdlroom *qrbuf)
 {
-
        CtdlPutRoom(qrbuf);
        end_critical_section(S_ROOMS);
-
 }
 
 
@@ -578,7 +553,6 @@ void CtdlGetFloor(struct floor *flbuf, int floor_num)
  */
 void lgetfloor(struct floor *flbuf, int floor_num)
 {
-
        begin_critical_section(S_FLOORTAB);
        CtdlGetFloor(flbuf, floor_num);
 }
@@ -646,7 +620,6 @@ void CtdlPutFloor(struct floor *flbuf, int floor_num)
  */
 void CtdlPutFloorLock(struct floor *flbuf, int floor_num)
 {
-
        CtdlPutFloor(flbuf, floor_num);
        end_critical_section(S_FLOORTAB);
 
@@ -663,7 +636,7 @@ void lputfloor(struct floor *flbuf, int floor_num)
 
 
 /* 
- *  Traverse the room file...
+ * Iterate through the room table, performing a callback for each room.
  */
 void CtdlForEachRoom(ForEachRoomCallBack CB, void *in_data)
 {
@@ -687,11 +660,9 @@ void CtdlForEachRoom(ForEachRoomCallBack CB, void *in_data)
 }
 
 /* 
- *  Traverse the room file...
+ * Iterate through the room table, performing a callback for each room that has a netconfig entry.
  */
-void CtdlForEachNetCfgRoom(ForEachRoomNetCfgCallBack CB,
-                          void *in_data,
-                          RoomNetCfg filter)
+void CtdlForEachNetCfgRoom(ForEachRoomNetCfgCallBack CB, void *in_data)
 {
        struct ctdlroom qrbuf;
        struct cdbdata *cdbqr;
@@ -700,21 +671,17 @@ void CtdlForEachNetCfgRoom(ForEachRoomNetCfgCallBack CB,
 
        while (cdbqr = cdb_next_item(CDB_ROOMS), cdbqr != NULL) {
                memset(&qrbuf, 0, sizeof(struct ctdlroom));
-               memcpy(&qrbuf, cdbqr->ptr,
-                      ((cdbqr->len > sizeof(struct ctdlroom)) ?
-                       sizeof(struct ctdlroom) : cdbqr->len)
-               );
+               memcpy(&qrbuf, cdbqr->ptr, ((cdbqr->len > sizeof(struct ctdlroom)) ?  sizeof(struct ctdlroom) : cdbqr->len));
                cdb_free(cdbqr);
                room_sanity_check(&qrbuf);
                if (qrbuf.QRflags & QR_INUSE)
                {
-                       OneRoomNetCfgRNCfg;
+                       OneRoomNetCfg *RNCfg;
                        RNCfg = CtdlGetNetCfgForRoom(qrbuf.QRnumber);
-                       if ((RNCfg != NULL) &&
-                           ((filter == maxRoomNetCfg) ||
-                            (RNCfg->NetConfigs[filter] != NULL)))
+                       if (RNCfg != NULL)
                        {
                                CB(&qrbuf, in_data, RNCfg);
+                               FreeRoomNetworkStruct(&RNCfg);
                        }
                }
        }
@@ -804,13 +771,15 @@ int CtdlIsNonEditable(struct ctdlroom *qrbuf)
  * specified room exists and is ok to access.
  */
 void CtdlUserGoto(char *where, int display_result, int transiently,
-               int *retmsgs, int *retnew)
+               int *retmsgs, int *retnew, long *retoldest, long *retnewest)
 {
        struct CitContext *CCC = CC;
        int a;
        int new_messages = 0;
        int old_messages = 0;
        int total_messages = 0;
+       long oldest_message = 0;
+       long newest_message = 0;
        int info = 0;
        int rmailflag;
        int raideflag;
@@ -845,8 +814,15 @@ void CtdlUserGoto(char *where, int display_result, int transiently,
        /* Know the room ... but not if it's the page log room, or if the
         * caller specified that we're only entering this room transiently.
         */
-       if ((strcasecmp(CCC->room.QRname, config.c_logpages))
-          && (transiently == 0) ) {
+       int add_room_to_known_list = 1;
+       if (transiently == 1) {
+               add_room_to_known_list = 0;
+       }
+       char *c_logpages = CtdlGetConfigStr("c_logpages");
+       if ( (c_logpages != NULL) && (!strcasecmp(CCC->room.QRname, c_logpages)) ) {
+               add_room_to_known_list = 0;
+       }
+       if (add_room_to_known_list) {
                vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
                vbuf.v_flags = vbuf.v_flags | V_ACCESS;
        }
@@ -860,8 +836,10 @@ void CtdlUserGoto(char *where, int display_result, int transiently,
        /* Check for new mail */
        newmailcount = NewMailCount();
 
-       /* set info to 1 if the user needs to read the room's info file */
-       if (CCC->room.QRinfo > vbuf.v_lastseen) {
+       /* Set info to 1 if the room banner is new since our last visit.
+        * Some clients only want to display it when it changes.
+        */
+       if (CCC->room.msgnum_info > vbuf.v_lastseen) {
                info = 1;
        }
 
@@ -878,6 +856,11 @@ void CtdlUserGoto(char *where, int display_result, int transiently,
                if (msglist[a] > 0L) ++total_messages;
        }
 
+       if (total_messages > 0) {
+               oldest_message = msglist[0];
+               newest_message = msglist[num_msgs - 1];
+       }
+
        num_sets = num_tokens(vbuf.v_seen, ',');
        for (s=0; s<num_sets; ++s) {
                extract_token(setstr, vbuf.v_seen, s, ',', sizeof setstr);
@@ -929,10 +912,11 @@ void CtdlUserGoto(char *where, int display_result, int transiently,
 
        if (retmsgs != NULL) *retmsgs = total_messages;
        if (retnew != NULL) *retnew = new_messages;
-       MSG_syslog(LOG_INFO, "<%s> %d new of %d total messages\n",
-                  CCC->room.QRname,
-                  new_messages, total_messages
-               );
+       if (retoldest != NULL) *retoldest = oldest_message;
+       if (retnewest != NULL) *retnewest = newest_message;
+       syslog(LOG_DEBUG, "<%s> %d new of %d total messages, oldest=%ld, newest=%ld",
+                  CCC->room.QRname, new_messages, total_messages, oldest_message, newest_message
+       );
 
        CCC->curr_view = (int)vbuf.v_view;
 
@@ -965,7 +949,7 @@ void CtdlUserGoto(char *where, int display_result, int transiently,
  */
 void convert_room_name_macros(char *towhere, size_t maxlen) {
        if (!strcasecmp(towhere, "_BASEROOM_")) {
-               safestrncpy(towhere, config.c_baseroom, maxlen);
+               safestrncpy(towhere, CtdlGetConfigStr("c_baseroom"), maxlen);
        }
        else if (!strcasecmp(towhere, "_MAIL_")) {
                safestrncpy(towhere, MAILROOM, maxlen);
@@ -977,7 +961,7 @@ void convert_room_name_macros(char *towhere, size_t maxlen) {
                safestrncpy(towhere, USERDRAFTROOM, maxlen);
        }
        else if (!strcasecmp(towhere, "_BITBUCKET_")) {
-               safestrncpy(towhere, config.c_twitroom, maxlen);
+               safestrncpy(towhere, CtdlGetConfigStr("c_twitroom"), maxlen);
        }
        else if (!strcasecmp(towhere, "_CALENDAR_")) {
                safestrncpy(towhere, USERCALENDARROOM, maxlen);
@@ -1003,6 +987,7 @@ void convert_room_name_macros(char *towhere, size_t maxlen) {
  * in *at least* the old name!
  */
 int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
+       struct CitContext *CCC = CC;
        int old_floor = 0;
        struct ctdlroom qrbuf;
        struct ctdlroom qrtmp;
@@ -1012,8 +997,7 @@ int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
        long owner = 0L;
        char actual_old_name[ROOMNAMELEN];
 
-       syslog(LOG_DEBUG, "CtdlRenameRoom(%s, %s, %d)\n",
-               old_name, new_name, new_floor);
+       syslog(LOG_DEBUG, "CtdlRenameRoom(%s, %s, %d)", old_name, new_name, new_floor);
 
        if (new_floor >= 0) {
                fl = CtdlGetCachedFloor(new_floor);
@@ -1033,9 +1017,9 @@ int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
                ret = crr_room_not_found;
        }
 
-       else if ( (CC->user.axlevel < AxAideU) && (!CC->internal_pgm)
-                 && (CC->user.usernum != qrbuf.QRroomaide)
-                 && ( (((qrbuf.QRflags & QR_MAILBOX) == 0) || (atol(qrbuf.QRname) != CC->user.usernum))) )  {
+       else if ( (CCC->user.axlevel < AxAideU) && (!CCC->internal_pgm)
+                 && (CCC->user.usernum != qrbuf.QRroomaide)
+                 && ( (((qrbuf.QRflags & QR_MAILBOX) == 0) || (atol(qrbuf.QRname) != CCC->user.usernum))) )  {
                ret = crr_access_denied;
        }
 
@@ -1059,8 +1043,9 @@ int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
                }
 
                /* Reject change of floor for baseroom/aideroom */
-               if (!strncasecmp(old_name, config.c_baseroom, ROOMNAMELEN) ||
-                   !strncasecmp(old_name, config.c_aideroom, ROOMNAMELEN)) {
+               if (!strncasecmp(old_name, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN) ||
+                   !strncasecmp(old_name, CtdlGetConfigStr("c_aideroom"), ROOMNAMELEN))
+               {
                        new_floor = 0;
                }
 
@@ -1075,13 +1060,11 @@ int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
                begin_critical_section(S_CONFIG);
        
                /* If baseroom/aideroom name changes, update config */
-               if (!strncasecmp(old_name, config.c_baseroom, ROOMNAMELEN)) {
-                       safestrncpy(config.c_baseroom, new_name, ROOMNAMELEN);
-                       put_config();
+               if (!strncasecmp(old_name, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN)) {
+                       CtdlSetConfigStr("c_baseroom", new_name);
                }
-               if (!strncasecmp(old_name, config.c_aideroom, ROOMNAMELEN)) {
-                       safestrncpy(config.c_aideroom, new_name, ROOMNAMELEN);
-                       put_config();
+               if (!strncasecmp(old_name, CtdlGetConfigStr("c_aideroom"), ROOMNAMELEN)) {
+                       CtdlSetConfigStr("c_aideroom", new_name);
                }
        
                end_critical_section(S_CONFIG);
@@ -1103,11 +1086,11 @@ int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
                lgetfloor(&flbuf, old_floor);
                --flbuf.f_ref_count;
                lputfloor(&flbuf, old_floor);
-               syslog(LOG_DEBUG, "Reference count for floor %d is now %d\n", old_floor, flbuf.f_ref_count);
+               syslog(LOG_DEBUG, "Reference count for floor %d is now %d", old_floor, flbuf.f_ref_count);
                lgetfloor(&flbuf, new_floor);
                ++flbuf.f_ref_count;
                lputfloor(&flbuf, new_floor);
-               syslog(LOG_DEBUG, "Reference count for floor %d is now %d\n", new_floor, flbuf.f_ref_count);
+               syslog(LOG_DEBUG, "Reference count for floor %d is now %d", new_floor, flbuf.f_ref_count);
        }
 
        /* ...and everybody say "YATTA!" */     
@@ -1115,22 +1098,20 @@ int CtdlRenameRoom(char *old_name, char *new_name, int new_floor) {
 }
 
 
-
 /*
- * 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.
+ * Asynchronously schedule a room for deletion.  By placing the room into an invalid private namespace,
+ * the room will appear deleted to the user(s), but the session doesn't need to block while waiting for
+ * database operations to complete.  Instead, the room gets purged when THE DREADED AUTO-PURGER makes
+ * its next run.  Aren't we so clever?!!
  */
 void CtdlScheduleRoomForDeletion(struct ctdlroom *qrbuf)
 {
        char old_name[ROOMNAMELEN];
        static int seq = 0;
 
-       syslog(LOG_NOTICE, "Scheduling room <%s> for deletion\n",
-               qrbuf->QRname);
+       syslog(LOG_NOTICE, "Scheduling room <%s> for deletion", qrbuf->QRname);
 
        safestrncpy(old_name, qrbuf->QRname, sizeof old_name);
-
        CtdlGetRoom(qrbuf, qrbuf->QRname);
 
        /* Turn the room into a private mailbox owned by a user who doesn't
@@ -1144,9 +1125,7 @@ void CtdlScheduleRoomForDeletion(struct ctdlroom *qrbuf)
        );
        qrbuf->QRflags |= QR_MAILBOX;
        time(&qrbuf->QRgen);    /* Use a timestamp as the new generation number  */
-
        CtdlPutRoom(qrbuf);
-
        b_deleteroom(old_name);
 }
 
@@ -1161,22 +1140,13 @@ void CtdlScheduleRoomForDeletion(struct ctdlroom *qrbuf)
 void CtdlDeleteRoom(struct ctdlroom *qrbuf)
 {
        struct floor flbuf;
-       char filename[100];
-       /* TODO: filename magic? does this realy work? */
-
-       syslog(LOG_NOTICE, "Deleting room <%s>\n", qrbuf->QRname);
+       char configdbkeyname[25];
 
-       /* Delete the info file */
-       assoc_file_name(filename, sizeof filename, qrbuf, ctdl_info_dir);
-       unlink(filename);
+       syslog(LOG_NOTICE, "Deleting room <%s>", qrbuf->QRname);
 
-       /* Delete the image file */
-       assoc_file_name(filename, sizeof filename, qrbuf, ctdl_image_dir);
-       unlink(filename);
-
-       /* Delete the room's network config file */
-       assoc_file_name(filename, sizeof filename, qrbuf, ctdl_netcfg_dir);
-       unlink(filename);
+       /* Delete the room's network configdb entry */
+       netcfg_keyname(configdbkeyname, qrbuf->QRnumber);
+       CtdlDelConfig(configdbkeyname);
 
        /* Delete the messages in the room
         * (Careful: this opens an S_ROOMS critical section!)
@@ -1198,7 +1168,6 @@ void CtdlDeleteRoom(struct ctdlroom *qrbuf)
 }
 
 
-
 /*
  * Check access control for deleting a room
  */
@@ -1257,11 +1226,10 @@ unsigned CtdlCreateRoom(char *new_room_name,
        struct floor flbuf;
        visit vbuf;
 
-       syslog(LOG_DEBUG, "CtdlCreateRoom(name=%s, type=%d, view=%d)\n",
-               new_room_name, new_room_type, new_room_view);
+       syslog(LOG_DEBUG, "CtdlCreateRoom(name=%s, type=%d, view=%d)", new_room_name, new_room_type, new_room_view);
 
        if (CtdlGetRoom(&qrbuf, new_room_name) == 0) {
-               syslog(LOG_DEBUG, "%s already exists.\n", new_room_name);
+               syslog(LOG_DEBUG, "Cannot create room <%s> - already exists", new_room_name);
                return(0);
        }