#!/usr/bin/perl # Filename: yp # Author: David Ljung # Description: Does a lookup at Yahoo # Requires: GET (lwp-request) use strict; ################################################## # Setup the variables ################################################## my $PROGNAME = $0; $PROGNAME =~ s|.*/||; #my $YP_HOST="yp.uswest.com"; #my $YP_PORT=80; #my $DOC="/cgi/search.fcg"; my $YP_HOST="yp.yahoo.com"; my $YP_PORT=80; my $DOC="/py/ypResults.py"; # Starting address my $DEFAULT_ADDR="1553 Fulton Street"; my $DEFAULT_CITY="San Francisco"; my $DEFAULT_STATE="CA"; # Actions my $BROWSER = "browser"; my $DIALER = "d"; ################################################## # Usage ################################################## sub usage { my $msg; foreach $msg (@_) { print "ERROR: $msg\n"; } print "\n"; print "Usage:\t$PROGNAME [-d] [-v] [-c city] [-s state] \n"; print "\tDoes an online Yellow Pages lookup\n"; print "\t-more\tGet more listings after the first page\n"; print "\t-a\tChoose starting address [Default: $DEFAULT_ADDR]\n"; print "\t-c\tChoose starting city [Default: $DEFAULT_CITY]\n"; print "\t-s\tChoose starting state [Default: $DEFAULT_STATE]\n"; print "\t-v\tVerbose (output address)\n"; print "\t-b\tStart up query in a browser\n"; print "\t-d\tDial menu [using: $DIALER]\n"; print "\t-D\tSet debug mode\n"; print "\n"; exit -1; } sub parse_args { my ($name,$addr,$city,$state); while ($#ARGV>=0) { $a=shift(@ARGV); if ($a =~ /^-h$/) { &usage; } if ($a =~ /^-D$/) { $MAIN::DEBUG=1; next; } if ($a =~ /^-d$/) { $MAIN::DIAL=1; next; } if ($a =~ /^-more$/) { $MAIN::MORE_LISTINGS=1; next; } if ($a =~ /^-v$/) { $MAIN::VERBOSE=1; next; } if ($a =~ /^-a$/) { $addr=shift(@ARGV); next; } if ($a =~ /^-c$/) { $city=shift(@ARGV); next; } if ($a =~ /^-s$/) { $state=shift(@ARGV); next; } if ($a =~ /^-b(rowser)?$/) { $MAIN::BROWSER=1; next; } if ($a =~ /^-/) { &usage("Unknown option: $a"); } $name=($name ? "$name " : "" ) . $a; } usage("You need to specify a name to lookup") if (!defined($name)); $addr=$DEFAULT_ADDR unless ($addr || $city); $city=$city || $DEFAULT_CITY; $state=$state || $DEFAULT_STATE; $city="san francisco" if (lc($city) eq "sf"); ($name,$addr,$city,$state); } ################################################## # Dialing code ################################################## sub menu { my (@menu) = @_; for(my $i=0; $i<=$#menu; $i++) { printf "%0.2d] ",$i+1; show_row(@{$menu[$i]}); } my $ans=-1; print STDERR "\n"; do { print STDERR "Choose: "; $ans = scalar <>; chomp $ans; } until ($ans>0 && $ans<=$#menu+1); $ans-1; } ################################################## # YP stuff ################################################## sub prep_url { $_[0] =~ s/ /+/g; $_[0]; } sub query { my ($name,$addr,$city,$state) = @_; my $query = $MAIN::BROWSER ? "stp=a" : "stp=n"; $query.="&stx=".prep_url($name) if ($name); $query.="&addr=".prep_url($addr) if ($addr); $query.="&city=".prep_url($city) if ($city); $query.="&state=".prep_url($state) if ($state); print "QUERY: $query\n" if ($MAIN::DEBUG); $query; } sub submit { my ($query) = @_; if ($MAIN::BROWSER) { $query=~s/&/\\&/g; # print "Command: $BROWSER http://$YP_HOST:$YP_PORT${DOC}?$query\n"; system("browser http://$YP_HOST:$YP_PORT${DOC}?$query"); exit; } # Yahoo doesn't allow GET # open(HTML,"GET 'http://$YP_HOST:$YP_PORT${DOC}?$query' |") # || die("Couldn't GET to $YP_HOST\n"); open(HTML,"lynx -source 'http://$YP_HOST:$YP_PORT${DOC}?$query' |") || die("Couldn't lynx -source to $YP_HOST\n"); my @text=; close(HTML); print "START RESPONSE:\n\n@text\n\nEND RESPONSE\n" if ($MAIN::DEBUG); chomp(@text); @text; } # Listings are in table after: # # Table format: (garbage), name, address, city, phone, (garbage), (distance) sub parse_text { my(@text)=@_; my %FOUND; # Find start of listings my $i; for($i=0;$i<=$#text;$i++) { # print "Query didn't hold for some reason.\n" # if ($text[$i] =~ /fields are required/i); last if ($text[$i] =~ /ACTUAL RECORDS/i); die("Invalid search Criteria?\n") if ($text[$i] =~ /Invalid Search Criteria/); die("Couldn't find it\n") if ($text[$i] =~ /no .*found/); } die("Couldn't find start line [ACTUAL RECORDS]\n") if ($i>$#text); $i++; # Get listings my (@rows, @row); while($i<=$#text && !($text[$i] =~ /DISTANCE FOOTNOTE/i)) { if ($text[$i] =~ m|(.+)|i) { my $td = $1; $td =~ s/<[^>]+>//g; $td =~ s/ //g; push(@row,$td); } elsif ($text[$i] =~ /]*>(.*)/) { my $line = $1; do { $line =~ s/<[^>]+>//g; $line =~ s/ //g; $line =~ s/^\s*//g; $line =~ s/\s*$//g; push(@row,$line) if $line; $line = $text[$i+1]; last if $line =~ /DISTANCE FOOTNOTE/; } until $text[++$i] =~ m||; } #print "$text[$i]\n"; if ($text[$i] =~ m|| && @row) { my ($name,$phone,$addr,$city,$map,$dist) = @row; # Don't print multiple copies of the same entry/phone unless ($FOUND{$phone}++) { if (defined $dist) { my @copy = @row; push(@rows, \@copy); } else { print STDERR "[$PROGNAME] Incomplete table row [$i]: @row\n"; } } # Clear the row undef @row; } $i++; } #die("Couldn't find end line\n") if ($i>$#text); return @rows if ($i>$#text); # Check for more listings problem while ($i<=$#text) { if ($text[$i] =~ /\NEXT MATCHES/i) { return print STDERR "--There were more listings. To see them, use the '-more' option.\n" unless ($MAIN::MORE_LISTINGS); print STDERR "--Getting more listings...\n"; my @text=submit($1); push(@rows, parse_text(@text)); } $i++; } return @rows; } sub handle_rows { my (@rows) = @_; return map (show_row(@$_), @rows) unless $MAIN::DIAL; my $pick = menu(@rows); my $num = $rows[$pick][1]; $num =~ s/[\(\)]//g; print "Dialing: $num\n"; exec($DIALER,$num); } sub show_row { my ($name,$phone,$addr,$city,$map,$dist) = @_; $MAIN::VERBOSE ? print "$name $phone\n$addr $city\n$dist miles\n\n" : printf "%-40s $phone\n",$name; } ################################################## # Main code ################################################## handle_rows(parse_text(submit(query(parse_args()))));