mirror of https://github.com/sipwise/jitsi.git
parent
2dde9f4937
commit
fbeb769df3
@ -0,0 +1,23 @@
|
||||
package net.java.sip.communicator.impl.protocol.icq;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* The ICQ implementation of the service.protocol.ContactGroup interface. There
|
||||
* are two types of groups possible here. <code>RootContactGroupIcqImpl</code>
|
||||
* which is the root node of the ContactList itself and
|
||||
* <code>ContactGroupIcqImpl</code> which represents standard icq groups. The
|
||||
* reason for having those 2 is that generally, ICQ groups may not contain
|
||||
* subgroups. A contact list on the other hand may not directly contain buddies.
|
||||
*
|
||||
*
|
||||
* The reason for having an abstract class is only - being able to esily
|
||||
* recognize our own (ICQ) contacts.
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public abstract class AbstractContactGroupIcqImpl
|
||||
implements ContactGroup
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.protocol.icq;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.configuration.*;
|
||||
|
||||
/**
|
||||
* The ICQ implementation of the ProtocolAccountManager.
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class AccountManagerIcqImpl
|
||||
implements AccountManager
|
||||
{
|
||||
private Hashtable registeredAccounts = new Hashtable();
|
||||
|
||||
|
||||
/**
|
||||
* Creates an instance of the IcqAccountManager.
|
||||
*/
|
||||
protected void IcqAccountManager()
|
||||
{
|
||||
|
||||
}
|
||||
/**
|
||||
* Returns a copy of the list containing all accounts currently
|
||||
* registered in this protocol provider.
|
||||
*
|
||||
* @return a copy of the llist containing all accounts currently installed
|
||||
* in the protocol provider.
|
||||
*/
|
||||
public ArrayList getRegisteredAcounts()
|
||||
{
|
||||
return new ArrayList(registeredAccounts.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ServiceReference for the protocol provider corresponding to
|
||||
* the specified accountID or null if the accountID is unknown.
|
||||
* @param accountID the accountID of the protocol provider we'd like to get
|
||||
* @return a ServiceReference object to the protocol provider with the
|
||||
* specified account id and null if the account id is unknwon to the
|
||||
* account manager.
|
||||
*/
|
||||
public ServiceReference getProviderForAccount(AccountID accountID)
|
||||
{
|
||||
ServiceRegistration registration
|
||||
= (ServiceRegistration)registeredAccounts.get(accountID);
|
||||
|
||||
return (registration == null )
|
||||
? null
|
||||
: registration.getReference();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializaed and creates an accoung corresponding to the specified
|
||||
* accountProperties and registers the resulting ProtocolProvider in the
|
||||
* <code>context</code> BundleContext parameter.
|
||||
*
|
||||
* @param context the BundleContext parameter where the newly created
|
||||
* ProtocolProviderService would have to be registered.
|
||||
* @param accountIDStr the user identifier for the new account
|
||||
* @param accountProperties a set of protocol (or implementation)
|
||||
* specific properties defining the new account.
|
||||
* @return the AccountID of the newly created account
|
||||
*/
|
||||
public AccountID installAccount( BundleContext context,
|
||||
String accountIDStr,
|
||||
Map accountProperties)
|
||||
{
|
||||
if(context == null)
|
||||
throw new NullPointerException("The specified BundleContext was null");
|
||||
|
||||
if(accountIDStr == null)
|
||||
throw new NullPointerException("The specified AccountID was null");
|
||||
|
||||
if(accountIDStr == null)
|
||||
throw new NullPointerException("The specified property map was null");
|
||||
|
||||
AccountID accountID = new IcqAccountID(accountIDStr, accountProperties);
|
||||
|
||||
//make sure we haven't seen this account id before.
|
||||
if( registeredAccounts.containsKey(accountID) )
|
||||
throw new IllegalStateException(
|
||||
"An account for id " + accountIDStr + " was already installed!");
|
||||
|
||||
Hashtable properties = new Hashtable();
|
||||
properties.put(
|
||||
AccountManager.PROTOCOL_PROPERTY_NAME, ProtocolNames.ICQ);
|
||||
properties.put(
|
||||
AccountManager.ACCOUNT_ID_PROPERTY_NAME, accountIDStr);
|
||||
|
||||
ProtocolProviderServiceIcqImpl icqProtocolProvider
|
||||
= new ProtocolProviderServiceIcqImpl();
|
||||
|
||||
icqProtocolProvider.initialize(accountIDStr, accountProperties);
|
||||
|
||||
ServiceRegistration registration
|
||||
= context.registerService( ProtocolProviderService.class.getName(),
|
||||
icqProtocolProvider,
|
||||
properties);
|
||||
|
||||
registeredAccounts.put(accountID, registration);
|
||||
return accountID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified account from the list of accounts that this
|
||||
* account manager is handling. If the specified accountID is unknown to the
|
||||
* AccountManager, the call has no effect and false is returned. This method
|
||||
* is persistent in nature and once called the account corresponding to the
|
||||
* specified ID will not be loaded during future runs of the project.
|
||||
*
|
||||
* @param accountID the ID of the account to remove.
|
||||
* @return true if an account with the specified ID existed and was removed
|
||||
* and false otherwise.
|
||||
*/
|
||||
public boolean uninstallAccount(AccountID accountID)
|
||||
{
|
||||
ServiceRegistration registration
|
||||
= (ServiceRegistration)registeredAccounts.remove(accountID);
|
||||
|
||||
if(registration == null)
|
||||
return false;
|
||||
|
||||
//kill the service
|
||||
registration.unregister();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all previously installed accounts that were stored in the
|
||||
* configuration service. The method is only loading accounts the first
|
||||
* time it gets called.
|
||||
*
|
||||
* @param context the context where icq protocol providers shouold be
|
||||
* registered
|
||||
* @param configurationService ConfigurationService
|
||||
*/
|
||||
void loadStoredAccounts(BundleContext context,
|
||||
ConfigurationService configurationService)
|
||||
{
|
||||
/** @todo implement loadStoredAccounts() */
|
||||
//make sure we haven't already done so.
|
||||
//load all accounts stored in the configuration service
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package net.java.sip.communicator.impl.protocol.icq;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import java.util.Hashtable;
|
||||
import net.java.sip.communicator.service.configuration.*;
|
||||
|
||||
/**
|
||||
* Loads the ICQ account manager and registers it with service in the OSGI
|
||||
* bundle context.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class Activator
|
||||
implements BundleActivator
|
||||
{
|
||||
ServiceRegistration icqAccManRegistration = null;
|
||||
|
||||
/**
|
||||
* Called when this bundle is started so the Framework can perform the
|
||||
* bundle-specific activities necessary to start this bundle.
|
||||
*
|
||||
* @param context The execution context of the bundle being started.
|
||||
* @throws Exception If this method throws an exception, this bundle is
|
||||
* marked as stopped and the Framework will remove this bundle's
|
||||
* listeners, unregister all services registered by this bundle, and
|
||||
* release all services used by this bundle.
|
||||
*/
|
||||
public void start(BundleContext context) throws Exception
|
||||
{
|
||||
Hashtable hashtable = new Hashtable();
|
||||
hashtable.put(AccountManager.PROTOCOL_PROPERTY_NAME, "ICQ");
|
||||
|
||||
AccountManagerIcqImpl icqAccountManager =
|
||||
new AccountManagerIcqImpl();
|
||||
|
||||
ServiceReference confReference
|
||||
= context.getServiceReference(ConfigurationService.class.getName());
|
||||
ConfigurationService configurationService
|
||||
= (ConfigurationService)context.getService(confReference);
|
||||
|
||||
//load all icq providers
|
||||
icqAccountManager.loadStoredAccounts(context, configurationService);
|
||||
|
||||
//reg the icq account man.
|
||||
icqAccManRegistration = context.registerService(
|
||||
AccountManager.class.getName(),
|
||||
icqAccountManager,
|
||||
hashtable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this bundle is stopped so the Framework can perform the
|
||||
* bundle-specific activities necessary to stop the bundle.
|
||||
*
|
||||
* @param context The execution context of the bundle being stopped.
|
||||
* @throws Exception If this method throws an exception, the bundle is
|
||||
* still marked as stopped, and the Framework will remove the bundle's
|
||||
* listeners, unregister all services registered by the bundle, and
|
||||
* release all services used by the bundle.
|
||||
*/
|
||||
public void stop(BundleContext context) throws Exception
|
||||
{
|
||||
icqAccManRegistration.unregister();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,405 @@
|
||||
/*
|
||||
* 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.protocol.icq;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.kano.joustsim.oscar.oscar.service.ssi.*;
|
||||
import net.kano.joustsim.*;
|
||||
|
||||
/**
|
||||
* The ICQ implementation of the ContactGroup interface. Intances of this class
|
||||
* (contrary to <code>RootContactGroupIcqImpl</code>) may only contain buddies
|
||||
* and cannot have sub groups. Note that instances of this class only use the
|
||||
* corresponding joust sim source group for reading their names and only
|
||||
* initially fill their <code>buddies</code> <code>java.util.List</code> with
|
||||
* the ContactIcqImpl objects corresponding to those contained in the source
|
||||
* group at the moment it is being created. They would, however, never try to
|
||||
* sync or update their contents ulteriorly. This would have to be done through
|
||||
* the addContact()/removeContact() methods.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class ContactGroupIcqImpl
|
||||
extends AbstractContactGroupIcqImpl
|
||||
{
|
||||
private List buddies = new LinkedList();
|
||||
|
||||
/**
|
||||
* The JoustSIM Group corresponding to this contact group.
|
||||
*/
|
||||
private MutableGroup joustSimSourceGroup = null;
|
||||
|
||||
/**
|
||||
* a list that would always remain empty. We only use it so that we're able
|
||||
* to extract empty iterators
|
||||
*/
|
||||
private List dummyGroupsList = new LinkedList();
|
||||
|
||||
/**
|
||||
* A variable that we use as a means of detecting changes in the name
|
||||
* of this group.
|
||||
*/
|
||||
private String nameCopy = null;
|
||||
|
||||
/**
|
||||
* Creates an ICQ group using the specified <code>joustSimGroup</code> as
|
||||
* a source. The newly created group will always return the name of the
|
||||
* underlying joustSimGroup and would thus automatically adapt to changes.
|
||||
* It would, however, not receive or try to poll for modifications of the
|
||||
* buddies it contains and would therefore have to be updated manually by
|
||||
* ServerStoredContactListImpl.
|
||||
* <p>
|
||||
* Note that we MUST NOT use the list of buddies obtained through the
|
||||
* getBuddiesCopy() of the joustSimGroup arg as we'd later need to be able
|
||||
* to directly compare ( == ) instances of buddies we've stored and others
|
||||
* that are returned by the framework.
|
||||
* <p>
|
||||
* @param joustSimGroup the JoustSIM Group correspoinding to the group
|
||||
* @param groupMembers the group members that we should add to the group.
|
||||
*
|
||||
* we're creating.
|
||||
*/
|
||||
ContactGroupIcqImpl(MutableGroup joustSimGroup, List groupMembers)
|
||||
{
|
||||
this.joustSimSourceGroup = joustSimGroup;
|
||||
|
||||
//store a copy of the name now so that we can detect changes in the
|
||||
//name of the underlying joustSimSourceGroup
|
||||
initNameCopy();
|
||||
|
||||
//do not use the buddies in the joustSimGroup since we want to keep
|
||||
//their real addresses and we can only get a list of copies from the
|
||||
//group itself.
|
||||
|
||||
for (int i = 0; i < groupMembers.size(); i++)
|
||||
{
|
||||
addContact( new ContactIcqImpl((Buddy)groupMembers.get(i)) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of <code>Contact</code> members of this
|
||||
* <code>ContactGroup</code>
|
||||
*
|
||||
* @return an int indicating the number of <code>Contact</code>s,
|
||||
* members of this <code>ContactGroup</code>.
|
||||
*/
|
||||
public int countContacts()
|
||||
{
|
||||
return buddies.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified contact at the specified position.
|
||||
* @param contact the new contact to add to this group
|
||||
* @param index the position where the new contact should be added.
|
||||
*/
|
||||
void addContact(int index, ContactIcqImpl contact)
|
||||
{
|
||||
buddies.add(index, contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified contact to the end of this group.
|
||||
* @param contact the new contact to add to this group
|
||||
*/
|
||||
void addContact(ContactIcqImpl contact)
|
||||
{
|
||||
addContact(countContacts(), contact);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the specified contact from this contact group
|
||||
* @param contact the contact to remove.
|
||||
*/
|
||||
void removeContact(ContactIcqImpl contact)
|
||||
{
|
||||
removeContact(buddies.indexOf(contact));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the contact with the specified index.
|
||||
* @param index the index of the cntact to remove
|
||||
*/
|
||||
void removeContact(int index)
|
||||
{
|
||||
buddies.remove(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all buddies in this group and reinsterts them as specified
|
||||
* by the <code>newOrder</code> param. Contacts not contained in the
|
||||
* newOrder list are left at the end of this group.
|
||||
*
|
||||
* @param newOrder a list containing all contacts in the order that is
|
||||
* to be applied.
|
||||
*
|
||||
*/
|
||||
void reorderContacts(List newOrder)
|
||||
{
|
||||
buddies.removeAll(newOrder);
|
||||
buddies.addAll(0, newOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator over all contacts, member of this
|
||||
* <code>ContactGroup</code>.
|
||||
*
|
||||
* @return a java.util.Iterator over all contacts inside this
|
||||
* <code>ContactGroup</code>. In case the group doesn't contain any
|
||||
* memebers it will return an empty iterator.
|
||||
*/
|
||||
public Iterator contacts()
|
||||
{
|
||||
return buddies.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>Contact</code> with the specified index.
|
||||
*
|
||||
* @param index the index of the <code>Contact</code> to return.
|
||||
* @return the <code>Contact</code> with the specified index.
|
||||
*/
|
||||
public Contact getContact(int index)
|
||||
{
|
||||
return (ContactIcqImpl) buddies.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>Contact</code> with the specified address or
|
||||
* identifier.
|
||||
* @param id the addres or identifier of the <code>Contact</code> we are
|
||||
* looking for.
|
||||
* @return the <code>Contact</code> with the specified id or address.
|
||||
*/
|
||||
public Contact getContact(String id)
|
||||
{
|
||||
return this.findContact(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this group.
|
||||
* @return a String containing the name of this group.
|
||||
*/
|
||||
public String getGroupName()
|
||||
{
|
||||
return joustSimSourceGroup.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the group may contain subgroups or not.
|
||||
*
|
||||
* @return always false since only the root group may contain subgroups.
|
||||
*/
|
||||
public boolean canContainSubgroups()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subgroup with the specified index (i.e. always null since
|
||||
* this group may not contain subgroups).
|
||||
*
|
||||
* @param index the index of the <code>ContactGroup</code> to retrieve.
|
||||
* @return always null
|
||||
*/
|
||||
public ContactGroup getGroup(int index)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subgroup with the specified name.
|
||||
* @param groupName the name of the <code>ContactGroup</code> to retrieve.
|
||||
* @return the <code>ContactGroup</code> with the specified index.
|
||||
*/
|
||||
public ContactGroup getGroup(String groupName)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty iterator. Subgroups may only be present in the root
|
||||
* group.
|
||||
*
|
||||
* @return an empty iterator
|
||||
*/
|
||||
public Iterator subGroups()
|
||||
{
|
||||
return dummyGroupsList.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of subgroups contained by this group, which is
|
||||
* always 0 since sub groups in the icq protocol may only be contained
|
||||
* by the root group - <code>RootContactGroupIcqImpl</code>.
|
||||
* @return a 0 int.
|
||||
*/
|
||||
public int countSubGroups()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code value for the object, which is actually the hashcode
|
||||
* value of the groupname.
|
||||
*
|
||||
* @return a hash code value for this ContactGroup.
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return getGroupName().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JoustSIM group that this class is encapsulating.
|
||||
* @return the JoustSIM group corresponding to this SC group.
|
||||
*/
|
||||
MutableGroup getJoustSimSourceGroup()
|
||||
{
|
||||
return joustSimSourceGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this group. A group is
|
||||
* considered equal to another group if it hase the same sets of (equal)
|
||||
* contacts.
|
||||
* <p>
|
||||
*
|
||||
* @param obj the reference object with which to compare.
|
||||
* @return <code>true</code> if this object is the same as the obj
|
||||
* argument; <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if( obj == this )
|
||||
return true;
|
||||
|
||||
if (obj == null
|
||||
|| !(obj instanceof ContactGroupIcqImpl) )
|
||||
return false;
|
||||
|
||||
if(!((ContactGroup)obj).getGroupName().equals(getGroupName()))
|
||||
return false;
|
||||
|
||||
//since ICQ does not support having two groups with the same name
|
||||
// at this point we could bravely state that the groups are the same
|
||||
// and not bother to compare buddies. (gotta check that though)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this group, in the form
|
||||
* IcqGroup.GroupName[size]{ buddy1.toString(), buddy2.toString(), ...}.
|
||||
* @return a String representation of the object.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buff = new StringBuffer("IcqGroup.");
|
||||
buff.append(getGroupName());
|
||||
buff.append(", childContacts="+countContacts()+":[");
|
||||
|
||||
Iterator contacts = contacts();
|
||||
while (contacts.hasNext())
|
||||
{
|
||||
ContactIcqImpl contact = (ContactIcqImpl) contacts.next();
|
||||
buff.append(contact.toString());
|
||||
if(contacts.hasNext())
|
||||
buff.append(", ");
|
||||
}
|
||||
return buff.append("]").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icq contact encapsulating the specified joustSim buddy or null
|
||||
* if no such buddy was found.
|
||||
*
|
||||
* @param joustSimBuddy the buddy whose encapsulating contact we're looking
|
||||
* for.
|
||||
* @return the <code>ContactIcqImpl</code> corresponding to the specified
|
||||
* joustSimBuddy or null if no such contact was found.
|
||||
*/
|
||||
ContactIcqImpl findContact(Buddy joustSimBuddy)
|
||||
{
|
||||
Iterator contacts = contacts();
|
||||
while (contacts.hasNext())
|
||||
{
|
||||
ContactIcqImpl item = (ContactIcqImpl) contacts.next();
|
||||
if(item.getJoustSimBuddy() == joustSimBuddy)
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of icq contact encapsulating the specified joustSim
|
||||
* buddy or -1 if no such buddy was found.
|
||||
*
|
||||
* @param joustSimBuddy the buddy whose encapsulating contact's index we're
|
||||
* looking for.
|
||||
* @return the index of the contact corresponding to the specified
|
||||
* joustSimBuddy or null if no such contact was found.
|
||||
*/
|
||||
int findContactIndex(Buddy joustSimBuddy)
|
||||
{
|
||||
Iterator contacts = contacts();
|
||||
int i = 0;
|
||||
while (contacts.hasNext())
|
||||
{
|
||||
ContactIcqImpl item = (ContactIcqImpl) contacts.next();
|
||||
if(item.getJoustSimBuddy() == joustSimBuddy)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icq contact encapsulating with the spcieified screen name or
|
||||
* null if no such contact was found.
|
||||
*
|
||||
* @param screenName the screenName (or icq UIN) for the contact we're
|
||||
* looking for.
|
||||
* @return the <code>ContactIcqImpl</code> corresponding to the specified
|
||||
* screnname or null if no such contact existed.
|
||||
*/
|
||||
ContactIcqImpl findContact(String screenName)
|
||||
{
|
||||
Iterator contacts = contacts();
|
||||
while (contacts.hasNext())
|
||||
{
|
||||
ContactIcqImpl item = (ContactIcqImpl) contacts.next();
|
||||
if(item.getJoustSimBuddy().getScreenname()
|
||||
.equals(new Screenname(screenName)))
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name copy field that we use as a means of detecing changes in
|
||||
* the group name.
|
||||
*/
|
||||
void initNameCopy()
|
||||
{
|
||||
this.nameCopy = getGroupName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the group as it was at the last call of initNameCopy.
|
||||
* @return a String containing a copy of the name of this group as it was
|
||||
* last time when we called <code>initNameCopy</code>.
|
||||
*/
|
||||
String getNameCopy()
|
||||
{
|
||||
return this.nameCopy;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
package net.java.sip.communicator.impl.protocol.icq;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.kano.joscar.snaccmd.*;
|
||||
import net.kano.joustsim.oscar.oscar.service.ssi.*;
|
||||
import net.java.sip.communicator.service.protocol.icqconstants.*;
|
||||
|
||||
/**
|
||||
* The ICQ implementation of the service.protocol.Contact interface.
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class ContactIcqImpl
|
||||
implements Contact
|
||||
{
|
||||
Buddy joustSimBuddy = null;
|
||||
private boolean isLocal = false;
|
||||
private byte[] image = null;
|
||||
private PresenceStatus icqStatus = IcqStatusEnum.OFFLINE;
|
||||
|
||||
/**
|
||||
* Creates an IcqContactImpl
|
||||
* @param buddy the JoustSIM object that we will be encapsulating.
|
||||
* @param isLocal specifies whether this is the representation of the local
|
||||
* contact (i.e. the user we are using to sign on icq)
|
||||
*/
|
||||
ContactIcqImpl(Buddy buddy, boolean isLocal)
|
||||
{
|
||||
this.joustSimBuddy = buddy;
|
||||
this.isLocal = isLocal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IcqContactImpl for a non local contact
|
||||
* @param buddy FullUserInfo
|
||||
*/
|
||||
ContactIcqImpl(Buddy buddy)
|
||||
{
|
||||
this(buddy, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ICQ uin (or AIM screen name)of this contact
|
||||
* @return the ICQ uin (or AIM screen name)of this contact
|
||||
*/
|
||||
public String getUIN()
|
||||
{
|
||||
return joustSimBuddy.getScreenname().getFormatted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ICQ uin (or AIM screen name)of this contact
|
||||
* @return the ICQ uin (or AIM screen name)of this contact
|
||||
*/
|
||||
public String getAddress(){
|
||||
return getUIN();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this Contact instance represents the user used
|
||||
* by this protocol provider to connect to the service.
|
||||
*
|
||||
* @return true if this Contact represents us (the local user) and false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isLocal()
|
||||
{
|
||||
return isLocal;
|
||||
}
|
||||
|
||||
public byte[] getImage()
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashCode for this contact. The returned hashcode is actually
|
||||
* that of the Contact's UIN
|
||||
* @return the hashcode of this Contact
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return getUIN().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this one.
|
||||
* <p>
|
||||
*
|
||||
* @param obj the reference object with which to compare.
|
||||
* @return <code>true</code> if this object is the same as the obj
|
||||
* argument; <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null
|
||||
|| !(obj instanceof ContactIcqImpl)
|
||||
|| !((ContactIcqImpl)obj).getUIN().equals(getUIN()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the joust sim buddy that this Contact is encapsulating.
|
||||
* @return Buddy
|
||||
*/
|
||||
Buddy getJoustSimBuddy()
|
||||
{
|
||||
return joustSimBuddy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this contact, containing most of its
|
||||
* representative details.
|
||||
*
|
||||
* @return a string representation of this contact.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buff = new StringBuffer("IcqContact[ uin=");
|
||||
buff.append(getAddress()).append(", alias=")
|
||||
.append(getJoustSimBuddy().getAlias()).append("]");
|
||||
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status that this contact is currently in. The method is to
|
||||
* only be called as a result of a status update received from the AIM
|
||||
* server.
|
||||
*
|
||||
* @param status the IcqStatusEnum that this contact is currently in.
|
||||
*/
|
||||
void updatePresenceStatus(PresenceStatus status)
|
||||
{
|
||||
this.icqStatus = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the contact as per the last status update we've
|
||||
* received for it. Note that this method is not to perform any network
|
||||
* operations and will simply return the status received in the last
|
||||
* status update message. If you want a reliable way of retrieving someone's
|
||||
* status, you should use the <code>queryContactStatus()</code> method in
|
||||
* <code>OperationSetPresence</code>.
|
||||
* @return the PresenceStatus that we've received in the last status update
|
||||
* pertaining to this contact.
|
||||
*/
|
||||
public PresenceStatus getPresenceStatus()
|
||||
{
|
||||
return icqStatus;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package net.java.sip.communicator.impl.protocol.icq;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* The ICQ implementation of a sip-communicator AccountID
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class IcqAccountID
|
||||
extends AccountID
|
||||
{
|
||||
IcqAccountID(String accountID, Map accountProperties)
|
||||
{
|
||||
super(accountID, accountProperties);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* 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.protocol.icq;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.kano.joustsim.oscar.*;
|
||||
import net.kano.joustsim.*;
|
||||
import net.kano.joustsim.oscar.oscar.service.icbm.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* An implementation of the protocol provider service over the AIM/ICQ protocol
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class ProtocolProviderServiceIcqImpl
|
||||
implements ProtocolProviderService
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ProtocolProviderServiceIcqImpl.class);
|
||||
|
||||
/**
|
||||
* The hashtable with the operation sets that we support locally.
|
||||
*/
|
||||
private Hashtable supportedOperationSets = new Hashtable();
|
||||
|
||||
private DefaultAppSession session = null;
|
||||
|
||||
private AimSession aimSession = null;
|
||||
|
||||
private AimConnection aimConnection = null;
|
||||
|
||||
private IcbmService icbmService = null;
|
||||
|
||||
/**
|
||||
* Listener that catches all connection events originating from joscar
|
||||
* during connection to icq.
|
||||
*/
|
||||
private AimConnStateListener aimConnStateListener = null;
|
||||
|
||||
/**
|
||||
* Listener that catches all incoming and outgoing chat events generated
|
||||
* by joscar.
|
||||
*/
|
||||
private AimIcbmListener aimIcbmListener = null;
|
||||
|
||||
/**
|
||||
* indicates whether or not the provider is initialized and ready for use.
|
||||
*/
|
||||
private boolean isInitialized = false;
|
||||
private Object initializationLock = new Object();
|
||||
|
||||
/**
|
||||
* A list of all listeners registered for
|
||||
* <code>RegistrationStateChangeEvent</code>s.
|
||||
*/
|
||||
private List registrationListeners = new ArrayList();
|
||||
|
||||
/**
|
||||
* Returns the state of the registration of this protocol provider
|
||||
* @return the <code>RegistrationState</code> that this provider is
|
||||
* currently in or null in case it is in a unknown state.
|
||||
*/
|
||||
public RegistrationState getRegistrationState()
|
||||
{
|
||||
State connState = getAimConnection().getState();
|
||||
|
||||
return joustSimStateToRegistrationState(connState);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts the specified joust sim connection state to a corresponding
|
||||
* RegistrationState.
|
||||
* @param joustSimConnState the joust sim connection state.
|
||||
* @return a RegistrationState corresponding best to the specified
|
||||
* joustSimState.
|
||||
*/
|
||||
private RegistrationState joustSimStateToRegistrationState(
|
||||
State joustSimConnState)
|
||||
{
|
||||
if(joustSimConnState == State.ONLINE)
|
||||
return RegistrationState.REGISTERED;
|
||||
else if (joustSimConnState == State.CONNECTING)
|
||||
return RegistrationState.REGISTERING;
|
||||
else if( joustSimConnState == State.AUTHORIZING)
|
||||
return RegistrationState.AUTHENTICATING;
|
||||
else if (joustSimConnState == State.CONNECTINGAUTH)
|
||||
return RegistrationState.AUTHENTICATING;
|
||||
else if (joustSimConnState == State.SIGNINGON)
|
||||
return RegistrationState.REGISTERING;
|
||||
else if (joustSimConnState == State.DISCONNECTED
|
||||
|| joustSimConnState == State.NOTCONNECTED)
|
||||
return RegistrationState.UNREGISTERED;
|
||||
else if (joustSimConnState == State.FAILED)
|
||||
return RegistrationState.CONNECTION_FAILED;
|
||||
else{
|
||||
logger.warn("Unknown state " + joustSimConnState
|
||||
+ ". Defaulting to " + RegistrationState.UNREGISTERED);
|
||||
return RegistrationState.UNREGISTERED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the registration process. Connection details such as
|
||||
* registration server, user name/number are provided through the
|
||||
* configuration service through implementation specific properties.
|
||||
*
|
||||
* @param authority the security authority that will be used for resolving
|
||||
* any security challenges that may be returned during the
|
||||
* registration or at any moment while wer're registered.
|
||||
*
|
||||
*/
|
||||
public void register(SecurityAuthority authority)
|
||||
{
|
||||
aimConnection.connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the registration of this protocol provider with the service.
|
||||
*/
|
||||
public void unregister()
|
||||
{
|
||||
aimConnection.disconnect(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not this provider is signed on the icq service
|
||||
* @return true if the provider is currently signed on (and hence online)
|
||||
* and false otherwise.
|
||||
*/
|
||||
public boolean isRegistered()
|
||||
{
|
||||
return getRegistrationState().equals(RegistrationState.REGISTERED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the short name of the protocol that the implementation of this
|
||||
* provider is based upon (like SIP, Jabber, ICQ/AIM, or others for
|
||||
* example).
|
||||
*
|
||||
* @return a String containing the short name of the protocol this
|
||||
* service is taking care of.
|
||||
*/
|
||||
public String getProtocolName()
|
||||
{
|
||||
return ProtocolNames.ICQ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all operation sets supported by the
|
||||
* current implementation.
|
||||
*
|
||||
* @return an array of OperationSet-s supported by this protocol
|
||||
* provider implementation.
|
||||
*/
|
||||
public Map getSupportedOperationSets()
|
||||
{
|
||||
return supportedOperationSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialized the service implementation, and puts it in a sate where it
|
||||
* could interoperate with other services. It is strongly recomended that
|
||||
* properties in this Map be mapped to property names as specified by
|
||||
* <code>AccountProperties</code>.
|
||||
*
|
||||
* @param screenname the account id/uin/screenname of the account that we're
|
||||
* about to create
|
||||
* @param initializationProperties all properties needed fo initializing the
|
||||
* account.
|
||||
*
|
||||
* @see net.java.sip.communicator.service.protocol.AccountProperties
|
||||
*/
|
||||
protected void initialize(String screenname, Map initializationProperties)
|
||||
{
|
||||
synchronized(initializationLock)
|
||||
{
|
||||
//extract the necessary properties and validate them
|
||||
String password =
|
||||
(String)initializationProperties.get(AccountProperties.PASSWORD);
|
||||
|
||||
//init the necessary objects
|
||||
session = new DefaultAppSession();
|
||||
aimSession = session.openAimSession(new Screenname(screenname));
|
||||
aimConnection = aimSession.openConnection(
|
||||
new AimConnectionProperties(new Screenname(screenname),
|
||||
password));
|
||||
|
||||
aimConnStateListener = new AimConnStateListener();
|
||||
aimConnection.addStateListener(aimConnStateListener);
|
||||
aimIcbmListener = new AimIcbmListener();
|
||||
|
||||
//initialize all the supported operation sets
|
||||
OperationSetPersistentPresence persistentPresence =
|
||||
new OperationSetPersistentPresenceIcqImpl(this, screenname);
|
||||
|
||||
supportedOperationSets.put(
|
||||
OperationSetPersistentPresence.class.getName(),
|
||||
persistentPresence);
|
||||
|
||||
isInitialized = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the service implementation close all open sockets and release
|
||||
* any resources that it might have taken and prepare for
|
||||
* shutdown/garbage collection.
|
||||
*/
|
||||
public void shutdown()
|
||||
{
|
||||
/** @todo is there anything else to add here? */
|
||||
synchronized(initializationLock){
|
||||
icbmService = null;
|
||||
session = null;
|
||||
aimSession = null;
|
||||
aimConnection = null;
|
||||
aimConnStateListener = null;
|
||||
aimIcbmListener = null;
|
||||
isInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider service implementation is initialized and
|
||||
* ready for use by other services, and false otherwise.
|
||||
*
|
||||
* @return true if the provider is initialized and ready for use and false
|
||||
* otherwise
|
||||
*/
|
||||
public boolean isInitialized()
|
||||
{
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified registration state change listener so that it does
|
||||
* not receive any further notifications upon changes of the
|
||||
* RegistrationState of this provider.
|
||||
*
|
||||
* @param listener the listener to register for
|
||||
* <code>RegistrationStateChangeEvent</code>s.
|
||||
*/
|
||||
public void removeRegistrationStateChangeListener(
|
||||
RegistrationStateChangeListener listener)
|
||||
{
|
||||
registrationListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the specified listener with this provider so that it would
|
||||
* receive notifications on changes of its state or other properties such
|
||||
* as its local address and display name.
|
||||
*
|
||||
* @param listener the listener to register.
|
||||
*/
|
||||
public void addRegistrationStateChangeListener(RegistrationStateChangeListener listener)
|
||||
{
|
||||
registrationListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a RegistrationStateChange event corresponding to the specified
|
||||
* old and new joust sim states and notifies all currently registered
|
||||
* listeners.
|
||||
*
|
||||
* @param oldJoustSimState the state that the joust sim connection had
|
||||
* before the change occurred
|
||||
* @param newJoustSimState the state that the underlying joust sim
|
||||
* connection is currently in.
|
||||
*/
|
||||
private void fireRegistrationStateChanged( State oldJoustSimState,
|
||||
State newJoustSimState)
|
||||
{
|
||||
RegistrationState oldRegistrationState
|
||||
= joustSimStateToRegistrationState(oldJoustSimState);
|
||||
RegistrationState newRegistrationState
|
||||
= joustSimStateToRegistrationState(newJoustSimState);
|
||||
|
||||
RegistrationStateChangeEvent event =
|
||||
new RegistrationStateChangeEvent(
|
||||
this, oldRegistrationState, newRegistrationState);
|
||||
|
||||
logger.debug("Dispatching " + event + " to "
|
||||
+ registrationListeners.size()+ " listeners.");
|
||||
|
||||
for (int i = 0; i < registrationListeners.size(); i++)
|
||||
{
|
||||
RegistrationStateChangeListener listener
|
||||
= (RegistrationStateChangeListener)registrationListeners.get(i);
|
||||
listener.registrationStateChanged(event);
|
||||
}
|
||||
|
||||
logger.trace("Done.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This class handles connection state events that have originated in this
|
||||
* provider's aim connection. Events are acted upon accordingly and,
|
||||
* if necessary, forwarded to registered listeners (asynchronously).
|
||||
*/
|
||||
private class AimConnStateListener implements StateListener
|
||||
{
|
||||
public void handleStateChange(StateEvent event)
|
||||
{
|
||||
State newState = event.getNewState();
|
||||
State oldState = event.getOldState();
|
||||
|
||||
AimConnection conn = event.getAimConnection();
|
||||
logger.debug("ICQ protocol provider " + getProtocolName()
|
||||
+ "changed registration status from "
|
||||
+ oldState + " to " + newState);
|
||||
|
||||
if (newState == State.ONLINE)
|
||||
{
|
||||
icbmService = conn.getIcbmService();
|
||||
icbmService.addIcbmListener(aimIcbmListener);
|
||||
}
|
||||
else if (newState == State.DISCONNECTED
|
||||
|| newState == State.FAILED)
|
||||
{
|
||||
logger.debug("The aim Connection was disconnected!");
|
||||
}
|
||||
|
||||
//now tell all interested parties about what happened.
|
||||
fireRegistrationStateChanged(oldState, newState);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>AimSession</code> opened by this provider.
|
||||
* @return a reference to the <code>AimSession</code> that this provider
|
||||
* last opened.
|
||||
*/
|
||||
protected AimSession getAimSession()
|
||||
{
|
||||
return aimSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>AimConnection</code>opened by this provider
|
||||
* @return a reference to the <code>AimConnection</code> last opened by this provider.
|
||||
*/
|
||||
protected AimConnection getAimConnection()
|
||||
{
|
||||
return aimConnection;
|
||||
}
|
||||
|
||||
public class AimIcbmListener implements IcbmListener
|
||||
{
|
||||
|
||||
public void newConversation(IcbmService service, Conversation conv)
|
||||
{
|
||||
System.out.println("Received a new conversation event");
|
||||
conv.addConversationListener(new AimConversationListener());
|
||||
}
|
||||
|
||||
public void buddyInfoUpdated(IcbmService service, Screenname buddy,
|
||||
IcbmBuddyInfo info)
|
||||
{
|
||||
System.out.println("Got a BuddINFO event");
|
||||
}
|
||||
}
|
||||
|
||||
public class AimConversationListener implements ConversationListener{
|
||||
public void sentOtherEvent(Conversation conversation,
|
||||
ConversationEventInfo event)
|
||||
{
|
||||
System.out.println("reveived ConversationEventInfo:" + event);
|
||||
}
|
||||
|
||||
// This may be called without ever calling conversationOpened
|
||||
public void conversationClosed(Conversation c)
|
||||
{
|
||||
System.out.println("conversation closed");
|
||||
}
|
||||
|
||||
public void gotOtherEvent(Conversation conversation,
|
||||
ConversationEventInfo event)
|
||||
{
|
||||
System.out.println("goet other event");
|
||||
if(event instanceof TypingInfo)
|
||||
{
|
||||
TypingInfo ti = (TypingInfo)event;
|
||||
System.out.println("got typing info and state is: " + ti.getTypingState());
|
||||
}
|
||||
else if (event instanceof MessageInfo)
|
||||
{
|
||||
MessageInfo ti = (MessageInfo)event;
|
||||
System.out.println("got message info for msg: " + ti.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void canSendMessageChanged(Conversation c, boolean canSend)
|
||||
{
|
||||
System.out.println("can send message event");
|
||||
}
|
||||
|
||||
// This may never be called
|
||||
public void conversationOpened(Conversation c)
|
||||
{
|
||||
System.out.println("conversation opened event");
|
||||
}
|
||||
|
||||
// This may be called after conversationClosed is called
|
||||
public void sentMessage(Conversation c, MessageInfo minfo)
|
||||
{
|
||||
System.out.println("sent message event");
|
||||
}
|
||||
|
||||
// This may be called after conversationClosed is called.
|
||||
public void gotMessage(Conversation c, MessageInfo minfo)
|
||||
{
|
||||
System.out.println("got message event" + minfo.getMessage().getMessageBody());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,222 @@
|
||||
package net.java.sip.communicator.impl.protocol.icq;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* A dummy ContactGroup implementation representing the ContactList root for
|
||||
* ICQ contact lists.
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class RootContactGroupIcqImpl
|
||||
extends AbstractContactGroupIcqImpl
|
||||
{
|
||||
private String ROOT_CONTACT_GROUP_NAME = "ContactListRoot";
|
||||
private List subGroups = new LinkedList();
|
||||
|
||||
/**
|
||||
* An empty list that we use when returning an iterator.
|
||||
*/
|
||||
private List dummyContacts = new LinkedList();
|
||||
|
||||
|
||||
/**
|
||||
* The ContactListRoot in ICQ is the only group that can contain subgroups.
|
||||
*
|
||||
* @return true (always)
|
||||
*/
|
||||
public boolean canContainSubgroups()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this group which is always
|
||||
* <code>ROOT_CONTACT_GROUP_NAME</code>.
|
||||
*
|
||||
* @return a String containing the name of this group.
|
||||
*/
|
||||
public String getGroupName()
|
||||
{
|
||||
return ROOT_CONTACT_GROUP_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified group at the specified position in the list of sub
|
||||
* groups.
|
||||
*
|
||||
* @param index the position at which the specified group should be added.
|
||||
* @param group the ContactGroup to add
|
||||
*/
|
||||
void addSubGroup(int index, ContactGroupIcqImpl group)
|
||||
{
|
||||
subGroups.add(index, group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified group to the end of the list of sub groups.
|
||||
* @param group the group to add.
|
||||
*/
|
||||
void addSubGroup(ContactGroupIcqImpl group)
|
||||
{
|
||||
addSubGroup(countContacts(), group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified from the list of sub groups
|
||||
* @param group the group to remove.
|
||||
*/
|
||||
void removeSubGroup(ContactGroupIcqImpl group)
|
||||
{
|
||||
removeSubGroup(subGroups.indexOf(group));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the sub group with the specified index.
|
||||
* @param index the index of the group to remove
|
||||
*/
|
||||
void removeSubGroup(int index)
|
||||
{
|
||||
subGroups.remove(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all contact sub groups and reinsterts them as specified
|
||||
* by the <code>newOrder</code> param. Contact groups not contained in the
|
||||
* newOrder list are left at the end of this group.
|
||||
*
|
||||
* @param newOrder a list containing all contact groups in the order that is
|
||||
* to be applied.
|
||||
*
|
||||
*/
|
||||
void reorderSubGroups(List newOrder)
|
||||
{
|
||||
subGroups.removeAll(newOrder);
|
||||
subGroups.addAll(0, newOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of subgroups contained by this
|
||||
* <code>RootContactGroupIcqImpl</code>.
|
||||
*
|
||||
* @return an int indicating the number of subgroups that this
|
||||
* ContactGroup contains.
|
||||
*/
|
||||
public int countSubGroups()
|
||||
{
|
||||
return subGroups.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subgroup with the specified index.
|
||||
*
|
||||
* @param index the index of the <code>ContactGroup</code> to retrieve.
|
||||
* @return the <code>ContactGroup</code> with the specified index.
|
||||
*/
|
||||
public ContactGroup getGroup(int index)
|
||||
{
|
||||
return (ContactGroupIcqImpl)subGroups.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subgroup with the specified name.
|
||||
* @param groupName the name of the <code>ContactGroup</code> to retrieve.
|
||||
* @return the <code>ContactGroup</code> with the specified index.
|
||||
*/
|
||||
public ContactGroup getGroup(String groupName)
|
||||
{
|
||||
Iterator subgroups = subGroups();
|
||||
while (subgroups.hasNext())
|
||||
{
|
||||
ContactGroupIcqImpl grp = (ContactGroupIcqImpl)subgroups.next();
|
||||
|
||||
if (grp.getGroupName().equals(groupName))
|
||||
return grp;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>Contact</code> with the specified address or
|
||||
* identifier.
|
||||
* @param id the addres or identifier of the <code>Contact</code> we are
|
||||
* looking for.
|
||||
* @return the <code>Contact</code> with the specified id or address.
|
||||
*/
|
||||
public Contact getContact(String id)
|
||||
{
|
||||
//no contacts in the root group for this icq impl.
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the sub groups that this
|
||||
* <code>ContactGroup</code> contains.
|
||||
*
|
||||
* @return a java.util.Iterator over the <code>ContactGroup</code>
|
||||
* children of this group (i.e. subgroups).
|
||||
*/
|
||||
public Iterator subGroups()
|
||||
{
|
||||
return subGroups.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number, which is always 0, of <code>Contact</code> members
|
||||
* of this <code>ContactGroup</code>
|
||||
* @return an int indicating the number of <code>Contact</code>s, members
|
||||
* of this <code>ContactGroup</code>.
|
||||
*/
|
||||
public int countContacts()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator over all contacts, member of this
|
||||
* <code>ContactGroup</code>.
|
||||
* @return a java.util.Iterator over all contacts inside this
|
||||
* <code>ContactGroup</code>
|
||||
*/
|
||||
public Iterator contacts()
|
||||
{
|
||||
return dummyContacts.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* A dummy impl of the corresponding interface method - always returns null.
|
||||
*
|
||||
* @param index the index of the <code>Contact</code> to return.
|
||||
* @return the <code>Contact</code> with the specified index, i.e. always
|
||||
* null.
|
||||
*/
|
||||
public Contact getContact(int index)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the root contact group that contains
|
||||
* all subgroups and subcontacts of this group.
|
||||
*
|
||||
* @return a string representation of this root contact group.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buff = new StringBuffer(getGroupName());
|
||||
buff.append(".subGroups="+countSubGroups()+":\n");
|
||||
|
||||
Iterator subGroups = subGroups();
|
||||
while (subGroups.hasNext())
|
||||
{
|
||||
ContactGroup group = (ContactGroup) subGroups.next();
|
||||
buff.append(group.toString());
|
||||
if(subGroups.hasNext())
|
||||
buff.append("\n");
|
||||
}
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,884 @@
|
||||
|
||||
/*
|
||||
* 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.protocol.icq;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.kano.joustsim.oscar.oscar.service.ssi.*;
|
||||
import java.util.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import net.kano.joustsim.Screenname;
|
||||
import net.kano.joscar.snaccmd.ssi.SsiItem;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.kano.joscar.ssiitem.*;
|
||||
import net.kano.joustsim.oscar.*;
|
||||
|
||||
/**
|
||||
* This class encapsulates the net.kano BuddyList class. Once created, it will
|
||||
* register itself as a listener to the encapsulated BuddyList and modify it's
|
||||
* local copy of Contacts and ContactGroups every time an event is generated
|
||||
* by the underlying joustsim framework. The class would also generate
|
||||
* corresponding sip-communicator events to all events coming from joustsim.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class ServerStoredContactListIcqImpl
|
||||
implements BuddyInfoTrackerListener
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ServerStoredContactListIcqImpl.class);
|
||||
/**
|
||||
* The joustsim buddy list that we encapsulate
|
||||
*/
|
||||
private MutableBuddyList buddyList = null;
|
||||
|
||||
/**
|
||||
* Our joustsim buddy list event listener
|
||||
*/
|
||||
private BuddyListListener buddyListListener = new BuddyListListener();
|
||||
|
||||
/**
|
||||
* Our joustsim group change listener.
|
||||
*/
|
||||
private GroupChangeListener jsimGroupChangeListener
|
||||
= new GroupChangeListener();
|
||||
|
||||
/**
|
||||
* A joust sim item change listener.
|
||||
*/
|
||||
private JoustSimItemChangeListener jsimItemChangeListener
|
||||
= new JoustSimItemChangeListener();
|
||||
|
||||
/**
|
||||
* Our joustsim buddy change listener.
|
||||
*/
|
||||
private JoustSimBuddyListener jsimBuddyListener
|
||||
= new JoustSimBuddyListener();
|
||||
|
||||
/**
|
||||
* The root contagroup. The container for all ICQ buddies and groups.
|
||||
*/
|
||||
private RootContactGroupIcqImpl rootGroup
|
||||
= new RootContactGroupIcqImpl();
|
||||
|
||||
/**
|
||||
* Listeners that others registered with us for contact list events.
|
||||
*/
|
||||
private Vector contactListListeners = new Vector();
|
||||
|
||||
/**
|
||||
* The joust sim service that deals with server stored information.
|
||||
*/
|
||||
private SsiService jSimSsiService = null;
|
||||
|
||||
/**
|
||||
* The operation set that created us and that we could use when dispatching
|
||||
* subscription events.
|
||||
*/
|
||||
private OperationSetPersistentPresenceIcqImpl parentOperationSet = null;
|
||||
|
||||
/**
|
||||
* The icqProvider that is on top of us.
|
||||
*/
|
||||
private ProtocolProviderServiceIcqImpl icqProvider = null;
|
||||
|
||||
/**
|
||||
* Listeners that would receive event notifications for changes in group
|
||||
* names or other properties, removal or creation of groups.
|
||||
*/
|
||||
private Vector serverStoredGroupListeners = new Vector();
|
||||
|
||||
/**
|
||||
* Creates a ServerStoredContactList wrapper for the specified BuddyList.
|
||||
*/
|
||||
ServerStoredContactListIcqImpl()
|
||||
{
|
||||
//don't add the sub ICQ groups to rootGroup here as we'll be having
|
||||
//event notifications for every one of them through the
|
||||
//RetroactiveBuddyListListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root group of the contact list.
|
||||
*
|
||||
* @return the root ContactGroup for the ContactList
|
||||
*/
|
||||
public ContactGroup getRootGroup()
|
||||
{
|
||||
return rootGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the specified group listener so that it would receive events
|
||||
* on group modification/creation/destruction.
|
||||
* @param l the ServerStoredGroupListener to register for group events
|
||||
*/
|
||||
void addGroupListener(ServerStoredGroupListener l)
|
||||
{
|
||||
synchronized(serverStoredGroupListeners){
|
||||
this.serverStoredGroupListeners.add(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified group listener so that it won't receive further
|
||||
* events on group modification/creation/destruction.
|
||||
* @param l the ServerStoredGroupListener to unregister
|
||||
*/
|
||||
void removeGroupListener(ServerStoredGroupListener l)
|
||||
{
|
||||
synchronized(serverStoredGroupListeners){
|
||||
this.serverStoredGroupListeners.remove(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the corresponding event and notifies all
|
||||
* <code>ServerStoredGroupListener</code>s that the source group has been
|
||||
* removed, changed, renamed or whatever happened to it.
|
||||
* @param group the ContactGroup that has been created/modified/removed
|
||||
* @param eventID the id of the event to generate.
|
||||
*/
|
||||
private void fireGroupEvent(ContactGroupIcqImpl group, int eventID)
|
||||
{
|
||||
ServerStoredGroupEvent evt = new ServerStoredGroupEvent(group, eventID,
|
||||
icqProvider, parentOperationSet);
|
||||
|
||||
logger.trace("Will dispatch the following grp event: " + evt);
|
||||
|
||||
synchronized (serverStoredGroupListeners){
|
||||
Iterator listeners = this.serverStoredGroupListeners.iterator();
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
ServerStoredGroupListener l
|
||||
= (ServerStoredGroupListener) listeners.next();
|
||||
if (eventID == ServerStoredGroupEvent.GROUP_REMOVED_EVENT)
|
||||
l.groupRemoved(evt);
|
||||
else if (eventID == ServerStoredGroupEvent.GROUP_RENAMED_EVENT)
|
||||
l.groupNameChanged(evt);
|
||||
else if (eventID == ServerStoredGroupEvent.GROUP_CREATED_EVENT)
|
||||
l.groupCreated(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fireGroupsReordered()
|
||||
{
|
||||
/** @todo implement fireGroupsReordered *///no need of args since it
|
||||
//could only mean one thing
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the parent persistent presence operation set dispatch a contact
|
||||
* added event.
|
||||
* @param parentGroup the group where the new contact was added
|
||||
* @param contact the contact that was added
|
||||
* @param index the index at which it was added.
|
||||
*/
|
||||
private void fireContactAdded( ContactGroupIcqImpl parentGroup,
|
||||
ContactIcqImpl contact,
|
||||
int index)
|
||||
{
|
||||
//bail out if no one's listening
|
||||
if(parentOperationSet == null){
|
||||
logger.debug("No presence op. set available. Bailing out.");
|
||||
return;
|
||||
}
|
||||
|
||||
//dispatch
|
||||
parentOperationSet.fireSubscriptionEvent(
|
||||
SubscriptionEvent.SUBSCRIPTION_CREATED, contact, parentGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the parent persistent presence operation set dispatch a contact
|
||||
* removed event.
|
||||
* @param parentGroup the group where that the removed contact belonged to.
|
||||
* @param contact the contact that was removed.
|
||||
*/
|
||||
private void fireContactRemoved( ContactGroupIcqImpl parentGroup,
|
||||
ContactIcqImpl contact)
|
||||
{
|
||||
//bail out if no one's listening
|
||||
if(parentOperationSet == null){
|
||||
logger.debug("No presence op. set available. Bailing out.");
|
||||
return;
|
||||
}
|
||||
|
||||
//dispatch
|
||||
parentOperationSet.fireSubscriptionEvent(
|
||||
SubscriptionEvent.SUBSCRIPTION_CREATED, contact, parentGroup);
|
||||
}
|
||||
|
||||
private void fireContactsReordered( ContactGroupIcqImpl parentGroup)
|
||||
{
|
||||
/** @todo implement fireContactsReordered() */
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the ContactGroup containing the specified joust sim
|
||||
* group.
|
||||
* @param joustSimGroup the joust sim group we're looking for.
|
||||
* @return the index of the ContactGroup containing the specified
|
||||
* joustSimGroup or -1 if no containing ContactGroup exists.
|
||||
*/
|
||||
public int findContactGroupIndex(Group joustSimGroup)
|
||||
{
|
||||
Iterator contactGroups = rootGroup.subGroups();
|
||||
int index = 0;
|
||||
|
||||
for (; contactGroups.hasNext(); index++)
|
||||
{
|
||||
ContactGroupIcqImpl contactGroup
|
||||
= (ContactGroupIcqImpl) contactGroups.next();
|
||||
|
||||
if (joustSimGroup == contactGroup.getJoustSimSourceGroup())
|
||||
return index;
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ContactGroup corresponding to the specified joust sim group.
|
||||
* @param joustSimGroup the joust sim group we're looking for.
|
||||
* @return the ContactGroup corresponding to the specified joustSimGroup
|
||||
* null if no containing ContactGroup exists.
|
||||
*/
|
||||
public ContactGroupIcqImpl findContactGroup(Group joustSimGroup)
|
||||
{
|
||||
Iterator contactGroups = rootGroup.subGroups();
|
||||
|
||||
while(contactGroups.hasNext())
|
||||
{
|
||||
ContactGroupIcqImpl contactGroup
|
||||
= (ContactGroupIcqImpl) contactGroups.next();
|
||||
|
||||
if (joustSimGroup == contactGroup.getJoustSimSourceGroup())
|
||||
return contactGroup;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Contact with the specified screenname (or icq UIN) or null if
|
||||
* no such screenname was found.
|
||||
*
|
||||
* @param screenName the screen name (or ICQ UIN) of the contact to find.
|
||||
* @return the <code>Contact</code> carrying the specified
|
||||
* <code>screenName</code> or <code>null</code> if no such contact exits.
|
||||
*/
|
||||
public ContactIcqImpl findContactByScreenName(String screenName)
|
||||
{
|
||||
Iterator contactGroups = rootGroup.subGroups();
|
||||
ContactIcqImpl result = null;
|
||||
|
||||
while(contactGroups.hasNext())
|
||||
{
|
||||
ContactGroupIcqImpl contactGroup
|
||||
= (ContactGroupIcqImpl) contactGroups.next();
|
||||
|
||||
result = contactGroup.findContact(screenName);
|
||||
|
||||
if (result != null)
|
||||
return result;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the ContactGroup containing the specified contact or null
|
||||
* if no such group or contact exist.
|
||||
*
|
||||
* @param child the contact whose parent group we're looking for.
|
||||
* @return the <code>ContactGroup</code> containing the specified
|
||||
* <code>contact</code> or <code>null</code> if no such groupo or contact
|
||||
* exist.
|
||||
*/
|
||||
public ContactGroupIcqImpl findContactGroup(ContactIcqImpl child)
|
||||
{
|
||||
Iterator contactGroups = rootGroup.subGroups();
|
||||
|
||||
while(contactGroups.hasNext())
|
||||
{
|
||||
ContactGroupIcqImpl contactGroup
|
||||
= (ContactGroupIcqImpl) contactGroups.next();
|
||||
|
||||
if( contactGroup.findContact(child.getJoustSimBuddy())!= null)
|
||||
return contactGroup;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new contact with the specified screenname to the list under a
|
||||
* default location.
|
||||
* @param screenname the screenname or icq uin of the contact to add.
|
||||
*/
|
||||
public void addContact(String screenname)
|
||||
{
|
||||
ContactGroupIcqImpl parent =
|
||||
(ContactGroupIcqImpl)getRootGroup().getGroup(0);
|
||||
|
||||
addContact(parent, screenname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new contact with the specified screenname to the list under the
|
||||
* specified group.
|
||||
* @param screenname the screenname or icq uin of the contact to add.
|
||||
* @param parent the group under which we want the new contact placed.
|
||||
*/
|
||||
public void addContact(ContactGroupIcqImpl parent, String screenname)
|
||||
{
|
||||
logger.trace("Addint contact " + screenname
|
||||
+ " to parent=" + parent.getGroupName());
|
||||
|
||||
//if the contact is already in the contact list, only broadcast an event
|
||||
final ContactIcqImpl existingContact
|
||||
= findContactByScreenName(screenname);
|
||||
|
||||
//if the contact already exists - just issue an event.
|
||||
if( existingContact != null)
|
||||
{
|
||||
logger.debug("Contact " + screenname + " already exists. Gen. evt.");
|
||||
//broadcast the event in a separate thread so that we don't
|
||||
//block the calling thread.
|
||||
new Thread(){
|
||||
public void run(){
|
||||
parentOperationSet.fireSubscriptionEvent(
|
||||
SubscriptionEvent.SUBSCRIPTION_CREATED,
|
||||
existingContact,
|
||||
findContactGroup(existingContact));
|
||||
}
|
||||
}.start();
|
||||
return;
|
||||
}
|
||||
|
||||
logger.trace("Adding the contact to the specified group.");
|
||||
//extract the top level group
|
||||
AddMutableGroup group = parent.getJoustSimSourceGroup();
|
||||
|
||||
group.addBuddy(screenname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the specified group on the server stored contact list.
|
||||
* @param groupName a String containing the name of the new group.
|
||||
*/
|
||||
public void createGroup(String groupName)
|
||||
{
|
||||
logger.trace("Creating group: " + groupName);
|
||||
buddyList.addGroup(groupName);
|
||||
logger.trace("Group " +groupName+ " created.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified group from the icq buddy list.
|
||||
* @param groupToRemove the group that we'd like removed.
|
||||
*/
|
||||
public void removeGroup(ContactGroupIcqImpl groupToRemove)
|
||||
{
|
||||
buddyList.deleteGroupAndBuddies(
|
||||
groupToRemove.getJoustSimSourceGroup());
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the specified group according to the specified new name..
|
||||
* @param groupToRename the group that we'd like removed.
|
||||
* @param newName the new name of the group
|
||||
*/
|
||||
public void renameGroup(ContactGroupIcqImpl groupToRename, String newName)
|
||||
{
|
||||
groupToRename.getJoustSimSourceGroup().rename(newName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Moves the specified <code>contact</code> to the group indicated by
|
||||
* <code>newParent</code>.
|
||||
* @param contact the contact that we'd like moved under the new group.
|
||||
* @param newParent the group where we'd like the parent placed.
|
||||
*/
|
||||
public void moveContact(ContactIcqImpl contact,
|
||||
ContactGroupIcqImpl newParent)
|
||||
{
|
||||
List contactsToMove = new ArrayList();
|
||||
contactsToMove.add(contact);
|
||||
|
||||
buddyList.moveBuddies(contactsToMove,
|
||||
newParent.getJoustSimSourceGroup());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a reference to the currently active and valid instance of
|
||||
* the JoustSIM SsiService that this list is to use for retrieving
|
||||
* server stored information
|
||||
* @param joustSimSsiService a valid reference to the currently active JoustSIM
|
||||
* SsiService.
|
||||
* @param parentOperationSet the operation set that created us and that
|
||||
* we could use for dispatching subscription events
|
||||
* @param icqProvider the icqProvider that has instantiated us.
|
||||
*/
|
||||
void init( SsiService joustSimSsiService,
|
||||
OperationSetPersistentPresenceIcqImpl parentOperationSet,
|
||||
ProtocolProviderServiceIcqImpl icqProvider)
|
||||
{
|
||||
this.jSimSsiService = joustSimSsiService;
|
||||
jSimSsiService.addItemChangeListener(jsimItemChangeListener);
|
||||
|
||||
this.buddyList = jSimSsiService.getBuddyList();
|
||||
buddyList.addRetroactiveLayoutListener(buddyListListener);
|
||||
|
||||
this.parentOperationSet = parentOperationSet;
|
||||
|
||||
this.icqProvider = icqProvider;
|
||||
|
||||
}
|
||||
|
||||
private class BuddyListListener
|
||||
implements BuddyListLayoutListener
|
||||
{
|
||||
/**
|
||||
* Called by joustsim as a notification of the fact that the server has
|
||||
* sent the specified group and that it is actually a member from
|
||||
* our contact list. We copy the group locally and generate the
|
||||
* corresponding sip-communicator events
|
||||
*
|
||||
* @param list the BuddyList where this is happening.
|
||||
* @param oldItems we don't use it
|
||||
* @param newItems we don't use it
|
||||
* @param group the new Group that has been added
|
||||
* @param buddies the members of the new group.
|
||||
*/
|
||||
public void groupAdded(BuddyList list, List oldItems, List newItems,
|
||||
Group group, List buddies)
|
||||
{
|
||||
logger.trace("Group added: " + group.getName());
|
||||
logger.trace("Buddies: " + buddies);
|
||||
ContactGroupIcqImpl newGroup
|
||||
= new ContactGroupIcqImpl((MutableGroup)group, buddies);
|
||||
|
||||
//add a joust sim buddy listener to all of the buddies in this group
|
||||
for(int i = 0; i < buddies.size(); i++)
|
||||
((Buddy)buddies.get(i)).addBuddyListener(jsimBuddyListener);
|
||||
|
||||
|
||||
//elements in the newItems list may include groups that have not
|
||||
//yet been reported through this method. In order to make sure that
|
||||
//we keep the order specified by the server, we try to add after a
|
||||
//newItems member that has a corresponding ContactGroup entry in our
|
||||
//contact list, and add the new entry after it
|
||||
int groupIndex = newItems.indexOf(group);
|
||||
|
||||
assert groupIndex != -1:group + " was not present in newItems"
|
||||
+ newItems;
|
||||
int insertPos = 0;
|
||||
if (groupIndex == 0)
|
||||
{
|
||||
//this is the first group so insert at 0.
|
||||
rootGroup.addSubGroup(insertPos, newGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; groupIndex >= 0; groupIndex--)
|
||||
{
|
||||
int prevContactGroupIndex
|
||||
= findContactGroupIndex( (Group) newItems.get(groupIndex));
|
||||
|
||||
//if we've found the nearest previous group that we already
|
||||
//know of we should insert the new group behind it.
|
||||
if (prevContactGroupIndex != -1)
|
||||
insertPos = prevContactGroupIndex + 1;
|
||||
}
|
||||
rootGroup.addSubGroup(insertPos, newGroup);
|
||||
}
|
||||
|
||||
//register a listener for name changes of this group
|
||||
group.addGroupListener(jsimGroupChangeListener);
|
||||
|
||||
//tell listeners about the added group
|
||||
fireGroupEvent(newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by joust sim when a group is removed.
|
||||
*
|
||||
* @param list the <code>BuddyList</code> owning the removed group.
|
||||
* @param oldItems the list of items as it was before removing the group.
|
||||
* @param newItems the list of items as it is after the group is removed.
|
||||
* @param group the group that was removed.
|
||||
*/
|
||||
public void groupRemoved(BuddyList list, List oldItems, List newItems,
|
||||
Group group)
|
||||
{
|
||||
logger.trace("Group Removed: " + group.getName());
|
||||
int index = findContactGroupIndex(group);
|
||||
ContactGroupIcqImpl removedGroup
|
||||
= (ContactGroupIcqImpl) rootGroup.getGroup(index);
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
logger.debug("non existing group: " + group.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
group.removeGroupListener(jsimGroupChangeListener);
|
||||
|
||||
rootGroup.removeSubGroup(index);
|
||||
|
||||
fireGroupEvent(removedGroup,
|
||||
ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by joust sim to notify us that a new buddy has been added
|
||||
* to the contact list.
|
||||
*
|
||||
* @param list the <code>BuddyList</code> owning the newly added buddy.
|
||||
* @param joustSimGroup the parent group of the added buddy.
|
||||
* @param oldItems unused
|
||||
* @param newItems unused
|
||||
* @param buddy the newly added <code>buddy</code>
|
||||
*/
|
||||
public void buddyAdded(BuddyList list, Group joustSimGroup, List oldItems,
|
||||
List newItems, Buddy buddy)
|
||||
{
|
||||
ContactIcqImpl newContact
|
||||
= new ContactIcqImpl(buddy);
|
||||
ContactGroupIcqImpl parentGroup = findContactGroup(joustSimGroup);
|
||||
|
||||
if (parentGroup == null)
|
||||
{
|
||||
logger.debug("no parent group "
|
||||
+ joustSimGroup + " found for buddy: " + buddy);
|
||||
return;
|
||||
}
|
||||
|
||||
int buddyIndex = newItems.indexOf(buddy);
|
||||
if( buddyIndex == -1 ){
|
||||
logger.debug(buddy+" was not present in newItems"+newItems);
|
||||
}
|
||||
|
||||
//elements in the newItems list may include buddies that have not
|
||||
//yet been reported through this method. In order to make sure that
|
||||
//we keep the order specified by the server, we try to add after a
|
||||
//newItems member that has a corresponding ContactGroup entry in our
|
||||
//contact list, and add the new entry after it
|
||||
|
||||
int insertPos = 0;
|
||||
if (buddyIndex == 0)
|
||||
{
|
||||
//this is the first group so insert at 0.
|
||||
parentGroup.addContact(insertPos, newContact);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; buddyIndex >= 0; buddyIndex--)
|
||||
{
|
||||
|
||||
int prevContactIndex = parentGroup.findContactIndex(
|
||||
(Buddy) newItems.get(buddyIndex));
|
||||
|
||||
//if we've found the nearest previous group that we already
|
||||
//know of we should insert the new group behind it.
|
||||
if (prevContactIndex != -1)
|
||||
insertPos = prevContactIndex + 1;
|
||||
}
|
||||
parentGroup.addContact(insertPos, newContact);
|
||||
}
|
||||
|
||||
//register a listener for name changes of this buddy
|
||||
buddy.addBuddyListener(jsimBuddyListener);
|
||||
|
||||
//tell listeners about the added group
|
||||
fireContactAdded(parentGroup, newContact, insertPos);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
b * Called by joust sim when a buddy is removed
|
||||
*
|
||||
* @param list the <code>BuddyList</code> containing the buddy
|
||||
* @param group the joust sim group that the buddy is removed from.
|
||||
* @param oldItems unused
|
||||
* @param newItems unused
|
||||
* @param buddy Buddy
|
||||
*/
|
||||
public void buddyRemoved(BuddyList list, Group group, List oldItems,
|
||||
List newItems, Buddy buddy)
|
||||
{
|
||||
ContactGroupIcqImpl parentGroup = findContactGroup(group);
|
||||
ContactIcqImpl contactToRemove = parentGroup.findContact(buddy);
|
||||
|
||||
parentGroup.removeContact(contactToRemove);
|
||||
|
||||
buddy.removeBuddyListener(jsimBuddyListener);
|
||||
|
||||
fireContactRemoved(parentGroup, contactToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by joust sim when contacts in a group have been reordered.
|
||||
* Removes all Contacts from the concerned group and reinserts them
|
||||
* in the right order.
|
||||
*
|
||||
* @param list the <code>BuddyList</code> where all this happens
|
||||
* @param group the group whose buddies have been reordered.
|
||||
* @param oldBuddies unused
|
||||
* @param newBuddies the list containing the buddies in their new order.
|
||||
*/
|
||||
public void buddiesReordered(BuddyList list, Group group,
|
||||
List oldBuddies, List newBuddies)
|
||||
{
|
||||
ContactGroupIcqImpl contactGroup = findContactGroup(group);
|
||||
|
||||
if (contactGroup == null)
|
||||
{
|
||||
logger.debug(
|
||||
"buddies reordered event received for unknown group"
|
||||
+ group);
|
||||
}
|
||||
|
||||
List reorderedContacts = new ArrayList();
|
||||
Iterator newBuddiesIter = newBuddies.iterator();
|
||||
while (newBuddiesIter.hasNext())
|
||||
{
|
||||
Buddy buddy = (Buddy) newBuddiesIter.next();
|
||||
ContactIcqImpl contact = contactGroup.findContact(buddy);
|
||||
|
||||
//make sure that this was not an empty buddy.
|
||||
if (contact == null)
|
||||
continue;
|
||||
reorderedContacts.add(contact);
|
||||
}
|
||||
|
||||
contactGroup.reorderContacts(reorderedContacts);
|
||||
|
||||
fireContactsReordered(contactGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by joust sim to indicate that the server stored groups
|
||||
* have been reordered. We filter this list for contact groups that
|
||||
* we've already heard of and pass it to the root contact group
|
||||
* so that it woul reorder its subgroups.
|
||||
*
|
||||
* @param list the <code>BuddyList</code> where all this is happening
|
||||
* @param oldOrder unused
|
||||
* @param newOrder the order in which groups are now stored by the
|
||||
* AIM/ICQ server.
|
||||
*/
|
||||
public void groupsReordered(BuddyList list, List oldOrder,
|
||||
List newOrder)
|
||||
{
|
||||
List reorderedGroups = new ArrayList();
|
||||
Iterator newOrderIter = newOrder.iterator();
|
||||
while (newOrderIter.hasNext())
|
||||
{
|
||||
Group group = (Group) newOrderIter.next();
|
||||
ContactGroupIcqImpl contactGroup = findContactGroup(group);
|
||||
|
||||
//make sure that this was not an empty buddy.
|
||||
if (contactGroup == null)
|
||||
continue;
|
||||
reorderedGroups.add(contactGroup);
|
||||
}
|
||||
|
||||
rootGroup.reorderSubGroups(reorderedGroups);
|
||||
|
||||
fireGroupsReordered();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxies events notifying of a change in the group name.
|
||||
*/
|
||||
private class GroupChangeListener
|
||||
implements GroupListener
|
||||
{
|
||||
/**
|
||||
* Verifies whether the concerned group really exists and fires
|
||||
* a corresponding event
|
||||
* @param group the group that changed name.
|
||||
* @param oldName the name, before it changed
|
||||
* @param newName the current name of the group.
|
||||
*/
|
||||
public void groupNameChanged(Group group, String oldName,
|
||||
String newName)
|
||||
{
|
||||
logger.trace("Group name for "+group.getName()+"changed from="
|
||||
+ oldName + " to=" + newName);
|
||||
ContactGroupIcqImpl contactGroup = findContactGroup(group);
|
||||
|
||||
if (contactGroup == null)
|
||||
{
|
||||
logger.debug(
|
||||
"group name changed event received for unknown group"
|
||||
+ group);
|
||||
}
|
||||
|
||||
//check whether the name has really changed (the joust sim stack
|
||||
//would call this method even when the name has not really changed
|
||||
//and values of oldName and newName would almost always be null)
|
||||
if (contactGroup.getGroupName()
|
||||
.equals( contactGroup.getNameCopy() )){
|
||||
logger.trace("Group name hasn't really changed("
|
||||
+contactGroup.getGroupName()+"). Ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
//we do have a new name. store a copy of it for our next deteciton
|
||||
//and fire the corresponding event.
|
||||
logger.trace("Dispatching group change event.");
|
||||
contactGroup.initNameCopy();
|
||||
|
||||
fireGroupEvent(contactGroup,
|
||||
ServerStoredGroupEvent.GROUP_RENAMED_EVENT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class JoustSimBuddyListener implements BuddyListener
|
||||
{
|
||||
/**
|
||||
* screennameChanged
|
||||
*
|
||||
* @param buddy Buddy
|
||||
* @param oldScreenname Screenname
|
||||
* @param newScreenname Screenname
|
||||
*/
|
||||
public void screennameChanged(Buddy buddy, Screenname oldScreenname,
|
||||
Screenname newScreenname)
|
||||
{
|
||||
/** @todo implement screennameChanged() */
|
||||
logger.debug("/** @todo implement screennameChanged() */=");
|
||||
logger.debug("buddy="+buddy);
|
||||
System.out.println("oldScreenname=" + oldScreenname);
|
||||
System.out.println("newScreenname=" + newScreenname);
|
||||
}
|
||||
|
||||
/**
|
||||
* alertActionChanged
|
||||
*
|
||||
* @param buddy Buddy
|
||||
* @param oldAlertAction int
|
||||
* @param newAlertAction int
|
||||
*/
|
||||
public void alertActionChanged(Buddy buddy, int oldAlertAction,
|
||||
int newAlertAction)
|
||||
{
|
||||
/** @todo implement alertActionChanged() */
|
||||
logger.debug("/** @todo implement alertActionChanged() */=");
|
||||
System.out.println("buddy=" + buddy);
|
||||
System.out.println("oldAlertAction=" + oldAlertAction);
|
||||
System.out.println("newAlertAction=" + newAlertAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* alertSoundChanged
|
||||
*
|
||||
* @param buddy Buddy
|
||||
* @param oldAlertSound String
|
||||
* @param newAlertSound String
|
||||
*/
|
||||
public void alertSoundChanged(Buddy buddy, String oldAlertSound,
|
||||
String newAlertSound)
|
||||
{
|
||||
/** @todo implement alertSoundChanged() */
|
||||
logger.debug("/** @todo implement alertSoundChanged() */");
|
||||
System.out.println("buddy=" + buddy);
|
||||
System.out.println("oldAlertSound=" + oldAlertSound);
|
||||
System.out.println("newAlertSound=" + newAlertSound);
|
||||
}
|
||||
|
||||
/**
|
||||
* alertTimeChanged
|
||||
*
|
||||
* @param buddy Buddy
|
||||
* @param oldAlertEvent int
|
||||
* @param newAlertEvent int
|
||||
*/
|
||||
public void alertTimeChanged(Buddy buddy, int oldAlertEvent,
|
||||
int newAlertEvent)
|
||||
{
|
||||
/** @todo implement alertTimeChanged() */
|
||||
logger.debug("/** @todo implement alertTimeChanged() */");
|
||||
System.out.println("buddy=" + buddy);
|
||||
System.out.println("oldAlertEvent=" + oldAlertEvent);
|
||||
System.out.println("newAlertEvent=" + newAlertEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* aliasChanged
|
||||
*
|
||||
* @param buddy Buddy
|
||||
* @param oldAlias String
|
||||
* @param newAlias String
|
||||
*/
|
||||
public void aliasChanged(Buddy buddy, String oldAlias, String newAlias)
|
||||
{
|
||||
/** @todo implement aliasChanged() */
|
||||
logger.debug("/** @todo implement aliasChanged() */");
|
||||
System.out.println("buddy=" + buddy);
|
||||
System.out.println("oldAlias=" + oldAlias);
|
||||
System.out.println("newAlias=" + newAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* buddyCommentChanged
|
||||
*
|
||||
* @param buddy Buddy
|
||||
* @param oldComment String
|
||||
* @param newComment String
|
||||
*/
|
||||
public void buddyCommentChanged(Buddy buddy, String oldComment,
|
||||
String newComment)
|
||||
{
|
||||
/** @todo implement buddyCommentChanged() */
|
||||
logger.debug("/** @todo implement buddyCommentChanged() */");
|
||||
System.out.println("buddy=" + buddy);
|
||||
System.out.println("oldComment=" + oldComment);
|
||||
System.out.println("newComment=" + newComment);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A dummy implementation of the JoustSIM SsiItemChangeListener.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
private class JoustSimItemChangeListener implements SsiItemChangeListener
|
||||
{
|
||||
public void handleItemCreated(SsiItem item)
|
||||
{
|
||||
/** @todo implement handleItemCreated() */
|
||||
logger.debug("!!! TODO: implement handleItemCreated() !!!" + item
|
||||
+ " DATA=" + item.getData().toString());
|
||||
}
|
||||
|
||||
public void handleItemDeleted(SsiItem item)
|
||||
{
|
||||
/** @todo implement handleItemDeleted() */
|
||||
logger.debug("!!! TODO: implement handleItemDeleted()!!!" + item);
|
||||
}
|
||||
|
||||
public void handleItemModified(SsiItem item)
|
||||
{
|
||||
/** @todo implement handleItemModified() */
|
||||
logger.debug("!!! TODO: implement handleItemModified() !!!" + item
|
||||
+ " DATA=" + item.getData().toString());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
Bundle-Activator: net.java.sip.communicator.impl.protocol.icq.Activator
|
||||
Bundle-Name: ICQ Protocol Provider Implementation
|
||||
Bundle-Description: An ICQ/AIM implementation of the Protocol Provider Service.
|
||||
Bundle-Vendor: sip-communicator.org
|
||||
Bundle-Version: 0.0.1
|
||||
Import-Package: org.osgi.framework,
|
||||
net.java.sip.communicator.service.configuration,
|
||||
net.java.sip.communicator.util,
|
||||
net.java.sip.communicator.service.configuration.event,
|
||||
Export-Package: net.java.sip.communicator.service.protocol,
|
||||
net.java.sip.communicator.service.protocol.icqconstants,
|
||||
net.java.sip.communicator.service.protocol.event
|
||||
Loading…
Reference in new issue