diff options
Diffstat (limited to 'src/LYmktime.c')
-rw-r--r-- | src/LYmktime.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/src/LYmktime.c b/src/LYmktime.c new file mode 100644 index 0000000..5cc1dc4 --- /dev/null +++ b/src/LYmktime.c @@ -0,0 +1,364 @@ +/* $LynxId: LYmktime.c,v 1.20 2019/08/28 22:54:45 tom Exp $ */ + +#include <LYStrings.h> +#include <LYUtils.h> + +#include <parsdate.h> + +#ifdef TEST_DRIVER + +int ascii_toupper(int i) +{ + if (123 > i && i > 96) + return (i - 32); + else + return i; +} + +char *LYstrncpy(char *dst, + const char *src, + int n) +{ + char *val; + int len; + + if (src == 0) + src = ""; + len = strlen(src); + + if (n < 0) + n = 0; + + val = StrNCpy(dst, src, n); + if (len < n) + *(dst + len) = '\0'; + else + *(dst + n) = '\0'; + return val; +} +#define strcasecomp strcasecmp +BOOLEAN WWW_TraceFlag = FALSE; +FILE *TraceFP(void) +{ + return stderr; +} +#define USE_PARSDATE 0 +#else +#define USE_PARSDATE 1 +#endif + +/* + * This function takes a string in the format + * "Mon, 01-Jan-96 13:45:35 GMT" or + * "Mon, 1 Jan 1996 13:45:35 GMT" or + * "dd-mm-yyyy" + * as an argument, and returns its conversion to clock format (seconds since + * 00:00:00 Jan 1 1970), or 0 if the string doesn't match the expected pattern. + * It also returns 0 if the time is in the past and the "absolute" argument is + * FALSE. It is intended for handling 'expires' strings in Version 0 cookies + * homologously to 'max-age' strings in Version 1 cookies, for which 0 is the + * minimum, and greater values are handled as '[max-age seconds] + time(NULL)'. + * If "absolute" is TRUE, we return the clock format value itself, but if + * anything goes wrong when parsing the expected patterns, we still return 0. + * - FM + */ +time_t LYmktime(char *string, + int absolute) +{ +#if USE_PARSDATE + time_t result = 0; + + if (non_empty(string)) { + CTRACE((tfp, "LYmktime: Parsing '%s'\n", string)); + if ((result = parsedate(string, 0)) == ((time_t) -1)) + result = 0; + + if (!absolute) { + time_t now = time((time_t *) NULL); + + if (result < now) + result = 0; + } + if (result != 0) { + CTRACE((tfp, "LYmktime: clock=%" PRI_time_t ", ctime=%s", + CAST_time_t (result), + ctime(&result))); + } + } + return result; +#else + char *s; + time_t clock2; + int day, month, year, hour, minutes, seconds; + char *start; + char temp[8]; + + /* + * Make sure we have a string to parse. - FM + */ + if (!non_empty(string)) + return (0); + s = string; + CTRACE((tfp, "LYmktime: Parsing '%s'\n", s)); + + /* + * Skip any lead alphabetic "Day, " field and seek a numeric day field. - + * FM + */ + while (*s != '\0' && !isdigit(UCH(*s))) + s++; + if (*s == '\0') + return (0); + + /* + * Get the numeric day and convert to an integer. - FM + */ + start = s; + while (*s != '\0' && isdigit(UCH(*s))) + s++; + if (*s == '\0' || (s - start) > 2) + return (0); + LYStrNCpy(temp, start, (s - start)); + day = atoi(temp); + if (day < 1 || day > 31) + return (0); + + /* + * Get the month string and convert to an integer. - FM + */ + while (*s != '\0' && !isalnum(UCH(*s))) + s++; + if (*s == '\0') + return (0); + start = s; + while (*s != '\0' && isalnum(UCH(*s))) + s++; + if ((*s == '\0') || + (s - start) < (isdigit(UCH(*(s - 1))) ? 2 : 3) || + (s - start) > (isdigit(UCH(*(s - 1))) ? 2 : 9)) + return (0); + LYStrNCpy(temp, start, (isdigit(UCH(*(s - 1))) ? 2 : 3)); + switch (TOUPPER(temp[0])) { + case '0': + case '1': + month = atoi(temp); + if (month < 1 || month > 12) { + return (0); + } + break; + case 'A': + if (!strcasecomp(temp, "Apr")) { + month = 4; + } else if (!strcasecomp(temp, "Aug")) { + month = 8; + } else { + return (0); + } + break; + case 'D': + if (!strcasecomp(temp, "Dec")) { + month = 12; + } else { + return (0); + } + break; + case 'F': + if (!strcasecomp(temp, "Feb")) { + month = 2; + } else { + return (0); + } + break; + case 'J': + if (!strcasecomp(temp, "Jan")) { + month = 1; + } else if (!strcasecomp(temp, "Jun")) { + month = 6; + } else if (!strcasecomp(temp, "Jul")) { + month = 7; + } else { + return (0); + } + break; + case 'M': + if (!strcasecomp(temp, "Mar")) { + month = 3; + } else if (!strcasecomp(temp, "May")) { + month = 5; + } else { + return (0); + } + break; + case 'N': + if (!strcasecomp(temp, "Nov")) { + month = 11; + } else { + return (0); + } + break; + case 'O': + if (!strcasecomp(temp, "Oct")) { + month = 10; + } else { + return (0); + } + break; + case 'S': + if (!strcasecomp(temp, "Sep")) { + month = 9; + } else { + return (0); + } + break; + default: + return (0); + } + + /* + * Get the numeric year string and convert to an integer. - FM + */ + while (*s != '\0' && !isdigit(UCH(*s))) + s++; + if (*s == '\0') + return (0); + start = s; + while (*s != '\0' && isdigit(UCH(*s))) + s++; + if ((s - start) == 4) { + LYStrNCpy(temp, start, 4); + } else if ((s - start) == 2) { + /* + * Assume that received 2-digit dates >= 70 are 19xx; others + * are 20xx. Only matters when dealing with broken software + * (HTTP server or web page) which is not Y2K compliant. The + * line is drawn on a best-guess basis; it is impossible for + * this to be completely accurate because it depends on what + * the broken sender software intends. (This totally breaks + * in 2100 -- setting up the next crisis...) - BL + */ + if (atoi(start) >= 70) + LYStrNCpy(temp, "19", 2); + else + LYStrNCpy(temp, "20", 2); + strncat(temp, start, 2); + temp[4] = '\0'; + } else { + return (0); + } + year = atoi(temp); + + /* + * Get the numeric hour string and convert to an integer. - FM + */ + while (*s != '\0' && !isdigit(UCH(*s))) + s++; + if (*s == '\0') { + hour = 0; + minutes = 0; + seconds = 0; + } else { + start = s; + while (*s != '\0' && isdigit(UCH(*s))) + s++; + if (*s != ':' || (s - start) > 2) + return (0); + LYStrNCpy(temp, start, (s - start)); + hour = atoi(temp); + + /* + * Get the numeric minutes string and convert to an integer. - FM + */ + while (*s != '\0' && !isdigit(UCH(*s))) + s++; + if (*s == '\0') + return (0); + start = s; + while (*s != '\0' && isdigit(UCH(*s))) + s++; + if (*s != ':' || (s - start) > 2) + return (0); + LYStrNCpy(temp, start, (s - start)); + minutes = atoi(temp); + + /* + * Get the numeric seconds string and convert to an integer. - FM + */ + while (*s != '\0' && !isdigit(UCH(*s))) + s++; + if (*s == '\0') + return (0); + start = s; + while (*s != '\0' && isdigit(UCH(*s))) + s++; + if (*s == '\0' || (s - start) > 2) + return (0); + LYStrNCpy(temp, start, (s - start)); + seconds = atoi(temp); + } + + /* + * Convert to clock format (seconds since 00:00:00 Jan 1 1970), but then + * zero it if it's in the past and "absolute" is not TRUE. - FM + */ + month -= 3; + if (month < 0) { + month += 12; + year--; + } + day += (year - 1968) * 1461 / 4; + day += ((((month * 153) + 2) / 5) - 672); + clock2 = (time_t) ((day * 60 * 60 * 24) + + (hour * 60 * 60) + + (minutes * 60) + + seconds); + if (absolute == FALSE && (long) (time((time_t *) 0) - clock2) >= 0) + clock2 = (time_t) 0; + if (clock2 > 0) + CTRACE((tfp, "LYmktime: clock=%" PRI_time_t ", ctime=%s", + CAST_time_t (clock2), + ctime(&clock2))); + + return (clock2); +#endif +} + +#ifdef TEST_DRIVER +static void test_mktime(char *source) +{ + time_t before = LYmktime(source, TRUE); + time_t after = parsedate(source, 0); + + printf("TEST %s\n", source); + printf("\t%" PRI_time_t " %s", CAST_time_t (before), ctime(&before)); + printf("\t%" PRI_time_t " %s", CAST_time_t (after), ctime(&after)); + + if (before != after) + printf("\t****\n"); +} + +int main(void) +{ + test_mktime("Mon, 01-Jan-96 13:45:35 GMT"); + test_mktime("Mon, 1 Jan 1996 13:45:35 GMT"); + test_mktime("31-12-1999"); + test_mktime("Wed May 14 22:00:00 2008"); + test_mktime("Sun, 29-Jun-2008 23:19:30 GMT"); + test_mktime("Sun Jul 06 07:00:00 2008 GMT"); + test_mktime("Sun Jul 06 07:00:00 2018 GMT"); + test_mktime("Sun Jul 06 07:00:00 2028 GMT"); + test_mktime("Tue Jan 01 07:00:00 2036 GMT"); + test_mktime("Thu Jan 01 07:00:00 2037 GMT"); + /* problems with 32-bits */ + test_mktime("Fri Jan 01 07:00:00 2038 GMT"); + test_mktime("Sun Jul 06 07:00:00 2038 GMT"); + test_mktime("Mon, 22-Aug-2039 15:13:56 GMT"); + test_mktime("Sat, 28 Aug 2066 18:41:53 -0400"); + test_mktime("Fri, 28 Aug 2099 18:41:53 -0400"); + test_mktime("Sat, 28 Aug 2100 18:41:53 -0400"); + test_mktime("Sun Jul 06 07:00:00 2138 GMT"); + test_mktime("Sat, 28 Aug 2150 18:41:53 -0400"); + test_mktime("Sat, 28 Aug 2200 18:41:53 -0400"); + printf("DONE!\n"); + return 0; +} +#endif |