Mercurial > emacs
comparison lisp/calendar/icalendar.el @ 62053:57aabea77432
From Ulf Jasper <ulf.jasper@web.de>:
(icalendar-version): Now at 0.12.
(icalendar-duration-correction): Remove.
(icalendar--get-event-properties): Split result at commas.
(icalendar--decode-isoduration): New optional argument
DURATION-CORRECTION.
(icalendar--convert-ordinary-to-ical)
(icalendar--convert-weekly-to-ical)
(icalendar--convert-yearly-to-ical)
(icalendar--convert-sexp-to-ical)
(icalendar--convert-block-to-ical)
(icalendar--convert-float-to-ical)
(icalendar--convert-date-to-ical)
(icalendar--convert-cyclic-to-ical)
(icalendar--convert-anniversary-to-ical): New functions, extracted
from icalendar-export-region, with bug fixes.
(icalendar-export-region): Use the above functions.
(icalendar-import-buffer): Check before saving diary file.
(icalendar--convert-recurring-to-diary)
(icalendar--convert-non-recurring-all-day-to-diary)
(icalendar--convert-non-recurring-not-all-day-to-diary): New
functions, extracted from icalendar--convert-ical-to-diary, with
bug fixes.
(icalendar--convert-ical-to-diary): Use the above functions.
author | Glenn Morris <rgm@gnu.org> |
---|---|
date | Tue, 03 May 2005 16:35:27 +0000 |
parents | 87759c244379 |
children | 6812f1044f86 |
comparison
equal
deleted
inserted
replaced
62052:fa7d4d214722 | 62053:57aabea77432 |
---|---|
26 | 26 |
27 ;;; Commentary: | 27 ;;; Commentary: |
28 | 28 |
29 ;; This package is documented in the Emacs Manual. | 29 ;; This package is documented in the Emacs Manual. |
30 | 30 |
31 ;; Please note: | |
32 ;; - Diary entries which have a start time but no end time are assumed to | |
33 ;; last for one hour when they are exported. | |
34 ;; - Weekly diary entries are assumed to occur the first time in the first | |
35 ;; week of the year 2000 when they are exported. | |
36 ;; - Yearly diary entries are assumed to occur the first time in the year | |
37 ;; 1900 when they are exported. | |
31 | 38 |
32 ;;; History: | 39 ;;; History: |
33 | 40 |
34 ;; 0.07 onwards: see lisp/ChangeLog | 41 ;; 0.07 onwards: see lisp/ChangeLog |
35 | 42 |
73 ;; + alarm | 80 ;; + alarm |
74 ;; + exceptions in recurring events | 81 ;; + exceptions in recurring events |
75 ;; + the parser is too soft | 82 ;; + the parser is too soft |
76 ;; + error log is incomplete | 83 ;; + error log is incomplete |
77 ;; + nice to have: #include "webcal://foo.com/some-calendar.ics" | 84 ;; + nice to have: #include "webcal://foo.com/some-calendar.ics" |
85 ;; + timezones, currently all times are local! | |
78 | 86 |
79 ;; * Export from diary to ical | 87 ;; * Export from diary to ical |
80 ;; + diary-date, diary-float, and self-made sexp entries are not | 88 ;; + diary-date, diary-float, and self-made sexp entries are not |
81 ;; understood | 89 ;; understood |
82 ;; + timezones, currently all times are local! | |
83 | 90 |
84 ;; * Other things | 91 ;; * Other things |
85 ;; + clean up all those date/time parsing functions | 92 ;; + clean up all those date/time parsing functions |
86 ;; + Handle todo items? | 93 ;; + Handle todo items? |
87 ;; + Check iso 8601 for datetime and period | 94 ;; + Check iso 8601 for datetime and period |
88 ;; + Which chars to (un)escape? | 95 ;; + Which chars to (un)escape? |
89 | 96 |
90 | 97 |
91 ;;; Code: | 98 ;;; Code: |
92 | 99 |
93 (defconst icalendar-version 0.11 | 100 (defconst icalendar-version 0.12 |
94 "Version number of icalendar.el.") | 101 "Version number of icalendar.el.") |
95 | 102 |
96 ;; ====================================================================== | 103 ;; ====================================================================== |
97 ;; Customizables | 104 ;; Customizables |
98 ;; ====================================================================== | 105 ;; ====================================================================== |
143 This applies only if the organizer is not empty! `%s' is | 150 This applies only if the organizer is not empty! `%s' is |
144 replaced by the organizer." | 151 replaced by the organizer." |
145 :type 'string | 152 :type 'string |
146 :group 'icalendar) | 153 :group 'icalendar) |
147 | 154 |
148 (defcustom icalendar-duration-correction | 155 (defvar icalendar-debug nil |
149 t | 156 "Enable icalendar debug messages.") |
150 "Workaround for all-day events. | |
151 If non-nil the length=duration of iCalendar appointments that | |
152 have a length of exactly n days is decreased by one day. This | |
153 fixes problems with all-day events, which appear to be one day | |
154 longer than they are." | |
155 :type 'boolean | |
156 :group 'icalendar) | |
157 | |
158 | 157 |
159 ;; ====================================================================== | 158 ;; ====================================================================== |
160 ;; NO USER SERVICABLE PARTS BELOW THIS LINE | 159 ;; NO USER SERVICABLE PARTS BELOW THIS LINE |
161 ;; ====================================================================== | 160 ;; ====================================================================== |
162 | 161 |
163 (defconst icalendar--weekday-array ["SU" "MO" "TU" "WE" "TH" "FR" "SA"]) | 162 (defconst icalendar--weekday-array ["SU" "MO" "TU" "WE" "TH" "FR" "SA"]) |
164 | |
165 (defvar icalendar-debug nil ".") | |
166 | 163 |
167 ;; ====================================================================== | 164 ;; ====================================================================== |
168 ;; all the other libs we need | 165 ;; all the other libs we need |
169 ;; ====================================================================== | 166 ;; ====================================================================== |
170 (require 'calendar) | 167 (require 'calendar) |
293 "For the given EVENT return a list of all values of the property PROP." | 290 "For the given EVENT return a list of all values of the property PROP." |
294 (let ((props (car (cddr event))) pp result) | 291 (let ((props (car (cddr event))) pp result) |
295 (while props | 292 (while props |
296 (setq pp (car props)) | 293 (setq pp (car props)) |
297 (if (eq (car pp) prop) | 294 (if (eq (car pp) prop) |
298 (setq result (cons (car (cddr pp)) result))) | 295 (setq result (append (split-string (car (cddr pp)) ",") result))) |
299 (setq props (cdr props))) | 296 (setq props (cdr props))) |
300 result)) | 297 result)) |
301 | 298 |
302 ;; (defun icalendar--set-event-property (event prop new-value) | 299 ;; (defun icalendar--set-event-property (event prop new-value) |
303 ;; "For the given EVENT set the property PROP to the value NEW-VALUE." | 300 ;; "For the given EVENT set the property PROP to the value NEW-VALUE." |
409 ;; hope for the best... | 406 ;; hope for the best... |
410 (list second minute hour day month year 0 nil 0)))) | 407 (list second minute hour day month year 0 nil 0)))) |
411 ;; isodatetimestring == nil | 408 ;; isodatetimestring == nil |
412 nil)) | 409 nil)) |
413 | 410 |
414 (defun icalendar--decode-isoduration (isodurationstring) | 411 (defun icalendar--decode-isoduration (isodurationstring |
415 "Return ISODURATIONSTRING in format like `decode-time'. | 412 &optional duration-correction) |
413 "Convert ISODURATIONSTRING into format provided by `decode-time'. | |
416 Converts from ISO-8601 to Emacs representation. If ISODURATIONSTRING | 414 Converts from ISO-8601 to Emacs representation. If ISODURATIONSTRING |
417 specifies UTC time (trailing letter Z) the decoded time is given in | 415 specifies UTC time (trailing letter Z) the decoded time is given in |
418 the local time zone! | 416 the local time zone! |
417 | |
418 Optional argument DURATION-CORRECTION shortens result by one day. | |
419 | 419 |
420 FIXME: TZID-attributes are ignored....! | 420 FIXME: TZID-attributes are ignored....! |
421 FIXME: multiple comma-separated values should be allowed!" | 421 FIXME: multiple comma-separated values should be allowed!" |
422 (if isodurationstring | 422 (if isodurationstring |
423 (save-match-data | 423 (save-match-data |
440 (cond | 440 (cond |
441 ((match-beginning 2) ;days only | 441 ((match-beginning 2) ;days only |
442 (setq days (read (substring isodurationstring | 442 (setq days (read (substring isodurationstring |
443 (match-beginning 3) | 443 (match-beginning 3) |
444 (match-end 3)))) | 444 (match-end 3)))) |
445 (when icalendar-duration-correction | 445 (when duration-correction |
446 (setq days (1- days)))) | 446 (setq days (1- days)))) |
447 ((match-beginning 4) ;days and time | 447 ((match-beginning 4) ;days and time |
448 (if (match-beginning 5) | 448 (if (match-beginning 5) |
449 (setq days (* 7 (read (substring isodurationstring | 449 (setq days (* 7 (read (substring isodurationstring |
450 (match-beginning 6) | 450 (match-beginning 6) |
708 (found-error nil) | 708 (found-error nil) |
709 (nonmarker (concat "^" (regexp-quote diary-nonmarking-symbol) | 709 (nonmarker (concat "^" (regexp-quote diary-nonmarking-symbol) |
710 "?"))) | 710 "?"))) |
711 ;; prepare buffer with error messages | 711 ;; prepare buffer with error messages |
712 (save-current-buffer | 712 (save-current-buffer |
713 (set-buffer (get-buffer-create " *icalendar-errors*")) | 713 (set-buffer (get-buffer-create "*icalendar-errors*")) |
714 (erase-buffer)) | 714 (erase-buffer)) |
715 | 715 |
716 ;; here we go | 716 ;; here we go |
717 (save-excursion | 717 (save-excursion |
718 (goto-char min) | 718 (goto-char min) |
719 (while (re-search-forward | 719 (while (re-search-forward |
720 "^\\([^ \t\n].*\\)\\(\\(\n[ \t].*\\)*\\)" max t) | 720 "^\\([^ \t\n].+\\)\\(\\(\n[ \t].*\\)*\\)" max t) |
721 (setq entry-main (match-string 1)) | 721 (setq entry-main (match-string 1)) |
722 (if (match-beginning 2) | 722 (if (match-beginning 2) |
723 (setq entry-rest (match-string 2)) | 723 (setq entry-rest (match-string 2)) |
724 (setq entry-rest "")) | 724 (setq entry-rest "")) |
725 (setq header (format "\nBEGIN:VEVENT\nUID:emacs%d%d%d" | 725 (setq header (format "\nBEGIN:VEVENT\nUID:emacs%d%d%d" |
726 (car (current-time)) | 726 (car (current-time)) |
727 (cadr (current-time)) | 727 (cadr (current-time)) |
728 (car (cddr (current-time))))) | 728 (car (cddr (current-time))))) |
729 (condition-case error-val | 729 (condition-case error-val |
730 (progn | 730 (progn |
731 (cond | 731 (setq contents |
732 ;; anniversaries | 732 (or |
733 ((string-match | 733 ;; anniversaries -- %%(diary-anniversary ...) |
734 (concat nonmarker | 734 (icalendar--convert-anniversary-to-ical nonmarker |
735 "%%(diary-anniversary \\([^)]+\\))\\s-*\\(.*\\)") | 735 entry-main) |
736 entry-main) | 736 ;; cyclic events -- %%(diary-cyclic ...) |
737 (icalendar--dmsg "diary-anniversary %s" entry-main) | 737 (icalendar--convert-cyclic-to-ical nonmarker entry-main) |
738 (let* ((datetime (substring entry-main (match-beginning 1) | 738 ;; diary-date -- %%(diary-date ...) |
739 (match-end 1))) | 739 (icalendar--convert-date-to-ical nonmarker entry-main) |
740 (summary (icalendar--convert-string-for-export | 740 ;; float events -- %%(diary-float ...) |
741 (substring entry-main (match-beginning 2) | 741 (icalendar--convert-float-to-ical nonmarker entry-main) |
742 (match-end 2)))) | 742 ;; block events -- %%(diary-block ...) |
743 (startisostring (icalendar--datestring-to-isodate | 743 (icalendar--convert-block-to-ical nonmarker entry-main) |
744 datetime)) | 744 ;; other sexp diary entries |
745 (endisostring (icalendar--datestring-to-isodate | 745 (icalendar--convert-sexp-to-ical nonmarker entry-main) |
746 datetime 1))) | 746 ;; weekly by day -- Monday 8:30 Team meeting |
747 (setq contents | 747 (icalendar--convert-weekly-to-ical nonmarker entry-main) |
748 (concat "\nDTSTART;VALUE=DATE:" startisostring | 748 ;; yearly by day -- 1 May Tag der Arbeit |
749 "\nDTEND;VALUE=DATE:" endisostring | 749 (icalendar--convert-yearly-to-ical nonmarker entry-main) |
750 "\nSUMMARY:" summary | 750 ;; "ordinary" events, start and end time given |
751 "\nRRULE:FREQ=YEARLY;INTERVAL=1" | 751 ;; 1 Feb 2003 blah |
752 ;; the following is redundant, | 752 (icalendar--convert-ordinary-to-ical nonmarker entry-main) |
753 ;; but korganizer seems to expect this... ;( | 753 ;; everything else |
754 ;; and evolution doesn't understand it... :( | 754 ;; Oops! what's that? |
755 ;; so... who is wrong?! | 755 (error "Could not parse entry"))) |
756 ";BYMONTH=" | 756 (unless (string= entry-rest "") |
757 (substring startisostring 4 6) | 757 (setq contents |
758 ";BYMONTHDAY=" | 758 (concat contents "\nDESCRIPTION:" |
759 (substring startisostring 6 8)))) | 759 (icalendar--convert-string-for-export |
760 (unless (string= entry-rest "") | 760 entry-rest)))) |
761 (setq contents | |
762 (concat contents "\nDESCRIPTION:" | |
763 (icalendar--convert-string-for-export | |
764 entry-rest))))) | |
765 ;; cyclic events | |
766 ;; %%(diary-cyclic ) | |
767 ((string-match | |
768 (concat nonmarker | |
769 "%%(diary-cyclic \\([^ ]+\\) +" | |
770 "\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*\\(.*\\)") | |
771 entry-main) | |
772 (icalendar--dmsg "diary-cyclic %s" entry-main) | |
773 (let* ((frequency (substring entry-main (match-beginning 1) | |
774 (match-end 1))) | |
775 (datetime (substring entry-main (match-beginning 2) | |
776 (match-end 2))) | |
777 (summary (icalendar--convert-string-for-export | |
778 (substring entry-main (match-beginning 3) | |
779 (match-end 3)))) | |
780 (startisostring (icalendar--datestring-to-isodate | |
781 datetime)) | |
782 (endisostring (icalendar--datestring-to-isodate | |
783 datetime 1))) | |
784 (setq contents | |
785 (concat "\nDTSTART;VALUE=DATE:" startisostring | |
786 "\nDTEND;VALUE=DATE:" endisostring | |
787 "\nSUMMARY:" summary | |
788 "\nRRULE:FREQ=DAILY;INTERVAL=" frequency | |
789 ;; strange: korganizer does not expect | |
790 ;; BYSOMETHING here... | |
791 ))) | |
792 (unless (string= entry-rest "") | |
793 (setq contents | |
794 (concat contents "\nDESCRIPTION:" | |
795 (icalendar--convert-string-for-export | |
796 entry-rest))))) | |
797 ;; diary-date -- FIXME | |
798 ((string-match | |
799 (concat nonmarker | |
800 "%%(diary-date \\([^)]+\\))\\s-*\\(.*\\)") | |
801 entry-main) | |
802 (icalendar--dmsg "diary-date %s" entry-main) | |
803 (error "`diary-date' is not supported yet")) | |
804 ;; float events -- FIXME | |
805 ((string-match | |
806 (concat nonmarker | |
807 "%%(diary-float \\([^)]+\\))\\s-*\\(.*\\)") | |
808 entry-main) | |
809 (icalendar--dmsg "diary-float %s" entry-main) | |
810 (error "`diary-float' is not supported yet")) | |
811 ;; block events | |
812 ((string-match | |
813 (concat nonmarker | |
814 "%%(diary-block \\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)" | |
815 " +\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*" | |
816 "\\(.*\\)") | |
817 entry-main) | |
818 (icalendar--dmsg "diary-block %s" entry-main) | |
819 (let* ((startstring (substring entry-main | |
820 (match-beginning 1) | |
821 (match-end 1))) | |
822 (endstring (substring entry-main | |
823 (match-beginning 2) | |
824 (match-end 2))) | |
825 (summary (icalendar--convert-string-for-export | |
826 (substring entry-main (match-beginning 3) | |
827 (match-end 3)))) | |
828 (startisostring (icalendar--datestring-to-isodate | |
829 startstring)) | |
830 (endisostring (icalendar--datestring-to-isodate | |
831 endstring 1))) | |
832 (setq contents | |
833 (concat "\nDTSTART;VALUE=DATE:" startisostring | |
834 "\nDTEND;VALUE=DATE:" endisostring | |
835 "\nSUMMARY:" summary)) | |
836 (unless (string= entry-rest "") | |
837 (setq contents | |
838 (concat contents "\nDESCRIPTION:" | |
839 (icalendar--convert-string-for-export | |
840 entry-rest)))))) | |
841 ;; other sexp diary entries -- FIXME | |
842 ((string-match | |
843 (concat nonmarker | |
844 "%%(\\([^)]+\\))\\s-*\\(.*\\)") | |
845 entry-main) | |
846 (icalendar--dmsg "diary-sexp %s" entry-main) | |
847 (error "sexp-entries are not supported yet")) | |
848 ;; weekly by day | |
849 ;; Monday 8:30 Team meeting | |
850 ((and (string-match | |
851 (concat nonmarker | |
852 "\\([a-z]+\\)\\s-+" | |
853 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)" | |
854 "\\([ap]m\\)?" | |
855 "\\(-0?" | |
856 "\\([1-9][0-9]?:[0-9][0-9]\\)" | |
857 "\\([ap]m\\)?\\)?" | |
858 "\\)?" | |
859 "\\s-*\\(.*\\)$") | |
860 entry-main) | |
861 (icalendar--get-weekday-abbrev | |
862 (substring entry-main (match-beginning 1) | |
863 (match-end 1)))) | |
864 (icalendar--dmsg "weekly %s" entry-main) | |
865 (let* ((day (icalendar--get-weekday-abbrev | |
866 (substring entry-main (match-beginning 1) | |
867 (match-end 1)))) | |
868 (starttimestring (icalendar--diarytime-to-isotime | |
869 (if (match-beginning 3) | |
870 (substring entry-main | |
871 (match-beginning 3) | |
872 (match-end 3)) | |
873 nil) | |
874 (if (match-beginning 4) | |
875 (substring entry-main | |
876 (match-beginning 4) | |
877 (match-end 4)) | |
878 nil))) | |
879 (endtimestring (icalendar--diarytime-to-isotime | |
880 (if (match-beginning 6) | |
881 (substring entry-main | |
882 (match-beginning 6) | |
883 (match-end 6)) | |
884 nil) | |
885 (if (match-beginning 7) | |
886 (substring entry-main | |
887 (match-beginning 7) | |
888 (match-end 7)) | |
889 nil))) | |
890 (summary (icalendar--convert-string-for-export | |
891 (substring entry-main (match-beginning 8) | |
892 (match-end 8))))) | |
893 (when starttimestring | |
894 (unless endtimestring | |
895 (let ((time (read | |
896 (icalendar--rris "^T0?" "" | |
897 starttimestring)))) | |
898 (setq endtimestring (format "T%06d" | |
899 (+ 10000 time)))))) | |
900 (setq contents | |
901 (concat "\nDTSTART;" | |
902 (if starttimestring | |
903 "VALUE=DATE-TIME:" | |
904 "VALUE=DATE:") | |
905 ;; find the correct week day, | |
906 ;; 1st january 2000 was a saturday | |
907 (format | |
908 "200001%02d" | |
909 (+ (icalendar--get-weekday-number day) 2)) | |
910 (or starttimestring "") | |
911 "\nDTEND;" | |
912 (if endtimestring | |
913 "VALUE=DATE-TIME:" | |
914 "VALUE=DATE:") | |
915 (format | |
916 "200001%02d" | |
917 ;; end is non-inclusive! | |
918 (+ (icalendar--get-weekday-number day) | |
919 (if endtimestring 2 3))) | |
920 (or endtimestring "") | |
921 "\nSUMMARY:" summary | |
922 "\nRRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=" | |
923 day))) | |
924 (unless (string= entry-rest "") | |
925 (setq contents | |
926 (concat contents "\nDESCRIPTION:" | |
927 (icalendar--convert-string-for-export | |
928 entry-rest))))) | |
929 ;; yearly by day | |
930 ;; 1 May Tag der Arbeit | |
931 ((string-match | |
932 (concat nonmarker | |
933 (if european-calendar-style | |
934 "0?\\([1-9]+[0-9]?\\)\\s-+\\([a-z]+\\)\\s-+" | |
935 "\\([a-z]+\\)\\s-+0?\\([1-9]+[0-9]?\\)\\s-+") | |
936 "\\*?\\s-*" | |
937 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | |
938 "\\(" | |
939 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" | |
940 "\\)?" | |
941 "\\s-*\\([^0-9]+.*\\)$" ; must not match years | |
942 ) | |
943 entry-main) | |
944 (icalendar--dmsg "yearly %s" entry-main) | |
945 (let* ((daypos (if european-calendar-style 1 2)) | |
946 (monpos (if european-calendar-style 2 1)) | |
947 (day (read (substring entry-main | |
948 (match-beginning daypos) | |
949 (match-end daypos)))) | |
950 (month (icalendar--get-month-number | |
951 (substring entry-main | |
952 (match-beginning monpos) | |
953 (match-end monpos)))) | |
954 (starttimestring (icalendar--diarytime-to-isotime | |
955 (if (match-beginning 4) | |
956 (substring entry-main | |
957 (match-beginning 4) | |
958 (match-end 4)) | |
959 nil) | |
960 (if (match-beginning 5) | |
961 (substring entry-main | |
962 (match-beginning 5) | |
963 (match-end 5)) | |
964 nil))) | |
965 (endtimestring (icalendar--diarytime-to-isotime | |
966 (if (match-beginning 7) | |
967 (substring entry-main | |
968 (match-beginning 7) | |
969 (match-end 7)) | |
970 nil) | |
971 (if (match-beginning 8) | |
972 (substring entry-main | |
973 (match-beginning 8) | |
974 (match-end 8)) | |
975 nil))) | |
976 (summary (icalendar--convert-string-for-export | |
977 (substring entry-main (match-beginning 9) | |
978 (match-end 9))))) | |
979 (when starttimestring | |
980 (unless endtimestring | |
981 (let ((time (read | |
982 (icalendar--rris "^T0?" "" | |
983 starttimestring)))) | |
984 (setq endtimestring (format "T%06d" | |
985 (+ 10000 time)))))) | |
986 (setq contents | |
987 (concat "\nDTSTART;" | |
988 (if starttimestring "VALUE=DATE-TIME:" | |
989 "VALUE=DATE:") | |
990 (format "1900%02d%02d" month day) | |
991 (or starttimestring "") | |
992 "\nDTEND;" | |
993 (if endtimestring "VALUE=DATE-TIME:" | |
994 "VALUE=DATE:") | |
995 ;; end is not included! shift by one day | |
996 (icalendar--date-to-isodate | |
997 (list month day 1900) | |
998 (if endtimestring 0 1)) | |
999 (or endtimestring "") | |
1000 "\nSUMMARY:" | |
1001 summary | |
1002 "\nRRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=" | |
1003 (format "%2d" month) | |
1004 ";BYMONTHDAY=" | |
1005 (format "%2d" day)))) | |
1006 (unless (string= entry-rest "") | |
1007 (setq contents | |
1008 (concat contents "\nDESCRIPTION:" | |
1009 (icalendar--convert-string-for-export | |
1010 entry-rest))))) | |
1011 ;; "ordinary" events, start and end time given | |
1012 ;; 1 Feb 2003 Hs Hochzeitsfeier, Dreieich | |
1013 ((string-match | |
1014 (concat nonmarker | |
1015 "\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)\\s-+" | |
1016 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | |
1017 "\\(" | |
1018 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" | |
1019 "\\)?" | |
1020 "\\s-*\\(.*\\)") | |
1021 entry-main) | |
1022 (icalendar--dmsg "ordinary %s" entry-main) | |
1023 (let* ((startdatestring (icalendar--datestring-to-isodate | |
1024 (substring entry-main | |
1025 (match-beginning 1) | |
1026 (match-end 1)))) | |
1027 (starttimestring (icalendar--diarytime-to-isotime | |
1028 (if (match-beginning 3) | |
1029 (substring entry-main | |
1030 (match-beginning 3) | |
1031 (match-end 3)) | |
1032 nil) | |
1033 (if (match-beginning 4) | |
1034 (substring entry-main | |
1035 (match-beginning 4) | |
1036 (match-end 4)) | |
1037 nil))) | |
1038 (endtimestring (icalendar--diarytime-to-isotime | |
1039 (if (match-beginning 6) | |
1040 (substring entry-main | |
1041 (match-beginning 6) | |
1042 (match-end 6)) | |
1043 nil) | |
1044 (if (match-beginning 7) | |
1045 (substring entry-main | |
1046 (match-beginning 7) | |
1047 (match-end 7)) | |
1048 nil))) | |
1049 (summary (icalendar--convert-string-for-export | |
1050 (substring entry-main (match-beginning 8) | |
1051 (match-end 8))))) | |
1052 (unless startdatestring | |
1053 (error "Could not parse date")) | |
1054 (when starttimestring | |
1055 (unless endtimestring | |
1056 (let ((time | |
1057 (read (icalendar--rris "^T0?" "" | |
1058 starttimestring)))) | |
1059 (setq endtimestring (format "T%06d" | |
1060 (+ 10000 time)))))) | |
1061 (setq contents (concat | |
1062 "\nDTSTART;" | |
1063 (if starttimestring "VALUE=DATE-TIME:" | |
1064 "VALUE=DATE:") | |
1065 startdatestring | |
1066 (or starttimestring "") | |
1067 "\nDTEND;" | |
1068 (if endtimestring "VALUE=DATE-TIME:" | |
1069 "VALUE=DATE:") | |
1070 (icalendar--datestring-to-isodate | |
1071 (substring entry-main | |
1072 (match-beginning 1) | |
1073 (match-end 1)) | |
1074 (if endtimestring 0 1)) | |
1075 (or endtimestring "") | |
1076 "\nSUMMARY:" | |
1077 summary)) | |
1078 ;; could not parse the date | |
1079 (unless (string= entry-rest "") | |
1080 (setq contents | |
1081 (concat contents "\nDESCRIPTION:" | |
1082 (icalendar--convert-string-for-export | |
1083 entry-rest)))))) | |
1084 ;; everything else | |
1085 (t | |
1086 ;; Oops! what's that? | |
1087 (error "Could not parse entry"))) | |
1088 (setq result (concat result header contents "\nEND:VEVENT"))) | 761 (setq result (concat result header contents "\nEND:VEVENT"))) |
1089 ;; handle errors | 762 ;; handle errors |
1090 (error | 763 (error |
1091 (setq found-error t) | 764 (setq found-error t) |
1092 (save-current-buffer | 765 (save-current-buffer |
1093 (set-buffer (get-buffer-create " *icalendar-errors*")) | 766 (set-buffer (get-buffer-create "*icalendar-errors*")) |
1094 (insert (format "Error in line %d -- %s: `%s'\n" | 767 (insert (format "Error in line %d -- %s: `%s'\n" |
1095 (count-lines (point-min) (point)) | 768 (count-lines (point-min) (point)) |
1096 (cadr error-val) | 769 (cadr error-val) |
1097 entry-main)))))) | 770 entry-main)))))) |
1098 | 771 |
1107 (insert result) | 780 (insert result) |
1108 (insert "\nEND:VCALENDAR\n") | 781 (insert "\nEND:VCALENDAR\n") |
1109 ;; save the diary file | 782 ;; save the diary file |
1110 (save-buffer)))) | 783 (save-buffer)))) |
1111 found-error)) | 784 found-error)) |
785 | |
786 ;; subroutines | |
787 (defun icalendar--convert-ordinary-to-ical (nonmarker entry-main) | |
788 "Convert \"ordinary\" diary entry to icalendar format. | |
789 | |
790 NONMARKER is a regular expression matching the start of non-marking | |
791 entries. ENTRY-MAIN is the first line of the diary entry." | |
792 (if (string-match (concat nonmarker | |
793 "\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)\\s-*" | |
794 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | |
795 "\\(" | |
796 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" | |
797 "\\)?" | |
798 "\\s-*\\(.*\\)") | |
799 entry-main) | |
800 (let* ((datetime (substring entry-main (match-beginning 1) | |
801 (match-end 1))) | |
802 (startisostring (icalendar--datestring-to-isodate | |
803 datetime)) | |
804 (endisostring (icalendar--datestring-to-isodate | |
805 datetime 1)) | |
806 (starttimestring (icalendar--diarytime-to-isotime | |
807 (if (match-beginning 3) | |
808 (substring entry-main | |
809 (match-beginning 3) | |
810 (match-end 3)) | |
811 nil) | |
812 (if (match-beginning 4) | |
813 (substring entry-main | |
814 (match-beginning 4) | |
815 (match-end 4)) | |
816 nil))) | |
817 (endtimestring (icalendar--diarytime-to-isotime | |
818 (if (match-beginning 6) | |
819 (substring entry-main | |
820 (match-beginning 6) | |
821 (match-end 6)) | |
822 nil) | |
823 (if (match-beginning 7) | |
824 (substring entry-main | |
825 (match-beginning 7) | |
826 (match-end 7)) | |
827 nil))) | |
828 (summary (icalendar--convert-string-for-export | |
829 (substring entry-main (match-beginning 8) | |
830 (match-end 8))))) | |
831 (icalendar--dmsg "ordinary %s" entry-main) | |
832 | |
833 (unless startisostring | |
834 (error "Could not parse date")) | |
835 (when starttimestring | |
836 (unless endtimestring | |
837 (let ((time | |
838 (read (icalendar--rris "^T0?" "" | |
839 starttimestring)))) | |
840 (setq endtimestring (format "T%06d" | |
841 (+ 10000 time)))))) | |
842 (concat "\nDTSTART;" | |
843 (if starttimestring "VALUE=DATE-TIME:" | |
844 "VALUE=DATE:") | |
845 startisostring | |
846 (or starttimestring "") | |
847 "\nDTEND;" | |
848 (if endtimestring "VALUE=DATE-TIME:" | |
849 "VALUE=DATE:") | |
850 (if starttimestring | |
851 startisostring | |
852 endisostring) | |
853 (or endtimestring "") | |
854 "\nSUMMARY:" | |
855 summary)) | |
856 ;; no match | |
857 nil)) | |
858 | |
859 (defun icalendar--convert-weekly-to-ical (nonmarker entry-main) | |
860 "Convert weekly diary entry to icalendar format. | |
861 | |
862 NONMARKER is a regular expression matching the start of non-marking | |
863 entries. ENTRY-MAIN is the first line of the diary entry." | |
864 (if (and (string-match (concat nonmarker | |
865 "\\([a-z]+\\)\\s-+" | |
866 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)" | |
867 "\\([ap]m\\)?" | |
868 "\\(-0?" | |
869 "\\([1-9][0-9]?:[0-9][0-9]\\)" | |
870 "\\([ap]m\\)?\\)?" | |
871 "\\)?" | |
872 "\\s-*\\(.*\\)$") | |
873 entry-main) | |
874 (icalendar--get-weekday-abbrev | |
875 (substring entry-main (match-beginning 1) | |
876 (match-end 1)))) | |
877 (let* ((day (icalendar--get-weekday-abbrev | |
878 (substring entry-main (match-beginning 1) | |
879 (match-end 1)))) | |
880 (starttimestring (icalendar--diarytime-to-isotime | |
881 (if (match-beginning 3) | |
882 (substring entry-main | |
883 (match-beginning 3) | |
884 (match-end 3)) | |
885 nil) | |
886 (if (match-beginning 4) | |
887 (substring entry-main | |
888 (match-beginning 4) | |
889 (match-end 4)) | |
890 nil))) | |
891 (endtimestring (icalendar--diarytime-to-isotime | |
892 (if (match-beginning 6) | |
893 (substring entry-main | |
894 (match-beginning 6) | |
895 (match-end 6)) | |
896 nil) | |
897 (if (match-beginning 7) | |
898 (substring entry-main | |
899 (match-beginning 7) | |
900 (match-end 7)) | |
901 nil))) | |
902 (summary (icalendar--convert-string-for-export | |
903 (substring entry-main (match-beginning 8) | |
904 (match-end 8))))) | |
905 (icalendar--dmsg "weekly %s" entry-main) | |
906 | |
907 (when starttimestring | |
908 (unless endtimestring | |
909 (let ((time (read | |
910 (icalendar--rris "^T0?" "" | |
911 starttimestring)))) | |
912 (setq endtimestring (format "T%06d" | |
913 (+ 10000 time)))))) | |
914 (concat "\nDTSTART;" | |
915 (if starttimestring | |
916 "VALUE=DATE-TIME:" | |
917 "VALUE=DATE:") | |
918 ;; find the correct week day, | |
919 ;; 1st january 2000 was a saturday | |
920 (format | |
921 "200001%02d" | |
922 (+ (icalendar--get-weekday-number day) 2)) | |
923 (or starttimestring "") | |
924 "\nDTEND;" | |
925 (if endtimestring | |
926 "VALUE=DATE-TIME:" | |
927 "VALUE=DATE:") | |
928 (format | |
929 "200001%02d" | |
930 ;; end is non-inclusive! | |
931 (+ (icalendar--get-weekday-number day) | |
932 (if endtimestring 2 3))) | |
933 (or endtimestring "") | |
934 "\nSUMMARY:" summary | |
935 "\nRRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=" | |
936 day)) | |
937 ;; no match | |
938 nil)) | |
939 | |
940 (defun icalendar--convert-yearly-to-ical (nonmarker entry-main) | |
941 "Convert yearly diary entry to icalendar format. | |
942 | |
943 NONMARKER is a regular expression matching the start of non-marking | |
944 entries. ENTRY-MAIN is the first line of the diary entry." | |
945 (if (string-match (concat nonmarker | |
946 (if european-calendar-style | |
947 "0?\\([1-9]+[0-9]?\\)\\s-+\\([a-z]+\\)\\s-+" | |
948 "\\([a-z]+\\)\\s-+0?\\([1-9]+[0-9]?\\)\\s-+") | |
949 "\\*?\\s-*" | |
950 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | |
951 "\\(" | |
952 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" | |
953 "\\)?" | |
954 "\\s-*\\([^0-9]+.*\\)$" ; must not match years | |
955 ) | |
956 entry-main) | |
957 (let* ((daypos (if european-calendar-style 1 2)) | |
958 (monpos (if european-calendar-style 2 1)) | |
959 (day (read (substring entry-main | |
960 (match-beginning daypos) | |
961 (match-end daypos)))) | |
962 (month (icalendar--get-month-number | |
963 (substring entry-main | |
964 (match-beginning monpos) | |
965 (match-end monpos)))) | |
966 (starttimestring (icalendar--diarytime-to-isotime | |
967 (if (match-beginning 4) | |
968 (substring entry-main | |
969 (match-beginning 4) | |
970 (match-end 4)) | |
971 nil) | |
972 (if (match-beginning 5) | |
973 (substring entry-main | |
974 (match-beginning 5) | |
975 (match-end 5)) | |
976 nil))) | |
977 (endtimestring (icalendar--diarytime-to-isotime | |
978 (if (match-beginning 7) | |
979 (substring entry-main | |
980 (match-beginning 7) | |
981 (match-end 7)) | |
982 nil) | |
983 (if (match-beginning 8) | |
984 (substring entry-main | |
985 (match-beginning 8) | |
986 (match-end 8)) | |
987 nil))) | |
988 (summary (icalendar--convert-string-for-export | |
989 (substring entry-main (match-beginning 9) | |
990 (match-end 9))))) | |
991 (icalendar--dmsg "yearly %s" entry-main) | |
992 | |
993 (when starttimestring | |
994 (unless endtimestring | |
995 (let ((time (read | |
996 (icalendar--rris "^T0?" "" | |
997 starttimestring)))) | |
998 (setq endtimestring (format "T%06d" | |
999 (+ 10000 time)))))) | |
1000 (concat "\nDTSTART;" | |
1001 (if starttimestring "VALUE=DATE-TIME:" | |
1002 "VALUE=DATE:") | |
1003 (format "1900%02d%02d" month day) | |
1004 (or starttimestring "") | |
1005 "\nDTEND;" | |
1006 (if endtimestring "VALUE=DATE-TIME:" | |
1007 "VALUE=DATE:") | |
1008 ;; end is not included! shift by one day | |
1009 (icalendar--date-to-isodate | |
1010 (list month day 1900) | |
1011 (if endtimestring 0 1)) | |
1012 (or endtimestring "") | |
1013 "\nSUMMARY:" | |
1014 summary | |
1015 "\nRRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=" | |
1016 (format "%2d" month) | |
1017 ";BYMONTHDAY=" | |
1018 (format "%2d" day))) | |
1019 ;; no match | |
1020 nil)) | |
1021 | |
1022 (defun icalendar--convert-sexp-to-ical (nonmarker entry-main) | |
1023 "Convert complex sexp diary entry to icalendar format -- unsupported! | |
1024 | |
1025 FIXME! | |
1026 | |
1027 NONMARKER is a regular expression matching the start of non-marking | |
1028 entries. ENTRY-MAIN is the first line of the diary entry." | |
1029 (if (string-match (concat nonmarker | |
1030 "%%(\\([^)]+\\))\\s-*\\(.*\\)") | |
1031 entry-main) | |
1032 (progn | |
1033 (icalendar--dmsg "diary-sexp %s" entry-main) | |
1034 (error "Sexp-entries are not supported yet")) | |
1035 ;; no match | |
1036 nil)) | |
1037 | |
1038 (defun icalendar--convert-block-to-ical (nonmarker entry-main) | |
1039 "Convert block diary entry to icalendar format. | |
1040 | |
1041 NONMARKER is a regular expression matching the start of non-marking | |
1042 entries. ENTRY-MAIN is the first line of the diary entry." | |
1043 (if (string-match (concat nonmarker | |
1044 "%%(diary-block \\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)" | |
1045 " +\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*" | |
1046 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | |
1047 "\\(" | |
1048 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" | |
1049 "\\)?" | |
1050 "\\s-*\\(.*\\)") | |
1051 entry-main) | |
1052 (let* ((startstring (substring entry-main | |
1053 (match-beginning 1) | |
1054 (match-end 1))) | |
1055 (endstring (substring entry-main | |
1056 (match-beginning 2) | |
1057 (match-end 2))) | |
1058 (startisostring (icalendar--datestring-to-isodate | |
1059 startstring)) | |
1060 (endisostring (icalendar--datestring-to-isodate | |
1061 endstring)) | |
1062 (endisostring+1 (icalendar--datestring-to-isodate | |
1063 endstring 1)) | |
1064 (starttimestring (icalendar--diarytime-to-isotime | |
1065 (if (match-beginning 4) | |
1066 (substring entry-main | |
1067 (match-beginning 4) | |
1068 (match-end 4)) | |
1069 nil) | |
1070 (if (match-beginning 5) | |
1071 (substring entry-main | |
1072 (match-beginning 5) | |
1073 (match-end 5)) | |
1074 nil))) | |
1075 (endtimestring (icalendar--diarytime-to-isotime | |
1076 (if (match-beginning 7) | |
1077 (substring entry-main | |
1078 (match-beginning 7) | |
1079 (match-end 7)) | |
1080 nil) | |
1081 (if (match-beginning 8) | |
1082 (substring entry-main | |
1083 (match-beginning 8) | |
1084 (match-end 8)) | |
1085 nil))) | |
1086 (summary (icalendar--convert-string-for-export | |
1087 (substring entry-main (match-beginning 9) | |
1088 (match-end 9))))) | |
1089 (icalendar--dmsg "diary-block %s" entry-main) | |
1090 (when starttimestring | |
1091 (unless endtimestring | |
1092 (let ((time | |
1093 (read (icalendar--rris "^T0?" "" | |
1094 starttimestring)))) | |
1095 (setq endtimestring (format "T%06d" | |
1096 (+ 10000 time)))))) | |
1097 (if starttimestring | |
1098 ;; with time -> write rrule | |
1099 (concat "\nDTSTART;VALUE=DATE-TIME:" | |
1100 startisostring | |
1101 starttimestring | |
1102 "\nDTEND;VALUE=DATE-TIME:" | |
1103 startisostring | |
1104 endtimestring | |
1105 "\nSUMMARY:" | |
1106 summary | |
1107 "\nRRULE:FREQ=DAILY;INTERVAL=1;UNTIL=" | |
1108 endisostring) | |
1109 ;; no time -> write long event | |
1110 (concat "\nDTSTART;VALUE=DATE:" startisostring | |
1111 "\nDTEND;VALUE=DATE:" endisostring+1 | |
1112 "\nSUMMARY:" summary))) | |
1113 ;; no match | |
1114 nil)) | |
1115 | |
1116 (defun icalendar--convert-float-to-ical (nonmarker entry-main) | |
1117 "Convert float diary entry to icalendar format -- unsupported! | |
1118 | |
1119 FIXME! | |
1120 | |
1121 NONMARKER is a regular expression matching the start of non-marking | |
1122 entries. ENTRY-MAIN is the first line of the diary entry." | |
1123 (if (string-match (concat nonmarker | |
1124 "%%(diary-float \\([^)]+\\))\\s-*\\(.*\\)") | |
1125 entry-main) | |
1126 (progn | |
1127 (icalendar--dmsg "diary-float %s" entry-main) | |
1128 (error "`diary-float' is not supported yet")) | |
1129 ;; no match | |
1130 nil)) | |
1131 | |
1132 (defun icalendar--convert-date-to-ical (nonmarker entry-main) | |
1133 "Convert `diary-date' diary entry to icalendar format -- unsupported! | |
1134 | |
1135 FIXME! | |
1136 | |
1137 NONMARKER is a regular expression matching the start of non-marking | |
1138 entries. ENTRY-MAIN is the first line of the diary entry." | |
1139 (if (string-match (concat nonmarker | |
1140 "%%(diary-date \\([^)]+\\))\\s-*\\(.*\\)") | |
1141 entry-main) | |
1142 (progn | |
1143 (icalendar--dmsg "diary-date %s" entry-main) | |
1144 (error "`diary-date' is not supported yet")) | |
1145 ;; no match | |
1146 nil)) | |
1147 | |
1148 (defun icalendar--convert-cyclic-to-ical (nonmarker entry-main) | |
1149 "Convert `diary-cyclic' diary entry to icalendar format. | |
1150 | |
1151 NONMARKER is a regular expression matching the start of non-marking | |
1152 entries. ENTRY-MAIN is the first line of the diary entry." | |
1153 (if (string-match (concat nonmarker | |
1154 "%%(diary-cyclic \\([^ ]+\\) +" | |
1155 "\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*" | |
1156 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | |
1157 "\\(" | |
1158 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" | |
1159 "\\)?" | |
1160 "\\s-*\\(.*\\)") | |
1161 entry-main) | |
1162 (let* ((frequency (substring entry-main (match-beginning 1) | |
1163 (match-end 1))) | |
1164 (datetime (substring entry-main (match-beginning 2) | |
1165 (match-end 2))) | |
1166 (startisostring (icalendar--datestring-to-isodate | |
1167 datetime)) | |
1168 (endisostring (icalendar--datestring-to-isodate | |
1169 datetime)) | |
1170 (endisostring+1 (icalendar--datestring-to-isodate | |
1171 datetime 1)) | |
1172 (starttimestring (icalendar--diarytime-to-isotime | |
1173 (if (match-beginning 4) | |
1174 (substring entry-main | |
1175 (match-beginning 4) | |
1176 (match-end 4)) | |
1177 nil) | |
1178 (if (match-beginning 5) | |
1179 (substring entry-main | |
1180 (match-beginning 5) | |
1181 (match-end 5)) | |
1182 nil))) | |
1183 (endtimestring (icalendar--diarytime-to-isotime | |
1184 (if (match-beginning 7) | |
1185 (substring entry-main | |
1186 (match-beginning 7) | |
1187 (match-end 7)) | |
1188 nil) | |
1189 (if (match-beginning 8) | |
1190 (substring entry-main | |
1191 (match-beginning 8) | |
1192 (match-end 8)) | |
1193 nil))) | |
1194 (summary (icalendar--convert-string-for-export | |
1195 (substring entry-main (match-beginning 9) | |
1196 (match-end 9))))) | |
1197 (icalendar--dmsg "diary-cyclic %s" entry-main) | |
1198 (when starttimestring | |
1199 (unless endtimestring | |
1200 (let ((time | |
1201 (read (icalendar--rris "^T0?" "" | |
1202 starttimestring)))) | |
1203 (setq endtimestring (format "T%06d" | |
1204 (+ 10000 time)))))) | |
1205 (concat "\nDTSTART;" | |
1206 (if starttimestring "VALUE=DATE-TIME:" | |
1207 "VALUE=DATE:") | |
1208 startisostring | |
1209 (or starttimestring "") | |
1210 "\nDTEND;" | |
1211 (if endtimestring "VALUE=DATE-TIME:" | |
1212 "VALUE=DATE:") | |
1213 (if endtimestring endisostring endisostring+1) | |
1214 (or endtimestring "") | |
1215 "\nSUMMARY:" summary | |
1216 "\nRRULE:FREQ=DAILY;INTERVAL=" frequency | |
1217 ;; strange: korganizer does not expect | |
1218 ;; BYSOMETHING here... | |
1219 )) | |
1220 ;; no match | |
1221 nil)) | |
1222 | |
1223 (defun icalendar--convert-anniversary-to-ical (nonmarker entry-main) | |
1224 "Convert `diary-anniversary' diary entry to icalendar format. | |
1225 | |
1226 NONMARKER is a regular expression matching the start of non-marking | |
1227 entries. ENTRY-MAIN is the first line of the diary entry." | |
1228 (if (string-match (concat nonmarker | |
1229 "%%(diary-anniversary \\([^)]+\\))\\s-*" | |
1230 "\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" | |
1231 "\\(" | |
1232 "-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" | |
1233 "\\)?" | |
1234 "\\s-*\\(.*\\)") | |
1235 entry-main) | |
1236 (let* ((datetime (substring entry-main (match-beginning 1) | |
1237 (match-end 1))) | |
1238 (startisostring (icalendar--datestring-to-isodate | |
1239 datetime)) | |
1240 (endisostring (icalendar--datestring-to-isodate | |
1241 datetime 1)) | |
1242 (starttimestring (icalendar--diarytime-to-isotime | |
1243 (if (match-beginning 3) | |
1244 (substring entry-main | |
1245 (match-beginning 3) | |
1246 (match-end 3)) | |
1247 nil) | |
1248 (if (match-beginning 4) | |
1249 (substring entry-main | |
1250 (match-beginning 4) | |
1251 (match-end 4)) | |
1252 nil))) | |
1253 (endtimestring (icalendar--diarytime-to-isotime | |
1254 (if (match-beginning 6) | |
1255 (substring entry-main | |
1256 (match-beginning 6) | |
1257 (match-end 6)) | |
1258 nil) | |
1259 (if (match-beginning 7) | |
1260 (substring entry-main | |
1261 (match-beginning 7) | |
1262 (match-end 7)) | |
1263 nil))) | |
1264 (summary (icalendar--convert-string-for-export | |
1265 (substring entry-main (match-beginning 8) | |
1266 (match-end 8))))) | |
1267 (icalendar--dmsg "diary-anniversary %s" entry-main) | |
1268 (when starttimestring | |
1269 (unless endtimestring | |
1270 (let ((time | |
1271 (read (icalendar--rris "^T0?" "" | |
1272 starttimestring)))) | |
1273 (setq endtimestring (format "T%06d" | |
1274 (+ 10000 time)))))) | |
1275 (concat "\nDTSTART;" | |
1276 (if starttimestring "VALUE=DATE-TIME:" | |
1277 "VALUE=DATE:") | |
1278 startisostring | |
1279 (or starttimestring "") | |
1280 "\nDTEND;" | |
1281 (if endtimestring "VALUE=DATE-TIME:" | |
1282 "VALUE=DATE:") | |
1283 endisostring | |
1284 (or endtimestring "") | |
1285 "\nSUMMARY:" summary | |
1286 "\nRRULE:FREQ=YEARLY;INTERVAL=1" | |
1287 ;; the following is redundant, | |
1288 ;; but korganizer seems to expect this... ;( | |
1289 ;; and evolution doesn't understand it... :( | |
1290 ;; so... who is wrong?! | |
1291 ";BYMONTH=" | |
1292 (substring startisostring 4 6) | |
1293 ";BYMONTHDAY=" | |
1294 (substring startisostring 6 8))) | |
1295 ;; no match | |
1296 nil)) | |
1112 | 1297 |
1113 ;; ====================================================================== | 1298 ;; ====================================================================== |
1114 ;; Import -- convert icalendar to emacs-diary | 1299 ;; Import -- convert icalendar to emacs-diary |
1115 ;; ====================================================================== | 1300 ;; ====================================================================== |
1116 | 1301 |
1168 (message "Converting icalendar...") | 1353 (message "Converting icalendar...") |
1169 (setq ical-errors (icalendar--convert-ical-to-diary | 1354 (setq ical-errors (icalendar--convert-ical-to-diary |
1170 ical-contents | 1355 ical-contents |
1171 diary-file do-not-ask non-marking)) | 1356 diary-file do-not-ask non-marking)) |
1172 (when diary-file | 1357 (when diary-file |
1173 ;; save the diary file | 1358 ;; save the diary file if it is visited already |
1174 (save-current-buffer | 1359 (let ((b (find-buffer-visiting diary-file))) |
1175 (set-buffer (find-buffer-visiting diary-file)) | 1360 (when b |
1176 (save-buffer))) | 1361 (save-current-buffer |
1362 (set-buffer b) | |
1363 (save-buffer))))) | |
1177 (message "Converting icalendar...done") | 1364 (message "Converting icalendar...done") |
1178 ;; return t if no error occured | 1365 ;; return t if no error occured |
1179 (not ical-errors)) | 1366 (not ical-errors)) |
1180 (message | 1367 (message |
1181 "Current buffer does not contain icalendar contents!") | 1368 "Current buffer does not contain icalendar contents!") |
1182 ;; return nil, i.e. import did not work | 1369 ;; return nil, i.e. import did not work |
1183 nil))) | 1370 nil))) |
1184 | 1371 |
1185 (defalias 'icalendar-extract-ical-from-buffer 'icalendar-import-buffer) | 1372 (defalias 'icalendar-extract-ical-from-buffer 'icalendar-import-buffer) |
1186 (make-obsolete 'icalendar-extract-ical-from-buffer 'icalendar-import-buffer) | 1373 (make-obsolete 'icalendar-extract-ical-from-buffer 'icalendar-import-buffer) |
1187 | |
1188 ;; ====================================================================== | |
1189 ;; private area | |
1190 ;; ====================================================================== | |
1191 | 1374 |
1192 (defun icalendar--format-ical-event (event) | 1375 (defun icalendar--format-ical-event (event) |
1193 "Create a string representation of an iCalendar EVENT." | 1376 "Create a string representation of an iCalendar EVENT." |
1194 (let ((string icalendar-import-format) | 1377 (let ((string icalendar-import-format) |
1195 (conversion-list | 1378 (conversion-list |
1224 DIARY-FILE. If DO-NOT-ASK is nil the user is asked for each event | 1407 DIARY-FILE. If DO-NOT-ASK is nil the user is asked for each event |
1225 whether to actually import it. NON-MARKING determines whether diary | 1408 whether to actually import it. NON-MARKING determines whether diary |
1226 events are created as non-marking. | 1409 events are created as non-marking. |
1227 This function attempts to return t if something goes wrong. In this | 1410 This function attempts to return t if something goes wrong. In this |
1228 case an error string which describes all the errors and problems is | 1411 case an error string which describes all the errors and problems is |
1229 written into the buffer ` *icalendar-errors*'." | 1412 written into the buffer `*icalendar-errors*'." |
1230 (let* ((ev (icalendar--all-events ical-list)) | 1413 (let* ((ev (icalendar--all-events ical-list)) |
1231 (error-string "") | 1414 (error-string "") |
1232 (event-ok t) | 1415 (event-ok t) |
1233 (found-error nil) | 1416 (found-error nil) |
1234 e diary-string) | 1417 e diary-string) |
1236 (while ev | 1419 (while ev |
1237 (setq e (car ev)) | 1420 (setq e (car ev)) |
1238 (setq ev (cdr ev)) | 1421 (setq ev (cdr ev)) |
1239 (setq event-ok nil) | 1422 (setq event-ok nil) |
1240 (condition-case error-val | 1423 (condition-case error-val |
1241 (let* ((dtstart (icalendar--decode-isodatetime | 1424 (let* ((dtstart (icalendar--get-event-property e 'DTSTART)) |
1242 (icalendar--get-event-property e 'DTSTART))) | 1425 (dtstart-dec (icalendar--decode-isodatetime dtstart)) |
1243 (start-d (icalendar--datetime-to-diary-date | 1426 (start-d (icalendar--datetime-to-diary-date |
1244 dtstart)) | 1427 dtstart-dec)) |
1245 (start-t (icalendar--datetime-to-colontime dtstart)) | 1428 (start-t (icalendar--datetime-to-colontime dtstart-dec)) |
1246 (dtend (icalendar--decode-isodatetime | 1429 (dtend (icalendar--get-event-property e 'DTEND)) |
1247 (icalendar--get-event-property e 'DTEND))) | 1430 (dtend-dec (icalendar--decode-isodatetime dtend)) |
1431 (dtend-1-dec (icalendar--decode-isodatetime dtend -1)) | |
1248 end-d | 1432 end-d |
1433 end-1-d | |
1249 end-t | 1434 end-t |
1250 (subject (icalendar--convert-string-for-import | 1435 (subject (icalendar--convert-string-for-import |
1251 (or (icalendar--get-event-property e 'SUMMARY) | 1436 (or (icalendar--get-event-property e 'SUMMARY) |
1252 "No Subject"))) | 1437 "No Subject"))) |
1253 (rrule (icalendar--get-event-property e 'RRULE)) | 1438 (rrule (icalendar--get-event-property e 'RRULE)) |
1254 (rdate (icalendar--get-event-property e 'RDATE)) | 1439 (rdate (icalendar--get-event-property e 'RDATE)) |
1255 (duration (icalendar--get-event-property e 'DURATION))) | 1440 (duration (icalendar--get-event-property e 'DURATION))) |
1256 (icalendar--dmsg "%s: %s" start-d subject) | 1441 (icalendar--dmsg "%s: `%s'" start-d subject) |
1257 ;; check whether start-time is missing | 1442 ;; check whether start-time is missing |
1258 (if (and (icalendar--get-event-property-attributes | 1443 (if (and dtstart |
1259 e 'DTSTART) | 1444 (string= |
1260 (string= (cadr (icalendar--get-event-property-attributes | 1445 (cadr (icalendar--get-event-property-attributes |
1261 e 'DTSTART)) | 1446 e 'DTSTART)) |
1262 "DATE")) | 1447 "DATE")) |
1263 (setq start-t nil)) | 1448 (setq start-t nil)) |
1264 (when duration | 1449 (when duration |
1265 (let ((dtend2 (icalendar--add-decoded-times | 1450 (let ((dtend-dec-d (icalendar--add-decoded-times |
1266 dtstart | 1451 dtstart-dec |
1267 (icalendar--decode-isoduration duration)))) | 1452 (icalendar--decode-isoduration duration))) |
1268 (if (and dtend (not (eq dtend dtend2))) | 1453 (dtend-1-dec-d (icalendar--add-decoded-times |
1454 dtstart-dec | |
1455 (icalendar--decode-isoduration duration | |
1456 t)))) | |
1457 (if (and dtend-dec (not (eq dtend-dec dtend-dec-d))) | |
1269 (message "Inconsistent endtime and duration for %s" | 1458 (message "Inconsistent endtime and duration for %s" |
1270 subject)) | 1459 subject)) |
1271 (setq dtend dtend2))) | 1460 (setq dtend-dec dtend-dec-d) |
1272 (setq end-d (if dtend | 1461 (setq dtend-1-dec dtend-1-dec-d))) |
1273 (icalendar--datetime-to-diary-date dtend) | 1462 (setq end-d (if dtend-dec |
1463 (icalendar--datetime-to-diary-date dtend-dec) | |
1274 start-d)) | 1464 start-d)) |
1275 (setq end-t (if dtend | 1465 (setq end-1-d (if dtend-1-dec |
1276 (icalendar--datetime-to-colontime dtend) | 1466 (icalendar--datetime-to-diary-date dtend-1-dec) |
1467 start-d)) | |
1468 (setq end-t (if (and | |
1469 dtend-dec | |
1470 (not (string= | |
1471 (cadr | |
1472 (icalendar--get-event-property-attributes | |
1473 e 'DTEND)) | |
1474 "DATE"))) | |
1475 (icalendar--datetime-to-colontime dtend-dec) | |
1277 start-t)) | 1476 start-t)) |
1278 (icalendar--dmsg "start-d: %s, end-d: %s" start-d end-d) | 1477 (icalendar--dmsg "start-d: %s, end-d: %s" start-d end-d) |
1279 (cond | 1478 (cond |
1280 ;; recurring event | 1479 ;; recurring event |
1281 (rrule | 1480 (rrule |
1282 (icalendar--dmsg "recurring event") | 1481 (setq diary-string |
1283 (let* ((rrule-props (icalendar--split-value rrule)) | 1482 (icalendar--convert-recurring-to-diary e dtstart-dec start-t |
1284 (frequency (cadr (assoc 'FREQ rrule-props))) | 1483 end-t)) |
1285 (until (cadr (assoc 'UNTIL rrule-props))) | 1484 (setq event-ok t)) |
1286 (interval (read (cadr (assoc 'INTERVAL rrule-props))))) | |
1287 (cond ((string-equal frequency "WEEKLY") | |
1288 (if (not start-t) | |
1289 (progn | |
1290 ;; weekly and all-day | |
1291 (icalendar--dmsg "weekly all-day") | |
1292 (if until | |
1293 (let ((fro | |
1294 (icalendar--datetime-to-diary-date | |
1295 (icalendar--decode-isodatetime | |
1296 (icalendar--get-event-property | |
1297 e | |
1298 'DTSTART)))) | |
1299 (unt | |
1300 (icalendar--datetime-to-diary-date | |
1301 (icalendar--decode-isodatetime | |
1302 until -1)))) | |
1303 (setq diary-string | |
1304 (format | |
1305 (concat "%%%%(and " | |
1306 "(diary-cyclic %d %s) " | |
1307 "(diary-block %s %s))") | |
1308 (* interval 7) | |
1309 (icalendar--datetime-to-diary-date | |
1310 dtstart) | |
1311 (icalendar--datetime-to-diary-date | |
1312 dtstart) | |
1313 (icalendar--datetime-to-diary-date | |
1314 (icalendar--decode-isodatetime | |
1315 until -1))))) | |
1316 (setq diary-string | |
1317 (format "%%%%(and (diary-cyclic %d %s))" | |
1318 (* interval 7) | |
1319 (icalendar--datetime-to-diary-date | |
1320 dtstart)))) | |
1321 (setq event-ok t)) | |
1322 ;; weekly and not all-day | |
1323 (let* ((byday (cadr (assoc 'BYDAY rrule-props))) | |
1324 (weekday | |
1325 (icalendar--get-weekday-number byday))) | |
1326 (icalendar--dmsg "weekly not-all-day") | |
1327 (if until | |
1328 (let ((fro | |
1329 (icalendar--datetime-to-diary-date | |
1330 (icalendar--decode-isodatetime | |
1331 (icalendar--get-event-property | |
1332 e | |
1333 'DTSTART)))) | |
1334 (unt | |
1335 (icalendar--datetime-to-diary-date | |
1336 (icalendar--decode-isodatetime | |
1337 until)))) | |
1338 (setq diary-string | |
1339 (format | |
1340 (concat "%%%%(and " | |
1341 "(diary-cyclic %d %s) " | |
1342 "(diary-block %s %s)) " | |
1343 "%s%s%s") | |
1344 (* interval 7) | |
1345 (icalendar--datetime-to-diary-date | |
1346 dtstart) | |
1347 (icalendar--datetime-to-diary-date | |
1348 dtstart) | |
1349 (icalendar--datetime-to-diary-date | |
1350 (icalendar--decode-isodatetime | |
1351 until)) | |
1352 start-t | |
1353 (if end-t "-" "") (or end-t "")))) | |
1354 ;; no limit | |
1355 ;; FIXME!!!! | |
1356 ;; DTSTART;VALUE=DATE-TIME:20030919T090000 | |
1357 ;; DTEND;VALUE=DATE-TIME:20030919T113000 | |
1358 (setq diary-string | |
1359 (format | |
1360 "%%%%(and (diary-cyclic %s %s)) %s%s%s" | |
1361 (* interval 7) | |
1362 (icalendar--datetime-to-diary-date | |
1363 dtstart) | |
1364 start-t | |
1365 (if end-t "-" "") (or end-t "")))) | |
1366 (setq event-ok t)))) | |
1367 ;; yearly | |
1368 ((string-equal frequency "YEARLY") | |
1369 (icalendar--dmsg "yearly") | |
1370 (setq diary-string | |
1371 (format | |
1372 "%%%%(and (diary-anniversary %s))" | |
1373 (icalendar--datetime-to-diary-date dtstart))) | |
1374 (setq event-ok t)) | |
1375 ;; FIXME: war auskommentiert: | |
1376 ((and (string-equal frequency "DAILY") | |
1377 ;;(not (string= start-d end-d)) | |
1378 ;;(not start-t) | |
1379 ;;(not end-t) | |
1380 ) | |
1381 (let ((ds (icalendar--datetime-to-diary-date | |
1382 (icalendar--decode-isodatetime | |
1383 (icalendar--get-event-property | |
1384 e 'DTSTART)))) | |
1385 (de (icalendar--datetime-to-diary-date | |
1386 (icalendar--decode-isodatetime | |
1387 until -1)))) | |
1388 (setq diary-string | |
1389 (format | |
1390 "%%%%(and (diary-block %s %s))" | |
1391 ds de))) | |
1392 (setq event-ok t)))) | |
1393 ;; Handle exceptions from recurrence rules | |
1394 (let ((ex-dates (icalendar--get-event-properties e | |
1395 'EXDATE))) | |
1396 (while ex-dates | |
1397 (let* ((ex-start (icalendar--decode-isodatetime | |
1398 (car ex-dates))) | |
1399 (ex-d (icalendar--datetime-to-diary-date | |
1400 ex-start))) | |
1401 (setq diary-string | |
1402 (icalendar--rris "^%%(\\(and \\)?" | |
1403 (format | |
1404 "%%%%(and (not (diary-date %s)) " | |
1405 ex-d) | |
1406 diary-string))) | |
1407 (setq ex-dates (cdr ex-dates)))) | |
1408 ;; FIXME: exception rules are not recognized | |
1409 (if (icalendar--get-event-property e 'EXRULE) | |
1410 (setq diary-string | |
1411 (concat diary-string | |
1412 "\n Exception rules: " | |
1413 (icalendar--get-event-properties | |
1414 e 'EXRULE))))) | |
1415 (rdate | 1485 (rdate |
1416 (icalendar--dmsg "rdate event") | 1486 (icalendar--dmsg "rdate event") |
1417 (setq diary-string "") | 1487 (setq diary-string "") |
1418 (mapcar (lambda (datestring) | 1488 (mapcar (lambda (datestring) |
1419 (setq diary-string | 1489 (setq diary-string |
1421 (format "......")))) | 1491 (format "......")))) |
1422 (icalendar--split-value rdate))) | 1492 (icalendar--split-value rdate))) |
1423 ;; non-recurring event | 1493 ;; non-recurring event |
1424 ;; all-day event | 1494 ;; all-day event |
1425 ((not (string= start-d end-d)) | 1495 ((not (string= start-d end-d)) |
1426 (icalendar--dmsg "non-recurring event") | 1496 (setq diary-string |
1427 (let ((ds (icalendar--datetime-to-diary-date dtstart)) | 1497 (icalendar--convert-non-recurring-all-day-to-diary |
1428 (de (icalendar--datetime-to-diary-date dtend))) | 1498 e start-d end-1-d)) |
1429 (setq diary-string | |
1430 (format "%%%%(and (diary-block %s %s))" | |
1431 ds de))) | |
1432 (setq event-ok t)) | 1499 (setq event-ok t)) |
1433 ;; not all-day | 1500 ;; not all-day |
1434 ((and start-t (or (not end-t) | 1501 ((and start-t (or (not end-t) |
1435 (not (string= start-t end-t)))) | 1502 (not (string= start-t end-t)))) |
1436 (icalendar--dmsg "not all day event") | 1503 (setq diary-string |
1437 (cond (end-t | 1504 (icalendar--convert-non-recurring-not-all-day-to-diary |
1438 (setq diary-string | 1505 e dtstart-dec dtend-dec start-t end-t)) |
1439 (format "%s %s-%s" | |
1440 (icalendar--datetime-to-diary-date | |
1441 dtstart "/") | |
1442 start-t end-t))) | |
1443 (t | |
1444 (setq diary-string | |
1445 (format "%s %s" | |
1446 (icalendar--datetime-to-diary-date | |
1447 dtstart "/") | |
1448 start-t)))) | |
1449 (setq event-ok t)) | 1506 (setq event-ok t)) |
1450 ;; all-day event | 1507 ;; all-day event |
1451 (t | 1508 (t |
1452 (icalendar--dmsg "all day event") | 1509 (icalendar--dmsg "all day event") |
1453 (setq diary-string (icalendar--datetime-to-diary-date | 1510 (setq diary-string (icalendar--datetime-to-diary-date |
1454 dtstart "/")) | 1511 dtstart-dec "/")) |
1455 (setq event-ok t))) | 1512 (setq event-ok t))) |
1456 ;; add all other elements unless the user doesn't want to have | 1513 ;; add all other elements unless the user doesn't want to have |
1457 ;; them | 1514 ;; them |
1458 (if event-ok | 1515 (if event-ok |
1459 (progn | 1516 (progn |
1476 (setq error-string (format "%s\n%s\nCannot handle this event: %s" | 1533 (setq error-string (format "%s\n%s\nCannot handle this event: %s" |
1477 error-val error-string e)) | 1534 error-val error-string e)) |
1478 (message error-string)))) | 1535 (message error-string)))) |
1479 (if found-error | 1536 (if found-error |
1480 (save-current-buffer | 1537 (save-current-buffer |
1481 (set-buffer (get-buffer-create " *icalendar-errors*")) | 1538 (set-buffer (get-buffer-create "*icalendar-errors*")) |
1482 (erase-buffer) | 1539 (erase-buffer) |
1483 (insert error-string))) | 1540 (insert error-string))) |
1484 (message "Converting icalendar...done") | 1541 (message "Converting icalendar...done") |
1485 found-error)) | 1542 found-error)) |
1543 | |
1544 ;; subroutines for importing | |
1545 (defun icalendar--convert-recurring-to-diary (e dtstart-dec start-t end-t) | |
1546 "Convert recurring icalendar event E to diary format. | |
1547 | |
1548 DTSTART-DEC is the DTSTART property of E. | |
1549 START-T is the event's start time in diary format. | |
1550 END-T is the event's end time in diary format." | |
1551 (icalendar--dmsg "recurring event") | |
1552 (let* ((rrule (icalendar--get-event-property e 'RRULE)) | |
1553 (rrule-props (icalendar--split-value rrule)) | |
1554 (frequency (cadr (assoc 'FREQ rrule-props))) | |
1555 (until (cadr (assoc 'UNTIL rrule-props))) | |
1556 (count (cadr (assoc 'COUNT rrule-props))) | |
1557 (interval (read (or (cadr (assoc 'INTERVAL rrule-props)) "1"))) | |
1558 (dtstart-conv (icalendar--datetime-to-diary-date dtstart-dec)) | |
1559 (until-conv (icalendar--datetime-to-diary-date | |
1560 (icalendar--decode-isodatetime until))) | |
1561 (until-1-conv (icalendar--datetime-to-diary-date | |
1562 (icalendar--decode-isodatetime until -1))) | |
1563 (result "")) | |
1564 | |
1565 ;; FIXME FIXME interval!!!!!!!!!!!!! | |
1566 | |
1567 (when count | |
1568 (if until | |
1569 (message "Must not have UNTIL and COUNT -- ignoring COUNT element!") | |
1570 (let ((until-1 0)) | |
1571 (cond ((string-equal frequency "DAILY") | |
1572 (setq until (icalendar--add-decoded-times | |
1573 dtstart-dec | |
1574 (list 0 0 0 (* (read count) interval) 0 0))) | |
1575 (setq until-1 (icalendar--add-decoded-times | |
1576 dtstart-dec | |
1577 (list 0 0 0 (* (- (read count) 1) interval) | |
1578 0 0))) | |
1579 ) | |
1580 ((string-equal frequency "WEEKLY") | |
1581 (setq until (icalendar--add-decoded-times | |
1582 dtstart-dec | |
1583 (list 0 0 0 (* (read count) 7 interval) 0 0))) | |
1584 (setq until-1 (icalendar--add-decoded-times | |
1585 dtstart-dec | |
1586 (list 0 0 0 (* (- (read count) 1) 7 | |
1587 interval) 0 0))) | |
1588 ) | |
1589 ((string-equal frequency "MONTHLY") | |
1590 (setq until (icalendar--add-decoded-times | |
1591 dtstart-dec (list 0 0 0 0 (* (- (read count) 1) | |
1592 interval) 0))) | |
1593 (setq until-1 (icalendar--add-decoded-times | |
1594 dtstart-dec (list 0 0 0 0 (* (- (read count) 1) | |
1595 interval) 0))) | |
1596 ) | |
1597 ((string-equal frequency "YEARLY") | |
1598 (setq until (icalendar--add-decoded-times | |
1599 dtstart-dec (list 0 0 0 0 0 (* (- (read count) 1) | |
1600 interval)))) | |
1601 (setq until-1 (icalendar--add-decoded-times | |
1602 dtstart-dec | |
1603 (list 0 0 0 0 0 (* (- (read count) 1) | |
1604 interval)))) | |
1605 ) | |
1606 (t | |
1607 (message "Cannot handle COUNT attribute for `%s' events." | |
1608 frequency))) | |
1609 (setq until-conv (icalendar--datetime-to-diary-date until)) | |
1610 (setq until-1-conv (icalendar--datetime-to-diary-date until-1)) | |
1611 )) | |
1612 ) | |
1613 (cond ((string-equal frequency "WEEKLY") | |
1614 (if (not start-t) | |
1615 (progn | |
1616 ;; weekly and all-day | |
1617 (icalendar--dmsg "weekly all-day") | |
1618 (if until | |
1619 (setq result | |
1620 (format | |
1621 (concat "%%%%(and " | |
1622 "(diary-cyclic %d %s) " | |
1623 "(diary-block %s %s))") | |
1624 (* interval 7) | |
1625 dtstart-conv | |
1626 dtstart-conv | |
1627 (if count until-1-conv until-conv) | |
1628 )) | |
1629 (setq result | |
1630 (format "%%%%(and (diary-cyclic %d %s))" | |
1631 (* interval 7) | |
1632 dtstart-conv)))) | |
1633 ;; weekly and not all-day | |
1634 (let* ((byday (cadr (assoc 'BYDAY rrule-props))) | |
1635 (weekday | |
1636 (icalendar--get-weekday-number byday))) | |
1637 (icalendar--dmsg "weekly not-all-day") | |
1638 (if until | |
1639 (setq result | |
1640 (format | |
1641 (concat "%%%%(and " | |
1642 "(diary-cyclic %d %s) " | |
1643 "(diary-block %s %s)) " | |
1644 "%s%s%s") | |
1645 (* interval 7) | |
1646 dtstart-conv | |
1647 dtstart-conv | |
1648 until-conv | |
1649 (or start-t "") | |
1650 (if end-t "-" "") (or end-t ""))) | |
1651 ;; no limit | |
1652 ;; FIXME!!!! | |
1653 ;; DTSTART;VALUE=DATE-TIME:20030919T090000 | |
1654 ;; DTEND;VALUE=DATE-TIME:20030919T113000 | |
1655 (setq result | |
1656 (format | |
1657 "%%%%(and (diary-cyclic %s %s)) %s%s%s" | |
1658 (* interval 7) | |
1659 dtstart-conv | |
1660 (or start-t "") | |
1661 (if end-t "-" "") (or end-t ""))))))) | |
1662 ;; yearly | |
1663 ((string-equal frequency "YEARLY") | |
1664 (icalendar--dmsg "yearly") | |
1665 (if until | |
1666 (setq result (format | |
1667 (concat "%%%%(and (diary-date %s %s t) " | |
1668 "(diary-block %s %s)) %s%s%s") | |
1669 (if european-calendar-style (nth 3 dtstart-dec) | |
1670 (nth 4 dtstart-dec)) | |
1671 (if european-calendar-style (nth 4 dtstart-dec) | |
1672 (nth 3 dtstart-dec)) | |
1673 dtstart-conv | |
1674 until-conv | |
1675 (or start-t "") | |
1676 (if end-t "-" "") (or end-t ""))) | |
1677 (setq result (format | |
1678 "%%%%(and (diary-anniversary %s)) %s%s%s" | |
1679 dtstart-conv | |
1680 (or start-t "") | |
1681 (if end-t "-" "") (or end-t ""))))) | |
1682 ;; monthly | |
1683 ((string-equal frequency "MONTHLY") | |
1684 (icalendar--dmsg "monthly") | |
1685 (setq result | |
1686 (format | |
1687 "%%%%(and (diary-date %s %s %s) (diary-block %s %s)) %s%s%s" | |
1688 (if european-calendar-style (nth 3 dtstart-dec) "t") | |
1689 (if european-calendar-style "t" (nth 3 dtstart-dec)) | |
1690 "t" | |
1691 dtstart-conv | |
1692 (if until | |
1693 until-conv | |
1694 "1 1 9999") ;; FIXME: should be unlimited | |
1695 (or start-t "") | |
1696 (if end-t "-" "") (or end-t "")))) | |
1697 ;; daily | |
1698 ((and (string-equal frequency "DAILY")) | |
1699 (if until | |
1700 (setq result | |
1701 (format | |
1702 (concat "%%%%(and (diary-cyclic %s %s) " | |
1703 "(diary-block %s %s)) %s%s%s") | |
1704 interval dtstart-conv dtstart-conv | |
1705 (if count until-1-conv until-conv) | |
1706 (or start-t "") | |
1707 (if end-t "-" "") (or end-t ""))) | |
1708 (setq result | |
1709 (format | |
1710 "%%%%(and (diary-cyclic %s %s)) %s%s%s" | |
1711 interval | |
1712 dtstart-conv | |
1713 (or start-t "") | |
1714 (if end-t "-" "") (or end-t "")))))) | |
1715 ;; Handle exceptions from recurrence rules | |
1716 (let ((ex-dates (icalendar--get-event-properties e 'EXDATE))) | |
1717 (while ex-dates | |
1718 (let* ((ex-start (icalendar--decode-isodatetime | |
1719 (car ex-dates))) | |
1720 (ex-d (icalendar--datetime-to-diary-date | |
1721 ex-start))) | |
1722 (setq result | |
1723 (icalendar--rris "^%%(\\(and \\)?" | |
1724 (format | |
1725 "%%%%(and (not (diary-date %s)) " | |
1726 ex-d) | |
1727 result))) | |
1728 (setq ex-dates (cdr ex-dates)))) | |
1729 ;; FIXME: exception rules are not recognized | |
1730 (if (icalendar--get-event-property e 'EXRULE) | |
1731 (setq result | |
1732 (concat result | |
1733 "\n Exception rules: " | |
1734 (icalendar--get-event-properties | |
1735 e 'EXRULE)))) | |
1736 result)) | |
1737 | |
1738 (defun icalendar--convert-non-recurring-all-day-to-diary (event start-d end-d) | |
1739 "Convert non-recurring icalendar EVENT to diary format. | |
1740 | |
1741 DTSTART is the decoded DTSTART property of E. | |
1742 Argument START-D gives the first day. | |
1743 Argument END-D gives the last day." | |
1744 (icalendar--dmsg "non-recurring all-day event") | |
1745 (format "%%%%(and (diary-block %s %s))" start-d end-d)) | |
1746 | |
1747 (defun icalendar--convert-non-recurring-not-all-day-to-diary (event dtstart-dec | |
1748 dtend-dec | |
1749 start-t | |
1750 end-t) | |
1751 "Convert recurring icalendar EVENT to diary format. | |
1752 | |
1753 DTSTART-DEC is the decoded DTSTART property of E. | |
1754 DTEND-DEC is the decoded DTEND property of E. | |
1755 START-T is the event's start time in diary format. | |
1756 END-T is the event's end time in diary format." | |
1757 (icalendar--dmsg "not all day event") | |
1758 (cond (end-t | |
1759 (format "%s %s-%s" | |
1760 (icalendar--datetime-to-diary-date | |
1761 dtstart-dec "/") | |
1762 start-t end-t)) | |
1763 (t | |
1764 (format "%s %s" | |
1765 (icalendar--datetime-to-diary-date | |
1766 dtstart-dec "/") | |
1767 start-t)))) | |
1486 | 1768 |
1487 (defun icalendar--add-diary-entry (string diary-file non-marking | 1769 (defun icalendar--add-diary-entry (string diary-file non-marking |
1488 &optional subject) | 1770 &optional subject) |
1489 "Add STRING to the diary file DIARY-FILE. | 1771 "Add STRING to the diary file DIARY-FILE. |
1490 STRING must be a properly formatted valid diary entry. NON-MARKING | 1772 STRING must be a properly formatted valid diary entry. NON-MARKING |