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/lib/smpp/pdu/base.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # PDUs are the protcol base units in SMPP
2
2
  module Smpp::Pdu
3
3
  class Base
4
+ #Protocol Version
5
+ PROTOCOL_VERSION = 0x34
4
6
  # Error constants
5
7
  ESME_ROK = 0x00000000 # OK!
6
8
  ESME_RINVMSGLEN = 0x00000001 # Message Length is invalid
@@ -59,7 +61,7 @@ module Smpp::Pdu
59
61
  CANCEL_SM_RESP = 0X80000008
60
62
  ENQUIRE_LINK = 0X00000015
61
63
  ENQUIRE_LINK_RESP = 0X80000015
62
- SUBMIT_MULTI = 0X00000021
64
+ SUBMIT_MULTI = 0X00000021
63
65
  SUBMIT_MULTI_RESP = 0X80000021
64
66
  # PDU sequence number.
65
67
  @@seq = [Time.now.to_i]
@@ -67,6 +69,9 @@ module Smpp::Pdu
67
69
  # Add monitor to sequence counter for thread safety
68
70
  @@seq.extend(MonitorMixin)
69
71
 
72
+ #factory class registry
73
+ @@cmd_map = {}
74
+
70
75
  attr_reader :command_id, :command_status, :sequence_number, :body, :data
71
76
 
72
77
  def initialize(command_id, command_status, seq, body='')
@@ -103,6 +108,12 @@ module Smpp::Pdu
103
108
  end
104
109
  end
105
110
 
111
+ #This factory should be implemented in every subclass that can create itself from wire
112
+ #data. The subclass should also register itself with the 'handles_cmd' class method.
113
+ def Base.from_wire_data(seq, status, body)
114
+ raise Exception.new("#{self.class} claimed to handle wire data, but doesn't.")
115
+ end
116
+
106
117
  # PDU factory method for common client PDUs (used to create PDUs from wire data)
107
118
  def Base.create(data)
108
119
  header = data[0..15]
@@ -111,33 +122,21 @@ module Smpp::Pdu
111
122
  end
112
123
  len, cmd, status, seq = header.unpack('N4')
113
124
  body = data[16..-1]
114
- case cmd
115
- when ENQUIRE_LINK:
116
- EnquireLink.new(seq)
117
- when ENQUIRE_LINK_RESP:
118
- EnquireLinkResponse.new(seq)
119
- when GENERIC_NACK:
120
- GenericNack.new(seq, status, body)
121
- when UNBIND:
122
- Unbind.new(seq)
123
- when UNBIND_RESP:
124
- UnbindResponse.new(seq, status)
125
- when BIND_TRANSMITTER_RESP:
126
- BindTransmitterResponse.new(seq, status, body) # could be opt'l params too
127
- when BIND_RECEIVER_RESP:
128
- BindReceiverResponse.new(seq, status, body)
129
- when BIND_TRANSCEIVER_RESP:
130
- BindTransceiverResponse.new(seq, status, body)
131
- when SUBMIT_SM_RESP:
132
- SubmitSmResponse.new(seq, status, body)
133
- when SUBMIT_MULTI_RESP:
134
- SubmitMultiResponse.new(seq, status, body)
135
- when DELIVER_SM:
136
- DeliverSm.new(seq, status, body)
125
+
126
+ #if a class has been registered to handle this command_id, try
127
+ #to create an instance from the wire data
128
+ if @@cmd_map[cmd]
129
+ @@cmd_map[cmd].from_wire_data(seq, status, body)
137
130
  else
138
131
  Smpp::Base.logger.error "Unknown PDU: 0x#{cmd.to_s(16)}"
139
132
  return nil
140
133
  end
141
134
  end
135
+
136
+ #maps a subclass as the handler for a particulular pdu
137
+ def Base.handles_cmd(command_id)
138
+ @@cmd_map[command_id] = self
139
+ end
140
+
142
141
  end
143
142
  end
