1 """Objects to represent bookmarks.html structure
3 This file is a part of Bookmarks database and Internet robot.
6 __author__ = "Oleg Broytman <phd@phdru.name>"
7 __copyright__ = "Copyright (C) 2000-2012 PhiloSoft Design"
8 __license__ = "GNU GPL"
10 __all__ = ['Folder', 'Bookmark', 'Ruler', 'Walker', 'Writer', 'Robot',
11 'InverseLinker', 'Linear', 'make_linear', 'make_tree', 'break_tree',
12 'quote_title', 'unquote_title',
18 BKMK_FORMAT = os.environ.get("BKMK_FORMAT", "MOZILLA")
24 def __init__(self, add_date=None, comment='', last_modified=None):
25 super(Folder, self).__init__()
26 self.comment = comment
27 self.add_date = add_date
28 self.last_modified = last_modified
30 def walk_depth(self, walker, level=0):
31 if hasattr(self, "header"): # root folder
33 walker.root_folder(self)
35 prune = walker.prune_folder(self)
37 walker.start_folder(self, level)
42 object.walk_depth(walker, level+1)
43 elif object.isBookmark:
44 walker.bookmark(object, level)
46 walker.ruler(object, level)
48 walker.end_folder(self, level)
55 def __init__(self, href, add_date, last_visit=None, last_modified=None,
56 keyword=None, comment='', icon_href=None, icon=None,
57 charset=None, parser_charset=None):
58 protocol, request = urllib.splittype(href)
59 user, password, port = None, None, None
60 host, path = urllib.splithost(request)
62 user, host = urllib.splituser(host)
64 user, password = urllib.splitpasswd(user)
65 host, port = urllib.splitport(host)
66 if port: port = int(port)
68 href = protocol + "://"
70 href += urllib.quote(user)
72 href += ':' + urllib.quote(password)
75 href += host.decode(parser_charset or 'utf-8').encode('idna')
82 self.add_date = add_date
83 self.last_visit = last_visit
84 self.last_modified = last_modified
85 self.keyword = keyword
86 self.comment = comment
87 self.icon_href = icon_href
89 self.charset = charset
99 Interface class. Any instance that will be passed to Folder.walk_depth
100 may be derived from this class. It is not mandatory - unlike Java
101 Python does not require interface classes; but it is convenient to have
102 some methods predefined to no-op, in case you do not want to
103 provide end_folder etc.
106 def root_folder(self, r):
109 def start_folder(self, f, level):
112 def end_folder(self, f, level):
115 def bookmark(self, b, level):
118 def ruler(self, r, level):
121 def prune_folder(self, folder):
125 class Writer(Walker):
126 def __init__(self, outfile, prune=None):
127 self.outfile = outfile
130 def prune_folder(self, folder):
131 return self.prune == folder.name
135 def __init__(self, log):
139 pass # Nothing to do on cleanup
142 # Helper class to make inverese links (nodes linked to their parent)
143 class InverseLinker(Walker):
144 def root_folder(self, r):
145 self.parent_stack = [r]
147 def start_folder(self, f, level):
148 f.parent = self.parent_stack[-1]
149 self.parent_stack.append(f) # Push the folder onto the stack of parents
151 def end_folder(self, f, level):
152 del self.parent_stack[-1] # Pop off the stack
154 def bookmark(self, b, level):
155 b.parent = self.parent_stack[-1]
157 def ruler(self, r, level):
158 r.parent = self.parent_stack[-1]
161 # Helper class to make linear represenatation of the tree
162 class Linear(Walker):
163 def root_folder(self, r):
165 self.linear = r.linear
167 def add_object(self, object):
168 self.linear.append(object)
170 def start_folder(self, f, level):
173 def bookmark(self, b, level):
176 def ruler(self, r, level):
180 # Helper - make linked linear represenatation of the tree, suitable to be stored in sequential storage
181 def make_linear(root_folder):
182 linker = InverseLinker()
183 root_folder.walk_depth(linker)
186 root_folder.walk_depth(linear)
189 # Helper, opposite of make_linear - make a tree from the linked linear representation
190 def make_tree(linear):
191 root_folder = linear[0]
194 for object in linear:
195 object.parent.append(object)
199 def break_tree(linear):
202 for object in linear:
206 def quote_title(title):
207 if BKMK_FORMAT == "MOZILLA":
208 title = title.replace("'", "'")
211 def unquote_title(title):
212 if BKMK_FORMAT == "MOZILLA":
213 from HTMLParser import HTMLParser
214 title = HTMLParser().unescape(title.replace("&", '&').decode('utf-8'))
215 title = title.encode('utf-8').replace("'", "'")