r_message.cc

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

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