iro/anbieter/smstrade.py
author Sandro Knauß <knauss@netzguerilla.net>
Fri, 27 Nov 2009 01:09:34 +0100
changeset 23 0180b538ed74
parent 22 8b363361ba55
child 37 6e5bd561ddd0
permissions -rw-r--r--
logging->logger wg. multiprocessing

# -*- 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 gsm0338
import urllib, httplib

import logging
logger=logging.getLogger("smstrade")

class UnknownStatusCode(Exception):
    def __init__(self,code):
        self.code=code

    def __str__(self):
        return "StatusCode %i is unknown"%self.code


class StatusCode:
     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"}

     def __init__(self,code):
        if code in self.statusCodes.keys():
            self.code=code
        else:
            raise UnknownStatusCode(code)
     
     def __str__(self):
        try:
            return self.statusCodes[self.code]
        except IndexError:
            raise UnkownStatusCode(self.code)

     def __int__(self):
        if not self.code in self.statusCodes.keys():
            raise UnknownStatusCode(self.code)
        return self.code




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

    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"""
        logger.debug('smstrade.sendSMS(%s,%s)'%(sms,  str(recipients)))
        sended = []
        route = unicode(self.route)
        message = sms.content
        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 ='00'+tel.land+tel.number
                if tel.land == '49':
                    route=unicode("basic")
                else:
                    route=unicode("economy")
                smsSendStatus = self.__send(route, to, message, timestamp)	
                logger.debug('smstrade._send(...)=%i(%s)'%(int(smsSendStatus),str(smsSendStatus)))
                if int(smsSendStatus) in(100, 999):
                    self.updateStatus(arranged=recipient)
                else:
                    self.updateStatus(failed=recipient)
            except (NotATelNumber,NoValidStatusCode,InternetConnectionError):
                self.updateStatus(failed=recipient)

    def __send(self, route, to, message,  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."""
        logger.debug('smstrade._send(%s,%s,%s,%s)'%( route, to, message, timestamp))
        parameters= {"key": self.key,
                "route": route,
                "to": to,
                "message": message,
                "charset":"utf-8", 
                "debug": self.debug,
                }
        
        if self.from_ is not None:
            parameters["from"] = self.from_
        
        if timestamp is not None:
            parameters["senddate"] = unicode(timestamp)

        parameters["concat_sms"] = "1" if len(message) > 160 else "0"
        params = "&".join( ["%s=%s" % (urllib.quote(k),urllib.quote(v.encode("utf-8"))) for (k, v) in parameters.items()])
        logger.debug('smstrade._send-parameters:%s\n\t->%s'%(str(parameters), str(params)) )
        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))
        finally:
            conn.close()
            
        try:
            return StatusCode(int(data))
        except UnknownStatusCode:
            # this happens if the sms will be send delayed
            return StatusCode(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