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