ruby-smpp 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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