menu: added new Keywords tag to .desktop files
[barry.git] / src / r_bookmark.cc
bloba8aaced1f185e5125d032470fa1f8eb4a535fd1c
1 ///
2 /// \file r_bookmark.cc
3 /// Record parsing class for the phone browser bookmarks database.
4 ///
6 /*
7 Copyright (C) 2008-2010, Nicolas VIVIEN
8 Copyright (C) 2005-2013, Net Direct Inc. (http://www.netdirect.ca/)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "i18n.h"
24 #include "r_bookmark.h"
25 #include "record-internal.h"
26 #include "protostructs.h"
27 #include "data.h"
28 #include "time.h"
29 #include "iconv.h"
30 #include "debug.h"
31 #include <ostream>
32 #include <iomanip>
33 #include <iostream>
34 #include "ios_state.h"
36 using namespace std;
37 using namespace Barry::Protocol;
39 namespace Barry {
41 ///////////////////////////////////////////////////////////////////////////////
42 // Bookmark Class
44 // Bookmark Field Codes
45 #define BMKFC_BOOKMARK_TYPE 0x01
46 #define BMKFC_STRUCT1 0x11
47 #define BMKFC_STRUCT2 0x12
49 #define BMKFC_END 0xffff
51 // Bookmark Struct1 section codes
52 #define BMK1SC_HOMEPAGE_KEY 0x85 // default section on 9550...
53 // has browser dropdown grayed
54 // out
55 #define BMK1SC_BOOKMARK_ID 0x87 // when user adds a bookmark
56 #define BMK1SC_BOOKMARK_ID2 0x84 // only Nicolas sees this?
57 #define BMK1SC_NAME 0x04
58 #define BMK1SC_ICON 0x05
59 #define BMK1SC_FOLDERS 0x81
61 //static FieldLink<Bookmark> BookmarkFieldLinks[] = {
62 // { BMKFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false }
63 //};
65 Bookmark::Bookmark()
67 Clear();
70 Bookmark::~Bookmark()
74 const unsigned char* Bookmark::ParseStruct1Field(const unsigned char *begin,
75 const unsigned char *end,
76 const IConverter *ic)
78 // grab section type
79 const uint8_t type = *begin;
80 begin += 1;
81 if( begin > end )
82 return begin;
84 switch( type )
86 case BMK1SC_HOMEPAGE_KEY:
87 case BMK1SC_BOOKMARK_ID:
88 case BMK1SC_BOOKMARK_ID2:
90 const BookmarkId *id = (const BookmarkId*) begin;
91 begin += BOOKMARK_ID_SIZE;
92 if( begin > end )
93 return begin;
95 // not sure where id->bookmark_id links to, so ignore
96 // for now...
97 Index = id->index;
99 return begin;
101 case BMK1SC_NAME:
102 case BMK1SC_ICON:
104 const VarStringField *f = (const VarStringField*) begin;
105 begin += VARSTRING_FIELD_HEADER_SIZE;
106 if( begin > end )
107 return begin;
109 const uint16_t size = be_btohs(f->be_size);
111 if( f->present == 1) { // if field is defined
112 begin += size;
113 if( begin > end )
114 return begin;
116 switch( type )
118 case BMK1SC_NAME:
119 Name = ParseFieldString(f->data, size);
120 break;
121 case BMK1SC_ICON:
122 Icon = ParseFieldString(f->data, size);
123 break;
124 default:
125 throw std::logic_error("Bookmark: Check case statement. Should never happen.");
126 break;
129 else if( f->present == 0 && size > 0xA0 ) {
130 // FIXME - a size of 0xA5 seems to occasionally
131 // appear, with 5 bytes of id-looking data
132 // we just skip it here.... note this
133 // may be a different field, but it meshes
134 // itself into the ICON section somehow,
135 // that is unclear
137 // example with the A5, before modification to add '?'
138 // Type: 0x11 Data:
139 // 00000000: 85 9b ed ca 13 00 04 01 00 09 48 6f 6d 65 20 50 ..........Home P
140 // 00000010: 61 67 65 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 00 age.............
141 // 00000020: 00 a5 b8 f0 97 e4 3a 00 00 01 ......:...
143 // example without the A5, after record modified:
144 // Type: 0x11 Data:
145 // 00000000: 85 9b ed ca 13 00 04 01 00 0a 48 6f 6d 65 20 50 ..........Home P
146 // 00000010: 61 67 65 3f 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 age?............
147 // 00000020: 00 00 00 00 00 01 ......
150 begin += size & 0x0F;
153 return begin;
155 case BMK1SC_FOLDERS:
157 //const BookmarkFolders *f = (const BookmarkFolders*) begin;
158 begin += BOOKMARK_FOLDERS_HEADER_SIZE;
159 if( begin > end )
160 return begin;
162 // currently don't know how to link these to
163 // anything else in the device.... skipping
165 return begin;
168 case 0x08:
169 isdefined = *b;
170 b += sizeof(uint8_t);
171 if (isdefined == 1) { // if field is defined
172 const uint16_t size = be_btohs(*((const uint16_t *) b));
173 b += sizeof(uint16_t);
174 b += size;
176 break;
179 default:
180 // if we are 3 bytes away from the end, these are the
181 // display, javascript, and browser identity flags
182 // (make sure to account for the type we ate above)
183 if( (end - begin) == 2 ) {
184 if ((Barry::Bookmark::DisplayModeType) *(begin - 3) > Barry::Bookmark::DisplayUnknown)
185 DisplayMode = Barry::Bookmark::DisplayUnknown;
186 else
187 DisplayMode = (Barry::Bookmark::DisplayModeType) *(begin - 3);
189 if ((Barry::Bookmark::JavaScriptModeType) *(begin - 2) > Barry::Bookmark::JavaScriptUnknown)
190 JavaScriptMode = Barry::Bookmark::JavaScriptUnknown;
191 else
192 JavaScriptMode = (Barry::Bookmark::JavaScriptModeType) *(begin - 2);
194 if ((Barry::Bookmark::BrowserIdentityType) *(begin - 1) > Barry::Bookmark::IdentityUnknown)
195 BrowserIdentity = Barry::Bookmark::IdentityUnknown;
196 else
197 BrowserIdentity = (Barry::Bookmark::BrowserIdentityType) *(begin - 1);
199 // if we are at the beginning, this could be the 7750
200 // with its odd no-code ID... the 7750 seems to have
201 // a BOOKMARK_ID record without any code byte,
202 // so check that the data looks like this:
203 // XX XX XX XX 00
204 // with the 4 byte ID and the index of 0, being the
205 // first default bookmark
206 else if( (begin + 3) < end && begin[3] == 0 ) {
207 // recurse into ourselves
208 return ParseStruct1Field(begin + 4, end, ic);
210 else {
211 ddout("Bookmark parser: unknown section type: "
212 << std::hex << (unsigned int) type);
214 break;
217 return begin;
220 const unsigned char* Bookmark::ParseStruct2(const unsigned char *begin,
221 const unsigned char *end,
222 const IConverter *ic)
224 // first field in struct2 seems to always be the URL
226 // grab size and advance over string, checking sizes
227 const StringField *field = (const StringField*) begin;
228 begin += STRING_FIELD_HEADER_SIZE;
229 if( begin > end )
230 return begin;
232 const uint16_t size = be_btohs(field->be_size);
233 begin += sizeof(uint16_t) + size;
234 if( begin > end ) // if begin==end, we are ok
235 return begin;
237 Url = ParseFieldString(field->data, size);
239 // FIXME - more fields after this, but unknown meaning
241 return begin;
244 const unsigned char* Bookmark::ParseField(const unsigned char *begin,
245 const unsigned char *end,
246 const IConverter *ic)
248 const CommonField *field = (const CommonField *) begin;
250 // advance and check size
251 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
252 if( begin > end ) // if begin==end, we are ok
253 return begin;
255 if( !btohs(field->size) ) // if field has no size, something's up
256 return begin;
259 const unsigned char *b = field->u.raw;
260 const unsigned char *e = begin;
262 // handle special cases
263 switch( field->type )
265 case BMKFC_STRUCT1:
266 while (b <= e) {
267 b = ParseStruct1Field(b, e, ic);
269 return b;
271 case BMKFC_BOOKMARK_TYPE:
272 // above size check guarantees at least one byte,
273 // so this is safe
274 if( field->u.raw[0] != 'D' ) {
275 throw Error( _("Bookmark::ParseField: BookmarkType is not 'D'") );
277 return begin;
279 case BMKFC_STRUCT2:
280 begin = ParseStruct2(b, e, ic);
281 return begin;
284 // if still not handled, add to the Unknowns list
285 UnknownField uf;
286 uf.type = field->type;
287 uf.data.assign((const char*)field->u.raw, btohs(field->size));
288 Unknowns.push_back(uf);
290 // return new pointer for next field
291 return begin;
294 void Bookmark::ParseHeader(const Data &data, size_t &offset)
296 // no header in Bookmark records
299 void Bookmark::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
301 const unsigned char *finish = ParseCommonFields(*this,
302 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
303 offset += finish - (data.GetData() + offset);
306 void Bookmark::Validate() const
310 void Bookmark::BuildHeader(Data &data, size_t &offset) const
312 // not yet implemented
315 void Bookmark::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
317 // not yet implemented
320 void Bookmark::Dump(std::ostream &os) const
322 ios_format_state state(os);
324 static const char *DisplayModeName[] = {
325 N_("Automatic"),
326 N_("Enabled"),
327 N_("Disabled"),
328 N_("Unknown")
330 static const char *JavaScriptModeName[] = {
331 N_("Automatic"),
332 N_("Enabled"),
333 N_("Disabled"),
334 N_("Unknown")
336 static const char *BrowserIdentityName[] = {
337 N_("Automatic"),
338 N_("BlackBerry"),
339 N_("FireFox"),
340 N_("Internet Explorer"),
341 N_("Unknown")
344 os << _("Bookmark entry: ") << "0x" << setbase(16) << RecordId
345 << " (" << (unsigned int)RecType << ")"
346 << " (" << _("index ") << (unsigned int)Index << ")\n";
348 if( Name.size() )
349 os << _(" Name: ") << Name << "\n";
350 if( Icon.size() )
351 os << _(" Icon: ") << Icon << "\n";
352 if( Url.size() )
353 os << _(" Url: ") << Url << "\n";
354 os << _(" Display mode: ")
355 << gettext( DisplayModeName[DisplayMode] ) << "\n";
356 os << _(" JavaScript mode: ")
357 << gettext( JavaScriptModeName[JavaScriptMode] ) << "\n";
358 os << _(" Browser Identity: ")
359 << gettext( BrowserIdentityName[BrowserIdentity] ) << "\n";
361 os << Unknowns;
362 os << "\n\n";
365 bool Bookmark::operator<(const Bookmark &other) const
367 int cmp = Name.compare(other.Name);
368 return cmp < 0;
371 void Bookmark::Clear()
373 RecType = GetDefaultRecType();
374 RecordId = 0;
375 Index = 0;
377 Name.clear();
378 Icon.clear();
379 Url.clear();
381 BrowserIdentity = IdentityUnknown;
382 DisplayMode = DisplayUnknown;
383 JavaScriptMode = JavaScriptUnknown;
385 Unknowns.clear();
388 const FieldHandle<Bookmark>::ListT& Bookmark::GetFieldHandles()
390 static FieldHandle<Bookmark>::ListT fhv;
392 if( fhv.size() )
393 return fhv;
395 #undef CONTAINER_OBJECT_NAME
396 #define CONTAINER_OBJECT_NAME fhv
398 #undef RECORD_CLASS_NAME
399 #define RECORD_CLASS_NAME Bookmark
401 FHP(RecType, _("Record Type"));
402 FHP(RecordId, _("Unique Record ID"));
404 FHP(Index, _("Bookmark Field Index"));
406 FHP(Name, _("Site Name"));
407 FHP(Icon, _("Site Icon"));
408 FHP(Url, _("Site URL"));
410 FHE(bit, BrowserIdentityType, BrowserIdentity, _("Browser Identity"));
411 FHE_CONST(bit, IdentityAuto, _("Auto detect browser"));
412 FHE_CONST(bit, IdentityBlackBerry, _("BlackBerry browser"));
413 FHE_CONST(bit, IdentityFireFox, _("FireFox browser"));
414 FHE_CONST(bit, IdentityInternetExplorer, _("Internet Explorer browser"));
415 FHE_CONST(bit, IdentityUnknown, _("Unknown browser"));
417 FHE(dmc, DisplayModeType, DisplayMode, _("Display Mode"));
418 FHE_CONST(dmc, DisplayAuto, _("Automatic"));
419 FHE_CONST(dmc, DisplayColomn, _("Column"));
420 FHE_CONST(dmc, DisplayPage, _("Page"));
421 FHE_CONST(dmc, DisplayUnknown, _("Unknown"));
423 FHE(jsm, JavaScriptModeType, JavaScriptMode, _("JavaScript Mode"));
424 FHE_CONST(jsm, JavaScriptAuto, _("Automatic"));
425 FHE_CONST(jsm, JavaScriptEnabled, _("Enabled"));
426 FHE_CONST(jsm, JavaScriptDisabled, _("Disabled"));
427 FHE_CONST(jsm, JavaScriptUnknown, _("Unknown"));
429 FHP(Unknowns, _("Unknown Fields"));
431 return fhv;
434 std::string Bookmark::GetDescription() const
436 return Name;
439 } // namespace Barry