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-2011, 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 "iconv.h"
00030 #include "debug.h"
00031 #include <ostream>
00032 #include <iomanip>
00033 #include <string.h>
00034 
00035 using namespace std;
00036 using namespace Barry::Protocol;
00037 
00038 namespace Barry {
00039 
00040 
00041 ///////////////////////////////////////////////////////////////////////////////
00042 // Task Class, static members
00043 
00044 //
00045 // Note! These functions currently only pass the same values through.
00046 //       In actuality, these are technically two different values:
00047 //       one on the raw protocol side, and the other part of the
00048 //       guaranteed Barry API.  If the Blackberry ever changes the
00049 //       meanings for these codes, do the translation here.
00050 //
00051 
00052 Task::AlarmFlagType Task::AlarmProto2Rec(uint8_t a)
00053 {
00054         return (AlarmFlagType)a;
00055 }
00056 
00057 uint8_t Task::AlarmRec2Proto(AlarmFlagType a)
00058 {
00059         return a;
00060 }
00061 
00062 Task::PriorityFlagType Task::PriorityProto2Rec(uint8_t p)
00063 {
00064         return (PriorityFlagType)p;
00065 }
00066 
00067 uint8_t Task::PriorityRec2Proto(PriorityFlagType p)
00068 {
00069         return p;
00070 }
00071 
00072 Task::StatusFlagType Task::StatusProto2Rec(uint8_t s)
00073 {
00074         return (StatusFlagType)s;
00075 }
00076 
00077 uint8_t Task::StatusRec2Proto(StatusFlagType s)
00078 {
00079         return s;
00080 }
00081 
00082 
00083 ///////////////////////////////////////////////////////////////////////////////
00084 // Task Class
00085 
00086 // Task Field Codes
00087 #define TSKFC_TASK_TYPE         0x01
00088 #define TSKFC_TITLE             0x02
00089 #define TSKFC_NOTES             0x03
00090 #define TSKFC_DUE_TIME          0x05
00091 #define TSKFC_START_TIME        0x06    // This is fuzzy... most devices seem
00092                                         // to anchor this value == to DUE_TIME
00093 #define TSKFC_DUE_FLAG          0x08
00094 #define TSKFC_STATUS            0x09
00095 #define TSKFC_PRIORITY          0x0a
00096 #define TSKFC_ALARM_TYPE        0x0e
00097 #define TSKFC_ALARM_TIME        0x0f
00098 #define TSKFC_TIMEZONE_CODE     0x10
00099 #define TSKFC_CATEGORIES        0x11
00100 #define TSKFC_END               0xffff
00101 
00102 static FieldLink<Task> TaskFieldLinks[] = {
00103    { TSKFC_TITLE,      "Summary",     0, 0, &Task::Summary, 0, 0, 0, 0, true },
00104    { TSKFC_NOTES,      "Notes",       0, 0, &Task::Notes, 0, 0, 0, 0, true },
00105    { TSKFC_START_TIME, "Start Time",  0, 0, 0, 0, &Task::StartTime, 0, 0, false },
00106    { TSKFC_DUE_TIME,   "Due Time",    0, 0, 0, 0, &Task::DueTime, 0, 0, false },
00107    { TSKFC_ALARM_TIME, "Alarm Time",  0, 0, 0, 0, &Task::AlarmTime, 0, 0, false },
00108    { TSKFC_END,        "End of List", 0, 0, 0, 0, 0, 0, 0, false },
00109 };
00110 
00111 Task::Task()
00112 {
00113         Clear();
00114 }
00115 
00116 Task::~Task()
00117 {
00118 }
00119 
00120 const unsigned char* Task::ParseField(const unsigned char *begin,
00121                                       const unsigned char *end,
00122                                       const IConverter *ic)
00123 {
00124         const CommonField *field = (const CommonField *) begin;
00125 
00126         // advance and check size
00127         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00128         if( begin > end )       // if begin==end, we are ok
00129                 return begin;
00130 
00131         if( !btohs(field->size) )   // if field has no size, something's up
00132                 return begin;
00133 
00134         if( field->type == TSKFC_TASK_TYPE ) {
00135                 if( field->u.raw[0] != 't' ) {
00136                         throw Error("Task::ParseField: Task Type is not 't'");
00137                 }
00138                 return begin;
00139         }
00140 
00141         // cycle through the type table
00142         for(    FieldLink<Task> *b = TaskFieldLinks;
00143                 b->type != TSKFC_END;
00144                 b++ )
00145         {
00146                 if( b->type == field->type ) {
00147                         if( b->strMember ) {
00148                                 std::string &s = this->*(b->strMember);
00149                                 s = ParseFieldString(field);
00150                                 if( b->iconvNeeded && ic )
00151                                         s = ic->FromBB(s);
00152                                 return begin;   // done!
00153                         }
00154                         else if( b->timeMember && btohs(field->size) == 4 ) {
00155                                 time_t &t = this->*(b->timeMember);
00156                                 t = min2time(field->u.min1900);
00157                                 return begin;
00158                         }
00159                 }
00160         }
00161         // handle special cases
00162         switch( field->type )
00163         {
00164         case TSKFC_PRIORITY:
00165                 if( field->u.raw[0] > TR_PRIORITY_RANGE_HIGH ) {
00166                         throw Error( "Task::ParseField: priority field out of bounds" );
00167                 }
00168                 else {
00169                         PriorityFlag = PriorityProto2Rec(field->u.raw[0]);
00170                 }
00171                 return begin;
00172 
00173         case TSKFC_STATUS:
00174                 if( field->u.raw[0] > TR_STATUS_RANGE_HIGH ) {
00175                         throw Error( "Task::ParseField: priority field out of bounds" );
00176                 }
00177                 else {
00178                         StatusFlag = StatusProto2Rec(field->u.raw[0]);
00179                 }
00180                 return begin;
00181 
00182         case TSKFC_TIMEZONE_CODE:
00183                 if( btohs(field->size) == 4 ) {
00184                         TimeZoneCode = btohs(field->u.code);
00185                         TimeZoneValid = true;
00186                 }
00187                 else {
00188                         throw Error("Task::ParseField: not enough data in time zone code field");
00189                 }
00190                 return begin;
00191 
00192         case TSKFC_DUE_FLAG:
00193                 DueDateFlag = field->u.raw[0];
00194                 return begin;
00195 
00196         case TSKFC_ALARM_TYPE:
00197                 if( field->u.raw[0] > TR_ALARM_RANGE_HIGH ) {
00198                         throw Error("Task::ParseField: AlarmType out of bounds" );
00199                 }
00200                 else {
00201                         AlarmType = AlarmProto2Rec(field->u.raw[0]);
00202                 }
00203                 return begin;
00204 
00205         case TSKFC_CATEGORIES:
00206                 {
00207                         std::string catstring = ParseFieldString(field);
00208                         if( ic )
00209                                 catstring = ic->FromBB(catstring);
00210                         Categories.CategoryStr2List(catstring);
00211                 }
00212                 return begin;
00213         }
00214         // base class handles recurring data
00215         if( RecurBase::ParseField(field->type, field->u.raw, btohs(field->size), ic) )
00216                 return begin;
00217 
00218         // if still not handled, add to the Unknowns list
00219         UnknownField uf;
00220         uf.type = field->type;
00221         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00222         Unknowns.push_back(uf);
00223 
00224         // return new pointer for next field
00225         return begin;
00226 }
00227 
00228 void Task::ParseHeader(const Data &data, size_t &offset)
00229 {
00230         // no header in Task records
00231 }
00232 
00233 void Task::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00234 {
00235         const unsigned char *finish = ParseCommonFields(*this,
00236                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00237         offset += finish - (data.GetData() + offset);
00238 }
00239 
00240 
00241 void Task::BuildHeader(Data &data, size_t &offset) const
00242 {
00243         // no header in Task records
00244 }
00245 
00246 
00247 //
00248 // Build
00249 //
00250 /// Build fields part of record.
00251 ///
00252 void Task::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00253 {
00254         data.Zap();
00255 
00256         // tack on the 't' task type field first
00257         BuildField(data, offset, TSKFC_TASK_TYPE, 't');
00258 
00259         BuildField(data, offset, TSKFC_STATUS, StatusRec2Proto(StatusFlag));
00260         BuildField(data, offset, TSKFC_PRIORITY, PriorityRec2Proto(PriorityFlag));
00261         BuildField(data, offset, TSKFC_ALARM_TYPE, AlarmRec2Proto(AlarmType));
00262 
00263         if ( DueDateFlag )
00264                 BuildField(data, offset, TSKFC_DUE_FLAG, (char) 1);
00265         else
00266                 BuildField(data, offset, TSKFC_DUE_FLAG, (char) 0);
00267 
00268         if( TimeZoneValid ) {
00269                 // the time zone code field is 4 bytes, but we only use
00270                 // the first two... pad it with zeros
00271                 uint32_t code = TimeZoneCode;
00272                 BuildField(data, offset, TSKFC_TIMEZONE_CODE, code);
00273         }
00274 
00275         // cycle through the type table
00276         for(    FieldLink<Task> *b = TaskFieldLinks;
00277                 b->type != TSKFC_END;
00278                 b++ )
00279         {
00280                 // print only fields with data
00281                 if( b->strMember ) {
00282                         const std::string &field = this->*(b->strMember);
00283                         if( field.size() ) {
00284                                 std::string s = (b->iconvNeeded && ic) ? ic->ToBB(field) : field;
00285                                 BuildField(data, offset, b->type, s);
00286                         }
00287                 }
00288                 else if( b->timeMember ) {
00289                         time_t t = this->*(b->timeMember);
00290                         if( t > 0 )
00291                                 BuildField1900(data, offset, b->type, t);
00292                 }
00293                 else if( b->postMember && b->postField ) {
00294                         const std::string &field = (this->*(b->postMember)).*(b->postField);
00295                         if( field.size() ) {
00296                                 std::string s = (b->iconvNeeded && ic) ? ic->ToBB(field) : field;
00297                                 BuildField(data, offset, b->type, s);
00298                         }
00299                 }
00300         }
00301 
00302         // Categories
00303         if( Categories.size() ) {
00304                 string store;
00305                 Categories.CategoryList2Str(store);
00306                 BuildField(data, offset, TSKFC_CATEGORIES, ic ? ic->ToBB(store) : store);
00307         }
00308 
00309         // and finally save unknowns
00310         UnknownsType::const_iterator
00311                 ub = Unknowns.begin(), ue = Unknowns.end();
00312         for( ; ub != ue; ub++ ) {
00313                 BuildField(data, offset, *ub);
00314         }
00315 
00316         data.ReleaseBuffer(offset);
00317 }
00318 
00319 
00320 
00321 void Task::Clear()
00322 {
00323         // clear the base class first
00324         RecurBase::Clear();
00325 
00326         // our variables...
00327         RecType = GetDefaultRecType();
00328         RecordId = 0;
00329 
00330         Summary.clear();
00331         Notes.clear();
00332         Categories.clear();
00333         UID.clear();
00334 
00335         StartTime = DueTime = AlarmTime = 0;
00336         TimeZoneCode = GetTimeZoneCode( 0, 0 ); // default to GMT
00337         TimeZoneValid = false;
00338 
00339         AlarmType = (AlarmFlagType)0;
00340         PriorityFlag = (PriorityFlagType)0;
00341         StatusFlag = (StatusFlagType)0;
00342 
00343         DueDateFlag = false;
00344 
00345         Unknowns.clear();
00346 }
00347 
00348 std::string Task::GetDescription() const
00349 {
00350         return Summary;
00351 }
00352 
00353 void Task::Dump(std::ostream &os) const
00354 {
00355         static const char *PriorityName[] = { "High", "Normal", "Low" };
00356         static const char *StatusName[] = { "Not Started", "In Progress",
00357                 "Completed", "Waiting", "Deferred" };
00358         static const char *DayNames[] = { "Sun", "Mon", "Tue", "Wed",
00359                 "Thu", "Fri", "Sat" };
00360         static const char *MonthNames[] = { "Jan", "Feb", "Mar", "Apr",
00361                 "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
00362         static const char *AlarmTypeName[] = { "None", "By Date", "Relative" };
00363 
00364         os << "Task entry: 0x" << setbase(16) << RecordId
00365            << " (" << (unsigned int)RecType << ")\n";
00366 
00367         // cycle through the type table
00368         for(    const FieldLink<Task> *b = TaskFieldLinks;
00369                 b->type != TSKFC_END;
00370                 b++ )
00371         {
00372                 if( b->strMember ) {
00373                         const std::string &s = this->*(b->strMember);
00374                         if( s.size() )
00375                                 os << "   " << b->name << ": " << s << "\n";
00376                 }
00377                 else if( b->timeMember ) {
00378                         time_t t = this->*(b->timeMember);
00379                         if( t > 0 )
00380                                 os << "   " << b->name << ": " << ctime(&t);
00381                 }
00382         }
00383 
00384         os << "   Due Date Flag: " << (DueDateFlag ? "true" : "false") << "\n";
00385         os << "   Priority: " << PriorityName[PriorityFlag] << "\n";
00386         os << "   Status: " << StatusName[StatusFlag] << "\n";
00387         if( AlarmType ) {
00388                 os << "   Alarm Type: " << AlarmTypeName[AlarmType] << "\n";
00389         }
00390         if( TimeZoneValid )
00391                 os << "   Time Zone: " << GetTimeZone(TimeZoneCode)->Name << "\n";
00392 
00393         // print recurrence data if available
00394         os << "   Recurring: " << (Recurring ? "yes" : "no") << "\n";
00395         if( Recurring ) {
00396                 switch( RecurringType )
00397                 {
00398                 case Day:
00399                         os << "      Every day.\n";
00400                         break;
00401 
00402                 case MonthByDate:
00403                         os << "      Every month on the "
00404                            << DayOfMonth
00405                            << (DayOfMonth == 1 ? "st" : "")
00406                            << (DayOfMonth == 2 ? "nd" : "")
00407                            << (DayOfMonth == 3 ? "rd" : "")
00408                            << (DayOfMonth > 3  ? "th" : "")
00409                            << "\n";
00410                         break;
00411 
00412                 case MonthByDay:
00413                         os << "      Every month on the "
00414                            << DayNames[DayOfWeek]
00415                            << " of week "
00416                            << WeekOfMonth
00417                            << "\n";
00418                         break;
00419 
00420                 case YearByDate:
00421                         os << "      Every year on "
00422                            << MonthNames[MonthOfYear-1]
00423                            << " " << DayOfMonth << "\n";
00424                         break;
00425 
00426                 case YearByDay:
00427                         os << "      Every year in " << MonthNames[MonthOfYear-1]
00428                            << " on "
00429                            << DayNames[DayOfWeek]
00430                            << " of week " << WeekOfMonth << "\n";
00431                         break;
00432 
00433                 case Week:
00434                         os << "      Every week on: ";
00435                         if( WeekDays & CAL_WD_SUN ) os << "Sun ";
00436                         if( WeekDays & CAL_WD_MON ) os << "Mon ";
00437                         if( WeekDays & CAL_WD_TUE ) os << "Tue ";
00438                         if( WeekDays & CAL_WD_WED ) os << "Wed ";
00439                         if( WeekDays & CAL_WD_THU ) os << "Thu ";
00440                         if( WeekDays & CAL_WD_FRI ) os << "Fri ";
00441                         if( WeekDays & CAL_WD_SAT ) os << "Sat ";
00442                         os << "\n";
00443                         break;
00444 
00445                 default:
00446                         os << "      Unknown recurrence type\n";
00447                         break;
00448                 }
00449 
00450                 os << "      Interval: " << Interval << "\n";
00451 
00452                 if( Perpetual )
00453                         os << "      Ends: never\n";
00454                 else
00455                         os << "      Ends: " << ctime(&RecurringEndTime);
00456         }
00457 
00458         if( Categories.size() ) {
00459                 string display;
00460                 Categories.CategoryList2Str(display);
00461                 os << "    Categories: " << display << "\n";
00462         }
00463 
00464         os << Unknowns;
00465         os << "\n\n";
00466 }
00467 
00468 bool Task::operator<(const Task &other) const
00469 {
00470         if( StartTime != other.StartTime )
00471                 return StartTime < other.StartTime;
00472         if( AlarmTime != other.AlarmTime )
00473                 return AlarmTime < other.AlarmTime;
00474 
00475         int cmp = Summary.compare(other.Summary);
00476         if( cmp == 0 )
00477                 cmp = Notes.compare(other.Notes);
00478         return cmp < 0;
00479 }
00480 
00481 } // namespace Barry
00482 

Generated on Tue Mar 1 17:50:16 2011 for Barry by  doxygen 1.5.6