diff options
Diffstat (limited to 'vmime-master/src/vmime/dateTime.cpp')
-rw-r--r-- | vmime-master/src/vmime/dateTime.cpp | 925 |
1 files changed, 925 insertions, 0 deletions
diff --git a/vmime-master/src/vmime/dateTime.cpp b/vmime-master/src/vmime/dateTime.cpp new file mode 100644 index 0000000..fd44303 --- /dev/null +++ b/vmime-master/src/vmime/dateTime.cpp @@ -0,0 +1,925 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002 Vincent Richard <vincent@vmime.org> +// +// 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 Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include <iomanip> + +#include "vmime/config.hpp" +#include "vmime/dateTime.hpp" +#include "vmime/platform.hpp" +#include "vmime/parserHelpers.hpp" + +#include "vmime/utility/datetimeUtils.hpp" + + +namespace vmime { + +/* + + RFC #822: + 5. DATE AND TIME SPECIFICATION + +date-time = [ day "," ] date time ; dd mm yy + ; hh:mm:ss zzz +day = "Mon" / "Tue" / "Wed" / "Thu" / + "Fri" / "Sat" / "Sun" + +date = 1*2DIGIT month 2DIGIT ; day month year + ; e.g. 20 Jun 82 +month = "Jan" / "Feb" / "Mar" / "Apr" / + "May" / "Jun" / "Jul" / "Aug" / + "Sep" / "Oct" / "Nov" / "Dec" + +time = hour zone ; ANSI and Military + +hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59 + +zone = "UT" / "GMT" ; Universal Time + ; North American : UT + / "EST" / "EDT" ; Eastern: - 5/ - 4 + / "CST" / "CDT" ; Central: - 6/ - 5 + / "MST" / "MDT" ; Mountain: - 7/ - 6 + / "PST" / "PDT" ; Pacific: - 8/ - 7 + / 1ALPHA ; Military: Z = UT; + ; A:-1; (J not used) + ; M:-12; N:+1; Y:+12 + / ( ("+" / "-") 4DIGIT ) ; Local differential + ; hours+min. (HHMM) +*/ + + +void datetime::parseImpl( + const parsingContext& /* ctx */, + const string& buffer, + const size_t position, + const size_t end, + size_t* newPosition +) { + + const char* const pend = buffer.data() + end; + const char* p = buffer.data() + position; + + // Parse the date and time value + while (p < pend && parserHelpers::isSpace(*p)) ++p; + + if (p < pend) { + + if (parserHelpers::isAlpha(*p)) { + + // Ignore week day + while (p < pend && parserHelpers::isAlpha(*p)) ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + if (p < pend && *p == ',') ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + } + + bool dayParsed = false; + + if (parserHelpers::isAlpha(*p)) { + + // Ill-formed date/time, this may be the month, + // so we skip day parsing (will be done later) + + } else { + + while (p < pend && !parserHelpers::isDigit(*p)) ++p; + + if (p < pend && parserHelpers::isDigit(*p)) { + + // Month day + int day = 0; + + do { + day = day * 10 + (*p - '0'); + ++p; + } while (p < pend && parserHelpers::isDigit(*p)); + + m_day = (day >= 1 && day <= 31) ? day : 1; + + while (p < pend && !parserHelpers::isSpace(*p)) ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + + } else { + + m_day = 1; + + // Skip everything to the next field + while (p < pend && !parserHelpers::isSpace(*p)) ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + } + + dayParsed = true; + } + + if (p < pend && parserHelpers::isAlpha(*p)) { + + // Month + char_t month[4] = { 0 }; + int monthLength = 0; + + do { + month[monthLength++] = *p; + ++p; + } while (monthLength < 3 && p < pend && parserHelpers::isAlpha(*p)); + + while (p < pend && parserHelpers::isAlpha(*p)) ++p; + + switch (month[0]) { + + case 'a': + case 'A': { + + if (month[1] == 'u' || month[1] == 'U') + m_month = AUGUST; + else + m_month = APRIL; // by default + + break; + } + case 'd': + case 'D': { + + m_month = DECEMBER; + break; + } + case 'f': + case 'F': { + + m_month = FEBRUARY; + break; + } + case 'j': + case 'J': { + + if (month[1] == 'u' || month[1] == 'U') { + + if (month[2] == 'l' || month[2] == 'L') { + m_month = JULY; + } else { // if (month[2] == 'n' || month[2] == 'N') + m_month = JUNE; + } + + } else { + + m_month = JANUARY; // by default + } + + break; + } + case 'm': + case 'M': { + + if ((month[1] == 'a' || month[1] == 'A') && + (month[2] == 'y' || month[2] == 'Y')) { + + m_month = MAY; + + } else { + + m_month = MARCH; // by default + } + + break; + } + case 'n': + case 'N': { + + m_month = NOVEMBER; + break; + } + case 'o': + case 'O': { + + m_month = OCTOBER; + break; + } + case 's': + case 'S': { + + m_month = SEPTEMBER; + break; + } + default: { + + m_month = JANUARY; // by default + break; + } + } + + while (p < pend && !parserHelpers::isSpace(*p)) ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + + } else { + + m_month = JANUARY; + + if (parserHelpers::isDigit(*p)) { + + // Here, we expected a month, but it maybe + // a ill-formed date, so try to parse a year + // (we don't skip anything). + + } else { + + // Skip everything to the next field + while (p < pend && !parserHelpers::isSpace(*p)) ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + } + } + + if (!dayParsed && p < pend && parserHelpers::isDigit(*p)) { + + // Month day + int day = 0; + + do { + day = day * 10 + (*p - '0'); + ++p; + } while (p < pend && parserHelpers::isDigit(*p)); + + m_day = (day >= 1 && day <= 31) ? day : 1; + + while (p < pend && !parserHelpers::isSpace(*p)) ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + } + + if (p < pend && parserHelpers::isDigit(*p)) { + + // Check for ill-formed date/time and try to recover + if (p + 2 < pend && *(p + 2) == ':') { + + // Skip year (default to current), and advance + // to time parsing + m_year = now().getYear(); + + } else { + + // Year + int year = 0; + + do { + year = year * 10 + (*p - '0'); + ++p; + } while (p < pend && parserHelpers::isDigit(*p)); + + if (year < 70) m_year = year + 2000; + else if (year < 1000) m_year = year + 1900; + else m_year = year; + + while (p < pend && !parserHelpers::isSpace(*p)) ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + } + + } else { + + m_year = 1970; + + // Skip everything to the next field + while (p < pend && !parserHelpers::isSpace(*p)) ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + } + + if (p < pend && parserHelpers::isDigit(*p)) { + + // Hour + int hour = 0; + + do { + hour = hour * 10 + (*p - '0'); + ++p; + } while (p < pend && parserHelpers::isDigit(*p)); + + m_hour = (hour >= 0 && hour <= 23) ? hour : 0; + + while (p < pend && parserHelpers::isSpace(*p)) ++p; + + if (p < pend && *p == ':') { + + ++p; + + while (p < pend && parserHelpers::isSpace(*p)) ++p; + + if (p < pend && parserHelpers::isDigit(*p)) { + + // Minute + int minute = 0; + + do { + minute = minute * 10 + (*p - '0'); + ++p; + } while (p < pend && parserHelpers::isDigit(*p)); + + m_minute = (minute >= 0 && minute <= 59) ? minute : 0; + + while (p < pend && parserHelpers::isSpace(*p)) ++p; + + if (p < pend && *p == ':') { + + ++p; + + while (p < pend && parserHelpers::isSpace(*p)) ++p; + + if (p < pend && parserHelpers::isDigit(*p)) { + + // Second + int second = 0; + + do { + second = second * 10 + (*p - '0'); + ++p; + } while (p < pend && parserHelpers::isDigit(*p)); + + m_second = (second >= 0 && second <= 59) ? second : 0; + + while (p < pend && !parserHelpers::isSpace(*p)) ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + + } else { + + m_second = 0; + } + + } else { + + m_second = 0; + } + + } else { + + m_minute = 0; + } + + } else { + + m_minute = 0; + } + + } else { + + m_hour = 0; + + // Skip everything to the next field + while (p < pend && !parserHelpers::isSpace(*p)) ++p; + while (p < pend && parserHelpers::isSpace(*p)) ++p; + } + + if (p + 1 < pend && (*p == '+' || *p == '-') && parserHelpers::isDigit(*(p + 1))) { + + const char_t sign = *p; + ++p; + + // Zone offset (in hour/minutes) + int offset = 0; + + do { + offset = offset * 10 + (*p - '0'); + ++p; + } while (p < pend && parserHelpers::isDigit(*p)); + + const int hourOff = offset / 100; + const int minOff = offset % 100; + + if (sign == '+') { + m_zone = hourOff * 60 + minOff; + } else { + m_zone = -(hourOff * 60 + minOff); + } + + } else if (p < pend && isalpha(*p)) { + + bool done = false; + + // Zone offset (Time zone name) + char_t zone[4] = { 0 }; + int zoneLength = 0; + + do { + zone[zoneLength++] = *p; + ++p; + } while (zoneLength < 3 && p < pend); + + switch (zone[0]) + { + case 'c': + case 'C': + { + if (zoneLength >= 2) + { + if (zone[1] == 's' || zone[1] == 'S') + m_zone = CST; + else + m_zone = CDT; + + done = true; + } + + break; + } + case 'e': + case 'E': + { + if (zoneLength >= 2) { + + if (zone[1] == 's' || zone[1] == 'S') { + m_zone = EST; + } else { + m_zone = EDT; + } + + done = true; + } + + break; + } + case 'm': + case 'M': { + + if (zoneLength >= 2) { + + if (zone[1] == 's' || zone[1] == 'S') { + m_zone = MST; + } else { + m_zone = MDT; + } + + done = true; + } + + break; + } + case 'p': + case 'P': { + + if (zoneLength >= 2) { + + if (zone[1] == 's' || zone[1] == 'S') { + m_zone = PST; + } else { + m_zone = PDT; + } + + done = true; + } + + break; + } + case 'g': + case 'G': + case 'u': + case 'U': { + + if (zoneLength >= 2) { + + m_zone = GMT; // = UTC + done = true; + } + + break; + } + + } + + if (!done) { + + const char_t z = zone[0]; + + // Military time zone + if (z != 'j' && z != 'J') { + + typedef std::map <char_t, int> Map; + static const Map::value_type offsetMapInit[] = { + + Map::value_type('a', -60), + Map::value_type('b', -120), + Map::value_type('c', -180), + Map::value_type('d', -240), + Map::value_type('e', -300), + Map::value_type('f', -360), + Map::value_type('g', -420), + Map::value_type('h', -480), + Map::value_type('i', -540), + Map::value_type('k', -600), + Map::value_type('l', -660), + Map::value_type('m', -720), + + Map::value_type('n', 60), + Map::value_type('o', 120), + Map::value_type('p', 180), + Map::value_type('q', 240), + Map::value_type('r', 300), + Map::value_type('s', 360), + Map::value_type('t', 420), + Map::value_type('u', 480), + Map::value_type('v', 540), + Map::value_type('w', 600), + Map::value_type('x', 660), + Map::value_type('y', 720), + + Map::value_type('z', 0), + }; + + static const Map offsetMap( + ::vmime::begin(offsetMapInit), + ::vmime::end(offsetMapInit) + ); + + Map::const_iterator pos = + offsetMap.find(parserHelpers::toLower(z)); + + if (pos != offsetMap.end()) { + m_zone = (*pos).second; + } else { + m_zone = GMT; + } + + } else { + + m_zone = GMT; + } + } + + } else { + + m_zone = 0; + } + + } else { + + m_year = 1970; + m_month = JANUARY; + m_day = 1; + + m_hour = 0; + m_minute = 0; + m_second = 0; + + m_zone = 0; + } + + setParsedBounds(position, end); + + if (newPosition) { + *newPosition = end; + } +} + + +void datetime::generateImpl( + const generationContext& /* ctx */, + utility::outputStream& os, + const size_t curLinePos, + size_t* newLinePos +) const { + + static const char* dayNames[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char* monthNames[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + const int z = ((m_zone < 0) ? -m_zone : m_zone); + const int zh = z / 60; + const int zm = z % 60; + + std::ostringstream oss; + oss.imbue(std::locale::classic()); + + oss << dayNames[getWeekDay()] << ", " + << m_day << " " << monthNames[m_month - 1] << " " << m_year + << " " << std::setfill('0') << std::setw(2) << m_hour << ":" + << std::setfill('0') << std::setw(2) << m_minute << ":" + << std::setfill('0') << std::setw(2) << m_second + << " " << ((m_zone < 0) ? '-' : '+') << std::setfill('0') << std::setw(2) << zh + << std::setfill('0') << std::setw(2) << zm; + + const string& str = oss.str(); + os << str; + + if (newLinePos) { + *newLinePos = curLinePos + str.length(); + } +} + + +datetime::datetime() + : m_year(1970), m_month(1), m_day(1), + m_hour(0), m_minute(0), m_second(0), m_zone(0) { + +} + + +datetime::datetime(const int year, const int month, const int day) + : m_year(year), m_month(month), m_day(day), + m_hour(0), m_minute(0), m_second(0), m_zone(0) { + +} + + +datetime::datetime( + const int year, + const int month, + const int day, + const int hour, + const int minute, + const int second, + const int zone +) + : m_year(year), + m_month(month), + m_day(day), + m_hour(hour), + m_minute(minute), + m_second(second), + m_zone(zone) { + +} + + +datetime::datetime(const datetime& d) + : headerFieldValue(), + m_year(d.m_year), + m_month(d.m_month), + m_day(d.m_day), + m_hour(d.m_hour), + m_minute(d.m_minute), + m_second(d.m_second), + m_zone(d.m_zone) { + +} + + +datetime::datetime(const time_t t, const int zone) { + +#if VMIME_HAVE_LOCALTIME_S + + struct tm tms; + + if (!gmtime_s(&tms, &t)) { + localtime_s(&tms, &t); + } + +#elif VMIME_HAVE_LOCALTIME_R + struct tm tms; + + if (!gmtime_r(&t, &tms)) { + localtime_r(&t, &tms); + } + +#else + + struct tm* gtm = gmtime(&t); + struct tm* ltm = localtime(&t); + + struct tm tms; + + if (gtm) { + tms = *gtm; + } else if (ltm) { + tms = *ltm; + } + +#endif + + m_year = tms.tm_year + 1900; + m_month = tms.tm_mon + 1; + m_day = tms.tm_mday; + m_hour = tms.tm_hour; + m_minute = tms.tm_min; + m_second = tms.tm_sec; + m_zone = zone; +} + + +datetime::datetime(const string& date) { + + parse(date); +} + + +datetime::~datetime() { + +} + + +void datetime::copyFrom(const component& other) { + + const datetime& d = dynamic_cast <const datetime&>(other); + + m_year = d.m_year; + m_month = d.m_month; + m_day = d.m_day; + m_hour = d.m_hour; + m_minute = d.m_minute; + m_second = d.m_second; + m_zone = d.m_zone; +} + + +datetime& datetime::operator=(const datetime& other) { + + copyFrom(other); + return *this; +} + + +datetime& datetime::operator=(const string& s) { + + parse(s); + return *this; +} + + +void datetime::getTime(int& hour, int& minute, int& second, int& zone) const { + + hour = m_hour; + minute = m_minute; + second = m_second; + zone = m_zone; +} + + +void datetime::getTime(int& hour, int& minute, int& second) const { + + hour = m_hour; + minute = m_minute; + second = m_second; +} + + +void datetime::getDate(int& year, int& month, int& day) const { + + year = m_year; + month = m_month; + day = m_day; +} + + +void datetime::setTime( + const int hour, + const int minute, + const int second, + const int zone +) { + + m_hour = hour; + m_minute = minute; + m_second = second; + m_zone = zone; +} + + +void datetime::setDate( + const int year, + const int month, + const int day +) { + + m_year = year; + m_month = month; + m_day = day; +} + + +const datetime datetime::now() { + + return platform::getHandler()->getCurrentLocalTime(); +} + + +shared_ptr <component> datetime::clone() const { + + return make_shared <datetime>(*this); +} + + +const std::vector <shared_ptr <component> > datetime::getChildComponents() { + + return std::vector <shared_ptr <component> >(); +} + + +int datetime::getYear() const { return m_year; } +int datetime::getMonth() const { return m_month; } +int datetime::getDay() const { return m_day; } +int datetime::getHour() const { return m_hour; } +int datetime::getMinute() const { return m_minute; } +int datetime::getSecond() const { return m_second; } +int datetime::getZone() const { return m_zone; } +int datetime::getWeekDay() const { return utility::datetimeUtils::getDayOfWeek(m_year, m_month, m_day); } +int datetime::getWeek() const { return utility::datetimeUtils::getWeekOfYear(m_year, m_month, m_day); } + +void datetime::setYear(const int year) { m_year = year; } +void datetime::setMonth(const int month) { m_month = std::min(std::max(month, 1), 12); } +void datetime::setDay(const int day) { m_day = day; } +void datetime::setHour(const int hour) { m_hour = hour; } +void datetime::setMinute(const int minute) { m_minute = minute; } +void datetime::setSecond(const int second) { m_second = second; } +void datetime::setZone(const int zone) { m_zone = zone; } + + +bool datetime::operator==(const datetime& other) const { + + const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this); + const datetime ut2 = utility::datetimeUtils::toUniversalTime(other); + + return ut1.m_year == ut2.m_year && + ut1.m_month == ut2.m_month && + ut1.m_day == ut2.m_day && + ut1.m_hour == ut2.m_hour && + ut1.m_minute == ut2.m_minute && + ut1.m_second == ut2.m_second; +} + + +bool datetime::operator!=(const datetime& other) const { + + const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this); + const datetime ut2 = utility::datetimeUtils::toUniversalTime(other); + + return ut1.m_year != ut2.m_year || + ut1.m_month != ut2.m_month || + ut1.m_day != ut2.m_day || + ut1.m_hour != ut2.m_hour || + ut1.m_minute != ut2.m_minute || + ut1.m_second != ut2.m_second; +} + + +bool datetime::operator<(const datetime& other) const { + + const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this); + const datetime ut2 = utility::datetimeUtils::toUniversalTime(other); + + return (ut1.m_year < ut2.m_year) || + ((ut1.m_year == ut2.m_year) && ((ut1.m_month < ut2.m_month) || + ((ut1.m_month == ut2.m_month) && ((ut1.m_day < ut2.m_day) || + ((ut1.m_day == ut2.m_day) && ((ut1.m_hour < ut2.m_hour) || + ((ut1.m_hour == ut2.m_hour) && ((ut1.m_minute < ut2.m_minute) || + ((ut1.m_minute == ut2.m_minute) && ((ut1.m_second < ut2.m_second))))))))))); +} + + +bool datetime::operator<=(const datetime& other) const { + + const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this); + const datetime ut2 = utility::datetimeUtils::toUniversalTime(other); + + return (ut1.m_year < ut2.m_year) || + ((ut1.m_year == ut2.m_year) && ((ut1.m_month < ut2.m_month) || + ((ut1.m_month == ut2.m_month) && ((ut1.m_day < ut2.m_day) || + ((ut1.m_day == ut2.m_day) && ((ut1.m_hour < ut2.m_hour) || + ((ut1.m_hour == ut2.m_hour) && ((ut1.m_minute < ut2.m_minute) || + ((ut1.m_minute == ut2.m_minute) && ((ut1.m_second <= ut2.m_second))))))))))); +} + + +bool datetime::operator>(const datetime& other) const { + + const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this); + const datetime ut2 = utility::datetimeUtils::toUniversalTime(other); + + return (ut1.m_year > ut2.m_year) || + ((ut1.m_year == ut2.m_year) && ((ut1.m_month > ut2.m_month) || + ((ut1.m_month == ut2.m_month) && ((ut1.m_day > ut2.m_day) || + ((ut1.m_day == ut2.m_day) && ((ut1.m_hour > ut2.m_hour) || + ((ut1.m_hour == ut2.m_hour) && ((ut1.m_minute > ut2.m_minute) || + ((ut1.m_minute == ut2.m_minute) && (ut1.m_second > ut2.m_second)))))))))); +} + + +bool datetime::operator>=(const datetime& other) const { + + const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this); + const datetime ut2 = utility::datetimeUtils::toUniversalTime(other); + + return (ut1.m_year > ut2.m_year) || + ((ut1.m_year == ut2.m_year) && ((ut1.m_month > ut2.m_month) || + ((ut1.m_month == ut2.m_month) && ((ut1.m_day > ut2.m_day) || + ((ut1.m_day == ut2.m_day) && ((ut1.m_hour > ut2.m_hour) || + ((ut1.m_hour == ut2.m_hour) && ((ut1.m_minute > ut2.m_minute) || + ((ut1.m_minute == ut2.m_minute) && (ut1.m_second >= ut2.m_second)))))))))); +} + + +} // vmime |