[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 536ef75: * externals-list: Convert excorporate to :externa
From: |
Stefan Monnier |
Subject: |
[elpa] master 536ef75: * externals-list: Convert excorporate to :external |
Date: |
Sun, 29 Nov 2020 15:43:20 -0500 (EST) |
branch: master
commit 536ef75e77446cd44f6a738d74c600510ce5b4f9
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>
* externals-list: Convert excorporate to :external
---
externals-list | 3 +-
packages/excorporate/NEWS | 132 ---
packages/excorporate/README | 40 -
packages/excorporate/dir | 18 -
packages/excorporate/excorporate-calendar.el | 46 -
packages/excorporate/excorporate-calfw.el | 151 ----
packages/excorporate/excorporate-diary.el | 322 -------
packages/excorporate/excorporate-org.el | 364 --------
packages/excorporate/excorporate.el | 1212 --------------------------
packages/excorporate/excorporate.info | 746 ----------------
packages/excorporate/excorporate.texi | 798 -----------------
11 files changed, 2 insertions(+), 3830 deletions(-)
diff --git a/externals-list b/externals-list
index 9b2b310..b1ee27a 100644
--- a/externals-list
+++ b/externals-list
@@ -86,6 +86,7 @@
("emms" :external "https://git.savannah.gnu.org/git/emms.git")
("enwc" :external
"hg::https://hg.savannah.nongnu.org/hgweb/enwc/")
("ergoemacs-mode" :external
"https://github.com/ergoemacs/ergoemacs-mode.git")
+ ("excorporate" :external nil)
("expand-region" :external "https://github.com/magnars/expand-region.el")
("exwm" :external "https://github.com/ch11ng/exwm.git")
("f90-interface-browser" :external "https://github.com/wence-/f90-iface")
@@ -99,7 +100,7 @@
("gnome-c-style" :external "https://github.com/ueno/gnome-c-style.git")
("gnorb" :external nil) ;; Was "https://github.com/girzel/gnorb"
("gnu-elpa" :external nil)
- ("gnugo" :external nil)
+ ("gnugo" :external nil)
("gpastel" :external
"https://gitlab.petton.fr/DamienCassou/gpastel")
("greader" :external
"https://gitlab.com/michelangelo-rodriguez/greader")
("guess-language" :external
"https://github.com/tmalsburg/guess-language.el")
diff --git a/packages/excorporate/NEWS b/packages/excorporate/NEWS
deleted file mode 100644
index 8b73280..0000000
--- a/packages/excorporate/NEWS
+++ /dev/null
@@ -1,132 +0,0 @@
-GNU Emacs Excorporate NEWS -- history of user-visible changes.
-
-* Excorporate 0.9.1
-
-Released 2020-10-05
-
-** Change default behaviour of decline, accept and tenatitvely-accept functions
-
-Always prompt for a response message in
-exco-org-decline-meeting-request, exco-org-accept-meeting-request, and
-exco-org-tentatively-accept-meeting-request, unless a prefix argument
-is specified.
-
-** Allow force-deleting calendar items
-
-Take a prefix argument to exco-org-delete-appointment to force-delete
-the calendar item at point in the *Excorporate* Org buffer.
-
-* Excorporate 0.9.0
-
-Released 2020-09-30
-
-** Add interactive exco-org meeting and appointment cancellation functions
-
-** Add interactive exco-org meeting reply functions
-
-** Add meeting and appointment creation functions
-
-** Add meeting organizer to Org entries
-
-** Add API Usage section to the manual, with several examples
-
-* Excorporate 0.8.3
-
-Released 2019-06-18
-
-** Fix appt percent-encoded URL printing
-
-** Update HTTP debugging steps in Info manual
-
-* Excorporate 0.8.2
-
-Released 2019-06-14
-
-** Enable multiple connections
-
-The excorporate-configuration variable can now be a list representing
-multiple servers. The excorporate function will create one connection
-per server configured. Connections to additional servers can be
-dynamically created by passing a prefix argument to the excorporate
-function.
-
-* Excorporate 0.8.1
-
-Released 2018-09-15
-
-** Depend on nadvice 0.3
-
-This fixes excorporate-diary-enable on Emacs 24.1, 24.2, and 24.3.
-
-* Excorporate 0.8.0
-
-Released 2018-09-13
-
-** Add functions for retrieving meeting details
-
-** Add diary support
-
-M-x excorporate
-M-x excorporate-diary-enable
-M-x calendar
-Press `d'
-
-** Add appt support
-
-After you've retrieved today's meetings, several minutes before the
-start of the next meeting a reminder window will pop up.
-
-If Emacs is left running overnight, it will display tomorrow's
-meetings at 12:01 AM.
-
-* Excorporate 0.7.7
-
-Released 2018-09-04
-
-** Enable calfw support
-
-* Excorporate 0.7.6
-
-Released 2016-10-05
-
-** Require some NTLM compatibility fixes via updated dependencies
-
-* Excorporate 0.7.5
-
-Released 2016-06-16
-
-** Interoperate with `save-some-buffers'
-
-* Excorporate 0.7.4
-
-Released 2016-06-15
-
-** Interoperate with `org-startup-with-latex-preview'
-
-* Excorporate 0.7.3
-
-Released 2016-04-01
-
-** Bind q to quit-window in Org mode backend
-
-* Excorporate 0.7.2
-
-Released 2016-03-16
-
-** Support Office 365 and Exchange 2010_SP1
-
-* Excorporate 0.7.1
-
-Released 2016-02-26
-
-** Add Info manual
-
-* Excorporate 0.7.0
-
-Released 2016-02-21
-
-** First release in GNU ELPA
-
-Local variables:
-mode: outline
-end:
diff --git a/packages/excorporate/README b/packages/excorporate/README
deleted file mode 100644
index 9dbf599..0000000
--- a/packages/excorporate/README
+++ /dev/null
@@ -1,40 +0,0 @@
-Excorporate provides Exchange integration for Emacs.
-
-Most Recent Improvements
-------------------------
-
-New in Excorporate 0.9.1, released 2020-10-05:
-
-** Change default behaviour of decline, accept and tenatitvely-accept functions
-
-Always prompt for a response message in
-exco-org-decline-meeting-request, exco-org-accept-meeting-request, and
-exco-org-tentatively-accept-meeting-request, unless a prefix argument
-is specified.
-
-** Allow force-deleting calendar items
-
-Take a prefix argument to exco-org-delete-appointment to force-delete
-the calendar item at point in the *Excorporate* Org buffer.
-
-Quick Start
------------
-
-To create a connection to a web service:
-
-M-x excorporate
-
-Excorporate will prompt for an email address that it will use to
-automatically discover settings. Then it will prompt you for your
-credentials two or three times depending on the server configuration.
-
-You should see a message indicating that the connection is ready
-either in the minibuffer or in the *Messages* buffer.
-
-Finally, run M-x calendar, and press 'e' to show today's meetings.
-
-If autodiscovery fails, customize `excorporate-configuration' to skip
-autodiscovery.
-
-For further information including connection troubleshooting, see the
-Excorporate Info node at C-h i d m Excorporate.
diff --git a/packages/excorporate/dir b/packages/excorporate/dir
deleted file mode 100644
index c0433c3..0000000
--- a/packages/excorporate/dir
+++ /dev/null
@@ -1,18 +0,0 @@
-This is the file .../info/dir, which contains the
-topmost node of the Info hierarchy, called (dir)Top.
-The first time you invoke Info you start off looking at this node.
-
-File: dir, Node: Top This is the top of the INFO tree
-
- This (the Directory node) gives a menu of major topics.
- Typing "q" exits, "?" lists all Info commands, "d" returns here,
- "h" gives a primer for first-timers,
- "mEmacs<Return>" visits the Emacs manual, etc.
-
- In Emacs, you can click mouse button 2 on a menu item or cross reference
- to select it.
-
-* Menu:
-
-Emacs
-* Excorporate: (excorporate). Exchange Web Services integration for Emacs.
diff --git a/packages/excorporate/excorporate-calendar.el
b/packages/excorporate/excorporate-calendar.el
deleted file mode 100644
index 506ac72..0000000
--- a/packages/excorporate/excorporate-calendar.el
+++ /dev/null
@@ -1,46 +0,0 @@
-;;; excorporate-calendar.el --- Exchange for calendar -*- lexical-binding: t
-*-
-
-;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
-
-;; Author: Thomas Fitzsimmons <fitzsim@fitzsim.org>
-;; Keywords: calendar
-
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Add a calendar keybinding for Excorporate. Default to the
-;; excorporate-org interface.
-
-;;; Code:
-
-(require 'calendar)
-
-(defcustom excorporate-calendar-show-day-function 'exco-org-show-day
- "A function to be called by pressing `e' in Calendar."
- :type 'function
- :group 'excorporate)
-
-(defun exco-calendar-show-day ()
- "Show meetings for the selected date."
- (interactive)
- (apply excorporate-calendar-show-day-function (calendar-cursor-to-date t)))
-
-;; I arrogantly claim "e" for now, but irresponsibly reserve the right
-;; to change it later.
-(define-key calendar-mode-map "e" #'exco-calendar-show-day)
-
-(provide 'excorporate-calendar)
-
-;;; excorporate-calendar.el ends here
diff --git a/packages/excorporate/excorporate-calfw.el
b/packages/excorporate/excorporate-calfw.el
deleted file mode 100644
index 5eda6e4..0000000
--- a/packages/excorporate/excorporate-calfw.el
+++ /dev/null
@@ -1,151 +0,0 @@
-;;; excorporate-calfw.el --- Exchange calendar view -*- lexical-binding: t
-*-
-
-;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
-
-;; Author: Thomas Fitzsimmons <fitzsim@fitzsim.org>
-;; Keywords: calendar
-
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Use the Calfw calendar framework to display daily meetings.
-
-;; To use this handler, set excorporate-calendar-show-day to
-;; exco-calfw-show-day using `customize-variable'.
-
-;; This Excorporate handler requires the Calfw package, which is not
-;; included in GNU ELPA because not all Calfw contributors have
-;; copyright assignment papers on file with the FSF.
-
-;;; Code:
-
-;; calfw is not FSF-assigned yet so it is not in GNU ELPA. The
-;; following workarounds allow excorporate-calfw.elc to be built
-;; regardless.
-(require 'calfw nil t)
-
-(declare-function cfw:component-model "ext:calfw" t)
-(declare-function cfw:cp-add-selection-change-hook "ext:calfw" t)
-(declare-function cfw:cp-get-contents-sources "ext:calfw" t)
-(declare-function cfw:create-calendar-component-buffer "ext:calfw" t)
-(declare-function cfw:cursor-to-nearest-date "ext:calfw" t)
-(declare-function cfw:date "ext:calfw" t)
-(declare-function cfw:model-set-contents-sources "ext:calfw" t)
-(declare-function cfw:refresh-calendar-buffer "ext:calfw" t)
-(declare-function make-cfw:event "ext:calfw" t)
-(declare-function make-cfw:source "ext:calfw" t)
-
-(defvar cfw:component)
-
-;; Fix a bad bug in calfw. See:
-;; https://github.com/kiwanami/emacs-calfw/pull/79
-(defun cfw:cp-set-contents-sources (component sources)
- "Set content SOURCES for COMPONENT.
-SOURCES is a list of content sources."
- (cfw:model-set-contents-sources
- sources (cfw:component-model component)))
-
-(require 'excorporate)
-
-(defvar excorporate-calfw-buffer-name "*Excorporate*"
- "The buffer into which Calfw output is inserted.")
-
-(defun exco-calfw-initialize-buffer (month day year)
- "Set up an initial blank Calfw buffer for date MONTH DAY YEAR."
- (with-current-buffer (get-buffer-create excorporate-calfw-buffer-name)
- (display-buffer (current-buffer))
- (let ((status-source (make-cfw:source :name "Updating..."
- :data (lambda (_b _e) nil))))
- (cfw:create-calendar-component-buffer
- :date (cfw:date month day year) :view 'day
- :contents-sources (list status-source)
- :buffer (current-buffer)))))
-
-(defun exco-calfw-add-meeting (subject start end location
- main-invitees optional-invitees)
- "Add a scheduled meeting to the event list.
-SUBJECT is a string, the subject of the meeting. START is the
-meeting start time in Emacs internal date time format, and END is
-the end of the meeting in the same format. LOCATION is a string
-representing the location. MAIN-INVITEES and OPTIONAL-INVITEES
-are the requested participants."
- (let ((start-list (decode-time start))
- (end-list (decode-time end)))
- (make-cfw:event :title (concat
- (format "\n\t%s" subject)
- (format "\n\tLocation: %s" location)
- (when main-invitees
- (format "\n\tInvitees: %s"
- (mapconcat 'identity
- main-invitees "; ")))
- (when optional-invitees
- (format "\n\tOptional: %s"
- (mapconcat 'identity
- optional-invitees "; "))))
- :start-date (list (elt start-list 4)
- (elt start-list 3)
- (elt start-list 5))
- :start-time (list (elt start-list 2)
- (elt start-list 1))
- :end-date (list (elt end-list 4)
- (elt end-list 3)
- (elt end-list 5))
- :end-time (list (elt end-list 2)
- (elt end-list 1)))))
-
-(defun exco-calfw-add-meetings (identifier response)
- "Add the connection IDENTIFIER's meetings from RESPONSE."
- (let ((event-list (exco-calendar-item-iterate response
- #'exco-calfw-add-meeting)))
- (with-current-buffer (get-buffer-create excorporate-calfw-buffer-name)
- (let* ((new-source (make-cfw:source
- :name (format "%S (as of %s)"
- identifier
- (format-time-string "%F %H:%M"))
- :data (lambda (_b _e)
- event-list)))
- (sources (cfw:cp-get-contents-sources cfw:component))
- (new-sources (append sources (list new-source))))
- (cfw:cp-set-contents-sources cfw:component new-sources)))))
-
-(defun exco-calfw-finalize-buffer ()
- "Finalize the Calfw widget after retrievals have completed."
- (with-current-buffer (get-buffer-create excorporate-calfw-buffer-name)
- (let ((sources (cfw:cp-get-contents-sources cfw:component))
- (status-source (make-cfw:source :name "Done."
- :data (lambda (_b _e) nil))))
- (cfw:cp-set-contents-sources cfw:component
- (cons status-source (cdr sources))))
- (cfw:cp-add-selection-change-hook cfw:component
- (lambda ()
- (apply #'exco-calfw-show-day
- (cfw:cursor-to-nearest-date))))
- (cfw:refresh-calendar-buffer nil)))
-
-;;;###autoload
-(defun exco-calfw-show-day (month day year)
- "Show meetings for the date specified by MONTH DAY YEAR."
- (exco-connection-iterate
- (lambda ()
- (exco-calfw-initialize-buffer month day year))
- (lambda (identifier callback)
- (exco-get-meetings-for-day identifier month day year
- callback))
- #'exco-calfw-add-meetings
- #'exco-calfw-finalize-buffer))
-
-(provide 'excorporate-calfw)
-
-;;; excorporate-calfw.el ends here
diff --git a/packages/excorporate/excorporate-diary.el
b/packages/excorporate/excorporate-diary.el
deleted file mode 100644
index 833df30..0000000
--- a/packages/excorporate/excorporate-diary.el
+++ /dev/null
@@ -1,322 +0,0 @@
-;;; excorporate-diary.el --- Diary integration -*- lexical-binding: t
-*-
-
-;; Copyright (C) 2018-2019 Free Software Foundation, Inc.
-
-;; Author: Thomas Fitzsimmons <fitzsim@fitzsim.org>
-;; Keywords: calendar
-
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Wrap interactive `diary-lib' functions so that they query the
-;; Exchange server asynchronously, then display retrieved results
-;; interleaved with local diary entries.
-
-;;; Code:
-
-(require 'diary-lib)
-(require 'calendar)
-(require 'icalendar)
-(require 'appt)
-(require 'excorporate)
-(require 'nadvice)
-
-;; For Emacs versions less than 27.1, which do not have the fix for
-;; Bug#35645, work around the issue where `icalendar-import-buffer'
-;; pops up the diary file buffer.
-(defun exco-diary-diary-make-entry (string &optional nonmarking file)
- "Insert a diary entry STRING which may be NONMARKING in FILE.
-If omitted, NONMARKING defaults to nil and FILE defaults to
-`diary-file'."
- (with-current-buffer (find-file-noselect (or file diary-file))
- (when (eq major-mode (default-value 'major-mode)) (diary-mode))
- (widen)
- (diary-unhide-everything)
- (goto-char (point-max))
- (when (let ((case-fold-search t))
- (search-backward "Local Variables:"
- (max (- (point-max) 3000) (point-min))
- t))
- (beginning-of-line)
- (insert "\n")
- (forward-line -1))
- (insert
- (if (bolp) "" "\n")
- (if nonmarking diary-nonmarking-symbol "")
- string)))
-
-(defun exco-diary-icalendar--add-diary-entry-around (original &rest arguments)
- "Prevent whitespace workaround from selecting diary buffer.
-Also prevent `diary-make-entry' from putting the diary file
-where (other-buffer (current-buffer)) will return it. ORIGINAL
-and ARGUMENTS are the original function and arguments
-respectively."
- (cl-letf (((symbol-function #'find-file)
- (symbol-function #'find-file-noselect))
- ;; This override suppresses diary-make-entry's window
- ;; and buffer manipulations.
- ((symbol-function #'diary-make-entry)
- (symbol-function #'exco-diary-diary-make-entry)))
- (apply original arguments)))
-
-(unless (string-match "omit-trailing-space" (documentation 'diary-make-entry))
- (advice-add #'icalendar--add-diary-entry :around
- #'exco-diary-icalendar--add-diary-entry-around))
-
-(defvar excorporate-diary-today-file
- "~/.emacs.d/excorporate/diary-excorporate-today"
- "The diary file where Excorporate should save today's meetings.
-This file will be #include'd in `diary-file' by
-`excorporate-diary-enable'.")
-
-(defvar excorporate-diary-transient-file
- "~/.emacs.d/excorporate/diary-excorporate-transient"
- "The diary file where Excorporate should save retrieved meetings.
-This file will be #include'd in `diary-file' by
-`excorporate-diary-enable'.")
-
-(defun exco-diary-initialize (today)
- "Initialize diary files used by Excorporate.
-Run before retrieving diary entries from servers. TODAY is t to
-initialize for today's date, nil otherwise."
- ;; Keep today's entries if running on a day other than today. If
- ;; retrieving results for today, delete results from days other than
- ;; today, in case the transient file (having been filled in on a
- ;; prior day) contains duplicate or stale results for today.
- (let ((files (if today
- (list excorporate-diary-today-file
- excorporate-diary-transient-file)
- (list excorporate-diary-transient-file))))
- (dolist (file files)
- (let ((directory (file-name-directory file)))
- (unless (file-exists-p directory)
- (make-directory directory))
- (with-current-buffer (find-file-noselect file)
- (delete-region (point-min) (point-max))
- ;; Do not call `save-buffer' to avoid any hooks from being
- ;; run. Otherwise `appt-update-list' in
- ;; `write-file-functions' can cause an infinite
- ;; connnection-callback loop.
- (basic-save-buffer-1))))))
-
-;; Literal percent signs (%) are not supported in a diary entry since
-;; they're interpreted as format strings by `diary-sexp-entry', so
-;; encode them during entry insertion, then unescape them during
-;; display. This is needed so that, e.g., encoded meeting URLs that
-;; contain literal percent signs (%) work with `browse-url'.
-(defun exco-diary--fix-percent-signs ()
- "Replace percent-sign placeholders with percent signs."
- (goto-char (point-min))
- (let ((inhibit-read-only t))
- (while (re-search-forward "<EXCO_PERCENT_SIGN>" nil t)
- (replace-match "%"))))
-
-(defun exco-diary-appt-disp-window (min-to-app new-time appt-msg)
- "Replace Excorporate diary percent signs.
-For MIN-TO-APP, NEW-TIME and APPT-MSG documentation, see
-`appt-disp-window'."
- (appt-disp-window min-to-app new-time appt-msg)
- (with-current-buffer (get-buffer-create appt-buffer-name)
- (let ((inhibit-read-only t))
- (exco-diary--fix-percent-signs))))
-
-(defun exco-diary-insert-meeting (finalize
- subject start _end _location
- _main-invitees _optional-invitees
- icalendar-text)
- "Insert a retrieved meeting into the diary.
-See also the documentation for `exco-calendar-item-iterate'. The
-arguments are SUBJECT, a string, the subject of the meeting,
-START, the start date and time in Emacs internal representation,
-and ICALENDAR-TEXT, iCalendar text representing the meeting.
-_END, _LOCATION, _MAIN-INVITEES, and _OPTIONAL-INVITEES are
-unused.
-
-Call FINALIZE after the meeting has been inserted."
- (when (not (string-match "^Cancel[l]?ed: " subject))
- ;; FIXME: Sometimes meetings are duplicated if they have
- ;; overlapping (and (diary-cyclic ...) (diary-block ...)) ranges,
- ;; e.g., one in the today file and one in the transient file.
- ;; Maybe we should de-duplicate them in the final display. If the
- ;; meeting start time is sometime today then put it in today's
- ;; diary file, otherwise put it in the transient one.
- (let* ((time (decode-time (current-time)))
- (now (list (elt time 3) (elt time 4) (elt time 5)))
- (dawn (apply #'encode-time 0 0 0 now))
- (dusk (time-add dawn (seconds-to-time 86400)))
- (file (if (and (time-less-p dawn start) (time-less-p start dusk))
- excorporate-diary-today-file
- excorporate-diary-transient-file)))
- (with-temp-buffer
- (insert icalendar-text)
-
- ;; FIXME: Maybe some users of multiple calendars will want to
- ;; know the source calendar's name for each diary entry.
- ;; There is no great way to achieve that right now, but one
- ;; idea is to add X-WR-CALNAME support to
- ;; icalendar-import-buffer, replace the
- ;; exco-diary-insert-meeting argument to
- ;; exco-calendar-item-with-details-iterate with:
- ;;
- ;; (lambda (&rest arguments)
- ;; (apply #'exco-diary-insert-meeting identifier arguments))
- ;;
- ;; and uncomment the following code.
- ;;
- ;; (goto-char (point-min))
- ;; (while (re-search-forward
- ;; "^SUMMARY\\([^:]*\\):\\(.*\\(\n[ ].*\\)*\\)" nil t)
- ;; (insert (format "\nX-WR-CALNAME: (%s)" identifier)))
-
- ;; Escape literal percent signs (%). Use less-than sign (<)
- ;; and greater-than sign (>) which are forbidden URL
- ;; characters, so that in the plain text diary file,
- ;; percent-encoded URLs become completely invalid rather than
- ;; slightly wrong.
- (goto-char (point-min))
- (while (re-search-forward "%" nil t)
- (replace-match "<EXCO_PERCENT_SIGN>"))
- (icalendar-import-buffer file t))))
- (funcall finalize))
-
-;; Bound in appt-check.
-(defvar appt-display-diary)
-
-(defun exco-diary-diary-advice (today date advisee &rest arguments)
- "Advise `diary' and `diary-view-entries' to add Excorporate support.
-TODAY is today's date in `calendar-current-date' format. DATE is
-the desired date to retrieve meetings for, in the same format.
-ADVISEE is the original function being advised. ARGUMENTS are
-the arguments to the advisee."
- ;; FIXME: Currently numeric arguments to `diary' and
- ;; `diary-view-entries' are ignored.
- (exco-connection-iterate
- (lambda ()
- (message "Retrieving diary entries via Excorporate...")
- (exco-diary-initialize (calendar-date-equal today date)))
- (lambda (identifier callback)
- (cl-destructuring-bind (month day year) date
- (exco-get-meetings-for-day identifier month day year callback)))
- (lambda (identifier response finalizer)
- (exco-calendar-item-with-details-iterate identifier response
- #'exco-diary-insert-meeting
- finalizer))
- (lambda ()
- (apply advisee arguments)
- ;; Warning: It is crucial to set appt-display-diary to nil here,
- ;; so that diary advice isn't entered repeatedly (ultimately via
- ;; the `appt-update-list' hook in `write-file-functions'), which
- ;; would create a connection-callback loop.
- (let ((appt-display-diary nil))
- (appt-check t))
- (message "Done retrieving diary entries via Excorporate."))
- t)
- ;; Just return nil from this advice. We eventually run the advisee
- ;; asynchronously so there is no way of providing the same return
- ;; value as the unadvised `diary' and `diary-view-entries'
- ;; functions. Luckily they seem to only be used interactively, at
- ;; least within Emacs itself.
- nil)
-
-(defun exco-diary-diary-around (original-diary &rest arguments)
- "Call `diary' asynchronously.
-Retrieve diary entries via Excorporate before showing results.
-ORIGINAL-DIARY is the original `diary' function, and ARGUMENTS
-are the arguments to it."
- (let ((today (calendar-current-date))
- (date (calendar-current-date)))
- (apply #'exco-diary-diary-advice today date original-diary arguments)))
-
-(defun exco-diary-diary-view-entries-override (&rest arguments)
- "Override `diary-view-entries' to make it asynchronous.
-Retrieve diary entries via Excorporate before showing results.
-ARGUMENTS are the arguments to `diary-view-entries'."
- (interactive "p")
- (diary-check-diary-file)
- (let ((today (calendar-current-date))
- (date (calendar-cursor-to-date t)))
- (apply #'exco-diary-diary-advice today date
- #'diary-list-entries date arguments)))
-
-;;;###autoload
-(defun excorporate-diary-enable ()
- "Enable Excorporate diary support."
- (interactive)
- ;; Create the directory for Excorporate diary files if it doesn't
- ;; already exist.
- (exco-diary-initialize t)
- ;; Remove advice first so that `diary' will not be run by any save
- ;; hooks.
- (advice-remove #'diary #'exco-diary-diary-around)
- (advice-remove #'diary-view-entries #'exco-diary-diary-view-entries-override)
- (with-current-buffer (find-file-noselect diary-file)
- (dolist (file (list excorporate-diary-transient-file
- excorporate-diary-today-file))
- (save-excursion
- (goto-char (point-min))
- (when (not (re-search-forward
- (concat "^ *" diary-include-string " *\"" file "\"") nil t))
- (let ((include-string (concat diary-include-string " \"" file "\"")))
- (if (string-match "omit-trailing-space"
- (documentation 'diary-make-entry))
- (with-no-warnings
- (diary-make-entry include-string nil nil t t))
- (exco-diary-diary-make-entry include-string)))
- (save-buffer)))))
- (advice-add #'diary :around #'exco-diary-diary-around)
- (advice-add #'diary-view-entries :override
- #'exco-diary-diary-view-entries-override)
- (add-hook 'diary-list-entries-hook #'diary-sort-entries)
- (add-hook 'diary-list-entries-hook #'diary-include-other-diary-files)
- (add-hook 'diary-fancy-display-mode-hook #'exco-diary--fix-percent-signs)
- (unless (eq appt-disp-window-function 'exco-diary-appt-disp-window)
- (if (eq appt-disp-window-function 'appt-disp-window)
- ;; exco-diary-appt-disp-window is compatible with
- ;; appt-disp-window, so override it.
- (setq appt-disp-window-function 'exco-diary-appt-disp-window)
- (warn (format (concat "Excorporate diary support needs appt-disp-window"
- " but appt-disp-window-function is currently %S")
- appt-disp-window-function))))
- (unless (eq diary-display-function 'diary-fancy-display)
- (warn (format
- (concat "Excorporate diary support needs diary-fancy-display"
- " but diary-display-function is currently %S")
- diary-display-function)))
- (appt-activate 1)
- (message "Excorporate diary support enabled."))
-
-(defun excorporate-diary-disable ()
- "Disable Excorporate diary support."
- (interactive)
- (advice-remove #'diary #'exco-diary-diary-around)
- (advice-remove #'diary-view-entries #'exco-diary-diary-view-entries-override)
- (remove-hook 'diary-fancy-display-mode-hook #'exco-diary--fix-percent-signs)
- (when (eq appt-disp-window-function 'exco-diary-appt-disp-window)
- (setq appt-disp-window-function 'appt-disp-window))
- (with-current-buffer (find-file-noselect diary-file)
- (dolist (file (list excorporate-diary-transient-file
- excorporate-diary-today-file))
- (save-excursion
- (goto-char (point-min))
- (when (search-forward
- (concat diary-include-string " \"" file "\"") nil t)
- (delete-region (progn (beginning-of-line) (point))
- (progn (forward-line 1) (point)))
- (save-buffer)))))
- (message "Excorporate diary support disabled."))
-
-(provide 'excorporate-diary)
-
-;;; excorporate-diary.el ends here
diff --git a/packages/excorporate/excorporate-org.el
b/packages/excorporate/excorporate-org.el
deleted file mode 100644
index 868fe72..0000000
--- a/packages/excorporate/excorporate-org.el
+++ /dev/null
@@ -1,364 +0,0 @@
-;;; excorporate-org.el --- Exchange Org Mode view -*- lexical-binding: t
-*-
-
-;; Copyright (C) 2016-2020 Free Software Foundation, Inc.
-
-;; Author: Thomas Fitzsimmons <fitzsim@fitzsim.org>
-;; Keywords: calendar
-
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Use Org Mode to display daily meetings.
-
-;;; Code:
-
-(require 'org)
-(require 'excorporate)
-(require 'cl-lib)
-
-(defvar excorporate-org-buffer-name "*Excorporate*"
- "The buffer into which Org Mode output is inserted.")
-
-(defvar exco-org--temporary-buffers '()
- "A list of per-connection result buffers.")
-
-(defun exco-org--calendar-item-region-at-point ()
- "A special case replacement for `org-element-at-point'.
-Return a list (BEGIN END) representing the region of the element
-at point, if point is at a calendar item. If point is not at a
-calendar item, return nil. This works back to Emacs 24.1's
-built-in Org 9.1.9 which does not have the `org-element'
-feature."
- (catch 'not-a-calendar-item
- (save-excursion
- (cl-values
- (progn (ignore-errors (org-back-to-heading))
- (unless (looking-at "^\\*\\* ") (throw 'not-a-calendar-item nil))
- (point))
- (progn (org-end-of-subtree) (forward-char 1)
- (point))))))
-
-(defun exco-org--connection-identifier-at-point ()
- "Return the connection identifier associated with point."
- (let* ((calendar-headline
- (save-excursion
- (org-up-heading-safe)
- (org-trim (substring-no-properties (thing-at-point 'line))))))
- (when (string-match "\\* Calendar (\\(.*\\))$" calendar-headline)
- (car (read-from-string (match-string 1 calendar-headline))))))
-
-(defun exco-org--item-identifier-at-point ()
- "Return the item identifier associated with point."
- (car (read-from-string
- (org-entry-get (car (org-get-property-block)) "Identifier"))))
-
-(defun exco-org--is-meeting ()
- "Return t if the entry at point is a meeting, not an appointment."
- (let ((region (exco-org--calendar-item-region-at-point)))
- (when region
- (let ((item-text (apply #'buffer-substring-no-properties region)))
- (when (string-match "^\+ Invitees:$" item-text) t)))))
-
-(defun exco-org--organizer ()
- "Return a string representing the item at point's organizer."
- (let ((region (exco-org--calendar-item-region-at-point)))
- (when region
- (let ((item-text (apply #'buffer-substring-no-properties region)))
- (string-match "^+ Organizer: \\(.*\\)$" item-text)
- ;; FIXME: Is this a critical region?
- (match-string 1 item-text)))))
-
-(defun exco-org--organizer-matches-connection ()
- "Return non-nil if the entry at point is owned by the connection owner."
- (let ((identifier (exco-org--connection-identifier-at-point))
- (organizer (exco-org--organizer)))
- (cond
- ((stringp identifier)
- (equal identifier organizer))
- ((consp identifier)
- (equal (car identifier) organizer))
- (t
- (error "Did not recognize error")))))
-
-(defmacro exco-org--handle-response (response
- response-type success failure &rest forms)
- "Handle a server response RESPONSE.
-RESPONSE-TYPE is one of CreateItemResponseMessage or
-DeleteItemResponseMessage. SUCCESS and FAILURE are strings added
-to the success and failure messages to the user. FORMS are what
-to do, starting from point being in the calendar entry being
-operated on."
- `(let ((response-code (exco-extract-value '(ResponseMessages
- ,response-type
- ResponseCode)
- ,response)))
- (if (equal response-code "NoError")
- (progn ,@forms (message "excorporate-org: Successfully %s" ,success))
- (message "excorporate-org: Failed to %s: %S" ,failure ,response))))
-
-(defun exco-org--remove-calendar-item ()
- "Remove the calendar item at point."
- (with-current-buffer (get-buffer-create excorporate-org-buffer-name)
- (let ((region (exco-org--calendar-item-region-at-point)))
- (when region
- (let ((inhibit-read-only t))
- (apply #'delete-region region))))))
-
-(defun exco-org--reply-to-meeting (acceptance do-not-prompt-for-message)
- "Reply to a meeting.
-ACCEPTANCE is a symbol, one of `accept', `tentatively-accept', or
-`decline'. If DO-NOT-PROMPT-FOR-MESSAGE is non-nil, do not
-prompt for or include a reply message, otherwise prompt for the
-reply message."
- (let (prompt success failure)
- (cl-ecase acceptance
- (accept
- (setq prompt "Acceptance message: ")
- (setq success "accepted")
- (setq failure "accept"))
- (tentatively-accept
- (setq prompt "Tentative acceptance message: ")
- (setq success "accepted tentatively")
- (setq failure "accept tentatively"))
- (decline
- (setq prompt "Declination message: ")
- (setq success "declined")
- (setq failure "decline")))
- (let ((message (when (not do-not-prompt-for-message)
- (read-from-minibuffer prompt)))
- (identifier (exco-org--connection-identifier-at-point))
- (item-identifier (exco-org--item-identifier-at-point)))
- (exco-calendar-item-meeting-reply
- identifier item-identifier message acceptance
- (lambda (_identifier response)
- (exco-org--handle-response response CreateItemResponseMessage
- success failure))))))
-
-(defun exco-org-accept-meeting-request (&optional argument)
- "Accept the meeting at point.
-With a prefix argument, ARGUMENT, do not prompt for acceptance
-message text, and do not send an acceptance response."
- (interactive "P")
- (exco-org--reply-to-meeting 'accept argument))
-
-(defun exco-org-decline-meeting-request (&optional argument)
- "Decline the meeting at point.
-With a prefix argument, ARGUMENT, do not prompt for declination
-message text, and do not send a declination message."
- (interactive "P")
- (exco-org--reply-to-meeting 'decline argument))
-
-(defun exco-org-tentatively-accept-meeting-request (&optional argument)
- "Tentatively accept the meeting at point.
-With a prefix argument, ARGUMENT, do not prompt for tentative
-acceptance message text, and do not send a tentative acceptance
-message."
- (interactive "P")
- (exco-org--reply-to-meeting 'tentatively-accept argument))
-
-(defun exco-org-cancel-meeting ()
- "Cancel the meeting at point, prompting for a cancellation message."
- (interactive)
- (unless (exco-org--is-meeting)
- (error (concat "This looks like an appointment,"
- " try `exco-org-delete-appointment' instead.")))
- (let ((identifier (exco-org--connection-identifier-at-point))
- (item-identifier (exco-org--item-identifier-at-point)))
- ;; Make sure the meeting owner matches the connection owner before
- ;; attempting to cancel the meeting.
- (unless (exco-org--organizer-matches-connection)
- (error (concat "exco-org will only attempt to delete"
- " meetings for which you are the organizer")))
- (when item-identifier
- (exco-calendar-item-meeting-cancel
- identifier item-identifier
- (read-from-minibuffer "Cancellation message: ")
- (lambda (_identifier response)
- (exco-org--handle-response
- response CreateItemResponseMessage
- "cancelled meeting" "cancel meeting"
- (exco-org--remove-calendar-item)))))))
-
-(defun exco-org-delete-appointment (&optional argument)
- "Delete the appointment at point.
-With a prefix argument, ARGUMENT, force-delete this calendar item
-without first checking if it is a meeting. This is required
-sometimes, for example as a way to delete meetings for which one
-is the organizer and the sole invitee, since the server will
-refuse to send a meeting cancellation message to the organizer."
- (interactive "P")
- (when (and (not argument)
- (exco-org--is-meeting))
- (error "This looks like a meeting, try `exco-org-cancel-meeting' instead"))
- (let ((identifier (exco-org--connection-identifier-at-point))
- (item-identifier (exco-org--item-identifier-at-point)))
- (when item-identifier
- (exco-calendar-item-appointment-delete
- identifier item-identifier
- (lambda (_identifier response)
- (exco-org--handle-response
- response DeleteItemResponseMessage
- "deleted appointment" "delete appointment"
- (exco-org--remove-calendar-item)))))))
-
-(defun exco-org-initialize-buffer ()
- "Add initial text to the destination buffer."
- (setq exco-org--temporary-buffers '())
- (with-current-buffer (get-buffer-create excorporate-org-buffer-name)
- (setq buffer-read-only t)
- ;; Some Org mode configurations need `buffer-file-name' to be
- ;; non-nil, or they'll make `org-mode' error out, for example
- ;; `org-startup-with-latex-preview'. Set `buffer-file-name' to
- ;; something non-nil temporarily during initialization. Don't
- ;; leave it set or `save-some-buffers' will always prompt about
- ;; *Excorporate*.
- (let ((buffer-file-name excorporate-org-buffer-name))
- (org-mode))
- (use-local-map (copy-keymap org-mode-map))
- (local-set-key "q" 'quit-window)
- (display-buffer (current-buffer))
- (let ((inhibit-read-only t))
- (delete-region (point-min) (point-max))
- (goto-char (point-min))
- (insert "# Updated..."))))
-
-(defun exco-org-format-headline (identifier)
- "Format an Org headline using IDENTIFIER."
- (format "* Calendar (%S)\n" identifier))
-
-(defun exco-org-insert-meeting-headline (subject
- start-time end-time
- &optional item-identifier)
- "Insert and schedule a meeting.
-SUBJECT is the meeting's subject, START-TIME and END-TIME are the
-meeting's start and end times in the same format as is returned
-by `current-time'. ITEM-IDENTIFIER is the opaque item
-identifier."
- (let* ((now (current-time))
- (keyword (if (time-less-p now end-time)
- "TODO"
- "DONE")))
- (insert (format "** %s %s\n" keyword subject))
- (org-schedule nil (format-time-string "<%Y-%m-%d %a %H:%M>"
- start-time))
- (forward-line -1)
- (end-of-line)
- (insert "--" (format-time-string "<%Y-%m-%d %a %H:%M>" end-time))
- (forward-line)
- (org-set-property "Identifier" (format "%S" item-identifier))
- (org-insert-time-stamp (current-time) t t "+ Retrieved " "\n")))
-
-(defun exco-org-insert-invitees (invitees)
- "Parse and insert a list of invitees, INVITEES."
- (dolist (invitee invitees)
- (insert (format " + %s\n" invitee))))
-
-(defun exco-org--identifier-buffer (identifier)
- "Return a hidden buffer with a name based on IDENTIFIER."
- (get-buffer-create
- (format " *exco-org-%S*" identifier)))
-
-(defun exco-org-insert-headline (identifier month day year)
- "Insert Org headline for IDENTIFIER on date MONTH DAY YEAR."
- (let ((temporary-buffer (exco-org--identifier-buffer identifier)))
- (push temporary-buffer exco-org--temporary-buffers)
- (with-current-buffer temporary-buffer
- (let ((inhibit-read-only t))
- (delete-region (point-min) (point-max))
- (insert (exco-org-format-headline identifier))
- (org-insert-time-stamp (encode-time 0 0 0 day month year)
- nil t " + Date " "\n")))))
-
-(defun exco-org-insert-meeting (subject start end location
- main-invitees optional-invitees
- &optional item-identifier organizer)
- "Insert a scheduled meeting.
-SUBJECT is a string, the subject of the meeting. START is the
-meeting start time in Emacs internal date time format, and END is
-the end of the meeting in the same format. LOCATION is a string
-representing the location. MAIN-INVITEES and OPTIONAL-INVITEES
-are the requested participants. ITEM-IDENTIFIER is the opaque
-item identifier. ORGANIZER is a string, the email address of the
-meeting organizer."
- (exco-org-insert-meeting-headline subject start end item-identifier)
- (insert (format "+ Duration: %d minutes\n"
- (round (/ (float-time (time-subtract end start)) 60.0))))
- (insert (format "+ Location: %s\n" location))
- (insert (format "+ Organizer: %s\n" organizer))
- (when main-invitees
- (insert "+ Invitees:\n")
- (exco-org-insert-invitees main-invitees))
- (when optional-invitees
- (insert "+ Optional invitees:\n")
- (exco-org-insert-invitees optional-invitees)))
-
-(defun exco-org-insert-meetings (identifier response)
- "Insert the connection IDENTIFIER's meetings from RESPONSE."
- (with-current-buffer (get-buffer-create excorporate-org-buffer-name)
- (let ((inhibit-read-only t))
- (goto-char (point-min))
- (end-of-line)
- (insert (format "%s..." identifier))))
- (with-current-buffer (exco-org--identifier-buffer identifier)
- (let ((inhibit-read-only t))
- (org-insert-time-stamp (current-time) t t " + Last checked " "\n")
- (exco-calendar-item-iterate-general
- response (lambda (&rest arguments)
- (with-current-buffer (exco-org--identifier-buffer identifier)
- (org-mode)
- (let ((new-arguments arguments))
- (setf (nth 7 new-arguments)
- (exco-resolve-organizer-email-address-synchronously
- identifier organizer-structure))
- (apply #'exco-org-insert-meeting new-arguments))))
- subject start-internal end-internal
- location main-invitees optional-invitees item-identifier
- organizer-structure)
- (goto-char (point-min))
- (if (save-excursion (org-goto-first-child))
- (org-sort-entries t ?s)
- (forward-line 3)
- (insert "`♘\n")))))
-
-(defun exco-org-finalize-buffer ()
- "Finalize text in buffer after all connections have responded."
- (with-current-buffer (get-buffer-create excorporate-org-buffer-name)
- ;; Sort top-level entries alphabetically.
- (let ((inhibit-read-only t))
- (goto-char (point-min))
- (end-of-line)
- (insert "done.\n")
- (dolist (result-buffer (nreverse exco-org--temporary-buffers))
- (insert-buffer-substring result-buffer)
- (save-excursion (org-up-heading-safe) (org-cycle-hide-drawers 'all))
- (kill-buffer result-buffer))
- (setq exco-org--temporary-buffers '()))))
-
-;;;###autoload
-(defun exco-org-show-day (month day year)
- "Show meetings for the date specified by MONTH DAY YEAR."
- (exco-connection-iterate #'exco-org-initialize-buffer
- (lambda (identifier callback)
- (exco-org-insert-headline identifier
- month day year)
- (exco-get-meetings-for-day identifier
- month day year
- callback))
- #'exco-org-insert-meetings
- #'exco-org-finalize-buffer))
-
-(provide 'excorporate-org)
-
-;;; excorporate-org.el ends here
diff --git a/packages/excorporate/excorporate.el
b/packages/excorporate/excorporate.el
deleted file mode 100644
index 4678da1..0000000
--- a/packages/excorporate/excorporate.el
+++ /dev/null
@@ -1,1212 +0,0 @@
-;;; excorporate.el --- Exchange Web Services (EWS) integration -*-
lexical-binding: t -*-
-
-;; Copyright (C) 2014-2020 Free Software Foundation, Inc.
-
-;; Author: Thomas Fitzsimmons <fitzsim@fitzsim.org>
-;; Maintainer: Thomas Fitzsimmons <fitzsim@fitzsim.org>
-;; Created: 2014-09-19
-;; Version: 0.9.1
-;; Keywords: calendar
-;; Homepage: https://www.fitzsim.org/blog/
-;; Package-Requires: ((emacs "24.1") (fsm "0.2.1") (soap-client "3.2.0")
(url-http-ntlm "2.0.4") (nadvice "0.3"))
-
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Excorporate provides Exchange integration for Emacs.
-
-;; To create a connection to a web service:
-
-;; M-x excorporate
-
-;; Excorporate will prompt for an email address that it will use to
-;; automatically discover settings. Then it will connect to two or
-;; three separate hosts: the autodiscovery host, the web service host
-;; or load balancer, and the actual server if there is a load
-;; balancer. Therefore you may be prompted for your credentials two
-;; or three times.
-
-;; You should see a message indicating that the connection is ready
-;; either in the minibuffer or failing that in the *Messages* buffer.
-
-;; Finally, run M-x calendar, and press 'e' to show today's meetings.
-
-;; Please try autodiscovery first and report issues not yet listed
-;; below. When autodiscovery works it is very convenient; the goal is
-;; to make it work for as many users as possible.
-
-;; If autodiscovery fails, customize `excorporate-configuration' to
-;; skip autodiscovery.
-
-;; Autodiscovery will fail if:
-
-;; - Excorporate is accessing the server through a proxy (Emacs
-;; bug#10).
-
-;; - The server is not configured to support autodiscovery.
-
-;; - The email address is at a different domain than the server, e.g.,
-;; user@domain1.com, autodiscover.domain2.com.
-
-;; - Authentication is Kerberos/GSSAPI.
-
-;; Excorporate does know about the special case where the mail address
-;; is at a subdomain, e.g., user@sub.domain.com, and the server is at
-;; the main domain, e.g., autodiscover.domain.com. Autodiscovery will
-;; work in that case.
-
-;; Excorporate must be loaded before any other package that requires
-;; `soap-client'. The version of `soap-client' that Excorporate
-;; bundles is backward compatible.
-
-;; Acknowledgments:
-
-;; Alexandru Harsanyi <AlexHarsanyi@gmail.com> provided help and
-;; guidance on how to extend soap-client.el's WSDL and XSD handling,
-;; enabling support for the full Exchange Web Services API.
-
-;; Alex Luccisano <casual.lexicon@gmail.com> tested early versions of
-;; this library against a corporate installation of Exchange.
-
-;; Jon Miller <jonebird@gmail.com> tested against Exchange 2013. He
-;; also tracked down and reported a bad interaction with other
-;; packages that require soap-client.
-
-;; Nicolas Lamirault <nicolas.lamirault@gmail.com> tested the
-;; autodiscovery feature.
-
-;; Trey Jackson <bigfaceworm@gmail.com> confirmed autodiscovery worked
-;; for him.
-
-;; Joakim Verona <joakim@verona.se> tested autodiscovery in a
-;; Kerberos/GSSAPI environment.
-
-;; Wilfred Hughes <me@wilfred.me.uk> tested on Exchange 2007 and
-;; suggested documentation improvements.
-
-;; Erik Hetzner <egh@e6h.org> tested on Office 365 and helped debug
-;; Office 365 support.
-
-;; Fabio Leimgruber <fabio.leimgruber@web.de> tested NTLM
-;; authentication against a challenging server configuration.
-
-;; Stefan Monnier <monnier@iro.umontreal.ca> wrote a variant of
-;; nadvice.el for GNU ELPA so that Excorporate could continue
-;; supporting Emacs versions 24.1, 24.2 and 24.3.
-
-;; Collin Day <dcday137@gmail.com> tested and helped debug accessing
-;; Office 365 through an HTTPS proxy.
-
-;;; Code:
-
-;; Implementation-visible functions and variables.
-
-;; Add NTLM authorization scheme.
-(require 'url-http-ntlm)
-(require 'soap-client)
-(require 'fsm)
-(require 'excorporate-calendar)
-(require 'org)
-
-;; For Office 365, URLs containing autodiscover-s.outlook.com do not
-;; seem to work properly (the returned XML gives ErrorCode 600).
-(defconst exco--autodiscovery-templates
- '("https://%s/autodiscover/autodiscover.svc"
- "https://autodiscover.%s/autodiscover/autodiscover.svc")
- "Autodiscovery URL templates.
-URL templates to be formatted with a domain name, then searched
-for autodiscovery files.")
-
-(defvar exco--connections nil
- "A hash table of finite state machines.
-The key is the identifier passed to `exco-connect'. Each finite
-state machine represents a service connection.")
-
-(defvar exco--connection-identifiers nil
- "An ordered list of connection identifiers.")
-
-(defvar exco--server-timeout 5
- "The timeout in seconds to wait for a synchronous server response.")
-
-(defun exco--parse-xml-in-current-buffer ()
- "Decode and parse the XML contents of the current buffer."
- (let ((mime-part (mm-dissect-buffer t t)))
- (unless mime-part
- (error "Failed to decode response from server"))
- (unless (equal (car (mm-handle-type mime-part)) "text/xml")
- (error "Server response is not an XML document"))
- (with-temp-buffer
- (mm-insert-part mime-part)
- (prog1
- (car (xml-parse-region (point-min) (point-max)))
- (kill-buffer)
- (mm-destroy-part mime-part)))))
-
-(defun exco--bind-wsdl (wsdl service-url port-name target-namespace
- binding-name)
- "Create a WSDL binding.
-Create a binding port for WSDL from SERVICE-URL, PORT-NAME,
-TARGET-NAMESPACE and BINDING-NAME."
- (let* ((namespace (soap-wsdl-find-namespace target-namespace wsdl))
- (port (make-soap-port
- :name port-name
- :binding (cons target-namespace binding-name)
- :service-url service-url)))
- (soap-namespace-put port namespace)
- (push port (soap-wsdl-ports wsdl))
- (soap-resolve-references port wsdl)
- wsdl))
-
-(defun exco--handle-url-error (url status)
- "Handle an error that occurred when retrieving URL.
-The details of the error are in STATUS, in the same format as the
-argument to a `url-retrieve' callback. Return non-nil to retry,
-nil to continue."
- (if (eq (cl-third (plist-get status :error)) 500)
- ;; The server reported an internal server error. Try to recover
- ;; by re-requesting the target URL and its most recent redirect.
- ;; I'm not sure what conditions cause the server to get into
- ;; this state -- it might be because the server has stale
- ;; knowledge of old keepalive connections -- but this should
- ;; recover it. We need to disable ntlm in
- ;; url-registered-auth-schemes so that it doesn't prevent
- ;; setting keepalives to nil.
- (let ((url-registered-auth-schemes nil)
- (url-http-attempt-keepalives nil)
- (redirect (plist-get status :redirect)))
- (fsm-debug-output "exco--fsm received 500 error for %s" url)
- (url-debug 'excorporate "Attempting 500 recovery")
- (ignore-errors
- ;; Emacs's url-retrieve does not respect the values of
- ;; url-http-attempt-keepalives and
- ;; url-registered-auth-schemes in asynchronous contexts.
- ;; Unless url.el is eventually changed to do so, the
- ;; following requests must be synchronous so that they run
- ;; entirely within url-http-attempt-keepalives's dynamic
- ;; extent. These calls block the main event loop,
- ;; unfortunately, but only in this rare error recovery
- ;; scenario.
- (url-retrieve-synchronously url)
- (when redirect (url-retrieve-synchronously redirect)))
- (url-debug 'excorporate "Done 500 recovery attempt")
- ;; Retry.
- t)
- ;; We received some other error, which just
- ;; means we should try the next URL.
- (fsm-debug-output "exco--fsm didn't find %s" url)
- ;; Don't retry.
- nil))
-
-(defun exco--retrieve-next-import (fsm state-data return-for next-state)
- "Retrieve the next XML schema import.
-FSM is the finite state machine, STATE-DATA is FSM's state data,
-and RETURN-FOR is one of :enter or :event to indicate what return
-type the calling function expects. NEXT-STATE is the next state
-the FSM should transition to on success."
- (let* ((url (plist-get state-data :service-url))
- (xml (plist-get state-data :service-xml))
- (wsdl (plist-get state-data :service-wsdl))
- (imports (soap-wsdl-xmlschema-imports wsdl))
- (next-state (if imports :parsing-service-wsdl next-state)))
- (when imports
- (let ((import-url (url-expand-file-name (pop imports) url)))
- (let ((url-request-method "GET")
- (url-package-name "soap-client.el")
- (url-package-version "1.0")
- (url-mime-charset-string "utf-8;q=1, iso-8859-1;q=0.5")
- (url-http-attempt-keepalives t))
- (url-retrieve
- import-url
- (lambda (status)
- (let ((data-buffer (current-buffer)))
- (unwind-protect
- (progn
- (url-debug 'excorporate "Processing import %s" status)
- (if (eq (car status) :error)
- ;; There is an error. It may be recoverable
- ;; if it's HTTP 500 (internal server error).
- (if (and (exco--handle-url-error import-url status)
- ;; Only retry once.
- (not (plist-get state-data :retrying)))
- ;; We should retry. Don't save the
- ;; popped urls list to state-data, so
- ;; that this :try-next-url will
- ;; re-attempt to retrieve the same car as
- ;; before. Set the retry flag.
- (progn
- (plist-put state-data :retrying t))
- ;; Save the popped urls list so that the next url
- ;; is attempted, and clear the retry flag.
- (plist-put state-data :retrying nil)
- (setf (soap-wsdl-xmlschema-imports wsdl) imports)
- (plist-put state-data :failure-message
- (format "Failed to retrieve %s"
- import-url))
- (fsm-send fsm :unrecoverable-error))
- ;; Success, parse WSDL.
- (plist-put state-data :retrying nil)
- (setf (soap-wsdl-xmlschema-imports wsdl) imports)
- (soap-with-local-xmlns xml
- (soap-wsdl-add-namespace
- (soap-parse-schema (soap-parse-server-response) wsdl)
- wsdl))
- (plist-put state-data :service-wsdl wsdl)))
- (and (buffer-live-p data-buffer)
- (kill-buffer data-buffer))))
- (fsm-send fsm t))))))
- (if (eq return-for :enter)
- (list state-data nil)
- (list next-state state-data nil))))
-
-(define-state-machine exco--fsm :start
- ((identifier)
- "Start an Excorporate finite state machine."
- (let* ((autodiscover (stringp identifier))
- (mail (if autodiscover identifier (car identifier)))
- (url (unless autodiscover (cdr identifier)))
- (autodiscovery-urls
- (when autodiscover
- (let ((domain (cadr (split-string mail "@"))))
- (unless (and domain (not (equal domain "")))
- (error "Invalid domain for address %s" mail))
- (append (mapcar (lambda (template)
- (format template domain))
- exco--autodiscovery-templates)
- ;; Handle the user@sub.domain.com =>
- ;; autodiscover.domain.com case reported by a
- ;; user. Only try one extra level.
- (let ((domain-parts (split-string domain "\\.")))
- (when (> (length domain-parts) 2)
- (mapcar (lambda (template)
- (format template
- (mapconcat
- 'identity
- (cdr domain-parts) ".")))
- exco--autodiscovery-templates)))))))
- (service-url (unless autodiscover url))
- (next-state (if autodiscover
- :retrieving-autodiscovery-xml
- ;; Go directly to :retrieving-service-xml,
- ;; skipping autodiscovery.
- :retrieving-service-xml)))
- (list next-state
- (list
- ;; State machine data.
- ;;
- ;; Unique finite state machine identifier, either a
- ;; string, mail-address (which implies the URL is
- ;; autodiscovered) or a pair of strings, (mail-address
- ;; . service-url). This format allows multiple state
- ;; machines to operate on the same mail address or service
- ;; URL. Login credentials are handled separately by
- ;; auth-source and url, so it should be possible for one
- ;; Emacs process to have simultaneous Excorporate
- ;; connections for, e.g.: ("mail-1" . "url-1") and
- ;; ("mail-2" . "url-1") or even: "mail-1" and ("mail-1"
- ;; . "url-2") if that's ever desirable.
- :identifier identifier
- ;; User data.
- :mail-address mail
- ;; Error recovery data.
- :retrying nil
- ;; Autodiscovery data.
- ;; This is nil when not doing autodiscovery.
- :autodiscovery-urls autodiscovery-urls
- ;; Service data.
- ;; When doing autodiscovery this is nil, otherwise
- ;; it is the service-url field from `identifier'.
- :service-url service-url
- :service-xml nil
- :service-wsdl nil
- ;; State data.
- :next-state-after-success nil
- :failure-message nil
- :server-version nil)
- ;; No timeout.
- nil))))
-
-(define-state exco--fsm :retrieving-autodiscovery-xml
- (fsm state-data event _callback)
- (cl-case event
- (:try-next-url
- (let ((urls (plist-get state-data :autodiscovery-urls)))
- (if urls
- (let ((url (pop urls)))
- (fsm-debug-output "exco--fsm will probe %s" url)
- (condition-case nil
- (url-retrieve
- url
- (lambda (status)
- (let ((data-buffer (current-buffer)))
- (unwind-protect
- (progn
- (url-debug 'excorporate
- "Processing status: %s" status)
- (if (eq (car status) :error)
- (progn
- (if (and
- (exco--handle-url-error url status)
- ;; Only retry once.
- (not (plist-get state-data :retrying)))
- ;; We should retry. Don't save the popped
- ;; urls list to state-data, so that this
- ;; :try-next-url will re-attempt to
- ;; retrieve the same car as before. Set
- ;; the retry flag.
- (plist-put state-data :retrying t)
- ;; Save the popped urls list so that the
- ;; next url is attempted, and clear the
- ;; retry flag.
- (plist-put state-data :retrying nil)
- (plist-put state-data
- :autodiscovery-urls urls))
- ;; Try next or retry.
- (fsm-send fsm :try-next-url))
- ;; Success, save URL and parse returned XML.
- (message
- "Excorporate: Found autodiscovery URL for %S: %s"
- (plist-get state-data :identifier) url)
- (plist-put state-data :retrying nil)
- (plist-put state-data :service-url url)
- (plist-put state-data :service-xml
- (exco--parse-xml-in-current-buffer))
- (fsm-send fsm :success))
- (url-debug 'excorporate "Done processing status"))
- (and (buffer-live-p data-buffer)
- (kill-buffer data-buffer))))))
- (error
- (fsm-debug-output "exco--fsm connection refused for %s" url)
- (plist-put state-data :retrying nil)
- (plist-put state-data :autodiscovery-urls urls)
- (fsm-send fsm :try-next-url)))
- (list :retrieving-autodiscovery-xml state-data nil))
- (plist-put state-data :failure-message
- "Autodiscovery ran out of URLs to try")
- (list :shutting-down-on-error state-data nil))))
- (:success
- (plist-put state-data :next-state-after-success :retrieving-service-xml)
- (list :parsing-service-wsdl state-data nil))))
-
-(define-enter-state exco--fsm :shutting-down-on-error
- (_fsm state-data)
- (let ((failure-message (plist-get state-data :failure-message)))
- (exco-disconnect (plist-get state-data :identifier))
- (message "Excorporate: %s" failure-message)
- (url-debug 'excorporate "Failed: %s" failure-message)
- (fsm-debug-output "exco--fsm failed: %s" failure-message))
- (list state-data nil))
-
-(define-state exco--fsm :shutting-down-on-error
- (_fsm state-data _event _callback)
- (list :shutting-down-on-error state-data nil))
-
-(define-enter-state exco--fsm :retrieving-service-xml
- (fsm state-data)
- (when (stringp (plist-get state-data :identifier))
- (let* ((xml (plist-get state-data :service-xml))
- (unbound-wsdl (plist-get state-data :service-wsdl))
- (wsdl
- (progn
- ;; Skip soap-parse-wsdl-phase-fetch-schema to avoid
- ;; synchronous URL fetches.
- (soap-parse-wsdl-phase-finish-parsing xml unbound-wsdl)
- (exco--bind-wsdl
- (soap-wsdl-resolve-references unbound-wsdl)
- (plist-get state-data :service-url)
- "AutodiscoverServicePort"
- "http://schemas.microsoft.com/exchange/2010/Autodiscover"
- "DefaultBinding_Autodiscover"))))
- (soap-invoke-async
- (lambda (response)
- (let ((result-url
- (exco-extract-value '(Response
- UserResponses
- UserResponse
- UserSettings
- UserSetting
- Value)
- response)))
- (if result-url
- (progn
- (plist-put state-data :service-url result-url)
- (message "Excorporate: Found service URL for %S: %s"
- (plist-get state-data :identifier)
- (plist-get state-data :service-url)))
- ;; No result. Check for error.
- (let ((error-message
- (exco-extract-value '(Response
- UserResponses
- UserResponse
- ErrorMessage)
- response)))
- (if error-message
- (message "Excorporate: %s" error-message)
- (message "Excorporate: Failed to find service URL"))))
- (fsm-send fsm :retrieve-xml)))
- nil
- wsdl
- "AutodiscoverServicePort"
- "GetUserSettings"
- `((RequestedServerVersion . "Exchange2010")
- (Request
- (Users
- (User
- (Mailbox . ,(plist-get state-data :mail-address))))
- (RequestedSettings
- (Setting . "InternalEwsUrl")))))))
- (list state-data nil))
-
-(define-state exco--fsm :retrieving-service-xml
- (fsm state-data event _callback)
- (cl-case event
- (:unrecoverable-error
- (list :shutting-down-on-error state-data nil))
- (:retrieve-xml
- (let* ((service-url (plist-get state-data :service-url))
- (wsdl-url (replace-regexp-in-string "/[^/]*$" "/Services.wsdl"
- service-url)))
- (url-retrieve wsdl-url
- (lambda (status)
- (let ((data-buffer (current-buffer)))
- (unwind-protect
- (if (eq (car status) :error)
- (progn
- (plist-put state-data :failure-message
- (format "Failed to retrieve %s"
- wsdl-url))
- (fsm-send fsm :unrecoverable-error))
- (plist-put state-data
- :service-xml
- (exco--parse-xml-in-current-buffer))
- (fsm-send fsm :success))
- (and (buffer-live-p data-buffer)
- (kill-buffer data-buffer)))))))
- (list :retrieving-service-xml state-data nil))
- (:success
- (plist-put state-data :next-state-after-success :retrieving-data)
- (list :parsing-service-wsdl state-data nil))))
-
-(define-enter-state exco--fsm :parsing-service-wsdl
- (fsm state-data)
- (let* ((url (plist-get state-data :service-url))
- (xml (plist-get state-data :service-xml))
- (next-state (plist-get state-data :next-state-after-success))
- (wsdl (soap-make-wsdl url)))
- (soap-parse-wsdl-phase-validate-node xml)
- ;; Skip soap-parse-wsdl-phase-fetch-imports to avoid synchronous
- ;; fetches of import URLs.
- (soap-parse-wsdl-phase-parse-schema xml wsdl)
- (plist-put state-data :service-wsdl wsdl)
- (exco--retrieve-next-import fsm state-data :enter next-state)))
-
-(define-state exco--fsm :parsing-service-wsdl
- (fsm state-data event _callback)
- (if (eq event :unrecoverable-error)
- (list :shutting-down-on-error state-data nil)
- (let ((next-state (plist-get state-data :next-state-after-success)))
- (exco--retrieve-next-import fsm state-data :event next-state))))
-
-(defun exco--get-server-version (wsdl)
- "Extract server version from WSDL."
- (let ((warning-message "Excorporate: Failed to determine server version")
- (namespace "http://schemas.microsoft.com/exchange/services/2006/types")
- (name "RequestServerVersion")
- (found-version nil))
- (unwind-protect
- (setq found-version
- (catch 'found
- (dolist (attribute
- (soap-xs-type-attributes
- (soap-xs-element-type (soap-wsdl-get
- `(,namespace . ,name)
- wsdl 'soap-xs-element-p))))
- (when (equal (soap-xs-attribute-name attribute) "Version")
- (throw 'found (car (soap-xs-simple-type-enumeration
- (soap-xs-attribute-type attribute))))))
- (warn warning-message)
- nil))
- (if found-version
- found-version
- (warn warning-message)
- nil))))
-
-(define-enter-state exco--fsm :retrieving-data
- (_fsm state-data)
- (let ((wsdl (plist-get state-data :service-wsdl))
- (identifier (plist-get state-data :identifier)))
- ;; Skip soap-parse-wsdl-phase-fetch-schema to avoid synchronous
- ;; URL fetches.
- (soap-parse-wsdl-phase-finish-parsing (plist-get state-data :service-xml)
- wsdl)
- (exco--bind-wsdl
- (soap-wsdl-resolve-references wsdl)
- (plist-get state-data :service-url)
- "ExchangeServicePort"
- "http://schemas.microsoft.com/exchange/services/2006/messages"
- "ExchangeServiceBinding")
- (plist-put state-data :server-version (exco--get-server-version wsdl))
- (fsm-debug-output "exco--fsm %s server version is %s"
- identifier (exco-server-version identifier))
- (message "Excorporate: Connection %S is ready" identifier))
- (list state-data nil))
-
-(define-state exco--fsm :retrieving-data
- (_fsm state-data event fsm-result-callback)
- (let* ((identifier (plist-get state-data :identifier))
- (wsdl (plist-get state-data :service-wsdl))
- (name (pop event))
- (arguments (pop event))
- (callback (pop event)))
- (if callback
- ;; exco-operate.
- (apply #'soap-invoke-async
- (lambda (response)
- (funcall callback identifier response))
- nil
- wsdl
- "ExchangeServicePort"
- name
- arguments)
- ;; exco-operate-synchronously.
- (funcall
- fsm-result-callback
- (apply #'soap-invoke wsdl "ExchangeServicePort" name arguments))))
- (list :retrieving-data state-data nil))
-
-(defun exco--ensure-connection ()
- "Ensure at least one connection exists or throw an error."
- (unless exco--connection-identifiers
- (error "Excorporate: No connections exist. Run M-x excorporate")))
-
-(defmacro exco--with-fsm (identifier &rest body)
- "With `fsm' set to IDENTIFIER, run BODY.
-Run BODY with `fsm' set to the finite state machine specified by
-IDENTIFIER."
- (declare (indent 1) (debug t))
- `(progn
- (exco--ensure-connection)
- (let ((fsm (gethash ,identifier exco--connections)))
- (unless fsm
- (error "Excorporate: Connection %S does not exist" ,identifier))
- ,@body)))
-
-;; Developer-visible functions and variables.
-
-(defun exco-api-version ()
- "Return the Excorporate API version.
-Return a non-negative integer representing the current
-Excorporate application programming interface version. Version 0
-is subject to change."
- 0)
-
-(defun exco-connect (identifier)
- "Connect or reconnect to a web service.
-IDENTIFIER is either a string representing a mail address or a
-pair of strings, representing a mail address and a service URL.
-
-If IDENTIFIER is a mail address, `exco-connect' will use it to
-autodiscover the service URL to use. If IDENTIFIER is a pair,
-`exco-connect' will not perform autodiscovery, but will instead
-use the `cdr' of the pair as the service URL."
- (let ((autodiscover (stringp identifier)))
- (when autodiscover
- (message "Excorporate: Starting autodiscovery for %s" identifier))
- (let ((fsm (start-exco--fsm identifier)))
- (unless exco--connections
- (setq exco--connections (make-hash-table :test 'equal)))
- (when (gethash identifier exco--connections)
- (exco-disconnect identifier))
- (puthash identifier fsm exco--connections)
- (push identifier exco--connection-identifiers)
- (if autodiscover
- (fsm-send fsm :try-next-url)
- (fsm-send fsm :retrieve-xml))
- nil)))
-
-(defun exco-operate (identifier name arguments callback)
- "Execute a service operation asynchronously.
-IDENTIFIER is the connection identifier. Execute operation NAME
-with ARGUMENTS then call CALLBACK with two arguments, IDENTIFIER
-and the server's response."
- (when (null callback) (error "CALLBACK cannot be nil"))
- (exco--with-fsm identifier
- (fsm-send fsm (list name arguments callback)))
- nil)
-
-(defun exco-operate-synchronously (identifier name arguments)
- "Execute a service operation synchronously.
-IDENTIFIER is the connection identifier. Execute operation NAME
-with ARGUMENTS then call CALLBACK with two arguments, IDENTIFIER
-and the server's response."
- (exco--with-fsm identifier
- (with-timeout (exco--server-timeout (error "Timed out waiting for server"))
- (fsm-call fsm (list name arguments)))))
-
-(defun exco-server-version (identifier)
- "Return the server version for connection IDENTIFIER, as a string.
-Examples are \"Exchange2010\", \"Exchange2010_SP1\",
-\"Exchange2013\"."
- (exco--with-fsm identifier
- (plist-get (fsm-get-state-data fsm) :server-version)))
-
-(defun exco-disconnect (identifier)
- "Disconnect from a web service.
-IDENTIFIER is the mail address used to look up the connection."
- (exco--with-fsm identifier
- (setq exco--connection-identifiers
- (delete identifier exco--connection-identifiers))
- (remhash identifier exco--connections))
- nil)
-
-(defun exco-extract-value (path result)
- "Extract the value at PATH from RESULT.
-PATH is an ordered list of node names."
- (let ((values (nreverse (car result))))
- (dolist (path-element path)
- (setq values (assoc path-element values)))
- (cdr values)))
-
-(defun exco--create-attendee-structure (attendees required)
- "Convert a list of email addresses to an Attendees structure or nil.
-ATTENDEES is a list of strings, attendee email addresses.
-REQUIRED is t if the structure should represent required
-attendees and nil for optional attendees.
-Return a structure, or nil, suitable for splicing into
-`exco-operate` parameters with ,@."
- (when attendees
- (let ((attendee-list '()))
- (dolist (address attendees)
- (push `(Attendee (Mailbox (EmailAddress . ,address))) attendee-list))
- (list (cons (if required 'RequiredAttendees 'OptionalAttendees)
- (nreverse attendee-list))))))
-
-(defun exco-operation-arity-nils (identifier operation)
- "Return a list of nil arguments for OPERATION.
-IDENTIFIER is the connection for which to look up OPERATION."
- (let* ((wsdl (exco--with-fsm identifier
- (plist-get (fsm-get-state-data fsm) :service-wsdl)))
- (arity (soap-operation-arity wsdl "ExchangeServicePort" operation)))
- (make-list arity nil)))
-
-(defun exco-calendar-item-meeting-create (identifier
- subject body start end location
- main-invitees optional-invitees
- callback)
- "Create a meeting calendar item.
-IDENTIFIER is the connection identifier.
-SUBJECT is a string, the subject of the appointment.
-BODY is a string, the message text of the appointment.
-START is the start date and time in Emacs internal representation.
-END is the end date and time in Emacs internal representation.
-LOCATION is a string representing the location of the meeting.
-MAIN-INVITEES is a list of strings representing required
-participants.
-OPTIONAL-INVITEES is a list of strings representing optional
-participants
-CALLBACK is a callback function called with two arguments,
-IDENTIFIER, the connection identifier for the responding
-connection, and RESPONSE, the server's response to the meeting
-creation."
- (exco-operate
- identifier
- "CreateItem"
- `(((SendMeetingInvitations . "SendToAllAndSaveCopy")
- (Items
- (CalendarItem
- (Subject . ,subject)
- (Body (BodyType . "Text") ,body)
- (Start . ,(exco-format-date-time start))
- (End . ,(exco-format-date-time end))
- (Location . ,location)
- ,@(exco--create-attendee-structure main-invitees t)
- ,@(exco--create-attendee-structure optional-invitees nil))))
- ;; Empty arguments.
- ,@(cdr (exco-operation-arity-nils identifier "CreateItem")))
- callback))
-
-(defun exco-calendar-item-meeting-reply (identifier
- item-identifier message acceptance
- callback)
- "Reply to a meeting request.
-IDENTIFIER is the connection identifier. ITEM-IDENTIFIER is the
-meeting identifier. MESSAGE is the body of the reply message
-that will be sent to attendees, or nil to omit the message.
-ACCEPTANCE is a symbol representing the type of reply, one of
-`accept', `tentatively-accect' or `decline'. CALLBACK is a
-callback function called with two arguments, IDENTIFIER, the
-connection identifier for the responding connection, and
-RESPONSE, the server's response to the meeting cancellation."
- (let ((acceptance-symbol (cl-ecase acceptance
- (accept 'AcceptItem)
- (tentatively-accept 'TentativelyAcceptItem)
- (decline 'DeclineItem))))
- (exco-operate
- identifier
- "CreateItem"
- `(((MessageDisposition . "SendAndSaveCopy")
- (Items
- (,acceptance-symbol
- (Sensitivity . "Private")
- (ReferenceItemId ,@(cdr item-identifier))
- ,@(when message (list `(Body (BodyType . "Text") ,message))))))
- ;; Empty arguments.
- ,@(cdr (exco-operation-arity-nils identifier "CreateItem")))
- callback)))
-
-(defun exco-calendar-item-meeting-cancel (identifier
- item-identifier message callback)
- "Cancel a meeting.
-IDENTIFIER is the connection identifier. ITEM-IDENTIFIER is the
-meeting identifier. MESSAGE is the body of the cancellation
-message that will be sent to attendees. CALLBACK is a callback
-function called with two arguments, IDENTIFIER, the connection
-identifier for the responding connection, and RESPONSE, the
-server's response to the meeting cancellation."
- (exco-operate
- identifier
- "CreateItem"
- `(((MessageDisposition . "SendAndSaveCopy")
- (Items
- (CancelCalendarItem
- (ReferenceItemId ,@(cdr item-identifier))
- (NewBodyContent (BodyType . "Text") ,message))))
- ;; Empty arguments.
- ,@(cdr (exco-operation-arity-nils identifier "CreateItem")))
- callback))
-
-(defun exco-calendar-item-appointment-create (identifier
- subject body start end callback)
- "Create an appointment calendar item.
-IDENTIFIER is the connection identifier.
-SUBJECT is a string, the subject of the appointment.
-BODY is a string, the message text of the appointment.
-START is the start date and time in Emacs internal representation.
-END is the end date and time in Emacs internal representation.
-CALLBACK is a callback function called with two arguments,
-IDENTIFIER, the connection identifier for the responding
-connection, and RESPONSE, the server's response to the
-appointment creation."
- (exco-operate identifier
- "CreateItem"
- `(((SendMeetingInvitations . "SendToNone")
- (Items
- (CalendarItem
- (Subject . ,subject)
- (Body (BodyType . "Text") ,body)
- (Start . ,(exco-format-date-time start))
- (End . ,(exco-format-date-time end)))))
- nil nil nil nil)
- callback))
-
-(defun exco-calendar-item-appointment-delete (identifier
- item-identifier callback)
- "Delete an appointment.
-IDENTIFIER is the connection identifier. ITEM-IDENTIFIER is an
-opaque item identifier. CALLBACK is a callback function called
-with two arguments, IDENTIFIER, the connection identifier for the
-responding connection, and RESPONSE, the server's response to the
-appointment deletion."
- (exco-operate identifier
- "DeleteItem"
- `(((DeleteType . "MoveToDeletedItems")
- (SendMeetingCancellations . "SendToAllAndSaveCopy")
- (ItemIds ,item-identifier))
- nil nil nil)
- callback))
-
-(defun exco-calendar-item-get-details (identifier item-identifier process-item)
- "Query server for details about ITEM-IDENTIFIER.
-IDENTIFIER is the connection identifier. Call PROCESS-ITEM with
-argument ICALENDAR-TEXT."
- (exco-operate identifier
- "GetItem"
- `(((ItemShape
- (BaseShape . "IdOnly")
- (IncludeMimeContent . t))
- (ItemIds ,item-identifier))
- nil nil nil nil nil nil)
- (lambda (_identifier response)
- (let* ((mime-path '(ResponseMessages
- GetItemResponseMessage
- Items
- CalendarItem
- MimeContent))
- (character-set-path (append mime-path '(CharacterSet)))
- (coding-system (intern (downcase (exco-extract-value
- character-set-path
- response)))))
- (unless (member coding-system coding-system-list)
- (error "Unrecognized coding system: %s"
- (exco-extract-value character-set-path response)))
- (funcall process-item (decode-coding-string
- (base64-decode-string
- (cdr (exco-extract-value
- mime-path response)))
- coding-system))))))
-
-;; The organizer email address is in some cases returned in the
-;; server's internal "EX" format which is very long and unfamiliar.
-;; If necessary resolve it to the "SMTP" format. This is done
-;; synchronously, for simplicity.
-(defun exco-resolve-organizer-email-address-synchronously (identifier
- organizer-structure)
- "Return the organizer's SMTP email address as a string.
-IDENTIFIER is the connection identifier to use to resolve
-ORGANIZER-STRUCTURE to the returned value. ORGANIZER-STRUCTURE
-should be treated as opaque. If the address is not already an
-SMTP address, then this function queries the server synchronously
-to resolve the SMTP address. It times out and returns nil if the
-server does not respond in under `exco--server-timeout' seconds."
- (let* ((wrapped (list (list organizer-structure)))
- (routing-type
- (exco-extract-value '(Organizer Mailbox RoutingType) wrapped))
- (email-address
- (exco-extract-value '(Organizer Mailbox EmailAddress) wrapped)))
- (cond
- ((equal routing-type "EX")
- (exco-extract-value
- '(ResponseMessages
- ResolveNamesResponseMessage
- ResolutionSet
- Resolution
- Mailbox
- EmailAddress)
- (with-timeout
- (exco--server-timeout
- (progn
- (message (concat "exco-organizer-smtp-email-address:"
- " Server did not respond in time"))
- nil))
- (exco-operate-synchronously identifier
- "ResolveNames"
- `(((UnresolvedEntry . ,email-address))
- nil nil nil)))))
- ((equal routing-type "SMTP") email-address))))
-
-(defmacro exco--calendar-item-dolist (item items &rest forms)
- "Iterate through ITEMS.
-On each iteration, ITEM is set, and FORMS are run."
- `(dolist (,item ,items)
- (let* ((subject (cdr (assoc 'Subject ,item)))
- (start (cdr (assoc 'Start ,item)))
- (start-internal (apply #'encode-time
- (soap-decode-date-time
- start 'dateTime)))
- (end (cdr (assoc 'End ,item)))
- (end-internal (apply #'encode-time
- (soap-decode-date-time
- end 'dateTime)))
- (location (cdr (assoc 'Location ,item)))
- (to-invitees (cdr (assoc 'DisplayTo ,item)))
- (main-invitees (when to-invitees
- (mapcar 'org-trim
- (split-string to-invitees ";"))))
- (cc-invitees (cdr (assoc 'DisplayCc ,item)))
- (optional-invitees (when cc-invitees
- (mapcar 'org-trim
- (split-string cc-invitees ";"))))
- (item-identifier (assoc 'ItemId ,item))
- (organizer-structure (assoc 'Organizer ,item)))
- ,@forms)))
-
-(defun exco-calendar-item-with-details-iterate (identifier
- response
- callback
- finalize)
- "Iterate through calendar items in RESPONSE, calling CALLBACK on each.
-IDENTIFIER identifies the connection.
-
-CALLBACK takes the following arguments: FINALIZE, which is the
-FINALIZE argument to this function wrapped in a countdown,
-SUBJECT, a string, the subject of the meeting, START, the start
-date and time in Emacs internal representation, END, the start
-date and time in Emacs internal representation, LOCATION, the
-location of the meeting, MAIN-INVITEES, a list of strings
-representing required participants, OPTIONAL-INVITEES, a list of
-strings representing optional participants, DETAILS is the
-meeting request message body, and ICALENDAR-TEXT, the iCalendar
-text representing the meeting series.
-
-CALLBACK must arrange for FINALIZE to be called after its main
-processing is done."
- (let* ((items (exco-extract-value '(ResponseMessages
- FindItemResponseMessage
- RootFolder
- Items)
- response))
- (countdown (length items))
- (finalizer
- (lambda (&rest arguments)
- (setq countdown (1- countdown))
- (when (equal countdown 0)
- (apply finalize arguments)))))
- (if (equal countdown 0)
- (funcall finalize)
- (exco--calendar-item-dolist
- calendar-item items
- (exco-calendar-item-get-details
- identifier item-identifier
- (lambda (icalendar-text)
- (funcall callback finalizer subject start-internal end-internal
- location main-invitees optional-invitees
- icalendar-text)))))))
-
-(defmacro exco-calendar-item-iterate-general (response
- callback &rest care-abouts)
- "Iterate through calendar items in RESPONSE, calling CALLBACK on each.
-Return a list of results from callback. CARE-ABOUTS is a list of
-symbols representing the arguments with which CALLBACK should be
-called. Options are:
-SUBJECT, a string, the subject of the meeting.
-START, the start date and time in Emacs internal representation.
-END, the start date and time in Emacs internal representation.
-LOCATION, the location of the meeting.
-MAIN-INVITEES, a list of strings, email addresses of the required
-participants.
-OPTIONAL-INVITEES, a list of strings, email addresses of optional
-participants.
-ITEM-IDENTIFIER, a structure representing the calendar item. It
-should be treated as opaque.
-ORGANIZER-STRUCTURE, a structure representing the organizer of
-the meeting. It should be treated as opaque and resolved with
-`exco-organizer-smtp-email-address'."
- `(let ((result-list '()))
- (exco--calendar-item-dolist
- calendar-item (exco-extract-value '(ResponseMessages
- FindItemResponseMessage
- RootFolder
- Items)
- ,response)
- (push (funcall ,callback ,@care-abouts)
- result-list))
- (nreverse result-list)))
-
-(defun exco-calendar-item-iterate (response callback)
- "Iterate through calendar items in RESPONSE, calling CALLBACK on each.
-Return a list of results from callback. CALLBACK takes arguments:
-SUBJECT, a string, the subject of the meeting.
-START, the start date and time in Emacs internal representation.
-END, the start date and time in Emacs internal representation.
-LOCATION, the location of the meeting.
-MAIN-INVITEES, a list of strings, email addresses of the required
-participants.
-OPTIONAL-INVITEES, a list of strings, email addresses of optional
-participants."
- (exco-calendar-item-iterate-general
- response callback
- subject start-internal end-internal
- location main-invitees optional-invitees))
-
-;; Date-time utility functions.
-(defun exco-extend-timezone (date-time-string)
- "Add a colon to the timezone in DATE-TIME-STRING.
-DATE-TIME-STRING must be formatted as if returned by
-`format-time-string' with FORMAT-STRING \"%FT%T%z\". Web
-services require the ISO8601 extended format of timezone, which
-includes the colon."
- (concat
- (substring date-time-string 0 22) ":" (substring date-time-string 22)))
-
-(defun exco-format-date-time (time-internal)
- "Convert TIME-INTERNAL to an XSD compatible date-time string."
- (exco-extend-timezone
- (format-time-string "%FT%T%z" time-internal)))
-
-;; Use month day year order to be compatible with
-;; calendar-cursor-to-date. I wish I could instead use the ISO 8601
-;; ordering, year month day.
-(defun exco-get-meetings-for-day (identifier month day year callback)
- "Return the meetings for the specified day.
-IDENTIFIER is the connection identifier. MONTH, DAY and YEAR are
-the meeting month, day and year. Call CALLBACK with two
-arguments, IDENTIFIER and the server's response."
- (let* ((start-of-day-time-internal
- (apply #'encode-time `(0 0 0 ,day ,month ,year)))
- (start-of-day-date-time
- (exco-format-date-time start-of-day-time-internal))
- (start-of-next-day-date-time
- (exco-extend-timezone
- (format-time-string "%FT00:00:00%z"
- (time-add start-of-day-time-internal
- (seconds-to-time 86400))))))
- (exco-operate
- identifier
- "FindItem"
- `(;; Main arguments.
- (;; RequestVersion is usually overridden by a fixed value in
- ;; the WSDL (the RequestServerVersion element); provide the
- ;; maximally-compatible Exchange2007 if the fixed value isn't
- ;; present.
- (RequestVersion (Version . "Exchange2007"))
- (Traversal . "Shallow")
- (ItemShape
- (BaseShape . "AllProperties"))
- ;; To aid productivity, excorporate-calfw automatically prunes your
- ;; meetings to a maximum of 100 per day.
- (CalendarView (MaxEntriesReturned . "100")
- (StartDate . ,start-of-day-date-time)
- (EndDate . ,start-of-next-day-date-time))
- (ParentFolderIds
- (DistinguishedFolderId (Id . "calendar"))))
- ;; Empty arguments.
- ,@(cdr (exco-operation-arity-nils identifier "FindItem")))
- callback)))
-
-(defun exco-connection-iterate (initialize-function
- per-connection-function
- per-connection-callback
- finalize-function
- &optional callback-will-call-finalize)
- "Iterate Excorporate connections.
-Call INITIALIZE-FUNCTION once before iterating. It takes no
-arguments.
-
-Call PER-CONNECTION-FUNCTION once for each server connection. It
-is run synchronously. It accepts two arguments, IDENTIFIER, the
-current server connection, and CALLBACK, which is a wrapped
-version of PER-CONNECTION-CALLBACK.
-
-PER-CONNECTION-CALLBACK takes a variable number of arguments,
-depending on which callback it is. If
-CALLBACK-WILL-CALL-FINALIZE is non-nil, it takes a final
-FINALIZE-FUNCTION argument, which is a countdown-wrapped
-finalizer function that PER-CONNECTION-CALLBACK should call (or
-arrange to be called asynchronously) each time it is invoked.
-
-If CALLBACK-WILL-CALL-FINALIZE is non-nil, this function will not
-call FINALIZE-FUNCTION itself. Instead it will wrap
-FINALIZE-FUNCTION into a function that can be called once per
-connection, then pass the wrapped finalizer to the callback as an
-argument. CALLBACK-WILL-CALL-FINALIZE must be set if the
-callback needs to make a recursive asynchronous call."
- (exco--ensure-connection)
- (funcall initialize-function)
- (let* ((countdown (length exco--connection-identifiers))
- (wrapped-finalizer
- (lambda (&rest arguments)
- (setq countdown (1- countdown))
- (when (equal countdown 0)
- (apply finalize-function arguments))))
- (wrapped-callback
- (lambda (&rest arguments)
- (apply per-connection-callback
- (append arguments
- (when callback-will-call-finalize
- (list wrapped-finalizer))))
- (unless callback-will-call-finalize
- (funcall wrapped-finalizer)))))
- (dolist (identifier exco--connection-identifiers)
- (funcall per-connection-function identifier
- wrapped-callback))))
-
-;; User-visible functions and variables.
-(defgroup excorporate nil
- "Exchange support."
- :version "25.1"
- :group 'comm
- :group 'calendar)
-
-;; Name the excorporate-configuration variable vaguely. It is currently a
-;; MAIL-ADDRESS string, a pair (MAIL-ADDRESS . SERVICE-URL), or nil. In the
-;; future it could allow a list of strings and pairs.
-(defcustom excorporate-configuration nil
- "Excorporate configuration.
-
-This is the account information that Excorporate uses to connect
-to one or more Exchange servers. No secrets are stored here. To
-manage passwords, Excorporate will either use `auth-source' or
-prompt for them in the minibuffer.
-
-This customization variable can hold a string representing an
-Exchange email address, or a pair of strings representing an
-Exchange email address and an Exchange Web Services (EWS) URL, or
-a list of such strings and pairs of strings.
-
-Specifying just an email address implies that Excorporate should
-attempt to autodiscover the service URL for the account.
-
-Examples:
-
-\"hacker@gnu.org\"
-=> Excorporate will attempt to autodiscover the EWS URL
-
-\(\"hacker@gnu.org\" . \"https://mail.gnu.org/EWS/Exchange.asmx\")
-=> Excorporate will use the provided EWS URL
-
-Other Excorporate documentation refers to the email address as
-the \"mail address\", and the EWS URL as the \"service URL\"."
- :type
- '(choice
- (const
- :tag "Prompt for Exchange account information" nil)
- #1=(string
- :tag "Exchange email address (autodiscover settings)")
- #2=(cons
- :tag "Exchange email address and EWS URL (no autodiscovery)"
- (string :tag "Exchange mail address (e.g., hacker@gnu.org)")
- (string :tag "EWS URL (e.g., https://mail.gnu.org/EWS/Exchange.asmx)"))
- (repeat :tag "List of configurations"
- (choice #1# #2#))))
-
-(defun exco--string-or-string-pair-p (value)
- "Return t if VALUE is a string or a pair of strings."
- (or (stringp value)
- ;; A single dotted pair with neither element nil.
- (and (consp value)
- (not (consp (cdr value)))
- (not (null (car value)))
- (not (null (cdr value))))))
-
-;;;###autoload
-(defun excorporate (&optional argument)
- "Start Excorporate.
-If `excorporate-configuration' is non-nil, use it without
-prompting, otherwise prompt for Exchange account information, starting
-with an email address.
-
-Prefixed with one \\[universal-argument], always prompt for
-Exchange account information for a new web service connection.
-ARGUMENT is the prefix argument."
- (interactive "P")
- (cond
- ((or (equal argument '(4))
- (eq excorporate-configuration nil))
- ;; Prompt.
- (let* ((url "https://mail.gnu.org/EWS/Exchange.asmx")
- (suggestion user-mail-address)
- (ask-1 "Exchange mail address: ")
- (ask-2 "Attempt settings autodiscovery ('n' for Office 365)?")
- (ask-3 "EWS URL: ")
- (mail (completing-read ask-1 (list suggestion) nil nil suggestion))
- (identifier
- (if (y-or-n-p ask-2)
- mail
- (cons mail(completing-read ask-3 (list url) nil nil url)))))
- (exco-connect identifier)))
- ((exco--string-or-string-pair-p excorporate-configuration)
- ;; A single string or a single pair.
- (exco-connect excorporate-configuration))
- ((consp (cdr excorporate-configuration))
- ;; A proper list.
- (dolist (configuration excorporate-configuration)
- (if (exco--string-or-string-pair-p configuration)
- (exco-connect configuration)
- (warn "Skipping invalid configuration: %s" configuration))))
- (t
- (error "Excorporate: Invalid configuration"))))
-
-(provide 'excorporate)
-
-;;; excorporate.el ends here
diff --git a/packages/excorporate/excorporate.info
b/packages/excorporate/excorporate.info
deleted file mode 100644
index 9214a8d..0000000
--- a/packages/excorporate/excorporate.info
+++ /dev/null
@@ -1,746 +0,0 @@
-This is excorporate.info, produced by makeinfo version 6.7 from
-excorporate.texi.
-
-Copyright (C) 2016 Free Software Foundation, Inc.
-
- Permission is granted to copy, distribute and/or modify this
- document under the terms of the GNU Free Documentation License,
- Version 1.2 or any later version published by the Free Software
- Foundation; with no Invariant Sections, with the Front-Cover, or
- Back-Cover Texts. A copy of the license is included in the section
- entitled "GNU Free Documentation License" in the Emacs manual.
-
- This document is part of a collection distributed under the GNU
- Free Documentation License. If you want to distribute this
- document separately from the collection, you can do so by adding a
- copy of the license to the document, as described in section 6 of
- the license.
-
- All Emacs Lisp code contained in this document may be used,
- distributed, and modified without restriction.
-INFO-DIR-SECTION Emacs
-START-INFO-DIR-ENTRY
-* Excorporate: (excorporate). Exchange Web Services integration for Emacs.
-END-INFO-DIR-ENTRY
-
-
-File: excorporate.info, Node: Top, Next: Reporting Bugs, Up: (dir)
-
-Excorporate Manual
-******************
-
-Excorporate provides Exchange Web Services (EWS) support for Emacs.
-
- If the Exchange server you access is configured to provide EWS
-support, then there's an 86% chance that Excorporate will enable you to
-retrieve your calendar entries from the comfort of Emacs.
-
- The 14% failure rate is because authenticating against an Exchange
-server can be challenging.
-
- Accessing an Exchange server through an HTTPS proxy is possible now
-that <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=10> and
-<https://debbugs.gnu.org/cgi/bugreport.cgi?bug=35969> are fixed.
-
- Kerberos/GSSAPI authentication needs more experimentation.
-
- Reports of success or failure of different connection types are
-welcome, as are patches to enable more of these access scenarios. See
-*note Reporting Bugs::.
-
-* Menu:
-
-* Reporting Bugs:: How to report bugs in Excorporate
-* Installation:: Getting and installing 'excorporate'.
-* Configuration:: Configuring 'excorporate'.
-* Usage:: Using 'excorporate'.
-* Troubleshooting:: Debugging why a connection failed
-* API Usage:: Using the API provided by 'excorporate'.
-
-
-File: excorporate.info, Node: Reporting Bugs, Next: Installation, Prev:
Top, Up: Top
-
-1 Reporting Bugs
-****************
-
-To report a bug, send an email to 'bug-gnu-emacs@gnu.org' using your
-favourite email program. Put "Excorporate" somewhere in the subject
-line, for example: "Excorporate: Failed to authenticate".
-
-
-File: excorporate.info, Node: Installation, Next: Configuration, Prev:
Reporting Bugs, Up: Top
-
-2 Installation
-**************
-
-Excorporate works on Emacs versions >= 24.1.
-
-Install 'excorporate' from the GNU ELPA repository:
-
- 'M-x package-install RET excorporate'
-
-
-File: excorporate.info, Node: Configuration, Next: Usage, Prev:
Installation, Up: Top
-
-3 Configuration
-***************
-
-Ideally you won't need to configure Excorporate beyond providing your
-account email address. On friendly Exchange setups, Excorporate can
-discover the EWS URL automatically.
-
-Run:
-
- 'M-x excorporate'
-
-which will prompt you for the Exchange account configuration. Follow
-the prompts and if all goes well, you'll see a message in the minibuffer
-or in *Messages* saying that the connection is ready. Using the
-prompts, you can first try with autodiscovery. If autodiscovery runs
-out of URLs to try, re-run 'excorporate', saying 'n' to the
-autodiscovery attempt, at which point you will be asked for the EWS URL.
-
-To save a working configuration, customize 'excorporate-configuration':
-
- 'M-x customize-variable RET excorporate-configuration'
-
-After saving the configuration, try 'M-x excorporate' again.
-
-If neither autodiscovery nor specifying the EWS URL work, *note
-Troubleshooting::.
-
-
-File: excorporate.info, Node: Usage, Next: Troubleshooting, Prev:
Configuration, Up: Top
-
-4 Usage
-*******
-
-Excorporate can put entries it retrieves into the Emacs Diary, and use
-'appt' to remind you a few minutes before a meeting starts. To enable
-this support, do:
-
- 'M-x excorporate-diary-enable'
-
- Excorporate's diary front-end will retrieve today's meetings.
-Subsequently 'appt' will pop up a reminder window several minutes prior
-to each meeting.
-
- If you leave Emacs running overnight, at 12:01 AM 'appt' (via
-Excorporate) will retrieve your meetings and display your diary so that
-you see the day's events first thing in the morning.
-
-Open the calendar with:
-
- 'M-x calendar'
-
-move the cursor to the date you want to see meetings for, and press 'd'.
-Some time later, asynchronously, a window will pop up containing events
-retrieved from the Exchange server in addition to locally-entered diary
-events. The events are all sorted by time.
-
- Excorporate also binds 'e' in '*Calendar*' buffers to
-'excorporate-calendar-show-day-function' to allow a different view of
-retrieved events. By default, 'excorporate-calendar-show-day-function'
-is set to 'exco-org-show-day' which displays meetings in a temporary
-read-only Org Mode buffer named '*Excorporate*'.
-
- In the Org Mode '*Excorporate*' buffer, you can run 'M-x
-exco-org-decline-meeting-request' to decline a meeting request. To
-accept, use ('exco-org-accept-meeting-request') or, to tentatively
-accept, invoke ('exco-org-tentatively-accept-meeting-request'). Pass a
-prefix argument to these functions to omit a reply message.
-
- A meeting is a calendar event to which at least one other person is
-invited. To cancel a meeting (or an occurence of a recurring meeting)
-that you organized, use 'M-x exco-org-cancel-meeting'.
-
- An appointment is a calendar item that has no invitees. To delete an
-appointment that you created, type 'M-x exco-org-delete-appointment'.
-With a prefix argument, 'M-x exco-org-delete-appointment' can be used to
-force-delete calendar items, whether they be meetings or appointments.
-One example where this is necessary is when "cancelling" a meeting with
-a single invitee, you, the organizer. The server will reject an attempt
-to cancel such a meeting because it refuses to send the organizer a
-cancellation message.
-
- If you prefer, you can install the 'calfw' package, and set
-'excorporate-calendar-show-day-function' to 'exco-calfw-show-day'.
-
-
-File: excorporate.info, Node: Troubleshooting, Next: API Usage, Prev:
Usage, Up: Top
-
-5 Troubleshooting
-*****************
-
-First, you'll want to double-check that the Exchange server you're
-trying to access provides EWS support. If it doesn't, Excorporate can't
-do anything for you. Before asking your Exchange administrator, check
-intranet wikis and so forth; other users of non-standard clients may
-have already found the EWS URL. This is called the "EWS endpoint". It
-can be as simple as, e.g.:
-
- 'https://mail.gnu.org/EWS/Exchange.asmx'
-
-First you need to make sure you can access the endpoint.
-
-For Exchange Web Services (EWS) which Excorporate uses, you'll have to
-determine the EWS endpoint for your Exchange account, call it 'ews-url'.
-It is usually something like:
-
- https://<mail host name>/EWS/Exchange.asmx
-
-Excorporate calculates the WSDL URL, call it 'wsdl-url', by replacing
-the endpoint's last path element with "Services.wsdl":
-
- https://<mail host name>/EWS/Services.wsdl
-
-Before even attempting Excorporate, you have to make these succeed:
-
- (with-current-buffer
- (url-retrieve-synchronously ews-url)
- (buffer-string))
-
-When this works, you'll see web page text in *Messages*, containing a
-message about having created a service.
-
- (with-current-buffer
- (url-retrieve-synchronously wsdl-url)
- (buffer-string))
-
-When this works, it will show a bunch of WSDL (XML) in *Messages*.
-
-Debug the above URL retrievals with 'M-:' in an 'emacs -Q' run:
-
- (progn
- (setq url-debug 1)
- (url-retrieve-synchronously URL-STRING)
- (dolist (p (seq-filter
- (lambda (b) (string-match " *http*" (buffer-name b)))
- (buffer-list)))
- (message "HTTP result buffer: \"%s\"\n%s"
- (buffer-name p)
- (with-current-buffer p (buffer-string))))
- "check *Messages*")
-
-Beware that HTTP responses can be out-of-order, and that if you set
-'url-debug' to a number or 't', Emacs may hang for a while if it
-attempts to print a very large data structure.
-
-Once you're sure the above steps are working, try 'M-x excorporate'.
-
-The buffer '*fsm-debug*' shows 'excorporate' state transitions and
-should provide details of where things went wrong.
-
-Also check '*Messages*' for anything obvious.
-
-If you suspect something wrong with accessing the EWS URL, try setting
-'url-debug' to t and retry 'M-x excorporate', then check the
-'*URL-DEBUG*' buffer for output.
-
-If you suspect NTLM authentication is failing, as a long shot, you might
-try setting 'ntlm-compatibility-level' to 0 and retrying 'M-x
-excorporate'.
-
-Excorporate's dependencies implement the tricky elements of asynchronous
-Exchange access: a state machine ('fsm'), TLS negotiation ('gnutls'),
-NTLM authentication ('ntlm' and 'url-http-ntlm') and SOAP communication
-('soap-client').
-
-
-File: excorporate.info, Node: API Usage, Prev: Troubleshooting, Up: Top
-
-6 API Usage
-***********
-
-Here are some examples of using the API (application programming
-interface) provided by Excorporate.
-
-Not all of Excorporate's functionality is exposed as interactive
-functions. Here is an example of creating a meeting to which
-hacker2@gnu.org is invited, using a non-interactive function provided by
-Excorporate:
-
- (exco-calendar-item-meeting-create
- (car exco--connection-identifiers)
- "Test meeting 1"
- "Hi,\n\nThis is a test meeting 1.\n\nRegards.\n"
- (encode-time 0 15 14 23 09 2020)
- (encode-time 0 0 15 23 09 2020)
- "Online only"
- '("hacker2@gnu.org")
- nil
- (lambda (identifier response)
- (message "%S: %S" identifier response)))
- =>
- ;; Printed in *Messages*:
- ("hacker1@gnu.org" . "https://mail.gnu.org/EWS/Exchange.asmx"):
- (((ResponseMessages
- (CreateItemResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError")
- (Items
- (CalendarItem
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]M"))))))))
-
-The callback is run asychronously after the server responds, so as not
-to block Emacs, and the result is what is printed in the '*Messages*'
-buffer. This example assumes the user has already run 'M-x excorporate'
-to create a connection. '(car exco--connection-identifiers)' is a hack
-that uses the first-established connection. Excorporate fully supports
-connecting to multiple different servers though (see
-'exco-connection-iterate') so published code that uses the Excorporate
-API should not assume just one connection.
-
-There is lots of server-side functionality that Excorporate does not
-provide high-level non-interactive functions for. Using that
-functionality is still possible with the low-level 'exco-operate' and
-'exco-operate-synchronously' functions.
-
-For example, evaluating this form produces lots of details about the
-meeting represented by the ItemId form, including tidbits like the list
-of invitees and how they've responded (accepted, declined, tentatively
-accepted, unknown). You can find ItemId forms to experiment with in the
-PROPERTIES drawer of calendar entries in the interactive Org buffer.
-
- (exco-operate-synchronously
- (car exco--connection-identifiers)
- "GetItem"
- '(((ItemShape
- (BaseShape . "AllProperties"))
- (ItemIds
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]d"))))
- nil nil nil nil nil nil))
- =>
- (((ResponseMessages
- (GetItemResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError")
- (Items
- (CalendarItem
- (ItemId (Id . "A[...]A==") (ChangeKey . "D[...]M"))
- (ParentFolderId (Id . "A[...]A") (ChangeKey . "A[...]A=="))
- (ItemClass . "IPM.Appointment")
- (Subject . "Excorporate discussion")
- (Sensitivity . "Normal")
- (Body (BodyType . "Text") . "Hi Hacker Two,
-
- Let's discuss Excorporate.
-
- Hacker One")
- (DateTimeReceived . "2020-09-24T20:07:26Z")
- (Size . 13709)
- (Importance . "Normal")
- (IsSubmitted)
- (IsDraft)
- (IsFromMe)
- (IsResend)
- (IsUnmodified)
- (DateTimeSent . "2020-09-24T20:07:26Z")
- (DateTimeCreated . "2020-09-24T20:07:26Z")
- (ResponseObjects
- (ForwardItem)
- (CancelCalendarItem))
- (ReminderDueBy . "2020-09-25T14:30:00Z")
- (ReminderIsSet . t)
- (ReminderMinutesBeforeStart . 15)
- (DisplayCc)
- (DisplayTo . "Hacker Two")
- (HasAttachments)
- (Culture . "en-US")
- (Start . "2020-09-25T14:30:00Z")
- (End . "2020-09-25T15:30:00Z")
- (IsAllDayEvent)
- (LegacyFreeBusyStatus . "Busy")
- (Location . "Online")
- (IsMeeting . t)
- (IsCancelled)
- (IsRecurring)
- (MeetingRequestWasSent . t)
- (IsResponseRequested . t)
- (CalendarItemType . "Single")
- (MyResponseType . "Organizer")
- (Organizer
- (Mailbox
- (Name . "Hacker One")
- (EmailAddress . "hacker1@gnu.org")
- (RoutingType . "SMTP")))
- (RequiredAttendees
- (Attendee
- (Mailbox
- (Name . "Hacker Two")
- (EmailAddress . "hacker2@gnu.org")
- (RoutingType . "SMTP")
- (MailboxType . "Mailbox"))
- (ResponseType . "Accept")
- (LastResponseTime . "2020-09-24T21:08:54Z")))
- (Duration . "PT1H")
- (TimeZone . "(UTC+00:00) Monrovia, Reykjavik")
- (AppointmentSequenceNumber . 0)
- (AppointmentState . 1)
- (IsOnlineMeeting)))))))
-
-Note that this function queries the server synchronously. In other
-words, it waits for, and evaluates to, the server's reply. This is nice
-when experimenting with the API, but published code should mostly use
-the asynchronous calls to avoid blocking Emacs during server operations.
-
-Here is a more complicated example that asynchronously queries the
-server for availability overlap for hacker1@gnu.org and hacker2@gnu.org,
-in the Eastern Time time zone.
-
- (exco-operate
- (car exco--connection-identifiers)
- "GetUserAvailability"
- '(((TimeZone
- (Bias . 300)
- (StandardTime
- (Bias . 0)
- (Time . "02:00:00")
- (DayOrder . 1)
- (Month . 11)
- (DayOfWeek . "Sunday"))
- (DaylightTime
- (Bias . -60)
- (Time . "02:00:00")
- (DayOrder . 2)
- (Month . 3)
- (DayOfWeek . "Sunday")))
- (MailboxDataArray
- (MailboxData
- (Email
- (Address . "hacker1@gnu.org"))
- (AttendeeType . "Required")
- (ExcludeConflicts . nil))
- (MailboxData
- (Email
- (Address . "hacker2@gnu.org"))
- (AttendeeType . "Required")
- (ExcludeConflicts . nil)))
- (FreeBusyViewOptions
- (TimeWindow
- (StartTime . "2020-09-25T00:00:00Z")
- (EndTime . "2020-09-25T23:59:00Z"))
- (MergedFreeBusyIntervalInMinutes . 60)
- (RequestedView "DetailedMerged")))
- nil nil nil)
- (lambda (identifier response)
- (message "%S: %S" identifier response)))
- =>
- ;; Printed in *Messages*:
- ("hacker1@gnu.org" . "https://mail.gnu.org/EWS/Exchange.asmx"):
- (((FreeBusyResponseArray
- (FreeBusyResponse
- (ResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError"))
- (FreeBusyView
- (FreeBusyViewType "FreeBusyMerged")
- (MergedFreeBusy . "000000000000000000000200")
- (CalendarEventArray
- (CalendarEvent
- (StartTime . "2020-09-25T12:00:00")
- (EndTime . "2020-09-25T12:30:00")
- (BusyType . "Busy")))
- (WorkingHours
- (TimeZone
- (Bias . 480)
- (StandardTime
- (Bias . 0)
- (Time . "02:00:00")
- (DayOrder . 1)
- (Month . 11)
- (DayOfWeek . "Sunday"))
- (DaylightTime
- (Bias . -60)
- (Time . "02:00:00")
- (DayOrder . 2)
- (Month . 3)
- (DayOfWeek . "Sunday")))
- (WorkingPeriodArray
- (WorkingPeriod
- (DayOfWeek "Monday" "Tuesday" "Wednesday" "Thursday" "Friday")
- (StartTimeInMinutes . 540)
- (EndTimeInMinutes . 1080))))))
- (FreeBusyResponse
- (ResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError"))
- (FreeBusyView
- (FreeBusyViewType "DetailedMerged")
- (MergedFreeBusy . "000000000000002200000200")
- (CalendarEventArray
- (CalendarEvent
- (StartTime . "2020-09-25T05:30:00")
- (EndTime . "2020-09-25T06:30:00")
- (BusyType . "Busy")
- (CalendarEventDetails
- (ID . "0[...]0")
- (Subject . "Excorporate discussion")
- (Location . "Online")
- (IsMeeting . t)
- (IsRecurring)
- (IsException)
- (IsReminderSet . t)
- (IsPrivate)))
- (CalendarEvent
- (StartTime . "2020-09-25T12:00:00")
- (EndTime . "2020-09-25T12:30:00")
- (BusyType . "Busy")
- (CalendarEventDetails
- (ID . "0[...]0")
- (Subject . "An occurence of a recurring meeting")
- (Location)
- (IsMeeting . t)
- (IsRecurring . t)
- (IsException)
- (IsReminderSet . t)
- (IsPrivate))))
- (WorkingHours
- (TimeZone
- (Bias . 480)
- (StandardTime
- (Bias . 0)
- (Time . "02:00:00")
- (DayOrder . 1)
- (Month . 11)
- (DayOfWeek . "Sunday"))
- (DaylightTime
- (Bias . -60)
- (Time . "02:00:00")
- (DayOrder . 2)
- (Month . 3)
- (DayOfWeek . "Sunday")))
- (WorkingPeriodArray
- (WorkingPeriod
- (DayOfWeek "Monday" "Tuesday" "Wednesday" "Thursday" "Friday")
- (StartTimeInMinutes . 480)
- (EndTimeInMinutes . 1020)))))))))
-
-This example shows how to create a recurrence in the "Eastern Standard
-Time" time zone. The 'exco-operation-arity-nils' call returns a list of
-nils with a length matching the number of arguments that the
-'CreateItem' operation takes. Arguments other than the first
-("request") argument may be needed in the future to use more complicated
-server functionality, but for now they can all be left 'nil'.
-
- (exco-operate
- (car exco--connection-identifiers)
- "CreateItem"
- `(((SendMeetingInvitations . "SendToAllAndSaveCopy")
- (Items
- (CalendarItem
- (Subject . "Test recurrence 1")
- (Body (BodyType . "Text") "Testing recurrence creation.")
- (Start . "2020-09-25T17:00:00-04:00")
- (End . "2020-09-25T18:00:00-04:00")
- (StartTimeZone (Id . "Eastern Standard Time"))
- (EndTimeZone (Id . "Eastern Standard Time"))
- (Location . "Online")
- (RequiredAttendees
- (Attendee (Mailbox (EmailAddress . "hacker1@gnu.org"))))
- (Recurrence
- (WeeklyRecurrence
- (Interval . 1)
- (DaysOfWeek "Friday"))
- (NumberedRecurrence
- (StartDate . "2020-09-25-04:00")
- (NumberOfOccurrences . 4))))))
- ;; Empty arguments.
- ,@(cdr (exco-operation-arity-nils identifier "CreateItem")))
- (lambda (identifier response)
- (message "%S: %S" identifier response)))
- =>
- ;; Printed in *Messages*:
- ("hacker1@gnu.org" . "https://mail.gnu.org/EWS/Exchange.asmx"):
- (((ResponseMessages
- (CreateItemResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError")
- (Items
- (CalendarItem
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]k"))))))))
-
-Now we can retrieve the item's properties to see the recurrence and time
-zone details:
-
- (exco-operate
- (car exco--connection-identifiers)
- "GetItem"
- '(((ItemShape
- (BaseShape . "AllProperties"))
- (ItemIds
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]d"))))
- nil nil nil nil nil nil)
- (lambda (identifier response)
- (message "%S: %S" identifier response)))
- =>
- ;; Printed in *Messages*:
- ("hacker1@gnu.org" . "https://mail.gnu.org/EWS/Exchange.asmx"):
- (((ResponseMessages
- (GetItemResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError")
- (Items
- (CalendarItem
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]h"))
- (ParentFolderId
- (Id . "A[...]A")
- (ChangeKey . "A[...]A=="))
- (ItemClass . "IPM.Appointment")
- (Subject . "Test recurrence 1")
- (Sensitivity . "Normal")
- (Body
- (BodyType . "Text") . "Testing recurrence creation.")
- (DateTimeReceived . "2020-09-26T00:23:59Z")
- (Size . 13636)
- (Importance . "Normal")
- (IsSubmitted)
- (IsDraft)
- (IsFromMe)
- (IsResend)
- (IsUnmodified)
- (DateTimeSent . "2020-09-26T00:23:59Z")
- (DateTimeCreated . "2020-09-26T00:23:59Z")
- (ResponseObjects
- (ForwardItem)
- (CancelCalendarItem))
- (ReminderDueBy . "2020-10-02T21:00:00Z")
- (ReminderIsSet . t)
- (ReminderMinutesBeforeStart . 15)
- (DisplayCc)
- (DisplayTo . "Hacker One")
- (HasAttachments)
- (Culture . "en-US")
- (Start . "2020-09-25T21:00:00Z")
- (End . "2020-09-25T22:00:00Z")
- (IsAllDayEvent)
- (LegacyFreeBusyStatus . "Busy")
- (Location . "Online")
- (IsMeeting . t)
- (IsCancelled)
- (IsRecurring)
- (MeetingRequestWasSent)
- (IsResponseRequested . t)
- (CalendarItemType . "RecurringMaster")
- (MyResponseType . "Organizer")
- (Organizer
- (Mailbox
- (Name . "Hacker One")
- (EmailAddress . "hacker1@gnu.org")
- (RoutingType . "SMTP")))
- (RequiredAttendees
- (Attendee
- (Mailbox
- (Name . "Hacker One")
- (EmailAddress . "hacker1@gnu.org")
- (RoutingType . "SMTP")
- (MailboxType . "Mailbox"))
- (ResponseType . "Unknown")))
- (Duration . "PT1H")
- (TimeZone . "
- (UTC-05:00) Eastern Time
- (US & Canada)")
- (AppointmentSequenceNumber . 0)
- (AppointmentState . 1)
- (Recurrence
- (WeeklyRecurrence
- (Interval . 1)
- (DaysOfWeek "Friday"))
- (NumberedRecurrence
- (StartDate . "2020-09-25-04:00")
- (NumberOfOccurrences . 4)))
- (FirstOccurrence
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]h"))
- (Start . "2020-09-25T21:00:00Z")
- (End . "2020-09-25T22:00:00Z")
- (OriginalStart . "2020-09-25T21:00:00Z"))
- (LastOccurrence
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]h"))
- (Start . "2020-10-16T21:00:00Z")
- (End . "2020-10-16T22:00:00Z")
- (OriginalStart . "2020-10-16T21:00:00Z"))
- (MeetingTimeZone
- (TimeZoneName . "Eastern Standard Time")
- (BaseOffset . 0)
- (Daylight
- (TimeZoneName . "Daylight")
- (Offset . 0)
- (RelativeYearlyRecurrence
- (DaysOfWeek . "Sunday")
- (DayOfWeekIndex . "Second")
- (Month . "March"))
- (Time . "02:00:00"))
- (Standard
- (TimeZoneName . "Standard")
- (Offset . 0)
- (RelativeYearlyRecurrence
- (DaysOfWeek . "Sunday")
- (DayOfWeekIndex . "First")
- (Month . "November"))
- (Time . "02:00:00")))
- (IsOnlineMeeting)))))))
-
-Finally, this is how to delete all the occurrences in the series.
-ItemId here is the top-level recurrence item identifier which is
-returned as '(CalendarItem (ItemId ...) ...)' by the above 'GetItem'
-operation, whose 'CalendarType' element is "RecurringMaster".
-
- (exco-operate
- (car exco--connection-identifiers)
- "DeleteItem"
- '(((DeleteType . "MoveToDeletedItems")
- (SendMeetingCancellations . "SendToNone")
- (ItemIds
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]h"))))
- nil nil nil)
- (lambda (identifier response)
- (message "%S: %S" identifier response)))
- =>
- ;; Printed in *Messages*:
- ("hacker1@gnu.org" . "https://mail.gnu.org/EWS/Exchange.asmx"):
- (((ResponseMessages
- (DeleteItemResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError")))))
-
-Feel free to contribute new functions that you think others would find
-useful; file a bug with a patch against
-'https://git.savannah.gnu.org/git/emacs/elpa.git'. Functions in
-'excorporate.el' must always keep the same interface so that they stay
-backward compatible. If an existing function has an insufficient
-interface, make a new one. Excorporate functions are written to work
-with older Emacs versions, back to Emacs 24.1.
-
-
-
-Tag Table:
-Node: Top1103
-Node: Reporting Bugs2399
-Node: Installation2723
-Node: Configuration2997
-Node: Usage4017
-Node: Troubleshooting6476
-Node: API Usage9344
-
-End Tag Table
-
-
-Local Variables:
-coding: utf-8
-End:
diff --git a/packages/excorporate/excorporate.texi
b/packages/excorporate/excorporate.texi
deleted file mode 100644
index c9e943e..0000000
--- a/packages/excorporate/excorporate.texi
+++ /dev/null
@@ -1,798 +0,0 @@
-\input texinfo
-@setfilename excorporate.info
-@settitle Excorporate Manual
-
-@dircategory Emacs
-@direntry
-* Excorporate: (excorporate). Exchange Web Services integration for Emacs.
-@end direntry
-
-@copying
-Copyright @copyright{} 2016 Free Software Foundation, Inc.
-
-@quotation
-Permission is granted to copy, distribute and/or modify this document
-under the terms of the GNU Free Documentation License, Version 1.2 or
-any later version published by the Free Software Foundation; with no
-Invariant Sections, with the Front-Cover, or Back-Cover Texts. A copy of
-the license is included in the section entitled ``GNU Free Documentation
-License'' in the Emacs manual.
-
-This document is part of a collection distributed under the GNU Free
-Documentation License. If you want to distribute this document
-separately from the collection, you can do so by adding a copy of the
-license to the document, as described in section 6 of the license.
-
-All Emacs Lisp code contained in this document may be used, distributed,
-and modified without restriction.
-@end quotation
-@end copying
-
-@titlepage
-@title Excorporate Manual
-@author Thomas Fitzsimmons
-@page
-@insertcopying
-@end titlepage
-
-@contents
-
-@node Top
-@top Excorporate Manual
-
-Excorporate provides Exchange Web Services (EWS) support for Emacs.
-
-If the Exchange server you access is configured to provide EWS
-support, then there's an 86% chance that Excorporate will enable you
-to retrieve your calendar entries from the comfort of Emacs.
-
-The 14% failure rate is because authenticating against an Exchange
-server can be challenging.
-
-Accessing an Exchange server through an HTTPS proxy is possible now that
-@uref{https://debbugs.gnu.org/cgi/bugreport.cgi?bug=10} and
-@uref{https://debbugs.gnu.org/cgi/bugreport.cgi?bug=35969} are fixed.
-
-Kerberos/GSSAPI authentication needs more experimentation.
-
-Reports of success or failure of different connection types are
-welcome, as are patches to enable more of these access scenarios. See
-@pxref{Reporting Bugs}.
-
-@menu
-* Reporting Bugs:: How to report bugs in Excorporate
-* Installation:: Getting and installing @code{excorporate}.
-* Configuration:: Configuring @code{excorporate}.
-* Usage:: Using @code{excorporate}.
-* Troubleshooting:: Debugging why a connection failed
-* API Usage:: Using the API provided by @code{excorporate}.
-@end menu
-
-@node Reporting Bugs
-@chapter Reporting Bugs
-
-@noindent
-To report a bug, send an email to @code{bug-gnu-emacs@@gnu.org} using
-your favourite email program. Put ``Excorporate'' somewhere in the
-subject line, for example: ``Excorporate: Failed to authenticate''.
-
-@node Installation
-@chapter Installation
-
-Excorporate works on Emacs versions >= 24.1.
-
-@noindent
-Install @code{excorporate} from the GNU ELPA repository:
-
-@code{M-x package-install RET excorporate}
-
-@node Configuration
-@chapter Configuration
-
-@noindent
-Ideally you won't need to configure Excorporate beyond providing your
-account email address. On friendly Exchange setups, Excorporate can
-discover the EWS URL automatically.
-
-@noindent
-Run:
-
-@code{M-x excorporate}
-
-@noindent
-which will prompt you for the Exchange account configuration. Follow
-the prompts and if all goes well, you'll see a message in the minibuffer
-or in *Messages* saying that the connection is ready. Using the
-prompts, you can first try with autodiscovery. If autodiscovery runs
-out of URLs to try, re-run @code{excorporate}, saying 'n' to the
-autodiscovery attempt, at which point you will be asked for the EWS URL.
-
-@noindent
-To save a working configuration, customize
-@code{excorporate-configuration}:
-
-@code{M-x customize-variable RET excorporate-configuration}
-
-@noindent
-After saving the configuration, try @code{M-x excorporate} again.
-
-@noindent
-If neither autodiscovery nor specifying the EWS URL work,
-@pxref{Troubleshooting}.
-
-@node Usage
-@chapter Usage
-
-@noindent
-Excorporate can put entries it retrieves into the Emacs Diary, and use
-@code{appt} to remind you a few minutes before a meeting starts. To
-enable this support, do:
-
-@code{M-x excorporate-diary-enable}
-
-Excorporate's diary front-end will retrieve today's meetings.
-Subsequently @code{appt} will pop up a reminder window several minutes
-prior to each meeting.
-
-If you leave Emacs running overnight, at 12:01 AM @code{appt} (via
-Excorporate) will retrieve your meetings and display your diary so
-that you see the day's events first thing in the morning.
-
-@noindent
-Open the calendar with:
-
-@code{M-x calendar}
-
-@noindent
-move the cursor to the date you want to see meetings for, and press
-`d'. Some time later, asynchronously, a window will pop up containing
-events retrieved from the Exchange server in addition to
-locally-entered diary events. The events are all sorted by time.
-
-Excorporate also binds `e' in @code{*Calendar*} buffers to
-@code{excorporate-calendar-show-day-function} to allow a different
-view of retrieved events. By default,
-@code{excorporate-calendar-show-day-function} is set to
-@code{exco-org-show-day} which displays meetings in a temporary
-read-only Org Mode buffer named @code{*Excorporate*}.
-
-In the Org Mode @code{*Excorporate*} buffer, you can run @kbd{M-x
-exco-org-decline-meeting-request} to decline a meeting request. To
-accept, use (@code{exco-org-accept-meeting-request}) or, to tentatively
-accept, invoke (@code{exco-org-tentatively-accept-meeting-request}).
-Pass a prefix argument to these functions to omit a reply message.
-
-A meeting is a calendar event to which at least one other person is
-invited. To cancel a meeting (or an occurence of a recurring meeting)
-that you organized, use @kbd{M-x exco-org-cancel-meeting}.
-
-An appointment is a calendar item that has no invitees. To delete an
-appointment that you created, type @kbd{M-x
-exco-org-delete-appointment}. With a prefix argument, @kbd{M-x
-exco-org-delete-appointment} can be used to force-delete calendar items,
-whether they be meetings or appointments. One example where this is
-necessary is when ``cancelling'' a meeting with a single invitee, you,
-the organizer. The server will reject an attempt to cancel such a
-meeting because it refuses to send the organizer a cancellation message.
-
-If you prefer, you can install the @code{calfw} package, and set
-@code{excorporate-calendar-show-day-function} to
-@code{exco-calfw-show-day}.
-
-@node Troubleshooting
-@chapter Troubleshooting
-
-@noindent
-First, you'll want to double-check that the Exchange server you're
-trying to access provides EWS support. If it doesn't, Excorporate
-can't do anything for you. Before asking your Exchange administrator,
-check intranet wikis and so forth; other users of non-standard clients
-may have already found the EWS URL. This is called the ``EWS
-endpoint''. It can be as simple as, e.g.:
-
-@code{https://mail.gnu.org/EWS/Exchange.asmx}
-
-@noindent
-First you need to make sure you can access the endpoint.
-
-@noindent
-For Exchange Web Services (EWS) which Excorporate uses, you'll have to
-determine the EWS endpoint for your Exchange account, call it
-@code{ews-url}. It is usually something like:
-
- https://<mail host name>/EWS/Exchange.asmx
-
-@noindent
-Excorporate calculates the WSDL URL, call it @code{wsdl-url}, by
-replacing the endpoint's last path element with ``Services.wsdl'':
-
- https://<mail host name>/EWS/Services.wsdl
-
-@noindent
-Before even attempting Excorporate, you have to make these succeed:
-
-@example
-(with-current-buffer
- (url-retrieve-synchronously ews-url)
- (buffer-string))
-@end example
-
-@noindent
-When this works, you'll see web page text in *Messages*, containing a
-message about having created a service.
-
-@example
-(with-current-buffer
- (url-retrieve-synchronously wsdl-url)
- (buffer-string))
-@end example
-
-@noindent
-When this works, it will show a bunch of WSDL (XML) in *Messages*.
-
-@noindent
-Debug the above URL retrievals with @code{M-:} in an @code{emacs -Q}
-run:
-
-@example
-(progn
- (setq url-debug 1)
- (url-retrieve-synchronously URL-STRING)
- (dolist (p (seq-filter
- (lambda (b) (string-match " *http*" (buffer-name b)))
- (buffer-list)))
- (message "HTTP result buffer: \"%s\"\n%s"
- (buffer-name p)
- (with-current-buffer p (buffer-string))))
- "check *Messages*")
-@end example
-
-@noindent
-Beware that HTTP responses can be out-of-order, and that if you set
-@code{url-debug} to a number or @code{t}, Emacs may hang for a while if
-it attempts to print a very large data structure.
-
-@noindent
-Once you're sure the above steps are working, try @code{M-x
-excorporate}.
-
-@noindent
-The buffer @code{*fsm-debug*} shows @code{excorporate} state
-transitions and should provide details of where things went wrong.
-
-@noindent
-Also check @code{*Messages*} for anything obvious.
-
-@noindent
-If you suspect something wrong with accessing the EWS URL, try setting
-@code{url-debug} to t and retry @code{M-x excorporate}, then check the
-@code{*URL-DEBUG*} buffer for output.
-
-@noindent
-If you suspect NTLM authentication is failing, as a long shot, you
-might try setting @code{ntlm-compatibility-level} to 0 and retrying
-@code{M-x excorporate}.
-
-@noindent
-Excorporate's dependencies implement the tricky elements of
-asynchronous Exchange access: a state machine (@code{fsm}), TLS
-negotiation (@code{gnutls}), NTLM authentication (@code{ntlm} and
-@code{url-http-ntlm}) and SOAP communication (@code{soap-client}).
-
-@node API Usage
-@chapter API Usage
-
-@noindent
-Here are some examples of using the API (application programming
-interface) provided by Excorporate.
-
-@noindent
-Not all of Excorporate's functionality is exposed as interactive
-functions. Here is an example of creating a meeting to which
-hacker2@@gnu.org is invited, using a non-interactive function provided by
-Excorporate:
-
-@example
-@group
-(exco-calendar-item-meeting-create
- (car exco--connection-identifiers)
- "Test meeting 1"
- "Hi,\n\nThis is a test meeting 1.\n\nRegards.\n"
- (encode-time 0 15 14 23 09 2020)
- (encode-time 0 0 15 23 09 2020)
- "Online only"
- '("hacker2@@gnu.org")
- nil
- (lambda (identifier response)
- (message "%S: %S" identifier response)))
-@result{}
-;; Printed in *Messages*:
-("hacker1@@gnu.org" . "https://mail.gnu.org/EWS/Exchange.asmx"):
-(((ResponseMessages
- (CreateItemResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError")
- (Items
- (CalendarItem
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]M"))))))))
-@end group
-@end example
-
-@noindent
-The callback is run asychronously after the server responds, so as not
-to block Emacs, and the result is what is printed in the
-@code{*Messages*} buffer. This example assumes the user has already run
-@kbd{M-x excorporate} to create a connection. @code{(car
-exco--connection-identifiers)} is a hack that uses the first-established
-connection. Excorporate fully supports connecting to multiple different
-servers though (see @code{exco-connection-iterate}) so published code
-that uses the Excorporate API should not assume just one connection.
-
-@noindent
-There is lots of server-side functionality that Excorporate does not
-provide high-level non-interactive functions for. Using that
-functionality is still possible with the low-level @code{exco-operate}
-and @code{exco-operate-synchronously} functions.
-
-@noindent
-For example, evaluating this form produces lots of details about the
-meeting represented by the ItemId form, including tidbits like the list
-of invitees and how they've responded (accepted, declined, tentatively
-accepted, unknown). You can find ItemId forms to experiment with in the
-PROPERTIES drawer of calendar entries in the interactive Org buffer.
-
-@example
-@group
-(exco-operate-synchronously
- (car exco--connection-identifiers)
- "GetItem"
- '(((ItemShape
- (BaseShape . "AllProperties"))
- (ItemIds
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]d"))))
- nil nil nil nil nil nil))
-@result{}
-(((ResponseMessages
- (GetItemResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError")
- (Items
- (CalendarItem
- (ItemId (Id . "A[...]A==") (ChangeKey . "D[...]M"))
- (ParentFolderId (Id . "A[...]A") (ChangeKey . "A[...]A=="))
- (ItemClass . "IPM.Appointment")
- (Subject . "Excorporate discussion")
- (Sensitivity . "Normal")
- (Body (BodyType . "Text") . "Hi Hacker Two,
-
-Let's discuss Excorporate.
-
-Hacker One")
- (DateTimeReceived . "2020-09-24T20:07:26Z")
- (Size . 13709)
- (Importance . "Normal")
- (IsSubmitted)
- (IsDraft)
- (IsFromMe)
- (IsResend)
- (IsUnmodified)
- (DateTimeSent . "2020-09-24T20:07:26Z")
- (DateTimeCreated . "2020-09-24T20:07:26Z")
- (ResponseObjects
- (ForwardItem)
- (CancelCalendarItem))
- (ReminderDueBy . "2020-09-25T14:30:00Z")
- (ReminderIsSet . t)
- (ReminderMinutesBeforeStart . 15)
- (DisplayCc)
- (DisplayTo . "Hacker Two")
- (HasAttachments)
- (Culture . "en-US")
- (Start . "2020-09-25T14:30:00Z")
- (End . "2020-09-25T15:30:00Z")
- (IsAllDayEvent)
- (LegacyFreeBusyStatus . "Busy")
- (Location . "Online")
- (IsMeeting . t)
- (IsCancelled)
- (IsRecurring)
- (MeetingRequestWasSent . t)
- (IsResponseRequested . t)
- (CalendarItemType . "Single")
- (MyResponseType . "Organizer")
- (Organizer
- (Mailbox
- (Name . "Hacker One")
- (EmailAddress . "hacker1@@gnu.org")
- (RoutingType . "SMTP")))
- (RequiredAttendees
- (Attendee
- (Mailbox
- (Name . "Hacker Two")
- (EmailAddress . "hacker2@@gnu.org")
- (RoutingType . "SMTP")
- (MailboxType . "Mailbox"))
- (ResponseType . "Accept")
- (LastResponseTime . "2020-09-24T21:08:54Z")))
- (Duration . "PT1H")
- (TimeZone . "(UTC+00:00) Monrovia, Reykjavik")
- (AppointmentSequenceNumber . 0)
- (AppointmentState . 1)
- (IsOnlineMeeting)))))))
-@end group
-@end example
-
-@noindent
-Note that this function queries the server synchronously. In other
-words, it waits for, and evaluates to, the server's reply. This is nice
-when experimenting with the API, but published code should mostly use
-the asynchronous calls to avoid blocking Emacs during server operations.
-
-@noindent
-Here is a more complicated example that asynchronously queries the
-server for availability overlap for hacker1@@gnu.org and
-hacker2@@gnu.org, in the Eastern Time time zone.
-
-@example
-@group
-(exco-operate
- (car exco--connection-identifiers)
- "GetUserAvailability"
- '(((TimeZone
- (Bias . 300)
- (StandardTime
- (Bias . 0)
- (Time . "02:00:00")
- (DayOrder . 1)
- (Month . 11)
- (DayOfWeek . "Sunday"))
- (DaylightTime
- (Bias . -60)
- (Time . "02:00:00")
- (DayOrder . 2)
- (Month . 3)
- (DayOfWeek . "Sunday")))
- (MailboxDataArray
- (MailboxData
- (Email
- (Address . "hacker1@@gnu.org"))
- (AttendeeType . "Required")
- (ExcludeConflicts . nil))
- (MailboxData
- (Email
- (Address . "hacker2@@gnu.org"))
- (AttendeeType . "Required")
- (ExcludeConflicts . nil)))
- (FreeBusyViewOptions
- (TimeWindow
- (StartTime . "2020-09-25T00:00:00Z")
- (EndTime . "2020-09-25T23:59:00Z"))
- (MergedFreeBusyIntervalInMinutes . 60)
- (RequestedView "DetailedMerged")))
- nil nil nil)
- (lambda (identifier response)
- (message "%S: %S" identifier response)))
-@result{}
-;; Printed in *Messages*:
-("hacker1@@gnu.org" . "https://mail.gnu.org/EWS/Exchange.asmx"):
-(((FreeBusyResponseArray
- (FreeBusyResponse
- (ResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError"))
- (FreeBusyView
- (FreeBusyViewType "FreeBusyMerged")
- (MergedFreeBusy . "000000000000000000000200")
- (CalendarEventArray
- (CalendarEvent
- (StartTime . "2020-09-25T12:00:00")
- (EndTime . "2020-09-25T12:30:00")
- (BusyType . "Busy")))
- (WorkingHours
- (TimeZone
- (Bias . 480)
- (StandardTime
- (Bias . 0)
- (Time . "02:00:00")
- (DayOrder . 1)
- (Month . 11)
- (DayOfWeek . "Sunday"))
- (DaylightTime
- (Bias . -60)
- (Time . "02:00:00")
- (DayOrder . 2)
- (Month . 3)
- (DayOfWeek . "Sunday")))
- (WorkingPeriodArray
- (WorkingPeriod
- (DayOfWeek "Monday" "Tuesday" "Wednesday" "Thursday" "Friday")
- (StartTimeInMinutes . 540)
- (EndTimeInMinutes . 1080))))))
- (FreeBusyResponse
- (ResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError"))
- (FreeBusyView
- (FreeBusyViewType "DetailedMerged")
- (MergedFreeBusy . "000000000000002200000200")
- (CalendarEventArray
- (CalendarEvent
- (StartTime . "2020-09-25T05:30:00")
- (EndTime . "2020-09-25T06:30:00")
- (BusyType . "Busy")
- (CalendarEventDetails
- (ID . "0[...]0")
- (Subject . "Excorporate discussion")
- (Location . "Online")
- (IsMeeting . t)
- (IsRecurring)
- (IsException)
- (IsReminderSet . t)
- (IsPrivate)))
- (CalendarEvent
- (StartTime . "2020-09-25T12:00:00")
- (EndTime . "2020-09-25T12:30:00")
- (BusyType . "Busy")
- (CalendarEventDetails
- (ID . "0[...]0")
- (Subject . "An occurence of a recurring meeting")
- (Location)
- (IsMeeting . t)
- (IsRecurring . t)
- (IsException)
- (IsReminderSet . t)
- (IsPrivate))))
- (WorkingHours
- (TimeZone
- (Bias . 480)
- (StandardTime
- (Bias . 0)
- (Time . "02:00:00")
- (DayOrder . 1)
- (Month . 11)
- (DayOfWeek . "Sunday"))
- (DaylightTime
- (Bias . -60)
- (Time . "02:00:00")
- (DayOrder . 2)
- (Month . 3)
- (DayOfWeek . "Sunday")))
- (WorkingPeriodArray
- (WorkingPeriod
- (DayOfWeek "Monday" "Tuesday" "Wednesday" "Thursday" "Friday")
- (StartTimeInMinutes . 480)
- (EndTimeInMinutes . 1020)))))))))
-@end group
-@end example
-
-@noindent
-This example shows how to create a recurrence in the ``Eastern Standard
-Time'' time zone. The @code{exco-operation-arity-nils} call returns a
-list of nils with a length matching the number of arguments that the
-@code{CreateItem} operation takes. Arguments other than the first
-(``request'') argument may be needed in the future to use more
-complicated server functionality, but for now they can all be left
-@code{nil}.
-
-@example
-@group
-(exco-operate
- (car exco--connection-identifiers)
- "CreateItem"
- `(((SendMeetingInvitations . "SendToAllAndSaveCopy")
- (Items
- (CalendarItem
- (Subject . "Test recurrence 1")
- (Body (BodyType . "Text") "Testing recurrence creation.")
- (Start . "2020-09-25T17:00:00-04:00")
- (End . "2020-09-25T18:00:00-04:00")
- (StartTimeZone (Id . "Eastern Standard Time"))
- (EndTimeZone (Id . "Eastern Standard Time"))
- (Location . "Online")
- (RequiredAttendees
- (Attendee (Mailbox (EmailAddress . "hacker1@@gnu.org"))))
- (Recurrence
- (WeeklyRecurrence
- (Interval . 1)
- (DaysOfWeek "Friday"))
- (NumberedRecurrence
- (StartDate . "2020-09-25-04:00")
- (NumberOfOccurrences . 4))))))
- ;; Empty arguments.
- ,@@(cdr (exco-operation-arity-nils identifier "CreateItem")))
- (lambda (identifier response)
- (message "%S: %S" identifier response)))
-@result{}
-;; Printed in *Messages*:
-("hacker1@@gnu.org" . "https://mail.gnu.org/EWS/Exchange.asmx"):
-(((ResponseMessages
- (CreateItemResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError")
- (Items
- (CalendarItem
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]k"))))))))
-@end group
-@end example
-
-@noindent
-Now we can retrieve the item's properties to see the recurrence and time
-zone details:
-
-@example
-@group
-(exco-operate
- (car exco--connection-identifiers)
- "GetItem"
- '(((ItemShape
- (BaseShape . "AllProperties"))
- (ItemIds
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]d"))))
- nil nil nil nil nil nil)
- (lambda (identifier response)
- (message "%S: %S" identifier response)))
-@result{}
-;; Printed in *Messages*:
-("hacker1@@gnu.org" . "https://mail.gnu.org/EWS/Exchange.asmx"):
-(((ResponseMessages
- (GetItemResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError")
- (Items
- (CalendarItem
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]h"))
- (ParentFolderId
- (Id . "A[...]A")
- (ChangeKey . "A[...]A=="))
- (ItemClass . "IPM.Appointment")
- (Subject . "Test recurrence 1")
- (Sensitivity . "Normal")
- (Body
- (BodyType . "Text") . "Testing recurrence creation.")
- (DateTimeReceived . "2020-09-26T00:23:59Z")
- (Size . 13636)
- (Importance . "Normal")
- (IsSubmitted)
- (IsDraft)
- (IsFromMe)
- (IsResend)
- (IsUnmodified)
- (DateTimeSent . "2020-09-26T00:23:59Z")
- (DateTimeCreated . "2020-09-26T00:23:59Z")
- (ResponseObjects
- (ForwardItem)
- (CancelCalendarItem))
- (ReminderDueBy . "2020-10-02T21:00:00Z")
- (ReminderIsSet . t)
- (ReminderMinutesBeforeStart . 15)
- (DisplayCc)
- (DisplayTo . "Hacker One")
- (HasAttachments)
- (Culture . "en-US")
- (Start . "2020-09-25T21:00:00Z")
- (End . "2020-09-25T22:00:00Z")
- (IsAllDayEvent)
- (LegacyFreeBusyStatus . "Busy")
- (Location . "Online")
- (IsMeeting . t)
- (IsCancelled)
- (IsRecurring)
- (MeetingRequestWasSent)
- (IsResponseRequested . t)
- (CalendarItemType . "RecurringMaster")
- (MyResponseType . "Organizer")
- (Organizer
- (Mailbox
- (Name . "Hacker One")
- (EmailAddress . "hacker1@@gnu.org")
- (RoutingType . "SMTP")))
- (RequiredAttendees
- (Attendee
- (Mailbox
- (Name . "Hacker One")
- (EmailAddress . "hacker1@@gnu.org")
- (RoutingType . "SMTP")
- (MailboxType . "Mailbox"))
- (ResponseType . "Unknown")))
- (Duration . "PT1H")
- (TimeZone . "
-(UTC-05:00) Eastern Time
-(US & Canada)")
- (AppointmentSequenceNumber . 0)
- (AppointmentState . 1)
- (Recurrence
- (WeeklyRecurrence
- (Interval . 1)
- (DaysOfWeek "Friday"))
- (NumberedRecurrence
- (StartDate . "2020-09-25-04:00")
- (NumberOfOccurrences . 4)))
- (FirstOccurrence
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]h"))
- (Start . "2020-09-25T21:00:00Z")
- (End . "2020-09-25T22:00:00Z")
- (OriginalStart . "2020-09-25T21:00:00Z"))
- (LastOccurrence
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]h"))
- (Start . "2020-10-16T21:00:00Z")
- (End . "2020-10-16T22:00:00Z")
- (OriginalStart . "2020-10-16T21:00:00Z"))
- (MeetingTimeZone
- (TimeZoneName . "Eastern Standard Time")
- (BaseOffset . 0)
- (Daylight
- (TimeZoneName . "Daylight")
- (Offset . 0)
- (RelativeYearlyRecurrence
- (DaysOfWeek . "Sunday")
- (DayOfWeekIndex . "Second")
- (Month . "March"))
- (Time . "02:00:00"))
- (Standard
- (TimeZoneName . "Standard")
- (Offset . 0)
- (RelativeYearlyRecurrence
- (DaysOfWeek . "Sunday")
- (DayOfWeekIndex . "First")
- (Month . "November"))
- (Time . "02:00:00")))
- (IsOnlineMeeting)))))))
-@end group
-@end example
-
-
-@noindent
-Finally, this is how to delete all the occurrences in the series.
-ItemId here is the top-level recurrence item identifier which is
-returned as @code{(CalendarItem (ItemId ...) ...)} by the above
-@code{GetItem} operation, whose @code{CalendarType} element is
-``RecurringMaster''.
-
-@example
-@group
-(exco-operate
- (car exco--connection-identifiers)
- "DeleteItem"
- '(((DeleteType . "MoveToDeletedItems")
- (SendMeetingCancellations . "SendToNone")
- (ItemIds
- (ItemId
- (Id . "A[...]A==")
- (ChangeKey . "D[...]h"))))
- nil nil nil)
- (lambda (identifier response)
- (message "%S: %S" identifier response)))
-@result{}
-;; Printed in *Messages*:
-("hacker1@@gnu.org" . "https://mail.gnu.org/EWS/Exchange.asmx"):
-(((ResponseMessages
- (DeleteItemResponseMessage
- (ResponseClass . "Success")
- (ResponseCode . "NoError")))))
-@end group
-@end example
-
-@noindent
-Feel free to contribute new functions that you think others would find
-useful; file a bug with a patch against
-@code{https://git.savannah.gnu.org/git/emacs/elpa.git}. Functions in
-@code{excorporate.el} must always keep the same interface so that they
-stay backward compatible. If an existing function has an insufficient
-interface, make a new one. Excorporate functions are written to work
-with older Emacs versions, back to Emacs 24.1.
-
-@bye
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [elpa] master 536ef75: * externals-list: Convert excorporate to :external,
Stefan Monnier <=