lib: Moving default Barry::Data size into constants.
[barry.git] / src / configfile.cc
blob5a8d399c33d03cc280220913d8026d026e406302
1 ///
2 /// \file configfile.cc
3 /// Barry configuraion class, for one device PIN
4 ///
6 /*
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"
23 #include "error.h"
24 #include "r_message.h"
25 #include <string.h>
26 #include <unistd.h>
27 #include <fstream>
28 #include <sstream>
29 #include <iostream>
30 #include <iomanip>
31 #include <sys/types.h>
32 #include <sys/stat.h>
34 namespace Barry {
36 bool ConfigFile::DBListType::IsSelected(const std::string &dbname) const
38 const_iterator i = begin();
39 for( ; i != end(); ++i ) {
40 if( *i == dbname ) {
41 return true;
44 return false;
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();
52 i != list.end();
53 ++i )
55 os << " " << *i << "\n";
57 return os;
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)
70 : m_pin(pin)
71 , m_loaded(false)
72 , m_promptBackupLabel(false)
73 , m_autoSelectAll(false)
75 if( m_pin == 0 )
76 throw ConfigFileError("Configfile: empty pin");
78 BuildFilename();
79 BuildDefaultPath(); // this handles the situation that path is not set
80 Load();
83 /// Opens and loads config file for given pin, and calls Enlighten
84 /// Throws ConfigFileError on error. Should never fail unless
85 /// passed a bad pin.
86 ConfigFile::ConfigFile(Barry::Pin pin,
87 const Barry::DatabaseDatabase &db)
88 : m_pin(pin)
89 , m_loaded(false)
90 , m_promptBackupLabel(false)
91 , m_autoSelectAll(false)
93 if( m_pin == 0 )
94 throw ConfigFileError("Configfile: empty pin");
96 BuildFilename();
97 BuildDefaultPath();
98 Load();
99 Enlighten(db);
102 ConfigFile::~ConfigFile()
106 void ConfigFile::Clear()
108 m_loaded = false;
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()
119 // start fresh
120 Clear();
122 // open input file
123 std::ifstream in(m_filename.c_str(), std::ios::in | std::ios::binary);
124 if( !in )
125 return;
127 std::string line;
128 DBListType *pList = 0;
130 while( std::getline(in, line) ) {
131 std::string keyword;
132 std::istringstream iss(line);
133 iss >> keyword;
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);
144 else {
145 pList = 0;
147 // add all remaining keyword checks here
148 if( keyword == "device_name" ) {
149 iss >> std::ws;
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
156 // the time
157 m_deviceName = " ";
160 else if( keyword == "backup_path" ) {
161 iss >> std::ws;
162 std::getline(iss, m_path);
163 if( (m_path.size() == 0) || !(CheckPath(m_path)))
164 BuildDefaultPath();
166 else if( keyword == "prompt_backup_label" ) {
167 int flag;
168 iss >> flag;
169 m_promptBackupLabel = flag != 0;
171 else if( keyword == "auto_select_all" ) {
172 int flag;
173 iss >> flag;
174 m_autoSelectAll = flag != 0;
179 m_loaded = true;
182 /// Saves current device's config, overwriting or creating a config file
183 bool ConfigFile::Save()
185 using namespace std;
187 if( !CheckPath(m_path, &m_last_error) )
188 return false;
190 ofstream out(m_filename.c_str(), std::ios::out | std::ios::binary);
191 if( !out ) {
192 m_last_error = "Unable to open " + m_filename + " for writing.";
193 return false;
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;
217 if( !out ) {
218 m_last_error = "Error during write. Config may be incomplete.";
219 return false;
221 return true;
224 /// Compares a given databasedatabase from a real device with the
225 /// current config. If not yet configured, initialize with valid
226 /// defaults.
227 void ConfigFile::Enlighten(const Barry::DatabaseDatabase &db)
229 if( !m_loaded ) {
230 // if not fully loaded, we use db as our default list
231 // our defaults are: backup everything, restore everything
232 // except email
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 ) {
240 // backup everything
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)
257 // start empty
258 clear();
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 ) {
264 push_back(i->Name);
267 return *this;
270 /// Sets list with new config
271 void ConfigFile::SetBackupList(const DBListType &list)
273 m_backupList = list;
274 m_loaded = true;
277 void ConfigFile::SetRestoreList(const DBListType &list)
279 m_restoreList = list;
280 m_loaded = true;
283 void ConfigFile::SetDeviceName(const std::string &name)
285 if( name.size() )
286 m_deviceName = name;
287 else
288 m_deviceName = " ";
291 void ConfigFile::SetBackupPath(const std::string &path)
293 if( path.size() && CheckPath(path) )
294 m_path = path;
295 else
296 BuildDefaultPath();
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()
314 : m_loaded(false)
315 , m_verboseLogging(false)
317 BuildFilename();
318 Load();
321 GlobalConfigFile::GlobalConfigFile(const std::string &appname)
322 : m_loaded(false)
323 , m_appname(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.");
330 BuildFilename();
331 Load();
334 GlobalConfigFile::~GlobalConfigFile()
338 void GlobalConfigFile::Clear()
340 m_loaded = false;
341 m_lastDevice = 0;
344 void GlobalConfigFile::Load()
346 // start fresh
347 Clear();
349 // open input file
350 std::ifstream in(m_filename.c_str(), std::ios::in | std::ios::binary);
351 if( !in )
352 return;
354 std::string line;
356 while( std::getline(in, line) ) {
357 std::string keyword;
358 std::istringstream iss(line);
359 iss >> keyword;
361 if( keyword == "last_device" ) {
362 iss >> std::ws;
363 m_lastDevice.Clear();
364 iss >> m_lastDevice;
366 else if( keyword == "verbose_logging" ) {
367 int flag = 0;
368 iss >> flag;
369 m_verboseLogging = flag != 0;
371 else {
372 // store any other keys as app keys
373 if( keyword.substr(0, 2) == "X-" ) {
374 iss >> std::ws;
375 line.clear();
376 std::getline(iss, line);
377 m_keymap[keyword] = line;
382 m_loaded = true;
385 /// Save the current global config, overwriting or creating as needed
386 bool GlobalConfigFile::Save()
388 if( !ConfigFile::CheckPath(m_path, &m_last_error) )
389 return false;
391 std::ofstream out(m_filename.c_str(), std::ios::out | std::ios::binary);
392 if( !out ) {
393 m_last_error = "Unable to open " + m_filename + " for writing.";
394 return false;
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;
409 if( !out ) {
410 m_last_error = "Error during write. Config may be incomplete.";
411 return false;
413 return true;
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;
438 return ci->second;
441 void GlobalConfigFile::SetLastDevice(const Barry::Pin &pin)
443 m_lastDevice = pin;
446 void GlobalConfigFile::SetVerboseLogging(bool verbose)
448 m_verboseLogging = verbose;
452 } // namespace Barry