chiark / gitweb /
be961eee6431ca79d979c7750b0a5f4a538341a3
[chiark-utils.git] / scripts / nntpid
1 #!/usr/bin/perl
2
3 # Originally by Simon Tatham
4 # Modified by Richard Kettlewell, Colin Watson, Ian Jackson
5
6 require 5.002;
7 use Socket;
8 use FileHandle;
9
10 $verbose=1, shift @ARGV if $ARGV[0] eq "-v";
11
12 $ns=$ENV{'NNTPSERVER'};
13 if (!defined $ns or !length $ns) {
14   $ns = `cat /etc/nntpserver`;
15   chomp($ns);
16 }
17 $port = (getservbyname("nntp", "tcp"))[2];
18 $ns = inet_aton($ns);
19 $proto = getprotobyname("tcp");
20 $paddr = sockaddr_in($port, $ns);
21
22 socket(S,PF_INET,SOCK_STREAM,$proto) or die "socket: $!";
23 connect(S,$paddr) or die "connect: $!";
24
25 S->autoflush(1);
26
27 &getline;
28 $code =~ /^2\d\d/ or die "no initial greeting from server\n";
29
30 &docmd("MODE READER");
31 # some servers require a GROUP before an ARTICLE command
32 &docmd("GROUP misc.misc");
33
34 if(@ARGV == 0) {
35   while(<>) {
36     s/(^\s+|\s+$)//gs;
37     lookup($_);
38   }
39 } else {
40   while (@ARGV) {
41     my $item = shift @ARGV;
42     if($item !~ /[\@:]/ and not defined $group) {
43       # maybe a bare group followed by an article number
44       die unless @ARGV;
45       my $number = shift @ARGV;
46       $item = "$item $number";
47     }
48     lookup($item);
49   }
50 }
51
52 &docmd("QUIT");
53 close S;
54
55 sub lookup {
56   my $mid = shift;
57
58   if($mid !~ /\@/ and $mid =~ /^(.*)[: ](\d+)$/) {
59       my ($g, $n) = ($1, $2);
60       &docmd("GROUP $g");
61       &docmd("ARTICLE $n");
62   } else {
63       $mid =~ s/.*\<//;
64       $mid =~ s/\>.*//;
65       &docmd("ARTICLE <$mid>");
66   }
67
68   my $fh= 'STDOUT';
69   if (-t $fh) {
70     my $lesscmd= $ENV{'NNTPID_PAGER'};
71     $lesscmd= 'less' unless defined $lesscmd;
72     open LESS, "|-", 'sh','-c',$lesscmd or die $!;
73     $fh= 'LESS';
74   }
75   
76   while (1) {
77     &getline;
78     s/[\r\n]//g;
79     last if /^\.$/;
80     s/^\.//;
81     print $fh "$_\n";
82   }
83
84   if ($fh ne 'STDOUT') {
85     close $fh or die "$? $!";
86   }
87 }
88
89 sub putline {
90   my ($line) = @_;
91   print STDERR ">>> $line\n" if $verbose;
92   print S "$line\r\n";
93 }
94
95 sub getline {
96   $_ = <S>;
97   s/[\r\n]*$//s;
98   $code = substr($_,0,3);
99   print STDERR "<<< $_\n" if $verbose;
100 }
101
102 sub docmd {
103   my ($cmd) = @_;
104   for my $n (0,1) {
105     &putline($cmd);
106     &getline;
107     if ($code eq "480") { &auth; } else { last; }
108   }
109   $code =~ /^2\d\d/ or die "failed on `$cmd':\n$_\n";
110 }
111
112 sub auth {
113   # Authentication.
114   if ($ENV{"NNTPAUTH"}) {
115     $auth = $ENV{"NNTPAUTH"};
116     &putline("AUTHINFO GENERIC $auth");
117     pipe AUTHSTDIN, TOAUTH or die "unable to create pipes";
118     pipe FROMAUTH, AUTHSTDOUT or die "unable to create pipes";
119     $pid = fork;
120     if (!defined $pid) {
121       die "unable to fork for authentication helper";
122     } elsif ($pid == 0) {
123       # we are child
124       $ENV{"NNTP_AUTH_FDS"} = "0.1";
125       open STDIN, "<&AUTHSTDIN";
126       open STDOUT, ">&AUTHSTDOUT";
127       close S;
128       exec $auth;
129     }
130     # we are parent
131     close AUTHSTDIN;
132     close AUTHSTDOUT;
133     autoflush TOAUTH 1;
134     &getline; print TOAUTH "$_\n";
135     while (<FROMAUTH>) {
136       s/[\r\n]*$//s;
137       &putline($_);
138       &getline;
139       print TOAUTH "$_\n";
140     }
141     die "failed authentication\n" unless $? == 0;
142   }
143 }