File indexing completed on 2024-04-28 16:42:50

0001 // SPDX-FileCopyrightText: 2020 Jonah BrĂ¼chert <jbb@kaidan.im>
0002 // SPDX-FileCopyrightText: 2021 Alexey Andreyev <aa13q@ya.ru>
0003 //
0004 // SPDX-License-Identifier: LicenseRef-KDE-Accepted-GPL
0005 
0006 /*
0007  * This class tries to match a phonenumber to one of your contacts.
0008  * This is not an easy tasks and involves some heuristics and tradeoffs.
0009  *
0010  * It works by maintaining a mapping from phonenumbers to KPeople URIs.
0011  * Since phonenumbers can be written in different formats the numbers are
0012  * normalized to a common form before comparing.
0013  *
0014  * If a contact's phonenumber in the address book is saved without a country
0015  * code then we need to guess a country. Guessing the country based on the locale
0016  * is problematic for people that have e.g. their phone in English but live
0017  * in Germany and assume the German country code in their address book.
0018  * Querying the country based on the cell network/MCC is problematic when travelling
0019  * abroad and the MCC changes.
0020  *
0021  * Our heuristic works like this:
0022  * First we normalize the number based on the cell network country and store the mapping.
0023  * If the locale's country is different to the cell network country we normalize the number
0024  * based on that and add it to the mapping as well.
0025  * When a call is received we first normalize the number based on the cell network country and
0026  * ask the mapping. If there is no entry we do the same based on the locale country.
0027  *
0028  * This covers the case of someone from Germany with English locale and the case of someone
0029  * from Germany using German locale travelling to France. It does not cover the case of
0030  * someone from Germany using English locale travelling to France.
0031  *
0032  * When the MCC changes, i.e. when we cross the border the mapping is cleared and redone with the new MCC.
0033  */
0034 
0035 #pragma once
0036 
0037 #include <KPeople/PersonsModel>
0038 #include <QObject>
0039 
0040 #include <unordered_map>
0041 
0042 class ContactPhoneNumberMapper : public QObject
0043 {
0044     Q_OBJECT
0045 
0046 public:
0047     /**
0048      * @brief Returns the KPeople URI belonging to phone number,
0049      * provided a contact exists containing the phone number.
0050      * If that is not the case, an empty string is returned.
0051      * @param phone number
0052      * @param guess the country
0053      * if a contact's phonenumber in the address book
0054      * is saved without a country code
0055      * @return the uri belonging to the phone number
0056      */
0057     QString uriForNumber(const QString &phoneNumber) const;
0058 
0059     static ContactPhoneNumberMapper &instance(bool testMode = false);
0060 
0061 Q_SIGNALS:
0062     /**
0063      * @brief contactsChanged is emitted whenever the ContactMapper has new data,
0064      * because a contact was added to KPeople
0065      * @param list of affected numbers
0066      */
0067     void contactsChanged(const QVector<QString> phoneNumbers);
0068 
0069 public Q_SLOTS:
0070     /**
0071      * @brief changeCountry should be executed by the daemon via appropriate signal
0072      * @param new two-letter country code
0073      */
0074     void changeCountry(const QString &countryCode);
0075 
0076 private Q_SLOTS:
0077     void processRows(const int first, const int last);
0078 
0079 private:
0080     explicit ContactPhoneNumberMapper(bool testMode);
0081     [[nodiscard]] std::string normalizeNumber(const std::string &numberString) const;
0082 
0083     KPeople::PersonsModel *_model;
0084     std::unordered_map<std::string, QString> _numberToUri;
0085 
0086     std::string _cellCountry;
0087     std::string _localeCountry;
0088 };