00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "r_memo.h"
00024 #include "record-internal.h"
00025 #include "protostructs.h"
00026 #include "data.h"
00027 #include "time.h"
00028 #include "iconv.h"
00029 #include <ostream>
00030 #include <iomanip>
00031
00032 using namespace std;
00033 using namespace Barry::Protocol;
00034
00035 namespace Barry {
00036
00037
00038
00039
00040
00041 #define MEMFC_TITLE 0x01
00042 #define MEMFC_BODY 0x02
00043 #define MEMFC_MEMO_TYPE 0x03
00044 #define MEMFC_CATEGORY 0x04
00045 #define MEMFC_END 0xffff
00046
00047 static FieldLink<Memo> MemoFieldLinks[] = {
00048 { MEMFC_TITLE, "Title", 0, 0, &Memo::Title, 0, 0, 0, 0, true },
00049 { MEMFC_BODY, "Body", 0, 0, &Memo::Body, 0, 0, 0, 0, true },
00050 { MEMFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false }
00051 };
00052
00053 Memo::Memo()
00054 {
00055 Clear();
00056 }
00057
00058 Memo::~Memo()
00059 {
00060 }
00061
00062 const unsigned char* Memo::ParseField(const unsigned char *begin,
00063 const unsigned char *end,
00064 const IConverter *ic)
00065 {
00066 const CommonField *field = (const CommonField *) begin;
00067
00068
00069 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00070 if( begin > end )
00071 return begin;
00072
00073 if( !btohs(field->size) )
00074 return begin;
00075
00076 if( field->type == MEMFC_MEMO_TYPE ) {
00077 if( field->u.raw[0] != 'm' ) {
00078 throw Error( "Memo::ParseField: MemoType is not 'm'" );
00079 }
00080 return begin;
00081 }
00082
00083
00084
00085 for( FieldLink<Memo> *b = MemoFieldLinks;
00086 b->type != MEMFC_END;
00087 b++ )
00088 {
00089 if( b->type == field->type ) {
00090 if( b->strMember ) {
00091 std::string &s = this->*(b->strMember);
00092 s = ParseFieldString(field);
00093 if( b->iconvNeeded && ic )
00094 s = ic->FromBB(s);
00095 return begin;
00096 }
00097 else if( b->timeMember && btohs(field->size) == 4 ) {
00098 time_t &t = this->*(b->timeMember);
00099 t = min2time(field->u.min1900);
00100 return begin;
00101 }
00102 }
00103 }
00104
00105 switch( field->type )
00106 {
00107 case MEMFC_CATEGORY:
00108 {
00109 std::string catstring = ParseFieldString(field);
00110 if( ic )
00111 catstring = ic->FromBB(catstring);
00112 Categories.CategoryStr2List(catstring);
00113 }
00114 return begin;
00115 }
00116
00117
00118 UnknownField uf;
00119 uf.type = field->type;
00120 uf.data.assign((const char*)field->u.raw, btohs(field->size));
00121 Unknowns.push_back(uf);
00122
00123
00124 return begin;
00125 }
00126
00127 void Memo::ParseHeader(const Data &data, size_t &offset)
00128 {
00129
00130 }
00131
00132 void Memo::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00133 {
00134 const unsigned char *finish = ParseCommonFields(*this,
00135 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00136 offset += finish - (data.GetData() + offset);
00137 }
00138
00139
00140 void Memo::BuildHeader(Data &data, size_t &offset) const
00141 {
00142
00143 }
00144
00145
00146
00147
00148
00149
00150
00151 void Memo::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00152 {
00153 data.Zap();
00154
00155
00156 BuildField(data, offset, MEMFC_MEMO_TYPE, 'm');
00157
00158
00159 if( Categories.size() ) {
00160 string store;
00161 Categories.CategoryList2Str(store);
00162 BuildField(data, offset, MEMFC_CATEGORY, ic ? ic->ToBB(store) : store);
00163 }
00164
00165
00166 for( FieldLink<Memo> *b = MemoFieldLinks;
00167 b->type != MEMFC_END;
00168 b++ )
00169 {
00170
00171 if( b->strMember ) {
00172 const std::string &field = this->*(b->strMember);
00173 if( field.size() ) {
00174 std::string s = (b->iconvNeeded && ic) ? ic->ToBB(field) : field;
00175 BuildField(data, offset, b->type, s);
00176 }
00177 }
00178 else if( b->postMember && b->postField ) {
00179 const std::string &field = (this->*(b->postMember)).*(b->postField);
00180 if( field.size() ) {
00181 std::string s = (b->iconvNeeded && ic) ? ic->ToBB(field) : field;
00182 BuildField(data, offset, b->type, s);
00183 }
00184 }
00185 }
00186
00187
00188 UnknownsType::const_iterator
00189 ub = Unknowns.begin(), ue = Unknowns.end();
00190 for( ; ub != ue; ub++ ) {
00191 BuildField(data, offset, *ub);
00192 }
00193
00194 data.ReleaseBuffer(offset);
00195 }
00196
00197
00198
00199 void Memo::Dump(std::ostream &os) const
00200 {
00201 os << "Memo entry: 0x" << setbase(16) << RecordId
00202 << " (" << (unsigned int)RecType << ")\n";
00203 os << " Title: " << Title << "\n";
00204 os << " Body: ";
00205
00206
00207
00208 for( string::const_iterator i = Body.begin(); i != Body.end(); ++i ) {
00209 if( *i == '\r' )
00210 os << "\n ";
00211 else
00212 os << *i;
00213 }
00214 os << "\n";
00215
00216 if( Categories.size() ) {
00217 string display;
00218 Categories.CategoryList2Str(display);
00219 os << " Categories: " << display << "\n";
00220 }
00221
00222 os << Unknowns;
00223 os << "\n\n";
00224 }
00225
00226 bool Memo::operator<(const Memo &other) const
00227 {
00228 int cmp = Title.compare(other.Title);
00229 if( cmp == 0 )
00230 cmp = Body.compare(other.Body);
00231 return cmp < 0;
00232 }
00233
00234 void Memo::Clear()
00235 {
00236 RecType = GetDefaultRecType();
00237 RecordId = 0;
00238
00239 Title.clear();
00240 Body.clear();
00241 Categories.clear();
00242
00243 Unknowns.clear();
00244 }
00245
00246
00247 }
00248