]> code.citadel.org Git - citadel.git/blob - citadel/room_ops.c
* Changed all "generation" variables from char to long, in preparation
[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 <time.h>
8 #include "citadel.h"
9 #include "server.h"
10 #include "database.h"
11 #include "config.h"
12 #include "room_ops.h"
13 #include "sysdep_decls.h"
14 #include "support.h"
15 #include "user_ops.h"
16 #include "msgbase.h"
17 #include "serv_chat.h"
18 #include "citserver.h"
19
20 /*
21  * is_known()  -  returns nonzero if room is in user's known room list
22  */
23 int is_known(struct quickroom *roombuf, int roomnum, struct usersupp *userbuf)
24 {
25
26         /* for internal programs, always succeed */
27         if (((CC->internal_pgm))&&(roombuf->QRflags & QR_INUSE)) return(1);
28
29         /* for regular rooms, check the permissions */
30         if ((roombuf->QRflags & QR_INUSE)
31                 && ( (roomnum!=2) || (userbuf->axlevel>=6))
32                 && (roombuf->QRgen != (userbuf->forget[roomnum]) )
33
34                 && (    ((roombuf->QRflags&QR_PREFONLY)==0)
35                 ||      ((userbuf->axlevel)>=5)
36                 )
37
38                 && (    ((roombuf->QRflags&QR_PRIVATE)==0)
39                 ||      ((userbuf->axlevel)>=6)
40                 ||      (roombuf->QRgen==(userbuf->generation[roomnum]))
41                 )
42
43                 ) return(1);
44         else return(0);
45         }
46
47
48 /*
49  * has_newmsgs()  -  returns nonzero if room has new messages
50  */
51 int has_newmsgs(struct quickroom *roombuf, int roomnum, struct usersupp *userbuf)
52 {
53         if (roomnum == 1) {
54                 return ( (NewMailCount() > 0) ? 1 : 0 );
55                 }
56         else {
57                 if (roombuf->QRhighest > (userbuf->lastseen[roomnum]) ) {
58                         return(1);
59                         }
60                 else {
61                         return(0);
62                         }
63                 }
64         }
65
66
67 /*
68  * is_zapped()  -  returns nonzero if room is on forgotten rooms list
69  */
70 int is_zapped(struct quickroom *roombuf, int roomnum, struct usersupp *userbuf)
71 {
72         if ((roombuf->QRflags & QR_INUSE)
73                 && (roombuf->QRgen == (userbuf->forget[roomnum]) )
74                 && ( (roomnum!=2) || ((userbuf->axlevel)>=6))
75                 && (    ((roombuf->QRflags&QR_PRIVATE)==0)
76                 ||      ((userbuf->axlevel)>=6)
77                 ||      (roombuf->QRgen==(userbuf->generation[roomnum]))
78                 )
79                 ) return(1);
80         else return(0);
81         }
82
83 /*
84  * getroom()  -  retrieve room data from disk
85  */
86 void getroom(struct quickroom *qrbuf, int room_num)
87 {
88         struct cdbdata *cdbqr;
89         int a;
90
91         bzero(qrbuf, sizeof(struct quickroom));
92         cdbqr = cdb_fetch(CDB_QUICKROOM, &room_num, sizeof(int));
93         if (cdbqr != NULL) {
94                 memcpy(qrbuf, cdbqr->ptr,
95                         ( (cdbqr->len > sizeof(struct quickroom)) ?
96                         sizeof(struct quickroom) : cdbqr->len) );
97                 cdb_free(cdbqr);
98                 }
99         else {
100                 if (room_num < 3) {
101                         qrbuf->QRflags = QR_INUSE;
102                         time(&qrbuf->QRgen);
103                         switch(room_num) {
104                                 case 0: strcpy(qrbuf->QRname, "Lobby");
105                                         break;
106                                 case 1: strcpy(qrbuf->QRname, "Mail");
107                                         break;
108                                 case 2: strcpy(qrbuf->QRname, "Aide");
109                                         break;
110                                 }
111                         }
112                 }
113
114
115         /** FIX **   VILE SLEAZY HACK ALERT!!  
116          * This is a temporary fix until we can track down where room names
117          * are getting corrupted on some systems.
118          */
119         for (a=0; a<20; ++a) if (qrbuf->QRname[a] < 32) qrbuf->QRname[a] = 0;
120         qrbuf->QRname[19] = 0;
121         }
122
123 /*
124  * lgetroom()  -  same as getroom() but locks the record (if supported)
125  */
126 void lgetroom(struct quickroom *qrbuf, int room_num)
127 {
128         begin_critical_section(S_QUICKROOM);
129         getroom(qrbuf,room_num);
130         }
131
132
133 /*
134  * putroom()  -  store room data on disk
135  */
136 void putroom(struct quickroom *qrbuf, int room_num)
137 {
138         time(&qrbuf->QRmtime);
139         cdb_store(CDB_QUICKROOM, &room_num, sizeof(int),
140                 qrbuf, sizeof(struct quickroom));
141         }
142
143
144 /*
145  * lputroom()  -  same as putroom() but unlocks the record (if supported)
146  */
147 void lputroom(struct quickroom *qrbuf, int room_num)
148 {
149
150         putroom(qrbuf,room_num);
151         end_critical_section(S_QUICKROOM);
152
153         }
154
155
156 /*
157  * getfloor()  -  retrieve floor data from disk
158  */
159 void getfloor(struct floor *flbuf, int floor_num)
160 {
161         struct cdbdata *cdbfl;
162
163         bzero(flbuf, sizeof(struct floor));
164         cdbfl = cdb_fetch(CDB_FLOORTAB, &floor_num, sizeof(int));
165         if (cdbfl != NULL) {
166                 memcpy(flbuf, cdbfl->ptr,
167                         ( (cdbfl->len > sizeof(struct floor)) ?
168                         sizeof(struct floor) : cdbfl->len) );
169                 cdb_free(cdbfl);
170                 }
171         else {
172                 if (floor_num == 0) {
173                         strcpy(flbuf->f_name, "Main Floor");
174                         flbuf->f_flags = F_INUSE;
175                         flbuf->f_ref_count = 3;
176                         }
177                 }
178
179         }
180
181 /*
182  * lgetfloor()  -  same as getfloor() but locks the record (if supported)
183  */
184 void lgetfloor(struct floor *flbuf, int floor_num)
185 {
186
187         begin_critical_section(S_FLOORTAB);
188         getfloor(flbuf,floor_num);
189         }
190
191
192 /*
193  * putfloor()  -  store floor data on disk
194  */
195 void putfloor(struct floor *flbuf, int floor_num)
196 {
197         cdb_store(CDB_FLOORTAB, &floor_num, sizeof(int),
198                 flbuf, sizeof(struct floor));
199         }
200
201
202 /*
203  * lputfloor()  -  same as putfloor() but unlocks the record (if supported)
204  */
205 void lputfloor(struct floor *flbuf, int floor_num)
206 {
207
208         putfloor(flbuf,floor_num);
209         end_critical_section(S_FLOORTAB);
210
211         }
212
213
214
215 /*
216  * get_msglist()  -  retrieve room message pointers
217  */
218 void get_msglist(int room_num)
219 {
220         struct cdbdata *cdbfr;
221
222         if (CC->msglist != NULL) {
223                 free(CC->msglist);
224                 }
225         CC->msglist = NULL;
226         CC->num_msgs = 0;
227
228         if (room_num != 1) {
229                 cdbfr = cdb_fetch(CDB_MSGLISTS, &room_num, sizeof(int));
230                 }
231         else {
232                 cdbfr = cdb_fetch(CDB_MAILBOXES, &CC->usersupp.usernum,
233                                         sizeof(long));
234                 }
235
236         if (cdbfr == NULL) {
237                 return;
238                 }
239
240         CC->msglist = malloc(cdbfr->len);
241         memcpy(CC->msglist, cdbfr->ptr, cdbfr->len);
242         CC->num_msgs = cdbfr->len / sizeof(long);
243         cdb_free(cdbfr);
244         }
245
246
247 /*
248  * put_msglist()  -  retrieve room message pointers
249  */
250 void put_msglist(int room_num)
251 {
252
253         if (room_num != 1) {
254                 cdb_store(CDB_MSGLISTS, &room_num, sizeof(int),
255                         CC->msglist, (CC->num_msgs * sizeof(long)) );
256                 }
257         else {
258                 cdb_store(CDB_MAILBOXES, &CC->usersupp.usernum, sizeof(long),
259                         CC->msglist, (CC->num_msgs * sizeof(long)) );
260                 }
261         }
262
263
264 /*
265  * MessageFromList()  -  get a message number from the list currently in memory
266  */
267 long MessageFromList(int whichpos) {
268
269         /* Return zero if the position is invalid */
270         if (whichpos >= CC->num_msgs) return 0L;
271
272         return(CC->msglist[whichpos]);
273         }
274
275 /* 
276  * SetMessageInList()  -  set a message number in the list currently in memory
277  */
278 void SetMessageInList(int whichpos, long newmsgnum) {
279
280         /* Return zero if the position is invalid */
281         if (whichpos >= CC->num_msgs) return;
282
283         CC->msglist[whichpos] = newmsgnum;
284         }
285
286
287
288 /*
289  * sort message pointers
290  * (returns new msg count)
291  */
292 int sort_msglist(long listptrs[], int oldcount)
293 {
294         int a,b;
295         long hold1, hold2;
296         int numitems;
297
298         numitems = oldcount;
299         if (numitems < 2) return(oldcount);
300
301         /* do the sort */
302         for (a=numitems-2; a>=0; --a) {
303                 for (b=0; b<=a; ++b) {
304                         if (listptrs[b] > (listptrs[b+1])) {
305                                 hold1 = listptrs[b];
306                                 hold2 = listptrs[b+1];
307                                 listptrs[b] = hold2;
308                                 listptrs[b+1] = hold1;
309                                 }
310                         }
311                 }
312
313         /* and yank any nulls */
314         while ( (numitems > 0) && (listptrs[0] == 0L) ) {
315                 memcpy(&listptrs[0], &listptrs[1],
316                         (sizeof(long) * (CC->num_msgs - 1)) );
317                 --numitems;
318                 }
319
320         return(numitems);
321         }
322
323  
324
325
326 /* 
327  * cmd_lrms()   -  List all accessible rooms, known or forgotten
328  */
329 void cmd_lrms(char *argbuf)
330 {
331         int a;
332         int target_floor = (-1);
333         struct quickroom qrbuf;
334
335         if (strlen(argbuf)>0) target_floor = extract_int(argbuf,0);
336
337         if (!(CC->logged_in)) {
338                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
339                 return;
340                 }
341
342         if (getuser(&CC->usersupp,CC->curr_user)) {
343                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
344                 return;
345                 }
346
347         cprintf("%d Accessible rooms:\n",LISTING_FOLLOWS);
348         
349         for (a=0; a<MAXROOMS; ++a) {
350                 getroom(&qrbuf,a);
351                 if ( ( (is_known(&qrbuf,a,&CC->usersupp))
352                    ||   (is_zapped(&qrbuf,a,&CC->usersupp)) )
353                 && ((qrbuf.QRfloor == target_floor)||(target_floor<0)) )
354                         cprintf("%s|%u|%d\n",
355                                 qrbuf.QRname,qrbuf.QRflags,qrbuf.QRfloor);
356                 }
357         cprintf("000\n");
358         }
359
360 /* 
361  * cmd_lkra()   -  List all known rooms
362  */
363 void cmd_lkra(char *argbuf)
364 {
365         int a;
366         struct quickroom qrbuf;
367         int target_floor = (-1);
368
369         if (strlen(argbuf)>0) target_floor = extract_int(argbuf,0);
370
371         if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
372                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
373                 return;
374                 }
375
376         if (!(CC->internal_pgm)) if (getuser(&CC->usersupp,CC->curr_user)) {
377                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
378                 return;
379                 }
380
381         cprintf("%d Known rooms:\n",LISTING_FOLLOWS);
382         
383         for (a=0; a<MAXROOMS; ++a) {
384                 getroom(&qrbuf,a);
385                 if ((is_known(&qrbuf,a,&CC->usersupp))
386                    && ((qrbuf.QRfloor == target_floor)||(target_floor<0)) )
387                         cprintf("%s|%u|%d\n",
388                                 qrbuf.QRname,qrbuf.QRflags,qrbuf.QRfloor);
389                 }
390         cprintf("000\n");
391         }
392
393 /* 
394  * cmd_lkrn()   -  List Known Rooms with New messages
395  */
396 void cmd_lkrn(char *argbuf)
397 {
398         int a;
399         struct quickroom qrbuf;
400         int target_floor = (-1);
401
402         if (strlen(argbuf)>0) target_floor = extract_int(argbuf,0);
403
404         if (!(CC->logged_in)) {
405                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
406                 return;
407                 }
408
409         if (getuser(&CC->usersupp,CC->curr_user)) {
410                 cprintf("%d can't locate user\n",ERROR+INTERNAL_ERROR);
411                 return;
412                 }
413
414         cprintf("%d list of rms w/ new msgs\n",LISTING_FOLLOWS);
415         
416         for (a=0; a<MAXROOMS; ++a) {
417                 getroom(&qrbuf,a);
418                 if ( ( (is_known(&qrbuf,a,&CC->usersupp))
419                    &&   (has_newmsgs(&qrbuf,a,&CC->usersupp)) )
420                    && ((qrbuf.QRfloor == target_floor)||(target_floor<0)) )
421                         cprintf("%s|%u|%d\n",
422                                 qrbuf.QRname,qrbuf.QRflags,qrbuf.QRfloor);
423                 }
424         cprintf("000\n");
425         }
426
427 /* 
428  * cmd_lkro()   -  List Known Rooms with Old (no new) messages
429  */
430 void cmd_lkro(char *argbuf)
431 {
432         int a;
433         struct quickroom qrbuf;
434         int target_floor = (-1);
435
436         if (strlen(argbuf)>0) target_floor = extract_int(argbuf,0);
437
438         if (!(CC->logged_in)) {
439                 cprintf("%d not logged in\n",ERROR+NOT_LOGGED_IN);
440                 return;
441                 }
442
443         if (getuser(&CC->usersupp,CC->curr_user)) {
444                 cprintf("%d can't locate user\n",ERROR+INTERNAL_ERROR);
445                 return;
446                 }
447
448         cprintf("%d list of rms w/o new msgs\n",LISTING_FOLLOWS);
449         
450         for (a=0; a<MAXROOMS; ++a) {
451                 getroom(&qrbuf,a);
452                 if ( ( (is_known(&qrbuf,a,&CC->usersupp))
453                    &&   (!has_newmsgs(&qrbuf,a,&CC->usersupp)) ) 
454                    && ((qrbuf.QRfloor == target_floor)||(target_floor<0)) ) {
455                         if (!strcmp(qrbuf.QRname,"000")) cprintf(">");
456                         cprintf("%s|%u|%d\n",
457                                 qrbuf.QRname,qrbuf.QRflags,qrbuf.QRfloor);
458                         }
459                 }
460         cprintf("000\n");
461         }
462
463 /* 
464  * cmd_lzrm()   -  List Zapped RooMs
465  */
466 void cmd_lzrm(char *argbuf)
467 {
468         int a;
469         struct quickroom qrbuf;
470         int target_floor = (-1);
471
472         if (strlen(argbuf)>0) target_floor = extract_int(argbuf,0);
473
474         if (!(CC->logged_in)) {
475                 cprintf("%d not logged in\n",ERROR+NOT_LOGGED_IN);
476                 return;
477                 }
478
479         if (getuser(&CC->usersupp,CC->curr_user)) {
480                 cprintf("%d can't locate user\n",ERROR+INTERNAL_ERROR);
481                 return;
482                 }
483
484         cprintf("%d list of forgotten rms\n",LISTING_FOLLOWS);
485         
486         for (a=0; a<MAXROOMS; ++a) {
487                 getroom(&qrbuf,a);
488                 if ( (is_zapped(&qrbuf,a,&CC->usersupp))
489                    && ((qrbuf.QRfloor == target_floor)||(target_floor<0)) ) {
490                         if (!strcmp(qrbuf.QRname,"000")) cprintf(">");
491                         cprintf("%s|%u|%d\n",
492                                 qrbuf.QRname,qrbuf.QRflags,qrbuf.QRfloor);
493                         }
494                 }
495         cprintf("000\n");
496         }
497
498
499
500 void usergoto(int where, int display_result)
501 {
502         int a,b,c;
503         int info = 0;
504         int rmailflag;
505         int raideflag;
506         int newmailcount = 0;
507
508         CC->curr_rm=where;
509         getroom(&CC->quickroom,CC->curr_rm);
510         lgetuser(&CC->usersupp,CC->curr_user);
511         CC->usersupp.forget[CC->curr_rm]=(-1);
512         CC->usersupp.generation[CC->curr_rm]=CC->quickroom.QRgen;
513         lputuser(&CC->usersupp,CC->curr_user);
514
515         /* check for new mail */
516         newmailcount = NewMailCount();
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) time(&CC->quickroom.QRgen);
833
834                 }
835
836         old_floor = CC->quickroom.QRfloor;
837         if (num_parms(args)>=6) {
838                 CC->quickroom.QRfloor = extract_int(args,5);
839                 }
840
841         lputroom(&CC->quickroom,CC->curr_rm);
842
843         /* adjust the floor reference counts */
844         lgetfloor(&flbuf,old_floor);
845         --flbuf.f_ref_count;
846         lputfloor(&flbuf,old_floor);
847         lgetfloor(&flbuf,CC->quickroom.QRfloor);
848         ++flbuf.f_ref_count;
849         lputfloor(&flbuf,CC->quickroom.QRfloor);
850
851         /* create a room directory if necessary */
852         if (CC->quickroom.QRflags & QR_DIRECTORY) {
853                 sprintf(buf,
854                         "mkdir ./files/%s </dev/null >/dev/null 2>/dev/null",
855                 CC->quickroom.QRdirname);
856                 system(buf);
857                 }
858
859         sprintf(buf,"%s> edited by %s",CC->quickroom.QRname,CC->curr_user);
860         aide_message(buf);
861         cprintf("%d Ok\n",OK);
862         }
863
864
865
866 /* 
867  * get the name of the room aide for this room
868  */
869 void cmd_geta(void) {
870         struct usersupp usbuf;
871
872         if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
873                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
874                 return;
875                 }
876
877         if (CC->curr_rm < 0) {
878                 cprintf("%d No current room.\n",ERROR);
879                 return;
880                 }
881
882         if (getuserbynumber(&usbuf,CC->quickroom.QRroomaide)==0) {
883                 cprintf("%d %s\n",OK,usbuf.fullname);
884                 }
885         else {
886                 cprintf("%d \n",OK);
887                 }
888         }
889
890
891 /* 
892  * set the room aide for this room
893  */
894 void cmd_seta(char *new_ra)
895 {
896         struct usersupp usbuf;
897         long newu;
898         char buf[256];
899         int post_notice;
900         
901         if (!(CC->logged_in)) {
902                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
903                 return;
904                 }
905
906         if (!is_room_aide()) {
907                 cprintf("%d Higher access required.\n",
908                         ERROR+HIGHER_ACCESS_REQUIRED);
909                 return;
910                 }
911
912         if (CC->curr_rm < 3) {
913                 cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
914                 return;
915                 }
916
917         if (getuser(&usbuf,new_ra)!=0) {
918                 newu = (-1L);
919                 }
920         else {
921                 newu = usbuf.usernum;
922                 }
923
924         lgetroom(&CC->quickroom,CC->curr_rm);
925         post_notice = 0;
926         if (CC->quickroom.QRroomaide != newu) {
927                 post_notice = 1;
928                 }
929         CC->quickroom.QRroomaide = newu;
930         lputroom(&CC->quickroom,CC->curr_rm);
931
932         /*
933          * We have to post the change notice _after_ writing changes to 
934          * the room table, otherwise it would deadlock!
935          */
936         if (post_notice == 1) {
937                 sprintf(buf,"%s is now room aide for %s>",
938                         usbuf.fullname,CC->quickroom.QRname);
939                 aide_message(buf);
940                 }
941         cprintf("%d Ok\n",OK);
942         }
943
944
945 /* 
946  * retrieve info file for this room
947  */
948 void cmd_rinf(void) {
949         char filename[64];
950         char buf[256];
951         FILE *info_fp;
952         
953         sprintf(filename,"./info/%d",CC->curr_rm);
954         info_fp = fopen(filename,"r");
955
956         if (info_fp==NULL) {
957                 cprintf("%d No info file.\n",ERROR);
958                 return;
959                 }
960
961         cprintf("%d Info:\n",LISTING_FOLLOWS);  
962         while (fgets(buf, 256, info_fp) != NULL) {
963                 if (strlen(buf) > 0) buf[strlen(buf)-1] = 0;
964                 cprintf("%s\n", buf);
965                 }
966         cprintf("000\n");
967         fclose(info_fp);
968         }
969
970 /*
971  * aide command: kill the current room
972  */
973 void cmd_kill(char *argbuf)
974 {
975         char aaa[100];
976         int a;
977         int kill_ok;
978         struct floor flbuf;
979         long MsgToDelete;
980         
981         kill_ok = extract_int(argbuf,0);
982
983         if (!(CC->logged_in)) {
984                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
985                 return;
986                 }
987
988         if (!is_room_aide()) {
989                 cprintf("%d Higher access required.\n",
990                         ERROR+HIGHER_ACCESS_REQUIRED);
991                 return;
992                 }
993
994         if (CC->curr_rm < 3) {
995                 cprintf("%d Can't kill this room.\n",ERROR+NOT_HERE);
996                 return;
997                 }
998
999         if (kill_ok) {
1000
1001                 /* first flag the room record as not in use */
1002                 lgetroom(&CC->quickroom,CC->curr_rm);
1003                 CC->quickroom.QRflags=0;
1004
1005                 /* then delete the messages in the room */
1006                 get_msglist(CC->curr_rm);
1007                 if (CC->num_msgs > 0) for (a=0; a < CC->num_msgs; ++a) {
1008                         MsgToDelete = MessageFromList(a);
1009                         cdb_delete(CDB_MSGMAIN, &MsgToDelete, sizeof(long));
1010                         }
1011                 put_msglist(CC->curr_rm);
1012                 free(CC->msglist);
1013                 CC->num_msgs = 0;
1014                 cdb_delete(CDB_MSGLISTS, &CC->curr_rm, sizeof(int));
1015
1016                 lputroom(&CC->quickroom,CC->curr_rm);
1017
1018
1019                 /* then decrement the reference count for the floor */
1020                 lgetfloor(&flbuf,(int)CC->quickroom.QRfloor);
1021                 flbuf.f_ref_count = flbuf.f_ref_count - 1;
1022                 lputfloor(&flbuf,(int)CC->quickroom.QRfloor);
1023
1024                 /* tell the world what we did */
1025                 sprintf(aaa,"%s> killed by %s",CC->quickroom.QRname,CC->curr_user);
1026                 aide_message(aaa);
1027                 CC->curr_rm=(-1);
1028                 cprintf("%d '%s' deleted.\n",OK,CC->quickroom.QRname);
1029                 }
1030         else {
1031                 cprintf("%d ok to delete.\n",OK);
1032                 }
1033         }
1034
1035
1036 /*
1037  * Find a free slot to create a new room in, or return -1 for error.
1038  * search_dir is the direction to search in.  1 causes this function to
1039  * return the first available slot, -1 gets the last available slot.
1040  */
1041 int get_free_room_slot(int search_dir)
1042 {
1043         int a,st;
1044         struct quickroom qrbuf;
1045
1046         st = ((search_dir>0) ? 3 : (MAXROOMS-1));
1047
1048         for (a=st; ((a<MAXROOMS)&&(a>=3)); a=a+search_dir) {
1049                 getroom(&qrbuf,a);
1050                 if ((qrbuf.QRflags & QR_INUSE)==0) return(a);
1051                 }
1052         return(-1);
1053         }
1054
1055
1056 /*
1057  * internal code to create a new room (returns room flags)
1058  */
1059 unsigned create_room(int free_slot, char *new_room_name, int new_room_type, char *new_room_pass, int new_room_floor)
1060 {
1061         struct quickroom qrbuf;
1062         struct floor flbuf;
1063
1064         lgetroom(&qrbuf,free_slot);
1065         strncpy(qrbuf.QRname,new_room_name,19);
1066         strncpy(qrbuf.QRpasswd,new_room_pass,9);
1067         qrbuf.QRflags = QR_INUSE;
1068         if (new_room_type > 0) qrbuf.QRflags=(qrbuf.QRflags|QR_PRIVATE);
1069         if (new_room_type == 1) qrbuf.QRflags=(qrbuf.QRflags|QR_GUESSNAME);
1070         if (new_room_type == 2) qrbuf.QRflags=(qrbuf.QRflags|QR_PASSWORDED);
1071         qrbuf.QRroomaide = (-1L);
1072         if ((new_room_type > 0)&&(CREATAIDE==1))
1073                 qrbuf.QRroomaide=CC->usersupp.usernum;
1074         qrbuf.QRhighest = 0L;
1075         time(&qrbuf.QRgen);
1076         qrbuf.QRfloor = new_room_floor;
1077
1078         /* save what we just did... */
1079         lputroom(&qrbuf,free_slot);
1080
1081         /* bump the reference count on whatever floor the room is on */
1082         lgetfloor(&flbuf,(int)qrbuf.QRfloor);
1083         flbuf.f_ref_count = flbuf.f_ref_count + 1;
1084         lputfloor(&flbuf,(int)qrbuf.QRfloor);
1085
1086         /* be sure not to kick the creator out of the room! */
1087         lgetuser(&CC->usersupp,CC->curr_user);
1088         CC->usersupp.generation[free_slot] = qrbuf.QRgen;
1089         CC->usersupp.forget[free_slot] = (-1);
1090         lputuser(&CC->usersupp,CC->curr_user);
1091
1092         /* resume our happy day */
1093         return(qrbuf.QRflags);
1094         }
1095
1096
1097 /*
1098  * create a new room
1099  */
1100 void cmd_cre8(char *args)
1101 {
1102         int cre8_ok;
1103         int free_slot;
1104         int a;
1105         char new_room_name[256];
1106         int new_room_type;
1107         char new_room_pass[256];
1108         int new_room_floor;
1109         char aaa[256];
1110         unsigned newflags;
1111         struct quickroom qrbuf;
1112         struct floor flbuf;
1113
1114         cre8_ok = extract_int(args,0);
1115         extract(new_room_name,args,1);
1116         new_room_name[19] = 0;
1117         new_room_type = extract_int(args,2);
1118         extract(new_room_pass,args,3);
1119         new_room_pass[9] = 0;
1120         new_room_floor = 0;
1121
1122         if ((strlen(new_room_name)==0) && (cre8_ok==1)) {
1123                 cprintf("%d Invalid room name.\n",ERROR);
1124                 return;
1125                 }
1126
1127         if (num_parms(args)>=5) {
1128                 getfloor(&flbuf,extract_int(args,4));
1129                 if ((flbuf.f_flags & F_INUSE) == 0) {
1130                         cprintf("%d Invalid floor number.\n",
1131                                 ERROR+INVALID_FLOOR_OPERATION);
1132                         return;
1133                         }
1134                 else {
1135                         new_room_floor = extract_int(args,4);
1136                         }
1137                 }
1138
1139         if (!(CC->logged_in)) {
1140                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1141                 return;
1142                 }
1143
1144         if (CC->usersupp.axlevel<3) {
1145                 cprintf("%d You need higher access to create rooms.\n",
1146                         ERROR+HIGHER_ACCESS_REQUIRED);
1147                 return;
1148                 }
1149
1150         free_slot = get_free_room_slot(1);
1151         if (free_slot<0) {
1152                 cprintf("%d There is no space available for a new room.\n",
1153                         ERROR);
1154                 return;
1155                 }
1156
1157         if (cre8_ok==0) {
1158                 cprintf("%d ok to create...\n",OK);
1159                 return;
1160                 }
1161
1162         for (a=0; a<MAXROOMS; ++a) {
1163                 getroom(&qrbuf,a);
1164                 if ( (!strcasecmp(qrbuf.QRname,new_room_name))
1165                    && (qrbuf.QRflags & QR_INUSE) ) {
1166                         cprintf("%d '%s' already exists.\n",
1167                                 ERROR,qrbuf.QRname);
1168                         return;
1169                         }
1170                 }
1171
1172         if ((new_room_type < 0) || (new_room_type > 3)) {
1173                 cprintf("%d Invalid room type.\n",ERROR);
1174                 return;
1175                 }
1176
1177         newflags = create_room(free_slot,new_room_name,
1178                         new_room_type,new_room_pass,new_room_floor);
1179
1180         /* post a message in Aide> describing the new room */
1181         strncpy(aaa,new_room_name,255);
1182         strcat(aaa,"> created by ");
1183         strcat(aaa,CC->usersupp.fullname);
1184         if (newflags&QR_PRIVATE) strcat(aaa," [private]");
1185         if (newflags&QR_GUESSNAME) strcat(aaa,"[guessname] ");
1186         if (newflags&QR_PASSWORDED) {
1187                 strcat(aaa,"\n Password: ");
1188                 strcat(aaa,new_room_pass);
1189                 }
1190         aide_message(aaa); 
1191
1192         sprintf(aaa,"./info/%d",free_slot);     /* delete old info file */
1193         unlink(aaa);    
1194         sprintf(aaa,"./images/room.%d.gif",free_slot);  /* and picture */
1195         unlink(aaa);    
1196
1197         cprintf("%d '%s' has been created.\n",OK,qrbuf.QRname);
1198         }
1199
1200
1201
1202 void cmd_einf(char *ok)
1203 {       /* enter info file for current room */
1204         FILE *fp;
1205         char infofilename[32];
1206         char buf[256];
1207
1208         if (!(CC->logged_in)) {
1209                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1210                 return;
1211                 }
1212
1213         if (!is_room_aide()) {
1214                 cprintf("%d Higher access required.\n",
1215                         ERROR+HIGHER_ACCESS_REQUIRED);
1216                 return;
1217                 }
1218
1219         if (atoi(ok)==0) {
1220                 cprintf("%d Ok.\n",OK);
1221                 return;
1222                 }
1223
1224         cprintf("%d Send info...\n",SEND_LISTING);
1225
1226         sprintf(infofilename,"./info/%d",CC->curr_rm);
1227
1228         fp=fopen(infofilename,"w");
1229         do {
1230                 client_gets(buf);
1231                 if (strcmp(buf,"000")) fprintf(fp,"%s\n",buf);
1232                 } while(strcmp(buf,"000"));
1233         fclose(fp);
1234
1235         /* now update the room index so people will see our new info */
1236         lgetroom(&CC->quickroom,CC->curr_rm);   /* lock so no one steps on us */
1237         CC->quickroom.QRinfo = CC->quickroom.QRhighest + 1L;
1238         lputroom(&CC->quickroom,CC->curr_rm);
1239         }
1240
1241
1242 /* 
1243  * cmd_lflr()   -  List all known floors
1244  */
1245 void cmd_lflr(void) {
1246         int a;
1247         struct floor flbuf;
1248
1249         if (!(CC->logged_in)) {
1250                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1251                 return;
1252                 }
1253
1254         /* if (getuser(&CC->usersupp,CC->curr_user)) {
1255                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
1256                 return;
1257                 }
1258         */
1259
1260         cprintf("%d Known floors:\n",LISTING_FOLLOWS);
1261         
1262         for (a=0; a<MAXFLOORS; ++a) {
1263                 getfloor(&flbuf,a);
1264                 if (flbuf.f_flags & F_INUSE) {
1265                         cprintf("%d|%s|%d\n",
1266                                 a,
1267                                 flbuf.f_name,
1268                                 flbuf.f_ref_count);
1269                         }
1270                 }
1271         cprintf("000\n");
1272         }
1273
1274
1275
1276 /*
1277  * create a new floor
1278  */
1279 void cmd_cflr(char *argbuf)
1280 {
1281         char new_floor_name[256];
1282         struct floor flbuf;
1283         int cflr_ok;
1284         int free_slot = (-1);
1285         int a;
1286
1287         extract(new_floor_name,argbuf,0);
1288         cflr_ok = extract_int(argbuf,1);
1289
1290         
1291         if (!(CC->logged_in)) {
1292                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1293                 return;
1294                 }
1295
1296         if (CC->usersupp.axlevel<6) {
1297                 cprintf("%d You need higher access to create rooms.\n",
1298                         ERROR+HIGHER_ACCESS_REQUIRED);
1299                 return;
1300                 }
1301
1302         for (a=0; a<MAXFLOORS; ++a) {
1303                 getfloor(&flbuf,a);
1304
1305                 /* note any free slots while we're scanning... */
1306                 if ( ((flbuf.f_flags & F_INUSE)==0) 
1307                      && (free_slot < 0) )  free_slot = a;
1308
1309                 /* check to see if it already exists */
1310                 if ( (!strcasecmp(flbuf.f_name,new_floor_name))
1311                      && (flbuf.f_flags & F_INUSE) ) {
1312                         cprintf("%d Floor '%s' already exists.\n",
1313                                 ERROR+ALREADY_EXISTS,
1314                                 flbuf.f_name);
1315                         return;
1316                         }
1317
1318                 }
1319
1320         if (free_slot<0) {
1321                 cprintf("%d There is no space available for a new floor.\n",
1322                         ERROR+INVALID_FLOOR_OPERATION);
1323                 return;
1324                 }
1325
1326         if (cflr_ok==0) {
1327                 cprintf("%d ok to create...\n",OK);
1328                 return;
1329                 }
1330
1331         lgetfloor(&flbuf,free_slot);
1332         flbuf.f_flags = F_INUSE;
1333         flbuf.f_ref_count = 0;
1334         strncpy(flbuf.f_name,new_floor_name,255);
1335         lputfloor(&flbuf,free_slot);
1336         cprintf("%d %d\n",OK,free_slot);
1337         }
1338
1339
1340
1341 /*
1342  * delete a floor
1343  */
1344 void cmd_kflr(char *argbuf)
1345 {
1346         struct floor flbuf;
1347         int floor_to_delete;
1348         int kflr_ok;
1349         int delete_ok;
1350
1351         floor_to_delete = extract_int(argbuf,0);
1352         kflr_ok = extract_int(argbuf,1);
1353
1354         
1355         if (!(CC->logged_in)) {
1356                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1357                 return;
1358                 }
1359
1360         if (CC->usersupp.axlevel<6) {
1361                 cprintf("%d You need higher access to delete floors.\n",
1362                         ERROR+HIGHER_ACCESS_REQUIRED);
1363                 return;
1364                 }
1365
1366         lgetfloor(&flbuf,floor_to_delete);
1367
1368         delete_ok = 1;  
1369         if ((flbuf.f_flags & F_INUSE) == 0) {
1370                 cprintf("%d Floor %d not in use.\n",
1371                         ERROR+INVALID_FLOOR_OPERATION,floor_to_delete);
1372                 delete_ok = 0;
1373                 }
1374
1375         else {
1376                 if (flbuf.f_ref_count != 0) {
1377                         cprintf("%d Cannot delete; floor contains %d rooms.\n",
1378                                 ERROR+INVALID_FLOOR_OPERATION,
1379                                 flbuf.f_ref_count);
1380                         delete_ok = 0;
1381                         }
1382
1383                 else {
1384                         if (kflr_ok == 1) {
1385                                 cprintf("%d Ok\n",OK);
1386                                 }
1387                         else {
1388                                 cprintf("%d Ok to delete...\n",OK);
1389                                 }
1390
1391                         }
1392
1393                 }
1394
1395         if ( (delete_ok == 1) && (kflr_ok == 1) ) flbuf.f_flags = 0;
1396         lputfloor(&flbuf,floor_to_delete);
1397         }
1398
1399 /*
1400  * edit a floor
1401  */
1402 void cmd_eflr(char *argbuf)
1403 {
1404         struct floor flbuf;
1405         int floor_num;
1406         int np;
1407
1408         np = num_parms(argbuf);
1409         if (np < 1) {
1410                 cprintf("%d Usage error.\n",ERROR);
1411                 return;
1412                 }
1413         
1414         if (!(CC->logged_in)) {
1415                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1416                 return;
1417                 }
1418
1419         if (CC->usersupp.axlevel<6) {
1420                 cprintf("%d You need higher access to edit floors.\n",
1421                         ERROR+HIGHER_ACCESS_REQUIRED);
1422                 return;
1423                 }
1424
1425         floor_num = extract_int(argbuf,0);
1426         lgetfloor(&flbuf,floor_num);
1427         if ( (flbuf.f_flags & F_INUSE) == 0) {
1428                 lputfloor(&flbuf,floor_num);
1429                 cprintf("%d Floor %d is not in use.\n",
1430                         ERROR+INVALID_FLOOR_OPERATION,floor_num);
1431                 return;
1432                 }
1433         if (np >= 2) extract(flbuf.f_name,argbuf,1);
1434         lputfloor(&flbuf,floor_num);
1435         
1436         cprintf("%d Ok\n",OK);
1437         }