DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T r

⟦c6474e1d1⟧ TextFile

    Length: 26395 (0x671b)
    Types: TextFile
    Names: »rmail.c«

Derivation

└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
    └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« 
        └─⟦e5a54fb17⟧ 
            └─⟦this⟧ »pp-5.0/Chans/uucp/rmail.c« 

TextFile

/* rmail.c: */ 

# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/uucp/RCS/rmail.c,v 5.0 90/09/20 15:55:26 pp Exp Locker: pp $";
# endif

/*
 * $Header: /cs/research/pp/hubris/pp-beta/Chans/uucp/RCS/rmail.c,v 5.0 90/09/20 15:55:26 pp Exp Locker: pp $
 *
 * $Log:	rmail.c,v $
 * Revision 5.0  90/09/20  15:55:26  pp
 * rcsforce : 5.0 public release
 * 
 */



/*
 *                              R M A I L . C
 *
 *      Developed from the Berkeley mail program of the same name
 *      by Mike Obrien at RAND to run with the MMDF mail system.
 *      Rewritten by Doug Kingston, US Army Ballistics Research Laboratory
 *      Hacked a lot by Steve Bellovin (smb@unc)
 *
 *      This program runs SETUID to Opr so that it can set effective and
 *      real [ug]ids to mmdflogin.
 *
 *      Steve Kille -  Aug 84
 *              Take machete to it.  Use protocol mode,
 *              and always go thru submit - phew
 *      Lee McLoughlin Oct 84.
 *              Address munges some header lines into 822 format.
 *	Peter Collinson Dec 85.
 *		Lee's version was dependent on
 *		 (a) the uucp channel
 *		 (b) the domain tables associated with the uucp channel
 *		This version costs more cycles (but there is generally
 *		only one of these running on a machine at a time) and
 *		uses mmdf's tables to dis-assemble bang routes converting
 *		them into a domain address.
 *	Peter Cowen Sept 89
 *		PP'ised
 *	Julian Onions July 90
 *		Choked to death on it!
 *	Piete Brooks June 90
 *		converted ! recipient addresses to % and @
 */
#undef  RUNALON

#include "util.h"
#include "head.h"
#include "q.h"
#include "prm.h"
#include "ap.h"
#include "adr.h"
#include "chan.h"
#include "retcode.h"
#include <pwd.h>
#include <signal.h>
#include <sys/stat.h>
#include <varargs.h>

#define VERSION "3.0"
#define NAMESZ  256		/* Limit on component name size.
				 * LMCL was 64 */
#define ungetline(s)	((void) strcpy (tmpline,s),usetmp=1)
#define MAXADRS 6		/* Max no. of adrs to output on a
				 * single line. */


char    debug;

extern char *loc_dom_site, *pplogin, *supportaddr, *hdr_822_bp, *ia5_bp, *cont_822;


extern char *index ();
extern char *rindex ();
extern char *getenv ();		/* get the Accounting system from
				 * the environment */
extern char *strdup ();
extern char *malloc ();
extern char *compress ();

FILE   *rm_msgf;		/* temporary out for message text */
CHAN   *chanptr;
int     Tmpmode = 0600;
char    Msgtmp[LINESIZE];
char    rm_date[LINESIZE];	/* date of origination from uucp
				 * header */
char    rm_from[LINESIZE];	/* accumulated path of sender */
char    origsys[NAMESZ];	/* originating system */
char    origpath[LINESIZE];	/* path from us to originating
				 * system */
char    Mailsys[LINESIZE];	/* Mail system signature */
char    tmpline[LINESIZE];	/* Temporary buffer for
				 * continuations and such */
char    usetmp = 0;		/* Wether tmpline should be used */
char    linebuf[LINESIZE];	/* scratchpad */
char    nextdoor[LINESIZE];	/* The site nextdoor who sent the
				 * mail */
char    uchan[LINESIZE];	/* Channel to use for submission */

