#!/usr/bin/perl  -w
# File: check_bookmarks.pl
# Description:
# Netscape bookmarks checker. Reads a bookmark file
# give as stdin, and checks wether the bookmark has modified
# or not. If it has, notify on stdout.
# -------------------------------------------------------
#        Copyright (C) 1998 Javier Fernandez-Sanguino Peņa
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# ------------------------------------------------------------

# User customisation
$USER=`whoami`;
$user_md5_default=glob '~/.check-url';

# Program configuration
$PROGRAM_NAME="Check_userBook";
$tmp_file="/tmp/.check-www";


require HTTP::Request;
require LWP::UserAgent;
use HTTP::Date;
# in Debian systems this will be given by: libwww-perl and libnet

# in Debian systems these three will be given by: libwww-perl and libnet
use Getopt::Std;


# To get command line options
getopts('tumvhp');

# Show help
if ($opt_h ) {
    print <<EOM;
Usage: $0 [-tvhup] [< html_file]
Checks URL's given as standard input or stored in user's file,
uses MD5sum algorithm to check for changes.
\t -t\ttest and print - don't check
\t -v\tbe verbose
\t -h\tprint this help
\t -u\tcheck only user list
\t -m\tmail-notify, will send e-mail if changes are found
\t -p\tuse environment proxies
EOM
    exit 1;
}


read_user_md5();

open (MD5USER,">>$user_md5_default") || die "Could not append to $user_md5_default";
if ($opt_u) {
    # We only check the users files
    foreach $url (keys %DATA) {
	print "CHECKING \"$DATA{$url}{'comment'}\" (${url})\n" if $opt_v;
	check_full($url,$DATA{$url}{'comment'}) if !$opt_t; 
	print "Nothing done... just testing.\n" if $opt_t;}
}
check_html_input() if !$opt_u;
close MD5USER;

sub read_user_md5 {
# We read the default user file and make it a hash array    
    if ( -e $user_md5_default ){
	open (MD5USER,"<$user_md5_default") || die "Could not open $user_md5_default";
	while (<MD5USER>) {
	    if (/^([\w,\d]+)[\s,\t]+(.+?)[\s,\t]+\"(.+)\"[\s,\t]+(.*)/){
		# We add the file/url his sum, and name to the hash array
		$DATA{$2}{'md5sum'}=$1;
		$DATA{$2}{'comment'}=$3; 
		$DATA{$2}{'date'}=$4;
	    }
	}
	close MD5USER
	}
    else {
	# We create the file by touching it
	open (MD5USER,">${user_md5_default}") || die "Could not open $user_md5_default";
	print MD5USER "# user DATA to check files/urls modifcations\n";
	$time=localtime;
	print MD5USER "# created by ${PROGRAM_NAME}, ${time}\n";
	print MD5USER "# format is md5sum url comment last_access_date\n";
	close MD5USER;
    }
}

sub notify {
#    We notify the user that something has changed
    my ($name, $url)=@_;
    print "\t$name ($url) has been MODIFIED\n" if $opt_v;
    mail_notify($name,$url) if $opt_m;
}

sub mail_notify {
# We send a mail to the user to notify him
    my ($name,$url)=@_;
    open (MAIL,"|mail -s \"${name} changed\" $USER") || die ("Could not mail message to user!\n");
    print MAIL <<EOM;

    Dear Sir,
       This is your Agent ${PROGRAM_NAME} speaking, just to notify
       you, that the source "${name}" (${url}) has changed
       since your last visit.

    Regards

    Your ${PROGRAMNAME} Agent.

EOM

    close MAIL;
}

sub check_html_input {

    while ($line=<STDIN>) {
	chomp $line;
	if ($line =~ /\<A HREF="(.*)" ADD_DATE="(\d*)" LAST_VISIT="(\d*)" LAST_MODIFIED="(\d*)"\>(.*)\<\/A\>/i) {
	    ($Url,$Add,$Visit,$Modif,$Name)=( $1, $2, $3, $4, $5);
	    print "CHECKING \"${Name}\" (${Url})\n" if $opt_v;
	    check_full($Url,$Name,$Modif)  if !$opt_t ;
	    print "Nothing done... just testing.\n" if $opt_t;}
    }
    
}


sub check_full {
    my ($url,$comment,$time)=@_;
    check($url);
    if (defined ($response->is_success)) {
	if ($response->is_success) {
	    # We pass on the content to a MD5SUM checker and retrieve 
	    # the result
	    open (TMP_FILE,">${tmp_file}") || die "Could not open ${tmp_file}!\n";
	    print TMP_FILE $response->content;
	    close TMP_FILE;
	    
	    $md5sum=md5sum_of_file($tmp_file);
	    if ($DATA{$url}{'md5sum'}) {
		if ( $md5sum ne $DATA{$url}{'md5sum'} )
		{ notify($comment,$url); }
		else { print "\t$comment is UP TO DATE\n" if $opt_v }
	    }
	    else {
		# Not in our list, we add it to it in MD5USERS
		print "$Name is NEW, adding it..\n" if $opt_v;
		$DATA{$url}{'md5sum'}=$md5sum;
		$DATA{$url}{'comment'}=$comment;
		$DATA{$url}{'date'}=$response->date;
		print MD5USER "${md5sum}\t${url}\t\"${Name}\"\t$DATA{$url}{'date'}\n";
	    }

	    if ( defined ($response->header(Last_Modified) ) ) {
		if ( str2time($response->header(Last_Modified)) > $time) 
		    # Url has been modified (at least timestamp)
		    print STDOUT "\t\"${Name}\" has MODIFIED TIMESTAMP.\n" }
	}
	else { print STDOUT "\t${Name} is UNAVAILABLE.\n" if $opt_v; }
    } # del if defined response
}


sub check
{ 
# We check here by sending an HTTP request for GET information of
# the URL given

# We must do this also for other URLs (currently works with
# http, ftp and gopher, but not with file://
# Easy to implement - just use Perl's file builting functions.
# But will have to build a HTTP::Response object
    my $URL= new URI::URL shift (@_);
    # Create UserAgent
    my $ua= new LWP::UserAgent;
    $ua->agent("$PROGRAM_NAME/0.9");
    # Timeout should be configurable
    $ua->timeout(10);
    
    # LWP::UserAgent no longer has max_size
    # $ua->max_size(1000);
    # If we want proxy enabled 
    $ua->env_proxy if $opt_p;
    
    # Setup and Send Request
    my $request= new HTTP::Request 'GET', $URL;
    # Now has to contact the host and ask for the file
    $response=$ua->request($request);
    
    return $response->date;
}



sub md5sum_of_file
{
    my ($file)=@_;
    my $md5;
    open (MD5SUM, "md5sum ${file}|") || die "Could not execute md5sum function!\n";    
    while (<MD5SUM>) {	/([\w\d]+)[\t,\s]+\Q$file/; $md5=$1;}
    close MD5SUM;
    return $md5;
}