@@ -0,0 +1,25 @@
1
+ # this class serves as the base for all the bind* commands.
2
+ # since the command format remains the same for all bind commands,
3
+ # sub classes just change the @@command_id
4
+ class Smpp::Pdu::BindBase < Smpp::Pdu::Base
5
+ class << self; attr_accessor :command_id ; end
6
+
7
+ attr_reader :system_id, :password, :system_type, :addr_ton, :addr_npi, :address_range
8
+
9
+ def initialize(system_id, password, system_type, addr_ton, addr_npi, address_range, seq = nil)
10
+ @system_id, @password, @system_type, @addr_ton, @addr_npi, @address_range =
11
+ system_id, password, system_type, addr_ton, addr_npi, address_range
12
+
13
+ seq ||= next_sequence_number
14
+ body = sprintf("%s\0%s\0%s\0%c%c%c%s\0", system_id, password,system_type, PROTOCOL_VERSION, addr_ton, addr_npi, address_range)
15
+ super(self.class.command_id, 0, seq, body)
16
+ end
17
+
18
+ def self.from_wire_data(seq, status, body)
19
+ #unpack the body
20
+ system_id, password, system_type, interface_version, addr_ton,
21
+ addr_npi, address_range = body.unpack("Z*Z*Z*CCCZ*")
22
+
23
+ self.new(system_id, password, system_type, addr_ton, addr_npi, address_range, seq)
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ class Smpp::Pdu::BindRespBase < Smpp::Pdu::Base
2
+ class << self; attr_accessor :command_id ; end
3
+ attr_accessor :system_id
4
+
5
+ def initialize(seq, status, system_id)
6
+ seq ||= next_sequence_number
7
+ system_id = system_id.to_s + "\000"
8
+ super(self.class.command_id, status, seq, system_id) # pass in system_id as body for simple debugging
9
+ @system_id = system_id
10
+ end
11
+
12
+ def self.from_wire_data(seq, status, body)
13
+ system_id = body.chomp("\000")
14
+ new(seq, status, system_id)
15
+ end
16
+
17
+ end
@@ -1,6 +1,4 @@
1
- class Smpp::Pdu::BindTransceiver < Smpp::Pdu::Base
2
- def initialize(system_id, password, system_type, addr_ton, addr_npi, address_range)
3
- body = sprintf("%s\0%s\0%s\0%c%c%c%s\0", system_id, password,system_type, 0x34, addr_ton, addr_npi, address_range)
4
- super(BIND_TRANSCEIVER, 0, next_sequence_number, body)
5
- end
1
+ class Smpp::Pdu::BindTransceiver < Smpp::Pdu::BindBase
2
+ @command_id = BIND_TRANSCEIVER
3
+ handles_cmd BIND_TRANSCEIVER
6
4
  end
@@ -1,7 +1,4 @@
1
- class Smpp::Pdu::BindTransceiverResponse < Smpp::Pdu::Base
2
- attr_accessor :system_id
3
- def initialize(seq, status, system_id)
4
- super(BIND_TRANSCEIVER_RESP, status, seq, system_id) # pass in system_id as body for simple debugging
5
- @system_id = system_id
6
- end
1
+ class Smpp::Pdu::BindTransceiverResponse < Smpp::Pdu::BindRespBase
2
+ @command_id = BIND_TRANSCEIVER_RESP
3
+ handles_cmd BIND_TRANSCEIVER_RESP
7
4
  end
@@ -1,40 +1,83 @@
1
1
  # Received for MO message or delivery notification
2
- class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
3
- attr_reader :source_addr, :destination_addr, :short_message, :source_addr, :esm_class, :msg_reference, :stat
4
- def initialize(seq, status, body)
5
- # brutally unpack it
6
- service_type,
7
- source_addr_ton,
8
- source_addr_npi,
9
- @source_addr,
10
- dest_addr_ton,
11
- dest_addr_npi,
12
- @destination_addr,
13
- @esm_class,
14
- protocol_id,
15
- priority_flag,
16
- schedule_delivery_time,
17
- validity_period,
18
- registered_delivery,
19
- replace_if_present_flag,
20
- data_coding,
21
- sm_default_msg_id,
22
- sm_length,
23
- @short_message = body.unpack('Z*CCZ*CCZ*CCCZ*Z*CCCCCa*')
24
- logger.debug "DeliverSM with source_addr=#{@source_addr}, destination_addr=#{@destination_addr}"
2
+ class Smpp::Pdu::DeliverSm < Smpp::Pdu::Base
3
+ handles_cmd DELIVER_SM
4
+ attr_reader :service_type, :source_addr_ton, :source_addr_npi, :source_addr, :dest_addr_ton, :dest_addr_npi,
5
+ :destination_addr, :esm_class, :protocol_id, :priority_flag, :schedule_delivery_time,
6
+ :validity_period, :registered_delivery, :replace_if_present_flag, :data_coding,
7
+ :sm_default_msg_id, :sm_length, :stat, :msg_reference, :udh, :short_message
8
+
9
+ def initialize(source_addr, destination_addr, short_message, options={}, seq=nil)
25
10
 
