presage  0.8.7
profileManager.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************
00003  *  Presage, an extensible predictive text entry system
00004  *  ---------------------------------------------------
00005  *
00006  *  Copyright (C) 2008  Matteo Vescovi <matteo.vescovi@yahoo.co.uk>
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License along
00019     with this program; if not, write to the Free Software Foundation, Inc.,
00020     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00021                                                                              *
00022                                                                 **********(*)*/
00023 
00024 
00025 #include "profileManager.h"
00026 #include "utility.h"        // isYes isNo isTrue isFalse utility function
00027 #include "dirs.h"                // sysconfdir macro define
00028 #include "configuration.h"
00029 
00030 #ifdef HAVE_PWD_H
00031 # include <pwd.h>
00032 #endif
00033 
00034 #if HAVE_UNISTD_H
00035 # include <sys/types.h>
00036 # include <unistd.h>
00037 #endif
00038 
00039 #if HAVE_STDLIB_H
00040 # include <stdlib.h>
00041 #endif
00042 
00043 #if defined(_WIN32)
00044 # include <windows.h>
00045 #endif
00046 
00047 const char* ProfileManager::LOGGER = "Presage.ProfileManager.LOGGER";
00048 const char* ProfileManager::AUTOPERSIST = "Presage.ProfileManager.AUTOPERSIST";
00049 
00055 ProfileManager::ProfileManager(const std::string profilename)
00056     : logger("ProfileManager", std::cerr)
00057 {
00058     config = new Configuration();
00059     loaded_at_least_one_profile = false;
00060     rw_profile = 0;
00061     autopersist_config = false;
00062 
00063     init_profiles (profilename);
00064 }
00065 
00066 
00070 ProfileManager::~ProfileManager()
00071 {
00072     flush_cached_log_messages ();
00073 
00074     set_autopersist (config->find (AUTOPERSIST)->get_value ());
00075     if (autopersist_config) {
00076         save_profile ();
00077     }
00078 
00079     delete config;
00080     delete rw_profile;
00081 }
00082 
00083 
00084 Profile* ProfileManager::create_profile_from_xml (const std::string& filename)
00085 {
00086     Profile* profile = new Profile (filename);
00087 
00088     std::string message;
00089     if (profile->file_read_ok ()) {
00090         // logger has not been init'd with configuration, because no
00091         // profile is known yet, hence caching this logging item,
00092         // which will be flushed when configuration is finally read in
00093         //
00094         message = "Loaded profile: " + filename;
00095           
00096         cache_log_message(logger.NOTICE, message);
00097                   
00098     } else {
00099         // logger has not been init'd with configuration, because no
00100         // profile is known yet, hence caching this logging item,
00101         // which will be flushed when configuration is finally read in
00102         //
00103         message = "Failed to load profile: " + filename;
00104           
00105         cache_log_message(logger.NOTICE, message);
00106 
00107     }
00108         
00109     return profile;
00110 }
00111 
00112 
00113 void ProfileManager::init_profiles (const std::string& profilename)
00114 {
00115     std::list<std::string> profiles;
00116 
00117     {
00118         // load default profile values
00119         DefaultProfile default_profile ("");
00120         default_profile.read_into_configuration (config);
00121     }
00122 
00123 
00124     // system etc directory
00125     profiles.push_back (get_system_etc_dir() + '/' + DefaultProfile::DEFAULT_PROFILE_FILENAME);
00126     // installation config directory
00127     profiles.push_back (static_cast<std::string>(sysconfdir) + '/' + DefaultProfile::DEFAULT_PROFILE_FILENAME);
00128     // home dir dotfile
00129     profiles.push_back (get_user_home_dir() + '/' + '.' + DefaultProfile::DEFAULT_PROFILE_FILENAME);
00130     // user specified profile (if any)
00131     if (! profilename.empty()) {
00132         profiles.push_back(profilename);
00133     }
00134 
00135 
00136     // read data from each profile and write it to configuration
00137     Profile* profile = 0;
00138     for (std::list<std::string>::const_iterator it = profiles.begin();
00139          it != profiles.end();
00140          it++ ) {
00141         delete profile;
00142         profile = create_profile_from_xml (*it);
00143         loaded_at_least_one_profile = loaded_at_least_one_profile || profile->file_read_ok ();
00144         profile->read_into_configuration (config);
00145     }
00146 
00147     // remember last profile as writable profile
00148     rw_profile = profile;
00149 }
00150 
00151 
00152 std::string ProfileManager::get_system_etc_dir() const
00153 {
00154      std::string result;
00155 
00156 #if defined(_WIN32)
00157      DWORD size;
00158      DWORD type;
00159      LONG res;
00160      HKEY reg_key = NULL;
00161      char *dst = NULL;
00162 
00163      res = RegOpenKeyExA (HKEY_CURRENT_USER, "Software", 0,
00164                           KEY_READ, &reg_key);
00165 
00166      if (res == ERROR_SUCCESS) {
00167           res = RegOpenKeyExA (reg_key, "Presage", 0,
00168                                KEY_READ, &reg_key);
00169      }
00170 
00171      if (res != ERROR_SUCCESS) {
00172           reg_key = (HKEY) INVALID_HANDLE_VALUE;
00173           return ".";
00174      }
00175   
00176 
00177      size = 64;
00178      dst = (char*) malloc (size);
00179   
00180      res = RegQueryValueExA (reg_key, "", 0, &type,
00181                              (LPBYTE) dst, &size);
00182      if (res == ERROR_MORE_DATA && type == REG_SZ) {
00183           dst = (char*) realloc (dst, size);
00184           res = RegQueryValueExA (reg_key, "", 0, &type,
00185                                   (LPBYTE) dst, &size);
00186      }
00187   
00188      if (type != REG_SZ || res != ERROR_SUCCESS) {
00189           free (dst);
00190           dst = 0;
00191      }
00192 
00193      result = dst;
00194      result += "\\etc";
00195      free (dst);
00196 #else
00197      result = "/etc";
00198 #endif
00199 
00200      return result;
00201 }
00202 
00203 
00204 std::string ProfileManager::get_user_home_dir() const
00205 {
00206     std::string result;
00207 
00208 #ifdef _WIN32
00209     const char* USERPROFILE = "USERPROFILE";
00210     char* value = getenv(USERPROFILE);
00211     // check if USERPROFILE env var exists...
00212     if (value) {
00213         result = value;
00214     }
00215 #else
00216 # ifdef HAVE_PWD_H
00217     uid_t me;
00218     struct passwd *my_passwd;
00219     
00220     me = getuid ();
00221     my_passwd = getpwuid (me);
00222     if (!my_passwd) {
00223         // got passwd for user
00224         // read home dir from passwd struct
00225         result = my_passwd->pw_dir;
00226     } else 
00227         // unable to get passwd struct,
00228         // read $HOME env variable
00229 # endif // HAVE_PWD_H
00230     {
00231         const char* HOME = "HOME";
00232         char* value = getenv(HOME);
00233         // check if HOME env var exists,
00234         // assigning a null pointer to a string is
00235         // not such a good idea...
00236         if (value) {
00237             result = value;
00238         }
00239     }
00240 #endif
00241 
00242     return result;
00243 }
00244 
00245 
00251 void ProfileManager::save_profile() const
00252 {
00253     rw_profile->read_from_configuration (config);
00254     bool saveOk = rw_profile->write_to_file ();
00255     if (! saveOk) {
00256         logger << ERROR << "Failed to save configuration to profile " << endl;
00257     }
00258 }
00259 
00260 Configuration* ProfileManager::get_configuration()
00261 {
00262     // since a Profile is being returned, we know we have a valid
00263     // configuration object. Here, we obtain a temporary Configuration
00264     // object to read the this ProfileManager configuration.  We could
00265     // not do this during profile manager construction because no
00266     // profile was available at that time.
00267     //
00268     refresh_config();
00269     return config;
00270 }
00271 
00272 void ProfileManager::cache_log_message(Logger<char>::Level level, const std::string& message)
00273 {
00274     static CachedLogMessage clm;
00275     //clm.level = level;
00276     clm.message = message;
00277     //std::cerr << "Caching message: " << message << std::endl;
00278     cached_log_messages.push_back(clm);
00279 }
00280 
00281 void ProfileManager::flush_cached_log_messages()
00282 {
00283     std::list<CachedLogMessage>::const_iterator it = cached_log_messages.begin();
00284     while (it != cached_log_messages.end()) {
00285         //std::cerr << "Flushing message: " << it->message << std::endl;
00286         logger << NOTICE << it->message << endl;
00287         it++;
00288     }
00289     cached_log_messages.clear();
00290 }
00291 
00292 void ProfileManager::refresh_config()
00293 {
00294     try {
00295         logger << setlevel(config->find (LOGGER)->get_value());
00296     } catch (Configuration::ConfigurationException& ex) {
00297         // if no config is available, turn on full logging for profile
00298         // manager
00299         logger << setlevel("ALL");
00300     }
00301 
00302     flush_cached_log_messages();
00303 }
00304 
00305 void ProfileManager::set_autopersist (const std::string& value)
00306 {
00307     autopersist_config = Utility::isTrue (value);
00308     logger << INFO << "AUTOPERSIST: " << autopersist_config << endl;
00309 }