main (argc, argv)
char  **argv;
int     argc;
{
	char    fromwhom[NAMESZ];	/* user on remote system */
	char   *fromptr;
	char    sys[NAMESZ];	/* an element in the uucp path */
	char   *cp, *d;
	struct passwd *pw, *getpwnam (), *getpwuid ();
	int     fd;

	sys_init (argv[0]);

	if (argc > 2 && strcmp (argv[1], "-d") == 0) {
		debug = 1;
		argc--;
		argv++;
	}

	if (argc < 2) {
		fprintf (stderr, "Usage: rmail user [user ...]\n");
		exit (1);
	}
	umask (0);

	/*
	 * First, change effective and real UID/GID into Mailsys
	 * owner
	 */
	if ((pw = getpwnam (pplogin)) == NULL) {
		fprintf (stderr, "Cannot find pplogin\n");
		exit (99);
	}
	setgid (pw->pw_gid);
	setuid (pw->pw_uid);

	(void) sprintf (Mailsys, "<%s@%s>", pplogin, loc_dom_site);

	/* Create temp file for body of message */
	(void) strcpy (Msgtmp, "/tmp/rmail.XXXXXX");
	mktemp (Msgtmp);
	if ((fd = creat (Msgtmp, Tmpmode)) < 0)
		bomb ("Can't create %s\n", Msgtmp);
	close (fd);

	if ((rm_msgf = fopen (Msgtmp, "r+")) == NULL)
		bomb ("Can't reopen %s\n", Msgtmp);

	unlink (Msgtmp);

	/*
	 * Unravell the From and >From lines at the head of the
	 * message to work who sent it, the path it took to get
	 * here and when it was sent. Some or all of this info may
	 * be ignore depending on the 822 header info given.
	 */
	for (;;) {
		if (fgets (linebuf, sizeof linebuf, stdin) == NULL)
			break;
		if (strncmp (linebuf, "From ", 5)
		    && strncmp (linebuf, ">From ", 6))
			break;

		cp = index (linebuf, ' ');	/* start of name */
		fromptr = ++cp;
		cp = index (cp, ' ');	/* cp at end of name */
		*cp++ = 0;	/* term. name, cp at date */
		(void) strcpy (fromwhom, fromptr);
		while (isspace (*cp))
			cp++;	/* Skip any ws */

		/*
		 * The date is the rest of the line ending at \0 or
		 * remote
		 */
		d = rm_date;
		while (*cp && strncmp (cp, " remote from ", 13))
			*d++ = *cp++;
		*d = '\0';

		for (;;) {
			cp = index (cp + 1, 'r');
			if (cp == NULL) {
				cp = rindex (fromwhom, '!');
				if (cp != NULL) {
					char   *p;

					*cp = '\0';
					p = rindex (fromwhom, '!');
					if (p != NULL)
						(void) strcpy (origsys, p + 1);
					else
						(void) strcpy (origsys, fromwhom);
					(void) strcat (rm_from, fromwhom);
					(void) strcat (rm_from, "!");
					(void) strcpy (fromwhom, cp + 1);
					goto out;
				}

				/*
				 * Nothing coherent found - so look
				 * in environment for ACCTSYS
				 */
				if ((cp = getenv ("ACCTSYS")) && *cp) {
					(void) strcpy (origsys, cp);
					(void) strcat (rm_from, cp);
					(void) strcat (rm_from, "!");
					goto out;
				}
				strcpy(cp = sys, "remote from somewhere");
			}
			if (strncmp (cp, "remote from ", 12) == 0)
				break;
		}

		sscanf (cp, "remote from %s", sys);
		(void) strcat (rm_from, sys);
		(void) strcpy (origsys, sys);	/* Save for quick ref. */
		(void) strcat (rm_from, "!");
out:		;
	}
	if (fromwhom[0] == '\0')/* No from line, illegal */
		bomb ("%s", "No 'from' lines in message\n");

	ungetline (linebuf);

	/* Complete the from field */
	(void) strcat (rm_from, fromwhom);

	/*
	 * A uk special - see if the first two components of the
	 * constructed bang address are in fact the same site.
	 * If so replace by their official name */
	domain_cross (rm_from);

	/*
	 * Save a copy of the path to the original site. This is
	 * all the the path we were given - the user name after the
	 * last !.  NOTE: We keep the trailing !, hence the +1.
	 */
	(void) strcpy (origpath, rm_from);
	*(rindex (origpath, '!') + 1) = '\0';

	/* Savepath is given a copy of the immediate neighbour */
	if ((d = index (rm_from, '!')) != NULL) {
		*d = '\0';
		(void) strcpy (nextdoor, rm_from);
		*d = '!';
	}
	else
		(void) strcpy (nextdoor, rm_from);

	/* find the channel depending in the nextdoor site */
	set_channel (nextdoor);

	/* Convert the from to Arpa format and leave it in from */
	fromcvt (rm_from, fromwhom);
	(void) strcpy (rm_from, fromwhom);

	if (debug)
		printf ("from=%s, origpath=%s, date=%s\n",
			rm_from, origpath, rm_date);

	msgfix (rm_from, rm_date);

	exit (xsubmit (rm_from, argv, argc));
}

