home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / net / talk.sys5 < prev    next >
Internet Message Format  |  1986-06-04  |  18KB

  1. From nwh@hrc63.UUCP (Nigel Holder Marconi) Tue Jun  3 06:27:09 1986
  2. Path: seismo!mcvax!ukc!hrc63!nwh
  3. From: nwh@hrc63.UUCP (Nigel Holder Marconi)
  4. Newsgroups: net.sources
  5. Subject: Talk for Sys V
  6. Message-ID: <364@hrc63.UUCP>
  7. Date: 3 Jun 86 10:27:09 GMT
  8. Organization: GEC Hirst Research Labs, Wembley, Middlesex.
  9. Lines: 815
  10. Posted: Tue Jun  3 10:27:09 1986
  11.  
  12.  
  13.     Since > 20 people requested this program, I have placed in
  14. into the usenet domain.
  15.  
  16.     This is a talk utility for System V.  It is supplied
  17. on an as is basis, although I would welcome any feedback.
  18.  
  19.     Have fun talking !
  20.  
  21.  
  22. --- Cut Here -------------- Cut Here ---------------- Cut Here ------------
  23.  
  24. #!    /bin/sh
  25. #
  26. #    This is a shell archive, meaning:
  27. #
  28. #    1. Remove everything above the #! /bin/sh line.
  29. #    2. Save the resulting text in a file.
  30. #    3. Execute the file with /bin/sh (not csh) to create:
  31. #            README
  32. #            Makefile
  33. #            talk.mansrc
  34. #            talk.c
  35. #
  36. #
  37. # This archive created: Tue Jun  3 10:13:56 BST 1986
  38. echo shar: "extracting 'README'" '(145 characters)'
  39. cat << \SHAR_EOF > 'README'
  40.  
  41.     This is a talk utility for System V.  To make it simply
  42. type in 'make' or 'make talk'.  In order to format the manual
  43. page type in 'make man'.
  44. SHAR_EOF
  45. echo shar: "extracting 'Makefile'" '(125 characters)'
  46. cat << \SHAR_EOF > 'Makefile'
  47. #    Makefile for Sys V talk
  48. #
  49. talk:    talk.c
  50.     cc -O -o talk talk.c -lcurses
  51. man:    talk.mansrc
  52.     nroff -man talk.mansrc > talk.man
  53. SHAR_EOF
  54. echo shar: "extracting 'talk.mansrc'" '(2400 characters)'
  55. cat << \SHAR_EOF > 'talk.mansrc'
  56. .TH Talk 1
  57. .SH NAME
  58. talk \- talk to another user
  59. .SH SYNOPSIS
  60. .B talk user [ tty ]
  61. .SH DESCRIPTION
  62. .PP
  63. Talk is a utility that enables two users to interactively
  64. communicate on a character basis on split screens.
  65. It is intended to supersede the write utility for interactive
  66. use by providing a more useful service.
  67.  
  68. Talk is invoked with a user name and an optional tty name thus :-
  69.  
  70.         talk user [ tty8 ]
  71.  
  72. .PP
  73. If user happens to be logged in more than once and no tty name is
  74. supplied, talk will use the first entry in /etc/utmp (as used by who).
  75. .PP
  76. Talk will then attempt to notify the requested user that you are
  77. trying to talk with him.
  78. Trying to talk to a user may fail for two reasons :-
  79.  
  80.         The requested user is not logged in.
  81.  
  82.         The requested user has disabled messages (via mesg)
  83.  
  84. .PP
  85. If the user doesn't answer, talk will keep notifying him.
  86. After a reasonable number of retries, talk will give up and exit.
  87. .PP
  88. To reply to a user trying to talk to you, you should type
  89. talk user (as shown in the request message).
  90. .PP
  91. When your party has connected you may both begin to talk (this
  92. will be indicated by the bell ringing on your terminal).
  93. The name of the person you are talking to and an elapsed time
  94. indicator will appear in the centre of the screen.
  95. You will notice that there are bursts of input and
  96. output - this is due to the way they are handled within talk.
  97. In order to avoid busy waiting, a sleep of one
  98. second occurs whenever there is no activity.
  99. .bp
  100. .PP
  101. Certain characters when typed have special meaning :-
  102.  
  103.  
  104. ctrl-l    -    Refresh the screen.  Useful if the
  105.                screen gets corrupted.
  106.  
  107. ctrl-d    -    Disconnect - finish talking.
  108.  
  109. ctrl-g    -    Ring the bell on other users terminal.
  110.  
  111. delete    -    Delete the character before the cursor
  112.                (works backwards over lines as well).
  113.                Uses your normal delete key.
  114.  
  115. ctrl-c    -    Forced exit.  This has the same effect
  116.                as disconnect, although it may be
  117.                used at any stage of the proceedings
  118.                (ie. before connection has occured).
  119.  
  120.  
  121. .SH FILES
  122. /etc/utmp               to find recipient's tty
  123. /tmp/tr_xxxxxxxx        temporary files (named pipes) for
  124. /tmp/tw_xxxxxxxx        communication pickup
  125. .SH BUGS
  126. .PP
  127. One second delay between bursts of activity (to be fixed when using
  128. version 8).
  129. .PP
  130. Restricted to the domain of current machine.
  131. SHAR_EOF
  132. echo shar: "extracting 'talk.c'" '(14050 characters)'
  133. cat << \SHAR_EOF > 'talk.c'
  134. #ifndef    lint
  135. static char sccsid[] = "@(#)talk.c  1.2 [Nigel Holder -  Baddow] 12/06/85";
  136. #endif
  137.  
  138.  
  139. /***************************************
  140. *
  141. *    Author   :  Nigel Holder
  142. *
  143. *    Date     :  12 June 1985
  144. *             4 December 1985        changed elapsed time stuff
  145. *                        to be synchronous to windows
  146. *
  147. *
  148. *       Talk - an interactive communication program that allows users
  149. *    to talk on a character basis (as opposed to a line basis, as for
  150. *    the system write utility).
  151. *
  152. *       Written for System V as it uses named pipes !
  153. *
  154. *    Bugs:
  155. *
  156. *    1.   Not as good as BSD talk, but it suffices.
  157. *
  158. *    2.   Really need select() type statement (BSD) instead of sleeping
  159. *         for 1 second between no input or output activity
  160. *         - (version 8 should fix this).
  161. *
  162. *    3.   Should check for name fields in dividewin overflowing screenwidth
  163. *
  164. *    4.   Probably should disable CTRL-c stopping program
  165. *
  166. ***************************************/
  167.  
  168.  
  169. #include <curses.h>
  170. #include <signal.h>
  171. #include <sys/types.h>
  172. #include <sys/stat.h>
  173. #include <fcntl.h>
  174. #include <ctype.h>
  175. #include <pwd.h>
  176. #include <utmp.h>
  177. #include <sys/dir.h>
  178.  
  179.  
  180. #define        FIFO            ( 0010660 )
  181. #define        EXIST            ( 00 )
  182. #define         INWINLINES              ( LINES / 2 )
  183. #define         OUTWINLINES             ( LINES - INWINLINES - 1 )
  184. #define        CONNECT            ( 0xF0 )
  185. #define        DISCONNECT        ( 0xF3 )
  186. #define        DELETE            ( 0xFC )
  187. #define        END_OF_FILE        ( 0x04 )
  188. #define        REFRESH            ( 0x0C )
  189. #define        SPACE            ( 0x20 )
  190. #define        BELL            ( 0x07 )
  191. #define        CLOCK_TEMP        ( sizeof(elapsed) )
  192. #define        CLOCK_TICK        ( 15 )
  193. #define        RETRIES            ( 3 )
  194. #define        TRIES            ( RETRIES + 1 )
  195. #define        WAIT_TIME        ( 20 )
  196. #define        DIRPREFIX        ( sizeof(tempdir) + 20 )
  197.  
  198. #define        not_printable(x)    \
  199.                 (x != '\n'  &&  x != '\t'  &&  isprint(x) == 0) 
  200.  
  201. /*  --  globals  --  */
  202.  
  203. FILE    *writing = NULL;            /*  pipe to write down  */
  204. int    reading = -1;                /*  fd for keyboard  */
  205. int    connected = FALSE;            /*  whether actually talking  */
  206. int    failed = FALSE;                /*  couldn't connect  */
  207. int    forced = FALSE;                /*  ctrl-c stopped program  */
  208. int    time_changed = FALSE;            /*  to update elapsed time  */
  209.  
  210. WINDOW    *inwin, *outwin, *dividewin;        /*  the three windows  */
  211. int    inwinx, inwiny;                /*  cursor pos in each window */
  212. int    outwinx, outwiny;
  213. int    divwiny, divwinx;
  214.  
  215. char    elapsed[] = "[%02d:%02d:%02d]  ";    /*  format of elapsed time  */
  216. char    tempdir[] = "/tmp/";            /*  temp place for pipes  */
  217. char    wprefix[] = "tw_";            /*  prefix for pipes  */
  218. char    rprefix[] = "tr_";
  219. char    writefile[DIRSIZ + DIRPREFIX];        /*  temp pipe filenames  */
  220. char    readfile[DIRSIZ + DIRPREFIX];
  221. char    tmp[BUFSIZ];                /*  general purpose !  */
  222. char    *myname, *theirname, *theirtty;
  223. char    *progname;
  224.  
  225. int    master;                    /*  whether master or slave   */
  226. int    delchar;                /*  favourite delete char  */
  227.  
  228.  
  229.  
  230.  
  231. main(argc, argv)
  232.  
  233. int    argc;
  234. char    *argv[];
  235.  
  236. {
  237.     int    forced_die();
  238.     char    *strrchr(), *getlogin();
  239.  
  240.     if ((progname = strrchr(argv[0], '/')) != NULL)   {
  241.         ++progname;
  242.     }
  243.     else   {
  244.         progname = argv[0];
  245.     }
  246.     if (argc < 2)   {
  247.         fprintf(stderr, "usage: %s user [tty]\n", progname);
  248.         exit(1);
  249.     }
  250.     theirname = argv[1];
  251.     if (argc > 2)   {
  252.         theirtty = argv[2];
  253.     }
  254.     else   {
  255.         theirtty = "";
  256.     }
  257.     if ((myname = getlogin()) == NULL)   {
  258.         fprintf(stderr, "You don't exist. Go away.\n");
  259.         exit(2);
  260.     }
  261.     signal(SIGINT, SIG_IGN);        /*  play safe  */
  262.     signal(SIGHUP, SIG_IGN);
  263.     signal(SIGQUIT, SIG_IGN);
  264.  
  265.     screen_init();                /*  set up windows  */
  266.     signal(SIGINT, forced_die);        /*  gracefully trap signals  */
  267.     signal(SIGHUP, forced_die);
  268.     set_up_channel();            /*  establish named pipes  */
  269.     talk();            /*  let your fingers do the walking !  */
  270.     die();                    /*  should never get here !  */
  271.     exit(3);
  272. }
  273.  
  274.  
  275.  
  276. set_up_channel()        /*  establish connection between users  */
  277.  
  278. {
  279.     char    *nameof();
  280.     char    clock_temp[CLOCK_TEMP];
  281.  
  282.     sprintf(readfile, "%s%s%s%s", tempdir, rprefix, myname, theirname);
  283.     sprintf(writefile, "%s%s%s%s", tempdir, wprefix, myname, theirname);
  284.  
  285.     /*  check to see if any old connections lying around !  */
  286.     /*  they could be caused (left around) by system crashes etc.  */
  287.     if (( ! access(readfile, EXIST))  &&  out_of_date(readfile))   {
  288.         unlink(readfile);
  289.     }
  290.     if (( ! access(writefile, EXIST))  &&  out_of_date(writefile))   {
  291.         unlink(writefile);
  292.     }
  293.     wheader(inwin, "[No connection yet]\n");
  294.     sprintf(readfile, "%s%s%s%s", tempdir, wprefix, theirname, myname);
  295.     if (access(readfile, EXIST))   {
  296.         master = TRUE;
  297.         master_channel();
  298.         unlink(readfile);    /*  remove pipes (clever eh ?)  */
  299.         unlink(writefile);
  300.     }
  301.     else   {
  302.         master = FALSE;
  303.         slave_channel();
  304.     }
  305.     connected = TRUE;
  306.     wheader(inwin, "[Connected]\n");
  307.     beep();
  308.     sprintf(clock_temp, elapsed, 0, 0, 0);
  309.     sprintf(tmp, "  %s is talking to %s (%s) ",
  310.                     myname, theirname, nameof(theirname));
  311.         wmove(dividewin, 0, (COLS - strlen(tmp) - strlen(clock_temp)) / 2);
  312.     wstandout(dividewin);
  313.     waddstr(dividewin, tmp);
  314.     getyx(dividewin, divwiny, divwinx);
  315.     waddstr(dividewin, clock_temp);
  316.     wstandend(dividewin);
  317.         wrefresh(dividewin);
  318. }
  319.  
  320.  
  321.  
  322. out_of_date(file_ptr)    /*  determine whether pipe file is not in use  */
  323.  
  324. char    *file_ptr;
  325.  
  326. {
  327.     long    time();
  328.     struct stat    stat_buf;
  329.  
  330.     if (stat(file_ptr, &stat_buf) == -1)   {   /*  assume doesn't exist  */
  331.         return(FALSE);
  332.     }
  333.     if ((time((long *) 0) - stat_buf.st_mtime) > (TRIES * WAIT_TIME))   {
  334.         return(TRUE);
  335.     }
  336.     return(FALSE);
  337. }
  338.  
  339.  
  340.  
  341. /*  create named pipes for connection to slave and try to connect  */
  342.  
  343. master_channel()
  344.  
  345. {
  346.     static char    *retry[] =   {
  347.                 "1st retry",
  348.                 "2nd retry",
  349.                 "3rd retry",
  350.                 "4th retry"
  351.     };
  352.  
  353.     char    *dialup();
  354.     int    retries, waiting;
  355.     char    *retry_message, *dialtty, c;
  356.  
  357.     sprintf(readfile, "%s%s%s%s", tempdir, rprefix, myname, theirname);
  358.     umask(0);
  359.     if (mknod(readfile, FIFO) == -1)   {
  360.         error("can't create %s", readfile);
  361.     }
  362.     if (mknod(writefile, FIFO) == -1)   {
  363.         error("can't create %s", writefile);
  364.     }
  365.     open_channel();
  366.     dialtty = dialup(CONNECT);
  367.     sprintf(tmp, "[Waiting for your party to respond on %s]\n", dialtty);
  368.     wheader(inwin, tmp);
  369.     c = DISCONNECT;
  370.     for (retries = 0 ; c != CONNECT  &&  retries <= RETRIES ; ++retries)   {
  371.         for (waiting = 0 ; c != CONNECT  &&
  372.                 waiting < WAIT_TIME ; ++waiting)   {
  373.             sleep(1);
  374.             read(reading, &c, 1);
  375.         }
  376.         if (c != CONNECT  &&  retries < RETRIES)   {
  377.             if (retries < (sizeof(retry) / sizeof(char *)))   {
  378.                 retry_message = retry[retries];
  379.             }
  380.             else   {
  381.                 retry_message = "Lost count !";
  382.             }
  383.             dialtty = dialup(CONNECT);
  384.             sprintf(tmp, "[Ringing your party again on %s (%s)]\n",
  385.                             dialtty, retry_message);
  386.             wheader(inwin, tmp);
  387.         }
  388.     }
  389.     if (c != CONNECT)   {
  390.         failed = TRUE;
  391.         wheader(inwin, "[Your party would not respond]\n");
  392.         die();
  393.     }
  394. }
  395.  
  396.  
  397.  
  398. slave_channel()        /*  form file names for slave connection  */
  399.  
  400. {
  401.     sprintf(readfile, "%s%s%s%s", tempdir, wprefix, theirname, myname);
  402.     sprintf(writefile, "%s%s%s%s", tempdir, rprefix, theirname, myname);
  403.     open_channel();
  404.     putc(CONNECT, writing);
  405. }
  406.  
  407.  
  408.  
  409. open_channel()            /*  establish communications via pipes  */
  410.  
  411. {
  412.     FILE    *fopen();
  413.  
  414.     if ((writing = fopen(writefile, "w+")) == NULL)   {
  415.         error("can't open FIFO for writing");
  416.     }
  417.     setbuf(writing, (char *) 0);    /*  unbuffer stream  */
  418.     if ((reading = open(readfile, O_NDELAY | O_RDONLY)) == -1)   {
  419.         error("can't open FIFO for reading");
  420.     }
  421. }
  422.  
  423.  
  424.  
  425. wheader(win, message)        /*  print message at head of window  */
  426.  
  427. WINDOW    *win;
  428. char    *message;
  429.  
  430. {
  431.     wmove(win, 0, 0);
  432.     wclrtoeol(win);
  433.     waddstr(win, message);
  434.     wrefresh(win);
  435. }
  436.  
  437.  
  438.  
  439. screen_init()                /*  initialise talk windows  */
  440.  
  441. {
  442.         int    i;
  443.  
  444.         initscr();
  445.         inwin = newwin(INWINLINES, COLS, 0, 0);
  446.         outwin = newwin(OUTWINLINES, COLS, INWINLINES + 1, 0);
  447.         dividewin = newwin(1, COLS, INWINLINES, 0);
  448.     noecho();
  449.     nodelay(inwin, TRUE);
  450.     cbreak();
  451.         scrollok(inwin, TRUE);
  452.         scrollok(outwin, TRUE);
  453.     idlok(inwin, TRUE);
  454.     idlok(outwin, TRUE);
  455.         wmove(dividewin, 0, 0);
  456.         for (i = 0 ; i < COLS ; ++i)   {
  457.                 waddch(dividewin, '-');
  458.         }
  459.         wnoutrefresh(inwin);    /* faster screen update (a la curses manual) */
  460.         wnoutrefresh(outwin);
  461.         wnoutrefresh(dividewin);
  462.     doupdate();
  463. }
  464.  
  465.  
  466.  
  467. /*  attempt to notify user that you wish to talk to him, or have given up  */
  468.  
  469. char *
  470. dialup(status)
  471.  
  472. int    status;
  473.  
  474. {
  475.     struct utmp    *ptr, *user, *getutent();
  476.     void    setutent();
  477.     long    tloc, time();
  478.     char    *nameof(), ctime();
  479.     FILE    *fp;
  480.     int    found, logins;
  481.     char    current_time[26 + 1];
  482.  
  483.     found = FALSE;
  484.     logins = 0;
  485.     setutent();
  486.     while ((ptr = getutent()) != NULL)   {        /*  search for user  */
  487.         if (strcmp(ptr->ut_user, theirname) == 0)   {
  488.             if ( ! *theirtty)   {
  489.                 user = ptr;
  490.                 found = TRUE;
  491.                 break;
  492.             }
  493.             else   {
  494.                 if (strcmp(theirtty, ptr->ut_line) == 0)   {
  495.                     user = ptr;
  496.                     found = TRUE;
  497.                     break;
  498.                 }
  499.                 else  {
  500.                     /*  not used at present  */
  501.                     ++logins;
  502.                 }
  503.             }
  504.         }
  505.     }
  506.     if ( ! found)   {
  507.         sprintf(tmp, "[Your party is not logged on %s]\n",
  508.             ( ! *theirtty )  ?  "\b" : theirtty);
  509.         wheader(inwin, tmp);
  510.         failed = TRUE;
  511.         die();
  512.     }
  513.     sprintf(tmp, "/dev/%s", user->ut_line);
  514.     if ((fp = fopen(tmp, "w")) == NULL)   {
  515.         wheader(inwin, "[Your party has disabled messages]\n");
  516.         failed = TRUE;
  517.         die();
  518.     }
  519.     if (status == CONNECT)   {
  520.         fprintf(fp,
  521.             "\r\7%s (%s) is phoning - respond with 'talk %s'    \n",
  522.                         myname, nameof(myname), myname);
  523.     }
  524.     else   {
  525.         if (time(&tloc) != -1)   {
  526.             strcpy(current_time, ctime(&tloc));
  527.             current_time[strlen(current_time) - 1] = NULL;
  528.         }
  529.         else   {
  530.             strcpy(current_time, "now");
  531.         }
  532.         fprintf(fp, "\r\7%s (%s) has stopped phoning [%s]\n",
  533.                     myname, nameof(myname), current_time);
  534.     }
  535.     fclose(fp);
  536.     return(user->ut_line);
  537. }
  538.  
  539.  
  540.  
  541. talk()                /*  talk to other user  */
  542.  
  543. {
  544.     int    clock();
  545.  
  546.     /*  initialise window cursor positions  */
  547.     inwinx = outwinx = outwiny = 0;
  548.     inwiny = 1;
  549.  
  550.     delchar = erasechar();
  551.     time_changed = FALSE;
  552.  
  553.     /*  place cursor in input window  */
  554.     wmove(inwin, inwiny, inwinx);
  555.     wrefresh(inwin);
  556.  
  557.     signal(SIGALRM, clock);
  558.     alarm(CLOCK_TICK);
  559.     while (1)   {
  560.         /*  place cursor in input window  */
  561.         wmove(inwin, inwiny, inwinx);
  562.         wrefresh(inwin);
  563.         /*  check for any activity  */
  564.         if (input() == FALSE  &&  output() == FALSE)   {
  565.             sleep(1);
  566.         }
  567.  
  568.         /*******************
  569.         *      SIGALRM was asynchronous to the rest of the program
  570.         *   ie. it occurred whenever it liked and updated elapsed
  571.         *   time.  This worked ok in general, although once in a while
  572.         *   things would get confused (nothing CTRL-l couldn't
  573.         *   overcome).  Fixed by using a global flag.
  574.         *******************/
  575.  
  576.         if (time_changed)   {            /*  elapsed time  */
  577.             time_changed = FALSE;
  578.             update_time();
  579.         }
  580.     }
  581. }
  582.  
  583.  
  584.  
  585. clock()        /*  set global flag to indicate time should be updated  */
  586.  
  587. {
  588.     time_changed = TRUE;
  589.     signal(SIGALRM, clock);
  590.     alarm(CLOCK_TICK);
  591. }
  592.  
  593.  
  594.  
  595. update_time()            /*  display current time on screen  */
  596.  
  597. {
  598.     static int    elapsed_time = 0;
  599.  
  600.     elapsed_time += CLOCK_TICK;
  601.     wmove(dividewin, divwiny, divwinx);
  602.     wstandout(dividewin);
  603.     wprintw(dividewin, elapsed, elapsed_time / 3600,
  604.                     elapsed_time / 60, elapsed_time % 60);
  605.     wstandend(dividewin);
  606.     wrefresh(dividewin);
  607. }
  608.  
  609.  
  610.  
  611. input()            /*  check for and act on user input  */
  612.  
  613. {
  614.     int    x;
  615.  
  616.     x = wgetch(inwin);
  617.     getyx(inwin, inwiny, inwinx);
  618.     if (x != -1)   {
  619.         switch(x)   {
  620.             case  END_OF_FILE  :
  621.                 waddstr(inwin, "\n[You have disconnected]");
  622.                 wrefresh(inwin);
  623.                 die();
  624.                 break;
  625.  
  626.             case  REFRESH  :
  627.                 clearok(curscr, TRUE);
  628.                 wrefresh(curscr);
  629.                 break;
  630.  
  631.             case  BELL  :
  632.                 putc(x, writing);
  633.                 break;
  634.  
  635.             default  :
  636.                 if (x != delchar)   {
  637.                     if (not_printable(x))   {
  638.                         beep();
  639.                         break;
  640.                     }
  641.                     wmove(inwin, inwiny, inwinx);
  642.                     waddch(inwin, x);
  643.                 }
  644.                 else   {
  645.                     wprevch(inwin);
  646.                     wdelch(inwin);
  647.                     x = DELETE;
  648.                 }
  649.                 getyx(inwin, inwiny, inwinx);
  650.                 wrefresh(inwin);
  651.                 putc(x, writing);
  652.                 break;
  653.         }
  654.         return(TRUE);
  655.     }
  656.     return(FALSE);
  657. }
  658.  
  659.  
  660.  
  661. output()        /*  check for and act on any output to be displayed  */
  662.  
  663. {
  664.     char    c;
  665.  
  666.     if (read(reading, &c, 1) != 0)   {
  667.         switch (c)   {
  668.             case  DISCONNECT  :
  669.                 waddstr(inwin,
  670.                     "\n[Your party has disconnected]");
  671.                 wrefresh(inwin);
  672.                 beep();
  673.                 die();
  674.                 break;
  675.  
  676.             case  DELETE  :
  677.                 wprevch(outwin);
  678.                 wdelch(outwin);
  679.                 break;
  680.  
  681.             case  BELL  :
  682.                 beep();
  683.                 break;
  684.  
  685.             default  :
  686.                 wmove(outwin, outwiny, outwinx);
  687.                 waddch(outwin, c);
  688.                 break;
  689.         }
  690.         getyx(outwin, outwiny, outwinx);
  691.         wrefresh(outwin);
  692.         return(TRUE);
  693.     }
  694.     return(FALSE);
  695. }
  696.  
  697.  
  698.  
  699. /*  move cursor back to previous non-space char within window  */
  700.  
  701. wprevch(win)
  702.  
  703. WINDOW    *win;
  704.  
  705. {
  706.     int    x, y;
  707.  
  708.     getyx(win, y, x);
  709.     if (--x < 0)   {
  710.         if (--y < 0)   {
  711.             wmove(win, 0, 0);
  712.             return;
  713.         }
  714.         for (x = win->_maxx - 1 ; x >= 0 ; --x)   {
  715.             wmove(win, y, x);
  716.             if (winch(win) != SPACE)   {
  717.                 return;
  718.             }
  719.         }
  720.         return;
  721.     }
  722.     wmove(win, y, x);
  723. }
  724.  
  725.  
  726.  
  727. char *
  728. nameof(user)            /*  find name of user (from passwd file)  */
  729.  
  730. char    *user;
  731.  
  732. {
  733.     struct passwd    *entry, *getpwnam();
  734.  
  735.     entry = getpwnam(user);
  736.     if (*(entry->pw_gecos))   {
  737.         return(entry->pw_gecos);
  738.     }
  739.     return("no name");
  740. }
  741.  
  742.  
  743.  
  744. forced_die()            /*  program interrupted by signal  */
  745.  
  746. {
  747.     alarm(0);        /*  disable clock to be safe  */
  748.     forced = TRUE;
  749.     die();
  750. }
  751.  
  752.  
  753.  
  754. die()            /*  gracefully exit program  */
  755.  
  756. {
  757.     char    *dialup();
  758.  
  759.     alarm(0);
  760.     signal(SIGALRM, SIG_IGN);
  761.     signal(SIGINT, SIG_IGN);
  762.  
  763.     if (writing != NULL)   {
  764.         putc(DISCONNECT, writing);
  765.         fclose(writing);
  766.     }
  767.     if (reading != -1)   {
  768.         close(reading);
  769.     }
  770.     if (master  &&  (! connected))   {
  771.         unlink(readfile);
  772.         unlink(writefile);
  773.     }
  774.  
  775.     wmove(outwin, OUTWINLINES - 1, 0);
  776.     if (forced)   {
  777.         sprintf(tmp, "[Forced exit%s] ",
  778.             (connected)  ?  " (disconnected)" : "");
  779.         waddstr(outwin, tmp);
  780.     }
  781.         wrefresh(outwin);
  782.     flushinp();
  783.     nodelay(inwin, FALSE);
  784.     delwin(inwin);
  785.     delwin(outwin);
  786.     delwin(dividewin);
  787.     endwin();
  788.     if (failed)   {
  789.         exit(4);
  790.     }
  791.     if (! connected)   {
  792.         dialup(DISCONNECT);
  793.     }
  794.     putchar('\n');
  795.     exit(0);
  796. }
  797.  
  798.  
  799.  
  800. /*  print error message and terminate program (via die())  */
  801. error(message, arg1, arg2)
  802.  
  803. char    *message, *arg1, *arg2;
  804.  
  805. {
  806.     wmove(outwin, OUTWINLINES - 2, 0);
  807.     wprintw(outwin, "%s: ", progname);
  808.     wprintw(outwin, message, arg1, arg2);
  809.     wrefresh(outwin);
  810.     failed = TRUE;
  811.     die();
  812. }
  813. SHAR_EOF
  814. exit 0
  815. #    End of shell archive
  816.  
  817. ---- Cut Here -------------- Cut Here ------------------ Cut Here -------
  818.  
  819.  
  820.  
  821. Nigel Holder            UK JANET:       yf21@uk.co.gec-mrc.u
  822. Marconi Research,        ARPA:           yf21%u.gec-mrc.co.uk@ucl-cs
  823. Chelmsford,
  824. Essex. CM2 8HN.
  825.  
  826. +44 245 73331   ext. 3219 / 3214
  827.  
  828.  
  829.