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