Source code for imessagedb.message
import plistlib
from datetime import datetime
from imessagedb.utils import *
import imessagedb
[docs]def _convert_attributed_body(encoded: bytes) -> str:
# This general logic was copied from
# https://github.com/my-other-github-account/imessage_tools/blob/master/imessage_tools.py, however
# I needed to make some improvements
text = encoded.split(b'NSNumber')[0]
text = text.split(b'NSString')[1]
text = text.split(b'NSDictionary')[0]
text = text[6:-12]
if b'\x01' in text:
text = text.split(b'\x01')[1]
if b'\x02' in text:
text = text.split(b'\x02')[1]
if b'\x00' in text:
text = text.split(b'\x00')[1]
if b'\x86' in text:
text = text.split(b'\x86')[0]
return text.decode('utf-8', errors='replace')
[docs]class Message:
""" Class for holding information about a message """
def __init__(self, database, rowid: int, guid: str, date: str, is_from_me: bool, handle_id: str,
attributed_body: bytes, message_summary_info: bytes, text: str, reply_to_guid: str,
thread_originator_guid: str, thread_originator_part: str, chat_id: str, message_attachments: list):
"""
Parameters
----------
database : imessagedb.DB
An instance of a connected database
rowid, guid, date, is_from_me, handle_id, attributed_body, message_summary_info, text,
reply_to_guid, thread_originator_guid, thread_originator_part, chat_id : str
The parameters are the fields in the database
message_attachments : list
The attachments for this message"""
self._rowid = rowid
self._guid = guid
self._date = date
self._is_from_me = is_from_me
self._handle_id = handle_id
self._attributed_body = attributed_body
self._message_summary_info = message_summary_info
self._text = text
self._attributed_body = attributed_body
self._reply_to_guid = reply_to_guid
self._thread_originator_guid = thread_originator_guid
self._thread_originator_part = thread_originator_part
self._chat_id = chat_id
self._attachments = message_attachments
self._thread = {}
self._edits = []
# There are a lot of messages that are saved into attributed_body instead of the text field.
# There isn't a good way to convert this in Python that I've found, so I have to run a
# program to do it. I need to fix this.
if (self._text is None or text == '' or text == ' ') and self._attributed_body is not None:
self._text = _convert_attributed_body(self._attributed_body)
# Edits are stored in message_summary_info
try:
plist = plistlib.loads(self._message_summary_info)
if 'ec' in plist:
for row in plist['ec']['0']:
self._edits.append({'text': _convert_attributed_body(row['t']),
'date': convert_from_database_date(row['d'])})
except plistlib.InvalidFileException as exp:
pass
[docs] def __repr__(self) -> str:
return_string = f'RowID: {self._rowid}' \
f' GUID: {self._guid}' \
f' Date: {self._date}' \
f' From me: {self._is_from_me}' \
f' HandleID: {self._handle_id}' \
f' Message: {self._text}' \
f' Originator Thread: {self._thread_originator_guid}' \
f' Reply Message: {self._reply_to_guid}' \
f' Thread Part: {self._thread_originator_part}' \
f' Chat ID: {self._chat_id}' \
f' Attachments: {self._attachments}'
return str(return_string)
@property
def rowid(self) -> int:
return self._rowid
@property
def guid(self) -> str:
return self._guid
@property
def date(self) -> str:
return self._date
@property
def is_from_me(self) -> bool:
return self._is_from_me
@property
def handle_id(self) -> str:
return self._handle_id
@property
def attributed_body(self) -> bytes:
return self._attributed_body
@property
def message_summary_info(self) -> bytes:
return self._message_summary_info
@property
def text(self) -> str:
return self._text
@property
def edits(self) -> list:
return self._edits
@property
def reply_to_guid(self) -> str:
return self._reply_to_guid
@property
def thread_originator_guid(self) -> str:
return self._thread_originator_guid
@property
def chat_id(self) -> str:
return self._chat_id
@property
def attachments(self) -> list:
return self._attachments
@property
def thread(self) -> dict:
return self._thread