Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/downloadmanager.py
diff options
context:
space:
mode:
Diffstat (limited to 'downloadmanager.py')
-rw-r--r--downloadmanager.py90
1 files changed, 89 insertions, 1 deletions
diff --git a/downloadmanager.py b/downloadmanager.py
index 4b6e84f..8d5fae9 100644
--- a/downloadmanager.py
+++ b/downloadmanager.py
@@ -23,6 +23,7 @@ import urlparse
import gtk
import hulahop
+import xpcom
from xpcom.nsError import *
from xpcom import components
from xpcom.components import interfaces
@@ -43,7 +44,8 @@ if dbus.version >= (0, 82, 3):
else:
DBUS_PYTHON_TIMEOUT_UNITS_PER_SECOND = 1000
-NS_BINDING_ABORTED = 0x804b0002 # From nsNetError.h
+NS_BINDING_ABORTED = 0x804b0002 # From nsNetError.h
+NS_ERROR_SAVE_LINK_AS_TIMEOUT = 0x805d0020 # From nsURILoader.h
DS_DBUS_SERVICE = 'org.laptop.sugar.DataStore'
DS_DBUS_INTERFACE = 'org.laptop.sugar.DataStore'
@@ -285,3 +287,89 @@ components.registrar.registerFactory('{23c51569-e9a1-4a92-adeb-3723db82ef7c}',
'Sugar Download',
'@mozilla.org/transfer;1',
Factory(Download))
+
+def save_link(url, text, owner_document):
+ # Inspired on Firefox' browser/base/content/nsContextMenu.js:saveLink()
+
+ cls = components.classes["@mozilla.org/network/io-service;1"]
+ io_service = cls.getService(interfaces.nsIIOService)
+ uri = io_service.newURI(url, None, None)
+ channel = io_service.newChannelFromURI(uri)
+
+ auth_prompt_callback = xpcom.server.WrapObject(
+ _AuthPromptCallback(owner_document.defaultView),
+ interfaces.nsIInterfaceRequestor)
+ channel.notificationCallbacks = auth_prompt_callback
+
+ channel.loadFlags = channel.loadFlags | \
+ interfaces.nsIRequest.LOAD_BYPASS_CACHE | \
+ interfaces.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS
+
+ if _implements_interface(channel, interfaces.nsIHttpChannel):
+ channel.referrer = io_service.newURI(owner_document.documentURI, None,
+ None)
+
+ # kick off the channel with our proxy object as the listener
+ listener = xpcom.server.WrapObject(
+ _SaveLinkProgressListener(owner_document),
+ interfaces.nsIStreamListener)
+ channel.asyncOpen(listener, None)
+
+def _implements_interface(obj, interface):
+ try:
+ obj.QueryInterface(interface)
+ return True
+ except xpcom.Exception, e:
+ if e.errno == NS_NOINTERFACE:
+ return False
+ else:
+ raise
+
+class _AuthPromptCallback(object):
+ _com_interfaces_ = interfaces.nsIInterfaceRequestor
+
+ def __init__(self, dom_window):
+ self._dom_window = dom_window
+
+ def getInterface(self, uuid):
+ if uuid in [interfaces.nsIAuthPrompt, interfaces.nsIAuthPrompt2]:
+ cls = components.classes["@mozilla.org/embedcomp/window-watcher;1"]
+ window_watcher = cls.getService(interfaces.nsIPromptFactory)
+ return window_watcher.getPrompt(self._dom_window, uuid)
+ return None
+
+class _SaveLinkProgressListener(object):
+ _com_interfaces_ = interfaces.nsIStreamListener
+
+ """ an object to proxy the data through to
+ nsIExternalHelperAppService.doContent, which will wait for the appropriate
+ MIME-type headers and then prompt the user with a file picker
+ """
+
+ def __init__(self, owner_document):
+ self._owner_document = owner_document
+ self._external_listener = None
+
+ def onStartRequest(self, request, context):
+ if request.status != NS_OK:
+ logging.error("Error downloading link")
+ return
+
+ cls = components.classes[
+ "@mozilla.org/uriloader/external-helper-app-service;1"]
+ external_helper = cls.getService(interfaces.nsIExternalHelperAppService)
+
+ channel = request.QueryInterface(interfaces.nsIChannel)
+
+ self._external_listener = \
+ external_helper.doContent(channel.contentType, request,
+ self._owner_document.defaultView, True)
+ self._external_listener.onStartRequest(request, context)
+
+ def onStopRequest(self, request, context, statusCode):
+ self._external_listener.onStopRequest(request, context, statusCode)
+
+ def onDataAvailable(self, request, context, inputStream, offset, count):
+ self._external_listener.onDataAvailable(request, context, inputStream,
+ offset, count);
+