| NNML documentation | Contained in the NNML distribution. |
NNML::Server - a minimal NNTP server
perl -MNNML::Server -e server perl -MNNML::Server -e unspool
NNML::Server server implements a minimal NNTP server. It is (hope-)
fully conformant to rfc977. In addition the commands XOVER and
AUTHINFO are implemented.
Supported commands:
ARTICLE, AUTHINFO, BODY, GROUP, HEAD, HELP, IHAVE, LAST, LIST, MODE, NEWGROUPS, NEWNEWS, NEXT, POST, QUIT, SLAVE, STAT XOVER, XHDR, LIST NEWSGROUPS ng-spec
The main reason for writing this was to synchronize my mail directories
across different hosts. The Mail directories are MH-Style with a .overview
file in each folder and an active file in the base
directory. These are maintained by the Emacs Gnus backend
NNML. To get started, you can generate/update this files using the
overview program. Upon POST and IHAVE commands this files
will also be updated.
To start from scratch use:
touch /tmp/active; perl -MNNML::Server -e 'server(base => "/tmp", port => 3000)'
To export your mh-Mail use:
perl overview -base ~/Mail
perl -MNNML::Server -e 'server(base => "$ENV{HOME}/Mail", port => 3000)'
The command POST and IHAVE honour the Newsgroups header if
not overwritten by the X-Nnml-Groups header. Articles will contain
an appropriate X-Nnml-Groups header when retrieved by message-id.
When the client submits the SLAVE command, all forther post
requests are spooled in $Config-spool> (usually
~/Mail/NNML.spool) for performance reasons. You can process the
spooled articles by submitting the XUNSPOOL command or by calling
perl -MNNML::Server -e unspool
Rejected articles will be saven in $Config-bad> (usually
~/Mail/NNML.bad)
To enable access restrictions use:
perl -MNNML::Auth -e "NNML::Auth::add_user($ENV{LOGANME}, 'passwd', \
'read', 'write', 'admin')"
If base/passwd exists, three levels of authorization are recognized:
Users with permission admin may shut down the server using SHUT.
Also these users may create new groups simply by posting to them.
Permission admin is also required for the XUNSPOOL command.
Users with permission write may use the POST and IHAVE commands.
All other commands require the read permission.
Version 1.06 implements the MODE GZIP command. After submiting this
commands, all articles, heads and bodies will be piped through gzip
-cf | mimencode. The server will recognize post requeste using the
same pipe automatically. This will speed up nnmirror if the line is
sufficiant slow.
The server handles multiple connections in a single thread. So a hung
POST or IHAVE would block all connections. Therfore a post
request is interrupted if the server could not read any bytes for 30
seconds. The Client is notified by message 441. If the client
continues to send the article, it is interpreted by the command loop.
The overview(1) and nnmirror(1) manpages.
Ulrich Pfeifer <pfeifer@ls6.informatik.uni-dortmund.de>
| NNML documentation | Contained in the NNML distribution. |
# -*- Mode: Perl -*- # Server.pm -- # ITIID : $ITI$ $Header $__Header$ # Author : Ulrich Pfeifer # Created On : Sat Sep 28 13:53:36 1996 # Last Modified By: Ulrich Pfeifer # Last Modified On: Tue Apr 1 13:23:28 1997 # Language : CPerl # Update Count : 154 # Status : Unknown, Use with caution! # # (C) Copyright 1996, Universität Dortmund, all rights reserved. # package NNML::Server; use vars qw($VERSION @ISA @EXPORT); use NNML::Connection; use NNML::Config qw($Config); use IO::Socket; use IO::Select; use NNML::Handle; use strict; require Exporter; @ISA = qw(Exporter); @EXPORT = qw(server unspool); $VERSION = do{my @r=(q$Revision: 1.13 $=~/(\d+)/g);sprintf "%d."."%02d"x$#r,@r}; sub server { my %opt = @_; my $port = $opt{port} || $Config->port; if (exists $opt{base}) { $Config->base($opt{base}); } NNML::Auth::_update; # just for the message my $lsn = new NNML::Handle(Reuse => 1, Listen => 5, LocalPort => $port, Proto => 'tcp'); die "Could not connect to port $port: $!\n" unless defined $lsn; my $SEL = new IO::Select( $lsn ); my %CON; my $fh; my @ready; print STDERR "listening on port $port\n"; while(1) { @ready = $SEL->can_read; REQUEST: foreach $fh (@ready) { if($fh == $lsn) { my $new = $lsn->accept; # Create a new socket $CON{$new} = new NNML::Connection $new, $VERSION; $SEL->add($new); } else { my ($cmd, $func, @args); my $fno = fileno($fh); $cmd = $fh->getline(); ($func, @args) = split ' ', $cmd; unless (fileno($fh)) { # client has closed connection without sending 'quitt' printf STDERR "Shuttig down $fh(%d)\n", $fno; delete $CON{$fh}; $SEL->remove($fno); next REQUEST; } $func = lc($func); if ($func eq 'shut') { # shut down the server if (NNML::Auth::perm($CON{$fh}, $func)) { my $fx; print STDERR "Going down\n"; for $fx (keys %CON) { $CON{$fx}->msg(400); $CON{$fx}->close; delete $CON{$fx}; } $SEL->remove($lsn); $lsn->close(); return; } else { $CON{$fh}->msg(480); next REQUEST; } } else { $func = $CON{$fh}->dispatch($func, @args); if ($func eq 'quit') { print STDERR "closed\n"; $SEL->remove($fh); $CON{$fh}->close; delete $CON{$fh}; } } } } } } 1; __END__