Move PDU fields methods into their own classes
parent
dbd2f09ec2
commit
1c3521586a
|
@ -1,19 +1,30 @@
|
||||||
require 'biju/pdu/gsm7bit'
|
require 'biju/pdu/gsm7bit'
|
||||||
require 'biju/pdu/ucs2'
|
require 'biju/pdu/ucs2'
|
||||||
|
|
||||||
|
require 'biju/pdu/user_data'
|
||||||
|
require 'biju/pdu/data_coding_scheme'
|
||||||
|
|
||||||
|
require 'biju/pdu/phone_number'
|
||||||
|
require 'biju/pdu/type_of_address'
|
||||||
|
|
||||||
module Biju
|
module Biju
|
||||||
module PDU
|
module PDU
|
||||||
ENCODING = {
|
def self.encode(phone_number, message, type_of_address: :international)
|
||||||
gsm7bit: GSM7Bit,
|
phone_number = PhoneNumber.encode(phone_number)
|
||||||
ucs2: UCS2,
|
user_data = UserData.encode(message)
|
||||||
}
|
|
||||||
|
|
||||||
def self.encode(hash)
|
[
|
||||||
end
|
'00',
|
||||||
|
'01',
|
||||||
def self.encode_user_data(message, encoding = :gsm7bit)
|
'00', # TP-Message-Reference
|
||||||
raise ArgumentError, "Unknown encoding" unless ENCODING.has_key?(encoding)
|
"%02x" % phone_number.length,
|
||||||
ENCODING[encoding].encode(message)
|
"%02x" % phone_number.type_of_address.hex,
|
||||||
|
phone_number.number,
|
||||||
|
'00', # TP-PID: Protocol identifier
|
||||||
|
"%02x" % user_data.encoding.hex,
|
||||||
|
"%02x" % user_data.length,
|
||||||
|
user_data.message
|
||||||
|
].join
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.decode(string)
|
def self.decode(string)
|
||||||
|
@ -32,36 +43,14 @@ module Biju
|
||||||
'%S%M%H%d%m%y%Z'),
|
'%S%M%H%d%m%y%Z'),
|
||||||
user_data_length: string[52..53],
|
user_data_length: string[52..53],
|
||||||
}
|
}
|
||||||
res[:sender_number] = string[22..(22 + res[:address_length])].scan(/../)
|
res[:sender_number] = PhoneNumber.new(
|
||||||
.map(&:reverse).join.chop
|
string[22, res[:address_length] + (res[:address_length].odd? ? 1 : 0)],
|
||||||
res[:user_data] = PDU.decode_user_data(string[54..-1],
|
type_of_address: res[:address_type])
|
||||||
|
res[:user_data] = UserData.new(message: string[54..-1],
|
||||||
encoding: res[:data_coding_scheme],
|
encoding: res[:data_coding_scheme],
|
||||||
length: res[:user_data_length].hex)
|
length: res[:user_data_length].hex)
|
||||||
|
|
||||||
res
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.decode_user_data(message, encoding: '00', length: 0)
|
|
||||||
encoding = data_coding_scheme(encoding) unless encoding.is_a?(Symbol)
|
|
||||||
|
|
||||||
raise ArgumentError, "Unknown encoding" unless ENCODING.has_key?(encoding)
|
|
||||||
ENCODING[encoding].decode(message, length: length)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.data_coding_scheme(dcs)
|
|
||||||
dcs = dcs.hex if dcs.is_a?(String)
|
|
||||||
if dcs & 0b11000000 == 0
|
|
||||||
case dcs & 0b00001100
|
|
||||||
when 0
|
|
||||||
:gsm7bit
|
|
||||||
when 4
|
|
||||||
:gsm8bit
|
|
||||||
when 8
|
|
||||||
:ucs2
|
|
||||||
when 12
|
|
||||||
:reserved
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
module Biju
|
||||||
|
module PDU
|
||||||
|
class DataCodingScheme
|
||||||
|
DATA_CODING_SCHEME = {
|
||||||
|
gsm7bit: 0,
|
||||||
|
gsm8bit: 4,
|
||||||
|
ucs2: 8,
|
||||||
|
reserved: 12,
|
||||||
|
}
|
||||||
|
|
||||||
|
def self.autodetect(message)
|
||||||
|
message.chars.each do |char|
|
||||||
|
return :ucs2 unless GSM7Bit::BASIC_7BIT_CHARACTER_SET.include?(char) ||
|
||||||
|
GSM7Bit::BASIC_7BIT_CHARACTER_SET_EXTENSION.has_value?(char)
|
||||||
|
end
|
||||||
|
|
||||||
|
:gsm7bit
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(dcs, options = {})
|
||||||
|
unless dcs.is_a?(Symbol)
|
||||||
|
dcs = dcs.hex if dcs.is_a?(String)
|
||||||
|
if dcs & 0b11000000 == 0
|
||||||
|
dcs = DATA_CODING_SCHEME.key(dcs & 0b00001100)
|
||||||
|
else
|
||||||
|
raise "Unsupported"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@dcs = dcs
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_sym
|
||||||
|
@dcs
|
||||||
|
end
|
||||||
|
|
||||||
|
def hex
|
||||||
|
DATA_CODING_SCHEME[@dcs]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,28 @@
|
||||||
|
module Biju
|
||||||
|
module PDU
|
||||||
|
class PhoneNumber
|
||||||
|
attr_accessor :type_of_address, :number
|
||||||
|
|
||||||
|
def self.encode(number, type_of_address: :international)
|
||||||
|
number << 'F' if number.length.odd?
|
||||||
|
new(
|
||||||
|
number.scan(/../).map(&:reverse).join,
|
||||||
|
type_of_address: type_of_address
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(number, type_of_address: :international)
|
||||||
|
self.number = number
|
||||||
|
self.type_of_address = TypeOfAddress.new(type_of_address)
|
||||||
|
end
|
||||||
|
|
||||||
|
def decode
|
||||||
|
number.scan(/../).map(&:reverse).join.chomp('F')
|
||||||
|
end
|
||||||
|
|
||||||
|
def length
|
||||||
|
number.length - (number[-2, 2].hex >> 4 == 15 ? 1 : 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,28 @@
|
||||||
|
module Biju
|
||||||
|
module PDU
|
||||||
|
class TypeOfAddress
|
||||||
|
TYPE_OF_ADDRESS = {
|
||||||
|
unknown: 0b10000001,
|
||||||
|
international: 0b10010001,
|
||||||
|
national: 0b10100001,
|
||||||
|
reserved: 0b11110001,
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize(type_of_address, options = {})
|
||||||
|
unless type_of_address.is_a?(Symbol)
|
||||||
|
type_of_address = type_of_address.hex if type_of_address.is_a?(String)
|
||||||
|
type_of_address = TYPE_OF_ADDRESS.key(type_of_address)
|
||||||
|
end
|
||||||
|
@type_of_address = type_of_address
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_sym
|
||||||
|
@type_of_address
|
||||||
|
end
|
||||||
|
|
||||||
|
def hex
|
||||||
|
TYPE_OF_ADDRESS[@type_of_address]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,31 @@
|
||||||
|
module Biju
|
||||||
|
module PDU
|
||||||
|
class UserData
|
||||||
|
ENCODING = {
|
||||||
|
gsm7bit: GSM7Bit,
|
||||||
|
ucs2: UCS2,
|
||||||
|
}
|
||||||
|
|
||||||
|
attr_accessor :encoding, :message, :length
|
||||||
|
|
||||||
|
def self.encode(message, encoding: nil)
|
||||||
|
encoding = DataCodingScheme.autodetect(message) if encoding.nil?
|
||||||
|
|
||||||
|
raise ArgumentError, 'Unknown encoding' unless ENCODING.has_key?(encoding)
|
||||||
|
res = ENCODING[encoding].encode(message)
|
||||||
|
|
||||||
|
new(message: res[0], length: res[1][:length], encoding: encoding)
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(message: '', length: 0, encoding: :gsm7bit)
|
||||||
|
self.encoding = DataCodingScheme.new(encoding)
|
||||||
|
self.message = message
|
||||||
|
self.length = length
|
||||||
|
end
|
||||||
|
|
||||||
|
def decode
|
||||||
|
ENCODING[encoding.to_sym].decode(message, length: length)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,15 +2,16 @@ require 'date'
|
||||||
|
|
||||||
module Biju
|
module Biju
|
||||||
class Sms
|
class Sms
|
||||||
attr_accessor :id, :phone_number, :message
|
attr_accessor :id, :phone_number, :type_of_address, :message
|
||||||
attr_reader :datetime
|
attr_reader :datetime
|
||||||
|
|
||||||
def self.from_pdu(string, id = nil)
|
def self.from_pdu(string, id = nil)
|
||||||
sms_infos = PDU.decode(string)
|
sms_infos = PDU.decode(string)
|
||||||
new(id: id,
|
new(id: id,
|
||||||
phone_number: sms_infos[:sender_number],
|
phone_number: sms_infos[:sender_number].decode,
|
||||||
|
type_of_address: sms_infos[:sender_number].type_of_address.to_sym,
|
||||||
datetime: sms_infos[:timestamp],
|
datetime: sms_infos[:timestamp],
|
||||||
message: sms_infos[:user_data])
|
message: sms_infos[:user_data].decode)
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(params={})
|
def initialize(params={})
|
||||||
|
@ -35,6 +36,7 @@ module Biju
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_pdu
|
def to_pdu
|
||||||
|
Biju::PDU.encode(phone_number, message, type_of_address: type_of_address)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue