[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 814e3b0: EUDC: Add macOS Contacts backend

From: Thomas Fitzsimmons
Subject: master 814e3b0: EUDC: Add macOS Contacts backend
Date: Thu, 9 Jul 2020 16:19:47 -0400 (EDT)

branch: master
commit 814e3b0b17bce65afb1d487167c1ce7291ddcf4d
Author: Alexander Adolf <alexander.adolf@condition-alpha.com>
Commit: Thomas Fitzsimmons <fitzsim@fitzsim.org>

    EUDC: Add macOS Contacts backend
    * lisp/net/eudcb-macos-contacts.el: New file.
    * doc/misc/eudc.texi (macOS Contacts): New section.
    (macOS Contacts Configuration): Likewise.
    * etc/NEWS: Mention new macOS Contacts backend.
 doc/misc/eudc.texi               |  52 +++++++++++++++++
 etc/NEWS                         |   7 +++
 lisp/net/eudcb-macos-contacts.el | 118 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 177 insertions(+)

diff --git a/doc/misc/eudc.texi b/doc/misc/eudc.texi
index 701340e..4ead603 100644
--- a/doc/misc/eudc.texi
+++ b/doc/misc/eudc.texi
@@ -83,6 +83,8 @@ Currently supported back-ends are:
 LDAP, Lightweight Directory Access Protocol
 BBDB, Big Brother's Insidious Database
+macOS Contacts
 @end itemize
 The main features of the EUDC interface are:
@@ -107,6 +109,7 @@ Interface to BBDB to let you insert server records into 
your own BBDB database
 * LDAP::                        What is LDAP ?
 * BBDB::                        What is BBDB ?
+* macOS Contacts::              What is macOS Contacts ?
 @end menu
@@ -159,6 +162,21 @@ queries on multiple servers.
 EUDC also offers a means to insert results from directory queries into
 your own local BBDB (@pxref{Creating BBDB Records})
+@node macOS Contacts
+@section macOS Contacts
+macOS Contacts is the rolodex-like application that ships with the
+macOS operating system@footnote{Apple have changed the names of their
+operating system and some applications over time.  macOS used to be
+called Mac OS X in the past, and the Contacts application was
+previously called Address Book.}.
+EUDC considers macOS Contacts as a directory server back end just like
+LDAP, though the macOS Contacts application always resides locally on
+your machine.
 @node Installation
 @chapter Installation
@@ -185,6 +203,7 @@ email composition buffers (@pxref{Inline Query Expansion})
 * LDAP Configuration::           EUDC needs external support for LDAP
+* macOS Contacts Configuration:: Enable the macOS Contacts backend
 @end menu
 @node LDAP Configuration
@@ -379,6 +398,39 @@ The @command{ldapsearch} command is formatted such that it 
can be
 copied and pasted into a terminal.  Set the @command{ldapsearch} debug
 level to 5 by appending @code{-d 5} to the command line.
+@node macOS Contacts Configuration
+@section macOS Contacts Configuration
+macOS Contacts support is added by means of @file{eudcb-mab.el}, or
+@file{eudcb-macos-contacts.el} which are part of Emacs.
+To enable a macOS Contacts backend, first `require' the respective
+library to load it, and then set the `eudc-server' to localhost in
+your init file:
+(require 'eudcb-macos-contacts)
+(eudc-macos-contacts-set-server "localhost")
+@end lisp
+@file{eudcb-macos-contacts.el} uses the public scripting interfaces
+offered by the Contacts app via the macOS Open Scripting Architecture
+(OSA).  To accomplish this, @file{eudcb-macos-contacts.el} uses an
+external command line utility named osascript, which is included with
+all macOS versions since 10.0 (which was released 2001).
+@file{eudcb-macos-contacts.el} is hence recommended for all new
+@file{eudcb-mab.el} reverse engineers the format of the database file
+used by the macOS Contacts app, and accesses its contents directly.
+While this may promise some performance advantages, it comes at the
+cost of using an undocumented interface.  Hence, users of
+@file{eudcb-mab.el} are recommended to double check the compatibility
+of @file{eudcb-mab.el} before upgrading to a new version of macOS.
+@file{eudcb-mab.el} is retained for backwards compatibility with
+existing configurations, and may be removed in a future release.
 @node Usage
 @chapter Usage
diff --git a/etc/NEWS b/etc/NEWS
index 07403f2..e55f57e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -279,6 +279,13 @@ This allows users to use (define-key eshell-mode-map ...) 
as usual.
 Some modules have their own minor mode now to account for these
+** EUDC
+*** New macOS Contacts backend.
+This backend works on newer versions of macOS and is generally
+preferred over the eudcb-mab.el backend.
 ** Tramp
diff --git a/lisp/net/eudcb-macos-contacts.el b/lisp/net/eudcb-macos-contacts.el
new file mode 100644
index 0000000..f258d5c
--- /dev/null
+++ b/lisp/net/eudcb-macos-contacts.el
@@ -0,0 +1,118 @@
+;;; 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
+;; 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 <https://www.gnu.org/licenses/>.
+;;; 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 ¬
+                       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
+  (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

reply via email to

[Prev in Thread] Current Thread [Next in Thread]