]> code.citadel.org Git - citadel.git/blobdiff - citadel/room_ops.c
Started implementing global room numbers.
[citadel.git] / citadel / room_ops.c
index 4aa538e8020f4d3e9379e4cb199f9c686bbac70c..7b306ae585b937bd1e851680751079c3f2b76775 100644 (file)
@@ -1,3 +1,4 @@
+/* $Id$ */
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -17,6 +18,7 @@
 #include "msgbase.h"
 #include "serv_chat.h"
 #include "citserver.h"
+#include "control.h"
 
 /*
  * Generic routine for determining user access to rooms
@@ -25,22 +27,41 @@ int CtdlRoomAccess(struct quickroom *roombuf, struct usersupp *userbuf) {
        int retval = 0;
        struct visit vbuf;
 
-       /* Make sure we're dealing with a real, existing room */
-       if (roombuf->QRflags & QR_INUSE) {
-               retval = retval | UA_INUSE;
-               }
-       else {
-               return(0);
-               }
-
        /* for internal programs, always do everything */
        if (((CC->internal_pgm))&&(roombuf->QRflags & QR_INUSE)) {
-               return(UA_INUSE | UA_KNOWN | UA_GOTOALLOWED);
+               return(UA_KNOWN | UA_GOTOALLOWED);
+               }
+
+       /* For mailbox rooms, only allow access to the owner */
+       if (roombuf->QRflags & QR_MAILBOX) {
+               if (userbuf->usernum != atol(roombuf->QRname)) {
+                       return(retval);
+                       }
                }
 
        /* Locate any applicable user/room relationships */
        CtdlGetRelationship(&vbuf, userbuf, roombuf);
 
