""" A python extension that adds a Digest property page. For each file, MD5 and SHA digests are computed and displayed. Computes digest in background, and is GnomeVFS enabled. Copyright (C) 2005 Gustavo Carneiro Based on the md5 property page example in nautilus-python, by Johan Dahlin. Prerequisites: - nautilus-python >= 0.4.1 Installation: - Copy the file to ~/.nautilus/python-extensions/ - Restart nautilus (logout/login, or killall nautilus) """ __revision__ = 0, 1 import md5 import sha import gtk import nautilus import gnomevfs import gobject class Digest(object): def __init__(self, uri, md5_hex_label, md5_status_label, sha_hex_label, sha_status_label): self.size = None self.bytes_read = 0 self.block_size = None self.md5_hex_label = md5_hex_label self.sha_hex_label = sha_hex_label self.md5_status_label = md5_status_label self.sha_status_label = sha_status_label self.md5 = md5.new() self.sha = sha.new() self.uri = uri self.aborted = False self.current_status = '' self.handle = None self._abort_exception = None self.__update_timeout = None gnomevfs.async.get_file_info(uri, self.__info_cb) def set_status(self, status): self.current_status = status self.__update_labels() def __update_labels_cb(self): def update_label(digest, hex_label, status_label): if self.size is None: progress = "??" else: progress = "%2.0f" % (float(self.bytes_read)/self.size*100) hex_label.set_markup("%s" % digest) status_label.set_markup(" (%s%%, %s)" % (progress, gobject.markup_escape_text(self.current_status))) update_label(self.md5.hexdigest(), self.md5_hex_label, self.md5_status_label) update_label(self.sha.hexdigest(), self.sha_hex_label, self.sha_status_label) self.__update_timeout = None return False def __update_labels(self): if self.__update_timeout is not None: return self.__update_labels_cb() self.__update_timeout = gobject.timeout_add(500, self.__update_labels_cb) def abort(self, exception): print "aborting..." self.aborted = True self._abort_exception = exception if exception is None: self.set_status("Aborted") else: self.set_status("Error") if self.handle is not None: self.handle.cancel() self.handle = None def __close_cb(self, handle, exception): self.set_status("finished") def __read_cb(self, handle, buffer, exception, bytes_requested): if self.aborted: return self.md5.update(buffer) self.sha.update(buffer) self.bytes_read += len(buffer) self.__update_labels() if exception is None: handle.read(self.block_size, self.__read_cb) else: if issubclass(exception, gnomevfs.EOFError): handle.close(self.__close_cb) def __open_cb(self, handle, exception): if self.aborted: return if exception is not None: self.abort(exception) return self.handle = handle handle.read(self.block_size, self.__read_cb) self.set_status("Reading...") def __info_cb(self, handle, results): if self.aborted: return assert len(results) == 1 uri, exception, info = results[0] if exception is None: try: self.size = info.size except ValueError: pass if self.size is None: self.block_size = 16384 else: self.block_size = max(1024, min(16384, self.size // 20)) gnomevfs.async.open(self.uri, self.__open_cb) class MD5SumPropertyPage(nautilus.PropertyPageProvider): def __init__(self): pass def get_property_pages(self, files): #sw = gtk.ScrolledWindow() #sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) vbox = gtk.VBox() vbox.set_border_width(12) #sw.show() vbox.show() #sw.add_with_viewport(vbox) for nfile in files: vbox.pack_start(gobject.new(gtk.Label, label=('%s:' % \ gobject.markup_escape_text(nfile.get_uri())), use_markup=True, visible=True, xalign=0), expand=False, fill=True, padding=12) property_label = gobject.new(gtk.Label, label='Digest', xalign=0, visible=True) def create_digest_widgets(title): hbox = gtk.HBox(0, False) hbox.show() vbox.pack_start(hbox, expand=False, fill=False, padding=2) hbox.pack_start(gobject.new(gtk.Label, label=' ', visible=True), expand=False, fill=False) label = gobject.new(gtk.Label, label=title, xalign=0, visible=True) hbox.pack_start(label, expand=False, fill=True) hex_label = gobject.new(gtk.Label, xalign=0, selectable=True, visible=True) hbox.pack_start(hex_label, expand=False, fill=True) status_label = gobject.new(gtk.Label, xalign=0, selectable=False, visible=True) hbox.pack_start(status_label, expand=False, fill=True) return hex_label, status_label md5_hex_label, md5_status_label = create_digest_widgets('MD5: ') sha_hex_label, sha_status_label = create_digest_widgets('SHA: ') digest = Digest(nfile.get_uri(), md5_hex_label, md5_status_label, sha_hex_label, sha_status_label) vbox.connect("notify::parent", self.__parent_notify_cb, digest, property_label) return nautilus.PropertyPage("NautilusPython::digest", property_label, vbox), def __parent_notify_cb(self, vbox, paramspec, digest, property_label): if vbox.parent is None: digest.abort("Cancelled") vbox.destroy() property_label.destroy()