diff --git a/.classpath b/.classpath index b0c5f2d03..cba1bcced 100755 --- a/.classpath +++ b/.classpath @@ -66,6 +66,7 @@ + diff --git a/build.xml b/build.xml index 722207cb6..2a17369f3 100644 --- a/build.xml +++ b/build.xml @@ -1047,7 +1047,7 @@ bundle-protocol,bundle-protocol-media,bundle-icq, bundle-icq-slick,bundle-mock,bundle-smacklib,bundle-jmdnslib, bundle-jabber,bundle-jabber-slick,bundle-swing-ui,bundle-ui-service, - bundle-jnalib, + bundle-jnalib,bundle-phonenumbers, bundle-msn,bundle-msn-slick,bundle-yahoo,bundle-yahoo-slick, bundle-contactlist,meta-contactlist,meta-contactlist-slick, bundle-plugin-icqaccregwizz,bundle-plugin-jabberaccregwizz, @@ -1529,6 +1529,17 @@ javax.swing.event, javax.swing.border"/> + + + + + + + + + cssList = new HashMap(); + /** + * The registered PhoneNumberI18nService. + */ + private static PhoneNumberI18nService phoneNumberI18nService; + /** * Returns a reference to a ConfigurationService implementation currently * registered in the bundle context or null if no such implementation was @@ -480,4 +485,20 @@ public static void disableContactSource(GoogleContactsConnection cnx) cssList.remove(found); } } + + /** + * Returns the PhoneNumberI18nService. + * @return returns the PhoneNumberI18nService. + */ + public static PhoneNumberI18nService getPhoneNumberI18nService() + { + if(phoneNumberI18nService == null) + { + phoneNumberI18nService = ServiceUtils.getService( + bundleContext, + PhoneNumberI18nService.class); + } + + return phoneNumberI18nService; + } } diff --git a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsQuery.java b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsQuery.java index b653b950a..f37121e36 100644 --- a/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsQuery.java +++ b/src/net/java/sip/communicator/impl/googlecontacts/GoogleContactsQuery.java @@ -208,7 +208,8 @@ private List getContactDetails(GoogleContactsEntry entry) supportedOpSets.add(OperationSetBasicTelephony.class); // can be added as contacts supportedOpSets.add(OperationSetPersistentPresence.class); - homePhone = PhoneNumberI18nService.normalize(homePhone); + homePhone = GoogleContactsActivator.getPhoneNumberI18nService() + .normalize(homePhone); detail = new ContactDetail(homePhone, ContactDetail.Category.Phone, new ContactDetail.SubCategory[]{ @@ -225,7 +226,8 @@ private List getContactDetails(GoogleContactsEntry entry) supportedOpSets.add(OperationSetBasicTelephony.class); // can be added as contacts supportedOpSets.add(OperationSetPersistentPresence.class); - workPhone = PhoneNumberI18nService.normalize(workPhone); + workPhone = GoogleContactsActivator.getPhoneNumberI18nService() + .normalize(workPhone); detail = new ContactDetail(workPhone, ContactDetail.Category.Phone, new ContactDetail.SubCategory[]{ @@ -242,7 +244,8 @@ private List getContactDetails(GoogleContactsEntry entry) supportedOpSets.add(OperationSetBasicTelephony.class); // can be added as contacts supportedOpSets.add(OperationSetPersistentPresence.class); - mobilePhone = PhoneNumberI18nService.normalize(mobilePhone); + mobilePhone = GoogleContactsActivator.getPhoneNumberI18nService() + .normalize(mobilePhone); detail = new ContactDetail(mobilePhone, ContactDetail.Category.Phone, new ContactDetail.SubCategory[]{ diff --git a/src/net/java/sip/communicator/impl/gui/GuiActivator.java b/src/net/java/sip/communicator/impl/gui/GuiActivator.java index 2fcdea84a..cf7a9e068 100644 --- a/src/net/java/sip/communicator/impl/gui/GuiActivator.java +++ b/src/net/java/sip/communicator/impl/gui/GuiActivator.java @@ -121,6 +121,11 @@ public class GuiActivator implements BundleActivator private static final Map replacementSourcesMap = new Hashtable(); + /** + * The registered PhoneNumberI18nService. + */ + private static PhoneNumberI18nService phoneNumberI18nService; + /** * Indicates if this bundle has been started. */ @@ -910,4 +915,20 @@ public static MessageHistoryService getMessageHistoryService() MessageHistoryService.class); return messageHistoryService; } + + /** + * Returns the PhoneNumberI18nService. + * @return returns the PhoneNumberI18nService. + */ + public static PhoneNumberI18nService getPhoneNumberI18nService() + { + if(phoneNumberI18nService == null) + { + phoneNumberI18nService = ServiceUtils.getService( + bundleContext, + PhoneNumberI18nService.class); + } + + return phoneNumberI18nService; + } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java b/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java index 8622bb7cb..f27a7aec9 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java @@ -912,7 +912,8 @@ public static void createCall( String callString, if (ConfigurationUtils.isNormalizePhoneNumber() && !NetworkUtils.isValidIPAddress(callString)) { - callString = PhoneNumberI18nService.normalize(callString); + callString = GuiActivator.getPhoneNumberI18nService() + .normalize(callString); } List telephonyProviders @@ -2519,8 +2520,8 @@ else if(formats.isEmpty()) if (stringContact != null) { - stringContact - = PhoneNumberI18nService.normalize(stringContact); + stringContact = GuiActivator.getPhoneNumberI18nService() + .normalize(stringContact); } } @@ -3555,7 +3556,8 @@ private static boolean showDesktopSharingWarning() private static void normalizePhoneNumbers(String callees[]) { for (int i = 0 ; i < callees.length ; i++) - callees[i] = PhoneNumberI18nService.normalize(callees[i]); + callees[i] = GuiActivator.getPhoneNumberI18nService() + .normalize(callees[i]); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java index 2413a78ff..1f993b13a 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/SearchFilter.java @@ -58,6 +58,12 @@ public class SearchFilter private static Map contactSourceOrder = new HashMap(); + /** + * If set, we are searching a phone number and will use the phone number + * service to try matching the numbers. + */ + private boolean isSearchingPhoneNumber = false; + /** * Creates an instance of SearchFilter. */ @@ -260,6 +266,9 @@ public void setFilterString(String filter) Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + + this.isSearchingPhoneNumber + = GuiActivator.getPhoneNumberI18nService().isPhoneNumber(filter); } /** @@ -270,9 +279,10 @@ public void setFilterString(String filter) */ private boolean isMatching(String text) { - if (filterPattern != null) - return filterPattern.matcher(text).find(); - - return true; + return (filterPattern != null + && filterPattern.matcher(text).find()) + || (isSearchingPhoneNumber + && GuiActivator.getPhoneNumberI18nService() + .phoneNumbersMatch(this.filterString, text)); } } diff --git a/src/net/java/sip/communicator/impl/ldap/LdapActivator.java b/src/net/java/sip/communicator/impl/ldap/LdapActivator.java index 9e8a36f35..2c3be39ec 100644 --- a/src/net/java/sip/communicator/impl/ldap/LdapActivator.java +++ b/src/net/java/sip/communicator/impl/ldap/LdapActivator.java @@ -10,6 +10,7 @@ import net.java.sip.communicator.service.contactsource.*; import net.java.sip.communicator.service.ldap.*; +import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; import org.jitsi.service.resources.*; @@ -60,6 +61,11 @@ public static LdapService getLdapService() private static Map cssList = new HashMap(); + /** + * The registered PhoneNumberI18nService. + */ + private static PhoneNumberI18nService phoneNumberI18nService; + /** * Starts the LDAP service * @@ -231,4 +237,20 @@ public static void unregisterContactSource(LdapDirectory ldapDir) cssList.remove(found); } } + + /** + * Returns the PhoneNumberI18nService. + * @return returns the PhoneNumberI18nService. + */ + public static PhoneNumberI18nService getPhoneNumberI18nService() + { + if(phoneNumberI18nService == null) + { + phoneNumberI18nService = ServiceUtils.getService( + bundleContext, + PhoneNumberI18nService.class); + } + + return phoneNumberI18nService; + } } diff --git a/src/net/java/sip/communicator/impl/ldap/LdapContactQuery.java b/src/net/java/sip/communicator/impl/ldap/LdapContactQuery.java index 99f98e455..e9062040e 100644 --- a/src/net/java/sip/communicator/impl/ldap/LdapContactQuery.java +++ b/src/net/java/sip/communicator/impl/ldap/LdapContactQuery.java @@ -149,7 +149,9 @@ private List getContactDetails(LdapPersonFound person) Set mobilePhones = person.getMobilePhone(); Set homePhones = person.getHomePhone(); Set workPhones = person.getWorkPhone(); - ContactDetail detail = null; + ContactDetail detail; + PhoneNumberI18nService phoneNumberI18nService + = LdapActivator.getPhoneNumberI18nService(); for(String mail : mailAddresses) { @@ -161,7 +163,7 @@ private List getContactDetails(LdapPersonFound person) for(String homePhone : homePhones) { - homePhone = PhoneNumberI18nService.normalize(homePhone); + homePhone = phoneNumberI18nService.normalize(homePhone); detail = new ContactDetail(homePhone, ContactDetail.Category.Phone, new ContactDetail.SubCategory[]{ @@ -175,7 +177,7 @@ private List getContactDetails(LdapPersonFound person) for(String workPhone : workPhones) { - workPhone = PhoneNumberI18nService.normalize(workPhone); + workPhone = phoneNumberI18nService.normalize(workPhone); detail = new ContactDetail(workPhone, ContactDetail.Category.Phone, new ContactDetail.SubCategory[]{ @@ -189,7 +191,7 @@ private List getContactDetails(LdapPersonFound person) for(String mobilePhone : mobilePhones) { - mobilePhone = PhoneNumberI18nService.normalize(mobilePhone); + mobilePhone = phoneNumberI18nService.normalize(mobilePhone); detail = new ContactDetail(mobilePhone, ContactDetail.Category.Phone, new ContactDetail.SubCategory[]{ diff --git a/src/net/java/sip/communicator/impl/phonenumbers/PhoneNumberI18nServiceImpl.java b/src/net/java/sip/communicator/impl/phonenumbers/PhoneNumberI18nServiceImpl.java new file mode 100644 index 000000000..97f74dfb4 --- /dev/null +++ b/src/net/java/sip/communicator/impl/phonenumbers/PhoneNumberI18nServiceImpl.java @@ -0,0 +1,241 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.phonenumbers; + +import com.google.i18n.phonenumbers.*; +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; + } + + /** + * 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"); + } +} diff --git a/src/net/java/sip/communicator/impl/phonenumbers/PhoneNumberServiceActivator.java b/src/net/java/sip/communicator/impl/phonenumbers/PhoneNumberServiceActivator.java new file mode 100644 index 000000000..3f365977e --- /dev/null +++ b/src/net/java/sip/communicator/impl/phonenumbers/PhoneNumberServiceActivator.java @@ -0,0 +1,44 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.phonenumbers; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; +import org.osgi.framework.*; + +/** + * Activates PhoneNumberI18nService implementation. + * + * @author Damian Minkov + */ +public class PhoneNumberServiceActivator + implements BundleActivator +{ + /** + * Our logging. + */ + private static Logger logger + = Logger.getLogger(PhoneNumberServiceActivator.class); + + @Override + public void start(BundleContext bundleContext) + throws Exception + { + bundleContext.registerService( + PhoneNumberI18nService.class.getName(), + new PhoneNumberI18nServiceImpl(), + null); + + if (logger.isInfoEnabled()) + logger.info("Packet Logging Service ...[REGISTERED]"); + } + + @Override + public void stop(BundleContext bundleContext) + throws Exception + {} +} diff --git a/src/net/java/sip/communicator/impl/phonenumbers/phonenumbers.manifest.mf b/src/net/java/sip/communicator/impl/phonenumbers/phonenumbers.manifest.mf new file mode 100644 index 000000000..8d33d43a2 --- /dev/null +++ b/src/net/java/sip/communicator/impl/phonenumbers/phonenumbers.manifest.mf @@ -0,0 +1,12 @@ +Bundle-Activator: net.java.sip.communicator.impl.phonenumbers.PhoneNumberServiceActivator +Bundle-Name: PhoneNumbers service +Bundle-Description: A bundle that provides arsing, formatting and validating of international phone numbers. +Bundle-Vendor: jitsi.org +Bundle-Version: 0.0.1 +Bundle-SymbolicName: net.java.sip.communicator.phonenumbers +Export-Package: com.google.i18n.phonenumbers +Import-Package: org.osgi.framework, + org.jitsi.service.configuration, + net.java.sip.communicator.service.protocol, + net.java.sip.communicator.util + diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java b/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java index 925f20e09..b932d9c1d 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/JabberActivator.java @@ -112,6 +112,11 @@ public class JabberActivator */ private static VersionService versionService = null; + /** + * The registered PhoneNumberI18nService. + */ + private static PhoneNumberI18nService phoneNumberI18nService; + /** * Called when this bundle is started so the Framework can perform the * bundle-specific activities necessary to start this bundle. @@ -421,4 +426,20 @@ public static VersionService getVersionService() } return versionService; } + + /** + * Returns the PhoneNumberI18nService. + * @return returns the PhoneNumberI18nService. + */ + public static PhoneNumberI18nService getPhoneNumberI18nService() + { + if(phoneNumberI18nService == null) + { + phoneNumberI18nService = ServiceUtils.getService( + bundleContext, + PhoneNumberI18nService.class); + } + + return phoneNumberI18nService; + } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetCusaxUtilsJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetCusaxUtilsJabberImpl.java index 28159be8d..9931c99b1 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetCusaxUtilsJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetCusaxUtilsJabberImpl.java @@ -61,7 +61,8 @@ public boolean doesDetailBelong(Contact contact, String detailAddress) while (phonesIter.hasNext()) { String phone = phonesIter.next(); - String normalizedPhone = PhoneNumberI18nService.normalize(phone); + String normalizedPhone = JabberActivator.getPhoneNumberI18nService() + .normalize(phone); if (phone.equals(detailAddress) || normalizedPhone.equals(detailAddress) diff --git a/src/net/java/sip/communicator/plugin/addrbook/AddrBookActivator.java b/src/net/java/sip/communicator/plugin/addrbook/AddrBookActivator.java index 6867be9b2..28a9fe5e3 100644 --- a/src/net/java/sip/communicator/plugin/addrbook/AddrBookActivator.java +++ b/src/net/java/sip/communicator/plugin/addrbook/AddrBookActivator.java @@ -106,6 +106,11 @@ public class AddrBookActivator */ private static List providers = new ArrayList(); + + /** + * The registered PhoneNumberI18nService. + */ + private static PhoneNumberI18nService phoneNumberI18nService; /** * The registration change listener. @@ -524,4 +529,20 @@ public static List getProtocolProviders() return result; } + + /** + * Returns the PhoneNumberI18nService. + * @return returns the PhoneNumberI18nService. + */ + public static PhoneNumberI18nService getPhoneNumberI18nService() + { + if(phoneNumberI18nService == null) + { + phoneNumberI18nService = ServiceUtils.getService( + bundleContext, + PhoneNumberI18nService.class); + } + + return phoneNumberI18nService; + } } diff --git a/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactQuery.java b/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactQuery.java index 2687f4602..e73c9e878 100644 --- a/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactQuery.java +++ b/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactQuery.java @@ -589,7 +589,8 @@ private List getContactDetails(Object[] values, String id) { if (kABPhoneProperty == property) stringValue - = PhoneNumberI18nService.normalize(stringValue); + = AddrBookActivator.getPhoneNumberI18nService() + .normalize(stringValue); contactDetails.add( setCapabilities( @@ -645,8 +646,9 @@ private void parseMultiDetails( { if (kABPhoneProperty == property) { - stringSubValue = PhoneNumberI18nService - .normalize(stringSubValue); + stringSubValue + = AddrBookActivator.getPhoneNumberI18nService() + .normalize(stringSubValue); } Object l = multiValue[multiValueIndex + 1]; diff --git a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java index b6c42ce6b..a7cdf7344 100644 --- a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java +++ b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java @@ -999,7 +999,8 @@ public static List getContactDetails(Object[] values) { if(isPhoneNumber(property)) stringValue - = PhoneNumberI18nService.normalize(stringValue); + = AddrBookActivator.getPhoneNumberI18nService() + .normalize(stringValue); MsOutlookAddrBookContactDetail contactDetail = new MsOutlookAddrBookContactDetail( diff --git a/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PNContactSourceActivator.java b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PNContactSourceActivator.java index 4a3fc6f92..e73ed0239 100644 --- a/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PNContactSourceActivator.java +++ b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PNContactSourceActivator.java @@ -51,6 +51,11 @@ public class PNContactSourceActivator */ private static ResourceManagementService resources = null; + /** + * The registered PhoneNumberI18nService. + */ + private static PhoneNumberI18nService phoneNumberI18nService; + /** * Starts this bundle. * @@ -214,4 +219,20 @@ private static void handleProviderRemoved( if (phoneProviders.contains(protocolProvider)) phoneProviders.remove(protocolProvider); } + + /** + * Returns the PhoneNumberI18nService. + * @return returns the PhoneNumberI18nService. + */ + public static PhoneNumberI18nService getPhoneNumberI18nService() + { + if(phoneNumberI18nService == null) + { + phoneNumberI18nService = ServiceUtils.getService( + bundleContext, + PhoneNumberI18nService.class); + } + + return phoneNumberI18nService; + } } diff --git a/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberContactQuery.java b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberContactQuery.java index f58fbb759..42a898737 100644 --- a/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberContactQuery.java +++ b/src/net/java/sip/communicator/plugin/phonenumbercontactsource/PhoneNumberContactQuery.java @@ -44,6 +44,11 @@ public class PhoneNumberContactQuery = Collections.synchronizedList( new LinkedList()); + /** + * Is the query searching for phone number. + */ + private final boolean isQueryPhoneNumber; + /** * Creates an instance of PhoneNumberContactQuery by specifying * the parent contact source, the query string to match and the maximum @@ -63,6 +68,10 @@ public PhoneNumberContactQuery( PhoneNumberContactSource contactSource, this.queryString = queryString; this.contactCount = contactCount; + + this.isQueryPhoneNumber + = PNContactSourceActivator.getPhoneNumberI18nService() + .isPhoneNumber(queryString); } /** @@ -204,7 +213,13 @@ else if(d instanceof VideoDetail) if(StringUtils.isNullOrEmpty(queryString) || query.matcher(numberString).find() || query.matcher(contactName).find() - || query.matcher(contactAddress).find()) + || query.matcher(contactAddress).find() + || (isQueryPhoneNumber + && PNContactSourceActivator + .getPhoneNumberI18nService() + .phoneNumbersMatch( + queryString, numberString)) + ) { ArrayList contactDetails = new ArrayList(); diff --git a/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdActivator.java b/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdActivator.java index d6a9c58a8..7dc43d76f 100644 --- a/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdActivator.java +++ b/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdActivator.java @@ -10,6 +10,7 @@ import net.java.sip.communicator.service.contactsource.*; import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; import org.jitsi.service.configuration.*; @@ -31,6 +32,11 @@ public class ThunderbirdActivator private static Map registrations; + /** + * The registered PhoneNumberI18nService. + */ + private static PhoneNumberI18nService phoneNumberI18nService; + /** * Gets the configuration service. * @return the configuration service. @@ -148,4 +154,20 @@ public void stop(BundleContext bundleContext) throws Exception registrations = null; } + + /** + * Returns the PhoneNumberI18nService. + * @return returns the PhoneNumberI18nService. + */ + public static PhoneNumberI18nService getPhoneNumberI18nService() + { + if(phoneNumberI18nService == null) + { + phoneNumberI18nService = ServiceUtils.getService( + bundleContext, + PhoneNumberI18nService.class); + } + + return phoneNumberI18nService; + } } diff --git a/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdContactQuery.java b/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdContactQuery.java index 1c10bba0d..a3f17d4a8 100644 --- a/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdContactQuery.java +++ b/src/net/java/sip/communicator/plugin/thunderbird/ThunderbirdContactQuery.java @@ -234,7 +234,8 @@ private void addPhoneDetail(List details, Row r, return; } - phone = PhoneNumberI18nService.normalize(phone); + phone + = ThunderbirdActivator.getPhoneNumberI18nService().normalize(phone); ContactDetail detail = new ContactDetail(phone, ContactDetail.Category.Phone, new ContactDetail.SubCategory[] diff --git a/src/net/java/sip/communicator/service/contactsource/AsyncContactQuery.java b/src/net/java/sip/communicator/service/contactsource/AsyncContactQuery.java index 21fa13c1b..c939ff9df 100644 --- a/src/net/java/sip/communicator/service/contactsource/AsyncContactQuery.java +++ b/src/net/java/sip/communicator/service/contactsource/AsyncContactQuery.java @@ -153,7 +153,7 @@ protected boolean addQueryResult(SourceContact sourceContact) */ protected String getPhoneNumberQuery() { - if ((phoneNumberQuery != null) && !queryIsConvertedToPhoneNumber) + if ((phoneNumberQuery == null) && !queryIsConvertedToPhoneNumber) { try { @@ -170,6 +170,16 @@ protected String getPhoneNumberQuery() phoneNumberQuery = pattern.substring(1, patternLength - 1); } + else if ((patternLength > 4) + && (pattern.charAt(0) == '\\') + && (pattern.charAt(1) == 'Q') + && (pattern.charAt(patternLength - 2) == '\\') + && (pattern.charAt(patternLength - 1) == 'E')) + { + phoneNumberQuery + = pattern.substring(2, patternLength - 2); + } + } } finally @@ -304,8 +314,8 @@ protected boolean phoneNumberMatches(String phoneNumber) boolean phoneNumberMatches = false; if (query - .matcher(PhoneNumberI18nService.normalize(phoneNumber)) - .find()) + .matcher(ContactSourceActivator.getPhoneNumberI18nService() + .normalize(phoneNumber)).find()) { phoneNumberMatches = true; } @@ -330,7 +340,8 @@ protected boolean phoneNumberMatches(String phoneNumber) try { phoneNumberMatches - = PhoneNumberI18nService.phoneNumbersMatch( + = ContactSourceActivator.getPhoneNumberI18nService() + .phoneNumbersMatch( phoneNumberQuery, phoneNumber); } diff --git a/src/net/java/sip/communicator/service/contactsource/ContactSourceActivator.java b/src/net/java/sip/communicator/service/contactsource/ContactSourceActivator.java new file mode 100644 index 000000000..77f1bad3d --- /dev/null +++ b/src/net/java/sip/communicator/service/contactsource/ContactSourceActivator.java @@ -0,0 +1,57 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.service.contactsource; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; +import org.osgi.framework.*; + +/** + * @author Damian Minkov + */ +public class ContactSourceActivator + implements BundleActivator +{ + /** + * OSGi bundle context. + */ + public static BundleContext bundleContext; + + /** + * The registered PhoneNumberI18nService. + */ + private static PhoneNumberI18nService phoneNumberI18nService; + + + @Override + public void start(BundleContext bundleContext) + throws Exception + { + this.bundleContext = bundleContext; + } + + @Override + public void stop(BundleContext bundleContext) + throws Exception + {} + + /** + * Returns the PhoneNumberI18nService. + * @return returns the PhoneNumberI18nService. + */ + public static PhoneNumberI18nService getPhoneNumberI18nService() + { + if(phoneNumberI18nService == null) + { + phoneNumberI18nService = ServiceUtils.getService( + bundleContext, + PhoneNumberI18nService.class); + } + + return phoneNumberI18nService; + } +} diff --git a/src/net/java/sip/communicator/service/contactsource/contactsource.manifest.mf b/src/net/java/sip/communicator/service/contactsource/contactsource.manifest.mf index e70e32ca1..f14c42dde 100644 --- a/src/net/java/sip/communicator/service/contactsource/contactsource.manifest.mf +++ b/src/net/java/sip/communicator/service/contactsource/contactsource.manifest.mf @@ -1,4 +1,5 @@ -Bundle-Name: Contact Source Service Interfaces +Bundle-Activator: net.java.sip.communicator.service.contactsource.ContactSourceActivator +Bundle-Name: Contact Source Service Interfaces Bundle-Description: ContactSource Service. Bundle-Vendor: jitsi.org Bundle-Version: 0.0.1 diff --git a/src/net/java/sip/communicator/service/protocol/PhoneNumberI18nService.java b/src/net/java/sip/communicator/service/protocol/PhoneNumberI18nService.java index 4ca060d85..2ee195b9b 100644 --- a/src/net/java/sip/communicator/service/protocol/PhoneNumberI18nService.java +++ b/src/net/java/sip/communicator/service/protocol/PhoneNumberI18nService.java @@ -6,86 +6,16 @@ */ package net.java.sip.communicator.service.protocol; -import java.util.regex.*; - -import org.jitsi.service.configuration.*; - /** * Implements PhoneNumberI18nService which aids the parsing, formatting * and validating of international phone numbers. * * @author Lyubomir Marinov * @author Vincent Lucas + * @author Damian Minkov */ -public abstract class PhoneNumberI18nService +public interface 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 @@ -97,56 +27,7 @@ public abstract class PhoneNumberI18nService * @return a String which is a normalized form of the specified * possibleNumber. */ - public static 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 PhoneNumberI18nService#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(""); - } + public String normalize(String possibleNumber); /** * Determines whether two String phone numbers match. @@ -158,15 +39,7 @@ private static String normalizeIdentifier(String id) * @return true if the specified Strings match as phone * numbers; otherwise, false */ - public static boolean phoneNumbersMatch( - String aPhoneNumber, - String bPhoneNumber) - { - String aPhoneNumberNormalized = normalize(aPhoneNumber); - String bPhoneNumberNormalized = normalize(bPhoneNumber); - - return aPhoneNumberNormalized.equals(bPhoneNumberNormalized); - } + public boolean phoneNumbersMatch(String aPhoneNumber, String bPhoneNumber); /** * Indicates if the given string is possibly a phone number. @@ -175,64 +48,5 @@ public static boolean phoneNumbersMatch( * @return true if the possibleNumber is a phone number, * false - otherwise */ - public static 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"); - } + public boolean isPhoneNumber(String possibleNumber); }