#!/usr/local/bin/perl
#
# $Header: /home/pat/perl/RCS/pnews,v 0.5 1993/08/23 19:51:26 pat Exp pat $
#
# pnews - Perl News (or maybe Pats News)
# a simple NNTP news posting client
#
# references:
# RFC 850
# RFC 977
#
#
#
# server connection code taken from pgnews written by
# Jeffrey B. McGough mcgough@wrdis01.af.mil
#
#
# bug reports, fixes, fan mail, cash donations to:
# pryan@stx.com (patrick m. ryan)
#
eval 'exec perl $0 -S ${1+"$@"}'
if $running_under_some_shell;
($version,$patchlevel) = ($] =~ /(\d+)\.(\d+)/);
if ($version >= 5) { # Perl 5
$cmd = "use Socket";
eval { $cmd; }
} else { # Perl 4
eval {
sub AF_INET {2;}
sub PF_INET {2;}
sub SOCK_STREAM {2;} #1
}
}
require 'getopts.pl';
require 'ctime.pl';
require 'date.pl';
&Getopts('h:s:dt');
$rcsid = q!$Id: pnews,v 0.5 1993/08/23 19:51:26 pat Exp pat $!;
$v = (split(/\s+/,$rcsid))[2];
$version = "pnews [v. $v]";
print "This is $version\n\n"; # toot our own horn
if ($opt_d)
{ print $rcsid,"\n"; }
# hostname must be available
chop($host = `hostname`);
if (!$host) { die "could not determine hostname\n"; }
# if we do not contain a "." then assume we are not a FQDN
if ($host !~ /\./)
{
$domain = "gsfc.nasa.gov";
if (!$domain) { die "no domain set\n"; }
$host .= ".$domain";
$host =~ s/\.+/./g; # remove any redundant .s
}
$fullname = (getpwuid($<))[6];
if ($fullname =~ /,/) # strip out any extra gcos stuff
{
$fullname = (split(/,/,$fullname))[0];
}
# get user name
$user = (getpwuid($<))[0] ||
## getlogin() ||
$ENV{USER} || $ENV{LOGNAME} ||
die "who are you?\n";
# get user home directory
$home = (getpwuid($<))[7] || $ENV{HOME} ||
die "you are homeless!\n";
# connect with the NNTP server
$port = 119; # for NNTP
$nntpserver = $opt_h || $ENV{NNTPSERVER};
if (!$nntpserver && -f '/etc/nntpserver')
{
chop ($nntpserver = `cat /etc/nntpserver`);
}
if (!$nntpserver) { $nntpserver='localhost'; } # last resort
# Pack format...
$sockaddr = 'S n a4 x8';
$DOMAIN = 2;
$STYLE = 1;
$rin = $rout = '';
($name, $aliases, $proto) = getprotobyname('tcp');
($name, $aliases, $type, $len, $hostaddr) = gethostbyname($nntpserver);
$sock = pack($sockaddr, $DOMAIN, $port, $hostaddr);
$SIG{'ALRM'} = 'handler';
alarm(60);
print "connecting to $nntpserver...";
##socket(S, $DOMAIN, $STYLE, $proto) || die $!;
socket(S, &PF_INET, &SOCK_STREAM, $proto) || die $!;
connect(S, $sock) || die $!;
select(S); $| = 1; select(STDOUT);
alarm(0);
print "\n";
# set up for select
vec($rin, fileno(S), 1) = 1;
# this select will block until the server gives us something.
$nfound = select($rout=$rin, undef, undef, 900);
if ($nfound == 0)
{
print "Socket timed out...";
exit 1;
}
$SIG{'QUIT'} = 'handler';
$SIG{'INT'} = 'handler';
$status = ; # read one line to see if we established a good connection.
if ($opt_d) { print $_; }
if ($status !~ /^20[01]/)
{
print;
print S 'quit\n';
$status && print $status;
## die "Service unavailable";
exit 1;
}
if ($opt_t) # just test a few things
{
while (@ARGV) # send arguments to NNTP server
{
$cmd = shift(@ARGV);
print "sending command \"$cmd\"\n";
print S $cmd,"\n";
# watch out. not all commands end in \n.\n
while () # get response from command
{
if (/^\./) { last; }
print;
}
}
exit 0;
}
if ($status =~ /^201/)
{
print STDERR "sorry, no posting allowed on host $nntpserver\n";
exit 1;
}
$tmpdir = $ENV{TMPDIR} || '/tmp';
$tmp = $tmpdir . '/.pinews.t.'.$$;
$art = $tmpdir . '/.pinews.a.'.$$;
$editor = $ENV{VISUAL} || $ENV{EDITOR} || "vi";
$dead = $home."/dead.article";
# list of required headers from RFC850
%headers = (
'From','',
'Date','',
## 'Relay-Version','',
## 'X-Newsreader','',
'X-Posting-Version',$version,
'Newsgroups','',
'Subject','',
'Message-ID','',
'Path','',
);
###$header{'NNTP-Posting-Host'} = $host;
$headers{From} = "$user@$host";
if ($fullname)
{ $headers{From} .= " ($fullname)"; }
# grab personal headers, if any
$prc = $home."/.prc";
$sig = $home."/.signature";
%my_headers=();
if ( -f $prc )
{
(%my_headers) = &split_headers($prc);
@my_headers = keys(%my_headers);
foreach (@my_headers) # stick them into the big list
{ $headers{$_} = $my_headers{$_}; }
}
# now ask the user for a few headers
@ask_headers = (); # make a list of headers for which to ask
# use these as newsgroups
if (@ARGV)
{
$headers{Newsgroups} = join(',',@ARGV);
}
else
{
push(@ask_headers,'Newsgroups');
}
# check to see if subject was specified
if ($opt_s)
{
$headers{Subject} = $opt_s;
}
else
{
push(@ask_headers,'Subject');
}
foreach (@ask_headers)
{
print "$_: ";
$r="";
until ($r)
{
$r = ;
chop $r;
}
$headers{$_} = $r;
}
# try to weed out any junk from the Newsgroups line
$headers{Newsgroups} =~ s/\s+//g;
$headers{Newsgroups} =~ s/,+/,/g;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)
= gmtime(time);
@months=('Jan','Feb','Mar','Apr','May','Jun',
'Jul','Aug','Sep','Oct','Nov','Dec');
$TZ='GMT';
$mon = $months[$mon];
if ($year < 1900) { $year += 1900; }
$mon = $months[$mon];
$d = sprintf "%2d %s %4d %02d:%02d:%02d",$mday,$mon,$year,$hour,$min,$sec;
$headers{Date} = $d;
if ($opt_d)
{
print "\nheaders:\n";
while (($key,$value) = each %headers)
{
print "\t$key: $value\n";
}
}
# construct header stuff
@edit_headers = (Newsgroups,Subject,@my_headers);
@sys_headers = (From,Date,'X-Posting-Version');
if ($opt_d)
{
print "edit headers: ";
foreach (@edit_headers) { print "$_ "; }
print "\n";
}
$head = '';
foreach (@edit_headers)
{
$head .= "$_: $headers{$_}";
if ($headers{$_} !~ /\n$/) # if necessary, append a newline
{ $head .= "\n"; }
}
# touch the file so that it is not world readable
open(TMP,">$tmp");
chmod(0600,$tmp);
close TMP;
# open it again and stick in the headers
open(TMP,">$tmp");
print TMP $head;
print TMP "\n"; # blank line after header
close TMP;
# invoke the editor for create the article
$cmd = "$editor $tmp";
if ($opt_d) { print $cmd,"\n"; }
system $cmd;
if ($?>>8) # error from system()
{
print STDERR "error executing \"$cmd\"\n";
if ( -s $tmp )
{
&save_article($tmp,$dead);
}
unlink $tmp;
print S "quit\n";
exit 1;
}
# ask what to do with the article
$done=0;
until ($done)
{
print "(p)ost, (i)spell, (e)edit, (q)uit? (p) ";
chop ($r = );
$r =~ s/^\s*//;
if ($r =~ /i/i)
{
$cmd = "ispell $tmp";
if ($opt_d)
{ print $cmd,"\n"; }
system $cmd;
}
elsif ($r =~ /q/i)
{
print "ok. not posting\n";
&save_article($tmp,$dead);
unlink $tmp;
print S 'quit\n';
exit 0;
}
elsif ($r =~ /e/i)
{
$cmd = "$editor $tmp";
if ($opt_d) { print $cmd,"\n"; }
system $cmd;
}
elsif ($r =~ /p/i || $r eq '')
{
$done=1;
}
else
{
print "$r: unrecognized command\n";
}
}
# now try to send the article
print "posting article...\n";
# put everything in another temp file
open(ART,">$art");
close ART;
chmod(0600,$art);
open(ART,">$art");
print S "post\n";
$_ = ;
if ($opt_d) { print $_; }
# check reply value
foreach (@sys_headers)
{
print ART "$_: $headers{$_}\n";
}
open(TMP,"<$tmp") || die;
while ()
{
if ($_ eq ".\n")
{ print ART "..\n"; } # this looks like an EOT marker
else
{ print ART $_; }
}
if ( -f $sig && -r $sig ) # append .sig file
{
open(SIG,"<$sig");
print ART "--\n";
while ()
{ print ART $_; }
close SIG;
}
print ART "\n.\n"; # send EOT marker
close TMP;
close ART;
# now actually send the article
open(ART,"<$art");
while() { print S $_; }
close ART;
$_ = ;
if ($opt_d) { print $_; }
if ($_ !~ /^240/)
{
print STDERR $_;
&save_article($art,$dead);
}
else
{
print "article posted\n";
}
print S "quit\n";
unlink $tmp;
unlink $art;
exit 0;
sub handler
{
local($sig) = @_;
print "\nCaught a SIG$sig--aborting\n";
unlink $tmp;
exit(0);
}
#
# [this was yanked out of my .deliver file]
# generates an associative array containing all of the header
# information from a mail message.
#
# bugs:
# doesn't handle multiple instances of the same field.
# right now, it just concatenates them.
# usually, this doesn't matter.
sub split_headers
{
local($file)=@_;
local(%headers,$tmp,@lines);
# swallow the entire header file. yum, yum...
open(HEADER,"<$file");
@lines=;
close(HEADER);
%headers=();
while (@lines)
{
$_ = shift(@lines);
if (/^\s*\n$/o) { last; } # this is an empty line
# split header line as "field: value"
## ($field,$value) = /^([^:]+):\s*(.*\n)/o ;
($field,$value) = split(/\s*:\s*/,$_,2);
if (( !$field ) || (!$value)) { next; } # unrecognized header
$tmp='';
# need to change field to all same case?
# append multiply defined headers
$headers{$field} .= $value;
# append any continuation lines
while ($lines[0] =~ /^\s+/o)
{
$headers{$field} .= shift(@lines);
}
}
#
return (%headers);
}
sub save_article
{
local($tmp,$dead) = @_;
$ok=1;
open(DEAD,">$dead") || die "couldn't save article\n";
print DEAD "\n";
open(TMP,"<$tmp");
while ()
{
print DEAD $_;
}
close TMP;
close DEAD;
chmod(0600,$dead);
print STDERR "saved article in $dead\n";
return;
}
# Local Variables:
# mode: perl
# End:
|