Normalizes phone numbers found in the Address Books of Microsoft Outlook and Mac OS X.

cusax-fix
Lyubomir Marinov 15 years ago
parent 8a95bf4ada
commit e9b0db5a09

@ -2578,6 +2578,7 @@ org.apache.http.util"/>
manifest="${src}/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/plugin/provisioning"
prefix="net/java/sip/communicator/plugin/provisioning" />
<zipfileset src="${lib.noinst}/libphonenumber-2.4.jar" prefix="" />
</jar>
</target>

@ -36,6 +36,7 @@
<classpathentry kind="lib" path="lib/installer-exclude/jspeex.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/junit.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/laf-widget.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/libphonenumber-2.4.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/log4j-1.2.8.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/lti-civil-no_s_w_t.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/jain-sdp.jar"/>

@ -123,7 +123,7 @@
<compilation-unit>
<package-root>src</package-root>
<classpath
mode="compile">lib/felix.jar:lib/jdic-all.jar:lib/bundle/junit.jar:lib/bundle/log4j.jar:lib/bundle/commons-logging.jar:lib/installer-exclude/concurrent.jar:lib/installer-exclude/dict4j.jar:lib/installer-exclude/dnsjava.jar:lib/installer-exclude/jain-sip-api.jar:lib/installer-exclude/jain-sip-ri.jar:lib/installer-exclude/jain-sdp.jar:lib/installer-exclude/jcalendar-1.3.2.jar:lib/installer-exclude/jdic_misc.jar:lib/installer-exclude/jdom.jar:lib/installer-exclude/jmf.jar:lib/installer-exclude/jml-1.0b5.jar:lib/installer-exclude/joscar-client.jar:lib/installer-exclude/joscar-common.jar:lib/installer-exclude/joscar-protocol.jar:lib/installer-exclude/jsocks-klea.jar:lib/installer-exclude/jspeex.jar:lib/installer-exclude/junit.jar:lib/installer-exclude/log4j-1.2.8.jar:lib/installer-exclude/nist-sdp-1.0.jar:lib/installer-exclude/rome-0.9.jar:lib/installer-exclude/smack.jar:lib/installer-exclude/smackx.jar:lib/installer-exclude/ymsg_network_v0_67.jar:lib/installer-exclude/fmj.jar:lib/installer-exclude/jna.jar:lib/installer-exclude/lti-civil-no_s_w_t.jar:lib/installer-exclude/swing-worker-1.2.jar:lib/os-specific/linux/installer-exclude/jmf.jar:lib/os-specific/linux/jdic_stub.jar:lib/os-specific/mac/OrangeExtensions.jar:lib/os-specific/mac/growl4j.jar:lib/os-specific/mac/jdic_stub.jar:lib/os-specific/mac/installer-exclude/jmf.jar:lib/os-specific/mac/installer-exclude/dock.jar:lib/os-specific/windows/jdic_stub.jar:lib/os-specific/windows/installer-exclude/jmf.jar:lib/os-specific/windows/installer-exclude/sound.jar:lib/installer-exclude/aclibico-2.1.jar:lib/installer-exclude/jdic_misc.jar:lib/installer-exclude/pircbot.jar:lib/os-specific/solaris/jdic_stub.jar:lib/os-specific/solaris/installer-exclude/jmf.jar:lib/installer-exclude/jsch-0.1.36.jar:lib/installer-exclude/apache-ant-1.7.0.jar:lib/installer-exclude/izpack-shortcut-link.jar:lib/installer-exclude/jfontchooser-1.0.5.jar:lib/installer-exclude/laf-widget.jar:lib/installer-exclude/transparency.jar:lib/installer-exclude/zrtp4j-light.jar:lib/installer-exclude/lcrypto-jdk16-143.jar:lib/installer-exclude/otr4j.jar:lib/installer-exclude/profiler4j-1.0-beta3-SC.jar:lib/installer-exclude/httpcore-4.0.1.jar:lib/installer-exclude/httpclient-4.0.1.jar:lib/installer-exclude/json-20090723.jar:lib/installer-exclude/ice4j.jar:lib/installer-exclude/dhcp4java-1.00.jar:lib/installer-exclude/jmdns.jar:lib/installer-exclude/jmyspell-core.jar:lib/installer-exclude/jnsapi.jar:lib/installer-exclude/mac_widgets-0.9.5.jar:lib/installer-exclude/forms-1.2.1.jar:lib/installer-exclude/weupnp-0.1.2-SNAPSHOT.jar</classpath>
mode="compile">lib/felix.jar:lib/jdic-all.jar:lib/bundle/junit.jar:lib/bundle/log4j.jar:lib/bundle/commons-logging.jar:lib/installer-exclude/concurrent.jar:lib/installer-exclude/dict4j.jar:lib/installer-exclude/dnsjava.jar:lib/installer-exclude/jain-sip-api.jar:lib/installer-exclude/jain-sip-ri.jar:lib/installer-exclude/jain-sdp.jar:lib/installer-exclude/jcalendar-1.3.2.jar:lib/installer-exclude/jdic_misc.jar:lib/installer-exclude/jdom.jar:lib/installer-exclude/jmf.jar:lib/installer-exclude/jml-1.0b5.jar:lib/installer-exclude/joscar-client.jar:lib/installer-exclude/joscar-common.jar:lib/installer-exclude/joscar-protocol.jar:lib/installer-exclude/jsocks-klea.jar:lib/installer-exclude/jspeex.jar:lib/installer-exclude/junit.jar:lib/installer-exclude/log4j-1.2.8.jar:lib/installer-exclude/nist-sdp-1.0.jar:lib/installer-exclude/rome-0.9.jar:lib/installer-exclude/smack.jar:lib/installer-exclude/smackx.jar:lib/installer-exclude/ymsg_network_v0_67.jar:lib/installer-exclude/fmj.jar:lib/installer-exclude/jna.jar:lib/installer-exclude/lti-civil-no_s_w_t.jar:lib/installer-exclude/swing-worker-1.2.jar:lib/os-specific/linux/installer-exclude/jmf.jar:lib/os-specific/linux/jdic_stub.jar:lib/os-specific/mac/OrangeExtensions.jar:lib/os-specific/mac/growl4j.jar:lib/os-specific/mac/jdic_stub.jar:lib/os-specific/mac/installer-exclude/jmf.jar:lib/os-specific/mac/installer-exclude/dock.jar:lib/os-specific/windows/jdic_stub.jar:lib/os-specific/windows/installer-exclude/jmf.jar:lib/os-specific/windows/installer-exclude/sound.jar:lib/installer-exclude/aclibico-2.1.jar:lib/installer-exclude/jdic_misc.jar:lib/installer-exclude/pircbot.jar:lib/os-specific/solaris/jdic_stub.jar:lib/os-specific/solaris/installer-exclude/jmf.jar:lib/installer-exclude/jsch-0.1.36.jar:lib/installer-exclude/apache-ant-1.7.0.jar:lib/installer-exclude/izpack-shortcut-link.jar:lib/installer-exclude/jfontchooser-1.0.5.jar:lib/installer-exclude/laf-widget.jar:lib/installer-exclude/transparency.jar:lib/installer-exclude/zrtp4j-light.jar:lib/installer-exclude/lcrypto-jdk16-143.jar:lib/installer-exclude/otr4j.jar:lib/installer-exclude/profiler4j-1.0-beta3-SC.jar:lib/installer-exclude/httpcore-4.0.1.jar:lib/installer-exclude/httpclient-4.0.1.jar:lib/installer-exclude/json-20090723.jar:lib/installer-exclude/ice4j.jar:lib/installer-exclude/dhcp4java-1.00.jar:lib/installer-exclude/jmdns.jar:lib/installer-exclude/jmyspell-core.jar:lib/installer-exclude/jnsapi.jar:lib/installer-exclude/mac_widgets-0.9.5.jar:lib/installer-exclude/forms-1.2.1.jar:lib/installer-exclude/weupnp-0.1.2-SNAPSHOT.jar:lib/installer-exclude/libphonenumber-2.4.jar</classpath>
<built-to>classes</built-to>
<source-level>1.5</source-level>
</compilation-unit>

