Bumped copyright dates for 2013
[barry.git] / gui / src / DeviceIface.cc
blob848da9d8744b47b4215b2e340326388c1de3f9f6
1 ///
2 /// \file DeviceIface.cc
3 /// Interface class for device backup and restore
4 ///
6 /*
7 Copyright (C) 2007-2013, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "DeviceIface.h"
23 #include "util.h"
24 #include "i18n.h"
25 #include <glibmm.h>
26 #include <iostream>
27 #include <iomanip>
28 #include <sstream>
29 #include <time.h>
30 #include <string.h>
31 #include <stdlib.h>
33 using namespace std;
35 DeviceInterface::DeviceInterface(Device *dev)
36 : m_dev(dev)
37 , m_con(0)
38 , m_desktop(0)
39 , m_dbnameMutex(new Glib::Mutex) // this is just in an effort to
40 // avoid gtkmm headers in
41 // DeviceIface.h
42 , m_thread_quit(false)
46 DeviceInterface::~DeviceInterface()
48 Disconnect();
49 delete m_dbnameMutex;
52 bool DeviceInterface::False(const std::string &msg)
54 m_last_error = msg;
55 return false;
58 void DeviceInterface::BackupThread()
60 bool error = false;
61 m_thread_quit = false;
62 m_last_thread_error = "";
64 try {
65 // cycle through all database names in the dbList
66 // and store them all
67 Barry::ConfigFile::DBListType::const_iterator name = m_dbBackupList.begin();
68 for( ; name != m_dbBackupList.end(); ++name ) {
69 // save current db name
70 SetThreadDBName(*name);
71 // call the controller to do the work
72 unsigned int dbId = m_desktop->GetDBID(*name);
73 m_desktop->LoadDatabase(dbId, *this);
76 catch( Glib::Exception &e ) {
77 m_last_thread_error = e.what();
78 error = true;
80 catch( std::exception &e ) {
81 m_last_thread_error = e.what();
82 error = true;
84 catch( Quit &q ) {
85 m_last_thread_error = _("Terminated by user.");
88 m_backupStats = m_backup->GetStats();
89 m_backup.reset();
91 if( error )
92 m_AppComm.m_error->emit();
94 // signal host thread that we're done
95 m_AppComm.m_done->emit();
97 // done!
98 m_AppComm.Invalidate();
101 void DeviceInterface::RestoreThread()
103 m_thread_quit = false;
104 m_last_thread_error = "";
106 try {
108 // cycle until m_end_of_tar
109 Barry::DBData meta;
110 while( !m_restore->EndOfFile() ) {
111 try {
112 if( m_restore->GetNextMeta(meta) ) {
113 // save current db name
114 SetThreadDBName(meta.GetDBName());
115 // call the controller to do the work
116 unsigned int dbId = m_desktop->GetDBID(meta.GetDBName());
117 m_AppComm.m_erase_db->emit();
118 m_desktop->SaveDatabase(dbId, *this);
119 m_AppComm.m_restored_db->emit();
122 catch( Barry::Error &be ) {
123 // save thread error
124 m_last_thread_error = _("Error while restoring ");
125 m_last_thread_error += meta.GetDBName() + ". ";
126 m_last_thread_error += be.what();
127 m_last_thread_error += _(" Will continue processing.");
129 // notify host thread
130 m_AppComm.m_error->emit();
132 // skip over records from this db
133 std::cerr << _("Error on database: ")
134 << meta.GetDBName()
135 << " (" << be.what() << ")"
136 << std::endl;
137 m_restore->SkipCurrentDB();
142 catch( Glib::Exception &e ) {
143 m_last_thread_error = e.what();
144 m_AppComm.m_error->emit();
146 catch( std::exception &e ) {
147 m_last_thread_error = e.what();
148 m_AppComm.m_error->emit();
150 catch( Quit &q ) {
151 m_last_thread_error = _("Terminated by user.");
154 m_restore.reset();
156 // signal host thread that we're done
157 m_AppComm.m_done->emit();
159 // done!
160 m_AppComm.Invalidate();
163 std::string DeviceInterface::MakeFilename(const std::string &label) const
165 return Barry::MakeBackupFilename(m_dev->GetPIN(), label);
168 /// Splits a tarpath of the form "DBName/DBID" into separate string values.
169 /// Returns true if successful, false if tarpath is a bad name.
170 bool DeviceInterface::SplitTarPath(const std::string &tarpath,
171 std::string &dbname,
172 std::string &dbid_text,
173 uint8_t &dbrectype,
174 uint32_t &dbid) const
176 std::string::size_type pos = tarpath.rfind('/');
177 if( pos == std::string::npos )
178 return false; // bad name
180 dbname = tarpath.substr(0, pos);
181 dbid_text = tarpath.substr(pos + 1);
182 if( dbname.size() == 0 || dbid_text.size() == 0 )
183 return false; // bad name
185 std::istringstream iss(dbid_text);
186 unsigned int temp;
187 iss >> std::hex >> dbid >> temp;
188 dbrectype = (uint8_t) temp;
190 return true;
193 void DeviceInterface::SetThreadDBName(const std::string &dbname)
195 Glib::Mutex::Lock lock(*m_dbnameMutex);
196 m_current_dbname = dbname;
199 //////////////////////////////////////////////////////////////////////////////
200 // Public API
202 void DeviceInterface::Reset()
204 Usb::Device dev(m_dev->result.m_dev);
205 dev.Reset();
208 bool DeviceInterface::Connect()
210 try {
211 Disconnect();
212 m_con = new Barry::Controller(m_dev->result);
213 m_desktop = new Barry::Mode::Desktop(*m_con);
214 m_desktop->Open();
215 return true;
217 catch( Barry::BadPassword & ) {
218 // pass on to the caller
219 throw;
221 catch( Barry::BadSize & ) {
222 // pass on to the caller
223 Disconnect();
224 throw;
226 catch( Barry::Error &e ) {
227 Disconnect();
228 return False(e.what());
232 bool DeviceInterface::Password(const char *password)
234 try {
235 m_desktop->RetryPassword(password);
236 return true;
238 catch( Barry::BadPassword & ) {
239 // pass on to the caller
240 throw;
242 catch( Barry::Error &e ) {
243 Disconnect();
244 return False(e.what());
248 void DeviceInterface::Disconnect()
250 delete m_desktop;
251 m_desktop = 0;
253 delete m_con;
254 m_con = 0;
257 // cycle through controller's DBDB and count the records in all the
258 // databases selected in the backupList
259 unsigned int DeviceInterface::GetRecordTotal(const Barry::ConfigFile::DBListType &backupList) const
261 unsigned int count = 0;
263 Barry::DatabaseDatabase::DatabaseArrayType::const_iterator
264 i = m_desktop->GetDBDB().Databases.begin();
265 for( ; i != m_desktop->GetDBDB().Databases.end(); ++i ) {
266 if( backupList.IsSelected(i->Name) ) {
267 count += i->RecordCount;
270 return count;
273 unsigned int DeviceInterface::GetRecordTotal(const Barry::ConfigFile::DBListType &restoreList, const std::string &filename) const
275 return Barry::Restore::GetRecordTotal(filename, restoreList, false);
278 // cycle through controller's DBDB and compare the record count of each
279 // database, and store an error message for each one that is not equal,
280 // and return the list of messages as a vector
281 std::vector<std::string> DeviceInterface::CompareTotals(const Barry::ConfigFile::DBListType &backupList) const
283 vector<string> msgs;
285 Barry::DatabaseDatabase::DatabaseArrayType::const_iterator
286 i = m_desktop->GetDBDB().Databases.begin();
287 for( ; i != m_desktop->GetDBDB().Databases.end(); ++i ) {
288 if( backupList.IsSelected(i->Name) ) {
289 if( (int)i->RecordCount != m_backupStats[i->Name] ) {
290 ostringstream oss;
291 oss << "'" << i->Name << "'" << _(" claimed to have ") << i->RecordCount << _(" records, but actually retrieved ") << m_backupStats[i->Name] << ".";
292 msgs.push_back(oss.str());
297 return msgs;
300 /// returns name of database the thread is currently working on
301 std::string DeviceInterface::GetThreadDBName() const
303 Glib::Mutex::Lock lock(*m_dbnameMutex);
304 return m_current_dbname;
307 bool DeviceInterface::StartBackup(AppComm comm,
308 const Barry::ConfigFile::DBListType &backupList,
309 const std::string &directory,
310 const std::string &backupLabel)
312 if( m_AppComm.IsValid() )
313 return False(_("Thread already running."));
315 try {
316 std::string filename = directory + "/" + MakeFilename(backupLabel);
317 m_backup.reset( new Barry::Backup(filename.c_str()) );
319 catch( Barry::BackupError &be ) {
320 return False(be.what());
323 // setup
324 m_AppComm = comm;
325 m_dbBackupList = backupList;
326 SetThreadDBName("");
328 // start the thread
329 Glib::Thread::create(sigc::mem_fun(*this, &DeviceInterface::BackupThread), false);
330 return true;
333 bool DeviceInterface::StartRestore(AppComm comm,
334 const Barry::ConfigFile::DBListType &restoreList,
335 const std::string &filename)
337 if( m_AppComm.IsValid() )
338 return False(_("Thread already running."));
340 try {
341 m_restore.reset( new Barry::Restore(filename.c_str(), false) );
343 catch( Barry::BackupError &be ) {
344 return False(be.what());
347 // setup
348 m_AppComm = comm;
349 m_restore->Add(restoreList);
350 SetThreadDBName("");
352 // start the thread
353 Glib::Thread::create(sigc::mem_fun(*this, &DeviceInterface::RestoreThread), false);
354 return true;
358 //////////////////////////////////////////////////////////////////////////////
359 // Barry::Parser overrides
361 void DeviceInterface::ParseRecord(const Barry::DBData &data,
362 const Barry::IConverter *ic)
364 m_backup->ParseRecord(data, ic);
365 m_AppComm.m_progress->emit();
367 // check quit flag
368 if( m_thread_quit ) {
369 throw Quit();
374 //////////////////////////////////////////////////////////////////////////////
375 // Barry::Builder overrides
377 bool DeviceInterface::BuildRecord(Barry::DBData &data, size_t &offset,
378 const Barry::IConverter *ic)
380 // check quit flag
381 if( m_thread_quit ) {
382 throw Quit();
385 if( m_restore->BuildRecord(data, offset, ic) ) {
386 m_AppComm.m_progress->emit();
387 return true;
389 else {
390 return false;
394 bool DeviceInterface::FetchRecord(Barry::DBData &data,
395 const Barry::IConverter *ic)
397 size_t offset = 0;
398 return BuildRecord(data, offset, ic);
401 Device::Device(const Barry::ProbeResult &result)
402 : result(result)