#!/usr/bin/perl use strict; use warnings; # use it like, # $ ./num-tabs.pl opera # $ ./num-tabs.pl palemoon # $ ./num-tabs.pl firefox use Cwd; use Fcntl qw(:seek); use Time::Piece; my $debug = 0; my $browser = lc($ARGV[0]); print "browser: $browser\n" if $debug; #$browser = 'opera' unless $browser; my $extension; if ($browser eq 'opera') { $extension = 'win'; } elsif ($browser eq 'palemoon' | $browser eq 'firefox') { $extension = 'session'; } else { print "Browser, \'$browser\', not supported.\n"; print "Put it in the dir with the session files then like below.\n$0 opera\n$0 palemoon\n$0 firefox\n"; exit; } my $dir = cwd(); my @files = glob( $dir . "/*.$extension" ); if ($debug) { print "files: " . scalar(@files) . "\n"; } my %sessions; foreach my $sessionfile (@files) { print "Filename: $sessionfile\n" if $debug; my $date; # does it follow my filename conventions? $date = use_superkuh_date_embeded_filenames($sessionfile); # if it isn't in the filename get the last modified date/time. unless ($date) { my $t = localtime((stat $sessionfile)[9]); $date = $t->ymd . " " . $t->hms; } my @entries; my $tabs = 0; if ($browser eq 'opera') { # Opera 5 - Opera 12 { open(SESSION, "$sessionfile") or die; local $/ = '\n'; while () { # all tab entries start with [4] or [5] or [6] or [48], etc. # count the number of matches for that pattern. $tabs = () = $_ =~ /\[\d+\]/g; } close SESSION; # but the first three entries, [1],[2],[3] are browser window meta-data, not tabs. # minus 3 from total tabs to fix the offset $tabs -= 3; # if there were 0 tabs, meaning no decodable text, try binary session parsing. if ($tabs == -3) { $tabs = op6binarytabs($sessionfile); } } } else { # Pale Moon and Firefox ([SessionManager v2] extension) # timestamp=1364215630579 # autosave=false count=1/142 screensize=1920x1080 { local $/ = '0xd'; # CARRIAGE RETURN (CR) open(SESSION, "$sessionfile") or die; while() { if (/count=\d+\/(\d+)/) { $tabs = $1; } } close SESSION; } } print "tabs: $tabs\n" if $debug; $sessions{$date} = $tabs; } for (sort {$a cmp $b} (keys %sessions)) { if ($sessions{$_} == -3) { print "$_ couldn't be parsed.\n"; } else { print "$_,$sessions{$_}\n"; } } sub op6binarytabs { # this is all just getting the third byte out and converting it to a decimal number. # it might be that for very large session both byte 2 and 3 are used. I ignore this. my $filename = shift; my($fh, $byte_position, $byte_value); $byte_position = 3; open($fh, "<", $filename) || die "can't open $filename: $!"; binmode($fh) || die "can't binmode $filename"; sysseek($fh, $byte_position, SEEK_CUR) # NB: 0-based || die "couldn't see to byte $byte_position in $filename: $!"; sysread($fh, $byte_value, 1) == 1 || die "couldn't read byte from $filename: $!"; close $fh; return ord($byte_value); } sub use_superkuh_date_embeded_filenames { my $sessionfile = shift; my $date = 0; # /12-28_21-04___Op76.win # /01-02_10-04.win # /11-12_1-03.win if ($sessionfile =~ m#.+/(\d\d)-(\d+)_(\d+)-(\d\d).+#) { # 2d Year Month Day 24H time $date = "20" . $4 . "-" . $1 . "-" . $2 . " $3:00:00"; } # /8-17-03.win if ($sessionfile =~ m#.+/(\d)-(\d\d)-(\d\d).+#) { # 2d Year Month Day 24H time $date = "20" . $3 . "-" . "0" . $1 . "-" . $2 . " 00:00:00"; } # /8-20_5-03.win if ($sessionfile =~ m#.+/(\d)-(\d\d)_(\d\d)-(\d\d).+#) { # 2d Year Month Day 24H time $date = "20" . $4 . "-" . $1 . "-" . $2 . " $3:00:00"; } return $date; }