1 /* Citadel/UX room-oriented routines */
10 #include <sys/types.h>
16 #define IFEXPERT if (userflags&US_EXPERT)
17 #define IFNEXPERT if ((userflags&US_EXPERT)==0)
18 #define IFAIDE if (axlevel>=6)
19 #define IFNAIDE if (axlevel<6)
45 extern unsigned room_flags;
46 extern char room_name[];
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[];
55 extern char sigcaught;
56 extern char floor_mode;
57 extern char curr_floor;
64 extern char floorlist[128][256];
67 void load_floorlist() {
71 for (a=0; a<128; ++a) floorlist[a][0] = 0;
76 strcpy(floorlist[0],"Main Floor");
79 while (serv_gets(buf), strcmp(buf,"000")) {
80 extract(floorlist[extract_int(buf,0)],buf,1);
92 if (buf[0]!='1') return;
96 while (serv_gets(buf), strcmp(buf,"000")) if (sigcaught==0) {
97 extract(rmname,buf,0);
98 if ((c + strlen(rmname) + 4) > screenwidth) {
102 f = extract_int(buf,1);
103 if (f & QR_PRIVATE) {
110 if ((f & QR_DIRECTORY) && (f & QR_NETWORK)) printf("} ");
111 else if (f & QR_DIRECTORY) printf("] ");
112 else if (f & QR_NETWORK) printf(") ");
114 c = c + strlen(rmname) + 3;
121 void list_other_floors() {
125 for (a=0; a<128; ++a) if ((strlen(floorlist[a])>0)&&(a!=curr_floor)) {
126 if ((c + strlen(floorlist[a]) + 4) > screenwidth) {
130 printf("%s: ",floorlist[a]);
131 c = c + strlen(floorlist[a]) + 3;
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.
140 void knrooms(kn_floor_mode)
147 if (kn_floor_mode == 0) {
149 printf("\n Rooms with unread messages:\n");
152 printf("\n\n No unseen messages in:\n");
157 if (kn_floor_mode == 1) {
159 printf("\n Rooms with unread messages on %s:\n",
160 floorlist[(int)curr_floor]);
161 sprintf(buf,"LKRN %d",curr_floor);
164 printf("\n\n Rooms with no new messages on %s:\n",
165 floorlist[(int)curr_floor]);
166 sprintf(buf,"LKRO %d",curr_floor);
169 printf("\n\n Other floors:\n");
174 if (kn_floor_mode == 2) {
175 for (a=0; a<128; ++a) if (floorlist[a][0]!=0) {
177 printf("\n Rooms on %s:\n",floorlist[a]);
178 sprintf(buf,"LKRA %d",a);
185 IFNEXPERT hit_any_key();
189 void listzrooms() { /* list public forgotten rooms */
191 printf("\n Forgotten public rooms:\n");
195 IFNEXPERT hit_any_key();
199 int set_room_attr(ibuf,prompt,sbit)
205 printf("%s [%s]? ",prompt,((ibuf&sbit) ? "Yes":"No"));
206 a=yesno_d(ibuf&sbit);
208 if (!a) ibuf=(ibuf^sbit);
215 * Select a floor (used in several commands)
216 * The supplied argument is the 'default' floor number.
217 * This function returns the selected floor number.
219 int select_floor(rfloor)
224 if (floor_mode == 1) {
225 if (floorlist[(int)curr_floor][0]==0) load_floorlist();
229 strcpy(floorstr,&floorlist[rfloor][0]);
230 strprompt("Which floor",floorstr,256);
231 for (a=0; a<128; ++a) {
232 if (!strucmp(floorstr,&floorlist[a][0]))
234 if ((newfloor<0)&&(!struncmp(floorstr,
235 &floorlist[a][0],strlen(floorstr))))
237 if ((newfloor<0)&&(pattern(&floorlist[a][0],
238 floorstr)>=0)) newfloor = a;
241 printf("\n One of:\n");
242 for (a=0; a<128; ++a)
243 if (floorlist[a][0]!=0)
247 } while(newfloor < 0);
257 * .<A>ide <E>dit room
259 void editthisroom() {
272 printf("%s\n",&buf[4]);
276 extract(rname,&buf[4],0);
277 extract(rpass,&buf[4],1);
278 extract(rdir, &buf[4],2);
279 rflags = extract_int(&buf[4],3);
280 rfloor = extract_int(&buf[4],4);
285 if (buf[0]=='2') strcpy(raide,&buf[4]);
286 else strcpy(raide,"");
287 if (strlen(raide)==0) strcpy(raide,"none");
289 strprompt("Room name",rname,19);
291 rfloor = select_floor(rfloor);
292 rflags = set_room_attr(rflags,"Private room",QR_PRIVATE);
293 if (rflags & QR_PRIVATE)
294 rflags = set_room_attr(rflags,
295 "Accessible by guessing room name",QR_GUESSNAME);
297 /* if it's public, clear the privacy classes */
298 if ((rflags & QR_PRIVATE)==0) {
299 if (rflags & QR_GUESSNAME) rflags = rflags - QR_GUESSNAME;
300 if (rflags & QR_PASSWORDED) rflags = rflags - QR_PASSWORDED;
303 /* if it's private, choose the privacy classes */
304 if ( (rflags & QR_PRIVATE)
305 && ( (rflags & QR_GUESSNAME) == 0) ) {
306 rflags = set_room_attr(rflags,
307 "Accessible by entering a password",QR_PASSWORDED);
309 if ( (rflags & QR_PRIVATE)
310 && ((rflags&QR_PASSWORDED)==QR_PASSWORDED) ) {
311 strprompt("Room password",rpass,9);
314 if ((rflags&QR_PRIVATE)==QR_PRIVATE) {
315 printf("Cause current users to forget room [No] ? ");
316 if (yesno_d(0)==1) rbump = 1;
319 rflags = set_room_attr(rflags,"Preferred users only",QR_PREFONLY);
320 rflags = set_room_attr(rflags,"Read-only room",QR_READONLY);
321 rflags = set_room_attr(rflags,"Directory room",QR_DIRECTORY);
322 rflags = set_room_attr(rflags,"Permanent room",QR_PERMANENT);
323 if (rflags & QR_DIRECTORY) {
324 strprompt("Directory name",rdir,14);
325 rflags = set_room_attr(rflags,"Uploading allowed",QR_UPLOAD);
326 rflags = set_room_attr(rflags,"Downloading allowed",
328 rflags = set_room_attr(rflags,"Visible directory",QR_VISDIR);
330 rflags = set_room_attr(rflags,"Network shared room",QR_NETWORK);
331 rflags = set_room_attr(rflags,
332 "Automatically make all messages anonymous",QR_ANONONLY);
333 if ( (rflags & QR_ANONONLY) == 0) {
334 rflags = set_room_attr(rflags,
335 "Ask users whether to make messages anonymous",
340 strprompt("Room aide (or 'none')",raide,29);
341 if (!strucmp(raide,"none")) {
346 sprintf(buf,"QUSR %s",raide);
349 if (buf[0]!='2') printf("%s\n",&buf[4]);
351 } while(buf[0]!='2');
353 if (!strucmp(raide,"none")) strcpy(raide,"");
355 printf("Save changes (y/n)? ");
357 sprintf(buf,"SETR %s|%s|%s|%d|%d|%d",
358 rname,rpass,rdir,rflags,rbump,rfloor);
361 printf("%s\n",&buf[4]);
362 sprintf(buf,"SETA %s",raide);
365 if (buf[0]=='2') dotgoto(rname,2);
371 * un-goto the previous room
376 if (!strcmp(ugname,"")) return;
377 sprintf(buf,"GOTO %s",ugname);
381 printf("%s\n",&buf[4]);
384 sprintf(buf,"SLRP %ld",uglsn);
387 if (buf[0]!='2') printf("%s\n",&buf[4]);
395 * download() - download a file or files. The argument passed to this
396 * function determines which protocol to use.
402 - 0 = paginate, 1 = xmodem, 2 = raw, 3 = ymodem, 4 = zmodem, 5 = save
409 long total_bytes = 0L;
410 long transmitted_bytes = 0L;
419 if ((room_flags & QR_DOWNLOAD) == 0) {
420 printf("*** You cannot download from this room.\n");
424 newprompt("Enter filename: ",filename,255);
426 sprintf(buf,"OPEN %s",filename);
430 printf("%s\n",&buf[4]);
433 total_bytes = extract_long(&buf[4],0);
436 /* Here's the code for simply transferring the file to the client,
437 * for folks who have their own clientware. It's a lot simpler than
438 * the [XYZ]modem code below...
441 printf("Enter the name of the directory to save '%s'\n",
443 printf("to, or press return for the current directory.\n");
444 newprompt("Directory: ",dbuf,256);
445 if (strlen(dbuf)==0) strcpy(dbuf,".");
447 strcat(dbuf,filename);
449 savefp = fopen(dbuf,"w");
450 if (savefp == NULL) {
451 printf("Cannot open '%s': %s\n",dbuf,strerror(errno));
452 /* close the download file at the server */
456 printf("%s\n",&buf[4]);
460 progress(0,total_bytes);
461 while ( (transmitted_bytes < total_bytes) && (broken == 0) ) {
462 bb = total_bytes - transmitted_bytes;
463 aa = ((bb < 4096) ? bb : 4096);
464 sprintf(buf,"READ %ld|%ld",transmitted_bytes,aa);
468 printf("%s\n",&buf[4]);
471 packet = extract_int(&buf[4],0);
472 serv_read(dbuf,packet);
473 if (fwrite(dbuf,packet,1,savefp) < 1) broken = 1;
474 transmitted_bytes = transmitted_bytes + (long)packet;
475 progress(transmitted_bytes,total_bytes);
478 /* close the download file at the server */
482 printf("%s\n",&buf[4]);
490 sprintf(buf,"mkfifo %s/%s",tempdir,filename);
492 sprintf(buf,"mknod %s/%s p",tempdir,filename);
496 /* We do the remainder of this function as a separate process in
497 * order to allow recovery if the transfer is aborted. If the
498 * file transfer program aborts, the first child process receives a
499 * "broken pipe" signal and aborts. We *should* be able to catch
500 * this condition with signal(), but it doesn't seem to work on all
505 /* wait for the download to finish */
506 while (wait(&b)!=a) ;;
508 /* close the download file at the server */
512 printf("%s\n",&buf[4]);
514 /* clean up the temporary directory */
519 sprintf(buf,"%s/%s",tempdir,filename); /* full pathname */
521 /* The next fork() creates a second child process that is used for
522 * the actual file transfer program (usually sz).
525 if (proto_pid == 0) {
528 signal(SIGINT,SIG_DFL);
529 signal(SIGQUIT,SIG_DFL);
530 sprintf(dbuf,"SHELL=/dev/null; export SHELL; TERM=dumb; export TERM; exec more -d <%s",buf);
536 signal(SIGINT,SIG_DFL);
537 signal(SIGQUIT,SIG_DFL);
538 if (proto==1) execlp("sx","sx",buf,NULL);
539 if (proto==2) execlp("cat","cat",buf,NULL);
540 if (proto==3) execlp("sb","sb",buf,NULL);
541 if (proto==4) execlp("sz","sz",buf,NULL);
542 execlp("cat","cat",buf,NULL);
546 tpipe = fopen(buf,"w");
548 while ( (transmitted_bytes < total_bytes) && (broken == 0) ) {
549 bb = total_bytes - transmitted_bytes;
550 aa = ((bb < 4096) ? bb : 4096);
551 sprintf(buf,"READ %ld|%ld",transmitted_bytes,aa);
555 printf("%s\n",&buf[4]);
558 packet = extract_int(&buf[4],0);
559 serv_read(dbuf,packet);
560 if (fwrite(dbuf,packet,1,tpipe) < 1) broken = 1;
561 transmitted_bytes = transmitted_bytes + (long)packet;
563 if (tpipe!=NULL) fclose(tpipe);
565 /* Hang out and wait for the file transfer program to finish */
566 while (wait(&a) != proto_pid) ;;
570 exit(0); /* transfer control back to the main program */
575 * read directory of this room
586 printf("%s\n",&buf[4]);
590 extract(comment,&buf[4],0);
591 extract(flnm,&buf[4],1);
592 printf("\nDirectory of %s on %s\n",flnm,comment);
593 printf("-----------------------\n");
594 while (serv_gets(buf), strcmp(buf,"000")) {
597 extract(comment,buf,2);
598 if (strlen(flnm)<=14)
599 printf("%-14s %8s %s\n",flnm,flsz,comment);
601 printf("%s\n%14s %8s %s\n",flnm,"",flsz,comment);
607 * add a user to a private room
610 char aaa[31],bbb[256];
612 if ((room_flags & QR_PRIVATE)==0) {
613 printf("This is not a private room.\n");
617 newprompt("Name of user? ",aaa,30);
618 if (aaa[0]==0) return;
620 sprintf(bbb,"INVT %s",aaa);
623 printf("%s\n",&bbb[4]);
628 * kick a user out of a room
631 char aaa[31],bbb[256];
633 if ((room_flags & QR_PRIVATE)==0) {
634 printf("Note: this is not a private room. Kicking a user ");
635 printf("out of this room will only\nhave the same effect ");
636 printf("as if they <Z>apped the room.\n\n");
639 newprompt("Name of user? ",aaa,30);
640 if (aaa[0]==0) return;
642 sprintf(bbb,"KICK %s",aaa);
645 printf("%s\n",&bbb[4]);
650 * aide command: kill the current room
658 printf("%s\n",&aaa[4]);
662 printf("Are you sure you want to kill this room? ");
663 if (yesno()==0) return;
667 printf("%s\n",&aaa[4]);
668 if (aaa[0]!='2') return;
669 dotgoto("_BASEROOM_",0);
672 void forget() { /* forget the current room */
675 printf("Are you sure you want to forget this room? ");
676 if (yesno()==0) return;
681 printf("%s\n",&cmd[4]);
685 /* now return to the lobby */
686 dotgoto("_BASEROOM_",0);
695 char new_room_name[20];
697 char new_room_pass[10];
705 printf("%s\n",&cmd[4]);
709 newprompt("Name for new room? ",new_room_name,19);
710 if (strlen(new_room_name)==0) return;
711 for (a=0; a<strlen(new_room_name); ++a)
712 if (new_room_name[a] == '|') new_room_name[a]='_';
714 new_room_floor = select_floor((int)curr_floor);
716 IFNEXPERT formout("roomaccess");
718 printf("<?>Help\n<1>Public room\n<2>Guess-name room\n");
719 printf("<3>Passworded room\n<4>Invitation-only room\n");
720 printf("Enter room type: ");
723 } while (((b<'1')||(b>'4')) && (b!='?'));
726 formout("roomaccess");
728 } while ((b<'1')||(b>'4'));
731 new_room_type = b - 1;
732 if (new_room_type==2) {
733 newprompt("Enter a room password: ",new_room_pass,9);
734 for (a=0; a<strlen(new_room_pass); ++a)
735 if (new_room_pass[a] == '|') new_room_pass[a]='_';
737 else strcpy(new_room_pass,"");
739 printf("\042%s\042, a",new_room_name);
740 if (b==1) printf(" public room.");
741 if (b==2) printf(" guess-name room.");
742 if (b==3) printf(" passworded room, password: %s",new_room_pass);
743 if (b==4) printf("n invitation-only room.");
744 printf("\nInstall it? (y/n) : ");
748 sprintf(cmd, "CRE8 1|%s|%d|%s|%d", new_room_name,
749 new_room_type, new_room_pass, new_room_floor);
753 printf("%s\n",&cmd[4]);
757 /* command succeeded... now GO to the new room! */
758 dotgoto(new_room_name,0);
763 void readinfo() { /* read info file for current room */
770 if (cmd[0]!='1') return;
772 fmout(screenwidth,NULL,
773 ((userflags & US_PAGINATOR) ? 1 : 0),
779 * <W>ho knows room...
786 printf("%s\n",&buf[5]);
790 sttybbs(SB_YES_INTR);
791 while (serv_gets(buf), strncmp(buf,"000",3)) {
792 if (sigcaught==0) printf("%s\n",buf);
798 void do_edit(desc,read_cmd,check_cmd,write_cmd)
806 int b,cksum,editor_exit;
809 if (strlen(editor_path)==0) {
810 printf("Do you wish to re-enter %s? ",desc);
811 if (yesno()==0) return;
814 fp = fopen(temp,"w");
817 serv_puts(check_cmd);
820 printf("%s\n",&cmd[4]);
824 if (strlen(editor_path)>0) {
828 fp = fopen(temp,"w");
829 while (serv_gets(cmd), strcmp(cmd,"000")) {
830 fprintf(fp,"%s\n",cmd);
836 cksum = file_checksum(temp);
838 if (strlen(editor_path)>0) {
843 execlp(editor_path,editor_path,temp,NULL);
846 if (editor_pid>0) do {
848 b=wait(&editor_exit);
849 } while((b!=editor_pid)&&(b>=0));
851 printf("Executed %s\n", editor_path);
855 printf("Entering %s. ",desc);
856 printf("Press return twice when finished.\n");
862 if (file_checksum(temp) == cksum) {
863 printf("*** Aborted.\n");
867 serv_puts(write_cmd);
870 printf("%s\n",&cmd[4]);
875 while (fgets(cmd,255,fp)!=NULL) {
876 cmd[strlen(cmd)-1] = 0;
887 void enterinfo() { /* edit info file for current room */
888 do_edit("the Info file for this room","RINF","EINF 0","EINF 1");
893 sprintf(cmd,"RBIO %s",fullname);
894 do_edit("your Bio",cmd,"NOOP","EBIO");
900 void create_floor() {
902 char newfloorname[256];
904 serv_puts("CFLR xx|0");
907 printf("%s\n",&buf[4]);
911 newprompt("Name for new floor: ",newfloorname,255);
912 sprintf(buf,"CFLR %s|1",newfloorname);
916 printf("Floor has been created.\n");
919 printf("%s\n",&buf[4]);
924 * edit the current floor
929 if (floorlist[(int)curr_floor][0]==0) load_floorlist();
930 strprompt("New floor name",&floorlist[(int)curr_floor][0],255);
931 sprintf(buf,"EFLR %d|%s",curr_floor,&floorlist[(int)curr_floor][0]);
934 printf("%s\n",&buf[4]);
942 * kill the current floor
945 int floornum_to_delete,a;
948 if (floorlist[(int)curr_floor][0]==0) load_floorlist();
950 floornum_to_delete = (-1);
951 printf("(Press return to abort)\n");
952 newprompt("Delete which floor? ",buf,255);
953 if (strlen(buf)==0) return;
954 for (a=0; a<128; ++a)
955 if (!strucmp(&floorlist[a][0],buf))
956 floornum_to_delete = a;
957 if (floornum_to_delete < 0) {
958 printf("No such floor. Select one of:\n");
959 for (a=0; a<128; ++a)
960 if (floorlist[a][0]!=0)
961 printf("%s\n",&floorlist[a][0]);
963 } while (floornum_to_delete < 0);
964 sprintf(buf,"KFLR %d|1",floornum_to_delete);
967 printf("%s\n",&buf[4]);