]> granicus.if.org Git - neomutt/commitdiff
lib: move some date/string functions
authorRichard Russon <rich@flatcap.org>
Wed, 9 Aug 2017 16:17:51 +0000 (17:17 +0100)
committerRichard Russon <rich@flatcap.org>
Thu, 10 Aug 2017 12:53:36 +0000 (13:53 +0100)
19 files changed:
from.c
lib/base64.c
lib/buffer.c
lib/buffer.h
lib/date.c
lib/date.h
lib/debug.h
lib/exit.c
lib/file.c
lib/memory.c
lib/memory.h
lib/string.c
lib/string2.h
parse.c
protos.h
rfc1524.c
rfc2047.c
rfc822.c
state.c

diff --git a/from.c b/from.c
index 2e04e2a200ffefbbf0086aae6a4323597ab201a4..14bbd476725afe3419ac08cd45aff93890c634a7 100644 (file)
--- a/from.c
+++ b/from.c
 #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:
  *
index 8fccd7b555b5555e36c7f29359d6c7de49abf115..462fe0d3bb3f874abd7cf3ec2e7d0e8ea5a00cf6 100644 (file)
  * @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
@@ -50,10 +54,14 @@ static const char B64Chars[64] = {
 };
 
 // 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,
index fdc1a22c67f1afebc933dc2f2df468e6a63c603c..7e3dc54a969234c068ef7a3aac455c014d5c6f9d 100644 (file)
@@ -3,6 +3,7 @@
  * 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
index d4e80809c0376c825c19672cee8e26fd64678e15..57bfb02efa05dd22870949672da9425d07f96196 100644 (file)
@@ -3,6 +3,9 @@
  * 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
@@ -34,6 +37,8 @@ struct Buffer
   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);
index 43926d60a707254356afc08a10d0b2b197fcc2c2..651f762018b0ed36df22f45f22b645d98ab38332 100644 (file)
  *
  * 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
@@ -97,6 +175,37 @@ static int is_leap_year_feb(struct tm *tm)
   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
@@ -274,3 +383,190 @@ char *mutt_make_date(char *buf, size_t buflen)
   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);
+}
index 8f04a3421f8295009524a47a4e35bcab4032223f..ad0eb9c38c4b1085c0357453974c2852850df917 100644 (file)
 #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 */
index 24394c075db151314154ec4c7d4b0b01f6a89266..0f14f2db22ae5163e3611046f6ac8b9f663a2d18 100644 (file)
@@ -23,8 +23,6 @@
 #ifndef _LIB_DEBUG_H
 #define _LIB_DEBUG_H
 
-#include <limits.h>
-
 #ifdef DEBUG
 void mutt_debug(int level, const char *fmt, ...);
 #else
index 62dc44676def73fdd5ba2788c649de3557d0c2af..32690960ecc3382b99678b3f11b65e55373572af 100644 (file)
@@ -30,6 +30,7 @@
  * | mutt_exit() | Leave NeoMutt NOW
  */
 
+#include "config.h"
 #include <unistd.h>
 
 /**
index dcef552c310820c494fc050a48b5c6974c3cbaa2..edb3060b622044ea26be5cd42c59492753398c30 100644 (file)
@@ -344,7 +344,8 @@ int safe_symlink(const char *oldpath, const char *newpath)
       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;
@@ -1110,4 +1111,3 @@ void mutt_unlink_empty(const char *path)
   mutt_unlock_file(path, fd);
   close(fd);
 }
-
index 49385129f461a794d881e046d2dadcaec4dd9849..25fb467a291b0d54b6e4b3a52ca3dd7e48499ffd 100644 (file)
@@ -36,7 +36,7 @@
  * | 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"
index 9299b4a60ecedf1a863c2c8f63579276df4c805a..2c4e4b7cf1a8c17eeb71b95b299b695dd4c79636 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef _LIB_MEMORY_H
 #define _LIB_MEMORY_H
 
-#include <stdio.h>
+#include <stddef.h>
 
 #ifdef ENABLE_NLS
 #include <libintl.h>
index 59956954e86efd71924d14de5681859a269ce366..d52bcbdd5fad559f2200ac5b7616315d0c7a2b32 100644 (file)
@@ -28,6 +28,8 @@
  * | 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"
@@ -58,8 +62,8 @@
 #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
@@ -517,3 +521,127 @@ int is_email_wsp(char c)
 {
   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;
+}
index 6c027b61d65ce5322fcc80ce56461eb4030e9eac..ffcf18af4e0f1b8ba011b276c71271f659ae5556 100644 (file)
   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);
@@ -63,10 +76,13 @@ int         mutt_strncmp(const char *a, const char *b, size_t l);
 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 */
diff --git a/parse.c b/parse.c
index 8985fce031496ea82b4f586beae92ea8aed26834..0de675d2574c64b0bb67784bc18bf92539c17dcd 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -666,234 +666,6 @@ struct Body *mutt_parse_multipart(FILE *fp, const char *boundary, LOFF_T end_off
   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
  *
@@ -1062,7 +834,16 @@ int mutt_parse_rfc822_line(struct Envelope *e, struct Header *hdr, char *line,
       {
         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;
index 05aaedc0fad07a0788162fdfb98afb958a71ce07..c137b668821f86d5479aed54a460ca821cbfd4ce 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -53,8 +53,6 @@ struct ListHead;
 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);
@@ -122,7 +120,6 @@ struct Content *mutt_get_content_info(const char *fname, struct Body *b);
 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,
index 778467cd2935289084ea68cc8c079249094e41e5..242bd01027e2eeee9bfba4361dfb280a83c034a8 100644 (file)
--- a/rfc1524.c
+++ b/rfc1524.c
@@ -443,13 +443,6 @@ int rfc1524_mailcap_lookup(struct Body *a, char *type,
   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
index c662f9be12d95241e89a5e0e8f5b5379fe483da0..a5a8ddbf269278aca7462726b07c1e8236ed303c 100644 (file)
--- a/rfc2047.c
+++ b/rfc2047.c
@@ -778,51 +778,6 @@ static const char *find_encoded_word(const char *s, const char **x)
   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
  *
index 0b767e1ade3998cd10956c3133eedb56462c109e..fc8835d1b58a9c9621bf9a055a2d2553d1c9b56d 100644 (file)
--- a/rfc822.c
+++ b/rfc822.c
 #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)
 
@@ -49,28 +38,6 @@ const char *const RFC822Errors[] = {
   "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);
diff --git a/state.c b/state.c
index 2e27be631e279b1521c4973d3cfb1f66f668f442..49a575165931661faa552952f3c745a6fd2839cb 100644 (file)
--- a/state.c
+++ b/state.c
@@ -21,6 +21,7 @@
  */
 
 #include "config.h"
+#include <limits.h>
 #include <stdarg.h>
 #include "state.h"
 #include "globals.h"