home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume3 / sys5-phone < prev    next >
Text File  |  1989-02-03  |  11KB  |  479 lines

  1. Path: xanth!mcnc!gatech!bloom-beacon!husc6!spdcc!ima!necntc!ncoast!allbery
  2. From: jack@swlabs.UUCP (Jack Bonn)
  3. Newsgroups: comp.sources.misc
  4. Subject: v03i086: VAX-like Phone Utility for SysV
  5. Message-ID: <1551@swlabs.UUCP>
  6. Date: 17 Jul 88 16:46:08 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: jack@swlabs.UUCP (Jack Bonn)
  9. Organization: Software Labs, Ltd. Easton, CT USA
  10. Lines: 466
  11. Approved: allbery@ncoast.UUCP
  12.  
  13. Posting-number: Volume 3, Issue 86
  14. Submitted-by: "Jack Bonn" <jack@swlabs.UUCP>
  15. Archive-name: sys5-phone
  16.  
  17. [Another "talk" clone.  ++bsa]
  18.  
  19. #!/bin/sh
  20. # shar:    Shell Archiver  (v1.22)
  21. #
  22. #    Run the following text with /bin/sh to create:
  23. #      phone.1
  24. #      phone.c
  25. #      Makefile
  26. #
  27. sed 's/^X//' << 'SHAR_EOF' > phone.1 &&
  28. X.TH PHONE 1 "July 17, 1988"
  29. X.UC 4
  30. X.SH NAME
  31. Xphone \- phone another user, typing screen to screen.
  32. X.SH SYNOPSIS
  33. Xphone user
  34. X.SH DESCRIPTION
  35. X.I Phone 
  36. Xcauses a message to appear on the terminal being used by
  37. X.I user
  38. Xthat indicates that someone is trying to phone him.  
  39. XIf the other user also executes phone, then both screens are cleared
  40. Xand the users are set up in a two way conversation.
  41. X.PP
  42. XEach user's input is displayed at the bottom of their own
  43. Xscreen and at the top of the other user's screen.  The
  44. Xfollowing control characters are handled:
  45. X.TP 20
  46. X.BI "ERASE\ (Control\ H)"
  47. XErase the character before the cursor.
  48. X.TP
  49. X.BI "KILL\ (Control\ U)"
  50. XErase the line the cursor is on and move the cursor to the beginning 
  51. Xof the (now blank) line.
  52. X.TP
  53. X.BI "Control\ L"
  54. XRefresh your own screen.
  55. X.TP
  56. X.BI "Control\ G"
  57. XEither flash (preferably) or ring the bell on other user's terminal.
  58. X.TP
  59. X.BI "EOF\ (Control\ D)"
  60. XDiscontinue execution.  The other user is informed.
  61. X.PP
  62. X(The characters in parenthesis above are typical assignments
  63. Xfor these control characters.  Those assigned by the user
  64. Xwill be used.  See STTY(1)).
  65. X.SH BUGS
  66. X.I Phone
  67. Xhandles only two users.  If a third user attempts entry into
  68. Xa conversation, strange things happen.
  69. X.PP
  70. XWorks only when each user is logged in once.  An error
  71. Xmessage is indicated otherwise (although a "-d tty" option
  72. Xwould be an obvious extension).
  73. X.PP
  74. XRequires System V, since it uses Sys V IPC.
  75. X.SH AUTHOR
  76. XJack Bonn
  77. X.br
  78. XSoftware Labs, Ltd.
  79. X.br
  80. XBox 451
  81. X.br
  82. XEaston, CT  06612
  83. X.PP
  84. Xjack@swlabs.UUCP
  85. X.br
  86. Xuunet!swlabs!jack
  87. SHAR_EOF
  88. chmod 0640 phone.1 || echo "restore of phone.1 fails"
  89. sed 's/^X//' << 'SHAR_EOF' > phone.c &&
  90. X#include <sys/param.h>
  91. X#include <sys/types.h>
  92. X#include <sys/ipc.h>
  93. X#include <sys/msg.h>
  94. X#include <utmp.h>
  95. X#include <signal.h>
  96. X#include <curses.h>
  97. X#include <stdio.h>
  98. X#include <string.h>
  99. X
  100. X#define SAME        0    /* For calls to strcmp */
  101. X#define CTRL_G        ('G'-'A'+1)
  102. X#define CTRL_L        ('L'-'A'+1)
  103. X
  104. X/*
  105. X    packet.type is one of these --
  106. X*/
  107. X#define    ERASE        1    /* Erase previous character */
  108. X#define    KILL        2    /* Erase line cursor is on */
  109. X#define    DISPLAY        3    /* Display character on screen */
  110. X#define    ADIOS        4    /* Hang up/disolve connection */
  111. X#define    REFRESH        5    /* Redraw screen on CTL-L */
  112. X#define    FLASH        6    /* Ring bell/flash screen */
  113. X
  114. X/*
  115. X    packet.origin is one of these --
  116. X*/
  117. X#define    LOCAL        0
  118. X#define    REMOTE        1
  119. X
  120. X#define    IPC_ID        230    /* Upper part of key (for uniqueness) */
  121. X#define RING_TIME    10    /* Ring cadence in seconds */
  122. X
  123. Xint pid = 0;            /* pid for offspring, if non-zero */
  124. X
  125. Xint loc_q, rem_q;        /* message queue id's */
  126. Xkey_t my_key, other_key;    /* keys for the two queues */
  127. Xkey_t ftok();            /* convert a file to a key */
  128. X
  129. Xchar *my_name, *other_name;    /* Both user names */
  130. X
  131. Xchar *my_tty;            /* Path of my device */
  132. Xchar other_tty[24];        /* Path of other users device */
  133. X
  134. Xint erase_ch, kill_ch, eof_ch;    /* Special control chars for user */
  135. X
  136. XWINDOW *topwin, *botwin;    /* curses windows */
  137. XWINDOW *topleg, *botleg;    /* windows for legends */
  138. Xstruct utmp *u_elem, *getutent();
  139. Xstruct termio new_ioargs, old_ioargs;
  140. X
  141. Xstruct packet            /* This is the packet that we ipc */
  142. X{
  143. X    long type;
  144. X    int origin;
  145. X    char keypress;
  146. X} s_pkt, r_pkt;
  147. X
  148. Xvoid wrapup();            /* Forward reference */
  149. Xvoid wrapup_child();        /* Forward reference */
  150. Xvoid exit();
  151. X
  152. Xmain(argc,argv)
  153. X    int argc;
  154. X    char *argv[];
  155. X    {
  156. X
  157. X    if (argc != 2) {
  158. X    printf ("usage: phone user\n");
  159. X    exit(1);
  160. X    }
  161. X
  162. X    signal (SIGINT, wrapup);
  163. X
  164. X    get_names(argv[1]);        /* Get our name and other user's */
  165. X
  166. X    if (!get_ttys())        /* Get our tty and other user's */
  167. X    wrapup();
  168. X
  169. X    get_keys();
  170. X
  171. X    if (!open_queues())
  172. X    wrapup();
  173. X
  174. X    init_screen();
  175. X
  176. X    if (pid=fork()) {
  177. X    scrn_proc();    /* Returns when ADIOS packet received */
  178. X    wrapup();
  179. X    } else {
  180. X    signal (SIGQUIT, wrapup_child);
  181. X    key_proc();    /* Never returns, must be killed */
  182. X    }
  183. X    /* NOTREACHED */
  184. X}
  185. X
  186. Xvoid wrapup () {
  187. X    int ret_code;            /* Wait insists on an argument */
  188. X    struct msqid_ds buf;
  189. X
  190. X    if (pid) {                /* Kill sibbling if present */
  191. X    kill (pid, SIGQUIT);
  192. X    wait (&ret_code);
  193. X    }
  194. X
  195. X    endwin();                /* Clean up curses windows */
  196. X    msgctl (loc_q, IPC_RMID, &buf);    /* Remove our message queue */
  197. X    send_remote (ADIOS, 0);        /* In case other side is still up */
  198. X    exit(0);
  199. X}
  200. X
  201. Xkey_proc() {
  202. X    int ch;
  203. X
  204. X    /* Keyboard process */
  205. X
  206. X    init_kbd();
  207. X
  208. X    for (;;) {
  209. X    ch=getchar();
  210. X
  211. X        if (ch == erase_ch)
  212. X        send_both (ERASE, 0);
  213. X
  214. X        else if (ch == kill_ch)
  215. X        send_both (KILL, 0);
  216. X
  217. X        else if (ch == CTRL_L)
  218. X        send_local (REFRESH, 0);
  219. X
  220. X        else if (ch == CTRL_G)
  221. X        send_both (FLASH, 0);
  222. X
  223. X    else if (ch == eof_ch)
  224. X        send_local (ADIOS, 0);
  225. X
  226. X        else {
  227. X            if (ch == '\r')
  228. X        ch = '\n';
  229. X        send_both (DISPLAY, ch);
  230. X
  231. X        }
  232. X    }
  233. X}
  234. X
  235. Xvoid wrapup_child () {
  236. X    reset_kbd();            /* Put ioctl stuff where it was */
  237. X    exit(0);
  238. X}
  239. X
  240. Xscrn_proc() {
  241. X    int y, x;
  242. X    int ch;
  243. X    WINDOW *window;            /* temp curses windows */
  244. X
  245. X    /* Screen process */
  246. X
  247. X    scrn_legend (topleg, other_name, other_tty);
  248. X    scrn_legend (botleg, my_name, my_tty);
  249. X
  250. X    wrefresh (topwin);
  251. X    wrefresh (botwin);
  252. X
  253. X    do {
  254. X    msgrcv (loc_q, &r_pkt, sizeof(r_pkt) - sizeof(r_pkt.type), 0L, 0);
  255. X
  256. X    if (r_pkt.origin == LOCAL)
  257. X        window = botwin;
  258. X        else
  259. X        window = topwin;
  260. X
  261. X        ch = r_pkt.keypress;
  262. X
  263. X    switch ((int)r_pkt.type) {
  264. X
  265. X    case ERASE:
  266. X        waddch(window, '\b');
  267. X        wdelch(window);
  268. X        break;
  269. X
  270. X    case KILL:
  271. X        wdeleteln(window);
  272. X        getyx(window, y, x);
  273. X        wmove(window, y, 0);
  274. X        break;
  275. X
  276. X    case DISPLAY:
  277. X        waddch (window, (char)ch);
  278. X        break;
  279. X
  280. X    case ADIOS:
  281. X        if (r_pkt.origin == REMOTE)
  282. X            wprintw(botwin, "\n*** %s has hung up. ***\n", other_name);
  283. X        break;
  284. X
  285. X    case REFRESH:
  286. X        clearok(curscr, TRUE);
  287. X        break;
  288. X
  289. X    case FLASH:
  290. X        flash();
  291. X        break;
  292. X
  293. X    }
  294. X
  295. X    if (r_pkt.origin == REMOTE)
  296. X        wrefresh (topwin);
  297. X
  298. X    wrefresh (botwin);
  299. X
  300. X    } while (r_pkt.type != ADIOS);
  301. X}
  302. X
  303. Xint open_queues()
  304. X    {
  305. X    int seconds;
  306. X
  307. X    loc_q = msgget (my_key, 0666 | IPC_CREAT);
  308. X
  309. X    if (loc_q == -1) {
  310. X    printf ("Unable to create my queue\n");
  311. X    return (FALSE);
  312. X    }
  313. X
  314. X    /*
  315. X    Stand on our head to test creation of rem_q more often 
  316. X    than when we ring the other user.
  317. X    */
  318. X    for (seconds=RING_TIME; ; seconds++) {
  319. X    rem_q = msgget (other_key, 0);
  320. X
  321. X    if (rem_q != -1)
  322. X        break;
  323. X
  324. X    if (seconds == RING_TIME) {
  325. X        seconds = 0;
  326. X        if (!ring (other_tty)) {
  327. X        printf ("%s's phone is off the hook (mesg -n).\n\n", other_name);
  328. X        return (FALSE);
  329. X        }
  330. X        printf ("Ringing %s on %.14s\n\n", other_name, other_tty);
  331. X    }
  332. X    if (sleep (1))    /* != 0 if interrupted by other signal */
  333. X        return (FALSE);
  334. X    }
  335. X    return (TRUE);
  336. X}
  337. X
  338. Xinit_screen() {
  339. X    initscr();
  340. X    topleg = newwin(1,0,0,0);
  341. X    topwin = newwin(10,0,1,0);
  342. X    botleg = newwin(1,0,12,0);
  343. X    botwin = newwin(10,0,13,0);
  344. X    idlok(topwin,TRUE);
  345. X    idlok(botwin,TRUE);
  346. X    scrollok(topwin,TRUE);
  347. X    scrollok(botwin,TRUE);
  348. X}
  349. X
  350. Xinit_kbd() {
  351. X    ioctl (0, TCGETA, &old_ioargs);
  352. X    erase_ch = old_ioargs.c_cc[VERASE];
  353. X    kill_ch = old_ioargs.c_cc[VKILL];
  354. X    eof_ch = old_ioargs.c_cc[VEOF];
  355. X    new_ioargs = old_ioargs;
  356. X    new_ioargs.c_lflag &= ~(ICANON | ECHO);
  357. X    new_ioargs.c_cc[VMIN] = (char)1;
  358. X    ioctl (0, TCSETA, &new_ioargs);
  359. X}
  360. X
  361. Xreset_kbd() {
  362. X    ioctl (0, TCSETA, &old_ioargs);
  363. X}
  364. X
  365. Xget_names(cmd_arg)
  366. X    char *cmd_arg;
  367. X    {
  368. X    char *getenv();
  369. X
  370. X    my_name = getenv("LOGNAME");
  371. X    other_name = cmd_arg;
  372. X    }
  373. X
  374. Xint get_ttys()
  375. X{
  376. X    int found;
  377. X    char *ttyname();
  378. X
  379. X    my_tty = ttyname(0);
  380. X    found=0;
  381. X    while(u_elem=getutent()) {
  382. X
  383. X    if (strcmp(u_elem->ut_user, other_name) == SAME) {
  384. X        found++;
  385. X        strcpy(other_tty, "/dev/");
  386. X        strncpy(&other_tty[5], u_elem->ut_line, sizeof(u_elem->ut_line));
  387. X    }
  388. X    }
  389. X    if (found != 1) {
  390. X    if (found == 0)
  391. X        printf("User %s is not logged in.\n", other_name);
  392. X    else
  393. X        printf("User %s is logged in more than once.\n", other_name);
  394. X    return (FALSE);
  395. X    }
  396. X    return (TRUE);
  397. X}
  398. X
  399. Xget_keys()    /* Get unique keys for naming message queues */
  400. X{
  401. X    my_key = ftok (my_tty, IPC_ID);
  402. X    other_key = ftok (other_tty, IPC_ID);
  403. X}
  404. X
  405. Xint ring (device)
  406. X    char *device;
  407. X    {
  408. X    FILE *out_s;
  409. X
  410. X    if (!(out_s = fopen (device, "w")))
  411. X    return (FALSE);
  412. X
  413. X    fprintf (out_s, "\n%s is phoning you.\n", my_name);
  414. X    fprintf (out_s, "Type 'phone %s' to answer.\007\n\n", my_name);
  415. X    fclose (out_s);
  416. X    return (TRUE);
  417. X}
  418. X
  419. Xscrn_legend (window, user, terminal)
  420. X    WINDOW *window;
  421. X    char *user;
  422. X    char *terminal;
  423. X    {
  424. X    char buffer[40];
  425. X
  426. X    wattron (window, A_REVERSE | A_BOLD);
  427. X    sprintf (buffer, "%s (%s):", user, terminal);
  428. X    wprintw (window, "%-*s", COLS, buffer);
  429. X    wrefresh (window);
  430. X    }
  431. X
  432. Xsend_local (type, ch)
  433. X    int type;
  434. X    int ch;
  435. X    {
  436. X    s_pkt.type = type;
  437. X    s_pkt.keypress = ch;
  438. X    s_pkt.origin = LOCAL;
  439. X    msgsnd (loc_q, &s_pkt, sizeof(s_pkt) - sizeof(s_pkt.type), 0);
  440. X    }
  441. X
  442. Xsend_remote (type, ch)
  443. X    int type;
  444. X    int ch;
  445. X    {
  446. X    s_pkt.type = type;
  447. X    s_pkt.keypress = ch;
  448. X    s_pkt.origin = REMOTE;
  449. X    msgsnd (rem_q, &s_pkt, sizeof(s_pkt) - sizeof(s_pkt.type), 0);
  450. X    }
  451. X
  452. Xsend_both (type, ch)
  453. X    int type;
  454. X    int ch;
  455. X    {
  456. X    send_local (type, ch);
  457. X    send_remote (type, ch);
  458. X    }
  459. SHAR_EOF
  460. chmod 0644 phone.c || echo "restore of phone.c fails"
  461. sed 's/^X//' << 'SHAR_EOF' > Makefile &&
  462. Xphone:    phone.c
  463. X    cc phone.c -o phone -lcurses
  464. X
  465. Xlint:
  466. X    lint phone.c -lcurses
  467. X
  468. Xinstall:
  469. X    cp phone /usr/lbin
  470. X
  471. Xshar:
  472. X    shar phone.1 phone.c Makefile >phone.sh
  473. SHAR_EOF
  474. chmod 0640 Makefile || echo "restore of Makefile fails"
  475. exit 0
  476. -- 
  477. Jack Bonn, <> Software Labs, Ltd, Box 451, Easton CT  06612
  478. uunet!swlabs!jack
  479.