Message

Struct Message 

Source
pub struct Message {
Show 32 fields pub rowid: i32, pub guid: String, pub text: Option<String>, pub service: Option<String>, pub handle_id: Option<i32>, pub destination_caller_id: Option<String>, pub subject: Option<String>, pub date: i64, pub date_read: i64, pub date_delivered: i64, pub is_from_me: bool, pub is_read: bool, pub item_type: i32, pub other_handle: Option<i32>, pub share_status: bool, pub share_direction: Option<bool>, pub group_title: Option<String>, pub group_action_type: i32, pub associated_message_guid: Option<String>, pub associated_message_type: Option<i32>, pub balloon_bundle_id: Option<String>, pub expressive_send_style_id: Option<String>, pub thread_originator_guid: Option<String>, pub thread_originator_part: Option<String>, pub date_edited: i64, pub associated_message_emoji: Option<String>, pub chat_id: Option<i32>, pub num_attachments: i32, pub deleted_from: Option<i32>, pub num_replies: i32, pub components: Vec<BubbleComponent>, pub edited_parts: Option<EditedMessage>,
}
Expand description

Represents a single row in the message table.

Additional information is available in the parent module.

Fields§

§rowid: i32

The unique identifier for the message in the database

§guid: String

The globally unique identifier for the message

§text: Option<String>

The text of the message, which may require calling Self::generate_text() to populate

§service: Option<String>

The service the message was sent from

§handle_id: Option<i32>

The ID of the person who sent the message

§destination_caller_id: Option<String>

The address the database owner received the message at, i.e. a phone number or email

§subject: Option<String>

The content of the Subject field

§date: i64

The date the message was written to the database

§date_read: i64

The date the message was read

§date_delivered: i64

The date a message was delivered

§is_from_me: bool

true if the database owner sent the message, else false

§is_read: bool

true if the message was read by the recipient, else false

§item_type: i32

Intermediate data for determining the Variant of a message

§other_handle: Option<i32>

Optional handle for the recipient of a message that includes shared content

§share_status: bool

Boolean determining whether some shared data is active or inactive, i.e. shared location being enabled or disabled

§share_direction: Option<bool>

Boolean determining the direction shared data was sent; false indicates it was sent from the database owner, true indicates it was sent to the database owner

§group_title: Option<String>

If the message updates the display_name of the chat, this field will be populated

§group_action_type: i32

If the message modified for a group, this will be nonzero

§associated_message_guid: Option<String>

The message GUID of a message associated with this one

§associated_message_type: Option<i32>

The numeric type code for the associated message, used to determine message variant

§balloon_bundle_id: Option<String>

The bundle ID of the app that generated the AppMessage

§expressive_send_style_id: Option<String>

Intermediate data for determining the expressive of a message

§thread_originator_guid: Option<String>

Indicates the first message in a thread of replies in get_replies()

§thread_originator_part: Option<String>

Indicates the part of a message a reply is pointing to

§date_edited: i64

The date the message was most recently edited

§associated_message_emoji: Option<String>

If present, this is the emoji associated with a custom emoji tapback

§chat_id: Option<i32>

The identifier of the chat the message belongs to

§num_attachments: i32

The number of attached files included in the message

§deleted_from: Option<i32>

The identifier of the chat the message was deleted from

§num_replies: i32

The number of replies to the message

§components: Vec<BubbleComponent>

The components of the message body, parsed by a TypedStreamDeserializer or streamtyped::parse()

§edited_parts: Option<EditedMessage>

The components of the message that may or may not have been edited or unsent

Implementations§

Source§

impl Message

Source

pub fn generate_text<'a>( &'a mut self, db: &'a Connection, ) -> Result<&'a str, MessageError>

Generate the text of a message, deserializing it as typedstream (and falling back to streamtyped) data if necessary.

Source

pub fn generate_text_legacy<'a>( &'a mut self, db: &'a Connection, ) -> Result<&'a str, MessageError>

Generates the text using the legacy parser only, ignoring any typedstream data. This is useful for messages that do not have typedstream data, such as those from older iOS versions.

Warning: This method does not handle typedstream data and will not parse all message types correctly.

Source

pub fn date(&self, offset: &i64) -> Result<DateTime<Local>, MessageError>

Calculates the date a message was written to the database.

This field is stored as a unix timestamp with an epoch of 2001-01-01 00:00:00 in the local time zone

offset can be provided by get_offset or manually.

Source

pub fn date_delivered( &self, offset: &i64, ) -> Result<DateTime<Local>, MessageError>

Calculates the date a message was marked as delivered.

This field is stored as a unix timestamp with an epoch of 2001-01-01 00:00:00 in the local time zone

offset can be provided by get_offset or manually.

Source

pub fn date_read(&self, offset: &i64) -> Result<DateTime<Local>, MessageError>

Calculates the date a message was marked as read.

This field is stored as a unix timestamp with an epoch of 2001-01-01 00:00:00 in the local time zone

