1 /* Citadel/UX room-oriented routines */
12 #include <sys/types.h>
26 #define IFNEXPERT if ((userflags&US_EXPERT)==0)
29 void sttybbs(int cmd);
30 void hit_any_key(void);
32 void strprompt(char *prompt, char *str, int len);
33 void newprompt(char *prompt, char *str, int len);
34 int struncmp(char *lstr, char *rstr, int len);
35 void dotgoto(char *towhere, int display_name);
36 void serv_read(char *buf, int bytes);
37 void formout(char *name);
39 int fmout(int width, FILE *fp, char pagin, int height, int starting_lp, char subst);
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 int checkpagin(int lp, int pagin, int height);
46 extern unsigned room_flags;
47 extern char room_name[];
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[];
56 extern char sigcaught;
57 extern char floor_mode;
58 extern char curr_floor;
65 extern char floorlist[128][256];
70 void load_floorlist(void) {
74 for (a=0; a<128; ++a) floorlist[a][0] = 0;
79 strcpy(floorlist[0],"Main Floor");
82 while (serv_gets(buf), strcmp(buf,"000")) {
83 extract(floorlist[extract_int(buf,0)],buf,1);
88 void room_tree_list(struct roomlisting *rp) {
90 char rmname[ROOMNAMELEN];
98 if (rp->lnext != NULL) {
99 room_tree_list(rp->lnext);
102 if (sigcaught == 0) {
103 strcpy(rmname, rp->rlname);
105 if ((c + strlen(rmname) + 4) > screenwidth) {
107 /* line break, check the paginator */
109 knlinecount = knlinecount + 1;
110 knlinecount = checkpagin(knlinecount,
111 ((userflags & US_PAGINATOR) ? 1 : 0),
116 if (f & QR_MAILBOX) {
117 color(BRIGHT_YELLOW);
119 else if (f & QR_PRIVATE) {
126 if ((f & QR_DIRECTORY) && (f & QR_NETWORK)) printf("} ");
127 else if (f & QR_DIRECTORY) printf("] ");
128 else if (f & QR_NETWORK) printf(") ");
130 c = c + strlen(rmname) + 3;
133 if (rp->rnext != NULL) {
134 room_tree_list(rp->rnext);
142 * Room ordering stuff (compare first by floor, then by order)
144 int rordercmp(struct roomlisting *r1, struct roomlisting *r2)
146 if ((r1==NULL)&&(r2==NULL)) return(0);
147 if (r1==NULL) return(-1);
148 if (r2==NULL) return(1);
149 if (r1->rlfloor < r2->rlfloor) return(-1);
150 if (r1->rlfloor > r2->rlfloor) return(1);
151 if (r1->rlorder < r2->rlorder) return(-1);
152 if (r1->rlorder > r2->rlorder) return(1);
158 * Common code for all room listings
160 void listrms(char *variety)
164 struct roomlisting *rl = NULL;
165 struct roomlisting *rp;
166 struct roomlisting *rs;
169 /* Ask the server for a room list */
172 if (buf[0]!='1') return;
173 while (serv_gets(buf), strcmp(buf, "000")) {
174 rp = malloc(sizeof(struct roomlisting));
175 extract(rp->rlname, buf, 0);
176 rp->rlflags = extract_int(buf, 1);
177 rp->rlfloor = extract_int(buf, 2);
178 rp->rlorder = extract_int(buf, 3);
186 else while (rp != NULL) {
187 if (rordercmp(rp, rs)<0) {
188 if (rs->lnext == NULL) {
197 if (rs->rnext == NULL) {
209 sttybbs(SB_YES_INTR);
210 room_tree_list(NULL);
217 void list_other_floors(void) {
221 for (a=0; a<128; ++a) if ((strlen(floorlist[a])>0)&&(a!=curr_floor)) {
222 if ((c + strlen(floorlist[a]) + 4) > screenwidth) {
226 printf("%s: ",floorlist[a]);
227 c = c + strlen(floorlist[a]) + 3;
233 * List known rooms. kn_floor_mode should be set to 0 for a 'flat' listing,
234 * 1 to list rooms on the current floor, or 1 to list rooms on all floors.
236 void knrooms(int kn_floor_mode)
244 if (kn_floor_mode == 0) {
246 printf("\n Rooms with unread messages:\n");
247 knlinecount = knlinecount + 2;
250 printf("\n\n No unseen messages in:\n");
251 knlinecount = knlinecount + 3;
254 knlinecount = knlinecount + 1;
257 if (kn_floor_mode == 1) {
259 printf("\n Rooms with unread messages on %s:\n",
260 floorlist[(int)curr_floor]);
261 knlinecount = knlinecount + 2;
262 sprintf(buf,"LKRN %d",curr_floor);
265 printf("\n\n Rooms with no new messages on %s:\n",
266 floorlist[(int)curr_floor]);
267 knlinecount = knlinecount + 3;
268 sprintf(buf,"LKRO %d",curr_floor);
271 printf("\n\n Other floors:\n");
272 knlinecount = knlinecount + 3;
275 knlinecount = knlinecount + 1;
278 if (kn_floor_mode == 2) {
279 for (a=0; a<128; ++a) if (floorlist[a][0]!=0) {
281 printf("\n Rooms on %s:\n",floorlist[a]);
282 knlinecount = knlinecount + 2;
283 sprintf(buf,"LKRA %d",a);
286 knlinecount = knlinecount + 1;
291 IFNEXPERT hit_any_key();
295 void listzrooms(void) { /* list public forgotten rooms */
297 printf("\n Forgotten public rooms:\n");
301 IFNEXPERT hit_any_key();
305 int set_room_attr(int ibuf, char *prompt, unsigned int sbit)
309 a = boolprompt(prompt, (ibuf&sbit));
311 if (!a) ibuf=(ibuf^sbit);
318 * Select a floor (used in several commands)
319 * The supplied argument is the 'default' floor number.
320 * This function returns the selected floor number.
322 int select_floor(int rfloor)
327 if (floor_mode == 1) {
328 if (floorlist[(int)curr_floor][0]==0) load_floorlist();
332 safestrncpy(floorstr,floorlist[rfloor],sizeof floorstr);
333 strprompt("Which floor",floorstr,256);
334 for (a=0; a<128; ++a) {
335 if (!strucmp(floorstr,&floorlist[a][0]))
337 if ((newfloor<0)&&(!struncmp(floorstr,
338 &floorlist[a][0],strlen(floorstr))))
340 if ((newfloor<0)&&(pattern(&floorlist[a][0],
341 floorstr)>=0)) newfloor = a;
344 printf("\n One of:\n");
345 for (a=0; a<128; ++a)
346 if (floorlist[a][0]!=0)
350 } while(newfloor < 0);
360 * .<A>ide <E>dit room
362 void editthisroom(void) {
363 char rname[ROOMNAMELEN];
373 int expire_value = 0;
375 /* Fetch the existing room config */
379 printf("%s\n",&buf[4]);
383 extract(rname,&buf[4],0);
384 extract(rpass,&buf[4],1);
385 extract(rdir, &buf[4],2);
386 rflags = extract_int(&buf[4],3);
387 rfloor = extract_int(&buf[4],4);
388 rorder = extract_int(&buf[4],5);
391 /* Fetch the name of the current room aide */
394 if (buf[0]=='2') safestrncpy(raide,&buf[4],sizeof raide);
395 else strcpy(raide,"");
396 if (strlen(raide)==0) strcpy(raide,"none");
398 /* Fetch the expire policy (this will silently fail on old servers,
399 * resulting in "default" policy)
401 serv_puts("GPEX room");
404 expire_mode = extract_int(&buf[4], 0);
405 expire_value = extract_int(&buf[4], 1);
408 /* Now interact with the user. */
409 strprompt("Room name",rname,ROOMNAMELEN-1);
411 rfloor = select_floor(rfloor);
412 rflags = set_room_attr(rflags,"Private room",QR_PRIVATE);
413 if (rflags & QR_PRIVATE)
414 rflags = set_room_attr(rflags,
415 "Accessible by guessing room name",QR_GUESSNAME);
417 /* if it's public, clear the privacy classes */
418 if ((rflags & QR_PRIVATE)==0) {
419 if (rflags & QR_GUESSNAME) rflags = rflags - QR_GUESSNAME;
420 if (rflags & QR_PASSWORDED) rflags = rflags - QR_PASSWORDED;
423 /* if it's private, choose the privacy classes */
424 if ( (rflags & QR_PRIVATE)
425 && ( (rflags & QR_GUESSNAME) == 0) ) {
426 rflags = set_room_attr(rflags,
427 "Accessible by entering a password",QR_PASSWORDED);
429 if ( (rflags & QR_PRIVATE)
430 && ((rflags&QR_PASSWORDED)==QR_PASSWORDED) ) {
431 strprompt("Room password",rpass,9);
434 if ((rflags&QR_PRIVATE)==QR_PRIVATE) {
435 rbump = boolprompt("Cause current users to forget room", 0);
438 rflags = set_room_attr(rflags,"Preferred users only",QR_PREFONLY);
439 rflags = set_room_attr(rflags,"Read-only room",QR_READONLY);
440 rflags = set_room_attr(rflags,"Directory room",QR_DIRECTORY);
441 rflags = set_room_attr(rflags,"Permanent room",QR_PERMANENT);
442 if (rflags & QR_DIRECTORY) {
443 strprompt("Directory name",rdir,14);
444 rflags = set_room_attr(rflags,"Uploading allowed",QR_UPLOAD);
445 rflags = set_room_attr(rflags,"Downloading allowed",
447 rflags = set_room_attr(rflags,"Visible directory",QR_VISDIR);
449 rflags = set_room_attr(rflags,"Network shared room",QR_NETWORK);
450 rflags = set_room_attr(rflags,
451 "Automatically make all messages anonymous",QR_ANONONLY);
452 if ( (rflags & QR_ANONONLY) == 0) {
453 rflags = set_room_attr(rflags,
454 "Ask users whether to make messages anonymous",
457 rorder = intprompt("Listing order", rorder, 1, 127);
459 /* Ask about the room aide */
461 strprompt("Room aide (or 'none')",raide,29);
462 if (!strucmp(raide,"none")) {
467 snprintf(buf,sizeof buf,"QUSR %s",raide);
470 if (buf[0]!='2') printf("%s\n",&buf[4]);
472 } while(buf[0]!='2');
474 if (!strucmp(raide,"none")) strcpy(raide,"");
477 /* Angels and demons dancing in my head... */
479 sprintf(buf, "%d", expire_mode);
480 strprompt("Message expire policy (? for list)", buf, 1);
483 printf("0. Use the default for this floor\n");
484 printf("1. Never automatically expire messages\n");
485 printf("2. Expire by message count\n");
486 printf("3. Expire by message age\n");
488 } while((buf[0]<48)||(buf[0]>51));
489 expire_mode = buf[0] - 48;
491 /* ...lunatics and monsters underneath my bed */
492 if (expire_mode == 2) {
493 sprintf(buf, "%d", expire_value);
494 strprompt("Keep how many messages online?", buf, 10);
495 expire_value = atol(buf);
498 if (expire_mode == 3) {
499 sprintf(buf, "%d", expire_value);
500 strprompt("Keep messages for how many days?", buf, 10);
501 expire_value = atol(buf);
504 /* Give 'em a chance to change their minds */
505 printf("Save changes (y/n)? ");
508 snprintf(buf,sizeof buf,"SETA %s",raide);
511 if (buf[0]!='2') printf("%s\n",&buf[4]);
513 snprintf(buf, sizeof buf, "SPEX room|%d|%d",
514 expire_mode, expire_value);
518 snprintf(buf,sizeof buf,"SETR %s|%s|%s|%d|%d|%d|%d",
519 rname,rpass,rdir,rflags,rbump,rfloor,rorder);
522 printf("%s\n",&buf[4]);
523 if (buf[0]=='2') dotgoto(rname,2);
529 * un-goto the previous room
534 if (!strcmp(ugname,"")) return;
535 snprintf(buf,sizeof buf,"GOTO %s",ugname);
539 printf("%s\n",&buf[4]);
542 sprintf(buf,"SLRP %ld",uglsn);
545 if (buf[0]!='2') printf("%s\n",&buf[4]);
546 safestrncpy(buf,ugname,sizeof buf);
552 /* Here's the code for simply transferring the file to the client,
553 * for folks who have their own clientware. It's a lot simpler than
554 * the [XYZ]modem code below...
555 * (This function assumes that a download file is already open on the server)
557 void download_to_local_disk(char *supplied_filename, long total_bytes)
561 long transmitted_bytes = 0L;
568 strcpy(filename, supplied_filename);
569 if (strlen(filename)==0) {
570 newprompt("Filename: ", filename, 250);
573 printf("Enter the name of the directory to save '%s'\n",
575 printf("to, or press return for the current directory.\n");
576 newprompt("Directory: ",dbuf,256);
577 if (strlen(dbuf)==0) strcpy(dbuf,".");
579 strcat(dbuf,filename);
581 savefp = fopen(dbuf,"w");
582 if (savefp == NULL) {
583 printf("Cannot open '%s': %s\n",dbuf,strerror(errno));
584 /* close the download file at the server */
588 printf("%s\n",&buf[4]);
592 progress(0,total_bytes);
593 while ( (transmitted_bytes < total_bytes) && (broken == 0) ) {
594 bb = total_bytes - transmitted_bytes;
595 aa = ((bb < 4096) ? bb : 4096);
596 sprintf(buf,"READ %ld|%ld",transmitted_bytes,aa);
600 printf("%s\n",&buf[4]);
603 packet = extract_int(&buf[4],0);
604 serv_read(dbuf,packet);
605 if (fwrite(dbuf,packet,1,savefp) < 1) broken = 1;
606 transmitted_bytes = transmitted_bytes + (long)packet;
607 progress(transmitted_bytes,total_bytes);
610 /* close the download file at the server */
614 printf("%s\n",&buf[4]);
621 * download() - download a file or files. The argument passed to this
622 * function determines which protocol to use.
623 * proto - 0 = paginate, 1 = xmodem, 2 = raw, 3 = ymodem, 4 = zmodem, 5 = save
625 void download(int proto)
630 char transmit_cmd[256];
631 long total_bytes = 0L;
633 long transmitted_bytes = 0L;
639 if ((room_flags & QR_DOWNLOAD) == 0) {
640 printf("*** You cannot download from this room.\n");
644 newprompt("Enter filename: ",filename,255);
646 snprintf(buf,sizeof buf,"OPEN %s",filename);
650 printf("%s\n",&buf[4]);
653 total_bytes = extract_long(&buf[4],0);
655 /* Save to local disk, for folks with their own copy of the client */
657 download_to_local_disk(filename, total_bytes);
661 /* Meta-download for public clients */
662 printf("Fetching file from Citadel server...\n");
663 mkdir(tempdir, 0700);
664 snprintf(tempname, sizeof tempname, "%s/%s", tempdir, filename);
665 tpipe = fopen(tempname, "wb");
666 while ( (transmitted_bytes < total_bytes) && (broken == 0) ) {
667 progress(transmitted_bytes, total_bytes);
668 bb = total_bytes - transmitted_bytes;
669 aa = ((bb < 4096) ? bb : 4096);
670 sprintf(buf,"READ %ld|%ld",transmitted_bytes,aa);
674 printf("%s\n",&buf[4]);
676 packet = extract_int(&buf[4],0);
677 serv_read(dbuf,packet);
678 if (fwrite(dbuf,packet,1,tpipe) < 1) broken = 1;
679 transmitted_bytes = transmitted_bytes + (long)packet;
682 progress(transmitted_bytes, total_bytes);
684 /* close the download file at the server */
688 printf("%s\n",&buf[4]);
691 if (proto==0) sprintf(transmit_cmd, "SHELL=/dev/null; export SHELL; TERM=dumb; export TERM; exec more -d <%s",tempname);
692 else if (proto==1) sprintf(transmit_cmd, "exec sx %s", tempname);
693 else if (proto==3) sprintf(transmit_cmd, "exec sb %s", tempname);
694 else if (proto==4) sprintf(transmit_cmd, "exec sz %s", tempname);
695 else sprintf(transmit_cmd, "exec cat %s", tempname);
698 system(transmit_cmd);
701 /* clean up the temporary directory */
708 * read directory of this room
719 pprintf("%s\n",&buf[4]);
723 extract(comment,&buf[4],0);
724 extract(flnm,&buf[4],1);
725 pprintf("\nDirectory of %s on %s\n",flnm,comment);
726 pprintf("-----------------------\n");
727 while (serv_gets(buf), strcmp(buf,"000")) {
730 extract(comment,buf,2);
731 if (strlen(flnm)<=14)
732 pprintf("%-14s %8s %s\n",flnm,flsz,comment);
734 pprintf("%s\n%14s %8s %s\n",flnm,"",flsz,comment);
740 * add a user to a private room
743 char aaa[31],bbb[256];
745 if ((room_flags & QR_PRIVATE)==0) {
746 printf("This is not a private room.\n");
750 newprompt("Name of user? ",aaa,30);
751 if (aaa[0]==0) return;
753 snprintf(bbb,sizeof bbb,"INVT %s",aaa);
756 printf("%s\n",&bbb[4]);
761 * kick a user out of a room
764 char aaa[31],bbb[256];
766 newprompt("Name of user? ",aaa,30);
767 if (aaa[0]==0) return;
769 snprintf(bbb,sizeof bbb,"KICK %s",aaa);
772 printf("%s\n",&bbb[4]);
777 * aide command: kill the current room
779 void killroom(void) {
785 printf("%s\n",&aaa[4]);
789 printf("Are you sure you want to kill this room? ");
790 if (yesno()==0) return;
794 printf("%s\n",&aaa[4]);
795 if (aaa[0]!='2') return;
796 dotgoto("_BASEROOM_",0);
799 void forget(void) { /* forget the current room */
802 printf("Are you sure you want to forget this room? ");
803 if (yesno()==0) return;
808 printf("%s\n",&cmd[4]);
812 /* now return to the lobby */
813 dotgoto("_BASEROOM_",0);
822 char new_room_name[ROOMNAMELEN];
824 char new_room_pass[10];
832 printf("%s\n",&cmd[4]);
836 newprompt("Name for new room? ",new_room_name,ROOMNAMELEN-1);
837 if (strlen(new_room_name)==0) return;
838 for (a=0; a<strlen(new_room_name); ++a)
839 if (new_room_name[a] == '|') new_room_name[a]='_';
841 new_room_floor = select_floor((int)curr_floor);
843 IFNEXPERT formout("roomaccess");
845 printf( "<?>Help\n<1>Public room\n<2>Guess-name room\n"
846 "<3>Passworded room\n<4>Invitation-only room\n"
847 "<5>Personal room\n");
848 printf("Enter room type: ");
851 } while (((b<'1')||(b>'5')) && (b!='?'));
854 formout("roomaccess");
856 } while ((b<'1')||(b>'5'));
859 new_room_type = b - 1;
860 if (new_room_type==2) {
861 newprompt("Enter a room password: ",new_room_pass,9);
862 for (a=0; a<strlen(new_room_pass); ++a)
863 if (new_room_pass[a] == '|') new_room_pass[a]='_';
865 else strcpy(new_room_pass,"");
867 printf("\042%s\042, a",new_room_name);
868 if (b==1) printf(" public room.");
869 if (b==2) printf(" guess-name room.");
870 if (b==3) printf(" passworded room, password: %s",new_room_pass);
871 if (b==4) printf("n invitation-only room.");
872 if (b==5) printf(" personal room.");
873 printf("\nInstall it? (y/n) : ");
877 snprintf(cmd, sizeof cmd, "CRE8 1|%s|%d|%s|%d", new_room_name,
878 new_room_type, new_room_pass, new_room_floor);
882 printf("%s\n",&cmd[4]);
886 /* command succeeded... now GO to the new room! */
887 dotgoto(new_room_name,0);
892 void readinfo(void) { /* read info file for current room */
899 if (cmd[0]!='1') return;
901 fmout(screenwidth,NULL,
902 ((userflags & US_PAGINATOR) ? 1 : 0),
908 * <W>ho knows room...
910 void whoknows(void) {
915 printf("%s\n",&buf[5]);
919 sttybbs(SB_YES_INTR);
920 while (serv_gets(buf), strncmp(buf,"000",3)) {
921 if (sigcaught==0) printf("%s\n",buf);
927 void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd)
931 int b,cksum,editor_exit;
934 if (strlen(editor_path)==0) {
935 printf("Do you wish to re-enter %s? ",desc);
936 if (yesno()==0) return;
939 fp = fopen(temp,"w");
942 serv_puts(check_cmd);
945 printf("%s\n",&cmd[4]);
949 if (strlen(editor_path)>0) {
953 fp = fopen(temp,"w");
954 while (serv_gets(cmd), strcmp(cmd,"000")) {
955 fprintf(fp,"%s\n",cmd);
961 cksum = file_checksum(temp);
963 if (strlen(editor_path)>0) {
968 execlp(editor_path,editor_path,temp,NULL);
971 if (editor_pid>0) do {
973 b=wait(&editor_exit);
974 } while((b!=editor_pid)&&(b>=0));
976 printf("Executed %s\n", editor_path);
980 printf("Entering %s. ",desc);
981 printf("Press return twice when finished.\n");
987 if (file_checksum(temp) == cksum) {
988 printf("*** Aborted.\n");
992 serv_puts(write_cmd);
995 printf("%s\n",&cmd[4]);
1000 while (fgets(cmd,255,fp)!=NULL) {
1001 cmd[strlen(cmd)-1] = 0;
1012 void enterinfo(void) { /* edit info file for current room */
1013 do_edit("the Info file for this room","RINF","EINF 0","EINF 1");
1016 void enter_bio(void) {
1018 snprintf(cmd,sizeof cmd,"RBIO %s",fullname);
1019 do_edit("your Bio",cmd,"NOOP","EBIO");
1023 * create a new floor
1025 void create_floor(void) {
1027 char newfloorname[256];
1029 serv_puts("CFLR xx|0");
1032 printf("%s\n",&buf[4]);
1036 newprompt("Name for new floor: ",newfloorname,255);
1037 snprintf(buf,sizeof buf,"CFLR %s|1",newfloorname);
1041 printf("Floor has been created.\n");
1044 printf("%s\n",&buf[4]);
1049 * edit the current floor
1051 void edit_floor(void) {
1053 int expire_mode = 0;
1054 int expire_value = 0;
1056 if (floorlist[(int)curr_floor][0]==0) load_floorlist();
1058 /* Fetch the expire policy (this will silently fail on old servers,
1059 * resulting in "default" policy)
1061 serv_puts("GPEX floor");
1064 expire_mode = extract_int(&buf[4], 0);
1065 expire_value = extract_int(&buf[4], 1);
1068 /* Interact with the user */
1069 strprompt("Floor name",&floorlist[(int)curr_floor][0],255);
1071 /* Angels and demons dancing in my head... */
1073 sprintf(buf, "%d", expire_mode);
1074 strprompt("Floor default essage expire policy (? for list)",
1076 if (buf[0] == '?') {
1078 printf("0. Use the system default\n");
1079 printf("1. Never automatically expire messages\n");
1080 printf("2. Expire by message count\n");
1081 printf("3. Expire by message age\n");
1083 } while((buf[0]<48)||(buf[0]>51));
1084 expire_mode = buf[0] - 48;
1086 /* ...lunatics and monsters underneath my bed */
1087 if (expire_mode == 2) {
1088 sprintf(buf, "%d", expire_value);
1089 strprompt("Keep how many messages online?", buf, 10);
1090 expire_value = atol(buf);
1093 if (expire_mode == 3) {
1094 sprintf(buf, "%d", expire_value);
1095 strprompt("Keep messages for how many days?", buf, 10);
1096 expire_value = atol(buf);
1100 snprintf(buf, sizeof buf, "SPEX floor|%d|%d",
1101 expire_mode, expire_value);
1105 snprintf(buf,sizeof buf,"EFLR %d|%s",curr_floor,
1106 &floorlist[(int)curr_floor][0]);
1109 printf("%s\n",&buf[4]);
1117 * kill the current floor
1119 void kill_floor(void) {
1120 int floornum_to_delete,a;
1123 if (floorlist[(int)curr_floor][0]==0) load_floorlist();
1125 floornum_to_delete = (-1);
1126 printf("(Press return to abort)\n");
1127 newprompt("Delete which floor? ",buf,255);
1128 if (strlen(buf)==0) return;
1129 for (a=0; a<128; ++a)
1130 if (!strucmp(&floorlist[a][0],buf))
1131 floornum_to_delete = a;
1132 if (floornum_to_delete < 0) {
1133 printf("No such floor. Select one of:\n");
1134 for (a=0; a<128; ++a)
1135 if (floorlist[a][0]!=0)
1136 printf("%s\n",&floorlist[a][0]);
1138 } while (floornum_to_delete < 0);
1139 sprintf(buf,"KFLR %d|1",floornum_to_delete);
1142 printf("%s\n",&buf[4]);