c2d76ddae4ee56eebe03db5afd6ed94cda890e10
[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[20];
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,19);
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_ANON2);
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 #ifdef USE_MKFIFO
488         sprintf(buf,"mkfifo %s/%s",tempdir,filename);
489 #else
490         sprintf(buf,"mknod %s/%s p",tempdir,filename);
491 #endif
492         system(buf);
493
494         /* We do the remainder of this function as a separate process in
495          * order to allow recovery if the transfer is aborted.  If the
496          * file transfer program aborts, the first child process receives a
497          * "broken pipe" signal and aborts.  We *should* be able to catch
498          * this condition with signal(), but it doesn't seem to work on all
499          * systems.
500          */
501         a = fork();
502         if (a!=0) {
503                 /* wait for the download to finish */
504                 while (wait(&b)!=a) ;;
505                 sttybbs(0);
506                 /* close the download file at the server */
507                 serv_puts("CLOS");
508                 serv_gets(buf);
509                 if (buf[0]!='2') {
510                         printf("%s\n",&buf[4]);
511                         }
512                 /* clean up the temporary directory */
513                 nukedir(tempdir);
514                 return;
515                 }
516
517         sprintf(buf,"%s/%s",tempdir,filename);  /* full pathname */
518
519         /* The next fork() creates a second child process that is used for
520          * the actual file transfer program (usually sz).
521          */
522         proto_pid = fork();
523         if (proto_pid == 0) {
524                 if (proto==0)  {
525                         sttybbs(0);
526                         signal(SIGINT,SIG_DFL);
527                         signal(SIGQUIT,SIG_DFL);
528                         sprintf(dbuf,"SHELL=/dev/null; export SHELL; TERM=dumb; export TERM; exec more -d <%s",buf);
529                         system(dbuf);
530                         sttybbs(SB_NO_INTR);
531                         exit(0);
532                         }
533                 sttybbs(3);
534                 signal(SIGINT,SIG_DFL);
535                 signal(SIGQUIT,SIG_DFL);
536                 if (proto==1) execlp("sx","sx",buf,NULL);
537                 if (proto==2) execlp("cat","cat",buf,NULL);
538                 if (proto==3) execlp("sb","sb",buf,NULL);
539                 if (proto==4) execlp("sz","sz",buf,NULL);
540                 execlp("cat","cat",buf,NULL);
541                 exit(1);
542                 }
543
544         tpipe = fopen(buf,"w");
545
546         while ( (transmitted_bytes < total_bytes) && (broken == 0) ) {
547                 bb = total_bytes - transmitted_bytes;
548                 aa = ((bb < 4096) ? bb : 4096);
549                 sprintf(buf,"READ %ld|%ld",transmitted_bytes,aa);
550                 serv_puts(buf);
551                 serv_gets(buf);
552                 if (buf[0]!='6') {
553                         printf("%s\n",&buf[4]);
554                         return;
555                         }
556                 packet = extract_int(&buf[4],0);
557                 serv_read(dbuf,packet);
558                 if (fwrite(dbuf,packet,1,tpipe) < 1) broken = 1;
559                 transmitted_bytes = transmitted_bytes + (long)packet;
560                 }
561         if (tpipe!=NULL) fclose(tpipe);
562
563         /* Hang out and wait for the file transfer program to finish */
564         while (wait(&a) != proto_pid) ;;
565
566
567         putc(7,stdout);
568         exit(0);        /* transfer control back to the main program */
569         }
570
571
572 /*
573  * read directory of this room
574  */
575 void roomdir(void) {
576         char flnm[256];
577         char flsz[32];
578         char comment[256];
579         char buf[256];
580
581         serv_puts("RDIR");
582         serv_gets(buf);
583         if (buf[0]!='1') {
584                 printf("%s\n",&buf[4]);
585                 return;
586                 }
587
588         extract(comment,&buf[4],0);
589         extract(flnm,&buf[4],1);
590         printf("\nDirectory of %s on %s\n",flnm,comment);
591         printf("-----------------------\n");
592         while (serv_gets(buf), strcmp(buf,"000")) {
593                 extract(flnm,buf,0);
594                 extract(flsz,buf,1);
595                 extract(comment,buf,2);
596                 if (strlen(flnm)<=14)
597                         printf("%-14s %8s %s\n",flnm,flsz,comment);
598                 else
599                         printf("%s\n%14s %8s %s\n",flnm,"",flsz,comment);
600                 }
601         }
602
603
604 /*
605  * add a user to a private room
606  */
607 void invite(void) {
608         char aaa[31],bbb[256];
609
610         if ((room_flags & QR_PRIVATE)==0) {
611                 printf("This is not a private room.\n");
612                 return;
613                 }
614
615         newprompt("Name of user? ",aaa,30);
616         if (aaa[0]==0) return;
617
618         sprintf(bbb,"INVT %s",aaa);
619         serv_puts(bbb);
620         serv_gets(bbb);
621         printf("%s\n",&bbb[4]);
622         }
623
624
625 /*
626  * kick a user out of a room
627  */
628 void kickout(void) {
629         char aaa[31],bbb[256];
630
631         if ((room_flags & QR_PRIVATE)==0) {
632                 printf("Note: this is not a private room.  Kicking a user ");
633                 printf("out of this room will only\nhave the same effect ");
634                 printf("as if they <Z>apped the room.\n\n");
635                 }
636
637         newprompt("Name of user? ",aaa,30);
638         if (aaa[0]==0) return;
639
640         sprintf(bbb,"KICK %s",aaa);
641         serv_puts(bbb);
642         serv_gets(bbb);
643         printf("%s\n",&bbb[4]);
644         }
645
646
647 /*
648  * aide command: kill the current room
649  */
650 void killroom(void) {
651         char aaa[100];
652
653         serv_puts("KILL 0");
654         serv_gets(aaa);
655         if (aaa[0]!='2') {
656                 printf("%s\n",&aaa[4]);
657                 return;
658                 }
659
660         printf("Are you sure you want to kill this room? ");
661         if (yesno()==0) return;
662
663         serv_puts("KILL 1");
664         serv_gets(aaa);
665         printf("%s\n",&aaa[4]);
666         if (aaa[0]!='2') return;
667         dotgoto("_BASEROOM_",0);
668         }
669
670 void forget(void) {     /* forget the current room */
671         char cmd[256];
672
673         printf("Are you sure you want to forget this room? ");
674         if (yesno()==0) return;
675
676         serv_puts("FORG");
677         serv_gets(cmd);
678         if (cmd[0]!='2') {
679                 printf("%s\n",&cmd[4]);
680                 return;
681                 }
682
683         /* now return to the lobby */
684         dotgoto("_BASEROOM_",0);
685         }
686
687
688 /*
689  * create a new room
690  */
691 void entroom(void) {
692         char cmd[256];
693         char new_room_name[20];
694         int new_room_type;
695         char new_room_pass[10];
696         int new_room_floor;
697         int a,b;
698
699         serv_puts("CRE8 0");
700         serv_gets(cmd);
701         
702         if (cmd[0]!='2') {
703                 printf("%s\n",&cmd[4]);
704                 return;
705                 }
706         
707         newprompt("Name for new room? ",new_room_name,19);
708         if (strlen(new_room_name)==0) return;
709         for (a=0; a<strlen(new_room_name); ++a)
710                 if (new_room_name[a] == '|') new_room_name[a]='_';
711
712         new_room_floor = select_floor((int)curr_floor);
713
714         IFNEXPERT formout("roomaccess");
715         do {
716                 printf("<?>Help\n<1>Public room\n<2>Guess-name room\n");
717                 printf("<3>Passworded room\n<4>Invitation-only room\n");
718                 printf("Enter room type: ");
719                 do {
720                         b=inkey();
721                         } while (((b<'1')||(b>'4')) && (b!='?'));
722                 if (b=='?') {
723                         printf("?\n");
724                         formout("roomaccess");
725                         }
726                 } while ((b<'1')||(b>'4'));
727         b=b-48;
728         printf("%d\n",b);
729         new_room_type = b - 1;
730         if (new_room_type==2) {
731                 newprompt("Enter a room password: ",new_room_pass,9);
732                 for (a=0; a<strlen(new_room_pass); ++a)
733                         if (new_room_pass[a] == '|') new_room_pass[a]='_';
734                 }
735         else strcpy(new_room_pass,"");
736
737         printf("\042%s\042, a",new_room_name);
738         if (b==1) printf(" public room.");
739         if (b==2) printf(" guess-name room.");
740         if (b==3) printf(" passworded room, password: %s",new_room_pass);
741         if (b==4) printf("n invitation-only room.");
742         printf("\nInstall it? (y/n) : ");
743         a=yesno();
744         if (a==0) return;
745
746         sprintf(cmd, "CRE8 1|%s|%d|%s|%d", new_room_name,
747                 new_room_type, new_room_pass, new_room_floor);
748         serv_puts(cmd);
749         serv_gets(cmd);
750         if (cmd[0]!='2') {
751                 printf("%s\n",&cmd[4]);
752                 return;
753                 }
754
755         /* command succeeded... now GO to the new room! */
756         dotgoto(new_room_name,0);
757         }
758
759
760
761 void readinfo(void) {   /* read info file for current room */
762         char cmd[256];
763         
764         sprintf(cmd,"RINF");
765         serv_puts(cmd);
766         serv_gets(cmd);
767
768         if (cmd[0]!='1') return;
769
770         fmout(screenwidth,NULL,
771                 ((userflags & US_PAGINATOR) ? 1 : 0),
772                 screenheight,0,1);
773         }
774
775
776 /*
777  * <W>ho knows room...
778  */
779 void whoknows(void) {
780         char buf[256];
781         serv_puts("WHOK");
782         serv_gets(buf);
783         if (buf[0]!='1') {
784                 printf("%s\n",&buf[5]);
785                 return;
786                 }
787         sigcaught = 0;
788         sttybbs(SB_YES_INTR);
789         while (serv_gets(buf), strncmp(buf,"000",3)) {
790                 if (sigcaught==0) printf("%s\n",buf);
791                 }
792         sttybbs(SB_NO_INTR);
793         }
794
795
796 void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd)
797 {
798         FILE *fp;
799         char cmd[256];
800         int b,cksum,editor_exit;
801
802
803         if (strlen(editor_path)==0) {
804                 printf("Do you wish to re-enter %s? ",desc);
805                 if (yesno()==0) return;
806                 }
807
808         fp = fopen(temp,"w");
809         fclose(fp);
810
811         serv_puts(check_cmd);
812         serv_gets(cmd);
813         if (cmd[0]!='2') {
814                 printf("%s\n",&cmd[4]);
815                 return;
816                 }
817
818         if (strlen(editor_path)>0) {
819                 serv_puts(read_cmd);
820                 serv_gets(cmd);
821                 if (cmd[0]=='1') {
822                         fp = fopen(temp,"w");
823                         while (serv_gets(cmd), strcmp(cmd,"000")) {
824                                 fprintf(fp,"%s\n",cmd);
825                                 }
826                         fclose(fp);
827                         }
828                 }
829
830         cksum = file_checksum(temp);
831
832         if (strlen(editor_path)>0) {
833                 editor_pid=fork();
834                 if (editor_pid==0) {
835                         chmod(temp,0600);
836                         sttybbs(SB_RESTORE);
837                         execlp(editor_path,editor_path,temp,NULL);
838                         exit(1);
839                         }
840                 if (editor_pid>0) do {
841                         editor_exit = 0;
842                         b=wait(&editor_exit);
843                         } while((b!=editor_pid)&&(b>=0));
844                 editor_pid = (-1);
845                 printf("Executed %s\n", editor_path);
846                 sttybbs(0);
847                 }
848         else {
849                 printf("Entering %s.  ",desc);
850                 printf("Press return twice when finished.\n");
851                 fp=fopen(temp,"r+");
852                 citedit(fp,0);
853                 fclose(fp);
854                 }
855
856         if (file_checksum(temp) == cksum) {
857                 printf("*** Aborted.\n");
858                 }
859
860         else {
861                 serv_puts(write_cmd);
862                 serv_gets(cmd);
863                 if (cmd[0]!='4') {
864                         printf("%s\n",&cmd[4]);
865                         return;
866                         }
867
868                 fp=fopen(temp,"r");
869                 while (fgets(cmd,255,fp)!=NULL) {
870                         cmd[strlen(cmd)-1] = 0;
871                         serv_puts(cmd);
872                         }
873                 fclose(fp);
874                 serv_puts("000");
875                 }
876
877         unlink(temp);
878         }
879
880
881 void enterinfo(void) {          /* edit info file for current room */
882         do_edit("the Info file for this room","RINF","EINF 0","EINF 1");
883         }
884
885 void enter_bio(void) {
886         char cmd[256];
887         sprintf(cmd,"RBIO %s",fullname);
888         do_edit("your Bio",cmd,"NOOP","EBIO");
889         }
890
891 /*
892  * create a new floor
893  */
894 void create_floor(void) {
895         char buf[256];
896         char newfloorname[256];
897
898         serv_puts("CFLR xx|0");
899         serv_gets(buf);
900         if (buf[0]!='2') {
901                 printf("%s\n",&buf[4]);
902                 return;
903                 }
904
905         newprompt("Name for new floor: ",newfloorname,255);
906         sprintf(buf,"CFLR %s|1",newfloorname);
907         serv_puts(buf);
908         serv_gets(buf);
909         if (buf[0]=='2') {
910                 printf("Floor has been created.\n");
911                 }
912         else {
913                 printf("%s\n",&buf[4]);
914                 }
915         }
916
917 /*
918  * edit the current floor
919  */
920 void edit_floor(void) {
921         char buf[256];
922
923         if (floorlist[(int)curr_floor][0]==0) load_floorlist();
924         strprompt("New floor name",&floorlist[(int)curr_floor][0],255);
925         sprintf(buf,"EFLR %d|%s",curr_floor,&floorlist[(int)curr_floor][0]);
926         serv_puts(buf);
927         serv_gets(buf);
928         printf("%s\n",&buf[4]);
929         load_floorlist();
930         }
931
932
933
934
935 /*
936  * kill the current floor 
937  */
938 void kill_floor(void) {
939         int floornum_to_delete,a;
940         char buf[256];
941
942         if (floorlist[(int)curr_floor][0]==0) load_floorlist();
943         do {
944                 floornum_to_delete = (-1);
945                 printf("(Press return to abort)\n");
946                 newprompt("Delete which floor? ",buf,255);
947                 if (strlen(buf)==0) return;
948                 for (a=0; a<128; ++a)
949                         if (!strucmp(&floorlist[a][0],buf))
950                                 floornum_to_delete = a;
951                 if (floornum_to_delete < 0) {
952                         printf("No such floor.  Select one of:\n");
953                         for (a=0; a<128; ++a)
954                                 if (floorlist[a][0]!=0)
955                                         printf("%s\n",&floorlist[a][0]);
956                         }
957                 } while (floornum_to_delete < 0);
958         sprintf(buf,"KFLR %d|1",floornum_to_delete);
959         serv_puts(buf);
960         serv_gets(buf);
961         printf("%s\n",&buf[4]);
962         }