#
# This module contains all the RPC-related functions the RHN code uses
#
# Copyright (c) 2005--2020 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# Red Hat trademarks are not licensed under GPLv2. No permission is
# granted to use or replicate Red Hat trademarks that are incorporated
# in this software or its documentation.
#

__version__ = "3.0.3-2.el9.cloudlinux-"

import xmlrpc.client as xmlrpclib

from urllib.parse import (
    urlparse,
    urlunparse,
    splittype,
    splithost,
)

from rhn import transports


class MalformedURIError(IOError):
    pass


class Server(xmlrpclib.ServerProxy):
    """uri [,options] -> a logical connection to an XML-RPC server

    uri is the connection point on the server, given as
    scheme://host/target.

    If the target part and the slash preceding it are both omitted,
    "/RPC2" is assumed.

    The following options can be given as keyword arguments:

        transport: a transport factory
        verbose: verbosity level
        proxy: use an HTTP proxy
        username: username for authenticated HTTP proxy
        password: password for authenticated HTTP proxy

    """

    def __init__(
            self, uri, transport=None, verbose=0,
            proxy=None, username=None, password=None, timeout=None):

        use_https = uri.startswith('https')
        if transport is None:
            transport = transports.RequestsTransport(
                use_https=use_https,
                timeout=timeout,
                proxy=self.get_proxy_uri(proxy, username, password, use_https)
            )

        self._reset_host_handler_and_type(uri)

        super().__init__(uri, transport, verbose=verbose)

    def get_proxy_uri(self, proxy_host, proxy_user, proxy_pass, use_https):
        if proxy_host is None:
            return None

        parts = urlparse('http://' + proxy_host)

        auth_string = None
        if proxy_user is not None:
            auth_string = proxy_user

        if auth_string and proxy_pass is not None:
            auth_string = auth_string + ':' + proxy_pass

        if auth_string:
            parts = parts._replace(netloc=auth_string + "@" + parts.netloc)

        if use_https:
            parts = parts._replace(scheme='https')
        else:
            parts = parts._replace(scheme='http')

        return urlunparse(parts)

    def _reset_host_handler_and_type(self, uri):
        """
        Reset the attributes:
        self._host, self._handler, self._type
        according the value of self._uri.

        Kept for backwards compatibility.
        """
        # get the url
        type, uri = splittype(uri)
        if type is None:
            raise MalformedURIError("missing protocol in uri")
        # with a real uri passed in, uri will now contain "//hostname..." so we
        # need at least 3 chars for it to maybe be ok...
        if len(uri) < 3 or uri[0:2] != "//":
            raise MalformedURIError
        self._type = type.lower()
        if self._type not in ("http", "https"):
            raise IOError("unsupported XML-RPC protocol")
        self._host, self._handler = splithost(uri)
        if not self._handler:
            self._handler = "/RPC2"

    def set_header(self, name, arg):
        return self._ServerProxy__transport.set_header(name, arg)

    def add_header(self, name, arg):
        return self._ServerProxy__transport.add_header(name, arg)

    def clear_headers(self):
        return self._ServerProxy__transport.clear_headers()

    def set_trusted_cert(self, certfile):
        self._ServerProxy__transport.set_trusted_cert(certfile)


def getHeaderValues(headers, name):
    import mimetools
    if not isinstance(headers, mimetools.Message):
        if name in headers:
            return [headers[name]]
        return []

    return [x.split(':', 1)[1].strip() for x in
            headers.getallmatchingheaders(name)]


def reportError(headers):
    """ Reports the error from the headers. """
    errcode = 0
    errmsg = ""
    s = "X-RHN-Fault-Code"
    if s in headers:
        errcode = int(headers[s])
    s = "X-RHN-Fault-String"
    if s in headers:
        _sList = getHeaderValues(headers, s)
        if _sList:
            _s = ''.join(_sList)
            import base64
            errmsg = "%s" % base64.decodestring(_s)

    return errcode, errmsg
