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
+12 -8
View File
@@ -61,7 +61,9 @@ final class AppleMailService {
/// the Apple-Events equivalent of `EKEventStore.authorizationStatus(for:)`, reusing the same /// the Apple-Events equivalent of `EKEventStore.authorizationStatus(for:)`, reusing the same
/// `PersonalDataAccessState` enum EventKitService/ContactsService/LocationMapsService use. /// `PersonalDataAccessState` enum EventKitService/ContactsService/LocationMapsService use.
var accessState: PersonalDataAccessState { 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 /// 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 /// 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 /// the user hasn't been asked yet (a no-op if already granted or denied). Deliberately NOT
/// user responds, so this must run off the main thread. /// 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 @discardableResult
func requestAccess() async -> Bool { func requestAccess() async -> Bool {
await withCheckedContinuation { continuation in
queue.async {
let status = Self.checkMailAutomationPermission(askUserIfNeeded: true) let status = Self.checkMailAutomationPermission(askUserIfNeeded: true)
continuation.resume(returning: status == 0) Log.mail.info("requestAccess: AEDeterminePermissionToAutomateTarget(askUserIfNeeded: true) returned \(status)")
} return status == 0
}
} }
private static func checkMailAutomationPermission(askUserIfNeeded: Bool) -> OSStatus { private static func checkMailAutomationPermission(askUserIfNeeded: Bool) -> OSStatus {