Viewing file: mozillasource.py (39.69 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# # Copyright (C) 2005 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #
import gobject import exceptions, sys, os.path, ConfigParser, re, cPickle import tempfile, types import traceback import errno import time
try: import util import config import userprofile import dirmonitor import mozilla_bookmarks except: from sabayon import util from sabayon import config from sabayon import userprofile from sabayon import dirmonitor from sabayon import mozilla_bookmarks
class file_state: (UNKNOWN, VALID, NOT_FOUND, SYS_ERROR, PARSE_ERROR ) = range(5)
firefox_rel_path = ".mozilla/firefox"
profiles_ini_rel_path = os.path.join(firefox_rel_path, "profiles.ini")
sabayon_pref_rel_path = os.path.join(firefox_rel_path, "sabayon-prefs.js") sabayon_mandatory_pref_rel_path = os.path.join(firefox_rel_path, "sabayon-mandatory-prefs.js")
sabayon_bookmark_rel_path = os.path.join(firefox_rel_path, "sabayon-bookmarks.html") sabayon_mandatory_bookmark_rel_path = os.path.join(firefox_rel_path, "sabayon-mandatory-bookmarks.html")
LOG_OPERATION = 0x00001 LOG_CHANGE = 0x00002 LOG_IGNORED_CHANGE = 0x00004 LOG_APPLY = 0x00008 LOG_SYNC = 0x00010 LOG_PARSE = 0x00020 LOG_PREF = 0x00040 LOG_FILE_CONTENTS = 0x00080 LOG_DATA = 0x00100 LOG_VERBOSE = 0x10000
def dprint(mask, fmt, *args): util.debug_print(util.DEBUG_MOZILLASOURCE, fmt % args, mask)
def dwarn(fmt, *args): print >> sys.stderr, "WARNING " + fmt % args
bookmark_exclude_attrs = [re.compile("^id$"), re.compile("^last_"), re.compile("^add_"), #re.compile("^icon$"), ]
def filter_attr(attr, exclude): if not exclude: return False
for regexp in exclude: if regexp.search(attr): return True return False
class MozillaChange(userprofile.ProfileChange): ( CREATED, DELETED, CHANGED ) = range(3) def __init__ (self, source, delegate, type, key, value, event): userprofile.ProfileChange.__init__ (self, source, delegate) assert event == self.CREATED or \ event == self.DELETED or \ event == self.CHANGED self.type = type self.key = key self.value = value self.event = event self.attrs = {}
def set_attr(self, attr, value): self.attrs[attr] = value
def get_attr(self, attr): return self.attrs[attr]
def get_type(self): return self.type
def get_key(self): return self.key
def get_value(self): return self.value
def get_id(self): return self.key
def get_short_description(self): if self.event == self.CREATED: return _("Mozilla key '%s' set to '%s'") % (self.key, self.value) elif self.event == self.DELETED: return _("Mozilla key '%s' unset") % self.key elif self.event == self.CHANGED: return _("Mozilla key '%s' changed to '%s'") % (self.key, self.value) else: raise ValueError
gobject.type_register(MozillaChange)
class MozillaDelegate(userprofile.SourceDelegate): def __init__ (self, source): dprint(LOG_OPERATION, "Delegate construction") userprofile.SourceDelegate.__init__ (self, "Firefox", source, ".mozilla") self.source = source self.delegate = self self.home_dir = util.get_home_dir() self.committed_prefs = {} self.committed_mandatory_prefs = {} self.committed_bookmarks = mozilla_bookmarks.BookmarkFolder("Null", None) self.committed_mandatory_bookmarks = mozilla_bookmarks.BookmarkFolder("Null", None) self.ini_file = None
def get_full_path(self, path): return os.path.join(self.home_dir, path)
def get_profiles_ini_path(self): return self.get_full_path(profiles_ini_rel_path)
def get_path_description (self, path): type = get_type_from_path(path)
if type == FirefoxProfileFile.TYPE_PREFS: return _("Web browser preferences") elif type == FirefoxProfileFile.TYPE_BOOKMARK: return _("Web browser bookmarks") elif type == FirefoxProfileFile.TYPE_PROFILE_INI: return _("Web browser profile list") else: # XXX basename = os.path.basename(path) if basename.endswith("prefs.js"): return _("Web browser preferences") elif basename.endswith("bookmarks.html"): return _("Web browser bookmarks") else: return path
def load_profiles_ini(self): if not self.ini_file: self.ini_file = FirefoxProfilesIni(self.home_dir, profiles_ini_rel_path) self.ini_file.read()
def load_profiles(self): if self.ini_file: self.ini_file.load_profiles()
def is_ini_file(self, rel_path): if rel_path == profiles_ini_rel_path: return True else: return False
def is_profile_file(self, rel_path): if self.ini_file and self.ini_file.is_valid(): rel_dir = os.path.dirname(rel_path) for profile in self.ini_file.get_profiles(): profile_rel_dir = profile.get_rel_dir() if rel_dir.startswith(profile_rel_dir): return profile return None else: return None
def handle_change(self, change): rel_path = change.get_id() # # INI File # if self.is_ini_file(rel_path): dprint(LOG_CHANGE, "%s ini file: %s", dirmonitor.event_to_string(change.event), rel_path) self.load_profiles_ini()
# # Profile File # profile = self.is_profile_file(rel_path) if profile: dprint(LOG_CHANGE, "%s profile file: %s", dirmonitor.event_to_string(change.event), rel_path)
profile_file = profile.add_file(rel_path) profile_file_type = profile_file.get_type()
if profile_file_type == FirefoxProfileFile.TYPE_PREFS: assert isinstance(profile_file, JavascriptPrefsFile) if change.event == dirmonitor.CREATED or \ change.event == dirmonitor.CHANGED: cat_file(profile_file.get_full_path()) profile_file.read() profile_file.emit_changes(self.source, self.delegate) return True elif change.event == dirmonitor.DELETED: # XXX - what to do here? pass else: raise ValueError elif profile_file_type == FirefoxProfileFile.TYPE_BOOKMARK: assert isinstance(profile_file, BookmarksFile) if change.event == dirmonitor.CREATED or \ change.event == dirmonitor.CHANGED: profile_file.read() profile_file.emit_changes(self.source, self.delegate) return True elif change.event == dirmonitor.DELETED: # XXX - what to do here? pass else: raise ValueError elif profile_file_type != FirefoxProfileFile.TYPE_UNKNOWN: if change.event == dirmonitor.CREATED or \ change.event == dirmonitor.CHANGED: profile.add_file(rel_path) elif change.event == dirmonitor.DELETED: profile.del_file(rel_path) else: raise ValueError else: return True # # Ignored Files # dprint(LOG_IGNORED_CHANGE, "IGNORED: %s", rel_path) return True
def commit_change(self, change, mandatory = False): if isinstance(change, MozillaChange): dprint(LOG_CHANGE, "Commiting preference (mandatory = %s) key = %s value = %s event = %s", mandatory, change.key, change.value, change.event)
if mandatory: self.committed_mandatory_prefs[change.get_key()] = \ JavascriptPreference(change.get_type(), change.get_key(), change.get_value()) else: self.committed_prefs[change.get_key()] = \ JavascriptPreference(change.get_type(), change.get_key(), change.get_value()) elif isinstance(change, BookmarkChange): bookmark_path = change.get_bookmark_path() entry = change.get_entry()
dprint(LOG_CHANGE, "Commiting bookmark (mandatory = %s) path = %s url = %s event = %s", mandatory, entry.path_as_string(), entry.get_url(), change.event)
if mandatory: self.committed_mandatory_bookmarks.add_path_entry(entry.path(), entry) else: self.committed_bookmarks.add_path_entry(entry.path(), entry)
def start_monitoring (self): """Start monitoring for configuration changes.""" # Read all files we are going to monitor so that when a change is # reported we have a "before" state to compare to and thus derive # what is different. dprint(LOG_OPERATION, "start_monitoring:") self.load_profiles_ini() self.load_profiles()
def stop_monitoring (self): """Stop monitoring for configuration changes.""" dprint(LOG_OPERATION, "stop_monitoring:")
def sync_changes(self): """Ensure that all committed changes are saved to disk."""
dprint(LOG_SYNC, "sync_changes: home_dir = %s", self.home_dir) ini = self.ini_file if ini.is_valid(): default_profile = ini.get_default_profile()
self.source.storage.add(ini.get_rel_path(), self.home_dir, self.name, {"file_type" : FirefoxProfileFile.TYPE_PROFILE_INI})
if len(self.committed_prefs) > 0: pref_rel_path = sabayon_pref_rel_path dprint(LOG_SYNC, "sync_changes: storing committed_prefs to %s", pref_rel_path) pref_file = JavascriptPrefsFile(self.home_dir, pref_rel_path) pref_file.set_prefs(self.committed_prefs) pref_file.write() self.source.storage.add(pref_rel_path, self.home_dir, self.name, {"file_type" : FirefoxProfileFile.TYPE_PREFS, "mandatory" : False})
if len(self.committed_mandatory_prefs) > 0: pref_rel_path = sabayon_mandatory_pref_rel_path dprint(LOG_SYNC, "sync_changes: storing mandatory committed_prefs to %s", pref_rel_path) pref_file = JavascriptPrefsFile(self.home_dir, pref_rel_path) pref_file.set_prefs(self.committed_mandatory_prefs) pref_file.write() self.source.storage.add(pref_rel_path, self.home_dir, self.name, {"file_type" : FirefoxProfileFile.TYPE_PREFS, "mandatory" : True})
if len(self.committed_bookmarks.entries) > 0: bookmark_rel_path = sabayon_bookmark_rel_path dprint(LOG_SYNC, "sync_changes: storing committed_bookmarks to %s", bookmark_rel_path) bookmark_file = BookmarksFile(self.home_dir, bookmark_rel_path) bookmark_file.set_root(self.committed_bookmarks) bookmark_file.write(exclude_attrs=bookmark_exclude_attrs) self.source.storage.add(bookmark_rel_path, self.home_dir, self.name, {"file_type" : FirefoxProfileFile.TYPE_BOOKMARK, "mandatory" : False})
if len(self.committed_mandatory_bookmarks.entries) > 0: bookmark_rel_path = sabayon_mandatory_bookmark_rel_path dprint(LOG_SYNC, "sync_changes: storing mandatory committed_bookmarks to %s", bookmark_rel_path) bookmark_file = BookmarksFile(self.home_dir, bookmark_rel_path) bookmark_file.set_root(self.committed_mandatory_bookmarks) bookmark_file.write(exclude_attrs=bookmark_exclude_attrs) self.source.storage.add(bookmark_rel_path, self.home_dir, self.name, {"file_type" : FirefoxProfileFile.TYPE_BOOKMARK, "mandatory" : True})
def set_enforce_mandatory (self, enforce): # Nothing to do here pass
def apply(self, is_sabayon_session): ini_files = [] pref_files = [] bookmark_files = [] other_files = [] dprint(LOG_APPLY, "apply: home_dir = %s", self.home_dir) storage_contents = self.source.storage.list(self.name)
for source, path in storage_contents: attributes = self.source.storage.get_attributes(path) file_type = attributes.get("file_type", None) if file_type != None: file_type = int(file_type) else: file_type = get_type_from_path(path)
if file_type == FirefoxProfileFile.TYPE_PROFILE_INI: ini_files.append(path) elif file_type == FirefoxProfileFile.TYPE_PREFS: pref_files.append(path) elif file_type == FirefoxProfileFile.TYPE_BOOKMARK: bookmark_files.append(path) elif file_type == FirefoxProfileFile.TYPE_UNKNOWN: other_files.append(path) else: raise ValueError dprint(LOG_APPLY, "apply: ini_files=%s pref_files=%s bookmark_files=%s other_files=%s", ini_files, pref_files, bookmark_files, other_files)
# Profiles.ini file must be done first, if the target does not # exist then extract it from the profile. # Parse the profiles.ini file to learn the target profiles self.load_profiles_ini() if not self.ini_file.is_valid(): dprint(LOG_APPLY, "apply: no valid ini file, extracting %s", profiles_ini_rel_path) if profiles_ini_rel_path in ini_files: self.source.storage.extract(profiles_ini_rel_path, self.home_dir, True) self.load_profiles_ini() else: dprint(LOG_APPLY, "apply: but there isn't an ini file in the profile!")
# -------------------- if sabayon_pref_rel_path in pref_files: dprint(LOG_APPLY, "extracting %s" % sabayon_pref_rel_path) self.source.storage.extract(sabayon_pref_rel_path, self.home_dir, True) apply_pref = JavascriptPrefsFile(self.home_dir, sabayon_pref_rel_path) apply_pref.read() else: apply_pref = None
if sabayon_mandatory_pref_rel_path in pref_files: dprint(LOG_APPLY, "extracting %s" % sabayon_mandatory_pref_rel_path) self.source.storage.extract(sabayon_mandatory_pref_rel_path, self.home_dir, True) mandatory_apply_pref = JavascriptPrefsFile(self.home_dir, sabayon_mandatory_pref_rel_path) mandatory_apply_pref.read() else: mandatory_apply_pref = None
# --------------------
if sabayon_bookmark_rel_path in bookmark_files: dprint(LOG_APPLY, "extracting %s" % sabayon_bookmark_rel_path) self.source.storage.extract(sabayon_bookmark_rel_path, self.home_dir, True) apply_bookmark = BookmarksFile(self.home_dir, sabayon_bookmark_rel_path) apply_bookmark.read() else: apply_bookmark = None
if sabayon_mandatory_bookmark_rel_path in bookmark_files: dprint(LOG_APPLY, "extracting %s" % sabayon_mandatory_bookmark_rel_path) self.source.storage.extract(sabayon_mandatory_bookmark_rel_path, self.home_dir, True) mandatory_apply_bookmark = BookmarksFile(self.home_dir, sabayon_mandatory_bookmark_rel_path) mandatory_apply_bookmark.read() else: mandatory_apply_bookmark = None
# --------------------
# Now merge the javascript pref files # XXX - iterate over all target profiles for profile in self.ini_file.get_profiles(): dprint(LOG_APPLY, "apply: applying to profile %s", profile.attrs) profile_rel_dir = profile.get_rel_dir()
# -------------------- target_pref_rel_path = os.path.join(profile_rel_dir, "prefs.js") target_pref = JavascriptPrefsFile(self.home_dir, target_pref_rel_path) target_pref.read()
if apply_pref: mandatory = False dprint(LOG_APPLY, "apply: applying src profile %s to target profile %s, mandatory=%s", sabayon_pref_rel_path, target_pref_rel_path, mandatory) target_pref.merge(apply_pref, mandatory)
if mandatory_apply_pref: mandatory = True dprint(LOG_APPLY, "apply: applying src profile %s to target profile %s, mandatory=%s", sabayon_pref_rel_path, target_pref_rel_path, mandatory) target_pref.merge(mandatory_apply_pref, mandatory)
if apply_pref or mandatory_apply_pref: target_pref.write()
# -------------------- target_bookmark_rel_path = os.path.join(profile_rel_dir, "bookmarks.html") target_bookmark = BookmarksFile(self.home_dir, target_bookmark_rel_path) target_bookmark.read()
if apply_bookmark: mandatory = False dprint(LOG_APPLY, "apply: applying src profile %s to target profile %s, mandatory=%s", sabayon_bookmark_rel_path, target_bookmark_rel_path, mandatory) target_bookmark.merge(apply_bookmark, mandatory)
if mandatory_apply_bookmark: mandatory = True dprint(LOG_APPLY, "apply: applying src profile %s to target profile %s, mandatory=%s", sabayon_bookmark_rel_path, target_bookmark_rel_path, mandatory) target_bookmark.merge(mandatory_apply_bookmark, mandatory)
if apply_bookmark or mandatory_apply_bookmark: target_bookmark.write()
# Finally extract any other file for path in other_files: attributes = self.source.storage.get_attributes(path) mandatory = attributes.get("mandatory", False) dprint(LOG_APPLY, "apply: extracting other file %s, mandatory=%s", path, mandatory) self.source.storage.extract(path, self.home_dir, mandatory) dprint(LOG_APPLY, "apply: finished")
def get_files_delegate(source): return MozillaDelegate(source)
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# ------ Globals ------
# XXX - Warning: this regular expression is not perfectly robust # the 1st parameter is expected to be a double quoted string without # commas in it nor escaped double quotes. The parsing of the 2nd parameter # should be robust. For our expected input it should be fine. Really # robust parsing would require tokeninzing the expression. pref_re = re.compile("(pref|user_pref|lock_pref)\s*\(\s*\"([^,\"]+)\s*\"\s*,\s*(.+?)\)\s*;\s*$", re.MULTILINE)
# ------ Excpetions ------
class FileNotFoundError(Exception): def __init__(self, filename): self.filename = filename def __str__(self): return _("File Not Found (%s)") % self.filename class BadIniFileError(Exception): def __init__(self, problem): self.problem = problem def __str__(self): return self.problem
# ------ Class FirefoxProfileFile ------
class FirefoxProfileFile: (TYPE_UNKNOWN, TYPE_PROFILE_INI, TYPE_PREFS, TYPE_BOOKMARK ) = range(4)
def __init__(self, home_dir, rel_path): self.home_dir = home_dir self.rel_path = rel_path self.attrs = {} self.file_type = get_type_from_path(rel_path)
def get_full_path(self): return os.path.join(self.home_dir, self.rel_path)
def get_rel_path(self): return self.rel_path
def type_to_string(self, type): if type == FirefoxProfileFile.TYPE_UNKNOWN: return "UNKNOWN" if type == FirefoxProfileFile.TYPE_PROFILE_INI: return "PROFILE_INI" if type == FirefoxProfileFile.TYPE_PREFS: return "PREFS" if type == FirefoxProfileFile.TYPE_BOOKMARK: return "BOOKMARK" return "?"
def get_type(self): return self.file_type
# ------ Class JavascriptPreference ------
class JavascriptPreference: def __init__(self, type, key, value): self.type = type self.key = key self.value = value
def __eq__(self, other): if self.type == other.type and \ self.key == other.key and \ self.value == other.value: return True else: return False
def get_type(self): return self.type
def get_key(self): return self.key
def get_value(self): return self.value
# ------ Class JavascriptPrefsFile ------
class JavascriptPrefsFile(FirefoxProfileFile): def __init__(self, home_dir, rel_path): dprint(LOG_OPERATION, "JavascriptPrefsFile: created (%s)", rel_path) FirefoxProfileFile.__init__(self, home_dir, rel_path) self.file_state = file_state.UNKNOWN self.prefs = {} self.prev_prefs = {}
def get_file_state(self): return self.file_state
def write(self, full_path=None): if not full_path: full_path = self.get_full_path() dir = os.path.dirname(full_path) if not os.path.exists(dir): os.makedirs(dir) dprint(LOG_OPERATION, "JavascriptPrefsFile: writing file (%s)", full_path) fd = open(full_path, "w") fd.write(''' # Mozilla User Preferences
/* * Do not edit this file. * Created by %s, version %s */ ''' % (config.PACKAGE, config.VERSION))
keys = self.prefs.keys() keys.sort() for key in keys: pref = self.prefs[key] fd.write("%s(\"%s\", %s);\n" % (pref.get_type(), pref.get_key(), pref.get_value()))
fd.close()
def merge(self, src, mandatory): for src_pref in src.prefs.values(): src_key = src_pref.get_key() if not self.prefs.has_key(src_key) or mandatory: # XXX - should this just be a copy? self.prefs[src_key] = JavascriptPreference(src_pref.get_type(), src_pref.get_key(), src_pref.get_value())
def read(self, full_path = None): self.prev_prefs = self.get_prefs()
if not full_path: full_path = self.get_full_path() dprint(LOG_OPERATION, "read profile prefs (%s)", self.get_full_path()) self.file_state = file_state.UNKNOWN try: fd = open(full_path) except IOError, e: if e.errno == errno.ENOENT: self.file_state = file_state.NOT_FOUND return else: self.file_state = file_state.SYS_ERROR raise
self.filebuf = fd.read() fd.close() self.file_state = file_state.VALID
self.kill_comments() self.parse()
def emit_changes(self, source, delegate): cur_prefs = self.get_prefs()
dc = util.DictCompare(self.prev_prefs, cur_prefs) dc.compare() cs = dc.get_change_set('a', 'b')
_add = cs['add'] _del = cs['del'] _mod = cs['mod']
def emit_changes(items, event): for key, pref in items: source.emit_change( MozillaChange(source, delegate, pref.get_type(), pref.get_key(), pref.get_value(), event))
emit_changes(_add.items(), MozillaChange.CREATED) emit_changes(_del.items(), MozillaChange.DELETED) emit_changes(_mod.items(), MozillaChange.CHANGED)
def kill_comments(self): def not_in_string (regexp): double = '\\"(?:\\\\.|[^\"\\\\])*\\"' single = "\\'(?:\\\\.|[^\"\\\\])*\\'" return "(" + double + "|" + single + ")(?:" + regexp + ")" def match (matchobj): return matchobj.group(1) slash_comment_re = re.compile(not_in_string ("//.*$"), re.MULTILINE) hash_comment_re = re.compile(not_in_string ("#.*$"), re.MULTILINE) c_comment_re = re.compile(not_in_string ("/\*.*?\*/"), re.MULTILINE | re.DOTALL)
self.filebuf = slash_comment_re.sub(match, self.filebuf) self.filebuf = hash_comment_re.sub(match, self.filebuf) self.filebuf = c_comment_re.sub(match, self.filebuf)
def parse(self): start = 0; self.prefs = {}
while 1: match = pref_re.search(self.filebuf, start) if match: type = match.group(1) key = match.group(2) value = match.group(3) dprint(LOG_PARSE, "(%d:%d) key='%s' value='%s'" % (match.start(), match.end(), key, value)) self.prefs[key] = JavascriptPreference(type, key, value) start = match.end() else: break
def set_prefs(self, prefs): self.prefs = prefs.copy()
def get_prefs(self): return self.prefs.copy()
def dump_prefs(self): keys = self.prefs.keys() keys.sort() for key in keys: dprint(LOG_, "%s=%s" % (key, self.prefs[key]))
# ------ Class FirefoxProfile ------
class FirefoxProfile: def __init__(self, section, home_dir, rel_dir): self.section = section self.home_dir = home_dir self.rel_dir = rel_dir self.attrs = {} self.files = {}
def set_attr(self, attr, value): self.attrs[attr] = value
def get_attr(self, attr): return self.attrs[attr]
def get_name(self): return self.get_attr("name")
def get_default(self): return self.get_attr("default")
def get_rel_dir(self): return os.path.join(self.rel_dir, self.get_dir())
def get_dir(self): return self.get_attr("path")
def add_file(self, rel_path): object = self.files.get(rel_path, None) if object: return(object)
file_type = get_type_from_path(rel_path)
if file_type == FirefoxProfileFile.TYPE_PREFS: object = JavascriptPrefsFile(self.home_dir, rel_path) elif file_type == FirefoxProfileFile.TYPE_BOOKMARK: object = BookmarksFile(self.home_dir, rel_path) else: object = FirefoxProfileFile(self.home_dir, rel_path) self.files[rel_path] = object return object
def del_file(self, rel_path): if rel_path in self.files: del self.files[rel_path]
def get_files_of_type(self, type): return [ file for file in self.files.values() if file.get_type() == type ]
# ------ Class FirefoxProfilesIni ------
class FirefoxProfilesIni: def __init__(self, home_dir, rel_path): self.file_state = file_state.UNKNOWN self.default_profile = None self.profiles = {} self.ini = ConfigParser.ConfigParser() self.home_dir = home_dir self.rel_path = rel_path self.rel_dir = os.path.dirname(rel_path)
def is_valid(self): return self.file_state == file_state.VALID
def get_full_path(self, path): return os.path.join(self.home_dir, path)
def get_rel_dir(self): return self.rel_dir
def get_rel_path(self): return self.rel_path
def get_file_state(self): return self.file_state
def load_profiles(self): dprint(LOG_OPERATION, "FirefoxProfilesIni.load_profiles()") for profile in self.get_profiles(): profile_rel_dir = profile.get_rel_dir()
pref_rel_path = os.path.join(profile_rel_dir, "prefs.js") dprint(LOG_OPERATION, "FirefoxProfilesIni.load_profiles() pref=%s", pref_rel_path) profile_file = profile.add_file(pref_rel_path) profile_file.read()
bookmark_rel_path = os.path.join(profile_rel_dir, "bookmarks.html") dprint(LOG_OPERATION, "FirefoxProfilesIni.load_profiles() bookmark=%s", bookmark_rel_path) profile_file = profile.add_file(bookmark_rel_path) profile_file.read()
def read(self): dprint(LOG_OPERATION, "FirefoxProfilesIni.read() path = %s", self.get_full_path(self.rel_path)) self.profiles = {}
try: if self.ini.read(self.get_full_path(self.rel_path)): self.file_state = file_state.VALID else: self.file_state = file_state.NOT_FOUND except ConfigParser.ParsingError, e: self.file_state = file_state.PARSE_ERROR
dprint(LOG_PARSE, "FirefoxProfilesIni: after read, state = %s", self.file_state) if self.file_state != file_state.VALID: self.default_profile = None
self.parse_sections()
def parse_sections(self): profile_re = re.compile("^Profile(\d+)$")
self.default_profile = None self.profiles = {} last_profile = None for section in self.ini.sections(): dprint(LOG_PARSE, "parse_sections() section=%s", section) match = profile_re.match(section) if match: try: default_profile = self.ini.get(section, "default") except ConfigParser.NoOptionError: default_profile = None name = self.ini.get(section, "Name") if name in self.profiles: raise BadIniFileError(_("duplicate name(%(name)s) in section %(section)s") % (name, section)) profile = FirefoxProfile(section, self.home_dir, self.rel_dir) self.profiles[name] = profile for (key, value) in self.ini.items(section): profile.set_attr(key, value) if default_profile: if self.default_profile: raise BadIniFileError(_("redundant default in section %s") % section) self.default_profile = profile
last_profile = profile
if self.default_profile == None and len(self.profiles) == 1: # If there's only one profile, its the default even if it # doesn't have the Default=1 flag # Note: by default Firefox's auto-generated profile doesn't # have the Default= flag) self.default_profile = last_profile dprint(LOG_OPERATION, "defaulting profile to the only choice") def get_default_profile(self): if not self.default_profile: raise BadIniFileError(_("no default profile")) return self.default_profile
def get_profiles(self, as_rel_dir=False): if as_rel_dir: return [ profile.get_rel_dir() for profile in self.profiles.values() ] else: return self.profiles.values()
# ------ Class BookmarkChange ------
class BookmarkChange(userprofile.ProfileChange): ( CREATED, DELETED, CHANGED ) = range(3) def __init__ (self, source, delegate, entry, event): userprofile.ProfileChange.__init__ (self, source, delegate) assert event == self.CREATED or \ event == self.DELETED or \ event == self.CHANGED self.entry = entry self.event = event self.attrs = {}
def set_attr(self, attr, value): self.attrs[attr] = value
def get_attr(self, attr): return self.attrs[attr]
def get_bookmark_path(self): return self.entry.path_as_string()
def get_entry(self): return self.entry
def get_url(self): return self.entry.get_url()
def get_id(self): return self.get_bookmark_path()
def get_short_description(self): url = self.get_url() bookmark_path = self.get_bookmark_path() if self.event == self.CREATED: # XXX - don't test for url, use type if url: return _("Mozilla bookmark created '%s' -> '%s'") % (bookmark_path, url) else: return _("Mozilla bookmark folder created '%s'") % (bookmark_path) elif self.event == self.DELETED: if url: return _("Mozilla bookmark deleted '%s'") % (bookmark_path) else: return _("Mozilla bookmark folder deleted '%s'") % (bookmark_path) elif self.event == self.CHANGED: if url: return _("Mozilla bookmark changed '%s' '%s'") % (bookmark_path, url) else: return _("Mozilla bookmark folder changed '%s'") % (bookmark_path) else: raise ValueError
gobject.type_register(BookmarkChange)
# ------ Class BookmarksFile ------
class BookmarksFile(FirefoxProfileFile): def __init__(self, home_dir, rel_path): dprint(LOG_OPERATION, "BookmarksFile: created (%s)", rel_path) FirefoxProfileFile.__init__(self, home_dir, rel_path) self.parser = mozilla_bookmarks.BookmarkHTMLParser() self.root = mozilla_bookmarks.BookmarkFolder("Null", None) self.parser.set_root(self.root) self.prev_root = self.parser.get_root() self.file_state = file_state.UNKNOWN
def get_full_path(self): return os.path.join(self.home_dir, self.rel_path)
def get_rel_path(self): return self.rel_path
def get_root(self): return self.root
def set_root(self, root): self.root = root self.parser.set_root(self.root)
def read(self): self.prev_root = self.parser.get_root() self.root = mozilla_bookmarks.BookmarkFolder("Null", None) self.parser.set_root(self.root) self.file_state = file_state.UNKNOWN full_path = self.get_full_path() dprint(LOG_OPERATION, "BookmarksFile: read (%s)", full_path) try: fd = open(full_path) except IOError, e: if e.errno == errno.ENOENT: self.file_state = file_state.NOT_FOUND return else: self.file_state = file_state.SYS_ERROR raise
self.file_state = file_state.VALID self.parser.feed(fd.read()) self.parser.close() self.root = self.parser.get_root() def write(self, full_path=None, exclude_attrs=None): if not full_path: full_path = self.get_full_path() dir = os.path.dirname(full_path) if not os.path.exists(dir): os.makedirs(dir) dprint(LOG_OPERATION, "MozillaBookmark: writing file (%s)", full_path) fd = open(full_path, "w") fd.write(''' <!DOCTYPE NETSCAPE-Bookmark-file-1> <!-- This is an automatically generated file. (Created by %s, version %s) It will be read and overwritten. DO NOT EDIT! --> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> <TITLE>Bookmarks</TITLE> <H1 LAST_MODIFIED="%.0f">Bookmarks</H1>
<DL><p> ''' % (config.PACKAGE, config.VERSION, time.time()))
def visit(entry, type, path, data): indent = " " level = len(path)
if type == mozilla_bookmarks.TYPE_FOLDER: fd.write("%s<DT><H3" % (indent*level)) for attr, value in entry.attrs.items(): if not filter_attr(attr, exclude_attrs): fd.write(" %s=\"%s\"" % (attr, value)) fd.write(">%s</H3>\n" % (entry.name)) fd.write("%s<DL><p>\n" % (indent*level)) elif type == mozilla_bookmarks.TYPE_BOOKMARK: fd.write("%s<DT><A" % (indent*level)) for attr, value in entry.attrs.items(): if not filter_attr(attr, exclude_attrs): fd.write(" %s=\"%s\"" % (attr, value)) fd.write(">%s</A>\n" % (entry.name)) elif type == mozilla_bookmarks.TYPE_FOLDER_END: fd.write("%s</DL><p>\n" % (indent*level)) else: raise ValueError
self.root.traverse(visit) fd.close() def convert_to_dict(self, root): result = {}
def visit(entry, type, path, data): bookmark_path = entry.path_as_string() result[bookmark_path] = entry
root.traverse(visit) return result def emit_changes(self, source, delegate): prev_dict = self.convert_to_dict(self.prev_root) cur_dict = self.convert_to_dict(self.root)
dc = util.DictCompare(prev_dict, cur_dict) dc.compare() cs = dc.get_change_set('a', 'b')
_add = cs['add'] _del = cs['del'] _mod = cs['mod']
def emit_changes(items, event): for bookmark_path, entry in items: source.emit_change( BookmarkChange(source, delegate, entry, event))
emit_changes(_add.items(), BookmarkChange.CREATED) emit_changes(_del.items(), BookmarkChange.DELETED) emit_changes(_mod.items(), BookmarkChange.CHANGED)
def merge(self, src, mandatory): def visit(entry, type, path, data): if type == mozilla_bookmarks.TYPE_FOLDER_END: return dst_entry = self.root.lookup_path(path) if not dst_entry or mandatory: self.root.add_path_entry(path, entry)
src.root.traverse(visit)
# ------ Utility Functions ------
def get_type_from_path(rel_path): basename = os.path.basename(rel_path) if basename == "prefs.js": return FirefoxProfileFile.TYPE_PREFS elif basename == "bookmarks.html": return FirefoxProfileFile.TYPE_BOOKMARK elif basename == "profiles.ini": return FirefoxProfileFile.TYPE_PROFILE_INI else: return FirefoxProfileFile.TYPE_UNKNOWN
def cat_file(path): if os.path.isfile(path): dprint(LOG_FILE_CONTENTS, "==== %s ====" % path) for line in open(path): dprint(LOG_FILE_CONTENTS, line.rstrip()) else: dprint(LOG_FILE_CONTENTS, "WARNING, does not exist ==== %s ====" % path)
#-----------------------------------------------------------------------------
# # Unit tests # def run_unit_tests(): test_prefs = {'foo':'"bar"', 'uno':'1'}
dprint(LOG_OPERATION, "In mozillaprofile tests")
|