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_ALLDAYEVENT_FLAG 0xff
00099 #define CALFC_END 0xffff
00100
00101 static FieldLink<Calendar> CalendarFieldLinks[] = {
00102 { CALFC_SUBJECT, "Subject", 0, 0, &Calendar::Subject, 0, 0, 0, 0, true },
00103 { CALFC_NOTES, "Notes", 0, 0, &Calendar::Notes, 0, 0, 0, 0, true },
00104 { CALFC_LOCATION, "Location", 0, 0, &Calendar::Location, 0, 0, 0, 0, true },
00105 { CALFC_NOTIFICATION_TIME,"Notification Time",0,0, 0, 0, &Calendar::NotificationTime, 0, 0, false },
00106 { CALFC_START_TIME, "Start Time", 0, 0, 0, 0, &Calendar::StartTime, 0, 0, false },
00107 { CALFC_END_TIME, "End Time", 0, 0, 0, 0, &Calendar::EndTime, 0, 0, false },
00108 { CALFC_ORGANIZER, "Organizer", 0, 0, 0, &Calendar::Organizer, 0, 0, 0, true },
00109 { CALFC_ACCEPTED_BY,"Accepted By",0, 0, 0, &Calendar::AcceptedBy, 0, 0, 0, true },
00110 { CALFC_INVITED, "Invited", 0, 0, 0, &Calendar::Invited, 0, 0, 0, true },
00111 { CALFC_END, "End of List",0, 0, 0, 0, 0, 0, 0, false }
00112 };
00113
00114 Calendar::Calendar()
00115 {
00116 Clear();
00117 }
00118
00119 Calendar::~Calendar()
00120 {
00121 }
00122
00123 const unsigned char* Calendar::ParseField(const unsigned char *begin,
00124 const unsigned char *end,
00125 const IConverter *ic)
00126 {
00127 const CommonField *field = (const CommonField *) begin;
00128
00129
00130 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00131 if( begin > end )
00132 return begin;
00133
00134 if( !btohs(field->size) )
00135 return begin;
00136
00137
00138 for( FieldLink<Calendar> *b = CalendarFieldLinks;
00139 b->type != CALFC_END;
00140 b++ )
00141 {
00142 if( b->type == field->type ) {
00143 if( b->strMember ) {
00144 std::string &s = this->*(b->strMember);
00145 s = ParseFieldString(field);
00146 if( b->iconvNeeded && ic )
00147 s = ic->FromBB(s);
00148 return begin;
00149 }
00150 else if( b->timeMember && btohs(field->size) == 4 ) {
00151 time_t &t = this->*(b->timeMember);
00152 dout("min1900: " << field->u.min1900);
00153 t = min2time(field->u.min1900);
00154 return begin;
00155 }
00156 else if( b->addrMember ) {
00157
00158
00159
00160
00161
00162
00163 std::string dual((const char*)field->u.raw, btohs(field->size));
00164
00165 EmailAddress a;
00166
00167
00168
00169
00170 a.Email = dual.c_str();
00171
00172
00173
00174 a.Name = dual.c_str() + a.Email.size() + 1;
00175
00176
00177 if( a.size() ) {
00178
00179 if( b->iconvNeeded && ic ) {
00180 a.Name = ic->FromBB(a.Name);
00181 a.Email = ic->FromBB(a.Email);
00182 }
00183
00184 EmailAddressList &al = this->*(b->addrMember);
00185 al.push_back(a);
00186 }
00187
00188 return begin;
00189 }
00190 }
00191 }
00192
00193
00194 switch( field->type )
00195 {
00196 case CALFC_APPT_TYPE_FLAG:
00197 switch( field->u.raw[0] )
00198 {
00199 case 'a':
00200 Recurring = false;
00201 return begin;
00202
00203 case '*':
00204 Recurring = true;
00205 return begin;
00206
00207 default:
00208 throw Error("Calendar::ParseField: unknown appointment type");
00209 }
00210 break;
00211
00212 case CALFC_ALLDAYEVENT_FLAG:
00213 AllDayEvent = field->u.raw[0] == 1;
00214 return begin;
00215
00216 case CALFC_TIMEZONE_CODE:
00217 if( btohs(field->size) == 2 ) {
00218
00219 TimeZoneCode = btohs(field->u.code);
00220 TimeZoneValid = true;
00221 }
00222 else {
00223 throw Error("Calendar::ParseField: not enough data in time zone code field");
00224 }
00225 return begin;
00226
00227 case CALFC_FREEBUSY_FLAG:
00228 if( field->u.raw[0] > CR_FREEBUSY_RANGE_HIGH ) {
00229 throw Error("Calendar::ParseField: FreeBusyFlag out of range" );
00230 }
00231 FreeBusyFlag = FreeBusyFlagProto2Rec(field->u.raw[0]);
00232 return begin;
00233
00234 case CALFC_CLASS_FLAG:
00235 if( field->u.raw[0] > CR_CLASS_RANGE_HIGH ) {
00236 throw Error("Calendar::ParseField: ClassFlag out of range" );
00237 }
00238 ClassFlag = ClassFlagProto2Rec(field->u.raw[0]);
00239 return begin;
00240 }
00241
00242
00243 if( RecurBase::ParseField(field->type, field->u.raw, btohs(field->size), ic) )
00244 return begin;
00245
00246
00247 UnknownField uf;
00248 uf.type = field->type;
00249 uf.data.assign((const char*)field->u.raw, btohs(field->size));
00250 Unknowns.push_back(uf);
00251
00252
00253 return begin;
00254 }
00255
00256 void Calendar::ParseHeader(const Data &data, size_t &offset)
00257 {
00258
00259 }
00260
00261 void Calendar::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00262 {
00263 const unsigned char *finish = ParseCommonFields(*this,
00264 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00265 offset += finish - (data.GetData() + offset);
00266 }
00267
00268 void Calendar::BuildHeader(Data &data, size_t &offset) const
00269 {
00270
00271 }
00272
00273
00274
00275
00276
00277
00278 void Calendar::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00279 {
00280 data.Zap();
00281
00282
00283 BuildField(data, offset, CALFC_APPT_TYPE_FLAG, Recurring ? '*' : 'a');
00284
00285
00286 if( AllDayEvent )
00287 BuildField(data, offset, CALFC_ALLDAYEVENT_FLAG, (char)1);
00288
00289
00290 for( const FieldLink<Calendar> *b = CalendarFieldLinks;
00291 b->type != CALFC_END;
00292 b++ )
00293 {
00294 if( b->strMember ) {
00295 const std::string &s = this->*(b->strMember);
00296 if( s.size() )
00297 BuildField(data, offset, b->type, (b->iconvNeeded && ic) ? ic->ToBB(s) : s);
00298 }
00299 else if( b->timeMember ) {
00300 time_t t = this->*(b->timeMember);
00301 if( t > 0 )
00302 BuildField1900(data, offset, b->type, t);
00303 }
00304 else if( b->addrMember ) {
00305 const EmailAddressList &al = this->*(b->addrMember);
00306 EmailAddressList::const_iterator lb = al.begin(), le = al.end();
00307
00308
00309 for( ; lb != le; ++lb ) {
00310
00311
00312 if( !lb->size() )
00313 continue;
00314
00315 std::string Name = lb->Name,
00316 Email = lb->Email;
00317
00318
00319 if( b->iconvNeeded && ic ) {
00320 Name = ic->ToBB(Name);
00321 Email = ic->ToBB(Email);
00322 }
00323
00324
00325
00326
00327
00328
00329
00330 std::string field(lb->Email.c_str(), lb->Email.size() + 1);
00331 field.append(lb->Name.c_str(), lb->Name.size() + 1);
00332 BuildField(data, offset, b->type, field.data(), field.size());
00333 }
00334 }
00335 }
00336
00337
00338 if( Recurring ) {
00339 CalendarRecurrenceDataField recur;
00340 BuildRecurrenceData(StartTime, &recur);
00341 BuildField(data, offset, RecurBase::RecurringFieldType(),
00342 &recur, CALENDAR_RECURRENCE_DATA_FIELD_SIZE);
00343 }
00344
00345 if( TimeZoneValid )
00346 BuildField(data, offset, CALFC_TIMEZONE_CODE, TimeZoneCode);
00347
00348 BuildField(data, offset, CALFC_FREEBUSY_FLAG, FreeBusyFlagRec2Proto(FreeBusyFlag));
00349 BuildField(data, offset, CALFC_CLASS_FLAG, ClassFlagRec2Proto(ClassFlag));
00350
00351
00352 UnknownsType::const_iterator
00353 ub = Unknowns.begin(), ue = Unknowns.end();
00354 for( ; ub != ue; ub++ ) {
00355 BuildField(data, offset, *ub);
00356 }
00357
00358 data.ReleaseBuffer(offset);
00359 }
00360
00361 void Calendar::Clear()
00362 {
00363 RecurBase::Clear();
00364
00365 RecType = Calendar::GetDefaultRecType();
00366
00367 AllDayEvent = false;
00368 Subject.clear();
00369 Notes.clear();
00370 Location.clear();
00371 NotificationTime = StartTime = EndTime = 0;
00372
00373 FreeBusyFlag = Free;
00374 ClassFlag = Public;
00375
00376 TimeZoneCode = GetTimeZoneCode(0, 0);
00377 TimeZoneValid = false;
00378
00379 Unknowns.clear();
00380 }
00381
00382 void Calendar::Dump(std::ostream &os) const
00383 {
00384 static const char *ClassTypes[] = { "Public", "Confidential", "Private" };
00385 static const char *FreeBusy[] = { "Free", "Tentative", "Busy", "Out of Office" };
00386
00387
00388
00389
00390
00391 os << "Calendar entry: 0x" << setbase(16) << RecordId
00392 << " (" << (unsigned int)RecType << ")\n";
00393 os << " All Day Event: " << (AllDayEvent ? "yes" : "no") << "\n";
00394 os << " Class: " << ClassTypes[ClassFlag] << "\n";
00395 os << " Free/Busy: " << FreeBusy[FreeBusyFlag] << "\n";
00396 if( TimeZoneValid )
00397 os << " Time Zone: " << GetTimeZone(TimeZoneCode)->Name << "\n";
00398
00399
00400 for( const FieldLink<Calendar> *b = CalendarFieldLinks;
00401 b->type != CALFC_END;
00402 b++ )
00403 {
00404 if( b->strMember ) {
00405 const std::string &s = this->*(b->strMember);
00406 if( s.size() )
00407 os << " " << b->name << ": " << s << "\n";
00408 }
00409 else if( b->timeMember ) {
00410 time_t t = this->*(b->timeMember);
00411 if( t > 0 )
00412 os << " " << b->name << ": " << ctime(&t);
00413 else
00414 os << " " << b->name << ": disabled\n";
00415 }
00416 else if( b->addrMember ) {
00417 const EmailAddressList &al = this->*(b->addrMember);
00418 EmailAddressList::const_iterator lb = al.begin(), le = al.end();
00419
00420 for( ; lb != le; ++lb ) {
00421 if( !lb->size() )
00422 continue;
00423
00424 os << " " << b->name << ": " << *lb << "\n";
00425 }
00426 }
00427 }
00428
00429
00430 RecurBase::Dump(os);
00431
00432
00433 os << Unknowns;
00434 }
00435
00436
00437 }
00438