26
- # Note: if the SM is a delivery receipt (esm_class=4) then the short_message _may_ be in this format:
11
+ @udh = options[:udh]
12
+ @service_type = options[:service_type]? options[:service_type] :''
13
+ @source_addr_ton = options[:source_addr_ton]?options[:source_addr_ton]:0 # network specific
14
+ @source_addr_npi = options[:source_addr_npi]?options[:source_addr_npi]:1 # unknown
15
+ @source_addr = source_addr
16
+ @dest_addr_ton = options[:dest_addr_ton]?options[:dest_addr_ton]:1 # international
17
+ @dest_addr_npi = options[:dest_addr_npi]?options[:dest_addr_npi]:1 # unknown
18
+ @destination_addr = destination_addr
19
+ @esm_class = options[:esm_class]?options[:esm_class]:0 # default smsc mode
20
+ @protocol_id = options[:protocol_id]?options[:protocol_id]:0
21
+ @priority_flag = options[:priority_flag]?options[:priority_flag]:1
22
+ @schedule_delivery_time = options[:schedule_delivery_time]?options[:schedule_delivery_time]:''
23
+ @validity_period = options[:validity_period]?options[:validity_period]:''
24
+ @registered_delivery = options[:registered_delivery]?options[:registered_delivery]:1 # we want delivery notifications
25
+ @replace_if_present_flag = options[:replace_if_present_flag]?options[:replace_if_present_flag]:0
26
+ @data_coding = options[:data_coding]?options[:data_coding]:3 # iso-8859-1
27
+ @sm_default_msg_id = options[:sm_default_msg_id]?options[:sm_default_msg_id]:0
28
+ @short_message = short_message
29
+ payload = @udh ? @udh + @short_message : @short_message
30
+ @sm_length = payload.length
31
+
32
+ #fields set for delivery report
33
+ @stat = options[:stat]
34
+ @msg_reference = options[:msg_reference]
35
+
36
+ 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
+ @dest_addr_ton, @dest_addr_npi, @destination_addr, @esm_class, @protocol_id, @priority_flag, @schedule_delivery_time, @validity_period,
38
+ @registered_delivery, @replace_if_present_flag, @data_coding, @sm_default_msg_id, @sm_length, payload)
39
+
40
+ seq ||= next_sequence_number
41
+
42
+ super(DELIVER_SM, 0, seq, pdu_body)
43
+ end
44
+
45
+ def self.from_wire_data(seq, status, body)
46
+ options = {}
47
+ # brutally unpack it
48
+ options[:service_type],
49
+ options[:source_addr_ton],
50
+ options[:source_addr_npi],
51
+ source_addr,
52
+ options[:dest_addr_ton],
53
+ options[:dest_addr_npi],
54
+ destination_addr,
55
+ options[:esm_class],
56
+ options[:protocol_id],
57
+ options[:priority_flag],
58
+ options[:schedule_delivery_time],
59
+ options[:validity_period],
60
+ options[:registered_delivery],
61
+ options[:replace_if_present_flag],
62
+ options[:data_coding],
63
+ options[:sm_default_msg_id],
64
+ options[:sm_length],
65
+ short_message = body.unpack('Z*CCZ*CCZ*CCCZ*Z*CCCCCa*')
66
+ Smpp::Base.logger.debug "DeliverSM with source_addr=#{source_addr}, destination_addr=#{destination_addr}"
67
+
68
+ #Note: if the SM is a delivery receipt (esm_class=4) then the short_message _may_ be in this format:
27
69
  # "id:Smsc2013 sub:1 dlvrd:1 submit date:0610171515 done date:0610171515 stat:0 err:0 text:blah"
