lib: added implicit ctor converter from DatabaseDatabase to DBListType
[barry/progweb.git] / src / r_calllog.cc
bloba04d5b81206a71bd775e5dbef320ed7e915d837c
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-2012, 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>
31 #include "ios_state.h"
33 using namespace std;
34 using namespace Barry::Protocol;
36 namespace Barry {
38 #define MILLISECONDS_IN_A_SECOND 1000
40 time_t CallLog::GetTime() const
42 return (time_t)(Timestamp / MILLISECONDS_IN_A_SECOND);
45 CallLog::DirectionFlagType CallLog::DirectionProto2Rec(uint8_t s)
47 return (DirectionFlagType)s;
50 uint8_t CallLog::DirectionRec2Proto(DirectionFlagType s)
52 return s;
55 CallLog::PhoneTypeFlagType CallLog::PhoneTypeProto2Rec(uint8_t s)
57 return (PhoneTypeFlagType)s;
60 uint8_t CallLog::PhoneTypeRec2Proto(PhoneTypeFlagType s)
62 return s;
66 ///////////////////////////////////////////////////////////////////////////////
67 // CallLog Class
69 // CallLog Field Codes
70 #define CLLFC_CALLLOG_TYPE 0x01
71 #define CLLFC_DIRECTION 0x02
72 #define CLLFC_DURATION 0x03
73 #define CLLFC_TIMESTAMP 0x04
74 #define CLLFC_STATUS 0x06
75 #define CLLFC_UNIQUEID 0x07
76 #define CLLFC_PHONE_TYPE 0x0b
77 #define CLLFC_PHONE_NUMBER 0x0c
78 #define CLLFC_PHONE_INFO 0x0d
79 #define CLLFC_CONTACT_NAME 0x1f
80 #define CLLFC_END 0xffff
82 static FieldLink<CallLog> CallLogFieldLinks[] = {
83 { CLLFC_PHONE_NUMBER, "Phone number", 0, 0, &CallLog::PhoneNumber, 0, 0, 0, 0, true },
84 { CLLFC_CONTACT_NAME, "Contact name", 0, 0, &CallLog::ContactName, 0, 0, 0, 0, true },
85 { CLLFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false }
88 CallLog::CallLog()
90 Clear();
93 CallLog::~CallLog()
97 const unsigned char* CallLog::ParseField(const unsigned char *begin,
98 const unsigned char *end,
99 const IConverter *ic)
101 const CommonField *field = (const CommonField *) begin;
103 // advance and check size
104 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
105 if( begin > end ) // if begin==end, we are ok
106 return begin;
108 if( !btohs(field->size) ) // if field has no size, something's up
109 return begin;
111 if( field->type == CLLFC_CALLLOG_TYPE ) {
112 if( field->u.raw[0] != 'p' ) {
113 throw Error( "CallLog::ParseField: CallLogType is not 'p'" );
115 return begin;
118 // this is always the same as the RecordID from the lower level
119 // protocol, so we throw this away for now
120 if( field->type == CLLFC_UNIQUEID)
121 return begin;
123 // cycle through the type table
124 for( FieldLink<CallLog> *b = CallLogFieldLinks;
125 b->type != CLLFC_END;
126 b++ )
128 if( b->type == field->type ) {
129 if( b->strMember ) {
130 std::string &s = this->*(b->strMember);
131 s = ParseFieldString(field);
132 if( b->iconvNeeded && ic )
133 s = ic->FromBB(s);
134 return begin; // done!
136 else if( b->timeMember && btohs(field->size) == 4 ) {
137 TimeT &t = this->*(b->timeMember);
138 t.Time = min2time(field->u.min1900);
139 return begin;
144 // handle special cases
145 switch( field->type )
147 case CLLFC_STATUS:
148 // single byte... size check above checks for non-zero already
149 switch (field->u.raw[0]) {
150 case 0x00:
151 StatusFlag = Barry::CallLog::OK;
152 break;
153 case 0x01:
154 StatusFlag = Barry::CallLog::Busy;
155 break;
156 case 0x09:
157 StatusFlag = Barry::CallLog::NetError;
158 break;
159 default:
160 StatusFlag = Barry::CallLog::Unknown;
162 return begin;
164 case CLLFC_DIRECTION:
165 if( field->u.raw[0] > CLL_DIRECTION_RANGE_HIGH ) {
166 throw Error( "CallLog::ParseField: direction field out of bounds" );
168 else {
169 DirectionFlag = DirectionProto2Rec(field->u.raw[0]);
171 return begin;
173 case CLLFC_PHONE_TYPE:
174 if( field->u.raw[0] > CLL_PHONETYPE_RANGE_HIGH ) {
175 PhoneTypeFlag = Barry::CallLog::TypeUnknown;
177 else {
178 PhoneTypeFlag = PhoneTypeProto2Rec(field->u.raw[0]);
180 return begin;
182 case CLLFC_PHONE_INFO:
183 switch (field->u.raw[0]) {
184 case 0x03:
185 PhoneInfoFlag = Barry::CallLog::InfoKnown;
186 break;
187 case 0x80:
188 PhoneInfoFlag = Barry::CallLog::InfoUnknown;
189 break;
190 case 0x40:
191 PhoneInfoFlag = Barry::CallLog::InfoPrivate;
192 break;
193 default:
194 PhoneInfoFlag = Barry::CallLog::InfoUndefined;
196 return begin;
198 case CLLFC_DURATION:
199 if( btohs(field->size) >= sizeof(field->u.uint32) ) {
200 Duration = btohl(field->u.uint32);
201 return begin;
203 break;
205 case CLLFC_TIMESTAMP:
206 if( btohs(field->size) >= sizeof(field->u.timestamp) ) {
207 Timestamp = btohll(field->u.timestamp);
208 return begin;
210 break;
213 // if still not handled, add to the Unknowns list
214 UnknownField uf;
215 uf.type = field->type;
216 uf.data.assign((const char*)field->u.raw, btohs(field->size));
217 Unknowns.push_back(uf);
219 // return new pointer for next field
220 return begin;
223 void CallLog::ParseHeader(const Data &data, size_t &offset)
225 // no header in CallLog records
228 void CallLog::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
230 const unsigned char *finish = ParseCommonFields(*this,
231 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
232 offset += finish - (data.GetData() + offset);
235 void CallLog::Validate() const
239 void CallLog::BuildHeader(Data &data, size_t &offset) const
241 // not yet implemented
244 void CallLog::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
246 // not yet implemented
249 void CallLog::Dump(std::ostream &os) const
251 ios_format_state state(os);
253 uint32_t timestamp = Duration;
254 int32_t days, hours, minutes, secondes;
256 static const char *DirectionName[] = { "Received", "Sent", "Call Missing (Messagerie)", "Call Missing" };
257 static const char *StatusName[] = { "OK", "Busy", "Error", "Not supported by Barry" };
258 static const char *PhoneInfoName[] = { "Undefined", "Known phone number", "Unknown phone number", "Private phone number" };
259 static const char *PhoneTypeName[] = { "Unknown", "Office", "Home", "Mobile", "Not supported by Barry" };
261 os << "CallLog entry: 0x" << setbase(16) << RecordId
262 << " (" << (unsigned int)RecType << ")\n";
264 time_t t = GetTime();
265 os << " Timestamp: " << ctime(&t);
266 os << " Direction: " << DirectionName[DirectionFlag] << "\n";
267 os << " Status: " << StatusName[StatusFlag] << "\n";
268 os << " Phone info: " << PhoneInfoName[PhoneInfoFlag] << "\n";
269 os << " Phone type: " << PhoneTypeName[PhoneTypeFlag] << "\n";
271 os << " Duration: ";
273 // Days :
274 days = (int) (timestamp / (60 * 60 * 24));
275 timestamp = timestamp - (days * (60 * 60 * 24));
276 // Hours :
277 hours = (int) (timestamp / (60 * 60));
278 timestamp = timestamp - (hours * (60 * 60));
279 // Minutes :
280 minutes = (int) (timestamp / 60);
281 timestamp = timestamp - (minutes * 60);
282 // Secondes :
283 secondes = timestamp;
285 if (days > 1)
286 os << setbase(10) << days << " days ";
287 else if (days > 0)
288 os << setbase(10) << days << " day ";
290 os << setfill ('0') << setw(2) << setbase(10) << hours;
291 os << ":";
292 os << setfill ('0') << setw(2) << setbase(10) << minutes;
293 os << ":";
294 os << setfill ('0') << setw(2) << setbase(10) << secondes;
295 os << "\n";
297 // cycle through the type table
298 for( const FieldLink<CallLog> *b = CallLogFieldLinks;
299 b->type != CLLFC_END;
300 b++ )
302 if( b->strMember ) {
303 const std::string &s = this->*(b->strMember);
304 if( s.size() )
305 os << " " << b->name << ": " << s << "\n";
307 else if( b->timeMember ) {
308 TimeT t = this->*(b->timeMember);
309 if( t.Time > 0 )
310 os << " " << b->name << ": " << t << "\n";
311 else
312 os << " " << b->name << ": unknown\n";
317 os << Unknowns;
318 os << "\n\n";
321 void CallLog::Clear()
323 RecType = GetDefaultRecType();
324 RecordId = 0;
326 Duration = 0;
327 Timestamp = 0;
329 ContactName.clear();
330 PhoneNumber.clear();
332 DirectionFlag = Barry::CallLog::Receiver;
333 StatusFlag = Barry::CallLog::Unknown;
334 PhoneTypeFlag = Barry::CallLog::TypeUnknown;
335 PhoneInfoFlag = Barry::CallLog::InfoUndefined;
337 Unknowns.clear();
340 const FieldHandle<CallLog>::ListT& CallLog::GetFieldHandles()
342 static FieldHandle<CallLog>::ListT fhv;
344 if( fhv.size() )
345 return fhv;
347 #undef CONTAINER_OBJECT_NAME
348 #define CONTAINER_OBJECT_NAME fhv
350 #undef RECORD_CLASS_NAME
351 #define RECORD_CLASS_NAME CallLog
353 FHP(RecType, "Record Type Code");
354 FHP(RecordId, "Unique Record ID");
356 FHD(Duration, "Duration of Call in Seconds", CLLFC_DURATION, false);
357 FHD(Timestamp, "Timestamp of Call in Milliseconds", CLLFC_TIMESTAMP, false);
358 FHD(ContactName, "Contact Name", CLLFC_CONTACT_NAME, true);
359 FHD(PhoneNumber, "Phone Number", CLLFC_PHONE_NUMBER, true);
361 FHE(dft, DirectionFlagType, DirectionFlag, "Direction of Call");
362 FHE_CONST(dft, Receiver, "Received Call");
363 FHE_CONST(dft, Emitter, "Placed the Call");
364 FHE_CONST(dft, Failed, "Failed Call");
365 FHE_CONST(dft, Missing, "Missed Call");
367 FHE(sft, StatusFlagType, StatusFlag, "Status of Call");
368 FHE_CONST(sft, OK, "OK");
369 FHE_CONST(sft, Busy, "Busy");
370 FHE_CONST(sft, NetError, "Network Error");
371 FHE_CONST(sft, Unknown, "Unsupported Status");
373 FHE(ptf, PhoneTypeFlagType, PhoneTypeFlag, "Phone Type");
374 FHE_CONST(ptf, TypeUndefined, "Undefined");
375 FHE_CONST(ptf, TypeOffice, "Office");
376 FHE_CONST(ptf, TypeHome, "Home");
377 FHE_CONST(ptf, TypeMobile, "Mobile");
378 FHE_CONST(ptf, TypeUnknown, "Unknown");
380 FHE(pif, PhoneInfoFlagType, PhoneInfoFlag, "Phone Info");
381 FHE_CONST(pif, InfoUndefined, "Undefined");
382 FHE_CONST(pif, InfoKnown, "Phone Number is Set");
383 FHE_CONST(pif, InfoUnknown, "Phone Number Not Set");
384 FHE_CONST(pif, InfoPrivate, "Phone Number is Private");
386 FHP(Unknowns, "Unknown Fields");
388 return fhv;
391 std::string CallLog::GetDescription() const
393 return ContactName;
396 } // namespace Barry