#include "lib/lib.h"
#include "protos.h"
-static const char *next_word(const char *s)
-{
- while (*s && !ISSPACE(*s))
- s++;
- SKIPWS(s);
- return s;
-}
-
-int mutt_check_month(const char *s)
-{
- for (int i = 0; i < 12; i++)
- if (mutt_strncasecmp(s, Months[i], 3) == 0)
- return i;
- return -1; /* error */
-}
-
-static bool is_day_name(const char *s)
-{
- if ((strlen(s) < 3) || !*(s + 3) || !ISSPACE(*(s + 3)))
- return false;
- for (int i = 0; i < 7; i++)
- if (mutt_strncasecmp(s, Weekdays[i], 3) == 0)
- return true;
- return false;
-}
-
/*
* A valid message separator looks like:
*
* @note RFC3548 obsoletes RFC2045.
* @note RFC4648 obsoletes RFC3548.
*
+ * | Data | Description
+ * | :----------------- | :--------------------------------------------------
+ * | #Index_64 | Lookup table for Base64 encoding characters
+ *
* | Function | Description
* | :----------------- | :-------------------------------------------------
* | mutt_from_base64() | convert null-terminated base64 string to raw bytes
};
// clang-format off
-/* This is very similar to the table in imap/utf7.c
+/**
+ * Index_64 - Lookup table for Base64 encoding characters
+ *
+ * @note This is very similar to the table in imap/utf7.c
+ *
* Encoding chars:
- * utf7 A-Za-z0-9+,
- * mime A-Za-z0-9+/
+ * * utf7 A-Za-z0-9+,
+ * * mime A-Za-z0-9+/
*/
const int Index_64[128] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
* General purpose object for storing and parsing strings
*
* @authors
+ * Copyright (C) 2017 Ian Zimmerman <itz@primate.net>
* Copyright (C) 2017 Richard Russon <rich@flatcap.org>
*
* @copyright
* General purpose object for storing and parsing strings
*
* @authors
+ * Copyright (C) 2017 Ian Zimmerman <itz@primate.net>
+ * Copyright (C) 2017 Richard Russon <rich@flatcap.org>
+ *
* @copyright
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
int destroy; /**< destroy 'data' when done? */
};
+#define MoreArgs(p) (*p->dptr && (*p->dptr != ';') && (*p->dptr != '#'))
+
struct Buffer *mutt_buffer_new(void);
struct Buffer *mutt_buffer_init(struct Buffer *b);
struct Buffer *mutt_buffer_from(char *seed);
*
* Some commonly used time and date functions.
*
+ * | Data | Description
+ * | :-------------------- | :--------------------------------------------------
+ * | #Months | Months of the year (abbreviated)
+ * | #TimeZones | Lookup table of Time Zones
+ * | #Weekdays | Day of the week (abbreviated)
+ *
* | Function | Description
* | :-------------------- | :--------------------------------------------------
+ * | is_day_name() | Is the string a valid day name
+ * | mutt_check_month() | Is the string a valid month name
* | mutt_local_tz() | Calculate the local timezone in seconds east of UTC
* | mutt_make_date() | Write a date in RFC822 format to a buffer
* | mutt_mktime() | Convert `struct tm` to `time_t`
* | mutt_normalize_time() | Fix the contents of a struct tm
+ * | mutt_parse_date() | Parse a date string in RFC822 format
*/
#include "config.h"
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include "date.h"
+#include "debug.h"
+#include "string2.h"
/* theoretically time_t can be float but it is integer on most (if not all) systems */
#define TIME_T_MAX ((((time_t) 1 << (sizeof(time_t) * 8 - 2)) - 1) * 2 + 1)
#define TM_YEAR_MAX \
(1970 + (((((TIME_T_MAX - 59) / 60) - 59) / 60) - 23) / 24 / 366)
+/**
+ * Weekdays - Day of the week (abbreviated)
+ */
const char *const Weekdays[] = {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
};
+
+/**
+ * Months - Months of the year (abbreviated)
+ */
const char *const Months[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
- "Aug", "Sep", "Oct", "Nov", "Dec", "ERR",
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+ "Aug", "Sep", "Oct", "Nov", "Dec", "ERR",
};
+// clang-format off
+/**
+ * TimeZones - Lookup table of Time Zones
+ *
+ * @note Keep in alphabetical order
+ */
+const struct Tz TimeZones[] = {
+ { "aat", 1, 0, true }, /* Atlantic Africa Time */
+ { "adt", 4, 0, false }, /* Arabia DST */
+ { "ast", 3, 0, false }, /* Arabia */
+//{ "ast", 4, 0, true }, /* Atlantic */
+ { "bst", 1, 0, false }, /* British DST */
+ { "cat", 1, 0, false }, /* Central Africa */
+ { "cdt", 5, 0, true },
+ { "cest", 2, 0, false }, /* Central Europe DST */
+ { "cet", 1, 0, false }, /* Central Europe */
+ { "cst", 6, 0, true },
+//{ "cst", 8, 0, false }, /* China */
+//{ "cst", 9, 30, false }, /* Australian Central Standard Time */
+ { "eat", 3, 0, false }, /* East Africa */
+ { "edt", 4, 0, true },
+ { "eest", 3, 0, false }, /* Eastern Europe DST */
+ { "eet", 2, 0, false }, /* Eastern Europe */
+ { "egst", 0, 0, false }, /* Eastern Greenland DST */
+ { "egt", 1, 0, true }, /* Eastern Greenland */
+ { "est", 5, 0, true },
+ { "gmt", 0, 0, false },
+ { "gst", 4, 0, false }, /* Presian Gulf */
+ { "hkt", 8, 0, false }, /* Hong Kong */
+ { "ict", 7, 0, false }, /* Indochina */
+ { "idt", 3, 0, false }, /* Israel DST */
+ { "ist", 2, 0, false }, /* Israel */
+//{ "ist", 5, 30, false }, /* India */
+ { "jst", 9, 0, false }, /* Japan */
+ { "kst", 9, 0, false }, /* Korea */
+ { "mdt", 6, 0, true },
+ { "met", 1, 0, false }, /* This is now officially CET */
+ { "msd", 4, 0, false }, /* Moscow DST */
+ { "msk", 3, 0, false }, /* Moscow */
+ { "mst", 7, 0, true },
+ { "nzdt", 13, 0, false }, /* New Zealand DST */
+ { "nzst", 12, 0, false }, /* New Zealand */
+ { "pdt", 7, 0, true },
+ { "pst", 8, 0, true },
+ { "sat", 2, 0, false }, /* South Africa */
+ { "smt", 4, 0, false }, /* Seychelles */
+ { "sst", 11, 0, true }, /* Samoa */
+//{ "sst", 8, 0, false }, /* Singapore */
+ { "utc", 0, 0, false },
+ { "wat", 0, 0, false }, /* West Africa */
+ { "west", 1, 0, false }, /* Western Europe DST */
+ { "wet", 0, 0, false }, /* Western Europe */
+ { "wgst", 2, 0, true }, /* Western Greenland DST */
+ { "wgt", 3, 0, true }, /* Western Greenland */
+ { "wst", 8, 0, false }, /* Western Australia */
+};
+// clang-format on
+
/**
* compute_tz - Calculate the number of seconds east of UTC
* @param g Local time
return 0;
}
+/**
+ * uncomment_timezone - Strip ()s from a timezone string
+ * @param buf Buffer to store the results
+ * @param buflen Length of buffer
+ * @param tz Timezone string to copy
+ * @retval ptr Results buffer
+ *
+ * Some time formats have the timezone in ()s, e.g. (MST) or (-0700)
+ *
+ * @note If the timezone doesn't have any ()s the function will return a
+ * pointer to the original string.
+ */
+static const char *uncomment_timezone(char *buf, size_t buflen, const char *tz)
+{
+ char *p = NULL;
+ size_t len;
+
+ if (*tz != '(')
+ return tz; /* no need to do anything */
+ tz = skip_email_wsp(tz + 1);
+ p = strpbrk(tz, " )");
+ if (!p)
+ return tz;
+ len = p - tz;
+ if (len > (buflen - 1))
+ len = buflen - 1;
+ memcpy(buf, tz, len);
+ buf[len] = 0;
+ return buf;
+}
+
/**
* mutt_local_tz - Calculate the local timezone in seconds east of UTC
* @param t Time to examine
return buf;
}
+/**
+ * mutt_check_month - Is the string a valid month name
+ * @param s - String to check
+ * @retval num Index into Months array (0-based)
+ * @retval -1 Error
+ *
+ * @note Only the first three characters are checked
+ * @note The comparison is case insensitive
+ */
+int mutt_check_month(const char *s)
+{
+ for (int i = 0; i < 12; i++)
+ if (mutt_strncasecmp(s, Months[i], 3) == 0)
+ return i;
+
+ return -1; /* error */
+}
+
+/**
+ * is_day_name - Is the string a valid day name
+ * @param s - String to check
+ * @retval boolean
+ *
+ * @note Only the first three characters are checked
+ * @note The comparison is case insensitive
+ */
+bool is_day_name(const char *s)
+{
+ if ((strlen(s) < 3) || !*(s + 3) || !ISSPACE(*(s + 3)))
+ return false;
+
+ for (int i = 0; i < 7; i++)
+ if (mutt_strncasecmp(s, Weekdays[i], 3) == 0)
+ return true;
+
+ return false;
+}
+
+/**
+ * mutt_parse_date - Parse a date string in RFC822 format
+ * @param[in] s String to parse
+ * @param[out] tz_out Pointer to timezone (optional)
+ * @retval num Unix time in seconds
+ *
+ * Parse a date of the form:
+ * `[ weekday , ] day-of-month month year hour:minute:second [ timezone ]`
+ *
+ * The 'timezone' field is optional; it defaults to +0000 if missing.
+ */
+time_t mutt_parse_date(const char *s, const struct Tz **tz_out)
+{
+ int count = 0;
+ char *t = NULL;
+ int hour, min, sec;
+ struct tm tm;
+ int i;
+ int tz_offset = 0;
+ int zhours = 0;
+ int zminutes = 0;
+ bool zoccident = false;
+ const char *ptz = NULL;
+ char tzstr[SHORT_STRING];
+ char scratch[SHORT_STRING];
+
+ /* Don't modify our argument. Fixed-size buffer is ok here since
+ * the date format imposes a natural limit.
+ */
+
+ strfcpy(scratch, s, sizeof(scratch));
+
+ /* kill the day of the week, if it exists. */
+ if ((t = strchr(scratch, ',')))
+ t++;
+ else
+ t = scratch;
+ t = skip_email_wsp(t);
+
+ memset(&tm, 0, sizeof(tm));
+
+ while ((t = strtok(t, " \t")) != NULL)
+ {
+ switch (count)
+ {
+ case 0: /* day of the month */
+ if ((mutt_atoi(t, &tm.tm_mday) < 0) || (tm.tm_mday < 0))
+ return -1;
+ if (tm.tm_mday > 31)
+ return -1;
+ break;
+
+ case 1: /* month of the year */
+ i = mutt_check_month(t);
+ if (i < 0)
+ return -1;
+ tm.tm_mon = i;
+ break;
+
+ case 2: /* year */
+ if ((mutt_atoi(t, &tm.tm_year) < 0) || (tm.tm_year < 0))
+ return -1;
+ if (tm.tm_year < 50)
+ tm.tm_year += 100;
+ else if (tm.tm_year >= 1900)
+ tm.tm_year -= 1900;
+ break;
+
+ case 3: /* time of day */
+ if (sscanf(t, "%d:%d:%d", &hour, &min, &sec) == 3)
+ ;
+ else if (sscanf(t, "%d:%d", &hour, &min) == 2)
+ sec = 0;
+ else
+ {
+ mutt_debug(1, "parse_date: could not process time format: %s\n", t);
+ return -1;
+ }
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+ break;
+
+ case 4: /* timezone */
+ /* sometimes we see things like (MST) or (-0700) so attempt to
+ * compensate by uncommenting the string if non-RFC822 compliant
+ */
+ ptz = uncomment_timezone(tzstr, sizeof(tzstr), t);
+
+ if (*ptz == '+' || *ptz == '-')
+ {
+ if (ptz[1] && ptz[2] && ptz[3] && ptz[4] &&
+ isdigit((unsigned char) ptz[1]) && isdigit((unsigned char) ptz[2]) &&
+ isdigit((unsigned char) ptz[3]) && isdigit((unsigned char) ptz[4]))
+ {
+ zhours = (ptz[1] - '0') * 10 + (ptz[2] - '0');
+ zminutes = (ptz[3] - '0') * 10 + (ptz[4] - '0');
+
+ if (ptz[0] == '-')
+ zoccident = true;
+ }
+ }
+ else
+ {
+ struct Tz *tz = NULL;
+
+ /* This is safe to do: A pointer to a struct equals a pointer to its first element */
+ tz = bsearch(ptz, TimeZones, sizeof(TimeZones) / sizeof(struct Tz),
+ sizeof(struct Tz),
+ (int (*)(const void *, const void *)) mutt_strcasecmp);
+
+ if (tz)
+ {
+ zhours = tz->zhours;
+ zminutes = tz->zminutes;
+ zoccident = tz->zoccident;
+
+ if (tz_out)
+ *tz_out = tz;
+ }
+
+ /* ad hoc support for the European MET (now officially CET) TZ */
+ if (mutt_strcasecmp(t, "MET") == 0)
+ {
+ if ((t = strtok(NULL, " \t")) != NULL)
+ {
+ if (mutt_strcasecmp(t, "DST") == 0)
+ zhours++;
+ }
+ }
+ }
+ tz_offset = (zhours * 3600) + (zminutes * 60);
+ if (!zoccident)
+ tz_offset = -tz_offset;
+ break;
+ }
+ count++;
+ t = 0;
+ }
+
+ if (count < 4) /* don't check for missing timezone */
+ {
+ mutt_debug(
+ 1, "parse_date(): error parsing date format, using received time\n");
+ return -1;
+ }
+
+ return (mutt_mktime(&tm, 0) + tz_offset);
+}
#ifndef _LIB_DATE_H
#define _LIB_DATE_H
+#include <stdbool.h>
#include <time.h>
+/**
+ * struct Tz - List of recognised Timezones
+ */
+struct Tz
+{
+ char tzname[5]; /**< Name, e.g. UTC */
+ unsigned char zhours; /**< Hours away from UTC */
+ unsigned char zminutes; /**< Minutes away from UTC */
+ bool zoccident; /**< True if west of UTC, False if East */
+};
+
extern const char *const Weekdays[];
extern const char *const Months[];
+extern const struct Tz TimeZones[];
time_t mutt_local_tz(time_t t);
time_t mutt_mktime(struct tm *t, int local);
void mutt_normalize_time(struct tm *tm);
char *mutt_make_date(char *buf, size_t buflen);
+time_t mutt_parse_date(const char *s, const struct Tz **tz_out);
+bool is_day_name(const char *s);
+int mutt_check_month(const char *s);
#endif /* _LIB_DATE_H */
#ifndef _LIB_DEBUG_H
#define _LIB_DEBUG_H
-#include <limits.h>
-
#ifdef DEBUG
void mutt_debug(int level, const char *fmt, ...);
#else
* | mutt_exit() | Leave NeoMutt NOW
*/
+#include "config.h"
#include <unistd.h>
/**
return -1;
}
- if ((stat(oldpath, &osb) == -1) || (stat(newpath, &nsb) == -1) || !compare_stat(&osb, &nsb))
+ if ((stat(oldpath, &osb) == -1) || (stat(newpath, &nsb) == -1) ||
+ !compare_stat(&osb, &nsb))
{
unlink(newpath);
return -1;
mutt_unlock_file(path, fd);
close(fd);
}
-
* | safe_realloc() | Resize a block of memory on the heap
*/
-#include <stdio.h>
+#include "config.h"
#include <stdlib.h>
#include <unistd.h>
#include "memory.h"
#ifndef _LIB_MEMORY_H
#define _LIB_MEMORY_H
-#include <stdio.h>
+#include <stddef.h>
#ifdef ENABLE_NLS
#include <libintl.h>
* | Function | Description
* | :------------------------ | :---------------------------------------------------------
* | is_email_wsp() | Is this a whitespace character (for an email header)
+ * | lwslen() | Measure the linear-white-space at the beginning of a string
+ * | lwsrlen() | Measure the linear-white-space at the end of a string
* | mutt_atoi() | Convert ASCII string to an integer
* | mutt_atos() | Convert ASCII string to a short
* | mutt_remove_trailing_ws() | Trim trailing whitespace from a string
* | mutt_str_replace() | Replace one string with another
* | mutt_substrcpy() | Copy a sub-string into a buffer
* | mutt_substrdup() | Duplicate a sub-string
+ * | rfc822_dequote_comment() | Un-escape characters in an email address comment
* | safe_strcat() | Concatenate two strings
* | safe_strdup() | Copy a string, safely
* | safe_strncat() | Concatenate two strings
* | skip_email_wsp() | Skip over whitespace as defined by RFC5322
* | strfcpy() | Copy a string into a buffer (guaranteeing NUL-termination)
+ * | strnfcpy() | Copy a limited string into a buffer (guaranteeing NUL-termination)
*/
#include "config.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
-#include "string2.h"
#include "memory.h"
+#include "string2.h"
/**
* mutt_atol - Convert ASCII string to a long
{
return c && (strchr(EMAIL_WSP, c) != NULL);
}
+
+/**
+ * strnfcpy - Copy a limited string into a buffer (guaranteeing NUL-termination)
+ * @param dest Buffer for the result
+ * @param src String to copy
+ * @param size Maximum number of characters to copy
+ * @param dlen Length of buffer
+ * @retval ptr Destination buffer
+ */
+char *strnfcpy(char *dest, char *src, size_t size, size_t dlen)
+{
+ if (dlen > size)
+ dlen = size - 1;
+ return strfcpy(dest, src, dlen);
+}
+
+/**
+ * lwslen - Measure the linear-white-space at the beginning of a string
+ * @param s String to check
+ * @param n Maximum number of characters to check
+ * @retval num Count of whitespace characters
+ *
+ * Count the number of whitespace characters at the beginning of a string.
+ * They can be `<space>`, `<tab>`, `<cr>` or `<lf>`.
+ */
+size_t lwslen(const char *s, size_t n)
+{
+ const char *p = s;
+ size_t len = n;
+
+ if (n <= 0)
+ return 0;
+
+ for (; p < (s + n); p++)
+ {
+ if (!strchr(" \t\r\n", *p))
+ {
+ len = p - s;
+ break;
+ }
+ }
+
+ if (strchr("\r\n", *(p - 1))) /* LWS doesn't end with CRLF */
+ len = 0;
+ return len;
+}
+
+/**
+ * lwsrlen - Measure the linear-white-space at the end of a string
+ * @param s String to check
+ * @param n Maximum number of characters to check
+ * @retval num Count of whitespace characters
+ *
+ * Count the number of whitespace characters at the end of a string.
+ * They can be `<space>`, `<tab>`, `<cr>` or `<lf>`.
+ */
+size_t lwsrlen(const char *s, size_t n)
+{
+ const char *p = s + n - 1;
+ size_t len = n;
+
+ if (n <= 0)
+ return 0;
+
+ if (strchr("\r\n", *p)) /* LWS doesn't end with CRLF */
+ return 0;
+
+ for (; p >= s; p--)
+ {
+ if (!strchr(" \t\r\n", *p))
+ {
+ len = s + n - 1 - p;
+ break;
+ }
+ }
+
+ return len;
+}
+
+/**
+ * rfc822_dequote_comment - Un-escape characters in an email address comment
+ * @param s String to the un-escaped
+ *
+ * @note The string is changed in-place
+ */
+void rfc822_dequote_comment(char *s)
+{
+ char *w = s;
+
+ for (; *s; s++)
+ {
+ if (*s == '\\')
+ {
+ if (!*++s)
+ break; /* error? */
+ *w++ = *s;
+ }
+ else if (*s != '\"')
+ {
+ if (w != s)
+ *w = *s;
+ w++;
+ }
+ }
+ *w = 0;
+}
+
+/**
+ * next_word - Find the next word in a string
+ * @param s String to examine
+ * @retval ptr Next word
+ *
+ * If the s is pointing to a word (non-space) is is skipped over.
+ * Then, any whitespace is skipped over.
+ *
+ * @note What is/isn't a word is determined by isspace()
+ */
+const char *next_word(const char *s)
+{
+ while (*s && !ISSPACE(*s))
+ s++;
+ SKIPWS(s);
+ return s;
+}
while (*(c) && isspace((unsigned char) *(c))) \
c++;
+#define terminate_string(a, b, c) \
+ do \
+ { \
+ if ((b) < (c)) \
+ a[(b)] = 0; \
+ else \
+ a[(c)] = 0; \
+ } while (0)
+
+#define terminate_buffer(a, b) terminate_string(a, b, sizeof(a) - 1)
+
int is_email_wsp(char c);
-int mutt_atos(const char *str, short *dst);
+size_t lwslen(const char *s, size_t n);
+size_t lwsrlen(const char *s, size_t n);
int mutt_atoi(const char *str, int *dst);
+int mutt_atos(const char *str, short *dst);
void mutt_remove_trailing_ws(char *s);
char * mutt_skip_whitespace(char *p);
void mutt_str_adjust(char **p);
void mutt_str_replace(char **p, const char *s);
char * mutt_substrcpy(char *dest, const char *begin, const char *end, size_t destlen);
char * mutt_substrdup(const char *begin, const char *end);
+const char *next_word(const char *s);
+void rfc822_dequote_comment(char *s);
char * safe_strcat(char *d, size_t l, const char *s);
char * safe_strdup(const char *s);
char * safe_strncat(char *d, size_t l, const char *s, size_t sl);
char * skip_email_wsp(const char *s);
char * strfcpy(char *dest, const char *src, size_t dlen);
+char * strnfcpy(char *dest, char *src, size_t size, size_t dlen);
#endif /* _LIB_STRING_H */
return head;
}
-static const char *uncomment_timezone(char *buf, size_t buflen, const char *tz)
-{
- char *p = NULL;
- size_t len;
-
- if (*tz != '(')
- return tz; /* no need to do anything */
- tz = skip_email_wsp(tz + 1);
- if ((p = strpbrk(tz, " )")) == NULL)
- return tz;
- len = p - tz;
- if (len > buflen - 1)
- len = buflen - 1;
- memcpy(buf, tz, len);
- buf[len] = 0;
- return buf;
-}
-
-/**
- * struct Tz - Lookup table of Time Zones
- */
-static const struct Tz
-{
- char tzname[5];
- unsigned char zhours;
- unsigned char zminutes;
- bool zoccident; /**< west of UTC? */
-} TimeZones[] = {
- { "aat", 1, 0, true }, /* Atlantic Africa Time */
- { "adt", 4, 0, false }, /* Arabia DST */
- { "ast", 3, 0, false }, /* Arabia */
- /* { "ast", 4, 0, true }, */ /* Atlantic */
- { "bst", 1, 0, false }, /* British DST */
- { "cat", 1, 0, false }, /* Central Africa */
- { "cdt", 5, 0, true },
- { "cest", 2, 0, false }, /* Central Europe DST */
- { "cet", 1, 0, false }, /* Central Europe */
- { "cst", 6, 0, true },
- /* { "cst", 8, 0, false }, */ /* China */
- /* { "cst", 9, 30, false }, */ /* Australian Central Standard Time */
- { "eat", 3, 0, false }, /* East Africa */
- { "edt", 4, 0, true },
- { "eest", 3, 0, false }, /* Eastern Europe DST */
- { "eet", 2, 0, false }, /* Eastern Europe */
- { "egst", 0, 0, false }, /* Eastern Greenland DST */
- { "egt", 1, 0, true }, /* Eastern Greenland */
- { "est", 5, 0, true },
- { "gmt", 0, 0, false },
- { "gst", 4, 0, false }, /* Presian Gulf */
- { "hkt", 8, 0, false }, /* Hong Kong */
- { "ict", 7, 0, false }, /* Indochina */
- { "idt", 3, 0, false }, /* Israel DST */
- { "ist", 2, 0, false }, /* Israel */
- /* { "ist", 5, 30, false }, */ /* India */
- { "jst", 9, 0, false }, /* Japan */
- { "kst", 9, 0, false }, /* Korea */
- { "mdt", 6, 0, true },
- { "met", 1, 0, false }, /* this is now officially CET */
- { "msd", 4, 0, false }, /* Moscow DST */
- { "msk", 3, 0, false }, /* Moscow */
- { "mst", 7, 0, true },
- { "nzdt", 13, 0, false }, /* New Zealand DST */
- { "nzst", 12, 0, false }, /* New Zealand */
- { "pdt", 7, 0, true },
- { "pst", 8, 0, true },
- { "sat", 2, 0, false }, /* South Africa */
- { "smt", 4, 0, false }, /* Seychelles */
- { "sst", 11, 0, true }, /* Samoa */
- /* { "sst", 8, 0, false }, */ /* Singapore */
- { "utc", 0, 0, false },
- { "wat", 0, 0, false }, /* West Africa */
- { "west", 1, 0, false }, /* Western Europe DST */
- { "wet", 0, 0, false }, /* Western Europe */
- { "wgst", 2, 0, true }, /* Western Greenland DST */
- { "wgt", 3, 0, true }, /* Western Greenland */
- { "wst", 8, 0, false }, /* Western Australia */
-};
-
-/**
- * mutt_parse_date - parses a date string in RFC822 format
- *
- * Date: [ weekday , ] day-of-month month year hour:minute:second timezone
- *
- * This routine assumes that `h' has been initialized to 0. the `timezone'
- * field is optional, defaulting to +0000 if missing.
- */
-time_t mutt_parse_date(const char *s, struct Header *h)
-{
- int count = 0;
- char *t = NULL;
- int hour, min, sec;
- struct tm tm;
- int i;
- int tz_offset = 0;
- int zhours = 0;
- int zminutes = 0;
- bool zoccident = false;
- const char *ptz = NULL;
- char tzstr[SHORT_STRING];
- char scratch[SHORT_STRING];
-
- /* Don't modify our argument. Fixed-size buffer is ok here since
- * the date format imposes a natural limit.
- */
-
- strfcpy(scratch, s, sizeof(scratch));
-
- /* kill the day of the week, if it exists. */
- if ((t = strchr(scratch, ',')))
- t++;
- else
- t = scratch;
- t = skip_email_wsp(t);
-
- memset(&tm, 0, sizeof(tm));
-
- while ((t = strtok(t, " \t")) != NULL)
- {
- switch (count)
- {
- case 0: /* day of the month */
- if (mutt_atoi(t, &tm.tm_mday) < 0 || tm.tm_mday < 0)
- return -1;
- if (tm.tm_mday > 31)
- return -1;
- break;
-
- case 1: /* month of the year */
- if ((i = mutt_check_month(t)) < 0)
- return -1;
- tm.tm_mon = i;
- break;
-
- case 2: /* year */
- if (mutt_atoi(t, &tm.tm_year) < 0 || tm.tm_year < 0)
- return -1;
- if (tm.tm_year < 50)
- tm.tm_year += 100;
- else if (tm.tm_year >= 1900)
- tm.tm_year -= 1900;
- break;
-
- case 3: /* time of day */
- if (sscanf(t, "%d:%d:%d", &hour, &min, &sec) == 3)
- ;
- else if (sscanf(t, "%d:%d", &hour, &min) == 2)
- sec = 0;
- else
- {
- mutt_debug(1, "parse_date: could not process time format: %s\n", t);
- return -1;
- }
- tm.tm_hour = hour;
- tm.tm_min = min;
- tm.tm_sec = sec;
- break;
-
- case 4: /* timezone */
- /* sometimes we see things like (MST) or (-0700) so attempt to
- * compensate by uncommenting the string if non-RFC822 compliant
- */
- ptz = uncomment_timezone(tzstr, sizeof(tzstr), t);
-
- if (*ptz == '+' || *ptz == '-')
- {
- if (ptz[1] && ptz[2] && ptz[3] && ptz[4] &&
- isdigit((unsigned char) ptz[1]) && isdigit((unsigned char) ptz[2]) &&
- isdigit((unsigned char) ptz[3]) && isdigit((unsigned char) ptz[4]))
- {
- zhours = (ptz[1] - '0') * 10 + (ptz[2] - '0');
- zminutes = (ptz[3] - '0') * 10 + (ptz[4] - '0');
-
- if (ptz[0] == '-')
- zoccident = true;
- }
- }
- else
- {
- struct Tz *tz = NULL;
-
- tz = bsearch(ptz, TimeZones, sizeof(TimeZones) / sizeof(struct Tz),
- sizeof(struct Tz), (int (*)(const void *, const void *)) mutt_strcasecmp
- /* This is safe to do: A pointer to a struct equals
- * a pointer to its first element */);
-
- if (tz)
- {
- zhours = tz->zhours;
- zminutes = tz->zminutes;
- zoccident = tz->zoccident;
- }
-
- /* ad hoc support for the European MET (now officially CET) TZ */
- if (mutt_strcasecmp(t, "MET") == 0)
- {
- if ((t = strtok(NULL, " \t")) != NULL)
- {
- if (mutt_strcasecmp(t, "DST") == 0)
- zhours++;
- }
- }
- }
- tz_offset = zhours * 3600 + zminutes * 60;
- if (!zoccident)
- tz_offset = -tz_offset;
- break;
- }
- count++;
- t = 0;
- }
-
- if (count < 4) /* don't check for missing timezone */
- {
- mutt_debug(
- 1, "parse_date(): error parsing date format, using received time\n");
- return -1;
- }
-
- if (h)
- {
- h->zhours = zhours;
- h->zminutes = zminutes;
- h->zoccident = zoccident;
- }
-
- return (mutt_mktime(&tm, 0) + tz_offset);
-}
-
/**
* mutt_extract_message_id - Find a message-id
*
{
mutt_str_replace(&e->date, p);
if (hdr)
- hdr->date_sent = mutt_parse_date(p, hdr);
+ {
+ const struct Tz *tz = NULL;
+ hdr->date_sent = mutt_parse_date(p, &tz);
+ if (tz)
+ {
+ hdr->zhours = tz->zhours;
+ hdr->zminutes = tz->zminutes;
+ hdr->zoccident = tz->zoccident;
+ }
+ }
matched = 1;
}
break;
struct stat;
struct passwd;
-#define MoreArgs(p) (*p->dptr && *p->dptr != ';' && *p->dptr != '#')
-
#define mutt_make_string(A, B, C, D, E) _mutt_make_string(A, B, C, D, E, 0)
void _mutt_make_string(char *dest, size_t destlen, const char *s, struct Context *ctx,
struct Header *hdr, enum FormatFlag flags);
char *mutt_read_rfc822_line(FILE *f, char *line, size_t *linelen);
struct Envelope *mutt_read_rfc822_header(FILE *f, struct Header *hdr, short user_hdrs, short weed);
-time_t mutt_parse_date(const char *s, struct Header *h);
int is_from(const char *s, char *path, size_t pathlen, time_t *tp);
const char *mutt_attach_fmt(char *dest, size_t destlen, size_t col, int cols,
return found;
}
-static void strnfcpy(char *d, char *s, size_t siz, size_t len)
-{
- if (len > siz)
- len = siz - 1;
- strfcpy(d, s, len);
-}
-
/**
* rfc1524_expand_filename - Expand a new filename from a template or existing filename
* @param nametemplate Template
return 0;
}
-/**
- * lwslen - return length of linear-white-space
- */
-static size_t lwslen(const char *s, size_t n)
-{
- const char *p = s;
- size_t len = n;
-
- if (n <= 0)
- return 0;
-
- for (; p < s + n; p++)
- if (!strchr(" \t\r\n", *p))
- {
- len = (size_t)(p - s);
- break;
- }
- if (strchr("\r\n", *(p - 1))) /* LWS doesn't end with CRLF */
- len = (size_t) 0;
- return len;
-}
-
-/**
- * lwsrlen - return length of linear-white-space : reverse
- */
-static size_t lwsrlen(const char *s, size_t n)
-{
- const char *p = s + n - 1;
- size_t len = n;
-
- if (n <= 0)
- return 0;
-
- if (strchr("\r\n", *p)) /* LWS doesn't end with CRLF */
- return (size_t) 0;
-
- for (; p >= s; p--)
- if (!strchr(" \t\r\n", *p))
- {
- len = (size_t)(s + n - 1 - p);
- break;
- }
- return len;
-}
-
/**
* rfc2047_decode - Decode any RFC2047-encoded header fields
*
#include "lib/lib.h"
#include "mutt_idna.h"
-#define terminate_string(a, b, c) \
- do \
- { \
- if ((b) < (c)) \
- a[(b)] = 0; \
- else \
- a[(c)] = 0; \
- } while (0)
-
-#define terminate_buffer(a, b) terminate_string(a, b, sizeof(a) - 1)
-
const char RFC822Specials[] = "@.,:;<>[]\\\"()";
#define is_special(x) strchr(RFC822Specials, x)
"bad route in <>", "bad address in <>", "bad address spec",
};
-void rfc822_dequote_comment(char *s)
-{
- char *w = s;
-
- for (; *s; s++)
- {
- if (*s == '\\')
- {
- if (!*++s)
- break; /* error? */
- *w++ = *s;
- }
- else if (*s != '\"')
- {
- if (w != s)
- *w = *s;
- w++;
- }
- }
- *w = 0;
-}
-
static void free_address(struct Address *a)
{
FREE(&a->personal);
*/
#include "config.h"
+#include <limits.h>
#include <stdarg.h>
#include "state.h"
#include "globals.h"