=head1 NAME

innfeed, imapfeed - Multi-host, multi-connection, streaming NNTP feeder

=head1 SYNOPSIS

B<innfeed> [B<-ChmMvxyz>] [B<-a> I<spool-dir>] [B<-b> I<directory>]
[B<-c> I<config-file>] [B<-d> I<log-level>] [B<-e> I<bytes>]
[B<-l> I<logfile>] [B<-o> I<bytes>] [B<-p> I<pid-file>] [B<-s> I<command>]
[B<-S> I<status-file>] [I<file>]

=head1 DESCRIPTION

B<innfeed> implements the NNTP protocol for transferring news between
computers.  It handles the standard IHAVE protocol as well as the
CHECK/TAKETHIS streaming extension.  B<innfeed> can feed any number of
remote hosts at once and will open multiple connections to each host if
configured to do so.  The only limitations are the process limits for open
file descriptors and memory.

As an alternative to using NNTP, INN may also be fed to an IMAP server.
This is done by using an executable called B<imapfeed>, which is identical
to B<innfeed> except for the delivery process.  The new version has two
types of connections: an LMTP connection to deliver regular messages and
an IMAP connection to handle control messages.

Used in conjunction with delayer(8), B<innfeed> can send a delayed feed to
remote peers or to another local instance of B<innd>, notably to permit the
rejection of spam before it actually arrives.

=head1 MODES

B<innfeed> has three modes of operation: channel, funnel-file and batch.

Channel mode is used when no filename is given on the command line,
the I<input-file> keyword is I<not> given in the config file, I<and>
the B<-x> option is I<not> given.  In channel mode, B<innfeed> runs with
stdin connected via a pipe to B<innd>.  Whenever B<innd> closes this pipe
(and it has several reasons during normal processing to do so), B<innfeed>
will exit.  It first will try to finish sending all articles it was in
the middle of transmitting, before issuing a QUIT command.  This means
B<innfeed> may take a while to exit depending on how slow your peers are.
It never (well, almost never) just drops the connection.  The recommended
way to restart B<innfeed> when run in channel mode is therefore to tell
B<innd> to close the pipe and spawn a new B<innfeed> process.  This can
be done with C<< ctlinnd flush I<feed> >> where I<feed> is the name of
the B<innfeed> channel feed in the F<newsfeeds> file.

Funnel-file mode is used when a filename is given as an argument or the
I<input-file> keyword is given in the config file.  In funnel-file mode,
it reads the specified file for the same formatted information as B<innd>
would give in channel mode.  It is expected that B<innd> is continually
writing to this file, so when B<innfeed> reaches the end of the file, it
will check periodically for new information.  To prevent the funnel file
from growing without bounds, you will need to periodically move the file
to the side (or simply remove it) and have B<innd> flush the file.  Then,
after the file is flushed by B<innd>, you can send B<innfeed> a SIGALRM,
and it too will close the file and open the new file created by B<innd>.
Something like:

    innfeed -p <pathrun in inn.conf>/innfeed.pid my-funnel-file &
    while true; do
        sleep 43200
        rm -f my-funnel-file
        ctlinnd flush funnel-file-site
        kill -ALRM `cat <pathrun>/innfeed.pid`
    done

Batch mode is used when the B<-x> flag is used.  In batch mode, B<innfeed>
will ignore stdin, and will simply process any backlog created by a
previously running B<innfeed>.  This mode is not normally needed as
B<innfeed> will take care of backlog processing.

=head1 CONFIGURATION

B<innfeed> expects a couple of things to be able to run correctly: a
directory where it can store backlog files and a configuration file to
describe which peers it should handle.

The configuration file is described in innfeed.conf(5).  The B<-c> option can
be used to specify a different file, and B<-b> to specify a different backlog
directory.  The I<backlog-*> keys in the configuration file parameterize the
behaviour of backlogging.  For each peer (say, C<foo>), B<innfeed> manages up
to 4 files in the backlog directory:

=over 2

=item *

A F<foo.lock> file, which prevents other instances of B<innfeed> from
interfering with this one.

=item *

A F<foo.input> file which has old article information B<innfeed> is reading
for re-processing.

=item *

A F<foo.output> file where B<innfeed> is writing information on articles
that could not be processed (normally due to a slow or blocked peer).  Every
I<backlog-rotate-period> seconds, B<innfeed> checks whether it is not empty,
and, if no F<foo> file exists and F<foo.input> is empty, will then rename
F<foo.output> to F<foo.input> and start reading from it.

=item *

