From 4fd4f8f0949f06a9ce69fd182f3ab8eb6129638f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com>
Date: Wed, 3 Sep 2014 18:51:52 -0400
Subject: [PATCH] Config: factor code in *Account superclasses

Refs #53127

Change-Id: I3266a4e8ee366ec2ee534df9f1406af908b99620
---
 daemon/src/account.cpp            |  90 ++++++++++++
 daemon/src/account.h              |  12 +-
 daemon/src/iax/iaxaccount.cpp     |  43 +-----
 daemon/src/iax/iaxaccount.h       |   6 +-
 daemon/src/sip/sipaccount.cpp     | 226 +++---------------------------
 daemon/src/sip/sipaccount.h       |   2 +-
 daemon/src/sip/sipaccountbase.cpp | 198 ++++++++++++++++++++++++++
 daemon/src/sip/sipaccountbase.h   |   8 ++
 8 files changed, 333 insertions(+), 252 deletions(-)

diff --git a/daemon/src/account.cpp b/daemon/src/account.cpp
index cf7b71fefc..afcda9204f 100644
--- a/daemon/src/account.cpp
+++ b/daemon/src/account.cpp
@@ -46,6 +46,10 @@
 #include "manager.h"
 
 #include "client/configurationmanager.h"
+#include "account_schema.h"
+#include "config/yamlparser.h"
+
+#include <yaml-cpp/yaml.h>
 
 const char * const Account::AUDIO_CODECS_KEY            = "audioCodecs";  // 0/9/110/111/112/
 const char * const Account::VIDEO_CODECS_KEY            = "videoCodecs";
@@ -160,6 +164,92 @@ void Account::loadDefaultCodecs()
 #endif
 }
 
+
+void Account::serialize(YAML::Emitter &out)
+{
+    using namespace Conf;
+
+    out << YAML::Key << ID_KEY << YAML::Value << accountID_;
+    out << YAML::Key << ALIAS_KEY << YAML::Value << alias_;
+    out << YAML::Key << ACCOUNT_ENABLE_KEY << YAML::Value << enabled_;
+    out << YAML::Key << TYPE_KEY << YAML::Value << getAccountType();
+    out << YAML::Key << AUDIO_CODECS_KEY << YAML::Value << audioCodecStr_;
+    out << YAML::Key << MAILBOX_KEY << YAML::Value << mailBox_;
+    out << YAML::Key << ACCOUNT_AUTOANSWER_KEY << YAML::Value << autoAnswerEnabled_;
+    out << YAML::Key << RINGTONE_ENABLED_KEY << YAML::Value << ringtoneEnabled_;
+    out << YAML::Key << RINGTONE_PATH_KEY << YAML::Value << ringtonePath_;
+    out << YAML::Key << HAS_CUSTOM_USER_AGENT_KEY << YAML::Value << hasCustomUserAgent_;
+    out << YAML::Key << USER_AGENT_KEY << YAML::Value << userAgent_;
+    out << YAML::Key << USERNAME_KEY << YAML::Value << username_;
+    out << YAML::Key << DISPLAY_NAME_KEY << YAML::Value << displayName_;
+    out << YAML::Key << HOSTNAME_KEY << YAML::Value << hostname_;
+}
+
+void Account::unserialize(const YAML::Node &node)
+{
+    using namespace yaml_utils;
+    parseValue(node, ALIAS_KEY, alias_);
+    parseValue(node, ACCOUNT_ENABLE_KEY, enabled_);
+    parseValue(node, USERNAME_KEY, username_);
+    parseValue(node, ACCOUNT_AUTOANSWER_KEY, autoAnswerEnabled_);
+    //parseValue(node, PASSWORD_KEY, password_);
+
+    parseValue(node, MAILBOX_KEY, mailBox_);
+    parseValue(node, AUDIO_CODECS_KEY, audioCodecStr_);
+
+    // Update codec list which one is used for SDP offer
+    setActiveAudioCodecs(split_string(audioCodecStr_));
+    parseValue(node, DISPLAY_NAME_KEY, displayName_);
+    parseValue(node, HOSTNAME_KEY, hostname_);
+
+    parseValue(node, HAS_CUSTOM_USER_AGENT_KEY, hasCustomUserAgent_);
+    parseValue(node, USER_AGENT_KEY, userAgent_);
+    parseValue(node, RINGTONE_PATH_KEY, ringtonePath_);
+    parseValue(node, RINGTONE_ENABLED_KEY, ringtoneEnabled_);
+}
+
+void Account::setAccountDetails(const std::map<std::string, std::string> &details)
+{
+    // Account setting common to SIP and IAX
+    parseString(details, CONFIG_ACCOUNT_ALIAS, alias_);
+    parseBool(details, CONFIG_ACCOUNT_ENABLE, enabled_);
+    parseString(details, CONFIG_ACCOUNT_USERNAME, username_);
+    parseString(details, CONFIG_ACCOUNT_HOSTNAME, hostname_);
+    parseString(details, CONFIG_ACCOUNT_MAILBOX, mailBox_);
+    parseString(details, CONFIG_ACCOUNT_USERAGENT, userAgent_);
+    parseBool(details, CONFIG_ACCOUNT_AUTOANSWER, autoAnswerEnabled_);
+    parseBool(details, CONFIG_RINGTONE_ENABLED, ringtoneEnabled_);
+    parseString(details, CONFIG_RINGTONE_PATH, ringtonePath_);
+    parseBool(details, CONFIG_ACCOUNT_HAS_CUSTOM_USERAGENT, hasCustomUserAgent_);
+    if (hasCustomUserAgent_)
+        parseString(details, CONFIG_ACCOUNT_USERAGENT, userAgent_);
+    else
+        userAgent_ = DEFAULT_USER_AGENT;
+}
+
+std::map<std::string, std::string> Account::getAccountDetails() const
+{
+    std::map<std::string, std::string> a;
+
+    a[CONFIG_ACCOUNT_ALIAS] = alias_;
+    a[CONFIG_ACCOUNT_ENABLE] = enabled_ ? "true" : "false";
+    a[CONFIG_ACCOUNT_TYPE] = getAccountType();
+    a[CONFIG_ACCOUNT_HOSTNAME] = hostname_;
+    a[CONFIG_ACCOUNT_USERNAME] = username_;
+    a[CONFIG_ACCOUNT_MAILBOX] = mailBox_;
+
+    RegistrationState state(registrationState_);
+
+    a[CONFIG_ACCOUNT_REGISTRATION_STATUS] = mapStateNumberToString(state);
+    a[CONFIG_ACCOUNT_USERAGENT] = hasCustomUserAgent_ ? userAgent_ : DEFAULT_USER_AGENT;
+    a[CONFIG_ACCOUNT_HAS_CUSTOM_USERAGENT] = hasCustomUserAgent_ ? TRUE_STR : FALSE_STR;
+    a[CONFIG_ACCOUNT_AUTOANSWER] = autoAnswerEnabled_ ? TRUE_STR : FALSE_STR;
+    a[CONFIG_RINGTONE_ENABLED] = ringtoneEnabled_ ? TRUE_STR : FALSE_STR;
+    a[CONFIG_RINGTONE_PATH] = ringtonePath_;
+
+    return a;
+}
+
 #ifdef SFL_VIDEO
 static bool
 isPositiveInteger(const string &s)
