Initial support for Google Contacts as contact source.

cusax-fix
Sebastien Vincent 16 years ago
parent 260fd209ae
commit 76767db08a

@ -890,7 +890,7 @@
bundle-callhistory, bundle-callhistory-slick, bundle-popupmessagehandler-slick,
bundle-netaddr,bundle-netaddr-slick,bundle-slickless,
bundle-slick-runner,bundle-sip,bundle-sip-slick,bundle-fileaccess,
bundle-fileaccess-slick,bundle-neomedia,bundle-hid,bundle-ldap,
bundle-fileaccess-slick,bundle-neomedia,bundle-hid,bundle-ldap,bundle-googlecontacts,
bundle-resource-manager,bundle-resources-defaultpack,
bundle-protocol,bundle-protocol-media,bundle-icq,
bundle-icq-slick,bundle-mock,bundle-smacklib,bundle-jmdnslib,
@ -1201,6 +1201,23 @@
</jar>
</target>
<!--BUNDLE-GOOGLECONTACTS-->
<target name="bundle-googlecontacts">
<jar compress="false" destfile="${bundles.dest}/googlecontacts.jar"
manifest="${src}/net/java/sip/communicator/impl/googlecontacts/googlecontacts.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/service/googlecontacts"
prefix="net/java/sip/communicator/service/googlecontacts"/>
<zipfileset dir="${dest}/net/java/sip/communicator/impl/googlecontacts"
prefix="net/java/sip/communicator/impl/googlecontacts" />
<zipfileset src="${lib.noinst}/google-collect-1.0-rc1.jar" prefix=""/>
<zipfileset src="${lib.noinst}/gdata-core-1.0.jar" prefix=""/>
<zipfileset src="${lib.noinst}/gdata-contacts-3.0.jar" prefix=""/>
<zipfileset src="${lib.noinst}/gdata-contacts-meta-3.0.jar" prefix=""/>
<zipfileset src="${lib.noinst}/gdata-client-1.0.jar" prefix=""/>
<zipfileset src="${lib.noinst}/gdata-client-meta-1.0.jar" prefix=""/>
</jar>
</target>
<!--BUNDLE-SERVICEBINDER -->
<target name="bundle-servicebinder">
<jar compress="true" destfile="lib/bundle/servicebinder.jar"

@ -68,5 +68,11 @@
<classpathentry kind="lib" path="lib/installer-exclude/mac_widgets-0.9.5.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/forms-1.2.1.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/weupnp-0.1.2-SNAPSHOT.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/google-collect-1.0-rc1.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/gdata-client-1.0.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/gdata-client-meta-1.0.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/gdata-contacts-3.0.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/gdata-contacts-meta-3.0.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/gdata-core-1.0.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

@ -64,6 +64,7 @@ felix.auto.start.45= \
felix.auto.start.49= \
reference:file:sc-bundles/provisioning.jar \
reference:file:sc-bundles/googlecontacts.jar \
reference:file:sc-bundles/bouncycastle.jar \
reference:file:sc-bundles/zrtp4j.jar \
reference:file:sc-bundles/protocol.jar \

@ -578,6 +578,7 @@ impl.gui.main.account.DEFAULT_PAGE_BODY=You can use the list above to select the
impl.gui.main.account.DUMMY_PROTOCOL_NAME=select network
impl.gui.main.account.DUMMY_PROTOCOL_DESCRIPTION=select network
# LDAP
impl.ldap.CONFIG_FORM_TITLE=LDAP configuration
impl.ldap.NEW=New
impl.ldap.EDIT=edit
@ -601,6 +602,19 @@ impl.ldap.SEARCH_BASE=Search base
impl.ldap.SCOPE=Scope
impl.ldap.WRONG_CREDENTIALS=Wrong credentials for LDAP directory {0}
# Google Contacts
impl.googlecontacts.CONFIG_FORM_TITLE=Google Contacts
impl.googlecontacts.NEW=New
impl.googlecontacts.EDIT=edit
impl.googlecontacts.REMOVE=Remove
impl.googlecontacts.ENABLED=Enabled
impl.googlecontacts.ACCOUNT_NAME=Account name
impl.googlecontacts.SAVE=Save
impl.googlecontacts.CANCEL=Cancel
impl.googlecontacts.USERNAME=Account name
impl.googlecontacts.PASSWORD=Password
impl.googlecontacts.WRONG_CREDENTIALS=Wrong credentials for Google account {0}
# account info
plugin.accountinfo.TITLE=Account Info
plugin.accountinfo.EXTENDED=Extended
@ -738,6 +752,7 @@ plugin.jabberaccregwizz.CSERVER=Server
plugin.jabberaccregwizz.SERVER=Connect Server
plugin.jabberaccregwizz.ENABLE_KEEP_ALIVE=Enable keep alive
plugin.jabberaccregwizz.ENABLE_GMAIL_NOTIFICATIONS=Enable Gmail notifications for new messages
plugin.jabberaccregwizz.ENABLE_GOOGLE_CONTACTS_SOURCE=Enable Google Contacts search
plugin.jabberaccregwizz.NEW_ACCOUNT_TITLE=Jabber new account registration
plugin.jabberaccregwizz.REGISTER_NEW_ACCOUNT_TEXT=In case you don't have a Jabber account, click on this button to create a new one.
plugin.jabberaccregwizz.CHOOSE_SERVER_TITLE=Jabber new account server chooser

@ -0,0 +1,393 @@
/*
* 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.impl.googlecontacts;
import java.util.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.contactsource.*;
import net.java.sip.communicator.service.credentialsstorage.*;
import net.java.sip.communicator.service.googlecontacts.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
import org.osgi.framework.*;
/**
* Activates the Google Contacts Service
*
* @author Sebastien Vincent
*/
public class GoogleContactsActivator implements BundleActivator
{
/**
* The <tt>Logger</tt> used by the <tt>GoogleContactsActivator</tt> class
* and its instances for logging output.
*/
private final Logger logger = Logger.getLogger(
GoogleContactsActivator.class);
/**
* The OSGi <tt>ServiceRegistration</tt> of
* <tt>GoogleContactsServiceImpl</tt>.
*/
private ServiceRegistration serviceRegistration = null;
/**
* BundleContext from the OSGI bus.
*/
private static BundleContext bundleContext;
/**
* Reference to the configuration service
*/
private static ConfigurationService configService;
/**
* Reference to the credentials service
*/
private static CredentialsStorageService credentialsService;
/**
* Reference to the resource management service
*/
private static ResourceManagementService resourceService;
/**
* The cached reference to the <tt>PhoneNumberI18nService</tt> instance used
* by the functionality of the Google Contacts plug-in and fetched from its
* <tt>BundleContext</tt>.
*/
private static PhoneNumberI18nService phoneNumberI18nService;
/**
* Google contacts service.
*/
private static GoogleContactsServiceImpl googleContactsService;
/**
* List of contact source service registrations.
*/
private static Map<GoogleContactsSourceService, ServiceRegistration> cssList
= new HashMap<GoogleContactsSourceService, ServiceRegistration>();
/**
* 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;
}
/**
* Returns a reference to a ConfigurationService implementation currently
* registered in the bundle context or null if no such implementation was
* found.
*
* @return a currently valid implementation of the ConfigurationService.
*/
public static ConfigurationService getConfigService()
{
if(configService == null)
{
ServiceReference confReference
= bundleContext.getServiceReference(
ConfigurationService.class.getName());
configService
= (ConfigurationService) bundleContext.getService(
confReference);
}
return configService;
}
/**
* Returns a reference to a GoogleContactsService implementation currently
* registered in the bundle context or null if no such implementation was
* found.
*
* @return a currently valid implementation of the GoogleContactsService
*/
public static GoogleContactsServiceImpl getGoogleContactsService()
{
return googleContactsService;
}
/**
* Returns a reference to a CredentialsStorageConfigurationService
* implementation currently registered in the bundle context or null if no
* such implementation was found.
*
* @return a currently valid implementation of the
* CredentialsStorageService.
*/
public static CredentialsStorageService getCredentialsService()
{
if(credentialsService == null)
{
ServiceReference confReference
= bundleContext.getServiceReference(
CredentialsStorageService.class.getName());
credentialsService
= (CredentialsStorageService) bundleContext.getService(
confReference);
}
return credentialsService;
}
/**
* Returns a reference to a ResourceManagementService implementation
* currently registered in the bundle context or null if no such
* implementation was found.
*
* @return a currently valid implementation of the
* ResourceManagementService.
*/
public static ResourceManagementService getResourceManagementService()
{
if(resourceService == null)
{
ServiceReference confReference
= bundleContext.getServiceReference(
ResourceManagementService.class.getName());
resourceService
= (ResourceManagementService) bundleContext.getService(
confReference);
}
return resourceService;
}
/**
* Starts the Google Contacts service
*
* @param bundleContext BundleContext
* @throws Exception if something goes wrong when starting service
*/
public void start(BundleContext bundleContext)
throws Exception
{
if (logger.isDebugEnabled())
logger.debug("Started.");
GoogleContactsActivator.bundleContext = bundleContext;
googleContactsService =
new GoogleContactsServiceImpl();
serviceRegistration =
bundleContext.registerService(GoogleContactsService.class.getName(),
googleContactsService, null);
/* registers the configuration form */
Dictionary<String, String> properties =
new Hashtable<String, String>();
properties.put( ConfigurationForm.FORM_TYPE,
ConfigurationForm.ADVANCED_TYPE);
bundleContext.registerService(
ConfigurationForm.class.getName(),
new LazyConfigurationForm(
"net.java.sip.communicator.impl.googlecontacts.configform.GoogleContactsConfigForm",
getClass().getClassLoader(),
"impl.googlecontacts.PLUGIN_ICON",
"impl.googlecontacts.CONFIG_FORM_TITLE",
2000, true),
properties);
if (logger.isDebugEnabled())
logger.debug("Google Contacts Service ... [REGISTERED]");
}
/**
* Stops the Google Contacts service.
*
* @param bundleContext BundleContext
* @throws Exception if something goes wrong when stopping service
*/
public void stop(BundleContext bundleContext)
throws Exception
{
if (serviceRegistration != null)
{
serviceRegistration.unregister();
serviceRegistration = null;
}
/* remove contact source services */
for(Map.Entry<GoogleContactsSourceService, ServiceRegistration> entry :
cssList.entrySet())
{
if (entry.getValue() != null)
{
try
{
entry.getValue().unregister();
}
finally
{
entry.getKey().stop();
}
}
}
cssList.clear();
GoogleContactsActivator.bundleContext = null;
}
/**
* Enable contact source service with specified
* <tt>GoogleContactsConnection</tt>.
*
* @param login login
* @param password password
*/
public static void enableContactSource(String login, String password)
{
GoogleContactsSourceService css = new GoogleContactsSourceService(
login, password);
ServiceRegistration cssServiceRegistration = null;
try
{
cssServiceRegistration
= bundleContext.registerService(
ContactSourceService.class.getName(),
css,
null);
}
finally
{
if (cssServiceRegistration == null)
{
css.stop();
css = null;
}
else
{
cssList.put(css, cssServiceRegistration);
}
}
}
/**
* Enable contact source service with specified
* <tt>GoogleContactsConnection</tt>.
*
* @param cnx <tt>GoogleContactsConnection</tt>
*/
public static void enableContactSource(GoogleContactsConnection cnx)
{
GoogleContactsSourceService css = new GoogleContactsSourceService(
cnx);
ServiceRegistration cssServiceRegistration = null;
try
{
cssServiceRegistration
= bundleContext.registerService(
ContactSourceService.class.getName(),
css,
null);
}
finally
{
if (cssServiceRegistration == null)
{
css.stop();
css = null;
}
else
{
cssList.put(css, cssServiceRegistration);
}
}
}
/**
* Disable contact source service with specified
* <tt>GoogleContactsConnection</tt>.
*
* @param login login
*/
public static void disableContactSource(String login)
{
GoogleContactsSourceService found = null;
for(Map.Entry<GoogleContactsSourceService, ServiceRegistration> entry :
cssList.entrySet())
{
String cssName =
entry.getKey().getConnection().getLogin();
if(cssName.equals(login))
{
try
{
entry.getValue().unregister();
}
finally
{
entry.getKey().stop();
}
found = entry.getKey();
break;
}
}
if(found != null)
{
cssList.remove(found);
}
}
/**
* Disable contact source service with specified
* <tt>GoogleContactsConnection</tt>.
*
* @param cnx <tt>GoogleContactsConnection</tt>.
*/
public static void disableContactSource(GoogleContactsConnection cnx)
{
GoogleContactsSourceService found = null;
for(Map.Entry<GoogleContactsSourceService, ServiceRegistration> entry :
cssList.entrySet())
{
String cssName =
entry.getKey().getConnection().getLogin();
String name = cnx.getLogin();
if(cssName.equals(name))
{
try
{
entry.getValue().unregister();
}
finally
{
entry.getKey().stop();
}
found = entry.getKey();
break;
}
}
if(found != null)
{
cssList.remove(found);
}
}
}