A F<foo> file that is never created by B<innfeed>, but if B<innfeed> notices
it when checking every I<backlog-newfile-period> seconds, it will rename it to
F<foo.input> at the next opportunity (every I<backlog-rotate-period> seconds
if F<foo.input> is empty) and will start reading from it.  This lets you
create a batch file and put it in a place where B<innfeed> will find it.

=back

You should never alter the F<foo.input> or F<foo.output> files of a running
B<innfeed>.  The format of these last three files is one of the following:

    /path/to/article <message-id>
    @token@ <message-id>

This is the same as the first two fields of the lines B<innd> feeds to
B<innfeed>, and the same as the first two fields of the lines of the batch
file B<innd> will write if B<innfeed> is unavailable for some reason.
When B<innfeed> processes its own batch files, it ignores everything after
the first two whitespace separated fields, so moving the B<innd>-created
batch file to the appropriate spot will work, even though the lines have
extra fields.

The first field can also be a storage API token.  The two types of lines
can be intermingled; B<innfeed> will use the storage manager if appropriate,
and otherwise treat the first field as a filename to read directly.

B<innfeed> writes its current status to the file F<innfeed.status> (or
the file given by the B<-S> option).  This file contains details on the
process as a whole, and on each peer this instance of B<innfeed> is managing.

If B<innfeed> is told to send an article to a host it is not managing,
then the article information will be put into a file matching the pattern
F<innfeed-dropped.*>, with part of the file name matching the pid of the
B<innfeed> process that is writing to it.  B<innfeed> will not process this
file except to write to it.  If nothing is written to the file, then it
will be removed if B<innfeed> exits normally.  Otherwise, the file remains,
and B<procbatch> can be invoked to process it afterwards.

=head1 SIGNALS

Upon receipt of a SIGALRM, B<innfeed> will close the funnel file specified
on the command line, and will reopen it (see funnel file description above).

B<innfeed> with catch SIGINT and will write a large debugging snapshot of
the state of the running system into a file named F<innfeed.snapshot> in
I<pathlog>.

B<innfeed> will catch SIGHUP and will reload both the config and the
log files.  See innfeed.conf(5) for more details.

B<innfeed> will catch SIGCHLD and will close and reopen all backlog files.

B<innfeed> will catch SIGTERM and will do an orderly shutdown.

Upon receipt of a SIGUSR1, B<innfeed> will increment the debugging level
by one; receipt of a SIGUSR2 will decrement it by one.  The debugging
level starts at zero (unless the B<-d> option it used), in which case no
debugging information is emitted.  A larger value for the level means more
debugging information.  Numbers up to 5 are currently useful.

=head1 SYSLOG ENTRIES

There are 3 different categories of syslog entries for statistics: host,
connection and global.

The host statistics are generated for a given peer at regular intervals
after the first connection is made (or, if the remote is unreachable, after
spooling starts).  The host statistics give totals over all connections
that have been active during the given time frame.  For example (broken
here to fit the page, with C<vixie> being the peer):

    May 23 12:49:08 news innfeed[16015]: vixie checkpoint
        seconds 1381 offered 2744 accepted 1286 refused 1021
        rejected 437 missing 0 accsize 8506220 rejsize 142129
        spooled 990 on_close 0 unspooled 240 deferred 10/15.3
        requeued 25 queue 42.1/100:14,35,13,4,24,10

The meanings of these fields are:

=over 2

=item seconds

The time since B<innfeed> connected to the host or since the statistics
were reset by a C<final> log entry.

=item offered

The number of IHAVE commands sent to the host if it is not in streaming
mode.  The sum of the number of TAKETHIS commands sent when no-CHECK mode
is in effect plus the number of CHECK commands sent in streaming mode
(when no-CHECK mode is not in effect).

=item accepted

The number of articles which were sent to the remote host and accepted by it.

=item refused

The number of articles offered to the host that it indicated it did not
want because it had already seen the message-ID.  The remote host indicates
this by sending a 435 response to an IHAVE command or a 438 response to
a CHECK command.

=item rejected

The number of articles transferred to the host that it did not accept because
it determined either that it already had the article or it did not want it
because of the article's Newsgroups or Distribution header fields, etc.
The remote host indicates that it is rejecting the article by sending a
437 or 439 response after B<innfeed> sent the entire article.

=item missing

The number of articles which B<innfeed> was told to offer to the host but
which were not present in the article spool.  These articles were probably
cancelled or expired before B<innfeed> was able to offer them to the host.

=item accsize

The number of bytes of all accepted articles transferred to the host.

=item rejsize

The number of bytes of all rejected articles transferred to the host.

=item spooled

The number of article entries that were written to the F<.output>
backlog file because the articles either could not be sent to the host
or were refused by it.  Articles are generally spooled either because new
articles are arriving more quickly than they can be offered to the host,
or because B<innfeed> closed all the connections to the host and pushed
all the articles currently in progress to the F<.output> backlog file.

