Subject:  News/mail gateway package, Part03/04
Newsgroups: alt.sources

Archive-name: newsgate2beta/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  gag.1 gate.h hdr.c lex.l news2mail.1 regex.3 sysexits.h
# Wrapped by rsalz@litchi.bbn.com on Fri Feb 28 11:14:01 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 3 (of 4)."'
if test -f 'gag.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'gag.1'\"
else
  echo shar: Extracting \"'gag.1'\" \(9099 characters\)
  sed "s/^X//" >'gag.1' <<'END_OF_FILE'
X.\" $Header: /nfs/papaya/u2/rsalz/src/newsgate/RCS/gag.1,v 1.6 91/04/01 09:43:50 rsalz Exp Locker: rsalz $
X.TH GAG 1 LOCAL
X.SH NAME
Xgag \- Gateway alias generator
X.SH SYNOPSIS
X.in +.5i
X.na
X.ti -.5i
X.B gag
X[
X.B \-a
X] [
X.BI \-b bbn_file
X] [
X.BI \-c cnews_file
X] [
X.BI \-i innnews_file
X] [
X.BI \-n bnews_file
X] [
X.BI \-d mmdf_dir
X] [
X.BI \-s sendmail_file
X] [
X.BI \-t PP_shell
X] [
X.BI \-u PP_user
X] [
X.B \-b
X] [
X.B \-p
X] [
X.I file
X]
X.ad
X.in -.5i
X.SH DESCRIPTION
X.I Gag
Xreads a control file and builds entries for
X.IR sendmail (8),
X.IR BBN ,
X.IR MMDF (8),
Xand
X.IR PP (8)
Xalias files, as well as
X.IR Netnews (1)
Xsys file entries.
XIt is an auxiliary program for helping to maintain a mail/news
Xgateway operation.
XA typical
X.I gag
Xfile sets up default values for all the parameters, then contains a list
Xof newsgroup\-mailing list pairs.
XGroup-specific values can override the defaults.
X.PP
X.I Gag
Xinput is fairly free-form.
XIt ignores C-style comments, and whitespace is allowed anywhere.
XThere are a couple of dozen keywords, and case is significant; most
Xof the keywords are parameters used to control the gatewaying.
XQuoted strings are written as they are in C, except they may not
Xspan lines.
X.PP
XUsing the parameters enumerated below,
X.I gag
Xcan write six different sets of alias files:
X.RS
X.ta \w'InterNetNews  'u
X.nf
XBBN	if the ``\-b'' flag is used
XMMDF	if the ``\-m'' flag is used
XB News	if the ``\-n'' flag is used
XC News	if the ``\-c'' flag is used
XInterNetNews	if the ``\-i'' flag is used
XSendmail	if the ``\-s'' flag is used
XPP shell	If the ``\-t'' flag is used
XPP user	if the ``\-u'' flag is used
X.fi
X.RE
XAny combination of these flags is allowed.
X.I Gag
Xdoes not edit any existing files; all output blindly overwrites the
Xspecified output files.
XThe intent is that you review the output, then manually update the
Xproduction versions.
XDoing something like ``gag \-n /usr/lib/news/sys'' is a sure recipe for
Xdisaster!
XDo something like this, instead:
X.RS
X.nf
X    sed '/--START-OF-GATEWAY-OUTPUT-/,/--END-OF-GATEWAY-OUTPUT-/d' \e
X	</usr/lib/news/sys >/tmp/sys
X    gag -n - <gag.data >>/tmp/sys
X    mv /tmp/sys /usr/lib/news/sys
X.fi
X.RE
X.PP
X.I Gag
Xnormally complains about attempts to gateway groups that are not in
Xthe news active file; use the ``\-a'' suppresses this check, assuming
Xthat all named groups are valid.
X.PP
XBBN-style
Xaliases can't pipe into a command with parameters.
XFor example,
X.I sendmail
Xcan have an entry like this in
X.IR /usr/lib/aliases (5):
X.RS
X.ta \w'post-bboard:  'u
X.nf
Xpost-bboard:	"|/usr/lib/news/mail2news -n bbn.bboard \e
X	-o 'BBN News/Mail Gateway' \e
X	-d bbn"
X.fi
X.RE
XWith BBN, it is necessary to create an alias that feeds into a custom script:
X.RS
X.ta \w'bboard-gate:  'u
X.nf
Xbboard-gate:	@mailer.bbn.com { "news|/usr/lib/news/.admin/gate-bboard" }
X	bboard-gate@mailer.bbn.com
X.fi
X.RE
X.I Gag
Xwill also create the utility script invoked by the above alias:
X.RS
X.ta \w'exec 'u
X.nf
X#! /bin/sh
X##  This script is on the "bboard" mailing list.
Xexec /usr/lib/news/mail2news -n bbn.bboard \e
X	-o "BBN News/Mail Gateway" \e
X	-d bbn
X.fi
X.RE
XTo create these scripts, use the ``\-d'' flag to name the directory where
Xthey should be created; ``\-d .'' will create them in the current directory.
X.PP
X.I MMDF
Xaliases are similar to
X.IR sendmail 's,
Xexcept that the the scripts are run under a specified user id
X(see below).
X.PP
X.I PP
Xuses two files, a shell and user file, whose format is not described here.
X.PP
XSome sites want to create mail aliases that forward into each newsgroup;
Xthat is, mail sent to ``comp-foo-bar'' should get posted to the ``comp.foo.bar''
Xnewsgroup.
XIf the ``\-p'' flag is used, then each gatewayed group will get such an
Xalias created.
XThe
X.IR mkmailpost (1L)
Xcommand can be used to create
X.I gag
X``mailpost'' commands for all entries in the news active file.
XNote that using
X.I mkmailpost
Xand the ``\-p'' flag will almost certainly result in the creation of duplicate
Xaliases.
X.PP
XThe parameters that control the gatewaying are:
X.IP directory
XThe directory where the BBN alias scripts are kept.
X(In the above example, the directory is
X.IR /usr/lib/news/.admin .)
X.IP distributions
XA space-separated list of distributions to forward from news to mail.
XIn most cases, this will be the full set of distributions received, but
Xit can be convenient, for example, to not forward regional articles out
Xto a world-wide mailing list.
XWith distributions set to ``world usa na'' then the news sys entry
Xfor ``comp.foo'' will have this in the second field:
X.in +.5i
X.nf
X<site>:\e
X  world,!world.all,usa,!usa.all,na,!na.all,comp.foo,!comp.foo.all\e
X  <rest of entry>
X.in -.5i
X.fi
X.IP "inews flags"
XThese are flags to pass on to
X.IR inews (8)
Xwhen gatewaying a mail message into netnews.
XThey are put on the
X.I news2mail (1)
Xcommand line, which will pass them along.
XA common use is to set a default distribution or organization.
X.IP mail2news
XThe full pathname of the
X.I mail2news
Xprogram.
X.IP mailcontact
XThis is the name of the person listed in the ``For more information, contact''
Xpart of the header generated by
X.IR news2mail .
X.IP mailhost
XWhen remote mailing lists are gatewayed into local newsgroups, it can
Xoften be convenient to provide a local alias that forwards on to the
Xremote host.
XFor example, if the list ``info-foo'' is maintained at ``vax.host.edu''
Xthen it is possible to create a local alias that just forwards to
X``info-foo@vax.host.edu.''
X.IP "mailinglist"
XIf set to ``true,'' then
X.I gag
Xwill write aliases that forward on to the list at the current mailhost; if
Xset to ``false'' than no such aliases will be written.
X.IP moderator
XIf set, then the value is put on the
X.I mail2news
Xcommand line with the ``\-a'' flag.
XThis is useful for making a semi-moderated one-way gateway.
X.IP news2mail
XThe full pathname of the
X.I news2mail
Xprogram.
X.IP organization
XIf set, then the value is put on the
X.I mail2news
Xcommand line with the ``\-o'' flag.
X.IP owner
XIf set, then all
X.I sendmail
Xaliases also have an ``owner\-'' version, with this value as the
Xrecipient, to receive trouble reports.
X.IP requestaddr
XMost mailing lists have a ``\-request'' address to handle list administration.
XWhen gatewaying the list ``info-foo'' if the maintenance address isn't
X``info-foo-request'' set this parameter to the proper address.
X.IP site
XThis is the name of the site to use in the news sys file; ``gateway'' is
Xa common choice.
X.IP user
XWhen running scripts under
X.I MMDF
X(either normal or with the BBN style)
Xa userid to setuid to must be given.
X.PP
XNote that there is some overlap in these parameters.
XIn particular the ``moderator'' and ``organization'' parameters can really
Xbe subsumed by the ``inews flags'' parameter.
XThey are explicitly called out, however, for convenience in specifying
Xthe types of gatewaying.
XFor example, while all gatewayed groups might go out with the same
Xdistribution, only some might need an
X.I Approved:
Xheader line.
X.SH "THE LANGUAGE"
XA
X.I gag
Xfile is composed of intermixed parts of three different constructs:
Xdefaults, mail/news posting entries, mail/news gateway entries.
X.PP
XIndividual groups can override the default parameters.
XThe defaults can be changed at any time, and retain the new value for
Xthe rest of the file or until changed again.
XFor example, most mail aliases will be ``owned'' by
X.IR postmaster ,
Xbut it might be convenient to set the forwarding address on specific
Xaliases to someone else.
XFor example:
X.RS
X.DT
X.nf
X/* Send gateway complaints to postmaster */
Xdefault owner = "postmaster";
X
X/* The "animals" list is privately maintained. */
Xgateway bbn.animals animal-rights
X	owner = "canus-major";
X.fi
X.RE
XThe syntax is explained in more detail, below.
X.PP
XA default parameter assignment looks like one of the following:
X.RS
X.DT
X.nf
X\fBdefault\fP <parameter> \fB= true ;\fP
X\fBdefault\fP <parameter> \fB= false ;\fP
X\fBdefault\fP <parameter> \fB=\fP "string value" \fB;\fP
X\fBdefault\fP <parameter> \fB= dotify (\fP "value" \fB) ;\fP
X.fi
X.RE
XThe last form is used to translate mixed-case strings into the prefix-period
Xform used by
X.IR mail2news .
X.PP
XA gateway declaration looks like this:
X.RS
X.DT
X.nf
X\fBgateway\fP <newsgroup> <mailinglist>
X	[ parameter settings ] \fB;\fP
X.fi
X.RE
XThe parameter settings are like the default settings shown above, except
Xthat the word ``default'' is left off, as are all semicolons but the
Xlast one.
X.PP
XTo set up a simple unidirectional newsgroup/mailing list gateway, use a
X``mailpost'' declaration:
X.RS
X.DT
X.nf
X\fBmailpost\fP <newsgroup> \fB;\fP
X.fi
X.RE
X.SH "BUGS AND CAVEATS"
X.I Gag
Xdoesn't free most of the memory that it allocates; in essence, the entire
Xinput must fit into the process space.
X.PP
XIn generating news
X.I sys
Xfile entries, remember that the command is a
X.IR sprintf (3)
Xformat string, and any percent signs
X.RI ( % )
Xmust be doubled or they will be taken as a formatting control.
X.SH "SEE ALSO"
Xmail2news(1L), mkmailpost(1L), news2mail(1L).
X.SH AUTHORS
XRich $alz <rsalz@bbn.com>, replacing some
X.I m4
Xscripts that
X.br
XErik E. Fair <fair@apple.com> wrote.
X.br
XPiete Brooks <pb@computer-lab.cambridge.ac.uk> provided the PP support.
END_OF_FILE
  if test 9099 -ne `wc -c <'gag.1'`; then
    echo shar: \"'gag.1'\" unpacked with wrong size!
  fi
  # end of 'gag.1'