28
70
  # or this format:
29
71
  # "4790000000SMSAlert^id:1054BC63 sub:0 dlvrd:1 submit date:0610231217 done date:0610231217 stat:DELIVRD err: text:"
30
72
  # (according to the SMPP spec, the format is vendor specific)
31
73
  # For example, Tele2 (Norway):
32
74
  # "<msisdn><shortcode>?id:10ea34755d3d4f7a20900cdb3349e549 sub:001 dlvrd:001 submit date:0611011228 done date:0611011230 stat:DELIVRD err:000 Text:abc'!10ea34755d3d4f7a20900cdb3349e549"
33
- if @esm_class == 4
34
- @msg_reference = @short_message.scanf('id:%s').to_s
75
+ if options[:esm_class] == 4
76
+ options[:msg_reference] = short_message.scanf('id:%s').to_s
35
77
  # @stat must be parsed according to the SMSC vendor's specifications (see comment above)
36
- @stat = 0
78
+ options[:stat] = 0
37
79
  end
38
- super(DELIVER_SM, status, seq, body)
80
+
81
+ new(source_addr, destination_addr, short_message, options, seq)
39
82
  end
40
- end
83
+ end
@@ -1,5 +1,12 @@
1
1
  class Smpp::Pdu::DeliverSmResponse < Smpp::Pdu::Base
2
+ handles_cmd DELIVER_SM_RESP
3
+
2
4
  def initialize(seq, status=ESME_ROK)
5
+ seq ||= next_sequence_number
3
6
  super(DELIVER_SM_RESP, status, seq, "\000") # body must be NULL..!
4
7
  end
8
+
9
+ def self.from_wire_data(seq, status, body)
10
+ new(seq, status)
11
+ end
5
12
  end
@@ -1,5 +1,11 @@
1
1
  class Smpp::Pdu::EnquireLink < Smpp::Pdu::Base
2
+ handles_cmd ENQUIRE_LINK
3
+
2
4
  def initialize(seq = next_sequence_number)
3
5
  super(ENQUIRE_LINK, 0, seq)
4
6
  end
7
+
8
+ def self.from_wire_data(seq, status, body)
9
+ new(seq)
10
+ end
5
11
  end
@@ -1,5 +1,11 @@
1
1
  class Smpp::Pdu::EnquireLinkResponse < Smpp::Pdu::Base
2
- def initialize(seq)
2
+ handles_cmd ENQUIRE_LINK_RESP
3
+
4
+ def initialize(seq = next_sequence_number)
3
5
  super(ENQUIRE_LINK_RESP, ESME_ROK, seq)
4
6
  end
7
+
8
+ def self.from_wire_data(seq, status, body)
9
+ new(seq)
10
+ end
5
11
  end
@@ -1,8 +1,20 @@
1
1
  # signals invalid message header
2
2
  class Smpp::Pdu::GenericNack < Smpp::Pdu::Base
3
+ handles_cmd GENERIC_NACK
4
+
3
5
  attr_accessor :error_code
4
- def initialize(seq, error_code, original_sequence_code)
5
- super(GENERIC_NACK, error_code, seq, "Error: #{error_code} Problem sequence: #{original_sequence_code.blank? ? 'unknown' : original_sequence_code }")
6
+
7
+ def initialize(seq, error_code, original_sequence_code = nil)
8
+ #TODO: original_sequence_code used to be passed to this function
9
+ #however, a GENERIC_NACK has only one sequence number and no body
10
+ #so this is a useless variable. I leave it here only to preserve
11
+ #the API, but it has no practical use.
12
+ seq ||= next_sequence_number
13
+ super(GENERIC_NACK, error_code, seq)
6
14
  @error_code = error_code
7
15
  end
16
+
17
+ def self.from_wire_data(seq, status, body)
18
+ new(seq,status,body)
19
+ end
8
20
  end
@@ -1,5 +1,6 @@
1
1
  # Sending an MT message to multiple addresses
2
2
  # Author: Abhishek Parolkar, (abhishek[at]parolkar.com)
3
+ #TODO: Implement from_wire_data for this pdu class.
3
4
  class Smpp::Pdu::SubmitMulti < Smpp::Pdu::Base
4
5
  IS_SMEADDR = 1 # type of dest_flag
