home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume06 / talksysv.vrb < prev    next >
Encoding:
Text File  |  1988-09-11  |  36.2 KB  |  1,463 lines

  1. Subject: v06i011:  A "talk" for System V (sysVtalkB)
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: cbosgd!ukma!ukecc!edward (Edward C. Bennett)
  6. Mod.sources: Volume 6, Issue 11
  7. Archive-name: sysVtalkB
  8.  
  9. [ This is the second of two different talk programs.
  10.   The manpage has some lines that start with periods;
  11.   let me know if this causes problems for anyone, and I
  12.   will fix this in future postings.  --r$]
  13.  
  14. This a version of the Berkeley talk program for System V. Talk allows
  15. conversing parties to type simultaineously while maintaining a neat,
  16. readable screen. It uses the 'messages' Interprocess Communication
  17. Facility of System V to pass data.
  18.  
  19. #! /bin/sh
  20. : This is a shell archive, meaning:
  21. : 1. Remove everything above the '#! /bin/sh' line.
  22. : 2. Save the resulting text in a file.
  23. : 3. Execute the file with /bin/sh '(not csh)' to create the files:
  24. :    'README'
  25. :    'talk.1'
  26. :    'Makefile'
  27. :    'talk.h'
  28. :    'talk.c'
  29. :    'talkd.c'
  30. :    'infotalk.c'
  31. :    'stoptalk.c'
  32. : This archive created: 'Fri Jun 13 14:04:24 1986'
  33. : By:    'Edward C. Bennett'
  34. export PATH; PATH=/bin:$PATH
  35. echo shar: extracting "'README'" '(2386 characters)'
  36. if test -f 'README'
  37. then
  38.     echo shar: will not over-write existing file "'README'"
  39. else
  40. cat  >'README' <<\SHAR_EOF
  41. Installing and maintaining 'talk'
  42.  
  43.     These instructions are intended to be fairly generic. They were
  44. written for a 3B20. Your milage may vary.
  45.  
  46.     The talk system is composed of three executable pieces.
  47.  
  48.     talk        the user interface
  49.     talkdemon    the background process that supervises conversations
  50.     stoptalk    a program for removing the talk msgqueue
  51.  
  52.     (Yes, I know it's usally spelled 'daemon'. But since my 3B20 has
  53. an 'errdemon' I figured System V wanted to be different. C'est la vie.)
  54.  
  55.     First, read the 'Makefile' and make any nessecary modifications.
  56. You might want to also change 'talk.h'. Running 'make install' will create
  57. and install the three binaries for you. /usr/bin/talk must run setuid.
  58. This is so that independent 'talk' process can exchange signals. Talkdemon
  59. and stoptalk should have 'other' permissions turned off to prevent regular
  60. users from tampering with them. The owner and group ids of the files are
  61. not important so you can set them as you like.
  62.  
  63.     After installing the binaries, provisions for automatic startup
  64. and shutdown of the talkdemon should be made. In your startup script
  65. (/etc/rc on my 3B20), at the point where /etc/cron is started, insert
  66. these lines:
  67.  
  68.     echo talkdemon started
  69.     /etc/talkdemon
  70.  
  71. and in your shutdown script (/etc/shutdown on my 3B20), before all user
  72. processes are killed, insert these lines:
  73.  
  74.     echo Talk msgqueue being removed
  75.     /etc/stoptalk
  76.  
  77. The entry in shutdown is needed because taking the system down to single
  78. user mode doesn't remove msgqueues and because /etc/shutdown kills
  79. user processes with a '-9' which prevents the talkdemon from removing
  80. it's own msgqueue.
  81.  
  82.     The 'infotalk' program provides status on the state of the demon.
  83. It was initally used for debugging purposes and has been included for
  84. completeness.
  85.  
  86. Known problems with talk
  87.  
  88. 1)    My version of System V has no high-precision sleep call, so the
  89. main loop of 'talk' runs as fast as the machine allows. I don't think
  90. this leads to any problems other than high CPU usage. If your system
  91. has a fractional-second sleep call, I suggest you use it to reduce talk's
  92. CPU time consumption. Let me know how it goes.
  93.  
  94. 2)    The version of `curses` on my machine has a bug which causes
  95. the cursor to jump to and from the beginning of the current line when
  96. a character is added to the screen. This is not harmful, just annoying.  
  97.  
  98. Edward C. Bennett
  99.     ihnp4!cbosgd!ukma!ukecc!edward
  100. SHAR_EOF
  101. fi
  102. echo shar: extracting "'talk.1'" '(1217 characters)'
  103. if test -f 'talk.1'
  104. then
  105.     echo shar: will not over-write existing file "'talk.1'"
  106. else
  107. cat  >'talk.1' <<\SHAR_EOF
  108. .TH TALK 1
  109. .SH NAME
  110. talk \- inter-terminal screen-oriented communication program
  111. .SH SYNOPSIS
  112. .B talk user
  113. [
  114. .B tty
  115. ]
  116. .SH DESCRIPTION
  117. .I Talk
  118. is a inter-terminal conversation program designed
  119. to allow both parties to type at the same time
  120. and still maintain a readable display.
  121. The
  122. .IR curses (3X)
  123. screen-management library is used to handle the
  124. display so you must set your TERM environment variable.
  125. .PP
  126. When you run
  127. .I talk
  128. you give the login name of who you want to converse with.
  129. If they are logged in more than once,
  130. you must also specify which tty of theirs you wish to talk to.
  131. .I Talk
  132. will inform them that you wish to communicate
  133. with them and wait for their response.
  134. If they are slow,
  135. .I talk
  136. will resend its message every 30 seconds until either
  137. they respond or you get bored and hit INTERRUPT.
  138. .PP
  139. A control-L will force the screen to be
  140. redrawn in case it becomes garbled.
  141. .PP
  142. Although the program emulates to Berkeley program of the
  143. same name, the code is 100% original.
  144. .SH AUTHOR
  145. Edward C. Bennett
  146. .SH DIAGNOSTICS
  147. Hopefully self-explanatory.
  148. .SH BUGS
  149. Because of an apparent bug in the SystemV curses package,
  150. if one person backspaces while the other is typing,
  151. text is lost off at least one screen.
  152. SHAR_EOF
  153. fi
  154. echo shar: extracting "'Makefile'" '(1416 characters)'
  155. if test -f 'Makefile'
  156. then
  157.     echo shar: will not over-write existing file "'Makefile'"
  158. else
  159. cat  >'Makefile' <<\SHAR_EOF
  160. #
  161. # Makefile for talk, stoptalk, and the talkdemon
  162. #
  163. # AUTHOR
  164. #    Edward C. Bennett (edward@ukecc)
  165. #
  166. # Copyright 1985 by Edward C. Bennett
  167. #
  168. # Permission is given to alter this code as needed to adapt it to forign
  169. # systems provided that this header is included and that the original
  170. # author's name is preserved.
  171. #
  172.  
  173. BIN=/usr/bin
  174. DEMONDIR=/etc
  175. #
  176. # /usr/bin/talk needs to run setuid. It doesn't have to be root so make
  177. # this something harmless.
  178. #
  179. OWNER=edward
  180.  
  181. #
  182. # Use whatever libraries you need to make curses work.
  183. #
  184. LIBS=-lcurses # -lterminfo -ltermcap -ltermlib
  185.  
  186. all: talk talkdemon infotalk stoptalk
  187.  
  188. talk: talk.o talk.c
  189.     cc -s talk.o -o talk ${LIBS}
  190.  
  191. tester: ntalk.c
  192.     cc -DSCHIZO ntalk.c -o tester ${LIBS}
  193.  
  194. talkdemon: talkd.o talkd.c
  195.      cc -s talkd.o -o talkdemon
  196.  
  197. infotalk: infotalk.o infotalk.c
  198.      cc -s infotalk.o -o infotalk
  199.  
  200. stoptalk: stoptalk.o stoptalk.c
  201.      cc -s stoptalk.o -o stoptalk
  202.  
  203. talk.o: talk.h
  204.     cc -c -O talk.c
  205.  
  206. talkd.o: talk.h
  207.     cc -c -O talkd.c
  208.  
  209. infotalk.o: talk.h
  210.     cc -c -O infotalk.c
  211.  
  212. stoptalk.o: talk.h
  213.     cc -c -O stoptalk.c
  214.  
  215. install: all
  216.     /etc/install -f ${BIN} talk
  217.     /etc/install -f ${DEMONDIR} talkdemon
  218.     /etc/install -f ${DEMONDIR} stoptalk
  219.     chown ${OWNER} ${BIN}/talk
  220.     chmod 4755 ${BIN}/talk
  221.     chmod 750 ${DEMONDIR}/talkdemon ${DEMONDIR}/stoptalk
  222.  
  223. clean:
  224.     rm -f *.o talk talkd talkdemon stoptalk
  225.  
  226. shar:
  227.     shar -v README talk.1 Makefile talk.h talk.c talkd.c infotalk.c stoptalk.c > talk.shar
  228. SHAR_EOF
  229. fi
  230. echo shar: extracting "'talk.h'" '(2629 characters)'
  231. if test -f 'talk.h'
  232. then
  233.     echo shar: will not over-write existing file "'talk.h'"
  234. else
  235. cat  >'talk.h' <<\SHAR_EOF
  236. /*
  237.  * Definitions for talk and the talkdemon
  238.  *
  239.  * AUTHOR
  240.  *    Edward C. Bennett (edward@ukecc)
  241.  *
  242.  * Copyright 1985 by Edward C. Bennett
  243.  *
  244.  * Permission is given to alter this code as needed to adapt it to forign
  245.  * systems provided that this header is included and that the original
  246.  * author's name is preserved.
  247.  */
  248. #include <sys/types.h>
  249. #include <sys/ipc.h>
  250. #include <sys/msg.h>
  251. #include <errno.h>
  252. #include <utmp.h>
  253. #include <string.h>
  254.  
  255. /*
  256.  * If your system has a high resolutiuon sleep call, define SLEEP to
  257.  * be the name of the function and define SLEEP_TIME to be whatever number
  258.  * gives you about a .1 second delay. The defines are used like this:
  259.  *    SLEEP(SLEEP_TIME);
  260.  */
  261. /* #define    SLEEP    sleep        /* Name of high resolution sleep call */
  262. /* #define    SLEEP_TIME    100    /* Number to give ~.1 second delay */
  263.  
  264. /*
  265.  * If your system has the old utmp file format, i.e. without USER_PROCESS,
  266.  * define OLDUTMP
  267.  */
  268. /* #define    OLDUTMP        /* If you use the old utmp format */
  269.  
  270. /*
  271.  * If you have a version of curses that is more Berkeley than System V,
  272.  * you'll probably need at least one of these.
  273.  */
  274. /* #define    cbreak    crmode        /* to turn off canonical input */
  275.  
  276. /* #define    CLRONEXIT    /* turn on if you want the screen cleared on exit */
  277. /*
  278.  * Defines for using msgget()
  279.  * If for some reason the msgkey that talk generates is already used on
  280.  * your system, change MAGIC_ID to another character.
  281.  */
  282. #define    TALK_PATH    "/usr/bin/talk"
  283. #define    MAGIC_ID    'E'         /* This can be any char. Be creative. */
  284. #define    MSGQ_PERMS    0666        /* You may want to change these */
  285.                     /* to increase security */
  286.  
  287. #define    NAMESIZ    8    /* from <utmp.h> */
  288. #define    LINESIZ    12    /* from <utmp.h> */
  289. #define    TTYLOC    16    /* ttys always start in this location in 'mtext' */
  290. #define    SEND    0    /* Locations in the 'lines' array for these msgtypes */
  291. #define    RECEIVE    1
  292. #define    CTL    2
  293. #define    PIDLOC    7    /* pids always ride in this spot in the 'lines' array */
  294. #define    STATUS    3    /* mtype for status messages */
  295.  
  296. /*
  297.  * Stuff for the Deamon MeSsaGes
  298.  * All message involving the demon use this structure
  299.  *
  300.  * Here's how the buffer is laid out:
  301.  *                    1            2
  302.  *    0        8        6            8
  303.  *     | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
  304.  *     |  name         |  name         | tty line              | pid
  305.  *     | send  |receive| ctl   |       |       |       |       | pid   |
  306.  */
  307. typedef    struct    {
  308.     long    mtype;
  309.     union    {
  310.         char    mtext[32];
  311.         long    lines[8];
  312.     } msgval;
  313. } DMSG;
  314.  
  315. DMSG    dmsgbuf;
  316. #define    MSGSIZ    sizeof(dmsgbuf.msgval.mtext)
  317.  
  318. /*
  319.  * 'Find' return codes
  320.  */
  321. #define    TALKABLE     1
  322. #define    NOTLOGGEDON    -1
  323. #define    NOTWRITE    -2
  324. #define    LOGGEDMORE    -3
  325. #define    NOTONLINE    -4
  326. SHAR_EOF
  327. fi
  328. echo shar: extracting "'talk.c'" '(9418 characters)'
  329. if test -f 'talk.c'
  330. then
  331.     echo shar: will not over-write existing file "'talk.c'"
  332. else
  333. cat  >'talk.c' <<\SHAR_EOF
  334. /*
  335.  * talk - a two-way, screen-oriented communication program
  336.  *
  337.  *    Talk, which emulates the Berkeley program of the same name, allows
  338.  * both parties in a conversation to type at will, without fear of garbling
  339.  * each others messages. Input from either user is immediatly written to both
  340.  * screens so that there is no waiting like there is with write(1).
  341.  *
  342.  *    Although this program resembles, to the user, the Berkeley program
  343.  * 'talk', the code is entirely original by the author.
  344.  *
  345.  * AUTHOR
  346.  *    Edward C. Bennett (edward@ukecc)
  347.  *
  348.  * Copyright 1985 by Edward C. Bennett
  349.  *
  350.  * Permission is given to alter this code as needed to adapt it to forign
  351.  * systems provided that this header is included and that the original
  352.  * author's name is preserved.
  353.  */
  354. #include <curses.h>
  355. #include <signal.h>
  356. #include <fcntl.h>
  357. #include "talk.h"
  358.  
  359. struct    msgbuf    sndbuf, rcvbuf;
  360.  
  361. int    msqid;
  362. int    avail;        /* The availabity of a perspective partner */
  363. int    parpid = 0;    /* The pid of the partner */
  364. char    *ctime(), *getlogin();
  365. time_t    tloc, otime, time();
  366.  
  367. main(argc, argv)
  368. int argc;
  369. char *argv[];
  370. {
  371.     key_t        msgkey, ftok();
  372.     long        fromtype;    /* The msgtype where we look for characters */
  373.                     /* from the partner */
  374. #ifdef FIONREAD
  375.     long        waiting;
  376. #endif
  377.     void        exit();
  378.     int        c, Finish();
  379.     int        MIDDLE;
  380.     short        orgy = 0, orgx = 0;    /* That's ORGinator's Y you pervert */
  381.     short        resy, resx = 0;
  382.  
  383.  
  384.     msgkey = ftok(TALK_PATH, MAGIC_ID);
  385.  
  386.     if ((msqid = msgget(msgkey, MSGQ_PERMS)) == -1) {
  387.         fprintf(stderr, "%s: Nonexistant talk msgqueue\n", argv[0]);
  388.         exit(1);
  389.     }
  390.  
  391. #ifndef SCHIZO
  392.     if (!isatty(0)) {
  393.         fprintf(stderr, "%s: must have a terminal for input\n", argv[0]);
  394.         exit(1);
  395.     }
  396. #endif
  397.  
  398. #ifndef SCHIZO
  399.     if (argc == 1) {
  400.         fprintf(stderr, "%s: No user specified\n", argv[0]);
  401.         exit(1);
  402.     }
  403.  
  404.     /*
  405.      * We need to tell the demon who we are, who we want to talk to,
  406.      * the tty of who we want (if it was given) and our process id.
  407.      */
  408.     strncpy(dmsgbuf.msgval.mtext, getlogin(), NAMESIZ);
  409.     strncpy(&dmsgbuf.msgval.mtext[NAMESIZ], argv[1], NAMESIZ);
  410.     if (argv[2])
  411.         strncpy(&dmsgbuf.msgval.mtext[TTYLOC], argv[2], LINESIZ);
  412.     dmsgbuf.msgval.lines[PIDLOC] = getpid();
  413.     dmsgbuf.mtype = 1;
  414.  
  415.     /*
  416.      * Tell the demon we are here.
  417.      */
  418.     if (msgsnd(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, 0) == -1) {
  419.         fprintf(stderr, "%s: msgsnd failure(%d)\n", argv[0], errno);
  420.         exit(1);
  421.     }
  422.  
  423.     /*
  424.      * Wait for a response from the demon.
  425.      */
  426.     if (msgrcv(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, (long)2, 0) == -1) {
  427.         fprintf(stderr, "%s: msgrcv failure(%d)\n", argv[0], errno);
  428.         exit(1);
  429.     }
  430.  
  431.     avail = dmsgbuf.msgval.lines[0];
  432.     /*
  433.      * A negative availability is untalkable.
  434.      */
  435.     if (avail < 0) {
  436.         Error(avail, argv);
  437.         exit(1);
  438.     }
  439.  
  440.     sndbuf.mtype = dmsgbuf.msgval.lines[SEND];
  441. #endif
  442.  
  443.     /*
  444.      * Now that it's OK to talk, go ahead and
  445.      * initialize the terminal and screen
  446.      */
  447.     if (initscr() == (WINDOW *)NULL) {
  448.         fprintf(stderr, "%s: TERM variable not set\n", argv[0]);
  449.         Finish(SIGINT);
  450.     }
  451.  
  452.     /*
  453.      * Since curses in now ineffect, we need to watch for
  454.      * ALL signals so that we can properly terminate
  455.      */
  456.     for (c = 0; c < NSIG; c++)
  457.         signal(c, Finish);
  458.  
  459.     cbreak();
  460.     noecho();
  461. #ifndef SCHIZO
  462. #ifndef FIONREAD
  463.     nodelay(stdscr, TRUE);
  464. #endif
  465. #endif
  466.     MIDDLE = LINES / 2 - 1;
  467.     time(&tloc);
  468.     mvprintw(MIDDLE, 0, "--------------------------------------------------------------- %12.12s --", ctime(&tloc) + 4);
  469.     move(orgy, orgx);
  470.     refresh();
  471.  
  472.     fromtype = dmsgbuf.msgval.lines[RECEIVE];
  473.  
  474. #ifndef SCHIZO
  475.     /*
  476.      * If we are given a ctl type, wait for a ctl message.
  477.      */
  478.     if (dmsgbuf.msgval.lines[CTL] > 0) {
  479.         mvprintw(0, 0, "[Waiting for %s to answer]\n", argv[1]);
  480.         refresh();
  481.         Ring();
  482.         while (msgrcv(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, dmsgbuf.msgval.lines[2], 0) == -1) {
  483.             /*
  484.              * The 'talkee' may have turned off his messages
  485.              */
  486.             if (avail < 0) {
  487.                 mvprintw(orgy++, orgx, "[%s no longer writable]\n", argv[1]);
  488.                 refresh();
  489.             }
  490.             /*
  491.              * EINTR is an interrupted system call
  492.              */
  493.             else if (errno == EINTR) {
  494.                 mvprintw(orgy++, orgx, "[Ringing %s again]\n", argv[1]);
  495.                 refresh();
  496.             }
  497.             else {
  498.                 fprintf(stderr, "%s: msgrcv failure(%d)\n", argv[0], errno);
  499.                 Finish(SIGINT);
  500.             }
  501.         }
  502.         if (orgy) {
  503.             while (orgy > 1) {
  504.                 move(--orgy, orgx);
  505.                 clrtoeol();
  506.             }
  507.         } else
  508.             orgy = 1;
  509.  
  510.         alarm(0);    /* Turn off the ringer */
  511.         beep();
  512.         mvaddstr(0, 0, "[Connection established]\n");
  513.         refresh();
  514.     }
  515.     parpid = dmsgbuf.msgval.lines[PIDLOC];
  516. #endif
  517.  
  518.     /*
  519.      * This loop just continually checks both users for input.
  520.      * It actually runs TOO FAST, but since SysV has no fractional
  521.      * second sleep we do the best we can.
  522.      */
  523.     resy = MIDDLE + 1;
  524.     for (;;) {
  525.         /*
  526.          * This is the owner's half
  527.          */
  528. #ifdef FIONREAD
  529.         ioctl(0, FIONREAD, &waiting);
  530.         if (waiting) {
  531.             c = getch();
  532. #else
  533.         if ((c = getch()) != EOF) {
  534. #endif
  535.             if (c == erasechar()) {
  536.                 c = '\b';
  537.                 if (--orgx < 0)
  538.                     orgx = 0;
  539.                 else
  540.                     mvaddstr(orgy, orgx, " \b");
  541.             }
  542.             else if (c == '\004')
  543.                 Finish(SIGINT);    
  544.             else if (c == '\f') {
  545.                 clearok(curscr, TRUE);
  546.                 refresh();
  547.                 continue;
  548.             }
  549.             else if (c == '\n') {
  550.                 orgy = ++orgy % MIDDLE;
  551.                 orgx = 0;
  552.                 move(orgy, orgx);
  553.                 clrtoeol();
  554.                 move((orgy + 1) % MIDDLE, orgx);
  555.                 clrtoeol();
  556.                 move(orgy, orgx);
  557.             }
  558.             /*
  559.              * Regular characters
  560.              */
  561.             else {
  562.                 /*
  563.                  * Check for wrap around
  564.                  */
  565.                 if (orgx >= 79) {
  566.                     orgy = ++orgy % MIDDLE;
  567.                     orgx = 0;
  568.                     move(orgy, orgx);
  569.                     clrtoeol();
  570.                     move((orgy + 1) % MIDDLE, orgx);
  571.                     clrtoeol();
  572.                 }
  573.                 mvaddch(orgy, orgx++, c);
  574.             }
  575.  
  576.             refresh();
  577. #ifndef SCHIZO
  578.             *sndbuf.mtext = c;
  579.             if (msgsnd(msqid, (struct msgbuf *)&sndbuf, 1, 0) == -1) {
  580.                 fprintf(stderr, "%s: msgsnd failure(%d)\n", argv[0], errno);
  581.                 Finish(SIGINT);
  582.             }
  583. #endif
  584.         }
  585.  
  586. #ifndef SCHIZO
  587.         /*
  588.          * This is the partner's half
  589.          */
  590.         if (msgrcv(msqid, (struct msgbuf *)&rcvbuf, 1, fromtype, IPC_NOWAIT) != -1) {
  591.             switch (*rcvbuf.mtext) {
  592.             case '\b':
  593.                 if (--resx < 0)
  594.                     resx = 0;
  595.                 else
  596.                     mvaddstr(resy, resx, " \b");
  597.                 break;
  598.  
  599.             case '\n':
  600.                 if (++resy >= LINES - 1)
  601.                     resy = MIDDLE + 1;
  602.                 resx = 0;
  603.                 mvaddch(resy, resx, '\n');
  604.                 mvaddch(((resy - MIDDLE) % (LINES - MIDDLE - 2)) + MIDDLE + 1, resx, '\n');
  605.                 move(resy, resx);
  606.                 break;
  607.  
  608.             default:
  609.                 /*
  610.                  * Check for wrap around
  611.                  */
  612.                 if (resx >= 79) {
  613.                     if (++resy >= LINES - 1)
  614.                         resy = MIDDLE + 1;
  615.                     resx = 0;
  616.                     move(resy, resx);
  617.                     clrtoeol();
  618.                     move(((resy - MIDDLE) % (LINES - MIDDLE - 2)) + MIDDLE + 1, resx);
  619.                     clrtoeol();
  620.                     move(resy, resx);
  621.                 }
  622.                 mvaddch(resy, resx++, *rcvbuf.mtext);
  623.                 break;
  624.             }
  625.  
  626.             refresh();
  627.         }
  628. #endif
  629.         /*
  630.          * Update the time
  631.          */
  632.         time(&tloc);
  633.         if (tloc >= otime + 60) {
  634.             otime = tloc;
  635.             mvprintw(MIDDLE, COLS - 16, "%12.12s", ctime(&tloc) + 4);
  636.             refresh();
  637.         }
  638. #ifdef SLEEP
  639.         SLEEP(SLEEP_TIME);
  640. #endif
  641.     }
  642. }
  643.  
  644. /*
  645.  * Ring - ring the perspective partner
  646.  *
  647.  * Ring();
  648.  *
  649.  * A request message is sent to the partner's terminal.
  650.  */
  651. Ring()
  652. {
  653.     FILE        *fp, *fopen();
  654.     char        *ttyname();
  655.     int        Ring();
  656.  
  657.     tloc = time((time_t *)0);
  658.     if ((fp = fopen(&dmsgbuf.msgval.mtext[TTYLOC], "w")) != NULL) {
  659.         fprintf(fp, "\r\n%c%cTalk request from %s on %s at %5.5s\r\n",
  660.             '\007', '\011', getlogin(), ttyname(0)+5, ctime(&tloc)+11);
  661.         fprintf(fp, "%cRespond with 'talk %s'\r\n", '\007', getlogin());
  662.         fclose(fp);
  663.     }
  664.     /*
  665.      * If the person being rung turns of his messages, set avail to
  666.      * indicate his new unavailablity
  667.      */
  668.     else 
  669.         avail = -1;
  670.  
  671.     signal(SIGALRM, Ring);
  672.     alarm((unsigned)20);
  673. }
  674.  
  675. /*
  676.  * Error - print an error message
  677.  *
  678.  * Error(code);
  679.  *    code    is the availability of who we want to talk to
  680.  *
  681.  * A message regarding why we can't talk is printed.
  682.  */
  683. Error(code, argv)
  684. int code;
  685. char **argv;
  686. {
  687.     switch (code) {
  688.  
  689.     case NOTLOGGEDON:
  690.         fprintf(stderr, "%s: %s not logged on\n", argv[0], argv[1]);
  691.         break;
  692.  
  693.     case NOTWRITE:
  694.         fprintf(stderr, "%s: %s not writeable\n", argv[0], argv[1]);
  695.         break;
  696.  
  697.     case LOGGEDMORE:
  698.         fprintf(stderr, "%s: %s logged on more than once\n", argv[0], argv[1]);
  699.         break;
  700.  
  701.     case NOTONLINE:
  702.         fprintf(stderr, "%s: %s not on line %s\n", argv[0], argv[1], argv[2]);
  703.         break;
  704.     }
  705. }
  706.  
  707. /*
  708.  * Finish - reset and exit
  709.  *
  710.  * Finish();
  711.  *
  712.  * Finish is called upon receipt of SIGINT or SIGUSR1. Finish resets the
  713.  * user's terminal and if called by SIGINT, sends SIGUSR1 signal to his
  714.  * partner's talk process so that both terminate simultaineously
  715.  */
  716. Finish(sig)
  717. int sig;
  718. {
  719.     FILE        *fp, *fopen();
  720.     int        i;
  721.  
  722.     /*
  723.      * Prevent from being interrupted while finishing
  724.      */
  725.     for (i = 0; i < NSIG; i++)
  726.         signal(i, SIG_IGN);
  727. #ifndef SCHIZO
  728.     if (sig == SIGINT) {
  729.         /*
  730.          * If a conversation was in process, tell the partner's
  731.          * process to stop also. Otherwise, tell the partner
  732.          * that the request is no longer pending.
  733.          */
  734.         if (parpid)
  735.             kill(parpid, SIGUSR1);
  736.         else if ((fp = fopen(&dmsgbuf.msgval.mtext[TTYLOC], "w")) != NULL) {
  737.             tloc = time((long *)0);
  738.             fprintf(fp, "\r\n%cTalk request from %s cancelled at %5.5s\r\n", '\011', getlogin(), ctime(&tloc)+11);
  739.             fclose(fp);
  740.         }
  741.     }
  742. #endif
  743.  
  744. #ifdef CLRONEXIT
  745.     clear();
  746. #endif
  747.     mvaddstr(0, 0, "[Connection closed]\n");
  748.     refresh();
  749.     nodelay(stdscr, FALSE);
  750.     endwin();
  751.  
  752. #ifndef SCHIZO
  753.     dmsgbuf.msgval.lines[PIDLOC] = -getpid();
  754.     dmsgbuf.mtype = 1;
  755.     if (msgsnd(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, 0) == -1) {
  756.         fprintf(stderr, "talk: msgsnd failure(%d)\n", errno);
  757.         exit(1);
  758.     }
  759. #endif
  760.  
  761.     exit(0);
  762. }
  763. SHAR_EOF
  764. fi
  765. echo shar: extracting "'talkd.c'" '(13950 characters)'
  766. if test -f 'talkd.c'
  767. then
  768.     echo shar: will not over-write existing file "'talkd.c'"
  769. else
  770. cat  >'talkd.c' <<\SHAR_EOF
  771. /*
  772.  * talkdemon - the demon for the talk program
  773.  *
  774.  * The talkdemon maintains a linked list of TALK structures, one for each
  775.  * person engaged in a conversation. The demon sits in the background and
  776.  * 'listens' on msgtype 1 for messages from talk programs. Whenever a talk
  777.  * process starts up or exits, it sends a message to the demon. The demon
  778.  * examines the message to see if it is and startup or an exit message.
  779.  * If it is the former, the demon compares the new structure with the existing
  780.  * list and manages to determine a set of send/receive msgtypes. (Each
  781.  * conversation gets its own set) Now, ctl messages. When the first half
  782.  * of a conversation (the originator) starts up, it has to wait for the    
  783.  * other process to start. If the demon determines that a talk process is
  784.  * an originator, in addition to the send/receive pair, the demon sends back
  785.  * a ctltype. The originating talk process waits on this ctltype for a demon
  786.  * message. This is sent when the second half of the conversation starts
  787.  * up (the responder). When either talk process exits, it sends a message
  788.  * to the demon as well as SIGUSR1 to the other process. When the demon
  789.  * receives an exit message, it removes that process's TALK structure
  790.  * from the linked list.
  791.  *
  792.  * AUTHOR
  793.  *    Edward C. Bennett (edward@ukecc)
  794.  *
  795.  * Copyright 1985 by Edward C. Bennett
  796.  *
  797.  * Permission is given to alter this code as needed to adapt it to forign
  798.  * systems provided that this header is included and that the original
  799.  * author's name is preserved.
  800.  */
  801. #include <stdio.h>
  802. #include <signal.h>
  803. #include "talk.h"
  804. #include <sys/stat.h>
  805.  
  806. #define    CONSOLE    "/dev/console"    /* Where to write errors if talkd exits */
  807.  
  808. /*
  809.  * Each conversationalist gets one of these
  810.  */
  811. typedef    struct    talk    {
  812.     char        user[NAMESIZ];        /* The user */
  813.     char        other[NAMESIZ];        /* Who they are talking to */
  814.     char        tty[LINESIZ];        /* The line of the PARTNER */
  815.     long        types;            /* Msgtype index */
  816.     int        pid;    /* pid of the user's talk process (what else?)*/
  817.     struct    talk    *next;
  818. } TALK;
  819.  
  820. int    msqid;
  821. char    *program, errbuf[BUFSIZ];
  822. void    exit(), free();
  823.  
  824. main(argc, argv)
  825. int argc;
  826. char **argv;
  827. {
  828.     TALK        *Head, *Addper(), *Delper();
  829.     key_t        msgkey, ftok();
  830.     long        ctl, Link();
  831.     int        i, avail, Finish();
  832.  
  833.     program = *argv;
  834.  
  835.     if (fork())
  836.         exit(0);
  837.  
  838.     setpgrp();
  839.     for (i = 0; i < NSIG; i++)
  840.         signal(i, Finish);
  841.  
  842.     msgkey = ftok(TALK_PATH, MAGIC_ID);
  843.  
  844.     if ((msqid = msgget(msgkey, MSGQ_PERMS|IPC_CREAT|IPC_EXCL)) == -1) {
  845.         sprintf(errbuf, "%s: Unable to create talk msgqueue(%d)", program, errno);
  846.         Finish(NSIG);
  847.     }
  848.  
  849.     Head = (TALK *)NULL;
  850.     /*
  851.      * The demon sits in this loop, waiting for a message
  852.      * from a potential user.
  853.      */
  854.     for (;;) {
  855. #ifdef DEBUG
  856.         fflush(stdout);
  857. #endif
  858.         if (msgrcv(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, (long)1, 0) == -1) {
  859.             sprintf(errbuf, "%s: msgrcv failure(%d)", program, errno);
  860.             Finish(NSIG);
  861.         }
  862.  
  863.         /*
  864.          * If a message comes in with the pid '0', the talkdemon
  865.          * will remove its msgqueue and exit. This is needed for
  866.          * for reboot procedures. Note that process '0' is ALWAYS
  867.          * the swapper so there is no danger of a user accidently
  868.          * killing the demon.
  869.          */
  870.         if (dmsgbuf.msgval.lines[PIDLOC] == 0) {
  871. #ifdef DEBUG
  872.             printf("\nStoptalk message received\n");
  873. #endif
  874.             sprintf(errbuf, "stopped by a command from stoptalk");
  875.             Finish(NSIG);
  876.         }
  877.  
  878.         /*
  879.          * A message with a pid of '1' is a request for status
  880.          * message. Status info is returned on msgtype 3. Note
  881.          * that process '1' is ALWAYS /etc/init so it is safe to
  882.          * assume that a message with a pid of '1' is an info
  883.          * request.
  884.          */
  885.         if (dmsgbuf.msgval.lines[PIDLOC] == 1) {
  886. #ifdef DEBUG
  887.             printf("\nInfotalk status request message received\n");
  888. #endif
  889.             Status(Head);
  890.             continue;
  891.         }
  892.  
  893.         /*
  894.          * When a users exits talk, he sends a removal message to
  895.          * the demon. Removal messages are identified by a negative
  896.          * pid.
  897.          */
  898.         if (dmsgbuf.msgval.lines[PIDLOC] < 0) {
  899. #ifdef DEBUG
  900.             printf("\nRemoval message received\n");
  901. #endif
  902.             Head = Delper(Head, dmsgbuf.msgval.lines[PIDLOC]);
  903.             continue;
  904.         }
  905.  
  906. #ifdef DEBUG
  907.         printf("\nInitiate message from: %s pid: %d to: %s\n",
  908.             dmsgbuf.msgval.mtext,
  909.             dmsgbuf.msgval.lines[PIDLOC],
  910.             &dmsgbuf.msgval.mtext[NAMESIZ]);
  911. #endif
  912.  
  913.         /*
  914.          * Determine the availability of the potential partner.
  915.          */
  916.         avail = Find(&dmsgbuf.msgval.mtext[8], &dmsgbuf.msgval.mtext[TTYLOC]);
  917. #ifdef DEBUG
  918.         printf("Availability of %s on %s is %d\n", &dmsgbuf.msgval.mtext[8], &dmsgbuf.msgval.mtext[TTYLOC], avail);
  919. #endif
  920.         if (avail == TALKABLE) {
  921.             if ((Head = Addper(Head, &dmsgbuf)) == NULL) {
  922.                 sprintf(errbuf, "%s: Unable to add user, malloc failure(%d)", program, errno);
  923.                 Finish(NSIG);
  924.             }
  925.  
  926.             /*
  927.              * Determine if the new user is an 'originator' or
  928.              * a 'responder' and assign them send and receive
  929.              * msgtypes.
  930.              */
  931.             ctl = Link(Head, &dmsgbuf);
  932.  
  933. #ifdef DEBUG
  934.             printf("Sending %d %d %d to type 2\n",
  935.                 dmsgbuf.msgval.lines[SEND],
  936.                 dmsgbuf.msgval.lines[RECEIVE],
  937.                 dmsgbuf.msgval.lines[CTL]);
  938. #endif
  939.         }
  940.         /*
  941.          * We do this if the requested partner is unavailable.
  942.          */
  943.         else {
  944.             dmsgbuf.msgval.lines[SEND] = avail;
  945.             ctl = -1;
  946.         }
  947.  
  948.         /*
  949.          * Send an acknowledgement to the user informing him of the
  950.          * availability of his partner and the msgtypes to use for
  951.          * sending and receiving.
  952.          */
  953.         dmsgbuf.mtype = 2;
  954.         if (msgsnd(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, 0) == -1) {
  955.             sprintf(errbuf, "%s: msgsnd failure(%d)", program, errno);
  956.             Finish(NSIG);
  957.         }
  958.  
  959.         /*
  960.          * If the most recent message was a 'responder', send
  961.          * a ctl message to the 'originator' telling him that
  962.          * his partner has answered. The ctl message includes
  963.          * the pid of the respondent.
  964.          */
  965.         if (ctl > 0) {
  966. #ifdef DEBUG
  967.             printf("Sending ctl message to %d\n", ctl);
  968. #endif
  969.             dmsgbuf.mtype = ctl;
  970.             dmsgbuf.msgval.lines[PIDLOC] = Head->pid;
  971.             if (msgsnd(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, 0) == -1) {
  972.                 sprintf(errbuf, "%s: msgsnd failure(%d)", program, errno);
  973.                 Finish(NSIG);
  974.             }
  975.         }
  976.     }
  977. }
  978.  
  979. /*
  980.  * Finish - clean up
  981.  *
  982.  * Finish();
  983.  *
  984.  * Finish remove the msgqueue and exits. It is normally not called
  985.  * but is here in case the demon encounters an error.
  986.  */
  987. Finish(sig)
  988. int sig;
  989. {
  990.     FILE        *fp, *fopen();
  991.     time_t        tloc, time();
  992.     char        *ctime();
  993.     int        rmv;
  994.  
  995.     if (sig != NSIG)
  996.         sprintf(errbuf, "caught signal #%d", sig);
  997.  
  998.     rmv = msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL);
  999.  
  1000.     if ((fp = fopen(CONSOLE, "w")) != NULL) {
  1001.         tloc = time((long *)0);
  1002.         fprintf(fp, "talkdemon exiting: %s", ctime(&tloc));
  1003.         fprintf(fp, "%s\n", errbuf);
  1004.         if (rmv == 0) {
  1005.             fprintf(fp, "talk msgqueue removed\n");
  1006. #ifdef DEBUG
  1007.             printf("%s: msgqueue removed. demon exiting\n", program);
  1008. #endif
  1009.         }
  1010.         else {
  1011.             fprintf(fp, "talk msgqueue not removed\n");
  1012. #ifdef DEBUG
  1013.             printf("%s: msgqueue not removed. demon exiting\n", program);
  1014. #endif
  1015.         }
  1016.     }
  1017.     exit(1);
  1018. }
  1019.  
  1020. /*
  1021.  * Status - report the status of the talkdemon
  1022.  *
  1023.  * Status(Head);
  1024.  *    Head    is a pointer to the first TALK structure in the user list
  1025.  *
  1026.  * Status runs through the current list of talk users and sends out one status
  1027.  * msgbuf for each user. All messages are sent to msgtype 3 which is reserved
  1028.  * for this use.
  1029.  *
  1030.  */
  1031. Status(Head)
  1032. TALK *Head;
  1033. {
  1034.     dmsgbuf.mtype = STATUS;
  1035.  
  1036.     for (; Head; Head = Head->next) {
  1037.         strncpy(dmsgbuf.msgval.mtext, Head->user, NAMESIZ);
  1038.         strncpy(&dmsgbuf.msgval.mtext[NAMESIZ], Head->other, NAMESIZ);
  1039.         strncpy(&dmsgbuf.msgval.mtext[TTYLOC], Head->tty, LINESIZ);
  1040.         /*
  1041.          * Do a little bit play to squeeze in some extra infomation.
  1042.          * No entirely kosher, but it will only screw up in already
  1043.          * hazardous situations. (types > 2^16)
  1044.          */
  1045.         dmsgbuf.msgval.lines[PIDLOC] = Head->types;
  1046.         dmsgbuf.msgval.lines[PIDLOC] <<= 16;
  1047.         dmsgbuf.msgval.lines[PIDLOC] += Head->pid;
  1048.  
  1049.         if (msgsnd(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, 0) == -1) {
  1050.             sprintf(errbuf, "%s: msgsnd failure(%d)", program, errno);
  1051.             Finish(NSIG);
  1052.         }
  1053.     }
  1054.     /*
  1055.      * A message containing a pid of '0' indicates the end of the status
  1056.      * information.
  1057.      */
  1058.     dmsgbuf.msgval.lines[PIDLOC] = 0;
  1059.     if (msgsnd(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, 0) == -1) {
  1060.         sprintf(errbuf, "%s: msgsnd failure(%d)", program, errno);
  1061.         Finish(NSIG);
  1062.     }
  1063. #ifdef DEBUG
  1064.     printf("End-of-status message written\n");
  1065. #endif
  1066. }
  1067.  
  1068. /*
  1069.  * Link - determine send and receive msgtypes for a TALK structure
  1070.  *
  1071.  * ctl = Link(Head, bufptr)
  1072.  *    ctl    is a ctl type for the TALK structure
  1073.  *    Head    is a pointer to the first TALK structure in the list,
  1074.  *        which is ALWAYS the most recently added.
  1075.  *    bufptr    is a pointer to a DMSG buffer.
  1076.  *
  1077.  * The newest TALK structure is compared against the rest of the list to
  1078.  * determine if the structure belongs to an 'originator' or a 'responder'.
  1079.  * If it's the former, a send/receive/ctl msgtype triple is selected, if
  1080.  * the latter, a send/receive pair is taken from the matched initiator's
  1081.  * structure.
  1082.  *
  1083.  * If the TALK structure belongs to a 'responder', the ctl msgtype for the
  1084.  * corresponding 'originator' is returned, otherwise a zero is returned.
  1085.  */
  1086. long
  1087. Link(Head, bufptr)
  1088. TALK *Head;
  1089. DMSG *bufptr;
  1090. {
  1091.     TALK        *ptr;
  1092.     int        i = 4;
  1093.  
  1094.     /*
  1095.      * See if there is a 'partner' for the new person.
  1096.      * This is done by looking for a TALK structure with the same
  1097.      * names, but reversed.
  1098.      */
  1099.     for (ptr = Head->next; ptr; ptr = ptr->next) {
  1100.         /*
  1101.          * Perform a sanity check on the list. Occasionally
  1102.          * talk process die without removing their TALK
  1103.          * structures. Dunno why.
  1104.          *
  1105.          * If a TALK structure represents a dead process, remove
  1106.          * it. Notice that the return value of Delper() is ignored.
  1107.          * We can do this because ptr->pid will never be Head->pid.
  1108.          */
  1109.         if (kill(ptr->pid, 0) == -1)
  1110.             (void) Delper(Head, ptr->pid);
  1111.  
  1112.         if (!strncmp(ptr->user, Head->other, NAMESIZ) &&
  1113.             !strncmp(ptr->other, Head->user, NAMESIZ)) {
  1114.             bufptr->msgval.lines[RECEIVE] = ptr->types;
  1115.             bufptr->msgval.lines[SEND] = ptr->types + 1;
  1116.             bufptr->msgval.lines[CTL] = 0;
  1117.             bufptr->msgval.lines[PIDLOC] = ptr->pid;
  1118.             /*
  1119.              * NULL the tty pointers of the structures
  1120.              * to show that they're connected.
  1121.              */
  1122.             *Head->tty = NULL;
  1123.             *ptr->tty = NULL;
  1124.             Head->types = ptr->types;
  1125.  
  1126.             return(ptr->types + 2);
  1127.         }
  1128.     }
  1129.  
  1130.     /*
  1131.      * If we got this far, the new person is an 'originator'.
  1132.      *
  1133.      * First, find an unused send/receive/ctl triple.
  1134.      */
  1135.     do {
  1136.         for (ptr = Head->next; ptr; ptr = ptr->next) {
  1137.             if (i == ptr->types) {
  1138.                 i += 3;
  1139.                 break;
  1140.             }
  1141.         }
  1142.     } while (ptr);
  1143.     Head->types = i;
  1144.     bufptr->msgval.lines[SEND] = i;
  1145.     bufptr->msgval.lines[RECEIVE] = i + 1;
  1146.     bufptr->msgval.lines[CTL] = i + 2;
  1147.  
  1148.     return(0);
  1149. }
  1150.  
  1151. /*
  1152.  * Find - locate the partner and determine their availability
  1153.  *
  1154.  * avail = Find(p1, p2);
  1155.  *    avail    is the availability of the requested partner
  1156.  *    p1    is a pointer to the partner's name
  1157.  *    p2    is a pointer to the name of the partner's tty
  1158.  *
  1159.  * Find reads UTMP_FILE to get the tty line of the initiator's requested
  1160.  * partner. If no tty was given, Find() fills it into p2.
  1161.  */
  1162. Find(partner, line)
  1163. char *partner, *line;
  1164. {
  1165.     struct    stat    lstat;
  1166.     struct    utmp    utmp;
  1167.     char        tmpbuf[18];
  1168.     int        fd, flag;
  1169.  
  1170.     flag = 0;
  1171.  
  1172.     if ((fd = open(UTMP_FILE, 0)) >= 0) {
  1173.         while (read(fd, (char *)&utmp, sizeof(utmp)) == sizeof(utmp)) {
  1174. #ifndef OLDUTMP
  1175.             if (utmp.ut_type != USER_PROCESS)
  1176.                 continue;
  1177. #endif
  1178.  
  1179.             if (!strncmp(utmp.ut_line, line, LINESIZ) &&
  1180.                 strncmp(utmp.ut_name, partner, NAMESIZ)) {
  1181.                 flag = -1;
  1182.                 break;
  1183.             }
  1184.             else if (!strncmp(utmp.ut_name, partner, NAMESIZ)) {
  1185.                 flag++;
  1186.                 /* if line was speced and found him on this
  1187.                    line, make flag one even if he was already
  1188.                    found on another line */
  1189.                 if (*line != NULL &&
  1190.                     !strncmp(utmp.ut_line, line, LINESIZ)) {
  1191.                     flag = 1;
  1192.                     break;
  1193.                 }
  1194.  
  1195.                 /* safe to copy line if not speced since it
  1196.                    cant match again */
  1197.                 if (*line == NULL)
  1198.                     strcpy(line, utmp.ut_line);
  1199. #ifdef DEBUG
  1200.                 printf("%s found on %s\n", partner, line);
  1201. #endif
  1202.             }
  1203.         }
  1204.         close(fd);
  1205.     }
  1206.     else {
  1207.         sprintf(errbuf, "%s: cannot open %s(%d)", program, UTMP_FILE, errno);
  1208.         Finish(NSIG);
  1209.     }
  1210.  
  1211.     if (flag == 0)
  1212.         return(NOTLOGGEDON);
  1213.     if (flag < 0)
  1214.         return(NOTONLINE);
  1215.     if (flag > 1)
  1216.         return(LOGGEDMORE);
  1217.  
  1218.     strcpy(tmpbuf, line);
  1219.     strcpy(line, "/dev/");
  1220.     strcat(line, tmpbuf);
  1221.     stat(line, &lstat);
  1222.     if (!(lstat.st_mode & 0002))
  1223.         return(NOTWRITE);
  1224.  
  1225.     return(TALKABLE);
  1226. }
  1227.  
  1228. /*
  1229.  * Addper - add a new user to the list
  1230.  *
  1231.  * tp = Addper(hp, mp);
  1232.  *    tp    is a pointer to new TALK structure
  1233.  *    hp    is a pointer to the Head of the TALK list
  1234.  *    mp    is a pointer to the dmsgbuf
  1235.  *
  1236.  * A new TALK structure is allocated and linked in at the head of the list.
  1237.  * Data from the just-received dmsg is copied into the new structure.
  1238.  * A pointer to the new structure is returned unless malloc() was unable
  1239.  * to allocate space, in which case NULL is returned.
  1240.  */
  1241. TALK *
  1242. Addper(ptr, mptr)
  1243. TALK *ptr;
  1244. DMSG *mptr;
  1245. {
  1246.     TALK        *p;
  1247.     char        *malloc();
  1248.  
  1249.     if ((p = (TALK *)malloc(sizeof(TALK))) == NULL)
  1250.         return(NULL);
  1251.  
  1252.     p->next = ptr;
  1253.  
  1254.     strncpy(p->user, mptr->msgval.mtext, NAMESIZ);
  1255.     strncpy(p->other, &mptr->msgval.mtext[NAMESIZ], NAMESIZ);
  1256.     strncpy(p->tty, &mptr->msgval.mtext[TTYLOC], LINESIZ);
  1257.     p->pid = mptr->msgval.lines[PIDLOC];
  1258.  
  1259.     return(p);
  1260. }
  1261.  
  1262. /*
  1263.  * Delper - remove somebody
  1264.  *
  1265.  * hp = Delper(p, pid);
  1266.  *    hp    is a pointer to the (possibly new) head of the list
  1267.  *    p    is a pointer to the head of the list
  1268.  *    pid    is the pid of the structure to remove
  1269.  *
  1270.  * The person whose talk pid is given is removed from the list.
  1271.  * The, possibly new, head of the list is returned.
  1272.  */
  1273. TALK *
  1274. Delper(Head, pid)
  1275. TALK *Head;
  1276. int pid;
  1277. {
  1278.     TALK        *ptr, *lastptr;
  1279.  
  1280.     pid = abs(pid);    /* Make sure pid is positive */
  1281.     ptr = Head;
  1282.     lastptr = (TALK *)NULL;
  1283.  
  1284.     while (ptr->pid != pid) {
  1285.         lastptr = ptr;
  1286.         ptr = ptr->next;
  1287.  
  1288.         if (ptr == (TALK *)NULL)    /* Just to be safe */
  1289.             return(Head);
  1290.     }
  1291.  
  1292.     if (lastptr)
  1293.         lastptr->next = ptr->next;
  1294.     else
  1295.         Head = ptr->next;
  1296.  
  1297. #ifdef DEBUG
  1298.     printf("Removing: %s %d from list\n", ptr->user, pid);
  1299. #endif
  1300.  
  1301.     free((char *)ptr);
  1302.  
  1303.     return(Head);
  1304. }
  1305. SHAR_EOF
  1306. fi
  1307. echo shar: extracting "'infotalk.c'" '(1673 characters)'
  1308. if test -f 'infotalk.c'
  1309. then
  1310.     echo shar: will not over-write existing file "'infotalk.c'"
  1311. else
  1312. cat  >'infotalk.c' <<\SHAR_EOF
  1313. /*
  1314.  * infotalk - provide current status of the talk system
  1315.  *
  1316.  * AUTHOR
  1317.  *    Edward C. Bennett (edward@ukecc)
  1318.  *
  1319.  * Copyright 1985 by Edward C. Bennett
  1320.  *
  1321.  * Permission is given to alter this code as needed to adapt it to forign
  1322.  * systems provided that this header is included and that the original
  1323.  * author's name is preserved.
  1324.  */
  1325. #include <stdio.h>
  1326. #include "talk.h"
  1327.  
  1328. int    msqid;
  1329.  
  1330. main(argc, argv)
  1331. int argc;
  1332. char *argv[];
  1333. {
  1334.     key_t        msgkey, ftok();
  1335.     void        exit();
  1336.     int        busy;
  1337.  
  1338.     msgkey = ftok(TALK_PATH, MAGIC_ID);
  1339.  
  1340.     if ((msqid = msgget(msgkey, MSGQ_PERMS)) == -1) {
  1341.         fprintf(stderr, "%s: Nonexistant talk msgqueue\n", argv[0]);
  1342.         exit(1);
  1343.     }
  1344.  
  1345.     dmsgbuf.msgval.lines[PIDLOC] = 1;
  1346.     dmsgbuf.mtype = 1;
  1347.  
  1348.     /*
  1349.      * Send the request to the demon
  1350.      */
  1351.     if (msgsnd(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, 0) == -1) {
  1352.         fprintf(stderr, "%s: msgsnd failure(%d)\n", argv[0], errno);
  1353.         exit(1);
  1354.     }
  1355. #ifdef DEBUG
  1356.     printf("Info request sent to talkdemon\n");
  1357. #endif
  1358.  
  1359.     printf("Talker      Talkee      TTY             PID    MTYPE\n");
  1360.     do {
  1361.         if (msgrcv(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, (long)STATUS, 0) == -1) {
  1362.             fprintf(stderr, "%s: msgrcv failure(%d)\n", argv[0], errno);
  1363.             exit(1);
  1364.         }
  1365. #ifdef DEBUG
  1366.     printf("Info message received from talkdemon\n");
  1367. #endif
  1368.         if (dmsgbuf.msgval.lines[PIDLOC]) {
  1369.             printf("%-12s", dmsgbuf.msgval.mtext);
  1370.             printf("%-12s", &dmsgbuf.msgval.mtext[NAMESIZ]);
  1371.             printf("%-16s", &dmsgbuf.msgval.mtext[TTYLOC]);
  1372.             printf("%5d", dmsgbuf.msgval.lines[PIDLOC] & 0177777);
  1373.             printf("  %5d\n", dmsgbuf.msgval.lines[PIDLOC] >> 16);
  1374.             busy++;
  1375.         }
  1376.     } while (dmsgbuf.msgval.lines[PIDLOC]);
  1377.     if (!busy)
  1378.         printf("No one is currently using talk\n");
  1379. }
  1380. SHAR_EOF
  1381. fi
  1382. echo shar: extracting "'stoptalk.c'" '(1814 characters)'
  1383. if test -f 'stoptalk.c'
  1384. then
  1385.     echo shar: will not over-write existing file "'stoptalk.c'"
  1386. else
  1387. cat  >'stoptalk.c' <<\SHAR_EOF
  1388. /*
  1389.  * stoptalk - shut down the talk facility
  1390.  *
  1391.  * SYNOPSIS
  1392.  *    stoptalk
  1393.  *
  1394.  * Stoptalk is used to stop the talk facility. Prior to a reboot the
  1395.  * current talk msgqueue needs to be removed manually because the
  1396.  * reboot procedure does not clear system msgqueues. The talkdemon
  1397.  * is incapable of removing its own msgqueue automatically because
  1398.  * /etc/kill stops process with SIGKILL which cannot be caught.
  1399.  *
  1400.  * Stoptalk sends a message to the talkdemon instructing it to exit.
  1401.  * If this fails, stoptalk tries to remove the msgsqueue itself.
  1402.  *
  1403.  * AUTHOR
  1404.  *    Edward C. Bennett (edward@ukecc)
  1405.  *
  1406.  * Copyright 1985 by Edward C. Bennett
  1407.  *
  1408.  * Permission is given to alter this code as needed to adapt it to forign
  1409.  * systems provided that this header is included and that the original
  1410.  * author's name is preserved.
  1411.  */
  1412. #include <stdio.h>
  1413. #include "talk.h"
  1414.  
  1415. main(argc, argv)
  1416. int argc;
  1417. char **argv;
  1418. {
  1419.     key_t        msgkey, ftok();
  1420.     void        exit();
  1421.     int        msqid;
  1422.  
  1423.     msgkey = ftok(TALK_PATH, MAGIC_ID);
  1424.  
  1425.     if ((msqid = msgget(msgkey, MSGQ_PERMS)) == -1) {
  1426.         fprintf(stderr, "%s: Nonexistant talk msgqueue\n", *argv);
  1427.         exit(1);
  1428.     }
  1429.  
  1430.     /*
  1431.      * Set up a msg containing the pid '0'. This will signal
  1432.      * the talkdemon to exit gracefully.
  1433.      */
  1434.     dmsgbuf.msgval.lines[PIDLOC] = 0;
  1435.     dmsgbuf.mtype = 1;
  1436.  
  1437.     /*
  1438.      * Send the 'kill' msg to the demon.
  1439.      */
  1440.     if (msgsnd(msqid, (struct msgbuf *)&dmsgbuf, MSGSIZ, IPC_NOWAIT) == 0) {
  1441.         /*
  1442.          * Wait while the demon prints its exit message
  1443.          */
  1444.         sleep(2);
  1445.         exit(0);
  1446.     }
  1447.     /*
  1448.      * The graceful method didn't work, get brutal
  1449.      */
  1450.     fprintf(stderr, "%s: msgsnd failure(%d)\n", *argv, errno);
  1451.     if (msgctl(msqid, IPC_RMID, (struct msqid_ds *)NULL) == 0) {
  1452.         fprintf(stderr, "%s: Talk msgqueue removed\n", *argv);
  1453.         exit(0);
  1454.     }
  1455.  
  1456.     fprintf(stderr, "%s: Unable to remove talk msgqueue\n", *argv);
  1457.     exit(1);
  1458. }
  1459. SHAR_EOF
  1460. fi
  1461. :    End of shell archive
  1462. exit 0
  1463.