fi
if test -f 'gate.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'gate.h'\"
else
  echo shar: Extracting \"'gate.h'\" \(8202 characters\)
  sed "s/^X//" >'gate.h' <<'END_OF_FILE'
X/*
X**  HEADER FILE FOR NEWS/MAIL GATEWAY CODE.
X**  $Header: /nfs/papaya/u2/rsalz/src/newsgate/RCS/gate.h,v 1.19 91/07/18 21:14:18 rsalz Exp Locker: rsalz $
X*/
X/* SUPPRESS 460 *//* '/' '*' occurred inside a comment */
X
X
X/*
X**  START OF CONFIGURATION SECTION
X*/
X
X
X/* Paths to some parts of your netnews installation.  Required.
X * If you set INEWS to point to a C News relaynews, then set NO_H_FLAG. */
X#define INEWS		"/usr/lib/news/inews"
X#define ACTIVE		"/usr/lib/news/active"
X#define NGDELIM		','
X
X/* If you #define this, then the -h flag will not be appended and the -=
X * flag will not delete it. */
X#undef NO_H_FLAG
X
X/* In writing Paths into From addresses, we can look at the output
X * of uuname from the L.sys file.  Define both or neither of the next
X * two.  We can also map some UUCP names to their domain names, if
X * the third line is enabled.  The UUCP_INET should match the value
X * in the Makefile.  This violates the "write once" rule, but it's
X * too much of a pain to fix for this one symbol. */
X#define UUNAME		"/usr/lib/news/.admin/uuname.out"
X#define L_SYS		"/usr/lib/uucp/L.sys"
X#define UUCP_INET	"/usr/lib/news/.admin/uucp-2-inet"
X
X
X/* Do you want news2mail to use the Path line in generating the From line?
X */
X#define USE_PATH_FOR_FROM
X
X
X/* Do you need to handle eight-bit characters in your addresses?  If
X * not (e.g., just USASCII) then #undef the next line.
X */
X#undef DO_8BIT_CHARS
X
X
X/* Where does the control file for talk.foo live?
X *	IN_ONEPLACE:	specified filename
X *	IN_SPOOLDIR:	/usr/spool/news/talk/foo/recnews.cmd
X *	IN_CMDDIR:	/usr/lib/news/.admin/talk.foo
X * One of these is required, but you can set IN_ONEPLACE to /dev/null to
X * disable the newsgroup editing. */
X#undef IN_ONEPLACE	"/dev/null"
X#undef IN_SPOOLDIR	"/usr/spool/news"
X#define	IN_CMDDIR	"/usr/lib/news/.admin"
X
X
X/* What do you want to do with the Path: line?  Put in a fixed string
X * (such as pointing to a mail reflector saying "Don't trust Path
X * lines as a way to reply").  Put a fixed "fake host" in the Path
X * before the user's host and name, or put just the user's host and
X * name there.  Note that the latter two can cause the poster's site
X * to never get the article sent to them.  Anyhow, pick one.  To pick
X * neither #define is to get the third behavior -- the user's host. */
X#define FIXED_PATH	"gateway"		/* .. */
X#undef	GATEWAY_NAME	"gateway"
X
X/* If the "hostname" you use for news (such as in the pathline) is not
X * the same as `hostname`, then define WHOAMI to be your news name (e.g.,
X * the contents of the C News file /usr/lib/news/whoami). */
X#undef WHOAMI		"bbn"
X
X
X/* The code in hdr.c does lots of work to canonicalize addresses.  You
X * might want to disable it if your sendmail.cf (e.g.) is very very good.
X * You might want to disable DO_GETHOSTBYNAME because gethostbyname(3)
X * doesn't handle MX records, and in some setups doesn't return a full
X * domain name. */
X#define DO_ADDRESS_CLEANUP			/* .. */
X#define DO_GETHOSTBYNAME			/* .. */
X
X
X/* Are you running sendmail or MMDF?  Pick one.  If you believe in
X * trusted users (MMDF doesn't?) to lie to your mailer, set the
X * user-ID. */
X#undef SENDMAIL	"/usr/lib/sendmail"
X#undef TRUSTED		1
X#define	MMDF		"/usr/mmdf/lib/submit"	/* .. */
X#undef MMDF_DELIVER_NOW
X
X
X/* Does your Sendmail mailer have the M flag on, requiring a Message-ID?
X * And do you want to require that the first line by a "From " line? */
X#if	defined(SENDMAIL)
X#define REQUIRE_MESSAGE_ID			/* .. */
X#undef REQUIRE_UNIX_FROM
X#endif	/* defined(SENDMAIL) */
X
X
X/* I love how we all speak the same language. */
X#define CATCHER		void		/* Type of a signal-catcher	*/
X#define IDX		index
X#define RDX		rindex
Xtypedef int		*align_t;	/* Worst-case alignment, for lint */
X#define CHARSTAR_SPRINTF		/* Need extern char *sprintf();	*/
X#define VOID_EXIT			/* Need extern void exit();	*/
X#define HAVE_SYSEXITS			/* Have <sysexits.h>?		*/
X#define HAVE_PUTENV			/* Have putenv(3)		*/
X#undef HAVE_STRERROR			/* Have strerror(3)?		*/
X
X#define SM_SIZE		512		/* A smallish buffer size	*/
X#define LG_SIZE		1024		/* big buffer size		*/
X
X/* Error log (stderr) for news2mail. */
X#define ERR_LOG		"/usr/lib/news/.admin/news2mail.out"
X#define TEMPFILE	"/tmp/gateXXXXXX" /* Temporary file pattern	*/
X
X
X/* Enable debugging code? */
X#define STATIC		static
X#if	!defined(lint) && !defined(SABER)
X#define RCSID
X#endif	/* !defined(lint) && !defined(SABER) */
X
X/*
X**  END OF CONFIGURATION SECTION.
X*/
X
X
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X
X#if	defined(HAVE_SYSEXITS)
X#include <sysexits.h>
X#else
X#include "sysexits.h"
X#endif	/* defined(HAVE_SYSEXITS) */
X
X
Xtypedef struct _HBUF {
X    char	approved[SM_SIZE];	/* Approved:		*/
X    char	ctlmsg[LG_SIZE];	/* Control:		*/
X    char	subdate[SM_SIZE];	/* Date: (submission)	*/
X    char	distribution[SM_SIZE];	/* Distribution:	*/
X    char	expdate[SM_SIZE];	/* Expires:		*/
X    char	followto[SM_SIZE];	/* Followup-to:		*/
X    char	from[SM_SIZE];		/* From:		*/
X    char	followid[SM_SIZE];	/* References:		*/
X    char	keywords[SM_SIZE];	/* Keywords:		*/
X    char	ident[SM_SIZE];		/* Message-ID:		*/
X    char	nbuf[LG_SIZE];		/* Newsgroups:		*/
X    char	organization[SM_SIZE];	/* Organization:	*/
X    char	title[SM_SIZE];		/* Subject:		*/
X    char	replyto[SM_SIZE];	/* Reply-To:		*/
X    char	summary[SM_SIZE];	/* Summary:		*/
X    char	path[LG_SIZE];		/* Path:		*/
X    char	sender[SM_SIZE];	/* Sender:		*/
X} HBUF;
X
X#if	defined(__GNUC__) || defined(__STDC__)
Xtypedef char const	*STRING;
X#else
Xtypedef char		*STRING;
X#endif	/* defined(__GNUC__) || defined(__STDC__) */
X
X/* String and memory manipulators. */
X#define APPEND(p, t)	strlen(strcpy((p), (t)))
X#define NEW(T, c)	(T *)MyAlloc((int)((c) * sizeof (T)))
X#define COPY(s)		strcpy(NEW(char, strlen((s)) + 1), (s))
X#define REALLOC(p, s)	realloc((char *)(p), (unsigned int)(s))
X
X
X/* Array sizing. */
X#define SIZEOF(x)	(sizeof x / sizeof x[0])
X#define ENDOF(x)	(&x[SIZEOF(x)])
X
X#if	defined(DO_8BIT_CHARS)
X#define ADDRCHAR	char	/* Addresses internal representation	*/
X#define QUOTE_MASK	0x0080	/* Mask to turn on 8-bit quoting	*/
X#define UNQUOTE_MASK	0x007F	/* Mask to turn off the 8-bit quote	*/
X#else
X#define ADDRCHAR	short	/* Addresses internal representation	*/
X#define QUOTE_MASK	0x0100	 /* Mask to turn on 9-bit quoting	*/
X#define UNQUOTE_MASK	0x00FF	/* Mask to turn off the 9-bit quote	*/
X#endif	/* defined(DO_8BIT_CHARS) */
X
X/* String and character operations. */
X#define WHITE(c)	((c) == ' ' || (c) == '\t')
X#define EQ(a, b)	((a)[0] == (b)[0] && strcmp((a), (b)) == 0)
X#define EQn(a, b, n)	((a)[0] == (b)[0] && strncmp((a), (b), (n)) == 0)
X#define NETCHR(c)	((c) == '%' || (c) == '@' || (c) == '!')
X#define CHREQ(c, d)	((d) == (islower((c)) ? toupper((c)) : (c)))
X
X
X/* Fundamental constants of the universe. */
X#define TRUE		1
X#define FALSE		0
X#define FAIL		(-1)
X
X
X/* SHUT UP! */
X#if	defined(lint)
X#undef	putc
X#undef	putchar
X#endif	/* defined(lint) */
X
X#define Close		(void)close
X#define Fflush		(void)fflush
X#define Fprintf		(void)fprintf
X#define Fputs		(void)fputs
X#define Signal		(void)signal
X#define Sprintf		(void)sprintf
X#define Strcpy		(void)strcpy
X#define Strcat		(void)strcat
X#define Strncpy		(void)strncpy
X
X
X/*
X**  External declarations.
X*/
X
X/* Program name; exists once for each main(). */
Xextern	char	*Pname;
X
X/* Routines we provide. */
Xextern align_t	MyAlloc();
Xextern int	Split();
Xextern int	CrackFrom();
Xextern void	re_modw();
Xextern void	SplitFree();
Xextern void	FreeFile();
Xextern char	**ReadFile();
Xextern char	*re_comp();
Xextern STRING	HackHeader();
Xextern void	rfc822read();
Xextern void	yyopen();
Xextern void	yyerror();
X
Xextern char	*strerror();
X
X/* Variables and routines that Unix(tm) provides. */
Xextern int	errno;
Xextern int	sys_nerr;
Xextern int	optind;
Xextern char	*sys_errlist[];
Xextern char	**environ;
Xextern char	*optarg;
X
Xextern FILE	*popen();
Xextern char	*IDX();
Xextern char	*RDX();
Xextern char	*ctime();
Xextern char	*malloc();
Xextern char	*mktemp();
Xextern char	*realloc();
Xextern char	*strcat();
Xextern char	*strncat();
Xextern char	*strcpy();
Xextern char	*strncpy();
X#if	defined(CHARSTAR_SPRINTF)
Xextern char	*sprintf();
X#endif	/* defined(CHARSTAR_SPRINTF) */
X#if	defined(VOID_EXIT)
Xextern void	exit();
X#endif	/* defined(VOID_EXIT) */
END_OF_FILE
  if test 8202 -ne `wc -c <'gate.h'`; then
    echo shar: \"'gate.h'\" unpacked with wrong size!
  fi
  # end of 'gate.h'