diff --git a/daemon/src/account.h b/daemon/src/account.h
index 2923cc6da1..6e1ae96828 100644
--- a/daemon/src/account.h
+++ b/daemon/src/account.h
@@ -53,6 +53,11 @@ class VoipLinkException : public std::runtime_error {
             std::runtime_error("VoipLinkException occured: " + str) {}
 };
 
+namespace YAML {
+    class Emitter;
+    class Node;
+}
+
 /**
  * @file account.h
  * @brief Interface to protocol account (SIPAccount, IAXAccount)
@@ -79,15 +84,18 @@ class Account : public Serializable {
          */
         void freeAccount();
 
-        virtual void setAccountDetails(const std::map<std::string, std::string> &details) = 0;
+        virtual void setAccountDetails(const std::map<std::string, std::string> &details);
 
-        virtual std::map<std::string, std::string> getAccountDetails() const = 0;
+        virtual std::map<std::string, std::string> getAccountDetails() const;
 
         /**
          * Load the settings for this account.
          */
         virtual void loadConfig() = 0;
 
+        virtual void serialize(YAML::Emitter &out);
+        virtual void unserialize(const YAML::Node &node);
+
         /**
          * Get the account ID
          * @return constant account id
diff --git a/daemon/src/iax/iaxaccount.cpp b/daemon/src/iax/iaxaccount.cpp
index fe2c883eb8..b23661c0a9 100644
--- a/daemon/src/iax/iaxaccount.cpp
+++ b/daemon/src/iax/iaxaccount.cpp
@@ -58,64 +58,29 @@ void IAXAccount::serialize(YAML::Emitter &out)
     using namespace Conf;
 
     out << YAML::BeginMap;
-    out << YAML::Key << ALIAS_KEY << YAML::Value << alias_;
-    out << YAML::Key << AUDIO_CODECS_KEY << YAML::Value << audioCodecStr_;
-    out << YAML::Key << ACCOUNT_ENABLE_KEY << YAML::Value << enabled_;
-    out << YAML::Key << MAILBOX_KEY << YAML::Value << mailBox_;
+    Account::serialize(out);
     out << YAML::Key << PASSWORD_KEY << YAML::Value << password_;
-    out << YAML::Key << TYPE_KEY << YAML::Value << ACCOUNT_TYPE;
-    out << YAML::Key << USER_AGENT_KEY << YAML::Value << userAgent_;
-    out << YAML::Key << USERNAME_KEY << YAML::Value << username_;
     out << YAML::EndMap;
 }
 
 void IAXAccount::unserialize(const YAML::Node &node)
 {
     using namespace yaml_utils;
-    parseValue(node, ALIAS_KEY, alias_);
-    parseValue(node, USERNAME_KEY, username_);
+    Account::unserialize(node);
     parseValue(node, PASSWORD_KEY, password_);
-    parseValue(node, HOSTNAME_KEY, hostname_);
-    parseValue(node, ACCOUNT_ENABLE_KEY, enabled_);
-    parseValue(node, MAILBOX_KEY, mailBox_);
-    parseValue(node, AUDIO_CODECS_KEY, audioCodecStr_);
-
-    // Update codec list which one is used for SDP offer
-    setActiveAudioCodecs(split_string(audioCodecStr_));
-    parseValue(node, DISPLAY_NAME_KEY, displayName_);
-
-    parseValue(node, USER_AGENT_KEY, userAgent_);
 }
 
 void IAXAccount::setAccountDetails(const std::map<std::string, std::string> &details)
 {
     // Account setting common to SIP and IAX
-    parseString(details, CONFIG_ACCOUNT_ALIAS, alias_);
-    parseString(details, CONFIG_ACCOUNT_USERNAME, username_);
-    parseString(details, CONFIG_ACCOUNT_HOSTNAME, hostname_);
+    Account::setAccountDetails(details);
     parseString(details, CONFIG_ACCOUNT_PASSWORD, password_);
-    parseBool(details, CONFIG_ACCOUNT_ENABLE, enabled_);
-    parseString(details, CONFIG_ACCOUNT_MAILBOX, mailBox_);
-    parseString(details, CONFIG_ACCOUNT_USERAGENT, userAgent_);
 }
 
 std::map<std::string, std::string> IAXAccount::getAccountDetails() const
 {
-    std::map<std::string, std::string> a;
-
-    a[CONFIG_ACCOUNT_ALIAS] = alias_;
-    a[CONFIG_ACCOUNT_ENABLE] = enabled_ ? "true" : "false";
-    a[CONFIG_ACCOUNT_TYPE] = ACCOUNT_TYPE;
-    a[CONFIG_ACCOUNT_HOSTNAME] = hostname_;
-    a[CONFIG_ACCOUNT_USERNAME] = username_;
+    std::map<std::string, std::string> a = Account::getAccountDetails();
     a[CONFIG_ACCOUNT_PASSWORD] = password_;
-    a[CONFIG_ACCOUNT_MAILBOX] = mailBox_;
-
-    RegistrationState state(registrationState_);
-
-    a[CONFIG_ACCOUNT_REGISTRATION_STATUS] = mapStateNumberToString(state);
-    a[CONFIG_ACCOUNT_USERAGENT] = userAgent_;
-
     return a;
 }
 
diff --git a/daemon/src/iax/iaxaccount.h b/daemon/src/iax/iaxaccount.h
index 7577f6bde5..f63631cc6e 100644
--- a/daemon/src/iax/iaxaccount.h
+++ b/daemon/src/iax/iaxaccount.h
@@ -54,6 +54,9 @@ class IAXAccount : public Account {
 
         IAXAccount(const std::string& accountID);
 
+        virtual void serialize(YAML::Emitter &out);
+        virtual void unserialize(const YAML::Node &node);
+
         const char* getAccountType() const {
             return ACCOUNT_TYPE;
         }
@@ -126,8 +129,7 @@ class IAXAccount : public Account {
         newIncomingCall(const std::string& id);
 
     private:
-        void serialize(YAML::Emitter &out);
-        void unserialize(const YAML::Node &node);
+
         void setAccountDetails(const std::map<std::string, std::string> &details);
 
         /**
diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp
index 784a8978d4..6744fb1ee2 100644
--- a/daemon/src/sip/sipaccount.cpp
+++ b/daemon/src/sip/sipaccount.cpp
@@ -73,7 +73,6 @@
 static const int MIN_REGISTRATION_TIME = 60;
 static const int DEFAULT_REGISTRATION_TIME = 3600;
 static const char *const VALID_TLS_METHODS[] = {"Default", "TLSv1", "SSLv3", "SSLv23"};
-static const char *const VALID_SRTP_KEY_EXCHANGES[] = {"", "sdes", "zrtp"};
 constexpr const char * const SIPAccount::ACCOUNT_TYPE;
 
 static void
@@ -165,15 +164,6 @@ updateRange(int min, int max, std::pair<uint16_t, uint16_t> &range)
     }
 }
 
-static void
-unserializeRange(const YAML::Node &node, const char *minKey, const char *maxKey, std::pair<uint16_t, uint16_t> &range)
-{
-    int tmpMin = 0;
-    int tmpMax = 0;
-    yaml_utils::parseValue(node, minKey, tmpMin);
-    yaml_utils::parseValue(node, maxKey, tmpMax);
-    updateRange(tmpMin, tmpMax, range);
-}
 
 std::shared_ptr<SIPCall>
 SIPAccount::newIncomingCall(const std::string& id)
@@ -359,24 +349,11 @@ void SIPAccount::serialize(YAML::Emitter &out)
     using namespace Conf;
 
     out << YAML::BeginMap;
-    out << YAML::Key << ALIAS_KEY << YAML::Value << alias_;
-    out << YAML::Key << AUDIO_CODECS_KEY << YAML::Value << audioCodecStr_;
-    out << YAML::Key << AUDIO_PORT_MAX_KEY << YAML::Value << audioPortRange_.second;
-    out << YAML::Key << AUDIO_PORT_MIN_KEY << YAML::Value << audioPortRange_.first;
-    out << YAML::Key << ACCOUNT_AUTOANSWER_KEY << YAML::Value << autoAnswerEnabled_;
+    SIPAccountBase::serialize(out);
+
     // each credential is a map, and we can have multiple credentials
     out << YAML::Key << CRED_KEY << YAML::Value << credentials_;
-
-    out << YAML::Key << DISPLAY_NAME_KEY << YAML::Value << displayName_;
-    out << YAML::Key << DTMF_TYPE_KEY << YAML::Value << dtmfType_;
-    out << YAML::Key << ACCOUNT_ENABLE_KEY << YAML::Value << enabled_;
-    out << YAML::Key << HAS_CUSTOM_USER_AGENT_KEY << YAML::Value << hasCustomUserAgent_;
-    out << YAML::Key << HOSTNAME_KEY << YAML::Value << hostname_;
-    out << YAML::Key << ID_KEY << YAML::Value << accountID_;
-    out << YAML::Key << INTERFACE_KEY << YAML::Value << interface_;
     out << YAML::Key << KEEP_ALIVE_ENABLED << YAML::Value << keepAliveEnabled_;
-    out << YAML::Key << MAILBOX_KEY << YAML::Value << mailBox_;
-    out << YAML::Key << PORT_KEY << YAML::Value << localPort_;
 
 #ifdef SFL_PRESENCE
     out << YAML::Key << PRESENCE_MODULE_ENABLED_KEY << YAML::Value << (presence_ and presence_->isEnabled());
@@ -387,22 +364,9 @@ void SIPAccount::serialize(YAML::Emitter &out)
     out << YAML::Key << PRESENCE_PUBLISH_SUPPORTED_KEY << YAML::Value << false;
     out << YAML::Key << PRESENCE_SUBSCRIBE_SUPPORTED_KEY << YAML::Value << false;
 #endif
-
-    out << YAML::Key << PUBLISH_ADDR_KEY << YAML::Value << publishedIpAddress_;
-    out << YAML::Key << PUBLISH_PORT_KEY << YAML::Value << publishedPort_;
     out << YAML::Key << Preferences::REGISTRATION_EXPIRE_KEY << YAML::Value << registrationExpire_;
-    out << YAML::Key << RINGTONE_ENABLED_KEY << YAML::Value << ringtoneEnabled_;
-    out << YAML::Key << RINGTONE_PATH_KEY << YAML::Value << ringtonePath_;
-    out << YAML::Key << SAME_AS_LOCAL_KEY << YAML::Value << publishedSameasLocal_;
     out << YAML::Key << SERVICE_ROUTE_KEY << YAML::Value << serviceRoute_;
 
-    // srtp submap
-    out << YAML::Key << SRTP_KEY << YAML::Value << YAML::BeginMap;
-    out << YAML::Key << SRTP_ENABLE_KEY << YAML::Value << srtpEnabled_;
-    out << YAML::Key << KEY_EXCHANGE_KEY << YAML::Value << srtpKeyExchange_;
-    out << YAML::Key << RTP_FALLBACK_KEY << YAML::Value << srtpFallback_;
-    out << YAML::EndMap;
-
     out << YAML::Key << STUN_ENABLED_KEY << YAML::Value << stunEnabled_;
     out << YAML::Key << STUN_SERVER_KEY << YAML::Value << stunServer_;
 
@@ -423,16 +387,6 @@ void SIPAccount::serialize(YAML::Emitter &out)
     out << YAML::Key << VERIFY_SERVER_KEY << YAML::Value << tlsVerifyServer_;
     out << YAML::EndMap;
 
-    out << YAML::Key << TYPE_KEY << YAML::Value << ACCOUNT_TYPE;
-    out << YAML::Key << USER_AGENT_KEY << YAML::Value << userAgent_;
-    out << YAML::Key << USERNAME_KEY << YAML::Value << username_;
-
-    out << YAML::Key << VIDEO_CODECS_KEY << YAML::Value << videoCodecList_;
-
-    out << YAML::Key << VIDEO_ENABLED_KEY << YAML::Value << videoEnabled_;
-    out << YAML::Key << VIDEO_PORT_MAX_KEY << YAML::Value << videoPortRange_.second;
-    out << YAML::Key << VIDEO_PORT_MIN_KEY << YAML::Value << videoPortRange_.first;
-
     // zrtp submap
     out << YAML::Key << ZRTP_KEY << YAML::Value << YAML::BeginMap;
     out << YAML::Key << DISPLAY_SAS_KEY << YAML::Value << zrtpDisplaySas_;
@@ -467,51 +421,13 @@ void SIPAccount::unserialize(const YAML::Node &node)
 {
     using namespace Conf;
     using namespace yaml_utils;
-    parseValue(node, ALIAS_KEY, alias_);
-    parseValue(node, USERNAME_KEY, username_);
-
-    if (not isIP2IP()) parseValue(node, HOSTNAME_KEY, hostname_);
-
-    parseValue(node, ACCOUNT_ENABLE_KEY, enabled_);
-    parseValue(node, ACCOUNT_AUTOANSWER_KEY, autoAnswerEnabled_);
-
-    if (not isIP2IP()) parseValue(node, MAILBOX_KEY, mailBox_);
-
-    parseValue(node, AUDIO_CODECS_KEY, audioCodecStr_);
-    // Update codec list which one is used for SDP offer
-    setActiveAudioCodecs(split_string(audioCodecStr_));
-    const auto &vCodecNode = node[VIDEO_CODECS_KEY];
-    auto tmp = parseVectorMap(vCodecNode, {VIDEO_CODEC_BITRATE,
-            VIDEO_CODEC_ENABLED, VIDEO_CODEC_NAME, VIDEO_CODEC_PARAMETERS});
-
-#ifdef SFL_VIDEO
-    if (tmp.empty()) {
-        // Video codecs are an empty list
-        WARN("Loading default video codecs");
-        tmp = libav_utils::getDefaultCodecs();
-    }
-#endif
-    // validate it
-    setVideoCodecs(tmp);
-
-    parseValue(node, RINGTONE_PATH_KEY, ringtonePath_);
-    parseValue(node, RINGTONE_ENABLED_KEY, ringtoneEnabled_);
-    parseValue(node, VIDEO_ENABLED_KEY, videoEnabled_);
-
-    if (not isIP2IP()) parseValue(node, Preferences::REGISTRATION_EXPIRE_KEY, registrationExpire_);
-
-    parseValue(node, INTERFACE_KEY, interface_);
-    int port = DEFAULT_SIP_PORT;
-    parseValue(node, PORT_KEY, port);
-    localPort_ = port;
-    parseValue(node, PUBLISH_ADDR_KEY, publishedIpAddress_);
-    parseValue(node, PUBLISH_PORT_KEY, port);
-    publishedPort_ = port;
-    parseValue(node, SAME_AS_LOCAL_KEY, publishedSameasLocal_);
 
+    SIPAccountBase::unserialize(node);
     if (not publishedSameasLocal_)
         usePublishedAddressPortInVIA();
 
+    if (not isIP2IP()) parseValue(node, Preferences::REGISTRATION_EXPIRE_KEY, registrationExpire_);
+
     if (not isIP2IP()) parseValue(node, KEEP_ALIVE_ENABLED, keepAliveEnabled_);
 
     bool presEnabled = false;
@@ -528,35 +444,20 @@ void SIPAccount::unserialize(const YAML::Node &node)
     }
 #endif
 
-    parseValue(node, DTMF_TYPE_KEY, dtmfType_);
-
     if (not isIP2IP()) parseValue(node, SERVICE_ROUTE_KEY, serviceRoute_);
 
     // stun enabled
     if (not isIP2IP()) parseValue(node, STUN_ENABLED_KEY, stunEnabled_);
-
     if (not isIP2IP()) parseValue(node, STUN_SERVER_KEY, stunServer_);
 
     // Init stun server name with default server name
     stunServerName_ = pj_str((char*) stunServer_.data());
 
-    parseValue(node, DISPLAY_NAME_KEY, displayName_);
-
     const auto &credsNode = node[CRED_KEY];
     const auto creds = parseVectorMap(credsNode, {CONFIG_ACCOUNT_PASSWORD,
             CONFIG_ACCOUNT_REALM, CONFIG_ACCOUNT_USERNAME});
     setCredentials(creds);
 
-    // get srtp submap
-    const auto &srtpMap = node[SRTP_KEY];
-
-    parseValue(srtpMap, SRTP_ENABLE_KEY, srtpEnabled_);
-
-    std::string tmpKey;
-    parseValue(srtpMap, KEY_EXCHANGE_KEY, tmpKey);
-    validate(srtpKeyExchange_, tmpKey, VALID_SRTP_KEY_EXCHANGES);
-    parseValue(srtpMap, RTP_FALLBACK_KEY, srtpFallback_);
-
     // get zrtp submap
     const auto &zrtpMap = node[ZRTP_KEY];
 
@@ -587,13 +488,6 @@ void SIPAccount::unserialize(const YAML::Node &node)
     // FIXME
     parseValue(tlsMap, TIMEOUT_KEY, tlsNegotiationTimeoutSec_);
 
-    parseValue(node, USER_AGENT_KEY, userAgent_);
-    parseValue(node, HAS_CUSTOM_USER_AGENT_KEY, hasCustomUserAgent_);
-
-    unserializeRange(node, AUDIO_PORT_MIN_KEY, AUDIO_PORT_MAX_KEY, audioPortRange_);
-#ifdef SFL_VIDEO
-    unserializeRange(node, VIDEO_PORT_MIN_KEY, VIDEO_PORT_MAX_KEY, videoPortRange_);
-#endif
 }
 
 template <typename T>
@@ -610,44 +504,21 @@ parseInt(const std::map<std::string, std::string> &details, const char *key, T &
 
 void SIPAccount::setAccountDetails(const std::map<std::string, std::string> &details)
 {
-    // Account setting common to SIP and IAX
-    parseString(details, CONFIG_ACCOUNT_ALIAS, alias_);
-    parseString(details, CONFIG_ACCOUNT_USERNAME, username_);
-    parseString(details, CONFIG_ACCOUNT_HOSTNAME, hostname_);
-    parseBool(details, CONFIG_ACCOUNT_ENABLE, enabled_);
-    parseBool(details, CONFIG_ACCOUNT_AUTOANSWER, autoAnswerEnabled_);
-    parseString(details, CONFIG_RINGTONE_PATH, ringtonePath_);
-    parseBool(details, CONFIG_RINGTONE_ENABLED, ringtoneEnabled_);
-    parseBool(details, CONFIG_VIDEO_ENABLED, videoEnabled_);
-    parseString(details, CONFIG_ACCOUNT_MAILBOX, mailBox_);
+	SIPAccountBase::setAccountDetails(details);
 
     // SIP specific account settings
-
-    // general sip settings
     parseString(details, CONFIG_ACCOUNT_ROUTESET, serviceRoute_);
-    parseString(details, CONFIG_LOCAL_INTERFACE, interface_);
-    parseBool(details, CONFIG_PUBLISHED_SAMEAS_LOCAL, publishedSameasLocal_);
-    parseString(details, CONFIG_PUBLISHED_ADDRESS, publishedIpAddress_);
-    parseInt(details, CONFIG_LOCAL_PORT, localPort_);
-    parseInt(details, CONFIG_PUBLISHED_PORT, publishedPort_);
 
     if (not publishedSameasLocal_)
         usePublishedAddressPortInVIA();
 
     parseString(details, CONFIG_STUN_SERVER, stunServer_);
     parseBool(details, CONFIG_STUN_ENABLE, stunEnabled_);
-    parseString(details, CONFIG_ACCOUNT_DTMF_TYPE, dtmfType_);
     parseInt(details, CONFIG_ACCOUNT_REGISTRATION_EXPIRE, registrationExpire_);
 
     if (registrationExpire_ < MIN_REGISTRATION_TIME)
         registrationExpire_ = MIN_REGISTRATION_TIME;
 
-    parseBool(details, CONFIG_ACCOUNT_HAS_CUSTOM_USERAGENT, hasCustomUserAgent_);
-    if (hasCustomUserAgent_)
-        parseString(details, CONFIG_ACCOUNT_USERAGENT, userAgent_);
-    else
-        userAgent_ = DEFAULT_USER_AGENT;
-
     parseBool(details, CONFIG_KEEP_ALIVE_ENABLED, keepAliveEnabled_);
 #ifdef SFL_PRESENCE
     bool presenceEnabled = false;
@@ -655,29 +526,11 @@ void SIPAccount::setAccountDetails(const std::map<std::string, std::string> &det
     enablePresence(presenceEnabled);
 #endif
 
-    int tmpMin = -1;
-    parseInt(details, CONFIG_ACCOUNT_AUDIO_PORT_MIN, tmpMin);
-    int tmpMax = -1;
-    parseInt(details, CONFIG_ACCOUNT_AUDIO_PORT_MAX, tmpMax);
-    updateRange(tmpMin, tmpMax, audioPortRange_);
-#ifdef SFL_VIDEO
-    tmpMin = -1;
-    parseInt(details, CONFIG_ACCOUNT_VIDEO_PORT_MIN, tmpMin);
-    tmpMax = -1;
-    parseInt(details, CONFIG_ACCOUNT_VIDEO_PORT_MAX, tmpMax);
-    updateRange(tmpMin, tmpMax, videoPortRange_);
-#endif
-
     // srtp settings
-    parseBool(details, CONFIG_SRTP_ENABLE, srtpEnabled_);
-    parseBool(details, CONFIG_SRTP_RTP_FALLBACK, srtpFallback_);
     parseBool(details, CONFIG_ZRTP_DISPLAY_SAS, zrtpDisplaySas_);
     parseBool(details, CONFIG_ZRTP_DISPLAY_SAS_ONCE, zrtpDisplaySasOnce_);
     parseBool(details, CONFIG_ZRTP_NOT_SUPP_WARNING, zrtpNotSuppWarning_);
     parseBool(details, CONFIG_ZRTP_HELLO_HASH, zrtpHelloHash_);
-    auto iter = details.find(CONFIG_SRTP_KEY_EXCHANGE);
-    if (iter != details.end())
-        validate(srtpKeyExchange_, iter->second, VALID_SRTP_KEY_EXCHANGES);
 
     // TLS settings
     parseBool(details, CONFIG_TLS_ENABLE, tlsEnable_);
@@ -687,7 +540,7 @@ void SIPAccount::setAccountDetails(const std::map<std::string, std::string> &det
 
     parseString(details, CONFIG_TLS_PRIVATE_KEY_FILE, tlsPrivateKeyFile_);
     parseString(details, CONFIG_TLS_PASSWORD, tlsPassword_);
-    iter = details.find(CONFIG_TLS_METHOD);
+    auto iter = details.find(CONFIG_TLS_METHOD);
     if (iter != details.end())
         validate(tlsMethod_, iter->second, VALID_TLS_METHODS);
     parseString(details, CONFIG_TLS_CIPHERS, tlsCiphers_);
@@ -728,25 +581,12 @@ static std::string retrievePassword(const std::map<std::string, std::string>& ma
     return "";
 }
 
-
-
 std::map<std::string, std::string> SIPAccount::getAccountDetails() const
 {
-    std::map<std::string, std::string> a;
+    std::map<std::string, std::string> a = SIPAccountBase::getAccountDetails();
 
-    // note: The IP2IP profile will always have IP2IP as an alias
-    a[CONFIG_ACCOUNT_ALIAS] = alias_;
-
-    a[CONFIG_ACCOUNT_ENABLE] = enabled_ ? TRUE_STR : FALSE_STR;
-    a[CONFIG_ACCOUNT_AUTOANSWER] = autoAnswerEnabled_ ? TRUE_STR : FALSE_STR;
-    a[CONFIG_ACCOUNT_TYPE] = ACCOUNT_TYPE;
-    a[CONFIG_ACCOUNT_HOSTNAME] = hostname_;
-    a[CONFIG_ACCOUNT_USERNAME] = username_;
-    // get password for this username
     a[CONFIG_ACCOUNT_PASSWORD] = "";
-
     if (hasCredentials()) {
-
         for (const auto &vect_item : credentials_) {
             const std::string password = retrievePassword(vect_item, username_);
 
@@ -755,70 +595,40 @@ std::map<std::string, std::string> SIPAccount::getAccountDetails() const
         }
     }
 
-    a[CONFIG_RINGTONE_PATH] = ringtonePath_;
-    a[CONFIG_RINGTONE_ENABLED] = ringtoneEnabled_ ? TRUE_STR : FALSE_STR;
-    a[CONFIG_VIDEO_ENABLED] = videoEnabled_ ? TRUE_STR : FALSE_STR;
-    a[CONFIG_ACCOUNT_MAILBOX] = mailBox_;
-#ifdef SFL_PRESENCE
-    a[CONFIG_PRESENCE_ENABLED] = presence_ and presence_->isEnabled()? TRUE_STR : FALSE_STR;
-    a[CONFIG_PRESENCE_PUBLISH_SUPPORTED] = presence_ and presence_->isSupported(PRESENCE_FUNCTION_PUBLISH)? TRUE_STR : FALSE_STR;
-    a[CONFIG_PRESENCE_SUBSCRIBE_SUPPORTED] = presence_ and presence_->isSupported(PRESENCE_FUNCTION_SUBSCRIBE)? TRUE_STR : FALSE_STR;
-    // initialize status values
-    a[CONFIG_PRESENCE_STATUS] = presence_ and presence_->isOnline()? TRUE_STR : FALSE_STR;
-    a[CONFIG_PRESENCE_NOTE] = presence_ ? presence_->getNote() : " ";
-#endif
-
-    RegistrationState state = RegistrationState::UNREGISTERED;
     std::string registrationStateCode;
     std::string registrationStateDescription;
-
     if (isIP2IP())
         registrationStateDescription = "Direct IP call";
     else {
-        state = registrationState_;
         int code = registrationStateDetailed_.first;
         std::stringstream out;
         out << code;
         registrationStateCode = out.str();
         registrationStateDescription = registrationStateDetailed_.second;
     }
-
-    a[CONFIG_ACCOUNT_REGISTRATION_STATUS] = isIP2IP() ? "READY" : mapStateNumberToString(state);
     a[CONFIG_ACCOUNT_REGISTRATION_STATE_CODE] = registrationStateCode;
     a[CONFIG_ACCOUNT_REGISTRATION_STATE_DESC] = registrationStateDescription;
 
+#ifdef SFL_PRESENCE
+    a[CONFIG_PRESENCE_ENABLED] = presence_ and presence_->isEnabled()? TRUE_STR : FALSE_STR;
+    a[CONFIG_PRESENCE_PUBLISH_SUPPORTED] = presence_ and presence_->isSupported(PRESENCE_FUNCTION_PUBLISH)? TRUE_STR : FALSE_STR;
+    a[CONFIG_PRESENCE_SUBSCRIBE_SUPPORTED] = presence_ and presence_->isSupported(PRESENCE_FUNCTION_SUBSCRIBE)? TRUE_STR : FALSE_STR;
+    // initialize status values
+    a[CONFIG_PRESENCE_STATUS] = presence_ and presence_->isOnline()? TRUE_STR : FALSE_STR;
+    a[CONFIG_PRESENCE_NOTE] = presence_ ? presence_->getNote() : " ";
+#endif
+
     // Add sip specific details
     a[CONFIG_ACCOUNT_ROUTESET] = serviceRoute_;
-    a[CONFIG_ACCOUNT_USERAGENT] = hasCustomUserAgent_ ? userAgent_ : DEFAULT_USER_AGENT;
-    a[CONFIG_ACCOUNT_HAS_CUSTOM_USERAGENT] = hasCustomUserAgent_ ? TRUE_STR : FALSE_STR;
-
-    addRangeToDetails(a, CONFIG_ACCOUNT_AUDIO_PORT_MIN, CONFIG_ACCOUNT_AUDIO_PORT_MAX, audioPortRange_);
-#ifdef SFL_VIDEO
-    addRangeToDetails(a, CONFIG_ACCOUNT_VIDEO_PORT_MIN, CONFIG_ACCOUNT_VIDEO_PORT_MAX, videoPortRange_);
-#endif
 
     std::stringstream registrationExpireStr;
     registrationExpireStr << registrationExpire_;
     a[CONFIG_ACCOUNT_REGISTRATION_EXPIRE] = registrationExpireStr.str();
-    a[CONFIG_LOCAL_INTERFACE] = interface_;
-    a[CONFIG_PUBLISHED_SAMEAS_LOCAL] = publishedSameasLocal_ ? TRUE_STR : FALSE_STR;
-    a[CONFIG_PUBLISHED_ADDRESS] = publishedIpAddress_;
-
-    std::stringstream localport;
-    localport << localPort_;
-    a[CONFIG_LOCAL_PORT] = localport.str();
-    std::stringstream publishedport;
-    publishedport << publishedPort_;
-    a[CONFIG_PUBLISHED_PORT] = publishedport.str();
+
     a[CONFIG_STUN_ENABLE] = stunEnabled_ ? TRUE_STR : FALSE_STR;
     a[CONFIG_STUN_SERVER] = stunServer_;
-    a[CONFIG_ACCOUNT_DTMF_TYPE] = dtmfType_;
     a[CONFIG_KEEP_ALIVE_ENABLED] = keepAliveEnabled_ ? TRUE_STR : FALSE_STR;
 
-    a[CONFIG_SRTP_KEY_EXCHANGE] = srtpKeyExchange_;
-    a[CONFIG_SRTP_ENABLE] = srtpEnabled_ ? TRUE_STR : FALSE_STR;
-    a[CONFIG_SRTP_RTP_FALLBACK] = srtpFallback_ ? TRUE_STR : FALSE_STR;
-
     a[CONFIG_ZRTP_DISPLAY_SAS] = zrtpDisplaySas_ ? TRUE_STR : FALSE_STR;
     a[CONFIG_ZRTP_DISPLAY_SAS_ONCE] = zrtpDisplaySasOnce_ ? TRUE_STR : FALSE_STR;
     a[CONFIG_ZRTP_HELLO_HASH] = zrtpHelloHash_ ? TRUE_STR : FALSE_STR;
diff --git a/daemon/src/sip/sipaccount.h b/daemon/src/sip/sipaccount.h
index 0486fbf2cd..f9d1b0fcb5 100644
--- a/daemon/src/sip/sipaccount.h
+++ b/daemon/src/sip/sipaccount.h
@@ -107,7 +107,7 @@ class SIPAccount : public SIPAccountBase {
          * Serialize internal state of this account for configuration
          * @param out Emitter to which state will be saved
          */
