From 5e302812c8fe3e6de8ab71c9b871d8dbb6e0960d Mon Sep 17 00:00:00 2001 From: Chris Frey Date: Thu, 22 Jan 2009 19:45:02 -0500 Subject: [PATCH] Refactored Calendar and Task record classes This commit creates a new RecurBase class to handle recurrence data. --- ChangeLog | 2 + src/Makefile.am | 2 + src/r_calendar.cc | 229 ++--------------------------- src/r_calendar.h | 57 +------- src/r_recur_base.cc | 306 +++++++++++++++++++++++++++++++++++++++ src/{r_task.h => r_recur_base.h} | 125 +++++++--------- src/r_task.cc | 150 +------------------ src/r_task.h | 36 +---- 8 files changed, 386 insertions(+), 521 deletions(-) create mode 100644 src/r_recur_base.cc copy src/{r_task.h => r_recur_base.h} (52%) diff --git a/ChangeLog b/ChangeLog index b407670d..ec645f5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,8 @@ Release: version 0.15 - 2009/01/?? - finished adding IConverter support to r_task and r_timezone - removed r_message_base.h from doxygen RecordParserClasses group - removed unused ClassType variable from Task record class + - refactored Calendar and Task record classes, creating new + RecurBase to handle recurrence data 2009/01/20 - applied Nicolas Vivien's javaloader patch, fixing constant defines and other small fixes diff --git a/src/Makefile.am b/src/Makefile.am index a5a1a8ab..d16403fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -79,6 +79,7 @@ include_barry_HEADERS = barry.h \ protocol.h \ record.h \ modem.h \ + r_recur_base.h \ r_calendar.h \ r_contact.h \ r_folder.h \ @@ -117,6 +118,7 @@ libbarry_la_SOURCES = time.cc \ dataqueue.cc \ protocol.cc \ record.cc \ + r_recur_base.cc \ r_calendar.cc \ r_contact.cc \ r_folder.cc \ diff --git a/src/r_calendar.cc b/src/r_calendar.cc index c50aa4dd..f539f40b 100644 --- a/src/r_calendar.cc +++ b/src/r_calendar.cc @@ -54,7 +54,6 @@ namespace Barry { #define CALFC_NOTIFICATION_TIME 0x05 #define CALFC_START_TIME 0x06 #define CALFC_END_TIME 0x07 -#define CALFC_RECURRENCE_DATA 0x0c #define CALFC_VERSION_DATA 0x10 #define CALFC_NOTIFICATION_DATA 0x1a #define CALFC_FREEBUSY_FLAG 0x1c @@ -141,17 +140,6 @@ const unsigned char* Calendar::ParseField(const unsigned char *begin, AllDayEvent = field->u.raw[0] == 1; return begin; - case CALFC_RECURRENCE_DATA: - if( btohs(field->size) >= CALENDAR_RECURRENCE_DATA_FIELD_SIZE ) { - // good data - ParseRecurrenceData(&field->u.raw[0]); - } - else { - // not enough data! - throw Error("Calendar::ParseField: not enough data in recurrence data field"); - } - return begin; - case CALFC_TIMEZONE_CODE: if( btohs(field->size) == 2 ) { // good data @@ -177,6 +165,10 @@ const unsigned char* Calendar::ParseField(const unsigned char *begin, return begin; } + // base class handles recurring data + if( RecurBase::ParseField(field->type, field->u.raw, btohs(field->size), ic) ) + return begin; + // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; @@ -187,136 +179,6 @@ const unsigned char* Calendar::ParseField(const unsigned char *begin, return begin; } -// this function assumes the size has already been checked -void Calendar::ParseRecurrenceData(const void *data) -{ - const CalendarRecurrenceDataField *rec = - (const CalendarRecurrenceDataField*) data; - - Interval = btohs(rec->interval); - if( Interval < 1 ) - Interval = 1; // must always be >= 1 - - if( rec->endTime == 0xffffffff ) { - Perpetual = true; - } - else { - RecurringEndTime = min2time(rec->endTime); - Perpetual = false; - } - - switch( rec->type ) - { - case CRDF_TYPE_DAY: - RecurringType = Day; - // no extra data - break; - - case CRDF_TYPE_MONTH_BY_DATE: - RecurringType = MonthByDate; - DayOfMonth = rec->u.month_by_date.monthDay; - break; - - case CRDF_TYPE_MONTH_BY_DAY: - RecurringType = MonthByDay; - DayOfWeek = rec->u.month_by_day.weekDay; - WeekOfMonth = rec->u.month_by_day.week; - break; - - case CRDF_TYPE_YEAR_BY_DATE: - RecurringType = YearByDate; - DayOfMonth = rec->u.year_by_date.monthDay; - MonthOfYear = rec->u.year_by_date.month; - break; - - case CRDF_TYPE_YEAR_BY_DAY: - RecurringType = YearByDay; - DayOfWeek = rec->u.year_by_day.weekDay; - WeekOfMonth = rec->u.year_by_day.week; - MonthOfYear = rec->u.year_by_day.month; - break; - - case CRDF_TYPE_WEEK: - RecurringType = Week; - - // Note: this simple copy is only possible since - // the CAL_WD_* constants are the same as CRDF_WD_* constants. - // If this ever changes, this code will need to change. - WeekDays = rec->u.week.days; - break; - - default: - eout("Unknown recurrence data type: " << rec->type); - throw Error("Unknown recurrence data type"); - } -} - -// this function assumes there is CALENDAR_RECURRENCE_DATA_FIELD_SIZE bytes -// available in data -void Calendar::BuildRecurrenceData(void *data) const -{ - if( !Recurring ) - throw Error("Calendar::BuildRecurrenceData: Attempting to build recurrence data on non-recurring record."); - - CalendarRecurrenceDataField *rec = (CalendarRecurrenceDataField*) data; - - // set all to zero - memset(data, 0, CALENDAR_RECURRENCE_DATA_FIELD_SIZE); - - rec->interval = htobs(Interval); - rec->startTime = time2min(StartTime); - if( Perpetual ) - rec->endTime = 0xffffffff; - else - rec->endTime = time2min(RecurringEndTime); - - switch( RecurringType ) - { - case Day: - rec->type = CRDF_TYPE_DAY; - // no extra data - break; - - case MonthByDate: - rec->type = CRDF_TYPE_MONTH_BY_DATE; - rec->u.month_by_date.monthDay = DayOfMonth; - break; - - case MonthByDay: - rec->type = CRDF_TYPE_MONTH_BY_DAY; - rec->u.month_by_day.weekDay = DayOfWeek; - rec->u.month_by_day.week = WeekOfMonth; - break; - - case YearByDate: - rec->type = CRDF_TYPE_YEAR_BY_DATE; - rec->u.year_by_date.monthDay = DayOfMonth; - rec->u.year_by_date.month = MonthOfYear; - break; - - case YearByDay: - rec->type = CRDF_TYPE_YEAR_BY_DAY; - rec->u.year_by_day.weekDay = DayOfWeek; - rec->u.year_by_day.week = WeekOfMonth; - rec->u.year_by_day.month = MonthOfYear; - break; - - case Week: - rec->type = CRDF_TYPE_WEEK; - - // Note: this simple copy is only possible since - // the CAL_WD_* constants are the same as CRDF_WD_* constants. - // If this ever changes, this code will need to change. - rec->u.week.days = WeekDays; - break; - - default: - eout("Calendar::BuildRecurrenceData: " - "Unknown recurrence data type: " << rec->type); - throw Error("Calendar::BuildRecurrenceData: Unknown recurrence data type"); - } -} - void Calendar::ParseHeader(const Data &data, size_t &offset) { // no header in Calendar records @@ -368,11 +230,10 @@ void Calendar::BuildFields(Data &data, size_t &offset, const IConverter *ic) con } // handle special cases - if( Recurring ) { CalendarRecurrenceDataField recur; - BuildRecurrenceData(&recur); - BuildField(data, offset, CALFC_RECURRENCE_DATA, + BuildRecurrenceData(StartTime, &recur); + BuildField(data, offset, RecurBase::RecurringFieldType(), &recur, CALENDAR_RECURRENCE_DATA_FIELD_SIZE); } @@ -394,6 +255,8 @@ void Calendar::BuildFields(Data &data, size_t &offset, const IConverter *ic) con void Calendar::Clear() { + RecurBase::Clear(); + RecType = Calendar::GetDefaultRecType(); AllDayEvent = false; @@ -405,25 +268,14 @@ void Calendar::Clear() FreeBusyFlag = Free; ClassFlag = Public; - Recurring = false; - RecurringType = Calendar::Week; - Interval = 1; - RecurringEndTime = 0; - Perpetual = false; TimeZoneCode = GetTimeZoneCode(0, 0); // default to GMT TimeZoneValid = false; - DayOfWeek = WeekOfMonth = DayOfMonth = MonthOfYear = 0; - WeekDays = 0; Unknowns.clear(); } void Calendar::Dump(std::ostream &os) 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" }; static const char *ClassTypes[] = { "Public", "Confidential", "Private" }; static const char *FreeBusy[] = { "Free", "Tentative", "Busy", "Out of Office" }; @@ -459,70 +311,7 @@ void Calendar::Dump(std::ostream &os) const } // print recurrence data if available - os << " Recurring: " << (Recurring ? "yes" : "no") << "\n"; - if( Recurring ) { - switch( RecurringType ) - { - case Day: - os << " Every day.\n"; - break; - - case MonthByDate: - os << " Every month on the " - << DayOfMonth - << (DayOfMonth == 1 ? "st" : "") - << (DayOfMonth == 2 ? "nd" : "") - << (DayOfMonth == 3 ? "rd" : "") - << (DayOfMonth > 3 ? "th" : "") - << "\n"; - break; - - case MonthByDay: - os << " Every month on the " - << DayNames[DayOfWeek] - << " of week " - << WeekOfMonth - << "\n"; - break; - - case YearByDate: - os << " Every year on " - << MonthNames[MonthOfYear-1] - << " " << DayOfMonth << "\n"; - break; - - case YearByDay: - os << " Every year in " << MonthNames[MonthOfYear-1] - << " on " - << DayNames[DayOfWeek] - << " of week " << WeekOfMonth << "\n"; - break; - - case Week: - os << " Every week on: "; - if( WeekDays & CAL_WD_SUN ) os << "Sun "; - if( WeekDays & CAL_WD_MON ) os << "Mon "; - if( WeekDays & CAL_WD_TUE ) os << "Tue "; - if( WeekDays & CAL_WD_WED ) os << "Wed "; - if( WeekDays & CAL_WD_THU ) os << "Thu "; - if( WeekDays & CAL_WD_FRI ) os << "Fri "; - if( WeekDays & CAL_WD_SAT ) os << "Sat "; - os << "\n"; - break; - - default: - os << " Unknown recurrence type\n"; - break; - } - - os << " Interval: " << Interval << "\n"; - - if( Perpetual ) - os << " Ends: never\n"; - else - os << " Ends: " - << ctime(&RecurringEndTime); - } + RecurBase::Dump(os); // print any unknowns os << Unknowns; diff --git a/src/r_calendar.h b/src/r_calendar.h index 995ad945..fb26d06c 100644 --- a/src/r_calendar.h +++ b/src/r_calendar.h @@ -24,6 +24,7 @@ #include "dll.h" #include "record.h" +#include "r_recur_base.h" #include #include #include @@ -45,7 +46,7 @@ class IConverter; /// \addtogroup RecordParserClasses /// @{ -class BXEXPORT Calendar +class BXEXPORT Calendar : public RecurBase { public: typedef std::vector UnknownsType; @@ -95,41 +96,7 @@ public: ClassFlagType ClassFlag; - /// - /// Recurring data - /// - /// Note: interval can be used on all of these recurring types to - /// make it happen "every other time" or more, etc. - /// - enum RecurringCodeType { - Day = 1, //< eg. every day - //< set: nothing - MonthByDate = 3, //< eg. every month on the 12th - //< set: DayOfMonth - MonthByDay = 4, //< eg. every month on 3rd Wed - //< set: DayOfWeek and WeekOfMonth - YearByDate = 5, //< eg. every year on March 5 - //< set: DayOfMonth and MonthOfYear - YearByDay = 6, //< eg. every year on 3rd Wed of Jan - //< set: DayOfWeek, WeekOfMonth, and - //< MonthOfYear - Week = 12 //< eg. every week on Mon and Fri - //< set: WeekDays - }; - - - - bool Recurring; - RecurringCodeType RecurringType; - unsigned short Interval; // must be >= 1 - time_t RecurringEndTime; // only pertains if Recurring is true - // sets the date and time when - // recurrence of this appointment - // should no longer occur - // If a perpetual appointment, this - // is 0xFFFFFFFF in the low level data - // Instead, set the following flag. - bool Perpetual; // if true, this will always recur + unsigned short TimeZoneCode; // the time zone originally used // for the recurrence data... // seems to have little use, but @@ -138,30 +105,12 @@ public: bool TimeZoneValid; // true if the record contained a // time zone code - unsigned short // recurring details, depending on type - DayOfWeek, // 0-6 - WeekOfMonth, // 1-5 - DayOfMonth, // 1-31 - MonthOfYear; // 1-12 - unsigned char WeekDays; // bitmask, bit 0 = sunday - -// FIXME - put these somewhere usable by both C and C++ - #define CAL_WD_SUN 0x01 - #define CAL_WD_MON 0x02 - #define CAL_WD_TUE 0x04 - #define CAL_WD_WED 0x08 - #define CAL_WD_THU 0x10 - #define CAL_WD_FRI 0x20 - #define CAL_WD_SAT 0x40 - // unknown UnknownsType Unknowns; public: const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); - void ParseRecurrenceData(const void *data); - void BuildRecurrenceData(void *data) const; public: Calendar(); diff --git a/src/r_recur_base.cc b/src/r_recur_base.cc new file mode 100644 index 00000000..bf13a581 --- /dev/null +++ b/src/r_recur_base.cc @@ -0,0 +1,306 @@ +/// +/// \file r_recur_base.cc +/// Base class for recurring calendar event data. +/// + +/* + Copyright (C) 2005-2009, Net Direct Inc. (http://www.netdirect.ca/) + + 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 2 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 in the COPYING file at the + root directory of this project for more details. +*/ + +#include "r_recur_base.h" +#include "protostructs.h" +#include "error.h" +#include "endian.h" +#include "time.h" +#include + +#define __DEBUG_MODE__ +#include "debug.h" + +using namespace std; +using namespace Barry::Protocol; + + +#define FIELDCODE_RECURRENCE_DATA 0x0c + +namespace Barry { + + +/////////////////////////////////////////////////////////////////////////////// +// RecurBase class + +RecurBase::RecurBase() +{ + Clear(); +} + +RecurBase::~RecurBase() +{ +} + +bool RecurBase::ParseField(uint8_t type, + const unsigned char *data, + size_t size, + const IConverter *ic) +{ + // handle special cases + switch( type ) + { + case FIELDCODE_RECURRENCE_DATA: + if( size >= CALENDAR_RECURRENCE_DATA_FIELD_SIZE ) { + // good data + ParseRecurrenceData(data); + } + else { + // not enough data! + throw Error("RecurBase::ParseField: not enough data in recurrence data field"); + } + return true; + } + + // unknown field + return false; +} + +// this function assumes the size has already been checked +void RecurBase::ParseRecurrenceData(const void *data) +{ + const CalendarRecurrenceDataField *rec = + (const CalendarRecurrenceDataField*) data; + + Interval = btohs(rec->interval); + if( Interval < 1 ) + Interval = 1; // must always be >= 1 + + if( rec->endTime == 0xffffffff ) { + Perpetual = true; + } + else { + RecurringEndTime = min2time(rec->endTime); + Perpetual = false; + } + + switch( rec->type ) + { + case CRDF_TYPE_DAY: + RecurringType = Day; + // no extra data + break; + + case CRDF_TYPE_MONTH_BY_DATE: + RecurringType = MonthByDate; + DayOfMonth = rec->u.month_by_date.monthDay; + break; + + case CRDF_TYPE_MONTH_BY_DAY: + RecurringType = MonthByDay; + DayOfWeek = rec->u.month_by_day.weekDay; + WeekOfMonth = rec->u.month_by_day.week; + break; + + case CRDF_TYPE_YEAR_BY_DATE: + RecurringType = YearByDate; + DayOfMonth = rec->u.year_by_date.monthDay; + MonthOfYear = rec->u.year_by_date.month; + break; + + case CRDF_TYPE_YEAR_BY_DAY: + RecurringType = YearByDay; + DayOfWeek = rec->u.year_by_day.weekDay; + WeekOfMonth = rec->u.year_by_day.week; + MonthOfYear = rec->u.year_by_day.month; + break; + + case CRDF_TYPE_WEEK: + RecurringType = Week; + + // Note: this simple copy is only possible since + // the CAL_WD_* constants are the same as CRDF_WD_* constants. + // If this ever changes, this code will need to change. + WeekDays = rec->u.week.days; + break; + + default: + eout("Unknown recurrence data type: 0x" + << setbase(16) << (unsigned int) rec->type); + throw Error("Unknown recurrence data type"); + } + + Recurring = true; +} + +// this function assumes there is CALENDAR_RECURRENCE_DATA_FIELD_SIZE bytes +// available in data +void RecurBase::BuildRecurrenceData(time_t StartTime, void *data) const +{ + if( !Recurring ) + throw Error("RecurBase::BuildRecurrenceData: Attempting to build recurrence data on non-recurring record."); + + CalendarRecurrenceDataField *rec = (CalendarRecurrenceDataField*) data; + + // set all to zero + memset(data, 0, CALENDAR_RECURRENCE_DATA_FIELD_SIZE); + + rec->interval = htobs(Interval); + rec->startTime = time2min(StartTime); + if( Perpetual ) + rec->endTime = 0xffffffff; + else + rec->endTime = time2min(RecurringEndTime); + + switch( RecurringType ) + { + case Day: + rec->type = CRDF_TYPE_DAY; + // no extra data + break; + + case MonthByDate: + rec->type = CRDF_TYPE_MONTH_BY_DATE; + rec->u.month_by_date.monthDay = DayOfMonth; + break; + + case MonthByDay: + rec->type = CRDF_TYPE_MONTH_BY_DAY; + rec->u.month_by_day.weekDay = DayOfWeek; + rec->u.month_by_day.week = WeekOfMonth; + break; + + case YearByDate: + rec->type = CRDF_TYPE_YEAR_BY_DATE; + rec->u.year_by_date.monthDay = DayOfMonth; + rec->u.year_by_date.month = MonthOfYear; + break; + + case YearByDay: + rec->type = CRDF_TYPE_YEAR_BY_DAY; + rec->u.year_by_day.weekDay = DayOfWeek; + rec->u.year_by_day.week = WeekOfMonth; + rec->u.year_by_day.month = MonthOfYear; + break; + + case Week: + rec->type = CRDF_TYPE_WEEK; + + // Note: this simple copy is only possible since + // the CAL_WD_* constants are the same as CRDF_WD_* constants. + // If this ever changes, this code will need to change. + rec->u.week.days = WeekDays; + break; + + default: + eout("RecurBase::BuildRecurrenceData: " + "Unknown recurrence data type: 0x" + << setbase(16) << (unsigned int) rec->type); + throw Error("RecurBase::BuildRecurrenceData: Unknown recurrence data type"); + } +} + +uint8_t RecurBase::RecurringFieldType() const +{ + return FIELDCODE_RECURRENCE_DATA; +} + +void RecurBase::Clear() +{ + Recurring = false; + RecurringType = RecurBase::Week; + Interval = 1; + RecurringEndTime = 0; + Perpetual = false; + DayOfWeek = WeekOfMonth = DayOfMonth = MonthOfYear = 0; + WeekDays = 0; +} + +void RecurBase::Dump(std::ostream &os) 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" }; + +// FIXME - need a "check all data" function that make sure that all +// recurrence data is within range. Then call that before using +// the data, such as in Build and in Dump. + + // print recurrence data if available + os << " Recurring: " << (Recurring ? "yes" : "no") << "\n"; + if( Recurring ) { + switch( RecurringType ) + { + case Day: + os << " Every day.\n"; + break; + + case MonthByDate: + os << " Every month on the " + << DayOfMonth + << (DayOfMonth == 1 ? "st" : "") + << (DayOfMonth == 2 ? "nd" : "") + << (DayOfMonth == 3 ? "rd" : "") + << (DayOfMonth > 3 ? "th" : "") + << "\n"; + break; + + case MonthByDay: + os << " Every month on the " + << DayNames[DayOfWeek] + << " of week " + << WeekOfMonth + << "\n"; + break; + + case YearByDate: + os << " Every year on " + << MonthNames[MonthOfYear-1] + << " " << DayOfMonth << "\n"; + break; + + case YearByDay: + os << " Every year in " << MonthNames[MonthOfYear-1] + << " on " + << DayNames[DayOfWeek] + << " of week " << WeekOfMonth << "\n"; + break; + + case Week: + os << " Every week on: "; + if( WeekDays & CAL_WD_SUN ) os << "Sun "; + if( WeekDays & CAL_WD_MON ) os << "Mon "; + if( WeekDays & CAL_WD_TUE ) os << "Tue "; + if( WeekDays & CAL_WD_WED ) os << "Wed "; + if( WeekDays & CAL_WD_THU ) os << "Thu "; + if( WeekDays & CAL_WD_FRI ) os << "Fri "; + if( WeekDays & CAL_WD_SAT ) os << "Sat "; + os << "\n"; + break; + + default: + os << " Unknown recurrence type\n"; + break; + } + + os << " Interval: " << Interval << "\n"; + + if( Perpetual ) + os << " Ends: never\n"; + else + os << " Ends: " << ctime(&RecurringEndTime); + } +} + + +} // namespace Barry + diff --git a/src/r_task.h b/src/r_recur_base.h similarity index 52% copy from src/r_task.h copy to src/r_recur_base.h index b43797bf..9b8f3330 100644 --- a/src/r_task.h +++ b/src/r_recur_base.h @@ -1,11 +1,10 @@ /// -/// \file r_task.h -/// Record parsing class for the task database. +/// \file r_recur_base.h +/// Base class for recurring calendar event data. /// /* Copyright (C) 2005-2009, Net Direct Inc. (http://www.netdirect.ca/) - Copyright (C) 2007, Brian Edginton 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 @@ -20,13 +19,15 @@ root directory of this project for more details. */ -#ifndef __BARRY_RECORD_TASK_H__ -#define __BARRY_RECORD_TASK_H__ +#ifndef __BARRY_RECORD_RECUR_BASE_H__ +#define __BARRY_RECORD_RECUR_BASE_H__ #include "dll.h" #include "record.h" -#include +#include #include +#include +#include #include namespace Barry { @@ -34,32 +35,20 @@ namespace Barry { // forward declarations class IConverter; -class BXEXPORT Task +// +// NOTE: All classes here must be container-safe! Perhaps add sorting +// operators in the future. +// + +class BXEXPORT RecurBase { public: - typedef std::vector UnknownsType; - uint8_t RecType; - uint32_t RecordId; - - uint8_t TaskType; - std::string Summary; - std::string Notes; - std::string Categories; - std::string UID; - - time_t StartTime; - time_t DueTime; - time_t AlarmTime; - int TimeZoneCode; - - enum AlarmFlagType - { - Date = 1, - Relative - }; - AlarmFlagType AlarmType; - - unsigned short Interval; + /// + /// Recurring data + /// + /// Note: interval can be used on all of these recurring types to + /// make it happen "every other time" or more, etc. + /// enum RecurringCodeType { Day = 1, //< eg. every day //< set: nothing @@ -75,8 +64,20 @@ public: Week = 12 //< eg. every week on Mon and Fri //< set: WeekDays }; + + + bool Recurring; RecurringCodeType RecurringType; - time_t RecurringEndTime; + unsigned short Interval; // must be >= 1 + time_t RecurringEndTime; // only pertains if Recurring is true + // sets the date and time when + // recurrence of this appointment + // should no longer occur + // If a perpetual appointment, this + // is 0xFFFFFFFF in the low level data + // Instead, set the following flag. + bool Perpetual; // if true, this will always recur + unsigned short // recurring details, depending on type DayOfWeek, // 0-6 WeekOfMonth, // 1-5 @@ -84,57 +85,37 @@ public: MonthOfYear; // 1-12 unsigned char WeekDays; // bitmask, bit 0 = sunday - enum PriorityFlagType - { - High = 0, - Normal, - Low - }; - PriorityFlagType PriorityFlag; - - enum StatusFlagType - { - NotStarted = 0, - InProgress, - Completed, - Waiting, - Deferred - }; - StatusFlagType StatusFlag; +// FIXME - put these somewhere usable by both C and C++ + #define CAL_WD_SUN 0x01 + #define CAL_WD_MON 0x02 + #define CAL_WD_TUE 0x04 + #define CAL_WD_WED 0x08 + #define CAL_WD_THU 0x10 + #define CAL_WD_FRI 0x20 + #define CAL_WD_SAT 0x40 - bool Recurring; - bool Perpetual; - bool DueDateFlag; // true if due date is set +protected: + void ParseRecurrenceData(const void *data); - UnknownsType Unknowns; +protected: + RecurBase(); + ~RecurBase(); -public: - Task(); - ~Task(); +public: + // return true if parse, false if not (for example, if type not + // recognized) + bool ParseField(uint8_t type, const unsigned char *data, size_t size, + const IConverter *ic = 0); + void BuildRecurrenceData(time_t StartTime, void *data) const; - const unsigned char* ParseField(const unsigned char *begin, - const unsigned char *end, const IConverter *ic = 0); - void ParseRecurrenceData(const void *data); - void BuildRecurrenceData(void *data); - uint8_t GetRecType() const { return RecType; } - uint32_t GetUniqueId() const { return RecordId; } - void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } - void ParseHeader(const Data &data, size_t &offset); - void ParseFields(const Data &data, size_t &offset, const IConverter *ic = 0); - void BuildHeader(Data &data, size_t &offset) const; + uint8_t RecurringFieldType() const; void Clear(); void Dump(std::ostream &os) const; - bool operator<(const Task &other) const { return Summary < other.Summary; } - - // database name - static const char * GetDBName() { return "Tasks"; } - static uint8_t GetDefaultRecType() { return 2; } - }; -BXEXPORT inline std::ostream& operator<<(std::ostream &os, const Task &msg) { +BXEXPORT inline std::ostream& operator<<(std::ostream &os, const RecurBase &msg) { msg.Dump(os); return os; } diff --git a/src/r_task.cc b/src/r_task.cc index eb8934a5..edaa2d4e 100644 --- a/src/r_task.cc +++ b/src/r_task.cc @@ -49,7 +49,6 @@ namespace Barry { #define TSKFC_DUE_FLAG 0x08 #define TSKFC_STATUS 0x09 #define TSKFC_PRIORITY 0x0a -#define TSKFC_RECURRENCE_DATA 0x0c #define TSKFC_ALARM_TYPE 0x0e #define TSKFC_ALARM_TIME 0x0f #define TSKFC_TIMEZONE_CODE 0x10 @@ -146,16 +145,6 @@ const unsigned char* Task::ParseField(const unsigned char *begin, } return begin; - case TSKFC_RECURRENCE_DATA: - if( btohs(field->size) >= CALENDAR_RECURRENCE_DATA_FIELD_SIZE ) { - Recurring = true; - ParseRecurrenceData(&field->u.raw[0]); - } - else { - throw Error("Task::ParseField: not enough data in recurrence data field"); - } - return begin; - case TSKFC_DUE_FLAG: DueDateFlag = field->u.raw[0]; return begin; @@ -170,6 +159,10 @@ const unsigned char* Task::ParseField(const unsigned char *begin, return begin; } + // base class handles recurring data + if( RecurBase::ParseField(field->type, field->u.raw, btohs(field->size), ic) ) + return begin; + // if still not handled, add to the Unknowns list UnknownField uf; uf.type = field->type; @@ -180,137 +173,6 @@ const unsigned char* Task::ParseField(const unsigned char *begin, return begin; } -// this function assumes the size has already been checked -void Task::ParseRecurrenceData(const void *data) -{ - const CalendarRecurrenceDataField *rec = - (const CalendarRecurrenceDataField*) data; - - Interval = btohs(rec->interval); - if( Interval < 1 ) - Interval = 1; // must always be >= 1 - - if( rec->endTime == 0xffffffff ) { - Perpetual = true; - } - else { - RecurringEndTime = min2time(rec->endTime); - Perpetual = false; - } - - switch( rec->type ) - { - case CRDF_TYPE_DAY: - RecurringType = Day; - // no extra data - break; - - case CRDF_TYPE_MONTH_BY_DATE: - RecurringType = MonthByDate; - DayOfMonth = rec->u.month_by_date.monthDay; - break; - - case CRDF_TYPE_MONTH_BY_DAY: - RecurringType = MonthByDay; - DayOfWeek = rec->u.month_by_day.weekDay; - WeekOfMonth = rec->u.month_by_day.week; - break; - - case CRDF_TYPE_YEAR_BY_DATE: - RecurringType = YearByDate; - DayOfMonth = rec->u.year_by_date.monthDay; - MonthOfYear = rec->u.year_by_date.month; - break; - - case CRDF_TYPE_YEAR_BY_DAY: - RecurringType = YearByDay; - DayOfWeek = rec->u.year_by_day.weekDay; - WeekOfMonth = rec->u.year_by_day.week; - MonthOfYear = rec->u.year_by_day.month; - break; - - case CRDF_TYPE_WEEK: - RecurringType = Week; - - // Note: this simple copy is only possible since - // the CAL_WD_* constants are the same as CRDF_WD_* constants. - // If this ever changes, this code will need to change. - WeekDays = rec->u.week.days; - break; - - default: - eout("Unknown recurrence data type: 0x" - << setbase(16) << (unsigned int) rec->type); - throw Error("Unknown recurrence data type"); - } -} - -// this function assumes there is CALENDAR_RECURRENCE_DATA_FIELD_SIZE bytes -// available in data -void Task::BuildRecurrenceData(void *data) -{ - if( !Recurring ) - throw Error("Task::BuildRecurrenceData: Attempting to build recurrence data on non-recurring record."); - - CalendarRecurrenceDataField *rec = (CalendarRecurrenceDataField*) data; - - // set all to zero - memset(data, 0, CALENDAR_RECURRENCE_DATA_FIELD_SIZE); - - rec->interval = htobs(Interval); - rec->startTime = time2min(StartTime); - if( Perpetual ) - rec->endTime = 0xffffffff; - else - rec->endTime = time2min(RecurringEndTime); - - switch( RecurringType ) - { - case Day: - rec->type = CRDF_TYPE_DAY; - // no extra data - break; - - case MonthByDate: - rec->type = CRDF_TYPE_MONTH_BY_DATE; - rec->u.month_by_date.monthDay = DayOfMonth; - break; - - case MonthByDay: - rec->type = CRDF_TYPE_MONTH_BY_DAY; - rec->u.month_by_day.weekDay = DayOfWeek; - rec->u.month_by_day.week = WeekOfMonth; - break; - - case YearByDate: - rec->type = CRDF_TYPE_YEAR_BY_DATE; - rec->u.year_by_date.monthDay = DayOfMonth; - rec->u.year_by_date.month = MonthOfYear; - break; - - case YearByDay: - rec->type = CRDF_TYPE_YEAR_BY_DAY; - rec->u.year_by_day.weekDay = DayOfWeek; - rec->u.year_by_day.week = WeekOfMonth; - rec->u.year_by_day.month = MonthOfYear; - break; - - case Week: - rec->type = CRDF_TYPE_WEEK; - - // Note: this simple copy is only possible since - // the CAL_WD_* constants are the same as CRDF_WD_* constants. - // If this ever changes, this code will need to change. - rec->u.week.days = WeekDays; - break; - - default: - eout("Task::BuildRecurrenceData: " - "Unknown recurrence data type: " << rec->type); - throw Error("Task::BuildRecurrenceData: Unknown recurrence data type"); - } -} - void Task::ParseHeader(const Data &data, size_t &offset) { // no header in Task records @@ -325,6 +187,8 @@ void Task::ParseFields(const Data &data, size_t &offset, const IConverter *ic) void Task::Clear() { + RecurBase::Clear(); + Summary.clear(); Notes.clear(); Categories.clear(); @@ -336,9 +200,7 @@ void Task::Clear() TaskType = 0; - Perpetual = false; DueDateFlag = false; - Recurring = false; TimeZoneCode = GetTimeZoneCode( 0, 0 ); diff --git a/src/r_task.h b/src/r_task.h index b43797bf..d73a3069 100644 --- a/src/r_task.h +++ b/src/r_task.h @@ -25,6 +25,7 @@ #include "dll.h" #include "record.h" +#include "r_recur_base.h" #include #include #include @@ -34,10 +35,11 @@ namespace Barry { // forward declarations class IConverter; -class BXEXPORT Task +class BXEXPORT Task : public RecurBase { public: - typedef std::vector UnknownsType; + typedef std::vector UnknownsType; + uint8_t RecType; uint32_t RecordId; @@ -59,31 +61,6 @@ public: }; AlarmFlagType AlarmType; - unsigned short Interval; - enum RecurringCodeType { - Day = 1, //< eg. every day - //< set: nothing - MonthByDate = 3, //< eg. every month on the 12th - //< set: DayOfMonth - MonthByDay = 4, //< eg. every month on 3rd Wed - //< set: DayOfWeek and WeekOfMonth - YearByDate = 5, //< eg. every year on March 5 - //< set: DayOfMonth and MonthOfYear - YearByDay = 6, //< eg. every year on 3rd Wed of Jan - //< set: DayOfWeek, WeekOfMonth, and - //< MonthOfYear - Week = 12 //< eg. every week on Mon and Fri - //< set: WeekDays - }; - RecurringCodeType RecurringType; - time_t RecurringEndTime; - unsigned short // recurring details, depending on type - DayOfWeek, // 0-6 - WeekOfMonth, // 1-5 - DayOfMonth, // 1-31 - MonthOfYear; // 1-12 - unsigned char WeekDays; // bitmask, bit 0 = sunday - enum PriorityFlagType { High = 0, @@ -102,10 +79,9 @@ public: }; StatusFlagType StatusFlag; - bool Recurring; - bool Perpetual; bool DueDateFlag; // true if due date is set + // unknown UnknownsType Unknowns; public: @@ -114,8 +90,6 @@ public: const unsigned char* ParseField(const unsigned char *begin, const unsigned char *end, const IConverter *ic = 0); - void ParseRecurrenceData(const void *data); - void BuildRecurrenceData(void *data); uint8_t GetRecType() const { return RecType; } uint32_t GetUniqueId() const { return RecordId; } void SetIds(uint8_t Type, uint32_t Id) { RecType = Type; RecordId = Id; } -- 2.11.4.GIT