]> code.citadel.org Git - citadel.git/blobdiff - citadel/room_ops.c
* added server command line option "-f" to defrag databases on startup
[citadel.git] / citadel / room_ops.c
index e0ab0b5aea06782576b5d426c92ce4e405c7303d..3bca3a7c211cb8b0aba861f93c1977a089ecc204 100644 (file)
@@ -1,12 +1,16 @@
 /* $Id$ */
+#include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <string.h>
+#ifdef HAVE_PTHREAD_H
 #include <pthread.h>
+#endif
 #include <time.h>
 #include <limits.h>
+#include <errno.h>
 #include "citadel.h"
 #include "server.h"
 #include "database.h"
@@ -18,6 +22,8 @@
 #include "msgbase.h"
 #include "serv_chat.h"
 #include "citserver.h"
+#include "control.h"
+#include "tools.h"
 
 /*
  * Generic routine for determining user access to rooms
@@ -115,6 +121,22 @@ NEWMSG:    /* By the way, we also check for the presence of new messages */
        return(retval);
        }
 
+/*
+ * Self-checking stuff for a room record read into memory
+ */
+void room_sanity_check(struct quickroom *qrbuf) {
+       /* Mailbox rooms are always on the lowest floor */
+       if (qrbuf->QRflags & QR_MAILBOX) {
+               qrbuf->QRfloor = 0;
+               }
+
+       /* Listing order of 0 is illegal except for base rooms */
+       if (qrbuf->QRorder == 0)
+               if (!is_noneditable(qrbuf))
+                       qrbuf->QRorder = 64;
+       }
+
+
 /*
  * getroom()  -  retrieve room data from disk
  */
@@ -138,10 +160,7 @@ int getroom(struct quickroom *qrbuf, char *room_name)
                        sizeof(struct quickroom) : cdbqr->len) );
                cdb_free(cdbqr);
 
-               /* Mailbox rooms are always on the lowest floor */
-               if (qrbuf->QRflags & QR_MAILBOX) {
-                       qrbuf->QRfloor = 0;
-                       }
+               room_sanity_check(qrbuf);
 
                return(0);
                }
@@ -272,43 +291,31 @@ void ForEachRoom(void (*CallBack)(struct quickroom *EachRoom)) {
                        ( (cdbqr->len > sizeof(struct quickroom)) ?
                        sizeof(struct quickroom) : cdbqr->len) );
                cdb_free(cdbqr);
+               room_sanity_check(&qrbuf);
                if (qrbuf.QRflags & QR_INUSE) (*CallBack)(&qrbuf);
                }
        }
 
 
 
