#!/afs/athena/contrib/perl/p
#
# File: nntpgrep - search news articles for patterns
# $Header: /afs/sipb/contrib/perl/nntp/RCS/nntpgrep,v 1.1 1992/09/17 04:11:50 ckclark Exp $
# 
# KOPYKNOT (K) 1991 Free Knoware Foundation, Ink.
# 
# This file is part of Randall's NNTP grep-n'-fetch-it utilites.
# 
# NNTP grep-n'-fetch-it is free software.  You can redistribute it and
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation or not.  That's what makes
# this a Kopyknot.  You can use this code for any purpose whatsoever.
# If you can make a dime off it, great.  I'm not out to stop you.  If
# you want to claim you wrote it, great.  It ain't up to me to blow your
# cover.  Go for it.
# 
# NNTP grep-n'-fetch-it is distributed in the hope that it will make
# Randall a famous net.personality.  It includes ABSOLUTELY NO WARRANTY.
# In fact, you should know that this code will probably fail in lots
# of different ways on lots of different machines.  If you want to fix
# the problems, great.  If you want to tell me what you changed, great.
# If you want me to fix something for you, go screw yourself.  I'm busy.
# 
# This Kopyknot was inspired by the GNU Copyleft.  I think that Richard
# Stallman is a mensch.  If I weren't so obsessed by the almighty buck,
# I'd try to get a job working for him.  If you want more information on
# the GNU General Public License, get GNU Emacs, or write to the Free
# Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
# 
# I hope you don't feel insulted by my parody, Richard.

unshift(@INC, "/afs/sipb.mit.edu/contrib/perl");
unshift(@INC, "/afs/sipb.mit.edu/contrib/perl/nntp");

require('getopts.pl');
require('nntp.pl');

$field = "subject";		# grep subject lines by default
$flg = "o";			# compile pattern only once
$opp = "";			# match specified pattern

sub usage
{
    die <<"EndoUsage"
usage: $0 [-<options>] <pattern> <newsgroup> ...
    options:	-s: 		search subjects (default)
		-f: 		search from lines
		-b: 		search article bodies
		-a: 		search entire articles
		-h <field>:	search specified header field
		-i:		case insensitive search
		-v:		match inverse of pattern
		-u:		limit search to unread articles
		-r <range>:	limit search to range
		-F <newsrc>:	use alternate newsrc file
		-S <server>:	use alternate news server
EndoUsage
    ;
}

# process command line arguments
&usage if ! &Getopts('sfbah:ivur:F:S:');

# set the article header field that is to be matched
$field = "article" if $opt_a;
$field = "body" if $opt_b;
$field = $opt_h if $opt_h;
$field = "from" if $opt_f;
$field = "subject" if $opt_s;
$flg = $opt_i ? "io" : "o";

$opp = "!" if $opt_v;		# match the opposite of pattern

$opt_u = 1 if $opt_F;		# always use .newsrc if specified
$opt_F = ($ENV{"HOME"} . "/.newsrc") if ! $opt_F;

# don't let the user specify a messy range
$opt_r = &nntp'canon_artlist($opt_r) if $opt_r;

# open a connection to the news server.  program will die if bad connection
$server = $opt_S ? &nntp'connect($opt_S) : &nntp'connect;

# get the pattern to match from the command line
&usage if ! ($pattern = shift);

# make a list of each group to scan
&usage if ! @ARGV;
while ($_ = shift)
{
    push(@groups, &nntp'list($server, $_));
}
die "No groups matched.\n" if (! @groups);

if ($field !~ /body|article/)
{
    $pattern =~ s/^\^/^[0-9]+ /;	# fix pattern to match article number

    foreach $ng (@groups)
    {
	next if $opt_u && ! &nntp'newsrc_get($opt_F, $ng, 0);

	@lim = &nntp'setgroup($server, $ng);
	next if ! @lim;			# this should never ever happen

	# generate an article range list for this news group
	$rangelist = "$lim[1]-$lim[2]";
	if ($opt_u)
	{
	    # user wants to look at unread messages only
	    local ($read) = &nntp'newsrc_get($opt_F, $ng, 0);
	    $rangelist = $read && 
		&nntp'canon_inverse(&nntp'canon_artlist($read),
 				    $lim[1], $lim[2]);
	}
	# intersect with the user's specified range.
	$rangelist = &nntp'canon_isect($rangelist, $opt_r) if $opt_r;

	# now do the hard stuff
	foreach $rng (&nntp'canon_expand($rangelist))
	{
	    local ($first, $last) = split(/-/, $rng);
	    local (@lines);

	    @lines = &nntp'grepfield($server, $field,
				     "$opp/$pattern/$flg", $first, $last);
	    foreach (@lines)
	    {
		s/^([0-9]+) /$1: /;
		print "$ng: $_\n";
	    }
	}
    }
}
else
{
    foreach $ng (@groups)
    {
	next if $opt_u && ! &nntp'newsrc_get($opt_F, $ng, 0);

	@lim = &nntp'setgroup($server, $ng);
	next if ! @lim;		# this should never ever happen

	# generate an article range list for this news group
	$rangelist = "$lim[1]-$lim[2]";
	if ($opt_u)
	{
	    # user wants to look at unread messages only
	    local ($read) = &nntp'newsrc_get($opt_F, $ng, 0);
	    $rangelist = $read && 
		&nntp'canon_inverse(&nntp'canon_artlist($read),
 				    $lim[1], $lim[2]);
	}
	# intersect with the user's specified range.
	$rangelist = &nntp'canon_isect($rangelist, $opt_r) if $opt_r;

	# now do the hard stuff
	foreach $rng (&nntp'canon_expand($rangelist))
	{
	    local ($first, $last) = split(/-/, $rng);
	    local (@lines);

	    @lines = &nntp'greptext($server, $field, "$opp/$pattern/$flg",
				    $first, $last);
	    foreach (@lines)
	    {
		s/^([0-9]+) /$1: /;
		print "$ng: $_\n";
	    }
	}
    }
}
