From 1c3521586a71239946f1dc4ad168d55889b66c11 Mon Sep 17 00:00:00 2001 From: Guillaume DOTT Date: Mon, 9 Sep 2013 15:50:27 +0200 Subject: [PATCH] Move PDU fields methods into their own classes --- lib/biju/pdu.rb | 61 ++++++++++++------------------ lib/biju/pdu/data_coding_scheme.rb | 42 ++++++++++++++++++++ lib/biju/pdu/phone_number.rb | 28 ++++++++++++++ lib/biju/pdu/type_of_address.rb | 28 ++++++++++++++ lib/biju/pdu/user_data.rb | 31 +++++++++++++++ lib/biju/sms.rb | 8 ++-- 6 files changed, 159 insertions(+), 39 deletions(-) create mode 100644 lib/biju/pdu/data_coding_scheme.rb create mode 100644 lib/biju/pdu/phone_number.rb create mode 100644 lib/biju/pdu/type_of_address.rb create mode 100644 lib/biju/pdu/user_data.rb diff --git a/lib/biju/pdu.rb b/lib/biju/pdu.rb index 001b605..baba27b 100644 --- a/lib/biju/pdu.rb +++ b/lib/biju/pdu.rb @@ -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 diff --git a/lib/biju/pdu/data_coding_scheme.rb b/lib/biju/pdu/data_coding_scheme.rb new file mode 100644 index 0000000..541767b --- /dev/null +++ b/lib/biju/pdu/data_coding_scheme.rb @@ -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 diff --git a/lib/biju/pdu/phone_number.rb b/lib/biju/pdu/phone_number.rb new file mode 100644 index 0000000..8ecdda8 --- /dev/null +++ b/lib/biju/pdu/phone_number.rb @@ -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 diff --git a/lib/biju/pdu/type_of_address.rb b/lib/biju/pdu/type_of_address.rb new file mode 100644 index 0000000..d0d7723 --- /dev/null +++ b/lib/biju/pdu/type_of_address.rb @@ -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 diff --git a/lib/biju/pdu/user_data.rb b/lib/biju/pdu/user_data.rb new file mode 100644 index 0000000..6f57813 --- /dev/null +++ b/lib/biju/pdu/user_data.rb @@ -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 diff --git a/lib/biju/sms.rb b/lib/biju/sms.rb index e46887e..97f55b5 100644 --- a/lib/biju/sms.rb +++ b/lib/biju/sms.rb @@ -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