openmarket.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import logging
  16. from base64 import b64encode
  17. from twisted.internet import defer, reactor
  18. from sydent.http.httpclient import SimpleHttpClient
  19. from twisted.web.http_headers import Headers
  20. logger = logging.getLogger(__name__)
  21. API_BASE_URL = "https://smsc.openmarket.com/sms/v4/mt"
  22. # The Customer Integration Environment, where you can send
  23. # the same requests but it doesn't actually send any SMS.
  24. # Useful for testing.
  25. #API_BASE_URL = "http://smsc-cie.openmarket.com/sms/v4/mt"
  26. # The TON (ie. Type of Number) codes by type used in our config file
  27. TONS = {
  28. 'long': 1,
  29. 'short': 3,
  30. 'alpha': 5,
  31. }
  32. def tonFromType(t):
  33. if t in TONS:
  34. return TONS[t]
  35. raise Exception("Unknown number type (%s) for originator" % t)
  36. class OpenMarketSMS:
  37. def __init__(self, sydent):
  38. self.sydent = sydent
  39. self.http_cli = SimpleHttpClient(sydent)
  40. @defer.inlineCallbacks
  41. def sendTextSMS(self, body, dest, source=None):
  42. body = {
  43. "mobileTerminate": {
  44. "message": {
  45. "content": body,
  46. "type": "text"
  47. },
  48. "destination": {
  49. "address": dest,
  50. }
  51. },
  52. }
  53. if source:
  54. body['mobileTerminate']['source'] = {
  55. "ton": tonFromType(source['type']),
  56. "address": source['text'],
  57. }
  58. b64creds = b64encode(b"%s:%s" % (
  59. self.sydent.cfg.get('sms', 'username'),
  60. self.sydent.cfg.get('sms', 'password'),
  61. ))
  62. headers = Headers({
  63. b"Authorization": [b"Basic " + b64creds],
  64. b"Content-Type": [b"application/json"],
  65. })
  66. resp = yield self.http_cli.post_json_get_nothing(
  67. API_BASE_URL, body, { "headers": headers }
  68. )
  69. headers = dict(resp.headers.getAllRawHeaders())
  70. if 'Location' not in headers:
  71. raise Exception("Got response from sending SMS with no location header")
  72. # Nominally we should parse the URL, but we can just split on '/' since
  73. # we only care about the last part.
  74. parts = headers['Location'][0].split('/')
  75. if len(parts) < 2:
  76. raise Exception("Got response from sending SMS with malformed location header")
  77. defer.returnValue(parts[-1])