]> git.phdru.name Git - bookmarks_db.git/blob - chk_urls.py
This commit was manufactured by cvs2svn to create tag 'version2'.
[bookmarks_db.git] / chk_urls.py
1 #! /usr/local/bin/python -O
2 """
3    For every URL in the FLAD database get info from the Net
4    and store info in check.db
5
6    Written by BroytMann, Aug-Oct 1997. Copyright (C) 1997 PhiloSoft Design
7 """
8
9 import sys, os, string, stat, shutil, time
10 from getopt import getopt
11 import tempfile
12
13 import urllib
14 from urllib import URLopener, splittype
15
16 from md5wrapper import md5wrapper
17 from flog import makelog, openlog
18 import fladm, fladc, www_util
19
20
21 # Shortcut for basic usage
22 _urlopener = None
23
24 def urlopen(url):
25    global _urlopener
26    if not _urlopener:
27       _urlopener = URLopener()
28    return _urlopener.open(url)
29
30 def urlretrieve(url, filename=None):
31    global _urlopener
32    if not _urlopener:
33       _urlopener = URLopener()
34    if filename:
35        return _urlopener.retrieve(url, filename)
36    else:
37        return _urlopener.retrieve(url)
38
39 def urlcleanup():
40    if _urlopener:
41       _urlopener.cleanup()
42
43
44 _key = None
45
46 def myftpwrapper(user, passwd, host, port, dirs):
47    global _key
48    _key = (user, host, port, string.joinfields(dirs, '/'))
49    return _ftpwrapper(user, passwd, host, port, dirs)
50
51 _ftpwrapper = urllib.ftpwrapper
52 urllib.ftpwrapper = myftpwrapper
53
54 def get_welcome():
55    global _key
56    _welcome = _urlopener.ftpcache[_key].ftp.welcome
57    _key = None # I am assuming there are no duplicate ftp URLs in db. If there are - _key in prev line is invalid
58    return _welcome
59
60
61 def set_checkpoint(rec_no):
62    cpfile = open("check.dat", 'w')
63    cpfile.write("# chk_urls checkpoint file\n")
64    cpfile.write("Size: %d\n" % db_stat[stat.ST_SIZE])
65    cpfile.write("MTime: %d\n" % db_stat[stat.ST_MTIME])
66    cpfile.write("Record: %d" % rec_no)
67    cpfile.close()
68
69 def get_checkpoint():
70    try:
71       cpfile = fladc.load_file("check.dat")
72       if (string.atoi(cpfile["Size"]) <> db_stat[stat.ST_SIZE]) or \
73          (string.atoi(cpfile["MTime"]) <> db_stat[stat.ST_MTIME]):
74          return -3
75
76       return string.atoi(cpfile["Record"])
77
78    except IOError: # No such file
79       return -1
80
81    except KeyError: # No such key in checkpoint file
82       return -2
83
84    except string.atoi_error: # Wrong numeric format
85       return -2
86
87    return 0
88
89
90 tempfname = tempfile.gettempprefix() + "check.tmp"
91
92
93 def get_error(msg):
94    if type(msg) == type(""):
95       return msg
96
97    else:
98       s = ""
99       for i in msg:
100          if s <> "":
101             s = s + ", "
102          x = string.join(string.split(str(i), "\n"), "\\n")
103          s = s + "'%s'" % x
104       return "(" + s + ")"
105
106 def check_url(record, url_type, url_rest):
107
108    now = str(int(time.time()))
109
110    try:
111       fname, headers = urlretrieve(url_type + ':' + url_rest, tempfname)
112
113       last_modified = None
114
115       record["Size"] = str(os.stat(tempfname)[stat.ST_SIZE])
116
117       if headers:
118          try:
119             last_modified = headers["Last-Modified"]
120          except KeyError:
121             last_modified = None
122
123          if last_modified:
124             last_modified = www_util.parse_time(last_modified)
125
126       if last_modified:
127          last_modified = str(int(last_modified))
128       else:
129          last_modified = record["LastVisit"]
130
131       record["LastModified"] = last_modified
132
133       md5 = md5wrapper()
134       if url_type == "ftp": # Pass welcome message through MD5
135          md5.update(get_welcome())
136
137       md5.md5file(tempfname)
138       record["MD5"] = str(md5)
139
140    except IOError, msg:
141       record["Error"] = get_error(msg)
142
143    except EOFError:
144       record["Error"] = "Unexpected EOF (FTP server closed connection)"
145
146    except KeyboardInterrupt:
147       return 0
148
149    # Mark this even in case of error
150    record["LastTested"] = now
151
152    return 1
153
154
155 def run():
156    optlist, args = getopt(sys.argv[1:], "is")
157
158    show_pbar = 1
159    report_stats = 1
160    db_name = "bookmarks.db"
161
162    for _opt, _arg in optlist:
163       if _opt == '-i':
164          show_pbar = 0
165       if _opt == '-s':
166          report_stats = 0
167    try:
168       del _opt, _arg
169    except NameError:
170       pass
171
172    if report_stats:
173       print "BroytMann chk_urls, Copyright (C) 1997-1998 PhiloSoft Design"
174
175    if args:
176       sys.stderr.write("chk_urls: too many arguments\n")
177       sys.exit(1)
178
179    if show_pbar:
180       show_pbar = sys.stderr.isatty()
181
182    if show_pbar:
183       try:
184          from tty_pbar import ttyProgressBar
185       except ImportError:
186          show_pbar = 0
187
188    global db_stat, log
189    db_stat = os.stat("bookmarks.db")
190
191    start_recno = get_checkpoint()
192    if start_recno < 0:
193       if start_recno == -1:
194          log = makelog("check.log")
195          log("chk_urls started")
196          if report_stats:
197             print "   chk_urls: normal start"
198
199       elif start_recno == -2:
200          log = openlog("check.log")
201          log("chk_urls started")
202          log("   invalid checkpoint file, checkpoint ignored")
203          if report_stats:
204             print "   chk_urls: invalid checkpoint file, checkpoint ignored"
205
206       elif start_recno == -3:
207          log = makelog("check.log")
208          log("chk_urls started")
209          log("   bookmarks.db changed, checkpoint ignored")
210          if report_stats:
211             print "   chk_urls: bookmarks.db changed, checkpoint ignored"
212
213       else:
214          raise RuntimeError, "wrong get_checkpoint() return: `%s'" % str(start_recno)
215
216       start_recno = 0
217
218    elif start_recno == 0:
219       raise RuntimeError, "wrong get_checkpoint() return: `%s'" % str(start_recno)
220
221    else: # start_recno > 0
222       if os.path.exists("check.db"):
223          if not os.path.exists("check.old"):
224             shutil.copy("check.db", "check.old")
225          db_name = "check.db"
226
227          log = openlog("check.log")
228          log("chk_urls started")
229          log("   found valid checkpoint file, continue")
230          if report_stats:
231             print "   chk_urls: found valid checkpoint file, continue"
232
233       else:
234          log = makelog("check.log")
235          log("chk_urls started")
236          log("   valid checkpoint, but no check.db file, restarting")
237          if report_stats:
238             print "   chk_urls: valid checkpoint, but no check.db file, restarting"
239          start_recno = 0
240
241    if report_stats:
242       sys.stdout.write("Loading %s: " % db_name)
243       sys.stdout.flush()
244
245    bookmarks_db = fladm.load_from_file(db_name, fladm.check_record, ["Level"])
246    db_len = len(bookmarks_db)
247
248    if report_stats:
249       print "Ok"
250
251    if start_recno >= db_len:
252       _s = "start_recno (%d) >= db_len (%d), restarting" % (start_recno, db_len)
253       log("   " + _s)
254       if report_stats:
255          print "   chk_urls: " + _s
256       del _s
257       start_recno = 0
258
259    if report_stats:
260       sys.stdout.write("Checking: ")
261       sys.stdout.flush()
262
263    if show_pbar:
264       pbar = ttyProgressBar(0, db_len)
265
266    urls_no = 0
267    record_count = 0
268    start_time = time.time()
269
270    rcode = 1
271    for record_no in range(start_recno, db_len):
272       if show_pbar:
273          pbar.display(record_no+1)
274
275       record = bookmarks_db[record_no]
276       record_count = record_count + 1
277
278       if record.has_key("URL"):
279          url_type, url_rest = splittype(record["URL"])
280          log("Checking %s:%s" % (url_type, url_rest))
281          rcode = check_url(record, url_type, url_rest)
282          if rcode:
283             current_time = time.time()
284             if current_time - start_time >= 300: # Save checkpoint and database every 5 min
285                bookmarks_db.store_to_file("check.db")
286                set_checkpoint(record_no)
287                log.flush()
288                start_time = current_time
289             urls_no = urls_no + 1
290          else:
291             log("Interrupted by user (^C)")
292             break
293
294    if show_pbar:
295       del pbar
296
297    if report_stats:
298       print "Ok"
299       print record_count, "records checked"
300       print urls_no, "URLs checked"
301
302    bookmarks_db.store_to_file("check.db")
303
304    if rcode:
305       log("chk_urls finished ok")
306    log.close()
307
308    urlcleanup()
309    if os.path.exists(tempfname):
310       os.unlink(tempfname)
311
312    if rcode:
313       if os.path.exists("check.dat"):
314          os.unlink("check.dat")
315    else:
316       set_checkpoint(record_no)
317       sys.exit(1)
318
319
320 if __name__ == '__main__':
321    run()