1 /* Citadel/UX room-oriented routines */
11 #include <sys/types.h>
20 #define IFNEXPERT if ((userflags&US_EXPERT)==0)
23 void sttybbs(int cmd);
24 void hit_any_key(void);
26 void strprompt(char *prompt, char *str, int len);
27 void newprompt(char *prompt, char *str, int len);
28 int struncmp(char *lstr, char *rstr, int len);
29 void dotgoto(char *towhere, int display_name);
30 void serv_read(char *buf, int bytes);
31 void formout(char *name);
33 int fmout(int width, FILE *fp, char pagin, int height, int starting_lp, char subst);
34 void citedit(FILE *fp, long int base_pos);
35 void progress(long int curr, long int cmax);
36 int pattern(char *search, char *patn);
37 int file_checksum(char *filename);
38 int nukedir(char *dirname);
39 void color(int colornum);
41 extern unsigned room_flags;
42 extern char room_name[];
44 extern char tempdir[];
45 extern int editor_pid;
46 extern char editor_path[];
47 extern int screenwidth;
48 extern int screenheight;
49 extern char fullname[];
51 extern char sigcaught;
52 extern char floor_mode;
53 extern char curr_floor;
60 extern char floorlist[128][256];
63 void load_floorlist(void) {
67 for (a=0; a<128; ++a) floorlist[a][0] = 0;
72 strcpy(floorlist[0],"Main Floor");
75 while (serv_gets(buf), strcmp(buf,"000")) {
76 extract(floorlist[extract_int(buf,0)],buf,1);
81 void room_tree_list(struct roomlisting *rp) {
91 if (rp->lnext != NULL) {
92 room_tree_list(rp->lnext);
96 strcpy(rmname, rp->rlname);
98 if ((c + strlen(rmname) + 4) > screenwidth) {
102 if (f & QR_MAILBOX) {
105 else if (f & QR_PRIVATE) {
112 if ((f & QR_DIRECTORY) && (f & QR_NETWORK)) printf("} ");
113 else if (f & QR_DIRECTORY) printf("] ");
114 else if (f & QR_NETWORK) printf(") ");
116 c = c + strlen(rmname) + 3;
119 if (rp->rnext != NULL) {
120 room_tree_list(rp->rnext);
128 * Room ordering stuff (compare first by floor, then by order)
130 int rordercmp(struct roomlisting *r1, struct roomlisting *r2)
132 if ((r1==NULL)&&(r2==NULL)) return(0);
133 if (r1==NULL) return(-1);
134 if (r2==NULL) return(1);
135 if (r1->rlfloor < r2->rlfloor) return(-1);
136 if (r1->rlfloor > r2->rlfloor) return(1);
137 if (r1->rlorder < r2->rlorder) return(-1);
138 if (r1->rlorder > r2->rlorder) return(1);
144 * Common code for all room listings
146 void listrms(char *variety)
150 struct roomlisting *rl = NULL;
151 struct roomlisting *rp;
152 struct roomlisting *rs;
155 /* Ask the server for a room list */
158 if (buf[0]!='1') return;
159 while (serv_gets(buf), strcmp(buf, "000")) {
160 rp = malloc(sizeof(struct roomlisting));
161 extract(rp->rlname, buf, 0);
162 rp->rlflags = extract_int(buf, 1);
163 rp->rlfloor = extract_int(buf, 2);
164 rp->rlorder = extract_int(buf, 3);
172 else while (rp != NULL) {
173 if (rordercmp(rp, rs)<0) {
174 if (rs->lnext == NULL) {
183 if (rs->rnext == NULL) {
195 sttybbs(SB_YES_INTR);
196 room_tree_list(NULL);
203 void list_other_floors(void) {
207 for (a=0; a<128; ++a) if ((strlen(floorlist[a])>0)&&(a!=curr_floor)) {
208 if ((c + strlen(floorlist[a]) + 4) > screenwidth) {
212 printf("%s: ",floorlist[a]);
213 c = c + strlen(floorlist[a]) + 3;
219 * List known rooms. kn_floor_mode should be set to 0 for a 'flat' listing,
220 * 1 to list rooms on the current floor, or 1 to list rooms on all floors.
222 void knrooms(int kn_floor_mode)
229 if (kn_floor_mode == 0) {
231 printf("\n Rooms with unread messages:\n");
234 printf("\n\n No unseen messages in:\n");
239 if (kn_floor_mode == 1) {
241 printf("\n Rooms with unread messages on %s:\n",
242 floorlist[(int)curr_floor]);
243 sprintf(buf,"LKRN %d",curr_floor);
246 printf("\n\n Rooms with no new messages on %s:\n",
247 floorlist[(int)curr_floor]);
248 sprintf(buf,"LKRO %d",curr_floor);
251 printf("\n\n Other floors:\n");
256 if (kn_floor_mode == 2) {
257 for (a=0; a<128; ++a) if (floorlist[a][0]!=0) {
259 printf("\n Rooms on %s:\n",floorlist[a]);
260 sprintf(buf,"LKRA %d",a);
267 IFNEXPERT hit_any_key();
271 void listzrooms(void) { /* list public forgotten rooms */
273 printf("\n Forgotten public rooms:\n");
277 IFNEXPERT hit_any_key();
281 int set_room_attr(int ibuf, char *prompt, unsigned int sbit)
285 a = boolprompt(prompt, (ibuf&sbit));
287 if (!a) ibuf=(ibuf^sbit);
294 * Select a floor (used in several commands)
295 * The supplied argument is the 'default' floor number.
296 * This function returns the selected floor number.
298 int select_floor(int rfloor)
303 if (floor_mode == 1) {
304 if (floorlist[(int)curr_floor][0]==0) load_floorlist();
308 safestrncpy(floorstr,floorlist[rfloor],sizeof floorstr);
309 strprompt("Which floor",floorstr,256);
310 for (a=0; a<128; ++a) {
311 if (!strucmp(floorstr,&floorlist[a][0]))
313 if ((newfloor<0)&&(!struncmp(floorstr,
314 &floorlist[a][0],strlen(floorstr))))
316 if ((newfloor<0)&&(pattern(&floorlist[a][0],
317 floorstr)>=0)) newfloor = a;
320 printf("\n One of:\n");
321 for (a=0; a<128; ++a)
322 if (floorlist[a][0]!=0)
326 } while(newfloor < 0);
336 * .<A>ide <E>dit room
338 void editthisroom(void) {
339 char rname[ROOMNAMELEN];
349 int expire_value = 0;
351 /* Fetch the existing room config */
355 printf("%s\n",&buf[4]);
359 extract(rname,&buf[4],0);
360 extract(rpass,&buf[4],1);
361 extract(rdir, &buf[4],2);
362 rflags = extract_int(&buf[4],3);
363 rfloor = extract_int(&buf[4],4);
364 rorder = extract_int(&buf[4],5);
367 /* Fetch the name of the current room aide */
370 if (buf[0]=='2') safestrncpy(raide,&buf[4],sizeof raide);
371 else strcpy(raide,"");
372 if (strlen(raide)==0) strcpy(raide,"none");
374 /* Fetch the expire policy (this will silently fail on old servers,
375 * resulting in "default" policy)
377 serv_puts("GPEX room");
380 expire_mode = extract_int(&buf[4], 0);
381 expire_value = extract_int(&buf[4], 1);
384 /* Now interact with the user. */
385 strprompt("Room name",rname,ROOMNAMELEN-1);
387 rfloor = select_floor(rfloor);
388 rflags = set_room_attr(rflags,"Private room",QR_PRIVATE);
389 if (rflags & QR_PRIVATE)
390 rflags = set_room_attr(rflags,
391 "Accessible by guessing room name",QR_GUESSNAME);
393 /* if it's public, clear the privacy classes */
394 if ((rflags & QR_PRIVATE)==0) {
395 if (rflags & QR_GUESSNAME) rflags = rflags - QR_GUESSNAME;
396 if (rflags & QR_PASSWORDED) rflags = rflags - QR_PASSWORDED;
399 /* if it's private, choose the privacy classes */
400 if ( (rflags & QR_PRIVATE)
401 && ( (rflags & QR_GUESSNAME) == 0) ) {
402 rflags = set_room_attr(rflags,
403 "Accessible by entering a password",QR_PASSWORDED);
405 if ( (rflags & QR_PRIVATE)
406 && ((rflags&QR_PASSWORDED)==QR_PASSWORDED) ) {
407 strprompt("Room password",rpass,9);
410 if ((rflags&QR_PRIVATE)==QR_PRIVATE) {
411 rbump = boolprompt("Cause current users to forget room", 0);
414 rflags = set_room_attr(rflags,"Preferred users only",QR_PREFONLY);
415 rflags = set_room_attr(rflags,"Read-only room",QR_READONLY);
416 rflags = set_room_attr(rflags,"Directory room",QR_DIRECTORY);
417 rflags = set_room_attr(rflags,"Permanent room",QR_PERMANENT);
418 if (rflags & QR_DIRECTORY) {
419 strprompt("Directory name",rdir,14);
420 rflags = set_room_attr(rflags,"Uploading allowed",QR_UPLOAD);
421 rflags = set_room_attr(rflags,"Downloading allowed",
423 rflags = set_room_attr(rflags,"Visible directory",QR_VISDIR);
425 rflags = set_room_attr(rflags,"Network shared room",QR_NETWORK);
426 rflags = set_room_attr(rflags,
427 "Automatically make all messages anonymous",QR_ANONONLY);
428 if ( (rflags & QR_ANONONLY) == 0) {
429 rflags = set_room_attr(rflags,
430 "Ask users whether to make messages anonymous",
433 rorder = intprompt("Listing order", rorder, 1, 127);
435 /* Ask about the room aide */
437 strprompt("Room aide (or 'none')",raide,29);
438 if (!strucmp(raide,"none")) {
443 snprintf(buf,sizeof buf,"QUSR %s",raide);
446 if (buf[0]!='2') printf("%s\n",&buf[4]);
448 } while(buf[0]!='2');
450 if (!strucmp(raide,"none")) strcpy(raide,"");
453 /* Angels and demons dancing in my head... */
455 sprintf(buf, "%d", expire_mode);
456 strprompt("Message expire policy (? for list)", buf, 1);
459 printf("0. Use the default for this floor\n");
460 printf("1. Never automatically expire messages\n");
461 printf("2. Expire by message count\n");
462 printf("3. Expire by message age\n");
464 } while((buf[0]<48)||(buf[0]>51));
465 expire_mode = buf[0] - 48;
467 /* ...lunatics and monsters underneath my bed */
468 if (expire_mode == 2) {
469 sprintf(buf, "%d", expire_value);
470 strprompt("Keep how many messages online?", buf, 10);
471 expire_value = atol(buf);
474 if (expire_mode == 3) {
475 sprintf(buf, "%d", expire_value);
476 strprompt("Keep messages for how many days?", buf, 10);
477 expire_value = atol(buf);
480 /* Give 'em a chance to change their minds */
481 printf("Save changes (y/n)? ");
484 snprintf(buf,sizeof buf,"SETA %s",raide);
487 if (buf[0]!='2') printf("%s\n",&buf[4]);
489 snprintf(buf, sizeof buf, "SPEX room|%d|%d",
490 expire_mode, expire_value);
494 snprintf(buf,sizeof buf,"SETR %s|%s|%s|%d|%d|%d|%d",
495 rname,rpass,rdir,rflags,rbump,rfloor,rorder);
498 printf("%s\n",&buf[4]);
499 if (buf[0]=='2') dotgoto(rname,2);
505 * un-goto the previous room
510 if (!strcmp(ugname,"")) return;
511 snprintf(buf,sizeof buf,"GOTO %s",ugname);
515 printf("%s\n",&buf[4]);
518 sprintf(buf,"SLRP %ld",uglsn);
521 if (buf[0]!='2') printf("%s\n",&buf[4]);
522 safestrncpy(buf,ugname,sizeof buf);
528 /* Here's the code for simply transferring the file to the client,
529 * for folks who have their own clientware. It's a lot simpler than
530 * the [XYZ]modem code below...
531 * (This function assumes that a download file is already open on the server)
533 void download_to_local_disk(char *filename, long total_bytes)
537 long transmitted_bytes = 0L;
543 printf("Enter the name of the directory to save '%s'\n",
545 printf("to, or press return for the current directory.\n");
546 newprompt("Directory: ",dbuf,256);
547 if (strlen(dbuf)==0) strcpy(dbuf,".");
549 strcat(dbuf,filename);
551 savefp = fopen(dbuf,"w");
552 if (savefp == NULL) {
553 printf("Cannot open '%s': %s\n",dbuf,strerror(errno));
554 /* close the download file at the server */
558 printf("%s\n",&buf[4]);
562 progress(0,total_bytes);
563 while ( (transmitted_bytes < total_bytes) && (broken == 0) ) {
564 bb = total_bytes - transmitted_bytes;
565 aa = ((bb < 4096) ? bb : 4096);
566 sprintf(buf,"READ %ld|%ld",transmitted_bytes,aa);
570 printf("%s\n",&buf[4]);
573 packet = extract_int(&buf[4],0);
574 serv_read(dbuf,packet);
575 if (fwrite(dbuf,packet,1,savefp) < 1) broken = 1;
576 transmitted_bytes = transmitted_bytes + (long)packet;
577 progress(transmitted_bytes,total_bytes);
580 /* close the download file at the server */
584 printf("%s\n",&buf[4]);
591 * download() - download a file or files. The argument passed to this
592 * function determines which protocol to use.
593 * proto - 0 = paginate, 1 = xmodem, 2 = raw, 3 = ymodem, 4 = zmodem, 5 = save
595 void download(int proto)
600 long total_bytes = 0L;
601 long transmitted_bytes = 0L;
609 if ((room_flags & QR_DOWNLOAD) == 0) {
610 printf("*** You cannot download from this room.\n");
614 newprompt("Enter filename: ",filename,255);
616 snprintf(buf,sizeof buf,"OPEN %s",filename);
620 printf("%s\n",&buf[4]);
623 total_bytes = extract_long(&buf[4],0);
625 /* Save to local disk, for folks with their own copy of the client */
627 download_to_local_disk(filename, total_bytes);
631 /* Meta-download for public clients */
633 snprintf(buf,sizeof buf,"%s/%s",tempdir,filename);
636 /* We do the remainder of this function as a separate process in
637 * order to allow recovery if the transfer is aborted. If the
638 * file transfer program aborts, the first child process receives a
639 * "broken pipe" signal and aborts. We *should* be able to catch
640 * this condition with signal(), but it doesn't seem to work on all
645 /* wait for the download to finish */
646 while (wait(&b)!=a) ;;
648 /* close the download file at the server */
652 printf("%s\n",&buf[4]);
654 /* clean up the temporary directory */
659 snprintf(buf,sizeof buf,"%s/%s",tempdir,filename); /* full pathname */
661 /* The next fork() creates a second child process that is used for
662 * the actual file transfer program (usually sz).
665 if (proto_pid == 0) {
668 signal(SIGINT,SIG_DFL);
669 signal(SIGQUIT,SIG_DFL);
670 snprintf(dbuf,sizeof dbuf,"SHELL=/dev/null; export SHELL; TERM=dumb; export TERM; exec more -d <%s",buf);
676 signal(SIGINT,SIG_DFL);
677 signal(SIGQUIT,SIG_DFL);
678 if (proto==1) execlp("sx","sx",buf,NULL);
679 if (proto==2) execlp("cat","cat",buf,NULL);
680 if (proto==3) execlp("sb","sb",buf,NULL);
681 if (proto==4) execlp("sz","sz",buf,NULL);
682 execlp("cat","cat",buf,NULL);
686 tpipe = fopen(buf,"w");
688 while ( (transmitted_bytes < total_bytes) && (broken == 0) ) {
689 bb = total_bytes - transmitted_bytes;
690 aa = ((bb < 4096) ? bb : 4096);
691 sprintf(buf,"READ %ld|%ld",transmitted_bytes,aa);
695 printf("%s\n",&buf[4]);
698 packet = extract_int(&buf[4],0);
699 serv_read(dbuf,packet);
700 if (fwrite(dbuf,packet,1,tpipe) < 1) broken = 1;
701 transmitted_bytes = transmitted_bytes + (long)packet;
703 if (tpipe!=NULL) fclose(tpipe);
705 /* Hang out and wait for the file transfer program to finish */
706 while (wait(&a) != proto_pid) ;;
710 exit(0); /* transfer control back to the main program */
715 * read directory of this room
726 printf("%s\n",&buf[4]);
730 extract(comment,&buf[4],0);
731 extract(flnm,&buf[4],1);
732 printf("\nDirectory of %s on %s\n",flnm,comment);
733 printf("-----------------------\n");
734 while (serv_gets(buf), strcmp(buf,"000")) {
737 extract(comment,buf,2);
738 if (strlen(flnm)<=14)
739 printf("%-14s %8s %s\n",flnm,flsz,comment);
741 printf("%s\n%14s %8s %s\n",flnm,"",flsz,comment);
747 * add a user to a private room
750 char aaa[31],bbb[256];
752 if ((room_flags & QR_PRIVATE)==0) {
753 printf("This is not a private room.\n");
757 newprompt("Name of user? ",aaa,30);
758 if (aaa[0]==0) return;
760 snprintf(bbb,sizeof bbb,"INVT %s",aaa);
763 printf("%s\n",&bbb[4]);
768 * kick a user out of a room
771 char aaa[31],bbb[256];
773 newprompt("Name of user? ",aaa,30);
774 if (aaa[0]==0) return;
776 snprintf(bbb,sizeof bbb,"KICK %s",aaa);
779 printf("%s\n",&bbb[4]);
784 * aide command: kill the current room
786 void killroom(void) {
792 printf("%s\n",&aaa[4]);
796 printf("Are you sure you want to kill this room? ");
797 if (yesno()==0) return;
801 printf("%s\n",&aaa[4]);
802 if (aaa[0]!='2') return;
803 dotgoto("_BASEROOM_",0);
806 void forget(void) { /* forget the current room */
809 printf("Are you sure you want to forget this room? ");
810 if (yesno()==0) return;
815 printf("%s\n",&cmd[4]);
819 /* now return to the lobby */
820 dotgoto("_BASEROOM_",0);
829 char new_room_name[ROOMNAMELEN];
831 char new_room_pass[10];
839 printf("%s\n",&cmd[4]);
843 newprompt("Name for new room? ",new_room_name,ROOMNAMELEN-1);
844 if (strlen(new_room_name)==0) return;
845 for (a=0; a<strlen(new_room_name); ++a)
846 if (new_room_name[a] == '|') new_room_name[a]='_';
848 new_room_floor = select_floor((int)curr_floor);
850 IFNEXPERT formout("roomaccess");
852 printf("<?>Help\n<1>Public room\n<2>Guess-name room\n");
853 printf("<3>Passworded room\n<4>Invitation-only room\n");
854 printf("Enter room type: ");
857 } while (((b<'1')||(b>'4')) && (b!='?'));
860 formout("roomaccess");
862 } while ((b<'1')||(b>'4'));
865 new_room_type = b - 1;
866 if (new_room_type==2) {
867 newprompt("Enter a room password: ",new_room_pass,9);
868 for (a=0; a<strlen(new_room_pass); ++a)
869 if (new_room_pass[a] == '|') new_room_pass[a]='_';
871 else strcpy(new_room_pass,"");
873 printf("\042%s\042, a",new_room_name);
874 if (b==1) printf(" public room.");
875 if (b==2) printf(" guess-name room.");
876 if (b==3) printf(" passworded room, password: %s",new_room_pass);
877 if (b==4) printf("n invitation-only room.");
878 printf("\nInstall it? (y/n) : ");
882 snprintf(cmd, sizeof cmd, "CRE8 1|%s|%d|%s|%d", new_room_name,
883 new_room_type, new_room_pass, new_room_floor);
887 printf("%s\n",&cmd[4]);
891 /* command succeeded... now GO to the new room! */
892 dotgoto(new_room_name,0);
897 void readinfo(void) { /* read info file for current room */
904 if (cmd[0]!='1') return;
906 fmout(screenwidth,NULL,
907 ((userflags & US_PAGINATOR) ? 1 : 0),
913 * <W>ho knows room...
915 void whoknows(void) {
920 printf("%s\n",&buf[5]);
924 sttybbs(SB_YES_INTR);
925 while (serv_gets(buf), strncmp(buf,"000",3)) {
926 if (sigcaught==0) printf("%s\n",buf);
932 void do_edit(char *desc, char *read_cmd, char *check_cmd, char *write_cmd)
936 int b,cksum,editor_exit;
939 if (strlen(editor_path)==0) {
940 printf("Do you wish to re-enter %s? ",desc);
941 if (yesno()==0) return;
944 fp = fopen(temp,"w");
947 serv_puts(check_cmd);
950 printf("%s\n",&cmd[4]);
954 if (strlen(editor_path)>0) {
958 fp = fopen(temp,"w");
959 while (serv_gets(cmd), strcmp(cmd,"000")) {
960 fprintf(fp,"%s\n",cmd);
966 cksum = file_checksum(temp);
968 if (strlen(editor_path)>0) {
973 execlp(editor_path,editor_path,temp,NULL);
976 if (editor_pid>0) do {
978 b=wait(&editor_exit);
979 } while((b!=editor_pid)&&(b>=0));
981 printf("Executed %s\n", editor_path);
985 printf("Entering %s. ",desc);
986 printf("Press return twice when finished.\n");
992 if (file_checksum(temp) == cksum) {
993 printf("*** Aborted.\n");
997 serv_puts(write_cmd);
1000 printf("%s\n",&cmd[4]);
1005 while (fgets(cmd,255,fp)!=NULL) {
1006 cmd[strlen(cmd)-1] = 0;
1017 void enterinfo(void) { /* edit info file for current room */
1018 do_edit("the Info file for this room","RINF","EINF 0","EINF 1");
1021 void enter_bio(void) {
1023 snprintf(cmd,sizeof cmd,"RBIO %s",fullname);
1024 do_edit("your Bio",cmd,"NOOP","EBIO");
1028 * create a new floor
1030 void create_floor(void) {
1032 char newfloorname[256];
1034 serv_puts("CFLR xx|0");
1037 printf("%s\n",&buf[4]);
1041 newprompt("Name for new floor: ",newfloorname,255);
1042 snprintf(buf,sizeof buf,"CFLR %s|1",newfloorname);
1046 printf("Floor has been created.\n");
1049 printf("%s\n",&buf[4]);
1054 * edit the current floor
1056 void edit_floor(void) {
1058 int expire_mode = 0;
1059 int expire_value = 0;
1061 if (floorlist[(int)curr_floor][0]==0) load_floorlist();
1063 /* Fetch the expire policy (this will silently fail on old servers,
1064 * resulting in "default" policy)
1066 serv_puts("GPEX floor");
1069 expire_mode = extract_int(&buf[4], 0);
1070 expire_value = extract_int(&buf[4], 1);
1073 /* Interact with the user */
1074 strprompt("Floor name",&floorlist[(int)curr_floor][0],255);
1076 /* Angels and demons dancing in my head... */
1078 sprintf(buf, "%d", expire_mode);
1079 strprompt("Floor default essage expire policy (? for list)",
1081 if (buf[0] == '?') {
1083 printf("0. Use the system default\n");
1084 printf("1. Never automatically expire messages\n");
1085 printf("2. Expire by message count\n");
1086 printf("3. Expire by message age\n");
1088 } while((buf[0]<48)||(buf[0]>51));
1089 expire_mode = buf[0] - 48;
1091 /* ...lunatics and monsters underneath my bed */
1092 if (expire_mode == 2) {
1093 sprintf(buf, "%d", expire_value);
1094 strprompt("Keep how many messages online?", buf, 10);
1095 expire_value = atol(buf);
1098 if (expire_mode == 3) {
1099 sprintf(buf, "%d", expire_value);
1100 strprompt("Keep messages for how many days?", buf, 10);
1101 expire_value = atol(buf);
1105 snprintf(buf, sizeof buf, "SPEX floor|%d|%d",
1106 expire_mode, expire_value);
1110 snprintf(buf,sizeof buf,"EFLR %d|%s",curr_floor,
1111 &floorlist[(int)curr_floor][0]);
1114 printf("%s\n",&buf[4]);
1122 * kill the current floor
1124 void kill_floor(void) {
1125 int floornum_to_delete,a;
1128 if (floorlist[(int)curr_floor][0]==0) load_floorlist();
1130 floornum_to_delete = (-1);
1131 printf("(Press return to abort)\n");
1132 newprompt("Delete which floor? ",buf,255);
1133 if (strlen(buf)==0) return;
1134 for (a=0; a<128; ++a)
1135 if (!strucmp(&floorlist[a][0],buf))
1136 floornum_to_delete = a;
1137 if (floornum_to_delete < 0) {
1138 printf("No such floor. Select one of:\n");
1139 for (a=0; a<128; ++a)
1140 if (floorlist[a][0]!=0)
1141 printf("%s\n",&floorlist[a][0]);
1143 } while (floornum_to_delete < 0);
1144 sprintf(buf,"KFLR %d|1",floornum_to_delete);
1147 printf("%s\n",&buf[4]);