anjlab-ruby-smpp 0.6.3 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +28 -0
- data/.travis.yml +6 -0
- data/Gemfile +3 -7
- data/Gemfile.lock +11 -8
- data/README.rdoc +11 -9
- data/Rakefile +1 -44
- data/anjlab-ruby-smpp.gemspec +21 -93
- data/examples/sample_gateway.rb +24 -24
- data/lib/smpp.rb +2 -1
- data/lib/smpp/base.rb +67 -52
- data/lib/smpp/encoding/utf8_encoder.rb +1 -1
- data/lib/smpp/optional_parameter.rb +4 -1
- data/lib/smpp/pdu/base.rb +1 -1
- data/lib/smpp/pdu/deliver_sm.rb +8 -0
- data/lib/smpp/server.rb +1 -1
- data/lib/smpp/transmitter.rb +64 -0
- data/lib/smpp/version.rb +3 -0
- metadata +65 -31
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 422a4789de23b5d5d553e358c14f9fc51084a563
|
4
|
+
data.tar.gz: 11ee81c9199fe2538ca0ef75ad07373800961cf7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0c8a7f4e2b3349b639095a7cefbb1638a3a83a78e6232e9be37f21e536e6353b9441cdaf9f08915ab6de462d72f15a895ad834ec4f45371f771c714d63a83885
|
7
|
+
data.tar.gz: 46b026a70ed509c048634f8bd69026f415866b6eb71190ca213b8e181c4d3651bd40f0158f1763e86f8b524d28586b2ff8d10dea956abc1b27a76359a6a9cbee
|
data/.gitignore
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
*.gem
|
8
|
+
|
9
|
+
## EMACS
|
10
|
+
*~
|
11
|
+
\#*
|
12
|
+
.\#*
|
13
|
+
|
14
|
+
## VIM
|
15
|
+
*.swp
|
16
|
+
|
17
|
+
## PROJECT::GENERAL
|
18
|
+
coverage
|
19
|
+
rdoc
|
20
|
+
pkg
|
21
|
+
tags
|
22
|
+
.bundle
|
23
|
+
vendor/ruby
|
24
|
+
.rvmrc
|
25
|
+
|
26
|
+
## PROJECT::SPECIFIC
|
27
|
+
*.log
|
28
|
+
nbproject
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,18 +1,21 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ruby-smpp (0.6.0)
|
5
|
+
eventmachine (>= 0.10.0)
|
6
|
+
|
1
7
|
GEM
|
2
|
-
remote:
|
8
|
+
remote: https://rubygems.org/
|
3
9
|
specs:
|
4
10
|
eventmachine (0.12.10)
|
5
|
-
git (1.2.5)
|
6
|
-
jeweler (1.6.4)
|
7
|
-
bundler (~> 1.0)
|
8
|
-
git (>= 1.2.5)
|
9
|
-
rake
|
10
11
|
rake (0.9.2)
|
12
|
+
test-unit (2.5.4)
|
11
13
|
|
12
14
|
PLATFORMS
|
13
15
|
ruby
|
14
16
|
|
15
17
|
DEPENDENCIES
|
16
|
-
|
17
|
-
jeweler
|
18
|
+
bundler (~> 1.3)
|
18
19
|
rake
|
20
|
+
ruby-smpp!
|
21
|
+
test-unit
|
data/README.rdoc
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
= Ruby-SMPP
|
2
2
|
|
3
|
+
{<img src="https://travis-ci.org/raykrueger/ruby-smpp.png" />}[https://travis-ci.org/raykrueger/ruby-smpp]
|
4
|
+
|
3
5
|
== DESCRIPTION:
|
4
6
|
|
5
7
|
Ruby-SMPP is a Ruby implementation of the SMPP v3.4 protocol. It is suitable for writing gateway daemons that communicate with SMSCs for sending and receiving SMS messages.
|
@@ -24,7 +26,7 @@ The SMPP 3.4 protocol spec can be downloaded here: http://smsforum.net/SMPP_v3_4
|
|
24
26
|
|
25
27
|
=== Testing/Sample Code
|
26
28
|
|
27
|
-
Logica provides an SMPP simulator that you can download from http://opensmpp.logica.com. You can
|
29
|
+
Logica provides an SMPP simulator that you can download from http://opensmpp.logica.com. You can
|
28
30
|
also sign up for a demo SMPP account at one of the many bulk-SMS providers out there.
|
29
31
|
|
30
32
|
For a quick test, download smscsim.jar and smpp.jar from the Logica site, and start the simulator by typing:
|
@@ -35,7 +37,7 @@ Then type 1 (start simulation), and enter 6000 for port number. The simulator th
|
|
35
37
|
|
36
38
|
ruby sample_gateway.rb
|
37
39
|
|
38
|
-
You will be able to send MT messages from the sample gateway terminal window by typing the message body. In the simulator terminal window you should see SMPP PDUs being sent from the sample gateway.
|
40
|
+
You will be able to send MT messages from the sample gateway terminal window by typing the message body. In the simulator terminal window you should see SMPP PDUs being sent from the sample gateway.
|
39
41
|
|
40
42
|
You can also send MO messages from the simulator to the sample gateway by typing 7 (log to screen off) and then 4 (send message). MO messages received by the sample gateway will be logged to ./sms_gateway.log.
|
41
43
|
|
@@ -47,18 +49,18 @@ You can also send MO messages from the simulator to the sample gateway by typing
|
|
47
49
|
|
48
50
|
== BASIC USAGE:
|
49
51
|
|
50
|
-
Start the transceiver. Receive delegate callbacks whenever incoming messages or delivery reports arrive. Send messages with Transceiver#send_mt.
|
52
|
+
Start the transceiver. Receive delegate callbacks whenever incoming messages or delivery reports arrive. Send messages with Transceiver#send_mt.
|
51
53
|
|
52
54
|
# connect to SMSC
|
53
|
-
tx = EventMachine::run do
|
55
|
+
tx = EventMachine::run do
|
54
56
|
$tx = EventMachine::connect(
|
55
|
-
host,
|
56
|
-
port,
|
57
|
-
Smpp::Transceiver,
|
58
|
-
config, # a property hash
|
57
|
+
host,
|
58
|
+
port,
|
59
|
+
Smpp::Transceiver,
|
60
|
+
config, # a property hash
|
59
61
|
delegate # delegate class that will receive callbacks on MOs and DRs and other events
|
60
62
|
end
|
61
|
-
|
63
|
+
|
62
64
|
# send a message
|
63
65
|
tx.send_mt(id, from, to, body)
|
64
66
|
|
data/Rakefile
CHANGED
@@ -1,24 +1,4 @@
|
|
1
|
-
require
|
2
|
-
require 'rake'
|
3
|
-
|
4
|
-
begin
|
5
|
-
require 'jeweler'
|
6
|
-
Jeweler::Tasks.new do |gem|
|
7
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
8
|
-
gem.name = "anjlab-ruby-smpp"
|
9
|
-
gem.summary = %Q{Ruby implementation of the SMPP protocol, based on EventMachine.}
|
10
|
-
gem.description = gem.summary + " SMPP is a protocol that allows ordinary people outside the mobile network to exchange SMS messages directly with mobile operators."
|
11
|
-
gem.email = "raykrueger@gmail.com"
|
12
|
-
gem.homepage = "http://github.com/raykrueger/ruby-smpp"
|
13
|
-
gem.authors = ["Ray Krueger", "August Z. Flatby"]
|
14
|
-
gem.rubyforge_project = gem.name
|
15
|
-
|
16
|
-
gem.extra_rdoc_files = ["README.rdoc", "CHANGELOG", "CONTRIBUTORS.txt"]
|
17
|
-
end
|
18
|
-
Jeweler::GemcutterTasks.new
|
19
|
-
rescue LoadError
|
20
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
21
|
-
end
|
1
|
+
require "bundler/gem_tasks"
|
22
2
|
|
23
3
|
require 'rake/testtask'
|
24
4
|
Rake::TestTask.new(:test) do |test|
|
@@ -27,27 +7,4 @@ Rake::TestTask.new(:test) do |test|
|
|
27
7
|
test.verbose = true
|
28
8
|
end
|
29
9
|
|
30
|
-
begin
|
31
|
-
require 'rcov/rcovtask'
|
32
|
-
Rcov::RcovTask.new do |test|
|
33
|
-
test.libs << 'test'
|
34
|
-
test.pattern = 'test/**/*_test.rb'
|
35
|
-
test.verbose = true
|
36
|
-
end
|
37
|
-
rescue LoadError
|
38
|
-
task :rcov do
|
39
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
10
|
task :default => :test
|
44
|
-
|
45
|
-
require 'rake/rdoctask'
|
46
|
-
Rake::RDocTask.new do |rdoc|
|
47
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
-
|
49
|
-
rdoc.rdoc_dir = 'rdoc'
|
50
|
-
rdoc.title = "ruby-smpp #{version}"
|
51
|
-
rdoc.rdoc_files.include('README*', "CHANGELOG", "CONTRIBUTORS.txt", "LICENSE")
|
52
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
-
end
|
data/anjlab-ruby-smpp.gemspec
CHANGED
@@ -1,98 +1,26 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'smpp/version'
|
5
5
|
|
6
|
-
Gem::Specification.new do |
|
7
|
-
|
8
|
-
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "anjlab-ruby-smpp"
|
8
|
+
spec.version = Smpp::VERSION
|
9
|
+
spec.authors = ["Ray Krueger", "August Z. Flatby"]
|
10
|
+
spec.email = ["raykrueger@gmail.com"]
|
11
|
+
spec.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.}
|
12
|
+
spec.summary = %q{Ruby implementation of the SMPP protocol, based on EventMachine.}
|
13
|
+
spec.homepage = "http://github.com/raykrueger/ruby-smpp"
|
14
|
+
spec.license = "MIT"
|
9
15
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
s.email = "raykrueger@gmail.com"
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"CHANGELOG",
|
17
|
-
"CONTRIBUTORS.txt",
|
18
|
-
"README.rdoc"
|
19
|
-
]
|
20
|
-
s.files = [
|
21
|
-
"CHANGELOG",
|
22
|
-
"CONTRIBUTORS.txt",
|
23
|
-
"Gemfile",
|
24
|
-
"Gemfile.lock",
|
25
|
-
"LICENSE",
|
26
|
-
"README.rdoc",
|
27
|
-
"Rakefile",
|
28
|
-
"VERSION",
|
29
|
-
"anjlab-ruby-smpp.gemspec",
|
30
|
-
"config/environment.rb",
|
31
|
-
"examples/PDU1.example",
|
32
|
-
"examples/PDU2.example",
|
33
|
-
"examples/sample_gateway.rb",
|
34
|
-
"examples/sample_smsc.rb",
|
35
|
-
"lib/smpp.rb",
|
36
|
-
"lib/smpp/base.rb",
|
37
|
-
"lib/smpp/encoding/utf8_encoder.rb",
|
38
|
-
"lib/smpp/optional_parameter.rb",
|
39
|
-
"lib/smpp/pdu/base.rb",
|
40
|
-
"lib/smpp/pdu/bind_base.rb",
|
41
|
-
"lib/smpp/pdu/bind_receiver.rb",
|
42
|
-
"lib/smpp/pdu/bind_receiver_response.rb",
|
43
|
-
"lib/smpp/pdu/bind_resp_base.rb",
|
44
|
-
"lib/smpp/pdu/bind_transceiver.rb",
|
45
|
-
"lib/smpp/pdu/bind_transceiver_response.rb",
|
46
|
-
"lib/smpp/pdu/bind_transmitter.rb",
|
47
|
-
"lib/smpp/pdu/bind_transmitter_response.rb",
|
48
|
-
"lib/smpp/pdu/deliver_sm.rb",
|
49
|
-
"lib/smpp/pdu/deliver_sm_response.rb",
|
50
|
-
"lib/smpp/pdu/enquire_link.rb",
|
51
|
-
"lib/smpp/pdu/enquire_link_response.rb",
|
52
|
-
"lib/smpp/pdu/generic_nack.rb",
|
53
|
-
"lib/smpp/pdu/submit_multi.rb",
|
54
|
-
"lib/smpp/pdu/submit_multi_response.rb",
|
55
|
-
"lib/smpp/pdu/submit_sm.rb",
|
56
|
-
"lib/smpp/pdu/submit_sm_response.rb",
|
57
|
-
"lib/smpp/pdu/unbind.rb",
|
58
|
-
"lib/smpp/pdu/unbind_response.rb",
|
59
|
-
"lib/smpp/receiver.rb",
|
60
|
-
"lib/smpp/server.rb",
|
61
|
-
"lib/smpp/transceiver.rb",
|
62
|
-
"lib/sms.rb",
|
63
|
-
"test/delegate.rb",
|
64
|
-
"test/encoding_test.rb",
|
65
|
-
"test/optional_parameter_test.rb",
|
66
|
-
"test/pdu_parsing_test.rb",
|
67
|
-
"test/receiver_test.rb",
|
68
|
-
"test/responsive_delegate.rb",
|
69
|
-
"test/server.rb",
|
70
|
-
"test/smpp_test.rb",
|
71
|
-
"test/submit_sm_test.rb",
|
72
|
-
"test/transceiver_test.rb"
|
73
|
-
]
|
74
|
-
s.homepage = "http://github.com/raykrueger/ruby-smpp"
|
75
|
-
s.require_paths = ["lib"]
|
76
|
-
s.rubyforge_project = "anjlab-ruby-smpp"
|
77
|
-
s.rubygems_version = "1.8.17"
|
78
|
-
s.summary = "Ruby implementation of the SMPP protocol, based on EventMachine."
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
79
20
|
|
80
|
-
|
81
|
-
s.specification_version = 3
|
21
|
+
spec.add_dependency "eventmachine", ">= 0.10.0"
|
82
22
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
s.add_development_dependency(%q<rake>, [">= 0"])
|
87
|
-
else
|
88
|
-
s.add_dependency(%q<eventmachine>, [">= 0.10.0"])
|
89
|
-
s.add_dependency(%q<jeweler>, [">= 0"])
|
90
|
-
s.add_dependency(%q<rake>, [">= 0"])
|
91
|
-
end
|
92
|
-
else
|
93
|
-
s.add_dependency(%q<eventmachine>, [">= 0.10.0"])
|
94
|
-
s.add_dependency(%q<jeweler>, [">= 0"])
|
95
|
-
s.add_dependency(%q<rake>, [">= 0"])
|
96
|
-
end
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "test-unit"
|
97
26
|
end
|
98
|
-
|
data/examples/sample_gateway.rb
CHANGED
@@ -20,15 +20,15 @@ module KeyboardHandler
|
|
20
20
|
def receive_line(data)
|
21
21
|
sender, receiver, *body_parts = data.split
|
22
22
|
unless sender && receiver && body_parts.size > 0
|
23
|
-
puts "Syntax: <sender> <receiver> <message body>"
|
23
|
+
puts "Syntax: <sender> <receiver> <message body>"
|
24
24
|
else
|
25
25
|
body = body_parts.join(' ')
|
26
|
-
puts "Sending MT from #{sender} to #{receiver}: #{body}"
|
26
|
+
puts "Sending MT from #{sender} to #{receiver}: #{body}"
|
27
27
|
SampleGateway.send_mt(sender, receiver, body)
|
28
28
|
end
|
29
29
|
prompt
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def prompt
|
33
33
|
print "MT: "
|
34
34
|
$stdout.flush
|
@@ -36,16 +36,16 @@ module KeyboardHandler
|
|
36
36
|
end
|
37
37
|
|
38
38
|
class SampleGateway
|
39
|
-
|
40
|
-
# MT id counter.
|
39
|
+
|
40
|
+
# MT id counter.
|
41
41
|
@@mt_id = 0
|
42
|
-
|
42
|
+
|
43
43
|
# expose SMPP transceiver's send_mt method
|
44
44
|
def self.send_mt(*args)
|
45
45
|
@@mt_id += 1
|
46
46
|
@@tx.send_mt(@@mt_id, *args)
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def logger
|
50
50
|
Smpp::Base.logger
|
51
51
|
end
|
@@ -53,22 +53,22 @@ class SampleGateway
|
|
53
53
|
def start(config)
|
54
54
|
# The transceiver sends MT messages to the SMSC. It needs a storage with Hash-like
|
55
55
|
# semantics to map SMSC message IDs to your own message IDs.
|
56
|
-
pdr_storage = {}
|
56
|
+
pdr_storage = {}
|
57
57
|
|
58
58
|
# Run EventMachine in loop so we can reconnect when the SMSC drops our connection.
|
59
59
|
puts "Connecting to SMSC..."
|
60
60
|
loop do
|
61
|
-
EventMachine::run do
|
61
|
+
EventMachine::run do
|
62
62
|
@@tx = EventMachine::connect(
|
63
|
-
config[:host],
|
64
|
-
config[:port],
|
65
|
-
Smpp::Transceiver,
|
66
|
-
config,
|
63
|
+
config[:host],
|
64
|
+
config[:port],
|
65
|
+
Smpp::Transceiver,
|
66
|
+
config,
|
67
67
|
self # delegate that will receive callbacks on MOs and DRs and other events
|
68
|
-
)
|
68
|
+
)
|
69
69
|
print "MT: "
|
70
70
|
$stdout.flush
|
71
|
-
|
71
|
+
|
72
72
|
# Start consuming MT messages (in this case, from the console)
|
73
73
|
# Normally, you'd hook this up to a message queue such as Starling
|
74
74
|
# or ActiveMQ via STOMP.
|
@@ -78,8 +78,8 @@ class SampleGateway
|
|
78
78
|
sleep 5
|
79
79
|
end
|
80
80
|
end
|
81
|
-
|
82
|
-
# ruby-smpp delegate methods
|
81
|
+
|
82
|
+
# ruby-smpp delegate methods
|
83
83
|
|
84
84
|
def mo_received(transceiver, pdu)
|
85
85
|
logger.info "Delegate: mo_received: from #{pdu.source_addr} to #{pdu.destination_addr}: #{pdu.short_message}"
|
@@ -101,19 +101,19 @@ class SampleGateway
|
|
101
101
|
logger.info "Delegate: transceiver bound"
|
102
102
|
end
|
103
103
|
|
104
|
-
def unbound(transceiver)
|
104
|
+
def unbound(transceiver)
|
105
105
|
logger.info "Delegate: transceiver unbound"
|
106
106
|
EventMachine::stop_event_loop
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
end
|
110
110
|
|
111
111
|
# Start the Gateway
|
112
|
-
begin
|
113
|
-
puts "Starting SMS Gateway. Please check the log at #{LOGFILE}"
|
112
|
+
begin
|
113
|
+
puts "Starting SMS Gateway. Please check the log at #{LOGFILE}"
|
114
114
|
|
115
115
|
# SMPP properties. These parameters work well with the Logica SMPP simulator.
|
116
|
-
# Consult the SMPP spec or your mobile operator for the correct settings of
|
116
|
+
# Consult the SMPP spec or your mobile operator for the correct settings of
|
117
117
|
# the other properties.
|
118
118
|
config = {
|
119
119
|
:host => '127.0.0.1',
|
@@ -129,9 +129,9 @@ begin
|
|
129
129
|
:source_address_range => '',
|
130
130
|
:destination_address_range => '',
|
131
131
|
:enquire_link_delay_secs => 10
|
132
|
-
}
|
132
|
+
}
|
133
133
|
gw = SampleGateway.new
|
134
|
-
gw.start(config)
|
134
|
+
gw.start(config)
|
135
135
|
rescue Exception => ex
|
136
136
|
puts "Exception in SMS Gateway: #{ex} at #{ex.backtrace.join("\n")}"
|
137
137
|
end
|
data/lib/smpp.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# SMPP v3.4 subset implementation.
|
2
|
-
# SMPP is a short message peer-to-peer protocol typically used to communicate
|
2
|
+
# SMPP is a short message peer-to-peer protocol typically used to communicate
|
3
3
|
# with SMS Centers (SMSCs) over TCP/IP.
|
4
4
|
#
|
5
5
|
# August Z. Flatby
|
@@ -10,6 +10,7 @@ require 'logger'
|
|
10
10
|
$:.unshift(File.dirname(__FILE__))
|
11
11
|
require 'smpp/base.rb'
|
12
12
|
require 'smpp/transceiver.rb'
|
13
|
+
require 'smpp/transmitter.rb'
|
13
14
|
require 'smpp/receiver.rb'
|
14
15
|
require 'smpp/optional_parameter'
|
15
16
|
require 'smpp/pdu/base.rb'
|
data/lib/smpp/base.rb
CHANGED
@@ -5,13 +5,13 @@ require 'eventmachine'
|
|
5
5
|
|
6
6
|
module Smpp
|
7
7
|
class InvalidStateException < Exception; end
|
8
|
-
|
8
|
+
|
9
9
|
class Base < EventMachine::Connection
|
10
10
|
include Smpp
|
11
|
-
|
11
|
+
|
12
12
|
# :bound or :unbound
|
13
13
|
attr_accessor :state
|
14
|
-
|
14
|
+
|
15
15
|
def initialize(config, delegate)
|
16
16
|
@state = :unbound
|
17
17
|
@config = config
|
@@ -19,7 +19,7 @@ module Smpp
|
|
19
19
|
@delegate = delegate
|
20
20
|
|
21
21
|
# Array of un-acked MT message IDs indexed by sequence number.
|
22
|
-
# As soon as we receive SubmitSmResponse we will use this to find the
|
22
|
+
# As soon as we receive SubmitSmResponse we will use this to find the
|
23
23
|
# associated message ID, and then create a pending delivery report.
|
24
24
|
@ack_ids = {}
|
25
25
|
|
@@ -31,11 +31,11 @@ module Smpp
|
|
31
31
|
def unbound?
|
32
32
|
@state == :unbound
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def bound?
|
36
36
|
@state == :bound
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def Base.logger
|
40
40
|
@@logger
|
41
41
|
end
|
@@ -47,8 +47,8 @@ module Smpp
|
|
47
47
|
def logger
|
48
48
|
@@logger
|
49
49
|
end
|
50
|
-
|
51
|
-
|
50
|
+
|
51
|
+
|
52
52
|
# invoked by EventMachine when connected
|
53
53
|
def post_init
|
54
54
|
# send Bind PDU if we are a binder (eg
|
@@ -68,9 +68,10 @@ module Smpp
|
|
68
68
|
# method named: periodic_call_method
|
69
69
|
def start_enquire_link_timer(delay_secs)
|
70
70
|
logger.info "Starting enquire link timer (with #{delay_secs}s interval)"
|
71
|
-
EventMachine::PeriodicTimer.new(delay_secs) do
|
71
|
+
timer = EventMachine::PeriodicTimer.new(delay_secs) do
|
72
72
|
if error?
|
73
73
|
logger.warn "Link timer: Connection is in error state. Disconnecting."
|
74
|
+
timer.cancel
|
74
75
|
close_connection
|
75
76
|
elsif unbound?
|
76
77
|
logger.warn "Link is unbound, waiting until next #{delay_secs} interval before querying again"
|
@@ -81,7 +82,7 @@ module Smpp
|
|
81
82
|
rval = defined?(periodic_call_method) ? periodic_call_method : true
|
82
83
|
|
83
84
|
# only send an OK if this worked
|
84
|
-
write_pdu Pdu::EnquireLink.new if rval
|
85
|
+
write_pdu Pdu::EnquireLink.new if rval
|
85
86
|
end
|
86
87
|
end
|
87
88
|
end
|
@@ -108,31 +109,33 @@ module Smpp
|
|
108
109
|
process_pdu(pdu) if pdu
|
109
110
|
rescue Exception => e
|
110
111
|
logger.error "Error receiving data: #{e}\n#{e.backtrace.join("\n")}"
|
111
|
-
|
112
|
-
@delegate.data_error(e)
|
113
|
-
end
|
112
|
+
run_callback(:data_error, e)
|
114
113
|
end
|
115
114
|
|
116
115
|
end
|
117
116
|
end
|
118
|
-
|
117
|
+
|
119
118
|
# EventMachine::Connection#unbind
|
120
119
|
# Invoked by EM when connection is closed. Delegates should consider
|
121
120
|
# breaking the event loop and reconnect when they receive this callback.
|
122
121
|
def unbind
|
123
|
-
|
124
|
-
@delegate.unbound(self)
|
125
|
-
end
|
122
|
+
run_callback(:unbound, self)
|
126
123
|
end
|
127
|
-
|
124
|
+
|
128
125
|
def send_unbind
|
129
126
|
write_pdu Pdu::Unbind.new
|
130
127
|
@state = :unbound
|
131
128
|
end
|
132
129
|
|
130
|
+
def run_callback(cb, *args)
|
131
|
+
if @delegate.respond_to?(cb)
|
132
|
+
@delegate.send(cb, *args)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
133
136
|
# process common PDUs
|
134
137
|
# returns true if no further processing necessary
|
135
|
-
def process_pdu(pdu)
|
138
|
+
def process_pdu(pdu)
|
136
139
|
case pdu
|
137
140
|
when Pdu::EnquireLinkResponse
|
138
141
|
# nop
|
@@ -142,7 +145,7 @@ module Smpp
|
|
142
145
|
@state = :unbound
|
143
146
|
write_pdu(Pdu::UnbindResponse.new(pdu.sequence_number, Pdu::Base::ESME_ROK))
|
144
147
|
close_connection
|
145
|
-
when Pdu::UnbindResponse
|
148
|
+
when Pdu::UnbindResponse
|
146
149
|
logger.info "Unbound OK. Closing connection."
|
147
150
|
close_connection
|
148
151
|
when Pdu::GenericNack
|
@@ -154,15 +157,11 @@ module Smpp
|
|
154
157
|
logger.debug "ESM CLASS #{pdu.esm_class}"
|
155
158
|
if pdu.esm_class != 4
|
156
159
|
# MO message
|
157
|
-
|
158
|
-
@delegate.mo_received(self, pdu)
|
159
|
-
end
|
160
|
+
run_callback(:mo_received, self, pdu)
|
160
161
|
else
|
161
162
|
# Delivery report
|
162
|
-
|
163
|
-
|
164
|
-
end
|
165
|
-
end
|
163
|
+
run_callback(:delivery_report_received, self, pdu)
|
164
|
+
end
|
166
165
|
write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number))
|
167
166
|
rescue => e
|
168
167
|
logger.warn "Send Receiver Temporary App Error due to #{e.inspect} raised in delegate"
|
@@ -173,19 +172,20 @@ module Smpp
|
|
173
172
|
when Pdu::Base::ESME_ROK
|
174
173
|
logger.debug "Bound OK."
|
175
174
|
@state = :bound
|
176
|
-
|
177
|
-
@delegate.bound(self)
|
178
|
-
end
|
175
|
+
run_callback(:bound, self)
|
179
176
|
when Pdu::Base::ESME_RINVPASWD
|
180
177
|
logger.warn "Invalid password."
|
181
|
-
#
|
178
|
+
# schedule the connection to close, which eventually will cause the unbound() delegate
|
182
179
|
# method to be invoked.
|
180
|
+
run_callback(:invalid_password, self)
|
183
181
|
close_connection
|
184
182
|
when Pdu::Base::ESME_RINVSYSID
|
185
183
|
logger.warn "Invalid system id."
|
184
|
+
run_callback(:invalid_system_id, self)
|
186
185
|
close_connection
|
187
186
|
else
|
188
187
|
logger.warn "Unexpected BindTransceiverResponse. Command status: #{pdu.command_status}"
|
188
|
+
run_callback(:unexpected_error, self)
|
189
189
|
close_connection
|
190
190
|
end
|
191
191
|
when Pdu::SubmitSmResponse
|
@@ -195,14 +195,10 @@ module Smpp
|
|
195
195
|
end
|
196
196
|
if pdu.command_status != Pdu::Base::ESME_ROK
|
197
197
|
logger.error "Error status in SubmitSmResponse: #{pdu.command_status}"
|
198
|
-
|
199
|
-
@delegate.message_rejected(self, mt_message_id, pdu)
|
200
|
-
end
|
198
|
+
run_callback(:message_rejected, self, mt_message_id, pdu)
|
201
199
|
else
|
202
200
|
logger.info "Got OK SubmitSmResponse (#{pdu.message_id} -> #{mt_message_id})"
|
203
|
-
|
204
|
-
@delegate.message_accepted(self, mt_message_id, pdu)
|
205
|
-
end
|
201
|
+
run_callback(:message_accepted, self, mt_message_id, pdu)
|
206
202
|
end
|
207
203
|
when Pdu::SubmitMultiResponse
|
208
204
|
mt_message_id = @ack_ids[pdu.sequence_number]
|
@@ -211,42 +207,61 @@ module Smpp
|
|
211
207
|
end
|
212
208
|
if pdu.command_status != Pdu::Base::ESME_ROK
|
213
209
|
logger.error "Error status in SubmitMultiResponse: #{pdu.command_status}"
|
214
|
-
|
215
|
-
@delegate.message_rejected(self, mt_message_id, pdu)
|
216
|
-
end
|
210
|
+
run_callback(:message_rejected, self, mt_message_id, pdu)
|
217
211
|
else
|
218
212
|
logger.info "Got OK SubmitMultiResponse (#{pdu.message_id} -> #{mt_message_id})"
|
219
|
-
|
220
|
-
@delegate.message_accepted(self, mt_message_id, pdu)
|
221
|
-
end
|
213
|
+
run_callback(:message_accepted, self, mt_message_id, pdu)
|
222
214
|
end
|
223
215
|
when Pdu::BindReceiverResponse
|
224
216
|
case pdu.command_status
|
225
217
|
when Pdu::Base::ESME_ROK
|
226
218
|
logger.debug "Bound OK."
|
227
219
|
@state = :bound
|
228
|
-
|
229
|
-
|
230
|
-
|
220
|
+
run_callback(:bound, self)
|
221
|
+
when Pdu::Base::ESME_RINVPASWD
|
222
|
+
logger.warn "Invalid password."
|
223
|
+
run_callback(:invalid_password, self)
|
224
|
+
# scheduele the connection to close, which eventually will cause the unbound() delegate
|
225
|
+
# method to be invoked.
|
226
|
+
close_connection
|
227
|
+
when Pdu::Base::ESME_RINVSYSID
|
228
|
+
logger.warn "Invalid system id."
|
229
|
+
run_callback(:invalid_system_id, self)
|
230
|
+
close_connection
|
231
|
+
else
|
232
|
+
logger.warn "Unexpected BindReceiverResponse. Command status: #{pdu.command_status}"
|
233
|
+
run_callback(:unexpected_error, self)
|
234
|
+
close_connection
|
235
|
+
end
|
236
|
+
when Pdu::BindTransmitterResponse
|
237
|
+
case pdu.command_status
|
238
|
+
when Pdu::Base::ESME_ROK
|
239
|
+
logger.debug "Bound OK."
|
240
|
+
@state = :bound
|
241
|
+
run_callback(:bound, self)
|
231
242
|
when Pdu::Base::ESME_RINVPASWD
|
232
243
|
logger.warn "Invalid password."
|
233
|
-
|
244
|
+
run_callback(:invalid_password, self)
|
245
|
+
# schedule the connection to close, which eventually will cause the unbound() delegate
|
234
246
|
# method to be invoked.
|
235
247
|
close_connection
|
236
248
|
when Pdu::Base::ESME_RINVSYSID
|
237
249
|
logger.warn "Invalid system id."
|
250
|
+
run_callback(:invalid_system_id, self)
|
238
251
|
close_connection
|
239
252
|
else
|
240
253
|
logger.warn "Unexpected BindReceiverResponse. Command status: #{pdu.command_status}"
|
254
|
+
run_callback(:unexpected_error, self)
|
241
255
|
close_connection
|
242
256
|
end
|
243
257
|
else
|
244
258
|
logger.warn "(#{self.class.name}) Received unexpected PDU: #{pdu.to_human}."
|
259
|
+
run_callback(:unexpected_pdu, self, pdu)
|
245
260
|
close_connection
|
246
261
|
end
|
247
262
|
end
|
248
263
|
|
249
|
-
private
|
264
|
+
private
|
250
265
|
def write_pdu(pdu)
|
251
266
|
logger.debug "<- #{pdu.to_human}"
|
252
267
|
hex_debug pdu.data, "<- "
|
@@ -256,12 +271,12 @@ module Smpp
|
|
256
271
|
def read_pdu(data)
|
257
272
|
pdu = nil
|
258
273
|
# we may either receive a new request or a response to a previous response.
|
259
|
-
begin
|
274
|
+
begin
|
260
275
|
pdu = Pdu::Base.create(data)
|
261
276
|
if !pdu
|
262
277
|
logger.warn "Not able to parse PDU!"
|
263
278
|
else
|
264
|
-
logger.debug "-> " + pdu.to_human
|
279
|
+
logger.debug "-> " + pdu.to_human
|
265
280
|
end
|
266
281
|
hex_debug data, "-> "
|
267
282
|
rescue Exception => ex
|
@@ -278,7 +293,7 @@ module Smpp
|
|
278
293
|
def Base.hex_debug(data, prefix = "")
|
279
294
|
logger.debug do
|
280
295
|
message = "Hex dump follows:\n"
|
281
|
-
hexdump(data).each_line do |line|
|
296
|
+
hexdump(data).each_line do |line|
|
282
297
|
message << (prefix + line.chomp + "\n")
|
283
298
|
end
|
284
299
|
message
|
@@ -303,6 +318,6 @@ module Smpp
|
|
303
318
|
}
|
304
319
|
output << ' '*(((2+width-ascii.size)*(2*group+1))/group.to_f).ceil+ascii
|
305
320
|
output[1..-1]
|
306
|
-
end
|
321
|
+
end
|
307
322
|
end
|
308
323
|
end
|
@@ -23,7 +23,10 @@ class Smpp::OptionalParameter
|
|
23
23
|
tag, length, remaining_bytes = data.unpack('H4na*')
|
24
24
|
tag = tag.hex
|
25
25
|
|
26
|
-
|
26
|
+
if tag == 0 || length.nil?
|
27
|
+
Smpp::Base.logger.error "invalid data, cannot parse optional parameters tag: #{tag} length:#{length}"
|
28
|
+
length = length.to_i
|
29
|
+
end
|
27
30
|
|
28
31
|
value = remaining_bytes.slice!(0...length)
|
29
32
|
|
data/lib/smpp/pdu/base.rb
CHANGED
@@ -115,7 +115,7 @@ module Smpp::Pdu
|
|
115
115
|
def Base.optional_parameters_to_buffer(optionals)
|
116
116
|
output = ""
|
117
117
|
optionals.each do |tag, optional_param|
|
118
|
-
length = optional_param.value.length
|
118
|
+
length = optional_param.value.to_s.length
|
119
119
|
buffer = []
|
120
120
|
buffer += [tag >> 8, tag & 0xff]
|
121
121
|
buffer += [length >> 8, length & 0xff]
|
data/lib/smpp/pdu/deliver_sm.rb
CHANGED
@@ -114,12 +114,20 @@ class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
|
|
114
114
|
# For example, Tele2 (Norway):
|
115
115
|
# "<msisdn><shortcode>?id:10ea34755d3d4f7a20900cdb3349e549 sub:001 dlvrd:001 submit date:0611011228 done date:0611011230 stat:DELIVRD err:000 Text:abc'!10ea34755d3d4f7a20900cdb3349e549"
|
116
116
|
if options[:esm_class] == 4
|
117
|
+
# id is in the mandatory part
|
117
118
|
msg_ref_match = short_message.match(/id:([^ ]*)/)
|
119
|
+
# id is not found, search it in the optional part
|
120
|
+
msg_ref_match = remaining_bytes.match(/id:([^ ]*)/) if !msg_ref_match
|
121
|
+
|
118
122
|
if msg_ref_match
|
119
123
|
options[:msg_reference] = msg_ref_match[1]
|
120
124
|
end
|
121
125
|
|
126
|
+
# stat is the mandatory part
|
122
127
|
stat_match = short_message.match(/stat:([^ ]*)/)
|
128
|
+
# stat is not found, search it in the optional part
|
129
|
+
stat_match = remaining_bytes.match(/stat:([^ ]*)/) if !stat_match
|
130
|
+
|
123
131
|
if stat_match
|
124
132
|
options[:stat] = stat_match[1]
|
125
133
|
end
|
data/lib/smpp/server.rb
CHANGED
@@ -13,7 +13,7 @@ class Smpp::Server < Smpp::Base
|
|
13
13
|
# a proc to invoke for delivery reports,
|
14
14
|
# and optionally a hash-like storage for pending delivery reports.
|
15
15
|
def initialize(config, received_messages = [], sent_messages = [])
|
16
|
-
super(config)
|
16
|
+
super(config, nil)
|
17
17
|
@state = :unbound
|
18
18
|
@received_messages = received_messages
|
19
19
|
@sent_messages = sent_messages
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# The SMPP Transmitter maintains a unidirectional connection to an SMSC.
|
2
|
+
# Provide a config hash with connection options to get started.
|
3
|
+
# See the sample_gateway.rb for examples of config values.
|
4
|
+
|
5
|
+
class Smpp::Transmitter < Smpp::Base
|
6
|
+
|
7
|
+
attr_reader :ack_ids
|
8
|
+
|
9
|
+
# Send an MT SMS message. Delegate will receive message_accepted callback when SMSC
|
10
|
+
# acknowledges, or the message_rejected callback upon error
|
11
|
+
def send_mt(message_id, source_addr, destination_addr, short_message, options={})
|
12
|
+
logger.debug "Sending MT: #{short_message}"
|
13
|
+
if @state == :bound
|
14
|
+
pdu = Pdu::SubmitSm.new(source_addr, destination_addr, short_message, options)
|
15
|
+
write_pdu(pdu)
|
16
|
+
|
17
|
+
# keep the message ID so we can associate the SMSC message ID with our message
|
18
|
+
# when the response arrives.
|
19
|
+
@ack_ids[pdu.sequence_number] = message_id
|
20
|
+
else
|
21
|
+
raise InvalidStateException, "Transmitter is unbound. Cannot send MT messages."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def send_concat_mt(message_id, source_addr, destination_addr, message, options = {})
|
26
|
+
if @state == :bound
|
27
|
+
# Split the message into parts of 134 characters.
|
28
|
+
parts = []
|
29
|
+
while message.size > 0 do
|
30
|
+
parts << message.slice!(0..133)
|
31
|
+
end
|
32
|
+
0.upto(parts.size-1) do |i|
|
33
|
+
udh = sprintf("%c", 5) # UDH is 5 bytes.
|
34
|
+
udh << sprintf("%c%c", 0, 3) # This is a concatenated message
|
35
|
+
udh << sprintf("%c", message_id) # The ID for the entire concatenated message
|
36
|
+
udh << sprintf("%c", parts.size) # How many parts this message consists of
|
37
|
+
|
38
|
+
udh << sprintf("%c", i+1) # This is part i+1
|
39
|
+
|
40
|
+
combined_options = {
|
41
|
+
:esm_class => 64, # This message contains a UDH header.
|
42
|
+
:udh => udh
|
43
|
+
}.merge(options)
|
44
|
+
|
45
|
+
pdu = Smpp::Pdu::SubmitSm.new(source_addr, destination_addr, parts[i], combined_options)
|
46
|
+
write_pdu(pdu)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
raise InvalidStateException, "Transmitter is unbound. Cannot send MT messages."
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def send_bind
|
54
|
+
raise IOError, 'Transmitter already bound.' unless unbound?
|
55
|
+
pdu = Pdu::BindTransmitter.new(
|
56
|
+
@config[:system_id],
|
57
|
+
@config[:password],
|
58
|
+
@config[:system_type],
|
59
|
+
@config[:source_ton],
|
60
|
+
@config[:source_npi],
|
61
|
+
@config[:source_address_range])
|
62
|
+
write_pdu(pdu)
|
63
|
+
end
|
64
|
+
end
|
data/lib/smpp/version.rb
ADDED
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: anjlab-ruby-smpp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
5
|
-
prerelease:
|
4
|
+
version: 0.6.4
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Ray Krueger
|
@@ -10,52 +9,75 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date:
|
12
|
+
date: 2013-12-27 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: eventmachine
|
17
|
-
requirement:
|
18
|
-
none: false
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
19
17
|
requirements:
|
20
|
-
- -
|
18
|
+
- - ">="
|
21
19
|
- !ruby/object:Gem::Version
|
22
20
|
version: 0.10.0
|
23
21
|
type: :runtime
|
24
22
|
prerelease: false
|
25
|
-
version_requirements:
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.10.0
|
26
28
|
- !ruby/object:Gem::Dependency
|
27
|
-
name:
|
28
|
-
requirement:
|
29
|
-
none: false
|
29
|
+
name: bundler
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
30
31
|
requirements:
|
31
|
-
- -
|
32
|
+
- - "~>"
|
32
33
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
34
|
+
version: '1.3'
|
34
35
|
type: :development
|
35
36
|
prerelease: false
|
36
|
-
version_requirements:
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.3'
|
37
42
|
- !ruby/object:Gem::Dependency
|
38
43
|
name: rake
|
39
|
-
requirement:
|
40
|
-
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: test-unit
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
41
59
|
requirements:
|
42
|
-
- -
|
60
|
+
- - ">="
|
43
61
|
- !ruby/object:Gem::Version
|
44
62
|
version: '0'
|
45
63
|
type: :development
|
46
64
|
prerelease: false
|
47
|
-
version_requirements:
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
48
70
|
description: Ruby implementation of the SMPP protocol, based on EventMachine. SMPP
|
49
71
|
is a protocol that allows ordinary people outside the mobile network to exchange
|
50
72
|
SMS messages directly with mobile operators.
|
51
|
-
email:
|
73
|
+
email:
|
74
|
+
- raykrueger@gmail.com
|
52
75
|
executables: []
|
53
76
|
extensions: []
|
54
|
-
extra_rdoc_files:
|
55
|
-
- CHANGELOG
|
56
|
-
- CONTRIBUTORS.txt
|
57
|
-
- README.rdoc
|
77
|
+
extra_rdoc_files: []
|
58
78
|
files:
|
79
|
+
- ".gitignore"
|
80
|
+
- ".travis.yml"
|
59
81
|
- CHANGELOG
|
60
82
|
- CONTRIBUTORS.txt
|
61
83
|
- Gemfile
|
@@ -97,6 +119,8 @@ files:
|
|
97
119
|
- lib/smpp/receiver.rb
|
98
120
|
- lib/smpp/server.rb
|
99
121
|
- lib/smpp/transceiver.rb
|
122
|
+
- lib/smpp/transmitter.rb
|
123
|
+
- lib/smpp/version.rb
|
100
124
|
- lib/sms.rb
|
101
125
|
- test/delegate.rb
|
102
126
|
- test/encoding_test.rb
|
@@ -109,27 +133,37 @@ files:
|
|
109
133
|
- test/submit_sm_test.rb
|
110
134
|
- test/transceiver_test.rb
|
111
135
|
homepage: http://github.com/raykrueger/ruby-smpp
|
112
|
-
licenses:
|
136
|
+
licenses:
|
137
|
+
- MIT
|
138
|
+
metadata: {}
|
113
139
|
post_install_message:
|
114
140
|
rdoc_options: []
|
115
141
|
require_paths:
|
116
142
|
- lib
|
117
143
|
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
-
none: false
|
119
144
|
requirements:
|
120
|
-
- -
|
145
|
+
- - ">="
|
121
146
|
- !ruby/object:Gem::Version
|
122
147
|
version: '0'
|
123
148
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
-
none: false
|
125
149
|
requirements:
|
126
|
-
- -
|
150
|
+
- - ">="
|
127
151
|
- !ruby/object:Gem::Version
|
128
152
|
version: '0'
|
129
153
|
requirements: []
|
130
|
-
rubyforge_project:
|
131
|
-
rubygems_version:
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 2.2.0
|
132
156
|
signing_key:
|
133
|
-
specification_version:
|
157
|
+
specification_version: 4
|
134
158
|
summary: Ruby implementation of the SMPP protocol, based on EventMachine.
|
135
|
-
test_files:
|
159
|
+
test_files:
|
160
|
+
- test/delegate.rb
|
161
|
+
- test/encoding_test.rb
|
162
|
+
- test/optional_parameter_test.rb
|
163
|
+
- test/pdu_parsing_test.rb
|
164
|
+
- test/receiver_test.rb
|
165
|
+
- test/responsive_delegate.rb
|
166
|
+
- test/server.rb
|
167
|
+
- test/smpp_test.rb
|
168
|
+
- test/submit_sm_test.rb
|
169
|
+
- test/transceiver_test.rb
|