Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

beebox / crossover   deb

Repository URL to install this package:

Version: 18.5.0-1 

/ opt / cxoffice / lib / python / proxyinfo.py

# (c) Copyright 2010-2014. CodeWeavers, Inc.

import os
import traceback
import urllib2
import sys

import cxlog
import cxproduct
import cxutils
import distversion


#####
#
# Desktop environment detection
#
#####

# Cache the desktop environment because determining it can be slow and it's
# not supposed to change at runtime.
_DESKTOP_ENVIRONMENT = None

def get_desktop_environment():
    """Returns the name of the currently running desktop environment."""
    # pylint: disable=W0603
    global _DESKTOP_ENVIRONMENT
    if _DESKTOP_ENVIRONMENT:
        return _DESKTOP_ENVIRONMENT

    _DESKTOP_ENVIRONMENT = 'unknown'
    if cxutils.CX_ROOT is not None and \
            cxproduct.get_config()['CrossOver'].get('ManualProxySettings', '0') == '1':
        _DESKTOP_ENVIRONMENT = 'config'
    elif distversion.IS_MACOSX:
        _DESKTOP_ENVIRONMENT = 'macosx'
    elif 'GNOME_DESKTOP_SESSION_ID' in os.environ:
        _DESKTOP_ENVIRONMENT = 'gnome'
    elif 'KDE_FULL_SESSION' in os.environ:
        _DESKTOP_ENVIRONMENT = 'kde'
    else:
        try:
            # pylint: disable=F0401
            import dbus
            bus = dbus.SystemBus()
            dbus_obj = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
            dbus_interface = dbus.Interface(dbus_obj, 'org.freedesktop.DBus')
        except Exception, exception: # pylint: disable=W0703
            cxlog.log("could not connect to D-Bus: %s\n" % str(exception))
        else:
            # Do it the slow way
            session_managers = (
                ('org.gnome.SessionManager', 'gnome'),
                ('org.kde.ksmserver', 'kde'),
                ('org.xfce.SessionManager', 'xfce'),
                )
            for dbus_name, desktop_environment in session_managers:
                if dbus_interface.NameHasOwner(dbus_name):
                    _DESKTOP_ENVIRONMENT = desktop_environment
                    break
    return _DESKTOP_ENVIRONMENT


#####
#
# libproxy support
#
#####

# As of version 0.3, libproxy is unfortunately too buggy to be usable
_USE_LIBPROXY = False
_LIBPROXY_FACTORY = None

def get_libproxy_factory():
    """Detects whether libproxy is available and sets it up."""
    # pylint: disable=W0603
    global _LIBPROXY_FACTORY
    if _USE_LIBPROXY and _LIBPROXY_FACTORY is None:
        try:
            # pylint: disable=F0401
            import libproxy
            _LIBPROXY_FACTORY = libproxy.ProxyFactory()
        except Exception, exception: # pylint: disable=W0703
            cxlog.log("could not load libproxy: %s\n" % str(exception))
    return _LIBPROXY_FACTORY

def has_libproxy():
    """Returns True if libproxy support is available."""
    if get_libproxy_factory():
        return True
    return False

def get_proxy_libproxy(req):
    """Returns the default proxy to use for the specified URL."""
    factory = get_libproxy_factory()
    if factory:
        proxy = factory.getProxies(req.get_full_url())[0]
        if proxy != 'direct://':
            return proxy
    return ''


#####
#
# Basic GNOME support
#
#####

def get_proxy_gconf(req):
    """Detects GNOME's proxy settings using GConf."""
    # pylint: disable=F0401
    try:
        import gconf
    except ImportError:
        return ''

    client = gconf.client_get_default()

    scheme = req.get_type()
    if scheme == 'https':
        scheme = 'secure' # gconf calls https "secure"

    if scheme == 'http':
        if not client.get_bool('/system/http_proxy/use_http_proxy'):
            return ''
        host = client.get_string('/system/http_proxy/host')
        port = client.get_int('/system/http_proxy/port')
    else:
        if client.get_string('/system/proxy/mode') == 'none':
            return ''
        host = client.get_string('/system/proxy/%s_host' % scheme)
        port = client.get_int('/system/proxy/%s_port' % scheme)

    if not host or not port:
        return ''

    if client.get_bool('/system/http_proxy/use_authentication'):
        # Not sure if we should do this unconditionally, but gconf provides
        # no other authentication info
        auth_user = client.get_string('/system/http_proxy/authentication_user')
        auth_pass = client.get_string('/system/http_proxy/authentication_password')
        auth_info = '%s:%s@' % (auth_user, auth_pass)
    else:
        auth_info = ''

    return '%s%s:%s' % (auth_info, host, port)

