record.h

Go to the documentation of this file.
00001 ///
00002 /// \file       record.h
00003 ///             Blackberry database record classes.  Help translate data
00004 ///             from data packets to useful structurs, and back.
00005 ///             This header provides the common types and classes
00006 ///             used by the general record parser classes in the
00007 ///             r_*.h files.  Only application-safe API stuff goes in
00008 ///             here.  Internal library types go in record-internal.h
00009 ///
00010 
00011 /*
00012     Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
00013 
00014     This program is free software; you can redistribute it and/or modify
00015     it under the terms of the GNU General Public License as published by
00016     the Free Software Foundation; either version 2 of the License, or
00017     (at your option) any later version.
00018 
00019     This program is distributed in the hope that it will be useful,
00020     but WITHOUT ANY WARRANTY; without even the implied warranty of
00021     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 
00023     See the GNU General Public License in the COPYING file at the
00024     root directory of this project for more details.
00025 */
00026 
00027 #ifndef __BARRY_RECORD_H__
00028 #define __BARRY_RECORD_H__
00029 
00030 #include "dll.h"
00031 #include <iosfwd>
00032 #include <string>
00033 #include <vector>
00034 #include <map>
00035 #include <stdint.h>
00036 #include <stdexcept>
00037 
00038 // forward declarations
00039 namespace Barry { class Data; }
00040 
00041 namespace Barry {
00042 
00043 //
00044 // NOTE:  All classes here must be container-safe!  Perhaps add sorting
00045 //        operators in the future.
00046 //
00047 
00048 
00049 // stream-based wrapper to avoid printing strings that contain
00050 // the \r carriage return characters
00051 class BXEXPORT Cr2LfWrapper
00052 {
00053         friend std::ostream& operator<< (std::ostream &os, const Cr2LfWrapper &str);
00054         const std::string &m_str;
00055 public:
00056         explicit Cr2LfWrapper(const std::string &str)
00057                 : m_str(str)
00058         {
00059         }
00060 };
00061 BXEXPORT std::ostream& operator<< (std::ostream &os, const Cr2LfWrapper &str);
00062 
00063 /// Struct wrapper for time_t, to make sure that it has its own type,
00064 /// for overload purposes.  Some systems, like QNX, use a uint32_t typedef.
00065 ///
00066 /// If Time contains 0, it is considered invalid/uninitialized when using
00067 /// IsValid().  Validity has no affect on comparison operators.
00068 struct BXEXPORT TimeT
00069 {
00070         time_t Time;
00071 
00072         TimeT()
00073                 : Time(0)
00074         {
00075         }
00076 
00077         explicit TimeT(time_t t)
00078                 : Time(t)
00079         {
00080         }
00081 
00082         void clear()
00083         {
00084                 Time = 0;
00085         }
00086 
00087         bool IsValid() const { return Time > 0; }
00088 
00089         bool operator< (const Barry::TimeT &other) const
00090         {
00091                 return Time < other.Time;
00092         }
00093 
00094         bool operator== (const Barry::TimeT &other) const
00095         {
00096                 return Time == other.Time;
00097         }
00098 
00099         bool operator!= (const Barry::TimeT &other) const
00100         {
00101                 return !operator==(other);
00102         }
00103 };
00104 BXEXPORT std::ostream& operator<< (std::ostream &os, const TimeT &t);
00105 
00106 struct BXEXPORT CommandTableCommand
00107 {
00108         unsigned int Code;
00109         std::string Name;
00110 };
00111 
00112 class BXEXPORT CommandTable
00113 {
00114 public:
00115         typedef CommandTableCommand Command;
00116         typedef std::vector<Command> CommandArrayType;
00117 
00118         CommandArrayType Commands;
00119 
00120 private:
00121         BXLOCAL const unsigned char* ParseField(const unsigned char *begin,
00122                 const unsigned char *end);
00123 public:
00124         CommandTable();
00125         ~CommandTable();
00126 
00127         void Parse(const Data &data, size_t offset);
00128         void Clear();
00129 
00130         // returns 0 if unable to find command name, which is safe, since
00131         // 0 is a special command that shouldn't be in the table anyway
00132         unsigned int GetCommand(const std::string &name) const;
00133 
00134         void Dump(std::ostream &os) const;
00135 };
00136 
00137 BXEXPORT inline std::ostream& operator<< (std::ostream &os, const CommandTable &command) {
00138         command.Dump(os);
00139         return os;
00140 }
00141 
00142 
00143 
00144 struct BXEXPORT RecordStateTableState
00145 {
00146         unsigned int Index;
00147         uint32_t RecordId;
00148         bool Dirty;
00149         unsigned int RecType;
00150         std::string Unknown2;
00151 };
00152 
00153 class BXEXPORT RecordStateTable
00154 {
00155 public:
00156         typedef RecordStateTableState State;
00157         typedef unsigned int IndexType;
00158         typedef std::map<IndexType, State> StateMapType;
00159 
00160         StateMapType StateMap;
00161 
00162 private:
00163         mutable IndexType m_LastNewRecordId;
00164 
00165 private:
00166         BXLOCAL const unsigned char* ParseField(const unsigned char *begin,
00167                 const unsigned char *end);
00168 
00169 public:
00170         RecordStateTable();
00171         ~RecordStateTable();
00172 
00173         void Parse(const Data &data);
00174         void Clear();
00175 
00176         bool GetIndex(uint32_t RecordId, IndexType *pFoundIndex = 0) const;
00177         uint32_t MakeNewRecordId() const;
00178 
00179         void Dump(std::ostream &os) const;
00180 };
00181 
00182 BXEXPORT inline std::ostream& operator<< (std::ostream &os, const RecordStateTable &rst) {
00183         rst.Dump(os);
00184         return os;
00185 }
00186 
00187 
00188 
00189 struct BXEXPORT DatabaseItem
00190 {
00191         unsigned int Number;
00192         unsigned int RecordCount;
00193         std::string Name;
00194 };
00195 
00196 class BXEXPORT DatabaseDatabase
00197 {
00198 public:
00199         typedef DatabaseItem Database;
00200         typedef std::vector<Database> DatabaseArrayType;
00201 
00202         DatabaseArrayType Databases;
00203 
00204 private:
00205         template <class RecordType, class FieldType>
00206         void ParseRec(const RecordType &rec, const unsigned char *end);
00207 
00208         template <class FieldType>
00209         const unsigned char* ParseField(const unsigned char *begin,
00210                 const unsigned char *end);
00211 
00212 public:
00213         DatabaseDatabase();
00214         ~DatabaseDatabase();
00215 
00216         void Parse(const Data &data);
00217         void Clear();
00218 
00219         void SortByName();
00220         void SortByRecordCount();
00221         unsigned int GetTotalRecordCount() const;
00222 
00223         // returns true on success, and fills target
00224         bool GetDBNumber(const std::string &name, unsigned int &number) const;
00225         bool GetDBName(unsigned int number, std::string &name) const;
00226 
00227         void Dump(std::ostream &os) const;
00228 };
00229 
00230 BXEXPORT inline std::ostream& operator<<(std::ostream &os, const DatabaseDatabase &dbdb) {
00231         dbdb.Dump(os);
00232         return os;
00233 }
00234 
00235 struct UnknownData
00236 {
00237         std::string raw_data;
00238 
00239         const std::string::value_type* data() const { return raw_data.data(); }
00240         std::string::size_type size() const { return raw_data.size(); }
00241         void assign(const std::string::value_type *s, std::string::size_type n)
00242                 { raw_data.assign(s, n); }
00243 
00244         bool operator==(const UnknownData &other) const
00245         {
00246                 return raw_data == other.raw_data;
00247         }
00248 
00249         bool operator!=(const UnknownData &other) const
00250         {
00251                 return !operator==(other);
00252         }
00253 
00254         bool operator< (const UnknownData &other) const
00255         {
00256                 return raw_data < other.raw_data;
00257         }
00258 };
00259 
00260 struct BXEXPORT UnknownField
00261 {
00262         uint8_t type;
00263         UnknownData data;
00264 
00265         bool operator==(const UnknownField &other) const
00266         {
00267                 return  type == other.type &&
00268                         data == other.data;
00269         }
00270 
00271         bool operator!=(const UnknownField &other) const
00272         {
00273                 return !operator==(other);
00274         }
00275 
00276         bool operator< (const UnknownField &other) const
00277         {
00278                 return type < other.type && data < other.data;
00279         }
00280 };
00281 typedef std::vector<UnknownField> UnknownsType;
00282 BXEXPORT std::ostream& operator<< (std::ostream &os, const UnknownsType &unknowns);
00283 
00284 // simple string email type and list... keep this a simple string list,
00285 // so it can be reused for other address-like data, like phone numbers.
00286 // If you need something more complex, use EmailAddress below or
00287 // create a new type.
00288 typedef std::string                             EmailType;
00289 class BXEXPORT EmailList : public std::vector<EmailType>
00290 {
00291 public:
00292         typedef std::vector<EmailType>          base_type;
00293 
00294 public:
00295         using base_type::size;
00296         using base_type::begin;
00297         using base_type::end;
00298         using base_type::at;
00299         using base_type::rbegin;
00300         using base_type::rend;
00301         using base_type::empty;
00302         using base_type::resize;
00303         using base_type::reserve;
00304         using base_type::front;
00305         using base_type::back;
00306         using base_type::push_back;
00307         using base_type::pop_back;
00308         using base_type::insert;
00309         using base_type::erase;
00310         using base_type::swap;
00311         using base_type::clear;
00312         using base_type::operator=;
00313         using base_type::operator[];
00314 };
00315 BXEXPORT std::ostream& operator<< (std::ostream &os, const EmailList &list);
00316 
00317 // struct, attempting to combine name + email address, for mail
00318 struct BXEXPORT EmailAddress
00319 {
00320         std::string Name;
00321         std::string Email;
00322 
00323         EmailAddress()
00324         {
00325         }
00326 
00327         /// Converts "Name <address@host.com>" into Name + Address
00328         /// Will also handle just a plain address too.
00329         explicit EmailAddress(const std::string &complex_address);
00330 
00331         void clear()
00332         {
00333                 Name.clear();
00334                 Email.clear();
00335         }
00336 
00337         size_t size() const
00338         {
00339                 return Name.size() + Email.size();
00340         }
00341 
00342         bool operator==(const EmailAddress &other) const
00343         {
00344                 return  Name == other.Name &&
00345                         Email == other.Email;
00346         }
00347 
00348         bool operator!=(const EmailAddress &other) const
00349         {
00350                 return !operator==(other);
00351         }
00352 
00353         bool operator< (const EmailAddress &other) const
00354         {
00355                 // sort by email only, since not every address has a name
00356                 return Email < other.Email;
00357         }
00358 };
00359 BXEXPORT std::ostream& operator<<(std::ostream &os, const EmailAddress &msga);
00360 
00361 class BXEXPORT EmailAddressList : public std::vector<EmailAddress>
00362 {
00363 public:
00364         std::string ToCommaSeparated() const;
00365         void AddCommaSeparated(const std::string &list);
00366 };
00367 
00368 BXEXPORT std::ostream& operator<<(std::ostream &os, const EmailAddressList &elist);
00369 
00370 struct BXEXPORT PostalAddress
00371 {
00372         std::string
00373                 Address1,
00374                 Address2,
00375                 Address3,
00376                 City,
00377                 Province,
00378                 PostalCode,
00379                 Country;
00380 
00381         std::string GetLabel() const;
00382         void Clear();
00383 
00384         bool HasData() const { return Address1.size() || Address2.size() ||
00385                 Address3.size() || City.size() || Province.size() ||
00386                 PostalCode.size() || Country.size(); }
00387 
00388         bool operator==(const PostalAddress &other) const
00389         {
00390                 return  Address1 == other.Address1 &&
00391                         Address2 == other.Address2 &&
00392                         Address3 == other.Address3 &&
00393                         City == other.City &&
00394                         Province == other.Province &&
00395                         PostalCode == other.PostalCode &&
00396                         Country == other.Country;
00397         }
00398         bool operator!=(const PostalAddress &other) const
00399         {
00400                 return !operator==(other);
00401         }
00402         bool operator< (const PostalAddress &other) const
00403         {
00404                 return GetLabel() < other.GetLabel();
00405         }
00406 };
00407 BXEXPORT std::ostream& operator<<(std::ostream &os, const PostalAddress &msga);
00408 
00409 struct BXEXPORT Date
00410 {
00411         int Month;                      // 0 to 11
00412         int Day;                        // 1 to 31
00413         int Year;                       // exact number, eg. 2008
00414 
00415         Date() : Month(0), Day(0), Year(0) {}
00416         explicit Date(const struct tm *timep);
00417 
00418         bool HasData() const { return Month || Day || Year; }
00419         void Clear();
00420 
00421         void ToTm(struct tm *timep) const;
00422         std::string ToYYYYMMDD() const;
00423         std::string ToBBString() const; // converts to Blackberry string
00424                                         // format of DD/MM/YYYY
00425 
00426         bool FromTm(const struct tm *timep);
00427         bool FromBBString(const std::string &str);
00428         bool FromYYYYMMDD(const std::string &str);
00429 
00430         bool operator==(const Date &other) const
00431         {
00432                 return Month == other.Month &&
00433                         Day == other.Day &&
00434                         Year == other.Year;
00435         }
00436         bool operator!=(const Date &other) const
00437         {
00438                 return !operator==(other);
00439         }
00440         bool operator< (const Date &other) const
00441         {
00442                 // YYYYMMDD as integer
00443                 unsigned int v1 = Year * 10000 + Month * 100 + Day;
00444                 unsigned int v2 = other.Year * 10000 + other.Month * 100 + other.Day;
00445                 return v1 < v2;
00446         }
00447 };
00448 BXEXPORT std::ostream& operator<<(std::ostream &os, const Date &date);
00449 
00450 class BXEXPORT CategoryList : public std::vector<std::string>
00451 {
00452 public:
00453         /// Parses the given comma delimited category string into
00454         /// this CategoryList object, appending each token to the vector.
00455         /// Will clear vector beforehand.
00456         void CategoryStr2List(const std::string &str);
00457 
00458         /// Turns the current vectory into a comma delimited category
00459         /// string suitable for use in Calendar, Task, and Memo
00460         /// protocol values.
00461         void CategoryList2Str(std::string &str) const;
00462 
00463         using std::vector<std::string>::operator=;
00464 };
00465 BXEXPORT std::ostream& operator<<(std::ostream &os, const CategoryList &cl);
00466 
00467 
00468 
00469 //////////////////////////////////////////////////////////////////////////////
00470 // Generic Field Handles
00471 
00472 /// \addtogroup GenericFieldHandles
00473 ///             Generic field handle classes, used to reference and work
00474 ///             with record members in a flexible, indirect way.
00475 ///
00476 ///             There are two ways to access device record data.  The obvious
00477 ///             way is to instantiate a record class, such as Contact, and
00478 ///             access the public data members of that class to read and
00479 ///             write.  If you always work with the same record class, this
00480 ///             works fine.
00481 ///
00482 ///             The other way is to have a list of pointers to members.
00483 ///             For example, you may wish to compare two records, without
00484 ///             actually caring what data is in each one.  You can compare
00485 ///             at the record class level, with Contact one, two; and then
00486 ///             if( one == two ), but this will not tell you what field in
00487 ///             the record changed.
00488 ///
00489 ///             This last feature is what Generic Field Handles are meant to
00490 ///             fix.  Each record class will contain a GetFieldHandles()
00491 ///             member function, which will return a list of type
00492 ///             FieldHandle<T>::ListT (currently a std::vector<>)
00493 ///             objects, for that specific record.  For example, Contact
00494 ///             would fill the ListT with FieldHandle<Contact> objects.
00495 ///             Each FieldHandle<> object contains a C++ pointer-to-member,
00496 ///             which the FieldHandle refers to, as well as a FieldIdentity
00497 ///             object.  The FieldIdentity object contains various identitying
00498 ///             information, such as the C++ variable name, an English
00499 ///             (or localized language) display name of the field, suitable
00500 ///             for user prompts, and other data more useful to the library.
00501 ///
00502 ///             The FieldHandle<> object has two member functions: Value()
00503 ///             and Member().
00504 ///
00505 ///             Value() will call a callback function with the _value_ of
00506 ///             the variable that FieldHandle<> points to.  For example,
00507 ///             if the FieldHandle<> points to a std::string record member
00508 ///             variable, then Value() will pass that string value in as
00509 ///             an argument, along with a reference to the FieldIdentity
00510 ///             object.  Value() requires a callback object and a record
00511 ///             object to perform this callback.
00512 ///
00513 ///             Member() will call a callback function/functor with the
00514 ///             pointer-to-member pointer and the FieldIdentity object.
00515 ///             This allows the programmer to create a functor with multiple
00516 ///             record objects, perhaps two objects to compare individual
00517 ///             fields, and use the pointer-to-member to access the field
00518 ///             data as needed.
00519 ///
00520 ///             For now, all data and callbacks are const, meaning that it
00521 ///             is not possible (without const_casting) to write to the
00522 ///             record via the pointers-to-members.  This design decision
00523 ///             may need to be revisited someday, depending on its usefulness.
00524 ///
00525 /// @{
00526 
00527 //
00528 // FieldIdentity
00529 //
00530 /// This class holds data that identifies a given field in a record.
00531 /// This is fairly constant data, referenced by the FieldHandle class.
00532 /// The information in here should be enough to show the user what kind
00533 /// of field this is.
00534 ///
00535 struct BXEXPORT FieldIdentity
00536 {
00537         // useful public data
00538         const char *Name;               // C++ name of field member variable in
00539                                         // record class
00540         std::string DisplayName;        // localized display name of field
00541                                         // in UTF8
00542                                         // FIXME - should we leave localization
00543                                         // to the application?
00544 
00545         // subfield detection
00546         bool HasSubfields;              // true if this field has subfields
00547         const char *ParentName;         // name of field member variable that
00548                                         // this field is a member of, or NULL
00549                                         // if this field is a member of the
00550                                         // record class.
00551                                         // For example, Contact::PostalAddress
00552                                         // would have HasSubfields == true,
00553                                         // and ParentName == NULL, while all
00554                                         // its subfield strings would have
00555                                         // HasSubfields == false and
00556                                         // ParentName == "WorkAddress" or
00557                                         // "HomeAddress".
00558                                         // The application could then decide
00559                                         // whether to process only main fields,
00560                                         // some of which have subfields,
00561                                         // or only individual subfields.
00562 
00563         // internal field data
00564         int FieldTypeCode;              // device type code for this field.
00565                                         // if -1, then this is a conglomerate
00566                                         // C++ field, such as
00567                                         // Contact::PostalAddress, not a device
00568                                         // field.
00569                                         // If -1, then none of the following
00570                                         // fields are valid.
00571         const char *Ldif;               // matching LDIF field name, or NULL
00572         const char *ObjectClass;        // matching LDIF object class, or NULL
00573         bool IconvNeeded;               // if true, the device's data needs to
00574                                         // be passed through an IConverter
00575 
00576         FieldIdentity(const char *name, const std::string &display_name,
00577                 int type_code = -1,
00578                 bool iconvneeded = false,
00579                 const char *ldif = 0, const char *oclass = 0,
00580                 bool has_sub = false, const char *parent = 0
00581                 )
00582                 : Name(name)
00583                 , DisplayName(display_name)
00584                 , HasSubfields(has_sub)
00585                 , ParentName(parent)
00586                 , FieldTypeCode(type_code)
00587                 , Ldif(ldif)
00588                 , ObjectClass(oclass)
00589                 , IconvNeeded(iconvneeded)
00590         {
00591         }
00592 };
00593 
00594 //
00595 // EnumConstants
00596 //
00597 /// This is the base class for the hierarchy of classes to define
00598 /// enum record members.  This is the base class, which contains the
00599 /// common code for creating and defining a list of enum constants for
00600 /// a given enum field.  The next derived class is EnumFieldBase<RecordT>,
00601 /// which defines the virtual API for talking to a given enum field
00602 /// in a given record.  The next derived class is EnumField<RecordT, EnumT>,
00603 /// which implements the pointer-to-member and virtual API for a given
00604 /// enum type in a given record class.
00605 ///
00606 /// For example, the Bookmark record class has the following enum field:
00607 ///
00608 /// <pre>
00609 ///     enum BrowserIdentityType
00610 ///     {
00611 ///             IdentityAuto = 0,
00612 ///             IdentityBlackBerry,
00613 ///             IdentityFireFox,
00614 ///             IdentityInternetExplorer,
00615 ///             IdentityUnknown
00616 ///     };
00617 ///     BrowserIdentityType BrowserIdentity;
00618 /// </pre>
00619 ///
00620 /// The EnumConstants class will hold a vector of EnumConstant structs
00621 /// defining each of the identity constants: Auto, BlackBerry, FireFox,
00622 /// InternetExplorer, and Unknown.
00623 ///
00624 /// The derived class EnumFieldBase<Bookmark> will define two additional
00625 /// pure virtual API calls: GetValue(const Bookmark&) and
00626 /// SetValue(Bookmark&, int).
00627 ///
00628 /// Finally, the derived class EnumField<Bookmark,Bookmark::BrowserIdentityType>
00629 /// will implement the virtual API, and contain a pointer-to-member to
00630 /// the Bookmark::BrowserIdentity member field.
00631 ///
00632 /// The FieldHandle<Bookmark> class will hold a pointer to
00633 /// EnumFieldBase<Bookmark>, which can hold a pointer to a specific
00634 /// EnumField<> object, one object for each of Bookmark's enum types,
00635 /// of which there are currently 3.
00636 ///
00637 class BXEXPORT EnumConstants
00638 {
00639 public:
00640         /// This defines one of the enum constants being defined.
00641         /// For example, for an enum declaration like:
00642         /// enum Mine { A, B, C }; then this struct could contain
00643         /// a definition for A, B, or C, but only one at at time.
00644         /// All three would be defined by the EnumConstantList.
00645         struct EnumConstant
00646         {
00647                 const char *Name;               //< C++ name of enum constant
00648                 std::string DisplayName;        //< user-friendly name / meaning
00649                 int Value;                      //< constant enum value
00650 
00651                 EnumConstant(const char *name, const std::string &display,
00652                         int value)
00653                         : Name(name)
00654                         , DisplayName(display)
00655                         , Value(value)
00656                 {
00657                 }
00658         };
00659 
00660         typedef std::vector<EnumConstant>       EnumConstantList;
00661 
00662 private:
00663         EnumConstantList m_constants;
00664 
00665 public:
00666         virtual ~EnumConstants() {}
00667 
00668         /// Adds a constant definition to the list
00669         void AddConstant(const char *name, const std::string &display, int val);
00670 
00671         /// Returns a vector of EnumConstant objects, describing all enum
00672         /// constants valid for this enum field.
00673         const EnumConstantList& GetConstantList() const { return m_constants; }
00674 
00675         /// Returns the EnumConstant for the given value.
00676         /// Throws std::logic_error if not found.
00677         const EnumConstant& GetConstant(int value) const;
00678 
00679         /// Returns the constant name (C++ name) based on the given value.
00680         /// Throws std::logic_error if not found.
00681         const char* GetName(int value) const;
00682 
00683         /// Returns the display name based on the given value.
00684         /// Throws std::logic_error if not found.
00685         const std::string& GetDisplayName(int value) const;
00686 
00687         /// Returns true if the value matches one of the constants in the list.
00688         bool IsConstantValid(int value) const;
00689 };
00690 
00691 //
00692 // FieldValueHandlerBase
00693 //
00694 /// This is a pure virtual base class, defining the various types that
00695 /// record fields can be.  To be able to handle all the types of data
00696 /// in all records, override these virtual functions to do with the
00697 /// data as you wish.
00698 ///
00699 /// All data from the records and fields will be passed in by value.
00700 /// i.e. if field is string data, the overloaded std::string handler
00701 /// will be called, and a refernce to the string will be passed in.
00702 ///
00703 /// The advantage of using this virtual class is that less code will be
00704 /// generated by templates.  The disadvantage is that this is less flexible.
00705 /// You will only get called for one field and record at a time.
00706 /// So you can't do comparisons this way.
00707 ///
00708 class BXEXPORT FieldValueHandlerBase
00709 {
00710 public:
00711         virtual ~FieldValueHandlerBase() {}
00712 
00713         /// For type std::string
00714         virtual void operator()(const std::string &v,
00715                                 const FieldIdentity &id) const = 0;
00716         /// For type EmailAddressList
00717         virtual void operator()(const EmailAddressList &v,
00718                                 const FieldIdentity &id) const = 0;
00719         /// For type Barry::TimeT
00720         virtual void operator()(const Barry::TimeT &v,
00721                                 const FieldIdentity &id) const = 0;
00722         /// For type uint8_t
00723         virtual void operator()(const uint8_t &v,
00724                                 const FieldIdentity &id) const = 0;
00725         /// For type uint16_t
00726         virtual void operator()(const uint16_t &v,
00727                                 const FieldIdentity &id) const = 0;
00728         /// For type uint32_t
00729         virtual void operator()(const uint32_t &v,
00730                                 const FieldIdentity &id) const = 0;
00731         /// For type uint64_t
00732         virtual void operator()(const uint64_t &v,
00733                                 const FieldIdentity &id) const = 0;
00734         /// For type bool
00735         virtual void operator()(const bool &v,
00736                                 const FieldIdentity &id) const = 0;
00737         /// For type int32_t
00738         virtual void operator()(const int32_t &v,
00739                                 const FieldIdentity &id) const = 0;
00740         /// For type EmailList
00741         virtual void operator()(const EmailList &v,
00742                                 const FieldIdentity &id) const = 0;
00743         /// For type Date
00744         virtual void operator()(const Date &v,
00745                                 const FieldIdentity &id) const = 0;
00746         /// For type CategoryList
00747         virtual void operator()(const CategoryList &v,
00748                                 const FieldIdentity &id) const = 0;
00749         /// For type PostalAddress
00750         virtual void operator()(const PostalAddress &v,
00751                                 const FieldIdentity &id) const = 0;
00752         /// For type UnknownsType
00753         virtual void operator()(const UnknownsType &v,
00754                                 const FieldIdentity &id) const = 0;
00755 };
00756 
00757 ///
00758 /// EnumFieldBase<RecordT>
00759 ///
00760 template <class RecordT>
00761 class EnumFieldBase : public EnumConstants
00762 {
00763 public:
00764         /// Return value of enum in rec
00765         virtual int GetValue(const RecordT &rec) const = 0;
00766         /// Set value of enum in rec
00767         /// Throws std::logic_error if value is out of range
00768         virtual void SetValue(RecordT &rec, int value) = 0;
00769 };
00770 
00771 ///
00772 /// EnumField<RecordT, EnumT>
00773 ///
00774 template <class RecordT, class EnumT>
00775 class EnumField : public EnumFieldBase<RecordT>
00776 {
00777         EnumT RecordT::* m_mp;
00778 
00779 public:
00780         explicit EnumField(EnumT RecordT::* mp)
00781                 : m_mp(mp)
00782         {
00783         }
00784 
00785         virtual int GetValue(const RecordT &rec) const
00786         {
00787                 return rec.*m_mp;
00788         }
00789 
00790         virtual void SetValue(RecordT &rec, int value)
00791         {
00792                 if( !this->IsConstantValid(value) )
00793                         throw std::logic_error("Bad enum value in EnumField");
00794                 rec.*m_mp = (EnumT) value;
00795         }
00796 };
00797 
00798 //
00799 // FieldHandle<RecordT>
00800 //
00801 /// This is a template class that handles pointers to members of multiple
00802 /// types of data and multiple types of records.
00803 ///
00804 /// This class contains a union of all known data pointers in all records.
00805 /// Therefore this class can hold a pointer to member of any record class.
00806 ///
00807 /// To do something with the field that this FieldHandle<> class refers to,
00808 /// call either Value() or Member() with appropriate callback functors.
00809 /// Value will pass a reference to the field.  You can use an object
00810 /// derived from FieldValueHandlerBase here.  Member() will pass a pointer
00811 /// to member.  Your functor will need to contain the record data in order
00812 /// to access its data via the pointer to member.
00813 ///
00814 /// The template functor callback that you pass into member must be
00815 /// capable of this:
00816 ///
00817 /// <pre>
00818 ///     template &lt;class RecordT&gt;
00819 ///     struct Callback
00820 ///     {
00821 ///             RecordT m_rec;
00822 ///
00823 ///             void operator()(typename FieldHandle<RecordT>::PostalPointer pp,
00824 ///                     const FieldIdentity &id) const
00825 ///             {
00826 ///                     PostalAddress pa = m_rec.*(pp.m_PostalAddress);
00827 ///                     std::string val = pa.*(pp.m_PostalField);
00828 ///                     ...
00829 ///             }
00830 ///
00831 ///             template &lt;class TypeT&gt;
00832 ///             void operator()(TypeT RecordT::* mp,
00833 ///                             const FieldIdentity &id) const
00834 ///             {
00835 ///                     TypeT val = m_rec.*mp;
00836 ///                     ...
00837 ///             }
00838 ///     };
00839 /// </pre>
00840 ///
00841 /// You don't have to use a TypeT template, but if you don't, then you must
00842 /// support all field types that the record class you're processing uses.
00843 ///
00844 ///
00845 template <class RecordT>
00846 class FieldHandle
00847 {
00848 public:
00849         typedef FieldHandle<RecordT>                    Self;
00850         typedef std::vector<Self>                       ListT;
00851 
00852         // Need to use this in the union, so no constructor allowed
00853         struct PostalPointer
00854         {
00855                 PostalAddress RecordT::* m_PostalAddress;
00856                 std::string PostalAddress::* m_PostalField;
00857         };
00858 
00859         // So use a factory function
00860         static PostalPointer MakePostalPointer(PostalAddress RecordT::* p1,
00861                         std::string PostalAddress::* p2)
00862         {
00863                 PostalPointer pp;
00864                 pp.m_PostalAddress = p1;
00865                 pp.m_PostalField = p2;
00866                 return pp;
00867         }
00868 
00869 private:
00870         union PointerUnion
00871         {
00872                 std::string RecordT::* m_string;                // index 0
00873                 EmailAddressList RecordT::* m_EmailAddressList; // 1
00874                 Barry::TimeT RecordT::* m_time;                 // 2
00875                 PostalPointer m_postal;                         // 3
00876                 uint8_t RecordT::* m_uint8;                     // 4
00877                 uint32_t RecordT::* m_uint32;                   // 5
00878                 EmailList RecordT::* m_EmailList;               // 6
00879                 Date RecordT::* m_Date;                         // 7
00880                 CategoryList RecordT::* m_CategoryList;         // 8
00881 //              GroupLinksType RecordT::* m_GroupLinksType;     // 9
00882                 UnknownsType RecordT::* m_UnknownsType;         // 10
00883                 bool RecordT::* m_bool;                         // 11
00884                 uint64_t RecordT::* m_uint64;                   // 12
00885                 uint16_t RecordT::* m_uint16;                   // 13
00886                 PostalAddress RecordT::* m_PostalAddress;       // 14
00887                 // used by non-union m_enum below:              // 15
00888                 int32_t RecordT::* m_int32;                     // 16
00889         };
00890 
00891         int m_type_index;
00892         PointerUnion m_union;
00893         EnumFieldBase<RecordT> *m_enum; // never freed, since this is a
00894                                         // static list, existing to end of
00895                                         // program lifetime
00896 
00897         FieldIdentity m_id;
00898 
00899 public:
00900         // 0
00901         FieldHandle(std::string RecordT::* mp, const FieldIdentity &id)
00902                 : m_type_index(0)
00903                 , m_enum(0)
00904                 , m_id(id)
00905         {
00906                 m_union.m_string = mp;
00907         }
00908 
00909         // 1
00910         FieldHandle(EmailAddressList RecordT::* mp, const FieldIdentity &id)
00911                 : m_type_index(1)
00912                 , m_enum(0)
00913                 , m_id(id)
00914         {
00915                 m_union.m_EmailAddressList = mp;
00916         }
00917 
00918         // 2
00919         FieldHandle(Barry::TimeT RecordT::* mp, const FieldIdentity &id)
00920                 : m_type_index(2)
00921                 , m_enum(0)
00922                 , m_id(id)
00923         {
00924                 m_union.m_time = mp;
00925         }
00926 
00927         // 3
00928         FieldHandle(const PostalPointer &pp, const FieldIdentity &id)
00929                 : m_type_index(3)
00930                 , m_enum(0)
00931                 , m_id(id)
00932         {
00933                 m_union.m_postal = pp;
00934         }
00935 
00936         // 4
00937         FieldHandle(uint8_t RecordT::* mp, const FieldIdentity &id)
00938                 : m_type_index(4)
00939                 , m_enum(0)
00940                 , m_id(id)
00941         {
00942                 m_union.m_uint8 = mp;
00943         }
00944 
00945         // 5
00946         FieldHandle(uint32_t RecordT::* mp, const FieldIdentity &id)
00947                 : m_type_index(5)
00948                 , m_enum(0)
00949                 , m_id(id)
00950         {
00951                 m_union.m_uint32 = mp;
00952         }
00953 
00954         // 6
00955         FieldHandle(EmailList RecordT::* mp, const FieldIdentity &id)
00956                 : m_type_index(6)
00957                 , m_enum(0)
00958                 , m_id(id)
00959         {
00960                 m_union.m_EmailList = mp;
00961         }
00962 
00963         // 7
00964         FieldHandle(Date RecordT::* mp, const FieldIdentity &id)
00965                 : m_type_index(7)
00966                 , m_enum(0)
00967                 , m_id(id)
00968         {
00969                 m_union.m_Date = mp;
00970         }
00971 
00972         // 8
00973         FieldHandle(CategoryList RecordT::* mp, const FieldIdentity &id)
00974                 : m_type_index(8)
00975                 , m_enum(0)
00976                 , m_id(id)
00977         {
00978                 m_union.m_CategoryList = mp;
00979         }
00980 
00981         // 9
00982 //      FieldHandle(GroupLinksType RecordT::* mp, const FieldIdentity &id)
00983 //              : m_type_index(9)
00984 //              , m_enum(0)
00985 //              , m_id(id)
00986 //      {
00987 //              m_union.m_GroupLinksType = mp;
00988 //      }
00989 
00990         // 10
00991         FieldHandle(UnknownsType RecordT::* mp, const FieldIdentity &id)
00992                 : m_type_index(10)
00993                 , m_enum(0)
00994                 , m_id(id)
00995         {
00996                 m_union.m_UnknownsType = mp;
00997         }
00998 
00999         // 11
01000         FieldHandle(bool RecordT::* mp, const FieldIdentity &id)
01001                 : m_type_index(11)
01002                 , m_enum(0)
01003                 , m_id(id)
01004         {
01005                 m_union.m_bool = mp;
01006         }
01007 
01008         // 12
01009         FieldHandle(uint64_t RecordT::* mp, const FieldIdentity &id)
01010                 : m_type_index(12)
01011                 , m_enum(0)
01012                 , m_id(id)
01013         {
01014                 m_union.m_uint64 = mp;
01015         }
01016 
01017         // 13
01018         FieldHandle(uint16_t RecordT::* mp, const FieldIdentity &id)
01019                 : m_type_index(13)
01020                 , m_enum(0)
01021                 , m_id(id)
01022         {
01023                 m_union.m_uint16 = mp;
01024         }
01025 
01026         // 14
01027         FieldHandle(PostalAddress RecordT::* mp, const FieldIdentity &id)
01028                 : m_type_index(14)
01029                 , m_enum(0)
01030                 , m_id(id)
01031         {
01032                 m_union.m_PostalAddress = mp;
01033         }
01034 
01035         // 15
01036         FieldHandle(EnumFieldBase<RecordT> *enum_, const FieldIdentity &id)
01037                 : m_type_index(15)
01038                 , m_enum(enum_)
01039                 , m_id(id)
01040         {
01041         }
01042 
01043         // 16
01044         FieldHandle(int32_t RecordT::* mp, const FieldIdentity &id)
01045                 : m_type_index(16)
01046                 , m_enum(0)
01047                 , m_id(id)
01048         {
01049                 m_union.m_int32 = mp;
01050         }
01051 
01052         /// Extracts FieldIdentity object from FieldHandle<>
01053         const FieldIdentity& GetIdentity() const { return m_id; }
01054 
01055         /// Calls the matching virtual function in FieldValueHandlerBase,
01056         /// passing in the value of the field that this FieldHandle<>
01057         /// refers to, and a referenct to the FieldIdentity object.
01058         /// Caller must pass in a RecordT object as well.
01059         void Value(const FieldValueHandlerBase &vh, const RecordT &rec) const
01060         {
01061                 switch( m_type_index )
01062                 {
01063                 case 0:
01064                         vh(rec.*(m_union.m_string), m_id);
01065                         break;
01066                 case 1:
01067                         vh(rec.*(m_union.m_EmailAddressList), m_id);
01068                         break;
01069                 case 2:
01070                         vh(rec.*(m_union.m_time), m_id);
01071                         break;
01072                 case 3:
01073                         vh(rec.*(m_union.m_postal.m_PostalAddress).*(m_union.m_postal.m_PostalField), m_id);
01074                         break;
01075                 case 4:
01076                         vh(rec.*(m_union.m_uint8), m_id);
01077                         break;
01078                 case 5:
01079                         vh(rec.*(m_union.m_uint32), m_id);
01080                         break;
01081                 case 6:
01082                         vh(rec.*(m_union.m_EmailList), m_id);
01083                         break;
01084                 case 7:
01085                         vh(rec.*(m_union.m_Date), m_id);
01086                         break;
01087                 case 8:
01088                         vh(rec.*(m_union.m_CategoryList), m_id);
01089                         break;
01090 //              case 9:
01091 //                      vh(rec.*(m_union.m_GroupLinksType), m_id);
01092 //                      break;
01093                 case 10:
01094                         vh(rec.*(m_union.m_UnknownsType), m_id);
01095                         break;
01096                 case 11:
01097                         vh(rec.*(m_union.m_bool), m_id);
01098                         break;
01099                 case 12:
01100                         vh(rec.*(m_union.m_uint64), m_id);
01101                         break;
01102                 case 13:
01103                         vh(rec.*(m_union.m_uint16), m_id);
01104                         break;
01105                 case 14:
01106                         vh(rec.*(m_union.m_PostalAddress), m_id);
01107                         break;
01108                 case 15:
01109                         vh(m_enum->GetValue(rec), m_id);
01110                         break;
01111                 case 16:
01112                         vh(rec.*(m_union.m_int32), m_id);
01113                         break;
01114                 default:
01115                         throw std::logic_error("Unknown field handle type index");
01116                 }
01117         }
01118 
01119         /// Calls the callback functor with two arguments: the pointer to
01120         /// member that this FieldHandle<> contains, and the FieldIdentity
01121         /// object.  It is assumed that the functor will either contain
01122         /// or know where to find one or more records of type RecordT.
01123         template <class CallbackT>
01124         void Member(const CallbackT &func) const
01125         {
01126                 switch( m_type_index )
01127                 {
01128                 case 0:
01129                         func(m_union.m_string, m_id);
01130                         break;
01131                 case 1:
01132                         func(m_union.m_EmailAddressList, m_id);
01133                         break;
01134                 case 2:
01135                         func(m_union.m_time, m_id);
01136                         break;
01137                 case 3:
01138                         func(m_union.m_postal, m_id);
01139                         break;
01140                 case 4:
01141                         func(m_union.m_uint8, m_id);
01142                         break;
01143                 case 5:
01144                         func(m_union.m_uint32, m_id);
01145                         break;
01146                 case 6:
01147                         func(m_union.m_EmailList, m_id);
01148                         break;
01149                 case 7:
01150                         func(m_union.m_Date, m_id);
01151                         break;
01152                 case 8:
01153                         func(m_union.m_CategoryList, m_id);
01154                         break;
01155 //              case 9:
01156 //                      func(m_union.m_GroupLinksType, m_id);
01157 //                      break;
01158                 case 10:
01159                         func(m_union.m_UnknownsType, m_id);
01160                         break;
01161                 case 11:
01162                         func(m_union.m_bool, m_id);
01163                         break;
01164                 case 12:
01165                         func(m_union.m_uint64, m_id);
01166                         break;
01167                 case 13:
01168                         func(m_union.m_uint16, m_id);
01169                         break;
01170                 case 14:
01171                         func(m_union.m_PostalAddress, m_id);
01172                         break;
01173                 case 15:
01174                         func(m_enum, m_id);
01175                         break;
01176                 case 16:
01177                         func(m_union.m_int32, m_id);
01178                         break;
01179                 default:
01180                         throw std::logic_error("Unknown field handle type index");
01181                 }
01182         }
01183 };
01184 
01185 /// Factory function to create a FieldHandle<> object.
01186 template <class RecordT, class TypeT>
01187 FieldHandle<RecordT> MakeFieldHandle(TypeT RecordT::* tp,
01188                                         const FieldIdentity &id)
01189 {
01190         return FieldHandle<RecordT>(tp, id);
01191 }
01192 
01193 /// Calls FieldHandle<>::Member() for each defined field for a given record
01194 /// type.  Takes a FieldHandle<>::ListT containing FieldHandle<> objects,
01195 /// and calls Member(func) for each one.
01196 template <class HandlesT, class CallbackT>
01197 void ForEachField(const HandlesT &handles, const CallbackT &func)
01198 {
01199         typename HandlesT::const_iterator
01200                 b = handles.begin(),
01201                 e = handles.end();
01202         for( ; b != e; ++b ) {
01203                 b->Member(func);
01204         }
01205 }
01206 
01207 /// Calls FieldHandle<>::Value() for each defined field for a given record.
01208 /// Takes a RecordT object and calls Value(vh, rec) for each FieldHandle<>
01209 /// object in the record's FieldHandles set.
01210 template <class RecordT>
01211 void ForEachFieldValue(const RecordT &rec, const FieldValueHandlerBase &vh)
01212 {
01213         typename FieldHandle<RecordT>::ListT::const_iterator
01214                 b = RecordT::GetFieldHandles().begin(),
01215                 e = RecordT::GetFieldHandles().end();
01216         for( ; b != e; ++b ) {
01217                 b->Value(vh, rec);
01218         }
01219 }
01220 
01221 //
01222 // FieldHandle setup macros
01223 //
01224 // #undef and #define the following macros to override these macros for you:
01225 //
01226 //      CONTAINER_OBJECT_NAME - the new FieldHandles will be .push_back()'d into
01227 //                              this container
01228 //      RECORD_CLASS_NAME     - the name of the record class you are defining,
01229 //                              i.e. Barry::Contact, or Barry::Calendar
01230 //
01231 
01232 // plain field, no connection to device field
01233 #define FHP(name, display) \
01234         CONTAINER_OBJECT_NAME.push_back( \
01235                 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
01236                         FieldIdentity(#name, display)))
01237 // record field with direct connection to device field, no LDIF data
01238 #define FHD(name, display, type_code, iconv) \
01239         CONTAINER_OBJECT_NAME.push_back( \
01240                 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
01241                         FieldIdentity(#name, display, type_code, iconv, \
01242                                 0, 0)))
01243 // record field with direct connection to device field, with LDIF data
01244 #define FHL(name, display, type_code, iconv, ldif, oclass) \
01245         CONTAINER_OBJECT_NAME.push_back( \
01246                 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
01247                         FieldIdentity(#name, display, type_code, iconv, \
01248                                 ldif, oclass)))
01249 // a subfield of a conglomerate field, with direct connection to device field,
01250 // with LDIF data
01251 #define FHS(name, subname, display, type, iconv, ldif, oclass) \
01252         CONTAINER_OBJECT_NAME.push_back( \
01253                 FieldHandle<RECORD_CLASS_NAME>( \
01254                         FieldHandle<RECORD_CLASS_NAME>::MakePostalPointer( \
01255                                 &RECORD_CLASS_NAME::name, \
01256                                 &PostalAddress::subname), \
01257                         FieldIdentity(#name "::" #subname, display, \
01258                                 type, iconv, ldif, oclass, \
01259                                 false, #name)))
01260 // record conglomerate field, which has subfields
01261 #define FHC(name, display) \
01262         CONTAINER_OBJECT_NAME.push_back( \
01263                 FieldHandle<RECORD_CLASS_NAME>(&RECORD_CLASS_NAME::name, \
01264                         FieldIdentity(#name, display, \
01265                                 -1, false, 0, 0, true, 0)))
01266 // create a new EnumField<> and add it to the list... use the new_var_name
01267 // to add constants with FHE_CONST below
01268 #define FHE(new_var_name, record_field_type, record_field_name, display) \
01269         EnumField<RECORD_CLASS_NAME, RECORD_CLASS_NAME::record_field_type> \
01270                 *new_var_name = new \
01271                 EnumField<RECORD_CLASS_NAME, RECORD_CLASS_NAME::record_field_type> \
01272                         (&RECORD_CLASS_NAME::record_field_name); \
01273         CONTAINER_OBJECT_NAME.push_back( \
01274                 FieldHandle<RECORD_CLASS_NAME>(new_var_name, \
01275                         FieldIdentity(#record_field_name, display)))
01276 // same as FHE, but for when RECORD_CLASS_NAME is a template argument
01277 #define FHET(new_var_name, record_field_type, record_field_name, display) \
01278         EnumField<RECORD_CLASS_NAME, typename RECORD_CLASS_NAME::record_field_type> \
01279                 *new_var_name = new \
01280                 EnumField<RECORD_CLASS_NAME, typename RECORD_CLASS_NAME::record_field_type> \
01281                         (&RECORD_CLASS_NAME::record_field_name); \
01282         CONTAINER_OBJECT_NAME.push_back( \
01283                 FieldHandle<RECORD_CLASS_NAME>(new_var_name, \
01284                         FieldIdentity(#record_field_name, display)))
01285 // add constant to enum created above
01286 #define FHE_CONST(var, name, display) \
01287         var->AddConstant(#name, display, RECORD_CLASS_NAME::name)
01288 
01289 /// @}
01290 
01291 } // namespace Barry
01292 
01293 
01294 /// \addtogroup RecordParserClasses
01295 ///             Parser and data storage classes.  These classes take a
01296 ///             Database Database record and convert them into C++ objects.
01297 ///             Each of these classes are safe to be used in standard
01298 ///             containers, and are meant to be used in conjunction with the
01299 ///             RecordParser<> template when calling Controller::LoadDatabase().
01300 /// @{
01301 /// @}
01302 
01303 #ifndef __BARRY_LIBRARY_BUILD__
01304 // Include all parser classes, to make it easy for the application to use.
01305 #include "r_calendar.h"
01306 #include "r_calllog.h"
01307 #include "r_bookmark.h"
01308 #include "r_contact.h"
01309 #include "r_cstore.h"
01310 #include "r_memo.h"
01311 #include "r_message.h"
01312 #include "r_servicebook.h"
01313 #include "r_task.h"
01314 #include "r_pin_message.h"
01315 #include "r_saved_message.h"
01316 #include "r_sms.h"
01317 #include "r_folder.h"
01318 #include "r_timezone.h"
01319 #include "r_hhagent.h"
01320 #endif
01321 
01322 #endif
01323