5
6
  IS_DISTLISTNAME = 2 #type of dest_flag
@@ -45,23 +46,23 @@ class Smpp::Pdu::SubmitMulti < Smpp::Pdu::Base
45
46
  a = @data.to_s.unpack('N4')
46
47
  sprintf("(%22s) len=%3d cmd=%8s status=%1d seq=%03d (%s)", self.class.to_s[11..-1], a[0], a[1].to_s(16), a[2], a[3], @msg_body[0..30])
47
48
  end
49
+
48
50
  def build_destination_addresses(dest_array,dest_addr_ton,dest_addr_npi, dest_flag = IS_SMEADDR)
49
-
50
- formatted_array = Array.new
51
- dest_array.each { |dest_elem|
52
- if dest_flag == IS_SMEADDR
53
- packet_str = sprintf("%c%c%c%s",IS_SMEADDR,dest_addr_ton,dest_addr_npi,dest_elem)
54
- formatted_array.push(packet_str)
51
+ formatted_array = Array.new
52
+ dest_array.each { |dest_elem|
53
+ if dest_flag == IS_SMEADDR
54
+ packet_str = sprintf("%c%c%c%s",IS_SMEADDR,dest_addr_ton,dest_addr_npi,dest_elem)
55
+ formatted_array.push(packet_str)
55
56
 
56
- elsif dest_flag == IS_DISTLISTNAME
57
- packet_str = sprintf("%c%s",IS_SMEADDR,dest_elem)
58
- formatted_array.push(packet_str)
57
+ elsif dest_flag == IS_DISTLISTNAME
58
+ packet_str = sprintf("%c%s",IS_SMEADDR,dest_elem)
59
+ formatted_array.push(packet_str)
59
60
 
60
- end
61
+ end
61
62
 
62
- }
63
+ }
63
64
 
64
- formatted_array.join('\0');
65
+ formatted_array.join('\0');
65
66
  end
66
67
 
67
68
  end
@@ -1,10 +1,49 @@
1
1
  # Recieving response for an MT message sent to multiple addresses
2
2
  # Author: Abhishek Parolkar, (abhishek[at]parolkar.com)
3
3
  class Smpp::Pdu::SubmitMultiResponse < Smpp::Pdu::Base
4
- attr_accessor :message_id
5
- def initialize(seq, status, message_id)
6
- message_id = message_id.chomp("\000")
7
- super(SUBMIT_MULTI_RESP, status, seq, message_id)
4
+ class UnsuccessfulSme
5
+ Struct.new(:dest_addr_ton, :dest_addr_npi, :destination_addr, :error_status_code)
6
+ end
7
+
8
+ handles_cmd SUBMIT_MULTI_RESP
9
+
10
+ attr_accessor :message_id, :unsuccess_smes
11
+
12
+ def initialize(seq, status, message_id, unsuccess_smes = [])
13
+ @unsuccess_smes = unsuccess_smes
14
+ seq ||= next_sequence_number
15
+
16
+ packed_smes = ""
17
+ unsuccess_smes.each do |sme|
18
+ packed_smes << [
19
+ sme.dest_addr_ton,
20
+ sme.dest_addr_npi,
21
+ sme.destination_addr,
22
+ sme.error_status_code
23
+ ].pack("CCZ*N")
24
+ end
25
+ body = [message_id, unsuccess_smes.size, packed_smes].pack("Z*Ca*")
26
+
27
+ super(SUBMIT_MULTI_RESP, status, seq, body)
8
28
  @message_id = message_id
9
29
  end
30
+
31
+ def self.from_wire_data(seq, status, body)
32
+ message_id, no_unsuccess, rest = body.unpack("Z*Ca*")
33
+ unsuccess_smes = []
34
+
35
+ no_unsuccess.times do |i|
36
+ #unpack the next sme
37
+ dest_addr_ton, dest_addr_npi, destination_addr, error_status_code =
38
+ rest.unpack("CCZ*N")
39
+ #remove the SME from rest
40
+ rest.slice!(0,7 + destination_addr.length)
41
+ unsuccess_smes << UnsuccessfulSme.new(dest_addr_ton, dest_addr_npi, destination_addr, error_status_code)
42
+ end
43
+
44
+ new(seq, status, message_id, unsuccess_smes)
45
+ end
46
+
47
+
48
+
10
49
  end
