messages.js 4.0 KB

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