/*
 * Munge the message header.
 * All header lines with addresses in are munged into 822 format.
 * If no "From:" line is given supply one based on the UUCP Froms, do the
 * same if no "Date:".
 */
typedef struct {
	char   *hname;
	int     hfound;
}       Hdrselect;

Hdrselect hdrselect[] = {
	"date", 0,		/* this is a little naughty - we
				 * need */
	/* to register that we have had this */
	/* but not address munge it */
	/* so it has token 0 */
	"from", 0,
	"to", 0,
	"cc", 0,
	"bcc", 0,
	"sender", 0,
	"reply-to", 0,
	"resent-from", 0,
	"resent-sender", 0,
	"resent-to", 0,
	0, 0

#define HDATE	0
#define HFROM	1
#define HTO	2
#define HCC	3
#define HBCC	4
#define HSENDER	5
#define HREPLY	6
#define HRFROM	7
#define HRSENDER	8
#define HRTO	9
};

/* Is this header in the list of those to have their addresses munged? */
/* return header value offset value */
/* notice that it returns 0 for the date header */
shouldmunge (name)
char   *name;
{
	register Hdrselect *h;

	if (debug)
		printf ("in shouldmunge with %s\n", name);

	for (h = hdrselect; h->hname != NULL; h++)
		if (!lexequ (h->hname, name)) {
			h->hfound++;
			return (h - hdrselect);
		}
	return (0);
}

/* If this is a header line then grab the name of the header and stuff it
 * into name then return a pointer to the actually body of the line.
 * Otherwise return NULL.
 * NOTE: A header is a line that begins with a word formed of alphanums and
 * dashes (-) then possibly some whitespace then a colon (:).
 */
char   *
        grabheader (s, name)
register char *s, *name;
{
	char    tmpbuf[LINESIZE];

	/* Copy the name into name */
	while (isalpha (*s) || isdigit (*s) || *s == '-')
		*name++ = *s++;
	*name = '\0';

	/* Skip any whitespace */
	while (isspace (*s))
		s++;

	/* This is a header if the next char is colon */
	if (*s == ':') {
		s++;

		/*
		 * This is probably illegal but we fail horribly if
		 * it happens - so we will guard against it
		 */
		if (*s != ' ' && *s != '\t' && *s != '\0') {	/* we need to add a
								 * space */
			(void) strcpy (tmpbuf, s);
			(void) sprintf (s, " %s", tmpbuf);
		}
		return (s);	/* Return a pointer to the rest of
				 * the line */
	}
	else
		return (NULL);
}

