r_sms.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_sms.cc
00003 ///             Record parsing class for the SMS database.
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2009, Net Direct Inc. (http://www.netdirect.ca/)
00008     Copyright (C) 2009, Ryan Li(ryan@ryanium.com)
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_sms.h"
00024 #include "record-internal.h"
00025 #include "protostructs.h"
00026 #include "data.h"
00027 #include "time.h"
00028 #include "debug.h"
00029 #include "iconv.h"
00030 #include "strnlen.h"
00031 #include <ostream>
00032 #include <iomanip>
00033 #include <string.h>
00034 
00035 using namespace std;
00036 using namespace Barry::Protocol;
00037 
00038 namespace Barry {
00039 
00040 ///////////////////////////////////////////////////////////////////////////////
00041 // Sms Class
00042 
00043 // SMS Field Codes
00044 #define SMSFC_METADATA 0x01
00045 #define SMSFC_ADDRESS 0x02
00046 #define SMSFC_BODY 0x04
00047 
00048 // SMS Field Sizes and Header Sizes
00049 #define SMS_ADDRESS_HEADER_SIZE 0x04
00050 
00051 #define MILLISECONDS_IN_A_SECOND 1000
00052 
00053 time_t Sms::GetTime() const
00054 {
00055         return (time_t)(Timestamp / MILLISECONDS_IN_A_SECOND);
00056 }
00057 
00058 time_t Sms::GetServiceCenterTime() const
00059 {
00060         return (time_t)(ServiceCenterTimestamp / MILLISECONDS_IN_A_SECOND);
00061 }
00062 
00063 void Sms::SetTime(const time_t timestamp, const unsigned milliseconds)
00064 {
00065         Timestamp = (uint64_t)timestamp * MILLISECONDS_IN_A_SECOND + milliseconds;
00066 }
00067 
00068 void Sms::SetServiceCenterTime(const time_t timestamp, const unsigned milliseconds)
00069 {
00070         ServiceCenterTimestamp = (uint64_t)timestamp * MILLISECONDS_IN_A_SECOND + milliseconds;
00071 }
00072 
00073 Sms::Sms()
00074 {
00075         Clear();
00076 }
00077 
00078 Sms::~Sms()
00079 {
00080 }
00081 
00082 const unsigned char* Sms::ParseField(const unsigned char *begin,
00083                                      const unsigned char *end,
00084                                      const IConverter *ic)
00085 {
00086         const CommonField *field = (const CommonField *)begin;
00087 
00088         // advance and check size
00089         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00090         if (begin > end) // if begin==end, we are ok
00091                 return begin;
00092 
00093         if (!btohs(field->size)) // if field has no size, something's up
00094                 return begin;
00095 
00096         switch (field->type)
00097         {
00098                 case SMSFC_METADATA:
00099                 {
00100                         if (btohs(field->size) < SMS_METADATA_SIZE)
00101                                 break; // size not match
00102 
00103                         const SMSMetaData &metadata = field->u.sms_metadata;
00104                         NewConversation = metadata.flags & SMS_FLG_NEW_CONVERSATION;
00105                         Saved = metadata.flags & SMS_FLG_SAVED;
00106                         Deleted = metadata.flags & SMS_FLG_DELETED;
00107                         Opened = metadata.flags & SMS_FLG_OPENED;
00108 
00109                         IsNew = metadata.new_flag;
00110 
00111                         uint32_t status = btohl(metadata.status);
00112 
00113                         switch (status)
00114                         {
00115                                 case SMS_STA_RECEIVED:
00116                                         MessageStatus = Received;
00117                                         break;
00118                                 case SMS_STA_DRAFT:
00119                                         MessageStatus = Draft;
00120                                         break;
00121                                 default:
00122                                         MessageStatus = Sent; // consider all others as sent
00123                         }
00124 
00125                         ErrorId = btohl(metadata.error_id);
00126 
00127                         Timestamp = btohll(metadata.timestamp);
00128                         ServiceCenterTimestamp = btohll(metadata.service_center_timestamp);
00129 
00130                         switch (metadata.dcs)
00131                         {
00132                                 case SMS_DCS_7BIT:
00133                                         DataCodingScheme = SevenBit;
00134                                         break;
00135                                 case SMS_DCS_8BIT:
00136                                         DataCodingScheme = EightBit;
00137                                         break;
00138                                 case SMS_DCS_UCS2:
00139                                         DataCodingScheme = UCS2;
00140                                         break;
00141                                 default:
00142                                         DataCodingScheme = SevenBit; // consider all unknowns as 7bit
00143                         }
00144 
00145                         return begin;
00146                 }
00147 
00148                 case SMSFC_ADDRESS:
00149                 {
00150                         uint16_t length = btohs(field->size);
00151                         if (length < SMS_ADDRESS_HEADER_SIZE + 1) // trailing '\0'
00152                                 break; // too short
00153 
00154                         length -= SMS_ADDRESS_HEADER_SIZE;
00155                         const char *address = (const char *)field->u.raw + SMS_ADDRESS_HEADER_SIZE;
00156                         Addresses.push_back(std::string(address, strnlen(address, length)));
00157                         return begin;
00158                 }
00159 
00160                 case SMSFC_BODY:
00161                 {
00162                         //
00163                         // Some SMS bodies contain a null terminator
00164                         // in the middle, and it is unknown at the moment
00165                         // why this is.  For regular 8bit char strings,
00166                         // we just strip out the nulls.  For UCS2
00167                         // 16bit char strings, we strip out the
00168                         // 16bit nulls.
00169                         //
00170                         // Any further information on why these null
00171                         // terminators appear is welcome.
00172                         //
00173                         const char *str = (const char *)field->u.raw;
00174                         uint16_t maxlen = btohs(field->size);
00175                         if (DataCodingScheme != UCS2) {
00176                                 for (uint16_t i = 0; i < maxlen; ++i) {
00177                                         if (str[i]) // if not null, push it
00178                                                 Body += str[i];
00179                                 }
00180 
00181                                 if (ic) {
00182                                         Body = ic->FromBB(Body);
00183                                 }
00184                         }
00185                         else {
00186                                 for (uint16_t i = 0; maxlen && i < (maxlen-1); i += 2) {
00187                                         if (str[i] || str[i + 1]) // if not null, push it
00188                                                 Body += std::string(str + i, 2);
00189                                 }
00190 
00191                                 if (ic) {
00192                                         IConvHandle ucs2("UCS-2BE", *ic);
00193                                         Body = ic->Convert(ucs2, Body);
00194                                 }
00195                         }
00196                         return begin;
00197                 }
00198         }
00199 
00200         // if still not handled, add to the Unknowns list
00201         UnknownField uf;
00202         uf.type = field->type;
00203         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00204         Unknowns.push_back(uf);
00205 
00206         // return new pointer for next field
00207         return begin;
00208 }
00209 
00210 void Sms::ParseHeader(const Data &data, size_t &offset)
00211 {
00212         // no header in SMS records
00213 }
00214 
00215 void Sms::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00216 {
00217         const unsigned char *finish = ParseCommonFields(*this,
00218                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00219         offset += finish - (data.GetData() + offset);
00220 }
00221 
00222 void Sms::Clear()
00223 {
00224         MessageStatus = Unknown;
00225         DeliveryStatus = NoReport;
00226         DataCodingScheme = SevenBit;
00227 
00228         IsNew = NewConversation = Saved = Deleted = Opened = false;
00229 
00230         Timestamp = ServiceCenterTimestamp = 0;
00231         ErrorId = 0;
00232 
00233         Addresses.clear();
00234         Body.clear();
00235 
00236         Unknowns.clear();
00237 }
00238 
00239 void Sms::Dump(std::ostream &os) const
00240 {
00241 
00242         os << "SMS record: 0x" << setbase(16) << RecordId
00243                 << " (" << (unsigned int)RecType << ")\n";
00244         time_t t = GetTime();
00245         os << "\tTimestamp: " << ctime(&t);
00246 
00247         if (MessageStatus == Received)
00248         {
00249                 t = GetServiceCenterTime();
00250                 os << "\tService Center Timestamp: " << ctime(&t);
00251         }
00252 
00253         if (ErrorId)
00254                 os << "\tSend Error: 0x" << setbase(16) << ErrorId << "\n";
00255 
00256         switch (MessageStatus)
00257         {
00258                 case Received:
00259                         os << "\tReceived From:\n";
00260                         break;
00261                 case Sent:
00262                         os << "\tSent to:\n";
00263                         break;
00264                 case Draft:
00265                         os << "\tDraft for:\n";
00266                         break;
00267                 case Unknown:
00268                         os << "\tUnknown status for:\n";
00269                         break;
00270         }
00271 
00272         os << "\t";
00273         for (std::vector<std::string>::const_iterator Iterator = Addresses.begin(); Iterator < Addresses.end(); ++Iterator)
00274         {
00275                 if (Iterator != Addresses.begin())
00276                         os << ", ";
00277                 os << *Iterator;
00278         }
00279         os << "\n";
00280 
00281         if (IsNew || Opened || Saved || Deleted || NewConversation)
00282         {
00283                 os << "\t";
00284                 if (IsNew)
00285                         os << "New ";
00286                 if (Opened)
00287                         os << "Opened ";
00288                 if (Saved)
00289                         os << "Saved ";
00290                 if (Deleted)
00291                         os << "Deleted ";
00292                 os << "Message" << (NewConversation ? " that starts a new conversation" : "") << "\n";
00293         }
00294         os << "\tContent: " << Body << "\n";
00295         os << "\n";
00296 }
00297 
00298 } // namespace Barry

Generated on Tue Jun 30 16:08:14 2009 for Barry by  doxygen 1.5.8