[comp.sources.misc] v03i057: send, reply, shout, huh, stom -- For SysV.

ag@elgar.UUCP (Keith Gabryelski) (06/16/88)

comp.sources.misc: Volume 3, Issue 57
Submitted-By: "Keith Gabryelski" <ag@elgar.UUCP>
Archive-Name: send

Here is source code for a send program written under Sco Xenix 2.2.1.
Also included is code for fsend (fast send) and its ilk, huh (display
last send), and stom (send format to unix mailbox format converter).

There should be no problem using this code on any system V machine.

This code will not work on a BSD machine.  Although it wouldn't be
much work to port it.

Send me your comments and bug reports/fixes.

It's public domain... Your mileage may vary.

--- 
  "If green is all there is to be, then green is good enough for me" - ktf
[  Keith   ]  UUCP: {ucsd, cbosgd!crash, sdcsvax!crash, nosc!crash}!elgar!ag
[Gabryelski]  INET: ag@elgar.cts.com                 ARPA: elgar!ag@ucsd.edu
----------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	Makefile
#	send.c
#	huh.c
#	stom.c
#	doc
# This archive created: Wed Jun 15 15:43:13 1988
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
To make this package:

	edit the Makefile -- change $(BINDIR) and $(MANDIR) to something
		    	     reasonable.
	make
	make install

Voila'
--- 
[  Keith   ]  UUCP: {ucsd, cbosgd!crash, sdcsvax!crash, nosc!crash}!elgar!ag
[Gabryelski]  INET: ag@elgar.cts.com                 ARPA: elgar!ag@ucsd.edu
SHAR_EOF
fi # end of overwriting check
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
SHELL=/bin/sh
BINDIR = /u/local/bin
MANDIR= /usr/man/man.LOCAL

all: send huh stom

send:	send.c
	cc -O send.c -o send

huh:	huh.c
	cc -O huh.c -o huh

stom:	stom.c
	cc -O stom.c -o stom

shar:
	shar README Makefile send.c huh.c stom.c doc > send.shar

install:
	-rm -f $(BINDIR)/fs $(BINDIR)/fsend $(BINDIR)/fr $(BINDIR)/freply
	-rm -f $(BINDIR)/reply $(BINDIR)/shout $(BINDIR)/send
	cp send huh stom $(BINDIR)
	ln $(BINDIR)/send $(BINDIR)/fs
	ln $(BINDIR)/send $(BINDIR)/fsend
	ln $(BINDIR)/send $(BINDIR)/fr
	ln $(BINDIR)/send $(BINDIR)/freply
	ln $(BINDIR)/send $(BINDIR)/reply
	ln $(BINDIR)/send $(BINDIR)/shout
	-cp doc/*.C $(MANDIR)

lint:
	lint send.c -o send
SHAR_EOF
fi # end of overwriting check
if test -f 'send.c'
then
	echo shar: will not over-write existing file "'send.c'"
else
cat << \SHAR_EOF > 'send.c'
/*
**  send.c
**
**	Written by: Keith Gabryelski (ag@elgar.UUCP)
**
**		Released into public domain June 14, 1988.
**			Please keep this header.
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <utmp.h>
#include <pwd.h>
#include <errno.h>

extern errno;

extern struct passwd *getpwuid(), *getpwnam();

extern FILE *fopen();
extern char *getlogin(), *strrchr(), *ctime(), *malloc(), *realloc();
extern char *ttyname(), *strcpy(), *strncpy(), *strcat();
extern long time();

extern char *sys_errlist[];
extern int sys_nerr;
extern void setutent();

#undef TRUE
#undef FALSE
#define TRUE			1
#define FALSE			0
#define UNUSED			-1

#define NORMAL			0
#define FAST			1

#define	SENDS_FILENAME		"/.sends"	/* must have the '/' */
#define	DEAD_SEND_FILENAME	"/dead.send"    /* must have the '/' */

#define MESSAGE_SEPARATOR	0x1F

char *puterr(), *get_typed_message(), *cat_message(), *myfgets();
char *get_last_sender();
int reply(), send(), shout();

