#!/Perl
# recent.pl
# AIM: To start, and keep a database of 'Recently Used Files'
# for each product. I always HATE that they ususally only support
# a maximum of 16 - BAH ...
# 20061029 - geoff mclane - http:\\geoffmcane.com\mperl\samples
# but regretably, it was NEVER finished ...
use strict;
use warnings;
use Encode;
use Win32::Registry;
use Win32::TieRegistry( Delimiter => "#", ArrayValues => 0 );
my $pound = $Registry->Delimiter("/");

require 'logfile.pl' or die "ERROR: Unable to load logfile.pl ...\n";

# log file stuff
my ($LF);
my $outfile = 'temp.'.$0.'.txt';
my ($epKey, $wdKey, $wdKey2);

my $keysdat = 'keysdat2.htm';

my %KeysVal = ();
my %PathMap = ();

my @Keys2Fetch = ();
my @Previous = ();

my $debug_on = 0;
# other USER variables
my $tab_space = ' '; # note tabs to 1 space - change if desired
my $mxwid = 50;
my $tdopn = '<td valign="top">';

my $epComp = "CUser/Software/ES-Computing/EditPlus 2/Recent File List";
# [HKEY_CURRENT_USER\Software\Microsoft\Office\10.0\Common\Open Find\Microsoft Word\Settings\Save As\File Name MRU]
# "Maximum Entries"=dword:0000000a
my $wdMRU = "CUser/Software/Microsoft/Office/10.0/Common/Open Find/Microsoft Word/Settings/Save As/File Name MRU";
my $wdMRU2 = "CUser/Software/Microsoft/Office/10.0/Common/Open Find/Microsoft Word/Settings/Modify Location/File Name MRU";

my $wdMRU3 = 'HKEY_CURRENT_USER/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/OpenSaveMRU/doc';
# items like
# "a"="C:\\Documents and Settings\\Geoff McLane.PRO-1\\My Documents\\Uwe\\lacigaleetlafourmi.doc"
# "MRUList"="edciajhgfb"
# "b"="C:\\Documents and Settings\\Geoff McLane.PRO-1\\My Documents\\Uwe\\uwe-13b.doc"
# "c"="C:\\Documents and Settings\\Geoff McLane.PRO-1\\My Documents\\Maree\\goldcoastanddarwin.doc"
my $wdMRU4 = 'HKEY_USERS/S-1-5-21-1993962763-1614895754-725345543-1003/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/OpenSaveMRU/doc';
# "a"="C:\\Documents and Settings\\Geoff McLane.PRO-1\\My Documents\\Uwe\\lacigaleetlafourmi.doc"
# "MRUList"="edciajhgfb"
# "b"="C:\\Documents and Settings\\Geoff McLane.PRO-1\\My Documents\\Uwe\\uwe-13b.doc"
# "c"="C:\\Documents and Settings\\Geoff McLane.PRO-1\\My Documents\\Maree\\goldcoastanddarwin.doc"

my $entry = '';
my $data = '';
my @entries = ();
my $dat = '';
my $tryu = 0;
my $keycnt = 0;
my $regcnt = 0;
my $wordkey = 'S-1-5-21-1993962763-1614895754-725345543-1003';

my $FPWebs = 'CUser/Software/Microsoft/FrontPage/Explorer/FrontPage Explorer/Recent Web List';
# with enties like "Web1"="file://,,/C:/HOMEPAGE/P26,Geoff McLane,-1,C:/HOMEPAGE/P26"
my $FPFiles = 'CUser/Software/Microsoft/FrontPage/Explorer/FrontPage Explorer/Recent File List';
# like
# "File1"="C:\\HOMEPAGE\\P26"
# "File2"="C:\\HOMEPAGE\\Max5"
my $ExLastMRU = 'CUser/Software/Microsoft/Windows/CurrentVersion/Explorer/ComDlg32/LastVisitedMRU';
##"a"=hex:6e,00,6f,00,74,00,65,00,70,00,61,00,64,00,2e,00,65,00,78,00,65,00,00,\
##  00,43,00,3a,00,5c,00,44,00,54,00,45,00,4d,00,50,00,00,00
##"MRUList"="rclaexdyuopikbhvnwqjmtsfg"
##"b"=hex:78,00,6e,00,76,00,69,00,65,00,77,00,2e,00,65,00,78,00,65,00,00,00,46,\
##  00,3a,00,5c,00,46,00,47,00,30,00,39,00,31,00,30,00,2d,00,34,00,00,00
### $Registry-> {"\\ValueName"}= [ pack("fmt",$data), REG_DATATYPE ];

my $MSVC6MRU = 'CUser/Software/Microsoft/VisualStudio/6.0/MenuMRUList';