@ -7,6 +7,7 @@
package net.java.sip.communicator.plugin.addrbook;
import net.java.sip.communicator.service.contactsource.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
import org.osgi.framework.*;
@ -27,6 +28,11 @@ public class AddrBookActivator
private static final Logger logger
= Logger.getLogger(AddrBookActivator.class);
/**
* The <tt>BundleContext</tt> in which the addrbook plug-in is started.
*/
private static BundleContext bundleContext;
/**
* The <tt>ContactSourceService</tt> implementation for the OS-specific
* Address Book.
@ -40,6 +46,32 @@ public class AddrBookActivator
*/
private ServiceRegistration cssServiceRegistration;
/**
* The cached reference to the <tt>PhoneNumberI18nService</tt> instance used
* by the functionality of the addrbook plug-in and fetched from its
* <tt>BundleContext</tt>.
*/
private static PhoneNumberI18nService phoneNumberI18nService;
/**
* Gets the <tt>PhoneNumberI18nService</tt> to be used by the functionality
* of the addrbook plug-in.
*
* @return the <tt>PhoneNumberI18nService</tt> to be used by the
* functionality of the addrbook plug-in
*/
public static PhoneNumberI18nService getPhoneNumberI18nService()
{
if (phoneNumberI18nService == null)
{
phoneNumberI18nService
= ServiceUtils.getService(
bundleContext,
PhoneNumberI18nService.class);
}
return phoneNumberI18nService;
}
/**
* Starts the addrbook plug-in.
*
@ -52,6 +84,14 @@ public class AddrBookActivator
public void start(BundleContext bundleContext)
throws Exception
{
AddrBookActivator.bundleContext = bundleContext;
bundleContext.registerService(
PhoneNumberI18nService.class.getName(),
new PhoneNumberI18nServiceImpl(),
null);
/* Register the ContactSourceService implementation (if any). */
String cssClassName;
if (OSUtils.IS_WINDOWS)

