]> diplodocus.org Git - nmh/blobdiff - sbr/datetime.c
tws.h: Remove redundant TW_SZONE and TW_SZNIL bit-masks.
[nmh] / sbr / datetime.c
index 8b2513621e8ce4ea4cf805e21dab2c3a6465cf2b..20b4be66901f89289cdfab0623215af0bf698831 100644 (file)
@@ -1,5 +1,4 @@
-/*
- * datetime.c -- functions for manipulating RFC 5545 date-time values
+/* datetime.c -- functions for manipulating RFC 5545 date-time values
  *
  * This code is Copyright (c) 2014, by the authors of nmh.
  * See the COPYRIGHT file in the root directory of the nmh
  *
  * This code is Copyright (c) 2014, by the authors of nmh.
  * See the COPYRIGHT file in the root directory of the nmh
@@ -62,7 +61,10 @@ parse_datetime (const char *datetime, const char *zone, int dst,
                 struct tws *tws) {
     char utc_indicator;
     int form_1 = 0;
                 struct tws *tws) {
     char utc_indicator;
     int form_1 = 0;
-    int items_matched =
+    int items_matched;
+
+    memset(tws, 0, sizeof *tws);
+    items_matched =
         sscanf (datetime, "%4d%2d%2dT%2d%2d%2d%c",
                 &tws->tw_year, &tws->tw_mon, &tws->tw_mday,
                 &tws->tw_hour, &tws->tw_min, &tws->tw_sec,
         sscanf (datetime, "%4d%2d%2dT%2d%2d%2d%c",
                 &tws->tw_year, &tws->tw_mon, &tws->tw_mday,
                 &tws->tw_hour, &tws->tw_min, &tws->tw_sec,
@@ -72,7 +74,7 @@ parse_datetime (const char *datetime, const char *zone, int dst,
     if (items_matched == 7) {
         /* The 'Z' must be capital according to RFC 5545 Sec. 3.3.5. */
         if (utc_indicator != 'Z') {
     if (items_matched == 7) {
         /* The 'Z' must be capital according to RFC 5545 Sec. 3.3.5. */
         if (utc_indicator != 'Z') {
-            advise (NULL, "%s has invalid timezone indicator of 0x%x",
+            inform("%s has invalid timezone indicator of 0x%x",
                     datetime, utc_indicator);
             return NOTOK;
         }
                     datetime, utc_indicator);
             return NOTOK;
         }
@@ -80,12 +82,16 @@ parse_datetime (const char *datetime, const char *zone, int dst,
         form_1 = 1;
     }
 
         form_1 = 1;
     }
 
-    if (items_matched >= 6) {
+    /* items_matched of 3 is for, e.g., 20151230.  Assume that means
+       the entire day.  The time fields of the tws struct were
+       initialized to 0 by the memset() above. */
+    if (items_matched >= 6  ||  items_matched == 3) {
         int offset = atoi (zone ? zone : "0");
 
         /* struct tws defines tw_mon over [0, 11]. */
         --tws->tw_mon;
 
         int offset = atoi (zone ? zone : "0");
 
         /* struct tws defines tw_mon over [0, 11]. */
         --tws->tw_mon;
 
+        /* Fill out rest of tws, i.e., its tw_wday and tw_flags. */
         set_dotw (tws);
         /* set_dotw() sets TW_SIMP.  Replace that with TW_SEXP so that
            dasctime() outputs the dotw before the date instead of after. */
         set_dotw (tws);
         /* set_dotw() sets TW_SIMP.  Replace that with TW_SEXP so that
            dasctime() outputs the dotw before the date instead of after. */
@@ -136,9 +142,9 @@ parse_datetime (const char *datetime, const char *zone, int dst,
         }
 
         return OK;
         }
 
         return OK;
-    } else {
-        return NOTOK;
     }
     }
+
+    return NOTOK;
 }
 
 tzdesc_t
 }
 
 tzdesc_t
