#!/usr/bin/perl #------------------------------------------- # MiniSearch v0.2 # Personal Website Search Engine # http://www.dansteinman.com/minisearch/ # # Copyright (C) 1999 Dan Steinman # Distributed under the terms of the of the GNU General Public License # You may modify this progam, redistribute it in it's entirety, # but any significant improvements must be made public # Read the LICENSE file for more details #------------------------------------------- # search # gets and displays the results of a query #------------------------------------------- #------------------------------------------- if (-e "searchdata/config") { &getConfig; &ReadParse; print "Content-type: text/html\n\n"; $root = $config{'root'}; $datadir = $config{'datadir'}; $webaddress = $config{'webaddress'}; $view = $in{'view'} || 'default'; @parts = split(/:/,$templates{$view}); $promptpage = "$datadir$parts[1]"; $resultspage = "$datadir$parts[2]"; $qstr = $ENV{'QUERY_STRING'}; if ($qstr eq "") { &displayPrompt; } else { &displayResults; } } else { # if no config go to searchindex to create one print "Location: searchindex.pl\n\n"; exit(0); } #------------------------------------------- # write the search prompt page sub displayPrompt { open(FILE,"$promptpage"); $output = join('',); close(FILE); print $output; } #------------------------------------------- # show the results of the search sub displayResults { if ($in{'query'} eq "") { &displayPrompt; exit(0); } $in{'query'} =~ s/'//g; $in{'query'} =~ tr/A-Z/a-z/; @queries = split(/ /,$in{'query'}); # the words to search for $totalqueries = @queries; $match = ($in{'match'} || "all"); $set = ($in{'set'} || 1); $max = ($in{'max'} || 10); $where = ($in{'where'} || 'all'); # convert if the where directory was a forum if ($where ne 'all') { @wheredirs = split(/:/,$where); # split in case there were multiple directories to filter for ($i=0;$i<@wheredirs;$i++) { foreach $forumdir (keys(%forums)) { if ($wheredirs[$i] eq $forums{$forumdir}) { $wheredirs[$i] = $forumdir; } } } } # retrieve the list of files and get the size/date/titles open(FILE,"$datadir/files"); while ($line = ) { @parts = split(/,/,$line); push(@files,$parts[1]); $file = $parts[1]; $matches{$file} = 0; $sizes{$file} = $parts[2]; $dates{$file} = $parts[3]; $titles{$file} = $parts[4]; } close(FILE); # split words open(FILE,"$datadir/words"); while () { next unless s/^(.*?) = \s*//; $words{$1} = [ split ]; } close(FILE); # find the potentially matched filenames foreach $query (@queries) { # loop through each of the query words if (@{$words{$query}}) { # if the word has an associated file foreach $index (@{$words{$query}}) { $potmatches{$files[$index]} += 1; # mark the file as a potential match by uping the potmatches count } } } # loop through all the potentially matched files and determine if it is a true match foreach $file (keys(%potmatches)) { # skip if next if ($match eq "any" && $potmatches{$file} == 0); # skip a potential match if the number of queries found was less than the number of queries searched for next if ($match eq "all" && $potmatches{$file} < $totalqueries); if ($where ne "all") { # if all queries are needed to be matched foreach $wheredir (@wheredirs) { # if where was given only make those filenames final matches if ($file =~ /^$wheredir/) { push(@matches,$file); } } } else { push(@matches,$file); # if any queries are needed add to final matches } } $nummatches = @matches; if ($in{'max'} eq 'unlimited') {$max = $nummatches;} # display the results page open(FILE,"$resultspage"); $output = join('',); close(FILE); $output =~ s/##QUERY##/$in{'query'}/g; $output =~ s/##NUMMATCHES##/$nummatches/g; $output =~ s/##SCRIPTSEARCH##/$config{'scriptsearch'}/g; if ($nummatches > 0) { $lastmatch = $max+($set-1)*$max; $lastmatch = $nummatches if ($lastmatch>$nummatches); for ($i=($set-1)*$max;$i<$lastmatch;$i++) { $file = $matches[$i]; $ip1 = $i+1; my($ksize) = ($sizes{$file}/1000); $size = &round($ksize,1); $date = &formattedDate($dates{$file}); # convert the url for the forum messages $url = $file; foreach $dir (keys(%forums)) { if ($file =~ /$dir/ && $file =~ /(.*)\/(.*)\.txt/) { $url = "$forums{$dir}\?msg=$2"; } } $resultstr .= "

$ip1. $titles{$file}"; $resultstr .= "
URL: $config{'webaddress'}$url"; $resultstr .= "
Size: ${size}KB, Date: $date"; } $numsets = int($nummatches/$max)+1; $next = $set+1; $previous = $set-1; $qstr =~ s/\&set=(.*[0-9])//; $qstr = "$config{'scriptsearch'}?$qstr&set="; } $resultstr .= "

"; $resultstr .= ""; $resultstr .= ""; $resultstr .= ""; $resultstr .= ""; $resultstr .= ""; $resultstr .= ""; # the number link bar "more matches" if ($numsets>1) { $resultstr .= "

More Matches:
"; if ($set!=1) { $resultstr .= "Previous | "; } if ($set>20 && $numsets>20) {$resultstr .= " < ";} if ($numsets>20) { if ($set>20) { $startset = 21; $endset = $numsets; } else { $startset = 1; $endset = 20; } } else { $startset = 1; $endset = $numsets; } for ($i=$startset;$i<=$endset;$i++) { if ($i == $set) { $resultstr .= "$i "; } else { $resultstr .= "$i "; } } if ($set<=20 && $numsets>20) {$resultstr .= " > ";} if ($set<$numsets) { $resultstr .= "| Next"; } } $output =~ s/##RESULTS##/$resultstr/; print $output; } #------------------------------------------- # some helper routines #------------------------------------------- # get configuration variables sub getConfig { if (open(FILE,"searchdata/config")) { @configfile = ; close(FILE); foreach $line (@configfile) { if ($line =~ /template = (.*)/) { @parts = split(/:/, $1); $templates{$parts[0]} = $1; } if ($line =~ /forum = (.*)/) { @parts = split(/:/, $1); $forums{$parts[0]} = $parts[1]; } elsif ($line =~ /(.*) = (.*)/) { $config{$1} = $2; } } } else { &setDefaultConfig; &generateConfig(1); } } # get form input sub ReadParse { local (*in) = @_ if @_; local ($i, $loc, $key, $val); if ($ENV{'REQUEST_METHOD'} eq "GET") { $in = $ENV{'QUERY_STRING'}; } elsif ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN,$in,$ENV{'CONTENT_LENGTH'}); } @in = split(/&/,$in); foreach $i (0 .. $#in) { $in[$i] =~ s/\+/ /g; ($key, $val) = split(/=/,$in[$i],2); $key =~ s/%(..)/pack("c",hex($1))/ge; $val =~ s/%(..)/pack("c",hex($1))/ge; $in{$key} .= "\0" if (defined($in{$key})); $in{$key} .= $val; } return 1; } # round $num to $dec decimal places sub round { my($num,$dec) = @_; my($exp) = 10**$dec; return(int($num*$exp+$exp/20)/$exp); } # make it look nicer sub formattedDate { my($date) = @_; ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($date); @months = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); if ($year<100) {$year += 1900;} $fdate = "$months[$mon] $mday, $year"; return $fdate; } #--end-----------------------------------------