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