fi
if test -f 'hdr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hdr.c'\"
else
  echo shar: Extracting \"'hdr.c'\" \(10923 characters\)
  sed "s/^X//" >'hdr.c' <<'END_OF_FILE'
X/*
X**  Header-cracking and address re-writing routines, with sincere
X**  apologies to Upas and Sendmail.
X*/
X#include "gate.h"
X#if	defined(DO_GETHOSTBYNAME)
X#include <netdb.h>
X#endif	/* defined(DO_GETHOSTBYNAME) */
X#if	defined(RCSID)
Xstatic char RCS[] =
X	"$Header: /nfs/papaya/u2/rsalz/src/newsgate/RCS/hdr.c,v 1.21 91/07/18 20:00:57 rsalz Exp $";
X#endif	/* defined(RCSID) */
X
X
X#if	defined(TEST)
X#if	!defined(DO_FIX_ADDRESS)
X#define DO_FIX_ADDRESS
X#endif	/* !defined(DO_FIX_ADDRESS) */
X#if	!defined(DO_ADDRESS_CLEANUP)
X#define DO_ADDRESS_CLEANUP
X#endif	/* !defined(DO_ADDRESS_CLEANUP) */
X#else
X#define dprintf(string, buff)	/* NULL */
X#endif	/* defined(TEST) */
X
X
X#if	defined(DO_ADDRESS_CLEANUP)
X/*
X**  List of domains that we recognize.
X*/
XSTATIC STRING	Domains[] = {
X    /* These aren't official domains, but we use them. */
X	".BITNET",
X	".UUCP",
X    /* Official organizational domains. */
X	".ARPA",	".COM",	".EDU",	".GOV",	".INT",	".MIL",
X	".NATO",	".NET",	".ORG",
X    /* Official natonal domans. */
X	".AR",	".AT",	".AU",	".BE",	".BR",	".CA",	".CH",	".CL",
X	".CN",	".CR",	".CS",	".DE",	".DK",	".EC",	".EG",	".ES",
X	".FI",	".FR",	".GR",	".HK",	".HU",	".IE",	".IL",	".IN",
X	".IS",	".IT",	".JP",	".KR",	".LK",	".MX",	".MY",	".NI",
X	".NL",	".NO",	".NZ",	".PH",	".PL",	".PR",	".PT",	".SE",
X	".SG",	".SU",	".TH",	".TR",	".TW",	".UK",	".US",	".UY",
X	".YU",	".ZA"
X};
X
X
X/*
X**  Handle route-addresses:
X**	@cruft:joe@site --> joe@site
X*/
XSTATIC void
XRouteAddr(p)
X    register ADDRCHAR	*p;
X{
X    register ADDRCHAR	*q;
X    register ADDRCHAR	*r;
X
X    if (*p != '@')
X	/* Not a route -- leave alone. */
X	return;
X
X    /* Find the last '@'. */
X    for (r = p; *r; r++)
X	continue;
X    while (*--r != '@')
X	continue;
X
X    /* Find the preceeding colon. */
X    for (q = r; q > p && *q != ':'; q--)
X	continue;
X    r = q++;
X    if (r > p)
X	while ((*p++ = *q++) != 0)
X	    continue;
X}
X
X
X/*
X**  Handle the '%' syntax:
X**	joe%site.EDU@gateway.DOMAIN -> joe@site.EDU
X*/
XSTATIC void
XPercent(p)
X    register ADDRCHAR	*p;
X{
X    register ADDRCHAR	*q;
X    register ADDRCHAR	*r;
X    register ADDRCHAR	*s;
X    register STRING	*dp;
X    register STRING	pat;
X
X    /* Find the rightmost '@'. */
X    for (r = p; *r; r++)
X	continue;
X    while (--r > p)
X	if (*r == '@')
X	    break;
X
X    for (; *r == '@'; r = q) {
X	/* Find the '%' just before the '@'. */
X	for (q = r; q > p && *q != '&'; q--)
X	    continue;
X	if (*q != '%')
X	    break;
X
X	for (dp = Domains; dp < ENDOF(Domains); dp++) {
X	    pat = *dp + strlen(*dp);
X	    for (s = r, pat--, s--; pat > *dp && s > q; pat--, s--)
X		if (*s != *pat
X		 && (!isupper(*pat) || *s != tolower(*pat)))
X		    break;
X	    if (*s != *pat)
X		/* Assume **dp == '.' or not letter. */
X		continue;
X	    *r = '\0';
X	    *q = '@';
X	    break;
X	}
X    }
X}
X
X
X/*
X**  Handle hybrid "!" and "@" addresses:
X**	a!site!joe@site --> leave alone
X**	a!site!joe --> site!joe@a.uucp
X**	a!site.EDU!joe --> joe@site.EDU
X*/
XSTATIC void
XHybrid(p)
X    register ADDRCHAR	*p;
X{
X    register ADDRCHAR	*q;
X    register ADDRCHAR	*r;
X    register ADDRCHAR	*user;
X
X    /* Already has an '@' */
X    for (q = p; *q; q++)
X	if (*q == '@')
X	    return;
X
X    /* Make sure there is a '!' */
X    for (user = p; *user; user++)
X	if (*user == '!')
X	    break;
X    if (*user != '!')
X	return;
X
X    for (*q++ = '@', *user = '\0', r = p; *r; r++)
X	*q++ = *r;
X    /* Copy back to beginning of list */
X    for (*q = '\0', r = p; *++user; r++)
X	*r = *user;
X    for (*r = '\0', user = r; *user != '@'; user--)
X	if (*user == '.')
X	    return;
X    *r++ = '.';
X    *r++ = 'U';
X    *r++ = 'U';
X    *r++ = 'C';
X    *r++ = 'P';
X    *r++ = '\0';
X}
X#endif	/* defined(DO_ADDRESS_CLEANUP) */
X
X
X#if	defined(TEST)
XSTATIC void
Xdprintf(prompt, p)
X    char	*prompt;
X    ADDRCHAR	*p;
X{
X    (void)printf("%s returns:  ", prompt);
X    for ( ; *p; p++) {
X	if (*p & QUOTE_MASK)
X	    (void)putchar('\\');
X	(void)putchar(*p & UNQUOTE_MASK);
X    }
X    (void)putchar('\n');
X}
X#endif	/* defined(TEST) */
X
X/*
X**  General address canonicalizer.
X*/
XSTATIC char *
XFixAddress(p)
X    register ADDRCHAR	*p;
X{
X    static char		buff[1024];
X    register char	*cp;
X    register int	local;
X    char		host[128];
X
X#if	defined(DO_ADDRESS_CLEANUP)
X    RouteAddr(p);
X    dprintf("RouteAddr", p);
X    Percent(p);
X    dprintf("  Percent", p);
X    Hybrid(p);
X    dprintf("   Hybrid", p);
X#endif	/* defined(DO_ADDRESS_CLEANUP) */
X
X    /* Copy address, removing all quoting, and see if it's local. */
X    for (local = 1, cp = buff; (*cp = *p & UNQUOTE_MASK) != '\0'; cp++, p++)
X	if (NETCHR(*p))
X	    local = 0;
X
X    if (local) {
X	if (gethostname(host, sizeof host) < 0) {
X	    Fprintf(stderr, "%s:  Can't get my hostname, %s.\n",
X		    Pname, strerror(errno));
X	    exit(EX_TEMPFAIL);
X	}
X	Sprintf(cp, "%s@%s", p, host);
X    }
X    return buff;
X}
X
X
X/*
X**  This subroutine is a concession to the realities of the Internet and
X**  and the USENET. Much as the idea is distasteful and likely to get me
X**  in trouble, I have to hack message-ids into a format that the USENET
X**  won't choke on.  Pray that if we're doing multiple insertion point
X**  gatewaying that ALL the gateways mung exactly the same things.
X**
X**  (Death to HERMES! Death to UNIX/MM-11! Death to EAN!)
X*/
XSTATIC int
XFixMessageID(s)
X    register char	*s;
X{
X    register int	atdot;
X    register int	closed;
X
X    /* Quickie tests -- why waste time? */
X    if (*s != '<')
X	return FALSE;
X
X    for (atdot = FALSE, closed = FALSE; *++s; )
X	switch (*s) {
X	default:
X	    if (!isascii(*s) || iscntrl(*s) || isspace(*s))
X		return FALSE;
X	    break;
X	case '<':
X	    /* Already got one. */
X	    return FALSE;
X	case '>':
X	    /* I hope no one is stupid enough to quote this... */
X	    closed = TRUE;
X	    s[1] = '\0';
X	    break;
X	case '.':
X	case '@':
X	    /* We should check for a domain spec, not just either/or. */
X	    atdot = TRUE;
X	    break;
X	case '\t':
X	case ' ':
X	case '/':
X	case '"':
X	    /* Avoid various problem characters. */
X	    *s = '_';
X	    break;
X	}
X
X    return atdot && closed;
X}
X
X
X/*
X**  Fix up the contents of In-Reply-To: fields and References: fields.
X*/
XSTATIC void
XFixReferences(hp)
X    register HBUF		*hp;
X{
X    register char		*cp;
X    register char		*ep;
X    register char		*p;
X    register char		*max;
X    char			scratch[LG_SIZE];
X
X    cp = hp->followid;
X    max = cp + strlen(cp);
X    for (p = scratch; (cp = IDX(cp, '<')) != NULL; ) {
X	if ((ep = IDX(cp, '>')) == NULL
X	 || ((ep - cp) + 1) > sizeof scratch - (p - scratch + 2))
X	    /* Unterminated ID, or no more room. */
X	    break;
X
X	if (FixMessageID(cp)) {
X	    if (p > scratch) {
X		*p++ = ' ';
X		*p++ = '\0';
X	    }
X	    p += APPEND(p, cp);
X	}
X	cp = ep + 2;
X	if (cp >= max)
X	    break;
X    }
X    Strcpy(hp->followid, scratch);
X}
X
X
X/*
X**  Count the number of '@' in the string.
X*/
XSTATIC int
XAtCount(s)
X    register char	*s;
X{
X    register int	n;
X
X    for (n = 0; *s; s++)
X	if (*s == '@')
X	    n++;
X    return n;
X}
X
X
X/*
X**  Canonicalize the "From:" line into the form
X**	From: local-part@domain (full-name)
X** RFC822 doesn't require the comment to be at the end of the string
X** like that.
X*/
XSTATIC void
XFixFrom(hp)
X    register HBUF		*hp;
X{
X    register char		*p;
X#if	defined(DO_GETHOSTBYNAME)
X    register struct hostent	*host;
X#endif	/* defined(DO_GETHOSTBYNAME) */
X    char			address[LG_SIZE];
X    char			fullname[LG_SIZE];
X    char			scratch[sizeof address];
X    ADDRCHAR			temp[LG_SIZE];
X
X    /* We should handle "Full-Name:" too, but it doesn't get read by the
X     * news header reader. */
X    (void)CrackFrom(temp, fullname, hp->from);
X    Strcpy(address, FixAddress(temp));
X
X    if (AtCount(address) != 1)
X	p = NULL;
X    else {
X	p = RDX(address, '@');
X	*p++ = '\0';
X
X#if	defined(DO_GETHOSTBYNAME)
X	/* If we can find the host's official name use that. */
X	if ((host = gethostbyname(p)) != NULL)
X	    p = host->h_name;
X#endif	/* defined(DO_GETHOSTBYNAME) */
X
X	/* We know have the canonical hostname; glue back together. */
X	Sprintf(scratch, "%s@%s", address, p);
X	Strncpy(address, scratch, sizeof address);
X	address[sizeof address - 1] = '\0';
X	p = IDX(address, '@');
X	*p++ = '\0';
X    }
X
X    /* Policy decision; what to put in the path? */
X#if	defined(FIXED_PATH)
X    Strcpy(hp->path, FIXED_PATH);
X#else
X#if	defined(GATEWAY_NAME)
X    Sprintf(scratch, "%s!%s!%s", GATEWAY_NAME, p, address);
X#else
X    Sprintf(scratch, "%s!%s", p, address);
X#endif	/* defined(GATEWAY_NAME) */
X    Strncpy(hp->path, scratch, sizeof hp->path);
X    hp->path[sizeof hp->path - 1] = '\0';
X#endif	/* defined(FIXED_PATH) */
X
X    /* Restore the @ if we took it out. */
X    if (p)
X	*--p = '@';
X
X    if (fullname[0]) {
X	p = address + strlen(address);
X	*p++ = ' ';
X	*p++ = '(';
X	p += APPEND(p, fullname);
X	*p++ = ')';
X	*p++ = '\0';
X    }
X
X    /* Stick the canonicalized From: back in. */
X    Strcpy(hp->from, address);
X    for (p = hp->from; *p; p++)
X	*p &= 0x7F;
X}
X
X
X#define ERROR "\
XMessage-ID syntax error.\n\
X*** Please refer to page 23, paragraph 4.6.1. and Appendix D\n\
X*** of NIC RFC #822 for the correct syntax, and fix your mailer."
X
X/*
X** Check an RFC822 header for validity and hack it to RFC1036 spec.
X** returns NULL for everything OK, or a character pointer to an
X** error message.
X*/
XSTRING
XHackHeader(hp, SubjectRequired)
X    register HBUF		*hp;
X    int				SubjectRequired;
X{
X#if	defined(REQUIRE_MESSAGE_ID)
X    /* Sendmail (almost) always has a Message-ID */
X    if (hp->ident[0] == '\0')
X	return "Message-ID header missing";
X    if (!FixMessageID(hp->ident))
X	return ERROR;
X#else
X    /* MMDF doesn't always have a Message-ID. */
X    if (hp->ident[0] && !FixMessageID(hp->ident))
X	return ERROR;
X#endif	/* defined(REQUIRE_MESSAGE_ID) */
X
X    /* Newsgroups */
X    if (hp->nbuf[0] == '\0')
X	return "Newsgroups header missing";
X
X    /* Subject */
X    if (hp->title[0] == '\0') {
X	if (SubjectRequired)
X	    return "Subject header missing";
X	Strcpy(hp->title, "(none)");
X    }
X
X    /* From */
X    if (hp->from[0] == '\0')
X	return "From header missing";
X    FixFrom(hp);
X
X    /* References and In-Reply-To */
X    if (hp->followid[0]) 
X	FixReferences(hp);
X
X    return NULL;
X}
X
X
X#if	defined(TEST)
X
Xchar	*Pname = "address-test";
X
X#if	!defined(HAVE_STRERROR)
X/*
X**  Return a printable representation of errno.
X*/
Xchar *
Xstrerror(x)
X    int			x;
X{
X    static char		buff[20];
X
X    if (x >= 0 && x < sys_nerr)
X	return sys_errlist[x];
X    Sprintf(buff, "Error code %d", x);
X    return buff;
X}
X#endif	/* !defined(HAVE_STRERROR) */
X
Xmain()
X{
X    HBUF	hp;
X    char	buff[BUFSIZ];
X    int		interactive;
X
X    interactive = isatty(0);
X    if (interactive)
X	(void)printf("Enter addresses, EOF to exit:\n");
X    for ( ; ; ) {
X	if (interactive) {
X	    (void)printf(">  ");
X	    (void)fflush(stdout);
X	}
X	if (gets(buff) == NULL)
X	    break;
X	if (buff[0] != '#' && buff[0] != '\0') {
X	    if (!interactive) {
X		(void)printf("%s\n", buff);
X		(void)fflush(stdout);
X	    }
X	    (void)strcpy(hp.from, buff);
X	    FixFrom(&hp);
X	    (void)printf("\t-> %s\n\n", hp.from);
X	}
X    }
X
X    exit(0);
X}
X#endif	/* defined(TEST) */
END_OF_FILE
  if test 10923 -ne `wc -c <'hdr.c'`; then
    echo shar: \"'hdr.c'\" unpacked with wrong size!
  fi
  # end of 'hdr.c'