@@ -170,7 +176,7 @@ load_timezones (const contentline *clines) {
                         params->start_dt = tws.tw_clock;
                     }
                 } else {
                         params->start_dt = tws.tw_clock;
                     }
                 } else {
-                    advise (NULL, "failed to parse start time %s for %s",
+                    inform("failed to parse start time %s for %s",
                             params->dtstart,
                             in_standard ? "standard" : "daylight");
                     return NULL;
                             params->dtstart,
                             in_standard ? "standard" : "daylight");
                     return NULL;
@@ -199,14 +205,18 @@ load_timezones (const contentline *clines) {
                 in_daylight = 1;
                 params = &timezone->daylight_params;
             } else if (! strcasecmp ("TZID", node->name)) {
                 in_daylight = 1;
                 params = &timezone->daylight_params;
             } else if (! strcasecmp ("TZID", node->name)) {
-                timezone->tzid = strdup (node->value);
+                /* See comment below in format_datetime() about removing any enclosing quotes from a
+                   timezone identifier. */
+                char *buf = mh_xmalloc(strlen(node->value) + 1);
+                unquote_string(node->value, buf);
+                timezone->tzid = buf;
             }
         } else {
             if (! strcasecmp ("BEGIN", node->name)  &&
                 ! strcasecmp ("VTIMEZONE", node->value)) {
 
                 in_vtimezone = 1;
             }
         } else {
             if (! strcasecmp ("BEGIN", node->name)  &&
                 ! strcasecmp ("VTIMEZONE", node->value)) {
 
                 in_vtimezone = 1;
-                timezone = mh_xcalloc (1, sizeof (struct tzdesc));
+                NEW0(timezone);
                 if (timezones) {
                     tzdesc_t t;
 
                 if (timezones) {
                     tzdesc_t t;
 
@@ -258,7 +268,8 @@ rrule_clock (const char *rrule, const char *starttime, const char *zone,
              unsigned int year) {
     time_t clock = 0;
 
              unsigned int year) {
     time_t clock = 0;
 
-    if (nmh_strcasestr (rrule, "FREQ=YEARLY;INTERVAL=1")) {
+    if (nmh_strcasestr (rrule, "FREQ=YEARLY;INTERVAL=1")  ||
+        (nmh_strcasestr (rrule, "FREQ=YEARLY")  &&  nmh_strcasestr(rrule, "INTERVAL") == NULL)) {
         struct tws *tws;
         const char *cp;
         int wday = -1, month = -1;
         struct tws *tws;
         const char *cp;
         int wday = -1, month = -1;
@@ -309,9 +320,8 @@ rrule_clock (const char *rrule, const char *starttime, const char *zone,
 
 fail:
     if (clock == 0) {
 
 fail:
     if (clock == 0) {
-        admonish (NULL,
-                  "Unsupported RRULE format: %s, assume local timezone",
-                  rrule);
+        inform("Unsupported RRULE format: %s, assume local timezone, continuing...",
+           rrule);
     }
 
     return clock;
     }
 
     return clock;
@@ -329,7 +339,15 @@ format_datetime (tzdesc_t timezones, const contentline *node) {
     /* Extract the timezone, if specified (RFC 5545 Sec. 3.3.5 Form #3). */
     for (p = node->params; p && p->param_name; p = p->next) {
         if (! strcasecmp (p->param_name, "TZID")  &&  p->values) {
     /* Extract the timezone, if specified (RFC 5545 Sec. 3.3.5 Form #3). */
     for (p = node->params; p && p->param_name; p = p->next) {
         if (! strcasecmp (p->param_name, "TZID")  &&  p->values) {
-            dt_timezone = p->values->value;
+            /* Remove any enclosing quotes from the timezone identifier.  I don't believe that it's
+               legal for it to be quoted, according to RFC 5545 ยง 3.2.19:
+                   tzidparam  = "TZID" "=" [tzidprefix] paramtext
+                   tzidprefix = "/"
+               where paramtext includes SAFE-CHAR, which specifically excludes DQUOTE.  But we'll
+               be generous and strip quotes. */
+            char *buf = mh_xmalloc(strlen(p->values->value) + 1);
+            unquote_string(p->values->value, buf);
+            dt_timezone = buf;
             break;
         }
     }
             break;
         }
     }
@@ -339,10 +357,9 @@ format_datetime (tzdesc_t timezones, const contentline *node) {
            Form #2: DATE WITH UTC TIME */
         if (parse_datetime (node->value, NULL, 0, &tws[0]) == OK) {
             return strdup (dasctime (&tws[0], 0));
            Form #2: DATE WITH UTC TIME */
         if (parse_datetime (node->value, NULL, 0, &tws[0]) == OK) {
             return strdup (dasctime (&tws[0], 0));
-        } else {
-            advise (NULL, "unable to parse datetime %s", node->value);
-            return NULL;
         }
         }
+        inform("unable to parse datetime %s", node->value);
+        return NULL;
     }
 
     /*
     }
 
     /*
@@ -360,8 +377,11 @@ format_datetime (tzdesc_t timezones, const contentline *node) {
         if (tz->tzid  &&  ! strcasecmp (dt_timezone, tz->tzid)) { break; }
     }
 
         if (tz->tzid  &&  ! strcasecmp (dt_timezone, tz->tzid)) { break; }
     }
 
-    if (! tz) {
-        advise (NULL, "did not find VTIMEZONE section for %s", dt_timezone);
+    if (tz) {
+        free(dt_timezone);
+    } else {
+        inform("did not find VTIMEZONE section for %s", dt_timezone);
+        free(dt_timezone);
         return NULL;
     }
 
         return NULL;
     }
 
@@ -402,7 +422,7 @@ format_datetime (tzdesc_t timezones, const contentline *node) {
         }
 
         if (transition[0] < transition[1]) {
         }
 
         if (transition[0] < transition[1]) {
-            advise (NULL, "format_datetime() requires that daylight "
+            inform("format_datetime() requires that daylight "
                     "saving time transition precede standard time "
                     "transition");
             return NULL;
                     "saving time transition precede standard time "
                     "transition");
             return NULL;
@@ -412,7 +432,7 @@ format_datetime (tzdesc_t timezones, const contentline *node) {
                             0, &tws[0]) == OK) {
             dt[0] = tws[0].tw_clock;
         } else {
                             0, &tws[0]) == OK) {
             dt[0] = tws[0].tw_clock;
         } else {
-            advise (NULL, "unable to parse datetime %s", node->value);
+            inform("unable to parse datetime %s", node->value);
             return NULL;
         }
 
             return NULL;
         }
 
@@ -425,7 +445,7 @@ format_datetime (tzdesc_t timezones, const contentline *node) {
                                     &tws[1]) == OK) {
                     dt[1] = tws[1].tw_clock;
                 } else {
                                     &tws[1]) == OK) {
                     dt[1] = tws[1].tw_clock;
                 } else {
-                    advise (NULL, "unable to parse datetime %s",
+                    inform("unable to parse datetime %s",
                             node->value);
                     return NULL;
                 }
                             node->value);
                     return NULL;
                 }
@@ -437,7 +457,7 @@ format_datetime (tzdesc_t timezones, const contentline *node) {
         if (dst) {
             if (tz->daylight_params.start_dt > 0  &&
                 dt[dst] < tz->daylight_params.start_dt) {
         if (dst) {
             if (tz->daylight_params.start_dt > 0  &&
                 dt[dst] < tz->daylight_params.start_dt) {
-                advise (NULL, "date-time of %s is before VTIMEZONE start "
+                inform("date-time of %s is before VTIMEZONE start "
                         "of %s", node->value,
                         tz->daylight_params.dtstart);
                 return NULL;
                         "of %s", node->value,
                         tz->daylight_params.dtstart);
                 return NULL;
@@ -445,7 +465,7 @@ format_datetime (tzdesc_t timezones, const contentline *node) {
         } else {
             if (tz->standard_params.start_dt > 0  &&
                 dt[dst] < tz->standard_params.start_dt) {
         } else {
             if (tz->standard_params.start_dt > 0  &&
                 dt[dst] < tz->standard_params.start_dt) {
-                advise (NULL, "date-time of %s is before VTIMEZONE start "
+                inform("date-time of %s is before VTIMEZONE start "
                         "of %s", node->value,
                         tz->standard_params.dtstart);
                 return NULL;
                         "of %s", node->value,
                         tz->standard_params.dtstart);
                 return NULL;
@@ -453,12 +473,12 @@ format_datetime (tzdesc_t timezones, const contentline *node) {
         }
     } else {
         if (! tp_std) {
         }
     } else {
         if (! tp_std) {
-            advise (NULL, "unsupported date-time format: %s",
+            inform("unsupported date-time format: %s",
                     tz->standard_params.dtstart);
             return NULL;
         }
         if (! tp_dt) {
                     tz->standard_params.dtstart);
             return NULL;
         }
         if (! tp_dt) {
-            advise (NULL, "unsupported date-time format: %s", node->value);
+            inform("unsupported date-time format: %s", node->value);
             return NULL;
         }
     }
             return NULL;
         }
     }