#!/usr/bin/perl # Copyright 2004-2005 by Wes Hardaker # All rights reserved. See below for license. ####################################################################### # type "perldoc rfcfind" to read the manual. # my %opts = (d => ($ENV{'RFCDIR'} || "$ENV{'HOME'}/docs/rfc/rfcs"), p => ($ENV{'PAGER'} || "more")); LocalGetOptions(\%opts, ["d|directory=s","Directory where the rfc repository is stored (or env var: RFCDIR)."], "", ["r|regexp=s", "Search for RFCs by REGEXP in the title list"], ["n|number=s", "Search for RFC numbers by number (actually REGEXP)"], "", ["m|more","View the resulting RFCs using your PAGER or 'more'"], ["p|pager=s","Set your pager to STRING"], ["g|grep=s","Grep the resulting RFCs for STRING"], ["e|edit","View the resulting RFCs using gnudoit (eg, emacs/gnuserv)"], ["k|kde","View the resulting RFCs using konqueror (kfmclient technically)"], "", ["i|fetch-index", "update your rfc database index file"], ["f|fetch-rfcs", "update your rfc database of just the matching RFCs"], ["s|sync-rfcs", "update your rfc database with rsync/wget"], "", ["h|help", "Show help for command line options"], ["v|version", "Display version"] ); if ($opts{'v'}) { print 'version: $Revision: 1.9 $' . "\n"; exit; } if ($opts{'s'} || $opts{'i'}) { print "fetching index file\n"; system("wget -O $opts{d}/rfc-index.txt http://www.ietf.org/rfc/rfc-index.txt"); } if ($opts{'s'}) { chdir($opts{'d'}); print "fetching all RFCs\n"; system("rsync --ignore-existing -avz ftp.rfc-editor.org::rfcs-text-only ."); exit(); } exit if ($opts{'i'}); if (!exists($opts{'r'}) && !($opts{'n'})) { print STDERR "You must specify one of -r, -n, -i or -s\n"; exit 1; } $/ = "\n\n"; $count = 0; open(I,"$opts{d}/rfc-index.txt"); while () { $out = $_; s/\s*\n\s*/ /g; s/\s\s+/ /g; ($n) = /^(\d{4})/; if ($opts{'r'} && ((!$opts{'i'} && /$opts{'r'}/i) || (/$opts{'r'}/)) || $opts{'n'} && $n =~ /$opts{'n'}/) { if ($opts{'c'}) { print $_,"\n"; } else { print $out; } $count++; push @total, $n; } } if ($opts{'f'}) { chdir($opts{'d'}); foreach my $rfc (@total) { my $file = "rfc$rfc.txt"; if (-f $opts{'d'} . "/$file") { print "already have $file\n"; next; } print "fetching $file\n"; $rfc =~ s/^0*//; system("wget http://www.ietf.org/rfc/$file"); } } map { $_ = $opts{'d'} . "/rfc" . $_ . ".txt" } @total; if ($count > 0 && $opts{'m'}) { system($opts{'p'} . " " . join(" ", @total)); } if ($count > 0 && $opts{'k'}) { system("kfmclient exec " . join(" ", @total)); } if ($count > 0 && $opts{'e'}) { my $editor = $ENV{'EDITOR'} || 'vi'; system("$editor ",join(" ",@total)); } if ($count > 0 && $opts{'g'}) { system("grep -n -i '$opts{g}' " . join(" ", @total) . " | sed -e 's\@^[^:]*/rfc\@rfc\@'"); } print "found: $count\n"; # # portable Getopt::GUI::Long code for those that don't have it # sub LocalGetOptions { if (eval {require Getopt::GUI::Long;}) { import Getopt::GUI::Long; # optional configure call Getopt::GUI::Long::Configure(qw(display_help no_ignore_case)); return GetOptions(@_) || exit(); } require Getopt::Long; import Getopt::Long; # optional configure call Getopt::Long::Configure(qw(auto_help no_ignore_case)); GetOptions(LocalOptionsMap(@_)) || exit(); } sub LocalOptionsMap { my ($st, $cb, @opts) = ((ref($_[0]) eq 'HASH') ? (1, 1, $_[0]) : (0, 2)); for (my $i = $st; $i <= $#_; $i += $cb) { if ($_[$i]) { next if (ref($_[$i]) eq 'ARRAY' && $_[$i][0] =~ /^GUI:/); push @opts, ((ref($_[$i]) eq 'ARRAY') ? $_[$i][0] : $_[$i]); push @opts, $_[$i+1] if ($cb == 2); } } return @opts; } 1; =pod =head1 NAME rfcfind - search an RFC list =head1 SYNOPSIS Fetch the index file first: rfcfind -i Search the indexes for RFCs releated to avian carriers: rfcfind -r 'avian.*carrier' Fetch just those RFCs: rfcfind -r 'avian.*carrier' -f Read them: rfcfind -r 'avian.*carrier' -m Decide you want 300Mbs of text files and get everything so you don't have to fetch them every time: rfcfind -s =head1 IMPORTANT NOTE This application does things by sometimes wrapping around the following system commands. This means you should be aware of this and that you may want to have them installed ;-) =over =item wget for -f switch =item rsync for -r switch =item more (or your $PAGER if set) for -m switch =item grep =item sed for -g switch =item kfmclient for -k switch =back =head1 DESCRIPTION The rfcfind program searches for RFCs by examining the RFC index.txt file from the RFC repository. By default, this must be placed in ~/docs/rfc/rfcs/ (since this is where mine are, for various reasons, this is where I expect yours to be ;-). You can override this by default using the RFCDIR environment variable or using the -d switch. In that directory you should have: =over =item the rfc-index.txt file =item a copy of the rfcs =back You can get these files from the http://www.ietf.org/rfc/ directory. =head1 OPTIONS =head2 Configuration Options =over =item -d DIRECTORY use DIRECTORY as the location where your rfc-index.txt and rfc files are stored. =back =head2 Search Options =over =item -r REGEXP Search the titles, etc (but not the RFC text itself) for REGEXP. If you don't understand what a REGEXP is, use something like "word1.*word2.*word3" (ie, .* in between words) =item -n REGEXP Search RFC numbers for a number or REGEXP. IE, you can use "1000" to get just RFC 1000, or you can use '[1-4]000' to get 1000, 2000, 3000 and 4000. =back =head2 Action Options =over =item -m Pass the resulting RFCS to the program specified by the -p flag or your PAGER program (enviorment variable) or "more" if not otherwise set. You should set it to less ;-) =item -g STRING Grep the resulting RFCs for a given string. IE: rfcfind -n 0822 -g address Searches the first email RFC for the word "address". =item -e Edits the resulting RFCs using gnudoit, an emacs specific edit connection. You must be running emacs with a working gnuserv installation. =item -k Sends the resulting files to a konqueror window if you're a kde user. =back =head2 IETF RFC Database Synchronization Options =over =item -i Fetch a new copy of the index file. =item -f For all matching RFCs, fech a copy of the RFC if you don't have a cached copy. =item -s Syncronizes your RFC database using rsync and wget. This gets *all* the RFCs if you don't have them, which currenly takes a bit less that 300Mb of disk space. =back =head2 Help options =over =item -h Shows help. May require the Getopt::GUI::Long module and the QWizard module. =back =head1 AUTHOR Wes Hardaker =head1 LICENSE Copyright (c) 2004-2005, Wes Hardaker All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Wes Hardaker nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =cut