/* Copyright (C) 2005-2009 Michel de Boer 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include "service.h" #include "log.h" #include "userintf.h" #include "util.h" #define FLD_CF_ALWAYS "cf_always" #define FLD_CF_BUSY "cf_busy" #define FLD_CF_NOANSWER "cf_noanswer" #define FLD_DND "dnd" #define FLD_AUTO_ANSWER "auto_answer" void t_service::lock() { mtx_service.lock(); } void t_service::unlock() { mtx_service.unlock(); } t_service::t_service(t_user *user) { user_config = user; // Call redirection cf_always_active = false; cf_busy_active = false; cf_noanswer_active = false; // Do not disturb dnd_active = false; // Auto answer auto_answer_active = false; string msg; (void)read_config(msg); } bool t_service::multiple_services_active(void) { int num_services = 0; if (is_cf_active()) num_services++; if (is_dnd_active()) num_services++; if (is_auto_answer_active()) num_services++; if (num_services > 1) return true; return false; } void t_service::enable_cf(t_cf_type cf_type, const list &cf_dest) { lock(); switch (cf_type) { case CF_ALWAYS: cf_always_active = true; cf_always_dest = cf_dest; break; case CF_BUSY: cf_busy_active = true; cf_busy_dest = cf_dest; break; case CF_NOANSWER: cf_noanswer_active = true; cf_noanswer_dest = cf_dest; break; default: assert(false); } unlock(); string msg; (void)write_config(msg); } void t_service::disable_cf(t_cf_type cf_type) { lock(); switch (cf_type) { case CF_ALWAYS: cf_always_active = false; cf_always_dest.clear(); break; case CF_BUSY: cf_busy_active = false; cf_busy_dest.clear(); break; case CF_NOANSWER: cf_noanswer_active = false; cf_noanswer_dest.clear(); break; default: assert(false); } unlock(); string msg; (void)write_config(msg); } bool t_service::get_cf_active(t_cf_type cf_type, list &dest) { bool active = false; lock(); switch (cf_type) { case CF_ALWAYS: active = cf_always_active; dest = cf_always_dest; break; case CF_BUSY: active = cf_busy_active; dest = cf_busy_dest; break; case CF_NOANSWER: active = cf_noanswer_active; dest = cf_noanswer_dest; break; default: assert(false); } unlock(); return active; } bool t_service::is_cf_active(void) { bool active = false; lock(); active = cf_always_active || cf_busy_active || cf_noanswer_active; unlock(); return active; } list t_service::get_cf_dest(t_cf_type cf_type) { list dest; lock(); switch (cf_type) { case CF_ALWAYS: dest = cf_always_dest; break; case CF_BUSY: dest = cf_busy_dest; break; case CF_NOANSWER: dest = cf_noanswer_dest; break; default: assert(false); } unlock(); return dest; } void t_service::enable_dnd(void) { lock(); dnd_active = true; unlock(); string msg; (void)write_config(msg); } void t_service::disable_dnd(void) { lock(); dnd_active = false; unlock(); string msg; (void)write_config(msg); } bool t_service::is_dnd_active(void) const { return dnd_active; } void t_service::enable_auto_answer(bool on) { lock(); auto_answer_active = on; unlock(); string msg; (void)write_config(msg); } bool t_service::is_auto_answer_active(void) const { return auto_answer_active; } bool t_service::read_config(string &error_msg) { struct stat stat_buf; lock(); string filename = user_config->get_profile_name() + SVC_FILE_EXT; string f = user_config->expand_filename(filename); // Check if config file exists if (stat(f.c_str(), &stat_buf) != 0) { unlock(); return true; } // Open file ifstream config(f.c_str()); if (!config) { error_msg = "Cannot open file for reading: "; error_msg += f; log_file->write_report(error_msg, "t_service::read_config", LOG_NORMAL, LOG_CRITICAL); unlock(); return false; } t_display_url display_url; cf_always_active = false; cf_always_dest.clear(); cf_busy_active = false; cf_busy_dest.clear(); cf_noanswer_active = false; cf_noanswer_dest.clear(); while (!config.eof()) { string line; getline(config, line); // Check if read operation succeeded if (!config.good() && !config.eof()) { error_msg = "File system error while reading file "; error_msg += f; log_file->write_report(error_msg, "t_service::read_config", LOG_NORMAL, LOG_CRITICAL); unlock(); return false; } line = trim(line); // Skip empty lines if (line.size() == 0) continue; // Skip comment lines if (line[0] == '#') continue; vector l = split_on_first(line, '='); if (l.size() != 2) { error_msg = "Syntax error in file "; error_msg += f; error_msg += "\n"; error_msg += line; log_file->write_report(error_msg, "t_service::read_config", LOG_NORMAL, LOG_CRITICAL); unlock(); return false; } string parameter = trim(l[0]); string value = trim(l[1]); if (parameter == FLD_CF_ALWAYS) { ui->expand_destination(user_config, value, display_url); if (display_url.is_valid()) { cf_always_active = true; cf_always_dest.push_back(display_url); } } else if (parameter == FLD_CF_BUSY) { ui->expand_destination(user_config, value, display_url); if (display_url.is_valid()) { cf_busy_active = true; cf_busy_dest.push_back(display_url); } } else if (parameter == FLD_CF_NOANSWER) { ui->expand_destination(user_config, value, display_url); if (display_url.is_valid()) { cf_noanswer_active = true; cf_noanswer_dest.push_back(display_url); } } else if (parameter == FLD_DND) { dnd_active = yesno2bool(value); } else if (parameter == FLD_AUTO_ANSWER) { auto_answer_active = yesno2bool(value); } else { // Ignore unknown parameters. Only report in log file. log_file->write_header("t_service::read_config", LOG_NORMAL, LOG_WARNING); log_file->write_raw("Unknown parameter in service config: "); log_file->write_raw(parameter); log_file->write_endl(); log_file->write_footer(); } } unlock(); return true; } bool t_service::write_config(string &error_msg) { struct stat stat_buf; lock(); string filename = user_config->get_profile_name() + SVC_FILE_EXT; string f = user_config->expand_filename(filename); // Make a backup of the file if we are editing an existing file, so // that can be restored when writing fails. string f_backup = f + '~'; if (stat(f.c_str(), &stat_buf) == 0) { if (rename(f.c_str(), f_backup.c_str()) != 0) { string err = get_error_str(errno); error_msg = "Failed to backup "; error_msg += f; error_msg += " to "; error_msg += f_backup; error_msg += "\n"; error_msg += err; log_file->write_report(error_msg, "t_service::write_config", LOG_NORMAL, LOG_CRITICAL); unlock(); return false; } } ofstream config(f.c_str()); if (!config) { error_msg = "Cannot open file for writing: "; error_msg += f; log_file->write_report(error_msg, "t_user::write_config", LOG_NORMAL, LOG_CRITICAL); unlock(); return false; } for (list::iterator i = cf_always_dest.begin(); i != cf_always_dest.end(); i++) { config << FLD_CF_ALWAYS << '=' << i->encode() << endl; } for (list::iterator i = cf_busy_dest.begin(); i != cf_busy_dest.end(); i++) { config << FLD_CF_BUSY << '=' << i->encode() << endl; } for (list::iterator i = cf_noanswer_dest.begin(); i != cf_noanswer_dest.end(); i++) { config << FLD_CF_NOANSWER << '=' << i->encode() << endl; } config << FLD_DND << '=' << bool2yesno(dnd_active) << endl; config << FLD_AUTO_ANSWER << '=' << bool2yesno(auto_answer_active) << endl; // Check if writing succeeded if (!config.good()) { // Restore backup config.close(); rename(f_backup.c_str(), f.c_str()); error_msg = "File system error while writing file "; error_msg += f; log_file->write_report(error_msg, "t_service::write_config", LOG_NORMAL, LOG_CRITICAL); unlock(); return false; } unlock(); return true; }