From 6c62a066c8296109888e818fea84a2671346d8ac Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Sat, 16 Jul 2011 12:50:17 +0300 Subject: [PATCH] * make time & size checking a bit stricter, report errors to user --- src/mu-query.cc | 42 ++++++++++++++------------------------- src/mu-store.cc | 2 +- src/mu-str.c | 40 ++++++++++++++++++------------------- src/mu-str.h | 13 ++++++------ src/tests/test-mu-query.c | 6 +++--- 5 files changed, 45 insertions(+), 58 deletions(-) diff --git a/src/mu-query.cc b/src/mu-query.cc index 88934a3f..5b72e238 100644 --- a/src/mu-query.cc +++ b/src/mu-query.cc @@ -45,32 +45,18 @@ public: if (!clear_prefix (begin)) return Xapian::BAD_VALUENO; - - // now and begin should only appear at the end, so - // correct them... - if (begin == "today" || begin == "now") - std::swap (begin, end); - substitute_date (begin); - substitute_date (end); + substitute_date (begin, true); + substitute_date (end, false); normalize_date (begin); normalize_date (end); - - // note, we'll have to compare the *completed* - // versions of begin and end to if the were specified - // in the opposite order; however, if that is true, we - // have to complete begin, end 'for real', as the - // begin date is completed to the begin of the - // interval, and the to the end of the interval - // ie. begin: 2008 -> 200801010000 end: 2008 -> - // 200812312359 - if (complete_date12(begin,true) > - complete_date12(end, false)) - std::swap (begin, end); - begin = complete_date12(begin,true); + begin = complete_date12(begin, true); end = complete_date12(end, false); + + if (begin > end) + throw Xapian::QueryParserError ("end time is before begin"); return (Xapian::valueno)MU_MSG_PSEUDO_FIELD_ID_DATESTR; } @@ -93,13 +79,15 @@ private: } else return false; } + - void substitute_date (std::string& date) { + void substitute_date (std::string& date, bool is_begin) { char datebuf[13]; time_t now = time(NULL); if (date == "today") { - strftime(datebuf, sizeof(datebuf), "%Y%m%d0000", + strftime(datebuf, sizeof(datebuf), + is_begin ? "%Y%m%d0000" : "%Y%m%d2359", localtime(&now)); date = datebuf; } else if (date == "now") { @@ -189,9 +177,9 @@ private: bool substitute_size (std::string& size) { gchar str[16]; - guint64 num = mu_str_size_parse_kmg (size.c_str()); - if (num == G_MAXUINT64) - return false; + gint64 num = mu_str_size_parse_bkm(size.c_str()); + if (num < 0) + throw Xapian::QueryParserError ("invalid size"); snprintf (str, sizeof(str), "%" G_GUINT64_FORMAT, num); size = str; return true; @@ -243,8 +231,8 @@ get_query (MuQuery *mqx, const char* searchexpr, GError **err) } catch (...) { /* some error occured */ - g_set_error (err, 0, MU_ERROR_QUERY, "parse error in query '%s'", - searchexpr); + g_set_error (err, 0, MU_ERROR_QUERY, + "parse error in query"); g_free (preprocessed); throw; } diff --git a/src/mu-store.cc b/src/mu-store.cc index 0e98647a..d8d60ab0 100644 --- a/src/mu-store.cc +++ b/src/mu-store.cc @@ -314,7 +314,7 @@ static void add_terms_values_date (Xapian::Document& doc, MuMsg *msg, MuMsgFieldId mfid) { - char datebuf[13]; /* YYYYMMDDHHMMSS */ + char datebuf[13]; /* YYYYMMDDHHMM\0 */ static const std::string pfx (1, mu_msg_field_xapian_prefix(mfid)); gint64 num = mu_msg_get_field_numeric (msg, mfid); diff --git a/src/mu-str.c b/src/mu-str.c index dde22086..8a16072b 100644 --- a/src/mu-str.c +++ b/src/mu-str.c @@ -345,30 +345,28 @@ mu_str_date_parse_hdwmy (const char *nptr) return delta <= now ? now - delta : never; } -guint64 -mu_str_size_parse_kmg (const char* str) +gint64 +mu_str_size_parse_bkm (const char* str) { gint64 num; - char *end; - - g_return_val_if_fail (str, G_MAXUINT64); - - num = strtol (str, &end, 10); - if (num < 0) - return G_MAXUINT64; - - if (!end || end[1] != '\0') - return G_MAXUINT64; - - switch (tolower(end[0])) { - case 'b': return num; /* bytes */ - case 'k': return num * 1000; /* kilobyte */ - case 'm': return num * 1000 * 1000; /* megabyte */ - /* case 'g': return num * 1000 * 1000 * 1000; /\* gigabyte *\/ */ - default: - return G_MAXUINT64; - } + const char *cur; + g_return_val_if_fail (str, -1); + + if (!isdigit(str[0])) + return -1; + + num = atoi(str); + for (++str; isdigit(*str); ++str); + + switch (tolower(*str)) { + case '\0': + case 'b' : return num; /* bytes */ + case 'k': return num * 1000; /* kilobyte */ + case 'm': return num * 1000 * 1000; /* megabyte */ + default: + return -1; + } } diff --git a/src/mu-str.h b/src/mu-str.h index 98bc1828..0ecd1065 100644 --- a/src/mu-str.h +++ b/src/mu-str.h @@ -215,10 +215,11 @@ time_t mu_str_date_parse_hdwmy (const char* str); /** * parse a byte size; a size is a number, with optionally a - * unit. Units recognized are K (1000) and M (1000*1000). Only the - * first letter is checked and the function is not case-sensitive, so - * 1000Kb, 3M will work equally well. Note, for kB, MB etc., we then - * follow the SI standards, not 2^10 etc. + * unit. Units recognized are b/B (bytes) k/K (1000) and m/M + * (1000*1000). Only the first letter is checked and the function is + * not case-sensitive, so 1000Kb, 3M will work equally well. Note, + * for kB, MB etc., we then follow the SI standards, not 2^10 etc. The + * 'b' may be omitted. * * practical sizes for email messages are in terms of Mb; even in * extreme cases it should be under 100 Mb. Function return @@ -226,9 +227,9 @@ time_t mu_str_date_parse_hdwmy (const char* str); * * @param str a string with a size, such a "100", "100Kb", "1Mb" * - * @return the corresponding time_t value (as a guint64) + * @return the corresponding size in bytes, or -1 in case of error */ -guint64 mu_str_size_parse_kmg (const char* str); +gint64 mu_str_size_parse_bkm (const char* str); /** * create a full path from a path + a filename. function is _not_ diff --git a/src/tests/test-mu-query.c b/src/tests/test-mu-query.c index 9518d642..f071178a 100644 --- a/src/tests/test-mu-query.c +++ b/src/tests/test-mu-query.c @@ -347,13 +347,13 @@ test_mu_query_dates (void) QResults queries[] = { { "date:20080731..20080804", 5}, - { "date:20080804..20080731", 5}, + /* { "date:20080804..20080731", 5}, */ { "date:2008-07/31..2008@08:04", 5}, { "date:2008-0731..20080804 s:gcc", 1}, { "date:2008-08-11-08-03..now", 1}, { "date:2008-08-11-08-03..today", 1}, - { "date:now..2008-08-11-08-03", 1}, - { "date:today..2008-08-11-08-03", 1}, + /* { "date:now..2008-08-11-08-03", 1}, */ + /* { "date:today..2008-08-11-08-03", 1}, */ { "date:2008-08-11-08-05..now", 0}, };