def get_proxy_gsettings(req):
    """Detects GNOME's proxy settings using gsettings."""

    which_cmd = ["which", "gsettings"]
    retcode, out, _err = cxutils.run(which_cmd, stdout=cxutils.GRAB)
    if retcode == 0:
        gsettings_path = out.rstrip()
    else:
        return ''

    schema = "org.gnome.system.proxy"

    gsettings_cmd = [gsettings_path, "get", schema, "mode"]
    retcode, out, _err = cxutils.run(gsettings_cmd, stdout=cxutils.GRAB)
    if retcode != 0 or out.rstrip().replace("'", "") == "none":
        return ''

    scheme = req.get_type()
    schema = "org.gnome.system.proxy." + scheme

    gsettings_cmd = [gsettings_path, "get", schema, "host"]
    retcode, out, _err = cxutils.run(gsettings_cmd, stdout=cxutils.GRAB)
    host = ""
    if retcode == 0:
        host = out.rstrip().replace("'", "")

    if host == "":
        return ''

    gsettings_cmd = [gsettings_path, "get", schema, "port"]
    retcode, out, _err = cxutils.run(gsettings_cmd, stdout=cxutils.GRAB)
    if retcode == 0:
        port = out.rstrip()
    else:
        return ''

    return '%s:%s' % (host, port)

#####
#
# Basic KDE 4 support
#
#####

_HAS_KDE = None

def _init_kde():
    """Initializes the KDE environment so we can query its proxy settings."""
    # pylint: disable=W0603
    global _HAS_KDE
    if _HAS_KDE is None:
        try:
            # pylint: disable=F0401
            import PyQt4.Qt
            # pylint: disable=W0612
            import PyKDE4.kdecore

            # QApplication must be instantiated before we can use KConfig.
            # Also it must be created on startup otherwise it will cause a
            # crash (maybe because of a conflict with GTK+).
            PyQt4.Qt.QApplication([])
            _HAS_KDE = True
        except Exception, exception: # pylint: disable=W0703
            cxlog.log("could not initialize the KDE 4 libraries: %s\n" % str(exception))
            _HAS_KDE = False

def get_proxy_kde_int(config, name):
    """Helper for get_proxy_kde(). Retrieves the value of an integer KDE
    property.
    """
    value = config.readEntry(name)
    if value == '':
        return 0
    return int(value)

def get_proxy_kde(req):
    """Detects KDE's proxy settings using PyQT4 and PyKDE4."""
    if _HAS_KDE:
        # pylint: disable=F0401
        import PyKDE4.kdecore
        # The config object must be recreated each time otherwise we won't
        # notice changes in the proxy settings
        config = PyKDE4.kdecore.KConfig('kioslaverc')
        proxy_settings = config.group('Proxy Settings')
        proxy_type = get_proxy_kde_int(proxy_settings, 'ProxyType')
        if proxy_type == 0:
            # no proxy
            return ''
        if proxy_type != 1:
            cxlog.warn("Cannot handle KDE proxy of type %d; using environment instead of KDE settings" % proxy_type)
            return ''
        if proxy_settings.readEntry('NoProxyFor'):
            if proxy_settings.readEntry('ReversedException') == 'false':
                # Expect the exception to only impact a few hosts we are not
                # going to access anyway, typically hosts on the LAN.
                cxlog.warn("Cannot handle proxy exceptions; ignoring them")
            else:
                cxlog.warn("Cannot handle proxy exceptions; using environment instead of KDE settings")
                return ''
        if get_proxy_kde_int(proxy_settings, 'AuthMode'):
            cxlog.warn("Don't know how to read KDE proxy authorization; using environment instead of KDE settings")
            return ''

        proxy_url = str(proxy_settings.readEntry(req.get_type() + 'Proxy'))
        proxy_url = proxy_url.replace(' ', ':') # string value separates host and port with space
        if not proxy_url.startswith('//:'):
            return proxy_url
    return ''