@ -0,0 +1,108 @@
/*
* 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.impl.googlecontacts;
import com.google.gdata.client.contacts.*;
import net.java.sip.communicator.service.googlecontacts.*;
/**
* Google Contacts credentials to connect to the service.
*
* @author Sebastien Vincent
*/
public class GoogleContactsConnectionImpl
implements GoogleContactsConnection
{
/**
* Login.
*/
private final String login;
/**
* Password.
*/
private final String password;
/**
* If the connection is enabled.
*/
private boolean enabled = false;
/**
* Google Contacts service.
*/
private final ContactsService googleService =
new ContactsService("GoogleContacts service for Jitsi");
/**
* Constructor.
*
* @param login the login to connect to the service
* @param password the password to connect to the service
* @throws Exception if something goes wrong during connection
*/
public GoogleContactsConnectionImpl(String login, String password)
throws Exception
{
this.login = login;
this.password = password;
googleService.setUserCredentials(login, password);
googleService.useSsl();
}
/**
* Returns the Google service.
*
* @return the Google service
*/
public ContactsService getGoogleService()
{
return googleService;
}
/**
* Get login.
*
* @return login to connect to the service
*/
public String getLogin()
{
return login;
}
/**
* get password.
*
* @return password to connect to the service
*/
public String getPassword()
{
return password;
}
/**
* Returns if the connection is enabled.
*
* @return true if connection is enabled, false otherwise
*/
public boolean isEnabled()
{
return enabled;
}
/**
* Set the connection to be enabled or not.
*
* @param enabled value to set
*/
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
}

@ -0,0 +1,527 @@
/*
* 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.impl.googlecontacts;
import java.util.*;
import net.java.sip.communicator.service.googlecontacts.*;
import com.google.gdata.data.*;
import com.google.gdata.data.extensions.*;
import com.google.gdata.data.contacts.ContactEntry; //disambiguation
/**
* Google Contacts entry implementation.
*
* @author Sebastien Vincent
*/
public class GoogleContactsEntryImpl
implements GoogleContactsEntry
{
/**
* Google Talk protocol type.
*/
private static final String GOOGLETALK_PROTOCOL =
"http://schemas.google.com/g/2005#GOOGLE_TALK";
/**
* Google Talk protocol type.
*/
private static final String YAHOO_PROTOCOL =
"http://schemas.google.com/g/2005#YAHOO";
/**
* Google Talk protocol type.
*/
private static final String AIM_PROTOCOL =
"http://schemas.google.com/g/2005#AIM";
/**
* Google Talk protocol type.
*/
private static final String MSN_PROTOCOL =
"http://schemas.google.com/g/2005#MSN";
/**
* Google Talk protocol type.
*/
private static final String ICQ_PROTOCOL =
"http://schemas.google.com/g/2005#ICQ";
/**
* Google Talk protocol type.
*/
private static final String JABBER_PROTOCOL =
"http://schemas.google.com/g/2005#JABBER";
/**
* Full name.
*/
private String fullName = null;
/**
* Family name.
*/
private String familyName = null;
/**
* Given name.
*/
private String givenName = null;
/**
* Home mails list.
*/
private final List<String> homeMails = new ArrayList<String>();
/**
* Work mails list.
*/
private final List<String> workMails = new ArrayList<String>();
/**
* Home phones list.
*/
private final List<String> homePhones = new ArrayList<String>();
/**
* Work phones list.
*/
private final List<String> workPhones = new ArrayList<String>();
/**
* Mobile phones list.
*/
private final List<String> mobilePhones = new ArrayList<String>();
/**
* IM addresses map.
*/
private final Map<String, IMProtocol> imAddresses =
new HashMap<String, IMProtocol>();
/**
* Photo link.
*/
private String photoLink = null;
/**
* Google photo link.
*/
private Link googlePhotoLink = null;
/**
* Get the full name.
*
* @return full name
*/
public String getFullName()
{
return fullName;
}
/**
* Get the family name.
*
* @return family name
*/
public String getFamilyName()
{
return familyName;
}
/**
* Get the given name.
*
* @return given name
*/
public String getGivenName()
{
return givenName;
}
/**
* Returns mails.
*
* @return mails
*/
public List<String> getAllMails()
{
List<String> mails = new ArrayList<String>();
for(String mail : homeMails)
{
mails.add(mail);
}
for(String mail : workMails)
{
mails.add(mail);
}
return mails;
}
/**
* Adds a home mail address.
*
* @param mail the mail address
*/
public void addHomeMail(String mail)
{
homeMails.add(mail);
}
/**
* Returns home mail addresses.
*
* @return home mail addresses
*/
public List<String> getHomeMails()
{
return homeMails;
}
/**
* Adds a work mail address.
*
* @param mail the mail address
*/
public void addWorkMails(String mail)
{
workMails.add(mail);
}
/**
* Returns work mail addresses.
*
* @return work mail addresses
*/
public List<String> getWorkMails()
{
return workMails;
}
/**
* Returns telephone numbers.
*
* @return telephone numbers
*/
public List<String> getAllPhones()
{
List<String> phones = new ArrayList<String>();
for(String phone : mobilePhones)
{
phones.add(phone);
}
for(String phone : homePhones)
{
phones.add(phone);
}
for(String phone : workPhones)
{
phones.add(phone);
}
return phones;
}
/**
* Adds a work telephone number.
*
* @param telephoneNumber the work telephone number
*/
public void addWorkPhone(String telephoneNumber)
{
workPhones.add(telephoneNumber);
}
/**
* Returns work telephone numbers.
*
* @return work telephone numbers
*/
public List<String> getWorkPhones()
{
return workPhones;
}
/**
* Adds a mobile telephone numbers.
*
* @param telephoneNumber the mobile telephone number
*/
public void addMobilePhone(String telephoneNumber)
{
mobilePhones.add(telephoneNumber);
}
/**
* Returns mobile telephone numbers.
*
* @return mobile telephone numbers
*/
public List<String> getMobilePhones()
{
return mobilePhones;
}
/**
* Adds a home telephone numbers.
*
* @param telephoneNumber the home telephone number
*/
public void addHomePhone(String telephoneNumber)
{
homePhones.add(telephoneNumber);
}
/**
* Returns home telephone numbers.
*
* @return home telephone numbers
*/
public List<String> getHomePhones()
{
return homePhones;
}
/**
* Get the photo full URI.
*
* @return the photo URI or null if there isn't
*/
public String getPhoto()
{
return photoLink;
}
/**
* Get the Google photo full URI.
*
* @return the Google photo URI or null if there isn't
*/
public Link getPhotoLink()
{
return googlePhotoLink;
}
/**
* Returns IM addresses.
*
* @return IM addresses
*/
public Map<String, IMProtocol> getIMAddresses()
{
return imAddresses;
}
/**
* Adds an IM address.
*
* @param imAddress IM address
*/
public void addIMAddress(String imAddress, IMProtocol protocol)
{
imAddresses.put(imAddress, protocol);
}
/**
* Set information.
*
* @param contact Google Contacts's <tt>ContactEntry</tt>
*/
public void setField(ContactEntry contact)
{
Name name = contact.getName();
if(name != null)
{
if(name.hasFullName())
{
fullName = name.getFullName().getValue();
}
if(name.hasFamilyName())
{
familyName = name.getFamilyName().getValue();
}
if(name.hasGivenName())
{
givenName = name.getGivenName().getValue();
}
}
photoLink = contact.getContactPhotoLink().getHref();
googlePhotoLink = contact.getContactPhotoLink();
for(Email mail : contact.getEmailAddresses())
{
if(mail.getRel().contains("#home"))
{
homeMails.add(mail.getAddress());
}
else if(mail.getRel().contains("#work"))
{
workMails.add(mail.getAddress());
}
else
{
homeMails.add(mail.getAddress());
}
}
for(PhoneNumber phone : contact.getPhoneNumbers())
{
if(phone.getRel().contains("#work"))
{
workPhones.add(phone.getPhoneNumber());
}
else if(phone.getRel().contains("#mobile"))
{
mobilePhones.add(phone.getPhoneNumber());
}
else if(phone.getRel().contains("#home"))
{
homePhones.add(phone.getPhoneNumber());
}
else
{
homePhones.add(phone.getPhoneNumber());
}
}
for(Im imAddress : contact.getImAddresses())
{
String protocol = imAddress.getProtocol();
IMProtocol proto;
if(protocol.equals(GOOGLETALK_PROTOCOL))
{
proto = GoogleContactsEntry.IMProtocol.GOOGLETALK;
}
else if(protocol.equals(YAHOO_PROTOCOL))
{
proto = GoogleContactsEntry.IMProtocol.YAHOO;
}
else if(protocol.equals(AIM_PROTOCOL))
{
proto = GoogleContactsEntry.IMProtocol.AIM;
}
else if(protocol.equals(MSN_PROTOCOL))
{
proto = GoogleContactsEntry.IMProtocol.MSN;
}
else if(protocol.equals(ICQ_PROTOCOL))
{
proto = GoogleContactsEntry.IMProtocol.ICQ;
}
else if(protocol.equals(JABBER_PROTOCOL))
{
proto = GoogleContactsEntry.IMProtocol.JABBER;
}
else
{
proto = GoogleContactsEntry.IMProtocol.OTHER;
}
imAddresses.put(imAddress.getAddress(), proto);
}
}
/**
* String representation of the <tt>GoogleContactsEntry</tt>.
*/
@Override
public String toString()
{
StringBuffer buffer = new StringBuffer();
if(fullName != null)
{
buffer.append("Full name: ");
buffer.append(fullName);
buffer.append("\n");
}
if(givenName != null || familyName != null)
{
buffer.append("Display name: ");
buffer.append(givenName != null ? givenName : "");
buffer.append(" ");
buffer.append(familyName != null ? familyName : "");
buffer.append("\n");
}
if(getAllMails().size() > 0)
{
buffer.append("Mail:\n");
for(String mail : getAllMails())
{
buffer.append("\t");
buffer.append(mail);
buffer.append("\n");
}
}
if(workPhones.size() > 0)
{
buffer.append("Work phones:\n");
for(String phone : workPhones)
{
buffer.append("\t");
buffer.append(phone);
buffer.append("\n");
}
}
if(homePhones.size() > 0)
{
buffer.append("Home phones:\n");
for(String phone : homePhones)
{
buffer.append("\t");
buffer.append(phone);
buffer.append("\n");
}
}
if(mobilePhones.size() > 0)
{
buffer.append("Mobile phones:\n");
for(String phone : mobilePhones)
{
buffer.append("\t");
buffer.append(phone);
buffer.append("\n");
}
}
if(imAddresses.size() > 0)
{
buffer.append("IM addresses:\n");
for(Map.Entry<String, IMProtocol> entry : imAddresses.entrySet())
{
buffer.append("\t");
buffer.append(entry.getKey());
buffer.append(" (");
buffer.append(entry.getValue());
buffer.append(")\n");
}
}
buffer.append("\n");
return buffer.toString();
}
}

