Phone utility for Sys V (chat screen to screen/uses curses)

Jack Bonn jack at swlabs.UUCP
Tue Jun 14 01:49:27 AEST 1988


#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  phone.doc
#	  phone.c
#	  Makefile
#
sed 's/^X//' << 'SHAR_EOF' > phone.doc &&
X	phone(1)						phone(1)
X
X	NAME
X		phone - phone another user, typing screen to screen.
X
X	SYNOPSIS
X		phone user
X
X	DESCRIPTION
X		phone causes text to appear on user's terminal indicating
X		that someone is trying to phone him.  If he also executes
X		phone, the two users are set up in a two way conversation.
X
X		Each user's input is displayed at the bottom of their own
X		screen and at the top of the other user's screen.  The
X		following control characters are handled:
X
X	        ERASE (Control H)	Erase character before the cursor.
X
X	        KILL (Control U)	Erase line cursor is on and move the
X					cursor to the beginning of the line.
X
X	        Control L		Refresh your own screen.
X
X	        Control G		Either flash (preferably) or ring bell
X					on other user's terminal.
X
X		EOF (Control D)		Discontinue execution.  Other user is
X					informed.
X
X		(The characters in parenthesis above are typical assignments
X		for these control characters.  Those assigned by the user
X		will be used.  See STTY(1)).
X
X	BUGS
X		Handles only two users.  If a third user attempts entry into
X		a conversation, strange things happen.
X
X		Only works when each user is only logged in once.  An error
X		message is indicated otherwise (although a "-d tty" option
X		would handle things better).
X
X		Requires System V, since it uses Sys V IPC.
X
X
X	Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT  06612
X	uunet!swlabs!jack
SHAR_EOF
chmod 0666 phone.doc || echo "restore of phone.doc fails"
sed 's/^X//' << 'SHAR_EOF' > phone.c &&
X#include <sys/types.h>
X#include <sys/ipc.h>
X#include <sys/msg.h>
X#include <utmp.h>
X#include <signal.h>
X#include <termio.h>
X#include <curses.h>
X#include <stdio.h>
X
X#define SAME	0
X#define CTRL_G	('G'-'A'+1)
X#define CTRL_L	('L'-'A'+1)
X
X/*
X	packet.type is one of these --
X*/
X#define	ERASE	1	/* Erase previous character */
X#define	KILL	2	/* Erase line cursor is on */
X#define	DISPLAY	3	/* Display character on screen */
X#define	ADIOS	4	/* Hang up/disolve connection */
X#define	REFRESH	5	/* Redraw screen on CTL-L */
X#define	FLASH	6	/* Ring bell/flash screen */
X
X/*
X	packet.origin is one of these --
X*/
X#define	LOCAL	0
X#define	REMOTE	1
X
X#define	IPC_ID	230		/* Upper part of key (for uniqueness) */
X
Xint pid = 0;			/* pid for offspring, if non-zero */
X
Xint loc_q, rem_q;		/* message queue id's */
Xkey_t my_key, other_key;	/* keys for the two queues */
Xkey_t ftok();			/* convert a file to a key */
X
Xchar other_tty[24];		/* Path of other users device */
X
Xint erase_ch, kill_ch, eof_ch;	/* Special control chars for user */
X
XWINDOW *topwin, *botwin, *window; /* curses windows */
Xstruct utmp *getutent(),*u_elem;
Xstruct termio new_ioargs, old_ioargs;
X
Xstruct packet			/* This is the packet that we ipc */
X{
X    long type;
X    int origin;
X    char keypress;
X} s_pkt, r_pkt;
X
Xvoid wrapup();			/* Forward reference */
Xvoid wrapup_child();		/* Forward reference */
X
Xmain(argc,argv)
X    int argc;
X    char *argv[];
X    {
X
X    if (argc != 2) {
X	printf ("usage: phone user\n");
X	exit(1);
X    }
X
X    signal (SIGINT, wrapup);
X
X    if (!get_keys(argv[1]))
X	wrapup();
X
X    if (!open_queues(argv[1]))
X	wrapup();
X
X    init_screen();
X
X    if (pid=fork()) {
X	screen_proc();	/* Returns when ADIOS packet received */
X	wrapup();
X    } else {
X	signal (SIGQUIT, wrapup_child);
X	key_proc();	/* Never returns, must be killed */
X    }
X}
X
Xvoid wrapup () {
X    int ret_code;			/* Wait insists on an argument */
X
X    if (pid) {				/* Kill sibbling if present */
X	kill (pid, SIGQUIT);
X	wait (&ret_code);
X    }
X
X    endwin();				/* Clean up curses windows */
X    msgctl (loc_q, IPC_RMID, &s_pkt);	/* Remove our message queue */
X    exit(0);
X}
X
Xkey_proc() {
X    int ch;
X
X    /* Keyboard process */
X
X    init_kbd();
X
X    for (;;) {
X	ch=getchar();
X
X        if (ch == erase_ch)
X	    send_loc_rem (ERASE, 0);
X
X        else if (ch == kill_ch)
X	    send_loc_rem (KILL, 0);
X
X        else if (ch == CTRL_L)
X	    send_local (REFRESH, 0);
X
X        else if (ch == CTRL_G)
X	    send_loc_rem (FLASH, 0);
X
X	else if (ch == eof_ch)
X	    send_loc_rem (ADIOS, 0);
X
X        else {
X            if (ch == '\r')
X		ch = '\n';
X	    send_loc_rem (DISPLAY, ch);
X
X        }
X    }
X}
X
Xvoid wrapup_child () {
X    reset_kbd();			/* Put ioctl stuff where it was */
X    exit(0);
X}
X
Xscreen_proc() {
X    int y, x;
X    int ch;
X
X    /* Screen process */
X
X    wrefresh (topwin);
X    wrefresh (botwin);
X
X    do {
X	msgrcv (loc_q, &r_pkt, sizeof(r_pkt) - sizeof(r_pkt.type), 0);
X
X	if (r_pkt.origin == LOCAL)
X	    window = botwin;
X        else
X	    window = topwin;
X
X        ch = r_pkt.keypress;
X
X	switch (r_pkt.type) {
X
X	case ERASE:
X	    waddch(window, '\b');
X	    wdelch(window);
X	    break;
X
X	case KILL:
X	    wdeleteln(window);
X	    getyx(window, y, x);
X	    wmove(window, y, 0);
X	    break;
X
X	case DISPLAY:
X	    waddch (window, ch);
X	    break;
X
X	case ADIOS:
X	    if (r_pkt.origin == REMOTE)
X	        waddstr(botwin, "\n*** Other user has hung up. ***\n");
X	    break;
X
X	case REFRESH:
X	    clearok(curscr, TRUE);
X	    break;
X
X	case FLASH:
X	    flash();
X	    break;
X
X	}
X
X	if (r_pkt.origin == REMOTE)
X	    wrefresh (topwin);
X
X	wrefresh (botwin);
X
X    } while (r_pkt.type != ADIOS);
X}
X
Xint open_queues(user)
X    char *user;
X    {
X
X    loc_q = msgget (my_key, 0666 | IPC_CREAT);
X
X    if (loc_q == -1) {
X	printf ("Unable to create my queue\n");
X	return (FALSE);
X    }
X
X    for (;;) {
X	rem_q = msgget (other_key, 0);
X
X	if (rem_q != -1)
X	    break;
X
X	if (!ring (other_tty)) {
X	    printf ("%s's phone is off the hook (mesg -n).\n\n", user);
X	    return (FALSE);
X	}
X
X	printf ("Ringing %s on %.14s\n\n", user, other_tty);
X	sleep (5);
X    }
X    return (TRUE);
X}
X
Xinit_screen() {
X    initscr();
X    topwin = newwin(12,COLS,0,0);
X    botwin = newwin(12,COLS,12,0);
X    idlok(topwin,TRUE);
X    idlok(botwin,TRUE);
X    scrollok(topwin,TRUE);
X    scrollok(botwin,TRUE);
X}
X
Xinit_kbd() {
X    ioctl (0, TCGETA, &old_ioargs);
X    erase_ch = old_ioargs.c_cc[VERASE];
X    kill_ch = old_ioargs.c_cc[VKILL];
X    eof_ch = old_ioargs.c_cc[VEOF];
X    new_ioargs = old_ioargs;
X    new_ioargs.c_lflag &= ~(ICANON | ECHO);
X    new_ioargs.c_cc[VMIN] = (char)1;
X    ioctl (0, TCSETA, &new_ioargs);
X}
X
Xreset_kbd() {
X    ioctl (0, TCSETA, &old_ioargs);
X}
X
Xint get_keys(user)	/* Get unique keys for naming message queues */
X    char *user;
X    {
X    int found;
X    char *my_tty, *ttyname();
X
X    my_tty = ttyname(0);
X    my_key = ftok (my_tty, IPC_ID);
X
X    found=0;
X    while(u_elem=getutent()) {
X
X	if (strcmp(u_elem->ut_user, user) == SAME) {
X	    found++;
X	    strcpy(other_tty, "/dev/");
X	    strncpy(&other_tty[5], u_elem->ut_line, sizeof(u_elem->ut_line));
X	}
X
X    }
X
X    if (found != 1) {
X
X	if (found == 0)
X	    printf("User %s is not logged in.\n", user);
X	else
X	    printf("User %s is logged in more than once.\n", user);
X	return (FALSE);
X    }
X
X    other_key = ftok (other_tty, IPC_ID);
X
X    return (TRUE);
X}
X
Xint ring (device)
X    char *device;
X    {
X    char *getenv(), *my_name;
X    FILE *out_s;
X
X    my_name = getenv("LOGNAME");
X
X    if (!(out_s = fopen (device, "w")))
X	return (FALSE);
X
X    fprintf (out_s, "\n%s is phoning you.\n", my_name);
X    fprintf (out_s, "Type 'phone %s' to answer.\007\n\n", my_name);
X    fclose (out_s);
X    return (TRUE);
X}
X
Xsend_local (type, ch)
X    int type;
X    int ch;
X    {
X    s_pkt.type = type;
X    s_pkt.keypress = ch;
X    s_pkt.origin = LOCAL;
X    msgsnd (loc_q, &s_pkt, sizeof(s_pkt) - sizeof(s_pkt.type), 0);
X    }
X
Xsend_remote (type, ch)
X    int type;
X    int ch;
X    {
X    s_pkt.type = type;
X    s_pkt.keypress = ch;
X    s_pkt.origin = REMOTE;
X    msgsnd (rem_q, &s_pkt, sizeof(s_pkt) - sizeof(s_pkt.type), 0);
X    }
X
Xsend_loc_rem (type, ch)
X    int type;
X    int ch;
X    {
X    send_local (type, ch);
X    send_remote (type, ch);
X    }
SHAR_EOF
chmod 0666 phone.c || echo "restore of phone.c fails"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
Xphone:	phone.c
X	cc -g phone.c -o phone -lcurses
X
Xinstall:
X	cp phone /usr/lbin
X
Xshar:
X	shar phone.doc phone.c Makefile >phone.sh
SHAR_EOF
chmod 0666 Makefile || echo "restore of Makefile fails"
exit 0
-- 
Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT  06612
uunet!swlabs!jack



More information about the Alt.sources mailing list