fix link to about.
# -*- coding: utf-8 -*-
# Copyright (c) 2012 netzguerilla.net <iro@netzguerilla.net>
#
# This file is part of Iro.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
# #Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import urllib.request, urllib.parse
from functools import partial
from decimal import Decimal
import copy
from ..config import Option
from ..model.status import Status
from .provider import Provider, providers
from ..error import RejectRecipient, ExternalException
#import logging
#logger=logging.getLogger("smstrade")
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.",
}
"""statuscodes of external smstrade API"""
class SmstradeException(ExternalException):
"""An excetion that connects the status code with the excetion string (see :attr:`statusCodes`)"""
def __init__(self,status):
ExternalException.__init__(self)
self.status = status
self.str_=str(status)
def __str__(self):
return "%s\n%s"%(ExternalException.__str__(self),self.str_)
class StatusCode:
"""Class that represents the output of one smstrade request."""
def __init__(self,code, exID=None, costs=Decimal("0.0"), count=0):
self.code = code
self.exID = exID
try:
self.costs = Decimal(costs)
except:
if not costs.strip():
self.costs = Decimal("0.0")
else:
raise
self.count = int(count)
def __str__(self):
if self.code in statusCodes.keys():
return "%i: %s"%(self.code, statusCodes[self.code])
return "%i: unknown statuscode."%self.code
def __int__(self):
return self.code
class Smstrade(Provider):
"""A Provider to send SMS to recipients using smstrade.
Smstrade only supports to send SMS and four diffrent routes: ``["basic","economy","gold","direct"]``.
It needs a smstrade Gateway Key https://login.smstrade.de/index.php?gateway in configuration file.
smstrade API documentation: http://kundencenter.smstrade.de/sites/smstrade.de.kundencenter/__pdf/SMS-Gateway_HTTP_API_v2.pdf
The smstrade API supports a debug mode, that can be set with :attr:`~iro.offer.provider.Provider.testmode`.
"""
_params= {"debug":("boolean",False),
"concat_sms":('boolean',False),
"message_id":('boolean',False),
"count":('boolean',False),
"cost":('boolean',False),
}
'''dict for standrd values of the smstrade api, it is used to get the right values to the API.'''
def __init__(self, name):
self.url = "https://gateway.smstrade.de"
options =[("key", Option(lambda x,y:x,int="smstrade Gateway Key https://login.smstrade.de/index.php?gateway", must=True)),]
Provider.__init__(self, name, {"sms":["basic","economy","gold","direct"]},options)
def send(self, route, recipient, sms):
"""send one SMS to recipient via route
:param string route: A valid route ``["basic", "economy", "gold", "direct"]``
:param `iro.telnumber.Telnumber` recipient: Mobilenumber of recipient
:param `iro.model.message.SMS` sms: the sms to send
:return:
- All went ok -- :class:`iro.model.status.Status` object
- otherwise -- an exception
"""
#logger.debug('smstrade.sendSMS(%s,%s)'%(sms, recipient))
if recipient.land != '49' and route == "basic":
raise RejectRecipient(recipient)
to ='00'+recipient.land+recipient.number
s = self.__send(route, to, sms)
s.costs = Decimal('0.0728')
if int(s) in (100,):
return Status(self,route, exID=s.exID, costs=s.costs, count=s.count)
elif int(s) in (70,71,):
raise RejectRecipient(recipient, status=s)
else:
raise SmstradeException(s)
def __send(self, route, to, sms):
""" This is the main function to request to the sms service.
:param string route: A valid route ``["basic", "economy", "gold", "direct"]
:param string recipient: Mobilenumber of recipient
:param `iro.model.message.sms` sms: the sms to send
:return: a :class:`.StatusCode` object
"""
#logger.debug('smstrade._send(%s,%s,%s)'%( route, to, sms))
parameters= {"key": self.key,
"route": route,
"to": to,
"message": sms.content,
"charset":"utf-8",
"debug": self.testmode,
"message_id":True,
"count":True,
"cost":True,
}
doubleChar="€[]{}|\\^~" #these charactar need two GSM Chars
if sms.from_ is not None:
parameters["from"] = sms.from_
length=len(sms.content)
for s in doubleChar:
length += sms.content.count(s)
parameters["concat_sms"] = True if length > 160 else False
ps={}
for p in parameters:
if p in list(self._params.keys()):
if self._params[p][0] == "boolean":
if parameters[p] != self._params[p][1]:
ps[p]=int(bool(parameters[p]))
else:
ps[p] = parameters[p]
params = urllib.parse.urlencode(ps)
dp=copy.deepcopy(ps)
dp["key"]="<KEY>"
print('smstrade._send-parameters:%s\n\t->%s'%(str(dp), urllib.parse.urlencode(dp)))
response = urllib.request.urlopen(self.url, params)
data = response.readlines()
print("result:%s"%(data))
if len(data) == 1:
return StatusCode(int(data[0]))
return StatusCode(int(data[0]),exID=data[1].strip(),costs=data[2],count=data[3])
def getSendFunc(self, typ, route):
"""returns a partial :meth:`send` methed with bounded route, if typ and route is valid."""
Provider.getSendFunc(self, typ, route)
return partial(self.send,route)
providers["smstrade"]=Smstrade