fi
if test -f 'lex.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lex.l'\"
else
  echo shar: Extracting \"'lex.l'\" \(3875 characters\)
  sed "s/^X//" >'lex.l' <<'END_OF_FILE'
X/*
X**  Lexical analyzer for the gag language.  We have our own FSA
X**  for comments because it's much smaller and quicker that way.
X*/
X%{
X/* SUPPRESS 15 on yyt *//* Copying a bad pointer */
X/* SUPPRESS 25 on yycrank *//* Creating a bad pointer during initialization */
X/* SUPPRESS 26 on yyt *//* Storing a bad pointer */
X/* SUPPRESS 592 on ncform_sccsid *//* Static variable was not used */
X/* SUPPRESS 593 on yyfussy *//* Label was not used */
X#include "gate.h"
X#include "gag.h"
X
X/* State of our automaton. */
Xtypedef enum _STATE {
X    S_STAR, S_NORMAL, S_END
X} STATE;
X
X/* Key-value pair. */
Xtypedef struct _PAIR {
X    STRING	name;
X    int		value;
X} PAIR;
X
Xchar		yyfilename[SM_SIZE];
Xextern int	Errors;
X
X/* List of GAG's keywords. */
XSTATIC PAIR	Keywords[] = {
X    {	"default",		tDEFAULT	},
X    {	"directory",		tDIRECTORY	},
X    {	"distributions",	tDISTRIBUTIONS	},
X    {	"dotify",		tDOTIFY		},
X    {	"false",		tFALSE		},
X    {	"flags",		tFLAGS		},
X    {	"gateway",		tGATEWAY	},
X    {	"inews",		tINEWS		},
X    {	"mail2news",		tMAIL2NEWS	},
X    {	"mailcontact",		tMAILCONTACT	},
X    {	"mailhost",		tMAILHOST	},
X    {	"mailinglist",		tMAILINGLIST	},
X    {	"mailpost",		tMAILPOST	},
X    {	"moderator",		tMODERATOR	},
X    {	"news2mail",		tNEWS2MAIL	},
X    {	"organization",		tORGANIZATION	},
X    {	"owner",		tOWNER		},
X    {	"request_address",	tREQUESTADDR	},
X    {	"site",			tSITE		},
X    {	"true",			tTRUE		},
X    {	"user",			tUSER		},
X    {	NULL,			0		}
X};
X
X%}
X
X%%
X
X[-+0-9A-Za-z_.]+	{
X		    /* A simple tID or keyword. */
X		    register PAIR	*p;
X
X		    /* Keyword? */
X		    for (p = Keywords; p->name; p++)
X			if (EQ(p->name, yytext))
X			    return p->value;
X		    yylval.String = COPY(yytext);
X		    return tID;
X		    /* NOTREACHED */
X		}
X
X^#[ \t]+[0-9]+[ \t]+"[^\n]+"[^\n]*$	{
X		    /* C pre-processor control line. */
X		    register char	*p;
X		    char		*namep;
X
X		    /* Find the line number. */
X		    for (p = yytext; *p && !isdigit(*p); p++)
X			continue;
X		    /* Parse the number, find the start of the filename. */
X		    for (yylineno = atoi(p); *p && *p != '"'; p++)
X			continue;
X		    /* March down to the end of the filename. */
X		    for (namep = p; *++p && *p != '"'; p++)
X			continue;
X		    *p = '\0';
X		    (void)strncpy(yyfilename, namep, sizeof yyfilename - 1);
X		    yyfilename[sizeof yyfilename - 1] = '\0';
X		}
X
X\"[^"]*		{
X		    /* Quoted string. */
X		    int		c;
X
X		    /* See the Lex paper in Volume 2A or PS1:16
X		     * for details on this code. */
X		    if (yytext[yyleng - 1] == '\\')
X			yymore();
X		    else {
X			if ((c = input()) == '"') {
X			    yylval.String = COPY(&yytext[1]);
X			    return tID;
X			}
X			unput(c);
X			yyerror("Bad string");
X		    }
X		}
X
X"/*"	        {
X		    /* Comment. */
X		    register STATE	S;
X
X		    for (S = S_NORMAL; S != S_END; )
X			switch (input()) {
X			case '/':
X			    if (S == S_STAR) {
X				S = S_END;
X				break;
X			    }
X			    /* FALLTHROUGH */
X			default:
X			    S = S_NORMAL;
X			    break;
X			case '\0':
X			    S = S_END;
X			    break;
X			case '*':
X			    S = S_STAR;
X			    break;
X			}
X		}
X
X[ \t\n]		{
X		    /* Tasty whitespace. */
X		}
X
X.		{
X		    /* Random special character. */
X		    return *yytext;
X		    /* NOTREACHED */
X		}
X
X%%
X
X
X/*
X**  Called by lex at end-of-stream.  Return one if no more input.
X*/
Xint
Xyywrap()
X{
X    return 1;
X}
X
X
Xvoid
Xyyopen(p)
X    char	*p;
X{
X    if (p == NULL)
X	(void)strcpy(yyfilename, "stdin");
X    else {
X	if ((yyin = fopen(p, "r")) == NULL) {
X	    Fprintf(stderr, "%s: Can't open \"%s\" for input, %s.\n",
X		    Pname, p, strerror(errno));
X	    exit(1);
X	}
X	(void)strcpy(yyfilename, p);
X    }
X}
X
X
X/*
X**  Write an error message.
X*/
Xvoid
Xyyerror(p)
X    char	*p;
X{
X    char	buff[SM_SIZE];
X
X    (void)strncpy(buff, yytext, sizeof buff);
X    buff[sizeof buff - 1] = '\0';
X    Fprintf(stderr, "\"%s\", line %d: %s (near \"%s\")\n",
X	    yyfilename, yylineno, p, buff);
X    Errors++;
X}
END_OF_FILE
  if test 3875 -ne `wc -c <'lex.l'`; then
    echo shar: \"'lex.l'\" unpacked with wrong size!
  fi
  # end of 'lex.l'