@ -0,0 +1,421 @@
/*
* 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.impl.googlecontacts;
import java.util.*;
import java.util.regex.*;
import net.java.sip.communicator.service.contactsource.*;
import net.java.sip.communicator.service.googlecontacts.*;
import net.java.sip.communicator.service.protocol.*;
/**
* Implements <tt>ContactQuery</tt> for Google Contacts.
*
* @author Sebastien Vincent
*/
public class GoogleContactsQuery
extends AsyncContactQuery<GoogleContactsSourceService>
{
/**
* Maximum results for Google Contacts query.
*/
public static final int GOOGLECONTACTS_MAX_RESULTS = 20;
/**
* Maximum number of results for this instance.
*/
private final int count;
/**
* The Google query.
*/
private GoogleQuery gQuery = null;
/**
* Initializes a new <tt>GoogleContactsQuery</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 GoogleContactsQuery(GoogleContactsSourceService
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
= GoogleContactsActivator.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
= GoogleContactsActivator.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;
}
/**
* Create a <tt>SourceContact</tt> from a <tt>GoogleContactsEntry</tt>.
*
* @param entry <tt>GoogleContactsEntry</tt>
*/
private void onGoogleContactsEntry(GoogleContactsEntry entry)
{
String displayName = entry.getFullName();
if(displayName == null || displayName.length() == 0)
{
if((entry.getGivenName() == null ||
entry.getGivenName().length() == 0) &&
(entry.getFamilyName() == null ||
entry.getFamilyName().length() == 0))
{
return;
}
displayName = entry.getGivenName() + " " +
entry.getFamilyName();
}
List<ContactDetail> contactDetails = getContactDetails(entry);
if (!contactDetails.isEmpty())
{
GenericSourceContact sourceContact
= new GenericSourceContact(
getContactSource(),
displayName,
contactDetails);
try
{
byte img[] = GoogleContactsServiceImpl.downloadPhoto(
((GoogleContactsEntryImpl)entry).getPhotoLink(),
getContactSource().getConnection().
getGoogleService());
sourceContact.setImage(img);
}
catch (OutOfMemoryError oome)
{
// Ignore it, the image is not vital.
}
addQueryResult(sourceContact);
}
}
/**
* Performs this <tt>AsyncContactQuery</tt> in a background <tt>Thread</tt>.
*
* @see AsyncContactQuery#run()
*/
@Override
protected void run()
{
GoogleContactsServiceImpl service = (GoogleContactsServiceImpl)
GoogleContactsActivator.getGoogleContactsService();
gQuery = new GoogleQuery(query);
GoogleContactsConnection cnx = getContactSource().getConnection();
if(cnx == null)
{
return;
}
service.searchContact(
cnx,
gQuery,
count,
new GoogleEntryCallback()
{
public void callback(GoogleContactsEntry entry)
{
onGoogleContactsEntry(entry);
}
});
}
/**
* Gets the <tt>contactDetails</tt> to be set on a <tt>SourceContact</tt>.
*
* @param entry <tt>GoogleContactsEntry</tt>
* @return the <tt>contactDetails</tt> to be set on a <tt>SourceContact</tt>
*/
private List<ContactDetail> getContactDetails(GoogleContactsEntry entry)
{
List<ContactDetail> ret = new LinkedList<ContactDetail>();
List<String> homeMails = entry.getHomeMails();
List<String> workMails = entry.getWorkMails();
List<String> mobilePhones = entry.getMobilePhones();
List<String> homePhones = entry.getHomePhones();
List<String> workPhones = entry.getWorkPhones();
Map<String, GoogleContactsEntry.IMProtocol> ims =
entry.getIMAddresses();
ContactDetail detail = null;
for(String mail : homeMails)
{
detail = new ContactDetail(mail, ContactDetail.CATEGORY_EMAIL,
new String[]{ContactDetail.LABEL_HOME});
ret.add(detail);
}
for(String mail : workMails)
{
detail = new ContactDetail(mail, ContactDetail.CATEGORY_EMAIL,
new String[]{ContactDetail.LABEL_WORK});
ret.add(detail);
}
for(String homePhone : homePhones)
{
List<Class<? extends OperationSet>> supportedOpSets
= new ArrayList<Class<? extends OperationSet>>(1);
supportedOpSets.add(OperationSetBasicTelephony.class);
homePhone = 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);
workPhone = normalizePhoneNumber(workPhone);
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);
mobilePhone = normalizePhoneNumber(mobilePhone);
detail = new ContactDetail(mobilePhone,
ContactDetail.CATEGORY_PHONE,
new String[]{ContactDetail.LABEL_MOBILE});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
for(Map.Entry<String, GoogleContactsEntry.IMProtocol> im :
ims.entrySet())
{
if(im.getValue() != GoogleContactsEntry.IMProtocol.OTHER)
{
detail = new ContactDetail(im.getKey(),
ContactDetail.CATEGORY_INSTANT_MESSAGING,
new String[]{im.getValue().toString()});
setIMCapabilities(detail, im.getValue());
ret.add(detail);
}
}
return ret;
}
/**
* Sets the IM capabilities of a specific <tt>ContactDetail</tt> (e.g.
* <tt>supportedOpSets</tt>).
*
* @param contactDetail the <tt>ContactDetail</tt> to set the capabilities
* of
* @param protocol protocol
* @return <tt>contactDetail</tt>
*/
private ContactDetail setIMCapabilities(
ContactDetail contactDetail,
GoogleContactsEntry.IMProtocol protocol)
{
List<Class<? extends OperationSet>> supportedOpSets
= new LinkedList<Class<? extends OperationSet>>();
Map<Class<? extends OperationSet>, String> preferredProtocols
= new HashMap<Class<? extends OperationSet>, String>();
switch (protocol)
{
case GOOGLETALK:
supportedOpSets.add(OperationSetBasicInstantMessaging.class);
preferredProtocols.put(
OperationSetBasicInstantMessaging.class,
ProtocolNames.AIM);
break;
case ICQ:
supportedOpSets.add(OperationSetBasicInstantMessaging.class);
preferredProtocols.put(
OperationSetBasicInstantMessaging.class,
ProtocolNames.ICQ);
break;
case JABBER:
supportedOpSets.add(OperationSetBasicInstantMessaging.class);
preferredProtocols.put(
OperationSetBasicInstantMessaging.class,
ProtocolNames.JABBER);
supportedOpSets.add(OperationSetBasicTelephony.class);
preferredProtocols.put(
OperationSetBasicTelephony.class,
ProtocolNames.JABBER);
break;
case MSN:
supportedOpSets.add(OperationSetBasicInstantMessaging.class);
preferredProtocols.put(
OperationSetBasicInstantMessaging.class,
ProtocolNames.MSN);
break;
case YAHOO:
supportedOpSets.add(OperationSetBasicInstantMessaging.class);
preferredProtocols.put(
OperationSetBasicInstantMessaging.class,
ProtocolNames.YAHOO);
break;
default:
break;
}
contactDetail.setSupportedOpSets(supportedOpSets);
if (!preferredProtocols.isEmpty())
contactDetail.setPreferredProtocols(preferredProtocols);
return contactDetail;
}
/**
* Notifies this <tt>GoogleContactsQuery</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()
{
if(gQuery != null)
{
gQuery.cancel();
}
super.cancel();
}
}

@ -0,0 +1,427 @@
/*
* 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.impl.googlecontacts;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.regex.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.credentialsstorage.*;
import net.java.sip.communicator.service.googlecontacts.*;
import net.java.sip.communicator.util.*;
import com.google.gdata.client.Service.*;
import com.google.gdata.client.contacts.*;
import com.google.gdata.data.*;
import com.google.gdata.data.contacts.ContactFeed;
import com.google.gdata.data.contacts.ContactEntry;
import com.google.gdata.data.extensions.*;
/**
* Implementation of Google Contacts service.
* We first get {@link #MAX_RESULT} contacts from Google Contacts then
* we filter it to get {@link #MAX_RESULT} that matched our query.
* If {@link #MAX_RESULT} is not reach, we try with additional
* contacts (if there are more than {@link #MAX_RESULT} contacts).
*
* @author Sebastien Vincent
*/
public class GoogleContactsServiceImpl
implements GoogleContactsService
{
/**
* Logger.
*/
private static final Logger logger =
Logger.getLogger(GoogleContactsServiceImpl.class);
/**
* Google Contacts feed URL string.
*/
private static final String feedURL =
"https://www.google.com/m8/feeds/contacts/default/full";
/**
* Maximum number of results for a query.
*/
public static final int MAX_RESULT = 20;
/**
* Maximum number of contacts retrieved for a query.
*/
public static final int MAX_NUMBER = 1000;
/**
* List of Google Contacts account.
*/
private final List<GoogleContactsConnectionImpl> accounts =
new ArrayList<GoogleContactsConnectionImpl>();
/**
* Path where to store the account settings
*/
private final static String CONFIGURATION_PATH =
"net.java.sip.communicator.impl.googlecontacts";
/**
* Constructor.
*/
public GoogleContactsServiceImpl()
{
loadConfig();
}
/**
* Get list of stored connections.
*
* @return list of connections
*/
public List<GoogleContactsConnectionImpl> getAccounts()
{
return accounts;
}
/**
* Loads configuration.
*/
private void loadConfig()
{
ConfigurationService configService =
GoogleContactsActivator.getConfigService();
CredentialsStorageService credentialsService =
GoogleContactsActivator.getCredentialsService();
List<String> list = configService.getPropertyNamesByPrefix(
CONFIGURATION_PATH, true);
for(Object configEntry : list)
{
String path = configEntry.toString();
Object oen = configService.getProperty(path + ".enabled");
boolean enabled = Boolean.parseBoolean((String)oen);
String login =
(String)configService.getProperty(path + ".account");
String password = credentialsService.loadPassword(path);
GoogleContactsConnectionImpl cnx = (GoogleContactsConnectionImpl)
getConnection(login, password);
cnx.setEnabled(enabled);
if(cnx != null)
{
accounts.add(cnx);
/* register contact source */
if(cnx.isEnabled())
{
addContactSource(cnx);
}
}
}
}
/**
* Perform a search for a contact using regular expression.
*
* @param cnx <tt>GoogleContactsConnection</tt> to perform the query
* @param gQuery Google query
* @param count maximum number of matched contacts
* @param callback object that will be notified for each new
* <tt>GoogleContactsEntry</tt> found
* @return list of <tt>GoogleContactsEntry</tt>
*/
public List<GoogleContactsEntry> searchContact(
GoogleContactsConnection cnx, GoogleQuery gQuery, int count,
GoogleEntryCallback callback)
{
URL url = null;
ContactFeed contactFeed = null;
ContactQuery query = null;
List<GoogleContactsEntry> ret = new ArrayList<GoogleContactsEntry>();
boolean endOfContacts = false;
int matchedContacts = 0;
int index = 1;
GoogleContactsConnectionImpl cnxImpl =
(GoogleContactsConnectionImpl)cnx;
if(count <= 0)
{
count = MAX_RESULT;
}
try
{
url = new URL(feedURL);
}
catch(MalformedURLException e)
{
logger.info("Malformed URL", e);
return ret;
}
if(gQuery.isCancelled())
{
return ret;
}
while(matchedContacts < count || endOfContacts)
{
query = new ContactQuery(url);
query.setStartIndex(index);
query.setMaxResults(MAX_NUMBER);
query.setSortOrder(ContactQuery.SortOrder.DESCENDING);
if(gQuery.isCancelled())
{
return ret;
}
try
{
contactFeed = cnxImpl.getGoogleService().query(
query, ContactFeed.class);
}
catch(Exception e)
{
logger.info(
"Problem occurred during Google Contacts retrievment",
e);
return ret;
}
if(contactFeed.getEntries().size() == 0)
{
endOfContacts = true;
break;
}
for (int i = 0; i < contactFeed.getEntries().size(); i++)
{
if(gQuery.isCancelled())
{
return ret;
}
ContactEntry entry = contactFeed.getEntries().get(i);
if(filter(entry, gQuery.getQueryPattern()))
{
GoogleContactsEntry gcEntry = null;
gcEntry = getGoogleContactsEntry(entry);
matchedContacts++;
ret.add(gcEntry);
if(callback != null)
{
callback.callback(gcEntry);
}
if(matchedContacts >= count)
{
break;
}
}
}
index += contactFeed.getEntries().size();
}
return ret;
}
/**
* Filter according to <tt>filter</tt>.
*
* @param entry <tt>ContactEntry</tt>
* @param filter regular expression
* @return true if entry match the filter, false otherwise
*/
private boolean filter(ContactEntry entry, Pattern filter)
{
Name name = entry.getName();
/* try to see if name, mail or phone match */
if(name != null)
{
if(name.hasFamilyName())
{
Matcher m = filter.matcher(name.getFamilyName().getValue());
if(m.matches())
{
return true;
}
}
if(name.hasGivenName())
{
Matcher m = filter.matcher(name.getGivenName().getValue());
if(m.find())
{
return true;
}
}
if(name.hasFullName())
{
Matcher m = filter.matcher(name.getFullName().getValue());
if(m.find())
{
return true;
}
}
}
for(Email mail : entry.getEmailAddresses())
{
Matcher m = filter.matcher(mail.getAddress());
if(m.find())
{
return true;
}
}
for(PhoneNumber phone : entry.getPhoneNumbers())
{
Matcher m = filter.matcher(phone.getPhoneNumber());
if(m.find())
{
return true;
}
}
return false;
}
/**
* Get a <tt>GoogleContactsEntry</tt> from a <tt>ContactEntry</tt>
*
* @param entry <tt>ContactEntry</tt>
* @return <tt>GoogleContactsEntry</tt>
*/
private GoogleContactsEntry getGoogleContactsEntry(ContactEntry entry)
{
GoogleContactsEntryImpl ret = new GoogleContactsEntryImpl();
ret.setField(entry);
return ret;
}
/**
* Get the full contacts list.
*
* @return list of <tt>GoogleContactsEntry</tt>
*/
public List<GoogleContactsEntry> getContacts()
{
return null;
}
/**
* Get a <tt>GoogleContactsConnection</tt>.
*
* @param login login to connect to the service
* @param password password to connect to the service
* @return <tt>GoogleContactsConnection</tt>.
*/
public GoogleContactsConnection getConnection(String login,
String password)
{
try
{
return new GoogleContactsConnectionImpl(login, password);
}
catch(Exception e)
{
logger.info("Failed to authenticate Google Contacts", e);
return null;
}
}
/**
* Add a contact source service with the specified.
*
* <tt>GoogleContactsConnection</tt>.
* @param cnx <tt>GoogleContactsConnection</tt>.
*/
public void addContactSource(GoogleContactsConnection cnx)
{
GoogleContactsActivator.enableContactSource(cnx);
}
/**
* Add a contact source service with the specified
* <tt>GoogleContactsConnection</tt>.
*
* @param login login
* @param password password
*/
public void addContactSource(String login, String password)
{
GoogleContactsActivator.enableContactSource(login, password);
}
/**
* Add a contact source service with the specified.
*
* <tt>GoogleContactsConnection</tt>.
* @param cnx <tt>GoogleContactsConnection</tt>.
*/
public void removeContactSource(GoogleContactsConnection cnx)
{
GoogleContactsActivator.disableContactSource(cnx);
}
/**
* Remove a contact source service with the specified
* <tt>GoogleContactsConnection</tt>.
*
* @param login login
*/
public void removeContactSource(String login)
{
GoogleContactsActivator.disableContactSource(login);
}
/**
* Retrieve photo of a contact. Adapted from Google sample.
*
* @param photoLink photo link
* @param service
* @return byte array containing image photo or null if problem happened
*/
public static byte[] downloadPhoto(ILink photoLink,
ContactsService service)
{
try
{
if (photoLink != null)
{
GDataRequest request =
service.createLinkQueryRequest(photoLink);
request.execute();
InputStream in = request.getResponseStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
for (int read = 0 ; (read = in.read(buffer)) != -1;
out.write(buffer, 0, read));
return out.toByteArray();
}
}
catch(Exception e)
{
logger.info("Failed to retrieve photo of the contact", e);
}
return null;
}
}