-/*
- * Create a database key for storage of message lists
- */
-void msglist_key(char *dbkey, struct quickroom *whichroom) {
-       int a;
-       
-       sprintf(dbkey, "%s%ld", whichroom->QRname, whichroom->QRgen);
-       for (a=0; a<strlen(dbkey); ++a) dbkey[a]=tolower(dbkey[a]);
-       }
-
 /*
  * get_msglist()  -  retrieve room message pointers
  */
 void get_msglist(struct quickroom *whichroom) {
        struct cdbdata *cdbfr;
-       char dbkey[256];
 
-       msglist_key(dbkey, whichroom);  
-       
        if (CC->msglist != NULL) {
-               free(CC->msglist);
+               phree(CC->msglist);
                }
        CC->msglist = NULL;
        CC->num_msgs = 0;
 
-       cdbfr = cdb_fetch(CDB_MSGLISTS, dbkey, strlen(dbkey));
+       cdbfr = cdb_fetch(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
        if (cdbfr == NULL) {
                return;
                }
 
-       CC->msglist = malloc(cdbfr->len);
+       CC->msglist = mallok(cdbfr->len);
        memcpy(CC->msglist, cdbfr->ptr, cdbfr->len);
        CC->num_msgs = cdbfr->len / sizeof(long);
        cdb_free(cdbfr);
@@ -319,11 +326,10 @@ void get_msglist(struct quickroom *whichroom) {
  * put_msglist()  -  retrieve room message pointers
  */
 void put_msglist(struct quickroom *whichroom) {
-       char dbkey[256];
 
-       msglist_key(dbkey, whichroom);  
-       cdb_store(CDB_MSGLISTS, dbkey, strlen(dbkey),
-               CC->msglist, CC->num_msgs * sizeof(long));
+       if (CC->msglist != NULL)
+               cdb_store(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long),
+                       CC->msglist, CC->num_msgs * sizeof(long));
        }
 
 
@@ -335,10 +341,8 @@ void put_msglist(struct quickroom *whichroom) {
  *       like "gdbm: illegal data" (no big deal, but could use fixing).
  */
 void delete_msglist(struct quickroom *whichroom) {
-       char dbkey[256];
 
-       msglist_key(dbkey, whichroom);  
-       cdb_delete(CDB_MSGLISTS, dbkey, strlen(dbkey));
+       cdb_delete(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
        }
 
 
@@ -347,21 +351,26 @@ void delete_msglist(struct quickroom *whichroom) {
  * So, why doesn't this function use the get_msglist() and put_msglist() stuff
  * defined above?  Because the room the message number is being written to
  * may not be the current room (as is the case with cmd_move() for example).
+ *
+ * This function returns the highest message number present in the room after
+ * the add operation is performed - which is not necessarily the message
+ * being added.
  */
-void AddMessageToRoom(struct quickroom *whichroom, long newmsgid) {
-       char dbkey[256];
+long AddMessageToRoom(struct quickroom *whichroom, long newmsgid) {
        struct cdbdata *cdbfr;
        int num_msgs;
        long *msglist;
-       
-       msglist_key(dbkey, whichroom);
-       cdbfr = cdb_fetch(CDB_MSGLISTS, dbkey, strlen(dbkey));
+       long highest_msg = 0L;
+
+       lprintf(9, "AddMessageToRoom(%s, %ld)\n", whichroom->QRname, newmsgid); 
+       cdbfr = cdb_fetch(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
        if (cdbfr == NULL) {
                msglist = NULL;
                num_msgs = 0;
                }
        else {
-               msglist = malloc(cdbfr->len);
+               msglist = mallok(cdbfr->len);
+               if (msglist==NULL)  lprintf(3, "ERROR malloc msglist!\n");
                num_msgs = cdbfr->len / sizeof(long);
                memcpy(msglist, cdbfr->ptr, cdbfr->len);
                cdb_free(cdbfr);
@@ -369,7 +378,7 @@ void AddMessageToRoom(struct quickroom *whichroom, long newmsgid) {
        
        /* Now add the new message */
        ++num_msgs;
-       msglist = realloc(msglist,
+       msglist = reallok(msglist,
                (num_msgs * sizeof(long)) );
 
        if (msglist == NULL) {
@@ -378,12 +387,19 @@ void AddMessageToRoom(struct quickroom *whichroom, long newmsgid) {
 
        msglist[num_msgs - 1] = newmsgid;
 
+       /* Sort the message list, so all the msgid's are in order */
+       num_msgs = sort_msglist(msglist, num_msgs);
+
+       /* Determine the highest message number */
+       highest_msg = msglist[num_msgs - 1];
+
        /* Write it back to disk. */
-       cdb_store(CDB_MSGLISTS, dbkey, strlen(dbkey),
+       cdb_store(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long),
                msglist, num_msgs * sizeof(long));
 
        /* And finally, free up the memory we used. */
-       free(msglist);
+       phree(msglist);
+       return(highest_msg);
        }
 
 
@@ -483,8 +499,10 @@ void list_roomname(struct quickroom *qrbuf) {
                }
 
        /* ...and now the other parameters */
-       cprintf("|%u|%d\n",
-               qrbuf->QRflags,qrbuf->QRfloor);
+       cprintf("|%u|%d|%d\n",
+               qrbuf->QRflags,
+               (int)qrbuf->QRfloor,
+               (int)qrbuf->QRorder);
        }
 
 
@@ -681,11 +699,15 @@ void usergoto(char *where, int display_result)
 
        strcpy(CC->quickroom.QRname, where);
        getroom(&CC->quickroom, where);
+
        lgetuser(&CC->usersupp,CC->curr_user);
        CtdlGetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
 
-       vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
-       vbuf.v_flags = vbuf.v_flags | V_ACCESS;
+       /* Know the room ... but not if it's the page log room */
+       if (strcasecmp(where, config.c_logpages)) {
+               vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
+               vbuf.v_flags = vbuf.v_flags | V_ACCESS;
+               }
 
        CtdlSetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
        lputuser(&CC->usersupp,CC->curr_user);
@@ -799,6 +821,12 @@ void cmd_goto(char *gargs)
                                                ERROR+PASSWORD_REQUIRED);
                                        return;
                                        }
+                       else if ( (QRscratch.QRflags&QR_PRIVATE) &&
+                                 ((QRscratch.QRflags&QR_PASSWORDED)==0) &&
+                                 ((QRscratch.QRflags&QR_GUESSNAME)==0) &&
+                                 ((ra & UA_KNOWN) == 0) ) {
+                                       goto NOPE;
+                               }
                        else {
                                usergoto(towhere, 1);
                                return;
@@ -806,7 +834,7 @@ void cmd_goto(char *gargs)
                        }
                }
 
-       cprintf("%d room '%s' not found\n",ERROR+ROOM_NOT_FOUND,towhere);
+NOPE:  cprintf("%d room '%s' not found\n",ERROR+ROOM_NOT_FOUND,towhere);
        }
 
 
@@ -930,13 +958,14 @@ void cmd_getr(void) {
                }
 
        getroom(&CC->quickroom, CC->quickroom.QRname);
-       cprintf("%d%c%s|%s|%s|%d|%d\n",
+       cprintf("%d%c%s|%s|%s|%d|%d|%d\n",
                OK,check_express(),
                CC->quickroom.QRname,
                ((CC->quickroom.QRflags & QR_PASSWORDED) ? CC->quickroom.QRpasswd : ""),
                ((CC->quickroom.QRflags & QR_DIRECTORY) ? CC->quickroom.QRdirname : ""),
                CC->quickroom.QRflags,
-               (int)CC->quickroom.QRfloor);
+               (int)CC->quickroom.QRfloor,
+               (int)CC->quickroom.QRorder);
        }
 
 
@@ -948,6 +977,7 @@ void cmd_setr(char *args) {
        struct floor flbuf;
        char old_name[ROOMNAMELEN];
        int old_floor;
+       int new_order = 0;
 
        if (!(CC->logged_in)) {
                cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
@@ -974,6 +1004,12 @@ void cmd_setr(char *args) {
                        }
                }
 
+       if (num_parms(args)>=7) {
+               new_order = extract_int(args, 6);
+               if (new_order < 1) new_order = 1;
+               if (new_order > 127) new_order = 127;
+               }
+
        lgetroom(&CC->quickroom, CC->quickroom.QRname);
        strcpy(old_name, CC->quickroom.QRname);
        extract(buf,args,0); buf[ROOMNAMELEN]=0;
@@ -983,6 +1019,8 @@ void cmd_setr(char *args) {
        extract(buf,args,2); buf[15]=0;
        strncpy(CC->quickroom.QRdirname,buf,19);
        CC->quickroom.QRflags = ( extract_int(args,3) | QR_INUSE);
+       if (num_parms(args)>=7)
+               CC->quickroom.QRorder = (char)new_order;
 
        /* Clean up a client boo-boo: if the client set the room to
         * guess-name or passworded, ensure that the private flag is
@@ -1010,10 +1048,6 @@ void cmd_setr(char *args) {
        /* If the room name changed, then there are now two room records,
         * so we have to delete the old one.
         */
-       /* FIX - This causes everybody to think it's a new room, because the
-        *       visit structs no longer match!  Major problem!  We have to
-        *       assign each room a unique Object ID and index by that.
-        */
        if (strcasecmp(CC->quickroom.QRname, old_name)) {
                putroom(NULL, old_name);
                }
@@ -1118,12 +1152,7 @@ void cmd_seta(char *new_ra)
  * Generate an associated file name for a room
  */
 void assoc_file_name(char *buf, struct quickroom *qrbuf, char *prefix) {
-       int a;
-
-       sprintf(buf, "./prefix/%s.%ld", qrbuf->QRname, qrbuf->QRgen);
-       for (a=0; a<strlen(buf); ++a) {
-               if (buf[a]==32) buf[a]='.';
-               }
+       sprintf(buf, "./%s/%ld", prefix, qrbuf->QRnumber);
        }
 
 /* 
@@ -1181,7 +1210,7 @@ void delete_room(struct quickroom *qrbuf) {
                cdb_delete(CDB_MSGMAIN, &MsgToDelete, sizeof(long));
                }
        put_msglist(qrbuf);
-       free(CC->msglist);
+       phree(CC->msglist);
        CC->msglist = NULL;
        CC->num_msgs = 0;
        delete_msglist(qrbuf);
@@ -1260,6 +1289,7 @@ unsigned create_room(char *new_room_name,
        strncpy(qrbuf.QRname,new_room_name,ROOMNAMELEN);
        strncpy(qrbuf.QRpasswd,new_room_pass,9);
        qrbuf.QRflags = QR_INUSE;
+       qrbuf.QRnumber = get_new_room_number();
        if (new_room_type > 0) qrbuf.QRflags=(qrbuf.QRflags|QR_PRIVATE);
        if (new_room_type == 1) qrbuf.QRflags=(qrbuf.QRflags|QR_GUESSNAME);
        if (new_room_type == 2) qrbuf.QRflags=(qrbuf.QRflags|QR_PASSWORDED);
@@ -1329,6 +1359,12 @@ void cmd_cre8(char *args)
                return;
                }
 
+       if (!strcasecmp(new_room_name, MAILROOM)) {
+               cprintf("%d '%s' already exists.\n",
+                       ERROR+ALREADY_EXISTS, new_room_name);
+               return;
+               }
+
        if (num_parms(args)>=5) {
                getfloor(&flbuf,extract_int(args,4));
                if ((flbuf.f_flags & F_INUSE) == 0) {
@@ -1346,7 +1382,7 @@ void cmd_cre8(char *args)
                return;
                }
 
-       if (CC->usersupp.axlevel<3) {
+       if (CC->usersupp.axlevel < config.c_createax) {
                cprintf("%d You need higher access to create rooms.\n",
                        ERROR+HIGHER_ACCESS_REQUIRED);
                return;
@@ -1360,7 +1396,7 @@ void cmd_cre8(char *args)
        /* Check to make sure the requested room name doesn't already exist */
        if (getroom(&qrbuf, new_room_name)==0) {
                cprintf("%d '%s' already exists.\n",
-                       ERROR,qrbuf.QRname);
+                       ERROR+ALREADY_EXISTS, qrbuf.QRname);
                return;
                }
 
@@ -1397,7 +1433,7 @@ void cmd_cre8(char *args)
 void cmd_einf(char *ok)
 {      /* enter info file for current room */
        FILE *fp;
-       char infofilename[64];
+       char infofilename[256];
        char buf[256];
 
        if (!(CC->logged_in)) {
@@ -1416,11 +1452,18 @@ void cmd_einf(char *ok)
                return;
                }
 
-       cprintf("%d Send info...\n",SEND_LISTING);
-
        assoc_file_name(infofilename, &CC->quickroom, "info");
+       lprintf(9, "opening\n");
+       fp = fopen(infofilename, "w");
+       lprintf(9, "checking\n");
+       if (fp == NULL) {
+               cprintf("%d Cannot open %s: %s\n",
+                       ERROR+INTERNAL_ERROR, infofilename, strerror(errno));
+               return;
+               }
+
+       cprintf("%d Send info...\n", SEND_LISTING);
 
-       fp=fopen(infofilename,"w");
        do {
                client_gets(buf);
                if (strcmp(buf,"000")) fprintf(fp,"%s\n",buf);