offset can be provided by get_offset or manually.

Source

pub fn date_edited(&self, offset: &i64) -> Result<DateTime<Local>, MessageError>

Calculates the date a message was most recently edited.

This field is stored as a unix timestamp with an epoch of 2001-01-01 00:00:00 in the local time zone

offset can be provided by get_offset or manually.

Source

pub fn time_until_read(&self, offset: &i64) -> Option<String>

Gets the time until the message was read. This can happen in two ways:

  • You received a message, then waited to read it
  • You sent a message, and the recipient waited to read it

In the former case, this subtracts the date read column (date_read) from the date received column (date). In the latter case, this subtracts the date delivered column (date_delivered) from the date received column (date).

Not all messages get tagged with the read properties. If more than one message has been sent in a thread before getting read, only the most recent message will get the tag.

offset can be provided by get_offset or manually.

Source

pub fn is_reply(&self) -> bool

true if the message is a response to a thread, else false

Source

pub fn is_announcement(&self) -> bool

true if the message is an Announcement, else false

Source

pub fn is_tapback(&self) -> bool

true if the message is a Tapback to another message, else false

Source

pub fn is_expressive(&self) -> bool

true if the message has an Expressive, else false

Source

pub fn is_url(&self) -> bool

true if the message has a URL preview, else false

Source

pub fn is_handwriting(&self) -> bool

true if the message is a HandwrittenMessage, else false

Source

pub fn is_digital_touch(&self) -> bool

true if the message is a Digital Touch, else false

Source

pub fn is_poll(&self) -> bool

true if the message is a Poll, else false

Source

pub fn is_poll_vote(&self) -> bool

true if the message is a Poll vote, else false

Source

pub fn is_poll_update(&self) -> bool

true if the message is a Poll vote, else false

Source

pub fn is_edited(&self) -> bool

true if the message was Edited, else false

Source

pub fn is_part_edited(&self, index: usize) -> bool

true if the specified message component was edited, else false

Source

pub fn is_fully_unsent(&self) -> bool

true if all message components were unsent, else false

Source

pub fn has_attachments(&self) -> bool

true if the message contains Attachments, else false

Attachments can be queried with Attachment::from_message().

Source

pub fn has_replies(&self) -> bool

true if the message begins a thread, else false

Source

pub fn is_kept_audio_message(&self) -> bool

true if the message indicates a sent audio message was kept, else false

Source

pub fn is_shareplay(&self) -> bool

true if the message is a SharePlay/FaceTime message, else false

Source

pub fn is_from_me(&self) -> bool

true if the message was sent by the database owner, else false

Source

pub fn started_sharing_location(&self) -> bool

true if the message indicates a sender started sharing their location, else false

Source

pub fn stopped_sharing_location(&self) -> bool

true if the message indicates a sender stopped sharing their location, else false

Source

pub fn is_deleted(&self) -> bool

true if the message was deleted and is recoverable, else false

Messages removed by deleting an entire conversation or by deleting a single message from a conversation are moved to a separate collection for up to 30 days. Messages present in this collection are restored to the conversations they belong to. Apple details this process here.

Messages that have expired from this restoration process are permanently deleted and cannot be recovered.

Note: This is not the same as an Unsent message.

Source

pub fn has_translation(&self, db: &Connection) -> bool

true if the message was translated, else false

Source

pub fn get_translation( &self, db: &Connection, ) -> Result<Option<Translation>, PlistParseError>

Generates the Translation for the current message

Source

pub fn cache_translations( db: &Connection, ) -> Result<HashSet<String>, TableError>

Cache all message GUIDs that contain translation data

Source

pub fn group_action(&self) -> Option<GroupAction<'_>>

Get the group action for the current message

Source

pub fn get_count( db: &Connection, context: &QueryContext, ) -> Result<u64, TableError>

Get the number of messages in the database

§Example
use imessage_database::util::dirs::default_db_path;
use imessage_database::tables::table::{Diagnostic, get_connection};
use imessage_database::tables::messages::Message;
use imessage_database::util::query_context::QueryContext;

let db_path = default_db_path();
let conn = get_connection(&db_path).unwrap();
let context = QueryContext::default();
Message::get_count(&conn, &context);
Source

pub fn stream_rows<'a>( db: &'a Connection, context: &'a QueryContext, ) -> Result<CachedStatement<'a>, TableError>

Stream messages from the database with optional filters.

§Example
use imessage_database::util::dirs::default_db_path;
use imessage_database::tables::table::{Diagnostic, get_connection};
use imessage_database::tables::{messages::Message, table::Table};
use imessage_database::util::query_context::QueryContext;

let db_path = default_db_path();
let conn = get_connection(&db_path).unwrap();
let context = QueryContext::default();

let mut statement = Message::stream_rows(&conn, &context).unwrap();

let messages = statement.query_map([], |row| Ok(Message::from_row(row))).unwrap();

messages.map(|msg| println!("{:#?}", Message::extract(msg)));
Source