msgfix (from, date)
char   *from, *date;
{
	register char *s;
	char   *rest;
	char   *lkp;
	char    name[LINESIZE];
	char    tmpbuf[LINESIZE];
	int     haveheader = 0;	/* Do I have a header? */
	int     headertoken;
	char   *grabline ();

	/* Loop through all the headers */
	while (1) {
		if (debug)
			printf ("in msgfix about to grabline\n");

		s = grabline ();

		if (debug)
			printf ("got %s", s);

		/* Is this the end of the header? */
		if (*s == '\0' || *s == '\n' || feof (stdin))
			break;


		/* Is this a continuation line? */
		if (haveheader && isspace (*s)) {

			/*
			 * Note: Address munged headers handled
			 * specially
			 */
			fputs (s, rm_msgf);
		}
		else {

			/* Grab the header name from the line */
			if ((rest = grabheader (s, name)) == NULL)

				/*
				 * Not a header therefore all
				 * headers done
				 */
				break;

			haveheader = 1;

			/* Should I address munge this? */
			if (headertoken = shouldmunge (name)) {
				char   *finalstr;

				finalstr = "\n";
				fprintf (rm_msgf, "%s: ", name);

				/*
				 * deal specially with From lines
				 * the parser loses comments so we
				 * retain them specially here
				 */
				if (headertoken == HFROM
				    || headertoken == HRFROM) {
					if (lkp = index (rest, '<')) {
						*lkp = '\0';
						if (*rest == ' ')
							fprintf (rm_msgf, "%s<", rest + 1);
						else
							fprintf (rm_msgf, "%s<", rest);
						*lkp = '<';
						finalstr = ">\n";
						(void) strcpy (tmpbuf, lkp);

						/*
						 * notice that we
						 * copy from the < *
						 * /* to start with
						 * a space
						 */
						tmpbuf[0] = ' ';
						rest = tmpbuf;
						lkp = rindex (rest, '>');
						if (lkp)
							*lkp = '\0';

					}
					if (lkp = index (rest, '(')) {
						*lkp = '\0';
						(void) sprintf (tmpbuf, " (%s\n", lkp + 1);
						finalstr = tmpbuf;
					}
				}
				hadr_munge (rest);
				fputs (finalstr, rm_msgf);
			}
			else
				fputs (s, rm_msgf);
		}
	}

	/* No From: line was given, create one based on the From's */
	if (hdrselect[HFROM].hfound == 0) {
		fprintf (rm_msgf, "From: %s", from);
	}

	/* No Date: line was given, create one based on the From's */
	if (hdrselect[HDATE].hfound == 0) {
		datecvt (date, tmpbuf);	/* Convert from uucp ->
					 * Arpa */
		fprintf (rm_msgf, "Date: %s\n", tmpbuf);
	}

	/* Copy the rest of the file, if there is any more */
	if (!feof (stdin)) {

		/*
		 * If the first line of the message isn't blank
		 * output the blank separator line.
		 */
		if (*s)
			putc ('\n', rm_msgf);
		do {
			fputs (s, rm_msgf);
			s = grabline ();
		} while (!feof (stdin));
	}
}

char   *
        grabline ()
{
	if (debug)
		printf ("in grabline ");

	/*
	 * Grab the next line. Remembering this might be the
	 * tmpline
	 */
	if (usetmp) {
		if (debug)
			printf ("using tmpline ");
		(void) strcpy (linebuf, tmpline);
		usetmp = 0;
	}
	else
		fgets (linebuf, sizeof linebuf, stdin);

	/* Anything wrong? */
	if (ferror (stdin))
		fputs ("\n  *** Problem during receipt from UUCP ***\n", rm_msgf);

	if (debug)
		printf ("returning %s\n ", linebuf);

	return (linebuf);

}

char   *next = NULL;		/* Where nextchar gets the next
				 * char from */
char    adrs[LINESIZE];		/* Partly munged addresses go here */

nextchar ()
{
	register char *s;	/* scratch pointer. */

	if (next != NULL && *next != '\0') {
		if (debug)
			printf ("<%c>", *next);
		return (*next++);
	}

	/* The last buffer is now empty, fill 'er up */
	next = grabline ();

	if (feof (stdin) || !isspace (*next) || *next == '\0') {

		/*
		 * Yipee! We've reached the end of the address
		 * list.
		 */
		ungetline (next);
		next = NULL;	/* Force it to read buffer */
		return (-1);
	}

	/* Zap excess whitespace */
	compress (next, adrs);

	/*
	 * This may be a slightly duff list generated by some of
	 * the UNIX mailers eg: "x y z" rather than "x,y,z" If it
	 * is in this ^^^^^^^ convert to  ^^^^^^^ NOTE: This won't
	 * handle list: "x<x@y> y<y@z>" conversions!
	 */
	if (index (adrs, ' ') != NULL &&
	    index (adrs, ',') == NULL &&
	    index (adrs, '<') == NULL &&
	    index (adrs, '(') == NULL &&
	    index (adrs, '"') == NULL) {
		for (s = adrs; *s; s++)
			if (*s == ' ')
				*s = ',';
	}
	next = adrs;

	/*
	 * This a continuation line so return in a seperator just
	 * in case
	 */
	return (',');
}


