From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: John Hamelink Newsgroups: gmane.emacs.bugs Subject: bug#54939: 29.0.50; icalendar cannot infer the DTEND from DTSTART + DURATION Date: Fri, 15 Apr 2022 10:39:20 +0100 Message-ID: <87k0bqk6eh.fsf@johnhame.link> References: <87fsmfoi0f.fsf@johnhame.link> <87v8vbk97u.fsf@gnus.org> <87fsmf32d0.fsf@johnhame.link> Mime-Version: 1.0 Content-Type: multipart/signed; boundary="===-=-="; micalg=pgp-sha512; protocol="application/pgp-signature" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="15477"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: mu4e 1.6.10; emacs 29.0.50 To: 54939@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri Apr 15 12:49:14 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nfJVo-0003py-Cq for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 15 Apr 2022 12:49:14 +0200 Original-Received: from localhost ([::1]:38060 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nfJVn-0004F6-E0 for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 15 Apr 2022 06:49:11 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:38814) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nfIr2-0007wz-1H for bug-gnu-emacs@gnu.org; Fri, 15 Apr 2022 06:07:05 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:36027) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nfIr0-0008Ku-6x for bug-gnu-emacs@gnu.org; Fri, 15 Apr 2022 06:07:03 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nfIr0-0004Em-1S for bug-gnu-emacs@gnu.org; Fri, 15 Apr 2022 06:07:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: John Hamelink Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 15 Apr 2022 10:07:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 54939 X-GNU-PR-Package: emacs Original-Received: via spool by 54939-submit@debbugs.gnu.org id=B54939.165001718616217 (code B ref 54939); Fri, 15 Apr 2022 10:07:01 +0000 Original-Received: (at 54939) by debbugs.gnu.org; 15 Apr 2022 10:06:26 +0000 Original-Received: from localhost ([127.0.0.1]:58153 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nfIqO-0004DQ-RG for submit@debbugs.gnu.org; Fri, 15 Apr 2022 06:06:25 -0400 Original-Received: from out3-smtp.messagingengine.com ([66.111.4.27]:35637) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nfIqL-0004DB-PR for 54939@debbugs.gnu.org; Fri, 15 Apr 2022 06:06:23 -0400 Original-Received: from compute2.internal (compute2.nyi.internal [10.202.2.46]) by mailout.nyi.internal (Postfix) with ESMTP id 53B025C020D for <54939@debbugs.gnu.org>; Fri, 15 Apr 2022 06:06:16 -0400 (EDT) Original-Received: from mailfrontend1 ([10.202.2.162]) by compute2.internal (MEProxy); Fri, 15 Apr 2022 06:06:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=johnhame.link; h=cc:content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to; s=fm3; t=1650017176; x=1650103576; bh=1Cf8v7qb7C nOvIoMRVun/ZxBn6u0flCL0CdkYWet9bU=; b=i4oIYZfWWuM9v3mg8KK1WwENM1 CWDGQezgbjcfuTdh6gV+u7EPdI1PHrfxodOMQVBKDJJcG5IibnknFyiSvOtPm4Tm 9mTuPCa8yR5FatigV9dGLrK5joH21Mz0AIXGtJvbLvIbHbdW86VHNf7L3FG2W6jS NsIgBQyOBbHHuqW1VGvQyCI86i2Lgy2glgNFvLZRvuFxdauHvEwaEqaXYGcLu8xf WWBJvDigmcXDD/snRw7wSuy/2OvWffugTd85s1JGMPUZowm71+wd1rAM5DfWapo3 Y6fROn1nJ+H9fLzAVKmLYmt4mMx6sUQukWL3wU2SJxc+WimgyiJGPWwL7Big== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1650017176; x= 1650103576; bh=1Cf8v7qb7CnOvIoMRVun/ZxBn6u0flCL0CdkYWet9bU=; b=U jLO7BLA4HD+gEjP8M9wRDYEYdG+SV4bxnisqWEXHok1ov22EvFGn+l+zq4QaVtds +52XzduDPxgNVH+LxqKINRzZ+6H9Kb8hqpfWC+cHf2fy8SQDbOk6+Z3+RIj4J6IN JPef9slHB/USL5C8KIGjx50s2+1SQjxGbr5Hb0p3EN4PlYq/S20GwJLsxR9czIWi h10K3Tdx8Lt5makKNUuTZwzQAPzEPsJFrhKABm6PPY0c6qx3K7KFLUvrsYU0DKVJ XLVMTPGSWc0VHR+3OH5fKxA/ZkJBORqKGa8cZtFtto0qS/GWTW/dPHZQHILrzCh/ lGntxm3dj2GksWl9W/lcQ== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvvddrudelhedgvdefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucenucfjughrpefhvffuffhffggjkfggtgesghdtre ertdertdenucfhrhhomheplfhohhhnucfjrghmvghlihhnkhcuoehmvgesjhhohhhnhhgr mhgvrdhlihhnkheqnecuggftrfgrthhtvghrnhepudekgfetvdegffeileeigfeghfettd egffelteduheevieffleeigeevuddvheeknecuvehluhhsthgvrhfuihiivgeptdenucfr rghrrghmpehmrghilhhfrhhomhepmhgvsehjohhhnhhhrghmvgdrlhhinhhk X-ME-Proxy: Original-Received: by mail.messagingengine.com (Postfix) with ESMTPA for <54939@debbugs.gnu.org>; Fri, 15 Apr 2022 06:06:15 -0400 (EDT) In-reply-to: <87fsmf32d0.fsf@johnhame.link> X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:229923 Archived-At: --===-=-= Content-Type: multipart/mixed; boundary="=-=-=" --=-=-= Content-Type: multipart/mixed; boundary="==-=-=" --==-=-= Content-Type: text/plain Content-Disposition: inline John Hamelink writes: > Great, then I'll have a crack at writing such a patch. I'm new to > Emacs lisp, but this seems to me like a manageable first task! OK, so I've implemented something that's approaching spec - but not ready for full review yet: particularly because I have a problem I need some guidance on. I have introduced the following tests: `gnus-icalendar-dtstart-only-date' (Failing) - `DTSTART' is `DTSTART;TZID=Europe/Berlin:20200915' - `DTEND' is undefined - `DURATION' is undefined - Fails because the `gnus-icalendar--datetimep' returns a truthy value. `gnus-icalendar-dtstart-only-datetime' (Passing) - `DTSTART' is `DTSTART;TZID=Europe/Berlin:20200915T140000' - `DTEND' is undefined - `DURATION' is undefined `gnus-icalendar-dtstart-duration' (Passing) - `DTSTART' is `DTSTART;TZID=Europe/Berlin:20200915T140000' - `DTEND' is undefined - `DURATION' is `PT3H' The reason `gnus-icalendar-dtstart-only-date' currently fails is because I haven't found a good way to differentiate between a date and a datetime - as the spec requires. In an attempt to unblock the rest of the implementation, I used the following: (defun gnus-icalendar--datep (date) "return t if DATE matches a date list." (and (length= date 9) (length= (seq-filter 'integerp (seq-take date 6)) 3))) (defun gnus-icalendar--datetimep (datetime) "Return t if DATETIME matches a date-time list." (and (length= datetime 9) (length= (seq-filter 'integerp (seq-take datetime 6)) 6))) This strategy doesn't work. In `icalendar--decode-isodatetime', hours, minutes and seconds are set to 0 by default, effectively normalising date to datetime. I wonder if there's a function already implemented for this that I don't know about yet? I've included all my patches so far, but I do plan on refactoring more and then checking my contribution against the contributing guidelines before formally submitting a patch for review. I've also sent an email to assign@gnu.org pre-emptively, in case that is necessary. Thanks! JH --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0005-lisp-gnus-gnus-icalendar-Add-RFC5545-DTEND-calculati.patch Content-Transfer-Encoding: quoted-printable From=20c8e460cc0657cb9ddf9e0fbc9abbca32c9344414 Mon Sep 17 00:00:00 2001 From: John Hamelink Date: Fri, 15 Apr 2022 03:35:18 +0100 Subject: [PATCH 5/5] lisp/gnus/gnus-icalendar: Add RFC5545 DTEND calculation function `gnus-icalendar-event--calculate-end-time' returns: - DTEND if it is set - or DTSTART + DURATION if DURATION is set - or DTSTART + 1 Day if DTSTART is a DATE - or DTSTART if DTSTART is a DATETIME =2D-- lisp/gnus/gnus-icalendar.el | 27 ++- test/lisp/gnus/gnus-icalendar-tests.el | 238 +++++++++++++++++++++++++ 2 files changed, 263 insertions(+), 2 deletions(-) diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el index 036832e1d5..64b21794cb 100644 =2D-- a/lisp/gnus/gnus-icalendar.el +++ b/lisp/gnus/gnus-icalendar.el @@ -237,6 +237,29 @@ gnus-icalendar--datetimep (seq-filter 'integerp (seq-take datetime 6)) 6))) =20 +(defun gnus-icalendar-event--calculate-end-time (event zone-map) + "Return DTEND, or calculate it as per RFC5545 3.6.1." + (let* ((dtstart (decode-time (gnus-icalendar-event--decode-datefield + event 'DTSTART zone-map))) + (dtend (gnus-icalendar-event--decode-datefield + event 'DTEND zone-map)) + (duration (gnus-icalendar-event--decode-duration + event 'DURATION))) + (cond + ;; Either Return DTEND + ((not (null dtend)) dtend) + ;; or DTSTART + DURATION if DURATION exists + ((not (null duration)) + (encode-time + (icalendar--add-decoded-times dtstart duration))) + ;; or DTSTART + 1DAY if DTSTART is a DATE + ((gnus-icalendar--datep dtstart) + (encode-time (icalendar--add-decoded-times + dtstart (icalendar--decode-isoduration "1D")))) + ;; or DSTART if DTSTART is a DATE-TIME + ((gnus-icalendar--datetimep dtstart) + (encode-time dtstart))))) + (defun gnus-icalendar-event-from-ical (ical &optional attendee-name-or-ema= il) (let* ((event (car (icalendar--all-events ical))) (organizer (replace-regexp-in-string @@ -266,8 +289,8 @@ gnus-icalendar-event-from-ical :organizer organizer :start-time (gnus-icalendar-event--decode-datefield event 'DTSTART zone-map) =2D :end-time (gnus-icalendar-event--decode-datefield =2D event 'DTEND zone-map) + :end-time (gnus-icalendar-event--calculate-end-time + event zone-map) :rsvp (string=3D (plist-get (cadr attendee) 'RSVP) "TRUE") :participation-type participation-type :req-participants (car attendee-names) diff --git a/test/lisp/gnus/gnus-icalendar-tests.el b/test/lisp/gnus/gnus-i= calendar-tests.el index 5fecfd3773..c26ddaf44c 100644 =2D-- a/test/lisp/gnus/gnus-icalendar-tests.el +++ b/test/lisp/gnus/gnus-icalendar-tests.el @@ -281,5 +281,243 @@ gnus-icalendary-weekly-byday <2020-09-21 14:00-14:30 +1w>"))) (setenv "TZ" tz)))) =20 +(ert-deftest gnus-icalendar-dtstart-duration () + "" + + (let ((tz (getenv "TZ")) + (event (gnus-icalendar-tests--get-ical-event "\ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VTIMEZONE +TZID:Europe/Berlin +X-LIC-LOCATION:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=3DYEARLY;BYMONTH=3D3;BYDAY=3D-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=3DYEARLY;BYMONTH=3D10;BYDAY=3D-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=3DEurope/Berlin:20200915T140000 +DURATION:PT3H +RRULE:FREQ=3DWEEKLY;BYDAY=3DFR,MO,TH,TU,WE +DTSTAMP:20200915T120627Z +ORGANIZER;CN=3Danon@anoncompany.com:mailto:anon@anoncompany.com +UID:7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com +ATTENDEE;CUTYPE=3DINDIVIDUAL;PARTSTAT=3DACCEPTED;RSVP=3DTRUE + ;CN=3Dparticipant@anoncompany.com;X-NUM-GUESTS=3D0:mailto:participant@ano= ncompany.com +CREATED:20200325T095723Z +DESCRIPTION:Coffee talk +LAST-MODIFIED:20200915T120623Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Casual coffee talk +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR" (list "participant@anoncompany.com")))) + + (unwind-protect + (progn + ;; Use this form so as not to rely on system tz database. + ;; Eg hydra.nixos.org. + (setenv "TZ" "CET-1CEST,M3.5.0/2,M10.5.0/3") + (should (eq (eieio-object-class event) 'gnus-icalendar-event-req= uest)) + (should (gnus-icalendar-event:recurring-p event)) + (should (string=3D (gnus-icalendar-event:recurring-interval even= t) "1")) + (should (string=3D (gnus-icalendar-event:start event) "2020-09-1= 5 14:00")) + (should (string=3D (gnus-icalendar-event:end event) "2020-09-15 = 17:00")) + (with-slots (organizer summary description location end-time uid= rsvp participation-type) event + (should (string=3D organizer "anon@anoncompany.com")) + (should (string=3D summary "Casual coffee talk")) + (should (string=3D description "Coffee talk")) + (should (string=3D location "")) + (should (string=3D (format-time-string "%Y-%m-%d %H:%M" end-ti= me) "2020-09-15 17:00")) + (should (string=3D uid "7b6g3m7iftuo90ei4ul00feqn_R20200915T12= 0000@google.com")) + (should rsvp) + (should (eq participation-type 'required))) + (should (equal (sort (gnus-icalendar-event:recurring-days event)= #'<) '(1 2 3 4 5))) + (should (string=3D (gnus-icalendar-event:org-timestamp event) "<= 2020-09-15 14:00-17:00 +1w> +<2020-09-16 14:00-17:00 +1w> +<2020-09-17 14:00-17:00 +1w> +<2020-09-18 14:00-17:00 +1w> +<2020-09-21 14:00-17:00 +1w>")) + + ) + (setenv "TZ" tz)))) + + +(ert-deftest gnus-icalendar-dtstart-only-datetime () + "" + + (let ((tz (getenv "TZ")) + (event (gnus-icalendar-tests--get-ical-event "\ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VTIMEZONE +TZID:Europe/Berlin +X-LIC-LOCATION:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=3DYEARLY;BYMONTH=3D3;BYDAY=3D-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=3DYEARLY;BYMONTH=3D10;BYDAY=3D-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=3DEurope/Berlin:20200915T140000 +RRULE:FREQ=3DWEEKLY;BYDAY=3DFR,MO,TH,TU,WE +DTSTAMP:20200915T120627Z +ORGANIZER;CN=3Danon@anoncompany.com:mailto:anon@anoncompany.com +UID:7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com +ATTENDEE;CUTYPE=3DINDIVIDUAL;PARTSTAT=3DACCEPTED;RSVP=3DTRUE + ;CN=3Dparticipant@anoncompany.com;X-NUM-GUESTS=3D0:mailto:participant@ano= ncompany.com +CREATED:20200325T095723Z +DESCRIPTION:Coffee talk +LAST-MODIFIED:20200915T120623Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Casual coffee talk +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR" (list "participant@anoncompany.com")))) + + (unwind-protect + (progn + ;; Use this form so as not to rely on system tz database. + ;; Eg hydra.nixos.org. + (setenv "TZ" "CET-1CEST,M3.5.0/2,M10.5.0/3") + (should (eq (eieio-object-class event) 'gnus-icalendar-event-req= uest)) + (should (gnus-icalendar-event:recurring-p event)) + (should (string=3D (gnus-icalendar-event:recurring-interval even= t) "1")) + (should (string=3D (gnus-icalendar-event:start event) "2020-09-1= 5 14:00")) + ;; For cases where a "VEVENT" calendar component specifies a + ;; "DTSTART" property with a DATE-TIME value type but no + ;; "DTEND" property, the event ends on the same calendar + ;; date and time of day specified by the "DTSTART" property. + (should (string=3D (gnus-icalendar-event:end event) "2020-09-15 = 14:00")) + (with-slots (organizer summary description location end-time uid= rsvp participation-type) event + (should (string=3D organizer "anon@anoncompany.com")) + (should (string=3D summary "Casual coffee talk")) + (should (string=3D description "Coffee talk")) + (should (string=3D location "")) + (should (string=3D (format-time-string "%Y-%m-%d %H:%M" end-ti= me) "2020-09-15 14:00")) + (should (string=3D uid "7b6g3m7iftuo90ei4ul00feqn_R20200915T12= 0000@google.com")) + (should rsvp) + (should (eq participation-type 'required))) + (should (equal (sort (gnus-icalendar-event:recurring-days event)= #'<) '(1 2 3 4 5))) + (should (string=3D (gnus-icalendar-event:org-timestamp event) "<= 2020-09-15 14:00-14:00 +1w> +<2020-09-16 14:00-14:00 +1w> +<2020-09-17 14:00-14:00 +1w> +<2020-09-18 14:00-14:00 +1w> +<2020-09-21 14:00-14:00 +1w>")) + + ) + (setenv "TZ" tz)))) + +(ert-deftest gnus-icalendar-dtstart-only-date () + "" + + (let ((tz (getenv "TZ")) + (event (gnus-icalendar-tests--get-ical-event "\ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:REQUEST +BEGIN:VTIMEZONE +TZID:Europe/Berlin +X-LIC-LOCATION:Europe/Berlin +BEGIN:DAYLIGHT +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +TZNAME:CEST +DTSTART:19700329T020000 +RRULE:FREQ=3DYEARLY;BYMONTH=3D3;BYDAY=3D-1SU +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +TZNAME:CET +DTSTART:19701025T030000 +RRULE:FREQ=3DYEARLY;BYMONTH=3D10;BYDAY=3D-1SU +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID=3DEurope/Berlin:20200915 +RRULE:FREQ=3DWEEKLY;BYDAY=3DFR,MO,TH,TU,WE +DTSTAMP:20200915T120627Z +ORGANIZER;CN=3Danon@anoncompany.com:mailto:anon@anoncompany.com +UID:7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com +ATTENDEE;CUTYPE=3DINDIVIDUAL;PARTSTAT=3DACCEPTED;RSVP=3DTRUE + ;CN=3Dparticipant@anoncompany.com;X-NUM-GUESTS=3D0:mailto:participant@ano= ncompany.com +CREATED:20200325T095723Z +DESCRIPTION:Coffee talk +LAST-MODIFIED:20200915T120623Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Casual coffee talk +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR" (list "participant@anoncompany.com")))) + + (unwind-protect + (progn + ;; Use this form so as not to rely on system tz database. + ;; Eg hydra.nixos.org. + (setenv "TZ" "CET-1CEST,M3.5.0/2,M10.5.0/3") + (should (eq (eieio-object-class event) 'gnus-icalendar-event-req= uest)) + (should (gnus-icalendar-event:recurring-p event)) + (should (string=3D (gnus-icalendar-event:recurring-interval even= t) "1")) + (should (string=3D (gnus-icalendar-event:start event) "2020-09-1= 5 00:00")) + ;; For cases where a "VEVENT" calendar component + ;; specifies a "DTSTART" property with a DATE value type but no + ;; "DTEND" nor "DURATION" property, the event's duration is take= n to + ;; be one day. + (should (string=3D (gnus-icalendar-event:end event) "2020-09-16 = 00:00")) + (with-slots (organizer summary description location end-time uid= rsvp participation-type) event + (should (string=3D organizer "anon@anoncompany.com")) + (should (string=3D summary "Casual coffee talk")) + (should (string=3D description "Coffee talk")) + (should (string=3D location "")) + (should (string=3D (format-time-string "%Y-%m-%d %H:%M" end-ti= me) "2020-09-16 00:00")) + (should (string=3D uid "7b6g3m7iftuo90ei4ul00feqn_R20200915T12= 0000@google.com")) + (should rsvp) + (should (eq participation-type 'required))) + (should (equal (sort (gnus-icalendar-event:recurring-days event)= #'<) '(1 2 3 4 5))) + (should (string=3D (gnus-icalendar-event:org-timestamp event) "<= 2020-09-15 00:00-00:00 +1w> +<2020-09-16 00:00-00:00 +1w> +<2020-09-17 00:00-00:00 +1w> +<2020-09-18 00:00-00:00 +1w> +<2020-09-21 00:00-00:00 +1w>")) + + ) + (setenv "TZ" tz)))) + (provide 'gnus-icalendar-tests) ;;; gnus-icalendar-tests.el ends here =2D-=20 2.35.2 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0004-lisp-gnus-gnus-icalendar-Add-gnus-icalendar-event-en.patch Content-Transfer-Encoding: quoted-printable From=207134ca9ecadf60efbe703ffd2203d25aada7fdfa Mon Sep 17 00:00:00 2001 From: John Hamelink Date: Fri, 15 Apr 2022 02:51:11 +0100 Subject: [PATCH 4/5] lisp/gnus/gnus-icalendar: Add gnus-icalendar-event:end =2D-- lisp/gnus/gnus-icalendar.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el index 221d98c63a..036832e1d5 100644 =2D-- a/lisp/gnus/gnus-icalendar.el +++ b/lisp/gnus/gnus-icalendar.el @@ -159,6 +159,9 @@ gnus-icalendar-event:recurring-days (cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event)) (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time ev= ent))) =20 +(cl-defmethod gnus-icalendar-event:end ((event gnus-icalendar-event)) + (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:end-time even= t))) + (defun gnus-icalendar-event--decode-duration (event field) (let ((duration (icalendar--get-event-property event field))) (unless (null duration) =2D-=20 2.35.2 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-lisp-gnus-gnus-icalendar-Add-gnus-icalendar-event-de.patch Content-Transfer-Encoding: quoted-printable From=206245118d273eb7672849fa31e3eb4f3992a6237b Mon Sep 17 00:00:00 2001 From: John Hamelink Date: Fri, 15 Apr 2022 02:49:55 +0100 Subject: [PATCH 3/5] lisp/gnus/gnus-icalendar: Add gnus-icalendar-event--decode-duration =2D-- lisp/gnus/gnus-icalendar.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el index 8eb3172e01..221d98c63a 100644 =2D-- a/lisp/gnus/gnus-icalendar.el +++ b/lisp/gnus/gnus-icalendar.el @@ -159,6 +159,11 @@ gnus-icalendar-event:recurring-days (cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event)) (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time ev= ent))) =20 +(defun gnus-icalendar-event--decode-duration (event field) + (let ((duration (icalendar--get-event-property event field))) + (unless (null duration) + (icalendar--decode-isoduration duration)))) + (defun gnus-icalendar-event--decode-datefield (event field zone-map) (let* ((dtdate (icalendar--get-event-property event field)) (dtdate-zone (icalendar--find-time-zone =2D-=20 2.35.2 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-lisp-gnus-gnus-icalendar-Add-gnus-icalendar-event-de.patch Content-Transfer-Encoding: quoted-printable From=206245118d273eb7672849fa31e3eb4f3992a6237b Mon Sep 17 00:00:00 2001 From: John Hamelink Date: Fri, 15 Apr 2022 02:49:55 +0100 Subject: [PATCH 3/5] lisp/gnus/gnus-icalendar: Add gnus-icalendar-event--decode-duration =2D-- lisp/gnus/gnus-icalendar.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el index 8eb3172e01..221d98c63a 100644 =2D-- a/lisp/gnus/gnus-icalendar.el +++ b/lisp/gnus/gnus-icalendar.el @@ -159,6 +159,11 @@ gnus-icalendar-event:recurring-days (cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event)) (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time ev= ent))) =20 +(defun gnus-icalendar-event--decode-duration (event field) + (let ((duration (icalendar--get-event-property event field))) + (unless (null duration) + (icalendar--decode-isoduration duration)))) + (defun gnus-icalendar-event--decode-datefield (event field zone-map) (let* ((dtdate (icalendar--get-event-property event field)) (dtdate-zone (icalendar--find-time-zone =2D-=20 2.35.2 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-lisp-gnus-gnus-icalendar-Return-nil-if-datefield-cou.patch Content-Transfer-Encoding: quoted-printable From=20d46a3e9982eb771255aad802d401c540995c79ac Mon Sep 17 00:00:00 2001 From: John Hamelink Date: Fri, 15 Apr 2022 02:40:45 +0100 Subject: [PATCH 2/5] lisp/gnus/gnus-icalendar: Return nil if datefield coul= dnt be decoded =2D-- lisp/gnus/gnus-icalendar.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el index 7d4a98e034..8eb3172e01 100644 =2D-- a/lisp/gnus/gnus-icalendar.el +++ b/lisp/gnus/gnus-icalendar.el @@ -165,7 +165,8 @@ gnus-icalendar-event--decode-datefield (icalendar--get-event-property-attributes event field) zone-map)) (dtdate-dec (icalendar--decode-isodatetime dtdate nil dtdate-zone= ))) =2D (encode-time dtdate-dec))) + (unless (null dtdate-dec) + (encode-time dtdate-dec)))) =20 (defun gnus-icalendar-event--find-attendee (ical name-or-email) (let* ((event (car (icalendar--all-events ical))) =2D-=20 2.35.2 --==-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-lisp-gnus-gnus-icalendar-Added-date-and-datetime-pre.patch Content-Transfer-Encoding: quoted-printable From=208de7d6f33199d136d05226548db776fc7b64f59e Mon Sep 17 00:00:00 2001 From: John Hamelink Date: Fri, 15 Apr 2022 02:35:05 +0100 Subject: [PATCH 1/5] lisp/gnus/gnus-icalendar: Added date and datetime predicates RFC5545 states that the end-time should be calculated differently depending on whether DTSTART is a date or a date-time. =2D-- lisp/gnus/gnus-icalendar.el | 14 ++++++++++++++ test/lisp/gnus/gnus-icalendar-tests.el | 26 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el index 1bffdf3513..7d4a98e034 100644 =2D-- a/lisp/gnus/gnus-icalendar.el +++ b/lisp/gnus/gnus-icalendar.el @@ -214,6 +214,20 @@ gnus-icalendar-event--get-attendee-names (attendee-names-by-type "REQ-PARTICIPANT") (attendee-names-by-type "OPT-PARTICIPANT"))))) =20 +(defun gnus-icalendar--datep (date) + "return t if DATE matches a date list." + (and (length=3D date 9) + (length=3D + (seq-filter 'integerp (seq-take date 6)) + 3))) + +(defun gnus-icalendar--datetimep (datetime) + "Return t if DATETIME matches a date-time list." + (and (length=3D datetime 9) + (length=3D + (seq-filter 'integerp (seq-take datetime 6)) + 6))) + (defun gnus-icalendar-event-from-ical (ical &optional attendee-name-or-ema= il) (let* ((event (car (icalendar--all-events ical))) (organizer (replace-regexp-in-string diff --git a/test/lisp/gnus/gnus-icalendar-tests.el b/test/lisp/gnus/gnus-i= calendar-tests.el index 348ddf9f05..5fecfd3773 100644 =2D-- a/test/lisp/gnus/gnus-icalendar-tests.el +++ b/test/lisp/gnus/gnus-icalendar-tests.el @@ -38,6 +38,32 @@ gnus-icalendar-tests--get-ical-event (setq event (gnus-icalendar-event-from-buffer (buffer-name) particip= ant))) event)) =20 +(ert-deftest gnus-icalendar-datetimep () + "Can differentiate between dates and datetimes." + (should + (equal + (gnus-icalendar--datetimep + (parse-time-string "2020-09-15 14:00")) + t)) + (should + (equal + (gnus-icalendar--datetimep + (iso8601-parse-date "2020-09-15")) + nil))) + +(ert-deftest gnus-icalendar-datep () + "Can differentiate between dates and datetimes." + (should + (equal + (gnus-icalendar--datep + (iso8601-parse-date "2020-09-15")) + t)) + (should + (equal + (gnus-icalendar--datep + (parse-time-string "2020-09-15 14:00")) + nil))) + (ert-deftest gnus-icalendar-parse () "test" (let ((tz (getenv "TZ")) =2D-=20 2.35.2 --==-=-=-- --=-=-=-- --===-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQJFBAEBCgAvFiEE+Yt/N+nvP8wO2AcVFT3f6aVKmkwFAmJZQ5YRHG1lQGpvaG5o YW1lLmxpbmsACgkQFT3f6aVKmky5hhAApQ/0kMCBn8RcuCVDJWBwavhg0qMl4Cak Yy0wilIJW0RH5tFzKTVGQe56o6MaqE+0z4N2pWaCJRQqK/LFGcYqIH9CbSxIBb+k 4zKJUhb03hcF3Tzeh0ObENpInC3XdeNUfG0sYV8ozVCfUKuElfZSqIwn8tawFrGl f6/EGic53D2wiIDVc1NDi3U6SksoIaq0v40P0sLPsTjEE2Knje6hhDK84wLlA4WV 2RS/ZuvfJu7gcuJAGeuHYp9auE/+14o5aO+SOGfJid9KY8CfM7oQyldALdzqmAS9 pZqWiNYU/BzoSjVRxYEg37q6gr//bwMS4jqYBOSk/Jvk5lKTpac+cxsmbxv+V1e7 M2j7tTnC35IOEN5AvdwpPw/9scajtsoGwK/y2/0fdAuqG5IqgafqJDrpecVCS5oS WcSupR0Twlt3U+HbcxeQ88ccF55mws8Lt/v3kbheOgx/iVBtpZA+MGsK9DplNHhw 9QD82QE9FQpbLRZWSfVbP//oGDzGgeMKXQiDYqPsu/Yp8LBDkXCnQyxVelm+D/Pu hDBZcpCyZp9Ac7k96GtrUIVE7skYN14l4Gmz6Jx1a81jaP2pNghZKMXOVWHapHSr WPDR1kSSFtOdMsIYOWa+sjjs1Sic68ZnqesvxxLllLOJc/zO0fD5gRePgUnQqJd6 NcKNTIoW4r4= =p7x2 -----END PGP SIGNATURE----- --===-=-=--