#!/usr/bin/python # Copyright (C) 2004 Henning Jacobs # # This program 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. # # $Id: CoCuMa_Client.py 82 2004-07-11 13:01:44Z henning $ from __version__ import __version__ import debug class CoCuMa_AbstractClient: "Abstract Base Client" def __init__(self): self.server = None self.connected = False self.errorstring = "" def getErrorString(self): return self.errorstring def Connect(self, connect_str): "Connect to Server and start Session" raise NotImplementedError def Disconnect(self): "Disconnect from Server = Exit Session" raise NotImplementedError def ListHandles(self, sortby): "Returns List of Handles" raise NotImplementedError def QueryAttributes(self, handles, attributes): "Returns a list of a list of attributes" raise NotImplementedError def GetContact(self, handle): "Returns Contact in vCard Format" raise NotImplementedError def PutContact(self, handle, data): "Store Contact and overwrite previous one" raise NotImplementedError def NewContact(self, initdict={}): "Create new Contact and return Handle" raise NotImplementedError def DelContact(self, handle): "Remove Contact" raise NotImplementedError def ListJournalHandles(self, sortby): "Returns List of Handles" raise NotImplementedError def QueryJournalAttributes(self, handles, attributes): "Returns a list of a list of attributes" raise NotImplementedError def GetJournal(self, handle): "Returns Contact in vEvent Format" raise NotImplementedError def PutJournal(self, handle, data): "Store Journal and overwrite previous one" raise NotImplementedError def NewJournal(self, initdict={}): "Create new Contact and return Handle" raise NotImplementedError def DelJournal(self, handle): "Remove Contact" raise NotImplementedError class CoCuMa_XMLRPCClient(CoCuMa_AbstractClient): "Client to the XMLRPC Server (CoCuMa_Server.py)" def __init__(self): CoCuMa_AbstractClient.__init__(self) self.cache_handles = {} self.cache_contacts = {} self.cache_journalhandles = {} self.cache_journals = {} def Connect(self, connect_str="http://localhost:8810"): "Connect to Server and start Session" self.errorstring = "" import xmlrpclib, socket retries = 4 # four connection retries for i in range(retries): try: self.server = xmlrpclib.ServerProxy(connect_str) ver = self.server.SessionInit() if ver == "CoCuMa_Server "+__version__: self.connected = True return True # Alright, we made it! else: self.errorstring = "Version Mismatch" debug.echo("CoCuMa_XMLRPCClient.Connect(): Could not connect to server: %s" % self.errorstring) # We don't need to retry, # because the server's version won't change ;-) return False except socket.error, detail: errno, self.errorstring = detail if errno != 111: return False except Exception, detail: self.errorstring = detail debug.echo("CoCuMa_XMLRPCClient.Connect(): Retrying connection to server..") import time # Exponential Backoff (wait up to 1.6 sec): time.sleep(0.2*(2**i)) return False def Disconnect(self): "Disconnect from Server = Exit Session" self.server.SessionQuit() self.server = None self.connected = False def ListHandles(self, sortby): "Returns List of Handles" if self.connected: if not self.cache_handles.has_key(sortby): self.cache_handles[sortby] = self.server.ListHandles(sortby) return self.cache_handles[sortby] else: return None def QueryAttributes(self, handles, attributes): "Returns a list of a list of attributes" if self.connected: return self.server.QueryAttributes(handles, attributes) else: return None def GetContact(self, handle): "Returns Contact in vCard Format" try: return self.cache_contacts[handle] except: if self.connected: data = self.server.GetContact(handle) self.cache_contacts[handle] = data return data else: return None def PutContact(self, handle, data): "Store Contact and overwrite previous one" if self.connected: try: self.cache_handles.clear() del self.cache_contacts[handle] except: pass return self.server.PutContact(handle, data) else: return None def NewContact(self, initdict={}): "Create new Contact and return Handle" if self.connected: self.cache_handles.clear() return self.server.NewContact(initdict) else: return None def DelContact(self, handle): "Remove Contact" if self.connected: try: del self.cache_contacts[handle] except: pass self.cache_handles.clear() return self.server.DelContact(handle) else: return None def ListJournalHandles(self, sortby): "Returns List of Handles" if self.connected: if not self.cache_journalhandles.has_key(sortby): self.cache_journalhandles[sortby] = self.server.ListJournalHandles(sortby) return self.cache_journalhandles[sortby] else: return None def QueryJournalAttributes(self, handles, attributes): "Returns a list of a list of attributes" if self.connected: return self.server.QueryJournalAttributes(handles, attributes) else: return None def GetJournal(self, handle): "Returns Contact in vEvent Format" try: return self.cache_journals[handle] except: if self.connected: data = self.server.GetJournal(handle) self.cache_journals[handle] = data return data else: return None def PutJournal(self, handle, data): "Store Journal and overwrite previous one" if self.connected: try: self.cache_journalhandles.clear() del self.cache_journals[handle] except: pass return self.server.PutJournal(handle, data) else: return None def NewJournal(self, initdict={}): "Create new Journal and return Handle" if self.connected: self.cache_journalhandles.clear() return self.server.NewJournal(initdict) else: return None def DelJournal(self, handle): "Remove Journal" if self.connected: try: del self.cache_journals[handle] except: pass self.cache_journalhandles.clear() return self.server.DelJournal(handle) else: return None class CoCuMa_FileClient(CoCuMa_AbstractClient): "Ordinary Filesystem Backend" def __init__(self): CoCuMa_AbstractClient.__init__(self) def Connect(self, connect_str): "Connect to Server and start Session" try: try: import os.path from CoCuMa_Server import CoCuMa_Server # XXX: Not very nice to use '.ics': root, ext = os.path.splitext(connect_str) self.server = CoCuMa_Server(addressbook_fname = connect_str, calendar_fname = root+'.ics') self.server.SessionInit() self.connected = True except Exception, detail: self.errorstring = detail finally: return self.connected def Disconnect(self): "Disconnect from Server = Exit Session" self.server.SessionQuit() self.server = None self.connected = False def ListHandles(self, sortby): "Returns List of Handles" if self.connected: return self.server.ListHandles(sortby) else: return None def QueryAttributes(self, handles, attributes): "Returns a list of a list of attributes" if self.connected: return self.server.QueryAttributes(handles, attributes) else: return None def GetContact(self, handle): "Returns Contact in vCard Format" if self.connected: return self.server.GetContact(handle) else: return None def PutContact(self, handle, data): "Store Contact and overwrite previous one" if self.connected: return self.server.PutContact(handle, data) else: return None def NewContact(self, initdict={}): "Create new Contact and return Handle" if self.connected: return self.server.NewContact(initdict) else: return None def DelContact(self, handle): "Remove Contact" if self.connected: return self.server.DelContact(handle) else: return None def ListJournalHandles(self, sortby): "Returns List of Handles" if self.connected: return self.server.ListJournalHandles(sortby) else: return None def QueryJournalAttributes(self, handles, attributes): "Returns a list of a list of attributes" if self.connected: return self.server.QueryJournalAttributes(handles, attributes) else: return None def GetJournal(self, handle): "Returns Journal in vCard Format" if self.connected: return self.server.GetJournal(handle) else: return None def PutJournal(self, handle, data): "Store Journal and overwrite previous one" if self.connected: return self.server.PutJournal(handle, data) else: return None def NewJournal(self, initdict={}): "Create new Journal and return Handle" if self.connected: return self.server.NewJournal(initdict) else: return None def DelJournal(self, handle): "Remove Journal" if self.connected: return self.server.DelJournal(handle) else: return None def Instantiate(con_type): "Instantiate Client Object depending on Connection Type" if con_type == 'xmlrpc': return CoCuMa_XMLRPCClient() elif con_type == 'file': return CoCuMa_FileClient() else: return None