struct
{
    char *name;				/* Command name.	*/
    int (*function)();			/* Function to use.	*/
    int type;				/* Parameters.		*/
    char *text;				/* First word in header.*/
}
command_table[] =
{
    {"fr", reply, FAST, "Reply"},
    {"freply", reply, FAST, "Reply"},
    {"fs", send, FAST, "Message"},
    {"fsend", send, FAST, "Message"},
    {"reply", reply, NORMAL, "Reply"},
    {"send", send, NORMAL, "Message"},
    {"shout", shout, NORMAL, "Shout"},
    {NULL, }
};

int argc, uid;
char **argv, *progname;
char login_name[] = "        \0",		/* eight chars plus nul */
     tty_name[] = "            \0";		/* twelve chars plus a nul */

char *
mymalloc(size)
unsigned size;
{
    char *p;

    if ((p = malloc(size)) == NULL)
    {
	(void) fprintf(stderr, "%s: Out of memory.\n", progname);
	exit(-1);
    }

    return p;
}

char *
myrealloc(p, size)
char *p;
unsigned size;
{
    if (p == NULL)
    {
	if ((p = malloc(size)) == NULL)
	{
	    (void) fprintf(stderr, "%s: Out of memory.\n", progname);
	    exit(-1);
	}
    }
    else if ((p = realloc(p, size)) == NULL)
    {
	(void) fprintf(stderr, "%s: Out of memory.\n", progname);
	exit(-1);
    }

    return p;
}

main(largc, largv)
int largc;
char **largv;
{
    char *ptr;
    int i;
    struct passwd *pt;

    progname = *largv++;  --largc;
    argv = largv;  argc = largc;

    uid = getuid();

    pt = getpwuid(uid);

    if ((ptr = getlogin()) == NULL)
	if ((ptr = pt->pw_name) == NULL)
	    ptr = "somebody";		/* can't figure this guy out */

    (void) strncpy(login_name, ptr, 8);

    if ((ptr = ttyname(0)) == NULL)
	strcpy(tty_name, "tty??");
    else
	strncpy(tty_name, ((ptr= strrchr(ptr, '/')) ? ptr+1 : "tty??"), 12);

    i = 0;
    while (command_table[i].name != NULL)
	if (strcmp(progname, command_table[i].name))
	    ++i;
	else
	    break;

    if (command_table[i].name == NULL)
	send(NORMAL, "Message");
    else
	(*command_table[i].function)(command_table[i].type,
				     command_table[i].text);

    exit(0);
}

/*
** reply --
**           Reply to a previously sent message.  This routine uses the
**           (from) user name of the last message sent as the user to
**           send a message to.
*/

reply(type, text)
int type;
char *text;
{
    char **send_to_list = (char **)mymalloc(0);
    char *message;

    /*
    ** make send_to_list initially have one element -- NULL.
    **
    ** Even though only one user is ever gonna get a message,
    ** I still use the add_to_list() routine.
    */

    send_to_list = (char **)myrealloc(send_to_list, sizeof(char *));
    send_to_list[0] = NULL;

    add_to_list(&send_to_list, get_last_sender());

    message = get_typed_message();

    send_message(send_to_list, message, type, text);
}

/*
** send - generic send-a-message-to-one-or-more-users routine.
**
**
**
*/

send(type, text)
int type;
char *text;
{
    char **send_to_list = (char **)mymalloc(0);
    char *message;

    /*
    ** make send_to_list initially have one element -- NULL.
    **
    */

    send_to_list = (char **)myrealloc(send_to_list, sizeof(char *));
    send_to_list[0] = NULL;

    if (argc < 1)
    {
	fprintf(stderr, "%s: usage: %s user1, [user2,] [...,] [message]\n",
		progname, progname);
	exit(-1);
    }

    while (*argv != NULL)
    {
	--argc;
	if ((*argv)[strlen(*argv)-1] == ',')
	{
	    (*argv)[strlen(*argv)-1] = '\0';
	    add_to_list(&send_to_list, *argv++);
	}
	else
	{
	    add_to_list(&send_to_list, *argv++);
	    break;
	}
    }

    message = get_typed_message();

    send_message(send_to_list, message, type, text);
}

/*
** shout -- Send a message to all logged in users.
**
**
*/

