1 |
;;; icalendar.el --- iCalendar implementation -*-coding: utf-8 -*- |
;;; icalendar.el --- iCalendar implementation -*-coding: utf-8 -*- |
2 |
|
|
3 |
;; Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. |
;; Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. |
4 |
|
|
5 |
;; Author: Ulf Jasper <ulf.jasper@web.de> |
;; Author: Ulf Jasper <ulf.jasper@web.de> |
6 |
;; Created: August 2002 |
;; Created: August 2002 |
90 |
|
|
91 |
;;; Code: |
;;; Code: |
92 |
|
|
93 |
(defconst icalendar-version 0.08 |
(defconst icalendar-version 0.09 |
94 |
"Version number of icalendar.el.") |
"Version number of icalendar.el.") |
95 |
|
|
96 |
;; ====================================================================== |
;; ====================================================================== |
268 |
;; (car (cddr event))) |
;; (car (cddr event))) |
269 |
|
|
270 |
(defun icalendar--get-event-property (event prop) |
(defun icalendar--get-event-property (event prop) |
271 |
"For the given EVENT return the value of the property PROP." |
"For the given EVENT return the value of the first occurence of PROP." |
272 |
(catch 'found |
(catch 'found |
273 |
(let ((props (car (cddr event))) pp) |
(let ((props (car (cddr event))) pp) |
274 |
(while props |
(while props |
278 |
(setq props (cdr props)))) |
(setq props (cdr props)))) |
279 |
nil)) |
nil)) |
280 |
|
|
281 |
|
(defun icalendar--get-event-property-attributes (event prop) |
282 |
|
"For the given EVENT return attributes of the first occurence of PROP." |
283 |
|
(catch 'found |
284 |
|
(let ((props (car (cddr event))) pp) |
285 |
|
(while props |
286 |
|
(setq pp (car props)) |
287 |
|
(if (eq (car pp) prop) |
288 |
|
(throw 'found (cadr pp))) |
289 |
|
(setq props (cdr props)))) |
290 |
|
nil)) |
291 |
|
|
292 |
|
(defun icalendar--get-event-properties (event prop) |
293 |
|
"For the given EVENT return a list of all values of the property PROP." |
294 |
|
(let ((props (car (cddr event))) pp result) |
295 |
|
(while props |
296 |
|
(setq pp (car props)) |
297 |
|
(if (eq (car pp) prop) |
298 |
|
(setq result (cons (car (cddr pp)) result))) |
299 |
|
(setq props (cdr props))) |
300 |
|
result)) |
301 |
|
|
302 |
;; (defun icalendar--set-event-property (event prop new-value) |
;; (defun icalendar--set-event-property (event prop new-value) |
303 |
;; "For the given EVENT set the property PROP to the value NEW-VALUE." |
;; "For the given EVENT set the property PROP to the value NEW-VALUE." |
304 |
;; (catch 'found |
;; (catch 'found |
340 |
(icalendar--get-children (car icalendar) 'VEVENT)) |
(icalendar--get-children (car icalendar) 'VEVENT)) |
341 |
|
|
342 |
(defun icalendar--split-value (value-string) |
(defun icalendar--split-value (value-string) |
343 |
"Splits VALUE-STRING at ';='." |
"Split VALUE-STRING at ';='." |
344 |
(let ((result '()) |
(let ((result '()) |
345 |
param-name param-value) |
param-name param-value) |
346 |
(when value-string |
(when value-string |
445 |
(if (match-beginning 11) |
(if (match-beginning 11) |
446 |
(setq seconds (read (substring isodurationstring |
(setq seconds (read (substring isodurationstring |
447 |
(match-beginning 12) |
(match-beginning 12) |
448 |
(match-end 12))))) |
(match-end 12)))))) |
|
) |
|
449 |
((match-beginning 13) ;weeks only |
((match-beginning 13) ;weeks only |
450 |
(setq days (* 7 (read (substring isodurationstring |
(setq days (* 7 (read (substring isodurationstring |
451 |
(match-beginning 14) |
(match-beginning 14) |
452 |
(match-end 14)))))) |
(match-end 14))))))) |
|
) |
|
453 |
(list seconds minutes hours days months years))) |
(list seconds minutes hours days months years))) |
454 |
;; isodatetimestring == nil |
;; isodatetimestring == nil |
455 |
nil)) |
nil)) |
471 |
;;(or (nth 6 time1) (nth 6 time2)) ;; FIXME? |
;;(or (nth 6 time1) (nth 6 time2)) ;; FIXME? |
472 |
))) |
))) |
473 |
|
|
474 |
(defun icalendar--datetime-to-noneuropean-date (datetime) |
(defun icalendar--datetime-to-noneuropean-date (datetime &optional separator) |
475 |
"Convert the decoded DATETIME to non-european-style format. |
"Convert the decoded DATETIME to non-european-style format. |
476 |
Non-European format: (month day year)." |
Optional argument SEPARATOR gives the separator between month, |
477 |
|
day, and year. If nil a blank character is used as separator. |
478 |
|
Non-European format: \"month day year\"." |
479 |
(if datetime |
(if datetime |
480 |
(list (nth 4 datetime) ;month |
(format "%d%s%d%s%d" (nth 4 datetime) ;month |
481 |
(nth 3 datetime) ;day |
(or separator " ") |
482 |
(nth 5 datetime)) ;year |
(nth 3 datetime) ;day |
483 |
|
(or separator " ") |
484 |
|
(nth 5 datetime)) ;year |
485 |
;; datetime == nil |
;; datetime == nil |
486 |
nil)) |
nil)) |
487 |
|
|
488 |
(defun icalendar--datetime-to-european-date (datetime) |
(defun icalendar--datetime-to-european-date (datetime &optional separator) |
489 |
"Convert the decoded DATETIME to European format. |
"Convert the decoded DATETIME to European format. |
490 |
|
Optional argument SEPARATOR gives the separator between month, |
491 |
|
day, and year. If nil a blank character is used as separator. |
492 |
European format: (day month year). |
European format: (day month year). |
493 |
FIXME" |
FIXME" |
494 |
(if datetime |
(if datetime |
495 |
(format "%d %d %d" (nth 3 datetime) ; day |
(format "%d%s%d%s%d" (nth 3 datetime) ;day |
496 |
|
(or separator " ") |
497 |
(nth 4 datetime) ;month |
(nth 4 datetime) ;month |
498 |
|
(or separator " ") |
499 |
(nth 5 datetime)) ;year |
(nth 5 datetime)) ;year |
500 |
;; datetime == nil |
;; datetime == nil |
501 |
nil)) |
nil)) |
502 |
|
|
503 |
|
(defun icalendar--datetime-to-diary-date (datetime &optional separator) |
504 |
|
"Convert the decoded DATETIME to diary format. |
505 |
|
Optional argument SEPARATOR gives the separator between month, |
506 |
|
day, and year. If nil a blank character is used as separator. |
507 |
|
Call icalendar--datetime-to-(non)-european-date according to |
508 |
|
value of `european-calendar-style'." |
509 |
|
(if european-calendar-style |
510 |
|
(icalendar--datetime-to-european-date datetime separator) |
511 |
|
(icalendar--datetime-to-noneuropean-date datetime separator))) |
512 |
|
|
513 |
(defun icalendar--datetime-to-colontime (datetime) |
(defun icalendar--datetime-to-colontime (datetime) |
514 |
"Extract the time part of a decoded DATETIME into 24-hour format. |
"Extract the time part of a decoded DATETIME into 24-hour format. |
515 |
Note that this silently ignores seconds." |
Note that this silently ignores seconds." |
532 |
|
|
533 |
(defun icalendar--get-weekday-number (abbrevweekday) |
(defun icalendar--get-weekday-number (abbrevweekday) |
534 |
"Return the number for the ABBREVWEEKDAY." |
"Return the number for the ABBREVWEEKDAY." |
535 |
(catch 'found |
(if abbrevweekday |
536 |
(let ((num 0) |
(catch 'found |
537 |
(aw (downcase abbrevweekday))) |
(let ((num 0) |
538 |
(mapc (lambda (day) |
(aw (downcase abbrevweekday))) |
539 |
(let ((d (downcase day))) |
(mapc (lambda (day) |
540 |
(if (string-equal d aw) |
(let ((d (downcase day))) |
541 |
(throw 'found num)) |
(if (string-equal d aw) |
542 |
(setq num (1+ num)))) |
(throw 'found num)) |
543 |
icalendar--weekday-array)) |
(setq num (1+ num)))) |
544 |
|
icalendar--weekday-array))) |
545 |
;; Error: |
;; Error: |
546 |
-1)) |
-1)) |
547 |
|
|
643 |
(format "T%04d00" starttimenum)) |
(format "T%04d00" starttimenum)) |
644 |
nil)) |
nil)) |
645 |
|
|
646 |
(defun icalendar--convert-string-for-export (s) |
(defun icalendar--convert-string-for-export (string) |
647 |
"Escape comma and other critical characters in string S." |
"Escape comma and other critical characters in STRING." |
648 |
(icalendar--rris "," "\\\\," s)) |
(icalendar--rris "," "\\\\," string)) |
649 |
|
|
650 |
(defun icalendar--convert-string-for-import (string) |
(defun icalendar--convert-string-for-import (string) |
651 |
"Remove escape chars for comma, semicolon etc. from STRING." |
"Remove escape chars for comma, semicolon etc. from STRING." |
679 |
All diary entries in the region from MIN to MAX in the current buffer are |
All diary entries in the region from MIN to MAX in the current buffer are |
680 |
converted to iCalendar format. The result is appended to the file |
converted to iCalendar format. The result is appended to the file |
681 |
ICAL-FILENAME. |
ICAL-FILENAME. |
682 |
|
This function attempts to return t if something goes wrong. In this |
683 |
Returns non-nil if an error occurred. In this case an error message is |
case an error string which describes all the errors and problems is |
684 |
written to the buffer ` *icalendar-errors*'." |
written into the buffer `*icalendar-errors*'." |
685 |
(interactive "r |
(interactive "r |
686 |
FExport diary data into iCalendar file: ") |
FExport diary data into iCalendar file: ") |
687 |
(let ((result "") |
(let ((result "") |
697 |
(save-current-buffer |
(save-current-buffer |
698 |
(set-buffer (get-buffer-create " *icalendar-errors*")) |
(set-buffer (get-buffer-create " *icalendar-errors*")) |
699 |
(erase-buffer)) |
(erase-buffer)) |
700 |
|
|
701 |
;; here we go |
;; here we go |
702 |
(save-excursion |
(save-excursion |
703 |
(goto-char min) |
(goto-char min) |
738 |
;; but korganizer seems to expect this... ;( |
;; but korganizer seems to expect this... ;( |
739 |
;; and evolution doesn't understand it... :( |
;; and evolution doesn't understand it... :( |
740 |
;; so... who is wrong?! |
;; so... who is wrong?! |
741 |
";BYMONTH=" (substring startisostring 4 6) |
";BYMONTH=" |
742 |
";BYMONTHDAY=" (substring startisostring 6 8) |
(substring startisostring 4 6) |
743 |
))) |
";BYMONTHDAY=" |
744 |
|
(substring startisostring 6 8)))) |
745 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
746 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents |
747 |
(icalendar--convert-string-for-export |
(concat contents "\nDESCRIPTION:" |
748 |
entry-rest))))) |
(icalendar--convert-string-for-export |
749 |
|
entry-rest))))) |
750 |
;; cyclic events |
;; cyclic events |
751 |
;; %%(diary-cyclic ) |
;; %%(diary-cyclic ) |
752 |
((string-match |
((string-match |
775 |
;; BYSOMETHING here... |
;; BYSOMETHING here... |
776 |
))) |
))) |
777 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
778 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents |
779 |
(icalendar--convert-string-for-export |
(concat contents "\nDESCRIPTION:" |
780 |
entry-rest))))) |
(icalendar--convert-string-for-export |
781 |
|
entry-rest))))) |
782 |
;; diary-date -- FIXME |
;; diary-date -- FIXME |
783 |
((string-match |
((string-match |
784 |
(concat nonmarker |
(concat nonmarker |
796 |
;; block events |
;; block events |
797 |
((string-match |
((string-match |
798 |
(concat nonmarker |
(concat nonmarker |
799 |
"%%(diary-block \\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\) +" |
"%%(diary-block \\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)" |
800 |
"\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*\\(.*\\)") |
" +\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*" |
801 |
|
"\\(.*\\)") |
802 |
entry-main) |
entry-main) |
803 |
(icalendar--dmsg "diary-block %s" entry-main) |
(icalendar--dmsg "diary-block %s" entry-main) |
804 |
(let* ((startstring (substring entry-main (match-beginning 1) |
(let* ((startstring (substring entry-main |
805 |
|
(match-beginning 1) |
806 |
(match-end 1))) |
(match-end 1))) |
807 |
(endstring (substring entry-main (match-beginning 2) |
(endstring (substring entry-main |
808 |
|
(match-beginning 2) |
809 |
(match-end 2))) |
(match-end 2))) |
810 |
(summary (icalendar--convert-string-for-export |
(summary (icalendar--convert-string-for-export |
811 |
(substring entry-main (match-beginning 3) |
(substring entry-main (match-beginning 3) |
817 |
(setq contents |
(setq contents |
818 |
(concat "\nDTSTART;VALUE=DATE:" startisostring |
(concat "\nDTSTART;VALUE=DATE:" startisostring |
819 |
"\nDTEND;VALUE=DATE:" endisostring |
"\nDTEND;VALUE=DATE:" endisostring |
820 |
"\nSUMMARY:" summary |
"\nSUMMARY:" summary)) |
|
)) |
|
821 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
822 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents |
823 |
(icalendar--convert-string-for-export |
(concat contents "\nDESCRIPTION:" |
824 |
entry-rest)))))) |
(icalendar--convert-string-for-export |
825 |
|
entry-rest)))))) |
826 |
;; other sexp diary entries -- FIXME |
;; other sexp diary entries -- FIXME |
827 |
((string-match |
((string-match |
828 |
(concat nonmarker |
(concat nonmarker |
835 |
((and (string-match |
((and (string-match |
836 |
(concat nonmarker |
(concat nonmarker |
837 |
"\\([a-z]+\\)\\s-+" |
"\\([a-z]+\\)\\s-+" |
838 |
"\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" |
"\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)" |
839 |
|
"\\([ap]m\\)?" |
840 |
"\\(-0?" |
"\\(-0?" |
841 |
"\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" |
"\\([1-9][0-9]?:[0-9][0-9]\\)" |
842 |
|
"\\([ap]m\\)?\\)?" |
843 |
"\\)?" |
"\\)?" |
844 |
"\\s-*\\(.*\\)$") |
"\\s-*\\(.*\\)$") |
845 |
entry-main) |
entry-main) |
846 |
(icalendar--get-weekday-abbrev |
(icalendar--get-weekday-abbrev |
847 |
(substring entry-main (match-beginning 1) (match-end 1)))) |
(substring entry-main (match-beginning 1) |
848 |
|
(match-end 1)))) |
849 |
(icalendar--dmsg "weekly %s" entry-main) |
(icalendar--dmsg "weekly %s" entry-main) |
850 |
(let* ((day (icalendar--get-weekday-abbrev |
(let* ((day (icalendar--get-weekday-abbrev |
851 |
(substring entry-main (match-beginning 1) |
(substring entry-main (match-beginning 1) |
877 |
(match-end 8))))) |
(match-end 8))))) |
878 |
(when starttimestring |
(when starttimestring |
879 |
(unless endtimestring |
(unless endtimestring |
880 |
(let ((time (read (icalendar--rris "^T0?" "" |
(let ((time (read |
881 |
starttimestring)))) |
(icalendar--rris "^T0?" "" |
882 |
(setq endtimestring (format "T%06d" (+ 10000 time)))))) |
starttimestring)))) |
883 |
|
(setq endtimestring (format "T%06d" |
884 |
|
(+ 10000 time)))))) |
885 |
(setq contents |
(setq contents |
886 |
(concat "\nDTSTART;" |
(concat "\nDTSTART;" |
887 |
(if starttimestring |
(if starttimestring |
904 |
(if endtimestring 2 3))) |
(if endtimestring 2 3))) |
905 |
(or endtimestring "") |
(or endtimestring "") |
906 |
"\nSUMMARY:" summary |
"\nSUMMARY:" summary |
907 |
"\nRRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=" day |
"\nRRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=" |
908 |
))) |
day))) |
909 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
910 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents |
911 |
(icalendar--convert-string-for-export |
(concat contents "\nDESCRIPTION:" |
912 |
entry-rest))))) |
(icalendar--convert-string-for-export |
913 |
|
entry-rest))))) |
914 |
;; yearly by day |
;; yearly by day |
915 |
;; 1 May Tag der Arbeit |
;; 1 May Tag der Arbeit |
916 |
((string-match |
((string-match |
929 |
(icalendar--dmsg "yearly %s" entry-main) |
(icalendar--dmsg "yearly %s" entry-main) |
930 |
(let* ((daypos (if european-calendar-style 1 2)) |
(let* ((daypos (if european-calendar-style 1 2)) |
931 |
(monpos (if european-calendar-style 2 1)) |
(monpos (if european-calendar-style 2 1)) |
932 |
(day (read (substring entry-main (match-beginning daypos) |
(day (read (substring entry-main |
933 |
|
(match-beginning daypos) |
934 |
(match-end daypos)))) |
(match-end daypos)))) |
935 |
(month (icalendar--get-month-number |
(month (icalendar--get-month-number |
936 |
(substring entry-main (match-beginning monpos) |
(substring entry-main |
937 |
|
(match-beginning monpos) |
938 |
(match-end monpos)))) |
(match-end monpos)))) |
939 |
(starttimestring (icalendar--diarytime-to-isotime |
(starttimestring (icalendar--diarytime-to-isotime |
940 |
(if (match-beginning 4) |
(if (match-beginning 4) |
963 |
(match-end 9))))) |
(match-end 9))))) |
964 |
(when starttimestring |
(when starttimestring |
965 |
(unless endtimestring |
(unless endtimestring |
966 |
(let ((time (read (icalendar--rris "^T0?" "" |
(let ((time (read |
967 |
starttimestring)))) |
(icalendar--rris "^T0?" "" |
968 |
(setq endtimestring (format "T%06d" (+ 10000 time)))))) |
starttimestring)))) |
969 |
|
(setq endtimestring (format "T%06d" |
970 |
|
(+ 10000 time)))))) |
971 |
(setq contents |
(setq contents |
972 |
(concat "\nDTSTART;" |
(concat "\nDTSTART;" |
973 |
(if starttimestring "VALUE=DATE-TIME:" |
(if starttimestring "VALUE=DATE-TIME:" |
979 |
"VALUE=DATE:") |
"VALUE=DATE:") |
980 |
;; end is not included! shift by one day |
;; end is not included! shift by one day |
981 |
(icalendar--date-to-isodate |
(icalendar--date-to-isodate |
982 |
(list month day 1900) (if endtimestring 0 1)) |
(list month day 1900) |
983 |
|
(if endtimestring 0 1)) |
984 |
(or endtimestring "") |
(or endtimestring "") |
985 |
"\nSUMMARY:" |
"\nSUMMARY:" |
986 |
summary |
summary |
987 |
"\nRRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=" |
"\nRRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=" |
988 |
(format "%2d" month) |
(format "%2d" month) |
989 |
";BYMONTHDAY=" |
";BYMONTHDAY=" |
990 |
(format "%2d" day) |
(format "%2d" day)))) |
|
))) |
|
991 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
992 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents |
993 |
(icalendar--convert-string-for-export |
(concat contents "\nDESCRIPTION:" |
994 |
entry-rest))))) |
(icalendar--convert-string-for-export |
995 |
|
entry-rest))))) |
996 |
;; "ordinary" events, start and end time given |
;; "ordinary" events, start and end time given |
997 |
;; 1 Feb 2003 Hs Hochzeitsfeier, Dreieich |
;; 1 Feb 2003 Hs Hochzeitsfeier, Dreieich |
998 |
((string-match |
((string-match |
1038 |
(error "Could not parse date")) |
(error "Could not parse date")) |
1039 |
(when starttimestring |
(when starttimestring |
1040 |
(unless endtimestring |
(unless endtimestring |
1041 |
(let ((time (read (icalendar--rris "^T0?" "" |
(let ((time |
1042 |
starttimestring)))) |
(read (icalendar--rris "^T0?" "" |
1043 |
(setq endtimestring (format "T%06d" (+ 10000 time)))))) |
starttimestring)))) |
1044 |
|
(setq endtimestring (format "T%06d" |
1045 |
|
(+ 10000 time)))))) |
1046 |
(setq contents (concat |
(setq contents (concat |
1047 |
"\nDTSTART;" |
"\nDTSTART;" |
1048 |
(if starttimestring "VALUE=DATE-TIME:" |
(if starttimestring "VALUE=DATE-TIME:" |
1062 |
summary)) |
summary)) |
1063 |
;; could not parse the date |
;; could not parse the date |
1064 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
1065 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents |
1066 |
(icalendar--convert-string-for-export |
(concat contents "\nDESCRIPTION:" |
1067 |
entry-rest)))))) |
(icalendar--convert-string-for-export |
1068 |
|
entry-rest)))))) |
1069 |
;; everything else |
;; everything else |
1070 |
(t |
(t |
1071 |
;; Oops! what's that? |
;; Oops! what's that? |
1082 |
entry-main)))))) |
entry-main)))))) |
1083 |
|
|
1084 |
;; we're done, insert everything into the file |
;; we're done, insert everything into the file |
1085 |
(let ((coding-system-for-write 'utf8)) |
(save-current-buffer |
1086 |
(set-buffer (find-file ical-filename)) |
(let ((coding-system-for-write 'utf8)) |
1087 |
(goto-char (point-max)) |
(set-buffer (find-file ical-filename)) |
1088 |
(insert "BEGIN:VCALENDAR") |
(goto-char (point-max)) |
1089 |
(insert "\nPRODID:-//Emacs//NONSGML icalendar.el//EN") |
(insert "BEGIN:VCALENDAR") |
1090 |
(insert "\nVERSION:2.0") |
(insert "\nPRODID:-//Emacs//NONSGML icalendar.el//EN") |
1091 |
(insert result) |
(insert "\nVERSION:2.0") |
1092 |
(insert "\nEND:VCALENDAR\n"))) |
(insert result) |
1093 |
|
(insert "\nEND:VCALENDAR\n") |
1094 |
|
;; save the diary file |
1095 |
|
(save-buffer)))) |
1096 |
found-error)) |
found-error)) |
1097 |
|
|
1098 |
;; ====================================================================== |
;; ====================================================================== |
1108 |
Optional argument NON-MARKING determines whether events are created as |
Optional argument NON-MARKING determines whether events are created as |
1109 |
non-marking or not." |
non-marking or not." |
1110 |
(interactive "fImport iCalendar data from file: |
(interactive "fImport iCalendar data from file: |
1111 |
Finto diary file: |
Finto diary file: |
1112 |
p") |
p") |
1113 |
;; clean up the diary file |
;; clean up the diary file |
1114 |
(save-current-buffer |
(save-current-buffer |
1132 |
NON-MARKING determines whether diary events are created as |
NON-MARKING determines whether diary events are created as |
1133 |
non-marking. |
non-marking. |
1134 |
|
|
1135 |
This function attempts to notify about problems that occur when |
Return code t means that importing worked well, return code nil |
1136 |
reading, parsing, or converting iCalendar data!" |
means that an error has occured. Error messages will be in the |
1137 |
|
buffer `*icalendar-errors*'." |
1138 |
(interactive) |
(interactive) |
1139 |
(save-current-buffer |
(save-current-buffer |
1140 |
;; prepare ical |
;; prepare ical |
1160 |
(set-buffer (find-buffer-visiting diary-file)) |
(set-buffer (find-buffer-visiting diary-file)) |
1161 |
(save-buffer))) |
(save-buffer))) |
1162 |
(message "Converting icalendar...done") |
(message "Converting icalendar...done") |
1163 |
(if (and ical-errors (y-or-n-p |
;; return t if no error occured |
1164 |
(concat "Something went wrong -- " |
(not ical-errors)) |
|
"do you want to see the " |
|
|
"error log? "))) |
|
|
(switch-to-buffer " *icalendar-errors*"))) |
|
1165 |
(message |
(message |
1166 |
"Current buffer does not contain icalendar contents!")))) |
"Current buffer does not contain icalendar contents!") |
1167 |
|
;; return nil, i.e. import did not work |
1168 |
|
nil))) |
1169 |
|
|
1170 |
(defalias 'icalendar-extract-ical-from-buffer 'icalendar-import-buffer) |
(defalias 'icalendar-extract-ical-from-buffer 'icalendar-import-buffer) |
1171 |
(make-obsolete 'icalendar-extract-ical-from-buffer 'icalendar-import-buffer) |
(make-obsolete 'icalendar-extract-ical-from-buffer 'icalendar-import-buffer) |
1225 |
(condition-case error-val |
(condition-case error-val |
1226 |
(let* ((dtstart (icalendar--decode-isodatetime |
(let* ((dtstart (icalendar--decode-isodatetime |
1227 |
(icalendar--get-event-property e 'DTSTART))) |
(icalendar--get-event-property e 'DTSTART))) |
1228 |
(start-d (calendar-date-string |
(start-d (icalendar--datetime-to-diary-date |
1229 |
(icalendar--datetime-to-noneuropean-date |
dtstart)) |
|
dtstart) |
|
|
t t)) |
|
1230 |
(start-t (icalendar--datetime-to-colontime dtstart)) |
(start-t (icalendar--datetime-to-colontime dtstart)) |
1231 |
(dtend (icalendar--decode-isodatetime |
(dtend (icalendar--decode-isodatetime |
1232 |
(icalendar--get-event-property e 'DTEND))) |
(icalendar--get-event-property e 'DTEND))) |
1239 |
(rdate (icalendar--get-event-property e 'RDATE)) |
(rdate (icalendar--get-event-property e 'RDATE)) |
1240 |
(duration (icalendar--get-event-property e 'DURATION))) |
(duration (icalendar--get-event-property e 'DURATION))) |
1241 |
(icalendar--dmsg "%s: %s" start-d subject) |
(icalendar--dmsg "%s: %s" start-d subject) |
1242 |
|
;; check whether start-time is missing |
1243 |
|
(if (and (icalendar--get-event-property-attributes |
1244 |
|
e 'DTSTART) |
1245 |
|
(string= (cadr (icalendar--get-event-property-attributes |
1246 |
|
e 'DTSTART)) |
1247 |
|
"DATE")) |
1248 |
|
(setq start-t nil)) |
1249 |
(when duration |
(when duration |
1250 |
(let ((dtend2 (icalendar--add-decoded-times |
(let ((dtend2 (icalendar--add-decoded-times |
1251 |
dtstart |
dtstart |
1255 |
subject)) |
subject)) |
1256 |
(setq dtend dtend2))) |
(setq dtend dtend2))) |
1257 |
(setq end-d (if dtend |
(setq end-d (if dtend |
1258 |
(calendar-date-string |
(icalendar--datetime-to-diary-date dtend) |
|
(icalendar--datetime-to-noneuropean-date |
|
|
dtend) |
|
|
t t) |
|
1259 |
start-d)) |
start-d)) |
1260 |
(setq end-t (if dtend |
(setq end-t (if dtend |
1261 |
(icalendar--datetime-to-colontime dtend) |
(icalendar--datetime-to-colontime dtend) |
1266 |
(rrule |
(rrule |
1267 |
(icalendar--dmsg "recurring event") |
(icalendar--dmsg "recurring event") |
1268 |
(let* ((rrule-props (icalendar--split-value rrule)) |
(let* ((rrule-props (icalendar--split-value rrule)) |
1269 |
(frequency (car (cdr (assoc 'FREQ rrule-props)))) |
(frequency (cadr (assoc 'FREQ rrule-props))) |
1270 |
(until (car (cdr (assoc 'UNTIL rrule-props)))) |
(until (cadr (assoc 'UNTIL rrule-props))) |
1271 |
(interval (read (car (cdr (assoc 'INTERVAL |
(interval (read (cadr (assoc 'INTERVAL rrule-props))))) |
|
rrule-props)))))) |
|
1272 |
(cond ((string-equal frequency "WEEKLY") |
(cond ((string-equal frequency "WEEKLY") |
1273 |
(if (not start-t) |
(if (not start-t) |
1274 |
(progn |
(progn |
1275 |
;; weekly and all-day |
;; weekly and all-day |
1276 |
(icalendar--dmsg "weekly all-day") |
(icalendar--dmsg "weekly all-day") |
1277 |
|
(if until |
1278 |
|
(let ((fro |
1279 |
|
(icalendar--datetime-to-diary-date |
1280 |
|
(icalendar--decode-isodatetime |
1281 |
|
(icalendar--get-event-property |
1282 |
|
e |
1283 |
|
'DTSTART)))) |
1284 |
|
(unt |
1285 |
|
(icalendar--datetime-to-diary-date |
1286 |
|
(icalendar--decode-isodatetime |
1287 |
|
until)))) |
1288 |
(setq diary-string |
(setq diary-string |
1289 |
(format |
(format |
1290 |
"%%%%(diary-cyclic %d %s)" |
(concat "%%%%(and " |
1291 |
|
"(diary-cyclic %d %s) " |
1292 |
|
"(diary-block %s %s))") |
1293 |
(* interval 7) |
(* interval 7) |
1294 |
(icalendar--datetime-to-european-date |
(icalendar--datetime-to-diary-date |
1295 |
dtstart)))) |
dtstart) |
1296 |
|
(icalendar--datetime-to-diary-date |
1297 |
|
dtstart) |
1298 |
|
(icalendar--datetime-to-diary-date |
1299 |
|
(icalendar--decode-isodatetime |
1300 |
|
until))))) |
1301 |
|
(setq diary-string |
1302 |
|
(format "%%%%(and (diary-cyclic %d %s))" |
1303 |
|
(* interval 7) |
1304 |
|
(icalendar--datetime-to-diary-date |
1305 |
|
dtstart)))) |
1306 |
|
(setq event-ok t)) |
1307 |
;; weekly and not all-day |
;; weekly and not all-day |
1308 |
(let* ((byday (cadr (assoc 'BYDAY rrule-props))) |
(let* ((byday (cadr (assoc 'BYDAY rrule-props))) |
1309 |
(weekday |
(weekday |
1310 |
(icalendar--get-weekday-number byday))) |
(icalendar--get-weekday-number byday))) |
1311 |
(icalendar--dmsg "weekly not-all-day") |
(icalendar--dmsg "weekly not-all-day") |
1312 |
(if (> weekday -1) |
(if until |
1313 |
(setq diary-string |
(let ((fro |
1314 |
(format "%s %s%s%s" |
(icalendar--datetime-to-diary-date |
1315 |
(aref calendar-day-name-array |
(icalendar--decode-isodatetime |
1316 |
weekday) |
(icalendar--get-event-property |
1317 |
start-t (if end-t "-" "") |
e |
1318 |
(or end-t ""))) |
'DTSTART)))) |
1319 |
|
(unt |
1320 |
|
(icalendar--datetime-to-diary-date |
1321 |
|
(icalendar--decode-isodatetime |
1322 |
|
until)))) |
1323 |
|
(setq diary-string |
1324 |
|
(format |
1325 |
|
(concat "%%%%(and " |
1326 |
|
"(diary-cyclic %d %s) " |
1327 |
|
"(diary-block %s %s)) " |
1328 |
|
"%s%s%s") |
1329 |
|
(* interval 7) |
1330 |
|
(icalendar--datetime-to-diary-date |
1331 |
|
dtstart) |
1332 |
|
(icalendar--datetime-to-diary-date |
1333 |
|
dtstart) |
1334 |
|
(icalendar--datetime-to-diary-date |
1335 |
|
(icalendar--decode-isodatetime |
1336 |
|
until)) |
1337 |
|
start-t |
1338 |
|
(if end-t "-" "") (or end-t "")))) |
1339 |
|
;; no limit |
1340 |
;; FIXME!!!! |
;; FIXME!!!! |
1341 |
;; DTSTART;VALUE=DATE-TIME:20030919T090000 |
;; DTSTART;VALUE=DATE-TIME:20030919T090000 |
1342 |
;; DTEND;VALUE=DATE-TIME:20030919T113000 |
;; DTEND;VALUE=DATE-TIME:20030919T113000 |
1343 |
(setq diary-string |
(setq diary-string |
1344 |
(format |
(format |
1345 |
"%%%%(diary-cyclic %s %s) %s%s%s" |
"%%%%(and (diary-cyclic %s %s)) %s%s%s" |
1346 |
(* interval 7) |
(* interval 7) |
1347 |
(icalendar--datetime-to-european-date |
(icalendar--datetime-to-diary-date |
1348 |
dtstart) |
dtstart) |
1349 |
start-t (if end-t "-" "") (or end-t "")))) |
start-t |
1350 |
|
(if end-t "-" "") (or end-t "")))) |
1351 |
(setq event-ok t)))) |
(setq event-ok t)))) |
1352 |
;; yearly |
;; yearly |
1353 |
((string-equal frequency "YEARLY") |
((string-equal frequency "YEARLY") |
1354 |
(icalendar--dmsg "yearly") |
(icalendar--dmsg "yearly") |
1355 |
(setq diary-string |
(setq diary-string |
1356 |
(format |
(format |
1357 |
"%%%%(diary-anniversary %s)" |
"%%%%(and (diary-anniversary %s))" |
1358 |
(icalendar--datetime-to-european-date dtstart))) |
(icalendar--datetime-to-diary-date dtstart))) |
1359 |
(setq event-ok t)) |
(setq event-ok t)) |
1360 |
;; FIXME: war auskommentiert: |
;; FIXME: war auskommentiert: |
1361 |
((and (string-equal frequency "DAILY") |
((and (string-equal frequency "DAILY") |
1363 |
;;(not start-t) |
;;(not start-t) |
1364 |
;;(not end-t) |
;;(not end-t) |
1365 |
) |
) |
1366 |
(let ((ds (icalendar--datetime-to-noneuropean-date |
(let ((ds (icalendar--datetime-to-diary-date |
1367 |
(icalendar--decode-isodatetime |
(icalendar--decode-isodatetime |
1368 |
(icalendar--get-event-property e |
(icalendar--get-event-property |
1369 |
'DTSTART)))) |
e 'DTSTART)))) |
1370 |
(de (icalendar--datetime-to-noneuropean-date |
(de (icalendar--datetime-to-diary-date |
1371 |
(icalendar--decode-isodatetime |
(icalendar--decode-isodatetime |
1372 |
until)))) |
until)))) |
1373 |
(setq diary-string |
(setq diary-string |
1374 |
(format |
(format |
1375 |
"%%%%(diary-block %d %d %d %d %d %d)" |
"%%%%(and (diary-block %s %s))" |
1376 |
(nth 1 ds) (nth 0 ds) (nth 2 ds) |
ds de))) |
1377 |
(nth 1 de) (nth 0 de) (nth 2 de)))) |
(setq event-ok t)))) |
1378 |
(setq event-ok t))) |
;; Handle exceptions from recurrence rules |
1379 |
)) |
(let ((ex-dates (icalendar--get-event-properties e |
1380 |
|
'EXDATE))) |
1381 |
|
(while ex-dates |
1382 |
|
(let* ((ex-start (icalendar--decode-isodatetime |
1383 |
|
(car ex-dates))) |
1384 |
|
(ex-d (icalendar--datetime-to-diary-date |
1385 |
|
ex-start))) |
1386 |
|
(setq diary-string |
1387 |
|
(icalendar--rris "^%%(\\(and \\)?" |
1388 |
|
(format |
1389 |
|
"%%%%(and (not (diary-date %s)) " |
1390 |
|
ex-d) |
1391 |
|
diary-string))) |
1392 |
|
(setq ex-dates (cdr ex-dates)))) |
1393 |
|
;; FIXME: exception rules are not recognized |
1394 |
|
(if (icalendar--get-event-property e 'EXRULE) |
1395 |
|
(setq diary-string |
1396 |
|
(concat diary-string |
1397 |
|
"\n Exception rules: " |
1398 |
|
(icalendar--get-event-properties |
1399 |
|
e 'EXRULE))))) |
1400 |
(rdate |
(rdate |
1401 |
(icalendar--dmsg "rdate event") |
(icalendar--dmsg "rdate event") |
1402 |
(setq diary-string "") |
(setq diary-string "") |
1409 |
;; long event |
;; long event |
1410 |
((not (string= start-d end-d)) |
((not (string= start-d end-d)) |
1411 |
(icalendar--dmsg "non-recurring event") |
(icalendar--dmsg "non-recurring event") |
1412 |
(let ((ds (icalendar--datetime-to-noneuropean-date dtstart)) |
(let ((ds (icalendar--datetime-to-diary-date dtstart)) |
1413 |
(de (icalendar--datetime-to-noneuropean-date dtend))) |
(de (icalendar--datetime-to-diary-date dtend))) |
1414 |
(setq diary-string |
(setq diary-string |
1415 |
(format "%%%%(diary-block %d %d %d %d %d %d)" |
(format "%%%%(and (diary-block %s %s))" |
1416 |
(nth 1 ds) (nth 0 ds) (nth 2 ds) |
ds de))) |
|
(nth 1 de) (nth 0 de) (nth 2 de)))) |
|
1417 |
(setq event-ok t)) |
(setq event-ok t)) |
1418 |
;; not all-day |
;; not all-day |
1419 |
((and start-t (or (not end-t) |
((and start-t (or (not end-t) |
1420 |
(not (string= start-t end-t)))) |
(not (string= start-t end-t)))) |
1421 |
(icalendar--dmsg "not all day event") |
(icalendar--dmsg "not all day event") |
1422 |
(cond (end-t |
(cond (end-t |
1423 |
(setq diary-string (format "%s %s-%s" start-d |
(setq diary-string |
1424 |
start-t end-t))) |
(format "%s %s-%s" |
1425 |
|
(icalendar--datetime-to-diary-date |
1426 |
|
dtstart "/") |
1427 |
|
start-t end-t))) |
1428 |
(t |
(t |
1429 |
(setq diary-string (format "%s %s" start-d |
(setq diary-string |
1430 |
start-t)))) |
(format "%s %s" |
1431 |
|
(icalendar--datetime-to-diary-date |
1432 |
|
dtstart "/") |
1433 |
|
start-t)))) |
1434 |
(setq event-ok t)) |
(setq event-ok t)) |
1435 |
;; all-day event |
;; all-day event |
1436 |
(t |
(t |
1437 |
(icalendar--dmsg "all day event") |
(icalendar--dmsg "all day event") |
1438 |
(setq diary-string start-d) |
(setq diary-string (icalendar--datetime-to-diary-date |
1439 |
|
dtstart "/")) |
1440 |
(setq event-ok t))) |
(setq event-ok t))) |
1441 |
;; add all other elements unless the user doesn't want to have |
;; add all other elements unless the user doesn't want to have |
1442 |
;; them |
;; them |
1453 |
(setq error-string |
(setq error-string |
1454 |
(format "%s\nCannot handle this event:%s" |
(format "%s\nCannot handle this event:%s" |
1455 |
error-string e)))) |
error-string e)))) |
1456 |
|
;; FIXME: inform user about ignored event properties |
1457 |
;; handle errors |
;; handle errors |
1458 |
(error |
(error |
1459 |
(message "Ignoring event \"%s\"" e) |
(message "Ignoring event \"%s\"" e) |
1460 |
(setq found-error t) |
(setq found-error t) |
1461 |
(setq error-string (format "%s\nCannot handle this event: %s" |
(setq error-string (format "%s\n%s\nCannot handle this event: %s" |
1462 |
error-string e))))) |
error-val error-string e)) |
1463 |
|
(message error-string)))) |
1464 |
(if found-error |
(if found-error |
1465 |
(save-current-buffer |
(save-current-buffer |
1466 |
(set-buffer (get-buffer-create " *icalendar-errors*")) |
(set-buffer (get-buffer-create " *icalendar-errors*")) |
1477 |
SUBJECT is not nil it must be a string that gives the subject of the |
SUBJECT is not nil it must be a string that gives the subject of the |
1478 |
entry. In this case the user will be asked whether he wants to insert |
entry. In this case the user will be asked whether he wants to insert |
1479 |
the entry." |
the entry." |
1480 |
(when (or (not subject) ; |
(when (or (not subject) |
1481 |
(y-or-n-p (format "Add appointment for `%s' to diary? " |
(y-or-n-p (format "Add appointment for `%s' to diary? " |
1482 |
subject))) |
subject))) |
1483 |
(when subject |
(when subject |