@ -0,0 +1,273 @@
/*
* 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.impl.googlecontacts;
import java.util.*;
import java.util.regex.*;
import net.java.sip.communicator.service.contactsource.*;
import net.java.sip.communicator.service.googlecontacts.*;
import net.java.sip.communicator.util.*;
/**
* Implements <tt>ContactSourceService</tt> for Google Contacts.
*
* @author Sebastien Vincent
*/
public class GoogleContactsSourceService
implements ExtendedContactSourceService
{
/**
* Logger.
*/
private static final Logger logger =
Logger.getLogger(GoogleContactsSourceService.class);
/**
* The <tt>List</tt> of <tt>GoogleContactsQuery</tt> instances
* which have been started and haven't stopped yet.
*/
private final List<GoogleContactsQuery> queries
= new LinkedList<GoogleContactsQuery>();
/**
* Login.
*/
private final String login;
/**
* Password.
*/
private final String password;
/**
* Google Contacts connection.
*/
private GoogleContactsConnection cnx = null;
/**
* Constructor.
*
* @param login login
* @param password password
*/
public GoogleContactsSourceService(String login, String password)
{
super();
this.login = login;
this.password = password;
}
/**
* Constructor.
*
* @param cnx connection
*/
public GoogleContactsSourceService(GoogleContactsConnection cnx)
{
super();
this.cnx = cnx;
this.login = cnx.getLogin();
this.password = cnx.getPassword();
}
/**
* 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,
GoogleContactsQuery.GOOGLECONTACTS_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)
{
GoogleContactsQuery query = new GoogleContactsQuery(this, queryPattern,
count);
synchronized (queries)
{
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 the Google Contacts connection.
*
* @return Google Contacts connection
*/
public GoogleContactsConnectionImpl getConnection()
{
int s = login.indexOf('@');
boolean isGoogleAppsOrGmail = false;
if(s == -1)
{
return null;
}
String domain = login.substring((s + 1));
try
{
SRVRecord srvRecords[] =
NetworkUtils.getSRVRecords("xmpp-client", "tcp", domain);
if(srvRecords == null)
{
return null;
}
for(SRVRecord srv : srvRecords)
{
if(srv.getTarget().endsWith("google.com") ||
srv.getTarget().endsWith("google.com."))
{
isGoogleAppsOrGmail = true;
break;
}
}
if(isGoogleAppsOrGmail)
{
if(cnx == null)
{
cnx = new GoogleContactsConnectionImpl(login, password);
}
}
else
{
cnx = null;
}
}
catch(Exception e)
{
logger.info("GoogleContacts connection error", e);
return null;
}
return (GoogleContactsConnectionImpl)cnx;
}
/**
* Returns a user-friendly string that identifies this contact source.
* @return the display name of this contact source
*/
public String getDisplayName()
{
return login;
}
/**
* 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 "GoogleContacts";
}
/**
* 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),
GoogleContactsQuery.GOOGLECONTACTS_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>GoogleContactsSourceService</tt> that a specific
* <tt>GoogleContactsQuery</tt> has stopped.
*
* @param query the <tt>GoogleContactsQuery</tt> which has stopped
*/
void stopped(GoogleContactsQuery query)
{
synchronized (queries)
{
if (queries.remove(query))
queries.notify();
}
}
}

