#!c:\perl\bin\perl #hcpl.pl: Program to check if you have books due in the near future at Harris #County Public Library and remind you by email if so. #To actually run the script, type the command at DOS prompt # perl thisscript.pl -d3 -e"you@domain.com another@domain.com" -i123456789 -npin -mmail [-pmyproxy[:port]] #This sends you@domain.com and another@domain.com an email about the books due #in 3 days checked out by the person with library card 123456789. The SMTP #mail server is "mail" (most companies use this name). If you have to go through #a proxy server named myproxy to connect to the Internet, append "-pmyproxy" or #"-pmyproxy:8080" to the end (no brackets or quotes; specify port if it's not 80). #If your proxy server additionally requires username/password, uncomment the two #lines below and set them correctly: #$proxyuser="myproxyusername"; #$proxypasswd="myproxypassword"; #This script, as well as hpl.pl is published as freeware at #http://yong321.freeshell.org/freeware/hplhcpl.html #(C) Copyright 2003-2008 Yong Huang (yong321@yahoo.com) #Features common to hcpl.pl and hpl.pl are in header comments of hpl.pl. ########## No need to modify below this line but hacking is welcome. ########## use Net::SMTP; use LWP::UserAgent; use Time::Local; use Getopt::Std; $|=1; getopts('d:e:i:n:m:p:'); if (!defined $opt_d or !defined $opt_e or !defined $opt_i or !defined $opt_n or !defined $opt_m) { print "Usage: perl $0 -d3 -e\"you\@domain.com another\@domain.com\" -i12345678901234 -n1234 -mmail [-pProxy[:port]] -d: from this many days ahead of due date you get email once a day -e: space-separated email addresses the notice will be sent to -i: HCPL library card number -n: card holder's pin number -m: mail server; usually 'mail' but confirm with your system admin -p (optional): proxy server if you have to go through it to access Internet "; exit; } $daysahead=$opt_d; $email=$opt_e; #($email=$opt_e) =~ s/@/\\@/g; $ID=$opt_i; $pin=$opt_n; $mailsrvr=$opt_m; $ProxyServer=$opt_p if defined $opt_p; $ua = new LWP::UserAgent; if (defined $opt_p) { $ua->proxy(http => "http://$ProxyServer"); $ua->env_proxy; } else { $ua->agent("AgentName/0.1"); } #Phase 1 $req = new HTTP::Request 'GET', 'http://catalog.hcpl.net/ipac20/ipac.jsp?session=10F335499F49D.450&profile=hcpl&menu=account&ts=1033354031398&login_prompt=true&lastlogin=1033441743618'; $req->proxy_authorization_basic($proxyuser, $proxypasswd) if defined $proxyuser; { my $cnt=0; sleep 1 while ($cnt++<10 && ($tmp=$ua->request($req)->as_string) eq ""); } #Sometimes this initial connection fails. Try it several times. #print "\n\nPhase 1 output:\n$tmp\n\n\n";#for debugging $tmp =~ /name="session" value="(.*?)"/; $session = $1; #print "Session is: $session\n"; #Phase 2 $req = new HTTP::Request POST => 'http://catalog.hcpl.net/ipac20/ipac.jsp'; $req->proxy_authorization_basic($proxyuser, $proxypasswd) if defined $proxyuser; $req->content_type('application/x-www-form-urlencoded'); $req->content("session=$session&menu=account&aspect=overview&npp=10&ipp=20&profile=hcpl&ri=&sec1=$ID&sec2=$pin"); $ua->request($req); #print "\n\nPhase 2 output:\n", $ua->request($req)->as_string; $ua->request($req)->as_string =~ /Checked Out: (\d+)/; $numbooks = $1; #print "Session: $session and Number of Books: $numbooks\n"; if ($numbooks == 0) { print "You did not check out any books."; exit; } #Phase 3 $req = new HTTP::Request GET => "http://catalog.hcpl.net/ipac20/ipac.jsp?session=$session&profile=hcpl&menu=account&submenu=itemsout"; $req->proxy_authorization_basic($proxyuser, $proxypasswd) if defined $proxyuser; $ua->request($req); #print "\n\nPhase 3 output:\n", $ua->request($req)->as_string; #print "\n---------------------------------\n"; undef $/; $_ = $ua->request($req)->as_string; @line = split /]+>(.*?)[/\.](.*?)(?:.*?)normalBlackFont2">(.*?)(?:.*?)normalBlackFont2">(.*?)#; #20040909 HCPL changed the code again so I'm changing too. #m#\!test\&[^>]+>(.*?)[/\.](.*?)(?:.*?)normalBlackFont2">(.*?)(?:.*?)normalBlackFont2">(.*?)#; # m#\!test\&[^>]+>(.*?)(.*?)(?:.*?)normalBlackFont2">(.*?)(?:.*?)normalBlackFont2">(.*?)#; # $1: title $2: by author $3: mm/dd/yyyy $4: mm/dd/yyyy #20050214 HCPL changed code again so I'm changing too. What a pain! But this time my regexp has #least dependency on their free text so it should be more resistant against their code change. #m#spp=20">([^<]+)(?:<(?:[^>]+)>)+([^<]+)(?:<(?:[^>]+)>)+([^<]+)(?:<(?:[^>]+)>)+([^<]+)#; #20060717 HCPL changed code so the above line no longer works #20080321 HCPL changed "spp=20" to "spp=60". That's the only change they made in the past one and half years. m#spp=60">([^<]+)(?:<(?:[^>]+)>)+([^<]+)(?:<(?:[^>]+)>)+(?:[^<]+)(?:<(?:[^>]+)>)+(?:[^<]+)(?:<(?:[^>]+)>)+([^<]+)(?:<(?:[^>]+)>)+([^<]+)#; # $1:title $2:by author $3:mm/dd/yyyy $4:mm/dd/yyyy #print "XXX1: ", $1, "XXX2: ", $2, "XXX3: ", $3, "XXX4: ", $4, "XXX5", $5, "XXX6", $6, "XXX"; #for debug next if !defined $1 or !defined $2 or !defined $3; $thisbook = "$1 $2 checked out on $3 due on $4"; #Info about this book $4 =~ m#(\d\d)/(\d\d)/(\d\d\d\d)#; $month = $1 - 1; #convert to seconds since epoch, second set to 1 to avoid midnight ambiguity $duetime = timelocal(1,0,0,$2,$month,$3); if ($remindtime >= $duetime) { $msg .= "$seq: $thisbook\n"; $seq++; } } if ($msg ne "") { print $msg; $smtp = Net::SMTP->new($mailsrvr); if ($email =~ / /) { @email = split / /,$email; $smtp->mail($email[0]); #Hopefully the first address is your own; in case of error this #address is more likely to receive the mail $smtp->to(@email); #cannot be fake $smtp->data(); $smtp->datasend("To: @email\n"); #can be fake } else { $smtp->mail($email); $smtp->to($email); $smtp->data(); $smtp->datasend("To: $email\n"); #can be fake } $smtp->datasend("From: $email\n"); #can be fake $smtp->datasend("Subject: Harris County Public Library books due\n\n"); $smtp->datasend("$msg\n"); $smtp->dataend(); $smtp->quit; }