~aleteoryx/muditaos

0342eb50c845e51c10b67fa5acfaed6964899379 — rrandomsky 3 years ago 6d7a2eb
[MOS-737] Fix for adding a country code prefix to existing contact

Adding or removing country code from existing contacts number is
changing now number record itself, exactly when changed number
is placed in DB, instead to create new number record, to avoid
miss match during matching numbers.
M module-apps/application-phonebook/windows/PhonebookNewContact.cpp => module-apps/application-phonebook/windows/PhonebookNewContact.cpp +6 -4
@@ 149,10 149,10 @@ namespace gui
            case DBServiceAPI::ContactVerificationResult::emptyContact:
                return false;
            case DBServiceAPI::ContactVerificationResult::primaryNumberDuplicate:
                showDialogDuplicatedNumber(contact->numbers[0].number);
                showDialogDuplicatedNumber(contact->numbers[0].number, contact->ID);
                return false;
            case DBServiceAPI::ContactVerificationResult::secondaryNumberDuplicate:
                showDialogDuplicatedNumber(contact->numbers[1].number);
                showDialogDuplicatedNumber(contact->numbers[1].number, contact->ID);
                return false;
            case DBServiceAPI::ContactVerificationResult::speedDialDuplicate:
                showDialogDuplicatedSpeedDialNumber();


