r_bookmark.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_bookmark.cc
00003 ///             Record parsing class for the phone browser bookmarks database.
00004 ///
00005 
00006 /*
00007     Copyright (C) 2008-2010, Nicolas VIVIEN
00008     Copyright (C) 2005-2011, 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_bookmark.h"
00024 #include "record-internal.h"
00025 #include "protostructs.h"
00026 #include "data.h"
00027 #include "time.h"
00028 #include "iconv.h"
00029 #include "debug.h"
00030 #include <ostream>
00031 #include <iomanip>
00032 #include <iostream>
00033 
00034 using namespace std;
00035 using namespace Barry::Protocol;
00036 
00037 namespace Barry {
00038 
00039 ///////////////////////////////////////////////////////////////////////////////
00040 // Bookmark Class
00041 
00042 // Bookmark Field Codes
00043 #define BMKFC_BOOKMARK_TYPE             0x01
00044 #define BMKFC_STRUCT1                   0x11
00045 #define BMKFC_STRUCT2                   0x12
00046 
00047 #define BMKFC_END                       0xffff
00048 
00049 // Bookmark Struct1 section codes
00050 #define BMK1SC_HOMEPAGE_KEY             0x85    // default section on 9550...
00051                                                 // has browser dropdown grayed
00052                                                 // out
00053 #define BMK1SC_BOOKMARK_ID              0x87    // when user adds a bookmark
00054 #define BMK1SC_BOOKMARK_ID2             0x84    // only Nicolas sees this?
00055 #define BMK1SC_NAME                     0x04
00056 #define BMK1SC_ICON                     0x05
00057 #define BMK1SC_FOLDERS                  0x81
00058 
00059 static FieldLink<Bookmark> BookmarkFieldLinks[] = {
00060     { BMKFC_END,        "End of List",   0, 0, 0, 0, 0, 0, 0, false }
00061 };
00062 
00063 Bookmark::Bookmark()
00064 {
00065         Clear();
00066 }
00067 
00068 Bookmark::~Bookmark()
00069 {
00070 }
00071 
00072 const unsigned char* Bookmark::ParseStruct1Field(const unsigned char *begin,
00073                                         const unsigned char *end,
00074                                         const IConverter *ic)
00075 {
00076         // grab section type
00077         const uint8_t type = *begin;
00078         begin += 1;
00079         if( begin > end )
00080                 return begin;
00081 
00082         switch( type )
00083         {
00084         case BMK1SC_HOMEPAGE_KEY:
00085         case BMK1SC_BOOKMARK_ID:
00086         case BMK1SC_BOOKMARK_ID2:
00087                 {
00088                         const BookmarkId *id = (const BookmarkId*) begin;
00089                         begin += BOOKMARK_ID_SIZE;
00090                         if( begin > end )
00091                                 return begin;
00092 
00093                         // not sure where id->bookmark_id links to, so ignore
00094                         // for now...
00095                         Index = id->index;
00096                 }
00097                 return begin;
00098 
00099         case BMK1SC_NAME:
00100         case BMK1SC_ICON:
00101                 {
00102                         const VarStringField *f = (const VarStringField*) begin;
00103                         begin += VARSTRING_FIELD_HEADER_SIZE;
00104                         if( begin > end )
00105                                 return begin;
00106 
00107                         const uint16_t size = be_btohs(f->be_size);
00108 
00109                         if( f->present == 1) {  // if field is defined
00110                                 begin += size;
00111                                 if( begin > end )
00112                                         return begin;
00113 
00114                                 switch( type )
00115                                 {
00116                                 case BMK1SC_NAME:
00117                                         Name = ParseFieldString(f->data, size);
00118                                         break;
00119                                 case BMK1SC_ICON:
00120                                         Icon = ParseFieldString(f->data, size);
00121                                         break;
00122                                 default:
00123                                         throw std::logic_error("Check cases");
00124                                         break;
00125                                 }
00126                         }
00127                         else if( f->present == 0 && size > 0xA0 ) {
00128                                 // FIXME - a size of 0xA5 seems to occasionally
00129                                 // appear, with 5 bytes of id-looking data
00130                                 // we just skip it here.... note this
00131                                 // may be a different field, but it meshes
00132                                 // itself into the ICON section somehow,
00133                                 // that is unclear
00134 //
00135 // example with the A5, before modification to add '?'
00136 //    Type: 0x11 Data:
00137 // 00000000: 85 9b ed ca 13 00 04 01 00 09 48 6f 6d 65 20 50  ..........Home P
00138 // 00000010: 61 67 65 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 00  age.............
00139 // 00000020: 00 a5 b8 f0 97 e4 3a 00 00 01                    ......:...
00140 //
00141 // example without the A5, after record modified:
00142 //    Type: 0x11 Data:
00143 // 00000000: 85 9b ed ca 13 00 04 01 00 0a 48 6f 6d 65 20 50  ..........Home P
00144 // 00000010: 61 67 65 3f 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05  age?............
00145 // 00000020: 00 00 00 00 00 01                                ......
00146 //
00147 
00148                                 begin += size & 0x0F;
00149                         }
00150                 }
00151                 return begin;
00152 
00153         case BMK1SC_FOLDERS:
00154                 {
00155                         //const BookmarkFolders *f = (const BookmarkFolders*) begin;
00156                         begin += BOOKMARK_FOLDERS_HEADER_SIZE;
00157                         if( begin > end )
00158                                 return begin;
00159 
00160                         // currently don't know how to link these to
00161                         // anything else in the device.... skipping
00162                 }
00163                 return begin;
00164 
00165 /*
00166         case 0x08:
00167                 isdefined = *b;
00168                 b += sizeof(uint8_t);
00169                 if (isdefined == 1) {   // if field is defined
00170                         const uint16_t size = be_btohs(*((const uint16_t *) b));
00171                         b += sizeof(uint16_t);
00172                         b += size;
00173                 }
00174                 break;
00175 */
00176 
00177         default:
00178                 // if we are 3 bytes away from the end, these are the
00179                 // display, javascript, and browser identity flags
00180                 // (make sure to account for the type we ate above)
00181                 if( (end - begin) == 2 ) {
00182                         if ((Barry::Bookmark::DisplayModeType) *(begin - 3) > Barry::Bookmark::DisplayUnknown)
00183                                 DisplayMode = Barry::Bookmark::DisplayUnknown;
00184                         else
00185                                 DisplayMode = (Barry::Bookmark::DisplayModeType) *(begin - 3);
00186 
00187                         if ((Barry::Bookmark::JavaScriptModeType) *(begin - 2) > Barry::Bookmark::JavaScriptUnknown)
00188                                 JavaScriptMode = Barry::Bookmark::JavaScriptUnknown;
00189                         else
00190                                 JavaScriptMode = (Barry::Bookmark::JavaScriptModeType) *(begin - 2);
00191 
00192                         if ((Barry::Bookmark::BrowserIdentityType) *(begin - 1) > Barry::Bookmark::IdentityUnknown)
00193                                 BrowserIdentity = Barry::Bookmark::IdentityUnknown;
00194                         else
00195                                 BrowserIdentity = (Barry::Bookmark::BrowserIdentityType) *(begin - 1);
00196                 }
00197                 // if we are at the beginning, this could be the 7750
00198                 // with its odd no-code ID... the 7750 seems to have
00199                 // a BOOKMARK_ID record without any code byte,
00200                 // so check that the data looks like this:
00201                 //    XX XX XX XX 00
00202                 // with the 4 byte ID and the index of 0, being the
00203                 // first default bookmark
00204                 else if( (begin + 3) < end && begin[3] == 0 ) {
00205                         // recurse into ourselves
00206                         return ParseStruct1Field(begin + 4, end, ic);
00207                 }
00208                 else {
00209                         ddout("Bookmark parser: unknown section type: "
00210                                 << std::hex << (unsigned int) type);
00211                 }
00212                 break;
00213         }
00214 
00215         return begin;
00216 }
00217 
00218 const unsigned char* Bookmark::ParseStruct2(const unsigned char *begin,
00219                                         const unsigned char *end,
00220                                         const IConverter *ic)
00221 {
00222         // first field in struct2 seems to always be the URL
00223 
00224         // grab size and advance over string, checking sizes
00225         const StringField *field = (const StringField*) begin;
00226         begin += STRING_FIELD_HEADER_SIZE;
00227         if( begin > end )
00228                 return begin;
00229 
00230         const uint16_t size = be_btohs(field->be_size);
00231         begin += sizeof(uint16_t) + size;
00232         if( begin > end )       // if begin==end, we are ok
00233                 return begin;
00234 
00235         Url = ParseFieldString(field->data, size);
00236 
00237         // FIXME - more fields after this, but unknown meaning
00238 
00239         return begin;
00240 }
00241 
00242 const unsigned char* Bookmark::ParseField(const unsigned char *begin,
00243                                       const unsigned char *end,
00244                                       const IConverter *ic)
00245 {
00246         const CommonField *field = (const CommonField *) begin;
00247 
00248         // advance and check size
00249         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00250         if( begin > end )       // if begin==end, we are ok
00251                 return begin;
00252 
00253         if( !btohs(field->size) )   // if field has no size, something's up
00254                 return begin;
00255 
00256 
00257         const unsigned char *b = field->u.raw;
00258         const unsigned char *e = begin;
00259 
00260         // handle special cases
00261         switch( field->type )
00262         {
00263         case BMKFC_STRUCT1:
00264                 while (b <= e) {
00265                         b = ParseStruct1Field(b, e, ic);
00266                 }
00267                 return b;
00268 
00269         case BMKFC_BOOKMARK_TYPE:
00270                 // above size check guarantees at least one byte,
00271                 // so this is safe
00272                 if( field->u.raw[0] != 'D' ) {
00273                         throw Error( "Bookmark::ParseField: BookmarkType is not 'D'" );
00274                 }
00275                 return begin;
00276 
00277         case BMKFC_STRUCT2:
00278                 begin = ParseStruct2(b, e, ic);
00279                 return begin;
00280         }
00281 
00282         // if still not handled, add to the Unknowns list
00283         UnknownField uf;
00284         uf.type = field->type;
00285         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00286         Unknowns.push_back(uf);
00287 
00288         // return new pointer for next field
00289         return begin;
00290 }
00291 
00292 void Bookmark::ParseHeader(const Data &data, size_t &offset)
00293 {
00294         // no header in Bookmark records
00295 }
00296 
00297 void Bookmark::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00298 {
00299         const unsigned char *finish = ParseCommonFields(*this,
00300                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00301         offset += finish - (data.GetData() + offset);
00302 }
00303 
00304 void Bookmark::BuildHeader(Data &data, size_t &offset) const
00305 {
00306         // not yet implemented
00307 }
00308 
00309 void Bookmark::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00310 {
00311         // not yet implemented
00312 }
00313 
00314 void Bookmark::Dump(std::ostream &os) const
00315 {
00316         static const char *DisplayModeName[] = { "Automatic", "Enabled", "Disabled", "Unknown" };
00317         static const char *JavaScriptModeName[] = { "Automatic", "Enabled", "Disabled", "Unknown" };
00318         static const char *BrowserIdentityName[] = { "Automatic", "BlackBerry", "FireFox", "Internet Explorer", "Unknown" };
00319 
00320         os << "Bookmark entry: 0x" << setbase(16) << RecordId
00321            << " (" << (unsigned int)RecType << ")"
00322            << " (index " << (unsigned int)Index << ")\n";
00323 
00324         // cycle through the type table
00325         for(    const FieldLink<Bookmark> *b = BookmarkFieldLinks;
00326                 b->type != BMKFC_END;
00327                 b++ )
00328         {
00329                 if( b->strMember ) {
00330                         const std::string &s = this->*(b->strMember);
00331                         if( s.size() )
00332                                 os << "   " << b->name << ": " << s << "\n";
00333                 }
00334                 else if( b->timeMember ) {
00335                         time_t t = this->*(b->timeMember);
00336                         if( t > 0 )
00337                                 os << "   " << b->name << ": " << ctime(&t);
00338                         else
00339                                 os << "   " << b->name << ": unknown\n";
00340                 }
00341         }
00342 
00343         if( Name.size() )
00344                 os << "                    Name: " << Name << "\n";
00345         if( Icon.size() )
00346                 os << "                    Icon: " << Icon << "\n";
00347         if( Url.size() )
00348                 os << "                     Url: " << Url << "\n";
00349         os << "            Display mode: " << DisplayModeName[DisplayMode] << "\n";
00350         os << "         JavaScript mode: " << JavaScriptModeName[JavaScriptMode] << "\n";
00351         os << "   Browser Identity mode: " << BrowserIdentityName[BrowserIdentity] << "\n";
00352 
00353         os << Unknowns;
00354         os << "\n\n";
00355 }
00356 
00357 bool Bookmark::operator<(const Bookmark &other) const
00358 {
00359         int cmp = Name.compare(other.Name);
00360         return cmp < 0;
00361 }
00362 
00363 void Bookmark::Clear()
00364 {
00365         RecType = GetDefaultRecType();
00366         RecordId = 0;
00367         Index = 0;
00368 
00369         Name.clear();
00370         Icon.clear();
00371         Url.clear();
00372 
00373         BrowserIdentity = IdentityUnknown;
00374         DisplayMode = DisplayUnknown;
00375         JavaScriptMode = JavaScriptUnknown;
00376 
00377         Unknowns.clear();
00378 }
00379 
00380 std::string Bookmark::GetDescription() const
00381 {
00382         return Name;
00383 }
00384 
00385 } // namespace Barry
00386 

Generated on Tue Mar 1 17:50:15 2011 for Barry by  doxygen 1.5.6