/* * vim: softtabstop=4 shiftwidth=4 cindent foldmethod=marker expandtab * * $LastChangedDate$ * $Revision$ * $LastChangedBy$ * $URL$ * * Copyright 2009-2011 Eric Connell * * This file is part of Mangler. * * Mangler 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 3 of the License, or * (at your option) any later version. * * Mangler 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 Mangler. If not, see . */ #include #include #include #include #include "mangler.h" #include "manglerconfig.h" #include #include "config.h" #include "manglerserverlist.h" #include #include #include // only needed for ConvertOldConfig #include // config directory, relative to $HOME #define CONFIG_DIRECTORY ".mangler" using namespace std; class ManglerConfigDir {/*{{{*/ public: static void dirInit(); static string filename(const string &name); private: static bool &initialized(); static string &confdir(); };/*}}}*/ bool &ManglerConfigDir::initialized() { static bool myInit( false ); return myInit; } string &ManglerConfigDir::confdir() { static string myString; return myString; } void ManglerConfigDir::dirInit() {/*{{{*/ string homedir = getenv("HOME"); if (! homedir.length() || homedir[homedir.length()-1] != '/') homedir += "/"; confdir() = homedir + CONFIG_DIRECTORY; if (confdir()[confdir().length()-1] == '/') confdir().erase(confdir().length()-1, confdir().npos); DIR *confDIR = ::opendir(confdir().c_str()); if (! confDIR) { if (::mkdir(confdir().c_str(), 0700)) { fprintf(stderr, "Unable to make directory '%s'\n", confdir().c_str()); fprintf(stderr, "No configuration settings can be saved.\n"); return; } } confdir() += "/"; initialized() = true; }/*}}}*/ string ManglerConfigDir::filename(const string &name) {/*{{{*/ if (! initialized()) dirInit(); return confdir() + name; }/*}}}*/ ManglerConfig::ManglerConfig() /*{{{*/ : config( ManglerConfigDir::filename("config.ini") ) , servers( ManglerConfigDir::filename("servers.ini") ) { // this is where we check to see if config.ini was loaded if (! config.contains("mangler")) { struct stat statbuf; string oldfile = getenv("HOME"); if (oldfile[oldfile.length()-1] != '/') oldfile += "/.manglerrc"; else oldfile += ".manglerrc"; if (stat(oldfile.c_str(), &statbuf) == 0) { ConvertOldConfig(); } else { istringstream sin( DefaultConfiguration ); config.load(sin); } save(); // should have something now!! config.reload(); servers.reload(); } }/*}}}*/ ManglerConfig::~ManglerConfig() {/*{{{*/ save(); // might as well :) }/*}}}*/ string ManglerConfig::confdir() {/*{{{*/ string confdir = getenv("HOME"); return confdir + "/" + CONFIG_DIRECTORY; }/*}}}*/ void ManglerConfig::ConvertOldConfig() {/*{{{*/ string buf; config.clear(); servers.clear(); istringstream sin( DefaultConfiguration ); config.load(sin); map serv_names; string oldconf = getenv("HOME"); if (! oldconf.length() || oldconf[oldconf.length() - 1] != '/') oldconf += "/"; oldconf += ".manglerrc"; ifstream fin( oldconf.c_str() ); if (! fin) { cerr << "unable to open old .manglerrc file for reading. can't convert." << endl; } for (int cnt = 1;;++cnt) { getline(fin, buf); if (fin.eof()) break; unsigned eq_pos = 0; while (eq_pos < buf.length() && buf[eq_pos] != '=') ++eq_pos; if (eq_pos == buf.length()) { cerr << "error parsing .manglerrc: line " << cnt << endl; continue; } string var = buf.substr(0, eq_pos); string val = buf.substr(eq_pos + 1, buf.npos); if (var.substr(0, 13) == "notification.") { var.erase(12, 1); var[0] = 'N'; var[12] = (char)toupper(var[12]); } else if (var.substr(0, 7) == "window.") { if (var.substr(7, 5) == "width" || var.substr(7, 6) == "height") { var.erase(6, 1); var[0] = 'W'; var[6] = (char)toupper(var[6]); } else { var.erase(0, 7); var[0] = (char)toupper(var[0]); } } else if (var.substr(0, 11) == "serverlist.") { int serv_id = 0; string serv_var = ""; unsigned i = 11; while (i < var.length() && var[i] != '.') ++i; if (i == var.length()) { cerr << "error parsing .manglerrc: line " << cnt << ": serverlist entry without id" << endl; continue; } serv_id = atoi(var.substr(11, i - 11).c_str()); serv_var = var.substr(i+1, var.npos); if (! serv_var.length()) { cerr << "error parsing .manglerrc: line " << cnt << ": serverlist line looks mangled ;)" << endl; continue; } if (serv_var == "name") { serv_names[serv_id] = val; continue; } else if (serv_var == "accept_u2u") { serv_var = "AcceptU2U"; } else if (serv_var == "accept_pages") { serv_var = "AcceptPages"; } else if (serv_var == "accept_privchat") { serv_var = "AcceptPrivateChat"; } else if (serv_var == "allow_recording") { serv_var = "AllowRecording"; } else if (serv_var == "persistent_connection") { serv_var = "PersistentConnection"; } else if (serv_var == "persistent_comments") { serv_var = "PersistentComments"; } else if (serv_var == "motdhash") { serv_var = "MotdHash"; } else if (serv_var == "defaultchannelid") { serv_var = "DefaultChannel"; } else if (serv_var == "defaultchannel") { continue; } else if (serv_var.substr(0, 7) == "volume.") { string vol_usr = serv_var.substr(7, serv_var.npos); serv_var = "UserVolume[" + vol_usr + "]"; } else if (serv_var.substr(0, 12) == "channelpass.") { string chan_pass = serv_var.substr(12, serv_var.npos); serv_var = "ChannelPassword[" + chan_pass + "]"; } else { serv_var[0] = (char)toupper(serv_var[0]); } string serv_name = serv_names[serv_id]; if (serv_name.length()) { servers[serv_name][serv_var] = val; continue; } else { cerr << "error parsing .manglerrc: line " << cnt << ": unknown server id" << endl; continue; } } else if (var.substr(0, 13) != "qc_lastserver" && var.substr(0, 14) != "lv3_debuglevel") { var[0] = (char)toupper(var[0]); } // if we get here, it's a main config option config["mangler"][var] = val; } fin.close(); int lcs_id = config["mangler"]["LastConnectedServerID"].toInt(); string lcs_name = serv_names[lcs_id]; config["mangler"]["LastConnectedServerName"] = lcs_name; config["mangler"].erase("LastConnectedServerID"); }/*}}}*/ void ManglerConfig::save() {/*{{{*/ //mutex.lock(); config.save(); servers.save(); //mutex.unlock(); }/*}}}*/ std::vector ManglerConfig::PushToTalkXKeyCodes() const {/*{{{*/ int begin = 0; uint32_t ctr; GdkWindow *rootwin = gdk_get_default_root_window(); vector ret; if (! config.contains("mangler") || ! config.at("mangler").contains("PushToTalkKeyValue")) return ret; Glib::ustring pttString = config.at("mangler").at("PushToTalkKeyValue").toUString(); Glib::ustring keyname; for (ctr = 0; ctr < pttString.length(); ctr++) { if (pttString[ctr] == '+') { keyname = pttString.substr(begin, ctr-begin); begin = ctr+1; if (keyname[0] == '<' && keyname[keyname.length()-1] == '>') { keyname = keyname.substr(1, keyname.length() - 2); } int keycode = XKeysymToKeycode(GDK_WINDOW_XDISPLAY(rootwin), XStringToKeysym(keyname.c_str())); ret.push_back(keycode); } } keyname = pttString.substr(begin, ctr-begin); if (keyname[0] == '<' && keyname[keyname.length()-1] == '>') { keyname = keyname.substr(1, keyname.length() - 2); } int keycode = XKeysymToKeycode(GDK_WINDOW_XDISPLAY(rootwin), XStringToKeysym(keyname.c_str())); ret.push_back(keycode); return ret; }/*}}}*/ iniValue &ManglerConfig::operator[](const string &configVar) {/*{{{*/ return config["mangler"][configVar]; }/*}}}*/ bool ManglerConfig::hasUserVolume(const string &server, const string &user) const {/*{{{*/ string varname = string( "UserVolume[" ) + user + string( "]" ); return servers.contains(server) && servers.at(server).contains(varname); }/*}}}*/ iniValue &ManglerConfig::UserVolume(const string &server, const string &user) {/*{{{*/ string varname = string( "UserVolume[" ) + user + string( "]" ); return servers[server][varname]; }/*}}}*/ bool ManglerConfig::hasUserMuted(const string &server, const string &user) const {/*{{{*/ string varname = string( "UserMuted[" ) + user + string( "]" ); return servers.contains(server) && servers.at(server).contains(varname); }/*}}}*/ iniValue &ManglerConfig::UserMuted(const string &server, const string &user) {/*{{{*/ string varname = string( "UserMuted[" ) + user + string( "]" ); return servers[server][varname]; }/*}}}*/ iniValue &ManglerConfig::ChannelPassword(const string &server, uint16_t channel) {/*{{{*/ string varname = string( "ChannelPassword[" ) + iniVariant( channel ).toString() + string( "]" ); return servers[server][varname]; }/*}}}*/ const char *ManglerConfig::DefaultConfiguration = "[mangler]\n" "PushToTalkKeyEnabled=0\n" "PushToTalkKeyValue=\n" "PushToTalkMouseEnabled=0\n" "PushToTalkMouseValue=\n" "AudioIntegrationEnabled=0\n" "AudioIntegrationPlayer=0\n" "VoiceActivationEnabled=0\n" "VoiceActivationSilenceDuration=2000\n" "VoiceActivationSensitivity=25\n" "InputDeviceName=\n" "InputDeviceCustomName=\n" "OutputDeviceName=\n" "OutputDeviceCustomName=\n" "NotificationDeviceName=\n" "NotificationDeviceCustomName=\n" "NotificationLoginLogout=1\n" "NotificationChannelEnterLeave=1\n" "NotificationTransmitStartStop=1\n" "NotificationTextToSpeech=1\n" "MouseDeviceName=\n" #ifdef HAVE_PULSE "AudioSubsystem=pulse\n" #elif HAVE_ALSA "AudioSubsystem=alsa\n" #elif HAVE_OSS "AudioSubsystem=oss\n" #endif "qc_lastserver.hostname=\n" "qc_lastserver.port=\n" "qc_lastserver.username=\n" "qc_lastserver.password=\n" "LastConnectedServerId=0\n" "lv3_debuglevel=0\n" "MasterVolumeLevel=79\n" "InputGainLevel=79\n" "WindowWidth=400\n" "WindowHeight=525\n" "ButtonsHidden=0\n" "ServerInfoHidden=0\n" "GuestFlagHidden=0\n" "ChatTimestamps=1\n";