my $MSVC7MRU = 'CUser/Software/Microsoft/VisualStudio/7.1/FileMRUList';
my $MSVC7MRU2 = 'CUser/Software/Microsoft/VisualStudio/7.1/ProjectMRUList';

# added 20070402 - extend into MSVC8 (or 9?)
my $MSVC8MRUF = 'HKEY_CURRENT_USER\Software\Microsoft\VCExpress\8.0\FileMRUList';
my $MSVC8MRUP = 'HKEY_CURRENT_USER\Software\Microsoft\VCExpress\8.0\ProjectMRUList';

open_log($outfile);
prt( "$0 ... Hello, World ...\n" );

get_keys_data( $keysdat );
my $pcnt = scalar @Previous;
prt( "Collected $pcnt previous entries ...\n" );

push(@Keys2Fetch, $epComp);
push(@Keys2Fetch, $wdMRU);
push(@Keys2Fetch, $wdMRU2);
push(@Keys2Fetch, $wdMRU3);
push(@Keys2Fetch, $wdMRU4);
push(@Keys2Fetch, $FPWebs);
push(@Keys2Fetch, $FPFiles);
push(@Keys2Fetch, $ExLastMRU);
push(@Keys2Fetch, $MSVC6MRU);
push(@Keys2Fetch, $MSVC7MRU);
push(@Keys2Fetch, $MSVC7MRU2);

foreach my $fetch (@Keys2Fetch) {
	show_REG_list( $fetch );
}
#show_REG_list( $epComp );
#show_REG_list( $wdMRU );
#show_REG_list( $wdMRU2 );
#show_REG_list( $wdMRU3 );
#show_REG_list( $wdMRU4 );
#show_REG_list( $FPWebs );
#show_REG_list( $FPFiles );
#show_REG_list( $ExLastMRU );
#show_REG_list( $MSVC6MRU );
#show_REG_list( $MSVC7MRU );
#show_REG_list( $MSVC7MRU2 );

my @keylist = keys(%KeysVal);
$keycnt = scalar @keylist;
prt( "Got $keycnt values to show ...\n" );
write_keys_data( $keysdat );

close_log($outfile,1);
exit(0);

# load the previous HTM data
sub get_keys_data {
	my ($fil) = shift;
	if (open INF, "<$fil") {
		my @lns = <INF>;
		close INF;
		my $prevhtm = join('',@lns);
		my $hl = length($prevhtm);
		my ($i, $c, $tag);
		my $in_td = 0;
		my $td_cnt = 0;
		my $td1 = '';
		my $td2 = '';
		my $tdt1 = '';
		my $tdt2 = '';
		my $lastp = '';
		for ($i = 0; $i < $hl; $i++) {
			$c = substr($prevhtm,$i,1);
			if ($c eq '<') {
				$tag = $c;
				$i++;
				for ( ; $i < $hl; $i++) {
					$c = substr($prevhtm,$i,1);
					$tag .= $c;
					if ($c eq '>') {
						last;
					}
				}
				if ($c eq '>') {
					if ($tag =~ /^<td.*>$/i) {
						$in_td = 1;
						$td_cnt++;
						if (length($td1) && length($td2)) {
							$tdt1 = trim_tail(html2text($td1));
							$tdt2 = trim_tail(html2text($td2));
							if ((length($tdt1) == 0)||($tdt1 =~ /^\s+$/)) {
								$tdt1 = $lastp;
							}
							###prt( "[$tdt1] [$tdt2]\n" );
							push(@Previous, [$tdt1, $tdt2]);
							$lastp = $tdt1;
						}
						if ($td_cnt & 1) {
							$td1 = '';
						} else {
							$td2 = '';
						}
					} elsif ($tag =~ /^<\/td>$/i ) {
						$in_td = 0;
					} elsif ($tag =~ /^<\/table>$/i ) {
						if (length($td1) && length($td2)) {
							$tdt1 = trim_tail(html2text($td1));
							$tdt2 = trim_tail(html2text($td2));
							if ($tdt1 =~ /^\s+$/) {
								$tdt1 = $lastp;
							}
							###prt( "[$tdt1] [$tdt2]\n" );
							push(@Previous, [$tdt1, $tdt2]);
							$lastp = $tdt1;
						}
					}
				}
			} else {
				if ($in_td) {
					if ($td_cnt & 1) {
						if ($c eq "\n") {
							$c = ' ';
							if ( length($td1) ) {
								if ( substr($td1,-1) =~ /\s/ ) {
									$c = '';
								}							
							} else {
								$c = '';
							}
						}
						$td1 .= $c;
					} else {
						if ($c eq "\n") {
							$c = ' ';
							if ( length($td2) ) {
								if ( substr($td2,-1) =~ /\s/ ) {
									$c = '';
								}							
							} else {
								$c = '';
							}
						}
						$td2 .= $c;
					}
				}
			}
		}
	} else {
		prt( "WARNING: Can NOT load [$fil] ...\n" );
	}
}

