r_calendar.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_calendar.cc
00003 ///             Blackberry database record parser class for calendar records.
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include "r_calendar.h"
00023 #include "r_recur_base-int.h"
00024 #include "record-internal.h"
00025 #include "protocol.h"
00026 #include "protostructs.h"
00027 #include "data.h"
00028 #include "time.h"
00029 #include "error.h"
00030 #include "endian.h"
00031 #include "iconv.h"
00032 #include <ostream>
00033 #include <iomanip>
00034 #include <time.h>
00035 #include <string.h>
00036 #include <stdexcept>
00037 #include "ios_state.h"
00038 
00039 #define __DEBUG_MODE__
00040 #include "debug.h"
00041 
00042 using namespace std;
00043 using namespace Barry::Protocol;
00044 
00045 namespace Barry {
00046 
00047 
00048 ///////////////////////////////////////////////////////////////////////////////
00049 // Calendar class, static members
00050 
00051 //
00052 // Note! These functions currently only pass the same values through.
00053 //       In actuality, these are technically two different values:
00054 //       one on the raw protocol side, and the other part of the
00055 //       guaranteed Barry API.  If the Blackberry ever changes the
00056 //       meanings for these codes, do the translation here.
00057 //
00058 
00059 Calendar::FreeBusyFlagType Calendar::FreeBusyFlagProto2Rec(uint8_t f)
00060 {
00061         return (FreeBusyFlagType)f;
00062 }
00063 
00064 uint8_t Calendar::FreeBusyFlagRec2Proto(FreeBusyFlagType f)
00065 {
00066         return f;
00067 }
00068 
00069 Calendar::ClassFlagType Calendar::ClassFlagProto2Rec(uint8_t f)
00070 {
00071         return (ClassFlagType)f;
00072 }
00073 
00074 uint8_t Calendar::ClassFlagRec2Proto(ClassFlagType f)
00075 {
00076         return f;
00077 }
00078 
00079 
00080 
00081 ///////////////////////////////////////////////////////////////////////////////
00082 // Calendar class
00083 
00084 // calendar field codes
00085 #define CALFC_APPT_TYPE_FLAG            0x01
00086 #define CALFC_SUBJECT                   0x02
00087 #define CALFC_NOTES                     0x03
00088 #define CALFC_LOCATION                  0x04
00089 #define CALFC_NOTIFICATION_TIME         0x05
00090 #define CALFC_START_TIME                0x06
00091 #define CALFC_END_TIME                  0x07
00092 #define CALFC_ACCEPTED_BY               0x0b
00093 #define CALFC_VERSION_DATA              0x10
00094 #define CALFC_INVITED                   0x15
00095 #define CALFC_ORGANIZER                 0x16
00096 #define CALFC_NOTIFICATION_DATA         0x1a
00097 #define CALFC_FREEBUSY_FLAG             0x1c
00098 #define CALFC_TIMEZONE_CODE             0x1e    // only seems to show up if recurring
00099 #define CALFC_CLASS_FLAG                0x28    // private flag from outlook
00100 #define CALFC_CALENDAR_ID               0x2b    // Calendar using (new devices have several calendar)
00101 #define CALFC_ALLDAYEVENT_FLAG          0xff
00102 #define CALFC_END                       0xffff
00103 
00104 static FieldLink<Calendar> CalendarFieldLinks[] = {
00105    { CALFC_SUBJECT,    "Subject",    0, 0,    &Calendar::Subject, 0, 0, 0, 0, true },
00106    { CALFC_NOTES,      "Notes",      0, 0,    &Calendar::Notes, 0, 0, 0, 0, true },
00107    { CALFC_LOCATION,   "Location",   0, 0,    &Calendar::Location, 0, 0, 0, 0, true },
00108    { CALFC_NOTIFICATION_TIME,"Notification Time",0,0, 0, 0, &Calendar::NotificationTime, 0, 0, false },
00109    { CALFC_START_TIME, "Start Time", 0, 0,    0, 0, &Calendar::StartTime, 0, 0, false },
00110    { CALFC_END_TIME,   "End Time",   0, 0,    0, 0, &Calendar::EndTime, 0, 0, false },
00111    { CALFC_ORGANIZER,  "Organizer",  0, 0,    0, &Calendar::Organizer, 0, 0, 0, true },
00112    { CALFC_ACCEPTED_BY,"Accepted By",0, 0,    0, &Calendar::AcceptedBy, 0, 0, 0, true },
00113    { CALFC_INVITED,    "Invited",    0, 0,    0, &Calendar::Invited, 0, 0, 0, true },
00114    { CALFC_END,        "End of List",0, 0,    0, 0, 0, 0, 0, false }
00115 };
00116 
00117 Calendar::Calendar()
00118 {
00119         Clear();
00120 }
00121 
00122 Calendar::~Calendar()
00123 {
00124 }
00125 
00126 const unsigned char* Calendar::ParseField(const unsigned char *begin,
00127                                           const unsigned char *end,
00128                                           const IConverter *ic)
00129 {
00130         const CommonField *field = (const CommonField *) begin;
00131 
00132         // advance and check size
00133         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00134         if( begin > end )               // if begin==end, we are ok
00135                 return begin;
00136 
00137         if( !btohs(field->size) )       // if field has no size, something's up
00138                 return begin;
00139 
00140         // cycle through the type table
00141         for(    FieldLink<Calendar> *b = CalendarFieldLinks;
00142                 b->type != CALFC_END;
00143                 b++ )
00144         {
00145                 if( b->type == field->type ) {
00146                         if( b->strMember ) {
00147                                 std::string &s = this->*(b->strMember);
00148                                 s = ParseFieldString(field);
00149                                 if( b->iconvNeeded && ic )
00150                                         s = ic->FromBB(s);
00151                                 return begin;   // done!
00152                         }
00153                         else if( b->timeMember && btohs(field->size) == 4 ) {
00154                                 TimeT &t = this->*(b->timeMember);
00155                                 dout("min1900: " << field->u.min1900);
00156                                 t.Time = min2time(field->u.min1900);
00157                                 return begin;
00158                         }
00159                         else if( b->addrMember ) {
00160                                 //
00161                                 // parse email address
00162                                 // get dual addr+name string first
00163                                 // Note: this is a different format than
00164                                 // used in r_message*.cc
00165                                 //
00166                                 std::string dual((const char*)field->u.raw, btohs(field->size));
00167 
00168                                 EmailAddress a;
00169 
00170                                 // assign first string, using null terminator
00171                                 // letting std::string add it for us if it
00172                                 // doesn't exist
00173                                 a.Email = dual.c_str();
00174 
00175                                 // assign second string, using first size
00176                                 // as starting point
00177                                 a.Name = dual.c_str() + a.Email.size() + 1;
00178 
00179                                 // if the address is non-empty, add to list
00180                                 if( a.size() ) {
00181                                         // i18n convert if needed
00182                                         if( b->iconvNeeded && ic ) {
00183                                                 a.Name = ic->FromBB(a.Name);
00184                                                 a.Email = ic->FromBB(a.Email);
00185                                         }
00186 
00187                                         EmailAddressList &al = this->*(b->addrMember);
00188                                         al.push_back(a);
00189                                 }
00190 
00191                                 return begin;
00192                         }
00193                 }
00194         }
00195 
00196         // handle special cases
00197         switch( field->type )
00198         {
00199         case CALFC_APPT_TYPE_FLAG:
00200                 switch( field->u.raw[0] )
00201                 {
00202                 case 'a':                       // regular non-recurring appointment
00203                         Recurring = false;
00204                         return begin;
00205 
00206                 case '*':                       // recurring appointment
00207                         Recurring = true;
00208                         return begin;
00209 
00210                 default:
00211                         throw Error("Calendar::ParseField: unknown appointment type");
00212                 }
00213                 break;
00214 
00215         case CALFC_ALLDAYEVENT_FLAG:
00216                 AllDayEvent = field->u.raw[0] == 1;
00217                 return begin;
00218 
00219         case CALFC_TIMEZONE_CODE:
00220                 if( btohs(field->size) == 2 ) {
00221                         // good data
00222                         TimeZoneCode = btohs(field->u.code);
00223                         TimeZoneValid = true;
00224                 }
00225                 else {
00226                         throw Error("Calendar::ParseField: not enough data in time zone code field");
00227                 }
00228                 return begin;
00229 
00230         case CALFC_FREEBUSY_FLAG:
00231                 if( field->u.raw[0] > CR_FREEBUSY_RANGE_HIGH ) {
00232                         throw Error("Calendar::ParseField: FreeBusyFlag out of range" );
00233                 }
00234                 FreeBusyFlag = FreeBusyFlagProto2Rec(field->u.raw[0]);
00235                 return begin;
00236 
00237         case CALFC_CALENDAR_ID:
00238                 if( btohs(field->size) == 8 ) {
00239                         CalendarID = btohll(field->u.uint64);
00240                 }
00241                 else {
00242                         throw Error("Calendar::ParseField: size data unknown in calendar field");
00243                 }
00244                 return begin;
00245 
00246         case CALFC_CLASS_FLAG:
00247                 if( field->u.raw[0] > CR_CLASS_RANGE_HIGH ) {
00248                         throw Error("Calendar::ParseField: ClassFlag out of range" );
00249                 }
00250                 ClassFlag = ClassFlagProto2Rec(field->u.raw[0]);
00251                 return begin;
00252         }
00253 
00254         // base class handles recurring data
00255         if( RecurBase::ParseField(field->type, field->u.raw, btohs(field->size), ic) )
00256                 return begin;
00257 
00258         // if still not handled, add to the Unknowns list
00259         UnknownField uf;
00260         uf.type = field->type;
00261         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00262         Unknowns.push_back(uf);
00263 
00264         // return new pointer for next field
00265         return begin;
00266 }
00267 
00268 void Calendar::ParseHeader(const Data &data, size_t &offset)
00269 {
00270         // no header in Calendar records
00271 }
00272 
00273 void Calendar::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00274 {
00275         const unsigned char *finish = ParseCommonFields(*this,
00276                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00277         offset += finish - (data.GetData() + offset);
00278 }
00279 
00280 void Calendar::Validate() const
00281 {
00282         RecurBase::Validate();
00283 }
00284 
00285 void Calendar::BuildHeader(Data &data, size_t &offset) const
00286 {
00287         // no header in Calendar records
00288 }
00289 
00290 //
00291 // Build
00292 //
00293 /// Build fields part of record.
00294 ///
00295 void Calendar::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00296 {
00297         data.Zap();
00298 
00299         // output the type first
00300         BuildField(data, offset, CALFC_APPT_TYPE_FLAG, Recurring ? '*' : 'a');
00301 
00302         // output all day event flag only if set
00303         if( AllDayEvent )
00304                 BuildField(data, offset, CALFC_ALLDAYEVENT_FLAG, (char)1);
00305 
00306         // cycle through the type table
00307         for(    const FieldLink<Calendar> *b = CalendarFieldLinks;
00308                 b->type != CALFC_END;
00309                 b++ )
00310         {
00311                 if( b->strMember ) {
00312                         const std::string &s = this->*(b->strMember);
00313                         if( s.size() )
00314                                 BuildField(data, offset, b->type, (b->iconvNeeded && ic) ? ic->ToBB(s) : s);
00315                 }
00316                 else if( b->timeMember ) {
00317                         TimeT t = this->*(b->timeMember);
00318                         if( t.Time > 0 )
00319                                 BuildField1900(data, offset, b->type, t.Time);
00320                 }
00321                 else if( b->addrMember ) {
00322                         const EmailAddressList &al = this->*(b->addrMember);
00323                         EmailAddressList::const_iterator lb = al.begin(), le = al.end();
00324 
00325                         // add all entries in list
00326                         for( ; lb != le; ++lb ) {
00327 
00328                                 // skip empty entries
00329                                 if( !lb->size() )
00330                                         continue;
00331 
00332                                 std::string Name = lb->Name,
00333                                         Email = lb->Email;
00334 
00335                                 // do i18n conversion only if needed
00336                                 if( b->iconvNeeded && ic ) {
00337                                         Name = ic->ToBB(Name);
00338                                         Email = ic->ToBB(Email);
00339                                 }
00340 
00341                                 //
00342                                 // Build an addr+name field, each string
00343                                 // null terminated.
00344                                 // Note: this is a different format than
00345                                 // what is used in r_message*.cc
00346                                 //
00347                                 std::string field(lb->Email.c_str(), lb->Email.size() + 1);
00348                                 field.append(lb->Name.c_str(), lb->Name.size() + 1);
00349                                 BuildField(data, offset, b->type, field.data(), field.size());
00350                         }
00351                 }
00352         }
00353 
00354         // handle special cases
00355         if( Recurring ) {
00356                 CalendarRecurrenceDataField recur;
00357                 BuildRecurrenceData(StartTime.Time, &recur);
00358                 BuildField(data, offset, RecurBase::RecurringFieldType(),
00359                         &recur, CALENDAR_RECURRENCE_DATA_FIELD_SIZE);
00360         }
00361 
00362         if( TimeZoneValid )
00363                 BuildField(data, offset, CALFC_TIMEZONE_CODE, TimeZoneCode);
00364 
00365         BuildField(data, offset, CALFC_FREEBUSY_FLAG, FreeBusyFlagRec2Proto(FreeBusyFlag));
00366         BuildField(data, offset, CALFC_CLASS_FLAG, ClassFlagRec2Proto(ClassFlag));
00367 
00368         // If CalendarID is defined and most of supported !
00369         // (by default 0xffff ffff ffff ffff)
00370         if( CalendarID != (uint64_t) -1 )
00371                 BuildField(data, offset, CALFC_CALENDAR_ID, CalendarID);
00372 
00373         // and finally save unknowns
00374         UnknownsType::const_iterator
00375                 ub = Unknowns.begin(), ue = Unknowns.end();
00376         for( ; ub != ue; ub++ ) {
00377                 BuildField(data, offset, *ub);
00378         }
00379 
00380         data.ReleaseBuffer(offset);
00381 }
00382 
00383 void Calendar::Clear()
00384 {
00385         // clear the base class too
00386         RecurBase::Clear();
00387 
00388         // clear our fields
00389         RecType = GetDefaultRecType();
00390         RecordId = 0;
00391 
00392         AllDayEvent = false;
00393         Subject.clear();
00394         Notes.clear();
00395         Location.clear();
00396         NotificationTime.clear();
00397         StartTime.clear();
00398         EndTime.clear();
00399         Organizer.clear();
00400         AcceptedBy.clear();
00401         Invited.clear();
00402 
00403         FreeBusyFlag = Free;
00404         ClassFlag = Public;
00405 
00406         CalendarID = btohll((uint64_t) -1);
00407 
00408         TimeZoneCode = GetStaticTimeZoneCode(0, 0);     // default to GMT
00409         TimeZoneValid = false;
00410 
00411         Unknowns.clear();
00412 }
00413 
00414 const FieldHandle<Calendar>::ListT& Calendar::GetFieldHandles()
00415 {
00416         static FieldHandle<Calendar>::ListT fhv;
00417 
00418         if( fhv.size() )
00419                 return fhv;
00420 
00421 #undef CONTAINER_OBJECT_NAME
00422 #define CONTAINER_OBJECT_NAME fhv
00423 
00424 #undef RECORD_CLASS_NAME
00425 #define RECORD_CLASS_NAME Calendar
00426 
00427 #define ALL_COMMON_CALENDAR_FIELDS \
00428         FHP(RecType, "Record Type Code"); \
00429         FHP(RecordId, "Unique Record ID"); \
00430  \
00431         FHP(AllDayEvent, "All Day Event"); \
00432         FHD(Subject, "Subject", CALFC_SUBJECT, true); \
00433         FHD(Notes, "Notes", CALFC_NOTES, true); \
00434         FHD(Location, "Location", CALFC_LOCATION, true); \
00435         FHD(NotificationTime, "Notification Time (0 is off)", \
00436                                 CALFC_NOTIFICATION_TIME, false); \
00437         FHD(StartTime, "Start Time", CALFC_START_TIME, false); \
00438         FHD(EndTime, "End Time", CALFC_END_TIME, false); \
00439         FHD(Organizer, "Organizer", CALFC_ORGANIZER, true); \
00440         FHD(AcceptedBy, "Accepted By", CALFC_ACCEPTED_BY, true); \
00441         FHD(Invited, "Invited", CALFC_INVITED, true); \
00442  \
00443         FHE(fbf, FreeBusyFlagType, FreeBusyFlag, "Free or Busy Flag"); \
00444         FHE_CONST(fbf, Free, "Free"); \
00445         FHE_CONST(fbf, Tentative, "Tentative"); \
00446         FHE_CONST(fbf, Busy, "Busy"); \
00447         FHE_CONST(fbf, OutOfOffice, "Out of Office"); \
00448  \
00449         FHE(cf, ClassFlagType, ClassFlag, "Event Class"); \
00450         FHE_CONST(cf, Public, "Public"); \
00451         FHE_CONST(cf, Confidential, "Confidential"); \
00452         FHE_CONST(cf, Private, "Private"); \
00453  \
00454         FHP(TimeZoneCode, "Time Zone Code"); \
00455         FHP(TimeZoneValid, "Time Zone Validity"); \
00456  \
00457         FHP(Unknowns, "Unknown Fields");
00458 
00459         ALL_COMMON_CALENDAR_FIELDS
00460 
00461         // the fields unique to Calendar, or different in CalendarALL
00462         FHD(CalendarID, "Calendar ID", CALFC_CALENDAR_ID, false);
00463 
00464         // and finally, the RecurBase fields
00465         RECUR_BASE_FIELD_HANDLES
00466 
00467         return fhv;
00468 }
00469 
00470 std::string Calendar::GetDescription() const
00471 {
00472         return Subject;
00473 }
00474 
00475 void Calendar::DumpSpecialFields(std::ostream &os) const
00476 {
00477         ios_format_state state(os);
00478 
00479         static const char *ClassTypes[] = { "Public", "Confidential", "Private" };
00480         static const char *FreeBusy[] = { "Free", "Tentative", "Busy", "Out of Office" };
00481 
00482         os << "   Calendar ID: 0x" << setbase(16) << CalendarID << "\n";
00483         os << "   All Day Event: " << (AllDayEvent ? "yes" : "no") << "\n";
00484         os << "   Class: " << ClassTypes[ClassFlag] << "\n";
00485         os << "   Free/Busy: " << FreeBusy[FreeBusyFlag] << "\n";
00486         if( TimeZoneValid )
00487                 os << "   Time Zone: " << GetStaticTimeZone(TimeZoneCode)->Name << "\n";
00488 }
00489 
00490 void Calendar::Dump(std::ostream &os) const
00491 {
00492         ios_format_state state(os);
00493 
00494 // FIXME - need a "check all data" function that make sure that all
00495 // recurrence data is within range.  Then call that before using
00496 // the data, such as in Build and in Dump.
00497 
00498         os << "Calendar entry: 0x" << setbase(16) << RecordId
00499                 << " (" << (unsigned int)RecType << ")\n";
00500         DumpSpecialFields(os);
00501 
00502         // cycle through the type table
00503         for(    const FieldLink<Calendar> *b = CalendarFieldLinks;
00504                 b->type != CALFC_END;
00505                 b++ )
00506         {
00507                 if( b->strMember ) {
00508                         const std::string &s = this->*(b->strMember);
00509                         if( s.size() )
00510                                 os << "   " << b->name << ": " << s << "\n";
00511                 }
00512                 else if( b->timeMember ) {
00513                         TimeT t = this->*(b->timeMember);
00514                         if( t.Time > 0 )
00515                                 os << "   " << b->name << ": " << t << "\n";
00516                         else
00517                                 os << "   " << b->name << ": disabled\n";
00518                 }
00519                 else if( b->addrMember ) {
00520                         const EmailAddressList &al = this->*(b->addrMember);
00521                         EmailAddressList::const_iterator lb = al.begin(), le = al.end();
00522 
00523                         for( ; lb != le; ++lb ) {
00524                                 if( !lb->size() )
00525                                         continue;
00526 
00527                                 os << "   " << b->name << ": " << *lb << "\n";
00528                         }
00529                 }
00530         }
00531 
00532         // print recurrence data if available
00533         RecurBase::Dump(os);
00534 
00535         // print any unknowns
00536         os << Unknowns;
00537 }
00538 
00539 bool Calendar::operator<(const Calendar &other) const
00540 {
00541         if( StartTime < other.StartTime )
00542                 return true;
00543         else if( other.StartTime < StartTime )
00544                 return false;
00545 
00546         // times are equal, so secondary sort based on Subject + Location
00547         int cmp = Subject.compare(other.Subject);
00548         if( cmp == 0 )
00549                 cmp = Location.compare(other.Location);
00550         return cmp < 0;
00551 }
00552 
00553 
00554 ///////////////////////////////////////////////////////////////////////////////
00555 // Calendar-All class
00556 
00557 // calendar-all field codes
00558 #define CALALLFC_CALENDAR_ID            0x02    // Calendar using (new devices have several calendar)
00559 #define CALALLFC_MAIL_ACCOUNT           0x03
00560 #define CALALLFC_UNIQUEID                       0x05
00561 #define CALALLFC_CAL_OBJECT                     0x0a
00562 #define CALALLFC_END                            0xffff
00563 
00564 void CalendarAll::Clear()
00565 {
00566         Calendar::Clear();
00567 
00568         MailAccount.clear();
00569 }
00570 
00571 const FieldHandle<CalendarAll>::ListT& CalendarAll::GetFieldHandles()
00572 {
00573         static FieldHandle<CalendarAll>::ListT fhv;
00574 
00575         if( fhv.size() )
00576                 return fhv;
00577 
00578 #undef CONTAINER_OBJECT_NAME
00579 #define CONTAINER_OBJECT_NAME fhv
00580 
00581 #undef RECORD_CLASS_NAME
00582 #define RECORD_CLASS_NAME CalendarAll
00583 
00584         ALL_COMMON_CALENDAR_FIELDS
00585 
00586         // Calendar:: field, but with a CalendarAll ID
00587         FHD(CalendarID, "Calendar ID", CALALLFC_CALENDAR_ID, false);
00588 
00589         // add the fields specific to CalendarAll
00590         FHD(MailAccount, "Mail Account", CALALLFC_MAIL_ACCOUNT, true);
00591 
00592         // and finally, the RecurBase fields
00593         RECUR_BASE_FIELD_HANDLES
00594 
00595         return fhv;
00596 }
00597 
00598 void CalendarAll::ParseHeader(const Data &data, size_t &offset)
00599 {
00600         const unsigned char *b = (const unsigned char*) (data.GetData() + offset);
00601         const unsigned char *e = (const unsigned char*) (data.GetData() + data.GetSize());
00602 
00603         while( (b + COMMON_FIELD_HEADER_SIZE) < e ) {
00604                 const CommonField *field = (const CommonField *) b;
00605 
00606                 // advance and check size
00607                 b += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00608                 if( b > e )                                     // if begin==end, we are ok
00609                         continue;
00610 
00611                 if( !btohs(field->size) )       // if field has no size, something's up
00612                         continue;
00613 
00614                 // handle special cases
00615                 if( field->type == CALALLFC_CAL_OBJECT )
00616                 {
00617                         b -= btohs(field->size);
00618                         // end of header
00619                         break;
00620                 }
00621 
00622                 switch( field->type )
00623                 {
00624                 case CALALLFC_CALENDAR_ID:
00625                         if( btohs(field->size) == 8 ) {
00626                                 CalendarID = btohll(field->u.uint64);
00627                         }
00628                         else {
00629                                 throw Error("CalendarAll::ParseField: size data unknown in calendar field");
00630                         }
00631                         continue;
00632 
00633                 case CALALLFC_MAIL_ACCOUNT:
00634                         MailAccount = ParseFieldString(field);
00635                         continue;
00636 
00637                 case CALALLFC_UNIQUEID:
00638                         if( btohs(field->size) == 4 ) {
00639                                 RecordId = btohl(field->u.uint32);
00640                         }
00641                         else {
00642                                 throw Error("CalendarAll::ParseHeader: size data unknown in calendar field");
00643                         }
00644                         continue;
00645                 }
00646 
00647                 // if still not handled, add to the Unknowns list
00648                 UnknownField uf;
00649                 uf.type = field->type;
00650                 uf.data.assign((const char*)field->u.raw, btohs(field->size));
00651                 Unknowns.push_back(uf);
00652         }
00653 
00654         offset += b - (data.GetData() + offset);
00655 }
00656 
00657 void CalendarAll::DumpSpecialFields(std::ostream &os) const
00658 {
00659         ios_format_state state(os);
00660 
00661         Calendar::DumpSpecialFields(os);
00662         os << "   Mail Account: " << MailAccount << "\n";
00663 }
00664 
00665 } // namespace Barry
00666