+       /* Force the properties of the Aide room */
+       if (!strcasecmp(roombuf->QRname, AIDEROOM)) {
+               if (userbuf->axlevel >= 6) {
+                       retval = UA_KNOWN | UA_GOTOALLOWED;
+                       }
+               else {
+                       retval=0;
+                       }
+               goto NEWMSG;
+               }
+
+       /* For mailboxes, we skip all the access stuff (and we've
+        * already checked by this point that the mailbox belongs
+        * to the user)
+        */
+       if (roombuf->QRflags & QR_MAILBOX) {
+               retval = UA_KNOWN | UA_GOTOALLOWED;
+               goto NEWMSG;
+               }
+
        /* If this is a public room, it's accessible... */
        if ((roombuf->QRflags & QR_PRIVATE) == 0) {
                retval = retval | UA_KNOWN | UA_GOTOALLOWED;
@@ -83,11 +104,11 @@ int CtdlRoomAccess(struct quickroom *roombuf, struct usersupp *userbuf) {
 
        /* Aides get access to everything */
        if (userbuf->axlevel >= 6) {
-               retval = retval | UA_INUSE | UA_KNOWN | UA_GOTOALLOWED;
+               retval = retval | UA_KNOWN | UA_GOTOALLOWED;
                retval = retval & ~UA_ZAPPED;
                }
 
-       /* By the way, we also check for the presence of new messages */
+NEWMSG:        /* By the way, we also check for the presence of new messages */
        if ( (roombuf->QRhighest) > (vbuf.v_lastseen) ) {
                retval = retval | UA_HASNEWMSGS;
                }
@@ -104,11 +125,12 @@ int getroom(struct quickroom *qrbuf, char *room_name)
        char lowercase_name[ROOMNAMELEN];
        int a;
 
-       for (a=0; a<=strlen(room_name); ++a) {
+       for (a=0; room_name[a] && a < sizeof lowercase_name - 1; ++a) {
                lowercase_name[a] = tolower(room_name[a]);
                }
+       lowercase_name[a] = 0;
 
-       bzero(qrbuf, sizeof(struct quickroom));
+       memset(qrbuf, 0, sizeof(struct quickroom));
        cdbqr = cdb_fetch(CDB_QUICKROOM,
                        lowercase_name, strlen(lowercase_name));
        if (cdbqr != NULL) {
@@ -116,6 +138,12 @@ int getroom(struct quickroom *qrbuf, char *room_name)
                        ( (cdbqr->len > sizeof(struct quickroom)) ?
                        sizeof(struct quickroom) : cdbqr->len) );
                cdb_free(cdbqr);
+
+               /* Mailbox rooms are always on the lowest floor */
+               if (qrbuf->QRflags & QR_MAILBOX) {
+                       qrbuf->QRfloor = 0;
+                       }
+
                return(0);
                }
        else {
@@ -179,7 +207,7 @@ void getfloor(struct floor *flbuf, int floor_num)
 {
        struct cdbdata *cdbfl;
 
-       bzero(flbuf, sizeof(struct floor));
+       memset(flbuf, 0, sizeof(struct floor));
        cdbfl = cdb_fetch(CDB_FLOORTAB, &floor_num, sizeof(int));
        if (cdbfl != NULL) {
                memcpy(flbuf, cdbfl->ptr,
@@ -240,7 +268,7 @@ void ForEachRoom(void (*CallBack)(struct quickroom *EachRoom)) {
        cdb_rewind(CDB_QUICKROOM);
 
        while(cdbqr = cdb_next_item(CDB_QUICKROOM), cdbqr != NULL) {
-               bzero(&qrbuf, sizeof(struct quickroom));
+               memset(&qrbuf, 0, sizeof(struct quickroom));
                memcpy(&qrbuf, cdbqr->ptr,
                        ( (cdbqr->len > sizeof(struct quickroom)) ?
                        sizeof(struct quickroom) : cdbqr->len) );
@@ -256,25 +284,14 @@ void ForEachRoom(void (*CallBack)(struct quickroom *EachRoom)) {
  */
 void get_msglist(struct quickroom *whichroom) {
        struct cdbdata *cdbfr;
-       char dbkey[256];
-       int a;
-       
-       lprintf(9, "get_msglist() called for <%s>\n", whichroom->QRname);
-       sprintf(dbkey, "%s%ld", whichroom->QRname, whichroom->QRgen);
-       for (a=0; a<strlen(dbkey); ++a) dbkey[a]=tolower(dbkey[a]);
-       lprintf(9, "database key is <%s>\n", dbkey);
-       
-       lprintf(9, "Freeing existing message list\n");
+
        if (CC->msglist != NULL) {
                free(CC->msglist);
                }
        CC->msglist = NULL;
        CC->num_msgs = 0;
 
-       lprintf(9, "calling cdb_fetch\n");
-       cdbfr = cdb_fetch(CDB_MSGLISTS, dbkey, strlen(dbkey));
-       lprintf(9, "done\n");
-
+       cdbfr = cdb_fetch(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
        if (cdbfr == NULL) {
                return;
                }
@@ -283,7 +300,6 @@ void get_msglist(struct quickroom *whichroom) {
        memcpy(CC->msglist, cdbfr->ptr, cdbfr->len);
        CC->num_msgs = cdbfr->len / sizeof(long);
        cdb_free(cdbfr);
-       lprintf(9, "Leaving get_msglist()\n");
        }
 
 
@@ -291,28 +307,65 @@ void get_msglist(struct quickroom *whichroom) {
  * put_msglist()  -  retrieve room message pointers
  */
 void put_msglist(struct quickroom *whichroom) {
-       char dbkey[256];
-       int a;
 
-       sprintf(dbkey, "%s%ld", whichroom->QRname, whichroom->QRgen);
-       for (a=0; a<strlen(dbkey); ++a) dbkey[a]=tolower(dbkey[a]);
-
-       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];
-       int a;
 
-       sprintf(dbkey, "%s%ld", whichroom->QRname, whichroom->QRgen);
-       for (a=0; a<strlen(dbkey); ++a) dbkey[a]=tolower(dbkey[a]);
+       cdb_delete(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
+       }
 
-       cdb_delete(CDB_MSGLISTS, dbkey, strlen(dbkey));
+
+/* 
+ * Add a message number to a room's message list.  
+ * 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).
+ */
+void AddMessageToRoom(struct quickroom *whichroom, long newmsgid) {
+       struct cdbdata *cdbfr;
+       int num_msgs;
+       long *msglist;
+       
+       cdbfr = cdb_fetch(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
+       if (cdbfr == NULL) {
+               msglist = NULL;
+               num_msgs = 0;
+               }
+       else {
+               msglist = malloc(cdbfr->len);
+               num_msgs = cdbfr->len / sizeof(long);
+               memcpy(msglist, cdbfr->ptr, cdbfr->len);
+               cdb_free(cdbfr);
+               }
+       
+       /* Now add the new message */
+       ++num_msgs;
+       msglist = realloc(msglist,
+               (num_msgs * sizeof(long)) );
+
+       if (msglist == NULL) {
+               lprintf(3, "ERROR: can't realloc message list!\n");
+               }
+
+       msglist[num_msgs - 1] = newmsgid;
+
+       /* Write it back to disk. */
+       cdb_store(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long),
+               msglist, num_msgs * sizeof(long));
+
+       /* And finally, free up the memory we used. */
+       free(msglist);
        }
 
 
@@ -375,7 +428,47 @@ int sort_msglist(long listptrs[], int oldcount)
        return(numitems);
        }
 
+
+/*
+ * 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);
+       }
+
+
+
+/*
+ * Back-back-end for all room listing commands
+ */
+void list_roomname(struct quickroom *qrbuf) {
+       char truncated_roomname[ROOMNAMELEN];
+
+       /* For mailbox rooms, chop off the owner prefix */
+       if (qrbuf->QRflags & QR_MAILBOX) {
+               strcpy(truncated_roomname, qrbuf->QRname);
+               strcpy(truncated_roomname, &truncated_roomname[11]);
+               cprintf("%s", truncated_roomname);
+               }
+       /* For all other rooms, just display the name in its entirety */
+       else {
+               cprintf("%s", qrbuf->QRname);
+               }
+
+       /* ...and now the other parameters */
+       cprintf("|%u|%d\n",
+               qrbuf->QRflags,qrbuf->QRfloor);
+       }
+
 
 /* 
  * cmd_lrms()   -  List all accessible rooms, known or forgotten
@@ -385,8 +478,7 @@ void cmd_lrms_backend(struct quickroom *qrbuf) {
             & (UA_KNOWN | UA_ZAPPED)))
        && ((qrbuf->QRfloor == (CC->FloorBeingSearched))
           ||((CC->FloorBeingSearched)<0)) ) 
-               cprintf("%s|%u|%d\n",
-                       qrbuf->QRname,qrbuf->QRflags,qrbuf->QRfloor);
+               list_roomname(qrbuf);
        }
 
 void cmd_lrms(char *argbuf)
@@ -419,9 +511,8 @@ void cmd_lkra_backend(struct quickroom *qrbuf) {
        if ( ((CtdlRoomAccess(qrbuf, &CC->usersupp)
             & (UA_KNOWN)))
        && ((qrbuf->QRfloor == (CC->FloorBeingSearched))
-          ||((CC->FloorBeingSearched)<0)) ) 
-               cprintf("%s|%u|%d\n",
-                       qrbuf->QRname,qrbuf->QRflags,qrbuf->QRfloor);
+          ||((CC->FloorBeingSearched)<0)) )
+               list_roomname(qrbuf);
        }
 
 void cmd_lkra(char *argbuf)
@@ -458,8 +549,7 @@ void cmd_lkrn_backend(struct quickroom *qrbuf) {
           && (ra & UA_HASNEWMSGS)
           && ((qrbuf->QRfloor == (CC->FloorBeingSearched))
              ||((CC->FloorBeingSearched)<0)) )
-               cprintf("%s|%u|%d\n",
-                       qrbuf->QRname,qrbuf->QRflags,qrbuf->QRfloor);
+               list_roomname(qrbuf);
        }
 
 void cmd_lkrn(char *argbuf)
@@ -496,8 +586,7 @@ void cmd_lkro_backend(struct quickroom *qrbuf) {
           && ((ra & UA_HASNEWMSGS)==0)
           && ((qrbuf->QRfloor == (CC->FloorBeingSearched))
              ||((CC->FloorBeingSearched)<0)) )
-               cprintf("%s|%u|%d\n",
-                       qrbuf->QRname,qrbuf->QRflags,qrbuf->QRfloor);
+               list_roomname(qrbuf);
        }
 
 void cmd_lkro(char *argbuf)
@@ -534,8 +623,7 @@ void cmd_lzrm_backend(struct quickroom *qrbuf) {
           && (ra & UA_ZAPPED)
           && ((qrbuf->QRfloor == (CC->FloorBeingSearched))
              ||((CC->FloorBeingSearched)<0)) )
-               cprintf("%s|%u|%d\n",
-                       qrbuf->QRname,qrbuf->QRflags,qrbuf->QRfloor);
+               list_roomname(qrbuf);
        }
 
 void cmd_lzrm(char *argbuf)
@@ -571,13 +659,11 @@ void usergoto(char *where, int display_result)
        int raideflag;
        int newmailcount = 0;
        struct visit vbuf;
+       char truncated_roomname[ROOMNAMELEN];
 
        strcpy(CC->quickroom.QRname, where);
-       lprintf(9, "usergoto() fetching room record\n");
        getroom(&CC->quickroom, where);
-       lprintf(9, "usergoto() fetching user record\n");
        lgetuser(&CC->usersupp,CC->curr_user);
-       lprintf(9, "usergoto() fetching relationships\n");
        CtdlGetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
 
        vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
@@ -586,7 +672,6 @@ void usergoto(char *where, int display_result)
        CtdlSetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
        lputuser(&CC->usersupp,CC->curr_user);
 
-       lprintf(9, "usergoto() about to check for new mail\n");
        /* check for new mail */
        newmailcount = NewMailCount();
 
@@ -594,7 +679,6 @@ void usergoto(char *where, int display_result)
        if (CC->quickroom.QRinfo > vbuf.v_lastseen) info = 1;
 
        get_mm();
-       lprintf(9, "Fetching message list for counting...\n");
        get_msglist(&CC->quickroom);
        for (a=0; a<CC->num_msgs; ++a) {
                if (MessageFromList(a)>0L) {
@@ -604,7 +688,6 @@ void usergoto(char *where, int display_result)
                                }
                        }
                }
-       lprintf(9, "...done counting\n");
 
        if (CC->quickroom.QRflags & QR_MAILBOX) rmailflag = 1;
        else rmailflag = 0;
@@ -613,21 +696,21 @@ void usergoto(char *where, int display_result)
           || (CC->usersupp.axlevel>=6) )  raideflag = 1;
        else raideflag = 0;
 
+       strcpy(truncated_roomname, CC->quickroom.QRname);
+       if (CC->quickroom.QRflags & QR_MAILBOX) {
+               strcpy(truncated_roomname, &truncated_roomname[11]);
+               }
+
        if (display_result) cprintf("%d%c%s|%d|%d|%d|%d|%ld|%ld|%d|%d|%d|%d\n",
                OK,check_express(),
-               CC->quickroom.QRname,
+               truncated_roomname,
                new_messages, total_messages,
                info,CC->quickroom.QRflags,
                CC->quickroom.QRhighest,
                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();
        }
 
 
@@ -640,7 +723,9 @@ void cmd_goto(char *gargs)
        int c;
        int ok = 0;
        int ra;
-       char bbb[ROOMNAMELEN],towhere[32],password[20];
+       char augmented_roomname[256];
+       char towhere[256];
+       char password[256];
 
        if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
                cprintf("%d not logged in\n",ERROR+NOT_LOGGED_IN);
@@ -650,8 +735,7 @@ void cmd_goto(char *gargs)
        extract(towhere,gargs,0);
        extract(password,gargs,1);
 
-       c=0;
-       getuser(&CC->usersupp,CC->curr_user);
+       getuser(&CC->usersupp, CC->curr_user);
 
        if (!strcasecmp(towhere, "_BASEROOM_"))
                strcpy(towhere, BASEROOM);
@@ -663,13 +747,24 @@ void cmd_goto(char *gargs)
                strcpy(towhere, config.c_twitroom);
 
 
-       /* let internal programs go directly to any room */
-       if (((CC->internal_pgm))&&(!strcasecmp(bbb,towhere))) {
-               usergoto(towhere, 1);
-               return;
+       /* First try a regular match */
+       c = getroom(&QRscratch, towhere);
+
+       /* Then try a mailbox name match */
+       if (c != 0) {
+               MailboxName(augmented_roomname, &CC->usersupp, towhere);
+               c = getroom(&QRscratch, augmented_roomname);
+               if (c == 0) strcpy(towhere, augmented_roomname);
                }
 
-       if (getroom(&QRscratch, towhere) == 0) {
+       /* And if the room was found... */
+       if (c == 0) {
+
+               /* let internal programs go directly to any room */
+               if (CC->internal_pgm) {
+                       usergoto(towhere, 1);
+                       return;
+                       }
 
                /* See if there is an existing user/room relationship */
                ra = CtdlRoomAccess(&QRscratch, &CC->usersupp);
@@ -716,7 +811,7 @@ void cmd_whok(void) {
        cprintf("%d Who knows room:\n",LISTING_FOLLOWS);
        cdb_rewind(CDB_USERSUPP);
        while(cdbus = cdb_next_item(CDB_USERSUPP), cdbus != NULL) {
-               bzero(&temp, sizeof(struct usersupp));
+               memset(&temp, 0, sizeof(struct usersupp));
                memcpy(&temp, cdbus->ptr, cdbus->len);
                cdb_free(cdbus);
 
@@ -811,8 +906,7 @@ void cmd_getr(void) {
                return;
                }
 
-       if ( (!strcasecmp(CC->quickroom.QRname, BASEROOM))
-            || (!strcasecmp(CC->quickroom.QRname, AIDEROOM)) ) {
+       if (is_noneditable(&CC->quickroom)) {
                cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
                return;
                }
@@ -834,6 +928,7 @@ void cmd_getr(void) {
 void cmd_setr(char *args) {
        char buf[256];
        struct floor flbuf;
+       char old_name[ROOMNAMELEN];
        int old_floor;
 
        if (!(CC->logged_in)) {
@@ -847,8 +942,7 @@ void cmd_setr(char *args) {
                return;
                }
 
-       if ( (!strcasecmp(CC->quickroom.QRname, BASEROOM))
-            || (!strcasecmp(CC->quickroom.QRname, AIDEROOM)) ) {
+       if (is_noneditable(&CC->quickroom)) {
                cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
                return;
                }
@@ -863,6 +957,7 @@ void cmd_setr(char *args) {
                }
 
        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;
@@ -891,8 +986,20 @@ 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.
+        */
+       /* 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);
+               }
+
        /* adjust the floor reference counts */
        lgetfloor(&flbuf,old_floor);
        --flbuf.f_ref_count;
@@ -927,8 +1034,7 @@ void cmd_geta(void) {
                return;
                }
 
-       if ( (!strcasecmp(CC->quickroom.QRname, BASEROOM))
-            || (!strcasecmp(CC->quickroom.QRname, AIDEROOM)) ) {
+       if (is_noneditable(&CC->quickroom)) {
                cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
                return;
                }
@@ -1036,6 +1142,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);
@@ -1049,19 +1157,15 @@ void delete_room(struct quickroom *qrbuf) {
        qrbuf->QRflags=0;
 
        /* then delete the messages in the room */
-       lprintf(9, "calling get_msglist()\n");
        get_msglist(qrbuf);
        if (CC->num_msgs > 0) for (a=0; a < CC->num_msgs; ++a) {
                MsgToDelete = MessageFromList(a);
-               lprintf(9, "Deleting message %ld\n", MsgToDelete);
                cdb_delete(CDB_MSGMAIN, &MsgToDelete, sizeof(long));
                }
-       lprintf(9, "calling put_msglist()\n");
        put_msglist(qrbuf);
        free(CC->msglist);
        CC->msglist = NULL;
        CC->num_msgs = 0;
-       lprintf(9, "calling delete_msglist()\n");
        delete_msglist(qrbuf);
        lputroom(qrbuf, qrbuf->QRname);
 
@@ -1072,7 +1176,6 @@ void delete_room(struct quickroom *qrbuf) {
 
        /* Delete the room record from the database! */
        putroom(NULL, qrbuf->QRname);
-       lprintf(9, "finished with delete_room()\n");
        }
 
 
@@ -1097,8 +1200,7 @@ void cmd_kill(char *argbuf) {
                return;
                }
 
-       if ( (!strcasecmp(CC->quickroom.QRname, BASEROOM))
-            || (!strcasecmp(CC->quickroom.QRname, AIDEROOM)) ) {
+       if (is_noneditable(&CC->quickroom)) {
                cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
                return;
                }
@@ -1106,16 +1208,12 @@ void cmd_kill(char *argbuf) {
        if (kill_ok) {
                strcpy(deleted_room_name, CC->quickroom.QRname);
                delete_room(&CC->quickroom);    /* Do the dirty work */
-               lprintf(9, "Calling usergoto()\n");
                usergoto(BASEROOM, 0);          /* Return to the Lobby */
 
-               lprintf(9, "Composing notice\n");
                /* tell the world what we did */
                sprintf(aaa,"%s> killed by %s",
                        deleted_room_name, CC->curr_user);
-               lprintf(9, "Posting notice\n");
                aide_message(aaa);
-               lprintf(9, "done posting notice\n");
                cprintf("%d '%s' deleted.\n", OK, deleted_room_name);
                }
        else {
@@ -1140,10 +1238,11 @@ unsigned create_room(char *new_room_name,
 
        if (getroom(&qrbuf, new_room_name)==0) return(0); /* already exists */
 
-       bzero(&qrbuf, sizeof(struct quickroom));
+       memset(&qrbuf, 0, sizeof(struct quickroom));
        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);