@@ -1,34 +1,46 @@
1
1
  # Sending an MT message
2
2
  class Smpp::Pdu::SubmitSm < Smpp::Pdu::Base
3
+ handles_cmd SUBMIT_SM
4
+ attr_reader :service_type, :source_addr_ton, :source_addr_npi, :source_addr, :dest_addr_ton, :dest_addr_npi,
5
+ :destination_addr, :esm_class, :protocol_id, :priority_flag, :schedule_delivery_time,
6
+ :validity_period, :registered_delivery, :replace_if_present_flag, :data_coding,
7
+ :sm_default_msg_id, :sm_length, :udh, :short_message
8
+
3
9
 
4
10
  # Note: short_message (the SMS body) must be in iso-8859-1 format
5
- def initialize(source_addr, destination_addr, short_message, options={})
11
+ def initialize(source_addr, destination_addr, short_message, options={}, seq = nil)
6
12
 
7
13
  @msg_body = short_message
8
14
 
9
- udh = options[:udh]
10
- service_type = options[:service_type]? options[:service_type] :''
11
- source_addr_ton = options[:source_addr_ton]?options[:source_addr_ton]:0 # network specific
12
- source_addr_npi = options[:source_addr_npi]?options[:source_addr_npi]:1 # unknown
13
- dest_addr_ton = options[:dest_addr_ton]?options[:dest_addr_ton]:1 # international
14
- dest_addr_npi = options[:dest_addr_npi]?options[:dest_addr_npi]:1 # unknown
15
- esm_class = options[:esm_class]?options[:esm_class]:0 # default smsc mode
16
- protocol_id = options[:protocol_id]?options[:protocol_id]:0
17
- priority_flag = options[:priority_flag]?options[:priority_flag]:1
18
- schedule_delivery_time = options[:schedule_delivery_time]?options[:schedule_delivery_time]:''
19
- validity_period = options[:validity_period]?options[:validity_period]:''
20
- registered_delivery = options[:registered_delivery]?options[:registered_delivery]:1 # we want delivery notifications
21
- replace_if_present_flag = options[:replace_if_present_flag]?options[:replace_if_present_flag]:0
22
- data_coding = options[:data_coding]?options[:data_coding]:3 # iso-8859-1
23
- sm_default_msg_id = options[:sm_default_msg_id]?options[:sm_default_msg_id]:0
24
- payload = udh ? udh + short_message : short_message # this used to be (short_message + "\0")
25
- sm_length = payload.length
15
+ @udh = options[:udh]
16
+ @service_type = options[:service_type]? options[:service_type] :''
17
+ @source_addr_ton = options[:source_addr_ton]?options[:source_addr_ton]:0 # network specific
18
+ @source_addr_npi = options[:source_addr_npi]?options[:source_addr_npi]:1 # unknown
19
+ @source_addr = source_addr
20
+ @dest_addr_ton = options[:dest_addr_ton]?options[:dest_addr_ton]:1 # international
21
+ @dest_addr_npi = options[:dest_addr_npi]?options[:dest_addr_npi]:1 # unknown
22
+ @destination_addr = destination_addr
23
+ @esm_class = options[:esm_class]?options[:esm_class]:0 # default smsc mode
24
+ @protocol_id = options[:protocol_id]?options[:protocol_id]:0
25
+ @priority_flag = options[:priority_flag]?options[:priority_flag]:1
26
+ @schedule_delivery_time = options[:schedule_delivery_time]?options[:schedule_delivery_time]:''
27
+ @validity_period = options[:validity_period]?options[:validity_period]:''
28
+ @registered_delivery = options[:registered_delivery]?options[:registered_delivery]:1 # we want delivery notifications
29
+ @replace_if_present_flag = options[:replace_if_present_flag]?options[:replace_if_present_flag]:0
30
+ @data_coding = options[:data_coding]?options[:data_coding]:3 # iso-8859-1
31
+ @sm_default_msg_id = options[:sm_default_msg_id]?options[:sm_default_msg_id]:0
32
+ @short_message = short_message
33
+ payload = @udh ? @udh + @short_message : @short_message
34
+ @sm_length = payload.length
26
35
 
