# HG changeset patch # User Sandro Knauß # Date 1256199311 -7200 # Node ID 18918fbc397c4da9140c8ba75b79f5e5262f710f # Parent a3b6e531f0d2465b0a810a87e98c2136ce5b3408 [svn r95] merged daemon-1/iro to iro-package/iro diff -r a3b6e531f0d2 -r 18918fbc397c iro/.eric4project/daemon.e4q --- 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 @@ - - - - - - - \ No newline at end of file diff -r a3b6e531f0d2 -r 18918fbc397c iro/anbieter/__init__.py --- 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ß - -#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 . - -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ß + +#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 . + +from sipgate import sipgate +from geonet import geonet +from FAX_de import FAX_de +from smtp import SMTP +from smstrade import smstrade diff -r a3b6e531f0d2 -r 18918fbc397c iro/anbieter/smstrade.py --- /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 . + + +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 diff -r a3b6e531f0d2 -r 18918fbc397c iro/iro.conf.inst --- 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 diff -r a3b6e531f0d2 -r 18918fbc397c iro/iro.py --- 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ß - -#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 . - -# 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ß + +#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 . + +# 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) + + diff -r a3b6e531f0d2 -r 18918fbc397c iro/xmlserver_test.py --- 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() - -