benpere

nokia_ib_parser

Sep 5th, 2024
254
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.39 KB | None | 0 0
  1. # Copyright (C) 2019 Yossi Gottlieb
  2. #
  3. # This program is free software: you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation, either version 3 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. # GNU General Public License for more details.
  12.  
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program.  If not, see <https://www.gnu.org/licenses/>.
  15.  
  16. import argparse
  17. import struct
  18.  
  19. class Entry(object):
  20.     def __init__(self, data):
  21.         header_len, = struct.unpack_from('H', data, 0)
  22.         name_offsets = {
  23.             0x01C8: 0x4A,
  24.             0x0238: 0x60,
  25.             0x0394: 0x16c
  26.         }
  27.         phone_offsets = {
  28.             0x01C8: 0x1D,
  29.             0x0238: 0x1E,
  30.             0x0394: 0x12A
  31.         }
  32.         if header_len not in name_offsets:
  33.             raise ValueError("Invalid Entry")
  34.        
  35.         name_offset = name_offsets[header_len]
  36.         # Name length
  37.         name_len = struct.unpack_from('B', data, name_offset)[0]
  38.  
  39.         # Name
  40.         start = name_offset+2
  41.         end = start + (name_len * 2)
  42.         self.name = data[start:end].decode('utf-16')
  43.         self.phone = self.__decode_phone(data, phone_offsets[header_len])
  44.  
  45.     @staticmethod
  46.     def __decode_digit(value):
  47.         if value >= 0 and value <= 9:
  48.             return str(value)
  49.         if value == 10:
  50.             return '*'
  51.         if value == 15:
  52.             return ''
  53.         if value == 11:
  54.             return '#'  # Just a guess
  55.         raise ValueError('Unknown digit value {}'.format(value))
  56.  
  57.     def __decode_phone(self, data, offset):
  58.         phone_len, extra = struct.unpack_from('bb', data, offset)
  59.         phone = ''
  60.         if extra & 0x10:
  61.             phone += '+'
  62.         for byte in data[offset+2:offset+2+phone_len]:
  63.             phone += self.__decode_digit(byte & 0x0f)
  64.             phone += self.__decode_digit(byte >> 4)
  65.         return phone
  66.  
  67.     def vcard(self):
  68.         return 'BEGIN:VCARD\nVERSION:3.0\nN:{name}\n' \
  69.                'FN:{name}\nTEL;type=HOME:{phone}\n' \
  70.                'END:VCARD\n'.format(name=self.name, phone=self.phone)
  71.  
  72.     def __str__(self):
  73.         return '<Entry name={} phone={}>'.format(self.name, self.phone)
  74.  
  75. def process(infile, outfile):
  76.     header = infile.read(0x244)
  77.     entries = 0
  78.     while True:
  79.         data_hdr = infile.read(2)
  80.         if not data_hdr:
  81.             break
  82.         entry_len, = struct.unpack('H', data_hdr)
  83.         data = data_hdr + infile.read(entry_len - len(data_hdr) + 24)
  84.         entry = Entry(data)
  85.         outfile.write(entry.vcard())
  86.         entries += 1
  87.     print('Exported {} entries.'.format(entries))
  88.  
  89. def main():
  90.     parser = argparse.ArgumentParser(
  91.         description='Nokia 3310 phonebook.ib exporter')
  92.     parser.add_argument('infile', type=argparse.FileType('rb'),
  93.                         help='Phonebook file to read')
  94.     parser.add_argument('outfile', type=argparse.FileType('w', encoding='utf8'),
  95.                         help='VCF File to write')
  96.     args = parser.parse_args()
  97.     process(args.infile, args.outfile)
  98.  
  99. if __name__ == '__main__':
  100.     main()
Advertisement
Add Comment
Please, Sign In to add comment