aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Morris2005-10-24 07:27:39 +0000
committerGlenn Morris2005-10-24 07:27:39 +0000
commitd2afe62f2adf8211d61036ed4e8f77d1d7e2926d (patch)
treec211096eb77de053bc98e874410a3366148e9bd4
parentad1eff1bc7c4bc8badfc7cbbbc6ed30925519887 (diff)
downloademacs-d2afe62f2adf8211d61036ed4e8f77d1d7e2926d.tar.gz
emacs-d2afe62f2adf8211d61036ed4e8f77d1d7e2926d.zip
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'.
-rw-r--r--lisp/calendar/icalendar.el550
1 files changed, 349 insertions, 201 deletions
diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el
index 0e0400bd686..33f89474504 100644
--- a/lisp/calendar/icalendar.el
+++ b/lisp/calendar/icalendar.el
@@ -97,7 +97,7 @@
97 97
98;;; Code: 98;;; Code:
99 99
100(defconst icalendar-version 0.12 100(defconst icalendar-version "0.13"
101 "Version number of icalendar.el.") 101 "Version number of icalendar.el.")
102 102
103;; ====================================================================== 103;; ======================================================================
@@ -113,18 +113,21 @@
113 "Format string for importing events from iCalendar into Emacs diary. 113 "Format string for importing events from iCalendar into Emacs diary.
114This string defines how iCalendar events are inserted into diary 114This string defines how iCalendar events are inserted into diary
115file. Meaning of the specifiers: 115file. Meaning of the specifiers:
116%c Class, see `icalendar-import-format-class'
116%d Description, see `icalendar-import-format-description' 117%d Description, see `icalendar-import-format-description'
117%l Location, see `icalendar-import-format-location' 118%l Location, see `icalendar-import-format-location'
118%o Organizer, see `icalendar-import-format-organizer' 119%o Organizer, see `icalendar-import-format-organizer'
119%s Subject, see `icalendar-import-format-subject'" 120%s Summary, see `icalendar-import-format-summary'
121%t Status, see `icalendar-import-format-status'
122%u URL, see `icalendar-import-format-url'"
120 :type 'string 123 :type 'string
121 :group 'icalendar) 124 :group 'icalendar)
122 125
123(defcustom icalendar-import-format-subject 126(defcustom icalendar-import-format-summary
124 "%s" 127 "%s"
125 "Format string defining how the subject element is formatted. 128 "Format string defining how the summary element is formatted.
126This applies only if the subject is not empty! `%s' is replaced 129This applies only if the summary is not empty! `%s' is replaced
127by the subject." 130by the summary."
128 :type 'string 131 :type 'string
129 :group 'icalendar) 132 :group 'icalendar)
130 133
@@ -152,6 +155,30 @@ replaced by the organizer."
152 :type 'string 155 :type 'string
153 :group 'icalendar) 156 :group 'icalendar)
154 157
158(defcustom icalendar-import-format-url
159 "\n URL: %s"
160 "Format string defining how the URL element is formatted.
161This applies only if the URL is not empty! `%s' is replaced by
162the URL."
163 :type 'string
164 :group 'icalendar)
165
166(defcustom icalendar-import-format-status
167 "\n Status: %s"
168 "Format string defining how the status element is formatted.
169This applies only if the status is not empty! `%s' is replaced by
170the status."
171 :type 'string
172 :group 'icalendar)
173
174(defcustom icalendar-import-format-class
175 "\n Class: %s"
176 "Format string defining how the class element is formatted.
177This applies only if the class is not empty! `%s' is replaced by
178the class."
179 :type 'string
180 :group 'icalendar)
181
155(defvar icalendar-debug nil 182(defvar icalendar-debug nil
156 "Enable icalendar debug messages.") 183 "Enable icalendar debug messages.")
157 184
@@ -195,15 +222,16 @@ buffer."
195 (replace-match "" nil nil))) 222 (replace-match "" nil nil)))
196 unfolded-buffer)) 223 unfolded-buffer))
197 224
198(defsubst icalendar--rris (re rp st) 225(defsubst icalendar--rris (&rest args)
199 "Replace regexp RE with RP in string ST and return the new string. 226 "Replace regular expression in string.
200This is here for compatibility with XEmacs." 227Pass ARGS to `replace-regexp-in-string' (Emacs) or to
228`replace-in-string' (XEmacs)."
201 ;; XEmacs: 229 ;; XEmacs:
202 (if (fboundp 'replace-in-string) 230 (if (fboundp 'replace-in-string)
203 (save-match-data ;; apparently XEmacs needs save-match-data 231 (save-match-data ;; apparently XEmacs needs save-match-data
204 (replace-in-string st re rp)) 232 (apply 'replace-in-string args))
205 ;; Emacs: 233 ;; Emacs:
206 (replace-regexp-in-string re rp st))) 234 (apply 'replace-regexp-in-string args)))
207 235
208(defun icalendar--read-element (invalue inparams) 236(defun icalendar--read-element (invalue inparams)
209 "Recursively read the next iCalendar element in the current buffer. 237 "Recursively read the next iCalendar element in the current buffer.
@@ -609,12 +637,11 @@ takes care of european-style."
609 (setq month day) 637 (setq month day)
610 (setq day x)))) 638 (setq day x))))
611 ( ;; date contains month names -- european-style 639 ( ;; date contains month names -- european-style
612 (and european-calendar-style 640 (string-match (concat "\\s-*"
613 (string-match (concat "\\s-*" 641 "0?\\([123]?[0-9]\\)[ \t/]\\s-*"
614 "0?\\([123]?[0-9]\\)[ \t/]\\s-*" 642 "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*"
615 "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" 643 "\\([0-9]\\{4\\}\\)")
616 "\\([0-9]\\{4\\}\\)") 644 datestring)
617 datestring))
618 (setq day (read (substring datestring (match-beginning 1) 645 (setq day (read (substring datestring (match-beginning 1)
619 (match-end 1)))) 646 (match-end 1))))
620 (setq month (icalendar--get-month-number 647 (setq month (icalendar--get-month-number
@@ -623,12 +650,11 @@ takes care of european-style."
623 (setq year (read (substring datestring (match-beginning 3) 650 (setq year (read (substring datestring (match-beginning 3)
624 (match-end 3))))) 651 (match-end 3)))))
625 ( ;; date contains month names -- non-european-style 652 ( ;; date contains month names -- non-european-style
626 (and (not european-calendar-style) 653 (string-match (concat "\\s-*"
627 (string-match (concat "\\s-*" 654 "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*"
628 "\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" 655 "0?\\([123]?[0-9]\\),?[ \t/]\\s-*"
629 "0?\\([123]?[0-9]\\),?[ \t/]\\s-*" 656 "\\([0-9]\\{4\\}\\)")
630 "\\([0-9]\\{4\\}\\)") 657 datestring)
631 datestring))
632 (setq day (read (substring datestring (match-beginning 2) 658 (setq day (read (substring datestring (match-beginning 2)
633 (match-end 2)))) 659 (match-end 2))))
634 (setq month (icalendar--get-month-number 660 (setq month (icalendar--get-month-number
@@ -704,10 +730,12 @@ FExport diary data into iCalendar file: ")
704 (entry-main "") 730 (entry-main "")
705 (entry-rest "") 731 (entry-rest "")
706 (header "") 732 (header "")
733 (contents-n-summary)
707 (contents) 734 (contents)
708 (found-error nil) 735 (found-error nil)
709 (nonmarker (concat "^" (regexp-quote diary-nonmarking-symbol) 736 (nonmarker (concat "^" (regexp-quote diary-nonmarking-symbol)
710 "?"))) 737 "?"))
738 (other-elements nil))
711 ;; prepare buffer with error messages 739 ;; prepare buffer with error messages
712 (save-current-buffer 740 (save-current-buffer
713 (set-buffer (get-buffer-create "*icalendar-errors*")) 741 (set-buffer (get-buffer-create "*icalendar-errors*"))
@@ -728,36 +756,33 @@ FExport diary data into iCalendar file: ")
728 (car (cddr (current-time))))) 756 (car (cddr (current-time)))))
729 (condition-case error-val 757 (condition-case error-val
730 (progn 758 (progn
731 (setq contents 759 (setq contents-n-summary
732 (or 760 (icalendar--convert-to-ical nonmarker entry-main))
733 ;; anniversaries -- %%(diary-anniversary ...) 761 (setq other-elements (icalendar--parse-summary-and-rest
734 (icalendar--convert-anniversary-to-ical nonmarker 762 (concat entry-main entry-rest)))
735 entry-main) 763 (setq contents (concat (car contents-n-summary)
736 ;; cyclic events -- %%(diary-cyclic ...) 764 "\nSUMMARY:" (cadr contents-n-summary)))
737 (icalendar--convert-cyclic-to-ical nonmarker entry-main) 765 (let ((cla (cdr (assoc 'cla other-elements)))
738 ;; diary-date -- %%(diary-date ...) 766 (des (cdr (assoc 'des other-elements)))
739 (icalendar--convert-date-to-ical nonmarker entry-main) 767 (loc (cdr (assoc 'loc other-elements)))
740 ;; float events -- %%(diary-float ...) 768 (org (cdr (assoc 'org other-elements)))
741 (icalendar--convert-float-to-ical nonmarker entry-main) 769 (sta (cdr (assoc 'sta other-elements)))
742 ;; block events -- %%(diary-block ...) 770 (sum (cdr (assoc 'sum other-elements)))
743 (icalendar--convert-block-to-ical nonmarker entry-main) 771 (url (cdr (assoc 'url other-elements))))
744 ;; other sexp diary entries 772 (if cla
745 (icalendar--convert-sexp-to-ical nonmarker entry-main) 773 (setq contents (concat contents "\nCLASS:" cla)))
746 ;; weekly by day -- Monday 8:30 Team meeting 774 (if des
747 (icalendar--convert-weekly-to-ical nonmarker entry-main) 775 (setq contents (concat contents "\nDESCRIPTION:" des)))
748 ;; yearly by day -- 1 May Tag der Arbeit 776 (if loc
749 (icalendar--convert-yearly-to-ical nonmarker entry-main) 777 (setq contents (concat contents "\nLOCATION:" loc)))
750 ;; "ordinary" events, start and end time given 778 (if org
751 ;; 1 Feb 2003 blah 779 (setq contents (concat contents "\nORGANIZER:" org)))
752 (icalendar--convert-ordinary-to-ical nonmarker entry-main) 780 (if sta
753 ;; everything else 781 (setq contents (concat contents "\nSTATUS:" sta)))
754 ;; Oops! what's that? 782 ;;(if sum
755 (error "Could not parse entry"))) 783 ;; (setq contents (concat contents "\nSUMMARY:" sum)))
756 (unless (string= entry-rest "") 784 (if url
757 (setq contents 785 (setq contents (concat contents "\nURL:" url))))
758 (concat contents "\nDESCRIPTION:"
759 (icalendar--convert-string-for-export
760 entry-rest))))
761 (setq result (concat result header contents "\nEND:VEVENT"))) 786 (setq result (concat result header contents "\nEND:VEVENT")))
762 ;; handle errors 787 ;; handle errors
763 (error 788 (error
@@ -780,13 +805,127 @@ FExport diary data into iCalendar file: ")
780 (insert result) 805 (insert result)
781 (insert "\nEND:VCALENDAR\n") 806 (insert "\nEND:VCALENDAR\n")
782 ;; save the diary file 807 ;; save the diary file
783 (save-buffer)))) 808 (save-buffer)
809 (unless found-error
810 (bury-buffer)))))
784 found-error)) 811 found-error))
785 812
786;; subroutines 813(defun icalendar--convert-to-ical (nonmarker entry-main)
814 "Convert a diary entry to icalendar format.
815NONMARKER is a regular expression matching the start of non-marking
816entries. ENTRY-MAIN is the first line of the diary entry."
817 (or
818 ;; anniversaries -- %%(diary-anniversary ...)
819 (icalendar--convert-anniversary-to-ical nonmarker entry-main)
820 ;; cyclic events -- %%(diary-cyclic ...)
821 (icalendar--convert-cyclic-to-ical nonmarker entry-main)
822 ;; diary-date -- %%(diary-date ...)
823 (icalendar--convert-date-to-ical nonmarker entry-main)
824 ;; float events -- %%(diary-float ...)
825 (icalendar--convert-float-to-ical nonmarker entry-main)
826 ;; block events -- %%(diary-block ...)
827 (icalendar--convert-block-to-ical nonmarker entry-main)
828 ;; other sexp diary entries
829 (icalendar--convert-sexp-to-ical nonmarker entry-main)
830 ;; weekly by day -- Monday 8:30 Team meeting
831 (icalendar--convert-weekly-to-ical nonmarker entry-main)
832 ;; yearly by day -- 1 May Tag der Arbeit
833 (icalendar--convert-yearly-to-ical nonmarker entry-main)
834 ;; "ordinary" events, start and end time given
835 ;; 1 Feb 2003 blah
836 (icalendar--convert-ordinary-to-ical nonmarker entry-main)
837 ;; everything else
838 ;; Oops! what's that?
839 (error "Could not parse entry")))
840
841(defun icalendar--parse-summary-and-rest (summary-and-rest)
842 "Parse SUMMARY-AND-REST from a diary to fill iCalendar properties."
843 (save-match-data
844 (let* ((s icalendar-import-format)
845 (p-cla (or (string-match "%c" icalendar-import-format) -1))
846 (p-des (or (string-match "%d" icalendar-import-format) -1))
847 (p-loc (or (string-match "%l" icalendar-import-format) -1))
848 (p-org (or (string-match "%o" icalendar-import-format) -1))
849 (p-sum (or (string-match "%s" icalendar-import-format) -1))
850 (p-sta (or (string-match "%t" icalendar-import-format) -1))
851 (p-url (or (string-match "%u" icalendar-import-format) -1))
852 (p-list (sort (list p-cla p-des p-loc p-org p-sta p-sum p-url) '<))
853 pos-cla pos-des pos-loc pos-org pos-sta pos-sum pos-url)
854 (dotimes (i (length p-list))
855 (cond ((and (>= p-cla 0) (= (nth i p-list) p-cla))
856 (setq pos-cla (+ 2 (* 2 i))))
857 ((and (>= p-des 0) (= (nth i p-list) p-des))
858 (setq pos-des (+ 2 (* 2 i))))
859 ((and (>= p-loc 0) (= (nth i p-list) p-loc))
860 (setq pos-loc (+ 2 (* 2 i))))
861 ((and (>= p-org 0) (= (nth i p-list) p-org))
862 (setq pos-org (+ 2 (* 2 i))))
863 ((and (>= p-sta 0) (= (nth i p-list) p-sta))
864 (setq pos-sta (+ 2 (* 2 i))))
865 ((and (>= p-sum 0) (= (nth i p-list) p-sum))
866 (setq pos-sum (+ 2 (* 2 i))))
867 ((and (>= p-url 0) (= (nth i p-list) p-url))
868 (setq pos-url (+ 2 (* 2 i))))))
869 (mapc (lambda (ij)
870 (setq s (icalendar--rris (car ij) (cadr ij) s t t)))
871 (list
872 ;; summary must be first! because of %s
873 (list "%s"
874 (concat "\\(" icalendar-import-format-summary "\\)?"))
875 (list "%c"
876 (concat "\\(" icalendar-import-format-class "\\)?"))
877 (list "%d"
878 (concat "\\(" icalendar-import-format-description "\\)?"))
879 (list "%l"
880 (concat "\\(" icalendar-import-format-location "\\)?"))
881 (list "%o"
882 (concat "\\(" icalendar-import-format-organizer "\\)?"))
883 (list "%t"
884 (concat "\\(" icalendar-import-format-status "\\)?"))
885 (list "%u"
886 (concat "\\(" icalendar-import-format-url "\\)?"))))
887 (setq s (concat (icalendar--rris "%s" "\\(.*\\)" s nil t) " "))
888 (if (string-match s summary-and-rest)
889 (let (cla des loc org sta sum url)
890 (if (and pos-sum (match-beginning pos-sum))
891 (setq sum (substring summary-and-rest
892 (match-beginning pos-sum)
893 (match-end pos-sum))))
894 (if (and pos-cla (match-beginning pos-cla))
895 (setq cla (substring summary-and-rest
896 (match-beginning pos-cla)
897 (match-end pos-cla))))
898 (if (and pos-des (match-beginning pos-des))
899 (setq des (substring summary-and-rest
900 (match-beginning pos-des)
901 (match-end pos-des))))
902 (if (and pos-loc (match-beginning pos-loc))
903 (setq loc (substring summary-and-rest
904 (match-beginning pos-loc)
905 (match-end pos-loc))))
906 (if (and pos-org (match-beginning pos-org))
907 (setq org (substring summary-and-rest
908 (match-beginning pos-org)
909 (match-end pos-org))))
910 (if (and pos-sta (match-beginning pos-sta))
911 (setq sta (substring summary-and-rest
912 (match-beginning pos-sta)
913 (match-end pos-sta))))
914 (if (and pos-url (match-beginning pos-url))
915 (setq url (substring summary-and-rest
916 (match-beginning pos-url)
917 (match-end pos-url))))
918 (list (if cla (cons 'cla cla) nil)
919 (if des (cons 'des des) nil)
920 (if loc (cons 'loc loc) nil)
921 (if org (cons 'org org) nil)
922 (if sta (cons 'sta sta) nil)
923 ;;(if sum (cons 'sum sum) nil)
924 (if url (cons 'url url) nil)))))))
925
926;; subroutines for icalendar-export-region
787(defun icalendar--convert-ordinary-to-ical (nonmarker entry-main) 927(defun icalendar--convert-ordinary-to-ical (nonmarker entry-main)
788 "Convert \"ordinary\" diary entry to icalendar format. 928 "Convert \"ordinary\" diary entry to icalendar format.
789
790NONMARKER is a regular expression matching the start of non-marking 929NONMARKER is a regular expression matching the start of non-marking
791entries. ENTRY-MAIN is the first line of the diary entry." 930entries. ENTRY-MAIN is the first line of the diary entry."
792 (if (string-match (concat nonmarker 931 (if (string-match (concat nonmarker
@@ -795,7 +934,7 @@ entries. ENTRY-MAIN is the first line of the diary entry."
795 "\\(" 934 "\\("
796 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" 935 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?"
797 "\\)?" 936 "\\)?"
798 "\\s-*\\(.*\\)") 937 "\\s-*\\(.*?\\) ?$")
799 entry-main) 938 entry-main)
800 (let* ((datetime (substring entry-main (match-beginning 1) 939 (let* ((datetime (substring entry-main (match-beginning 1)
801 (match-end 1))) 940 (match-end 1)))
@@ -839,26 +978,24 @@ entries. ENTRY-MAIN is the first line of the diary entry."
839 starttimestring)))) 978 starttimestring))))
840 (setq endtimestring (format "T%06d" 979 (setq endtimestring (format "T%06d"
841 (+ 10000 time)))))) 980 (+ 10000 time))))))
842 (concat "\nDTSTART;" 981 (list (concat "\nDTSTART;"
843 (if starttimestring "VALUE=DATE-TIME:" 982 (if starttimestring "VALUE=DATE-TIME:"
844 "VALUE=DATE:") 983 "VALUE=DATE:")
845 startisostring 984 startisostring
846 (or starttimestring "") 985 (or starttimestring "")
847 "\nDTEND;" 986 "\nDTEND;"
848 (if endtimestring "VALUE=DATE-TIME:" 987 (if endtimestring "VALUE=DATE-TIME:"
849 "VALUE=DATE:") 988 "VALUE=DATE:")
850 (if starttimestring 989 (if starttimestring
851 startisostring 990 startisostring
852 endisostring) 991 endisostring)
853 (or endtimestring "") 992 (or endtimestring ""))
854 "\nSUMMARY:" 993 summary))
855 summary))
856 ;; no match 994 ;; no match
857 nil)) 995 nil))
858 996
859(defun icalendar--convert-weekly-to-ical (nonmarker entry-main) 997(defun icalendar--convert-weekly-to-ical (nonmarker entry-main)
860 "Convert weekly diary entry to icalendar format. 998 "Convert weekly diary entry to icalendar format.
861
862NONMARKER is a regular expression matching the start of non-marking 999NONMARKER is a regular expression matching the start of non-marking
863entries. ENTRY-MAIN is the first line of the diary entry." 1000entries. ENTRY-MAIN is the first line of the diary entry."
864 (if (and (string-match (concat nonmarker 1001 (if (and (string-match (concat nonmarker
@@ -869,7 +1006,7 @@ entries. ENTRY-MAIN is the first line of the diary entry."
869 "\\([1-9][0-9]?:[0-9][0-9]\\)" 1006 "\\([1-9][0-9]?:[0-9][0-9]\\)"
870 "\\([ap]m\\)?\\)?" 1007 "\\([ap]m\\)?\\)?"
871 "\\)?" 1008 "\\)?"
872 "\\s-*\\(.*\\)$") 1009 "\\s-*\\(.*?\\) ?$")
873 entry-main) 1010 entry-main)
874 (icalendar--get-weekday-abbrev 1011 (icalendar--get-weekday-abbrev
875 (substring entry-main (match-beginning 1) 1012 (substring entry-main (match-beginning 1)
@@ -911,35 +1048,34 @@ entries. ENTRY-MAIN is the first line of the diary entry."
911 starttimestring)))) 1048 starttimestring))))
912 (setq endtimestring (format "T%06d" 1049 (setq endtimestring (format "T%06d"
913 (+ 10000 time)))))) 1050 (+ 10000 time))))))
914 (concat "\nDTSTART;" 1051 (list (concat "\nDTSTART;"
915 (if starttimestring 1052 (if starttimestring
916 "VALUE=DATE-TIME:" 1053 "VALUE=DATE-TIME:"
917 "VALUE=DATE:") 1054 "VALUE=DATE:")
918 ;; find the correct week day, 1055 ;; find the correct week day,
919 ;; 1st january 2000 was a saturday 1056 ;; 1st january 2000 was a saturday
920 (format 1057 (format
921 "200001%02d" 1058 "200001%02d"
922 (+ (icalendar--get-weekday-number day) 2)) 1059 (+ (icalendar--get-weekday-number day) 2))
923 (or starttimestring "") 1060 (or starttimestring "")
924 "\nDTEND;" 1061 "\nDTEND;"
925 (if endtimestring 1062 (if endtimestring
926 "VALUE=DATE-TIME:" 1063 "VALUE=DATE-TIME:"
927 "VALUE=DATE:") 1064 "VALUE=DATE:")
928 (format 1065 (format
929 "200001%02d" 1066 "200001%02d"
930 ;; end is non-inclusive! 1067 ;; end is non-inclusive!
931 (+ (icalendar--get-weekday-number day) 1068 (+ (icalendar--get-weekday-number day)
932 (if endtimestring 2 3))) 1069 (if endtimestring 2 3)))
933 (or endtimestring "") 1070 (or endtimestring "")
934 "\nSUMMARY:" summary 1071 "\nRRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY="
935 "\nRRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=" 1072 day)
936 day)) 1073 summary))
937 ;; no match 1074 ;; no match
938 nil)) 1075 nil))
939 1076
940(defun icalendar--convert-yearly-to-ical (nonmarker entry-main) 1077(defun icalendar--convert-yearly-to-ical (nonmarker entry-main)
941 "Convert yearly diary entry to icalendar format. 1078 "Convert yearly diary entry to icalendar format.
942
943NONMARKER is a regular expression matching the start of non-marking 1079NONMARKER is a regular expression matching the start of non-marking
944entries. ENTRY-MAIN is the first line of the diary entry." 1080entries. ENTRY-MAIN is the first line of the diary entry."
945 (if (string-match (concat nonmarker 1081 (if (string-match (concat nonmarker
@@ -951,7 +1087,7 @@ entries. ENTRY-MAIN is the first line of the diary entry."
951 "\\(" 1087 "\\("
952 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" 1088 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?"
953 "\\)?" 1089 "\\)?"
954 "\\s-*\\([^0-9]+.*\\)$" ; must not match years 1090 "\\s-*\\([^0-9]+.*?\\) ?$" ; must not match years
955 ) 1091 )
956 entry-main) 1092 entry-main)
957 (let* ((daypos (if european-calendar-style 1 2)) 1093 (let* ((daypos (if european-calendar-style 1 2))
@@ -997,25 +1133,24 @@ entries. ENTRY-MAIN is the first line of the diary entry."
997 starttimestring)))) 1133 starttimestring))))
998 (setq endtimestring (format "T%06d" 1134 (setq endtimestring (format "T%06d"
999 (+ 10000 time)))))) 1135 (+ 10000 time))))))
1000 (concat "\nDTSTART;" 1136 (list (concat "\nDTSTART;"
1001 (if starttimestring "VALUE=DATE-TIME:" 1137 (if starttimestring "VALUE=DATE-TIME:"
1002 "VALUE=DATE:") 1138 "VALUE=DATE:")
1003 (format "1900%02d%02d" month day) 1139 (format "1900%02d%02d" month day)
1004 (or starttimestring "") 1140 (or starttimestring "")
1005 "\nDTEND;" 1141 "\nDTEND;"
1006 (if endtimestring "VALUE=DATE-TIME:" 1142 (if endtimestring "VALUE=DATE-TIME:"
1007 "VALUE=DATE:") 1143 "VALUE=DATE:")
1008 ;; end is not included! shift by one day 1144 ;; end is not included! shift by one day
1009 (icalendar--date-to-isodate 1145 (icalendar--date-to-isodate
1010 (list month day 1900) 1146 (list month day 1900)
1011 (if endtimestring 0 1)) 1147 (if endtimestring 0 1))
1012 (or endtimestring "") 1148 (or endtimestring "")
1013 "\nSUMMARY:" 1149 "\nRRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH="
1014 summary 1150 (format "%2d" month)
1015 "\nRRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=" 1151 ";BYMONTHDAY="
1016 (format "%2d" month) 1152 (format "%2d" day))
1017 ";BYMONTHDAY=" 1153 summary))
1018 (format "%2d" day)))
1019 ;; no match 1154 ;; no match
1020 nil)) 1155 nil))
1021 1156
@@ -1026,18 +1161,28 @@ FIXME!
1026 1161
1027NONMARKER is a regular expression matching the start of non-marking 1162NONMARKER is a regular expression matching the start of non-marking
1028entries. ENTRY-MAIN is the first line of the diary entry." 1163entries. ENTRY-MAIN is the first line of the diary entry."
1029 (if (string-match (concat nonmarker 1164 (cond ((string-match (concat nonmarker
1030 "%%(\\([^)]+\\))\\s-*\\(.*\\)") 1165 "%%(and \\(([^)]+)\\))\\(\\s-*.*?\\) ?$")
1031 entry-main) 1166 entry-main)
1032 (progn 1167 ;; simple sexp entry as generated by icalendar.el: strip off the
1033 (icalendar--dmsg "diary-sexp %s" entry-main) 1168 ;; unnecessary (and)
1034 (error "Sexp-entries are not supported yet")) 1169 (icalendar--dmsg "diary-sexp from icalendar.el %s" entry-main)
1035 ;; no match 1170 (icalendar--convert-to-ical
1036 nil)) 1171 nonmarker
1172 (concat "%%"
1173 (substring entry-main (match-beginning 1) (match-end 1))
1174 (substring entry-main (match-beginning 2) (match-end 2)))))
1175 ((string-match (concat nonmarker
1176 "%%([^)]+)\\s-*.*")
1177 entry-main)
1178 (icalendar--dmsg "diary-sexp %s" entry-main)
1179 (error "Sexp-entries are not supported yet"))
1180 (t
1181 ;; no match
1182 nil)))
1037 1183
1038(defun icalendar--convert-block-to-ical (nonmarker entry-main) 1184(defun icalendar--convert-block-to-ical (nonmarker entry-main)
1039 "Convert block diary entry to icalendar format. 1185 "Convert block diary entry to icalendar format.
1040
1041NONMARKER is a regular expression matching the start of non-marking 1186NONMARKER is a regular expression matching the start of non-marking
1042entries. ENTRY-MAIN is the first line of the diary entry." 1187entries. ENTRY-MAIN is the first line of the diary entry."
1043 (if (string-match (concat nonmarker 1188 (if (string-match (concat nonmarker
@@ -1047,7 +1192,7 @@ entries. ENTRY-MAIN is the first line of the diary entry."
1047 "\\(" 1192 "\\("
1048 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" 1193 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?"
1049 "\\)?" 1194 "\\)?"
1050 "\\s-*\\(.*\\)") 1195 "\\s-*\\(.*?\\) ?$")
1051 entry-main) 1196 entry-main)
1052 (let* ((startstring (substring entry-main 1197 (let* ((startstring (substring entry-main
1053 (match-beginning 1) 1198 (match-beginning 1)
@@ -1096,20 +1241,19 @@ entries. ENTRY-MAIN is the first line of the diary entry."
1096 (+ 10000 time)))))) 1241 (+ 10000 time))))))
1097 (if starttimestring 1242 (if starttimestring
1098 ;; with time -> write rrule 1243 ;; with time -> write rrule
1099 (concat "\nDTSTART;VALUE=DATE-TIME:" 1244 (list (concat "\nDTSTART;VALUE=DATE-TIME:"
1100 startisostring 1245 startisostring
1101 starttimestring 1246 starttimestring
1102 "\nDTEND;VALUE=DATE-TIME:" 1247 "\nDTEND;VALUE=DATE-TIME:"
1103 startisostring 1248 startisostring
1104 endtimestring 1249 endtimestring
1105 "\nSUMMARY:" 1250 "\nRRULE:FREQ=DAILY;INTERVAL=1;UNTIL="
1106 summary 1251 endisostring)
1107 "\nRRULE:FREQ=DAILY;INTERVAL=1;UNTIL=" 1252 summary)
1108 endisostring)
1109 ;; no time -> write long event 1253 ;; no time -> write long event
1110 (concat "\nDTSTART;VALUE=DATE:" startisostring 1254 (list (concat "\nDTSTART;VALUE=DATE:" startisostring
1111 "\nDTEND;VALUE=DATE:" endisostring+1 1255 "\nDTEND;VALUE=DATE:" endisostring+1)
1112 "\nSUMMARY:" summary))) 1256 summary)))
1113 ;; no match 1257 ;; no match
1114 nil)) 1258 nil))
1115 1259
@@ -1121,7 +1265,7 @@ FIXME!
1121NONMARKER is a regular expression matching the start of non-marking 1265NONMARKER is a regular expression matching the start of non-marking
1122entries. ENTRY-MAIN is the first line of the diary entry." 1266entries. ENTRY-MAIN is the first line of the diary entry."
1123 (if (string-match (concat nonmarker 1267 (if (string-match (concat nonmarker
1124 "%%(diary-float \\([^)]+\\))\\s-*\\(.*\\)") 1268 "%%(diary-float \\([^)]+\\))\\s-*\\(.*?\\) ?$")
1125 entry-main) 1269 entry-main)
1126 (progn 1270 (progn
1127 (icalendar--dmsg "diary-float %s" entry-main) 1271 (icalendar--dmsg "diary-float %s" entry-main)
@@ -1137,7 +1281,7 @@ FIXME!
1137NONMARKER is a regular expression matching the start of non-marking 1281NONMARKER is a regular expression matching the start of non-marking
1138entries. ENTRY-MAIN is the first line of the diary entry." 1282entries. ENTRY-MAIN is the first line of the diary entry."
1139 (if (string-match (concat nonmarker 1283 (if (string-match (concat nonmarker
1140 "%%(diary-date \\([^)]+\\))\\s-*\\(.*\\)") 1284 "%%(diary-date \\([^)]+\\))\\s-*\\(.*?\\) ?$")
1141 entry-main) 1285 entry-main)
1142 (progn 1286 (progn
1143 (icalendar--dmsg "diary-date %s" entry-main) 1287 (icalendar--dmsg "diary-date %s" entry-main)
@@ -1147,7 +1291,6 @@ entries. ENTRY-MAIN is the first line of the diary entry."
1147 1291
1148(defun icalendar--convert-cyclic-to-ical (nonmarker entry-main) 1292(defun icalendar--convert-cyclic-to-ical (nonmarker entry-main)
1149 "Convert `diary-cyclic' diary entry to icalendar format. 1293 "Convert `diary-cyclic' diary entry to icalendar format.
1150
1151NONMARKER is a regular expression matching the start of non-marking 1294NONMARKER is a regular expression matching the start of non-marking
1152entries. ENTRY-MAIN is the first line of the diary entry." 1295entries. ENTRY-MAIN is the first line of the diary entry."
1153 (if (string-match (concat nonmarker 1296 (if (string-match (concat nonmarker
@@ -1157,7 +1300,7 @@ entries. ENTRY-MAIN is the first line of the diary entry."
1157 "\\(" 1300 "\\("
1158 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" 1301 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?"
1159 "\\)?" 1302 "\\)?"
1160 "\\s-*\\(.*\\)") 1303 "\\s-*\\(.*?\\) ?$")
1161 entry-main) 1304 entry-main)
1162 (let* ((frequency (substring entry-main (match-beginning 1) 1305 (let* ((frequency (substring entry-main (match-beginning 1)
1163 (match-end 1))) 1306 (match-end 1)))
@@ -1202,27 +1345,26 @@ entries. ENTRY-MAIN is the first line of the diary entry."
1202 starttimestring)))) 1345 starttimestring))))
1203 (setq endtimestring (format "T%06d" 1346 (setq endtimestring (format "T%06d"
1204 (+ 10000 time)))))) 1347 (+ 10000 time))))))
1205 (concat "\nDTSTART;" 1348 (list (concat "\nDTSTART;"
1206 (if starttimestring "VALUE=DATE-TIME:" 1349 (if starttimestring "VALUE=DATE-TIME:"
1207 "VALUE=DATE:") 1350 "VALUE=DATE:")
1208 startisostring 1351 startisostring
1209 (or starttimestring "") 1352 (or starttimestring "")
1210 "\nDTEND;" 1353 "\nDTEND;"
1211 (if endtimestring "VALUE=DATE-TIME:" 1354 (if endtimestring "VALUE=DATE-TIME:"
1212 "VALUE=DATE:") 1355 "VALUE=DATE:")
1213 (if endtimestring endisostring endisostring+1) 1356 (if endtimestring endisostring endisostring+1)
1214 (or endtimestring "") 1357 (or endtimestring "")
1215 "\nSUMMARY:" summary 1358 "\nRRULE:FREQ=DAILY;INTERVAL=" frequency
1216 "\nRRULE:FREQ=DAILY;INTERVAL=" frequency 1359 ;; strange: korganizer does not expect
1217 ;; strange: korganizer does not expect 1360 ;; BYSOMETHING here...
1218 ;; BYSOMETHING here... 1361 )
1219 )) 1362 summary))
1220 ;; no match 1363 ;; no match
1221 nil)) 1364 nil))
1222 1365
1223(defun icalendar--convert-anniversary-to-ical (nonmarker entry-main) 1366(defun icalendar--convert-anniversary-to-ical (nonmarker entry-main)
1224 "Convert `diary-anniversary' diary entry to icalendar format. 1367 "Convert `diary-anniversary' diary entry to icalendar format.
1225
1226NONMARKER is a regular expression matching the start of non-marking 1368NONMARKER is a regular expression matching the start of non-marking
1227entries. ENTRY-MAIN is the first line of the diary entry." 1369entries. ENTRY-MAIN is the first line of the diary entry."
1228 (if (string-match (concat nonmarker 1370 (if (string-match (concat nonmarker
@@ -1231,7 +1373,7 @@ entries. ENTRY-MAIN is the first line of the diary entry."
1231 "\\(" 1373 "\\("
1232 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" 1374 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?"
1233 "\\)?" 1375 "\\)?"
1234 "\\s-*\\(.*\\)") 1376 "\\s-*\\(.*?\\) ?$")
1235 entry-main) 1377 entry-main)
1236 (let* ((datetime (substring entry-main (match-beginning 1) 1378 (let* ((datetime (substring entry-main (match-beginning 1)
1237 (match-end 1))) 1379 (match-end 1)))
@@ -1272,26 +1414,26 @@ entries. ENTRY-MAIN is the first line of the diary entry."
1272 starttimestring)))) 1414 starttimestring))))
1273 (setq endtimestring (format "T%06d" 1415 (setq endtimestring (format "T%06d"
1274 (+ 10000 time)))))) 1416 (+ 10000 time))))))
1275 (concat "\nDTSTART;" 1417 (list (concat "\nDTSTART;"
1276 (if starttimestring "VALUE=DATE-TIME:" 1418 (if starttimestring "VALUE=DATE-TIME:"
1277 "VALUE=DATE:") 1419 "VALUE=DATE:")
1278 startisostring 1420 startisostring
1279 (or starttimestring "") 1421 (or starttimestring "")
1280 "\nDTEND;" 1422 "\nDTEND;"
1281 (if endtimestring "VALUE=DATE-TIME:" 1423 (if endtimestring "VALUE=DATE-TIME:"
1282 "VALUE=DATE:") 1424 "VALUE=DATE:")
1283 endisostring 1425 endisostring
1284 (or endtimestring "") 1426 (or endtimestring "")
1285 "\nSUMMARY:" summary 1427 "\nRRULE:FREQ=YEARLY;INTERVAL=1"
1286 "\nRRULE:FREQ=YEARLY;INTERVAL=1" 1428 ;; the following is redundant,
1287 ;; the following is redundant, 1429 ;; but korganizer seems to expect this... ;(
1288 ;; but korganizer seems to expect this... ;( 1430 ;; and evolution doesn't understand it... :(
1289 ;; and evolution doesn't understand it... :( 1431 ;; so... who is wrong?!
1290 ;; so... who is wrong?! 1432 ";BYMONTH="
1291 ";BYMONTH=" 1433 (substring startisostring 4 6)
1292 (substring startisostring 4 6) 1434 ";BYMONTHDAY="
1293 ";BYMONTHDAY=" 1435 (substring startisostring 6 8))
1294 (substring startisostring 6 8))) 1436 summary))
1295 ;; no match 1437 ;; no match
1296 nil)) 1438 nil))
1297 1439
@@ -1302,7 +1444,7 @@ entries. ENTRY-MAIN is the first line of the diary entry."
1302;;;###autoload 1444;;;###autoload
1303(defun icalendar-import-file (ical-filename diary-filename 1445(defun icalendar-import-file (ical-filename diary-filename
1304 &optional non-marking) 1446 &optional non-marking)
1305 "Import a iCalendar file and append to a diary file. 1447 "Import an iCalendar file and append to a diary file.
1306Argument ICAL-FILENAME output iCalendar file. 1448Argument ICAL-FILENAME output iCalendar file.
1307Argument DIARY-FILENAME input `diary-file'. 1449Argument DIARY-FILENAME input `diary-file'.
1308Optional argument NON-MARKING determines whether events are created as 1450Optional argument NON-MARKING determines whether events are created as
@@ -1376,10 +1518,13 @@ buffer `*icalendar-errors*'."
1376 "Create a string representation of an iCalendar EVENT." 1518 "Create a string representation of an iCalendar EVENT."
1377 (let ((string icalendar-import-format) 1519 (let ((string icalendar-import-format)
1378 (conversion-list 1520 (conversion-list
1379 '(("%d" DESCRIPTION icalendar-import-format-description) 1521 '(("%c" CLASS icalendar-import-format-class)
1380 ("%s" SUMMARY icalendar-import-format-subject) 1522 ("%d" DESCRIPTION icalendar-import-format-description)
1381 ("%l" LOCATION icalendar-import-format-location) 1523 ("%l" LOCATION icalendar-import-format-location)
1382 ("%o" ORGANIZER icalendar-import-format-organizer)))) 1524 ("%o" ORGANIZER icalendar-import-format-organizer)
1525 ("%s" SUMMARY icalendar-import-format-summary)
1526 ("%t" STATUS icalendar-import-format-status)
1527 ("%u" URL icalendar-import-format-url))))
1383 ;; convert the specifiers in the format string 1528 ;; convert the specifiers in the format string
1384 (mapcar (lambda (i) 1529 (mapcar (lambda (i)
1385 (let* ((spec (car i)) 1530 (let* ((spec (car i))
@@ -1392,17 +1537,19 @@ buffer `*icalendar-errors*'."
1392 (icalendar--rris "%s" 1537 (icalendar--rris "%s"
1393 (icalendar--convert-string-for-import 1538 (icalendar--convert-string-for-import
1394 contents) 1539 contents)
1395 (symbol-value format)))) 1540 (symbol-value format)
1541 t t)))
1396 (setq string (icalendar--rris spec 1542 (setq string (icalendar--rris spec
1397 formatted-contents 1543 formatted-contents
1398 string)))) 1544 string
1545 t t))))
1399 conversion-list) 1546 conversion-list)
1400 string)) 1547 string))
1401 1548
1402(defun icalendar--convert-ical-to-diary (ical-list diary-file 1549(defun icalendar--convert-ical-to-diary (ical-list diary-file
1403 &optional do-not-ask 1550 &optional do-not-ask
1404 non-marking) 1551 non-marking)
1405 "Convert an iCalendar file to an Emacs diary file. 1552 "Convert Calendar data to an Emacs diary file.
1406Import VEVENTS from the iCalendar object ICAL-LIST and saves them to a 1553Import VEVENTS from the iCalendar object ICAL-LIST and saves them to a
1407DIARY-FILE. If DO-NOT-ASK is nil the user is asked for each event 1554DIARY-FILE. If DO-NOT-ASK is nil the user is asked for each event
1408whether to actually import it. NON-MARKING determines whether diary 1555whether to actually import it. NON-MARKING determines whether diary
@@ -1432,13 +1579,13 @@ written into the buffer `*icalendar-errors*'."
1432 end-d 1579 end-d
1433 end-1-d 1580 end-1-d
1434 end-t 1581 end-t
1435 (subject (icalendar--convert-string-for-import 1582 (summary (icalendar--convert-string-for-import
1436 (or (icalendar--get-event-property e 'SUMMARY) 1583 (or (icalendar--get-event-property e 'SUMMARY)
1437 "No Subject"))) 1584 "No summary")))
1438 (rrule (icalendar--get-event-property e 'RRULE)) 1585 (rrule (icalendar--get-event-property e 'RRULE))
1439 (rdate (icalendar--get-event-property e 'RDATE)) 1586 (rdate (icalendar--get-event-property e 'RDATE))
1440 (duration (icalendar--get-event-property e 'DURATION))) 1587 (duration (icalendar--get-event-property e 'DURATION)))
1441 (icalendar--dmsg "%s: `%s'" start-d subject) 1588 (icalendar--dmsg "%s: `%s'" start-d summary)
1442 ;; check whether start-time is missing 1589 ;; check whether start-time is missing
1443 (if (and dtstart 1590 (if (and dtstart
1444 (string= 1591 (string=
@@ -1456,7 +1603,7 @@ written into the buffer `*icalendar-errors*'."
1456 t)))) 1603 t))))
1457 (if (and dtend-dec (not (eq dtend-dec dtend-dec-d))) 1604 (if (and dtend-dec (not (eq dtend-dec dtend-dec-d)))
1458 (message "Inconsistent endtime and duration for %s" 1605 (message "Inconsistent endtime and duration for %s"
1459 subject)) 1606 summary))
1460 (setq dtend-dec dtend-dec-d) 1607 (setq dtend-dec dtend-dec-d)
1461 (setq dtend-1-dec dtend-1-dec-d))) 1608 (setq dtend-1-dec dtend-1-dec-d)))
1462 (setq end-d (if dtend-dec 1609 (setq end-d (if dtend-dec
@@ -1517,9 +1664,9 @@ written into the buffer `*icalendar-errors*'."
1517 (setq diary-string 1664 (setq diary-string
1518 (concat diary-string " " 1665 (concat diary-string " "
1519 (icalendar--format-ical-event e))) 1666 (icalendar--format-ical-event e)))
1520 (if do-not-ask (setq subject nil)) 1667 (if do-not-ask (setq summary nil))
1521 (icalendar--add-diary-entry diary-string diary-file 1668 (icalendar--add-diary-entry diary-string diary-file
1522 non-marking subject)) 1669 non-marking summary))
1523 ;; event was not ok 1670 ;; event was not ok
1524 (setq found-error t) 1671 (setq found-error t)
1525 (setq error-string 1672 (setq error-string
@@ -1570,7 +1717,7 @@ END-T is the event's end time in diary format."
1570 (let ((until-1 0)) 1717 (let ((until-1 0))
1571 (cond ((string-equal frequency "DAILY") 1718 (cond ((string-equal frequency "DAILY")
1572 (setq until (icalendar--add-decoded-times 1719 (setq until (icalendar--add-decoded-times
1573 dtstart-dec 1720 dtstart-dec
1574 (list 0 0 0 (* (read count) interval) 0 0))) 1721 (list 0 0 0 (* (read count) interval) 0 0)))
1575 (setq until-1 (icalendar--add-decoded-times 1722 (setq until-1 (icalendar--add-decoded-times
1576 dtstart-dec 1723 dtstart-dec
@@ -1767,23 +1914,24 @@ END-T is the event's end time in diary format."
1767 start-t)))) 1914 start-t))))
1768 1915
1769(defun icalendar--add-diary-entry (string diary-file non-marking 1916(defun icalendar--add-diary-entry (string diary-file non-marking
1770 &optional subject) 1917 &optional summary)
1771 "Add STRING to the diary file DIARY-FILE. 1918 "Add STRING to the diary file DIARY-FILE.
1772STRING must be a properly formatted valid diary entry. NON-MARKING 1919STRING must be a properly formatted valid diary entry. NON-MARKING
1773determines whether diary events are created as non-marking. If 1920determines whether diary events are created as non-marking. If
1774SUBJECT is not nil it must be a string that gives the subject of the 1921SUMMARY is not nil it must be a string that gives the summary of the
1775entry. In this case the user will be asked whether he wants to insert 1922entry. In this case the user will be asked whether he wants to insert
1776the entry." 1923the entry."
1777 (when (or (not subject) 1924 (when (or (not summary)
1778 (y-or-n-p (format "Add appointment for `%s' to diary? " 1925 (y-or-n-p (format "Add appointment for `%s' to diary? "
1779 subject))) 1926 summary)))
1780 (when subject 1927 (when summary
1781 (setq non-marking 1928 (setq non-marking
1782 (y-or-n-p (format "Make appointment non-marking? ")))) 1929 (y-or-n-p (format "Make appointment non-marking? "))))
1783 (save-window-excursion 1930 (save-window-excursion
1784 (unless diary-file 1931 (unless diary-file
1785 (setq diary-file 1932 (setq diary-file
1786 (read-file-name "Add appointment to this diary file: "))) 1933 (read-file-name "Add appointment to this diary file: ")))
1934 ;; Note: make-diary-entry will add a trailing blank char.... :(
1787 (make-diary-entry string non-marking diary-file)))) 1935 (make-diary-entry string non-marking diary-file))))
1788 1936
1789(provide 'icalendar) 1937(provide 'icalendar)