/* Munge and address list thats part of a header line.
 * Try and get the ap_* (MMDF) routines to do as much as possible for
 * us.
 */
hadr_munge (list)
char   *list;
{
	AP_ptr  the_addr;	/* ---> THE ADDRESS <--- */
	int     adrsout = 0;	/* How many address have been
				 * output */

	ungetline (list);

	while (1) {
		AP_ptr  ap_pinit ();

		the_addr = ap_pinit (nextchar);

		if (the_addr == (AP_ptr) NOTOK)
			bomb ("%s", "cannot initialise address parser!");

		ap_clear ();

		switch (ap_1adr ()) {
		    case NOTOK:
			/* Something went wrong!! */
			ap_sqdelete (the_addr, (AP_ptr) 0);
			ap_free (the_addr);

			/*
			 * Emergency action in case of parser break
			 * down: print out the rest of the line (I
			 * hope).
			 */
			fprintf (rm_msgf, "%s", tmpline);
			continue;
		    case OK:
			/* I've got an address to output! */

			/*
			 * output a comma seperator between the
			 * addresses and a newline every once in a
			 * while to make sure the lines aren't too
			 * long
			 */
			if (adrsout++)
				fprintf (rm_msgf, ",%s ", adrsout % MAXADRS ? "" : "\n");

			/* Munge will do all the work to output it */
			munge (the_addr);

			/* Reclaim the space */
			ap_sqdelete (the_addr, (AP_ptr) 0);
			ap_free (the_addr);

			if (debug)
				printf ("munged and space freed\n");
			break;
		    case DONE:
			if (debug)
				printf ("hadr_munge all done\n");

			/* Reclaim the space */
			ap_sqdelete (the_addr, (AP_ptr) 0);
			ap_free (the_addr);

			return;

		}
	}
}

/* We now have a single address in the_addr to output.
 */
munge (the_addr)
AP_ptr  the_addr;
{
	char    adr[LINESIZE];
	char   *s, *frees;
	AP_ptr  local, domain, route;

	if (debug)
		printf ("in munge with: ");

	/* Find where the important bits begin in the tree */
	ap_t2p (the_addr, (AP_ptr *) 0, (AP_ptr *) 0,
		&local, &domain, &route);

	/* Convert from the tree back into a string */
	frees = s = ap_p2s_nc ((AP_ptr) 0, (AP_ptr) 0, local, domain, route);

	if (debug)
		printf ("%s\n", s);

	/* Is it a uucp style address? */
	if (domain == (AP_ptr) 0 && index (s, '!') != (char *) 0) {
		char    adr2[LINESIZE];

		(void) strcpy (adr, s);

		/*
		 * Stick the path it took to get here at the start.
		 * But try to avoid any duplicates by overlapping
		 * the matching parts of the address. Eg: adr =
		 * 'x!y!z'  path = 'a!b!x!y!' adr2 = 'a!b!x!y!z'
		 */
		for (s = origpath; *s; s++) {
			/* Does it match? */
			if (strncmp (adr, s, strlen (s)) == 0) {
				char    c = *s;

				*s = '\0';
				(void) strcpy (adr2, origpath);
				(void) strcat (adr2, adr);
				*s = c;
				break;
			}
		}

		/*
		 * Did I just scan the whole path without finding a
		 * match!
		 */
		if (*s == '\0') {
			/* Append the adr to the path */
			(void) strcpy (adr2, origpath);
			(void) strcat (adr2, adr);
		}

		/*
		 * Munge the address into its shortest form and
		 * print it
		 */
		fromcvt (adr2, adr);
		fprintf (rm_msgf, "%s", adr);

		if (debug)
			printf ("uucp munge gives %s\n", adr);
	}
	else {
		char   *p;
		char   *at;
		char   *official = NULL;
		char   *fmt;
		char   *brace;
		AP_ptr  norm;
		extern int ap_outtype;

		/* Normalise the address */
		ap_outtype = AP_PARSE_733;	/* Hmm. Maybe should be
						 * from channel */
		norm = ap_normalize (the_addr, CH_USA_PREF);

		/* Convert it back in to a string and output it */
		ap_t2s (norm, &p);
		if (debug)
			printf ("Normalised address: %s\n", p);

		/*
		 * Look for the last address component and re-write
		 * to the
		 */

		/*
		 * official form. There are probably better ways of
		 * doing this
		 */
		at = rindex (p, '@');
		fmt = "%s";
		if (at) {
			brace = index (at + 1, '>');
			if (brace)
				*brace = '\0';
			official = strdup (at + 1);
			if (official) {
				*at = '\0';
				fmt = brace ? "%s@%s>" : "%s@%s";
			}
			else if (brace)
				*brace = '>';
		}
		fprintf (rm_msgf, fmt, p, official);

		if (debug) {
			printf ("arpa munge gives ");
			printf (fmt, p, official);
			printf ("\n");
		}

		free (p);
	}
	free (frees);
}



