smess 1.0.0 → 1.0.1
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.
- 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
|
+
[](http://badge.fury.io/rb/smess)
|
|
2
|
+
[](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
|