From 489cf2b2357faee4be85438b0369f1f0f1d9849b Mon Sep 17 00:00:00 2001
From: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com>
Date: Fri, 28 Sep 2018 11:34:59 -0400
Subject: [PATCH] conversationmodel: fix uncatched std::out_of_range

ContactModel::getContact() raises std::out_of_range if it fails to
find the contact. Calls to getContact() should always be protected by
a try catch block.

Change-Id: I4208a72b8ed205ea5811ca0e2f10b745c82b33e5
Reviewed-by: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
---
 src/conversationmodel.cpp | 115 ++++++++++++++++++++------------------
 1 file changed, 60 insertions(+), 55 deletions(-)

diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp
index 7a22eb1b..5ed1d9fd 100644
--- a/src/conversationmodel.cpp
+++ b/src/conversationmodel.cpp
@@ -291,68 +291,73 @@ ConversationModel::allFilteredConversations() const
         pimpl_->conversations.begin(), pimpl_->conversations.end(),
         pimpl_->filteredConversations.begin(),
         [this] (const conversation::Info& entry) {
-            auto contactInfo = owner.contactModel->getContact(entry.participants.front());
-
-            auto filter = pimpl_->filter;
-            auto uri = URI(QString(filter.c_str()));
-            bool stripScheme = (uri.schemeType() == URI::SchemeType::NONE) || (uri.schemeType() == URI::SchemeType::RING);
-            FlagPack<URI::Section> flags = URI::Section::USER_INFO | URI::Section::HOSTNAME | URI::Section::PORT;
-            if (!stripScheme) {
-                flags |= URI::Section::SCHEME;
-            }
+            try {
+                auto contactInfo = owner.contactModel->getContact(entry.participants.front());
+
+                auto filter = pimpl_->filter;
+                auto uri = URI(QString(filter.c_str()));
+                bool stripScheme = (uri.schemeType() == URI::SchemeType::NONE) || (uri.schemeType() == URI::SchemeType::RING);
+                FlagPack<URI::Section> flags = URI::Section::USER_INFO | URI::Section::HOSTNAME | URI::Section::PORT;
+                if (!stripScheme) {
+                    flags |= URI::Section::SCHEME;
+                }
 
-            filter = uri.format(flags).toStdString();
+                filter = uri.format(flags).toStdString();
 
-            /* Check contact */
-            // If contact is banned, only match if filter is a perfect match
-            if (contactInfo.isBanned) {
-                if (filter == "") return false;
-                return contactInfo.profileInfo.uri == filter
-                       || contactInfo.profileInfo.alias == filter
-                       || contactInfo.registeredName == filter;
-            }
+                /* Check contact */
+                // If contact is banned, only match if filter is a perfect match
+                if (contactInfo.isBanned) {
+                    if (filter == "") return false;
+                    return contactInfo.profileInfo.uri == filter
+                           || contactInfo.profileInfo.alias == filter
+                           || contactInfo.registeredName == filter;
+                }
 
-            std::regex regexFilter;
-            auto isValidReFilter = true;
-            try {
-                regexFilter = std::regex(filter, std::regex_constants::icase);
-            } catch(std::regex_error&) {
-                isValidReFilter = false;
-            }
+                std::regex regexFilter;
+                auto isValidReFilter = true;
+                try {
+                    regexFilter = std::regex(filter, std::regex_constants::icase);
+                } catch(std::regex_error&) {
+                    isValidReFilter = false;
+                }
 
-            auto filterUriAndReg = [regexFilter, isValidReFilter](auto contact, auto filter) {
-                auto result = contact.profileInfo.uri.find(filter) != std::string::npos
-                || contact.registeredName.find(filter) != std::string::npos;
-                if (!result) {
-                    auto regexFound = isValidReFilter? (!contact.profileInfo.uri.empty()
-                           && std::regex_search(contact.profileInfo.uri, regexFilter))
-                           || std::regex_search(contact.registeredName, regexFilter) : false;
-                    result |= regexFound;
+                auto filterUriAndReg = [regexFilter, isValidReFilter](auto contact, auto filter) {
+                    auto result = contact.profileInfo.uri.find(filter) != std::string::npos
+                    || contact.registeredName.find(filter) != std::string::npos;
+                    if (!result) {
+                        auto regexFound = isValidReFilter? (!contact.profileInfo.uri.empty()
+                               && std::regex_search(contact.profileInfo.uri, regexFilter))
+                               || std::regex_search(contact.registeredName, regexFilter) : false;
+                        result |= regexFound;
+                    }
+                    return result;
+                };
+
+                /* Check type */
+                if (pimpl_->typeFilter != profile::Type::PENDING) {
+                    // Remove pending contacts and get the temporary item if filter is not empty
+                    switch (contactInfo.profileInfo.type) {
+                    case profile::Type::INVALID:
+                    case profile::Type::PENDING:
+                        return false;
+                    case profile::Type::TEMPORARY:
+                        return filterUriAndReg(contactInfo, filter);
+                    }
+                } else {
+                    // We only want pending requests matching with the filter
+                    if (contactInfo.profileInfo.type != profile::Type::PENDING)
+                        return false;
                 }
+
+                // Otherwise perform usual regex search
+                bool result = contactInfo.profileInfo.alias.find(filter) != std::string::npos;
+                if (!result && isValidReFilter) result |= std::regex_search(contactInfo.profileInfo.alias, regexFilter);
+                if (!result) result |= filterUriAndReg(contactInfo, filter);
                 return result;
-            };
-
-            /* Check type */
-            if (pimpl_->typeFilter != profile::Type::PENDING) {
-                // Remove pending contacts and get the temporary item if filter is not empty
-                switch (contactInfo.profileInfo.type) {
-                case profile::Type::INVALID:
-                case profile::Type::PENDING:
-                    return false;
-                case profile::Type::TEMPORARY:
-                    return filterUriAndReg(contactInfo, filter);
-                }
-            } else {
-                // We only want pending requests matching with the filter
-                if (contactInfo.profileInfo.type != profile::Type::PENDING)
-                    return false;
+            } catch (std::out_of_range&) {
+                // getContact() failed
+                return false;
             }
-
-            // Otherwise perform usual regex search
-            bool result = contactInfo.profileInfo.alias.find(filter) != std::string::npos;
-            if (!result && isValidReFilter) result |= std::regex_search(contactInfo.profileInfo.alias, regexFilter);
-            if (!result) result |= filterUriAndReg(contactInfo, filter);
-            return result;
     });
     pimpl_->filteredConversations.resize(std::distance(pimpl_->filteredConversations.begin(), it));
     pimpl_->dirtyConversations.first = false;
-- 
GitLab