/*
 *      datecvt()  --  convert UNIX ctime() style date to ARPA style
 *                      (change done in place)
 */
datecvt (date, newdate)
char   *date;
char   *newdate;
{

	/*
	 * LMCL: Changed the default timezone, when none given.
	 */

	if (isdigit (date[0]) || date[3] == ',' || isdigit (date[5]))
		(void) strcpy (newdate, date); /* Probably already ARPA */
	else if (isdigit (date[20]))
		(void) sprintf (newdate,
				"%.3s, %.2s %.3s %.2s %.2s:%.2s:%.2s GMT",
				date, date + 8, date + 4, date + 22,
				date + 11, date + 14, date + 17);
	else if (isalpha (date[17])) /* LMCL. Bum Unix format */
		(void) sprintf (newdate,
				"%.3s, %.2s %.3s %.2s %.2s:%.2s:00 GMT",
				date, date + 8, date + 4, date + 23,
				date + 11, date + 14);
	else
		(void) sprintf (newdate,
				"%.3s, %.2s %.3s %.2s %.2s:%.2s:%.2s %.3s",
				date, date + 8, date + 4, date + 26,
				date + 11, date + 14, date + 17, date + 20);
}


msg_failure (addr, rp, reason)
char   *addr;
RP_Buf *rp;
char   *reason;
{
	extern char	*postmaster;
	char    buf[BUFSIZ];

	if (rp)
		(void) sprintf (buf, "%s: %s [%s]",
				reason, rp->rp_line,
				rp_valstr ((int)rp->rp_val));
	else
		(void) sprintf (buf, "%s", reason);

	PP_LOG (LLOG_EXCEPTIONS, ("Message failure: %s", buf));

	return msg_return (postmaster, addr, buf);
}


msg_return (addr, dest, reason)
char   *addr, *dest, *reason;
{
	RP_Buf  rp;

	io_end (NOTOK);

	if (rp_isbad (pps_1adr ("UUCP (rmail) Failed Message", addr, &rp)))
		bomb ("pps_1adr failed [%s]", rp.rp_line);
	if (rp_isbad (pps_txt ("Your message was not delivered to:\n    ", &rp)))
		bomb ("pps_txt failed [%s]", rp.rp_line);
	if (rp_isbad (pps_txt (dest, &rp)))
		bomb ("pps_txt failed [%s]", rp.rp_line);
	if (rp_isbad (pps_txt ("\nFor the following reason:\n    ", &rp)))
		bomb ("pps_txt failed [%s]", rp.rp_line);
	if (rp_isbad (pps_txt (reason, &rp)))
		bomb ("pps_txt failed [%s]", rp.rp_line);
	if (rp_isbad (pps_txt ("\n\n--------------- Returned Mail ---------------\n\n", &rp)))
		bomb ("pps_txt failed [%s]", rp.rp_line);
	rewind (rm_msgf);
	if (rp_isbad (pps_file (rm_msgf, &rp)))
		bomb ("pps_file failed [%s]", rp.rp_line);

	if (rp_isbad (pps_txt ("--------------- End of Returned Mail -------------\n", &rp)))
		bomb ("pps_txt failed [%s]", rp.rp_line);
	if (rp_isbad (pps_end (OK, &rp)))
		bomb ("pps_end failed [%s]", rp.rp_line);
	return 0;
}

