iro/anbieter/smstrade.py
changeset 1 18918fbc397c
child 9 4c5f1cf088f6
--- /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 <http://www.gnu.org/licenses/>.
+
+
+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