Skip to content

Commit f14ad5e

Browse files
committed
-
1 parent 1509252 commit f14ad5e

5 files changed

Lines changed: 35 additions & 16 deletions

File tree

src/api.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ function getDNDState() {
4747
return new Set(arr)
4848
}
4949
export default class AppleiMessage implements PlatformAPI {
50-
currentUser: CurrentUser | undefined
50+
constructor(public readonly accountID: string) {}
5151

52-
// private accountID: string
52+
currentUser: CurrentUser | undefined
5353

5454
private threadReadStore?: ThreadReadStore
5555

@@ -148,7 +148,6 @@ export default class AppleiMessage implements PlatformAPI {
148148

149149
init = async (session: SerializedSession, { dataDirPath }: ClientContext, prefs?: Record<string, any>) => {
150150
this.session = session || {}
151-
// this.accountID = accountID
152151
const userDataDirPath = path.dirname(dataDirPath)
153152
this.experiments = await fs.readFile(path.join(userDataDirPath, 'imessage-enabled-experiments'), 'utf-8').catch(() => '')
154153
if (swiftServer) {
@@ -359,6 +358,7 @@ export default class AppleiMessage implements PlatformAPI {
359358
texts.error(`imsg/getThreads: couldn't log hashed ids: ${err}`)
360359
}
361360
const items = mapThreads(chatRows, {
361+
accountID: this.accountID,
362362
mapMessageArgsMap,
363363
handleRowsMap,
364364
chatImagesMap,
@@ -393,7 +393,7 @@ export default class AppleiMessage implements PlatformAPI {
393393
db.getAttachments(msgRowIDs),
394394
db.getMessageReactions(msgGUIDs, { type: 'guid', guid: threadID }),
395395
])
396-
const items = mapMessages(msgRows, attachmentRows, reactionRows, this.currentUser!.id)
396+
const items = mapMessages(msgRows, attachmentRows, reactionRows, this.currentUser!.id, this.accountID)
397397
return {
398398
// NOTE(types): appease typescript, but we aren't actually using the texts SDK contract
399399
items: items.map(hashMessage) as Message[],
@@ -411,7 +411,7 @@ export default class AppleiMessage implements PlatformAPI {
411411
db.getAttachments([msgRow.ROWID]),
412412
db.getMessageReactions([msgRow.guid], { type: 'guid', guid: threadID }),
413413
])
414-
const items = mapMessages([msgRow], attachmentRows, reactionRows, this.currentUser!.id)
414+
const items = mapMessages([msgRow], attachmentRows, reactionRows, this.currentUser!.id, this.accountID)
415415
const message = items.find(i => i.id === messageID)
416416
// NOTE(types): appease typescript, but we aren't actually using the texts SDK contract
417417
return (message ? hashMessage(message) : message) as Message
@@ -440,7 +440,7 @@ export default class AppleiMessage implements PlatformAPI {
440440
db.getAttachments(msgRowIDs),
441441
threadID ? db.getMessageReactions(msgGUIDs, { type: 'guid', guid: threadID }) : [],
442442
])
443-
const items = mapMessages(msgRows, attachmentRows, reactionRows, this.currentUser!.id)
443+
const items = mapMessages(msgRows, attachmentRows, reactionRows, this.currentUser!.id, this.accountID)
444444
return {
445445
// NOTE(types): appease typescript, but we aren't actually using the texts SDK contract
446446
items: items.map(hashMessage) as Message[],
@@ -886,6 +886,15 @@ export default class AppleiMessage implements PlatformAPI {
886886
return url.pathToFileURL(filePath).href
887887
}
888888

889+
case 'reaction-sticker': {
890+
const reactionRowID = Number.parseInt(methodName, 10)
891+
if (!Number.isFinite(reactionRowID)) throw new Error("invalid reaction sticker row ID")
892+
const db = await this.ensureDB()
893+
const attachment = (await db.getAttachments([reactionRowID])).find(a => a.filePath)
894+
if (!attachment?.filePath) throw new Error("couldn't resolve sticker attachment for reaction row")
895+
return url.pathToFileURL(attachment.filePath).href
896+
}
897+
889898
default: {
890899
const filePath = Buffer.from(pathHex, 'hex').toString()
891900
const buffer = await fs.readFile(filePath)

src/constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const ASSOC_MSG_TYPE = {
1919
2004: 'reacted_emphasize',
2020
2005: 'reacted_question',
2121
2006: 'reacted_emoji',
22+
2007: 'reacted_sticker',
2223

2324
3000: 'unreacted_heart',
2425
3001: 'unreacted_like',
@@ -27,6 +28,7 @@ export const ASSOC_MSG_TYPE = {
2728
3004: 'unreacted_emphasize',
2829
3005: 'unreacted_question',
2930
3006: 'unreacted_emoji',
31+
3007: 'unreacted_sticker',
3032
} as const
3133

3234
export const REACTION_VERB_MAP = {
@@ -37,6 +39,7 @@ export const REACTION_VERB_MAP = {
3739
reacted_emphasize: 'emphasized',
3840
reacted_question: 'questioned',
3941
reacted_emoji: 'reacted to',
42+
reacted_sticker: 'reacted with a sticker to',
4043

4144
unreacted_heart: 'removed a heart from',
4245
unreacted_like: 'removed a like from',
@@ -45,6 +48,7 @@ export const REACTION_VERB_MAP = {
4548
unreacted_emphasize: 'removed an exclamation from',
4649
unreacted_question: 'removed a question mark from',
4750
unreacted_emoji: 'unreacted from',
51+
unreacted_sticker: 'removed a sticker from',
4852
} as const
4953

5054
export const EXPRESSIVE_MSGS = {

src/db-api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ FROM message AS m
8080
LEFT JOIN message_attachment_join AS maj ON maj.message_id = m.ROWID
8181
LEFT JOIN attachment AS a ON a.ROWID = maj.attachment_id
8282
WHERE m.ROWID IN (${new Array(msgIDs.length).fill('?').join(', ')})`,
83-
getMessageReactions: (msgGUIDs: string[]) => `SELECT is_from_me, handle_id, associated_message_type, associated_message_guid, ${IS_SEQUOIA_OR_UP ? 'associated_message_emoji,' : ''} h.id AS participantID
83+
getMessageReactions: (msgGUIDs: string[]) => `SELECT m.ROWID, is_from_me, handle_id, associated_message_type, associated_message_guid, ${IS_SEQUOIA_OR_UP ? 'associated_message_emoji,' : ''} h.id AS participantID
8484
FROM message AS m
8585
LEFT JOIN handle AS h ON m.handle_id = h.ROWID
8686
LEFT JOIN chat_message_join AS cmj ON cmj.message_id = m.ROWID
@@ -411,7 +411,7 @@ WHERE m.ROWID = ?`, rowID)
411411
private getMappedMessagesWithoutExtraRows = async (chatGUID: string, pagination?: PaginationArg) => {
412412
const msgRows = await this.getMessages(chatGUID, pagination)
413413
if (pagination?.direction !== 'after') msgRows.reverse()
414-
const items = mapMessages(msgRows, [], [], this.papi.currentUser!.id)
414+
const items = mapMessages(msgRows, [], [], this.papi.currentUser!.id, this.papi.accountID)
415415
return {
416416
items,
417417
hasMore: msgRows.length === MESSAGES_LIMIT,

src/mappers.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ const removeObjReplacementChar = (text: string): string => {
5959
return text.replaceAll(OBJ_REPLACEMENT_CHAR, ' ').trim()
6060
}
6161

62-
function assignReactions(currentUserID: string, message: BeeperMessage, _reactionRows: MappedReactionMessageRow[] = [], filterIndex?: number) {
62+
const reactionStickerAssetURL = (accountID: string, rowID: MappedReactionMessageRow['ROWID']) => `asset://${accountID}/reaction-sticker/${rowID}`
63+
64+
function assignReactions(currentUserID: string, accountID: string, message: BeeperMessage, _reactionRows: MappedReactionMessageRow[] = [], filterIndex?: number) {
6365
const reactions: MessageReaction[] = []
6466
const reactionRows = filterIndex != null
6567
? _reactionRows.filter(r => r.associated_message_guid.startsWith(`p:${filterIndex}/`))
@@ -75,6 +77,7 @@ function assignReactions(currentUserID: string, message: BeeperMessage, _reactio
7577
id: participantID,
7678
reactionKey: actionKey === 'emoji' ? reaction.associated_message_emoji : actionKey,
7779
participantID,
80+
imgURL: actionKey === 'sticker' ? reactionStickerAssetURL(accountID, reaction.ROWID) : undefined,
7881
})
7982
} else if (actionType === 'unreacted') {
8083
const index = reactions.findIndex(r => r.id === participantID)
@@ -241,7 +244,7 @@ const UUID_START = 11
241244
const UUID_LENGTH = 36
242245
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$/i
243246
// eslint-disable-next-line @typescript-eslint/default-param-last -- FIXME(skip)
244-
export function mapMessage(msgRow: MappedMessageRow, attachmentRows: MappedAttachmentRow[] = [], reactionRows: MappedReactionMessageRow[], currentUserID: string): BeeperMessage[] {
247+
export function mapMessage(msgRow: MappedMessageRow, attachmentRows: MappedAttachmentRow[] = [], reactionRows: MappedReactionMessageRow[], currentUserID: string, accountID: string): BeeperMessage[] {
245248
const attachments = attachmentRows.map(a => mapAttachment(a, msgRow)).filter(attachment => attachment != null)
246249
const isSMS = msgRow.service === 'SMS' || msgRow.service === 'RCS'
247250
const isGroup = !!msgRow.room_name
@@ -615,9 +618,10 @@ export function mapMessage(msgRow: MappedMessageRow, attachmentRows: MappedAttac
615618
type: reactionType,
616619
messageID: m.linkedMessageID,
617620
participantID: m.senderID,
621+
imgURL: assocMsgType === 'reacted_sticker' ? attachmentRows[0]?.filename : undefined,
618622
reactionKey: actionKey === 'emoji' ? msgRow.associated_message_emoji : actionKey,
619623
}
620-
if (actionKey === 'emoji' || actionKey in supportedReactions) {
624+
if (actionKey === 'emoji' || actionKey === 'sticker' || actionKey in supportedReactions) {
621625
m.parseTemplate = true
622626
m.text = `${msgRow.is_from_me ? 'You' : '{{sender}}'} ${REACTION_VERB_MAP[assocMsgType]} ${msi?.ams ? `"${msi?.ams}"` : 'a message'}`
623627
m.isHidden = true
@@ -629,7 +633,7 @@ export function mapMessage(msgRow: MappedMessageRow, attachmentRows: MappedAttac
629633

630634
return messages.map(msg => {
631635
// texts.log('assigning reactions', msg.id, msg.index, reactionRows)
632-
assignReactions(currentUserID, msg, reactionRows, messages.length === 1 ? undefined : msg.extra?.part)
636+
assignReactions(currentUserID, accountID, msg, reactionRows, messages.length === 1 ? undefined : msg.extra?.part)
633637
return msg
634638
})
635639
}
@@ -672,6 +676,7 @@ function mapParticipant({ participantID: id, uncanonicalized_id }: MappedHandleR
672676
export const mapAccountLogin = (al: string) => al?.replace(/^(E|P):/, '')
673677

674678
type Context = {
679+
accountID: string
675680
currentUserID: string
676681
handleRowsMap: { [threadID: string]: MappedHandleRow[] }
677682
mapMessageArgsMap: { [threadID: string]: [MappedMessageRow[], MappedAttachmentRow[], MappedReactionMessageRow[]] }
@@ -688,16 +693,16 @@ type Context = {
688693

689694
// @ts-expect-error FIXME(skip): argument ordering
690695
// eslint-disable-next-line @typescript-eslint/default-param-last
691-
export function mapMessages(messages: MappedMessageRow[], attachmentRows?: MappedAttachmentRow[], reactionRows?: MappedReactionMessageRow[], currentUserID: string): BeeperMessage[] {
696+
export function mapMessages(messages: MappedMessageRow[], attachmentRows?: MappedAttachmentRow[], reactionRows?: MappedReactionMessageRow[], currentUserID: string, accountID: string): BeeperMessage[] {
692697
const groupedAttachmentRows = groupBy(attachmentRows, 'msgRowID')
693698
const groupedReactionRows = groupBy(reactionRows, r => r.associated_message_guid.replace(assocMsgGuidPrefix, ''))
694699
return messages
695-
.flatMap(message => mapMessage(message, groupedAttachmentRows[message.ROWID], groupedReactionRows[message.guid], currentUserID))
700+
.flatMap(message => mapMessage(message, groupedAttachmentRows[message.ROWID], groupedReactionRows[message.guid], currentUserID, accountID))
696701
.filter(Boolean)
697702
}
698703

699704
export function mapThread(chat: MappedChatRow, context: Context): BeeperThread {
700-
const { currentUserID } = context
705+
const { currentUserID, accountID } = context
701706
const handleRows = context.handleRowsMap[chat.guid]
702707
const mapMessageArgs = context.mapMessageArgsMap?.[chat.guid]
703708
const selfID = chat.last_addressed_handle || mapAccountLogin(chat.account_login) || currentUserID
@@ -707,7 +712,7 @@ export function mapThread(chat: MappedChatRow, context: Context): BeeperThread {
707712
const participants = [...handleRows.map(h => mapParticipant(h, chat.display_name)), selfParticipant].filter(participant => participant != null)
708713
const isGroup = !!chat.room_name
709714
const isReadOnly = chat.state === 0 && chat.properties != null
710-
const messages = mapMessageArgs ? mapMessages(...mapMessageArgs, currentUserID) : []
715+
const messages = mapMessageArgs ? mapMessages(...mapMessageArgs, currentUserID, accountID) : []
711716
/*
712717
props = {
713718
"com.apple.iChat.LastArchivedMessageID": [ 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', 101010 ],

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ export type MappedMessageRow = MessageRow & {
175175
// db-api.ts -> SQLS
176176
export type MappedReactionMessageRow = Pick<
177177
MappedMessageRow,
178+
'ROWID' |
178179
'is_from_me' |
179180
'handle_id' |
180181
'associated_message_type' |

0 commit comments

Comments
 (0)