Py-iMessenger icon indicating copy to clipboard operation
Py-iMessenger copied to clipboard

Fix for Null Messages

Open olliepro opened this issue 1 year ago • 1 comments

If anyone sees this, I managed to fix the issue of null messages:

"Py-iMessenger is completely broken with MacOS Ventura. As far as I can tell, the database is no longer being updated with messages and frankly I've lost the energy to continue with this project. As of 06/05/23 I have tried accessing the iMessage DB as it shows that is updating but when trying to view the messages some appear as NULL until the entire database itself is copied and pasted elsewhere."

The message.attributedBody column in the db is where the message data is now stored. I was able to parse it by using this pattern: https://docs.rs/imessage-database/latest/src/imessage_database/util/streamtyped.rs.html#28-72

transcribed to python:

class StreamTypedError(Exception):
    pass


START_PATTERN = [0x01, 0x2B]  # Literal: [<Start of Heading> (SOH), +]
END_PATTERN = [0x86, 0x84]  # Literal: [<Start of Selected Area> (SSA), <Index> (IND)]


def find_pattern(stream: bytearray, pattern: list) -> int:
    """Finds the pattern in the stream."""
    for idx in range(len(stream) - len(pattern) + 1):
        if list(stream[idx : idx + len(pattern)]) == pattern:
            return idx
    return None


def drop_chars(offset: int, string: str) -> str:
    """Drops the first `offset` characters from the string."""
    if len(string) < offset:
        raise StreamTypedError("InvalidPrefix")
    return string[offset:]


def parse(stream: bytearray) -> str:
    # Find the start index and drain
    start_idx = find_pattern(stream, START_PATTERN)
    if start_idx is None:
        raise StreamTypedError("NoStartPattern")

    stream = stream[start_idx + 2 :]

    # Find the end index and truncate
    end_idx = find_pattern(stream, END_PATTERN)
    if end_idx is None:
        raise StreamTypedError("NoEndPattern")

    stream = stream[:end_idx]

    # Attempt UTF-8 decoding first, then fallback to lossy decoding if necessary
    try:
        string = stream.decode("utf-8")
        return drop_chars(1, string)
    except UnicodeDecodeError:
        string = stream.decode("utf-8", errors="replace")
        return drop_chars(3, string)

Hopefully this helps!

olliepro avatar Sep 27 '24 20:09 olliepro

That's awesome! Thank you so much!

If you can add a pull request, I'd love to merge that with main

VarunPatelius avatar Sep 27 '24 23:09 VarunPatelius