Skip to content

Commit ad137a9

Browse files
committed
Custom typing indicators
1 parent 8ac4a32 commit ad137a9

File tree

4 files changed

+30
-14
lines changed

4 files changed

+30
-14
lines changed

src/imessage/aps_client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ impl IMClient {
236236
cv_name: None,
237237
sender_guid: None,
238238
after_guid: None,
239-
}), Message::Typing(true)).ok())
239+
}), Message::Typing(true, None)).ok())
240240
}
241241

242242
// errors

src/imessage/messages.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,6 +1589,12 @@ impl SetTranscriptBackgroundMessage {
15891589
}
15901590
}
15911591

1592+
#[derive(Clone)]
1593+
pub struct TypingApp {
1594+
pub bundle_id: String,
1595+
pub icon: Vec<u8>,
1596+
}
1597+
15921598
#[repr(C)]
15931599
#[derive(Clone)]
15941600
pub enum Message {
@@ -1598,7 +1604,7 @@ pub enum Message {
15981604
React(ReactMessage),
15991605
Delivered,
16001606
Read,
1601-
Typing(bool),
1607+
Typing(bool, Option<TypingApp>),
16021608
Unsend(UnsendMessage),
16031609
Edit(EditMessage),
16041610
IconChange(IconChangeMessage),
@@ -1652,7 +1658,7 @@ impl Message {
16521658
Self::ChangeParticipants(_) => 190,
16531659
Self::Delivered => 101,
16541660
Self::Read => 102,
1655-
Self::Typing(_) => 100,
1661+
Self::Typing(_, _) => 100,
16561662
Self::Edit(_) => 118,
16571663
Self::Unsend(_) => 118,
16581664
Self::IconChange(_) => 190,
@@ -1730,7 +1736,7 @@ impl Message {
17301736
return Some(true)
17311737
}
17321738
match self {
1733-
Self::Typing(_) => Some(true),
1739+
Self::Typing(_, _) => Some(true),
17341740
Self::Delivered => Some(true),
17351741
Self::Edit(_) => Some(true),
17361742
Self::Unsend(_) => Some(true),
@@ -1772,7 +1778,7 @@ impl fmt::Display for Message {
17721778
Message::Delivered => {
17731779
write!(f, "delivered")
17741780
},
1775-
Message::Typing(typing) => {
1781+
Message::Typing(typing, _) => {
17761782
write!(f, "{}", if *typing { "typing" } else { "stopped typing" })
17771783
},
17781784
Message::Edit(e) => {
@@ -1932,7 +1938,7 @@ impl MessageInst {
19321938
match &self.message {
19331939
Message::Read => false,
19341940
Message::Delivered => false,
1935-
Message::Typing(typing) => self.conversation.as_ref().is_some_and(|a| a.participants.len() > 2) || !*typing,
1941+
Message::Typing(typing, app) => self.conversation.as_ref().is_some_and(|a| a.participants.len() > 2) || app.is_some() || !*typing,
19361942
Message::MessageReadOnDevice => false,
19371943
Message::PeerCacheInvalidate => false,
19381944
Message::Unschedule => false,
@@ -1943,7 +1949,7 @@ impl MessageInst {
19431949

19441950
pub fn get_ex(&self) -> Option<u32> {
19451951
match &self.message {
1946-
Message::Typing(_) => Some(0),
1952+
Message::Typing(_, _) => Some(0),
19471953
_ => None
19481954
}
19491955
}
@@ -1964,7 +1970,7 @@ impl MessageInst {
19641970

19651971
pub fn get_send_participants(&self, my_handles: &[String]) -> Vec<String> {
19661972
let mut target_participants = self.conversation.as_ref().unwrap().participants.clone();
1967-
if let Message::Delivered | Message::Typing(_) = self.message {
1973+
if let Message::Delivered | Message::Typing(_, _) = self.message {
19681974
// do not send delivery reciepts to other devices on same acct
19691975
target_participants.retain(|p| {
19701976
!my_handles.contains(p)
@@ -2127,16 +2133,18 @@ impl MessageInst {
21272133
};
21282134
plist_to_bin(&raw).unwrap()
21292135
},
2130-
Message::Typing(typing) => {
2136+
Message::Typing(typing, app) => {
21312137
let raw = RawEncryptedTyping {
2132-
participants: conversation.participants.clone(),
2138+
participants: Some(conversation.participants.clone()),
21332139
sender_guid: conversation.sender_guid.clone(),
21342140
pv: 0,
21352141
gv: "8".to_string(),
21362142
v: if !*typing { Some("1".to_string()) } else { None },
21372143
cv_name: conversation.cv_name.clone(),
21382144
gt: if conversation.participants.len() > 2 { Some(true) } else { None },
21392145
u: if *typing { Some(true) } else { None },
2146+
bundle_id: app.as_ref().map(|a| a.bundle_id.clone()),
2147+
icon: app.as_ref().map(|a| gzip_normal(&a.icon).unwrap().into()),
21402148
..Default::default()
21412149
};
21422150

@@ -2508,12 +2516,16 @@ impl MessageInst {
25082516
}
25092517
if wrapper.is_typing == Some(0) {
25102518
if let Ok(loaded) = plist::from_value::<RawEncryptedTyping>(&value) {
2519+
debug!("Got typing");
25112520
return wrapper.to_message(Some(ConversationData {
2512-
participants: loaded.participants.clone(),
2521+
participants: loaded.participants.clone().unwrap_or(vec![wrapper.sender.clone().expect("No sender?"), wrapper.target.clone().expect("No target?")]),
25132522
cv_name: loaded.cv_name.clone(),
25142523
sender_guid: loaded.sender_guid.clone(),
25152524
after_guid: None,
2516-
}), Message::Typing(loaded.u == Some(true)));
2525+
}), Message::Typing(loaded.u == Some(true), if let (Some(bid), Some(icon)) = (&loaded.bundle_id, loaded.icon) { Some(TypingApp {
2526+
bundle_id: bid.clone(),
2527+
icon: ungzip(icon.as_ref())?,
2528+
}) } else { None }));
25172529
}
25182530
}
25192531
if let Ok(loaded) = plist::from_value::<RawSmsDeactivateMessage>(&value) {

src/imessage/rawmessages.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,11 @@ struct RawMMCSBalloon {
370370
struct RawEncryptedTyping {
371371
pv: u32,
372372
#[serde(rename = "p")]
373-
participants: Vec<String>,
373+
participants: Option<Vec<String>>,
374+
#[serde(rename = "tic")]
375+
icon: Option<Data>,
376+
#[serde(rename = "bid")]
377+
bundle_id: Option<String>,
374378
u: Option<bool>,
375379
gt: Option<bool>,
376380
#[serde(rename = "gid")]

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use async_trait::async_trait;
3333
pub use mmcs::{FileContainer, prepare_put};
3434
pub use omnisette::AnisetteProvider;
3535
use icloud_auth::LoginClientInfo;
36-
pub use imessage::messages::{SetTranscriptBackgroundMessage, UpdateProfileMessage, UpdateProfileSharingMessage, MessageInst, ShareProfileMessage, SharedPoster, ScheduleMode, PermanentDeleteMessage, OperatedChat, DeleteTarget, MoveToRecycleBinMessage, TextFormat, TextEffect, TextFlags, LinkMeta, LPLinkMetadata, ReactMessageType, ErrorMessage, Reaction, UnsendMessage, EditMessage, UpdateExtensionMessage, PartExtension, ReactMessage, ChangeParticipantMessage, LPImageMetadata, RichLinkImageAttachmentSubstitute, LPIconMetadata, AttachmentType, ExtensionApp, BalloonLayout, Balloon, ConversationData, Message, MessageType, Attachment, NormalMessage, RenameMessage, IconChangeMessage, MessageParts, MessagePart, MMCSFile, IndexedMessagePart};
36+
pub use imessage::messages::{TypingApp, SetTranscriptBackgroundMessage, UpdateProfileMessage, UpdateProfileSharingMessage, MessageInst, ShareProfileMessage, SharedPoster, ScheduleMode, PermanentDeleteMessage, OperatedChat, DeleteTarget, MoveToRecycleBinMessage, TextFormat, TextEffect, TextFlags, LinkMeta, LPLinkMetadata, ReactMessageType, ErrorMessage, Reaction, UnsendMessage, EditMessage, UpdateExtensionMessage, PartExtension, ReactMessage, ChangeParticipantMessage, LPImageMetadata, RichLinkImageAttachmentSubstitute, LPIconMetadata, AttachmentType, ExtensionApp, BalloonLayout, Balloon, ConversationData, Message, MessageType, Attachment, NormalMessage, RenameMessage, IconChangeMessage, MessageParts, MessagePart, MMCSFile, IndexedMessagePart};
3737
pub use imessage::aps_client::{IMClient, MADRID_SERVICE};
3838
use util::encode_hex;
3939
pub use util::{NSArrayClass, ResourceState, NSDictionaryClass, NSURL, NSArray, ResourceFailure};

0 commit comments

Comments
 (0)