--- /dev/null
+;;; 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:
+
+(require 'calfw)
+(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)
+ (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)
+ (declare (special cfw:component))
+ (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)
+ (declare (special cfw:component))
+ (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