aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/impl/phonenumbers/PhoneNumberI18nServiceImpl.java
blob: 4d4d4170f96fc2ab7ec950123ad4747492471cf4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/*
 * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.java.sip.communicator.impl.phonenumbers;

import com.google.i18n.phonenumbers.*;
import com.google.i18n.phonenumbers.PhoneNumberUtil.*;
import com.google.i18n.phonenumbers.Phonenumber.*;

import net.java.sip.communicator.service.protocol.*;
import org.jitsi.service.configuration.*;

import java.util.regex.*;

/**
 * Implements <tt>PhoneNumberI18nService</tt> which aids the parsing, formatting
 * and validating of international phone numbers.
 *
 * @author Lyubomir Marinov
 * @author Vincent Lucas
 * @author Damian Minkov
 */
public class PhoneNumberI18nServiceImpl
    implements PhoneNumberI18nService
{
    /**
     * The configuration service.
     */
    private static ConfigurationService configService
        = ProtocolProviderActivator.getConfigurationService();

    /**
     * Characters which have to be removed from a phone number in order to
     * normalized it.
     */
    private static final Pattern removedCharactersToNormalizedPhoneNumber
        = Pattern.compile("[-\\(\\)\\.\\\\\\/ ]");

    /**
     * Characters which have to be removed from a number (which is not a phone
     * number, such as a sip id, a jabber id, etc.) in order to normalized it.
     */
    private static final Pattern removedCharactersToNormalizedIdentifier
        = Pattern.compile("[\\(\\) ]");

    /**
     * The list of characters corresponding to the number 2 in a phone dial pad.
     */
    private static final Pattern charactersFordialPadNumber2
        = Pattern.compile("[abc]", Pattern.CASE_INSENSITIVE);
    /**
     * The list of characters corresponding to the number 3 in a phone dial pad.
     */
    private static final Pattern charactersFordialPadNumber3
        = Pattern.compile("[def]", Pattern.CASE_INSENSITIVE);

    /**
     * The list of characters corresponding to the number 4 in a phone dial pad.
     */
    private static final Pattern charactersFordialPadNumber4
        = Pattern.compile("[ghi]", Pattern.CASE_INSENSITIVE);

    /**
     * The list of characters corresponding to the number 5 in a phone dial pad.
     */
    private static final Pattern charactersFordialPadNumber5
        = Pattern.compile("[jkl]", Pattern.CASE_INSENSITIVE);

    /**
     * The list of characters corresponding to the number 6 in a phone dial pad.
     */
    private static final Pattern charactersFordialPadNumber6
        = Pattern.compile("[mno]", Pattern.CASE_INSENSITIVE);

    /**
     * The list of characters corresponding to the number 7 in a phone dial pad.
     */
    private static final Pattern charactersFordialPadNumber7
        = Pattern.compile("[pqrs]", Pattern.CASE_INSENSITIVE);

    /**
     * The list of characters corresponding to the number 8 in a phone dial pad.
     */
    private static final Pattern charactersFordialPadNumber8
        = Pattern.compile("[tuv]", Pattern.CASE_INSENSITIVE);

    /**
     * The list of characters corresponding to the number 9 in a phone dial pad.
     */
    private static final Pattern charactersFordialPadNumber9
        = Pattern.compile("[wxyz]", Pattern.CASE_INSENSITIVE);

    /**
     * Normalizes a <tt>String</tt> which may be a phone number or a identifier
     * by removing useless characters and, if necessary, replacing the alpahe
     * characters in corresponding dial pad numbers.
     *
     * @param possibleNumber a <tt>String</tt> which may represents a phone
     * number or an identifier to normalize.
     *
     * @return a <tt>String</tt> which is a normalized form of the specified
     * <tt>possibleNumber</tt>.
     */
    public String normalize(String possibleNumber)
    {
        String normalizedNumber;
        if(isPhoneNumber(possibleNumber))
        {
            normalizedNumber = normalizePhoneNumber(possibleNumber);
        }
        else
        {
            normalizedNumber = normalizeIdentifier(possibleNumber);
        }

        return normalizedNumber;
    }


    /**
     * Normalizes a <tt>String</tt> phone number by converting alpha characters
     * to their respective digits on a keypad and then stripping non-digit
     * characters.
     *
     * @param phoneNumber a <tt>String</tt> which represents a phone number to
     * normalize
     *
     * @return a <tt>String</tt> which is a normalized form of the specified
     * <tt>phoneNumber</tt>
     *
     * @see net.java.sip.communicator.impl.phonenumbers.PhoneNumberI18nServiceImpl#normalize(String)
     */
    private static String normalizePhoneNumber(String phoneNumber)
    {
        phoneNumber = convertAlphaCharactersInNumber(phoneNumber);
        return removedCharactersToNormalizedPhoneNumber
            .matcher(phoneNumber).replaceAll("");
    }

    /**
     * Removes useless characters from a identifier (which is not a phone
     * number) in order to normalized it.
     *
     * @param id The identifier string with some useless characters like: " ",
     * "(", ")".
     *
     * @return The normalized identifier.
     */
    private static String normalizeIdentifier(String id)
    {
        return removedCharactersToNormalizedIdentifier
            .matcher(id).replaceAll("");
    }

    /**
     * Determines whether two <tt>String</tt> phone numbers match.
     *
     * @param aPhoneNumber a <tt>String</tt> which represents a phone number to
     * match to <tt>bPhoneNumber</tt>
     * @param bPhoneNumber a <tt>String</tt> which represents a phone number to
     * match to <tt>aPhoneNumber</tt>
     * @return <tt>true</tt> if the specified <tt>String</tt>s match as phone
     * numbers; otherwise, <tt>false</tt>
     */
    public boolean phoneNumbersMatch(String aPhoneNumber, String bPhoneNumber)
    {
        PhoneNumberUtil.MatchType match = PhoneNumberUtil.getInstance()
            .isNumberMatch(aPhoneNumber, bPhoneNumber);

        return match != PhoneNumberUtil.MatchType.NOT_A_NUMBER
            && match != PhoneNumberUtil.MatchType.NO_MATCH;
    }

    /**
     * Tries to format the passed phone number into the international format. If
     * parsing fails or the string is not recognized as a valid phone number,
     * the input is returned as is.
     * 
     * @param phoneNumber The phone number to format.
     * @return the formatted phone number in the international format.
     */
    public String formatForDisplay(String phoneNumber)
    {
        try
        {
            PhoneNumber pn = PhoneNumberUtil.getInstance().parse(phoneNumber,
                System.getProperty("user.country"));
            if (PhoneNumberUtil.getInstance().isPossibleNumber(pn))
            {
                return PhoneNumberUtil.getInstance().format(pn,
                    PhoneNumberFormat.INTERNATIONAL);
            }
        }
        catch (NumberParseException e)
        {
        }

        return phoneNumber;
    }

    /**
     * Indicates if the given string is possibly a phone number.
     *
     * @param possibleNumber the string to be verified
     * @return <tt>true</tt> if the possibleNumber is a phone number,
     * <tt>false</tt> - otherwise
     */
    public boolean isPhoneNumber(String possibleNumber)
    {
        // If the string does not contains an "@", this may be a phone number.
        if(possibleNumber.indexOf('@') == -1)
        {
            // If the string does not contain any alphabetical characters, then
            // this is a phone number.
            if(!possibleNumber.matches(".*[a-zA-Z].*"))
            {
                return true;
            }
            else
            {
                // Removes the " ", "(" and ")" in order to search the "+"
                // character at the beginning at the string.
                String tmpPossibleNumber
                    = possibleNumber.replaceAll(" \\(\\)", "");
                // If the property is enabled and the string starts with a "+",
                // then we consider that this is a phone number.
                if(configService.getBoolean(
                        "impl.gui.ACCEPT_PHONE_NUMBER_WITH_ALPHA_CHARS",
                        true)
                        && tmpPossibleNumber.startsWith("+"))
                {
                    return true;
                }
            }
        }
        // Else the string is not a phone number.
        return false;
    }

    /**
     * Changes all alphabetical characters into numbers, following phone dial
     * pad disposition.
     *
     * @param phoneNumber The phone number string with some alphabetical
     * characters.
     *
     * @return The phone number with all alphabetical caracters replaced with
     * the corresponding dial pad number.
     */
    private static String convertAlphaCharactersInNumber(String phoneNumber)
    {
        phoneNumber
            = charactersFordialPadNumber2.matcher(phoneNumber).replaceAll("2");
        phoneNumber
            = charactersFordialPadNumber3.matcher(phoneNumber).replaceAll("3");
        phoneNumber
            = charactersFordialPadNumber4.matcher(phoneNumber).replaceAll("4");
        phoneNumber
            = charactersFordialPadNumber5.matcher(phoneNumber).replaceAll("5");
        phoneNumber
            = charactersFordialPadNumber6.matcher(phoneNumber).replaceAll("6");
        phoneNumber
            = charactersFordialPadNumber7.matcher(phoneNumber).replaceAll("7");
        phoneNumber
            = charactersFordialPadNumber8.matcher(phoneNumber).replaceAll("8");
        return charactersFordialPadNumber9.matcher(phoneNumber).replaceAll("9");
    }
}