Mercurial > emacs
changeset 66374:88fc54347c68
From Ulf Jasper <ulf.jasper@web.de>:
(icalendar-version): Increase to 0.13. Now a string.
(icalendar-import-format): Handle CLASS, STATUS, URL. Rename
`subject' to `summary'.
(icalendar-import-format-summary): Rename from
`icalendar-import-format-subject'.
(icalendar-import-format-url, icalendar-import-format-status)
(icalendar-import-format-class): New variables.
(icalendar--rris): Take variable argument list.
(icalendar--datestring-to-isodate): Remove unnecessary
calendar-style check when converting dates with explicit month
names.
(icalendar-export-region): Change return type of conversion
subroutines. Bury current buffer unless error occurred.
(icalendar--convert-to-ical)
(icalendar--parse-summary-and-rest): New functions.
(icalendar--convert-ordinary-to-ical)
(icalendar--convert-weekly-to-ical)
(icalendar--convert-yearly-to-ical)
(icalendar--convert-block-to-ical)
(icalendar--convert-cyclic-to-ical)
(icalendar--convert-anniversary-to-ical): Change return type.
Strip trailing blanks from subject.
(icalendar--convert-sexp-to-ical): Change return type.
Strip trailing blanks from subject. Handle simple sexp
entries as generated by icalendar.el.
(icalendar--convert-float-to-ical)
(icalendar--convert-date-to-ical): Strip trailing blanks from
subject.
(icalendar-import-file): Doc fix.
(icalendar--format-ical-event): Handle CLASS, STATUS, URL.
Correct call to icalendar--rris.
(icalendar--convert-ical-to-diary): Doc fix. Rename `subject' to
`summary'.
(icalendar--add-diary-entry): Rename `subject' to `summary'.
author | Glenn Morris <rgm@gnu.org> |
---|---|
date | Mon, 24 Oct 2005 07:27:39 +0000 |
parents | a0e9e787944e |
children | 6680788d2e7f |
files | lisp/calendar/icalendar.el |
diffstat | 1 files changed, 349 insertions(+), 201 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/calendar/icalendar.el Mon Oct 24 07:26:18 2005 +0000 +++ b/lisp/calendar/icalendar.el Mon Oct 24 07:27:39 2005 +0000 @@ -97,7 +97,7 @@ ;;; Code: -(defconst icalendar-version 0.12 +(defconst icalendar-version "0.13" "Version number of icalendar.el.") ;; ====================================================================== @@ -113,18 +113,21 @@ "Format string for importing events from iCalendar into Emacs diary. This string defines how iCalendar events are inserted into diary file. Meaning of the specifiers: +%c Class, see `icalendar-import-format-class' %d Description, see `icalendar-import-format-description' %l Location, see `icalendar-import-format-location' %o Organizer, see `icalendar-import-format-organizer' -%s Subject, see `icalendar-import-format-subject'" +%s Summary, see `icalendar-import-format-summary' +%t Status, see `icalendar-import-format-status' +%u URL, see `icalendar-import-format-url'" :type 'string :group 'icalendar) -(defcustom icalendar-import-format-subject +(defcustom icalendar-import-format-summary "%s" - "Format string defining how the subject element is formatted. -This applies only if the subject is not empty! `%s' is replaced -by the subject." + "Format string defining how the summary element is formatted. +This applies only if the summary is not empty! `%s' is replaced +by the summary." :type 'string :group 'icalendar) @@ -152,6 +155,30 @@ :type 'string :group 'icalendar) +(defcustom icalendar-import-format-url + "\n URL: %s" + "Format string defining how the URL element is formatted. +This applies only if the URL is not empty! `%s' is replaced by +the URL." + :type 'string + :group 'icalendar) + +(defcustom icalendar-import-format-status + "\n Status: %s" + "Format string defining how the status element is formatted. +This applies only if the status is not empty! `%s' is replaced by +the status." + :type 'string + :group 'icalendar) + +(defcustom icalendar-import-format-class + "\n Class: %s" + "Format string defining how the class element is formatted. +This applies only if the class is not empty! `%s' is replaced by +the class." + :type 'string + :group 'icalendar) + (defvar icalendar-debug nil "Enable icalendar debug messages.") @@ -195,15 +222,16 @@ (replace-match "" nil nil))) unfolded-buffer)) -(defsubst icalendar--rris (re rp st) - "Replace regexp RE with RP in string ST and return the new string. -This is here for compatibility with XEmacs." +(defsubst icalendar--rris (&rest args) + "Replace regular expression in string. +Pass ARGS to `replace-regexp-in-string' (Emacs) or to +`replace-in-string' (XEmacs)." ;; XEmacs: (if (fboundp 'replace-in-string) (save-match-data ;; apparently XEmacs needs save-match-data - (replace-in-string st re rp)) + (apply 'replace-in-string args)) ;; Emacs: - (replace-regexp-in-string re rp st))) + (apply 'replace-regexp-in-string args))) (defun icalendar--read-element (invalue inparams) "Recursively read the next iCalendar element in the current buffer. @@ -609,12 +637,11 @@ (setq month day) (setq day x)))) ( ;; date contains month names -- european-style - (and european-calendar-style - (string-match (concat "\\s-*" - "0?\\([123]?[0-9]\\)[ \t/]\\s-*" - "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" - "\\([0-9]\\{4\\}\\)") - datestring)) + (string-match (concat "\\s-*" + "0?\\([123]?[0-9]\\)[ \t/]\\s-*" + "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" + "\\([0-9]\\{4\\}\\)") + datestring) (setq day (read (substring datestring (match-beginning 1) (match-end 1)))) (setq month (icalendar--get-month-number @@ -623,12 +650,11 @@ (setq year (read (substring datestring (match-beginning 3) (match-end 3))))) ( ;; date contains month names -- non-european-style - (and (not european-calendar-style) - (string-match (concat "\\s-*" - "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" - "0?\\([123]?[0-9]\\),?[ \t/]\\s-*" - "\\([0-9]\\{4\\}\\)") - datestring)) + (string-match (concat "\\s-*" + "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" + "0?\\([123]?[0-9]\\),?[ \t/]\\s-*" + "\\([0-9]\\{4\\}\\)") + datestring) (setq day (read (substring datestring (match-beginning 2) (match-end 2)))) (setq month (icalendar--get-month-number @@ -704,10 +730,12 @@ (entry-main "") (entry-rest "") (header "") + (contents-n-summary) (contents) (found-error nil) (nonmarker (concat "^" (regexp-quote diary-nonmarking-symbol) - "?"))) + "?")) + (other-elements nil)) ;; prepare buffer with error messages (save-current-buffer (set-buffer (get-buffer-create "*icalendar-errors*")) @@ -728,36 +756,33 @@ (car (cddr (current-time))))) (condition-case error-val (progn - (setq contents - (or - ;; anniversaries -- %%(diary-anniversary ...) - (icalendar--convert-anniversary-to-ical nonmarker - entry-main) - ;; cyclic events -- %%(diary-cyclic ...) - (icalendar--convert-cyclic-to-ical nonmarker entry-main) - ;; diary-date -- %%(diary-date ...) - (icalendar--convert-date-to-ical nonmarker entry-main) - ;; float events -- %%(diary-float ...) - (icalendar--convert-float-to-ical nonmarker entry-main) - ;; block events -- %%(diary-block ...) - (icalendar--convert-block-to-ical nonmarker entry-main) - ;; other sexp diary entries - (icalendar--convert-sexp-to-ical nonmarker entry-main) - ;; weekly by day -- Monday 8:30 Team meeting - (icalendar--convert-weekly-to-ical nonmarker entry-main) - ;; yearly by day -- 1 May Tag der Arbeit - (icalendar--convert-yearly-to-ical nonmarker entry-main) - ;; "ordinary" events, start and end time given - ;; 1 Feb 2003 blah - (icalendar--convert-ordinary-to-ical nonmarker entry-main) - ;; everything else - ;; Oops! what's that? - (error "Could not parse entry"))) - (unless (string= entry-rest "") - (setq contents - (concat contents "\nDESCRIPTION:" - (icalendar--convert-string-for-export - entry-rest)))) + (setq contents-n-summary + (icalendar--convert-to-ical nonmarker entry-main)) + (setq other-elements (icalendar--parse-summary-and-rest + (concat entry-main entry-rest))) + (setq contents (concat (car contents-n-summary) + "\nSUMMARY:" (cadr contents-n-summary))) + (let ((cla (cdr (assoc 'cla other-elements))) + (des (cdr (assoc 'des other-elements))) + (loc (cdr (assoc 'loc other-elements))) + (org (cdr (assoc 'org other-elements))) + (sta (cdr (assoc 'sta other-elements))) + (sum (cdr (assoc 'sum other-elements))) + (url (cdr (assoc 'url other-elements)))) + (if cla + (setq contents (concat contents "\nCLASS:" cla))) + (if des + (setq contents (concat contents "\nDESCRIPTION:" des))) + (if loc + (setq contents (concat contents "\nLOCATION:" loc))) + (if org + (setq contents (concat contents "\nORGANIZER:" org))) + (if sta + (setq contents (concat contents "\nSTATUS:" sta))) + ;;(if sum + ;; (setq contents (concat contents "\nSUMMARY:" sum))) + (if url + (setq contents (concat contents "\nURL:" url)))) (setq result (concat result header contents "\nEND:VEVENT"))) ;; handle errors (error @@ -780,13 +805,127 @@ (insert result) (insert "\nEND:VCALENDAR\n") ;; save the diary file - (save-buffer)))) + (save-buffer) + (unless found-error + (bury-buffer))))) found-error)) -;; subroutines +(defun icalendar--convert-to-ical (nonmarker entry-main) + "Convert a diary entry to icalendar format. +NONMARKER is a regular expression matching the start of non-marking +entries. ENTRY-MAIN is the first line of the diary entry." + (or + ;; anniversaries -- %%(diary-anniversary ...) + (icalendar--convert-anniversary-to-ical nonmarker entry-main) + ;; cyclic events -- %%(diary-cyclic ...) + (icalendar--convert-cyclic-to-ical nonmarker entry-main) + ;; diary-date -- %%(diary-date ...) + (icalendar--convert-date-to-ical nonmarker entry-main) + ;; float events -- %%(diary-float ...) + (icalendar--convert-float-to-ical nonmarker entry-main) + ;; block events -- %%(diary-block ...) + (icalendar--convert-block-to-ical nonmarker entry-main) + ;; other sexp diary entries + (icalendar--convert-sexp-to-ical nonmarker entry-main) + ;; weekly by day -- Monday 8:30 Team meeting + (icalendar--convert-weekly-to-ical nonmarker entry-main) + ;; yearly by day -- 1 May Tag der Arbeit + (icalendar--convert-yearly-to-ical nonmarker entry-main) + ;; "ordinary" events, start and end time given + ;; 1 Feb 2003 blah + (icalendar--convert-ordinary-to-ical nonmarker entry-main) + ;; everything else + ;; Oops! what's that? + (error "Could not parse entry"))) + +(defun icalendar--parse-summary-and-rest (summary-and-rest) + "Parse SUMMARY-AND-REST from a diary to fill iCalendar properties." + (save-match-data + (let* ((s icalendar-import-format) + (p-cla (or (string-match "%c" icalendar-import-format) -1)) + (p-des (or (string-match "%d" icalendar-import-format) -1)) + (p-loc (or (string-match "%l" icalendar-import-format) -1)) + (p-org (or (string-match "%o" icalendar-import-format) -1)) + (p-sum (or (string-match "%s" icalendar-import-format) -1)) + (p-sta (or (string-match "%t" icalendar-import-format) -1)) + (p-url (or (string-match "%u" icalendar-import-format) -1)) + (p-list (sort (list p-cla p-des p-loc p-org p-sta p-sum p-url) '<)) + pos-cla pos-des pos-loc pos-org pos-sta pos-sum pos-url) + (dotimes (i (length p-list)) + (cond ((and (>= p-cla 0) (= (nth i p-list) p-cla)) + (setq pos-cla (+ 2 (* 2 i)))) + ((and (>= p-des 0) (= (nth i p-list) p-des)) + (setq pos-des (+ 2 (* 2 i)))) + ((and (>= p-loc 0) (= (nth i p-list) p-loc)) + (setq pos-loc (+ 2 (* 2 i)))) + ((and (>= p-org 0) (= (nth i p-list) p-org)) + (setq pos-org (+ 2 (* 2 i)))) + ((and (>= p-sta 0) (= (nth i p-list) p-sta)) + (setq pos-sta (+ 2 (* 2 i)))) + ((and (>= p-sum 0) (= (nth i p-list) p-sum)) + (setq pos-sum (+ 2 (* 2 i)))) + ((and (>= p-url 0) (= (nth i p-list) p-url)) + (setq pos-url (+ 2 (* 2 i)))))) + (mapc (lambda (ij) + (setq s (icalendar--rris (car ij) (cadr ij) s t t))) + (list + ;; summary must be first! because of %s + (list "%s" + (concat "\\(" icalendar-import-format-summary "\\)?")) + (list "%c" + (concat "\\(" icalendar-import-format-class "\\)?")) + (list "%d" + (concat "\\(" icalendar-import-format-description "\\)?")) + (list "%l" + (concat "\\(" icalendar-import-format-location "\\)?")) + (list "%o" + (concat "\\(" icalendar-import-format-organizer "\\)?")) + (list "%t" + (concat "\\(" icalendar-import-format-status "\\)?")) + (list "%u" + (concat "\\(" icalendar-import-format-url "\\)?")))) + (setq s (concat (icalendar--rris "%s" "\\(.*\\)" s nil t) " ")) + (if (string-match s summary-and-rest) + (let (cla des loc org sta sum url) + (if (and pos-sum (match-beginning pos-sum)) + (setq sum (substring summary-and-rest + (match-beginning pos-sum) + (match-end pos-sum)))) + (if (and pos-cla (match-beginning pos-cla)) + (setq cla (substring summary-and-rest + (match-beginning pos-cla) + (match-end pos-cla)))) + (if (and pos-des (match-beginning pos-des)) + (setq des (substring summary-and-rest + (match-beginning pos-des) + (match-end pos-des)))) + (if (and pos-loc (match-beginning pos-loc)) + (setq loc (substring summary-and-rest + (match-beginning pos-loc) + (match-end pos-loc)))) + (if (and pos-org (match-beginning pos-org)) + (setq org (substring summary-and-rest + (match-beginning pos-org) + (match-end pos-org)))) + (if (and pos-sta (match-beginning pos-sta)) + (setq sta (substring summary-and-rest + (match-beginning pos-sta) + (match-end pos-sta)))) + (if (and pos-url (match-beginning pos-url)) + (setq url (substring summary-and-rest + (match-beginning pos-url) + (match-end pos-url)))) + (list (if cla (cons 'cla cla) nil) + (if des (cons 'des des) nil) + (if loc (cons 'loc loc) nil) + (if org (cons 'org org) nil) + (if sta (cons 'sta sta) nil) + ;;(if sum (cons 'sum sum) nil) + (if url (cons 'url url) nil))))))) + +;; subroutines for icalendar-export-region (defun icalendar--convert-ordinary-to-ical (nonmarker entry-main) "Convert \"ordinary\" diary entry to icalendar format. - NONMARKER is a regular expression matching the start of non-marking entries. ENTRY-MAIN is the first line of the diary entry." (if (string-match (concat nonmarker @@ -795,7 +934,7 @@ "\\(" "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" "\\)?" - "\\s-*\\(.*\\)") + "\\s-*\\(.*?\\) ?$") entry-main) (let* ((datetime (substring entry-main (match-beginning 1) (match-end 1))) @@ -839,26 +978,24 @@ starttimestring)))) (setq endtimestring (format "T%06d" (+ 10000 time)))))) - (concat "\nDTSTART;" - (if starttimestring "VALUE=DATE-TIME:" - "VALUE=DATE:") - startisostring - (or starttimestring "") - "\nDTEND;" - (if endtimestring "VALUE=DATE-TIME:" - "VALUE=DATE:") - (if starttimestring - startisostring - endisostring) - (or endtimestring "") - "\nSUMMARY:" - summary)) + (list (concat "\nDTSTART;" + (if starttimestring "VALUE=DATE-TIME:" + "VALUE=DATE:") + startisostring + (or starttimestring "") + "\nDTEND;" + (if endtimestring "VALUE=DATE-TIME:" + "VALUE=DATE:") + (if starttimestring + startisostring + endisostring) + (or endtimestring "")) + summary)) ;; no match nil)) (defun icalendar--convert-weekly-to-ical (nonmarker entry-main) "Convert weekly diary entry to icalendar format. - NONMARKER is a regular expression matching the start of non-marking entries. ENTRY-MAIN is the first line of the diary entry." (if (and (string-match (concat nonmarker @@ -869,7 +1006,7 @@ "\\([1-9][0-9]?:[0-9][0-9]\\)" "\\([ap]m\\)?\\)?" "\\)?" - "\\s-*\\(.*\\)$") + "\\s-*\\(.*?\\) ?$") entry-main) (icalendar--get-weekday-abbrev (substring entry-main (match-beginning 1) @@ -911,35 +1048,34 @@ starttimestring)))) (setq endtimestring (format "T%06d" (+ 10000 time)))))) - (concat "\nDTSTART;" - (if starttimestring - "VALUE=DATE-TIME:" - "VALUE=DATE:") - ;; find the correct week day, - ;; 1st january 2000 was a saturday - (format - "200001%02d" - (+ (icalendar--get-weekday-number day) 2)) - (or starttimestring "") - "\nDTEND;" - (if endtimestring - "VALUE=DATE-TIME:" - "VALUE=DATE:") - (format - "200001%02d" - ;; end is non-inclusive! - (+ (icalendar--get-weekday-number day) - (if endtimestring 2 3))) - (or endtimestring "") - "\nSUMMARY:" summary - "\nRRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=" - day)) + (list (concat "\nDTSTART;" + (if starttimestring + "VALUE=DATE-TIME:" + "VALUE=DATE:") + ;; find the correct week day, + ;; 1st january 2000 was a saturday + (format + "200001%02d" + (+ (icalendar--get-weekday-number day) 2)) + (or starttimestring "") + "\nDTEND;" + (if endtimestring + "VALUE=DATE-TIME:" + "VALUE=DATE:") + (format + "200001%02d" + ;; end is non-inclusive! + (+ (icalendar--get-weekday-number day) + (if endtimestring 2 3))) + (or endtimestring "") + "\nRRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=" + day) + summary)) ;; no match nil)) (defun icalendar--convert-yearly-to-ical (nonmarker entry-main) "Convert yearly diary entry to icalendar format. - NONMARKER is a regular expression matching the start of non-marking entries. ENTRY-MAIN is the first line of the diary entry." (if (string-match (concat nonmarker @@ -951,7 +1087,7 @@ "\\(" "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" "\\)?" - "\\s-*\\([^0-9]+.*\\)$" ; must not match years + "\\s-*\\([^0-9]+.*?\\) ?$" ; must not match years ) entry-main) (let* ((daypos (if european-calendar-style 1 2)) @@ -997,25 +1133,24 @@ starttimestring)))) (setq endtimestring (format "T%06d" (+ 10000 time)))))) - (concat "\nDTSTART;" - (if starttimestring "VALUE=DATE-TIME:" - "VALUE=DATE:") - (format "1900%02d%02d" month day) - (or starttimestring "") - "\nDTEND;" - (if endtimestring "VALUE=DATE-TIME:" - "VALUE=DATE:") - ;; end is not included! shift by one day - (icalendar--date-to-isodate - (list month day 1900) - (if endtimestring 0 1)) - (or endtimestring "") - "\nSUMMARY:" - summary - "\nRRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=" - (format "%2d" month) - ";BYMONTHDAY=" - (format "%2d" day))) + (list (concat "\nDTSTART;" + (if starttimestring "VALUE=DATE-TIME:" + "VALUE=DATE:") + (format "1900%02d%02d" month day) + (or starttimestring "") + "\nDTEND;" + (if endtimestring "VALUE=DATE-TIME:" + "VALUE=DATE:") + ;; end is not included! shift by one day + (icalendar--date-to-isodate + (list month day 1900) + (if endtimestring 0 1)) + (or endtimestring "") + "\nRRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=" + (format "%2d" month) + ";BYMONTHDAY=" + (format "%2d" day)) + summary)) ;; no match nil)) @@ -1026,18 +1161,28 @@ NONMARKER is a regular expression matching the start of non-marking entries. ENTRY-MAIN is the first line of the diary entry." - (if (string-match (concat nonmarker - "%%(\\([^)]+\\))\\s-*\\(.*\\)") - entry-main) - (progn - (icalendar--dmsg "diary-sexp %s" entry-main) - (error "Sexp-entries are not supported yet")) - ;; no match - nil)) + (cond ((string-match (concat nonmarker + "%%(and \\(([^)]+)\\))\\(\\s-*.*?\\) ?$") + entry-main) + ;; simple sexp entry as generated by icalendar.el: strip off the + ;; unnecessary (and) + (icalendar--dmsg "diary-sexp from icalendar.el %s" entry-main) + (icalendar--convert-to-ical + nonmarker + (concat "%%" + (substring entry-main (match-beginning 1) (match-end 1)) + (substring entry-main (match-beginning 2) (match-end 2))))) + ((string-match (concat nonmarker + "%%([^)]+)\\s-*.*") + entry-main) + (icalendar--dmsg "diary-sexp %s" entry-main) + (error "Sexp-entries are not supported yet")) + (t + ;; no match + nil))) (defun icalendar--convert-block-to-ical (nonmarker entry-main) "Convert block diary entry to icalendar format. - NONMARKER is a regular expression matching the start of non-marking entries. ENTRY-MAIN is the first line of the diary entry." (if (string-match (concat nonmarker @@ -1047,7 +1192,7 @@ "\\(" "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" "\\)?" - "\\s-*\\(.*\\)") + "\\s-*\\(.*?\\) ?$") entry-main) (let* ((startstring (substring entry-main (match-beginning 1) @@ -1096,20 +1241,19 @@ (+ 10000 time)))))) (if starttimestring ;; with time -> write rrule - (concat "\nDTSTART;VALUE=DATE-TIME:" - startisostring - starttimestring - "\nDTEND;VALUE=DATE-TIME:" - startisostring - endtimestring - "\nSUMMARY:" - summary - "\nRRULE:FREQ=DAILY;INTERVAL=1;UNTIL=" - endisostring) + (list (concat "\nDTSTART;VALUE=DATE-TIME:" + startisostring + starttimestring + "\nDTEND;VALUE=DATE-TIME:" + startisostring + endtimestring + "\nRRULE:FREQ=DAILY;INTERVAL=1;UNTIL=" + endisostring) + summary) ;; no time -> write long event - (concat "\nDTSTART;VALUE=DATE:" startisostring - "\nDTEND;VALUE=DATE:" endisostring+1 - "\nSUMMARY:" summary))) + (list (concat "\nDTSTART;VALUE=DATE:" startisostring + "\nDTEND;VALUE=DATE:" endisostring+1) + summary))) ;; no match nil)) @@ -1121,7 +1265,7 @@ NONMARKER is a regular expression matching the start of non-marking entries. ENTRY-MAIN is the first line of the diary entry." (if (string-match (concat nonmarker - "%%(diary-float \\([^)]+\\))\\s-*\\(.*\\)") + "%%(diary-float \\([^)]+\\))\\s-*\\(.*?\\) ?$") entry-main) (progn (icalendar--dmsg "diary-float %s" entry-main) @@ -1137,7 +1281,7 @@ NONMARKER is a regular expression matching the start of non-marking entries. ENTRY-MAIN is the first line of the diary entry." (if (string-match (concat nonmarker - "%%(diary-date \\([^)]+\\))\\s-*\\(.*\\)") + "%%(diary-date \\([^)]+\\))\\s-*\\(.*?\\) ?$") entry-main) (progn (icalendar--dmsg "diary-date %s" entry-main) @@ -1147,7 +1291,6 @@ (defun icalendar--convert-cyclic-to-ical (nonmarker entry-main) "Convert `diary-cyclic' diary entry to icalendar format. - NONMARKER is a regular expression matching the start of non-marking entries. ENTRY-MAIN is the first line of the diary entry." (if (string-match (concat nonmarker @@ -1157,7 +1300,7 @@ "\\(" "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" "\\)?" - "\\s-*\\(.*\\)") + "\\s-*\\(.*?\\) ?$") entry-main) (let* ((frequency (substring entry-main (match-beginning 1) (match-end 1))) @@ -1202,27 +1345,26 @@ starttimestring)))) (setq endtimestring (format "T%06d" (+ 10000 time)))))) - (concat "\nDTSTART;" - (if starttimestring "VALUE=DATE-TIME:" - "VALUE=DATE:") - startisostring - (or starttimestring "") - "\nDTEND;" - (if endtimestring "VALUE=DATE-TIME:" - "VALUE=DATE:") - (if endtimestring endisostring endisostring+1) - (or endtimestring "") - "\nSUMMARY:" summary - "\nRRULE:FREQ=DAILY;INTERVAL=" frequency - ;; strange: korganizer does not expect - ;; BYSOMETHING here... - )) + (list (concat "\nDTSTART;" + (if starttimestring "VALUE=DATE-TIME:" + "VALUE=DATE:") + startisostring + (or starttimestring "") + "\nDTEND;" + (if endtimestring "VALUE=DATE-TIME:" + "VALUE=DATE:") + (if endtimestring endisostring endisostring+1) + (or endtimestring "") + "\nRRULE:FREQ=DAILY;INTERVAL=" frequency + ;; strange: korganizer does not expect + ;; BYSOMETHING here... + ) + summary)) ;; no match nil)) (defun icalendar--convert-anniversary-to-ical (nonmarker entry-main) "Convert `diary-anniversary' diary entry to icalendar format. - NONMARKER is a regular expression matching the start of non-marking entries. ENTRY-MAIN is the first line of the diary entry." (if (string-match (concat nonmarker @@ -1231,7 +1373,7 @@ "\\(" "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" "\\)?" - "\\s-*\\(.*\\)") + "\\s-*\\(.*?\\) ?$") entry-main) (let* ((datetime (substring entry-main (match-beginning 1) (match-end 1))) @@ -1272,26 +1414,26 @@ starttimestring)))) (setq endtimestring (format "T%06d" (+ 10000 time)))))) - (concat "\nDTSTART;" - (if starttimestring "VALUE=DATE-TIME:" - "VALUE=DATE:") - startisostring - (or starttimestring "") - "\nDTEND;" - (if endtimestring "VALUE=DATE-TIME:" - "VALUE=DATE:") - endisostring - (or endtimestring "") - "\nSUMMARY:" summary - "\nRRULE:FREQ=YEARLY;INTERVAL=1" - ;; the following is redundant, - ;; but korganizer seems to expect this... ;( - ;; and evolution doesn't understand it... :( - ;; so... who is wrong?! - ";BYMONTH=" - (substring startisostring 4 6) - ";BYMONTHDAY=" - (substring startisostring 6 8))) + (list (concat "\nDTSTART;" + (if starttimestring "VALUE=DATE-TIME:" + "VALUE=DATE:") + startisostring + (or starttimestring "") + "\nDTEND;" + (if endtimestring "VALUE=DATE-TIME:" + "VALUE=DATE:") + endisostring + (or endtimestring "") + "\nRRULE:FREQ=YEARLY;INTERVAL=1" + ;; the following is redundant, + ;; but korganizer seems to expect this... ;( + ;; and evolution doesn't understand it... :( + ;; so... who is wrong?! + ";BYMONTH=" + (substring startisostring 4 6) + ";BYMONTHDAY=" + (substring startisostring 6 8)) + summary)) ;; no match nil)) @@ -1302,7 +1444,7 @@ ;;;###autoload (defun icalendar-import-file (ical-filename diary-filename &optional non-marking) - "Import a iCalendar file and append to a diary file. + "Import an iCalendar file and append to a diary file. Argument ICAL-FILENAME output iCalendar file. Argument DIARY-FILENAME input `diary-file'. Optional argument NON-MARKING determines whether events are created as @@ -1376,10 +1518,13 @@ "Create a string representation of an iCalendar EVENT." (let ((string icalendar-import-format) (conversion-list - '(("%d" DESCRIPTION icalendar-import-format-description) - ("%s" SUMMARY icalendar-import-format-subject) + '(("%c" CLASS icalendar-import-format-class) + ("%d" DESCRIPTION icalendar-import-format-description) ("%l" LOCATION icalendar-import-format-location) - ("%o" ORGANIZER icalendar-import-format-organizer)))) + ("%o" ORGANIZER icalendar-import-format-organizer) + ("%s" SUMMARY icalendar-import-format-summary) + ("%t" STATUS icalendar-import-format-status) + ("%u" URL icalendar-import-format-url)))) ;; convert the specifiers in the format string (mapcar (lambda (i) (let* ((spec (car i)) @@ -1392,17 +1537,19 @@ (icalendar--rris "%s" (icalendar--convert-string-for-import contents) - (symbol-value format)))) + (symbol-value format) + t t))) (setq string (icalendar--rris spec formatted-contents - string)))) + string + t t)))) conversion-list) string)) (defun icalendar--convert-ical-to-diary (ical-list diary-file &optional do-not-ask non-marking) - "Convert an iCalendar file to an Emacs diary file. + "Convert Calendar data to an Emacs diary file. Import VEVENTS from the iCalendar object ICAL-LIST and saves them to a DIARY-FILE. If DO-NOT-ASK is nil the user is asked for each event whether to actually import it. NON-MARKING determines whether diary @@ -1432,13 +1579,13 @@ end-d end-1-d end-t - (subject (icalendar--convert-string-for-import + (summary (icalendar--convert-string-for-import (or (icalendar--get-event-property e 'SUMMARY) - "No Subject"))) + "No summary"))) (rrule (icalendar--get-event-property e 'RRULE)) (rdate (icalendar--get-event-property e 'RDATE)) (duration (icalendar--get-event-property e 'DURATION))) - (icalendar--dmsg "%s: `%s'" start-d subject) + (icalendar--dmsg "%s: `%s'" start-d summary) ;; check whether start-time is missing (if (and dtstart (string= @@ -1456,7 +1603,7 @@ t)))) (if (and dtend-dec (not (eq dtend-dec dtend-dec-d))) (message "Inconsistent endtime and duration for %s" - subject)) + summary)) (setq dtend-dec dtend-dec-d) (setq dtend-1-dec dtend-1-dec-d))) (setq end-d (if dtend-dec @@ -1517,9 +1664,9 @@ (setq diary-string (concat diary-string " " (icalendar--format-ical-event e))) - (if do-not-ask (setq subject nil)) + (if do-not-ask (setq summary nil)) (icalendar--add-diary-entry diary-string diary-file - non-marking subject)) + non-marking summary)) ;; event was not ok (setq found-error t) (setq error-string @@ -1570,7 +1717,7 @@ (let ((until-1 0)) (cond ((string-equal frequency "DAILY") (setq until (icalendar--add-decoded-times - dtstart-dec + dtstart-dec (list 0 0 0 (* (read count) interval) 0 0))) (setq until-1 (icalendar--add-decoded-times dtstart-dec @@ -1767,23 +1914,24 @@ start-t)))) (defun icalendar--add-diary-entry (string diary-file non-marking - &optional subject) + &optional summary) "Add STRING to the diary file DIARY-FILE. STRING must be a properly formatted valid diary entry. NON-MARKING determines whether diary events are created as non-marking. If -SUBJECT is not nil it must be a string that gives the subject of the +SUMMARY is not nil it must be a string that gives the summary of the entry. In this case the user will be asked whether he wants to insert the entry." - (when (or (not subject) + (when (or (not summary) (y-or-n-p (format "Add appointment for `%s' to diary? " - subject))) - (when subject + summary))) + (when summary (setq non-marking (y-or-n-p (format "Make appointment non-marking? ")))) (save-window-excursion (unless diary-file (setq diary-file (read-file-name "Add appointment to this diary file: "))) + ;; Note: make-diary-entry will add a trailing blank char.... :( (make-diary-entry string non-marking diary-file)))) (provide 'icalendar)