summaryrefslogtreecommitdiffstats
path: root/src/LYmktime.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/LYmktime.c')
-rw-r--r--src/LYmktime.c364
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