1 """Objects to represent bookmarks.html structure
3 This file is a part of Bookmarks database and Internet robot.
7 __author__ = "Oleg Broytman <phd@phdru.name>"
8 __copyright__ = "Copyright (C) 2000-2023 PhiloSoft Design"
9 __license__ = "GNU GPL"
11 __all__ = ['Folder', 'Bookmark', 'Ruler', 'Walker', 'Writer', 'Robot',
12 'InverseLinker', 'Linear', 'make_linear', 'make_tree', 'break_tree',
13 'quote_title', 'unquote_title', 'parse_params', 'set_params',
19 BKMK_FORMAT = os.environ.get("BKMK_FORMAT", "MOZILLA")
26 def __init__(self, add_date=None, comment='', last_modified=None):
27 super(Folder, self).__init__()
28 self.comment = comment
29 self.add_date = add_date
30 self.last_modified = last_modified
32 def walk_depth(self, walker, level=0):
33 if hasattr(self, "header"): # root folder
35 walker.root_folder(self)
37 prune = walker.prune_folder(self)
39 walker.start_folder(self, level)
44 object.walk_depth(walker, level+1)
45 elif object.isBookmark:
46 walker.bookmark(object, level)
48 walker.ruler(object, level)
50 walker.end_folder(self, level)
53 class Bookmark(object):
57 def __init__(self, href, add_date, last_visit=None, last_modified=None,
58 keyword=None, comment='', icon_href=None, icon=None,
59 charset=None, parser_charset=None):
60 protocol, request = urllib.splittype(href)
61 user, password, port = None, None, None
62 host, path = urllib.splithost(request)
64 user, host = urllib.splituser(host)
66 user, password = urllib.splitpasswd(user)
67 host, port = urllib.splitport(host)
68 if port: port = int(port)
70 if protocol == 'place':
73 href = protocol + "://"
75 href += urllib.quote(user)
77 href += ':' + urllib.quote(password)
80 href += host.decode(parser_charset or 'utf-8').encode('idna')
87 self.add_date = add_date
88 self.last_visit = last_visit
89 self.last_modified = last_modified
90 self.keyword = keyword
91 self.comment = comment
92 self.icon_href = icon_href
94 self.charset = charset
102 class Walker(object):
104 Interface class. Any instance that will be passed to Folder.walk_depth
105 may be derived from this class. It is not mandatory - unlike Java
106 Python does not require interface classes; but it is convenient to have
107 some methods predefined to no-op, in case you do not want to
108 provide end_folder etc.
111 def root_folder(self, r):
114 def start_folder(self, f, level):
117 def end_folder(self, f, level):
120 def bookmark(self, b, level):
123 def ruler(self, r, level):
126 def prune_folder(self, folder):
130 class Writer(Walker):
131 def __init__(self, outfile, prune=None):
132 self.outfile = outfile
135 def prune_folder(self, folder):
136 return self.prune == folder.name
140 def __init__(self, log):
144 pass # Nothing to do on cleanup
147 # Helper class to make inverese links (nodes linked to their parent)
148 class InverseLinker(Walker):
149 def root_folder(self, r):
150 self.parent_stack = [r]
152 def start_folder(self, f, level):
153 f.parent = self.parent_stack[-1]
154 self.parent_stack.append(f) # Push the folder onto the stack of parents
156 def end_folder(self, f, level):
157 del self.parent_stack[-1] # Pop off the stack
159 def bookmark(self, b, level):
160 b.parent = self.parent_stack[-1]
162 def ruler(self, r, level):
163 r.parent = self.parent_stack[-1]
166 # Helper class to make linear represenatation of the tree
167 class Linear(Walker):
168 def root_folder(self, r):
170 self.linear = r.linear
172 def add_object(self, object):
173 self.linear.append(object)
175 def start_folder(self, f, level):
178 def bookmark(self, b, level):
181 def ruler(self, r, level):
185 # Helper - make linked linear represenatation of the tree, suitable to be stored in sequential storage
186 def make_linear(root_folder):
187 linker = InverseLinker()
188 root_folder.walk_depth(linker)
191 root_folder.walk_depth(linear)
194 # Helper, opposite of make_linear - make a tree from the linked linear representation
195 def make_tree(linear):
196 root_folder = linear[0]
199 for object in linear:
200 object.parent.append(object)
205 def break_tree(linear):
208 for object in linear:
212 def quote_title(title):
213 if BKMK_FORMAT == "MOZILLA":
214 title = title.replace("'", "'")
218 def unquote_title(title):
219 if BKMK_FORMAT == "MOZILLA":
220 from HTMLParser import HTMLParser
221 title = HTMLParser().unescape(title.replace("&", '&').decode('utf-8'))
222 title = title.encode('utf-8').replace("'", "'")
226 def parse_params(param_str):
227 params = param_str.split(':')
228 main_param = params.pop(0)
231 key, value = param.split('=', 1)
232 param_list[key] = value
233 return main_param, param_list
236 def set_params(obj, params):
237 if hasattr(params, "items"):
238 params = params.items()
239 for key, value in params:
240 setattr(obj, key, value)