This is Info file pm.info, produced by Makeinfo version 1.68 from the
input file bigpm.texi.


File: pm.info,  Node: News/AutoReply,  Next: News/FormArticle,  Prev: News/Article,  Up: Module List

derivative of News::Article for generating autoreplies
******************************************************

NAME
====

   News::AutoReply - derivative of News::Article for generating autoreplies

DESCRIPTION
===========

   Like News::Article, but must be given a reference to another article at
creation time - initialises To, In-Reply-To, References etc.  correctly as
an automatic reply.

USAGE
=====

     use News::AutoReply;

   Exports nothing.

Constructor
===========

new ( ORIGINAL )
     Construct an autoreply to a message, assuming that the Reply-To (if
     present, otherwise the From) header of `ORIGINAL' is valid.

     Returns a new Article object with no body or envelope sender, but with
     suitable headers.

     If an environment variable LOOP is defined, it is used as the contents
     of an X-Loop header added to the reply (this is useful when using this
     code in progs launched from a procmail recipe). Always preserves
     X-Loop headers in the original.

     The reference-folding code could probably be improved.

AUTHOR
======

   Andrew Gierth <andrew@erlenstar.demon.co.uk>

SOURCE
======

   Contact the author.

COPYRIGHT
=========

   Copyright 1997 Andrew Gierth <andrew@erlenstar.demon.co.uk>

   This code may be used and/or distributed under the same terms as Perl
itself.


File: pm.info,  Node: News/FormArticle,  Next: News/FormReply,  Prev: News/AutoReply,  Up: Module List

derivative of News::Article
***************************

NAME
====

   News::FormArticle - derivative of News::Article

DESCRIPTION
===========

   Like News::Article, but designed to be constructed from a file
containing form text with substitutions.

   Currently, the source text is substituted as follows:

   Variables are denoted by $NAME or @NAME (where NAME is any simple
identifier). (The sequences $$ and @@ denote literal $ and @ characters.)
Variables of the form $NAME are expected to supply scalar values which are
interpolated; variables of the form @NAME are expected to supply lists (or
references to arrays) which are interpolated with separating newlines.

   Values of variables are found by consulting the list of sources
supplied. Each source may be either a reference to a hash, or a reference
to code.

   Source hashes may contain as values either the desired value (scalar or
reference to array), or a typeglob, or a code reference which will be
called to return the result. (Since typeglobs are allowed values, it is
possible to supply a reference to a module symbol table as a valid source.)

   Code references supplied as sources are invoked with the variable name
(including the leading $ or @) as the only parameter. In the degenerate
case, all variables accessible in the source scope may be made available
for interpolation by supplying the following as a source:

     sub { eval shift }

   If multiple sources are supplied, then each is consulted in turn until
a defined value is found.

USAGE
=====

     use News::FormArticle;

   Exports nothing.

Constructor
===========

new ( FILENAME [, SOURCE [...]] )
     Construct an article from the specified file, performing variable
     substitution with values supplied by the SOURCE parameters (see
     Description).

AUTHOR
======

   Andrew Gierth <andrew@erlenstar.demon.co.uk>

COPYRIGHT
=========

   Copyright 1997 Andrew Gierth <andrew@erlenstar.demon.co.uk>

   This code may be used and/or distributed under the same terms as Perl
itself.


File: pm.info,  Node: News/FormReply,  Next: News/Gateway,  Prev: News/FormArticle,  Up: Module List

derivative of News::FormArticle and News::AutoReply
***************************************************

NAME
====

   News::FormReply - derivative of News::FormArticle and News::AutoReply

DESCRIPTION
===========

   This is a "mixin" of News::FormArticle and News::AutoReply; it
generates form replies by performing substitutions on a text file.

USAGE
=====

     use News::FormReply;

   Exports nothing.

Constructor
===========

new ( ORIGINAL, FILENAME [, SOURCE [...]] )
     Construct an article as a reply to `ORIGINAL', initialised from the
     specified file, performing variable substitution with values supplied
     by the SOURCE parameters (see News::FormArticle).

     The Subject, To, References and In-Reply-To headers are setup after
     the template has been read and substituted, but a Subject header set
     in a template will not be overridden.

AUTHOR
======

   Andrew Gierth <andrew@erlenstar.demon.co.uk>

COPYRIGHT
=========

   Copyright 1997 Andrew Gierth <andrew@erlenstar.demon.co.uk>

   This code may be used and/or distributed under the same terms as Perl
itself.


File: pm.info,  Node: News/Gateway,  Next: News/NNTPClient,  Prev: News/FormReply,  Up: Module List

Tools for gatewaying messages between news and mail.
****************************************************

NAME
====

   News::Gateway - Tools for gatewaying messages between news and mail.

SYNOPSIS
========

     use News::Gateway;
     my $gateway = News::Gateway->new (1, 'user@example.com');
     $gateway->modules ('headers', mailtonews => ['misc.test']);
     $gateway->config_file ('/path/to/config/file');
     $gateway->read (\*STDIN);
     my $error = $gateway->apply ();
     if ($error) { $gateway->error ($error) }
     $error = $gateway->post ();
     if ($error) { $gateway->error ($error) }

DESCRIPTION
===========

   This module is a collection of tools to allow gatewaying of mail
messages into newsgroups or vice versa.  It's written to be extremely
modular and extendable, so that any modification or check of incoming
messages can be dropped in.  It's intended to be usable for both a
straight gateway or a robomoderator, or even as the front end and
supporting tool set for human moderation.

   The module is intended to take input from three different sources:  an