fi
if test -f 'news2mail.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'news2mail.1'\"
else
  echo shar: Extracting \"'news2mail.1'\" \(5359 characters\)
  sed "s/^X//" >'news2mail.1' <<'END_OF_FILE'
X.\" $Header: /nfs/papaya/u2/rsalz/src/newsgate/RCS/news2mail.1,v 1.8 91/04/01 09:43:57 rsalz Exp Locker: rsalz $
X.TH NEWS2MAIL 1 LOCAL
X.SH NAME
Xnews2mail \- feed a Usenet news article to mail
X.SH SYNOPSIS
X.B news2mail
X[
X.BI \-E var=value
X] [
X.B \-.
X]
Xlistname listaddr listadmin host [ article ]
X.SH DESCRIPTION
X.PP
X.I News2mail
Xreads a news article edits the headers to make it look like an RFC822 mail
Xmessage.
XIt feeds the results to
X.IR sendmail (8),
X.IR MMDF (8),
Xor a shell script.
XIf the ``\-.'' flag is used, then the results are sent to standard output,
Xfor debugging.
X.PP
XThe article is taken from the file specified on the command line, or read
Xfrom standard input if not specified.
X.PP
XThe ``\-E'' flag can be used to set environment variables for the delivery
Xprogram that is invoked.
XThey should be of the form ``name=value'' as in
X\&``\-E mailer=/usr/lib/pp/cmds/submit''.
X.PP
X.I News2mail
Xswallows control messages,
Xremoves all but the last three entries from the ``References'' header,
Xand merges the ``From'' and ``Path'' headers to build a single
X``From'' header for the mail message (see below).
XThe ``Date,'' ``Subject,'' ``Reply\-To,'' ``Message\-ID,'' and ``Organization''
Xheaders are passed through unchanged.
XAny other headers in the original input are removed.
X.PP
XTo ``To,'' and ``Sender'' headers and the SMTP destination envelope are set
Xaccording to the parameters specified on the command line.
XThe ``To'' header is set to be \fIlistname\fP, with \fI@host\fP appended if there
Xis no atsign in \fIlistname\fP.
XThis should contain the name of the mailing list.
XThe mail is actually sent to \fIlistaddr\fP by specifying it as the
Xrecipient in the mailer command line.
X(If \fIlistaddr\fP does not have an atsign, then \fIlistaddr@host\fP is used.)
XBy treating the ``To'' header and the destination envelope separately,
Xother members of the mailing list can properly reply to the messages that
Xpass through
X.IR news2mail .
XIn addition, \fIlistaddr\fP can be an address that sends to everyone on
Xthe list except the gateway.
XThis is an optimization, however, because
X.IR inews (8)
Xwill reject any Message-ID that it has already seen.
X.PP
XThe ``Sender'' header is set to be \fIlistadmin\fP, with \fI@host\fP
Xappended if there is no atsign in \fIlistadmin\fP.
XThese values should correspond to the maintainer of the mailing list.
XSome mailers will also automatically fill in the ``Return-Path'' header
Xwith this value.
X.PP
XThe goal of the header manipulations is to send the news article to all
Xrecipient of the mailing list, but with the headers set so that delivery
Xerrors are sent to the list maintainer for disposition.
X.PP
X.IR Mail2news
Xtries to shrink the ``Path'' header by taking note of neighboring
X\s-2UUCP\s0 hosts and scanning for other Internet hosts that it can
Xshort\-circuit to.
X.IR Uuname (1)
Xis used to check for \s-2UUCP\s0 neighbors; the file
X.I uucp\-2\-inet
Xis read to map \s-2UUCP\s0 names to Internet domain names.
XFor efficiency,
X.I mail2news
Xstores
X.IR uuname 's
Xoutput in a private file, and will only call
X.I uuname
Xif the file is older than the \s-2UUCP\s0
X.IR L.sys (5)
Xfile.
X.PP
XIn order to have
X.I sendmail
Xbelieve that the headers it has created are valid,
X.I news2mail
Xmust be able to 
X.IR setuid (2)
Xto one of
X.IR sendmail 's
Xtrusted users.
X.SH EXAMPLE
X.PP
XSuppose the following article arrives
X.IR comp.sources.unix\| :
X.RS
X.nf
XPath: news.bbn.com!uunet!rsalz
XFrom: rsalz@uunet.UU.NET (Rich Salz)
XNewsgroups: comp.sources.unix
XSubject: v10INF1:  Introduction to comp.sources.unix
XMessage\-ID: <830@uunet.UU.NET>
XDate: 10 Aug 87 21:57:17 GMT
XExpires: 10 Nov 87 22:17:17 GMT
XOrganization: UUNET Communications Services, Arlington, VA
XLines: 189
XApproved: rsalz@uunet.UU.NET
X
XThis is the first of two introductory articles about comp.sources.unix.
X\&...
X.fi
X.RE
XAlso, assume the following line is in your news sys file (see
X.IR news (5)):
X.RS
X.nf
Xgateway:world,comp.sources.unix::\e
X.ti +.5i
Xnews2mail unix\-sources rsalz unix\-sources\-request bbn.com
X.fi
X.RE
XThe
X.I news2mail
Xprogram would generate the following article and feed it to
X.IR sendmail :
X.RS
X.nf
XReceived: from USENET by bbn.com with netnews
X	for rsalz@bbn.com (unix\-sources@bbn.com);
X	contact usenet@bbn.com if you have questions.
XTo: unix\-sources@bbn.com
XDate: 10 Aug 87 21:57:17 GMT
XFrom: rsalz@uunet.uu.net (Rich Salz)
XSender: unix\-sources\-request@bbn.com
XSubject: v10INF1:  Introduction to comp.sources.unix
XMessage\-ID: <830@uunet.UU.NET>
XOrganization: UUNET Communications Services, Arlington, VA
X
XThis is the first of two introductory articles about comp.sources.unix.
X\&...
X.fi
X.RE
X.SH DIAGNOSTICS
XMost return values from I/O routines are checked; if anything goes
Xwrong, a diagnostic message is sent to a log file.
XThis file will occasionally have to be examined and trimmed.
X.SH FILES
X.ta \w'news2mail.out  'u
Xnews2mail.out	Error log (standard error)
X.br
Xuucp\-2\-inet	Mapping of ``Path'' names to Internet hostnames.
X.br
Xuuname.out	Last output from
X.IR uuname .
X.br
XThe full paths to these files are compile\-time constants; see
X.I gate.h
Xin the source for the exact details.
X.SH "SEE ALSO"
Xgag(1L), mail2news(1L).
X.SH AUTHOR
XRich $alz <rsalz@bbn.com>, after a set of scripts and a excellent manpage by
X.br
XErik E. Fair <fair@apple.com>.
X.br
XPiete Brooks <pb@computer-lab.cambridge.ac.uk> helped write the option-handling.
END_OF_FILE
  if test 5359 -ne `wc -c <'news2mail.1'`; then
    echo shar: \"'news2mail.1'\" unpacked with wrong size!
  fi
  # end of 'news2mail.1'
