home *** CD-ROM | disk | FTP | other *** search
- From: lm03_cif@troi.cc.rochester.edu (Larry Moss)
- Newsgroups: alt.sources
- Subject: nmsg - a 'write' style program to send messages across the net
- Message-ID: <12639@ur-cc.UUCP>
- Date: 6 Mar 91 20:24:58 GMT
-
- Nmsg was written to send messages to users across the net when a 'talk'
- isn't desired or simply doesn't work. Periodically there are requests
- for sample code using sockets. If nothing else this is an example of
- that. It may be preferred to /bin/write even on the local host since it
- also does things like word wrap.
-
- The program works farily well -- usually. It can basically be expected
- to work on a sun4 running sunOS 4.0.3. It should work on other machines
- and other versions of the OS (not sure about other flavors of UNIX) but
- for some reason it doesn't. Before I explain the problems I'd just like
- to apologize for posting a program that doesn't have all the bugs worked
- out. I wasn't really sure if it was appropriate to post something like
- this, but several people that I asked thought it was a reasonable idea.
- I just hope someone reading this can help us out. I'm posting this now
- for two reasons. 1) Gavin and I no longer have any idea what to try to
- fix it and would like suggestions. 2) We have now been asked by system
- administrators here to not run a daemon on these machines until the bugs
- are out. It's a perfectly reasonable request but one of our problems is
- that it doesn't compile on the one machine we do have permission to run it
- on (a sun3 running 4.1) so again any suggestions would be appreciated.
-
- Problems:
- Sun4 OS4.0.3 - when the client is paused (^Z) the daemon stops also.
- I have no idea why this is happening but this only a problem if the
- client is then killed before it receives (and sends on to the daemon) a
- SIGCONT. If this happens the daemon just hangs uselessly.
-
- Sun4 OS4.1 - If the client is stopped (^Z), continuing it (fg) does not
- send a SIGCONT to the client so it never goes back into cbreak and noecho
- modes.
-
- Sun3 OS4.1 - Doesn't compile - but we haven't spent much time on that.
-
- So we're really confused about why it behaves so differently on the
- differnet machines.
-
- Thanks for help, suggestions, etc...
- Larry
- --
- lm03_cif@uhura.cc.rochester.edu / "I'm so tired... I was up all night
- lmo3_ss@db1.cc.rochester.edu / trying to round off infinity."
- lmo3_ss@uordbv.bitnet / - Stephen Wright
- --
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: README input.c msgd.c nmsg.c socklib.c utmp.c input.h
- # socket.h socketnum.h msgd.man nmsg.man Makefile TODO
- # Wrapped by lm03_cif@troi.cc.rochester.edu on Wed Mar 6 15:03:06 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(2078 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XWHAT IS NMSG?
- XIt's basically a program to replace /bin/write that will send messages
- Xover the net and do other really nifty things. Well, kinda nifty anyway.
- XIf nothing else it is an example of network communication and stuff.
- XThere seem to be requests fairly often for samples like that for people
- Xto look at.
- X
- XBRIEF HISTORY (read: disclaimer)
- XThis program was originally bits of little things that were kind of
- Xthrown together. Most of the stuff in it (handling sockets, handling
- Xinput in cbreak mode, etc) was written because neither of us had ever
- Xdone it before and thought it might be interesting. Putting stuff in a
- Xuseful program was more or less an afterthought. In fact the socket
- Xstuff was actually sitting around for over a year because after writing
- Xit I didn't know what to do with it. It does do exactly what it was
- Xmeant to most of the time. We both learned a lot from it, but ran into
- Xsome problems that we can't solve. Since this was originally several
- Xdiffernet hacked together pieces that two people were working on it may
- Xnot seem as clear to someone reading it as we think. We have tried to
- Xleave the code clean and easy to read and tried to do things efficiently
- X(except where pure laziness took over).
- X
- XINSTALLATION
- XShould be as simple as editing the Makefile. Everything that should need
- Xto be changed is commented. If you wish to change the port that the
- Xserver runs on, edit socketnum.h. This is the only way we have right now
- Xof restricting who can send messages to particular machines.
- X
- XTHANKS TO
- XMark Sirota who we borrowed some code from. utmp.c was taken from him.
- XThat's one of the examples of pure laziness.
- X
- XCOPYING
- XDo whatever you wish with the code as long as we get credit for what
- Xwe've done. If you find this useful in any way or wish to do something
- Xwith parts of the code that it wasn't originally intended for, let us
- Xknow. We're really just wondering if we've managed to do something
- Xuseful with our time. (Consider it an ego thing.)
- X
- X- Larry
- X
- XLarry Moss lm03_cif@cc.rochester.edu
- XGavin Stark gest_ss@cc.rochester.edu
- END_OF_FILE
- if test 2078 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'input.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'input.c'\"
- else
- echo shar: Extracting \"'input.c'\" \(9749 characters\)
- sed "s/^X//" >'input.c' <<'END_OF_FILE'
- X/*
- X * input.c: Larry Moss (lm03_cif@cc.rochester.edu)
- X * Fall, 1990
- X *
- X * This was written as part of nmsg, a version of write that can be used
- X * over the net, by Larry Moss and Gavin Stark. Feel free to do whatever
- X * you want with this code as long as my name stays on it and I receive
- X * credit for what I've done.
- X */
- X
- X/*
- X * Here are the i/o routines to be used with nmsg. This code deals with
- X * ioctl to set the terminal the way we want it (cbreak mode, no echo). Some
- X * of this may not be done in the cleanest ways, but it is functional. All
- X * normal UNIX line editting stuff (C-U, C-W, etc.) are included. I think it
- X * handles tabs correctly also. I've included a bunch of things just to learn
- X * how to do it so if anyone reading this has suggestions for doing things
- X * better, I'm listening.
- X */
- X
- X#include <stdio.h>
- X#include <string.h>
- X#include <signal.h>
- X#include <sgtty.h>
- X#include <ctype.h>
- X#include <pwd.h>
- X#include <time.h>
- X#include <vfork.h>
- X#include <sys/types.h>
- X#include <sys/wait.h>
- X
- X#include "input.h"
- X
- Xvoid getmessage(message, maxlength)
- Xchar *message;
- Xint maxlength;
- X{
- X FILE *fp;
- X char savename[1000];
- X int messagelength;
- X time_t cur_time;
- X struct tm *t;
- X char tempbuf[BUFSIZ];
- X
- X /*
- X * Set up the header for the message. Get the time.
- X */
- X time(&cur_time);
- X t = localtime(&cur_time);
- X
- X get_input(message);
- X
- X sprintf(tempbuf, "\007\r\nFrom %s on %s at %d:%02d\r\n%s\r\n",
- X getusername(), getttyname(), t->tm_hour,
- X t->tm_min,message);
- X
- X /*
- X * Save the message
- X */
- X sprintf(savename, "%s/.oldmsg", getenv("HOME"));
- X
- X if((fp = fopen(savename, "w")) == NULL)
- X fprintf(stderr, "error writing to %s", savename);
- X else
- X fputs(message, fp);
- X
- X fclose(fp);
- X
- X /*
- X * The text needs to be in message for the calling procedure.
- X */
- X strcpy(message,tempbuf);
- X}
- X
- X
- Xvoid get_input(message)
- Xchar *message;
- X{
- X int messagelength, c, i, ctrlc=0, cp, column=0;
- X int linelength;
- X char temp[80];
- X
- X messagelength = strlen(message);
- X
- X /*
- X * If the program is not being run interactively it's real simple
- X * to get the message.
- X */
- X if(!isatty(0)) {
- X messagelength = readmessage(message, messagelength, stdin);
- X return;
- X }
- X
- X /*
- X * If the program is being used interactively we want to set it up
- X * for things like word wrap and make sure it handles signals
- X * correctly.
- X */
- X setterm();
- X
- X puts("Enter your message, and terminate with Ctl-D or '.'.");
- X printf("Messages are limited to %d characters.\n\n", MAXLENGTH);
- X fflush(stdout);
- X
- X while((c = getchar()) != CTL('d')) {
- X switch (c) {
- X case CTL('c'):
- X if(ctrlc)
- X interrupt();
- X else {
- X ctrlc=1;
- X puts("\n** interrupt -- one more to kill message **");
- X }
- X break;
- X case CTL('h'):
- X case DEL:
- X if(messagelength > 0) {
- X BACKSPACE;
- X message[--messagelength] = NULL;
- X column--;
- X }
- X break;
- X case '\n':
- X putchar(c);
- X message[messagelength++] = '\r';
- X message[messagelength++] = '\n';
- X if ((message[messagelength-3] == '.') && (column ==1)) {
- X message[messagelength-3] = NULL;
- X unsetterm();
- X return;
- X }
- X column = 0;
- X break;
- X case KILL:
- X while ((message[messagelength-1] != '\n') &&
- X (messagelength > 0)) {
- X message[--messagelength] = NULL;
- X BACKSPACE;
- X }
- X column = 0;
- X break;
- X case WERASE:
- X while ((!isspace(message[messagelength-1])) &&
- X (messagelength > 0)) {
- X message[--messagelength] = NULL;
- X BACKSPACE;
- X column--;
- X }
- X break;
- X case CTL('r'):
- X putchar('\n');
- X fputs(&message[messagelength - column],stdout);
- X break;
- X case TAB:
- X for(i=0; i <= (column % 8); i++) {
- X putchar(' ');
- X message[messagelength++] = ' ';
- X column++;
- X }
- X break;
- X case '~':
- X if(message[messagelength-1] == '\n' || messagelength ==0) {
- X putchar(c);
- X messagelength = handle_tilde(message,messagelength);
- X break;
- X }
- X default:
- X if(column >= 78) {
- X for(cp=messagelength;!isspace(message[cp]); cp--)
- X BACKSPACE;
- X strcpy(temp, &message[cp+1]);
- X message[cp] = '\r'; message[cp+1]='\n';
- X strcpy(&message[cp+2], temp);
- X messagelength++;
- X fputs(&message[cp],stdout);
- X column = messagelength - cp;
- X }
- X putchar(c);
- X message[messagelength++] = c;
- X column++;
- X break;
- X }
- X }
- X puts("EOF");
- X unsetterm();
- X}
- X
- X/*
- X * Set the terminal to cbreak mode, turn off echo and prevent special
- X * characters from affecting the input. We will handle EOF and other fun
- X * stuff our own way. Backup copies of the current setup will be kept
- X * to insure the terminal gets returned to its initial state.
- X */
- Xvoid setterm() {
- X struct sgttyb termrec;
- X struct tchars trec;
- X
- X signal(SIGINT, interrupt);
- X signal(SIGTSTP, pause);
- X signal(SIGSTOP, pause);
- X signal(SIGCONT, cont);
- X
- X gtty(0, &termrec);
- X termrec.sg_flags |= CBREAK;
- X termrec.sg_flags &= ~ECHO;
- X stty(0, &termrec);
- X
- X ioctl(0, TIOCGETC, &trec);
- X trec.t_quitc = (char) -1;
- X trec.t_eofc = (char) -1;
- X trec.t_intrc = (char) -1;
- X ioctl(0, TIOCSETC, &trec);
- X}
- X
- X/*
- X * Reset terminal settings to the way they were before. well, that's not
- X * really true. Since I didn't save the original settings, I'll set things
- X * to the way they normally are. I suppose I should do this correctly, but
- X * for now, this works.
- X */
- Xvoid unsetterm() {
- X struct sgttyb termrec;
- X struct tchars trec;
- X
- X signal(SIGINT, SIG_IGN);
- X signal(SIGTSTP, SIG_IGN);
- X signal(SIGSTOP, SIG_IGN);
- X signal(SIGCONT, SIG_IGN);
- X
- X gtty(0, &termrec);
- X termrec.sg_flags &= ~CBREAK;
- X termrec.sg_flags |= ECHO;
- X stty(0, &termrec);
- X
- X ioctl(0, TIOCGETC, &trec);
- X trec.t_quitc = CTL('\\');
- X trec.t_eofc = CTL('d');
- X trec.t_intrc = CTL('c');
- X ioctl(0, TIOCSETC, &trec);
- X}
- X
- X/*
- X * Interrupt handlers
- X */
- Xpause() {
- X unsetterm();
- X kill(getpid(), SIGSTOP);
- X}
- X
- Xcont() {
- X setterm();
- X}
- X
- Xinterrupt() {
- X unsetterm();
- X putchar('\n');
- X exit(1);
- X}
- X
- X
- X/*
- X * Handle tilde commands in messages.
- X */
- Xint handle_tilde(message, messagelength)
- Xchar *message;
- Xint messagelength;
- X{
- X char command[120], line[MAXLENGTH], *editor, oldmsg[120];
- X static char tempfile[] = "/tmp/msg.XXXXXX";
- X FILE *fp;
- X int i;
- X
- X unsetterm();
- X fgets(command, 120, stdin);
- X switch(command[0]) {
- X case 'v':
- X /*
- X * An editor will be invoked
- X * First save text to a temp file so the editor can
- X * deal with it.
- X */
- X mktemp(tempfile);
- X if((fp=fopen(tempfile, "w")) == NULL) {
- X fprintf(stderr, "error opening %s", tempfile);
- X return;
- X }
- X messagelength=0;
- X fputs(message, fp);
- X fclose(fp);
- X
- X /*
- X * Figure out which editor will be used.
- X * /usr/ucb/vi will be used unless the editor
- X * environment variable is present.
- X */
- X if((editor=getenv("EDITOR")) == NULL)
- X editor="/usr/ucb/vi";
- X
- X /*
- X * Start the new process and ignore interrupts
- X * until the editing is done so th eprocesses don't
- X * fight for input.
- X */
- X if(vfork() == 0) {
- X execl(editor, editor, tempfile, (char *)NULL);
- X exit(0);
- X }
- X wait(0);
- X
- X /*
- X * Read in the modified message and get rid of the
- X * temp file.
- X */
- X fp=fopen(tempfile, "r");
- X messagelength=readmessage(message, messagelength, fp);
- X fclose(fp);
- X unlink(tempfile);
- X strcpy(tempfile, "/tmp/msg.XXXXXX");
- X puts("\n-- Continue editing message --");
- X break;
- X case 'r':
- X /*
- X * read contents of file into message. If no file
- X * is specified try to read the last message sent.
- X */
- X if(strlen(command) == 2) {
- X sprintf(oldmsg, "%s/.oldmsg", getenv("HOME"));
- X if((fp=fopen(oldmsg, "r")) == NULL)
- X fputs("no old message\n");
- X else
- X messagelength=readmessage(message, messagelength, fp);
- X }
- X /*
- X * read the file specified. Handle tildes if
- X * necessary
- X */
- X else {
- X sprintf(oldmsg, "%s", &command[1]);
- X oldmsg[strlen(oldmsg)-1] = NULL;
- X for(i=0;oldmsg[i]==' ' || oldmsg[i]=='\t'; i++);
- X if(oldmsg[i]=='~')
- X if(strcpy(&oldmsg[i], expand(&oldmsg[i])) == NULL) {
- X fprintf(stderr, "unknown user\n");
- X break;
- X }
- X if((fp=fopen(&oldmsg[i], "r")) == NULL) {
- X fprintf(stderr, "***error opening %s***\n", oldmsg);
- X }
- X else {
- X messagelength=readmessage(message, messagelength, fp);
- X }
- X }
- X fclose(fp);
- X fprintf(stderr, "(Continue.)\n");
- X break;
- X case 'p':
- X /*
- X * print the current message.
- X */
- X puts(message);
- X break;
- X }
- X setterm();
- X return messagelength;
- X}
- X
- X/*
- X * this is the routine used to read a message from a file or stdin when
- X * input is not coming from a tty.
- X */
- Xint readmessage(message, messagelength, fp)
- Xchar *message;
- Xint messagelength;
- XFILE *fp;
- X{
- X char line[MAXLENGTH], answer[80];
- X int linelength;
- X
- X while (fgets(line, MAXLENGTH, fp) != (char *) NULL) {
- X linelength = strlen(line);
- X if (messagelength + linelength + 2 > MAXLENGTH - 1) {
- X linelength = (MAXLENGTH - messagelength - 3);
- X fprintf(stderr, "The last line was truncated to %d characters.\nSend anyway? (y/n) ",
- X linelength);
- X fgets(answer, 80, fp);
- X if (answer[0] != 'y')
- X exit(2);
- X line[linelength]= (char) NULL;
- X }
- X strcpy(message + messagelength, line);
- X messagelength += linelength;
- X }
- X return messagelength;
- X}
- X
- X/*
- X * Expand tildes in filenames. The only way I know of to get the home
- X * directory of another user is to look up passwd information. If we want
- X * the user's home directory we can just get it from the environment.
- X */
- Xchar *expand(filename)
- Xchar *filename;
- X{
- X struct passwd *p;
- X char tempmsg[120];
- X
- X if(filename[1] == '/') {
- X sprintf(tempmsg, "%s%s", getenv("HOME"), &filename[1]);
- X return tempmsg;
- X }
- X
- X /*
- X * Try to get user information. If user information can't be
- X * obtained return NULL
- X */
- X if((p = getpwnam(strtok(&filename[1], "/"))) == (struct passwd *)NULL)
- X return (char *)NULL;
- X sprintf(tempmsg, "%s/%s", p->pw_dir, strtok(NULL, " "));
- X return tempmsg;
- X}
- END_OF_FILE
- if test 9749 -ne `wc -c <'input.c'`; then
- echo shar: \"'input.c'\" unpacked with wrong size!
- fi
- # end of 'input.c'
- fi
- if test -f 'msgd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'msgd.c'\"
- else
- echo shar: Extracting \"'msgd.c'\" \(4283 characters\)
- sed "s/^X//" >'msgd.c' <<'END_OF_FILE'
- X/*
- X * msgd: daemon for the msg program. Allows users to send messages to
- X * other users screens across the net. The daemon listens to a port and
- X * waits for reqeuests to send messages. If the user is logged in and
- X * allowing messages, the daemon accepts the message from the sending
- X * machine.
- X */
- X
- X/*
- X * Written by Larry Moss (lm03_cif@uhura.cc.rochester.edu)
- X * Gavin Stark (gest_ss@uhura.cc.rocehster.edu)
- X * Fall, 1990
- X */
- X
- X#include <signal.h>
- X#include <sys/wait.h>
- X#include <sys/time.h>
- X#include <sys/resource.h>
- X#include "socket.h" /* Socket defs */
- X#include "socketnum.h" /* Socket number */
- X
- Xvoid deal_with_connection();
- Xvoid dummy();
- Xvoid restart();
- X
- Xvoid main()
- X{
- X int s; /* Socket that we are working with */
- X FILE *logfp;
- X
- X /*
- X * Set things up to handle SIG_CHLDs so that they can die normally.
- X * Then disconnect the daemon from the shell. We fork and only let
- X * the child live so the shell thinks the process is finished.
- X */
- X signal(SIGCHLD, dummy);
- X close(0); close(1); close(2);
- X if(fork())
- X exit(0);
- X setpgrp(0, 0);
- X
- X s=sockit(); /* Go set the socket stuff */
- X
- X listen(s, 5); /* listen for as many as 5 connections at once */
- X for (;;) {
- X struct sockaddr_in his_addr;
- X int his_len = sizeof (his_addr);
- X int ns;
- X
- X /*
- X * wait for connection to be established.
- X * If accept returns something less than zero there was an
- X * error. For now we'll ignore it since errors will occur
- X * when a child dies.
- X */
- X if ((ns = accept(s, &his_addr, &his_len)) > 0) {
- X if(fork() == 0) {
- X close(s);
- X deal_with_connection(ns); /* Go and deal with a connection */
- X exit();
- X }
- X }
- X close(ns);
- X }
- X}
- X
- X/*
- X * Talk to calling program and get some information, like who it is that's
- X * calling and the actual message. In other words, the bulk of the
- X * program. It should probably return some error code if it fails for some
- X * unexpected reason.
- X */
- Xvoid deal_with_connection(ns)
- Xint ns;
- X{
- X FILE *fp; /* Input/Output file */
- X char whocalled[200],to[200],tty[200]; /* Info variables */
- X char s[BUFSIZ]; /* string to get message */
- X char message[BUFSIZ];
- X
- X struct utmp *u; /* utmp entry */
- X extern struct utmp *getutmpline(), /* get utmp programs */
- X *getutmpname();
- X
- X FILE *ttyfp; /* tty file */
- X int loop;
- X
- X fp=fdopen(ns,"w+"); /* Open file to socket */
- X rewind(fp);
- X
- X fscanf(fp,"%s %s %s",whocalled,to,tty); /* Get info from the remote program */
- X
- X rewind(fp); /* Rewind the file for writing */
- X
- X if(strcmp(tty,"NONE")==0) /* NONE is sent because I couldn't */
- X tty[0]=0; /* figure out how to send the NULL */
- X /* pointer it is expecting */
- X
- X if (tty[0] != 0)
- X u = getutmpline(tty);
- X else
- X u = getutmpname(to); /* GET UTMP NAME */
- X
- X
- X /*
- X * Check to see if person is logged in. It's kind of hard to send
- X * a message to someone that isn't there. It should be able to
- X * check for a user on a particular tty also. That still needs to
- X * be implemented.
- X */
- X if (u == (struct utmp *) NULL || strncmp(u->ut_name, to, 8) != 0) {
- X if (tty[0] != 0) {
- X fprintf(fp,"ERROR\n");
- X fprintf(fp, "TTY_ERROR: %s is not logged on to %s\n",
- X to, tty);
- X }
- X else {
- X fprintf(fp, "ERROR\n");
- X fprintf(fp, "%s is not logged on to %s\n", to,get_local_hostname());
- X }
- X fclose(fp);
- X return;
- X }
- X
- X /*
- X * Set up a string containing the full pathname to the line.
- X */
- X sprintf(tty, "/dev/%.8s", u->ut_line);
- X
- X /*
- X * Check to see if the person is refusing messages. I hate it when
- X * people do that, but I know some people REALLY don't want to be
- X * bugged, so....
- X */
- X if ((ttyfp = fopen(tty,"w")) == (FILE *)NULL ) {
- X fprintf(fp,"ERROR\n");
- X fprintf(fp, "%.8s is not receiving messages on %.8s\n",
- X u->ut_name, u->ut_line);
- X fclose(fp);
- X return;
- X }
- X fprintf(fp,"NOERROR\n"); /* Send that no errors were found */
- X
- X rewind(fp); /* rewind for reading */
- X
- X /*
- X * Clear message buffer. Read message from socket, and send to tty.
- X */
- X
- X for(loop=0;loop<BUFSIZ;loop++) message[loop]=0; /* Clear message */
- X
- X fread(message,BUFSIZ,1,fp); /* Read message */
- X
- X fprintf(ttyfp,message); /* print message */
- X
- X fclose(ttyfp); /* Close the tty */
- X
- X/* rewind(fp); /* Rewind just in case */
- X fclose(fp);
- X return; /* Do I need to document this */
- X}
- X
- Xvoid dummy() {
- X wait(0);
- X}
- END_OF_FILE
- if test 4283 -ne `wc -c <'msgd.c'`; then
- echo shar: \"'msgd.c'\" unpacked with wrong size!
- fi
- # end of 'msgd.c'
- fi
- if test -f 'nmsg.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'nmsg.c'\"
- else
- echo shar: Extracting \"'nmsg.c'\" \(3504 characters\)
- sed "s/^X//" >'nmsg.c' <<'END_OF_FILE'
- X/*
- X * nmsg: Client for the network version of msg. Allows users to send
- X * messages to other users screens across the net. The client parses the
- X * command line and gets the message to send. The message is passed on to
- X * the daemon to deliver.
- X */
- X
- X/*
- X * Written by Larry Moss (lm03_cif@uhura.cc.rochester.edu)
- X * Gavin Stark (gest_ss@uhura.cc.rocehster.edu)
- X * Fall, 1990
- X */
- X
- X#include <stdio.h>
- X#include <string.h>
- X#include "socketnum.h"
- X#include "socket.h"
- X
- X
- Xextern char *ttyname();
- X
- Xvoid usage();
- Xvoid interrupt();
- Xvoid sendit();
- Xvoid getmessage();
- Xchar *getttyname();
- Xchar *getusername();
- Xint daemon_sockit();
- X
- Xvoid main(argc,argv)
- Xint argc;
- Xchar **argv;
- X{
- X int trc=argc;
- X
- X int daemon_socket; /* Socket File number */
- X char toaddress[255], /* Host to connect to */
- X tty[50], /* TTY to address */
- X localhost[255], /* Our host */
- X errorstate[5],
- X s[BUFSIZ],
- X message[BUFSIZ];
- X
- X int i;
- X FILE *fp; /* Socket Read/Write file */
- X char *name, *host; /* Strings used to parse username and host */
- X
- X /*
- X * use the local address as the default
- X */
- X strcpy(localhost,get_local_hostname());
- X
- X /*
- X * If no arguments were given to the program, just exit. Otherwise
- X * parse the command line.
- X */
- X if(argc == 1)
- X usage(argv[0]);
- X
- X
- X /*
- X * Parse TTY info
- X */
- X
- X if(argc<3)
- X strcpy(tty,"NONE");
- X else
- X strcpy(tty,argv[2]);
- X
- X
- X if((name = strtok(argv[1], "@")) != (char *)NULL)
- X host=strtok((char *)NULL,"\0");
- X
- X /*
- X * if host was parsed, copy that hostname into toaddress
- X */
- X if(host!=0) strcpy(toaddress,host);
- X else strcpy(toaddress,localhost);
- X
- X /*
- X * open connection to remote daemon
- X */
- X daemon_socket=daemon_sockit(toaddress);
- X
- X
- X fp=fdopen(daemon_socket,"w+"); /* Open socket */
- X
- X /*
- X * Send data to daemon
- X */
- X fprintf(fp, "\r%s\n%s\n%s\n", getpwuid(getuid())->pw_name,name,tty);
- X
- X rewind(fp); /* Rewind */
- X
- X fscanf(fp,"%s",errorstate); /* See if any errors were encountered */
- X
- X if(strcmp(errorstate,"ERROR")==0) { /* If there was an error get it */
- X fgets(s,BUFSIZ,fp);
- X fgets(s,BUFSIZ,fp);
- X
- X printf("%s\n",s);
- X fclose(fp);
- X exit(0);
- X }
- X rewind(fp);
- X
- X /*
- X * Send the message
- X */
- X getmessage(message, BUFSIZ); /* Get the message */
- X fputs(message, fp); /* Put the message */
- X fclose(fp); /* Close the socket */
- X}
- X
- X
- Xvoid usage(progname)
- Xchar *progname;
- X{
- X fprintf(stderr, "Usage: %s <user>[@host] [tty]\n", progname);
- X exit(1);
- X}
- X
- X /*
- X * This still belongs to Sirota
- X */
- X
- X/*
- X * Get the username associated with the current uid.
- X */
- Xchar *getusername()
- X{
- X struct passwd *p;
- X char *cp;
- X static char name[BUFSIZ];
- X
- X /*
- X * Get the passwd file entry associated with the current uid
- X */
- X if ((p = getpwuid(getuid())) == (struct passwd *) NULL) {
- X fprintf(stderr, "Who the hell are you, anyway?\n");
- X exit(-1);
- X }
- X
- X /*
- X * Pretend that the GECOS field contains only the full name
- X */
- X if ((cp = index(p->pw_gecos, ',')) != (char *) NULL)
- X *cp = (char) NULL;
- X
- X /*
- X * Create and return a string containing the full name and username
- X */
- X sprintf(name, "%s <%s@%s>", p->pw_gecos, p->pw_name, get_local_hostname());
- X return name;
- X}
- X
- X/*
- X * Get the name of the tty associated with stdout (2). If unknown, say so.
- X */
- Xchar *getttyname()
- X{
- X char *tty, *cp;
- X
- X /*
- X * Get the ttyname
- X */
- X tty = ttyname(2);
- X
- X /*
- X * If it's unknown, say so.
- X */
- X if (tty == (char *) NULL)
- X return "[tty unknown]";
- X
- X /*
- X * Strip off the pathname
- X */
- X if ((cp = rindex(tty, '/')) != (char *) NULL)
- X tty = cp + 1;
- X
- X /*
- X * Return it
- X */
- X return tty;
- X}
- END_OF_FILE
- if test 3504 -ne `wc -c <'nmsg.c'`; then
- echo shar: \"'nmsg.c'\" unpacked with wrong size!
- fi
- # end of 'nmsg.c'
- fi
- if test -f 'socklib.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'socklib.c'\"
- else
- echo shar: Extracting \"'socklib.c'\" \(3211 characters\)
- sed "s/^X//" >'socklib.c' <<'END_OF_FILE'
- X#include "socket.h"
- X#include "socketnum.h"
- X
- X
- X
- Xchar *
- Xget_local_hostname()
- X{
- X static char local_host_name[128];
- X static int host_name_is_set = NO;
- X
- X if (host_name_is_set == NO) {
- X if (gethostname(local_host_name, sizeof (local_host_name)) == -1) {
- X perror("gethostname:");
- X strcpy(local_host_name, "localhost");
- X }
- X host_name_is_set = YES;
- X }
- X
- X return local_host_name;
- X}
- X
- X/* Hostname to address takes a pointer to a internet socket address
- X (struct sockaddr_in) and a hostname, and puts the internet address
- X of that host in the sockaddr. This particular routine also takes
- X an internet host number (e.g., 128.20.45.56??) and converts that
- X to an address (an address is really just a 32 bit number). */
- X
- Xhostname_to_address(sin, host_name)
- Xstruct sockaddr_in *sin;
- Xchar *host_name;
- X{
- X struct hostent *hp;
- X
- X bzero(sin, sizeof (*sin));
- X if (isdigit(host_name[0])) {
- X unsigned long addr;
- X
- X addr = inet_addr(host_name);
- X if ((int) addr != -1) {
- X bcopy((char *) &addr, (char *) &sin->sin_addr, sizeof (addr));
- X sin->sin_family = htons(AF_INET);
- X return YES;
- X }
- X }
- X if ((hp = gethostbyname(host_name)) == NULL)
- X return NO;
- X bcopy(hp->h_addr, (char *) &sin->sin_addr, hp->h_length);
- X sin->sin_family = hp->h_addrtype;
- X
- X return YES;
- X}
- X
- X/* This takes a socket, and address, and the length of the address, which
- X is just the sizeof (struct sockaddr_in), and binds the socket to that
- X address and SOME free port. It then does a getsockname(). Basically,
- X it sets the port to 0, does a bind system call, which chooses a random
- X port us. The system chooses the random port BUT it doesn't store that
- X random port back into the ADDR structure. So, since I might want to
- X know what port got assigned, I do a getsockname() system call, which
- X given a socket, puts the address (which contains the port) in the
- X address structure. Sorry if that made no sense. */
- X
- Xbind_and_name(s, addr, len)
- Xstruct sockaddr_in *addr;
- X{
- X addr->sin_port = 0;
- X if (bind(s, addr, len) == -1)
- X return -1;
- X if (getsockname(s, addr, &len) == -1)
- X return -1;
- X}
- X
- X
- Xset_port(addr, port)
- Xstruct sockaddr_in *addr;
- X{
- X addr->sin_port = htons((short) port);
- X}
- X
- Xsockit()
- X{
- X int s;
- X struct sockaddr_in my_addr;
- X int len=sizeof (my_addr);
- X
- X s = socket(AF_INET, SOCK_STREAM, 0);
- X if (hostname_to_address(&my_addr, get_local_hostname()) < 0) {
- X perror("reply: hostname_to_address");
- X exit(1);
- X }
- X set_port(&my_addr, SERVER_PORT);
- X if (bind(s, &my_addr, len) < 0)
- X perror("bind:"); /* something's wrong */
- X return s;
- X}
- X
- X
- X/*
- X * open connection to remote daemon
- X */
- Xdaemon_sockit(toaddress)
- Xchar toaddress[255];
- X{
- X int daemon_socket;
- X
- X struct sockaddr_in my_addr,daemon_addr;
- X
- X if (hostname_to_address(&my_addr, get_local_hostname()) < 0) {
- X perror("reply: hostname_to_address");
- X exit(1);
- X }
- X
- X if (hostname_to_address(&daemon_addr,toaddress) < 0) {
- X perror("reply: hostname_to_address");
- X exit(1);
- X }
- X
- X daemon_socket = socket(AF_INET, SOCK_STREAM, 0);
- X bind_and_name(daemon_socket, &my_addr, sizeof (my_addr));
- X set_port(&daemon_addr, SERVER_PORT);
- X
- X if (connect(daemon_socket, &daemon_addr, sizeof (daemon_addr)) < 0) {
- X perror("Could not connect with remote daemon");
- X exit();
- X }
- X return daemon_socket;
- X}
- END_OF_FILE
- if test 3211 -ne `wc -c <'socklib.c'`; then
- echo shar: \"'socklib.c'\" unpacked with wrong size!
- fi
- # end of 'socklib.c'
- fi
- if test -f 'utmp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'utmp.c'\"
- else
- echo shar: Extracting \"'utmp.c'\" \(1383 characters\)
- sed "s/^X//" >'utmp.c' <<'END_OF_FILE'
- X/*
- X * This program is Copyright (c) 1988, 1989 by Mark Sirota.
- X * It is provided to you without charge, and with no warranty.
- X * You may give away copies of libutmp, including sources, provided that this
- X * notice is included in all the files.
- X */
- X
- X#include <utmp.h>
- X#include <sys/file.h>
- X#include <stdio.h>
- X
- Xstatic int utmpfd = -1;
- X
- X/*
- X * Get the next entry in /etc/utmp
- X */
- Xstruct utmp *
- Xgetutmpent()
- X{
- X static struct utmp u;
- X
- X if (utmpfd == -1)
- X if ((utmpfd = open("/etc/utmp", O_RDONLY)) == -1)
- X return (struct utmp *) NULL;
- X
- X if (read(utmpfd, &u, sizeof (struct utmp)) != sizeof (struct utmp))
- X return (struct utmp *) NULL;
- X
- X return &u;
- X}
- X
- X/*
- X * Get a utmp entry according to ut_line.
- X */
- Xstruct utmp *
- Xgetutmpline(line)
- Xregister char *line;
- X{
- X register struct utmp *u;
- X
- X setutmpent();
- X while ((u = getutmpent()) != (struct utmp *) NULL) {
- X printf("testline in utmp.c %s\n",u->ut_line);
- X if (strncmp(u->ut_line, line, 8) == 0)
- X break;
- X }
- X return u;
- X}
- X
- X/*
- X * Get a utmp entry according to ut_name.
- X */
- Xstruct utmp *
- Xgetutmpname(name)
- Xregister char *name;
- X{
- X register struct utmp *u;
- X
- X setutmpent();
- X while ((u = getutmpent()) != (struct utmp *) NULL)
- X if (strncmp(u->ut_name, name, 8) == 0)
- X break;
- X return u;
- X}
- X
- X/*
- X * Rewind /etc/utmp
- X */
- Xint
- Xsetutmpent()
- X{
- X lseek(utmpfd, 0L, L_SET);
- X}
- X
- X/*
- X * Close /etc/utmp
- X */
- Xint
- Xendutmpent()
- X{
- X close(utmpfd);
- X utmpfd = -1;
- X}
- END_OF_FILE
- if test 1383 -ne `wc -c <'utmp.c'`; then
- echo shar: \"'utmp.c'\" unpacked with wrong size!
- fi
- # end of 'utmp.c'
- fi
- if test -f 'input.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'input.h'\"
- else
- echo shar: Extracting \"'input.h'\" \(709 characters\)
- sed "s/^X//" >'input.h' <<'END_OF_FILE'
- X/*
- X * header file for:
- X * input.c: Larry Moss (lm03_cif@cc.rochester.edu)
- X * Fall, 1990
- X *
- X * This was written as part of nmsg, a version of write that can be used
- X * over the net, by Larry Moss and Gavin Stark. Feel free to do whatever
- X * you want with this code as long as my name stays on it and I receive
- X * credit for what I've done.
- X */
- X
- X#define LINELENGTH 78
- X#define BACKSPACE fputs("\b \b", stdout)
- X#define DEL 127
- X#define WERASE 23
- X#define KILL 21
- X#define TAB 9
- X#define CTL(c) (c & 037)
- X#define MAXLENGTH 1024
- X
- Xvoid get_input();
- Xvoid setterm();
- Xvoid unsetterm();
- Xint handle_tilde();
- Xint interrupt();
- Xint pause();
- Xint cont();
- Xint child();
- Xint readmessage();
- Xchar *getenv();
- Xchar *expand();
- END_OF_FILE
- if test 709 -ne `wc -c <'input.h'`; then
- echo shar: \"'input.h'\" unpacked with wrong size!
- fi
- # end of 'input.h'
- fi
- if test -f 'socket.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'socket.h'\"
- else
- echo shar: Extracting \"'socket.h'\" \(253 characters\)
- sed "s/^X//" >'socket.h' <<'END_OF_FILE'
- X#define NO 0
- X#define YES 1
- X#include <ctype.h>
- X#include <fcntl.h>
- X#include <netdb.h>
- X#include <pwd.h>
- X#include <stdio.h>
- X#include <strings.h>
- X#include <sys/param.h>
- X#include <sys/socket.h>
- X#include <sys/types.h>
- X#include <utmp.h>
- X#include <netinet/in.h>
- END_OF_FILE
- if test 253 -ne `wc -c <'socket.h'`; then
- echo shar: \"'socket.h'\" unpacked with wrong size!
- fi
- # end of 'socket.h'
- fi
- if test -f 'socketnum.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'socketnum.h'\"
- else
- echo shar: Extracting \"'socketnum.h'\" \(25 characters\)
- sed "s/^X//" >'socketnum.h' <<'END_OF_FILE'
- X#define SERVER_PORT 2834
- END_OF_FILE
- if test 25 -ne `wc -c <'socketnum.h'`; then
- echo shar: \"'socketnum.h'\" unpacked with wrong size!
- fi
- # end of 'socketnum.h'
- fi
- if test -f 'msgd.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'msgd.man'\"
- else
- echo shar: Extracting \"'msgd.man'\" \(465 characters\)
- sed "s/^X//" >'msgd.man' <<'END_OF_FILE'
- X.TH MSGD 8 "23 JAN 1991"
- X.SH NAME
- Xmsgd \- Delivers messages sent with nmsg(1).
- X.SH SYNOPSIS
- X\fBmsgd\fP
- X.SH DESCRIPTION
- X\fBmsgd\fP is the daemon for nmsg(1). It receives messages sent over the
- Xinternet and delivers them to the appropriate user. It will
- Xautomagically disconnect itself from the shell and run in the background.
- X.RE
- X.SH FILES
- X/etc/utmp
- X.SH "SEE ALSO"
- Xnmsg(1)
- X.SH AUTHORS
- XGavin Stark gest_ss@cc.rochester.edu
- X.br
- XLarry Moss lm03_cif@cc.rochester.edu
- END_OF_FILE
- if test 465 -ne `wc -c <'msgd.man'`; then
- echo shar: \"'msgd.man'\" unpacked with wrong size!
- fi
- # end of 'msgd.man'
- fi
- if test -f 'nmsg.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'nmsg.man'\"
- else
- echo shar: Extracting \"'nmsg.man'\" \(1870 characters\)
- sed "s/^X//" >'nmsg.man' <<'END_OF_FILE'
- X.TH NMSG 1 "23 JAN 1991"
- X.SH NAME
- Xnmsg \- Send a message to a user
- X.SH SYNOPSIS
- X\fBnmsg\fP <\fIuser\fP>[\fI@host\fP] [\fItty\fP]
- X.SH DESCRIPTION
- X\fBnmsg\fP sends a message to the specified \fIuser\fP. The message is
- Xread from the standard input until a CTL-D or a single '.' on one line is
- Xencountered. In normal usage the program works interactively to provide
- Xword wrap and to allow tilde commands to be used. If the input is coming
- Xfrom a pipe it will be read in straight without word wrapping, and tildes
- Xwill be ignored. In all cases a copy of the message is saved in
- X$HOME/.oldmsg.
- X.PP
- XThe optional \fBhost\fP argument allows a message to be sent to someone on
- Xa remote machine assuming \fBhost\fP has msgd(8) running on the same port.
- XThe \fItty\fP argument specifies which tty to write to, in the case that
- Xa user is logged in more than once. If \fItty\fP is not supplied, the
- Xterminal chosen is arbitrary.
- X.PP
- X.RS
- X.B Tilde commands:
- X.IP
- X~p Print contents of current message.
- X.IP
- X~r\fIfile\fP include \fIfile\fP in message. If no argument is given
- X\fBnmsg\fP attempts to use the file $HOME/.oldmsg as input. Tilde
- Xexpansion of file names does work however there are no wildcards.
- X.IP
- X~v This will place you in an editor. If you have the variable
- XEDITOR set in your environment it will use that. Otherwise it will
- Xdefault to /usr/ucb/vi. This is definitely the silliest feature of the
- Xprogram.
- X.RE
- X.SH FILES
- X/etc/utmp
- X.SH BUGS
- XWhen running interactively the program assumes you are using an 80 column
- Xterminal window.
- X.LP
- XOften entering the editor twice in one session causes problems. Also you
- Xcan't pause out of the editor.
- X.LP
- XThe program isn't very smart about picking the tty to write to.
- X.SH "SEE ALSO"
- Xmail(1), mesg(1), talk(1), who(1), write(1), msgd(8)
- X.SH AUTHORS
- XLarry Moss lm03_cif@cc.rochester.edu
- X.br
- XGavin Stark gest_ss@cc.rochester.edu
- END_OF_FILE
- if test 1870 -ne `wc -c <'nmsg.man'`; then
- echo shar: \"'nmsg.man'\" unpacked with wrong size!
- fi
- # end of 'nmsg.man'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(1368 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X#
- X# Makefile for msg - a program to splash text on someone's screen
- X# over the network.
- X#
- X
- X#
- X# This is the only section that should need to be changed.
- X# for some reason, gcc won't compile this correctly on a sun3. There's a
- X# problem with bcopy() that needs to be looked into.
- X#
- XDESTDIR = /u/cif/lm03_cif
- XBINDIR = $(DESTDIR)/bin
- XETCDIR = $(DESTDIR)/etc
- XMANDIR = $(DESTDIR)/man
- X#CC = gcc
- XCC = cc
- X
- X#
- X# Comment out the next line if you don't want to use the nameserver.
- X#
- XLDFLAGS = -lresolv
- X
- X#
- X# the NORESOLV definition doesn't do anything now. Some #include lines may
- X# need to be commented out in socket.h. Nothing else should need to be
- X# changed.
- X#
- X#CFLAGS = -O -D"NORESOLV"
- X#CFLAGS = -g
- XCFLAGS = -O
- XDOBJS = msgd.o socklib.o utmp.o
- XMOBJS = nmsg.o socklib.o input.o
- X
- X#
- X# .c.o is being changed so gcc won't complain about the options sun's make
- X# supplies to $(CC)
- X#
- X.c.o:
- X $(CC) $(CFLAGS) -c $<
- X
- Xall: nmsg msgd
- X
- Xnmsg: $(MOBJS)
- X $(CC) -o nmsg $(MOBJS) $(LDLIBS) $(LDFLAGS)
- X
- Xmsgd: $(DOBJS)
- X $(CC) -o msgd $(DOBJS) $(LDLIBS) $(LDFLAGS)
- X
- Xinstall: nmsg msgd
- X install -s nmsg $(BINDIR)
- X install -s msgd $(ETCDIR)
- X install -c -m 0644 nmsg.man $(MANDIR)/man1/nmsg.1
- X install -c -m 0644 msgd.man $(MANDIR)/man8/msgd.8
- X
- Xtar:
- X tar -cvf nmsg.tar README *.c *.h *.man Makefile TODO
- X
- Xshar:
- X shar -onmsg.shar README *.c *.h *.man Makefile TODO
- X
- Xclean:
- X rm -f *.o msgd nmsg core
- END_OF_FILE
- if test 1368 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'TODO' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'TODO'\"
- else
- echo shar: Extracting \"'TODO'\" \(1100 characters\)
- sed "s/^X//" >'TODO' <<'END_OF_FILE'
- XIf no tty is specified it should be smarter. It would be nice if it could
- Xselect the 'best' tty rather than grabbing a random one.
- X
- XIt won't let the editor pause. (low priority item)
- X
- Xsometimes chokes when you edit something a second time.
- X
- Xwill try to deliver message even if user logs out.
- X
- XIt should be able to handle multiple users. Probably notify after who the
- Xmessage was delivered to rather than try to find out which people are
- Xlogged in ahead of time. Input format would be changed to user@host:tty
- X
- XMark's suggestion:
- X> Of course, a neat extra-credit technique would be to batch messages to the
- X> same host, so that if I send to "lm03_cif@troi.cc.rochester.edu
- X> jdic@troi.cc.rochester.edu", it would only contact troi's msgd once instead of
- X> twice. But that's extra credit. :-)
- X
- XAnother idea would be to keep a record of users that received messages in
- Xthe last hour or so so you can check to see who sent you a message if you
- Xjust cleared your screen. Something like 'nmsg -w'.
- X
- XIf a record is kept of who sent the last message, then 'nmsg -r' could
- Xjust reply to the last person.
- END_OF_FILE
- if test 1100 -ne `wc -c <'TODO'`; then
- echo shar: \"'TODO'\" unpacked with wrong size!
- fi
- # end of 'TODO'
- fi
- echo shar: End of shell archive.
- exit 0
- --
- lm03_cif@uhura.cc.rochester.edu / "I'm so tired... I was up all night
- lmo3_ss@db1.cc.rochester.edu / trying to round off infinity."
- lmo3_ss@uordbv.bitnet / - Stephen Wright
-