iro/anbieter/smstrade.py
author Sandro Knauß <knauss@netzguerilla.net>
Sat, 31 Oct 2009 03:20:59 +0100
changeset 11 f25033cf93e0
parent 1 18918fbc397c
child 15 c04a21066aad
permissions -rw-r--r--
Backend auswahl nun möglich

# -*- 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 sipgate import  NoValidStatusCode
from telnumber import telnumber, NotATelNumber
import ConfigParser
import xmlrpclib
import base64
import urllib, httplib

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)
        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()						                
                code, smsSendStatus = self.__send(key, route, to, message, from_, timestamp)	
                if code in(100, 999):
                    self.updateStatus(arranged=recipient)
            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 int(data), self.statusCodes[int(data)]
        except ValueError:
            # this happens if the sms will be send delayed
            return 999, 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