Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id 1C37D431FC0 for ; Mon, 25 Jan 2010 02:50:47 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: -1.472 X-Spam-Level: X-Spam-Status: No, score=-1.472 tagged_above=-999 required=5 tests=[AWL=1.127, BAYES_00=-2.599] autolearn=ham Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3bUteJuX0AnQ for ; Mon, 25 Jan 2010 02:50:46 -0800 (PST) Received: from homiemail-a25.g.dreamhost.com (caiajhbdccac.dreamhost.com [208.97.132.202]) by olra.theworths.org (Postfix) with ESMTP id 04AD5431FBC for ; Mon, 25 Jan 2010 02:50:45 -0800 (PST) Received: from localhost.localdomain (unknown [84.55.198.58]) by homiemail-a25.g.dreamhost.com (Postfix) with ESMTPA id 83A9667806B; Mon, 25 Jan 2010 02:50:38 -0800 (PST) From: Sebastian Spaeth To: notmuch@notmuchmail.org Date: Mon, 25 Jan 2010 11:50:34 +0100 Message-Id: <1264416634-18414-1-git-send-email-Sebastian@SSpaeth.de> X-Mailer: git-send-email 1.6.3.3 In-Reply-To: <1264342433-15663-1-git-send-email-Sebastian@SSpaeth.de> References: <1264342433-15663-1-git-send-email-Sebastian@SSpaeth.de> Subject: [notmuch] [PATCH] Make the date parser nicer. This is v3 and considered to be final (but the documentation). X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 25 Jan 2010 10:50:47 -0000 Currently we have to enter mail dates as timestamps. This approach does 2 things: 1) it requires the prefix 'date:' 2) it allows dates to be specified in a flexible way. So a notmuch show date:2005..2006-05-12 will find all mails from 2005-01-01 until 2006-05-12. Possible time formats: YYYY-MM-DD, YYYY-MM (from/through that month) , YYYY (from/through that year), MM-DD (month-day in current year), DD (day in current month). Signed-off-by: Sebastian Spaeth --- lib/database.cc | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 79 insertions(+), 1 deletions(-) diff --git a/lib/database.cc b/lib/database.cc index 5b12320..da2fda8 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -494,6 +494,84 @@ _notmuch_database_ensure_writable (notmuch_database_t *notmuch) return NOTMUCH_STATUS_SUCCESS; } +struct MaildateValueRangeProcessor : public Xapian::ValueRangeProcessor { + MaildateValueRangeProcessor() {} + + time_t + parsedate(std::string &str, bool early) { + /* Parse the date to a 'time_t', return NULL on error */ + /* possible time formats: YYYY-MM-DD, YYYY-MM, YYYY, */ + /* MM-DD (current month), DD (day in current month). */ + /* Uses start of time unit when 'early', end otherwise, e.g. */ + /* 2001:=2001-01-01:00:00:00 when 'early' or 2001-12-31:23:59:59 */ + struct tm *timeinfo; + time_t timet; + int year = 0, month = 0, day = 0; + + if (str.size() == 2) { + /* We got just current day in month, parse & remove it */ + day = atoi(str.c_str()); + str.erase(0,2); + } + + if (str.size() == 4 or str.size() > 5) { + /* expect a year, parse & remove it */ + year = atoi(str.c_str()); + str.erase(0,5); + } + + /* parse & remove month if there is sth left in the string */ + month = atoi(str.c_str()); + str.erase(0,3); + + /* Parse day if we have one left */ + if (str.size()) + day = atoi(str.c_str()); + + if (year == 0 && month == 0 && day == 0) + // no expected time format + return -1 ; + + timet = time(NULL); /* init timeinfo with current time */ + timeinfo = gmtime(&timet); + /* add timeunit if !early (1 second too much, which we deduct later */ + if (!early) { + if (year && !month) ++year; /* only year given */ + if (year && month && !day) ++month; /* year & month given */ + } + if (year) timeinfo -> tm_year = year - 1900; + if (month) timeinfo -> tm_mon = month - 1; + if (day) timeinfo -> tm_mday = (early ? day : ++day); + else timeinfo -> tm_mday = 1; + + timeinfo -> tm_hour = 0; + timeinfo -> tm_min = 0; + timeinfo -> tm_sec = (early ? 0 : -1); /* -1 sec if !early */ + timet = mktime(timeinfo); + + return timet; + } + + Xapian::valueno operator()(std::string &begin, std::string &end) { + time_t begintime, endtime; + + if (begin.substr(0, 5) != "date:") + return Xapian::BAD_VALUENO; + begin.erase(0, 5); + + begintime = parsedate(begin, true); + endtime = parsedate(end, false); + if ((begintime == -1) || (endtime == -1)) + // parsedate failed, no valid time format + return Xapian::BAD_VALUENO; + + begin.assign(Xapian::sortable_serialise(begintime)); + end.assign(Xapian::sortable_serialise(endtime)); + + return NOTMUCH_VALUE_TIMESTAMP; + } +}; + notmuch_database_t * notmuch_database_open (const char *path, notmuch_database_mode_t mode) @@ -570,8 +648,7 @@ notmuch_database_open (const char *path, notmuch->query_parser = new Xapian::QueryParser; notmuch->term_gen = new Xapian::TermGenerator; notmuch->term_gen->set_stemmer (Xapian::Stem ("english")); - notmuch->value_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP); + notmuch->value_range_processor = new MaildateValueRangeProcessor(); notmuch->query_parser->set_default_op (Xapian::Query::OP_AND); notmuch->query_parser->set_database (*notmuch->xapian_db); -- 1.6.3.3