=item on_close

The number of articles that were spooled when B<innfeed> closed all the
connections to the host.

=item unspooled

The number of article entries that were read from the F<.input> backlog file.

=item deferred

The first number is the number of articles that the host told B<innfeed>
to retry later by sending a 431 or 436 response.  B<innfeed> immediately
puts these articles back on the tail of the queue.

The second number is the average (mean) size of deferred articles during
the previous logging interval

=item requeued

The number of articles that were in progress on connections when B<innfeed>
dropped those connections and put the articles back on the queue.
These connections may have been broken by a network problem or became
unresponsive causing B<innfeed> to time them out.

=item queue

The first number is the average (mean) queue size during the previous
logging interval.  The second number is the maximum allowable queue size.
The third number is the percentage of the time that the queue was empty.
The fourth through seventh numbers are the percentages of the time that
the queue was >0% to 25% full, 25% to 50% full, 50% to 75% full, and 75%
to <100% full.  The last number is the percentage of the time that the
queue was totally full.

=back

If the B<-z> option is used (see below), then when the peer stats are
generated, each connection will log its stats too.  For example, for
connection number zero (from a set of five):

    May 23 12:49:08 news innfeed[16015]: vixie:0 checkpoint
        seconds 1381 offered 596 accepted 274 refused 225
        rejected 97 accsize 773623 rejsize 86591

If you only open a maximum of one connection to a remote, then there will
be a close correlation between connection numbers and host numbers, but
in general you cannot tie the two sets of number together in any easy or
very meaningful way.  When a connection closes, it will always log its stats.

If all connections for a host get closed together, then the host logs its
stats as C<final> and resets its counters.  If the feed is so busy that
there is always at least one connection open and running, then after some
amount of time (set via the config file), the host stats are logged as final
and reset.  This is to make generating higher level stats from log files,
by other programs, easier.

There is one log entry that is emitted for a host just after its last
connection closes and B<innfeed> is preparing to exit.  This entry contains
counts over the entire life of the process.  The C<seconds> field is from the
first time a connection was successfully built, or the first time spooling
started.  If a host has been completely idle, it will have no such log entry.

    May 23 12:49:08 news innfeed[16015]: decwrl global
        seconds 1381 offered 34 accepted 22 refused 3 rejected 7
        missing 0 accsize 81277 rejsize 12738 spooled 0 unspooled 0

The final log entry is emitted immediately before exiting.  It contains a
summary of the statistics over the entire life of the process.

    Feb 13 14:43:41 news innfeed[22344]: ME global
        seconds 15742 offered 273441 accepted 45750 refused 222008
        rejected 3334 missing 217 accsize 93647166 rejsize 7421839
        spooled 10 unspooled 0

=head1 OPTIONS

B<innfeed> takes the following options.

=over 4

=item B<-a> I<spool-dir>

The B<-a> flag is used to specify the top of the article spool tree.
B<innfeed> does a chdir(2) to this directory, so it should probably be an
absolute path.  The default is I<patharticles> as set in F<inn.conf>.

=item B<-b> I<directory>

The B<-b> flag may be used to specify a different directory for backlog
file storage and retrieval, as well as for lock files.  If the path is
relative, then it is relative to I<pathspool> as set in F<inn.conf>.
The default is C<innfeed>.

You are encouraged to use the I<backlog-directory> parameter in the
configuration file to declare a specific directory, as otherwise B<news.daily>
won't get it and some maintenance operations on the backlog directory won't
be performed.

=item B<-c> I<config-file>

The B<-c> flag may be used to specify a different config file from the
default value.  If the path is relative, then it is relative to I<pathetc>
as set in F<inn.conf>.  The default is F<innfeed.conf>.

Note that if you use a different name than the default one, and also change
the default setting of I<log-file> or I<pid-file> in the configuration
file, B<scanlogs> will not be able to rotate the debug log files (their
names are searched in F<innfeed.conf> and F<innfeed-delayed.conf>).
Other maintenance operations performed by B<news.daily> won't also be done if
I<backlog-directory> is changed from its default in a configuration file named
differently.

=item B<-C>

The B<-C> flag is used to have B<innfeed> simply check the config file,
report on any errors and then exit.

=item B<-d> I<log-level>

The B<-d> flag may be used to specify the initial logging level.
All debugging messages go to stderr (which may not be what you want,
see the B<-l> flag below).

=item B<-e> I<bytes>

