# r_memo.cc

Go to the documentation of this file.

    00001 ///
    00002 /// \file       r_memo.cc
    00003 ///             Record parsing class for the memo database.
    00004 ///
    00005
    00006 /*
    00007     Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/)
    00008     Copyright (C) 2007, Brian Edginton
    00009
    00010     This program is free software; you can redistribute it and/or modify
    00011     it under the terms of the GNU General Public License as published by
    00012     the Free Software Foundation; either version 2 of the License, or
    00013     (at your option) any later version.
    00014
    00015     This program is distributed in the hope that it will be useful,
    00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00018
    00019     See the GNU General Public License in the COPYING file at the
    00020     root directory of this project for more details.
    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 // Memo Class
    00039
    00040 // Memo Field Codes
    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         // advance and check size
    00069         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
    00070         if( begin > end )       // if begin==end, we are ok
    00071                 return begin;
    00072
    00073         if( !btohs(field->size) )   // if field has no size, something's up
    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         // cycle through the type table
    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;   // done!
    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         // handle special cases
    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         // if still not handled, add to the Unknowns list
    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         // return new pointer for next field
    00124         return begin;
    00125 }
    00126
    00127 void Memo::ParseHeader(const Data &data, size_t &offset)
    00128 {
    00129         // no header in Memo records
    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         // no header in Memo records
    00143 }
    00144
    00145
    00146 //
    00147 // Build
    00148 //
    00149 /// Build fields part of record.
    00150 ///
    00151 void Memo::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
    00152 {
    00153         data.Zap();
    00154
    00155         // tack on the 'm' memo type field first
    00156         BuildField(data, offset, MEMFC_MEMO_TYPE, 'm');
    00157
    00158         // Categories
    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         // cycle through the type table
    00166         for(    FieldLink<Memo> *b = MemoFieldLinks;
    00167                 b->type != MEMFC_END;
    00168                 b++ )
    00169         {
    00170                 // print only fields with data
    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         // and finally save unknowns
    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         // The Body may have '\r' characters... translate them
    00207         // in the output to make it look more pretty
    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 std::string Memo::GetDescription() const
    00247 {
    00248         return Title;
    00249 }
    00250
    00251 } // namespace Barry
    00252