# 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