pdu_sms 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +56 -0
- data/Rakefile +6 -0
- data/bin/console +8 -0
- data/bin/setup +7 -0
- data/lib/pdu_sms.rb +99 -0
- data/lib/pdu_sms/data_coding_scheme.rb +120 -0
- data/lib/pdu_sms/destination_address.rb +57 -0
- data/lib/pdu_sms/helpers.rb +67 -0
- data/lib/pdu_sms/message_reference.rb +41 -0
- data/lib/pdu_sms/originating_address.rb +57 -0
- data/lib/pdu_sms/packet_data_unit.rb +126 -0
- data/lib/pdu_sms/packet_data_unit_error.rb +2 -0
- data/lib/pdu_sms/pdu_type.rb +179 -0
- data/lib/pdu_sms/phone.rb +121 -0
- data/lib/pdu_sms/protocol_identifier.rb +55 -0
- data/lib/pdu_sms/service_center_address.rb +74 -0
- data/lib/pdu_sms/service_center_time_stamp.rb +76 -0
- data/lib/pdu_sms/user_data.rb +276 -0
- data/lib/pdu_sms/user_data_length.rb +81 -0
- data/lib/pdu_sms/validity_period.rb +164 -0
- data/lib/pdu_sms/version.rb +3 -0
- data/pdu_sms.gemspec +25 -0
- metadata +112 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module PduSms
|
|
2
|
+
class MessageReference
|
|
3
|
+
|
|
4
|
+
def initialize(num)
|
|
5
|
+
if (0..255).include?(num)
|
|
6
|
+
@mr = num
|
|
7
|
+
else
|
|
8
|
+
raise ArgumentError, 'The "num" is incorrect'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def MessageReference.encode_ms(num)
|
|
13
|
+
new(num).freeze
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def MessageReference.decode_ms(pdu)
|
|
17
|
+
new(MessageReference.cut_off_pdu(pdu, :current, :ms).to_i(2)).freeze
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def MessageReference.cut_off_pdu(pdu, part=:all, type=:ms) # tail current
|
|
21
|
+
part_pdu = PDUType.cut_off_pdu(pdu, :tail)
|
|
22
|
+
raise ArgumentError, 'The "pdu" is incorrect' if part_pdu.length < 2
|
|
23
|
+
current = part_pdu[0..1]
|
|
24
|
+
tail = part_pdu[2..-1]
|
|
25
|
+
case part
|
|
26
|
+
when :current then current
|
|
27
|
+
when :tail then tail
|
|
28
|
+
else [current,tail]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def get_hex
|
|
33
|
+
'%02x' % @mr
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def get_mr
|
|
37
|
+
@mr
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module PduSms
|
|
2
|
+
class OriginatingAddress < Phone
|
|
3
|
+
|
|
4
|
+
def initialize(type=false, data=false, number_play_identifier=false, type_number=false)
|
|
5
|
+
if type == :decode_sc
|
|
6
|
+
_set_pdu_hex OriginatingAddress.cut_off_pdu(data, :current, :sc)
|
|
7
|
+
elsif type == :encode_sc
|
|
8
|
+
_set_phone_number data, number_play_identifier, type_number
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def OriginatingAddress.encode_sc(phone, number_play_identifier=false, type_number=false)
|
|
13
|
+
new(:encode_sc, phone, number_play_identifier, type_number)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def OriginatingAddress.decode_sc(pdu)
|
|
17
|
+
new(:decode_sc, pdu).freeze
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def OriginatingAddress.cut_off_pdu(pdu, part=:all, type=:sc) # tail current
|
|
21
|
+
part_pdu = PDUType.cut_off_pdu(pdu, :tail)
|
|
22
|
+
raise ArgumentError, 'The "pdu" is incorrect' if part_pdu.length < 4
|
|
23
|
+
length = part_pdu[0..1].to_i(16)
|
|
24
|
+
if length % 2 == 0
|
|
25
|
+
current = part_pdu[0..length+3]
|
|
26
|
+
tail = part_pdu[length+4..-1]
|
|
27
|
+
else
|
|
28
|
+
current = part_pdu[0..length+4]
|
|
29
|
+
tail = part_pdu[length+5..-1]
|
|
30
|
+
end
|
|
31
|
+
case part
|
|
32
|
+
when :current then current
|
|
33
|
+
when :tail then tail
|
|
34
|
+
else [current,tail]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def get_hex
|
|
39
|
+
'%s%s' % [_address_length, _get_hex_type_and_phone]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def _set_pdu_hex(str_pdu)
|
|
45
|
+
_set_hex_type_and_phone(str_pdu[2..-1])
|
|
46
|
+
self
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def _address_length
|
|
50
|
+
if @number_plan_identifier == ID_ALPHANUMERIC
|
|
51
|
+
'%02x' % (@phone_number.length * 0.875 * 2).round
|
|
52
|
+
else
|
|
53
|
+
'%02x' % @phone_number.length
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
|
|
2
|
+
module PduSms
|
|
3
|
+
|
|
4
|
+
class PacketDataUnit
|
|
5
|
+
|
|
6
|
+
attr_reader(:sca,:service_center_address,:pdu_type,:mr,:message_reference,:da,:destination_address,
|
|
7
|
+
:pid,:protocol_identifier,:dcs,:data_coding_scheme,:vp,:validity_period,:udl,:user_data_length,:ud,:user_data,
|
|
8
|
+
:oa,:originating_address,:scts,:service_center_time_stamp)
|
|
9
|
+
|
|
10
|
+
def initialize(sca: false, pdu_type: false, mr: false, da: false, pid: false, dcs: false, vp: false, udl: false, ud: false, oa: false, scts: false)
|
|
11
|
+
raise ArgumentError, 'sca parameter should contain an object of class ServiceCenterAddress' unless ServiceCenterAddress == sca.class
|
|
12
|
+
raise ArgumentError, 'pdu_type parameter should contain an object of class PDUType' unless PDUType == pdu_type.class
|
|
13
|
+
raise ArgumentError, 'mr parameter should contain an object of class MessageReference' unless mr == false or MessageReference == mr.class
|
|
14
|
+
raise ArgumentError, 'da parameter should contain an object of class DestinationAddress' unless da == false or DestinationAddress == da.class
|
|
15
|
+
raise ArgumentError, 'pid parameter should contain an object of class ProtocolIdentifier' unless ProtocolIdentifier == pid.class
|
|
16
|
+
raise ArgumentError, 'dcs parameter should contain an object of class DataCodingScheme' unless DataCodingScheme == dcs.class
|
|
17
|
+
raise ArgumentError, 'vp parameter should contain an object of class ValidityPeriod' unless vp == false or ValidityPeriod == vp.class
|
|
18
|
+
raise ArgumentError, 'udl parameter should contain an object of class UserDataLength' unless UserDataLength == udl.class
|
|
19
|
+
raise ArgumentError, 'ud parameter should contain an object of class UserData' unless UserData == ud.class
|
|
20
|
+
raise ArgumentError, 'oa parameter should contain an object of class OriginatingAddress' unless oa == false or OriginatingAddress == oa.class
|
|
21
|
+
raise ArgumentError, 'scts parameter should contain an object of class ServiceCenterTimeStamp' unless scts == false or ServiceCenterTimeStamp == scts.class
|
|
22
|
+
@sca = @service_center_address = sca
|
|
23
|
+
@pdu_type = pdu_type
|
|
24
|
+
@mr = @message_reference = mr
|
|
25
|
+
@da = @destination_address = da
|
|
26
|
+
@pid = @protocol_identifier = pid
|
|
27
|
+
@dcs = @data_coding_scheme = dcs
|
|
28
|
+
@vp = @validity_period = vp
|
|
29
|
+
@udl = @user_data_length = udl
|
|
30
|
+
@ud = @user_data = ud
|
|
31
|
+
@oa = @originating_address = oa
|
|
32
|
+
@scts = @service_center_time_stamp = scts
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def PacketDataUnit.encode_ms(phone, message, coding: :auto, phone_npi: false, phone_ton: false, sca: false, sca_npi: false, sca_ton: false, rp: REPLY_PATH_0, srr: STATUS_REPORT_REQUEST_0, vp: false, rd: REJECT_DUPLICATES_0, message_class: false, compressed: UNCOMPRESSED)
|
|
36
|
+
user_data_array = UserData.encode_ms(message, coding)
|
|
37
|
+
user_data_array.collect.each_with_index do |user_data, current_num_pdu|
|
|
38
|
+
service_center_address = ServiceCenterAddress.encode_ms(sca, sca_npi, sca_ton)
|
|
39
|
+
destination_address = DestinationAddress.encode_ms(phone, phone_npi, phone_ton)
|
|
40
|
+
protocol_identifier = ProtocolIdentifier.encode_ms
|
|
41
|
+
message_reference = MessageReference.encode_ms(current_num_pdu)
|
|
42
|
+
validity_period = ValidityPeriod.encode_ms(vp)
|
|
43
|
+
pdu_type = PDUType.encode_ms(rp:rp, srr:srr, rd:rd, udhi: user_data.get_udh, vpf: validity_period.is_setup)
|
|
44
|
+
data_coding_scheme = DataCodingScheme.encode_ms(compressed: compressed, message_class: message_class, alphabet: user_data.get_coding)
|
|
45
|
+
user_data_length = UserDataLength.encode_ms(user_data)
|
|
46
|
+
new(sca: service_center_address, pdu_type: pdu_type, mr: message_reference, da: destination_address, pid: protocol_identifier, dcs: data_coding_scheme, vp: validity_period, udl: user_data_length, ud: user_data).freeze
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def PacketDataUnit.decode_ms(pdu)
|
|
51
|
+
service_center_address = ServiceCenterAddress.decode_ms(pdu)
|
|
52
|
+
pdu_type = PDUType.decode_ms(pdu)
|
|
53
|
+
message_reference = MessageReference.decode_ms(pdu)
|
|
54
|
+
destination_address = DestinationAddress.decode_ms(pdu)
|
|
55
|
+
protocol_identifier = ProtocolIdentifier.decode_ms(pdu)
|
|
56
|
+
data_coding_scheme = DataCodingScheme.decode_ms(pdu)
|
|
57
|
+
validity_period = ValidityPeriod.decode_ms(pdu)
|
|
58
|
+
user_data_length = UserDataLength.decode_ms(pdu)
|
|
59
|
+
user_data = UserData.decode_ms(pdu)
|
|
60
|
+
new(sca: service_center_address, pdu_type: pdu_type, mr: message_reference, da: destination_address, pid: protocol_identifier, dcs: data_coding_scheme, vp: validity_period, udl: user_data_length, ud: user_data).freeze
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def PacketDataUnit.encode_sc(sca, phone, message, coding: :auto, sca_npi: false, sca_ton: false, phone_npi: false, phone_ton: false, rp: REPLY_PATH_0, sri: STATUS_REPORT_INDICATION_0, mms: MORE_MESSAGES_TO_SEND_0, message_class: false, compressed: UNCOMPRESSED, scts: Time.now.getutc.to_i)
|
|
64
|
+
user_data_array = UserData.encode_sc(message, coding)
|
|
65
|
+
user_data_array.collect do |user_data|
|
|
66
|
+
service_center_address = ServiceCenterAddress.encode_sc(sca, sca_npi, sca_ton)
|
|
67
|
+
pdu_type = PDUType.encode_sc(rp: rp, udhi: user_data.get_udh, sri: sri, mms: mms)
|
|
68
|
+
originating_address = OriginatingAddress.encode_sc(phone, phone_npi, phone_ton)
|
|
69
|
+
protocol_identifier = ProtocolIdentifier.encode_sc
|
|
70
|
+
data_coding_scheme = DataCodingScheme.encode_sc(compressed: compressed, message_class: message_class, alphabet: user_data.get_coding)
|
|
71
|
+
service_center_time_stamp = ServiceCenterTimeStamp.encode_sc(scts)
|
|
72
|
+
user_data_length = UserDataLength.encode_sc(user_data)
|
|
73
|
+
new(sca: service_center_address, pdu_type: pdu_type, pid: protocol_identifier, dcs: data_coding_scheme, udl: user_data_length, ud: user_data, oa: originating_address, scts: service_center_time_stamp).freeze
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def PacketDataUnit.decode_sc(pdu)
|
|
78
|
+
service_center_address = ServiceCenterAddress.decode_sc(pdu)
|
|
79
|
+
pdu_type = PDUType.decode_sc(pdu)
|
|
80
|
+
originating_address = OriginatingAddress.decode_sc(pdu)
|
|
81
|
+
protocol_identifier = ProtocolIdentifier.decode_sc(pdu)
|
|
82
|
+
data_coding_scheme = DataCodingScheme.decode_sc(pdu)
|
|
83
|
+
service_center_time_stamp = ServiceCenterTimeStamp.decode_sc(pdu)
|
|
84
|
+
user_data_length = UserDataLength.decode_sc(pdu)
|
|
85
|
+
user_data = UserData.decode_sc(pdu)
|
|
86
|
+
new(sca: service_center_address, pdu_type: pdu_type, pid: protocol_identifier, dcs: data_coding_scheme, udl: user_data_length, ud: user_data, oa: originating_address, scts: service_center_time_stamp).freeze
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def PacketDataUnit.decode(pdu)
|
|
90
|
+
pdu_type = PDUType.decode(pdu)
|
|
91
|
+
if pdu_type.message_type_indicator_in?
|
|
92
|
+
decode_sc(pdu)
|
|
93
|
+
elsif pdu_type.message_type_indicator_out?
|
|
94
|
+
decode_ms(pdu)
|
|
95
|
+
else
|
|
96
|
+
raise ArgumentError, 'failed to recognize the type of package'
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def get_hex
|
|
101
|
+
if @pdu_type.message_type_indicator_out?
|
|
102
|
+
'' << @sca.get_hex << @pdu_type.get_hex << @mr.get_hex << @da.get_hex << @pid.get_hex << @dcs.get_hex << @vp.get_hex << @udl.get_hex << @ud.get_hex
|
|
103
|
+
elsif @pdu_type.message_type_indicator_in?
|
|
104
|
+
'' << @sca.get_hex << @pdu_type.get_hex << @oa.get_hex << @pid.get_hex << @dcs.get_hex << @scts.get_hex << @udl.get_hex << @ud.get_hex
|
|
105
|
+
else
|
|
106
|
+
raise PacketDataUnitError, 'oops SMS-SUBMIT not supported by this version of the library'
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def get_message
|
|
111
|
+
@ud.get_message
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def get_phone_number
|
|
115
|
+
if @pdu_type.message_type_indicator_out?
|
|
116
|
+
@da.get_phone_number
|
|
117
|
+
elsif @pdu_type.message_type_indicator_in?
|
|
118
|
+
@oa.get_phone_number
|
|
119
|
+
else
|
|
120
|
+
raise PacketDataUnitError, 'oops SMS-SUBMIT not supported by this version of the library'
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
module PduSms
|
|
2
|
+
class PDUType
|
|
3
|
+
|
|
4
|
+
def initialize(type, rp: REPLY_PATH_0, udhi: USER_DATA_HEADER_INCLUDED_0, mti: MESSAGE_TYPE_INDICATOR_01, vpf: false, srr: false, sri: false, rd: false, mms: false)
|
|
5
|
+
raise ArgumentError, 'The "rp" is incorrect' unless (REPLY_PATH_0..REPLY_PATH_1).include?(rp)
|
|
6
|
+
raise ArgumentError, 'The "udhi" is incorrect' unless (USER_DATA_HEADER_INCLUDED_0..USER_DATA_HEADER_INCLUDED_1).include?(udhi)
|
|
7
|
+
raise ArgumentError, 'The "mti" is incorrect' unless (MESSAGE_TYPE_INDICATOR_00..MESSAGE_TYPE_INDICATOR_11).include?(mti)
|
|
8
|
+
if mti == MESSAGE_TYPE_INDICATOR_01
|
|
9
|
+
raise ArgumentError, 'The "srr" is incorrect' unless (STATUS_REPORT_REQUEST_0..STATUS_REPORT_REQUEST_1).include?(srr)
|
|
10
|
+
raise ArgumentError, 'The "vpf" is incorrect' unless (VALIDITY_PERIOD_FORMAT_00..VALIDITY_PERIOD_FORMAT_11).include?(vpf)
|
|
11
|
+
raise ArgumentError, 'The "rd" is incorrect' unless (REJECT_DUPLICATES_0..REJECT_DUPLICATES_1).include?(rd)
|
|
12
|
+
elsif mti == MESSAGE_TYPE_INDICATOR_00
|
|
13
|
+
raise ArgumentError, 'The "sri" is incorrect' unless (STATUS_REPORT_INDICATION_0..STATUS_REPORT_INDICATION_1).include?(sri)
|
|
14
|
+
raise ArgumentError, 'The "mms" is incorrect' unless (MORE_MESSAGES_TO_SEND_0..MORE_MESSAGES_TO_SEND_1).include?(mms)
|
|
15
|
+
end
|
|
16
|
+
@rp = rp
|
|
17
|
+
@udhi = udhi
|
|
18
|
+
@srr = srr
|
|
19
|
+
@vpf = vpf
|
|
20
|
+
@rd = rd
|
|
21
|
+
@mti = mti
|
|
22
|
+
@mms = mms
|
|
23
|
+
@sri = sri
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def PDUType.encode(rp: REPLY_PATH_0, udhi: USER_DATA_HEADER_INCLUDED_0, srr: STATUS_REPORT_REQUEST_0, vpf: VALIDITY_PERIOD_FORMAT_00, rd: REJECT_DUPLICATES_0, mti: MESSAGE_TYPE_INDICATOR_01, sri: STATUS_REPORT_INDICATION_0, mms:MORE_MESSAGES_TO_SEND_0)
|
|
27
|
+
if mti == MESSAGE_TYPE_INDICATOR_01
|
|
28
|
+
PDUType.encode_ms(rp:rp,udhi:udhi, srr:srr, vpf:vpf, rd:rd)
|
|
29
|
+
elsif mti == MESSAGE_TYPE_INDICATOR_00
|
|
30
|
+
PDUType.encode_sc(rp:rp, udhi:udhi, sri:sri, mms:mms)
|
|
31
|
+
elsif mti == MESSAGE_TYPE_INDICATOR_10
|
|
32
|
+
raise PacketDataUnitError, 'oops SMS-SUBMIT not supported by this version of the library'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def PDUType.decode(pdu_str)
|
|
37
|
+
pdu = '%08b' % PDUType.cut_off_pdu(pdu_str, :current, :ms)
|
|
38
|
+
mti = pdu[6..7].to_i(2)
|
|
39
|
+
if mti == MESSAGE_TYPE_INDICATOR_00
|
|
40
|
+
PDUType.decode_sc(pdu_str)
|
|
41
|
+
elsif mti == MESSAGE_TYPE_INDICATOR_01
|
|
42
|
+
PDUType.decode_ms(pdu_str)
|
|
43
|
+
elsif mti == MESSAGE_TYPE_INDICATOR_10
|
|
44
|
+
raise PacketDataUnitError, 'oops SMS-SUBMIT not supported by this version of the library'
|
|
45
|
+
else
|
|
46
|
+
raise PacketDataUnitError, 'format error'
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def PDUType.encode_ms(rp: REPLY_PATH_0, udhi: USER_DATA_HEADER_INCLUDED_0, srr: STATUS_REPORT_REQUEST_0, vpf: VALIDITY_PERIOD_FORMAT_00, rd: REJECT_DUPLICATES_0)
|
|
51
|
+
new(:encode_ms, rp:rp, udhi:udhi, srr:srr, vpf:vpf, rd:rd, mti:MESSAGE_TYPE_INDICATOR_01).freeze
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def PDUType.decode_ms(pdu_str)
|
|
55
|
+
pdu = '%08b' % PDUType.cut_off_pdu(pdu_str, :current, :ms).to_i(16)
|
|
56
|
+
raise ArgumentError, 'wrong format "PDU" package' if pdu[6..7].to_i(2) != MESSAGE_TYPE_INDICATOR_01
|
|
57
|
+
new(:decode_ms, rp:pdu[0].to_i(2), udhi:pdu[1].to_i(2), srr:pdu[2].to_i(2), vpf:pdu[3..4].to_i(2), rd:pdu[5].to_i(2), mti:MESSAGE_TYPE_INDICATOR_01).freeze
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def PDUType.encode_sc(rp: REPLY_PATH_0, udhi: USER_DATA_HEADER_INCLUDED_0, sri: STATUS_REPORT_INDICATION_0, mms:MORE_MESSAGES_TO_SEND_0)
|
|
61
|
+
new(:encode_ms, rp:rp, udhi:udhi, sri:sri, mms:mms, mti:MESSAGE_TYPE_INDICATOR_00).freeze
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def PDUType.decode_sc(pdu_str)
|
|
65
|
+
pdu = '%08b' % PDUType.cut_off_pdu(pdu_str, :current, :sc).to_i(16)
|
|
66
|
+
raise ArgumentError, 'wrong format "PDU" package' if pdu[6..7].to_i(2) != MESSAGE_TYPE_INDICATOR_00
|
|
67
|
+
new(:decode_ms, rp:pdu[0].to_i(2), udhi:pdu[1].to_i(2), sri:pdu[2].to_i(2), mms:pdu[5].to_i(2), mti:MESSAGE_TYPE_INDICATOR_00).freeze
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def PDUType.cut_off_pdu(pdu, part=:all, type=:ms) # tail current
|
|
71
|
+
part_pdu = ServiceCenterAddress.cut_off_pdu(pdu, :tail)
|
|
72
|
+
raise TypeError.new('Слишком короткая строка') if part_pdu.length < 2
|
|
73
|
+
current = part_pdu[0..1]
|
|
74
|
+
tail = part_pdu[2..-1]
|
|
75
|
+
case part
|
|
76
|
+
when :current then current
|
|
77
|
+
when :tail then tail
|
|
78
|
+
else [current,tail]
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def reply_path?
|
|
83
|
+
@rp == REPLY_PATH_1
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def user_data_header_included?
|
|
87
|
+
@udhi == USER_DATA_HEADER_INCLUDED_1
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def status_report_request?
|
|
91
|
+
@srr == STATUS_REPORT_REQUEST_1
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def validity_period_format_off?
|
|
95
|
+
@vpf == VALIDITY_PERIOD_FORMAT_00
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def validity_period_format_reserve?
|
|
99
|
+
@vpf == VALIDITY_PERIOD_FORMAT_01
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def validity_period_format_relative?
|
|
103
|
+
@vpf == VALIDITY_PERIOD_FORMAT_10
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def validity_period_format_absolute?
|
|
107
|
+
@vpf == VALIDITY_PERIOD_FORMAT_11
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def reject_duplicates?
|
|
111
|
+
@rd == REJECT_DUPLICATES_1
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def message_type_indicator_in?
|
|
115
|
+
@mti == MESSAGE_TYPE_INDICATOR_00
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def message_type_indicator_out?
|
|
119
|
+
@mti == MESSAGE_TYPE_INDICATOR_01
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def message_type_indicator_report?
|
|
123
|
+
@mti == MESSAGE_TYPE_INDICATOR_10
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def message_type_indicator_reserve?
|
|
127
|
+
@mti == MESSAGE_TYPE_INDICATOR_11
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def more_messages_to_send?
|
|
131
|
+
@mms == MORE_MESSAGES_TO_SEND_1
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def status_report_indication?
|
|
135
|
+
@sri == STATUS_REPORT_INDICATION_1
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def get_reply_path
|
|
139
|
+
'%b' % @rp
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def get_user_data_header_included
|
|
143
|
+
'%b' % @udhi
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def get_status_report_request
|
|
147
|
+
'%b' % @srr
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def get_validity_period_format
|
|
151
|
+
'%02b' % @vpf
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def get_reject_duplicates
|
|
155
|
+
'%b' % @rd
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def get_message_type_indicator
|
|
159
|
+
'%02b' % @mti
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def get_status_report_indication
|
|
163
|
+
'%b' % @sri
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def get_more_messages_to_send
|
|
167
|
+
'%b' % @mms
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def get_hex
|
|
171
|
+
if message_type_indicator_out?
|
|
172
|
+
'%02x' % [('' << get_reply_path << get_user_data_header_included << get_status_report_request << get_validity_period_format << get_reject_duplicates << get_message_type_indicator).to_i(2)]
|
|
173
|
+
elsif message_type_indicator_in?
|
|
174
|
+
'%02x' % [('' << get_reply_path << get_user_data_header_included << get_status_report_indication << '00' << get_more_messages_to_send << get_message_type_indicator).to_i(2)]
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
module PduSms
|
|
2
|
+
|
|
3
|
+
class Phone
|
|
4
|
+
|
|
5
|
+
attr_reader(:number_plan_identifier, :type_number)
|
|
6
|
+
|
|
7
|
+
@phone_number = ''
|
|
8
|
+
@number_plan_identifier = false
|
|
9
|
+
@type_number = false
|
|
10
|
+
|
|
11
|
+
def get_phone_number
|
|
12
|
+
if @number_plan_identifier == ID_INTERNATIONAL
|
|
13
|
+
'+%s' % @phone_number
|
|
14
|
+
else
|
|
15
|
+
'%s' % @phone_number
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
def _auto_detect(phone_number)
|
|
22
|
+
if /^\+\d+$/ === phone_number
|
|
23
|
+
@number_plan_identifier = ID_INTERNATIONAL
|
|
24
|
+
@type_number = TP_ISDN
|
|
25
|
+
elsif /^\d+$/ === phone_number
|
|
26
|
+
@number_plan_identifier = ID_UNKNOWN
|
|
27
|
+
@type_number = TP_ISDN
|
|
28
|
+
elsif is_7bit?(phone_number)
|
|
29
|
+
@number_plan_identifier = ID_ALPHANUMERIC
|
|
30
|
+
@type_number = TP_UNKNOWN
|
|
31
|
+
else
|
|
32
|
+
raise PacketDataUnitError, 'Could not automatically determine the type of phone number'
|
|
33
|
+
end
|
|
34
|
+
self
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def _check_phone?
|
|
38
|
+
if @number_plan_identifier == ID_ALPHANUMERIC
|
|
39
|
+
is_7bit?(@phone_number)
|
|
40
|
+
else
|
|
41
|
+
/^\d+$/ === @phone_number
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def _get_hex_type_and_phone
|
|
46
|
+
if @number_plan_identifier == ID_ALPHANUMERIC
|
|
47
|
+
'%s%s' % [_type_of_address_hex, encode_7bit(@phone_number)]
|
|
48
|
+
else
|
|
49
|
+
'%s%s' % [_type_of_address_hex, _convert_to_bcd_format]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def _set_phone_number(phone_number, number_play_identifier=false, type_number=false)
|
|
54
|
+
if number_play_identifier == false or type_number == false
|
|
55
|
+
_auto_detect(phone_number)
|
|
56
|
+
else
|
|
57
|
+
raise ArgumentError, 'Incorrect type of phone number' unless (TP_UNKNOWN..TP_RESERVED).include?(type_number)
|
|
58
|
+
raise ArgumentError, 'Invalid type id telephone' unless (ID_UNKNOWN..ID_RESERVED).include?(number_play_identifier)
|
|
59
|
+
@type_number = type_number
|
|
60
|
+
@number_plan_identifier = number_play_identifier
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
if @number_plan_identifier == ID_INTERNATIONAL and phone_number[0] == '+'
|
|
64
|
+
@phone_number = phone_number[1..-1]
|
|
65
|
+
else
|
|
66
|
+
@phone_number = phone_number
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
unless _check_phone?
|
|
70
|
+
@phone_number = ''
|
|
71
|
+
raise ArgumentError, 'Phone number is invalid'
|
|
72
|
+
end
|
|
73
|
+
self
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def _set_hex_type_and_phone(bcd)
|
|
79
|
+
_convert_to_normal_format bcd
|
|
80
|
+
unless _check_phone?
|
|
81
|
+
@phone_number = ''
|
|
82
|
+
raise ArgumentError, 'Phone number is invalid'
|
|
83
|
+
end
|
|
84
|
+
self
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def _convert_to_bcd_format
|
|
88
|
+
if @phone_number[0] == ?+
|
|
89
|
+
clear_phone = @phone_number[1..-1]
|
|
90
|
+
else
|
|
91
|
+
clear_phone = @phone_number
|
|
92
|
+
end
|
|
93
|
+
if clear_phone.length % 2 != 0
|
|
94
|
+
clear_phone += 'F'
|
|
95
|
+
end
|
|
96
|
+
encode_bcd(clear_phone)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def _convert_to_normal_format(bcd)
|
|
100
|
+
@phone_number = ''
|
|
101
|
+
if bcd.length < 4
|
|
102
|
+
raise ArgumentError, 'Wrong format'
|
|
103
|
+
end
|
|
104
|
+
raise ArgumentError, 'Incorrect number plan identifier' unless (128..255).include?(bcd[0..1].to_i(16))
|
|
105
|
+
number_type = '%08b' % bcd[0..1].to_i(16)
|
|
106
|
+
@number_plan_identifier = number_type[1..3].to_i(2)
|
|
107
|
+
@type_number = number_type[4..7].to_i(2)
|
|
108
|
+
if @number_plan_identifier == ID_ALPHANUMERIC
|
|
109
|
+
@phone_number = decode_7bit(bcd[2..-1])
|
|
110
|
+
else
|
|
111
|
+
@phone_number = decode_bcd(bcd[2..-1])[/[fF]$/] ? decode_bcd(bcd[2..-1])[0..-2] : decode_bcd(bcd[2..-1])
|
|
112
|
+
end
|
|
113
|
+
self
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def _type_of_address_hex
|
|
117
|
+
'%02x' % ('1%03b%04b' % [@number_plan_identifier, @type_number]).to_i(2)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
end
|
|
121
|
+
end
|