| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 | 
							- ;;; org-mac-iCal.el --- Imports events from iCal.app to the Emacs diary
 
- ;; Copyright (C) 2009-2014 Christopher Suckling
 
- ;; Author: Christopher Suckling <suckling at gmail dot com>
 
- ;; Version: 0.1057.104
 
- ;; Keywords: outlines, calendar
 
- ;; This file is not part of GNU Emacs.
 
- ;; 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, 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 GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
- ;;; Commentary:
 
- ;;
 
- ;; This file provides the import of events from Mac OS X 10.5 iCal.app
 
- ;; into the Emacs diary (it is not compatible with OS X < 10.5). The
 
- ;; function org-mac-iCal will import events in all checked iCal.app
 
- ;; calendars for the date range org-mac-iCal-range months, centered
 
- ;; around the current date.
 
- ;;
 
- ;; CAVEAT: This function is destructive; it will overwrite the current
 
- ;; contents of the Emacs diary.
 
- ;;
 
- ;; Installation: add (require 'org-mac-iCal) to your .emacs.
 
- ;;
 
- ;; If you view Emacs diary entries in org-agenda, the following hook
 
- ;; will ensure that all-day events are not orphaned below TODO items
 
- ;; and that any supplementary fields to events (e.g. Location) are
 
- ;; grouped with their parent event
 
- ;;
 
- ;; (add-hook 'org-agenda-cleanup-fancy-diary-hook
 
- ;; 	  (lambda ()
 
- ;; 	    (goto-char (point-min))
 
- ;; 	    (save-excursion
 
- ;; 	      (while (re-search-forward "^[a-z]" nil t)
 
- ;; 		(goto-char (match-beginning 0))
 
- ;; 		(insert "0:00-24:00 ")))
 
- ;; 	    (while (re-search-forward "^ [a-z]" nil t)
 
- ;; 	      (goto-char (match-beginning 0))
 
- ;; 	      (save-excursion
 
- ;; 		(re-search-backward "^[0-9]+:[0-9]+-[0-9]+:[0-9]+ " nil t))
 
- ;; 	      (insert (match-string 0)))))
 
- ;;; Code:
 
- (defcustom org-mac-iCal-range 2
 
-   "The range in months to import iCal.app entries into the Emacs
 
- diary. The import is centered around today's date; thus a value
 
- of 2 imports entries for one month before and one month after
 
- today's date"
 
-   :group 'org-time
 
-   :type 'integer)
 
- (defun org-mac-iCal ()
 
-   "Selects checked calendars in iCal.app and imports them into
 
- the the Emacs diary"
 
-   (interactive)
 
-   ;; kill diary buffers then empty diary files to avoid duplicates
 
-   (setq currentBuffer (buffer-name))
 
-   (setq openBuffers (mapcar (function buffer-name) (buffer-list)))
 
-   (omi-kill-diary-buffer openBuffers)
 
-   (with-temp-buffer
 
-     (insert-file-contents diary-file)
 
-     (delete-region (point-min) (point-max))
 
-     (write-region (point-min) (point-max) diary-file))
 
-   ;; determine available calendars
 
-   (setq caldav-folders (directory-files "~/Library/Calendars" 1 ".*caldav$"))
 
-   (setq caldav-calendars nil)
 
-   (mapc
 
-      (lambda (x)
 
-        (setq caldav-calendars (nconc caldav-calendars (directory-files x 1 ".*calendar$"))))
 
-      caldav-folders)
 
-   (setq local-calendars nil)
 
-   (setq local-calendars (directory-files "~/Library/Calendars" 1 ".*calendar$"))
 
-   (setq all-calendars (append caldav-calendars local-calendars))
 
-   ;; parse each calendar's Info.plist to see if calendar is checked in iCal
 
-   (setq all-calendars (delq 'nil (mapcar
 
- 				    (lambda (x)
 
- 				      (omi-checked x))
 
- 				    all-calendars)))
 
-   ;; for each calendar, concatenate individual events into a single ics file
 
-   (with-temp-buffer
 
-     (shell-command "sw_vers" (current-buffer))
 
-     (when (re-search-backward "10\\.[5678]" nil t)
 
-       (omi-concat-leopard-ics all-calendars)))
 
-   ;; move all caldav ics files to the same place as local ics files
 
-   (mapc
 
-    (lambda (x)
 
-      (mapc
 
-       (lambda (y)
 
-         (rename-file (concat x "/" y);
 
-                      (concat "~/Library/Calendars/" y)))
 
-       (directory-files x nil ".*ics$")))
 
-    caldav-folders)
 
-   ;; check calendar has contents and import
 
-   (setq import-calendars (directory-files "~/Library/Calendars" 1 ".*ics$"))
 
-   (mapc
 
-    (lambda (x)
 
-      (when (/= (nth 7 (file-attributes x 'string)) 0)
 
-        (omi-import-ics x)))
 
-    import-calendars)
 
-   ;; tidy up intermediate files and buffers
 
-   (setq usedCalendarsBuffers (mapcar (function buffer-name) (buffer-list)))
 
-   (omi-kill-ics-buffer usedCalendarsBuffers)
 
-   (setq usedCalendarsFiles (directory-files "~/Library/Calendars" 1 ".*ics$"))
 
-   (omi-delete-ics-file usedCalendarsFiles)
 
-   (org-pop-to-buffer-same-window currentBuffer))
 
- (defun omi-concat-leopard-ics (list)
 
-   "Leopard stores each iCal.app event in a separate ics file.
 
- Whilst useful for Spotlight indexing, this is less helpful for
 
- icalendar-import-file. omi-concat-leopard-ics concatenates these
 
- individual event files into a single ics file"
 
-   (mapc
 
-    (lambda (x)
 
-      (setq omi-leopard-events (directory-files (concat x "/Events") 1 ".*ics$"))
 
-      (with-temp-buffer
 
-        (mapc
 
- 	(lambda (y)
 
- 	  (insert-file-contents (expand-file-name y)))
 
- 	omi-leopard-events)
 
-        (write-region (point-min) (point-max) (concat (expand-file-name x) ".ics"))))
 
-    list))
 
- (defun omi-import-ics (string)
 
-   "Imports an ics file into the Emacs diary. First tidies up the
 
- ics file so that it is suitable for import and selects a sensible
 
- date range so that Emacs calendar view doesn't grind to a halt"
 
-   (with-temp-buffer
 
-     (insert-file-contents string)
 
-     (goto-char (point-min))
 
-     (while
 
- 	(re-search-forward "^BEGIN:VCALENDAR$" nil t)
 
-       (setq startEntry (match-beginning 0))
 
-       (re-search-forward "^END:VCALENDAR$" nil t)
 
-       (setq endEntry (match-end 0))
 
-       (save-restriction
 
- 	(narrow-to-region startEntry endEntry)
 
- 	(goto-char (point-min))
 
- 	(re-search-forward "\\(^DTSTART;.*:\\)\\([0-9][0-9][0-9][0-9]\\)\\([0-9][0-9]\\)" nil t)
 
- 	(if (or (eq (match-string 2) nil) (eq (match-string 3) nil))
 
- 	    (progn
 
- 	      (setq yearEntry 1)
 
- 	      (setq monthEntry 1))
 
- 	  (setq yearEntry (string-to-number (match-string 2)))
 
- 	  (setq monthEntry (string-to-number (match-string 3))))
 
- 	(setq year (string-to-number (format-time-string "%Y")))
 
- 	(setq month (string-to-number (format-time-string "%m")))
 
-         (setq now (list month 1 year))
 
-         (setq entryDate (list monthEntry 1 yearEntry))
 
-         ;; Check to see if this is a repeating event
 
-         (goto-char (point-min))
 
-         (setq isRepeating (re-search-forward "^RRULE:" nil t))
 
- 	;; Delete if outside range and not repeating
 
-         (when (and
 
-                (not isRepeating)
 
-                (> (abs (- (calendar-absolute-from-gregorian now)
 
-                           (calendar-absolute-from-gregorian entryDate)))
 
-                   (* (/ org-mac-iCal-range 2) 30))
 
- 	  (delete-region startEntry endEntry)))
 
-           (goto-char (point-max))))
 
-     (while
 
- 	(re-search-forward "^END:VEVENT$" nil t)
 
-       (delete-blank-lines))
 
-     (goto-line 1)
 
-     (insert "BEGIN:VCALENDAR\n\n")
 
-     (goto-line 2)
 
-     (while
 
- 	(re-search-forward "^BEGIN:VCALENDAR$" nil t)
 
-       (replace-match "\n"))
 
-     (goto-line 2)
 
-     (while
 
- 	(re-search-forward "^END:VCALENDAR$" nil t)
 
-       (replace-match "\n"))
 
-     (insert "END:VCALENDAR")
 
-     (goto-line 1)
 
-     (delete-blank-lines)
 
-     (while
 
- 	(re-search-forward "^END:VEVENT$" nil t)
 
-       (delete-blank-lines))
 
-     (goto-line 1)
 
-     (while
 
- 	(re-search-forward "^ORG.*" nil t)
 
-       (replace-match "\n"))
 
-     (goto-line 1)
 
-     (write-region (point-min) (point-max) string))
 
-   (icalendar-import-file string diary-file))
 
- (defun omi-kill-diary-buffer (list)
 
-   (mapc
 
-    (lambda (x)
 
-      (if (string-match "^diary" x)
 
- 	 (kill-buffer x)))
 
-    list))
 
- (defun omi-kill-ics-buffer (list)
 
-   (mapc
 
-    (lambda (x)
 
-      (if (string-match "ics$" x)
 
- 	 (kill-buffer x)))
 
-    list))
 
- (defun omi-delete-ics-file (list)
 
-   (mapc
 
-    (lambda (x)
 
-      (delete-file x))
 
-    list))
 
- (defun omi-checked (directory)
 
-   "Parse Info.plist in iCal.app calendar folder and determine
 
- whether Checked key is 1. If Checked key is not 1, remove
 
- calendar from list of calendars for import"
 
-   (let* ((root (xml-parse-file (car (directory-files directory 1 "Info.plist"))))
 
- 	 (plist (car root))
 
- 	 (dict (car (xml-get-children plist 'dict)))
 
- 	 (keys (cdr (xml-node-children dict)))
 
- 	 (keys (mapcar
 
- 		(lambda (x)
 
- 		  (cond ((listp x)
 
- 			 x)))
 
- 		keys))
 
- 	 (keys (delq 'nil keys)))
 
-     (when (equal "1" (car (cddr (lax-plist-get keys '(key nil "Checked")))))
 
-       directory)))
 
- (provide 'org-mac-iCal)
 
- ;;; org-mac-iCal.el ends here
 
 
  |