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