- fixed null pointer access in opensync's HasMultipleVEvents()
[barry.git] / src / r_pin_message.cc
bloba6dd5dfcaf52f0cc3672a8ae1be4fd8ce81b1867
1 ///
2 /// \file r_pin_message.cc
3 /// Blackberry database record parser class for pin message records.
4 ///
6 /*
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"
25 #include "protocol.h"
26 #include "protostructs.h"
27 #include "data.h"
28 #include "time.h"
29 #include "error.h"
30 #include "endian.h"
31 #include <ostream>
32 #include <iomanip>
33 #include <time.h>
34 #include <stdexcept>
36 #define __DEBUG_MODE__
37 #include "debug.h"
39 using namespace std;
40 using namespace Barry::Protocol;
42 namespace Barry {
44 //std::ostream& operator<<(std::ostream &os, const Address &msgp) {
45 // os << msgp.Name.c_str() << " <" << msgp.Email.c_str() << ">";
46 // return os;
47 //}
49 ///////////////////////////////////////////////////////////////////////////////
50 // PINMessage class
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
106 return begin;
108 if( !btohs(field->size) ) // if field has no size, something's up
109 return begin;
111 // cycle through the type table
112 for( FieldLink<PINMessage> *b = PINMessageFieldLinks;
113 b->type != PNMFC_END;
114 b++ )
116 if( b->type == field->type ) {
117 if( b->strMember ) {
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;
135 return begin;
140 // handle special cases
141 switch( field->type )
143 case PNMFC_RECORDID:
144 MessageRecordId = field->u.uint32;
145 return begin;
148 // if still not handled, add to the Unknowns list
149 UnknownField uf;
150 uf.type = field->type;
151 uf.data.assign((const char*)field->u.raw, btohs(field->size));
152 Unknowns.push_back(uf);
154 return begin;
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);
171 // Priority
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;
180 else
181 MessagePriority = UnknownPriority;
183 // Sensitivity
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;
195 else
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;
201 // Status Flags
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()
247 From.clear();
248 To.clear();
249 Cc.clear();
250 Bcc.clear();
252 Subject.clear();
253 Body.clear();
255 MessageRecordId = 0;
256 MessageReplyTo = 0;
257 MessageDateSent = 0;
258 MessageDateReceived = 0;
259 MessageTruncated = false;
260 MessageRead = false;
261 MessageReply = false;
262 MessageSaved = false;
263 MessageSavedDeleted = false;
265 Unknowns.clear();
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";
279 if( MessageReplyTo )
280 os << "X-rim-org-msg-ref-id: " << std::dec << MessageReplyTo << "\n";
281 if( MessageSaved )
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";
304 if( Subject.size() )
305 os << " Subject: " << Subject << "\n";
306 else
307 os << " Subject: <>\n";
308 os << "\n";
310 for( std::string::const_iterator i = Body.begin();
311 i != Body.end() && *i;
312 i++)
314 if( *i == '\r' )
315 os << '\n';
316 else
317 os << *i;
319 os << "\n";
321 os << Unknowns;
322 os << "\n\n";
326 } // namespace Barry