27
36
  # craft the string/byte buffer
28
- 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,
29
- dest_addr_ton, dest_addr_npi, destination_addr, esm_class, protocol_id, priority_flag, schedule_delivery_time, validity_period,
30
- registered_delivery, replace_if_present_flag, data_coding, sm_default_msg_id, sm_length, payload)
31
- super(SUBMIT_SM, 0, next_sequence_number, pdu_body)
37
+ 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,
38
+ @dest_addr_ton, @dest_addr_npi, @destination_addr, @esm_class, @protocol_id, @priority_flag, @schedule_delivery_time, @validity_period,
39
+ @registered_delivery, @replace_if_present_flag, @data_coding, @sm_default_msg_id, @sm_length, payload)
40
+
41
+ seq ||= next_sequence_number
42
+
43
+ super(SUBMIT_SM, 0, seq, pdu_body)
32
44
  end
33
45
 
34
46
  # some special formatting is needed for SubmitSm PDUs to show the actual message content
@@ -37,4 +49,31 @@ class Smpp::Pdu::SubmitSm < Smpp::Pdu::Base
37
49
  a = @data.to_s.unpack('N4')
38
50
  sprintf("(%22s) len=%3d cmd=%8s status=%1d seq=%03d (%s)", self.class.to_s[11..-1], a[0], a[1].to_s(16), a[2], a[3], @msg_body[0..30])
39
51
  end
52
+
53
+ def self.from_wire_data(seq, status, body)
54
+ options = {}
55
+
56
+ options[:service_type],
57
+ options[:source_addr_ton],
58
+ options[:source_addr_npi],
59
+ source_addr,
60
+ options[:dest_addr_ton],
61
+ options[:dest_addr_npi],
62
+ destination_addr,
63
+ options[:esm_class],
64
+ options[:protocol_id],
65
+ options[:priority_flag],
66
+ options[:schedule_delivery_time],
67
+ options[:validity_period],
68
+ options[:registered_delivery],
69
+ options[:replace_if_present_flag],
70
+ options[:data_coding],
71
+ options[:sm_default_msg_id],
72
+ options[:sm_length],
73
+ short_message = body.unpack('Z*CCZ*CCZ*CCCZ*Z*CCCCCa*')
74
+ Smpp::Base.logger.debug "DeliverSM with source_addr=#{source_addr}, destination_addr=#{destination_addr}"
75
+
76
+ new(source_addr, destination_addr, short_message, options, seq)
77
+ end
78
+
40
79
  end
@@ -1,8 +1,17 @@
1
1
  class Smpp::Pdu::SubmitSmResponse < Smpp::Pdu::Base
2
+ handles_cmd SUBMIT_SM_RESP
3
+
2
4
  attr_accessor :message_id
5
+
3
6
  def initialize(seq, status, message_id)
4
- message_id = message_id.chomp("\000")
5
- super(SUBMIT_SM_RESP, status, seq, message_id)
7
+ seq ||= next_sequence_number
8
+ body = message_id.to_s + "\000"
9
+ super(SUBMIT_SM_RESP, status, seq, body)
6
10
  @message_id = message_id
7
11
  end
12
+
13
+ def self.from_wire_data(seq, status, body)
14
+ message_id = body.chomp("\000")
15
+ new(seq, status, message_id)
16
+ end
8
17
  end
@@ -1,5 +1,11 @@
1
1
  class Smpp::Pdu::Unbind < Smpp::Pdu::Base
2
+ handles_cmd UNBIND
3
+
2
4
  def initialize(seq=next_sequence_number)
3
5
  super(UNBIND, 0, seq)
4
6
  end
7
+
8
+ def self.from_wire_data(seq, status, body)
9
+ new(seq)
10
+ end
5
11
  end
@@ -1,5 +1,12 @@
1
1
  class Smpp::Pdu::UnbindResponse < Smpp::Pdu::Base
2
+ handles_cmd UNBIND_RESP
3
+
2
4
  def initialize(seq, status)
5
+ seq ||= next_sequence_number
3
6
  super(UNBIND_RESP, status, seq)
4
7
  end
8
+
9
+ def self.from_wire_data(seq, status, body)
10
+ new(seq, status)
11
+ end
5
12
  end