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