00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "r_calendar.h"
00023 #include "record-internal.h"
00024 #include "protocol.h"
00025 #include "protostructs.h"
00026 #include "data.h"
00027 #include "time.h"
00028 #include "error.h"
00029 #include "endian.h"
00030 #include <ostream>
00031 #include <iomanip>
00032 #include <time.h>
00033 #include <string.h>
00034 #include <stdexcept>
00035
00036 #define __DEBUG_MODE__
00037 #include "debug.h"
00038
00039 using namespace std;
00040 using namespace Barry::Protocol;
00041
00042 namespace Barry {
00043
00044
00045
00046
00047
00048
00049 #define CALFC_APPT_TYPE_FLAG 0x01
00050 #define CALFC_SUBJECT 0x02
00051 #define CALFC_NOTES 0x03
00052 #define CALFC_LOCATION 0x04
00053 #define CALFC_NOTIFICATION_TIME 0x05
00054 #define CALFC_START_TIME 0x06
00055 #define CALFC_END_TIME 0x07
00056 #define CALFC_RECURRENCE_DATA 0x0c
00057 #define CALFC_VERSION_DATA 0x10
00058 #define CALFC_NOTIFICATION_DATA 0x1a
00059 #define CALFC_FREEBUSY_FLAG 0x1c
00060 #define CALFC_TIMEZONE_CODE 0x1e // only seems to show up if recurring
00061 #define CALFC_CLASS_FLAG 0x28 // private flag from outlook
00062 #define CALFC_ALLDAYEVENT_FLAG 0xff
00063 #define CALFC_END 0xffff
00064
00065 FieldLink<Calendar> CalendarFieldLinks[] = {
00066 { CALFC_SUBJECT, "Subject", 0, 0, &Calendar::Subject, 0, 0 },
00067 { CALFC_NOTES, "Notes", 0, 0, &Calendar::Notes, 0, 0 },
00068 { CALFC_LOCATION, "Location", 0, 0, &Calendar::Location, 0, 0 },
00069 { CALFC_NOTIFICATION_TIME,"Notification Time",0,0, 0, 0, &Calendar::NotificationTime },
00070 { CALFC_START_TIME, "Start Time", 0, 0, 0, 0, &Calendar::StartTime },
00071 { CALFC_END_TIME, "End Time", 0, 0, 0, 0, &Calendar::EndTime },
00072 { CALFC_END, "End of List",0, 0, 0, 0, 0 }
00073 };
00074
00075 Calendar::Calendar()
00076 {
00077 Clear();
00078 }
00079
00080 Calendar::~Calendar()
00081 {
00082 }
00083
00084 const unsigned char* Calendar::ParseField(const unsigned char *begin,
00085 const unsigned char *end)
00086 {
00087 const CommonField *field = (const CommonField *) begin;
00088
00089
00090 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00091 if( begin > end )
00092 return begin;
00093
00094 if( !btohs(field->size) )
00095 return begin;
00096
00097
00098 for( FieldLink<Calendar> *b = CalendarFieldLinks;
00099 b->type != CALFC_END;
00100 b++ )
00101 {
00102 if( b->type == field->type ) {
00103 if( b->strMember ) {
00104 std::string &s = this->*(b->strMember);
00105 s = ParseFieldString(field);
00106 return begin;
00107 }
00108 else if( b->timeMember && btohs(field->size) == 4 ) {
00109 time_t &t = this->*(b->timeMember);
00110 dout("min1900: " << field->u.min1900);
00111 t = min2time(field->u.min1900);
00112 return begin;
00113 }
00114 }
00115 }
00116
00117
00118 switch( field->type )
00119 {
00120 case CALFC_APPT_TYPE_FLAG:
00121 switch( field->u.raw[0] )
00122 {
00123 case 'a':
00124 Recurring = false;
00125 return begin;
00126
00127 case '*':
00128 Recurring = true;
00129 return begin;
00130
00131 default:
00132 throw Error("Calendar::ParseField: unknown appointment type");
00133 }
00134 break;
00135
00136 case CALFC_ALLDAYEVENT_FLAG:
00137 AllDayEvent = field->u.raw[0] == 1;
00138 return begin;
00139
00140 case CALFC_RECURRENCE_DATA:
00141 if( btohs(field->size) >= CALENDAR_RECURRENCE_DATA_FIELD_SIZE ) {
00142
00143 ParseRecurrenceData(&field->u.raw[0]);
00144 }
00145 else {
00146
00147 throw Error("Calendar::ParseField: not enough data in recurrence data field");
00148 }
00149 return begin;
00150
00151 case CALFC_TIMEZONE_CODE:
00152 if( btohs(field->size) == 2 ) {
00153
00154 TimeZoneCode = btohs(field->u.code);
00155 }
00156 else {
00157 throw Error("Calendar::ParseField: not enough data in time zone code field");
00158 }
00159 return begin;
00160
00161 case CALFC_FREEBUSY_FLAG:
00162 FreeBusyFlag = (FreeBusyFlagType)field->u.raw[0];
00163 if( FreeBusyFlag > OutOfOffice ) {
00164 throw Error("Calendar::ParseField: FreeBusyFlag out of range" );
00165 }
00166 return begin;
00167
00168 case CALFC_CLASS_FLAG:
00169 ClassFlag = (ClassFlagType)field->u.raw[0];
00170 if( ClassFlag > Private ) {
00171 throw Error("Calendar::ParseField: ClassFlag out of range" );
00172 }
00173 return begin;
00174 }
00175
00176
00177 UnknownField uf;
00178 uf.type = field->type;
00179 uf.data.assign((const char*)field->u.raw, btohs(field->size));
00180 Unknowns.push_back(uf);
00181
00182
00183 return begin;
00184 }
00185
00186
00187 void Calendar::ParseRecurrenceData(const void *data)
00188 {
00189 const CalendarRecurrenceDataField *rec =
00190 (const CalendarRecurrenceDataField*) data;
00191
00192 Interval = btohs(rec->interval);
00193 if( Interval < 1 )
00194 Interval = 1;
00195
00196 if( rec->endTime == 0xffffffff ) {
00197 Perpetual = true;
00198 }
00199 else {
00200 RecurringEndTime = min2time(rec->endTime);
00201 Perpetual = false;
00202 }
00203
00204 switch( rec->type )
00205 {
00206 case CRDF_TYPE_DAY:
00207 RecurringType = Day;
00208
00209 break;
00210
00211 case CRDF_TYPE_MONTH_BY_DATE:
00212 RecurringType = MonthByDate;
00213 DayOfMonth = rec->u.month_by_date.monthDay;
00214 break;
00215
00216 case CRDF_TYPE_MONTH_BY_DAY:
00217 RecurringType = MonthByDay;
00218 DayOfWeek = rec->u.month_by_day.weekDay;
00219 WeekOfMonth = rec->u.month_by_day.week;
00220 break;
00221
00222 case CRDF_TYPE_YEAR_BY_DATE:
00223 RecurringType = YearByDate;
00224 DayOfMonth = rec->u.year_by_date.monthDay;
00225 MonthOfYear = rec->u.year_by_date.month;
00226 break;
00227
00228 case CRDF_TYPE_YEAR_BY_DAY:
00229 RecurringType = YearByDay;
00230 DayOfWeek = rec->u.year_by_day.weekDay;
00231 WeekOfMonth = rec->u.year_by_day.week;
00232 MonthOfYear = rec->u.year_by_day.month;
00233 break;
00234
00235 case CRDF_TYPE_WEEK:
00236 RecurringType = Week;
00237
00238
00239
00240
00241 WeekDays = rec->u.week.days;
00242 break;
00243
00244 default:
00245 eout("Unknown recurrence data type: " << rec->type);
00246 throw Error("Unknown recurrence data type");
00247 }
00248 }
00249
00250
00251
00252 void Calendar::BuildRecurrenceData(void *data) const
00253 {
00254 if( !Recurring )
00255 throw Error("Calendar::BuildRecurrenceData: Attempting to build recurrence data on non-recurring record.");
00256
00257 CalendarRecurrenceDataField *rec = (CalendarRecurrenceDataField*) data;
00258
00259
00260 memset(data, 0, CALENDAR_RECURRENCE_DATA_FIELD_SIZE);
00261
00262 rec->interval = htobs(Interval);
00263 rec->startTime = time2min(StartTime);
00264 if( Perpetual )
00265 rec->endTime = 0xffffffff;
00266 else
00267 rec->endTime = time2min(RecurringEndTime);
00268
00269 switch( RecurringType )
00270 {
00271 case Day:
00272 rec->type = CRDF_TYPE_DAY;
00273
00274 break;
00275
00276 case MonthByDate:
00277 rec->type = CRDF_TYPE_MONTH_BY_DATE;
00278 rec->u.month_by_date.monthDay = DayOfMonth;
00279 break;
00280
00281 case MonthByDay:
00282 rec->type = CRDF_TYPE_MONTH_BY_DAY;
00283 rec->u.month_by_day.weekDay = DayOfWeek;
00284 rec->u.month_by_day.week = WeekOfMonth;
00285 break;
00286
00287 case YearByDate:
00288 rec->type = CRDF_TYPE_YEAR_BY_DATE;
00289 rec->u.year_by_date.monthDay = DayOfMonth;
00290 rec->u.year_by_date.month = MonthOfYear;
00291 break;
00292
00293 case YearByDay:
00294 rec->type = CRDF_TYPE_YEAR_BY_DAY;
00295 rec->u.year_by_day.weekDay = DayOfWeek;
00296 rec->u.year_by_day.week = WeekOfMonth;
00297 rec->u.year_by_day.month = MonthOfYear;
00298 break;
00299
00300 case Week:
00301 rec->type = CRDF_TYPE_WEEK;
00302
00303
00304
00305
00306 rec->u.week.days = WeekDays;
00307 break;
00308
00309 default:
00310 eout("Calendar::BuildRecurrenceData: "
00311 "Unknown recurrence data type: " << rec->type);
00312 throw Error("Calendar::BuildRecurrenceData: Unknown recurrence data type");
00313 }
00314 }
00315
00316 void Calendar::ParseHeader(const Data &data, size_t &offset)
00317 {
00318
00319 }
00320
00321 void Calendar::ParseFields(const Data &data, size_t &offset)
00322 {
00323 const unsigned char *finish = ParseCommonFields(*this,
00324 data.GetData() + offset, data.GetData() + data.GetSize());
00325 offset += finish - (data.GetData() + offset);
00326 }
00327
00328 void Calendar::BuildHeader(Data &data, size_t &offset) const
00329 {
00330
00331 }
00332
00333
00334
00335
00336
00337
00338 void Calendar::BuildFields(Data &data, size_t &offset) const
00339 {
00340 data.Zap();
00341
00342
00343 BuildField(data, offset, CALFC_APPT_TYPE_FLAG, Recurring ? '*' : 'a');
00344
00345
00346 if( AllDayEvent )
00347 BuildField(data, offset, CALFC_ALLDAYEVENT_FLAG, (char)1);
00348
00349
00350 for( const FieldLink<Calendar> *b = CalendarFieldLinks;
00351 b->type != CALFC_END;
00352 b++ )
00353 {
00354 if( b->strMember ) {
00355 const std::string &s = this->*(b->strMember);
00356 if( s.size() )
00357 BuildField(data, offset, b->type, s);
00358 }
00359 else if( b->timeMember ) {
00360 time_t t = this->*(b->timeMember);
00361 if( t > 0 )
00362 BuildField1900(data, offset, b->type, t);
00363 }
00364 }
00365
00366
00367
00368 if( Recurring ) {
00369 CalendarRecurrenceDataField recur;
00370 BuildRecurrenceData(&recur);
00371 BuildField(data, offset, CALFC_RECURRENCE_DATA,
00372 &recur, CALENDAR_RECURRENCE_DATA_FIELD_SIZE);
00373 }
00374
00375 if( TimeZoneValid )
00376 BuildField(data, offset, CALFC_TIMEZONE_CODE, TimeZoneCode);
00377
00378 BuildField(data, offset, CALFC_FREEBUSY_FLAG, (char)FreeBusyFlag);
00379 BuildField(data, offset, CALFC_CLASS_FLAG, (char)ClassFlag);
00380
00381
00382 UnknownsType::const_iterator
00383 ub = Unknowns.begin(), ue = Unknowns.end();
00384 for( ; ub != ue; ub++ ) {
00385 BuildField(data, offset, *ub);
00386 }
00387
00388 data.ReleaseBuffer(offset);
00389 }
00390
00391 void Calendar::Clear()
00392 {
00393 RecType = Calendar::GetDefaultRecType();
00394
00395 AllDayEvent = false;
00396 Subject.clear();
00397 Notes.clear();
00398 Location.clear();
00399 NotificationTime = StartTime = EndTime = 0;
00400
00401 FreeBusyFlag = Free;
00402 ClassFlag = Public;
00403
00404 Recurring = false;
00405 RecurringType = Calendar::Week;
00406 Interval = 1;
00407 RecurringEndTime = 0;
00408 Perpetual = false;
00409 TimeZoneCode = GetTimeZoneCode(0, 0);
00410 TimeZoneValid = false;
00411 DayOfWeek = WeekOfMonth = DayOfMonth = MonthOfYear = 0;
00412 WeekDays = 0;
00413
00414 Unknowns.clear();
00415 }
00416
00417 void Calendar::Dump(std::ostream &os) const
00418 {
00419 static const char *DayNames[] = { "Sun", "Mon", "Tue", "Wed",
00420 "Thu", "Fri", "Sat" };
00421 static const char *MonthNames[] = { "Jan", "Feb", "Mar", "Apr",
00422 "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
00423 static const char *ClassTypes[] = { "Public", "Confidential", "Private" };
00424 static const char *FreeBusy[] = { "Free", "Tentative", "Busy", "Out of Office" };
00425
00426
00427
00428
00429
00430 os << "Calendar entry: 0x" << setbase(16) << RecordId
00431 << " (" << (unsigned int)RecType << ")\n";
00432 os << " All Day Event: " << (AllDayEvent ? "yes" : "no") << "\n";
00433 os << " Class: " << ClassTypes[ClassFlag] << "\n";
00434 os << " Free/Busy: " << FreeBusy[FreeBusyFlag] << "\n";
00435 if( TimeZoneValid )
00436 os << " Time Zone: " << GetTimeZone(TimeZoneCode)->Name << "\n";
00437
00438
00439 for( const FieldLink<Calendar> *b = CalendarFieldLinks;
00440 b->type != CALFC_END;
00441 b++ )
00442 {
00443 if( b->strMember ) {
00444 const std::string &s = this->*(b->strMember);
00445 if( s.size() )
00446 os << " " << b->name << ": " << s << "\n";
00447 }
00448 else if( b->timeMember ) {
00449 time_t t = this->*(b->timeMember);
00450 if( t > 0 )
00451 os << " " << b->name << ": " << ctime(&t);
00452 else
00453 os << " " << b->name << ": disabled\n";
00454 }
00455 }
00456
00457
00458 os << " Recurring: " << (Recurring ? "yes" : "no") << "\n";
00459 if( Recurring ) {
00460 switch( RecurringType )
00461 {
00462 case Day:
00463 os << " Every day.\n";
00464 break;
00465
00466 case MonthByDate:
00467 os << " Every month on the "
00468 << DayOfMonth
00469 << (DayOfMonth == 1 ? "st" : "")
00470 << (DayOfMonth == 2 ? "nd" : "")
00471 << (DayOfMonth == 3 ? "rd" : "")
00472 << (DayOfMonth > 3 ? "th" : "")
00473 << "\n";
00474 break;
00475
00476 case MonthByDay:
00477 os << " Every month on the "
00478 << DayNames[DayOfWeek]
00479 << " of week "
00480 << WeekOfMonth
00481 << "\n";
00482 break;
00483
00484 case YearByDate:
00485 os << " Every year on "
00486 << MonthNames[MonthOfYear-1]
00487 << " " << DayOfMonth << "\n";
00488 break;
00489
00490 case YearByDay:
00491 os << " Every year in " << MonthNames[MonthOfYear-1]
00492 << " on "
00493 << DayNames[DayOfWeek]
00494 << " of week " << WeekOfMonth << "\n";
00495 break;
00496
00497 case Week:
00498 os << " Every week on: ";
00499 if( WeekDays & CAL_WD_SUN ) os << "Sun ";
00500 if( WeekDays & CAL_WD_MON ) os << "Mon ";
00501 if( WeekDays & CAL_WD_TUE ) os << "Tue ";
00502 if( WeekDays & CAL_WD_WED ) os << "Wed ";
00503 if( WeekDays & CAL_WD_THU ) os << "Thu ";
00504 if( WeekDays & CAL_WD_FRI ) os << "Fri ";
00505 if( WeekDays & CAL_WD_SAT ) os << "Sat ";
00506 os << "\n";
00507 break;
00508
00509 default:
00510 os << " Unknown recurrence type\n";
00511 break;
00512 }
00513
00514 os << " Interval: " << Interval << "\n";
00515
00516 if( Perpetual )
00517 os << " Ends: never\n";
00518 else
00519 os << " Ends: "
00520 << ctime(&RecurringEndTime);
00521 }
00522
00523
00524 os << Unknowns;
00525 }
00526
00527
00528 }
00529