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