Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/201911
  • release/releaseWindowsTestOne
  • release/windowsReleaseTest
  • release/releaseTest
  • release/releaseWindowsTest
  • release/201910
  • release/qt/201910
  • release/windows-test/201910
  • release/201908
  • release/201906
  • release/201905
  • release/201904
  • release/201903
  • release/201902
  • release/201901
  • release/201812
  • 4.0.0
  • 2.2.0
  • 2.1.0
  • 2.0.1
  • 2.0.0
  • 1.4.1
  • 1.4.0
  • 1.3.0
  • 1.2.0
  • 1.1.0
30 results

sipaccount.cpp

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    sipaccount.cpp 31.77 KiB
    /*
     *  Copyright (C) 2004, 2005, 2006, 2009, 2008, 2009, 2010, 2011 Savoir-Faire Linux Inc.
    *
    *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
    *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
    *
    *  This program is free software; you can redistribute it and/or modify
    *  it under the terms of the GNU General Public License as published by
    *  the Free Software Foundation; either version 3 of the License, or
    *  (at your option) any later version.
    *
    *  This program is distributed in the hope that it will be useful,
    *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    *  GNU General Public License for more details.
    *
    *  You should have received a copy of the GNU General Public License
    *  along with this program; if not, write to the Free Software
    *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     *
     *  Additional permission under GNU GPL version 3 section 7:
     *
     *  If you modify this program, or any covered work, by linking or
     *  combining it with the OpenSSL project's OpenSSL library (or a
     *  modified version of that library), containing parts covered by the
     *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
     *  grants you additional permission to convey the resulting work.
     *  Corresponding Source for a non-source form of such a combination
     *  shall include the source code for the parts of OpenSSL used as well
     *  as that of the covered work.
    */
    
    #include "sipaccount.h"
    #include "manager.h"
    #include <pwd.h>
    #include <sstream>
    #include <cassert>
    
    namespace {
        const char * const DFT_STUN_SERVER = "stun.sflphone.org"; /** Default STUN server address */
        const char *DFT_EXPIRE_VALUE = "600"; /** Default expire value for registration */
    } // end anonymous namespace
    
    Credentials::Credentials() : credentialCount (0) {}
    
    Credentials::~Credentials() {}
    
    void Credentials::setNewCredential (const std::string &username,
                                        const std::string &password,
                                        const std::string &realm)
    {
        credentialArray[credentialCount].username = username;
        credentialArray[credentialCount].password = password;
        credentialArray[credentialCount].realm = realm;
    }
    
    const CredentialItem *Credentials::getCredential (unsigned index) const
    {
        if (index >= credentialCount)
    		return NULL;
        return &credentialArray[index];
    }
    
    void Credentials::serialize (Conf::YamlEmitter *emitter UNUSED)
    {
    }
    
    void Credentials::unserialize (Conf::MappingNode *map)
    {
        int count;
        map->getValue(credentialCountKey, &count);
        credentialCount = count;
    }
    
    namespace {
    static void free_cred(pjsip_cred_info *cred)
    {
        if (!cred)
            return;
    
        unsigned i;
        unsigned max = 1; /* getCredentialCount() see #6408 */ 
        for (i = 0 ; i < max ; i++) {
            free(cred[i].username.ptr);
            free(cred[i].data.ptr);
            free(cred[i].realm.ptr);
        }
        free (cred);
    }
    } // end anonymous namespace
    
    SIPAccount::SIPAccount (const AccountID& accountID)
        : Account (accountID, "SIP")
        , _routeSet ("")
        , _pool (NULL)
        , _regc (NULL)
        , _bRegister (false)
        , _registrationExpire ("")
        , _interface ("default")
        , _publishedSameasLocal (true)
        , _publishedIpAddress ("")
        , _localPort (atoi (DEFAULT_SIP_PORT))
        , _publishedPort (atoi (DEFAULT_SIP_PORT))
        , _serviceRoute ("")
        , _tlsListenerPort (atoi (DEFAULT_SIP_TLS_PORT))
        , _transportType (PJSIP_TRANSPORT_UNSPECIFIED)
        , _transport (NULL)
        , _resolveOnce (false)
        , _cred (NULL)
        , _realm (DEFAULT_REALM)
        , _authenticationUsername ("")
        , _tlsSetting (NULL)
        , _dtmfType (OVERRTP)
        , _tlsEnable ("false")
        , _tlsPortStr (DEFAULT_SIP_TLS_PORT)
        , _tlsCaListFile ("")
        , _tlsCertificateFile ("")
        , _tlsPrivateKeyFile ("")
        , _tlsPassword ("")
        , _tlsMethod ("TLSv1")
        , _tlsCiphers ("")
        , _tlsServerName ("")
        , _tlsVerifyServer (true)
        , _tlsVerifyClient (true)
        , _tlsRequireClientCertificate (true)
        , _tlsNegotiationTimeoutSec ("2")
        , _tlsNegotiationTimeoutMsec ("0")
        , _stunServer (DFT_STUN_SERVER)
        , _stunEnabled (false)
        , _srtpEnabled (false)
        , _srtpKeyExchange ("sdes")
        , _srtpFallback (false)
        , _zrtpDisplaySas (true)
        , _zrtpDisplaySasOnce (false)
        , _zrtpHelloHash (true)
        , _zrtpNotSuppWarning (true)
    {
        _stunServerName.ptr = NULL;
        _stunServerName.slen = 0;
        _stunPort = 0;
    }
    
    SIPAccount::~SIPAccount()
    {
        /* One SIP account less connected to the sip voiplink */
        if (_accountID != "default")
            dynamic_cast<SIPVoIPLink*> (_link)->decrementClients();
    
        /* Delete accounts-related information */
        _regc = NULL;
        free_cred(_cred);
        delete _tlsSetting;
    }
    
    void SIPAccount::serialize (Conf::YamlEmitter *emitter)
    {
    	if(emitter == NULL) {
    		_error("SIPAccount: Error: emitter is NULL in serialize");
    		return;
    	}
    
        Conf::MappingNode accountmap (NULL);
        Conf::MappingNode credentialmap (NULL);
        Conf::MappingNode srtpmap (NULL);
        Conf::MappingNode zrtpmap (NULL);
        Conf::MappingNode tlsmap (NULL);
    
        Conf::ScalarNode id (Account::_accountID);
        Conf::ScalarNode username (Account::_username);
        Conf::ScalarNode password (Account::_password);
        Conf::ScalarNode alias (Account::_alias);
        Conf::ScalarNode hostname (Account::_hostname);
        Conf::ScalarNode enable (_enabled);
        Conf::ScalarNode type (Account::_type);
        Conf::ScalarNode expire (_registrationExpire);
        Conf::ScalarNode interface (_interface);
        std::stringstream portstr;
        portstr << _localPort;
        Conf::ScalarNode port (portstr.str());
        Conf::ScalarNode serviceRoute (_serviceRoute);
    
        Conf::ScalarNode mailbox (_mailBox);
        Conf::ScalarNode publishAddr (_publishedIpAddress);
        std::stringstream publicportstr;
        publicportstr << _publishedPort;
        Conf::ScalarNode publishPort (publicportstr.str());
        Conf::ScalarNode sameasLocal (_publishedSameasLocal);
        Conf::ScalarNode resolveOnce (_resolveOnce);
        Conf::ScalarNode codecs (_codecStr);
        Conf::ScalarNode ringtonePath (_ringtonePath);
        Conf::ScalarNode ringtoneEnabled (_ringtoneEnabled);
        Conf::ScalarNode stunServer (_stunServer);
        Conf::ScalarNode stunEnabled (_stunEnabled);
        Conf::ScalarNode displayName (_displayName);
        Conf::ScalarNode dtmfType (_dtmfType==OVERRTP ? "overrtp" : "sipinfo");
    
        std::stringstream countstr;
        countstr << 0;
        Conf::ScalarNode count (countstr.str());
    
        Conf::ScalarNode srtpenabled (_srtpEnabled);
        Conf::ScalarNode keyExchange (_srtpKeyExchange);
        Conf::ScalarNode rtpFallback (_srtpFallback);
    
        Conf::ScalarNode displaySas (_zrtpDisplaySas);
        Conf::ScalarNode displaySasOnce (_zrtpDisplaySasOnce);
        Conf::ScalarNode helloHashEnabled (_zrtpHelloHash);
        Conf::ScalarNode notSuppWarning (_zrtpNotSuppWarning);
    
        Conf::ScalarNode tlsport (_tlsPortStr);
        Conf::ScalarNode certificate (_tlsCertificateFile);
        Conf::ScalarNode calist (_tlsCaListFile);
        Conf::ScalarNode ciphers (_tlsCiphers);
        Conf::ScalarNode tlsenabled (_tlsEnable);
        Conf::ScalarNode tlsmethod (_tlsMethod);
        Conf::ScalarNode timeout (_tlsNegotiationTimeoutSec);
        Conf::ScalarNode tlspassword (_tlsPassword);
        Conf::ScalarNode privatekey (_tlsPrivateKeyFile);
        Conf::ScalarNode requirecertif (_tlsRequireClientCertificate);
        Conf::ScalarNode server (_tlsServerName);
        Conf::ScalarNode verifyclient (_tlsVerifyServer);
        Conf::ScalarNode verifyserver (_tlsVerifyClient);
    
        accountmap.setKeyValue (aliasKey, &alias);
        accountmap.setKeyValue (typeKey, &type);
        accountmap.setKeyValue (idKey, &id);
        accountmap.setKeyValue (usernameKey, &username);
        accountmap.setKeyValue (passwordKey, &password);
        accountmap.setKeyValue (hostnameKey, &hostname);
        accountmap.setKeyValue (accountEnableKey, &enable);
        accountmap.setKeyValue (mailboxKey, &mailbox);
        accountmap.setKeyValue (expireKey, &expire);
        accountmap.setKeyValue (interfaceKey, &interface);
        accountmap.setKeyValue (portKey, &port);
        accountmap.setKeyValue (stunServerKey, &stunServer);
        accountmap.setKeyValue (stunEnabledKey, &stunEnabled);
        accountmap.setKeyValue (publishAddrKey, &publishAddr);
        accountmap.setKeyValue (publishPortKey, &publishPort);
        accountmap.setKeyValue (sameasLocalKey, &sameasLocal);
        accountmap.setKeyValue (resolveOnceKey, &resolveOnce);
        accountmap.setKeyValue (serviceRouteKey, &serviceRoute);
        accountmap.setKeyValue (dtmfTypeKey, &dtmfType);
        accountmap.setKeyValue (displayNameKey, &displayName);
        accountmap.setKeyValue (codecsKey, &codecs);
        accountmap.setKeyValue (ringtonePathKey, &ringtonePath);
        accountmap.setKeyValue (ringtoneEnabledKey, &ringtoneEnabled);
    
        accountmap.setKeyValue (srtpKey, &srtpmap);
        srtpmap.setKeyValue (srtpEnableKey, &srtpenabled);
        srtpmap.setKeyValue (keyExchangeKey, &keyExchange);
        srtpmap.setKeyValue (rtpFallbackKey, &rtpFallback);
    
        accountmap.setKeyValue (zrtpKey, &zrtpmap);
        zrtpmap.setKeyValue (displaySasKey, &displaySas);
        zrtpmap.setKeyValue (displaySasOnceKey, &displaySasOnce);
        zrtpmap.setKeyValue (helloHashEnabledKey, &helloHashEnabled);
        zrtpmap.setKeyValue (notSuppWarningKey, &notSuppWarning);
    
        accountmap.setKeyValue (credKey, &credentialmap);
        credentialmap.setKeyValue (credentialCountKey, &count);
    
        accountmap.setKeyValue (tlsKey, &tlsmap);
        tlsmap.setKeyValue (tlsPortKey, &tlsport);
        tlsmap.setKeyValue (certificateKey, &certificate);
        tlsmap.setKeyValue (calistKey, &calist);
        tlsmap.setKeyValue (ciphersKey, &ciphers);
        tlsmap.setKeyValue (tlsEnableKey, &tlsenabled);
        tlsmap.setKeyValue (methodKey, &tlsmethod);
        tlsmap.setKeyValue (timeoutKey, &timeout);
        tlsmap.setKeyValue (tlsPasswordKey, &tlspassword);
        tlsmap.setKeyValue (privateKeyKey, &privatekey);
        tlsmap.setKeyValue (requireCertifKey, &requirecertif);
        tlsmap.setKeyValue (serverKey, &server);
        tlsmap.setKeyValue (verifyClientKey, &verifyclient);
        tlsmap.setKeyValue (verifyServerKey, &verifyserver);
    
        try {
            emitter->serializeAccount (&accountmap);
        } catch (Conf::YamlEmitterException &e) {
            _error ("ConfigTree: %s", e.what());
        }
    }
    
    
    
    void SIPAccount::unserialize (Conf::MappingNode *map)
    {
        Conf::MappingNode *srtpMap;
        Conf::MappingNode *tlsMap;
        Conf::MappingNode *zrtpMap;
        Conf::MappingNode *credMap;
    
        assert(map);
    
        map->getValue(aliasKey, &_alias);
        map->getValue(typeKey, &_type);
        map->getValue(idKey, &_accountID);
        map->getValue(usernameKey, &_username);
        map->getValue(passwordKey, &_password);
        map->getValue(hostnameKey, &_hostname);
        map->getValue(accountEnableKey, &_enabled);
        map->getValue(mailboxKey, &_mailBox);
        map->getValue(codecsKey, &_codecStr);
        // Update codec list which one is used for SDP offer
        setActiveCodecs (Manager::instance ().unserialize (_codecStr));
    
        map->getValue(ringtonePathKey, &_ringtonePath);
        map->getValue(ringtoneEnabledKey, &_ringtoneEnabled);
        map->getValue(expireKey, &_registrationExpire);
        map->getValue(interfaceKey, &_interface);
        int port;
        map->getValue(portKey, &port);
        _localPort = port;
        map->getValue(publishAddrKey, &_publishedIpAddress);
        map->getValue(publishPortKey, &port);
        _publishedPort = port;
        map->getValue(sameasLocalKey, &_publishedSameasLocal);
        map->getValue(resolveOnceKey, &_resolveOnce);
    
        std::string dtmfType;
        map->getValue(dtmfTypeKey, &dtmfType);
        _dtmfType = (dtmfType == "overrtp") ? OVERRTP : SIPINFO;
    
        map->getValue(serviceRouteKey, &_serviceRoute);
        // stun enabled
        map->getValue(stunEnabledKey, &_stunEnabled);
        map->getValue(stunServerKey, &_stunServer);
    
        // Init stun server name with default server name
        _stunServerName = pj_str ( (char*) _stunServer.data());
    
        map->getValue(displayNameKey, &_displayName);
    
    
        credMap = (Conf::MappingNode *) (map->getValue (credKey));
        if (credMap)
            credentials.unserialize (credMap);
    
    
        // get srtp submap
        srtpMap = (Conf::MappingNode *) (map->getValue (srtpKey));
        if (!srtpMap)
            throw SipAccountException (" did not found srtp map");
    
        srtpMap->getValue(srtpEnableKey, &_srtpEnabled);
        srtpMap->getValue(keyExchangeKey, &_srtpKeyExchange);
        srtpMap->getValue(rtpFallbackKey, &_srtpFallback);
    
    
        // get zrtp submap
        zrtpMap = (Conf::MappingNode *) (map->getValue (zrtpKey));
        if (!zrtpMap)
            throw SipAccountException (" did not found zrtp map");
    
        zrtpMap->getValue(displaySasKey, &_zrtpDisplaySas);
        zrtpMap->getValue(displaySasOnceKey, &_zrtpDisplaySasOnce);
        zrtpMap->getValue(helloHashEnabledKey, &_zrtpHelloHash);
        zrtpMap->getValue(notSuppWarningKey, &_zrtpNotSuppWarning);
    
    
        // get tls submap
        tlsMap = (Conf::MappingNode *) (map->getValue (tlsKey));
        if (!tlsMap)
            throw SipAccountException (" did not found tls map");
    
        tlsMap->getValue(tlsEnableKey, &_tlsEnable);
        tlsMap->getValue(tlsPortKey, &_tlsPortStr);
        tlsMap->getValue(certificateKey, &_tlsCertificateFile);
        tlsMap->getValue(calistKey, &_tlsCaListFile);
        tlsMap->getValue(ciphersKey, &_tlsCiphers);
        tlsMap->getValue(methodKey, &_tlsMethod);
        tlsMap->getValue(tlsPasswordKey, &_tlsPassword);
        tlsMap->getValue(privateKeyKey, &_tlsPrivateKeyFile);
        tlsMap->getValue(requireCertifKey, &_tlsRequireClientCertificate);
        tlsMap->getValue(serverKey, &_tlsServerName);
        tlsMap->getValue(verifyClientKey, &_tlsVerifyServer);
        tlsMap->getValue(verifyServerKey, &_tlsVerifyClient);
        // FIXME
        tlsMap->getValue(timeoutKey, &_tlsNegotiationTimeoutSec);
        tlsMap->getValue(timeoutKey, &_tlsNegotiationTimeoutMsec);
    }
    
    
    void SIPAccount::setAccountDetails (std::map<std::string, std::string> details)
    {
    	std::string password, username;
    
        // Account setting common to SIP and IAX
        setAlias (details[CONFIG_ACCOUNT_ALIAS]);
        setType (details[CONFIG_ACCOUNT_TYPE]);
        username = details[USERNAME];
        setUsername (username);
        setHostname (details[HOSTNAME]);
        password = details[PASSWORD];
        setPassword (password);
        setEnabled ( (details[CONFIG_ACCOUNT_ENABLE] == "true"));
        setRingtonePath (details[CONFIG_RINGTONE_PATH]);
        setRingtoneEnabled ( (details[CONFIG_RINGTONE_ENABLED] == "true"));
        setMailBox (details[CONFIG_ACCOUNT_MAILBOX]);
    
        // SIP specific account settings
    
        // general sip settings
        setDisplayName (details[DISPLAY_NAME]);
        setServiceRoute (details[ROUTESET]);
        setLocalInterface (details[LOCAL_INTERFACE]);
        setPublishedSameasLocal (details[PUBLISHED_SAMEAS_LOCAL] == "true");
        setPublishedAddress (details[PUBLISHED_ADDRESS]);
        setLocalPort (atoi (details[LOCAL_PORT].c_str()));
        setPublishedPort (atoi (details[PUBLISHED_PORT].c_str()));
        setStunServer (details[STUN_SERVER]);
        setStunEnabled (details[STUN_ENABLE] == "true");
        setDtmfType ( (details[ACCOUNT_DTMF_TYPE] == "overrtp") ? OVERRTP : SIPINFO);
    
        setResolveOnce (details[CONFIG_ACCOUNT_RESOLVE_ONCE] == "true");
        setRegistrationExpire (details[CONFIG_ACCOUNT_REGISTRATION_EXPIRE]);
    
        // sip credential
        _realm = details[REALM];
        _authenticationUsername = details[AUTHENTICATION_USERNAME];
    
        setUseragent (details[USERAGENT]);
    
        // srtp settings
        setSrtpEnable (details[SRTP_ENABLE] == "true");
        setSrtpFallback (details[SRTP_RTP_FALLBACK] == "true");
        setZrtpDisplaySas (details[ZRTP_DISPLAY_SAS] == "true");
        setZrtpDiaplaySasOnce (details[ZRTP_DISPLAY_SAS_ONCE] == "true");
        setZrtpNotSuppWarning (details[ZRTP_NOT_SUPP_WARNING] == "true");
        setZrtpHelloHash (details[ZRTP_HELLO_HASH] == "true");
        setSrtpKeyExchange (details[SRTP_KEY_EXCHANGE]);
    
        // TLS settings
        // The TLS listener is unique and globally defined through IP2IP_PROFILE
        if (_accountID == IP2IP_PROFILE)
        	setTlsListenerPort (atoi (details[TLS_LISTENER_PORT].c_str()));
    
        setTlsEnable (details[TLS_ENABLE]);
        setTlsCaListFile (details[TLS_CA_LIST_FILE]);
        setTlsCertificateFile (details[TLS_CERTIFICATE_FILE]);
        setTlsPrivateKeyFile (details[TLS_PRIVATE_KEY_FILE]);
        setTlsPassword (details[TLS_PASSWORD]);
        setTlsMethod (details[TLS_METHOD]);
        setTlsCiphers (details[TLS_CIPHERS]);
        setTlsServerName (details[TLS_SERVER_NAME]);
        setTlsVerifyServer (details[TLS_VERIFY_SERVER] == "true");
        setTlsVerifyClient (details[TLS_VERIFY_CLIENT] == "true");
        setTlsRequireClientCertificate (details[TLS_REQUIRE_CLIENT_CERTIFICATE] == "true");
        setTlsNegotiationTimeoutSec (details[TLS_NEGOTIATION_TIMEOUT_SEC]);
        setTlsNegotiationTimeoutMsec (details[TLS_NEGOTIATION_TIMEOUT_MSEC]);
    
        if (!Manager::instance().preferences.getMd5Hash()) {
            setPassword (password);
        } else {
            // Make sure not to re-hash the password field if
            // it is already saved as a MD5 Hash.
            // TODO: This test is weak. Fix this.
            if ( (password.compare (getPassword()) != 0)) {
                _debug ("SipAccount: Password sent and password from config are different. Re-hashing");
    			std::string &authenticationUsername = _authenticationUsername.empty() ? username : _authenticationUsername;
                setPassword (Manager::instance().computeMd5HashFromCredential (authenticationUsername, password, _realm));
            }
        }
    }
    
    std::map<std::string, std::string> SIPAccount::getAccountDetails() const
    {
        std::map<std::string, std::string> a;
    
        a[ACCOUNT_ID] = _accountID;
        // The IP profile does not allow to set an alias
        a[CONFIG_ACCOUNT_ALIAS] = (_accountID == IP2IP_PROFILE) ? IP2IP_PROFILE : getAlias();
    
        a[CONFIG_ACCOUNT_ENABLE] = isEnabled() ? "true" : "false";
        a[CONFIG_ACCOUNT_TYPE] = getType();
        a[HOSTNAME] = getHostname();
        a[USERNAME] = getUsername();
        a[PASSWORD] = getPassword();
    
        a[CONFIG_RINGTONE_PATH] = getRingtonePath();
        a[CONFIG_RINGTONE_ENABLED] = getRingtoneEnabled() ? "true" : "false";
        a[CONFIG_ACCOUNT_MAILBOX] = getMailBox();
    
        RegistrationState state = Unregistered;
        std::string registrationStateCode;
        std::string registrationStateDescription;
    
        if (_accountID == IP2IP_PROFILE) {
            registrationStateCode = ""; // emtpy field
            registrationStateDescription = "Direct IP call";
        } else {
            state = getRegistrationState();
            int code = getRegistrationStateDetailed().first;
            std::stringstream out;
            out << code;
            registrationStateCode = out.str();
            registrationStateDescription = getRegistrationStateDetailed().second;
        }
    
        a[REGISTRATION_STATUS] = (_accountID == IP2IP_PROFILE) ? "READY": Manager::instance().mapStateNumberToString (state);
        a[REGISTRATION_STATE_CODE] = registrationStateCode;
        a[REGISTRATION_STATE_DESCRIPTION] = registrationStateDescription;
    
        // Add sip specific details
        a[ROUTESET] = getServiceRoute();
        a[CONFIG_ACCOUNT_RESOLVE_ONCE] = isResolveOnce() ? "true" : "false";
        a[REALM] = _realm;
        a[USERAGENT] = getUseragent();
    
        a[CONFIG_ACCOUNT_REGISTRATION_EXPIRE] = getRegistrationExpire();
        a[LOCAL_INTERFACE] = getLocalInterface();
        a[PUBLISHED_SAMEAS_LOCAL] = getPublishedSameasLocal() ? "true" : "false";
        a[PUBLISHED_ADDRESS] = getPublishedAddress();
    
        std::stringstream localport;
        localport << getLocalPort();
        a[LOCAL_PORT] = localport.str();
        std::stringstream publishedport;
        publishedport << getPublishedPort();
        a[PUBLISHED_PORT] = publishedport.str();
        a[STUN_ENABLE] = isStunEnabled() ? "true" : "false";
        a[STUN_SERVER] = getStunServer();
        a[ACCOUNT_DTMF_TYPE] = (getDtmfType() == OVERRTP) ? "overrtp" : "sipinfo";
    
        a[SRTP_KEY_EXCHANGE] = getSrtpKeyExchange();
        a[SRTP_ENABLE] = getSrtpEnable() ? "true" : "false";
        a[SRTP_RTP_FALLBACK] = getSrtpFallback() ? "true" : "false";
    
        a[ZRTP_DISPLAY_SAS] = getZrtpDisplaySas() ? "true" : "false";
        a[ZRTP_DISPLAY_SAS_ONCE] = getZrtpDiaplaySasOnce() ? "true" : "false";
        a[ZRTP_HELLO_HASH] = getZrtpHelloHash() ? "true" : "false";
        a[ZRTP_NOT_SUPP_WARNING] = getZrtpNotSuppWarning() ? "true" : "false";
    
        // TLS listener is unique and parameters are modified through IP2IP_PROFILE
        std::stringstream tlslistenerport;
        tlslistenerport << getTlsListenerPort();
        a[TLS_LISTENER_PORT] = tlslistenerport.str();
        a[TLS_ENABLE] = getTlsEnable();
        a[TLS_CA_LIST_FILE] = getTlsCaListFile();
        a[TLS_CERTIFICATE_FILE] = getTlsCertificateFile();
        a[TLS_PRIVATE_KEY_FILE] = getTlsPrivateKeyFile();
        a[TLS_PASSWORD] = getTlsPassword();
        a[TLS_METHOD] = getTlsMethod();
        a[TLS_CIPHERS] = getTlsCiphers();
        a[TLS_SERVER_NAME] = getTlsServerName();
        a[TLS_VERIFY_SERVER] = getTlsVerifyServer() ? "true" : "false";
        a[TLS_VERIFY_CLIENT] = getTlsVerifyClient() ? "true" : "false";
        a[TLS_REQUIRE_CLIENT_CERTIFICATE] = getTlsRequireClientCertificate() ? "true" : "false";
        a[TLS_NEGOTIATION_TIMEOUT_SEC] = getTlsNegotiationTimeoutSec();
        a[TLS_NEGOTIATION_TIMEOUT_MSEC] = getTlsNegotiationTimeoutMsec();
    
        return a;
    }
    
    
    // void SIPAccount::setVoIPLink(VoIPLink *link) {
    void SIPAccount::setVoIPLink()
    {
    
        _link = SIPVoIPLink::instance ("");
        dynamic_cast<SIPVoIPLink*> (_link)->incrementClients();
    
    }
    
    
    void SIPAccount::initCredential (void)
    {
        // We want to make sure that the password is really
        // 32 characters long. Otherwise, pjsip will fail
        // on an assertion.
        bool md5HashingEnabled = Manager::instance().preferences.getMd5Hash()
                                 && _password.length() == 32;
        int dataType = md5HashingEnabled ? PJSIP_CRED_DATA_DIGEST 
                                         : PJSIP_CRED_DATA_PLAIN_PASSWD;
        std::string digest;
    
        // Create the credential array
        free_cred(_cred);
        _cred = (pjsip_cred_info *) calloc(getCredentialCount(), sizeof (pjsip_cred_info));
    
        if (!_cred) {
            _error ("SipAccount: Error: Failed to set _cred for account %s", _accountID.c_str());
            return;
        }
    
        if (md5HashingEnabled )
            _debug ("Setting digest ");
    
        std::string &authenticationUsername = _authenticationUsername.empty() ? _username : _authenticationUsername;
        // Use authentication username if provided
        _cred[0].username = pj_str (strdup (authenticationUsername.c_str()));
    
        // Set password
        _cred[0].data =  pj_str (strdup (_password.c_str()));
    
        // Set realm for that credential. * by default.
        _cred[0].realm = pj_str (strdup (_realm.c_str()));
    
        _cred[0].data_type = dataType;
        _cred[0].scheme = pj_str ( (char*) "digest");
    
    #if 0 // FIXME, unused. see https://projects.savoirfairelinux.com/issues/6408
        unsigned i;
    
        // Default credential already initialized, use credentials.getCredentialCount()
        for (i = 0; i < credentials.getCredentialCount(); i++) {
    
            _cred[i].username = pj_str (strdup (_username.c_str()));
            _cred[i].data = pj_str (strdup (_password.c_str()));
            _cred[i].realm = pj_str (strdup (_realm.c_str()));
    
            _cred[i].data_type = dataType;
    
            _cred[i].scheme = pj_str ( (char*) "digest");
    
            _debug ("Setting credential %u realm = %s passwd = %s username = %s data_type = %d", i, _realm.c_str(), _password.c_str(), _username.c_str(), _cred[i].data_type);
        }
    #endif
    }
    
    
    int SIPAccount::registerVoIPLink()
    {
        if (_hostname.length() >= PJ_MAX_HOSTNAME) {
            return 1;
        }
    
        // Init set of additional credentials, if supplied by the user
        initCredential();
    
        // Init TLS settings if the user wants to use TLS
        if (_tlsEnable == "true") {
            _debug ("SIPAccount: TLS is enabled for account %s", getAccountID().c_str());
            _transportType = PJSIP_TRANSPORT_TLS;
            initTlsConfiguration();
        }
    
        // Init STUN settings for this account if the user selected it
        if (_stunEnabled) {
            _transportType = PJSIP_TRANSPORT_START_OTHER;
            initStunConfiguration ();
        } else {
            _stunServerName = pj_str ( (char*) _stunServer.data());
        }
    
        try {
            // In our definition of the ip2ip profile (aka Direct IP Calls),
            // no registration should be performed
            if (_accountID != IP2IP_PROFILE) {
                _link->sendRegister (_accountID);
            }
        }
        catch(VoipLinkException &e) {
            _error("SIPAccount: %s", e.what());
        }
    
        return 0;
    }
    
    int SIPAccount::unregisterVoIPLink()
    {
        if (_accountID == IP2IP_PROFILE) {
            return true;
        }
    
        try {
            _link->sendUnregister (_accountID);
            setRegistrationInfo (NULL);
        }
        catch(VoipLinkException &e) {
            _error("SIPAccount: %s", e.what());
            return false;
        }
    
        return true;
    }
    
    pjsip_ssl_method SIPAccount::sslMethodStringToPjEnum (const std::string& method)
    {
        if (method == "Default")
            return PJSIP_SSL_UNSPECIFIED_METHOD;
    
        if (method == "TLSv1")
            return PJSIP_TLSV1_METHOD;
    
        if (method == "SSLv2")
            return PJSIP_SSLV2_METHOD;
    
        if (method == "SSLv3")
            return PJSIP_SSLV3_METHOD;
    
        if (method == "SSLv23")
            return PJSIP_SSLV23_METHOD;
    
        return PJSIP_SSL_UNSPECIFIED_METHOD;
    }
    
    void SIPAccount::initTlsConfiguration (void)
    {
        // TLS listener is unique and should be only modified through IP2IP_PROFILE
    
        // setTlsListenerPort(atoi(tlsPortStr.c_str()));
        setTlsListenerPort (atoi (_tlsPortStr.c_str()));
    
        delete _tlsSetting;
        _tlsSetting = new pjsip_tls_setting;
    
        assert (_tlsSetting);
    
        pjsip_tls_setting_default (_tlsSetting);
    
        pj_cstr (&_tlsSetting->ca_list_file, _tlsCaListFile.c_str());
        pj_cstr (&_tlsSetting->cert_file, _tlsCertificateFile.c_str());
        pj_cstr (&_tlsSetting->privkey_file, _tlsPrivateKeyFile.c_str());
        pj_cstr (&_tlsSetting->password, _tlsPassword.c_str());
        _tlsSetting->method = sslMethodStringToPjEnum (_tlsMethod);
        pj_cstr (&_tlsSetting->ciphers, _tlsCiphers.c_str());
        pj_cstr (&_tlsSetting->server_name, _tlsServerName.c_str());
    
        _tlsSetting->verify_server = _tlsVerifyServer ? PJ_TRUE: PJ_FALSE;
        _tlsSetting->verify_client = _tlsVerifyClient ? PJ_TRUE: PJ_FALSE;
        _tlsSetting->require_client_cert = _tlsRequireClientCertificate ? PJ_TRUE: PJ_FALSE;
    
        _tlsSetting->timeout.sec = atol (_tlsNegotiationTimeoutSec.c_str());
        _tlsSetting->timeout.msec = atol (_tlsNegotiationTimeoutMsec.c_str());
    }
    
    void SIPAccount::initStunConfiguration (void)
    {
        size_t pos;
        std::string stunServer, serverName, serverPort;
    
        stunServer = _stunServer;
        // Init STUN socket
        pos = stunServer.find (':');
    
        if (pos == std::string::npos) {
            _stunServerName = pj_str ( (char*) stunServer.data());
            _stunPort = PJ_STUN_PORT;
            //stun_status = pj_sockaddr_in_init (&stun_srv.ipv4, &stun_adr, (pj_uint16_t) 3478);
        } else {
            serverName = stunServer.substr (0, pos);
            serverPort = stunServer.substr (pos + 1);
            _stunPort = atoi (serverPort.data());
            _stunServerName = pj_str ( (char*) serverName.data());
            //stun_status = pj_sockaddr_in_init (&stun_srv.ipv4, &stun_adr, (pj_uint16_t) nPort);
        }
    }
    
    void SIPAccount::loadConfig()
    {
        if (_registrationExpire.empty())
            _registrationExpire = DFT_EXPIRE_VALUE;
    
        if (_tlsEnable == "true") {
            initTlsConfiguration();
            _transportType = PJSIP_TRANSPORT_TLS;
        } else {
            _transportType = PJSIP_TRANSPORT_UDP;
        }
    
        // Account generic
        Account::loadConfig();
    }
    
    bool SIPAccount::fullMatch (const std::string& username, const std::string& hostname) const
    {
        return (userMatch (username) && hostnameMatch (hostname));
    }
    
    bool SIPAccount::userMatch (const std::string& username) const
    {
        if (username.empty()) {
            return false;
        }
    
        return (username == getUsername());
    }
    
    bool SIPAccount::hostnameMatch (const std::string& hostname) const
    {
        return (hostname == getHostname());
    }
    
    std::string SIPAccount::getMachineName (void) const
    {
        std::string hostname;
        hostname = std::string (pj_gethostname()->ptr, pj_gethostname()->slen);
        return hostname;
    }
    
    std::string SIPAccount::getLoginName (void) const
    {
        std::string username;
    
        uid_t uid = getuid();
    
        struct passwd * user_info = NULL;
        user_info = getpwuid (uid);
    
        if (user_info != NULL) {
            username = user_info->pw_name;
        }
    
        return username;
    }
    
    std::string SIPAccount::getTransportMapKey (void) const
    {
    
        std::stringstream out;
        out << getLocalPort();
        std::string localPort = out.str();
    
        return localPort;
    }
    
    
    std::string SIPAccount::getFromUri (void) const
    {
        char uri[PJSIP_MAX_URL_SIZE];
    
        std::string scheme;
        std::string transport;
        std::string username = _username;
        std::string hostname = _hostname;
    
        // UDP does not require the transport specification
    
        if (_transportType == PJSIP_TRANSPORT_TLS) {
            scheme = "sips:";
            transport = ";transport=" + std::string (pjsip_transport_get_type_name (_transportType));
        } else {
            scheme = "sip:";
            transport = "";
        }
    
        // Get login name if username is not specified
        if (_username.empty()) {
            username = getLoginName();
        }
    
    
        // Get machine hostname if not provided
        if (_hostname.empty()) {
            hostname = getMachineName();
        }
    
    
        int len = pj_ansi_snprintf (uri, PJSIP_MAX_URL_SIZE,
    
                "<%s%s@%s%s>",
                scheme.c_str(),
                username.c_str(),
                hostname.c_str(),
                transport.c_str());
    
        return std::string (uri, len);
    }
    
    std::string SIPAccount::getToUri (const std::string& username) const
    {
        char uri[PJSIP_MAX_URL_SIZE];
    
        std::string scheme;
        std::string transport;
        std::string hostname = "";
    
        // UDP does not require the transport specification
        if (_transportType == PJSIP_TRANSPORT_TLS) {
            scheme = "sips:";
            transport = ";transport=" + std::string (pjsip_transport_get_type_name (_transportType));
        } else {
            scheme = "sip:";
            transport = "";
        }
    
        // Check if scheme is already specified
        if (username.find ("sip") == 0) {
            scheme = "";
        }
    
        // Check if hostname is already specified
        if (username.find ("@") == std::string::npos) {
            // hostname not specified
            hostname = _hostname;
        }
    
        int len = pj_ansi_snprintf (uri, PJSIP_MAX_URL_SIZE,
    
                "<%s%s%s%s%s>",
                scheme.c_str(),
                username.c_str(),
                (hostname.empty()) ? "" : "@",
                hostname.c_str(),
                transport.c_str());
    
        return std::string (uri, len);
    }
    
    std::string SIPAccount::getServerUri (void) const
    {
        char uri[PJSIP_MAX_URL_SIZE];
    
        std::string scheme;
        std::string transport;
        std::string hostname = _hostname;
    
        // UDP does not require the transport specification
    
        if (_transportType == PJSIP_TRANSPORT_TLS) {
            scheme = "sips:";
            transport = ";transport=" + std::string (pjsip_transport_get_type_name (_transportType));
        } else {
            scheme = "sip:";
            transport = "";
        }
    
        int len = pj_ansi_snprintf (uri, PJSIP_MAX_URL_SIZE,
                "<%s%s%s>",
                scheme.c_str(),
                hostname.c_str(),
                transport.c_str());
    
        return std::string (uri, len);
    }
    
    std::string SIPAccount::getContactHeader (const std::string& address, const std::string& port) const
    {
        char contact[PJSIP_MAX_URL_SIZE];
        const char * beginquote, * endquote;
    
        std::string scheme;
        std::string transport;
    
        // if IPV6, should be set to []
        beginquote = endquote = "";
    
        // UDP does not require the transport specification
    
        if (_transportType == PJSIP_TRANSPORT_TLS) {
            scheme = "sips:";
            transport = ";transport=" + std::string (pjsip_transport_get_type_name (_transportType));
        } else {
            scheme = "sip:";
            transport = "";
        }
    
        _debug ("Display Name: %s", _displayName.c_str());
    
        int len = pj_ansi_snprintf (contact, PJSIP_MAX_URL_SIZE,
    
                "%s%s<%s%s%s%s%s%s:%d%s>",
                _displayName.c_str(),
                (_displayName.empty() ? "" : " "),
                scheme.c_str(),
                _username.c_str(),
                (_username.empty() ? "":"@"),
                beginquote,
                address.c_str(),
                endquote,
                atoi (port.c_str()),
                transport.c_str());
    
        return std::string (contact, len);
    }