shout(type, text)
int type;
char *text;
{
    char **send_to_list = (char **)mymalloc(0);
    char *message;
    struct utmp *getutent(), *ut;

    /*
    ** make send_to_list initially have one element -- NULL.
    **
    */

    send_to_list = (char **)myrealloc(send_to_list, sizeof(char *));
    send_to_list[0] = NULL;

    setutent();

    while ((ut = getutent()) != (struct utmp *)NULL)
	if (ut->ut_type == USER_PROCESS)
	    add_to_list(&send_to_list, ut->ut_line);

    message = get_typed_message();

    send_message(send_to_list, message, type, text);
}

/*
** get_typed_message() --
**                         Get arguments for a message of the command line
**                         and take input from stdin if the last argument
**                         is "-" or no message was given on the command
**                         line.
*/

char *
get_typed_message()
{
    char *buffer = mymalloc(1);
    int old_argc;

    *buffer = '\0';

    old_argc = argc;
    while (argc > 0 && !(argc == 1 && !strcmp(*argv, "-")))
    {
	buffer = cat_message(buffer, *argv++);
	buffer = cat_message(buffer, " ");
	--argc;
    }

    if (argc || !old_argc)
    {
	char *line = mymalloc(BUFSIZ);

	while ((line = myfgets(line, BUFSIZ, stdin)) != NULL)
	    buffer = cat_message(buffer, line);
    }

    /*
    ** That extra <cr> or ' '. ack...
    */

    if (buffer[strlen(buffer)-1] == '\n' || buffer[strlen(buffer)-1] == ' ')
	buffer[strlen(buffer)-1] = '\0';

    return buffer;
}

char *
myfgets(buffer, size, stream)
char *buffer;
int size;
FILE *stream;
{
    int c, length = 0;

    while ((c = getc(stream)) != EOF && c != '\n' && (length-1) < size)
	if (c >= ' ')
	    buffer[length++] = c;

    if (c == '\n')
	buffer[length++] = c;

    buffer[length++] = '\0';

    return  c == EOF ? NULL : buffer;
}

char *
cat_message(buffer, line)
char *buffer, *line;
{
    buffer = myrealloc(buffer, strlen(buffer) + strlen(line) + 1);
    strcat(buffer, line);
    return buffer;
}

char *
get_last_sender()
{
    char *ptr, *sends_filename = mymalloc(0);
    char dummy[50];
    static char name[50];
    int c, n;
    struct passwd *pt;
    FILE *fp;

    pt = getpwuid(uid);

    if ((ptr = pt->pw_dir) != NULL)
    {
	sends_filename = myrealloc(sends_filename, strlen(ptr) +
				   sizeof(SENDS_FILENAME) + 1);

	strcpy(sends_filename, ptr);
	strcat(sends_filename, SENDS_FILENAME);

	if ((fp = fopen(sends_filename, "r")) == (FILE *)NULL)
	{
	    fprintf(stderr, "%s: No reply possible, can't open %s (%s).\n",
		    progname, sends_filename, puterr(errno));
	    exit(-1);
	}

	*name = '\0';
	while (fscanf(fp, "[%s %s %s (%s", dummy, dummy, dummy,
			   name) == 4)
	    while ((c = getc(fp)) != MESSAGE_SEPARATOR && c != EOF)
		;

	fclose(fp);

	if (name[strlen(name)-1] == ')')
	    name[strlen(name)-1] = '\0';

	if (*name == '\0')
	{
	    fprintf(stderr, "%s: no sends.\n", progname);
	    exit(-1);
	}
    }
    else
    {
	fprintf(stderr, "%s: No reply possible, no home directory.\n",
		progname);

	exit(-1);
    }

    return name;
}