@ -0,0 +1,282 @@
/*
* 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.impl.googlecontacts.configform;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import net.java.sip.communicator.util.swing.*;
import net.java.sip.communicator.impl.googlecontacts.*;
import net.java.sip.communicator.service.googlecontacts.*;
/**
* The page with hostname/port/encryption fields
*
* @author Sebastien Mazy
* @author Sebastien Vincent
*/
public class AccountSettingsForm
extends SIPCommDialog
implements ActionListener
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* component holding the name
*/
private JTextField nameField;
/**
* the component holding the password
*/
private JPasswordField passwordField;
/**
* Save button.
*/
private JButton saveBtn = new JButton(
Resources.getString("impl.googlecontacts.SAVE"));
/**
* Cancel button.
*/
private JButton cancelBtn = new JButton(
Resources.getString("impl.googlecontacts.CANCEL"));
/**
* Return code.
*/
private int retCode = 0;
/**
* The Google Contacts connection.
*/
private GoogleContactsConnection cnx = null;
/**
* Constructor.
*/
public AccountSettingsForm()
{
this.setTitle(Resources.getString(
"impl.googlecontacts.CONFIG_FORM_TITLE"));
getContentPane().add(getContentPanel());
setMinimumSize(new Dimension(400, 200));
setSize(new Dimension(400, 400));
setPreferredSize(new Dimension(400, 200));
pack();
}
/**
* the panel to display in the card layout of the wizard
*
* @return this page's panel
*/
public JPanel getContentPanel()
{
JPanel contentPanel = new TransparentPanel(new BorderLayout());
JPanel mainPanel = new TransparentPanel();
JPanel basePanel = new TransparentPanel(new GridBagLayout());
JPanel btnPanel = new TransparentPanel(new FlowLayout(
FlowLayout.RIGHT));
BoxLayout boxLayout = new BoxLayout(mainPanel, BoxLayout.Y_AXIS);
GridBagConstraints c = new GridBagConstraints();
/* name text field */
JLabel nameLabel = new JLabel(
Resources.getString("impl.googlecontacts.ACCOUNT_NAME"));
this.nameField = new JTextField();
nameLabel.setLabelFor(nameField);
c.gridx = 0;
c.gridy = 0;
c.weightx = 0;
c.weighty = 0;
c.gridwidth = 1;
c.insets = new Insets(2, 50, 0, 5);
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.LINE_START;
basePanel.add(nameLabel, c);
c.gridx = 1;
c.gridy = 0;
c.weightx = 1;
c.weighty = 0;
c.gridwidth = GridBagConstraints.REMAINDER;
c.insets = new Insets(2, 5, 0, 50);
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.LINE_END;
basePanel.add(nameField, c);
JLabel nameExampleLabel = new JLabel("myaccount@gmail.com");
nameExampleLabel.setForeground(Color.GRAY);
nameExampleLabel.setFont(nameExampleLabel.getFont().deriveFont(8));
c.gridx = 1;
c.gridy = 1;
c.weightx = 1;
c.weighty = 0;
c.gridwidth = GridBagConstraints.REMAINDER;
c.insets = new Insets(0, 13, 2, 0);
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.LINE_START;
basePanel.add(nameExampleLabel, c);
JLabel passwordLabel = new JLabel(
Resources.getString("impl.googlecontacts.PASSWORD"));
this.passwordField = new JPasswordField();
nameLabel.setLabelFor(passwordField);
c.gridx = 0;
c.gridy = 2;
c.weightx = 0;
c.weighty = 0;
c.gridwidth = 1;
c.insets = new Insets(2, 50, 0, 5);
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.LINE_START;
basePanel.add(passwordLabel, c);
c.gridx = 1;
c.gridy = 2;
c.weightx = 1;
c.weighty = 0;
c.gridwidth = GridBagConstraints.REMAINDER;
c.insets = new Insets(2, 5, 0, 50);
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.LINE_END;
basePanel.add(passwordField, c);
mainPanel.setLayout(boxLayout);
mainPanel.add(basePanel);
/* listeners */
this.nameField.addActionListener(this);
this.passwordField.addActionListener(this);
this.saveBtn.addActionListener(this);
this.cancelBtn.addActionListener(this);
btnPanel.add(saveBtn);
btnPanel.add(cancelBtn);
contentPanel.add(mainPanel, BorderLayout.CENTER);
contentPanel.add(btnPanel, BorderLayout.SOUTH);
return contentPanel;
}
/**
* Loads the information.
*
* @param cnx connection
*/
public void loadData(GoogleContactsConnection cnx)
{
if(cnx != null)
{
this.nameField.setText(cnx.getLogin());
this.passwordField.setText(cnx.getPassword());
}
else
{
this.nameField.setText("");
this.passwordField.setText("");
}
}
/**
* Implementation of actionPerformed.
*
* @param e the ActionEvent triggered
*/
public void actionPerformed(ActionEvent e)
{
Object src = e.getSource();
if(src == saveBtn)
{
String login = nameField.getText();
String password = new String(passwordField.getPassword());
cnx = GoogleContactsActivator.getGoogleContactsService().
getConnection(login, password);
if(cnx == null)
{
JOptionPane.showMessageDialog(
this,
Resources.getString(
"impl.googlecontacts.WRONG_CREDENTIALS",
new String[]{login}),
Resources.getString(
"impl.googlecontacts.WRONG_CREDENTIALS",
new String[]{login}),
JOptionPane.WARNING_MESSAGE);
return;
}
retCode = 1;
dispose();
}
else if(src == cancelBtn)
{
retCode = 0;
dispose();
}
}
/**
* Get the connection.
*
* @return GoogleContactsConnection
*/
public GoogleContactsConnection getConnection()
{
return cnx;
}
/**
* All functions implemented in this method will be invoked when user
* presses the Escape key.
*
* @param escaped <tt>true</tt> if this dialog has been closed by pressing
* the Esc key; otherwise, <tt>false</tt>
*/
protected void close(boolean escaped)
{
cancelBtn.doClick();
}
/**
* Show the dialog and returns if the user has modified something (create
* or modify entry).
*
* @return true if the user has modified something (create
* or modify entry), false otherwise.
*/
public int showDialog()
{
retCode = 0;
cnx = null;
setVisible(true);
// this will block until user click on save/cancel/press escape/close
// the window
setVisible(false);
return retCode;
}
/**
* Set the name field enable or not
*
* @param enable parameter to set
*/
public void setNameFieldEnabled(boolean enable)
{
this.nameField.setEnabled(enable);
}
}