/* \f

 */

static char *
pling2norm(to, from)
char *to;
char *from;
{
	char temp[1024];
	char *pling;
	strcpy(temp, from);

	*to = '\0';
	while (pling = rindex(temp, '!'))
	{	*(pling++) = '\0';
		if (*to) strcat(to, "%");
		strcat(to, pling);
	}
	if (*to) strcat(to, "%");
	strcat(to, temp);
	if (pling = rindex(to, '%')) *pling = '@';
	if (debug) printf("%s -> %s\n", from, to);
	return to;
}
/* \f

 */

xsubmit (from, argv, argc)
char   *from;
char  **argv;
int     argc;
{
	char    buf[LINESIZE];
	RP_Buf  rp;
	struct prm_vars prm;
	LIST_BPT *new;
	ADDR   *orig = NULL;
	Q_struct que;
	char   *name = NULL;
	int     i;
	int     first_bp = TRUE;

	prm_init (&prm);
	q_init (&que);
	/* inbound channel, inbound host, contenttype */

	prm.prm_opts = PRM_ACCEPTALL;
	que.msgtype = MT_UMPDU;
	que.encodedinfo.eit_types = NULLIST_BPT;
	new = list_bpt_new (hdr_822_bp);
	list_bpt_add (&que.encodedinfo.eit_types, new);
	new = list_bpt_new (ia5_bp);
	list_bpt_add (&que.encodedinfo.eit_types, new);

	que.inbound = list_rchan_new (origsys, chanptr->ch_name);

	rewind (rm_msgf);

	if (debug) {
		char buff[1024];

		for (argv++; --argc > 0; argv++)
			printf ("arg = %s (%s)\n",
				pling2norm(buff, *argv), *argv);
		while (fgets (buf, LINESIZE - 1, rm_msgf) != NULL)
			printf ("T=%s", buf);
		if (ferror (rm_msgf))
			bomb ("%s", "Error reading messge file");

		exit (0);
	}

	if (rp_isbad (io_init (&rp)))
		return msg_failure (from, &rp, "io_init failed");

	if (rp_isbad (io_wprm (&prm, &rp)))
		return msg_failure (from, &rp, "io_wprm failed");
	if (rp_isbad (io_wrq (&que, &rp)))
		return msg_failure (from, &rp, "io_wrq failed");

	orig = adr_new (from, AD_822_TYPE, 0);
	if (rp_isbad (io_wadr (orig, AD_ORIGINATOR, &rp)))
		return msg_failure (from, &rp,
				    "Sender address unacceptable");

	adr_free (orig);

	for (i = 1; i < argc; i++) {
		ADDR   *adr;
		char buff[1024];

		name = pling2norm(buff, argv[i]);
		adr = adr_new (name, AD_822_TYPE, i);
		if (rp_isbad (io_wadr (adr, AD_RECIPIENT, &rp)))
			return msg_failure (name, &rp,
					 "Recipient address bad");
		adr_free (adr);
	}

	if (rp_isbad (io_adend (&rp)))
		return msg_failure (name, &rp, "Address end failed");

	if (rp_isbad (io_tinit (&rp)))
		return msg_failure (name, &rp, "body initialisation failed");
	if (rp_isbad (io_tpart (hdr_822_bp, FALSE, &rp)))
		return msg_failure (name, &rp,
				    "822 header initialisation failed");

	rewind (rm_msgf);
	first_bp = TRUE;
	while (fgets (buf, LINESIZE - 1, rm_msgf) != NULL) {
		if (first_bp == TRUE
		    && buf[0] == '\n') {
			first_bp = FALSE;
			if (rp_isbad (io_tdend (&rp)))
				msg_failure (name, &rp,
					     "header end failed");
			if (rp_isbad (io_tpart ("1.ia5", FALSE, &rp)))
				msg_failure (name, &rp,
				    "body initialisation failed");
		}

		if (rp_isbad (io_tdata (buf, strlen (buf))))
			msg_failure (name, (RP_Buf *)0, "data copied failed");
	}
	if (ferror (rm_msgf))
		msg_failure (name, (RP_Buf *)0, "Data copy failed");

	if (rp_isbad (io_tdend (&rp)))
		msg_failure (name, &rp, "Text termination problem");

	if (rp_isbad (io_tend (&rp)))
		msg_failure (name, &rp, "Termination problem");
	(void) io_end (OK);
	return 0;
}


