2 /// \file r_pin_message.cc
3 /// Blackberry database record parser class for pin message records.
7 Copyright (C) 2005-2007, Net Direct Inc. (http://www.netdirect.ca/)
8 Copyright (C) 2007, Brian Edginton (edge@edginton.net)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "r_pin_message.h"
24 #include "record-internal.h"
26 #include "protostructs.h"
36 #define __DEBUG_MODE__
40 using namespace Barry::Protocol
;
44 //std::ostream& operator<<(std::ostream &os, const Address &msgp) {
45 // os << msgp.Name.c_str() << " <" << msgp.Email.c_str() << ">";
49 ///////////////////////////////////////////////////////////////////////////////
53 // PIN message field codes
54 #define PNMFC_TO 0x01 // can occur multiple times
55 #define PNMFC_CC 0x02 // ditto
56 #define PNMFC_BCC 0x03 // ditto
57 #define PNMFC_FROM 0x05
58 #define PNMFC_SUBJECT 0x0b
59 #define PNMFC_BODY 0x0c
60 #define PNMFC_REPLY_UNKNOWN 0x12 // this appears on replies, always 0x00
61 #define PNMFC_RECORDID 0x4b // Internal Message ID, mimics header RecNumber
62 #define PNMFC_END 0xffff
64 #define PRIORITY_MASK 0x003f
65 #define PRIORITY_HIGH 0x0008
66 #define PRIORITY_LOW 0x0002
68 #define SENSITIVE_MASK 0xff80
69 #define SENSITIVE_CONFIDENTIAL 0x0100
70 #define SENSITIVE_PERSONAL 0x0080
71 #define SENSITIVE_PRIVATE 0x0040 // actual pattern is 0x00C0
73 #define MESSAGE_READ 0x0800
74 #define MESSAGE_REPLY 0x0001
75 #define MESSAGE_SAVED 0x0002
76 #define MESSAGE_FORWARD 0x0008
77 #define MESSAGE_TRUNCATED 0x0020
78 #define MESSAGE_SAVED_DELETED 0x0080
80 FieldLink
<PINMessage
> PINMessageFieldLinks
[] = {
81 { PNMFC_TO
, "To", 0, 0, 0, &PINMessage::To
, 0 },
82 { PNMFC_CC
, "Cc", 0, 0, 0, &PINMessage::Cc
, 0 },
83 { PNMFC_BCC
, "Bcc", 0, 0, 0, &PINMessage::Bcc
, 0 },
84 { PNMFC_FROM
, "From", 0, 0, 0, &PINMessage::From
, 0 },
85 { PNMFC_SUBJECT
, "Subject", 0, 0, &PINMessage::Subject
, 0, 0 },
86 { PNMFC_BODY
, "Body", 0, 0, &PINMessage::Body
, 0, 0 },
87 { PNMFC_END
, "End of List", 0, 0, 0, 0, 0 }
90 PINMessage::PINMessage()
94 PINMessage::~PINMessage()
98 const unsigned char* PINMessage::ParseField(const unsigned char *begin
,
99 const unsigned char *end
)
101 const CommonField
*field
= (const CommonField
*) begin
;
103 // advance and check size
104 begin
+= COMMON_FIELD_HEADER_SIZE
+ btohs(field
->size
);
105 if( begin
> end
) // if begin==end, we are ok
108 if( !btohs(field
->size
) ) // if field has no size, something's up
111 // cycle through the type table
112 for( FieldLink
<PINMessage
> *b
= PINMessageFieldLinks
;
113 b
->type
!= PNMFC_END
;
116 if( b
->type
== field
->type
) {
118 // parse regular string
119 std::string
&s
= this->*(b
->strMember
);
120 s
.assign((const char *)field
->u
.raw
, btohs(field
->size
)-1);
121 return begin
; // done!
123 else if( b
->addrMember
) {
124 // parse email address
125 // get dual name+addr string first
126 const char *fa
= (const char*)field
->u
.addr
.addr
;
127 std::string
dual(fa
, btohs(field
->size
) - sizeof(field
->u
.addr
.unknown
));
129 // assign first string, using null terminator...letting std::string add it for us if it doesn't exist
130 Address
&a
= this->*(b
->addrMember
);
131 a
.Name
= dual
.c_str();
133 // assign second string, using first size as starting point
134 a
.Email
= dual
.c_str() + a
.Name
.size() + 1;
140 // handle special cases
141 switch( field
->type
)
144 MessageRecordId
= field
->u
.uint32
;
148 // if still not handled, add to the Unknowns list
150 uf
.type
= field
->type
;
151 uf
.data
.assign((const char*)field
->u
.raw
, btohs(field
->size
));
152 Unknowns
.push_back(uf
);
157 void PINMessage::ParseHeader(const Data
&data
, size_t &offset
)
159 // FIXME - we are using a Message (email) record header size
160 // for a PIN Message record... this is not necessarily guaranteed
161 // to be the same... someday we could use some more info on
162 // the message record header and pin message record header
164 // FIXED - the header structure for both the PIN messages and
165 // email messages are the same, as is the header structure for
166 // 'Saved Email Messages' although some of the fields may not directly apply.
168 // and someday is now here ;) - edge
170 MAKE_RECORD(const Barry::Protocol::MessageRecord
, mr
, data
, offset
);
172 MessagePriority
= NormalPriority
;
173 if( mr
->priority
& PRIORITY_MASK
) {
174 if( mr
->priority
& PRIORITY_HIGH
) {
175 MessagePriority
= HighPriority
;
177 else if( mr
->priority
& PRIORITY_LOW
) {
178 MessagePriority
= LowPriority
;
181 MessagePriority
= UnknownPriority
;
184 MessageSensitivity
= NormalSensitivity
;
185 if( mr
->priority
& SENSITIVE_MASK
) {
186 if(( mr
->priority
& SENSITIVE_CONFIDENTIAL
) == SENSITIVE_CONFIDENTIAL
) {
187 MessageSensitivity
= Confidential
;
189 else if(( mr
->priority
& SENSITIVE_PRIVATE
) == SENSITIVE_PRIVATE
) {
190 MessageSensitivity
= Private
;
192 else if(( mr
->priority
& SENSITIVE_PERSONAL
) == SENSITIVE_PERSONAL
) {
193 MessageSensitivity
= Personal
;
196 MessageSensitivity
= UnknownSensitivity
;
198 // X-rim-org-message-ref-id // NOTE: I'm cheating a bit here and using this as a reply-to
199 if( mr
->inReplyTo
) // It's actually sent by BB with the actual UID in every message
200 MessageReplyTo
= mr
->inReplyTo
;
202 if( !( mr
->flags
& MESSAGE_READ
))
203 MessageRead
= true; // NOTE: A lot of these flags are 'backwards' but this seemed
204 // like the most logical way to interpret them for now
205 if(( mr
->flags
& MESSAGE_REPLY
) == MESSAGE_REPLY
)
206 MessageReply
= true; // NOTE: This is a reply, the original message's flags are not changed
207 // the inReplyTo field is updated with the original messages's UID
208 if( !( mr
->flags
& MESSAGE_TRUNCATED
))
209 MessageTruncated
= true; // NOTE: This bit is unset on truncation, around 4096 on my 7100g
210 // NOTE: bit 0x400 is set on REALLY huge messages, haven't tested
211 // the exact size yet
212 if( !( mr
->flags
& MESSAGE_SAVED
))
213 MessageSaved
= true; // NOTE: Saved to 'saved' folder
214 if( !( mr
->flags
& MESSAGE_SAVED_DELETED
))
215 MessageSavedDeleted
= true; // NOTE: Saved to 'saved' folder and then deleted from inbox
217 MessageDateSent
= ( mr
->dateSent
& 0x01ff ) - 0x29;
218 MessageDateSent
= DayToDate( MessageDateSent
);
219 MessageDateSent
+= (time_t)( mr
->timeSent
*1.77 );
221 MessageDateReceived
= ( mr
->dateReceived
& 0x01ff ) - 0x29;
222 MessageDateReceived
= DayToDate( MessageDateReceived
);
223 MessageDateReceived
+= (time_t)( mr
->timeReceived
*1.77 );
225 offset
+= MESSAGE_RECORD_HEADER_SIZE
;
228 void PINMessage::ParseFields(const Data
&data
, size_t &offset
)
230 const unsigned char *finish
= ParseCommonFields(*this,
231 data
.GetData() + offset
, data
.GetData() + data
.GetSize());
232 offset
+= finish
- (data
.GetData() + offset
);
235 void PINMessage::BuildHeader(Data
&data
, size_t &offset
) const
237 throw std::logic_error("PINMessage::BuildHeader not yet implemented");
240 void PINMessage::BuildFields(Data
&data
, size_t &offset
) const
242 throw std::logic_error("PINMessage::BuildFields not yet implemented");
245 void PINMessage::Clear()
258 MessageDateReceived
= 0;
259 MessageTruncated
= false;
261 MessageReply
= false;
262 MessageSaved
= false;
263 MessageSavedDeleted
= false;
268 // dump message in mbox format
269 void PINMessage::Dump(std::ostream
&os
) const
271 static const char *MessageImportance
[] =
272 { "Low", "Normal", "High", "Unknown Priority" };
273 static const char *MessageSensitivityString
[] =
274 { "Normal", "Personal", "Private", "Confidential", "Unknown Sensivity" };
276 os
<< "From " << (From
.Email
.size() ? From
.Email
.c_str() : "unknown")
277 << " " << ctime( &MessageDateSent
);
278 os
<< "X-Record-ID: (" << setw(8) << std::hex
<< MessageRecordId
<< ")\n";
280 os
<< "X-rim-org-msg-ref-id: " << std::dec
<< MessageReplyTo
<< "\n";
282 os
<< "Message Status: Saved\n";
283 else if( MessageRead
)
284 os
<< "Message Status: Opened\n";
285 if( MessagePriority
!= NormalPriority
)
286 os
<< "Importance: " << MessageImportance
[MessagePriority
] << "\n";
287 if( MessageSensitivity
!= NormalSensitivity
)
288 os
<< "Sensitivity: " << MessageSensitivityString
[MessageSensitivity
] << "\n";
289 os
<< "Date: " << ctime(&MessageDateSent
);
291 if( From
.Name
.size()) {
292 os
<< " From: " << From
.Name
<< " <" << From
.Email
<< ">\n";
294 if( To
.Name
.size()) {
295 os
<< " To: " << To
.Name
<< " <" << To
.Email
<< ">\n";
297 if( Cc
.Name
.size()) {
298 os
<< " Cc: " << Cc
.Name
<< " <" << Cc
.Email
<< ">\n";
300 if( Bcc
.Name
.size()) {
301 os
<< " Bcc: " << Bcc
.Name
<< " <" << Bcc
.Email
<< ">\n";
305 os
<< " Subject: " << Subject
<< "\n";
307 os
<< " Subject: <>\n";
310 for( std::string::const_iterator i
= Body
.begin();
311 i
!= Body
.end() && *i
;