r_servicebook.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_servicebook.cc
00003 ///             Blackberry database record parser class for
00004 ///             Service Book records.
00005 ///
00006 
00007 /*
00008     Copyright (C) 2005-2010, Net Direct Inc. (http://www.netdirect.ca/)
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019     See the GNU General Public License in the COPYING file at the
00020     root directory of this project for more details.
00021 */
00022 
00023 #include "r_servicebook.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 <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 // ServiceBookConfig class
00047 
00048 // service book packed field codes
00049 #define SBFCC_END                       0xffff
00050 
00051 static FieldLink<ServiceBookConfig> ServiceBookConfigFieldLinks[] = {
00052 //   { SBFC_DSID,        "DSID",       0, 0,    &ServiceBook::DSID, 0, 0 },
00053    { SBFCC_END,         "End of List",0, 0,    0, 0, 0 }
00054 };
00055 
00056 ServiceBookConfig::ServiceBookConfig()
00057         : Format(0)
00058 {
00059         Clear();
00060 }
00061 
00062 ServiceBookConfig::~ServiceBookConfig()
00063 {
00064 }
00065 
00066 const unsigned char* ServiceBookConfig::ParseField(const unsigned char *begin,
00067                                                    const unsigned char *end,
00068                                                    const IConverter *ic)
00069 {
00070         const void *raw;
00071         uint16_t size, type;
00072 
00073         switch( Format )
00074         {
00075         case 0x01:
00076         case 0x02:
00077                 {
00078                         const PackedField_02 *field = (const PackedField_02 *) begin;
00079                         raw = field->raw;
00080                         size = field->size;
00081                         type = field->type;
00082                         begin += PACKED_FIELD_02_HEADER_SIZE + size;
00083                 }
00084                 break;
00085 
00086         case 0x10:
00087                 {
00088                         const PackedField_10 *field = (const PackedField_10 *) begin;
00089                         raw = field->raw;
00090                         size = field->size;
00091                         type = field->type;
00092                         begin += PACKED_FIELD_10_HEADER_SIZE + size;
00093                 }
00094                 break;
00095 
00096         default:
00097                 eout("------> Unknown packed field format: 0x" << std::hex <<
00098                         (unsigned int) Format);
00099                 throw BadPackedFormat(Format);
00100                 return begin + 1;
00101         }
00102 
00103 
00104         // check size
00105         if( begin > end )               // if begin==end, we are ok
00106                 return begin;
00107 
00108         if( !size )             // if field has no size, something's up
00109                 return begin;
00110 
00111         // cycle through the type table
00112         for(    FieldLink<ServiceBookConfig> *b = ServiceBookConfigFieldLinks;
00113                 b->type != SBFCC_END;
00114                 b++ )
00115         {
00116                 if( b->type == type ) {
00117                         if( b->strMember ) {
00118                                 std::string &s = this->*(b->strMember);
00119                                 s = ParseFieldString(raw, size-1);
00120                                 return begin;   // done!
00121                         }
00122                 }
00123         }
00124 
00125 /*
00126         // handle special cases
00127         switch( type )
00128         {
00129         }
00130 */
00131 
00132         // if still not handled, add to the Unknowns list
00133         UnknownField uf;
00134         uf.type = type;
00135         uf.data.assign((const char*)raw, size);
00136         Unknowns.push_back(uf);
00137 
00138         // return new pointer for next field
00139         return begin;
00140 }
00141 
00142 void ServiceBookConfig::ParseHeader(const Data &data, size_t &offset)
00143 {
00144         MAKE_RECORD(const Barry::Protocol::ServiceBookConfigField, sbc, data, offset);
00145         offset += SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE;
00146         if( data.GetSize() >= offset ) {        // size check!
00147                 Format = sbc->format;
00148         }
00149 }
00150 
00151 void ServiceBookConfig::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00152 {
00153         const unsigned char *finish = ParseCommonFields(*this,
00154                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00155         offset += finish - (data.GetData() + offset);
00156 }
00157 
00158 void ServiceBookConfig::BuildHeader(Data &data, size_t &offset) const
00159 {
00160         // make sure there is enough space
00161         data.GetBuffer(offset + SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE);
00162 
00163         MAKE_RECORD(Barry::Protocol::ServiceBookConfigField, sbc, data, offset);
00164         sbc->format = Format;
00165 
00166         offset += SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE;
00167 }
00168 
00169 //
00170 // BuildFields
00171 //
00172 /// Build fields part of record
00173 ///
00174 void ServiceBookConfig::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00175 {
00176         throw std::logic_error("ServiceBookConfig::Build not yet implemented");
00177 }
00178 
00179 void ServiceBookConfig::Clear()
00180 {
00181         Unknowns.clear();
00182 }
00183 
00184 void ServiceBookConfig::Dump(std::ostream &os) const
00185 {
00186         os << "   ServiceBookConfig Format: " << setbase(16) << (uint16_t)Format << "\n";
00187 
00188         // cycle through the type table
00189         for(    const FieldLink<ServiceBookConfig> *b = ServiceBookConfigFieldLinks;
00190                 b->type != SBFCC_END;
00191                 b++ )
00192         {
00193                 if( b->strMember ) {
00194                         const std::string &s = this->*(b->strMember);
00195                         if( s.size() )
00196                                 os << "      " << b->name << ": " << s << "\n";
00197                 }
00198                 else if( b->timeMember ) {
00199                         time_t t = this->*(b->timeMember);
00200                         if( t > 0 )
00201                                 os << "      " << b->name << ": " << ctime(&t);
00202                 }
00203         }
00204 
00205         // print any unknowns
00206         os << Unknowns;
00207         os << "   ------------------- End of Config Field\n";
00208 }
00209 
00210 
00211 ///////////////////////////////////////////////////////////////////////////////
00212 // ServiceBook class
00213 
00214 // service book field codes
00215 #define SBFC_OLD_NAME                   0x01
00216 #define SBFC_HIDDEN_NAME                0x02
00217 #define SBFC_NAME                       0x03
00218 #define SBFC_OLD_UNIQUE_ID              0x06
00219 #define SBFC_UNIQUE_ID                  0x07
00220 #define SBFC_CONTENT_ID                 0x08
00221 #define SBFC_CONFIG                     0x09
00222 #define SBFC_OLD_DESC                   0x32
00223 #define SBFC_DESCRIPTION                0x0f
00224 #define SBFC_DSID                       0xa1
00225 #define SBFC_BES_DOMAIN                 0xa2
00226 #define SBFC_USER_ID                    0xa3
00227 #define SBFC_END                        0xffff
00228 
00229 // private data class, containing internal structures
00230 class ServiceBookData
00231 {
00232 public:
00233         FieldLink<ServiceBook> *m_typeSet;
00234         ServiceBookData(FieldLink<ServiceBook> *typeSet) : m_typeSet(typeSet) {}
00235 };
00236 
00237 // The Old/New tables contain the same fields, but use different
00238 // type codes.  Keeping them separate yet linked makes it possible
00239 // to convert between old and new type codes, while hopefully keeping
00240 // things generic.
00241 static FieldLink<ServiceBook> ServiceBookOldFieldLinks[] = {
00242    { SBFC_OLD_NAME,      "Old Name", 0, 0,     &ServiceBook::Name, 0, 0, 0, 0, true },
00243    { SBFC_OLD_DESC,      "Old Desc", 0, 0,     &ServiceBook::Description, 0, 0, 0, 0, true },
00244    { SBFC_OLD_UNIQUE_ID, "Old UniqueId", 0, 0, &ServiceBook::UniqueId, 0, 0, 0, 0, false },
00245    { SBFC_END,           "End of List", 0, 0,  0, 0, 0, 0, 0, false }
00246 };
00247 
00248 static FieldLink<ServiceBook> ServiceBookNewFieldLinks[] = {
00249    { SBFC_NAME,        "Name", 0, 0,         &ServiceBook::Name, 0, 0, 0, 0, true },
00250    { SBFC_DESCRIPTION, "Description", 0, 0,  &ServiceBook::Description, 0, 0, 0, 0, true },
00251    { SBFC_UNIQUE_ID,   "UniqueId", 0, 0,     &ServiceBook::UniqueId, 0, 0, 0, 0, false },
00252    { SBFC_END,         "End of List", 0, 0,  0, 0, 0, 0, 0, false }
00253 };
00254 
00255 // This table holds all
00256 static FieldLink<ServiceBook> ServiceBookFieldLinks[] = {
00257    { SBFC_HIDDEN_NAME, "Hidden Name",0, 0, &ServiceBook::HiddenName, 0, 0, 0, 0, true },
00258    { SBFC_DSID,        "DSID",       0, 0, &ServiceBook::DSID, 0, 0, 0, 0, false },
00259    { SBFC_CONTENT_ID,  "ContentId",  0, 0, &ServiceBook::ContentId, 0, 0, 0, 0, false },
00260    { SBFC_BES_DOMAIN,  "BES Domain", 0, 0, &ServiceBook::BesDomain, 0, 0, 0, 0, false },
00261    { SBFC_END,         "End of List",0, 0, 0, 0, 0, 0, 0, false }
00262 };
00263 
00264 // Array of conflicting tables only
00265 static FieldLink<ServiceBook> *ServiceBookLinkTable[] = {
00266    ServiceBookOldFieldLinks,
00267    ServiceBookNewFieldLinks,
00268    0
00269 };
00270 
00271 #define FIELDLINK_END 0xffff
00272 
00273 template <class RecordT>
00274 FieldLink<RecordT>* ParseFieldByTable(RecordT *rec,
00275                                       const CommonField *field,
00276                                       const IConverter *ic,
00277                                       FieldLink<RecordT> *links)
00278 {
00279         // cycle through the type table
00280         for( FieldLink<RecordT> *b = links; b->type != FIELDLINK_END; b++ ) {
00281                 if( b->type == field->type ) {
00282                         if( b->strMember ) {
00283                                 std::string &s = rec->*(b->strMember);
00284                                 if( s.size() ) {
00285                                         dout(RecordT::GetDBName() << ": field '" << b->name << "' already has data (" << s << "). Overwriting.");
00286                                 }
00287                                 s = ParseFieldString(field);
00288                                 if( b->iconvNeeded && ic )
00289                                         s = ic->FromBB(s);
00290                                 return links;
00291                         }
00292                         else if( b->timeMember && btohs(field->size) == 4 ) {
00293                                 time_t &t = rec->*(b->timeMember);
00294                                 t = min2time(field->u.min1900);
00295                                 return links;
00296                         }
00297                 }
00298         }
00299         return 0;
00300 }
00301 
00302 template <class RecordT>
00303 FieldLink<RecordT>* ParseFieldByTable(RecordT *rec,
00304                                       const CommonField *field,
00305                                       const IConverter *ic,
00306                                       FieldLink<RecordT> **b)
00307 {
00308         for( ; *b; b++ ) {
00309                 FieldLink<RecordT> *link =
00310                         ParseFieldByTable<RecordT>(rec, field, ic, *b);
00311                 if( link )
00312                         return link;
00313         }
00314         return 0;
00315 }
00316 
00317 ServiceBook::ServiceBook()
00318         : m_data( new ServiceBookData(ServiceBookOldFieldLinks) )
00319         , RecordId(0)
00320 {
00321         Clear();
00322 }
00323 
00324 ServiceBook::~ServiceBook()
00325 {
00326 }
00327 
00328 const unsigned char* ServiceBook::ParseField(const unsigned char *begin,
00329                                              const unsigned char *end,
00330                                              const IConverter *ic)
00331 {
00332         const CommonField *field = (const CommonField *) begin;
00333 
00334         // advance and check size
00335         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00336         if( begin > end )               // if begin==end, we are ok
00337                 return begin;
00338 
00339         if( !btohs(field->size) )       // if field has no size, something's up
00340                 return begin;
00341 
00342         // cycle through the type tables
00343         FieldLink<ServiceBook> *typeSet =
00344                 ParseFieldByTable(this, field, ic, ServiceBookLinkTable);
00345         if( typeSet ) {
00346                 if( m_data->m_typeSet && m_data->m_typeSet != typeSet ) {
00347                         dout("ServiceBook record has a mix of old and new field types.");
00348                 }
00349                 m_data->m_typeSet = typeSet;
00350                 return begin;
00351         }
00352         else {
00353                 if( ParseFieldByTable(this, field, ic, ServiceBookFieldLinks) )
00354                         return begin;   // done!
00355         }
00356 
00357         // handle special cases
00358         switch( field->type )
00359         {
00360         case SBFC_CONFIG:
00361                 try {
00362                         Data config((const void *)field->u.raw, btohs(field->size));
00363                         size_t offset = 0;
00364                         Config.ParseHeader(config, offset);
00365                         Config.ParseFields(config, offset);
00366                         return begin;   // success
00367                 }
00368                 catch( BadPackedFormat & ) {
00369                         // break here so unprocessed raw packet is still
00370                         // visible in dump
00371                         break;
00372                 }
00373         }
00374 
00375         // if still not handled, add to the Unknowns list
00376         UnknownField uf;
00377         uf.type = field->type;
00378         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00379         Unknowns.push_back(uf);
00380 
00381         // return new pointer for next field
00382         return begin;
00383 }
00384 
00385 void ServiceBook::ParseHeader(const Data &data, size_t &offset)
00386 {
00387         // no header in this record (?)
00388 }
00389 
00390 void ServiceBook::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00391 {
00392         const unsigned char *finish = ParseCommonFields(*this,
00393                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00394         offset += finish - (data.GetData() + offset);
00395 }
00396 
00397 void ServiceBook::BuildHeader(Data &data, size_t &offset) const
00398 {
00399         // no header in this record (?)
00400 }
00401 
00402 //
00403 // BuildFields
00404 //
00405 /// Build fields part of record
00406 ///
00407 void ServiceBook::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00408 {
00409         throw std::logic_error("ServiceBook::BuildFields not yet implemented");
00410 }
00411 
00412 void ServiceBook::Clear()
00413 {
00414         m_data->m_typeSet = ServiceBookOldFieldLinks;
00415         Unknowns.clear();
00416         Config.Clear();
00417 }
00418 
00419 inline void FormatStr(std::ostream &os, const char *name, const std::string &str)
00420 {
00421         if( str.size() ) {
00422                 os << "   " << setw(20) << name;
00423                 os << ": " << str << "\n";
00424         }
00425 }
00426 
00427 void ServiceBook::Dump(std::ostream &os) const
00428 {
00429         ios::fmtflags oldflags = os.setf(ios::left);
00430         char fill = os.fill(' ');
00431 
00432         os << "ServiceBook entry: 0x" << setbase(16) << RecordId
00433                 << " (" << (unsigned int)RecType << ")\n";
00434 
00435         FormatStr(os, "Name", Name);
00436         FormatStr(os, "Hidden Name", HiddenName);
00437         FormatStr(os, "Description", Description);
00438         FormatStr(os, "DSID", DSID);
00439         FormatStr(os, "Unique ID", UniqueId);
00440         FormatStr(os, "Content ID", ContentId);
00441         FormatStr(os, "(BES) Domain", BesDomain);
00442 
00443         os << Config;
00444 
00445         // print any unknowns
00446         os << Unknowns;
00447 
00448         // cleanup the stream
00449         os.flags(oldflags);
00450         os.fill(fill);
00451 }
00452 
00453 bool ServiceBook::operator<(const ServiceBook &other) const
00454 {
00455         int cmp = BesDomain.compare(other.BesDomain);
00456         if( cmp == 0 )
00457                 cmp = DSID.compare(other.DSID);
00458         if( cmp == 0 )
00459                 cmp = Name.compare(other.Name);
00460         if( cmp == 0 )
00461                 cmp = UniqueId.compare(other.UniqueId);
00462         return cmp < 0;
00463 }
00464 
00465 } // namespace Barry
00466 
Generated by  doxygen 1.6.2-20100208