ruby-smpp 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +3 -7
- data/README.rdoc +1 -0
- data/Rakefile +0 -2
- data/VERSION +1 -1
- data/lib/smpp/base.rb +109 -5
- data/lib/smpp/encoding/utf8_encoder.rb +37 -0
- data/lib/smpp/optional_parameter.rb +4 -0
- data/lib/smpp/pdu/base.rb +3 -1
- data/lib/smpp/pdu/deliver_sm.rb +15 -3
- data/lib/smpp/pdu/submit_multi.rb +1 -1
- data/lib/smpp/pdu/submit_sm.rb +1 -1
- data/lib/smpp/pdu/submit_sm_response.rb +18 -4
- data/lib/smpp/receiver.rb +1 -54
- data/lib/smpp/transceiver.rb +20 -100
- data/ruby-smpp.gemspec +77 -66
- data/test/encoding_test.rb +231 -0
- data/test/pdu_parsing_test.rb +29 -2
- data/test/receiver_test.rb +36 -1
- data/test/transceiver_test.rb +35 -0
- metadata +65 -12
- data/.gitignore +0 -24
data/Gemfile.lock
CHANGED
@@ -2,16 +2,12 @@ GEM
|
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
4
|
eventmachine (0.12.10)
|
5
|
-
gemcutter (0.6.1)
|
6
5
|
git (1.2.5)
|
7
|
-
jeweler (1.
|
8
|
-
|
6
|
+
jeweler (1.5.2)
|
7
|
+
bundler (~> 1.0.0)
|
9
8
|
git (>= 1.2.5)
|
10
|
-
|
11
|
-
json_pure (1.4.6)
|
9
|
+
rake
|
12
10
|
rake (0.8.7)
|
13
|
-
rubyforge (2.0.4)
|
14
|
-
json_pure (>= 1.1.7)
|
15
11
|
|
16
12
|
PLATFORMS
|
17
13
|
ruby
|
data/README.rdoc
CHANGED
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/lib/smpp/base.rb
CHANGED
@@ -13,6 +13,22 @@ module Smpp
|
|
13
13
|
# :bound or :unbound
|
14
14
|
attr_accessor :state
|
15
15
|
|
16
|
+
def initialize(config, delegate)
|
17
|
+
@state = :unbound
|
18
|
+
@config = config
|
19
|
+
@data = ""
|
20
|
+
@delegate = delegate
|
21
|
+
@pdr_storage = pdr_storage={}
|
22
|
+
|
23
|
+
# Array of un-acked MT message IDs indexed by sequence number.
|
24
|
+
# As soon as we receive SubmitSmResponse we will use this to find the
|
25
|
+
# associated message ID, and then create a pending delivery report.
|
26
|
+
@ack_ids = {}
|
27
|
+
|
28
|
+
ed = @config[:enquire_link_delay_secs] || 5
|
29
|
+
comm_inactivity_timeout = 2 * ed
|
30
|
+
end
|
31
|
+
|
16
32
|
# queries the state of the transmitter - is it bound?
|
17
33
|
def unbound?
|
18
34
|
@state == :unbound
|
@@ -34,11 +50,6 @@ module Smpp
|
|
34
50
|
@@logger
|
35
51
|
end
|
36
52
|
|
37
|
-
def initialize(config)
|
38
|
-
@state = :unbound
|
39
|
-
@config = config
|
40
|
-
@data = ""
|
41
|
-
end
|
42
53
|
|
43
54
|
# invoked by EventMachine when connected
|
44
55
|
def post_init
|
@@ -140,6 +151,99 @@ module Smpp
|
|
140
151
|
logger.warn "Received NACK! (error code #{pdu.error_code})."
|
141
152
|
# we don't take this lightly: close the connection
|
142
153
|
close_connection
|
154
|
+
when Pdu::DeliverSm
|
155
|
+
logger.debug "ESM CLASS #{pdu.esm_class}"
|
156
|
+
if pdu.esm_class != 4
|
157
|
+
# MO message
|
158
|
+
begin
|
159
|
+
if @delegate.respond_to?(:mo_received)
|
160
|
+
@delegate.mo_received(self, pdu)
|
161
|
+
end
|
162
|
+
write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number))
|
163
|
+
rescue => e
|
164
|
+
logger.warn "Send Receiver Temporary App Error due to #{e.inspect} raised in delegate"
|
165
|
+
write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number, Pdu::Base::ESME_RX_T_APPN))
|
166
|
+
end
|
167
|
+
else
|
168
|
+
# Delivery report
|
169
|
+
if @delegate.respond_to?(:delivery_report_received)
|
170
|
+
@delegate.delivery_report_received(self, pdu)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
when Pdu::BindTransceiverResponse
|
174
|
+
case pdu.command_status
|
175
|
+
when Pdu::Base::ESME_ROK
|
176
|
+
logger.debug "Bound OK."
|
177
|
+
@state = :bound
|
178
|
+
if @delegate.respond_to?(:bound)
|
179
|
+
@delegate.bound(self)
|
180
|
+
end
|
181
|
+
when Pdu::Base::ESME_RINVPASWD
|
182
|
+
logger.warn "Invalid password."
|
183
|
+
# scheduele the connection to close, which eventually will cause the unbound() delegate
|
184
|
+
# method to be invoked.
|
185
|
+
close_connection
|
186
|
+
when Pdu::Base::ESME_RINVSYSID
|
187
|
+
logger.warn "Invalid system id."
|
188
|
+
close_connection
|
189
|
+
else
|
190
|
+
logger.warn "Unexpected BindTransceiverResponse. Command status: #{pdu.command_status}"
|
191
|
+
close_connection
|
192
|
+
end
|
193
|
+
when Pdu::SubmitSmResponse
|
194
|
+
mt_message_id = @ack_ids.delete(pdu.sequence_number)
|
195
|
+
if !mt_message_id
|
196
|
+
raise "Got SubmitSmResponse for unknown sequence_number: #{pdu.sequence_number}"
|
197
|
+
end
|
198
|
+
if pdu.command_status != Pdu::Base::ESME_ROK
|
199
|
+
logger.error "Error status in SubmitSmResponse: #{pdu.command_status}"
|
200
|
+
if @delegate.respond_to?(:message_rejected)
|
201
|
+
@delegate.message_rejected(self, mt_message_id, pdu)
|
202
|
+
end
|
203
|
+
else
|
204
|
+
logger.info "Got OK SubmitSmResponse (#{pdu.message_id} -> #{mt_message_id})"
|
205
|
+
if @delegate.respond_to?(:message_accepted)
|
206
|
+
@delegate.message_accepted(self, mt_message_id, pdu)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
# Now we got the SMSC message id; create pending delivery report.
|
210
|
+
@pdr_storage[pdu.message_id] = mt_message_id
|
211
|
+
when Pdu::SubmitMultiResponse
|
212
|
+
mt_message_id = @ack_ids[pdu.sequence_number]
|
213
|
+
if !mt_message_id
|
214
|
+
raise "Got SubmitMultiResponse for unknown sequence_number: #{pdu.sequence_number}"
|
215
|
+
end
|
216
|
+
if pdu.command_status != Pdu::Base::ESME_ROK
|
217
|
+
logger.error "Error status in SubmitMultiResponse: #{pdu.command_status}"
|
218
|
+
if @delegate.respond_to?(:message_rejected)
|
219
|
+
@delegate.message_rejected(self, mt_message_id, pdu)
|
220
|
+
end
|
221
|
+
else
|
222
|
+
logger.info "Got OK SubmitMultiResponse (#{pdu.message_id} -> #{mt_message_id})"
|
223
|
+
if @delegate.respond_to?(:message_accepted)
|
224
|
+
@delegate.message_accepted(self, mt_message_id, pdu)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
when Pdu::BindReceiverResponse
|
228
|
+
case pdu.command_status
|
229
|
+
when Pdu::Base::ESME_ROK
|
230
|
+
logger.debug "Bound OK."
|
231
|
+
@state = :bound
|
232
|
+
if @delegate.respond_to?(:bound)
|
233
|
+
@delegate.bound(self)
|
234
|
+
end
|
235
|
+
when Pdu::Base::ESME_RINVPASWD
|
236
|
+
logger.warn "Invalid password."
|
237
|
+
# scheduele the connection to close, which eventually will cause the unbound() delegate
|
238
|
+
# method to be invoked.
|
239
|
+
close_connection
|
240
|
+
when Pdu::Base::ESME_RINVSYSID
|
241
|
+
logger.warn "Invalid system id."
|
242
|
+
close_connection
|
243
|
+
else
|
244
|
+
logger.warn "Unexpected BindReceiverResponse. Command status: #{pdu.command_status}"
|
245
|
+
close_connection
|
246
|
+
end
|
143
247
|
else
|
144
248
|
logger.warn "(#{self.class.name}) Received unexpected PDU: #{pdu.to_human}."
|
145
249
|
close_connection
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'iconv'
|
2
|
+
|
3
|
+
module Smpp
|
4
|
+
module Encoding
|
5
|
+
|
6
|
+
# This class is not required by smpp.rb at all, you need to bring it in yourself.
|
7
|
+
# This class also requires iconv, you'll need to ensure it is installed.
|
8
|
+
class Utf8Encoder
|
9
|
+
|
10
|
+
EURO_TOKEN = "_X_EURO_X_"
|
11
|
+
|
12
|
+
GSM_ESCAPED_CHARACTERS = {
|
13
|
+
?( => "\173", # {
|
14
|
+
?) => "\175", # }
|
15
|
+
184 => "\174", # |
|
16
|
+
?< => "\133", # [
|
17
|
+
?> => "\135", # ]
|
18
|
+
?= => "\176", # ~
|
19
|
+
?/ => "\134", # \
|
20
|
+
134 => "\252", # ^
|
21
|
+
?e => EURO_TOKEN
|
22
|
+
}
|
23
|
+
|
24
|
+
def encode(data_coding, short_message)
|
25
|
+
if data_coding < 2
|
26
|
+
sm = short_message.gsub(/\215./) { |match| GSM_ESCAPED_CHARACTERS[match[1]] }
|
27
|
+
sm = Iconv.conv("UTF-8", "HP-ROMAN8", sm)
|
28
|
+
sm.gsub(EURO_TOKEN, "\342\202\254")
|
29
|
+
elsif data_coding == 8
|
30
|
+
Iconv.conv("UTF-8", "UTF-16BE", short_message)
|
31
|
+
else
|
32
|
+
short_message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/smpp/pdu/base.rb
CHANGED
@@ -39,6 +39,8 @@ module Smpp::Pdu
|
|
39
39
|
ESME_RINVNUMMSGS = 0x00000055 # Invalid number of messages
|
40
40
|
ESME_RTHROTTLED = 0x00000058 # Throttling error (ESME has exceeded allowed message limits)
|
41
41
|
|
42
|
+
ESME_RX_T_APPN = 0x00000064 # ESME Receiver Temporary App Error Code
|
43
|
+
|
42
44
|
# PDU types
|
43
45
|
GENERIC_NACK = 0X80000000
|
44
46
|
BIND_RECEIVER = 0X00000001
|
@@ -166,7 +168,7 @@ module Smpp::Pdu
|
|
166
168
|
@@cmd_map[command_id] = self
|
167
169
|
end
|
168
170
|
|
169
|
-
def Base.
|
171
|
+
def Base.parse_optional_parameters(remaining_bytes)
|
170
172
|
optionals = {}
|
171
173
|
while not remaining_bytes.empty?
|
172
174
|
optional = {}
|
data/lib/smpp/pdu/deliver_sm.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
|
+
|
1
2
|
# Received for MO message or delivery notification
|
2
3
|
class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
|
3
4
|
handles_cmd DELIVER_SM
|
5
|
+
|
4
6
|
attr_reader :service_type, :source_addr_ton, :source_addr_npi, :source_addr, :dest_addr_ton, :dest_addr_npi,
|
5
7
|
:destination_addr, :esm_class, :protocol_id, :priority_flag, :schedule_delivery_time,
|
6
8
|
:validity_period, :registered_delivery, :replace_if_present_flag, :data_coding,
|
7
9
|
:sm_default_msg_id, :sm_length, :stat, :msg_reference, :udh, :short_message,
|
8
10
|
:message_state, :receipted_message_id, :optional_parameters
|
9
11
|
|
12
|
+
@@encoder = nil
|
13
|
+
|
10
14
|
def initialize(source_addr, destination_addr, short_message, options={}, seq=nil)
|
11
15
|
|
12
16
|
@udh = options[:udh]
|
@@ -83,7 +87,7 @@ class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
|
|
83
87
|
short_message = remaining_bytes.slice!(0...options[:sm_length])
|
84
88
|
|
85
89
|
#everything left in remaining_bytes is 3.4 optional parameters
|
86
|
-
options[:optional_parameters] =
|
90
|
+
options[:optional_parameters] = parse_optional_parameters(remaining_bytes)
|
87
91
|
|
88
92
|
#parse the 'standard' optional parameters for delivery receipts
|
89
93
|
options[:optional_parameters].each do |tag, tlv|
|
@@ -123,8 +127,16 @@ class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
|
|
123
127
|
Smpp::Base.logger.debug "DeliverSM with source_addr=#{source_addr}, destination_addr=#{destination_addr}, msg_reference=#{options[:msg_reference]}, stat=#{options[:stat]}"
|
124
128
|
else
|
125
129
|
Smpp::Base.logger.debug "DeliverSM with source_addr=#{source_addr}, destination_addr=#{destination_addr}"
|
126
|
-
end
|
127
|
-
|
130
|
+
end
|
131
|
+
|
132
|
+
#yield the data_coding and short_message to the encoder if one is set
|
133
|
+
short_message = @@encoder.encode(options[:data_coding], short_message) if @@encoder.respond_to?(:encode)
|
134
|
+
|
128
135
|
new(source_addr, destination_addr, short_message, options, seq)
|
129
136
|
end
|
137
|
+
|
138
|
+
#set an encoder that can be called to yield the data_coding and short_message
|
139
|
+
def self.data_encoder=(encoder)
|
140
|
+
@@encoder = encoder
|
141
|
+
end
|
130
142
|
end
|
data/lib/smpp/pdu/submit_sm.rb
CHANGED
@@ -81,7 +81,7 @@ class Smpp::Pdu::SubmitSm < Smpp::Pdu::Base
|
|
81
81
|
short_message = remaining_bytes.slice!(0...options[:sm_length])
|
82
82
|
|
83
83
|
#everything left in remaining_bytes is 3.4 optional parameters
|
84
|
-
options[:optional_parameters] =
|
84
|
+
options[:optional_parameters] = parse_optional_parameters(remaining_bytes)
|
85
85
|
|
86
86
|
Smpp::Base.logger.debug "SubmitSM with source_addr=#{source_addr}, destination_addr=#{destination_addr}"
|
87
87
|
|
@@ -2,16 +2,30 @@ class Smpp::Pdu::SubmitSmResponse < Smpp::Pdu::Base
|
|
2
2
|
handles_cmd SUBMIT_SM_RESP
|
3
3
|
|
4
4
|
attr_accessor :message_id
|
5
|
+
attr_accessor :optional_parameters
|
5
6
|
|
6
|
-
def initialize(seq, status, message_id)
|
7
|
+
def initialize(seq, status, message_id, optional_parameters=nil)
|
7
8
|
seq ||= next_sequence_number
|
8
9
|
body = message_id.to_s + "\000"
|
9
10
|
super(SUBMIT_SM_RESP, status, seq, body)
|
10
11
|
@message_id = message_id
|
12
|
+
@optional_parameters = optional_parameters
|
13
|
+
end
|
14
|
+
|
15
|
+
def optional_parameter(tag)
|
16
|
+
if optional_parameters
|
17
|
+
if param = optional_parameters[tag]
|
18
|
+
param.value
|
19
|
+
end
|
20
|
+
end
|
11
21
|
end
|
12
22
|
|
13
23
|
def self.from_wire_data(seq, status, body)
|
14
|
-
message_id = body.
|
15
|
-
|
24
|
+
message_id, remaining_bytes = body.unpack("Z*a*")
|
25
|
+
optionals = nil
|
26
|
+
if remaining_bytes && !remaining_bytes.empty?
|
27
|
+
optionals = parse_optional_parameters(remaining_bytes)
|
28
|
+
end
|
29
|
+
new(seq, status, message_id, optionals)
|
16
30
|
end
|
17
|
-
end
|
31
|
+
end
|
data/lib/smpp/receiver.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
# The SMPP Receiver maintains a unidirectional connection to an SMSC.
|
3
2
|
# Provide a config hash with connection options to get started.
|
4
3
|
# See the sample_gateway.rb for examples of config values.
|
@@ -12,59 +11,6 @@
|
|
12
11
|
|
13
12
|
class Smpp::Receiver < Smpp::Base
|
14
13
|
|
15
|
-
def initialize(config, delegate)
|
16
|
-
super(config)
|
17
|
-
@delegate = delegate
|
18
|
-
|
19
|
-
ed = @config[:enquire_link_delay_secs] || 5
|
20
|
-
comm_inactivity_timeout = 2 * ed
|
21
|
-
rescue Exception => ex
|
22
|
-
logger.error "Exception setting up receiver: #{ex} at #{ex.backtrace.join("\n")}"
|
23
|
-
raise
|
24
|
-
end
|
25
|
-
|
26
|
-
# a PDU is received. Parse it and invoke delegate methods.
|
27
|
-
def process_pdu(pdu)
|
28
|
-
case pdu
|
29
|
-
when Pdu::DeliverSm
|
30
|
-
write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number))
|
31
|
-
logger.debug "ESM CLASS #{pdu.esm_class}"
|
32
|
-
if pdu.esm_class != 4
|
33
|
-
# MO message
|
34
|
-
if @delegate.respond_to?(:mo_received)
|
35
|
-
@delegate.mo_received(self, pdu)
|
36
|
-
end
|
37
|
-
else
|
38
|
-
# Delivery report
|
39
|
-
if @delegate.respond_to?(:delivery_report_received)
|
40
|
-
@delegate.delivery_report_received(self, pdu)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
when Pdu::BindReceiverResponse
|
44
|
-
case pdu.command_status
|
45
|
-
when Pdu::Base::ESME_ROK
|
46
|
-
logger.debug "Bound OK."
|
47
|
-
@state = :bound
|
48
|
-
if @delegate.respond_to?(:bound)
|
49
|
-
@delegate.bound(self)
|
50
|
-
end
|
51
|
-
when Pdu::Base::ESME_RINVPASWD
|
52
|
-
logger.warn "Invalid password."
|
53
|
-
# scheduele the connection to close, which eventually will cause the unbound() delegate
|
54
|
-
# method to be invoked.
|
55
|
-
close_connection
|
56
|
-
when Pdu::Base::ESME_RINVSYSID
|
57
|
-
logger.warn "Invalid system id."
|
58
|
-
close_connection
|
59
|
-
else
|
60
|
-
logger.warn "Unexpected BindReceiverResponse. Command status: #{pdu.command_status}"
|
61
|
-
close_connection
|
62
|
-
end
|
63
|
-
else
|
64
|
-
super
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
14
|
# Send BindReceiverResponse PDU.
|
69
15
|
def send_bind
|
70
16
|
raise IOError, 'Receiver already bound.' unless unbound?
|
@@ -77,4 +23,5 @@ class Smpp::Receiver < Smpp::Base
|
|
77
23
|
@config[:source_address_range])
|
78
24
|
write_pdu(pdu)
|
79
25
|
end
|
26
|
+
|
80
27
|
end
|
data/lib/smpp/transceiver.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
# The SMPP Transceiver maintains a bidirectional connection to an SMSC.
|
3
2
|
# Provide a config hash with connection options to get started.
|
4
3
|
# See the sample_gateway.rb for examples of config values.
|
@@ -14,23 +13,6 @@
|
|
14
13
|
|
15
14
|
class Smpp::Transceiver < Smpp::Base
|
16
15
|
|
17
|
-
def initialize(config, delegate, pdr_storage={})
|
18
|
-
super(config)
|
19
|
-
@delegate = delegate
|
20
|
-
@pdr_storage = pdr_storage
|
21
|
-
|
22
|
-
# Array of un-acked MT message IDs indexed by sequence number.
|
23
|
-
# As soon as we receive SubmitSmResponse we will use this to find the
|
24
|
-
# associated message ID, and then create a pending delivery report.
|
25
|
-
@ack_ids = {}
|
26
|
-
|
27
|
-
ed = @config[:enquire_link_delay_secs] || 5
|
28
|
-
comm_inactivity_timeout = 2 * ed
|
29
|
-
rescue Exception => ex
|
30
|
-
logger.error "Exception setting up transceiver: #{ex} at #{ex.backtrace.join("\n")}"
|
31
|
-
raise
|
32
|
-
end
|
33
|
-
|
34
16
|
# Send an MT SMS message. Delegate will receive message_accepted callback when SMSC
|
35
17
|
# acknowledges, or the message_rejected callback upon error
|
36
18
|
def send_mt(message_id, source_addr, destination_addr, short_message, options={})
|
@@ -54,21 +36,22 @@ class Smpp::Transceiver < Smpp::Base
|
|
54
36
|
# Split the message into parts of 153 characters. (160 - 7 characters for UDH)
|
55
37
|
parts = []
|
56
38
|
while message.size > 0 do
|
57
|
-
parts << message.slice!(0..
|
39
|
+
parts << message.slice!(0..Smpp::Transceiver.get_message_part_size(options))
|
58
40
|
end
|
59
41
|
|
60
42
|
0.upto(parts.size-1) do |i|
|
61
43
|
udh = sprintf("%c", 5) # UDH is 5 bytes.
|
62
44
|
udh << sprintf("%c%c", 0, 3) # This is a concatenated message
|
45
|
+
|
46
|
+
#TODO Figure out why this needs to be an int here, it's a string elsewhere
|
63
47
|
udh << sprintf("%c", message_id) # The ID for the entire concatenated message
|
48
|
+
|
64
49
|
udh << sprintf("%c", parts.size) # How many parts this message consists of
|
65
50
|
udh << sprintf("%c", i+1) # This is part i+1
|
66
51
|
|
67
|
-
options =
|
68
|
-
|
69
|
-
|
70
|
-
}
|
71
|
-
|
52
|
+
options[:esm_class] = 64 # This message contains a UDH header.
|
53
|
+
options[:udh] = udh
|
54
|
+
|
72
55
|
pdu = Pdu::SubmitSm.new(source_addr, destination_addr, parts[i], options)
|
73
56
|
write_pdu pdu
|
74
57
|
|
@@ -98,82 +81,6 @@ class Smpp::Transceiver < Smpp::Base
|
|
98
81
|
end
|
99
82
|
end
|
100
83
|
|
101
|
-
# a PDU is received. Parse it and invoke delegate methods.
|
102
|
-
def process_pdu(pdu)
|
103
|
-
case pdu
|
104
|
-
when Pdu::DeliverSm
|
105
|
-
write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number))
|
106
|
-
logger.debug "ESM CLASS #{pdu.esm_class}"
|
107
|
-
if pdu.esm_class != 4
|
108
|
-
# MO message
|
109
|
-
if @delegate.respond_to?(:mo_received)
|
110
|
-
@delegate.mo_received(self, pdu)
|
111
|
-
end
|
112
|
-
else
|
113
|
-
# Delivery report
|
114
|
-
if @delegate.respond_to?(:delivery_report_received)
|
115
|
-
@delegate.delivery_report_received(self, pdu)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
when Pdu::BindTransceiverResponse
|
119
|
-
case pdu.command_status
|
120
|
-
when Pdu::Base::ESME_ROK
|
121
|
-
logger.debug "Bound OK."
|
122
|
-
@state = :bound
|
123
|
-
if @delegate.respond_to?(:bound)
|
124
|
-
@delegate.bound(self)
|
125
|
-
end
|
126
|
-
when Pdu::Base::ESME_RINVPASWD
|
127
|
-
logger.warn "Invalid password."
|
128
|
-
# scheduele the connection to close, which eventually will cause the unbound() delegate
|
129
|
-
# method to be invoked.
|
130
|
-
close_connection
|
131
|
-
when Pdu::Base::ESME_RINVSYSID
|
132
|
-
logger.warn "Invalid system id."
|
133
|
-
close_connection
|
134
|
-
else
|
135
|
-
logger.warn "Unexpected BindTransceiverResponse. Command status: #{pdu.command_status}"
|
136
|
-
close_connection
|
137
|
-
end
|
138
|
-
when Pdu::SubmitSmResponse
|
139
|
-
mt_message_id = @ack_ids.delete(pdu.sequence_number)
|
140
|
-
if !mt_message_id
|
141
|
-
raise "Got SubmitSmResponse for unknown sequence_number: #{pdu.sequence_number}"
|
142
|
-
end
|
143
|
-
if pdu.command_status != Pdu::Base::ESME_ROK
|
144
|
-
logger.error "Error status in SubmitSmResponse: #{pdu.command_status}"
|
145
|
-
if @delegate.respond_to?(:message_rejected)
|
146
|
-
@delegate.message_rejected(self, mt_message_id, pdu)
|
147
|
-
end
|
148
|
-
else
|
149
|
-
logger.info "Got OK SubmitSmResponse (#{pdu.message_id} -> #{mt_message_id})"
|
150
|
-
if @delegate.respond_to?(:message_accepted)
|
151
|
-
@delegate.message_accepted(self, mt_message_id, pdu)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
# Now we got the SMSC message id; create pending delivery report.
|
155
|
-
@pdr_storage[pdu.message_id] = mt_message_id
|
156
|
-
when Pdu::SubmitMultiResponse
|
157
|
-
mt_message_id = @ack_ids[pdu.sequence_number]
|
158
|
-
if !mt_message_id
|
159
|
-
raise "Got SubmitMultiResponse for unknown sequence_number: #{pdu.sequence_number}"
|
160
|
-
end
|
161
|
-
if pdu.command_status != Pdu::Base::ESME_ROK
|
162
|
-
logger.error "Error status in SubmitMultiResponse: #{pdu.command_status}"
|
163
|
-
if @delegate.respond_to?(:message_rejected)
|
164
|
-
@delegate.message_rejected(self, mt_message_id, pdu)
|
165
|
-
end
|
166
|
-
else
|
167
|
-
logger.info "Got OK SubmitMultiResponse (#{pdu.message_id} -> #{mt_message_id})"
|
168
|
-
if @delegate.respond_to?(:message_accepted)
|
169
|
-
@delegate.message_accepted(self, mt_message_id, pdu)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
else
|
173
|
-
super
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
84
|
# Send BindTransceiverResponse PDU.
|
178
85
|
def send_bind
|
179
86
|
raise IOError, 'Receiver already bound.' unless unbound?
|
@@ -186,4 +93,17 @@ class Smpp::Transceiver < Smpp::Base
|
|
186
93
|
@config[:source_address_range])
|
187
94
|
write_pdu(pdu)
|
188
95
|
end
|
96
|
+
|
97
|
+
# Use data_coding to find out what message part size we can use
|
98
|
+
# http://en.wikipedia.org/wiki/SMS#Message_size
|
99
|
+
def self.get_message_part_size options
|
100
|
+
return 153 if options[:data_coding].nil?
|
101
|
+
return 153 if options[:data_coding] == 0
|
102
|
+
return 134 if options[:data_coding] == 3
|
103
|
+
return 134 if options[:data_coding] == 5
|
104
|
+
return 134 if options[:data_coding] == 6
|
105
|
+
return 134 if options[:data_coding] == 7
|
106
|
+
return 67 if options[:data_coding] == 8
|
107
|
+
return 153
|
108
|
+
end
|
189
109
|
end
|
data/ruby-smpp.gemspec
CHANGED
@@ -1,101 +1,112 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ruby-smpp}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ray Krueger", "August Z. Flatby"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-04-16}
|
13
13
|
s.description = %q{Ruby implementation of the SMPP protocol, based on EventMachine. SMPP is a protocol that allows ordinary people outside the mobile network to exchange SMS messages directly with mobile operators.}
|
14
14
|
s.email = %q{raykrueger@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"CHANGELOG",
|
17
|
-
|
18
|
-
|
17
|
+
"CONTRIBUTORS.txt",
|
18
|
+
"README.rdoc"
|
19
19
|
]
|
20
20
|
s.files = [
|
21
|
-
"
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
21
|
+
"CHANGELOG",
|
22
|
+
"CONTRIBUTORS.txt",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"config/environment.rb",
|
30
|
+
"examples/PDU1.example",
|
31
|
+
"examples/PDU2.example",
|
32
|
+
"examples/sample_gateway.rb",
|
33
|
+
"examples/sample_smsc.rb",
|
34
|
+
"lib/smpp.rb",
|
35
|
+
"lib/smpp/base.rb",
|
36
|
+
"lib/smpp/encoding/utf8_encoder.rb",
|
37
|
+
"lib/smpp/optional_parameter.rb",
|
38
|
+
"lib/smpp/pdu/base.rb",
|
39
|
+
"lib/smpp/pdu/bind_base.rb",
|
40
|
+
"lib/smpp/pdu/bind_receiver.rb",
|
41
|
+
"lib/smpp/pdu/bind_receiver_response.rb",
|
42
|
+
"lib/smpp/pdu/bind_resp_base.rb",
|
43
|
+
"lib/smpp/pdu/bind_transceiver.rb",
|
44
|
+
"lib/smpp/pdu/bind_transceiver_response.rb",
|
45
|
+
"lib/smpp/pdu/deliver_sm.rb",
|
46
|
+
"lib/smpp/pdu/deliver_sm_response.rb",
|
47
|
+
"lib/smpp/pdu/enquire_link.rb",
|
48
|
+
"lib/smpp/pdu/enquire_link_response.rb",
|
49
|
+
"lib/smpp/pdu/generic_nack.rb",
|
50
|
+
"lib/smpp/pdu/submit_multi.rb",
|
51
|
+
"lib/smpp/pdu/submit_multi_response.rb",
|
52
|
+
"lib/smpp/pdu/submit_sm.rb",
|
53
|
+
"lib/smpp/pdu/submit_sm_response.rb",
|
54
|
+
"lib/smpp/pdu/unbind.rb",
|
55
|
+
"lib/smpp/pdu/unbind_response.rb",
|
56
|
+
"lib/smpp/receiver.rb",
|
57
|
+
"lib/smpp/server.rb",
|
58
|
+
"lib/smpp/transceiver.rb",
|
59
|
+
"lib/sms.rb",
|
60
|
+
"ruby-smpp.gemspec",
|
61
|
+
"test/delegate.rb",
|
62
|
+
"test/encoding_test.rb",
|
63
|
+
"test/optional_parameter_test.rb",
|
64
|
+
"test/pdu_parsing_test.rb",
|
65
|
+
"test/receiver_test.rb",
|
66
|
+
"test/responsive_delegate.rb",
|
67
|
+
"test/server.rb",
|
68
|
+
"test/smpp_test.rb",
|
69
|
+
"test/submit_sm_test.rb",
|
70
|
+
"test/transceiver_test.rb"
|
69
71
|
]
|
70
72
|
s.homepage = %q{http://github.com/raykrueger/ruby-smpp}
|
71
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
72
73
|
s.require_paths = ["lib"]
|
73
74
|
s.rubyforge_project = %q{ruby-smpp}
|
74
|
-
s.rubygems_version = %q{1.3
|
75
|
+
s.rubygems_version = %q{1.5.3}
|
75
76
|
s.summary = %q{Ruby implementation of the SMPP protocol, based on EventMachine.}
|
76
77
|
s.test_files = [
|
78
|
+
"examples/sample_gateway.rb",
|
79
|
+
"examples/sample_smsc.rb",
|
77
80
|
"test/delegate.rb",
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
81
|
+
"test/encoding_test.rb",
|
82
|
+
"test/optional_parameter_test.rb",
|
83
|
+
"test/pdu_parsing_test.rb",
|
84
|
+
"test/receiver_test.rb",
|
85
|
+
"test/responsive_delegate.rb",
|
86
|
+
"test/server.rb",
|
87
|
+
"test/smpp_test.rb",
|
88
|
+
"test/submit_sm_test.rb",
|
89
|
+
"test/transceiver_test.rb"
|
87
90
|
]
|
88
91
|
|
89
92
|
if s.respond_to? :specification_version then
|
90
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
91
93
|
s.specification_version = 3
|
92
94
|
|
93
|
-
if Gem::Version.new(Gem::
|
95
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
96
|
+
s.add_runtime_dependency(%q<jeweler>, [">= 0"])
|
97
|
+
s.add_runtime_dependency(%q<rake>, [">= 0"])
|
98
|
+
s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
|
94
99
|
s.add_runtime_dependency(%q<eventmachine>, [">= 0.10.0"])
|
95
100
|
else
|
101
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
102
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
103
|
+
s.add_dependency(%q<eventmachine>, [">= 0"])
|
96
104
|
s.add_dependency(%q<eventmachine>, [">= 0.10.0"])
|
97
105
|
end
|
98
106
|
else
|
107
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
108
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
109
|
+
s.add_dependency(%q<eventmachine>, [">= 0"])
|
99
110
|
s.add_dependency(%q<eventmachine>, [">= 0.10.0"])
|
100
111
|
end
|
101
112
|
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'smpp/encoding/utf8_encoder'
|
4
|
+
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + "../../lib/smpp")
|
6
|
+
|
7
|
+
class EncodingTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
|
10
|
+
def setup
|
11
|
+
::Smpp::Pdu::DeliverSm.data_encoder = ::Smpp::Encoding::Utf8Encoder.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def teardown
|
15
|
+
::Smpp::Pdu::DeliverSm.data_encoder = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_should_decode_pound_sign_from_hp_roman_8_to_utf_8
|
19
|
+
raw_data = <<-EOF
|
20
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
21
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
22
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
23
|
+
0000 0000 0000 0000 2950 6C65 6173 6520
|
24
|
+
6465 706F 7369 7420 BB35 2069 6E74 6F20
|
25
|
+
6D79 2061 6363 6F75 6E74 2C20 4A6F 73C5
|
26
|
+
EOF
|
27
|
+
|
28
|
+
pdu = create_pdu(raw_data)
|
29
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
30
|
+
assert_equal 0, pdu.data_coding
|
31
|
+
|
32
|
+
expected = "Please deposit \302\2435 into my account, Jos\303\251"
|
33
|
+
assert_equal expected, pdu.short_message
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_should_unescape_gsm_escaped_euro_symbol
|
37
|
+
raw_data = <<-EOF
|
38
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
39
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
40
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
41
|
+
0000 0000 0000 0000 1950 6c65 6173 6520
|
42
|
+
6465 706f 7369 7420 8d65 3520 7468 616e
|
43
|
+
6b73
|
44
|
+
EOF
|
45
|
+
|
46
|
+
pdu = create_pdu(raw_data)
|
47
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
48
|
+
assert_equal 0, pdu.data_coding
|
49
|
+
|
50
|
+
expected = "Please deposit \342\202\2545 thanks"
|
51
|
+
assert_equal expected, pdu.short_message
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_should_unescape_gsm_escaped_left_curly_bracket_symbol
|
55
|
+
raw_data = <<-EOF
|
56
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
57
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
58
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
59
|
+
0000 0000 0000 0000 028d 28
|
60
|
+
EOF
|
61
|
+
|
62
|
+
pdu = create_pdu(raw_data)
|
63
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
64
|
+
assert_equal 0, pdu.data_coding
|
65
|
+
|
66
|
+
assert_equal "{", pdu.short_message
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_should_unescape_gsm_escaped_right_curly_bracket_symbol
|
70
|
+
raw_data = <<-EOF
|
71
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
72
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
73
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
74
|
+
0000 0000 0000 0000 028d 29
|
75
|
+
EOF
|
76
|
+
|
77
|
+
pdu = create_pdu(raw_data)
|
78
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
79
|
+
assert_equal 0, pdu.data_coding
|
80
|
+
|
81
|
+
assert_equal "}", pdu.short_message
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_should_unescape_gsm_escaped_tilde_symbol
|
85
|
+
raw_data = <<-EOF
|
86
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
87
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
88
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
89
|
+
0000 0000 0000 0000 028d 3d
|
90
|
+
EOF
|
91
|
+
|
92
|
+
pdu = create_pdu(raw_data)
|
93
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
94
|
+
assert_equal 0, pdu.data_coding
|
95
|
+
|
96
|
+
assert_equal "~", pdu.short_message
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_should_unescape_gsm_escaped_left_square_bracket_symbol
|
100
|
+
raw_data = <<-EOF
|
101
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
102
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
103
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
104
|
+
0000 0000 0000 0000 028d 3c
|
105
|
+
EOF
|
106
|
+
|
107
|
+
pdu = create_pdu(raw_data)
|
108
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
109
|
+
assert_equal 0, pdu.data_coding
|
110
|
+
|
111
|
+
assert_equal "[", pdu.short_message
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_should_unescape_gsm_escaped_right_square_bracket_symbol
|
115
|
+
raw_data = <<-EOF
|
116
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
117
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
118
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
119
|
+
0000 0000 0000 0000 028d 3e
|
120
|
+
EOF
|
121
|
+
|
122
|
+
pdu = create_pdu(raw_data)
|
123
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
124
|
+
assert_equal 0, pdu.data_coding
|
125
|
+
|
126
|
+
assert_equal "]", pdu.short_message
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_should_unescape_gsm_escaped_backslash_symbol
|
130
|
+
raw_data = <<-EOF
|
131
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
132
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
133
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
134
|
+
0000 0000 0000 0000 028d 2f
|
135
|
+
EOF
|
136
|
+
|
137
|
+
pdu = create_pdu(raw_data)
|
138
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
139
|
+
assert_equal 0, pdu.data_coding
|
140
|
+
|
141
|
+
assert_equal "\\", pdu.short_message
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_should_unescape_gsm_escaped_vertical_bar_symbol
|
145
|
+
raw_data = <<-EOF
|
146
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
147
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
148
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
149
|
+
0000 0000 0000 0000 028d b8
|
150
|
+
EOF
|
151
|
+
|
152
|
+
pdu = create_pdu(raw_data)
|
153
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
154
|
+
assert_equal 0, pdu.data_coding
|
155
|
+
|
156
|
+
assert_equal "|", pdu.short_message
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_should_unescape_gsm_escaped_caret_or_circumflex_symbol
|
160
|
+
raw_data = <<-EOF
|
161
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
162
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
163
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
164
|
+
0000 0000 0000 0000 028d 86
|
165
|
+
EOF
|
166
|
+
|
167
|
+
pdu = create_pdu(raw_data)
|
168
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
169
|
+
assert_equal 0, pdu.data_coding
|
170
|
+
|
171
|
+
expected = "\313\206"
|
172
|
+
assert_equal expected, pdu.short_message
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_should_unescape_gsm_escaped_characters_together
|
176
|
+
raw_data = <<-EOF
|
177
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
178
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
179
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
180
|
+
0000 0000 0000 0000 4054 6573 748d b869
|
181
|
+
6e67 208d 8620 7374 6167 2f69 6e67 208d
|
182
|
+
3d20 6575 726f 208d 6520 616e 6420 8d28
|
183
|
+
6f74 688d 2f65 7220 8d3c 2063 6861 7261
|
184
|
+
8d3e 6374 6572 738d 29
|
185
|
+
EOF
|
186
|
+
|
187
|
+
pdu = create_pdu(raw_data)
|
188
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
189
|
+
assert_equal 0, pdu.data_coding
|
190
|
+
|
191
|
+
expected = "Test|ing ˆ stag/ing ~ euro € and {oth\\er [ chara]cters}"
|
192
|
+
assert_equal expected, pdu.short_message
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_should_convert_ucs_2_into_utf_8_where_data_coding_indicates_its_presence
|
196
|
+
raw_data = <<-EOF
|
197
|
+
0000 003d 0000 0005 0000 0000 0000 0002
|
198
|
+
0001 0134 3437 3830 3330 3239 3833 3700
|
199
|
+
0101 3434 3738 3033 3032 3938 3337 0000
|
200
|
+
0000 0000 0000 0800 0E00 db00 f100 ef00
|
201
|
+
e700 f800 6401 13
|
202
|
+
EOF
|
203
|
+
|
204
|
+
pdu = create_pdu(raw_data)
|
205
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
206
|
+
assert_equal 8, pdu.data_coding
|
207
|
+
|
208
|
+
expected = "\303\233\303\261\303\257\303\247\303\270d\304\223" # Ûñïçødē
|
209
|
+
assert_equal expected, pdu.short_message
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_should_decode_pound_sign_from_hp_roman_8_to_utf_8_when_data_coding_set_to_1
|
213
|
+
raw_data = <<-EOF
|
214
|
+
0000 0096 0000 0005 0000 0000 0000 1b10
|
215
|
+
0005 004d 6f6e 6579 416c 6572 7400 0101
|
216
|
+
3434 3737 3738 3030 3036 3133 0000 0000
|
217
|
+
0000 0000 0100 5fbb 506f 756e 6473 bb20
|
218
|
+
EOF
|
219
|
+
|
220
|
+
pdu = create_pdu(raw_data)
|
221
|
+
assert_equal Smpp::Pdu::DeliverSm, pdu.class
|
222
|
+
assert_equal "£Pounds£ ", pdu.short_message
|
223
|
+
end
|
224
|
+
|
225
|
+
protected
|
226
|
+
def create_pdu(raw_data)
|
227
|
+
hex_data = [raw_data.chomp.gsub(" ","").gsub(/\n/,"")].pack("H*")
|
228
|
+
Smpp::Pdu::Base.create(hex_data)
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
data/test/pdu_parsing_test.rb
CHANGED
@@ -75,10 +75,37 @@ class PduParsingTest < Test::Unit::TestCase
|
|
75
75
|
assert_equal " and provide a good user experience", pdu.short_message
|
76
76
|
end
|
77
77
|
|
78
|
+
def test_submit_sm_response_clean
|
79
|
+
data = <<-EOF
|
80
|
+
0000 0028 8000 0004 0000 0000 4da8 ebed
|
81
|
+
3534 3131 342d 3034 3135 562d 3231 3230
|
82
|
+
452d 3039 4831 5100
|
83
|
+
EOF
|
84
|
+
|
85
|
+
pdu = create_pdu(data)
|
86
|
+
assert_equal Smpp::Pdu::SubmitSmResponse, pdu.class
|
87
|
+
assert_equal "54114-0415V-2120E-09H1Q", pdu.message_id
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_submit_sm_response_with_optional_params
|
91
|
+
data = <<-EOF
|
92
|
+
0000 0031 8000 0004 0000 042e 4da8 e9a1
|
93
|
+
0021 5300 0201 7721 6700 1653 6f75 7263
|
94
|
+
6520 6164 6472 6573 7320 6465 6e69 6564
|
95
|
+
2e
|
96
|
+
EOF
|
97
|
+
|
98
|
+
pdu = create_pdu(data)
|
99
|
+
assert_equal Smpp::Pdu::SubmitSmResponse, pdu.class
|
100
|
+
assert_equal "", pdu.message_id
|
101
|
+
assert pdu.optional_parameters
|
102
|
+
assert_equal "Source address denied.", pdu.optional_parameter(0x2167)
|
103
|
+
end
|
104
|
+
|
78
105
|
protected
|
79
106
|
def create_pdu(raw_data)
|
80
|
-
hex_data = [raw_data.chomp.gsub(
|
107
|
+
hex_data = [raw_data.chomp.gsub(/\s/,"")].pack("H*")
|
81
108
|
Smpp::Pdu::Base.create(hex_data)
|
82
109
|
end
|
83
110
|
|
84
|
-
end
|
111
|
+
end
|
data/test/receiver_test.rb
CHANGED
@@ -20,6 +20,12 @@ class ReceiverTest < Test::Unit::TestCase
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
class ExceptionRaisingDelegate < RecordingDelegate
|
24
|
+
def mo_received(receiver, pdu)
|
25
|
+
raise "exception in delegate"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
23
29
|
def test_receiving_bind_receiver_response_with_ok_status_should_become_bound
|
24
30
|
receiver = build_receiver
|
25
31
|
bind_receiver_response = Smpp::Pdu::BindReceiverResponse.new(nil, Smpp::Pdu::Base::ESME_ROK, 1)
|
@@ -76,7 +82,36 @@ class ReceiverTest < Test::Unit::TestCase
|
|
76
82
|
end
|
77
83
|
|
78
84
|
def test_receiving_deliver_sm_should_send_deliver_sm_response
|
79
|
-
|
85
|
+
delegate = RecordingDelegate.new
|
86
|
+
receiver = build_receiver(delegate)
|
87
|
+
deliver_sm = Smpp::Pdu::DeliverSm.new("from", "to", "message")
|
88
|
+
|
89
|
+
receiver.process_pdu(deliver_sm)
|
90
|
+
|
91
|
+
first_sent_data = receiver.sent_data.first
|
92
|
+
assert_not_nil first_sent_data
|
93
|
+
actual_response = Smpp::Pdu::Base.create(first_sent_data)
|
94
|
+
expected_response = Smpp::Pdu::DeliverSmResponse.new(deliver_sm.sequence_number)
|
95
|
+
assert_equal expected_response.to_human, actual_response.to_human
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_receiving_deliver_sm_should_send_error_response_if_delegate_raises_exception
|
99
|
+
delegate = ExceptionRaisingDelegate.new
|
100
|
+
receiver = build_receiver(delegate)
|
101
|
+
deliver_sm = Smpp::Pdu::DeliverSm.new("from", "to", "message")
|
102
|
+
|
103
|
+
receiver.process_pdu(deliver_sm)
|
104
|
+
|
105
|
+
first_sent_data = receiver.sent_data.first
|
106
|
+
assert_not_nil first_sent_data
|
107
|
+
actual_response = Smpp::Pdu::Base.create(first_sent_data)
|
108
|
+
expected_response = Smpp::Pdu::DeliverSmResponse.new(deliver_sm.sequence_number, Smpp::Pdu::Base::ESME_RX_T_APPN)
|
109
|
+
assert_equal expected_response.to_human, actual_response.to_human
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_receiving_deliver_sm_should_still_send_deliver_sm_response_when_no_delegate_is_provided
|
113
|
+
delegate = nil
|
114
|
+
receiver = build_receiver(delegate)
|
80
115
|
deliver_sm = Smpp::Pdu::DeliverSm.new("from", "to", "message")
|
81
116
|
|
82
117
|
receiver.process_pdu(deliver_sm)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "test/unit"
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + "../../lib/smpp")
|
4
|
+
|
5
|
+
class TransceiverTest < Test::Unit::TestCase
|
6
|
+
def test_get_message_part_size_8
|
7
|
+
options = {:data_coding => 8}
|
8
|
+
assert_equal(67, Smpp::Transceiver.get_message_part_size(options))
|
9
|
+
end
|
10
|
+
def test_get_message_part_size_0_and_1
|
11
|
+
options = {:data_coding => 0}
|
12
|
+
assert_equal(153, Smpp::Transceiver.get_message_part_size(options))
|
13
|
+
options = {:data_coding => 1}
|
14
|
+
assert_equal(153, Smpp::Transceiver.get_message_part_size(options))
|
15
|
+
end
|
16
|
+
def test_get_message_part_size_nil
|
17
|
+
options = {}
|
18
|
+
assert_equal(153, Smpp::Transceiver.get_message_part_size(options))
|
19
|
+
end
|
20
|
+
def test_get_message_part_size_other
|
21
|
+
options = {:data_coding => 3}
|
22
|
+
assert_equal(134, Smpp::Transceiver.get_message_part_size(options))
|
23
|
+
options = {:data_coding => 5}
|
24
|
+
assert_equal(134, Smpp::Transceiver.get_message_part_size(options))
|
25
|
+
options = {:data_coding => 6}
|
26
|
+
assert_equal(134, Smpp::Transceiver.get_message_part_size(options))
|
27
|
+
options = {:data_coding => 7}
|
28
|
+
assert_equal(134, Smpp::Transceiver.get_message_part_size(options))
|
29
|
+
end
|
30
|
+
def test_get_message_part_size_non_existant_data_coding
|
31
|
+
options = {:data_coding => 666}
|
32
|
+
assert_equal(153, Smpp::Transceiver.get_message_part_size(options))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-smpp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 11
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
+
- 5
|
8
9
|
- 0
|
9
|
-
version: 0.
|
10
|
+
version: 0.5.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Ray Krueger
|
@@ -15,23 +16,67 @@ autorequire:
|
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date: 2011-
|
19
|
+
date: 2011-04-16 00:00:00 -05:00
|
19
20
|
default_executable:
|
20
21
|
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: jeweler
|
24
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
prerelease: false
|
34
|
+
type: :runtime
|
35
|
+
requirement: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
prerelease: false
|
48
|
+
type: :runtime
|
49
|
+
requirement: *id002
|
21
50
|
- !ruby/object:Gem::Dependency
|
22
51
|
name: eventmachine
|
52
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
prerelease: false
|
23
62
|
type: :runtime
|
24
|
-
|
63
|
+
requirement: *id003
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: eventmachine
|
66
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
25
68
|
requirements:
|
26
69
|
- - ">="
|
27
70
|
- !ruby/object:Gem::Version
|
71
|
+
hash: 55
|
28
72
|
segments:
|
29
73
|
- 0
|
30
74
|
- 10
|
31
75
|
- 0
|
32
76
|
version: 0.10.0
|
33
77
|
prerelease: false
|
34
|
-
|
78
|
+
type: :runtime
|
79
|
+
requirement: *id004
|
35
80
|
description: Ruby implementation of the SMPP protocol, based on EventMachine. SMPP is a protocol that allows ordinary people outside the mobile network to exchange SMS messages directly with mobile operators.
|
36
81
|
email: raykrueger@gmail.com
|
37
82
|
executables: []
|
@@ -43,7 +88,6 @@ extra_rdoc_files:
|
|
43
88
|
- CONTRIBUTORS.txt
|
44
89
|
- README.rdoc
|
45
90
|
files:
|
46
|
-
- .gitignore
|
47
91
|
- CHANGELOG
|
48
92
|
- CONTRIBUTORS.txt
|
49
93
|
- Gemfile
|
@@ -59,6 +103,7 @@ files:
|
|
59
103
|
- examples/sample_smsc.rb
|
60
104
|
- lib/smpp.rb
|
61
105
|
- lib/smpp/base.rb
|
106
|
+
- lib/smpp/encoding/utf8_encoder.rb
|
62
107
|
- lib/smpp/optional_parameter.rb
|
63
108
|
- lib/smpp/pdu/base.rb
|
64
109
|
- lib/smpp/pdu/bind_base.rb
|
@@ -84,6 +129,7 @@ files:
|
|
84
129
|
- lib/sms.rb
|
85
130
|
- ruby-smpp.gemspec
|
86
131
|
- test/delegate.rb
|
132
|
+
- test/encoding_test.rb
|
87
133
|
- test/optional_parameter_test.rb
|
88
134
|
- test/pdu_parsing_test.rb
|
89
135
|
- test/receiver_test.rb
|
@@ -91,38 +137,46 @@ files:
|
|
91
137
|
- test/server.rb
|
92
138
|
- test/smpp_test.rb
|
93
139
|
- test/submit_sm_test.rb
|
140
|
+
- test/transceiver_test.rb
|
94
141
|
has_rdoc: true
|
95
142
|
homepage: http://github.com/raykrueger/ruby-smpp
|
96
143
|
licenses: []
|
97
144
|
|
98
145
|
post_install_message:
|
99
|
-
rdoc_options:
|
100
|
-
|
146
|
+
rdoc_options: []
|
147
|
+
|
101
148
|
require_paths:
|
102
149
|
- lib
|
103
150
|
required_ruby_version: !ruby/object:Gem::Requirement
|
151
|
+
none: false
|
104
152
|
requirements:
|
105
153
|
- - ">="
|
106
154
|
- !ruby/object:Gem::Version
|
155
|
+
hash: 3
|
107
156
|
segments:
|
108
157
|
- 0
|
109
158
|
version: "0"
|
110
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
|
+
none: false
|
111
161
|
requirements:
|
112
162
|
- - ">="
|
113
163
|
- !ruby/object:Gem::Version
|
164
|
+
hash: 3
|
114
165
|
segments:
|
115
166
|
- 0
|
116
167
|
version: "0"
|
117
168
|
requirements: []
|
118
169
|
|
119
170
|
rubyforge_project: ruby-smpp
|
120
|
-
rubygems_version: 1.3
|
171
|
+
rubygems_version: 1.5.3
|
121
172
|
signing_key:
|
122
173
|
specification_version: 3
|
123
174
|
summary: Ruby implementation of the SMPP protocol, based on EventMachine.
|
124
175
|
test_files:
|
176
|
+
- examples/sample_gateway.rb
|
177
|
+
- examples/sample_smsc.rb
|
125
178
|
- test/delegate.rb
|
179
|
+
- test/encoding_test.rb
|
126
180
|
- test/optional_parameter_test.rb
|
127
181
|
- test/pdu_parsing_test.rb
|
128
182
|
- test/receiver_test.rb
|
@@ -130,5 +184,4 @@ test_files:
|
|
130
184
|
- test/server.rb
|
131
185
|
- test/smpp_test.rb
|
132
186
|
- test/submit_sm_test.rb
|
133
|
-
-
|
134
|
-
- examples/sample_smsc.rb
|
187
|
+
- test/transceiver_test.rb
|
data/.gitignore
DELETED