ContactRescue.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #!/usr/bin/python3
  2. # coding=utf-8
  3. # Doc
  4. # Script to extract Contacts from Sailfish Contact SQLite DB located at
  5. #
  6. #
  7. # Links
  8. # FileFormatdescription: https://docs.fileformat.com/email/vcf/#vcf-30-example
  9. # Pytho vobject: http://eventable.github.io/vobject/
  10. # Version
  11. version=0.2
  12. # ChangeLog
  13. # 2021-08-03 - 0.1 - multiple E-Mails with different types are working correctly
  14. # 2021-08-09 - 0.2 - Phonenumbers with parameters, Addresses with parameters, E-Mail-Addresses with marameters
  15. import sqlite3
  16. import vobject
  17. import uuid
  18. import argparse
  19. def DEBUG(debug,msg):
  20. if debug is True:
  21. print("..DEBUG: " + msg)
  22. parser = argparse.ArgumentParser(description='Restore SailfishOS 3 Contacts', epilog='This script was written to restore SailfishOS 3 contacts as VCF files. To see additional information, visit: https://wiki.siningsoft.de/doku.php?id=sailfishos:projects:sailfish_contacts_rescue' )
  23. parser.add_argument('--db','-d', required=True, help="Sqlite3 Database file usually /home/{nemo,defaultuser)/.local/share/system/Contacts/qtcontacts-sqlite/contacts.db")
  24. parser.add_argument('--output','-o',required=True, help="Output directory for vcf files")
  25. parser.add_argument('--debug',action="store_true",help="debugging output to identify problems")
  26. parser.add_argument('--version', action='version', version='%(prog)s ' + str(version))
  27. args = parser.parse_args()
  28. SQLconn = sqlite3.connect(args.db)
  29. try:
  30. SQLContCur = SQLconn.cursor()
  31. for row in SQLContCur.execute('SELECT * FROM Contacts'):
  32. # contactID abfragen
  33. contactID=row[0]
  34. familyN=row[6]
  35. givenN=row[4]
  36. fullN=row[1]
  37. cardfile=args.output + "/" + fullN.replace(" ","_") + ".vcf"
  38. # wir erstellen das Objekt
  39. vcf = vobject.vCard()
  40. vcf.add('uid').value = str(uuid.uuid4())
  41. #vcf.add('uid').value = "Testdaten"
  42. vcf.add('n').value = vobject.vcard.Name( family=familyN, given=givenN )
  43. vcf.add('fn').value =fullN
  44. print("exporting " + fullN + " to file " + cardfile)
  45. DEBUG(args.debug,"Contact " + fullN)
  46. # abfrage der Adressdaten
  47. SQLADRCur = SQLconn.cursor()
  48. for ADRrow in SQLADRCur.execute('SELECT * FROM Addresses JOIN Details on Details.detailId = Addresses.detailId where Addresses.contactId = ' + str(contactID)):
  49. if ADRrow[2] is not None:
  50. ADRstr=str(ADRrow[2])
  51. else:
  52. ADRstr=""
  53. if ADRrow[5] is not None:
  54. ADRcit=str(ADRrow[5])
  55. else:
  56. ADRcit=""
  57. if ADRrow[4] is not None:
  58. ADRreg=str(ADRrow[4])
  59. else:
  60. ADRreg=""
  61. if ADRrow[6] is not None:
  62. ADRcod=str(ADRrow[6])
  63. else:
  64. ADRcod=""
  65. if ADRrow[7] is not None:
  66. ADRcou=str(ADRrow[7])
  67. else:
  68. ADRcou=""
  69. DEBUG(args.debug,"Addressdata: street=" + ADRstr + " city=" + ADRcit + " region=" + ADRreg + " code=" + ADRcod + " country=" + ADRcou)
  70. adr = vcf.add('ADR').value = vobject.vcard.Address(street=ADRstr, city=ADRcit, region=ADRreg, code=ADRcod,country=ADRcou)
  71. ## Abfragen Organisation
  72. SQLORGCur = SQLconn.cursor()
  73. for ORGrow in SQLORGCur.execute('SELECT * from Organizations where contactId = ' + str(contactID)):
  74. org = vcf.add('ORG').value = [str(ORGrow[2]), str(ORGrow[6])]
  75. if ORGrow[4] is not None:
  76. title = vcf.add('TITLE').value = str(ORGrow[4])
  77. if ORGrow[3] is not None:
  78. role = vcf.add('ROLE').value = str(ORGrow[3])
  79. # Also parameters are possible. Could be read out
  80. # | columnID | column |
  81. # ----------------------------
  82. # | 0 | detailId |
  83. # | 1 | contactId |
  84. # | 2 | name |
  85. # | 3 | role |
  86. # | 4 | title |
  87. # | 5 | location |
  88. # | 6 | department |
  89. # | 7 | logoUrl |
  90. # | 8 | assistantName |
  91. ## Abfragen E-Mail-Adressen
  92. SQLEmailCur = SQLconn.cursor()
  93. for Emailrow in SQLEmailCur.execute('SELECT * from EmailAddresses JOIN Details on Details.detailId= EmailAddresses.detailId where EmailAddresses.contactId = ' + str(contactID)):
  94. # debug ausgabe
  95. DEBUG(args.debug,str(Emailrow[2]) + " at " + str(Emailrow[9]))
  96. email = vcf.add('email')
  97. email.value = str(Emailrow[2])
  98. # nur den Typ einpflegen, wenn das hier nicht none ist
  99. if Emailrow[9] != None:
  100. email.type_param = str(Emailrow[9])
  101. SQLPhoneCur = SQLconn.cursor()
  102. ## Abfragen Telefonnummer, Fax, SMS - Nummern kommen aus der gleichen Tabelle
  103. for Phonerow in SQLPhoneCur.execute('SELECT * from PhoneNumbers JOIN Details on Details.detailId = PhoneNumbers.detailId where PhoneNumbers.contactId = ' + str(contactID)):
  104. # wir müssen die SubTypen unterscheiden
  105. #Null voice
  106. #1 cell
  107. #2 fax
  108. #3 pager
  109. #6 video
  110. #10 Assistent
  111. # debug ausgabe
  112. DEBUG(args.debug,str(Phonerow[2]) + " at " + str(Phonerow[10]) + " subtype=" + str(Phonerow[3]))
  113. # None is a normal phone Number
  114. if Phonerow[3] == "1":
  115. phcat='cell'
  116. elif Phonerow[3] == "2":
  117. phcat='fax'
  118. elif Phonerow[3] == "3":
  119. phcat='pager'
  120. elif Phonerow[3] == "6":
  121. phcat='video'
  122. elif Phonerow[3] == "10":
  123. phcat='assistent'
  124. elif Phonerow[3] is None:
  125. phcat='voice'
  126. DEBUG(args.debug,phcat)
  127. phone = vcf.add(phcat).value = str(Phonerow[2])
  128. # nur den Typ einpflegen, wenn das hier nicht none ist
  129. if Phonerow[10] != None:
  130. try:
  131. phone.type_param = str(Phonerow[10])
  132. except AttributeError:
  133. continue
  134. # Ausgabe
  135. f = open(cardfile,'w')
  136. f.write(vcf.serialize())
  137. f.close()
  138. # hier brauchen wir einige eception handles -> wie bekommen wir die einzelnen exceptions heruas ?
  139. #except:
  140. #print("Error in executing SQL")
  141. except AttributeError:
  142. print("Datatype mismatch")
  143. raise
  144. # das generöse Except am Ende
  145. except:
  146. print("unhandled error")
  147. raise