Bumped copyright dates for 2013
[barry.git] / src / r_hhagent.cc
blobe059b1c2cdafd708d5eab306ebb00e38db81d7fc
1 ///
2 /// \file r_hhagent.cc
3 /// Blackberry database record parser class for Handheld Agent records
4 ///
6 /*
7 Copyright (C) 2011-2013, 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.
22 #include "i18n.h"
23 #include "r_hhagent.h"
24 #include "record-internal.h"
25 #include "protostructs.h"
26 #include "iconv.h"
27 #include "time.h"
28 #include <iostream>
29 #include <sstream>
30 #include <iomanip>
31 #include <string>
32 #include "ios_state.h"
34 #define __DEBUG_MODE__
35 #include "debug.h"
37 using namespace std;
38 using namespace Barry::Protocol;
40 namespace Barry {
43 ///////////////////////////////////////////////////////////////////////////////
44 // HandheldAgent class
46 // Common field codes
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()
113 Clear();
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
129 return begin;
131 if( !btohs(field->size) ) // if field has no size, something's up
132 return begin;
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 ) {
157 if( b->strMember ) {
158 std::string &s = this->*(b->strMember);
159 s = ParseFieldString(field);
160 if( b->iconvNeeded && ic )
161 s = ic->FromBB(s);
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);
168 return begin;
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));
179 EmailAddress a;
181 // assign first string, using null terminator
182 // letting std::string add it for us if it
183 // doesn't exist
184 a.Email = dual.c_str();
186 // assign second string, using first size
187 // as starting point
188 a.Name = dual.c_str() + a.Email.size() + 1;
190 // if the address is non-empty, add to list
191 if( a.size() ) {
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);
199 al.push_back(a);
202 return begin;
207 // handle special cases
208 // switch( field->type )
209 // {
210 // }
212 // if still not handled, add to the Unknowns list
213 UnknownField uf;
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
219 return begin;
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
244 // Build
246 /// Build fields part of record.
248 void HandheldAgent::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
252 void HandheldAgent::Clear()
254 // clear our fields
255 RecType = GetDefaultRecType();
256 RecordId = 0;
258 MEID.clear();
259 Model.clear();
260 Bands.clear();
261 Pin.clear();
262 Version.clear();
263 PlatformVersion.clear();
264 Manufacturer.clear();
265 Network.clear();
267 Unknowns.clear();
270 const FieldHandle<HandheldAgent>::ListT& HandheldAgent::GetFieldHandles()
272 static FieldHandle<HandheldAgent>::ListT fhv;
274 if( fhv.size() )
275 return 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"));
300 return fhv;
303 std::string HandheldAgent::GetDescription() const
305 ostringstream oss;
306 oss << _("Handheld Agent: ") << "0x" << hex << RecordId;
307 return oss.str();
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;
320 b++ )
322 if( b->strMember ) {
323 const std::string &s = this->*(b->strMember);
324 if( s.size() )
325 os << " " << gettext(b->name) << ": " << s << "\n";
327 else if( b->timeMember ) {
328 TimeT t = this->*(b->timeMember);
329 if( t.Time > 0 )
330 os << " " << gettext(b->name) << ": " << t << "\n";
331 else
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 ) {
339 if( !lb->size() )
340 continue;
342 os << " " << gettext(b->name) << ": " << *lb << "\n";
347 // print any unknowns
348 os << Unknowns;
351 bool HandheldAgent::operator<(const HandheldAgent &other) const
353 return RecordId < other.RecordId;
356 bool HandheldAgent::IsSpecial(uint32_t record_id)
358 return
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
369 // with zeros.
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 ) {
383 return true;
386 return false;
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 ) {
395 return true;
398 return false;
401 std::string HandheldAgent::ESNDec2Hex(const std::string &esn)
403 string empty;
405 if( esn.size() != 11 )
406 return empty;
408 unsigned int part1, part2;
409 istringstream iss(esn.substr(0, 3));
410 iss >> dec >> part1;
411 if( !iss )
412 return empty;
413 iss.str(esn.substr(3));
414 iss.clear();
415 iss >> dec >> part2;
416 if( !iss )
417 return empty;
419 ostringstream oss;
420 oss << setfill('0') << setw(2) << hex << part1;
421 oss << setfill('0') << setw(6) << hex << part2;
422 if( !oss )
423 return empty;
424 return oss.str();
427 std::string HandheldAgent::ESNHex2Dec(const std::string &esn)
429 string empty;
431 if( esn.size() != 8 )
432 return empty;
434 unsigned int part1, part2;
435 istringstream iss(esn.substr(0, 2));
436 iss >> hex >> part1;
437 if( !iss )
438 return empty;
439 iss.str(esn.substr(2));
440 iss.clear();
441 iss >> hex >> part2;
442 if( !iss )
443 return empty;
445 ostringstream oss;
446 oss << setfill('0') << setw(3) << dec << part1;
447 oss << setfill('0') << setw(8) << dec << part2;
448 if( !oss )
449 return empty;
450 return oss.str();
453 } // namespace Barry