# 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-2011, 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
    00032 using namespace std;
    00033 using namespace Barry::Protocol;
    00034
    00035 namespace Barry {
    00036
    00037 #define MILLISECONDS_IN_A_SECOND 1000
    00038
    00039 time_t CallLog::GetTime() const
    00040 {
    00041         return (time_t)(Timestamp / MILLISECONDS_IN_A_SECOND);
    00042 }
    00043
    00044 CallLog::DirectionFlagType CallLog::DirectionProto2Rec(uint8_t s)
    00045 {
    00046         return (DirectionFlagType)s;
    00047 }
    00048
    00049 uint8_t CallLog::DirectionRec2Proto(DirectionFlagType s)
    00050 {
    00051         return s;
    00052 }
    00053
    00054 CallLog::PhoneTypeFlagType CallLog::PhoneTypeProto2Rec(uint8_t s)
    00055 {
    00056         return (PhoneTypeFlagType)s;
    00057 }
    00058
    00059 uint8_t CallLog::PhoneTypeRec2Proto(PhoneTypeFlagType s)
    00060 {
    00061         return s;
    00062 }
    00063
    00064
    00065 ///////////////////////////////////////////////////////////////////////////////
    00066 // CallLog Class
    00067
    00068 // CallLog Field Codes
    00069 #define CLLFC_CALLLOG_TYPE              0x01
    00070 #define CLLFC_DIRECTION                 0x02
    00071 #define CLLFC_DURATION                  0x03
    00072 #define CLLFC_TIMESTAMP                 0x04
    00073 #define CLLFC_STATUS                    0x06
    00074 #define CLLFC_UNIQUEID                  0x07
    00075 #define CLLFC_PHONE_TYPE                0x0b
    00076 #define CLLFC_PHONE_NUMBER              0x0c
    00077 #define CLLFC_PHONE_INFO                0x0d
    00078 #define CLLFC_CONTACT_NAME              0x1f
    00079 #define CLLFC_END                       0xffff
    00080
    00081 static FieldLink<CallLog> CallLogFieldLinks[] = {
    00082     { CLLFC_PHONE_NUMBER,       "Phone number",  0, 0, &CallLog::PhoneNumber, 0, 0, 0, 0, true },
    00083     { CLLFC_CONTACT_NAME,       "Contact name",  0, 0, &CallLog::ContactName, 0, 0, 0, 0, true },
    00084     { CLLFC_END,                "End of List",   0, 0, 0, 0, 0, 0, 0, false }
    00085 };
    00086
    00087 CallLog::CallLog()
    00088 {
    00089         Clear();
    00090 }
    00091
    00092 CallLog::~CallLog()
    00093 {
    00094 }
    00095
    00096 const unsigned char* CallLog::ParseField(const unsigned char *begin,
    00097                                       const unsigned char *end,
    00098                                       const IConverter *ic)
    00099 {
    00100         const CommonField *field = (const CommonField *) begin;
    00101
    00102         // advance and check size
    00103         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
    00104         if( begin > end )       // if begin==end, we are ok
    00105                 return begin;
    00106
    00107         if( !btohs(field->size) )   // if field has no size, something's up
    00108                 return begin;
    00109
    00110         if( field->type == CLLFC_CALLLOG_TYPE ) {
    00111                 if( field->u.raw[0] != 'p' ) {
    00112                         throw Error( "CallLog::ParseField: CallLogType is not 'p'" );
    00113                 }
    00114                 return begin;
    00115         }
    00116
    00117         // this is always the same as the RecordID from the lower level
    00118         // protocol, so we throw this away for now
    00119         if( field->type == CLLFC_UNIQUEID)
    00120                 return begin;
    00121
    00122         // cycle through the type table
    00123         for(    FieldLink<CallLog> *b = CallLogFieldLinks;
    00124                 b->type != CLLFC_END;
    00125                 b++ )
    00126         {
    00127                 if( b->type == field->type ) {
    00128                         if( b->strMember ) {
    00129                                 std::string &s = this->*(b->strMember);
    00130                                 s = ParseFieldString(field);
    00131                                 if( b->iconvNeeded && ic )
    00132                                         s = ic->FromBB(s);
    00133                                 return begin;   // done!
    00134                         }
    00135                         else if( b->timeMember && btohs(field->size) == 4 ) {
    00136                                 time_t &t = this->*(b->timeMember);
    00137                                 t = min2time(field->u.min1900);
    00138                                 return begin;
    00139                         }
    00140                 }
    00141         }
    00142
    00143         // handle special cases
    00144         switch( field->type )
    00145         {
    00146         case CLLFC_STATUS:
    00147                 // single byte... size check above checks for non-zero already
    00148                 switch (field->u.raw[0]) {
    00149                 case 0x00:
    00150                         StatusFlag = Barry::CallLog::OK;
    00151                         break;
    00152                 case 0x01:
    00153                         StatusFlag = Barry::CallLog::Busy;
    00154                         break;
    00155                 case 0x09:
    00156                         StatusFlag = Barry::CallLog::NetError;
    00157                         break;
    00158                 default:
    00159                         StatusFlag = Barry::CallLog::Unknown;
    00160                 }
    00161                 return begin;
    00162
    00163         case CLLFC_DIRECTION:
    00164                 if( field->u.raw[0] > CLL_DIRECTION_RANGE_HIGH ) {
    00165                         throw Error( "CallLog::ParseField: direction field out of bounds" );
    00166                 }
    00167                 else {
    00168                         DirectionFlag = DirectionProto2Rec(field->u.raw[0]);
    00169                 }
    00170                 return begin;
    00171
    00172         case CLLFC_PHONE_TYPE:
    00173                 if( field->u.raw[0] > CLL_PHONETYPE_RANGE_HIGH ) {
    00174                         PhoneTypeFlag = Barry::CallLog::TypeUnknown;
    00175                 }
    00176                 else {
    00177                         PhoneTypeFlag = PhoneTypeProto2Rec(field->u.raw[0]);
    00178                 }
    00179                 return begin;
    00180
    00181         case CLLFC_PHONE_INFO:
    00182                 switch (field->u.raw[0]) {
    00183                 case 0x03:
    00184                         PhoneInfoFlag = Barry::CallLog::InfoKnown;
    00185                         break;
    00186                 case 0x80:
    00187                         PhoneInfoFlag = Barry::CallLog::InfoUnknown;
    00188                         break;
    00189                 case 0x40:
    00190                         PhoneInfoFlag = Barry::CallLog::InfoPrivate;
    00191                         break;
    00192                 default:
    00193                         PhoneInfoFlag = Barry::CallLog::InfoUndefined;
    00194                 }
    00195                 return begin;
    00196
    00197         case CLLFC_DURATION:
    00198                 if( btohs(field->size) >= sizeof(field->u.uint32) ) {
    00199                         Duration = btohl(field->u.uint32);
    00200                         return begin;
    00201                 }
    00202                 break;
    00203
    00204         case CLLFC_TIMESTAMP:
    00205                 if( btohs(field->size) >= sizeof(field->u.timestamp) ) {
    00206                         Timestamp = btohll(field->u.timestamp);
    00207                         return begin;
    00208                 }
    00209                 break;
    00210         }
    00211
    00212         // if still not handled, add to the Unknowns list
    00213         UnknownField uf;
    00214         uf.type = field->type;
    00215         uf.data.assign((const char*)field->u.raw, btohs(field->size));
    00216         Unknowns.push_back(uf);
    00217
    00218         // return new pointer for next field
    00219         return begin;
    00220 }
    00221
    00222 void CallLog::ParseHeader(const Data &data, size_t &offset)
    00223 {
    00224         // no header in CallLog records
    00225 }
    00226
    00227 void CallLog::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
    00228 {
    00229         const unsigned char *finish = ParseCommonFields(*this,
    00230                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
    00231         offset += finish - (data.GetData() + offset);
    00232 }
    00233
    00234 void CallLog::BuildHeader(Data &data, size_t &offset) const
    00235 {
    00236         // not yet implemented
    00237 }
    00238
    00239 void CallLog::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
    00240 {
    00241         // not yet implemented
    00242 }
    00243
    00244 void CallLog::Dump(std::ostream &os) const
    00245 {
    00246         uint32_t timestamp = Duration;
    00247         int32_t days, hours, minutes, secondes;
    00248
    00249         static const char *DirectionName[] = { "Received", "Sent", "Call Missing (Messagerie)", "Call Missing" };
    00250         static const char *StatusName[] = { "OK", "Busy", "Error", "Not supported by Barry" };
    00251         static const char *PhoneInfoName[] = { "Undefined", "Known phone number", "Unknown phone number", "Private phone number" };
    00252         static const char *PhoneTypeName[] = { "Unknown", "Office", "Home", "Mobile", "Not supported by Barry" };
    00253
    00254         os << "CallLog entry: 0x" << setbase(16) << RecordId
    00255            << " (" << (unsigned int)RecType << ")\n";
    00256
    00257         time_t t = GetTime();
    00258         os << "   Timestamp: " << ctime(&t);
    00259         os << "   Direction: " << DirectionName[DirectionFlag] << "\n";
    00260         os << "   Status: " << StatusName[StatusFlag] << "\n";
    00261         os << "   Phone info: " << PhoneInfoName[PhoneInfoFlag] << "\n";
    00262         os << "   Phone type: " << PhoneTypeName[PhoneTypeFlag] << "\n";
    00263
    00264         os << "   Duration: ";
    00265
    00266         // Days :
    00267         days = (int) (timestamp / (60 * 60 * 24));
    00268         timestamp = timestamp - (days * (60 * 60 * 24));
    00269         // Hours :
    00270         hours = (int) (timestamp / (60 * 60));
    00271         timestamp = timestamp - (hours * (60 * 60));
    00272         // Minutes :
    00273         minutes = (int) (timestamp / 60);
    00274         timestamp = timestamp - (minutes * 60);
    00275         // Secondes :
    00276         secondes = timestamp;
    00277
    00278         if (days > 1)
    00279                 os << setbase(10) << days << " days ";
    00280         else if (days > 0)
    00281                 os << setbase(10) << days << " day ";
    00282
    00283         os << setfill ('0') << setw(2) << setbase(10) << hours;
    00284         os << ":";
    00285         os << setfill ('0') << setw(2) << setbase(10) << minutes;
    00286         os << ":";
    00287         os << setfill ('0') << setw(2) << setbase(10) << secondes;
    00288         os << "\n";
    00289
    00290         // cycle through the type table
    00291         for(    const FieldLink<CallLog> *b = CallLogFieldLinks;
    00292                 b->type != CLLFC_END;
    00293                 b++ )
    00294         {
    00295                 if( b->strMember ) {
    00296                         const std::string &s = this->*(b->strMember);
    00297                         if( s.size() )
    00298                                 os << "   " << b->name << ": " << s << "\n";
    00299                 }
    00300                 else if( b->timeMember ) {
    00301                         time_t t = this->*(b->timeMember);
    00302                         if( t > 0 )
    00303                                 os << "   " << b->name << ": " << ctime(&t);
    00304                         else
    00305                                 os << "   " << b->name << ": unknown\n";
    00306                 }
    00307         }
    00308
    00309
    00310         os << Unknowns;
    00311         os << "\n\n";
    00312 }
    00313
    00314 void CallLog::Clear()
    00315 {
    00316         RecType = GetDefaultRecType();
    00317         RecordId = 0;
    00318
    00319         Duration = 0;
    00320         Timestamp = 0;
    00321
    00322         ContactName.clear();
    00323         PhoneNumber.clear();
    00324
    00325         DirectionFlag = Barry::CallLog::Receiver;
    00326         StatusFlag = Barry::CallLog::Unknown;
    00327         PhoneTypeFlag = Barry::CallLog::TypeUnknown;
    00328         PhoneInfoFlag = Barry::CallLog::InfoUndefined;
    00329
    00330         Unknowns.clear();
    00331 }
    00332
    00333 std::string CallLog::GetDescription() const
    00334 {
    00335         return ContactName;
    00336 }
    00337
    00338 } // namespace Barry
    00339