#/usr/local/bin/perl #---------------------------------------------------------------------- # variables you might have to change: $nntp_server = "news.cis.umn.edu"; $nntp_port = 119; $nntp_defart = "article"; $nntp_groups = "/etc/go4gw/ACTIVE"; # could be active file $nntp_reverse = 0; # to list articles in reverse order #---------------------------------------------------------------------- @nntp_acl=( # ipaddress group access + = allow, - = deny '^134.84\. .* +', '^128.101\. .* +', '^131.212\. .* +', '^146.57\. .* +', '.* ^clari -', '.* .* +' ); # end of variables # Commands this server responds to: # # "" -> list top level groups # ls [$group] [$range] -> list group's articles and sub-groups # lsa [$group] [$range] -> like "", sends "article" & "lsa" commands back # lsb [$group] [$range] -> "" sends "body" & "lsb" commands back # lsh [$group] [$range] -> "" sends "header" & "lsh" commands back # article -> get article by ID # article $group $number -> get 1 article, number can be "last" or "first", # or any numeric perl expression. # body -> like article, but just get text # body $group $number -> "" # head -> like article, but just get header # head $group $number -> "" # sorry -> send sorry message # # The optional $range arguement has the following format: # n - return 'n' most recent articles # x:y - return articles x through y (inclusive) # x and y can both be numeric perl expressions. The # string 'last' is replaced with the last article in the # group, and the string 'first' is replaced with the first. # first:last - all articles (same as not specifiying a range # last:first - all articles (in reverse order) # last-9:last - return last 10 articles (same as specifiying 10) # last:last-9 - return last 10 articles in reverse order sub nntp_main { local($_) = @_; &do_ls("",$nntp_defart,"ls") if /^$/; &do_ls("",$nntp_defart,"ls") if /^ls\s*$/; &do_ls($1,$nntp_defart,"ls") if /^ls\s+(.*)/i; &do_ls("","article","lsa") if /^lsa\s*$/; &do_ls($1,"article","lsa") if /^lsa\s+(.*)/i; &do_ls("","body","lsb") if /^lsb\s*$/; &do_ls($1,"body","lsb") if /^lsb\s+(.*)/i; &do_ls("","head","lsh") if /^lsh\s*$/; &do_ls($1,"head","lsh") if /^lsh\s+(.*)/i; &do_article($1,$2,"ARTICLE") if /^article\s+(\S+)\s+(\S+)/i; &do_article_id($1,"ARTICLE") if /^article\s+(<.*>)/i; &do_article($1,$2,"HEAD") if /^head\s+(\S+)\s+(\S+)/i; &do_article_id($1,"HEAD") if /^head\s+(<.*>)/i; &do_article($1,$2,"BODY") if /^body\s+(\S+)\s+(\S+)/i; &do_article_id($1,"BODY") if /^body\s+(<.*>)/i; &Gsorry if /^sorry$/; &Gabort("Unknown command!"); exit; } sub do_article_id { local($id,$cmd) = @_; &open_nntp; &Gsend("$cmd $id"); $_ = &Grecv; &Gabort($_) if !/^2/; while() { print; last if /^\.\r\n$/; } &close_nntp; exit; } sub do_article { local($group,$number,$cmd) = @_; if (&check_access($group) eq '-') { &Gsorry; } &open_nntp; &Gsend("GROUP $group"); $_ = &Grecv; &Gabort($_) if !/^2/; ($n,$f,$l) = /\d+\s+(\d+)\s+(\d+)\s+(\d+)/; $number =~ s/first/\$f/g; $number =~ s/last/\$l/g; $number = int(eval($number)); &Gsend("$cmd $number"); $_ = &Grecv; &Gabort($_) if !/^2/; while() { print; last if /^\.\r\n$/; } &close_nntp; exit; } sub list_group { local($group,$type,$range) = @_; &Gsend("GROUP $group"); $_ = &Grecv; &Gabort($_) if !/^211/; ($n,$f,$l) = /211\s+(\d+)\s+(\d+)\s+(\d+)/; if ($range =~ /^(\S+):(\S+)$/) { $low = $1; $high = $2; $low =~ s/first/\$f/g; $low =~ s/last/\$l/g; $high =~ s/first/\$f/g; $high =~ s/last/\$l/g; $low = int(eval($low)); $high = int(eval($high)); if ($low > $l) { $low = $l; } elsif ($low < $f) {$low = $f; } if ($high > $l) { $high = $l; } elsif ($high < $f) {$high = $f; } if ($high < $low) { $f = $high; $l = $low; $nntp_reverse=1; } if ($low <= $high) { $f = $low; $l = $high; $nntp_reverse=0; } } elsif ($range ne '') { $range =~ s/first/\$f/g; $range =~ s/last/\$l/g; $range = int(eval($range)); if ($range >0 && $range < $n) { $f = $l - $range + 1; } } &Gsend("XHDR Subject $f-$l"); $_ = &Grecv; &Gabort($_) if !/^221/; while() { chop; chop; last if /^\.$/; ($article,$subject) = /^(\d+)\s+(.*)/; $subject =~ s/\t/ /g; # just in case! if ($nntp_reverse) { push(@reply,"0$subject\t$Ggw $atype $group $article\t$Ghost\t$Gport"); } else { &Greply("0$subject\t$Ggw $atype $group $article\t$Ghost\t$Gport"); } } if ($nntp_reverse) { for ($i=$#reply; $i!= -1; $i--) { &Greply($reply[$i]); } } &Greply("."); &close_nntp; exit; } sub do_ls { local($prefix,$atype,$lscmd) = @_; local($range); $prefix =~ s/\s+$//; if ($prefix =~ /(\S+)\s+(\S+)/) { $prefix = $1; $range = $2; } elsif (($prefix =~ /^\d+$/) || ($prefix =~ /:/)) { $range = $prefix; $prefix = ""; } if (&check_access($prefix) eq '-') { &Greply("0Sorry! No access off of campus!\t$Ggw sorry\t$Ghost\t$Gport"); &Greply("."); exit; } &open_nntp; &get_groups; foreach ( sort @groups) { if ($_ eq $prefix) { $do_list_group = $_; } elsif (/^$prefix\.([^.]*)\.?/) { $leaf=$1; $save{"$prefix.$leaf"} = "1$leaf\t$Ggw $lscmd $prefix.$leaf $range\t$Ghost\t$Gport"; } elsif ($prefix eq '' && /([^.]*)/) { $save{"$1"} = "1$1\t$Ggw $lscmd $1 $range\t$Ghost\t$Gport"; } } foreach ( sort keys %save) { &Greply($save{$_}); } &list_group($do_list_group,$atype,$range) if ($do_list_group); &Greply("."); &close_nntp; exit; } sub open_nntp { local($_); &GopenServer($nntp_server,$nntp_port); $_ = &Grecv; &Gabort($_) if !/^2/; } sub close_nntp { &Gsend("QUIT"); close(GSERVER); } sub get_groups { if (open(GROUPS,$nntp_groups)) { while() { chop; ($grp) = /^(\S+)/; push(@groups,$grp); } close(GROUPS); } else { # can't open file, get list from server! &load_groups; } } sub load_groups { &open_nntp; &Gsend("LIST"); $_ = &Grecv; &Gabort($_) if !/^215/; while() { chop; chop; last if /^\.$/; s/^(\S+).*/$1/; push(@groups,$_); } } sub create_groups { &load_groups; open(GROUPS,">$nntp_groups") || die "$nntp_groups: $!"; foreach (@groups) { print GROUPS "$_\n"; } close GROUPS; &close_nntp; exit; } sub check_access { local($group)=@_; return 1 if (-t STDIN); $sockaddr = 'S n a4 x8'; $mysockaddr = getpeername(STDIN); ($ramily,$rport,$raddr) = unpack($sockaddr,$mysockaddr); ($a,$b,$c,$d) = unpack('C4',$raddr); $ipaddress = "$a.$b.$c.$d"; foreach (@nntp_acl) { ($ipacl,$groupacl,$access)=split; return $access if ($ipaddress =~ /$ipacl/) && ($group =~ /$groupacl/); } return '-'; #default is to restrict access } 1; # for require