r_task.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_task.cc
00003 ///             Record parsing class for the task database.
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2009, Net Direct Inc. (http://www.netdirect.ca/)
00008     Copyright (C) 2007, Brian Edginton
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019     See the GNU General Public License in the COPYING file at the
00020     root directory of this project for more details.
00021 */
00022 
00023 #include "r_task.h"
00024 #include "r_calendar.h"                        // for CAL_* defines
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 // Task Class
00041 
00042 // Task Field Codes
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         // advance and check size
00084         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00085         if( begin > end )       // if begin==end, we are ok
00086                 return begin;
00087 
00088         if( !btohs(field->size) )   // if field has no size, something's up
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         // cycle through the type table
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;   // done!
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         // handle special cases
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         // if still not handled, add to the Unknowns list
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         // return new pointer for next field
00177         return begin;
00178 }
00179 
00180 // this function assumes the size has already been checked
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;   // must always be >= 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                 // no extra data
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                 // Note: this simple copy is only possible since
00233                 // the CAL_WD_* constants are the same as CRDF_WD_* constants.
00234                 // If this ever changes, this code will need to change.
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 // this function assumes there is CALENDAR_RECURRENCE_DATA_FIELD_SIZE bytes
00246 // available in data
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         // set all to zero
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                 // no extra data
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                 // Note: this simple copy is only possible since
00299                 // the CAL_WD_* constants are the same as CRDF_WD_* constants.
00300                 // If this ever changes, this code will need to change.
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         // no header in Task records
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         // cycle through the type table
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         // print recurrence data if available
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 } // namespace Barry
00452 

Generated on Mon Jan 12 10:51:13 2009 for Barry by  doxygen 1.5.7.1