send_message(user_list, message, type, text)
char **user_list, *message;
int type;
char *text;
{
    char *date_text, *ptr, *sends_filename = mymalloc(0);
    char **sent_to_list = (char **)mymalloc(0);
    char **sends_list = (char **)mymalloc(0);
    int sendit = TRUE, sent = FALSE, failed = FALSE, need_crlf = FALSE;
    long clock[1];
    struct utmp *getutent(), *ut;
    struct passwd *pt;
    struct stat stbuf;
    FILE *fp;
    static char device[] = "/dev/            \0";

    /* setup null sent_to_list */

    sent_to_list = (char **)myrealloc(sent_to_list, sizeof(char *));
    sent_to_list[0] = NULL;

    sends_list = (char **)myrealloc(sends_list, sizeof(char *));
    sends_list[0] = NULL;

    /* get the date without a terminating <cr> */

    clock[0] = time((long *)0);
    date_text = ctime(clock);
    date_text[24] = '\0';

    /* find user/tty in utmp */

    while (*user_list != NULL)
    {
	setutent();
	sendit = UNUSED;
	sent = FALSE;

	while ((ut = getutent()) != (struct utmp *)NULL)
	{
	    if ((ut->ut_type == USER_PROCESS) &&
		((!strncmp(ut->ut_user, *user_list, 8)) ||
		 (!strncmp(ut->ut_line, *user_list, 12))))
	    {
		sendit = TRUE;

		if (add_to_list(&sent_to_list, ut->ut_line))
		{
		    sent = TRUE;
		    break;
		}

		strncpy(device+5, ut->ut_line, 12);

		if (uid != 0)
		{
		    if (stat(device, &stbuf) == -1)
		    {
			fprintf(stderr, "%s: Couldn't stat %s (%s).\n",
				progname, device, puterr(errno));
			sendit = FALSE;
			failed = TRUE;
		    }
		    else
			if (!stbuf.st_mode&2)
			{
			    fprintf(stderr,
				    "[%s/%s]: Is not receiving sends.\n",
				    ut->ut_user, ut->ut_line);
			    sendit = FALSE;
			    failed = TRUE;
			}
		}

		/* open device and send the message */

		if (sendit)
		{
		    if ((fp = fopen(device, "w")) == (FILE *)NULL)
			fprintf(stderr, "%s: could not open %s (%s).\n",
				progname, device, puterr(errno));
		    else
		    {
			if (type&FAST)
			    fprintf(fp, "\007\n[%s/%s: %s]\n", login_name,
				    tty_name, message);
			else
			    fprintf(fp, "\007\n[%s from %s (%s) %s]\n%s\n",
				    text, login_name, tty_name, date_text,
				    message);

			printf("[%s/%s] ", ut->ut_user, ut->ut_line);

			need_crlf = sent = TRUE;

			fclose(fp);

			/* write send to ~user/.sends file */
			if (!add_to_list(&sends_list, ut->ut_user))
			{
			    pt = getpwnam(ut->ut_user);

			    if ((ptr = pt->pw_dir) != NULL)
			    {
				sends_filename =
				    myrealloc(sends_filename, strlen(ptr) +
					      sizeof(SENDS_FILENAME) + 1);

				strcpy(sends_filename, ptr);
				strcat(sends_filename, SENDS_FILENAME);

				if ((fp = fopen(sends_filename, "a+")) !=
				    (FILE *)NULL)
				    fprintf(fp, "[%s from %s (%s) %s]\n%s\n%c",
					    text, login_name, tty_name,
					    date_text, message,
					    MESSAGE_SEPARATOR);

				fclose(fp);
			    }
			}
		    }
		}
	    }
	}

	if (!sent)
	{
	    failed = TRUE;
	    if (sendit == UNUSED)
	    {
		/*
		** Decide what the user tried to type in.  Was it a user
		** who isn't logged in or maybe a tty device that no user
		** is logged on to or maybe a mistyped username.
		*/

		if ((pt = getpwuid(*user_list)) == (struct passwd *)NULL)
		{
		    int status;

		    strncpy(device+5, *user_list, 12);

		    status = stat(device, &stbuf);

		    if (status == -1 || !stbuf.st_mode&S_IFCHR)
			fprintf(stderr, "%s: no user %s.\n", progname,
				*user_list);
		    else
			fprintf(stderr, "%s: no user logged on device %s.\n",
				progname, *user_list);
		}
		else
		    fprintf(stderr, "%s: %s not logged in.\n", progname,
			    *user_list);
	    }
	}
	++user_list;
    }

    if (failed)
    {
	char *dead_filename = malloc(0);

	pt = getpwuid(uid);

	if ((ptr = pt->pw_dir) == NULL)
	{
	    dead_filename = myrealloc(dead_filename, sizeof("/tmp/") +
				      sizeof(login_name) + 
				      sizeof(DEAD_SEND_FILENAME) + 1);

	    strcpy(dead_filename, "/tmp/");
	    strcat(dead_filename, login_name);
	    strcat(dead_filename, DEAD_SEND_FILENAME);
	}
	else
	{
	    dead_filename = myrealloc(dead_filename, strlen(ptr) +
				       sizeof(DEAD_SEND_FILENAME) + 1);
	    strcpy(dead_filename, ptr);
	    strcat(dead_filename, DEAD_SEND_FILENAME);
	}

	if ((fp = fopen(dead_filename, "a+")) != (FILE *)NULL)
	{
	    fprintf(fp, "[%s from %s (%s) %s]\n%s\n%c", text, login_name,
		    tty_name, date_text, message, MESSAGE_SEPARATOR);

	    fprintf(stderr, "%s: message copied to %s.\n", progname,
		    dead_filename);
	    
	}

	fclose(fp);
	free(dead_filename);
    }

    if (need_crlf)
	putchar('\n');

    free(sends_filename);
}

