The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

News::NNTP - NNTP client implementation

SYNOPSIS

 use News::NNTP;

 my $nntp = News::NNTP->new({ 'server' => 'news.supernews.com' });

 my $resp = $nntp->command('group news.software.nntp');

DESCRIPTION

Provides a low-level NNTP client implementation.

"Low-level" means that you just send your NNTP commands as strings and get back responses, rather than hunting for the proper syntax for each command. It also means that the module does as little as possible to get in your way; most responses are simply returned to you to handle as you see fit. You can parse things like overviews and active file entries in whatever way works for you.

Large server responses, like XOVER and LIST ACTIVE responses, can be handled as they come off the wire, and not saved in-core by this module, if you want, and aren't parsed into massive data structures. (Some other Perl NNTP impmementations can consume the system's entire memory and eventually crash just from doing an XOVER.)

The module attempts to handle dropped connections (from an idle timeout on the server, for example) by transparently re-establishing the connection and restoring any necessary state (authentication, current group, etc). So if you sit idle, the server drops the connection, and then you innocently send along a command, it can appear from your end as if the command just worked, without you needing to worry about whether the connection timed out.

You can pass a username and password to the constructor, and the module will authenticate to the server when challenged to do so; however, in the spirit of not getting in your way, you can also just get back the 480 and then send AUTHINFO commands yourself. In the latter case, the module will still remember your username and password for reconnecting later, if needed.

METHODS

new ( server [, username, password ] )
new ( { options } )

Creates an instance of a News::NNTP object and returns it. A connection is opened to the server, and the initial banner response is retrieved. If the socket connection fails, an exception is thrown; if you catch the exception you should have the error in $!. If the connection succeeds but the server returns a 4xx or 5xx response (indicating that you won't be able to go any further), handling it is up to you (you'll get a valid object back).

A server must be provided. Other options can be provided as well; you can give the server, username, and password as regular arguments to the function, or pass a hashref with any of these options:

  server - NNTP server name (required).
  username - authentication for the server.
  password - authentication for the server.
  port - TCP port to connect on (default is 119).
  connect_timeout - socket timeout, passed to IO::Socket::INET.
  trace - a coderef to handle trace information (see below).
  on_error - a coderef to handle fatal errors (see below).

If a username and password are supplied, they will be used to authenticate to the server if any subsequent command returns a 480 response. In that case, you won't get the 480 back, you will simply receive the response to your actual command.

If you do not provide a username or password, and a 480 response is received, it will be returned to you and then you must handle it yourself. In that case you can send AUTHINFO commands, and the username and password you use will be remembered for subsequent use after a dropped connection.

command ( command [, data ...] )
command ( command [, code ] )

Send an NNTP command to the server.

Returns true if the command succeeded (response code 1xx, 2xx, or 3xx), and false otherwise.

The response code, message, and possibly data from a multiline response are stored so you can retrieve them using $nntp->lastcode, $nntp->lastmsg, $nntp->lastresp, and $nntp->data.

If the command was GROUP, then as long as the selected group remains current, you can also retrieve the current group, article count, high-water mark, low-water mark, and current article pointer; see appropriate methods below.

If the command returns multi-line output (ARTICLE, LIST ACTIVE, XOVER, etc), then the data returned is available in $nntp->data. However, if you would prefer not to handle it that way, pass a coderef as the second argument to the method. This code will be called repeatedly, once for each line in the response body, as it is read from the network, and then called with undef as the argument when the response is finished. In this case, the data is NOT stored internally. Note that CRLF pairs are turned into newlines.

If the command was LIST OVERVIEW.FMT, the returned format will be stored for use when parsing overviews using ov_hashref().

If the command requires multi-line input, you can provide it in the function call. Any extra arguments after the command are used, in order, until there are no more. Each argument is taken to be part of the input, and is sent in turn. Linefeeds are turned into CRLF pairs for you, dot-stuffing is done, and you need not (and should not) end the input with a dot-CRLF sequence, as that is done for you as well.

