Skip to main content

imessage_db/imessage/
entities.rs

1/// Entity structs mapping to iMessage chat.db tables.
2///
3/// These are plain Rust structs — no ORM. Values are transformed
4/// during row reading (booleans, dates, reaction types).
5///
6/// Fields use transformed types:
7/// - Boolean columns: `bool` (from 0/1 integers)
8/// - Date columns: `Option<i64>` (Unix ms, None if DB value is 0/null)
9/// - associated_message_type: `Option<String>` (reaction name or raw int as string)
10/// - Blob columns (attributedBody, etc.): `Option<Vec<u8>>` (raw bytes, decoded later)
11use serde::Serialize;
12
13/// A message row from the `message` table.
14#[derive(Debug, Clone, Default, Serialize)]
15pub struct Message {
16    // Core columns (always present)
17    pub rowid: i64,
18    pub guid: String,
19    pub text: Option<String>,
20    pub replace: i64,
21    pub service_center: Option<String>,
22    pub handle_id: i64,
23    pub subject: Option<String>,
24    pub country: Option<String>,
25    pub attributed_body: Option<Vec<u8>>,
26    pub version: i64,
27    pub r#type: i64,
28    pub service: Option<String>,
29    pub account: Option<String>,
30    pub account_guid: Option<String>,
31    pub error: i64,
32    pub date: Option<i64>,
33    pub date_read: Option<i64>,
34    pub date_delivered: Option<i64>,
35    pub is_delivered: bool,
36    pub is_finished: bool,
37    pub is_emote: bool,
38    pub is_from_me: bool,
39    pub is_empty: bool,
40    pub is_delayed: bool,
41    pub is_auto_reply: bool,
42    pub is_prepared: bool,
43    pub is_read: bool,
44    pub is_system_message: bool,
45    pub is_sent: bool,
46    pub has_dd_results: bool,
47    pub is_service_message: bool,
48    pub is_forward: bool,
49    pub was_downgraded: bool,
50    pub is_archive: bool,
51    pub cache_has_attachments: bool,
52    pub cache_roomnames: Option<String>,
53    pub was_data_detected: bool,
54    pub was_deduplicated: bool,
55    pub is_audio_message: bool,
56    pub is_played: bool,
57    pub date_played: Option<i64>,
58    pub item_type: i64,
59    pub other_handle: i64,
60    pub group_title: Option<String>,
61    pub group_action_type: i64,
62    pub share_status: i64,
63    pub share_direction: i64,
64    pub is_expirable: bool,
65    pub expire_state: bool,
66    pub message_action_type: i64,
67    pub message_source: i64,
68
69    pub associated_message_guid: Option<String>,
70    pub associated_message_type: Option<String>,
71    pub associated_message_emoji: Option<String>,
72    pub balloon_bundle_id: Option<String>,
73    pub payload_data: Option<Vec<u8>>,
74    pub expressive_send_style_id: Option<String>,
75    pub associated_message_range_location: Option<i64>,
76    pub associated_message_range_length: Option<i64>,
77    pub time_expressive_send_played: Option<i64>,
78    pub message_summary_info: Option<Vec<u8>>,
79    pub reply_to_guid: Option<String>,
80    pub is_corrupt: Option<bool>,
81    pub is_spam: Option<bool>,
82    pub thread_originator_guid: Option<String>,
83    pub thread_originator_part: Option<String>,
84    pub date_retracted: Option<i64>,
85    pub date_edited: Option<i64>,
86    pub part_count: Option<i64>,
87    pub was_delivered_quietly: Option<bool>,
88    pub did_notify_recipient: Option<bool>,
89
90    // Relations (populated by joins)
91    pub handle: Option<Handle>,
92    pub chats: Vec<Chat>,
93    pub attachments: Vec<Attachment>,
94}
95
96/// A chat row from the `chat` table.
97#[derive(Debug, Clone, Default, Serialize)]
98pub struct Chat {
99    pub rowid: i64,
100    pub guid: String,
101    pub style: i64,
102    pub state: i64,
103    pub account_id: Option<String>,
104    pub properties: Option<Vec<u8>>,
105    pub chat_identifier: Option<String>,
106    pub service_name: Option<String>,
107    pub room_name: Option<String>,
108    pub account_login: Option<String>,
109    pub is_archived: bool,
110    pub last_read_message_timestamp: Option<i64>,
111    pub last_addressed_handle: Option<String>,
112    pub display_name: Option<String>,
113    pub group_id: Option<String>,
114    pub is_filtered: bool,
115    pub successful_query: bool,
116
117    // Relations
118    pub participants: Vec<Handle>,
119    pub messages: Vec<Message>,
120}
121
122impl Chat {
123    /// Group chats have style == 43 in the chat.db.
124    pub fn is_group(&self) -> bool {
125        self.style == 43
126    }
127}
128
129/// A handle row from the `handle` table.
130#[derive(Debug, Clone, Default, Serialize)]
131pub struct Handle {
132    pub rowid: i64,
133    /// The `id` column in the DB (serialized as `address` in the API).
134    pub id: String,
135    pub country: Option<String>,
136    pub service: String,
137    pub uncanonicalized_id: Option<String>,
138}
139
140/// An attachment row from the `attachment` table.
141#[derive(Debug, Clone, Default, Serialize)]
142pub struct Attachment {
143    pub rowid: i64,
144    pub guid: String,
145    pub created_date: Option<i64>,
146    pub start_date: Option<i64>,
147    /// The `filename` column in the DB (the file path).
148    pub filename: Option<String>,
149    pub uti: Option<String>,
150    pub mime_type: Option<String>,
151    pub transfer_state: i64,
152    pub is_outgoing: bool,
153    pub user_info: Option<Vec<u8>>,
154    pub transfer_name: Option<String>,
155    pub total_bytes: i64,
156
157    pub is_sticker: Option<bool>,
158    pub sticker_user_info: Option<Vec<u8>>,
159    pub attribution_info: Option<Vec<u8>>,
160    pub hide_attachment: Option<bool>,
161    pub original_guid: Option<String>,
162}