rosenbk@dalcs.UUCP (Rob P. and Stan L.) (04/29/85)
Gentlepeople: After completing a software design course, which involved a software project using sockets, I decided to do a little spare time hacking myself in order to produce this multi-user "talk" program. I thought it would be an interesting project because I could learn the use of 4.2BSD sockets and because talk(1) only handles two people and requires a driver. Do whatever you want with this piece of software, but please leave the comments in main.c undisturbed. A few notes: 1) In evals.c, in e_ring(), change the command for pwrite from ~puchyr/com/pwrite to an appropriate path. 2) The following is a shell archive file. make a directory and save this file in it. Edit this file and remove the top portion of this file up to and including the ----cut here---- line. Then use the command: sh this_file Do not run this file through csh. It must be fed to the Bourne shell. 3) You should end up a number of C programs, a Makefile, and a pwrite.man manual entry. use the command: make to compile the programs. An 'a.out' will result. If anyone comes with bug fixes please post them to the net. .__ ___. .__ .. |__\ /___| |__\ || || >> <<__ || >>.. .. __. ||__ .. .. .. __. ||// \__\ ||// || || /__| |._ \ \\ || |'/__| ||\\ .___>> || ||_||<<__. || || \\|| | / || \\ |___/ || \__| \__| || || \`| || \| ._________________________________________/| |_________________________________________/ Robert Scott Puchyr; ...dartvax!dalcs!dalcsug!puchyr Dalhousie University, Halifax, Nova Scotia, Canada. -----cut here-----cut here-----cut here-----cut here----- #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # Makefile # evals.c # goodbye.c # header.h # hello.c # main.c # pwrite.man # socket_lib.c # users.c # utils.c # windows.c cat - << \SHAR_EOF > Makefile a.out: main.o evals.o goodbye.o hello.o socket_lib.o users.o utils.o windows.o cc -g main.o evals.o goodbye.o hello.o socket_lib.o users.o utils.o windows.o -lcurses -ltermcap main.o: header.h main.c evals.o: header.h evals.c goodbye.o: header.h goodbye.c hello.o: header.h hello.c socket_lib.o: header.h socket_lib.c users.o: header.h users.c utils.o: header.h utils.c windows.o: header.h windows.c SHAR_EOF cat - << \SHAR_EOF > evals.c #include "header.h" eval_key(c) char c; { int a, k; switch(c) { case 4: goodbye(); break; case 12: wrefresh(curscr); break; case 18: w_redraw(0); break; case 23: if (SNOOPER >= 0) p_sendch(c); break; case ESC: eval_esc(); break; case 127: case 8: w_writech(0,'\b'); p_sendch('\b'); break; default: if (c >= ' ' || c == RET) { w_writech(0,c); p_sendch(c); } break; } } eval_esc() { int c; overwrite(curscr,SCREEN); w_setcorners(CURRENT_WINDOW); sprintf(STRING,"%c\n\"%s\" --> COMM-MODE.%c",BEGIN_SECRET,T[0].__tty,END_SECRET); p_sendstr(STRING); w_corners(1); do_line("Command Mode. Press ESC to return to Talk Mode."); while ((c = getchar()) != ESC) { w_corners(0); switch(c) { case 12: wrefresh(curscr); break; case 18: w_redraw(0); break; case 'w': w_who(); break; case 'a': e_call(); break; case 'd': e_delete(); break; case 'r': e_ring(); break; case '?': w_help(); break; case 'h': w_mvcorners( 0,-2, 0,-2); break; case 'j': w_mvcorners( 1, 0, 1, 0); break; case 'k': w_mvcorners(-1, 0,-1, 0); break; case 'l': w_mvcorners( 0, 2, 0, 2); break; case 'H': w_mvcorners( 0, 0, 0,-2); break; case 'J': w_mvcorners( 0, 0, 1, 0); break; case 'K': w_mvcorners( 0, 0,-1, 0); break; case 'L': w_mvcorners( 0, 0, 0, 2); break; case SPC: w_nextcorners(); break; case '@': w_change(); break; } w_corners(1); do_line("Command Mode. Press ESC to return to Talk Mode."); } w_corners(0); w_redraw(1); sprintf(STRING,"%c\n\"%s\" <-- COMM-MODE.%c",BEGIN_SECRET,T[0].__tty,END_SECRET); p_sendstr(STRING); sock_io(); } e_call() { int a; w_who(); strcpy(STRING,enter_line("Which user do you want? ")); if (*STRING) { if (!strcmp(STRING,"**")) { if (p_check(STRING,0) < 0) { SNOOPER = p_add("**","Super Snooper",-1,0); w_new_user(SNOOPER); sprintf(STRING,"%c\n\"%s\" ADD \"**\" %c",BEGIN_SECRET,T[0].__tty,END_SECRET); p_sendstr(STRING); } else { panic("How many Super Snoopers do you want?!?!?",2); } } else if ((a = p_check(STRING,1)) < 0) { panic("That user is not on the system.",2); } else { if (p_check(STRING,0) < 0) { a = p_add(W[a].W_tty,W[a].W_username,-1,0); w_new_user(a); sprintf(STRING,"%c\n\"%s\" ADD \"%s\".%c",BEGIN_SECRET,T[0].__tty,T[a].__tty,END_SECRET); p_sendstr(STRING); } else { panic("That user is already on pwrite.",2); } } } w_redraw(0); } e_delete() { int a; w_who(); strcpy(STRING,enter_line("Which user do you want to delete? ")); if (*STRING) { if ((a = p_check(STRING,0)) < 0) { panic("That user is not on pwrite.",2); } else { sprintf(STRING,"%c\n\"%s\" DEL \"%s\".%c",BEGIN_SECRET,T[0].__tty,T[a].__tty,END_SECRET); p_delete(a); p_sendstr(STRING); } } w_redraw(0); } e_ring() { int a; for (a=1; a < NUM_T; a++) { if (!T[a].__dead && !T[a].__connected) { sprintf(STRING,"/dev/tty%s",T[a].__tty); if ((fp = fopen(STRING,"w")) != NULL) { fprintf(fp,"\n\n\n%c",7); fprintf(fp,"pwrite: User '%s' on 'tty%s' wishes to talk to you using 'pwrite'.\n",T[0].__username,T[0].__tty); fprintf(fp,"pwrite: Please respond using: '~puchyr/com/pwrite' and wait 10 seconds.\n"); fprintf(fp,"\n\n%c",7); fflush(fp); fclose(fp); w_writestr(a,"[RING] "); } else { w_writestr(a,"[NO RING] "); } } } } SHAR_EOF cat - << \SHAR_EOF > goodbye.c #include "header.h" goodbye() { int a; for (a=0; a < NUM_T; a++) { if (T[a].__sock >= 0 && !T[a].__dead) s_delete(T[a].__sock); } unlink(T[0].__file); do_line(""); nocrmode(); echo(); endwin(); exit(1); } SHAR_EOF cat - << \SHAR_EOF > header.h #include <curses.h> #include <ctype.h> #include <errno.h> #include <signal.h> #include <fcntl.h> #include <utmp.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/time.h> #include <sys/socket.h> #include <sys/un.h> #define MAX_USERS 12 #define ESC 27 #define RET '\n' #define SPC ' ' #define BEGIN_SECRET 19 #define END_SECRET 20 WINDOW *SCREEN; /* a full-size work area */ WINDOW *LINE; /* bottom line of screen */ FILE *fp, *fopen(); struct pw__user /* pwrite user structure */ { WINDOW *__win1; /* user's border window */ WINDOW *__win2; /* user's inner window */ char __file[32]; /* user's socket file name */ char __tty[8]; /* user's tty number (tty??) */ char __username[32]; /* user's username */ int __sock; /* user's socket descriptor */ int __connected; /* is this user connected? */ int __dead; /* is this connection dead? */ int __secret; /* is currently sending secret */ }; struct pw__user T[MAX_USERS]; /* I am T[0] */ struct corners { int C_y; /* y coordinate or this corner */ int C_x; /* x coordinate or this corner */ int C_under; /* what was under this corner */ }; struct corners C[4]; int CURRENT_WINDOW; /* The current window */ struct def__loc /* default locations of wins */ { int D_y; /* default row of this window */ int D_x; /* default col */ int D_ysize; /* default y size */ int D_xsize; /* default x size */ }; struct def__loc D[MAX_USERS]; /* I am D[0] */ struct who__list /* who_list structure */ { char W_tty[8]; /* tty */ char W_username[32]; /* username */ }; struct who__list W[64]; /* The who_list */ int NUM_W; /* # of users on the system */ char STRING[BUFSIZ]; /* General purpose string */ int NUM_T; /* # of users you have */ int NUM_C; /* # of users connectd to you */ int ACTIVE_MASK; /* mask of active descriptors */ int SMART; /* TRUE if terminal is smart */ int SNOOPER; /* T element for the Snooper */ int errno; /* standard error noumber */ int sock_io(); /* a place to go on SIGURG */ int goodbye(); /* a place to go and die */ int _pipe_(); /* "The Universe is defective" */ int _death_(); /* program bombed badley! */ struct timeval TIMEOUT; /* timeout structure */ extern char *enter_line(); /* input routine */ SHAR_EOF cat - << \SHAR_EOF > hello.c #include "header.h" int DEF_LENGTH, DEF_WIDTH; int NUM_DOWN, NUM_ACROSS; hello() { int a; int y, x; /* printf("# of lines: "); LINES = atoi(gets(STRING)); printf("# of cols : "); COLS = atoi(gets(STRING)); */ initscr(); crmode(); noecho(); signal(SIGQUIT,SIG_IGN); signal(SIGINT, goodbye); /* signal(SIGPIPE, _pipe_); */ signal(SIGSEGV,_death_); signal(SIGBUS, _death_); if (*CM && LINES >= 8 && COLS >= 32) SMART = 1; else SMART = 0; TIMEOUT.tv_sec = 5; /* 5 seconds */ TIMEOUT.tv_usec = 0; /* 0 microseconds */ SCREEN = newwin(LINES,COLS,0,0); clearok(SCREEN,0); LINE = newwin(1,COLS,LINES-1,0); DEF_LENGTH = 8; DEF_WIDTH = (COLS - 8) / 2; if (DEF_WIDTH > 32) DEF_WIDTH = 32; NUM_DOWN = LINES / DEF_LENGTH; NUM_ACROSS = (COLS - 8) / DEF_WIDTH; for (a=0; a < MAX_USERS; a++) { D[a].D_ysize = DEF_LENGTH; D[a].D_xsize = DEF_WIDTH; D[a].D_y = LINES - DEF_LENGTH; D[a].D_x = COLS - DEF_WIDTH; } for (x=a=0; x < NUM_ACROSS; x++) for (y=0; y < NUM_DOWN; y++,a++) { D[a].D_y = y * DEF_LENGTH; D[a].D_x = x * DEF_WIDTH + 8; } p_setup_me(); } SHAR_EOF cat - << \SHAR_EOF > main.c #include "header.h" #define VERSION "2.0" /*********************************************************************** * * ____ * | \ o | A multi-user communication * |___/ _ _ _ __ _. _|_ ___ program by: * | | | |/ | | /___> * | |/\| | _|_ |_/ \___ Robert Scott Puchyr, * Dalhousie University, * Halifax, Nova Scotia, * Canada, * April 9, 1985 * ***********************************************************************/ main(argc,argv) int argc; char **argv; { printf("Pwrite. version %s.\nPress ESC ? for help.\n\n",VERSION); hello(); do_pwrite(); goodbye(); } do_pwrite() { while (1) { sock_io(); if (NUM_C < NUM_T) p_beg(); } } sock_io() { char S[BUFSIZ]; int a, i, m; m = s_select(ACTIVE_MASK); if (m & 1) { read(0,&a,1); eval_key(a); } if (m <= 1) return(0); if (m & (1 << T[0].__sock)) { p_answer(); } for (a=1; a < NUM_T; a++) { if (m & (1 << T[a].__sock) && T[a].__connected) { i = read(T[a].__sock,S,BUFSIZ); if (i <= 0) { sprintf(STRING,"%c\n\"%s\" LOS \"%s\".%c",BEGIN_SECRET,T[0].__tty,T[a].__tty,END_SECRET); p_delete(a); p_sendstr(STRING); } else { S[i] = NULL; w_writestr(a,S); } } } } SHAR_EOF cat - << \SHAR_EOF > pwrite.man PWRITE(1) UNIX Programmer's Manual PWRITE(1) NAME pwrite - multi-user ``talk'' program SYNOPSIS pwrite DESCRIPTION _P_w_r_i_t_e allows a user to communicate with a number of other users who are logged into the computer. There are no command line arguments for _p_w_r_i_t_e. After entering _p_w_r_i_t_e, a box or window labeled with your username and terminal tty will appear in the upper left portion of your screen. There are two modes in _p_w_r_i_t_e, talk mode, and command mode. The ESCAPE button functions as a toggle switch between talk mode and command mode. The following commands are available in com- mand mode. a - Add a user. A ``ghost'' window will appear on the screen. When adding a user, the user's name or the user's terminal tty number are valid inputs. Ghost windows, drawn with dotted lines, are used to indicate incomplete connections. d - Delete a connection. Deleting yourself will exit you from the program. r - Ring. All unanswered connections, ghost windows, are rung by sending a note to the expected users. [NO RING] appears if a user has his write permis- sion off. You are free to ring as frequently or infrequently as you wish. w - See who is on the system. ? - Help. A few help windows are displayed in the lower right area of the screen. _P_w_r_i_t_e allows a maximun of 12 windows on the screen. You are free to change the windows within command mode. Included in command mode are four corner posts, [ [ ] ] , which are used as sights for changing windows. The window on which they are placed is called the _c_u_r_r_e_n_t _w_i_n_d_o_w. The commands for customizing the windows within command mode are: h j k l - Moves the sights left (h), down (j), up (k), or right (l) respectively. H J K L - Changes size by moving the lower right sight left, down, up, or right while holding the upper left sight stationary. SPACE - Select current window. With a number of windows Printed 4/29/85 9 April 1985 1 PWRITE(1) UNIX Programmer's Manual PWRITE(1) on your screen, pressing SPACE will allow you to select a different current window. @ - Actually move and resize the current window to fit within the four sights. Moving the sights alone will not change the current window's loca- tion or size. The @ command does. FILES /tmp/.pw_* - communication sockets SEE ALSO talk(1), mesg(1) BUGS _P_w_r_i_t_e is heavily dependent on sockets. The program tends to boldly state that the current Universe is defective. This is done when an unknown SIGPIPE error ocurrs with the sockets. Printed 4/29/85 9 April 1985 2 SHAR_EOF cat - << \SHAR_EOF > socket_lib.c #include "header.h" /***************************************************************************** * * SCOKET_ID = make_a_socket(); * * make_a_socket() creates a socket local to the system and * binds the name FILE_NAME to it. This function is called * by new_server_socket() and new_client_socket(). A SOCKET_ID * is returned on success, -1 if not. * *****************************************************************************/ make_a_socket() { int SOCKET_ID; errno = 0; if ((SOCKET_ID = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { return(-1); } return(SOCKET_ID); } /***************************************************************************** * * SOCKET_ID = s_new_server(FILE_NAME); * * s_new_server() creates a socket ready for connection * by connect_server(). This function returns a SOCKET_ID * if successful, otherwise -1. * *****************************************************************************/ s_new_server(FILE_NAME) char *FILE_NAME; { int SOCKET_ID; struct sockaddr SOCKET_INFO; errno = 0; if ((SOCKET_ID = make_a_socket()) < 0) { return(-1); } SOCKET_INFO.sa_family = AF_UNIX; strcpy(SOCKET_INFO.sa_data, FILE_NAME); unlink(SOCKET_INFO.sa_data); errno = 0; if (bind(SOCKET_ID, &SOCKET_INFO, sizeof(SOCKET_INFO)) < 0) { return(-1); } chmod(SOCKET_INFO.sa_data, 0666); listen(SOCKET_ID,5); return(SOCKET_ID); } /***************************************************************************** * * SOCKET_ID = s_new_client(); * * s_new_client() creates and returns a SOCKET_ID ready * ready for connrction using connect_client(). A -1 is returned * if something messed up. * *****************************************************************************/ s_new_client() { int SOCKET_ID; errno = 0; if ((SOCKET_ID = make_a_socket()) < 0) { return(-1); } return(SOCKET_ID); } /***************************************************************************** * * s_connect_server(SOCKET_ID, FILE_NAME); * * s_connect_server() connects the already created SOCKET_ID * with a UNIX file. -1 is returned if the connection cannot * be made. Otherwise, the filename of the client's socket * placed in FILE_NAME and a SOCKET_ID file descriptor is * for the newly accpeted socket is returned. * *****************************************************************************/ s_connect_server (SOCKET_ID, FILE_NAME) int SOCKET_ID; char *FILE_NAME; { int NEW_SOCKET; int namelen; struct sockaddr SOCKET_INFO; namelen = sizeof(SOCKET_INFO); errno = 0; if ((NEW_SOCKET = accept(SOCKET_ID, &SOCKET_INFO, &namelen)) < 0) { return(-1); } strcpy(FILE_NAME,SOCKET_INFO.sa_data); return(NEW_SOCKET); } /***************************************************************************** * * s_connect_client(SOCKET_ID, FILE_NAME); * * s_connect_client() connects a SOCKET_ID already created with * new_client_socket() and connects it (with the UNIX file * FILE_NAME). Zero is returned upon success, -1 if you're not * so fortunate. * *****************************************************************************/ s_connect_client (SOCKET_ID, FILE_NAME) int SOCKET_ID; char *FILE_NAME; { int namelen; struct sockaddr SOCKET_INFO; namelen = sizeof(SOCKET_INFO); SOCKET_INFO.sa_family = AF_UNIX; strcpy(SOCKET_INFO.sa_data, FILE_NAME); errno = 0; return(connect(SOCKET_ID, &SOCKET_INFO, namelen)); } /***************************************************************************** * * s_select(MASK); * *****************************************************************************/ s_select (MASK) int MASK; { int mask; mask = MASK; select(20, &mask, 0, 0, &TIMEOUT); return(mask); } /***************************************************************************** * * s_read(SOCKET_ID, STRING, NUM_CHARS); * * s_read() reads NUM_CHARS bytes from the socket SOCKET_ID * and places them in STRING. This function returns -1 if * reading is not possible from SOCKET_ID, this means that * the socket has been closed down from the other end. * A SOCKET_ID of 0 will read from standard input. If no * problems occur, the number of characters actually read * from the socket is returned. * *****************************************************************************/ s_read(SOCKET_ID,STRING,NUM_CHARS) int SOCKET_ID; char *STRING; int NUM_CHARS; { int num_read; if (s_select(SOCKET_ID)) { if ((num_read = read(SOCKET_ID, STRING, NUM_CHARS)) <= 0) { return(-1); /* Socket was closed from other side */ } STRING[num_read] = NULL; return(num_read); } return(0); } /***************************************************************************** * * s_write(SOCKET_ID, STRING); * * s_write() writes a NULL terminated STRING to the socket * specified by SOCKET_ID. The number of characters written to * the socket is returned. -1 is returned something goes wrong. * *****************************************************************************/ s_write(SOCKET_ID,STRING) int SOCKET_ID; char *STRING; { return(write(SOCKET_ID, STRING, strlen(STRING))); } /***************************************************************************** * * s_delete(SOCKET_ID); * * s_delete() closes down a socket, as specified by * SOCKET_ID; * *****************************************************************************/ s_delete(SOCKET_ID) int SOCKET_ID; { errno = 0; shutdown(SOCKET_ID, 2); return(close(SOCKET_ID)); } SHAR_EOF cat - << \SHAR_EOF > users.c #include "header.h" FILE *fp; struct utmp ubuf; p_setup_me() { CURRENT_WINDOW = NUM_T = NUM_C = 0; SNOOPER = -1; ACTIVE_MASK = 0 | (1 << 0); /* 0 is stdin */ strcpy(T[0].__tty,rindex(ttyname(0),'/') + 4); strcpy(T[0].__username,getenv("USER")); sprintf(T[0].__file,"/tmp/.pw_%s",T[0].__tty); if ((T[0].__sock = s_new_server(T[0].__file)) < 0) panic("Error creating your socket.",0); T[0].__connected = 1; w_new_user(0); NUM_T++; NUM_C++; ACTIVE_MASK |= (1 << T[0].__sock); } p_delete(n) int n; { int a; if (T[n].__connected) NUM_C--; delwin(T[n].__win1); delwin(T[n].__win2); if (SMART) { wclear(T[n].__win1); wclear(T[n].__win2); wrefresh(T[n].__win1); wrefresh(T[n].__win2); } else { printf("\nUser '%s' on 'tty%s' has disconnected%c\n",T[n].__username,T[n].__tty,7); } if (T[n].__sock >= 0) { ACTIVE_MASK &= ~(1 << T[n].__sock); s_delete(T[n].__sock); } strcpy(T[n].__tty,""); strcpy(T[n].__username,""); strcpy(T[n].__file,""); T[n].__sock = -1; T[n].__dead = 1; T[n].__connected = 0; if (NUM_C < 1 || n == 0) goodbye(); if (n == SNOOPER) SNOOPER = -1; if (n == CURRENT_WINDOW) w_nextcorners(); } p_answer() { char t[8], u[32]; int a, c, s; strcpy(STRING,""); s = s_connect_server(T[0].__sock,STRING); if (s < 0) return(-1); a = read(s,STRING,BUFSIZ); /* "j6|puchyr|" */ STRING[a] = NULL; STRING[2] = NULL; strcpy(t,STRING); aslstr(STRING,3); for (a=0; STRING[a] != '|'; u[a] = STRING[a++]); u[a] = NULL; a = p_add(t,u,s,1); w_new_user(a); sprintf(STRING,"%c\n\"%s\" ANS \"%s\".%c",BEGIN_SECRET,T[0].__tty,T[a].__tty,END_SECRET); p_sendstr(STRING); NUM_C++; } p_add(t,u,s,c) char *t, *u; int s, c; { int a; if (NUM_C >= MAX_USERS) { panic("You cannot add any more.",4); return(0); } for (a=1; a < NUM_T; a++) { if (T[a].__dead) break; } sprintf(T[a].__file,"/tmp/.pw_%s",t); strcpy(T[a].__tty,t); strcpy(T[a].__username,u); T[a].__dead = 0; T[a].__secret = 0; T[a].__sock = s; T[a].__connected = c; if (c) ACTIVE_MASK |= (1 << T[a].__sock); if (a >= NUM_T) NUM_T++; CURRENT_WINDOW = a; return(a); } p_beg() { int a; for (a=0; a < NUM_T; a++) { if (!T[a].__dead && !T[a].__connected) { if (T[a].__sock < 0) T[a].__sock = s_new_client(); if (s_connect_client(T[a].__sock,T[a].__file) >= 0) { sprintf(STRING,"%s|%s|",T[0].__tty,T[0].__username); s_write(T[a].__sock,STRING); T[a].__connected = 1; delwin(T[a].__win1); delwin(T[a].__win2); w_new_user(a); sprintf(STRING,"%c\n\"%s\" GOT \"%s\".%c",BEGIN_SECRET,T[0].__tty,T[a].__tty,END_SECRET); p_sendstr(STRING); NUM_C++; ACTIVE_MASK |= (1 << T[a].__sock); } } } } p_who() { if ((fp = fopen("/etc/utmp","r")) == NULL) { panic("Can't open /etc/utmp. (Major Bug!!)\n",0); } for (NUM_W=0; fread((char *) &ubuf, sizeof(ubuf), 1, fp) == 1; ) { if (*ubuf.ut_name) { strcpy(W[NUM_W].W_username,ubuf.ut_name); W[NUM_W].W_tty[0] = ubuf.ut_line[3]; W[NUM_W].W_tty[1] = ubuf.ut_line[4]; W[NUM_W].W_tty[2] = NULL; NUM_W++; } } fclose(fp); } p_check(s,how) char *s; int how; { int a, l; if (how) { p_who(); if ((l = strlen(s)) <= 2) { for (a=0; a < NUM_W; a++) { if (!strcmp(W[a].W_tty,s)) break; } } else { for (a=0; a < NUM_W; a++) { if (!strcmp(W[a].W_username,s)) break; } } if (a < NUM_W) return(a); else return(-1); } else { if ((l = strlen(s)) <= 2) { for (a=0; a < NUM_T; a++) { if (!strcmp(T[a].__tty,s)) break; } } else { for (a=0; a < NUM_T; a++) { if (!strcmp(T[a].__username,s)) break; } } if (a < NUM_T) return(a); else return(-1); } } p_sendch(c) int c; { int a; for (a=1; a < NUM_T; a++) if (T[a].__connected && !T[a].__dead && T[a].__sock >= 0) write(T[a].__sock,&c,1); } p_sendstr(s) char *s; { int a; for (a=1; a < NUM_T; a++) if (T[a].__connected && !T[a].__dead && T[a].__sock >= 0) write(T[a].__sock,s,strlen(s)); } p_secretcommand(n,c) int n, c; { char temp[16]; int a; switch(c) { case 23: sprintf(STRING,"%c\n\"%s\" HAS",BEGIN_SECRET,T[0].__tty); for (a=0; a < NUM_T; a++) { if (!T[a].__dead) { strcat(STRING," \""); strcat(STRING,T[a].__tty); strcat(STRING,"\""); } } sprintf(temp,".%c",END_SECRET); strcat(STRING,temp); write(T[n].__sock,STRING,strlen(STRING)); break; } } SHAR_EOF cat - << \SHAR_EOF > utils.c #include "header.h" panic(s,n) char *s; int n; { if (SMART) { do_line(s); } else { printf("\n%s\n",s); } fflush(stdout); if (n) { sleep(n); } else { sleep(5); goodbye(); } } do_line(s) char *s; { int a, l; if (SMART) { wclear(LINE); if ((l = strlen(s)) < COLS) { waddstr(LINE,s); } else { for (a=16; a > 0; a--) waddch(LINE,s[l-a]); } if (!*s) touchwin(LINE); wrefresh(LINE); } else { printf("\n%s\n",s); } } _pipe_() { signal(SIGINT, SIG_IGN); if (SMART) mvcur(0,COLS-1,LINES-9,0); printf("\n"); printf(".----------------------.\n"); printf("| THIS UNIVERSE SEEMS |\n"); printf("| TO BE DEFECTIVE! |\n"); printf("| |\n"); printf("| PLEASE TRY ANOTHER. |\n"); printf("| Press RETURN |\n"); printf("`----------------------'\n"); gets(STRING); endwin(); exit(0); } _death_() { signal(SIGINT, SIG_IGN); if (SMART) mvcur(0,COLS-1,LINES-9,0); printf("\n"); printf(".----------------------.\n"); printf("| .-----* A serious |\n"); printf("| _|_ system error |\n"); printf("| / \\ has occurred |\n"); printf("| | TNT | |\n"); printf("| \\___/ Press RETURN |\n"); printf("`----------------------'\n"); gets(STRING); endwin(); exit(0); } char *enter_line(s) char *s; { char e_line[BUFSIZ], c; int a, no_echo; if (!SMART) { printf("\n%s",s); echo(); nocrmode(); gets(e_line); noecho(); crmode(); return(e_line); } no_echo = 0; if (*s == '^') { s++; no_echo = 1; } do_line(s); a = 0; for (a=e_line[0]=0; (c=getchar()) != RET && c != ESC; ) { switch(c) { case 127: case 8: if (a > 0) e_line[--a] = NULL; break; case 21: a = 0; e_line[a] = NULL; break; default: if (a < BUFSIZ && c >= ' ') { e_line[a++] = c; e_line[a] = NULL; } break; } if (!no_echo) do_line(e_line); } if (c == ESC) strcpy(e_line,""); return(e_line); } aslstr(s,n) char *s; int n; { int a; for (a=0; s[a] = s[a+n]; a++); } SHAR_EOF cat - << \SHAR_EOF > windows.c #include "header.h" WINDOW *W_WINDOW; WINDOW *H_WINDOW; w_new_user(n) int n; { int a, b, c, x, y; T[n].__win1 = newwin(D[n].D_ysize,D[n].D_xsize,D[n].D_y,D[n].D_x); T[n].__win2 = newwin(D[n].D_ysize-3,D[n].D_xsize-3,D[n].D_y+2,D[n].D_x+2); if (T[n].__connected) { box(T[n].__win1,'|','-'); } else { for (y=0; y < D[n].D_ysize; y++) { mvwaddch(T[n].__win1,y,0,'.'); mvwaddch(T[n].__win1,y,D[n].D_xsize-1,'.'); } for (x=0; x < D[n].D_xsize; x+=2) { mvwaddch(T[n].__win1,D[n].D_ysize-1,x,'-'); mvwaddch(T[n].__win1,0,x+1,'-'); } } mvwaddch(T[n].__win1,0,0,'.'); mvwaddch(T[n].__win1,D[n].D_ysize-1,0,'`'); mvwaddch(T[n].__win1,0,D[n].D_xsize-1,'.'); mvwaddch(T[n].__win1,D[n].D_ysize-1,D[n].D_xsize-1,'\''); sprintf(STRING,"%s %s",T[n].__tty,T[n].__username); for (a=0; STRING[a] && a+3 < T[n].__win1->_maxx; a++) mvwaddch(T[n].__win1,0,a+2,STRING[a]); scrollok(T[n].__win2,1); w_setcorners(n); if (SMART) { wrefresh(T[n].__win1); wrefresh(T[n].__win2); } else { printf("\nUser '%s' on 'tty%s' has joined.%c\n",T[n].__username,T[n].__tty,7); } } w_setcorners(n) int n; { CURRENT_WINDOW = n; C[0].C_y = C[1].C_y = D[n].D_y; C[0].C_x = C[2].C_x = D[n].D_x; C[2].C_y = C[3].C_y = D[n].D_y + D[n].D_ysize-1; C[1].C_x = C[3].C_x = D[n].D_x + D[n].D_xsize-1; } w_addch(n,c) int n, c; { switch(c) { case BEGIN_SECRET: T[n].__secret = 1; return(0); break; case END_SECRET: T[n].__secret = 0; return(0); break; case 23: p_secretcommand(n,c); return(0); break; } if (T[n].__secret) { if (SNOOPER < 0) return(0); else n = SNOOPER; } if (SMART) { if (c == 8) { w_backspace(n); } else if (T[n].__win2->_curx == T[n].__win2->_maxx-1) { if (c == RET || c == SPC) waddch(T[n].__win2,RET); else { w_wordwrap(n); waddch(T[n].__win2,c); } } else { waddch(T[n].__win2,c); } if (n == SNOOPER) wrefresh(T[SNOOPER].__win2); } else { putchar(c); } } w_writech(n,c) int n, c; { w_addch(n,c); if (SMART) wrefresh(T[n].__win2); else fflush(stdout); } w_writestr(n,s) int n; char *s; { for (; *s; w_addch(n,*s++)); if (SMART) wrefresh(T[n].__win2); else fflush(stdout); } w_wordwrap(n) int n; { int c, x, y, s; waddch(T[n].__win2,RET); y = T[n].__win2->_cury; x = T[n].__win2->_maxx - 2; for ( ; x > 0 && T[n].__win2->_y[y-1][x] != SPC; x--); s = x + 1; if (x) { for (x=0; s < T[n].__win2->_maxx - 1; x++,s++) { wmove(T[n].__win2,y-1,s); c = winch(T[n].__win2); waddch(T[n].__win2,SPC); mvwaddch(T[n].__win2,y,x,c); } } } w_backspace(n) int n; { int y, x; if (!T[n].__win2->_curx && (y = T[n].__win2->_cury)) { wmove(T[n].__win2,y-1,T[n].__win2->_maxx-1); for (x=T[n].__win2->_maxx-2; x >= 0; x--) { wmove(T[n].__win2,y-1,x); if (winch(T[n].__win2) != SPC) break; } wmove(T[n].__win2,y-1,x+1); } else waddch(T[n].__win2,8); } w_who() { int a, i, j, x, y; p_who(); y = LINES - 4; x = NUM_W / y; if (NUM_W % y) x++; if (NUM_W < y) y = NUM_W; x *= 16; if (SMART) W_WINDOW = newwin(y+3,x+4,LINES-(y+4),0); else W_WINDOW = newwin(y+3,x+4,0,0); box(W_WINDOW,'|','-'); mvwaddch(W_WINDOW,0,0,'.'); mvwaddch(W_WINDOW,y+2,0,'`'); mvwaddch(W_WINDOW,0,x+3,'.'); mvwaddch(W_WINDOW,y+2,x+3,'\''); mvwaddstr(W_WINDOW,0,2,"who"); for (i=j=a=0; a < NUM_W; a++) { if (p_check(W[a].W_tty,0) != -1) { wstandout(W_WINDOW); mvwaddstr(W_WINDOW,j+2,(i*16)+2," <"); } mvwaddstr(W_WINDOW,j+2,(i*16)+2,W[a].W_tty); mvwaddstr(W_WINDOW,j+2,(i*16)+6,W[a].W_username); wstandend(W_WINDOW); j++; if (j >= y) { j = 0; i++; } } wrefresh(W_WINDOW); delwin(W_WINDOW); } w_redraw(n) int n; { int a; if (SMART) { werase(SCREEN); for (a=0; a < NUM_T; a++) { if (!T[a].__dead) { overwrite(T[a].__win1,SCREEN); overwrite(T[a].__win2,SCREEN); } } if (n) touchwin(SCREEN); wrefresh(SCREEN); } } w_help() { if (SMART) H_WINDOW = newwin(14,40,LINES-15,COLS-40); else H_WINDOW = newwin(14,40,0,0); wprintw(H_WINDOW,".-help---------------------------------."); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"| Talk-mode commands: |"); wprintw(H_WINDOW,"| =================== |"); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"| ^L - redraw screen |"); wprintw(H_WINDOW,"| ^D - exit pwrite |"); wprintw(H_WINDOW,"| ESC - enter Command Mode |"); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"`-Press SPACE for more-----------------'"); wrefresh(H_WINDOW); while (getchar() != SPC); wclear(H_WINDOW); wprintw(H_WINDOW,".-help---------------------------------."); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"| Command Mode commands: |"); wprintw(H_WINDOW,"| ====================== |"); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"| a - add a user |"); wprintw(H_WINDOW,"| d - delete a user |"); wprintw(H_WINDOW,"| w - see who is on the system |"); wprintw(H_WINDOW,"| r - ring all unanswered users |"); wprintw(H_WINDOW,"| ^L - redraw screen |"); wprintw(H_WINDOW,"| ESC - return to Talk Mode |"); wprintw(H_WINDOW,"| ? - show these help pages |"); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"`-Press SPACE for more-----------------'"); wrefresh(H_WINDOW); while (getchar() != SPC); wclear(H_WINDOW); wprintw(H_WINDOW,".-help---------------------------------."); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"| Moving windows around: |"); wprintw(H_WINDOW,"| ---------------------- |"); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"| h j k l - move the four border |"); wprintw(H_WINDOW,"| corners left, down, up, |"); wprintw(H_WINDOW,"| or right. |"); wprintw(H_WINDOW,"| H J K L - change size. |"); wprintw(H_WINDOW,"| SPACE - select another window. |"); wprintw(H_WINDOW,"| @ - move window to fit |"); wprintw(H_WINDOW,"| within the four corners. |"); wprintw(H_WINDOW,"| |"); wprintw(H_WINDOW,"`-Press SPACE--------------------------'"); wrefresh(H_WINDOW); while (getchar() != SPC); delwin(H_WINDOW); w_redraw(1); } w_corners(n) int n; { int a; if (!SMART) return(0); if (n) { for (a=0; a < 4; a++) { wmove(curscr,C[a].C_y,C[a].C_x); C[a].C_under = winch(curscr); wmove(SCREEN,C[a].C_y,C[a].C_x); wstandout(SCREEN); if (a % 2) waddch(SCREEN,']'); else waddch(SCREEN,'['); wstandend(SCREEN); } } else { for (a=0; a < 4; a++) { wmove(SCREEN,C[a].C_y,C[a].C_x); waddch(SCREEN,C[a].C_under); } } wrefresh(SCREEN); } w_mvcorners(y,x,j,i) int y, x, j, i; { if (!SMART) return(0); C[0].C_y += y; C[0].C_x += x; C[1].C_y += y; C[1].C_x += i; C[2].C_y += j; C[2].C_x += x; C[3].C_y += j; C[3].C_x += i; if (C[0].C_y < 0 || C[0].C_y >= (LINES - (C[2].C_y - C[0].C_y))) { C[0].C_y -= y; C[1].C_y -= y; } if (C[0].C_x < 0 || C[0].C_x >= (COLS - (C[1].C_x - C[0].C_x))) { C[0].C_x -= x; C[2].C_x -= x; } if (C[3].C_y < (C[0].C_y+4) || C[3].C_y >= LINES) { C[2].C_y -= j; C[3].C_y -= j; } if (C[3].C_x < (C[0].C_x+7) || C[3].C_x >= COLS) { C[1].C_x -= i; C[3].C_x -= i; } } w_change() { if (!SMART) return(0); delwin(T[CURRENT_WINDOW].__win1); delwin(T[CURRENT_WINDOW].__win2); D[CURRENT_WINDOW].D_ysize = C[2].C_y - C[0].C_y + 1; D[CURRENT_WINDOW].D_xsize = C[1].C_x - C[0].C_x + 1; D[CURRENT_WINDOW].D_y = C[0].C_y; D[CURRENT_WINDOW].D_x = C[0].C_x; w_new_user(CURRENT_WINDOW); w_redraw(1); } w_nextcorners() { if (!SMART) return(0); do { if (++CURRENT_WINDOW >= NUM_T) CURRENT_WINDOW = 0; } while (T[CURRENT_WINDOW].__dead); w_setcorners(CURRENT_WINDOW); } SHAR_EOF #That's all folks! exit 0