anjlab-ruby-smpp 0.6.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/CHANGELOG +52 -0
- data/CONTRIBUTORS.txt +11 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +18 -0
- data/LICENSE +20 -0
- data/README.rdoc +89 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/config/environment.rb +2 -0
- data/examples/PDU1.example +26 -0
- data/examples/PDU2.example +26 -0
- data/examples/sample_gateway.rb +137 -0
- data/examples/sample_smsc.rb +102 -0
- data/lib/smpp.rb +25 -0
- data/lib/smpp/base.rb +308 -0
- data/lib/smpp/encoding/utf8_encoder.rb +37 -0
- data/lib/smpp/optional_parameter.rb +35 -0
- data/lib/smpp/pdu/base.rb +183 -0
- data/lib/smpp/pdu/bind_base.rb +25 -0
- data/lib/smpp/pdu/bind_receiver.rb +4 -0
- data/lib/smpp/pdu/bind_receiver_response.rb +4 -0
- data/lib/smpp/pdu/bind_resp_base.rb +17 -0
- data/lib/smpp/pdu/bind_transceiver.rb +4 -0
- data/lib/smpp/pdu/bind_transceiver_response.rb +4 -0
- data/lib/smpp/pdu/deliver_sm.rb +142 -0
- data/lib/smpp/pdu/deliver_sm_response.rb +12 -0
- data/lib/smpp/pdu/enquire_link.rb +11 -0
- data/lib/smpp/pdu/enquire_link_response.rb +11 -0
- data/lib/smpp/pdu/generic_nack.rb +20 -0
- data/lib/smpp/pdu/submit_multi.rb +68 -0
- data/lib/smpp/pdu/submit_multi_response.rb +49 -0
- data/lib/smpp/pdu/submit_sm.rb +91 -0
- data/lib/smpp/pdu/submit_sm_response.rb +31 -0
- data/lib/smpp/pdu/unbind.rb +11 -0
- data/lib/smpp/pdu/unbind_response.rb +12 -0
- data/lib/smpp/receiver.rb +27 -0
- data/lib/smpp/server.rb +223 -0
- data/lib/smpp/transceiver.rb +109 -0
- data/lib/sms.rb +9 -0
- data/ruby-smpp.gemspec +96 -0
- data/test/delegate.rb +28 -0
- data/test/encoding_test.rb +231 -0
- data/test/optional_parameter_test.rb +30 -0
- data/test/pdu_parsing_test.rb +111 -0
- data/test/receiver_test.rb +232 -0
- data/test/responsive_delegate.rb +53 -0
- data/test/server.rb +56 -0
- data/test/smpp_test.rb +239 -0
- data/test/submit_sm_test.rb +40 -0
- data/test/transceiver_test.rb +35 -0
- metadata +133 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
class Smpp::OptionalParameter
|
2
|
+
|
3
|
+
attr_reader :tag, :value
|
4
|
+
|
5
|
+
def initialize(tag, value)
|
6
|
+
@tag = tag
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](symbol)
|
11
|
+
self.send symbol
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
self.inspect
|
16
|
+
end
|
17
|
+
|
18
|
+
#class methods
|
19
|
+
class << self
|
20
|
+
def from_wire_data(data)
|
21
|
+
|
22
|
+
return nil if data.nil?
|
23
|
+
tag, length, remaining_bytes = data.unpack('H4na*')
|
24
|
+
tag = tag.hex
|
25
|
+
|
26
|
+
raise "invalid data, cannot parse optional parameters" if tag == 0 or length.nil?
|
27
|
+
|
28
|
+
value = remaining_bytes.slice!(0...length)
|
29
|
+
|
30
|
+
return new(tag, value), remaining_bytes
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# PDUs are the protcol base units in SMPP
|
2
|
+
module Smpp::Pdu
|
3
|
+
class Base
|
4
|
+
#Protocol Version
|
5
|
+
PROTOCOL_VERSION = 0x34
|
6
|
+
# Error constants
|
7
|
+
ESME_ROK = 0x00000000 # OK!
|
8
|
+
ESME_RINVMSGLEN = 0x00000001 # Message Length is invalid
|
9
|
+
ESME_RINVCMDLEN = 0x00000002 # Command Length is invalid
|
10
|
+
ESME_RINVCMDID = 0x00000003 # Invalid Command ID
|
11
|
+
ESME_RINVBNDSTS = 0x00000004 # Incorrect BIND Status for given com-
|
12
|
+
ESME_RALYBND = 0x00000005 # ESME Already in Bound State
|
13
|
+
ESME_RINVPRTFLG = 0x00000006 # Invalid Priority Flag
|
14
|
+
ESME_RINVREGDLVFLG = 0x00000007 # Invalid Registered Delivery Flag
|
15
|
+
ESME_RSYSERR = 0x00000008 # System Error
|
16
|
+
ESME_RINVSRCADR = 0x0000000A # Invalid Source Address
|
17
|
+
ESME_RINVDSTADR = 0x0000000B # Invalid Dest Addr
|
18
|
+
ESME_RINVMSGID = 0x0000000C # Message ID is invalid
|
19
|
+
ESME_RBINDFAIL = 0x0000000D # Bind Failed
|
20
|
+
ESME_RINVPASWD = 0x0000000E # Invalid Password
|
21
|
+
ESME_RINVSYSID = 0x0000000F # Invalid System ID
|
22
|
+
ESME_RCANCELFAIL = 0x00000011 # Cancel SM Failed
|
23
|
+
ESME_RREPLACEFAIL = 0x00000013 # Replace SM Failed
|
24
|
+
ESME_RMSGQFUL = 0x00000014 # Message Queue Full
|
25
|
+
ESME_RINVSERTYP = 0x00000015 # Invalid Service Type
|
26
|
+
ESME_RINVNUMDESTS = 0x00000033 # Invalid number of destinations
|
27
|
+
ESME_RINVDLNAME = 0x00000034 # Invalid Distribution List name
|
28
|
+
ESME_RINVDESTFLAG = 0x00000040 # Destination flag is invalid
|
29
|
+
ESME_RINVSUBREP = 0x00000042 # Invalid ‘submit with replace’ request
|
30
|
+
ESME_RINVESMCLASS = 0x00000043 # Invalid esm_class field data
|
31
|
+
ESME_RCNTSUBDL = 0x00000044 # Cannot Submit to Distribution List
|
32
|
+
ESME_RSUBMITFAIL = 0x00000045 # submit_sm or submit_multi failed
|
33
|
+
ESME_RINVSRCTON = 0x00000048 # Invalid Source address TON
|
34
|
+
ESME_RINVSRCNPI = 0x00000049 # Invalid Source address NPI
|
35
|
+
ESME_RINVDSTTON = 0x00000050 # Invalid Destination address TON
|
36
|
+
ESME_RINVDSTNPI = 0x00000051 # Invalid Destination address NPI
|
37
|
+
ESME_RINVSYSTYP = 0x00000053 # Invalid system_type field
|
38
|
+
ESME_RINVREPFLAG = 0x00000054 # Invalid replace_if_present flag
|
39
|
+
ESME_RINVNUMMSGS = 0x00000055 # Invalid number of messages
|
40
|
+
ESME_RTHROTTLED = 0x00000058 # Throttling error (ESME has exceeded allowed message limits)
|
41
|
+
|
42
|
+
ESME_RX_T_APPN = 0x00000064 # ESME Receiver Temporary App Error Code
|
43
|
+
|
44
|
+
# PDU types
|
45
|
+
GENERIC_NACK = 0X80000000
|
46
|
+
BIND_RECEIVER = 0X00000001
|
47
|
+
BIND_RECEIVER_RESP = 0X80000001
|
48
|
+
BIND_TRANSMITTER = 0X00000002
|
49
|
+
BIND_TRANSMITTER_RESP = 0X80000002
|
50
|
+
BIND_TRANSCEIVER = 0X00000009
|
51
|
+
BIND_TRANSCEIVER_RESP = 0X80000009
|
52
|
+
QUERY_SM = 0X00000003
|
53
|
+
QUERY_SM_RESP = 0X80000003
|
54
|
+
SUBMIT_SM = 0X00000004
|
55
|
+
SUBMIT_SM_RESP = 0X80000004
|
56
|
+
DELIVER_SM = 0X00000005
|
57
|
+
DELIVER_SM_RESP = 0X80000005
|
58
|
+
UNBIND = 0X00000006
|
59
|
+
UNBIND_RESP = 0X80000006
|
60
|
+
REPLACE_SM = 0X00000007
|
61
|
+
REPLACE_SM_RESP = 0X80000007
|
62
|
+
CANCEL_SM = 0X00000008
|
63
|
+
CANCEL_SM_RESP = 0X80000008
|
64
|
+
ENQUIRE_LINK = 0X00000015
|
65
|
+
ENQUIRE_LINK_RESP = 0X80000015
|
66
|
+
SUBMIT_MULTI = 0X00000021
|
67
|
+
SUBMIT_MULTI_RESP = 0X80000021
|
68
|
+
|
69
|
+
OPTIONAL_RECEIPTED_MESSAGE_ID = 0x001E
|
70
|
+
OPTIONAL_MESSAGE_STATE = 0x0427
|
71
|
+
|
72
|
+
SEQUENCE_MAX = 0x7FFFFFFF
|
73
|
+
|
74
|
+
# PDU sequence number.
|
75
|
+
@@seq = [Time.now.to_i]
|
76
|
+
|
77
|
+
# Add monitor to sequence counter for thread safety
|
78
|
+
@@seq.extend(MonitorMixin)
|
79
|
+
|
80
|
+
#factory class registry
|
81
|
+
@@cmd_map = {}
|
82
|
+
|
83
|
+
attr_reader :command_id, :command_status, :sequence_number, :body, :data
|
84
|
+
|
85
|
+
def initialize(command_id, command_status, seq, body='')
|
86
|
+
length = 16 + body.length
|
87
|
+
@command_id = command_id
|
88
|
+
@command_status = command_status
|
89
|
+
@body = body
|
90
|
+
@sequence_number = seq
|
91
|
+
@data = fixed_int(length) + fixed_int(command_id) + fixed_int(command_status) + fixed_int(seq) + body
|
92
|
+
end
|
93
|
+
|
94
|
+
def logger
|
95
|
+
Smpp::Base.logger
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_human
|
99
|
+
# convert header (4 bytes) to array of 4-byte ints
|
100
|
+
a = @data.to_s.unpack('N4')
|
101
|
+
sprintf("(%22s) len=%3d cmd=%8s status=%1d seq=%03d (%s)", self.class.to_s[11..-1], a[0], a[1].to_s(16), a[2], a[3], @body)
|
102
|
+
end
|
103
|
+
|
104
|
+
# return int as binary string of 4 octets
|
105
|
+
def Base.fixed_int(value)
|
106
|
+
arr = [value >> 24, value >> 16, value >> 8, value & 0xff]
|
107
|
+
arr.pack("cccc")
|
108
|
+
end
|
109
|
+
|
110
|
+
def fixed_int(value)
|
111
|
+
Base.fixed_int(value)
|
112
|
+
end
|
113
|
+
|
114
|
+
#expects a hash like {tag => Smpp::OptionalParameter}
|
115
|
+
def Base.optional_parameters_to_buffer(optionals)
|
116
|
+
output = ""
|
117
|
+
optionals.each do |tag, optional_param|
|
118
|
+
length = optional_param.value.length
|
119
|
+
buffer = []
|
120
|
+
buffer += [tag >> 8, tag & 0xff]
|
121
|
+
buffer += [length >> 8, length & 0xff]
|
122
|
+
output << buffer.pack('cccc') << optional_param.value
|
123
|
+
end
|
124
|
+
output
|
125
|
+
end
|
126
|
+
|
127
|
+
def optional_parameters_to_buffer(optionals)
|
128
|
+
Base.optional_parameters_to_buffer(optionals)
|
129
|
+
end
|
130
|
+
|
131
|
+
def next_sequence_number
|
132
|
+
Base.next_sequence_number
|
133
|
+
end
|
134
|
+
|
135
|
+
def Base.next_sequence_number
|
136
|
+
@@seq.synchronize do
|
137
|
+
(@@seq[0] += 1) % SEQUENCE_MAX
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
#This factory should be implemented in every subclass that can create itself from wire
|
142
|
+
#data. The subclass should also register itself with the 'handles_cmd' class method.
|
143
|
+
def Base.from_wire_data(seq, status, body)
|
144
|
+
raise Exception.new("#{self.class} claimed to handle wire data, but doesn't.")
|
145
|
+
end
|
146
|
+
|
147
|
+
# PDU factory method for common client PDUs (used to create PDUs from wire data)
|
148
|
+
def Base.create(data)
|
149
|
+
header = data[0..15]
|
150
|
+
if !header
|
151
|
+
return nil
|
152
|
+
end
|
153
|
+
len, cmd, status, seq = header.unpack('N4')
|
154
|
+
body = data[16..-1]
|
155
|
+
|
156
|
+
#if a class has been registered to handle this command_id, try
|
157
|
+
#to create an instance from the wire data
|
158
|
+
if @@cmd_map[cmd]
|
159
|
+
@@cmd_map[cmd].from_wire_data(seq, status, body)
|
160
|
+
else
|
161
|
+
Smpp::Base.logger.error "Unknown PDU: #{"0x%08x" % cmd}"
|
162
|
+
return nil
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
#maps a subclass as the handler for a particulular pdu
|
167
|
+
def Base.handles_cmd(command_id)
|
168
|
+
@@cmd_map[command_id] = self
|
169
|
+
end
|
170
|
+
|
171
|
+
def Base.parse_optional_parameters(remaining_bytes)
|
172
|
+
optionals = {}
|
173
|
+
while not remaining_bytes.empty?
|
174
|
+
optional = {}
|
175
|
+
optional_parameter, remaining_bytes = Smpp::OptionalParameter.from_wire_data(remaining_bytes)
|
176
|
+
optionals[optional_parameter.tag] = optional_parameter
|
177
|
+
end
|
178
|
+
|
179
|
+
return optionals
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# this class serves as the base for all the bind* commands.
|
2
|
+
# since the command format remains the same for all bind commands,
|
3
|
+
# sub classes just change the @@command_id
|
4
|
+
class Smpp::Pdu::BindBase < Smpp::Pdu::Base
|
5
|
+
class << self; attr_accessor :command_id ; end
|
6
|
+
|
7
|
+
attr_reader :system_id, :password, :system_type, :addr_ton, :addr_npi, :address_range
|
8
|
+
|
9
|
+
def initialize(system_id, password, system_type, addr_ton, addr_npi, address_range, seq = nil)
|
10
|
+
@system_id, @password, @system_type, @addr_ton, @addr_npi, @address_range =
|
11
|
+
system_id, password, system_type, addr_ton, addr_npi, address_range
|
12
|
+
|
13
|
+
seq ||= next_sequence_number
|
14
|
+
body = sprintf("%s\0%s\0%s\0%c%c%c%s\0", system_id, password,system_type, PROTOCOL_VERSION, addr_ton, addr_npi, address_range)
|
15
|
+
super(self.class.command_id, 0, seq, body)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.from_wire_data(seq, status, body)
|
19
|
+
#unpack the body
|
20
|
+
system_id, password, system_type, interface_version, addr_ton,
|
21
|
+
addr_npi, address_range = body.unpack("Z*Z*Z*CCCZ*")
|
22
|
+
|
23
|
+
self.new(system_id, password, system_type, addr_ton, addr_npi, address_range, seq)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Smpp::Pdu::BindRespBase < Smpp::Pdu::Base
|
2
|
+
class << self; attr_accessor :command_id ; end
|
3
|
+
attr_accessor :system_id
|
4
|
+
|
5
|
+
def initialize(seq, status, system_id)
|
6
|
+
seq ||= next_sequence_number
|
7
|
+
system_id = system_id.to_s + "\000"
|
8
|
+
super(self.class.command_id, status, seq, system_id) # pass in system_id as body for simple debugging
|
9
|
+
@system_id = system_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.from_wire_data(seq, status, body)
|
13
|
+
system_id = body.chomp("\000")
|
14
|
+
new(seq, status, system_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
|
2
|
+
# Received for MO message or delivery notification
|
3
|
+
class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
|
4
|
+
handles_cmd DELIVER_SM
|
5
|
+
|
6
|
+
attr_reader :service_type, :source_addr_ton, :source_addr_npi, :source_addr, :dest_addr_ton, :dest_addr_npi,
|
7
|
+
:destination_addr, :esm_class, :protocol_id, :priority_flag, :schedule_delivery_time,
|
8
|
+
:validity_period, :registered_delivery, :replace_if_present_flag, :data_coding,
|
9
|
+
:sm_default_msg_id, :sm_length, :stat, :msg_reference, :udh, :short_message,
|
10
|
+
:message_state, :receipted_message_id, :optional_parameters
|
11
|
+
|
12
|
+
@@encoder = nil
|
13
|
+
|
14
|
+
def initialize(source_addr, destination_addr, short_message, options={}, seq=nil)
|
15
|
+
|
16
|
+
@udh = options[:udh]
|
17
|
+
@service_type = options[:service_type]? options[:service_type] :''
|
18
|
+
@source_addr_ton = options[:source_addr_ton]?options[:source_addr_ton]:0 # network specific
|
19
|
+
@source_addr_npi = options[:source_addr_npi]?options[:source_addr_npi]:1 # unknown
|
20
|
+
@source_addr = source_addr
|
21
|
+
@dest_addr_ton = options[:dest_addr_ton]?options[:dest_addr_ton]:1 # international
|
22
|
+
@dest_addr_npi = options[:dest_addr_npi]?options[:dest_addr_npi]:1 # unknown
|
23
|
+
@destination_addr = destination_addr
|
24
|
+
@esm_class = options[:esm_class]?options[:esm_class]:0 # default smsc mode
|
25
|
+
@protocol_id = options[:protocol_id]?options[:protocol_id]:0
|
26
|
+
@priority_flag = options[:priority_flag]?options[:priority_flag]:0
|
27
|
+
@schedule_delivery_time = options[:schedule_delivery_time]?options[:schedule_delivery_time]:''
|
28
|
+
@validity_period = options[:validity_period]?options[:validity_period]:''
|
29
|
+
@registered_delivery = options[:registered_delivery]?options[:registered_delivery]:1 # we want delivery notifications
|
30
|
+
@replace_if_present_flag = options[:replace_if_present_flag]?options[:replace_if_present_flag]:0
|
31
|
+
@data_coding = options[:data_coding]?options[:data_coding]:3 # iso-8859-1
|
32
|
+
@sm_default_msg_id = options[:sm_default_msg_id]?options[:sm_default_msg_id]:0
|
33
|
+
@short_message = short_message
|
34
|
+
payload = @udh ? @udh.to_s + @short_message : @short_message
|
35
|
+
@sm_length = payload.length
|
36
|
+
|
37
|
+
#fields set for delivery report
|
38
|
+
@stat = options[:stat]
|
39
|
+
@msg_reference = options[:msg_reference]
|
40
|
+
@receipted_message_id = options[:receipted_message_id]
|
41
|
+
@message_state = options[:message_state]
|
42
|
+
@optional_parameters = options[:optional_parameters]
|
43
|
+
|
44
|
+
pdu_body = sprintf("%s\0%c%c%s\0%c%c%s\0%c%c%c%s\0%s\0%c%c%c%c%c%s", @service_type, @source_addr_ton, @source_addr_npi, @source_addr,
|
45
|
+
@dest_addr_ton, @dest_addr_npi, @destination_addr, @esm_class, @protocol_id, @priority_flag, @schedule_delivery_time, @validity_period,
|
46
|
+
@registered_delivery, @replace_if_present_flag, @data_coding, @sm_default_msg_id, @sm_length, payload)
|
47
|
+
|
48
|
+
seq ||= next_sequence_number
|
49
|
+
|
50
|
+
super(DELIVER_SM, 0, seq, pdu_body)
|
51
|
+
end
|
52
|
+
|
53
|
+
def total_parts
|
54
|
+
@udh ? @udh[4] : 0
|
55
|
+
end
|
56
|
+
|
57
|
+
def part
|
58
|
+
@udh ? @udh[5] : 0
|
59
|
+
end
|
60
|
+
|
61
|
+
def message_id
|
62
|
+
@udh ? @udh[3] : 0
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.from_wire_data(seq, status, body)
|
66
|
+
options = {}
|
67
|
+
# brutally unpack it
|
68
|
+
options[:service_type],
|
69
|
+
options[:source_addr_ton],
|
70
|
+
options[:source_addr_npi],
|
71
|
+
source_addr,
|
72
|
+
options[:dest_addr_ton],
|
73
|
+
options[:dest_addr_npi],
|
74
|
+
destination_addr,
|
75
|
+
options[:esm_class],
|
76
|
+
options[:protocol_id],
|
77
|
+
options[:priority_flag],
|
78
|
+
options[:schedule_delivery_time],
|
79
|
+
options[:validity_period],
|
80
|
+
options[:registered_delivery],
|
81
|
+
options[:replace_if_present_flag],
|
82
|
+
options[:data_coding],
|
83
|
+
options[:sm_default_msg_id],
|
84
|
+
options[:sm_length],
|
85
|
+
remaining_bytes = body.unpack('Z*CCZ*CCZ*CCCZ*Z*CCCCCa*')
|
86
|
+
|
87
|
+
short_message = remaining_bytes.slice!(0...options[:sm_length])
|
88
|
+
|
89
|
+
#everything left in remaining_bytes is 3.4 optional parameters
|
90
|
+
options[:optional_parameters] = parse_optional_parameters(remaining_bytes)
|
91
|
+
|
92
|
+
#parse the 'standard' optional parameters for delivery receipts
|
93
|
+
options[:optional_parameters].each do |tag, tlv|
|
94
|
+
if OPTIONAL_MESSAGE_STATE == tag
|
95
|
+
value = tlv[:value].unpack('C')
|
96
|
+
options[:message_state] = value[0] if value
|
97
|
+
|
98
|
+
elsif OPTIONAL_RECEIPTED_MESSAGE_ID == tag
|
99
|
+
value = tlv[:value].unpack('A*')
|
100
|
+
options[:receipted_message_id] = value[0] if value
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Check to see if body has a 5 bit header
|
105
|
+
if short_message.unpack("c")[0] == 5
|
106
|
+
options[:udh] = short_message.slice!(0..5).unpack("CCCCCC")
|
107
|
+
end
|
108
|
+
|
109
|
+
#Note: if the SM is a delivery receipt (esm_class=4) then the short_message _may_ be in this format:
|
110
|
+
# "id:Smsc2013 sub:1 dlvrd:1 submit date:0610171515 done date:0610171515 stat:0 err:0 text:blah"
|
111
|
+
# or this format:
|
112
|
+
# "4790000000SMSAlert^id:1054BC63 sub:0 dlvrd:1 submit date:0610231217 done date:0610231217 stat:DELIVRD err: text:"
|
113
|
+
# (according to the SMPP spec, the format is vendor specific)
|
114
|
+
# For example, Tele2 (Norway):
|
115
|
+
# "<msisdn><shortcode>?id:10ea34755d3d4f7a20900cdb3349e549 sub:001 dlvrd:001 submit date:0611011228 done date:0611011230 stat:DELIVRD err:000 Text:abc'!10ea34755d3d4f7a20900cdb3349e549"
|
116
|
+
if options[:esm_class] == 4
|
117
|
+
msg_ref_match = short_message.match(/id:([^ ]*)/)
|
118
|
+
if msg_ref_match
|
119
|
+
options[:msg_reference] = msg_ref_match[1]
|
120
|
+
end
|
121
|
+
|
122
|
+
stat_match = short_message.match(/stat:([^ ]*)/)
|
123
|
+
if stat_match
|
124
|
+
options[:stat] = stat_match[1]
|
125
|
+
end
|
126
|
+
|
127
|
+
Smpp::Base.logger.debug "DeliverSM with source_addr=#{source_addr}, destination_addr=#{destination_addr}, msg_reference=#{options[:msg_reference]}, stat=#{options[:stat]}"
|
128
|
+
else
|
129
|
+
Smpp::Base.logger.debug "DeliverSM with source_addr=#{source_addr}, destination_addr=#{destination_addr}"
|
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
|
+
|
135
|
+
new(source_addr, destination_addr, short_message, options, seq)
|
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
|
142
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Smpp::Pdu::DeliverSmResponse < Smpp::Pdu::Base
|
2
|
+
handles_cmd DELIVER_SM_RESP
|
3
|
+
|
4
|
+
def initialize(seq, status=ESME_ROK)
|
5
|
+
seq ||= next_sequence_number
|
6
|
+
super(DELIVER_SM_RESP, status, seq, "\000") # body must be NULL..!
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.from_wire_data(seq, status, body)
|
10
|
+
new(seq, status)
|
11
|
+
end
|
12
|
+
end
|