aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils.c
diff options
context:
space:
mode:
authorLars Henriksen <LarsHenriksen@get2net.dk>2017-11-06 19:30:32 +0100
committerLukas Fleischer <lfleischer@calcurse.org>2018-08-25 10:03:28 +0200
commitfd635150a8bf131c3a8cec2bf41feaf469832dc5 (patch)
tree7349af62e6d6648217efcc0c3b704a7422048e96 /src/utils.c
parentc45da5f5ca550215588ba9483eef62f2a214addb (diff)
downloadcalcurse-fd635150a8bf131c3a8cec2bf41feaf469832dc5.tar.gz
calcurse-fd635150a8bf131c3a8cec2bf41feaf469832dc5.zip
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 <lfleischer@calcurse.org>
Diffstat (limited to 'src/utils.c')
-rw-r--r--src/utils.c49
1 files changed, 44 insertions, 5 deletions
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;
}