@ -0,0 +1,394 @@
/*
* 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.impl.googlecontacts.configform;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
import net.java.sip.communicator.impl.googlecontacts.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.credentialsstorage.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.googlecontacts.*;
/**
* This ConfigurationForm shows the list of Google Contacts account and allow
* users to manage them.
*
* @author Sebastien Mazy
* @author Sebastien Vincent
*/
public class GoogleContactsConfigForm
extends TransparentPanel
implements ConfigurationForm,
ActionListener,
ListSelectionListener
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The logger for this class.
*/
private static Logger logger = Logger.getLogger(
GoogleContactsConfigForm.class);
/**
* Opens the new directory registration wizard
*/
private JButton newButton = new JButton("+");
/**
* Opens a directory modification dialog
*/
private JButton modifyButton = new JButton(
Resources.getString("impl.googlecontacts.EDIT"));
/**
* Pops a directory deletion confirmation dialog
*/
private JButton removeButton = new JButton("-");
/**
* Displays the registered Google Contacts account.
*/
private JTable accountTable = new JTable();
/**
* Contains the new/modify/remove buttons
*/
private TransparentPanel buttonsPanel
= new TransparentPanel(new FlowLayout(FlowLayout.LEFT));
/**
* Contains the directoryTable
*/
private JScrollPane scrollPane = new JScrollPane();
/**
* Contains the buttonsPanel,
*/
private JPanel rightPanel = new TransparentPanel(new BorderLayout());
/**
* Contains listPanel and rightPanel
*/
private JPanel mainPanel = this;
/**
* Model for the directoryTable
*/
private GoogleContactsTableModel tableModel =
new GoogleContactsTableModel();
/**
* Settings form.
*/
private final AccountSettingsForm settingsForm =
new AccountSettingsForm();
/**
* Path where to store the account settings
*/
private final static String CONFIGURATION_PATH =
"net.java.sip.communicator.impl.googlecontacts";
/**
* Constructor
*/
public GoogleContactsConfigForm()
{
super(new BorderLayout());
logger.trace("GoogleContacts configuration form.");
initComponents();
}
/**
* Remove a connection.
*
* @param cnx connection to save
*/
private void removeConfig(GoogleContactsConnection cnx)
{
ConfigurationService configService =
GoogleContactsActivator.getConfigService();
configService.removeProperty(CONFIGURATION_PATH + ".acc" +
Math.abs(cnx.getLogin().hashCode()));
}
/**
* Save configuration.
*
* @param cnx connection to save
*/
private void saveConfig(GoogleContactsConnection cnx)
{
ConfigurationService configService =
GoogleContactsActivator.getConfigService();
CredentialsStorageService credentialsService =
GoogleContactsActivator.getCredentialsService();
String login = cnx.getLogin();
String path = CONFIGURATION_PATH + ".acc" + Math.abs(login.hashCode());
configService.setProperty(
path,
login);
configService.setProperty(
path + ".account",
login);
configService.setProperty(
path + ".enabled",
((GoogleContactsConnectionImpl)cnx).isEnabled());
credentialsService.storePassword(path, cnx.getPassword());
}
/**
* Inits the swing components
*/
private void initComponents()
{
modifyButton.setEnabled(false);
removeButton.setEnabled(false);
newButton.setSize(newButton.getMinimumSize());
modifyButton.setSize(modifyButton.getMinimumSize());
removeButton.setSize(removeButton.getMinimumSize());
accountTable.setRowHeight(22);
accountTable.setSelectionMode(
ListSelectionModel.SINGLE_SELECTION);
accountTable.setShowHorizontalLines(false);
accountTable.setShowVerticalLines(false);
accountTable.setModel(tableModel);
accountTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
accountTable.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent e)
{
if(e.getClickCount() > 1)
{
}
}
});
settingsForm.setModal(true);
/* consistency with the accounts config form */
rightPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
rightPanel.add(buttonsPanel, BorderLayout.NORTH);
scrollPane.getViewport().add(accountTable);
mainPanel.add(scrollPane, BorderLayout.CENTER);
mainPanel.add(rightPanel, BorderLayout.SOUTH);
mainPanel.setPreferredSize(new Dimension(500, 400));
buttonsPanel.add(newButton);
buttonsPanel.add(removeButton);
buttonsPanel.add(modifyButton);
accountTable.getSelectionModel().addListSelectionListener(this);
newButton.setActionCommand("new");
newButton.addActionListener(this);
modifyButton.addActionListener(this);
modifyButton.setActionCommand("modify");
removeButton.addActionListener(this);
removeButton.setActionCommand("remove");
}
/**
* @see net.java.sip.communicator.service.gui.ConfigurationForm#getTitle
*/
public String getTitle()
{
return Resources.getString("impl.googlecontacts.CONFIG_FORM_TITLE");
}
/**
* @see net.java.sip.communicator.service.gui.ConfigurationForm#getIcon
*/
public byte[] getIcon()
{
return Resources.getImageInBytes(
"GOOGLECONTACTS_CONFIG_FORM_ICON");
}
/**
* @see net.java.sip.communicator.service.gui.ConfigurationForm#getForm
*/
public Object getForm()
{
return this;
}
/**
* Required by ConfirgurationForm interface
*
* Returns the index of this configuration form in the configuration window.
* This index is used to put configuration forms in the desired order.
* <p>
* 0 is the first position
* -1 means that the form will be put at the end
* </p>
* @return the index of this configuration form in the configuration window.
*
* @see net.java.sip.communicator.service.gui.ConfigurationForm#getIndex
*/
public int getIndex()
{
return -1;
}
/**
* Processes buttons events (new, modify, remove)
*
* @see java.awt.event.ActionListener#actionPerformed
*/
public void actionPerformed(ActionEvent e)
{
int row = accountTable.getSelectedRow();
if (e.getActionCommand().equals("new"))
{
settingsForm.setNameFieldEnabled(true);
settingsForm.loadData(null);
int ret = settingsForm.showDialog();
if(ret == 1)
{
GoogleContactsConnection cnx = settingsForm.getConnection();
tableModel.addAccount(cnx, true);
new RefreshContactSourceThread(null, cnx).start();
saveConfig(cnx);
refresh();
}
}
if (e.getActionCommand().equals("modify") && row != -1)
{
settingsForm.setNameFieldEnabled(false);
GoogleContactsConnection cnx = tableModel.getAccountAt(row);
settingsForm.loadData(cnx);
int ret = settingsForm.showDialog();
if(ret == 1)
{
refresh();
}
}
if (e.getActionCommand().equals("remove") && row != -1)
{
GoogleContactsConnection cnx = tableModel.getAccountAt(row);
tableModel.removeAccount(cnx.getLogin());
removeConfig(cnx);
new RefreshContactSourceThread(cnx, null).start();
refresh();
}
}
/**
* Required by ListSelectionListener. Enables the "modify"
* button when a server is selected in the table
*
* @param e event triggered
*/
public void valueChanged(ListSelectionEvent e)
{
if(accountTable.getSelectedRow() == -1)
{
modifyButton.setEnabled(false);
removeButton.setEnabled(false);
return;
}
else if(!e.getValueIsAdjusting())
{
modifyButton.setEnabled(true);
removeButton.setEnabled(true);
saveConfig(tableModel.getAccountAt(accountTable.getSelectedRow()));
}
}
/**
* refreshes the table display
*/
private void refresh()
{
tableModel.fireTableStructureChanged();
}
/**
* Indicates if this is an advanced configuration form.
* @return <tt>true</tt> if this is an advanced configuration form,
* otherwise it returns <tt>false</tt>
*/
public boolean isAdvanced()
{
return true;
}
/**
* Thread that will perform refresh of contact sources.
*/
public static class RefreshContactSourceThread
extends Thread
{
/**
* Old connection.
*/
private GoogleContactsConnection oldCnx = null;
/**
* New connection.
*/
private GoogleContactsConnection newCnx = null;
/**
* Constructor.
*
* @param oldCnx old connection.
* @param newCnx new connection.
*/
RefreshContactSourceThread(GoogleContactsConnection oldCnx,
GoogleContactsConnection newCnx)
{
this.oldCnx = oldCnx;
this.newCnx = newCnx;
}
/**
* Thread entry point.
*/
public void run()
{
if(oldCnx != null)
{
GoogleContactsActivator.getGoogleContactsService().
removeContactSource(oldCnx);
}
if(newCnx != null)
{
GoogleContactsActivator.getGoogleContactsService().
addContactSource(newCnx);
}
}
}
}

@ -0,0 +1,217 @@
/*
* 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.impl.googlecontacts.configform;
import java.util.*;
import javax.swing.table.*;
import net.java.sip.communicator.service.googlecontacts.*;
import net.java.sip.communicator.impl.googlecontacts.*;
/**
* A table model suitable for the directories list in
* the configuration form. Takes its data in an LdapDirectorySet.
*
* @author Sebastien Mazy
* @author Sebastien Vincent
*/
public class GoogleContactsTableModel
extends AbstractTableModel
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* Google Contacts service reference.
*/
private final GoogleContactsServiceImpl googleService =
GoogleContactsActivator.getGoogleContactsService();
/**
* Add account from table.
*
* @param cnx account
* @param enabled if the account should be enabled
*/
public void addAccount(GoogleContactsConnection cnx, boolean enabled)
{
if(cnx != null)
{
((GoogleContactsConnectionImpl)cnx).setEnabled(enabled);
googleService.getAccounts().add((GoogleContactsConnectionImpl)cnx);
}
}
/**
* Remove account from table.
*
* @param login account login to remove
*/
public void removeAccount(String login)
{
Iterator<GoogleContactsConnectionImpl> it =
googleService.getAccounts().iterator();
while(it.hasNext())
{
GoogleContactsConnection cnx = it.next();
if(cnx.getLogin().equals(login))
{
it.remove();
return;
}
}
}
/**
* Returns the title for this column
*
* @param column the column
*
* @return the title for this column
*
* @see javax.swing.table.AbstractTableModel#getColumnName
*/
public String getColumnName(int column)
{
switch(column)
{
case 0:
return Resources.getString("impl.googlecontacts.ENABLED");
case 1:
return Resources.getString("impl.googlecontacts.ACCOUNT_NAME");
default:
throw new IllegalArgumentException("column not found");
}
}
/**
* Returns the number of rows in the table
*
* @return the number of rows in the table
* @see javax.swing.table.AbstractTableModel#getRowCount
*/
public int getRowCount()
{
return googleService.getAccounts().size();
}
/**
* Returns the number of column in the table
*
* @return the number of columns in the table
*
* @see javax.swing.table.AbstractTableModel#getColumnCount
*/
public int getColumnCount()
{
// 2 columns: "enable" and "account name"
return 2;
}
/**
* Returns the text for the given cell of the table
*
* @param row cell row
* @param column cell column
*
* @see javax.swing.table.AbstractTableModel#getValueAt
*/
public Object getValueAt(int row, int column)
{
switch(column)
{
case 0:
return new Boolean(getAccountAt(row).isEnabled());
case 1:
return getAccountAt(row).getLogin();
default:
throw new IllegalArgumentException("column not found");
}
}
/**
* Returns the account credentials at the row 'row'
*
* @param row the row
*
* @return the login/password for the account
*/
public GoogleContactsConnectionImpl getAccountAt(int row)
{
if(row < 0 || row >= googleService.getAccounts().size())
{
throw new IllegalArgumentException("row not found");
}
else
{
return googleService.getAccounts().get(row);
}
}
/**
* Returns whether a cell is editable. Only "enable" column (checkboxes)
* is editable
*
* @param row row of the cell
* @param col column of the cell
*
* @return whether the cell is editable
*/
public boolean isCellEditable(int row, int col)
{
if(col == 0)
return true;
else
return false;
}
/**
* Overrides a method that always returned Object.class
* Now it will return Boolean.class for the first method,
* letting the DefaultTableCellRenderer create checkboxes.
*
* @param columnIndex index of the column
* @return Column class
*/
public Class<?> getColumnClass(int columnIndex)
{
return getValueAt(0, columnIndex).getClass();
}
/**
* Sets a value in an editable cell, that is to say
* an enable/disable chekbox in colum 0
*/
public void setValueAt(Object aValue, int rowIndex, int columnIndex)
{
if(columnIndex != 0)
throw new IllegalArgumentException("non editable column!");
GoogleContactsConfigForm.RefreshContactSourceThread th = null;
GoogleContactsConnectionImpl cnx = getAccountAt(rowIndex);
if(cnx.isEnabled())
{
th = new GoogleContactsConfigForm.RefreshContactSourceThread(cnx,
null);
}
else
{
th = new GoogleContactsConfigForm.RefreshContactSourceThread(null,
cnx);
}
cnx.setEnabled(!cnx.isEnabled());
th.start();
}
}

