/*
* 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 PhoneNumberI18nService 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 String 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 String which may represents a phone
* number or an identifier to normalize.
*
* @return a String which is a normalized form of the specified
* possibleNumber.
*/
public String normalize(String possibleNumber)
{
String normalizedNumber;
if(isPhoneNumber(possibleNumber))
{
normalizedNumber = normalizePhoneNumber(possibleNumber);
}
else
{
normalizedNumber = normalizeIdentifier(possibleNumber);
}
return normalizedNumber;
}
/**
* Normalizes a String phone number by converting alpha characters
* to their respective digits on a keypad and then stripping non-digit
* characters.
*
* @param phoneNumber a String which represents a phone number to
* normalize
*
* @return a String which is a normalized form of the specified
* phoneNumber
*
* @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 String phone numbers match.
*
* @param aPhoneNumber a String which represents a phone number to
* match to bPhoneNumber
* @param bPhoneNumber a String which represents a phone number to
* match to aPhoneNumber
* @return true if the specified Strings match as phone
* numbers; otherwise, false
*/
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 true if the possibleNumber is a phone number,
* false - 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");
}
}