Move PDU fields methods into their own classes

develop
Guillaume DOTT 2013-09-09 15:50:27 +02:00
parent dbd2f09ec2
commit 1c3521586a
6 changed files with 159 additions and 39 deletions

View File

@ -1,19 +1,30 @@
require 'biju/pdu/gsm7bit'
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 PDU
ENCODING = {
gsm7bit: GSM7Bit,
ucs2: UCS2,
}
def self.encode(phone_number, message, type_of_address: :international)
phone_number = PhoneNumber.encode(phone_number)
user_data = UserData.encode(message)
def self.encode(hash)
end
def self.encode_user_data(message, encoding = :gsm7bit)
raise ArgumentError, "Unknown encoding" unless ENCODING.has_key?(encoding)
ENCODING[encoding].encode(message)
[
'00',
'01',
'00', # TP-Message-Reference
"%02x" % phone_number.length,
"%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
def self.decode(string)
@ -32,36 +43,14 @@ module Biju
'%S%M%H%d%m%y%Z'),
user_data_length: string[52..53],
}
res[:sender_number] = string[22..(22 + res[:address_length])].scan(/../)
.map(&:reverse).join.chop
res[:user_data] = PDU.decode_user_data(string[54..-1],
res[:sender_number] = PhoneNumber.new(
string[22, res[:address_length] + (res[:address_length].odd? ? 1 : 0)],
type_of_address: res[:address_type])
res[:user_data] = UserData.new(message: string[54..-1],
encoding: res[:data_coding_scheme],
length: res[:user_data_length].hex)
res
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2,15 +2,16 @@ require 'date'
module Biju
class Sms
attr_accessor :id, :phone_number, :message
attr_accessor :id, :phone_number, :type_of_address, :message
attr_reader :datetime
def self.from_pdu(string, id = nil)
sms_infos = PDU.decode(string)
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],
message: sms_infos[:user_data])
message: sms_infos[:user_data].decode)
end
def initialize(params={})
@ -35,6 +36,7 @@ module Biju
end
def to_pdu
Biju::PDU.encode(phone_number, message, type_of_address: type_of_address)
end
end
end