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
00051
00052
00053
00054
00055
00056
00057 Calendar::FreeBusyFlagType Calendar::FreeBusyFlagProto2Rec(uint8_t f)
00058 {
00059 return (FreeBusyFlagType)f;
00060 }
00061
00062 uint8_t Calendar::FreeBusyFlagRec2Proto(FreeBusyFlagType f)
00063 {
00064 return f;
00065 }
00066
00067 Calendar::ClassFlagType Calendar::ClassFlagProto2Rec(uint8_t f)
00068 {
00069 return (ClassFlagType)f;
00070 }
00071
00072 uint8_t Calendar::ClassFlagRec2Proto(ClassFlagType f)
00073 {
00074 return f;
00075 }
00076
00077
00078
00079
00080
00081
00082
00083 #define CALFC_APPT_TYPE_FLAG 0x01
00084 #define CALFC_SUBJECT 0x02
00085 #define CALFC_NOTES 0x03
00086 #define CALFC_LOCATION 0x04
00087 #define CALFC_NOTIFICATION_TIME 0x05
00088 #define CALFC_START_TIME 0x06
00089 #define CALFC_END_TIME 0x07
00090 #define CALFC_ACCEPTED_BY 0x0b
00091 #define CALFC_VERSION_DATA 0x10
00092 #define CALFC_INVITED 0x15
00093 #define CALFC_ORGANIZER 0x16
00094 #define CALFC_NOTIFICATION_DATA 0x1a
00095 #define CALFC_FREEBUSY_FLAG 0x1c
00096 #define CALFC_TIMEZONE_CODE 0x1e // only seems to show up if recurring
00097 #define CALFC_CLASS_FLAG 0x28 // private flag from outlook
00098 #define CALFC_CALENDAR_ID 0x2b // Calendar using (new devices have several calendar)
00099 #define CALFC_ALLDAYEVENT_FLAG 0xff
00100 #define CALFC_END 0xffff
00101
00102 static FieldLink<Calendar> CalendarFieldLinks[] = {
00103 { CALFC_SUBJECT, "Subject", 0, 0, &Calendar::Subject, 0, 0, 0, 0, true },
00104 { CALFC_NOTES, "Notes", 0, 0, &Calendar::Notes, 0, 0, 0, 0, true },
00105 { CALFC_LOCATION, "Location", 0, 0, &Calendar::Location, 0, 0, 0, 0, true },
00106 { CALFC_NOTIFICATION_TIME,"Notification Time",0,0, 0, 0, &Calendar::NotificationTime, 0, 0, false },
00107 { CALFC_START_TIME, "Start Time", 0, 0, 0, 0, &Calendar::StartTime, 0, 0, false },
00108 { CALFC_END_TIME, "End Time", 0, 0, 0, 0, &Calendar::EndTime, 0, 0, false },
00109 { CALFC_ORGANIZER, "Organizer", 0, 0, 0, &Calendar::Organizer, 0, 0, 0, true },
00110 { CALFC_ACCEPTED_BY,"Accepted By",0, 0, 0, &Calendar::AcceptedBy, 0, 0, 0, true },
00111 { CALFC_INVITED, "Invited", 0, 0, 0, &Calendar::Invited, 0, 0, 0, true },
00112 { CALFC_END, "End of List",0, 0, 0, 0, 0, 0, 0, false }
00113 };
00114
00115 Calendar::Calendar()
00116 {
00117 Clear();
00118 }
00119
00120 Calendar::~Calendar()
00121 {
00122 }
00123
00124 const unsigned char* Calendar::ParseField(const unsigned char *begin,
00125 const unsigned char *end,
00126 const IConverter *ic)
00127 {
00128 const CommonField *field = (const CommonField *) begin;
00129
00130
00131 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00132 if( begin > end )
00133 return begin;
00134
00135 if( !btohs(field->size) )
00136 return begin;
00137
00138
00139 for( FieldLink<Calendar> *b = CalendarFieldLinks;
00140 b->type != CALFC_END;
00141 b++ )
00142 {
00143 if( b->type == field->type ) {
00144 if( b->strMember ) {
00145 std::string &s = this->*(b->strMember);
00146 s = ParseFieldString(field);
00147 if( b->iconvNeeded && ic )
00148 s = ic->FromBB(s);
00149 return begin;
00150 }
00151 else if( b->timeMember && btohs(field->size) == 4 ) {
00152 time_t &t = this->*(b->timeMember);
00153 dout("min1900: " << field->u.min1900);
00154 t = min2time(field->u.min1900);
00155 return begin;
00156 }
00157 else if( b->addrMember ) {
00158
00159
00160
00161
00162
00163
00164 std::string dual((const char*)field->u.raw, btohs(field->size));
00165
00166 EmailAddress a;
00167
00168
00169
00170
00171 a.Email = dual.c_str();
00172
00173
00174
00175 a.Name = dual.c_str() + a.Email.size() + 1;
00176
00177
00178 if( a.size() ) {
00179
00180 if( b->iconvNeeded && ic ) {
00181 a.Name = ic->FromBB(a.Name);
00182 a.Email = ic->FromBB(a.Email);
00183 }
00184
00185 EmailAddressList &al = this->*(b->addrMember);
00186 al.push_back(a);
00187 }
00188
00189 return begin;
00190 }
00191 }
00192 }
00193
00194
00195 switch( field->type )
00196 {
00197 case CALFC_APPT_TYPE_FLAG:
00198 switch( field->u.raw[0] )
00199 {
00200 case 'a':
00201 Recurring = false;
00202 return begin;
00203
00204 case '*':
00205 Recurring = true;
00206 return begin;
00207
00208 default:
00209 throw Error("Calendar::ParseField: unknown appointment type");
00210 }
00211 break;
00212
00213 case CALFC_ALLDAYEVENT_FLAG:
00214 AllDayEvent = field->u.raw[0] == 1;
00215 return begin;
00216
00217 case CALFC_TIMEZONE_CODE:
00218 if( btohs(field->size) == 2 ) {
00219
00220 TimeZoneCode = btohs(field->u.code);
00221 TimeZoneValid = true;
00222 }
00223 else {
00224 throw Error("Calendar::ParseField: not enough data in time zone code field");
00225 }
00226 return begin;
00227
00228 case CALFC_FREEBUSY_FLAG:
00229 if( field->u.raw[0] > CR_FREEBUSY_RANGE_HIGH ) {
00230 throw Error("Calendar::ParseField: FreeBusyFlag out of range" );
00231 }
00232 FreeBusyFlag = FreeBusyFlagProto2Rec(field->u.raw[0]);
00233 return begin;
00234
00235 case CALFC_CALENDAR_ID:
00236 if( btohs(field->size) == 8 ) {
00237 CalendarID = btohll(field->u.uint64);
00238 }
00239 else {
00240 throw Error("Calendar::ParseField: size data unknown in calendar field");
00241 }
00242 return begin;
00243
00244 case CALFC_CLASS_FLAG:
00245 if( field->u.raw[0] > CR_CLASS_RANGE_HIGH ) {
00246 throw Error("Calendar::ParseField: ClassFlag out of range" );
00247 }
00248 ClassFlag = ClassFlagProto2Rec(field->u.raw[0]);
00249 return begin;
00250 }
00251
00252
00253 if( RecurBase::ParseField(field->type, field->u.raw, btohs(field->size), ic) )
00254 return begin;
00255
00256
00257 UnknownField uf;
00258 uf.type = field->type;
00259 uf.data.assign((const char*)field->u.raw, btohs(field->size));
00260 Unknowns.push_back(uf);
00261
00262
00263 return begin;
00264 }
00265
00266 void Calendar::ParseHeader(const Data &data, size_t &offset)
00267 {
00268
00269 }
00270
00271 void Calendar::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00272 {
00273 const unsigned char *finish = ParseCommonFields(*this,
00274 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00275 offset += finish - (data.GetData() + offset);
00276 }
00277
00278 void Calendar::BuildHeader(Data &data, size_t &offset) const
00279 {
00280
00281 }
00282
00283
00284
00285
00286
00287
00288 void Calendar::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00289 {
00290 data.Zap();
00291
00292
00293 BuildField(data, offset, CALFC_APPT_TYPE_FLAG, Recurring ? '*' : 'a');
00294
00295
00296 if( AllDayEvent )
00297 BuildField(data, offset, CALFC_ALLDAYEVENT_FLAG, (char)1);
00298
00299
00300 for( const FieldLink<Calendar> *b = CalendarFieldLinks;
00301 b->type != CALFC_END;
00302 b++ )
00303 {
00304 if( b->strMember ) {
00305 const std::string &s = this->*(b->strMember);
00306 if( s.size() )
00307 BuildField(data, offset, b->type, (b->iconvNeeded && ic) ? ic->ToBB(s) : s);
00308 }
00309 else if( b->timeMember ) {
00310 time_t t = this->*(b->timeMember);
00311 if( t > 0 )
00312 BuildField1900(data, offset, b->type, t);
00313 }
00314 else if( b->addrMember ) {
00315 const EmailAddressList &al = this->*(b->addrMember);
00316 EmailAddressList::const_iterator lb = al.begin(), le = al.end();
00317
00318
00319 for( ; lb != le; ++lb ) {
00320
00321
00322 if( !lb->size() )
00323 continue;
00324
00325 std::string Name = lb->Name,
00326 Email = lb->Email;
00327
00328
00329 if( b->iconvNeeded && ic ) {
00330 Name = ic->ToBB(Name);
00331 Email = ic->ToBB(Email);
00332 }
00333
00334
00335
00336
00337
00338
00339
00340 std::string field(lb->Email.c_str(), lb->Email.size() + 1);
00341 field.append(lb->Name.c_str(), lb->Name.size() + 1);
00342 BuildField(data, offset, b->type, field.data(), field.size());
00343 }
00344 }
00345 }
00346
00347
00348 if( Recurring ) {
00349 CalendarRecurrenceDataField recur;
00350 BuildRecurrenceData(StartTime, &recur);
00351 BuildField(data, offset, RecurBase::RecurringFieldType(),
00352 &recur, CALENDAR_RECURRENCE_DATA_FIELD_SIZE);
00353 }
00354
00355 if( TimeZoneValid )
00356 BuildField(data, offset, CALFC_TIMEZONE_CODE, TimeZoneCode);
00357
00358 BuildField(data, offset, CALFC_FREEBUSY_FLAG, FreeBusyFlagRec2Proto(FreeBusyFlag));
00359 BuildField(data, offset, CALFC_CLASS_FLAG, ClassFlagRec2Proto(ClassFlag));
00360
00361
00362
00363 if( CalendarID != (uint64_t) -1 )
00364 BuildField(data, offset, CALFC_CALENDAR_ID, CalendarID);
00365
00366
00367 UnknownsType::const_iterator
00368 ub = Unknowns.begin(), ue = Unknowns.end();
00369 for( ; ub != ue; ub++ ) {
00370 BuildField(data, offset, *ub);
00371 }
00372
00373 data.ReleaseBuffer(offset);
00374 }
00375
00376 void Calendar::Clear()
00377 {
00378
00379 RecurBase::Clear();
00380
00381
00382 RecType = GetDefaultRecType();
00383 RecordId = 0;
00384
00385 AllDayEvent = false;
00386 Subject.clear();
00387 Notes.clear();
00388 Location.clear();
00389 NotificationTime = StartTime = EndTime = 0;
00390 Organizer.clear();
00391 AcceptedBy.clear();
00392 Invited.clear();
00393
00394 FreeBusyFlag = Free;
00395 ClassFlag = Public;
00396
00397 CalendarID = btohll((uint64_t) -1);
00398
00399 TimeZoneCode = GetTimeZoneCode(0, 0);
00400 TimeZoneValid = false;
00401
00402 Unknowns.clear();
00403 }
00404
00405 std::string Calendar::GetDescription() const
00406 {
00407 return Subject;
00408 }
00409
00410 void Calendar::DumpSpecialFields(std::ostream &os) const
00411 {
00412 static const char *ClassTypes[] = { "Public", "Confidential", "Private" };
00413 static const char *FreeBusy[] = { "Free", "Tentative", "Busy", "Out of Office" };
00414
00415 os << " Calendar ID: 0x" << setbase(16) << CalendarID << "\n";
00416 os << " All Day Event: " << (AllDayEvent ? "yes" : "no") << "\n";
00417 os << " Class: " << ClassTypes[ClassFlag] << "\n";
00418 os << " Free/Busy: " << FreeBusy[FreeBusyFlag] << "\n";
00419 if( TimeZoneValid )
00420 os << " Time Zone: " << GetTimeZone(TimeZoneCode)->Name << "\n";
00421 }
00422
00423 void Calendar::Dump(std::ostream &os) const
00424 {
00425
00426
00427
00428
00429
00430 os << "Calendar entry: 0x" << setbase(16) << RecordId
00431 << " (" << (unsigned int)RecType << ")\n";
00432 DumpSpecialFields(os);
00433
00434
00435 for( const FieldLink<Calendar> *b = CalendarFieldLinks;
00436 b->type != CALFC_END;
00437 b++ )
00438 {
00439 if( b->strMember ) {
00440 const std::string &s = this->*(b->strMember);
00441 if( s.size() )
00442 os << " " << b->name << ": " << s << "\n";
00443 }
00444 else if( b->timeMember ) {
00445 time_t t = this->*(b->timeMember);
00446 if( t > 0 )
00447 os << " " << b->name << ": " << ctime(&t);
00448 else
00449 os << " " << b->name << ": disabled\n";
00450 }
00451 else if( b->addrMember ) {
00452 const EmailAddressList &al = this->*(b->addrMember);
00453 EmailAddressList::const_iterator lb = al.begin(), le = al.end();
00454
00455 for( ; lb != le; ++lb ) {
00456 if( !lb->size() )
00457 continue;
00458
00459 os << " " << b->name << ": " << *lb << "\n";
00460 }
00461 }
00462 }
00463
00464
00465 RecurBase::Dump(os);
00466
00467
00468 os << Unknowns;
00469 }
00470
00471 bool Calendar::operator<(const Calendar &other) const
00472 {
00473 if( StartTime < other.StartTime )
00474 return true;
00475 else if( StartTime > other.StartTime )
00476 return false;
00477
00478 int cmp = Subject.compare(other.Subject);
00479 if( cmp == 0 )
00480 cmp = Location.compare(other.Location);
00481 return cmp < 0;
00482 }
00483
00484
00485
00486
00487
00488
00489 #define CALALLFC_CALENDAR_ID 0x02 // Calendar using (new devices have several calendar)
00490 #define CALALLFC_MAIL_ACCOUNT 0x03
00491 #define CALALLFC_UNIQUEID 0x05
00492 #define CALALLFC_CAL_OBJECT 0x0a
00493 #define CALALLFC_END 0xffff
00494
00495 void CalendarAll::Clear()
00496 {
00497 Calendar::Clear();
00498
00499 MailAccount.clear();
00500 }
00501
00502 void CalendarAll::ParseHeader(const Data &data, size_t &offset)
00503 {
00504 const unsigned char *b = (const unsigned char*) (data.GetData() + offset);
00505 const unsigned char *e = (const unsigned char*) (data.GetData() + data.GetSize());
00506
00507 while( (b + COMMON_FIELD_HEADER_SIZE) < e ) {
00508 const CommonField *field = (const CommonField *) b;
00509
00510
00511 b += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00512 if( b > e )
00513 continue;
00514
00515 if( !btohs(field->size) )
00516 continue;
00517
00518
00519 if( field->type == CALALLFC_CAL_OBJECT )
00520 {
00521 b -= btohs(field->size);
00522
00523 break;
00524 }
00525
00526 switch( field->type )
00527 {
00528 case CALALLFC_CALENDAR_ID:
00529 if( btohs(field->size) == 8 ) {
00530 CalendarID = btohll(field->u.uint64);
00531 }
00532 else {
00533 throw Error("CalendarAll::ParseField: size data unknown in calendar field");
00534 }
00535 continue;
00536
00537 case CALALLFC_MAIL_ACCOUNT:
00538 MailAccount = ParseFieldString(field);
00539 continue;
00540
00541 case CALALLFC_UNIQUEID:
00542 if( btohs(field->size) == 4 ) {
00543 RecordId = btohl(field->u.uint32);
00544 }
00545 else {
00546 throw Error("CalendarAll::ParseHeader: size data unknown in calendar field");
00547 }
00548 continue;
00549 }
00550
00551
00552 UnknownField uf;
00553 uf.type = field->type;
00554 uf.data.assign((const char*)field->u.raw, btohs(field->size));
00555 Unknowns.push_back(uf);
00556 }
00557
00558 offset += b - (data.GetData() + offset);
00559 }
00560
00561 void CalendarAll::DumpSpecialFields(std::ostream &os) const
00562 {
00563 Calendar::DumpSpecialFields(os);
00564 os << " Mail Account: " << MailAccount << "\n";
00565 }
00566
00567 }
00568