00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "record.h"
00028 #include "record-internal.h"
00029 #include "protocol.h"
00030 #include "protostructs.h"
00031 #include "data.h"
00032 #include "time.h"
00033 #include "error.h"
00034 #include "endian.h"
00035 #include <sstream>
00036 #include <iomanip>
00037 #include <time.h>
00038 #include <string.h>
00039 #include <stdexcept>
00040
00041 #define __DEBUG_MODE__
00042 #include "debug.h"
00043
00044 using namespace std;
00045 using namespace Barry::Protocol;
00046
00047 namespace Barry {
00048
00049
00050
00051
00052 void BuildField1900(Data &data, size_t &size, uint8_t type, time_t t)
00053 {
00054 size_t timesize = COMMON_FIELD_MIN1900_SIZE;
00055 size_t fieldsize = COMMON_FIELD_HEADER_SIZE + timesize;
00056 unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00057 CommonField *field = (CommonField *) pd;
00058
00059 field->size = htobs(timesize);
00060 field->type = type;
00061 field->u.min1900 = time2min(t);
00062
00063 size += fieldsize;
00064 }
00065
00066 void BuildField(Data &data, size_t &size, uint8_t type, char c)
00067 {
00068 size_t strsize = 1;
00069 size_t fieldsize = COMMON_FIELD_HEADER_SIZE + strsize;
00070 unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00071 CommonField *field = (CommonField *) pd;
00072
00073 field->size = htobs(strsize);
00074 field->type = type;
00075 memcpy(field->u.raw, &c, strsize);
00076
00077 size += fieldsize;
00078 }
00079
00080 void BuildField(Data &data, size_t &size, uint8_t type, uint16_t value)
00081 {
00082 size_t strsize = 2;
00083 size_t fieldsize = COMMON_FIELD_HEADER_SIZE + strsize;
00084 unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00085 CommonField *field = (CommonField *) pd;
00086
00087 field->size = htobs(strsize);
00088 field->type = type;
00089
00090 uint16_t store = htobs(value);
00091 memcpy(field->u.raw, &store, strsize);
00092
00093 size += fieldsize;
00094 }
00095
00096 void BuildField(Data &data, size_t &size, uint8_t type, const std::string &str)
00097 {
00098
00099 BuildField(data, size, type, str.c_str(), str.size() + 1);
00100 }
00101
00102 void BuildField(Data &data, size_t &size, uint8_t type,
00103 const void *buf, size_t bufsize)
00104 {
00105
00106 size_t fieldsize = COMMON_FIELD_HEADER_SIZE + bufsize;
00107 unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00108 CommonField *field = (CommonField *) pd;
00109
00110 field->size = htobs(bufsize);
00111 field->type = type;
00112 memcpy(field->u.raw, buf, bufsize);
00113
00114 size += fieldsize;
00115 }
00116
00117 void BuildField(Data &data, size_t &size, const Barry::UnknownField &field)
00118 {
00119 BuildField(data, size, field.type,
00120 field.data.raw_data.data(), field.data.raw_data.size());
00121 }
00122
00123 void BuildField(Data &data, size_t &size, uint8_t type, const Barry::Protocol::GroupLink &link)
00124 {
00125 size_t linksize = sizeof(Barry::Protocol::GroupLink);
00126 size_t fieldsize = COMMON_FIELD_HEADER_SIZE + linksize;
00127 unsigned char *pd = data.GetBuffer(size + fieldsize) + size;
00128 CommonField *field = (CommonField *) pd;
00129
00130 field->size = htobs(linksize);
00131 field->type = type;
00132 field->u.link = link;
00133
00134 size += fieldsize;
00135 }
00136
00137 std::string ParseFieldString(const Barry::Protocol::CommonField *field)
00138 {
00139
00140
00141
00142 return ParseFieldString(field->u.raw, btohs(field->size));
00143 }
00144
00145 std::string ParseFieldString(const void *data, uint16_t maxlen)
00146 {
00147 const char *str = (const char *)data;
00148
00149
00150
00151 while( maxlen && str[maxlen-1] == 0 )
00152 maxlen--;
00153
00154 return std::string(str, maxlen);
00155 }
00156
00157
00158
00159
00160
00161 CommandTable::CommandTable()
00162 {
00163 }
00164
00165 CommandTable::~CommandTable()
00166 {
00167 }
00168
00169 const unsigned char* CommandTable::ParseField(const unsigned char *begin,
00170 const unsigned char *end)
00171 {
00172
00173 const unsigned char *headend = begin + sizeof(CommandTableField);
00174 if( headend > end )
00175 return headend;
00176
00177 const CommandTableField *field = (const CommandTableField *) begin;
00178
00179
00180 begin += COMMAND_FIELD_HEADER_SIZE + field->size;
00181 if( begin > end )
00182 return begin;
00183
00184 if( !field->size )
00185 return begin;
00186
00187 Command command;
00188 command.Code = field->code;
00189 command.Name.assign((const char *)field->name, field->size);
00190 Commands.push_back(command);
00191 return begin;
00192 }
00193
00194 void CommandTable::Parse(const Data &data, size_t offset)
00195 {
00196 if( offset >= data.GetSize() )
00197 return;
00198
00199 const unsigned char *begin = data.GetData() + offset;
00200 const unsigned char *end = data.GetData() + data.GetSize();
00201
00202 while( begin < end )
00203 begin = ParseField(begin, end);
00204 }
00205
00206 void CommandTable::Clear()
00207 {
00208 Commands.clear();
00209 }
00210
00211 unsigned int CommandTable::GetCommand(const std::string &name) const
00212 {
00213 CommandArrayType::const_iterator b = Commands.begin();
00214 for( ; b != Commands.end(); b++ )
00215 if( b->Name == name )
00216 return b->Code;
00217 return 0;
00218 }
00219
00220 void CommandTable::Dump(std::ostream &os) const
00221 {
00222 CommandArrayType::const_iterator b = Commands.begin();
00223 os << "Command table:\n";
00224 for( ; b != Commands.end(); b++ ) {
00225 os << " Command: 0x" << setbase(16) << b->Code
00226 << " '" << b->Name << "'\n";
00227 }
00228 }
00229
00230
00231
00232
00233
00234
00235 RecordStateTable::RecordStateTable()
00236 : m_LastNewRecordId(1)
00237 {
00238 }
00239
00240 RecordStateTable::~RecordStateTable()
00241 {
00242 }
00243
00244 const unsigned char* RecordStateTable::ParseField(const unsigned char *begin,
00245 const unsigned char *end)
00246 {
00247 const RecordStateTableField *field = (const RecordStateTableField *) begin;
00248
00249
00250 begin += sizeof(RecordStateTableField);
00251 if( begin > end )
00252 return begin;
00253
00254 State state;
00255 state.Index = btohs(field->index);
00256 state.RecordId = btohl(field->uniqueId);
00257 state.Dirty = (field->flags & BARRY_RSTF_DIRTY) != 0;
00258 state.RecType = field->rectype;
00259 state.Unknown2.assign((const char*)field->unknown2, sizeof(field->unknown2));
00260 StateMap[state.Index] = state;
00261
00262 return begin;
00263 }
00264
00265 void RecordStateTable::Parse(const Data &data)
00266 {
00267 size_t offset = 12;
00268
00269 if( offset >= data.GetSize() )
00270 return;
00271
00272 const unsigned char *begin = data.GetData() + offset;
00273 const unsigned char *end = data.GetData() + data.GetSize();
00274
00275 while( begin < end )
00276 begin = ParseField(begin, end);
00277 }
00278
00279 void RecordStateTable::Clear()
00280 {
00281 StateMap.clear();
00282 m_LastNewRecordId = 1;
00283 }
00284
00285
00286
00287
00288 bool RecordStateTable::GetIndex(uint32_t RecordId, IndexType *pFoundIndex) const
00289 {
00290 StateMapType::const_iterator i = StateMap.begin();
00291 for( ; i != StateMap.end(); ++i ) {
00292 if( i->second.RecordId == RecordId ) {
00293 if( pFoundIndex )
00294 *pFoundIndex = i->first;
00295 return true;
00296 }
00297 }
00298 return false;
00299 }
00300
00301
00302
00303 uint32_t RecordStateTable::MakeNewRecordId() const
00304 {
00305
00306 m_LastNewRecordId++;
00307
00308
00309 StateMapType::const_iterator i = StateMap.begin();
00310 while( i != StateMap.end() ) {
00311 if( m_LastNewRecordId == i->second.RecordId ) {
00312 m_LastNewRecordId++;
00313 i = StateMap.begin();
00314 }
00315 else {
00316 ++i;
00317 }
00318 }
00319 return m_LastNewRecordId;
00320 }
00321
00322 void RecordStateTable::Dump(std::ostream &os) const
00323 {
00324 ios::fmtflags oldflags = os.setf(ios::right);
00325 char fill = os.fill(' ');
00326 bool bPrintAscii = Data::PrintAscii();
00327 Data::PrintAscii(false);
00328
00329 os << " Index RecordId Dirty RecType" << endl;
00330 os << "------- ---------- ----- -------" << endl;
00331
00332 StateMapType::const_iterator b, e = StateMap.end();
00333 for( b = StateMap.begin(); b != e ; ++b ) {
00334 const State &state = b->second;
00335
00336 os.fill(' ');
00337 os << setbase(10) << setw(7) << state.Index;
00338 os << " 0x" << setbase(16) << setfill('0') << setw(8) << state.RecordId;
00339 os << " " << setfill(' ') << setw(5) << (state.Dirty ? "yes" : "no");
00340 os << " 0x" << setbase(16) << setfill('0') << setw(2) << state.RecType;
00341 os << " " << Data(state.Unknown2.data(), state.Unknown2.size());
00342 }
00343
00344
00345 os.flags(oldflags);
00346 os.fill(fill);
00347 Data::PrintAscii(bPrintAscii);
00348 }
00349
00350
00351
00352
00353
00354
00355 DatabaseDatabase::DatabaseDatabase()
00356 {
00357 }
00358
00359 DatabaseDatabase::~DatabaseDatabase()
00360 {
00361 }
00362
00363 template <class RecordType, class FieldType>
00364 void DatabaseDatabase::ParseRec(const RecordType &rec, const unsigned char *end)
00365 {
00366 }
00367
00368 template <class FieldType>
00369 const unsigned char* DatabaseDatabase::ParseField(const unsigned char *begin,
00370 const unsigned char *end)
00371 {
00372
00373 const unsigned char *headend = begin + sizeof(FieldType);
00374 if( headend > end )
00375 return headend;
00376
00377
00378 const FieldType *field = (const FieldType *) begin;
00379
00380
00381 begin += sizeof(FieldType) - sizeof(field->name) + ConvertHtoB(field->nameSize);
00382 if( begin > end )
00383 return begin;
00384
00385 if( !ConvertHtoB(field->nameSize) )
00386 return begin;
00387
00388 Database db;
00389 db.Number = ConvertHtoB(field->dbNumber);
00390 db.RecordCount = ConvertHtoB(field->dbRecordCount);
00391 db.Name.assign((const char *)field->name, ConvertHtoB(field->nameSize) - 1);
00392 Databases.push_back(db);
00393 return begin;
00394 }
00395
00396 void DatabaseDatabase::Parse(const Data &data)
00397 {
00398
00399 if( data.GetSize() < (SB_PACKET_DBACCESS_HEADER_SIZE + 1) )
00400 return;
00401
00402 MAKE_PACKET(pack, data);
00403 const unsigned char *begin = 0;
00404 const unsigned char *end = data.GetData() + data.GetSize();
00405
00406 switch( pack->u.db.u.response.operation )
00407 {
00408 case SB_DBOP_GET_DBDB:
00409
00410 if( data.GetSize() > SB_PACKET_DBDB_HEADER_SIZE ) {
00411 begin = (const unsigned char *)
00412 &pack->u.db.u.response.u.dbdb.field[0];
00413
00414
00415
00416 while( begin < end )
00417 begin = ParseField<DBDBField>(begin, end);
00418 }
00419 else
00420 dout("DatabaseDatabase: not enough data for parsing");
00421 break;
00422
00423 case SB_DBOP_OLD_GET_DBDB:
00424
00425 if( data.GetSize() > SB_PACKET_OLD_DBDB_HEADER_SIZE ) {
00426 begin = (const unsigned char *)
00427 &pack->u.db.u.response.u.old_dbdb.field[0];
00428
00429
00430
00431 while( begin < end )
00432 begin = ParseField<OldDBDBField>(begin, end);
00433 }
00434 else
00435 dout("DatabaseDatabase: not enough data for parsing");
00436 break;
00437
00438 default:
00439
00440 dout("Unknown protocol");
00441 break;
00442 }
00443
00444
00445 }
00446
00447 void DatabaseDatabase::Clear()
00448 {
00449 Databases.clear();
00450 }
00451
00452 bool DatabaseDatabase::GetDBNumber(const std::string &name,
00453 unsigned int &number) const
00454 {
00455 DatabaseArrayType::const_iterator b = Databases.begin();
00456 for( ; b != Databases.end(); b++ )
00457 if( b->Name == name ) {
00458 number = b->Number;
00459 return true;
00460 }
00461 return false;
00462 }
00463
00464 bool DatabaseDatabase::GetDBName(unsigned int number,
00465 std::string &name) const
00466 {
00467 DatabaseArrayType::const_iterator b = Databases.begin();
00468 for( ; b != Databases.end(); b++ )
00469 if( b->Number == number ) {
00470 name = b->Name;
00471 return true;
00472 }
00473 return false;
00474 }
00475
00476 void DatabaseDatabase::Dump(std::ostream &os) const
00477 {
00478 DatabaseArrayType::const_iterator b = Databases.begin();
00479 os << "Database database:\n";
00480 for( ; b != Databases.end(); b++ ) {
00481 os << " Database: 0x" << setbase(16) << b->Number
00482 << " '" << b->Name << "' (records: "
00483 << setbase(10) << b->RecordCount << ")\n";
00484 }
00485 }
00486
00487
00488 std::ostream& operator<< (std::ostream &os, const std::vector<UnknownField> &unknowns)
00489 {
00490 std::vector<UnknownField>::const_iterator
00491 ub = unknowns.begin(), ue = unknowns.end();
00492 if( ub != ue )
00493 os << " Unknowns:\n";
00494 for( ; ub != ue; ub++ ) {
00495 os << " Type: 0x" << setbase(16)
00496 << (unsigned int) ub->type
00497 << " Data:\n" << Data(ub->data.data(), ub->data.size());
00498 }
00499 return os;
00500 }
00501
00502
00503
00504
00505
00506
00507 std::ostream& operator<<(std::ostream &os, const EmailAddress &msga) {
00508 os << msga.Name.c_str() << " <" << msga.Email.c_str() << ">";
00509 return os;
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521 std::string PostalAddress::GetLabel() const
00522 {
00523 std::string address = Address1;
00524 if( Address2.size() ) {
00525 if( address.size() )
00526 address += "\n";
00527 address += Address2;
00528 }
00529 if( Address3.size() ) {
00530 if( address.size() )
00531 address += "\n";
00532 address += Address3;
00533 }
00534 if( address.size() )
00535 address += "\n";
00536 if( City.size() )
00537 address += City + " ";
00538 if( Province.size() )
00539 address += Province + " ";
00540 if( Country.size() )
00541 address += Country;
00542 if( address.size() )
00543 address += "\n";
00544 if( PostalCode.size() )
00545 address += PostalCode;
00546
00547 return address;
00548 }
00549
00550 void PostalAddress::Clear()
00551 {
00552 Address1.clear();
00553 Address2.clear();
00554 Address3.clear();
00555 City.clear();
00556 Province.clear();
00557 PostalCode.clear();
00558 Country.clear();
00559 }
00560
00561 std::ostream& operator<<(std::ostream &os, const PostalAddress &post) {
00562 os << post.GetLabel();
00563 return os;
00564 }
00565
00566
00567
00568
00569
00570
00571 Date::Date(const struct tm *timep)
00572 {
00573 FromTm(timep);
00574 }
00575
00576 void Date::Clear()
00577 {
00578 Month = Day = Year = 0;
00579 }
00580
00581 void Date::ToTm(struct tm *timep) const
00582 {
00583 memset(timep, 0, sizeof(tm));
00584 timep->tm_year = Year - 1900;
00585 timep->tm_mon = Month;
00586 timep->tm_mday = Day;
00587 }
00588
00589 std::string Date::ToYYYYMMDD() const
00590 {
00591 std::ostringstream oss;
00592 oss << setw(4) << Year
00593 << setw(2) << Month + 1
00594 << setw(2) << Day;
00595 return oss.str();
00596 }
00597
00598
00599
00600
00601
00602
00603
00604 std::string Date::ToBBString() const
00605 {
00606 std::ostringstream oss;
00607 oss << setw(2) << Day
00608 << Month + 1
00609 << Year;
00610 return oss.str();
00611 }
00612
00613 bool Date::FromTm(const struct tm *timep)
00614 {
00615 Year = timep->tm_year + 1900;
00616 Month = timep->tm_mon;
00617 Day = timep->tm_mday;
00618 return true;
00619 }
00620
00621 bool Date::FromBBString(const std::string &str)
00622 {
00623 int m, d, y;
00624 if( 3 == sscanf(str.c_str(), "%d/%d/%d", &d, &m, &y) ) {
00625 Year = y;
00626 Month = m - 1;
00627 Day = d;
00628 return true;
00629 }
00630 return false;
00631 }
00632
00633 bool Date::FromYYYYMMDD(const std::string &str)
00634 {
00635 int m, d, y;
00636 if( 3 == sscanf(str.c_str(), "%4d%2d%2d", &y, &m, &d) ) {
00637 Year = y;
00638 Month = m - 1;
00639 Day = d;
00640 return true;
00641 }
00642 return false;
00643 }
00644
00645 std::ostream& operator<<(std::ostream &os, const Date &date)
00646 {
00647 os << setw(4) << date.Year << '/'
00648 << setw(2) << date.Month << '/'
00649 << setw(2) << date.Day;
00650 return os;
00651 }
00652
00653
00654
00655 }
00656
00657
00658 #ifdef __TEST_MODE__
00659
00660 #include <iostream>
00661
00662 int main(int argc, char *argv[])
00663 {
00664 if( argc < 2 ) {
00665 cerr << "Usage: test <datafile>" << endl;
00666 return 1;
00667 }
00668
00669 std::vector<Data> array;
00670 if( !LoadDataArray(argv[1], array) ) {
00671 cerr << "Unable to load file: " << argv[1] << endl;
00672 return 1;
00673 }
00674
00675 cout << "Loaded " << array.size() << " items" << endl;
00676
00677 for( std::vector<Data>::iterator b = array.begin(), e = array.end();
00678 b != e; b++ )
00679 {
00680 Data &d = *b;
00681
00682 if( d.GetSize() > 13 && d.GetData()[6] == 0x4f ) {
00683 Barry::Contact contact;
00684 size_t size = 13;
00685 contact.ParseFields(d, size);
00686 cout << contact << endl;
00687 contact.DumpLdif(cout, "ou=People,dc=example,dc=com");
00688 }
00689 else if( d.GetSize() > 13 && d.GetData()[6] == 0x44 ) {
00690 Barry::Calendar cal;
00691 size_t size = 13;
00692 cal.ParseFields(d, size);
00693 cout << cal << endl;
00694 }
00695 }
00696 }
00697
00698 #endif
00699