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-2010, 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::Dump(std::ostream &os) const
00235 {
00236         uint32_t timestamp = Duration;
00237         int32_t days, hours, minutes, secondes;
00238 
00239         static const char *DirectionName[] = { "Received", "Sent", "Call Missing (Messagerie)", "Call Missing" };
00240         static const char *StatusName[] = { "OK", "Busy", "Error", "Not supported by Barry" };
00241         static const char *PhoneInfoName[] = { "Undefined", "Known phone number", "Unknown phone number", "Private phone number" };
00242         static const char *PhoneTypeName[] = { "Unknown", "Office", "Home", "Mobile", "Not supported by Barry" };
00243 
00244         os << "CallLog entry: 0x" << setbase(16) << RecordId
00245            << " (" << (unsigned int)RecType << ")\n";
00246 
00247         time_t t = GetTime();
00248         os << "   Timestamp: " << ctime(&t);
00249         os << "   Direction: " << DirectionName[DirectionFlag] << "\n";
00250         os << "   Status: " << StatusName[StatusFlag] << "\n";
00251         os << "   Phone info: " << PhoneInfoName[PhoneInfoFlag] << "\n";
00252         os << "   Phone type: " << PhoneTypeName[PhoneTypeFlag] << "\n";
00253 
00254         os << "   Duration: ";
00255 
00256         // Days :
00257         days = (int) (timestamp / (60 * 60 * 24));
00258         timestamp = timestamp - (days * (60 * 60 * 24));
00259         // Hours :
00260         hours = (int) (timestamp / (60 * 60));
00261         timestamp = timestamp - (hours * (60 * 60));
00262         // Minutes :
00263         minutes = (int) (timestamp / 60);
00264         timestamp = timestamp - (minutes * 60);
00265         // Secondes :
00266         secondes = timestamp;
00267 
00268         if (days > 1)
00269                 os << setbase(10) << days << " days ";
00270         else if (days > 0)
00271                 os << setbase(10) << days << " day ";
00272 
00273         os << setfill ('0') << setw(2) << setbase(10) << hours;
00274         os << ":";
00275         os << setfill ('0') << setw(2) << setbase(10) << minutes;
00276         os << ":";
00277         os << setfill ('0') << setw(2) << setbase(10) << secondes;
00278         os << "\n";
00279 
00280         // cycle through the type table
00281         for(    const FieldLink<CallLog> *b = CallLogFieldLinks;
00282                 b->type != CLLFC_END;
00283                 b++ )
00284         {
00285                 if( b->strMember ) {
00286                         const std::string &s = this->*(b->strMember);
00287                         if( s.size() )
00288                                 os << "   " << b->name << ": " << s << "\n";
00289                 }
00290                 else if( b->timeMember ) {
00291                         time_t t = this->*(b->timeMember);
00292                         if( t > 0 )
00293                                 os << "   " << b->name << ": " << ctime(&t);
00294                         else
00295                                 os << "   " << b->name << ": unknown\n";
00296                 }
00297         }
00298 
00299 
00300         os << Unknowns;
00301         os << "\n\n";
00302 }
00303 
00304 void CallLog::Clear()
00305 {
00306         RecType = CallLog::GetDefaultRecType();
00307 
00308         Duration = 0;
00309         Timestamp = 0;
00310 
00311         ContactName.clear();
00312         PhoneNumber.clear();
00313 
00314         DirectionFlag = Barry::CallLog::Receiver;
00315         StatusFlag = Barry::CallLog::Unknown;
00316         PhoneTypeFlag = Barry::CallLog::TypeUnknown;
00317         PhoneInfoFlag = Barry::CallLog::InfoUndefined;
00318 
00319         Unknowns.clear();
00320 }
00321 
00322 } // namespace Barry
00323 

Generated on 29 Mar 2010 for Barry by  doxygen 1.6.1