diff --git a/src/manager.cpp b/src/manager.cpp index ccafe6ae34a96bb766cf2705f2786092379c5fce..e3f91c25f43b9645bdb0ed0cff09d6b9587f4067 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -458,6 +458,17 @@ Manager::switchCall(const std::shared_ptr<Call>& call) switchCall(call->getCallId()); } +template <class T> +inline std::shared_ptr<T> +Manager::findAccount(const std::function<bool(const std::shared_ptr<T>&)>& pred) +{ + for (const auto& account : getAllAccounts<T>()) { + if (pred(account)) + return account; + } + return {}; +} + /////////////////////////////////////////////////////////////////////////////// // Management of events' IP-phone user /////////////////////////////////////////////////////////////////////////////// @@ -2842,42 +2853,40 @@ Manager::getAudioDriver() } std::shared_ptr<Call> -Manager::newOutgoingCall(const std::string& toUrl, - const std::string& preferredAccountId) +Manager::newOutgoingCall(const std::string& toUrl, const std::string& preferredAccountId) { - auto preferred = getAccount(preferredAccountId); + auto account = getAccount(preferredAccountId); + if (account and !account->isUsable()) { + RING_WARN("Prefered account is not usable for calling"); + account = nullptr; + } + // If no prefered or not suitable account given, + // find first usable account depending on url scheme. if (toUrl.find("ring:") != std::string::npos) { - if (preferred && preferred->getAccountType() == RingAccount::ACCOUNT_TYPE) - return preferred->newOutgoingCall(toUrl); - auto dhtAcc = getAllAccounts<RingAccount>(); - for (const auto& acc : dhtAcc) - if (acc->isEnabled()) - return acc->newOutgoingCall(toUrl); - } - // If peer url is an IP, and the preferred account is not an "IP2IP like", - // we try to find a suitable one in all SIPAccount's. - auto strippedToUrl = toUrl; - sip_utils::stripSipUriPrefix(strippedToUrl); // FIXME: have a generic version to remove sip dependency - if (IpAddr::isValid(strippedToUrl) and !preferred->isIP2IP()) { - std::shared_ptr<Account> ip2ip_acc; - for (const auto& acc : getAllAccounts<SIPAccount>()) - if (acc->isEnabled() and acc->isIP2IP()) - ip2ip_acc = acc; - if (!ip2ip_acc) { - RING_ERR("No suitable IP2IP account found to call '%s'", toUrl.c_str()); - return nullptr; + if (!account or account->getAccountType() != RingAccount::ACCOUNT_TYPE) { + account = findAccount<RingAccount>([](const std::shared_ptr<RingAccount>& acc){ + return acc->isUsable(); + }); } - preferred = ip2ip_acc; + } else if (!account or account->getAccountType() != SIPAccount::ACCOUNT_TYPE) { + // For IP url restricts results on IP2IP accounts + auto strippedToUrl = toUrl; + sip_utils::stripSipUriPrefix(strippedToUrl); + auto only_ip = IpAddr::isValid(strippedToUrl); + + account = findAccount<SIPAccount>([only_ip](const std::shared_ptr<SIPAccount>& acc) { + return acc->isUsable() + and (!only_ip or acc->isIP2IP()); + }); } - // Sanity checks - if (!preferred or !preferred->isUsable()) { - RING_ERR("No suitable account found to create outgoing call"); + if (!account) { + RING_ERR("No suitable account to create outgoing call"); return nullptr; } - return preferred->newOutgoingCall(toUrl); + return account->newOutgoingCall(toUrl); } #ifdef RING_VIDEO diff --git a/src/manager.h b/src/manager.h index 7c5227c489909bf04b558b1f662d122ba29b4d5d..ef4a36d2602047221d8625d52cc8c05e7e0d1dce 100644 --- a/src/manager.h +++ b/src/manager.h @@ -1073,6 +1073,9 @@ class Manager { #endif void bindCallToConference(Call& call, Conference& conf); + + template <class T> + std::shared_ptr<T> findAccount(const std::function<bool(const std::shared_ptr<T>&)>&); }; // Helper to install a callback to be called once by the main event loop