add_to_list(list, name)
char ***list, *name;
{
    register int i;

    for (i = 0; (*list)[i] != NULL; ++i)
	if (!strcmp((*list)[i], name))
	    return TRUE;

    *list = (char **)myrealloc(*list, sizeof(char *) * (i + 2));
    (*list)[i] = mymalloc(strlen(name)+1);
    strcpy((*list)[i], name);
    (*list)[i+1] = NULL;

    return FALSE;
}

/*
**
**free_list(list)
**char **list;
**{
**    register int i;
**
**    for (i = 0; list[i] != NULL; ++i)
**	free(list[i]);
**
**    free(list);
**}
*/

char *
puterr(error)
int error;
{
    static char qwerty[42];

    (void) sprintf(qwerty, "Unknown error %d", error);

    return ((unsigned)error >= sys_nerr) ? qwerty : sys_errlist[error];
}
SHAR_EOF
fi # end of overwriting check
if test -f 'huh.c'
then
	echo shar: will not over-write existing file "'huh.c'"
else
cat << \SHAR_EOF > 'huh.c'
/*
**  huh.c --
**		What was that last send?
**
**	Written by: Keith Gabryelski (ag@elgar.UUCP)
**
**		Released into public domain June 14, 1988.
**			Please keep this header.
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <errno.h>

extern errno;

extern FILE *fopen();
extern struct passwd *getpwuid(), *getpwnam();
extern char *sys_errlist[], *malloc(), *realloc();
extern int sys_nerr;

#undef TRUE
#undef FALSE
#define TRUE			1
#define FALSE			0

#define	SENDS_FILENAME		"/.sends"	/* must have the '/' */
#define MESSAGE_SEPARATOR	0x1F

char *puterr(), *mymalloc(), *myrealloc();
char *progname;

int sflag = FALSE;

char *
mymalloc(size)
unsigned size;
{
    char *p;

    if ((p = malloc(size)) == NULL)
    {
	(void) fprintf(stderr, "%s: Out of memory.\n", progname);
	exit(-1);
    }

    return p;
}

char *
myrealloc(p, size)
char *p;
unsigned size;
{
    if (p == NULL)
    {
	if ((p = malloc(size)) == NULL)
	{
	    (void) fprintf(stderr, "%s: Out of memory.\n", progname);
	    exit(-1);
	}
    }
    else if ((p = realloc(p, size)) == NULL)
    {
	(void) fprintf(stderr, "%s: Out of memory.\n", progname);
	exit(-1);
    }

    return p;
}

