Emacs の calendar と Google カレンダーを連携させる

はじめに

Google カレンダーを Emacs で見る方法があるというので探してみたが、そのままでは Windows 上で動かなかった。
動くようにする方法を書く。

(追記アリ)

修正箇所

google-calendar.el を以下のように書き換えた。
wget は導入すること。

52a53,56
> (defcustom google-calendar-retrieval-program "wget -q --no-check-certificate -P '%s' '%s'"
>   "Google Calendar iCal retrieving program."
>   :group 'calendar)
>
71,74c75,82
<   (shell-command-to-string (concat "mv -f " diary-file  " " diary-file ".backup" ))
<   (shell-command-to-string (concat "cd " google-calendar-directory "; "
<                                  "rm -f basic.ics; rm -f diary;"
<                                  "wget " google-calendar-url "; "))
---
>   (rename-file diary-file (concat diary-file ".backup") t)
>   (condition-case nil
>       (delete-file (concat google-calendar-directory "/basic.ics"))
>     (file-error nil))
>   (condition-case nil
>       (delete-file (concat google-calendar-directory "/diary"))
>     (file-error nil))
>   (shell-command (format google-calendar-retrieval-program (expand-file-name google-calendar-directory) google-calendar-url))
81c89
<   (shell-command-to-string (concat "cp -f " google-calendar-directory "/diary " diary-file))
---
>   (copy-file (concat google-calendar-directory "/diary") diary-file t)

追記

エラートラップとか怪しすぎたのでもう少し書きなおした。

  • 以下を追加
(defcustom google-calendar-retrieval-program "wget -q --no-check-certificate -O '%s' '%s'"
  "Google Calendar iCal retrieving program.
If you use curl, set it to \"curl --silent -o '%s' '%s'\"."
  :group 'calendar)
  • google-calendar-download を以下にする
(defun google-calendar-download ()
  "Download diary from Google and replace local diary using shell commands."
  (interactive)
  (setq bfname (buffer-name))
  (let ((ical-file (concat google-calendar-directory "/basic.ics"))
        (gcal-diary-file (concat google-calendar-directory "/diary"))
        (diary-backup-file (concat diary-file ".backup")))
    (condition-case e
        (progn
          (if (not (file-exists-p diary-file))
              (signal 'quit (format "%s does not exist." diary-file)))
          (rename-file diary-file diary-backup-file t)
          (if (file-exists-p ical-file)
              (delete-file ical-file))
          (if (file-exists-p gcal-diary-file)
              (delete-file gcal-diary-file))
          (let ((retrieve-command
                 (format google-calendar-retrieval-program
                         (expand-file-name ical-file)
                         google-calendar-url)))
            (if (/= 0 (shell-command retrieve-command))
                (signal 'error (format "Failed to retrieve ical: %s" retrieve-command)))
            )
          (icalendar-import-file ical-file gcal-diary-file)
          (switch-to-buffer (find-file-noselect (concat  google-calendar-directory "/basic.ics" )))
          (kill-buffer nil)
          (switch-to-buffer (find-file-noselect (concat  google-calendar-directory "/diary" )))
          (kill-buffer nil)
          (copy-file (concat google-calendar-directory "/diary") diary-file t)
          (message "Diary updated from Google Calendar."))
      (error
       (if (not (file-exists-p diary-file))
           (rename-file diary-backup-file diary-file))
       (message "Error: %s" (cdr e)) nil)
      (quit (message "Quit: %s" (cdr e)) nil)))
  (switch-to-buffer bfname)
  )

さらに、google-calendar-add-event のデフォルトの日付を、カレンダー上の日付にする変更を加える。

  ;; All day
  (if (y-or-n-p "All day event : ")
      (setq google-calendar-allday "Y")
    (setq google-calendar-allday "N"))
  (setq year (format "%d" (nth 2 (calendar-cursor-to-date t))))
  (setq month (format "%02d" (nth 0 (calendar-cursor-to-date t))))
  (setq day (format "%02d" (nth 1 (calendar-cursor-to-date t))))
  ;; Start DATE TIME
  (setq google-calendar-start-day (read-from-minibuffer "Start (day) [[[YYYY]MM]DD]: " (format "%s%s%s" year month day)))

これだと calendar 上で実行しないとエラーになるけど…まあいいか。
エラートラップしたかったら (calendar-cursor-to-date) で nil が返ったら云々すればいい。

キーバインド案。

(define-key calendar-mode-map "R" 'google-calendar-download)
(define-key calendar-mode-map "+" 'google-calendar-add-event)

注意

このままだと GMT で予定時刻が入力されてしまう。
ロケールに従って適切にやらせるにはもっと改造が必要なので別エントリに書く。