[svn r95] merged daemon-1/iro to iro-package/iro
authorSandro Knauß <knauss@netzguerilla.net>
Thu, 22 Oct 2009 10:15:11 +0200
changeset 1 18918fbc397c
parent 0 a3b6e531f0d2
child 2 5b7dd3bd728d
[svn r95] merged daemon-1/iro to iro-package/iro
iro/.eric4project/daemon.e4q
iro/anbieter/__init__.py
iro/anbieter/smstrade.py
iro/iro.conf.inst
iro/iro.py
iro/xmlserver_test.py
--- a/iro/.eric4project/daemon.e4q	Thu Oct 22 10:00:01 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE UserProject SYSTEM "UserProject-4.0.dtd">
-<!-- eric4 user project file for project daemon -->
-<!-- Saved: 2009-10-10, 13:26:41 -->
-<!-- Copyright (C) 2009 Sandro Knauß, bugs@sandroknauss.de -->
-<UserProject version="4.0">
-</UserProject>
\ No newline at end of file
--- a/iro/anbieter/__init__.py	Thu Oct 22 10:00:01 2009 +0200
+++ b/iro/anbieter/__init__.py	Thu Oct 22 10:15:11 2009 +0200
@@ -1,17 +1,18 @@
-# -*- coding: utf-8 -*-
-#Copyright (C) 2009  Sandro Knauß <bugs@sandroknauss.de>
-
-#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 3 of the License, or any later version.
-#This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-#without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-#See the GNU General Public License for more details.
-
-#You should have received a copy of the GNU General Public License
-#along with this program; if not, see <http://www.gnu.org/licenses/>.
-
-from sipgate import sipgate
-from geonet import geonet
-from FAX_de import FAX_de
-from smtp import SMTP
+# -*- coding: utf-8 -*-
+#Copyright (C) 2009  Sandro Knauß <bugs@sandroknauss.de>
+
+#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 3 of the License, or any later version.
+#This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+#without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#See the GNU General Public License for more details.
+
+#You should have received a copy of the GNU General Public License
+#along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from sipgate import sipgate
+from geonet import geonet
+from FAX_de import FAX_de
+from smtp import SMTP
+from smstrade import smstrade
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/iro/anbieter/smstrade.py	Thu Oct 22 10:15:11 2009 +0200
@@ -0,0 +1,143 @@
+# -*- coding: utf-8 -*-
+#Copyright (C) 2009  Georg Bischoff
+
+#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 3 of the License, or any later version.
+#This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+#without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#See the GNU General Public License for more details.
+
+#You should have received a copy of the GNU General Public License
+#along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+
+from anbieter import anbieter
+from telnumber import telnumber, NotATelNumber
+import ConfigParser
+import xmlrpclib
+import base64
+
+class smstrade(anbieter):
+	"""
+	s. auch http://kundencenter.smstrade.de/sites/smstrade.de.kundencenter/__pdf/SMS-Gateway_HTTP_API_v2.pdf
+	"""
+	section="smstrade"
+	url="https://gateway.smstrade.de"
+	def __init__(self):       
+		self.domain = "smstrade.de" # website of the sms service
+		self.gateway = "gateway.smstrade.de" # gateway where the request will be sent
+		self.gatewayPort = 80 # port of the gateway
+		self.script = "/"  # full path to the script that will handle the request
+		self.method = "POST" # method that will be used. Currently only POST is supported
+
+		self.maxMessageLength = None # maximum length of message; None if should not be set
+		self.smsCanBeSendDelayed = True # True if sms can be sent delayed by the sms service. Otherwise False
+		self.senderRe = r"^.{0,11}|[0-9]{0,15}" # RegEx for the sender-input-field
+
+		self.routes = ("basicplus", "economy", "gold", "direct") # possible routes that can be used
+		self.routesWithSourceIdentifier = ("gold", "direct") # routes where a sender can be defined
+
+# statusCodes that the sms service returns on requests
+		self.statusCodes = {10 : "Empfaengernummer nicht korrekt",
+			20 : "Absenderkennung nicht korrekt",
+			30 : "Nachrichtentext nicht korrekt",
+			31 : "Messagetyp nicht korrekt",
+			40 : "SMS Route nicht korrekt",
+			50 : "Identifikation fehlgeschlagen",
+			60 : "nicht genuegend Guthaben",
+			70 : "Netz wird von Route nicht abgedeckt",
+			71 : "Feature nicht ueber diese Route moeglich",
+			80 : "Uebergabe an SMS-C fehlgeschlagen",
+			90 : "Versand nicht moeglich",
+			100 : "SMS wurde versendet",
+			999 : "SMS wird zeitversetzt verschickt"}
+
+		self.parameters = {} # don't write anything into this dict! Don't delete it!                   
+
+	def read_basic_config(self,filename):
+		"""Read basic options from the config file"""
+		cp = ConfigParser.ConfigParser()
+		cp.read([filename])
+		self.key=cp.get(self.section, 'key')
+		self.route=cp.get(self.section, 'route')
+		self.from_=cp.get(self.section, 'from')
+		self.debug=cp.get(self.section, 'debug')
+
+def sendSMS(self,sms,recipients):
+	"""send SMS with $sms to $recipients"""
+	sended = []
+	key = self.key
+	route = unicode(self.route)
+	message = unicode(sms.content.toPlainText())
+	from_ = unicode(self.from_)
+	timestamp = None
+	for recipient in recipients:
+		try:
+			tel = telnumber(recipient)                
+			if tel in sended:                                                                           #only send message once per recipient
+				continue
+			sended.append(tel)	
+			to = unicode((tel.number)).strip()						                
+			smsSendStatus = self.__sendSms( 
+						key, route, to, message, from_, timestamp)									            
+		except (NotATelNumber,NoValidStatusCode,InternetConnectionError):
+			self.updateStatus(failed=recipient)
+
+def __send(self, key, route, to, message, from_=None, timestamp=None):
+	""" This function is the main part of the request to the sms service.    
+	The function has to return a unicode formated string that will represent the answer of the sms service
+	to the request."""
+	self.parameters["key"] = key        
+	self.parameters["route"] = route
+	self.parameters["to"] = to
+	self.parameters["message"] = message
+	self.parameters["debug"] = self.debug				
+	
+	if from_ is not None:
+		self.parameters["from"] = from_
+	else:
+		if "from" in self.parameters.keys():
+			del(self.parameters["from"])
+	
+	if timestamp is not None:
+		self.parameters["senddate"] = unicode(timestamp)
+	else:
+		if "senddate" in self.parameters.keys():
+			del(self.parameters["senddate"])
+
+	self.parameters["concat_sms"] = "1" if len(message) > 160 else "0"
+
+	params = urllib.urlencode(dict([k, v.encode('iso-8859-1')] for k, v in self.parameters.items()))
+	headers = {"Content-type": "application/x-www-form-urlencoded",
+		"Accept": "text/plain"}
+	conn = httplib.HTTPConnection("%s:%i" % (self.gateway, self.gatewayPort))
+	try:
+		conn.request(self.method, self.script, params, headers)
+		response = conn.getresponse()
+
+		data = response.read()
+	except socket.gaierror:
+		raise InternetConnectionError("%s:%i" % (self.gateway, self.gatewayPort))
+	else:
+		conn.close()
+
+	try:
+		return self.statusCodes[int(data)]
+	except ValueError:
+		# this happens if the sms will be send delayed
+		return self.statusCodes[999]
+
+def updateStatus(self, arranged=None, failed=None):
+	"""is a function that is called, if a new SMS/FAX was send
+	-arranged is non None, if SMS/FAX was sended successfully
+	-failed is non None, if SMS/FAX sending failed
+	the content will be the recipent"""
+	pass
+
+class InternetConnectionError(Exception):
+	def __init__(self, url):
+		self.url = url
+
+	def __str__(self):
+		return "InternetConnectionError: It is not possible to open 'http://%s'. Please check your connection to the Internet!" % self.url
--- a/iro/iro.conf.inst	Thu Oct 22 10:00:01 2009 +0200
+++ b/iro/iro.conf.inst	Thu Oct 22 10:15:11 2009 +0200
@@ -1,31 +1,37 @@
-[geonet]
-host = localhost
-port = 25
-send_from =
-user = 
-password =
-
-
-[FAX_de]
-host = localhost
-port = 25
-send_from = 
-user = 
-password =
-
-[sipgate]
-user = 
-password =
-
-[smtp]
-host = localhost
-port = 25
-send_from =
-user = 
-password =
-TLS=No
-SSL=No
-
-[server]
-key=
-cert=
+[geonet]
+host = localhost
+port = 25
+send_from =
+user = 
+password =
+
+
+[FAX_de]
+host = localhost
+port = 25
+send_from = 
+user = 
+password =
+
+[sipgate]
+user = 
+password =
+
+[smtp]
+host = localhost
+port = 25
+send_from =
+user = 
+password =
+TLS=No
+SSL=No
+
+[server]
+key=
+cert=
+
+[smstrade]
+key=KhqPcYybb28f2367dW73x2U
+route=basic
+debug=1
+from=antirep
--- a/iro/iro.py	Thu Oct 22 10:00:01 2009 +0200
+++ b/iro/iro.py	Thu Oct 22 10:15:11 2009 +0200
@@ -1,230 +1,247 @@
-# -*- coding: utf-8 -*-
-#Copyright (C) 2009  Sandro Knauß <bugs@sandroknauss.de>
-
-#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 3 of the License, or any later version.
-#This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-#without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-#See the GNU General Public License for more details.
-
-#You should have received a copy of the GNU General Public License
-#along with this program; if not, see <http://www.gnu.org/licenses/>.
-
-# Server code
-
-from xmlrpc import SecureUserDBXMLRPCServer,UserDB
-import time, os, md5
-from user import User, Admin
-import content
-import anbieter
-import ConfigParser
-
-class MyUserDB(UserDB):
-    def __init__(self, userlist,jobqueue):
-        UserDB.__init__(self, None,userlist,jobqueue)
-        
-    def createUser(self, user):
-        self.userlist[self.createHash(user)]=user["class"](self.jobqueue)
-
-class Job(object):
-    '''
-    Basic class for all jobs
-    '''   
-    def __init__(self,provider,name):
-        self.provider=provider
-        self.name=name
-        self.status = "init"
-        self.dStatus={"good":[], "failed":[]}
-
-    def start(self):
-        self.status = "started"
-        
-    def stop(self):
-        self.status = "stopped"
-        
-    def getStatus(self,detailed):
-        if detailed and self.status == "started" or self.status == "sended":
-            return self.status, self.dStatus
-        return self.status, {}
-    
-    def getName(self):
-        return self.name
-        
-    def getProvider(self):
-        return self.provider
-        
-    def addGood(self, good):
-        if type(good) == list:
-            self.dStatus['good']=self.dStatus['good']+good
-        else:
-            self.dStatus['good'].append(good)
-    
-    def addFailed(self, failed):
-        if type(failed) == list:
-            self.dStatus['failed']=self.dStatus['failed']+failed
-        else:
-            self.dStatus['failed'].append(failed)
-
-class MessageJob(Job):
-    '''
-    A specialized class for smsjobs
-    '''
-    def __init__(self,provider,name, message,recipients):
-        self.message=message
-        self.recipients=recipients
-        Job.__init__(self,provider, name)
-        
-    def stop(self):
-        pass
-        
-    def start(self):
-        Job.start(self)
-        self.provider.setJob(self)
-        self.message.sendto(self.provider, self.recipients)
-        self.status="sended"
-
-    def getMessage(self):
-        return self.message
-        
-    def getRecipients(self):
-        return self.recipients
- 
-
-class MySipgate(anbieter.sipgate):
-    
-    def __init__(self,user="",password="" ):
-        anbieter.sipgate.__init__(self, user, password)
-    
-    def setJob(self, job):
-        self.job=job
-    
-    def updateStatus(self, arranged=None, failed=None):
-        if arranged:
-            self.job.addGood(arranged)
-        
-        if failed:
-            self.job.addFailed(failed)
-            
-class MySMTP(anbieter.SMTP):
-    
-    def __init__(self,config_filename=None,section="smtp"):
-        anbieter.SMTP.__init__(self,config_filename,section)
-    
-    def setJob(self, job):
-        self.job=job
-    
-    def updateStatus(self, arranged=None, failed=None):
-        if arranged:
-            self.job.addGood(arranged)
-        
-        if failed:
-            self.job.addFailed(failed)
-    
-
-class Jobs:
-    '''
-    Providing an list of jobs; each new job gets a hash id
-    '''
-    def __init__(self,manager, queue,provider):
-        self.jobs={}
-        self.manager=manager
-        self.queue=queue
-        self.provider=provider
-        
-
-    def __getitem__(self,key):
-        return self.jobs[key]
-
-    def __registerJob__(self, job):
-        id = self._createID()
-        self.jobs[id]=job
-        self.queue.put(job)
-        return id
-
-    def newSMS(self,message,recipients):
-        '''
-        creates a new SMS
-        '''
-        job=self.manager.MessageJob(self.provider["sms"],message, content.SMS(message),recipients)
-        return self.__registerJob__(job)
-
-    def newFAX(self,subject, fax,recipients):
-        '''
-        creates a new Fax
-        '''
-        job=self.manager.MessageJob(self.provider["fax"],subject, content.FAX(subject, fax),recipients)
-        return self.__registerJob__(job)
-
-    def newMail(self,subject, body,recipients):
-        '''
-        creates a new Mail
-        '''
-        job=self.manager.MessageJob(self.provider["mail"],subject, content.Mail(subject, body),recipients)
-        return self.__registerJob__(job) 
-
-    def _createID(self):
-        '''
-        creats a random hash id
-        '''
-        while True:
-            m = md5.new()
-            m.update(str(time.time()))
-            m.update(os.urandom(10))
-            if not self.jobs.has_key(m.hexdigest):
-                self.jobs[m.hexdigest()]=None
-                break
-        return m.hexdigest()
-
-def start(userlist):
-    from multiprocessing import Queue
-    from multiprocessing.managers import BaseManager
-    
-    class MyManager(BaseManager):
-        pass
-    
-    MyManager.register('MessageJob', MessageJob) 
-    manager = MyManager()
-    manager.start()
-    
-    
-    #anbieter erzeugen und konfigurieren
-
-    sip=MySipgate()
-    sip.read_basic_config("iro.conf")
-    
-    localhost=MySMTP()
-    localhost.read_basic_config("iro.conf")
-    
-    #Benutzerdatenbank erstellen
-    queue = Queue()
-    provider={"sms":sip, "fax":sip, "mail":localhost}
-    jobqueue=Jobs(manager,  queue, provider)
-    userdb=MyUserDB(userlist,jobqueue)
-
-    #working thread erstellen
-    from worker import Worker
-    worker=Worker(queue)
-    worker.start()
-
-    #Server starten
-    cp = ConfigParser.ConfigParser()
-    cp.read(["iro.conf"])
-    cert=cp.get('server', 'cert')
-    key=cp.get('server', 'key')
-    server = SecureUserDBXMLRPCServer(addr=("localhost", 8000), 
-                                      userdb=userdb,
-                                      certificate=cert,privatekey=key)
-    server.relam="xmlrpc"
-    
-    print "Server started..."
-    server.serve_forever()
-    
-    worker.terminate()
-
-if __name__ == '__main__':
-    userlist=[{"name":"test","password":"test",  "class":User},
-	      {"name":"test2","password":"test2", "class": Admin}]
-    start(userlist)
-
-
+# -*- coding: utf-8 -*-
+#Copyright (C) 2009  Sandro Knauß <bugs@sandroknauss.de>
+
+#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 3 of the License, or any later version.
+#This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+#without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#See the GNU General Public License for more details.
+
+#You should have received a copy of the GNU General Public License
+#along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+# Server code
+
+from xmlrpc import SecureUserDBXMLRPCServer,UserDB
+import time, os, md5
+from user import User, Admin
+import content
+import anbieter
+import ConfigParser
+
+class MyUserDB(UserDB):
+    def __init__(self, userlist,jobqueue):
+        UserDB.__init__(self, None,userlist,jobqueue)
+        
+    def createUser(self, user):
+        self.userlist[self.createHash(user)]=user["class"](self.jobqueue)
+
+class Job(object):
+    '''
+    Basic class for all jobs
+    '''   
+    def __init__(self,provider,name):
+        self.provider=provider
+        self.name=name
+        self.status = "init"
+        self.dStatus={"good":[], "failed":[]}
+
+    def start(self):
+        self.status = "started"
+        
+    def stop(self):
+        self.status = "stopped"
+        
+    def getStatus(self,detailed):
+        if detailed and self.status == "started" or self.status == "sended":
+            return self.status, self.dStatus
+        return self.status, {}
+    
+    def getName(self):
+        return self.name
+        
+    def getProvider(self):
+        return self.provider
+        
+    def addGood(self, good):
+        if type(good) == list:
+            self.dStatus['good']=self.dStatus['good']+good
+        else:
+            self.dStatus['good'].append(good)
+    
+    def addFailed(self, failed):
+        if type(failed) == list:
+            self.dStatus['failed']=self.dStatus['failed']+failed
+        else:
+            self.dStatus['failed'].append(failed)
+
+class MessageJob(Job):
+    '''
+    A specialized class for smsjobs
+    '''
+    def __init__(self,provider,name, message,recipients):
+        self.message=message
+        self.recipients=recipients
+        Job.__init__(self,provider, name)
+        
+    def stop(self):
+        pass
+        
+    def start(self):
+        Job.start(self)
+        self.provider.setJob(self)
+        self.message.sendto(self.provider, self.recipients)
+        self.status="sended"
+
+    def getMessage(self):
+        return self.message
+        
+    def getRecipients(self):
+        return self.recipients
+ 
+
+class MySipgate(anbieter.sipgate):
+    
+    def __init__(self,user="",password="" ):
+        anbieter.sipgate.__init__(self, user, password)
+    
+    def setJob(self, job):
+        self.job=job
+    
+    def updateStatus(self, arranged=None, failed=None):
+        if arranged:
+            self.job.addGood(arranged)
+        
+        if failed:
+            self.job.addFailed(failed)
+            
+class MySMTP(anbieter.SMTP):
+    
+    def __init__(self,config_filename=None,section="smtp"):
+        anbieter.SMTP.__init__(self,config_filename,section)
+    
+    def setJob(self, job):
+        self.job=job
+    
+    def updateStatus(self, arranged=None, failed=None):
+        if arranged:
+            self.job.addGood(arranged)
+        
+        if failed:
+            self.job.addFailed(failed)
+    
+class MySmstrade(anbieter.smstrade):
+    
+    def __init__(self ):
+        anbieter.smstrade.__init__(self )
+    
+    def setJob(self, job):
+        self.job=job
+    
+    def updateStatus(self, arranged=None, failed=None):
+        if arranged:
+            self.job.addGood(arranged)
+        
+        if failed:
+            self.job.addFailed(failed)
+						
+class Jobs:
+    '''
+    Providing an list of jobs; each new job gets a hash id
+    '''
+    def __init__(self,manager, queue,provider):
+        self.jobs={}
+        self.manager=manager
+        self.queue=queue
+        self.provider=provider
+        
+
+    def __getitem__(self,key):
+        return self.jobs[key]
+
+    def __registerJob__(self, job):
+        id = self._createID()
+        self.jobs[id]=job
+        self.queue.put(job)
+        return id
+
+    def newSMS(self,message,recipients):
+        '''
+        creates a new SMS
+        '''
+        job=self.manager.MessageJob(self.provider["sms"],message, content.SMS(message),recipients)
+        return self.__registerJob__(job)
+
+    def newFAX(self,subject, fax,recipients):
+        '''
+        creates a new Fax
+        '''
+        job=self.manager.MessageJob(self.provider["fax"],subject, content.FAX(subject, fax),recipients)
+        return self.__registerJob__(job)
+
+    def newMail(self,subject, body,recipients):
+        '''
+        creates a new Mail
+        '''
+        job=self.manager.MessageJob(self.provider["mail"],subject, content.Mail(subject, body),recipients)
+        return self.__registerJob__(job) 
+
+    def _createID(self):
+        '''
+        creats a random hash id
+        '''
+        while True:
+            m = md5.new()
+            m.update(str(time.time()))
+            m.update(os.urandom(10))
+            if not self.jobs.has_key(m.hexdigest):
+                self.jobs[m.hexdigest()]=None
+                break
+        return m.hexdigest()
+
+def start(userlist):
+    from multiprocessing import Queue
+    from multiprocessing.managers import BaseManager
+    
+    class MyManager(BaseManager):
+        pass
+    
+    MyManager.register('MessageJob', MessageJob) 
+    manager = MyManager()
+    manager.start()
+    
+    
+    #anbieter erzeugen und konfigurieren
+
+    sip=MySipgate()
+    sip.read_basic_config("iro.conf")
+    
+    localhost=MySMTP()
+    localhost.read_basic_config("iro.conf")
+
+    smstrade=MySmstrade()
+    smstrade.read_basic_config("iro.conf")
+    
+    #Benutzerdatenbank erstellen
+    queue = Queue()
+    provider={"sms":sip, "fax":sip, "mail":localhost}
+    jobqueue=Jobs(manager,  queue, provider)
+    userdb=MyUserDB(userlist,jobqueue)
+
+    #working thread erstellen
+    from worker import Worker
+    worker=Worker(queue)
+    worker.start()
+
+    #Server starten
+    cp = ConfigParser.ConfigParser()
+    cp.read(["iro.conf"])
+    cert=cp.get('server', 'cert')
+    key=cp.get('server', 'key')
+    server = SecureUserDBXMLRPCServer(addr=("localhost", 8000), 
+                                      userdb=userdb,
+                                      certificate=cert,privatekey=key)
+    server.relam="xmlrpc"
+    
+    print "Server started..."
+    server.serve_forever()
+    
+    worker.terminate()
+
+if __name__ == '__main__':
+    userlist=[{"name":"test","password":"test",  "class":User},
+	      {"name":"test2","password":"test2", "class": Admin}]
+    start(userlist)
+
+
--- a/iro/xmlserver_test.py	Thu Oct 22 10:00:01 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-# Server code
-
-from xmlrpc import SecureXMLRPCServer,SecureAuthentificateXMLRPCRequestHandler
-import md5, time, os
-
-class Job:
-    def __init__(self,provider,name):
-        self.provider=provider
-        self.name=name
-        self.status="stopped"
-
-    def start(self):
-        self.status="started"
-
-    def stop(self):
-        self.status="stopped"
-
-class SMSJob(Job):
-    def __init__(self,provider,message,recipients):
-        self.message=message
-        self.recipients=recipients
-        Job.__init__(self,provider,message)
-
-class Jobs:
-    def __init__(self,queue,provider):
-        self.jobs={}
-        self.queue=queue
-        self.provider=provider
-
-    def __getitem__(self,key):
-        return self.jobs[key]
-
-    def newSMS(self,message,recipients):
-        job=SMSJob(self.provider,message,recipients)
-        id = self._createID()
-        self.jobs[id]=job
-        #self.queue.put(job)
-        return id
-
-    def _createID(self):
-        while True:
-            m = md5.new()
-            m.update(str(time.time()))
-            m.update(os.urandom(10))
-            if not self.jobs.has_key(m.hexdigest):
-                self.jobs[m.hexdigest()]=None
-                break
-        return m.hexdigest()
-
-
-class User: 
-    def __init__(self,jobqueue):
-        self.jobqueue=jobqueue
-        self.jobs={}
-
-    def status(self,id=None):
-        if id==None:
-            jobs=self.jobs
-        else:
-            try:
-                jobs={id:self.jobs[id]}
-            except:
-                raise String("No Job with ID: %i" %(id))
-        ret={}
-        for key in jobs:
-            job=jobs[key]
-            ret[key]={"name":job.name,"status":job.status}
-        return ret
-
-    def stop(self,id):
-        try:
-            job=self.jobs[id]
-        except:
-            raise String("No Job with ID: %i" %(id))
-
-        job.stop()
-
-    
-    def startSMS(self,message,recipients):
-        id = self.jobqueue.newSMS(message,recipients)
-        self.jobs[id]=self.jobqueue[id]
-        return id
-
-class UserDB:
-    def __init__(self,userlist,jobqueue):
-        self.salt=os.urandom(20)
-        self.jobqueue=jobqueue
-        self.userlist={}
-        for user in userlist:
-            self.createUser(user)
-
-    def createHash(self,username,password):
-        m=md5.new()
-        m.update(self.salt)
-        m.update(username)
-        m.update(password)
-        return m.hexdigest()
-
-    def createUser(self,user):
-        self.userlist[self.createHash(user.username,user.password)]=User(self.jobqueue)
-
-    def __getitem__(self,key):
-        return self.userlist[key]
-
-    
-class SecureAuthentificateXMLRPCRequestHandler2(SecureAuthentificateXMLRPCRequestHandler):
-
-    def testUser(self,username,password):
-        return self.server.activateUser(username,password)
-
-class SecureUserDBXMLRPCServer(SecureXMLRPCServer):
-    def __init__(self, addr, userdb, 
-                 requestHandler=SecureAuthentificateXMLRPCRequestHandler2,
-                 certificate="server.cert", privatekey="server.pem",
-                 logRequests=1):
-        SecureXMLRPCServer.__init__(self, addr, requestHandler, certificate, privatekey, logRequests)
-        self.userdb=userdb
-
-    def activateUser(self,username,password):
-        try:
-            user = self.userdb[self.userdb.createHash(username,password)]
-            self.register_instance(user)
-            return True
-        except KeyError:
-            return False
-        
-
-
-def test():
-    server = SecureXMLRPCServer(("localhost", 8000),requestHandler=SecureAuthentificateXMLRPCRequestHandler,certificate="./certs/test.cert.pem",privatekey="./certs/test.key.pem")
-    server.register_introspection_functions()
-    server.register_instance(StringFunctions())
-    server.register_function(lambda x: x*x, 'square')
-    server.serve_forever()
-
-if __name__ == '__main__':
-    test()
-
-