@@ 191,9 191,11 @@ namespace gui
        return true;
    } // namespace gui

    void PhonebookNewContact::showDialogDuplicatedNumber(const utils::PhoneNumber::View &duplicatedNumber)
    void PhonebookNewContact::showDialogDuplicatedNumber(const utils::PhoneNumber::View &duplicatedNumber,
                                                         const std::uint32_t duplicatedNumberContactID)
    {
        auto matchedContact   = DBServiceAPI::MatchContactByPhoneNumber(application, duplicatedNumber);
        auto matchedContact =
            DBServiceAPI::MatchContactByPhoneNumber(application, duplicatedNumber, duplicatedNumberContactID);
        auto oldContactRecord = (matchedContact != nullptr) ? *matchedContact : ContactRecord{};
        auto metaData         = std::make_unique<gui::DialogMetadataMessage>(
            gui::DialogMetadata{duplicatedNumber.getFormatted(),

M module-apps/application-phonebook/windows/PhonebookNewContact.hpp => module-apps/application-phonebook/windows/PhonebookNewContact.hpp +3 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 35,7 35,8 @@ namespace gui
        };

        auto verifyAndSave() -> bool;
        void showDialogDuplicatedNumber(const utils::PhoneNumber::View &duplicatedNumber);
        void showDialogDuplicatedNumber(const utils::PhoneNumber::View &duplicatedNumber,
                                        const std::uint32_t duplicatedNumberContactID = 0u);
        void showDialogDuplicatedSpeedDialNumber();
        void setSaveButtonVisible(bool visible);


M module-db/Interface/ContactRecord.cpp => module-db/Interface/ContactRecord.cpp +37 -7
@@ 123,10 123,37 @@ auto ContactRecordInterface::Update(const ContactRecord &rec) -> bool
        return false;
    }

    auto oldNumberIDs  = splitNumberIDs(contact.numbersID);
    auto newNumbersIDs = getNumbersIDs(contact.ID, rec);
    auto oldNumberIDs = splitNumberIDs(contact.numbersID);

    /* Changing number table record in place if new number is same as old number but with/without country code */
    auto numberMatcher = buildNumberMatcher(NumberMatcherPageSize);
    for (const auto oldNumberID : oldNumberIDs) { // pick one of the old number for this contactID (from DB)
        auto numberRecord = contactDB->number.getById(oldNumberID);
        utils::PhoneNumber oldPhoneNumber(numberRecord.numberUser, numberRecord.numbere164);
        for (const auto &newNumberID : rec.numbers) { // pick one of the new number from &rec
            utils::PhoneNumber newPhoneNumber(newNumberID.number);
            // if DB have not such a new number already and if one of this have country code and other doesn't
            if (!numberMatcher.bestMatch(newPhoneNumber, utils::PhoneNumber::Match::EXACT).has_value() &&
                (newPhoneNumber.match(oldPhoneNumber) == utils::PhoneNumber::Match::POSSIBLE) &&
                ((!oldPhoneNumber.isValid() && newPhoneNumber.isValid()) ||
                 (oldPhoneNumber.isValid() && !newPhoneNumber.isValid()))) {
                // which means that only country code is to add or remove (change of country code is not supported here)
                // then change old number record in number table to the new number
                auto oldNumberRecordToUpdate       = contactDB->number.getById(oldNumberID);
                oldNumberRecordToUpdate.numberUser = newPhoneNumber.get();
                oldNumberRecordToUpdate.numbere164 = newPhoneNumber.toE164();
                if (!contactDB->number.update(oldNumberRecordToUpdate)) {
                    return false;
                }
            }
        }
    }

    auto newNumbersIDs = getNumbersIDs(contact.ID, rec, utils::PhoneNumber::Match::EXACT);
    for (auto oldNumberID : oldNumberIDs) {
        if (std::find(std::begin(newNumbersIDs), std::end(newNumbersIDs), oldNumberID) == std::end(newNumbersIDs)) {
            // If any oldNumberID is NOT one of the newNumbersID, which will be assigned to this contact, then
            // make temporary contact with this oldNumberID
            auto numberRecord = contactDB->number.getById(oldNumberID);
            if (!numberRecord.isValid()) {
                return false;


@@ 141,6 168,7 @@ auto ContactRecordInterface::Update(const ContactRecord &rec) -> bool
                          e.what());
                return false;
            }
            // make temporary contact with old number
            const auto tmpContactRecord = addTemporaryContactForNumber(number);
            if (!tmpContactRecord.has_value()) {
                return false;


@@ 195,8 223,9 @@ auto ContactRecordInterface::Update(const ContactRecord &rec) -> bool
    return true;
}

auto ContactRecordInterface::getNumbersIDs(std::uint32_t contactID, const ContactRecord &contact)
    -> std::vector<std::uint32_t>
auto ContactRecordInterface::getNumbersIDs(std::uint32_t contactID,
                                           const ContactRecord &contact,
                                           utils::PhoneNumber::Match matchLevel) -> std::vector<std::uint32_t>
{
    std::vector<std::uint32_t> result;



@@ 213,7 242,7 @@ auto ContactRecordInterface::getNumbersIDs(std::uint32_t contactID, const Contac
            return {};
        }

        auto numberMatch = numberMatcher.bestMatch(phoneNumber, utils::PhoneNumber::Match::POSSIBLE);
        auto numberMatch = numberMatcher.bestMatch(phoneNumber, matchLevel);
        if (!numberMatch.has_value()) {
            // number does not exist in the DB yet. Let's add it.
            if (!contactDB->number.add(ContactsNumberTableRow{Record(DB_ID_NONE),


@@ 1211,7 1240,8 @@ auto ContactRecordInterface::buildNumberMatcher(unsigned int maxPageSize)

auto ContactRecordInterface::MatchByNumber(const utils::PhoneNumber::View &numberView,
                                           CreateTempContact createTempContact,
                                           utils::PhoneNumber::Match matchLevel)
                                           utils::PhoneNumber::Match matchLevel,
                                           const std::uint32_t contactIDToIgnore)
    -> std::optional<ContactRecordInterface::ContactNumberMatch>
{
    utils::PhoneNumber phoneNumber;


@@ 1225,7 1255,7 @@ auto ContactRecordInterface::MatchByNumber(const utils::PhoneNumber::View &numbe
    }

    auto numberMatcher = buildNumberMatcher(NumberMatcherPageSize);
    auto matchedNumber = numberMatcher.bestMatch(phoneNumber, matchLevel);
    auto matchedNumber = numberMatcher.bestMatch(phoneNumber, matchLevel, contactIDToIgnore);
    if (!matchedNumber.has_value()) {
        if (createTempContact != CreateTempContact::True) {
            return std::nullopt;

M module-db/Interface/ContactRecord.hpp => module-db/Interface/ContactRecord.hpp +7 -4
@@ 206,9 206,9 @@ class ContactRecordInterface : public RecordInterface<ContactRecord, ContactReco
    auto GetByNumberID(std::uint32_t numberId) -> std::optional<ContactRecord>;

    auto MatchByNumber(const utils::PhoneNumber::View &numberView,
                       CreateTempContact createTempContact  = CreateTempContact::False,
                       utils::PhoneNumber::Match matchLevel = utils::PhoneNumber::Match::POSSIBLE)
        -> std::optional<ContactNumberMatch>;
                       CreateTempContact createTempContact   = CreateTempContact::False,
                       utils::PhoneNumber::Match matchLevel  = utils::PhoneNumber::Match::POSSIBLE,
                       const std::uint32_t contactIDToIgnore = 0u) -> std::optional<ContactNumberMatch>;

    auto GetBySpeedDial(const UTF8 &speedDial) -> std::unique_ptr<std::vector<ContactRecord>>;



@@ 289,7 289,10 @@ class ContactRecordInterface : public RecordInterface<ContactRecord, ContactReco
        -> const std::unique_ptr<db::QueryResult>;

    auto addTemporaryContactForNumber(const ContactRecord::Number &number) -> std::optional<ContactRecord>;
    auto getNumbersIDs(std::uint32_t contactID, const ContactRecord &contact) -> std::vector<std::uint32_t>;
    auto getNumbersIDs(std::uint32_t contactID,
                       const ContactRecord &contact,
                       utils::PhoneNumber::Match matchLevel = utils::PhoneNumber::Match::POSSIBLE)
        -> std::vector<std::uint32_t>;
    auto addNumbers(std::uint32_t contactID, const std::vector<ContactRecord::Number> &numbers)
        -> std::optional<std::string>;
    auto addOrUpdateName(std::uint32_t contactID, std::uint32_t nameID, const ContactRecord &contact)

M module-db/tests/ContactsRecord_tests.cpp => module-db/tests/ContactsRecord_tests.cpp +105 -1
@@ 264,7 264,12 @@ TEST_CASE("Contact record numbers update")
    auto records = ContactRecordInterface(&contactDB);

    ContactRecord testRecord, otherRecord;
    std::array<std::string, 4> numbers = {{{"600100100"}, {"600100200"}, {"600100300"}, {"600100400"}}};
    std::array<std::string, 4> numbers   = {{{"600100100"}, {"600100200"}, {"600100300"}, {"600100400"}}};
    std::array<std::string, 4> numbersPL = {
        {{"+48600100100"}, {"+48600100200"}, {"+48600100300"}, {"+48600100400"}}}; // Poland country code
    std::array<std::string, 4> numbersFR = {
        {{"+33600100100"}, {"+33600100200"}, {"+33600100300"}, {"+33600100400"}}}; // France country code
    std::array<std::string, 2> unUsedNumbers = {{{"612130140"}, {"612130141"}}};

    testRecord.primaryName     = "number";
    testRecord.alternativeName = "test";


@@ 369,6 374,105 @@ TEST_CASE("Contact record numbers update")
        REQUIRE(validatationRecord.numbers[0].number.getEntered() == numbers[3]);
    }

    SECTION("Single number update - adding country code")
    {
        auto newRecord = records.GetByID(1);
        REQUIRE(newRecord.numbers.size() == 2);

        newRecord.numbers = std::vector<ContactRecord::Number>({ContactRecord::Number(numbersPL[0], std::string("")),
                                                                ContactRecord::Number(numbersFR[1], std::string(""))});
        REQUIRE(records.Update(newRecord));
        REQUIRE(contactDB.number.count() == 4);

        auto validationRecord = records.GetByID(1);
        REQUIRE(validationRecord.numbers.size() == 2);
        REQUIRE(validationRecord.numbers[0].number.getEntered() == numbersPL[0]);
        REQUIRE(validationRecord.numbers[1].number.getEntered() == numbersFR[1]);

        validationRecord = records.GetByID(2);
        REQUIRE(validationRecord.numbers.size() == 2);
        REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[2]);

        // There is no new temporary contact
        validationRecord = records.GetByIdWithTemporary(3);
        REQUIRE(validationRecord.ID == DB_ID_NONE);
        REQUIRE(validationRecord.numbers.empty());
    }

    SECTION("Single number update - removing country code")
    {
        auto newRecord = records.GetByID(1);
        REQUIRE(newRecord.numbers.size() == 2);

        // add country code
        newRecord.numbers = std::vector<ContactRecord::Number>({ContactRecord::Number(numbersPL[0], std::string("")),
                                                                ContactRecord::Number(numbersFR[1], std::string(""))});
        REQUIRE(records.Update(newRecord));
        REQUIRE(contactDB.number.count() == 4);

        // deleting country code
        newRecord.numbers = std::vector<ContactRecord::Number>(
            {ContactRecord::Number(numbers[0], std::string("")), ContactRecord::Number(numbers[1], std::string(""))});
        REQUIRE(records.Update(newRecord));
        REQUIRE(contactDB.number.count() == 4);

        auto validationRecord = records.GetByID(1);
        REQUIRE(validationRecord.numbers.size() == 2);
        REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[0]);
        REQUIRE(validationRecord.numbers[1].number.getEntered() == numbers[1]);

        validationRecord = records.GetByID(2);
        REQUIRE(validationRecord.numbers.size() == 2);
        REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[2]);

        // There is no new temporary contact
        validationRecord = records.GetByIdWithTemporary(3);
        REQUIRE(validationRecord.ID == DB_ID_NONE);
        REQUIRE(validationRecord.numbers.empty());
    }

    SECTION("Single number update - changing country code")
    {
        auto newRecord = records.GetByID(1);
        REQUIRE(newRecord.numbers.size() == 2);

        // add country code (PL)
        newRecord.numbers = std::vector<ContactRecord::Number>({ContactRecord::Number(numbersPL[0], std::string("")),
                                                                ContactRecord::Number(numbersPL[1], std::string(""))});
        REQUIRE(records.Update(newRecord));
        REQUIRE(contactDB.number.count() == 4);

        // changing country code (to FR)
        newRecord.numbers = std::vector<ContactRecord::Number>({ContactRecord::Number(numbersFR[0], std::string("")),
                                                                ContactRecord::Number(numbersFR[1], std::string(""))});
        REQUIRE(records.Update(newRecord));
        REQUIRE(contactDB.number.count() == 6);
        REQUIRE(contactDB.number.getById(1).contactID != 1); // old numbers do not belong to any contact
        REQUIRE(contactDB.number.getById(1).contactID != 2);
        REQUIRE(contactDB.number.getById(2).contactID != 1);
        REQUIRE(contactDB.number.getById(2).contactID != 2);

        auto validationRecord = records.GetByID(1);
        REQUIRE(validationRecord.numbers.size() == 2);
        REQUIRE(validationRecord.numbers[0].number.getEntered() == numbersFR[0]);
        REQUIRE(validationRecord.numbers[1].number.getEntered() == numbersFR[1]);

        validationRecord = records.GetByID(2);
        REQUIRE(validationRecord.numbers.size() == 2);
        REQUIRE(validationRecord.numbers[0].number.getEntered() == numbers[2]);

        // A temporary contact for number ID 1 (which was previously assigned to recordID=1) has been created.
        validationRecord = records.GetByIdWithTemporary(3);
        REQUIRE(validationRecord.ID != DB_ID_NONE);
        REQUIRE(validationRecord.numbers[0].number.getEntered() == numbersPL[0]);

        // A temporary contact for numberID 2 (which was previously assigned to recordID=2 for a moment) has been
        // created.
        validationRecord = records.GetByIdWithTemporary(4);
        REQUIRE(validationRecord.ID != DB_ID_NONE);
        REQUIRE(validationRecord.numbers[0].number.getEntered() == numbersPL[1]);
    }

    SECTION("Change both numbers")
    {
        auto newRecord = records.GetByID(1);

M module-services/service-db/DBServiceAPI.cpp => module-services/service-db/DBServiceAPI.cpp +6 -5
@@ 68,10 68,11 @@ auto DBServiceAPI::ContactGetBySpeeddial(sys::Service *serv, UTF8 speeddial)
    return ContactGetByIDCommon(serv, msg);
}

auto DBServiceAPI::MatchContactByPhoneNumber(sys::Service *serv, const utils::PhoneNumber::View &numberView)
    -> std::unique_ptr<ContactRecord>
auto DBServiceAPI::MatchContactByPhoneNumber(sys::Service *serv,
                                             const utils::PhoneNumber::View &numberView,
                                             const std::uint32_t contactIDToOmit) -> std::unique_ptr<ContactRecord>
{
    auto msg = std::make_shared<DBContactNumberMessage>(numberView);
    auto msg = std::make_shared<DBMatchContactNumberBesidesOfContactIDMessage>(numberView, contactIDToOmit);

    auto ret             = serv->bus.sendUnicastSync(std::move(msg), service::name::db, DefaultTimeoutInMs);
    auto contactResponse = dynamic_cast<DBContactNumberResponseMessage *>(ret.second.get());


@@ 139,8 140,8 @@ auto DBServiceAPI::verifyContact(sys::Service *serv, const ContactRecord &rec)
    }

    if (rec.numbers.size() > 0 && rec.numbers[0].number.getEntered().size() > 0) {
        auto retPhone1 = MatchContactByPhoneNumber(serv, rec.numbers[0].number);
        if (retPhone1 && retPhone1->ID != rec.ID) {
        auto retPhone1 = MatchContactByPhoneNumber(serv, rec.numbers[0].number, rec.ID);
        if (retPhone1) {
            if (retPhone1->isTemporary()) {
                return ContactVerificationResult::temporaryContactExists;
            }

M module-services/service-db/include/service-db/DBContactMessage.hpp => module-services/service-db/include/service-db/DBContactMessage.hpp +37 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 62,6 62,42 @@ class DBContactNumberMessage : public sys::DataMessage
};

/**
 * @brief Message used to match Contact by an instance of PhoneNumber::View while omitting the specific contactID.
 *        Omitting specific Contact during searching is helpful to ignore the number which is already signed to Contact
 *        that we want to find a matching number for
 *
 */
class DBMatchContactNumberBesidesOfContactIDMessage : public sys::DataMessage
{
  public:
    /**
     * @brief Construct a new DBMatchContactNumberBesidesOfContactIDMessage object
     *
     * @param numberView - a number to match with
     */

    DBMatchContactNumberBesidesOfContactIDMessage(const utils::PhoneNumber::View &numberView,
                                                  std::uint32_t contactIDToOmit);
    /**
     * @brief Destroy the DBMatchContactNumberBesidesOfContactIDMessage object
     *
     */
    virtual ~DBMatchContactNumberBesidesOfContactIDMessage();

    /**
     * @brief number to match with
     *
     */
    utils::PhoneNumber::View numberView;

    /**
     * @brief numbers connected with this contact Id are omitting during the searching
     *
     */
    std::uint32_t contactIDToOmit;
};

/**
 * @brief A response to DBContactNumberMessage - returns an instance of a ContactRecord matched by provided
 * PhoneNumber::View
 *

M module-services/service-db/include/service-db/DBServiceAPI.hpp => module-services/service-db/include/service-db/DBServiceAPI.hpp +4 -1
@@ 92,9 92,12 @@ class DBServiceAPI
     *
     * @param serv - calling service
     * @param numberView - number to match contact with
     * @param contactIDToOmit - for this contact ID the match will be ignored
     * @return std::unique_ptr<ContactRecord>
     */
    [[deprecated]] static auto MatchContactByPhoneNumber(sys::Service *serv, const utils::PhoneNumber::View &numberView)
    [[deprecated]] static auto MatchContactByPhoneNumber(sys::Service *serv,
                                                         const utils::PhoneNumber::View &numberView,
                                                         const std::uint32_t contactIDToOmit = 0u)
        -> std::unique_ptr<ContactRecord>;
    [[deprecated]] static auto MatchContactByNumberID(sys::Service *serv, std::uint32_t numberID)
        -> std::unique_ptr<ContactRecord>;

M module-services/service-db/messages/DBContactMessage.cpp => module-services/service-db/messages/DBContactMessage.cpp +9 -0
@@ 36,6 36,15 @@ DBContactNumberMessage::DBContactNumberMessage(const utils::PhoneNumber::View &n
DBContactNumberMessage::~DBContactNumberMessage()
{}

DBMatchContactNumberBesidesOfContactIDMessage::DBMatchContactNumberBesidesOfContactIDMessage(
    const utils::PhoneNumber::View &numberView, std::uint32_t contactIDToOmit)
    : sys::DataMessage(MessageType::DBMatchContactNumberBesidesOfContactID), numberView(numberView),
      contactIDToOmit(contactIDToOmit)
{}

DBMatchContactNumberBesidesOfContactIDMessage::~DBMatchContactNumberBesidesOfContactIDMessage()
{}

DBContactNumberResponseMessage::DBContactNumberResponseMessage(sys::ReturnCodes retCode,
                                                               std::unique_ptr<ContactRecord> contact)
    : sys::ResponseMessage(retCode, MessageType::DBContactMatchByNumber), contact(std::move(contact))

M module-utils/phonenumber/NumberHolderMatcher.hpp => module-utils/phonenumber/NumberHolderMatcher.hpp +7 -4
@@ 58,10 58,12 @@ namespace utils
         *
         * @param other - number to match with
         * @param level - minimum acceptable match level
         * @param contactIDToIgnore - for this contact ID the match will be ignored
         * @return Best match for the other phone number
         */
        std::optional<THolder> bestMatch(const PhoneNumber &phoneNumber,
                                         PhoneNumber::Match level = PhoneNumber::Match::EXACT)
                                         PhoneNumber::Match level              = PhoneNumber::Match::EXACT,
                                         const std::uint32_t contactIDToIgnore = 0u)
        {
            utils::time::Scoped t{"bestMatch()"};
            // if empty string, do not try to match, simply return


@@ 71,9 73,10 @@ namespace utils

            restartFor(phoneNumber);
            do {
                const auto it =
                    std::find_if(numbers.cbegin(), numbers.cend(), [&phoneNumber, level](const auto &number) {
                        return phoneNumber.match(number.getNumber()) >= level;
                const auto it = std::find_if(
                    numbers.cbegin(), numbers.cend(), [&phoneNumber, level, contactIDToIgnore](const auto &number) {
                        return (phoneNumber.match(number.getNumber()) >= level) &&
                               (number.getContactID() != contactIDToIgnore);
                    });
                if (it != numbers.cend()) {
                    return *it;

M module-utils/phonenumber/tests/unittest_numbermatcher.cpp => module-utils/phonenumber/tests/unittest_numbermatcher.cpp +14 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>


@@ 16,15 16,26 @@ using namespace utils;
class DummyHolder
{
    PhoneNumber number;
    static std::uint32_t dummyHolderCount; // init by 0
    std::uint32_t contactID;

  public:
    DummyHolder(const PhoneNumber &number) : number(number)
    {}
    DummyHolder(const PhoneNumber &number, const std::uint32_t contactID = 0u) : number(number), contactID(contactID)
    {
        if (contactID == 0)
            this->contactID = ++dummyHolderCount;
    }
    const PhoneNumber &getNumber() const
    {
        return number;
    }

    const decltype(contactID) &getContactID() const
    {
        return contactID;
    }
};
std::uint32_t DummyHolder::dummyHolderCount = 0u;

static constexpr auto DefaultPageSize = 1; // so the paging mechanism is checked.


M products/PurePhone/services/db/ServiceDB.cpp => products/PurePhone/services/db/ServiceDB.cpp +18 -0
@@ 133,6 133,24 @@ sys::MessagePointer ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::
        }
    } break;

    case MessageType::DBMatchContactNumberBesidesOfContactID: {
        auto time = utils::time::Scoped("DBMatchContactNumberBesidesOfContactID");
        auto *msg = dynamic_cast<DBMatchContactNumberBesidesOfContactIDMessage *>(msgl);
        auto ret  = contactRecordInterface->MatchByNumber(msg->numberView,
                                                         ContactRecordInterface::CreateTempContact::False,
                                                         utils::PhoneNumber::Match::POSSIBLE,
                                                         msg->contactIDToOmit);

        if (ret.has_value()) {
            responseMsg = std::make_shared<DBContactNumberResponseMessage>(
                sys::ReturnCodes::Success, std::make_unique<ContactRecord>(std::move(ret->contact)));
        }
        else {
            responseMsg = std::make_shared<DBContactNumberResponseMessage>(sys::ReturnCodes::Success,
                                                                           std::unique_ptr<ContactRecord>());
        }
    } break;

    case MessageType::DBContactMatchByNumberID: {
        auto time = utils::time::Scoped("DBContactMatchByNumberID");
        auto *msg = dynamic_cast<DBMatchContactByNumberIDMessage *>(msgl);

M pure_changelog.md => pure_changelog.md +1 -0
@@ 9,6 9,7 @@
* Fixed looping on the SIM card selection screen
* Fixed notes paste option showing for empty clipboard
* Fixed notes window title
* Fixed adding and deleting country code prefix to existing contact

### Added


M source/MessageType.hpp => source/MessageType.hpp +4 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 26,6 26,9 @@ enum class MessageType
    DBContactMatchByNumberID [[deprecated]],
    DBContactMatchByNumber
    [[deprecated]], ///< used to best match with a single contact using a phone number (primary or secondary)
    DBMatchContactNumberBesidesOfContactID
    [[deprecated]], ///< used to best match with a single contact using a phone number (primary or secondary)
                    ///< but witch omitting specific contact ID
    DBContactAdd [[deprecated]],    ///< Add contact record
    DBContactRemove [[deprecated]], ///< Remove contact remove
    DBContactUpdate [[deprecated]], ///< Update contact remove