use DBD::SQLite; use strict; use warnings; =pod This program reads a file named places.sqlite which is found somewhere under your folder named Mozilla/Firefox/Profiles You pass the pathname of this file as a command-line argument. This program outputs html. =cut my $dbfile = shift; $dbfile or die "Usage: $0 /places.sqlite \n"; -r $dbfile or die "Unreadable $dbfile\n"; $dbfile =~ /\bplaces\.sqlite$/ or die "File should be places.sqlite\n"; my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","","") or die "Error opening db $dbfile\n"; my $bookmarks = $dbh->selectall_hashref("select * from moz_bookmarks",'id'); my $places = $dbh->selectall_hashref("select * from moz_places",'id'); # construct the tree: my $root; for my $b ( values %$bookmarks ) { if ( $b->{parent} ) { my $p = $bookmarks->{ $b->{parent} }; push @{ $p->{children} }, $b; } else # yep, there's exactly one. { $root = $b; } } # produce the html: local($,,$\)=("\t","\n"); sub walk; # because it recurses. sub walk { my $depth = shift; my $n = shift; my $indent = "\t" x $depth; if ( $n->{type} == 2 ) # folder { print $indent . ($depth?"
  • ":'') . "

    $n->{title}

    "; if ( $n->{children} ) { print $indent . "
      "; for my $c ( sort { $a->{position} <=> $b->{position} } @{ $n->{children} } ) { walk($depth+1,$c); } print $indent . "
    "; } $depth and print $indent . "
  • "; } else # leaf bookmark { my $link = $n->{title}; if ( $n->{fk} and $places->{$n->{fk}} and $places->{$n->{fk}}{url} ) { my $url = $places->{$n->{fk}}{url}; $link =~ /\S/ or $link = $url; $link = qq($link); } else { $link =~ /\S/ or $link = "$n->{type}:$n->{id}"; } print $indent . "
  • $link
  • "; } } walk(0,$root);