~fboucault/telepathy-ofono/crossbuild_fixes

« back to all changes in this revision

Viewing changes to phoneutils.cpp

Use libphonenumber for phone number validation, normalization and comparison. Fixes: #1334860, #1444883, #1471545
Approved by: PS Jenkins bot

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2012-2013 Canonical, Ltd.
 
2
 * Copyright (C) 2012-2015 Canonical, Ltd.
3
3
 *
4
4
 * Authors:
5
5
 *  Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
 
6
 *  Renato Araujo Oliveira Filho <renato.filho@canonical.com>
6
7
 *  Tiago Salem Herrmann <tiago.herrmann@canonical.com>
7
8
 *
8
9
 * This file is part of telepathy-ofono.
20
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22
 */
22
23
 
23
 
#include <QRegExp>
24
24
#include "phoneutils_p.h"
25
 
#include "phonenumberutils_p.h"
26
 
 
27
 
PhoneUtils::PhoneUtils(QObject *parent) :
28
 
    QObject(parent)
29
 
{
30
 
}
31
 
 
32
 
bool PhoneUtils::comparePhoneNumbers(const QString &number1, const QString &number2)
33
 
{
34
 
    if (isPhoneNumber(number1) && isPhoneNumber(number2)) {
35
 
        return PhoneNumberUtils::compareLoosely(number1, number2);
36
 
    }
37
 
    return number1 == number2;
38
 
}
39
 
 
40
 
bool PhoneUtils::isPhoneNumber(const QString &identifier) {
41
 
    // remove all non diable digits
42
 
    QString finalNumber = QString(identifier).replace(QRegExp("[p+*#/(),;-]"),"");
43
 
    finalNumber = finalNumber.replace(QRegExp("(\\s+)"), "");
44
 
    // if empty, the number is invalid
45
 
    if (finalNumber.isEmpty())
46
 
        return false;
47
 
 
48
 
    finalNumber = finalNumber.replace(QRegExp("(\\d+)"), "");
49
 
    return finalNumber.isEmpty();
50
 
}
51
 
 
52
 
// TODO improve this normalization algorithm. More complex numbers 
53
 
// like "+1 234 234-1234 w 12345678#" should be normalizd to "+12342341234"
54
 
QString PhoneUtils::normalizePhoneNumber(const QString &identifier) {
55
 
    if (!isPhoneNumber(identifier)) {
56
 
        // do not normalize non phone numbers
57
 
        return identifier;
58
 
    }
59
 
    QRegExp regexp = QRegExp("(\\s+)");
60
 
    QString finalNumber = QString(identifier).replace(regexp,"");
61
 
    finalNumber = finalNumber.replace(QRegExp("[()/-]"),"");
62
 
    return finalNumber;
63
 
}
64
 
 
65
 
 
 
25
 
 
26
 
 
27
#include <phonenumbers/phonenumbermatch.h>
 
28
#include <phonenumbers/phonenumbermatcher.h>
 
29
#include <phonenumbers/phonenumberutil.h>
 
30
 
 
31
#include <QLocale>
 
32
#include <QDebug>
 
33
#include <QTextStream>
 
34
#include <QFile>
 
35
 
 
36
QString PhoneUtils::mMcc = QString();
 
37
 
 
38
void PhoneUtils::setMcc(const QString &mcc)
 
39
{
 
40
    mMcc = mcc;
 
41
}
 
42
 
 
43
QString PhoneUtils::countryCodeForMCC(const QString &mcc, bool useFallback)
 
44
{
 
45
    static QMap<QString, QString> countryCodes;
 
46
    if (countryCodes.isEmpty()) {
 
47
        QFile countryCodesFile(":/countrycodes.txt");
 
48
        if (!countryCodesFile.open(QFile::ReadOnly)) {
 
49
            qCritical() << "Failed to open " << countryCodesFile.fileName();
 
50
            if (useFallback) {
 
51
                return region();
 
52
            }
 
53
            return QString();
 
54
        }
 
55
        QTextStream stream(&countryCodesFile);
 
56
        while (!stream.atEnd()) {
 
57
            QString line = stream.readLine();
 
58
            QStringList tuple = line.split(":");
 
59
            if (tuple.size() != 2) {
 
60
                qCritical() << "Failed to parse line" << line;
 
61
                if (useFallback) {
 
62
                    return region();
 
63
                }
 
64
                return QString();
 
65
            }
 
66
            countryCodes[tuple[0]] = tuple[1];
 
67
        }
 
68
    }
 
69
    if (!countryCodes.contains(mcc) && useFallback) {
 
70
        return region();
 
71
    }
 
72
    return countryCodes[mcc];
 
73
}
 
