messages.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. const fileHash = require('../../util/backup_filehash')
  2. const log = require('../../util/log')
  3. const apple_timestamp = require('../../util/apple_timestamp')
  4. const SMS_DB = fileHash('Library/SMS/sms.db')
  5. module.exports = {
  6. version: 4,
  7. name: 'messages.messages',
  8. description: `List all SMS and iMessage messages in a conversation`,
  9. requiresBackup: true,
  10. // Run on a v3 lib / backup object.
  11. run (lib, { backup, id }) {
  12. return new Promise((resolve, reject) => {
  13. if (id === undefined) {
  14. return reject(new Error('You must specify an id for usage with the message report'))
  15. }
  16. resolve(getMessages(backup, id))
  17. })
  18. },
  19. // Available fields.
  20. output: {
  21. id: el => el.ROWID,
  22. date: el => el.date,
  23. sender: el => el.x_sender,
  24. text: el => (el.text || '').trim(),
  25. dateRead: el => el.date_read + '',
  26. dateDelivered: el => el.date_delivered + '',
  27. isDelivered: el => !!el.is_delivered,
  28. isFinished: el => !!el.is_finished,
  29. isFromMe: el => !!el.is_from_me,
  30. isRead: el => !!el.is_read,
  31. isSent: el => !!el.is_sent,
  32. attachments: el => (el.attachments || []).map((at) => at.filename)
  33. }
  34. }
  35. function getMessages (backup, chatId) {
  36. return new Promise(async (resolve, reject) => {
  37. try {
  38. let messages = await getMessagesiOS10iOS11(backup, chatId)
  39. resolve(messages)
  40. } catch (e) {
  41. log.verbose('iOS 10/11 messages lookup failed', e)
  42. }
  43. try {
  44. let messages = await getMessagesiOS9(backup, chatId)
  45. resolve(messages)
  46. } catch (e) {
  47. log.verbose('iOS 9 messages lookup failed', e)
  48. }
  49. reject(new Error('No Suitable messages database or query found. Use -v to see error information'))
  50. })
  51. }
  52. function getMessagesiOS9 (backup, chatId) {
  53. return new Promise((resolve, reject) => {
  54. backup.openDatabase(SMS_DB)
  55. .then(db => {
  56. db.all(`
  57. SELECT
  58. message.*,
  59. handle.id as sender_name,
  60. ${apple_timestamp.parse(date)} AS date
  61. FROM chat_message_join
  62. INNER JOIN message
  63. ON message.rowid = chat_message_join.message_id
  64. INNER JOIN handle
  65. ON handle.rowid = message.handle_id
  66. WHERE chat_message_join.chat_id = ?`, [parseInt(chatId)],
  67. async function (err, chats) {
  68. if (err) return reject(err)
  69. chats = chats || []
  70. // Compute the user's name
  71. for (var i in chats) {
  72. var el = chats[i]
  73. el.x_sender = el.is_from_me ? 'Me' : el.sender_name
  74. // if (!el.is_from_me) {
  75. // var contact = await backup.getName(el.sender_name)
  76. // if (contact) {
  77. // el.x_sender = `${contact.name} <${contact.query}>`
  78. // }
  79. // }
  80. }
  81. resolve(chats)
  82. })
  83. })
  84. .catch(reject)
  85. })
  86. }
  87. function getMessagesiOS10iOS11 (backup, chatId) {
  88. return new Promise((resolve, reject) => {
  89. backup.openDatabase(SMS_DB)
  90. .then(db => {
  91. db.all(`
  92. SELECT
  93. message.*,
  94. handle.id as sender_name,
  95. ${apple_timestamp.parse('date_read')} AS date_read,
  96. ${apple_timestamp.parse('date_delivered')} AS date_delivered,
  97. ${apple_timestamp.parse('date')} AS date
  98. FROM chat_message_join
  99. INNER JOIN message
  100. ON message.rowid = chat_message_join.message_id
  101. INNER JOIN handle
  102. ON handle.rowid = message.handle_id
  103. WHERE chat_message_join.chat_id = ?`, [parseInt(chatId)],
  104. async function (err, chats) {
  105. if (err) return reject(err)
  106. chats = chats || []
  107. // Compute the user's name
  108. for (var i in chats) {
  109. var el = chats[i]
  110. el.x_sender = el.is_from_me ? 'Me' : el.sender_name
  111. // if (!el.is_from_me) {
  112. // var contact = await backup.getName(el.sender_name)
  113. // if (contact) {
  114. // el.x_sender = `${contact.name} <${contact.query}>`
  115. // }
  116. // }
  117. }
  118. resolve(chats)
  119. })
  120. })
  121. .catch(reject)
  122. })
  123. }