]> code.citadel.org Git - citadel.git/blob - citadel/room_ops.c
* Various changes to allow "new messages" to work correctly with Mail
[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                         qrbuf->QRgen = 1;
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) CC->quickroom.QRgen=1;
833                 }
834
835         old_floor = CC->quickroom.QRfloor;
836         if (num_parms(args)>=6) {
837                 CC->quickroom.QRfloor = extract_int(args,5);
838                 }
839
840         lputroom(&CC->quickroom,CC->curr_rm);
841
842         /* adjust the floor reference counts */
843         lgetfloor(&flbuf,old_floor);
844         --flbuf.f_ref_count;
845         lputfloor(&flbuf,old_floor);
846         lgetfloor(&flbuf,CC->quickroom.QRfloor);
847         ++flbuf.f_ref_count;
848         lputfloor(&flbuf,CC->quickroom.QRfloor);
849
850         /* create a room directory if necessary */
851         if (CC->quickroom.QRflags & QR_DIRECTORY) {
852                 sprintf(buf,
853                         "mkdir ./files/%s </dev/null >/dev/null 2>/dev/null",
854                 CC->quickroom.QRdirname);
855                 system(buf);
856                 }
857
858         sprintf(buf,"%s> edited by %s",CC->quickroom.QRname,CC->curr_user);
859         aide_message(buf);
860         cprintf("%d Ok\n",OK);
861         }
862
863
864
865 /* 
866  * get the name of the room aide for this room
867  */
868 void cmd_geta(void) {
869         struct usersupp usbuf;
870
871         if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
872                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
873                 return;
874                 }
875
876         if (CC->curr_rm < 0) {
877                 cprintf("%d No current room.\n",ERROR);
878                 return;
879                 }
880
881         if (getuserbynumber(&usbuf,CC->quickroom.QRroomaide)==0) {
882                 cprintf("%d %s\n",OK,usbuf.fullname);
883                 }
884         else {
885                 cprintf("%d \n",OK);
886                 }
887         }
888
889
890 /* 
891  * set the room aide for this room
892  */
893 void cmd_seta(char *new_ra)
894 {
895         struct usersupp usbuf;
896         long newu;
897         char buf[256];
898         int post_notice;
899         
900         if (!(CC->logged_in)) {
901                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
902                 return;
903                 }
904
905         if (!is_room_aide()) {
906                 cprintf("%d Higher access required.\n",
907                         ERROR+HIGHER_ACCESS_REQUIRED);
908                 return;
909                 }
910
911         if (CC->curr_rm < 3) {
912                 cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
913                 return;
914                 }
915
916         if (getuser(&usbuf,new_ra)!=0) {
917                 newu = (-1L);
918                 }
919         else {
920                 newu = usbuf.usernum;
921                 }
922
923         lgetroom(&CC->quickroom,CC->curr_rm);
924         post_notice = 0;
925         if (CC->quickroom.QRroomaide != newu) {
926                 post_notice = 1;
927                 }
928         CC->quickroom.QRroomaide = newu;
929         lputroom(&CC->quickroom,CC->curr_rm);
930
931         /*
932          * We have to post the change notice _after_ writing changes to 
933          * the room table, otherwise it would deadlock!
934          */
935         if (post_notice == 1) {
936                 sprintf(buf,"%s is now room aide for %s>",
937                         usbuf.fullname,CC->quickroom.QRname);
938                 aide_message(buf);
939                 }
940         cprintf("%d Ok\n",OK);
941         }
942
943
944 /* 
945  * retrieve info file for this room
946  */
947 void cmd_rinf(void) {
948         char filename[64];
949         char buf[256];
950         FILE *info_fp;
951         
952         sprintf(filename,"./info/%d",CC->curr_rm);
953         info_fp = fopen(filename,"r");
954
955         if (info_fp==NULL) {
956                 cprintf("%d No info file.\n",ERROR);
957                 return;
958                 }
959
960         cprintf("%d Info:\n",LISTING_FOLLOWS);  
961         while (fgets(buf, 256, info_fp) != NULL) {
962                 if (strlen(buf) > 0) buf[strlen(buf)-1] = 0;
963                 cprintf("%s\n", buf);
964                 }
965         cprintf("000\n");
966         fclose(info_fp);
967         }
968
969 /*
970  * aide command: kill the current room
971  */
972 void cmd_kill(char *argbuf)
973 {
974         char aaa[100];
975         int a;
976         int kill_ok;
977         struct floor flbuf;
978         long MsgToDelete;
979         
980         kill_ok = extract_int(argbuf,0);
981
982         if (!(CC->logged_in)) {
983                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
984                 return;
985                 }
986
987         if (!is_room_aide()) {
988                 cprintf("%d Higher access required.\n",
989                         ERROR+HIGHER_ACCESS_REQUIRED);
990                 return;
991                 }
992
993         if (CC->curr_rm < 3) {
994                 cprintf("%d Can't kill this room.\n",ERROR+NOT_HERE);
995                 return;
996                 }
997
998         if (kill_ok) {
999
1000                 /* first flag the room record as not in use */
1001                 lgetroom(&CC->quickroom,CC->curr_rm);
1002                 CC->quickroom.QRflags=0;
1003
1004                 /* then delete the messages in the room */
1005                 get_msglist(CC->curr_rm);
1006                 if (CC->num_msgs > 0) for (a=0; a < CC->num_msgs; ++a) {
1007                         MsgToDelete = MessageFromList(a);
1008                         cdb_delete(CDB_MSGMAIN, &MsgToDelete, sizeof(long));
1009                         }
1010                 put_msglist(CC->curr_rm);
1011                 free(CC->msglist);
1012                 CC->num_msgs = 0;
1013                 cdb_delete(CDB_MSGLISTS, &CC->curr_rm, sizeof(int));
1014
1015                 lputroom(&CC->quickroom,CC->curr_rm);
1016
1017
1018                 /* then decrement the reference count for the floor */
1019                 lgetfloor(&flbuf,(int)CC->quickroom.QRfloor);
1020                 flbuf.f_ref_count = flbuf.f_ref_count - 1;
1021                 lputfloor(&flbuf,(int)CC->quickroom.QRfloor);
1022
1023                 /* tell the world what we did */
1024                 sprintf(aaa,"%s> killed by %s",CC->quickroom.QRname,CC->curr_user);
1025                 aide_message(aaa);
1026                 CC->curr_rm=(-1);
1027                 cprintf("%d '%s' deleted.\n",OK,CC->quickroom.QRname);
1028                 }
1029         else {
1030                 cprintf("%d ok to delete.\n",OK);
1031                 }
1032         }
1033
1034
1035 /*
1036  * Find a free slot to create a new room in, or return -1 for error.
1037  * search_dir is the direction to search in.  1 causes this function to
1038  * return the first available slot, -1 gets the last available slot.
1039  */
1040 int get_free_room_slot(int search_dir)
1041 {
1042         int a,st;
1043         struct quickroom qrbuf;
1044
1045         st = ((search_dir>0) ? 3 : (MAXROOMS-1));
1046
1047         for (a=st; ((a<MAXROOMS)&&(a>=3)); a=a+search_dir) {
1048                 getroom(&qrbuf,a);
1049                 if ((qrbuf.QRflags & QR_INUSE)==0) return(a);
1050                 }
1051         return(-1);
1052         }
1053
1054
1055 /*
1056  * internal code to create a new room (returns room flags)
1057  */
1058 unsigned create_room(int free_slot, char *new_room_name, int new_room_type, char *new_room_pass, int new_room_floor)
1059 {
1060         struct quickroom qrbuf;
1061         struct floor flbuf;
1062
1063         lgetroom(&qrbuf,free_slot);
1064         strncpy(qrbuf.QRname,new_room_name,19);
1065         strncpy(qrbuf.QRpasswd,new_room_pass,9);
1066         qrbuf.QRflags = QR_INUSE;
1067         if (new_room_type > 0) qrbuf.QRflags=(qrbuf.QRflags|QR_PRIVATE);
1068         if (new_room_type == 1) qrbuf.QRflags=(qrbuf.QRflags|QR_GUESSNAME);
1069         if (new_room_type == 2) qrbuf.QRflags=(qrbuf.QRflags|QR_PASSWORDED);
1070         qrbuf.QRroomaide = (-1L);
1071         if ((new_room_type > 0)&&(CREATAIDE==1))
1072                 qrbuf.QRroomaide=CC->usersupp.usernum;
1073         qrbuf.QRhighest = 0L;
1074         ++qrbuf.QRgen; if (qrbuf.QRgen>=126) qrbuf.QRgen=10;
1075         qrbuf.QRfloor = new_room_floor;
1076
1077         /* save what we just did... */
1078         lputroom(&qrbuf,free_slot);
1079
1080         /* bump the reference count on whatever floor the room is on */
1081         lgetfloor(&flbuf,(int)qrbuf.QRfloor);
1082         flbuf.f_ref_count = flbuf.f_ref_count + 1;
1083         lputfloor(&flbuf,(int)qrbuf.QRfloor);
1084
1085         /* be sure not to kick the creator out of the room! */
1086         lgetuser(&CC->usersupp,CC->curr_user);
1087         CC->usersupp.generation[free_slot] = qrbuf.QRgen;
1088         CC->usersupp.forget[free_slot] = (-1);
1089         lputuser(&CC->usersupp,CC->curr_user);
1090
1091         /* resume our happy day */
1092         return(qrbuf.QRflags);
1093         }
1094
1095
1096 /*
1097  * create a new room
1098  */
1099 void cmd_cre8(char *args)
1100 {
1101         int cre8_ok;
1102         int free_slot;
1103         int a;
1104         char new_room_name[256];
1105         int new_room_type;
1106         char new_room_pass[256];
1107         int new_room_floor;
1108         char aaa[256];
1109         unsigned newflags;
1110         struct quickroom qrbuf;
1111         struct floor flbuf;
1112
1113         cre8_ok = extract_int(args,0);
1114         extract(new_room_name,args,1);
1115         new_room_name[19] = 0;
1116         new_room_type = extract_int(args,2);
1117         extract(new_room_pass,args,3);
1118         new_room_pass[9] = 0;
1119         new_room_floor = 0;
1120
1121         if ((strlen(new_room_name)==0) && (cre8_ok==1)) {
1122                 cprintf("%d Invalid room name.\n",ERROR);
1123                 return;
1124                 }
1125
1126         if (num_parms(args)>=5) {
1127                 getfloor(&flbuf,extract_int(args,4));
1128                 if ((flbuf.f_flags & F_INUSE) == 0) {
1129                         cprintf("%d Invalid floor number.\n",
1130                                 ERROR+INVALID_FLOOR_OPERATION);
1131                         return;
1132                         }
1133                 else {
1134                         new_room_floor = extract_int(args,4);
1135                         }
1136                 }
1137
1138         if (!(CC->logged_in)) {
1139                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1140                 return;
1141                 }
1142
1143         if (CC->usersupp.axlevel<3) {
1144                 cprintf("%d You need higher access to create rooms.\n",
1145                         ERROR+HIGHER_ACCESS_REQUIRED);
1146                 return;
1147                 }
1148
1149         free_slot = get_free_room_slot(1);
1150         if (free_slot<0) {
1151                 cprintf("%d There is no space available for a new room.\n",
1152                         ERROR);
1153                 return;
1154                 }
1155
1156         if (cre8_ok==0) {
1157                 cprintf("%d ok to create...\n",OK);
1158                 return;
1159                 }
1160
1161         for (a=0; a<MAXROOMS; ++a) {
1162                 getroom(&qrbuf,a);
1163                 if ( (!strcasecmp(qrbuf.QRname,new_room_name))
1164                    && (qrbuf.QRflags & QR_INUSE) ) {
1165                         cprintf("%d '%s' already exists.\n",
1166                                 ERROR,qrbuf.QRname);
1167                         return;
1168                         }
1169                 }
1170
1171         if ((new_room_type < 0) || (new_room_type > 3)) {
1172                 cprintf("%d Invalid room type.\n",ERROR);
1173                 return;
1174                 }
1175
1176         newflags = create_room(free_slot,new_room_name,
1177                         new_room_type,new_room_pass,new_room_floor);
1178
1179         /* post a message in Aide> describing the new room */
1180         strncpy(aaa,new_room_name,255);
1181         strcat(aaa,"> created by ");
1182         strcat(aaa,CC->usersupp.fullname);
1183         if (newflags&QR_PRIVATE) strcat(aaa," [private]");
1184         if (newflags&QR_GUESSNAME) strcat(aaa,"[guessname] ");
1185         if (newflags&QR_PASSWORDED) {
1186                 strcat(aaa,"\n Password: ");
1187                 strcat(aaa,new_room_pass);
1188                 }
1189         aide_message(aaa); 
1190
1191         sprintf(aaa,"./info/%d",free_slot);     /* delete old info file */
1192         unlink(aaa);    
1193         sprintf(aaa,"./images/room.%d.gif",free_slot);  /* and picture */
1194         unlink(aaa);    
1195
1196         cprintf("%d '%s' has been created.\n",OK,qrbuf.QRname);
1197         }
1198
1199
1200
1201 void cmd_einf(char *ok)
1202 {       /* enter info file for current room */
1203         FILE *fp;
1204         char infofilename[32];
1205         char buf[256];
1206
1207         if (!(CC->logged_in)) {
1208                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1209                 return;
1210                 }
1211
1212         if (!is_room_aide()) {
1213                 cprintf("%d Higher access required.\n",
1214                         ERROR+HIGHER_ACCESS_REQUIRED);
1215                 return;
1216                 }
1217
1218         if (atoi(ok)==0) {
1219                 cprintf("%d Ok.\n",OK);
1220                 return;
1221                 }
1222
1223         cprintf("%d Send info...\n",SEND_LISTING);
1224
1225         sprintf(infofilename,"./info/%d",CC->curr_rm);
1226
1227         fp=fopen(infofilename,"w");
1228         do {
1229                 client_gets(buf);
1230                 if (strcmp(buf,"000")) fprintf(fp,"%s\n",buf);
1231                 } while(strcmp(buf,"000"));
1232         fclose(fp);
1233
1234         /* now update the room index so people will see our new info */
1235         lgetroom(&CC->quickroom,CC->curr_rm);   /* lock so no one steps on us */
1236         CC->quickroom.QRinfo = CC->quickroom.QRhighest + 1L;
1237         lputroom(&CC->quickroom,CC->curr_rm);
1238         }
1239
1240
1241 /* 
1242  * cmd_lflr()   -  List all known floors
1243  */
1244 void cmd_lflr(void) {
1245         int a;
1246         struct floor flbuf;
1247
1248         if (!(CC->logged_in)) {
1249                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1250                 return;
1251                 }
1252
1253         /* if (getuser(&CC->usersupp,CC->curr_user)) {
1254                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
1255                 return;
1256                 }
1257         */
1258
1259         cprintf("%d Known floors:\n",LISTING_FOLLOWS);
1260         
1261         for (a=0; a<MAXFLOORS; ++a) {
1262                 getfloor(&flbuf,a);
1263                 if (flbuf.f_flags & F_INUSE) {
1264                         cprintf("%d|%s|%d\n",
1265                                 a,
1266                                 flbuf.f_name,
1267                                 flbuf.f_ref_count);
1268                         }
1269                 }
1270         cprintf("000\n");
1271         }
1272
1273
1274
1275 /*
1276  * create a new floor
1277  */
1278 void cmd_cflr(char *argbuf)
1279 {
1280         char new_floor_name[256];
1281         struct floor flbuf;
1282         int cflr_ok;
1283         int free_slot = (-1);
1284         int a;
1285
1286         extract(new_floor_name,argbuf,0);
1287         cflr_ok = extract_int(argbuf,1);
1288
1289         
1290         if (!(CC->logged_in)) {
1291                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1292                 return;
1293                 }
1294
1295         if (CC->usersupp.axlevel<6) {
1296                 cprintf("%d You need higher access to create rooms.\n",
1297                         ERROR+HIGHER_ACCESS_REQUIRED);
1298                 return;
1299                 }
1300
1301         for (a=0; a<MAXFLOORS; ++a) {
1302                 getfloor(&flbuf,a);
1303
1304                 /* note any free slots while we're scanning... */
1305                 if ( ((flbuf.f_flags & F_INUSE)==0) 
1306                      && (free_slot < 0) )  free_slot = a;
1307
1308                 /* check to see if it already exists */
1309                 if ( (!strcasecmp(flbuf.f_name,new_floor_name))
1310                      && (flbuf.f_flags & F_INUSE) ) {
1311                         cprintf("%d Floor '%s' already exists.\n",
1312                                 ERROR+ALREADY_EXISTS,
1313                                 flbuf.f_name);
1314                         return;
1315                         }
1316
1317                 }
1318
1319         if (free_slot<0) {
1320                 cprintf("%d There is no space available for a new floor.\n",
1321                         ERROR+INVALID_FLOOR_OPERATION);
1322                 return;
1323                 }
1324
1325         if (cflr_ok==0) {
1326                 cprintf("%d ok to create...\n",OK);
1327                 return;
1328                 }
1329
1330         lgetfloor(&flbuf,free_slot);
1331         flbuf.f_flags = F_INUSE;
1332         flbuf.f_ref_count = 0;
1333         strncpy(flbuf.f_name,new_floor_name,255);
1334         lputfloor(&flbuf,free_slot);
1335         cprintf("%d %d\n",OK,free_slot);
1336         }
1337
1338
1339
1340 /*
1341  * delete a floor
1342  */
1343 void cmd_kflr(char *argbuf)
1344 {
1345         struct floor flbuf;
1346         int floor_to_delete;
1347         int kflr_ok;
1348         int delete_ok;
1349
1350         floor_to_delete = extract_int(argbuf,0);
1351         kflr_ok = extract_int(argbuf,1);
1352
1353         
1354         if (!(CC->logged_in)) {
1355                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1356                 return;
1357                 }
1358
1359         if (CC->usersupp.axlevel<6) {
1360                 cprintf("%d You need higher access to delete floors.\n",
1361                         ERROR+HIGHER_ACCESS_REQUIRED);
1362                 return;
1363                 }
1364
1365         lgetfloor(&flbuf,floor_to_delete);
1366
1367         delete_ok = 1;  
1368         if ((flbuf.f_flags & F_INUSE) == 0) {
1369                 cprintf("%d Floor %d not in use.\n",
1370                         ERROR+INVALID_FLOOR_OPERATION,floor_to_delete);
1371                 delete_ok = 0;
1372                 }
1373
1374         else {
1375                 if (flbuf.f_ref_count != 0) {
1376                         cprintf("%d Cannot delete; floor contains %d rooms.\n",
1377                                 ERROR+INVALID_FLOOR_OPERATION,
1378                                 flbuf.f_ref_count);
1379                         delete_ok = 0;
1380                         }
1381
1382                 else {
1383                         if (kflr_ok == 1) {
1384                                 cprintf("%d Ok\n",OK);
1385                                 }
1386                         else {
1387                                 cprintf("%d Ok to delete...\n",OK);
1388                                 }
1389
1390                         }
1391
1392                 }
1393
1394         if ( (delete_ok == 1) && (kflr_ok == 1) ) flbuf.f_flags = 0;
1395         lputfloor(&flbuf,floor_to_delete);
1396         }
1397
1398 /*
1399  * edit a floor
1400  */
1401 void cmd_eflr(char *argbuf)
1402 {
1403         struct floor flbuf;
1404         int floor_num;
1405         int np;
1406
1407         np = num_parms(argbuf);
1408         if (np < 1) {
1409                 cprintf("%d Usage error.\n",ERROR);
1410                 return;
1411                 }
1412         
1413         if (!(CC->logged_in)) {
1414                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1415                 return;
1416                 }
1417
1418         if (CC->usersupp.axlevel<6) {
1419                 cprintf("%d You need higher access to edit floors.\n",
1420                         ERROR+HIGHER_ACCESS_REQUIRED);
1421                 return;
1422                 }
1423
1424         floor_num = extract_int(argbuf,0);
1425         lgetfloor(&flbuf,floor_num);
1426         if ( (flbuf.f_flags & F_INUSE) == 0) {
1427                 lputfloor(&flbuf,floor_num);
1428                 cprintf("%d Floor %d is not in use.\n",
1429                         ERROR+INVALID_FLOOR_OPERATION,floor_num);
1430                 return;
1431                 }
1432         if (np >= 2) extract(flbuf.f_name,argbuf,1);
1433         lputfloor(&flbuf,floor_num);
1434         
1435         cprintf("%d Ok\n",OK);
1436         }