# This file is a portion of the Red Hat Network Panel Applet
#
# Copyright (C) 1999-2003 Red Hat, Inc. All Rights Reserved.
# Distributed under GPL version 2.
#
# This handle the up2date package list source
#
# Author: Chip Turner
#
# $Id: rhn_applet_rpc.py,v 1.22 2003/10/15 22:52:19 veillard Exp $

import string
import os
import time
import pwd
import cPickle
import socket

import rhn_utils

try:
    from rhn import rpclib
    from rhn import xmlrpclib
except ImportError:
    rpclib = __import__("xmlrpclib")

from rhn_utils import \
     rhnAppletException, \
     rhnAppletRPCFault, \
     rhnAppletNetworkException
from rhn_applet_source import rhnAppletSource

class rhnAppletRPC(rhnAppletSource):
    def __init__(self, url, refresh_callback, uuid, release, arch, cert, proxy_url, proxy_username, proxy_password):
	rhnAppletSource.__init__(self, url=url, release=release, arch=arch)
        self.__arch__ = arch
        self.__release__ = release
        
        self.__server_url__ = url
        self.__uuid__ = uuid
        self.__refresh_callback__ = refresh_callback
        
        self.__cert__ = cert
        self.__proxy_url__ = proxy_url
        self.__proxy_username__ = proxy_username
        self.__proxy_password__ = proxy_password

        self.__latest_packages__ = []
        self.__latest_packages_mtime__ = 0

        self.__get_data_store()
	self.__nb_errors = 0

    def name(self):
        return "RHN @ %s" % (self.__server_url__)

    def in_error(self):
        return self.__nb_errors != 0

    def set_proxy(self, proxy_url, proxy_username, proxy_password):
        self.__proxy_url__ = self.__proxy_username__ = self.__proxy_password__ = ''
        
        if proxy_url:
            self.__proxy_url__ = proxy_url
            if proxy_username:
                self.__proxy_username__ = proxy_username
                self.__proxy_password__ = proxy_password
        
    def create_server(self):
        options = { "uri" : self.__server_url__,
                    "refreshCallback" : self.__refresh_callback__ }

        if self.__proxy_url__:
            options["proxy"] = self.__proxy_url__
            if self.__proxy_username__:
                options["username"] = self.__proxy_username__
                options["password"] = self.__proxy_password__

        s = apply(rpclib.Server, [], options)

        if self.__cert__:
            s.add_trusted_cert(self.__cert__)

        return s

    def _do_refresh(self):
        server = self.create_server()

        try:
            status = server.applet.poll_status()
        
            # let's not change this object's state unless we fully
            # succeed in our checkin
            
            last_checkin = time.time()
            next_checkin = time.time() + int(status["checkin_interval"])

            latest_packages = server.applet.poll_packages(self.__release__,
                                                          self.__arch__,
                                                          self.__latest_packages_mtime__,
                                                          self.__uuid__)
        except (socket.error, socket.sslerror), e:
	    self.__nb_errors = 1
            rhn_utils.log_debug("socket error in rpc: %s" % type(e))
            if len(e.args) > 1:
                raise rhnAppletNetworkException(e.args[0], e.args[1])
            else:
                raise rhnAppletNetworkException(-12, e.args[0])
        except rpclib.Fault, f:
	    self.__nb_errors = 1
            rhn_utils.log_debug("xmlrpc fault in rpc: %s" % f)
            raise rhnAppletRPCFault(f.faultCode, f.faultString)
        except rpclib.ProtocolError, p:
	    self.__nb_errors = 1
            rhn_utils.log_debug("xmlrpc protocol error in rpc: %s" % p)
            raise rhnAppletException(p)
            
        self.__last_checkin__ = last_checkin
        self.set_next_checking(next_checkin)
	self.__nb_errors = 0

        if latest_packages.has_key("no_packages"):
            rhn_utils.log_debug("no_packages received from server")
            self.__latest_packages_mtime__ = 0
            self.__latest_packages__ = []
            self.inc_change_number()

            self.__save_data_store()
        elif latest_packages.has_key("use_cached_copy"):
            rhn_utils.log_debug("server says to use cached copy")
            pass
            # nop
        else:
            rhn_utils.log_debug("packages received from server, mtime %s" % latest_packages["last_modified"])
            self.__latest_packages__ = latest_packages["contents"]
            self.__latest_packages_mtime__ = latest_packages["last_modified"]
            self.inc_change_number()

            self.__save_data_store()
            
    def latest_packages(self):
        return self.__latest_packages__

    def __get_data_store(self):
        file = pwd.getpwuid(os.getuid())[5]
        file = file + "/.rhn-applet.cache"

        try:
            fd = open(file, "r")
            self.__latest_packages_mtime__, self.__latest_packages__ = cPickle.load(fd)
	    #
	    # if there have been an upgrade or downgrade since the last save
	    # the cache should be disabled.
	    #
	    for package in self.__latest_packages__:
	        if package['name'] == 'redhat-release':
		    if self.__release__ != package['version']:
		        rhn_utils.log_debug("Cache invalid, version %s current is %s" % (package['version'], self.__release__))
			self.__latest_packages__ = []
			self.__latest_packages_mtime__ = 0
			try:
			    os.unlink(file)
			except:
			    pass
		    break

        except Exception, e:
            rhn_utils.log_debug("can't open for reading %s: %s, trying to remove it..." % (file, str(e)))
            try:
                os.unlink(file)
            except:
                pass

    def __save_data_store(self):
        file = pwd.getpwuid(os.getuid())[5]
        file = file + "/.rhn-applet.cache"

        try:
            fd = open(file, "w")
            cPickle.dump([ self.__latest_packages_mtime__, self.__latest_packages__ ], fd, 1)
        except Exception, e:
            rhn_utils.log_debug("can't open for writing %s: %s, trying to remove it..." % (file, str(e)))
            try:
                os.unlink(file)
            except:
                pass
        
