From 2e051ab008bf05744dae8e16eed2acd3751e00cd Mon Sep 17 00:00:00 2001 From: Ryan Farley Date: Tue, 31 Oct 2017 18:39:35 -0500 Subject: [PATCH] importer: add mozilla places.sqlite support This adds supports for the places.sqlite format as used by Firefox, Seamonkey, Pale Moon, and presumably others. Search engine support is limited to keyword-style '%s' functionality. vulture whitelist for row_factory --- scripts/dev/run_vulture.py | 1 + scripts/importer.py | 78 +++++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/scripts/dev/run_vulture.py b/scripts/dev/run_vulture.py index 1c0b2224b..b4d064c0d 100755 --- a/scripts/dev/run_vulture.py +++ b/scripts/dev/run_vulture.py @@ -122,6 +122,7 @@ def whitelist_generator(): # noqa yield 'qutebrowser.command.command.ArgInfo._validate_exclusive' yield 'scripts.get_coredumpctl_traces.Line.uid' yield 'scripts.get_coredumpctl_traces.Line.gid' + yield 'scripts.importer.import_moz_places.places.row_factory' def filter_func(item): diff --git a/scripts/importer.py b/scripts/importer.py index 9171bbbb6..d664af7c1 100755 --- a/scripts/importer.py +++ b/scripts/importer.py @@ -22,18 +22,21 @@ """Tool to import data from other browsers. -Currently only importing bookmarks from Netscape Bookmark files is supported. +Currently importing bookmarks from Netscape Bookmark files and Mozilla +profiles is supported. """ import argparse +import sqlite3 +import os browser_default_input_format = { 'chromium': 'netscape', 'ie': 'netscape', - 'firefox': 'netscape', - 'seamonkey': 'netscape', - 'palemoon': 'netscape' + 'firefox': 'mozilla', + 'seamonkey': 'mozilla', + 'palemoon': 'mozilla' } @@ -68,7 +71,10 @@ def main(): #default to netscape input_format = 'netscape' - import_function = {'netscape': import_netscape_bookmarks} + import_function = { + 'netscape': import_netscape_bookmarks, + 'mozilla': import_moz_places + } import_function[input_format](args.bookmarks, bookmark_types, output_format) @@ -132,7 +138,10 @@ def get_args(): action='store_true', default=False, required=False) - parser.add_argument('bookmarks', help="Bookmarks file (html format)") + parser.add_argument( + 'bookmarks', + help="Bookmarks file (html format) or " + "profile folder (Mozilla format)") args = parser.parse_args() return args @@ -202,5 +211,62 @@ def import_netscape_bookmarks(bookmarks_file, bookmark_types, output_format): print(bookmark) +def import_moz_places(profile, bookmark_types, output_format): + """Import bookmarks from a Mozilla profile's places.sqlite database.""" + place_query = { + 'bookmark': + ("SELECT DISTINCT moz_bookmarks.title,moz_places.url " + "FROM moz_bookmarks,moz_places " + "WHERE moz_places.id=moz_bookmarks.fk " + "AND moz_places.id NOT IN (SELECT place_id FROM moz_keywords) " + "AND moz_places.url NOT LIKE 'place:%';" + ), # Bookmarks with no keywords assigned + 'keyword': + ("SELECT moz_keywords.keyword,moz_places.url " + "FROM moz_keywords,moz_places,moz_bookmarks " + "WHERE moz_places.id=moz_bookmarks.fk " + "AND moz_places.id=moz_keywords.place_id " + "AND moz_places.url NOT LIKE '%!%s%' ESCAPE '!';" + ), # Bookmarks with keywords assigned but no %s substitution + 'search': + ("SELECT moz_keywords.keyword, " + " moz_bookmarks.title, " + " search_conv(moz_places.url) AS url " + "FROM moz_keywords,moz_places,moz_bookmarks " + "WHERE moz_places.id=moz_bookmarks.fk " + "AND moz_places.id=moz_keywords.place_id " + "AND moz_places.url LIKE '%!%s%' ESCAPE '!';" + ) # bookmarks with keyword and %s substitution + } + out_template = { + 'bookmark': { + 'bookmark': '{url} {title}', + 'keyword': '{url} {keyword}' + }, + 'quickmark': { + 'bookmark': '{title} {url}', + 'keyword': '{keyword} {url}' + }, + 'oldsearch': { + 'search': '{keyword} {url} #{title}' + }, + 'search': { + 'search': "c.url.searchengines['{keyword}'] = '{url}' #{title}" + } + } + + def search_conv(url): + return search_escape(url).replace('%s', '{}') + + places = sqlite3.connect(os.path.join(profile, "places.sqlite")) + places.create_function('search_conv', 1, search_conv) + places.row_factory = sqlite3.Row + c = places.cursor() + for typ in bookmark_types: + c.execute(place_query[typ]) + for row in c: + print(out_template[output_format][typ].format(**row)) + + if __name__ == '__main__': main()