From 27998dc1340a2879a619225bbe43e952c858ef7e Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 4 Jun 2018 14:25:29 +0200 Subject: [PATCH] Remove gmime dependency --- meson.build | 21 +- plparse/meson.build | 1 + plparse/totem-pl-parser-decode-date.c | 608 ++++++++++++++++++++++++++ plparse/totem-pl-parser-decode-date.h | 25 ++ plparse/totem-pl-parser.c | 5 +- 5 files changed, 641 insertions(+), 19 deletions(-) create mode 100644 plparse/totem-pl-parser-decode-date.c create mode 100644 plparse/totem-pl-parser-decode-date.h diff --git a/meson.build b/meson.build index 1c126c5..bad7351 100644 --- a/meson.build +++ b/meson.build @@ -137,25 +137,16 @@ foreach cflag: test_cflags endforeach # gmime dependency -enable_gmime = not get_option('disable-gmime-i-know-what-im-doing') +enable_gmime = true if enable_gmime - have_gmime3 = false - gmime_dep = dependency('gmime-3.0', required : false) - if gmime_dep.found() - cdata.set('HAVE_GMIME3', true, - description: 'GMime 3.0 available in the system') - pkgconf.set('GMIME', 'gmime-3.0') - else - gmime_dep = dependency('gmime-2.6', required : false) - if not gmime_dep.found() - error('libgmime is required to compile totem-pl-parser.') - endif - pkgconf.set('GMIME', 'gmime-2.6') - endif pkgconf.set('USEGMIME', 'yes') cdata.set('HAVE_GMIME', true, description: 'GMime available in the system') - totem_pl_parser_deps += [gmime_dep] + pkgconf.set('GMIME', '') + cdata.set('HAVE_TM_GMTOFF', true, + description: 'Whether struct tm has a tm_gmtoff member') + cdata.set('HAVE_TIMEZONE', true, + description: 'Whether libc defines a timezone variable') else message(''' ************************************************************** diff --git a/plparse/meson.build b/plparse/meson.build index bbc3757..48b0556 100644 --- a/plparse/meson.build +++ b/plparse/meson.build @@ -34,6 +34,7 @@ plparser_sources = [ 'totem-disc.c', 'totem-pl-parser.c', 'totem-pl-parser-amz.c', + 'totem-pl-parser-decode-date.c', 'totem-pl-parser-lines.c', 'totem-pl-parser-media.c', 'totem-pl-parser-misc.c', diff --git a/plparse/totem-pl-parser-decode-date.c b/plparse/totem-pl-parser-decode-date.c new file mode 100644 index 0000000..aefefd1 --- /dev/null +++ b/plparse/totem-pl-parser-decode-date.c @@ -0,0 +1,608 @@ +/* GMime + * Copyright (C) 2000-2009 Jeffrey Stedfast + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "config.h" + +#include + +#include +#include +#include + +#include "totem-pl-parser-decode-date.h" + +#define d(x) + +#define DATE_TOKEN_NON_NUMERIC (1 << 0) +#define DATE_TOKEN_NON_WEEKDAY (1 << 1) +#define DATE_TOKEN_NON_MONTH (1 << 2) +#define DATE_TOKEN_NON_TIME (1 << 3) +#define DATE_TOKEN_HAS_COLON (1 << 4) +#define DATE_TOKEN_NON_TIMEZONE_ALPHA (1 << 5) +#define DATE_TOKEN_NON_TIMEZONE_NUMERIC (1 << 6) +#define DATE_TOKEN_HAS_SIGN (1 << 7) + +static unsigned char gmime_datetok_table[256] = { + 128,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111, 79, 79,111,175,111,175,111,111, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,119,111,111,111,111,111, + 111, 75,111, 79, 75, 79,105, 79,111,111,107,111,111, 73, 75,107, + 79,111,111, 73, 77, 79,111,109,111, 79, 79,111,111,111,111,111, + 111,105,107,107,109,105,111,107,105,105,111,111,107,107,105,105, + 107,111,105,105,105,105,107,111,111,105,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +}; + +/* hrm, is there a library for this shit? */ +static struct { + char *name; + int offset; +} tz_offsets [] = { + { "UT", 0 }, + { "GMT", 0 }, + { "EST", -500 }, /* these are all US timezones. bloody yanks */ + { "EDT", -400 }, + { "CST", -600 }, + { "CDT", -500 }, + { "MST", -700 }, + { "MDT", -600 }, + { "PST", -800 }, + { "PDT", -700 }, + { "Z", 0 }, + { "A", -100 }, + { "M", -1200 }, + { "N", 100 }, + { "Y", 1200 }, +}; + +static char *tm_months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static char *tm_days[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +/* This is where it gets ugly... */ + +typedef struct _date_token { + struct _date_token *next; + unsigned char mask; + const char *start; + size_t len; +} date_token; + +#define date_token_free(tok) g_slice_free (date_token, tok) +#define date_token_new() g_slice_new (date_token) + +static date_token * +datetok (const char *date) +{ + date_token *tokens = NULL, *token, *tail = (date_token *) &tokens; + const char *start, *end; + unsigned char mask; + + start = date; + while (*start) { + /* kill leading whitespace */ + while (*start == ' ' || *start == '\t') + start++; + + if (*start == '\0') + break; + + mask = gmime_datetok_table[(unsigned char) *start]; + + /* find the end of this token */ + end = start + 1; + while (*end && !strchr ("-/,\t\r\n ", *end)) + mask |= gmime_datetok_table[(unsigned char) *end++]; + + if (end != start) { + token = date_token_new (); + token->next = NULL; + token->start = start; + token->len = end - start; + token->mask = mask; + + tail->next = token; + tail = token; + } + + if (*end) + start = end + 1; + else + break; + } + + return tokens; +} + +static int +decode_int (const char *in, size_t inlen) +{ + register const char *inptr; + int sign = 1, val = 0; + const char *inend; + + inptr = in; + inend = in + inlen; + + if (*inptr == '-') { + sign = -1; + inptr++; + } else if (*inptr == '+') + inptr++; + + for ( ; inptr < inend; inptr++) { + if (!(*inptr >= '0' && *inptr <= '9')) + return -1; + else + val = (val * 10) + (*inptr - '0'); + } + + val *= sign; + + return val; +} + +#if 0 +static int +get_days_in_month (int month, int year) +{ + switch (month) { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return 31; + case 4: + case 6: + case 9: + case 11: + return 30; + case 2: + if (g_date_is_leap_year (year)) + return 29; + else + return 28; + default: + return 0; + } +} +#endif + +static int +get_wday (const char *in, size_t inlen) +{ + int wday; + + g_return_val_if_fail (in != NULL, -1); + + if (inlen < 3) + return -1; + + for (wday = 0; wday < 7; wday++) { + if (!g_ascii_strncasecmp (in, tm_days[wday], 3)) + return wday; + } + + return -1; /* unknown week day */ +} + +static int +get_mday (const char *in, size_t inlen) +{ + int mday; + + g_return_val_if_fail (in != NULL, -1); + + mday = decode_int (in, inlen); + + if (mday < 0 || mday > 31) + mday = -1; + + return mday; +} + +static int +get_month (const char *in, size_t inlen) +{ + int i; + + g_return_val_if_fail (in != NULL, -1); + + if (inlen < 3) + return -1; + + for (i = 0; i < 12; i++) { + if (!g_ascii_strncasecmp (in, tm_months[i], 3)) + return i; + } + + return -1; /* unknown month */ +} + +static int +get_year (const char *in, size_t inlen) +{ + int year; + + g_return_val_if_fail (in != NULL, -1); + + if ((year = decode_int (in, inlen)) == -1) + return -1; + + if (year < 100) + year += (year < 70) ? 2000 : 1900; + + if (year < 1969) + return -1; + + return year; +} + +static gboolean +get_time (const char *in, size_t inlen, int *hour, int *min, int *sec) +{ + register const char *inptr; + int *val, colons = 0; + const char *inend; + + *hour = *min = *sec = 0; + + inend = in + inlen; + val = hour; + for (inptr = in; inptr < inend; inptr++) { + if (*inptr == ':') { + colons++; + switch (colons) { + case 1: + val = min; + break; + case 2: + val = sec; + break; + default: + return FALSE; + } + } else if (!(*inptr >= '0' && *inptr <= '9')) + return FALSE; + else + *val = (*val * 10) + (*inptr - '0'); + } + + return TRUE; +} + +static int +get_tzone (date_token **token) +{ + const char *inptr, *inend; + size_t inlen; + int i, t; + + for (i = 0; *token && i < 2; *token = (*token)->next, i++) { + inptr = (*token)->start; + inlen = (*token)->len; + inend = inptr + inlen; + + if (*inptr == '+' || *inptr == '-') { + return decode_int (inptr, inlen); + } else { + if (*inptr == '(') { + inptr++; + if (*(inend - 1) == ')') + inlen -= 2; + else + inlen--; + } + + for (t = 0; t < 15; t++) { + size_t len = strlen (tz_offsets[t].name); + + if (len != inlen) + continue; + + if (!strncmp (inptr, tz_offsets[t].name, len)) + return tz_offsets[t].offset; + } + } + } + + return -1; +} + +static time_t +mktime_utc (struct tm *tm) +{ + time_t tt; + long tz; + + tm->tm_isdst = -1; + tt = mktime (tm); + +#if defined (G_OS_WIN32) + _get_timezone (&tz); + if (tm->tm_isdst > 0) { + int dst; + + _get_dstbias (&dst); + tz += dst; + } +#elif defined (HAVE_TM_GMTOFF) + tz = -tm->tm_gmtoff; +#elif defined (HAVE_TIMEZONE) + if (tm->tm_isdst > 0) { +#if defined (HAVE_ALTZONE) + tz = altzone; +#else /* !defined (HAVE_ALTZONE) */ + tz = (timezone - 3600); +#endif + } else { + tz = timezone; + } +#elif defined (HAVE__TIMEZONE) + tz = _timezone; +#else +#error Neither HAVE_TIMEZONE nor HAVE_TM_GMTOFF defined. Rerun meson. +#endif + + return tt - tz; +} + +static time_t +parse_rfc822_date (date_token *tokens, int *tzone) +{ + int hour, min, sec, offset, n; + date_token *token; + struct tm tm; + time_t t; + + g_return_val_if_fail (tokens != NULL, (time_t) 0); + + token = tokens; + + memset ((void *) &tm, 0, sizeof (struct tm)); + + if ((n = get_wday (token->start, token->len)) != -1) { + /* not all dates may have this... */ + tm.tm_wday = n; + token = token->next; + } + + /* get the mday */ + if (!token || (n = get_mday (token->start, token->len)) == -1) + return (time_t) 0; + + tm.tm_mday = n; + token = token->next; + + /* get the month */ + if (!token || (n = get_month (token->start, token->len)) == -1) + return (time_t) 0; + + tm.tm_mon = n; + token = token->next; + + /* get the year */ + if (!token || (n = get_year (token->start, token->len)) == -1) + return (time_t) 0; + + tm.tm_year = n - 1900; + token = token->next; + + /* get the hour/min/sec */ + if (!token || !get_time (token->start, token->len, &hour, &min, &sec)) + return (time_t) 0; + + tm.tm_hour = hour; + tm.tm_min = min; + tm.tm_sec = sec; + token = token->next; + + /* get the timezone */ + if (!token || (n = get_tzone (&token)) == -1) { + /* I guess we assume tz is GMT? */ + offset = 0; + } else { + offset = n; + } + + t = mktime_utc (&tm); + + /* t is now GMT of the time we want, but not offset by the timezone ... */ + + /* this should convert the time to the GMT equiv time */ + t -= ((offset / 100) * 60 * 60) + (offset % 100) * 60; + + if (tzone) + *tzone = offset; + + return t; +} + + +#define date_token_mask(t) (((date_token *) t)->mask) +#define is_numeric(t) ((date_token_mask (t) & DATE_TOKEN_NON_NUMERIC) == 0) +#define is_weekday(t) ((date_token_mask (t) & DATE_TOKEN_NON_WEEKDAY) == 0) +#define is_month(t) ((date_token_mask (t) & DATE_TOKEN_NON_MONTH) == 0) +#define is_time(t) (((date_token_mask (t) & DATE_TOKEN_NON_TIME) == 0) && (date_token_mask (t) & DATE_TOKEN_HAS_COLON)) +#define is_tzone_alpha(t) ((date_token_mask (t) & DATE_TOKEN_NON_TIMEZONE_ALPHA) == 0) +#define is_tzone_numeric(t) (((date_token_mask (t) & DATE_TOKEN_NON_TIMEZONE_NUMERIC) == 0) && (date_token_mask (t) & DATE_TOKEN_HAS_SIGN)) +#define is_tzone(t) (is_tzone_alpha (t) || is_tzone_numeric (t)) + +static time_t +parse_broken_date (date_token *tokens, int *tzone) +{ + gboolean got_wday, got_month, got_tzone; + int hour, min, sec, offset, n; + date_token *token; + struct tm tm; + time_t t; + + memset ((void *) &tm, 0, sizeof (struct tm)); + got_wday = got_month = got_tzone = FALSE; + offset = 0; + + token = tokens; + while (token) { + if (is_weekday (token) && !got_wday) { + if ((n = get_wday (token->start, token->len)) != -1) { + d(printf ("weekday; ")); + got_wday = TRUE; + tm.tm_wday = n; + goto next; + } + } + + if (is_month (token) && !got_month) { + if ((n = get_month (token->start, token->len)) != -1) { + d(printf ("month; ")); + got_month = TRUE; + tm.tm_mon = n; + goto next; + } + } + + if (is_time (token) && !tm.tm_hour && !tm.tm_min && !tm.tm_sec) { + if (get_time (token->start, token->len, &hour, &min, &sec)) { + d(printf ("time; ")); + tm.tm_hour = hour; + tm.tm_min = min; + tm.tm_sec = sec; + goto next; + } + } + + if (is_tzone (token) && !got_tzone) { + date_token *t = token; + + if ((n = get_tzone (&t)) != -1) { + d(printf ("tzone; ")); + got_tzone = TRUE; + offset = n; + goto next; + } + } + + if (is_numeric (token)) { + if (token->len == 4 && !tm.tm_year) { + if ((n = get_year (token->start, token->len)) != -1) { + d(printf ("year; ")); + tm.tm_year = n - 1900; + goto next; + } + } else { + /* Note: assumes MM-DD-YY ordering if '0 < MM < 12' holds true */ + if (!got_month && token->next && is_numeric (token->next)) { + if ((n = decode_int (token->start, token->len)) > 12) { + goto mday; + } else if (n > 0) { + d(printf ("mon; ")); + got_month = TRUE; + tm.tm_mon = n - 1; + } + goto next; + } else if (!tm.tm_mday && (n = get_mday (token->start, token->len)) != -1) { + mday: + d(printf ("mday; ")); + tm.tm_mday = n; + goto next; + } else if (!tm.tm_year) { + if ((n = get_year (token->start, token->len)) != -1) { + d(printf ("2-digit year; ")); + tm.tm_year = n - 1900; + } + goto next; + } + } + } + + d(printf ("???; ")); + + next: + + token = token->next; + } + + d(printf ("\n")); + + t = mktime_utc (&tm); + + /* t is now GMT of the time we want, but not offset by the timezone ... */ + + /* this should convert the time to the GMT equiv time */ + t -= ((offset / 100) * 60 * 60) + (offset % 100) * 60; + + if (tzone) + *tzone = offset; + + return t; +} + +/** + * g_mime_utils_header_decode_date: + * @str: input date string + * @tz_offset: timezone offset + * + * Decodes the rfc822 date string and saves the GMT offset into + * @tz_offset if non-NULL. + * + * Returns: the time_t representation of the date string specified by + * @str or (time_t) %0 on error. If @tz_offset is non-NULL, the value + * of the timezone offset will be stored. + **/ +time_t +g_mime_utils_header_decode_date (const char *str, int *tz_offset) +{ + date_token *token, *tokens; + time_t date; + + if (!(tokens = datetok (str))) { + if (tz_offset) + *tz_offset = 0; + + return (time_t) 0; + } + + if (!(date = parse_rfc822_date (tokens, tz_offset))) + date = parse_broken_date (tokens, tz_offset); + + /* cleanup */ + while (tokens) { + token = tokens; + tokens = tokens->next; + date_token_free (token); + } + + return date; +} diff --git a/plparse/totem-pl-parser-decode-date.h b/plparse/totem-pl-parser-decode-date.h new file mode 100644 index 0000000..f1a7725 --- /dev/null +++ b/plparse/totem-pl-parser-decode-date.h @@ -0,0 +1,25 @@ +/* GMime + * Copyright (C) 2000-2009 Jeffrey Stedfast + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include + +#include + +time_t g_mime_utils_header_decode_date (const char *str, int *tz_offset); + diff --git a/plparse/totem-pl-parser.c b/plparse/totem-pl-parser.c index 505957a..83fafa1 100644 --- a/plparse/totem-pl-parser.c +++ b/plparse/totem-pl-parser.c @@ -132,16 +132,13 @@ #ifndef TOTEM_PL_PARSER_MINI #include -#ifdef HAVE_GMIME -#include -#endif - #include "totem-pl-parser.h" #include "totemplparser-marshal.h" #include "totem-disc.h" #endif /* !TOTEM_PL_PARSER_MINI */ #include "totem-pl-parser-mini.h" +#include "totem-pl-parser-decode-date.h" #include "totem-pl-parser-wm.h" #include "totem-pl-parser-qt.h" #include "totem-pl-parser-pls.h" -- 2.17.0