-        void serialize(YAML::Emitter &out);
+        virtual void serialize(YAML::Emitter &out);
 
         /**
          * Populate the internal state for this account based on info stored in the configuration file
diff --git a/daemon/src/sip/sipaccountbase.cpp b/daemon/src/sip/sipaccountbase.cpp
index 32cc48b460..84608c36c1 100644
--- a/daemon/src/sip/sipaccountbase.cpp
+++ b/daemon/src/sip/sipaccountbase.cpp
@@ -32,12 +32,210 @@
 #include "sipaccountbase.h"
 #include "sipvoiplink.h"
 
+#ifdef SFL_VIDEO
+#include "video/libav_utils.h"
+#endif
+
+#include "account_schema.h"
+#include <yaml-cpp/yaml.h>
+#include "config/yamlparser.h"
+
 bool SIPAccountBase::portsInUse_[HALF_MAX_PORT];
 
+static const char *const VALID_SRTP_KEY_EXCHANGES[] = {"", "sdes", "zrtp"};
+
 SIPAccountBase::SIPAccountBase(const std::string& accountID)
     : Account(accountID), link_(getSIPVoIPLink())
 {}
 
+template <typename T>
+static void
+validate(std::string &member, const std::string &param, const T& valid)
+{
+    const auto begin = std::begin(valid);
+    const auto end = std::end(valid);
+    if (find(begin, end, param) != end)
+        member = param;
+    else
+        ERROR("Invalid parameter \"%s\"", param.c_str());
+}
+
+static void
+updateRange(int min, int max, std::pair<uint16_t, uint16_t> &range)
+{
+    if (min > 0 and (max > min) and max <= MAX_PORT - 2) {
+        range.first = min;
+        range.second = max;
+    }
+}
+
+static void
+unserializeRange(const YAML::Node &node, const char *minKey, const char *maxKey, std::pair<uint16_t, uint16_t> &range)
+{
+    int tmpMin = 0;
+    int tmpMax = 0;
+    yaml_utils::parseValue(node, minKey, tmpMin);
+    yaml_utils::parseValue(node, maxKey, tmpMax);
+    updateRange(tmpMin, tmpMax, range);
+}
+
+template <typename T>
+static void
+parseInt(const std::map<std::string, std::string> &details, const char *key, T &i)
+{
+    const auto iter = details.find(key);
+    if (iter == details.end()) {
+        ERROR("Couldn't find key %s", key);
+        return;
+    }
+    i = atoi(iter->second.c_str());
+}
+
+void SIPAccountBase::serialize(YAML::Emitter &out)
+{
+    using namespace Conf;
+
+    Account::serialize(out);
+
+    out << YAML::Key << AUDIO_PORT_MAX_KEY << YAML::Value << audioPortRange_.second;
+    out << YAML::Key << AUDIO_PORT_MIN_KEY << YAML::Value << audioPortRange_.first;
+    out << YAML::Key << DTMF_TYPE_KEY << YAML::Value << dtmfType_;
+    out << YAML::Key << INTERFACE_KEY << YAML::Value << interface_;
+    out << YAML::Key << PORT_KEY << YAML::Value << localPort_;
+    out << YAML::Key << PUBLISH_ADDR_KEY << YAML::Value << publishedIpAddress_;
+    out << YAML::Key << PUBLISH_PORT_KEY << YAML::Value << publishedPort_;
+    out << YAML::Key << SAME_AS_LOCAL_KEY << YAML::Value << publishedSameasLocal_;
+
+    // srtp submap
+    out << YAML::Key << SRTP_KEY << YAML::Value << YAML::BeginMap;
+    out << YAML::Key << SRTP_ENABLE_KEY << YAML::Value << srtpEnabled_;
+    out << YAML::Key << KEY_EXCHANGE_KEY << YAML::Value << srtpKeyExchange_;
+    out << YAML::Key << RTP_FALLBACK_KEY << YAML::Value << srtpFallback_;
+    out << YAML::EndMap;
+
+    out << YAML::Key << VIDEO_CODECS_KEY << YAML::Value << videoCodecList_;
+    out << YAML::Key << VIDEO_ENABLED_KEY << YAML::Value << videoEnabled_;
+    out << YAML::Key << VIDEO_PORT_MAX_KEY << YAML::Value << videoPortRange_.second;
+    out << YAML::Key << VIDEO_PORT_MIN_KEY << YAML::Value << videoPortRange_.first;
+}
+
+
+void SIPAccountBase::unserialize(const YAML::Node &node)
+{
+    using namespace Conf;
+    using namespace yaml_utils;
+
+    Account::unserialize(node);
+
+    parseValue(node, VIDEO_ENABLED_KEY, videoEnabled_);
+    const auto &vCodecNode = node[VIDEO_CODECS_KEY];
+    auto tmp = parseVectorMap(vCodecNode, {VIDEO_CODEC_BITRATE, VIDEO_CODEC_ENABLED, VIDEO_CODEC_NAME, VIDEO_CODEC_PARAMETERS});
+#ifdef SFL_VIDEO
+    if (tmp.empty()) {
+        // Video codecs are an empty list
+        WARN("Loading default video codecs");
+        tmp = libav_utils::getDefaultCodecs();
+    }
+#endif
+    // validate it
+    setVideoCodecs(tmp);
+
+    parseValue(node, INTERFACE_KEY, interface_);
+    int port = DEFAULT_SIP_PORT;
+    parseValue(node, PORT_KEY, port);
+    localPort_ = port;
+    parseValue(node, PUBLISH_ADDR_KEY, publishedIpAddress_);
+    parseValue(node, PUBLISH_PORT_KEY, port);
+    publishedPort_ = port;
+    parseValue(node, SAME_AS_LOCAL_KEY, publishedSameasLocal_);
+
+    parseValue(node, DTMF_TYPE_KEY, dtmfType_);
+
+    // get srtp submap
+    const auto &srtpMap = node[SRTP_KEY];
+    parseValue(srtpMap, SRTP_ENABLE_KEY, srtpEnabled_);
+
+    std::string tmpKey;
+    parseValue(srtpMap, KEY_EXCHANGE_KEY, tmpKey);
+    validate(srtpKeyExchange_, tmpKey, VALID_SRTP_KEY_EXCHANGES);
+    parseValue(srtpMap, RTP_FALLBACK_KEY, srtpFallback_);
+
+    unserializeRange(node, AUDIO_PORT_MIN_KEY, AUDIO_PORT_MAX_KEY, audioPortRange_);
+#ifdef SFL_VIDEO
+    unserializeRange(node, VIDEO_PORT_MIN_KEY, VIDEO_PORT_MAX_KEY, videoPortRange_);
+#endif
+}
+
+
+void SIPAccountBase::setAccountDetails(const std::map<std::string, std::string> &details)
+{
+	Account::setAccountDetails(details);
+
+    parseBool(details, CONFIG_VIDEO_ENABLED, videoEnabled_);
+
+    // general sip settings
+    parseString(details, CONFIG_LOCAL_INTERFACE, interface_);
+    parseBool(details, CONFIG_PUBLISHED_SAMEAS_LOCAL, publishedSameasLocal_);
+    parseString(details, CONFIG_PUBLISHED_ADDRESS, publishedIpAddress_);
+    parseInt(details, CONFIG_LOCAL_PORT, localPort_);
+    parseInt(details, CONFIG_PUBLISHED_PORT, publishedPort_);
+
+    parseString(details, CONFIG_ACCOUNT_DTMF_TYPE, dtmfType_);
+
+    int tmpMin = -1;
+    parseInt(details, CONFIG_ACCOUNT_AUDIO_PORT_MIN, tmpMin);
+    int tmpMax = -1;
+    parseInt(details, CONFIG_ACCOUNT_AUDIO_PORT_MAX, tmpMax);
+    updateRange(tmpMin, tmpMax, audioPortRange_);
+#ifdef SFL_VIDEO
+    tmpMin = -1;
+    parseInt(details, CONFIG_ACCOUNT_VIDEO_PORT_MIN, tmpMin);
+    tmpMax = -1;
+    parseInt(details, CONFIG_ACCOUNT_VIDEO_PORT_MAX, tmpMax);
+    updateRange(tmpMin, tmpMax, videoPortRange_);
+#endif
+
+    // srtp settings
+    parseBool(details, CONFIG_SRTP_ENABLE, srtpEnabled_);
+    parseBool(details, CONFIG_SRTP_RTP_FALLBACK, srtpFallback_);
+    auto iter = details.find(CONFIG_SRTP_KEY_EXCHANGE);
+    if (iter != details.end())
+        validate(srtpKeyExchange_, iter->second, VALID_SRTP_KEY_EXCHANGES);
+}
+
+std::map<std::string, std::string>
+SIPAccountBase::getAccountDetails() const
+{
+    std::map<std::string, std::string> a = Account::getAccountDetails();
+
+    // note: The IP2IP profile will always have IP2IP as an alias
+    a[CONFIG_VIDEO_ENABLED] = videoEnabled_ ? TRUE_STR : FALSE_STR;
+    a[CONFIG_ACCOUNT_REGISTRATION_STATUS] = isIP2IP() ? "READY" : mapStateNumberToString(registrationState_);
+
+    // Add sip specific details
+
+    addRangeToDetails(a, CONFIG_ACCOUNT_AUDIO_PORT_MIN, CONFIG_ACCOUNT_AUDIO_PORT_MAX, audioPortRange_);
+#ifdef SFL_VIDEO
+    addRangeToDetails(a, CONFIG_ACCOUNT_VIDEO_PORT_MIN, CONFIG_ACCOUNT_VIDEO_PORT_MAX, videoPortRange_);
+#endif
+
+    a[CONFIG_LOCAL_INTERFACE] = interface_;
+    a[CONFIG_PUBLISHED_SAMEAS_LOCAL] = publishedSameasLocal_ ? TRUE_STR : FALSE_STR;
+    a[CONFIG_PUBLISHED_ADDRESS] = publishedIpAddress_;
+
+    std::stringstream localport;
+    localport << localPort_;
+    a[CONFIG_LOCAL_PORT] = localport.str();
+    std::stringstream publishedport;
+    publishedport << publishedPort_;
+    a[CONFIG_PUBLISHED_PORT] = publishedport.str();
+
+    a[CONFIG_SRTP_KEY_EXCHANGE] = srtpKeyExchange_;
+    a[CONFIG_SRTP_ENABLE] = srtpEnabled_ ? TRUE_STR : FALSE_STR;
+    a[CONFIG_SRTP_RTP_FALLBACK] = srtpFallback_ ? TRUE_STR : FALSE_STR;
+    return a;
+}
+
 
 void
 SIPAccountBase::setTransport(pjsip_transport* transport, pjsip_tpfactory* lis)
diff --git a/daemon/src/sip/sipaccountbase.h b/daemon/src/sip/sipaccountbase.h
index 7eabf8c093..0cdf549b3f 100644
--- a/daemon/src/sip/sipaccountbase.h
+++ b/daemon/src/sip/sipaccountbase.h
@@ -131,6 +131,7 @@ public:
 
     virtual ~SIPAccountBase() = default;
 
+
     /**
      * Create incoming SIPCall.
      * @param[in] id The ID of the call
@@ -286,6 +287,13 @@ public:
 
 
 protected:
+    virtual void serialize(YAML::Emitter &out);
+    virtual void unserialize(const YAML::Node &node);
+
+    virtual void setAccountDetails(const std::map<std::string, std::string> &details);
+
+    virtual std::map<std::string, std::string> getAccountDetails() const;
+
     /**
      * Voice over IP Link contains a listener thread and calls
      */
-- 
GitLab