fi
if test -f 'regex.3' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'regex.3'\"
else
  echo shar: Extracting \"'regex.3'\" \(7417 characters\)
  sed "s/^X//" >'regex.3' <<'END_OF_FILE'
X.\" $Header: /nfs/papaya/u2/rsalz/src/newsgate/RCS/regex.3,v 1.4 91/02/12 14:50:56 rsalz Exp $
X.TH REGEX 3 LOCAL
X.SH NAME
Xre_comp, re_exec, re_subs, re_modw, re_fail \- regular expression handling
X.SH SYNOPSIS
X.nf
X.B "char *re_comp(pat)"
X.B "char *pat;"
X.sp
X.B "re_exec(str)"
X.B "char *str;"
X.sp
X.B "re_subs(src, dst)"
X.B "char *src;"
X.B "char *dst;"
X.sp
X.B "void re_fail(msg, op)"
X.B "char *msg;"
X.B "char op;"
X.sp
X.B "void re_modw(str)"
X.B "char *str;"
X.fi
X.SH DESCRIPTION
XThese functions implement
X.IR ed (1)\-style
Xpartial regular expressions and supporting facilities.
X.PP
X.I Re_comp
Xcompiles a pattern string into an internal form (a deterministic finite\-state
Xautomaton) to be executed by
X.I re_exec
Xfor pattern matching.
X.I Re_comp
Xreturns zero if the pattern is compiled successfully, otherwise it returns an
Xerror message string.
XIf
X.I re_comp
Xis called with a null pointer or a pointer to an empty string, it returns
Xwithout changing the currently compiled regular expression.
X.PP
X.I Re_comp
Xsupports the same limited set of
X.I "regular expressions"
Xfound in
X.I ed
Xand Berkeley
X.IR regex (3)
Xroutines:
X.in +1i
X.de Ti
X.sp
X.ti -1i
X.ta 0.5i +0.5i +0.5i
X..
X.Ti
X[1]	\fIchar\fP	Matches itself, unless it is a special
Xcharacter (meta\-character): \fB. \e [ ] * + ^ $\fP
X.Ti
X[2]	\fB.\fP	Matches \fIany\fP character.
X.Ti
X[3]	\fB\e\fP	Matches the character following it, except
Xwhen followed by a digit, \fB(\fP, \fB)\fP, \fB<\fP or \fB>\fP
X(see [7], [8] and [9]).
XIt is used as an escape character for all other meta\-characters, and itself.
XWhen used in a set ([4]), it is treated as an ordinary character.
X.Ti
X[4]	\fB[\fP\fIset\fP\fB]\fP	Matches one of the characters in the set.
XIf the first character in the set is \fB^\fP, it matches a character \fInot\fP
Xin the set.
Xthe shorthand
X.IR S \- E
Xspecifies the set of characters
X.I S
Xthrough
X.IR E ,
Xinclusive.
XThe special characters \fB]\fP and \fB\-\fP have no special meaning if they
Xappear as the first characters in the set.
X.nf
X.ta \w'[a\-zA\-Z0\-9]    'u
XExamples	Match
X[a\-z]		any lowercase alpha
X[^]\-]		any char except ] and \-
X[^A\-Z]		any char except uppercase alpha
X[a\-zA\-Z0\-9]	any alphanumeric
X.fi
X.Ti
X[5]	\fB*\fP	Any regular expression form [1] to [4], followed by the
Xclosure character (*) matches zero or more matches of that form.
X.Ti
X[6]	\fB+\fP	Same as [5], except it matches one or more.
X.Ti
X[7]	\e\|( \e)	A regular expression in the form [1] to [10], enclosed
Xas \e\|(\fIform\fP\e) matches what form matches.
XThe enclosure creates a set of tags, used for [8] and for pattern
Xsubstitution in
X.IR re_subs .
XThe tagged forms are numbered starting from one.
X.Ti
X[8]	\ed	A \e followed by a digit matches whatever a previously tagged
Xregular expression ([7]) matched.
X.Ti
X[9]	\fB\e<\fP	Matches the beginning of a \fIword\fP; that is,
Xan empty string followed by a letter, digit, or _ and not preceded by a
Xletter, digit, or _ .
X.Ti
X	\fB\e>\fP	Matches the end of a \fIword\fP; that is, an empty
Xstring preceded by a letter, digit, or _ , and not followed by a letter,
Xdigit, or _ .
X.Ti
X[10]		A composite regular expression \fIxy\fP where \fIx\fP and
X\fIy\fP are in the form of [1] to [10] matches the longest match of \fIx\fP
Xfollowed by a match for \fIy\fP.
X.Ti
X[11]	\fB^ $\fP	A regular expression starting with a \fB^\fP character
Xand/or ending with a \fB$\fP character, restricts the pattern matching to the
Xbeginning of the line, and/or the end of line (anchors).
XElsewhere in the pattern, \fB^\fP and \fB$\fP are treated as ordinary
Xcharacters.
X.in -1i
X.PP
X.I Re_exec
Xexecutes the internal form produced by
X.I re_comp
Xand searches the argument string for the regular expression described
Xby the internal form.
X.I Re_exec
Xreturns 1 if the last regular expression pattern is matched within the string,
X0 if no match is found.
XIn case of an internal error (corrupted internal form),
X.I re_exec
Xcalls the user\-supplied
X.I re_fail
Xand returns 0.
X.PP
XThe strings passed to both
X.I re_comp
Xand
X.I re_exec
Xmay have trailing or embedded newline characters, but must be properly
Xterminated with a NUL.
X.PP
X.I Re_subs
Xdoes
X.IR ed \-style
Xpattern substitution, after a successful match is found by
X.I re_exec.
XThe source string parameter to
X.I re_subs
Xis copied to the destination string with the following interpretation:
X.sp
X.in +1i
X.Ti
X[1]	&	Substitute the entire matched string in the destination.
X.Ti
X[2]	\e\fId\fP	Substitute the substring matched by a tagged subpattern
Xnumbered \fId\fP, where \fId\fP is between 1 and 9, inclusive.
X.Ti
X[3]	\e\fIc\fP	Treat the next character literally, unless the
Xcharacter is a digit ([2]).
X.in -1i
X.PP
XIf the copy operation with the substitutions is successful,
X.I re_subs
Xreturns 1.
XIf the source string is corrupted, or the last call to
X.I re_exec
Xfails, it returns 0.
X.PP
X.I Re_modw
Xis used to
Xadd new characters into an internal table to
Xchange the re_exec's understanding of what
Xa \fIword\fP should look like, when matching with \fB\e<\fP and \fB\e>\fP
Xconstructs. If the string parameter is 0 or null string,
Xthe table is reset back to the default, which contains \fBA\-Z a\-z 0\-9 _\fP .
X.PP
X.I Re_fail
Xis a user\-supplied routine to handle internal errors.
X.I Re_exec
Xcalls
X.I re_fail
Xwith an error message string, and the opcode character that caused the error.
XThe default
X.I re_fail
Xroutine simply prints the message and the opcode character to the standard
Xerror and calls
X.IR exit (2).
X.SH EXAMPLES
XFor additional details, refer to the sources.
X.PP
X.RS
X.nf
X.ta \w'\e\|(foo\e)[1\-3]\e1    'u
Xfoo*.*	fo foo fooo foobar fobar foxx ...
X
Xfo[ob]a[rz]	fobar fooar fobaz fooaz
X
Xfoo\e\e+	foo\e foo\e\e foo\e\e\e  ...
X
X\e\|(foo\e)[1\-3]\e1	foo1foo foo2foo foo3foo
X(This is the same as \fIfoo[1\-3]foo\fP, but it takes less internal space.)
X
X\e\|(fo.*\e)\-\e1	foo\-foo fo\-fo fob\-fob foobar\-foobar ...
X.fi
X.RE
X.SH DIAGNOSTICS
X.I Re_comp
Xreturns one of the following strings if an error occurs:
X.RS
X.nf
X.I "No previous regular expression"
X.I "Empty closure"
X.I "Illegal closure"
X.I "Cyclical reference"
X.I "Undetermined reference"
X.I "Unmatched \e\|("
X.I "Missing ]"
X.I "Null pattern inside \e\|(\e)"
X.I "Null pattern inside \e<\e>"
X.I "Too many \e\|(\e) pairs"
X.I "Unmatched \e)"
X.fi
X.RE
X.SH REFERENCES
X.nf
X.IR "Software tools" ", Kernighan & Plauger."
X.IR "Software tools in Pascal" ", Kernighan & Plauger."
X.IR "Grep sources [rsx\-11 C dist]" ", David Conroy."
X.IR "Ed \- text editor" ", Unix Programmer's Manual."
X.IR "Advanced editing on Unix" ", B. W. Kernighan."
X.IR "RegExp sources" ", Henry Spencer."
X.fi
X.SH "HISTORY AND NOTES"
XThese routines are
X.IR Public Domain ,
Xyou can get them in source.
XThey are derived from various implementations found in the
X.I "Software Tools"
Xbooks, and David Conroy's
X.IR grep .
XThey are NOT derived from licensed/restricted software.
XFor more interesting/academic/complicated implementations, see Henry Spencer's
X.I regexp
Xroutines, or the
X.I "GNU Emacs"
Xpattern
Xmatching module.
X.PP
X.I Re_comp
Xand
X.I re_exec
Xgenerally perform at least as well as their licensed counterparts.
XIn a very few instances, they are about 10% to 15% slower.
X.SH AUTHOR
XOzan S. Yigit <yunexus!oz>.
X.br
XThis manual page was edited from the original by Rich $alz <rsalz@bbn.com>.
X.SH BUGS
XThe internal buffer for the compiled pattern is not checked for overflow;
Xthe size is currently 1024 bytes.
X.br
XThere are no doubt other bugs, too.
X.SH "SEE ALSO"
Xed(1), egrep(1), fgrep(1), grep(1)
END_OF_FILE
  if test 7417 -ne `wc -c <'regex.3'`; then
    echo shar: \"'regex.3'\" unpacked with wrong size!
  fi
  # end of 'regex.3'
