/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Preferences.cpp * This class stores preferences in files * Copyright (C) 2005-2008 Simon Newton */ #include #include #include #include #include #include #include #include #include #include #include #include #include "ola/Logging.h" #include "ola/StringUtils.h" #include "olad/Preferences.h" namespace ola { using std::ifstream; using std::ofstream; using std::pair; const char BoolValidator::TRUE[] = "true"; const char BoolValidator::FALSE[] = "false"; const char FileBackedPreferences::OLA_CONFIG_DIR[] = ".ola"; const char FileBackedPreferences::OLA_CONFIG_PREFIX[] = "ola-"; const char FileBackedPreferences::OLA_CONFIG_SUFFIX[] = ".conf"; // Validators //----------------------------------------------------------------------------- bool StringValidator::IsValid(const string &value) const { return !value.empty(); } bool BoolValidator::IsValid(const string &value) const { return (value == TRUE || value == FALSE); } bool IntValidator::IsValid(const string &value) const { unsigned int output; if (!StringToUInt(value, &output)) return false; return (output >= m_gt && output <= m_lt); } bool SetValidator::IsValid(const string &value) const { return m_values.end() != m_values.find(value); } bool IPv4Validator::IsValid(const string &value) const { if (value.empty()) return m_empty_ok; vector tokens; StringSplit(value, tokens, "."); if (tokens.size() != 4) return false; for (unsigned int i = 0 ; i < 4; i++) { unsigned int octet; if (!StringToUInt(tokens[i], &octet)) return false; if (octet > 255) return false; } return true; } // Prefs Factory //----------------------------------------------------------------------------- /** * Cleanup */ PreferencesFactory::~PreferencesFactory() { map::const_iterator iter; for (iter = m_preferences_map.begin(); iter != m_preferences_map.end(); ++iter) { delete iter->second; } m_preferences_map.clear(); } /** * Lookup a preference object */ Preferences *PreferencesFactory::NewPreference(const string &name) { map::iterator iter = m_preferences_map.find(name); if (iter == m_preferences_map.end()) { Preferences *pref = Create(name); m_preferences_map.insert(pair(name, pref)); return pref; } else { return iter->second; } } // Memory Preferences //----------------------------------------------------------------------------- /* * Destroy this object */ MemoryPreferences::~MemoryPreferences() { m_pref_map.clear(); } /* * Clear the preferences */ void MemoryPreferences::Clear() { m_pref_map.clear(); } /* * Set a preference value, overiding the existing value. * @param key * @param value */ void MemoryPreferences::SetValue(const string &key, const string &value) { m_pref_map.erase(key); m_pref_map.insert(pair(key, value)); } /* * Adds this preference value to the store * @param key * @param value */ void MemoryPreferences::SetMultipleValue(const string &key, const string &value) { m_pref_map.insert(pair(key, value)); } /* * Set a preference value only if it doesn't pass the validator. * Note this only checks the first value. * @param key * @param validator A Validator object * @param value the new value * @return true if we set the value, false if it already existed */ bool MemoryPreferences::SetDefaultValue(const string &key, const Validator &validator, const string &value) { map::const_iterator iter; iter = m_pref_map.find(key); if (iter == m_pref_map.end() || !validator.IsValid(iter->second)) { SetValue(key, value); return true; } return false; } /* * Get a preference value * @param key the key to fetch * @return the value corrosponding to key, or the empty string if the key * doesn't exist. */ string MemoryPreferences::GetValue(const string &key) const { map::const_iterator iter; iter = m_pref_map.find(key); if (iter != m_pref_map.end()) return iter->second; return ""; } /* * Returns all preference values corrosponding to this key * @returns a vector of strings. */ vector MemoryPreferences::GetMultipleValue(const string &key) const { vector values; map::const_iterator iter; for (iter = m_pref_map.find(key); iter != m_pref_map.end() && iter->first == key; ++iter) { values.push_back(iter->second); } return values; } /* * Remove a preference value. * @param key */ void MemoryPreferences::RemoveValue(const string &key) { m_pref_map.erase(key); } /* * Set a value as a bool. * @param key * @param value */ void MemoryPreferences::SetValueAsBool(const string &key, bool value) { m_pref_map.erase(key); if (value) m_pref_map.insert(pair(key, BoolValidator::TRUE)); else m_pref_map.insert(pair(key, BoolValidator::FALSE)); } /* * Get a preference value as a bool * @param key the key to fetch * @return true if the value is 'true' or false otherwise */ bool MemoryPreferences::GetValueAsBool(const string &key) const { map::const_iterator iter; iter = m_pref_map.find(key); if (iter != m_pref_map.end()) return iter->second == BoolValidator::TRUE; return false; } // FileBackedPreferences //----------------------------------------------------------------------------- /* * Load the preferences from storage */ bool FileBackedPreferences::Load() { if (!ChangeDir()) return false; return LoadFromFile(FileName()); } /* * Save the preferences to storage */ bool FileBackedPreferences::Save() const { if (!ChangeDir()) return false; return SaveToFile(FileName()); } /* * Return the name of the file used to save the preferences */ const string FileBackedPreferences::FileName() const { return OLA_CONFIG_PREFIX + m_preference_name + OLA_CONFIG_SUFFIX; } /* * Load these preferences from a file * @param filename the filename to load from */ bool FileBackedPreferences::LoadFromFile(const string &filename) { ifstream pref_file(filename.data()); if (!pref_file.is_open()) { OLA_INFO << "Missing " << filename << ": " << strerror(errno) << " - this isn't an error, we'll just use the defaults"; return false; } m_pref_map.clear(); string line; while (getline(pref_file, line)) { StringTrim(&line); if (line.empty() || line.at(0) == '#') continue; vector tokens; StringSplit(line, tokens, "="); if (tokens.size() != 2) { OLA_INFO << "Skipping line: " << line; continue; } string key = tokens[0]; string value = tokens[1]; StringTrim(&key); StringTrim(&value); m_pref_map.insert(pair(key, value)); } pref_file.close(); return true; } /* * Save the preferences to a file * @param filename - the name of the file to save to */ bool FileBackedPreferences::SaveToFile(const string &filename) const { map::const_iterator iter; ofstream pref_file(filename.data()); if (!pref_file.is_open()) { OLA_INFO << "Missing " << filename << ": " << strerror(errno); return false; } for (iter = m_pref_map.begin(); iter != m_pref_map.end(); ++iter) { pref_file << iter->first << " = " << iter->second << std::endl; } pref_file.close(); return true; } /* * Change to the ola preferences directory */ bool FileBackedPreferences::ChangeDir() const { struct passwd pwd, *pwd_ptr; unsigned int size = 1024; bool ok = false; char *buffer; while (!ok) { buffer = new char[size]; int ret = getpwuid_r(getuid(), &pwd, buffer, size, &pwd_ptr); switch (ret) { case 0: ok = true; break; case ERANGE: delete[] buffer; size += 1024; break; default: delete[] buffer; return false; } } string home_dir = pwd_ptr->pw_dir; delete[] buffer; if (chdir(home_dir.data())) return false; if (chdir(OLA_CONFIG_DIR)) { // try and create it if (mkdir(OLA_CONFIG_DIR, 0755)) return false; if (chdir(OLA_CONFIG_DIR)) return false; } return true; } } // ola