diff --git a/daemon/src/config/config.cpp b/daemon/src/config/config.cpp index bd3818d857eb3b499585cd96b9de8d19cb3ca02b..ede267907559fa27e38e08d79d5c61039b6a01a7 100644 --- a/daemon/src/config/config.cpp +++ b/daemon/src/config/config.cpp @@ -43,16 +43,7 @@ namespace Conf { ConfigTree::~ConfigTree() -{ - // erase every new ItemMap (by CreateSection) - SectionMap::iterator iter = sections_.begin(); - - while (iter != sections_.end()) { - delete iter->second; - iter->second = NULL; - iter++; - } -} +{} void ConfigTree::addDefaultValue(const std::pair<std::string, std::string>& token, std::string section) { @@ -81,7 +72,7 @@ ConfigTree::createSection(const std::string& section) { // if we doesn't find the item, create it if (sections_.find(section) == sections_.end()) - sections_[section] = new ItemMap; + sections_[section] = ItemMap(); } /** @@ -98,18 +89,13 @@ ConfigTree::removeSection(const std::string& section) } /** Retrieve the sections as an array */ -TokenList +std::list<std::string> ConfigTree::getSections() { - TokenList sections; - - SectionMap::iterator iter = sections_.begin(); + std::list<std::string> sections; - while (iter != sections_.end()) { - // add to token list the: iter->second; + for (SectionMap::iterator iter = sections_.begin(); iter != sections_.end(); ++iter) sections.push_back(iter->first); - iter++; - } return sections; } @@ -125,7 +111,7 @@ ConfigTree::addConfigTreeItem(const std::string& section, const ConfigTreeItem i SectionMap::iterator iter = sections_.find(section); if (iter == sections_.end()) { - sections_[section] = new ItemMap; + sections_[section] = ItemMap(); iter = sections_.find(section); } @@ -133,9 +119,8 @@ ConfigTree::addConfigTreeItem(const std::string& section, const ConfigTreeItem i if (iter != sections_.end()) { std::string name(item.getName()); - if (iter->second->find(name) == iter->second->end()) { - (*(iter->second))[name] = item; - } + if (iter->second.find(name) == iter->second.end()) + iter->second[name] = item; } } @@ -163,17 +148,11 @@ ConfigTree::getConfigTreeItemIntValue(const std::string& section, const std::str bool ConfigTree::getConfigTreeItemBoolValue(const std::string& section, const std::string& itemName) const { - std::string configItem = getConfigTreeItemValue(section, itemName); - - if (configItem == "true") { - return true; - } - - return false; + return getConfigTreeItemValue(section, itemName) == "true"; } bool -ConfigTree::getConfigTreeItemToken(const std::string& section, const std::string& itemName, TokenList& arg) const +ConfigTree::getConfigTreeItemToken(const std::string& section, const std::string& itemName, std::list<std::string>& arg) const { const ConfigTreeItem *item = getConfigTreeItem(section, itemName); @@ -186,8 +165,8 @@ ConfigTree::getConfigTreeItemToken(const std::string& section, const std::string arg.push_back(item->getDefaultValue()); return true; } - - return false; + else + return false; } /** @@ -201,9 +180,9 @@ ConfigTree::getConfigTreeItem(const std::string& section, const std::string& ite if (iter == sections_.end()) return NULL; - ItemMap::const_iterator iterItem = iter->second->find(itemName); + ItemMap::const_iterator iterItem = iter->second.find(itemName); - if (iterItem == iter->second->end()) + if (iterItem == iter->second.end()) return NULL; return & (iterItem->second); @@ -220,18 +199,17 @@ ConfigTree::setConfigTreeItem(const std::string& section, const std::string& itemName, const std::string& value) { - SectionMap::iterator iter = sections_.find(section); if (iter == sections_.end()) { // Not found, create section - sections_[section] = new ItemMap; + sections_[section] = ItemMap(); iter = sections_.find(section); } - ItemMap::iterator iterItem = iter->second->find(itemName); + ItemMap::iterator iterItem = iter->second.find(itemName); - if (iterItem == iter->second->end()) { + if (iterItem == iter->second.end()) { // If not found, search in our default list to find // something that would fit. std::string defaultValue = getDefaultValue(itemName); @@ -240,13 +218,12 @@ ConfigTree::setConfigTreeItem(const std::string& section, } // Use default value if the value is empty. - if (value.empty() == true) { + if (value.empty()) { iterItem->second.setValue(getDefaultValue(itemName)); return true; } iterItem->second.setValue(value); - return true; } @@ -254,7 +231,7 @@ ConfigTree::setConfigTreeItem(const std::string& section, // return false if empty, no config, or enable to open // return true if everything is ok bool -ConfigTree::saveConfigTree(const std::string& fileName) +ConfigTree::saveConfigTree(const std::string& fileName) const { DEBUG("ConfigTree: Save %s", fileName.c_str()); @@ -271,20 +248,12 @@ ConfigTree::saveConfigTree(const std::string& fileName) } // for each section, for each item... - SectionMap::iterator iter = sections_.begin(); - - while (iter != sections_.end()) { + for (SectionMap::const_iterator iter = sections_.begin(); iter != sections_.end(); ++iter) { file << "[" << iter->first << "]" << std::endl; - ItemMap::iterator iterItem = iter->second->begin(); - - while (iterItem != iter->second->end()) { + for (ItemMap::const_iterator iterItem = iter->second.begin(); iterItem != iter->second.end(); ++iterItem) file << iterItem->first << "=" << iterItem->second.getValue() << std::endl; - iterItem++; - } file << std::endl; - - iter++; } file.close(); @@ -335,10 +304,9 @@ ConfigTree::populateFromFile(const std::string& fileName) } std::string line; - - std::string section(""); - std::string key(""); - std::string val(""); + std::string section; + std::string key; + std::string val; std::string::size_type pos; while (!file.eof()) { @@ -371,16 +339,16 @@ ConfigTree::populateFromFile(const std::string& fileName) return 1; } -TokenList -ConfigTreeIterator::begin() +std::list<std::string> +ConfigTreeIterator::begin() const { - TokenList tk; + std::list<std::string> tk; iter_ = tree_->sections_.begin(); - if (iter_!=tree_->sections_.end()) { - iterItem_ = iter_->second->begin(); + if (iter_ != tree_->sections_.end()) { + iterItem_ = iter_->second.begin(); - if (iterItem_!=iter_->second->end()) { + if (iterItem_ != iter_->second.end()) { tk.push_back(iter_->first); tk.push_back(iterItem_->first); tk.push_back(iterItem_->second.getType()); @@ -392,26 +360,26 @@ ConfigTreeIterator::begin() return tk; } -TokenList +std::list<std::string> ConfigTreeIterator::next() { - TokenList tk; + std::list<std::string> tk; // we return tk empty if we are at the end of the list... if (iter_ == tree_->sections_.end()) return tk; - if (iterItem_ != iter_->second->end()) + if (iterItem_ != iter_->second.end()) iterItem_++; - if (iterItem_ == iter_->second->end()) { + if (iterItem_ == iter_->second.end()) { // if we increment, and we are at the end of a section iter_++; if (iter_ != tree_->sections_.end()) { - iterItem_ = iter_->second->begin(); + iterItem_ = iter_->second.begin(); - if (iterItem_ != iter_->second->end()) { + if (iterItem_ != iter_->second.end()) { tk.push_back(iter_->first); tk.push_back(iterItem_->first); tk.push_back(iterItem_->second.getType()); diff --git a/daemon/src/config/config.h b/daemon/src/config/config.h index b91dd819c154dbce27251e7c5a10fc7a895d3be1..aff39f99a759c120a0f00c9411436b84a048ff91 100644 --- a/daemon/src/config/config.h +++ b/daemon/src/config/config.h @@ -47,8 +47,7 @@ static const char * const TRUE_STR = "true"; class ConfigTreeItem; typedef std::map<std::string, ConfigTreeItem> ItemMap; -typedef std::map<std::string, ItemMap*> SectionMap; -typedef std::list<std::string> TokenList; +typedef std::map<std::string, ItemMap> SectionMap; class ConfigTreeItemException { }; @@ -58,25 +57,13 @@ class ConfigTree; class ConfigTreeIterator { public: - /** - * Parsing method - * @return TokenList - */ - TokenList begin(); + std::list<std::string> begin() const; - /** - * Parsing method - * @return TokenList - */ - const TokenList& end() const { + const std::list<std::string> & end() const { return endToken_; } - /** - * Parsing method - * @return TokenList - */ - TokenList next(); + std::list<std::string> next(); private: friend class ConfigTree; @@ -85,9 +72,9 @@ class ConfigTreeIterator { NON_COPYABLE(ConfigTreeIterator); ConfigTree* tree_; - TokenList endToken_; - SectionMap::iterator iter_; - ItemMap::iterator iterItem_; + std::list<std::string> endToken_; + mutable SectionMap::iterator iter_; + mutable ItemMap::iterator iterItem_; }; class ConfigTree { @@ -118,7 +105,7 @@ class ConfigTree { * * @return array Strings of the sections */ - TokenList getSections(); + std::list<std::string> getSections(); void addConfigTreeItem(const std::string& section, const ConfigTreeItem item); /** @@ -149,14 +136,14 @@ class ConfigTree { /** * Flush data to .ini file */ - bool saveConfigTree(const std::string& fileName); + bool saveConfigTree(const std::string& fileName) const; /** * Load data (and fill ConfigTree) from disk */ int populateFromFile(const std::string& fileName); - bool getConfigTreeItemToken(const std::string& section, const std::string& itemName, TokenList& arg) const; + bool getConfigTreeItemToken(const std::string& section, const std::string& itemName, std::list<std::string>& arg) const; private: std::string getDefaultValue(const std::string& key) const; @@ -196,19 +183,19 @@ class ConfigTreeItem { value_ = value; } - const std::string getName() const { + std::string getName() const { return name_; } - const std::string getValue() const { + std::string getValue() const { return value_; } - const std::string getDefaultValue() const { + std::string getDefaultValue() const { return defaultValue_; } - const std::string getType() const { + std::string getType() const { return type_; } diff --git a/daemon/src/dbus/configurationmanager-introspec.xml b/daemon/src/dbus/configurationmanager-introspec.xml index 13f666940b39300c39b405ac4abe3ff7ce1e0aa0..6271c12c9d3cedfc8f6c286d7d199b5b51e1e386 100644 --- a/daemon/src/dbus/configurationmanager-introspec.xml +++ b/daemon/src/dbus/configurationmanager-introspec.xml @@ -258,7 +258,7 @@ </tp:docstring> </arg> </method> - + <method name="getIsAlwaysRecording" tp:name-for-bindings="getIsAlwaysRecording"> <tp:docstring> </tp:docstring> @@ -333,7 +333,6 @@ </arg> </method> - <!-- Audio devices methods --> <method name="getAudioPluginList" tp:name-for-bindings="getAudioPluginList"> @@ -457,7 +456,7 @@ </tp:docstring> </arg> </method> - + <method name="getEchoCancelTailLength" tp:name-for-bindings="getEchoCancelTailLength"> <tp:docstring> </tp:docstring> @@ -466,22 +465,22 @@ </tp:docstring> </arg> </method> - + <method name="setEchoCancelDelay" tp:name-for-bindings="setEchoCancelDelay"> <tp:docstring> </tp:docstring> <arg type="i" name="index" direction="in"> </arg> - </method> - + </method> + <method name="getEchoCancelDelay" tp:name-for-bindings="getEchoCancelDelay"> <tp:docstring> </tp:docstring> <arg type="i" name="index" direction="out"> </arg> </method> - - + + <method name="getNoiseSuppressState" tp:name-for-bindings="getEchoCancelState"> <tp:docstring> </tp:docstring> @@ -521,7 +520,6 @@ </arg> </method> - <method name="getHistoryLimit" tp:name-for-bindings="getHistoryLimit"> <tp:docstring> </tp:docstring> @@ -603,35 +601,27 @@ </arg> </method> - <method name="getHistory" tp:name-for-bindings="getHistory"> - <tp:docstring> - </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MapStringString"/> - <arg type="as" name="entries" direction="out"> - <tp:docstring> - </tp:docstring> - </arg> + <method name="getHistory" tp:name-for-bindings="getHistory"> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/> + <!-- Return a List of type Dict<string, string> >...a List of Dicts --> + <arg type="aa{ss}" name="entries" direction="out"/> </method> <method name="setHistory" tp:name-for-bindings="setHistory"> - <tp:docstring> - </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MapStringString"/> - <arg type="as" name="entries" direction="in"> - <tp:docstring> - </tp:docstring> + <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="VectorMapStringString"/> + <arg type="aa{ss}" name="entries" direction="in"> </arg> </method> <signal name="accountsChanged" tp:name-for-bindings="accountsChanged"> - </signal> + </signal> <signal name="errorAlert" tp:name-for-bindings="errorAlert"> <arg type="i" name="code"> <tp:docstring> </tp:docstring> </arg> - </signal> + </signal> <!-- TLS Methods --> <method name="getSupportedTlsMethod" tp:name-for-bindings="getSupportedTlsMethod"> diff --git a/daemon/src/dbus/configurationmanager.cpp b/daemon/src/dbus/configurationmanager.cpp index 056b819de1217eb56fa71529a33e9046bfc8b8fd..aec8f5e881e48f1e6e088ee1bca06f6dd5c026cf 100644 --- a/daemon/src/dbus/configurationmanager.cpp +++ b/daemon/src/dbus/configurationmanager.cpp @@ -398,18 +398,18 @@ void ConfigurationManager::setAccountsOrder(const std::string& order) Manager::instance().setAccountsOrder(order); } -std::vector<std::string> ConfigurationManager::getHistory() +std::vector<std::map<std::string, std::string> > ConfigurationManager::getHistory() { - return Manager::instance().getHistorySerialized(); + return Manager::instance().getHistory(); } -void ConfigurationManager::setHistory(const std::vector<std::string>& entries) +void ConfigurationManager::setHistory(const std::vector<std::map<std::string, std::string> > &entries) { Manager::instance().setHistorySerialized(entries); } -std::string ConfigurationManager::getAddrFromInterfaceName( - const std::string& interface) +std::string +ConfigurationManager::getAddrFromInterfaceName(const std::string& interface) { return SIPVoIPLink::getInterfaceAddrFromName(interface); } diff --git a/daemon/src/dbus/configurationmanager.h b/daemon/src/dbus/configurationmanager.h index f3e03670176e22a0a86fdda460b9f2c3aa562512..9264c886bc12ff6334d58ef4ddfcbaec0030fc9c 100644 --- a/daemon/src/dbus/configurationmanager.h +++ b/daemon/src/dbus/configurationmanager.h @@ -123,8 +123,8 @@ class ConfigurationManager : std::map<std::string, std::string> getHookSettings(); void setHookSettings(const std::map<std::string, std::string>& settings); - std::vector<std::string> getHistory(); - void setHistory(const std::vector<std::string> &entries); + std::vector<std::map<std::string, std::string> > getHistory(); + void setHistory(const std::vector<std::map<std::string, std::string> > &entries); std::map<std::string, std::string> getTlsSettings(); void setTlsSettings(const std::map< std::string, std::string >& details); diff --git a/daemon/src/history/historyitem.cpp b/daemon/src/history/historyitem.cpp index 738c7cf4a441b9d64e175c79d24b9b82c659a3d6..a0edd4b34d9a21eb31b649f56d6a6595aab94be3 100644 --- a/daemon/src/history/historyitem.cpp +++ b/daemon/src/history/historyitem.cpp @@ -33,127 +33,76 @@ #include "historyitem.h" #include <sstream> #include <cstdlib> -#include "manager.h" - -static const char * const ITEM_SEPARATOR = "|"; - -HistoryItem::HistoryItem(const std::string ×tamp_start, - CallType call_type, const std::string ×tamp_stop, - const std::string &name, const std::string &number, - const std::string &id, const std::string &account_id, - const std::string &recording, - const std::string &confID, - const std::string &timeAdded) - : timestamp_start_(timestamp_start), - timestamp_stop_(timestamp_stop), - call_type_(call_type), - name_(name), - number_(number), - id_(id), - account_id_(account_id), - recording_file_(recording), - confID_(confID), - timeAdded_(timeAdded) +#include "config/config.h" + +const char * const HistoryItem::ACCOUNT_ID_KEY = "accountid"; +const char * const HistoryItem::CALLID_KEY = "callid"; +const char * const HistoryItem::CONFID_KEY = "confid"; +const char * const HistoryItem::PEER_NAME_KEY = "peer_name"; +const char * const HistoryItem::PEER_NUMBER_KEY = "peer_number"; +const char * const HistoryItem::RECORDING_PATH_KEY = "recordfile"; +const char * const HistoryItem::TIMESTAMP_START_KEY = "timestamp_start"; +const char * const HistoryItem::TIMESTAMP_STOP_KEY = "timestamp_stop"; +const char * const HistoryItem::STATE_KEY = "state"; +const char * const HistoryItem::MISSED_STRING = "missed"; +const char * const HistoryItem::INCOMING_STRING = "incoming"; +const char * const HistoryItem::OUTGOING_STRING = "outgoing"; + +HistoryItem::HistoryItem(const std::map<std::string, std::string> &args) + : entryMap_(args) {} - -HistoryItem::HistoryItem(std::string serialized_form) : - timestamp_start_(), timestamp_stop_(), call_type_(CALL_MISSED), name_(), - number_(), id_(), account_id_(), recording_file_(), confID_(), timeAdded_() +HistoryItem::HistoryItem(const std::string &item, Conf::ConfigTree &historyList) + : entryMap_() { - for (int index = 0; serialized_form.find(ITEM_SEPARATOR, 0) != std::string::npos; ++index) { - size_t pos = serialized_form.find(ITEM_SEPARATOR, 0); - std::string tmp(serialized_form.substr(0, pos)); - serialized_form.erase(0, pos + 1); - - switch (index) { - case 0: // The call type - call_type_ = (CallType) atoi(tmp.c_str()); - break; - case 1: // The number field - number_ = tmp; - break; - case 2: // The name field - name_ = tmp; - - if (name_ == "empty") - name_ = ""; - break; - case 3: // The start timestamp - timestamp_start_ = tmp; - break; - case 4: // The end timestamp - timestamp_stop_ = tmp; - break; - case 5: // The ID - id_ = tmp; - break; - case 6: // The account ID - account_id_ = tmp; - break; - case 7: // The recorded file name - recording_file_ = tmp; - break; - case 8: // The conference ID - confID_ = tmp; - break; - case 9: // the time - timeAdded_ = tmp; - break; - default: // error - ERROR("Unserialized form %d not recognized\n", index); - break; - } - } + const char *const KEYS [] = { + ACCOUNT_ID_KEY, + CALLID_KEY, + CONFID_KEY, + PEER_NAME_KEY, + PEER_NUMBER_KEY, + RECORDING_PATH_KEY, + TIMESTAMP_START_KEY, + TIMESTAMP_STOP_KEY, + STATE_KEY, + NULL}; + for (int i = 0; KEYS[i]; ++i) + entryMap_[KEYS[i]] = historyList.getConfigTreeItemValue(item, KEYS[i]); } -bool HistoryItem::save(Conf::ConfigTree **history) +void HistoryItem::save(Conf::ConfigTree &history) const { + // The section is : "[" + random integer = "]" std::stringstream section; - std::stringstream call_type; - - // The section is : "[" + timestamp = "]" section << rand(); - std::string sectionstr = section.str(); - call_type << call_type_; + const std::string sectionstr = section.str(); - return (*history)->setConfigTreeItem(sectionstr, "type", call_type.str()) - && (*history)->setConfigTreeItem(sectionstr, "timestamp_start", timestamp_start_) - && (*history)->setConfigTreeItem(sectionstr, "timestamp_stop", timestamp_stop_) - && (*history)->setConfigTreeItem(sectionstr, "number", number_) - && (*history)->setConfigTreeItem(sectionstr, "id", id_) - && (*history)->setConfigTreeItem(sectionstr, "accountid", account_id_) - && (*history)->setConfigTreeItem(sectionstr, "name", name_) - && (*history)->setConfigTreeItem(sectionstr, "recordfile", recording_file_) - && (*history)->setConfigTreeItem(sectionstr, "confid", confID_) - && (*history)->setConfigTreeItem(sectionstr, "timeadded", timeAdded_); + typedef std::map<std::string, std::string>::const_iterator EntryIter; + for (EntryIter iter = entryMap_.begin(); iter != entryMap_.end(); ++iter) + history.setConfigTreeItem(sectionstr, iter->first, iter->second); } -std::string HistoryItem::serialize() const +std::map<std::string, std::string> HistoryItem::toMap() const { - // Replace empty string with a valid standard string value - std::string name(name_); - - if (name.empty()) - name = "empty"; - - // For the account ID, check also if the accountID corresponds to an existing account - // ie the account may have been removed - std::string accountID(account_id_); - - if (account_id_.empty() or not valid_account(account_id_)) - accountID = "empty"; - - std::stringstream res; - // Serialize it - res << call_type_ << ITEM_SEPARATOR << number_ << ITEM_SEPARATOR << name << ITEM_SEPARATOR << timestamp_start_ << ITEM_SEPARATOR << timestamp_stop_ - << ITEM_SEPARATOR << id_ << ITEM_SEPARATOR << accountID << ITEM_SEPARATOR << recording_file_ << ITEM_SEPARATOR << confID_ << ITEM_SEPARATOR << timeAdded_; - - return res.str(); + return entryMap_; } +bool HistoryItem::youngerThan(int otherTime) const +{ + return atol(getTimestampStart().c_str()) >= otherTime; +} -bool HistoryItem::valid_account(const std::string &id) const +bool HistoryItem::hasPeerNumber() const { - return Manager::instance().accountExists(id); + return entryMap_.find(PEER_NUMBER_KEY) != entryMap_.end(); +} + +std::string HistoryItem::getTimestampStart() const { + using std::map; + using std::string; + map<string, string>::const_iterator iter(entryMap_.find(TIMESTAMP_START_KEY)); + if (iter != entryMap_.end()) + return iter->second; + else + return ""; } diff --git a/daemon/src/history/historyitem.h b/daemon/src/history/historyitem.h index 5fb240d6f6ed2fc2f3e99e7afaa198f8fc70e8de..c134e46f18c4763c785d5178c601738856896506 100644 --- a/daemon/src/history/historyitem.h +++ b/daemon/src/history/historyitem.h @@ -34,101 +34,41 @@ #define HISTORY_ITEM_H_ #include <string> - -typedef enum CallType { - CALL_MISSED, - CALL_INCOMING, - CALL_OUTGOING -} CallType; +#include <map> namespace Conf { class ConfigTree; } class HistoryItem { - public: - /* - * Constructor - * - * @param Timestamp start - * @param Call type - * @param Timestamp stop - * @param Call name - * @param Call number - * @param Call id - * @param Call account id - * @param Recording file name (if any recording were performed) - * @param Configuration ID - * @param time added - */ - HistoryItem(const std::string&, CallType, const std::string&, - const std::string&, const std::string&, const std::string&, - const std::string&, const std::string&, const std::string&, - const std::string&); - - /* - * Constructor from a serialized form - * @string contaning serialized form - */ - HistoryItem(std::string=""); + static const char * const ACCOUNT_ID_KEY; + static const char * const CONFID_KEY; + static const char * const CALLID_KEY; + static const char * const PEER_NAME_KEY; + static const char * const PEER_NUMBER_KEY; + static const char * const RECORDING_PATH_KEY; + static const char * const TIMESTAMP_START_KEY; + static const char * const TIMESTAMP_STOP_KEY; + static const char * const STATE_KEY; - std::string get_timestamp() const { - return timestamp_start_; - } + static const char * const MISSED_STRING; + static const char * const INCOMING_STRING; + static const char * const OUTGOING_STRING; + HistoryItem(const std::map<std::string, std::string> &args); + HistoryItem(const std::string &item, Conf::ConfigTree &list); - bool save(Conf::ConfigTree **history); - - std::string serialize() const; - - private: - /* - * @return true if the account ID corresponds to a loaded account - */ - bool valid_account(const std::string &id) const; + bool hasPeerNumber() const; - /* - * Timestamp representing the date of the call - */ - std::string timestamp_start_; - std::string timestamp_stop_; + bool youngerThan(int otherTime) const; - /* - * Represents the type of call - * Has be either CALL_MISSED, CALL_INCOMING or CALL_OUTGOING - */ - CallType call_type_; + void save(Conf::ConfigTree &history) const; - /* - * The information about the callee/caller, depending on the type of call. - */ - std::string name_; - std::string number_; + std::map<std::string, std::string> toMap() const; - /** - * The identifier fo this item - */ - std::string id_; - - /* - * The account the call was made with - */ - std::string account_id_; - - /** - * Whether or not a recording exist for this call - */ - std::string recording_file_; - - /** - * The conference ID for this call (if any) - */ - std::string confID_; - - /** - * Time added to conference - */ - std::string timeAdded_; + private: + std::string getTimestampStart() const; + std::map<std::string, std::string> entryMap_; }; diff --git a/daemon/src/history/historymanager.cpp b/daemon/src/history/historymanager.cpp index d19df319dd29f4453475c4a869bc240f57672aed..46966cc504fc6c66becdd87b6b5d630ee646030e 100644 --- a/daemon/src/history/historymanager.cpp +++ b/daemon/src/history/historymanager.cpp @@ -37,7 +37,8 @@ #include "config/config.h" namespace { - int get_unix_timestamp_equivalent(int days) { + int get_unix_timestamp_equivalent(int days) + { // Number of seconds in one day: 60 x 60 x 24 static const int DAY_UNIX_TIMESTAMP = 86400; return days * DAY_UNIX_TIMESTAMP; @@ -48,59 +49,46 @@ HistoryManager::HistoryManager() : history_items_(), history_loaded_(false), history_path_("") {} -int HistoryManager::load_history(int limit, const std::string &path) +int HistoryManager::loadHistory(int limit, const std::string &path) { - Conf::ConfigTree history_list; - create_history_path(path); - load_history_from_file(&history_list); - return load_history_items_map(&history_list, limit); + Conf::ConfigTree historyList; + createHistoryPath(path); + loadHistoryFromFile(historyList); + return loadHistoryItemsMap(historyList, limit); } -bool HistoryManager::save_history() +bool HistoryManager::saveHistory() { - Conf::ConfigTree history_list; - save_history_items_map(&history_list); - return save_history_to_file(&history_list); + Conf::ConfigTree historyList; + saveHistoryItemsVector(historyList); + return saveHistoryToFile(historyList); } -bool HistoryManager::load_history_from_file(Conf::ConfigTree *history_list) +bool HistoryManager::loadHistoryFromFile(Conf::ConfigTree &historyList) { - DEBUG("HistoryManager: Load history from file %s", history_path_.c_str()); - - int exist = history_list->populateFromFile(history_path_.c_str()); + int exist = historyList.populateFromFile(history_path_.c_str()); history_loaded_ = (exist == 2) ? false : true; return history_loaded_; } -int HistoryManager::load_history_items_map(Conf::ConfigTree *history_list, int limit) +int HistoryManager::loadHistoryItemsMap(Conf::ConfigTree &historyList, int limit) { using std::string; // We want to save only the items recent enough (ie compared to CONFIG_HISTORY_LIMIT) - // Get the current timestamp - time_t current_timestamp; - time(¤t_timestamp); - int history_limit = get_unix_timestamp_equivalent(limit); + time_t currentTimestamp; + time(¤tTimestamp); + int historyLimit = get_unix_timestamp_equivalent(limit); + int oldestEntryTime = static_cast<int>(currentTimestamp) - historyLimit; - Conf::TokenList sections(history_list->getSections()); + std::list<std::string> sections(historyList.getSections()); int nb_items = 0; - for (Conf::TokenList::iterator iter = sections.begin(); iter != sections.end(); ++iter) { - CallType type = (CallType) getConfigInt(*iter, "type", history_list); - string timestamp_start(getConfigString(*iter, "timestamp_start", history_list)); - string timestamp_stop(getConfigString(*iter, "timestamp_stop", history_list)); - string name(getConfigString(*iter, "name", history_list)); - string number(getConfigString(*iter, "number", history_list)); - string callID(getConfigString(*iter, "id", history_list)); - string accountID(getConfigString(*iter, "accountid", history_list)); - string recording_file(getConfigString(*iter, "recordfile", history_list)); - string confID(getConfigString(*iter, "confid", history_list)); - string timeAdded(getConfigString(*iter, "timeadded", history_list)); - + for (std::list<std::string>::const_iterator iter = sections.begin(); iter != sections.end(); ++iter) { + HistoryItem item(*iter, historyList); // Make a check on the start timestamp to know it is loadable according to CONFIG_HISTORY_LIMIT - if (atoi(timestamp_start.c_str()) >= ((int) current_timestamp - history_limit)) { - HistoryItem item(timestamp_start, type, timestamp_stop, name, number, callID, accountID, recording_file, confID, timeAdded); - add_new_history_entry(item); + if (item.youngerThan(oldestEntryTime)) { + addNewHistoryEntry(item); ++nb_items; } } @@ -108,32 +96,24 @@ int HistoryManager::load_history_items_map(Conf::ConfigTree *history_list, int l return nb_items; } - -bool HistoryManager::save_history_to_file(Conf::ConfigTree *history_list) +bool HistoryManager::saveHistoryToFile(const Conf::ConfigTree &historyList) const { DEBUG("HistoryManager: Saving history in XDG directory: %s", history_path_.c_str()); - return history_list->saveConfigTree(history_path_.data()); + return historyList.saveConfigTree(history_path_.data()); } -int HistoryManager::save_history_items_map(Conf::ConfigTree *history_list) +void HistoryManager::saveHistoryItemsVector(Conf::ConfigTree &historyList) const { - int items_saved = 0; - for (std::vector<HistoryItem>::iterator iter = history_items_.begin(); iter != history_items_.end(); ++iter) { - if (iter->save(&history_list)) - ++items_saved; - else - DEBUG("can't save NULL history item\n"); - } - - return items_saved; + for (std::vector<HistoryItem>::const_iterator iter = history_items_.begin(); iter != history_items_.end(); ++iter) + iter->save(historyList); } -void HistoryManager::add_new_history_entry(const HistoryItem &new_item) +void HistoryManager::addNewHistoryEntry(const HistoryItem &new_item) { history_items_.push_back(new_item); } -void HistoryManager::create_history_path(const std::string &path) +void HistoryManager::createHistoryPath(const std::string &path) { std::string xdg_data = std::string(HOMEDIR) + DIR_SEPARATOR_STR + ".local/share/sflphone"; @@ -143,7 +123,7 @@ void HistoryManager::create_history_path(const std::string &path) // Else we 'll the standard one, ie: XDG_DATA_HOME = $HOMEDIR/.local/share/sflphone if (XDG_DATA_HOME != NULL) { std::string xdg_env(XDG_DATA_HOME); - (xdg_env.length() > 0) ? userdata = xdg_env : userdata = xdg_data; + (!xdg_env.empty()) ? userdata = xdg_env : userdata = xdg_data; } else userdata = xdg_data; @@ -155,36 +135,32 @@ void HistoryManager::create_history_path(const std::string &path) } } // Load user's history - set_history_path(userdata + DIR_SEPARATOR_STR + "history"); + setHistoryPath(userdata + DIR_SEPARATOR_STR + "history"); } else - set_history_path(path); + setHistoryPath(path); } -int -HistoryManager::getConfigInt(const std::string& section, const std::string& name, Conf::ConfigTree *history_list) +std::vector<std::map<std::string, std::string> > HistoryManager::getSerialized() const { - return history_list->getConfigTreeItemIntValue(section, name); -} - -std::string -HistoryManager::getConfigString(const std::string& section, const std::string& name, Conf::ConfigTree *history_list) -{ - return history_list->getConfigTreeItemValue(section, name); -} + using std::map; + using std::string; + using std::vector; -std::vector<std::string> HistoryManager::get_history_serialized() const -{ - std::vector<std::string> serialized; - for (std::vector<HistoryItem>::const_iterator iter = history_items_.begin(); iter != history_items_.end(); ++iter) - serialized.push_back(iter->serialize()); + vector<map<string, string> > result; + for (vector<HistoryItem>::const_iterator iter = history_items_.begin(); + iter != history_items_.end(); ++iter) + result.push_back(iter->toMap()); - return serialized; + return result; } -int HistoryManager::set_serialized_history(const std::vector<std::string> &history, int limit) +int HistoryManager::setHistorySerialized(const std::vector<std::map<std::string, std::string> > &history, int limit) { history_items_.clear(); + using std::map; + using std::string; + using std::vector; // We want to save only the items recent enough (ie compared to CONFIG_HISTORY_LIMIT) // Get the current timestamp @@ -193,12 +169,11 @@ int HistoryManager::set_serialized_history(const std::vector<std::string> &histo int history_limit = get_unix_timestamp_equivalent(limit); int items_added = 0; - for (std::vector<std::string>::const_iterator iter = history.begin(); iter != history.end(); ++iter) { + for (vector<map<string, string> >::const_iterator iter = history.begin(); iter != history.end(); ++iter) { HistoryItem new_item(*iter); - int item_timestamp = atoi(new_item.get_timestamp().c_str()); - if (item_timestamp >= ((int) current_timestamp - history_limit)) { - add_new_history_entry(new_item); + if (new_item.hasPeerNumber() and new_item.youngerThan((int) current_timestamp - history_limit)) { + addNewHistoryEntry(new_item); ++items_added; } } diff --git a/daemon/src/history/historymanager.h b/daemon/src/history/historymanager.h index 06614b438403a97b83e910d7e1f77a76bf116aaa..3e25dff8a63d8b1b0930436543cef4a7dfd51a28 100644 --- a/daemon/src/history/historymanager.h +++ b/daemon/src/history/historymanager.h @@ -34,7 +34,7 @@ #define _HISTORY_MANAGER #include "historyitem.h" -#include <global.h> +#include "global.h" class HistoryManager { @@ -49,72 +49,71 @@ class HistoryManager { * *@return int The number of history items successfully loaded */ - int load_history(int limit, const std::string &path=""); + int loadHistory(int limit, const std::string &path=""); /** *@return bool True if the history has been successfully saved in the file */ - bool save_history(); + bool saveHistory(); /* * Load the history from a file to the dedicated data structure */ - bool load_history_from_file(Conf::ConfigTree *history_list); + bool loadHistoryFromFile(Conf::ConfigTree &history_list); /* * @return int The number of history items loaded */ - int load_history_items_map(Conf::ConfigTree *history_list, int limit); + int loadHistoryItemsMap(Conf::ConfigTree &history_list, int limit); /* * Inverse method, ie save a data structure containing the history into a file */ - bool save_history_to_file(Conf::ConfigTree *history_list); + bool saveHistoryToFile(const Conf::ConfigTree &history_list) const; - /** - * @return int The number of history entries successfully saved - */ - int save_history_items_map(Conf::ConfigTree *history_list); + void saveHistoryItemsVector(Conf::ConfigTree &history_list) const; /** *@return bool True if the history file has been successfully read */ - bool is_loaded() const { + bool isLoaded() const { return history_loaded_; } - void set_history_path(const std::string &filename) { + void setHistoryPath(const std::string &filename) { history_path_ = filename; } /* *@return int The number of items found in the history file */ - int get_history_size() const { + size_t numberOfItems() const { return history_items_.size(); } - std::vector<std::string> get_history_serialized() const; + bool empty() const { + return history_items_.empty(); + } - int set_serialized_history(const std::vector<std::string> &history, int limit); + std::vector<std::string> getHistorySerialized() const; + std::vector<std::map<std::string, std::string> > getSerialized() const; - private: - int getConfigInt(const std::string& section, const std::string& name, Conf::ConfigTree *history_list); - std::string getConfigString(const std::string& section, const std::string& name, Conf::ConfigTree *history_list); + int setHistorySerialized(const std::vector<std::map<std::string, std::string> > &history, int limit); + private: /* * Set the path to the history file * * @param path A specific file to use; if empty, use the global one */ - void create_history_path(const std::string &path=""); + void createHistoryPath(const std::string &path=""); /* * Add a new history item in the data structure */ - void add_new_history_entry(const HistoryItem &new_item); + void addNewHistoryEntry(const HistoryItem &new_item); /* - * Map containing the history items + * Vector containing the history items */ std::vector<HistoryItem> history_items_; diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index 2c2d008f08fb339e5649ee96438c18ed80e77ac6..778102e15eec04432ee44bf2d57311fc20285458 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -76,7 +76,7 @@ ManagerImpl::ManagerImpl() : audiolayerMutex_(), waitingCall_(), waitingCallMutex_(), nbIncomingWaitingCall_(0), path_(), callAccountMap_(), callAccountMapMutex_(), callConfigMap_(), accountMap_(), - mainBuffer_(), conferenceMap_(), history_(new HistoryManager), + mainBuffer_(), conferenceMap_(), history_(), imModule_(new sfl::InstantMessaging) { // initialize random generator for call id @@ -87,7 +87,6 @@ ManagerImpl::ManagerImpl() : ManagerImpl::~ManagerImpl() { delete imModule_; - delete history_; delete audiofile_; } @@ -129,7 +128,7 @@ void ManagerImpl::init(std::string config_file) audioLayerMutexUnlock(); - history_->load_history(preferences.getHistoryLimit()); + history_.loadHistory(preferences.getHistoryLimit()); registerAccounts(); } @@ -2955,15 +2954,15 @@ std::map<std::string, std::string> ManagerImpl::getCallDetails(const std::string return call_details; } -std::vector<std::string> ManagerImpl::getHistorySerialized() const +std::vector<std::map<std::string, std::string> > ManagerImpl::getHistory() const { - return history_->get_history_serialized(); + return history_.getSerialized(); } -void ManagerImpl::setHistorySerialized(std::vector<std::string> history) +void ManagerImpl::setHistorySerialized(const std::vector<std::map<std::string, std::string> > &history) { - history_->set_serialized_history(history, preferences.getHistoryLimit());; - history_->save_history(); + history_.setHistorySerialized(history, preferences.getHistoryLimit()); + history_.saveHistory(); } namespace { diff --git a/daemon/src/managerimpl.h b/daemon/src/managerimpl.h index fff615a48d8072889eab549693efdb7d3b49712a..2412ac20680f7540e19c20ac0ea520697de6d2cc 100644 --- a/daemon/src/managerimpl.h +++ b/daemon/src/managerimpl.h @@ -51,6 +51,7 @@ #include "audio/codecs/audiocodecfactory.h" #include "audio/mainbuffer.h" +#include "history/historymanager.h" #include "preferences.h" #include "noncopyable.h" @@ -73,7 +74,6 @@ class VoIPLink; class DNSService; #endif -class HistoryManager; class Account; /** Define a type for a AccountMap container */ @@ -1145,17 +1145,13 @@ class ManagerImpl { */ bool accountExists(const std::string& accountID); - /** - * Get a list of serialized history entries - * @return A list of serialized entry - */ - std::vector<std::string> getHistorySerialized() const; + std::vector<std::map<std::string, std::string> > getHistory() const; /** * Set a list of serialized history entries * @param Vector of history entries */ - void setHistorySerialized(std::vector<std::string> history); + void setHistorySerialized(const std::vector<std::map<std::string, std::string> > &history); /** * Get an account pointer * @param accountID account ID to get @@ -1200,8 +1196,9 @@ class ManagerImpl { /** * To handle the persistent history + * TODO: move this to ConfigurationManager */ - HistoryManager * history_; + HistoryManager history_; /** * Instant messaging module, resposible to initiate, format, parse, diff --git a/daemon/test/history-sample.tpl b/daemon/test/history-sample.tpl index e4e0e895d56aabd4d8e365780dca8deb2dd9bbc2..9cd7a615a4366bc6160e0b6b101c62e340f51eeb 100644 --- a/daemon/test/history-sample.tpl +++ b/daemon/test/history-sample.tpl @@ -5,10 +5,9 @@ id=Account:1239059899 name=Emmanuel Milou number=136 recordfile= -timeadded= timestamp_start=747638685 timestamp_stop=747638765 -type=2 +state=outgoing [221051947] accountid=empty @@ -17,10 +16,9 @@ id= name=Savoir-faire Linux number=514-276-5468 recordfile= -timeadded= timestamp_start=144562000 timestamp_stop=144562458 -type=0 +state=missed [871962260] accountid= @@ -29,8 +27,7 @@ id=Account:43789459478 name= number=5143848557 recordfile= -timeadded= timestamp_start=775354456 timestamp_stop=775354987 -type=1 +state=incoming diff --git a/daemon/test/historytest.cpp b/daemon/test/historytest.cpp index c5a186934606441dd7fd5c82a8179fdde472339c..a910e3d8ec569b93941e49febfe0397bcb47e748 100644 --- a/daemon/test/historytest.cpp +++ b/daemon/test/historytest.cpp @@ -57,8 +57,7 @@ void backup() void HistoryTest::setUp() { backup(); - // Instantiate the cleaner singleton - history = new HistoryManager(); + history_ = new HistoryManager(); } @@ -68,9 +67,9 @@ void HistoryTest::test_create_history_path() std::string path(HISTORY_SAMPLE); - history->create_history_path(path); - CPPUNIT_ASSERT(!history->is_loaded()); - CPPUNIT_ASSERT(history->history_path_ == path); + history_->createHistoryPath(path); + CPPUNIT_ASSERT(!history_->isLoaded()); + CPPUNIT_ASSERT(history_->history_path_ == path); } void HistoryTest::test_load_history_from_file() @@ -80,11 +79,11 @@ void HistoryTest::test_load_history_from_file() bool res; Conf::ConfigTree history_list; - history->create_history_path(HISTORY_SAMPLE); - res = history->load_history_from_file(&history_list); + history_->createHistoryPath(HISTORY_SAMPLE); + res = history_->loadHistoryFromFile(history_list); - CPPUNIT_ASSERT(history->is_loaded()); - CPPUNIT_ASSERT(res == true); + CPPUNIT_ASSERT(history_->isLoaded()); + CPPUNIT_ASSERT(res); } void HistoryTest::test_load_history_items_map() @@ -95,12 +94,11 @@ void HistoryTest::test_load_history_items_map() int nb_items; Conf::ConfigTree history_list; - history->set_history_path(HISTORY_SAMPLE); - history->load_history_from_file(&history_list); - nb_items = history->load_history_items_map(&history_list, - HUGE_HISTORY_LIMIT); + history_->setHistoryPath(HISTORY_SAMPLE); + history_->loadHistoryFromFile(history_list); + nb_items = history_->loadHistoryItemsMap(history_list, HUGE_HISTORY_LIMIT); CPPUNIT_ASSERT(nb_items == HISTORY_SAMPLE_SIZE); - CPPUNIT_ASSERT(history->get_history_size() == HISTORY_SAMPLE_SIZE); + CPPUNIT_ASSERT(history_->numberOfItems() == HISTORY_SAMPLE_SIZE); } void HistoryTest::test_save_history_items_map() @@ -108,15 +106,12 @@ void HistoryTest::test_save_history_items_map() DEBUG("-------------------- HistoryTest::test_save_history_items_map --------------------\n"); std::string path; - int nb_items_loaded, nb_items_saved; Conf::ConfigTree history_list, history_list2; - history->set_history_path(HISTORY_SAMPLE); - history->load_history_from_file(&history_list); - nb_items_loaded = history->load_history_items_map(&history_list, - HUGE_HISTORY_LIMIT); - nb_items_saved = history->save_history_items_map(&history_list2); - CPPUNIT_ASSERT(nb_items_loaded == nb_items_saved); + history_->setHistoryPath(HISTORY_SAMPLE); + history_->loadHistoryFromFile(history_list); + history_->loadHistoryItemsMap(history_list, HUGE_HISTORY_LIMIT); + history_->saveHistoryItemsVector(history_list2); } void HistoryTest::test_save_history_to_file() @@ -128,115 +123,27 @@ void HistoryTest::test_save_history_to_file() std::map<std::string, std::string> res; std::map<std::string, std::string>::iterator iter; - history->set_history_path(HISTORY_SAMPLE); - history->load_history_from_file(&history_list); - history->load_history_items_map(&history_list, HUGE_HISTORY_LIMIT); - history->save_history_items_map(&history_list2); - CPPUNIT_ASSERT(history->save_history_to_file(&history_list2)); + history_->setHistoryPath(HISTORY_SAMPLE); + history_->loadHistoryFromFile(history_list); + history_->loadHistoryItemsMap(history_list, HUGE_HISTORY_LIMIT); + history_->saveHistoryItemsVector(history_list2); + CPPUNIT_ASSERT(history_->saveHistoryToFile(history_list2)); } void HistoryTest::test_get_history_serialized() { DEBUG("-------------------- HistoryTest::test_get_history_serialized --------------------\n"); - std::vector<std::string> res; std::vector<std::string>::iterator iter; std::string tmp; - CPPUNIT_ASSERT(history->load_history(HUGE_HISTORY_LIMIT, HISTORY_SAMPLE) == HISTORY_SAMPLE_SIZE); - res = history->get_history_serialized(); - CPPUNIT_ASSERT(res.size() == HISTORY_SAMPLE_SIZE); - - - // Warning - If you change the history-sample file, you must change the following lines also so that the tests could work - // The reference here is the file history-sample in this test directory - // The serialized form is: calltype%to%from%callid - - // Check the first - tmp = "2|136|Emmanuel Milou|747638685|747638765|Account:1239059899|empty|||"; - // std::cout << "res[0] " << res[0] << std::endl; - // CPPUNIT_ASSERT (Validator::isEqual (tmp, res[0])); - - // the account ID does not correspond to a loaded account - tmp = "2|136|Emmanuel Milou|747638685|747638765|Account:1239059899|empty|||"; - // std::cout << "res[1] " << res[1] << std::endl; - // CPPUNIT_ASSERT (Validator::isEqual (tmp, res[1])); -} - -void HistoryTest::test_set_serialized_history() -{ - DEBUG("-------------------- HistoryTest::test_set_serialized_history --------------------\n"); - - // We build a map to have an efficient test - std::vector<std::string> test_vector; - std::string tmp; - Conf::ConfigTree history_list; - - test_vector.push_back("0|514-276-5468|Savoir-faire Linux|144562000|144562458||empty|||"); - test_vector.push_back("2|136|Emmanuel Milou|747638685|747638765|Account:1239059899||||"); - test_vector.push_back("1|5143848557|empty|775354456|775354987|Account:43789459478||||"); - - CPPUNIT_ASSERT(history->load_history(HUGE_HISTORY_LIMIT, HISTORY_SAMPLE) == HISTORY_SAMPLE_SIZE); - // We use a large history limit to be able to interpret results - CPPUNIT_ASSERT(history->set_serialized_history(test_vector, HUGE_HISTORY_LIMIT) == 3); - CPPUNIT_ASSERT(history->get_history_size() == 3); - - test_vector.clear(); - test_vector = history->get_history_serialized(); - CPPUNIT_ASSERT(test_vector.size() == 3); - - // Check the first - tmp = "0|514-276-5468|Savoir-faire Linux|144562000|144562458||empty|||"; - // CPPUNIT_ASSERT (Validator::isEqual (tmp, test_vector[0])); - - // the account ID does not correspond to a loaded account - tmp = "2|136|Emmanuel Milou|747638685|747638765|Account:1239059899|empty|||"; - // std::cout << "test vector : " << test_vector[1] << std::endl; - // CPPUNIT_ASSERT (Validator::isEqual (tmp, test_vector[1])); - - history->save_history_items_map(&history_list); - CPPUNIT_ASSERT(history->save_history_to_file(&history_list)); -} - -void HistoryTest::test_set_serialized_history_with_limit() -{ - DEBUG("-------------------- HistoryTest::test_set_serialized_history_with_limit --------------------\n"); - - // We build a map to have an efficient test - std::vector<std::string> test_vector; - std::string tmp; - - Conf::ConfigTree history_list; - time_t current, day = 86400; // One day in unix timestamp - std::stringstream current_1, current_2, current_3; - (void) time(¤t); - current_1 << "0|514-276-5468|Savoir-faire Linux|" << (current - 2 * day) << "|144562458|empty|" << std::endl; - current_2 << "2|136|Emmanuel Milou|" << (current - 5 * day) << "|747638765|Account:1239059899|" << std::endl; - current_3 << "1|5143848557|empty|" << (current - 11 * day) << "|775354987|Account:43789459478|" << std::endl; - - test_vector.push_back(current_1.str()); - test_vector.push_back(current_2.str()); - test_vector.push_back(current_3.str()); - - CPPUNIT_ASSERT(history->load_history(HUGE_HISTORY_LIMIT, HISTORY_SAMPLE) == HISTORY_SAMPLE_SIZE); - // We use different value of history limit - // 10 days - the last entry should not be saved - CPPUNIT_ASSERT(history->set_serialized_history(test_vector, 10) == 2); - CPPUNIT_ASSERT(history->get_history_size() == 2); - - // 4 days - the two last entries should not be saved - CPPUNIT_ASSERT(history->set_serialized_history(test_vector, 4) == 1); - CPPUNIT_ASSERT(history->get_history_size() == 1); - - // 1 day - no entry should not be saved - CPPUNIT_ASSERT(history->set_serialized_history(test_vector, 1) == 0); - CPPUNIT_ASSERT(history->get_history_size() == 0); + CPPUNIT_ASSERT(history_->loadHistory(HUGE_HISTORY_LIMIT, HISTORY_SAMPLE) == HISTORY_SAMPLE_SIZE); + CPPUNIT_ASSERT(history_->getSerialized().size() == HISTORY_SAMPLE_SIZE); } void HistoryTest::tearDown() { // Delete the history object - delete history; - history = 0; + delete history_; restore(); } diff --git a/daemon/test/historytest.h b/daemon/test/historytest.h index 9fb3b97d0f35a222626d4bab3603a58e0795d638..1706bab7d88efe04a3a50f771a2685c63bc10266 100644 --- a/daemon/test/historytest.h +++ b/daemon/test/historytest.h @@ -59,13 +59,11 @@ class HistoryTest : public CppUnit::TestCase { CPPUNIT_TEST(test_load_history_from_file); CPPUNIT_TEST(test_load_history_items_map); CPPUNIT_TEST(test_get_history_serialized); - CPPUNIT_TEST(test_set_serialized_history); - CPPUNIT_TEST(test_set_serialized_history_with_limit); // CPPUNIT_TEST (test_save_history_to_file); CPPUNIT_TEST_SUITE_END(); public: - HistoryTest() : CppUnit::TestCase("History Tests"), history(0) {} + HistoryTest() : CppUnit::TestCase("History Tests"), history_(0) {} /* * Code factoring - Common resources can be initialized here. @@ -97,7 +95,7 @@ class HistoryTest : public CppUnit::TestCase { private: NON_COPYABLE(HistoryTest); - HistoryManager *history; + HistoryManager *history_; }; /* Register our test module */ diff --git a/gnome/src/actions.c b/gnome/src/actions.c index a02a9fe0af88bfeb602c66ac2a935391365b6693..4e33ba443a4bd5afc861b286873477fcec6d923a 100644 --- a/gnome/src/actions.c +++ b/gnome/src/actions.c @@ -41,7 +41,6 @@ #include <string.h> #include <sys/types.h> #include <unistd.h> -#include <assert.h> #include <arpa/nameser.h> #include <netinet/in.h> @@ -61,57 +60,11 @@ #include "icons/icon_factory.h" #include "imwindow.h" #include "statusicon.h" +#include "unused.h" #include "widget/imwidget.h" - static GHashTable * ip2ip_profile; -static gchar ** sflphone_order_history_hash_table(GHashTable *result) -{ - GHashTableIter iter; - gint size = 0; - gchar **ordered_list = NULL; - - assert(result); - - while (g_hash_table_size(result)) { - gpointer key, value; - gpointer key_to_min = NULL; - - // find lowest timestamp in map - g_hash_table_iter_init(&iter, result); - - gint min_timestamp = G_MAXINT; - - while (g_hash_table_iter_next(&iter, &key, &value)) { - gint timestamp = atoi((gchar*) key); - - if (timestamp < min_timestamp) { - min_timestamp = timestamp; - key_to_min = key; - } - } - - if (g_hash_table_lookup_extended(result, key_to_min, &key, &value)) { - GSList *llist = (GSList *)value; - - while (llist) { - ordered_list = (gchar **) g_realloc(ordered_list, (size + 1) * sizeof(gchar *)); - *(ordered_list + size) = g_strdup((gchar *)llist->data); - size++; - llist = g_slist_next(llist); - } - - g_hash_table_remove(result, key_to_min); - } - } - - ordered_list = (gchar **) g_realloc(ordered_list, (size + 1) * sizeof(gchar *)); - ordered_list[size] = NULL; - - return ordered_list; -} - void sflphone_notify_voice_mail(const gchar* accountID , guint count) { @@ -174,8 +127,8 @@ status_bar_display_account() if (acc) { msg = g_markup_printf_escaped("%s %s (%s)" , _("Using account"), - (gchar*) g_hash_table_lookup(acc->properties , ACCOUNT_ALIAS), - (gchar*) g_hash_table_lookup(acc->properties , ACCOUNT_TYPE)); + (gchar*) g_hash_table_lookup(acc->properties, ACCOUNT_ALIAS), + (gchar*) g_hash_table_lookup(acc->properties, ACCOUNT_TYPE)); } else { msg = g_markup_printf_escaped(_("No registered accounts")); } @@ -451,7 +404,7 @@ sflphone_pick_up() break; case CALL_STATE_INCOMING: - selectedCall->_history_state = INCOMING; + selectedCall->_history_state = g_strdup(INCOMING_STRING); calltree_update_call(history_tab, selectedCall); // if instant messaging window is visible, create new tab (deleted automatically if not used) @@ -597,7 +550,7 @@ sflphone_display_transfer_status(const gchar* message) void sflphone_incoming_call(callable_obj_t * c) { - c->_history_state = MISSED; + c->_history_state = g_strdup(MISSED_STRING); calllist_add_call(current_calls_tab, c); calltree_add_call(current_calls_tab, c, NULL); @@ -688,7 +641,7 @@ sflphone_new_call() callable_obj_t *c = create_new_call(CALL, CALL_STATE_DIALING, "", "", "", ""); - c->_history_state = OUTGOING; + c->_history_state = g_strdup(OUTGOING_STRING); calllist_add_call(current_calls_tab, c); calltree_add_call(current_calls_tab, c, NULL); @@ -741,7 +694,7 @@ sflphone_keypad(guint keyval, gchar * key) switch (keyval) { case GDK_Return: case GDK_KP_Enter: - c->_history_state = INCOMING; + c->_history_state = g_strdup(INCOMING_STRING); calltree_update_call(history_tab, c); dbus_accept(c); break; @@ -867,7 +820,7 @@ static int place_registered_call(callable_obj_t * c) notify_current_account(current); } - c->_history_state = OUTGOING; + c->_history_state = g_strdup(OUTGOING_STRING); return 0; } @@ -924,8 +877,6 @@ sflphone_add_participant(const gchar* callID, const gchar* confID) return; } - time(&call->_time_added); - dbus_add_participant(callID, confID); } @@ -1075,27 +1026,21 @@ void sflphone_fill_conference_list(void) g_strfreev(conferences); } -void sflphone_fill_history(void) +static void +create_callable_from_entry(gpointer data, gpointer user_data UNUSED) { - gchar **entries, **entries_orig; - entries = entries_orig = dbus_get_history(); - - while (entries && *entries) { - gchar *current_entry = *entries; - /* do something with key and value */ - callable_obj_t *history_call = create_history_entry_from_serialized_form(current_entry); + GHashTable *entry = (GHashTable *) data; + callable_obj_t *history_call = create_history_entry_from_hashtable(entry); - /* Add it and update the GUI */ - calllist_add_call(history_tab, history_call); - entries++; - } - - g_strfreev(entries_orig); + /* Add it and update the GUI */ + calllist_add_call_to_front(history_tab, history_call); +} - // fill the treeview with calls +static void fill_treeview_with_calls(void) +{ guint n = calllist_get_size(history_tab); - for (guint i = 0; i < n; i++) { + for (guint i = 0; i < n; ++i) { QueueElement *element = calllist_get_nth(history_tab, i); if (element->type == HIST_CALL) @@ -1103,28 +1048,43 @@ void sflphone_fill_history(void) } } -#if ! (GLIB_CHECK_VERSION(2,28,0)) -static void -g_slist_free_full(GSList *list, - GDestroyNotify free_func) +void sflphone_fill_history(void) { - g_slist_foreach(list, (GFunc) free_func, NULL); - g_slist_free(list); -} -#endif + GPtrArray *entries = dbus_get_history(); + if (entries) + g_ptr_array_foreach(entries, create_callable_from_entry, NULL); + fill_treeview_with_calls(); +} -static void hist_free_elt(gpointer list) +/* Ordered from highest timestamp (most recent) to lowest (oldest) */ +static gint +history_compare_func(gconstpointer a, gconstpointer b) { - g_slist_free_full((GSList *)list, g_free); + gconstpointer first_value = g_hash_table_lookup(* (GHashTable **) a, TIMESTAMP_START_KEY); + gconstpointer second_value = g_hash_table_lookup(* (GHashTable **) b, TIMESTAMP_START_KEY); + /* treat NULL values as less than non-NULL values, like g_strcmp0 does */ + if (!first_value) + return -(first_value != second_value); + else if (!second_value) + return first_value != second_value; + + long f = atol(first_value); + long s = atol(second_value); + if (f > s) + return -1; + else if (f == s) + return 0; + else + return 1; } void sflphone_save_history(void) { - GHashTable *result = g_hash_table_new_full(NULL, g_str_equal, g_free, hist_free_elt); - gint size = calllist_get_size(history_tab); + GPtrArray *sorted_history = g_ptr_array_new(); + /* For each entry in our call history */ for (gint i = 0; i < size; ++i) { QueueElement *current = calllist_get_nth(history_tab, i); @@ -1133,23 +1093,17 @@ void sflphone_save_history(void) break; } - gchar *value; - if (current->type == HIST_CALL) { - value = serialize_history_call_entry(current->elem.call); - gchar *key = g_strdup_printf("%i", (int) current->elem.call->_time_start); - - g_hash_table_replace(result, (gpointer) key, - g_slist_append(g_hash_table_lookup(result, key),(gpointer) value)); + GHashTable *value = create_hashtable_from_history_entry(current->elem.call); + g_ptr_array_add(sorted_history, (gpointer) value); } else ERROR("SFLphone: Error: Unknown type for serialization"); } - gchar **ordered_result = sflphone_order_history_hash_table(result); - dbus_set_history(ordered_result); - g_strfreev(ordered_result); - g_hash_table_unref(result); + g_ptr_array_sort(sorted_history, history_compare_func); + dbus_set_history(sorted_history); + g_ptr_array_free(sorted_history, TRUE); } void diff --git a/gnome/src/callable_obj.c b/gnome/src/callable_obj.c index d6e3771c481417289596e30dca8bb3b2c77eba3d..995cbdf80a206fa5099e5f2db4a661f8d98a70eb 100644 --- a/gnome/src/callable_obj.c +++ b/gnome/src/callable_obj.c @@ -164,83 +164,43 @@ callable_obj_t *create_new_call_from_details(const gchar *call_id, GHashTable *d return c; } -static history_state_t get_history_state_from_id(gchar *indice) +static gconstpointer get_str(GHashTable *entry, gconstpointer key) { - history_state_t state = atoi(indice); - - if (state > LAST) - state = MISSED; - - return state; + gconstpointer result = g_hash_table_lookup(entry, key); + if (!result || g_strcmp0(result, "empty") == 0) + result = ""; + return result; } -callable_obj_t *create_history_entry_from_serialized_form(const gchar *entry) +/* FIXME:tmatth: These need to be in sync with the daemon */ +static const char * const ACCOUNT_ID_KEY = "accountid"; +static const char * const CALLID_KEY = "callid"; +static const char * const CONFID_KEY = "confid"; +static const char * const PEER_NAME_KEY = "peer_name"; +static const char * const PEER_NUMBER_KEY = "peer_number"; +static const char * const RECORDING_PATH_KEY = "recordfile"; +static const char * const TIMESTAMP_STOP_KEY = "timestamp_stop"; +static const char * const STATE_KEY = "state"; + +callable_obj_t *create_history_entry_from_hashtable(GHashTable *entry) { - const gchar *peer_name = ""; - const gchar *peer_number = ""; - const gchar *callID = ""; - const gchar *accountID = ""; - const gchar *time_start = ""; - const gchar *time_stop = ""; - const gchar *recordfile = ""; - const gchar *confID = ""; - const gchar *time_added = ""; - history_state_t history_state = MISSED; - - gchar **ptr_orig = g_strsplit(entry, "|", 10); - gchar **ptr; - gint token; - - for (ptr = ptr_orig, token = 0; ptr && token < 10; token++, ptr++) - switch (token) { - case 0: - history_state = get_history_state_from_id(*ptr); - break; - case 1: - peer_number = *ptr; - break; - case 2: - peer_name = *ptr; - break; - case 3: - time_start = *ptr; - break; - case 4: - time_stop = *ptr; - break; - case 5: - callID = *ptr; - break; - case 6: - accountID = *ptr; - break; - case 7: - recordfile = *ptr; - break; - case 8: - confID = *ptr; - break; - case 9: - time_added = *ptr; - break; - default: - break; - } - - if (g_strcasecmp(peer_name, "empty") == 0) - peer_name = ""; - + gconstpointer callID = get_str(entry, CALLID_KEY); + gconstpointer accountID = get_str(entry, ACCOUNT_ID_KEY); + gconstpointer peer_name = get_str(entry, PEER_NAME_KEY); + gconstpointer peer_number = get_str(entry, PEER_NUMBER_KEY); callable_obj_t *new_call = create_new_call(HISTORY_ENTRY, CALL_STATE_DIALING, callID, accountID, peer_name, peer_number); - new_call->_history_state = history_state; - new_call->_time_start = atoi(time_start); - new_call->_time_stop = atoi(time_stop); - new_call->_recordfile = g_strdup(recordfile); - new_call->_confID = g_strdup(confID); - new_call->_historyConfID = g_strdup(confID); - new_call->_time_added = atoi(time_added); + new_call->_history_state = g_strdup(get_str(entry, STATE_KEY)); + gconstpointer value = g_hash_table_lookup(entry, TIMESTAMP_START_KEY); + new_call->_time_start = value ? atoi(value) : 0; + value = g_hash_table_lookup(entry, TIMESTAMP_STOP_KEY); + new_call->_time_stop = value ? atoi(value) : 0; + value = g_hash_table_lookup(entry, RECORDING_PATH_KEY); + new_call->_recordfile = g_strdup(value); + value = g_hash_table_lookup(entry, CONFID_KEY); + new_call->_confID = g_strdup(value); + new_call->_historyConfID = g_strdup(value); new_call->_record_is_playing = FALSE; - g_strfreev(ptr_orig); return new_call; } @@ -276,49 +236,40 @@ gchar* get_call_duration(callable_obj_t *obj) return g_strdup_printf("<small>Duration:</small> %.2ld:%.2ld" , duration/60 , duration%60); } -static const gchar* get_history_id_from_state(history_state_t state) +static +void add_to_hashtable(GHashTable *hashtable, const gchar *key, const gchar *value) { - if (state >= LAST) - return ""; - - return state + "0"; + g_hash_table_insert(hashtable, g_strdup(key), g_strdup(value)); } -gchar* serialize_history_call_entry(callable_obj_t *entry) +GHashTable* create_hashtable_from_history_entry(callable_obj_t *entry) { - // "0|514-276-5468|Savoir-faire Linux|144562458" for instance - gchar *peer_number, *peer_name, *account_id; - static const gchar * const separator = "|"; - gchar *record_file; - gchar *confID; - - // Need the string form for the history state - const gchar *history_state = get_history_id_from_state(entry->_history_state); + const gchar *history_state = entry->_history_state ? entry->_history_state : ""; // and the timestamps gchar *time_start = g_strdup_printf("%i", (int) entry->_time_start); gchar *time_stop = g_strdup_printf("%i", (int) entry->_time_stop); - gchar *time_added = g_strdup_printf("%i", (int) entry->_time_added); - - peer_number = entry->_peer_number ? entry->_peer_number : ""; - peer_name = (entry->_peer_name && *entry->_peer_name) ? entry->_peer_name : "empty"; - account_id = (entry->_accountID && *entry->_accountID) ? entry->_accountID : "empty"; - - confID = entry->_historyConfID ? entry->_historyConfID : ""; - record_file = entry->_recordfile ? entry->_recordfile : ""; - - gchar *result = g_strconcat(history_state, separator, - peer_number, separator, - peer_name, separator, - time_start, separator, - time_stop, separator, - entry->_callID, separator, - account_id, separator, - record_file, separator, - confID, separator, - time_added, NULL); - g_free(time_start); - g_free(time_stop); - g_free(time_added); + + const gchar *call_id = entry->_callID ? entry->_callID : ""; + const gchar *peer_number = entry->_peer_number ? entry->_peer_number : ""; + const gchar *peer_name = (entry->_peer_name && *entry->_peer_name) ? entry->_peer_name : "empty"; + const gchar *account_id = (entry->_accountID && *entry->_accountID) ? entry->_accountID : "empty"; + + const gchar *conf_id = entry->_historyConfID ? entry->_historyConfID : ""; + const gchar *recording_path = entry->_recordfile ? entry->_recordfile : ""; + + GHashTable *result = g_hash_table_new(NULL, g_str_equal); + add_to_hashtable(result, CALLID_KEY, call_id); + add_to_hashtable(result, CONFID_KEY, conf_id); + add_to_hashtable(result, PEER_NUMBER_KEY, peer_number); + add_to_hashtable(result, PEER_NAME_KEY, peer_name); + add_to_hashtable(result, RECORDING_PATH_KEY, recording_path); + add_to_hashtable(result, ACCOUNT_ID_KEY, account_id); + add_to_hashtable(result, TIMESTAMP_START_KEY, time_start); + add_to_hashtable(result, TIMESTAMP_STOP_KEY, time_stop); + add_to_hashtable(result, STATE_KEY, history_state); + /* These values were already allocated dynamically */ + g_hash_table_insert(result, g_strdup(TIMESTAMP_START_KEY), time_start); + g_hash_table_insert(result, g_strdup(TIMESTAMP_STOP_KEY), time_stop); return result; } diff --git a/gnome/src/callable_obj.h b/gnome/src/callable_obj.h index 2f81d683e7e372360487cd75e7ecf2201c066702..849ec7783d662ec7dc1a927fdc025cd731d7a711 100644 --- a/gnome/src/callable_obj.h +++ b/gnome/src/callable_obj.h @@ -35,17 +35,6 @@ #include <time.h> #include <gtk/gtk.h> -/** - * @enum history_state - * This enum have all the state a call can take in the history - */ -typedef enum { - MISSED = 0, - INCOMING = 1, - OUTGOING = 2, - LAST = 3, -} history_state_t; - /** * @enum contact_type * This enum have all types of contacts: HOME phone, cell phone, etc... @@ -83,6 +72,11 @@ typedef enum { CALL_STATE_RECORD, } call_state_t; +static const char * const TIMESTAMP_START_KEY = "timestamp_start"; +static const char * const MISSED_STRING = "missed"; +static const char * const INCOMING_STRING = "incoming"; +static const char * const OUTGOING_STRING = "outgoing"; + typedef enum { SRTP_STATE_UNLOCKED = 0, SRTP_STATE_SDES_SUCCESS, @@ -103,11 +97,11 @@ typedef struct { gchar* _state_code_description; // A textual description of _state_code gchar* _callID; // The call ID gchar* _confID; // The conference ID (NULL if don't participate to a conference) - gchar* _historyConfID; // Persistent conf id to be stored in history + gchar* _historyConfID; // Persistent conf id to be stored in history gchar* _accountID; // The account the call is made with time_t _time_start; // The timestamp the call was initiating time_t _time_stop; // The timestamp the call was over - history_state_t _history_state; // The history state if necessary + gchar *_history_state; // The history state if necessary srtp_state_t _srtp_state; // The state of security on the call gchar* _srtp_cipher; // Cipher used for the srtp session gchar* _sas; // The Short Authentication String that should be displayed @@ -158,21 +152,21 @@ typedef struct { /* Associated IM widget */ GtkWidget *_im_widget; - - time_t _time_added; } callable_obj_t; -callable_obj_t *create_new_call (callable_type_t, call_state_t, const gchar* const, const gchar* const, const gchar* const, const gchar* const); +callable_obj_t *create_new_call(callable_type_t, call_state_t, const gchar* const, const gchar* const, const gchar* const, const gchar* const); -callable_obj_t *create_new_call_from_details (const gchar *, GHashTable *); +callable_obj_t *create_new_call_from_details(const gchar *, GHashTable *); -callable_obj_t *create_history_entry_from_serialized_form (const gchar *); +callable_obj_t *create_history_entry_from_hashtable(GHashTable *entry); -void call_add_error (callable_obj_t * call, gpointer dialog); +GHashTable* create_hashtable_from_history_entry(callable_obj_t *entry); -void call_remove_error (callable_obj_t * call, gpointer dialog); +void call_add_error(callable_obj_t * call, gpointer dialog); -void call_remove_all_errors (callable_obj_t * call); +void call_remove_error(callable_obj_t * call, gpointer dialog); + +void call_remove_all_errors(callable_obj_t * call); /* * GCompareFunc to compare a callID (gchar* and a callable_obj_t) @@ -182,32 +176,30 @@ void call_remove_all_errors (callable_obj_t * call); /* * GCompareFunc to get current call (gchar* and a callable_obj_t) */ -gint get_state_callstruct (gconstpointer, gconstpointer); +gint get_state_callstruct(gconstpointer, gconstpointer); /** * This function parse the callable_obj_t.from field to return the name * @param c The call * @return The full name of the caller or an empty string */ -gchar* call_get_peer_name (const gchar*); +gchar* call_get_peer_name(const gchar*); /** * This function parse the callable_obj_t.from field to return the number * @param c The call * @return The number of the caller */ -gchar* call_get_peer_number (const gchar*); - -void free_callable_obj_t (callable_obj_t *c); +gchar* call_get_peer_number(const gchar*); -gchar* get_peer_info (const gchar* const, const gchar* const); +void free_callable_obj_t(callable_obj_t *c); -gchar* get_call_duration (callable_obj_t *obj); +gchar* get_peer_info(const gchar* const, const gchar* const); -gchar* serialize_history_call_entry(callable_obj_t *entry); +gchar* get_call_duration(callable_obj_t *obj); -gchar* get_formatted_start_timestamp (time_t); +gchar* get_formatted_start_timestamp(time_t); -gchar* call_get_audio_codec (callable_obj_t *obj); +gchar* call_get_audio_codec(callable_obj_t *obj); #endif diff --git a/gnome/src/config/preferencesdialog.c b/gnome/src/config/preferencesdialog.c index 8a38ed761a3e81bc63534cbcfd9224782dceb3e5..3bd50579130952f4b00f007b497ca63b3c44145a 100644 --- a/gnome/src/config/preferencesdialog.c +++ b/gnome/src/config/preferencesdialog.c @@ -346,12 +346,14 @@ static GtkTreeModel* create_model(GtkWidget *widget) }; GdkPixbuf *pixbuf; GtkTreeIter iter; - gint i, nb_entries; GtkListStore *store = gtk_list_store_new(3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT); - nb_entries = sizeof(browser_entries_full) / sizeof(browser_entries_full[0]); + gint nb_entries = sizeof(browser_entries_full) / sizeof(browser_entries_full[0]); + /* Skip address book entry if that plugin is not installed */ + if (!addrbook) + --nb_entries; - for (i = 0; i < nb_entries; i++) { + for (gint i = 0; i < nb_entries; ++i) { gtk_list_store_append (store, &iter); pixbuf = get_icon(browser_entries_full[i].icon_name, widget); gtk_list_store_set(store, &iter, diff --git a/gnome/src/contacts/calllist.c b/gnome/src/contacts/calllist.c index 75b0727f8c03104ee93158e47a74a58b8df8ad0c..4cc64dbf3875e006cacfe56a41f72ab283245150 100644 --- a/gnome/src/contacts/calllist.c +++ b/gnome/src/contacts/calllist.c @@ -29,6 +29,7 @@ */ #include "calllist.h" +#include <string.h> #include "calltab.h" #include "calltree.h" #include "unused.h" @@ -120,6 +121,15 @@ calllist_add_call(calltab_t* tab, callable_obj_t * c) g_queue_push_tail(tab->callQueue, (gpointer) element); } +void +calllist_add_call_to_front(calltab_t* tab, callable_obj_t * c) +{ + QueueElement *element = g_new0(QueueElement, 1); + element->type = HIST_CALL; + element->elem.call = c; + g_queue_push_head(tab->callQueue, (gpointer) element); +} + void calllist_clean_history(void) { @@ -150,7 +160,7 @@ calllist_remove_call(calltab_t* tab, const gchar * callID) if (c == NULL) return; - QueueElement *element = (QueueElement *)c->data; + QueueElement *element = (QueueElement *) c->data; if (element->type != HIST_CALL) { ERROR("CallList: Error: Element %s is not a call", callID); @@ -159,8 +169,11 @@ calllist_remove_call(calltab_t* tab, const gchar * callID) g_queue_remove(tab->callQueue, element); - calllist_add_call(history_tab, element->elem.call); - calltree_add_history_entry(element->elem.call); + /* Don't save empty (i.e. started dialing, then deleted) calls */ + if (element->elem.call->_peer_number && strlen(element->elem.call->_peer_number) > 0) { + calllist_add_call(history_tab, element->elem.call); + calltree_add_history_entry(element->elem.call); + } } @@ -172,7 +185,7 @@ calllist_get_by_state(calltab_t* tab, call_state_t state) } guint -calllist_get_size(calltab_t* tab) +calllist_get_size(const calltab_t* tab) { return g_queue_get_length(tab->callQueue); } diff --git a/gnome/src/contacts/calllist.h b/gnome/src/contacts/calllist.h index 66d793f5627f598d5c792b8a480c0f893b8e94f7..b69814b5e14d4549878e6747d6a72e8358fc8a0e 100644 --- a/gnome/src/contacts/calllist.h +++ b/gnome/src/contacts/calllist.h @@ -67,59 +67,65 @@ typedef struct { } calltab_t; void -calllist_add_contact (gchar *, gchar *, contact_type_t, GdkPixbuf *); +calllist_add_contact(gchar *, gchar *, contact_type_t, GdkPixbuf *); /** This function empty and free the call list. */ void -calllist_clean (calltab_t* tab); +calllist_clean(calltab_t* tab); /** This function empty, free the call list and allocate a new one. */ void -calllist_reset (calltab_t* tab); +calllist_reset(calltab_t* tab); /** Get the maximun number of calls in the history calltab */ gdouble -call_history_get_max_calls (void); +call_history_get_max_calls(void); /** Set the maximun number of calls in the history calltab */ void -call_history_set_max_calls (const gdouble number); +call_history_set_max_calls(const gdouble number); /** This function append a call to list. * @param c The call you want to add * */ void -calllist_add_call (calltab_t* tab, callable_obj_t * c); +calllist_add_call(calltab_t* tab, callable_obj_t * c); + +/** This function inserts a call to front of list. + * @param c The call you want to add + * */ +void +calllist_add_call_to_front(calltab_t* tab, callable_obj_t * c); /** This function remove a call from list. * @param callID The callID of the call you want to remove */ void -calllist_remove_call (calltab_t* tab, const gchar * callID); +calllist_remove_call(calltab_t* tab, const gchar * callID); /** Return the first call that corresponds to the state. * This is usefull for unique states as DIALING and CURRENT. * @param state The state * @return A call or NULL */ callable_obj_t * -calllist_get_by_state (calltab_t* tab, call_state_t state); +calllist_get_by_state(calltab_t* tab, call_state_t state); /** Return the number of calls in the list * @return The number of calls in the list */ guint -calllist_get_size (calltab_t* tab); +calllist_get_size(const calltab_t* tab); /** Return the call at the nth position in the list * @param n The position of the call you want * @return A call or NULL */ QueueElement * -calllist_get_nth (calltab_t* tab, guint n); +calllist_get_nth(calltab_t* tab, guint n); /** Return the call corresponding to the callID * @param n The callID of the call you want * @return A call or NULL */ callable_obj_t * -calllist_get_call (calltab_t* tab, const gchar * callID); +calllist_get_call(calltab_t* tab, const gchar * callID); /** * Clean the history. Delete all calls @@ -132,12 +138,12 @@ calllist_clean_history(); * @param c The call to remove */ void -calllist_remove_from_history (callable_obj_t* c); +calllist_remove_from_history(callable_obj_t* c); /** * Initialize a non-empty call list */ void -calllist_set_list (calltab_t* tab, gchar **call_list); +calllist_set_list(calltab_t* tab, gchar **call_list); #endif diff --git a/gnome/src/contacts/calltree.c b/gnome/src/contacts/calltree.c index 2e70bc5e929f1f9ac609cb3f26abc69403c8e93d..3ccf76705a13aa832e10b7cd02121b6202665ebf 100644 --- a/gnome/src/contacts/calltree.c +++ b/gnome/src/contacts/calltree.c @@ -339,7 +339,7 @@ calltree_display_call_info(callable_obj_t * c, CallDisplayType display_type, con gchar display_number[strlen(c->_peer_number) + 1]; strcpy(display_number, c->_peer_number); - if (c->_type != CALL || c->_history_state != OUTGOING) { + if (c->_type != CALL || g_strcmp0(c->_history_state, OUTGOING_STRING)) { // Get the hostname for this call (NULL if not existent) gchar * hostname = g_strrstr(c->_peer_number, "@"); @@ -564,6 +564,14 @@ calltree_remove_call(calltab_t* tab, callable_obj_t * c) calltree_remove_call_recursive(tab, c, NULL); } +GdkPixbuf *history_state_to_pixbuf(const gchar *history_state) +{ + gchar *svg_filename = g_strconcat(ICONS_DIR, "/", history_state, ".svg", NULL); + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(svg_filename, NULL); + g_free(svg_filename); + return pixbuf; +} + static void calltree_update_call_recursive(calltab_t* tab, callable_obj_t * c, GtkTreeIter *parent) { @@ -689,22 +697,10 @@ calltree_update_call_recursive(calltab_t* tab, callable_obj_t * c, GtkTreeIter * } } else if (tab == history_tab) { - if (parent == NULL) { - // parent is NULL this is not a conference participant - switch (c->_history_state) { - case INCOMING: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/incoming.svg", NULL); - break; - case OUTGOING: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/outgoing.svg", NULL); - break; - case MISSED: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/missed.svg", NULL); - break; - default: - WARN("History - Should not happen!"); - } - } else // parent is not NULL this is a conference participant + // parent is NULL this is not a conference participant + if (parent == NULL) + pixbuf = history_state_to_pixbuf(c->_history_state); + else // parent is not NULL this is a conference participant pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/current.svg", NULL); g_free(description); @@ -856,21 +852,7 @@ void calltree_add_history_entry(callable_obj_t *c) GtkTreeIter iter; gtk_tree_store_prepend(history_tab->store, &iter, NULL); - GdkPixbuf *pixbuf = NULL; - - switch (c->_history_state) { - case INCOMING: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/incoming.svg", NULL); - break; - case OUTGOING: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/outgoing.svg", NULL); - break; - case MISSED: - pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/missed.svg", NULL); - break; - default: - WARN("History - Should not happen!"); - } + GdkPixbuf *pixbuf = history_state_to_pixbuf(c->_history_state); gchar *date = get_formatted_start_timestamp(c->_time_start); gchar *duration = get_call_duration(c); diff --git a/gnome/src/contacts/history.c b/gnome/src/contacts/history.c index 36cd0a2ac4ad1d72e2b8c7cb1b097683739d5889..33b01177d9b5db2b7f019cc5b4cd691122406421 100644 --- a/gnome/src/contacts/history.c +++ b/gnome/src/contacts/history.c @@ -37,6 +37,21 @@ static GtkTreeModel *history_filter; static GtkEntry *history_searchbar_widget; +static gboolean +search_type_matches_state(SearchType type, const gchar *state) +{ + switch (type) { + case SEARCH_MISSED: + return !g_strcmp0(state, MISSED_STRING); + case SEARCH_INCOMING: + return !g_strcmp0(state, INCOMING_STRING); + case SEARCH_OUTGOING: + return !g_strcmp0(state, OUTGOING_STRING); + default: + return FALSE; + } +} + static gboolean history_is_visible(GtkTreeModel* model, GtkTreeIter* iter, gpointer data UNUSED) { gboolean ret = TRUE; @@ -72,8 +87,8 @@ static gboolean history_is_visible(GtkTreeModel* model, GtkTreeIter* iter, gpoin if (search_type == SEARCH_ALL) goto end; - else // We need a match on the history_state_t and the current search type - ret = ret && (history_entry->_history_state + 1) == search_type; + else // We need a match on the history_state and the current search type + ret = ret && search_type_matches_state(search_type, history_entry->_history_state); } end: diff --git a/gnome/src/dbus/configurationmanager-introspec.xml b/gnome/src/dbus/configurationmanager-introspec.xml index 21493d0a003e6dc6c04833ed202416b36867d7bf..6271c12c9d3cedfc8f6c286d7d199b5b51e1e386 100644 --- a/gnome/src/dbus/configurationmanager-introspec.xml +++ b/gnome/src/dbus/configurationmanager-introspec.xml @@ -89,7 +89,7 @@ <tp:docstring> </tp:docstring> </arg> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="VectorMapStringString"/> <arg type="aa{ss}" name="credentialInformation" direction="in" tp:type="String_String_Map"> <tp:docstring> </tp:docstring> @@ -258,7 +258,7 @@ </tp:docstring> </arg> </method> - + <method name="getIsAlwaysRecording" tp:name-for-bindings="getIsAlwaysRecording"> <tp:docstring> </tp:docstring> @@ -308,7 +308,7 @@ <method name="getActiveAudioCodecList" tp:name-for-bindings="getActiveAudioCodecList"> <tp:docstring> </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorString"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorInt"/> <arg type="s" name="accountID" direction="in"> <tp:docstring> </tp:docstring> @@ -333,7 +333,6 @@ </arg> </method> - <!-- Audio devices methods --> <method name="getAudioPluginList" tp:name-for-bindings="getAudioPluginList"> @@ -457,7 +456,7 @@ </tp:docstring> </arg> </method> - + <method name="getEchoCancelTailLength" tp:name-for-bindings="getEchoCancelTailLength"> <tp:docstring> </tp:docstring> @@ -466,22 +465,22 @@ </tp:docstring> </arg> </method> - + <method name="setEchoCancelDelay" tp:name-for-bindings="setEchoCancelDelay"> <tp:docstring> </tp:docstring> <arg type="i" name="index" direction="in"> </arg> - </method> - + </method> + <method name="getEchoCancelDelay" tp:name-for-bindings="getEchoCancelDelay"> <tp:docstring> </tp:docstring> <arg type="i" name="index" direction="out"> </arg> </method> - - + + <method name="getNoiseSuppressState" tp:name-for-bindings="getEchoCancelState"> <tp:docstring> </tp:docstring> @@ -521,7 +520,6 @@ </arg> </method> - <method name="getHistoryLimit" tp:name-for-bindings="getHistoryLimit"> <tp:docstring> </tp:docstring> @@ -603,35 +601,27 @@ </arg> </method> - <method name="getHistory" tp:name-for-bindings="getHistory"> - <tp:docstring> - </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MapStringString"/> - <arg type="as" name="entries" direction="out"> - <tp:docstring> - </tp:docstring> - </arg> + <method name="getHistory" tp:name-for-bindings="getHistory"> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/> + <!-- Return a List of type Dict<string, string> >...a List of Dicts --> + <arg type="aa{ss}" name="entries" direction="out"/> </method> <method name="setHistory" tp:name-for-bindings="setHistory"> - <tp:docstring> - </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MapStringString"/> - <arg type="as" name="entries" direction="in"> - <tp:docstring> - </tp:docstring> + <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="VectorMapStringString"/> + <arg type="aa{ss}" name="entries" direction="in"> </arg> </method> <signal name="accountsChanged" tp:name-for-bindings="accountsChanged"> - </signal> + </signal> <signal name="errorAlert" tp:name-for-bindings="errorAlert"> <arg type="i" name="code"> <tp:docstring> </tp:docstring> </arg> - </signal> + </signal> <!-- TLS Methods --> <method name="getSupportedTlsMethod" tp:name-for-bindings="getSupportedTlsMethod"> @@ -667,7 +657,7 @@ <method name="setTlsSettings" tp:name-for-bindings="setTlsSettings"> <tp:docstring> </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="MapStringString"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MapStringString"/> <arg type="a{ss}" name="details" direction="in"> <tp:docstring> </tp:docstring> diff --git a/gnome/src/dbus/dbus.c b/gnome/src/dbus/dbus.c index 5c3cbfc55d42b17dac3ec1fc5f0f97af50098cc4..e4cc43bc5089501dc9bb74b3a40afc3ee9dd652e 100644 --- a/gnome/src/dbus/dbus.c +++ b/gnome/src/dbus/dbus.c @@ -194,8 +194,8 @@ call_state_cb(DBusGProxy *proxy UNUSED, const gchar* callID, const gchar* state, GHashTable *call_details = dbus_get_call_details(callID); callable_obj_t *new_call = create_new_call_from_details(callID, call_details); - new_call->_history_state = (g_strcasecmp(g_hash_table_lookup(call_details, "CALL_TYPE"), "0") == 0) - ? INCOMING : OUTGOING; + new_call->_history_state = (g_strcasecmp(g_hash_table_lookup(call_details, "CALL_TYPE"), INCOMING_STRING) == 0) + ? g_strdup(INCOMING_STRING) : g_strdup(OUTGOING_STRING); calllist_add_call(current_calls_tab, new_call); calltree_add_call(current_calls_tab, new_call, NULL); @@ -275,9 +275,6 @@ conference_created_cb(DBusGProxy *proxy UNUSED, const gchar* confID, void * foo for (gchar **part = participants; part && *part; ++part) { callable_obj_t *call = calllist_get_call(current_calls_tab, *part); - /* set when this call has been added to the conference */ - time(&call->_time_added); - im_widget_update_state(IM_WIDGET(call->_im_widget), FALSE); // if one of these participant is currently recording, the whole conference will be recorded @@ -1943,17 +1940,17 @@ dbus_set_accounts_order(const gchar* order) } } -gchar ** +GPtrArray * dbus_get_history(void) { GError *error = NULL; - gchar **entries = NULL; + GPtrArray *entries = NULL; org_sflphone_SFLphone_ConfigurationManager_get_history( configurationManagerProxy, &entries, &error); if (error) { - ERROR("Error calling get history: %s", error->message); + ERROR("Error calling get history simple: %s", error->message); g_error_free(error); } @@ -1961,15 +1958,15 @@ dbus_get_history(void) } void -dbus_set_history(gchar **entries) +dbus_set_history(const GPtrArray *entries) { GError *error = NULL; org_sflphone_SFLphone_ConfigurationManager_set_history( - configurationManagerProxy, (const char **)entries, &error); + configurationManagerProxy, entries, &error); if (error) { - ERROR("Error calling org_sflphone_SFLphone_CallManager_set_history"); + ERROR("Error calling org_sflphone_SFLphone_ConfigurationlManager_set_history"); g_error_free(error); } } diff --git a/gnome/src/dbus/dbus.h b/gnome/src/dbus/dbus.h index 41193d89dc991a2dce2bf5747e03b4feda1dec31..8ff9027cb9e0a27a05f77bc7639565aa0bf37393 100644 --- a/gnome/src/dbus/dbus.h +++ b/gnome/src/dbus/dbus.h @@ -472,17 +472,17 @@ gchar** dbus_get_conference_list (void); void dbus_set_accounts_order (const gchar* order); /** - * Get a list of serialized hisotry entries - * @return The list of history entries + * Get a the history + * @return The PtrArray of history entries */ -gchar **dbus_get_history (void); +GPtrArray *dbus_get_history(void); /** - * Set the history entries into the daemon. The daemon then write teh content + * Set the history entries into the daemon. The daemon then writes the content * of this list into the history file * @param A list of serialized history entries */ -void dbus_set_history (gchar **); +void dbus_set_history (const GPtrArray *history); void sflphone_display_transfer_status (const gchar* message); diff --git a/kde/src/dbus/configurationmanager-introspec.xml b/kde/src/dbus/configurationmanager-introspec.xml index 043a19bff83388726e65670e5a9aed4bc2db04fe..6271c12c9d3cedfc8f6c286d7d199b5b51e1e386 100755 --- a/kde/src/dbus/configurationmanager-introspec.xml +++ b/kde/src/dbus/configurationmanager-introspec.xml @@ -89,7 +89,7 @@ <tp:docstring> </tp:docstring> </arg> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="VectorMapStringString"/> <arg type="aa{ss}" name="credentialInformation" direction="in" tp:type="String_String_Map"> <tp:docstring> </tp:docstring> @@ -258,7 +258,7 @@ </tp:docstring> </arg> </method> - + <method name="getIsAlwaysRecording" tp:name-for-bindings="getIsAlwaysRecording"> <tp:docstring> </tp:docstring> @@ -333,7 +333,6 @@ </arg> </method> - <!-- Audio devices methods --> <method name="getAudioPluginList" tp:name-for-bindings="getAudioPluginList"> @@ -457,7 +456,7 @@ </tp:docstring> </arg> </method> - + <method name="getEchoCancelTailLength" tp:name-for-bindings="getEchoCancelTailLength"> <tp:docstring> </tp:docstring> @@ -466,22 +465,22 @@ </tp:docstring> </arg> </method> - + <method name="setEchoCancelDelay" tp:name-for-bindings="setEchoCancelDelay"> <tp:docstring> </tp:docstring> <arg type="i" name="index" direction="in"> </arg> - </method> - + </method> + <method name="getEchoCancelDelay" tp:name-for-bindings="getEchoCancelDelay"> <tp:docstring> </tp:docstring> <arg type="i" name="index" direction="out"> </arg> </method> - - + + <method name="getNoiseSuppressState" tp:name-for-bindings="getEchoCancelState"> <tp:docstring> </tp:docstring> @@ -521,7 +520,6 @@ </arg> </method> - <method name="getHistoryLimit" tp:name-for-bindings="getHistoryLimit"> <tp:docstring> </tp:docstring> @@ -603,35 +601,27 @@ </arg> </method> - <method name="getHistory" tp:name-for-bindings="getHistory"> - <tp:docstring> - </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="MapStringString"/> - <arg type="as" name="entries" direction="out"> - <tp:docstring> - </tp:docstring> - </arg> + <method name="getHistory" tp:name-for-bindings="getHistory"> + <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="VectorMapStringString"/> + <!-- Return a List of type Dict<string, string> >...a List of Dicts --> + <arg type="aa{ss}" name="entries" direction="out"/> </method> <method name="setHistory" tp:name-for-bindings="setHistory"> - <tp:docstring> - </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MapStringString"/> - <arg type="as" name="entries" direction="in"> - <tp:docstring> - </tp:docstring> + <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="VectorMapStringString"/> + <arg type="aa{ss}" name="entries" direction="in"> </arg> </method> <signal name="accountsChanged" tp:name-for-bindings="accountsChanged"> - </signal> + </signal> <signal name="errorAlert" tp:name-for-bindings="errorAlert"> <arg type="i" name="code"> <tp:docstring> </tp:docstring> </arg> - </signal> + </signal> <!-- TLS Methods --> <method name="getSupportedTlsMethod" tp:name-for-bindings="getSupportedTlsMethod"> @@ -667,7 +657,7 @@ <method name="setTlsSettings" tp:name-for-bindings="setTlsSettings"> <tp:docstring> </tp:docstring> - <annotation name="com.trolltech.QtDBus.QtTypeName.In1" value="MapStringString"/> + <annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="MapStringString"/> <arg type="a{ss}" name="details" direction="in"> <tp:docstring> </tp:docstring>