1 |
;;; icalendar.el --- iCalendar implementation |
;;; icalendar.el --- iCalendar implementation -*-coding: utf-8 -*- |
2 |
|
|
3 |
;; Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. |
;; Copyright (C) 2002, 2003, 2004 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 |
7 |
;; Keywords: calendar |
;; Keywords: calendar |
8 |
;; Human-Keywords: calendar, diary, iCalendar, vCalendar |
;; Human-Keywords: calendar, diary, iCalendar, vCalendar |
9 |
|
|
10 |
;; This file is part of GNU Emacs. |
;; This file is part of GNU Emacs. |
31 |
|
|
32 |
;;; History: |
;;; History: |
33 |
|
|
34 |
;; 0.06 Bugfixes regarding icalendar-import-format-*. |
;; 0.07: Renamed commands! |
35 |
;; Fix in icalendar-convert-diary-to-ical -- thanks to Philipp Grau. |
;; icalendar-extract-ical-from-buffer -> icalendar-import-buffer |
36 |
|
;; icalendar-convert-diary-to-ical -> icalendar-export-file |
37 |
|
;; Naming scheme: icalendar-.* = user command; icalendar--.* = |
38 |
|
;; internal. |
39 |
|
;; Added icalendar-export-region. |
40 |
|
;; The import and export commands do not clear their target file, |
41 |
|
;; but append their results to the target file. |
42 |
|
;; I18n-problems fixed -- use calendar-(month|day)-name-array. |
43 |
|
;; Fixed problems with export of multi-line diary entries. |
44 |
|
|
45 |
|
;; 0.06: Bugfixes regarding icalendar-import-format-*. |
46 |
|
;; Fix in icalendar-convert-diary-to-ical -- thanks to Philipp |
47 |
|
;; Grau. |
48 |
|
|
49 |
;; 0.05: New import format scheme: Replaced icalendar-import-prefix-*, |
;; 0.05: New import format scheme: Replaced icalendar-import-prefix-*, |
50 |
;; icalendar-import-ignored-properties, and |
;; icalendar-import-ignored-properties, and |
73 |
;; ====================================================================== |
;; ====================================================================== |
74 |
;; To Do: |
;; To Do: |
75 |
|
|
76 |
;; * Import from ical: |
;; * Import from ical to diary: |
77 |
;; + Need more properties for icalendar-import-format |
;; + Need more properties for icalendar-import-format |
78 |
;; + check vcalendar version |
;; + check vcalendar version |
79 |
;; + check (unknown) elements |
;; + check (unknown) elements |
85 |
;; + error log is incomplete |
;; + error log is incomplete |
86 |
;; + nice to have: #include "webcal://foo.com/some-calendar.ics" |
;; + nice to have: #include "webcal://foo.com/some-calendar.ics" |
87 |
|
|
88 |
;; * Export into ical |
;; * Export from diary to ical |
89 |
;; + diary-date, diary-float, and self-made sexp entries are not |
;; + diary-date, diary-float, and self-made sexp entries are not |
90 |
;; understood |
;; understood |
91 |
;; + timezones, currently all times are local! |
;; + timezones, currently all times are local! |
92 |
|
|
93 |
;; * Other things |
;; * Other things |
|
;; + defcustom icalendar-import-ignored-properties does not work with |
|
|
;; XEmacs. |
|
94 |
;; + clean up all those date/time parsing functions |
;; + clean up all those date/time parsing functions |
95 |
;; + Handle todo items? |
;; + Handle todo items? |
96 |
;; + Check iso 8601 for datetime and period |
;; + Check iso 8601 for datetime and period |
97 |
;; + Which chars to (un)escape? |
;; + Which chars to (un)escape? |
|
;; + Time to find out how the profiler works? |
|
98 |
|
|
99 |
|
|
100 |
;;; Code: |
;;; Code: |
101 |
|
|
102 |
(defconst icalendar-version 0.06 |
(defconst icalendar-version 0.07 |
103 |
"Version number of icalendar.el.") |
"Version number of icalendar.el.") |
104 |
|
|
105 |
;; ====================================================================== |
;; ====================================================================== |
169 |
;; NO USER SERVICABLE PARTS BELOW THIS LINE |
;; NO USER SERVICABLE PARTS BELOW THIS LINE |
170 |
;; ====================================================================== |
;; ====================================================================== |
171 |
|
|
172 |
(defconst icalendar-weekdayabbrev-table |
(defconst icalendar--weekday-array ["SU" "MO" "TU" "WE" "TH" "FR" "SA"]) |
|
'(("mon\\(day\\)?" . "MO") |
|
|
("tue\\(sday\\)?" . "TU") |
|
|
("wed\\(nesday\\)?" . "WE") |
|
|
("thu\\(rsday\\)?" . "TH") |
|
|
("fri\\(day\\)?" . "FR") |
|
|
("sat\\(urday\\)?" . "SA") |
|
|
("sun\\(day\\)?" . "SU")) |
|
|
"Translation table for weekdays.") |
|
|
|
|
|
(defconst icalendar-monthnumber-table |
|
|
'(("^jan\\(uar\\)?y?$" . 1) |
|
|
("^feb\\(ruar\\)?y?$" . 2) |
|
|
("^mar\\(ch\\)?\\|märz?$" . 3) |
|
|
("^apr\\(il\\)?$" . 4) |
|
|
("^ma[iy]$" . 5) |
|
|
("^jun[ie]?$" . 6) |
|
|
("^jul[iy]?$" . 7) |
|
|
("^aug\\(ust\\)?$" . 8) |
|
|
("^sep\\(tember\\)?$" . 9) |
|
|
("^o[ck]t\\(ober\\)?$" . 10) |
|
|
("^nov\\(ember\\)?$" . 11) |
|
|
("^de[cz]\\(ember\\)?$" . 12)) |
|
|
"Regular expressions for month names. |
|
|
Currently this matches only German and English.") |
|
173 |
|
|
174 |
(defvar icalendar-debug nil ".") |
(defvar icalendar-debug nil ".") |
175 |
|
|
180 |
(require 'appt) |
(require 'appt) |
181 |
|
|
182 |
;; ====================================================================== |
;; ====================================================================== |
183 |
|
;; misc |
184 |
|
;; ====================================================================== |
185 |
|
(defun icalendar--dmsg (&rest args) |
186 |
|
"Print message ARGS if `icalendar-debug' is non-nil." |
187 |
|
(if icalendar-debug |
188 |
|
(apply 'message args))) |
189 |
|
|
190 |
|
;; ====================================================================== |
191 |
;; Core functionality |
;; Core functionality |
192 |
;; Functions for parsing icalendars, importing and so on |
;; Functions for parsing icalendars, importing and so on |
193 |
;; ====================================================================== |
;; ====================================================================== |
194 |
|
|
195 |
(defun icalendar-get-unfolded-buffer (folded-ical-buffer) |
(defun icalendar--get-unfolded-buffer (folded-ical-buffer) |
196 |
"Return a new buffer containing the unfolded contents of a buffer. |
"Return a new buffer containing the unfolded contents of a buffer. |
197 |
Folding is the iCalendar way of wrapping long lines. In the |
Folding is the iCalendar way of wrapping long lines. In the |
198 |
created buffer all occurrences of CR LF BLANK are replaced by the |
created buffer all occurrences of CR LF BLANK are replaced by the |
204 |
(erase-buffer) |
(erase-buffer) |
205 |
(insert-buffer folded-ical-buffer) |
(insert-buffer folded-ical-buffer) |
206 |
(while (re-search-forward "\r?\n[ \t]" nil t) |
(while (re-search-forward "\r?\n[ \t]" nil t) |
207 |
(replace-match "" nil nil)) |
(replace-match "" nil nil))) |
|
) |
|
208 |
unfolded-buffer)) |
unfolded-buffer)) |
209 |
|
|
210 |
;; Replace regexp RE with RP in string ST and return the new string. |
(defsubst icalendar--rris (re rp st) |
211 |
;; This is here for compatibility with XEmacs. |
"Replace regexp RE with RP in string ST and return the new string. |
212 |
(defsubst icalendar-rris (re rp st) |
This is here for compatibility with XEmacs." |
213 |
;; XEmacs: |
;; XEmacs: |
214 |
(if (fboundp 'replace-in-string) |
(if (fboundp 'replace-in-string) |
215 |
(save-match-data ;; apparently XEmacs needs save-match-data |
(save-match-data ;; apparently XEmacs needs save-match-data |
217 |
;; Emacs: |
;; Emacs: |
218 |
(replace-regexp-in-string re rp st))) |
(replace-regexp-in-string re rp st))) |
219 |
|
|
220 |
(defun icalendar-read-element (invalue inparams) |
(defun icalendar--read-element (invalue inparams) |
221 |
"Recursively read the next iCalendar element in the current buffer. |
"Recursively read the next iCalendar element in the current buffer. |
222 |
INVALUE gives the current iCalendar element we are reading. |
INVALUE gives the current iCalendar element we are reading. |
223 |
INPARAMS gives the current parameters..... |
INPARAMS gives the current parameters..... |
225 |
it finds" |
it finds" |
226 |
(let (element children line name params param param-name param-value |
(let (element children line name params param param-name param-value |
227 |
value |
value |
228 |
(continue t)) |
(continue t)) |
229 |
(setq children '()) |
(setq children '()) |
230 |
(while (and continue |
(while (and continue |
231 |
(re-search-forward "^\\([A-Za-z0-9-]+\\)[;:]" nil t)) |
(re-search-forward "^\\([A-Za-z0-9-]+\\)[;:]" nil t)) |
253 |
(error "Oops")) |
(error "Oops")) |
254 |
(forward-char 1) |
(forward-char 1) |
255 |
(re-search-forward "\\(.*\\)\\(\r?\n[ \t].*\\)*" nil t) |
(re-search-forward "\\(.*\\)\\(\r?\n[ \t].*\\)*" nil t) |
256 |
(setq value (icalendar-rris "\r?\n[ \t]" "" (match-string 0))) |
(setq value (icalendar--rris "\r?\n[ \t]" "" (match-string 0))) |
257 |
(setq line (list name params value)) |
(setq line (list name params value)) |
258 |
(cond ((eq name 'BEGIN) |
(cond ((eq name 'BEGIN) |
259 |
(setq children |
(setq children |
260 |
(append children |
(append children |
261 |
(list (icalendar-read-element (intern value) |
(list (icalendar--read-element (intern value) |
262 |
params))))) |
params))))) |
263 |
((eq name 'END) |
((eq name 'END) |
264 |
(setq continue nil)) |
(setq continue nil)) |
265 |
(t |
(t |
272 |
;; helper functions for examining events |
;; helper functions for examining events |
273 |
;; ====================================================================== |
;; ====================================================================== |
274 |
|
|
275 |
(defsubst icalendar-get-all-event-properties (event) |
;;(defsubst icalendar--get-all-event-properties (event) |
276 |
"Return the list of properties in this EVENT." |
;; "Return the list of properties in this EVENT." |
277 |
(car (cddr event))) |
;; (car (cddr event))) |
278 |
|
|
279 |
(defun icalendar-get-event-property (event prop) |
(defun icalendar--get-event-property (event prop) |
280 |
"For the given EVENT return the value of the property PROP." |
"For the given EVENT return the value of the property PROP." |
281 |
(catch 'found |
(catch 'found |
282 |
(let ((props (car (cddr event))) pp) |
(let ((props (car (cddr event))) pp) |
287 |
(setq props (cdr props)))) |
(setq props (cdr props)))) |
288 |
nil)) |
nil)) |
289 |
|
|
290 |
(defun icalendar-set-event-property (event prop new-value) |
;; (defun icalendar--set-event-property (event prop new-value) |
291 |
"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." |
292 |
(catch 'found |
;; (catch 'found |
293 |
(let ((props (car (cddr event))) pp) |
;; (let ((props (car (cddr event))) pp) |
294 |
(while props |
;; (while props |
295 |
(setq pp (car props)) |
;; (setq pp (car props)) |
296 |
(when (eq (car pp) prop) |
;; (when (eq (car pp) prop) |
297 |
(setcdr (cdr pp) new-value) |
;; (setcdr (cdr pp) new-value) |
298 |
(throw 'found (car (cddr pp)))) |
;; (throw 'found (car (cddr pp)))) |
299 |
(setq props (cdr props))) |
;; (setq props (cdr props))) |
300 |
(setq props (car (cddr event))) |
;; (setq props (car (cddr event))) |
301 |
(setcar (cddr event) |
;; (setcar (cddr event) |
302 |
(append props (list (list prop nil new-value))))))) |
;; (append props (list (list prop nil new-value))))))) |
303 |
|
|
304 |
(defun icalendar-get-children (node name) |
(defun icalendar--get-children (node name) |
305 |
"Return all children of the given NODE which have a name NAME. |
"Return all children of the given NODE which have a name NAME. |
306 |
For instance the VCALENDAR node can have VEVENT children as well as VTODO |
For instance the VCALENDAR node can have VEVENT children as well as VTODO |
307 |
children." |
children." |
313 |
(when children |
(when children |
314 |
(let ((subresult |
(let ((subresult |
315 |
(delq nil |
(delq nil |
316 |
(mapcar (lambda (n) |
(mapcar (lambda (n) |
317 |
(icalendar-get-children n name)) |
(icalendar--get-children n name)) |
318 |
children)))) |
children)))) |
319 |
(if subresult |
(if subresult |
320 |
(if result |
(if result |
321 |
(setq result (append result subresult)) |
(setq result (append result subresult)) |
322 |
(setq result subresult))))) |
(setq result subresult))))) |
323 |
result)) |
result)) |
324 |
|
|
325 |
; private |
; private |
326 |
(defun icalendar-all-events (icalendar) |
(defun icalendar--all-events (icalendar) |
327 |
"Return the list of all existing events in the given ICALENDAR." |
"Return the list of all existing events in the given ICALENDAR." |
328 |
(interactive "") |
(icalendar--get-children (car icalendar) 'VEVENT)) |
|
(icalendar-get-children (car icalendar) 'VEVENT)) |
|
329 |
|
|
330 |
(defun icalendar-split-value (value-string) |
(defun icalendar--split-value (value-string) |
331 |
"Splits VALUE-STRING at ';='." |
"Splits VALUE-STRING at ';='." |
332 |
(let ((result '()) |
(let ((result '()) |
333 |
param-name param-value) |
param-name param-value) |
339 |
(insert value-string) |
(insert value-string) |
340 |
(goto-char (point-min)) |
(goto-char (point-min)) |
341 |
(while |
(while |
342 |
(re-search-forward |
(re-search-forward |
343 |
"\\([A-Za-z0-9-]+\\)=\\(\\([^;,:]+\\)\\|\"\\([^\"]+\\)\"\\);?" |
"\\([A-Za-z0-9-]+\\)=\\(\\([^;,:]+\\)\\|\"\\([^\"]+\\)\"\\);?" |
344 |
nil t) |
nil t) |
345 |
(setq param-name (intern (match-string 1))) |
(setq param-name (intern (match-string 1))) |
346 |
(setq param-value (match-string 2)) |
(setq param-value (match-string 2)) |
347 |
(setq result |
(setq result |
348 |
(append result (list (list param-name param-value))))))) |
(append result (list (list param-name param-value))))))) |
349 |
result)) |
result)) |
350 |
|
|
351 |
(defun icalendar-decode-isodatetime (isodatetimestring) |
(defun icalendar--decode-isodatetime (isodatetimestring) |
352 |
"Return ISODATETIMESTRING in format like `decode-time'. |
"Return ISODATETIMESTRING in format like `decode-time'. |
353 |
Converts from ISO-8601 to Emacs representation. If ISODATETIMESTRING |
Converts from ISO-8601 to Emacs representation. If ISODATETIMESTRING |
354 |
specifies UTC time (trailing letter Z) the decoded time is given in |
specifies UTC time (trailing letter Z) the decoded time is given in |
355 |
the local time zone! FIXME: TZID-attributes are ignored....! FIXME: |
the local time zone! FIXME: TZID-attributes are ignored....! FIXME: |
356 |
multiple comma-separated values should be allowed!" |
multiple comma-separated values should be allowed!" |
357 |
(icalendar-dmsg isodatetimestring) |
(icalendar--dmsg isodatetimestring) |
358 |
(if isodatetimestring |
(if isodatetimestring |
359 |
;; day/month/year must be present |
;; day/month/year must be present |
360 |
(let ((year (read (substring isodatetimestring 0 4))) |
(let ((year (read (substring isodatetimestring 0 4))) |
364 |
(minute 0) |
(minute 0) |
365 |
(second 0)) |
(second 0)) |
366 |
(when (> (length isodatetimestring) 12) |
(when (> (length isodatetimestring) 12) |
367 |
;; hour/minute present |
;; hour/minute present |
368 |
(setq hour (read (substring isodatetimestring 9 11))) |
(setq hour (read (substring isodatetimestring 9 11))) |
369 |
(setq minute (read (substring isodatetimestring 11 13)))) |
(setq minute (read (substring isodatetimestring 11 13)))) |
370 |
(when (> (length isodatetimestring) 14) |
(when (> (length isodatetimestring) 14) |
371 |
;; seconds present |
;; seconds present |
372 |
(setq second (read (substring isodatetimestring 13 15)))) |
(setq second (read (substring isodatetimestring 13 15)))) |
373 |
(when (and (> (length isodatetimestring) 15) |
(when (and (> (length isodatetimestring) 15) |
374 |
;; UTC specifier present |
;; UTC specifier present |
375 |
(char-equal ?Z (aref isodatetimestring 15))) |
(char-equal ?Z (aref isodatetimestring 15))) |
376 |
;; if not UTC add current-time-zone offset |
;; if not UTC add current-time-zone offset |
377 |
(setq second (+ (car (current-time-zone)) second))) |
(setq second (+ (car (current-time-zone)) second))) |
386 |
;; isodatetimestring == nil |
;; isodatetimestring == nil |
387 |
nil)) |
nil)) |
388 |
|
|
389 |
(defun icalendar-decode-isoduration (isodurationstring) |
(defun icalendar--decode-isoduration (isodurationstring) |
390 |
"Return ISODURATIONSTRING in format like `decode-time'. |
"Return ISODURATIONSTRING in format like `decode-time'. |
391 |
Converts from ISO-8601 to Emacs representation. If ISODURATIONSTRING |
Converts from ISO-8601 to Emacs representation. If ISODURATIONSTRING |
392 |
specifies UTC time (trailing letter Z) the decoded time is given in |
specifies UTC time (trailing letter Z) the decoded time is given in |
400 |
"\\(\\([0-9]+\\)D\\)" ; days only |
"\\(\\([0-9]+\\)D\\)" ; days only |
401 |
"\\|" |
"\\|" |
402 |
"\\(\\(\\([0-9]+\\)D\\)?T\\(\\([0-9]+\\)H\\)?" ; opt days |
"\\(\\(\\([0-9]+\\)D\\)?T\\(\\([0-9]+\\)H\\)?" ; opt days |
403 |
"\\(\\([0-9]+\\)M\\)?\\(\\([0-9]+\\)S\\)?\\)" ; mand. time |
"\\(\\([0-9]+\\)M\\)?\\(\\([0-9]+\\)S\\)?\\)" ; mand. time |
404 |
"\\|" |
"\\|" |
405 |
"\\(\\([0-9]+\\)W\\)" ; weeks only |
"\\(\\([0-9]+\\)W\\)" ; weeks only |
406 |
"\\)$") isodurationstring) |
"\\)$") isodurationstring) |
410 |
(days 0) |
(days 0) |
411 |
(months 0) |
(months 0) |
412 |
(years 0)) |
(years 0)) |
413 |
(cond |
(cond |
414 |
((match-beginning 2) ;days only |
((match-beginning 2) ;days only |
415 |
(setq days (read (substring isodurationstring |
(setq days (read (substring isodurationstring |
416 |
(match-beginning 3) |
(match-beginning 3) |
417 |
(match-end 3)))) |
(match-end 3)))) |
418 |
(when icalendar-duration-correction |
(when icalendar-duration-correction |
419 |
(setq days (1- days)))) |
(setq days (1- days)))) |
420 |
((match-beginning 4) ;days and time |
((match-beginning 4) ;days and time |
421 |
(if (match-beginning 5) |
(if (match-beginning 5) |
422 |
(setq days (* 7 (read (substring isodurationstring |
(setq days (* 7 (read (substring isodurationstring |
423 |
(match-beginning 6) |
(match-beginning 6) |
424 |
(match-end 6)))))) |
(match-end 6)))))) |
425 |
(if (match-beginning 7) |
(if (match-beginning 7) |
426 |
(setq hours (read (substring isodurationstring |
(setq hours (read (substring isodurationstring |
427 |
(match-beginning 8) |
(match-beginning 8) |
428 |
(match-end 8))))) |
(match-end 8))))) |
429 |
(if (match-beginning 9) |
(if (match-beginning 9) |
430 |
(setq minutes (read (substring isodurationstring |
(setq minutes (read (substring isodurationstring |
431 |
(match-beginning 10) |
(match-beginning 10) |
432 |
(match-end 10))))) |
(match-end 10))))) |
433 |
(if (match-beginning 11) |
(if (match-beginning 11) |
434 |
(setq seconds (read (substring isodurationstring |
(setq seconds (read (substring isodurationstring |
435 |
(match-beginning 12) |
(match-beginning 12) |
436 |
(match-end 12))))) |
(match-end 12))))) |
437 |
) |
) |
438 |
((match-beginning 13) ;weeks only |
((match-beginning 13) ;weeks only |
439 |
(setq days (* 7 (read (substring isodurationstring |
(setq days (* 7 (read (substring isodurationstring |
440 |
(match-beginning 14) |
(match-beginning 14) |
441 |
(match-end 14)))))) |
(match-end 14)))))) |
442 |
) |
) |
443 |
(list seconds minutes hours days months years))) |
(list seconds minutes hours days months years))) |
444 |
;; isodatetimestring == nil |
;; isodatetimestring == nil |
445 |
nil)) |
nil)) |
446 |
|
|
447 |
(defun icalendar-add-decoded-times (time1 time2) |
(defun icalendar--add-decoded-times (time1 time2) |
448 |
"Add TIME1 to TIME2. |
"Add TIME1 to TIME2. |
449 |
Both times must be given in decoded form. One of these times must be |
Both times must be given in decoded form. One of these times must be |
450 |
valid (year > 1900 or something)." |
valid (year > 1900 or something)." |
461 |
;;(or (nth 6 time1) (nth 6 time2)) ;; FIXME? |
;;(or (nth 6 time1) (nth 6 time2)) ;; FIXME? |
462 |
))) |
))) |
463 |
|
|
464 |
(defun icalendar-datetime-to-noneuropean-date (datetime) |
(defun icalendar--datetime-to-noneuropean-date (datetime) |
465 |
"Convert the decoded DATETIME to non-european-style format. |
"Convert the decoded DATETIME to non-european-style format. |
466 |
Non-European format: (month day year)." |
Non-European format: (month day year)." |
467 |
(if datetime |
(if datetime |
468 |
(list (nth 4 datetime) ;month |
(list (nth 4 datetime) ;month |
469 |
(nth 3 datetime) ;day |
(nth 3 datetime) ;day |
470 |
(nth 5 datetime));year |
(nth 5 datetime)) ;year |
471 |
;; datetime == nil |
;; datetime == nil |
472 |
nil)) |
nil)) |
473 |
|
|
474 |
(defun icalendar-datetime-to-european-date (datetime) |
(defun icalendar--datetime-to-european-date (datetime) |
475 |
"Convert the decoded DATETIME to European format. |
"Convert the decoded DATETIME to European format. |
476 |
European format: (day month year). |
European format: (day month year). |
477 |
FIXME" |
FIXME" |
478 |
(if datetime |
(if datetime |
479 |
(format "%d %d %d" (nth 3 datetime); day |
(format "%d %d %d" (nth 3 datetime) ; day |
480 |
(nth 4 datetime) ;month |
(nth 4 datetime) ;month |
481 |
(nth 5 datetime));year |
(nth 5 datetime)) ;year |
482 |
;; datetime == nil |
;; datetime == nil |
483 |
nil)) |
nil)) |
484 |
|
|
485 |
(defun icalendar-datetime-to-colontime (datetime) |
(defun icalendar--datetime-to-colontime (datetime) |
486 |
"Extract the time part of a decoded DATETIME into 24-hour format. |
"Extract the time part of a decoded DATETIME into 24-hour format. |
487 |
Note that this silently ignores seconds." |
Note that this silently ignores seconds." |
488 |
(format "%02d:%02d" (nth 2 datetime) (nth 1 datetime))) |
(format "%02d:%02d" (nth 2 datetime) (nth 1 datetime))) |
489 |
|
|
490 |
(defun icalendar-get-month-number (monthname) |
(defun icalendar--get-month-number (monthname) |
491 |
"Return the month number for the given MONTHNAME." |
"Return the month number for the given MONTHNAME." |
492 |
(save-match-data |
(catch 'found |
493 |
(let ((case-fold-search t)) |
(let ((num 1) |
494 |
(assoc-default monthname icalendar-monthnumber-table |
(m (downcase monthname))) |
495 |
'string-match)))) |
(mapc (lambda (month) |
496 |
|
(let ((mm (downcase month))) |
497 |
|
(if (or (string-equal mm m) |
498 |
|
(string-equal (substring mm 0 3) m)) |
499 |
|
(throw 'found num)) |
500 |
|
(setq num (1+ num)))) |
501 |
|
calendar-month-name-array)) |
502 |
|
;; Error: |
503 |
|
-1)) |
504 |
|
|
505 |
(defun icalendar-get-weekday-abbrev (weekday) |
(defun icalendar--get-weekday-number (abbrevweekday) |
506 |
|
"Return the number for the ABBREVWEEKDAY." |
507 |
|
(catch 'found |
508 |
|
(let ((num 0) |
509 |
|
(aw (downcase abbrevweekday))) |
510 |
|
(mapc (lambda (day) |
511 |
|
(let ((d (downcase day))) |
512 |
|
(if (string-equal d aw) |
513 |
|
(throw 'found num)) |
514 |
|
(setq num (1+ num)))) |
515 |
|
icalendar--weekday-array)) |
516 |
|
;; Error: |
517 |
|
-1)) |
518 |
|
|
519 |
|
(defun icalendar--get-weekday-abbrev (weekday) |
520 |
"Return the abbreviated WEEKDAY." |
"Return the abbreviated WEEKDAY." |
521 |
;;FIXME: ISO-like(?). |
(catch 'found |
522 |
(save-match-data |
(let ((num 0) |
523 |
(let ((case-fold-search t)) |
(w (downcase weekday))) |
524 |
(assoc-default weekday icalendar-weekdayabbrev-table |
(mapc (lambda (day) |
525 |
'string-match)))) |
(let ((d (downcase day))) |
526 |
|
(if (or (string-equal d w) |
527 |
|
(string-equal (substring d 0 3) w)) |
528 |
|
(throw 'found (aref icalendar--weekday-array num))) |
529 |
|
(setq num (1+ num)))) |
530 |
|
calendar-day-name-array)) |
531 |
|
;; Error: |
532 |
|
"??")) |
533 |
|
|
534 |
(defun icalendar-datestring-to-isodate (datestring &optional day-shift) |
(defun icalendar--datestring-to-isodate (datestring &optional day-shift) |
535 |
"Convert diary-style DATESTRING to iso-style date. |
"Convert diary-style DATESTRING to iso-style date. |
536 |
If DAY-SHIFT is non-nil, the result is shifted by DAY-SHIFT days |
If DAY-SHIFT is non-nil, the result is shifted by DAY-SHIFT days |
537 |
-- DAY-SHIFT must be either nil or an integer. This function |
-- DAY-SHIFT must be either nil or an integer. This function |
538 |
takes care of european-style." |
takes care of european-style." |
539 |
(let ((day -1) month year) |
(let ((day -1) month year) |
540 |
(save-match-data |
(save-match-data |
541 |
(cond (;; numeric date |
(cond ( ;; numeric date |
542 |
(string-match (concat "\\s-*" |
(string-match (concat "\\s-*" |
543 |
"0?\\([1-9][0-9]?\\)[ \t/]\\s-*" |
"0?\\([1-9][0-9]?\\)[ \t/]\\s-*" |
544 |
"0?\\([1-9][0-9]?\\),?[ \t/]\\s-*" |
"0?\\([1-9][0-9]?\\),?[ \t/]\\s-*" |
545 |
"\\([0-9]\\{4\\}\\)") |
"\\([0-9]\\{4\\}\\)") |
546 |
datestring) |
datestring) |
547 |
(setq day (read (substring datestring (match-beginning 1) |
(setq day (read (substring datestring (match-beginning 1) |
548 |
(match-end 1)))) |
(match-end 1)))) |
549 |
(setq month (read (substring datestring (match-beginning 2) |
(setq month (read (substring datestring (match-beginning 2) |
550 |
(match-end 2)))) |
(match-end 2)))) |
551 |
(setq year (read (substring datestring (match-beginning 3) |
(setq year (read (substring datestring (match-beginning 3) |
552 |
(match-end 3)))) |
(match-end 3)))) |
553 |
(unless european-calendar-style |
(unless european-calendar-style |
554 |
(let ((x month)) |
(let ((x month)) |
555 |
(setq month day) |
(setq month day) |
556 |
(setq day x)))) |
(setq day x)))) |
557 |
(;; date contains month names -- european-style |
( ;; date contains month names -- european-style |
558 |
(and european-calendar-style |
(and european-calendar-style |
559 |
(string-match (concat "\\s-*" |
(string-match (concat "\\s-*" |
560 |
"0?\\([123]?[0-9]\\)[ \t/]\\s-*" |
"0?\\([123]?[0-9]\\)[ \t/]\\s-*" |
561 |
"\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" |
"\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" |
562 |
"\\([0-9]\\{4\\}\\)") |
"\\([0-9]\\{4\\}\\)") |
563 |
datestring)) |
datestring)) |
564 |
(setq day (read (substring datestring (match-beginning 1) |
(setq day (read (substring datestring (match-beginning 1) |
565 |
(match-end 1)))) |
(match-end 1)))) |
566 |
(setq month (icalendar-get-month-number |
(setq month (icalendar--get-month-number |
567 |
(substring datestring (match-beginning 2) |
(substring datestring (match-beginning 2) |
568 |
(match-end 2)))) |
(match-end 2)))) |
569 |
(setq year (read (substring datestring (match-beginning 3) |
(setq year (read (substring datestring (match-beginning 3) |
570 |
(match-end 3))))) |
(match-end 3))))) |
571 |
(;; date contains month names -- non-european-style |
( ;; date contains month names -- non-european-style |
572 |
(and (not european-calendar-style) |
(and (not european-calendar-style) |
573 |
(string-match (concat "\\s-*" |
(string-match (concat "\\s-*" |
574 |
"\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" |
"\\([A-Za-z][^ ]+\\)[ \t/]\\s-*" |
575 |
"0?\\([123]?[0-9]\\),?[ \t/]\\s-*" |
"0?\\([123]?[0-9]\\),?[ \t/]\\s-*" |
576 |
"\\([0-9]\\{4\\}\\)") |
"\\([0-9]\\{4\\}\\)") |
577 |
datestring)) |
datestring)) |
578 |
(setq day (read (substring datestring (match-beginning 2) |
(setq day (read (substring datestring (match-beginning 2) |
579 |
(match-end 2)))) |
(match-end 2)))) |
580 |
(setq month (icalendar-get-month-number |
(setq month (icalendar--get-month-number |
581 |
(substring datestring (match-beginning 1) |
(substring datestring (match-beginning 1) |
582 |
(match-end 1)))) |
(match-end 1)))) |
583 |
(setq year (read (substring datestring (match-beginning 3) |
(setq year (read (substring datestring (match-beginning 3) |
584 |
(match-end 3))))) |
(match-end 3))))) |
585 |
(t |
(t |
586 |
nil))) |
nil))) |
587 |
(if (> day 0) |
(if (> day 0) |
588 |
(let ((mdy (calendar-gregorian-from-absolute |
(let ((mdy (calendar-gregorian-from-absolute |
589 |
(+ (calendar-absolute-from-gregorian (list month day year)) |
(+ (calendar-absolute-from-gregorian (list month day |
590 |
(or day-shift 0))))) |
year)) |
591 |
(format "%04d%02d%02d" (nth 2 mdy) (nth 0 mdy) (nth 1 mdy))) |
(or day-shift 0))))) |
592 |
|
(format "%04d%02d%02d" (nth 2 mdy) (nth 0 mdy) (nth 1 mdy))) |
593 |
nil))) |
nil))) |
594 |
|
|
595 |
(defun icalendar-dmsg (&rest args) |
(defun icalendar--diarytime-to-isotime (timestring ampmstring) |
|
"Print message ARGS if `icalendar-debug' is non-nil." |
|
|
(if icalendar-debug |
|
|
(apply 'message args))) |
|
|
|
|
|
(defun icalendar-diarytime-to-isotime (timestring ampmstring) |
|
596 |
"Convert a a time like 9:30pm to an iso-conform string like T213000. |
"Convert a a time like 9:30pm to an iso-conform string like T213000. |
597 |
In this example the TIMESTRING would be \"9:30\" and the AMPMSTRING |
In this example the TIMESTRING would be \"9:30\" and the AMPMSTRING |
598 |
would be \"pm\"." |
would be \"pm\"." |
599 |
(if timestring |
(if timestring |
600 |
(let ((starttimenum (read (icalendar-rris ":" "" timestring)))) |
(let ((starttimenum (read (icalendar--rris ":" "" timestring)))) |
601 |
;; take care of am/pm style |
;; take care of am/pm style |
602 |
(if (and ampmstring (string= "pm" ampmstring)) |
(if (and ampmstring (string= "pm" ampmstring)) |
603 |
(setq starttimenum (+ starttimenum 1200))) |
(setq starttimenum (+ starttimenum 1200))) |
604 |
(format "T%04d00" starttimenum)) |
(format "T%04d00" starttimenum)) |
605 |
nil)) |
nil)) |
606 |
|
|
607 |
(defun icalendar-convert-string-for-export (s) |
(defun icalendar--convert-string-for-export (s) |
608 |
"Escape comma and other critical characters in string S." |
"Escape comma and other critical characters in string S." |
609 |
(icalendar-rris "," "\\\\," s)) |
(icalendar--rris "," "\\\\," s)) |
610 |
|
|
611 |
(defun icalendar-convert-for-import (string) |
(defun icalendar--convert-string-for-import (string) |
612 |
"Remove escape chars for comma, semicolon etc. from STRING." |
"Remove escape chars for comma, semicolon etc. from STRING." |
613 |
(icalendar-rris |
(icalendar--rris |
614 |
"\\\\n" "\n " (icalendar-rris |
"\\\\n" "\n " (icalendar--rris |
615 |
"\\\\\"" "\"" (icalendar-rris |
"\\\\\"" "\"" (icalendar--rris |
616 |
"\\\\;" ";" (icalendar-rris |
"\\\\;" ";" (icalendar--rris |
617 |
"\\\\," "," string))))) |
"\\\\," "," string))))) |
618 |
|
|
619 |
;; ====================================================================== |
;; ====================================================================== |
620 |
;; export -- convert emacs-diary to icalendar |
;; Export -- convert emacs-diary to icalendar |
621 |
;; ====================================================================== |
;; ====================================================================== |
622 |
|
|
623 |
(defun icalendar-convert-diary-to-ical (diary-filename ical-filename |
;; User function |
624 |
&optional do-not-clear-diary-file) |
(defun icalendar-export-file (diary-filename ical-filename) |
625 |
"Export diary file to iCalendar format -- erases ical-filename!!!. |
"Export diary file to iCalendar format. |
626 |
Argument DIARY-FILENAME is the input `diary-file'. |
All diary entries in the file DIARY-FILENAME are converted to iCalendar |
627 |
Argument ICAL-FILENAME is the output iCalendar file. |
format. The result is appended to the file ICAL-FILENAME." |
|
If DO-NOT-CLEAR-DIARY-FILE is not nil the target iCalendar file |
|
|
is not erased." |
|
628 |
(interactive "FExport diary data from file: |
(interactive "FExport diary data from file: |
629 |
Finto iCalendar file: ") |
Finto iCalendar file: ") |
630 |
|
(save-current-buffer |
631 |
|
(set-buffer (find-file diary-filename)) |
632 |
|
(icalendar-export-region (point-min) (point-max) ical-filename))) |
633 |
|
|
634 |
|
(defalias 'icalendar-convert-diary-to-ical 'icalendar-export-file) |
635 |
|
(make-obsolete 'icalendar-convert-diary-to-ical 'icalendar-export-file |
636 |
|
"icalendar 0.07") |
637 |
|
|
638 |
|
;; User function |
639 |
|
(defun icalendar-export-region (min max ical-filename) |
640 |
|
"Export region in diary file to iCalendar format. |
641 |
|
All diary entries in the region from MIN to MAX in the current buffer are |
642 |
|
converted to iCalendar format. The result is appended to the file |
643 |
|
ICAL-FILENAME." |
644 |
|
(interactive "r |
645 |
|
FExport diary data into iCalendar file: ") |
646 |
(let ((result "") |
(let ((result "") |
647 |
(start 0) |
(start 0) |
648 |
(entry-main "") |
(entry-main "") |
651 |
(contents) |
(contents) |
652 |
(oops nil) |
(oops nil) |
653 |
(nonmarker (concat "^" (regexp-quote diary-nonmarking-symbol) |
(nonmarker (concat "^" (regexp-quote diary-nonmarking-symbol) |
654 |
"?"))) |
"?"))) |
655 |
(save-current-buffer |
(save-excursion |
656 |
(set-buffer (find-file diary-filename)) |
(goto-char min) |
|
(goto-char (point-min)) |
|
657 |
(while (re-search-forward |
(while (re-search-forward |
658 |
"^\\([^ \t\n].*\\)\\(\n[ \t].*\\)*" nil t) |
"^\\([^ \t\n].*\\)\\(\\(\n[ \t].*\\)*\\)" max t) |
659 |
(setq entry-main (match-string 1)) |
(setq entry-main (match-string 1)) |
660 |
(if (match-beginning 2) |
(if (match-beginning 2) |
661 |
(setq entry-rest (match-string 2)) |
(setq entry-rest (match-string 2)) |
671 |
(concat nonmarker |
(concat nonmarker |
672 |
"%%(diary-anniversary \\([^)]+\\))\\s-*\\(.*\\)") |
"%%(diary-anniversary \\([^)]+\\))\\s-*\\(.*\\)") |
673 |
entry-main) |
entry-main) |
674 |
(icalendar-dmsg "diary-anniversary %s" entry-main) |
(icalendar--dmsg "diary-anniversary %s" entry-main) |
675 |
(let* ((datetime (substring entry-main (match-beginning 1) |
(let* ((datetime (substring entry-main (match-beginning 1) |
676 |
(match-end 1))) |
(match-end 1))) |
677 |
(summary (icalendar-convert-string-for-export |
(summary (icalendar--convert-string-for-export |
678 |
(substring entry-main (match-beginning 2) |
(substring entry-main (match-beginning 2) |
679 |
(match-end 2)))) |
(match-end 2)))) |
680 |
(startisostring (icalendar-datestring-to-isodate |
(startisostring (icalendar--datestring-to-isodate |
681 |
datetime)) |
datetime)) |
682 |
(endisostring (icalendar-datestring-to-isodate |
(endisostring (icalendar--datestring-to-isodate |
683 |
datetime 1))) |
datetime 1))) |
684 |
(setq contents |
(setq contents |
685 |
(concat "\nDTSTART;VALUE=DATE:" startisostring |
(concat "\nDTSTART;VALUE=DATE:" startisostring |
686 |
"\nDTEND;VALUE=DATE:" endisostring |
"\nDTEND;VALUE=DATE:" endisostring |
695 |
))) |
))) |
696 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
697 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents (concat contents "\nDESCRIPTION:" |
698 |
(icalendar-convert-string-for-export |
(icalendar--convert-string-for-export |
699 |
entry-rest))))) |
entry-rest))))) |
700 |
;; cyclic events |
;; cyclic events |
701 |
;; %%(diary-cyclic ) |
;; %%(diary-cyclic ) |
704 |
"%%(diary-cyclic \\([^ ]+\\) +" |
"%%(diary-cyclic \\([^ ]+\\) +" |
705 |
"\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*\\(.*\\)") |
"\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*\\(.*\\)") |
706 |
entry-main) |
entry-main) |
707 |
(icalendar-dmsg "diary-cyclic %s" entry-main) |
(icalendar--dmsg "diary-cyclic %s" entry-main) |
708 |
(let* ((frequency (substring entry-main (match-beginning 1) |
(let* ((frequency (substring entry-main (match-beginning 1) |
709 |
(match-end 1))) |
(match-end 1))) |
710 |
(datetime (substring entry-main (match-beginning 2) |
(datetime (substring entry-main (match-beginning 2) |
711 |
(match-end 2))) |
(match-end 2))) |
712 |
(summary (icalendar-convert-string-for-export |
(summary (icalendar--convert-string-for-export |
713 |
(substring entry-main (match-beginning 3) |
(substring entry-main (match-beginning 3) |
714 |
(match-end 3)))) |
(match-end 3)))) |
715 |
(startisostring (icalendar-datestring-to-isodate |
(startisostring (icalendar--datestring-to-isodate |
716 |
datetime)) |
datetime)) |
717 |
(endisostring (icalendar-datestring-to-isodate |
(endisostring (icalendar--datestring-to-isodate |
718 |
datetime 1))) |
datetime 1))) |
719 |
(setq contents |
(setq contents |
720 |
(concat "\nDTSTART;VALUE=DATE:" startisostring |
(concat "\nDTSTART;VALUE=DATE:" startisostring |
721 |
"\nDTEND;VALUE=DATE:" endisostring |
"\nDTEND;VALUE=DATE:" endisostring |
726 |
))) |
))) |
727 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
728 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents (concat contents "\nDESCRIPTION:" |
729 |
(icalendar-convert-string-for-export |
(icalendar--convert-string-for-export |
730 |
entry-rest))))) |
entry-rest))))) |
731 |
;; diary-date -- FIXME |
;; diary-date -- FIXME |
732 |
((string-match |
((string-match |
733 |
(concat nonmarker |
(concat nonmarker |
734 |
"%%(diary-date \\([^)]+\\))\\s-*\\(.*\\)") |
"%%(diary-date \\([^)]+\\))\\s-*\\(.*\\)") |
735 |
entry-main) |
entry-main) |
736 |
(icalendar-dmsg "diary-date %s" entry-main) |
(icalendar--dmsg "diary-date %s" entry-main) |
737 |
(setq oops t)) |
(setq oops t)) |
738 |
;; float events -- FIXME |
;; float events -- FIXME |
739 |
((string-match |
((string-match |
740 |
(concat nonmarker |
(concat nonmarker |
741 |
"%%(diary-float \\([^)]+\\))\\s-*\\(.*\\)") |
"%%(diary-float \\([^)]+\\))\\s-*\\(.*\\)") |
742 |
entry-main) |
entry-main) |
743 |
(icalendar-dmsg "diary-float %s" entry-main) |
(icalendar--dmsg "diary-float %s" entry-main) |
744 |
(setq oops t)) |
(setq oops t)) |
745 |
;; block events |
;; block events |
746 |
((string-match |
((string-match |
748 |
"%%(diary-block \\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\) +" |
"%%(diary-block \\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\) +" |
749 |
"\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*\\(.*\\)") |
"\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\))\\s-*\\(.*\\)") |
750 |
entry-main) |
entry-main) |
751 |
(icalendar-dmsg "diary-block %s" entry-main) |
(icalendar--dmsg "diary-block %s" entry-main) |
752 |
(let* ((startstring (substring entry-main (match-beginning 1) |
(let* ((startstring (substring entry-main (match-beginning 1) |
753 |
(match-end 1))) |
(match-end 1))) |
754 |
(endstring (substring entry-main (match-beginning 2) |
(endstring (substring entry-main (match-beginning 2) |
755 |
(match-end 2))) |
(match-end 2))) |
756 |
(summary (icalendar-convert-string-for-export |
(summary (icalendar--convert-string-for-export |
757 |
(substring entry-main (match-beginning 3) |
(substring entry-main (match-beginning 3) |
758 |
(match-end 3)))) |
(match-end 3)))) |
759 |
(startisostring (icalendar-datestring-to-isodate |
(startisostring (icalendar--datestring-to-isodate |
760 |
startstring)) |
startstring)) |
761 |
(endisostring (icalendar-datestring-to-isodate |
(endisostring (icalendar--datestring-to-isodate |
762 |
endstring 1))) |
endstring 1))) |
763 |
(setq contents |
(setq contents |
764 |
(concat "\nDTSTART;VALUE=DATE:" startisostring |
(concat "\nDTSTART;VALUE=DATE:" startisostring |
765 |
"\nDTEND;VALUE=DATE:" endisostring |
"\nDTEND;VALUE=DATE:" endisostring |
767 |
)) |
)) |
768 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
769 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents (concat contents "\nDESCRIPTION:" |
770 |
(icalendar-convert-string-for-export |
(icalendar--convert-string-for-export |
771 |
entry-rest)))))) |
entry-rest)))))) |
772 |
;; other sexp diary entries -- FIXME |
;; other sexp diary entries -- FIXME |
773 |
((string-match |
((string-match |
774 |
(concat nonmarker |
(concat nonmarker |
775 |
"%%(\\([^)]+\\))\\s-*\\(.*\\)") |
"%%(\\([^)]+\\))\\s-*\\(.*\\)") |
776 |
entry-main) |
entry-main) |
777 |
(icalendar-dmsg "diary-sexp %s" entry-main) |
(icalendar--dmsg "diary-sexp %s" entry-main) |
778 |
(setq oops t)) |
(setq oops t)) |
779 |
;; weekly by day |
;; weekly by day |
780 |
;; Monday 8:30 Team meeting |
;; Monday 8:30 Team meeting |
787 |
"\\)?" |
"\\)?" |
788 |
"\\s-*\\(.*\\)$") |
"\\s-*\\(.*\\)$") |
789 |
entry-main) |
entry-main) |
790 |
(icalendar-get-weekday-abbrev |
(icalendar--get-weekday-abbrev |
791 |
(substring entry-main (match-beginning 1) (match-end 1)))) |
(substring entry-main (match-beginning 1) (match-end 1)))) |
792 |
(icalendar-dmsg "weekly %s" entry-main) |
(icalendar--dmsg "weekly %s" entry-main) |
793 |
(let* ((day (icalendar-get-weekday-abbrev |
(let* ((day (icalendar--get-weekday-abbrev |
794 |
(substring entry-main (match-beginning 1) |
(substring entry-main (match-beginning 1) |
795 |
(match-end 1)))) |
(match-end 1)))) |
796 |
(starttimestring (icalendar-diarytime-to-isotime |
(starttimestring (icalendar--diarytime-to-isotime |
797 |
(if (match-beginning 3) |
(if (match-beginning 3) |
798 |
(substring entry-main |
(substring entry-main |
799 |
(match-beginning 3) |
(match-beginning 3) |
804 |
(match-beginning 4) |
(match-beginning 4) |
805 |
(match-end 4)) |
(match-end 4)) |
806 |
nil))) |
nil))) |
807 |
(endtimestring (icalendar-diarytime-to-isotime |
(endtimestring (icalendar--diarytime-to-isotime |
808 |
(if (match-beginning 6) |
(if (match-beginning 6) |
809 |
(substring entry-main |
(substring entry-main |
810 |
(match-beginning 6) |
(match-beginning 6) |
811 |
(match-end 6)) |
(match-end 6)) |
812 |
nil) |
nil) |
813 |
(if (match-beginning 7) |
(if (match-beginning 7) |
814 |
(substring entry-main |
(substring entry-main |
815 |
(match-beginning 7) |
(match-beginning 7) |
816 |
(match-end 7)) |
(match-end 7)) |
817 |
nil))) |
nil))) |
818 |
(summary (icalendar-convert-string-for-export |
(summary (icalendar--convert-string-for-export |
819 |
(substring entry-main (match-beginning 8) |
(substring entry-main (match-beginning 8) |
820 |
(match-end 8))))) |
(match-end 8))))) |
821 |
(when starttimestring |
(when starttimestring |
822 |
(unless endtimestring |
(unless endtimestring |
823 |
(let ((time (read (icalendar-rris "^T0?" "" |
(let ((time (read (icalendar--rris "^T0?" "" |
824 |
starttimestring)))) |
starttimestring)))) |
825 |
(setq endtimestring (format "T%06d" (+ 10000 time)))))) |
(setq endtimestring (format "T%06d" (+ 10000 time)))))) |
826 |
(setq contents |
(setq contents |
827 |
(concat "\nDTSTART" |
(concat "\nDTSTART" |
838 |
))) |
))) |
839 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
840 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents (concat contents "\nDESCRIPTION:" |
841 |
(icalendar-convert-string-for-export |
(icalendar--convert-string-for-export |
842 |
entry-rest))))) |
entry-rest))))) |
843 |
;; yearly by day |
;; yearly by day |
844 |
;; 1 May Tag der Arbeit |
;; 1 May Tag der Arbeit |
850 |
"\\*?\\s-*" |
"\\*?\\s-*" |
851 |
"\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" |
"\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" |
852 |
"\\(" |
"\\(" |
853 |
"-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" |
"-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" |
854 |
"\\)?" |
"\\)?" |
855 |
"\\s-*\\([^0-9]+.*\\)$"; must not match years |
"\\s-*\\([^0-9]+.*\\)$" ; must not match years |
856 |
) |
) |
857 |
entry-main) |
entry-main) |
858 |
(icalendar-dmsg "yearly %s" entry-main) |
(icalendar--dmsg "yearly %s" entry-main) |
859 |
(let* ((daypos (if european-calendar-style 1 2)) |
(let* ((daypos (if european-calendar-style 1 2)) |
860 |
(monpos (if european-calendar-style 2 1)) |
(monpos (if european-calendar-style 2 1)) |
861 |
(day (read (substring entry-main (match-beginning daypos) |
(day (read (substring entry-main (match-beginning daypos) |
862 |
(match-end daypos)))) |
(match-end daypos)))) |
863 |
(month (icalendar-get-month-number |
(month (icalendar--get-month-number |
864 |
(substring entry-main (match-beginning monpos) |
(substring entry-main (match-beginning monpos) |
865 |
(match-end monpos)))) |
(match-end monpos)))) |
866 |
(starttimestring (icalendar-diarytime-to-isotime |
(starttimestring (icalendar--diarytime-to-isotime |
867 |
(if (match-beginning 4) |
(if (match-beginning 4) |
868 |
(substring entry-main |
(substring entry-main |
869 |
(match-beginning 4) |
(match-beginning 4) |
874 |
(match-beginning 5) |
(match-beginning 5) |
875 |
(match-end 5)) |
(match-end 5)) |
876 |
nil))) |
nil))) |
877 |
(endtimestring (icalendar-diarytime-to-isotime |
(endtimestring (icalendar--diarytime-to-isotime |
878 |
(if (match-beginning 7) |
(if (match-beginning 7) |
879 |
(substring entry-main |
(substring entry-main |
880 |
(match-beginning 7) |
(match-beginning 7) |
881 |
(match-end 7)) |
(match-end 7)) |
882 |
nil) |
nil) |
883 |
(if (match-beginning 8) |
(if (match-beginning 8) |
884 |
(substring entry-main |
(substring entry-main |
885 |
(match-beginning 8) |
(match-beginning 8) |
886 |
(match-end 8)) |
(match-end 8)) |
887 |
nil))) |
nil))) |
888 |
(summary (icalendar-convert-string-for-export |
(summary (icalendar--convert-string-for-export |
889 |
(substring entry-main (match-beginning 9) |
(substring entry-main (match-beginning 9) |
890 |
(match-end 9))))) |
(match-end 9))))) |
891 |
(when starttimestring |
(when starttimestring |
892 |
(unless endtimestring |
(unless endtimestring |
893 |
(let ((time (read (icalendar-rris "^T0?" "" |
(let ((time (read (icalendar--rris "^T0?" "" |
894 |
starttimestring)))) |
starttimestring)))) |
895 |
(setq endtimestring (format "T%06d" (+ 10000 time)))))) |
(setq endtimestring (format "T%06d" (+ 10000 time)))))) |
896 |
(setq contents |
(setq contents |
897 |
(concat "\nDTSTART" |
(concat "\nDTSTART" |
910 |
))) |
))) |
911 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
912 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents (concat contents "\nDESCRIPTION:" |
913 |
(icalendar-convert-string-for-export |
(icalendar--convert-string-for-export |
914 |
entry-rest))))) |
entry-rest))))) |
915 |
;; "ordinary" events, start and end time given |
;; "ordinary" events, start and end time given |
916 |
;; 1 Feb 2003 Hs Hochzeitsfeier, Dreieich |
;; 1 Feb 2003 Hs Hochzeitsfeier, Dreieich |
919 |
"\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)\\s-+" |
"\\([^ /]+[ /]+[^ /]+[ /]+[^ ]+\\)\\s-+" |
920 |
"\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" |
"\\(0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?" |
921 |
"\\(" |
"\\(" |
922 |
"-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" |
"-0?\\([1-9][0-9]?:[0-9][0-9]\\)\\([ap]m\\)?\\)?" |
923 |
"\\)?" |
"\\)?" |
924 |
"\\s-*\\(.*\\)") |
"\\s-*\\(.*\\)") |
925 |
entry-main) |
entry-main) |
926 |
(icalendar-dmsg "ordinary %s" entry-main) |
(icalendar--dmsg "ordinary %s" entry-main) |
927 |
(let* ((datestring (icalendar-datestring-to-isodate |
(let* ((datestring (icalendar--datestring-to-isodate |
928 |
(substring entry-main (match-beginning 1) |
(substring entry-main (match-beginning 1) |
929 |
(match-end 1)))) |
(match-end 1)))) |
930 |
(starttimestring (icalendar-diarytime-to-isotime |
(starttimestring (icalendar--diarytime-to-isotime |
931 |
(if (match-beginning 3) |
(if (match-beginning 3) |
932 |
(substring entry-main |
(substring entry-main |
933 |
(match-beginning 3) |
(match-beginning 3) |
938 |
(match-beginning 4) |
(match-beginning 4) |
939 |
(match-end 4)) |
(match-end 4)) |
940 |
nil))) |
nil))) |
941 |
(endtimestring (icalendar-diarytime-to-isotime |
(endtimestring (icalendar--diarytime-to-isotime |
942 |
(if (match-beginning 6) |
(if (match-beginning 6) |
943 |
(substring entry-main |
(substring entry-main |
944 |
(match-beginning 6) |
(match-beginning 6) |
945 |
(match-end 6)) |
(match-end 6)) |
946 |
nil) |
nil) |
947 |
(if (match-beginning 7) |
(if (match-beginning 7) |
948 |
(substring entry-main |
(substring entry-main |
949 |
(match-beginning 7) |
(match-beginning 7) |
950 |
(match-end 7)) |
(match-end 7)) |
951 |
nil))) |
nil))) |
952 |
(summary (icalendar-convert-string-for-export |
(summary (icalendar--convert-string-for-export |
953 |
(substring entry-main (match-beginning 8) |
(substring entry-main (match-beginning 8) |
954 |
(match-end 8))))) |
(match-end 8))))) |
955 |
(when starttimestring |
(when starttimestring |
956 |
(unless endtimestring |
(unless endtimestring |
957 |
(let ((time (read (icalendar-rris "^T0?" "" |
(let ((time (read (icalendar--rris "^T0?" "" |
958 |
starttimestring)))) |
starttimestring)))) |
959 |
(setq endtimestring (format "T%06d" (+ 10000 time)))))) |
(setq endtimestring (format "T%06d" (+ 10000 time)))))) |
960 |
(setq contents (format |
(setq contents (format |
961 |
"\nDTSTART%s:%s%s\nDTEND%s:%s%s\nSUMMARY:%s" |
"\nDTSTART%s:%s%s\nDTEND%s:%s%s\nSUMMARY:%s" |
962 |
(if starttimestring "" ";VALUE=DATE") |
(if starttimestring "" ";VALUE=DATE") |
963 |
datestring |
datestring |
964 |
(or starttimestring "") |
(or starttimestring "") |
965 |
(if endtimestring "" |
(if endtimestring "" |
966 |
";VALUE=DATE") |
";VALUE=DATE") |
967 |
datestring |
datestring |
968 |
(or endtimestring "") |
(or endtimestring "") |
969 |
summary)) |
summary)) |
970 |
(unless (string= entry-rest "") |
(unless (string= entry-rest "") |
971 |
(setq contents (concat contents "\nDESCRIPTION:" |
(setq contents (concat contents "\nDESCRIPTION:" |
972 |
(icalendar-convert-string-for-export |
(icalendar--convert-string-for-export |
973 |
entry-rest)))))) |
entry-rest)))))) |
974 |
;; everything else |
;; everything else |
975 |
(t |
(t |
977 |
(setq oops t))) |
(setq oops t))) |
978 |
(if oops |
(if oops |
979 |
(message "Cannot export entry on line %d" |
(message "Cannot export entry on line %d" |
980 |
(count-lines (point-min) (point))) |
(count-lines (point-min) (point))) |
981 |
(setq result (concat result header contents "\nEND:VEVENT")))) |
(setq result (concat result header contents "\nEND:VEVENT")))) |
982 |
;; we're done, insert everything into the file |
;; we're done, insert everything into the file |
983 |
(let ((coding-system-for-write 'utf8)) |
(let ((coding-system-for-write 'utf8)) |
984 |
(set-buffer (find-file ical-filename)) |
(set-buffer (find-file ical-filename)) |
985 |
(unless do-not-clear-diary-file |
(goto-char (point-max)) |
986 |
(erase-buffer)) |
(insert "BEGIN:VCALENDAR") |
987 |
(insert |
(insert "\nPRODID:-//Emacs//NONSGML icalendar.el//EN") |
|
"BEGIN:VCALENDAR\nPRODID:-//Emacs//NONSGML icalendar.el//EN") |
|
988 |
(insert "\nVERSION:2.0") |
(insert "\nVERSION:2.0") |
989 |
(insert result) |
(insert result) |
990 |
(insert "\nEND:VCALENDAR\n"))))) |
(insert "\nEND:VCALENDAR\n"))))) |
991 |
|
|
|
|
|
992 |
;; ====================================================================== |
;; ====================================================================== |
993 |
;; import -- convert icalendar to emacs-diary |
;; Import -- convert icalendar to emacs-diary |
994 |
;; ====================================================================== |
;; ====================================================================== |
995 |
|
|
996 |
;; user function |
;; User function |
997 |
(defun icalendar-import-file (ical-filename diary-filename |
(defun icalendar-import-file (ical-filename diary-filename |
998 |
&optional non-marking |
&optional non-marking) |
999 |
do-not-clear-diary-file) |
"Import a iCalendar file and append to a diary file. |
|
"Import a iCalendar file and save to a diary file -- erases diary-file! |
|
1000 |
Argument ICAL-FILENAME output iCalendar file. |
Argument ICAL-FILENAME output iCalendar file. |
1001 |
Argument DIARY-FILENAME input `diary-file'. |
Argument DIARY-FILENAME input `diary-file'. |
1002 |
Optional argument NON-MARKING determines whether events are created as |
Optional argument NON-MARKING determines whether events are created as |
1003 |
non-marking or not. |
non-marking or not." |
|
If DO-NOT-CLEAR-DIARY-FILE is not nil the target diary file is |
|
|
not erased." |
|
1004 |
(interactive "fImport iCalendar data from file: |
(interactive "fImport iCalendar data from file: |
1005 |
Finto diary file (will be erased!): |
Finto diary file: |
1006 |
p") |
p") |
1007 |
;; clean up the diary file |
;; clean up the diary file |
1008 |
(save-current-buffer |
(save-current-buffer |
|
(unless do-not-clear-diary-file |
|
|
;; clear the target diary file |
|
|
(set-buffer (find-file diary-filename)) |
|
|
(erase-buffer)) |
|
1009 |
;; now load and convert from the ical file |
;; now load and convert from the ical file |
1010 |
(set-buffer (find-file ical-filename)) |
(set-buffer (find-file ical-filename)) |
1011 |
(icalendar-extract-ical-from-buffer diary-filename t non-marking))) |
(icalendar-import-buffer diary-filename t non-marking))) |
1012 |
|
|
1013 |
; user function |
;; User function |
1014 |
(defun icalendar-extract-ical-from-buffer (&optional |
(defun icalendar-import-buffer (&optional diary-file do-not-ask |
1015 |
diary-file do-not-ask |
non-marking) |
|
non-marking) |
|
1016 |
"Extract iCalendar events from current buffer. |
"Extract iCalendar events from current buffer. |
1017 |
|
|
1018 |
This function searches the current buffer for the first iCalendar |
This function searches the current buffer for the first iCalendar |
1032 |
(save-current-buffer |
(save-current-buffer |
1033 |
;; prepare ical |
;; prepare ical |
1034 |
(message "Preparing icalendar...") |
(message "Preparing icalendar...") |
1035 |
(set-buffer (icalendar-get-unfolded-buffer (current-buffer))) |
(set-buffer (icalendar--get-unfolded-buffer (current-buffer))) |
1036 |
(goto-char (point-min)) |
(goto-char (point-min)) |
1037 |
(message "Preparing icalendar...done") |
(message "Preparing icalendar...done") |
1038 |
(if (re-search-forward "^BEGIN:VCALENDAR\\s-*$" nil t) |
(if (re-search-forward "^BEGIN:VCALENDAR\\s-*$" nil t) |
1040 |
;; read ical |
;; read ical |
1041 |
(message "Reading icalendar...") |
(message "Reading icalendar...") |
1042 |
(beginning-of-line) |
(beginning-of-line) |
1043 |
(setq ical-contents (icalendar-read-element nil nil)) |
(setq ical-contents (icalendar--read-element nil nil)) |
1044 |
(message "Reading icalendar...done") |
(message "Reading icalendar...done") |
1045 |
;; convert ical |
;; convert ical |
1046 |
(message "Converting icalendar...") |
(message "Converting icalendar...") |
1047 |
(setq ical-errors (icalendar-convert-ical-to-diary |
(setq ical-errors (icalendar--convert-ical-to-diary |
1048 |
ical-contents |
ical-contents |
1049 |
diary-file do-not-ask non-marking)) |
diary-file do-not-ask non-marking)) |
1050 |
(when diary-file |
(when diary-file |
1054 |
(save-buffer))) |
(save-buffer))) |
1055 |
(message "Converting icalendar...done") |
(message "Converting icalendar...done") |
1056 |
(if (and ical-errors (y-or-n-p |
(if (and ical-errors (y-or-n-p |
1057 |
(concat "Something went wrong -- " |
(concat "Something went wrong -- " |
1058 |
"do you want to see the " |
"do you want to see the " |
1059 |
"error log? "))) |
"error log? "))) |
1060 |
(switch-to-buffer " *icalendar-errors*"))) |
(switch-to-buffer " *icalendar-errors*"))) |
1061 |
(message |
(message |
1062 |
"Current buffer does not contain icalendar contents!")))) |
"Current buffer does not contain icalendar contents!")))) |
1063 |
|
|
1064 |
;; ---------------------------------------------------------------------- |
(defalias 'icalendar-extract-ical-from-buffer 'icalendar-import-buffer) |
1065 |
|
|
1066 |
|
(make-obsolete 'icalendar-extract-ical-from-buffer 'icalendar-import-buffer |
1067 |
|
"icalendar 0.07") |
1068 |
|
|
1069 |
|
;; ====================================================================== |
1070 |
;; private area |
;; private area |
1071 |
;; ---------------------------------------------------------------------- |
;; ====================================================================== |
1072 |
(defun icalendar-format-ical-event (event) |
|
1073 |
|
(defun icalendar--format-ical-event (event) |
1074 |
"Create a string representation of an iCalendar EVENT." |
"Create a string representation of an iCalendar EVENT." |
1075 |
(let ((string icalendar-import-format) |
(let ((string icalendar-import-format) |
1076 |
(conversion-list |
(conversion-list |
1083 |
(let* ((spec (car i)) |
(let* ((spec (car i)) |
1084 |
(prop (cadr i)) |
(prop (cadr i)) |
1085 |
(format (car (cddr i))) |
(format (car (cddr i))) |
1086 |
(contents (icalendar-get-event-property event prop)) |
(contents (icalendar--get-event-property event prop)) |
1087 |
(formatted-contents "")) |
(formatted-contents "")) |
|
;;(message "%s" event) |
|
|
;;(message "contents%s = %s" prop contents) |
|
1088 |
(when (and contents (> (length contents) 0)) |
(when (and contents (> (length contents) 0)) |
1089 |
(setq formatted-contents |
(setq formatted-contents |
1090 |
(icalendar-rris "%s" |
(icalendar--rris "%s" |
1091 |
(icalendar-convert-for-import |
(icalendar--convert-string-for-import |
1092 |
contents) |
contents) |
1093 |
(symbol-value format)))) |
(symbol-value format)))) |
1094 |
(setq string (icalendar-rris spec |
(setq string (icalendar--rris spec |
1095 |
formatted-contents |
formatted-contents |
1096 |
string)))) |
string)))) |
1097 |
conversion-list) |
conversion-list) |
1098 |
string)) |
string)) |
1099 |
|
|
1100 |
(defun icalendar-convert-ical-to-diary (ical-list diary-file |
(defun icalendar--convert-ical-to-diary (ical-list diary-file |
1101 |
&optional do-not-ask |
&optional do-not-ask |
1102 |
non-marking) |
non-marking) |
1103 |
"Convert an iCalendar file to an Emacs diary file. |
"Convert an iCalendar file to an Emacs diary file. |
1104 |
Import VEVENTS from the iCalendar object ICAL-LIST and saves them to a |
Import VEVENTS from the iCalendar object ICAL-LIST and saves them to a |
1105 |
DIARY-FILE. If DO-NOT-ASK is nil the user is asked for each event |
DIARY-FILE. If DO-NOT-ASK is nil the user is asked for each event |
1108 |
This function attempts to return t if something goes wrong. In this |
This function attempts to return t if something goes wrong. In this |
1109 |
case an error string which describes all the errors and problems is |
case an error string which describes all the errors and problems is |
1110 |
written into the buffer ` *icalendar-errors*'." |
written into the buffer ` *icalendar-errors*'." |
1111 |
(let* ((ev (icalendar-all-events ical-list)) |
(let* ((ev (icalendar--all-events ical-list)) |
1112 |
(error-string "") |
(error-string "") |
1113 |
(event-ok t) |
(event-ok t) |
1114 |
(found-error nil) |
(found-error nil) |
1119 |
(setq ev (cdr ev)) |
(setq ev (cdr ev)) |
1120 |
(setq event-ok nil) |
(setq event-ok nil) |
1121 |
(condition-case error-val |
(condition-case error-val |
1122 |
(let* ((dtstart (icalendar-decode-isodatetime |
(let* ((dtstart (icalendar--decode-isodatetime |
1123 |
(icalendar-get-event-property e 'DTSTART))) |
(icalendar--get-event-property e 'DTSTART))) |
1124 |
(start-d (calendar-date-string |
(start-d (calendar-date-string |
1125 |
(icalendar-datetime-to-noneuropean-date |
(icalendar--datetime-to-noneuropean-date |
1126 |
dtstart) |
dtstart) |
1127 |
t t)) |
t t)) |
1128 |
(start-t (icalendar-datetime-to-colontime dtstart)) |
(start-t (icalendar--datetime-to-colontime dtstart)) |
1129 |
(dtend (icalendar-decode-isodatetime |
(dtend (icalendar--decode-isodatetime |
1130 |
(icalendar-get-event-property e 'DTEND))) |
(icalendar--get-event-property e 'DTEND))) |
1131 |
end-d |
end-d |
1132 |
end-t |
end-t |
1133 |
(subject (icalendar-convert-for-import |
(subject (icalendar--convert-string-for-import |
1134 |
(or (icalendar-get-event-property e 'SUMMARY) |
(or (icalendar--get-event-property e 'SUMMARY) |
1135 |
"No Subject"))) |
"No Subject"))) |
1136 |
(rrule (icalendar-get-event-property e 'RRULE)) |
(rrule (icalendar--get-event-property e 'RRULE)) |
1137 |
(rdate (icalendar-get-event-property e 'RDATE)) |
(rdate (icalendar--get-event-property e 'RDATE)) |
1138 |
(duration (icalendar-get-event-property e 'DURATION))) |
(duration (icalendar--get-event-property e 'DURATION))) |
1139 |
(icalendar-dmsg "%s: %s" start-d subject) |
(icalendar--dmsg "%s: %s" start-d subject) |
1140 |
(when duration |
(when duration |
1141 |
(let ((dtend2 (icalendar-add-decoded-times |
(let ((dtend2 (icalendar--add-decoded-times |
1142 |
dtstart |
dtstart |
1143 |
(icalendar-decode-isoduration duration)))) |
(icalendar--decode-isoduration duration)))) |
1144 |
(if (and dtend (not (eq dtend dtend2))) |
(if (and dtend (not (eq dtend dtend2))) |
1145 |
(message "Inconsistent endtime and duration for %s" |
(message "Inconsistent endtime and duration for %s" |
1146 |
subject)) |
subject)) |
1147 |
(setq dtend dtend2))) |
(setq dtend dtend2))) |
1148 |
(setq end-d (if dtend |
(setq end-d (if dtend |
1149 |
(calendar-date-string |
(calendar-date-string |
1150 |
(icalendar-datetime-to-noneuropean-date |
(icalendar--datetime-to-noneuropean-date |
1151 |
dtend) |
dtend) |
1152 |
t t) |
t t) |
1153 |
start-d)) |
start-d)) |
1154 |
(setq end-t (if dtend |
(setq end-t (if dtend |
1155 |
(icalendar-datetime-to-colontime dtend) |
(icalendar--datetime-to-colontime dtend) |
1156 |
start-t)) |
start-t)) |
1157 |
(icalendar-dmsg "start-d: %s, end-d: %s" start-d end-d) |
(icalendar--dmsg "start-d: %s, end-d: %s" start-d end-d) |
1158 |
(cond |
(cond |
1159 |
;; recurring event |
;; recurring event |
1160 |
(rrule |
(rrule |
1161 |
(icalendar-dmsg "recurring event") |
(icalendar--dmsg "recurring event") |
1162 |
(let* ((rrule-props (icalendar-split-value rrule)) |
(let* ((rrule-props (icalendar--split-value rrule)) |
1163 |
(frequency (car (cdr (assoc 'FREQ rrule-props)))) |
(frequency (car (cdr (assoc 'FREQ rrule-props)))) |
1164 |
(until (car (cdr (assoc 'UNTIL rrule-props)))) |
(until (car (cdr (assoc 'UNTIL rrule-props)))) |
1165 |
(interval (read (car (cdr (assoc 'INTERVAL |
(interval (read (car (cdr (assoc 'INTERVAL |
1166 |
rrule-props)))))) |
rrule-props)))))) |
1167 |
(cond ((string-equal frequency "WEEKLY") |
(cond ((string-equal frequency "WEEKLY") |
1168 |
(if (not start-t) |
(if (not start-t) |
1169 |
(progn |
(progn |
1170 |
;; weekly and all-day |
;; weekly and all-day |
1171 |
(icalendar-dmsg "weekly all-day") |
(icalendar--dmsg "weekly all-day") |
1172 |
(setq diary-string |
(setq diary-string |
1173 |
(format |
(format |
1174 |
"%%%%(diary-cyclic %d %s)" |
"%%%%(diary-cyclic %d %s)" |
1175 |
(* interval 7) |
(* interval 7) |
1176 |
(icalendar-datetime-to-european-date |
(icalendar--datetime-to-european-date |
1177 |
dtstart)))) |
dtstart)))) |
1178 |
;; weekly and not all-day |
;; weekly and not all-day |
1179 |
(let* ((byday (cadr (assoc 'BYDAY rrule-props))) |
(let* ((byday (cadr (assoc 'BYDAY rrule-props))) |
1180 |
(weekday |
(weekday |
1181 |
(cdr (rassoc |
(icalendar--get-weekday-number byday))) |
1182 |
byday |
(icalendar--dmsg "weekly not-all-day") |
1183 |
icalendar-weekdayabbrev-table)))) |
(if (> weekday -1) |
|
(icalendar-dmsg "weekly not-all-day") |
|
|
(if weekday |
|
1184 |
(setq diary-string |
(setq diary-string |
1185 |
(format "%s %s%s%s" weekday |
(format "%s %s%s%s" |
1186 |
|
(aref calendar-day-name-array |
1187 |
|
weekday) |
1188 |
start-t (if end-t "-" "") |
start-t (if end-t "-" "") |
1189 |
(or end-t ""))) |
(or end-t ""))) |
1190 |
;; FIXME!!!! |
;; FIXME!!!! |
1192 |
;; DTEND;VALUE=DATE-TIME:20030919T113000 |
;; DTEND;VALUE=DATE-TIME:20030919T113000 |
1193 |
(setq diary-string |
(setq diary-string |
1194 |
(format |
(format |
1195 |
"%%%%(diary-cyclic %s %s) %s%s%s" |
"%%%%(diary-cyclic %s %s) %s%s%s" |
1196 |
(* interval 7) |
(* interval 7) |
1197 |
(icalendar-datetime-to-european-date |
(icalendar--datetime-to-european-date |
1198 |
dtstart) |
dtstart) |
1199 |
start-t (if end-t "-" "") (or end-t "")))) |
start-t (if end-t "-" "") (or end-t "")))) |
1200 |
(setq event-ok t)))) |
(setq event-ok t)))) |
1201 |
;; yearly |
;; yearly |
1202 |
((string-equal frequency "YEARLY") |
((string-equal frequency "YEARLY") |
1203 |
(icalendar-dmsg "yearly") |
(icalendar--dmsg "yearly") |
1204 |
(setq diary-string |
(setq diary-string |
1205 |
(format |
(format |
1206 |
"%%%%(diary-anniversary %s)" |
"%%%%(diary-anniversary %s)" |
1207 |
(icalendar-datetime-to-european-date dtstart))) |
(icalendar--datetime-to-european-date dtstart))) |
1208 |
(setq event-ok t)) |
(setq event-ok t)) |
1209 |
;; FIXME: war auskommentiert: |
;; FIXME: war auskommentiert: |
1210 |
((and (string-equal frequency "DAILY") |
((and (string-equal frequency "DAILY") |
1212 |
;;(not start-t) |
;;(not start-t) |
1213 |
;;(not end-t) |
;;(not end-t) |
1214 |
) |
) |
1215 |
(let ((ds (icalendar-datetime-to-noneuropean-date |
(let ((ds (icalendar--datetime-to-noneuropean-date |
1216 |
(icalendar-decode-isodatetime |
(icalendar--decode-isodatetime |
1217 |
(icalendar-get-event-property e |
(icalendar--get-event-property e |
1218 |
'DTSTART)))) |
'DTSTART)))) |
1219 |
(de (icalendar-datetime-to-noneuropean-date |
(de (icalendar--datetime-to-noneuropean-date |
1220 |
(icalendar-decode-isodatetime |
(icalendar--decode-isodatetime |
1221 |
until)))) |
until)))) |
1222 |
(setq diary-string |
(setq diary-string |
1223 |
(format |
(format |
1224 |
"%%%%(diary-block %d %d %d %d %d %d)" |
"%%%%(diary-block %d %d %d %d %d %d)" |
1225 |
(nth 1 ds) (nth 0 ds) (nth 2 ds) |
(nth 1 ds) (nth 0 ds) (nth 2 ds) |
1226 |
(nth 1 de) (nth 0 de) (nth 2 de)))) |
(nth 1 de) (nth 0 de) (nth 2 de)))) |
1227 |
(setq event-ok t))) |
(setq event-ok t))) |
1228 |
)) |
)) |
1229 |
(rdate |
(rdate |
1230 |
(icalendar-dmsg "rdate event") |
(icalendar--dmsg "rdate event") |
1231 |
(setq diary-string "") |
(setq diary-string "") |
1232 |
(mapcar (lambda (datestring) |
(mapcar (lambda (datestring) |
1233 |
(setq diary-string |
(setq diary-string |
1234 |
(concat diary-string |
(concat diary-string |
1235 |
(format "......")))) |
(format "......")))) |
1236 |
(icalendar-split-value rdate))) |
(icalendar--split-value rdate))) |
1237 |
;; non-recurring event |
;; non-recurring event |
1238 |
;; long event |
;; long event |
1239 |
((not (string= start-d end-d)) |
((not (string= start-d end-d)) |
1240 |
(icalendar-dmsg "non-recurring event") |
(icalendar--dmsg "non-recurring event") |
1241 |
(let ((ds (icalendar-datetime-to-noneuropean-date dtstart)) |
(let ((ds (icalendar--datetime-to-noneuropean-date dtstart)) |
1242 |
(de (icalendar-datetime-to-noneuropean-date dtend))) |
(de (icalendar--datetime-to-noneuropean-date dtend))) |
1243 |
(setq diary-string |
(setq diary-string |
1244 |
(format "%%%%(diary-block %d %d %d %d %d %d)" |
(format "%%%%(diary-block %d %d %d %d %d %d)" |
1245 |
(nth 1 ds) (nth 0 ds) (nth 2 ds) |
(nth 1 ds) (nth 0 ds) (nth 2 ds) |
1248 |
;; not all-day |
;; not all-day |
1249 |
((and start-t (or (not end-t) |
((and start-t (or (not end-t) |
1250 |
(not (string= start-t end-t)))) |
(not (string= start-t end-t)))) |
1251 |
(icalendar-dmsg "not all day event") |
(icalendar--dmsg "not all day event") |
1252 |
(cond (end-t |
(cond (end-t |
1253 |
(setq diary-string (format "%s %s-%s" start-d |
(setq diary-string (format "%s %s-%s" start-d |
1254 |
start-t end-t))) |
start-t end-t))) |
1255 |
(t |
(t |
1256 |
(setq diary-string (format "%s %s" start-d |
(setq diary-string (format "%s %s" start-d |
1257 |
start-t)))) |
start-t)))) |
1258 |
(setq event-ok t)) |
(setq event-ok t)) |
1259 |
;; all-day event |
;; all-day event |
1260 |
(t |
(t |
1261 |
(icalendar-dmsg "all day event") |
(icalendar--dmsg "all day event") |
1262 |
(setq diary-string start-d) |
(setq diary-string start-d) |
1263 |
(setq event-ok t))) |
(setq event-ok t))) |
1264 |
;; add all other elements unless the user doesn't want to have |
;; add all other elements unless the user doesn't want to have |
1266 |
(if event-ok |
(if event-ok |
1267 |
(progn |
(progn |
1268 |
(setq diary-string |
(setq diary-string |
1269 |
(concat diary-string " " |
(concat diary-string " " |
1270 |
(icalendar-format-ical-event e))) |
(icalendar--format-ical-event e))) |
1271 |
(if do-not-ask (setq subject nil)) |
(if do-not-ask (setq subject nil)) |
1272 |
(icalendar-add-diary-entry diary-string diary-file |
(icalendar--add-diary-entry diary-string diary-file |
1273 |
non-marking subject)) |
non-marking subject)) |
1274 |
;; event was not ok |
;; event was not ok |
1275 |
(setq found-error t) |
(setq found-error t) |
1276 |
(setq error-string |
(setq error-string |
1277 |
(format "%s\nCannot handle this event:%s" |
(format "%s\nCannot handle this event:%s" |
1278 |
error-string e)))) |
error-string e)))) |
1279 |
;; handle errors |
;; handle errors |
1280 |
(error |
(error |
1281 |
(message "Ignoring event \"%s\"" e) |
(message "Ignoring event \"%s\"" e) |
1290 |
(message "Converting icalendar...done") |
(message "Converting icalendar...done") |
1291 |
found-error)) |
found-error)) |
1292 |
|
|
1293 |
(defun icalendar-add-diary-entry (string diary-file non-marking |
(defun icalendar--add-diary-entry (string diary-file non-marking |
1294 |
&optional subject) |
&optional subject) |
1295 |
"Add STRING to the diary file DIARY-FILE. |
"Add STRING to the diary file DIARY-FILE. |
1296 |
STRING must be a properly formatted valid diary entry. NON-MARKING |
STRING must be a properly formatted valid diary entry. NON-MARKING |
1297 |
determines whether diary events are created as non-marking. If |
determines whether diary events are created as non-marking. If |
1298 |
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 |
1299 |
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 |
1300 |
the entry." |
the entry." |
1301 |
(when (or (not subject) ; |
(when (or (not subject) ; |
1302 |
(y-or-n-p (format "Add appointment for `%s' to diary? " |
(y-or-n-p (format "Add appointment for `%s' to diary? " |
1303 |
subject))) |
subject))) |
1304 |
(when subject |
(when subject |
1305 |
(setq non-marking |
(setq non-marking |
1306 |
(y-or-n-p (format "Make appointment non-marking? ")))) |
(y-or-n-p (format "Make appointment non-marking? ")))) |
1310 |
(read-file-name "Add appointment to this diary file: "))) |
(read-file-name "Add appointment to this diary file: "))) |
1311 |
(make-diary-entry string non-marking diary-file)))) |
(make-diary-entry string non-marking diary-file)))) |
1312 |
|
|
|
;; ====================================================================== |
|
|
;; (add-hook 'list-diary-entries-hook 'include-icalendar-files) |
|
|
;; ====================================================================== |
|
|
(defun include-icalendar-files () |
|
|
"Not yet implemented.") |
|
|
|
|
1313 |
(provide 'icalendar) |
(provide 'icalendar) |
1314 |
|
|
1315 |
;; arch-tag: 74fdbe8e-0451-4e38-bb61-4416e822f4fc |
;; arch-tag: 74fdbe8e-0451-4e38-bb61-4416e822f4fc |