# HG changeset patch # User morshed.nader@gmail.com # Date 1294603709 0 # Node ID c61d3e5ec1dac7a8f2f0ca87a065b8c92aab08c5 # Parent 80db1ca54fb668fd064d111591a11e1648acc70f Fix purple_str_to_time(). Fixes #13131. committer: John Bailey diff -r 80db1ca54fb6 -r c61d3e5ec1da configure.ac --- a/configure.ac Sun Jan 09 06:28:35 2011 +0000 +++ b/configure.ac Sun Jan 09 20:08:29 2011 +0000 @@ -329,7 +329,7 @@ dnl ####################################################################### dnl # Check for GLib 2.12 (required) dnl ####################################################################### -PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.12.0 gobject-2.0 gmodule-2.0 gthread-2.0], , [ +PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.12.0 gio-2.0 gobject-2.0 gmodule-2.0 gthread-2.0], , [ AC_MSG_RESULT(no) AC_MSG_ERROR([ @@ -2406,7 +2406,7 @@ AC_MSG_CHECKING(for me pot o' gold) AC_MSG_RESULT(no) -AC_CHECK_FUNCS(gethostid lrand48) +AC_CHECK_FUNCS(gethostid lrand48 timegm) AC_CHECK_FUNCS(memcpy memmove random strchr strerror vprintf) AC_CHECK_HEADERS(malloc.h paths.h sgtty.h stdarg.h sys/cdefs.h) AC_CHECK_HEADERS(sys/file.h sys/filio.h sys/ioctl.h sys/msgbuf.h) diff -r 80db1ca54fb6 -r c61d3e5ec1da libpurple/util.c --- a/libpurple/util.c Sun Jan 09 06:28:35 2011 +0000 +++ b/libpurple/util.c Sun Jan 09 20:08:29 2011 +0000 @@ -664,159 +664,192 @@ return mktime(&tm); } +/* originally taken from GLib trunk 1-6-11 */ +/* originally licensed as LGPL 2+ */ +static time_t +mktime_utc(struct tm *tm) +{ + time_t retval; + +#ifndef HAVE_TIMEGM + static const gint days_before[] = + { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 + }; +#endif + +#ifndef HAVE_TIMEGM + if (tm->tm_mon < 0 || tm->tm_mon > 11) + return (time_t) -1; + + retval = (tm->tm_year - 70) * 365; + retval += (tm->tm_year - 68) / 4; + retval += days_before[tm->tm_mon] + tm->tm_mday - 1; + + if (tm->tm_year % 4 == 0 && tm->tm_mon < 2) + retval -= 1; + + retval = ((((retval * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec; +#else + retval = timegm (tm); +#endif /* !HAVE_TIMEGM */ + + return retval; +} + time_t purple_str_to_time(const char *timestamp, gboolean utc, - struct tm *tm, long *tz_off, const char **rest) + struct tm *tm, long *tz_off, const char **rest) { - time_t retval = 0; - static struct tm t; - const char *c = timestamp; - int year = 0; + struct tm t; + const gchar *str; + gint year = 0; long tzoff = PURPLE_NO_TZ_OFF; - - time(&retval); - localtime_r(&retval, &t); + time_t retval; + gboolean mktime_with_utc = TRUE; if (rest != NULL) *rest = NULL; + g_return_val_if_fail(timestamp != NULL, 0); + + str = timestamp; + + /* Strip leading whitespace */ + while (g_ascii_isspace(*str)) + str++; + + if (*str == '\0') { + if (rest != NULL && *str != '\0') + *rest = str; + + return 0; + } + + if (!g_ascii_isdigit(*str) && *str != '-' && *str != '+') { + if (rest != NULL && *str != '\0') + *rest = str; + + return 0; + } + /* 4 digit year */ - if (sscanf(c, "%04d", &year) && year > 1900) - { - c += 4; - if (*c == '-') - c++; + if (sscanf(str, "%04d", &year) && year >= 1900) { + str += 4; + + if (*str == '-' || *str == '/') + str++; + t.tm_year = year - 1900; } /* 2 digit month */ - if (!sscanf(c, "%02d", &t.tm_mon)) - { - if (rest != NULL && *c != '\0') - *rest = c; + if (!sscanf(str, "%02d", &t.tm_mon)) { + if (rest != NULL && *str != '\0') + *rest = str; + return 0; } - c += 2; - if (*c == '-' || *c == '/') - c++; + + str += 2; t.tm_mon -= 1; + if (*str == '-' || *str == '/') + str++; + /* 2 digit day */ - if (!sscanf(c, "%02d", &t.tm_mday)) - { - if (rest != NULL && *c != '\0') - *rest = c; + if (!sscanf(str, "%02d", &t.tm_mday)) { + if (rest != NULL && *str != '\0') + *rest = str; + return 0; } - c += 2; - if (*c == '/') - { - c++; - - if (!sscanf(c, "%04d", &t.tm_year)) - { - if (rest != NULL && *c != '\0') - *rest = c; + + str += 2; + + /* Grab the year off the end if there's still stuff */ + if (*str == '/' || *str == '-') { + /* But make sure we don't read the year twice */ + if (year >= 1900) { + if (rest != NULL && *str != '\0') + *rest = str; + + return 0; + } + + str++; + + if (!sscanf(str, "%04d", &t.tm_year)) { + if (rest != NULL && *str != '\0') + *rest = str; + return 0; } + t.tm_year -= 1900; - } - else if (*c == 'T' || *c == '.') - { - c++; - /* we have more than a date, keep going */ - - /* 2 digit hour */ - if ((sscanf(c, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && (c = c + 8)) || - (sscanf(c, "%02d%02d%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && (c = c + 6))) + } else if (*str == 'T' || *str == '.') { + str++; + + /* Continue grabbing the hours/minutes/seconds */ + if ((sscanf(str, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && + (str += 8)) || + (sscanf(str, "%02d%02d%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && + (str += 6))) { - gboolean offset_positive = FALSE; - int tzhrs; - int tzmins; - - t.tm_isdst = -1; - - if (*c == '.') { + gint sign, tzhrs, tzmins; + + if (*str == '.') { + /* Cut off those pesky micro-seconds */ do { - c++; - } while (*c >= '0' && *c <= '9'); /* dealing with precision we don't care about */ - } - if (*c == '+') - offset_positive = TRUE; - if (((*c == '+' || *c == '-') && (c = c + 1)) && - ((sscanf(c, "%02d:%02d", &tzhrs, &tzmins) == 2 && (c = c + 5)) || - (sscanf(c, "%02d%02d", &tzhrs, &tzmins) == 2 && (c = c + 4)))) - { - tzoff = tzhrs*60*60 + tzmins*60; - if (offset_positive) - tzoff *= -1; - } - else if ((*c == 'Z') && (c = c + 1)) - { - /* 'Z' = Zulu = UTC */ - tzoff = 0; + str++; + } while (*str >= '0' && *str <= '9'); } - else if (utc) - { - static struct tm tmptm; - time_t tmp; - tmp = mktime(&t); - /* we care about whether it *was* dst, and the offset, here on this - * date, not whether we are currently observing dst locally *now*. - * This isn't perfect, because we would need to know in advance the - * offset we are trying to work out in advance to be sure this - * works for times around dst transitions but it'll have to do. */ - localtime_r(&tmp, &tmptm); - t.tm_isdst = tmptm.tm_isdst; -#ifdef HAVE_TM_GMTOFF - t.tm_gmtoff = tmptm.tm_gmtoff; -#endif - } - - if (rest != NULL && *c != '\0') - { - if (*c == ' ') - c++; - if (*c != '\0') - *rest = c; + + sign = (*str == '+') ? -1 : 1; + + /* Process the timezone */ + if (*str == '+' || *str == '-') { + str++; + + if (((sscanf(str, "%02d:%02d", &tzhrs, &tzmins) == 2 && (str += 5)) || + (sscanf(str, "%02d%02d", &tzhrs, &tzmins) == 2 && (str += 4)))) + { + tzoff = tzhrs * 60 * 60 + tzmins * 60; + tzoff *= sign; + } else { + if (rest != NULL && *str != '\0') + *rest = str; + + return 0; + } + } else if (*str == 'Z') { + /* 'Z' = Zulu = UTC */ + str++; + utc = TRUE; + } else if (!utc) { + /* Local Time */ + t.tm_isdst = -1; + mktime_with_utc = FALSE; } - if (tzoff != PURPLE_NO_TZ_OFF || utc) - { -#if defined(_WIN32) - long sys_tzoff; -#endif - -#if defined(_WIN32) || defined(HAVE_TM_GMTOFF) || defined (HAVE_TIMEZONE) - if (tzoff == PURPLE_NO_TZ_OFF) - tzoff = 0; -#endif - -#ifdef _WIN32 - if ((sys_tzoff = wpurple_get_tz_offset()) == -1) - tzoff = PURPLE_NO_TZ_OFF; - else - tzoff += sys_tzoff; -#else -#ifdef HAVE_TM_GMTOFF - tzoff += t.tm_gmtoff; -#else -# ifdef HAVE_TIMEZONE - tzset(); /* making sure */ - tzoff -= timezone; -# endif -#endif -#endif /* _WIN32 */ - } - } - else - { - if (rest != NULL && *c != '\0') - *rest = c; + if (utc) + tzoff = 0; } } - retval = mktime(&t); + if (rest != NULL && *str != '\0') { + /* Strip trailing whitespace */ + while (g_ascii_isspace(*str)) + str++; + + if (*str != '\0') + *rest = str; + } + + if (mktime_with_utc) + retval = mktime_utc(&t); + else + retval = mktime(&t); if (tm != NULL) *tm = t;