aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/plugin
diff options
context:
space:
mode:
authorSebastien Vincent <seb@jitsi.org>2011-03-09 09:30:54 +0000
committerSebastien Vincent <seb@jitsi.org>2011-03-09 09:30:54 +0000
commit5393fc96a763bcf0ecedf95275edc7712f2b897f (patch)
tree9dab2f9963a2aca12b6038ada01165a655141057 /src/net/java/sip/communicator/plugin
parentdcb607dd8b10f297af6a590e29a7b9b6f6002aff (diff)
downloadjitsi-5393fc96a763bcf0ecedf95275edc7712f2b897f.zip
jitsi-5393fc96a763bcf0ecedf95275edc7712f2b897f.tar.gz
jitsi-5393fc96a763bcf0ecedf95275edc7712f2b897f.tar.bz2
Ongoing work on LDAP contact source support.
Diffstat (limited to 'src/net/java/sip/communicator/plugin')
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/AddrBookSourceContact.java194
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/AsyncContactQuery.java325
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/AsyncContactSourceService.java63
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactQuery.java97
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactSourceService.java1
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java95
-rw-r--r--src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java1
-rw-r--r--src/net/java/sip/communicator/plugin/ldap/LdapActivator.java150
-rw-r--r--src/net/java/sip/communicator/plugin/ldap/LdapContactQuery.java352
-rw-r--r--src/net/java/sip/communicator/plugin/ldap/LdapContactSourceService.java172
-rw-r--r--src/net/java/sip/communicator/plugin/ldap/ldap.manifest.mf12
11 files changed, 873 insertions, 589 deletions
diff --git a/src/net/java/sip/communicator/plugin/addrbook/AddrBookSourceContact.java b/src/net/java/sip/communicator/plugin/addrbook/AddrBookSourceContact.java
deleted file mode 100644
index 91cfceb..0000000
--- a/src/net/java/sip/communicator/plugin/addrbook/AddrBookSourceContact.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * 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 java.util.*;
-
-import net.java.sip.communicator.service.contactsource.*;
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * Implements a generic <tt>SourceContact</tt> for the purposes of the support
- * for the OS-specific Address Book.
- *
- * @author Lyubomir Marinov
- */
-public class AddrBookSourceContact
- implements SourceContact
-{
- /**
- * The <tt>ContactDetail</tt>s of this <tt>SourceContact</tt>.
- */
- private final List<ContactDetail> contactDetails;
-
- /**
- * The <tt>ContactSourceService</tt> which has created this
- * <tt>SourceContact</tt>.
- */
- private final ContactSourceService contactSource;
-
- /**
- * The display name of this <tt>SourceContact</tt>.
- */
- private final String displayName;
-
- /**
- * The image/avatar of this <tt>SourceContact</tt>
- */
- private byte[] image;
-
- /**
- * Initializes a new <tt>AddrBookSourceContact</tt> instance.
- *
- * @param contactSource the <tt>ContactSourceService</tt> which is creating
- * the new instance
- * @param displayName the display name of the new instance
- * @param contactDetails the <tt>ContactDetail</tt>s of the new instance
- */
- public AddrBookSourceContact(
- ContactSourceService contactSource,
- String displayName,
- List<ContactDetail> contactDetails)
- {
- this.contactSource = contactSource;
- this.displayName = displayName;
- this.contactDetails = contactDetails;
- }
-
- /**
- * Gets the <tt>ContactDetail</tt>s of this <tt>SourceContact</tt>.
- *
- * @return the <tt>ContactDetail</tt>s of this <tt>SourceContact</tt>
- * @see SourceContact#getContactDetails()
- */
- public List<ContactDetail> getContactDetails()
- {
- return Collections.unmodifiableList(contactDetails);
- }
-
- /**
- * Gets the <tt>ContactDetail</tt>s of this <tt>SourceContact</tt> which
- * support a specific <tt>OperationSet</tt>.
- *
- * @param operationSet the <tt>OperationSet</tt> the supporting
- * <tt>ContactDetail</tt>s of which are to be returned
- * @return the <tt>ContactDetail</tt>s of this <tt>SourceContact</tt> which
- * support the specified <tt>operationSet</tt>
- * @see SourceContact#getContactDetails(Class)
- */
- public List<ContactDetail> getContactDetails(
- Class<? extends OperationSet> operationSet)
- {
- List<ContactDetail> contactDetails = new LinkedList<ContactDetail>();
-
- for (ContactDetail contactDetail : getContactDetails())
- {
- List<Class<? extends OperationSet>> supportedOperationSets
- = contactDetail.getSupportedOperationSets();
-
- if ((supportedOperationSets != null)
- && supportedOperationSets.contains(operationSet))
- contactDetails.add(contactDetail);
- }
- return contactDetails;
- }
-
- /**
- * Returns a list of all <tt>ContactDetail</tt>s corresponding to the given
- * category.
- * @param category the <tt>OperationSet</tt> class we're looking for
- * @return a list of all <tt>ContactDetail</tt>s corresponding to the given
- * category
- */
- public List<ContactDetail> getContactDetails(String category)
- {
- List<ContactDetail> contactDetails = new LinkedList<ContactDetail>();
-
- for (ContactDetail contactDetail : getContactDetails())
- {
- String detailCategory = contactDetail.getCategory();
- if (detailCategory != null && detailCategory.equals(category))
- contactDetails.add(contactDetail);
- }
- return contactDetails;
- }
-
- /**
- * Gets the <tt>ContactSourceService</tt> which has created this
- * <tt>SourceContact</tt>.
- *
- * @return the <tt>ContactSourceService</tt> which has created this
- * <tt>SourceContact</tt>
- * @see SourceContact#getContactSource()
- */
- public ContactSourceService getContactSource()
- {
- return contactSource;
- }
-
- /**
- * Gets the display details of this <tt>SourceContact</tt>.
- *
- * @return the display details of this <tt>SourceContact</tt>
- * @see SourceContact#getDisplayDetails()
- */
- public String getDisplayDetails()
- {
- // TODO Auto-generated method stub
- return null;
- }
-
- /**
- * Gets the display name of this <tt>SourceContact</tt>.
- *
- * @return the display name of this <tt>SourceContact</tt>
- * @see SourceContact#getDisplayName()
- */
- public String getDisplayName()
- {
- return displayName;
- }
-
- /**
- * Gets the image/avatar of this <tt>SourceContact</tt>.
- *
- * @return the image/avatar of this <tt>SourceContact</tt>
- * @see SourceContact#getImage()
- */
- public byte[] getImage()
- {
- return image;
- }
-
- /**
- * Gets the preferred <tt>ContactDetail</tt> for a specific
- * <tt>OperationSet</tt>.
- *
- * @param operationSet the <tt>OperationSet</tt> to get the preferred
- * <tt>ContactDetail</tt> for
- * @return the preferred <tt>ContactDetail</tt> for the specified
- * <tt>operationSet</tt>
- * @see SourceContact#getPreferredContactDetail(Class)
- */
- public ContactDetail getPreferredContactDetail(
- Class<? extends OperationSet> operationSet)
- {
- List<ContactDetail> contactDetails = getContactDetails(operationSet);
-
- return contactDetails.isEmpty() ? null : contactDetails.get(0);
- }
-
- /**
- * Sets the image/avatar of this <tt>SourceContact</tt>.
- *
- * @param image the image/avatar to be set on this <tt>SourceContact</tt>
- */
- public void setImage(byte[] image)
- {
- this.image = image;
- }
-}
diff --git a/src/net/java/sip/communicator/plugin/addrbook/AsyncContactQuery.java b/src/net/java/sip/communicator/plugin/addrbook/AsyncContactQuery.java
deleted file mode 100644
index 502a7d4..0000000
--- a/src/net/java/sip/communicator/plugin/addrbook/AsyncContactQuery.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * 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 java.util.*;
-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
- * a separate <tt>Thread</tt>.
- *
- * @author Lyubomir Marinov
- * @param <T> the very type of <tt>ContactSourceService</tt> which performs the
- * <tt>ContactQuery</tt>
- */
-public abstract class AsyncContactQuery<T extends ContactSourceService>
- extends AbstractContactQuery<T>
-{
- /**
- * The {@link #query} in the form of a <tt>String</tt> telephone number if
- * such parsing, formatting and validation is possible; otherwise,
- * <tt>null</tt>.
- */
- private String phoneNumberQuery;
-
- /**
- * The <tt>Pattern</tt> for which the associated
- * <tt>ContactSourceService</tt> is being queried.
- */
- protected final Pattern query;
-
- /**
- * The indicator which determines whether there has been an attempt to
- * convert {@link #query} to {@link #phoneNumberQuery}. If the conversion has
- * been successful, <tt>phoneNumberQuery</tt> will be non-<tt>null</tt>.
- */
- private boolean queryIsConvertedToPhoneNumber;
-
- /**
- * The <tt>SourceContact</tt>s which match {@link #query}.
- */
- private final List<SourceContact> queryResults
- = new LinkedList<SourceContact>();
-
- /**
- * The <tt>Thread</tt> in which this <tt>AsyncContactQuery</tt> is
- * performing {@link #query}.
- */
- private Thread thread;
-
- /**
- * Initializes a new <tt>AsyncContactQuery</tt> instance which is to perform
- * a specific <tt>query</tt> on behalf of a specific <tt>contactSource</tt>.
- *
- * @param contactSource the <tt>ContactSourceService</tt> which is to
- * perform the new <tt>ContactQuery</tt> instance
- * @param query the <tt>Pattern</tt> for which <tt>contactSource</tt> is
- * being queried
- */
- protected AsyncContactQuery(T contactSource, Pattern query)
- {
- super(contactSource);
-
- this.query = query;
- }
-
- /**
- * Adds a specific <tt>SourceContact</tt> to the list of
- * <tt>SourceContact</tt>s to be returned by this <tt>ContactQuery</tt> in
- * response to {@link #getQueryResults()}.
- *
- * @param sourceContact the <tt>SourceContact</tt> to be added to the
- * <tt>queryResults</tt> of this <tt>ContactQuery</tt>
- * @return <tt>true</tt> if the <tt>queryResults</tt> of this
- * <tt>ContactQuery</tt> has changed in response to the call
- */
- protected boolean addQueryResult(SourceContact sourceContact)
- {
- boolean changed;
-
- synchronized (queryResults)
- {
- changed = queryResults.add(sourceContact);
- }
- if (changed)
- fireContactReceived(sourceContact);
- return changed;
- }
-
- /**
- * Gets the {@link #query} of this <tt>AsyncContactQuery</tt> as a
- * <tt>String</tt> which represents a phone number (if possible).
- *
- * @return a <tt>String</tt> which represents the <tt>query</tt> of this
- * <tt>AsyncContactQuery</tt> as a phone number if such parsing, formatting
- * and validation is possible; otherwise, <tt>null</tt>
- */
- protected String getPhoneNumberQuery()
- {
- if ((phoneNumberQuery != null) && !queryIsConvertedToPhoneNumber)
- {
- try
- {
- String pattern = query.pattern();
-
- if (pattern != null)
- {
- int patternLength = pattern.length();
-
- if ((patternLength > 2)
- && (pattern.charAt(0) == '^')
- && (pattern.charAt(patternLength - 1) == '$'))
- {
- phoneNumberQuery
- = pattern.substring(1, patternLength - 1);
- }
- }
- }
- finally
- {
- queryIsConvertedToPhoneNumber = true;
- }
- }
- return phoneNumberQuery;
- }
-
- /**
- * Gets the number of <tt>SourceContact</tt>s which match this
- * <tt>ContactQuery</tt>.
- *
- * @return the number of <tt>SourceContact</tt> which match this
- * <tt>ContactQuery</tt>
- */
- public int getQueryResultCount()
- {
- synchronized (queryResults)
- {
- return queryResults.size();
- }
- }
-
- /**
- * Gets the <tt>List</tt> of <tt>SourceContact</tt>s which match this
- * <tt>ContactQuery</tt>.
- *
- * @return the <tt>List</tt> of <tt>SourceContact</tt>s which match this
- * <tt>ContactQuery</tt>
- * @see ContactQuery#getQueryResults()
- */
- public List<SourceContact> getQueryResults()
- {
- List<SourceContact> qr;
-
- synchronized (queryResults)
- {
- qr = new ArrayList<SourceContact>(queryResults.size());
- qr.addAll(queryResults);
- }
- return qr;
- }
-
- /**
- * Returns the query string, this query was created for.
- *
- * @return the query string, this query was created for
- */
- public String getQueryString()
- {
- return query.toString();
- }
-
- /**
- * 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);
- }
-
- /**
- * Determines whether a specific <tt>String</tt> phone number matches the
- * {@link #query} of this <tt>AsyncContactQuery</tt>.
- *
- * @param phoneNumber the <tt>String</tt> which represents the phone number
- * to match to the <tt>query</tt> of this <tt>AsyncContactQuery</tt>
- * @return <tt>true</tt> if the specified <tt>phoneNumber</tt> matches the
- * <tt>query</tt> of this <tt>AsyncContactQuery</tt>; otherwise,
- * <tt>false</tt>
- */
- protected boolean phoneNumberMatches(String phoneNumber)
- {
- /*
- * PhoneNumberI18nService implements functionality to aid the parsing,
- * formatting and validation of international phone numbers so attempt to
- * use it to determine whether the specified phoneNumber matches the
- * query. For example, check whether the normalized phoneNumber matches
- * the query.
- */
-
- PhoneNumberI18nService phoneNumberI18nService
- = AddrBookActivator.getPhoneNumberI18nService();
- boolean phoneNumberMatches = false;
-
- if (phoneNumberI18nService != null)
- {
- if (query
- .matcher(phoneNumberI18nService.normalize(phoneNumber))
- .find())
- {
- phoneNumberMatches = true;
- }
- else
- {
- /*
- * The fact that the normalized form of the phoneNumber doesn't
- * match the query doesn't mean that, for example, it doesn't
- * match the normalized form of the query. The latter, though,
- * requires the query to look like a phone number as well. In
- * order to not accidentally start matching all queries to phone
- * numbers, it seems justified to normalize the query only when
- * it is a phone number, not whenever it looks like a piece of a
- * phone number.
- */
-
- String phoneNumberQuery = getPhoneNumberQuery();
-
- if ((phoneNumberQuery != null)
- && (phoneNumberQuery.length() != 0))
- {
- try
- {
- phoneNumberMatches
- = phoneNumberI18nService.phoneNumbersMatch(
- phoneNumberQuery,
- phoneNumber);
- }
- catch (IllegalArgumentException iaex)
- {
- /*
- * Ignore it, phoneNumberMatches will remain equal to
- * false.
- */
- }
- }
- }
- }
- return phoneNumberMatches;
- }
-
- /**
- * Performs this <tt>ContactQuery</tt> in a background <tt>Thread</tt>.
- */
- protected abstract void run();
-
- /**
- * Starts this <tt>AsyncContactQuery</tt>.
- */
- public synchronized void start()
- {
- if (thread == null)
- {
- thread
- = new Thread()
- {
- @Override
- public void run()
- {
- boolean completed = false;
-
- try
- {
- AsyncContactQuery.this.run();
- completed = true;
- }
- finally
- {
- synchronized (AsyncContactQuery.this)
- {
- if (thread == Thread.currentThread())
- stopped(completed);
- }
- }
- }
- };
- thread.setDaemon(true);
- thread.start();
- }
- else
- throw new IllegalStateException("thread");
- }
-
- /**
- * Notifies this <tt>AsyncContactQuery</tt> that it has stopped performing
- * in the associated background <tt>Thread</tt>.
- *
- * @param completed <tt>true</tt> if this <tt>ContactQuery</tt> has
- * successfully completed, <tt>false</tt> if an error has been encountered
- * during its execution
- */
- protected void stopped(boolean completed)
- {
- if (getStatus() == QUERY_IN_PROGRESS)
- setStatus(completed ? QUERY_COMPLETED : QUERY_ERROR);
- }
-}
diff --git a/src/net/java/sip/communicator/plugin/addrbook/AsyncContactSourceService.java b/src/net/java/sip/communicator/plugin/addrbook/AsyncContactSourceService.java
deleted file mode 100644
index c89d9aa..0000000
--- a/src/net/java/sip/communicator/plugin/addrbook/AsyncContactSourceService.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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 java.util.regex.*;
-
-import net.java.sip.communicator.service.contactsource.*;
-
-/**
- * Declares the interface of a <tt>ContactSourceService</tt> which performs
- * <tt>ContactQuery</tt>s in a separate <tt>Thread</tt>.
- *
- * @author Lyubomir Marinov
- */
-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>.
- *
- * @param query the <tt>String</tt> which this <tt>ContactSourceService</tt>
- * is being queried for
- * @return a <tt>ContactQuery</tt> which represents the query of this
- * <tt>ContactSourceService</tt> implementation for the specified
- * <tt>String</tt> and via which the matching <tt>SourceContact</tt>s (if
- * any) will be returned
- * @see ContactSourceService#queryContactSource(String)
- */
- public ContactQuery queryContactSource(String query)
- {
- return queryContactSource(
- Pattern.compile(query, Pattern.CASE_INSENSITIVE | Pattern.LITERAL));
- }
-
- /**
- * Queries this <tt>ContactSourceService</tt> for <tt>SourceContact</tt>s
- * which match a specific <tt>query</tt> <tt>String</tt>.
- *
- * @param query the <tt>String</tt> which this <tt>ContactSourceService</tt>
- * is being queried for
- * @param contactCount the maximum count of result contacts
- * @return a <tt>ContactQuery</tt> which represents the query of this
- * <tt>ContactSourceService</tt> implementation for the specified
- * <tt>String</tt> and via which the matching <tt>SourceContact</tt>s (if
- * any) will be returned
- * @see ContactSourceService#queryContactSource(String)
- */
- public ContactQuery queryContactSource(String query, int contactCount)
- {
- return queryContactSource(
- Pattern.compile(query, Pattern.CASE_INSENSITIVE | Pattern.LITERAL));
- }
-
- /**
- * Stops this <tt>ContactSourceService</tt>.
- */
- public abstract void stop();
-}
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 280dc33..8c224c9 100644
--- a/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactQuery.java
+++ b/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactQuery.java
@@ -616,7 +616,7 @@ public class MacOSXAddrBookContactQuery
/**
* Determines whether an <tt>ABPerson</tt> represented by the values of its
* {@link #ABPERSON_PROPERTIES} matches {@link #query}.
- *
+ *
* @param values the values of the <tt>ABPERSON_PROPERTIES</tt> which
* represent the <tt>ABPerson</tt> to be determined whether it matches
* <tt>query</tt>
@@ -675,8 +675,8 @@ public class MacOSXAddrBookContactQuery
if (!contactDetails.isEmpty())
{
- AddrBookSourceContact sourceContact
- = new AddrBookSourceContact(
+ GenericSourceContact sourceContact
+ = new GenericSourceContact(
getContactSource(),
displayName,
contactDetails);
@@ -787,4 +787,95 @@ public class MacOSXAddrBookContactQuery
return contactDetail;
}
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Determines whether a specific <tt>String</tt> phone number matches the
+ * {@link #query} of this <tt>AsyncContactQuery</tt>.
+ *
+ * @param phoneNumber the <tt>String</tt> which represents the phone number
+ * to match to the <tt>query</tt> of this <tt>AsyncContactQuery</tt>
+ * @return <tt>true</tt> if the specified <tt>phoneNumber</tt> matches the
+ * <tt>query</tt> of this <tt>AsyncContactQuery</tt>; otherwise,
+ * <tt>false</tt>
+ */
+ protected boolean phoneNumberMatches(String phoneNumber)
+ {
+ /*
+ * PhoneNumberI18nService implements functionality to aid the parsing,
+ * formatting and validation of international phone numbers so attempt to
+ * use it to determine whether the specified phoneNumber matches the
+ * query. For example, check whether the normalized phoneNumber matches
+ * the query.
+ */
+
+ PhoneNumberI18nService phoneNumberI18nService
+ = AddrBookActivator.getPhoneNumberI18nService();
+ boolean phoneNumberMatches = false;
+
+ if (phoneNumberI18nService != null)
+ {
+ if (query
+ .matcher(phoneNumberI18nService.normalize(phoneNumber))
+ .find())
+ {
+ phoneNumberMatches = true;
+ }
+ else
+ {
+ /*
+ * The fact that the normalized form of the phoneNumber doesn't
+ * match the query doesn't mean that, for example, it doesn't
+ * match the normalized form of the query. The latter, though,
+ * requires the query to look like a phone number as well. In
+ * order to not accidentally start matching all queries to phone
+ * numbers, it seems justified to normalize the query only when
+ * it is a phone number, not whenever it looks like a piece of a
+ * phone number.
+ */
+
+ String phoneNumberQuery = getPhoneNumberQuery();
+
+ if ((phoneNumberQuery != null)
+ && (phoneNumberQuery.length() != 0))
+ {
+ try
+ {
+ phoneNumberMatches
+ = phoneNumberI18nService.phoneNumbersMatch(
+ phoneNumberQuery,
+ phoneNumber);
+ }
+ catch (IllegalArgumentException iaex)
+ {
+ /*
+ * Ignore it, phoneNumberMatches will remain equal to
+ * false.
+ */
+ }
+ }
+ }
+ }
+ return phoneNumberMatches;
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactSourceService.java b/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactSourceService.java
index 46e54d2..bb06efe 100644
--- a/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactSourceService.java
+++ b/src/net/java/sip/communicator/plugin/addrbook/macosx/MacOSXAddrBookContactSourceService.java
@@ -8,7 +8,6 @@ package net.java.sip.communicator.plugin.addrbook.macosx;
import java.util.regex.*;
-import net.java.sip.communicator.plugin.addrbook.*;
import net.java.sip.communicator.service.contactsource.*;
/**
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 535e1a1..7ecb171 100644
--- a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java
+++ b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactQuery.java
@@ -376,8 +376,8 @@ public class MsOutlookAddrBookContactQuery
}
}
- AddrBookSourceContact sourceContact
- = new AddrBookSourceContact(
+ GenericSourceContact sourceContact
+ = new GenericSourceContact(
getContactSource(),
(String) props[PR_DISPLAY_NAME],
contactDetails);
@@ -456,4 +456,95 @@ public class MsOutlookAddrBookContactQuery
getContactSource().stopped(this);
}
}
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Determines whether a specific <tt>String</tt> phone number matches the
+ * {@link #query} of this <tt>AsyncContactQuery</tt>.
+ *
+ * @param phoneNumber the <tt>String</tt> which represents the phone number
+ * to match to the <tt>query</tt> of this <tt>AsyncContactQuery</tt>
+ * @return <tt>true</tt> if the specified <tt>phoneNumber</tt> matches the
+ * <tt>query</tt> of this <tt>AsyncContactQuery</tt>; otherwise,
+ * <tt>false</tt>
+ */
+ protected boolean phoneNumberMatches(String phoneNumber)
+ {
+ /*
+ * PhoneNumberI18nService implements functionality to aid the parsing,
+ * formatting and validation of international phone numbers so attempt to
+ * use it to determine whether the specified phoneNumber matches the
+ * query. For example, check whether the normalized phoneNumber matches
+ * the query.
+ */
+
+ PhoneNumberI18nService phoneNumberI18nService
+ = AddrBookActivator.getPhoneNumberI18nService();
+ boolean phoneNumberMatches = false;
+
+ if (phoneNumberI18nService != null)
+ {
+ if (query
+ .matcher(phoneNumberI18nService.normalize(phoneNumber))
+ .find())
+ {
+ phoneNumberMatches = true;
+ }
+ else
+ {
+ /*
+ * The fact that the normalized form of the phoneNumber doesn't
+ * match the query doesn't mean that, for example, it doesn't
+ * match the normalized form of the query. The latter, though,
+ * requires the query to look like a phone number as well. In
+ * order to not accidentally start matching all queries to phone
+ * numbers, it seems justified to normalize the query only when
+ * it is a phone number, not whenever it looks like a piece of a
+ * phone number.
+ */
+
+ String phoneNumberQuery = getPhoneNumberQuery();
+
+ if ((phoneNumberQuery != null)
+ && (phoneNumberQuery.length() != 0))
+ {
+ try
+ {
+ phoneNumberMatches
+ = phoneNumberI18nService.phoneNumbersMatch(
+ phoneNumberQuery,
+ phoneNumber);
+ }
+ catch (IllegalArgumentException iaex)
+ {
+ /*
+ * Ignore it, phoneNumberMatches will remain equal to
+ * false.
+ */
+ }
+ }
+ }
+ }
+ return phoneNumberMatches;
+ }
}
diff --git a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java
index 20c915a..ddb2a82 100644
--- a/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java
+++ b/src/net/java/sip/communicator/plugin/addrbook/msoutlook/MsOutlookAddrBookContactSourceService.java
@@ -9,7 +9,6 @@ package net.java.sip.communicator.plugin.addrbook.msoutlook;
import java.util.*;
import java.util.regex.*;
-import net.java.sip.communicator.plugin.addrbook.*;
import net.java.sip.communicator.service.contactsource.*;
/**
diff --git a/src/net/java/sip/communicator/plugin/ldap/LdapActivator.java b/src/net/java/sip/communicator/plugin/ldap/LdapActivator.java
new file mode 100644
index 0000000..76f7a61
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/ldap/LdapActivator.java
@@ -0,0 +1,150 @@
+/*
+ * 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.ldap;
+
+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.service.gui.*;
+import net.java.sip.communicator.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * Implements <tt>BundleActivator</tt> for the LDAP plug-in which provides
+ * support for LDAP contact sources.
+ *
+ * @author Sebastien Vincent
+ */
+public class LdapActivator implements BundleActivator
+{
+ /**
+ * The <tt>BundleContext</tt> in which the LDAP plug-in is started.
+ */
+ private static BundleContext bundleContext = null;
+
+ /**
+ * LDAP service.
+ */
+ private static LdapService ldapService = null;
+
+ /**
+ * The <tt>ContactSourceService</tt> implementation for the OS-specific
+ * Address Book.
+ */
+ private LdapContactSourceService css = null;
+
+ /**
+ * The <tt>ServiceRegistration</tt> of {@link #css} in the
+ * <tt>BundleContext</tt> in which this <tt>LdapActivator</tt> has been
+ * started.
+ */
+ private ServiceRegistration cssServiceRegistration = null;
+
+ /**
+ * The cached reference to the <tt>PhoneNumberI18nService</tt> instance used
+ * by the functionality of the LDAP plug-in and fetched from its
+ * <tt>BundleContext</tt>.
+ */
+ private static PhoneNumberI18nService phoneNumberI18nService;
+
+ /**
+ * Starts the LDAP plug-in.
+ *
+ * @param bundleContext the <tt>BundleContext</tt> in which the LDAP
+ * plug-in is to be started
+ * @throws Exception if anything goes wrong while starting the LDAP
+ * plug-in
+ * @see BundleActivator#start(BundleContext)
+ */
+ public void start(BundleContext bundleContext) throws Exception
+ {
+ LdapActivator.bundleContext = bundleContext;
+
+ css = new LdapContactSourceService();
+
+ try
+ {
+ cssServiceRegistration
+ = bundleContext.registerService(
+ ContactSourceService.class.getName(),
+ css,
+ null);
+ }
+ finally
+ {
+ if (cssServiceRegistration == null)
+ {
+ css.stop();
+ css = null;
+ }
+ }
+ }
+
+ /**
+ * Get LDAP service.
+ *
+ * @return LDAP service
+ */
+ public static LdapService getLdapService()
+ {
+ if(ldapService == null)
+ {
+ ldapService = ServiceUtils.getService(bundleContext,
+ LdapService.class);
+ }
+
+ return ldapService;
+ }
+
+ /**
+ * Stops the LDAP plug-in.
+ *
+ * @param bundleContext the <tt>BundleContext</tt> in which the LDAP
+ * plug-in is to be stopped
+ * @throws Exception if anything goes wrong while stopping the LDAP
+ * plug-in
+ * @see BundleActivator#stop(BundleContext)
+ */
+ public void stop(BundleContext bundleContext) throws Exception
+ {
+ try
+ {
+ if (cssServiceRegistration != null)
+ {
+ cssServiceRegistration.unregister();
+ cssServiceRegistration = null;
+ }
+ }
+ finally
+ {
+ if (css != null)
+ {
+ css.stop();
+ }
+ }
+ }
+
+ /**
+ * 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;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/ldap/LdapContactQuery.java b/src/net/java/sip/communicator/plugin/ldap/LdapContactQuery.java
new file mode 100644
index 0000000..637c314
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/ldap/LdapContactQuery.java
@@ -0,0 +1,352 @@
+package net.java.sip.communicator.plugin.ldap;
+
+import java.util.*;
+import java.util.regex.*;
+
+import net.java.sip.communicator.service.ldap.*;
+import net.java.sip.communicator.service.ldap.event.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.contactsource.*;
+
+/**
+ * Implements <tt>ContactQuery</tt> for LDAP.
+ *
+ * @author Sebastien Vincent
+ */
+public class LdapContactQuery
+ extends AsyncContactQuery<LdapContactSourceService>
+{
+ /**
+ * Maximum results for LDAP query.
+ */
+ public static final int LDAP_MAX_RESULTS = 40;
+
+ /**
+ * Maximum number of results for this instance.
+ */
+ private final int count;
+
+ /**
+ * LDAP query.
+ */
+ LdapQuery ldapQuery = null;
+
+ /**
+ * Object lock.
+ */
+ private final Object objLock = new Object();
+
+ /**
+ * Initializes a new <tt>LdapContactQuery</tt> instance which is to perform
+ * a specific <tt>query</tt> on behalf of a specific <tt>contactSource</tt>.
+ *
+ * @param contactSource the <tt>ContactSourceService</tt> which is to
+ * perform the new <tt>ContactQuery</tt> instance
+ * @param query the <tt>Pattern</tt> for which <tt>contactSource</tt> is
+ * being queried
+ * @param count maximum number of results
+ */
+ protected LdapContactQuery(LdapContactSourceService
+ contactSource, Pattern query, int count)
+ {
+ super(contactSource, query);
+ this.count = count;
+ }
+
+ /**
+ * 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
+ = LdapActivator.getPhoneNumberI18nService();
+
+ return
+ (phoneNumberI18nService == null)
+ ? phoneNumber
+ : phoneNumberI18nService.normalize(phoneNumber);
+ }
+
+ /**
+ * Determines whether a specific <tt>String</tt> phone number matches the
+ * {@link #query} of this <tt>AsyncContactQuery</tt>.
+ *
+ * @param phoneNumber the <tt>String</tt> which represents the phone number
+ * to match to the <tt>query</tt> of this <tt>AsyncContactQuery</tt>
+ * @return <tt>true</tt> if the specified <tt>phoneNumber</tt> matches the
+ * <tt>query</tt> of this <tt>AsyncContactQuery</tt>; otherwise,
+ * <tt>false</tt>
+ */
+ protected boolean phoneNumberMatches(String phoneNumber)
+ {
+ /*
+ * PhoneNumberI18nService implements functionality to aid the parsing,
+ * formatting and validation of international phone numbers so attempt to
+ * use it to determine whether the specified phoneNumber matches the
+ * query. For example, check whether the normalized phoneNumber matches
+ * the query.
+ */
+
+ PhoneNumberI18nService phoneNumberI18nService
+ = LdapActivator.getPhoneNumberI18nService();
+ boolean phoneNumberMatches = false;
+
+ if (phoneNumberI18nService != null)
+ {
+ if (query
+ .matcher(phoneNumberI18nService.normalize(phoneNumber))
+ .find())
+ {
+ phoneNumberMatches = true;
+ }
+ else
+ {
+ /*
+ * The fact that the normalized form of the phoneNumber doesn't
+ * match the query doesn't mean that, for example, it doesn't
+ * match the normalized form of the query. The latter, though,
+ * requires the query to look like a phone number as well. In
+ * order to not accidentally start matching all queries to phone
+ * numbers, it seems justified to normalize the query only when
+ * it is a phone number, not whenever it looks like a piece of a
+ * phone number.
+ */
+
+ String phoneNumberQuery = getPhoneNumberQuery();
+
+ if ((phoneNumberQuery != null)
+ && (phoneNumberQuery.length() != 0))
+ {
+ try
+ {
+ phoneNumberMatches
+ = phoneNumberI18nService.phoneNumbersMatch(
+ phoneNumberQuery,
+ phoneNumber);
+ }
+ catch (IllegalArgumentException iaex)
+ {
+ /*
+ * Ignore it, phoneNumberMatches will remain equal to
+ * false.
+ */
+ }
+ }
+ }
+ }
+ return phoneNumberMatches;
+ }
+
+ /**
+ * Performs this <tt>AsyncContactQuery</tt> in a background <tt>Thread</tt>.
+ *
+ * @see AsyncContactQuery#run()
+ */
+ @Override
+ protected void run()
+ {
+ /* query we get is delimited by \Q and \E
+ * and we should not query LDAP server with a too small number of
+ * characters
+ */
+ String queryStr = query.toString();
+ if(queryStr.length() < (4))// + LDAP_MINIMUM_CHARACTERS))
+ {
+ return;
+ }
+
+ /* remove \Q and \E from the Pattern */
+ String queryString = queryStr.substring(2, queryStr.length() - 2);
+
+ LdapService ldapService = LdapActivator.getLdapService();
+ LdapFactory factory = ldapService.getFactory();
+
+
+ ldapQuery = factory.createQuery(queryString);
+ LdapSearchSettings settings = factory.createSearchSettings();
+ settings.setDelay(250);
+ settings.setMaxResults(count);
+
+ LdapListener caller = new LdapListener()
+ {
+ public void ldapEventReceived(LdapEvent evt)
+ {
+ processLdapResponse(evt);
+ }
+ };
+
+ ldapService.getServerSet().searchPerson(ldapQuery, caller, settings);
+
+ synchronized(objLock)
+ {
+ try
+ {
+ objLock.wait();
+ }
+ catch(InterruptedException e)
+ {
+ }
+ }
+ }
+
+ /**
+ * Gets the <tt>contactDetails</tt> to be set on a <tt>SourceContact</tt>.
+ *
+ * @param person LDAP person
+ * @return the <tt>contactDetails</tt> to be set on a <tt>SourceContact</tt>
+ */
+ private List<ContactDetail> getContactDetails(LdapPersonFound person)
+ {
+ List<ContactDetail> ret = new LinkedList<ContactDetail>();
+ Set<String> mailAddresses = person.getMail();
+ Set<String> mobilePhones = person.getMobilePhone();
+ Set<String> homePhones = person.getHomePhone();
+ Set<String> workPhones = person.getWorkPhone();
+ ContactDetail detail = null;
+
+ for(String mail : mailAddresses)
+ {
+ detail = new ContactDetail(mail, ContactDetail.CATEGORY_EMAIL,
+ null);
+ ret.add(detail);
+ }
+
+ for(String homePhone : homePhones)
+ {
+ List<Class<? extends OperationSet>> supportedOpSets
+ = new ArrayList<Class<? extends OperationSet>>(1);
+
+ supportedOpSets.add(OperationSetBasicTelephony.class);
+ homePhone = this.normalizePhoneNumber(homePhone);
+ detail = new ContactDetail(homePhone, ContactDetail.CATEGORY_PHONE,
+ new String[]{ContactDetail.LABEL_HOME});
+ detail.setSupportedOpSets(supportedOpSets);
+ ret.add(detail);
+ }
+
+ for(String workPhone : workPhones)
+ {
+ List<Class<? extends OperationSet>> supportedOpSets
+ = new ArrayList<Class<? extends OperationSet>>(1);
+
+ supportedOpSets.add(OperationSetBasicTelephony.class);
+ detail = new ContactDetail(workPhone, ContactDetail.CATEGORY_PHONE,
+ new String[]{ContactDetail.LABEL_WORK});
+ detail.setSupportedOpSets(supportedOpSets);
+ ret.add(detail);
+ }
+
+ for(String mobilePhone : mobilePhones)
+ {
+ List<Class<? extends OperationSet>> supportedOpSets
+ = new ArrayList<Class<? extends OperationSet>>(1);
+
+ supportedOpSets.add(OperationSetBasicTelephony.class);
+ detail = new ContactDetail(mobilePhone, ContactDetail.CATEGORY_PHONE,
+ new String[]{ContactDetail.LABEL_MOBILE});
+ detail.setSupportedOpSets(supportedOpSets);
+ ret.add(detail);
+ }
+ return ret;
+ }
+
+ /**
+ * Process LDAP event.
+ *
+ * @param evt LDAP event
+ */
+ private void processLdapResponse(LdapEvent evt)
+ {
+ if(evt.getCause() == LdapEvent.LdapEventCause.SEARCH_ACHIEVED ||
+ evt.getCause() == LdapEvent.LdapEventCause.SEARCH_CANCELLED)
+ {
+ synchronized(objLock)
+ {
+ objLock.notify();
+ }
+ }
+
+ if(evt.getCause() == LdapEvent.LdapEventCause.NEW_SEARCH_RESULT)
+ {
+ LdapPersonFound person = (LdapPersonFound) evt.getContent();
+ String displayName = null;
+
+ if(person == null)
+ {
+ return;
+ }
+
+ if(person.getDisplayName() != null)
+ {
+ displayName = person.getDisplayName();
+ }
+ else
+ {
+ displayName = person.getFirstName() + " " + person.getSurname();
+ }
+
+ List<ContactDetail> contactDetails = getContactDetails(person);
+
+ if (!contactDetails.isEmpty())
+ {
+ GenericSourceContact sourceContact
+ = new GenericSourceContact(
+ getContactSource(),
+ displayName,
+ contactDetails);
+
+ try
+ {
+ sourceContact.setImage(person.fetchPhoto());
+ }
+ catch (OutOfMemoryError oome)
+ {
+ // Ignore it, the image is not vital.
+ }
+
+ addQueryResult(sourceContact);
+ }
+ }
+ }
+
+ /**
+ * Notifies this <tt>LdapContactQuery</tt> that it has stopped performing
+ * in the associated background <tt>Thread</tt>.
+ *
+ * @param completed <tt>true</tt> if this <tt>ContactQuery</tt> has
+ * successfully completed, <tt>false</tt> if an error has been encountered
+ * during its execution
+ * @see AsyncContactQuery#stopped(boolean)
+ */
+ @Override
+ protected void stopped(boolean completed)
+ {
+ try
+ {
+ super.stopped(completed);
+ }
+ finally
+ {
+ getContactSource().stopped(this);
+ }
+ }
+
+ /**
+ * Cancels this <tt>ContactQuery</tt>.
+ *
+ * @see ContactQuery#cancel()
+ */
+ @Override
+ public void cancel()
+ {
+ ldapQuery.setState(LdapQuery.State.CANCELLED);
+ super.cancel();
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/ldap/LdapContactSourceService.java b/src/net/java/sip/communicator/plugin/ldap/LdapContactSourceService.java
new file mode 100644
index 0000000..11d452f
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/ldap/LdapContactSourceService.java
@@ -0,0 +1,172 @@
+/*
+ * 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.ldap;
+
+import java.util.*;
+import java.util.regex.*;
+
+import net.java.sip.communicator.service.contactsource.*;
+
+/**
+ * Implements <tt>ContactSourceService</tt> for LDAP.
+ *
+ * @author Sebastien Vincent
+ */
+public class LdapContactSourceService
+ implements ExtendedContactSourceService
+{
+ /**
+ * The <tt>List</tt> of <tt>LdapContactQuery</tt> instances
+ * which have been started and haven't stopped yet.
+ */
+ private final List<LdapContactQuery> queries
+ = new LinkedList<LdapContactQuery>();
+
+ /**
+ * Queries this search source for the given <tt>searchPattern</tt>.
+ *
+ * @param queryPattern the pattern to search for
+ * @return the created query
+ */
+ public ContactQuery queryContactSource(Pattern queryPattern)
+ {
+ return queryContactSource(queryPattern,
+ LdapContactQuery.LDAP_MAX_RESULTS);
+ }
+
+ /**
+ * Queries this search source for the given <tt>searchPattern</tt>.
+ *
+ * @param queryPattern the pattern to search for
+ * @param count maximum number of contact returned
+ * @return the created query
+ */
+ public ContactQuery queryContactSource(Pattern queryPattern, int count)
+ {
+ LdapContactQuery query = new LdapContactQuery(this, queryPattern,
+ count);
+
+ synchronized (queries)
+ {
+ // cancel previous queries
+ for(LdapContactQuery q : queries)
+ {
+ q.cancel();
+ }
+
+ queries.add(query);
+ }
+
+ boolean hasStarted = false;
+
+ try
+ {
+ query.start();
+ hasStarted = true;
+ }
+ finally
+ {
+ if (!hasStarted)
+ {
+ synchronized (queries)
+ {
+ if (queries.remove(query))
+ queries.notify();
+ }
+ }
+ }
+
+ return query;
+ }
+
+ /**
+ * Returns a user-friendly string that identifies this contact source.
+ * @return the display name of this contact source
+ */
+ public String getDisplayName()
+ {
+ return "LDAP directory";
+ }
+
+ /**
+ * Returns the identifier of this contact source. Some of the common
+ * identifiers are defined here (For example the CALL_HISTORY identifier
+ * should be returned by all call history implementations of this interface)
+ * @return the identifier of this contact source
+ */
+ public String getIdentifier()
+ {
+ return "LDAP";
+ }
+
+ /**
+ * Queries this search source for the given <tt>queryString</tt>.
+ * @param query the string to search for
+ * @return the created query
+ */
+ public ContactQuery queryContactSource(String query)
+ {
+ return queryContactSource(
+ Pattern.compile(query), LdapContactQuery.LDAP_MAX_RESULTS);
+ }
+
+ /**
+ * Queries this search source for the given <tt>queryString</tt>.
+ *
+ * @param query the string to search for
+ * @param contactCount the maximum count of result contacts
+ * @return the created query
+ */
+ public ContactQuery queryContactSource(String query, int contactCount)
+ {
+ return queryContactSource(Pattern.compile(query), contactCount);
+ }
+
+ /**
+ * Stops this <tt>ContactSourceService</tt> implementation and prepares it
+ * for garbage collection.
+ *
+ * @see AsyncContactSourceService#stop()
+ */
+ public void stop()
+ {
+ boolean interrupted = false;
+
+ synchronized (queries)
+ {
+ while (!queries.isEmpty())
+ {
+ queries.get(0).cancel();
+ try
+ {
+ queries.wait();
+ }
+ catch (InterruptedException iex)
+ {
+ interrupted = true;
+ }
+ }
+ }
+ if (interrupted)
+ Thread.currentThread().interrupt();
+ }
+
+ /**
+ * Notifies this <tt>LdapContactSourceService</tt> that a specific
+ * <tt>LdapContactQuery</tt> has stopped.
+ *
+ * @param query the <tt>LdapContactQuery</tt> which has stopped
+ */
+ void stopped(LdapContactQuery query)
+ {
+ synchronized (queries)
+ {
+ if (queries.remove(query))
+ queries.notify();
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/ldap/ldap.manifest.mf b/src/net/java/sip/communicator/plugin/ldap/ldap.manifest.mf
new file mode 100644
index 0000000..d9dc72d
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/ldap/ldap.manifest.mf
@@ -0,0 +1,12 @@
+Bundle-Activator: net.java.sip.communicator.plugin.ldap.LdapActivator
+Bundle-Description: LDAP support
+Bundle-Name: LDAP support
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: net.java.sip.communicator.service.contactsource,
+ net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.service.ldap,
+ net.java.sip.communicator.service.ldap.event,
+ net.java.sip.communicator.util,
+ org.osgi.framework
+System-Bundle: yes \ No newline at end of file