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.
@@ -0,0 +1,55 @@
1
+ module PduSms
2
+ class ProtocolIdentifier
3
+
4
+ def initialize(num)
5
+ if (0..255).include?(num)
6
+ @pid = num
7
+ else
8
+ raise ArgumentError, 'The "num is incorrect'
9
+ end
10
+ end
11
+
12
+ def ProtocolIdentifier.cut_off_pdu(pdu, part=:all, type=:ms)
13
+ if type == :ms
14
+ part_pdu = DestinationAddress.cut_off_pdu(pdu, :tail)
15
+ elsif type == :sc
16
+ part_pdu = OriginatingAddress.cut_off_pdu(pdu, :tail)
17
+ else
18
+ raise ArgumentError, 'Format "PDU" not valid'
19
+ end
20
+ raise ArgumentError, 'Too short packet pdu' if part_pdu.length < 2
21
+ current = part_pdu[0..1]
22
+ tail = part_pdu[2..-1]
23
+ case part
24
+ when :current then current
25
+ when :tail then tail
26
+ else [current,tail]
27
+ end
28
+ end
29
+
30
+ def ProtocolIdentifier.encode_ms(pid=PROTOCOL_IDENTIFIER)
31
+ new(pid).freeze
32
+ end
33
+
34
+ def ProtocolIdentifier.decode_ms(pdu)
35
+ new(ProtocolIdentifier.cut_off_pdu(pdu, :current, :ms).to_i(2)).freeze
36
+ end
37
+
38
+ def ProtocolIdentifier.encode_sc(pid=PROTOCOL_IDENTIFIER)
39
+ new(pid).freeze
40
+ end
41
+
42
+ def ProtocolIdentifier.decode_sc(pdu)
43
+ new(ProtocolIdentifier.cut_off_pdu(pdu, :current, :sc).to_i(2)).freeze
44
+ end
45
+
46
+ def get_hex
47
+ '%02x' % [@pid]
48
+ end
49
+
50
+ def get_pid
51
+ @pid
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,74 @@
1
+ module PduSms
2
+
3
+ class ServiceCenterAddress < Phone
4
+
5
+ def initialize(type, data=false, number_play_identifier=false, type_number=false)
6
+ if not data
7
+ @phone_number = ''
8
+ elsif type == :encode_ms
9
+ _set_phone_number data, number_play_identifier, type_number
10
+ elsif type == :decode_ms
11
+ _set_pdu_hex ServiceCenterAddress.cut_off_pdu(data, part=:current, :ms)
12
+ elsif type == :encode_sc
13
+ _set_phone_number data, number_play_identifier, type_number
14
+ elsif type == :decode_sc
15
+ _set_pdu_hex ServiceCenterAddress.cut_off_pdu(data, part=:current, :sc)
16
+ end
17
+ end
18
+
19
+ def ServiceCenterAddress.encode_ms(str_phone_number=false, number_play_identifier=false, type_number=false)
20
+ new(:encode_ms, str_phone_number, number_play_identifier, type_number).freeze
21
+ end
22
+
23
+ def ServiceCenterAddress.decode_ms(str_pdu)
24
+ new(:decode_ms, str_pdu).freeze
25
+ end
26
+
27
+ def ServiceCenterAddress.encode_sc(str_phone_number=false, number_play_identifier=false, type_number=false)
28
+ new(:encode_sc, str_phone_number, number_play_identifier, type_number).freeze
29
+ end
30
+
31
+ def ServiceCenterAddress.decode_sc(str_pdu)
32
+ new(:decode_sc, str_pdu).freeze
33
+ end
34
+
35
+ def ServiceCenterAddress.cut_off_pdu(pdu, part=:all, type=:sc) # tail current
36
+ raise ArgumentError, 'The "pdu" is incorrect' if pdu.length < 3
37
+ sca_length = pdu[0..1].to_i
38
+ if sca_length > 0
39
+ current = pdu[0..(sca_length * 2 + 1)]
40
+ tail = pdu[(sca_length * 2 + 2)..-1]
41
+ else
42
+ current = '00'
43
+ tail = pdu[2..-1]
44
+ end
45
+ case part
46
+ when :current then current
47
+ when :tail then tail
48
+ else [current,tail]
49
+ end
50
+ end
51
+
52
+ def get_hex
53
+ return '%02x' % 0x00 unless _check_phone?
54
+ '%s%s' % [_address_length_hex, _get_hex_type_and_phone]
55
+ end
56
+
57
+ private
58
+
59
+ def _set_pdu_hex(str_pdu)
60
+ if str_pdu == '00'
61
+ @phone_number = ''
62
+ else
63
+ _set_hex_type_and_phone(str_pdu[2..-1])
64
+ end
65
+ self
66
+ end
67
+
68
+ def _address_length_hex
69
+ '%02x' % (_get_hex_type_and_phone.size / 2).to_s.to_i(16)
70
+ end
71
+
72
+ end
73
+ end
74
+
@@ -0,0 +1,76 @@
1
+ require 'date'
2
+
3
+ module PduSms
4
+
5
+ class ServiceCenterTimeStamp
6
+
7
+ def initialize(type, data)
8
+ if type == :encode_sc
9
+ @scts = _absolute_timestamp data
10
+ elsif type == :decode_sc
11
+ @scts = data
12
+ else
13
+ raise ArgumentError, 'The "type" is incorrect'
14
+ end
15
+ end
16
+
17
+ def ServiceCenterTimeStamp.encode_sc(times)
18
+ new(:encode_sc, times).freeze
19
+ end
20
+
21
+ def ServiceCenterTimeStamp.decode_sc(pdu_str)
22
+ scts = ServiceCenterTimeStamp.cut_off_pdu(pdu_str, part=:current, :sс)
23
+ new(:decode_sc, scts).freeze
24
+ end
25
+
26
+ def ServiceCenterTimeStamp.cut_off_pdu(pdu, part=:all, type=:sс) # tail current
27
+ part_pdu = DataCodingScheme.cut_off_pdu(pdu, :tail, :sc)
28
+ raise ArgumentError, 'The "pdu" is incorrect' if part_pdu.length < 14
29
+ current = part_pdu[0..13]
30
+ tail = part_pdu[14..-1]
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
+ @scts
40
+ end
41
+
42
+ def get_time
43
+ _absolute_pdu @scts
44
+ end
45
+
46
+ private
47
+
48
+ def _absolute_timestamp(timestamp)
49
+ time = Time.at(timestamp).to_datetime
50
+ date_time = time.strftime('%y%m%d%H%M%S')
51
+ if time.strftime('%z').to_i >= 0
52
+ date_time += ('%02x' % (4 * time.strftime('%z')[0..2].to_i + time.strftime('%z')[3..4].to_i / 15).to_s.to_i(16))
53
+ else
54
+ tz = '%08b' % ((4 * time.strftime('%z')[0..2].to_i.abs + time.strftime('%z')[3..4].to_i / 15).to_s.to_i(16))
55
+ tz[0] = ?1
56
+ date_time += '%02x' % tz.to_i(2)
57
+ end
58
+ @scts = encode_bcd(date_time)
59
+ end
60
+
61
+ def _absolute_pdu(vp)
62
+ ss = decode_bcd(vp)
63
+ year, month, day, hours, minutes, seconds, zone_quarter = Time.now.year.to_s[0..1] + ss[0..1], ss[2..3], ss[4..5], ss[6..7], ss[8..9], ss[10..11], ss[12..13]
64
+ tz = '%08b' % zone_quarter
65
+ if tz[0] == '1'
66
+ tz[0] = ?0
67
+ zone = '-'
68
+ else
69
+ zone = '+'
70
+ end
71
+ zone += '%02i:%02i' % [(tz.to_i(2) / 4), ((tz.to_i(2) % 4) * 15)]
72
+ Time.new(year, month, day, hours, minutes, seconds, zone).to_i
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,276 @@
1
+ module PduSms
2
+ class UserData
3
+
4
+ def initialize(message, coding, ied1: false, ied2: false, ied3: false, udhl: false, iei: false, iedl: false)
5
+ @coding = _check_coding coding
6
+ @message = _check_message message, coding, ied1
7
+ @ied1 = _check_ied1 ied1, coding
8
+ @ied2 = _check_ied2 ied2
9
+ @ied3 = _check_ied3 ied3
10
+ @udhl = udhl ? udhl : _check_udhl(coding, ied1)
11
+ @iei = iei ? iei : _check_iei(coding, ied1)
12
+ @iedl = iedl ? iedl : _check_iedl(coding, ied1)
13
+ end
14
+
15
+ def UserData.encode_ms(message, coding=:auto)
16
+ message_array = [message]
17
+ coding = is_7bit?(message) ? ALPHABET_7BIT : ALPHABET_16BIT if coding == :auto
18
+ if coding == ALPHABET_7BIT
19
+ if message.length > 160
20
+ message_array = message.scan(/.{1,152}/)
21
+ ied1 = rand(65536)
22
+ end
23
+ elsif coding == ALPHABET_8BIT
24
+ if message.length > 140
25
+ message_array = message.scan(/.{1,133}/)
26
+ ied1 = rand(65536)
27
+ end
28
+ elsif coding == ALPHABET_16BIT
29
+ if message.length > 70
30
+ message_array = message.scan(/.{1,67}/)
31
+ ied1 = rand(256)
32
+ end
33
+ else
34
+ raise ArgumentError, 'The "coding" is incorrect'
35
+ end
36
+ message_array.collect.each_with_index do |mess, current_message|
37
+ if message_array.length > 1
38
+ new(mess, coding, ied1:ied1, ied2:message_array.length, ied3:current_message+1).freeze
39
+ else
40
+ new(mess, coding).freeze
41
+ end
42
+ end
43
+ end
44
+
45
+ def UserData.decode_ms(pdu_str)
46
+ header, message = UserData.cut_off_pdu(pdu_str, :all, :ms)
47
+ dcs = DataCodingScheme.decode_ms(pdu_str)
48
+ if dcs.alphabet_7bit?
49
+ coding = dcs.get_alphabet.to_i(2)
50
+ message = decode_7bit(message)
51
+ elsif dcs.alphabet_8bit?
52
+ coding = dcs.get_alphabet.to_i(2)
53
+ message = decode_8bit(message)
54
+ elsif dcs.alphabet_16bit?
55
+ coding = dcs.get_alphabet.to_i(2)
56
+ message = decode_ucs2(message)
57
+ else
58
+ raise ArgumentError, 'The "pdu_str" is incorrect'
59
+ end
60
+ if header.empty?
61
+ new(message, coding).freeze
62
+ else
63
+ if header[4..5].to_i(16) == 4
64
+ new(message, coding, udhl: header[0..1].to_i(16), iei: header[2..3].to_i(16), iedl: header[4..5].to_i(16), ied1: header[6..9].to_i(16), ied2: header[10..11].to_i(16), ied3: header[12..13].to_i(16)).freeze
65
+ elsif header[4..5].to_i(16) == 3
66
+ new(message, coding, udhl: header[0..1].to_i(16), iei: header[2..3].to_i(16), iedl: header[4..5].to_i(16), ied1: header[6..7].to_i(16), ied2: header[8..9].to_i(16), ied3: header[10..11].to_i(16)).freeze
67
+ end
68
+ end
69
+ end
70
+
71
+ def UserData.encode_sc(message, coding=:auto)
72
+ UserData.encode_ms(message, coding)
73
+ end
74
+
75
+ def UserData.decode_sc(pdu_str)
76
+ header, message = UserData.cut_off_pdu(pdu_str, :all, :sc)
77
+ dcs = DataCodingScheme.decode_sc(pdu_str)
78
+ if dcs.alphabet_7bit?
79
+ coding = dcs.get_alphabet.to_i(2)
80
+ message = decode_7bit(message)
81
+ elsif dcs.alphabet_8bit?
82
+ coding = dcs.get_alphabet.to_i(2)
83
+ message = decode_8bit(message)
84
+ elsif dcs.alphabet_16bit?
85
+ coding = dcs.get_alphabet.to_i(2)
86
+ message = decode_ucs2(message)
87
+ else
88
+ raise ArgumentError, 'The "pdu_str" is incorrect'
89
+ end
90
+ if header.empty?
91
+ new(message, coding).freeze
92
+ else
93
+ if header[4..5].to_i(16) == 4
94
+ new(message, coding, udhl: header[0..1].to_i(16), iei: header[2..3].to_i(16), iedl: header[4..5].to_i(16), ied1: header[6..9].to_i(16), ied2: header[10..11].to_i(16), ied3: header[12..13].to_i(16)).freeze
95
+ elsif header[4..5].to_i(16) == 3
96
+ new(message, coding, udhl: header[0..1].to_i(16), iei: header[2..3].to_i(16), iedl: header[4..5].to_i(16), ied1: header[6..7].to_i(16), ied2: header[8..9].to_i(16), ied3: header[10..11].to_i(16)).freeze
97
+ end
98
+ end
99
+ end
100
+
101
+ def UserData.cut_off_pdu(pdu, part=:all, type=:ms) # tail current
102
+ part_pdu = UserDataLength.cut_off_pdu(pdu, :tail, type)
103
+ pdu_type = PDUType.decode(pdu)
104
+ raise ArgumentError, 'The "pdu_str" is incorrect' if part_pdu.length < 2
105
+ if pdu_type.user_data_header_included?
106
+ current = part_pdu[0..(part_pdu[0..1].to_i(16) * 2 + 1)]
107
+ tail = part_pdu[(part_pdu[0..1].to_i(16) * 2 + 2)..-1]
108
+ else
109
+ current = ''
110
+ tail = part_pdu[0..-1]
111
+ end
112
+ case part
113
+ when :current then current
114
+ when :tail then tail
115
+ else [current,tail]
116
+ end
117
+ end
118
+
119
+ def get_message
120
+ @message
121
+ end
122
+
123
+ def get_coding
124
+ @coding
125
+ end
126
+
127
+ def is_udh?
128
+ @ied1 ? true : false
129
+ end
130
+
131
+ def get_udh
132
+ if is_udh?
133
+ USER_DATA_HEADER_INCLUDED_1
134
+ else
135
+ USER_DATA_HEADER_INCLUDED_0
136
+ end
137
+ end
138
+
139
+ def get_ied1
140
+ return '' unless @ied1
141
+ case @coding
142
+ when ALPHABET_7BIT then '%04x' % @ied1
143
+ when ALPHABET_8BIT then '%04x' % @ied1
144
+ when ALPHABET_16BIT then '%02x' % @ied1
145
+ else raise 'unknown encoding'
146
+ end
147
+ end
148
+
149
+ def get_ied2
150
+ return '' unless @ied2
151
+ '%02x' % @ied2
152
+ end
153
+
154
+ def get_ied3
155
+ return '' unless @ied3
156
+ '%02x' % @ied3
157
+ end
158
+
159
+ def get_udhl
160
+ return '' unless @udhl
161
+ '%02x' % @udhl
162
+ end
163
+
164
+ def get_iei
165
+ return '' unless @iei
166
+ '%02x' % @iei
167
+ end
168
+
169
+ def get_iedl
170
+ return '' unless @iedl
171
+ '%02x' % @iedl
172
+ end
173
+
174
+ def get_hex
175
+ message = case @coding
176
+ when ALPHABET_7BIT
177
+ encode_7bit(@message)
178
+ when ALPHABET_8BIT
179
+ encode_8bit(@message)
180
+ when ALPHABET_16BIT
181
+ encode_ucs2(@message)
182
+ end
183
+ '%s%s%s%s%s%s%s' % [get_udhl, get_iei, get_iedl, get_ied1, get_ied2, get_ied3, message]
184
+ end
185
+
186
+ private
187
+
188
+ def _check_message(message, coding, ied1=false)
189
+ raise ArgumentError, 'The "coding" is incorrect' unless message.class == String and message.encoding.to_s == 'UTF-8'
190
+ case coding
191
+ when ALPHABET_7BIT
192
+ raise ArgumentError, 'The message is too long' if (ied1 and message.length > 152) or message.length > 160
193
+ when ALPHABET_8BIT
194
+ raise ArgumentError, 'The message is too long' if (ied1 and message.length > 133) or message.length > 140
195
+ when ALPHABET_16BIT
196
+ raise ArgumentError, 'The message is too long' if (ied1 and message.length > 67) or message.length > 70
197
+ else
198
+ raise ArgumentError, 'Unknown encoding'
199
+ end
200
+ message
201
+ end
202
+
203
+ def _check_coding(coding)
204
+ raise ArgumentError, 'Unknown encoding' unless (ALPHABET_7BIT..ALPHABET_16BIT).include?(coding)
205
+ coding
206
+ end
207
+
208
+ def _check_ied1(ied1, coding)
209
+ return false unless ied1
210
+ case coding
211
+ when ALPHABET_7BIT
212
+ raise ArgumentError, 'The message is too long' unless (0..65535).include?(ied1)
213
+ when ALPHABET_8BIT
214
+ raise ArgumentError, 'The message is too long' unless (0..65535).include?(ied1)
215
+ when ALPHABET_16BIT
216
+ raise ArgumentError, 'The message is too long' unless (0..255).include?(ied1)
217
+ else
218
+ false
219
+ end
220
+ ied1
221
+ end
222
+
223
+ def _check_ied2(ied2)
224
+ raise ArgumentError, 'The "coding" is incorrect' unless ied2 == false or (0..255).include?(ied2)
225
+ ied2
226
+ end
227
+
228
+ def _check_ied3(ied3)
229
+ raise ArgumentError, 'The "coding" is incorrect' unless ied3 == false or (0..255).include?(ied3)
230
+ ied3
231
+ end
232
+
233
+ def _check_udhl(coding, ied1)
234
+ return false unless ied1
235
+ case coding
236
+ when ALPHABET_7BIT
237
+ 0x06
238
+ when ALPHABET_8BIT
239
+ 0x06
240
+ when ALPHABET_16BIT
241
+ 0x05
242
+ else
243
+ false
244
+ end
245
+ end
246
+
247
+ def _check_iei(coding, ied1)
248
+ return false unless ied1
249
+ case coding
250
+ when ALPHABET_7BIT
251
+ 0x08
252
+ when ALPHABET_8BIT
253
+ 0x08
254
+ when ALPHABET_16BIT
255
+ 0x00
256
+ else
257
+ false
258
+ end
259
+ end
260
+
261
+ def _check_iedl(coding, ied1)
262
+ return false unless ied1
263
+ case coding
264
+ when ALPHABET_7BIT
265
+ 0x04
266
+ when ALPHABET_8BIT
267
+ 0x04
268
+ when ALPHABET_16BIT
269
+ 0x03
270
+ else
271
+ false
272
+ end
273
+ end
274
+
275
+ end
276
+ end