From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: Alexander Adolf Newsgroups: gmane.emacs.devel Subject: Re: [Proposal] New EUDC backend for macOS address book Date: Wed, 06 May 2020 17:14:59 +0200 Message-ID: <8da7df5281e91d8a351f97c0837d79b7@condition-alpha.com> References: Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="4136"; mail-complaints-to="usenet@ciao.gmane.io" Cc: emacs-devel@gnu.org To: Thomas Fitzsimmons , Jean-Christophe Helary Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed May 06 17:16:07 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jWLmJ-0000pK-9e for ged-emacs-devel@m.gmane-mx.org; Wed, 06 May 2020 17:16:07 +0200 Original-Received: from localhost ([::1]:35646 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jWLmD-0006Ue-C9 for ged-emacs-devel@m.gmane-mx.org; Wed, 06 May 2020 11:16:01 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:40256) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jWLlM-0005Zj-T0 for emacs-devel@gnu.org; Wed, 06 May 2020 11:15:09 -0400 Original-Received: from smtprelay03.ispgateway.de ([80.67.31.26]:44406) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jWLlL-0000KX-4V for emacs-devel@gnu.org; Wed, 06 May 2020 11:15:08 -0400 Original-Received: from [46.244.197.96] (helo=localhost) by smtprelay03.ispgateway.de with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.92.3) (envelope-from ) id 1jWLlE-0004F2-9c; Wed, 06 May 2020 17:15:00 +0200 In-Reply-To: X-Df-Sender: YWxleGFuZGVyLmFkb2xmQGNvbmRpdGlvbi1hbHBoYS5jb20= Received-SPF: pass client-ip=80.67.31.26; envelope-from=alexander.adolf@condition-alpha.com; helo=smtprelay03.ispgateway.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/05/06 11:15:01 X-ACL-Warn: Detected OS = Linux 3.11 and newer [fuzzy] X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:249093 Archived-At: --=-=-= Content-Type: text/plain Hello Thomas, Jean-Christophe, Thomas Fitzsimmons writes: >>> [...] >>> Do you have a sense for how far back the AppleScript method will work? >>> [...] >> The application that is called in the applescript is called "Contacts". >> >> Before July 2012, when macos 10.8 was released, it was called "Address Book". >> >> So if the script wants to support machines with an OS older that 10.8 >> there will be a need to check the OS version and change the name of >> the application that is called. > [...] > Alexander, I see you report an error if osascript is not present. Can > you add a separate check via AppleScript for whether "Contacts" (or > failing that, "Address Book") is running and accessible? Then the user > would get a clear error if osascript can't access the application for > whatever reason. Thomas, thanks for pointing out the subtlety about the app naming which I had happily ignored ;-). Luckily, Apple provide a forward-compatibility-catchall in that when I do a `tell application "Address Book"` on a current macOS, it will "translate" this and connect to the right app (i.e. Contacts). This is of course to support legacy scripts (hidden goodness). Therefore, we can simply use `tell application "Address Book"`, and it will work on all 10.x macOS-es. > Can you also use the AppleScript line continuation character (U+00AC, > from what I can tell from some online searches) to wrap the longest line > to under 80 columns? I didn't know about U+00AC; cool. Done. > [...] > Alexander, given Jean-Christophe's research, and once the above > AppleScript-related comments are sorted out, I think this is fine to go > in, code-wise. Agree. I have added both above suggestions ("Contacts" vs. "Address Book", and U+00AC) to the attached, updated version. I have also amended the diagnostic error message to be more specific about the problem encountered. I have also folded the lengthy error message line to be below the 80 limit. Not sure whether this would be considered good practice? > Would you be able to write a section in the EUDC manual describing the > backend and how it relates to eudcb-mab.el? > > I don't think it hurts to offer both backends, provided they're > documented and contrasted in the EUDC manual. Yes, I'll be happy to write up a text for the manual. I agree that it would be good to offer both backends for a transition period. > [...] > diff --git a/lisp/net/eudcb-macos-contacts.el b/lisp/net/eudcb-macos-contacts.el > [...] Thanks for these improvements. All applied in the attached, updated version; except for the last one, which I solved differently. Many thanks and looking forward to your thoughts, --alexander --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=eudcb-macos-contacts.el Content-Transfer-Encoding: quoted-printable ;;; eudcb-macos-contacts.el --- EUDC - macOS Contacts backend ;; Copyright (C) 2020 condition-alpha.com ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; This library provides an interface to the macOS Contacts app as ;; an EUDC data source. It uses AppleScript to interface with the ;; Contacts app on localhost, so no 3rd party tools are needed. ;;; Usage: ;; (require 'eudcb-macos-contacts) ;; (eudc-macos-contacts-set-server "localhost") ;;; Code: (require 'eudc) (require 'executable) ;;{{{ Internal cooking (defvar eudc-macos-contacts-conversion-alist nil) ;; hook ourselves into the EUDC framework (eudc-protocol-set 'eudc-query-function 'eudc-macos-contacts-query-internal 'macos-contacts) (eudc-protocol-set 'eudc-list-attributes-function nil 'macos-contacts) (eudc-protocol-set 'eudc-macos-contacts-conversion-alist nil 'macos-contacts) (eudc-protocol-set 'eudc-protocol-has-default-query-attributes nil 'macos-contacts) (defun eudc-macos-contacts-search-helper (str) "Helper function to query the Contacts app via AppleScript. Searches for all persons with a case-insensitive substring match of STR in any of their name fields (first, middle, or last)." (if (executable-find "osascript") (call-process "osascript" nil t nil "-e" (format " set results to {} tell application \"Address Book\" set pList to every person whose (name contains \"%s\") repeat with pers in pList repeat with emailAddr in emails of pers set results to results & {name of pers & \":\" & value =C2=AC of emailAddr & \"\n\"} end repeat end repeat get results as text end tell" str)) (message (concat "[eudc] Error in macOS Contacts backend: " "`osascript' executable not found. " "Is this is a macOS 10.0 or later system?")))) (defun eudc-macos-contacts-query-internal (query &optional return-attrs) "Query macOS Contacts with QUERY. QUERY is a list of cons cells (ATTR . VALUE) where ATTRs should be valid macOS Contacts attribute names. RETURN-ATTRS is a list of attributes to return, defaulting to `eudc-default-return-attributes'." (let ((macos-contacts-buffer (get-buffer-create " *macOS Contacts*")) result) (with-current-buffer macos-contacts-buffer (erase-buffer) (dolist (term query) (eudc-macos-contacts-search-helper (cdr term))) (delete-duplicate-lines (point-min) (point-max)) (goto-char (point-min)) (while (not (eobp)) (if (not (equal (line-beginning-position) (line-end-position))) (let* ((args (split-string (buffer-substring (point) (line-end-position)) ":")) (name (nth 0 args)) (email (nth 1 args))) (setq result (cons `((name . ,name) (email . ,email)) result)))) (forward-line)) result))) ;;}}} ;;{{{ High-level interfaces (interactive functions) (defun eudc-macos-contacts-set-server (dummy) "Set the EUDC server to macOS Contacts app. The server in DUMMY is not actually used, since this backend always and implicitly connetcs to an instance of the Contacts app running on the local host." (interactive) (eudc-set-server dummy 'macos-contacts) (message "[eudc] macOS Contacts app server selected")) ;;}}} (eudc-register-protocol 'macos-contacts) (provide 'eudcb-macos-contacts) ;;; eudcb-macos-contacts.el ends here --=-=-=--