2 /// \file r_saved_message.cc
3 /// Blackberry database record parser class for saved email
8 Copyright (C) 2005-2007, Net Direct Inc. (http://www.netdirect.ca/)
9 Copyright (C) 2005-2007, Brian Edginton (edge@edginton.net)
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 See the GNU General Public License in the COPYING file at the
21 root directory of this project for more details.
24 #include "r_saved_message.h"
25 #include "record-internal.h"
27 #include "protostructs.h"
37 #define __DEBUG_MODE__
41 using namespace Barry::Protocol
;
45 ///////////////////////////////////////////////////////////////////////////////
49 // Email / message field codes
50 #define SEMFC_TO 0x01 // can occur multiple times
51 #define SEMFC_CC 0x02 // ditto
52 #define SEMFC_BCC 0x03 // ditto
53 #define SEMFC_SENDER 0x04
54 #define SEMFC_FROM 0x05
55 #define SEMFC_REPLY_TO 0x06
56 #define SEMFC_SUBJECT 0x0b
57 #define SEMFC_BODY 0x0c
58 #define SEMFC_ATTACHMENT 0x16
59 #define SEMFC_RECORDID 0x4b
60 #define SEMFC_END 0xffff
62 #define PRIORITY_MASK 0x003f
63 #define PRIORITY_HIGH 0x0008
64 #define PRIORITY_LOW 0x0002
66 #define SENSITIVE_MASK 0xff80
67 #define SENSITIVE_CONFIDENTIAL 0x0100
68 #define SENSITIVE_PERSONAL 0x0080
69 #define SENSITIVE_PRIVATE 0x0040 // actual pattern is 0x00C0
71 #define MESSAGE_READ 0x0800
72 #define MESSAGE_REPLY 0x0001
73 #define MESSAGE_SAVED 0x0002
74 #define MESSAGE_FORWARD 0x0008
75 #define MESSAGE_TRUNCATED 0x0020
76 #define MESSAGE_SAVED_DELETED 0x0080
78 FieldLink
<SavedMessage
> SavedMessageFieldLinks
[] = {
79 { SEMFC_TO
, "To", 0, 0, 0, &SavedMessage::To
, 0 },
80 { SEMFC_CC
, "Cc", 0, 0, 0, &SavedMessage::Cc
, 0 },
81 { SEMFC_BCC
, "Bcc", 0, 0, 0, &SavedMessage::Bcc
, 0 },
82 { SEMFC_SENDER
, "Sender", 0, 0, 0, &SavedMessage::Sender
, 0 },
83 { SEMFC_FROM
, "From", 0, 0, 0, &SavedMessage::From
, 0 },
84 { SEMFC_REPLY_TO
, "ReplyTo", 0, 0, 0, &SavedMessage::ReplyTo
, 0 },
85 { SEMFC_SUBJECT
, "Subject", 0, 0, &SavedMessage::Subject
, 0, 0 },
86 { SEMFC_BODY
, "Body", 0, 0, &SavedMessage::Body
, 0, 0 },
87 { SEMFC_ATTACHMENT
, "Attachment", 0, 0, &SavedMessage::Attachment
, 0, 0 },
88 { SEMFC_END
, "End of List", 0, 0, 0, 0, 0 }
91 SavedMessage::SavedMessage()
96 SavedMessage::~SavedMessage()
100 const unsigned char* SavedMessage::ParseField(const unsigned char *begin
,
101 const unsigned char *end
)
103 const CommonField
*field
= (const CommonField
*) begin
;
105 // advance and check size
106 begin
+= COMMON_FIELD_HEADER_SIZE
+ btohs(field
->size
);
107 if( begin
> end
) // if begin==end, we are ok
110 if( !btohs(field
->size
) ) // if field has no size, something's up
113 // cycle through the type table
114 for( FieldLink
<SavedMessage
> *b
= SavedMessageFieldLinks
;
115 b
->type
!= SEMFC_END
;
118 if( b
->type
== field
->type
) {
120 // parse regular string
121 std::string
&s
= this->*(b
->strMember
);
122 s
.assign((const char *)field
->u
.raw
, btohs(field
->size
)-1);
123 return begin
; // done!
125 else if( b
->addrMember
) {
126 // parse email address
127 // get dual name+addr string first
128 const char *fa
= (const char*)field
->u
.addr
.addr
;
129 std::string
dual(fa
, btohs(field
->size
) - sizeof(field
->u
.addr
.unknown
));
131 // assign first string, using null terminator...letting std::string add it for us if it doesn't exist
132 Address
&a
= this->*(b
->addrMember
);
133 a
.Name
= dual
.c_str();
135 // assign second string, using first size as starting point
136 a
.Email
= dual
.c_str() + a
.Name
.size() + 1;
142 // handle special cases
143 switch( field
->type
)
146 MessageRecordId
= field
->u
.uint32
;
150 // if still not handled, add to the Unknowns list
152 uf
.type
= field
->type
;
153 uf
.data
.assign((const char*)field
->u
.raw
, btohs(field
->size
));
154 Unknowns
.push_back(uf
);
159 void SavedMessage::ParseHeader(const Data
&data
, size_t &offset
)
161 MAKE_RECORD(const Barry::Protocol::MessageRecord
, mr
, data
, offset
);
163 MessagePriority
= NormalPriority
;
164 if( mr
->priority
& PRIORITY_MASK
) {
165 if( mr
->priority
& PRIORITY_HIGH
) {
166 MessagePriority
= HighPriority
;
168 else if( mr
->priority
& PRIORITY_LOW
) {
169 MessagePriority
= LowPriority
;
172 MessagePriority
= UnknownPriority
;
175 MessageSensitivity
= NormalSensitivity
;
176 if( mr
->priority
& SENSITIVE_MASK
) {
177 if(( mr
->priority
& SENSITIVE_CONFIDENTIAL
) == SENSITIVE_CONFIDENTIAL
) {
178 MessageSensitivity
= Confidential
;
180 else if(( mr
->priority
& SENSITIVE_PRIVATE
) == SENSITIVE_PRIVATE
) {
181 MessageSensitivity
= Private
;
183 else if(( mr
->priority
& SENSITIVE_PERSONAL
) == SENSITIVE_PERSONAL
) {
184 MessageSensitivity
= Personal
;
187 MessageSensitivity
= UnknownSensitivity
;
189 // X-rim-org-message-ref-id // NOTE: I'm cheating a bit here and using this as a reply-to
190 if( mr
->inReplyTo
) // It's actually sent by BB with the actual UID in every message
191 MessageReplyTo
= mr
->inReplyTo
;
193 if( !( mr
->flags
& MESSAGE_READ
))
194 MessageRead
= true; // NOTE: A lot of these flags are 'backwards' but this seemed
195 // like the most logical way to interpret them for now
196 if(( mr
->flags
& MESSAGE_REPLY
) == MESSAGE_REPLY
)
197 MessageReply
= true; // NOTE: This is a reply, the original message's flags are not changed
198 // the inReplyTo field is updated with the original messages's UID
199 if( !( mr
->flags
& MESSAGE_TRUNCATED
))
200 MessageTruncated
= true; // NOTE: This bit is unset on truncation, around 4096 on my 7100g
201 // NOTE: bit 0x400 is set on REALLY huge messages, haven't tested
202 // the exact size yet
203 if( !( mr
->flags
& MESSAGE_SAVED
))
204 MessageSaved
= true; // NOTE: Saved to 'saved' folder
205 if( !( mr
->flags
& MESSAGE_SAVED_DELETED
))
206 MessageSavedDeleted
= true; // NOTE: Saved to 'saved' folder and then deleted from inbox
208 MessageDateSent
= ( mr
->dateSent
& 0x01ff ) - 0x29;
209 MessageDateSent
= DayToDate( MessageDateSent
);
210 MessageDateSent
+= (time_t)( mr
->timeSent
*1.77 );
212 MessageDateReceived
= ( mr
->dateReceived
& 0x01ff ) - 0x29;
213 MessageDateReceived
= DayToDate( MessageDateReceived
);
214 MessageDateReceived
+= (time_t)( mr
->timeReceived
*1.77 );
215 offset
+= MESSAGE_RECORD_HEADER_SIZE
;
218 void SavedMessage::ParseFields(const Data
&data
, size_t &offset
)
220 const unsigned char *finish
= ParseCommonFields(*this,
221 data
.GetData() + offset
, data
.GetData() + data
.GetSize());
222 offset
+= finish
- (data
.GetData() + offset
);
225 void SavedMessage::BuildHeader(Data
&data
, size_t &offset
) const
227 throw std::logic_error("SavedMessage::BuildHeader not yet implemented");
230 void SavedMessage::BuildFields(Data
&data
, size_t &offset
) const
232 throw std::logic_error("SavedMessage::BuildFields not yet implemented");
235 void SavedMessage::Clear()
250 MessageDateReceived
= 0;
251 MessageTruncated
= false;
253 MessageReply
= false;
254 MessageSaved
= false;
255 MessageSavedDeleted
= false;
259 // dump message in mbox format
260 void SavedMessage::Dump(std::ostream
&os
) const
262 static const char *MessageImportance
[] =
263 { "Low", "Normal", "High", "Unknown Priority" };
264 static const char *MessageSensitivityString
[] =
265 { "Normal", "Personal", "Private", "Confidential", "Unknown Sensivity" };
267 os
<< "From " << (From
.Email
.size() ? From
.Email
.c_str() : "unknown")
268 << " " << ctime( &MessageDateSent
);
269 os
<< "X-Record-ID: (" << setw(8) << std::hex
<< MessageRecordId
<< ")\n";
271 os
<< "X-rim-org-msg-ref-id: " << std::dec
<< MessageReplyTo
<< "\n";
273 os
<< "Message Status: Saved\n";
274 else if( MessageRead
)
275 os
<< "Message Status: Opened\n";
276 if( MessagePriority
!= NormalPriority
)
277 os
<< "Importance: " << MessageImportance
[MessagePriority
] << "\n";
278 if( MessageSensitivity
!= NormalSensitivity
)
279 os
<< "Sensitivity: " << MessageSensitivityString
[MessageSensitivity
] << "\n";
280 os
<< "Date: " << ctime(&MessageDateSent
);
281 os
<< "From: " << From
<< "\n";
282 if( To
.Email
.size() )
283 os
<< "To: " << To
<< "\n";
284 if( Cc
.Email
.size() )
285 os
<< "Cc: " << Cc
<< "\n";
286 if( Bcc
.Email
.size() )
287 os
<< "Bcc: " << Bcc
<< "\n";
288 if( Sender
.Email
.size() )
289 os
<< "Sender: " << Sender
<< "\n";
290 if( ReplyTo
.Email
.size())
291 os
<< "Reply To: " << ReplyTo
<< "\n";
293 os
<< "Subject: " << Subject
<< "\n";
295 for( std::string::const_iterator i
= Body
.begin();
296 i
!= Body
.end() && *i
;
305 if( Attachment
.size() )
306 os
<< "Attachments: " << Attachment
<< "\n";