ContactRescue.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. # coding=utf-8
  2. # Doc
  3. # Script to extract Contacts from Sailfish Contact SQLite DB located at
  4. #
  5. #
  6. # Links
  7. # FileFormatdescription: https://docs.fileformat.com/email/vcf/#vcf-30-example
  8. # Pytho vobject: http://eventable.github.io/vobject/
  9. # ChangeLog
  10. # 2021-08-03 - multiple E-Mails with different types are working correctly
  11. import sqlite3
  12. import vobject
  13. import uuid
  14. import argparse
  15. def DEBUG(debug,msg):
  16. if debug is not None:
  17. print("..DEBUG: " + msg)
  18. 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' )
  19. parser.add_argument('--db','-d', help="Sqlite3 Database file usually /home/{nemo,defaultuser)/.local/share/system/Contacts/qtcontacts-sqlite/contacts.db")
  20. parser.add_argument('--output','-o',help="Output directory for vcf files")
  21. parser.add_argument('--debug',action="store_true",help="debugging output to identify problems")
  22. args = parser.parse_args()
  23. SQLconn = sqlite3.connect(args.db)
  24. try:
  25. SQLContCur = SQLconn.cursor()
  26. for row in SQLContCur.execute('SELECT * FROM Contacts'):
  27. # contactID abfragen
  28. contactID=row[0]
  29. # wir erstellen das Objekt
  30. vcf = vobject.vCard()
  31. vcf.add('uid').value = str(uuid.uuid4())
  32. #vcf.add('uid').value = "Testdaten"
  33. vcf.add('n').value = vobject.vcard.Name( family=row[6], given=row[4] )
  34. vcf.add('fn').value =row[1]
  35. DEBUG(args.debug,"Contact " + row[1])
  36. SQLADRCur = SQLconn.cursor()
  37. for ADRrow in SQLADRCur.execute('SELECT * FROM Addresses JOIN Details on Details.detailId = Addresses.detailId where Addresses.contactId = ' + str(contactID)):
  38. adr = vcf.add('ADR').value = vobject.vcard.Address(street=ADRrow[2], city=ADRrow[5], region=ADRrow[4], code=ADRrow[6],country=ADRrow[7])
  39. ## Abfragen Organisation
  40. SQLORGCur = SQLconn.cursor()
  41. for ORGrow in SQLORGCur.execute('SELECT * from Organizations where contactId = ' + str(contactID)):
  42. org = vcf.add('ORG').value = [str(ORGrow[2]), str(ORGrow[6])]
  43. if ORGrow[4] is not None:
  44. title = vcf.add('TITLE').value = str(ORGrow[4])
  45. if ORGrow[3] is not None:
  46. role = vcf.add('ROLE').value = str(ORGrow[3])
  47. # Also parameters are possible. Could be read out
  48. # | columnID | column |
  49. # ----------------------------
  50. # | 0 | detailId |
  51. # | 1 | contactId |
  52. # | 2 | name |
  53. # | 3 | role |
  54. # | 4 | title |
  55. # | 5 | location |
  56. # | 6 | department |
  57. # | 7 | logoUrl |
  58. # | 8 | assistantName |
  59. ## Abfragen E-Mail-Adressen
  60. SQLEmailCur = SQLconn.cursor()
  61. for Emailrow in SQLEmailCur.execute('SELECT * from EmailAddresses JOIN Details on Details.detailId= EmailAddresses.detailId where EmailAddresses.contactId = ' + str(contactID)):
  62. # debug ausgabe
  63. DEBUG(args.debug,str(Emailrow[2]) + " at " + str(Emailrow[9]))
  64. email = vcf.add('email')
  65. email.value = str(Emailrow[2])
  66. # nur den Typ einpflegen, wenn das hier nicht none ist
  67. if Emailrow[9] != None:
  68. email.type_param = str(Emailrow[9])
  69. SQLPhoneCur = SQLconn.cursor()
  70. ## Abfragen Telefonnummer, Fax, SMS - Nummern kommen aus der gleichen Tabelle
  71. for Phonerow in SQLPhoneCur.execute('SELECT * from PhoneNumbers JOIN Details on Details.detailId = PhoneNumbers.detailId where PhoneNumbers.contactId = ' + str(contactID)):
  72. # wir müssen die SubTypen unterscheiden
  73. #Null voice
  74. #1 cell
  75. #2 fax
  76. #3 pager
  77. #6 video
  78. #10 Assistent
  79. # debug ausgabe
  80. print("...debug: " + str(Phonerow[2]) + " at " + str(Phonerow[10]) + " subtype=" + str(Phonerow[3]))
  81. # None is a normal phone Number
  82. if Phonerow[3] == "1":
  83. phcat='cell'
  84. elif Phonerow[3] == "2":
  85. phcat='fax'
  86. elif Phonerow[3] == "3":
  87. phcat='pager'
  88. elif Phonerow[3] == "6":
  89. phcat='video'
  90. elif Phonerow[3] == "10":
  91. phcat='assistent'
  92. elif Phonerow[3] is None:
  93. phcat='voice'
  94. print("...debug: " + phcat)
  95. phone = vcf.add(phcat).value = str(Phonerow[2])
  96. # nur den Typ einpflegen, wenn das hier nicht none ist
  97. if Phonerow[10] != None:
  98. try:
  99. phone.type_param = str(Phonerow[10])
  100. except AttributeError:
  101. continue
  102. # Ausgabe
  103. print(vcf.serialize())
  104. # hier brauchen wir einige eception handles -> wie bekommen wir die einzelnen exceptions heruas ?
  105. #except:
  106. #print("Error in executing SQL")
  107. except AttributeError:
  108. print("Datatype mismatch")
  109. raise
  110. # das generöse Except am Ende
  111. except:
  112. print("unhandled error")
  113. raise