lib: show offset and rectype in HexDumpParser
[barry.git] / src / r_calllog.cc
blob4a94c1ffa388da34c16c4a8cf10cb044061c6509
1 ///
2 /// \file r_calllog.cc
3 /// Record parsing class for the phone call logs database.
4 ///
6 /*
7 Copyright (C) 2008-2009, Nicolas VIVIEN
8 Copyright (C) 2005-2010, 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 "r_calllog.h"
24 #include "record-internal.h"
25 #include "protostructs.h"
26 #include "data.h"
27 #include "time.h"
28 #include "iconv.h"
29 #include <ostream>
30 #include <iomanip>
32 using namespace std;
33 using namespace Barry::Protocol;
35 namespace Barry {
37 #define MILLISECONDS_IN_A_SECOND 1000
39 time_t CallLog::GetTime() const
41 return (time_t)(Timestamp / MILLISECONDS_IN_A_SECOND);
44 CallLog::DirectionFlagType CallLog::DirectionProto2Rec(uint8_t s)
46 return (DirectionFlagType)s;
49 uint8_t CallLog::DirectionRec2Proto(DirectionFlagType s)
51 return s;
54 CallLog::PhoneTypeFlagType CallLog::PhoneTypeProto2Rec(uint8_t s)
56 return (PhoneTypeFlagType)s;
59 uint8_t CallLog::PhoneTypeRec2Proto(PhoneTypeFlagType s)
61 return s;
65 ///////////////////////////////////////////////////////////////////////////////
66 // CallLog Class
68 // CallLog Field Codes
69 #define CLLFC_CALLLOG_TYPE 0x01
70 #define CLLFC_DIRECTION 0x02
71 #define CLLFC_DURATION 0x03
72 #define CLLFC_TIMESTAMP 0x04
73 #define CLLFC_STATUS 0x06
74 #define CLLFC_UNIQUEID 0x07
75 #define CLLFC_PHONE_TYPE 0x0b
76 #define CLLFC_PHONE_NUMBER 0x0c
77 #define CLLFC_PHONE_INFO 0x0d
78 #define CLLFC_CONTACT_NAME 0x1f
79 #define CLLFC_END 0xffff
81 static FieldLink<CallLog> CallLogFieldLinks[] = {
82 { CLLFC_PHONE_NUMBER, "Phone number", 0, 0, &CallLog::PhoneNumber, 0, 0, 0, 0, true },
83 { CLLFC_CONTACT_NAME, "Contact name", 0, 0, &CallLog::ContactName, 0, 0, 0, 0, true },
84 { CLLFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false }
87 CallLog::CallLog()
89 Clear();
92 CallLog::~CallLog()
96 const unsigned char* CallLog::ParseField(const unsigned char *begin,
97 const unsigned char *end,
98 const IConverter *ic)
100 const CommonField *field = (const CommonField *) begin;
102 // advance and check size
103 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
104 if( begin > end ) // if begin==end, we are ok
105 return begin;
107 if( !btohs(field->size) ) // if field has no size, something's up
108 return begin;
110 if( field->type == CLLFC_CALLLOG_TYPE ) {
111 if( field->u.raw[0] != 'p' ) {
112 throw Error( "CallLog::ParseField: CallLogType is not 'p'" );
114 return begin;
117 // this is always the same as the RecordID from the lower level
118 // protocol, so we throw this away for now
119 if( field->type == CLLFC_UNIQUEID)
120 return begin;
122 // cycle through the type table
123 for( FieldLink<CallLog> *b = CallLogFieldLinks;
124 b->type != CLLFC_END;
125 b++ )
127 if( b->type == field->type ) {
128 if( b->strMember ) {
129 std::string &s = this->*(b->strMember);
130 s = ParseFieldString(field);
131 if( b->iconvNeeded && ic )
132 s = ic->FromBB(s);
133 return begin; // done!
135 else if( b->timeMember && btohs(field->size) == 4 ) {
136 time_t &t = this->*(b->timeMember);
137 t = min2time(field->u.min1900);
138 return begin;
143 // handle special cases
144 switch( field->type )
146 case CLLFC_STATUS:
147 // single byte... size check above checks for non-zero already
148 switch (field->u.raw[0]) {
149 case 0x00:
150 StatusFlag = Barry::CallLog::OK;
151 break;
152 case 0x01:
153 StatusFlag = Barry::CallLog::Busy;
154 break;
155 case 0x09:
156 StatusFlag = Barry::CallLog::NetError;
157 break;
158 default:
159 StatusFlag = Barry::CallLog::Unknown;
161 return begin;
163 case CLLFC_DIRECTION:
164 if( field->u.raw[0] > CLL_DIRECTION_RANGE_HIGH ) {
165 throw Error( "CallLog::ParseField: direction field out of bounds" );
167 else {
168 DirectionFlag = DirectionProto2Rec(field->u.raw[0]);
170 return begin;
172 case CLLFC_PHONE_TYPE:
173 if( field->u.raw[0] > CLL_PHONETYPE_RANGE_HIGH ) {
174 PhoneTypeFlag = Barry::CallLog::TypeUnknown;
176 else {
177 PhoneTypeFlag = PhoneTypeProto2Rec(field->u.raw[0]);
179 return begin;
181 case CLLFC_PHONE_INFO:
182 switch (field->u.raw[0]) {
183 case 0x03:
184 PhoneInfoFlag = Barry::CallLog::InfoKnown;
185 break;
186 case 0x80:
187 PhoneInfoFlag = Barry::CallLog::InfoUnknown;
188 break;
189 case 0x40:
190 PhoneInfoFlag = Barry::CallLog::InfoPrivate;
191 break;
192 default:
193 PhoneInfoFlag = Barry::CallLog::InfoUndefined;
195 return begin;
197 case CLLFC_DURATION:
198 if( btohs(field->size) >= sizeof(field->u.uint32) ) {
199 Duration = btohl(field->u.uint32);
200 return begin;
202 break;
204 case CLLFC_TIMESTAMP:
205 if( btohs(field->size) >= sizeof(field->u.timestamp) ) {
206 Timestamp = btohll(field->u.timestamp);
207 return begin;
209 break;
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 CallLog::ParseHeader(const Data &data, size_t &offset)
224 // no header in CallLog records
227 void CallLog::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 CallLog::Dump(std::ostream &os) const
236 uint32_t timestamp = Duration;
237 int32_t days, hours, minutes, secondes;
239 static const char *DirectionName[] = { "Received", "Sent", "Call Missing (Messagerie)", "Call Missing" };
240 static const char *StatusName[] = { "OK", "Busy", "Error", "Not supported by Barry" };
241 static const char *PhoneInfoName[] = { "Undefined", "Known phone number", "Unknown phone number", "Private phone number" };
242 static const char *PhoneTypeName[] = { "Unknown", "Office", "Home", "Mobile", "Not supported by Barry" };
244 os << "CallLog entry: 0x" << setbase(16) << RecordId
245 << " (" << (unsigned int)RecType << ")\n";
247 time_t t = GetTime();
248 os << " Timestamp: " << ctime(&t);
249 os << " Direction: " << DirectionName[DirectionFlag] << "\n";
250 os << " Status: " << StatusName[StatusFlag] << "\n";
251 os << " Phone info: " << PhoneInfoName[PhoneInfoFlag] << "\n";
252 os << " Phone type: " << PhoneTypeName[PhoneTypeFlag] << "\n";
254 os << " Duration: ";
256 // Days :
257 days = (int) (timestamp / (60 * 60 * 24));
258 timestamp = timestamp - (days * (60 * 60 * 24));
259 // Hours :
260 hours = (int) (timestamp / (60 * 60));
261 timestamp = timestamp - (hours * (60 * 60));
262 // Minutes :
263 minutes = (int) (timestamp / 60);
264 timestamp = timestamp - (minutes * 60);
265 // Secondes :
266 secondes = timestamp;
268 if (days > 1)
269 os << setbase(10) << days << " days ";
270 else if (days > 0)
271 os << setbase(10) << days << " day ";
273 os << setfill ('0') << setw(2) << setbase(10) << hours;
274 os << ":";
275 os << setfill ('0') << setw(2) << setbase(10) << minutes;
276 os << ":";
277 os << setfill ('0') << setw(2) << setbase(10) << secondes;
278 os << "\n";
280 // cycle through the type table
281 for( const FieldLink<CallLog> *b = CallLogFieldLinks;
282 b->type != CLLFC_END;
283 b++ )
285 if( b->strMember ) {
286 const std::string &s = this->*(b->strMember);
287 if( s.size() )
288 os << " " << b->name << ": " << s << "\n";
290 else if( b->timeMember ) {
291 time_t t = this->*(b->timeMember);
292 if( t > 0 )
293 os << " " << b->name << ": " << ctime(&t);
294 else
295 os << " " << b->name << ": unknown\n";
300 os << Unknowns;
301 os << "\n\n";
304 void CallLog::Clear()
306 RecType = CallLog::GetDefaultRecType();
308 Duration = 0;
309 Timestamp = 0;
311 ContactName.clear();
312 PhoneNumber.clear();
314 DirectionFlag = Barry::CallLog::Receiver;
315 StatusFlag = Barry::CallLog::Unknown;
316 PhoneTypeFlag = Barry::CallLog::TypeUnknown;
317 PhoneInfoFlag = Barry::CallLog::InfoUndefined;
319 Unknowns.clear();
322 } // namespace Barry