home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3004 < prev    next >
Internet Message Format  |  1991-03-06  |  39KB

  1. From: lm03_cif@troi.cc.rochester.edu (Larry Moss)
  2. Newsgroups: alt.sources
  3. Subject: nmsg - a 'write' style program to send messages across the net
  4. Message-ID: <12639@ur-cc.UUCP>
  5. Date: 6 Mar 91 20:24:58 GMT
  6.  
  7. Nmsg was written to send messages to users across the net when a 'talk'
  8. isn't desired or simply doesn't work.  Periodically there are requests
  9. for sample code using sockets.  If nothing else this is an example of
  10. that.  It may be preferred to /bin/write even on the local host since it
  11. also does things like word wrap.
  12.  
  13. The program works farily well -- usually.  It can basically be expected
  14. to work on a sun4 running sunOS 4.0.3.  It should work on other machines
  15. and other versions of the OS (not sure about other flavors of UNIX) but
  16. for some reason it doesn't.  Before I explain the problems I'd just like
  17. to apologize for posting a program that doesn't have all the bugs worked
  18. out.  I wasn't really sure if it was appropriate to post something like
  19. this, but several people that I asked thought it was a reasonable idea.
  20. I just hope someone reading this can help us out.  I'm posting this now
  21. for two reasons.  1) Gavin and I no longer have any idea what to try to
  22. fix it and would like suggestions.  2) We have now been asked by system
  23. administrators here to not run a daemon on these machines until the bugs
  24. are out.  It's a perfectly reasonable request but one of our problems is
  25. that it doesn't compile on the one machine we do have permission to run it
  26. on (a sun3 running 4.1) so again any suggestions would be appreciated.
  27.  
  28. Problems:
  29. Sun4 OS4.0.3 - when the client is paused (^Z) the daemon stops also.
  30. I have no idea why this is happening but this only a problem if the
  31. client is then killed before it receives (and sends on to the daemon) a
  32. SIGCONT.  If this happens the daemon just hangs uselessly.
  33.  
  34. Sun4 OS4.1 - If the client is stopped (^Z), continuing it (fg) does not
  35. send a SIGCONT to the client so it never goes back into cbreak and noecho
  36. modes.
  37.  
  38. Sun3 OS4.1 - Doesn't compile - but we haven't spent much time on that.
  39.  
  40. So we're really confused about why it behaves so differently on the
  41. differnet machines.
  42.  
  43. Thanks for help, suggestions, etc...
  44. Larry
  45. --
  46. lm03_cif@uhura.cc.rochester.edu / "I'm so tired... I was up all night
  47. lmo3_ss@db1.cc.rochester.edu   / trying to round off infinity."
  48. lmo3_ss@uordbv.bitnet         / - Stephen Wright
  49. --
  50.  
  51. #! /bin/sh
  52. # This is a shell archive.  Remove anything before this line, then unpack
  53. # it by saving it into a file and typing "sh file".  To overwrite existing
  54. # files, type "sh file -c".  You can also feed this as standard input via
  55. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  56. # will see the following message at the end:
  57. #        "End of shell archive."
  58. # Contents:  README input.c msgd.c nmsg.c socklib.c utmp.c input.h
  59. #   socket.h socketnum.h msgd.man nmsg.man Makefile TODO
  60. # Wrapped by lm03_cif@troi.cc.rochester.edu on Wed Mar  6 15:03:06 1991
  61. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  62. if test -f 'README' -a "${1}" != "-c" ; then 
  63.   echo shar: Will not clobber existing file \"'README'\"
  64. else
  65. echo shar: Extracting \"'README'\" \(2078 characters\)
  66. sed "s/^X//" >'README' <<'END_OF_FILE'
  67. XWHAT IS NMSG?
  68. XIt's basically a program to replace /bin/write that will send messages
  69. Xover the net and do other really nifty things.  Well, kinda nifty anyway.
  70. XIf nothing else it is an example of network communication and stuff.
  71. XThere seem to be requests fairly often for samples like that for people
  72. Xto look at.
  73. X
  74. XBRIEF HISTORY (read: disclaimer) 
  75. XThis program was originally bits of little things that were kind of
  76. Xthrown together.  Most of the stuff in it (handling sockets, handling
  77. Xinput in cbreak mode, etc) was written because neither of us had ever
  78. Xdone it before and thought it might be interesting.  Putting stuff in a
  79. Xuseful program was more or less an afterthought.  In fact the socket
  80. Xstuff was actually sitting around for over a year because after writing
  81. Xit I didn't know what to do with it.  It does do exactly what it was
  82. Xmeant to most of the time.  We both learned a lot from it, but ran into
  83. Xsome problems that we can't solve.  Since this was originally several
  84. Xdiffernet hacked together pieces that two people were working on it may
  85. Xnot seem as clear to someone reading it as we think.  We have tried to
  86. Xleave the code clean and easy to read and tried to do things efficiently
  87. X(except where pure laziness took over).
  88. X
  89. XINSTALLATION
  90. XShould be as simple as editing the Makefile.  Everything that should need
  91. Xto be changed is commented.  If you wish to change the port that the
  92. Xserver runs on, edit socketnum.h.  This is the only way we have right now
  93. Xof restricting who can send messages to particular machines.
  94. X
  95. XTHANKS TO
  96. XMark Sirota who we borrowed some code from.  utmp.c was taken from him.
  97. XThat's one of the examples of pure laziness.
  98. X
  99. XCOPYING
  100. XDo whatever you wish with the code as long as we get credit for what
  101. Xwe've done.  If you find this useful in any way or wish to do something
  102. Xwith parts of the code that it wasn't originally intended for, let us
  103. Xknow.  We're really just wondering if we've managed to do something
  104. Xuseful with our time.  (Consider it an ego thing.)
  105. X
  106. X- Larry
  107. X
  108. XLarry Moss    lm03_cif@cc.rochester.edu
  109. XGavin Stark    gest_ss@cc.rochester.edu
  110. END_OF_FILE
  111. if test 2078 -ne `wc -c <'README'`; then
  112.     echo shar: \"'README'\" unpacked with wrong size!
  113. fi
  114. # end of 'README'
  115. fi
  116. if test -f 'input.c' -a "${1}" != "-c" ; then 
  117.   echo shar: Will not clobber existing file \"'input.c'\"
  118. else
  119. echo shar: Extracting \"'input.c'\" \(9749 characters\)
  120. sed "s/^X//" >'input.c' <<'END_OF_FILE'
  121. X/*
  122. X * input.c: Larry Moss (lm03_cif@cc.rochester.edu)
  123. X *        Fall, 1990
  124. X *
  125. X * This was written as part of nmsg, a version of write that can be used
  126. X * over the net, by Larry Moss and Gavin Stark.  Feel free to do whatever 
  127. X * you want with this code as long as my name stays on it and I receive
  128. X * credit for what I've done.
  129. X */
  130. X/*
  131. X * Here are the i/o routines to be used with nmsg.  This code deals with 
  132. X * ioctl to set the terminal the way we want it (cbreak mode, no echo).  Some
  133. X * of this may not be done in the cleanest ways, but it is functional.  All
  134. X * normal UNIX line editting stuff (C-U, C-W, etc.) are included.  I think it
  135. X * handles tabs correctly also.  I've included a bunch of things just to learn 
  136. X * how to do it so if anyone reading this has suggestions for doing things 
  137. X * better, I'm listening.
  138. X */
  139. X
  140. X#include <stdio.h>
  141. X#include <string.h>
  142. X#include <signal.h>
  143. X#include <sgtty.h>
  144. X#include <ctype.h>
  145. X#include <pwd.h>
  146. X#include <time.h>
  147. X#include <vfork.h>
  148. X#include <sys/types.h>
  149. X#include <sys/wait.h>
  150. X
  151. X#include "input.h"
  152. X
  153. Xvoid getmessage(message, maxlength)
  154. Xchar    *message;
  155. Xint    maxlength;
  156. X{
  157. X    FILE        *fp;
  158. X    char        savename[1000];
  159. X    int        messagelength;
  160. X    time_t        cur_time;
  161. X    struct tm    *t;
  162. X    char        tempbuf[BUFSIZ];
  163. X
  164. X    /*
  165. X     * Set up the header for the message. Get the time.
  166. X     */
  167. X    time(&cur_time);
  168. X    t = localtime(&cur_time);
  169. X
  170. X    get_input(message);
  171. X
  172. X    sprintf(tempbuf, "\007\r\nFrom %s on %s at %d:%02d\r\n%s\r\n",
  173. X        getusername(), getttyname(), t->tm_hour,
  174. X        t->tm_min,message);
  175. X
  176. X    /*
  177. X     * Save the message
  178. X     */
  179. X    sprintf(savename, "%s/.oldmsg", getenv("HOME"));
  180. X
  181. X    if((fp = fopen(savename, "w")) == NULL)
  182. X        fprintf(stderr, "error writing to %s", savename);
  183. X    else 
  184. X        fputs(message, fp);
  185. X
  186. X    fclose(fp);
  187. X
  188. X    /*
  189. X     * The text needs to be in message for the calling procedure.
  190. X     */
  191. X    strcpy(message,tempbuf);
  192. X}
  193. X
  194. X
  195. Xvoid get_input(message)
  196. Xchar    *message;
  197. X{
  198. X    int        messagelength, c, i, ctrlc=0, cp, column=0;
  199. X    int        linelength;
  200. X    char        temp[80];
  201. X
  202. X    messagelength = strlen(message);
  203. X
  204. X    /*
  205. X     * If the program is not being run interactively it's real simple
  206. X     * to get the message.
  207. X     */
  208. X    if(!isatty(0)) {
  209. X        messagelength = readmessage(message, messagelength, stdin);
  210. X        return;
  211. X    }
  212. X    
  213. X    /*
  214. X     * If the program is being used interactively we want to set it up
  215. X     * for things like word wrap and make sure it handles signals
  216. X     * correctly.
  217. X     */
  218. X    setterm();
  219. X
  220. X    puts("Enter your message, and terminate with Ctl-D or '.'.");
  221. X    printf("Messages are limited to %d characters.\n\n", MAXLENGTH);
  222. X    fflush(stdout);
  223. X
  224. X    while((c = getchar()) != CTL('d')) {
  225. X        switch (c) {
  226. X            case CTL('c'):
  227. X                if(ctrlc)
  228. X                    interrupt();
  229. X                else {
  230. X                    ctrlc=1;
  231. X                    puts("\n** interrupt -- one more to kill message **");
  232. X                }
  233. X                break;
  234. X            case CTL('h'):
  235. X            case DEL:
  236. X                if(messagelength > 0) {
  237. X                    BACKSPACE;
  238. X                    message[--messagelength] = NULL;
  239. X                    column--;
  240. X                }
  241. X                break;
  242. X            case '\n':
  243. X                putchar(c);
  244. X                message[messagelength++] = '\r';
  245. X                message[messagelength++] = '\n';
  246. X                if ((message[messagelength-3] == '.') && (column ==1)) {
  247. X                    message[messagelength-3] = NULL;
  248. X                    unsetterm();
  249. X                    return;
  250. X                }
  251. X                column = 0;
  252. X                break;
  253. X            case KILL:
  254. X                while ((message[messagelength-1] != '\n') &&
  255. X                       (messagelength > 0)) {
  256. X                    message[--messagelength] = NULL;
  257. X                    BACKSPACE;
  258. X                }
  259. X                column = 0;
  260. X                break;
  261. X            case WERASE:
  262. X                while ((!isspace(message[messagelength-1])) &&
  263. X                       (messagelength > 0)) {
  264. X                    message[--messagelength] = NULL;
  265. X                    BACKSPACE;
  266. X                    column--;
  267. X                }
  268. X                break;
  269. X            case CTL('r'):
  270. X                putchar('\n');
  271. X                fputs(&message[messagelength - column],stdout);
  272. X                break;
  273. X            case TAB:
  274. X                for(i=0; i <= (column % 8); i++) {
  275. X                    putchar(' ');
  276. X                    message[messagelength++] = ' ';
  277. X                    column++;
  278. X                }
  279. X                break;
  280. X            case '~':
  281. X                if(message[messagelength-1] == '\n' || messagelength ==0) {
  282. X                    putchar(c);
  283. X                    messagelength = handle_tilde(message,messagelength);
  284. X                    break;
  285. X                }
  286. X            default:
  287. X                if(column >= 78) {
  288. X                    for(cp=messagelength;!isspace(message[cp]); cp--)
  289. X                        BACKSPACE;
  290. X                    strcpy(temp, &message[cp+1]);
  291. X                    message[cp] = '\r'; message[cp+1]='\n';
  292. X                    strcpy(&message[cp+2], temp);
  293. X                    messagelength++;
  294. X                    fputs(&message[cp],stdout);
  295. X                    column = messagelength - cp;
  296. X                }
  297. X                putchar(c);
  298. X                message[messagelength++] = c;
  299. X                column++;
  300. X                break;
  301. X        }
  302. X    }
  303. X    puts("EOF");
  304. X    unsetterm();
  305. X}
  306. X
  307. X/*
  308. X * Set the terminal to cbreak mode, turn off echo and prevent special
  309. X * characters from affecting the input.  We will handle EOF and other fun
  310. X * stuff our own way.  Backup copies of the current setup will be kept
  311. X * to insure the terminal gets returned to its initial state.
  312. X */
  313. Xvoid setterm() {
  314. X    struct sgttyb    termrec;
  315. X    struct tchars    trec;
  316. X
  317. X    signal(SIGINT, interrupt);
  318. X    signal(SIGTSTP, pause);
  319. X    signal(SIGSTOP, pause);
  320. X    signal(SIGCONT, cont);
  321. X
  322. X    gtty(0, &termrec);
  323. X    termrec.sg_flags |= CBREAK;
  324. X    termrec.sg_flags &= ~ECHO;
  325. X    stty(0, &termrec);
  326. X
  327. X    ioctl(0, TIOCGETC, &trec);
  328. X    trec.t_quitc = (char) -1;
  329. X    trec.t_eofc = (char) -1;
  330. X    trec.t_intrc = (char) -1;
  331. X    ioctl(0, TIOCSETC, &trec);
  332. X}
  333. X
  334. X/*
  335. X * Reset terminal settings to the way they were before.  well, that's not
  336. X * really true.  Since I didn't save the original settings, I'll set things
  337. X * to the way they normally are.  I suppose I should do this correctly, but
  338. X * for now, this works.
  339. X */
  340. Xvoid unsetterm() {
  341. X    struct sgttyb    termrec;
  342. X    struct tchars    trec;
  343. X
  344. X    signal(SIGINT, SIG_IGN);
  345. X    signal(SIGTSTP, SIG_IGN);
  346. X    signal(SIGSTOP, SIG_IGN);
  347. X    signal(SIGCONT, SIG_IGN);
  348. X
  349. X    gtty(0, &termrec);
  350. X    termrec.sg_flags &= ~CBREAK;
  351. X    termrec.sg_flags |= ECHO;
  352. X    stty(0, &termrec);
  353. X
  354. X    ioctl(0, TIOCGETC, &trec);
  355. X    trec.t_quitc = CTL('\\');
  356. X    trec.t_eofc = CTL('d');
  357. X    trec.t_intrc = CTL('c');
  358. X    ioctl(0, TIOCSETC, &trec);
  359. X}
  360. X
  361. X/*
  362. X * Interrupt handlers
  363. X */
  364. Xpause() {
  365. X    unsetterm();
  366. X    kill(getpid(), SIGSTOP);
  367. X}
  368. X
  369. Xcont() {
  370. X    setterm();
  371. X}
  372. X
  373. Xinterrupt() {
  374. X    unsetterm();
  375. X    putchar('\n');
  376. X    exit(1);
  377. X}
  378. X
  379. X
  380. X/*
  381. X * Handle tilde commands in messages.
  382. X */
  383. Xint handle_tilde(message, messagelength)
  384. Xchar    *message;
  385. Xint    messagelength;
  386. X{
  387. X    char    command[120], line[MAXLENGTH], *editor, oldmsg[120];
  388. X    static char    tempfile[] = "/tmp/msg.XXXXXX";
  389. X    FILE    *fp;
  390. X    int    i;
  391. X
  392. X    unsetterm();
  393. X    fgets(command, 120, stdin);
  394. X    switch(command[0]) {
  395. X        case 'v':
  396. X            /*
  397. X             * An editor will be invoked
  398. X             * First save text to a temp file so the editor can
  399. X             * deal with it.
  400. X             */
  401. X            mktemp(tempfile);
  402. X            if((fp=fopen(tempfile, "w")) == NULL) {
  403. X                fprintf(stderr, "error opening %s", tempfile);
  404. X                return;
  405. X            }
  406. X            messagelength=0;
  407. X            fputs(message, fp);
  408. X            fclose(fp);
  409. X
  410. X            /*
  411. X             * Figure out which editor will be used.
  412. X             * /usr/ucb/vi will be used unless the editor
  413. X             * environment variable is present.
  414. X             */
  415. X            if((editor=getenv("EDITOR")) == NULL)
  416. X                editor="/usr/ucb/vi";
  417. X
  418. X            /*
  419. X             * Start the new process and ignore interrupts
  420. X             * until the editing is done so th eprocesses don't
  421. X             * fight for input.
  422. X             */
  423. X            if(vfork() == 0) {
  424. X                execl(editor, editor, tempfile, (char *)NULL);
  425. X                exit(0);
  426. X            }
  427. X            wait(0);
  428. X
  429. X            /*
  430. X             * Read in the modified message and get rid of the
  431. X             * temp file.
  432. X             */
  433. X            fp=fopen(tempfile, "r");
  434. X            messagelength=readmessage(message, messagelength, fp);
  435. X            fclose(fp);
  436. X            unlink(tempfile);
  437. X            strcpy(tempfile, "/tmp/msg.XXXXXX");
  438. X            puts("\n-- Continue editing message --");
  439. X            break;
  440. X        case 'r':
  441. X            /*
  442. X             * read contents of file into message.  If no file
  443. X             * is specified try to read the last message sent.
  444. X             */
  445. X            if(strlen(command) == 2) {
  446. X                sprintf(oldmsg, "%s/.oldmsg", getenv("HOME"));
  447. X                if((fp=fopen(oldmsg, "r")) == NULL)
  448. X                    fputs("no old message\n");
  449. X                else
  450. X                    messagelength=readmessage(message, messagelength, fp);
  451. X            }
  452. X            /*
  453. X             * read the file specified.  Handle tildes if
  454. X             * necessary
  455. X             */
  456. X            else {
  457. X                sprintf(oldmsg, "%s", &command[1]);
  458. X                oldmsg[strlen(oldmsg)-1] = NULL;
  459. X                for(i=0;oldmsg[i]==' ' || oldmsg[i]=='\t'; i++);
  460. X                if(oldmsg[i]=='~')
  461. X                if(strcpy(&oldmsg[i], expand(&oldmsg[i])) == NULL) {
  462. X                    fprintf(stderr, "unknown user\n");
  463. X                    break;
  464. X                }
  465. X                if((fp=fopen(&oldmsg[i], "r")) == NULL) {
  466. X                    fprintf(stderr, "***error opening %s***\n", oldmsg);
  467. X                }
  468. X                else {
  469. X                    messagelength=readmessage(message, messagelength, fp);
  470. X                }
  471. X            }
  472. X            fclose(fp);
  473. X            fprintf(stderr, "(Continue.)\n");
  474. X            break;
  475. X        case 'p':
  476. X            /*
  477. X             * print the current message.
  478. X             */
  479. X            puts(message);
  480. X            break;
  481. X    }
  482. X    setterm();
  483. X    return messagelength;
  484. X}
  485. X
  486. X/*
  487. X * this is the routine used to read a message from a file or stdin when
  488. X * input is not coming from a tty.
  489. X */
  490. Xint readmessage(message, messagelength, fp)
  491. Xchar    *message;
  492. Xint    messagelength;
  493. XFILE    *fp;
  494. X{
  495. X    char    line[MAXLENGTH], answer[80];
  496. X    int    linelength;
  497. X    
  498. X    while (fgets(line, MAXLENGTH, fp) != (char *) NULL) {
  499. X        linelength = strlen(line);
  500. X        if (messagelength + linelength + 2 > MAXLENGTH - 1) {
  501. X            linelength = (MAXLENGTH - messagelength - 3);
  502. X            fprintf(stderr, "The last line was truncated to %d characters.\nSend anyway? (y/n) ",
  503. X                linelength);
  504. X            fgets(answer, 80, fp);
  505. X            if (answer[0] != 'y')
  506. X                exit(2);
  507. X            line[linelength]= (char) NULL;
  508. X        }
  509. X        strcpy(message + messagelength, line);
  510. X        messagelength += linelength;
  511. X    }
  512. X    return messagelength;
  513. X}
  514. X
  515. X/*
  516. X * Expand tildes in filenames.  The only way I know of to get the home
  517. X * directory of another user is to look up passwd information.  If we want
  518. X * the user's home directory we can just get it from the environment.
  519. X */
  520. Xchar *expand(filename)
  521. Xchar    *filename;
  522. X{
  523. X    struct passwd    *p;
  524. X    char        tempmsg[120];
  525. X
  526. X    if(filename[1] == '/') {
  527. X        sprintf(tempmsg, "%s%s", getenv("HOME"), &filename[1]);
  528. X        return tempmsg;
  529. X    }
  530. X
  531. X    /*
  532. X     * Try to get user information.  If user information can't be
  533. X     * obtained return NULL
  534. X     */
  535. X    if((p = getpwnam(strtok(&filename[1], "/"))) == (struct passwd *)NULL)
  536. X        return (char *)NULL;
  537. X    sprintf(tempmsg, "%s/%s", p->pw_dir, strtok(NULL, " "));
  538. X    return tempmsg;
  539. X}
  540. END_OF_FILE
  541. if test 9749 -ne `wc -c <'input.c'`; then
  542.     echo shar: \"'input.c'\" unpacked with wrong size!
  543. fi
  544. # end of 'input.c'
  545. fi
  546. if test -f 'msgd.c' -a "${1}" != "-c" ; then 
  547.   echo shar: Will not clobber existing file \"'msgd.c'\"
  548. else
  549. echo shar: Extracting \"'msgd.c'\" \(4283 characters\)
  550. sed "s/^X//" >'msgd.c' <<'END_OF_FILE'
  551. X/*
  552. X * msgd: daemon for the msg program.  Allows users to send messages to
  553. X * other users screens across the net.  The daemon listens to a port and
  554. X * waits for reqeuests to send messages.  If the user is logged in and
  555. X * allowing messages, the daemon accepts the message from the sending
  556. X * machine.
  557. X */
  558. X
  559. X/*
  560. X * Written by Larry Moss (lm03_cif@uhura.cc.rochester.edu)
  561. X *          Gavin Stark (gest_ss@uhura.cc.rocehster.edu)
  562. X * Fall, 1990
  563. X */
  564. X
  565. X#include <signal.h>
  566. X#include <sys/wait.h>
  567. X#include <sys/time.h>
  568. X#include <sys/resource.h>
  569. X#include "socket.h"            /* Socket defs */
  570. X#include "socketnum.h"            /* Socket number */
  571. X
  572. Xvoid deal_with_connection();
  573. Xvoid dummy();
  574. Xvoid restart();
  575. X
  576. Xvoid main()
  577. X{
  578. X    int s;        /* Socket that we are working with */
  579. X    FILE        *logfp;
  580. X
  581. X    /*
  582. X     * Set things up to handle SIG_CHLDs so that they can die normally.
  583. X     * Then disconnect the daemon from the shell.  We fork and only let
  584. X     * the child live so the shell thinks the process is finished.
  585. X     */
  586. X    signal(SIGCHLD, dummy);
  587. X    close(0); close(1); close(2);
  588. X    if(fork())
  589. X        exit(0);
  590. X    setpgrp(0, 0);
  591. X    
  592. X    s=sockit();    /* Go set the socket stuff */
  593. X
  594. X    listen(s, 5);    /* listen for as many as 5 connections at once */
  595. X    for (;;) {
  596. X        struct sockaddr_in    his_addr;
  597. X        int            his_len = sizeof (his_addr);
  598. X        int            ns;
  599. X
  600. X        /*
  601. X         * wait for connection to be established.
  602. X         * If accept returns something less than zero there was an
  603. X         * error.  For now we'll ignore it since errors will occur
  604. X         * when a child dies.
  605. X         */
  606. X        if ((ns = accept(s, &his_addr, &his_len)) > 0) {
  607. X            if(fork() == 0) {
  608. X                close(s);
  609. X                deal_with_connection(ns);  /* Go and deal with a connection */
  610. X                exit();
  611. X            }
  612. X        }
  613. X        close(ns);
  614. X    }
  615. X}
  616. X
  617. X/*
  618. X * Talk to calling program and get some information, like who it is that's
  619. X * calling and the actual message.  In other words, the bulk of the
  620. X * program.  It should probably return some error code if it fails for some
  621. X * unexpected reason.
  622. X */
  623. Xvoid deal_with_connection(ns)
  624. Xint ns;
  625. X{
  626. X    FILE *fp;                /* Input/Output file */
  627. X    char whocalled[200],to[200],tty[200];   /* Info variables */
  628. X    char            s[BUFSIZ];    /* string to get message */
  629. X    char            message[BUFSIZ];
  630. X
  631. X    struct utmp        *u;        /* utmp entry */
  632. X    extern struct utmp    *getutmpline(), /* get utmp programs */
  633. X                *getutmpname(); 
  634. X
  635. X    FILE            *ttyfp;        /* tty file */
  636. X    int            loop;
  637. X
  638. X    fp=fdopen(ns,"w+");    /* Open file to socket */
  639. X    rewind(fp);
  640. X
  641. X    fscanf(fp,"%s %s %s",whocalled,to,tty);     /* Get info from the remote program */
  642. X
  643. X    rewind(fp);            /* Rewind the file for writing */
  644. X
  645. X    if(strcmp(tty,"NONE")==0)     /* NONE is sent because I couldn't */
  646. X        tty[0]=0;        /* figure out how to send the NULL */
  647. X                    /* pointer it is expecting */
  648. X
  649. X    if (tty[0] != 0) 
  650. X        u = getutmpline(tty);    
  651. X    else 
  652. X        u = getutmpname(to);    /* GET UTMP NAME */
  653. X    
  654. X
  655. X    /*
  656. X     * Check to see if person is logged in.  It's kind of hard to send
  657. X     * a message to someone that isn't there.  It should be able to
  658. X     * check for a user on a particular tty also.  That still needs to
  659. X     * be implemented.
  660. X     */
  661. X    if (u == (struct utmp *) NULL || strncmp(u->ut_name, to, 8) != 0) {
  662. X        if (tty[0] != 0) {
  663. X            fprintf(fp,"ERROR\n");
  664. X            fprintf(fp, "TTY_ERROR: %s is not logged on to %s\n",
  665. X                to, tty);
  666. X        }
  667. X        else  {
  668. X            fprintf(fp, "ERROR\n");
  669. X            fprintf(fp, "%s is not logged on to %s\n", to,get_local_hostname());
  670. X        }
  671. X        fclose(fp);
  672. X        return;
  673. X    }
  674. X
  675. X    /*
  676. X     * Set up a string containing the full pathname to the line.
  677. X     */
  678. X    sprintf(tty, "/dev/%.8s", u->ut_line);
  679. X
  680. X    /*
  681. X     * Check to see if the person is refusing messages.  I hate it when
  682. X     * people do that, but I know some people REALLY don't want to be
  683. X     * bugged, so....
  684. X     */
  685. X    if ((ttyfp = fopen(tty,"w")) == (FILE *)NULL ) {
  686. X        fprintf(fp,"ERROR\n");
  687. X        fprintf(fp, "%.8s is not receiving messages on %.8s\n",
  688. X            u->ut_name, u->ut_line);
  689. X        fclose(fp);
  690. X        return;
  691. X    }
  692. X    fprintf(fp,"NOERROR\n");    /* Send that no errors were found */
  693. X
  694. X    rewind(fp);             /* rewind for reading */
  695. X
  696. X    /*
  697. X     *  Clear message buffer.  Read message from socket, and send to tty.
  698. X     */
  699. X
  700. X    for(loop=0;loop<BUFSIZ;loop++) message[loop]=0;    /* Clear message */
  701. X
  702. X    fread(message,BUFSIZ,1,fp);        /* Read message */
  703. X
  704. X    fprintf(ttyfp,message);            /* print message */
  705. X
  706. X        fclose(ttyfp);            /* Close the tty */
  707. X
  708. X/*    rewind(fp);            /* Rewind just in case */
  709. X    fclose(fp);
  710. X    return;                /* Do I need to document this */
  711. X}
  712. X
  713. Xvoid dummy() {
  714. X    wait(0);
  715. X}
  716. END_OF_FILE
  717. if test 4283 -ne `wc -c <'msgd.c'`; then
  718.     echo shar: \"'msgd.c'\" unpacked with wrong size!
  719. fi
  720. # end of 'msgd.c'
  721. fi
  722. if test -f 'nmsg.c' -a "${1}" != "-c" ; then 
  723.   echo shar: Will not clobber existing file \"'nmsg.c'\"
  724. else
  725. echo shar: Extracting \"'nmsg.c'\" \(3504 characters\)
  726. sed "s/^X//" >'nmsg.c' <<'END_OF_FILE'
  727. X/*
  728. X * nmsg: Client for the network version of msg.  Allows users to send
  729. X * messages to other users screens across the net.  The client parses the
  730. X * command line and gets the message to send.  The message is passed on to
  731. X * the daemon to deliver.
  732. X */
  733. X
  734. X/*
  735. X * Written by Larry Moss (lm03_cif@uhura.cc.rochester.edu)
  736. X *          Gavin Stark (gest_ss@uhura.cc.rocehster.edu)
  737. X * Fall, 1990
  738. X */
  739. X
  740. X#include <stdio.h>
  741. X#include <string.h>
  742. X#include "socketnum.h"
  743. X#include "socket.h"
  744. X
  745. X
  746. Xextern char *ttyname();
  747. X
  748. Xvoid    usage();
  749. Xvoid    interrupt();
  750. Xvoid    sendit();
  751. Xvoid    getmessage();
  752. Xchar    *getttyname();
  753. Xchar    *getusername();
  754. Xint    daemon_sockit();
  755. X
  756. Xvoid main(argc,argv)
  757. Xint argc;
  758. Xchar **argv;
  759. X{
  760. X    int trc=argc;
  761. X
  762. X    int    daemon_socket;        /* Socket File number */
  763. X    char    toaddress[255],        /* Host to connect to */
  764. X        tty[50],    /* TTY to address */
  765. X        localhost[255],        /* Our host */
  766. X        errorstate[5],
  767. X        s[BUFSIZ],
  768. X        message[BUFSIZ];
  769. X
  770. X    int    i;
  771. X    FILE    *fp;            /* Socket Read/Write file */
  772. X    char    *name, *host;   /* Strings used to parse username and host */    
  773. X
  774. X    /*
  775. X     * use the local address as the default
  776. X     */
  777. X    strcpy(localhost,get_local_hostname());
  778. X
  779. X    /*
  780. X     * If no arguments were given to the program, just exit.  Otherwise
  781. X     * parse the command line.
  782. X     */
  783. X    if(argc == 1)
  784. X        usage(argv[0]);
  785. X
  786. X
  787. X    /*
  788. X     * Parse TTY info
  789. X     */
  790. X
  791. X    if(argc<3) 
  792. X        strcpy(tty,"NONE");
  793. X    else    
  794. X        strcpy(tty,argv[2]);
  795. X
  796. X
  797. X    if((name = strtok(argv[1], "@")) != (char *)NULL) 
  798. X        host=strtok((char *)NULL,"\0");
  799. X
  800. X    /*
  801. X      * if host was parsed, copy that hostname into toaddress
  802. X     */
  803. X    if(host!=0) strcpy(toaddress,host);
  804. X            else strcpy(toaddress,localhost);
  805. X
  806. X    /*
  807. X     * open connection to remote daemon
  808. X     */
  809. X    daemon_socket=daemon_sockit(toaddress);
  810. X
  811. X
  812. X    fp=fdopen(daemon_socket,"w+");    /* Open socket */
  813. X
  814. X    /*
  815. X     * Send data to daemon
  816. X     */
  817. X    fprintf(fp, "\r%s\n%s\n%s\n", getpwuid(getuid())->pw_name,name,tty); 
  818. X
  819. X    rewind(fp);            /* Rewind */
  820. X
  821. X    fscanf(fp,"%s",errorstate);   /* See if any errors were encountered */
  822. X
  823. X    if(strcmp(errorstate,"ERROR")==0) { /* If there was an error get it */
  824. X        fgets(s,BUFSIZ,fp);        
  825. X        fgets(s,BUFSIZ,fp);
  826. X
  827. X        printf("%s\n",s);
  828. X        fclose(fp);
  829. X        exit(0);
  830. X    }
  831. X    rewind(fp);
  832. X
  833. X    /*
  834. X     * Send the message
  835. X     */
  836. X    getmessage(message, BUFSIZ);    /* Get the message */
  837. X    fputs(message, fp);            /* Put the message */
  838. X    fclose(fp);    /* Close the socket */
  839. X}
  840. X
  841. X
  842. Xvoid usage(progname)
  843. Xchar    *progname;
  844. X{
  845. X    fprintf(stderr, "Usage: %s <user>[@host] [tty]\n", progname);
  846. X    exit(1);
  847. X}
  848. X
  849. X        /*  
  850. X         *  This still belongs to Sirota
  851. X         */
  852. X
  853. X/* 
  854. X * Get the username associated with the current uid.
  855. X */
  856. Xchar *getusername()
  857. X{
  858. X    struct passwd    *p;
  859. X    char        *cp;
  860. X    static char    name[BUFSIZ];
  861. X
  862. X    /*
  863. X     * Get the passwd file entry associated with the current uid
  864. X     */
  865. X    if ((p = getpwuid(getuid())) == (struct passwd *) NULL) {
  866. X        fprintf(stderr, "Who the hell are you, anyway?\n");
  867. X        exit(-1);
  868. X    }
  869. X
  870. X    /*
  871. X     * Pretend that the GECOS field contains only the full name
  872. X     */
  873. X    if ((cp = index(p->pw_gecos, ',')) != (char *) NULL)
  874. X        *cp = (char) NULL;
  875. X
  876. X    /*
  877. X     * Create and return a string containing the full name and username
  878. X     */
  879. X    sprintf(name, "%s <%s@%s>", p->pw_gecos, p->pw_name, get_local_hostname());
  880. X    return name;
  881. X}
  882. X
  883. X/*
  884. X * Get the name of the tty associated with stdout (2).  If unknown, say so.
  885. X */
  886. Xchar *getttyname()
  887. X{
  888. X    char        *tty, *cp;
  889. X
  890. X    /*
  891. X     * Get the ttyname
  892. X     */
  893. X    tty = ttyname(2);
  894. X
  895. X    /*
  896. X     * If it's unknown, say so.
  897. X     */
  898. X    if (tty == (char *) NULL)
  899. X        return "[tty unknown]";
  900. X
  901. X    /*
  902. X     * Strip off the pathname
  903. X     */
  904. X    if ((cp = rindex(tty, '/')) != (char *) NULL)
  905. X        tty = cp + 1;
  906. X
  907. X    /*
  908. X     * Return it
  909. X     */
  910. X    return tty;
  911. X}
  912. END_OF_FILE
  913. if test 3504 -ne `wc -c <'nmsg.c'`; then
  914.     echo shar: \"'nmsg.c'\" unpacked with wrong size!
  915. fi
  916. # end of 'nmsg.c'
  917. fi
  918. if test -f 'socklib.c' -a "${1}" != "-c" ; then 
  919.   echo shar: Will not clobber existing file \"'socklib.c'\"
  920. else
  921. echo shar: Extracting \"'socklib.c'\" \(3211 characters\)
  922. sed "s/^X//" >'socklib.c' <<'END_OF_FILE'
  923. X#include "socket.h"
  924. X#include "socketnum.h"
  925. X
  926. X
  927. X
  928. Xchar *
  929. Xget_local_hostname()
  930. X{
  931. X    static char    local_host_name[128];
  932. X    static int    host_name_is_set = NO;
  933. X
  934. X    if (host_name_is_set == NO) {
  935. X        if (gethostname(local_host_name, sizeof (local_host_name)) == -1) {
  936. X            perror("gethostname:");
  937. X            strcpy(local_host_name, "localhost");
  938. X        }
  939. X        host_name_is_set = YES;
  940. X    }
  941. X
  942. X    return local_host_name;
  943. X}
  944. X
  945. X/* Hostname to address takes a pointer to a internet socket address
  946. X   (struct sockaddr_in) and a hostname, and puts the internet address
  947. X   of that host in the sockaddr.  This particular routine also takes
  948. X   an internet host number (e.g., 128.20.45.56??) and converts that
  949. X   to an address (an address is really just a 32 bit number). */
  950. X
  951. Xhostname_to_address(sin, host_name)
  952. Xstruct sockaddr_in    *sin;
  953. Xchar    *host_name;
  954. X{
  955. X    struct hostent    *hp;
  956. X
  957. X    bzero(sin, sizeof (*sin));
  958. X    if (isdigit(host_name[0])) {
  959. X        unsigned long    addr;
  960. X
  961. X        addr = inet_addr(host_name);
  962. X        if ((int) addr != -1) {
  963. X            bcopy((char *) &addr, (char *) &sin->sin_addr, sizeof (addr));
  964. X            sin->sin_family = htons(AF_INET);
  965. X            return YES;
  966. X        }
  967. X    }
  968. X    if ((hp = gethostbyname(host_name)) == NULL)
  969. X        return NO;
  970. X    bcopy(hp->h_addr, (char *) &sin->sin_addr, hp->h_length);
  971. X    sin->sin_family = hp->h_addrtype;
  972. X
  973. X    return YES;
  974. X}
  975. X
  976. X/* This takes a socket, and address, and the length of the address, which
  977. X   is just the sizeof (struct sockaddr_in), and binds the socket to that
  978. X   address and SOME free port.  It then does a getsockname().  Basically,
  979. X   it sets the port to 0, does a bind system call, which chooses a random
  980. X   port us.  The system chooses the random port BUT it doesn't store that
  981. X   random port back into the ADDR structure.  So, since I might want to
  982. X   know what port got assigned, I do a getsockname() system call, which
  983. X   given a socket, puts the address (which contains the port) in the
  984. X   address structure.  Sorry if that made no sense. */
  985. X
  986. Xbind_and_name(s, addr, len)
  987. Xstruct sockaddr_in    *addr;
  988. X{
  989. X    addr->sin_port = 0;
  990. X    if (bind(s, addr, len) == -1)
  991. X        return -1;
  992. X    if (getsockname(s, addr, &len) == -1)
  993. X        return -1;
  994. X}
  995. X
  996. X
  997. Xset_port(addr, port)
  998. Xstruct sockaddr_in    *addr;
  999. X{
  1000. X    addr->sin_port = htons((short) port);
  1001. X}
  1002. X
  1003. Xsockit()
  1004. X{
  1005. X    int s;
  1006. X    struct sockaddr_in    my_addr;
  1007. X    int len=sizeof (my_addr);
  1008. X
  1009. X    s = socket(AF_INET, SOCK_STREAM, 0);
  1010. X    if (hostname_to_address(&my_addr, get_local_hostname()) < 0) {
  1011. X        perror("reply: hostname_to_address");
  1012. X        exit(1);
  1013. X    }
  1014. X    set_port(&my_addr, SERVER_PORT);
  1015. X    if (bind(s, &my_addr, len) < 0)
  1016. X        perror("bind:");        /* something's wrong */
  1017. X    return s;
  1018. X}
  1019. X
  1020. X
  1021. X/*
  1022. X * open connection to remote daemon
  1023. X */
  1024. Xdaemon_sockit(toaddress)
  1025. Xchar toaddress[255];
  1026. X{
  1027. X    int daemon_socket;
  1028. X
  1029. X    struct sockaddr_in    my_addr,daemon_addr;
  1030. X
  1031. X    if (hostname_to_address(&my_addr, get_local_hostname()) < 0) {
  1032. X        perror("reply: hostname_to_address");
  1033. X        exit(1);
  1034. X    }
  1035. X
  1036. X    if (hostname_to_address(&daemon_addr,toaddress) < 0) {
  1037. X        perror("reply: hostname_to_address"); 
  1038. X        exit(1);
  1039. X    }
  1040. X
  1041. X    daemon_socket = socket(AF_INET, SOCK_STREAM, 0);
  1042. X    bind_and_name(daemon_socket, &my_addr, sizeof (my_addr));
  1043. X    set_port(&daemon_addr, SERVER_PORT);
  1044. X
  1045. X    if (connect(daemon_socket, &daemon_addr, sizeof (daemon_addr)) < 0) {
  1046. X        perror("Could not connect with remote daemon"); 
  1047. X        exit();
  1048. X    }
  1049. X    return daemon_socket;
  1050. X}
  1051. END_OF_FILE
  1052. if test 3211 -ne `wc -c <'socklib.c'`; then
  1053.     echo shar: \"'socklib.c'\" unpacked with wrong size!
  1054. fi
  1055. # end of 'socklib.c'
  1056. fi
  1057. if test -f 'utmp.c' -a "${1}" != "-c" ; then 
  1058.   echo shar: Will not clobber existing file \"'utmp.c'\"
  1059. else
  1060. echo shar: Extracting \"'utmp.c'\" \(1383 characters\)
  1061. sed "s/^X//" >'utmp.c' <<'END_OF_FILE'
  1062. X/*
  1063. X * This program is Copyright (c) 1988, 1989 by Mark Sirota.
  1064. X * It is provided to you without charge, and with no warranty.
  1065. X * You may give away copies of libutmp, including sources, provided that this
  1066. X * notice is included in all the files.
  1067. X */
  1068. X
  1069. X#include <utmp.h>
  1070. X#include <sys/file.h>
  1071. X#include <stdio.h>
  1072. X
  1073. Xstatic int    utmpfd = -1;
  1074. X
  1075. X/*
  1076. X * Get the next entry in /etc/utmp
  1077. X */
  1078. Xstruct utmp *
  1079. Xgetutmpent()
  1080. X{
  1081. X    static struct utmp    u;
  1082. X
  1083. X    if (utmpfd == -1)
  1084. X        if ((utmpfd = open("/etc/utmp", O_RDONLY)) == -1)
  1085. X            return (struct utmp *) NULL;
  1086. X
  1087. X    if (read(utmpfd, &u, sizeof (struct utmp)) != sizeof (struct utmp))
  1088. X        return (struct utmp *) NULL;
  1089. X
  1090. X    return &u;
  1091. X}
  1092. X
  1093. X/*
  1094. X * Get a utmp entry according to ut_line.
  1095. X */
  1096. Xstruct utmp *
  1097. Xgetutmpline(line)
  1098. Xregister char    *line;
  1099. X{
  1100. X    register struct utmp    *u;
  1101. X
  1102. X    setutmpent();
  1103. X    while ((u = getutmpent()) != (struct utmp *) NULL) {
  1104. X        printf("testline in utmp.c   %s\n",u->ut_line);
  1105. X        if (strncmp(u->ut_line, line, 8) == 0)
  1106. X            break;
  1107. X    }
  1108. X    return u;
  1109. X}
  1110. X
  1111. X/*
  1112. X * Get a utmp entry according to ut_name.
  1113. X */
  1114. Xstruct utmp *
  1115. Xgetutmpname(name)
  1116. Xregister char    *name;
  1117. X{
  1118. X    register struct utmp    *u;
  1119. X
  1120. X    setutmpent();
  1121. X    while ((u = getutmpent()) != (struct utmp *) NULL)
  1122. X        if (strncmp(u->ut_name, name, 8) == 0)
  1123. X            break;
  1124. X    return u;
  1125. X}
  1126. X
  1127. X/*
  1128. X * Rewind /etc/utmp
  1129. X */
  1130. Xint
  1131. Xsetutmpent()
  1132. X{
  1133. X    lseek(utmpfd, 0L, L_SET);
  1134. X}
  1135. X
  1136. X/*
  1137. X * Close /etc/utmp
  1138. X */
  1139. Xint
  1140. Xendutmpent()
  1141. X{
  1142. X    close(utmpfd);
  1143. X    utmpfd = -1;
  1144. X}
  1145. END_OF_FILE
  1146. if test 1383 -ne `wc -c <'utmp.c'`; then
  1147.     echo shar: \"'utmp.c'\" unpacked with wrong size!
  1148. fi
  1149. # end of 'utmp.c'
  1150. fi
  1151. if test -f 'input.h' -a "${1}" != "-c" ; then 
  1152.   echo shar: Will not clobber existing file \"'input.h'\"
  1153. else
  1154. echo shar: Extracting \"'input.h'\" \(709 characters\)
  1155. sed "s/^X//" >'input.h' <<'END_OF_FILE'
  1156. X/*
  1157. X * header file for:
  1158. X * input.c: Larry Moss (lm03_cif@cc.rochester.edu)
  1159. X *        Fall, 1990
  1160. X *
  1161. X * This was written as part of nmsg, a version of write that can be used
  1162. X * over the net, by Larry Moss and Gavin Stark.  Feel free to do whatever 
  1163. X * you want with this code as long as my name stays on it and I receive
  1164. X * credit for what I've done.
  1165. X */
  1166. X
  1167. X#define    LINELENGTH    78
  1168. X#define BACKSPACE    fputs("\b \b", stdout)
  1169. X#define DEL        127
  1170. X#define WERASE        23
  1171. X#define KILL        21
  1172. X#define TAB        9
  1173. X#define CTL(c)        (c & 037)
  1174. X#define MAXLENGTH    1024
  1175. X
  1176. Xvoid get_input();
  1177. Xvoid setterm();
  1178. Xvoid unsetterm();
  1179. Xint handle_tilde();
  1180. Xint interrupt();
  1181. Xint pause();
  1182. Xint cont();
  1183. Xint child();
  1184. Xint readmessage();
  1185. Xchar *getenv();
  1186. Xchar *expand();
  1187. END_OF_FILE
  1188. if test 709 -ne `wc -c <'input.h'`; then
  1189.     echo shar: \"'input.h'\" unpacked with wrong size!
  1190. fi
  1191. # end of 'input.h'
  1192. fi
  1193. if test -f 'socket.h' -a "${1}" != "-c" ; then 
  1194.   echo shar: Will not clobber existing file \"'socket.h'\"
  1195. else
  1196. echo shar: Extracting \"'socket.h'\" \(253 characters\)
  1197. sed "s/^X//" >'socket.h' <<'END_OF_FILE'
  1198. X#define NO 0
  1199. X#define YES 1
  1200. X#include <ctype.h>
  1201. X#include <fcntl.h>
  1202. X#include <netdb.h>
  1203. X#include <pwd.h>
  1204. X#include <stdio.h>
  1205. X#include <strings.h>
  1206. X#include <sys/param.h>
  1207. X#include <sys/socket.h>
  1208. X#include <sys/types.h>
  1209. X#include <utmp.h>
  1210. X#include <netinet/in.h>
  1211. END_OF_FILE
  1212. if test 253 -ne `wc -c <'socket.h'`; then
  1213.     echo shar: \"'socket.h'\" unpacked with wrong size!
  1214. fi
  1215. # end of 'socket.h'
  1216. fi
  1217. if test -f 'socketnum.h' -a "${1}" != "-c" ; then 
  1218.   echo shar: Will not clobber existing file \"'socketnum.h'\"
  1219. else
  1220. echo shar: Extracting \"'socketnum.h'\" \(25 characters\)
  1221. sed "s/^X//" >'socketnum.h' <<'END_OF_FILE'
  1222. X#define SERVER_PORT 2834
  1223. END_OF_FILE
  1224. if test 25 -ne `wc -c <'socketnum.h'`; then
  1225.     echo shar: \"'socketnum.h'\" unpacked with wrong size!
  1226. fi
  1227. # end of 'socketnum.h'
  1228. fi
  1229. if test -f 'msgd.man' -a "${1}" != "-c" ; then 
  1230.   echo shar: Will not clobber existing file \"'msgd.man'\"
  1231. else
  1232. echo shar: Extracting \"'msgd.man'\" \(465 characters\)
  1233. sed "s/^X//" >'msgd.man' <<'END_OF_FILE'
  1234. X.TH MSGD 8 "23 JAN 1991"
  1235. X.SH NAME
  1236. Xmsgd \- Delivers messages sent with nmsg(1).
  1237. X.SH SYNOPSIS
  1238. X\fBmsgd\fP
  1239. X.SH DESCRIPTION
  1240. X\fBmsgd\fP is the daemon for nmsg(1).  It receives messages sent over the
  1241. Xinternet and delivers them to the appropriate user.  It will
  1242. Xautomagically disconnect itself from the shell and run in the background.
  1243. X.RE
  1244. X.SH FILES
  1245. X/etc/utmp
  1246. X.SH "SEE ALSO"
  1247. Xnmsg(1)
  1248. X.SH AUTHORS
  1249. XGavin Stark gest_ss@cc.rochester.edu
  1250. X.br
  1251. XLarry Moss lm03_cif@cc.rochester.edu
  1252. END_OF_FILE
  1253. if test 465 -ne `wc -c <'msgd.man'`; then
  1254.     echo shar: \"'msgd.man'\" unpacked with wrong size!
  1255. fi
  1256. # end of 'msgd.man'
  1257. fi
  1258. if test -f 'nmsg.man' -a "${1}" != "-c" ; then 
  1259.   echo shar: Will not clobber existing file \"'nmsg.man'\"
  1260. else
  1261. echo shar: Extracting \"'nmsg.man'\" \(1870 characters\)
  1262. sed "s/^X//" >'nmsg.man' <<'END_OF_FILE'
  1263. X.TH NMSG 1 "23 JAN 1991"
  1264. X.SH NAME
  1265. Xnmsg \- Send a message to a user
  1266. X.SH SYNOPSIS
  1267. X\fBnmsg\fP <\fIuser\fP>[\fI@host\fP] [\fItty\fP]
  1268. X.SH DESCRIPTION
  1269. X\fBnmsg\fP sends a message to the specified \fIuser\fP.  The message is
  1270. Xread from the standard input until a CTL-D or a single '.' on one line is
  1271. Xencountered.  In normal usage the program works interactively to provide
  1272. Xword wrap and to allow tilde commands to be used.  If the input is coming
  1273. Xfrom a pipe it will be read in straight without word wrapping, and tildes
  1274. Xwill be ignored.  In all cases a copy of the message is saved in
  1275. X$HOME/.oldmsg.
  1276. X.PP
  1277. XThe optional \fBhost\fP argument allows a message to be sent to someone on
  1278. Xa remote machine assuming \fBhost\fP has msgd(8) running on the same port.
  1279. XThe \fItty\fP argument specifies which tty to write to, in the case that
  1280. Xa user is logged in more than once.  If \fItty\fP is not supplied, the
  1281. Xterminal chosen is arbitrary.
  1282. X.PP
  1283. X.RS
  1284. X.B Tilde commands:
  1285. X.IP
  1286. X~p    Print contents of current message.
  1287. X.IP
  1288. X~r\fIfile\fP    include \fIfile\fP in message.  If no argument is given
  1289. X\fBnmsg\fP attempts to use the file $HOME/.oldmsg as input.  Tilde
  1290. Xexpansion of file names does work however there are no wildcards.
  1291. X.IP
  1292. X~v    This will place you in an editor.  If you have the variable
  1293. XEDITOR set in your environment it will use that.  Otherwise it will
  1294. Xdefault to /usr/ucb/vi.  This is definitely the silliest feature of the
  1295. Xprogram.
  1296. X.RE
  1297. X.SH FILES
  1298. X/etc/utmp
  1299. X.SH BUGS
  1300. XWhen running interactively the program assumes you are using an 80 column
  1301. Xterminal window.
  1302. X.LP
  1303. XOften entering the editor twice in one session causes problems.  Also you
  1304. Xcan't pause out of the editor.
  1305. X.LP
  1306. XThe program isn't very smart about picking the tty to write to.
  1307. X.SH "SEE ALSO"
  1308. Xmail(1), mesg(1), talk(1), who(1), write(1), msgd(8)
  1309. X.SH AUTHORS
  1310. XLarry Moss lm03_cif@cc.rochester.edu
  1311. X.br
  1312. XGavin Stark gest_ss@cc.rochester.edu
  1313. END_OF_FILE
  1314. if test 1870 -ne `wc -c <'nmsg.man'`; then
  1315.     echo shar: \"'nmsg.man'\" unpacked with wrong size!
  1316. fi
  1317. # end of 'nmsg.man'
  1318. fi
  1319. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  1320.   echo shar: Will not clobber existing file \"'Makefile'\"
  1321. else
  1322. echo shar: Extracting \"'Makefile'\" \(1368 characters\)
  1323. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  1324. X#
  1325. X# Makefile for msg - a program to splash text on someone's screen
  1326. X# over the network.
  1327. X#
  1328. X
  1329. X#
  1330. X# This is the only section that should need to be changed.
  1331. X# for some reason, gcc won't compile this correctly on a sun3.  There's a
  1332. X# problem with bcopy() that needs to be looked into.
  1333. X#
  1334. XDESTDIR = /u/cif/lm03_cif
  1335. XBINDIR = $(DESTDIR)/bin
  1336. XETCDIR = $(DESTDIR)/etc
  1337. XMANDIR = $(DESTDIR)/man
  1338. X#CC = gcc
  1339. XCC = cc
  1340. X
  1341. X#
  1342. X# Comment out the next line if you don't want to use the nameserver.
  1343. X#
  1344. XLDFLAGS = -lresolv
  1345. X
  1346. X#
  1347. X# the NORESOLV definition doesn't do anything now.  Some #include lines may
  1348. X# need to be commented out in socket.h.  Nothing else should need to be 
  1349. X# changed.
  1350. X#
  1351. X#CFLAGS = -O -D"NORESOLV"
  1352. X#CFLAGS = -g
  1353. XCFLAGS = -O
  1354. XDOBJS = msgd.o socklib.o utmp.o
  1355. XMOBJS = nmsg.o socklib.o input.o
  1356. X
  1357. X#
  1358. X# .c.o is being changed so gcc won't complain about the options sun's make
  1359. X# supplies to $(CC)
  1360. X#
  1361. X.c.o:
  1362. X    $(CC) $(CFLAGS) -c $<
  1363. X
  1364. Xall: nmsg msgd
  1365. X
  1366. Xnmsg: $(MOBJS)
  1367. X    $(CC) -o nmsg $(MOBJS) $(LDLIBS) $(LDFLAGS)
  1368. X
  1369. Xmsgd: $(DOBJS)
  1370. X    $(CC) -o msgd $(DOBJS) $(LDLIBS) $(LDFLAGS)
  1371. X
  1372. Xinstall: nmsg msgd
  1373. X    install -s nmsg $(BINDIR)
  1374. X    install -s msgd $(ETCDIR)
  1375. X    install -c -m 0644 nmsg.man $(MANDIR)/man1/nmsg.1
  1376. X    install -c -m 0644 msgd.man $(MANDIR)/man8/msgd.8
  1377. X
  1378. Xtar:
  1379. X    tar -cvf nmsg.tar README *.c *.h *.man Makefile TODO
  1380. X
  1381. Xshar:
  1382. X    shar -onmsg.shar README *.c *.h *.man Makefile TODO
  1383. X
  1384. Xclean:
  1385. X    rm -f *.o msgd nmsg core
  1386. END_OF_FILE
  1387. if test 1368 -ne `wc -c <'Makefile'`; then
  1388.     echo shar: \"'Makefile'\" unpacked with wrong size!
  1389. fi
  1390. # end of 'Makefile'
  1391. fi
  1392. if test -f 'TODO' -a "${1}" != "-c" ; then 
  1393.   echo shar: Will not clobber existing file \"'TODO'\"
  1394. else
  1395. echo shar: Extracting \"'TODO'\" \(1100 characters\)
  1396. sed "s/^X//" >'TODO' <<'END_OF_FILE'
  1397. XIf no tty is specified it should be smarter.  It would be nice if it could
  1398. Xselect the 'best' tty rather than grabbing a random one.
  1399. X
  1400. XIt won't let the editor pause. (low priority item)
  1401. X
  1402. Xsometimes chokes when you edit something a second time.
  1403. X
  1404. Xwill try to deliver message even if user logs out.
  1405. X
  1406. XIt should be able to handle multiple users.  Probably notify after who the
  1407. Xmessage was delivered to rather than try to find out which people are
  1408. Xlogged in ahead of time.  Input format would be changed to user@host:tty
  1409. X
  1410. XMark's suggestion:
  1411. X> Of course, a neat extra-credit technique would be to batch messages to the
  1412. X> same host, so that if I send to "lm03_cif@troi.cc.rochester.edu
  1413. X> jdic@troi.cc.rochester.edu", it would only contact troi's msgd once instead of
  1414. X> twice.  But that's extra credit. :-)
  1415. X
  1416. XAnother idea would be to keep a record of users that received messages in
  1417. Xthe last hour or so so you can check to see who sent you a message if you
  1418. Xjust cleared your screen.  Something like 'nmsg -w'.
  1419. X
  1420. XIf a record is kept of who sent the last message, then 'nmsg -r' could
  1421. Xjust reply to the last person.
  1422. END_OF_FILE
  1423. if test 1100 -ne `wc -c <'TODO'`; then
  1424.     echo shar: \"'TODO'\" unpacked with wrong size!
  1425. fi
  1426. # end of 'TODO'
  1427. fi
  1428. echo shar: End of shell archive.
  1429. exit 0
  1430. --
  1431. lm03_cif@uhura.cc.rochester.edu / "I'm so tired... I was up all night
  1432. lmo3_ss@db1.cc.rochester.edu   / trying to round off infinity."
  1433. lmo3_ss@uordbv.bitnet         / - Stephen Wright
  1434.