fi
if test -f 'sysexits.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sysexits.h'\"
else
  echo shar: Extracting \"'sysexits.h'\" \(4568 characters\)
  sed "s/^X//" >'sysexits.h' <<'END_OF_FILE'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	@(#)sysexits.h	4.5 (Berkeley) 7/6/88
X */
X
X/*
X**  SYSEXITS.H -- Exit status codes for system programs.
X**
X**	This include file attempts to categorize possible error
X**	exit statuses for system programs, notably delivermail
X**	and the Berkeley network.
X**
X**	Error numbers begin at EX__BASE to reduce the possibility of
X**	clashing with other exit statuses that random programs may
X**	already return.  The meaning of the codes is approximately
X**	as follows:
X**
X**	EX_USAGE -- The command was used incorrectly, e.g., with
X**		the wrong number of arguments, a bad flag, a bad
X**		syntax in a parameter, or whatever.
X**	EX_DATAERR -- The input data was incorrect in some way.
X**		This should only be used for user's data & not
X**		system files.
X**	EX_NOINPUT -- An input file (not a system file) did not
X**		exist or was not readable.  This could also include
X**		errors like "No message" to a mailer (if it cared
X**		to catch it).
X**	EX_NOUSER -- The user specified did not exist.  This might
X**		be used for mail addresses or remote logins.
X**	EX_NOHOST -- The host specified did not exist.  This is used
X**		in mail addresses or network requests.
X**	EX_UNAVAILABLE -- A service is unavailable.  This can occur
X**		if a support program or file does not exist.  This
X**		can also be used as a catchall message when something
X**		you wanted to do doesn't work, but you don't know
X**		why.
X**	EX_SOFTWARE -- An internal software error has been detected.
X**		This should be limited to non-operating system related
X**		errors as possible.
X**	EX_OSERR -- An operating system error has been detected.
X**		This is intended to be used for such things as "cannot
X**		fork", "cannot create pipe", or the like.  It includes
X**		things like getuid returning a user that does not
X**		exist in the passwd file.
X**	EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
X**		etc.) does not exist, cannot be opened, or has some
X**		sort of error (e.g., syntax error).
X**	EX_CANTCREAT -- A (user specified) output file cannot be
X**		created.
X**	EX_IOERR -- An error occurred while doing I/O on some file.
X**	EX_TEMPFAIL -- temporary failure, indicating something that
X**		is not really an error.  In sendmail, this means
X**		that a mailer (e.g.) could not create a connection,
X**		and the request should be reattempted later.
X**	EX_PROTOCOL -- the remote system returned something that
X**		was "not possible" during a protocol exchange.
X**	EX_NOPERM -- You did not have sufficient permission to
X**		perform the operation.  This is not intended for
X**		file system problems, which should use NOINPUT or
X**		CANTCREAT, but rather for higher level permissions.
X**		For example, kre uses this to restrict who students
X**		can send mail to.
X**
X**	Maintained by Eric Allman (eric@berkeley, ucbvax!eric) --
X**		please mail changes to me.
X**
X**			@(#)sysexits.h	4.5		7/6/88
X*/
X
X# define EX_OK		0	/* successful termination */
X
X# define EX__BASE	64	/* base value for error messages */
X
X# define EX_USAGE	64	/* command line usage error */
X# define EX_DATAERR	65	/* data format error */
X# define EX_NOINPUT	66	/* cannot open input */
X# define EX_NOUSER	67	/* addressee unknown */
X# define EX_NOHOST	68	/* host name unknown */
X# define EX_UNAVAILABLE	69	/* service unavailable */
X# define EX_SOFTWARE	70	/* internal software error */
X# define EX_OSERR	71	/* system error (e.g., can't fork) */
X# define EX_OSFILE	72	/* critical OS file missing */
X# define EX_CANTCREAT	73	/* can't create (user) output file */
X# define EX_IOERR	74	/* input/output error */
X# define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
X# define EX_PROTOCOL	76	/* remote error in protocol */
X# define EX_NOPERM	77	/* permission denied */
X# define EX_CONFIG	78	/* configuration error */
END_OF_FILE
  if test 4568 -ne `wc -c <'sysexits.h'`; then
    echo shar: \"'sysexits.h'\" unpacked with wrong size!
  fi
  # end of 'sysexits.h'
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
exit 0
exit 0 # Just in case...
