/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.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 ContactQuery for Google Contacts.
*
* @author Sebastien Vincent
*/
public class GoogleContactsQuery
extends AsyncContactQuery
{
/**
* 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 GoogleContactsQuery instance which is to
* perform a specific query on behalf of a specific
* contactSource.
*
* @param contactSource the ContactSourceService which is to
* perform the new ContactQuery instance
* @param query the Pattern for which contactSource is
* being queried
* @param count maximum number of results
*/
protected GoogleContactsQuery(GoogleContactsSourceService
contactSource, Pattern query, int count)
{
super(contactSource, query);
this.count = count;
}
/**
* Create a SourceContact from a GoogleContactsEntry.
*
* @param entry GoogleContactsEntry
*/
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 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 AsyncContactQuery in a background Thread.
*
* @see AsyncContactQuery#run()
*/
@Override
protected void run()
{
GoogleContactsServiceImpl service =
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);
}
});
}
@Override
public synchronized void start()
{
boolean hasStarted = false;
try
{
super.start();
hasStarted = true;
}
finally
{
if (!hasStarted)
{
getContactSource().removeQuery(this);
}
}
}
/**
* Gets the contactDetails to be set on a SourceContact.
*
* @param entry GoogleContactsEntry
* @return the contactDetails to be set on a SourceContact
*/
private List getContactDetails(GoogleContactsEntry entry)
{
List ret = new LinkedList();
List homeMails = entry.getHomeMails();
List workMails = entry.getWorkMails();
List mobilePhones = entry.getMobilePhones();
List homePhones = entry.getHomePhones();
List workPhones = entry.getWorkPhones();
Map ims =
entry.getIMAddresses();
ContactDetail detail = null;
for(String mail : homeMails)
{
List> supportedOpSets
= new ArrayList>(1);
// can be added as contacts
supportedOpSets.add(OperationSetPersistentPresence.class);
detail = new ContactDetail(mail,
ContactDetail.Category.Email,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Home});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
for(String mail : workMails)
{
List> supportedOpSets
= new ArrayList>(1);
// can be added as contacts
supportedOpSets.add(OperationSetPersistentPresence.class);
detail = new ContactDetail(mail,
ContactDetail.Category.Email,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Work});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
for(String homePhone : homePhones)
{
List> supportedOpSets
= new ArrayList>(2);
supportedOpSets.add(OperationSetBasicTelephony.class);
// can be added as contacts
supportedOpSets.add(OperationSetPersistentPresence.class);
homePhone = GoogleContactsActivator.getPhoneNumberI18nService()
.normalize(homePhone);
detail = new ContactDetail(homePhone,
ContactDetail.Category.Phone,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Home});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
for(String workPhone : workPhones)
{
List> supportedOpSets
= new ArrayList>(2);
supportedOpSets.add(OperationSetBasicTelephony.class);
// can be added as contacts
supportedOpSets.add(OperationSetPersistentPresence.class);
workPhone = GoogleContactsActivator.getPhoneNumberI18nService()
.normalize(workPhone);
detail = new ContactDetail(workPhone,
ContactDetail.Category.Phone,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Work});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
for(String mobilePhone : mobilePhones)
{
List> supportedOpSets
= new ArrayList>(2);
supportedOpSets.add(OperationSetBasicTelephony.class);
// can be added as contacts
supportedOpSets.add(OperationSetPersistentPresence.class);
mobilePhone = GoogleContactsActivator.getPhoneNumberI18nService()
.normalize(mobilePhone);
detail = new ContactDetail(mobilePhone,
ContactDetail.Category.Phone,
new ContactDetail.SubCategory[]{
ContactDetail.SubCategory.Mobile});
detail.setSupportedOpSets(supportedOpSets);
ret.add(detail);
}
for(Map.Entry im
: ims.entrySet())
{
if(im.getValue() != GoogleContactsEntry.IMProtocol.OTHER)
{
ContactDetail.SubCategory imSubCat;
switch(im.getValue())
{
case AIM:
imSubCat = ContactDetail.SubCategory.AIM;
break;
case ICQ:
imSubCat = ContactDetail.SubCategory.ICQ;
break;
case YAHOO:
imSubCat = ContactDetail.SubCategory.Yahoo;
break;
case JABBER:
imSubCat = ContactDetail.SubCategory.Jabber;
break;
case MSN:
imSubCat = ContactDetail.SubCategory.MSN;
break;
case GOOGLETALK:
imSubCat = ContactDetail.SubCategory.GoogleTalk;
break;
default:
imSubCat = null;
break;
}
detail
= new ContactDetail(
im.getKey(),
ContactDetail.Category.InstantMessaging,
new ContactDetail.SubCategory[] { imSubCat });
setIMCapabilities(detail, im.getValue());
// can be added as contacts
detail.getSupportedOperationSets().add(
OperationSetPersistentPresence.class);
ret.add(detail);
}
}
return ret;
}
/**
* Sets the IM capabilities of a specific ContactDetail (e.g.
* supportedOpSets).
*
* @param contactDetail the ContactDetail to set the capabilities
* of
* @param protocol protocol
* @return contactDetail
*/
private ContactDetail setIMCapabilities(
ContactDetail contactDetail,
GoogleContactsEntry.IMProtocol protocol)
{
List> supportedOpSets
= new LinkedList>();
Map, String> preferredProtocols
= new HashMap, 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 GoogleContactsQuery that it has stopped performing
* in the associated background Thread.
*
* @param completed true if this ContactQuery has
* successfully completed, false 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 ContactQuery.
*
* @see ContactQuery#cancel()
*/
@Override
public void cancel()
{
if(gQuery != null)
{
gQuery.cancel();
}
super.cancel();
}
}