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