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