From e4e2e0eb20794972b8d4c89dcfeb6c257c45c3a1 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Tue, 7 Feb 2017 17:52:14 +0100 Subject: Gracefully parse iCal parameters with colons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to RFC 5545, iCalendar content lines can have optional parameters, which can be quoted strings containing colons (":"). Make sure that such colons are not interpreted as delimiters marking the start of the value string. Also, add a test case that covers this corner case. Reported-by: HÃ¥kan Jerning Signed-off-by: Lukas Fleischer --- src/ical.c | 36 ++++++++++++++++++++++++------------ test/Makefile.am | 1 + test/data/ical-008.ical | 12 ++++++++++++ test/ical-008.sh | 28 ++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 test/data/ical-008.ical create mode 100755 test/ical-008.sh diff --git a/src/ical.c b/src/ical.c index f17b1cf..c2c8c5b 100644 --- a/src/ical.c +++ b/src/ical.c @@ -670,6 +670,21 @@ static long ical_compute_rpt_until(long start, ical_rpt_t * rpt) } } +/* + * Skip to the value part of an iCalendar content line. + */ +static char *ical_get_value(char *p) +{ + for (; *p != ':'; p++) { + if (*p == '\0') + return NULL; + if (*p == '"') + for (p++; *p != '"'; p++); + } + + return p + 1; +} + /* * Read a recurrence rule from an iCalendar RRULE string. * @@ -717,14 +732,13 @@ static ical_rpt_t *ical_read_rrule(FILE * log, char *rrulestr, ical_rpt_t *rpt; char *p; - p = strchr(rrulestr, ':'); + p = ical_get_value(rrulestr); if (!p) { ical_log(log, ICAL_VEVENT, itemline, _("recurrence rule malformed.")); (*noskipped)++; return NULL; } - p++; rpt = mem_malloc(sizeof(ical_rpt_t)); memset(rpt, 0, sizeof(ical_rpt_t)); @@ -807,14 +821,13 @@ ical_read_exdate(llist_t * exc, FILE * log, char *exstr, { char *p, *q; - p = strchr(exstr, ':'); + p = ical_get_value(exstr); if (!p) { ical_log(log, ICAL_VEVENT, itemline, _("recurrence exception dates malformed.")); (*noskipped)++; return; } - p++; while ((q = strchr(p, ',')) != NULL) { char buf[BUFSIZ]; @@ -835,14 +848,13 @@ static char *ical_read_note(char *line, unsigned *noskipped, { char *p, *notestr, *note; - p = strchr(line, ':'); + p = ical_get_value(line); if (!p) { ical_log(log, item_type, itemline, _("description malformed.")); (*noskipped)++; return NULL; } - p++; notestr = ical_unformat_line(p); if (notestr == NULL) { @@ -865,11 +877,11 @@ static char *ical_read_summary(char *line) { char *p, *summary; - p = strchr(line, ':'); + p = ical_get_value(line); if (!p) return NULL; - summary = ical_unformat_line(p + 1); + summary = ical_unformat_line(p); if (!summary) return NULL; @@ -970,28 +982,28 @@ ical_read_event(FILE * fdi, FILE * log, unsigned *noevents, } if (starts_with_ci(buf, "DTSTART")) { - p = strchr(buf, ':'); + p = ical_get_value(buf); if (!p) { ical_log(log, ICAL_VEVENT, ITEMLINE, _("event start time malformed.")); goto cleanup; } - vevent.start = ical_datetime2time_t(++p, &vevent_type); + vevent.start = ical_datetime2time_t(p, &vevent_type); if (!vevent.start) { ical_log(log, ICAL_VEVENT, ITEMLINE, _("could not retrieve event start time.")); goto cleanup; } } else if (starts_with_ci(buf, "DTEND")) { - p = strchr(buf, ':'); + p = ical_get_value(buf); if (!p) { ical_log(log, ICAL_VEVENT, ITEMLINE, _("event end time malformed.")); goto cleanup; } - vevent.end = ical_datetime2time_t(++p, &vevent_type); + vevent.end = ical_datetime2time_t(p, &vevent_type); if (!vevent.end) { ical_log(log, ICAL_VEVENT, ITEMLINE, _("could not retrieve event end time.")); diff --git a/test/Makefile.am b/test/Makefile.am index f8d6088..b59a1a8 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -49,6 +49,7 @@ TESTS = \ ical-005.sh \ ical-006.sh \ ical-007.sh \ + ical-008.sh \ next-001.sh \ search-001.sh \ bug-002.sh \ diff --git a/test/data/ical-008.ical b/test/data/ical-008.ical new file mode 100644 index 0000000..51625d5 --- /dev/null +++ b/test/data/ical-008.ical @@ -0,0 +1,12 @@ +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +DTSTART;TZID="(UTC+01:00) Amsterdam, Berlin, Bern, Rom, Stockholm, Wien":19800101T000100 +DURATION:P1DT9H17M0S +SUMMARY:Calibrator's +END:VEVENT +BEGIN:VTODO +PRIORITY:1 +SUMMARY:Nary parabled Louvre's fleetest mered +END:VTODO +END:VCALENDAR diff --git a/test/ical-008.sh b/test/ical-008.sh new file mode 100755 index 0000000..ff45cad --- /dev/null +++ b/test/ical-008.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +. "${TEST_INIT:-./test-init.sh}" + +if [ "$1" = 'actual' ]; then + mkdir .calcurse || exit 1 + cp "$DATA_DIR/conf" .calcurse || exit 1 + "$CALCURSE" -D "$PWD/.calcurse" -i "$DATA_DIR/ical-008.ical" + "$CALCURSE" -D "$PWD/.calcurse" -s01/01/1980 -r2 + "$CALCURSE" -D "$PWD/.calcurse" -t + rm -rf .calcurse || exit 1 +elif [ "$1" = 'expected' ]; then + cat < ..:.. + Calibrator's + +01/02/80: + - ..:.. -> 09:18 + Calibrator's +to do: +0. Nary parabled Louvre's fleetest mered +EOD +else + ./run-test "$0" +fi -- cgit v1.2.3-70-g09d2