]> diplodocus.org Git - nmh/blobdiff - sbr/datetime.c
Add check-programs target to Makefile.am to add to `make all'.
[nmh] / sbr / datetime.c
index 8b2513621e8ce4ea4cf805e21dab2c3a6465cf2b..8478414e4a0feb2cdd52b2079bc4f765abe23d2c 100644 (file)
@@ -62,7 +62,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,
@@ -80,12 +83,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. */
@@ -199,14 +206,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 +269,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;
@@ -329,7 +341,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;
         }
     }
@@ -360,8 +380,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) {
+    if (tz) {
+        free(dt_timezone);
+    } else {
         advise (NULL, "did not find VTIMEZONE section for %s", dt_timezone);
         advise (NULL, "did not find VTIMEZONE section for %s", dt_timezone);
+        free(dt_timezone);
         return NULL;
     }
 
         return NULL;
     }