main(argc, argv)
int argc;
char **argv;
{
    char *ptr, *sends_filename = mymalloc(0);
    int amount = 1, n, c;
    long *seek_list = (long *)mymalloc(0);
    struct passwd *pt;
    FILE *fp;

    progname = *argv++;  --argc;

    if (**argv == '-')
	if (!strcmp(*argv, "-s"))
	{
	    sflag = TRUE;
	    *++argv; --argc;
	}
	else
	{
	    fprintf(stderr, "%s: invalid switch given.\n", progname);
	    usage();
	}

    if (argc > 2)
	usage();

    if (argc)
    {
	amount = atoi(*argv++);
	--argc;
    }

    if (amount < 1)
    {
	fprintf(stderr, "%s: invalid amount.\n", progname);
	usage();
    }

    if (argc)
    {
	if ((pt = getpwnam(*argv)) == (struct passwd *)NULL)
	{
	    fprintf(stderr, "%s: invalid user name '%s'.\n", progname, *argv);
	    exit(-1);
	}
    }
    else
	pt = getpwuid(getuid());

    if ((ptr = pt->pw_dir) == NULL)
    {
	fprintf(stderr, "%s: couldn't find a home directory.\n", progname);
	exit(-1);
    }

    sends_filename = myrealloc(sends_filename, strlen(ptr) +
			       sizeof(SENDS_FILENAME) + 1);

    strcpy(sends_filename, ptr);
    strcat(sends_filename, SENDS_FILENAME);

    if ((fp = fopen(sends_filename, "r")) == (FILE *)NULL)
    {
	if (errno == ENOENT)
	{
	    fprintf(stderr, "No sends.\n");
	    exit(0);
	}
	else
	{
	    fprintf(stderr, "%s: couldn't open sends file %s (%s).\n",
		    progname, sends_filename, puterr(errno));
	    exit(-1);
	}
    }

    /* setup null sent_to_list */

    seek_list = (long *)myrealloc(seek_list, sizeof(long));
    seek_list[0] = -1;

    do
    {
	n = add_to_list(&seek_list, ftell(fp));

	while((c = getc(fp)) != MESSAGE_SEPARATOR && c != EOF)
	    ;
    } while (c != EOF);

    if (n == 1)
	fprintf(stderr, "No sends.\n");
    else
    {
	if (n-1 < amount)
	    amount = 0;
	else
	    amount = n - amount - 1;

	fseek(fp, seek_list[amount], 0);

	do
	{
	    while ((c = getc(fp)) != MESSAGE_SEPARATOR && c != EOF)
		putchar(c);

	    if (sflag && c == MESSAGE_SEPARATOR)
		putchar(MESSAGE_SEPARATOR);
	} while (c != EOF);
    }
    
    fclose(fp);

    exit(0);
}

usage()
{
    fprintf(stderr, "%s: usage %s [-s] [amount] [username]\n", progname,
	    progname);
    exit(-1);
}

add_to_list(list, element)
long **list, element;
{
    register int i;

    for (i = 0; (*list)[i] != -1; ++i)
	;

    *list = (long *)myrealloc(*list, sizeof(long) * (i + 2));
    (*list)[i] = element;
    (*list)[i+1] = -1;

    return i+1;
}

char *
puterr(error)
int error;
{
    static char qwerty[42];

    (void) sprintf(qwerty, "Unknown error %d", error);

    return ((unsigned)error >= sys_nerr) ? qwerty : sys_errlist[error];
}
SHAR_EOF
fi # end of overwriting check
if test -f 'stom.c'
then
	echo shar: will not over-write existing file "'stom.c'"
else
cat << \SHAR_EOF > 'stom.c'
/*
**  stom.c --
**		Convert a .sends formatted message into a Unix mailbox
**		format.
**
**	Written by: Keith Gabryelski (ag@elgar.UUCP)
**
**		Released into public domain June 14, 1988.
**			Please keep this header.
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <errno.h>

extern errno;

extern FILE *fopen();
extern struct passwd *getpwuid(), *getpwnam();
extern char *sys_errlist[], *malloc(), *realloc();
extern int sys_nerr;

#undef TRUE
#undef FALSE
#define TRUE			1
#define FALSE			0

#define	SENDS_FILENAME		"/.sends"	/* must have the '/' */
#define MESSAGE_SEPARATOR	0x1F

char *puterr(), *mymalloc(), *myrealloc();
char *progname;

main(argc, argv)
int argc;
char **argv;
{
    FILE *fp;

    progname = *argv++; --argc;

    if (argc < 1)
	convert(stdin);
    else
	while (argc--)
	{
	    if ((fp = fopen(*argv, "r")) == NULL)
		fprintf(stderr, "%s: can't access file %s (%s).\n", progname,
			*argv, puterr(errno));
	    else
		convert(fp);

	    *++argv;
	}

    exit(0);
}

convert(stream)
FILE *stream;
{
    char text[20], user_name[10], date[28];
    char *dp;
    int c;

    while (fscanf(stream, "[%s from %s ", text, user_name) == 2)
    {
	/*
	** ignore tty.
	*/
	while ((c = getc(stream)) != ')')
	    ;

	/*
	** get date.
	*/

	dp = date;

	while ((c = getc(stream)) != ']')
	    *dp++ = c;

	*dp = '\0';

	printf("From %s%s\nSubject: A %s\n",  user_name, date, text);

	/*
	** And the message itself.
	*/
	while ((c = getc(stream)) != MESSAGE_SEPARATOR)
	    putchar(c);
    }
}