incoming message, a set of modules that contain checks or modifications to
be performed to that message, and a configuration file that affects the
behavior of the modules.  Each module can list one or more configuration
directives that it takes, and then when those directives are encountered
in the configuration file, they're parsed and and handed off to the
module.  Then, after the message has been read in, its headers and body
are given to each module in turn, so that they can perform whatever tests
and make whatever modifications they were designed to do.

   A message is represented internally as a News::Article object that each
module has access to, allowing the headers or body to be read and
manipulated.

CONSTRUCTOR
===========

new (INTERACTIVE [, MAINTAINER [, SENDER]])
     This builds a new News::Gateway object.  `INTERACTIVE' is a true/false
     flag specifying whether the program is running interactively.  If
     true, the error() method will call die in the event of an error;
     otherwise, it will attempt to send mail to the maintainer and the
     sender of the message.  MAINTAINER is the e-mail address of the
     maintainer of the gateway, defaulting to the user the program is
     running as if not supplied.  SENDER is the envelope sender which
     should be used for all mail sent through News::Gateway, defaulting to
     MAINTAINER if not supplied.

METHODS
=======

   First, the standard methods in the order in which they are normally
called.  Some of these methods, like modules(), are normally called only
once, while others, like read(), may be called multiple times for multiple
incoming messages.  You'll almost certainly also want to read about the
config(), `config_file()', and post() directives below in `"UTILITY
MODULES"' in this node.

modules (MODULE [ => ARGUMENTS ] [, ...])
     Sets the list of modules that should be applied to each incoming
     message.  The list of modules is cumulative; in other words,
     modules() can be called multiple times to add more modules to the
     list of ones which will be applied.  This method both adds each
     supplied module name to the list of modules that will be run if
     `apply()' is called with no arguments and sets up callbacks so that
     any configuration directives that MODULE is interested in will be
     passed along to it when configuration directives are processed.

     Some modules may take arguments; if so, they can be passed in as an
     anonymous array associated with the module.  For example:

          $gateway->modules (mailtonews => ['misc.test']);

     adds mailtonews to the list of modules and passes in `misc.test' as an
     argument to it.

     Modules will be run in the order they are given to modules().

     modules() should always be called before any call to `apply()',
     config(), or `config_file()' that those modules are supposed to
     affect.

read (SOURCE [, MAXSIZE [, MAXHEAD]])
     Reads in a new message from the supplied source, which can be a file
     name, a file handle, or even an anonymous sub which will be called
     repeatedly for each line of the message until it returns undef.
     `MAXSIZE', if given, specifies the maximum size in bytes of the
     article body, and `MAXHEAD', if given, specifies the maximum size in
     bytes of the article headers.  `MAXSIZE' defaults to 256KB and
     `MAXHEAD' defaults to 8KB.

     This method returns the total number of bytes read if successful, or
     undef in the case of an error.

     This method constructs a new News::Article object and calls its
     method, so it will always support essentially the same arguments as
     the corresponding News::Article read() method.

apply (MODULES)
     This method hands the message off to each module given (if no modules
     are given, the message is given to each module registered by
     modules() in the order in which they were given to modules()) and
     lets them do whatever they wish with the article.  If a module
     returns undef, it's presumed to be successful and the message is
     given to the next module.  If a module returns a string, it's
     considered to be a failure message and `apply()' stops.

     If all modules succeed, `apply()' returns undef or the empty list.
     If a module fails, `apply()' returns a list consisting of the module
     which failed and the message it failed with in a list context; or a
     string consisting of the name of the module, a colon, a space, and
     the message it failed with in a scalar context.

     The calling script should then look at the failure message and take
     the appropriate action.

   The following additional methods are also supplied, some of which are
mostly intended for internal use.

error (ERROR)
     Handles a fatal error.  If the `INTERACTIVE' flag passed to new() was
     true, this method just calls die with the error message.  Otherwise,
     it calls `mail_error()' (part of the standard mail module), which
     attempts to mail the maintainer and the sender of the message.  If
     that fails, for whatever reason, News::Gateway calls exit with the
     right status code for a mail bounce.

     This method should be used *only* for fatal, unrecoverable errors,
     particularly when `INTERACTIVE' isn't true, since it could bounce
     mail or notify the wrong person of problems.  It's a last resort that
     goes to great lengths to try to keep the message from being lost.

get_article ()
     An accessor method that returns the underlying News::Article object.

set_article (ARTICLE)
     Takes a News::Article object and makes that the underlying message in
     that instance of News::Gateway, discarding the old one if any.

REWRITE MODULES
===============

   The following modules to perform checks or rewrites of messages are part
of the standard distribution.  To use them with a News::Gateway object,
pass them (along with anonymous arrays for their options, if any) to the
modules() method.

anykeyword
----------

   This module requires that every incoming message have at least one
keyword on the subject line.  For the purposes of this check, a keyword is
defined as anything that matches:

     /^(?:Re:\s+)?\[\S+\]/

   (in other words, something without spaces enclosed in square brackets at
the beginning of the subject line modulo any Re:).  If no keyword is found
in the incoming message, this module returns the message:

     No keyword found

   This module takes no arguments or configuration directives.

bodyheaders
-----------

   Extracts headers from the beginning of a message body and lifts them up
into the message headers.  This is to assist posters whose software makes
it difficult for them to edit the headers of their posts or mail.

   This module looks for recognized headers at the beginning of the article
