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