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