]> code.citadel.org Git - citadel.git/blob - citadel/rooms.c
* rooms.c: use mkfifo(3) instead of system("mkfifo")
[citadel.git] / citadel / rooms.c
1 /* Citadel/UX room-oriented routines */
2
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <ctype.h>
8 #include <string.h>
9 #include <signal.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <sys/wait.h>
13 #include <errno.h>
14 #include "citadel.h"
15 #include "rooms.h"
16
17 #define IFEXPERT if (userflags&US_EXPERT)
18 #define IFNEXPERT if ((userflags&US_EXPERT)==0)
19 #define IFAIDE if (axlevel>=6)
20 #define IFNAIDE if (axlevel<6)
21
22
23 void sttybbs(int cmd);
24 void extract(char *dest, char *source, int parmnum);
25 int extract_int(char *source, int parmnum);
26 void hit_any_key(void);
27 int yesno(void);
28 int yesno_d(int d);
29 void strprompt(char *prompt, char *str, int len);
30 void newprompt(char *prompt, char *str, int len);
31 int struncmp(char *lstr, char *rstr, int len);
32 void dotgoto(char *towhere, int display_name);
33 long extract_long(char *source, int parmnum);
34 void serv_read(char *buf, int bytes);
35 void formout(char *name);
36 int inkey(void);
37 int fmout(int width, FILE *fp, char pagin, int height, int starting_lp, char subst);
38 void citedit(FILE *fp, long int base_pos);
39 void progress(long int curr, long int cmax);
40 int pattern(char *search, char *patn);
41 int file_checksum(char *filename);
42 int nukedir(char *dirname);
43 void color(int colornum);
44
45 extern unsigned room_flags;
46 extern char room_name[];
47 extern char temp[];
48 extern char tempdir[];
49 extern int editor_pid;
50 extern char editor_path[];
51 extern int screenwidth;
52 extern int screenheight;
53 extern char fullname[];
54 extern int userflags;
55 extern char sigcaught;
56 extern char floor_mode;
57 extern char curr_floor;
58
59
60 extern int ugnum;
61 extern long uglsn;
62 extern char ugname[];
63
64 extern char floorlist[128][256];
65
66
67 void load_floorlist(void) {
68         int a;
69         char buf[256];
70
71         for (a=0; a<128; ++a) floorlist[a][0] = 0;
72
73         serv_puts("LFLR");
74         serv_gets(buf);
75         if (buf[0]!='1') {
76                 strcpy(floorlist[0],"Main Floor");
77                 return;
78                 }
79         while (serv_gets(buf), strcmp(buf,"000")) {
80                 extract(floorlist[extract_int(buf,0)],buf,1);
81                 }
82         }
83
84 void listrms(char *variety)
85 {
86         char buf[256];
87         char rmname[32];
88         int f,c;
89
90         serv_puts(variety);
91         serv_gets(buf);
92         if (buf[0]!='1') return;
93         c = 1;
94         sigcaught = 0;
95         sttybbs(SB_YES_INTR);
96         while (serv_gets(buf), strcmp(buf,"000")) if (sigcaught==0) {
97                 extract(rmname,buf,0);
98                 if ((c + strlen(rmname) + 4) > screenwidth) {
99                         printf("\n");
100                         c = 1;
101                         }
102                 f = extract_int(buf,1);
103                 if (f & QR_PRIVATE) {
104                         color(1);
105                         }
106                 else {
107                         color(2);
108                         }
109                 printf("%s",rmname);
110                 if ((f & QR_DIRECTORY) && (f & QR_NETWORK)) printf("}  ");
111                 else if (f & QR_DIRECTORY) printf("]  ");
112                 else if (f & QR_NETWORK) printf(")  ");
113                 else printf(">  ");
114                 c = c + strlen(rmname) + 3;
115                 }
116         color(7);
117         sttybbs(SB_NO_INTR);
118         }
119
120
121 void list_other_floors(void) {
122         int a,c;
123
124         c = 1;
125         for (a=0; a<128; ++a) if ((strlen(floorlist[a])>0)&&(a!=curr_floor)) {
126                 if ((c + strlen(floorlist[a]) + 4) > screenwidth) {
127                         printf("\n");
128                         c = 1;
129                         }
130                 printf("%s:  ",floorlist[a]);
131                 c = c + strlen(floorlist[a]) + 3;
132                 }
133         }
134
135
136 /*
137  * List known rooms.  kn_floor_mode should be set to 0 for a 'flat' listing,
138  * 1 to list rooms on the current floor, or 1 to list rooms on all floors.
139  */
140 void knrooms(int kn_floor_mode)
141 {
142         char buf[256];
143         int a;
144
145         load_floorlist();
146
147         if (kn_floor_mode == 0) {
148                 color(3);
149                 printf("\n   Rooms with unread messages:\n");
150                 listrms("LKRN");
151                 color(3);
152                 printf("\n\n   No unseen messages in:\n");
153                 listrms("LKRO");
154                 printf("\n");
155                 }
156
157         if (kn_floor_mode == 1) {
158                 color(3);
159                 printf("\n   Rooms with unread messages on %s:\n",
160                         floorlist[(int)curr_floor]);
161                 sprintf(buf,"LKRN %d",curr_floor);
162                 listrms(buf);
163                 color(3);
164                 printf("\n\n   Rooms with no new messages on %s:\n",
165                         floorlist[(int)curr_floor]);
166                 sprintf(buf,"LKRO %d",curr_floor);
167                 listrms(buf);
168                 color(3);
169                 printf("\n\n   Other floors:\n");
170                 list_other_floors();
171                 printf("\n");
172                 }
173
174         if (kn_floor_mode == 2) {
175                 for (a=0; a<128; ++a) if (floorlist[a][0]!=0) {
176                         color(3);
177                         printf("\n   Rooms on %s:\n",floorlist[a]);
178                         sprintf(buf,"LKRA %d",a);
179                         listrms(buf);
180                         printf("\n");
181                         }
182                 }
183         
184         color(7);
185         IFNEXPERT hit_any_key();
186         }
187
188
189 void listzrooms(void) {         /* list public forgotten rooms */
190         color(3);
191         printf("\n   Forgotten public rooms:\n");
192         listrms("LZRM");
193         printf("\n");
194         color(7);
195         IFNEXPERT hit_any_key();
196         }
197
198
199 int set_room_attr(int ibuf, char *prompt, unsigned int sbit)
200 {
201         int a;
202
203         printf("%s [%s]? ",prompt,((ibuf&sbit) ? "Yes":"No"));
204         a=yesno_d(ibuf&sbit);
205         ibuf=(ibuf|sbit);
206         if (!a) ibuf=(ibuf^sbit);
207         return(ibuf);
208         }
209
210
211
212 /*
213  * Select a floor (used in several commands)
214  * The supplied argument is the 'default' floor number.
215  * This function returns the selected floor number.
216  */
217 int select_floor(int rfloor)
218 {
219         int a, newfloor;
220         char floorstr[256];
221
222         if (floor_mode == 1) {
223                 if (floorlist[(int)curr_floor][0]==0) load_floorlist();
224
225                 do {
226                         newfloor = (-1);
227                         strcpy(floorstr,&floorlist[rfloor][0]);
228                         strprompt("Which floor",floorstr,256);
229                         for (a=0; a<128; ++a) {
230                                 if (!strucmp(floorstr,&floorlist[a][0]))
231                                         newfloor = a;
232                                 if ((newfloor<0)&&(!struncmp(floorstr,
233                                         &floorlist[a][0],strlen(floorstr))))
234                                                 newfloor = a;
235                                 if ((newfloor<0)&&(pattern(&floorlist[a][0],
236                                         floorstr)>=0)) newfloor = a;
237                                 }
238                         if (newfloor<0) {
239                                 printf("\n One of:\n");
240                                 for (a=0; a<128; ++a)
241                                         if (floorlist[a][0]!=0)
242                                                 printf("%s\n",
243                                                         &floorlist[a][0]);
244                                 }
245                         } while(newfloor < 0);
246                 return(newfloor);
247                 }
248         return(rfloor);
249         }
250
251
252
253
254 /*
255  * .<A>ide <E>dit room
256  */
257 void editthisroom(void) {
258         char rname[ROOMNAMELEN];
259         char rpass[10];
260         char rdir[15];
261         unsigned rflags;
262         int rbump;
263         char raide[32];
264         char buf[256];
265         int rfloor;
266
267         serv_puts("GETR");
268         serv_gets(buf);
269         if (buf[0]!='2') {
270                 printf("%s\n",&buf[4]);
271                 return;
272                 }
273
274         extract(rname,&buf[4],0);
275         extract(rpass,&buf[4],1);
276         extract(rdir, &buf[4],2);
277         rflags = extract_int(&buf[4],3);
278         rfloor = extract_int(&buf[4],4);
279         rbump = 0;
280
281         serv_puts("GETA");
282         serv_gets(buf);
283         if (buf[0]=='2') strcpy(raide,&buf[4]);
284         else strcpy(raide,"");
285         if (strlen(raide)==0) strcpy(raide,"none");
286
287         strprompt("Room name",rname,ROOMNAMELEN-1);
288
289         rfloor = select_floor(rfloor);
290         rflags = set_room_attr(rflags,"Private room",QR_PRIVATE);
291         if (rflags & QR_PRIVATE)
292                 rflags = set_room_attr(rflags,
293                         "Accessible by guessing room name",QR_GUESSNAME);
294
295         /* if it's public, clear the privacy classes */
296         if ((rflags & QR_PRIVATE)==0) {
297                 if (rflags & QR_GUESSNAME)  rflags = rflags - QR_GUESSNAME;
298                 if (rflags & QR_PASSWORDED) rflags = rflags - QR_PASSWORDED;
299                 }
300
301         /* if it's private, choose the privacy classes */
302         if ( (rflags & QR_PRIVATE)
303            && ( (rflags & QR_GUESSNAME) == 0) ) {
304                 rflags = set_room_attr(rflags,
305                         "Accessible by entering a password",QR_PASSWORDED);
306                 }
307         if ( (rflags & QR_PRIVATE)
308            && ((rflags&QR_PASSWORDED)==QR_PASSWORDED) ) {
309                 strprompt("Room password",rpass,9);
310                 }
311
312         if ((rflags&QR_PRIVATE)==QR_PRIVATE) {
313                 printf("Cause current users to forget room [No] ? ");
314                 if (yesno_d(0)==1) rbump = 1;
315                 }
316
317         rflags = set_room_attr(rflags,"Preferred users only",QR_PREFONLY);
318         rflags = set_room_attr(rflags,"Read-only room",QR_READONLY);
319         rflags = set_room_attr(rflags,"Directory room",QR_DIRECTORY);
320         rflags = set_room_attr(rflags,"Permanent room",QR_PERMANENT);
321         if (rflags & QR_DIRECTORY) {
322                 strprompt("Directory name",rdir,14);
323                 rflags = set_room_attr(rflags,"Uploading allowed",QR_UPLOAD);
324                 rflags = set_room_attr(rflags,"Downloading allowed",
325                                                                 QR_DOWNLOAD);
326                 rflags = set_room_attr(rflags,"Visible directory",QR_VISDIR);
327                 }
328         rflags = set_room_attr(rflags,"Network shared room",QR_NETWORK);
329         rflags = set_room_attr(rflags,
330                 "Automatically make all messages anonymous",QR_ANONONLY);
331         if ( (rflags & QR_ANONONLY) == 0) {
332                 rflags = set_room_attr(rflags,
333                         "Ask users whether to make messages anonymous",
334                         QR_ANONOPT);
335                 }
336
337         do {
338                 strprompt("Room aide (or 'none')",raide,29);
339                 if (!strucmp(raide,"none")) {
340                         strcpy(raide,"");
341                         strcpy(buf,"200");
342                         }
343                 else {
344                         sprintf(buf,"QUSR %s",raide);
345                         serv_puts(buf);
346                         serv_gets(buf);
347                         if (buf[0]!='2') printf("%s\n",&buf[4]);
348                         }
349                 } while(buf[0]!='2');
350
351         if (!strucmp(raide,"none")) strcpy(raide,"");
352
353         printf("Save changes (y/n)? ");
354         if (yesno()==1) {
355                 sprintf(buf,"SETR %s|%s|%s|%d|%d|%d",
356                         rname,rpass,rdir,rflags,rbump,rfloor);
357                 serv_puts(buf);
358                 serv_gets(buf);
359                 printf("%s\n",&buf[4]);
360                 sprintf(buf,"SETA %s",raide);
361                 serv_puts(buf);
362                 serv_gets(buf);
363                 if (buf[0]=='2') dotgoto(rname,2);
364                 }
365         }
366
367
368 /*
369  * un-goto the previous room
370  */
371 void ungoto(void) { 
372         char buf[256];
373         
374         if (!strcmp(ugname,"")) return;
375         sprintf(buf,"GOTO %s",ugname);
376         serv_puts(buf);
377         serv_gets(buf);
378         if (buf[0]!='2') {
379                 printf("%s\n",&buf[4]);
380                 return;
381                 }
382         sprintf(buf,"SLRP %ld",uglsn);
383         serv_puts(buf);
384         serv_gets(buf);
385         if (buf[0]!='2') printf("%s\n",&buf[4]);
386         strcpy(buf,ugname);
387         strcpy(ugname,"");
388         dotgoto(buf,0);
389         }
390
391
392 /*
393  * download()  -  download a file or files.  The argument passed to this
394  *                function determines which protocol to use.
395  */
396 void download(int proto)
397 {
398
399 /*
400   - 0 = paginate, 1 = xmodem, 2 = raw, 3 = ymodem, 4 = zmodem, 5 = save
401 */
402
403
404         char buf[256];
405         char dbuf[4096];
406         char filename[256];
407         long total_bytes = 0L;
408         long transmitted_bytes = 0L;
409         long aa,bb;
410         int a,b;
411         int packet;
412         FILE *tpipe = NULL;
413         FILE *savefp = NULL;
414         int proto_pid;
415         int broken = 0;
416
417         if ((room_flags & QR_DOWNLOAD) == 0) {
418                 printf("*** You cannot download from this room.\n");
419                 return;
420                 }
421         
422         newprompt("Enter filename: ",filename,255);
423
424         sprintf(buf,"OPEN %s",filename);
425         serv_puts(buf);
426         serv_gets(buf);
427         if (buf[0]!='2') {
428                 printf("%s\n",&buf[4]);
429                 return;
430                 }
431         total_bytes = extract_long(&buf[4],0);
432
433
434         /* Here's the code for simply transferring the file to the client,
435          * for folks who have their own clientware.  It's a lot simpler than
436          * the [XYZ]modem code below...
437          */
438         if (proto == 5) {
439                 printf("Enter the name of the directory to save '%s'\n",
440                         filename);
441                 printf("to, or press return for the current directory.\n");
442                 newprompt("Directory: ",dbuf,256);
443                 if (strlen(dbuf)==0) strcpy(dbuf,".");
444                 strcat(dbuf,"/");
445                 strcat(dbuf,filename);
446                 
447                 savefp = fopen(dbuf,"w");
448                 if (savefp == NULL) {
449                         printf("Cannot open '%s': %s\n",dbuf,strerror(errno));
450                         /* close the download file at the server */
451                         serv_puts("CLOS");
452                         serv_gets(buf);
453                         if (buf[0]!='2') {
454                                 printf("%s\n",&buf[4]);
455                                 }
456                         return;
457                         }
458                 progress(0,total_bytes);
459                 while ( (transmitted_bytes < total_bytes) && (broken == 0) ) {
460                         bb = total_bytes - transmitted_bytes;
461                         aa = ((bb < 4096) ? bb : 4096);
462                         sprintf(buf,"READ %ld|%ld",transmitted_bytes,aa);
463                         serv_puts(buf);
464                         serv_gets(buf);
465                         if (buf[0]!='6') {
466                                 printf("%s\n",&buf[4]);
467                                 return;
468                                 }
469                         packet = extract_int(&buf[4],0);
470                         serv_read(dbuf,packet);
471                         if (fwrite(dbuf,packet,1,savefp) < 1) broken = 1;
472                         transmitted_bytes = transmitted_bytes + (long)packet;
473                         progress(transmitted_bytes,total_bytes);
474                         }
475                 fclose(savefp);
476                 /* close the download file at the server */
477                 serv_puts("CLOS");
478                 serv_gets(buf);
479                 if (buf[0]!='2') {
480                         printf("%s\n",&buf[4]);
481                         }
482                 return;
483                 }
484
485
486         mkdir(tempdir,0700);
487         sprintf(buf,"%s/%s",tempdir,filename);
488         mkfifo(buf, 0777);
489
490         /* We do the remainder of this function as a separate process in
491          * order to allow recovery if the transfer is aborted.  If the
492          * file transfer program aborts, the first child process receives a
493          * "broken pipe" signal and aborts.  We *should* be able to catch
494          * this condition with signal(), but it doesn't seem to work on all
495          * systems.
496          */
497         a = fork();
498         if (a!=0) {
499                 /* wait for the download to finish */
500                 while (wait(&b)!=a) ;;
501                 sttybbs(0);
502                 /* close the download file at the server */
503                 serv_puts("CLOS");
504                 serv_gets(buf);
505                 if (buf[0]!='2') {
506                         printf("%s\n",&buf[4]);
507                         }
508                 /* clean up the temporary directory */
509                 nukedir(tempdir);
510                 return;
511                 }
512
513         sprintf(buf,"%s/%s",tempdir,filename);  /* full pathname */
514
515         /* The next fork() creates a second child process that is used for
516          * the actual file transfer program (usually sz).
517          */
518         proto_pid = fork();
519         if (proto_pid == 0) {
520                 if (proto==0)  {
521                         sttybbs(0);
522                         signal(SIGINT,SIG_DFL);
523                         signal(SIGQUIT,SIG_DFL);
524                         sprintf(dbuf,"SHELL=/dev/null; export SHELL; TERM=dumb; export TERM; exec more -d <%s",buf);
525                         system(dbuf);
526                         sttybbs(SB_NO_INTR);
527                         exit(0);
528                         }
529                 sttybbs(3);
530                 signal(SIGINT,SIG_DFL);
531                 signal(SIGQUIT,SIG_DFL);
532                 if (proto==1) execlp("sx","sx",buf,NULL);
533                 if (proto==2) execlp("cat","cat",buf,NULL);
534                 if (proto==3) execlp("sb","sb",buf,NULL);
535                 if (proto==4) execlp("sz","sz",buf,NULL);
536                 execlp("cat","cat",buf,NULL);
537                 exit(1);
538                 }
539
540         tpipe = fopen(buf,"w");
541
542         while ( (transmitted_bytes < total_bytes) && (broken == 0) ) {
543                 bb = total_bytes - transmitted_bytes;
544                 aa = ((bb < 4096) ? bb : 4096);
545                 sprintf(buf,"READ %ld|%ld",transmitted_bytes,aa);
546                 serv_puts(buf);
547                 serv_gets(buf);
548                 if (buf[0]!='6') {
549                         printf("%s\n",&buf[4]);
550                         return;
551                         }
552                 packet = extract_int(&buf[4],0);
553                 serv_read(dbuf,packet);
554                 if (fwrite(dbuf,packet,1,tpipe) < 1) broken = 1;
555                 transmitted_bytes = transmitted_bytes + (long)packet;
556                 }
557         if (tpipe!=NULL) fclose(tpipe);
558
559         /* Hang out and wait for the file transfer program to finish */
560         while (wait(&a) != proto_pid) ;;
561
562
563         putc(7,stdout);
564         exit(0);        /* transfer control back to the main program */
565         }
566
567
568 /*
569  * read directory of this room
570  */
571 void roomdir(void) {
572         char flnm[256];
573         char flsz[32];
574         char comment[256];
575         char buf[256];
576
577         serv_puts("RDIR");
578         serv_gets(buf);
579         if (buf[0]!='1') {
580                 printf("%s\n",&buf[4]);
581                 return;
582                 }
583
584         extract(comment,&buf[4],0);
585         extract(flnm,&buf[4],1);
586         printf("\nDirectory of %s on %s\n",flnm,comment);
587         printf("-----------------------\n");
588         while (serv_gets(buf), strcmp(buf,"000")) {
589                 extract(flnm,buf,0);
590                 extract(flsz,buf,1);
591                 extract(comment,buf,2);
592                 if (strlen(flnm)<=14)
593                         printf("%-14s %8s %s\n",flnm,flsz,comment);
594                 else
595                         printf("%s\n%14s %8s %s\n",flnm,"",flsz,comment);
596                 }
597         }
598
599
600 /*
601  * add a user to a private room
602  */
603 void invite(void) {
604         char aaa[31],bbb[256];
605
606         if ((room_flags & QR_PRIVATE)==0) {
607                 printf("This is not a private room.\n");
608                 return;
609                 }
610
611         newprompt("Name of user? ",aaa,30);
612         if (aaa[0]==0) return;
613
614         sprintf(bbb,"INVT %s",aaa);
615         serv_puts(bbb);
616         serv_gets(bbb);
617         printf("%s\n",&bbb[4]);
618         }
619
620
621 /*
622  * kick a user out of a room
623  */
624 void kickout(void) {
625         char aaa[31],bbb[256];
626
627         if ((room_flags & QR_PRIVATE)==0) {
628                 printf("Note: this is not a private room.  Kicking a user ");
629                 printf("out of this room will only\nhave the same effect ");
630                 printf("as if they <Z>apped the room.\n\n");
631                 }
632
633         newprompt("Name of user? ",aaa,30);
634         if (aaa[0]==0) return;
635
636         sprintf(bbb,"KICK %s",aaa);
637         serv_puts(bbb);
638         serv_gets(bbb);
639         printf("%s\n",&bbb[4]);
640         }
641
642
643 /*
644  * aide command: kill the current room
645  */
646 void killroom(void) {
647         char aaa[100];
648
649         serv_puts("KILL 0");
650         serv_gets(aaa);
651         if (aaa[0]!='2') {
652                 printf("%s\n",&aaa[4]);
653                 return;
654                 }
655
656         printf("Are you sure you want to kill this room? ");
657         if (yesno()==0) return;
658
659         serv_puts("KILL 1");
660         serv_gets(aaa);
661         printf("%s\n",&aaa[4]);
662         if (aaa[0]!='2') return;
663         dotgoto("_BASEROOM_",0);
664         }
665
666 void forget(void) {     /* forget the current room */
667         char cmd[256];
668
669         printf("Are you sure you want to forget this room? ");
670         if (yesno()==0) return;
671
672         serv_puts("FORG");
673         serv_gets(cmd);
674         if (cmd[0]!='2') {
675                 printf("%s\n",&cmd[4]);
676                 return;
677                 }
678
679         /* now return to the lobby */
680         dotgoto("_BASEROOM_",0);
681         }
682
683
684 /*
685  * create a new room
686  */
687 void entroom(void) {
688         char cmd[256];
689         char new_room_name[ROOMNAMELEN];
690         int new_room_type;
691         char new_room_pass[10];
692         int new_room_floor;
693         int a,b;
694
695         serv_puts("CRE8 0");
696         serv_gets(cmd);
697         
698         if (cmd[0]!='2') {
699                 printf("%s\n",&cmd[4]);
700                 return;
701                 }
702         
703         newprompt("Name for new room? ",new_room_name,ROOMNAMELEN-1);
704         if (strlen(new_room_name)==0) return;
705         for (a=0; a<strlen(new_room_name); ++a)
706                 if (new_room_name[a] == '|') new_room_name[a]='_';
707
708         new_room_floor = select_floor((int)curr_floor);
709
710         IFNEXPERT formout("roomaccess");
711         do {
712                 printf("<?>Help\n<1>Public room\n<2>Guess-name room\n");
713                 printf("<3>Passworded room\n<4>Invitation-only room\n");
714                 printf("Enter room type: ");
715                 do {
716                         b=inkey();
717                         } while (((b<'1')||(b>'4')) && (b!='?'));
718                 if (b=='?') {
719                         printf("?\n");
720                         formout("roomaccess");
721                         }
722                 } while ((b<'1')||(b>'4'));
723         b=b-48;
724         printf("%d\n",b);
725         new_room_type = b - 1;
726         if (new_room_type==2) {
727                 newprompt("Enter a room password: ",new_room_pass,9);
728                 for (a=0; a<strlen(new_room_pass); ++a)
729                         if (new_room_pass[a] == '|') new_room_pass[a]='_';
730                 }
731         else strcpy(new_room_pass,"");
732
733         printf("\042%s\042, a",new_room_name);
734         if (b==1) printf(" public room.");
735         if (b==2) printf(" guess-name room.");
736         if (b==3) printf(" passworded room, password: %s",new_room_pass);
737         if (b==4) printf("n invitation-only room.");
738         printf("\nInstall it? (y/n) : ");
739         a=yesno();
740         if (a==0) return;
741
742         sprintf(cmd, "CRE8 1|%s|%d|%s|%d", new_room_name,
743                 new_room_type, new_room_pass, new_room_floor);
744         serv_puts(cmd);
745         serv_gets(cmd);
746         if (cmd[0]!='2') {
747                 printf("%s\n",&cmd[4]);
748                 return;
749                 }
750
751         /* command succeeded... now GO to the new room! */
752         dotgoto(new_room_name,0);
753         }
754
755
756
757 void readinfo(void) {   /* read info file for current room */
758         char cmd[256];
759         
760         sprintf(cmd,"RINF");
761         serv_puts(cmd);
762         serv_gets(cmd);
763
764         if (cmd[0]!='1') return;
765
766         fmout(screenwidth,NULL,
767                 ((userflags & US_PAGINATOR) ? 1 : 0),
768                 screenheight,0,1);
769         }
770
771
772 /*
773  * <W>ho knows room...
774  */
775 void whoknows(void) {
776         char buf[256];
777         serv_puts("WHOK");
778         serv_gets(buf);
779         if (buf[0]!='1') {
780                 printf("%s\n",&buf[5]);
781                 return;
782                 }
783         sigcaught = 0;
784         sttybbs(SB_YES_INTR);
785         while (serv_gets(buf), strncmp(buf,"000",3)) {
786                 if (sigcaught==0) printf("%s\n",buf);
787                 }
788         sttybbs(SB_NO_INTR);
789         }
790
791
792 void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd)
793 {
794         FILE *fp;
795         char cmd[256];
796         int b,cksum,editor_exit;
797
798
799         if (strlen(editor_path)==0) {
800                 printf("Do you wish to re-enter %s? ",desc);
801                 if (yesno()==0) return;
802                 }
803
804         fp = fopen(temp,"w");
805         fclose(fp);
806
807         serv_puts(check_cmd);
808         serv_gets(cmd);
809         if (cmd[0]!='2') {
810                 printf("%s\n",&cmd[4]);
811                 return;
812                 }
813
814         if (strlen(editor_path)>0) {
815                 serv_puts(read_cmd);
816                 serv_gets(cmd);
817                 if (cmd[0]=='1') {
818                         fp = fopen(temp,"w");
819                         while (serv_gets(cmd), strcmp(cmd,"000")) {
820                                 fprintf(fp,"%s\n",cmd);
821                                 }
822                         fclose(fp);
823                         }
824                 }
825
826         cksum = file_checksum(temp);
827
828         if (strlen(editor_path)>0) {
829                 editor_pid=fork();
830                 if (editor_pid==0) {
831                         chmod(temp,0600);
832                         sttybbs(SB_RESTORE);
833                         execlp(editor_path,editor_path,temp,NULL);
834                         exit(1);
835                         }
836                 if (editor_pid>0) do {
837                         editor_exit = 0;
838                         b=wait(&editor_exit);
839                         } while((b!=editor_pid)&&(b>=0));
840                 editor_pid = (-1);
841                 printf("Executed %s\n", editor_path);
842                 sttybbs(0);
843                 }
844         else {
845                 printf("Entering %s.  ",desc);
846                 printf("Press return twice when finished.\n");
847                 fp=fopen(temp,"r+");
848                 citedit(fp,0);
849                 fclose(fp);
850                 }
851
852         if (file_checksum(temp) == cksum) {
853                 printf("*** Aborted.\n");
854                 }
855
856         else {
857                 serv_puts(write_cmd);
858                 serv_gets(cmd);
859                 if (cmd[0]!='4') {
860                         printf("%s\n",&cmd[4]);
861                         return;
862                         }
863
864                 fp=fopen(temp,"r");
865                 while (fgets(cmd,255,fp)!=NULL) {
866                         cmd[strlen(cmd)-1] = 0;
867                         serv_puts(cmd);
868                         }
869                 fclose(fp);
870                 serv_puts("000");
871                 }
872
873         unlink(temp);
874         }
875
876
877 void enterinfo(void) {          /* edit info file for current room */
878         do_edit("the Info file for this room","RINF","EINF 0","EINF 1");
879         }
880
881 void enter_bio(void) {
882         char cmd[256];
883         sprintf(cmd,"RBIO %s",fullname);
884         do_edit("your Bio",cmd,"NOOP","EBIO");
885         }
886
887 /*
888  * create a new floor
889  */
890 void create_floor(void) {
891         char buf[256];
892         char newfloorname[256];
893
894         serv_puts("CFLR xx|0");
895         serv_gets(buf);
896         if (buf[0]!='2') {
897                 printf("%s\n",&buf[4]);
898                 return;
899                 }
900
901         newprompt("Name for new floor: ",newfloorname,255);
902         sprintf(buf,"CFLR %s|1",newfloorname);
903         serv_puts(buf);
904         serv_gets(buf);
905         if (buf[0]=='2') {
906                 printf("Floor has been created.\n");
907                 }
908         else {
909                 printf("%s\n",&buf[4]);
910                 }
911         }
912
913 /*
914  * edit the current floor
915  */
916 void edit_floor(void) {
917         char buf[256];
918
919         if (floorlist[(int)curr_floor][0]==0) load_floorlist();
920         strprompt("New floor name",&floorlist[(int)curr_floor][0],255);
921         sprintf(buf,"EFLR %d|%s",curr_floor,&floorlist[(int)curr_floor][0]);
922         serv_puts(buf);
923         serv_gets(buf);
924         printf("%s\n",&buf[4]);
925         load_floorlist();
926         }
927
928
929
930
931 /*
932  * kill the current floor 
933  */
934 void kill_floor(void) {
935         int floornum_to_delete,a;
936         char buf[256];
937
938         if (floorlist[(int)curr_floor][0]==0) load_floorlist();
939         do {
940                 floornum_to_delete = (-1);
941                 printf("(Press return to abort)\n");
942                 newprompt("Delete which floor? ",buf,255);
943                 if (strlen(buf)==0) return;
944                 for (a=0; a<128; ++a)
945                         if (!strucmp(&floorlist[a][0],buf))
946                                 floornum_to_delete = a;
947                 if (floornum_to_delete < 0) {
948                         printf("No such floor.  Select one of:\n");
949                         for (a=0; a<128; ++a)
950                                 if (floorlist[a][0]!=0)
951                                         printf("%s\n",&floorlist[a][0]);
952                         }
953                 } while (floornum_to_delete < 0);
954         sprintf(buf,"KFLR %d|1",floornum_to_delete);
955         serv_puts(buf);
956         serv_gets(buf);
957         printf("%s\n",&buf[4]);
958         }