diff --git a/lib/smpp.rb b/lib/smpp.rb index b4e81fa..65a7565 100644 --- a/lib/smpp.rb +++ b/lib/smpp.rb @@ -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' diff --git a/lib/smpp/pdu/submit_base.rb b/lib/smpp/pdu/submit_base.rb new file mode 100644 index 0000000..40e2148 --- /dev/null +++ b/lib/smpp/pdu/submit_base.rb @@ -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 \ No newline at end of file diff --git a/lib/smpp/pdu/submit_multi.rb b/lib/smpp/pdu/submit_multi.rb index bfabce6..a8cb203 100644 --- a/lib/smpp/pdu/submit_multi.rb +++ b/lib/smpp/pdu/submit_multi.rb @@ -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, diff --git a/lib/smpp/sender_base.rb b/lib/smpp/sender_base.rb new file mode 100644 index 0000000..04bdac8 --- /dev/null +++ b/lib/smpp/sender_base.rb @@ -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 \ No newline at end of file diff --git a/lib/smpp/transceiver.rb b/lib/smpp/transceiver.rb index 7999094..2bee5e7 100644 --- a/lib/smpp/transceiver.rb +++ b/lib/smpp/transceiver.rb @@ -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 diff --git a/lib/smpp/transmitter.rb b/lib/smpp/transmitter.rb index a188db4..2786336 100644 --- a/lib/smpp/transmitter.rb +++ b/lib/smpp/transmitter.rb @@ -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