gget r24 - trunk/gget



Author: johans
Date: Wed Jul  9 10:06:16 2008
New Revision: 24
URL: http://svn.gnome.org/viewvc/gget?rev=24&view=rev

Log:
Remember downloads between sessions.

Added:
   trunk/gget/DownloadList.py
Modified:
   trunk/gget/AddDownloadDialog.py
   trunk/gget/Configuration.py
   trunk/gget/Download.py
   trunk/gget/DownloadManager.py
   trunk/gget/GUI.py
   trunk/gget/Main.py
   trunk/gget/MainWindow.py
   trunk/gget/Utils.py
   trunk/gget/metalink.py

Modified: trunk/gget/AddDownloadDialog.py
==============================================================================
--- trunk/gget/AddDownloadDialog.py	(original)
+++ trunk/gget/AddDownloadDialog.py	Wed Jul  9 10:06:16 2008
@@ -24,7 +24,7 @@
 
 import GUI
 from Configuration import Configuration
-from DownloadManager import DownloadManager
+from DownloadList import DownloadList
 from gget import NAME
 
 class AddDownloadDialog:
@@ -93,8 +93,8 @@
         self.add_button.clicked()
 
     def __add_button_clicked(self, button):
-        download_manager = DownloadManager()
-        download_manager.start_download(self.url_entry.get_text(),
+        download_list = DownloadList()
+        download_list.add_download(self.url_entry.get_text(),
                 self.download_filechooserbutton.get_current_folder())
         self.dialog.destroy()
 

Modified: trunk/gget/Configuration.py
==============================================================================
--- trunk/gget/Configuration.py	(original)
+++ trunk/gget/Configuration.py	Wed Jul  9 10:06:16 2008
@@ -133,9 +133,9 @@
         return Configuration.instance
 
     def __init(self, *args):
-        # self.base_dir = os.path.expanduser("~/.gnome2/gget")
-        # if not os.path.exists(self.base_dir):
-            # os.makedirs(self.base_dir)
+        self.base_dir = os.path.expanduser("~/.gnome2/gget")
+        if not os.path.exists(self.base_dir):
+            os.makedirs(self.base_dir)
 
         self.client = gconf.client_get_default()
         if self.client.dir_exists(DIR_GGET):

Modified: trunk/gget/Download.py
==============================================================================
--- trunk/gget/Download.py	(original)
+++ trunk/gget/Download.py	Wed Jul  9 10:06:16 2008
@@ -26,26 +26,34 @@
 
 import Utils
 import GUI
+import metalink
 from gget import NAME
 
-class Download(gobject.GObject):
-    __gproperties__ = {"url": (str, "Download URL", "URL to the file being \
-                               downloaded", "", gobject.PARAM_READWRITE),
-                       "path": (str, "Download path", "Path to the location \
-                                where to save the download", "",
-                                gobject.PARAM_READWRITE)}
+CONNECTING = 0
+DOWNLOADING = 1
+STOPPED = 2
+PAUSED = 3
+COMPLETED = 4
+ERROR = 5
 
+class Download(gobject.GObject):
     __gsignals__ = {"update":   (gobject.SIGNAL_RUN_LAST, None, (int, int,
                                  int)),
                     "speed-changed": (gobject.SIGNAL_RUN_LAST, None, (int,)),
                     "status-changed": (gobject.SIGNAL_RUN_LAST, None, (int,))}
 
-    def __init__(self, url, path):
+    def __init__(self, uri, path):
         gobject.GObject.__init__(self)
-        self.url = url
+        self.uri = uri
         self.path = path
 
-        self.file_name = os.path.basename(self.url)
+        if uri.endswith(".metalink") or metalink.urlhead(uri,
+                metalink=True)["content-type"].startswith(metalink.MIME_TYPE):
+            self.is_metalink = True
+        else:
+            self.is_metalink = False
+
+        self.file_name = os.path.basename(self.uri)
         self.file = os.path.join(path, self.file_name)
 
         self.total_size = 0
@@ -53,23 +61,15 @@
         self.block_size = 0
         self.percent_complete = 0
 
-    def __str__(self):
-        return self.url
+        self.status = -1
 
-    def do_get_property(self, property):
-        if property.name == "url":
-            return self.url
-        elif property.name == "path":
-            return self.path
-
-    def do_set_property(self, property, value):
-        if property.name == "url":
-            self.url = value
-        elif property.name == "path":
-            self.path = path
+    def __str__(self):
+        return self.uri
 
     def update(self, block_count, block_size, total_size):
-        Utils.debug_print("Download.update called with block_count: %s block_size: %s total_size: %s" % (block_count, block_size, total_size))
+        Utils.debug_print("Download.update called with block_count: %s \
+                block_size: %s total_size: %s" % (block_count, block_size,
+                    total_size))
         self.block_count = block_count
         self.block_size = block_size
         self.total_size = total_size
@@ -81,13 +81,43 @@
         except ZeroDivisionError:
             self.percent_complete = 0
 
+        if self.status != DOWNLOADING and self.percent_complete > 0:
+            self.set_status(DOWNLOADING)
+
         if self.percent_complete > 100:
             self.percent_complete = 100
 
+        if self.percent_complete == 100:
+            self.set_status(COMPLETED)
+
         Utils.debug_print("Percent complete: %s" % self.percent_complete)
 
         gtk.gdk.threads_enter()
-        self.emit("update", block_count, block_size, total_size)
+        self.emit("update", int(block_count), int(block_size), int(total_size))
         gtk.gdk.threads_leave()
 
+    def set_status(self, status):
+        self.status = status
+        Utils.debug_print("Download status for %s changed to: %s (%s)" % (self,
+            self.get_status_string(), status))
+        gtk.gdk.threads_enter()
+        self.emit("status-changed", status)
+        gtk.gdk.threads_leave()
+
+    def get_status_string(self, status=None):
+        if self.status == CONNECTING:
+            return _("Connecting")
+        elif self.status == DOWNLOADING:
+            return _("Downloading")
+        elif self.status == STOPPED:
+            return _("Stopped")
+        elif self.status == PAUSED:
+            return _("Paused")
+        elif self.status == COMPLETED:
+            return _("Completed")
+        elif self.status == ERROR:
+            return _("Error")
+        else:
+            return _("N/A")
+
 # vim: set sw=4 et sts=4 tw=79 fo+=l:

Added: trunk/gget/DownloadList.py
==============================================================================
--- (empty file)
+++ trunk/gget/DownloadList.py	Wed Jul  9 10:06:16 2008
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2008 Johan Svedberg <johan svedberg com>
+
+# This file is part of gget.
+
+# gget 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.
+
+# gget 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 gget; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+
+import os.path
+import sys
+from xml.etree import cElementTree as ET
+
+import gobject
+
+import Utils
+from Configuration import Configuration
+from Download import Download
+
+XML_HEADER = '<?xml version="1.0" encoding="UTF-8" ?>\n'
+DOWNLOADS_FILE = "downloads.xml"
+
+class DownloadList(gobject.GObject):
+    """Singleton holding the list of downloads"""
+
+    __gsignals__ = {"download-added": (gobject.SIGNAL_RUN_LAST, None,
+        (object,))}
+
+    instance = None
+
+    def __new__(type, *args):
+        if DownloadList.instance is None:
+            DownloadList.instance = gobject.GObject.__new__(type)
+            DownloadList.instance.__init(*args)
+        return DownloadList.instance
+
+    def __init(self, *args):
+        gobject.GObject.__init__(self)
+        self.config = Configuration()
+        self.downloads = []
+
+    def load_from_xml(self):
+        """Loads download objects from the xml file."""
+        self.download_file_path = os.path.join(self.config.base_dir,
+                DOWNLOADS_FILE)
+        if not os.path.exists(self.download_file_path):
+            self.__create_xml()
+        else:
+            self.tree = ET.parse(self.download_file_path)
+            downloads_element = self.tree.getroot()
+            for download_element in list(downloads_element):
+                uri = download_element.findtext("uri")
+                path = download_element.findtext("path")
+                status = download_element.findtext("status")
+                download = Download(uri, path)
+                download.status = status
+                self.__append_download(download)
+
+    def __create_xml(self):
+        file = open(self.download_file_path, "w")
+        file.write(XML_HEADER)
+        self.tree = ET.ElementTree(ET.fromstring("<downloads>\n</downloads>"))
+        self.tree.write(file)
+        file.close()
+
+    def add_download(self, uri, path=None):
+        if path is None:
+            path = self.config.default_folder
+
+        download = Download(uri, path)
+        self.__append_download(download)
+        self.__add_download_to_xml(download)
+
+    def __append_download(self, download):
+        download.connect("status-changed", self.__download_status_changed)
+        self.downloads.append(download)
+        Utils.debug_print("Appended download %s to list of downloads." %
+                download)
+        self.emit("download-added", (download))
+
+    def __add_download_to_xml(self, download):
+        """Adds the download to the xml tree and saves it to disk."""
+        downloads_element = self.tree.getroot()
+        download_element = ET.SubElement(downloads_element, "download")
+        uri_element = ET.SubElement(download_element, "uri")
+        uri_element.text = download.uri
+        path_element = ET.SubElement(download_element, "path")
+        path_element.text = download.path
+        # filename_element = ET.SubElement(download_element, "filename")
+        # filename_element.text = download.file_name
+        # size_element = ET.SubElement(download_element, "size")
+        # size_element.text = download.total_size
+        status_element = ET.SubElement(download_element, "status")
+        status_element.text = str(download.status)
+        self.__save_xml()
+
+    def __download_status_changed(self, download, status):
+        """Finds the download element which status changed and update
+        the xml tree."""
+        downloads_element = self.tree.getroot()
+        for download_element in list(downloads_element):
+            uri = download_element.findtext("uri")
+            path = download_element.findtext("path")
+            if download.uri == uri and download.path == path:
+                status_element = download_element.find("status")
+                status_element.text = str(status)
+                break
+        self.__save_xml()
+
+    def __save_xml(self):
+        """Adds a header and indents the xml tree before saving it to disk."""
+        file = open(self.download_file_path, "w")
+        file.write(XML_HEADER)
+        Utils.indent(self.tree.getroot())
+        self.tree.write(file)
+        file.close()
+
+# vim: set sw=4 et sts=4 tw=79 fo+=l:

Modified: trunk/gget/DownloadManager.py
==============================================================================
--- trunk/gget/DownloadManager.py	(original)
+++ trunk/gget/DownloadManager.py	Wed Jul  9 10:06:16 2008
@@ -28,16 +28,16 @@
 
 import metalink
 
-import Utils
+import Download
 import GUI
-from Download import Download
+import Utils
 from Configuration import Configuration
 from gget import NAME, VERSION
 
 class DownloadManager(gobject.GObject):
     """Singleton handling the downloads"""
 
-    __gsignals__ = {"download-added": (gobject.SIGNAL_RUN_LAST, None,
+    __gsignals__ = {"download-started": (gobject.SIGNAL_RUN_LAST, None,
         (object,))}
 
     instance = None
@@ -51,7 +51,6 @@
     def __init(self, *args):
         gobject.GObject.__init__(self)
         self.config = Configuration()
-        self.downloads = []
 
         metalink.USER_AGENT = "%s %s" % (NAME, VERSION)
 
@@ -73,26 +72,37 @@
             else:
                 metalink.HTTP_PROXY = "http://%s:%s"; % (self.config.proxy_host, self.config.proxy_port)
 
-    def start_download(self, uri, path=None):
-        if path is None:
-            path = self.config.default_folder
-        download = Download(uri, path)
+    def download_added(self, download_list, download):
+        self.start_download(download)
 
+    def start_download(self, download):
         Utils.debug_print("Starting download %s" % download)
-        self.downloads.append(download)
         result = thread.start_new_thread(self.__start_download_in_thread,
                 (download,))
-        self.emit("download-added", (download))
+        self.emit("download-started", (download))
         # self.__start_download_in_thread(download)
         if not result:
-            print "Failed downloading of file %s" % download.url
+            download.set_status(Download.ERROR)
+            print "Failed downloading of file %s" % download.uri
 
     def __start_download_in_thread(self, download):
         # Python 2.5 seems to have a bug: sys.excepthook is not call from code
         # in a thread, see http://spyced.blogspot.com/2007/06/workaround-for-sysexcepthook-bug.html
         # sys.excepthook(*sys.exc_info())
 
-        metalink.get(download.url, download.path, handler=download.update)
+        download.set_status(Download.CONNECTING)
+        metalink.get(download.uri, download.path, handler=download.update)
 
+    def set_proxy(self, protocol, proxy):
+        """Sets the proxy to use for the specified protocol."""
+        if protocol == "http":
+            metalink.HTTP_PROXY = proxy
+            Utils.debug_print("HTTP proxy: %s", metalink.HTTP_PROXY)
+        elif protocol == "https":
+            metalink.HTTPS_PROXY = proxy
+            Utils.debug_print("HTTPS proxy: %s", metalink.HTTPS_PROXY)
+        elif protocol == "ftp":
+            metalink.FTP_PROXY = proxy
+            Utils.debug_print("FTP proxy: %s", metalink.FTP_PROXY)
 
 # vim: set sw=4 et sts=4 tw=79 fo+=l:

Modified: trunk/gget/GUI.py
==============================================================================
--- trunk/gget/GUI.py	(original)
+++ trunk/gget/GUI.py	Wed Jul  9 10:06:16 2008
@@ -68,12 +68,18 @@
 def load_icon_from_mime_type(mime_type, size=48):
     """Loads an icon from a mime type string. This is ugly and error prone,
     there must be a better way to do this."""
+    pixbuf = None
     l = mime_type.split("/")
     mime = "%s-%s" % (l[0], l[1])
-    pixbuf = icon_theme.load_icon(mime, size, gtk.ICON_LOOKUP_USE_BUILTIN)
-    if not pixbuf:
-        mime = "gnome-mime-%s" % mime
+    try:
         pixbuf = icon_theme.load_icon(mime, size, gtk.ICON_LOOKUP_USE_BUILTIN)
+    except Exception, msg1:
+        try:
+            mime = "gnome-mime-%s" % mime
+            pixbuf = icon_theme.load_icon(mime, size,
+                    gtk.ICON_LOOKUP_USE_BUILTIN)
+        except Exception, msg2:
+            pass
     return pixbuf
 
 def queue_resize(treeview):

Modified: trunk/gget/Main.py
==============================================================================
--- trunk/gget/Main.py	(original)
+++ trunk/gget/Main.py	Wed Jul  9 10:06:16 2008
@@ -30,6 +30,8 @@
 import gnome
 
 import GUI
+from AddDownloadDialog import AddDownloadDialog
+from DownloadList import DownloadList
 from DownloadManager import DownloadManager
 from MainWindow import MainWindow
 from StatusIcon import StatusIcon
@@ -61,9 +63,11 @@
     gtk.window_set_default_icon_list(*GUI.get_icon_list([16, 22, 24, 32]))
 
     config = Configuration(debug)
+    download_list = DownloadList()
     download_manager = DownloadManager()
+    download_list.connect("download-added", download_manager.download_added)
 
-    main_window = MainWindow(config, download_manager)
+    main_window = MainWindow(config, download_list)
     if config.show_main_window:
         main_window.window.show()
 
@@ -73,8 +77,14 @@
 
     # sys.excepthook = main_window.on_unhandled_exception
 
+    download_list.load_from_xml()
+
     for uri in args:
-        download_manager.start_download(uri)
+        if config.ask_for_location:
+            add = AddDownloadDialog(uri)
+            add.dialog.show()
+        else:
+            download_list.add_download(uri, config.default_folder)
 
     gtk.main()
 

Modified: trunk/gget/MainWindow.py
==============================================================================
--- trunk/gget/MainWindow.py	(original)
+++ trunk/gget/MainWindow.py	Wed Jul  9 10:06:16 2008
@@ -42,10 +42,10 @@
 TARGET_NETSCAPE_URL = 1
 
 class MainWindow:
-    def __init__(self, config, download_manager):
+    def __init__(self, config, download_list):
         self.config = config
-        self.download_manager = download_manager
-        self.download_manager.connect("download-added", self.__download_added)
+        self.download_list = download_list
+        self.download_list.connect("download-added", self.__download_added)
 
         self.__get_widgets()
 
@@ -228,8 +228,8 @@
         """Data function for the image of the download."""
         download = model.get_value(iter, 0)
         mime_type = gnomevfs.get_file_mime_type(download.file_name)
-        cell.props.pixbuf = GUI.load_icon_from_mime_type(mime_type,
-                32)
+        pixbuf = GUI.load_icon_from_mime_type(mime_type, 32)
+        cell.props.pixbuf = pixbuf
 
     def __name_cell_data_func(self, column, cell, model, iter):
         """Data function for the name of downloads."""
@@ -239,12 +239,12 @@
     def __status_cell_data_func(self, column, cell, model, iter):
         """Data function for the status of downloads."""
         download = model.get_value(iter, 0)
-        cell.props.text = "N/A"
+        cell.props.text = download.get_status_string()
 
     def __size_cell_data_func(self, column, cell, model, iter):
         """Data function for the file size of downloads."""
         download = model.get_value(iter, 0)
-        cell.props.text = Utils.get_readable_size(float(download.block_count * download.block_size))
+        cell.props.text = Utils.get_readable_size(download.block_count * download.block_size)
 
     def __total_size_cell_data_func(self, column, cell, model, iter):
         """Data function for the file size of downloads."""
@@ -352,11 +352,7 @@
             add = AddDownloadDialog(uri)
             add.dialog.show()
         else:
-            # print uri
-            # print self.config.default_folder
-            self.download_manager.start_download(uri,
-                    self.config.default_folder)
-
+            self.download_list.add_download(uri, self.config.default_folder)
             context.finish(True, False, time)
 
     def show_add_download_dialog(self, widget):
@@ -612,17 +608,26 @@
         else:
             self.eta_treeview_column.props.visible = True
 
-    def __download_added(self, download_manager, download):
+    def __download_added(self, download_list, download):
         """Called when a new download is added to DownloadManager. Adds the
         download to the treeview model and sets up the update handler."""
         self.downloads_model.append([download])
         download.connect("update", self.__download_update)
+        download.connect("status-changed", self.__download_status_changed)
         GUI.queue_resize(self.downloads_treeview)
 
     def __download_update(self, download, block_count, block_size, total_size):
         """Called on download updates. Finds the associated treeview row and
         fires a row changed signal."""
         # self.window.set_title("%s %s (%.2f%%)" % (NAME, download.file_name, download.percent_complete))
+        self.update_download_row(download)
+
+    def __download_status_changed(self, download, status):
+        self.update_download_row(download)
+
+    def update_download_row(self, download):
+        """Called on download updates. Finds the associated treeview row and
+        fires a row changed signal."""
         downloads_iter = self.downloads_model.get_iter_first()
         for row in self.downloads_model:
             if row[0] is download:

Modified: trunk/gget/Utils.py
==============================================================================
--- trunk/gget/Utils.py	(original)
+++ trunk/gget/Utils.py	Wed Jul  9 10:06:16 2008
@@ -24,8 +24,9 @@
 
 def get_readable_size(bits):
     for unit in ['bytes','KB','MB','GB','TB']:
-        if bits < 1024.0:
+        if float(bits) < 1024.0:
             return "%3.1f %s" % (bits, unit)
+        bits = float(bits)
         bits /= 1024.0
 
 def debug_print(message):
@@ -34,4 +35,18 @@
         print("[%s] %s" % (time.strftime("%Y/%m/%d %H:%M:%S", time.localtime()),
                 message))
 
+def indent(element, level=0):
+    """Indents a xml.ElementTree starting from element."""
+    i = "\n" + level*"  "
+    if len(element):
+        if not element.text or not element.text.strip():
+            element.text = i + "  "
+        for element in element:
+            indent(element, level+1)
+        if not element.tail or not element.tail.strip():
+            element.tail = i
+    else:
+        if level and (not element.tail or not element.tail.strip()):
+            element.tail = i
+
 # vim: set sw=4 et sts=4 tw=79 fo+=l:

Modified: trunk/gget/metalink.py
==============================================================================
--- trunk/gget/metalink.py	(original)
+++ trunk/gget/metalink.py	Wed Jul  9 10:06:16 2008
@@ -67,6 +67,10 @@
 #
 # CHANGELOG:
 #
+# Version 4.0
+# -----------
+# - Bugfixes
+#
 # Version 3.8
 # -----------
 # - Will now download any file type and auto-detect metalink files
@@ -190,6 +194,7 @@
 import ftplib
 import locale
 import gettext
+import logging
 import urllib2
 import urlparse
 import hashlib
@@ -202,10 +207,11 @@
 import socket
 import ftplib
 import httplib
-import logging
 import base64
 import sys
 import gettext
+import StringIO
+import gzip
 import os
 import StringIO
 import os.path
@@ -213,6 +219,11 @@
 import gettext
 import sys
 import locale
+
+try:
+    import win32process
+except ImportError: pass
+
 import xml.dom.minidom
 import optparse
 import socket
@@ -289,7 +300,7 @@
 
     #print base, localedir
     t = gettext.translation(base, localedir, [locale.getdefaultlocale()[0]], None, 'en')
-    return t.lgettext
+    return t.ugettext
 
 _ = translate()
 
@@ -613,8 +624,9 @@
 ########################################################################
 
 #import utils
+#import logging
 
-USER_AGENT = "Metalink Checker/3.8 +http://www.nabber.org/projects/";
+USER_AGENT = "Metalink Checker/4.0 +http://www.nabber.org/projects/";
 
 SEGMENTED = True
 LIMIT_PER_HOST = 1
@@ -668,7 +680,7 @@
 
     #print base, localedir
     t = gettext.translation(base, localedir, [locale.getdefaultlocale()[0]], None, 'en')
-    return t.lgettext
+    return t.ugettext
 
 _ = translate()
 
@@ -684,23 +696,61 @@
         self.preference = int(preference)
         self.maxconnections = int(maxconnections)
 
+
+class DecompressFile(gzip.GzipFile):
+    def __init__(self, fp):
+        self.fp = fp
+        self.geturl = fp.geturl
+
+        compressed = StringIO.StringIO(fp.read())
+        gzip.GzipFile.__init__(self, fileobj=compressed)
+    
+    def info(self):
+        info = self.fp.info()
+        # store current position, must reset if in middle of read operation
+        reset = self.tell()
+        # reset to start
+        self.seek(0)
+        newsize = str(len(self.read()))
+        # reset to original position
+        self.seek(reset)
+        info["Content-Length"] = newsize
+        return info
+    
 def urlopen(url, data = None, metalink=False):
+    #print "URLOPEN:", url
     url = complete_url(url)
-    headers = {'User-agent': USER_AGENT}
+    req = urllib2.Request(url, data)
+    req.add_header('User-agent', USER_AGENT)
+    req.add_header('Cache-Control', "no-cache")
+    req.add_header('Pragma', "no-cache")
+    req.add_header('Accept-Encoding', 'gzip')
     if metalink:
-        headers['Accept'] = MIME_TYPE + ", */*"
-    req = urllib2.Request(url, data, headers)
+        req.add_header('Accept', MIME_TYPE + ", */*")
+
     fp = urllib2.urlopen(req)
+    try:
+        if fp.headers['Content-Encoding'] == "gzip":
+            return DecompressFile(fp)
+    except KeyError: pass
+    #print fp.info()
     #print fp.read()
     return fp
 
 def urlhead(url, metalink=False):
+    '''
+    raise IOError for example if the URL does not exist
+    '''
     url = complete_url(url)
-    headers = {'User-agent': USER_AGENT}
+    req = urllib2.Request(url, None)
+    req.add_header('User-agent', USER_AGENT)
+    req.add_header('Cache-Control', "no-cache")
+    req.add_header('Pragma', "no-cache")
     if metalink:
-        headers['Accept'] = MIME_TYPE + ", */*"
-    req = urllib2.Request(url, None, headers)
+        req.add_header('Accept', MIME_TYPE + ", */*")
+
     req.get_method = lambda: "HEAD"
+    logging.debug(url)
     fp = urllib2.urlopen(req)
     headers = fp.headers
     fp.close()
@@ -738,19 +788,27 @@
     # assume metalink if ends with .metalink
     if src.endswith(".metalink"):
         return download_metalink(src, path, force, handler)
-    # add head check for metalink type, if MIME_TYPE or application/xml? treat as metalink
-    elif urlhead(src, metalink=True)["content-type"].startswith(MIME_TYPE):
-        print _("Metalink content-type detected.")
-        return download_metalink(src, path, force, handler)
-    # assume normal file download here
     else:
-        # parse out filename portion here
-        filename = os.path.basename(src)
-        result = download_file(src, os.path.join(path, filename), 
-                0, checksums, force, handler, segmented = segmented)
-        if result:
-            return [result]
-        return False
+        # not all servers support HEAD where GET is also supported
+        # also a WindowsError is thrown if a local file does not exist
+        try:
+            # add head check for metalink type, if MIME_TYPE or application/xml? treat as metalink
+            if urlhead(src, metalink=True)["content-type"].startswith(MIME_TYPE):
+                print _("Metalink content-type detected.")
+                return download_metalink(src, path, force, handler)
+        except IOError, e:
+            pass
+        except WindowsError, e:
+            pass
+            
+    # assume normal file download here
+    # parse out filename portion here
+    filename = os.path.basename(src)
+    result = download_file(src, os.path.join(path, filename), 
+            0, checksums, force, handler, segmented = segmented)
+    if result:
+        return [result]
+    return False
     
 def download_file(url, local_file, size=0, checksums={}, force = False, 
         handler = None, segmented = SEGMENTED, chunksums = {}, chunk_size = None):
@@ -928,7 +986,6 @@
                 result = download_file_node(filenode, path, force, handler)
                 if result:
                     results.append(result)
-                    
     if len(results) == 0:
         return False
     
@@ -1026,7 +1083,7 @@
     ### FIXME need to check contents from previous download here
     resume = FileResume(filename + ".temp")
     resume.add_block(0)
-    
+
     while block:
         block = temp.read(block_size)
         data.write(block)
@@ -1083,15 +1140,15 @@
                     offset = count
                 total += self.size
             elif offset != None:
-                start = ((offset * self.size) / size) + 1
-                newblocks.extend(range(start, start + (total / size)))
+                start = ((offset * self.size) / size)
+                newblocks.extend(map(str, range(start, start + (total / size))))
                 total = 0
                 offset = None
             count += 1
 
         if offset != None:
-            start = ((offset * self.size) / size) + 1
-            newblocks.extend(range(start, start + (total / size)))
+            start = ((offset * self.size) / size)
+            newblocks.extend(map(str, range(start, start + (total / size))))
 
         self.blocks = newblocks
         self.set_block_size(size)
@@ -1147,6 +1204,7 @@
         filehandle.write("%s:" % str(self.size))
         #for block_id in self.blocks:
             #filehandle.write(str(block_id) + ",")
+        #print self.blocks
         filehandle.write(",".join(self.blocks))
         filehandle.close()
 
@@ -1305,6 +1363,7 @@
         return True
     
     return False
+
 def is_remote(name):
     transport = get_transport(name)
         
@@ -1344,10 +1403,11 @@
     except:
         return ""
 
-    data = filehandle.read()
+    chunksize = 1024*1024
+    data = filehandle.read(chunksize)
     while(data != ""):
         filesha.update(data)
-        data = filehandle.read()
+        data = filehandle.read(chunksize)
 
     filehandle.close()
     return filesha.hexdigest()
@@ -1500,34 +1560,34 @@
         '''
         ?
         '''
-        try:
-            if self.size == "" or self.size == 0:
-                self.size = self.get_size()
-                if self.size == None:
-                    #crap out and do it the old way
-                    self.close_handler()
-                    return False
-            
-            while True:
-                #print "\ntc:", self.active_count(), len(self.sockets), len(self.urls)
-                #if self.active_count() == 0:
-                #print self.byte_total(), self.size
-                time.sleep(0.1)
-                self.update()
-                self.resume.extend_blocks(self.chunk_list())
-                if self.byte_total() >= self.size and self.active_count() == 0:
-                    self.resume.complete()
-                    self.close_handler()
-                    return True
+        #try:
+        if self.size == "" or self.size == 0:
+            self.size = self.get_size()
+            if self.size == None:
                 #crap out and do it the old way
-                if len(self.urls) == 0:
-                    self.close_handler()
-                    return False
-                
-            return False
-        except BaseException, e:
-            logging.warning(unicode(e))
-            return False
+                self.close_handler()
+                return False
+        
+        while True:
+            #print "\ntc:", self.active_count(), len(self.sockets), len(self.urls)
+            #if self.active_count() == 0:
+            #print self.byte_total(), self.size
+            time.sleep(0.1)
+            self.update()
+            self.resume.extend_blocks(self.chunk_list())
+            if self.byte_total() >= self.size and self.active_count() == 0:
+                self.resume.complete()
+                self.close_handler()
+                return True
+            #crap out and do it the old way
+            if len(self.urls) == 0:
+                self.close_handler()
+                return False
+            
+        return False
+##        except BaseException, e:
+##            logging.warning(unicode(e))
+##            return False
 
     def update(self):
         next = self.next_url()
@@ -2300,6 +2360,7 @@
 download = Dummy()
 download.CONNECT_RETRY_COUNT = CONNECT_RETRY_COUNT
 download.COUNTRY = COUNTRY
+download.DecompressFile = DecompressFile
 download.FTP = FTP
 download.FTP_PROXY = FTP_PROXY
 download.FileResume = FileResume
@@ -2387,7 +2448,7 @@
 
     #print base, localedir
     t = gettext.translation(base, localedir, [locale.getdefaultlocale()[0]], None, 'en')
-    return t.lgettext
+    return t.ugettext
 
 _ = translate()
 
@@ -2405,17 +2466,23 @@
         self.signature_id = self.key_id = None
         self.username = None
         self.error = None
+        self.nopubkey = False
 
     def BADSIG(self, value):
+        self.error = "BADSIG"
         self.valid = 0
         self.key_id, self.username = value.split(None, 1)
     def GOODSIG(self, value):
         self.valid = 1
+        #self.error = "GOODSIG"
         self.key_id, self.username = value.split(None, 1)
     def VALIDSIG(self, value):
         #print value
+        #self.valid = 1
+        #self.error = "VALID_SIG"
         self.fingerprint, self.creation_date, self.timestamp, other = value.split(" ", 3)
     def SIG_ID(self, value):
+        #self.error = "SIG_ID"
         self.signature_id, self.creation_date, self.timestamp = value.split(" ", 2)
     def NODATA(self, value):
         self.error = _("File not properly loaded for signature.")
@@ -2423,10 +2490,19 @@
         #print value
         self.error = _("Signature error.")
     def NO_PUBKEY(self, value):
-        #print value
+        self.key_id = value
+        self.nopubkey = True
         self.error = _("Signature error, missing public key with id 0x%s.") % value[-8:]
+        
+    def TRUST_ULTIMATE(self, value):
+        '''
+        see http://cvs.gnupg.org/cgi-bin/viewcvs.cgi/trunk/doc/DETAILS?rev=289
+        Trust settings do NOT determine if a signature is good or not!  That is reserved for GOOD_SIG!
+        '''
+        return
+        
     def TRUST_UNDEFINED(self, value):
-        pass
+        self.error = _("Trust undefined")
         #print value.split()
         #raise AssertionError, "File not properly loaded for signature."
     
@@ -2577,7 +2653,7 @@
         # the file objects for communicating with it.
         cmd = [self.gpg_binary, '--status-fd 2']
         if self.keyring:
-            cmd.append('--keyring "%s" --no-default-keyring'%self.keyring)
+            cmd.append('--keyring "%s" --no-default-keyring'% self.keyring)
 
         cmd.extend(args)
         cmd = ' '.join(cmd)
@@ -2586,7 +2662,14 @@
         shell = True
         if os.name == 'nt':
             shell = False
-        process = subprocess.Popen(cmd, shell=shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+        # From: http://www.py2exe.org/index.cgi/Py2ExeSubprocessInteractions
+        creationflags = 0
+        try:
+            creationflags = win32process.CREATE_NO_WINDOW
+        except NameError: pass
+            
+        process = subprocess.Popen(cmd, shell=shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags = creationflags)
         #child_stdout, child_stdin, child_stderr =  #popen2.popen3(cmd)
         #return child_stdout, child_stdin, child_stderr
         #print process.stderr
@@ -2939,7 +3022,7 @@
 
 
 # DO NOT CHANGE
-VERSION="Metalink Checker Version 3.8"
+VERSION="Metalink Checker Version 4.0"
 
 
 def translate():
@@ -2960,7 +3043,7 @@
 
     #print base, localedir
     t = gettext.translation(base, localedir, [locale.getdefaultlocale()[0]], None, 'en')
-    return t.lgettext
+    return t.ugettext
 
 _ = translate()
 
@@ -2971,7 +3054,7 @@
     # Command line parser options.
     parser = optparse.OptionParser(version=VERSION)
     parser.add_option("--download", "-d", action="store_true", dest="download", help=_("Actually download the file(s) in the metalink"))
-    parser.add_option("--file", "-f", dest="filevar", metavar="FILE", help=_("Metalink file to check"))
+    parser.add_option("--file", "-f", dest="filevar", metavar="FILE", help=_("Metalink file to check or file to download"))
     parser.add_option("--timeout", "-t", dest="timeout", metavar="TIMEOUT", help=_("Set timeout in seconds to wait for response (default=10)"))
     parser.add_option("--os", "-o", dest="os", metavar="OS", help=_("Operating System preference"))
     parser.add_option("--no-segmented", "-s", action="store_true", dest="nosegmented", help=_("Do not use the segmented download method"))
@@ -3009,13 +3092,9 @@
         return
     
     if options.download:
-        download.SEGMENTED = True
-        if options.nosegmented:
-            download.SEGMENTED = False
 
         progress = ProgressBar(55)
-        result = download.get(options.filevar, os.getcwd(), handler=progress.download_update)
-        #result = download.download_metalink(options.filevar, os.getcwd(), handler=progress.download_update)
+        result = download.get(options.filevar, os.getcwd(), handler=progress.download_update, segmented = not options.nosegmented)
         progress.download_end()
         if not result:
             sys.exit(-1)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]