summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ical.c341
-rw-r--r--src/note.c7
-rw-r--r--test/Makefile.am2
-rw-r--r--test/data/ical-009.ical13
-rw-r--r--test/data/ical-012.ical93
-rwxr-xr-xtest/ical-009.sh24
-rwxr-xr-xtest/ical-012.sh76
7 files changed, 479 insertions, 77 deletions
diff --git a/src/ical.c b/src/ical.c
index 09d3b2a..521ce0c 100644
--- a/src/ical.c
+++ b/src/ical.c
@@ -54,6 +54,15 @@ typedef enum {
EVENT
} ical_vevent_e;
+typedef enum {
+ NO_PROPERTY,
+ SUMMARY,
+ DESCRIPTION,
+ LOCATION,
+ COMMENT,
+ STATUS
+} ical_property_e;
+
typedef struct {
enum recur_type type;
int freq;
@@ -440,14 +449,16 @@ ical_store_apoint(char *mesg, char *note, long start, long dur,
}
/*
- * Returns an allocated string representing the argument string with escaped
- * characters decoded, or NULL on error.
- * The string is assumed to be the value part of a SUMMARY or DESCRIPTION line.
+ * Return an allocated string containing the decoded 'line' or NULL on error.
+ * The last arguments are used to format a note file entry.
+ * The line is assumed to be the value part of a content line of type TEXT or
+ * INTEGER (RFC 5545, 3.3.11 and 3.3.8) without list or field separators (3.1.1).
*/
-static char *ical_unformat_line(char *line)
+static char *ical_unformat_line(char *line, int eol, int indentation)
{
struct string s;
char *p;
+ const char *INDENT = " ";
string_init(&s);
for (p = line; *p; p++) {
@@ -457,6 +468,8 @@ static char *ical_unformat_line(char *line)
case 'N':
case 'n':
string_catf(&s, "%c", '\n');
+ if (indentation)
+ string_catf(&s, "%s", INDENT);
p++;
break;
case '\\':
@@ -472,9 +485,7 @@ static char *ical_unformat_line(char *line)
break;
case ',':
case ';':
- /*
- * No list or field separator allowed.
- */
+ /* No list or field separator allowed. */
mem_free(s.buf);
return NULL;
default:
@@ -482,6 +493,9 @@ static char *ical_unformat_line(char *line)
break;
}
}
+ /* Add the final EOL removed by ical_readline(). */
+ if (eol)
+ string_catf(&s, "\n");
return string_buf(&s);
}
@@ -879,31 +893,54 @@ ical_read_exdate(llist_t * exc, FILE * log, char *exstr,
return 1;
}
-/* Return an allocated string containing the name of the newly created note. */
-static char *ical_read_note(char *line, unsigned *noskipped,
+/*
+ * Return an allocated string containing a property value to be written in a
+ * note file or NULL on error.
+ */
+static char *ical_read_note(char *line, ical_property_e property, unsigned *noskipped,
ical_types_e item_type, const int itemline,
FILE * log)
{
- char *p, *notestr, *note;
+ const int EOL = 1,
+ INDENT = (property != DESCRIPTION);
+ char *p, *pname, *notestr;
+
+ switch (property) {
+ case DESCRIPTION:
+ pname = "description";
+ break;
+ case LOCATION:
+ pname = "location";
+ break;
+ case COMMENT:
+ pname = "comment";
+ break;
+ case STATUS:
+ pname = "status";
+ break;
+ default:
+ pname = "no property";
+ }
p = ical_get_value(line);
if (!p) {
- ical_log(log, item_type, itemline,
- _("malformed description line."));
+ asprintf(&p, _("malformed %s line."), pname);
+ ical_log(log, item_type, itemline, p);
+ mem_free(p);
(*noskipped)++;
- return NULL;
+ notestr = NULL;
+ goto leave;
}
- notestr = ical_unformat_line(p);
+ notestr = ical_unformat_line(p, EOL, INDENT);
if (!notestr) {
- ical_log(log, item_type, itemline, _("malformed description."));
+ asprintf(&p, _("malformed %s."), pname);
+ ical_log(log, item_type, itemline, p);
+ mem_free(p);
(*noskipped)++;
- return NULL;
- } else {
- note = generate_note(notestr);
- mem_free(notestr);
- return note;
}
+ leave:
+ return notestr;
}
/* Returns an allocated string containing the ical item summary. */
@@ -911,30 +948,31 @@ static char *ical_read_summary(char *line, unsigned *noskipped,
ical_types_e item_type, const int itemline,
FILE * log)
{
- char *p, *summary;
+ const int EOL = 0, INDENT = 0;
+ char *p, *summary = NULL;
p = ical_get_value(line);
if (!p) {
- ical_log(log, item_type, itemline, _("malformed summary line"));
+ ical_log(log, item_type, itemline, _("malformed summary line."));
(*noskipped)++;
- return NULL;
+ goto leave;
}
- summary = ical_unformat_line(p);
+ summary = ical_unformat_line(p, EOL, INDENT);
if (!summary) {
ical_log(log, item_type, itemline, _("malformed summary."));
(*noskipped)++;
- return NULL;
+ goto leave;
}
- /* Event summaries must not contain newlines. */
+ /* An event summary is one line only. */
if (strchr(summary, '\n')) {
ical_log(log, item_type, itemline, _("line break in summary."));
(*noskipped)++;
mem_free(summary);
- return NULL;
+ summary = NULL;
}
-
+ leave:
return summary;
}
@@ -946,21 +984,26 @@ ical_read_event(FILE * fdi, FILE * log, unsigned *noevents,
{
const int ITEMLINE = *lineno - !feof(fdi);
ical_vevent_e vevent_type;
- char *p;
+ ical_property_e property;
+ char *p, *note = NULL, *comment;
+ const char *SEPARATOR = "-- \n";
+ struct string s;
struct {
llist_t exc;
ical_rpt_t *rpt;
- char *mesg, *note;
+ char *mesg, *desc, *loc, *comm, *stat, *note;
long start, end, dur;
int has_alarm;
} vevent;
- int skip_alarm;
+ int skip_alarm, has_note, separator;
vevent_type = UNDEFINED;
memset(&vevent, 0, sizeof vevent);
LLIST_INIT(&vevent.exc);
- skip_alarm = 0;
+ skip_alarm = has_note = separator = 0;
while (ical_readline(fdi, buf, lstore, lineno)) {
+ note = NULL;
+ property = NO_PROPERTY;
if (skip_alarm) {
/*
* Need to skip VALARM properties because some keywords
@@ -970,7 +1013,6 @@ ical_read_event(FILE * fdi, FILE * log, unsigned *noevents,
skip_alarm = 0;
continue;
}
-
if (starts_with_ci(buf, "END:VEVENT")) {
if (!vevent.mesg) {
ical_log(log, ICAL_VEVENT, ITEMLINE,
@@ -982,7 +1024,6 @@ ical_read_event(FILE * fdi, FILE * log, unsigned *noevents,
_("item start date is not defined."));
goto skip;
}
-
if (vevent_type == APPOINTMENT && vevent.dur == 0) {
if (vevent.end != 0) {
vevent.dur = vevent.end - vevent.start;
@@ -994,13 +1035,38 @@ ical_read_event(FILE * fdi, FILE * log, unsigned *noevents,
goto skip;
}
}
-
if (vevent.rpt && vevent.rpt->count) {
vevent.rpt->until =
ical_compute_rpt_until(vevent.start,
vevent.rpt);
}
-
+ if (has_note) {
+ /* Construct string with note file contents. */
+ string_init(&s);
+ if (vevent.desc) {
+ string_catf(&s, "%s", vevent.desc);
+ mem_free(vevent.desc);
+ if (separator)
+ string_catf(&s, SEPARATOR);
+ }
+ if (vevent.loc) {
+ string_catf(&s, _("Location: %s"),
+ vevent.loc);
+ mem_free(vevent.loc);
+ }
+ if (vevent.comm) {
+ string_catf(&s, _("Comment: %s"),
+ vevent.comm);
+ mem_free(vevent.comm);
+ }
+ if (vevent.stat) {
+ string_catf(&s, _("Status: %s"),
+ vevent.stat);
+ mem_free(vevent.stat);
+ }
+ vevent.note = generate_note(string_buf(&s));
+ mem_free(s.buf);
+ }
switch (vevent_type) {
case APPOINTMENT:
ical_store_apoint(vevent.mesg, vevent.note,
@@ -1023,10 +1089,8 @@ ical_read_event(FILE * fdi, FILE * log, unsigned *noevents,
goto skip;
break;
}
-
return;
}
-
if (starts_with_ci(buf, "DTSTART")) {
p = ical_get_value(buf);
if (!p) {
@@ -1079,23 +1143,84 @@ ical_read_event(FILE * fdi, FILE * log, unsigned *noevents,
} else if (starts_with_ci(buf, "BEGIN:VALARM")) {
skip_alarm = vevent.has_alarm = 1;
} else if (starts_with_ci(buf, "DESCRIPTION")) {
- vevent.note = ical_read_note(buf, noskipped,
- ICAL_VEVENT, ITEMLINE, log);
- if (!vevent.note)
+ property = DESCRIPTION;
+ } else if (starts_with_ci(buf, "LOCATION")) {
+ property = LOCATION;
+ } else if (starts_with_ci(buf, "COMMENT")) {
+ property = COMMENT;
+ } else if (starts_with_ci(buf, "STATUS")) {
+ property = STATUS;
+ }
+ if (property) {
+ note = ical_read_note(buf, property, noskipped,
+ ICAL_VEVENT, ITEMLINE, log);
+ if (!note)
goto cleanup;
+ separator = (property != DESCRIPTION);
+ has_note = 1;
+ }
+ switch (property) {
+ case DESCRIPTION:
+ if (vevent.desc) {
+ ical_log(log, ICAL_VEVENT, ITEMLINE,
+ _("only one description allowed."));
+ goto skip;
+ }
+ vevent.desc = note;
+ break;
+ case LOCATION:
+ if (vevent.loc) {
+ ical_log(log, ICAL_VEVENT, ITEMLINE,
+ _("only one location allowed."));
+ goto skip;
+ }
+ vevent.loc = note;
+ break;
+ case COMMENT:
+ /* There may be more than one. */
+ if (vevent.comm) {
+ asprintf(&comment, "%sComment: %s",
+ vevent.comm, note);
+ mem_free(vevent.comm);
+ vevent.comm = comment;
+ } else
+ vevent.comm = note;
+ break;
+ case STATUS:
+ if (vevent.stat) {
+ ical_log(log, ICAL_VEVENT, ITEMLINE,
+ _("only one status allowed."));
+ goto skip;
+ }
+ if (!(starts_with(note, "TENTATIVE") ||
+ starts_with(note, "CONFIRMED") ||
+ starts_with(note, "CANCELLED"))) {
+ ical_log(log, ICAL_VEVENT, ITEMLINE,
+ _("invalid status value."));
+ goto skip;
+ }
+ vevent.stat = note;
+ break;
+ default:
+ break;
}
}
-
ical_log(log, ICAL_VEVENT, ITEMLINE,
_("The ical file seems to be malformed. "
"The end of item was not found."));
-
-skip:
+ skip:
(*noskipped)++;
-
cleanup:
- if (vevent.note)
- mem_free(vevent.note);
+ if (note)
+ mem_free(note);
+ if (vevent.desc)
+ mem_free(vevent.desc);
+ if (vevent.loc)
+ mem_free(vevent.loc);
+ if (vevent.comm)
+ mem_free(vevent.comm);
+ if (vevent.stat)
+ mem_free(vevent.stat);
if (vevent.mesg)
mem_free(vevent.mesg);
if (vevent.rpt)
@@ -1108,16 +1233,22 @@ ical_read_todo(FILE * fdi, FILE * log, unsigned *notodos, unsigned *noskipped,
char *buf, char *lstore, unsigned *lineno, const char *fmt_todo)
{
const int ITEMLINE = *lineno - !feof(fdi);
+ ical_property_e property;
+ char *note = NULL, *comment;
+ const char *SEPARATOR = "-- \n";
+ struct string s;
struct {
- char *mesg, *note;
+ char *mesg, *desc, *loc, *comm, *stat, *note;
int priority;
int completed;
} vtodo;
- int skip_alarm;
+ int skip_alarm, has_note, separator;
memset(&vtodo, 0, sizeof vtodo);
- skip_alarm = 0;
+ skip_alarm = has_note = separator = 0;
while (ical_readline(fdi, buf, lstore, lineno)) {
+ note = NULL;
+ property = NO_PROPERTY;
if (skip_alarm) {
/*
* Need to skip VALARM properties because some keywords
@@ -1127,20 +1258,44 @@ ical_read_todo(FILE * fdi, FILE * log, unsigned *notodos, unsigned *noskipped,
skip_alarm = 0;
continue;
}
-
if (starts_with_ci(buf, "END:VTODO")) {
if (!vtodo.mesg) {
ical_log(log, ICAL_VTODO, ITEMLINE,
_("could not retrieve item summary."));
goto cleanup;
}
-
+ if (has_note) {
+ /* Construct string with note file contents. */
+ string_init(&s);
+ if (vtodo.desc) {
+ string_catf(&s, "%s", vtodo.desc);
+ mem_free(vtodo.desc);
+ if (separator)
+ string_catf(&s, SEPARATOR);
+ }
+ if (vtodo.loc) {
+ string_catf(&s, _("Location: %s"),
+ vtodo.loc);
+ mem_free(vtodo.loc);
+ }
+ if (vtodo.comm) {
+ string_catf(&s, _("Comment: %s"),
+ vtodo.comm);
+ mem_free(vtodo.comm);
+ }
+ if (vtodo.stat) {
+ string_catf(&s, _("Status: %s"),
+ vtodo.stat);
+ mem_free(vtodo.stat);
+ }
+ vtodo.note = generate_note(string_buf(&s));
+ mem_free(s.buf);
+ }
ical_store_todo(vtodo.priority, vtodo.completed,
vtodo.mesg, vtodo.note, fmt_todo);
(*notodos)++;
return;
}
-
if (starts_with_ci(buf, "PRIORITY:")) {
sscanf(buf, "PRIORITY:%d\n", &vtodo.priority);
if (vtodo.priority < 0 || vtodo.priority > 9) {
@@ -1151,6 +1306,7 @@ ical_read_todo(FILE * fdi, FILE * log, unsigned *notodos, unsigned *noskipped,
}
} else if (starts_with_ci(buf, "STATUS:COMPLETED")) {
vtodo.completed = 1;
+ property = STATUS;
} else if (starts_with_ci(buf, "SUMMARY")) {
vtodo.mesg =
ical_read_summary(buf, noskipped, ICAL_VTODO,
@@ -1160,22 +1316,85 @@ ical_read_todo(FILE * fdi, FILE * log, unsigned *notodos, unsigned *noskipped,
} else if (starts_with_ci(buf, "BEGIN:VALARM")) {
skip_alarm = 1;
} else if (starts_with_ci(buf, "DESCRIPTION")) {
- vtodo.note = ical_read_note(buf, noskipped, ICAL_VTODO,
- ITEMLINE, log);
- if (!vtodo.note)
+ property = DESCRIPTION;
+ } else if (starts_with_ci(buf, "LOCATION")) {
+ property = LOCATION;
+ } else if (starts_with_ci(buf, "COMMENT")) {
+ property = COMMENT;
+ } else if (starts_with_ci(buf, "STATUS")) {
+ property = STATUS;
+ }
+ if (property) {
+ note = ical_read_note(buf, property, noskipped,
+ ICAL_VTODO, ITEMLINE, log);
+ if (!note)
goto cleanup;
+ separator = (property != DESCRIPTION);
+ has_note = 1;
+ }
+ switch (property) {
+ case DESCRIPTION:
+ if (vtodo.desc) {
+ ical_log(log, ICAL_VTODO, ITEMLINE,
+ _("only one description allowed."));
+ goto skip;
+ }
+ vtodo.desc = note;
+ break;
+ case LOCATION:
+ if (vtodo.loc) {
+ ical_log(log, ICAL_VTODO, ITEMLINE,
+ _("only one location allowed."));
+ goto skip;
+ }
+ vtodo.loc = note;
+ break;
+ case COMMENT:
+ /* There may be more than one. */
+ if (vtodo.comm) {
+ asprintf(&comment, "%sComment: %s",
+ vtodo.comm, note);
+ mem_free(vtodo.comm);
+ vtodo.comm = comment;
+ } else
+ vtodo.comm = note;
+ break;
+ case STATUS:
+ if (vtodo.stat) {
+ ical_log(log, ICAL_VTODO, ITEMLINE,
+ _("only one status allowed."));
+ goto skip;
+ }
+ if (!(starts_with(note, "NEEDS-ACTION") ||
+ starts_with(note, "COMPLETED") ||
+ starts_with(note, "IN-PROCESS") ||
+ starts_with(note, "CANCELLED"))) {
+ ical_log(log, ICAL_VTODO, ITEMLINE,
+ _("invalid status value."));
+ goto skip;
+ }
+ vtodo.stat = note;
+ break;
+ default:
+ break;
}
}
-
ical_log(log, ICAL_VTODO, ITEMLINE,
_("The ical file seems to be malformed. "
"The end of item was not found."));
-
-skip:
+ skip:
(*noskipped)++;
cleanup:
- if (vtodo.note)
- mem_free(vtodo.note);
+ if (note)
+ mem_free(note);
+ if (vtodo.desc)
+ mem_free(vtodo.desc);
+ if (vtodo.loc)
+ mem_free(vtodo.loc);
+ if (vtodo.comm)
+ mem_free(vtodo.comm);
+ if (vtodo.stat)
+ mem_free(vtodo.stat);
if (vtodo.mesg)
mem_free(vtodo.mesg);
}
diff --git a/src/note.c b/src/note.c
index 2160874..92c1ecf 100644
--- a/src/note.c
+++ b/src/note.c
@@ -59,13 +59,9 @@ HTABLE_PROTOTYPE(htp, note_gc_hash)
char *generate_note(const char *str)
{
char *sha1 = mem_malloc(SHA1_DIGESTLEN * 2 + 1);
- char *notepath, *s;
+ char *notepath;
FILE *fp;
- /* Temporary hack */
- asprintf(&s, "%s\n", str);
- str = s;
-
sha1_digest(str, sha1);
asprintf(&notepath, "%s%s", path_notes, sha1);
fp = fopen(notepath, "w");
@@ -74,7 +70,6 @@ char *generate_note(const char *str)
fputs(str, fp);
file_close(fp, __FILE_POS__);
- mem_free(s);
mem_free(notepath);
return sha1;
}
diff --git a/test/Makefile.am b/test/Makefile.am
index 6b04d86..8a62a0c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -59,6 +59,7 @@ TESTS = \
ical-009.sh \
ical-010.sh \
ical-011.sh \
+ ical-012.sh \
next-001.sh \
next-002.sh \
next-003.sh \
@@ -134,5 +135,6 @@ EXTRA_DIST = \
data/ical-007.ical \
data/ical-008.ical \
data/ical-009.ical \
+ data/ical-012.ical \
data/todo \
data/todo-export
diff --git a/test/data/ical-009.ical b/test/data/ical-009.ical
index 73e9037..39ae422 100644
--- a/test/data/ical-009.ical
+++ b/test/data/ical-009.ical
@@ -63,6 +63,19 @@ BEGIN:VTODO
PRIORITY:1
SUMMARY:an unescaped comma: ,
END:VTODO
+BEGIN:VEVENT
+DTSTART:20200406T221300
+DURATION:PT0H15M0S
+SUMMARY:Invalid STATUS
+STATUS:confirmed
+END:VEVENT
+BEGIN:VEVENT
+DTSTART:20200406T221300
+DURATION:PT0H15M0S
+SUMMARY:LOCATION twice
+LOCATION:first
+LOCATION:second
+END:VEVENT
BEGIN:VTODO
SUMMARY:finally\, missing end of item
END:VCALENDAR
diff --git a/test/data/ical-012.ical b/test/data/ical-012.ical
new file mode 100644
index 0000000..09385fb
--- /dev/null
+++ b/test/data/ical-012.ical
@@ -0,0 +1,93 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+
+BEGIN:VEVENT
+DTSTART:20200404T204500
+DURATION:PT1H30M0S
+SUMMARY:event with one-line description
+DESCRIPTION:event with one-line description
+END:VEVENT
+
+BEGIN:VEVENT
+DTSTART:20200404T204500
+DURATION:PT1H30M0S
+SUMMARY:description and location
+DESCRIPTION:event with description\nand location
+LOCATION: Right here
+END:VEVENT
+
+BEGIN:VEVENT
+DTSTART:20200404T084100
+DURATION:PT1H30M0S
+SUMMARY:No description. Comment and status
+COMMENT:Event without description: a comment\nstreching over\nthree lines
+STATUS:CONFIRMED
+END:VEVENT
+
+BEGIN:VEVENT
+DTSTART:20200404T084100
+DURATION:PT1H30M0S
+SUMMARY:Empty description
+DESCRIPTION:
+END:VEVENT
+
+BEGIN:VEVENT
+DTSTART:20200404T084100
+DURATION:PT1H30M0S
+SUMMARY:Empty description\, but comment
+DESCRIPTION:
+COMMENT:event with empty description
+END:VEVENT
+
+BEGIN:VEVENT
+DTSTART:20200404T204500
+DURATION:PT1H30M0S
+SUMMARY:description\, status\, comment and location
+DESCRIPTION:event with\ndescription\nstatus\ncomment\nand location
+LOCATION: Right here
+COMMENT:just a repetition of description:\nevent with\ndescription\nstatus\ncomment\nand location
+STATUS:CANCELLED
+END:VEVENT
+
+BEGIN:VTODO
+PRIORITY:2
+SUMMARY:todo with one-line description
+DESCRIPTION:todo with one-line description
+END:VTODO
+
+BEGIN:VTODO
+PRIORITY:3
+SUMMARY:description and location
+DESCRIPTION:todo with description\nand location
+LOCATION: Right here
+END:VTODO
+
+BEGIN:VTODO
+PRIORITY:4
+SUMMARY:Comment and status
+COMMENT:Todo with out description. A comment\nstreching over\nthree lines
+STATUS:NEEDS-ACTION
+END:VTODO
+
+BEGIN:VTODO
+PRIORITY:5
+SUMMARY:Empty description
+DESCRIPTION:
+END:VTODO
+
+BEGIN:VTODO
+PRIORITY:6
+SUMMARY:Empty description\,but status
+DESCRIPTION:
+STATUS:COMPLETED
+END:VTODO
+
+BEGIN:VTODO
+SUMMARY:todo with description\, status\, comment and location
+DESCRIPTION:todo with\ndescription\nstatus\ncomment\nand location\,\nbut no priority
+LOCATION: Right here
+COMMENT:mostly a repetition of description:\ntodo with\ndescription\nstatus\ncomment\nand location
+STATUS:IN-PROCESS
+END:VTODO
+
+END:VCALENDAR
diff --git a/test/ical-009.sh b/test/ical-009.sh
index 31dc283..d912f5c 100755
--- a/test/ical-009.sh
+++ b/test/ical-009.sh
@@ -7,27 +7,31 @@ if [ "$1" = 'actual' ]; then
mkdir .calcurse || exit 1
cp "$DATA_DIR/conf" .calcurse || exit 1
out=$("$CALCURSE" -D "$PWD/.calcurse" -i "$DATA_DIR/ical-009.ical" 2>&1)
- echo "$out" | sed -n '4,5p'
- log=$(echo "$out" | awk '$1 == "See" {print $2}')
- cat "$log" | sed '1,17d'
- cat $PWD/.calcurse/notes/* | wc
+ # Print the import report (stdout).
+ echo "$out" | awk '$1 == "Import"; $2 == "apps"'
+ # Find the log file and print the log messages (stderr).
+ logfile=$(echo "$out" | awk '$1 == "See" { print $2 }')
+ sed '1,18d' "$logfile"
+ # One empty note file.
+ cat "$PWD/.calcurse/notes"/* | wc | awk '{ print $1 $2 $3 }'
rm -rf .calcurse || exit 1
elif [ "$1" = 'expected' ]; then
cat <<EOD
-Import process report: 0068 lines read
-2 apps / 0 events / 1 todo / 10 skipped
-
+Import process report: 0081 lines read
+2 apps / 0 events / 1 todo / 12 skipped
VEVENT [12]: could not retrieve event start time.
VEVENT [17]: recurrence frequency not recognized.
-VEVENT [23]: malformed summary line
+VEVENT [23]: malformed summary line.
VTODO [28]: item priority is invalid (must be between 0 and 9).
VEVENT [32]: malformed exceptions line.
VEVENT [39]: line break in summary.
VEVENT [44]: malformed description line.
VEVENT [50]: malformed description.
VTODO [62]: malformed summary.
-VTODO [66]: The ical file seems to be malformed. The end of item was not found.
- 1 0 1
+VEVENT [66]: invalid status value.
+VEVENT [72]: only one location allowed.
+VTODO [79]: The ical file seems to be malformed. The end of item was not found.
+101
EOD
else
./run-test "$0"
diff --git a/test/ical-012.sh b/test/ical-012.sh
new file mode 100755
index 0000000..9175db9
--- /dev/null
+++ b/test/ical-012.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+# Note file creation. Eleven note files are created for 6 apps and 6 todos.
+# To produce a fixed, predictable directory listing it is necessary that the
+# notes are of different sizes (except for the vevent and vtodo empty note which
+# is shared).
+
+. "${TEST_INIT:-./test-init.sh}"
+
+if [ "$1" = 'actual' ]; then
+ mkdir .calcurse &&
+ cp "$DATA_DIR/conf" .calcurse || exit 1
+ "$CALCURSE" -D "$PWD/.calcurse" -i "$DATA_DIR/ical-012.ical"
+ (cd "$PWD/.calcurse/notes/"; cat $(ls -S1))
+ rm -rf .calcurse || exit 1
+elif [ "$1" = 'expected' ]; then
+ cat <<EOD
+Import process report: 0093 lines read
+6 apps / 0 events / 6 todos / 0 skipped
+todo with
+description
+status
+comment
+and location,
+but no priority
+--
+Location: Right here
+Comment: mostly a repetition of description:
+ todo with
+ description
+ status
+ comment
+ and location
+Status: IN-PROCESS
+event with
+description
+status
+comment
+and location
+--
+Location: Right here
+Comment: just a repetition of description:
+ event with
+ description
+ status
+ comment
+ and location
+Status: CANCELLED
+Comment: Todo with out description. A comment
+ streching over
+ three lines
+Status: NEEDS-ACTION
+Comment: Event without description: a comment
+ streching over
+ three lines
+Status: CONFIRMED
+event with description
+and location
+--
+Location: Right here
+todo with description
+and location
+--
+Location: Right here
+
+--
+Comment: event with empty description
+event with one-line description
+todo with one-line description
+
+--
+Status: COMPLETED
+
+EOD
+else
+ ./run-test "$0"
+fi