sub split_line_at {
	my ($tx, $mx) = @_;
	my $tl = length($tx);
	my ($is, $cch);
	if ($tl > $mx) {
		my $ntx = '';
		my $ptx = '';
		for ($is = 0; $is < $tl; $is++) {
			$cch = substr($tx,$is,1);
			if (length($ptx) > ($mx - 5)) {
				#if ($cch =~ /[\s-;:,\/\\]/) {
				if ($cch =~ /[\s\-;:,\/\\]/) {
					$ptx .= $cch;
					$ntx .= $ptx . '<br>' . "\n";
					$ptx = '';
					$cch = '';
				}
			}
			$ptx .= $cch;
		}
		$ntx .= $ptx;
		return $ntx;
	}
	return $tx;
}

sub delete_previous {
	my ($p, $v ) = @_;
	my $pcnt = scalar @Previous;
	my ($j);
	for ($j = 0; $j < $pcnt; $j++) {
		my $pp = $Previous[$j][0];
		my $pv = $Previous[$j][1];
		if (($p eq $pp)&&($v eq $pv)) {
			###delete $Previous[$j];
			splice(@Previous, $j);
			last;
		}
	}
}

sub write_keys_data {
	my ($fil) = shift;
	open OUTF, ">$fil" or mydie("ERROR: Unable to create [$fil] file ... $! ...\n" );
	my ($msg);
	my $htm_head = <<"EOF";
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html lang="en">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Registry Key Data</title>
</head>

<body>

<h1>List of MRU from Registry</h1>

<table border="2" summary="List of the current MRU keys from registry">
<caption>List of the current MRU keys from registry</caption>
<tr><th>Path</th><th>Content</th></tr>

EOF

	my $htm_tail = <<"EOF";
</body>
</html>
EOF

	print OUTF $htm_head;
	my $lastpath = '';
	my $val = '';
	my @a = ();
	my $k2 = '';
	my $p = '';
	foreach my $key (sort(keys(%KeysVal))) {
		$val = $KeysVal{$key};
		@a = split(/\./,$key);
		$k2 = $a[0];
		$p = $PathMap{$k2};
		prt( "Pth[$p]$k2\n" );
		prt( "key[$key] = [$val]\n" );
		$msg = "<tr>\n";
		$msg .= "$tdopn\n";
		if ($lastpath eq $p) {
			$msg .= '&nbsp;'. "\n";
		} else {
			$lastpath = $p;
			$msg .= split_line_at(html_line($p), $mxwid) . "\n";
		}
		$msg .= "</td>\n";
		$msg .= "$tdopn\n";
		$msg .= split_line_at(html_line($val), $mxwid) . "\n";
		$msg .= "</td>\n";
		$msg .= "</tr>\n";
		delete_previous( $p, $val );
		print OUTF $msg;
	}
	$lastpath = '';
	my $pcnt = scalar @Previous;
	my ($j);
	prt( "Adding $pcnt, from previous file ...\n" );
	for ($j = 0; $j < $pcnt; $j++) {
		my $pp = $Previous[$j][0];
		my $pv = $Previous[$j][1];
		$msg = "<tr>\n";
		$msg .= "$tdopn\n";
		if ($lastpath eq $pp) {
			$msg .= '&nbsp;'. "\n";
		} else {
			$lastpath = $pp;
			$msg .= split_line_at(html_line($pp), $mxwid) . "\n";
		}
		$msg .= "</td>\n";
		$msg .= "$tdopn\n";
		$msg .= split_line_at(html_line($pv), $mxwid) . "\n";
		$msg .= "</td>\n";
		$msg .= "</tr>\n";
	}

	print OUTF "</table>\n";
	$lastpath = '';
	my $lo = 0;
	# generate in LIST form
# <dt><strong>The procedure:</strong></dt>
# <dd>
# <ol>
# <li>Mix dry ingredients thoroughly.</li>
# <li>Pour in wet ingredients.</li>
# <li>Mix for 10 minutes.</li>
# <li>Bake for one hour at 300 degrees.</li>
# </ol>
# </dd>
	print OUTF "<p>\n";
	foreach my $key (sort(keys(%KeysVal))) {
		$val = $KeysVal{$key};
		@a = split(/\./,$key);
		$k2 = $a[0];
		$p = $PathMap{$k2};
		if ($lastpath eq $p) {
			$msg = '<li>' . html_line($val) . "</li>\n";
		} else {
			$lastpath = $p;
			$msg = '';
			if ($lo) {
				$msg .= "</ol>\n</dd>\n";
			}
			$msg .= '<dt><strong>' . html_line($p) . "</strong></dt>\n";
			$msg .= "<dd>\n<ol>\n";
			$msg .= '<li>' . html_line($val) . "</li>\n";
			$lo = 1;
		}
		print OUTF $msg;
	}
	$msg = '';
	if ($lo) {
		$msg .= "</ol>\n</dd>\n";
		print OUTF $msg;
	}
	print OUTF "</p>\n";
	print OUTF $htm_tail;
	close OUTF;
	system($fil);
}