body.  As long as it's seen only blank lines (possibly containing
whitespace) and recognized headers, it adds all of those headers to the
main message headers.  As soon as it finds a line that isn't a recognized
header, it stops, and if it found any headers it removes everything up to
the first non-header line from the body.

   This module takes one configuration directive:

bodyheaders HEADER [HEADER ...]
     A list of headers to look for in the beginning of the body.  The
     headers are not case sensitive, and any amount of whitespace
     (including none) is allowed after the colon.

   For example, with the directive:

     bodyheaders x-no-archive

   and a message beginning with:

     x-no-archive:yes

     Comment: hello

   an X-No-Archive header with content "yes" will be added to the message
headers and the first line of the message body after this module runs will
be the line starting with "Comment:".  Had "comment" also been listed in
the configuration directive, that header would have been lifted into the
article headers as well and this module would have continued looking.

   Whitespace on the line before the header is not allowed, and such a line
would not be recognized as a header to be lifted to the message headers.

   This module takes no arguments and cannot fail.

cleanbody
---------

   This module checks the body of an incoming article and cleans it up,
attempting to enforce standard ISO 8859-1 text.  If it's encoded in
quoted-printable, that encoding is undone.  Microsoft Word SmartQuotes are
converted into their ASCII equivalents, any Ctrl-Ms are removed, and the
module checks to make sure that the message contains no invalid characters
(outside of the standard ISO 8859-1 range) and that no lines are longer
than 79 characters.

   The messages returned by the checks in the event of failure are:

Invalid characters in body
     The body contains characters outside the range [\s!-~\xa0-\xff].

Line over 79 characters
     One or more lines in the body are over 79 characters long.

   This module takes no arguments or configuration directives.  If the
original message was in quoted-printable, it will change the
Content-Transfer-Encoding header to be "8bit".  It recognizes
quoted-printable from the MIME encoding headers.

crosspost
---------

   Limits crossposting and followups.  This module takes, in some ways, the
opposite approach from the newsgroups module; rather than listing
newsgroups which are allowed, it allows one to set a limit on the number
of groups crossposted, on the number of groups to which followups would
go, and on which groups can be crossposted to or to which followups can be
directed.

   A group can be excluded from the Newsgroups header or from the
Followup-To header in one of two ways; either messages posted to that
group or messages that direct followups to a set of newsgroups including
that group can be rejected, or that group can be silently removed from the
Newsgroups and/or Followup-To headers.  The latter behavior is generally
not recommended for robomoderators, since moderators are generally
discouraged to make decisions about where posts should be posted for the
poster.  Returning the post and asking the poster to choose a more
appropriate set of groups is generally a better approach.

   This module will remove a Followup-To header (and not add one) if its
content is/would be identical to the Newsgroups header.

   This module takes the following configuration directives:

crosspost max COUNT
     Reject any message crossposted to more than `COUNT' newsgroups.

crosspost remove|reject GROUP
     Either remove `GROUP' silently from the Newsgroups header if present
     or reject all articles crossposted to `GROUP'.

followup max COUNT
     Reject any messages that would direct followups to more than `COUNT'
     newsgroups, bearing in mind that if no Followup-To header is present,
     followups would go to all groups in the Newsgroups header.

followup remove|reject GROUP
     Either remove `GROUP' silently from the followups if present or reject
     all articles crossposted to `GROUP'.

   This module may return one of the following failure messages:

Invalid crosspost to %s
     The message was crossposted to a group mentioned in a `crosspost
     reject' directive.

Followups would go to %s
     Followups to the message would go to a group mentioned in a `followup
     reject' directive.

Excessively crossposted
     The message was crossposted to more groups than allowed by a
     `crosspost max' directive.

Followups would go to too many groups
     Followups to the message would go to more groups than allowed by a
     `followup max' directive.

   This module works with a Newsgroups header, so if other modules need to
be applied to construct the Newsgroups header, they should run before this
one.  This module takes no arguments.

headers
-------

   This module implements some general header rewriting functions,
including adding, dropping, and renaming headers and replacing header
contents.  It takes one configuration directive:

header HEADER FUNCTION [ CONTENT ]
     Specify an action on the header `HEADER'.  FUNCTION can be any of the
     following:  drop deletes a header, rename renames the original header
     to X-Original-HEADER retaining the same value, ifempty adds a header
     with content CONTENT if and only if the message doesn't already
     contain a header `HEADER', replace replaces all existing `HEADER'
     headers with one containing CONTENT, prepend adds CONTENT to the
     beginning of the first header `HEADER' or creates a new header
     `HEADER' with content CONTENT if none already exists, and reject
     returns an error if `HEADER' is present in the incoming message.

     CONTENT can contain various special variables:  $n will be replaced
     with the name of the running program, `$v' will be replaced with the
     version of News::Gateway, and $i will be replaced with a unique
     identifier formed from the current time and the process ID.  $$ will
     be replaced with `$', so to put a literal dollar sign in a header, you
     should use $$.

   For example, suppose you have a configuration file with the following
directives:

     header organization add     SNAP
     header message-id   rename
     header sender       drop
     header comment      replace $n $v
     header subject      ifempty no subject (thread id $i)

   and suppose you have an incoming message with the headers:

     Organization: Restaurant Reviews
     Message-ID: <123142@bar.org>
     Sender: foo@bar.org
     Comment: Hello
     Comment: Hello again

   After the headers module runs, the message will have a header of:

     Organization: Restaurant Reviews
     Organization: SNAP
     X-Original-Message-ID: <123142@bar.org>
     Comment: PROGRAM VERSION
     Subject: no subject (thread id ID)

   where `PROGRAM' is the name of the running program (ie, $0), VERSION is
