Skip to content

Commit aafe3f3

Browse files
committed
fix: prefer chat guid for chat_id sends
1 parent ab86177 commit aafe3f3

File tree

8 files changed

+62
-9
lines changed

8 files changed

+62
-9
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Changelog
22

3-
## Unreleased (0.3.1)
3+
## Unreleased (0.3.2)
4+
- fix: prefer chat guid for chat_id sends to avoid 1:1 AppleScript errors (thanks @mshuffett)
45
- chore: replace pnpm scripts with make targets
56
- build: add universal binary build helper
67
- ci: switch to make-based lint/test/build

Sources/IMsgCore/MessageSender.swift

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,12 @@ public struct MessageSender {
5151

5252
public func send(_ options: MessageSendOptions) throws {
5353
var resolved = options
54-
let chatTarget = resolved.chatIdentifier.isEmpty ? resolved.chatGUID : resolved.chatIdentifier
54+
let chatTarget = resolveChatTarget(&resolved)
5555
let useChat = !chatTarget.isEmpty
5656
if useChat == false {
5757
if resolved.region.isEmpty { resolved.region = "US" }
5858
resolved.recipient = normalizer.normalize(resolved.recipient, region: resolved.region)
5959
if resolved.service == .auto { resolved.service = .imessage }
60-
} else if chatTarget.isEmpty {
61-
throw IMsgError.invalidChatTarget("Missing chat identifier or guid")
6260
}
6361

6462
try sendViaAppleScript(resolved, chatTarget: chatTarget, useChat: useChat)
@@ -124,6 +122,36 @@ public struct MessageSender {
124122
"""
125123
}
126124

125+
private func resolveChatTarget(_ options: inout MessageSendOptions) -> String {
126+
let guid = options.chatGUID.trimmingCharacters(in: .whitespacesAndNewlines)
127+
if !guid.isEmpty {
128+
return guid
129+
}
130+
let identifier = options.chatIdentifier.trimmingCharacters(in: .whitespacesAndNewlines)
131+
if identifier.isEmpty {
132+
return ""
133+
}
134+
if looksLikeHandle(identifier) {
135+
if options.recipient.isEmpty {
136+
options.recipient = identifier
137+
}
138+
return ""
139+
}
140+
return identifier
141+
}
142+
143+
private func looksLikeHandle(_ value: String) -> Bool {
144+
let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
145+
if trimmed.isEmpty { return false }
146+
let lower = trimmed.lowercased()
147+
if lower.hasPrefix("imessage:") || lower.hasPrefix("sms:") || lower.hasPrefix("auto:") {
148+
return true
149+
}
150+
if trimmed.contains("@") { return true }
151+
let allowed = CharacterSet(charactersIn: "+0123456789 ()-")
152+
return trimmed.rangeOfCharacter(from: allowed.inverted) == nil
153+
}
154+
127155
private static func runAppleScript(source: String, arguments: [String]) throws {
128156
guard let script = NSAppleScript(source: source) else {
129157
throw IMsgError.appleScriptFailure("Unable to compile AppleScript")

Sources/imsg/Resources/Info.plist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
<key>CFBundlePackageType</key>
1212
<string>APPL</string>
1313
<key>CFBundleShortVersionString</key>
14-
<string>0.3.1</string>
14+
<string>0.3.2</string>
1515
<key>CFBundleVersion</key>
16-
<string>0.3.1</string>
16+
<string>0.3.2</string>
1717
<key>NSAppleEventsUsageDescription</key>
1818
<string>Send messages via Messages.app.</string>
1919
</dict>

Sources/imsg/Version.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// Generated by scripts/generate-version.sh. Do not edit.
22
enum IMsgVersion {
3-
static let current = "0.3.1"
3+
static let current = "0.3.2"
44
}

Tests/IMsgCoreTests/UtilityTests.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,33 @@ func messageSenderUsesChatIdentifier() throws {
155155
chatGUID: "ignored-guid"
156156
)
157157
)
158-
#expect(captured[5] == "iMessage;+;chat123")
158+
#expect(captured[5] == "ignored-guid")
159159
#expect(captured[6] == "1")
160160
#expect(captured[4] == "1")
161161
}
162162

163+
@Test
164+
func messageSenderTreatsHandleIdentifierAsRecipient() throws {
165+
var captured: [String] = []
166+
let sender = MessageSender(runner: { _, args in
167+
captured = args
168+
})
169+
try sender.send(
170+
MessageSendOptions(
171+
recipient: "",
172+
text: "hi",
173+
attachmentPath: "",
174+
service: .auto,
175+
region: "US",
176+
chatIdentifier: "+16502530000",
177+
chatGUID: ""
178+
)
179+
)
180+
#expect(captured[0] == "+16502530000")
181+
#expect(captured[5].isEmpty)
182+
#expect(captured[6] == "0")
183+
}
184+
163185
@Test
164186
func errorDescriptionsIncludeDetails() {
165187
let error = IMsgError.invalidService("weird")

Tests/imsgTests/CommandTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func sendCommandResolvesChatID() async throws {
192192
})
193193
#expect(captured?.chatIdentifier == "+123")
194194
#expect(captured?.chatGUID == "iMessage;+;chat123")
195+
#expect(captured?.recipient.isEmpty == true)
195196
}
196197

197198
@Test

Tests/imsgTests/RPCServerTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ func rpcSendResolvesChatID() async throws {
171171

172172
#expect(captured?.chatIdentifier == "iMessage;+;chat123")
173173
#expect(captured?.chatGUID == "iMessage;+;chat123")
174+
#expect(captured?.recipient.isEmpty == true)
174175
#expect(output.responses.first?["result"] as? [String: Any] != nil)
175176
}
176177

version.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
MARKETING_VERSION=0.3.1
1+
MARKETING_VERSION=0.3.2

0 commit comments

Comments
 (0)