2 /// \file configfile.cc
3 /// Barry configuraion class, for one device PIN
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 "configfile.h"
24 #include "r_message.h"
31 #include <sys/types.h>
36 bool ConfigFile::DBListType::IsSelected(const std::string
&dbname
) const
38 const_iterator i
= begin();
39 for( ; i
!= end(); ++i
) {
47 std::ostream
& operator<< (std::ostream
&os
, const ConfigFile::DBListType
&list
)
49 os
<< "DBListType dump:\n";
51 for( ConfigFile::DBListType::const_iterator i
= list
.begin();
55 os
<< " " << *i
<< "\n";
61 //////////////////////////////////////////////////////////////////////////////
62 // ConfigFile class members
64 /// Loads config file for the given pin, and ends up in an
65 /// unenlightened state. Throws ConfigFileError on error,
66 /// but it is not an error if the config does not exist.
67 /// Never use this if you have a DatabaseDatabase object!
68 /// This ctor is only for temporary loading of config data.
69 ConfigFile::ConfigFile(Barry::Pin pin
)
72 , m_promptBackupLabel(false)
73 , m_autoSelectAll(false)
76 throw ConfigFileError("Configfile: empty pin");
79 BuildDefaultPath(); // this handles the situation that path is not set
83 /// Opens and loads config file for given pin, and calls Enlighten
84 /// Throws ConfigFileError on error. Should never fail unless
86 ConfigFile::ConfigFile(Barry::Pin pin
,
87 const Barry::DatabaseDatabase
&db
)
90 , m_promptBackupLabel(false)
91 , m_autoSelectAll(false)
94 throw ConfigFileError("Configfile: empty pin");
102 ConfigFile::~ConfigFile()
106 void ConfigFile::Clear()
109 m_backupList
.clear();
110 m_restoreList
.clear();
111 m_deviceName
.clear();
112 m_promptBackupLabel
= false;
113 m_autoSelectAll
= false;
116 /// Attempt to load the configuration file, but do not fail if not available
117 void ConfigFile::Load()
123 std::ifstream
in(m_filename
.c_str(), std::ios::in
| std::ios::binary
);
128 DBListType
*pList
= 0;
130 while( std::getline(in
, line
) ) {
132 std::istringstream
iss(line
);
135 if( keyword
== "backup_list" ) {
136 pList
= &m_backupList
;
138 else if( keyword
== "restore_list" ) {
139 pList
= &m_restoreList
;
141 else if( line
[0] == ' ' && pList
) {
142 pList
->push_back(line
.c_str() + 1);
147 // add all remaining keyword checks here
148 if( keyword
== "device_name" ) {
150 std::getline(iss
, m_deviceName
);
151 if( m_deviceName
.size() == 0 ) {
152 // if there is a device_name setting,
153 // then this value must hold something,
154 // so that the user can ignore this
155 // field, and not get pestered all
160 else if( keyword
== "backup_path" ) {
162 std::getline(iss
, m_path
);
163 if( (m_path
.size() == 0) || !(CheckPath(m_path
)))
166 else if( keyword
== "prompt_backup_label" ) {
169 m_promptBackupLabel
= flag
!= 0;
171 else if( keyword
== "auto_select_all" ) {
174 m_autoSelectAll
= flag
!= 0;
182 /// Saves current device's config, overwriting or creating a config file
183 bool ConfigFile::Save()
187 if( !CheckPath(m_path
, &m_last_error
) )
190 ofstream
out(m_filename
.c_str(), std::ios::out
| std::ios::binary
);
192 m_last_error
= "Unable to open " + m_filename
+ " for writing.";
196 out
<< "backup_list" << endl
;
197 for( DBListType::iterator i
= m_backupList
.begin(); i
!= m_backupList
.end(); ++i
) {
198 out
<< " " << *i
<< endl
;
201 out
<< "restore_list" << endl
;
202 for( DBListType::iterator i
= m_restoreList
.begin(); i
!= m_restoreList
.end(); ++i
) {
203 out
<< " " << *i
<< endl
;
206 if( m_deviceName
.size() ) {
207 out
<< "device_name " << m_deviceName
<< endl
;
210 if( m_path
.size() ) {
211 out
<< "backup_path " << m_path
<< endl
;
214 out
<< "prompt_backup_label " << (m_promptBackupLabel
? 1 : 0) << endl
;
215 out
<< "auto_select_all " << (m_autoSelectAll
? 1 : 0) << endl
;
218 m_last_error
= "Error during write. Config may be incomplete.";
224 /// Compares a given databasedatabase from a real device with the
225 /// current config. If not yet configured, initialize with valid
227 void ConfigFile::Enlighten(const Barry::DatabaseDatabase
&db
)
230 // if not fully loaded, we use db as our default list
231 // our defaults are: backup everything, restore everything
234 m_backupList
.clear();
235 m_restoreList
.clear();
237 Barry::DatabaseDatabase::DatabaseArrayType::const_iterator i
=
238 db
.Databases
.begin();
239 for( ; i
!= db
.Databases
.end(); ++i
) {
241 m_backupList
.push_back(i
->Name
);
243 // restore everything except email (which could take ages)
244 // and Handheld Agent (which seems write protected)
245 if( i
->Name
!= Barry::Message::GetDBName() &&
246 i
->Name
!= "Handheld Agent" )
248 m_restoreList
.push_back(i
->Name
);
254 // fill list with all databases from dbdb
255 ConfigFile:: DBListType
& ConfigFile::DBListType::operator=(const DatabaseDatabase
&dbdb
)
260 // copy over all DB names
261 DatabaseDatabase::DatabaseArrayType::const_iterator
262 i
= dbdb
.Databases
.begin(), e
= dbdb
.Databases
.end();
263 for( ; i
!= e
; ++i
) {
270 /// Sets list with new config
271 void ConfigFile::SetBackupList(const DBListType
&list
)
277 void ConfigFile::SetRestoreList(const DBListType
&list
)
279 m_restoreList
= list
;
283 void ConfigFile::SetDeviceName(const std::string
&name
)
291 void ConfigFile::SetBackupPath(const std::string
&path
)
293 if( path
.size() && CheckPath(path
) )
299 void ConfigFile::SetPromptBackupLabel(bool prompt
)
301 m_promptBackupLabel
= prompt
;
304 void ConfigFile::SetAutoSelectAll(bool asa
)
306 m_autoSelectAll
= asa
;
310 //////////////////////////////////////////////////////////////////////////////
311 // GlobalConfigFile class members
313 GlobalConfigFile::GlobalConfigFile()
315 , m_verboseLogging(false)
321 GlobalConfigFile::GlobalConfigFile(const std::string
&appname
)
324 , m_verboseLogging(false)
326 // there can be no spaces in the appname
327 if( m_appname
.find(' ') != std::string::npos
)
328 throw std::logic_error("App name must have no spaces.");
334 GlobalConfigFile::~GlobalConfigFile()
338 void GlobalConfigFile::Clear()
344 void GlobalConfigFile::Load()
350 std::ifstream
in(m_filename
.c_str(), std::ios::in
| std::ios::binary
);
356 while( std::getline(in
, line
) ) {
358 std::istringstream
iss(line
);
361 if( keyword
== "last_device" ) {
363 m_lastDevice
.Clear();
366 else if( keyword
== "verbose_logging" ) {
369 m_verboseLogging
= flag
!= 0;
372 // store any other keys as app keys
373 if( keyword
.substr(0, 2) == "X-" ) {
376 std::getline(iss
, line
);
377 m_keymap
[keyword
] = line
;
385 /// Save the current global config, overwriting or creating as needed
386 bool GlobalConfigFile::Save()
388 if( !ConfigFile::CheckPath(m_path
, &m_last_error
) )
391 std::ofstream
out(m_filename
.c_str(), std::ios::out
| std::ios::binary
);
393 m_last_error
= "Unable to open " + m_filename
+ " for writing.";
397 if( !(m_lastDevice
== 0) ) {
398 out
<< "last_device " << m_lastDevice
.Str() << std::endl
;
401 out
<< "verbose_logging " << (m_verboseLogging
? 1 : 0) << std::endl
;
403 // store all app keys
404 keymap_type::const_iterator ci
= m_keymap
.begin();
405 for( ; ci
!= m_keymap
.end(); ++ci
) {
406 out
<< ci
->first
<< " " << ci
->second
<< std::endl
;
410 m_last_error
= "Error during write. Config may be incomplete.";
416 void GlobalConfigFile::SetKey(const std::string
&key
, const std::string
&value
)
418 if( !m_appname
.size() )
419 throw std::logic_error("Cannot use SetKey() without specifying an appname in the constructor.");
421 if( value
.find_first_of("\n\r") != std::string::npos
)
422 throw std::logic_error("SetKey values may not contain newline characters.");
424 std::string fullkey
= "X-" + m_appname
+ "-" + key
;
425 m_keymap
[fullkey
] = value
;
428 std::string
GlobalConfigFile::GetKey(const std::string
&key
,
429 const std::string
&default_value
) const
431 if( !m_appname
.size() )
432 throw std::logic_error("Cannot use SetKey() without specifying an appname in the constructor.");
434 std::string fullkey
= "X-" + m_appname
+ "-" + key
;
435 keymap_type::const_iterator ci
= m_keymap
.find(fullkey
);
436 if( ci
== m_keymap
.end() )
437 return default_value
;
441 void GlobalConfigFile::SetLastDevice(const Barry::Pin
&pin
)
446 void GlobalConfigFile::SetVerboseLogging(bool verbose
)
448 m_verboseLogging
= verbose
;