configfile.cc
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "configfile.h"
00023 #include "error.h"
00024 #include "r_message.h"
00025 #include <pwd.h>
00026 #include <string.h>
00027 #include <errno.h>
00028 #include <unistd.h>
00029 #include <fstream>
00030 #include <sstream>
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033
00034 namespace Barry {
00035
00036 bool ConfigFile::DBListType::IsSelected(const std::string &dbname) const
00037 {
00038 const_iterator i = begin();
00039 for( ; i != end(); ++i ) {
00040 if( *i == dbname ) {
00041 return true;
00042 }
00043 }
00044 return false;
00045 }
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 ConfigFile::ConfigFile(Barry::Pin pin)
00057 : m_pin(pin)
00058 , m_loaded(false)
00059 , m_promptBackupLabel(false)
00060 {
00061 if( m_pin == 0 )
00062 throw ConfigFileError("Configfile: empty pin");
00063
00064 BuildFilename();
00065 BuildDefaultPath();
00066 Load();
00067 }
00068
00069
00070
00071
00072 ConfigFile::ConfigFile(Barry::Pin pin,
00073 const Barry::DatabaseDatabase &db)
00074 : m_pin(pin)
00075 , m_loaded(false)
00076 , m_promptBackupLabel(false)
00077 {
00078 if( m_pin == 0 )
00079 throw ConfigFileError("Configfile: empty pin");
00080
00081 BuildFilename();
00082 BuildDefaultPath();
00083 Load();
00084 Enlighten(db);
00085 }
00086
00087 ConfigFile::~ConfigFile()
00088 {
00089 }
00090
00091 void ConfigFile::BuildFilename()
00092 {
00093 struct passwd *pw = getpwuid(getuid());
00094 if( !pw )
00095 throw ConfigFileError("BuildFilename: getpwuid failed", errno);
00096
00097 m_filename = pw->pw_dir;
00098 m_filename += "/.barry/backup/";
00099 m_filename += m_pin.str();
00100 m_filename += "/config";
00101 }
00102
00103 void ConfigFile::BuildDefaultPath()
00104 {
00105 struct passwd *pw = getpwuid(getuid());
00106 m_path = pw->pw_dir;
00107 m_path += "/.barry/backup/";
00108 m_path += m_pin.str();
00109 }
00110
00111 void ConfigFile::Clear()
00112 {
00113 m_loaded = false;
00114 m_backupList.clear();
00115 m_restoreList.clear();
00116 m_deviceName.clear();
00117 m_promptBackupLabel = false;
00118 }
00119
00120
00121 void ConfigFile::Load()
00122 {
00123
00124 Clear();
00125
00126
00127 std::ifstream in(m_filename.c_str(), std::ios::in | std::ios::binary);
00128 if( !in )
00129 return;
00130
00131 std::string line;
00132 DBListType *pList = 0;
00133
00134 while( std::getline(in, line) ) {
00135 std::string keyword;
00136 std::istringstream iss(line);
00137 iss >> keyword;
00138
00139 if( keyword == "backup_list" ) {
00140 pList = &m_backupList;
00141 }
00142 else if( keyword == "restore_list" ) {
00143 pList = &m_restoreList;
00144 }
00145 else if( line[0] == ' ' && pList ) {
00146 pList->push_back(line.c_str() + 1);
00147 }
00148 else {
00149 pList = 0;
00150
00151
00152 if( keyword == "device_name" ) {
00153 iss >> std::ws;
00154 std::getline(iss, m_deviceName);
00155 if( m_deviceName.size() == 0 ) {
00156
00157
00158
00159
00160
00161 m_deviceName = " ";
00162 }
00163 }
00164 else if( keyword == "backup_path" ) {
00165 iss >> std::ws;
00166 std::getline(iss, m_path);
00167 if( (m_path.size() == 0) || !(CheckPath(m_path)))
00168 BuildDefaultPath();
00169 }
00170 else if( keyword == "prompt_backup_label" ) {
00171 int flag;
00172 iss >> flag;
00173 m_promptBackupLabel = flag;
00174 }
00175 }
00176 }
00177
00178 m_loaded = true;
00179 }
00180
00181
00182 bool ConfigFile::Save()
00183 {
00184 if( !CheckPath(m_path, &m_last_error) )
00185 return false;
00186
00187 std::ofstream out(m_filename.c_str(), std::ios::out | std::ios::binary);
00188 if( !out ) {
00189 m_last_error = "Unable to open " + m_filename + " for writing.";
00190 return false;
00191 }
00192
00193 out << "backup_list" << std::endl;
00194 for( DBListType::iterator i = m_backupList.begin(); i != m_backupList.end(); ++i ) {
00195 out << " " << *i << std::endl;
00196 }
00197
00198 out << "restore_list" << std::endl;
00199 for( DBListType::iterator i = m_restoreList.begin(); i != m_restoreList.end(); ++i ) {
00200 out << " " << *i << std::endl;
00201 }
00202
00203 if( m_deviceName.size() ) {
00204 out << "device_name " << m_deviceName << std::endl;
00205 }
00206
00207 if( m_path.size() ) {
00208 out << "backup_path " << m_path << std::endl;
00209 }
00210
00211 out << "prompt_backup_label " << (m_promptBackupLabel ? 1 : 0) << std::endl;
00212
00213 if( !out ) {
00214 m_last_error = "Error during write. Config may be incomplete.";
00215 return false;
00216 }
00217 return true;
00218 }
00219
00220
00221
00222
00223 void ConfigFile::Enlighten(const Barry::DatabaseDatabase &db)
00224 {
00225 if( !m_loaded ) {
00226
00227
00228
00229
00230 m_backupList.clear();
00231 m_restoreList.clear();
00232
00233 Barry::DatabaseDatabase::DatabaseArrayType::const_iterator i =
00234 db.Databases.begin();
00235 for( ; i != db.Databases.end(); ++i ) {
00236
00237 m_backupList.push_back(i->Name);
00238
00239
00240
00241 if( i->Name != Barry::Message::GetDBName() &&
00242 i->Name != "Handheld Agent" )
00243 {
00244 m_restoreList.push_back(i->Name);
00245 }
00246 }
00247 }
00248 }
00249
00250
00251 void ConfigFile::SetBackupList(const DBListType &list)
00252 {
00253 m_backupList = list;
00254 m_loaded = true;
00255 }
00256
00257 void ConfigFile::SetRestoreList(const DBListType &list)
00258 {
00259 m_restoreList = list;
00260 m_loaded = true;
00261 }
00262
00263 void ConfigFile::SetDeviceName(const std::string &name)
00264 {
00265 if( name.size() )
00266 m_deviceName = name;
00267 else
00268 m_deviceName = " ";
00269 }
00270
00271 void ConfigFile::SetBackupPath(const std::string &path)
00272 {
00273 if( path.size() && CheckPath(path) )
00274 m_path = path;
00275 else
00276 BuildDefaultPath();
00277 }
00278
00279 void ConfigFile::SetPromptBackupLabel(bool prompt)
00280 {
00281 m_promptBackupLabel = prompt;
00282 }
00283
00284
00285
00286 bool ConfigFile::CheckPath(const std::string &path, std::string *perr)
00287 {
00288 if( path.size() == 0 ) {
00289 if( perr )
00290 *perr = "path is empty!";
00291 return false;
00292 }
00293
00294 if( access(path.c_str(), F_OK) == 0 )
00295 return true;
00296
00297 std::string base;
00298 std::string::size_type slash = 0;
00299 while( (slash = path.find('/', slash + 1)) != std::string::npos ) {
00300 base = path.substr(0, slash);
00301 if( access(base.c_str(), F_OK) != 0 ) {
00302 if( mkdir(base.c_str(), 0755) == -1 ) {
00303 if( perr ) {
00304 *perr = "mkdir(" + base + ") failed: ";
00305 *perr += strerror(errno);
00306 }
00307 return false;
00308 }
00309 }
00310 }
00311 if( mkdir(path.c_str(), 0755) == -1 ) {
00312 if( perr ) {
00313 *perr = "last mkdir(" + path + ") failed: ";
00314 *perr += strerror(errno);
00315 }
00316 return false;
00317 }
00318 return true;
00319 }
00320
00321
00322
00323
00324
00325
00326 GlobalConfigFile::GlobalConfigFile()
00327 : m_loaded(false)
00328 , m_verboseLogging(false)
00329 {
00330 BuildFilename();
00331 Load();
00332 }
00333
00334 GlobalConfigFile::GlobalConfigFile(const std::string &appname)
00335 : m_loaded(false)
00336 , m_appname(appname)
00337 , m_verboseLogging(false)
00338 {
00339
00340 if( m_appname.find(' ') != std::string::npos )
00341 throw std::logic_error("App name must have no spaces.");
00342
00343 BuildFilename();
00344 Load();
00345 }
00346
00347 GlobalConfigFile::~GlobalConfigFile()
00348 {
00349 }
00350
00351 void GlobalConfigFile::BuildFilename()
00352 {
00353 struct passwd *pw = getpwuid(getuid());
00354 if( !pw )
00355 throw ConfigFileError("BuildFilename: getpwuid failed", errno);
00356
00357 m_filename = pw->pw_dir;
00358 m_filename += "/.barry/config";
00359
00360
00361 m_path = pw->pw_dir;
00362 m_path += "/.barry";
00363 }
00364
00365 void GlobalConfigFile::Clear()
00366 {
00367 m_loaded = false;
00368 m_lastDevice = 0;
00369 }
00370
00371 void GlobalConfigFile::Load()
00372 {
00373
00374 Clear();
00375
00376
00377 std::ifstream in(m_filename.c_str(), std::ios::in | std::ios::binary);
00378 if( !in )
00379 return;
00380
00381 std::string line;
00382
00383 while( std::getline(in, line) ) {
00384 std::string keyword;
00385 std::istringstream iss(line);
00386 iss >> keyword;
00387
00388 if( keyword == "last_device" ) {
00389 iss >> std::ws;
00390 m_lastDevice.clear();
00391 iss >> m_lastDevice;
00392 }
00393 else if( keyword == "verbose_logging" ) {
00394 int flag = 0;
00395 iss >> flag;
00396 m_verboseLogging = flag;
00397 }
00398 else {
00399
00400 if( keyword.substr(0, 2) == "X-" ) {
00401 iss >> std::ws;
00402 line.clear();
00403 std::getline(iss, line);
00404 m_keymap[keyword] = line;
00405 }
00406 }
00407 }
00408
00409 m_loaded = true;
00410 }
00411
00412
00413 bool GlobalConfigFile::Save()
00414 {
00415 if( !ConfigFile::CheckPath(m_path, &m_last_error) )
00416 return false;
00417
00418 std::ofstream out(m_filename.c_str(), std::ios::out | std::ios::binary);
00419 if( !out ) {
00420 m_last_error = "Unable to open " + m_filename + " for writing.";
00421 return false;
00422 }
00423
00424 if( !(m_lastDevice == 0) ) {
00425 out << "last_device " << m_lastDevice.str() << std::endl;
00426 }
00427
00428 out << "verbose_logging " << (m_verboseLogging ? 1 : 0) << std::endl;
00429
00430
00431 keymap_type::const_iterator ci = m_keymap.begin();
00432 for( ; ci != m_keymap.end(); ++ci ) {
00433 out << ci->first << " " << ci->second << std::endl;
00434 }
00435
00436 if( !out ) {
00437 m_last_error = "Error during write. Config may be incomplete.";
00438 return false;
00439 }
00440 return true;
00441 }
00442
00443 void GlobalConfigFile::SetKey(const std::string &key, const std::string &value)
00444 {
00445 if( !m_appname.size() )
00446 throw std::logic_error("Cannot use SetKey() without specifying an appname in the constructor.");
00447
00448 if( value.find_first_of("\n\r") != std::string::npos )
00449 throw std::logic_error("SetKey values may not contain newline characters.");
00450
00451 std::string fullkey = "X-" + m_appname + "-" + key;
00452 m_keymap[fullkey] = value;
00453 }
00454
00455 std::string GlobalConfigFile::GetKey(const std::string &key) const
00456 {
00457 if( !m_appname.size() )
00458 throw std::logic_error("Cannot use SetKey() without specifying an appname in the constructor.");
00459
00460 std::string fullkey = "X-" + m_appname + "-" + key;
00461 keymap_type::const_iterator ci = m_keymap.find(fullkey);
00462 if( ci == m_keymap.end() )
00463 return "";
00464 return ci->second;
00465 }
00466
00467 void GlobalConfigFile::SetLastDevice(const Barry::Pin &pin)
00468 {
00469 m_lastDevice = pin;
00470 }
00471
00472 void GlobalConfigFile::SetVerboseLogging(bool verbose)
00473 {
00474 m_verboseLogging = verbose;
00475 }
00476
00477
00478 }
00479