ruby-smpp 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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