sub show_REG_list {
	my ($tx) = shift;
	my ($tkey);
	my $lcnt = 0;
	prt( "\nProbe of [$tx] ...\n" );
	my $tx2 = $tx;
	$tx2 =~ s/ /_/g;
	$tx2 =~ s/\//\./g;
	$regcnt++;
	$tx2 = "Reg" . $regcnt;
	$PathMap{$tx2} = $tx;
	if ( $tkey = $Registry->{$tx} ) {
		foreach my $ent (  keys(%$tkey)  ) {
			my $dat1 = $tkey->{$ent};
			$ent =~ s/^\///;	# drop leading separator
			my $tx3 = $tx2 . '.' . $ent;
			my @aent = split(/\x00/, $dat1);
			my $ct = scalar @aent;
			my $vl = join(' ',@aent);
			if ($ct == 1) {
				$vl = $dat1;
				prt( "ent = [$ent], dat1 = [$dat1]\n" );
			} else {
				###prt( "ent = $ent - $ct items\n" );
				$lcnt = 0;
				$vl = join('#', @aent);
				###prt( "[$vl]\n" );
				my $sval = '';
				foreach my $d (@aent) {
					$d =~ s/^\///;
					$lcnt++;
					###prt( "dat".$lcnt." = [$d]\n" );
					if (length($d) == 0) {
						if ( length($sval) && (substr($sval,-1) eq ' ') ) {
							$d = '';
						} else {
							$d = ' ';
						}
					}
					$sval .= $d;
				}
				prt( "ent = [$ent] $lcnt [$sval]\n" );
				$vl = $sval;
			}
			if (defined $KeysVal{$tx3}) {
				prt( "Adding [$vl] to " . $KeysVal{$tx3} . "...\n" );
				$KeysVal{$tx3} .= ' ' . $vl;
			} else {
				$KeysVal{$tx3} = $vl;
			}
		}
	} else {
		prt( "\nERROR: Can't open [$tx] value: $^E\n" );
	}
}

###################################
sub nice_string {
	join("",
		map { $_ > 255 ?                  # if wide character...
               sprintf("\\x{%04X}", $_) :  # \x{...}
               chr($_) =~ /[[:cntrl:]]/ ?  # else if control character ...
               sprintf("\\x%02X", $_) :    # \x..
               quotemeta(chr($_))          # else quoted or as themselves
         } unpack("U*", $_[0]));           # unpack Unicode characters
}

###########################################################################
# VERY IMPORTANT SERVICE
# This converts the 'text' into HTML text, but only does a partial job!
# 1. Convert '&' to '&amp;' to avoid interpreting as replacement
# 2. Convert '<' to '&lt;' to avoid interpreting as HTML
# 3. Convert '"' to '&quot;'
# 4. Convert '\t' to SPACES
# 5. Finally, if there are double or more SPACES, convert to '&nbsp;'
###########################################################################
sub html_line {
   my $t = shift;
   #my $ot = $t;
   $t =~ s/&/&amp;/g; # all '&' become '&amp;'
   $t =~ s/</&lt;/g; # make sure all '<' is/are swapped out
   $t =~ s/\"/&quot;/g; # and all quotes become &quot;
   $t =~ s/\t/$tab_space/g; # tabs to spaces
   #if ($t =~ /\s\s/) { # if any two consecutive white space
   #   return conv_spaces($t);
   #}
   #prt( "html_line: from [$ot] to [$t] ...\n" ) if $debug_on;
   return $t;
}

sub html2text {
	my ($t) = shift;
	$t =~ s/&amp;/&/g;
    $t =~ s/&lt;/</g; # make sure all '<' is/are swapped back
    $t =~ s/&quot;/\"/g; # and all &quot; become "
	$t =~ s/&nbsp;/ /g;	# back to real space
	return $t;
}

sub trim_tail {
	my ($ln) = shift;
	while (length($ln) && ($ln =~ /\s$/m)) {
		$ln = substr($ln,0, length($ln) - 1);
	}
	return $ln;
}


# eof - recent.pl

