00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "m_desktop.h"
00023 #include "data.h"
00024 #include "protocol.h"
00025 #include "protostructs.h"
00026 #include "packet.h"
00027 #include "endian.h"
00028 #include "error.h"
00029 #include "usbwrap.h"
00030 #include "controller.h"
00031 #include "parser.h"
00032 #include <stdexcept>
00033 #include <sstream>
00034
00035 #include "debug.h"
00036
00037 namespace Barry { namespace Mode {
00038
00039
00040
00041
00042
00043 Desktop::Desktop(Controller &con)
00044 : Mode(con, Controller::Desktop)
00045 , m_ic(0)
00046 {
00047 }
00048
00049 Desktop::Desktop(Controller &con, const IConverter &ic)
00050 : Mode(con, Controller::Desktop)
00051 , m_ic(&ic)
00052 {
00053 }
00054
00055 Desktop::~Desktop()
00056 {
00057 }
00058
00059
00060
00061
00062 void Desktop::LoadCommandTable()
00063 {
00064 char rawCommand[] = { 6, 0, 0x0a, 0, 0x40, 0, 0, 1, 0, 0 };
00065 *((uint16_t*) rawCommand) = htobs(m_socket->GetSocket());
00066
00067 Data command(rawCommand, sizeof(rawCommand));
00068
00069 try {
00070 m_socket->Packet(command, m_response);
00071
00072 MAKE_PACKET(rpack, m_response);
00073 while( rpack->command != SB_COMMAND_DB_DONE ) {
00074 m_socket->NextRecord(m_response);
00075
00076 rpack = (const Protocol::Packet *) m_response.GetData();
00077 if( rpack->command == SB_COMMAND_DB_DATA && btohs(rpack->size) > 10 ) {
00078
00079
00080 m_commandTable.Clear();
00081 m_commandTable.Parse(m_response, 6);
00082 }
00083 }
00084
00085 ddout(m_commandTable);
00086
00087 }
00088 catch( Usb::Error & ) {
00089 eout("Desktop: error getting command table");
00090 eeout(command, m_response);
00091 throw;
00092 }
00093 }
00094
00095 void Desktop::LoadDBDB()
00096 {
00097 DBPacket packet(*this, m_command, m_response);
00098 packet.GetDBDB();
00099
00100 m_socket->Packet(packet);
00101
00102 while( packet.Command() != SB_COMMAND_DB_DONE ) {
00103 if( packet.Command() == SB_COMMAND_DB_DATA ) {
00104 m_dbdb.Clear();
00105 m_dbdb.Parse(m_response);
00106 }
00107
00108
00109 m_socket->NextRecord(m_response);
00110 }
00111 }
00112
00113 void Desktop::OnOpen()
00114 {
00115
00116 LoadCommandTable();
00117 LoadDBDB();
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134 unsigned int Desktop::GetDBID(const std::string &name) const
00135 {
00136 unsigned int ID = 0;
00137
00138 if( !m_dbdb.GetDBNumber(name, ID) ) {
00139 throw Error("Desktop: database name not found: " + name);
00140 }
00141 return ID;
00142 }
00143
00144
00145
00146
00147
00148
00149
00150 unsigned int Desktop::GetDBCommand(CommandType ct)
00151 {
00152 unsigned int cmd = 0;
00153 const char *cmdName = "Unknown";
00154
00155 switch( ct )
00156 {
00157 case DatabaseAccess:
00158 cmdName = "Database Access";
00159 cmd = m_commandTable.GetCommand(cmdName);
00160 break;
00161 default:
00162 throw std::logic_error("Desktop: unknown command type");
00163 }
00164
00165 if( cmd == 0 ) {
00166 std::ostringstream oss;
00167 oss << "Desktop: unable to get command code: " << cmdName;
00168 throw Error(oss.str());
00169 }
00170
00171 return cmd;
00172 }
00173
00174 void Desktop::SetIConverter(const IConverter &ic)
00175 {
00176 m_ic = ⁣
00177 }
00178
00179
00180
00181
00182
00183
00184
00185
00186 void Desktop::GetRecordStateTable(unsigned int dbId, RecordStateTable &result)
00187 {
00188 dout("Database ID: " << dbId);
00189
00190
00191 result.Clear();
00192
00193 DBPacket packet(*this, m_command, m_response);
00194 packet.GetRecordStateTable(dbId);
00195
00196 m_socket->Packet(packet);
00197 result.Parse(m_response);
00198
00199
00200 while( packet.Command() != SB_COMMAND_DB_DONE )
00201 m_socket->NextRecord(m_response);
00202 }
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 void Desktop::AddRecord(unsigned int dbId, Builder &build)
00213 {
00214 dout("Database ID: " << dbId);
00215
00216 DBPacket packet(*this, m_command, m_response);
00217
00218 if( packet.SetRecord(dbId, build, m_ic) ) {
00219
00220 std::ostringstream oss;
00221
00222 m_socket->Packet(packet);
00223
00224
00225 if( packet.Command() != SB_COMMAND_DB_DONE ) {
00226 oss << "Desktop: device responded with unexpected packet command code: "
00227 << "0x" << std::hex << packet.Command();
00228 throw Error(oss.str());
00229 }
00230
00231 if( packet.ReturnCode() != 0 ) {
00232 oss << "Desktop: device responded with error code (command: "
00233 << packet.Command() << ", code: "
00234 << packet.ReturnCode() << ")";
00235 throw Error(oss.str());
00236 }
00237 }
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247 void Desktop::GetRecord(unsigned int dbId,
00248 unsigned int stateTableIndex,
00249 Parser &parser)
00250 {
00251 dout("Database ID: " << dbId);
00252
00253 std::string dbName;
00254 m_dbdb.GetDBName(dbId, dbName);
00255
00256 DBPacket packet(*this, m_command, m_response);
00257 packet.GetRecordByIndex(dbId, stateTableIndex);
00258
00259 m_socket->Packet(packet);
00260
00261
00262 if( m_response.GetSize() < SB_PACKET_RESPONSE_HEADER_SIZE ) {
00263 eeout(m_command, m_response);
00264
00265 std::ostringstream oss;
00266 oss << "Desktop: invalid response packet size of "
00267 << std::dec << m_response.GetSize();
00268 eout(oss.str());
00269 throw Error(oss.str());
00270 }
00271 if( packet.Command() != SB_COMMAND_DB_DATA ) {
00272 eeout(m_command, m_response);
00273
00274 std::ostringstream oss;
00275 oss << "Desktop: unexpected command of 0x"
00276 << std::setbase(16) << packet.Command()
00277 << " instead of expected 0x"
00278 << std::setbase(16) << (unsigned int)SB_COMMAND_DB_DATA;
00279 eout(oss.str());
00280 throw Error(oss.str());
00281 }
00282
00283
00284 packet.Parse(parser, dbName, m_ic);
00285
00286
00287 while( packet.Command() != SB_COMMAND_DB_DONE )
00288 m_socket->NextRecord(m_response);
00289 }
00290
00291
00292
00293
00294
00295
00296
00297 void Desktop::SetRecord(unsigned int dbId, unsigned int stateTableIndex,
00298 Builder &build)
00299 {
00300 dout("Database ID: " << dbId << " Index: " << stateTableIndex);
00301
00302 DBPacket packet(*this, m_command, m_response);
00303
00304
00305 if( !packet.SetRecordByIndex(dbId, stateTableIndex, build, m_ic) ) {
00306 throw std::logic_error("Desktop: no data available in SetRecord");
00307 }
00308
00309 m_socket->Packet(packet);
00310
00311 std::ostringstream oss;
00312
00313
00314 if( packet.Command() != SB_COMMAND_DB_DONE ) {
00315 oss << "Desktop: device responded with unexpected packet command code: "
00316 << "0x" << std::hex << packet.Command();
00317 throw Error(oss.str());
00318 }
00319
00320 if( packet.ReturnCode() != 0 ) {
00321 oss << "Desktop: device responded with error code (command: "
00322 << packet.Command() << ", code: "
00323 << packet.ReturnCode() << ")";
00324 throw Error(oss.str());
00325 }
00326 }
00327
00328
00329
00330
00331
00332
00333 void Desktop::ClearDirty(unsigned int dbId, unsigned int stateTableIndex)
00334 {
00335 dout("Database ID: " << dbId);
00336
00337 DBPacket packet(*this, m_command, m_response);
00338 packet.SetRecordFlags(dbId, stateTableIndex, 0);
00339
00340 m_socket->Packet(packet);
00341
00342
00343 while( packet.Command() != SB_COMMAND_DB_DONE )
00344 m_socket->NextRecord(m_response);
00345 }
00346
00347
00348
00349
00350
00351
00352 void Desktop::DeleteRecord(unsigned int dbId, unsigned int stateTableIndex)
00353 {
00354 dout("Database ID: " << dbId);
00355
00356 DBPacket packet(*this, m_command, m_response);
00357 packet.DeleteRecordByIndex(dbId, stateTableIndex);
00358
00359 m_socket->Packet(packet);
00360
00361
00362 while( packet.Command() != SB_COMMAND_DB_DONE )
00363 m_socket->NextRecord(m_response);
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 void Desktop::LoadDatabase(unsigned int dbId, Parser &parser)
00390 {
00391 DBData data;
00392 DBLoader loader(*this);
00393 bool loading = loader.StartDBLoad(dbId, data);
00394 while( loading ) {
00395
00396 parser.ParseRecord(data, m_ic);
00397
00398
00399 loading = loader.GetNextRecord(data);
00400 }
00401 }
00402
00403 void Desktop::ClearDatabase(unsigned int dbId)
00404 {
00405 dout("Database ID: " << dbId);
00406
00407 DBPacket packet(*this, m_command, m_response);
00408 packet.ClearDatabase(dbId);
00409
00410
00411 m_socket->Packet(packet, 60000);
00412 if( packet.ReturnCode() != 0 ) {
00413 std::ostringstream oss;
00414 oss << "Desktop: could not clear database: (command: "
00415 << "0x" << std::hex << packet.Command() << ", code: "
00416 << "0x" << std::hex << packet.ReturnCode() << ")";
00417 throw Error(oss.str());
00418 }
00419
00420
00421 if( packet.Command() != SB_COMMAND_DB_DONE ) {
00422 eeout(m_command, m_response);
00423 throw Error("Desktop: error clearing database, bad response");
00424 }
00425 }
00426
00427 void Desktop::SaveDatabase(unsigned int dbId, Builder &builder)
00428 {
00429 dout("Database ID: " << dbId);
00430
00431
00432
00433
00434
00435
00436
00437
00438 ClearDatabase(dbId);
00439
00440 DBPacket packet(*this, m_command, m_response);
00441
00442
00443 bool first = true;
00444 while( packet.SetRecord(dbId, builder, m_ic) ) {
00445 dout("Database ID: " << dbId);
00446
00447 m_socket->Packet(packet, first ? 60000 : -1);
00448 first = false;
00449
00450 std::ostringstream oss;
00451
00452 if( packet.Command() != SB_COMMAND_DB_DONE ) {
00453 oss << "Desktop: device responded with unexpected packet command code: "
00454 << "0x" << std::hex << packet.Command();
00455 throw Error(oss.str());
00456 }
00457
00458 if( packet.ReturnCode() != 0 ) {
00459 oss << "Desktop: device responded with error code (command: "
00460 << packet.Command() << ", code: "
00461 << packet.ReturnCode() << ")";
00462 throw Error(oss.str());
00463 }
00464 }
00465 }
00466
00467
00468
00469
00470
00471
00472 struct DBLoaderData
00473 {
00474 DBPacket m_packet;
00475 DBLoaderData(Desktop &desktop, Data &command, Data &response)
00476 : m_packet(desktop, command, response)
00477 {
00478 }
00479 };
00480
00481 DBLoader::DBLoader(Desktop &desktop)
00482 : m_desktop(desktop)
00483 , m_loading(false)
00484 , m_loader(new DBLoaderData(desktop, m_send, m_send))
00485 {
00486 }
00487
00488 DBLoader::~DBLoader()
00489 {
00490 delete m_loader;
00491 }
00492
00493 bool DBLoader::StartDBLoad(unsigned int dbId, DBData &data)
00494 {
00495 dout("Database ID: " << dbId);
00496
00497 m_loading = true;
00498 m_desktop.m_dbdb.GetDBName(dbId, m_dbName);
00499
00500 DBPacket &packet = m_loader->m_packet;
00501 packet.SetNewReceive(data.UseData());
00502 packet.GetRecords(dbId);
00503 m_desktop.m_socket->Packet(packet);
00504
00505 while( packet.Command() != SB_COMMAND_DB_DONE ) {
00506 if( packet.Command() == SB_COMMAND_DB_DATA ) {
00507 packet.ParseMeta(data);
00508 data.SetDBName(m_dbName);
00509 return true;
00510 }
00511
00512
00513 m_desktop.m_socket->NextRecord(data.UseData());
00514 }
00515
00516 m_loading = false;
00517 return false;
00518 }
00519
00520 bool DBLoader::GetNextRecord(DBData &data)
00521 {
00522 if( !m_loading )
00523 return false;
00524
00525 DBPacket &packet = m_loader->m_packet;
00526 packet.SetNewReceive(data.UseData());
00527
00528 do {
00529
00530 m_desktop.m_socket->NextRecord(data.UseData());
00531
00532 if( packet.Command() == SB_COMMAND_DB_DATA ) {
00533 packet.ParseMeta(data);
00534 return true;
00535 }
00536 } while( m_loader->m_packet.Command() != SB_COMMAND_DB_DONE );
00537
00538 m_loading = false;
00539 return false;
00540 }
00541
00542 }
00543
00544
00545
00546
00547
00548
00549
00550
00551 DeviceBuilder::DeviceBuilder(Mode::Desktop &desktop)
00552 : m_started(false)
00553 , m_desktop(desktop)
00554 , m_loader(desktop)
00555 {
00556 Restart();
00557 }
00558
00559
00560
00561
00562 bool DeviceBuilder::Add(const std::string &dbname)
00563 {
00564 try {
00565 DBLabel id(m_desktop.GetDBID(dbname), dbname);
00566 m_dbIds.push_back(id);
00567 return true;
00568 }
00569 catch( Barry::Error & ) {
00570
00571 return false;
00572 }
00573 }
00574
00575 void DeviceBuilder::Add(const Barry::DatabaseDatabase &dbdb)
00576 {
00577 DatabaseDatabase::DatabaseArrayType::const_iterator
00578 b = dbdb.Databases.begin(),
00579 e = dbdb.Databases.end();
00580
00581 for( ; b != e; ++b ) {
00582
00583
00584
00585 DBLabel id(b->Number, b->Name);
00586 m_dbIds.push_back(id);
00587 }
00588 }
00589
00590 bool DeviceBuilder::BuildRecord(DBData &data,
00591 size_t &offset,
00592 const IConverter *ic)
00593 {
00594 DBData temp;
00595 if( !FetchRecord(temp, ic) )
00596 return false;
00597
00598
00599 data.SetVersion(temp.GetVersion());
00600 data.SetDBName(temp.GetDBName());
00601 data.SetIds(temp.GetRecType(), temp.GetUniqueId());
00602 data.SetOffset(offset);
00603
00604
00605 size_t tempsize = temp.GetData().GetSize() - temp.GetOffset();
00606 data.UseData().MemCpy(offset,
00607 temp.GetData().GetData() + temp.GetOffset(), tempsize);
00608 data.UseData().ReleaseBuffer(offset + tempsize);
00609 return true;
00610 }
00611
00612 bool DeviceBuilder::FetchRecord(DBData &data, const IConverter *ic)
00613 {
00614 bool ret;
00615
00616 if( !m_dbIds.size() )
00617 return false;
00618
00619 if( !m_started ) {
00620 m_current = m_dbIds.begin();
00621 ret = m_loader.StartDBLoad(m_current->id, data);
00622 m_started = true;
00623 }
00624 else if( m_loader.IsBusy() ) {
00625 ret = m_loader.GetNextRecord(data);
00626 }
00627 else {
00628
00629 if( EndOfFile() )
00630 return false;
00631
00632
00633
00634 ++m_current;
00635 if( EndOfFile() )
00636 return false;
00637
00638 ret = m_loader.StartDBLoad(m_current->id, data);
00639 }
00640
00641
00642 if( ret ) {
00643 data.SetDBName(m_current->name);
00644 }
00645 return ret;
00646 }
00647
00648 bool DeviceBuilder::EndOfFile() const
00649 {
00650 return m_current == m_dbIds.end();
00651 }
00652
00653
00654
00655
00656
00657
00658 DeviceParser::DeviceParser(Mode::Desktop &desktop, WriteMode mode)
00659 : m_desktop(desktop)
00660 , m_mode(mode)
00661 {
00662 }
00663
00664 DeviceParser::~DeviceParser()
00665 {
00666 }
00667
00668 void DeviceParser::StartDB(const DBData &data, const IConverter *ic)
00669 {
00670
00671 m_rstate.Clear();
00672 m_current_db = data.GetDBName();
00673 if( !m_desktop.GetDBDB().GetDBNumber(m_current_db, m_current_dbid) ) {
00674
00675 dout("Database '" << m_current_db << "' does not exist in this device. Dropping record.");
00676 m_current_db.clear();
00677 m_current_dbid = 0;
00678 return;
00679 }
00680
00681
00682 WriteMode mode = m_mode;
00683 if( mode == DECIDE_BY_CALLBACK )
00684 mode = DecideWrite(data);
00685
00686 switch( mode )
00687 {
00688 case ERASE_ALL_WRITE_ALL:
00689 m_desktop.ClearDatabase(m_current_dbid);
00690 WriteNext(data, ic);
00691 break;
00692
00693 case INDIVIDUAL_OVERWRITE:
00694 case ADD_BUT_NO_OVERWRITE:
00695 case ADD_WITH_NEW_ID:
00696 m_desktop.GetRecordStateTable(m_current_dbid, m_rstate);
00697 WriteNext(data, ic);
00698 break;
00699
00700 case DROP_RECORD:
00701 break;
00702
00703 case DECIDE_BY_CALLBACK:
00704 default:
00705 throw std::logic_error("DeviceParser: unknown mode");
00706 }
00707 }
00708
00709 void DeviceParser::WriteNext(const DBData &data, const IConverter *ic)
00710 {
00711
00712 WriteMode mode = m_mode;
00713 if( mode == DECIDE_BY_CALLBACK )
00714 mode = DecideWrite(data);
00715
00716
00717 DBData local(data.GetVersion(), data.GetDBName(),
00718 data.GetRecType(), data.GetUniqueId(), data.GetOffset(),
00719 data.GetData().GetData(), data.GetData().GetSize());
00720 DBDataBuilder dbuild(local);
00721
00722 RecordStateTable::IndexType index;
00723
00724 switch( mode )
00725 {
00726 case ERASE_ALL_WRITE_ALL:
00727
00728 m_desktop.AddRecord(m_current_dbid, dbuild);
00729 break;
00730
00731 case INDIVIDUAL_OVERWRITE:
00732
00733 if( m_rstate.GetIndex(local.GetUniqueId(), &index) ) {
00734
00735 m_desktop.SetRecord(m_current_dbid, index, dbuild);
00736 }
00737 else {
00738
00739 m_desktop.AddRecord(m_current_dbid, dbuild);
00740 }
00741 break;
00742
00743 case ADD_BUT_NO_OVERWRITE:
00744 if( !m_rstate.GetIndex(local.GetUniqueId()) ) {
00745
00746 m_desktop.AddRecord(m_current_dbid, dbuild);
00747 }
00748
00749 break;
00750
00751 case ADD_WITH_NEW_ID:
00752
00753 local.SetIds(local.GetRecType(), m_rstate.MakeNewRecordId());
00754 m_desktop.AddRecord(m_current_dbid, dbuild);
00755 break;
00756
00757 case DROP_RECORD:
00758 break;
00759
00760 case DECIDE_BY_CALLBACK:
00761 default:
00762 throw std::logic_error("DeviceParser: unknown mode");
00763 }
00764 }
00765
00766 void DeviceParser::ParseRecord(const DBData &data, const IConverter *ic)
00767 {
00768 if( data.GetDBName() == m_current_db ) {
00769 WriteNext(data, ic);
00770 }
00771 else {
00772 StartDB(data, ic);
00773 }
00774 }
00775
00776 }
00777