]> code.citadel.org Git - citadel.git/blob - citadel/room_ops.c
* BOTH the old and new generation systems are being written to at
[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         struct visit vbuf;
508
509         CC->curr_rm=where;
510         getroom(&CC->quickroom,CC->curr_rm);
511         lgetuser(&CC->usersupp,CC->curr_user);
512         CtdlGetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
513
514         /* old method - remove when we're ready */
515         CC->usersupp.forget[CC->curr_rm]=(-1);
516         CC->usersupp.generation[CC->curr_rm]=CC->quickroom.QRgen;
517
518         /* new method */
519         vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
520
521         CtdlSetRelationship(&vbuf, &CC->usersupp, &CC->quickroom);
522         lputuser(&CC->usersupp,CC->curr_user);
523
524         /* check for new mail */
525         newmailcount = NewMailCount();
526
527         /* set info to 1 if the user needs to read the room's info file */
528         if (CC->quickroom.QRinfo > CC->usersupp.lastseen[CC->curr_rm]) info = 1;
529
530         b=0; c=0;
531         get_mm();
532         get_msglist(CC->curr_rm);
533         for (a=0; a<CC->num_msgs; ++a) {
534                 if (MessageFromList(a)>0L) {
535                         ++b;
536                         if (MessageFromList(a)
537                            > CC->usersupp.lastseen[CC->curr_rm]) ++c;
538                         }
539                 }
540
541
542         if (CC->curr_rm == 1) rmailflag = 1;
543         else rmailflag = 0;
544
545         if ( (CC->quickroom.QRroomaide == CC->usersupp.usernum)
546            || (CC->usersupp.axlevel>=6) )  raideflag = 1;
547         else raideflag = 0;
548
549         if (display_result) cprintf("%d%c%s|%d|%d|%d|%d|%ld|%ld|%d|%d|%d|%d\n",
550                 OK,check_express(),
551                 CC->quickroom.QRname,c,b,info,CC->quickroom.QRflags,
552                 CC->quickroom.QRhighest,CC->usersupp.lastseen[CC->curr_rm],
553                 rmailflag,raideflag,newmailcount,CC->quickroom.QRfloor);
554         if (CC->quickroom.QRflags & QR_PRIVATE) {
555                 set_wtmpsupp("<private room>");
556                 }
557         else {
558                 set_wtmpsupp(CC->quickroom.QRname);
559                 }
560         }
561
562
563 /* 
564  * cmd_goto()  -  goto a new room
565  */
566 void cmd_goto(char *gargs)
567 {
568         struct quickroom QRscratch;
569         int a,c;
570         int ok;
571         char bbb[20],towhere[32],password[20];
572
573         if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
574                 cprintf("%d not logged in\n",ERROR+NOT_LOGGED_IN);
575                 return;
576                 }
577
578         extract(towhere,gargs,0);
579         extract(password,gargs,1);
580
581         c=0;
582         getuser(&CC->usersupp,CC->curr_user);
583         for (a=0; a<MAXROOMS; ++a) {
584                 getroom(&QRscratch,a);
585                 if ((a==0)&&(!strcasecmp(towhere,"_BASEROOM_"))) {
586                         strncpy(towhere,QRscratch.QRname,31);
587                         }
588                 if ((a==1)&&(!strcasecmp(towhere,"_MAIL_"))) {
589                         strncpy(towhere,QRscratch.QRname,31);
590                         }
591                 if ((!strcasecmp(QRscratch.QRname,config.c_twitroom))
592                    &&(!strcasecmp(towhere,"_BITBUCKET_"))) {
593                         strncpy(towhere,QRscratch.QRname,31);
594                         }
595                 strcpy(bbb,QRscratch.QRname);
596                 ok = 0;
597
598                 /* let internal programs go directly to any room */
599                 if (((CC->internal_pgm))&&(!strcasecmp(bbb,towhere))) {
600                         usergoto(a,1);
601                         return;
602                         }
603
604                 /* normal clients have to pass through security */
605                 if ( 
606                         (strcasecmp(bbb,towhere)==0)
607                         &&      ((QRscratch.QRflags&QR_INUSE)!=0)
608
609                         && (    ((QRscratch.QRflags&QR_PREFONLY)==0)
610                         ||      (CC->usersupp.axlevel>=5)
611                         )
612
613                         && (    (a!=2) || (CC->usersupp.axlevel>=6) )
614
615                         && (    ((QRscratch.QRflags&QR_PRIVATE)==0)
616                         || (QRscratch.QRflags&QR_GUESSNAME)
617                         || (CC->usersupp.axlevel>=6)
618                         || (QRscratch.QRflags&QR_PASSWORDED)
619                         ||      (QRscratch.QRgen==CC->usersupp.generation[a])
620                         )
621         
622                         ) ok = 1;
623
624
625                 if (ok==1) {
626
627                         if (  (QRscratch.QRflags&QR_PASSWORDED) &&
628                                 (CC->usersupp.axlevel<6) &&
629                                 (QRscratch.QRgen!=CC->usersupp.generation[a]) &&
630                                 (strcasecmp(QRscratch.QRpasswd,password))
631                                 ) {
632                                         cprintf("%d wrong or missing passwd\n",
633                                                 ERROR+PASSWORD_REQUIRED);
634                                         return;
635                                         }
636
637                         usergoto(a,1);
638                         return;
639                         }
640
641                 }
642         cprintf("%d room '%s' not found\n",ERROR+ROOM_NOT_FOUND,towhere);
643         }
644
645
646 void cmd_whok(void) {
647         struct usersupp temp;
648         struct cdbdata *cdbus;
649
650         if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
651                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
652                 return;
653                 }
654         getuser(&CC->usersupp,CC->curr_user);
655
656         if ((!is_room_aide()) && (!(CC->internal_pgm)) ) {
657                 cprintf("%d Higher access required.\n",
658                         ERROR+HIGHER_ACCESS_REQUIRED);
659                 return;
660                 }
661
662         cprintf("%d Who knows room:\n",LISTING_FOLLOWS);
663         cdb_rewind(CDB_USERSUPP);
664         while(cdbus = cdb_next_item(CDB_USERSUPP), cdbus != NULL) {
665                 bzero(&temp, sizeof(struct usersupp));
666                 memcpy(&temp, cdbus->ptr, cdbus->len);
667                 cdb_free(cdbus);
668                 if ((CC->quickroom.QRflags & QR_INUSE)
669                         && ( (CC->curr_rm!=2) || (temp.axlevel>=6) )
670                         && (CC->quickroom.QRgen != (temp.forget[CC->curr_rm]) )
671
672                         && (    ((CC->quickroom.QRflags&QR_PREFONLY)==0)
673                         ||      (temp.axlevel>=5)
674                         )
675
676                         && (    ((CC->quickroom.QRflags&QR_PRIVATE)==0)
677                         ||      (temp.axlevel>=6)
678                         ||      (CC->quickroom.QRgen==(temp.generation[CC->curr_rm]))
679                         )
680
681                         && (strncmp(temp.fullname,"000",3))
682
683                 ) cprintf("%s\n",temp.fullname);
684                 }
685         cprintf("000\n");
686         }
687
688
689 /*
690  * RDIR command for room directory
691  */
692 void cmd_rdir(void) {
693         char buf[256];
694         char flnm[256];
695         char comment[256];
696         FILE *ls,*fd;
697         struct stat statbuf;
698
699         if (!(CC->logged_in)) {
700                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
701                 return;
702                 }
703
704         getroom(&CC->quickroom,CC->curr_rm);
705         getuser(&CC->usersupp,CC->curr_user);
706
707         if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
708                 cprintf("%d not here.\n",ERROR+NOT_HERE);
709                 return;
710                 }
711
712         if (((CC->quickroom.QRflags & QR_VISDIR) == 0)
713            && (CC->usersupp.axlevel<6)
714            && (CC->usersupp.usernum != CC->quickroom.QRroomaide)) {
715                 cprintf("%d not here.\n",ERROR+HIGHER_ACCESS_REQUIRED);
716                 return;
717                 }
718
719         cprintf("%d %s|%s/files/%s\n",
720                 LISTING_FOLLOWS,config.c_fqdn,BBSDIR,CC->quickroom.QRdirname);
721
722         sprintf(buf,"cd %s/files/%s; ls >%s 2>/dev/null",
723                 BBSDIR,CC->quickroom.QRdirname,CC->temp);
724         system(buf);
725
726         sprintf(buf,"%s/files/%s/filedir",BBSDIR,CC->quickroom.QRdirname);
727         fd = fopen(buf,"r");
728         if (fd==NULL) fd=fopen("/dev/null","r");
729
730         ls = fopen(CC->temp,"r");
731         while (fgets(flnm,256,ls)!=NULL) {
732                 flnm[strlen(flnm)-1]=0;
733                 if (strcasecmp(flnm,"filedir")) {
734                         sprintf(buf,"%s/files/%s/%s",
735                                 BBSDIR,CC->quickroom.QRdirname,flnm);
736                         stat(buf,&statbuf);
737                         strcpy(comment,"");
738                         fseek(fd,0L,0);
739                         while ((fgets(buf,256,fd)!=NULL)
740                             &&(strlen(comment)==0)) {
741                                 buf[strlen(buf)-1] = 0;
742                                 if ((!strncasecmp(buf,flnm,strlen(flnm)))
743                                    && (buf[strlen(flnm)]==' ')) 
744                                         strncpy(comment,
745                                                 &buf[strlen(flnm)+1],255);
746                                 }
747                         cprintf("%s|%ld|%s\n",flnm,statbuf.st_size,comment);
748                         }
749                 }
750         fclose(ls);
751         fclose(fd);
752         unlink(CC->temp);
753
754         cprintf("000\n");
755         }
756
757 /*
758  * get room parameters (aide or room aide command)
759  */
760 void cmd_getr(void) {
761         if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
762                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
763                 return;
764                 }
765
766         if ( (!is_room_aide()) && (!(CC->internal_pgm)) ) {
767                 cprintf("%d Higher access required.\n",
768                         ERROR+HIGHER_ACCESS_REQUIRED);
769                 return;
770                 }
771
772         if (CC->curr_rm < 3) {
773                 cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
774                 return;
775                 }
776
777         getroom(&CC->quickroom,CC->curr_rm);
778         cprintf("%d%c%s|%s|%s|%d|%d\n",
779                 OK,check_express(),
780                 CC->quickroom.QRname,
781                 ((CC->quickroom.QRflags & QR_PASSWORDED) ? CC->quickroom.QRpasswd : ""),
782                 ((CC->quickroom.QRflags & QR_DIRECTORY) ? CC->quickroom.QRdirname : ""),
783                 CC->quickroom.QRflags,
784                 (int)CC->quickroom.QRfloor);
785         }
786
787
788 /*
789  * set room parameters (aide or room aide command)
790  */
791 void cmd_setr(char *args) {
792         char buf[256];
793         struct floor flbuf;
794         int old_floor;
795
796         if (!(CC->logged_in)) {
797                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
798                 return;
799                 }
800
801         if (!is_room_aide()) {
802                 cprintf("%d Higher access required.\n",
803                         ERROR+HIGHER_ACCESS_REQUIRED);
804                 return;
805                 }
806
807         if (CC->curr_rm < 3) {
808                 cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
809                 return;
810                 }
811
812         if (num_parms(args)>=6) {
813                 getfloor(&flbuf,extract_int(args,5));
814                 if ((flbuf.f_flags & F_INUSE) == 0) {
815                         cprintf("%d Invalid floor number.\n",
816                                 ERROR+INVALID_FLOOR_OPERATION);
817                         return;
818                         }
819                 }
820
821         lgetroom(&CC->quickroom,CC->curr_rm);
822         extract(buf,args,0); buf[20]=0;
823         strncpy(CC->quickroom.QRname,buf,19);
824         extract(buf,args,1); buf[10]=0;
825         strncpy(CC->quickroom.QRpasswd,buf,9);
826         extract(buf,args,2); buf[15]=0;
827         strncpy(CC->quickroom.QRdirname,buf,19);
828         CC->quickroom.QRflags = ( extract_int(args,3) | QR_INUSE);
829
830         /* Clean up a client boo-boo: if the client set the room to
831          * guess-name or passworded, ensure that the private flag is
832          * also set.
833          */
834         if ((CC->quickroom.QRflags & QR_GUESSNAME)
835            ||(CC->quickroom.QRflags & QR_PASSWORDED))
836                 CC->quickroom.QRflags |= QR_PRIVATE;
837
838         /* Kick everyone out if the client requested it (by changing the
839          * room's generation number)
840          */
841         if (extract_int(args,4)) {
842                 time(&CC->quickroom.QRgen);
843                 }
844
845         old_floor = CC->quickroom.QRfloor;
846         if (num_parms(args)>=6) {
847                 CC->quickroom.QRfloor = extract_int(args,5);
848                 }
849
850         lputroom(&CC->quickroom,CC->curr_rm);
851
852         /* adjust the floor reference counts */
853         lgetfloor(&flbuf,old_floor);
854         --flbuf.f_ref_count;
855         lputfloor(&flbuf,old_floor);
856         lgetfloor(&flbuf,CC->quickroom.QRfloor);
857         ++flbuf.f_ref_count;
858         lputfloor(&flbuf,CC->quickroom.QRfloor);
859
860         /* create a room directory if necessary */
861         if (CC->quickroom.QRflags & QR_DIRECTORY) {
862                 sprintf(buf,
863                         "mkdir ./files/%s </dev/null >/dev/null 2>/dev/null",
864                 CC->quickroom.QRdirname);
865                 system(buf);
866                 }
867
868         sprintf(buf,"%s> edited by %s",CC->quickroom.QRname,CC->curr_user);
869         aide_message(buf);
870         cprintf("%d Ok\n",OK);
871         }
872
873
874
875 /* 
876  * get the name of the room aide for this room
877  */
878 void cmd_geta(void) {
879         struct usersupp usbuf;
880
881         if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
882                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
883                 return;
884                 }
885
886         if (CC->curr_rm < 0) {
887                 cprintf("%d No current room.\n",ERROR);
888                 return;
889                 }
890
891         if (getuserbynumber(&usbuf,CC->quickroom.QRroomaide)==0) {
892                 cprintf("%d %s\n",OK,usbuf.fullname);
893                 }
894         else {
895                 cprintf("%d \n",OK);
896                 }
897         }
898
899
900 /* 
901  * set the room aide for this room
902  */
903 void cmd_seta(char *new_ra)
904 {
905         struct usersupp usbuf;
906         long newu;
907         char buf[256];
908         int post_notice;
909         
910         if (!(CC->logged_in)) {
911                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
912                 return;
913                 }
914
915         if (!is_room_aide()) {
916                 cprintf("%d Higher access required.\n",
917                         ERROR+HIGHER_ACCESS_REQUIRED);
918                 return;
919                 }
920
921         if (CC->curr_rm < 3) {
922                 cprintf("%d Can't edit this room.\n",ERROR+NOT_HERE);
923                 return;
924                 }
925
926         if (getuser(&usbuf,new_ra)!=0) {
927                 newu = (-1L);
928                 }
929         else {
930                 newu = usbuf.usernum;
931                 }
932
933         lgetroom(&CC->quickroom,CC->curr_rm);
934         post_notice = 0;
935         if (CC->quickroom.QRroomaide != newu) {
936                 post_notice = 1;
937                 }
938         CC->quickroom.QRroomaide = newu;
939         lputroom(&CC->quickroom,CC->curr_rm);
940
941         /*
942          * We have to post the change notice _after_ writing changes to 
943          * the room table, otherwise it would deadlock!
944          */
945         if (post_notice == 1) {
946                 sprintf(buf,"%s is now room aide for %s>",
947                         usbuf.fullname,CC->quickroom.QRname);
948                 aide_message(buf);
949                 }
950         cprintf("%d Ok\n",OK);
951         }
952
953
954 /* 
955  * retrieve info file for this room
956  */
957 void cmd_rinf(void) {
958         char filename[64];
959         char buf[256];
960         FILE *info_fp;
961         
962         sprintf(filename,"./info/%d",CC->curr_rm);
963         info_fp = fopen(filename,"r");
964
965         if (info_fp==NULL) {
966                 cprintf("%d No info file.\n",ERROR);
967                 return;
968                 }
969
970         cprintf("%d Info:\n",LISTING_FOLLOWS);  
971         while (fgets(buf, 256, info_fp) != NULL) {
972                 if (strlen(buf) > 0) buf[strlen(buf)-1] = 0;
973                 cprintf("%s\n", buf);
974                 }
975         cprintf("000\n");
976         fclose(info_fp);
977         }
978
979 /*
980  * aide command: kill the current room
981  */
982 void cmd_kill(char *argbuf)
983 {
984         char aaa[100];
985         int a;
986         int kill_ok;
987         struct floor flbuf;
988         long MsgToDelete;
989         
990         kill_ok = extract_int(argbuf,0);
991
992         if (!(CC->logged_in)) {
993                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
994                 return;
995                 }
996
997         if (!is_room_aide()) {
998                 cprintf("%d Higher access required.\n",
999                         ERROR+HIGHER_ACCESS_REQUIRED);
1000                 return;
1001                 }
1002
1003         if (CC->curr_rm < 3) {
1004                 cprintf("%d Can't kill this room.\n",ERROR+NOT_HERE);
1005                 return;
1006                 }
1007
1008         if (kill_ok) {
1009
1010                 /* first flag the room record as not in use */
1011                 lgetroom(&CC->quickroom,CC->curr_rm);
1012                 CC->quickroom.QRflags=0;
1013
1014                 /* then delete the messages in the room */
1015                 get_msglist(CC->curr_rm);
1016                 if (CC->num_msgs > 0) for (a=0; a < CC->num_msgs; ++a) {
1017                         MsgToDelete = MessageFromList(a);
1018                         cdb_delete(CDB_MSGMAIN, &MsgToDelete, sizeof(long));
1019                         }
1020                 put_msglist(CC->curr_rm);
1021                 free(CC->msglist);
1022                 CC->num_msgs = 0;
1023                 cdb_delete(CDB_MSGLISTS, &CC->curr_rm, sizeof(int));
1024
1025                 lputroom(&CC->quickroom,CC->curr_rm);
1026
1027
1028                 /* then decrement the reference count for the floor */
1029                 lgetfloor(&flbuf,(int)CC->quickroom.QRfloor);
1030                 flbuf.f_ref_count = flbuf.f_ref_count - 1;
1031                 lputfloor(&flbuf,(int)CC->quickroom.QRfloor);
1032
1033                 /* tell the world what we did */
1034                 sprintf(aaa,"%s> killed by %s",CC->quickroom.QRname,CC->curr_user);
1035                 aide_message(aaa);
1036                 CC->curr_rm=(-1);
1037                 cprintf("%d '%s' deleted.\n",OK,CC->quickroom.QRname);
1038                 }
1039         else {
1040                 cprintf("%d ok to delete.\n",OK);
1041                 }
1042         }
1043
1044
1045 /*
1046  * Find a free slot to create a new room in, or return -1 for error.
1047  * search_dir is the direction to search in.  1 causes this function to
1048  * return the first available slot, -1 gets the last available slot.
1049  */
1050 int get_free_room_slot(int search_dir)
1051 {
1052         int a,st;
1053         struct quickroom qrbuf;
1054
1055         st = ((search_dir>0) ? 3 : (MAXROOMS-1));
1056
1057         for (a=st; ((a<MAXROOMS)&&(a>=3)); a=a+search_dir) {
1058                 getroom(&qrbuf,a);
1059                 if ((qrbuf.QRflags & QR_INUSE)==0) return(a);
1060                 }
1061         return(-1);
1062         }
1063
1064
1065 /*
1066  * internal code to create a new room (returns room flags)
1067  */
1068 unsigned create_room(int free_slot, char *new_room_name, int new_room_type, char *new_room_pass, int new_room_floor)
1069 {
1070         struct quickroom qrbuf;
1071         struct floor flbuf;
1072         struct visit vbuf;
1073
1074         lgetroom(&qrbuf,free_slot);
1075         strncpy(qrbuf.QRname,new_room_name,19);
1076         strncpy(qrbuf.QRpasswd,new_room_pass,9);
1077         qrbuf.QRflags = QR_INUSE;
1078         if (new_room_type > 0) qrbuf.QRflags=(qrbuf.QRflags|QR_PRIVATE);
1079         if (new_room_type == 1) qrbuf.QRflags=(qrbuf.QRflags|QR_GUESSNAME);
1080         if (new_room_type == 2) qrbuf.QRflags=(qrbuf.QRflags|QR_PASSWORDED);
1081         qrbuf.QRroomaide = (-1L);
1082         if ((new_room_type > 0)&&(CREATAIDE==1))
1083                 qrbuf.QRroomaide=CC->usersupp.usernum;
1084         qrbuf.QRhighest = 0L;
1085         time(&qrbuf.QRgen);
1086         qrbuf.QRfloor = new_room_floor;
1087
1088         /* save what we just did... */
1089         lputroom(&qrbuf,free_slot);
1090
1091         /* bump the reference count on whatever floor the room is on */
1092         lgetfloor(&flbuf,(int)qrbuf.QRfloor);
1093         flbuf.f_ref_count = flbuf.f_ref_count + 1;
1094         lputfloor(&flbuf,(int)qrbuf.QRfloor);
1095
1096         /* be sure not to kick the creator out of the room! */
1097         lgetuser(&CC->usersupp,CC->curr_user);
1098         CtdlGetRelationship(&vbuf, &CC->usersupp, &qrbuf);
1099         /* (old method) */
1100         CC->usersupp.generation[free_slot] = qrbuf.QRgen;
1101         CC->usersupp.forget[free_slot] = (-1);
1102         /* (new method) */
1103         vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
1104         CtdlSetRelationship(&vbuf, &CC->usersupp, &qrbuf);
1105         lputuser(&CC->usersupp,CC->curr_user);
1106
1107         /* resume our happy day */
1108         return(qrbuf.QRflags);
1109         }
1110
1111
1112 /*
1113  * create a new room
1114  */
1115 void cmd_cre8(char *args)
1116 {
1117         int cre8_ok;
1118         int free_slot;
1119         int a;
1120         char new_room_name[256];
1121         int new_room_type;
1122         char new_room_pass[256];
1123         int new_room_floor;
1124         char aaa[256];
1125         unsigned newflags;
1126         struct quickroom qrbuf;
1127         struct floor flbuf;
1128
1129         cre8_ok = extract_int(args,0);
1130         extract(new_room_name,args,1);
1131         new_room_name[19] = 0;
1132         new_room_type = extract_int(args,2);
1133         extract(new_room_pass,args,3);
1134         new_room_pass[9] = 0;
1135         new_room_floor = 0;
1136
1137         if ((strlen(new_room_name)==0) && (cre8_ok==1)) {
1138                 cprintf("%d Invalid room name.\n",ERROR);
1139                 return;
1140                 }
1141
1142         if (num_parms(args)>=5) {
1143                 getfloor(&flbuf,extract_int(args,4));
1144                 if ((flbuf.f_flags & F_INUSE) == 0) {
1145                         cprintf("%d Invalid floor number.\n",
1146                                 ERROR+INVALID_FLOOR_OPERATION);
1147                         return;
1148                         }
1149                 else {
1150                         new_room_floor = extract_int(args,4);
1151                         }
1152                 }
1153
1154         if (!(CC->logged_in)) {
1155                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1156                 return;
1157                 }
1158
1159         if (CC->usersupp.axlevel<3) {
1160                 cprintf("%d You need higher access to create rooms.\n",
1161                         ERROR+HIGHER_ACCESS_REQUIRED);
1162                 return;
1163                 }
1164
1165         free_slot = get_free_room_slot(1);
1166         if (free_slot<0) {
1167                 cprintf("%d There is no space available for a new room.\n",
1168                         ERROR);
1169                 return;
1170                 }
1171
1172         if (cre8_ok==0) {
1173                 cprintf("%d ok to create...\n",OK);
1174                 return;
1175                 }
1176
1177         for (a=0; a<MAXROOMS; ++a) {
1178                 getroom(&qrbuf,a);
1179                 if ( (!strcasecmp(qrbuf.QRname,new_room_name))
1180                    && (qrbuf.QRflags & QR_INUSE) ) {
1181                         cprintf("%d '%s' already exists.\n",
1182                                 ERROR,qrbuf.QRname);
1183                         return;
1184                         }
1185                 }
1186
1187         if ((new_room_type < 0) || (new_room_type > 3)) {
1188                 cprintf("%d Invalid room type.\n",ERROR);
1189                 return;
1190                 }
1191
1192         newflags = create_room(free_slot,new_room_name,
1193                         new_room_type,new_room_pass,new_room_floor);
1194
1195         /* post a message in Aide> describing the new room */
1196         strncpy(aaa,new_room_name,255);
1197         strcat(aaa,"> created by ");
1198         strcat(aaa,CC->usersupp.fullname);
1199         if (newflags&QR_PRIVATE) strcat(aaa," [private]");
1200         if (newflags&QR_GUESSNAME) strcat(aaa,"[guessname] ");
1201         if (newflags&QR_PASSWORDED) {
1202                 strcat(aaa,"\n Password: ");
1203                 strcat(aaa,new_room_pass);
1204                 }
1205         aide_message(aaa); 
1206
1207         sprintf(aaa,"./info/%d",free_slot);     /* delete old info file */
1208         unlink(aaa);    
1209         sprintf(aaa,"./images/room.%d.gif",free_slot);  /* and picture */
1210         unlink(aaa);    
1211
1212         cprintf("%d '%s' has been created.\n",OK,qrbuf.QRname);
1213         }
1214
1215
1216
1217 void cmd_einf(char *ok)
1218 {       /* enter info file for current room */
1219         FILE *fp;
1220         char infofilename[32];
1221         char buf[256];
1222
1223         if (!(CC->logged_in)) {
1224                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1225                 return;
1226                 }
1227
1228         if (!is_room_aide()) {
1229                 cprintf("%d Higher access required.\n",
1230                         ERROR+HIGHER_ACCESS_REQUIRED);
1231                 return;
1232                 }
1233
1234         if (atoi(ok)==0) {
1235                 cprintf("%d Ok.\n",OK);
1236                 return;
1237                 }
1238
1239         cprintf("%d Send info...\n",SEND_LISTING);
1240
1241         sprintf(infofilename,"./info/%d",CC->curr_rm);
1242
1243         fp=fopen(infofilename,"w");
1244         do {
1245                 client_gets(buf);
1246                 if (strcmp(buf,"000")) fprintf(fp,"%s\n",buf);
1247                 } while(strcmp(buf,"000"));
1248         fclose(fp);
1249
1250         /* now update the room index so people will see our new info */
1251         lgetroom(&CC->quickroom,CC->curr_rm);   /* lock so no one steps on us */
1252         CC->quickroom.QRinfo = CC->quickroom.QRhighest + 1L;
1253         lputroom(&CC->quickroom,CC->curr_rm);
1254         }
1255
1256
1257 /* 
1258  * cmd_lflr()   -  List all known floors
1259  */
1260 void cmd_lflr(void) {
1261         int a;
1262         struct floor flbuf;
1263
1264         if (!(CC->logged_in)) {
1265                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1266                 return;
1267                 }
1268
1269         /* if (getuser(&CC->usersupp,CC->curr_user)) {
1270                 cprintf("%d Can't locate user!\n",ERROR+INTERNAL_ERROR);
1271                 return;
1272                 }
1273         */
1274
1275         cprintf("%d Known floors:\n",LISTING_FOLLOWS);
1276         
1277         for (a=0; a<MAXFLOORS; ++a) {
1278                 getfloor(&flbuf,a);
1279                 if (flbuf.f_flags & F_INUSE) {
1280                         cprintf("%d|%s|%d\n",
1281                                 a,
1282                                 flbuf.f_name,
1283                                 flbuf.f_ref_count);
1284                         }
1285                 }
1286         cprintf("000\n");
1287         }
1288
1289
1290
1291 /*
1292  * create a new floor
1293  */
1294 void cmd_cflr(char *argbuf)
1295 {
1296         char new_floor_name[256];
1297         struct floor flbuf;
1298         int cflr_ok;
1299         int free_slot = (-1);
1300         int a;
1301
1302         extract(new_floor_name,argbuf,0);
1303         cflr_ok = extract_int(argbuf,1);
1304
1305         
1306         if (!(CC->logged_in)) {
1307                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1308                 return;
1309                 }
1310
1311         if (CC->usersupp.axlevel<6) {
1312                 cprintf("%d You need higher access to create rooms.\n",
1313                         ERROR+HIGHER_ACCESS_REQUIRED);
1314                 return;
1315                 }
1316
1317         for (a=0; a<MAXFLOORS; ++a) {
1318                 getfloor(&flbuf,a);
1319
1320                 /* note any free slots while we're scanning... */
1321                 if ( ((flbuf.f_flags & F_INUSE)==0) 
1322                      && (free_slot < 0) )  free_slot = a;
1323
1324                 /* check to see if it already exists */
1325                 if ( (!strcasecmp(flbuf.f_name,new_floor_name))
1326                      && (flbuf.f_flags & F_INUSE) ) {
1327                         cprintf("%d Floor '%s' already exists.\n",
1328                                 ERROR+ALREADY_EXISTS,
1329                                 flbuf.f_name);
1330                         return;
1331                         }
1332
1333                 }
1334
1335         if (free_slot<0) {
1336                 cprintf("%d There is no space available for a new floor.\n",
1337                         ERROR+INVALID_FLOOR_OPERATION);
1338                 return;
1339                 }
1340
1341         if (cflr_ok==0) {
1342                 cprintf("%d ok to create...\n",OK);
1343                 return;
1344                 }
1345
1346         lgetfloor(&flbuf,free_slot);
1347         flbuf.f_flags = F_INUSE;
1348         flbuf.f_ref_count = 0;
1349         strncpy(flbuf.f_name,new_floor_name,255);
1350         lputfloor(&flbuf,free_slot);
1351         cprintf("%d %d\n",OK,free_slot);
1352         }
1353
1354
1355
1356 /*
1357  * delete a floor
1358  */
1359 void cmd_kflr(char *argbuf)
1360 {
1361         struct floor flbuf;
1362         int floor_to_delete;
1363         int kflr_ok;
1364         int delete_ok;
1365
1366         floor_to_delete = extract_int(argbuf,0);
1367         kflr_ok = extract_int(argbuf,1);
1368
1369         
1370         if (!(CC->logged_in)) {
1371                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1372                 return;
1373                 }
1374
1375         if (CC->usersupp.axlevel<6) {
1376                 cprintf("%d You need higher access to delete floors.\n",
1377                         ERROR+HIGHER_ACCESS_REQUIRED);
1378                 return;
1379                 }
1380
1381         lgetfloor(&flbuf,floor_to_delete);
1382
1383         delete_ok = 1;  
1384         if ((flbuf.f_flags & F_INUSE) == 0) {
1385                 cprintf("%d Floor %d not in use.\n",
1386                         ERROR+INVALID_FLOOR_OPERATION,floor_to_delete);
1387                 delete_ok = 0;
1388                 }
1389
1390         else {
1391                 if (flbuf.f_ref_count != 0) {
1392                         cprintf("%d Cannot delete; floor contains %d rooms.\n",
1393                                 ERROR+INVALID_FLOOR_OPERATION,
1394                                 flbuf.f_ref_count);
1395                         delete_ok = 0;
1396                         }
1397
1398                 else {
1399                         if (kflr_ok == 1) {
1400                                 cprintf("%d Ok\n",OK);
1401                                 }
1402                         else {
1403                                 cprintf("%d Ok to delete...\n",OK);
1404                                 }
1405
1406                         }
1407
1408                 }
1409
1410         if ( (delete_ok == 1) && (kflr_ok == 1) ) flbuf.f_flags = 0;
1411         lputfloor(&flbuf,floor_to_delete);
1412         }
1413
1414 /*
1415  * edit a floor
1416  */
1417 void cmd_eflr(char *argbuf)
1418 {
1419         struct floor flbuf;
1420         int floor_num;
1421         int np;
1422
1423         np = num_parms(argbuf);
1424         if (np < 1) {
1425                 cprintf("%d Usage error.\n",ERROR);
1426                 return;
1427                 }
1428         
1429         if (!(CC->logged_in)) {
1430                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
1431                 return;
1432                 }
1433
1434         if (CC->usersupp.axlevel<6) {
1435                 cprintf("%d You need higher access to edit floors.\n",
1436                         ERROR+HIGHER_ACCESS_REQUIRED);
1437                 return;
1438                 }
1439
1440         floor_num = extract_int(argbuf,0);
1441         lgetfloor(&flbuf,floor_num);
1442         if ( (flbuf.f_flags & F_INUSE) == 0) {
1443                 lputfloor(&flbuf,floor_num);
1444                 cprintf("%d Floor %d is not in use.\n",
1445                         ERROR+INVALID_FLOOR_OPERATION,floor_num);
1446                 return;
1447                 }
1448         if (np >= 2) extract(flbuf.f_name,argbuf,1);
1449         lputfloor(&flbuf,floor_num);
1450         
1451         cprintf("%d Ok\n",OK);
1452         }