@ -10,6 +10,7 @@
import java.util.regex.*;
import net.java.sip.communicator.service.contactsource.*;
import net.java.sip.communicator.service.protocol.*;
/**
* Provides an abstract implementation of a <tt>ContactQuery</tt> which runs in
@ -115,6 +116,27 @@ public List<SourceContact> getQueryResults()
return qr;
}
/**
* 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>
*/
protected String normalizePhoneNumber(String phoneNumber)
{
PhoneNumberI18nService phoneNumberI18nService
= AddrBookActivator.getPhoneNumberI18nService();
return
(phoneNumberI18nService == null)
? phoneNumber
: phoneNumberI18nService.normalize(phoneNumber);
}
/**
* Performs this <tt>ContactQuery</tt> in a background <tt>Thread</tt>.
*/

@ -19,7 +19,6 @@
public abstract class AsyncContactSourceService
implements ExtendedContactSourceService
{
/**
* Queries this <tt>ContactSourceService</tt> for <tt>SourceContact</tt>s
* which match a specific <tt>query</tt> <tt>String</tt>.

@ -0,0 +1,42 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.addrbook;
import net.java.sip.communicator.service.protocol.*;
import com.google.i18n.phonenumbers.*;
/**
* Implements <tt>PhoneNumberI18nService</tt> which aids the parsing, formatting
* and validating of international phone numbers using the libphonenumber
* library.
*
* @author Lyubomir Marinov
*/
public class PhoneNumberI18nServiceImpl
implements PhoneNumberI18nService
{
/**
* 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 PhoneNumberI18nService#normalize(String)
*/
public String normalize(String phoneNumber)
{
return
PhoneNumberUtil.normalizeDigitsOnly(
PhoneNumberUtil.convertAlphaCharactersInNumber(
phoneNumber));
}
}

@ -240,6 +240,9 @@ private List<ContactDetail> getContactDetails(Object[] values)
if (stringValue.length() != 0)
{
if (kABPhoneProperty == property)
stringValue = normalizePhoneNumber(stringValue);
contactDetails.add(
setCapabilities(
new ContactDetail(stringValue),
@ -256,6 +259,12 @@ else if (value instanceof Object[])
if (stringSubValue.length() != 0)
{
if (kABPhoneProperty == property)
{
stringSubValue
= normalizePhoneNumber(stringSubValue);
}
contactDetails.add(
setCapabilities(
new ContactDetail(stringSubValue),
@ -487,6 +496,27 @@ else if (value instanceof Object[])
*/
private static native long kABYahooInstantProperty();
/**
* Determines whether a specific <tt>ABPerson</tt> property with a specific
* <tt>value</tt> matches the {@link #query} of this
* <tt>AsyncContactQuery</tt>.
*
* @param property the <tt>ABPerson</tt> property to check
* @param value the value of the <tt>property</tt> to check
* @return <tt>true</tt> if the specified <tt>value</tt> of the specified
* <tt>property</tt> matches the <tt>query</tt> of this
* <tt>AsyncContactQuery</tt>; otherwise, <tt>false</tt>
*/
private boolean matches(int property, String value)
{
return
query.matcher(value).find()
|| ((kABPhoneProperty == property)
&& query
.matcher(normalizePhoneNumber(value))
.find());
}
/**
* Determines whether an <tt>ABPerson</tt> represented by the values of its
* {@link #ABPERSON_PROPERTIES} matches {@link #query}.
@ -500,11 +530,13 @@ else if (value instanceof Object[])
*/
private boolean matches(Object[] values)
{
int property = 0;
for (Object value : values)
{
if (value instanceof String)
{
if (query.matcher((String) value).find())
if (matches(property, (String) value))
return true;
}
else if (value instanceof Object[])
@ -512,10 +544,11 @@ else if (value instanceof Object[])
for (Object subValue : (Object[]) value)
{
if ((subValue instanceof String)
&& query.matcher((String) subValue).find())
&& matches(property, (String) subValue))
return true;
}
}
property++;
}
return false;
}

@ -194,6 +194,30 @@ private static native Object[] IMAPIProp_GetProps(
long[] propIds, long flags)
throws MsOutlookMAPIHResultException;
/**
* Determines whether a specific index in {@link #MAPI_MAILUSER_PROP_IDS}
* stands for a property with a phone number value.
*
* @param propIndex the index in <tt>MAPI_MAILUSER_PROP_IDS</tt> of the
* property to check
* @return <tt>true</tt> if <tt>propIndex</tt> stands for a property with a
* phone number value; otherwise, <tt>false</tt>
*/
private boolean isPhoneNumber(int propIndex)
{
switch (propIndex)
{
case PR_BUSINESS2_TELEPHONE_NUMBER:
case PR_BUSINESS_TELEPHONE_NUMBER:
case PR_HOME2_TELEPHONE_NUMBER:
case PR_HOME_TELEPHONE_NUMBER:
case PR_MOBILE_TELEPHONE_NUMBER:
return true;
default:
return false;
}
}
/**
* Notifies this <tt>MsOutlookAddrBookContactQuery</tt> about a specific
* <tt>MAPI_MAILUSER</tt>.
@ -225,15 +249,24 @@ private boolean onMailUser(long iUnknown)
if ((MAPI_MAILUSER == objType) && (mapiMessageCount != 0))
return false;
int propIndex = 0;
boolean matches = false;
for (Object prop : props)
{
if ((prop instanceof String) && query.matcher((String) prop).find())
if ((prop instanceof String)
&& (query.matcher((String) prop).find()
|| (isPhoneNumber(propIndex)
&& query
.matcher(
normalizePhoneNumber(
(String) prop))
.find())))
{
matches = true;
break;
}
propIndex++;
}
if (matches)
{
@ -247,7 +280,9 @@ private boolean onMailUser(long iUnknown)
for (int i = 0; i < CONTACT_DETAIL_PROP_INDEXES.length; i++)
{
Object prop = props[CONTACT_DETAIL_PROP_INDEXES[i]];
propIndex = CONTACT_DETAIL_PROP_INDEXES[i];
Object prop = props[propIndex];
if (prop instanceof String)
{
@ -255,6 +290,9 @@ private boolean onMailUser(long iUnknown)
if (stringProp.length() != 0)
{
if (isPhoneNumber(propIndex))
stringProp = normalizePhoneNumber(stringProp);
ContactDetail contactDetail
= new ContactDetail(stringProp);

@ -0,0 +1,28 @@
/*
* SIP Communicator, 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.protocol;
/**
* Represents an OSGi service which aids the parsing, formatting and validating
* of international phone numbers.
*
* @author Lyubomir Marinov
*/
public interface PhoneNumberI18nService
{
/**
* 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>
*/
public String normalize(String phoneNumber);
}
Loading…
Cancel
Save