From fd635150a8bf131c3a8cec2bf41feaf469832dc5 Mon Sep 17 00:00:00 2001 From: Lars Henriksen Date: Mon, 6 Nov 2017 19:30:32 +0100 Subject: Start and end time validation. All appointment times are checked for validity. Overflow by time arithmetic is detected. End times are checked when appointments are moved. Three functions are involved: parse_datetime(), parse_duration() and parse_date_duration(); they all have a new argument for validation purposes. Signed-off-by: Lukas Fleischer --- src/calcurse.h | 6 +++--- src/utils.c | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/calcurse.h b/src/calcurse.h index 178af1f..88a0916 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -1162,9 +1162,9 @@ int parse_date_interactive(const char *, int *, int *, int *); int check_sec(time_t *); int check_time(unsigned, unsigned); int parse_time(const char *, unsigned *, unsigned *); -int parse_duration(const char *, unsigned *); -int parse_date_duration(const char *, unsigned *); -int parse_datetime(const char *, long *); +int parse_duration(const char *, unsigned *, time_t); +int parse_date_duration(const char *, unsigned *, time_t); +int parse_datetime(const char *, time_t *, time_t); void file_close(FILE *, const char *); void psleep(unsigned); int fork_exec(int *, int *, const char *, const char *const *); diff --git a/src/utils.c b/src/utils.c index 8728dfb..0690d4e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -936,10 +936,11 @@ parse_date_interactive(const char *datestr, int *year, int *month, int *day) /* * Convert a date duration string into a number of days. + * If start is non-zero, the final end time is validated. * * Returns 1 on success and 0 on failure. */ -int parse_date_duration(const char *string, unsigned *days) +int parse_date_duration(const char *string, unsigned *days, time_t start) { enum { STATE_INITIAL, @@ -1000,6 +1001,17 @@ int parse_date_duration(const char *string, unsigned *days) return 0; dur += in; + if (start) { + /* wanted: start = start + dur * DAYINSEC */ + int p, s; + if (overflow_mul(dur, DAYINSEC, &p)) + return 0; + if (overflow_add(start, p, &s)) + return 0; + start = s; + if (!check_sec(&start)) + return 0; + } *days = dur; return 1; @@ -1051,6 +1063,7 @@ int parse_time(const char *string, unsigned *hour, unsigned *minute) /* * Converts a duration string into minutes. + * If start time is non-zero, the final end time is validated. * * Allowed formats (noted as regular expressions): * @@ -1062,7 +1075,7 @@ int parse_time(const char *string, unsigned *hour, unsigned *minute) * * Returns 1 on success and 0 on failure. */ -int parse_duration(const char *string, unsigned *duration) +int parse_duration(const char *string, unsigned *duration, time_t start) { enum { STATE_INITIAL, @@ -1140,13 +1153,23 @@ int parse_duration(const char *string, unsigned *duration) denom = 1; } } - if ((state == STATE_HHMM_MM && in >= HOURINMIN) || ((state == STATE_DDHHMM_HH || state == STATE_DDHHMM_MM) && in > 0)) return 0; - dur += in; + if (start) { + /* wanted: end = start + dur * MININSEC */ + time_t end; + int p, s; + if (overflow_mul(dur, MININSEC, &p)) + return 0; + if (overflow_add(start, p, &s)) + return 0; + end = s; + if (!check_sec(&end) || end < start) + return 0; + } *duration = dur; return 1; @@ -1161,10 +1184,13 @@ int parse_duration(const char *string, unsigned *duration) * updated and the date remains the same. If the string contains both a date * and a time, the time stamp is updated to match the given string. * + * The final time is validated. In addition, if a positive duration is given, + * time + duration validated (zero duration needs no validation). + * * Returns a positive value on success and 0 on failure. The least-significant * bit is set if the date was updated. Bit 1 is set if the time was updated. */ -int parse_datetime(const char *string, long *ts) +int parse_datetime(const char *string, time_t *ts, time_t dur) { char *t = mem_strdup(string); char *p = strchr(t, ' '); @@ -1197,6 +1223,19 @@ int parse_datetime(const char *string, long *ts) *ts = update_time_in_date(*ts, hour, minute); mem_free(t); + /* Is the resulting time a valid (start or end) time? */ + if (!check_sec(ts)) + return 0; + /* Is the resulting time + dur a valid end time? */ + if (dur) { + /* want: sec = *ts + dur */ + int s; + if (overflow_add(*ts, dur, &s)) + return 0; + time_t sec = s; + if (!check_sec(&sec)) + return 0; + } return ret; } -- cgit v1.2.3-70-g09d2