3 /// Blackberry database record parser class for email records.
7 Copyright (C) 2005-2007, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "r_message.h"
23 #include "record-internal.h"
25 #include "protostructs.h"
35 #define __DEBUG_MODE__
39 using namespace Barry::Protocol
;
43 std::ostream
& operator<<(std::ostream
&os
, const Address
&msga
) {
44 os
<< msga
.Name
.c_str() << " <" << msga
.Email
.c_str() << ">";
48 ///////////////////////////////////////////////////////////////////////////////
52 // Email / message field codes
53 #define MFC_TO 0x01 // can occur multiple times
54 #define MFC_CC 0x02 // ditto
55 #define MFC_BCC 0x03 // ditto
56 #define MFC_SENDER 0x04
58 #define MFC_REPLY_TO 0x06
59 #define MFC_SUBJECT 0x0b
61 #define MFC_REPLY_UNKNOWN 0x12 // This shows up as 0x00 on replies but we don't do much with it now
62 #define MFC_ATTACHMENT 0x16
63 #define MFC_RECORDID 0x4b
64 #define MFC_END 0xffff
66 #define PRIORITY_MASK 0x003f
67 #define PRIORITY_HIGH 0x0008
68 #define PRIORITY_LOW 0x0002
70 #define SENSITIVE_MASK 0xff80
71 #define SENSITIVE_CONFIDENTIAL 0x0100
72 #define SENSITIVE_PERSONAL 0x0080
73 #define SENSITIVE_PRIVATE 0x0040 // actual pattern is 0x00C0
75 #define MESSAGE_READ 0x0800
76 #define MESSAGE_REPLY 0x0001
77 #define MESSAGE_SAVED 0x0002
78 #define MESSAGE_FORWARD 0x0008
79 #define MESSAGE_TRUNCATED 0x0020
80 #define MESSAGE_SAVED_DELETED 0x0080
82 FieldLink
<Message
> MessageFieldLinks
[] = {
83 { MFC_TO
, "To", 0, 0, 0, &Message::To
, 0 },
84 { MFC_CC
, "Cc", 0, 0, 0, &Message::Cc
, 0 },
85 { MFC_BCC
, "Bcc", 0, 0, 0, &Message::Bcc
, 0 },
86 { MFC_SENDER
, "Sender", 0, 0, 0, &Message::Sender
, 0 },
87 { MFC_FROM
, "From", 0, 0, 0, &Message::From
, 0 },
88 { MFC_REPLY_TO
, "ReplyTo", 0, 0, 0, &Message::ReplyTo
, 0 },
89 { MFC_SUBJECT
, "Subject", 0, 0, &Message::Subject
, 0, 0 },
90 { MFC_BODY
, "Body", 0, 0, &Message::Body
, 0, 0 },
91 { MFC_ATTACHMENT
, "Attachment", 0, 0, &Message::Attachment
, 0, 0 },
92 { MFC_END
, "End of List", 0, 0, 0, 0, 0 }
104 const unsigned char* Message::ParseField(const unsigned char *begin
,
105 const unsigned char *end
)
107 const CommonField
*field
= (const CommonField
*) begin
;
109 // advance and check size
110 begin
+= COMMON_FIELD_HEADER_SIZE
+ btohs(field
->size
);
111 if( begin
> end
) // if begin==end, we are ok
114 if( !btohs(field
->size
) ) // if field has no size, something's up
117 // cycle through the type table
118 for( FieldLink
<Message
> *b
= MessageFieldLinks
;
122 if( b
->type
== field
->type
) {
124 // parse regular string
125 std::string
&s
= this->*(b
->strMember
);
126 s
.assign((const char *)field
->u
.raw
, btohs(field
->size
)-1);
127 return begin
; // done!
129 else if( b
->addrMember
) {
130 // parse email address
131 // get dual name+addr string first
132 const char *fa
= (const char*)field
->u
.addr
.addr
;
133 std::string
dual(fa
, btohs(field
->size
) - sizeof(field
->u
.addr
.unknown
));
135 // assign first string, using null terminator...letting std::string add it for us if it doesn't exist
136 Address
&a
= this->*(b
->addrMember
);
137 a
.Name
= dual
.c_str();
139 // assign second string, using first size as starting point
140 a
.Email
= dual
.c_str() + a
.Name
.size() + 1;
145 // handle special cases
147 switch( field
->type
)
150 MessageRecordId
= field
->u
.uint32
;
152 case MFC_REPLY_UNKNOWN
:
153 swallow
= field
->u
.raw
[0];
156 // if still not handled, add to the Unknowns list
158 uf
.type
= field
->type
;
159 uf
.data
.assign((const char*)field
->u
.raw
, btohs(field
->size
));
160 Unknowns
.push_back(uf
);
165 uint8_t Message::GetRecType() const
167 throw std::logic_error("Message::GetRecType() called, and not supported by the USB protocol. Should never get called.");
170 // empty API, not required by protocol
171 uint32_t Message::GetUniqueId() const
173 throw std::logic_error("Message::GetUniqueId() called, and not supported by the USB protocol. Should never get called.");
176 void Message::ParseHeader(const Data
&data
, size_t &offset
)
178 MAKE_RECORD(const Barry::Protocol::MessageRecord
, mr
, data
, offset
);
181 MessagePriority
= NormalPriority
;
182 if( mr
->priority
& PRIORITY_MASK
) {
183 if( mr
->priority
& PRIORITY_HIGH
) {
184 MessagePriority
= HighPriority
;
186 else if( mr
->priority
& PRIORITY_LOW
) {
187 MessagePriority
= LowPriority
;
190 MessagePriority
= UnknownPriority
;
193 MessageSensitivity
= NormalSensitivity
;
194 if( mr
->priority
& SENSITIVE_MASK
) {
195 if(( mr
->priority
& SENSITIVE_CONFIDENTIAL
) == SENSITIVE_CONFIDENTIAL
) {
196 MessageSensitivity
= Confidential
;
198 else if(( mr
->priority
& SENSITIVE_PRIVATE
) == SENSITIVE_PRIVATE
) {
199 MessageSensitivity
= Private
;
201 else if(( mr
->priority
& SENSITIVE_PERSONAL
) == SENSITIVE_PERSONAL
) {
202 MessageSensitivity
= Personal
;
205 MessageSensitivity
= UnknownSensitivity
;
207 // X-rim-org-message-ref-id // NOTE: I'm cheating a bit here and using this as a reply-to
208 if( mr
->inReplyTo
) // It's actually sent by BB with the actual UID in every message
209 MessageReplyTo
= mr
->inReplyTo
;
211 if( !( mr
->flags
& MESSAGE_READ
))
212 MessageRead
= true; // NOTE: A lot of these flags are 'backwards' but this seemed
213 // like the most logical way to interpret them for now
214 if(( mr
->flags
& MESSAGE_REPLY
) == MESSAGE_REPLY
)
215 MessageReply
= true; // NOTE: This is a reply, the original message's flags are not changed
216 // the inReplyTo field is updated with the original messages's UID
217 if( !( mr
->flags
& MESSAGE_TRUNCATED
))
218 MessageTruncated
= true; // NOTE: This bit is unset on truncation, around 4096 on my 7100g
219 // NOTE: bit 0x400 is set on REALLY huge messages, haven't tested
220 // the exact size yet
221 if( !( mr
->flags
& MESSAGE_SAVED
))
222 MessageSaved
= true; // NOTE: Saved to 'saved' folder
223 if( !( mr
->flags
& MESSAGE_SAVED_DELETED
))
224 MessageSavedDeleted
= true; // NOTE: Saved to 'saved' folder and then deleted from inbox
226 MessageDateSent
= ( mr
->dateSent
& 0x01ff ) - 0x29;
227 MessageDateSent
= DayToDate( MessageDateSent
);
228 MessageDateSent
+= (time_t)( mr
->timeSent
*1.77 );
230 MessageDateReceived
= ( mr
->dateReceived
& 0x01ff ) - 0x29;
231 MessageDateReceived
= DayToDate( MessageDateReceived
);
232 MessageDateReceived
+= (time_t)( mr
->timeReceived
*1.77 );
234 offset
+= MESSAGE_RECORD_HEADER_SIZE
;
237 void Message::ParseFields(const Data
&data
, size_t &offset
)
239 const unsigned char *finish
= ParseCommonFields(*this,
240 data
.GetData() + offset
, data
.GetData() + data
.GetSize());
241 offset
+= finish
- (data
.GetData() + offset
);
244 void Message::BuildHeader(Data
&data
, size_t &offset
) const
246 throw std::logic_error("Message::BuildHeader not yet implemented");
249 void Message::BuildFields(Data
&data
, size_t &offset
) const
251 throw std::logic_error("Message::BuildFields not yet implemented");
254 void Message::Clear()
269 MessageDateReceived
= 0;
270 MessageTruncated
= false;
272 MessageReply
= false;
273 MessageSaved
= false;
274 MessageSavedDeleted
= false;
279 std::string
Message::SimpleEmailAddress() const
281 if( From
.Email
.size() ) {
282 // remove all spaces from the email
284 for( size_t i
= 0; i
< From
.Email
.size(); i
++ )
285 if( From
.Email
[i
] != ' ' )
286 ret
+= From
.Email
[i
];
295 // dump message in mbox format
296 void Message::Dump(std::ostream
&os
) const
298 static const char *MessageImportance
[] =
299 { "Low", "Normal", "High", "Unknown Priority" };
300 static const char *MessageSensitivityString
[] =
301 { "Normal", "Personal", "Private", "Confidential", "Unknown Sensivity" };
303 os
<< "From " << SimpleEmailAddress() << " " << ctime( &MessageDateReceived
);
304 os
<< "X-Record-ID: (" << setw(8) << std::hex
<< MessageRecordId
<< ")\n";
306 os
<< "X-rim-org-msg-ref-id: " << std::dec
<< MessageReplyTo
<< "\n";
308 os
<< "X-Message-Status: Saved\n";
309 else if( MessageRead
)
310 os
<< "Message Status: Opened\n";
311 if( MessagePriority
!= NormalPriority
)
312 os
<< "Importance: " << MessageImportance
[MessagePriority
] << "\n";
313 if( MessageSensitivity
!= NormalSensitivity
)
314 os
<< "Sensitivity: " << MessageSensitivityString
[MessageSensitivity
] << "\n";
315 os
<< "Date: " << ctime(&MessageDateSent
);
316 os
<< "From: " << From
<< "\n";
317 if( To
.Email
.size() )
318 os
<< "To: " << To
<< "\n";
319 if( Cc
.Email
.size() )
320 os
<< "Cc: " << Cc
<< "\n";
321 if( Bcc
.Email
.size() )
322 os
<< "Bcc: " << Bcc
<< "\n";
323 if( Sender
.Email
.size() )
324 os
<< "Sender: " << Sender
<< "\n";
325 if( ReplyTo
.Email
.size())
326 os
<< "Reply To: " << ReplyTo
<< "\n";
328 os
<< "Subject: " << Subject
<< "\n";
330 for( std::string::const_iterator i
= Body
.begin();
331 i
!= Body
.end() && *i
;
340 if( Attachment
.size() )
341 os
<< "Attachments: " << Attachment
<< "\n";