smess 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,155 @@
1
+ require 'uri'
2
+ require 'httpi'
3
+
4
+ module Smess
5
+ class Mblox
6
+ include Smess::Logging
7
+
8
+ def deliver_sms(sms)
9
+ return false unless sms.kind_of? Sms
10
+
11
+ parts = Smess.split_sms(sms.message.strip_nongsm_chars)
12
+ return false if parts[0].empty?
13
+
14
+ xml_params = {
15
+ subscriber_number: sms.to,
16
+ message: ""
17
+ }
18
+ # if we have several parts, send them as concatenated sms
19
+ if parts.length > 1
20
+ logger.info "Num Parts: #{parts.length.to_s}"
21
+ # create concat-sms UDH
22
+ ref_id = Random.new.rand(255).to_s(16).rjust(2,"0")
23
+ num_parts = parts.length
24
+ xml_params[:udh] = ":05:00:03:#{ref_id}:#{num_parts.to_s(16).rjust(2,'0')}:01" # {050003}{ff}{02}{01} {concat-command}{id to link all parts}{total num parts}{num of current part}
25
+ end
26
+
27
+ xml_params[:message] = parts.shift
28
+ # send first SMS... the one we return the result from...
29
+ result = send_one_sms( xml_params )
30
+ result[:data][:text] = sms.message.strip_nongsm_chars
31
+
32
+
33
+ # send additional parts if we have them
34
+ if parts.length > 0 && result[:response_code] != "-1"
35
+ more_results = []
36
+ parts.each_with_index do |part, i|
37
+ xml_params[:message] = part
38
+ xml_params[:udh] = ":05:00:03:#{ref_id}:#{num_parts.to_s(16).rjust(2,'0')}:#{(i+2).to_s(16).rjust(2,'0')}"
39
+ more_results << send_one_sms( xml_params )
40
+ end
41
+ # we don't actually return the status for any of these which is cheating
42
+ logger.info more_results
43
+ end
44
+
45
+ result
46
+ end
47
+
48
+
49
+ def send_one_sms(xml_params)
50
+ xml = xml_data_for(xml_params)
51
+ body = "XMLDATA="+URI::encode( xml.encode("ISO-8859-1") ) # escape
52
+
53
+ request = HTTPI::Request.new
54
+ request.url = 'https://xml4.us.mblox.com:443/send'
55
+ request.headers["Content-Type"] = "application/x-www-form-urlencoded"
56
+ request.body = body
57
+
58
+ begin
59
+ HTTPI.log_level = :debug
60
+ response = HTTPI.post request
61
+
62
+ rescue Exception => e
63
+ logger.warn response
64
+ # connection problem or some error
65
+ result = {
66
+ response_code: '-1',
67
+ response: {
68
+ temporaryError: 'true',
69
+ responseCode: e.code,
70
+ responseText: e.message
71
+ },
72
+ data: {
73
+ to: xml_params[:subscriber_number],
74
+ text: xml_params[:message],
75
+ from: ENV["SMESS_MBLOX_SURE_ROUTE_SHORTCODE"]
76
+ }
77
+ }
78
+ else
79
+ response_data = Nori.parse(response.body)
80
+ response_code = response_code_for response_data
81
+ # Successful response
82
+ result = {
83
+ message_id: @message_id,
84
+ response_code: response_code,
85
+ response: response_data,
86
+ destination_address: xml_params[:subscriber_number],
87
+ data: {
88
+ to: xml_params[:subscriber_number],
89
+ text: xml_params[:message],
90
+ from: ENV["SMESS_MBLOX_SURE_ROUTE_SHORTCODE"]
91
+ }
92
+ }
93
+ end
94
+ result
95
+ end
96
+
97
+
98
+ def xml_data_for(xml_params)
99
+ Gyoku.convert_symbols_to :camelcase
100
+ '<?xml version="1.0"?>'+
101
+ Gyoku.xml( hash_data_for(xml_params) )
102
+ end
103
+
104
+ def hash_data_for(xml_params)
105
+ rand = (SecureRandom.random_number*100000000).to_i
106
+ @message_id = rand # "#{Time.now.to_i}#{xml_params.to}#{rand}"
107
+
108
+ xml_hash = {
109
+ notification_request: {
110
+ notification_header: {
111
+ partner_name: ENV["SMESS_MBLOX_SURE_ROUTE_USER"],
112
+ partner_password: ENV["SMESS_MBLOX_SURE_ROUTE_PASS"]
113
+ },
114
+ notification_list: {
115
+ notification: {
116
+ message: xml_params[:message],
117
+ profile: ENV["SMESS_MBLOX_SURE_ROUTE_PROFILE_ID"],
118
+ udh: xml_params.fetch(:udh,""),
119
+ sender_i_d: ENV["SMESS_MBLOX_SURE_ROUTE_SHORTCODE"],
120
+ # expire_date: "",
121
+ # operator: "",
122
+ # tariff: "",
123
+ subscriber: {
124
+ subscriber_number: xml_params[:subscriber_number],
125
+ session_id: ""
126
+ },
127
+ # tags: '<Tag Name=”Number”>56</Tag><Tag Name=”City”>Paris</Tag>',
128
+ # service_desc: "",
129
+ # content_type: "",
130
+ service_id: ENV["SMESS_MBLOX_SURE_ROUTE_SID"],
131
+ attributes!: { sender_i_d: { "Type" => "Shortcode" } }
132
+ },
133
+ attributes!: { notification: { "SequenceNumber" => "1", "MessageType" => "SMS" } } # FlashSMS
134
+ },
135
+ attributes!: { notification_list: { "BatchID" => @message_id } }
136
+ },
137
+ attributes!: { notification_request: { "Version" => "3.5" } }
138
+ }
139
+ xml_hash[:notification_request][:notification_list][:notification].delete :udh unless xml_params.key? :udh
140
+ xml_hash
141
+ end
142
+
143
+ def response_code_for(response_data)
144
+ request_result_code = response_data[:notification_request_result][:notification_result_header][:request_result_code] rescue "-1"
145
+ return "request:#{request_result_code}" unless request_result_code == "0"
146
+
147
+ notification_result_code = response_data[:notification_request_result][:notification_result_list][:notification_result][:notification_result_code] rescue "-1"
148
+ return "notification:#{notification_result_code}" unless notification_result_code == "0"
149
+
150
+ subscriber_result_code = response_data[:notification_request_result][:notification_result_list][:notification_result][:subscriber_result][:subscriber_result_code] rescue "-1"
151
+ (subscriber_result_code == "0") ? subscriber_result_code : "subscriber:#{subscriber_result_code}"
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,122 @@
1
+ module Smess
2
+
3
+ class Mm7
4
+ include Smess::Logging
5
+
6
+ def initialize
7
+
8
+ # SOAP defaults
9
+ @endpoint = "http://example.com/mms/mm7"
10
+
11
+ # MM7 defaults
12
+ @mm7ns = "http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-6-MM7-1-2"
13
+ @mm7header = {
14
+ "mm7:TransactionID" => Time.now.strftime('%Y%m%d%H%M%S'),
15
+ :attributes! => {
16
+ "mm7:TransactionID" => {
17
+ "xmlns:mm7" => @mm7ns
18
+ }
19
+ }
20
+ }
21
+ @mm7body = {
22
+ "mm7:MM7Version" => "6.5.0",
23
+ "mm7:SenderIdentification" => {
24
+ "mm7:VASPID" => "",
25
+ "mm7:SenderAddress" => {}
26
+ },
27
+ "mm7:Recipients" => {
28
+ "mm7:To" => {
29
+ "mm7:Number" => ""
30
+ }
31
+ },
32
+ "mm7:ServiceCode" => "",
33
+ "mm7:LinkedID" => "",
34
+ "mm7:DeliveryReport" => "true",
35
+ "mm7:Subject" => "",
36
+ "mm7:Content/" => nil,
37
+ :attributes! => {"mm7:Content/" => {"href" => "cid:attachment_1"}}
38
+ }
39
+
40
+ @credentials = nil
41
+
42
+ end
43
+
44
+ private
45
+
46
+ def perform_operator_adaptation(msisdn)
47
+ # implement this method to do modify the message output
48
+ end
49
+
50
+ def soap_client
51
+ Savon.configure do |config|
52
+ config.log_level = :info
53
+ config.raise_errors = false
54
+ end
55
+
56
+
57
+ endpoint = @endpoint
58
+ mm7ns = @mm7ns
59
+ credentials = @credentials
60
+
61
+ client = Savon::Client.new do |wsdl, http|
62
+ wsdl.endpoint = endpoint
63
+ wsdl.namespace = mm7ns
64
+
65
+ http.open_timeout = 15
66
+ http.read_timeout = 60 # Won't set read timeout to 10 minutes!! (IPX are crazy)
67
+ http.auth.basic credentials[:name], credentials[:pass] unless credentials.nil?
68
+ end
69
+ client
70
+ end
71
+
72
+ def get_response_hash_from(response)
73
+ response.to_hash[:submit_rsp]
74
+ end
75
+
76
+ def get_message_id_from hash
77
+ hash[:message_id] rescue ''
78
+ end
79
+
80
+ def parse_response(response)
81
+ logger.debug ' --- '
82
+ logger.debug response.http_error.to_hash
83
+ logger.debug ' --- '
84
+ # logger.debug response.success?
85
+ # logger.debug ' --- '
86
+ # logger.debug "#{response.http_error}, #{response.soap_fault }"
87
+ # logger.debug ' --- '
88
+
89
+ unless response.success?
90
+ result = {
91
+ :response_code => "-1",
92
+ :response => {
93
+ :responseCode => "-1",
94
+ :responseText => response.http_error? ? response.http_error.to_hash : response.soap_fault.to_hash
95
+ }
96
+ }
97
+
98
+ return result
99
+ end
100
+
101
+ hash = get_response_hash_from response
102
+ message_id = get_message_id_from hash
103
+
104
+ # any 1000 range code is a success, anything else is an error.
105
+ status_code = hash[:status][:status_code] rescue '-1'
106
+ if (1000..1999) === status_code.to_i
107
+ response_code = "0"
108
+ else
109
+ response_code = status_code
110
+ # LOG error here?
111
+ end
112
+
113
+ result = {
114
+ :message_id => message_id,
115
+ :response_code => response_code,
116
+ :response => hash
117
+ }
118
+
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,70 @@
1
+ require 'uri'
2
+ require 'httpi'
3
+
4
+ module Smess
5
+ class Smsglobal
6
+ include Smess::Logging
7
+
8
+ def deliver_sms(sms)
9
+ return false unless sms.kind_of? Sms
10
+
11
+ url = "https://www.smsglobal.com/http-api.php"
12
+ from = sms.originator || ENV["SMESS_SMSGLOBAL_SENDER_ID"]
13
+
14
+ params = {
15
+ action: "sendsms",
16
+ user: ENV["SMESS_SMSGLOBAL_USER"],
17
+ password: ENV["SMESS_SMSGLOBAL_PASS"],
18
+ from: from,
19
+ to: sms.to,
20
+ text: sms.message.strip_nongsm_chars,
21
+ maxsplit: "3"
22
+ }
23
+
24
+ request = HTTPI::Request.new
25
+ request.url = url
26
+ request.body = params
27
+
28
+ begin
29
+ HTTPI.log_level = :debug
30
+ response = HTTPI.post request
31
+
32
+ rescue Exception => e
33
+ logger.warn response
34
+ # connection problem or some error
35
+ result = {
36
+ response_code: '-1',
37
+ response: {
38
+ temporaryError: 'true',
39
+ responseCode: e.code,
40
+ responseText: e.message
41
+ },
42
+ data: {
43
+ to: sms.to,
44
+ text: sms.message.strip_nongsm_chars,
45
+ from: from
46
+ }
47
+ }
48
+ else
49
+ first_response = response.body.split(/\r\n/).first.split(";")
50
+ response_code = first_response.first.split(':').last.to_i
51
+ message_id = first_response.last.split('SMSGlobalMsgID:').last
52
+
53
+ # Successful response
54
+ result = {
55
+ message_id: message_id,
56
+ response_code: response_code.to_s,
57
+ response: response.body,
58
+ destination_address: sms.to,
59
+ data: {
60
+ to: sms.to,
61
+ text: sms.message.strip_nongsm_chars,
62
+ from: from
63
+ }
64
+ }
65
+ end
66
+ result
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,31 @@
1
+ module Smess
2
+ class Test
3
+
4
+ @@instance = nil
5
+ @delivery_result = {
6
+ :response_code => '-1',
7
+ :response => {
8
+ :temporaryError =>'true',
9
+ :responseCode => '-1',
10
+ :responseText => 'No delivery result set in test output object.'
11
+ }
12
+ }
13
+ class << self; attr_accessor :delivery_result end
14
+ attr_reader :sms, :mms
15
+
16
+ def initialize
17
+ @@instance = self
18
+ end
19
+
20
+ def self.instance
21
+ @@instance
22
+ end
23
+
24
+ def deliver_sms(sms)
25
+ return false unless sms.kind_of? Sms
26
+ @sms = sms
27
+ self.class.delivery_result
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,69 @@
1
+ require 'twilio-ruby'
2
+
3
+ module Smess
4
+ class Twilio
5
+ include Smess::Logging
6
+
7
+ def deliver_sms(sms)
8
+ return false unless sms.kind_of? Sms
9
+
10
+ parts = Smess.separate_sms sms.message.strip_nongsm_chars
11
+ return false if parts[0].empty?
12
+
13
+ @client = ::Twilio::REST::Client.new(ENV["SMESS_TWILIO_SID"], ENV["SMESS_TWILIO_AUTH_TOKEN"])
14
+
15
+
16
+ results = []
17
+ while parts.length > 0
18
+ results << send_one_sms(sms, parts.shift)
19
+ end
20
+ results[0][:data][:text] = sms.message.strip_nongsm_chars
21
+ results[0]
22
+ end
23
+
24
+ def send_one_sms(sms, message)
25
+ begin
26
+ response = @client.account.sms.messages.create({
27
+ from: ENV["SMESS_TWILIO_FROM"],
28
+ to: "+#{sms.to}",
29
+ body: message,
30
+ status_callback: ENV["SMESS_TWILIO_CALLBACK_URL"]
31
+ })
32
+ rescue Exception => e
33
+ logger.warn response
34
+ # connection problem or some error
35
+ result = {
36
+ response_code: '-1',
37
+ response: {
38
+ temporaryError: 'true',
39
+ responseCode: e.code,
40
+ responseText: e.message
41
+ },
42
+ data: {
43
+ to: sms.to,
44
+ text: message,
45
+ from: ENV["SMESS_TWILIO_FROM"]
46
+ }
47
+ }
48
+ else
49
+ response_code = response.status
50
+ response_code = "0" unless response.status == "failed"
51
+ # Successful response
52
+ result = {
53
+ message_id: response.sid,
54
+ response_code: response_code.to_s,
55
+ response: MultiJson.load(@client.last_response.body),
56
+ destination_address: sms.to,
57
+ data: {
58
+ to: sms.to,
59
+ text: message,
60
+ from: ENV["SMESS_TWILIO_FROM"]
61
+ }
62
+ }
63
+ end
64
+ result
65
+ end
66
+
67
+
68
+ end
69
+ end