/*VARARGS1*/
#ifdef lint
bomb (fmt)
char   *fmt;
{
	return bomb (fmt);
}

#else
bomb (va_alist)
va_dcl
{
	va_list ap;
	char    buf[BUFSIZ];

	va_start (ap);

	_asprintf (buf, NULLCP, ap);
	PP_LOG (LLOG_EXCEPTIONS, ("uucp bombing: %s", buf));
	va_end (ap);

	exit (99);
}
#endif

/*
 *      fromcvt()  --  trys to convert the UUCP style path into
 *                      an ARPA style name.
 */
fromcvt (from, newfrom)
char   *from, *newfrom;
{
	register char *cp;
	register char *sp;
	register char *off;
	char   *at;
	char   *atoff;
	char    buf[LINESIZE];

	if (debug)
		printf ("fromcvt on %s\n", from);

	(void) strcpy (buf, from);
	cp = rindex (buf, '!');
	if (cp == 0) {
		(void) strcpy (newfrom, from);
		return;
	}

	/*
	 * look for @site at the end of the name
	 */
	atoff = NULL;
	if ((at = index (cp, '@')) != NULL) {
		/* got one - is it followed by a ! ? */
		if (index (at + 1, '!') != NULL)
			at = NULL;
		else {
			/* look up the official name of the at site */
			atoff = strdup (at + 1);
		}
	}
	*cp = 0;
	while (sp = rindex (buf, '!')) {

		/*
		 * scan the path backwards looking for hosts that
		 * we know about
		 */
		if (off = strdup (sp + 1)) {
			if (atoff && !lexequ (atoff, off))
				(void) strcpy (newfrom, cp + 1);
			else
				(void) sprintf (newfrom, "%s@%s", cp + 1, off);
			return;
		}
		else if (at && !lexequ (at + 1, sp + 1)) {
			(void) strcpy (newfrom, cp + 1);
			return;
		}
		*cp = '!';
		cp = sp;
		*cp = 0;
	}
	if (off = strdup (buf))
		(void) sprintf (newfrom, "%s@%s", cp + 1, off);
	else
		(void) sprintf (newfrom, "%s@%s", cp + 1, buf);
}

/*
 *	This piece added by Peter Collinson (UKC)
 *	rather than just making rmail submit into the uucp channel which
 *	is hard coded. First look up in a table 'rmail.chans' for entries
 *	of the form
 *	nextdoor:channel
 *	If the name exists then use that channel otherwise just default to
 *	the uucp channel. This is for authorisation purposes really
 */
extern char *uucpin_chan;

set_channel (nxt)
char   *nxt;
{
	if ((chanptr = ch_nm2struct (uucpin_chan)) == NULLCHAN)
		bomb ("Cannot look up channel '%s'\n", uucpin_chan);
}

/*
 *	Check if the from machine which we have constructed actually
 *	contains two references to the same machine of the form
 *	site.uucp!site.??.uk!something
 *	if so replace by the single official name
 */
domain_cross (route)
char   *route;
{
	char   *second;
	char   *endsecond;
	char   *official;
	char   *host_equal ();

	second = index (route, '!');
	if (second == (char *) 0)
		return;
	second++;
	endsecond = index (second, '!');
	if (endsecond == (char *) 0)
		return;
	second[-1] = '\0';
	*endsecond = '\0';
	if (official = host_equal (route, second)) {
		(void) strcpy (route, official);
		*endsecond = '!';
		(void) strcat (route, endsecond);
	}
	else {
		second[-1] = '!';
		*endsecond = '!';
	}
}

/*
 *	host_equal
 *	a routine to see whether the strings which are input
 *	are in fact the same host
 *	Returns the official name if they are and a null pointer if not
 */
char   *
        host_equal (n1, n2)
char   *n1, *n2;
{
	if (lexequ (n1, n2) == 0)
		return n1;
	return NULLCP;
}