the version of News::Gateway, and ID is a unique identifier as described
above.

   This module may fail and call error() with the following message while
reading the configuration directives:

Unknown header rewrite action %s
     A rewrite action was specified that isn't among those that are
     supported.  This probably indicates a typo.

   This module may fail in one way:

Invalid header %s
     A header that was associated with a reject action in a configuration
     directive was present in the incoming message.  Note that the header
     will be given in all lowercase.

   As a side note, if you're constructing a robomoderator for a newsgroup,
dropping or renaming the Path header in incoming messages is highly
recommended.  It turns out that some news servers will add a Path header
with their hostname before remailing the message to a moderator, and if
you keep that Path header when you post, the article will never propagate
back to the site of the original poster.

keywords
--------

   This module checks the Subject header of a message and ensures that it
starts (modulo an initial Re:) with a valid keyword.  By default, the
following keyword formats are supported:

     KEYWORD:
     KEYWORD/KEYWORD:
     [KEYWORD]
     [KEYWORD/KEYWORD]
     [KEYWORD][KEYWORD]

   If multiple keywords are given, they all have to be valid.  Keywords are
checked against a list given in a file and are case-insensitive.

   This module takes one optional argument, a reference to a sub which, if
given a subject line, returns a list of all the keywords present.  This
can be used to override the default patterns listed above.

   There is one required configuration file directive:

keywords FILENAME
     Specifies the file from which the list of valid keywords will be read.
     The file should list all valid keywords, one per line.

   Two failure messages are possible:

No keywords found
     There were no keywords in the subject header of the message.

Invalid keyword '%s'
     A keyword was found that wasn't in the list of valid keywords.

mailpath
--------

   Generates an X-Mail-Path header from the Received headers of a mail
message.  It attempts to figure out the real name of each host that the
mail passed through based on the standard comment syntax used by most
mailers, but this problem is inherently impossible to solve completely.

   X-Mail-Path is set to a !-separated list of hosts that the mail has
passed through.  If from the Received headers the name of a host appears
to be trusted, it's given; otherwise the name followed by the IP address in
brackets is given.  If the IP address isn't available, "[UNTRUSTED]" is
appended.

   The envelope sender is added to the end of the X-Mail-Path if known; if
not, "UNKNOWN" is added instead.

   mailpath takes no arguments or configuration directives and cannot fail.

mailtonews
----------

   Performs a variety of rewrites, changes, and checks necessary to do the
basic conversion of a mail message into a news message.  Most of this
involves deleting or renaming headers that a news server will not accept
or would overwrite and making sure that the required news headers are
present.

   This module does the following:  Checks to ensure there is a From
header; compacts the From header down to one line if it contained any
continuation lines since INN can't deal with continuation lines in a From
header; adds a Newsgroups header with the default group if none is
present, or checks the Newsgroups header for validity and removes
duplicate groups if one is present; drop the headers Lines, Received,
Relay-Version, and Xref which will be rejected or overwritten by the news
server; renames the headers NNTP-Posting-Host and Sender to be prefixed
with X-Original- since new ones will be generated; adds a new Sender
header pointing to the maintainer (set in the News::Gateway constructor);
renames the Message-ID header to X-Original-Message-ID if the message ID
is syntactically invalid for a news message (this will cause a new message
ID to be generated by the server); checks the In-Reply-To header if
present to see if it contains something that looks like a message ID and
if so adds it to the end of the References header if and only if it
doesn't duplicate the message ID on the end of the References header; and
sets the subject of the article to the value "(none)" if there is no
Subject header.

   This module takes one argument, the default newsgroup to post to.  A
Newsgroups header containing this group will be added if no Newsgroups
header is present in the incoming message.  This argument is optional, but
if you're gating mail messages to news messages you'll pretty much always
want to supply it.  While it's tempting to assume that all submissions to
a moderated group will already have a Newsgroups header added by the news
server, you'll find in practice that people will often mail submissions
directly to the submission address, or that news servers won't handle
things in the way that you would expect.

   This module (possibly combined with the headers module) may be
sufficient for generating the Newsgroups header if the program only
handles one newsgroup, but any more complicated situation will probably
require that a module (such as the newsgroups module) be run before this
one to generate the Newsgroups header.

   There are three possible failure messages which may be returned;

Empty body
     The body of the message was empty.  Most news servers will reject
     messages with an empty body.

Missing required From header
     The incoming message doesn't have a From header.  A From header is
     required for all messages.

No Newsgroups header or default group
     The incoming message didn't have a Newsgroups header and no argument
     was supplied to the module.  If you don't supply an argument
     specifying the default newsgroup, all incoming messages must have a
     Newsgroups header before this module is run, since a Newsgroups
     header is mandatory in a news article.

   This module takes no configuration directives.

moosesign
---------

   Does simple PGPMoose signing of messages.  This module is not a full
implementation of PGPMoose; in particular, it doesn't support all of the
crosspost handling.  It looks through the groups in the Newsgroups header
and adds a PGPMoose X-Auth header for every group in the Newsgroups header
for which a PGP key has been given.

   This module takes one configuration directive, which associates a PGP
key ID and passphrase with a newsgroup:

pgpkey NEWSGROUP PASSPHRASE KEYID
     Associates the given `KEYID' and `PASSPHRASE' with `NEWSGROUP'.
     `KEYID' is optional and will default to the name of the newsgroup
     surrounded by spaces if not given.  (This default will allow PGP to
     find the key correctly if the key ID is something like "Moderator for
     group.name <address>" while avoiding confusing group.name and
     group.name.other.)

   Note that using this module means putting the PGP passphrases for the
moderation keys in cleartext in the configuration file or in the script.

   This module takes no arguments and cannot fail.

mungeids
--------

   Programmatically munges the message IDs in the Message-ID and References
headers by adding a slash-separated list of newsgroups to which the
article is going to be posted, followed by a slash, to the beginning of
them.  We also strip off any prefix that looks like a prefix we'd generate
(any number of strings that could be a newsgroup name, separated by
slashes) to prevent threads with replies from readers of multiple
mungeid'd groups from generating constantly-growing message IDs and to
hopefully still get threading right.  For the purposes of this check, we
assume newsgroup names will contain at least one period; this module may
not work correctly for newsgroup names that do not.

   The purpose of this is for use with mailing list to newsgroup gateways.
Since messages to multiple mailing lists may all have the same message ID,
and since the same mailing list may be gated to Usenet in multiple places,
the message IDs of incoming mailing list messages need to be munged in
some fashion before being passed on to Usenet.  Ideally, however,
threading should be preserved, and replies to mailing list messages from
other people on the mailing list won't refer to the munged message ID.
This module therefore applies the same munge to all of the message IDs in
the References header as well, in the hope of maintaining threading and
still getting message ID uniqueness.

   If the message doesn't already have a Message-ID header, this module
will generate one.

   Since an accurate Newsgroups header is needed to correctly munge the
IDs, this module should run after any modules responsible for generating
that.  It also needs the final Message-ID and References header, so it
should run after the mailtonews module since that module may promote
message IDs from In-Reply-To into References and discard existing
Message-ID headers.

   This module takes one optional configuration directive:

mungeids REGEX [REGEX ...]
     `REGEX' is a regex matching newsgroups which should be used to make up
     the prefix that we'll be adding to message IDs.  If this configuration
     directive is supplied, then only newsgroups matching one of the
     supplied regexes will be used to construct the prefix.  By default,
     all newsgroups in the Newsgroups header will be used in the prefix.

   mungeids takes no arguments and cannot fail.

newsgroups
----------

   Construct the Newsgroups header for a message.  This is the general
module for this purpose, and is considerably more flexible than the simple
handling built into the mailtonews module.

   The guiding purpose of this module is to attempt to deal with
crossposting correctly in the context of a generic mail to news gateway
(where incoming mail messages may not, unlike submissions for moderated
groups, already have Newsgroups headers in them).  We're ambitious,
though, and try to also handle the case where we do have an incoming
Newsgroups header.

   All of the gory details of what this module does in every circumstance
are documented in the comment block at the beginning of the code.  If
you're really curious, I'd recommend reading that.  It's far more
information than most people are going to want to know.  Here's the
briefer summary:

   The program tells this module what the primary newsgroup is.  This
should be the group to which we should post by default.  In other words,
suppose you have several different mail to news gateway addresses for
several different groups which all feed into the same program.  To use this
module, configure such a system so that the program knows what address a
given message arrived via (either by having access to the envelope
recipient through using qmail, using procmail as a delivery agent, or some
other method, or by having each mail to news gateway alias give the
program the name of its primary newsgroup on the command line).  The
program tells this module what group that is by providing it as an
argument to the module.

   We also have a list of associations between addresses and newsgroups
given to us in configuration directives.  An address can either be a
literal address (which will be matched exactly, albeit without regard to
case) or a regex.  Note that although this module wants to know about as
many of those associations as possible, it can deal with not knowing about
them all and will generally do the right thing.  It will just tend to
multipost when it could have crossposted unless it knows which addresses
correspond to which newsgroups.

   If the incoming message doesn't have a Newsgroups header, this module
will construct one by inspecting the To and Cc headers and seeing where the
message was sent.  If the primary group corresponds to one of the
addresses in the To and Cc headers, then it will crosspost between the
groups corresponding to the recognized addresses in the To and Cc headers
(with the caveat given below).  Otherwise, it assumes that the address via
which we received the message either is one we don't know about or was
Bcc'd and posts only to the primary group.

   There is one problem with this.  If a message is addressed to a number
of different addresses, all of which eventually gate to a newsgroup, if all
of those gateways do this analysis and crosspost, the article ends up
multiposted (one copy for each group crossposted to).  The solution to
this problem is for one of the instances of the gateway program decide to
post and all of the other ones exit quietly.  We support this by returning
the error "Not primary instance" if the primary group is in the list
formed from the To and Cc headers but isn't the first group in that list.
We assume that we'll also get the mail going to the address corresponding
to the first group in that list, and that instance will do the
crossposting.  A program using this module should probably exit silently
if we return "Not primary instance".

   If the message does contain a Newsgroups header, then what we do depends
on whether our primary group is among the groups in that header, and
whether any of the addresses in the To or Cc headers correspond to groups
in that header.  The exact rules are very complicated (see the source
comments), but we ignore the Newsgroups header entirely if neither the
primary group nor the groups corresponding to addresses in the To and Cc
headers occur in it, honor it if the primary group is in it, and post only
to the groups corresponding to addreses in the To and Cc headers that
aren't in the Newsgroups header if some addresses in the To and Cc headers
correspond to groups in the Newsgroups header but our primary group isn't
in that header.  We also return "Not primary instance" where appropriate
to ensure that a post to a given set of newsgroups is only done once.

   (Yes, this is a simplification.  See the source comments for the real
complexity.)

   We also rename Message-ID to X-Original-Message-ID if we have some
