2 /// \file DeviceIface.cc
3 /// Interface class for device backup and restore
7 Copyright (C) 2007-2012, 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"
35 DeviceInterface::DeviceInterface(Device
*dev
)
39 , m_dbnameMutex(new Glib::Mutex
) // this is just in an effort to
40 // avoid gtkmm headers in
42 , m_thread_quit(false)
46 DeviceInterface::~DeviceInterface()
52 bool DeviceInterface::False(const std::string
&msg
)
58 void DeviceInterface::BackupThread()
61 m_thread_quit
= false;
62 m_last_thread_error
= "";
65 // cycle through all database names in the dbList
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();
80 catch( std::exception
&e
) {
81 m_last_thread_error
= e
.what();
85 m_last_thread_error
= _("Terminated by user.");
88 m_backupStats
= m_backup
->GetStats();
92 m_AppComm
.m_error
->emit();
94 // signal host thread that we're done
95 m_AppComm
.m_done
->emit();
98 m_AppComm
.Invalidate();
101 void DeviceInterface::RestoreThread()
103 m_thread_quit
= false;
104 m_last_thread_error
= "";
108 // cycle until m_end_of_tar
110 while( !m_restore
->EndOfFile() ) {
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
) {
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: ")
135 << " (" << be
.what() << ")"
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();
151 m_last_thread_error
= _("Terminated by user.");
156 // signal host thread that we're done
157 m_AppComm
.m_done
->emit();
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
,
172 std::string
&dbid_text
,
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
);
187 iss
>> std::hex
>> dbid
>> temp
;
188 dbrectype
= (uint8_t) temp
;
193 void DeviceInterface::SetThreadDBName(const std::string
&dbname
)
195 Glib::Mutex::Lock
lock(*m_dbnameMutex
);
196 m_current_dbname
= dbname
;
199 //////////////////////////////////////////////////////////////////////////////
202 void DeviceInterface::Reset()
204 Usb::Device
dev(m_dev
->result
.m_dev
);
208 bool DeviceInterface::Connect()
212 m_con
= new Barry::Controller(m_dev
->result
);
213 m_desktop
= new Barry::Mode::Desktop(*m_con
);
217 catch( Barry::BadPassword
& ) {
218 // pass on to the caller
221 catch( Barry::BadSize
& ) {
222 // pass on to the caller
226 catch( Barry::Error
&e
) {
228 return False(e
.what());
232 bool DeviceInterface::Password(const char *password
)
235 m_desktop
->RetryPassword(password
);
238 catch( Barry::BadPassword
& ) {
239 // pass on to the caller
242 catch( Barry::Error
&e
) {
244 return False(e
.what());
248 void DeviceInterface::Disconnect()
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
;
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
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
] ) {
291 oss
<< "'" << i
->Name
<< "'" << _(" claimed to have ") << i
->RecordCount
<< _(" records, but actually retrieved ") << m_backupStats
[i
->Name
] << ".";
292 msgs
.push_back(oss
.str());
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."));
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());
325 m_dbBackupList
= backupList
;
329 Glib::Thread::create(sigc::mem_fun(*this, &DeviceInterface::BackupThread
), false);
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."));
341 m_restore
.reset( new Barry::Restore(filename
.c_str(), false) );
343 catch( Barry::BackupError
&be
) {
344 return False(be
.what());
349 m_restore
->Add(restoreList
);
353 Glib::Thread::create(sigc::mem_fun(*this, &DeviceInterface::RestoreThread
), false);
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();
368 if( m_thread_quit
) {
374 //////////////////////////////////////////////////////////////////////////////
375 // Barry::Builder overrides
377 bool DeviceInterface::BuildRecord(Barry::DBData
&data
, size_t &offset
,
378 const Barry::IConverter
*ic
)
381 if( m_thread_quit
) {
385 if( m_restore
->BuildRecord(data
, offset
, ic
) ) {
386 m_AppComm
.m_progress
->emit();
394 bool DeviceInterface::FetchRecord(Barry::DBData
&data
,
395 const Barry::IConverter
*ic
)
398 return BuildRecord(data
, offset
, ic
);
401 Device::Device(const Barry::ProbeResult
&result
)