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_servicebook.h"
00024 #include "record-internal.h"
00025 #include "protocol.h"
00026 #include "protostructs.h"
00027 #include "data.h"
00028 #include "time.h"
00029 #include "error.h"
00030 #include "endian.h"
00031 #include "iconv.h"
00032 #include <ostream>
00033 #include <iomanip>
00034 #include <time.h>
00035 #include <stdexcept>
00036
00037 #define __DEBUG_MODE__
00038 #include "debug.h"
00039
00040 using namespace std;
00041 using namespace Barry::Protocol;
00042
00043 namespace Barry {
00044
00045
00046
00047
00048
00049 #define SBFCC_END 0xffff
00050
00051 static FieldLink<ServiceBookConfig> ServiceBookConfigFieldLinks[] = {
00052
00053 { SBFCC_END, "End of List",0, 0, 0, 0, 0 }
00054 };
00055
00056 ServiceBookConfig::ServiceBookConfig()
00057 : Format(0)
00058 {
00059 Clear();
00060 }
00061
00062 ServiceBookConfig::~ServiceBookConfig()
00063 {
00064 }
00065
00066 const unsigned char* ServiceBookConfig::ParseField(const unsigned char *begin,
00067 const unsigned char *end,
00068 const IConverter *ic)
00069 {
00070 const void *raw;
00071 uint16_t size, type;
00072
00073 switch( Format )
00074 {
00075 case 0x01:
00076 case 0x02:
00077 {
00078 const PackedField_02 *field = (const PackedField_02 *) begin;
00079 raw = field->raw;
00080 size = field->size;
00081 type = field->type;
00082 begin += PACKED_FIELD_02_HEADER_SIZE + size;
00083 }
00084 break;
00085
00086 case 0x10:
00087 {
00088 const PackedField_10 *field = (const PackedField_10 *) begin;
00089 raw = field->raw;
00090 size = field->size;
00091 type = field->type;
00092 begin += PACKED_FIELD_10_HEADER_SIZE + size;
00093 }
00094 break;
00095
00096 default:
00097 eout("------> Unknown packed field format: 0x" << std::hex <<
00098 (unsigned int) Format);
00099 throw BadPackedFormat(Format);
00100 return begin + 1;
00101 }
00102
00103
00104
00105 if( begin > end )
00106 return begin;
00107
00108 if( !size )
00109 return begin;
00110
00111
00112 for( FieldLink<ServiceBookConfig> *b = ServiceBookConfigFieldLinks;
00113 b->type != SBFCC_END;
00114 b++ )
00115 {
00116 if( b->type == type ) {
00117 if( b->strMember ) {
00118 std::string &s = this->*(b->strMember);
00119 s = ParseFieldString(raw, size-1);
00120 return begin;
00121 }
00122 }
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 UnknownField uf;
00134 uf.type = type;
00135 uf.data.assign((const char*)raw, size);
00136 Unknowns.push_back(uf);
00137
00138
00139 return begin;
00140 }
00141
00142 void ServiceBookConfig::ParseHeader(const Data &data, size_t &offset)
00143 {
00144 MAKE_RECORD(const Barry::Protocol::ServiceBookConfigField, sbc, data, offset);
00145 offset += SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE;
00146 if( data.GetSize() >= offset ) {
00147 Format = sbc->format;
00148 }
00149 }
00150
00151 void ServiceBookConfig::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00152 {
00153 const unsigned char *finish = ParseCommonFields(*this,
00154 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00155 offset += finish - (data.GetData() + offset);
00156 }
00157
00158 void ServiceBookConfig::BuildHeader(Data &data, size_t &offset) const
00159 {
00160
00161 data.GetBuffer(offset + SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE);
00162
00163 MAKE_RECORD(Barry::Protocol::ServiceBookConfigField, sbc, data, offset);
00164 sbc->format = Format;
00165
00166 offset += SERVICE_BOOK_CONFIG_FIELD_HEADER_SIZE;
00167 }
00168
00169
00170
00171
00172
00173
00174 void ServiceBookConfig::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00175 {
00176 throw std::logic_error("ServiceBookConfig::Build not yet implemented");
00177 }
00178
00179 void ServiceBookConfig::Clear()
00180 {
00181 Format = 0;
00182 Unknowns.clear();
00183 }
00184
00185 void ServiceBookConfig::Dump(std::ostream &os) const
00186 {
00187 os << " ServiceBookConfig Format: " << setbase(16) << (uint16_t)Format << "\n";
00188
00189
00190 for( const FieldLink<ServiceBookConfig> *b = ServiceBookConfigFieldLinks;
00191 b->type != SBFCC_END;
00192 b++ )
00193 {
00194 if( b->strMember ) {
00195 const std::string &s = this->*(b->strMember);
00196 if( s.size() )
00197 os << " " << b->name << ": " << s << "\n";
00198 }
00199 else if( b->timeMember ) {
00200 time_t t = this->*(b->timeMember);
00201 if( t > 0 )
00202 os << " " << b->name << ": " << ctime(&t);
00203 }
00204 }
00205
00206
00207 os << Unknowns;
00208 os << " ------------------- End of Config Field\n";
00209 }
00210
00211
00212
00213
00214
00215
00216 #define SBFC_OLD_NAME 0x01
00217 #define SBFC_HIDDEN_NAME 0x02
00218 #define SBFC_NAME 0x03
00219 #define SBFC_OLD_UNIQUE_ID 0x06
00220 #define SBFC_UNIQUE_ID 0x07
00221 #define SBFC_CONTENT_ID 0x08
00222 #define SBFC_CONFIG 0x09
00223 #define SBFC_OLD_DESC 0x32
00224 #define SBFC_DESCRIPTION 0x0f
00225 #define SBFC_DSID 0xa1
00226 #define SBFC_BES_DOMAIN 0xa2
00227 #define SBFC_USER_ID 0xa3
00228 #define SBFC_END 0xffff
00229
00230
00231 class ServiceBookData
00232 {
00233 public:
00234 FieldLink<ServiceBook> *m_typeSet;
00235 ServiceBookData(FieldLink<ServiceBook> *typeSet) : m_typeSet(typeSet) {}
00236 };
00237
00238
00239
00240
00241
00242 static FieldLink<ServiceBook> ServiceBookOldFieldLinks[] = {
00243 { SBFC_OLD_NAME, "Old Name", 0, 0, &ServiceBook::Name, 0, 0, 0, 0, true },
00244 { SBFC_OLD_DESC, "Old Desc", 0, 0, &ServiceBook::Description, 0, 0, 0, 0, true },
00245 { SBFC_OLD_UNIQUE_ID, "Old UniqueId", 0, 0, &ServiceBook::UniqueId, 0, 0, 0, 0, false },
00246 { SBFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false }
00247 };
00248
00249 static FieldLink<ServiceBook> ServiceBookNewFieldLinks[] = {
00250 { SBFC_NAME, "Name", 0, 0, &ServiceBook::Name, 0, 0, 0, 0, true },
00251 { SBFC_DESCRIPTION, "Description", 0, 0, &ServiceBook::Description, 0, 0, 0, 0, true },
00252 { SBFC_UNIQUE_ID, "UniqueId", 0, 0, &ServiceBook::UniqueId, 0, 0, 0, 0, false },
00253 { SBFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false }
00254 };
00255
00256
00257 static FieldLink<ServiceBook> ServiceBookFieldLinks[] = {
00258 { SBFC_HIDDEN_NAME, "Hidden Name",0, 0, &ServiceBook::HiddenName, 0, 0, 0, 0, true },
00259 { SBFC_DSID, "DSID", 0, 0, &ServiceBook::DSID, 0, 0, 0, 0, false },
00260 { SBFC_CONTENT_ID, "ContentId", 0, 0, &ServiceBook::ContentId, 0, 0, 0, 0, false },
00261 { SBFC_BES_DOMAIN, "BES Domain", 0, 0, &ServiceBook::BesDomain, 0, 0, 0, 0, false },
00262 { SBFC_END, "End of List",0, 0, 0, 0, 0, 0, 0, false }
00263 };
00264
00265
00266 static FieldLink<ServiceBook> *ServiceBookLinkTable[] = {
00267 ServiceBookOldFieldLinks,
00268 ServiceBookNewFieldLinks,
00269 0
00270 };
00271
00272 #define FIELDLINK_END 0xffff
00273
00274 template <class RecordT>
00275 FieldLink<RecordT>* ParseFieldByTable(RecordT *rec,
00276 const CommonField *field,
00277 const IConverter *ic,
00278 FieldLink<RecordT> *links)
00279 {
00280
00281 for( FieldLink<RecordT> *b = links; b->type != FIELDLINK_END; b++ ) {
00282 if( b->type == field->type ) {
00283 if( b->strMember ) {
00284 std::string &s = rec->*(b->strMember);
00285 if( s.size() ) {
00286 dout(RecordT::GetDBName() << ": field '" << b->name << "' already has data (" << s << "). Overwriting.");
00287 }
00288 s = ParseFieldString(field);
00289 if( b->iconvNeeded && ic )
00290 s = ic->FromBB(s);
00291 return links;
00292 }
00293 else if( b->timeMember && btohs(field->size) == 4 ) {
00294 time_t &t = rec->*(b->timeMember);
00295 t = min2time(field->u.min1900);
00296 return links;
00297 }
00298 }
00299 }
00300 return 0;
00301 }
00302
00303 template <class RecordT>
00304 FieldLink<RecordT>* ParseFieldByTable(RecordT *rec,
00305 const CommonField *field,
00306 const IConverter *ic,
00307 FieldLink<RecordT> **b)
00308 {
00309 for( ; *b; b++ ) {
00310 FieldLink<RecordT> *link =
00311 ParseFieldByTable<RecordT>(rec, field, ic, *b);
00312 if( link )
00313 return link;
00314 }
00315 return 0;
00316 }
00317
00318 ServiceBook::ServiceBook()
00319 : m_data( new ServiceBookData(ServiceBookOldFieldLinks) )
00320 , RecordId(0)
00321 {
00322 Clear();
00323 }
00324
00325 ServiceBook::~ServiceBook()
00326 {
00327 }
00328
00329 const unsigned char* ServiceBook::ParseField(const unsigned char *begin,
00330 const unsigned char *end,
00331 const IConverter *ic)
00332 {
00333 const CommonField *field = (const CommonField *) begin;
00334
00335
00336 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
00337 if( begin > end )
00338 return begin;
00339
00340 if( !btohs(field->size) )
00341 return begin;
00342
00343
00344 FieldLink<ServiceBook> *typeSet =
00345 ParseFieldByTable(this, field, ic, ServiceBookLinkTable);
00346 if( typeSet ) {
00347 if( m_data->m_typeSet && m_data->m_typeSet != typeSet ) {
00348 dout("ServiceBook record has a mix of old and new field types.");
00349 }
00350 m_data->m_typeSet = typeSet;
00351 return begin;
00352 }
00353 else {
00354 if( ParseFieldByTable(this, field, ic, ServiceBookFieldLinks) )
00355 return begin;
00356 }
00357
00358
00359 switch( field->type )
00360 {
00361 case SBFC_CONFIG:
00362 try {
00363 Data config((const void *)field->u.raw, btohs(field->size));
00364 size_t offset = 0;
00365 Config.ParseHeader(config, offset);
00366 Config.ParseFields(config, offset);
00367 return begin;
00368 }
00369 catch( BadPackedFormat & ) {
00370
00371
00372 break;
00373 }
00374 }
00375
00376
00377 UnknownField uf;
00378 uf.type = field->type;
00379 uf.data.assign((const char*)field->u.raw, btohs(field->size));
00380 Unknowns.push_back(uf);
00381
00382
00383 return begin;
00384 }
00385
00386 void ServiceBook::ParseHeader(const Data &data, size_t &offset)
00387 {
00388
00389 }
00390
00391 void ServiceBook::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
00392 {
00393 const unsigned char *finish = ParseCommonFields(*this,
00394 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
00395 offset += finish - (data.GetData() + offset);
00396 }
00397
00398 void ServiceBook::BuildHeader(Data &data, size_t &offset) const
00399 {
00400
00401 }
00402
00403
00404
00405
00406
00407
00408 void ServiceBook::BuildFields(Data &data, size_t &offset, const IConverter *ic) const
00409 {
00410 throw std::logic_error("ServiceBook::BuildFields not yet implemented");
00411 }
00412
00413 void ServiceBook::Clear()
00414 {
00415 m_data->m_typeSet = ServiceBookOldFieldLinks;
00416 Unknowns.clear();
00417 Config.Clear();
00418 }
00419
00420 inline void FormatStr(std::ostream &os, const char *name, const std::string &str)
00421 {
00422 if( str.size() ) {
00423 os << " " << setw(20) << name;
00424 os << ": " << str << "\n";
00425 }
00426 }
00427
00428 void ServiceBook::Dump(std::ostream &os) const
00429 {
00430 ios::fmtflags oldflags = os.setf(ios::left);
00431 char fill = os.fill(' ');
00432
00433 os << "ServiceBook entry: 0x" << setbase(16) << RecordId
00434 << " (" << (unsigned int)RecType << ")\n";
00435
00436 FormatStr(os, "Name", Name);
00437 FormatStr(os, "Hidden Name", HiddenName);
00438 FormatStr(os, "Description", Description);
00439 FormatStr(os, "DSID", DSID);
00440 FormatStr(os, "Unique ID", UniqueId);
00441 FormatStr(os, "Content ID", ContentId);
00442 FormatStr(os, "(BES) Domain", BesDomain);
00443
00444 os << Config;
00445
00446
00447 os << Unknowns;
00448
00449
00450 os.flags(oldflags);
00451 os.fill(fill);
00452 }
00453
00454 bool ServiceBook::operator<(const ServiceBook &other) const
00455 {
00456 int cmp = BesDomain.compare(other.BesDomain);
00457 if( cmp == 0 )
00458 cmp = DSID.compare(other.DSID);
00459 if( cmp == 0 )
00460 cmp = Name.compare(other.Name);
00461 if( cmp == 0 )
00462 cmp = UniqueId.compare(other.UniqueId);
00463 return cmp < 0;
00464 }
00465
00466 }
00467