3 /// Blackberry database record parser class for Handheld Agent records
7 Copyright (C) 2011-2012, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
23 #include "r_hhagent.h"
24 #include "record-internal.h"
25 #include "protostructs.h"
32 #include "ios_state.h"
34 #define __DEBUG_MODE__
38 using namespace Barry::Protocol
;
43 ///////////////////////////////////////////////////////////////////////////////
44 // HandheldAgent class
47 #define HHAFC_END 0xffff
49 // Field codes for record 3000000
50 #define HHAFC3_MODEL 0x03
51 #define HHAFC3_BANDS 0x07
52 #define HHAFC3_VERSION 0x08
53 #define HHAFC3_NETWORK 0x0f
54 #define HHAFC3_PIN 0x10
55 #define HHAFC3_MEID 0x11
57 // Field codes for record 7000000
58 #define HHAFC7_FIRMWARE 0x13
59 #define HHAFC7_MANUFACTURER 0x14
60 #define HHAFC7_MODEL 0x15
61 #define HHAFC7_PLATFORM 0x17
63 // These fields are only valid for RecordId 0x3000000
64 static FieldLink
<HandheldAgent
> HandheldAgentFieldLinks_3000000
[] = {
65 { HHAFC3_MODEL
, N_("Model"), 0, 0, &HandheldAgent::Model
, 0, 0, 0, 0, true },
66 { HHAFC3_NETWORK
, N_("Network"), 0, 0, &HandheldAgent::Network
, 0, 0, 0, 0, true },
67 { HHAFC3_BANDS
, N_("Bands"), 0, 0, &HandheldAgent::Bands
, 0, 0, 0, 0, true },
68 { HHAFC3_MEID
, N_("MEID/ESN"), 0, 0, &HandheldAgent::MEID
, 0, 0, 0, 0, true },
69 { HHAFC3_PIN
, N_("PIN"), 0, 0, &HandheldAgent::Pin
, 0, 0, 0, 0, true },
70 { HHAFC3_VERSION
, N_("Version"),0, 0, &HandheldAgent::Version
, 0, 0, 0, 0, true },
71 { HHAFC_END
, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false }
74 // These fields are only for RecordId 0x4000000
75 static FieldLink
<HandheldAgent
> HandheldAgentFieldLinks_4000000
[] = {
76 { HHAFC_END
, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false }
79 // These fields are only for RecordId 0x5000000
80 static FieldLink
<HandheldAgent
> HandheldAgentFieldLinks_5000000
[] = {
81 { HHAFC_END
, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false }
84 // These fields are only for RecordId 0x7000000
85 static FieldLink
<HandheldAgent
> HandheldAgentFieldLinks_7000000
[] = {
86 { HHAFC7_MODEL
, N_("Model"), 0, 0, &HandheldAgent::Model
, 0, 0, 0, 0, true },
87 { HHAFC7_MANUFACTURER
,N_("Manufacturer"),0,0,&HandheldAgent::Manufacturer
,0, 0, 0, 0, true },
88 { HHAFC7_FIRMWARE
, N_("Firmware"), 0, 0, &HandheldAgent::Version
, 0, 0, 0, 0, true },
89 { HHAFC7_PLATFORM
, N_("Platform"), 0, 0, &HandheldAgent::PlatformVersion
, 0, 0, 0, 0, true },
90 { HHAFC_END
, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false }
93 // Use this table for default application style records
94 static FieldLink
<HandheldAgent
> HandheldAgentFieldLinks_Default
[] = {
95 { HHAFC_END
, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false }
98 // Use this for display / Dump() etc... includes all fields
99 static FieldLink
<HandheldAgent
> HandheldAgentFieldLinks_All
[] = {
100 { 0, N_("Model"), 0, 0, &HandheldAgent::Model
, 0, 0, 0, 0, true },
101 { 0, N_("Network"), 0, 0, &HandheldAgent::Network
, 0, 0, 0, 0, true },
102 { 0, N_("Manufacturer"),0,0, &HandheldAgent::Manufacturer
,0, 0, 0, 0, true },
103 { 0, N_("Bands"), 0, 0, &HandheldAgent::Bands
, 0, 0, 0, 0, true },
104 { 0, N_("MEID/ESN"), 0, 0, &HandheldAgent::MEID
, 0, 0, 0, 0, true },
105 { 0, N_("PIN"), 0, 0, &HandheldAgent::Pin
, 0, 0, 0, 0, true },
106 { 0, N_("Version"), 0, 0, &HandheldAgent::Version
, 0, 0, 0, 0, true },
107 { 0, N_("Platform"), 0, 0, &HandheldAgent::PlatformVersion
, 0, 0, 0, 0, true },
108 { HHAFC_END
, N_("End of List"),0, 0, 0, 0, 0, 0, 0, false }
111 HandheldAgent::HandheldAgent()
116 HandheldAgent::~HandheldAgent()
120 const unsigned char* HandheldAgent::ParseField(const unsigned char *begin
,
121 const unsigned char *end
,
122 const IConverter
*ic
)
124 const CommonField
*field
= (const CommonField
*) begin
;
126 // advance and check size
127 begin
+= COMMON_FIELD_HEADER_SIZE
+ btohs(field
->size
);
128 if( begin
> end
) // if begin==end, we are ok
131 if( !btohs(field
->size
) ) // if field has no size, something's up
134 // cycle through the type table
135 FieldLink
<HandheldAgent
> *b
= HandheldAgentFieldLinks_Default
;
136 if( RecordId
== 0 ) {
137 // internal consistency check... all parsing code should
138 // call SetIds() first, and HandheldAgent relies on this,
139 // so double check, and throw if not
140 throw std::logic_error(_("HandheldAgent requires SetIds() to be called before ParseField()"));
142 else if( RecordId
== GetMEIDRecordId() ) {
143 b
= HandheldAgentFieldLinks_3000000
;
145 else if( RecordId
== GetUnknown1RecordId() ) {
146 b
= HandheldAgentFieldLinks_4000000
;
148 else if( RecordId
== GetUnknown2RecordId() ) {
149 b
= HandheldAgentFieldLinks_5000000
;
151 else if( RecordId
== GetUnknown3RecordId() ) {
152 b
= HandheldAgentFieldLinks_7000000
;
155 for( ; b
->type
!= HHAFC_END
; b
++ ) {
156 if( b
->type
== field
->type
) {
158 std::string
&s
= this->*(b
->strMember
);
159 s
= ParseFieldString(field
);
160 if( b
->iconvNeeded
&& ic
)
162 return begin
; // done!
164 else if( b
->timeMember
&& btohs(field
->size
) == 4 ) {
165 TimeT
&t
= this->*(b
->timeMember
);
166 dout("min1900: " << field
->u
.min1900
);
167 t
.Time
= min2time(field
->u
.min1900
);
170 else if( b
->addrMember
) {
172 // parse email address
173 // get dual addr+name string first
174 // Note: this is a different format than
175 // used in r_message*.cc
177 std::string
dual((const char*)field
->u
.raw
, btohs(field
->size
));
181 // assign first string, using null terminator
182 // letting std::string add it for us if it
184 a
.Email
= dual
.c_str();
186 // assign second string, using first size
188 a
.Name
= dual
.c_str() + a
.Email
.size() + 1;
190 // if the address is non-empty, add to list
192 // i18n convert if needed
193 if( b
->iconvNeeded
&& ic
) {
194 a
.Name
= ic
->FromBB(a
.Name
);
195 a
.Email
= ic
->FromBB(a
.Email
);
198 EmailAddressList
&al
= this->*(b
->addrMember
);
207 // handle special cases
208 // switch( field->type )
212 // if still not handled, add to the Unknowns list
214 uf
.type
= field
->type
;
215 uf
.data
.assign((const char*)field
->u
.raw
, btohs(field
->size
));
216 Unknowns
.push_back(uf
);
218 // return new pointer for next field
222 void HandheldAgent::ParseHeader(const Data
&data
, size_t &offset
)
224 // no header in HandheldAgent records
227 void HandheldAgent::ParseFields(const Data
&data
, size_t &offset
, const IConverter
*ic
)
229 const unsigned char *finish
= ParseCommonFields(*this,
230 data
.GetData() + offset
, data
.GetData() + data
.GetSize(), ic
);
231 offset
+= finish
- (data
.GetData() + offset
);
234 void HandheldAgent::Validate() const
238 void HandheldAgent::BuildHeader(Data
&data
, size_t &offset
) const
240 // no header in HandheldAgent records
246 /// Build fields part of record.
248 void HandheldAgent::BuildFields(Data
&data
, size_t &offset
, const IConverter
*ic
) const
252 void HandheldAgent::Clear()
255 RecType
= GetDefaultRecType();
263 PlatformVersion
.clear();
264 Manufacturer
.clear();
270 const FieldHandle
<HandheldAgent
>::ListT
& HandheldAgent::GetFieldHandles()
272 static FieldHandle
<HandheldAgent
>::ListT fhv
;
277 #undef CONTAINER_OBJECT_NAME
278 #define CONTAINER_OBJECT_NAME fhv
280 #undef RECORD_CLASS_NAME
281 #define RECORD_CLASS_NAME HandheldAgent
283 FHP(RecType
, _("Record Type Code"));
284 FHP(RecordId
, _("Unique Record ID"));
286 // These fields are only valid for RecordId 0x3000000
287 FHD(MEID
, _("MEID/ESN"), HHAFC3_MEID
, true);
288 FHD(Model
, _("Model"), HHAFC3_MODEL
, true);
289 FHD(Bands
, _("Bands"), HHAFC3_BANDS
, true);
290 FHD(Pin
, _("PIN"), HHAFC3_PIN
, true);
291 FHD(Version
, _("Version"), HHAFC3_VERSION
, true);
292 FHD(Network
, _("Network"), HHAFC3_NETWORK
, true);
294 // These fields are only for RecordId 0x7000000
295 FHD(PlatformVersion
, _("Platform Version"), HHAFC7_PLATFORM
, true);
296 FHD(Manufacturer
, _("Manufacturer"), HHAFC7_MANUFACTURER
, true);
298 FHP(Unknowns
, _("Unknown Fields"));
303 std::string
HandheldAgent::GetDescription() const
306 oss
<< _("Handheld Agent: ") << "0x" << hex
<< RecordId
;
310 void HandheldAgent::Dump(std::ostream
&os
) const
312 ios_format_state
state(os
);
314 os
<< _("HandheldAgent entry: ") << "0x" << hex
<< RecordId
315 << " (" << (unsigned int)RecType
<< ")\n";
317 // cycle through the type table
318 for( const FieldLink
<HandheldAgent
> *b
= HandheldAgentFieldLinks_All
;
319 b
->type
!= HHAFC_END
;
323 const std::string
&s
= this->*(b
->strMember
);
325 os
<< " " << gettext(b
->name
) << ": " << s
<< "\n";
327 else if( b
->timeMember
) {
328 TimeT t
= this->*(b
->timeMember
);
330 os
<< " " << gettext(b
->name
) << ": " << t
<< "\n";
332 os
<< " " << gettext(b
->name
) << ": disabled\n";
334 else if( b
->addrMember
) {
335 const EmailAddressList
&al
= this->*(b
->addrMember
);
336 EmailAddressList::const_iterator lb
= al
.begin(), le
= al
.end();
338 for( ; lb
!= le
; ++lb
) {
342 os
<< " " << gettext(b
->name
) << ": " << *lb
<< "\n";
347 // print any unknowns
351 bool HandheldAgent::operator<(const HandheldAgent
&other
) const
353 return RecordId
< other
.RecordId
;
356 bool HandheldAgent::IsSpecial(uint32_t record_id
)
359 record_id
== GetMEIDRecordId() ||
360 record_id
== GetUnknown1RecordId() ||
361 record_id
== GetUnknown2RecordId() ||
362 record_id
== GetUnknown3RecordId();
366 // The ESN number is in two parts. When in decimal, the first 3
367 // characters are one number, then the rest. In hex, the first 2
368 // digits are the same number, then the rest. Both are padded
371 // For example, hex: 4c070068 dec: 07600458856
372 // hex: [4c]070068 dec: [076]00458856
374 // Returns an empty string on error.
377 bool HandheldAgent::IsESNHex(const std::string
&esn
)
379 const char *hex
= "0123456789ABCDEFabcdef";
380 size_t npos
= string::npos
;
382 if( esn
.size() == 8 && esn
.find_first_not_of(hex
) == npos
) {
389 bool HandheldAgent::IsESNDec(const std::string
&esn
)
391 const char *dec
= "0123456789";
392 size_t npos
= string::npos
;
394 if( esn
.size() == 11 && esn
.find_first_not_of(dec
) == npos
) {
401 std::string
HandheldAgent::ESNDec2Hex(const std::string
&esn
)
405 if( esn
.size() != 11 )
408 unsigned int part1
, part2
;
409 istringstream
iss(esn
.substr(0, 3));
413 iss
.str(esn
.substr(3));
420 oss
<< setfill('0') << setw(2) << hex
<< part1
;
421 oss
<< setfill('0') << setw(6) << hex
<< part2
;
427 std::string
HandheldAgent::ESNHex2Dec(const std::string
&esn
)
431 if( esn
.size() != 8 )
434 unsigned int part1
, part2
;
435 istringstream
iss(esn
.substr(0, 2));
439 iss
.str(esn
.substr(2));
446 oss
<< setfill('0') << setw(3) << dec
<< part1
;
447 oss
<< setfill('0') << setw(8) << dec
<< part2
;