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
Row from the message table, plus body/edit metadata populated by parse_body.
Fields§
§rowid: i32Message row ID.
guid: StringMessage GUID.
text: Option<String>Plain body text. parse_body may populate this from attributedBody.
service: Option<String>Raw service name.
handle_id: Option<i32>Sender handle row ID.
destination_caller_id: Option<String>Address that received the message.
subject: Option<String>Subject field.
date: i64Raw timestamp for when the message was written to the database.
date_read: i64Raw timestamp for when the message was read.
date_delivered: i64Raw timestamp for when the message was delivered.
is_from_me: booltrue when the database owner sent the message.
is_read: booltrue when the message was read by the recipient.
item_type: i32Message item type used by variant.
other_handle: Option<i32>Additional handle used by shared-location and group-action messages.
Shared-location active/inactive flag.
Shared-location direction flag.
group_title: Option<String>Group title carried by group-name-change messages.
group_action_type: i32Group action code.
associated_message_guid: Option<String>GUID of the message this row references.
associated_message_type: Option<i32>Type code for the associated message, used by variant.
balloon_bundle_id: Option<String>The bundle ID of the app that generated the AppMessage
expressive_send_style_id: Option<String>Expressive-send identifier used by get_expressive.
thread_originator_guid: Option<String>Indicates the first message in a thread of replies in get_replies()
thread_originator_part: Option<String>Body part index targeted by a reply.
date_edited: i64Raw timestamp for the most recent edit.
associated_message_emoji: Option<String>Emoji associated with a custom emoji tapback.
chat_id: Option<i32>Chat row ID this message belongs to.
num_attachments: i32Number of attached files included in the message.
deleted_from: Option<i32>The rowid of the chat the message was deleted from
num_replies: i32Number 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>Parsed edit/unsent metadata from message_summary_info.
Implementations§
Source§impl Message
impl Message
Sourcepub fn run_diagnostic(db: &Connection) -> Result<MessageDiagnostic, TableError>
pub fn run_diagnostic(db: &Connection) -> Result<MessageDiagnostic, TableError>
Compute diagnostic data for the message table.
§Example
use imessage_database::util::dirs::default_db_path;
use imessage_database::tables::table::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 Message
impl Message
Sourcepub fn parse_body(&self, db: &Connection) -> Result<ParsedBody, MessageError>
pub fn parse_body(&self, db: &Connection) -> Result<ParsedBody, MessageError>
Parse the body of a message, deserializing it as typedstream
(and falling back to streamtyped) data if necessary.
This method performs pure parsing without mutating the message. Use Self::apply_body()
to apply the result back to the message.
§Example
if let Ok(body) = message.parse_body(&conn) {
message.apply_body(body);
}Sourcepub fn apply_body(&mut self, body: ParsedBody)
pub fn apply_body(&mut self, body: ParsedBody)
Apply a ParsedBody to this message, setting its text, components,
edited parts, and balloon bundle ID.
Sourcepub fn generate_text_legacy<'a>(
&'a mut self,
db: &'a Connection,
) -> Result<&'a str, MessageError>
pub fn generate_text_legacy<'a>( &'a mut self, db: &'a Connection, ) -> Result<&'a str, MessageError>
Parse text with the legacy parser only.
This ignores typedstream attributes and does not preserve every modern message type.
Sourcepub fn date(&self, offset: i64) -> Result<DateTime<Local>, MessageError>
pub fn date(&self, offset: i64) -> Result<DateTime<Local>, MessageError>
Convert date to local time.
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.
Sourcepub fn date_delivered(
&self,
offset: i64,
) -> Result<DateTime<Local>, MessageError>
pub fn date_delivered( &self, offset: i64, ) -> Result<DateTime<Local>, MessageError>
Convert date_delivered to local time.
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.
Sourcepub fn date_read(&self, offset: i64) -> Result<DateTime<Local>, MessageError>
pub fn date_read(&self, offset: i64) -> Result<DateTime<Local>, MessageError>
Convert date_read to local time.
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.
Sourcepub fn date_edited(&self, offset: i64) -> Result<DateTime<Local>, MessageError>
pub fn date_edited(&self, offset: i64) -> Result<DateTime<Local>, MessageError>
Convert date_edited to local time.
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.
Sourcepub fn time_until_read(&self, offset: i64) -> Option<String>
pub fn time_until_read(&self, offset: i64) -> Option<String>
Calculate the elapsed time until the message was read or delivered.
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 computes the difference from the date received (date) to the date read (date_read).
In the latter case, this computes the difference from the date sent (date) to the date delivered (date_delivered).
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.
Sourcepub fn is_announcement(&self) -> bool
pub fn is_announcement(&self) -> bool
true when the message is an Announcement.
Sourcepub fn is_tapback(&self) -> bool
pub fn is_tapback(&self) -> bool
true when the message is a Tapback to another message.
Sourcepub fn is_expressive(&self) -> bool
pub fn is_expressive(&self) -> bool
true when the message has an Expressive send effect.
Sourcepub fn is_url(&self) -> bool
pub fn is_url(&self) -> bool
true when the message has a URL preview.
Sourcepub fn is_handwriting(&self) -> bool
pub fn is_handwriting(&self) -> bool
true when the message is a HandwrittenMessage.
Sourcepub fn is_digital_touch(&self) -> bool
pub fn is_digital_touch(&self) -> bool
true when the message is a Digital Touch message.
Sourcepub fn is_poll_vote(&self) -> bool
pub fn is_poll_vote(&self) -> bool
true when the message is a PollVote.
Sourcepub fn is_poll_update(&self) -> bool
pub fn is_poll_update(&self) -> bool
true when the message adds or updates poll options.
Sourcepub fn is_part_edited(&self, index: usize) -> bool
pub fn is_part_edited(&self, index: usize) -> bool
true when the specified message component was edited.
Sourcepub fn is_fully_unsent(&self) -> bool
pub fn is_fully_unsent(&self) -> bool
true when all message components were unsent.
Sourcepub fn has_attachments(&self) -> bool
pub fn has_attachments(&self) -> bool
true when the message contains Attachments.
Attachments can be queried with Attachment::from_message().
Sourcepub fn has_replies(&self) -> bool
pub fn has_replies(&self) -> bool
true when the message begins a thread.
Sourcepub fn is_kept_audio_message(&self) -> bool
pub fn is_kept_audio_message(&self) -> bool
true when the message indicates a sent audio message was kept.
true when the message is a SharePlay/FaceTime message.
Sourcepub fn is_from_me(&self) -> bool
pub fn is_from_me(&self) -> bool
true when the message was sent by the database owner.
Returns the SharedLocation when the message is a legacy
shared-location event.
Sourcepub fn is_deleted(&self) -> bool
pub fn is_deleted(&self) -> bool
true when the message is present in the recoverable deleted-message table.
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.
Sourcepub fn has_translation(&self, db: &Connection) -> bool
pub fn has_translation(&self, db: &Connection) -> bool
true when the message summary includes translation metadata.
Sourcepub fn get_translation(
&self,
db: &Connection,
) -> Result<Option<Translation>, MessageError>
pub fn get_translation( &self, db: &Connection, ) -> Result<Option<Translation>, MessageError>
Parse translation metadata for the message.
Sourcepub fn cache_translations(
db: &Connection,
) -> Result<HashSet<String>, TableError>
pub fn cache_translations( db: &Connection, ) -> Result<HashSet<String>, TableError>
Cache message GUIDs whose summaries include translation metadata.
Sourcepub fn group_action(&self) -> Option<GroupAction<'_>>
pub fn group_action(&self) -> Option<GroupAction<'_>>
Parse the group action encoded by the message.
Sourcepub fn get_count(
db: &Connection,
context: &QueryContext,
) -> Result<i64, TableError>
pub fn get_count( db: &Connection, context: &QueryContext, ) -> Result<i64, TableError>
Count messages matching the provided query context.
§Example
use imessage_database::util::dirs::default_db_path;
use imessage_database::tables::table::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);Sourcepub fn stream_rows<'a>(
db: &'a Connection,
context: &'a QueryContext,
) -> Result<CachedStatement<'a>, TableError>
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::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();
for message in Message::rows(&mut statement, []).unwrap() {
println!("{:#?}", message);
}Sourcepub fn clean_associated_guid(&self) -> Option<(usize, &str)>
pub fn clean_associated_guid(&self) -> Option<(usize, &str)>
Parse the target body component index and GUID from associated_message_guid.
Returns a tuple of (component index, message GUID) if present.
Sourcepub fn get_replies(
&self,
db: &Connection,
) -> Result<HashMap<usize, Vec<Self>>, TableError>
pub fn get_replies( &self, db: &Connection, ) -> Result<HashMap<usize, Vec<Self>>, TableError>
Group replies by target body component index.
Sourcepub fn get_votes(&self, db: &Connection) -> Result<Vec<Self>, TableError>
pub fn get_votes(&self, db: &Connection) -> Result<Vec<Self>, TableError>
Load messages that vote on or update the parent poll.
Sourcepub fn as_poll(&self, db: &Connection) -> Result<Option<Poll>, MessageError>
pub fn as_poll(&self, db: &Connection) -> Result<Option<Poll>, MessageError>
Parse this message as a poll, including vote counts and option updates.
Sourcepub fn variant(&self) -> Variant<'_>
pub fn variant(&self) -> Variant<'_>
Classify the message using its associated-message fields and app balloon bundle ID.
Sourcepub fn get_announcement(&self) -> Option<Announcement<'_>>
pub fn get_announcement(&self) -> Option<Announcement<'_>>
Parse the announcement represented by this message.
Sourcepub fn payload_data(&self, db: &Connection) -> Option<Value>
pub fn payload_data(&self, db: &Connection) -> Option<Value>
Parse the MESSAGE_PAYLOAD BLOB column as a property list.
Calling this reads a BLOB from the database.
This column contains data used by iMessage app balloons and can be parsed with
parse_ns_keyed_archiver().
Sourcepub fn raw_payload_data(&self, db: &Connection) -> Option<Vec<u8>>
pub fn raw_payload_data(&self, db: &Connection) -> Option<Vec<u8>>
Read the raw MESSAGE_PAYLOAD BLOB bytes.
Calling this reads a BLOB from the database.
This column contains data used by HandwrittenMessages.
Sourcepub fn message_summary_info(&self, db: &Connection) -> Option<Value>
pub fn message_summary_info(&self, db: &Connection) -> Option<Value>
Parse the MESSAGE_SUMMARY_INFO BLOB column as a property list.
Calling this reads a BLOB from the database.
This column contains data used by edited iMessages.
Sourcepub fn attributed_body(&self, db: &Connection) -> Option<Vec<u8>>
pub fn attributed_body(&self, db: &Connection) -> Option<Vec<u8>>
Get a message’s typedstream from the ATTRIBUTED_BODY BLOB column
Calling this reads a BLOB from the database.
This column contains the message’s body text with any other attributes.
Sourcepub fn get_expressive(&self) -> Expressive<'_>
pub fn get_expressive(&self) -> Expressive<'_>
Parse the expressive send effect.
Sourcepub fn from_guid(guid: &str, db: &Connection) -> Result<Self, TableError>
pub fn from_guid(guid: &str, db: &Connection) -> Result<Self, TableError>
Query a single message by GUID.
§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) {
if let Ok(body) = message.parse_body(&conn) {
message.apply_body(body);
}
println!("{:#?}", message)
}Trait Implementations§
Source§impl Cacheable for Message
impl Cacheable for Message
Source§fn cache(db: &Connection) -> Result<HashMap<Self::K, Self::V>, TableError>
fn cache(db: &Connection) -> Result<HashMap<Self::K, Self::V>, TableError>
Cache tapback messages by target message GUID and body component index.
Builds a map like:
{
"message_guid": {
0: [Message, Message],
1: [Message]
}
}The 0 and 1 keys are component indexes in the target message body.
Source§impl Table for Message
impl Table for Message
Source§fn get(db: &Connection) -> Result<CachedStatement<'_>, TableError>
fn get(db: &Connection) -> Result<CachedStatement<'_>, TableError>
Prepare the newest compatible message query, falling back through older schemas.
Source§fn from_row(row: &Row<'_>) -> Result<Message>
fn from_row(row: &Row<'_>) -> Result<Message>
Self. Returns rusqlite::Result
for direct use inside rusqlite::query_map / query_row
callbacks. For high-level iteration, prefer Table::rows or
Table::row.Source§fn rows<'stmt, P: Params>(
stmt: &'stmt mut Statement<'_>,
params: P,
) -> Result<impl Iterator<Item = Result<Self, TableError>> + 'stmt, TableError>where
Self: 'stmt,
fn rows<'stmt, P: Params>(
stmt: &'stmt mut Statement<'_>,
params: P,
) -> Result<impl Iterator<Item = Result<Self, TableError>> + 'stmt, TableError>where
Self: 'stmt,
stmt, deserializing each via
from_row. Errors at row-fetch or row-deserialize
time are surfaced uniformly as TableError. Accepts both
rusqlite::Statement and rusqlite::CachedStatement (the
latter via deref coercion). Read moreSource§fn row<P: Params>(
stmt: &mut Statement<'_>,
params: P,
) -> Result<Self, TableError>
fn row<P: Params>( stmt: &mut Statement<'_>, params: P, ) -> Result<Self, TableError>
stmt. Returns
TableError::QueryError if the row is missing or fails to
deserialize. Accepts both rusqlite::Statement and
rusqlite::CachedStatement (the latter via deref coercion).Source§fn stream<F, E>(db: &Connection, callback: F) -> Result<(), E>
fn stream<F, E>(db: &Connection, callback: F) -> Result<(), E>
SELECT * query using a
callback. Builds and discards the prepared statement internally, so
the caller never sees it. Read more