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