expectation that otherwise we'll clash with another post (either made by
another instance of the same program or posted elsewhere).  We also rename
Newsgroups to X-Original-Newsgroups if we don't honor the supplied header.
Note that this module goes to some length to avoid renaming Message-ID
unless necessary; if you want to drop all incoming message IDs and
generate new ones, you should do that using the headers module.

   We take an argument specifying the primary group, and we take one
configuration directive in one of three forms:

group NEWSGROUP [ ADDRESS | /PATTERN/ ]
     Adds `NEWSGROUP' to the list of valid newsgroups and optionally
     associates it with either `ADDRESS' or PATTERN.  `ADDRESS' is a
     literal string that (case-insensitively) exactly matches the address
     associated with `NEWSGROUP'.  PATTERN is a Perl regex that matches
     addresses associated with `NEWSGROUP'.

group /PATTERN/
     Tells this module to consider any newsgroup matching PATTERN to be
     valid to crosspost to.  Note that this directive doesn't set up any
     address to group mappings, just changes what groups are allowed in a
     pre-existing Newsgroups header.

group FILE /PATTERN/
     Tells this module to add all newsgroups matching PATTERN in the file
     FILE to the list of valid newsgroups for crossposts.  Note that this
     directive doesn't set up any address to group mappings, just changes
     what groups are allowed in a pre-existing Newsgroups header.  FILE
     must be an absolute path (i.e., it must begin with /).

   In all of the above, the /s around PATTERN arguments are required, as
they allow unambiguous parsing of the configuration file directives.

   There are three possible failure messages returned by this module:

Invalid crossposted group %s
     The incoming message already had a Newsgroups header which included a
     group that wasn't on the list of allowable newsgroups for
     crossposting.

Not primary instance
     Although the primary group is among the groups we would normally post
     to, it isn't the "first" such group.  This probably means that
     multiple copies of the message were received by different gateways
     and this instance should exit silently since another instance will be
     doing the posting.

   In addition to that, there are two possible fatal errors that can occur
during the parsing of the configuration file and a third at the time of
parsing the incoming message.  These errors are passed to the
News::Gateway error() method.

Invalid regex /%s/: %s
     An error occurred while compiling the given regex from a PATTERN
     argument to a configuration directive.

Can't open group file %s: %s
     An error occurred while attempting to open a file from a FILE argument
     to a configuration directive.

newsgroups module missing required argument
     The newsgroups module requires an argument giving the primary
     newsgroup, or all of the tricks we use to figure out crossposting and
     where to post won't work correctly.

newstomail
----------

   Rewrites a news article into a mail message, using a set of newsgroup to
e-mail address mappings to determine which addresses to mail the resulting
message to.

   This module does the following:  Checks to make sure there's a
Newsgroups header; drops Bcc and Resent-Bcc headers in the message;
renames To, Cc, Apparently-To, Resent-To, Resent-Cc, Return-Path, and
Sender headers (if present) to the same name prefixed by X-Original- since
they may be misinterpreted by e-mail software, and sets a new To header
consisting of the e-mail addresses corresponding to all the groups in the
Newsgroups header that have defined mappings.  Duplicate addresses are
stripped out.

   This module takes one configuration file directive:

newstomail FILENAME
     Specifies the file from which the list of newsgroup to address
     mappings should be read, in the form newsgroup, whitespace, address.
     If the filename ends in .db, then the file will be assumed to be a
     Berkeley database instead, with newsgroups as the keys and addresses
     as the values.

   Two failure messages are possible:

Missing required Newsgroups header
     The incoming message doesn't have a Newsgroups header.  This module
     only handles posts and needs the Newsgroups header to determine what
     addresses to which to send the message.

No newsgroup with a mapping
     None of the newsgroups in the Newsgroups header had a mapping to an
     e-mail address, so there's nowhere to send the message.

   This module takes no arguments.

nobinaries
----------

   Checks the message to see if it is or contains a binary and rejects it
if it is.  The following checks are performed:  Ensure that no Content-Type
header in the headers or the body contains the strings "application",
"image", "audio", or "video"; ensure that no Content-Transfer-Encoding
header in the headers or the body is equal to "base64", and ensure that
encoded lines do not exceed 50% of the number of lines in the body for any
article with at least 40 lines.

   An encoded line is defined as a line beginning with an M (with optional
leading whitespace or quoting characters) and exactly 60 or 61 characters
in length, or a line containing no spaces, not starting with M or ~, and
between 59 and 80 characters in length.

   Lines meeting those criteria are counted separately (the first as
potential uuencoding, the second as potential base64 encoding), and if the
count of lines in any one category is over half of the total body lines,
the message is rejected.

   The rejection messages are:

base64 encoded
     The message contains a Content-Transfer-Encoding header with a value
     of "base64".

Invalid content type
     The message contains a Content-Type header that contains one of the
     strings "application", "image", "audio", or "video".

Apparently uuencoded
     The message body is at least 40 lines and more than 50% of those lines
     start with M (modulo whitespace and quoting) and are exactly 60 or 61
     characters long.

Apparently base64-encoded
     The message body is at least 40 lines and more than 50% of those lines
     contain no spaces, do not begin with M or ~, and are between 59 and 80
     characters long.

   This article takes no arguments or configuration directives.

previoushop
-----------

   Adds the previous host through which a mail message passed to the Path