#####
#
# Support the environment variables as a fallback
#
#####

def get_proxy_env(req):
    """Detects the environment's proxy settings."""
    return os.environ.get(req.get_type() + '_proxy', '')


def get_proxy_conf(req):
    """Reads proxy settings from crossover.conf."""
    global_config = cxproduct.get_config()
    return global_config['CrossOver'].get(req.get_type() + 'Proxy', '')


#####
#
# DynamicProxyHandler
#
#####

class DynamicProxyHandler(urllib2.ProxyHandler):
    """A proxy handler that dynamically detects the proxy settings each time
    it is queried so it can react to proxy configuration changes.
    """

    # Proxies must be in front
    handler_order = 100

    _PROXY_DETECTORS = {
        'gnome':   (get_proxy_gconf, get_proxy_gsettings, get_proxy_env),
        'kde':     (get_proxy_kde, get_proxy_env),
        'xfce':    (get_proxy_gconf, get_proxy_env),
        # The Mac GUI avoids urllib2, so this doesn't matter.
        'macosx':  (get_proxy_env, ),
        'unknown': (get_proxy_env, ),
        'config':  (get_proxy_conf, ),
        }

    def __init__(self):
        urllib2.ProxyHandler.__init__(self, {})
        if has_libproxy():
            # libproxy supports all the desktop environments we support, only
            # better. So we don't want to fall back to our code and pick up
            # potentially incorrect settings (e.g. environment variables).
            self._detectors = (get_proxy_libproxy, )
        else:
            # The desktop environment is not supposed to change at runtime.
            self._detectors = self._PROXY_DETECTORS[get_desktop_environment()]

    def get_proxy(self, req):
        for get_proxy in self._detectors:
            try:
                url = get_proxy(req)
                if url:
                    if '://' not in url and \
                            not (sys.version_info >= (2, 6) or \
                                     hasattr(urllib2, '_parse_proxy')):
                        # Some old versions of python can't cope with a proxy
                        # URL without a schema
                        url = 'http://' + url
                    #
                    # NOTE! It would be a possible security threat to
                    # log the actual proxy settings here b/c, for some
                    # settings, a username/password combo might be included.
                    # So, don't do that.
                    #
                    cxlog.log("Proxy settings detected.  Network communication will be attempted via proxy.\n")
                    return url
            except: # pylint: disable=W0702
                cxlog.warn("Could not get the proxy info:\n%s" % traceback.format_exc())
        return None

    def do_open(self, req):
        proxy = self.get_proxy(req)
        if proxy:
            return self.proxy_open(req, proxy, req.get_type())
        return None

    def ftp_open(self, req):
        return self.do_open(req)

    def http_open(self, req):
        return self.do_open(req)

    def https_open(self, req):
        return self.do_open(req)

    def socks_open(self, req):
        return self.do_open(req)


def install_default_opener():
    """Sets up a default opener that auto-detects the current proxy settings."""
    proxy_handler = DynamicProxyHandler()
    opener = urllib2.build_opener(proxy_handler)
    urllib2.install_opener(opener)


def _init():
    """Performs the initialization tasks that must be performed at startup."""
    if not has_libproxy() and get_desktop_environment() == 'kde':
        # Initializing KDE can be quite slow so only do it if needed
        _init_kde()


if __name__ == '__main__':
    # set CX_ROOT so reading crossover.conf will work when run stand-alone
    cxutils.CX_ROOT = os.path.join(os.path.dirname(sys.argv[0]), '../..')
_init()


#####
#
# Test code
#
#####

def main():
    print 'Desktop environment: ' + get_desktop_environment()
    dynproxy = DynamicProxyHandler()
    print "Hit Enter to refresh, Ctrl-D to quit"
    while sys.stdin.readline():
        for scheme in ('ftp', 'http', 'https', 'socks'):
            print '%s -> [%s]' % (scheme, dynproxy.get_proxy(urllib2.Request(scheme + '://codeweavers.com')))


if __name__ == '__main__':
    main()