Each of the data arguments can be a simple scalar (taken as-is); a reference to a simple scalar (dereferenced and used); an arrayref (each item is taken and sent, and can be in any of the forms allowed here); or an iterator coderef. An iterator will be called repeatedly until it returns undef to indicate it is exhaused, and each returned value will be sent to the server as it is received (not stored up in memory, so if you have a large amount of data and don't want the module to store it all, this is the way to go).

If you don't provide any multiline data at all, you'll get back the 3xx response and you'll be responsible for sending the data yourself using $nntp->senddata, or $nntp->senddata_partial and $nntp->finish_partial.

data

Returns the multi-line response body from the last command that returned one. This field is wiped out by any subsequent command that returns its own multi-line response, but NOT by other commands. The data is returned as a reference to a list of lines. Lines have trailing newlines (CRLF line terminators are turned into just newlines).

After an ARTICLE command, the return value of $nntp->data can be passed directly to News::Article->new, if desired.

lastcode

Returns the NNTP response code from the last command. This is the three-digit code that begins the response line. Refer to the NNTP spec to see what these mean.

lastcodetype

Returns the first digit of the last NNTP response code received. The first digit is used to determine success or failure of a command. In general, 1xx indicates an informational response (for a HELP command, for example), 2xx is for success, 3xx is for partial success with further input expected, 4xx is for transient errors, and 5xx is for fatal errors.

lastmsg

Returns the message portion of the last NNTP response. This is the rest of the response line after the code is removed.

lastresp

Returns the last NNTP response in full (code, space, message).

lastcmd

Returns the last NNTP command you sent.

curgroup

Returns the currently selected newsgroup, if any.

curart

Returns the current article pointer (article number), if a group is selected.

curgroup_count

Returns the (approximate) number of articles present in the current group, if a group is selected. This is the count as indicated in the GROUP response, and is not guaranteed to be correct (if it is incorrect, the actual number of articles should be lower than this number).

curgroup_lowater

Returns the current group's low-water mark, if a group is selected. This is as returned in the GROUP response.

curgroup_hiwater

Returns the current group's high-water mark, if a group is selected. This is as returned in the GROUP response.

overview_fmt

Returns a listref of fields in the server's overview format. If you have done a LIST OVERVIEW.FMT command during the session, the stored result from that is used; if not, the default is returned, which will be wrong if the server is not using the default (which is uncommon).

drop

Close the NNTP connection and clean up. This will also send a QUIT command to the server, if the connection is still open and valid.

ov_hashref ( line )

Given a line from an overview, return a hashref of header/value pairs. The header names are all in lower-case. If you've done LIST OVERVIEW.FMT during the session, the result from it will be used to parse the overview. If not, the default will be used, which will be wrong if the server is not using the default -- which is uncommon, but it's still good practice to get this from the server.

Entries with the :full suffix will not have that suffix on the hash key, and the header name is removed from the value for you. The article number is in the hash with the key NUMBER (all caps).

(This must be called as an object method on an open session so the format from the server can be used.)

CALLBACK METHODS

These methods are used to set some callbacks for various purposes.

on_error ( code )

Set a function to handle fatal errors. If a fatal error occurs (one that would normally result in an exception being thrown), this function will be called with the error message as its argument. You may also have a system error in $! if one existed.

If your function doesn't die, but instead returns, the NNTP connection could still be left in an inconsistent or unpredictable state, so the connection is dropped, and whatever the module was trying to do will (probably) return undef, and $! should be preserved.

This function does not catch all exceptions, just ones that would be thrown by this module itself as part of error handling.

resphook ( code )

Set a function callback to be called with NNTP command responses. The function will be called for each (single-line) NNTP response received, with the response as the argument. Call with undef to remove the hook.

trace ( code )

Set a function to be called with protocol trace information. The passed function is called with incoming and outgoing NNTP commands and responses as an argument. Outgoing messages are preceded with "-> ", and incoming with "<- ". By default, nothing is done with trace messages. Call with undef to remove the hook.

trace_stderr ( [ remove ] )

Arrange for protocol trace messages to be printed to standard error. This is just a convenience function that calls $nntp->trace with an appropriate callback function. Call with a true argument to remove the trace hook.

CONVENIENCE FUNCTIONS

These convenience functions can be called as object methods, package methods, or directly as function calls, and can be imported from the module by the caller in the usual way.

parse_date ( date )

Given a Date header from a Usenet article, parse it and return a unixtime.

format_date ( unixtime )

Given a unixtime, return a formatted string suitable for use in a Date header. If no time is given, the current time is used.

Note that this function currently depends on the strftime() library function supporting "%z", which has been specified for several years. I don't know how universally implemented this is, though; if it is a problem, let me know and I'll do an internal implementation.

active_group ( line )
active_hiwater ( line )
active_lowater ( line )
active_count ( line )

Given a line from an active file, return either the newsgroup name, the high-water number, the low-water number, or the estimated article count (high minus low) from parsing the line.

cmd_has_multiline_input ( command )

Return true if the given NNTP command expects multi-line input.

cmd_has_multiline_output ( command )

Return true if the given NNTP command returns multi-line output.

LESS-USED METHODS

These probably aren't very useful, but here they are if you need them.

server
username
password
port
connect_timeout

Return or set the corresponding fields (as passed to the constructor). It is probably of limited value to set these values on an already-open connection, but you can pass a new value to be set if you want.

sock

Returns the IO::Socket::INET object being used by this connection. Note that you could do things to it that will confuse this module, so, you know, be careful.

COMMAND AND RESPONSE METHODS

These methods are used internally by $nntp->command, but are here if you really want them. Here there be dragons. You should probably look at the code if you think you want to use these methods.

sendcmd ( command )

Send an NNTP command to the server. You can then read the response using $nntp->getresp. This method will transparently re-establish a dropped connection, but will not do any other magic like authenticating if needed, keeping track of group and article poiners, etc. Returns true on success and false for failure -- note that this means success or failure of sending the command over the network, NOT the application-level success or failure of the NNTP command itself.

If you use this, everything internal to this module that keeps track of the current state (group name, article pointer, etc) may end up in an inconsistent state.

getresp

Read an NNTP response from the server. This will populate lastcode, lastmsg, lastresp, and lastcodetype, but will not handle multi-line responses. This is the most likely place a server-dropped connection will be detected, so it will also try to re-establish a dropped connection if necessary.

getdata ( [ code ] )

Read a multi-line response body from the server. If a coderef is passed, it will be called once for each line of the response, and then called with undef to indicate that it's finished. Otherwise, an arrayref of lines is returned.

senddata ( data ... )

Send multi-line data to the server. Data arguments are specified as described for $nntp->command.

senddata_partial ( data )

Each item from senddata is passed to this function, which sends it to the server. The (single) argument here must be a plain scalar.

finish_partial

After sending multi-line data to the server using senddata_partial, this method finishes the send, including sending the dot-CRLF sequence. It must be called after using senddata_partial, but senddata calls it internally.

STANDARD INPUT/OUTPUT CLIENT

run_on_stdio

Creates an object, opens a connection, and attaches it to standard input and output. Call as a static (package) method, a plain function, or as a method on an existing object (in which case that object is used).

Thus:

perl -MNews::NNTP -e 'News::NNTP::run_on_stdio("server","user","pass")'

creates a connection on your terminal, like telnet news 119. Useful for testing purposes.

STATUS

I consider this code beta-quality, as not all features have been well tested. Bugs are probably present.

LIMITATIONS / TODO

Pipelining of commands is not supported.

If the server's initial response is 4xx or 5xx, responsibility is punted back to the caller. There may be a better way to handle that.

Reading articles line by line may not be the most efficient method possible.

Regression tests are incomplete.

Regression tests need a news server to connect to. They retrieve live data from the server to use for testing, so it's possible for them to fail through no fault of this module if the server returns bad data.

AUTHOR

Jeremy Nixon <jnixon@cpan.org>

LICENSE

This module is released under a BSD license.