Fix Request Access button doing nothing: run permission prompt on main thread

requestAccess() was dispatched onto the background queue used for
AppleScript execution, on the assumption that a blocking call needed to
be off-main. That's backwards for AEDeterminePermissionToAutomateTarget's
consent dialog — like this app's existing NSAlert.runModal() calls, it
needs to run on the main thread/run loop to actually display. Off-main,
it silently returned without ever showing a prompt or changing state.

Also added Log.mail diagnostics on both the status-only check and the
prompting call so a future report of "still doesn't work" has an actual
status code to look at instead of starting from scratch.
This commit is contained in:
2026-08-19 14:13:56 +02:00
parent 21d598d88a
commit da7bce26a2
+13 -9
View File
@@ -61,7 +61,9 @@ final class AppleMailService {
/// the Apple-Events equivalent of `EKEventStore.authorizationStatus(for:)`, reusing the same
/// `PersonalDataAccessState` enum EventKitService/ContactsService/LocationMapsService use.
var accessState: PersonalDataAccessState {
Self.mapAutomationPermissionStatus(Self.checkMailAutomationPermission(askUserIfNeeded: false))
let status = Self.checkMailAutomationPermission(askUserIfNeeded: false)
Log.mail.debug("accessState: AEDeterminePermissionToAutomateTarget(askUserIfNeeded: false) returned \(status)")
return Self.mapAutomationPermissionStatus(status)
}
/// Pure mapping from an `AEDeterminePermissionToAutomateTarget` status code to the shared
@@ -75,16 +77,18 @@ final class AppleMailService {
}
/// Triggers the real macOS "Confab wants to control Mail" Automation permission prompt if
/// the user hasn't been asked yet (a no-op if already granted or denied). Blocks until the
/// user responds, so this must run off the main thread.
/// the user hasn't been asked yet (a no-op if already granted or denied). Deliberately NOT
/// dispatched to the background `queue` used for AppleScript execution the system consent
/// prompt needs to be raised from the main thread/run loop to actually display (same as this
/// codebase's existing blocking `NSAlert.runModal()` calls); calling it off-main appears to
/// silently fail (no dialog, no error, no state change the exact symptom Rune hit live).
/// `AppleMailService` has no explicit actor annotation, so under this project's
/// `-default-isolation=MainActor` build setting this method already runs on the main actor.
@discardableResult
func requestAccess() async -> Bool {
await withCheckedContinuation { continuation in
queue.async {
let status = Self.checkMailAutomationPermission(askUserIfNeeded: true)
continuation.resume(returning: status == 0)
}
}
let status = Self.checkMailAutomationPermission(askUserIfNeeded: true)
Log.mail.info("requestAccess: AEDeterminePermissionToAutomateTarget(askUserIfNeeded: true) returned \(status)")
return status == 0
}
private static func checkMailAutomationPermission(askUserIfNeeded: Bool) -> OSStatus {