ruby-smpp 0.1.1 → 0.1.2
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/CONTRIBUTORS.txt +9 -0
- data/History.txt +5 -0
- data/Manifest.txt +11 -2
- data/NEWS.txt +44 -0
- data/README.txt +2 -2
- data/examples/PDU1.example +26 -0
- data/examples/PDU2.example +26 -0
- data/examples/sample_gateway.rb +113 -99
- data/examples/sample_smsc.rb +103 -0
- data/lib/smpp/base.rb +39 -16
- data/lib/smpp/pdu/base.rb +23 -24
- data/lib/smpp/pdu/bind_base.rb +25 -0
- data/lib/smpp/pdu/bind_resp_base.rb +17 -0
- data/lib/smpp/pdu/bind_transceiver.rb +3 -5
- data/lib/smpp/pdu/bind_transceiver_response.rb +3 -6
- data/lib/smpp/pdu/deliver_sm.rb +72 -29
- data/lib/smpp/pdu/deliver_sm_response.rb +7 -0
- data/lib/smpp/pdu/enquire_link.rb +6 -0
- data/lib/smpp/pdu/enquire_link_response.rb +7 -1
- data/lib/smpp/pdu/generic_nack.rb +14 -2
- data/lib/smpp/pdu/submit_multi.rb +13 -12
- data/lib/smpp/pdu/submit_multi_response.rb +43 -4
- data/lib/smpp/pdu/submit_sm.rb +61 -22
- data/lib/smpp/pdu/submit_sm_response.rb +11 -2
- data/lib/smpp/pdu/unbind.rb +6 -0
- data/lib/smpp/pdu/unbind_response.rb +7 -0
- data/lib/smpp/server.rb +224 -0
- data/lib/smpp/transceiver.rb +87 -30
- data/lib/smpp/version.rb +1 -1
- data/lib/smpp.rb +3 -1
- data/ruby-smpp.gemspec +36 -0
- data/test/smpp_test.rb +218 -12
- metadata +16 -5
data/lib/smpp/server.rb
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
# the opposite of a client-based receiver, the server transmitter waill send
|
2
|
+
# out MOs to the client when set up
|
3
|
+
class Smpp::Server < Smpp::Base
|
4
|
+
|
5
|
+
attr_accessor :bind_status
|
6
|
+
|
7
|
+
# Expects a config hash,
|
8
|
+
# a proc to invoke for incoming (MO) messages,
|
9
|
+
# a proc to invoke for delivery reports,
|
10
|
+
# and optionally a hash-like storage for pending delivery reports.
|
11
|
+
def initialize(config, received_messages = [], sent_messages = [])
|
12
|
+
super(config)
|
13
|
+
@state = :unbound
|
14
|
+
@received_messages = received_messages
|
15
|
+
@sent_messages = sent_messages
|
16
|
+
|
17
|
+
# Array of un-acked MT message IDs indexed by sequence number.
|
18
|
+
# As soon as we receive SubmitSmResponse we will use this to find the
|
19
|
+
# associated message ID, and then create a pending delivery report.
|
20
|
+
@ack_ids = Array.new(512)
|
21
|
+
|
22
|
+
ed = @config[:enquire_link_delay_secs] || 5
|
23
|
+
comm_inactivity_timeout = [ed - 5, 3].max
|
24
|
+
rescue Exception => ex
|
25
|
+
logger.error "Exception setting up server: #{ex}"
|
26
|
+
raise
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
#######################################################################
|
31
|
+
# Session management functions
|
32
|
+
#######################################################################
|
33
|
+
# Session helpers
|
34
|
+
|
35
|
+
# convenience methods
|
36
|
+
# is this session currently bound?
|
37
|
+
def bound?
|
38
|
+
@state == :bound
|
39
|
+
end
|
40
|
+
# is this session currently unbound?
|
41
|
+
def unbound?
|
42
|
+
@state == :unbound
|
43
|
+
end
|
44
|
+
# set of valid bind statuses
|
45
|
+
BIND_STATUSES = {:transmitter => :bound_tx,
|
46
|
+
:receiver => :bound_rx, :transceiver => :bound_trx}
|
47
|
+
# set the bind status based on the common-name for the bind class
|
48
|
+
def set_bind_status(bind_classname)
|
49
|
+
@bind_status = BIND_STATUSES[bind_classname]
|
50
|
+
end
|
51
|
+
# and kill the bind status when done
|
52
|
+
def unset_bind_status
|
53
|
+
@bind_status = nil
|
54
|
+
end
|
55
|
+
# what is the bind_status?
|
56
|
+
def bind_status
|
57
|
+
@bind_status
|
58
|
+
end
|
59
|
+
# convenience function - are we able to transmit in this bind-Status?
|
60
|
+
def transmitting?
|
61
|
+
# not transmitting if not bound
|
62
|
+
return false if unbound? || bind_status.nil?
|
63
|
+
# receivers can't transmit
|
64
|
+
bind_status != :bound_rx
|
65
|
+
end
|
66
|
+
# convenience function - are we able to receive in this bind-Status?
|
67
|
+
def receiving?
|
68
|
+
# not receiving if not bound
|
69
|
+
return false if unbound? || bind_status.nil?
|
70
|
+
# transmitters can't receive
|
71
|
+
bind_status != :bound_tx
|
72
|
+
end
|
73
|
+
|
74
|
+
def am_server?
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
# REVISIT - not sure if these are using the correct data. Currently just
|
79
|
+
# pulls the data straight out of the given pdu and sends it right back.
|
80
|
+
#
|
81
|
+
def fetch_bind_response_class(bind_classname)
|
82
|
+
# check we have a valid classname - probably overkill as only our code
|
83
|
+
# will send the classnames through
|
84
|
+
raise IOError, "bind class name missing" if bind_classname.nil?
|
85
|
+
raise IOError, "bind class name: #{bind_classname} unknown" unless BIND_STATUSES.has_key?(bind_classname)
|
86
|
+
|
87
|
+
case bind_classname
|
88
|
+
when :transceiver
|
89
|
+
return Smpp::Pdu::BindTransceiverResponse
|
90
|
+
when :transmitter
|
91
|
+
return Smpp::Pdu::BindTransmitterResponse
|
92
|
+
when :receiver
|
93
|
+
return Smpp::Pdu::BindReceiverResponse
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# actually perform the action of binding the session to the given session
|
98
|
+
# type
|
99
|
+
def bind_session(bind_pdu, bind_classname)
|
100
|
+
# TODO: probably should not "raise" here - what's better?
|
101
|
+
raise IOError, "Session already bound." if bound?
|
102
|
+
response_class = fetch_bind_response_class(bind_classname)
|
103
|
+
|
104
|
+
# TODO: look inside the pdu for the password and check it
|
105
|
+
|
106
|
+
send_bind_response(bind_pdu, response_class)
|
107
|
+
|
108
|
+
@state = :bound
|
109
|
+
set_bind_status(bind_classname)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Send BindReceiverResponse PDU - used in response to a "bind_receiver"
|
113
|
+
# pdu.
|
114
|
+
def send_bind_response(bind_pdu, bind_class)
|
115
|
+
resp_pdu = bind_class.new(
|
116
|
+
bind_pdu.sequence_number,
|
117
|
+
# currently assume that it binds ok
|
118
|
+
Pdu::Base::ESME_ROK,
|
119
|
+
# TODO: not sure where we get the system ID
|
120
|
+
# is this the session id?
|
121
|
+
bind_pdu.system_id)
|
122
|
+
write_pdu(resp_pdu)
|
123
|
+
end
|
124
|
+
|
125
|
+
#######################################################################
|
126
|
+
# Message submission (transmitter) functions (used by transmitter and
|
127
|
+
# transceiver-bound system)
|
128
|
+
# Note - we only support submit_sm message type, not submit_multi or
|
129
|
+
# data_sm message types
|
130
|
+
#######################################################################
|
131
|
+
# Receive an incoming message to send to the network and respond
|
132
|
+
# REVISIT = just a stub
|
133
|
+
def receive_sm(pdu)
|
134
|
+
# TODO: probably should not "raise" here - what's better?
|
135
|
+
raise IOError, "Connection not bound." if unbound?
|
136
|
+
# Doesn't matter if it's a TX/RX/TRX, have to send a SubmitSmResponse:
|
137
|
+
# raise IOError, "Connection not set to receive" unless receiving?
|
138
|
+
|
139
|
+
# Must respond to SubmitSm requests with the same sequence number
|
140
|
+
m_seq = pdu.sequence_number
|
141
|
+
# add the id to the list of ids of which we're awaiting acknowledgement
|
142
|
+
@received_messages << m_seq
|
143
|
+
|
144
|
+
# In theory this is where the MC would actually do something useful with
|
145
|
+
# the PDU - eg send it on to the network. We'd check if it worked and
|
146
|
+
# send a failure PDU if it failed.
|
147
|
+
#
|
148
|
+
# Given this is a dummy MC, that's not necessary, so all our responses
|
149
|
+
# will be OK.
|
150
|
+
|
151
|
+
# so respond with a successful response
|
152
|
+
pdu = Pdu::SubmitSmResponse.new(m_seq, Pdu::Base::ESME_ROK, message_id = '' )
|
153
|
+
write_pdu pdu
|
154
|
+
@received_messages.delete m_seq
|
155
|
+
|
156
|
+
logger.info "Received submit sm message: #{m_seq}"
|
157
|
+
end
|
158
|
+
|
159
|
+
#######################################################################
|
160
|
+
# Message delivery (receiver) functions (used by receiver and
|
161
|
+
# transceiver-bound system)
|
162
|
+
#######################################################################
|
163
|
+
# When we get an incoming SMS to send on to the client, we need to
|
164
|
+
# initiate one of these PDUs.
|
165
|
+
# Note - data doesn't have to be valid, as we're not really doing much
|
166
|
+
# useful with it. Only the params that will be pulled out by the test
|
167
|
+
# system need to be valid.
|
168
|
+
def deliver_sm(from, to, message, config = {})
|
169
|
+
# TODO: probably should not "raise" here - what's better?
|
170
|
+
raise IOError, "Connection not bound." if unbound?
|
171
|
+
raise IOError, "Connection not set to receive" unless receiving?
|
172
|
+
|
173
|
+
# submit the given message
|
174
|
+
new_pdu = Pdu::DeliverSm.new(from, to, message, config)
|
175
|
+
write_pdu(new_pdu)
|
176
|
+
# add the id to the list of ids of which we're awaiting acknowledgement
|
177
|
+
@sent_messages << m_seq
|
178
|
+
|
179
|
+
logger.info "Delivered SM message id: #{m_seq}"
|
180
|
+
|
181
|
+
new_pdu
|
182
|
+
end
|
183
|
+
|
184
|
+
# Acknowledge delivery of an outgoing MO message
|
185
|
+
# REVISIT = just a stub
|
186
|
+
def accept_deliver_sm_response(pdu)
|
187
|
+
m_seq = pdu.sequence_number
|
188
|
+
# add the id to the list of ids we're awaiting acknowledgement of
|
189
|
+
# REVISIT - what id do we need to store?
|
190
|
+
unless @sent_messages && @sent_messages.include?(m_seq)
|
191
|
+
logger.error("Received deliver response for message for which we have no saved id: #{m_seq}")
|
192
|
+
else
|
193
|
+
@sent_messages.delete(m_seq)
|
194
|
+
logger.info "Acknowledged receipt of SM delivery message id: #{m_seq}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
# a PDU is received
|
200
|
+
# these pdus are all responses to a message sent by the client and require
|
201
|
+
# their own special response
|
202
|
+
def process_pdu(pdu)
|
203
|
+
case pdu
|
204
|
+
# client has asked to set up a connection
|
205
|
+
when Pdu::BindTransmitter
|
206
|
+
bind_session(pdu, :transmitter)
|
207
|
+
when Pdu::BindReceiver
|
208
|
+
bind_session(pdu, :receiver)
|
209
|
+
when Pdu::BindTransceiver
|
210
|
+
bind_session(pdu, :transceiver)
|
211
|
+
# client has acknowledged receipt of a message we sent to them
|
212
|
+
when Pdu::DeliverSmResponse
|
213
|
+
accept_deliver_sm_response(pdu) # acknowledge its sending
|
214
|
+
|
215
|
+
# client has asked for a message to be sent
|
216
|
+
when Pdu::SubmitSm
|
217
|
+
receive_sm(pdu)
|
218
|
+
else
|
219
|
+
# for generic functions or default fallback
|
220
|
+
super(pdu)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
data/lib/smpp/transceiver.rb
CHANGED
@@ -1,15 +1,22 @@
|
|
1
|
+
|
2
|
+
# The SMPP Transceiver maintains a bidirectional connection to an SMSC.
|
3
|
+
# Provide a config hash with connection options to get started.
|
4
|
+
# See the sample_gateway.rb for examples of config values.
|
5
|
+
# The transceiver accepts a delegate object that may implement
|
6
|
+
# the following (all optional) methods:
|
7
|
+
#
|
8
|
+
# mo_received(transceiver, source_addr, destination_addr, short_message)
|
9
|
+
# delivery_report_received(transceiver, msg_reference, stat, pdu)
|
10
|
+
# message_accepted(transceiver, mt_message_id, smsc_message_id)
|
11
|
+
# bound(transceiver)
|
12
|
+
# unbound(transceiver)
|
13
|
+
|
1
14
|
class Smpp::Transceiver < Smpp::Base
|
2
15
|
|
3
|
-
|
4
|
-
# a proc to invoke for incoming (MO) messages,
|
5
|
-
# a proc to invoke for delivery reports,
|
6
|
-
# and optionally a hash-like storage for pending delivery reports.
|
7
|
-
def initialize(config, mo_proc, dr_proc, pdr_storage={})
|
16
|
+
def initialize(config, delegate, pdr_storage={})
|
8
17
|
super(config)
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@dr_proc = dr_proc
|
12
|
-
@pdr_storage = pdr_storage
|
18
|
+
@delegate = delegate
|
19
|
+
@pdr_storage = pdr_storage
|
13
20
|
|
14
21
|
# Array of un-acked MT message IDs indexed by sequence number.
|
15
22
|
# As soon as we receive SubmitSmResponse we will use this to find the
|
@@ -17,13 +24,14 @@ class Smpp::Transceiver < Smpp::Base
|
|
17
24
|
@ack_ids = Array.new(512)
|
18
25
|
|
19
26
|
ed = @config[:enquire_link_delay_secs] || 5
|
20
|
-
comm_inactivity_timeout =
|
27
|
+
comm_inactivity_timeout = 2 * ed
|
21
28
|
rescue Exception => ex
|
22
|
-
logger.error "Exception setting up transceiver: #{ex}"
|
29
|
+
logger.error "Exception setting up transceiver: #{ex} at #{ex.backtrace.join("\n")}"
|
23
30
|
raise
|
24
31
|
end
|
25
32
|
|
26
|
-
# Send an MT SMS message
|
33
|
+
# Send an MT SMS message. Delegate will receive message_accepted callback when SMSC
|
34
|
+
# acknowledges.
|
27
35
|
def send_mt(message_id, source_addr, destination_addr, short_message, options={})
|
28
36
|
logger.debug "Sending MT: #{short_message}"
|
29
37
|
if @state == :bound
|
@@ -37,6 +45,41 @@ class Smpp::Transceiver < Smpp::Base
|
|
37
45
|
raise InvalidStateException, "Transceiver is unbound. Cannot send MT messages."
|
38
46
|
end
|
39
47
|
end
|
48
|
+
|
49
|
+
# Send a concatenated message with a body of > 160 characters as multiple messages.
|
50
|
+
def send_concat_mt(message_id, source_addr, destination_addr, message, options = {})
|
51
|
+
logger.debug "Sending concatenated MT: #{message}"
|
52
|
+
if @state == :bound
|
53
|
+
# Split the message into parts of 153 characters. (160 - 7 characters for UDH)
|
54
|
+
parts = []
|
55
|
+
while message.size > 0 do
|
56
|
+
parts << message.slice!(0..152)
|
57
|
+
end
|
58
|
+
|
59
|
+
0.upto(parts.size-1) do |i|
|
60
|
+
udh = sprintf("%c", 5) # UDH is 5 bytes.
|
61
|
+
udh << sprintf("%c%c", 0, 3) # This is a concatenated message
|
62
|
+
udh << sprintf("%c", message_id) # The ID for the entire concatenated message
|
63
|
+
udh << sprintf("%c", parts.size) # How many parts this message consists of
|
64
|
+
udh << sprintf("%c", i+1) # This is part i+1
|
65
|
+
|
66
|
+
options = {
|
67
|
+
:esm_class => 64, # This message contains a UDH header.
|
68
|
+
:udh => udh
|
69
|
+
}
|
70
|
+
|
71
|
+
pdu = Pdu::SubmitSm.new(source_addr, destination_addr, parts[i], options)
|
72
|
+
write_pdu pdu
|
73
|
+
|
74
|
+
# This is definately a bit hacky - multiple PDUs are being associated with a single
|
75
|
+
# message_id.
|
76
|
+
@ack_ids[pdu.sequence_number] = message_id
|
77
|
+
end
|
78
|
+
else
|
79
|
+
raise InvalidStateException, "Transceiver is unbound. Connot send MT messages."
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
40
83
|
# Send MT SMS message for multiple dest_address
|
41
84
|
# Author: Abhishek Parolkar (abhishek[at]parolkar.com)
|
42
85
|
# USAGE: $tx.send_multi_mt(123, "9100000000", ["9199000000000","91990000000001","9199000000002"], "Message here")
|
@@ -54,34 +97,42 @@ class Smpp::Transceiver < Smpp::Base
|
|
54
97
|
end
|
55
98
|
end
|
56
99
|
|
57
|
-
|
58
|
-
# a PDU is received
|
100
|
+
# a PDU is received. Parse it and invoke delegate methods.
|
59
101
|
def process_pdu(pdu)
|
60
102
|
case pdu
|
61
103
|
when Pdu::DeliverSm
|
62
104
|
write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number))
|
63
105
|
logger.debug "ESM CLASS #{pdu.esm_class}"
|
64
106
|
if pdu.esm_class != 4
|
65
|
-
# MO message
|
66
|
-
@
|
107
|
+
# MO message
|
108
|
+
if @delegate.respond_to?(:mo_received)
|
109
|
+
@delegate.mo_received(self, pdu.source_addr, pdu.destination_addr, pdu.short_message)
|
110
|
+
end
|
67
111
|
else
|
68
|
-
#
|
69
|
-
@
|
112
|
+
# Delivery report
|
113
|
+
if @delegate.respond_to?(:delivery_report_received)
|
114
|
+
@delegate.delivery_report_received(self, pdu.msg_reference.to_s, pdu.stat, pdu)
|
115
|
+
end
|
70
116
|
end
|
71
117
|
when Pdu::BindTransceiverResponse
|
72
118
|
case pdu.command_status
|
73
119
|
when Pdu::Base::ESME_ROK
|
74
120
|
logger.debug "Bound OK."
|
75
121
|
@state = :bound
|
122
|
+
if @delegate.respond_to?(:bound)
|
123
|
+
@delegate.bound(self)
|
124
|
+
end
|
76
125
|
when Pdu::Base::ESME_RINVPASWD
|
77
126
|
logger.warn "Invalid password."
|
78
|
-
|
127
|
+
# scheduele the connection to close, which eventually will cause the unbound() delegate
|
128
|
+
# method to be invoked.
|
129
|
+
close_connection
|
79
130
|
when Pdu::Base::ESME_RINVSYSID
|
80
131
|
logger.warn "Invalid system id."
|
81
|
-
|
132
|
+
close_connection
|
82
133
|
else
|
83
134
|
logger.warn "Unexpected BindTransceiverResponse. Command status: #{pdu.command_status}"
|
84
|
-
|
135
|
+
close_connection
|
85
136
|
end
|
86
137
|
when Pdu::SubmitSmResponse
|
87
138
|
mt_message_id = @ack_ids[pdu.sequence_number]
|
@@ -92,9 +143,12 @@ class Smpp::Transceiver < Smpp::Base
|
|
92
143
|
logger.error "Error status in SubmitSmResponse: #{pdu.command_status}"
|
93
144
|
else
|
94
145
|
logger.info "Got OK SubmitSmResponse (#{pdu.message_id} -> #{mt_message_id})"
|
146
|
+
if @delegate.respond_to?(:message_accepted)
|
147
|
+
@delegate.message_accepted(self, mt_message_id, pdu.message_id)
|
148
|
+
end
|
95
149
|
end
|
96
|
-
# Now we got the SMSC message id; create pending delivery report
|
97
|
-
@pdr_storage[pdu.message_id] = mt_message_id
|
150
|
+
# Now we got the SMSC message id; create pending delivery report.
|
151
|
+
@pdr_storage[pdu.message_id] = mt_message_id
|
98
152
|
when Pdu::SubmitMultiResponse
|
99
153
|
mt_message_id = @ack_ids[pdu.sequence_number]
|
100
154
|
if !mt_message_id
|
@@ -104,6 +158,9 @@ class Smpp::Transceiver < Smpp::Base
|
|
104
158
|
logger.error "Error status in SubmitMultiResponse: #{pdu.command_status}"
|
105
159
|
else
|
106
160
|
logger.info "Got OK SubmitMultiResponse (#{pdu.message_id} -> #{mt_message_id})"
|
161
|
+
if @delegate.respond_to?(:message_accepted)
|
162
|
+
@delegate.message_accepted(self, mt_message_id, pdu.message_id)
|
163
|
+
end
|
107
164
|
end
|
108
165
|
else
|
109
166
|
super
|
@@ -112,14 +169,14 @@ class Smpp::Transceiver < Smpp::Base
|
|
112
169
|
|
113
170
|
# Send BindTransceiverResponse PDU.
|
114
171
|
def send_bind
|
115
|
-
raise IOError, 'Receiver already bound.' unless
|
172
|
+
raise IOError, 'Receiver already bound.' unless unbound?
|
116
173
|
pdu = Pdu::BindTransceiver.new(
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
174
|
+
@config[:system_id],
|
175
|
+
@config[:password],
|
176
|
+
@config[:system_type],
|
177
|
+
@config[:source_ton],
|
178
|
+
@config[:source_npi],
|
179
|
+
@config[:source_address_range])
|
123
180
|
write_pdu(pdu)
|
124
181
|
end
|
125
182
|
end
|
data/lib/smpp/version.rb
CHANGED
data/lib/smpp.rb
CHANGED
@@ -11,6 +11,8 @@ $:.unshift(File.dirname(__FILE__))
|
|
11
11
|
require 'smpp/base.rb'
|
12
12
|
require 'smpp/transceiver.rb'
|
13
13
|
require 'smpp/pdu/base.rb'
|
14
|
+
require 'smpp/pdu/bind_base.rb'
|
15
|
+
require 'smpp/pdu/bind_resp_base.rb'
|
14
16
|
|
15
17
|
# Load all PDUs
|
16
18
|
Dir.glob(File.join(File.dirname(__FILE__), 'smpp', 'pdu', '*.rb')) do |f|
|
@@ -18,4 +20,4 @@ Dir.glob(File.join(File.dirname(__FILE__), 'smpp', 'pdu', '*.rb')) do |f|
|
|
18
20
|
end
|
19
21
|
|
20
22
|
# Default logger. Invoke this call in your client to use another logger.
|
21
|
-
Smpp::Base.logger = Logger.new(STDOUT)
|
23
|
+
Smpp::Base.logger = Logger.new(STDOUT)
|
data/ruby-smpp.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{ruby-smpp}
|
3
|
+
s.version = "0.1.2"
|
4
|
+
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
|
+
s.authors = ["August Z. Flatby"]
|
7
|
+
s.date = %q{2009-01-04}
|
8
|
+
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.}
|
9
|
+
s.email = ["august@apparat.no"]
|
10
|
+
s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "README.txt", "CONTRIBUTORS.txt"]
|
11
|
+
s.files = ["History.txt", "License.txt", "Manifest.txt", "README.txt", "CONTRIBUTORS.txt", "Rakefile", "examples/PDU1.example", "examples/PDU2.example", "examples/sample_gateway.rb", "examples/sample_smsc.rb", "config/hoe.rb", "config/requirements.rb", "lib/smpp.rb", "lib/smpp/base.rb", "lib/smpp/pdu/base.rb", "lib/smpp/pdu/bind_base.rb", "lib/smpp/pdu/bind_receiver.rb", "lib/smpp/pdu/bind_receiver_response.rb", "lib/smpp/pdu/bind_resp_base.rb", "lib/smpp/pdu/bind_transceiver.rb", "lib/smpp/pdu/bind_transceiver_response.rb", "lib/smpp/pdu/bind_transmitter.rb", "lib/smpp/pdu/bind_transmitter_response.rb", "lib/smpp/pdu/deliver_sm.rb", "lib/smpp/pdu/deliver_sm_response.rb", "lib/smpp/pdu/enquire_link.rb", "lib/smpp/pdu/enquire_link_response.rb", "lib/smpp/pdu/generic_nack.rb", "lib/smpp/pdu/submit_multi.rb", "lib/smpp/pdu/submit_multi_response.rb", "lib/smpp/pdu/submit_sm.rb", "lib/smpp/pdu/submit_sm_response.rb", "lib/smpp/pdu/unbind.rb", "lib/smpp/pdu/unbind_response.rb", "lib/smpp/server.rb", "lib/smpp/transceiver.rb", "lib/smpp/version.rb", "lib/sms.rb", "script/console", "script/destroy", "script/generate", "script/txt2html", "setup.rb", "tasks/deployment.rake", "tasks/environment.rake", "test/smpp_test.rb", "test/test_helper.rb"]
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.homepage = %q{http://ruby-smpp.rubyforge.org}
|
14
|
+
s.rdoc_options = ["--main", "README.txt"]
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
s.rubyforge_project = %q{ruby-smpp}
|
17
|
+
s.rubygems_version = %q{1.3.0}
|
18
|
+
s.summary = %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.}
|
19
|
+
s.test_files = ["test/test_helper.rb"]
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
+
s.specification_version = 2
|
24
|
+
|
25
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
|
+
s.add_runtime_dependency(%q<eventmachine>, [">= 0.10.0"])
|
27
|
+
s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
|
28
|
+
else
|
29
|
+
s.add_dependency(%q<eventmachine>, [">= 0.10.0"])
|
30
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
31
|
+
end
|
32
|
+
else
|
33
|
+
s.add_dependency(%q<eventmachine>, [">= 0.10.0"])
|
34
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
35
|
+
end
|
36
|
+
end
|