# HG changeset patch # User Sandro Knauß # Date 1256198401 -7200 # Node ID a3b6e531f0d2465b0a810a87e98c2136ce5b3408 [svn r93] creating iro package branch diff -r 000000000000 -r a3b6e531f0d2 iro/.eric4project/daemon.e4q --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/.eric4project/daemon.e4q Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff -r 000000000000 -r a3b6e531f0d2 iro/.eric4project/iro.e4p --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/.eric4project/iro.e4p Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,7 @@ + + + + + + + diff -r 000000000000 -r a3b6e531f0d2 iro/.eric4project/iro.e4t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/.eric4project/iro.e4t Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff -r 000000000000 -r a3b6e531f0d2 iro/MyIro_daemon --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/MyIro_daemon Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,44 @@ +#! /bin/sh +NAME="IRO" +DEAMON=/home/sandy/svn/daemon/MyIro +DEAMON_OPTS="" +PID=/home/sandy/var/run/$NAME.pid + +test -x $DEAMON || exit 0 + +. /lib/lsb/init-functions + +case "$1" in + start) + log_daemon_msg "Starting $NAME" $NAME + if start-stop-daemon --start --quiet --oknodo --pidfile $PID --make-pidfile --background --chuid sandy --group sandy --chdir /home/sandy/svn/iro --startas $DEAMON -- $DEAMON_OPTS; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + stop) + log_daemon_msg "Stopping $NAME" $NAME + if start-stop-daemon --stop --quiet --oknodo --pidfile $PID; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + + restart) + $0 stop + sleep 1 + $0 start + ;; + + status) + status_of_proc -p $PID $DEAMON $NAME && exit 0 || exit $? + ;; + + *) + log_action_msg "Usage: $0 {start|stop|restart|status}" + exit 1 +esac + +exit 0 diff -r 000000000000 -r a3b6e531f0d2 iro/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/__init__.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,1 @@ + diff -r 000000000000 -r a3b6e531f0d2 iro/anbieter/FAX_de.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/anbieter/FAX_de.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,31 @@ +# -*- 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 smtp import SMTP +from geonet import geonet +from telnumber import telnumber + +class FAX_de(geonet): + section="FAX_de" + default_conf="iro.conf" + max_recipients=50 + + def __init__(self): + self.smtp=SMTP(self.default_conf,self.section) + + def createMailaddress(produkt,number): + try: + tel=telnumber(number) + return "%s00%s%s@fax.de" %(produkt,tel.land,tel.number) + except: + return number diff -r 000000000000 -r a3b6e531f0d2 iro/anbieter/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/anbieter/__init__.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,17 @@ +# -*- 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 diff -r 000000000000 -r a3b6e531f0d2 iro/anbieter/anbieter.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/anbieter/anbieter.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,34 @@ +# -*- 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 . + +class anbieter: + default_conf = '' # override this + section = 'anbieter' # override this + + def sendSMS(self,sms,recipients): + pass + def sendFAX(self,fax,recipients): + pass + def sendMail(self,mail,recipients): + pass + + + + + + + + + + + diff -r 000000000000 -r a3b6e531f0d2 iro/anbieter/geonet.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/anbieter/geonet.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,61 @@ +# -*- 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 smtp import SMTP +from anbieter import anbieter +from telnumber import telnumber + +from email import Encoders +from email.MIMEMultipart import MIMEMultipart +from email.MIMEBase import MIMEBase +from email.MIMEText import MIMEText + +class Mail(MIMEMultipart): + def __init__(self,send_from,header,cont,attachments): + MIMEMultipart.__init__(self) + self['From'] = send_from + self['Subject']=header + self.attach(MIMEText(cont)) + for attachment in attachments: + part = MIMEBase('application', mimetypes.guess_type(attachment)[0]) + part.set_payload( open(attachment,"rb").read() ) + Encoders.encode_base64(part) + art.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f)) + self.attach(part) + +class geonet(anbieter): + section="geonet" + default_conf="iro.conf" + max_recipients=50 + + def __init__(self): + self.smtp=SMTP(self.default_conf,self.section) + + def createMailaddress(produkt,number): + try: + tel=telnum(number) + return "%s%s@%s.geonet.de" %(tel.land,tel.number,produkt) + except: + return number + + def sendSMS(self,sms,recipients): + recps=[] + for recpipient in recipients: + recps.append(self.createMailadress(recpipient)) + self.sendMail(Mail(self.smtp.send_from,sms.content,"",[]),recps) + + def sendFAX(self,fax,recipients): + recps=[] + for recpipient in recipients: + recps.append(self.createMailadress(recpipient)) + self.sendMail(Mail(self.smtp.send_from,"","",fax.attachments),recps) diff -r 000000000000 -r a3b6e531f0d2 iro/anbieter/sipgate.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/anbieter/sipgate.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,140 @@ +# -*- 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 anbieter import anbieter +from telnumber import telnumber, NotATelNumber +import ConfigParser +import xmlrpclib +import base64 + +class NoValidStatusCode(Exception): + pass + +class sipgate(anbieter): + """ + s. auch http://www.tuxad.com/sipgate.html + und http://lists.sipgate.net/pipermail/sipgate-developers/2007-September/000016.html + """ + section="sipgate" + url="https://%s:%s@samurai.sipgate.net/RPC2" + def __init__(self,user="",password=""): + self.user=user + self.password=password + + def read_basic_config(self,filename): + """Read basic options from the config file""" + cp = ConfigParser.ConfigParser() + cp.read([filename]) + self.user=cp.get(self.section, 'user') + self.password=cp.get(self.section, 'password') + + def sendSMS(self,sms,recipients): + """send SMS with $sms to $recipients""" + args={ + "TOS" : "text", + "Content" : sms.content + } + self.__send(args,recipients) + + def sendFAX(self,fax,recipients): + """send the PDF file $fax to $recipients""" + pdf=open(fax.attachments[0],"rb") + args={ + "TOS" : "fax", + "Content" : base64.encodestring(pdf.read()) + } + pdf.close() + self.__send(args,recipients) + + def __connect(self): + """connect to sipgate XMLRPC Server""" + self.samurai=xmlrpclib.Server(self.url%(self.user,self.password)).samurai + args_identify = { + "ClientName" : "anbieter.py", + "ClientVersion" : "V1.0", + "ClientVendor" : "Sandro Knauss" + } + + self.__send_method(self.samurai.ClientIdentify, args_identify) + + def __send_method(self, func, args=None): + """execute $func and test weather if the func ran successfully or not""" + if args==None: + xmlrpc_result = func() + else: + xmlrpc_result = func(args) + if xmlrpc_result['StatusCode'] != 200: + raise NoValidStatusCode("There was an error during identification to the server! %d %s"% (xmlrpc_result['StatusCode'], xmlrpc_result['StatusString'])) + + return xmlrpc_result + + def __send(self,args,recipients): + """main sending method - sending the args to $recipients""" + sended=[] + self.__connect() + for recipient in recipients: + try: + tel = telnumber(recipient) + + if tel in sended: #only send message once per recipient + continue + sended.append(tel) + + args["RemoteUri"]="sip:%s%s@sipgate.net"%(tel.land,tel.number) + xmlrpc_result = self.__send_method(self.samurai.SessionInitiate, args) + self.updateStatus(arranged=recipient) + except NotATelNumber,NoValidStatusCode : + self.updateStatus(failed=recipient) + + self.__disconnect() + + 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 + + def BalanceGet(self): + """get the balance of sipgate""" + self.__connect() + ret = self.__send_method(self.samurai.BalanceGet ) + self.__disconnect() + return ret['CurrentBalance'] + + def getNewMessages(self): + """get new messages from inbox""" + self.__connect() + tmp = self.__send_method(self.samurai.UmSummaryGet) + self.__disconnect() + tmp=tmp['UmSummary'] + ret={} + for entry in tmp: + ret[entry['TOS']]={'read':entry["Read"],'unread':entry["Unread"]} + return ret + + def getRecommendedInterval(self,methods): + """how often you can call one $methods""" + self.__connect() + args = {"MethodList" : methods } + tmp = self.__send_method(self.samurai.RecommendedIntervalGet, args) + self. __disconnect() + ret={} + for entry in tmp['IntervalList']: + ret[entry['MethodName']]=entry['RecommendedInterval'] + return ret + + def __disconnect(self): + """disconnect xmlrpc client""" + self.xmlrpc=None diff -r 000000000000 -r a3b6e531f0d2 iro/anbieter/smtp.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/anbieter/smtp.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,94 @@ +# -*- 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 . + +class anbieter: + default_conf = '' # override this +import smtplib +import ConfigParser + + +class SMTP(): + def __init__(self,config_filename=None,section="smtp"): + self.config_filename=config_filename + self.section=section + self.bStart=False + self.bTLS=False + self.bSSL=False + self.max_recipients=1 + + def read_basic_config(self,config_filename=None): + """Read basic options from the config file""" + if not (config_filename is None): + self.config_filename=config_filename + + cp = ConfigParser.ConfigParser() + cp.read([self.config_filename]) + self.config_parser = cp + self.send_from=cp.get(self.section, 'send_from') + self.host=cp.get(self.section, 'host') + self.port=cp.get(self.section, 'port') + self.user=cp.get(self.section, 'user') + self.pw=cp.get(self.section, 'password') + + try: + self.bTLS=cp.getboolean(self.section, 'TLS') + except ValueError: + self.bTLS=False + + try: + self.bSSL=cp.getboolean(self.section, 'SSL') + except ValueError: + self.bSSL=False + + + def prepareSMTP(self): + if self.bSSL: + self.smtp = smtplib.SMTP_SSL(self.host,self.port) + else: + self.smtp = smtplib.SMTP(self.host,self.port) + + if self.bTLS: + self.smtp.starttls() + + if not self.user == "": + self.smtp.login(self.user,self.pw) + + self.bStart=True + + def sendMail(self,mail,recipients): + if not self.bStart: + self.prepareSMTP() + + mail.content['From']=self.send_from + while len(recipients) > 0: + tmp_recipients=recipients[:self.max_recipients] + print tmp_recipients + self.smtp.sendmail(self.send_from, tmp_recipients, mail.as_string()) + self.updateStatus( arranged=tmp_recipients) + recipients = recipients[self.max_recipients:] + + self.smtp.shutdownSMTP() + + + 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 + + def shutdownSMTP(self): + self.smtp.quit() + self.bStart=False + + diff -r 000000000000 -r a3b6e531f0d2 iro/anbieter/telnumber.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/anbieter/telnumber.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,59 @@ +# -*- 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 . + +class anbieter: + default_conf = '' # override this +import re + +class NotATelNumber(Exception): + def __init__(self, number): + self.number= number + + def __str__(self): + return ("This is not a telefonnumber:", selfnumber) + +class telnumber: + re_telnum=re.compile(r'^\s*(\+)?([0-9\s\-/\(\)])+\s*$') + re_land=re.compile(r'^\s*(\+|00)(?P[1-9]{2})') + re_number=re.compile(r'[^0-9]') + std_land="49" + + def __init__(self,number=None): + if not(number is None): + self.createNumber(number) + + def createNumber(self, number): + + if not self.re_telnum.match(number): + raise NotATelNumber(number) + + + self.land=self.std_land + land=self.re_land.match(number) + + if not(land is None): + self.land=land.group("land") + number=number[land.end("land"):] + + number=self.re_number.sub('',number) + + if number[0]=="0": + number=number[1:] + + self.number = number + + def __eq__(self, y): + return ((self.number == y.number) and ( self.land == y.land)) + + def __ne__(self, y): + return not self.__eq__(y) diff -r 000000000000 -r a3b6e531f0d2 iro/anbieter/test.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/anbieter/test.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,59 @@ +# -*- 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 . + +class anbieter: + default_conf = '' # override this + +import unittest +import telnumber as tn + +class TestTelnumber(unittest.TestCase): + def equalNumber(self, tel1, tel2): + self.assertEqual(tel1.number, tel2.number) + self.assertEqual(tel1.land, tel2.land) + + def testWrongNumber(self): + telnum=tn.telnumber() + self.assertRaises(tn.NotATelNumber, telnum.createNumber, "hallo") + self.assertRaises(tn.NotATelNumber, telnum.createNumber, "0?242") + + + def testNumber(self): + telnum=tn.telnumber("0551-28293640") + telnum2=tn.telnumber("+49551/28293640") + telnum3=tn.telnumber("00495512829364-0") + telnum4=tn.telnumber("+49(0)551-28293640") + + self.assertEqual(telnum.land, "49") + self.assertEqual(telnum.number, "55128293640") + + self.equalNumber(telnum, telnum2) + self.equalNumber(telnum, telnum3) + self.equalNumber(telnum, telnum4) + + def testEqual(self): + telnum=tn.telnumber("0551-28293640") + telnum2=tn.telnumber("+49551/28293640") + li=[] + self.assertEqual(telnum == telnum2, True) + self.assertEqual(telnum <> telnum2, False) + self.assertEqual(telnum, telnum2) + self.assertEqual(telnum in li,False) + li.append(telnum) + self.assertEqual(telnum in li,True) + self.assertEqual(telnum in li,True) + +if __name__ == "__main__": + unittest.main() + + diff -r 000000000000 -r a3b6e531f0d2 iro/content.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/content.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,50 @@ +# -*- 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 email.mime.text import MIMEText + +class content: + def __init__(self,content): + self.content=content + + def sendto(self,anbieter,recipients): + pass + +class SMS(content): + def __init__(self,cont): + content.__init__(self,cont) + + def sendto(self,anbieter,recipients): + anbieter.sendSMS(self,recipients) + +class FAX(content): + def __init__(self,header,cont,attachments): + content.__init__(self,cont) + self.header=header + self.attachments=attachments + + def sendto(self,anbieter,recipients): + anbieter.sendFAX(self,recipients) + +class Mail(content): + def __init__(self, subject, body): + con=MIMEText(body) + con['Subject']=subject + content.__init__(self, con) + + def sendto(self,anbieter,recipients): + anbieter.sendMail(self,recipients) + + def as_string(self): + return self.content.as_string() + diff -r 000000000000 -r a3b6e531f0d2 iro/iro.api --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/iro.api Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,162 @@ +iro.anbieter.FAX_de.FAX_de.createMailaddress?4(number) +iro.anbieter.FAX_de.FAX_de.default_conf?7 +iro.anbieter.FAX_de.FAX_de.max_recipients?7 +iro.anbieter.FAX_de.FAX_de.section?7 +iro.anbieter.FAX_de.FAX_de?1() +iro.anbieter.anbieter.anbieter.default_conf?7 +iro.anbieter.anbieter.anbieter.section?7 +iro.anbieter.anbieter.anbieter.sendFAX?4(fax, recipients) +iro.anbieter.anbieter.anbieter.sendMail?4(mail, recipients) +iro.anbieter.anbieter.anbieter.sendSMS?4(sms, recipients) +iro.anbieter.geonet.Mail?1(send_from, header, cont, attachments) +iro.anbieter.geonet.geonet.createMailaddress?4(number) +iro.anbieter.geonet.geonet.default_conf?7 +iro.anbieter.geonet.geonet.max_recipients?7 +iro.anbieter.geonet.geonet.section?7 +iro.anbieter.geonet.geonet.sendFAX?4(fax, recipients) +iro.anbieter.geonet.geonet.sendMail?4(mail, recipients) +iro.anbieter.geonet.geonet.sendSMS?4(sms, recipients) +iro.anbieter.geonet.geonet?1() +iro.anbieter.sipgate.sipgate.BalanceGet?4() +iro.anbieter.sipgate.sipgate.__connect?6() +iro.anbieter.sipgate.sipgate.__disconnect?6() +iro.anbieter.sipgate.sipgate.__send?6(args, recipients) +iro.anbieter.sipgate.sipgate.__send_method?6(func, args=None) +iro.anbieter.sipgate.sipgate.getNewMessages?4() +iro.anbieter.sipgate.sipgate.getRecommendedInterval?4(methods) +iro.anbieter.sipgate.sipgate.read_basic_config?4(filename) +iro.anbieter.sipgate.sipgate.section?7 +iro.anbieter.sipgate.sipgate.sendFAX?4(fax, recipients) +iro.anbieter.sipgate.sipgate.sendSMS?4(sms, recipients) +iro.anbieter.sipgate.sipgate.updateStatus?4(arranged=None, failed=None) +iro.anbieter.sipgate.sipgate.url?7 +iro.anbieter.sipgate.sipgate?1(user="", password="") +iro.anbieter.smtp.SMTP.prepareSMTP?4() +iro.anbieter.smtp.SMTP.read_basic_config?4() +iro.anbieter.smtp.SMTP.sendMail?4(mail, recipients) +iro.anbieter.smtp.SMTP.shutdownSMTP?4() +iro.anbieter.smtp.SMTP?1(config_filename, section) +iro.anbieter.smtp.anbieter.default_conf?7 +iro.anbieter.telnumber.NotATelNumber.__str__?6() +iro.anbieter.telnumber.NotATelNumber?1(number) +iro.anbieter.telnumber.anbieter.default_conf?7 +iro.anbieter.telnumber.telnumber.__eq__?6(y) +iro.anbieter.telnumber.telnumber.__ne__?6(y) +iro.anbieter.telnumber.telnumber.createNumber?4(number) +iro.anbieter.telnumber.telnumber.re_land?7 +iro.anbieter.telnumber.telnumber.re_number?7 +iro.anbieter.telnumber.telnumber.re_telnum?7 +iro.anbieter.telnumber.telnumber.std_land?7 +iro.anbieter.telnumber.telnumber?1(number=None) +iro.anbieter.test.TestTelnumber.equalNumber?4(tel1, tel2) +iro.anbieter.test.TestTelnumber.testEqual?4() +iro.anbieter.test.TestTelnumber.testNumber?4() +iro.anbieter.test.TestTelnumber.testWrongNumber?4() +iro.anbieter.test.anbieter.default_conf?7 +iro.content.FAX.sendto?4(anbieter, recipients) +iro.content.FAX?1(header, cont, attachments) +iro.content.SMS.sendto?4(anbieter, recipients) +iro.content.SMS?1(cont) +iro.content.content.sendto?4(anbieter, recipients) +iro.content.content?1(content) +iro.iro.Job.addFailed?4(failed) +iro.iro.Job.addGood?4(good) +iro.iro.Job.getName?4() +iro.iro.Job.getProvider?4() +iro.iro.Job.getStatus?4(detailed) +iro.iro.Job.start?4() +iro.iro.Job.stop?4() +iro.iro.Job?1(provider, name) +iro.iro.Jobs.__getitem__?6(key) +iro.iro.Jobs.__registerJob__?6(job) +iro.iro.Jobs._createID?5() +iro.iro.Jobs.newFAX?4(subject, fax, recipients) +iro.iro.Jobs.newMail?4(subject, body, recipients) +iro.iro.Jobs.newSMS?4(message, recipients) +iro.iro.Jobs?1(manager, queue, provider) +iro.iro.MessageJob.getMessage?4() +iro.iro.MessageJob.getRecipients?4() +iro.iro.MessageJob.start?4() +iro.iro.MessageJob.stop?4() +iro.iro.MessageJob?1(provider, message, recipients) +iro.iro.MyManager.certificate?7 +iro.iro.MyManager.userdb?7 +iro.iro.MySipgate.setJob?4(job) +iro.iro.MySipgate.updateStatus?4(arranged=None, failed=None) +iro.iro.MySipgate?1(user="", password="") +iro.iro.MyUserDB.createUser?4(user) +iro.iro.MyUserDB?1(userlist, jobqueue) +iro.iro.start?4(userlist) +iro.test.MyManager.certificate?7 +iro.test.MyManager.userdb?7 +iro.test.StoppableXMLRPCServer.run?4() +iro.test.StoppableXMLRPCServer.running?7 +iro.test.StoppableXMLRPCServer.stop?4() +iro.test.StoppableXMLRPCServer?1(*args, **kwargs) +iro.test.TestServer.admin?7 +iro.test.TestServer.client1?7 +iro.test.TestServer.client2?7 +iro.test.TestServer.client?7 +iro.test.TestServer.id1?7 +iro.test.TestServer.id2?7 +iro.test.TestServer.id?7 +iro.test.TestServer.servstr?7 +iro.test.TestServer.setUp?4() +iro.test.TestServer.tearDown?4() +iro.test.TestServer.testLogin?4() +iro.test.TestServer.testTwoUser?4() +iro.test.TestServer.testsendSMS?4() +iro.test.TestServer.u1?7 +iro.test.TestServer.u2?7 +iro.test.init_server?4() +iro.user.Admin?1(jobqueue) +iro.user.User.startMail?4(subject, body, recipients) +iro.user.User.startSMS?4(message, recipients) +iro.user.User.status?4(id=None, detailed=False) +iro.user.User.stop?4(id) +iro.user.User?1(jobqueue) +iro.worker.Worker.run?4() +iro.worker.Worker?1(queue) +iro.xmlrpc.AuthentificateXMLRPCServer.AuthentificateXMLRPCRequestHandler.do_POST?4() +iro.xmlrpc.AuthentificateXMLRPCServer.AuthentificateXMLRPCRequestHandler.report_401?4() +iro.xmlrpc.AuthentificateXMLRPCServer.AuthentificateXMLRPCRequestHandler.report_error?4(code) +iro.xmlrpc.AuthentificateXMLRPCServer.AuthentificateXMLRPCRequestHandler.testUser?4(username, password) +iro.xmlrpc.AuthentificateXMLRPCServer.test?4() +iro.xmlrpc.SecureAuthentificateXMLRPCServer.SecureAuthentificateXMLRPCRequestHandler.do_POST?4() +iro.xmlrpc.SecureAuthentificateXMLRPCServer.test?4() +iro.xmlrpc.SecureUserdbXMLRPCServer.SecureAuthentificateXMLRPCRequestHandler2.testUser?4(username, password) +iro.xmlrpc.SecureUserdbXMLRPCServer.SecureUserDBXMLRPCServer.activateUser?4(username, password) +iro.xmlrpc.SecureUserdbXMLRPCServer.SecureUserDBXMLRPCServer?1(addr, userdb, requestHandler=SecureAuthentificateXMLRPCRequestHandler2, certificate="server.cert", privatekey="server.pem", logRequests=1) +iro.xmlrpc.SecureUserdbXMLRPCServer.UserDB.__getitem__?6(key) +iro.xmlrpc.SecureUserdbXMLRPCServer.UserDB.createHash?4(user) +iro.xmlrpc.SecureUserdbXMLRPCServer.UserDB.createUser?4(user) +iro.xmlrpc.SecureUserdbXMLRPCServer.UserDB?1(userClass, userlist, jobqueue) +iro.xmlrpc.SecureXMLRPCServer.SSLWrapper.__getattr__?6(name) +iro.xmlrpc.SecureXMLRPCServer.SSLWrapper.__setattr__?6(name, value) +iro.xmlrpc.SecureXMLRPCServer.SSLWrapper.accept?4() +iro.xmlrpc.SecureXMLRPCServer.SSLWrapper.shutdown?4(how=1) +iro.xmlrpc.SecureXMLRPCServer.SSLWrapper?1(conn) +iro.xmlrpc.SecureXMLRPCServer.SecureTCPServer?1(server_address, RequestHandlerClass, certificate, privatekey) +iro.xmlrpc.SecureXMLRPCServer.SecureXMLRPCRequestHandler.setup?4() +iro.xmlrpc.SecureXMLRPCServer.SecureXMLRPCServer?1(addr, requestHandler=SecureXMLRPCRequestHandler, certificate="server.cert", privatekey="server.pem", logRequests=1) +iro.xmlrpc.SecureXMLRPCServer.test?4() +iro.xmlserver_test.Job.start?4() +iro.xmlserver_test.Job.stop?4() +iro.xmlserver_test.Job?1(provider, name) +iro.xmlserver_test.Jobs.__getitem__?6(key) +iro.xmlserver_test.Jobs._createID?5() +iro.xmlserver_test.Jobs.newSMS?4(message, recipients) +iro.xmlserver_test.Jobs?1(queue, provider) +iro.xmlserver_test.SMSJob?1(provider, message, recipients) +iro.xmlserver_test.SecureAuthentificateXMLRPCRequestHandler2.testUser?4(username, password) +iro.xmlserver_test.SecureUserDBXMLRPCServer.activateUser?4(username, password) +iro.xmlserver_test.SecureUserDBXMLRPCServer?1(addr, userdb, requestHandler=SecureAuthentificateXMLRPCRequestHandler2, certificate="server.cert", privatekey="server.pem", logRequests=1) +iro.xmlserver_test.User.startSMS?4(message, recipients) +iro.xmlserver_test.User.status?4(id=None) +iro.xmlserver_test.User.stop?4(id) +iro.xmlserver_test.User?1(jobqueue) +iro.xmlserver_test.UserDB.__getitem__?6(key) +iro.xmlserver_test.UserDB.createHash?4(username, password) +iro.xmlserver_test.UserDB.createUser?4(user) +iro.xmlserver_test.UserDB?1(userlist, jobqueue) +iro.xmlserver_test.test?4() \ No newline at end of file diff -r 000000000000 -r a3b6e531f0d2 iro/iro.conf.inst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/iro.conf.inst Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,31 @@ +[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= diff -r 000000000000 -r a3b6e531f0d2 iro/iro.e4p --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/iro.e4p Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,220 @@ + + + + + + + + Python + Console + Ein Daemon zum Senden von Massensms, -faxen und emails + 0.1 + Sandro Knauß + bugs@sandroknauss.de + + iro.py + content.py + __init__.py + xmlrpc/SecureXMLRPCServer.py + xmlrpc/__init__.py + xmlrpc/SecureAuthentificateXMLRPCServer.py + xmlrpc/AuthentificateXMLRPCServer.py + xmlserver_test.py + anbieter/smtp.py + anbieter/geonet.py + anbieter/__init__.py + anbieter/FAX_de.py + anbieter/sipgate.py + anbieter/anbieter.py + xmlrpc/SecureUserdbXMLRPCServer.py + worker.py + user.py + anbieter/telnumber.py + anbieter/test.py + test.py + + + + + + + + + + + iro.conf.inst + + iro.py + + Subversion + + + + add + + + + + + + + checkout + + + + + + + + commit + + + + + + + + diff + + + + + + + + export + + + + + + + + global + + + + + + + + history + + + + + + + + log + + + + + + + + remove + + + + + + + + status + + + + + + + + tag + + + + + + + + update + + + + + + + + + + + + standardLayout + + + True + + + + + + + + + + + + + + + ERIC4API + + + + + basePackage + + + iro + + + ignoreFilePatterns + + + + + + + + includePrivate + + + True + + + languages + + + + Python + + + + outputFile + + + iro.api + + + useRecursion + + + True + + + + + + + \ No newline at end of file diff -r 000000000000 -r a3b6e531f0d2 iro/iro.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/iro.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,230 @@ +# -*- 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) + + diff -r 000000000000 -r a3b6e531f0d2 iro/merlin --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/merlin Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,25 @@ +#!/bin/bash +# +# merlin commando +# +# eine überprüfung auf korrekten aufruf findet nicht statt +# +# beispiel: +# +# ./merlin ./arthur +# +# startet programm arthur und wenn er stirbt, wird er sofort +# wiederbelebt. +# harmlose magie halt... :-) +# +LOG=/home/sandy/var/log/merlin_Iro.log +while : ; do + echo -n "$(date +'%F %T %Z') " >> $LOG + $1 status >> $LOG + if [ $? -eq 1 ]; then + echo $(date +'%F %T %Z') $1 neustarten >> $LOG + $1 start >> $LOG + fi + sleep 60 +done + diff -r 000000000000 -r a3b6e531f0d2 iro/merlin_daemon --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/merlin_daemon Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,44 @@ +#! /bin/sh +NAME="merlin" +DEAMON=/home/sandy/svn/daemon/$NAME +DEAMON_OPTS="/home/sandy/svn/iro/MyIro_daemon" +PID=/home/sandy/var/run/$NAME.pid + +test -x $DEAMON || exit 0 + +. /lib/lsb/init-functions + +case "$1" in + start) + log_daemon_msg "Starting $NAME server" $NAME + if start-stop-daemon --start --quiet --oknodo --pidfile $PID --make-pidfile --background --startas $DEAMON -- $DEAMON_OPTS; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + stop) + log_daemon_msg "Stopping $NAME server" $NAME + if start-stop-daemon --stop --quiet --oknodo --pidfile $PID; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + + restart) + $0 stop + sleep 1 + $0 start + ;; + + status) + status_of_proc -p $PID $DEAMON $NAME && exit 0 || exit $? + ;; + + *) + log_action_msg "Usage: $0 {start|stop|restart|status}" + exit 1 +esac + +exit 0 diff -r 000000000000 -r a3b6e531f0d2 iro/test.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/test.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- + +import unittest +import server +import threading, xmlrpclib +from multiprocessing import Queue +from multiprocessing.managers import BaseManager + +class StoppableXMLRPCServer(server.SecureUserDBXMLRPCServer, threading.Thread): + running=True + def __init__(self, *args, **kwargs): + server.SecureUserDBXMLRPCServer.__init__(self, *args, **kwargs) + threading.Thread.__init__(self) + + + def run(self): + # *serve_forever* muss in einem eigenen Thread laufen, damit man es + # unterbrechen kann! + while (self.running): + self.handle_request() + + + def stop(self): + self.running=False + self.server_close() + + +def init_server(): + userlist=[{"name":"test","password":"test", "class":server.User}, + {"name":"test2","password":"test2", "class": server.User}, + {"name":"admin","password":"admin", "class": server.Admin}] + + + + class MyManager(BaseManager): + pass + + MyManager.register('MessageJob', server.MessageJob) + manager = MyManager() + manager.start() + + + #anbieter erzeugen und konfigurieren + import anbieter + sip=anbieter.sipgate() + sip.read_basic_config("iro.conf") + localhost="" + + #Benutzerdatenbank erstellen + queue = Queue() + provider={"sms":sip, "fax":sip, "mail":localhost} + jobqueue=server.Jobs(manager, queue, provider) + userdb=server.MyUserDB(userlist,jobqueue) + + + #Server starten + serv = StoppableXMLRPCServer(addr=("localhost", 8000), + userdb=userdb, + certificate="./certs/test.cert.pem",privatekey="./certs/test.key.pem") + serv.relam="xmlrpc" + return serv + + +class TestServer(unittest.TestCase): + + def setUp(self): + self.serv = init_server() + self.serv.start() + + def tearDown(self): + self.serv.stop() + xmlrpclib.Server("https://test:test@localhost:8000").status() #letzte nachricht abrufen, damit richt geschlossen wird + + def testLogin(self): + self.assertEqual(xmlrpclib.Server("https://test:test@localhost:8000").status(), {}) + self.assertEqual(xmlrpclib.Server("https://test2:test2@localhost:8000").status(), {}) + self.assertRaises(xmlrpclib.ProtocolError, xmlrpclib.Server("https://test2:test@localhost:8000").status) + self.assertRaises(xmlrpclib.ProtocolError,xmlrpclib.Server ("https://test:test2@localhost:8000").status) + + def testsendSMS(self): + servstr="https://test:test@localhost:8000" + client=xmlrpclib.Server(servstr) + id=client.startSMS("test",["01234"] ) + self.assertEqual(client.status(id),{id: {'status': ['init',{}], 'name': {'content': 'test'}}} ) + + def testTwoUser(self): + u1="https://test:test@localhost:8000" + u2="https://test2:test2@localhost:8000" + admin="https://admin:admin@localhost:8000" + client1=xmlrpclib.Server(u1) + client2=xmlrpclib.Server(u2) + admin=xmlrpclib.Server(admin) + id1=client1.startSMS("test",["01234"] ) + self.assertEqual(client2.status(),{} ) + self.assertEqual(admin.status(id1),{id1: {'status': ['init',{}], 'name': {'content': 'test'}}} ) + id2=client2.startSMS("test2",["01234"] ) + self.assertNotEqual(id1, id2) + self.assertEqual(client1.status(),{id1: {'status': ['init',{}], 'name': {'content': 'test'}}}) + self.assertEqual(client2.status(),{id2: {'status': ['init',{}], 'name': {'content': 'test2'}}}) + self.assertEqual(admin.status(),{id1: {'status': ['init',{}], 'name': {'content': 'test'}}, + id2: {'status': ['init',{}], 'name': {'content': 'test2'}}} ) + + self.assertRaises(xmlrpclib.Fault, client2.status, id1) + self.assertRaises(xmlrpclib.Fault, client1.status, id2) + +if __name__ == "__main__": + unittest.main() diff -r 000000000000 -r a3b6e531f0d2 iro/user.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/user.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,69 @@ +# -*- 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 . +class User: + ''' + class for a xmlrpc user + ''' + def __init__(self,jobqueue): + self.jobqueue=jobqueue + self.jobs={} + + def status(self,id=None,detailed=False): + ''' + gets the status for a job + if the id is None all Jobs of an user are given back + ''' + 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.getName(),"status":job.getStatus(detailed)} + + return ret + + def stop(self,id): + ''' + stops an job with id + ''' + try: + job=self.jobs[id] + job.stop() + except: + raise String("No Job with ID: %i" %(id)) + job.stop() + + + def startSMS(self,message,recipients): + ''' + starts the SMS with message to recipients + ''' + id = self.jobqueue.newSMS(message,recipients) + self.jobs[id]=self.jobqueue[id] + return id + + + def startMail(self,subject, body , recipients): + id = self.jobqueue.newMail(subject, body ,recipients) + self.jobs[id]=self.jobqueue[id] + return id + +class Admin(User): + def __init__(self,jobqueue): + User.__init__(self, jobqueue) + self.jobs=jobqueue.jobs diff -r 000000000000 -r a3b6e531f0d2 iro/worker.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/worker.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# Worker code + +from multiprocessing import Process +import time + +class Worker(Process): + def __init__(self,queue): + Process.__init__(self) + self.queue=queue + + def run(self): + while 1: + job=self.queue.get() + if job is None: + break # reached end of queue + job.start() diff -r 000000000000 -r a3b6e531f0d2 iro/xmlrpc/AuthentificateXMLRPCServer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/xmlrpc/AuthentificateXMLRPCServer.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,76 @@ +# Server code +import SimpleXMLRPCServer +import string,base64 + +class AuthentificateXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): + def do_POST(self): + try: + header = self.headers['Authorization'] + type, user_passwd = header.split() + username, password = string.split(base64.decodestring(user_passwd), ':') + if self.testUser(username,password): + SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self) + else: + self.report_error(401) + except: + self.report_error(401) + + def report_error (self,code): + ''' + Send back an errorcode + ''' + #it is important to read out the complete sended request , + # but throw the data away, because an error should be send back + try: + max_chunk_size = 10*1024*1024 + size_remaining = int(self.headers["content-length"]) + while size_remaining: + chunk_size = min(size_remaining, max_chunk_size) + size_remaining -= len(self.rfile.read(chunk_size)) + except: + pass + + #now just send the error back + special_errors={401:self.report_401, + 404:self.report_404} + if special_errors.has_key(code): + special_errors[code]() + else: + self.send_response(code) + self.end_headers() + self.connection.shutdown(1) + + def report_401(self): + self.send_response(401) + self.send_header("WWW-Authenticate", 'Basic realm="%s"'% self.server.relam) + response = 'Unauthorised' + self.send_header("Content-type", "text/plain") + self.send_header("Content-length", str(len(response))) + self.end_headers() + self.wfile.write(response) + # shut down the connection + self.wfile.flush() + self.connection.shutdown(1) + + def testUser(self,username,password): + """ + Function for testing authentification + """ + if username=="test" and password=="test": + return True + + return False + + + +def test(): + server = SimpleXMLRPCServer.SimpleXMLRPCServer(("localhost", 8000),AuthentificateXMLRPCRequestHandler) + server.relam="xmlrpc" + server.register_introspection_functions() + server.register_function(lambda x: x*x, 'square') + server.serve_forever() + +if __name__ == '__main__': + test() + + diff -r 000000000000 -r a3b6e531f0d2 iro/xmlrpc/SecureAuthentificateXMLRPCServer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/xmlrpc/SecureAuthentificateXMLRPCServer.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,20 @@ +# Server code +import AuthentificateXMLRPCServer +import SecureXMLRPCServer + +class SecureAuthentificateXMLRPCRequestHandler(SecureXMLRPCServer.SecureXMLRPCRequestHandler,AuthentificateXMLRPCServer.AuthentificateXMLRPCRequestHandler): + def do_POST(self): + AuthentificateXMLRPCServer.AuthentificateXMLRPCRequestHandler.do_POST(self) + + +def test(): + server = SecureXMLRPCServer.SecureXMLRPCServer(("localhost", 8000),requestHandler=SecureAuthentificateXMLRPCRequestHandler,certificate="./certs/test.cert.pem",privatekey="./certs/test.key.pem") + server.relam="xmlrpc" + server.register_introspection_functions() + server.register_function(lambda x: x*x, 'square') + server.serve_forever() + +if __name__ == '__main__': + test() + + diff -r 000000000000 -r a3b6e531f0d2 iro/xmlrpc/SecureUserdbXMLRPCServer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/xmlrpc/SecureUserdbXMLRPCServer.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,63 @@ +from SecureAuthentificateXMLRPCServer import SecureAuthentificateXMLRPCRequestHandler +from SecureXMLRPCServer import SecureXMLRPCServer +import os, md5 + +class UserDB: + ''' + class for managing all xmlrpc users + - each user is indyfied via a hash value, which is created out of the username + password + ''' + def __init__(self,userClass, userlist,jobqueue): + self.salt=os.urandom(20) + self.jobqueue=jobqueue + self.userClass=userClass + self.userlist={} + for user in userlist: + self.createUser(user) + + def createHash(self,user): + """ + returns a hash out of username and the password and self.salt + user is a directory with two keys: username and password + """ + m=md5.new() + m.update(user["name"]) + m.update(self.salt) + m.update(user["password"]) + return m.hexdigest() + + def createUser(self,user): + self.userlist[self.createHash(user)]=self.userClass(self.jobqueue) + + def __getitem__(self,key): + return self.userlist[key] + + +class SecureAuthentificateXMLRPCRequestHandler2(SecureAuthentificateXMLRPCRequestHandler): + def testUser(self,username,password): + """ + Function for testing authentification + """ + 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.relam="xmlrpc" + self.userdb=userdb + + def activateUser(self,username,password): + """ + Function is executed, if someone ant to login + -searches for a regular user in the userdb and then put all methods of the user as XMLRPC + returns weather a user was found or not + """ + try: + user = self.userdb[self.userdb.createHash({"name":username,"password":password})] + self.register_instance(user) + return True + except KeyError: + return False diff -r 000000000000 -r a3b6e531f0d2 iro/xmlrpc/SecureXMLRPCServer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/xmlrpc/SecureXMLRPCServer.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,113 @@ +""" +SecureXMLRPCServer module using pyOpenSSL 0.5 +Written 0907.2002 +by Michal Wallace +http://www.sabren.net/ + +This acts exactly like SimpleXMLRPCServer +from the standard python library, but +uses secure connections. The technique +and classes should work for any SocketServer +style server. However, the code has not +been extensively tested. + +This code is in the public domain. +It is provided AS-IS WITH NO WARRANTY WHATSOEVER. +""" +import SocketServer +import os, socket +import SimpleXMLRPCServer +from OpenSSL import SSL + +class SSLWrapper: + """ + This whole class exists just to filter out a parameter + passed in to the shutdown() method in SimpleXMLRPC.doPOST() + """ + def __init__(self, conn): + """ + Connection is not yet a new-style class, + so I'm making a proxy instead of subclassing. + """ + self.__dict__["conn"] = conn + def __getattr__(self,name): + return getattr(self.__dict__["conn"], name) + def __setattr__(self,name, value): + setattr(self.__dict__["conn"], name, value) + def shutdown(self, how=1): + """ + SimpleXMLRpcServer.doPOST calls shutdown(1), + and Connection.shutdown() doesn't take + an argument. So we just discard the argument. + """ + self.__dict__["conn"].shutdown() + def accept(self): + """ + This is the other part of the shutdown() workaround. + Since servers create new sockets, we have to infect + them with our magic. :) + """ + c, a = self.__dict__["conn"].accept() + return (SSLWrapper(c), a) + + + +class SecureTCPServer(SocketServer.TCPServer): + """ + Just like TCPServer, but use a socket. + This really ought to let you specify the key and certificate files. + """ + def __init__(self, server_address, RequestHandlerClass,certificate,privatekey): + SocketServer.BaseServer.__init__(self, server_address, RequestHandlerClass) + + ## Same as normal, but make it secure: + ctx = SSL.Context(SSL.SSLv23_METHOD) + ctx.set_options(SSL.OP_NO_SSLv2) + + ctx.use_privatekey_file (privatekey) + ctx.use_certificate_file(certificate) + + self.socket = SSLWrapper(SSL.Connection(ctx, socket.socket(self.address_family, + self.socket_type))) + self.server_bind() + self.server_activate() + + +class SecureXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): + def setup(self): + """ + We need to use socket._fileobject Because SSL.Connection + doesn't have a 'dup'. Not exactly sure WHY this is, but + this is backed up by comments in socket.py and SSL/connection.c + """ + self.connection = self.request # for doPOST + self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) + self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) + + +class SecureXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer, SecureTCPServer): + def __init__(self, addr, + requestHandler=SecureXMLRPCRequestHandler, + certificate="server.cert",privatekey="server.pem", + logRequests=1): + """ + This is the exact same code as SimpleXMLRPCServer.__init__ + except it calls SecureTCPServer.__init__ instead of plain + old TCPServer.__init__ + """ + self.funcs = {} + self.logRequests = logRequests + self.instance = None + SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self,False,None) + SecureTCPServer.__init__(self, addr, requestHandler,certificate=certificate,privatekey=privatekey) + + +def test(): + server = SecureXMLRPCServer.SecureXMLRPCServer(("localhost", 8000),requestHandler=SecureXMLRPCRequestHandler,certificate="./certs/test.cert.pem",privatekey="./certs/test.key.pem") + server.register_introspection_functions() + server.register_function(lambda x: x*x, 'square') + server.serve_forever() + +if __name__ == '__main__': + test() + diff -r 000000000000 -r a3b6e531f0d2 iro/xmlrpc/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/xmlrpc/__init__.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,4 @@ +from AuthentificateXMLRPCServer import AuthentificateXMLRPCRequestHandler +from SecureXMLRPCServer import SecureXMLRPCRequestHandler, SecureXMLRPCServer +from SecureAuthentificateXMLRPCServer import SecureAuthentificateXMLRPCRequestHandler +from SecureUserdbXMLRPCServer import SecureUserDBXMLRPCServer, UserDB diff -r 000000000000 -r a3b6e531f0d2 iro/xmlserver_test.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/iro/xmlserver_test.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,139 @@ +# 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() + + diff -r 000000000000 -r a3b6e531f0d2 setup.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup.py Thu Oct 22 10:00:01 2009 +0200 @@ -0,0 +1,2 @@ +from setuptools import setup +setup(name="iro",version='0.1',install_requires=[])