r_pin_message.cc

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

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