r_hhagent.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_hhagent.cc
00003 ///             Blackberry database record parser class for Handheld Agent records
00004 ///
00005 
00006 /*
00007     Copyright (C) 2011-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_hhagent.h"
00023 #include "record-internal.h"
00024 #include "protostructs.h"
00025 #include "iconv.h"
00026 #include "time.h"
00027 #include <iostream>
00028 #include <sstream>
00029 #include <iomanip>
00030 #include <string>
00031 #include "ios_state.h"
00032 
00033 #define __DEBUG_MODE__
00034 #include "debug.h"
00035 
00036 using namespace std;
00037 using namespace Barry::Protocol;
00038 
00039 namespace Barry {
00040 
00041 
00042 ///////////////////////////////////////////////////////////////////////////////
00043 // HandheldAgent class
00044 
00045 // Common field codes
00046 #define HHAFC_END               0xffff
00047 
00048 // Field codes for record 3000000
00049 #define HHAFC3_MODEL            0x03
00050 #define HHAFC3_BANDS            0x07
00051 #define HHAFC3_VERSION          0x08
00052 #define HHAFC3_NETWORK          0x0f
00053 #define HHAFC3_PIN              0x10
00054 #define HHAFC3_MEID             0x11
00055 
00056 // Field codes for record 7000000
00057 #define HHAFC7_FIRMWARE         0x13
00058 #define HHAFC7_MANUFACTURER     0x14
00059 #define HHAFC7_MODEL            0x15
00060 #define HHAFC7_PLATFORM         0x17
00061 
00062 // These fields are only valid for RecordId 0x3000000
00063 static FieldLink<HandheldAgent> HandheldAgentFieldLinks_3000000[] = {
00064    { HHAFC3_MODEL,     "Model",      0, 0, &HandheldAgent::Model, 0, 0, 0, 0, true },
00065    { HHAFC3_NETWORK,   "Network",    0, 0, &HandheldAgent::Network, 0, 0, 0, 0, true },
00066    { HHAFC3_BANDS,     "Bands",      0, 0, &HandheldAgent::Bands, 0, 0, 0, 0, true },
00067    { HHAFC3_MEID,      "MEID/ESN",   0, 0, &HandheldAgent::MEID, 0, 0, 0, 0, true },
00068    { HHAFC3_PIN,       "PIN",        0, 0, &HandheldAgent::Pin, 0, 0, 0, 0, true },
00069    { HHAFC3_VERSION,   "Version",0, 0, &HandheldAgent::Version, 0, 0, 0, 0, true },
00070    { HHAFC_END,        "End of List",0, 0, 0, 0, 0, 0, 0, false }
00071 };
00072 
00073 // These fields are only for RecordId 0x4000000
00074 static FieldLink<HandheldAgent> HandheldAgentFieldLinks_4000000[] = {
00075    { HHAFC_END,        "End of List",0, 0, 0, 0, 0, 0, 0, false }
00076 };
00077 
00078 // These fields are only for RecordId 0x5000000
00079 static FieldLink<HandheldAgent> HandheldAgentFieldLinks_5000000[] = {
00080    { HHAFC_END,        "End of List",0, 0, 0, 0, 0, 0, 0, false }
00081 };
00082 
00083 // These fields are only for RecordId 0x7000000
00084 static FieldLink<HandheldAgent> HandheldAgentFieldLinks_7000000[] = {
00085    { HHAFC7_MODEL,     "Model",    0, 0, &HandheldAgent::Model, 0, 0, 0, 0, true },
00086    { HHAFC7_MANUFACTURER,"Manufacturer",0,0,&HandheldAgent::Manufacturer,0, 0, 0, 0, true },
00087    { HHAFC7_FIRMWARE,  "Firmware", 0, 0, &HandheldAgent::Version, 0, 0, 0, 0, true },
00088    { HHAFC7_PLATFORM,  "Platform", 0, 0, &HandheldAgent::PlatformVersion, 0, 0, 0, 0, true },
00089    { HHAFC_END,        "End of List",0, 0, 0, 0, 0, 0, 0, false }
00090 };
00091 
00092 // Use this table for default application style records
00093 static FieldLink<HandheldAgent> HandheldAgentFieldLinks_Default[] = {
00094    { HHAFC_END,        "End of List",0, 0, 0, 0, 0, 0, 0, false }
00095 };
00096 
00097 // Use this for display / Dump() etc... includes all fields
00098 static FieldLink<HandheldAgent> HandheldAgentFieldLinks_All[] = {
00099    { 0, "Model",      0, 0, &HandheldAgent::Model, 0, 0, 0, 0, true },
00100    { 0, "Network",    0, 0, &HandheldAgent::Network, 0, 0, 0, 0, true },
00101    { 0, "Manufacturer",0,0, &HandheldAgent::Manufacturer,0, 0, 0, 0, true },
00102    { 0, "Bands",      0, 0, &HandheldAgent::Bands, 0, 0, 0, 0, true },
00103    { 0, "MEID/ESN",   0, 0, &HandheldAgent::MEID, 0, 0, 0, 0, true },
00104    { 0, "PIN",        0, 0, &HandheldAgent::Pin, 0, 0, 0, 0, true },
00105    { 0, "Version",    0, 0, &HandheldAgent::Version, 0, 0, 0, 0, true },
00106    { 0, "Platform",   0, 0, &HandheldAgent::PlatformVersion, 0, 0, 0, 0, true },
00107    { HHAFC_END,        "End of List",0, 0, 0, 0, 0, 0, 0, false }
00108 };
00109 
00110 HandheldAgent::HandheldAgent()
00111 {
00112         Clear();
00113 }
00114 
00115 HandheldAgent::~HandheldAgent()
00116 {
00117 }
00118 
00119 const unsigned char* HandheldAgent::ParseField(const unsigned char *begin,
00120                                           const unsigned char *end,
00121                                           const IConverter *ic)
00122 {
00123         const CommonField *field = (const CommonField *) begin;
00124 
00125         // advance and check size
00126         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00127         if( begin > end )               // if begin==end, we are ok
00128                 return begin;
00129 
00130         if( !btohs(field->size) )       // if field has no size, something's up
00131                 return begin;
00132 
00133         // cycle through the type table
00134         FieldLink<HandheldAgent> *b = HandheldAgentFieldLinks_Default;
00135         if( RecordId == 0 ) {
00136                 // internal consistency check... all parsing code should
00137                 // call SetIds() first, and HandheldAgent relies on this,
00138                 // so double check, and throw if not
00139                 throw std::logic_error("HandheldAgent requires SetIds() to be called before ParseField()");
00140         }
00141         else if( RecordId == GetMEIDRecordId() ) {
00142                 b = HandheldAgentFieldLinks_3000000;
00143         }
00144         else if( RecordId == GetUnknown1RecordId() ) {
00145                 b = HandheldAgentFieldLinks_4000000;
00146         }
00147         else if( RecordId == GetUnknown2RecordId() ) {
00148                 b = HandheldAgentFieldLinks_5000000;
00149         }
00150         else if( RecordId == GetUnknown3RecordId() ) {
00151                 b = HandheldAgentFieldLinks_7000000;
00152         }
00153 
00154         for( ; b->type != HHAFC_END; b++ ) {
00155                 if( b->type == field->type ) {
00156                         if( b->strMember ) {
00157                                 std::string &s = this->*(b->strMember);
00158                                 s = ParseFieldString(field);
00159                                 if( b->iconvNeeded && ic )
00160                                         s = ic->FromBB(s);
00161                                 return begin;   // done!
00162                         }
00163                         else if( b->timeMember && btohs(field->size) == 4 ) {
00164                                 TimeT &t = this->*(b->timeMember);
00165                                 dout("min1900: " << field->u.min1900);
00166                                 t.Time = min2time(field->u.min1900);
00167                                 return begin;
00168                         }
00169                         else if( b->addrMember ) {
00170                                 //
00171                                 // parse email address
00172                                 // get dual addr+name string first
00173                                 // Note: this is a different format than
00174                                 // used in r_message*.cc
00175                                 //
00176                                 std::string dual((const char*)field->u.raw, btohs(field->size));
00177 
00178                                 EmailAddress a;
00179 
00180                                 // assign first string, using null terminator
00181                                 // letting std::string add it for us if it
00182                                 // doesn't exist
00183                                 a.Email = dual.c_str();
00184 
00185                                 // assign second string, using first size
00186                                 // as starting point
00187                                 a.Name = dual.c_str() + a.Email.size() + 1;
00188 
00189                                 // if the address is non-empty, add to list
00190                                 if( a.size() ) {
00191                                         // i18n convert if needed
00192                                         if( b->iconvNeeded && ic ) {
00193                                                 a.Name = ic->FromBB(a.Name);
00194                                                 a.Email = ic->FromBB(a.Email);
00195                                         }
00196 
00197                                         EmailAddressList &al = this->*(b->addrMember);
00198                                         al.push_back(a);
00199                                 }
00200 
00201                                 return begin;
00202                         }
00203                 }
00204         }
00205 
00206         // handle special cases
00207 //      switch( field->type )
00208 //      {
00209 //      }
00210 
00211         // if still not handled, add to the Unknowns list
00212         UnknownField uf;
00213         uf.type = field->type;
00214         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00215         Unknowns.push_back(uf);
00216 
00217         // return new pointer for next field
00218         return begin;
00219 }
00220 
00221 void HandheldAgent::ParseHeader(const Data &data, size_t &offset)
00222 {
00223         // no header in HandheldAgent records
00224 }
00225 
00226 void HandheldAgent::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00227 {
00228         const unsigned char *finish = ParseCommonFields(*this,
00229                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00230         offset += finish - (data.GetData() + offset);
00231 }
00232 
00233 void HandheldAgent::Validate() const
00234 {
00235 }
00236 
00237 void HandheldAgent::BuildHeader(Data &data, size_t &offset) const
00238 {
00239         // no header in HandheldAgent records
00240 }
00241 
00242 //
00243 // Build
00244 //
00245 /// Build fields part of record.
00246 ///
00247 void HandheldAgent::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00248 {
00249 }
00250 
00251 void HandheldAgent::Clear()
00252 {
00253         // clear our fields
00254         RecType = GetDefaultRecType();
00255         RecordId = 0;
00256 
00257         MEID.clear();
00258         Model.clear();
00259         Bands.clear();
00260         Pin.clear();
00261         Version.clear();
00262         PlatformVersion.clear();
00263         Manufacturer.clear();
00264         Network.clear();
00265 
00266         Unknowns.clear();
00267 }
00268 
00269 const FieldHandle<HandheldAgent>::ListT& HandheldAgent::GetFieldHandles()
00270 {
00271         static FieldHandle<HandheldAgent>::ListT fhv;
00272 
00273         if( fhv.size() )
00274                 return fhv;
00275 
00276 #undef CONTAINER_OBJECT_NAME
00277 #define CONTAINER_OBJECT_NAME fhv
00278 
00279 #undef RECORD_CLASS_NAME
00280 #define RECORD_CLASS_NAME HandheldAgent
00281 
00282         FHP(RecType, "Record Type Code");
00283         FHP(RecordId, "Unique Record ID");
00284 
00285         // These fields are only valid for RecordId 0x3000000
00286         FHD(MEID, "MEID/ESN", HHAFC3_MEID, true);
00287         FHD(Model, "Model", HHAFC3_MODEL, true);
00288         FHD(Bands, "Bands", HHAFC3_BANDS, true);
00289         FHD(Pin, "PIN", HHAFC3_PIN, true);
00290         FHD(Version, "Version", HHAFC3_VERSION, true);
00291         FHD(Network, "Network", HHAFC3_NETWORK, true);
00292 
00293         // These fields are only for RecordId 0x7000000
00294         FHD(PlatformVersion, "Platform Version", HHAFC7_PLATFORM, true);
00295         FHD(Manufacturer, "Manufacturer", HHAFC7_MANUFACTURER, true);
00296 
00297         FHP(Unknowns, "Unknown Fields");
00298 
00299         return fhv;
00300 }
00301 
00302 std::string HandheldAgent::GetDescription() const
00303 {
00304         ostringstream oss;
00305         oss << "Handheld Agent: 0x" << hex << RecordId;
00306         return oss.str();
00307 }
00308 
00309 void HandheldAgent::Dump(std::ostream &os) const
00310 {
00311         ios_format_state state(os);
00312 
00313         os << "HandheldAgent entry: 0x" << hex << RecordId
00314                 << " (" << (unsigned int)RecType << ")\n";
00315 
00316         // cycle through the type table
00317         for(    const FieldLink<HandheldAgent> *b = HandheldAgentFieldLinks_All;
00318                 b->type != HHAFC_END;
00319                 b++ )
00320         {
00321                 if( b->strMember ) {
00322                         const std::string &s = this->*(b->strMember);
00323                         if( s.size() )
00324                                 os << "   " << b->name << ": " << s << "\n";
00325                 }
00326                 else if( b->timeMember ) {
00327                         TimeT t = this->*(b->timeMember);
00328                         if( t.Time > 0 )
00329                                 os << "   " << b->name << ": " << t << "\n";
00330                         else
00331                                 os << "   " << b->name << ": disabled\n";
00332                 }
00333                 else if( b->addrMember ) {
00334                         const EmailAddressList &al = this->*(b->addrMember);
00335                         EmailAddressList::const_iterator lb = al.begin(), le = al.end();
00336 
00337                         for( ; lb != le; ++lb ) {
00338                                 if( !lb->size() )
00339                                         continue;
00340 
00341                                 os << "   " << b->name << ": " << *lb << "\n";
00342                         }
00343                 }
00344         }
00345 
00346         // print any unknowns
00347         os << Unknowns;
00348 }
00349 
00350 bool HandheldAgent::operator<(const HandheldAgent &other) const
00351 {
00352         return RecordId < other.RecordId;
00353 }
00354 
00355 bool HandheldAgent::IsSpecial(uint32_t record_id)
00356 {
00357         return
00358                 record_id == GetMEIDRecordId() ||
00359                 record_id == GetUnknown1RecordId() ||
00360                 record_id == GetUnknown2RecordId() ||
00361                 record_id == GetUnknown3RecordId();
00362 }
00363 
00364 //
00365 // The ESN number is in two parts.  When in decimal, the first 3
00366 // characters are one number, then the rest.  In hex, the first 2
00367 // digits are the same number, then the rest.  Both are padded
00368 // with zeros.
00369 //
00370 // For example, hex: 4c070068   dec: 07600458856
00371 //        hex: [4c]070068   dec: [076]00458856
00372 //
00373 // Returns an empty string on error.
00374 //
00375 
00376 bool HandheldAgent::IsESNHex(const std::string &esn)
00377 {
00378         const char *hex = "0123456789ABCDEFabcdef";
00379         size_t npos = string::npos;
00380 
00381         if( esn.size() == 8 && esn.find_first_not_of(hex) == npos ) {
00382                 return true;
00383         }
00384 
00385         return false;
00386 }
00387 
00388 bool HandheldAgent::IsESNDec(const std::string &esn)
00389 {
00390         const char *dec = "0123456789";
00391         size_t npos = string::npos;
00392 
00393         if( esn.size() == 11 && esn.find_first_not_of(dec) == npos ) {
00394                 return true;
00395         }
00396 
00397         return false;
00398 }
00399 
00400 std::string HandheldAgent::ESNDec2Hex(const std::string &esn)
00401 {
00402         string empty;
00403 
00404         if( esn.size() != 11 )
00405                 return empty;
00406 
00407         unsigned int part1, part2;
00408         istringstream iss(esn.substr(0, 3));
00409         iss >> dec >> part1;
00410         if( !iss )
00411                 return empty;
00412         iss.str(esn.substr(3));
00413         iss.clear();
00414         iss >> dec >> part2;
00415         if( !iss )
00416                 return empty;
00417 
00418         ostringstream oss;
00419         oss << setfill('0') << setw(2) << hex << part1;
00420         oss << setfill('0') << setw(6) << hex << part2;
00421         if( !oss )
00422                 return empty;
00423         return oss.str();
00424 }
00425 
00426 std::string HandheldAgent::ESNHex2Dec(const std::string &esn)
00427 {
00428         string empty;
00429 
00430         if( esn.size() != 8 )
00431                 return empty;
00432 
00433         unsigned int part1, part2;
00434         istringstream iss(esn.substr(0, 2));
00435         iss >> hex >> part1;
00436         if( !iss )
00437                 return empty;
00438         iss.str(esn.substr(2));
00439         iss.clear();
00440         iss >> hex >> part2;
00441         if( !iss )
00442                 return empty;
00443 
00444         ostringstream oss;
00445         oss << setfill('0') << setw(3) << dec << part1;
00446         oss << setfill('0') << setw(8) << dec << part2;
00447         if( !oss )
00448                 return empty;
00449         return oss.str();
00450 }
00451 
00452 } // namespace Barry
00453