forked from alexsilva/luabit-legacy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
noki.lua
332 lines (287 loc) · 7.64 KB
/
noki.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
--[[---------------
Noki v0.4
-------------------
Noki is a toolkit to convert Nokia PC Suite backuped SMS to a
unicode .txt file, which is more accessible than the original
.nfb or .nfc.
It works well for Nokia PC Suite 6.5.12 and my mobile phone is
Nokia 7360. There might be some compatibility problem if you
use earlier version of the PC Suite.
How to use:
noki.save_sms('nokia.nfb', 'sms.txt')
Under the MIT license.
Noki is a part of LuaBit(http://luaforge.net/projects/bit/).
copyright(c) 2006~2007 hanzhao (abrash_han@hotmail.com)
--]]---------------
require 'hex'
require 'bit'
do
-- globals
local RETURN = '\13\0\10\0'
local SMS_FILE = '\\MPAPI\\MESSAGES'
local SMS_INBOX = 'PIT_MESSAGE_INBOX'
local SMS_OUTBOX = 'PIT_MESSAGE_OUTBOX'
local SMS_ARCHIVEBOX = 'PIT_MESSAGE_ARCHIVE'
-- output decorator
local SMS_INBOX_DEC = '[INBOX] '
local SMS_OUTBOX_DEC = '[OUTBOX] '
local SMS_ARCHIVE_DEC = '[ARCHIVE] '
-- box type
local BoxType = {
NON = 0,
IN = 1,
OUT = 2,
ARCHIVE = 3,
}
-- feed each char with an extra \0
local function asci_to_uni(asci)
--print("-------")
local uni = ""
for i = 1, string.len(asci) do
local str = string.format('%c\0', string.byte(asci, i))
--print(string.len(str))
uni = uni .. str
end
return uni
end
local function asci_padding(asci, pad)
local uni = ""
for i = 1, string.len(asci) do
local str = string.format('%c', string.byte(asci, i))
--print(string.len(str))
uni = uni .. str .. pad
end
return uni
end
-- shrink the \0 in uni code string
local function uni_to_asci(uni)
local asci = ''
--print('uni len ' .. string.len(uni))
for i = 1, string.len(uni), 2 do
asci = asci .. string.sub(uni, i, i)
end
return asci
end
local function reader(str)
local index = 1
return function (n)
--print('reader>>> idx ' .. index .. " n " .. n)
local sub = string.sub(str, index, index + n - 1)
--[[print(hex.to_hex(string.byte(sub, 1)))
print(hex.to_hex(string.byte(sub, 2)))
print(hex.to_hex(string.byte(sub, 3)))
print(hex.to_hex(string.byte(sub, 4)))
--]]
index = index + n
return sub
end
end
local function read_number(read, n)
local str = read(n)
local rslt = 0
for i = 1, n do
local v = string.byte(str, i)
rslt = bit.bor(rslt, bit.blshift(v, (i-1)*8))
end
return rslt
end
local function read_int(read)
return read_number(read, 4)
end
local function read_short(read)
return read_number(read, 2)
end
local function read_nfb_string(read)
local len = read_int(read)
local unistr = read(len*2)
return unistr
end
local function read_nfb_header(read)
local nfb_header = {
ver = read_int(read),
firmware = read_nfb_string(read),
phone = read_nfb_string(read),
entries = read_int(read),
}
return nfb_header
end
local function read_nfb_file(read)
local nfbf = {}
nfbf.path = read_nfb_string(read)
nfbf.nbytes = read_int(read)
nfbf.bytes = read(nfbf.nbytes)
local stamp = read_int(read)
return nfbf
end
local function read_nfb_dir(read)
local nfbd = {
path = read_nfb_string(read)
}
return nfbd
end
local function save_entry(fp, tbl)
for k, v in pairs(tbl) do
fp:write(v)
fp:write(RETURN)
end
end
-- save sms entries
local function save_sms(fp, ctnt)
-- print("save sms ----")
local in_box = asci_padding(SMS_INBOX, "%z")
local out_box = asci_padding(SMS_OUTBOX, "%z")
local archive_box = asci_padding(SMS_ARCHIVEBOX, "%z")
local line_s = asci_padding("1020", "%z")
local head = asci_padding("1033", "%z")
local tail = asci_padding("1040", "%z")
local service_center_tail = asci_padding("1080", "%z")
local phone_nb = "%+%z%d%z%d%z[%d%z]+" -- default is type 145 with '+'
local phone_nb_129 = string.rep("%d%z", 11) -- phone number type 129 without '+'
local time = "[%d%z]+%-%z%d%z%d%z%-%z%d%z%d%zT%z%d%z%d%z:%z%d%z%d%z"
local pattern = "([^\10]+)\13%z\10%z"
local line_end = "\13%z\10%z"
local lineb, linee = string.find(ctnt, line_end)
local start = 1
local line_number = 1
while(lineb and linee) do
local line = string.sub(ctnt, start, lineb - 1)
--line = string.sub(ctnt, gb, ge)
local type = BoxType.NON
--print('capture ' .. string.len(line))
--print(uni_to_asci(box))
if(string.find(line, in_box)) then
fp:write(asci_to_uni(SMS_INBOX_DEC))
type = BoxType.IN
elseif(string.find(line, out_box)) then
fp:write(asci_to_uni(SMS_OUTBOX_DEC))
type = BoxType.OUT
elseif(string.find(line, archive_box)) then
fp:write(asci_to_uni(SMS_ARCHIVE_DEC))
type = BoxType.ARCHIVE
else
--print(uni_to_asci(line))
io.close(fp)
--error('unknown sms type')
return
end
hb, he = string.find(line, head)
tb, te = string.find(line, tail)
local first_number = ""
-- service center address
sb, se = string.find(line, phone_nb, tb)
--print("" .. sb .. ", " .. se)
if(sb and se) then
--print(uni_to_asci(string.sub(line, sb, se)))
-- keep the find number, if the second find for sender address fails
-- then this number is the sender address
first_number = string.sub(line, sb, se)
else
sb, se = string.find(line, phone_nb_129, tb)
if(not (sb and se)) then
--io.close(fp)
--error("error service center address")
--return
first_number = "empty number"
-- nokia's pc suite may leave the serivce center address empty
end
end
-- sender address
se_old = se
sb, se = string.find(line, phone_nb, se)
--print("" .. sb .. ", " .. se)
local sender_address = ""
if(sb and se) then
--print(uni_to_asci(string.sub(line, sb, se)))
sender_address = string.sub(line, sb, se)
else
sb, se = string.find(line, phone_nb_129, se_old)
if(not (sb and se)) then
--[[
print(line_number)
io.close(fp)
error("error sender address")
--]]
sender_address = first_number
end
end
-- write sender
fp:write(sender_address)
fp:write(" \0")
-- date time
-- out box have no date time slot
if(type ~= BoxType.OUT and first_number ~= "empty number") then
tmb, tme = string.find(line, time, se)
--print('' .. tmb .. ", " .. tme)
if(tmb and tme) then
--print(uni_to_asci(string.sub(line, tmb+1, tme)))
else
io.close(fp)
error("error reading date time")
return
end
fp:write(string.sub(line, tmb+1, tme))
end
fp:write(RETURN)
fp:write(string.sub(line, he+3, tb-3))
fp:write(RETURN)
fp:write(RETURN)
--end
start = linee + 1
lineb, linee = string.find(ctnt, line_end, linee)
line_number = line_number + 1
end
end
-- save sms from a .nfc or .nfb file to a unicode .txt file
local function save_nfx_to(from, too)
local fp = io.open(too, 'wb')
if(not fp) then
error("error opening file " .. too .. " to write")
return
end
v = string.format('%c%c', 255, 254)
-- unicode .txt 'FF FE'
fp:write(v)
-- read the .nfc file
local nokia = io.open(from, 'rb')
if(not nokia) then
error("error open file " .. from .. " to read")
end
local ctnt = nokia:read("*a")
io.close(nokia)
local read = reader(ctnt)
local header = read_nfb_header(read)
--print(header.ver)
--print(header.entries)
for i=1, header.entries do
--print(i)
local type = read_int(read)
if(type == 1) then
-- file entry
--print('file')
local fe = read_nfb_file(read)
--save_entry(fp, fe)
if(uni_to_asci(fe.path) == SMS_FILE) then
local smsctnt = fe.bytes
--print('sms len ' .. fe.nbytes)
save_sms(fp, smsctnt)
return
end
elseif(type == 2) then
-- dir entry
--print('dir')
local fd = read_nfb_dir(read)
--save_entry(fp, fd)
else
io.close(fp)
error('unknown entry type : ' .. hex.to_hex(type))
end
end
io.close(fp)
end
-- noki interface --
noki = {
save_sms = save_nfx_to
}
end -- end block
-- sample
-- noki.save_sms('nokia2.nfb', 'sms2.txt')