char *
puterr(error)
int error;
{
    static char qwerty[42];

    (void) sprintf(qwerty, "Unknown error %d", error);

    return ((unsigned)error >= sys_nerr) ? qwerty : sys_errlist[error];
}
SHAR_EOF
fi # end of overwriting check
if test ! -d 'doc'
then
	mkdir 'doc'
fi
cd 'doc'
if test -f 'send.C'
then
	echo shar: will not over-write existing file "'send.C'"
else
cat << \SHAR_EOF > 'send.C'
.TH SEND C
.SH NAME
send, fsend, fs, reply, freply, fr, shout \- send a message to one or more
users on the system.
.SH SYNOPSIS
.B send
user1[, user2][, user3][,... ][message]

.B fsend
user1[, user2][, user3][,... ][message]

.B fs
user1[, user2][, user3][,... ][message]

.B reply
[message]

.B freply
[message]

.B fr
[message]

.B shout
[message]
.SH DESCRIPTION

Send (and its counterparts) display messages on a specified user (or
users) terminal(s).

Send (and fsend) take a comma separated list of usernames (or tty
devices) to send the message to.  If a message is given on the command
line, it may be continued (via stdin) by putting a dash as the last
argument on the command line.  If no message is specified, stdin will
be used.

Reply will use the username of the last person to send you a message
as the recipient of the current message.

Fsend and freply use shorter headers to cutdown on message output.
They work exactly like their counterparts (send and reply) in all
other respects.

Shout will send a message to all users on the system.  Not for regular
use.

As a message is sent to user, it is also written to a save file called
".sends" in the recipients home directory.  This file must exist and should
be 622 mode for it to be updated correctly.  This file is typically
cleared on logout.

Fs and fr are finger savers for fsend and freply.
.SH FILES
~USERNAME/.sends	- Sends save file.
~/dead.send		- Save file for failed sends.
.SH SEE ALSO
huh(C), stom(C)
.SH AUTHOR
.RS
.PP
Keith M. Gabryelski (ag@elgar.UUCP)
.RE
SHAR_EOF
fi # end of overwriting check
if test -f 'huh.C'
then
	echo shar: will not over-write existing file "'huh.C'"
else
cat << \SHAR_EOF > 'huh.C'
.TH HUH C
.SH NAME
huh \- Display last send.
.SH SYNOPSIS
.B huh
[-s] [amount] [username]
.SH DESCRIPTION
Huh will display the last 
.B amount
(default; 1)
send message(s) from the user 
.B username
(default; your own) .sends file.

-s is used to format the output of huh(C) into something stom(C) can
use as input.
.SH FILES
~USERNAME/.sends	- Sends save file.
.SH SEE ALSO
send(C), stom(C)
.SH AUTHOR
.RS
.PP
Keith M. Gabryelski (ag@elgar.UUCP)
.RE
SHAR_EOF
fi # end of overwriting check
if test -f 'stom.C'
then
	echo shar: will not over-write existing file "'stom.C'"
else
cat << \SHAR_EOF > 'stom.C'
.TH STOM C
.SH NAME
stom \- convert a .sends formatted file to a unix mailbox format.
.SH SYNOPSIS
.B stom
[file1] [file2] [file3] [...]
.SH DESCRIPTION
Stom converts a .sends formatted file into a unix mailbox format.  If
no arguments are given stom will use stdin.

This is useful when used in conjuction with huh(C) to reply via mail
to a send.

.RS
huh -s | stom > mailbox
.PP
mail -f mailbox
.RE
.SH SEE ALSO
huh(C), send(C)
.SH AUTHOR
.RS
.PP
Keith M. Gabryelski (ag@elgar.UUCP)
.RE
SHAR_EOF
fi # end of overwriting check
cd ..
#	End of shell archive
exit 0
-- 
  "If green is all there is to be, then green is good enough for me" - ktf
[  Keith   ]  UUCP: {ucsd, cbosgd!crash, sdcsvax!crash, nosc!crash}!elgar!ag
[Gabryelski]  INET: ag@elgar.cts.com                ARPA: elgar!ag@ucsd.edu