Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/smpp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

$:.unshift(File.dirname(__FILE__))
require 'smpp/base.rb'
require 'smpp/sender_base.rb'
require 'smpp/transceiver.rb'
require 'smpp/transmitter.rb'
require 'smpp/receiver.rb'
Expand Down
8 changes: 8 additions & 0 deletions lib/smpp/pdu/submit_base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# encoding: UTF-8

# Base class for the SubmitSm and the SubmitMulti classes
# Author: Jorge Piera Llodra(jorge[at]pierallodra.es)
class Smpp::Pdu::SubmitBase < Smpp::Pdu::Base


end
35 changes: 16 additions & 19 deletions lib/smpp/pdu/submit_multi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,29 @@ class Smpp::Pdu::SubmitMulti < Smpp::Pdu::Base

# Note: short_message (the SMS body) must be in iso-8859-1 format
def initialize(source_addr, destination_addr_array, short_message, options={})
options.merge!(
:esm_class => 0, # default smsc mode
:dcs => 3 # iso-8859-1
) { |key, old_val, new_val| old_val }


@msg_body = short_message

udh = options[:udh]
service_type = ''
source_addr_ton = 0 # network specific
source_addr_npi = 1 # unknown
service_type = options[:service_type]? options[:service_type] :''
source_addr_ton = options[:source_addr_ton]?options[:source_addr_ton]:0 # network specific
source_addr_npi = options[:source_addr_npi]?options[:source_addr_npi]:1 # unknown
number_of_dests = destination_addr_array.length # Max value can be 254
dest_addr_ton = 1 # international
dest_addr_npi = 1 # unknown
dest_addr_ton = options[:dest_addr_ton]?options[:dest_addr_ton]:1 # international
dest_addr_npi = options[:dest_addr_npi]?options[:dest_addr_npi]:1 # unknown
dest_addresses = build_destination_addresses(destination_addr_array,dest_addr_ton,dest_addr_npi,IS_SMEADDR)
esm_class = options[:esm_class]
protocol_id = 0
priority_flag = 0
schedule_delivery_time = ''
validity_period = ''
registered_delivery = 1 # we want delivery notifications
replace_if_present_flag = 0
data_coding = options[:dcs]
sm_default_msg_id = 0
esm_class = options[:esm_class]?options[:esm_class]:0 # default smsc mode
protocol_id = options[:protocol_id]?options[:protocol_id]:0
priority_flag = options[:priority_flag]?options[:priority_flag]:0
schedule_delivery_time = options[:schedule_delivery_time]?options[:schedule_delivery_time]:''
validity_period = options[:validity_period]?options[:validity_period]:''
registered_delivery = options[:registered_delivery]?options[:registered_delivery]:1
replace_if_present_flag = options[:replace_if_present_flag]?options[:replace_if_present_flag]:0
data_coding = options[:data_coding]?options[:data_coding]:3 # iso-8859-1
sm_default_msg_id = options[:sm_default_msg_id]?options[:sm_default_msg_id]:0
payload = udh ? udh + short_message : short_message # this used to be (short_message + "\0")
sm_length = payload.length