74
 
 
75
QString PhoneUtils::region()
 
76
{
 
77
     QString countryCode = QLocale::system().name().split("_").last();
 
78
     if (countryCode.size() < 2) {
 
79
         // fallback to US if no valid country code was provided, otherwise libphonenumber
 
80
         // will fail to parse any numbers
 
81
         return QString("US");
 
82
     }
 
83
     return countryCode;
 
84
}
 
85
 
 
86
QString PhoneUtils::normalizePhoneNumber(const QString &phoneNumber)
 
87
{
 
88
    static i18n::phonenumbers::PhoneNumberUtil *phonenumberUtil = i18n::phonenumbers::PhoneNumberUtil::GetInstance();
 
89
    if (!isPhoneNumber(phoneNumber)) {
 
90
        return phoneNumber;
 
91
    }
 
92
    std::string number = phoneNumber.toStdString();
 
93
    phonenumberUtil->NormalizeDiallableCharsOnly(&number);
 
94
    return QString::fromStdString(number);
 
95
}
 
96
 
 
97
bool PhoneUtils::comparePhoneNumbers(const QString &phoneNumberA, const QString &phoneNumberB)
 
98
{
 
99
    static i18n::phonenumbers::PhoneNumberUtil *phonenumberUtil = i18n::phonenumbers::PhoneNumberUtil::GetInstance();
 
100
    // if any of the number isn't a phone number, just do a simple string comparison
 
101
    if (!isPhoneNumber(phoneNumberA) || !isPhoneNumber(phoneNumberB)) {
 
102
        return phoneNumberA == phoneNumberB;
 
103
    }
 
104
    i18n::phonenumbers::PhoneNumberUtil::MatchType match = phonenumberUtil->
 
105
            IsNumberMatchWithTwoStrings(phoneNumberA.toStdString(),
 
106
                                        phoneNumberB.toStdString());
 
107
    return (match > i18n::phonenumbers::PhoneNumberUtil::NO_MATCH);
 
108
}
 
109
 
 
110
bool PhoneUtils::isPhoneNumber(const QString &phoneNumber)
 
111
{
 
112
    static i18n::phonenumbers::PhoneNumberUtil *phonenumberUtil = i18n::phonenumbers::PhoneNumberUtil::GetInstance();
 
113
    std::string formattedNumber;
 
114
    i18n::phonenumbers::PhoneNumber number;
 
115
    i18n::phonenumbers::PhoneNumberUtil::ErrorType error;
 
116
    error = phonenumberUtil->Parse(phoneNumber.toStdString(), countryCodeForMCC(mMcc, true).toStdString(), &number);
 
117
 
 
118
    switch(error) {
 
119
    case i18n::phonenumbers::PhoneNumberUtil::INVALID_COUNTRY_CODE_ERROR:
 
120
        qWarning() << "Invalid country code for:" << phoneNumber;
 
121
        return false;
 
122
    case i18n::phonenumbers::PhoneNumberUtil::NOT_A_NUMBER:
 
123
        qWarning() << "The phone number is not a valid number:" << phoneNumber;
 
124
        return false;
 
125
    case i18n::phonenumbers::PhoneNumberUtil::TOO_SHORT_AFTER_IDD:
 
126
    case i18n::phonenumbers::PhoneNumberUtil::TOO_SHORT_NSN:
 
127
    case i18n::phonenumbers::PhoneNumberUtil::TOO_LONG_NSN:
 
128
        qWarning() << "Invalid phone number" << phoneNumber;
 
129
        return false;
 
130
    default:
 
131
        break;
 
132
    }
 
133
    return true;
 
134
}