Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 246 lines (214 sloc) 11.7 KB
# basically create a readable version of xml-ish files like
# firefox sessionstore, optionally grepping some values. This is
# more of a quick hackish parser testbed for a quick way to
# mangle structured files than a stable and unchanging program.
# also useful for things like moving tabs from the default
# current firefox instance to a -3 3.0 firefox instance, or
# -sm seamonkey, or whatever you added to the firefox(stdin)? wrapper
# firefoxsessionlist -tree | grep github | firefoxstdin -3
my $version="0.2";
# 20090213 PJ 0.1 initial version
# 20090729 PJ 0.2 small fixes for ff3.5
# 20090906 PJ fixed default/-list to work with 3.5
# copyright: (c) 2009, placed under GPL v3 or later
# archive:
undef $/;
while($_=shift @ARGV) {
/^-i$/ and do{ $igncase=1; next};
/^-t$/ and do{ $titlegrep=1; next};
/^-file$/ and do{ $file=shift; next};
/^-list$/ and do{ $cmd.=" list "; next};
/^-cookies$/ and do{ $cmd.=" cookies "; next};
/^-tree$/ and do{ $cmd.=" tree "; next};
/^-treeview$/ and do{ $cmd.=" treedump "; next};
/^-listview$/ and do{$cmd.=" print "; next};
/^-grep$/ and do{ $grep=shift; next};
print <<EOF;
read an xml-ish file and return a readable or tree version.
-file FILENAME # defaults to mozilla sessionstore file
-grep REGEX
-i / -t # grep: ignore case, include title
# these try to print only data from tabs
-list # list or grep urls from sessionstore file
# (default; fast, but really not properly parsing at all)
-cookies # generate cookies.txt-style output from treeview-parsed sessionstore
-tree # list or grep urls from treeview-parsed sessionstore
# view sessionstore.js style files (might also prettyprint paranthesed data)
-listview # no real parsing, but keep track of paren levels
-treeview # proper recursive parsing into an internal data structure
- mozilla may take quite a few seconds to update the sessionstore.js file,
so sleeping is advised.
- if it doesn't like the input, also try the -tree/-treeview and
the -listview options, as those might still work for your input
- I'm looking forward to the PEGs of perl 6 :)
- use firefoxsessionlist -tree | grep ... | firefoxstdin -3
to load a subset of active tabs into another browser
(for this trick you need 2 browsers that do NOT 'see' each
other with the --remote command, such as firefox 3.0 and 3.5.
NOTE that this is implemented by X resources, thus any 3.5
firefox on the same X DISPLAY will use the 'first' 3.5 and
its profile for all --remote uses. NOTE2: the default for
--remote/--no-remote has been switched with 3.5).
$file="$HOME/.firefox/sessionstore.js" if not $file;
if (not -f $file) {
# allows for migration from firefox to a hopefully more current firefox-<...>
my $firefoxhome=`ls -dr1 ~/.mozilla/firefox{,-*}| head -1`;
$file=`ls -dt1 $firefoxhome/*default/sessionstore.js 2>/dev/null | head -1`;
if($file) {
warn "# opening '$file'\n";
open(FH,"<", $file) and $contents=<FH>; close FH;
die "no input.\n" if not $contents;
$cmd=" list " if not $cmd;
$grep="(?i)$grep" if $igncase; # extends beyond '|', but not beyond an enclosing ')'
$titlegrep=$grep if $titlegrep;
# common init for tree/treedump
$cmd=~/ tree | treedump / and do{
#use Storable qw/freeze thaw/; $Storable::canonical=1; print freeze($tree);
#use FreezeThaw qw/freeze thaw/; print freeze($tree);
use Data::Dumper;
# lex sort in general, but pairs of numbers in numeric order please - may show a few oddities for inputs like 000a and 002 and 43b
$Data::Dumper::Sortkeys=sub{my($hash)=@_;return[sort {($a=~/\A[\d]+\Z/o and $b=~/\A[\d]+\Z/o) ? $a<=>$b : $a cmp $b} keys %$hash]};
$cmd=~/ treedump / and do{
print Dumper($tree);
$cmd=~/ tree / and do{
$node=$node->{$anonprefix.$anonstart} while defined $node and not $node->{windows}; $node=$node->{windows} or die "no window no tabs.";
foreach $w (map {$node->{$_}} sort keys %$node) {
foreach $t (map {$w->{tabs}->{$_}} sort keys %{$w->{tabs}}) {
$e=$t->{entries}->{$anonprefix . ( $t->{index}-1+$anonstart )};
$url= $e->{url};
if ($grep) {
#print Dumper($t);
print "$url\n" if $url=~/$grep/o or $title=~/$titlegrep/o;
} else {
print "$url\n";
$cmd=~/ cookies / and do{
$node=$node->{$anonprefix.$anonstart} while $node and not $node->{windows}; $node=$node->{windows} or die "no window no tabs.";
foreach $w (map {$node->{$_}} sort keys %$node) {
foreach $c (map {$w->{cookies}->{$_}} sort keys %{$w->{cookies}}) {
$c->{httponly} and $c->{ishttponly}= $c->{httponly};
$c->{secure} and $c->{issecure} = $c->{secure}; # force use of prefix _is_ like in cookies.sqlite!
$c->{ishttponly} eq 'false' and $c->{ishttponly}= 0; # values in sqlite: int (true values other than 1?)
$c->{issecure} eq 'false' and $c->{issecure} = 0;
$c->{ishttponly} = 0!=$c->{ishttponly} ? "TRUE" : "FALSE";
$c->{issecure} = 0!=$c->{issecure} ? "TRUE" : "FALSE";
$c->{expiry} or $c->{expiry} = time + 38640000; # more than a year from now
foreach (qw/ host ishttponly path issecure expiry name value/) {
$t.="\t" if $t;
print $t,"\n";
$cmd=~/ print / and do{print &readable};
$cmd=~/ list / and do{print &tab2list};
# return readable representations of paranthesed data:
# arithmetics using substr/pos:
# perl -e '$a="123456789"; $a=~/45/g; print pos $a, " $` $& $'"'"' ", substr($a,0,pos $a), " ", substr($a, pos $a), "\n"'
# for now all routines operate on main::$_ directly
# for the sessionstore.js file:
# mozilla: typically this is an implicit tree, with strings and levels implying semantics
# ( ??? - anyway, we have only one pair, encapsulating the whole mess.
# [ denoting list of objects (implying that "{" denotes object cum structure)
# (the children: retain the urls for frames / iframes, required if the topurl does not change)
# string: name of object or object attribute
# why are cookies and hosts associated with the window instead of the session!?
sub tree {
return tree1();
sub tree1 {
# for now operating on $_ directly with side effects
# BUG: the anonymous element naming is a bit risky...
my %node=();
while(1) {
if (not defined $name) { $name=$anonprefix.$anon++; }
/\A\s+/go and do{$_=substr($_,pos);next};
/\A\(/go and do{$_=substr($_,pos); $node{$name}=&tree1(); $name=undef};
/\A\[/go and do{$_=substr($_,pos); $node{$name}=&tree1(); $name=undef};
/\A\{/go and do{$_=substr($_,pos); $node{$name}=&tree1(); $name=undef};
/\A,/go and do{$_=substr($_,pos); $node{$name}=$value if $value; $name=undef};
/\A:/go and do{$_=substr($_,pos); $name=$value; $value=undef;};
( /\A"([^\\]*?(\\[\S\s])?)*?"/go or
/\A'([^\\]*?(\\[\S\s])?)*?'/go )
and do{$value=substr($_,1,pos()-2);$_=substr($_,pos);};
/\A[^ \t,\{\[\(\}\]\)\x0a\x0d'":]+/go
and do{$value=substr($_,0,pos);$_=substr($_,pos);};
/\A[\)\]\}]/go and do{$_=substr($_,pos);last};
# /()/go and do{last};
not $_ and do{last};
if (not defined $name) { $name=$anonprefix.$anon; }
if ($value) {$node{$name}=$value};
return \%node;
sub readable {
while(1) {
# expr outbuf or output outbuf delta out-offset clear outbuf
# set new inbuf loopcontrol
/\A[\t ]+/go and do{$out.=substr($_,0,pos) if $out; $_=substr($_,pos); next};
and do{$out.=substr($_,0,pos); $_=substr($_,pos); next};
and do{$out.=substr($_,0,pos); $_=substr($_,pos); next};
/\A[\{\(\[]/go and do{push @return, " " x $level . $out . substr($_,0,pos) . "\n"; $level+=$offset; $_=substr($_,pos); $out=""; next};
/\A[\}\)\]],?/go and do{push @return, " " x $level . $out . "\n" if $out; $level-=$offset;
push @return, " " x $level . substr($_,0,pos) . "\n"; $_=substr($_,pos); $out=""; next};
/\A,/go and do{push @return, " " x $level . $out . substr($_,0,pos) . "\n"; $_=substr($_,pos); $out=""; next};
/\A[\x0a\x0d]+/go and do{push @return, " " x $level . $out . substr($_,0,pos) . "\n"; $_=substr($_,pos); $out=""; next};
/\A[^ \t,\{\[\(\}\]\)\x0a\x0d'"]+/go
and do{$out.=substr($_,0,pos); $_=substr($_,pos); next};
# /()/go and do{push @return, " " x $level . $out . "\n" if $out; $out=""; last};
not $_ and do{push @return, " " x $level . $out . "\n" if $out; $out=""; last};
return @return;
sub tab2list {
next if $grep and $url!~/$grep/o;
next if $url{$url}++;
push @return, "$url\n";
return @return;