pub fn clean_associated_guid(&self) -> Option<(usize, &str)>

Clean and parse the associated message GUID for tapbacks and replies.

Returns a tuple of (component index, message GUID) if present.

Source

pub fn get_replies( &self, db: &Connection, ) -> Result<HashMap<usize, Vec<Self>>, TableError>

Build a HashMap of message component index to messages that reply to that component

Source

pub fn get_votes(&self, db: &Connection) -> Result<Vec<Self>, TableError>

Build a Vec of messages that vote on the parent poll

Source

pub fn as_poll(&self, db: &Connection) -> Result<Option<Poll>, PlistParseError>

If the message is a poll, attempt to parse and return it

Source

pub fn variant(&self) -> Variant<'_>

Get the variant of a message, see variants for detail.

Source

pub fn get_announcement(&self) -> Option<Announcement<'_>>

Determine the type of announcement a message contains, if it contains one

Source

pub fn service(&self) -> Service<'_>

Determine the service the message was sent from, i.e. iMessage, SMS, IRC, etc.

Source

pub fn payload_data(&self, db: &Connection) -> Option<Value>

Get a message’s plist from the MESSAGE_PAYLOAD BLOB column

Calling this hits the database, so it is expensive and should only get invoked when needed.

This column contains data used by iMessage app balloons and can be parsed with parse_ns_keyed_archiver().

Source

pub fn raw_payload_data(&self, db: &Connection) -> Option<Vec<u8>>

Get a message’s raw data from the MESSAGE_PAYLOAD BLOB column

Calling this hits the database, so it is expensive and should only get invoked when needed.

This column contains data used by HandwrittenMessages.

Source

pub fn message_summary_info(&self, db: &Connection) -> Option<Value>

Get a message’s plist from the MESSAGE_SUMMARY_INFO BLOB column

Calling this hits the database, so it is expensive and should only get invoked when needed.

This column contains data used by edited iMessages.

Source

pub fn attributed_body(&self, db: &Connection) -> Option<Vec<u8>>

Get a message’s typedstream from the ATTRIBUTED_BODY BLOB column

Calling this hits the database, so it is expensive and should only get invoked when needed.

This column contains the message’s body text with any other attributes.

Source

pub fn get_expressive(&self) -> Expressive<'_>

Determine which Expressive the message was sent with

Source

pub fn from_guid(guid: &str, db: &Connection) -> Result<Self, TableError>

Create a message from a given GUID; useful for debugging

§Example
use imessage_database::{
    tables::{
        messages::Message,
        table::get_connection,
    },
    util::dirs::default_db_path,
};

let db_path = default_db_path();
let conn = get_connection(&db_path).unwrap();

if let Ok(mut message) = Message::from_guid("example-guid", &conn) {
    let _ = message.generate_text(&conn);
    println!("{:#?}", message)
}

Trait Implementations§

Source§

impl Cacheable for Message

Source§

fn cache(db: &Connection) -> Result<HashMap<Self::K, Self::V>, TableError>

Used for tapbacks that do not exist in a foreign key table

Builds a map like:

{
    "message_guid": {
        0: [Message, Message],
        1: [Message]
    }
}

Where the 0 and 1 are the tapback indexes in the body of the message mapped by message_guid

Source§

type K = String

The key type for the cache HashMap
Source§

type V = HashMap<usize, Vec<Message>>

The value type for the cache HashMap
Source§

impl Debug for Message

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Diagnostic for Message

Source§

fn run_diagnostic(db: &Connection) -> Result<(), TableError>

Emit diagnostic data for the Messages table

§Example
use imessage_database::util::dirs::default_db_path;
use imessage_database::tables::table::{Diagnostic, get_connection};
use imessage_database::tables::messages::Message;

let db_path = default_db_path();
let conn = get_connection(&db_path).unwrap();
Message::run_diagnostic(&conn);
Source§

impl Table for Message

Source§

fn get(db: &Connection) -> Result<CachedStatement<'_>, TableError>

Convert data from the messages table to native Rust data structures, falling back to more compatible queries to ensure compatibility with older database schemas

Source§

fn from_row(row: &Row<'_>) -> Result<Message>

Deserialize a single row into Self, returning a rusqlite::Result
Source§

fn extract( message: Result<Result<Self, Error>, Error>, ) -> Result<Self, TableError>

Map a rusqlite::Result<Self> into our TableError
Source§

fn stream<F, E>(db: &Connection, callback: F) -> Result<(), TableError>
where F: FnMut(Result<Self, TableError>) -> Result<(), E>,

Process all rows from the table using a callback. This is the most memory-efficient approach for large tables. Read more
Source§

fn get_blob<'a>( &self, db: &'a Connection, table: &str, column: &str, rowid: i64, ) -> Option<Blob<'a>>

Get a BLOB from the table Read more
Source§

fn has_blob( &self, db: &Connection, table: &str, column: &str, rowid: i64, ) -> bool

Check if a BLOB exists in the table

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.