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-2012, 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 #include "ios_state.h"
00032 
00033 using namespace std;
00034 using namespace Barry::Protocol;
00035 
00036 namespace Barry {
00037 
00038 ///////////////////////////////////////////////////////////////////////////////
00039 // Memo Class
00040 
00041 // Memo Field Codes
00042 #define MEMFC_TITLE             0x01
00043 #define MEMFC_BODY              0x02
00044 #define MEMFC_MEMO_TYPE         0x03
00045 #define MEMFC_CATEGORY          0x04
00046 #define MEMFC_END               0xffff
00047 
00048 static FieldLink<Memo> MemoFieldLinks[] = {
00049     { MEMFC_TITLE,     "Title",       0, 0, &Memo::Title, 0, 0, 0, 0, true },
00050     { MEMFC_BODY,      "Body",        0, 0, &Memo::Body, 0, 0, 0, 0, true },
00051     { MEMFC_END,       "End of List", 0, 0, 0, 0, 0, 0, 0, false }
00052 };
00053 
00054 Memo::Memo()
00055 {
00056         Clear();
00057 }
00058 
00059 Memo::~Memo()
00060 {
00061 }
00062 
00063 const unsigned char* Memo::ParseField(const unsigned char *begin,
00064                                       const unsigned char *end,
00065                                       const IConverter *ic)
00066 {
00067         const CommonField *field = (const CommonField *) begin;
00068 
00069         // advance and check size
00070         begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00071         if( begin > end )       // if begin==end, we are ok
00072                 return begin;
00073 
00074         if( !btohs(field->size) )   // if field has no size, something's up
00075                 return begin;
00076 
00077         if( field->type == MEMFC_MEMO_TYPE ) {
00078                 if( field->u.raw[0] != 'm' ) {
00079                         throw Error( "Memo::ParseField: MemoType is not 'm'" );
00080                 }
00081                 return begin;
00082         }
00083 
00084 
00085         // cycle through the type table
00086         for(    FieldLink<Memo> *b = MemoFieldLinks;
00087                 b->type != MEMFC_END;
00088                 b++ )
00089         {
00090                 if( b->type == field->type ) {
00091                         if( b->strMember ) {
00092                                 std::string &s = this->*(b->strMember);
00093                                 s = ParseFieldString(field);
00094                                 if( b->iconvNeeded && ic )
00095                                         s = ic->FromBB(s);
00096                                 return begin;   // done!
00097                         }
00098                         else if( b->timeMember && btohs(field->size) == 4 ) {
00099                                 TimeT &t = this->*(b->timeMember);
00100                                 t.Time = min2time(field->u.min1900);
00101                                 return begin;
00102                         }
00103                 }
00104         }
00105         // handle special cases
00106         switch( field->type )
00107         {
00108         case MEMFC_CATEGORY:
00109                 {
00110                         std::string catstring = ParseFieldString(field);
00111                         if( ic )
00112                                 catstring = ic->FromBB(catstring);
00113                         Categories.CategoryStr2List(catstring);
00114                 }
00115                 return begin;
00116         }
00117 
00118         // if still not handled, add to the Unknowns list
00119         UnknownField uf;
00120         uf.type = field->type;
00121         uf.data.assign((const char*)field->u.raw, btohs(field->size));
00122         Unknowns.push_back(uf);
00123 
00124         // return new pointer for next field
00125         return begin;
00126 }
00127 
00128 void Memo::ParseHeader(const Data &data, size_t &offset)
00129 {
00130         // no header in Memo records
00131 }
00132 
00133 void Memo::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00134 {
00135         const unsigned char *finish = ParseCommonFields(*this,
00136                 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00137         offset += finish - (data.GetData() + offset);
00138 }
00139 
00140 
00141 void Memo::Validate() const
00142 {
00143 }
00144 
00145 void Memo::BuildHeader(Data &data, size_t &offset) const
00146 {
00147         // no header in Memo records
00148 }
00149 
00150 
00151 //
00152 // Build
00153 //
00154 /// Build fields part of record.
00155 ///
00156 void Memo::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00157 {
00158         data.Zap();
00159 
00160         // tack on the 'm' memo type field first
00161         BuildField(data, offset, MEMFC_MEMO_TYPE, 'm');
00162 
00163         // Categories
00164         if( Categories.size() ) {
00165                 string store;
00166                 Categories.CategoryList2Str(store);
00167                 BuildField(data, offset, MEMFC_CATEGORY, ic ? ic->ToBB(store) : store);
00168         }
00169 
00170         // cycle through the type table
00171         for(    FieldLink<Memo> *b = MemoFieldLinks;
00172                 b->type != MEMFC_END;
00173                 b++ )
00174         {
00175                 // print only fields with data
00176                 if( b->strMember ) {
00177                         const std::string &field = this->*(b->strMember);
00178                         if( field.size() ) {
00179                                 std::string s = (b->iconvNeeded && ic) ? ic->ToBB(field) : field;
00180                                 BuildField(data, offset, b->type, s);
00181                         }
00182                 }
00183                 else if( b->postMember && b->postField ) {
00184                         const std::string &field = (this->*(b->postMember)).*(b->postField);
00185                         if( field.size() ) {
00186                                 std::string s = (b->iconvNeeded && ic) ? ic->ToBB(field) : field;
00187                                 BuildField(data, offset, b->type, s);
00188                         }
00189                 }
00190         }
00191 
00192         // and finally save unknowns
00193         UnknownsType::const_iterator
00194                 ub = Unknowns.begin(), ue = Unknowns.end();
00195         for( ; ub != ue; ub++ ) {
00196                 BuildField(data, offset, *ub);
00197         }
00198 
00199         data.ReleaseBuffer(offset);
00200 }
00201 
00202 
00203 
00204 void Memo::Dump(std::ostream &os) const
00205 {
00206         ios_format_state state(os);
00207 
00208         os << "Memo entry: 0x" << setbase(16) << RecordId
00209            << " (" << (unsigned int)RecType << ")\n";
00210         os << "    Title: " << Title << "\n";
00211         os << "    Body: ";
00212 
00213         // The Body may have '\r' characters... translate them
00214         // in the output to make it look more pretty
00215         for( string::const_iterator i = Body.begin(); i != Body.end(); ++i ) {
00216                 if( *i == '\r' )
00217                         os << "\n          ";
00218                 else
00219                         os << *i;
00220         }
00221         os << "\n";
00222 
00223         if( Categories.size() ) {
00224                 string display;
00225                 Categories.CategoryList2Str(display);
00226                 os << "    Categories: " << display << "\n";
00227         }
00228 
00229         os << Unknowns;
00230         os << "\n\n";
00231 }
00232 
00233 bool Memo::operator<(const Memo &other) const
00234 {
00235         int cmp = Title.compare(other.Title);
00236         if( cmp == 0 )
00237                 cmp = Body.compare(other.Body);
00238         return cmp < 0;
00239 }
00240 
00241 void Memo::Clear()
00242 {
00243         RecType = GetDefaultRecType();
00244         RecordId = 0;
00245 
00246         Title.clear();
00247         Body.clear();
00248         Categories.clear();
00249 
00250         Unknowns.clear();
00251 }
00252 
00253 const FieldHandle<Memo>::ListT& Memo::GetFieldHandles()
00254 {
00255         static FieldHandle<Memo>::ListT fhv;
00256 
00257         if( fhv.size() )
00258                 return fhv;
00259 
00260 #undef CONTAINER_OBJECT_NAME
00261 #define CONTAINER_OBJECT_NAME fhv
00262 
00263 #undef RECORD_CLASS_NAME
00264 #define RECORD_CLASS_NAME Memo
00265 
00266         FHP(RecType, "Record Type Code");
00267         FHP(RecordId, "Unique Record ID");
00268 
00269         FHD(Title, "Title", MEMFC_TITLE, true);
00270         FHD(Body, "Body", MEMFC_BODY, true);
00271         FHD(Categories, "Categories", MEMFC_CATEGORY, true);
00272 
00273         FHP(Unknowns, "Unknown Fields");
00274 
00275         return fhv;
00276 }
00277 
00278 std::string Memo::GetDescription() const
00279 {
00280         return Title;
00281 }
00282 
00283 } // namespace Barry
00284