summaryrefslogtreecommitdiffstats
path: root/src/service.cpp
diff options
context:
space:
mode:
authorMichal Kubecek <mkubecek@suse.cz>2015-04-13 09:21:39 +0200
committerMichal Kubecek <mkubecek@suse.cz>2015-04-13 09:21:39 +0200
commite2bc6f4153813cc570ae814c8ddb74628009b488 (patch)
treea40b171be1d859c2232ccc94f758010f9ae54d3c /src/service.cpp
downloadtwinkle-e2bc6f4153813cc570ae814c8ddb74628009b488.tar
twinkle-e2bc6f4153813cc570ae814c8ddb74628009b488.tar.gz
twinkle-e2bc6f4153813cc570ae814c8ddb74628009b488.tar.lz
twinkle-e2bc6f4153813cc570ae814c8ddb74628009b488.tar.xz
twinkle-e2bc6f4153813cc570ae814c8ddb74628009b488.zip
initial checkin
Check in contents of upstream 1.4.2 tarball, exclude generated files.
Diffstat (limited to 'src/service.cpp')
-rw-r--r--src/service.cpp400
1 files changed, 400 insertions, 0 deletions
diff --git a/src/service.cpp b/src/service.cpp
new file mode 100644
index 0000000..e292125
--- /dev/null
+++ b/src/service.cpp
@@ -0,0 +1,400 @@
+/*
+ Copyright (C) 2005-2009 Michel de Boer <michel@twinklephone.com>
+
+ 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <cassert>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fstream>
+#include <iostream>
+#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<t_display_url> &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<t_display_url> &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_display_url> t_service::get_cf_dest(t_cf_type cf_type) {
+ list<t_display_url> 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<string> 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<t_display_url>::iterator i = cf_always_dest.begin();
+ i != cf_always_dest.end(); i++)
+ {
+ config << FLD_CF_ALWAYS << '=' << i->encode() << endl;
+ }
+
+ for (list<t_display_url>::iterator i = cf_busy_dest.begin();
+ i != cf_busy_dest.end(); i++)
+ {
+ config << FLD_CF_BUSY << '=' << i->encode() << endl;
+ }
+
+ for (list<t_display_url>::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;
+}