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