smess 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -0
- data/lib/smess.rb +0 -1
- data/lib/smess/outputs/global_mouth.rb +83 -55
- data/lib/smess/outputs/iconectiv.rb +1 -28
- data/lib/smess/outputs/ipx.rb +97 -101
- data/lib/smess/outputs/ipxus.rb +15 -36
- data/lib/smess/outputs/mblox.rb +1 -1
- data/lib/smess/outputs/smsglobal.rb +66 -45
- data/lib/smess/utils.rb +0 -38
- data/lib/smess/version.rb +1 -1
- data/lib/string.rb +4 -4
- metadata +4 -4
- data/lib/smess/outputs/mm7.rb +0 -122
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0a1e283815e44722a3631efb29a2eaa38d0fa4eb
|
4
|
+
data.tar.gz: 1c48a4e6deb6695578794876979b2fb1d3bf928d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffcaee4dd2e2e81dd04de3d50d9d3a915b84160d675fefd4fa7d127141e61a77b3f41dc662b3d5ecb95ef7bd31b968beed9965fdc1386b7f5059673e455e9d4e
|
7
|
+
data.tar.gz: 6dc69c352819f3e6061efae4b72b0f163cb860a760c5cba95024c030a65363d99d35792e5cb9984cdad90db47e1fe6b69ca2ead4fb039a832c76e66f1318c511
|
data/README.md
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/smess.png)](http://badge.fury.io/rb/smess)
|
2
|
+
[![Code Climate](https://codeclimate.com/repos/52249703f3ea003d03072821/badges/efe9fa39e239e1515d4e/gpa.png)](https://codeclimate.com/repos/52249703f3ea003d03072821/feed)
|
3
|
+
|
1
4
|
# Smess - A mess of SMS messaging
|
2
5
|
|
3
6
|
This is a messy SMS messenger supporting every aggregator I have gotten my hands on.
|
data/lib/smess.rb
CHANGED
@@ -5,74 +5,29 @@ module Smess
|
|
5
5
|
class GlobalMouth
|
6
6
|
include Smess::Logging
|
7
7
|
|
8
|
+
def deliver_sms(sms_arg)
|
9
|
+
return false unless sms_arg.kind_of? Sms
|
10
|
+
@sms = sms_arg
|
8
11
|
|
9
|
-
|
10
|
-
hash = "#{username}#{values.join}"
|
11
|
-
auth_hash = Digest::MD5.hexdigest "#{username}:#{password}"
|
12
|
-
Digest::MD5.hexdigest "#{hash}#{auth_hash}"
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
def deliver_sms(sms)
|
17
|
-
return false unless sms.kind_of? Sms
|
18
|
-
|
19
|
-
url = "https://mcm.globalmouth.com:8443/api/mcm"
|
20
|
-
from = sms.originator || sender_id
|
21
|
-
message_id = Digest::MD5.hexdigest "#{Time.now.strftime('%Y%m%d%H%M%S')}#{sms.to}-#{SecureRandom.hex(6)}"
|
22
|
-
|
23
|
-
params = {
|
24
|
-
username: username,
|
25
|
-
msisdn: "+#{sms.to}",
|
26
|
-
body: sms.message.strip_nongsm_chars.encode("ISO-8859-1"),
|
27
|
-
originator: from,
|
28
|
-
ref: message_id,
|
29
|
-
dlr: "true"
|
30
|
-
}
|
31
|
-
params[:hash] = compute_hash(
|
32
|
-
[sms.message.strip_nongsm_chars.encode("ISO-8859-1"), params[:originator], params[:msisdn]]
|
33
|
-
)
|
34
|
-
request = HTTPI::Request.new
|
12
|
+
generate_mac_hash
|
35
13
|
request.url = "#{url}?#{params.to_query}"
|
36
14
|
|
37
15
|
begin
|
38
16
|
HTTPI.log_level = :debug
|
39
17
|
response = HTTPI.get request
|
40
|
-
|
18
|
+
result = normal_result(response)
|
41
19
|
rescue Exception => e
|
42
20
|
logger.warn response
|
43
21
|
# connection problem or some error
|
44
|
-
result =
|
45
|
-
response_code: '-1',
|
46
|
-
response: {
|
47
|
-
temporaryError: 'true',
|
48
|
-
responseCode: e.code,
|
49
|
-
responseText: e.message
|
50
|
-
},
|
51
|
-
data: {
|
52
|
-
to: sms.to,
|
53
|
-
text: sms.message.strip_nongsm_chars,
|
54
|
-
from: from
|
55
|
-
}
|
56
|
-
}
|
57
|
-
else
|
58
|
-
response_code = response.body.split(/\n/).first
|
59
|
-
response_code = "0" if response_code == "200"
|
60
|
-
# Successful response
|
61
|
-
result = {
|
62
|
-
message_id: message_id,
|
63
|
-
response_code: response_code.to_s,
|
64
|
-
response: {body: response.body},
|
65
|
-
destination_address: sms.to,
|
66
|
-
data: {
|
67
|
-
to: sms.to,
|
68
|
-
text: sms.message.strip_nongsm_chars,
|
69
|
-
from: from
|
70
|
-
}
|
71
|
-
}
|
22
|
+
result = result_for_error(e)
|
72
23
|
end
|
73
24
|
result
|
74
25
|
end
|
75
26
|
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :sms
|
30
|
+
|
76
31
|
def username
|
77
32
|
ENV["SMESS_GLOBAL_MOUTH_USER"].dup # paranoid safeguard
|
78
33
|
end
|
@@ -83,5 +38,78 @@ module Smess
|
|
83
38
|
ENV["SMESS_GLOBAL_MOUTH_SENDER_ID"]
|
84
39
|
end
|
85
40
|
|
41
|
+
def url
|
42
|
+
"https://mcm.globalmouth.com:8443/api/mcm"
|
43
|
+
end
|
44
|
+
|
45
|
+
def from
|
46
|
+
sms.originator || sender_id
|
47
|
+
end
|
48
|
+
|
49
|
+
def message_id
|
50
|
+
@message_id ||= Digest::MD5.hexdigest "#{Time.now.strftime('%Y%m%d%H%M%S')}#{sms.to}-#{SecureRandom.hex(6)}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def params
|
54
|
+
@params ||= {
|
55
|
+
username: username,
|
56
|
+
msisdn: "+#{sms.to}",
|
57
|
+
body: sms.message.strip_nongsm_chars.encode("ISO-8859-1"),
|
58
|
+
originator: from,
|
59
|
+
ref: message_id,
|
60
|
+
dlr: "true"
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def compute_hash(values = [])
|
65
|
+
hash = "#{username}#{values.join}"
|
66
|
+
auth_hash = Digest::MD5.hexdigest "#{username}:#{password}"
|
67
|
+
Digest::MD5.hexdigest "#{hash}#{auth_hash}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def generate_mac_hash
|
71
|
+
params[:hash] = compute_hash(
|
72
|
+
[sms.message.strip_nongsm_chars.encode("ISO-8859-1"), params[:originator], params[:msisdn]]
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
def request
|
77
|
+
@request ||= HTTPI::Request.new
|
78
|
+
end
|
79
|
+
|
80
|
+
def result_for_error(e)
|
81
|
+
code = e.code rescue "-1"
|
82
|
+
{
|
83
|
+
response_code: '-1',
|
84
|
+
response: {
|
85
|
+
temporaryError: 'true',
|
86
|
+
responseCode: e.code,
|
87
|
+
responseText: e.message
|
88
|
+
},
|
89
|
+
data: result_data
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def normal_result(response)
|
94
|
+
response_code = response.body.split(/\n/).first
|
95
|
+
response_code = "0" if response_code == "200"
|
96
|
+
# Successful response
|
97
|
+
{
|
98
|
+
message_id: message_id,
|
99
|
+
response_code: response_code.to_s,
|
100
|
+
response: {body: response.body},
|
101
|
+
destination_address: sms.to,
|
102
|
+
data: result_data
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
def result_data
|
107
|
+
{
|
108
|
+
to: sms.to,
|
109
|
+
text: sms.message.strip_nongsm_chars,
|
110
|
+
from: from
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
86
114
|
end
|
87
115
|
end
|
@@ -1,33 +1,6 @@
|
|
1
1
|
module Smess
|
2
2
|
class Iconectiv < Ipxus
|
3
3
|
|
4
|
-
def build_sms_payload
|
5
|
-
# SOAP data
|
6
|
-
@sms_options = {
|
7
|
-
"correlationId" => Time.now.strftime('%Y%m%d%H%M%S') + @sms.to,
|
8
|
-
"originatingAddress" => account[:shortcode],
|
9
|
-
"originatorTON" => "0",
|
10
|
-
"destinationAddress" => nil,
|
11
|
-
"userData" => "",
|
12
|
-
"userDataHeader" => "#NULL#",
|
13
|
-
"DCS" => "-1",
|
14
|
-
"PID" => "-1",
|
15
|
-
"relativeValidityTime" => "-1",
|
16
|
-
"deliveryTime" => "#NULL#",
|
17
|
-
"statusReportFlags" => "1", # 1
|
18
|
-
"accountName" => account[:account_name],
|
19
|
-
"tariffClass" => "USD0",
|
20
|
-
"VAT" => "-1",
|
21
|
-
"referenceId" => "#NULL#",
|
22
|
-
"serviceName" => account[:service_name],
|
23
|
-
"serviceCategory" => "#NULL#",
|
24
|
-
"serviceMetaData" => "#NULL#",
|
25
|
-
"campaignName" => "#NULL#",
|
26
|
-
"username" => account[:username],
|
27
|
-
"password" => account[:password]
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
4
|
def account
|
32
5
|
@account ||= {
|
33
6
|
sms_url: 'http://66.70.32.42:32005/api/services2/SmsApi52?wsdl',
|
@@ -36,7 +9,7 @@ module Smess
|
|
36
9
|
password: ENV["SMESS_ICONECTIV_PASS"],
|
37
10
|
account_name: ENV["SMESS_ICONECTIV_ACCOUNT_NAME"],
|
38
11
|
service_name: ENV["SMESS_SERVICE_NAME"],
|
39
|
-
|
12
|
+
service_meta_data_t_mobile_us: ENV["SMESS_ICONECTIV_SERVICE_META_DATA_T_MOBILE_US"],
|
40
13
|
service_meta_data_verizon: ENV["SMESS_ICONECTIV_SERVICE_META_DATA_VERIZON"]
|
41
14
|
}
|
42
15
|
end
|
data/lib/smess/outputs/ipx.rb
CHANGED
@@ -4,10 +4,9 @@ module Smess
|
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
@endpoint = account[:sms_url]
|
7
|
-
|
8
7
|
@credentials = {
|
9
|
-
:
|
10
|
-
:
|
8
|
+
name: account[:username],
|
9
|
+
pass: account[:password]
|
11
10
|
}
|
12
11
|
end
|
13
12
|
|
@@ -22,13 +21,44 @@ module Smess
|
|
22
21
|
}
|
23
22
|
end
|
24
23
|
|
25
|
-
def
|
26
|
-
|
27
|
-
@
|
28
|
-
|
24
|
+
def deliver_sms(sms_arg)
|
25
|
+
return false unless sms_arg.kind_of? Sms
|
26
|
+
@sms = sms_arg
|
27
|
+
|
28
|
+
set_originator(sms.originator)
|
29
|
+
|
30
|
+
perform_operator_adaptation sms.to
|
31
|
+
|
32
|
+
results = []
|
33
|
+
parts.each_with_index do |part, i|
|
34
|
+
return false if part.empty?
|
35
|
+
# if we have several parts, send them as concatenated sms using UDH codes
|
36
|
+
soap_body["userDataHeader"] = concatenation_udh(i+1, parts.length) if parts.length > 1
|
37
|
+
soap_body["userData"] = part
|
38
|
+
soap_body["correlationId"] = Time.now.strftime('%Y%m%d%H%M%S') + sms.to + (i+1).to_s
|
39
|
+
results << send_one_sms
|
40
|
+
|
41
|
+
# halt and use fallback on error...
|
42
|
+
unless results.last[:response_code].to_s == "0"
|
43
|
+
logger.info "IPX_ERROR: #{results.last}"
|
44
|
+
return fallback_to_twilio || results.first
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# we don't actually return the status for any of additional messages which is cheating
|
49
|
+
results.first
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
attr_reader :sms
|
55
|
+
|
56
|
+
def soap_body
|
57
|
+
@soap_body ||= {
|
58
|
+
"correlationId" => Time.now.strftime('%Y%m%d%H%M%S') + sms.to,
|
29
59
|
"originatingAddress" => account[:shortcode],
|
30
60
|
"originatorTON" => "0",
|
31
|
-
"destinationAddress" =>
|
61
|
+
"destinationAddress" => sms.to,
|
32
62
|
"userData" => "",
|
33
63
|
"userDataHeader" => "#NULL#",
|
34
64
|
"DCS" => "-1",
|
@@ -37,7 +67,7 @@ module Smess
|
|
37
67
|
"deliveryTime" => "#NULL#",
|
38
68
|
"statusReportFlags" => "1", # 1
|
39
69
|
"accountName" => account[:account_name],
|
40
|
-
"tariffClass" => "USD0",
|
70
|
+
"tariffClass" => "USD0", # needs to be extracted and variable per country
|
41
71
|
"VAT" => "-1",
|
42
72
|
"referenceId" => "#NULL#",
|
43
73
|
"serviceName" => account[:service_name],
|
@@ -49,63 +79,6 @@ module Smess
|
|
49
79
|
}
|
50
80
|
end
|
51
81
|
|
52
|
-
def deliver_sms(sms)
|
53
|
-
return false unless sms.kind_of? Sms
|
54
|
-
|
55
|
-
@sms = sms
|
56
|
-
build_sms_payload
|
57
|
-
|
58
|
-
set_originator sms.originator
|
59
|
-
@sms_options["destinationAddress"] = sms.to
|
60
|
-
|
61
|
-
perform_operator_adaptation sms.to
|
62
|
-
|
63
|
-
# validate sms contents
|
64
|
-
parts = Smess.split_sms(sms.message.strip_nongsm_chars)
|
65
|
-
return false if parts[0].empty?
|
66
|
-
# if we have several parts, send them as concatenated sms
|
67
|
-
if parts.length > 1
|
68
|
-
logger.info "Num Parts: #{parts.length.to_s}"
|
69
|
-
# create concat-sms smpp header
|
70
|
-
ref_id = Random.new.rand(255).to_s(16).rjust(2,"0")
|
71
|
-
num_parts = parts.length
|
72
|
-
@sms_options["userDataHeader"] = "050003#{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}
|
73
|
-
end
|
74
|
-
|
75
|
-
@sms_options["userData"] = parts.shift
|
76
|
-
|
77
|
-
result = send_one_sms
|
78
|
-
result[:data] = @sms_options.dup
|
79
|
-
result[:data].delete "password"
|
80
|
-
result[:data]["userData"] = sms.message.strip_nongsm_chars
|
81
|
-
|
82
|
-
# fallback...
|
83
|
-
unless result[:response_code].to_s == "0"
|
84
|
-
logger.info "IPX_ERROR: #{result}"
|
85
|
-
return fallback_to_twilio
|
86
|
-
end
|
87
|
-
|
88
|
-
# send aditional parts if we have them
|
89
|
-
if parts.length > 0 && result[:response_code] != "-1"
|
90
|
-
logger.info "Sending more parts..."
|
91
|
-
set_originator sms.originator
|
92
|
-
@sms_options["destinationAddress"] = sms.to
|
93
|
-
|
94
|
-
more_results = []
|
95
|
-
parts.each_with_index do |part,i|
|
96
|
-
logger.info "Sending Part #{(i+2).to_s}"
|
97
|
-
@sms_options["userData"] = part
|
98
|
-
@sms_options["userDataHeader"] = "050003#{ref_id}#{num_parts.to_s(16).rjust(2,'0')}#{(i+2).to_s(16).rjust(2,'0')}"
|
99
|
-
@sms_options["correlationId"] = Time.now.strftime('%Y%m%d%H%M%S') + @sms.to + (i+1).to_s
|
100
|
-
more_results << send_one_sms
|
101
|
-
# we don't actually return the status for any of these which is cheating
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
result
|
106
|
-
end
|
107
|
-
|
108
|
-
private
|
109
82
|
|
110
83
|
def soap_client
|
111
84
|
Savon.configure do |config|
|
@@ -113,7 +86,6 @@ module Smess
|
|
113
86
|
config.raise_errors = false
|
114
87
|
end
|
115
88
|
|
116
|
-
|
117
89
|
endpoint = @endpoint
|
118
90
|
mm7ns = wsdl_namespace
|
119
91
|
credentials = @credentials
|
@@ -133,8 +105,8 @@ module Smess
|
|
133
105
|
# and being able to reduce non-deliveries by more than half
|
134
106
|
# is a big deal when sending transactional messages.
|
135
107
|
def fallback_to_twilio
|
136
|
-
|
137
|
-
|
108
|
+
sms.output = :twilio
|
109
|
+
sms.deliver
|
138
110
|
end
|
139
111
|
|
140
112
|
def get_response_hash_from(response)
|
@@ -146,8 +118,8 @@ module Smess
|
|
146
118
|
end
|
147
119
|
|
148
120
|
def set_originator(originator)
|
149
|
-
|
150
|
-
|
121
|
+
soap_body["originatingAddress"] = originator
|
122
|
+
soap_body["originatorTON"] = (originator.length == 5 && originator.to_i.to_s == originator) ? "0" : "1"
|
151
123
|
end
|
152
124
|
|
153
125
|
def xmlns
|
@@ -158,59 +130,83 @@ module Smess
|
|
158
130
|
"http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-6-MM7-1-2"
|
159
131
|
end
|
160
132
|
|
133
|
+
def parts
|
134
|
+
@parts ||= split_parts
|
135
|
+
end
|
136
|
+
|
137
|
+
def split_parts
|
138
|
+
Smess.split_sms(sms.message.strip_nongsm_chars).reject {|s| s.empty? }
|
139
|
+
end
|
140
|
+
|
141
|
+
# {050003}{ff}{02}{01} {concat-command}{id to link all parts}{total num parts}{num of current part}
|
142
|
+
def concatenation_udh(num, total)
|
143
|
+
"050003#{ref_id}#{total.to_s(16).rjust(2,'0')}#{(num).to_s(16).rjust(2,'0')}"
|
144
|
+
end
|
145
|
+
|
146
|
+
def ref_id
|
147
|
+
@ref_id ||= Random.new.rand(255).to_s(16).rjust(2,"0")
|
148
|
+
end
|
149
|
+
|
161
150
|
def send_one_sms
|
162
151
|
client = soap_client
|
163
|
-
|
152
|
+
soap_body_var = soap_body
|
164
153
|
begin
|
165
154
|
response = client.request "SendRequest", "xmlns" => xmlns do
|
166
|
-
soap.body =
|
155
|
+
soap.body = soap_body_var
|
167
156
|
end
|
157
|
+
result = parse_sms_response(response)
|
168
158
|
rescue Exception => e
|
169
|
-
result =
|
170
|
-
:response_code => "-1",
|
171
|
-
:response => {
|
172
|
-
:temporaryError =>"true",
|
173
|
-
:responseCode => "-1",
|
174
|
-
:responseText => "MM: System Communication Error. #{e.inspect}"
|
175
|
-
}
|
176
|
-
}
|
159
|
+
result = result_for_error(e)
|
177
160
|
# LOG error here?
|
178
|
-
return result
|
179
161
|
end
|
180
|
-
|
162
|
+
result
|
181
163
|
end
|
182
164
|
|
183
|
-
|
184
165
|
def parse_sms_response(response)
|
185
|
-
# logger.debug " --- "
|
186
|
-
# logger.debug response.to_hash
|
187
|
-
# logger.debug " --- "
|
188
166
|
if response.http_error? || response.soap_fault?
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
:responseCode => "-1",
|
194
|
-
:responseText => response.http_error || response.soap_fault.to_hash
|
195
|
-
}
|
196
|
-
}
|
197
|
-
# LOG error here?
|
198
|
-
return result
|
167
|
+
e = Struct.new(:code, :message).new("-1", response.http_error || response.soap_fault.to_hash)
|
168
|
+
result = result_for_error(e)
|
169
|
+
else
|
170
|
+
result = normal_result(response)
|
199
171
|
end
|
172
|
+
result
|
173
|
+
end
|
200
174
|
|
175
|
+
def result_for_error(e)
|
176
|
+
code = e.code rescue "-1"
|
177
|
+
{
|
178
|
+
response_code: '-1',
|
179
|
+
response: {
|
180
|
+
temporaryError: 'true',
|
181
|
+
responseCode: code,
|
182
|
+
responseText: e.message
|
183
|
+
},
|
184
|
+
data: result_data
|
185
|
+
}
|
186
|
+
end
|
201
187
|
|
188
|
+
def normal_result(response)
|
202
189
|
hash = response.to_hash[:send_response]
|
203
190
|
message_id = ""
|
204
191
|
message_id = hash[:message_id] if hash.has_key? :message_id
|
205
192
|
response_code = hash[:response_code]
|
206
193
|
|
207
|
-
|
208
|
-
:
|
209
|
-
:
|
210
|
-
:
|
194
|
+
{
|
195
|
+
message_id: message_id,
|
196
|
+
response_code: response_code,
|
197
|
+
response: hash,
|
198
|
+
destination_address: sms.to,
|
199
|
+
data: result_data
|
211
200
|
}
|
212
201
|
end
|
213
202
|
|
203
|
+
def result_data
|
204
|
+
data = soap_body.dup
|
205
|
+
data.delete "password"
|
206
|
+
data["userData"] = sms.message.strip_nongsm_chars
|
207
|
+
data
|
208
|
+
end
|
209
|
+
|
214
210
|
|
215
211
|
# Called before final message assembly
|
216
212
|
# used to look up the operator and make changes to the SOAP data for some carriers
|
data/lib/smess/outputs/ipxus.rb
CHANGED
@@ -23,15 +23,10 @@ module Smess
|
|
23
23
|
# Called before final message assembly
|
24
24
|
# used to look up the operator and make changes to the MM7 for Verizon and T-mobile
|
25
25
|
def perform_operator_adaptation(msisdn)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
operator_data = lookup_operator msisdn
|
31
|
-
unless operator_data[:operator].nil?
|
32
|
-
method_name = "adapt_for_#{operator_data[:operator].to_underscore.gsub(" ","_")}"
|
33
|
-
send(method_name,msisdn) if respond_to?(:"#{method_name}", true)
|
34
|
-
end
|
26
|
+
operator_data = lookup_operator msisdn
|
27
|
+
unless operator_data[:operator].nil?
|
28
|
+
method_name = "adapt_for_#{operator_data[:operator].to_underscore.gsub(" ","_")}"
|
29
|
+
send(method_name, msisdn) if respond_to?(:"#{method_name}", true)
|
35
30
|
end
|
36
31
|
end
|
37
32
|
|
@@ -54,49 +49,33 @@ module Smess
|
|
54
49
|
response = client.request "ResolveOperatorRequest", "xmlns"=>"http://www.ipx.com/api/services/consumerlookupapi09/types" do
|
55
50
|
soap.body = body
|
56
51
|
end
|
52
|
+
result = parse_operator_response(response)
|
57
53
|
rescue Exception => e
|
58
|
-
result =
|
59
|
-
|
60
|
-
:response => {
|
61
|
-
:temporaryError =>"true",
|
62
|
-
:responseCode => "-1",
|
63
|
-
:responseText => "MM: System Communication Error"
|
64
|
-
}
|
65
|
-
}
|
66
|
-
# LOG error here?
|
54
|
+
result = result_for_error(e)
|
55
|
+
ensure
|
67
56
|
@endpoint = orig_endpoint
|
68
57
|
@credentials = orig_credentials
|
69
|
-
return result
|
70
58
|
end
|
71
|
-
|
72
|
-
@credentials = orig_credentials
|
73
|
-
return parse_operator_response response
|
59
|
+
result
|
74
60
|
end
|
75
61
|
|
76
62
|
def parse_operator_response(response)
|
77
63
|
if response.http_error? || response.soap_fault?
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
:responseCode => "-1",
|
83
|
-
:responseText => response.http_error || response.soap_fault.to_hash
|
84
|
-
}
|
85
|
-
}
|
86
|
-
# LOG error here?
|
87
|
-
return result
|
64
|
+
e = Struct.new(:code, :message).new("-1", response.http_error || response.soap_fault.to_hash)
|
65
|
+
result = result_for_error(e)
|
66
|
+
else
|
67
|
+
result = response.to_hash[:resolve_operator_response]
|
88
68
|
end
|
89
|
-
|
90
|
-
hash = response.to_hash[:resolve_operator_response]
|
69
|
+
result
|
91
70
|
end
|
92
71
|
|
93
72
|
|
94
73
|
def adapt_for_verizon(msisdn)
|
95
|
-
|
74
|
+
soap_body["serviceMetaData"] = account[:service_meta_data_verizon]
|
96
75
|
end
|
97
76
|
|
98
77
|
def adapt_for_t_mobile_us(msisdn)
|
99
|
-
|
78
|
+
soap_body["serviceMetaData"] = account[:service_meta_data_t_mobile_us]
|
100
79
|
end
|
101
80
|
|
102
81
|
end
|
data/lib/smess/outputs/mblox.rb
CHANGED
@@ -5,13 +5,39 @@ module Smess
|
|
5
5
|
class Smsglobal
|
6
6
|
include Smess::Logging
|
7
7
|
|
8
|
-
def deliver_sms(
|
9
|
-
return false unless
|
8
|
+
def deliver_sms(sms_arg)
|
9
|
+
return false unless sms_arg.kind_of? Sms
|
10
|
+
@sms = sms_arg
|
10
11
|
|
11
|
-
url =
|
12
|
-
|
12
|
+
request.url = url
|
13
|
+
request.body = params
|
14
|
+
|
15
|
+
begin
|
16
|
+
HTTPI.log_level = :debug
|
17
|
+
response = HTTPI.post request
|
18
|
+
result = normal_result(response)
|
19
|
+
rescue Exception => e
|
20
|
+
puts logger.warn response
|
21
|
+
# connection problem or some error
|
22
|
+
result = result_for_error(e)
|
23
|
+
end
|
24
|
+
result
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
13
28
|
|
14
|
-
|
29
|
+
attr_reader :sms
|
30
|
+
|
31
|
+
def url
|
32
|
+
"https://www.smsglobal.com/http-api.php"
|
33
|
+
end
|
34
|
+
|
35
|
+
def from
|
36
|
+
sms.originator || ENV["SMESS_SMSGLOBAL_SENDER_ID"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def params
|
40
|
+
@params ||= {
|
15
41
|
action: "sendsms",
|
16
42
|
user: ENV["SMESS_SMSGLOBAL_USER"],
|
17
43
|
password: ENV["SMESS_SMSGLOBAL_PASS"],
|
@@ -20,50 +46,45 @@ module Smess
|
|
20
46
|
text: sms.message.strip_nongsm_chars,
|
21
47
|
maxsplit: "3"
|
22
48
|
}
|
49
|
+
end
|
23
50
|
|
24
|
-
|
25
|
-
request
|
26
|
-
|
51
|
+
def request
|
52
|
+
@request ||= HTTPI::Request.new
|
53
|
+
end
|
27
54
|
|
28
|
-
|
29
|
-
|
30
|
-
|
55
|
+
def result_for_error(e)
|
56
|
+
code = e.code rescue "-1"
|
57
|
+
{
|
58
|
+
response_code: '-1',
|
59
|
+
response: {
|
60
|
+
temporaryError: 'true',
|
61
|
+
responseCode: e.code,
|
62
|
+
responseText: e.message
|
63
|
+
},
|
64
|
+
data: result_data
|
65
|
+
}
|
66
|
+
end
|
31
67
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
68
|
+
def normal_result(response)
|
69
|
+
first_response = response.body.split(/\r\n/).first.split(";")
|
70
|
+
response_code = first_response.first.split(':').last.to_i
|
71
|
+
message_id = first_response.last.split('SMSGlobalMsgID:').last
|
72
|
+
# Successful response
|
73
|
+
{
|
74
|
+
message_id: message_id,
|
75
|
+
response_code: response_code.to_s,
|
76
|
+
response: response.body,
|
77
|
+
destination_address: sms.to,
|
78
|
+
data: result_data
|
79
|
+
}
|
80
|
+
end
|
52
81
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
data: {
|
60
|
-
to: sms.to,
|
61
|
-
text: sms.message.strip_nongsm_chars,
|
62
|
-
from: from
|
63
|
-
}
|
64
|
-
}
|
65
|
-
end
|
66
|
-
result
|
82
|
+
def result_data
|
83
|
+
{
|
84
|
+
to: sms.to,
|
85
|
+
text: sms.message.strip_nongsm_chars,
|
86
|
+
from: from
|
87
|
+
}
|
67
88
|
end
|
68
89
|
|
69
90
|
end
|
data/lib/smess/utils.rb
CHANGED
@@ -1,46 +1,8 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
3
|
module Smess
|
4
|
-
|
5
4
|
class << self
|
6
5
|
|
7
|
-
# cleans and forces the selected country prefix on the number given
|
8
|
-
# if international is set a lighter cleaning is done to preserve any existing country code
|
9
|
-
# this is not entirely problem-free for US area codes without leading 0.
|
10
|
-
def clean_phone(num)
|
11
|
-
num = num.to_s
|
12
|
-
|
13
|
-
return nil if /\{[a-z]+:.+\}/.match(num)
|
14
|
-
|
15
|
-
# make num all digits
|
16
|
-
num = num.gsub(/\D/,"")
|
17
|
-
|
18
|
-
if num.length > 0 && num[0..1] == "00"
|
19
|
-
num = num[2..-1]
|
20
|
-
elsif num.length > 0 && num[0] == "0"
|
21
|
-
# cut away leading zeros
|
22
|
-
num = num[1..-1] # while num[0] == "0"
|
23
|
-
# Add country code unless the start of the number is the correct country code
|
24
|
-
unless num[0..Smess.config.country_code.to_s.length-1] == Smess.config.country_code.to_s
|
25
|
-
num = Smess.config.country_code.to_s + num
|
26
|
-
end
|
27
|
-
elsif !Smess.config.international
|
28
|
-
# Add country code unless the start of the number is the correct country code
|
29
|
-
unless num[0..Smess.config.country_code.to_s.length-1] == Smess.config.country_code.to_s
|
30
|
-
num = Smess.config.country_code.to_s + num
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# number must be in a valid range
|
35
|
-
unless (10..15) === num.length
|
36
|
-
return nil
|
37
|
-
end
|
38
|
-
|
39
|
-
num
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
6
|
# returns an array of strings of gsm-compatible lengths
|
45
7
|
# performance issue: utf8_safe_split also loops over the split point
|
46
8
|
# this should be used when sending via concatenating providers
|
data/lib/smess/version.rb
CHANGED
data/lib/string.rb
CHANGED
@@ -47,7 +47,7 @@ class String
|
|
47
47
|
# Should this be a patch to String?
|
48
48
|
|
49
49
|
# keeping them here in canse I need them
|
50
|
-
|
50
|
+
# basic alpha
|
51
51
|
# '@','£','$','¥','è','é','ù','ì','ò','Ç',"\n",'Ø','ø',"\r",'Å','å',
|
52
52
|
# 'Δ','_','Φ','Γ','Λ','Ω','Π','Ψ','Σ','Θ','Ξ','Æ','æ','ß','É',' ',
|
53
53
|
# '!','"','#','¤','%','&','\'','(',')','*','+',',','-','.','/','0',
|
@@ -56,9 +56,9 @@ class String
|
|
56
56
|
# 'Q','R','S','T','U','V','W','X','Y','Z','Ä','Ö','Ñ','Ü','§','¿',
|
57
57
|
# 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',
|
58
58
|
# 'q','r','s','t','u','v','w','x','y','z','ä','ö','ñ','ü','à'
|
59
|
-
#
|
60
|
-
|
61
|
-
|
59
|
+
#
|
60
|
+
# extended alpha
|
61
|
+
# '|','^','€','{','}','[',']','~','\\'
|
62
62
|
|
63
63
|
allowed = '@£$¥èéùìòÇ'+"\n"+'Øø'+"\r"+'ÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ'+' '+Regexp.escape('!"#¤%&\'()*+,-.')+'\/'+Regexp.escape('0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà|^€{}[]~\\')
|
64
64
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smess
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Westin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -152,7 +152,6 @@ files:
|
|
152
152
|
- lib/smess/outputs/ipx.rb
|
153
153
|
- lib/smess/outputs/ipxus.rb
|
154
154
|
- lib/smess/outputs/mblox.rb
|
155
|
-
- lib/smess/outputs/mm7.rb
|
156
155
|
- lib/smess/outputs/smsglobal.rb
|
157
156
|
- lib/smess/outputs/test.rb
|
158
157
|
- lib/smess/outputs/twilio.rb
|
@@ -166,7 +165,8 @@ files:
|
|
166
165
|
- LICENSE
|
167
166
|
- README.md
|
168
167
|
homepage: https://github.com/eimermusic/smess
|
169
|
-
licenses:
|
168
|
+
licenses:
|
169
|
+
- MIT
|
170
170
|
metadata: {}
|
171
171
|
post_install_message:
|
172
172
|
rdoc_options: []
|
data/lib/smess/outputs/mm7.rb
DELETED
@@ -1,122 +0,0 @@
|
|
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
|