r_calllog.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_calllog.cc
00003 ///             Record parsing class for the phone call logs database.
00004 ///
00005 
00006 /*
00007     Copyright (C) 2008-2009, Nicolas VIVIEN
00008     Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019     See the GNU General Public License in the COPYING file at the
00020     root directory of this project for more details.
00021 */
00022 
00023 #include "r_calllog.h"
00024 #include "record-internal.h"
00025 #include "protostructs.h"
00026 #include "data.h"
00027 #include "time.h"
00028 #include "iconv.h"
00029 #include <ostream>
00030 #include <iomanip>
00031 #include "ios_state.h"
00032 
00033 using namespace std;
00034 using namespace Barry::Protocol;
00035 
00036 namespace Barry {
00037 
00038 #define MILLISECONDS_IN_A_SECOND 1000
00039 
00040 time_t CallLog::GetTime() const
00041 {
00042         return (time_t)(Timestamp / MILLISECONDS_IN_A_SECOND);
00043 }
00044 
00045 CallLog::DirectionFlagType CallLog::DirectionProto2Rec(uint8_t s)
00046 {
00047         return (DirectionFlagType)s;
00048 }
00049 
00050 uint8_t CallLog::DirectionRec2Proto(DirectionFlagType s)
00051 {
00052         return s;
00053 }
00054 
00055 CallLog::PhoneTypeFlagType CallLog::PhoneTypeProto2Rec(uint8_t s)
00056 {
00057         return (PhoneTypeFlagType)s;
00058 }
00059 
00060 uint8_t CallLog::PhoneTypeRec2Proto(PhoneTypeFlagType s)
00061 {
00062         return s;
00063 }
00064 
00065 
00066 ///////////////////////////////////////////////////////////////////////////////
00067 // CallLog Class
00068 
00069 // CallLog Field Codes
00070 #define CLLFC_CALLLOG_TYPE              0x01
00071 #define CLLFC_DIRECTION                 0x02
00072 #define CLLFC_DURATION                  0x03
00073 #define CLLFC_TIMESTAMP                 0x04
00074 #define CLLFC_STATUS                    0x06
00075 #define CLLFC_UNIQUEID                  0x07
00076 #define CLLFC_PHONE_TYPE                0x0b
00077 #define CLLFC_PHONE_NUMBER              0x0c
00078 #define CLLFC_PHONE_INFO                0x0d
00079 #define CLLFC_CONTACT_NAME              0x1f
00080 #define CLLFC_END                       0xffff
00081 
00082 static FieldLink<CallLog> CallLogFieldLinks[] = {
00083     { CLLFC_PHONE_NUMBER,       "Phone number",  0, 0, &CallLog::PhoneNumber, 0, 0, 0, 0, true },
00084     { CLLFC_CONTACT_NAME,       "Contact name",  0, 0, &CallLog::ContactName, 0, 0, 0, 0, true },
00085     { CLLFC_END,                "End of List",   0, 0, 0, 0, 0, 0, 0, false }
00086 };
00087 
00088 CallLog::CallLog()
00089 {
00090         Clear();
00091 }
00092 
00093 CallLog::~CallLog()
00094 {
00095 }
00096 
00097 const unsigned char* CallLog::ParseField(const unsigned char *begin,
00098                                       const unsigned char *end,
00099                                       const IConverter *ic)
00100 {
00101         const CommonField *field = (const CommonField *) begin;
00102 
00103         // advance and check size
00104         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00105         if( begin > end )       // if begin==end, we are ok
00106                 return begin;
00107 
00108         if( !btohs(field->size) )   // if field has no size, something's up
00109                 return begin;
00110 
00111         if( field->type == CLLFC_CALLLOG_TYPE ) {
00112                 if( field->u.raw[0] != 'p' ) {
00113                         throw Error( "CallLog::ParseField: CallLogType is not 'p'" );
00114                 }
00115                 return begin;
00116         }
00117 
00118         // this is always the same as the RecordID from the lower level
00119         // protocol, so we throw this away for now
00120         if( field->type == CLLFC_UNIQUEID)
00121                 return begin;
00122 
00123         // cycle through the type table
00124         for(    FieldLink<CallLog> *b = CallLogFieldLinks;
00125                 b->type != CLLFC_END;
00126                 b++ )
00127         {
00128                 if( b->type == field->type ) {
00129                         if( b->strMember ) {
00130                                 std::string &s = this->*(b->strMember);
00131                                 s = ParseFieldString(field);
00132                                 if( b->iconvNeeded && ic )
00133                                         s = ic->FromBB(s);
00134                                 return begin;   // done!
00135                         }
00136                         else if( b->timeMember && btohs(field->size) == 4 ) {
00137                                 TimeT &t = this->*(b->timeMember);
00138                                 t.Time = min2time(field->u.min1900);
00139                                 return begin;
00140                         }
00141                 }
00142         }
00143 
00144         // handle special cases
00145         switch( field->type )
00146         {
00147         case CLLFC_STATUS:
00148                 // single byte... size check above checks for non-zero already
00149                 switch (field->u.raw[0]) {
00150                 case 0x00:
00151                         StatusFlag = Barry::CallLog::OK;
00152                         break;
00153                 case 0x01:
00154                         StatusFlag = Barry::CallLog::Busy;
00155                         break;
00156                 case 0x09:
00157                         StatusFlag = Barry::CallLog::NetError;
00158                         break;
00159                 default:
00160                         StatusFlag = Barry::CallLog::Unknown;
00161                 }
00162                 return begin;
00163 
00164         case CLLFC_DIRECTION:
00165                 if( field->u.raw[0] > CLL_DIRECTION_RANGE_HIGH ) {
00166                         throw Error( "CallLog::ParseField: direction field out of bounds" );
00167                 }
00168                 else {
00169                         DirectionFlag = DirectionProto2Rec(field->u.raw[0]);
00170                 }
00171                 return begin;
00172 
00173         case CLLFC_PHONE_TYPE:
00174                 if( field->u.raw[0] > CLL_PHONETYPE_RANGE_HIGH ) {
00175                         PhoneTypeFlag = Barry::CallLog::TypeUnknown;
00176                 }
00177                 else {
00178                         PhoneTypeFlag = PhoneTypeProto2Rec(field->u.raw[0]);
00179                 }
00180                 return begin;
00181 
00182         case CLLFC_PHONE_INFO:
00183                 switch (field->u.raw[0]) {
00184                 case 0x03:
00185                         PhoneInfoFlag = Barry::CallLog::InfoKnown;
00186                         break;
00187                 case 0x80:
00188                         PhoneInfoFlag = Barry::CallLog::InfoUnknown;
00189                         break;
00190                 case 0x40:
00191                         PhoneInfoFlag = Barry::CallLog::InfoPrivate;
00192                         break;
00193                 default:
00194                         PhoneInfoFlag = Barry::CallLog::InfoUndefined;
00195                 }
00196                 return begin;
00197 
00198         case CLLFC_DURATION:
00199                 if( btohs(field->size) >= sizeof(field->u.uint32) ) {
00200                         Duration = btohl(field->u.uint32);
00201                         return begin;
00202                 }
00203                 break;
00204 
00205         case CLLFC_TIMESTAMP:
00206                 if( btohs(field->size) >= sizeof(field->u.timestamp) ) {
00207                         Timestamp = btohll(field->u.timestamp);
00208                         return begin;
00209                 }
00210                 break;
00211         }
00212 
00213         // if still not handled, add to the Unknowns list
00214         UnknownField uf;
00215         uf.type = field->type;
00216         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00217         Unknowns.push_back(uf);
00218 
00219         // return new pointer for next field
00220         return begin;
00221 }
00222 
00223 void CallLog::ParseHeader(const Data &data, size_t &offset)
00224 {
00225         // no header in CallLog records
00226 }
00227 
00228 void CallLog::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00229 {
00230         const unsigned char *finish = ParseCommonFields(*this,
00231                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00232         offset += finish - (data.GetData() + offset);
00233 }
00234 
00235 void CallLog::Validate() const
00236 {
00237 }
00238 
00239 void CallLog::BuildHeader(Data &data, size_t &offset) const
00240 {
00241         // not yet implemented
00242 }
00243 
00244 void CallLog::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00245 {
00246         // not yet implemented
00247 }
00248 
00249 void CallLog::Dump(std::ostream &os) const
00250 {
00251         ios_format_state state(os);
00252 
00253         uint32_t timestamp = Duration;
00254         int32_t days, hours, minutes, secondes;
00255 
00256         static const char *DirectionName[] = { "Received", "Sent", "Call Missing (Messagerie)", "Call Missing" };
00257         static const char *StatusName[] = { "OK", "Busy", "Error", "Not supported by Barry" };
00258         static const char *PhoneInfoName[] = { "Undefined", "Known phone number", "Unknown phone number", "Private phone number" };
00259         static const char *PhoneTypeName[] = { "Unknown", "Office", "Home", "Mobile", "Not supported by Barry" };
00260 
00261         os << "CallLog entry: 0x" << setbase(16) << RecordId
00262            << " (" << (unsigned int)RecType << ")\n";
00263 
00264         time_t t = GetTime();
00265         os << "   Timestamp: " << ctime(&t);
00266         os << "   Direction: " << DirectionName[DirectionFlag] << "\n";
00267         os << "   Status: " << StatusName[StatusFlag] << "\n";
00268         os << "   Phone info: " << PhoneInfoName[PhoneInfoFlag] << "\n";
00269         os << "   Phone type: " << PhoneTypeName[PhoneTypeFlag] << "\n";
00270 
00271         os << "   Duration: ";
00272 
00273         // Days :
00274         days = (int) (timestamp / (60 * 60 * 24));
00275         timestamp = timestamp - (days * (60 * 60 * 24));
00276         // Hours :
00277         hours = (int) (timestamp / (60 * 60));
00278         timestamp = timestamp - (hours * (60 * 60));
00279         // Minutes :
00280         minutes = (int) (timestamp / 60);
00281         timestamp = timestamp - (minutes * 60);
00282         // Secondes :
00283         secondes = timestamp;
00284 
00285         if (days > 1)
00286                 os << setbase(10) << days << " days ";
00287         else if (days > 0)
00288                 os << setbase(10) << days << " day ";
00289 
00290         os << setfill ('0') << setw(2) << setbase(10) << hours;
00291         os << ":";
00292         os << setfill ('0') << setw(2) << setbase(10) << minutes;
00293         os << ":";
00294         os << setfill ('0') << setw(2) << setbase(10) << secondes;
00295         os << "\n";
00296 
00297         // cycle through the type table
00298         for(    const FieldLink<CallLog> *b = CallLogFieldLinks;
00299                 b->type != CLLFC_END;
00300                 b++ )
00301         {
00302                 if( b->strMember ) {
00303                         const std::string &s = this->*(b->strMember);
00304                         if( s.size() )
00305                                 os << "   " << b->name << ": " << s << "\n";
00306                 }
00307                 else if( b->timeMember ) {
00308                         TimeT t = this->*(b->timeMember);
00309                         if( t.Time > 0 )
00310                                 os << "   " << b->name << ": " << t << "\n";
00311                         else
00312                                 os << "   " << b->name << ": unknown\n";
00313                 }
00314         }
00315 
00316 
00317         os << Unknowns;
00318         os << "\n\n";
00319 }
00320 
00321 void CallLog::Clear()
00322 {
00323         RecType = GetDefaultRecType();
00324         RecordId = 0;
00325 
00326         Duration = 0;
00327         Timestamp = 0;
00328 
00329         ContactName.clear();
00330         PhoneNumber.clear();
00331 
00332         DirectionFlag = Barry::CallLog::Receiver;
00333         StatusFlag = Barry::CallLog::Unknown;
00334         PhoneTypeFlag = Barry::CallLog::TypeUnknown;
00335         PhoneInfoFlag = Barry::CallLog::InfoUndefined;
00336 
00337         Unknowns.clear();
00338 }
00339 
00340 const FieldHandle<CallLog>::ListT& CallLog::GetFieldHandles()
00341 {
00342         static FieldHandle<CallLog>::ListT fhv;
00343 
00344         if( fhv.size() )
00345                 return fhv;
00346 
00347 #undef CONTAINER_OBJECT_NAME
00348 #define CONTAINER_OBJECT_NAME fhv
00349 
00350 #undef RECORD_CLASS_NAME
00351 #define RECORD_CLASS_NAME CallLog
00352 
00353         FHP(RecType, "Record Type Code");
00354         FHP(RecordId, "Unique Record ID");
00355 
00356         FHD(Duration, "Duration of Call in Seconds", CLLFC_DURATION, false);
00357         FHD(Timestamp, "Timestamp of Call in Milliseconds", CLLFC_TIMESTAMP, false);
00358         FHD(ContactName, "Contact Name", CLLFC_CONTACT_NAME, true);
00359         FHD(PhoneNumber, "Phone Number", CLLFC_PHONE_NUMBER, true);
00360 
00361         FHE(dft, DirectionFlagType, DirectionFlag, "Direction of Call");
00362         FHE_CONST(dft, Receiver, "Received Call");
00363         FHE_CONST(dft, Emitter, "Placed the Call");
00364         FHE_CONST(dft, Failed, "Failed Call");
00365         FHE_CONST(dft, Missing, "Missed Call");
00366 
00367         FHE(sft, StatusFlagType, StatusFlag, "Status of Call");
00368         FHE_CONST(sft, OK, "OK");
00369         FHE_CONST(sft, Busy, "Busy");
00370         FHE_CONST(sft, NetError, "Network Error");
00371         FHE_CONST(sft, Unknown, "Unsupported Status");
00372 
00373         FHE(ptf, PhoneTypeFlagType, PhoneTypeFlag, "Phone Type");
00374         FHE_CONST(ptf, TypeUndefined, "Undefined");
00375         FHE_CONST(ptf, TypeOffice, "Office");
00376         FHE_CONST(ptf, TypeHome, "Home");
00377         FHE_CONST(ptf, TypeMobile, "Mobile");
00378         FHE_CONST(ptf, TypeUnknown, "Unknown");
00379 
00380         FHE(pif, PhoneInfoFlagType, PhoneInfoFlag, "Phone Info");
00381         FHE_CONST(pif, InfoUndefined, "Undefined");
00382         FHE_CONST(pif, InfoKnown, "Phone Number is Set");
00383         FHE_CONST(pif, InfoUnknown, "Phone Number Not Set");
00384         FHE_CONST(pif, InfoPrivate, "Phone Number is Private");
00385 
00386         FHP(Unknowns, "Unknown Fields");
00387 
00388         return fhv;
00389 }
00390 
00391 std::string CallLog::GetDescription() const
00392 {
00393         return ContactName;
00394 }
00395 
00396 } // namespace Barry
00397