]> code.citadel.org Git - citadel.git/blobdiff - citadel/room_ops.c
Implemented "access level required to create rooms" (client & server)
[citadel.git] / citadel / room_ops.c
index 13022f258fb18b438b791a8d78e22ca0d6c0bad1..5efcdc72435c6d479cf0708824955147b3ed84a9 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
@@ -38,8 +44,10 @@ int CtdlRoomAccess(struct quickroom *roombuf, struct usersupp *userbuf) {
                        }
                }
 
+       /* Locate any applicable user/room relationships */
+       CtdlGetRelationship(&vbuf, userbuf, roombuf);
+
        /* Force the properties of the Aide room */
-       /* FIX FIX FIX ... this doesn't work */
        if (!strcasecmp(roombuf->QRname, AIDEROOM)) {
                if (userbuf->axlevel >= 6) {
                        retval = UA_KNOWN | UA_GOTOALLOWED;
@@ -50,9 +58,6 @@ int CtdlRoomAccess(struct quickroom *roombuf, struct usersupp *userbuf) {
                goto NEWMSG;
                }
 
-       /* Locate any applicable user/room relationships */
-       CtdlGetRelationship(&vbuf, userbuf, roombuf);
-
        /* For mailboxes, we skip all the access stuff (and we've
         * already checked by this point that the mailbox belongs
         * to the user)
@@ -116,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,6 +159,9 @@ int getroom(struct quickroom *qrbuf, char *room_name)
                        ( (cdbqr->len > sizeof(struct quickroom)) ?
                        sizeof(struct quickroom) : cdbqr->len) );
                cdb_free(cdbqr);
+
+               room_sanity_check(qrbuf);
+
                return(0);
                }
        else {
@@ -267,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);
@@ -314,22 +326,22 @@ 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),
+       cdb_store(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long),
                CC->msglist, CC->num_msgs * sizeof(long));
        }
 
 
 /*
  * delete_msglist()  -  delete room message pointers
+ * FIX - this really should check first to make sure there's actually a
+ *       msglist to delete.  As things stand now, calling this function on
+ *       a room which has never been posted in will result in a message
+ *       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));
        }
 
 
@@ -338,21 +350,24 @@ 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;
+       long highest_msg = 0L;
        
-       msglist_key(dbkey, whichroom);
-       cdbfr = cdb_fetch(CDB_MSGLISTS, dbkey, strlen(dbkey));
+       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);
                num_msgs = cdbfr->len / sizeof(long);
                memcpy(msglist, cdbfr->ptr, cdbfr->len);
                cdb_free(cdbfr);
@@ -360,7 +375,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) {
@@ -369,12 +384,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);
        }
 
 
@@ -439,11 +461,18 @@ int sort_msglist(long listptrs[], int oldcount)
 
 
 /*
- * Determine whether a given room is one of the base non-editable rooms
+ * Determine whether a given room is non-editable.
  */
 int is_noneditable(struct quickroom *qrbuf) {
+
+       /* Lobby> and Aide> are non-editable */
        if (!strcasecmp(qrbuf->QRname, BASEROOM)) return(1);
        else if (!strcasecmp(qrbuf->QRname, AIDEROOM)) return(1);
+
+       /* Mailbox rooms are also non-editable */
+       else if (qrbuf->QRflags & QR_MAILBOX) return(1);
+
+       /* Everything else is editable */
        else return(0);
        }
 
@@ -467,8 +496,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);
        }
 
 
@@ -665,11 +696,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);
@@ -712,12 +747,7 @@ void usergoto(char *where, int display_result)
                vbuf.v_lastseen,
                rmailflag,raideflag,newmailcount,CC->quickroom.QRfloor);
 
-       if (CC->quickroom.QRflags & QR_PRIVATE) {
-               set_wtmpsupp("<private room>");
-               }
-       else {
-               set_wtmpsupp(CC->quickroom.QRname);
-               }
+       set_wtmpsupp_to_current_room();
        }
 
 
@@ -788,6 +818,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;
@@ -795,7 +831,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);
        }
 
 
@@ -919,13 +955,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);
        }
 
 
@@ -935,7 +972,9 @@ void cmd_getr(void) {
 void cmd_setr(char *args) {
        char buf[256];
        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);
@@ -962,7 +1001,14 @@ 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;
        strncpy(CC->quickroom.QRname,buf,ROOMNAMELEN-1);
        extract(buf,args,1); buf[10]=0;
@@ -970,6 +1016,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
@@ -991,8 +1039,16 @@ void cmd_setr(char *args) {
                CC->quickroom.QRfloor = extract_int(args,5);
                }
 
+       /* Write the room record back to disk */
        lputroom(&CC->quickroom, CC->quickroom.QRname);
 
+       /* If the room name changed, then there are now two room records,
+        * so we have to delete the old one.
+        */
+       if (strcasecmp(CC->quickroom.QRname, old_name)) {
+               putroom(NULL, old_name);
+               }
+
        /* adjust the floor reference counts */
        lgetfloor(&flbuf,old_floor);
        --flbuf.f_ref_count;
@@ -1093,12 +1149,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);
        }
 
 /* 
@@ -1135,6 +1186,8 @@ void delete_room(struct quickroom *qrbuf) {
        char aaa[100];
        int a;
 
+       lprintf(9, "Deleting room <%s>\n", qrbuf->QRname);
+
        /* Delete the info file */
        assoc_file_name(aaa, qrbuf, "info");
        unlink(aaa);
@@ -1154,7 +1207,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);
@@ -1233,6 +1286,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);
@@ -1302,6 +1356,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) {
@@ -1319,7 +1379,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;
@@ -1333,7 +1393,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;
                }
 
@@ -1370,7 +1430,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)) {
@@ -1389,11 +1449,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);