From: Ricardo Mones Date: Sun, 4 Oct 2015 22:19:30 +0000 (+0200) Subject: Fix bug #3263 ‘Wrong timezone while using date_fmt function’ X-Git-Tag: 3.13.0~26 X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=commitdiff_plain;h=e98adf35bc6efaf304863700f420a47e173831dc Fix bug #3263 ‘Wrong timezone while using date_fmt function’ In addition of %z for timezone offset, the strftime allows also a %Z specifier for timezone name and also some modifiers and field width. All these specifier are detected now and ignored, appending the timezone on the message. Otherwise they would be passed to the strftime call as is, which uses the local timezone, wrong most of the time. --- diff --git a/src/quote_fmt_parse.y b/src/quote_fmt_parse.y index 13c588f14..af7f42146 100644 --- a/src/quote_fmt_parse.y +++ b/src/quote_fmt_parse.y @@ -247,6 +247,40 @@ static int isseparator(int ch) return g_ascii_isspace(ch) || ch == '.' || ch == '-'; } +/* + * Search for glibc extended strftime timezone specs within haystack. + * If not found NULL is returned and the integer pointed by tzspeclen is + * not changed. + * If found a pointer to the start of the specification within haystack + * is returned and the integer pointed by tzspeclen is set to the lenght + * of specification. + */ +static const char* strtzspec(const char *haystack, int *tzspeclen) +{ + const char *p = NULL; + const char *q = NULL; + const char *r = NULL; + + p = strstr(haystack, "%"); + while (p != NULL) { + q = p + 1; + if (!*q) return NULL; + r = strchr("_-0^#", *q); /* skip flags */ + if (r != NULL) { + ++q; + if (!*q) return NULL; + } + while (*q >= '0' && *q <= '9') ++q; /* skip width */ + if (!*q) return NULL; + if (*q == 'z' || *q == 'Z') { /* numeric or name */ + *tzspeclen = 1 + (q - p); + return p; + } + p = strstr(q, "%"); + } + return NULL; +} + static void quote_fmt_show_date(const MsgInfo *msginfo, const gchar *format) { char result[100]; @@ -266,7 +300,6 @@ static void quote_fmt_show_date(const MsgInfo *msginfo, const gchar *format) */ #define RLEFT (sizeof result) - (rptr - result) -#define STR_SIZE(x) (sizeof (x) - 1) zone[0] = 0; @@ -276,11 +309,11 @@ static void quote_fmt_show_date(const MsgInfo *msginfo, const gchar *format) * feed it to strftime(). don't forget that '%%z' mean literal '%z'. */ for (rptr = result, fptr = format; fptr && *fptr && rptr < &result[sizeof result - 1];) { - int perc; + int perc, zlen; const char *p; char *tmp; - if (NULL != (zptr = strstr(fptr, "%z"))) { + if (NULL != (zptr = strtzspec(fptr, &zlen))) { /* * count nr. of prepended percent chars */ @@ -289,7 +322,7 @@ static void quote_fmt_show_date(const MsgInfo *msginfo, const gchar *format) /* * feed to strftime() */ - tmp = g_strndup(fptr, zptr - fptr + (perc % 2 ? 0 : STR_SIZE("%z"))); + tmp = g_strndup(fptr, zptr - fptr + (perc % 2 ? 0 : zlen)); if (tmp) { rptr += strftime(rptr, RLEFT, tmp, <); g_free(tmp); @@ -299,7 +332,7 @@ static void quote_fmt_show_date(const MsgInfo *msginfo, const gchar *format) */ if (zone[0] && perc % 2) rptr += g_snprintf(rptr, RLEFT, "%s", zone); - fptr = zptr + STR_SIZE("%z"); + fptr = zptr + zlen; } else { rptr += strftime(rptr, RLEFT, fptr, <); fptr = NULL; @@ -325,7 +358,6 @@ static void quote_fmt_show_date(const MsgInfo *msginfo, const gchar *format) g_free(utf); } } -#undef STR_SIZE #undef RLEFT }