@ -0,0 +1,68 @@
/*
* 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.impl.googlecontacts.configform;
import javax.swing.*;
import net.java.sip.communicator.impl.googlecontacts.*;
/**
* The <tt>Resources</tt> class manages the access to the internationalization
* properties files and the image resources used in this plugin.
*
* @author Yana Stamcheva
*/
public class Resources
{
/**
* Returns an internationalized string corresponding to the given key.
*
* @param key The key of the string.
* @return An internationalized string corresponding to the given key.
*/
public static String getString(String key)
{
return GoogleContactsActivator.getResourceManagementService()
.getI18NString(key);
}
/**
* Returns an internationalized string corresponding to the given key.
*
* @param key The key of the string.
* @param params additionnal parameters
* @return An internationalized string corresponding to the given key.
*/
public static String getString(String key, String[] params)
{
return GoogleContactsActivator.getResourceManagementService()
.getI18NString(key, params);
}
/**
* Loads an image from a given image identifier.
*
* @param imageID The identifier of the image.
* @return The image for the given identifier.
*/
public static ImageIcon getImage(String imageID)
{
return GoogleContactsActivator.getResourceManagementService().getImage(imageID);
}
/**
* Loads an image from a given image identifier.
*
* @param imageID The identifier of the image.
* @return The image for the given identifier.
*/
public static byte[] getImageInBytes(String imageID)
{
return GoogleContactsActivator.getResourceManagementService().
getImageInBytes(imageID);
}
}

@ -0,0 +1,26 @@
Bundle-Activator: net.java.sip.communicator.impl.googlecontacts.GoogleContactsActivator
Bundle-Name: Google Contacts Service Implementation
Bundle-Description: A bundle that offers access to Google Contacts
Bundle-Vendor: sip-communicator.org
Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: org.osgi.framework,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.service.credentialsstorage,
net.java.sip.communicator.service.contactsource,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.util,
net.java.sip.communicator.util.swing,
org.xml.sax,
org.xml.sax.helpers,
javax.xml.parsers,
javax.xml,
javax.swing,
javax.swing.border,
javax.swing.event,
javax.swing.table,
javax.swing.tree,
javax.swing.text,
Export-Package: net.java.sip.communicator.service.googlecontacts

@ -44,7 +44,7 @@ public static LdapService getLdapService()
* Starts the LDAP service
*
* @param bundleContext BundleContext
* @throws Exception
* @throws Exception if something goes wrong when starting service
*/
public void start(BundleContext bundleContext)
throws Exception
@ -72,6 +72,9 @@ public void start(BundleContext bundleContext)
/**
* Stops the LDAP service
*
* @param bundleContext BundleContext
* @throws Exception if something goes wrong when stopping service
*/
public void stop(BundleContext bundleContext)
throws Exception

@ -1119,7 +1119,7 @@ public ScreenDevice getScreenForPoint(Point p)
return null;
}
/**
* Get origin for desktop streaming device.
*
@ -1130,7 +1130,7 @@ public Point getOriginForDesktopStreamingDevice(MediaDevice mediaDevice)
MediaDeviceImpl dev = (MediaDeviceImpl)mediaDevice;
CaptureDeviceInfo devInfo = dev.getCaptureDeviceInfo();
MediaLocator locator = devInfo.getLocator();
if(!locator.getProtocol().
equals(ImageStreamingAuto.LOCATOR_PROTOCOL))
{

@ -16,8 +16,10 @@
import net.java.sip.communicator.service.packetlogging.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.service.googlecontacts.*;
import net.java.sip.communicator.util.*;
import org.jivesoftware.smack.util.StringUtils;
import org.osgi.framework.*;
/**
@ -84,7 +86,17 @@ public class JabberActivator
*/
private static HIDService hidService = null;
private static PacketLoggingService packetLoggingService = null;
/**
* A reference to the currently valid <tt>PacketLoggingService</tt>
* instance.
*/
private static PacketLoggingService packetLoggingService = null;
/**
* A reference to the currently valid <tt>GoogleContactsService</tt>
* instance.
*/
private static GoogleContactsService googleService = null;
/**
* Called when this bundle is started so the Framework can perform the
@ -323,4 +335,24 @@ public static PacketLoggingService getPacketLogging()
}
return packetLoggingService;
}
/**
* Returns a reference to the GoogleContactsService implementation
* currently registered in the bundle context or null if no such
* implementation was found.
*
* @return a reference to a GoogleContactsService implementation
* currently registered in the bundle context or null if no such
* implementation was found.
*/
public static GoogleContactsService getGoogleService()
{
if (googleService == null)
{
googleService
= ServiceUtils.getService(
bundleContext, GoogleContactsService.class);
}
return googleService;
}
}

@ -158,7 +158,10 @@ public void modifyAccount( ProtocolProviderService protocolProvider,
try
{
if(protocolProvider.isRegistered())
{
protocolProvider.unregister();
protocolProvider.shutdown();
}
} catch (Throwable e)
{
// we don't care for this, cause we are modifying and

@ -22,6 +22,7 @@
import net.java.sip.communicator.impl.protocol.jabber.extensions.inputevt.*;
import net.java.sip.communicator.impl.protocol.jabber.sasl.*;
import net.java.sip.communicator.service.certificate.*;
import net.java.sip.communicator.service.googlecontacts.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.packet.*;
@ -927,7 +928,6 @@ private void disconnectAndCleanConnection()
} catch (Exception e)
{}
connectionListener = null;
connection = null;
// make it null as it also holds a reference to the old connection
@ -1258,6 +1258,9 @@ protected void initialize(String screenname,
OperationSetGenericNotifications.class,
new OperationSetGenericNotificationsJabberImpl(this));
/* add Google Contacts as contact source if enabled */
registerGoogleContactsSource();
isInitialized = true;
}
}
@ -1274,6 +1277,8 @@ public void shutdown()
if (logger.isTraceEnabled())
logger.trace("Killing the Jabber Protocol Provider.");
unregisterGoogleContactsSource();
//kill all active calls
OperationSetBasicTelephonyJabberImpl telephony
= (OperationSetBasicTelephonyJabberImpl)getOperationSet(
@ -1897,6 +1902,56 @@ public SmackServiceNode getJingleNodesServiceNode()
return jingleNodesServiceNode;
}
/**
* Register Google Contacts as contact source if user has enable it.
*/
private void registerGoogleContactsSource()
{
if(accountID.getAccountPropertyBoolean(
"GOOGLE_CONTACTS_ENABLED",
false))
{
logger.info("Register Google Contacts service as contact source");
GoogleContactsService googleService =
JabberActivator.getGoogleService();
if(googleService != null)
{
googleService.addContactSource(
org.jivesoftware.smack.util.StringUtils.parseName(
getOurJID()) + "@" +
StringUtils.parseServer(getAccountID().getUserID()),
JabberActivator.
getProtocolProviderFactory().loadPassword(
getAccountID()));
}
}
}
/**
* Unregister Google Contacts as contact source.
*/
private void unregisterGoogleContactsSource()
{
if(accountID.getAccountPropertyBoolean(
"GOOGLE_CONTACTS_ENABLED",
false))
{
logger.info("Unregister Google Contacts service as contact source");
GoogleContactsService googleService =
JabberActivator.getGoogleService();
if(googleService != null)
{
googleService.removeContactSource(
org.jivesoftware.smack.util.StringUtils.parseName(
getOurJID()) + "@" +
StringUtils.parseServer(getAccountID().getUserID()));
}
}
}
/**
* Logs a specific message and associated <tt>Throwable</tt> cause as an
* error using the current <tt>Logger</tt> and then throws a new

@ -48,6 +48,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.argdelegation,
net.java.sip.communicator.service.certificate,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.googlecontacts,
org.xmlpull.v1,
org.xmlpull.mxp1,
javax.xml.parsers,

@ -14,13 +14,18 @@
import net.java.sip.communicator.util.swing.*;
/**
*
*
* @author Yana Stamcheva
*/
public class ConnectionPanel
extends TransparentPanel
implements ValidatingPanel
{
/**
* Serial version UID.
*/
private final static long serialVersionUID = 0L;
private final TransparentPanel mainPanel = new TransparentPanel();
private final JPanel advancedOpPanel
@ -39,6 +44,10 @@ public class ConnectionPanel
Resources.getString(
"plugin.jabberaccregwizz.ENABLE_GMAIL_NOTIFICATIONS"));
private final JCheckBox googleContactsBox = new SIPCommCheckBox(
Resources.getString(
"plugin.jabberaccregwizz.ENABLE_GOOGLE_CONTACTS_SOURCE"));
private final JLabel resourceLabel
= new JLabel(Resources.getString("plugin.jabberaccregwizz.RESOURCE"));
@ -126,6 +135,7 @@ public void removeUpdate(DocumentEvent evt)
= new TransparentPanel(new GridLayout(0, 1, 10, 10));
checkBoxesPanel.add(sendKeepAliveBox);
checkBoxesPanel.add(gmailNotificationsBox);
checkBoxesPanel.add(googleContactsBox);
advancedOpPanel.add(checkBoxesPanel, BorderLayout.NORTH);
advancedOpPanel.add(labelsAdvOpPanel, BorderLayout.WEST);
@ -256,6 +266,28 @@ void setGmailNotificationsEnabled(boolean isEnabled)
gmailNotificationsBox.setSelected(isEnabled);
}
/**
* Returns <tt>true</tt> if the "Google contacts" check box is selected,
* otherwise returns <tt>false</tt>.
* @return <tt>true</tt> if the "Google contacts" check box is selected,
* otherwise returns <tt>false</tt>
*/
boolean isGoogleContactsEnabled()
{
return googleContactsBox.isSelected();
}
/**
* Selects/unselects the "Google contacts" check box according to the
* given <tt>isEnabled</tt> property.
* @param isEnabled indicates if the "Google contacts"
* check box should be selected or not
*/
void setGoogleContactsEnabled(boolean isEnabled)
{
googleContactsBox.setSelected(isEnabled);
}
/**
* Disables Next Button if Port field value is incorrect
*/

