Mercurial > emacs
comparison lisp/calendar/icalendar.el @ 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 | a65f8ec418fc |
children | 8daf7d9a0771 |
comparison
equal
deleted
inserted
replaced
66373:a0e9e787944e | 66374:88fc54347c68 |
---|---|
95 ;; + Which chars to (un)escape? | 95 ;; + Which chars to (un)escape? |
96 | 96 |
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 ;; ====================================================================== |
104 ;; Customizables | 104 ;; Customizables |
105 ;; ====================================================================== | 105 ;; ====================================================================== |
111 (defcustom icalendar-import-format | 111 (defcustom icalendar-import-format |
112 "%s%d%l%o" | 112 "%s%d%l%o" |
113 "Format string for importing events from iCalendar into Emacs diary. | 113 "Format string for importing events from iCalendar into Emacs diary. |
114 This string defines how iCalendar events are inserted into diary | 114 This string defines how iCalendar events are inserted into diary |
115 file. Meaning of the specifiers: | 115 file. 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. |
126 This applies only if the subject is not empty! `%s' is replaced | 129 This applies only if the summary is not empty! `%s' is replaced |
127 by the subject." | 130 by the summary." |
128 :type 'string | 131 :type 'string |
129 :group 'icalendar) | 132 :group 'icalendar) |
130 | 133 |
131 (defcustom icalendar-import-format-description | 134 (defcustom icalendar-import-format-description |
132 "\n Desc: %s" | 135 "\n Desc: %s" |
147 (defcustom icalendar-import-format-organizer | 150 (defcustom icalendar-import-format-organizer |
148 "\n Organizer: %s" | 151 "\n Organizer: %s" |
149 "Format string defining how the organizer element is formatted. | 152 "Format string defining how the organizer element is formatted. |
150 This applies only if the organizer is not empty! `%s' is | 153 This applies only if the organizer is not empty! `%s' is |
151 replaced by the organizer." | 154 replaced by the organizer." |
155 :type 'string | |
156 :group 'icalendar) | |
157 | |
158 (defcustom icalendar-import-format-url | |
159 "\n URL: %s" | |
160 "Format string defining how the URL element is formatted. | |
161 This applies only if the URL is not empty! `%s' is replaced by | |
162 the 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. | |
169 This applies only if the status is not empty! `%s' is replaced by | |
170 the 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. | |
177 This applies only if the class is not empty! `%s' is replaced by | |
178 the class." | |
152 :type 'string | 179 :type 'string |
153 :group 'icalendar) | 180 :group 'icalendar) |
154 | 181 |
155 (defvar icalendar-debug nil | 182 (defvar icalendar-debug nil |
156 "Enable icalendar debug messages.") | 183 "Enable icalendar debug messages.") |
193 (goto-char (point-min)) | 220 (goto-char (point-min)) |
194 (while (re-search-forward "\r?\n[ \t]" nil t) | 221 (while (re-search-forward "\r?\n[ \t]" nil t) |
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. |
200 This is here for compatibility with XEmacs." | 227 Pass 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. |
210 INVALUE gives the current iCalendar element we are reading. | 238 INVALUE gives the current iCalendar element we are reading. |
211 INPARAMS gives the current parameters..... | 239 INPARAMS gives the current parameters..... |
607 (unless european-calendar-style | 635 (unless european-calendar-style |
608 (let ((x month)) | 636 (let ((x month)) |
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 |
621 (substring datestring (match-beginning 2) | 648 (substring datestring (match-beginning 2) |
622 (match-end 2)))) | 649 (match-end 2)))) |
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 |
635 (substring datestring (match-beginning 1) | 661 (substring datestring (match-beginning 1) |
636 (match-end 1)))) | 662 (match-end 1)))) |
702 (let ((result "") | 728 (let ((result "") |
703 (start 0) | 729 (start 0) |
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*")) |
714 (erase-buffer)) | 742 (erase-buffer)) |
715 | 743 |
726 (car (current-time)) | 754 (car (current-time)) |
727 (cadr (current-time)) | 755 (cadr (current-time)) |
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 |
764 (setq found-error t) | 789 (setq found-error t) |
765 (save-current-buffer | 790 (save-current-buffer |
778 (insert "\nPRODID:-//Emacs//NONSGML icalendar.el//EN") | 803 (insert "\nPRODID:-//Emacs//NONSGML icalendar.el//EN") |
779 (insert "\nVERSION:2.0") | 804 (insert "\nVERSION:2.0") |
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. | |
815 NONMARKER is a regular expression matching the start of non-marking | |
816 entries. 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 | |
790 NONMARKER is a regular expression matching the start of non-marking | 929 NONMARKER is a regular expression matching the start of non-marking |
791 entries. ENTRY-MAIN is the first line of the diary entry." | 930 entries. ENTRY-MAIN is the first line of the diary entry." |
792 (if (string-match (concat nonmarker | 931 (if (string-match (concat nonmarker |
793 "\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)\\s-*" | 932 "\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)\\s-*" |
794 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | 933 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" |
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))) |
802 (startisostring (icalendar--datestring-to-isodate | 941 (startisostring (icalendar--datestring-to-isodate |
803 datetime)) | 942 datetime)) |
837 (let ((time | 976 (let ((time |
838 (read (icalendar--rris "^T0?" "" | 977 (read (icalendar--rris "^T0?" "" |
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 | |
862 NONMARKER is a regular expression matching the start of non-marking | 999 NONMARKER is a regular expression matching the start of non-marking |
863 entries. ENTRY-MAIN is the first line of the diary entry." | 1000 entries. ENTRY-MAIN is the first line of the diary entry." |
864 (if (and (string-match (concat nonmarker | 1001 (if (and (string-match (concat nonmarker |
865 "\\([a-z]+\\)\\s-+" | 1002 "\\([a-z]+\\)\\s-+" |
866 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)" | 1003 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)" |
867 "\\([ap]m\\)?" | 1004 "\\([ap]m\\)?" |
868 "\\(-0?" | 1005 "\\(-0?" |
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) |
876 (match-end 1)))) | 1013 (match-end 1)))) |
877 (let* ((day (icalendar--get-weekday-abbrev | 1014 (let* ((day (icalendar--get-weekday-abbrev |
909 (let ((time (read | 1046 (let ((time (read |
910 (icalendar--rris "^T0?" "" | 1047 (icalendar--rris "^T0?" "" |
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 | |
943 NONMARKER is a regular expression matching the start of non-marking | 1079 NONMARKER is a regular expression matching the start of non-marking |
944 entries. ENTRY-MAIN is the first line of the diary entry." | 1080 entries. ENTRY-MAIN is the first line of the diary entry." |
945 (if (string-match (concat nonmarker | 1081 (if (string-match (concat nonmarker |
946 (if european-calendar-style | 1082 (if european-calendar-style |
947 "0?\\([1-9]+[0-9]?\\)\\s-+\\([a-z]+\\)\\s-+" | 1083 "0?\\([1-9]+[0-9]?\\)\\s-+\\([a-z]+\\)\\s-+" |
949 "\\*?\\s-*" | 1085 "\\*?\\s-*" |
950 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | 1086 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" |
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)) |
958 (monpos (if european-calendar-style 2 1)) | 1094 (monpos (if european-calendar-style 2 1)) |
959 (day (read (substring entry-main | 1095 (day (read (substring entry-main |
995 (let ((time (read | 1131 (let ((time (read |
996 (icalendar--rris "^T0?" "" | 1132 (icalendar--rris "^T0?" "" |
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 |
1022 (defun icalendar--convert-sexp-to-ical (nonmarker entry-main) | 1157 (defun icalendar--convert-sexp-to-ical (nonmarker entry-main) |
1023 "Convert complex sexp diary entry to icalendar format -- unsupported! | 1158 "Convert complex sexp diary entry to icalendar format -- unsupported! |
1024 | 1159 |
1025 FIXME! | 1160 FIXME! |
1026 | 1161 |
1027 NONMARKER is a regular expression matching the start of non-marking | 1162 NONMARKER is a regular expression matching the start of non-marking |
1028 entries. ENTRY-MAIN is the first line of the diary entry." | 1163 entries. 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 | |
1041 NONMARKER is a regular expression matching the start of non-marking | 1186 NONMARKER is a regular expression matching the start of non-marking |
1042 entries. ENTRY-MAIN is the first line of the diary entry." | 1187 entries. ENTRY-MAIN is the first line of the diary entry." |
1043 (if (string-match (concat nonmarker | 1188 (if (string-match (concat nonmarker |
1044 "%%(diary-block \\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)" | 1189 "%%(diary-block \\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)" |
1045 " +\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*" | 1190 " +\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*" |
1046 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | 1191 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" |
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) |
1054 (match-end 1))) | 1199 (match-end 1))) |
1055 (endstring (substring entry-main | 1200 (endstring (substring entry-main |
1094 starttimestring)))) | 1239 starttimestring)))) |
1095 (setq endtimestring (format "T%06d" | 1240 (setq endtimestring (format "T%06d" |
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 |
1116 (defun icalendar--convert-float-to-ical (nonmarker entry-main) | 1260 (defun icalendar--convert-float-to-ical (nonmarker entry-main) |
1117 "Convert float diary entry to icalendar format -- unsupported! | 1261 "Convert float diary entry to icalendar format -- unsupported! |
1119 FIXME! | 1263 FIXME! |
1120 | 1264 |
1121 NONMARKER is a regular expression matching the start of non-marking | 1265 NONMARKER is a regular expression matching the start of non-marking |
1122 entries. ENTRY-MAIN is the first line of the diary entry." | 1266 entries. 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) |
1128 (error "`diary-float' is not supported yet")) | 1272 (error "`diary-float' is not supported yet")) |
1129 ;; no match | 1273 ;; no match |
1135 FIXME! | 1279 FIXME! |
1136 | 1280 |
1137 NONMARKER is a regular expression matching the start of non-marking | 1281 NONMARKER is a regular expression matching the start of non-marking |
1138 entries. ENTRY-MAIN is the first line of the diary entry." | 1282 entries. 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) |
1144 (error "`diary-date' is not supported yet")) | 1288 (error "`diary-date' is not supported yet")) |
1145 ;; no match | 1289 ;; no match |
1146 nil)) | 1290 nil)) |
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 | |
1151 NONMARKER is a regular expression matching the start of non-marking | 1294 NONMARKER is a regular expression matching the start of non-marking |
1152 entries. ENTRY-MAIN is the first line of the diary entry." | 1295 entries. ENTRY-MAIN is the first line of the diary entry." |
1153 (if (string-match (concat nonmarker | 1296 (if (string-match (concat nonmarker |
1154 "%%(diary-cyclic \\([^ ]+\\) +" | 1297 "%%(diary-cyclic \\([^ ]+\\) +" |
1155 "\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*" | 1298 "\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*" |
1156 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | 1299 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" |
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))) |
1164 (datetime (substring entry-main (match-beginning 2) | 1307 (datetime (substring entry-main (match-beginning 2) |
1165 (match-end 2))) | 1308 (match-end 2))) |
1200 (let ((time | 1343 (let ((time |
1201 (read (icalendar--rris "^T0?" "" | 1344 (read (icalendar--rris "^T0?" "" |
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 | |
1226 NONMARKER is a regular expression matching the start of non-marking | 1368 NONMARKER is a regular expression matching the start of non-marking |
1227 entries. ENTRY-MAIN is the first line of the diary entry." | 1369 entries. ENTRY-MAIN is the first line of the diary entry." |
1228 (if (string-match (concat nonmarker | 1370 (if (string-match (concat nonmarker |
1229 "%%(diary-anniversary \\([^)]+\\))\\s-*" | 1371 "%%(diary-anniversary \\([^)]+\\))\\s-*" |
1230 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | 1372 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" |
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))) |
1238 (startisostring (icalendar--datestring-to-isodate | 1380 (startisostring (icalendar--datestring-to-isodate |
1239 datetime)) | 1381 datetime)) |
1270 (let ((time | 1412 (let ((time |
1271 (read (icalendar--rris "^T0?" "" | 1413 (read (icalendar--rris "^T0?" "" |
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 |
1298 ;; ====================================================================== | 1440 ;; ====================================================================== |
1299 ;; Import -- convert icalendar to emacs-diary | 1441 ;; Import -- convert icalendar to emacs-diary |
1300 ;; ====================================================================== | 1442 ;; ====================================================================== |
1301 | 1443 |
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. |
1306 Argument ICAL-FILENAME output iCalendar file. | 1448 Argument ICAL-FILENAME output iCalendar file. |
1307 Argument DIARY-FILENAME input `diary-file'. | 1449 Argument DIARY-FILENAME input `diary-file'. |
1308 Optional argument NON-MARKING determines whether events are created as | 1450 Optional argument NON-MARKING determines whether events are created as |
1309 non-marking or not." | 1451 non-marking or not." |
1310 (interactive "fImport iCalendar data from file: | 1452 (interactive "fImport iCalendar data from file: |
1374 | 1516 |
1375 (defun icalendar--format-ical-event (event) | 1517 (defun icalendar--format-ical-event (event) |
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)) |
1386 (prop (cadr i)) | 1531 (prop (cadr i)) |
1387 (format (car (cddr i))) | 1532 (format (car (cddr i))) |
1390 (when (and contents (> (length contents) 0)) | 1535 (when (and contents (> (length contents) 0)) |
1391 (setq formatted-contents | 1536 (setq formatted-contents |
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. |
1406 Import VEVENTS from the iCalendar object ICAL-LIST and saves them to a | 1553 Import VEVENTS from the iCalendar object ICAL-LIST and saves them to a |
1407 DIARY-FILE. If DO-NOT-ASK is nil the user is asked for each event | 1554 DIARY-FILE. If DO-NOT-ASK is nil the user is asked for each event |
1408 whether to actually import it. NON-MARKING determines whether diary | 1555 whether to actually import it. NON-MARKING determines whether diary |
1409 events are created as non-marking. | 1556 events are created as non-marking. |
1410 This function attempts to return t if something goes wrong. In this | 1557 This function attempts to return t if something goes wrong. In this |
1430 (dtend-dec (icalendar--decode-isodatetime dtend)) | 1577 (dtend-dec (icalendar--decode-isodatetime dtend)) |
1431 (dtend-1-dec (icalendar--decode-isodatetime dtend -1)) | 1578 (dtend-1-dec (icalendar--decode-isodatetime dtend -1)) |
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= |
1445 (cadr (icalendar--get-event-property-attributes | 1592 (cadr (icalendar--get-event-property-attributes |
1446 e 'DTSTART)) | 1593 e 'DTSTART)) |
1454 dtstart-dec | 1601 dtstart-dec |
1455 (icalendar--decode-isoduration duration | 1602 (icalendar--decode-isoduration duration |
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 |
1463 (icalendar--datetime-to-diary-date dtend-dec) | 1610 (icalendar--datetime-to-diary-date dtend-dec) |
1464 start-d)) | 1611 start-d)) |
1515 (if event-ok | 1662 (if event-ok |
1516 (progn | 1663 (progn |
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 |
1526 (format "%s\nCannot handle this event:%s" | 1673 (format "%s\nCannot handle this event:%s" |
1527 error-string e)))) | 1674 error-string e)))) |
1568 (if until | 1715 (if until |
1569 (message "Must not have UNTIL and COUNT -- ignoring COUNT element!") | 1716 (message "Must not have UNTIL and COUNT -- ignoring COUNT element!") |
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 |
1577 (list 0 0 0 (* (- (read count) 1) interval) | 1724 (list 0 0 0 (* (- (read count) 1) interval) |
1578 0 0))) | 1725 0 0))) |
1765 (icalendar--datetime-to-diary-date | 1912 (icalendar--datetime-to-diary-date |
1766 dtstart-dec "/") | 1913 dtstart-dec "/") |
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. |
1772 STRING must be a properly formatted valid diary entry. NON-MARKING | 1919 STRING must be a properly formatted valid diary entry. NON-MARKING |
1773 determines whether diary events are created as non-marking. If | 1920 determines whether diary events are created as non-marking. If |
1774 SUBJECT is not nil it must be a string that gives the subject of the | 1921 SUMMARY is not nil it must be a string that gives the summary of the |
1775 entry. In this case the user will be asked whether he wants to insert | 1922 entry. In this case the user will be asked whether he wants to insert |
1776 the entry." | 1923 the 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) |
1790 | 1938 |
1791 ;; arch-tag: 74fdbe8e-0451-4e38-bb61-4416e822f4fc | 1939 ;; arch-tag: 74fdbe8e-0451-4e38-bb61-4416e822f4fc |