From 0df06a3ac574ddd17cdf82c0f1f236711c768305 Mon Sep 17 00:00:00 2001 From: Ulf Jasper Date: Sat, 15 Nov 2014 13:49:28 +0100 Subject: [PATCH 1/4] intermediate commit --- lisp/calendar/icalendar.el | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el index 9dba6ff2dcf..cdda8f0fba2 100644 --- a/lisp/calendar/icalendar.el +++ b/lisp/calendar/icalendar.el @@ -267,6 +267,34 @@ other sexp entries are enumerated in any case." :type 'boolean :group 'icalendar) +(defcustom icalendar-export-alarms + nil + "Determine if and how alarms are included in exported diary events. +FIXME +... appt-display-format +... appt-audible +.... appt-message-warning-time +... appt-warning-time-regexp +" + :version "25.1" + :type '(choice (const :tag "Do not include alarms in export" nil) + (const :tag "Apply emacs defaults FIXME" 'default) + (list :tag "Create alarms in exported diary entries" + (integer :tag "Advance time (minutes)" + ;; FIXME + :value appt-message-warning-time) + (choice :tag "Alarm type" + (list :tag "Audio" + (string :tag "Audio file")) + (cons :tag "Display" + (string :tag "Description")) + (list :tag "Email" + (string :tag "Description") + (string :tag "Summary") + (string :tag "Attendees"))))) + :group 'icalendar) + + (defvar icalendar-debug nil "Enable icalendar debug messages.") @@ -281,6 +309,7 @@ other sexp entries are enumerated in any case." ;; ====================================================================== (require 'calendar) (require 'diary-lib) +(require 'appt) ;; ====================================================================== ;; misc @@ -1053,7 +1082,7 @@ FExport diary data into iCalendar file: ") (condition-case error-val (progn (setq cns-cons-or-list - (icalendar--convert-to-ical nonmarker entry-main)) + (icalendar--convert-to-ical nonmarker entry-main)) (setq other-elements (icalendar--parse-summary-and-rest entry-full)) (mapc (lambda (contents-n-summary) From 6f20cde0117a181159eed4a1992ed8c536d8ecce Mon Sep 17 00:00:00 2001 From: Ulf Jasper Date: Sat, 15 Nov 2014 20:54:28 +0100 Subject: [PATCH 2/4] alarm export, first step --- lisp/calendar/icalendar.el | 68 +++++++++++++++++++++---------- test/automated/icalendar-tests.el | 15 ++++++- 2 files changed, 60 insertions(+), 23 deletions(-) diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el index cdda8f0fba2..e00976da349 100644 --- a/lisp/calendar/icalendar.el +++ b/lisp/calendar/icalendar.el @@ -270,28 +270,22 @@ other sexp entries are enumerated in any case." (defcustom icalendar-export-alarms nil "Determine if and how alarms are included in exported diary events. -FIXME -... appt-display-format -... appt-audible -.... appt-message-warning-time -... appt-warning-time-regexp -" +FIXME" :version "25.1" - :type '(choice (const :tag "Do not include alarms in export" nil) - (const :tag "Apply emacs defaults FIXME" 'default) + :type '(choice (const :tag "Do not include alarms in export" + nil) (list :tag "Create alarms in exported diary entries" (integer :tag "Advance time (minutes)" - ;; FIXME - :value appt-message-warning-time) - (choice :tag "Alarm type" - (list :tag "Audio" - (string :tag "Audio file")) - (cons :tag "Display" - (string :tag "Description")) - (list :tag "Email" - (string :tag "Description") - (string :tag "Summary") - (string :tag "Attendees"))))) + :value 10) + (set :tag "Alarm type" + (list :tag "Audio" + (const audio :tag "Audio")) + (list :tag "Display" + (const display :tag "Display")) + (list :tag "Email" + (const email) + (repeat :tag "Attendees" + (string :tag "Email")))))) :group 'icalendar) @@ -1055,6 +1049,7 @@ FExport diary data into iCalendar file: ") (header "") (contents-n-summary) (contents) + (alarm) (found-error nil) (nonmarker (concat "^" (regexp-quote diary-nonmarking-symbol) "?")) @@ -1117,8 +1112,10 @@ FExport diary data into iCalendar file: ") (setq header (concat "\nBEGIN:VEVENT\nUID:" (or uid (icalendar--create-uid - entry-full contents))))) - (setq result (concat result header contents + entry-full contents)))) + (setq alarm (icalendar--create-ical-alarm + (car contents-n-summary)))) + (setq result (concat result header contents alarm "\nEND:VEVENT"))) (if (consp cns-cons-or-list) (list cns-cons-or-list) @@ -1293,6 +1290,35 @@ Returns an alist." (if url (cons 'url url) nil) (if uid (cons 'uid uid) nil)))))))) +(defun icalendar--create-ical-alarm (summary) + (when icalendar-export-alarms + (let* ((advance-time (car icalendar-export-alarms)) + (alarm-specs (cadr icalendar-export-alarms)) + (fun (lambda (spec) + (icalendar--do-create-ical-alarm advance-time spec summary)))) + (mapconcat fun alarm-specs "\n")))) + +(defun icalendar--do-create-ical-alarm (advance-time alarm-spec summary) + (let* ((action (car alarm-spec)) + (act (format "ACTION:%s\n" + (cdr (assoc action '((audio . "AUDIO") + (display . "DISPLAY") + (email . "EMAIL")))))) + (tri (format "TRIGGER:-PT%dM\n" advance-time)) + (des (if (memq action '(display email)) + (format "DESCRIPTION:%s\n" summary) + "")) + (sum (if (eq action 'email) + (format "SUMMARY:%s\n" summary) + "")) + (att (if (eq action 'email) + (mapconcat (lambda (i) + (format "ATTENDEE:MAILTO:%s\n" i)) + (cadr alarm-spec) "") + ""))) + + (concat "BEGIN:VALARM\n" act tri des sum att "END:VALARM"))) + ;; subroutines for icalendar-export-region (defun icalendar--convert-ordinary-to-ical (nonmarker entry-main) "Convert \"ordinary\" diary entry to iCalendar format. diff --git a/test/automated/icalendar-tests.el b/test/automated/icalendar-tests.el index 23afb14792d..3e2fecff1cd 100644 --- a/test/automated/icalendar-tests.el +++ b/test/automated/icalendar-tests.el @@ -503,6 +503,15 @@ END:VEVENT ;; restore time-zone even if something went terribly wrong (setenv "TZ" tz))) ) +(ert-deftest icalendar--create-ical-alarm () + "Test `icalendar--create-ical-alarms'." + (let ((icalendar-export-alarms)) + ;; testcase: no alarms + (setq icalendar-export-alarm nil) + (should (equal nil + (icalendar--create-ical-alarm "sumsum"))))) + + ;; ====================================================================== ;; Export tests ;; ====================================================================== @@ -519,7 +528,8 @@ European style input data must use german month names. American and ISO style input data must use english month names." (let ((tz (getenv "TZ")) (calendar-date-style 'iso) - (icalendar-recurring-start-year 2000)) + (icalendar-recurring-start-year 2000) + (icalendar-export-alarms nil)) (unwind-protect (progn ;;; (message "Current time zone: %s" (current-time-zone)) @@ -1286,7 +1296,8 @@ Argument INPUT icalendar event string." (icalendar-import-format-status "\n Status: %s") (icalendar-import-format-url "\n URL: %s") (icalendar-import-format-class "\n Class: %s") - (icalendar-import-format-class "\n UID: %s")) + (icalendar-import-format-class "\n UID: %s") + (icalendar-export-alarms nil)) (dolist (calendar-date-style '(iso european american)) (icalendar-tests--do-test-cycle))))) From b7cce56d7d8aa213259b4582c39970e331b16fc6 Mon Sep 17 00:00:00 2001 From: Ulf Jasper Date: Mon, 17 Nov 2014 16:44:52 +0100 Subject: [PATCH 3/4] intermediate commit --- lisp/calendar/icalendar.el | 1 + 1 file changed, 1 insertion(+) diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el index e00976da349..dddcc640736 100644 --- a/lisp/calendar/icalendar.el +++ b/lisp/calendar/icalendar.el @@ -267,6 +267,7 @@ other sexp entries are enumerated in any case." :type 'boolean :group 'icalendar) + (defcustom icalendar-export-alarms nil "Determine if and how alarms are included in exported diary events. From 16b5f507688b32b78843620417bb2176b3131752 Mon Sep 17 00:00:00 2001 From: Ulf Jasper Date: Mon, 17 Nov 2014 20:51:26 +0100 Subject: [PATCH 4/4] New option `icalendar-export-alarms'. --- lisp/ChangeLog | 9 +++ lisp/calendar/icalendar.el | 28 ++++---- test/ChangeLog | 8 +++ test/automated/icalendar-tests.el | 105 ++++++++++++++++++++++++++---- 4 files changed, 128 insertions(+), 22 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 9d22d7609e2..2bca643199f 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,12 @@ +2014-11-17 Ulf Jasper + + * calendar/icalendar.el (icalendar-export-alarms): New + customizable variable. + (icalendar-export-region): Export alarms as specified in + `icalendar-export-alarms'. + (icalendar--create-ical-alarm, icalendar--do-create-ical-alarm): + New functions for exporting alarms. + 2014-11-16 Ulf Jasper * calendar/icalendar.el (icalendar--convert-tz-offset): Return diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el index dddcc640736..af9b2a48324 100644 --- a/lisp/calendar/icalendar.el +++ b/lisp/calendar/icalendar.el @@ -270,8 +270,7 @@ other sexp entries are enumerated in any case." (defcustom icalendar-export-alarms nil - "Determine if and how alarms are included in exported diary events. -FIXME" + "Determine if and how alarms are included in exported diary events." :version "25.1" :type '(choice (const :tag "Do not include alarms in export" nil) @@ -304,7 +303,6 @@ FIXME" ;; ====================================================================== (require 'calendar) (require 'diary-lib) -(require 'appt) ;; ====================================================================== ;; misc @@ -1115,7 +1113,7 @@ FExport diary data into iCalendar file: ") (icalendar--create-uid entry-full contents)))) (setq alarm (icalendar--create-ical-alarm - (car contents-n-summary)))) + (cdr contents-n-summary)))) (setq result (concat result header contents alarm "\nEND:VEVENT"))) (if (consp cns-cons-or-list) @@ -1292,33 +1290,41 @@ Returns an alist." (if uid (cons 'uid uid) nil)))))))) (defun icalendar--create-ical-alarm (summary) + "Return VALARM blocks for the given SUMMARY." (when icalendar-export-alarms (let* ((advance-time (car icalendar-export-alarms)) (alarm-specs (cadr icalendar-export-alarms)) (fun (lambda (spec) (icalendar--do-create-ical-alarm advance-time spec summary)))) - (mapconcat fun alarm-specs "\n")))) + (mapconcat fun alarm-specs "")))) (defun icalendar--do-create-ical-alarm (advance-time alarm-spec summary) + "Return a VALARM block. +Argument ADVANCE-TIME is a number giving the time when the alarm +fires (minutes before the respective event). Argument ALARM-SPEC +is a list which must be one of '(audio), '(display) or +'(email (ADDRESS1 ...)), see `icalendar-export-alarms'. Argument +SUMMARY is a string which contains a short description for the +alarm." (let* ((action (car alarm-spec)) - (act (format "ACTION:%s\n" + (act (format "\nACTION:%s" (cdr (assoc action '((audio . "AUDIO") (display . "DISPLAY") (email . "EMAIL")))))) - (tri (format "TRIGGER:-PT%dM\n" advance-time)) + (tri (format "\nTRIGGER:-PT%dM" advance-time)) (des (if (memq action '(display email)) - (format "DESCRIPTION:%s\n" summary) + (format "\nDESCRIPTION:%s" summary) "")) (sum (if (eq action 'email) - (format "SUMMARY:%s\n" summary) + (format "\nSUMMARY:%s" summary) "")) (att (if (eq action 'email) (mapconcat (lambda (i) - (format "ATTENDEE:MAILTO:%s\n" i)) + (format "\nATTENDEE:MAILTO:%s" i)) (cadr alarm-spec) "") ""))) - (concat "BEGIN:VALARM\n" act tri des sum att "END:VALARM"))) + (concat "\nBEGIN:VALARM" act tri des sum att "\nEND:VALARM"))) ;; subroutines for icalendar-export-region (defun icalendar--convert-ordinary-to-ical (nonmarker entry-main) diff --git a/test/ChangeLog b/test/ChangeLog index 4a6f0059344..5290ef30b42 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,11 @@ +2014-11-17 Ulf Jasper + + * automated/icalendar-tests.el (icalendar-tests--test-export): New + optional parameter `alarms'. + (icalendar-export-alarms): New test for exporting icalendar + alarms. + (icalendar-tests--test-cycle): Let `icalendar-export-alarms' be nil. + 2014-11-16 Ulf Jasper * automated/icalendar-tests.el (icalendar--parse-vtimezone): Add diff --git a/test/automated/icalendar-tests.el b/test/automated/icalendar-tests.el index 3e2fecff1cd..ddff15544b3 100644 --- a/test/automated/icalendar-tests.el +++ b/test/automated/icalendar-tests.el @@ -503,33 +503,25 @@ END:VEVENT ;; restore time-zone even if something went terribly wrong (setenv "TZ" tz))) ) -(ert-deftest icalendar--create-ical-alarm () - "Test `icalendar--create-ical-alarms'." - (let ((icalendar-export-alarms)) - ;; testcase: no alarms - (setq icalendar-export-alarm nil) - (should (equal nil - (icalendar--create-ical-alarm "sumsum"))))) - - ;; ====================================================================== ;; Export tests ;; ====================================================================== (defun icalendar-tests--test-export (input-iso input-european input-american - expected-output) + expected-output &optional alarms) "Perform an export test. Argument INPUT-ISO iso style diary string. Argument INPUT-EUROPEAN european style diary string. Argument INPUT-AMERICAN american style diary string. Argument EXPECTED-OUTPUT expected iCalendar result string. +Optional argument ALARMS the value of `icalendar-export-alarms' for this test. European style input data must use german month names. American and ISO style input data must use english month names." (let ((tz (getenv "TZ")) (calendar-date-style 'iso) (icalendar-recurring-start-year 2000) - (icalendar-export-alarms nil)) + (icalendar-export-alarms alarms)) (unwind-protect (progn ;;; (message "Current time zone: %s" (current-time-zone)) @@ -763,6 +755,97 @@ RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20010706 SUMMARY:block no end time ")) +(ert-deftest icalendar-export-alarms () + "Perform export test with different settings for exporting alarms." + ;; no alarm + (icalendar-tests--test-export + "2014 Nov 17 19:30 no alarm" + "17 Nov 2014 19:30 no alarm" + "Nov 17 2014 19:30 no alarm" + "DTSTART;VALUE=DATE-TIME:20141117T193000 +DTEND;VALUE=DATE-TIME:20141117T203000 +SUMMARY:no alarm +" + nil) + + ;; 10 minutes in advance, audio + (icalendar-tests--test-export + "2014 Nov 17 19:30 audio alarm" + "17 Nov 2014 19:30 audio alarm" + "Nov 17 2014 19:30 audio alarm" + "DTSTART;VALUE=DATE-TIME:20141117T193000 +DTEND;VALUE=DATE-TIME:20141117T203000 +SUMMARY:audio alarm +BEGIN:VALARM +ACTION:AUDIO +TRIGGER:-PT10M +END:VALARM +" + '(10 ((audio)))) + + ;; 20 minutes in advance, display + (icalendar-tests--test-export + "2014 Nov 17 19:30 display alarm" + "17 Nov 2014 19:30 display alarm" + "Nov 17 2014 19:30 display alarm" + "DTSTART;VALUE=DATE-TIME:20141117T193000 +DTEND;VALUE=DATE-TIME:20141117T203000 +SUMMARY:display alarm +BEGIN:VALARM +ACTION:DISPLAY +TRIGGER:-PT20M +DESCRIPTION:display alarm +END:VALARM +" + '(20 ((display)))) + + ;; 66 minutes in advance, email + (icalendar-tests--test-export + "2014 Nov 17 19:30 email alarm" + "17 Nov 2014 19:30 email alarm" + "Nov 17 2014 19:30 email alarm" + "DTSTART;VALUE=DATE-TIME:20141117T193000 +DTEND;VALUE=DATE-TIME:20141117T203000 +SUMMARY:email alarm +BEGIN:VALARM +ACTION:EMAIL +TRIGGER:-PT66M +DESCRIPTION:email alarm +SUMMARY:email alarm +ATTENDEE:MAILTO:att.one@email.com +ATTENDEE:MAILTO:att.two@email.com +END:VALARM +" + '(66 ((email ("att.one@email.com" "att.two@email.com"))))) + + ;; 2 minutes in advance, all alarms + (icalendar-tests--test-export + "2014 Nov 17 19:30 all alarms" + "17 Nov 2014 19:30 all alarms" + "Nov 17 2014 19:30 all alarms" + "DTSTART;VALUE=DATE-TIME:20141117T193000 +DTEND;VALUE=DATE-TIME:20141117T203000 +SUMMARY:all alarms +BEGIN:VALARM +ACTION:EMAIL +TRIGGER:-PT2M +DESCRIPTION:all alarms +SUMMARY:all alarms +ATTENDEE:MAILTO:att.one@email.com +ATTENDEE:MAILTO:att.two@email.com +END:VALARM +BEGIN:VALARM +ACTION:AUDIO +TRIGGER:-PT2M +END:VALARM +BEGIN:VALARM +ACTION:DISPLAY +TRIGGER:-PT2M +DESCRIPTION:all alarms +END:VALARM +" + '(2 ((email ("att.one@email.com" "att.two@email.com")) (audio) (display))))) + ;; ====================================================================== ;; Import tests ;; ======================================================================