00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "r_task.h"
00024 #include "record-internal.h"
00025 #include "protostructs.h"
00026 #include "data.h"
00027 #include "time.h"
00028 #include "debug.h"
00029 #include <ostream>
00030 #include <iomanip>
00031 #include <string.h>
00032
00033 using namespace std;
00034 using namespace Barry::Protocol;
00035
00036 namespace Barry {
00037
00038
00039
00040
00041
00042 #define TSKFC_TASK_TYPE 0x01
00043 #define TSKFC_TITLE 0x02
00044 #define TSKFC_NOTES 0x03
00045 #define TSKFC_START_TIME 0x05
00046 #define TSKFC_DUE_TIME 0x06
00047 #define TSKFC_DUE_FLAG 0x08
00048 #define TSKFC_STATUS 0x09
00049 #define TSKFC_PRIORITY 0x0a
00050 #define TSKFC_RECURRENCE_DATA 0x0c
00051 #define TSKFC_ALARM_TYPE 0x0e
00052 #define TSKFC_ALARM_TIME 0x0f
00053 #define TSKFC_TIMEZONE_CODE 0x10
00054 #define TSKFC_CATEGORIES 0x11
00055 #define TSKFC_END 0xffff
00056
00057 FieldLink<Task> TaskFieldLinks[] = {
00058 { TSKFC_TITLE, "Summary", 0, 0, &Task::Summary, 0, 0 },
00059 { TSKFC_NOTES, "Notes", 0, 0, &Task::Notes, 0, 0 },
00060 { TSKFC_START_TIME, "Start Time", 0, 0, 0, 0, &Task::StartTime },
00061 { TSKFC_DUE_TIME, "Due Time", 0, 0, 0, 0, &Task::DueTime },
00062 { TSKFC_ALARM_TIME, "Alarm Time", 0, 0, 0, 0, &Task::AlarmTime },
00063 { TSKFC_CATEGORIES, "Categories", 0, 0, &Task::Categories, 0, 0 },
00064 { TSKFC_END, "End of List", 0, 0, 0, 0, 0 },
00065 };
00066
00067 Task::Task()
00068 {
00069 Clear();
00070 }
00071
00072 Task::~Task()
00073 {
00074 }
00075
00076 const unsigned char* Task::ParseField(const unsigned char *begin,
00077 const unsigned char *end)
00078 {
00079 const CommonField *field = (const CommonField *) begin;
00080
00081
00082 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00083 if( begin > end )
00084 return begin;
00085
00086 if( !btohs(field->size) )
00087 return begin;
00088
00089 if( field->type == TSKFC_TASK_TYPE ) {
00090 if( ( TaskType = field->u.raw[0] ) != 't' ) {
00091 throw Error("Task::ParseField: Task Type is not 't'");
00092 }
00093 return begin;
00094 }
00095
00096
00097 for( FieldLink<Task> *b = TaskFieldLinks;
00098 b->type != TSKFC_END;
00099 b++ )
00100 {
00101 if( b->type == field->type ) {
00102 if( b->strMember ) {
00103 std::string &s = this->*(b->strMember);
00104 s = ParseFieldString(field);
00105 return begin;
00106 }
00107 else if( b->timeMember && btohs(field->size) == 4 ) {
00108 time_t &t = this->*(b->timeMember);
00109 t = min2time(field->u.min1900);
00110 return begin;
00111 }
00112 }
00113 }
00114
00115 switch( field->type )
00116 {
00117 case TSKFC_PRIORITY:
00118 if( field->u.raw[0] > Low ) {
00119 throw Error( "Task::ParseField: priority field out of bounds" );
00120 }
00121 else {
00122 PriorityFlag = (PriorityFlagType)field->u.raw[0];
00123 }
00124 return begin;
00125
00126 case TSKFC_STATUS:
00127 if( field->u.raw[0] > Deferred ) {
00128 throw Error( "Task::ParseField: priority field out of bounds" );
00129 }
00130 else {
00131 StatusFlag = (StatusFlagType)field->u.raw[0];
00132 }
00133 return begin;
00134
00135 case TSKFC_TIMEZONE_CODE:
00136 if( btohs(field->size) == 4 ) {
00137 TimeZoneCode = btohs(field->u.code);
00138 }
00139 else {
00140 throw Error("Task::ParseField: not enough data in time zone code field");
00141 }
00142 return begin;
00143
00144 case TSKFC_RECURRENCE_DATA:
00145 if( btohs(field->size) >= CALENDAR_RECURRENCE_DATA_FIELD_SIZE ) {
00146 Recurring = true;
00147 ParseRecurrenceData(&field->u.raw[0]);
00148 }
00149 else {
00150 throw Error("Task::ParseField: not enough data in recurrence data field");
00151 }
00152 return begin;
00153
00154 case TSKFC_DUE_FLAG:
00155 DueDateFlag = field->u.raw[0];
00156 return begin;
00157
00158 case TSKFC_ALARM_TYPE:
00159 if( field->u.raw[0] > Relative ) {
00160 throw Error("Task::ParseField: AlarmType out of bounds" );
00161 }
00162 else {
00163 AlarmType = (AlarmFlagType)field->u.raw[0];
00164 }
00165 return begin;
00166 }
00167
00168
00169 UnknownField uf;
00170 uf.type = field->type;
00171 uf.data.assign((const char*)field->u.raw, btohs(field->size));
00172 Unknowns.push_back(uf);
00173
00174
00175 return begin;
00176 }
00177
00178
00179 void Task::ParseRecurrenceData(const void *data)
00180 {
00181 const CalendarRecurrenceDataField *rec =
00182 (const CalendarRecurrenceDataField*) data;
00183
00184 Interval = btohs(rec->interval);
00185 if( Interval < 1 )
00186 Interval = 1;
00187
00188 if( rec->endTime == 0xffffffff ) {
00189 Perpetual = true;
00190 }
00191 else {
00192 RecurringEndTime = min2time(rec->endTime);
00193 Perpetual = false;
00194 }
00195
00196 switch( rec->type )
00197 {
00198 case CRDF_TYPE_DAY:
00199 RecurringType = Day;
00200
00201 break;
00202
00203 case CRDF_TYPE_MONTH_BY_DATE:
00204 RecurringType = MonthByDate;
00205 DayOfMonth = rec->u.month_by_date.monthDay;
00206 break;
00207
00208 case CRDF_TYPE_MONTH_BY_DAY:
00209 RecurringType = MonthByDay;
00210 DayOfWeek = rec->u.month_by_day.weekDay;
00211 WeekOfMonth = rec->u.month_by_day.week;
00212 break;
00213
00214 case CRDF_TYPE_YEAR_BY_DATE:
00215 RecurringType = YearByDate;
00216 DayOfMonth = rec->u.year_by_date.monthDay;
00217 MonthOfYear = rec->u.year_by_date.month;
00218 break;
00219
00220 case CRDF_TYPE_YEAR_BY_DAY:
00221 RecurringType = YearByDay;
00222 DayOfWeek = rec->u.year_by_day.weekDay;
00223 WeekOfMonth = rec->u.year_by_day.week;
00224 MonthOfYear = rec->u.year_by_day.month;
00225 break;
00226
00227 case CRDF_TYPE_WEEK:
00228 RecurringType = Week;
00229
00230
00231
00232
00233 WeekDays = rec->u.week.days;
00234 break;
00235
00236 default:
00237 eout("Unknown recurrence data type: 0x"
00238 << setbase(16) << (unsigned int) rec->type);
00239 throw Error("Unknown recurrence data type");
00240 }
00241 }
00242
00243
00244
00245 void Task::BuildRecurrenceData(void *data)
00246 {
00247 if( !Recurring )
00248 throw Error("Task::BuildRecurrenceData: Attempting to build recurrence data on non-recurring record.");
00249
00250 CalendarRecurrenceDataField *rec = (CalendarRecurrenceDataField*) data;
00251
00252
00253 memset(data, 0, CALENDAR_RECURRENCE_DATA_FIELD_SIZE);
00254
00255 rec->interval = htobs(Interval);
00256 rec->startTime = time2min(StartTime);
00257 if( Perpetual )
00258 rec->endTime = 0xffffffff;
00259 else
00260 rec->endTime = time2min(RecurringEndTime);
00261
00262 switch( RecurringType )
00263 {
00264 case Day:
00265 rec->type = CRDF_TYPE_DAY;
00266
00267 break;
00268
00269 case MonthByDate:
00270 rec->type = CRDF_TYPE_MONTH_BY_DATE;
00271 rec->u.month_by_date.monthDay = DayOfMonth;
00272 break;
00273
00274 case MonthByDay:
00275 rec->type = CRDF_TYPE_MONTH_BY_DAY;
00276 rec->u.month_by_day.weekDay = DayOfWeek;
00277 rec->u.month_by_day.week = WeekOfMonth;
00278 break;
00279
00280 case YearByDate:
00281 rec->type = CRDF_TYPE_YEAR_BY_DATE;
00282 rec->u.year_by_date.monthDay = DayOfMonth;
00283 rec->u.year_by_date.month = MonthOfYear;
00284 break;
00285
00286 case YearByDay:
00287 rec->type = CRDF_TYPE_YEAR_BY_DAY;
00288 rec->u.year_by_day.weekDay = DayOfWeek;
00289 rec->u.year_by_day.week = WeekOfMonth;
00290 rec->u.year_by_day.month = MonthOfYear;
00291 break;
00292
00293 case Week:
00294 rec->type = CRDF_TYPE_WEEK;
00295
00296
00297
00298
00299 rec->u.week.days = WeekDays;
00300 break;
00301
00302 default:
00303 eout("Task::BuildRecurrenceData: "
00304 "Unknown recurrence data type: " << rec->type);
00305 throw Error("Task::BuildRecurrenceData: Unknown recurrence data type");
00306 }
00307 }
00308
00309 void Task::ParseHeader(const Data &data, size_t &offset)
00310 {
00311
00312 }
00313
00314 void Task::ParseFields(const Data &data, size_t &offset)
00315 {
00316 const unsigned char *finish = ParseCommonFields(*this,
00317 data.GetData() + offset, data.GetData() + data.GetSize());
00318 offset += finish - (data.GetData() + offset);
00319 }
00320
00321 void Task::Clear()
00322 {
00323 Summary.clear();
00324 Notes.clear();
00325 Categories.clear();
00326 StartTime = DueTime = AlarmTime = 0;
00327
00328 PriorityFlag = (PriorityFlagType)0;
00329 StatusFlag = (StatusFlagType)0;
00330 AlarmType = (AlarmFlagType)0;
00331
00332 TaskType = 0;
00333
00334 Perpetual = false;
00335 DueDateFlag = false;
00336 Recurring = false;
00337
00338 TimeZoneCode = GetTimeZoneCode( 0, 0 );
00339
00340 Unknowns.clear();
00341 }
00342
00343 void Task::Dump(std::ostream &os) const
00344 {
00345 static const char *PriorityName[] = { "High", "Normal", "Low" };
00346 static const char *StatusName[] = { "Not Started", "In Progress",
00347 "Completed", "Waiting", "Deferred" };
00348 static const char *DayNames[] = { "Sun", "Mon", "Tue", "Wed",
00349 "Thu", "Fri", "Sat" };
00350 static const char *MonthNames[] = { "Jan", "Feb", "Mar", "Apr",
00351 "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
00352 static const char *AlarmTypeName[] = { "None", "By Date", "Relative" };
00353
00354 os << "Task entry: 0x" << setbase(16) << RecordId
00355 << " (" << (unsigned int)RecType << ")\n";
00356
00357
00358 for( const FieldLink<Task> *b = TaskFieldLinks;
00359 b->type != TSKFC_END;
00360 b++ )
00361 {
00362 if( b->strMember ) {
00363 const std::string &s = this->*(b->strMember);
00364 if( s.size() )
00365 os << " " << b->name << ": " << s << "\n";
00366 }
00367 else if( b->timeMember ) {
00368 time_t t = this->*(b->timeMember);
00369 if( t > 0 )
00370 os << " " << b->name << ": " << ctime(&t);
00371 }
00372 }
00373
00374 os << " Priority: " << PriorityName[PriorityFlag] << "\n";
00375 os << " Status: " << StatusName[StatusFlag] << "\n";
00376 if( AlarmType ) {
00377 os << " Alarm Type: " << AlarmTypeName[AlarmType] << "\n";
00378 }
00379
00380
00381 os << " Recurring: " << (Recurring ? "yes" : "no") << "\n";
00382 if( Recurring ) {
00383 switch( RecurringType )
00384 {
00385 case Day:
00386 os << " Every day.\n";
00387 break;
00388
00389 case MonthByDate:
00390 os << " Every month on the "
00391 << DayOfMonth
00392 << (DayOfMonth == 1 ? "st" : "")
00393 << (DayOfMonth == 2 ? "nd" : "")
00394 << (DayOfMonth == 3 ? "rd" : "")
00395 << (DayOfMonth > 3 ? "th" : "")
00396 << "\n";
00397 break;
00398
00399 case MonthByDay:
00400 os << " Every month on the "
00401 << DayNames[DayOfWeek]
00402 << " of week "
00403 << WeekOfMonth
00404 << "\n";
00405 break;
00406
00407 case YearByDate:
00408 os << " Every year on "
00409 << MonthNames[MonthOfYear-1]
00410 << " " << DayOfMonth << "\n";
00411 break;
00412
00413 case YearByDay:
00414 os << " Every year in " << MonthNames[MonthOfYear-1]
00415 << " on "
00416 << DayNames[DayOfWeek]
00417 << " of week " << WeekOfMonth << "\n";
00418 break;
00419
00420 case Week:
00421 os << " Every week on: ";
00422 if( WeekDays & CAL_WD_SUN ) os << "Sun ";
00423 if( WeekDays & CAL_WD_MON ) os << "Mon ";
00424 if( WeekDays & CAL_WD_TUE ) os << "Tue ";
00425 if( WeekDays & CAL_WD_WED ) os << "Wed ";
00426 if( WeekDays & CAL_WD_THU ) os << "Thu ";
00427 if( WeekDays & CAL_WD_FRI ) os << "Fri ";
00428 if( WeekDays & CAL_WD_SAT ) os << "Sat ";
00429 os << "\n";
00430 break;
00431
00432 default:
00433 os << " Unknown recurrence type\n";
00434 break;
00435 }
00436
00437 os << " Interval: " << Interval << "\n";
00438
00439 if( Perpetual )
00440 os << " Ends: never\n";
00441 else
00442 os << " Ends: " << ctime(&RecurringEndTime);
00443 }
00444
00445 os << Unknowns;
00446 os << "\n\n";
00447 }
00448
00449 }
00450