summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--src/calcurse.h6
-rw-r--r--src/utils.c49
2 files changed, 47 insertions, 8 deletions
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;
}