r_saved_message.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_saved_message.cc
00003 ///             Blackberry database record parser class for saved email
00004 ///             message records.
00005 ///
00006 
00007 /*
00008     Copyright (C) 2005-2008, Net Direct Inc. (http://www.netdirect.ca/)
00009     Copyright (C) 2005-2007, Brian Edginton (edge@edginton.net)
00010 
00011     This program is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     This program is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00019 
00020     See the GNU General Public License in the COPYING file at the
00021     root directory of this project for more details.
00022 */
00023 
00024 #include "r_saved_message.h"
00025 #include "record-internal.h"
00026 #include "protocol.h"
00027 #include "protostructs.h"
00028 #include "data.h"
00029 #include "time.h"
00030 #include "error.h"
00031 #include "endian.h"
00032 #include <ostream>
00033 #include <iomanip>
00034 #include <time.h>
00035 #include <stdexcept>
00036 
00037 #define __DEBUG_MODE__
00038 #include "debug.h"
00039 
00040 using namespace std;
00041 using namespace Barry::Protocol;
00042 
00043 namespace Barry {
00044 
00045 ///////////////////////////////////////////////////////////////////////////////
00046 // Message class
00047 
00048 
00049 // Email / message field codes
00050 #define SEMFC_TO                0x01            // can occur multiple times
00051 #define SEMFC_CC                0x02            // ditto
00052 #define SEMFC_BCC               0x03            // ditto
00053 #define SEMFC_SENDER            0x04
00054 #define SEMFC_FROM              0x05
00055 #define SEMFC_REPLY_TO          0x06
00056 #define SEMFC_SUBJECT           0x0b
00057 #define SEMFC_BODY              0x0c
00058 #define SEMFC_ATTACHMENT        0x16
00059 #define SEMFC_RECORDID          0x4b
00060 #define SEMFC_END               0xffff
00061 
00062 #define PRIORITY_MASK           0x003f
00063 #define PRIORITY_HIGH           0x0008
00064 #define PRIORITY_LOW            0x0002
00065 
00066 #define SENSITIVE_MASK          0xff80
00067 #define SENSITIVE_CONFIDENTIAL  0x0100
00068 #define SENSITIVE_PERSONAL      0x0080
00069 #define SENSITIVE_PRIVATE       0x0040  // actual pattern is 0x00C0
00070 
00071 #define MESSAGE_READ            0x0800
00072 #define MESSAGE_REPLY           0x0001
00073 #define MESSAGE_SAVED           0x0002
00074 #define MESSAGE_FORWARD         0x0008
00075 #define MESSAGE_TRUNCATED       0x0020
00076 #define MESSAGE_SAVED_DELETED   0x0080
00077 
00078 FieldLink<SavedMessage> SavedMessageFieldLinks[] = {
00079    { SEMFC_TO,         "To",          0, 0,    0, &SavedMessage::To, 0 },
00080    { SEMFC_CC,         "Cc",          0, 0,    0, &SavedMessage::Cc, 0 },
00081    { SEMFC_BCC,        "Bcc",         0, 0,    0, &SavedMessage::Bcc, 0 },
00082    { SEMFC_SENDER,     "Sender",      0, 0,    0, &SavedMessage::Sender, 0 },
00083    { SEMFC_FROM,       "From",        0, 0,    0, &SavedMessage::From, 0 },
00084    { SEMFC_REPLY_TO,   "ReplyTo",     0, 0,    0, &SavedMessage::ReplyTo, 0 },
00085    { SEMFC_SUBJECT,    "Subject",     0, 0,    &SavedMessage::Subject, 0, 0 },
00086    { SEMFC_BODY,       "Body",        0, 0,    &SavedMessage::Body, 0, 0 },
00087    { SEMFC_ATTACHMENT, "Attachment",  0, 0,    &SavedMessage::Attachment, 0, 0 },
00088    { SEMFC_END,        "End of List", 0, 0,    0, 0, 0 }
00089 };
00090 
00091 SavedMessage::SavedMessage()
00092 {
00093         Clear();
00094 }
00095 
00096 SavedMessage::~SavedMessage()
00097 {
00098 }
00099 
00100 const unsigned char* SavedMessage::ParseField(const unsigned char *begin,
00101                                               const unsigned char *end)
00102 {
00103         const CommonField *field = (const CommonField *) begin;
00104 
00105         // advance and check size
00106         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00107         if( begin > end )               // if begin==end, we are ok
00108                 return begin;
00109 
00110         if( !btohs(field->size) )       // if field has no size, something's up
00111                 return begin;
00112 
00113         // cycle through the type table
00114         for(    FieldLink<SavedMessage> *b = SavedMessageFieldLinks;
00115                 b->type != SEMFC_END;
00116                 b++ )
00117         {
00118                 if( b->type == field->type ) {
00119                         if( b->strMember ) {
00120                                 // parse regular string
00121                                 std::string &s = this->*(b->strMember);
00122                                 s = ParseFieldString(field);
00123                                 return begin;   // done!
00124                         }
00125                         else if( b->addrMember ) {
00126                                 // parse email address
00127                                 // get dual name+addr string first
00128                                 const char *fa = (const char*)field->u.addr.addr;
00129                                 std::string dual(fa, btohs(field->size) - sizeof(field->u.addr.unknown));
00130 
00131                                 // assign first string, using null terminator...letting std::string add it for us if it doesn't exist
00132                                 EmailAddress &a = this->*(b->addrMember);
00133                                 a.Name = dual.c_str();
00134 
00135                                 // assign second string, using first size as starting point
00136                                 a.Email = dual.c_str() + a.Name.size() + 1;
00137                                 return begin;
00138                         }
00139                 }
00140         }
00141 
00142         // handle special cases
00143         switch( field->type )
00144         {
00145         case SEMFC_RECORDID:
00146                 MessageRecordId = btohl(field->u.uint32);
00147                 return begin;
00148         }
00149 
00150         // if still not handled, add to the Unknowns list
00151         UnknownField uf;
00152         uf.type = field->type;
00153         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00154         Unknowns.push_back(uf);
00155 
00156         return begin;
00157 }
00158 
00159 void SavedMessage::ParseHeader(const Data &data, size_t &offset)
00160 {
00161         Protocol::CheckSize(data, offset + MESSAGE_RECORD_HEADER_SIZE);
00162 
00163         MAKE_RECORD(const Barry::Protocol::MessageRecord, mr, data, offset);
00164 
00165         // Priority
00166         MessagePriority = NormalPriority;
00167 
00168         uint16_t priority = btohs(mr->priority);  // deal with endian swap once
00169         if( priority & PRIORITY_MASK ) {
00170                 if( priority & PRIORITY_HIGH ) {
00171                         MessagePriority = HighPriority;
00172                 }
00173                 else if( priority & PRIORITY_LOW ) {
00174                         MessagePriority = LowPriority;
00175                 }
00176                 else
00177                         MessagePriority = UnknownPriority;
00178         } 
00179         // Sensitivity
00180         MessageSensitivity = NormalSensitivity;
00181         if( priority & SENSITIVE_MASK ) {
00182                 if(( priority & SENSITIVE_CONFIDENTIAL ) == SENSITIVE_CONFIDENTIAL ) {
00183                         MessageSensitivity = Confidential;
00184                 }
00185                 else if(( priority & SENSITIVE_PRIVATE ) == SENSITIVE_PRIVATE ) {
00186                         MessageSensitivity = Private;
00187                 }
00188                 else if(( priority & SENSITIVE_PERSONAL ) == SENSITIVE_PERSONAL ) {
00189                         MessageSensitivity = Personal;
00190                 }
00191                 else
00192                         MessageSensitivity = UnknownSensitivity;
00193         }
00194         // X-rim-org-message-ref-id             // NOTE: I'm cheating a bit here and using this as a reply-to
00195         if( mr->inReplyTo )                     // It's actually sent by BB with the actual UID in every message
00196                 MessageReplyTo = btohl(mr->inReplyTo);
00197 
00198         // Status Flags
00199         uint32_t flags = btohl(mr->flags);
00200         if( !( flags & MESSAGE_READ ))
00201                 MessageRead = true;             // NOTE: A lot of these flags are 'backwards' but this seemed
00202                                                 // like the most logical way to interpret them for now
00203         if(( flags & MESSAGE_REPLY ) == MESSAGE_REPLY )
00204                 MessageReply = true;            // NOTE: This is a reply, the original message's flags are not changed
00205                                                 // the inReplyTo field is updated with the original messages's UID
00206         if( !( flags & MESSAGE_TRUNCATED ))
00207                 MessageTruncated = true;        // NOTE: This bit is unset on truncation, around 4096 on my 7100g
00208                                                 // NOTE: bit 0x400 is set on REALLY huge messages, haven't tested
00209                                                 //       the exact size yet
00210         if( !( flags & MESSAGE_SAVED ))
00211                 MessageSaved = true;            // NOTE: Saved to 'saved' folder
00212         if( !( flags & MESSAGE_SAVED_DELETED ))
00213                 MessageSavedDeleted = true;     // NOTE: Saved to 'saved' folder and then deleted from inbox
00214 
00215         MessageDateSent = Message2Time(mr->dateSent, mr->timeSent);
00216         MessageDateReceived = Message2Time(mr->dateReceived, mr->timeReceived);
00217 
00218         offset += MESSAGE_RECORD_HEADER_SIZE;
00219 }
00220 
00221 void SavedMessage::ParseFields(const Data &data, size_t &offset)
00222 {
00223         const unsigned char *finish = ParseCommonFields(*this,
00224                 data.GetData() + offset, data.GetData() + data.GetSize());
00225         offset += finish - (data.GetData() + offset);
00226 }
00227 
00228 void SavedMessage::BuildHeader(Data &data, size_t &offset) const
00229 {
00230         throw std::logic_error("SavedMessage::BuildHeader not yet implemented");
00231 }
00232 
00233 void SavedMessage::BuildFields(Data &data, size_t &offset) const
00234 {
00235         throw std::logic_error("SavedMessage::BuildFields not yet implemented");
00236 }
00237 
00238 void SavedMessage::Clear()
00239 {
00240         From.clear();
00241         To.clear();
00242         Cc.clear();
00243         Bcc.clear();
00244         Sender.clear();
00245         ReplyTo.clear();
00246         Subject.clear();
00247         Body.clear();
00248         Attachment.clear();
00249 
00250         MessageRecordId = 0;
00251         MessageReplyTo = 0;
00252         MessageDateSent = 0;
00253         MessageDateReceived = 0;
00254         MessageTruncated = false;
00255         MessageRead = false;
00256         MessageReply = false;
00257         MessageSaved = false;
00258         MessageSavedDeleted = false;
00259         Unknowns.clear();
00260 }
00261 
00262 // dump message in mbox format
00263 void SavedMessage::Dump(std::ostream &os) const
00264 {
00265         static const char *MessageImportance[] = 
00266                 { "Low", "Normal", "High", "Unknown Priority" };
00267         static const char *MessageSensitivityString[] = 
00268                 { "Normal", "Personal", "Private", "Confidential", "Unknown Sensivity" };
00269         
00270         os << "From " << (From.Email.size() ? From.Email.c_str() : "unknown")
00271            << "  " << ctime( &MessageDateSent );
00272         os << "X-Record-ID: (" << setw(8) << std::hex << MessageRecordId << ")\n";
00273         if( MessageReplyTo )
00274                 os << "X-rim-org-msg-ref-id: " << std::dec << MessageReplyTo << "\n";
00275         if( MessageSaved )
00276                 os << "Message Status: Saved\n";
00277         else if( MessageRead )
00278                 os << "Message Status: Opened\n";
00279         if( MessagePriority != NormalPriority )
00280                 os << "Importance: " << MessageImportance[MessagePriority] << "\n";
00281         if( MessageSensitivity != NormalSensitivity )
00282                 os << "Sensitivity: " << MessageSensitivityString[MessageSensitivity] << "\n";
00283         os << "Date: " << ctime(&MessageDateSent);
00284         os << "From: " << From << "\n";
00285         if( To.Email.size() )
00286                 os << "To: " << To << "\n";
00287         if( Cc.Email.size() )
00288                 os << "Cc: " << Cc << "\n";
00289         if( Bcc.Email.size() )
00290                 os << "Bcc: " << Bcc << "\n";
00291         if( Sender.Email.size() )
00292                 os << "Sender: " << Sender << "\n";
00293         if( ReplyTo.Email.size())
00294                 os << "Reply To: " << ReplyTo << "\n";
00295         if( Subject.size() )
00296                 os << "Subject: " << Subject << "\n";
00297         os << "\n";
00298         for(    std::string::const_iterator i = Body.begin();
00299                 i != Body.end() && *i;
00300                 i++)
00301         {
00302                 if( *i == '\r' )
00303                         os << '\n';
00304                 else
00305                         os << *i;
00306         }
00307         os << "\n";
00308         if( Attachment.size() )
00309                 os << "Attachments: " << Attachment << "\n";
00310         
00311         os << Unknowns;
00312         os << "\n\n";
00313 }
00314 
00315 
00316 } // namespace Barry
00317 

Generated on Wed Sep 24 21:27:32 2008 for Barry by  doxygen 1.5.1