]> code.citadel.org Git - citadel.git/blob - citadel/room_ops.c
3bca3a7c211cb8b0aba861f93c1977a089ecc204
[citadel.git] / citadel / room_ops.c
1 /* $Id$ */
2 #include "sysdep.h"
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <stdio.h>
6 #include <sys/stat.h>
7 #include <string.h>
8 #ifdef HAVE_PTHREAD_H
9 #include <pthread.h>
10 #endif
11 #include <time.h>
12 #include <limits.h>
13 #include <errno.h>
14 #include "citadel.h"
15 #include "server.h"
16 #include "database.h"
17 #include "config.h"
18 #include "room_ops.h"
19 #include "sysdep_decls.h"
20 #include "support.h"
21 #include "user_ops.h"
22 #include "msgbase.h"
23 #include "serv_chat.h"
24 #include "citserver.h"
25 #include "control.h"
26 #include "tools.h"
27
28 /*
29  * Generic routine for determining user access to rooms
30  */
31 int CtdlRoomAccess(struct quickroom *roombuf, struct usersupp *userbuf) {
32         int retval = 0;
33         struct visit vbuf;
34
35         /* for internal programs, always do everything */
36         if (((CC->internal_pgm))&&(roombuf->QRflags & QR_INUSE)) {
37                 return(UA_KNOWN | UA_GOTOALLOWED);
38                 }
39
40         /* For mailbox rooms, only allow access to the owner */
41         if (roombuf->QRflags & QR_MAILBOX) {
42                 if (userbuf->usernum != atol(roombuf->QRname)) {
43                         return(retval);
44                         }
45                 }
46
47         /* Locate any applicable user/room relationships */
48         CtdlGetRelationship(&vbuf, userbuf, roombuf);
49
50         /* Force the properties of the Aide room */
51         if (!strcasecmp(roombuf->QRname, AIDEROOM)) {
52                 if (userbuf->axlevel >= 6) {
53                         retval = UA_KNOWN | UA_GOTOALLOWED;
54                         }
55                 else {
56                         retval=0;
57                         }
58                 goto NEWMSG;
59                 }
60
61         /* For mailboxes, we skip all the access stuff (and we've
62          * already checked by this point that the mailbox belongs
63          * to the user)
64          */
65         if (roombuf->QRflags & QR_MAILBOX) {
66                 retval = UA_KNOWN | UA_GOTOALLOWED;
67                 goto NEWMSG;
68                 }
69
70         /* If this is a public room, it's accessible... */
71         if ((roombuf->QRflags & QR_PRIVATE) == 0) {
72                 retval = retval | UA_KNOWN | UA_GOTOALLOWED;
73                 }
74
75         /* If this is a preferred users only room, check access level */
76         if (roombuf->QRflags & QR_PREFONLY) {
77                 if (userbuf->axlevel < 5) {
78                         retval = retval & ~UA_KNOWN & ~UA_GOTOALLOWED;
79                         }
80                 }
81
82         /* For private rooms, check the generation number matchups */
83         if (roombuf->QRflags & QR_PRIVATE) {
84
85                 /* An explicit match means the user belongs in this room */
86                 if (vbuf.v_flags & V_ACCESS) {
87                         retval = retval | UA_KNOWN | UA_GOTOALLOWED;
88                         }
89                 /* Otherwise, check if this is a guess-name or passworded
90                  * room.  If it is, a goto may at least be attempted
91                  */
92                 else if ((roombuf->QRflags & QR_PRIVATE)
93                      ||(roombuf->QRflags & QR_PASSWORDED)) {
94                         retval = retval & ~UA_KNOWN;
95                         retval = retval | UA_GOTOALLOWED;
96                         }
97                 }
98
99         /* Check to see if the user has forgotten this room */
100         if (vbuf.v_flags & V_FORGET) {
101                 retval = retval & ~UA_KNOWN;
102                 retval = retval | UA_ZAPPED;
103                 }
104
105         /* If user is explicitly locked out of this room, deny everything */
106         if (vbuf.v_flags & V_LOCKOUT) {
107                 retval = retval & ~UA_KNOWN & ~UA_GOTOALLOWED;
108                 }
109
110         /* Aides get access to everything */
111         if (userbuf->axlevel >= 6) {
112                 retval = retval | UA_KNOWN | UA_GOTOALLOWED;
113                 retval = retval & ~UA_ZAPPED;
114                 }
115
116 NEWMSG: /* By the way, we also check for the presence of new messages */
117         if ( (roombuf->QRhighest) > (vbuf.v_lastseen) ) {
118                 retval = retval | UA_HASNEWMSGS;
119                 }
120
121         return(retval);
122         }
123
124 /*
125  * Self-checking stuff for a room record read into memory
126  */
127 void room_sanity_check(struct quickroom *qrbuf) {
128         /* Mailbox rooms are always on the lowest floor */
129         if (qrbuf->QRflags & QR_MAILBOX) {
130                 qrbuf->QRfloor = 0;
131                 }
132
133         /* Listing order of 0 is illegal except for base rooms */
134         if (qrbuf->QRorder == 0)
135                 if (!is_noneditable(qrbuf))
136                         qrbuf->QRorder = 64;
137         }
138
139
140 /*
141  * getroom()  -  retrieve room data from disk
142  */
143 int getroom(struct quickroom *qrbuf, char *room_name)
144 {
145         struct cdbdata *cdbqr;
146         char lowercase_name[ROOMNAMELEN];
147         int a;
148
149         for (a=0; room_name[a] && a < sizeof lowercase_name - 1; ++a) {
150                 lowercase_name[a] = tolower(room_name[a]);
151                 }
152         lowercase_name[a] = 0;
153
154         memset(qrbuf, 0, sizeof(struct quickroom));
155         cdbqr = cdb_fetch(CDB_QUICKROOM,
156                         lowercase_name, strlen(lowercase_name));
157         if (cdbqr != NULL) {
158                 memcpy(qrbuf, cdbqr->ptr,
159                         ( (cdbqr->len > sizeof(struct quickroom)) ?
160                         sizeof(struct quickroom) : cdbqr->len) );
161                 cdb_free(cdbqr);
162
163                 room_sanity_check(qrbuf);
164
165                 return(0);
166                 }
167         else {
168                 return(1);
169                 }
170         }
171
172 /*
173  * lgetroom()  -  same as getroom() but locks the record (if supported)
174  */
175 int lgetroom(struct quickroom *qrbuf, char *room_name)
176 {
177         begin_critical_section(S_QUICKROOM);
178         return(getroom(qrbuf, room_name));
179         }
180
181
182 /*
183  * putroom()  -  store room data on disk
184  *              (if the supplied buffer is NULL, delete the room record)
185  */
186 void putroom(struct quickroom *qrbuf, char *room_name)
187 {
188         char lowercase_name[ROOMNAMELEN];
189         int a;
190
191         for (a=0; a<=strlen(room_name); ++a) {
192                 lowercase_name[a] = tolower(room_name[a]);
193                 }
194
195         if (qrbuf == NULL) {
196                 cdb_delete(CDB_QUICKROOM,
197                         lowercase_name, strlen(lowercase_name));
198                 }
199         else {
200                 time(&qrbuf->QRmtime);
201                 cdb_store(CDB_QUICKROOM,
202                         lowercase_name, strlen(lowercase_name),
203                         qrbuf, sizeof(struct quickroom));
204                 }
205         }
206
207
208 /*
209  * lputroom()  -  same as putroom() but unlocks the record (if supported)
210  */
211 void lputroom(struct quickroom *qrbuf, char *room_name)
212 {
213
214         putroom(qrbuf, room_name);
215         end_critical_section(S_QUICKROOM);
216
217         }
218
219 /****************************************************************************/
220
221 /*
222  * getfloor()  -  retrieve floor data from disk
223  */
224 void getfloor(struct floor *flbuf, int floor_num)
225 {
226         struct cdbdata *cdbfl;
227
228         memset(flbuf, 0, sizeof(struct floor));
229         cdbfl = cdb_fetch(CDB_FLOORTAB, &floor_num, sizeof(int));
230         if (cdbfl != NULL) {
231                 memcpy(flbuf, cdbfl->ptr,
232                         ( (cdbfl->len > sizeof(struct floor)) ?
233                         sizeof(struct floor) : cdbfl->len) );
234                 cdb_free(cdbfl);
235                 }
236         else {
237                 if (floor_num == 0) {
238                         strcpy(flbuf->f_name, "Main Floor");
239                         flbuf->f_flags = F_INUSE;
240                         flbuf->f_ref_count = 3;
241                         }
242                 }
243
244         }
245
246 /*
247  * lgetfloor()  -  same as getfloor() but locks the record (if supported)
248  */
249 void lgetfloor(struct floor *flbuf, int floor_num)
250 {
251
252         begin_critical_section(S_FLOORTAB);
253         getfloor(flbuf,floor_num);
254         }
255
256
257 /*
258  * putfloor()  -  store floor data on disk
259  */
260 void putfloor(struct floor *flbuf, int floor_num)
261 {
262         cdb_store(CDB_FLOORTAB, &floor_num, sizeof(int),
263                 flbuf, sizeof(struct floor));
264         }
265
266
267 /*
268  * lputfloor()  -  same as putfloor() but unlocks the record (if supported)
269  */
270 void lputfloor(struct floor *flbuf, int floor_num)
271 {
272
273         putfloor(flbuf,floor_num);
274         end_critical_section(S_FLOORTAB);
275
276         }
277
278
279 /* 
280  *  Traverse the room file...
281  */
282 void ForEachRoom(void (*CallBack)(struct quickroom *EachRoom)) {
283         struct quickroom qrbuf;
284         struct cdbdata *cdbqr;
285
286         cdb_rewind(CDB_QUICKROOM);
287
288         while(cdbqr = cdb_next_item(CDB_QUICKROOM), cdbqr != NULL) {
289                 memset(&qrbuf, 0, sizeof(struct quickroom));
290                 memcpy(&qrbuf, cdbqr->ptr,
291                         ( (cdbqr->len > sizeof(struct quickroom)) ?
292                         sizeof(struct quickroom) : cdbqr->len) );
293                 cdb_free(cdbqr);
294                 room_sanity_check(&qrbuf);
295                 if (qrbuf.QRflags & QR_INUSE) (*CallBack)(&qrbuf);
296                 }
297         }
298
299
300
301 /*
302  * get_msglist()  -  retrieve room message pointers
303  */
304 void get_msglist(struct quickroom *whichroom) {
305         struct cdbdata *cdbfr;
306
307         if (CC->msglist != NULL) {
308                 phree(CC->msglist);
309                 }
310         CC->msglist = NULL;
311         CC->num_msgs = 0;
312
313         cdbfr = cdb_fetch(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
314         if (cdbfr == NULL) {
315                 return;
316                 }
317
318         CC->msglist = mallok(cdbfr->len);
319         memcpy(CC->msglist, cdbfr->ptr, cdbfr->len);
320         CC->num_msgs = cdbfr->len / sizeof(long);
321         cdb_free(cdbfr);
322         }
323
324
325 /*
326  * put_msglist()  -  retrieve room message pointers
327  */
328 void put_msglist(struct quickroom *whichroom) {
329
330         if (CC->msglist != NULL)
331                 cdb_store(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long),
332                         CC->msglist, CC->num_msgs * sizeof(long));
333         }
334
335
336 /*
337  * delete_msglist()  -  delete room message pointers
338  * FIX - this really should check first to make sure there's actually a
339  *       msglist to delete.  As things stand now, calling this function on
340  *       a room which has never been posted in will result in a message
341  *       like "gdbm: illegal data" (no big deal, but could use fixing).
342  */
343 void delete_msglist(struct quickroom *whichroom) {
344
345         cdb_delete(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
346         }
347
348
349 /* 
350  * Add a message number to a room's message list.  
351  * So, why doesn't this function use the get_msglist() and put_msglist() stuff
352  * defined above?  Because the room the message number is being written to
353  * may not be the current room (as is the case with cmd_move() for example).
354  *
355  * This function returns the highest message number present in the room after
356  * the add operation is performed - which is not necessarily the message
357  * being added.
358  */
359 long AddMessageToRoom(struct quickroom *whichroom, long newmsgid) {
360         struct cdbdata *cdbfr;
361         int num_msgs;
362         long *msglist;
363         long highest_msg = 0L;
364
365         lprintf(9, "AddMessageToRoom(%s, %ld)\n", whichroom->QRname, newmsgid); 
366         cdbfr = cdb_fetch(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long));
367         if (cdbfr == NULL) {
368                 msglist = NULL;
369                 num_msgs = 0;
370                 }
371         else {
372                 msglist = mallok(cdbfr->len);
373                 if (msglist==NULL)  lprintf(3, "ERROR malloc msglist!\n");
374                 num_msgs = cdbfr->len / sizeof(long);
375                 memcpy(msglist, cdbfr->ptr, cdbfr->len);
376                 cdb_free(cdbfr);
377                 }
378         
379         /* Now add the new message */
380         ++num_msgs;
381         msglist = reallok(msglist,
382                 (num_msgs * sizeof(long)) );
383
384         if (msglist == NULL) {
385                 lprintf(3, "ERROR: can't realloc message list!\n");
386                 }
387
388         msglist[num_msgs - 1] = newmsgid;
389
390         /* Sort the message list, so all the msgid's are in order */
391         num_msgs = sort_msglist(msglist, num_msgs);
392
393         /* Determine the highest message number */
394         highest_msg = msglist[num_msgs - 1];
395
396         /* Write it back to disk. */
397         cdb_store(CDB_MSGLISTS, &whichroom->QRnumber, sizeof(long),
398                 msglist, num_msgs * sizeof(long));
399
400         /* And finally, free up the memory we used. */
401         phree(msglist);
402         return(highest_msg);
403         }
404
405
406 /*
407  * MessageFromList()  -  get a message number from the list currently in memory
408  */
409 long MessageFromList(int whichpos) {
410
411         /* Return zero if the position is invalid */
412         if (whichpos >= CC->num_msgs) return 0L;
413
414         return(CC->msglist[whichpos]);
415         }
416
417 /* 
418  * SetMessageInList()  -  set a message number in the list currently in memory
419  */
420 void SetMessageInList(int whichpos, long newmsgnum) {
421
422         /* Return zero if the position is invalid */
423         if (whichpos >= CC->num_msgs) return;
424
425         CC->msglist[whichpos] = newmsgnum;
426         }
427
428
429
430 /*
431  * sort message pointers
432  * (returns new msg count)
433  */
434 int sort_msglist(long listptrs[], int oldcount)
435 {
436         int a,b;
437         long hold1, hold2;
438         int numitems;
439
440         numitems = oldcount;
441         if (numitems < 2) return(oldcount);
442
443         /* do the sort */
444         for (a=numitems-2; a>=0; --a) {
445                 for (b=0; b<=a; ++b) {
446                         if (listptrs[b] > (listptrs[b+1])) {
447                                 hold1 = listptrs[b];
448                                 hold2 = listptrs[b+1];
449                                 listptrs[b] = hold2;
450                                 listptrs[b+1] = hold1;
451                                 }
452                         }
453                 }
454
455         /* and yank any nulls */
456         while ( (numitems > 0) && (listptrs[0] == 0L) ) {
457                 memcpy(&listptrs[0], &listptrs[1],
458                         (sizeof(long) * (CC->num_msgs - 1)) );
459                 --numitems;
460                 }
461
462         return(numitems);
463         }
464
465
466 /*
467  * Determine whether a given room is non-editable.
468  */
469 int is_noneditable(struct quickroom *qrbuf) {
470
471         /* Lobby> and Aide> are non-editable */
472         if (!strcasecmp(qrbuf->QRname, BASEROOM)) return(1);
473         else if (!strcasecmp(qrbuf->QRname, AIDEROOM)) return(1);
474
475         /* Mailbox rooms are also non-editable */
476         else if (qrbuf->QRflags & QR_MAILBOX) return(1);
477
478         /* Everything else is editable */
479         else return(0);
480         }
481
482
483
484 /*
485  * Back-back-end for all room listing commands
486  */
487 void list_roomname(struct quickroom *qrbuf) {
488         char truncated_roomname[ROOMNAMELEN];
489
490         /* For mailbox rooms, chop off the owner prefix */
491         if (qrbuf->QRflags & QR_MAILBOX) {
492                 strcpy(truncated_roomname, qrbuf->QRname);
493                 strcpy(truncated_roomname, &truncated_roomname[11]);
494                 cprintf("%s", truncated_roomname);
495                 }
496         /* For all other rooms, just display the name in its entirety */
497         else {
498                 cprintf("%s", qrbuf->QRname);
499                 }
500
501         /* ...and now the other parameters */
502         cprintf("|%u|%d|%d\n",
503                 qrbuf->QRflags,
504                 (int)qrbuf->QRfloor,
505                 (int)qrbuf->QRorder);
506         }
507
508
509 /* 
510  * cmd_lrms()   -  List all accessible rooms, known or forgotten
511  */
512 void cmd_lrms_backend(struct quickroom *qrbuf) {
513         if ( ((CtdlRoomAccess(qrbuf, &CC->usersupp)
514              & (UA_KNOWN | UA_ZAPPED)))
515         && ((qrbuf->QRfloor == (CC->FloorBeingSearched))
516            ||((CC->FloorBeingSearched)<0)) ) 
517                 list_roomname(qrbuf);
518         }
519
520 void cmd_lrms(char *argbuf)
521 {
522         CC->FloorBeingSearched = (-1);
523         if (strlen(argbuf)>0) CC->FloorBeingSearched = extract_int(argbuf,0);
524
525         if (!(CC->logged_in)) {
526                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
527                 return;
528                 }
529
530         if (getuser(&CC->usersupp,CC->curr_user)) {
531                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
532                 return;
533                 }
534
535         cprintf("%d Accessible rooms:\n",LISTING_FOLLOWS);
536
537         ForEachRoom(cmd_lrms_backend);  
538         cprintf("000\n");
539         }
540
541
542
543 /* 
544  * cmd_lkra()   -  List all known rooms
545  */
546 void cmd_lkra_backend(struct quickroom *qrbuf) {
547         if ( ((CtdlRoomAccess(qrbuf, &CC->usersupp)
548              & (UA_KNOWN)))
549         && ((qrbuf->QRfloor == (CC->FloorBeingSearched))
550            ||((CC->FloorBeingSearched)<0)) )
551                 list_roomname(qrbuf);
552         }
553
554 void cmd_lkra(char *argbuf)
555 {
556         CC->FloorBeingSearched = (-1);
557         if (strlen(argbuf)>0) CC->FloorBeingSearched = extract_int(argbuf,0);
558
559         if (!(CC->logged_in)) {
560                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
561                 return;
562                 }
563
564         if (getuser(&CC->usersupp,CC->curr_user)) {
565                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
566                 return;
567                 }
568
569         cprintf("%d Known rooms:\n",LISTING_FOLLOWS);
570
571         ForEachRoom(cmd_lkra_backend);  
572         cprintf("000\n");
573         }
574
575
576
577 /* 
578  * cmd_lkrn()   -  List all known rooms with new messages
579  */
580 void cmd_lkrn_backend(struct quickroom *qrbuf) {
581         int ra;
582
583         ra = CtdlRoomAccess(qrbuf, &CC->usersupp);
584         if ( (ra & UA_KNOWN)
585            && (ra & UA_HASNEWMSGS)
586            && ((qrbuf->QRfloor == (CC->FloorBeingSearched))
587               ||((CC->FloorBeingSearched)<0)) )
588                 list_roomname(qrbuf);
589         }
590
591 void cmd_lkrn(char *argbuf)
592 {
593         CC->FloorBeingSearched = (-1);
594         if (strlen(argbuf)>0) CC->FloorBeingSearched = extract_int(argbuf,0);
595
596         if (!(CC->logged_in)) {
597                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
598                 return;
599                 }
600
601         if (getuser(&CC->usersupp,CC->curr_user)) {
602                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
603                 return;
604                 }
605
606         cprintf("%d Rooms w/ new msgs:\n",LISTING_FOLLOWS);
607
608         ForEachRoom(cmd_lkrn_backend);  
609         cprintf("000\n");
610         }
611
612
613
614 /* 
615  * cmd_lkro()   -  List all known rooms
616  */
617 void cmd_lkro_backend(struct quickroom *qrbuf) {
618         int ra;
619
620         ra = CtdlRoomAccess(qrbuf, &CC->usersupp);
621         if ( (ra & UA_KNOWN)
622            && ((ra & UA_HASNEWMSGS)==0)
623            && ((qrbuf->QRfloor == (CC->FloorBeingSearched))
624               ||((CC->FloorBeingSearched)<0)) )
625                 list_roomname(qrbuf);
626         }
627
628 void cmd_lkro(char *argbuf)
629 {
630         CC->FloorBeingSearched = (-1);
631         if (strlen(argbuf)>0) CC->FloorBeingSearched = extract_int(argbuf,0);
632
633         if (!(CC->logged_in)) {
634                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
635                 return;
636                 }
637
638         if (getuser(&CC->usersupp,CC->curr_user)) {
639                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
640                 return;
641                 }
642
643         cprintf("%d Rooms w/o new msgs:\n",LISTING_FOLLOWS);
644
645         ForEachRoom(cmd_lkro_backend);  
646         cprintf("000\n");
647         }
648
649
650
651 /* 
652  * cmd_lzrm()   -  List all forgotten rooms
653  */
654 void cmd_lzrm_backend(struct quickroom *qrbuf) {
655         int ra;
656
657         ra = CtdlRoomAccess(qrbuf, &CC->usersupp);
658         if ( (ra & UA_GOTOALLOWED)
659            && (ra & UA_ZAPPED)
660            && ((qrbuf->QRfloor == (CC->FloorBeingSearched))
661               ||((CC->FloorBeingSearched)<0)) )
662                 list_roomname(qrbuf);
663         }
664
665 void cmd_lzrm(char *argbuf)
666 {
667         CC->FloorBeingSearched = (-1);
668         if (strlen(argbuf)>0) CC->FloorBeingSearched = extract_int(argbuf,0);
669
670         if (!(CC->logged_in)) {
671                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
672                 return;
673                 }
674
675         if (getuser(&CC->usersupp,CC->curr_user)) {
676                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
677                 return;
678                 }
679
680         cprintf("%d Zapped rooms:\n",LISTING_FOLLOWS);
681
682         ForEachRoom(cmd_lzrm_backend);  
683         cprintf("000\n");
684         }
685
686
687
688 void usergoto(char *where, int display_result)
689 {
690         int a;
691         int new_messages = 0;
692         int total_messages = 0;
693         int info = 0;
694         int rmailflag;
695         int raideflag;
696         int newmailcount = 0;
697         struct visit vbuf;
698         char truncated_roomname[ROOMNAMELEN];
699
700         strcpy(CC->quickroom.QRname, where);
701         getroom(&CC->quickroom, where);
702
703         lgetuser(&CC->usersupp,CC->curr_user);
704         CtdlGetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
705
706         /* Know the room ... but not if it's the page log room */
707         if (strcasecmp(where, config.c_logpages)) {
708                 vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
709                 vbuf.v_flags = vbuf.v_flags | V_ACCESS;
710                 }
711
712         CtdlSetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
713         lputuser(&CC->usersupp,CC->curr_user);
714
715         /* check for new mail */
716         newmailcount = NewMailCount();
717
718         /* set info to 1 if the user needs to read the room's info file */
719         if (CC->quickroom.QRinfo > vbuf.v_lastseen) info = 1;
720
721         get_mm();
722         get_msglist(&CC->quickroom);
723         for (a=0; a<CC->num_msgs; ++a) {
724                 if (MessageFromList(a)>0L) {
725                         ++total_messages;
726                         if (MessageFromList(a) > vbuf.v_lastseen) {
727                                 ++new_messages;
728                                 }
729                         }
730                 }
731
732         if (CC->quickroom.QRflags & QR_MAILBOX) rmailflag = 1;
733         else rmailflag = 0;
734
735         if ( (CC->quickroom.QRroomaide == CC->usersupp.usernum)
736            || (CC->usersupp.axlevel>=6) )  raideflag = 1;
737         else raideflag = 0;
738
739         strcpy(truncated_roomname, CC->quickroom.QRname);
740         if (CC->quickroom.QRflags & QR_MAILBOX) {
741                 strcpy(truncated_roomname, &truncated_roomname[11]);
742                 }
743
744         if (display_result) cprintf("%d%c%s|%d|%d|%d|%d|%ld|%ld|%d|%d|%d|%d\n",
745                 OK,check_express(),
746                 truncated_roomname,
747                 new_messages, total_messages,
748                 info,CC->quickroom.QRflags,
749                 CC->quickroom.QRhighest,
750                 vbuf.v_lastseen,
751                 rmailflag,raideflag,newmailcount,CC->quickroom.QRfloor);
752
753         set_wtmpsupp_to_current_room();
754         }
755
756
757 /* 
758  * cmd_goto()  -  goto a new room
759  */
760 void cmd_goto(char *gargs)
761 {
762         struct quickroom QRscratch;
763         int c;
764         int ok = 0;
765         int ra;
766         char augmented_roomname[256];
767         char towhere[256];
768         char password[256];
769
770         if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
771                 cprintf("%d not logged in\n",ERROR+NOT_LOGGED_IN);
772                 return;
773                 }
774
775         extract(towhere,gargs,0);
776         extract(password,gargs,1);
777
778         getuser(&CC->usersupp, CC->curr_user);
779
780         if (!strcasecmp(towhere, "_BASEROOM_"))
781                 strcpy(towhere, BASEROOM);
782
783         if (!strcasecmp(towhere, "_MAIL_"))
784                 strcpy(towhere, MAILROOM);
785
786         if (!strcasecmp(towhere, "_BITBUCKET_"))
787                 strcpy(towhere, config.c_twitroom);
788
789
790         /* First try a regular match */
791         c = getroom(&QRscratch, towhere);
792
793         /* Then try a mailbox name match */
794         if (c != 0) {
795                 MailboxName(augmented_roomname, &CC->usersupp, towhere);
796                 c = getroom(&QRscratch, augmented_roomname);
797                 if (c == 0) strcpy(towhere, augmented_roomname);
798                 }
799
800         /* And if the room was found... */
801         if (c == 0) {
802
803                 /* let internal programs go directly to any room */
804                 if (CC->internal_pgm) {
805                         usergoto(towhere, 1);
806                         return;
807                         }
808
809                 /* See if there is an existing user/room relationship */
810                 ra = CtdlRoomAccess(&QRscratch, &CC->usersupp);
811
812                 /* normal clients have to pass through security */
813                 if (ra & UA_GOTOALLOWED) ok = 1;
814
815                 if (ok==1) {
816                         if (  (QRscratch.QRflags&QR_PASSWORDED) &&
817                                 ((ra & UA_KNOWN) == 0) &&
818                                 (strcasecmp(QRscratch.QRpasswd,password))
819                                 ) {
820                                         cprintf("%d wrong or missing passwd\n",
821                                                 ERROR+PASSWORD_REQUIRED);
822                                         return;
823                                         }
824                         else if ( (QRscratch.QRflags&QR_PRIVATE) &&
825                                   ((QRscratch.QRflags&QR_PASSWORDED)==0) &&
826                                   ((QRscratch.QRflags&QR_GUESSNAME)==0) &&
827                                   ((ra & UA_KNOWN) == 0) ) {
828                                         goto NOPE;
829                                 }
830                         else {
831                                 usergoto(towhere, 1);
832                                 return;
833                                 }
834                         }
835                 }
836
837 NOPE:   cprintf("%d room '%s' not found\n",ERROR+ROOM_NOT_FOUND,towhere);
838         }
839
840
841 void cmd_whok(void) {
842         struct usersupp temp;
843         struct cdbdata *cdbus;
844
845         if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
846                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
847                 return;
848                 }
849         getuser(&CC->usersupp,CC->curr_user);
850
851         if ((!is_room_aide()) && (!(CC->internal_pgm)) ) {
852                 cprintf("%d Higher access required.\n",
853                         ERROR+HIGHER_ACCESS_REQUIRED);
854                 return;
855                 }
856
857         cprintf("%d Who knows room:\n",LISTING_FOLLOWS);
858         cdb_rewind(CDB_USERSUPP);
859         while(cdbus = cdb_next_item(CDB_USERSUPP), cdbus != NULL) {
860                 memset(&temp, 0, sizeof(struct usersupp));
861                 memcpy(&temp, cdbus->ptr, cdbus->len);
862                 cdb_free(cdbus);
863
864                 if ( (CC->quickroom.QRflags & QR_INUSE)
865                         && (CtdlRoomAccess(&CC->quickroom, &temp) & UA_KNOWN)
866                    ) cprintf("%s\n",temp.fullname);
867                 }
868         cprintf("000\n");
869         }
870
871
872 /*
873  * RDIR command for room directory
874  */
875 void cmd_rdir(void) {
876         char buf[256];
877         char flnm[256];
878         char comment[256];
879         FILE *ls,*fd;
880         struct stat statbuf;
881
882         if (!(CC->logged_in)) {
883                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
884                 return;
885                 }
886
887         getroom(&CC->quickroom, CC->quickroom.QRname);
888         getuser(&CC->usersupp, CC->curr_user);
889
890         if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
891                 cprintf("%d not here.\n",ERROR+NOT_HERE);
892                 return;
893                 }
894
895         if (((CC->quickroom.QRflags & QR_VISDIR) == 0)
896            && (CC->usersupp.axlevel<6)
897            && (CC->usersupp.usernum != CC->quickroom.QRroomaide)) {
898                 cprintf("%d not here.\n",ERROR+HIGHER_ACCESS_REQUIRED);
899                 return;
900                 }
901
902         cprintf("%d %s|%s/files/%s\n",
903                 LISTING_FOLLOWS,config.c_fqdn,BBSDIR,CC->quickroom.QRdirname);
904
905         sprintf(buf,"cd %s/files/%s; ls >%s 2>/dev/null",
906                 BBSDIR,CC->quickroom.QRdirname,CC->temp);
907         system(buf);
908
909         sprintf(buf,"%s/files/%s/filedir",BBSDIR,CC->quickroom.QRdirname);
910         fd = fopen(buf,"r");
911         if (fd==NULL) fd=fopen("/dev/null","r");
912
913         ls = fopen(CC->temp,"r");
914         while (fgets(flnm,256,ls)!=NULL) {
915                 flnm[strlen(flnm)-1]=0;
916                 if (strcasecmp(flnm,"filedir")) {
917                         sprintf(buf,"%s/files/%s/%s",
918                                 BBSDIR,CC->quickroom.QRdirname,flnm);
919                         stat(buf,&statbuf);
920                         strcpy(comment,"");
921                         fseek(fd,0L,0);
922                         while ((fgets(buf,256,fd)!=NULL)
923                             &&(strlen(comment)==0)) {
924                                 buf[strlen(buf)-1] = 0;
925                                 if ((!strncasecmp(buf,flnm,strlen(flnm)))
926                                    && (buf[strlen(flnm)]==' ')) 
927                                         strncpy(comment,
928                                                 &buf[strlen(flnm)+1],255);
929                                 }
930                         cprintf("%s|%ld|%s\n",flnm,statbuf.st_size,comment);
931                         }
932                 }
933         fclose(ls);
934         fclose(fd);
935         unlink(CC->temp);
936
937         cprintf("000\n");
938         }
939
940 /*
941  * get room parameters (aide or room aide command)
942  */
943 void cmd_getr(void) {
944         if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
945                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
946                 return;
947                 }
948
949         if ( (!is_room_aide()) && (!(CC->internal_pgm)) ) {
950                 cprintf("%d Higher access required.\n",
951                         ERROR+HIGHER_ACCESS_REQUIRED);
952                 return;
953                 }
954
955         if (is_noneditable(&CC->quickroom)) {
956                 cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
957                 return;
958                 }
959
960         getroom(&CC->quickroom, CC->quickroom.QRname);
961         cprintf("%d%c%s|%s|%s|%d|%d|%d\n",
962                 OK,check_express(),
963                 CC->quickroom.QRname,
964                 ((CC->quickroom.QRflags & QR_PASSWORDED) ? CC->quickroom.QRpasswd : ""),
965                 ((CC->quickroom.QRflags & QR_DIRECTORY) ? CC->quickroom.QRdirname : ""),
966                 CC->quickroom.QRflags,
967                 (int)CC->quickroom.QRfloor,
968                 (int)CC->quickroom.QRorder);
969         }
970
971
972 /*
973  * set room parameters (aide or room aide command)
974  */
975 void cmd_setr(char *args) {
976         char buf[256];
977         struct floor flbuf;
978         char old_name[ROOMNAMELEN];
979         int old_floor;
980         int new_order = 0;
981
982         if (!(CC->logged_in)) {
983                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
984                 return;
985                 }
986
987         if (!is_room_aide()) {
988                 cprintf("%d Higher access required.\n",
989                         ERROR+HIGHER_ACCESS_REQUIRED);
990                 return;
991                 }
992
993         if (is_noneditable(&CC->quickroom)) {
994                 cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
995                 return;
996                 }
997
998         if (num_parms(args)>=6) {
999                 getfloor(&flbuf,extract_int(args,5));
1000                 if ((flbuf.f_flags & F_INUSE) == 0) {
1001                         cprintf("%d Invalid floor number.\n",
1002                                 ERROR+INVALID_FLOOR_OPERATION);
1003                         return;
1004                         }
1005                 }
1006
1007         if (num_parms(args)>=7) {
1008                 new_order = extract_int(args, 6);
1009                 if (new_order < 1) new_order = 1;
1010                 if (new_order > 127) new_order = 127;
1011                 }
1012
1013         lgetroom(&CC->quickroom, CC->quickroom.QRname);
1014         strcpy(old_name, CC->quickroom.QRname);
1015         extract(buf,args,0); buf[ROOMNAMELEN]=0;
1016         strncpy(CC->quickroom.QRname,buf,ROOMNAMELEN-1);
1017         extract(buf,args,1); buf[10]=0;
1018         strncpy(CC->quickroom.QRpasswd,buf,9);
1019         extract(buf,args,2); buf[15]=0;
1020         strncpy(CC->quickroom.QRdirname,buf,19);
1021         CC->quickroom.QRflags = ( extract_int(args,3) | QR_INUSE);
1022         if (num_parms(args)>=7)
1023                 CC->quickroom.QRorder = (char)new_order;
1024
1025         /* Clean up a client boo-boo: if the client set the room to
1026          * guess-name or passworded, ensure that the private flag is
1027          * also set.
1028          */
1029         if ((CC->quickroom.QRflags & QR_GUESSNAME)
1030            ||(CC->quickroom.QRflags & QR_PASSWORDED))
1031                 CC->quickroom.QRflags |= QR_PRIVATE;
1032
1033         /* Kick everyone out if the client requested it (by changing the
1034          * room's generation number)
1035          */
1036         if (extract_int(args,4)) {
1037                 time(&CC->quickroom.QRgen);
1038                 }
1039
1040         old_floor = CC->quickroom.QRfloor;
1041         if (num_parms(args)>=6) {
1042                 CC->quickroom.QRfloor = extract_int(args,5);
1043                 }
1044
1045         /* Write the room record back to disk */
1046         lputroom(&CC->quickroom, CC->quickroom.QRname);
1047
1048         /* If the room name changed, then there are now two room records,
1049          * so we have to delete the old one.
1050          */
1051         if (strcasecmp(CC->quickroom.QRname, old_name)) {
1052                 putroom(NULL, old_name);
1053                 }
1054
1055         /* adjust the floor reference counts */
1056         lgetfloor(&flbuf,old_floor);
1057         --flbuf.f_ref_count;
1058         lputfloor(&flbuf,old_floor);
1059         lgetfloor(&flbuf,CC->quickroom.QRfloor);
1060         ++flbuf.f_ref_count;
1061         lputfloor(&flbuf,CC->quickroom.QRfloor);
1062
1063         /* create a room directory if necessary */
1064         if (CC->quickroom.QRflags & QR_DIRECTORY) {
1065                 sprintf(buf,
1066                         "mkdir ./files/%s </dev/null >/dev/null 2>/dev/null",
1067                 CC->quickroom.QRdirname);
1068                 system(buf);
1069                 }
1070
1071         sprintf(buf,"%s> edited by %s",CC->quickroom.QRname,CC->curr_user);
1072         aide_message(buf);
1073         cprintf("%d Ok\n",OK);
1074         }
1075
1076
1077
1078 /* 
1079  * get the name of the room aide for this room
1080  */
1081 void cmd_geta(void) {
1082         struct usersupp usbuf;
1083
1084         if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
1085                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1086                 return;
1087                 }
1088
1089         if (is_noneditable(&CC->quickroom)) {
1090                 cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
1091                 return;
1092                 }
1093
1094         if (getuserbynumber(&usbuf,CC->quickroom.QRroomaide)==0) {
1095                 cprintf("%d %s\n",OK,usbuf.fullname);
1096                 }
1097         else {
1098                 cprintf("%d \n",OK);
1099                 }
1100         }
1101
1102
1103 /* 
1104  * set the room aide for this room
1105  */
1106 void cmd_seta(char *new_ra)
1107 {
1108         struct usersupp usbuf;
1109         long newu;
1110         char buf[256];
1111         int post_notice;
1112         
1113         if (!(CC->logged_in)) {
1114                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1115                 return;
1116                 }
1117
1118         if (!is_room_aide()) {
1119                 cprintf("%d Higher access required.\n",
1120                         ERROR+HIGHER_ACCESS_REQUIRED);
1121                 return;
1122                 }
1123
1124         if (getuser(&usbuf,new_ra)!=0) {
1125                 newu = (-1L);
1126                 }
1127         else {
1128                 newu = usbuf.usernum;
1129                 }
1130
1131         lgetroom(&CC->quickroom, CC->quickroom.QRname);
1132         post_notice = 0;
1133         if (CC->quickroom.QRroomaide != newu) {
1134                 post_notice = 1;
1135                 }
1136         CC->quickroom.QRroomaide = newu;
1137         lputroom(&CC->quickroom, CC->quickroom.QRname);
1138
1139         /*
1140          * We have to post the change notice _after_ writing changes to 
1141          * the room table, otherwise it would deadlock!
1142          */
1143         if (post_notice == 1) {
1144                 sprintf(buf,"%s is now room aide for %s>",
1145                         usbuf.fullname,CC->quickroom.QRname);
1146                 aide_message(buf);
1147                 }
1148         cprintf("%d Ok\n",OK);
1149         }
1150
1151 /*
1152  * Generate an associated file name for a room
1153  */
1154 void assoc_file_name(char *buf, struct quickroom *qrbuf, char *prefix) {
1155         sprintf(buf, "./%s/%ld", prefix, qrbuf->QRnumber);
1156         }
1157
1158 /* 
1159  * retrieve info file for this room
1160  */
1161 void cmd_rinf(void) {
1162         char filename[128];
1163         char buf[256];
1164         FILE *info_fp;
1165         
1166         assoc_file_name(filename, &CC->quickroom, "info");
1167         info_fp = fopen(filename,"r");
1168
1169         if (info_fp==NULL) {
1170                 cprintf("%d No info file.\n",ERROR);
1171                 return;
1172                 }
1173
1174         cprintf("%d Info:\n",LISTING_FOLLOWS);  
1175         while (fgets(buf, 256, info_fp) != NULL) {
1176                 if (strlen(buf) > 0) buf[strlen(buf)-1] = 0;
1177                 cprintf("%s\n", buf);
1178                 }
1179         cprintf("000\n");
1180         fclose(info_fp);
1181         }
1182
1183 /*
1184  * Back end processing to delete a room and everything associated with it
1185  */
1186 void delete_room(struct quickroom *qrbuf) {
1187         struct floor flbuf;
1188         long MsgToDelete;
1189         char aaa[100];
1190         int a;
1191
1192         lprintf(9, "Deleting room <%s>\n", qrbuf->QRname);
1193
1194         /* Delete the info file */
1195         assoc_file_name(aaa, qrbuf, "info");
1196         unlink(aaa);
1197
1198         /* Delete the image file */
1199         assoc_file_name(aaa, qrbuf, "images");
1200         unlink(aaa);
1201
1202         /* first flag the room record as not in use */
1203         lgetroom(qrbuf, qrbuf->QRname);
1204         qrbuf->QRflags=0;
1205
1206         /* then delete the messages in the room */
1207         get_msglist(qrbuf);
1208         if (CC->num_msgs > 0) for (a=0; a < CC->num_msgs; ++a) {
1209                 MsgToDelete = MessageFromList(a);
1210                 cdb_delete(CDB_MSGMAIN, &MsgToDelete, sizeof(long));
1211                 }
1212         put_msglist(qrbuf);
1213         phree(CC->msglist);
1214         CC->msglist = NULL;
1215         CC->num_msgs = 0;
1216         delete_msglist(qrbuf);
1217         lputroom(qrbuf, qrbuf->QRname);
1218
1219         /* then decrement the reference count for the floor */
1220         lgetfloor(&flbuf,(int)(qrbuf->QRfloor));
1221         flbuf.f_ref_count = flbuf.f_ref_count - 1;
1222         lputfloor(&flbuf,(int)(qrbuf->QRfloor));
1223
1224         /* Delete the room record from the database! */
1225         putroom(NULL, qrbuf->QRname);
1226         }
1227
1228
1229 /*
1230  * aide command: kill the current room
1231  */
1232 void cmd_kill(char *argbuf) {
1233         char aaa[100];
1234         char deleted_room_name[ROOMNAMELEN];
1235         int kill_ok;
1236         
1237         kill_ok = extract_int(argbuf,0);
1238
1239         if (!(CC->logged_in)) {
1240                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1241                 return;
1242                 }
1243
1244         if (!is_room_aide()) {
1245                 cprintf("%d Higher access required.\n",
1246                         ERROR+HIGHER_ACCESS_REQUIRED);
1247                 return;
1248                 }
1249
1250         if (is_noneditable(&CC->quickroom)) {
1251                 cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
1252                 return;
1253                 }
1254
1255         if (kill_ok) {
1256                 strcpy(deleted_room_name, CC->quickroom.QRname);
1257                 delete_room(&CC->quickroom);    /* Do the dirty work */
1258                 usergoto(BASEROOM, 0);          /* Return to the Lobby */
1259
1260                 /* tell the world what we did */
1261                 sprintf(aaa,"%s> killed by %s",
1262                         deleted_room_name, CC->curr_user);
1263                 aide_message(aaa);
1264                 cprintf("%d '%s' deleted.\n", OK, deleted_room_name);
1265                 }
1266         else {
1267                 cprintf("%d ok to delete.\n",OK);
1268                 }
1269         }
1270
1271
1272 /*
1273  * Internal code to create a new room (returns room flags)
1274  *
1275  * Room types:  0=public, 1=guessname, 2=passworded, 3=inv-only, 4=mailbox
1276  */
1277 unsigned create_room(char *new_room_name,
1278                         int new_room_type,
1279                         char *new_room_pass,
1280                         int new_room_floor) {
1281
1282         struct quickroom qrbuf;
1283         struct floor flbuf;
1284         struct visit vbuf;
1285
1286         if (getroom(&qrbuf, new_room_name)==0) return(0); /* already exists */
1287
1288         memset(&qrbuf, 0, sizeof(struct quickroom));
1289         strncpy(qrbuf.QRname,new_room_name,ROOMNAMELEN);
1290         strncpy(qrbuf.QRpasswd,new_room_pass,9);
1291         qrbuf.QRflags = QR_INUSE;
1292         qrbuf.QRnumber = get_new_room_number();
1293         if (new_room_type > 0) qrbuf.QRflags=(qrbuf.QRflags|QR_PRIVATE);
1294         if (new_room_type == 1) qrbuf.QRflags=(qrbuf.QRflags|QR_GUESSNAME);
1295         if (new_room_type == 2) qrbuf.QRflags=(qrbuf.QRflags|QR_PASSWORDED);
1296         if (new_room_type == 4) qrbuf.QRflags=(qrbuf.QRflags|QR_MAILBOX);
1297
1298         /* If the room is private, and the system administrator has elected
1299          * to automatically grant room aide privileges, do so now; otherwise,
1300          * set the room aide to undefined.
1301          */
1302         if ( (qrbuf.QRflags & QR_PRIVATE) && (CREATAIDE==1) ) {
1303                 qrbuf.QRroomaide=CC->usersupp.usernum;
1304                 }
1305         else {
1306                 qrbuf.QRroomaide = (-1L);
1307                 }
1308
1309         qrbuf.QRhighest = 0L;   /* No messages in this room yet */
1310         time(&qrbuf.QRgen);     /* Use a timestamp as the generation number */
1311         qrbuf.QRfloor = new_room_floor;
1312
1313         /* save what we just did... */
1314         putroom(&qrbuf, qrbuf.QRname);
1315
1316         /* bump the reference count on whatever floor the room is on */
1317         lgetfloor(&flbuf,(int)qrbuf.QRfloor);
1318         flbuf.f_ref_count = flbuf.f_ref_count + 1;
1319         lputfloor(&flbuf,(int)qrbuf.QRfloor);
1320
1321         /* be sure not to kick the creator out of the room! */
1322         lgetuser(&CC->usersupp,CC->curr_user);
1323         CtdlGetRelationship(&vbuf, &CC->usersupp, &qrbuf);
1324         vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
1325         vbuf.v_flags = vbuf.v_flags | V_ACCESS;
1326         CtdlSetRelationship(&vbuf, &CC->usersupp, &qrbuf);
1327         lputuser(&CC->usersupp,CC->curr_user);
1328
1329         /* resume our happy day */
1330         return(qrbuf.QRflags);
1331         }
1332
1333
1334 /*
1335  * create a new room
1336  */
1337 void cmd_cre8(char *args)
1338 {
1339         int cre8_ok;
1340         char new_room_name[256];
1341         int new_room_type;
1342         char new_room_pass[256];
1343         int new_room_floor;
1344         char aaa[256];
1345         unsigned newflags;
1346         struct quickroom qrbuf;
1347         struct floor flbuf;
1348
1349         cre8_ok = extract_int(args,0);
1350         extract(new_room_name,args,1);
1351         new_room_name[ROOMNAMELEN-1] = 0;
1352         new_room_type = extract_int(args,2);
1353         extract(new_room_pass,args,3);
1354         new_room_pass[9] = 0;
1355         new_room_floor = 0;
1356
1357         if ((strlen(new_room_name)==0) && (cre8_ok==1)) {
1358                 cprintf("%d Invalid room name.\n",ERROR);
1359                 return;
1360                 }
1361
1362         if (!strcasecmp(new_room_name, MAILROOM)) {
1363                 cprintf("%d '%s' already exists.\n",
1364                         ERROR+ALREADY_EXISTS, new_room_name);
1365                 return;
1366                 }
1367
1368         if (num_parms(args)>=5) {
1369                 getfloor(&flbuf,extract_int(args,4));
1370                 if ((flbuf.f_flags & F_INUSE) == 0) {
1371                         cprintf("%d Invalid floor number.\n",
1372                                 ERROR+INVALID_FLOOR_OPERATION);
1373                         return;
1374                         }
1375                 else {
1376                         new_room_floor = extract_int(args,4);
1377                         }
1378                 }
1379
1380         if (!(CC->logged_in)) {
1381                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1382                 return;
1383                 }
1384
1385         if (CC->usersupp.axlevel < config.c_createax) {
1386                 cprintf("%d You need higher access to create rooms.\n",
1387                         ERROR+HIGHER_ACCESS_REQUIRED);
1388                 return;
1389                 }
1390
1391         if ((strlen(new_room_name)==0) && (cre8_ok==0)) {
1392                 cprintf("%d Ok to create rooms.\n", OK);
1393                 return;
1394                 }
1395
1396         /* Check to make sure the requested room name doesn't already exist */
1397         if (getroom(&qrbuf, new_room_name)==0) {
1398                 cprintf("%d '%s' already exists.\n",
1399                         ERROR+ALREADY_EXISTS, qrbuf.QRname);
1400                 return;
1401                 }
1402
1403         if ((new_room_type < 0) || (new_room_type > 3)) {
1404                 cprintf("%d Invalid room type.\n",ERROR);
1405                 return;
1406                 }
1407
1408         if (cre8_ok == 0) {
1409                 cprintf("%d OK to create '%s'\n", OK, new_room_name);
1410                 return;
1411                 }
1412
1413         newflags = create_room(new_room_name,
1414                         new_room_type,new_room_pass,new_room_floor);
1415
1416         /* post a message in Aide> describing the new room */
1417         strncpy(aaa,new_room_name,255);
1418         strcat(aaa,"> created by ");
1419         strcat(aaa,CC->usersupp.fullname);
1420         if (newflags&QR_PRIVATE) strcat(aaa," [private]");
1421         if (newflags&QR_GUESSNAME) strcat(aaa,"[guessname] ");
1422         if (newflags&QR_PASSWORDED) {
1423                 strcat(aaa,"\n Password: ");
1424                 strcat(aaa,new_room_pass);
1425                 }
1426         aide_message(aaa); 
1427
1428         cprintf("%d '%s' has been created.\n",OK,qrbuf.QRname);
1429         }
1430
1431
1432
1433 void cmd_einf(char *ok)
1434 {       /* enter info file for current room */
1435         FILE *fp;
1436         char infofilename[256];
1437         char buf[256];
1438
1439         if (!(CC->logged_in)) {
1440                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1441                 return;
1442                 }
1443
1444         if (!is_room_aide()) {
1445                 cprintf("%d Higher access required.\n",
1446                         ERROR+HIGHER_ACCESS_REQUIRED);
1447                 return;
1448                 }
1449
1450         if (atoi(ok)==0) {
1451                 cprintf("%d Ok.\n",OK);
1452                 return;
1453                 }
1454
1455         assoc_file_name(infofilename, &CC->quickroom, "info");
1456         lprintf(9, "opening\n");
1457         fp = fopen(infofilename, "w");
1458         lprintf(9, "checking\n");
1459         if (fp == NULL) {
1460                 cprintf("%d Cannot open %s: %s\n",
1461                         ERROR+INTERNAL_ERROR, infofilename, strerror(errno));
1462                 return;
1463                 }
1464
1465         cprintf("%d Send info...\n", SEND_LISTING);
1466
1467         do {
1468                 client_gets(buf);
1469                 if (strcmp(buf,"000")) fprintf(fp,"%s\n",buf);
1470                 } while(strcmp(buf,"000"));
1471         fclose(fp);
1472
1473         /* now update the room index so people will see our new info */
1474         lgetroom(&CC->quickroom,CC->quickroom.QRname); /* lock so no one steps on us */
1475         CC->quickroom.QRinfo = CC->quickroom.QRhighest + 1L;
1476         lputroom(&CC->quickroom,CC->quickroom.QRname);
1477         }
1478
1479
1480 /* 
1481  * cmd_lflr()   -  List all known floors
1482  */
1483 void cmd_lflr(void) {
1484         int a;
1485         struct floor flbuf;
1486
1487         if (!(CC->logged_in)) {
1488                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1489                 return;
1490                 }
1491
1492         /* if (getuser(&CC->usersupp,CC->curr_user)) {
1493                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
1494                 return;
1495                 }
1496         */
1497
1498         cprintf("%d Known floors:\n",LISTING_FOLLOWS);
1499         
1500         for (a=0; a<MAXFLOORS; ++a) {
1501                 getfloor(&flbuf,a);
1502                 if (flbuf.f_flags & F_INUSE) {
1503                         cprintf("%d|%s|%d\n",
1504                                 a,
1505                                 flbuf.f_name,
1506                                 flbuf.f_ref_count);
1507                         }
1508                 }
1509         cprintf("000\n");
1510         }
1511
1512
1513
1514 /*
1515  * create a new floor
1516  */
1517 void cmd_cflr(char *argbuf)
1518 {
1519         char new_floor_name[256];
1520         struct floor flbuf;
1521         int cflr_ok;
1522         int free_slot = (-1);
1523         int a;
1524
1525         extract(new_floor_name,argbuf,0);
1526         cflr_ok = extract_int(argbuf,1);
1527
1528         
1529         if (!(CC->logged_in)) {
1530                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1531                 return;
1532                 }
1533
1534         if (CC->usersupp.axlevel<6) {
1535                 cprintf("%d You need higher access to create rooms.\n",
1536                         ERROR+HIGHER_ACCESS_REQUIRED);
1537                 return;
1538                 }
1539
1540         for (a=0; a<MAXFLOORS; ++a) {
1541                 getfloor(&flbuf,a);
1542
1543                 /* note any free slots while we're scanning... */
1544                 if ( ((flbuf.f_flags & F_INUSE)==0) 
1545                      && (free_slot < 0) )  free_slot = a;
1546
1547                 /* check to see if it already exists */
1548                 if ( (!strcasecmp(flbuf.f_name,new_floor_name))
1549                      && (flbuf.f_flags & F_INUSE) ) {
1550                         cprintf("%d Floor '%s' already exists.\n",
1551                                 ERROR+ALREADY_EXISTS,
1552                                 flbuf.f_name);
1553                         return;
1554                         }
1555
1556                 }
1557
1558         if (free_slot<0) {
1559                 cprintf("%d There is no space available for a new floor.\n",
1560                         ERROR+INVALID_FLOOR_OPERATION);
1561                 return;
1562                 }
1563
1564         if (cflr_ok==0) {
1565                 cprintf("%d ok to create...\n",OK);
1566                 return;
1567                 }
1568
1569         lgetfloor(&flbuf,free_slot);
1570         flbuf.f_flags = F_INUSE;
1571         flbuf.f_ref_count = 0;
1572         strncpy(flbuf.f_name,new_floor_name,255);
1573         lputfloor(&flbuf,free_slot);
1574         cprintf("%d %d\n",OK,free_slot);
1575         }
1576
1577
1578
1579 /*
1580  * delete a floor
1581  */
1582 void cmd_kflr(char *argbuf)
1583 {
1584         struct floor flbuf;
1585         int floor_to_delete;
1586         int kflr_ok;
1587         int delete_ok;
1588
1589         floor_to_delete = extract_int(argbuf,0);
1590         kflr_ok = extract_int(argbuf,1);
1591
1592         
1593         if (!(CC->logged_in)) {
1594                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1595                 return;
1596                 }
1597
1598         if (CC->usersupp.axlevel<6) {
1599                 cprintf("%d You need higher access to delete floors.\n",
1600                         ERROR+HIGHER_ACCESS_REQUIRED);
1601                 return;
1602                 }
1603
1604         lgetfloor(&flbuf,floor_to_delete);
1605
1606         delete_ok = 1;  
1607         if ((flbuf.f_flags & F_INUSE) == 0) {
1608                 cprintf("%d Floor %d not in use.\n",
1609                         ERROR+INVALID_FLOOR_OPERATION,floor_to_delete);
1610                 delete_ok = 0;
1611                 }
1612
1613         else {
1614                 if (flbuf.f_ref_count != 0) {
1615                         cprintf("%d Cannot delete; floor contains %d rooms.\n",
1616                                 ERROR+INVALID_FLOOR_OPERATION,
1617                                 flbuf.f_ref_count);
1618                         delete_ok = 0;
1619                         }
1620
1621                 else {
1622                         if (kflr_ok == 1) {
1623                                 cprintf("%d Ok\n",OK);
1624                                 }
1625                         else {
1626                                 cprintf("%d Ok to delete...\n",OK);
1627                                 }
1628
1629                         }
1630
1631                 }
1632
1633         if ( (delete_ok == 1) && (kflr_ok == 1) ) flbuf.f_flags = 0;
1634         lputfloor(&flbuf,floor_to_delete);
1635         }
1636
1637 /*
1638  * edit a floor
1639  */
1640 void cmd_eflr(char *argbuf)
1641 {
1642         struct floor flbuf;
1643         int floor_num;
1644         int np;
1645
1646         np = num_parms(argbuf);
1647         if (np < 1) {
1648                 cprintf("%d Usage error.\n",ERROR);
1649                 return;
1650                 }
1651         
1652         if (!(CC->logged_in)) {
1653                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1654                 return;
1655                 }
1656
1657         if (CC->usersupp.axlevel<6) {
1658                 cprintf("%d You need higher access to edit floors.\n",
1659                         ERROR+HIGHER_ACCESS_REQUIRED);
1660                 return;
1661                 }
1662
1663         floor_num = extract_int(argbuf,0);
1664         lgetfloor(&flbuf,floor_num);
1665         if ( (flbuf.f_flags & F_INUSE) == 0) {
1666                 lputfloor(&flbuf,floor_num);
1667                 cprintf("%d Floor %d is not in use.\n",
1668                         ERROR+INVALID_FLOOR_OPERATION,floor_num);
1669                 return;
1670                 }
1671         if (np >= 2) extract(flbuf.f_name,argbuf,1);
1672         lputfloor(&flbuf,floor_num);
1673         
1674         cprintf("%d Ok\n",OK);
1675         }