#
# nntp.pl
#
# No main program is in this file.
#
# ishii@hexard.co.jp
#
# $Id: nntp.pl,v 1.7 1992/12/09 17:28:04 jik Exp $
#

# load socket package
require "sys/socket.ph";

package nntp;

# PRIVATE: news_command( $command ) -> returned_string
sub news_command {
    local( $r );
    print NEWS (@_[0]."\r\n");
    print STDERR ">".@_[0]."\n" if $main'opt_D;
    $r = <NEWS>;
    print STDERR "<".$r if $main'opt_D;
#	if ($r !~ /^[23]/){
#		($retcode, $reason) = split( /[ \t]+/, $r, 2 );
#		print STDERR @_[0].":".$reason."\n";
#	}
    return $r;
}

# PUBLIC: news_open( $server_name )
sub main'news_open {
    local( $hostname );
    local( $server ) = @_[0];
    local( $name, $aliases, $proto, $port );
    local( $type, $len, $thisaddr, $thataddr );
    local( $this, $that );
    local( $r );
    chop( $hostname = `hostname` );
#
# create socket sturcture
#
    $sockaddr_t = "S n a4 x8";
    ($name, $aliases, $proto) = getprotobyname( "tcp" );
    ($name, $aliases, $port) = getservbyname( "nntp", "tcp" );
    ($name, $aliases, $type, $len, $thisaddr) = gethostbyname( $hostname );
    ($name, $aliases, $type, $len, $thataddr) = gethostbyname( $server );
    $this = pack( $sockaddr_t, &main'AF_INET, 0, $thisaddr );
    $that = pack( $sockaddr_t, &main'AF_INET, $port, $thataddr );
#
# connect with nntp server
#
    socket( NEWS, &main'PF_INET, &main'SOCK_STREAM, $proto ) ||
	die "socket: $!\n";
    bind( NEWS, $this ) || die "bind: $!\n";
    connect( NEWS, $that ) || die "connect: $!\n";
    select( NEWS ); $| = 1; select( STDOUT );
    $r = <NEWS>;
    print STDERR "<".$r if $main'opt_D;
    chop( $r );
    if ($r !~ /^20[01]/){
	die "Sorry, your NNTP connection request was rejected.\n";
    }
    $r = &news_command("MODE READER"); 
    if ($r !~ /^(20[01]|500)/){
        die "Sorry, the mode reader command bombed horribly.\n";
    }
}

# PUBLIC: news_select_ng( $newsgroup_name ) -> (first, last, num)
sub main'news_select_ng {
    local( $ng ) = $_[0];
    local( $cc, $num, $first, $last, $curr );
    ($cc, $num, $first, $last) = split( /[ \t]+/,
				       &news_command( "GROUP ".$ng ) );
    if (($cc !~ /^[23]/)){
	return undef;
    }
    return ( $first, $last, $num );
}

# PUBLIC: news_jump( $article_no ) -> article_no
sub main'news_jump {
    local( $article ) = $_[0];
    local( $cc );
    ($cc, $article) = split( /[ \t]+/, &news_command( "STAT ".$article ) );
    return $article;
}

# PUBLIC: news_previous() -> article_no
sub main'news_previous {
    local( $cc, $article );
    $cc = &news_command( "LAST" );
    if ($cc !~ /^[23]/){ return -1; }
    ($cc, $article) = split( /[ \t]+/, $cc );
    return $article;
}

# PUBLIC: news_next() -> article_no
sub main'news_next {
    local( $cc, $article );
    $cc = &news_command( "NEXT" );
    if ($cc !~ /^[23]/){ return -1; }
    ($cc, $article) = split( /[ \t]+/, $cc );
    return $article;
}

# PUBLIC: news_header_open()
sub main'news_header_open {
    local($r) = &news_command( "HEAD" );
    if ($r !~ /^[23]/){
	($retcode, $reason) = split( /[ \t]+/, $r, 2 );
	print STDERR $retcode.":".$reason."\n";
	return 0;
    }
    $news_stat = 1;
    return 1;
}

# PUBLIC: news_header_next()
sub main'news_header_next {
    local($_);
    if (! ($_ = <NEWS>)) {
	$news_stat = 0;
	return 0;
    }
    print STDERR "<".$_ if $main'opt_D;
    chop; chop;
    if ($_ eq "."){ $news_stat = 0; return 0; }
    return 1;
}

# PUBLIC: news_header_close()
sub main'news_header_close {
    if ($news_stat){
	while (&main'news_header_next){
	}
	$news_stat = 0;
    }
}

# PUBLIC: news_get_header()
sub main'news_get_header {
    local($_);
    &main'news_header_open;
    local(%current);
    while (&main'news_header_next){
	($key, $value) = split( /:\s*/, $_, 2 );
	$value =~ s/^[ \t]+//;
	$current{$key} = $value;
    }
    &main'news_header_close;
    return %current;
}

# PUBLIC: news_body_open()
sub main'news_body_open {
    local($r) = &news_command( "BODY" );
    if ($r !~ /^[23]/){
	($retcode, $reason) = split( /[ \t]+/, $r, 2 );
	print STDERR @_[0].":".$reason."\n";
	return 0;
    }
    $news_stat = 2;
    return 1;
}

# PUBLIC: news_body_next()
sub main'news_body_next {
    local($_);
    if (! ($_ = <NEWS>)) {
	$news_stat = 0;
	return 0;
    }
    print STDERR "<".$_ if $main'opt_D;
    chop; chop;
    if ($_ eq "."){ $news_stat = 0; return 0; }
    return 1;
}

# PUBLIC: news_body_close()
sub main'news_body_close {
    if ($news_stat){
	while (&main'news_body_next){
	}
	$news_stat = 0;
    }
}


sub main'news_xhdr_init {
    local($r) = &news_command("XHDR $_[0] $_[1]");
    if ($r !~ /^[23]/) {
	($retcode, $reason) = split( /[ \t]+/, $r, 2 );
	undef;
    }
    else {
	$news_stat = 2;
	1;
    }
}

sub main'news_xhdr_next {
    local(@F);
    local($_);
    while (1) {
	if (! ($_ = <NEWS>)) {
	    $news_stat = 0;
	    return 0;
	}
	print STDERR "<$_" if $main'opt_D;
	chop; chop;
	if ($_ eq "."){ $news_stat = 0; return undef; }
	@F = split(' ', $_, 2);
	last if ($F[1] ne "(none)");
    }
    @F;
}

sub main'news_close {
    &news_command("QUIT");
    close(NEWS);
}

1;