header of the message.  It does this by looking through the raw Received
headers, finding the first Received header that specifies a host from
which the message was received, and prepending it to the Path header (or
creating a new Path header if none already exists).

   If no Received headers that contain a "from" clause are found (which may
be the case for mail originating locally), nothing is done.

   The reason for this module is to support news to mail and mail to news
gateways for the same unmoderated newsgroup.  If the mail to news address
is subscribed to a mailing list and posts to the newsgroup are sent back
to the mailing list, a loop will be created unless something is done to
stop it.  One method of stopping such loops is to alias the hostname of
the mailing list machine out of the feed to the news to mail gateway in
the news server and then use this module to put the hostname of the
mailing list machine in the Path of all articles posted through the mail
to news gateway.

   This module takes no arguments or configuration directives and cannot
fail.

whitelist
---------

   Checks to make sure that the incoming message is from a poster in a file
of valid posters.  The most common use of this module is in conjunction
with human moderation; all messages from pre-approved posters are sent
straight through via the robomoderator and the rest are relayed to a human
moderator for hand checking.

   This module takes one configuration directive:

whitelist FILE
     FILE is a list of poster addresses, one per line.  Only the address
     should be included in this file, not the name or other comments.
     Files ending in `.db' are reserved for future implementations
     (eventually, these will automatically be recognized as Berkeley db
     files for handling large lists of posters).

   There is one possible failure message:

Unknown poster %s
     The message is from a poster address which isn't in the whitelist of
     known addresses.

   In addition, during parsing of the configuration directives, one fatal
error, which would be passed to error(), is possible:

Can't open whitelist file %s: %s
     An error occurred while trying to open a file given as a FILE argument
     to a configuration directive.

   This module takes no arguments.

UTILITY MODULES
===============

   The following modules are also part of the standard distribution.
Rather than rewrite or check messages, they provide additional methods
that can be used by programs, other modules, even or the News::Gateway
core code.  Methods supplied by utility modules can be called like any
other News::Gateway method.

config
------

   This module contains the code for reading and parsing configuration
directives and calling the appropriate module callback hooks.  Nearly all
News::Gateway programs will make use of this module.

   WARNING: Information in configuration directives is *trusted* by
modules, and modules may go so far as to eval things from configuration
directives as Perl code.  This means that anyone who has access to the
configuration directives read by this module has as much control over what
a program does as someone who can edit the source.  Any necessary sanity
or security checking on the content of configuration directives must be
done before they are passed off to modules, and `config_file()' does no
such checking.

config (DIRECTIVE, ARGUMENT [, ARGUMENT ...])
     Calls the registered module callbacks for all modules who have
     expressed an interest in `DIRECTIVE'.  This bypasses any parsing, and
     the arguments are given to the callbacks exactly as passed in.
     `DIRECTIVE' is case-insensitive.

config_file (FILE | HANDLE)
     Reads in configuration directives from the supplied file name or file
     handle (which can be either an object reference or a reference to a
     typeglob) until end of file is reached.

     Blank lines and lines beginning with a `#' are ignored.  All other
     lines are parsed into a directive (the first whitespace-separated
     word) and some number of arguments, and then the parse results are
     passed along to the module which has registered interest in that
     directive.  If an argument contains embedded whitespace, it can be
     enclosed in double quotes.  A backslash will escape the next
     character, whatever it is.  A line is considered to be continued on
     the next line if it ends in a backslash, and if the line continuation
     occurs inside double quotes, a literal newline will be part of the
     string.

     For example, the following configuration directive tells the headers
     module to add a new header named X-Comment with the content "This is a
     long comment about this newsgroup":

          header x-comment add \
                 "This is a long comment about this newsgroup"

     Multiple configuration files can be read by calling `config_file()'
     multiple times.  One handy trick for simple scripts using
     News::Gateway is to put the configuration lines at the end of the
     script after an __END__ and then pass them to News::Gateway with:

          $gateway->config_file (\*DATA);

     `config_file()' should be called before any `apply()' it is supposed
     to affect.