# craft the string/byte buffer
pdu_body = sprintf("%s\0%c%c%s\0%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, number_of_dests,dest_addresses, esm_class, protocol_id, priority_flag, schedule_delivery_time, validity_period,
Expand Down
100 changes: 100 additions & 0 deletions lib/smpp/sender_base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# encoding: UTF-8

# Base class for all the classes that send smss

class Smpp::SenderBase < Smpp::Base

# Send an MT SMS message. Delegate will receive message_accepted callback when SMSC
# acknowledges, or the message_rejected callback upon error
def send_mt(message_id, source_addr, destination_addr, short_message, options={})
logger.debug "Sending MT: #{short_message}"
if @state == :bound
pdu = Pdu::SubmitSm.new(source_addr, destination_addr, short_message, options)
write_pdu pdu

# keep the message ID so we can associate the SMSC message ID with our message
# when the response arrives.
@ack_ids[pdu.sequence_number] = message_id
else
raise InvalidStateException, "Transceiver is unbound. Cannot send MT messages."
end
end

# Send MT SMS message for multiple dest_address
# Author: Abhishek Parolkar (abhishek[at]parolkar.com)
# USAGE: $tx.send_multi_mt(123, "9100000000", ["9199000000000","91990000000001","9199000000002"], "Message here")
def send_multi_mt(message_id, source_addr, destination_addr_arr, short_message, options={})
logger.debug "Sending Multiple MT: #{short_message}"
if @state == :bound
pdu = Pdu::SubmitMulti.new(source_addr, destination_addr_arr, short_message, options)
write_pdu pdu

# keep the message ID so we can associate the SMSC message ID with our message
# when the response arrives.
@ack_ids[pdu.sequence_number] = message_id
else
raise InvalidStateException, "Transceiver is unbound. Cannot send MT messages."
end
end

# Send BindTransceiverResponse PDU.
def send_bind
raise IOError, 'Receiver already bound.' unless unbound?
pdu = Pdu::BindTransceiver.new(
@config[:system_id],
@config[:password],
@config[:system_type],
@config[:source_ton],
@config[:source_npi],
@config[:source_address_range])
write_pdu(pdu)
end

# Send a concatenated message with a body of > 160 characters as multiple messages.
def send_concat_mt(message_id, source_addr, destination_addr, message, options = {})
logger.debug "Sending concatenated MT: #{message}"
if @state == :bound
# Split the message into parts of 153 characters. (160 - 7 characters for UDH)
parts = []
while message.size > 0 do
parts << message.slice!(0..Smpp::Transceiver.get_message_part_size(options))
end

0.upto(parts.size-1) do |i|
udh = sprintf("%c", 5) # UDH is 5 bytes.
udh << sprintf("%c%c", 0, 3) # This is a concatenated message

#TODO Figure out why this needs to be an int here, it's a string elsewhere
udh << sprintf("%c", message_id) # The ID for the entire concatenated message

udh << sprintf("%c", parts.size) # How many parts this message consists of
udh << sprintf("%c", i+1) # This is part i+1

options[:esm_class] = 64 # This message contains a UDH header.
options[:udh] = udh

pdu = Pdu::SubmitSm.new(source_addr, destination_addr, parts[i], options)
write_pdu pdu

# This is definately a bit hacky - multiple PDUs are being associated with a single
# message_id.
@ack_ids[pdu.sequence_number] = message_id
end
else
raise InvalidStateException, "Transceiver is unbound. Connot send MT messages."
end
end

# Use data_coding to find out what message part size we can use
# http://en.wikipedia.org/wiki/SMS#Message_size
def self.get_message_part_size options
return 153 if options[:data_coding].nil?
return 153 if options[:data_coding] == 0
return 134 if options[:data_coding] == 3
return 134 if options[:data_coding] == 5
return 134 if options[:data_coding] == 6
return 134 if options[:data_coding] == 7
return 67 if options[:data_coding] == 8
return 153
end
end
94 changes: 1 addition & 93 deletions lib/smpp/transceiver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,99 +13,7 @@
# bound(transceiver)
# unbound(transceiver)

class Smpp::Transceiver < Smpp::Base
class Smpp::Transceiver < Smpp::SenderBase

# Send an MT SMS message. Delegate will receive message_accepted callback when SMSC
# acknowledges, or the message_rejected callback upon error
def send_mt(message_id, source_addr, destination_addr, short_message, options={})
logger.debug "Sending MT: #{short_message}"
if @state == :bound
pdu = Pdu::SubmitSm.new(source_addr, destination_addr, short_message, options)
write_pdu pdu

# keep the message ID so we can associate the SMSC message ID with our message
# when the response arrives.
@ack_ids[pdu.sequence_number] = message_id
else
raise InvalidStateException, "Transceiver is unbound. Cannot send MT messages."
end
end

# Send a concatenated message with a body of > 160 characters as multiple messages.
def send_concat_mt(message_id, source_addr, destination_addr, message, options = {})
logger.debug "Sending concatenated MT: #{message}"
if @state == :bound
# Split the message into parts of 153 characters. (160 - 7 characters for UDH)
parts = []
while message.size > 0 do
parts << message.slice!(0..Smpp::Transceiver.get_message_part_size(options))
end

0.upto(parts.size-1) do |i|
udh = sprintf("%c", 5) # UDH is 5 bytes.
udh << sprintf("%c%c", 0, 3) # This is a concatenated message

#TODO Figure out why this needs to be an int here, it's a string elsewhere
udh << sprintf("%c", message_id) # The ID for the entire concatenated message

udh << sprintf("%c", parts.size) # How many parts this message consists of
udh << sprintf("%c", i+1) # This is part i+1

options[:esm_class] = 64 # This message contains a UDH header.
options[:udh] = udh

pdu = Pdu::SubmitSm.new(source_addr, destination_addr, parts[i], options)
write_pdu pdu

# This is definately a bit hacky - multiple PDUs are being associated with a single
# message_id.
@ack_ids[pdu.sequence_number] = message_id
end
else
raise InvalidStateException, "Transceiver is unbound. Connot send MT messages."
end
end

# Send MT SMS message for multiple dest_address
# Author: Abhishek Parolkar (abhishek[at]parolkar.com)
# USAGE: $tx.send_multi_mt(123, "9100000000", ["9199000000000","91990000000001","9199000000002"], "Message here")
def send_multi_mt(message_id, source_addr, destination_addr_arr, short_message, options={})
logger.debug "Sending Multiple MT: #{short_message}"
if @state == :bound
pdu = Pdu::SubmitMulti.new(source_addr, destination_addr_arr, short_message, options)
write_pdu pdu

# keep the message ID so we can associate the SMSC message ID with our message
# when the response arrives.
@ack_ids[pdu.sequence_number] = message_id
else
raise InvalidStateException, "Transceiver is unbound. Cannot send MT messages."
end
end

# Send BindTransceiverResponse PDU.
def send_bind
raise IOError, 'Receiver already bound.' unless unbound?
pdu = Pdu::BindTransceiver.new(
@config[:system_id],
@config[:password],
@config[:system_type],
@config[:source_ton],
@config[:source_npi],
@config[:source_address_range])
write_pdu(pdu)
end

# Use data_coding to find out what message part size we can use
# http://en.wikipedia.org/wiki/SMS#Message_size
def self.get_message_part_size options
return 153 if options[:data_coding].nil?
return 153 if options[:data_coding] == 0
return 134 if options[:data_coding] == 3
return 134 if options[:data_coding] == 5
return 134 if options[:data_coding] == 6
return 134 if options[:data_coding] == 7
return 67 if options[:data_coding] == 8
return 153
end
end
60 changes: 2 additions & 58 deletions lib/smpp/transmitter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,7 @@

# The SMPP Transmitter is the shizzle

class Smpp::Transmitter < Smpp::Base
class Smpp::Transmitter < Smpp::SenderBase

attr_reader :ack_ids

# Send an MT SMS message. Delegate will receive message_accepted callback when SMSC
# acknowledges, or the message_rejected callback upon error
def send_mt(message_id, source_addr, destination_addr, short_message, options={})
logger.debug "Sending MT: #{short_message}"
if @state == :bound
pdu = Pdu::SubmitSm.new(source_addr, destination_addr, short_message, options)
write_pdu(pdu)

# keep the message ID so we can associate the SMSC message ID with our message
# when the response arrives.
@ack_ids[pdu.sequence_number] = message_id
else
raise InvalidStateException, "Transmitter is unbound. Cannot send MT messages."
end
end

def send_concat_mt(message_id, source_addr, destination_addr, message, options = {})
if @state == :bound
# Split the message into parts of 134 characters.
parts = []
while message.size > 0 do
parts << message.slice!(0..133)
end
0.upto(parts.size-1) do |i|
udh = sprintf("%c", 5) # UDH is 5 bytes.
udh << sprintf("%c%c", 0, 3) # This is a concatenated message
udh << sprintf("%c", message_id) # The ID for the entire concatenated message
udh << sprintf("%c", parts.size) # How many parts this message consists of

udh << sprintf("%c", i+1) # This is part i+1

combined_options = {
:esm_class => 64, # This message contains a UDH header.
:udh => udh
}.merge(options)

pdu = Smpp::Pdu::SubmitSm.new(source_addr, destination_addr, parts[i], combined_options)
write_pdu(pdu)
end
else
raise InvalidStateException, "Transmitter is unbound. Cannot send MT messages."
end
end

def send_bind
raise IOError, 'Transmitter already bound.' unless unbound?
pdu = Pdu::BindTransmitter.new(
@config[:system_id],
@config[:password],
@config[:system_type],
@config[:source_ton],
@config[:source_npi],
@config[:source_address_range])
write_pdu(pdu)
end

end