@ -28,6 +28,9 @@ public class FirstWizardPage
*/
private static final long serialVersionUID = 0L;
/**
* Identifier of the first page.
*/
public static final String FIRST_PAGE_IDENTIFIER = "FirstPageIdentifier";
private Object nextPageIdentifier = WizardPage.SUMMARY_PAGE_IDENTIFIER;

@ -88,6 +88,11 @@ public class JabberAccountRegistration
*/
private boolean enableGmailNotification = false;
/**
* Indicates if Google Contacts should be enabled.
*/
private boolean enableGoogleContacts = false;
/**
* Indicates if ICE should be used.
*/
@ -232,6 +237,18 @@ public boolean isGmailNotificationEnabled()
return enableGmailNotification;
}
/**
* Determines whether SIP Communicator should use Google Contacts as
* ContactSource
*
* @return <tt>true</tt> if we are to enable Google Contacts and
* <tt>false</tt> otherwise.
*/
public boolean isGoogleContactsEnabled()
{
return enableGoogleContacts;
}
/**
* Sets the User ID of the jabber registration account.
*
@ -316,6 +333,18 @@ public void setGmailNotificationEnabled(boolean enabled)
this.enableGmailNotification = enabled;
}
/**
* Specifies whether SIP Communicator should use Google Contacts as
* ContactSource.
*
* @param enabled <tt>true</tt> if we are to enable Google Contacts and
* <tt>false</tt> otherwise.
*/
public void setGoogleContactsEnabled(boolean enabled)
{
this.enableGoogleContacts = enabled;
}
/**
* Returns the resource.
* @return the resource

@ -17,6 +17,11 @@
public class JabberAccountRegistrationForm
extends TransparentPanel
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
private final AccountPanel accountPanel;
private final ConnectionPanel connectionPanel;
@ -125,7 +130,7 @@ void reValidateInput()
}
/**
* Adds panel to the list of panels with values which need validation.
* Adds panel to the list of panels with values which need validation.
* @param panel ValidatingPanel.
*/
public void addValidatingPanel(ValidatingPanel panel)
@ -163,7 +168,7 @@ String getServerAddress()
/**
* Indicates if this wizard is modifying an existing account or is creating
* a new one.
*
*
* @return <code>true</code> to indicate that this wizard is currently in
* modification mode, <code>false</code> - otherwise.
*/
@ -193,6 +198,8 @@ public boolean commitPage(JabberAccountRegistration registration)
registration.setSendKeepAlive(connectionPanel.isSendKeepAlive());
registration.setGmailNotificationEnabled(
connectionPanel.isGmailNotificationsEnabled());
registration.setGoogleContactsEnabled(
connectionPanel.isGoogleContactsEnabled());
registration.setResource(connectionPanel.getResource());
String serverPort = connectionPanel.getServerPort();
@ -280,6 +287,12 @@ public void loadAccount(AccountID accountID)
connectionPanel.setGmailNotificationsEnabled(gmailNotificationEnabled);
boolean googleContactsEnabled
= Boolean.parseBoolean(
accountProperties.get("GOOGLE_CONTACTS_ENABLED"));
connectionPanel.setGoogleContactsEnabled(googleContactsEnabled);
String resource
= accountProperties.get(ProtocolProviderFactory.RESOURCE);

@ -295,6 +295,8 @@ protected ProtocolProviderService installAccount(
accountProperties.put("GMAIL_NOTIFICATIONS_ENABLED",
String.valueOf(registration.isGmailNotificationEnabled()));
accountProperties.put("GOOGLE_CONTACTS_ENABLED",
String.valueOf(registration.isGoogleContactsEnabled()));
String serverName = null;
if (registration.getServerAddress() != null)

@ -0,0 +1,29 @@
/*
* 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.googlecontacts;
/**
* Interface that define a Google Contacts connection.
*
* @author Sebastien Vincent
*/
public interface GoogleContactsConnection
{
/**
* Get login.
*
* @return login to connect to the service
*/
public String getLogin();
/**
* get password.
*
* @return password to connect to the service
*/
public String getPassword();
}

@ -0,0 +1,185 @@
/*
* 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.googlecontacts;
import java.util.*;
/**
* Entry of Google Contacts directory.
*
* @author Sebastien Vincent
*/
public interface GoogleContactsEntry
{
/**
* The supported IM protocol
*/
public enum IMProtocol
{
/**
* Google Talk protocol.
*/
GOOGLETALK,
/**
* Yahoo protocol.
*/
YAHOO,
/**
* AIM protocol.
*/
AIM,
/**
* MSN protocol.
*/
MSN,
/**
* ICQ protocol.
*/
ICQ,
/**
* Jabber protocol.
*/
JABBER,
/**
* Other protocol (i.e. not supported).
*/
OTHER,
}
/**
* Get the full name.
*
* @return full name
*/
public String getFullName();
/**
* Get the family name.
*
* @return family name
*/
public String getFamilyName();
/**
* Get the given name.
*
* @return given name
*/
public String getGivenName();
/**
* Returns mails.
*
* @return mails
*/
public List<String> getAllMails();
/**
* Adds a home mail address.
*
* @param mail the mail address
*/
public void addHomeMail(String mail);
/**
* Returns home mail addresses.
*
* @return home mail addresses
*/
public List<String> getHomeMails();
/**
* Adds a work mail address.
*
* @param mail the mail address
*/
public void addWorkMails(String mail);
/**
* Returns work mail addresses.
*
* @return work mail addresses
*/
public List<String> getWorkMails();
/**
* Returns telephone numbers.
*
* @return telephone numbers
*/
public List<String> getAllPhones();
/**
* Adds a work telephone number.
*
* @param telephoneNumber the work telephone number
*/
public void addWorkPhone(String telephoneNumber);
/**
* Returns work telephone numbers.
*
* @return work telephone numbers
*/
public List<String> getWorkPhones();
/**
* Adds a mobile telephone numbers.
*
* @param telephoneNumber the mobile telephone number
*/
public void addMobilePhone(String telephoneNumber);
/**
* Returns mobile telephone numbers.
*
* @return mobile telephone numbers
*/
public List<String> getMobilePhones();
/**
* Adds a home telephone numbers.
*
* @param telephoneNumber the home telephone number
*/
public void addHomePhone(String telephoneNumber);
/**
* Returns home telephone numbers.
*
* @return home telephone numbers
*/
public List<String> getHomePhones();
/**
* Get the photo full URI.
*
* @return the photo URI or null if there isn't
*/
public String getPhoto();
/**
* Returns IM addresses.
*
* @return Map where key is IM address and value is IM protocol (MSN, ...)
*/
public Map<String, IMProtocol> getIMAddresses();
/**
* Adds an IM address.
*
* @param imAddress IM address
* @param protocol IM protocol
*/
public void addIMAddress(String imAddress, IMProtocol protocol);
}

@ -0,0 +1,80 @@
/*
* 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.googlecontacts;
import java.util.*;
/**
* Google Contacts service.
*
* @author Sebastien Vincent
*/
public interface GoogleContactsService
{
/**
* Perform a search for a contact using regular expression.
*
* @param cnx <tt>GoogleContactsConnection</tt> to perform the query
* @param query Google query
* @param count maximum number of matched contacts
* @param callback object that will be notified for each new
* <tt>GoogleContactsEntry</tt> found
* @return list of <tt>GoogleContactsEntry</tt>
*/
public List<GoogleContactsEntry> searchContact(GoogleContactsConnection cnx,
GoogleQuery query, int count, GoogleEntryCallback callback);
/**
* Get a <tt>GoogleContactsConnection</tt>.
*
* @param login login to connect to the service
* @param password password to connect to the service
* @return <tt>GoogleContactsConnection</tt>.
*/
public GoogleContactsConnection getConnection(String login,
String password);
/**
* Get the full contacts list.
*
* @return list of <tt>GoogleContactsEntry</tt>
*/
public List<GoogleContactsEntry> getContacts();
/**
* Add a contact source service with the specified
* <tt>GoogleContactsConnection</tt>.
*
* @param login login
* @param password password
*/
public void addContactSource(String login, String password);
/**
* Add a contact source service with the specified
* <tt>GoogleContactsConnection</tt>.
*
* @param cnx <tt>GoogleContactsConnection</tt>.
*/
public void addContactSource(GoogleContactsConnection cnx);
/**
* Remove a contact source service with the specified
* <tt>GoogleContactsConnection</tt>.
*
* @param cnx <tt>GoogleContactsConnection</tt>.
*/
public void removeContactSource(GoogleContactsConnection cnx);
/**
* Remove a contact source service with the specified
* <tt>GoogleContactsConnection</tt>.
*
* @param login login
*/
public void removeContactSource(String login);
}

@ -0,0 +1,23 @@
/*
* 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.googlecontacts;
/**
* Defines the interface for a callback function which is called by the
* <tt>GoogleContactsService</tt> when a new <tt>GoogleContactsEntry</tt> has
* been found during a search.
*/
public interface GoogleEntryCallback
{
/**
* Notifies this <tt>GoogleEntryCallback</tt> when a new
* <tt>GoogleContactsEntry</tt> has been found.
*
* @param entry the <tt>GoogleContactsEntry</tt> found
*/
void callback(GoogleContactsEntry entry);
}

@ -0,0 +1,65 @@
/*
* 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.googlecontacts;
import java.util.regex.*;
/**
* Describes a Google query.
*
* @author Sebastien Vincent
*/
public class GoogleQuery
{
/**
* If the query is cancelled.
*/
private boolean cancelled = false;
/**
* The query pattern.
*/
private Pattern query = null;
/**
* Constructor.
*
* @param query query string
*/
public GoogleQuery(Pattern query)
{
this.query = query;
}
/**
* Get the query pattern.
*
* @return query pattern
*/
public Pattern getQueryPattern()
{
return query;
}
/**
* Cancel the query.
*/
public void cancel()
{
cancelled = true;
}
/**
* If the query has been cancelled.
*
* @return true If the query has been cancelled, false otherwise
*/
public boolean isCancelled()
{
return cancelled;
}
}
Loading…
Cancel
Save