config_line (LINE)
     Parses and handles a single configuration line, just as if it were
     read from a file (in fact, `config_file()' calls this method for each
     non-blank, non-comment line).  This can be used to feed individual
     configuration lines to the News::Gateway object without having to
     give it a file or file handle.

config_parse (LINE)
     Parses a configuration file line, returning the results as an array.
     This is the method used by `config_file()' and `config_line()' to
     parse configuration files.  This probably isn't generally useful.

   These methods adds two additional fatal error messages, which may be
passed to error().

Parse error in %s
     A configuration line was unable to be parsed.  The most likely cause
     is unbalanced double quotes.

Unknown configuration directive %s
     News::Gateway encountered a configuration directive that no module had
     expressed interest in.  Chances are you made a typo in your
     configuration file or forgot to register a module with modules() that
     you were planning on using.

mail
----

   This module separates out various functions related to sending mail into
their own module so that it can be autoloaded on demand rather than always
compiled.  The following methods are included:

mail ([ ADDRESS [, ADDRESS ...]])
     The message in its current form will be mailed to `ADDRESS', and the
     method will return true on success, false on failure.  If `ADDRESS' is
     not supplied, the message is mailed to the addresses in the standard
     mail headers (To, Cc, Bcc, and the Resent-* varients depending on
     your MTA), so this method should also be used after news to mail
     rewrites have taken place.

     *NOTE: The old mail_forward() method is DEPRECATED.*

mail_bounce (ERROR)
     Bounces the message by printing ERROR to stderr and then exiting with
     the permanent failure status code (as defined in the beginning of the
     News::Gateway source).  This should only be used as a last resort,
     particularly for robomoderators, since the bounces will go to the
     envelope sender address which is often not the same as the poster.

mail_error (ERROR)
     Attempts to send an error message to the sender of the original
     message, cc'd to the maintainer address.  Replies will be set to the
     maintainer address, the subject will be "failure notice," and a
     Precedence header of "junk" will be added, which can be used to avoid
     loops.

     If no From or Reply-To header has been seen, or if sending the mail
     fails, this method will call mail_bounce() with the same error
     message instead.

     The message sent will be:

          Hi.  I'm afraid that I was unable to post your message.  This
          is a fatal error; I've given up.  A copy of this report is
          being sent to my maintainer.  The error message I received was:

          ERROR

          --- Below this line is a copy of the message.

     followed by the original article headers and the body, with ERROR
     replaced by ERROR.  Note that if ERROR should be word-wrapped in the
     message, this must be done by the caller.

mail_filereply (FILENAME [, SOURCES])
     Mails a News::FormReply-style message to the author of the incoming
     message.  See *Note News/FormReply: News/FormReply, for more
     information.  FILENAME is the path to the file to use to construct
     the reply, and SOURCES for News::FormReply variables can optionally
     be provided.  The following variables are exposed to the form message
     by default:

          @BODY        Message body, possibly munged by previous modules.
          @HEADERS     Current message headers.
          @OLDHEADERS  Original message headers.
          $SUBJECT     Original subject line.
          $MAINTAINER  Maintainer of this gateway.

     Returns true if sending the mail succeeded, false if it failed.

post
----

   Implements all methods related to posting articles.  The following
methods are included:

post ([ SERVER ])
     Posts the article using the NNTP POST command.  Under most
     circumstances, this is how you want to post an article.  SERVER, if
     specified, may be either the name or IP address of a news server to
     use for posting or a reference to an open Net::NNTP connection to be
     used.  undef is returned on success; the error message is returned on
     failure.

     Before this method is called, the message headers should be rewritten
     into ones appropriate for a news message; this is one of the purposes
     of the modules.

post_ihave ([ SERVER ])
     Posts the article using the NNTP IHAVE command.  This connects to a
     news server as a transfer server rather than as a client; under most
     circumstances this is not what you want.  Unless you already know what
     IHAVE is, you may not want to use this.  In order to use this posting
     method, the article already has to have all necessary headers to be a
     properly formatted news article, including Path and Message-ID; unlike
     POST, IHAVE will not automatically fill in missing headers.

     As above, SERVER if specified may be either the name or IP address of
     a news server to use for posting or a reference to an open Net::NNTP
     connection.  undef is returned on success; the error message is
     returned on failure.

post_program (COMMAND [, ARGUMENT ... ])
     Posts the article by running a program and passing the article to it
     on stdin.  This can be used to post via inews or rnews if you so wish,
     although using the post() method is recommended under most
     circumstances.  The arguments to the command should be a list of
     strings; this command does not fork a shell so shell metacharacters
     will not be interpreted as such.

     If the program exits with status 0, success is assumed and this method
     returns undef.  If the program exits with non-zero status or some
     other error occurs, this method returns the output of the program
     (both stdout and stderr) and an error message.  The output and error
     message will be newline-terminated.

DIAGNOSTICS
===========

   In addition to the failure messages generated by modules (listed above),
the following messages may be generated by the News::Gateway core code and
would be passed to the error() method.

Autoload of %s failed: %s
     A method was called that doesn't exist in the core code and was
     unable to be loaded from a module.  Chances are you made a typo when
     referring to a News::Gateway method.

Cannot open file %s: %s
     News::Gateway attempted to open a file (probably the configuration
     file) and failed for the given reason.

Unable to load %s: %s
     One of the modules (either rewrite or utility) you used requires an
     external Perl module and was unable to load it.

Unknown module %s
     You told modules() to load a module that has no hooks registered.
     News::Gateway has to know about every module that it can use; you
     can't just copy in a new module with the others and have it work.
     Instead, put the module in the modules directory before the build
     process.

BUGS
====

   Many.  This is an *alpha* release, with all that's implied by that in
terms of bugs, interface instability, and other such concerns.  Use at
your own risk, but if you encounter a bug please let me know.  Patches in
particular are gratefully accepted.

NOTES
=====

   If you are interested in being notified of new releases, helping with
development, developing, testing, or using new modules, or even just
getting tips on how to use this module, there is a mailing list available.
To subscribe, send mail to majordomo@eyrie.org with:

     subscribe gateway-users

   in the body.

   New patches and modules are always welcome, whether from people on the
list or not, and can be mailed to the address listed below.

SEE ALSO
========

   *Note News/Article: News/Article,

AUTHOR
======

   Russ Allbery <rra@stanford.edu>.

HISTORY
=======

   News::Gateway started as a simple mail to news Perl script, written
right after the cs.utexas.edu mail to news gateway closed and just a quick
hack for the use of people who had previously used that gateway to post to
rec.arts.comics.creative and alt.comics.lnh.  Over time, it became a
general mail to news gateway with a fairly broad set of features.

   Eventually, it became obvious that it really should have been a module
rather than a script, and it also became clear that it could be used as
the core of a robomoderator.  Since there was no real general-purpose
robomoderation software around that was nearly as flexible as I thought a
package should be, I decided to be ambitious and try to solve the general
problem.

   Then I took a complete detour to rewrite the entire thing again to use
Andrew Gierth's News::Article class, which is what I should have been
doing from the beginning.  And now, finally, it's getting closer to what
I'd envisioned.


