- updated r_saved_messages.cc comment to match header
[barry.git] / src / r_saved_message.cc
blobfd14353f2046d23f3cbc79209b7cf2fe25983391
1 ///
2 /// \file r_saved_message.cc
3 /// Blackberry database record parser class for saved email
4 /// message records.
5 ///
7 /*
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"
26 #include "protocol.h"
27 #include "protostructs.h"
28 #include "data.h"
29 #include "time.h"
30 #include "error.h"
31 #include "endian.h"
32 #include <ostream>
33 #include <iomanip>
34 #include <time.h>
35 #include <stdexcept>
37 #define __DEBUG_MODE__
38 #include "debug.h"
40 using namespace std;
41 using namespace Barry::Protocol;
43 namespace Barry {
45 ///////////////////////////////////////////////////////////////////////////////
46 // Message class
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 FieldLink<SavedMessage> SavedMessageFieldLinks[] = {
63 { SEMFC_TO, "To", 0, 0, 0, &SavedMessage::To, 0 },
64 { SEMFC_CC, "Cc", 0, 0, 0, &SavedMessage::Cc, 0 },
65 { SEMFC_BCC, "Bcc", 0, 0, 0, &SavedMessage::Bcc, 0 },
66 { SEMFC_SENDER, "Sender", 0, 0, 0, &SavedMessage::Sender, 0 },
67 { SEMFC_FROM, "From", 0, 0, 0, &SavedMessage::From, 0 },
68 { SEMFC_REPLY_TO, "ReplyTo", 0, 0, 0, &SavedMessage::ReplyTo, 0 },
69 { SEMFC_SUBJECT, "Subject", 0, 0, &SavedMessage::Subject, 0, 0 },
70 { SEMFC_BODY, "Body", 0, 0, &SavedMessage::Body, 0, 0 },
71 { SEMFC_ATTACHMENT, "Attachment", 0, 0, &SavedMessage::Attachment, 0, 0 },
72 { SEMFC_END, "End of List", 0, 0, 0, 0, 0 }
75 SavedMessage::SavedMessage()
77 Clear();
80 SavedMessage::~SavedMessage()
84 const unsigned char* SavedMessage::ParseField(const unsigned char *begin,
85 const unsigned char *end)
87 const CommonField *field = (const CommonField *) begin;
89 // advance and check size
90 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
91 if( begin > end ) // if begin==end, we are ok
92 return begin;
94 if( !btohs(field->size) ) // if field has no size, something's up
95 return begin;
97 // cycle through the type table
98 for( FieldLink<SavedMessage> *b = SavedMessageFieldLinks;
99 b->type != SEMFC_END;
100 b++ )
102 if( b->type == field->type ) {
103 if( b->strMember ) {
104 // parse regular string
105 std::string &s = this->*(b->strMember);
106 s.assign((const char *)field->u.raw, btohs(field->size)-1);
107 return begin; // done!
109 else if( b->addrMember ) {
110 // parse email address
111 // get dual name+addr string first
112 const char *fa = (const char*)field->u.addr.addr;
113 std::string dual(fa, btohs(field->size) - sizeof(field->u.addr.unknown));
115 // assign first string, using null terminator...letting std::string add it for us if it doesn't exist
116 Address &a = this->*(b->addrMember);
117 a.Name = dual.c_str();
119 // assign second string, using first size as starting point
120 a.Email = dual.c_str() + a.Name.size() + 1;
121 return begin;
126 // handle special cases
127 switch( field->type )
129 case SEMFC_RECORDID:
130 MessageRecordId = field->u.uint32;
131 return begin;
134 // if still not handled, add to the Unknowns list
135 UnknownField uf;
136 uf.type = field->type;
137 uf.data.assign((const char*)field->u.raw, btohs(field->size));
138 Unknowns.push_back(uf);
140 return begin;
143 void SavedMessage::ParseHeader(const Data &data, size_t &offset)
145 // we skip the "header" since we don't know what to do with it yet
146 // FIXME - we are using a Message (email) record header size
147 // for a PIN Message record... this is not necessarily guaranteed
148 // to be the same... someday we could use some more info on
149 // the message record header and pin message record header
150 offset += MESSAGE_RECORD_HEADER_SIZE;
153 void SavedMessage::ParseFields(const Data &data, size_t &offset)
155 const unsigned char *finish = ParseCommonFields(*this,
156 data.GetData() + offset, data.GetData() + data.GetSize());
157 offset += finish - (data.GetData() + offset);
160 void SavedMessage::BuildHeader(Data &data, size_t &offset) const
162 throw std::logic_error("SavedMessage::BuildHeader not yet implemented");
165 void SavedMessage::BuildFields(Data &data, size_t &offset) const
167 throw std::logic_error("SavedMessage::BuildFields not yet implemented");
170 void SavedMessage::Clear()
172 From.clear();
173 To.clear();
174 Cc.clear();
175 Bcc.clear();
176 Sender.clear();
177 ReplyTo.clear();
178 Subject.clear();
179 Body.clear();
180 Attachment.clear();
182 MessageRecordId = 0;
184 Unknowns.clear();
187 // dump message in mbox format
188 void SavedMessage::Dump(std::ostream &os) const
190 // FIXME - use current time until we figure out the date headers
191 time_t fixme = time(NULL);
193 os << "From " << (From.Email.size() ? From.Email.c_str() : "unknown")
194 << " " << ctime(&fixme);
195 os << "X-Record-ID: (0x" << std::hex << MessageRecordId << ")\n";
196 os << "Date: " << ctime(&fixme);
197 os << "From: " << From << "\n";
198 if( To.Email.size() )
199 os << "To: " << To << "\n";
200 if( Cc.Email.size() )
201 os << "Cc: " << Cc << "\n";
202 if( Bcc.Email.size() )
203 os << "Bcc: " << Bcc << "\n";
204 if( Sender.Email.size() )
205 os << "Sender: " << Sender << "\n";
206 if( ReplyTo.Email.size())
207 os << "Reply To: " << ReplyTo << "\n";
208 if( Subject.size() )
209 os << "Subject: " << Subject << "\n";
210 os << "\n";
211 for( std::string::const_iterator i = Body.begin();
212 i != Body.end() && *i;
213 i++)
215 if( *i == '\r' )
216 os << '\n';
217 else
218 os << *i;
220 os << "\n";
221 if( Attachment.size() )
222 os << "Attachments: " << Attachment << "\n";
224 os << Unknowns;
225 os << "\n\n";
229 } // namespace Barry