ruby-smpp 0.1.2 → 0.1.3.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +23 -0
- data/{NEWS.txt → CHANGELOG} +7 -2
- data/CONTRIBUTORS.txt +3 -1
- data/{License.txt → LICENSE} +0 -0
- data/{README.txt → README.rdoc} +33 -41
- data/Rakefile +58 -9
- data/VERSION +1 -0
- data/examples/sample_gateway.rb +55 -78
- data/examples/sample_smsc.rb +2 -3
- data/lib/smpp/base.rb +33 -0
- data/lib/smpp/pdu/base.rb +23 -5
- data/lib/smpp/pdu/deliver_sm.rb +39 -7
- data/lib/smpp/server.rb +5 -1
- data/lib/smpp/transceiver.rb +15 -8
- data/ruby-smpp.gemspec +66 -18
- data/test/smpp_test.rb +147 -30
- metadata +26 -37
- data/History.txt +0 -14
- data/Manifest.txt +0 -45
- data/config/hoe.rb +0 -70
- data/config/requirements.rb +0 -15
- data/lib/smpp/version.rb +0 -9
- data/script/console +0 -10
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/script/txt2html +0 -74
- data/setup.rb +0 -1585
- data/tasks/deployment.rake +0 -34
- data/tasks/environment.rake +0 -7
- data/test/test_helper.rb +0 -2
data/examples/sample_smsc.rb
CHANGED
@@ -3,9 +3,8 @@
|
|
3
3
|
# Sample SMPP SMS Gateway.
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
|
-
|
7
|
-
require 'smpp'
|
8
|
-
require 'smpp/server'
|
6
|
+
require File.dirname(__FILE__) + '/../lib/smpp'
|
7
|
+
require File.dirname(__FILE__) + '/../lib/smpp/server'
|
9
8
|
|
10
9
|
# set up logger
|
11
10
|
Smpp::Base.logger = Logger.new('smsc.log')
|
data/lib/smpp/base.rb
CHANGED
@@ -142,6 +142,7 @@ module Smpp
|
|
142
142
|
private
|
143
143
|
def write_pdu(pdu)
|
144
144
|
logger.debug "<- #{pdu.to_human}"
|
145
|
+
hex_debug pdu.data, "<- "
|
145
146
|
send_data pdu.data
|
146
147
|
end
|
147
148
|
|
@@ -155,11 +156,43 @@ module Smpp
|
|
155
156
|
else
|
156
157
|
logger.debug "-> " + pdu.to_human
|
157
158
|
end
|
159
|
+
hex_debug data, "-> "
|
158
160
|
rescue Exception => ex
|
159
161
|
logger.error "Exception while reading PDUs: #{ex} in #{ex.backtrace[0]}"
|
160
162
|
raise
|
161
163
|
end
|
162
164
|
pdu
|
165
|
+
end
|
166
|
+
|
167
|
+
def hex_debug(data, prefix = "")
|
168
|
+
return unless @config[:hex_debug]
|
169
|
+
logger.debug do
|
170
|
+
message = "Hex dump follows:\n"
|
171
|
+
hexdump(data).each_line do |line|
|
172
|
+
message << (prefix + line.chomp + "\n")
|
173
|
+
end
|
174
|
+
message
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def hexdump(target)
|
179
|
+
width=16
|
180
|
+
group=2
|
181
|
+
|
182
|
+
output = ""
|
183
|
+
n=0
|
184
|
+
ascii=''
|
185
|
+
target.each_byte { |b|
|
186
|
+
if n%width == 0
|
187
|
+
output << "%s\n%08x: "%[ascii,n]
|
188
|
+
ascii='| '
|
189
|
+
end
|
190
|
+
output << "%02x"%b
|
191
|
+
output << ' ' if (n+=1)%group==0
|
192
|
+
ascii << "%s"%b.chr.tr('^ -~','.')
|
193
|
+
}
|
194
|
+
output << ' '*(((2+width-ascii.size)*(2*group+1))/group.to_f).ceil+ascii
|
195
|
+
output[1..-1]
|
163
196
|
end
|
164
197
|
end
|
165
198
|
end
|
data/lib/smpp/pdu/base.rb
CHANGED
@@ -61,8 +61,12 @@ module Smpp::Pdu
|
|
61
61
|
CANCEL_SM_RESP = 0X80000008
|
62
62
|
ENQUIRE_LINK = 0X00000015
|
63
63
|
ENQUIRE_LINK_RESP = 0X80000015
|
64
|
-
SUBMIT_MULTI
|
64
|
+
SUBMIT_MULTI = 0X00000021
|
65
65
|
SUBMIT_MULTI_RESP = 0X80000021
|
66
|
+
|
67
|
+
OPTIONAL_RECEIPTED_MESSAGE_ID = 0x001E
|
68
|
+
OPTIONAL_MESSAGE_STATE = 0x0427
|
69
|
+
|
66
70
|
# PDU sequence number.
|
67
71
|
@@seq = [Time.now.to_i]
|
68
72
|
|
@@ -95,7 +99,8 @@ module Smpp::Pdu
|
|
95
99
|
|
96
100
|
# return int as binary string of 4 octets
|
97
101
|
def fixed_int(value)
|
98
|
-
|
102
|
+
arr = [value >> 24, value >> 16, value >> 8, value & 0xff]
|
103
|
+
arr.pack("cccc")
|
99
104
|
end
|
100
105
|
|
101
106
|
def next_sequence_number
|
@@ -103,7 +108,7 @@ module Smpp::Pdu
|
|
103
108
|
end
|
104
109
|
|
105
110
|
def Base.next_sequence_number
|
106
|
-
@@seq.synchronize do
|
111
|
+
@@seq.synchronize do
|
107
112
|
(@@seq[0] += 1) % 512
|
108
113
|
end
|
109
114
|
end
|
@@ -122,13 +127,13 @@ module Smpp::Pdu
|
|
122
127
|
end
|
123
128
|
len, cmd, status, seq = header.unpack('N4')
|
124
129
|
body = data[16..-1]
|
125
|
-
|
130
|
+
|
126
131
|
#if a class has been registered to handle this command_id, try
|
127
132
|
#to create an instance from the wire data
|
128
133
|
if @@cmd_map[cmd]
|
129
134
|
@@cmd_map[cmd].from_wire_data(seq, status, body)
|
130
135
|
else
|
131
|
-
Smpp::Base.logger.error "Unknown PDU:
|
136
|
+
Smpp::Base.logger.error "Unknown PDU: #{"0x%08x" % cmd}"
|
132
137
|
return nil
|
133
138
|
end
|
134
139
|
end
|
@@ -138,5 +143,18 @@ module Smpp::Pdu
|
|
138
143
|
@@cmd_map[command_id] = self
|
139
144
|
end
|
140
145
|
|
146
|
+
def Base.optional_parameters(remaining_bytes)
|
147
|
+
optionals = {}
|
148
|
+
while not remaining_bytes.empty?
|
149
|
+
optional = {}
|
150
|
+
tag, optional[:length], remaining_bytes = remaining_bytes.unpack('H4na*')
|
151
|
+
optional[:tag] = tag.hex
|
152
|
+
optional[:value] = remaining_bytes.slice!(0...optional[:length])
|
153
|
+
optionals[tag.hex] = optional
|
154
|
+
end
|
155
|
+
|
156
|
+
return optionals
|
157
|
+
end
|
158
|
+
|
141
159
|
end
|
142
160
|
end
|
data/lib/smpp/pdu/deliver_sm.rb
CHANGED
@@ -4,7 +4,8 @@ class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
|
|
4
4
|
attr_reader :service_type, :source_addr_ton, :source_addr_npi, :source_addr, :dest_addr_ton, :dest_addr_npi,
|
5
5
|
:destination_addr, :esm_class, :protocol_id, :priority_flag, :schedule_delivery_time,
|
6
6
|
:validity_period, :registered_delivery, :replace_if_present_flag, :data_coding,
|
7
|
-
:sm_default_msg_id, :sm_length, :stat, :msg_reference, :udh, :short_message
|
7
|
+
:sm_default_msg_id, :sm_length, :stat, :msg_reference, :udh, :short_message,
|
8
|
+
:message_state, :receipted_message_id, :optional_parameters
|
8
9
|
|
9
10
|
def initialize(source_addr, destination_addr, short_message, options={}, seq=nil)
|
10
11
|
|
@@ -32,6 +33,9 @@ class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
|
|
32
33
|
#fields set for delivery report
|
33
34
|
@stat = options[:stat]
|
34
35
|
@msg_reference = options[:msg_reference]
|
36
|
+
@receipted_message_id = options[:receipted_message_id]
|
37
|
+
@message_state = options[:message_state]
|
38
|
+
@optional_parameters = options[:optional_parameters]
|
35
39
|
|
36
40
|
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,
|
37
41
|
@dest_addr_ton, @dest_addr_npi, @destination_addr, @esm_class, @protocol_id, @priority_flag, @schedule_delivery_time, @validity_period,
|
@@ -62,8 +66,26 @@ class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
|
|
62
66
|
options[:data_coding],
|
63
67
|
options[:sm_default_msg_id],
|
64
68
|
options[:sm_length],
|
65
|
-
|
66
|
-
|
69
|
+
remaining_bytes = body.unpack('Z*CCZ*CCZ*CCCZ*Z*CCCCCa*')
|
70
|
+
|
71
|
+
short_message = remaining_bytes.slice!(0...options[:sm_length])
|
72
|
+
|
73
|
+
#everything left in remaining_bytes is 3.4 optional parameters
|
74
|
+
options[:optional_parameters] = optional_parameters(remaining_bytes)
|
75
|
+
|
76
|
+
#parse the 'standard' optional parameters for delivery receipts
|
77
|
+
options[:optional_parameters].each do |tag, tlv|
|
78
|
+
if OPTIONAL_MESSAGE_STATE == tag
|
79
|
+
value = tlv[:value].unpack('C')
|
80
|
+
options[:message_state] = value[0] if value
|
81
|
+
|
82
|
+
elsif OPTIONAL_RECEIPTED_MESSAGE_ID == tag
|
83
|
+
value = tlv[:value].unpack('A*')
|
84
|
+
options[:receipted_message_id] = value[0] if value
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
67
89
|
|
68
90
|
#Note: if the SM is a delivery receipt (esm_class=4) then the short_message _may_ be in this format:
|
69
91
|
# "id:Smsc2013 sub:1 dlvrd:1 submit date:0610171515 done date:0610171515 stat:0 err:0 text:blah"
|
@@ -73,10 +95,20 @@ class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
|
|
73
95
|
# For example, Tele2 (Norway):
|
74
96
|
# "<msisdn><shortcode>?id:10ea34755d3d4f7a20900cdb3349e549 sub:001 dlvrd:001 submit date:0611011228 done date:0611011230 stat:DELIVRD err:000 Text:abc'!10ea34755d3d4f7a20900cdb3349e549"
|
75
97
|
if options[:esm_class] == 4
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
98
|
+
msg_ref_match = short_message.match(/id:([^ ]*)/)
|
99
|
+
if msg_ref_match
|
100
|
+
options[:msg_reference] = msg_ref_match[1]
|
101
|
+
end
|
102
|
+
|
103
|
+
stat_match = short_message.match(/stat:([^ ]*)/)
|
104
|
+
if stat_match
|
105
|
+
options[:stat] = stat_match[1]
|
106
|
+
end
|
107
|
+
|
108
|
+
Smpp::Base.logger.debug "DeliverSM with source_addr=#{source_addr}, destination_addr=#{destination_addr}, msg_reference=#{options[:msg_reference]}, stat=#{options[:stat]}"
|
109
|
+
else
|
110
|
+
Smpp::Base.logger.debug "DeliverSM with source_addr=#{source_addr}, destination_addr=#{destination_addr}"
|
111
|
+
end
|
80
112
|
|
81
113
|
new(source_addr, destination_addr, short_message, options, seq)
|
82
114
|
end
|
data/lib/smpp/server.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# --------
|
2
|
+
# This is experimental stuff submitted by taryn@taryneast.org
|
3
|
+
# --------
|
4
|
+
|
5
|
+
# the opposite of a client-based receiver, the server transmitter will send
|
2
6
|
# out MOs to the client when set up
|
3
7
|
class Smpp::Server < Smpp::Base
|
4
8
|
|
data/lib/smpp/transceiver.rb
CHANGED
@@ -5,9 +5,10 @@
|
|
5
5
|
# The transceiver accepts a delegate object that may implement
|
6
6
|
# the following (all optional) methods:
|
7
7
|
#
|
8
|
-
# mo_received(transceiver,
|
9
|
-
# delivery_report_received(transceiver,
|
10
|
-
# message_accepted(transceiver, mt_message_id,
|
8
|
+
# mo_received(transceiver, pdu)
|
9
|
+
# delivery_report_received(transceiver, pdu)
|
10
|
+
# message_accepted(transceiver, mt_message_id, pdu)
|
11
|
+
# message_rejected(transceiver, mt_message_id, pdu)
|
11
12
|
# bound(transceiver)
|
12
13
|
# unbound(transceiver)
|
13
14
|
|
@@ -31,7 +32,7 @@ class Smpp::Transceiver < Smpp::Base
|
|
31
32
|
end
|
32
33
|
|
33
34
|
# Send an MT SMS message. Delegate will receive message_accepted callback when SMSC
|
34
|
-
# acknowledges
|
35
|
+
# acknowledges, or the message_rejected callback upon error
|
35
36
|
def send_mt(message_id, source_addr, destination_addr, short_message, options={})
|
36
37
|
logger.debug "Sending MT: #{short_message}"
|
37
38
|
if @state == :bound
|
@@ -106,12 +107,12 @@ class Smpp::Transceiver < Smpp::Base
|
|
106
107
|
if pdu.esm_class != 4
|
107
108
|
# MO message
|
108
109
|
if @delegate.respond_to?(:mo_received)
|
109
|
-
@delegate.mo_received(self, pdu
|
110
|
+
@delegate.mo_received(self, pdu)
|
110
111
|
end
|
111
112
|
else
|
112
113
|
# Delivery report
|
113
114
|
if @delegate.respond_to?(:delivery_report_received)
|
114
|
-
@delegate.delivery_report_received(self, pdu
|
115
|
+
@delegate.delivery_report_received(self, pdu)
|
115
116
|
end
|
116
117
|
end
|
117
118
|
when Pdu::BindTransceiverResponse
|
@@ -141,10 +142,13 @@ class Smpp::Transceiver < Smpp::Base
|
|
141
142
|
end
|
142
143
|
if pdu.command_status != Pdu::Base::ESME_ROK
|
143
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
|
144
148
|
else
|
145
149
|
logger.info "Got OK SubmitSmResponse (#{pdu.message_id} -> #{mt_message_id})"
|
146
150
|
if @delegate.respond_to?(:message_accepted)
|
147
|
-
@delegate.message_accepted(self, mt_message_id, pdu
|
151
|
+
@delegate.message_accepted(self, mt_message_id, pdu)
|
148
152
|
end
|
149
153
|
end
|
150
154
|
# Now we got the SMSC message id; create pending delivery report.
|
@@ -156,10 +160,13 @@ class Smpp::Transceiver < Smpp::Base
|
|
156
160
|
end
|
157
161
|
if pdu.command_status != Pdu::Base::ESME_ROK
|
158
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
|
159
166
|
else
|
160
167
|
logger.info "Got OK SubmitMultiResponse (#{pdu.message_id} -> #{mt_message_id})"
|
161
168
|
if @delegate.respond_to?(:message_accepted)
|
162
|
-
@delegate.message_accepted(self, mt_message_id, pdu
|
169
|
+
@delegate.message_accepted(self, mt_message_id, pdu)
|
163
170
|
end
|
164
171
|
end
|
165
172
|
else
|
data/ruby-smpp.gemspec
CHANGED
@@ -1,36 +1,84 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
1
6
|
Gem::Specification.new do |s|
|
2
7
|
s.name = %q{ruby-smpp}
|
3
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.3.pre1"
|
4
9
|
|
5
|
-
s.required_rubygems_version = Gem::Requirement.new("
|
6
|
-
s.authors = ["August Z. Flatby"]
|
7
|
-
s.date = %q{
|
8
|
-
s.description = %q{Ruby
|
9
|
-
s.email =
|
10
|
-
s.extra_rdoc_files = [
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ray Krueger", "August Z. Flatby"]
|
12
|
+
s.date = %q{2010-02-05}
|
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
|
+
s.email = %q{raykrueger@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"CHANGELOG",
|
17
|
+
"CONTRIBUTORS.txt",
|
18
|
+
"README.rdoc"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".gitignore",
|
22
|
+
"CHANGELOG",
|
23
|
+
"CONTRIBUTORS.txt",
|
24
|
+
"LICENSE",
|
25
|
+
"README.rdoc",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"examples/PDU1.example",
|
29
|
+
"examples/PDU2.example",
|
30
|
+
"examples/sample_gateway.rb",
|
31
|
+
"examples/sample_smsc.rb",
|
32
|
+
"lib/smpp.rb",
|
33
|
+
"lib/smpp/base.rb",
|
34
|
+
"lib/smpp/pdu/base.rb",
|
35
|
+
"lib/smpp/pdu/bind_base.rb",
|
36
|
+
"lib/smpp/pdu/bind_resp_base.rb",
|
37
|
+
"lib/smpp/pdu/bind_transceiver.rb",
|
38
|
+
"lib/smpp/pdu/bind_transceiver_response.rb",
|
39
|
+
"lib/smpp/pdu/deliver_sm.rb",
|
40
|
+
"lib/smpp/pdu/deliver_sm_response.rb",
|
41
|
+
"lib/smpp/pdu/enquire_link.rb",
|
42
|
+
"lib/smpp/pdu/enquire_link_response.rb",
|
43
|
+
"lib/smpp/pdu/generic_nack.rb",
|
44
|
+
"lib/smpp/pdu/submit_multi.rb",
|
45
|
+
"lib/smpp/pdu/submit_multi_response.rb",
|
46
|
+
"lib/smpp/pdu/submit_sm.rb",
|
47
|
+
"lib/smpp/pdu/submit_sm_response.rb",
|
48
|
+
"lib/smpp/pdu/unbind.rb",
|
49
|
+
"lib/smpp/pdu/unbind_response.rb",
|
50
|
+
"lib/smpp/server.rb",
|
51
|
+
"lib/smpp/transceiver.rb",
|
52
|
+
"lib/sms.rb",
|
53
|
+
"ruby-smpp.gemspec",
|
54
|
+
"test/smpp_test.rb"
|
55
|
+
]
|
56
|
+
s.homepage = %q{http://github.com/raykrueger/ruby-smpp}
|
57
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
15
58
|
s.require_paths = ["lib"]
|
16
59
|
s.rubyforge_project = %q{ruby-smpp}
|
17
|
-
s.rubygems_version = %q{1.3.
|
18
|
-
s.summary = %q{Ruby
|
19
|
-
s.test_files = [
|
60
|
+
s.rubygems_version = %q{1.3.5}
|
61
|
+
s.summary = %q{Ruby implementation of the SMPP protocol, based on EventMachine.}
|
62
|
+
s.test_files = [
|
63
|
+
"test/smpp_test.rb",
|
64
|
+
"examples/sample_gateway.rb",
|
65
|
+
"examples/sample_smsc.rb"
|
66
|
+
]
|
20
67
|
|
21
68
|
if s.respond_to? :specification_version then
|
22
69
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
-
s.specification_version =
|
70
|
+
s.specification_version = 3
|
24
71
|
|
25
72
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
73
|
s.add_runtime_dependency(%q<eventmachine>, [">= 0.10.0"])
|
27
|
-
s.add_development_dependency(%q<
|
74
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
28
75
|
else
|
29
76
|
s.add_dependency(%q<eventmachine>, [">= 0.10.0"])
|
30
|
-
s.add_dependency(%q<
|
77
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
31
78
|
end
|
32
79
|
else
|
33
80
|
s.add_dependency(%q<eventmachine>, [">= 0.10.0"])
|
34
|
-
s.add_dependency(%q<
|
81
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
35
82
|
end
|
36
83
|
end
|
84
|
+
|
data/test/smpp_test.rb
CHANGED
@@ -1,75 +1,179 @@
|
|
1
|
-
$:.unshift File.dirname(__FILE__) + '/../lib/'
|
2
|
-
|
3
1
|
require 'rubygems'
|
4
2
|
require 'test/unit'
|
5
|
-
require 'stringio'
|
6
3
|
require 'smpp'
|
7
4
|
|
8
5
|
# a server which immediately requests the client to unbind
|
9
|
-
module
|
10
|
-
def
|
11
|
-
|
6
|
+
module Server
|
7
|
+
def self.config
|
8
|
+
{
|
9
|
+
:host => 'localhost',
|
10
|
+
:port => 2775,
|
11
|
+
:system_id => 'foo',
|
12
|
+
:password => 'bar',
|
13
|
+
:system_type => '',
|
14
|
+
:source_ton => 0,
|
15
|
+
:source_npi => 1,
|
16
|
+
:destination_ton => 1,
|
17
|
+
:destination_npi => 1,
|
18
|
+
:source_address_range => '',
|
19
|
+
:destination_address_range => ''
|
20
|
+
}
|
12
21
|
end
|
13
|
-
end
|
14
22
|
|
15
|
-
module
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
send_data Smpp::Pdu::SubmitSmResponse.new(1, 2, "100").data
|
23
|
+
module Unbind
|
24
|
+
def receive_data(data)
|
25
|
+
send_data Smpp::Pdu::Unbind.new.data
|
26
|
+
end
|
20
27
|
end
|
28
|
+
|
29
|
+
module SubmitSmResponse
|
30
|
+
def receive_data(data)
|
31
|
+
# problem: our Pdu's should have factory methods for "both ways"; ie. when created
|
32
|
+
# by client, and when created from wire data.
|
33
|
+
send_data Smpp::Pdu::SubmitSmResponse.new(1, 2, "100").data
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module SubmitSmResponseWithErrorStatus
|
38
|
+
attr_reader :state #state=nil => bind => state=bound => send =>state=sent => unbind => state=unbound
|
39
|
+
def receive_data(data)
|
40
|
+
if @state.nil?
|
41
|
+
@state = 'bound'
|
42
|
+
pdu = Smpp::Pdu::Base.create(data)
|
43
|
+
response_pdu = Smpp::Pdu::BindTransceiverResponse.new(pdu.sequence_number,Smpp::Pdu::Base::ESME_ROK,Server::config[:system_id])
|
44
|
+
send_data response_pdu.data
|
45
|
+
elsif @state == 'bound'
|
46
|
+
@state = 'sent'
|
47
|
+
pdu = Smpp::Pdu::Base.create(data)
|
48
|
+
pdu.to_human
|
49
|
+
send_data Smpp::Pdu::SubmitSmResponse.new(pdu.sequence_number, Smpp::Pdu::Base::ESME_RINVDSTADR, pdu.body).data
|
50
|
+
#send_data Smpp::Pdu::SubmitSmResponse.new(1, 2, "100").data
|
51
|
+
elsif @state == 'sent'
|
52
|
+
@state = 'unbound'
|
53
|
+
send_data Smpp::Pdu::Unbind.new.data
|
54
|
+
else
|
55
|
+
raise "unexpected state"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
21
60
|
end
|
22
61
|
|
62
|
+
|
23
63
|
# the delagate receives callbacks when interesting things happen on the connection
|
24
64
|
class Delegate
|
25
|
-
|
65
|
+
|
66
|
+
def mo_received(transceiver, pdu)
|
67
|
+
puts "** mo_received"
|
68
|
+
end
|
69
|
+
|
70
|
+
def delivery_report_received(transceiver, pdu)
|
71
|
+
puts "** delivery_report_received"
|
72
|
+
end
|
73
|
+
|
74
|
+
def message_accepted(transceiver, mt_message_id, pdu)
|
75
|
+
puts "** message_sent"
|
76
|
+
end
|
77
|
+
|
78
|
+
def message_rejected(transceiver, mt_message_id, pdu)
|
79
|
+
puts "** message_rejected"
|
80
|
+
end
|
81
|
+
|
82
|
+
def bound(transceiver)
|
83
|
+
puts "** bound"
|
84
|
+
end
|
85
|
+
|
86
|
+
def unbound(transceiver)
|
87
|
+
puts "** unbound"
|
88
|
+
EventMachine::stop_event_loop
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
#TODO This should be made prettier with mocha
|
93
|
+
class ResponsiveDelegate
|
94
|
+
attr_reader :seq, :event_counter
|
95
|
+
|
96
|
+
def initialize
|
97
|
+
@seq = 0
|
98
|
+
@event_counter = nil
|
99
|
+
end
|
100
|
+
def seq
|
101
|
+
@seq += 1
|
102
|
+
end
|
103
|
+
def count_function
|
104
|
+
func = caller(1)[0].split("`")[1].split("'")[0].to_sym
|
105
|
+
@event_counter = {} unless @event_counter.is_a?(Hash)
|
106
|
+
@event_counter[func] = 0 if @event_counter[func].nil?
|
107
|
+
@event_counter[func]+=1
|
108
|
+
end
|
109
|
+
|
110
|
+
def mo_received(transceiver, pdu)
|
111
|
+
count_function
|
26
112
|
puts "** mo_received"
|
27
113
|
end
|
28
114
|
|
29
|
-
def delivery_report_received(transceiver,
|
115
|
+
def delivery_report_received(transceiver, pdu)
|
116
|
+
count_function
|
30
117
|
puts "** delivery_report_received"
|
31
118
|
end
|
32
119
|
|
33
|
-
def message_accepted(transceiver, mt_message_id,
|
120
|
+
def message_accepted(transceiver, mt_message_id, pdu)
|
121
|
+
count_function
|
34
122
|
puts "** message_sent"
|
123
|
+
#sending messages from delegate to escape making a fake message sender - not nice :(
|
124
|
+
$tx.send_mt(self.seq, 1, 2, "short_message @ message_accepted")
|
125
|
+
end
|
126
|
+
|
127
|
+
def message_rejected(transceiver, mt_message_id, pdu)
|
128
|
+
count_function
|
129
|
+
puts "** message_rejected"
|
130
|
+
$tx.send_mt(self.seq, 1, 2, "short_message @ message_rejected")
|
35
131
|
end
|
36
132
|
|
37
133
|
def bound(transceiver)
|
134
|
+
count_function
|
38
135
|
puts "** bound"
|
136
|
+
$tx.send_mt(self.seq, 1, 2, "short_message @ bound")
|
39
137
|
end
|
40
138
|
|
41
|
-
def unbound(transceiver)
|
139
|
+
def unbound(transceiver)
|
140
|
+
count_function
|
42
141
|
puts "** unbound"
|
43
142
|
EventMachine::stop_event_loop
|
44
143
|
end
|
45
144
|
end
|
46
145
|
|
146
|
+
class Poller
|
147
|
+
def start
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
|
47
153
|
class SmppTest < Test::Unit::TestCase
|
48
154
|
|
49
155
|
def config
|
50
|
-
|
51
|
-
:host => 'localhost',
|
52
|
-
:port => 2775,
|
53
|
-
:system_id => 'foo',
|
54
|
-
:password => 'bar',
|
55
|
-
:system_type => '',
|
56
|
-
:source_ton => 0,
|
57
|
-
:source_npi => 1,
|
58
|
-
:destination_ton => 1,
|
59
|
-
:destination_npi => 1,
|
60
|
-
:source_address_range => '',
|
61
|
-
:destination_address_range => ''
|
62
|
-
}
|
156
|
+
Server::config
|
63
157
|
end
|
64
158
|
|
65
159
|
def test_transceiver_should_bind_and_unbind_then_stop
|
66
160
|
EventMachine.run {
|
67
|
-
EventMachine.start_server "localhost", 9000,
|
161
|
+
EventMachine.start_server "localhost", 9000, Server::Unbind
|
68
162
|
EventMachine.connect "localhost", 9000, Smpp::Transceiver, config, Delegate.new
|
69
163
|
}
|
70
164
|
# should not hang here: the server's response should have caused the client to terminate
|
71
165
|
end
|
72
166
|
|
167
|
+
def test_transceiver_api_should_respond_to_message_rejected
|
168
|
+
$tx = nil
|
169
|
+
delegate = ResponsiveDelegate.new
|
170
|
+
EventMachine.run {
|
171
|
+
EventMachine.start_server "localhost", 9000, Server::SubmitSmResponseWithErrorStatus
|
172
|
+
$tx = EventMachine.connect "localhost", 9000, Smpp::Transceiver, config, delegate
|
173
|
+
}
|
174
|
+
assert_equal(delegate.event_counter[:message_rejected], 1)
|
175
|
+
end
|
176
|
+
|
73
177
|
def test_bind_transceiver
|
74
178
|
pdu1 = Smpp::Pdu::BindTransceiver.new(
|
75
179
|
config[:system_id],
|
@@ -158,6 +262,11 @@ class SmppTest < Test::Unit::TestCase
|
|
158
262
|
assert_equal(pdu1.command_status, pdu2.command_status)
|
159
263
|
end
|
160
264
|
|
265
|
+
def test_submit_sm_receiving_invalid_status
|
266
|
+
pdu1 = Smpp::Pdu::SubmitSm.new( '11111', '1111111111', "This is a test" )
|
267
|
+
pdu2 = Smpp::Pdu::Base.create(pdu1.data)
|
268
|
+
end
|
269
|
+
|
161
270
|
def test_deliver_sm_response
|
162
271
|
pdu1 = Smpp::Pdu::DeliverSmResponse.new( nil )
|
163
272
|
pdu2 = Smpp::Pdu::Base.create(pdu1.data)
|
@@ -256,5 +365,13 @@ class SmppTest < Test::Unit::TestCase
|
|
256
365
|
assert_equal(pdu1.sequence_number, pdu2.sequence_number)
|
257
366
|
assert_equal(pdu1.command_status, pdu2.command_status)
|
258
367
|
end
|
368
|
+
|
369
|
+
def test_should_parse_ref_and_stat_from_deliver_sm
|
370
|
+
direct = Smpp::Pdu::DeliverSm.new( '1', '2', "419318028472222#id:11f8f46639bd4f7a209016e1a181e3ae sub:001 dlvrd:001 submit date:0902191702 done date:0902191702 stat:DELIVRD err:000 Text:TVILLING: Sl? ut h?'!11f8f46639bd4f7a209016e1a181e3ae", :esm_class => 4)
|
371
|
+
parsed = Smpp::Pdu::Base.create(direct.data)
|
372
|
+
assert_equal("DELIVRD", parsed.stat)
|
373
|
+
assert_equal("11f8f46639bd4f7a209016e1a181e3ae", parsed.msg_reference)
|
374
|
+
end
|
375
|
+
|
259
376
|
|
260
377
|
end
|