The B<-e> flag may be used to specify the size limit (in bytes) for the
F<.output> backlog files B<innfeed> creates.  If the output file gets
bigger than 10% more than the given number, B<innfeed> will replace the
output file with the tail of the original version.  The default value is
C<0>, which means there is no limit.

=item B<-h>

Use the B<-h> flag to print the usage message.

=item B<-l> I<logfile>

The B<-l> flag may be used to specify a different log file from stderr.
As B<innd> starts B<innfeed> with stderr attached to F</dev/null>, using
this option can be useful in catching any abnormal error messages, or any
debugging messages (all "normal" errors messages go to syslog).

You are encouraged to use the I<log-file> parameter in the configuration file
to declare a specific file name, as otherwise B<scanlogs> won't get it and the
log file won't be rotated.

=item B<-m>

The B<-m> flag is used to turn on logging of all missing articles.
Normally, if an article is missing, B<innfeed> keeps a count, but logs no
further information.  When this flag is used, details about message-IDs
and expected path names are logged.

=item B<-M>

If B<innfeed> has been built with mmap support, then the B<-M> flag turns
OFF the use of mmap(); otherwise, it has no effect.

=item B<-o> I<bytes>

The B<-o> flag sets a value of the maximum number of bytes of article data
B<innfeed> is supposed to keep in memory.  This does not work properly yet.

=item B<-p> I<pid-file>

The B<-p> flag is used to specify the file name to write the pid of
the process into.  A relative path is relative to I<pathrun> as set in
F<inn.conf>.  The default is F<innfeed.pid>.

You are encouraged to use the I<pid-file> parameter in the configuration file
to declare a specific file name, as otherwise B<scanlogs> won't get it and the
log file won't be properly flushed before being rotated.

=item B<-s> I<command>

The B<-s> flag specifies the name of a command to run in a subprocess and
read article information from.  This is similar to channel mode operation,
only that I<command> takes the place usually occupied by B<innd>.

=item B<-S> I<status-file>

The B<-S> flag specifies the name of the file to write the periodic status
to.  If the path is relative, it is considered relative to I<pathlog>
as set in F<inn.conf>.  The default is F<innfeed.status>.

=item B<-v>

When the B<-v> flag is given, version information is printed to stderr
and then B<innfeed> exits.

=item B<-x>

The B<-x> flag is used to tell B<innfeed> not to expect any article
information from B<innd> but just to process any backlog files that exist
and then exit.

=item B<-y>

The B<-y> flag is used to allow dynamic peer binding.  If this flag is
used and article information is received from B<innd> that specifies an
unknown peer, then the peer name is taken to be the IP name too, and an
association with it is created.  Using this, it is possible to only have
the global defaults in the F<innfeed.conf> file, provided the peer name
as used by B<innd> is the same as the IP name.

Note that B<innfeed> with B<-y> and no peer in F<innfeed.conf> would cause
a problem that B<innfeed> drops the first article.

=item B<-z>

The B<-z> flag is used to cause each connection, in a parallel feed
configuration, to report statistics when the controller for the connections
prints its statistics.

=back

=head1 BUGS

When using the B<-x> option, the config file entry's I<initial-connections>
field will be the total number of connections created and used, no matter
how many big the batch file, and no matter how big the I<max-connections>
field specifies.  Thus a value of C<0> for I<initial-connections> means
nothing will happen in B<-x> mode.

B<innfeed> does not automatically grab the file out of I<pathoutgoing>.
This needs to be prepared for it by external means.

Probably too many other bugs to count.

=head1 ALTERNATIVE

An alternative to B<innfeed> can be
B<innduct>, maintained by Ian Jackson and available at
L<http://www.chiark.greenend.org.uk/ucgi/~ian/git-manpage/innduct.git/innduct.8>.
It is intended to solve a design issue in the way B<innfeed> works.
As a matter of fact, the program feed protocol spoken between B<innd>
and B<innfeed> is lossy: if B<innfeed> dies unexpectedly, articles
which B<innd> has written to the pipe to B<innfeed> will be skipped.
B<innd> has no way of telling which articles those are, no useful
records, and no attempts to resend these articles.

=head1 FILES

=over 4

=item I<pathbin>/innfeed

The binary program itself.

=item I<pathetc>/innfeed.conf

The configuration file.

=item I<pathspool>/innfeed

The directory for backlog files.

=back

=head1 HISTORY

Written by James Brister <brister@vix.com> for InterNetNews.  Converted to
POD by Julien Elie.

Earlier versions of B<innfeed> (up to 0.10.1) were shipped separately;
B<innfeed> is now part of INN and shares the same version number.

=head1 SEE ALSO

ctlinnd(8), delayer(8), inn.conf(5), innfeed.conf(5), innd(8), procbatch(8).

=cut
