aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip
diff options
context:
space:
mode:
authorVincent Lucas <chenzo@jitsi.org>2008-05-26 14:11:33 +0000
committerVincent Lucas <chenzo@jitsi.org>2008-05-26 14:11:33 +0000
commit137cf4192707221c9a39b839c2ea26bc48a4856e (patch)
treeb4e28903f9c6ec31bf9f9acf886328bb9d6d86be /src/net/java/sip
parentf126eda471f403003cd672b8625556bef9ef8228 (diff)
downloadjitsi-137cf4192707221c9a39b839c2ea26bc48a4856e.zip
jitsi-137cf4192707221c9a39b839c2ea26bc48a4856e.tar.gz
jitsi-137cf4192707221c9a39b839c2ea26bc48a4856e.tar.bz2
Adding DICT protocol and wizard.
Diffstat (limited to 'src/net/java/sip')
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/ContactDictImpl.java322
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/ContactGroupDictImpl.java588
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictAccountID.java33
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictActivator.java108
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictAdapter.java605
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictException.java287
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictRegistry.java64
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictResult.java97
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictResultset.java107
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/DictStatusEnum.java104
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/MessageDictImpl.java138
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/OperationSetBasicInstantMessagingDictImpl.java421
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/OperationSetDirectoryDictImpl.java58
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/OperationSetPersistentPresenceDictImpl.java1298
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/ProtocolIconDictImpl.java98
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderFactoryDictImpl.java318
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderServiceDictImpl.java451
-rw-r--r--src/net/java/sip/communicator/impl/protocol/dict/dict.provider.manifest.mf13
-rw-r--r--src/net/java/sip/communicator/impl/version/NightlyBuildID.java2
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccRegWizzActivator.java136
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccountRegistration.java123
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccountRegistrationWizard.java409
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/DictAdapter.java183
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/FirstWizardPage.java672
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/Resources.java116
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/StrategyThread.java207
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/dictaccregwizz.manifest.mf31
-rw-r--r--src/net/java/sip/communicator/plugin/dictaccregwizz/resources.properties2
28 files changed, 6990 insertions, 1 deletions
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/ContactDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/ContactDictImpl.java
new file mode 100644
index 0000000..0d9cc2b
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/ContactDictImpl.java
@@ -0,0 +1,322 @@
+/*
+ * 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.dict;
+
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * An implementation of a Dict contact
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class ContactDictImpl
+ implements Contact
+{
+ /**
+ * The id of the contact.
+ */
+ private String contactID = null;
+
+ /**
+ * The provider that created us.
+ */
+ private ProtocolProviderServiceDictImpl parentProvider = null;
+
+ /**
+ * The group that belong to.
+ */
+ private ContactGroupDictImpl parentGroup = null;
+
+ /**
+ * The presence status of the contact.
+ */
+ private PresenceStatus presenceStatus = DictStatusEnum.ONLINE;
+
+ /**
+ * Determines whether this contact is persistent, i.e. member of the contact
+ * list or whether it is here only temporarily.
+ */
+ private boolean isPersistent = true;
+
+ /**
+ * Determines whether the contact has been resolved (i.e. we have a
+ * confirmation that it is still on the server contact list).
+ */
+ private boolean isResolved = true;
+
+ /**
+ * Socket connection associated with the contact
+ */
+ private DictAdapter dictAdapter = null;
+
+ /**
+ * Creates an instance of a meta contact with the specified string used
+ * as a name and identifier.
+ *
+ * @param id the identifier of this contact (also used as a name).
+ * @param parentProvider the provider that created us.
+ */
+ public ContactDictImpl(
+ String databaseCode,
+ ProtocolProviderServiceDictImpl parentProvider)
+ {
+ this.contactID = databaseCode;
+ this.parentProvider = parentProvider;
+ }
+
+ /**
+ * This method is only called when the contact is added to a new
+ * <tt>ContactGroupDictImpl</tt> by the
+ * <tt>ContactGroupDictImpl</tt> itself.
+ *
+ * @param newParentGroup the <tt>ContactGroupDictImpl</tt> that is now
+ * parent of this <tt>ContactDictImpl</tt>
+ */
+ void setParentGroup(ContactGroupDictImpl newParentGroup)
+ {
+ this.parentGroup = newParentGroup;
+ }
+
+ /**
+ * Returns a String that can be used for identifying the contact.
+ *
+ * @return a String id representing and uniquely identifying the contact.
+ */
+ public String getContactID()
+ {
+ return contactID;
+ }
+
+ /**
+ * Returns a String that can be used for identifying the contact.
+ *
+ * @return a String id representing and uniquely identifying the contact.
+ */
+ public String getAddress()
+ {
+ return contactID;
+ }
+
+ /**
+ * Returns a String that could be used by any user interacting modules
+ * for referring to this contact.
+ *
+ * @return a String that can be used for referring to this contact when
+ * interacting with the user.
+ */
+ public String getDisplayName()
+ {
+ return contactID;
+ }
+
+ /**
+ * Returns a byte array containing an image (most often a photo or an
+ * avatar) that the contact uses as a representation.
+ *
+ * @return byte[] an image representing the contact.
+ */
+ public byte[] getImage()
+ {
+ return null;
+ }
+
+ /**
+ * Returns the status of the contact.
+ *
+ * @return always DictStatusEnum.ONLINE.
+ */
+ public PresenceStatus getPresenceStatus()
+ {
+ return this.presenceStatus;
+ }
+
+ /**
+ * Sets <tt>dictPresenceStatus</tt> as the PresenceStatus that this
+ * contact is currently in.
+ * @param dictPresenceStatus the <tt>DictPresenceStatus</tt>
+ * currently valid for this contact.
+ */
+ public void setPresenceStatus(PresenceStatus dictPresenceStatus)
+ {
+ this.presenceStatus = dictPresenceStatus;
+ }
+
+ /**
+ * Returns a reference to the protocol provider that created the contact.
+ *
+ * @return a refererence to an instance of the ProtocolProviderService
+ */
+ public ProtocolProviderService getProtocolProvider()
+ {
+ return parentProvider;
+ }
+
+ /**
+ * Return a reference to the socket connexion linked with the Account
+ * @return a reference to the socket connexion (DictAdapter)
+ */
+ public DictAdapter getDictAdapter()
+ {
+ return parentProvider.getDictAdapter();
+ }
+
+ /**
+ * Determines whether or not this contact represents our own identity.
+ *
+ * @return true in case this is a contact that represents ourselves and
+ * false otherwise.
+ */
+ public boolean isLocal()
+ {
+ return false;
+ }
+
+ /**
+ * Returns the group that contains this contact.
+ * @return a reference to the <tt>ContactGroupDictImpl</tt> that
+ * contains this contact.
+ */
+ public ContactGroup getParentContactGroup()
+ {
+ return this.parentGroup;
+ }
+
+ /**
+ * 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("ContactDictImpl[ DisplayName=")
+ .append(getDisplayName()).append("]");
+
+ return buff.toString();
+ }
+
+ /**
+ * Determines whether or not this contact is being stored by the server.
+ * Non persistent contacts are common in the case of simple, non-persistent
+ * presence operation sets. They could however also be seen in persistent
+ * presence operation sets when for example we have received an event
+ * from someone not on our contact list. Non persistent contacts are
+ * volatile even when coming from a persistent presence op. set. They would
+ * only exist until the application is closed and will not be there next
+ * time it is loaded.
+ *
+ * @return true if the contact is persistent and false otherwise.
+ */
+ public boolean isPersistent()
+ {
+ return isPersistent;
+ }
+
+ /**
+ * Specifies whether or not this contact is being stored by the server.
+ * Non persistent contacts are common in the case of simple, non-persistent
+ * presence operation sets. They could however also be seen in persistent
+ * presence operation sets when for example we have received an event
+ * from someone not on our contact list. Non persistent contacts are
+ * volatile even when coming from a persistent presence op. set. They would
+ * only exist until the application is closed and will not be there next
+ * time it is loaded.
+ *
+ * @param isPersistent true if the contact is persistent and false
+ * otherwise.
+ */
+ public void setPersistent(boolean isPersistent)
+ {
+ this.isPersistent = isPersistent;
+ }
+
+
+ /**
+ * Returns null as no persistent data is required and the contact address is
+ * sufficient for restoring the contact.
+ * <p>
+ * @return null as no such data is needed.
+ */
+ public String getPersistentData()
+ {
+ return null;
+ }
+
+ /**
+ * Determines whether or not this contact has been resolved against the
+ * server. Unresolved contacts are used when initially loading a contact
+ * list that has been stored in a local file until the presence operation
+ * set has managed to retrieve all the contact list from the server and has
+ * properly mapped contacts to their on-line buddies.
+ *
+ * @return true if the contact has been resolved (mapped against a buddy)
+ * and false otherwise.
+ */
+ public boolean isResolved()
+ {
+ return isResolved;
+ }
+
+ /**
+ * Return the current status message of this contact.
+ *
+ * @return null as the protocol has currently no support of status messages
+ */
+ public String getStatusMessage()
+ {
+ return null;
+ }
+
+ /**
+ * Makes the contact resolved or unresolved.
+ *
+ * @param resolved true to make the contact resolved; false to
+ * make it unresolved
+ */
+ public void setResolved(boolean resolved)
+ {
+ this.isResolved = resolved;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one which in terms
+ * of contacts translates to having equal ids. The resolved status of the
+ * contacts deliberately ignored so that contacts would be declared equal
+ * even if it differs.
+ * <p>
+ * @param obj the reference object with which to compare.
+ * @return <code>true</code> if this contact has the same id as that of the
+ * <code>obj</code> argument.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == null || ! (obj instanceof ContactDictImpl)) {
+ return false;
+ }
+
+ ContactDictImpl dictContact = (ContactDictImpl) obj;
+
+ return this.getAddress().equals(dictContact.getAddress());
+ }
+
+
+ /**
+ * Returns the persistent presence operation set that this contact belongs
+ * to.
+ *
+ * @return the <tt>OperationSetPersistentPresenceGibberishImpl</tt> that
+ * this contact belongs to.
+ */
+ public OperationSetPersistentPresenceDictImpl
+ getParentPresenceOperationSet()
+ {
+ return (OperationSetPersistentPresenceDictImpl) parentProvider
+ .getOperationSet(OperationSetPersistentPresence.class);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/ContactGroupDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/ContactGroupDictImpl.java
new file mode 100644
index 0000000..2c706f8
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/ContactGroupDictImpl.java
@@ -0,0 +1,588 @@
+/*
+ * 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.dict;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * A simple, straightforward implementation of a dict ContactGroup. Since
+ * the Dict protocol is not a real one, we simply store all group details
+ * in class fields. You should know that when implementing a real protocol,
+ * the contact group implementation would rather encapsulate group objects from
+ * the protocol stack and group property values should be returned by consulting
+ * the encapsulated object.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class ContactGroupDictImpl
+ implements ContactGroup
+{
+
+ /**
+ * The name of this Dict contact group.
+ */
+ private String groupName = null;
+
+ /**
+ * The list of this group's members.
+ */
+ private Vector contacts = new Vector();
+
+ /**
+ * The list of sub groups belonging to this group.
+ */
+ private Vector subGroups = new Vector();
+
+ /**
+ * The group that this group belongs to (or null if this is the root group).
+ */
+ private ContactGroupDictImpl parentGroup = null;
+
+ /**
+ * Determines whether this group is really in the contact list or whether
+ * it is here only temporarily and will be gone next time we restart.
+ */
+ private boolean isPersistent = true;
+
+ /**
+ * The protocol provider that created us.
+ */
+ private ProtocolProviderServiceDictImpl parentProvider = null;
+
+ /**
+ * Determines whether this group has been resolved on the server.
+ * Unresolved groups are groups that were available on previous runs and
+ * that the meta contact list has stored. During all next runs, when
+ * bootstrapping, the meta contact list would create these groups as
+ * unresolved. Once a protocol provider implementation confirms that the
+ * groups are still on the server, it would issue an event indicating that
+ * the groups are now resolved.
+ */
+ private boolean isResolved = true;
+
+ /**
+ * An id uniquely identifying the group. For many protocols this could be
+ * the group name itself.
+ */
+ private String uid = null;
+ private static final String UID_SUFFIX = ".uid";
+
+ /**
+ * Creates a ContactGroupDictImpl with the specified name.
+ *
+ * @param groupName the name of the group.
+ * @param parentProvider the protocol provider that created this group.
+ */
+ public ContactGroupDictImpl(
+ String groupName,
+ ProtocolProviderServiceDictImpl parentProvider)
+ {
+ this.groupName = groupName;
+ this.uid = groupName + UID_SUFFIX;
+ this.parentProvider = parentProvider;
+ }
+
+ /**
+ * Determines whether the group may contain subgroups or not.
+ *
+ * @return always true in this implementation.
+ */
+ public boolean canContainSubgroups()
+ {
+ return true;
+ }
+
+ /**
+ * Returns the protocol provider that this group belongs to.
+ * @return a regerence to the ProtocolProviderService instance that this
+ * ContactGroup belongs to.
+ */
+ public ProtocolProviderService getProtocolProvider()
+ {
+ return parentProvider;
+ }
+
+ /**
+ * Returns an Iterator over all contacts, member of this
+ * <tt>ContactGroup</tt>.
+ *
+ * @return a java.util.Iterator over all contacts inside this
+ * <tt>ContactGroup</tt>
+ */
+ public Iterator contacts()
+ {
+ return contacts.iterator();
+ }
+
+ /**
+ * Adds the specified contact to this group.
+ * @param contactToAdd the ContactDictImpl to add to this group.
+ */
+ public void addContact(ContactDictImpl contactToAdd)
+ {
+ this.contacts.add(contactToAdd);
+ contactToAdd.setParentGroup(this);
+ }
+
+ /**
+ * Returns the number of <tt>Contact</tt> members of this
+ * <tt>ContactGroup</tt>
+ *
+ * @return an int indicating the number of <tt>Contact</tt>s, members of
+ * this <tt>ContactGroup</tt>.
+ */
+ public int countContacts()
+ {
+ return contacts.size();
+ }
+
+ /**
+ * Returns the number of subgroups contained by this
+ * <tt>ContactGroup</tt>.
+ *
+ * @return the number of subGroups currently added to this group.
+ */
+ public int countSubgroups()
+ {
+ return subGroups.size();
+ }
+
+ /**
+ * Adds the specified contact group to the contained by this group.
+ * @param subgroup the ContactGroupDictImpl to add as a subgroup to this group.
+ */
+ public void addSubgroup(ContactGroupDictImpl subgroup)
+ {
+ this.subGroups.add(subgroup);
+ subgroup.setParentGroup(this);
+ }
+
+ /**
+ * Sets the group that is the new parent of this group
+ * @param parent ContactGroupDictImpl
+ */
+ void setParentGroup(ContactGroupDictImpl parent)
+ {
+ this.parentGroup = parent;
+ }
+
+ /**
+ * Returns the contact group that currently contains this group or null if
+ * this is the root contact group.
+ * @return the contact group that currently contains this group or null if
+ * this is the root contact group.
+ */
+ public ContactGroup getParentContactGroup()
+ {
+ return this.parentGroup;
+ }
+
+ /**
+ * Removes the specified contact group from the this group's subgroups.
+ * @param subgroup the ContactGroupDictImpl subgroup to remove.
+ */
+ public void removeSubGroup(ContactGroupDictImpl subgroup)
+ {
+ this.subGroups.remove(subgroup);
+ subgroup.setParentGroup(null);
+ }
+
+
+ /**
+ * Returns the <tt>Contact</tt> with the specified index.
+ *
+ * @param index the index of the <tt>Contact</tt> to return.
+ * @return the <tt>Contact</tt> with the specified index.
+ */
+ public Contact getContact(int index)
+ {
+ return (ContactDictImpl)contacts.get(index);
+ }
+
+ /**
+ * Returns the group that is parent of the specified dictGroup or null
+ * if no parent was found.
+ * @param dictGroup the group whose parent we're looking for.
+ * @return the ContactGroupDictImpl instance that dictGroup
+ * belongs to or null if no parent was found.
+ */
+ public ContactGroupDictImpl findGroupParent(
+ ContactGroupDictImpl dictGroup)
+ {
+ if ( subGroups.contains(dictGroup) )
+ return this;
+
+ Iterator subGroupsIter = subgroups();
+ while (subGroupsIter.hasNext())
+ {
+ ContactGroupDictImpl subgroup
+ = (ContactGroupDictImpl) subGroupsIter.next();
+
+ ContactGroupDictImpl parent
+ = subgroup.findGroupParent(dictGroup);
+
+ if(parent != null)
+ return parent;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the group that is parent of the specified dictContact or
+ * null if no parent was found.
+ *
+ * @param dictContact the contact whose parent we're looking for.
+ * @return the ContactGroupDictImpl instance that dictContact
+ * belongs to or <tt>null</tt> if no parent was found.
+ */
+ public ContactGroupDictImpl findContactParent(
+ ContactDictImpl dictContact)
+ {
+ if ( contacts.contains(dictContact) )
+ return this;
+
+ Iterator subGroupsIter = subgroups();
+ while (subGroupsIter.hasNext())
+ {
+ ContactGroupDictImpl subgroup
+ = (ContactGroupDictImpl) subGroupsIter.next();
+
+ ContactGroupDictImpl parent
+ = subgroup.findContactParent(dictContact);
+
+ if(parent != null)
+ return parent;
+ }
+ return null;
+ }
+
+
+
+ /**
+ * Returns the <tt>Contact</tt> with the specified address or identifier.
+ *
+ * @param id the addres or identifier of the <tt>Contact</tt> we are
+ * looking for.
+ * @return the <tt>Contact</tt> with the specified id or address.
+ */
+ public Contact getContact(String id)
+ {
+ Iterator contactsIter = contacts();
+ while (contactsIter.hasNext())
+ {
+ ContactDictImpl contact = (ContactDictImpl) contactsIter.next();
+ if (contact.getAddress().equals(id))
+ return contact;
+
+ }
+ return null;
+ }
+
+ /**
+ * Returns the subgroup with the specified index.
+ *
+ * @param index the index of the <tt>ContactGroup</tt> to retrieve.
+ * @return the <tt>ContactGroup</tt> with the specified index.
+ */
+ public ContactGroup getGroup(int index)
+ {
+ return (ContactGroup)subGroups.get(index);
+ }
+
+ /**
+ * Returns the subgroup with the specified name.
+ *
+ * @param groupName the name of the <tt>ContactGroup</tt> to retrieve.
+ * @return the <tt>ContactGroup</tt> with the specified index.
+ */
+ public ContactGroup getGroup(String groupName)
+ {
+ Iterator groupsIter = subgroups();
+ while (groupsIter.hasNext())
+ {
+ ContactGroupDictImpl contactGroup
+ = (ContactGroupDictImpl) groupsIter.next();
+ if (contactGroup.getGroupName().equals(groupName))
+ return contactGroup;
+
+ }
+ return null;
+
+ }
+
+ /**
+ * Returns the name of this group.
+ *
+ * @return a String containing the name of this group.
+ */
+ public String getGroupName()
+ {
+ return this.groupName;
+ }
+
+ /**
+ * Sets this group a new name.
+ * @param newGrpName a String containing the new name of this group.
+ */
+ public void setGroupName(String newGrpName)
+ {
+ this.groupName = newGrpName;
+ }
+
+ /**
+ * Returns an iterator over the sub groups that this
+ * <tt>ContactGroup</tt> contains.
+ *
+ * @return a java.util.Iterator over the <tt>ContactGroup</tt> children
+ * of this group (i.e. subgroups).
+ */
+ public Iterator subgroups()
+ {
+ return subGroups.iterator();
+ }
+
+ /**
+ * Removes the specified contact from this group.
+ * @param contact the ContactDictImpl to remove from this group
+ */
+ public void removeContact(ContactDictImpl contact)
+ {
+ this.contacts.remove(contact);
+ }
+
+ /**
+ * Returns the contact with the specified id or null if no such contact
+ * exists.
+ * @param id the id of the contact we're looking for.
+ * @return ContactDictImpl
+ */
+ public ContactDictImpl findContactByID(String id)
+ {
+ //first go through the contacts that are direct children.
+ Iterator contactsIter = contacts();
+
+ while(contactsIter.hasNext())
+ {
+ ContactDictImpl mContact = (ContactDictImpl)contactsIter.next();
+
+ if( mContact.getAddress().equals(id) )
+ return mContact;
+ }
+
+ //if we didn't find it here, let's try in the subougroups
+ Iterator groupsIter = subgroups();
+
+ while( groupsIter.hasNext() )
+ {
+ ContactGroupDictImpl mGroup = (ContactGroupDictImpl)groupsIter.next();
+
+ ContactDictImpl mContact = mGroup.findContactByID(id);
+
+ if (mContact != null)
+ return mContact;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Returns a String representation of this group and the contacts it
+ * contains (may turn out to be a relatively long string).
+ * @return a String representing this group and its child contacts.
+ */
+ public String toString()
+ {
+
+ StringBuffer buff = new StringBuffer(getGroupName());
+ buff.append(".subGroups=" + countSubgroups() + ":\n");
+
+ Iterator subGroups = subgroups();
+ while (subGroups.hasNext())
+ {
+ ContactGroupDictImpl group = (ContactGroupDictImpl)subGroups.next();
+ buff.append(group.toString());
+ if (subGroups.hasNext())
+ buff.append("\n");
+ }
+
+ buff.append("\nChildContacts="+countContacts()+":[");
+
+ Iterator contacts = contacts();
+ while (contacts.hasNext())
+ {
+ ContactDictImpl contact = (ContactDictImpl) contacts.next();
+ buff.append(contact.toString());
+ if(contacts.hasNext())
+ buff.append(", ");
+ }
+ return buff.append("]").toString();
+ }
+
+ /**
+ * Specifies whether or not this contact group is being stored by the server.
+ * Non persistent contact groups are common in the case of simple,
+ * non-persistent presence operation sets. They could however also be seen
+ * in persistent presence operation sets when for example we have received
+ * an event from someone not on our contact list and the contact that we
+ * associated with that user is placed in a non persistent group. Non
+ * persistent contact groups are volatile even when coming from a persistent
+ * presence op. set. They would only exist until the application is closed
+ * and will not be there next time it is loaded.
+ *
+ * @param isPersistent true if the contact group is to be persistent and
+ * false otherwise.
+ */
+ public void setPersistent(boolean isPersistent)
+ {
+ this.isPersistent = isPersistent;
+ }
+
+ /**
+ * Determines whether or not this contact group is being stored by the
+ * server. Non persistent contact groups exist for the sole purpose of
+ * containing non persistent contacts.
+ * @return true if the contact group is persistent and false otherwise.
+ */
+ public boolean isPersistent()
+ {
+ return isPersistent;
+ }
+
+ /**
+ * Returns null as no persistent data is required and the contact address is
+ * sufficient for restoring the contact.
+ * <p>
+ * @return null as no such data is needed.
+ */
+ public String getPersistentData()
+ {
+ return null;
+ }
+
+ /**
+ * Determines whether or not this contact has been resolved against the
+ * server. Unresolved contacts are used when initially loading a contact
+ * list that has been stored in a local file until the presence operation
+ * set has managed to retrieve all the contact list from the server and has
+ * properly mapped contacts to their on-line buddies.
+ * @return true if the contact has been resolved (mapped against a buddy)
+ * and false otherwise.
+ */
+ public boolean isResolved()
+ {
+ return isResolved;
+ }
+
+ /**
+ * Makes the group resolved or unresolved.
+ *
+ * @param resolved true to make the group resolved; false to
+ * make it unresolved
+ */
+ public void setResolved(boolean resolved)
+ {
+ this.isResolved = resolved;
+ }
+
+ /**
+ * Returns a <tt>String</tt> that uniquely represnets the group inside
+ * the current protocol. The string MUST be persistent (it must not change
+ * across connections or runs of the application). In many cases (Jabber,
+ * ICQ) the string may match the name of the group as these protocols
+ * only allow a single level of contact groups and there is no danger of
+ * having the same name twice in the same contact list. Other protocols
+ * (no examples come to mind but that doesn't bother me ;) ) may be
+ * supporting mutilple levels of grooups so it might be possible for group
+ * A and group B to both contain groups named C. In such cases the
+ * implementation must find a way to return a unique identifier in this
+ * method and this UID should never change for a given group.
+ *
+ * @return a String representing this group in a unique and persistent
+ * way.
+ */
+ public String getUID()
+ {
+ return uid;
+ }
+
+ /**
+ * Ugly but tricky conversion method.
+ * @param uid the uid we'd like to get a name from
+ * @return the name of the group with the specified <tt>uid</tt>.
+ */
+ static String createNameFromUID(String uid)
+ {
+ return uid.substring(0, uid.length() - (UID_SUFFIX.length()));
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one which in terms
+ * of contact groups translates to having the equal names and matching
+ * subgroups and child contacts. The resolved status of contactgroups and
+ * contacts is deliberately ignored so that groups and/or contacts would
+ * be assumed equal even if it differs.
+ * <p>
+ * @param obj the reference object with which to compare.
+ * @return <code>true</code> if this contact group has the equal child
+ * contacts and subgroups to those of the <code>obj</code> argument.
+ */
+ public boolean equals(Object obj)
+ {
+ if(obj == null
+ || !(obj instanceof ContactGroupDictImpl))
+ return false;
+
+ ContactGroupDictImpl dictGroup
+ = (ContactGroupDictImpl)obj;
+
+ if( ! dictGroup.getGroupName().equals(getGroupName())
+ || ! dictGroup.getUID().equals(getUID())
+ || dictGroup.countContacts() != countContacts()
+ || dictGroup.countSubgroups() != countSubgroups())
+ return false;
+
+ //traverse child contacts
+ Iterator theirContacts = dictGroup.contacts();
+
+ while(theirContacts.hasNext())
+ {
+ ContactDictImpl theirContact
+ = (ContactDictImpl)theirContacts.next();
+
+ ContactDictImpl ourContact
+ = (ContactDictImpl)getContact(theirContact.getAddress());
+
+ if(ourContact == null
+ || !ourContact.equals(theirContact))
+ return false;
+ }
+
+ //traverse subgroups
+ Iterator theirSubgroups = dictGroup.subgroups();
+
+ while(theirSubgroups.hasNext())
+ {
+ ContactGroupDictImpl theirSubgroup
+ = (ContactGroupDictImpl)theirSubgroups.next();
+
+ ContactGroupDictImpl ourSubgroup
+ = (ContactGroupDictImpl)getGroup(
+ theirSubgroup.getGroupName());
+
+ if(ourSubgroup == null
+ || !ourSubgroup.equals(theirSubgroup))
+ return false;
+ }
+
+ return true;
+ }
+}
+
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictAccountID.java b/src/net/java/sip/communicator/impl/protocol/dict/DictAccountID.java
new file mode 100644
index 0000000..6f823f5
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/DictAccountID.java
@@ -0,0 +1,33 @@
+/*
+ * 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.dict;
+
+import net.java.sip.communicator.service.protocol.*;
+import java.util.Map;
+
+/**
+ * The Dict implementation of a sip-communicator account id.
+ * @author LITZELMANN Cédric
+ * @author ROTH Damien
+ */
+public class DictAccountID
+ extends AccountID
+{
+ /**
+ * Creates an account id from the specified id and account properties.
+ *
+ * @param userID the user identifier correspnding to the account
+ * @param accountProperties any other properties necessary for the account.
+ */
+ DictAccountID(String userID, Map accountProperties)
+ {
+ super( userID,
+ accountProperties,
+ "Dict",
+ "dict.org");
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictActivator.java b/src/net/java/sip/communicator/impl/protocol/dict/DictActivator.java
new file mode 100644
index 0000000..455fb63
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/DictActivator.java
@@ -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.protocol.dict;
+
+import org.osgi.framework.*;
+import net.java.sip.communicator.util.*;
+import java.util.*;
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * Loads the Dict provider factory and registers its services in the OSGI
+ * bundle context.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class DictActivator
+ implements BundleActivator
+{
+ private static final Logger logger = Logger.getLogger(DictActivator.class);
+
+ /**
+ * The currently valid bundle context.
+ */
+ private static BundleContext bundleContext = null;
+
+ private ServiceRegistration dictPpFactoryServReg = null;
+ private static ProtocolProviderFactoryDictImpl
+ dictProviderFactory = null;
+
+ /**
+ * Called when this bundle is started. In here we'll export the
+ * dict ProtocolProviderFactory implementation so that it could be
+ * possible to register accounts with it in SIP Communicator.
+ *
+ * @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
+ {
+ bundleContext = context;
+
+ Hashtable hashtable = new Hashtable();
+ hashtable.put(ProtocolProviderFactory.PROTOCOL, ProtocolNames.DICT);
+
+ dictProviderFactory = new ProtocolProviderFactoryDictImpl();
+
+ //load all stored Dict accounts.
+ dictProviderFactory.loadStoredAccounts();
+
+ //reg the dict provider factory.
+ dictPpFactoryServReg = context.registerService(
+ ProtocolProviderFactory.class.getName(),
+ dictProviderFactory,
+ hashtable);
+
+ logger.info("DICT protocol implementation [STARTED].");
+ }
+
+ /**
+ * Returns a reference to the bundle context that we were started with.
+ * @return a reference to the BundleContext instance that we were started
+ * witn.
+ */
+ public static BundleContext getBundleContext()
+ {
+ return bundleContext;
+ }
+
+ /**
+ * 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
+ {
+
+ this.dictProviderFactory.stop();
+ dictPpFactoryServReg.unregister();
+
+ logger.info("DICT protocol implementation [STOPPED].");
+ }
+
+ /**
+ * Retrurns a reference to the protocol provider factory that we have
+ * registered.
+ * @return a reference to the <tt>ProtocolProviderFactoryDictImpl</tt>
+ * instance that we have registered from this package.
+ */
+ public static ProtocolProviderFactoryDictImpl getProtocolProviderFactory()
+ {
+ return dictProviderFactory;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictAdapter.java b/src/net/java/sip/communicator/impl/protocol/dict/DictAdapter.java
new file mode 100644
index 0000000..433c423
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/DictAdapter.java
@@ -0,0 +1,605 @@
+/*
+ * 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.dict;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * Layer abstraction of a dict server
+ *
+ * @author LITZELMANN Cédric
+ * @author ROTH Damien
+ */
+public class DictAdapter
+{
+ /**
+ * The host name of the server: i.e. "dict.org"
+ */
+ private String host;
+
+ /**
+ * The port used by the server. The default one for the DICT protocol is
+ * 2628.
+ */
+ private int port;
+
+ /**
+ * The name of the strategy used for searching words with command MATCH:
+ * i.e. the strategie can de "prefix", "suffix", "soundex", "levenshtein", etc.
+ */
+ private String strategy;
+
+ /**
+ * A string representation used to identify the client to the serveur. In
+ * our case we will use the "SIP Communicator" string for the client name.
+ */
+ private String clientName = "";
+
+ // Status
+ /**
+ * The socket used to connect to the DICT server.
+ */
+ private Socket socket;
+
+ /**
+ * A output stream piped to the socket in order to send command to the server.
+ */
+ private PrintWriter out;
+
+ /**
+ * A input stream piped to the socket in order to receive messages from the server.
+ */
+ private BufferedReader in;
+
+ /**
+ * A boolean telling if we are currently connected to the DICT server.
+ */
+ private boolean connected;
+
+ /**
+ * The list of all the databases hosted by the server. Each database
+ * correspond to a dictionnary.
+ */
+ Vector<String> databasesList;
+
+ /**
+ * Initialize a basic instance with predefined settings
+ */
+ public DictAdapter()
+ {
+ this.host = "dict.org";
+ this.port = 2628;
+ this.strategy = "prefix";
+ this.connected = false;
+ this.socket = null;
+ this.out = null;
+ this.in = null;
+ }
+
+ /**
+ * Initialize a basic instance and set th host
+ * @param host Host
+ */
+ public DictAdapter(String host)
+ {
+ this.host = host;
+ this.port = 2628;
+ this.strategy = "prefix";
+ this.connected = false;
+ this.socket = null;
+ this.out = null;
+ this.in = null;
+ }
+
+ /**
+ * Initialize an instance and set the host and the port
+ * @param host Host
+ * @param port Port
+ */
+ public DictAdapter(String host, int port)
+ {
+ this.host = host;
+ this.port = port;
+ this.strategy = "prefix";
+ this.connected = false;
+ this.socket = null;
+ this.out = null;
+ this.in = null;
+ }
+
+ /**
+ * Initialize an instance and set the host, port and strategy
+ * @param host Host
+ * @param port Port
+ * @param strategy Match strategy
+ */
+ public DictAdapter(String host, int port, String strategy)
+ {
+ this.host = host;
+ this.port = port;
+ this.strategy = strategy;
+ this.connected = false;
+ this.socket = null;
+ this.out = null;
+ this.in = null;
+ }
+
+
+ /**
+ * Establish a connexion to the dict server
+ * @throws Exception
+ * @return DictResultset containing the error - null otherwise
+ */
+ private void connect() throws Exception
+ {
+ String fromServer;
+
+ if (this.isConnected())
+ {
+ return;
+ }
+
+ try
+ {
+ this.socket = new Socket(this.host, this.port);
+ this.out = new PrintWriter(new OutputStreamWriter(this.socket.getOutputStream(),
+ "UTF-8"), true);
+ this.in = new BufferedReader(new InputStreamReader(this.socket.getInputStream(),
+ "UTF-8"));
+
+ fromServer = this.in.readLine(); // Server banner
+
+ if (fromServer.startsWith("220"))
+ { // 220 = connect ok
+ this.connected = true;
+ this.client("SIP Communicator");
+ return;
+ }
+ else
+ {
+ throw new DictException(fromServer.substring(0, 3));
+ }
+ }
+ catch(UnknownHostException uhe)
+ {
+ throw new DictException(uhe);
+ }
+ catch(IOException ioe)
+ {
+ throw new DictException(ioe);
+ }
+ }
+
+ /**
+ * Close the actual connexion
+ * @throws Exception
+ */
+ public void close() throws Exception
+ {
+ String fromServer;
+ boolean quit = false;
+
+ if (!this.isConnected())
+ {
+ return;
+ }
+
+ try
+ {
+ this.out.println("QUIT");
+
+ // Clean the socket buffer
+ while (quit == false && (fromServer = this.in.readLine()) != null)
+ {
+ if (fromServer.startsWith("221"))
+ { // Quit response
+ quit = true;
+ }
+ }
+
+ this.out.close();
+ this.in.close();
+ this.socket.close();
+
+ this.connected = false;
+ }
+ catch (IOException ioe)
+ {
+ throw new DictException(ioe);
+ }
+ }
+
+ /**
+ * Get the database list from the server
+ * @throws Exception
+ * @return a DictResultset containing the database list - otherwise the error code
+ */
+ public DictResultset showDB() throws Exception
+ {
+ String fromServer;
+ boolean quit = false;
+ DictResultset result = new DictResultset();
+ this.connect();
+
+ try
+ {
+ fromServer = this.query("SHOW DB");
+
+ if (fromServer.startsWith("110"))
+ { // OK - getting responses from the server
+ result.newResultset();
+ while (quit == false && (fromServer = this.in.readLine()) != null)
+ {
+ if (fromServer.startsWith("250"))
+ {
+ quit = true;
+ }
+ else if (!fromServer.equals("."))
+ {
+ result.addResult(fromServer);
+ }
+ }
+ }
+ else
+ {
+ throw new DictException(fromServer.substring(0,3));
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new DictException(ioe);
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the strategies allowed by the server for the MATCH command
+ * @throws Exception
+ * @return a DictResultset containing the database list - otherwise the error code
+ */
+ public DictResultset showStrat() throws Exception
+ {
+ String fromServer;
+ boolean quit = false;
+ DictResultset result = new DictResultset();
+ this.connect();
+
+ try
+ {
+ fromServer = this.query("SHOW STRAT");
+
+ if (fromServer.startsWith("111"))
+ { // OK - getting responses from the server
+ result.newResultset();
+ while (quit == false && (fromServer = this.in.readLine()) != null)
+ {
+ if (fromServer.startsWith("250"))
+ {
+ quit = true;
+ }
+ else if (!fromServer.equals("."))
+ {
+ result.addResult(fromServer);
+ }
+ }
+ }
+ else
+ {
+ throw new DictException(fromServer.substring(0,3));
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new DictException(ioe);
+ }
+
+ return result;
+ }
+
+
+ /**
+ * Get the definition of a word
+ * @param database the database in which the word will be searched
+ * @param word the search word
+ * @throws Exception
+ * @return a DictResultset containing the database list - otherwise the error code
+ */
+ public DictResultset define(String database, String word) throws Exception
+ {
+ String fromServer;
+ boolean quit = false;
+ DictResultset result = new DictResultset();
+ String[] test;
+ this.connect();
+
+ try
+ {
+ fromServer = this.query("DEFINE " + database + " " + word);
+
+ if (fromServer.startsWith("150"))
+ {
+ while (quit == false && (fromServer = this.in.readLine()) != null)
+ {
+ if (fromServer.startsWith("151"))
+ { // First line - Contains the DB Name
+ test = fromServer.split(" ", 4);
+ result.newResultset(test[3].substring(1, test[3].length() - 1));
+ continue;
+ }
+ else if (fromServer.startsWith("250"))
+ { // End of the request
+ quit = true;
+ }
+ else if (!fromServer.equals("."))
+ {
+ result.addResult(fromServer);
+ }
+ }
+ }
+ else
+ {
+ throw new DictException(fromServer.substring(0,3));
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new DictException(ioe);
+ }
+
+ return result;
+ }
+
+ /**
+ * Get words that match with a strategie form a word with the stored strategy
+ * @param database The database in which the words will be searched
+ * @param word The base word
+ * @return a DictResultset containing the words list - otherwise throw an exception
+ * @throws Exception
+ */
+ public DictResultset match(String database, String word) throws Exception
+ {
+ return this.match(database, this.strategy, word);
+ }
+
+ /**
+ * Get words that match with a strategie from a word
+ * @param database the database in which the words will be searched
+ * @param strat the strategies used
+ * @param word the base word
+ * @throws Exception
+ * @return a DictResultset containing the words list - otherwise the error code
+ */
+ public DictResultset match(String database, String strat, String word) throws Exception
+ {
+ String fromServer;
+ boolean quit = false;
+ DictResultset result = new DictResultset();
+ this.connect();
+
+ try
+ {
+ fromServer = this.query("MATCH " + database + " " + strat + " " + word);
+
+ if (fromServer.startsWith("152"))
+ {
+ result.newResultset();
+ while (quit == false && (fromServer = this.in.readLine()) != null)
+ {
+ if (fromServer.startsWith("250"))
+ {
+ quit = true;
+ }
+ else if (!fromServer.equals("."))
+ {
+ result.addResult(fromServer);
+ }
+ }
+ }
+ else
+ {
+ throw new DictException(fromServer.substring(0,3));
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new DictException(ioe);
+ }
+
+ return result;
+ }
+
+ /**
+ * Provide information to the server about the clientname, for logging and statistical purposes
+ * @param clientname Client name
+ * @throws Exception
+ */
+ public void client(String clientname) throws Exception
+ {
+ String fromServer;
+ this.connect();
+
+ fromServer = this.query("CLIENT " + clientname);
+
+ // 250 code is the only possible answer
+ if (!fromServer.startsWith("250"))
+ {
+ throw new DictException(fromServer.substring(0, 3));
+ }
+ }
+
+ /**
+ * Set the host
+ * @param newHost host address
+ */
+ public void setHost(String newHost) throws Exception
+ {
+ if (isUrl(newHost))
+ {
+ this.host = newHost;
+ }
+ else
+ {
+ throw new DictException(900, "Host URL is incorrect");
+ }
+ }
+
+ /**
+ * Set the host port
+ * @param newPort Port
+ */
+ public void setPort(int newPort)
+ {
+ this.port = newPort;
+ }
+
+ /**
+ * Set the strategy
+ * @param newStrat Strategy
+ */
+ public void setStrategy(String newStrat)
+ {
+ this.strategy = newStrat;
+ }
+
+ /**
+ * Set the client name which is communicated to the server
+ * @param cn Client name
+ */
+ public void setClientName(String cn)
+ {
+ this.clientName = cn;
+ }
+
+ /**
+ * Return the host
+ * @return return the host
+ */
+ public String getHost()
+ {
+ return this.host;
+ }
+
+ /**
+ * Return the port
+ * @return return the port
+ */
+ public int getPort()
+ {
+ return this.port;
+ }
+
+ /**
+ * Return the strategy
+ * @return return the strategy
+ */
+ public String getStrategy()
+ {
+ return this.strategy;
+ }
+
+ /**
+ * Return the client name
+ * @return return the client name
+ */
+ public String getClientName()
+ {
+ return this.clientName;
+ }
+
+ /**
+ * Gets the database's list from the server
+ * @return List of the databases
+ * @throws Exception
+ */
+ public Vector<String> getDatabases() throws Exception
+ {
+ if (this.databasesList == null)
+ {
+ DictResultset drs = this.showDB();
+ DictResult list = drs.getResultset(0);
+
+ this.databasesList = new Vector<String>();
+
+ while(list.hasNext())
+ {
+ this.databasesList.add(list.next());
+ }
+ }
+ return this.databasesList;
+ }
+
+ /**
+ * Check if we are connected to the server
+ * @return true if we are connected - false otherwise
+ */
+ public boolean isConnected()
+ {
+ return this.connected;
+ }
+
+ /**
+ * Check if the URL is correct and a server exists
+ * @param url an Url
+ * @return true if everything is ok - false otherwise
+ */
+ public static boolean isUrl(String url)
+ {
+ boolean ok;
+ if (url == null)
+ {
+ return false;
+ }
+
+ try
+ {
+ InetAddress.getByName(url);
+ ok = true;
+ }
+ catch (UnknownHostException uhex)
+ {
+ ok = false;
+ }
+
+ return ok;
+ }
+
+ /**
+ * Executes a query and deals with the automatic deconnexion
+ * @param query A query to send to the server
+ * @return The first ligne of the response from the server
+ * @throws Exception IOException and DictException
+ */
+ private String query(String query) throws Exception
+ {
+ String result = null;
+
+ this.out.println(query);
+ result = in.readLine();
+
+ if (result == null)
+ {
+ // The connexion may be close, reconnexion
+ this.connected = false;
+ this.connect();
+
+ this.out.println(query);
+ result = in.readLine();
+
+ if (result == null)
+ {
+ // If result is still equal to null, the server is unavailable
+ // We send the appropriate exception
+ throw new DictException(420);
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictException.java b/src/net/java/sip/communicator/impl/protocol/dict/DictException.java
new file mode 100644
index 0000000..7792365
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/DictException.java
@@ -0,0 +1,287 @@
+/*
+ * 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.dict;
+
+/**
+ * Exception class managing the basics dict server errors.
+ *
+ * @author LITZELMANN Cédric
+ * @author ROTH Damien
+ */
+public class DictException
+ extends Exception
+{
+ // Error number
+ private int error;
+
+ // Error message
+ private String errorMessage;
+
+ /**
+ * Create an exception from the dict error code
+ * @param error Error code returned by the server
+ */
+ public DictException(int error)
+ {
+ this.error = error;
+ }
+
+ /**
+ * Create an exception with a custom message
+ * @param error Error code returned by the server
+ * @param message Custom message
+ */
+ public DictException(int error, String message)
+ {
+ this.error = error;
+ this.errorMessage = message;
+ }
+
+ /**
+ * Same as the first constructor but with a string (converted to an int)
+ * @param error Error code returned by the server
+ */
+ public DictException(String error)
+ {
+ this.error = Integer.parseInt(error);
+ }
+
+ /**
+ * Create an exception from a java exception
+ * @param e Java Exception
+ */
+ public DictException(Exception e)
+ {
+ String className = e.getClass().toString();
+
+ if (className.endsWith("IOException"))
+ {
+ this.error = 901;
+ this.errorMessage = "IOException";
+ }
+ else if (className.endsWith("UnknownHostException"))
+ {
+ this.error = 902;
+ this.errorMessage = "UnknownHostException";
+ }
+ else if (className.endsWith("SecurityException"))
+ {
+ this.error = 903;
+ this.errorMessage = "SecurityException";
+ }
+ else if (className.endsWith("SocketTimeoutException"))
+ {
+ this.error = 904;
+ this.errorMessage = "SocketTimeoutException";
+ }
+ else
+ {
+ this.error = 900;
+ this.errorMessage = "Unknown error [" + className + "]";
+ }
+
+ this.errorMessage += ": " + e.getMessage();
+ }
+
+ /**
+ * Return the error code
+ * @return the error code
+ */
+ public int getErrorCode()
+ {
+ return this.error;
+ }
+
+ /**
+ * Return the error message
+ * @return the error message
+ */
+ public String getMessage()
+ {
+ return this.errorMessage;
+ }
+
+ /**
+ * Get an explanation of the error
+ * @return Returns an explanation corresponding to the current error
+ * (this.error).
+ */
+ public String getErrorMessage()
+ {
+ String result;
+ switch(this.error)
+ {
+ case 110 :
+ result = "n databases present";
+ break;
+ case 111 :
+ result = "n strategies available";
+ break;
+ case 112 :
+ result = "database information follows";
+ break;
+ case 113 :
+ result = "help text follows";
+ break;
+ case 114 :
+ result = "server information follows";
+ break;
+ case 130 :
+ result = "challenge follows";
+ break;
+ case 150 :
+ result = "n definitions retrieved";
+ break;
+ case 151 :
+ result = "word database name";
+ break;
+ case 152 :
+ result = "n matches found";
+ break;
+ case 210 :
+ result = "optional timing";
+ break;
+ case 220 :
+ result = "Connexion OK";
+ break;
+ case 221 :
+ result = "Closing Connection";
+ break;
+ case 230 :
+ result = "Authentification successful";
+ break;
+ case 250 :
+ result = "Ok";
+ break;
+ case 330 :
+ result = "send response";
+ break;
+ case 420 :
+ result = "Server temporarily unavailable";
+ break;
+ case 421 :
+ result = "Server shutting down at operator request";
+ break;
+ case 500 :
+ result = "Syntax error, command not recognized";
+ break;
+ case 501 :
+ result = "Syntax error, illegal parameters";
+ break;
+ case 502 :
+ result = "Command not implemented";
+ break;
+ case 503 :
+ result = "Command parameter not implemented";
+ break;
+ case 530 :
+ result = "Access denied";
+ break;
+ case 531 :
+ result = "Access denied, use SHOW INFO for server information";
+ break;
+ case 532 :
+ result = "Access denied, unknown mechanism";
+ break;
+ case 550 :
+ result = "Invalid database, use SHOW DB for list of databases";
+ break;
+ case 551 :
+ result = "Invalid strategy, use SHOW STRAT for a list of strategies";
+ break;
+ case 552 :
+ result = "No match";
+ break;
+ case 554 :
+ result = "No databases present";
+ break;
+ case 555 :
+ result = "No strategies available";
+ break;
+ default :
+ if (error >= 900)
+ {
+ result = this.errorMessage;
+ }
+ else
+ {
+ result = this.errorGen(error);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Get informations about unknowns errors
+ * @param err Error number
+ * @return Error definition
+ */
+ private String errorGen(int err)
+ {
+ String error_type = Integer.toString(err);
+
+ String result = new String();
+
+ if(error_type.startsWith("1"))
+ {// test on digit one
+ result = "Positive Preliminary reply : ";
+ }
+ else if(error_type.startsWith("2"))
+ {
+ result = "Positive Completion reply : " ;
+ }
+ else if(error_type.startsWith("3"))
+ {
+ result = "Positive Intermediate reply : ";
+ }
+ else if(error_type.startsWith("4"))
+ {
+ result = "Transient Negative Completion reply : ";
+ }
+ else if(error_type.startsWith("5"))
+ {
+ result = "Permanent Negative Completion reply : ";
+ }
+ else
+ {
+ return "Unknown error";
+ }
+
+ //test on digit two
+ if(error_type.charAt(1) == '0')
+ {
+ result += "Syntax";
+ }
+ else if ( error_type.charAt(1) == '1')
+ {
+ result += "Information";
+ }
+ else if ( error_type.charAt(1) == '2')
+ {
+ result += "Connections";
+ }
+ else if ( error_type.charAt(1) == '3')
+ {
+ result += "Authentication";
+ }
+ else if ( error_type.charAt(1) == '4')
+ {
+ result += "Unspecified as yet";
+ }
+ else if ( error_type.charAt(1) == '5')
+ {
+ result += "DICT System";
+ }
+ else if ( error_type.charAt(1) == '8')
+ {
+ result += "Nonstandard (private implementation) extensions";
+ }
+
+ return result;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictRegistry.java b/src/net/java/sip/communicator/impl/protocol/dict/DictRegistry.java
new file mode 100644
index 0000000..eca70b7
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/DictRegistry.java
@@ -0,0 +1,64 @@
+/*
+ * 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.dict;
+
+import java.util.*;
+
+/**
+ * Static registry storing the connexions to dict servers
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class DictRegistry
+{
+ private static HashMap<String, DictAdapter> adapters = new HashMap<String,DictAdapter>();
+
+ /**
+ * Checks if an adapter associated with the given key is stored in the regitry
+ * @param key Key to the adapter
+ * @return true, if an adapter exists - false otherwise
+ */
+ public static boolean has(String key)
+ {
+ return adapters.containsKey(key);
+ }
+
+ /**
+ * Stores a new adapter in the registry
+ * @param key Key
+ * @param value DictAdapter class
+ */
+ public static void put(String key, DictAdapter value)
+ {
+ adapters.put(key, value);
+ }
+
+ /**
+ * Returns the adapter associated with the given key
+ * @param key Key
+ * @return the adapter associated with the given key - null otherwise
+ */
+ public static DictAdapter get(String key)
+ {
+ if (DictRegistry.has(key))
+ {
+ return adapters.get(key);
+ }
+ return null;
+ }
+
+ /**
+ * Removes the adapter associated with the given key from the registry
+ * @param key
+ */
+ public static void remove(String key)
+ {
+ if (DictRegistry.has(key)) {
+ adapters.remove(key);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictResult.java b/src/net/java/sip/communicator/impl/protocol/dict/DictResult.java
new file mode 100644
index 0000000..464d915
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/DictResult.java
@@ -0,0 +1,97 @@
+/*
+ * 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.dict;
+
+import java.util.*;
+
+/**
+ * Representation of the results of a response to a query
+ *
+ * @author ROTH Damien
+ * @author LITZEMANN Cédric
+ */
+public class DictResult
+ implements Iterator<String>
+{
+ private String databaseName;
+ private int index;
+ private ArrayList<String> data;
+
+ /**
+ * Basic construct initializing the result
+ */
+ public DictResult()
+ {
+ this.index = 0;
+ this.data = new ArrayList<String>();
+ this.databaseName = "";
+ }
+
+ /**
+ * Initialize the result and save the database name
+ * @param dbn Database name
+ */
+ public DictResult(String dbn)
+ {
+ this.index = 0;
+ this.data = new ArrayList<String>();
+ this.databaseName = dbn;
+ }
+
+ /**
+ * Add a result
+ * @param s result
+ */
+ public void add(String s)
+ {
+ this.data.add(s);
+ }
+
+ /**
+ * From the Iterator implementation, return the next part of the result
+ * @return the next part of the result
+ */
+ public String next()
+ {
+ return (String) this.data.get(this.index++);
+ }
+
+ /**
+ * From the Iterator implementation, return true if the iteration has more elements
+ * @return true if the iteration has more elements - false otherwise
+ */
+ public boolean hasNext()
+ {
+ return (this.index < this.data.size());
+ }
+
+ /**
+ * From the Iterator implementation but unsupported
+ */
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Set the database name
+ * @param dbn Database name
+ */
+ public void setDatabaseName(String dbn)
+ {
+ this.databaseName = dbn;
+ }
+
+ /**
+ * Return the database name
+ * @return the database name
+ */
+ public String getDatabaseName()
+ {
+ return this.databaseName;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictResultset.java b/src/net/java/sip/communicator/impl/protocol/dict/DictResultset.java
new file mode 100644
index 0000000..3e4251c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/DictResultset.java
@@ -0,0 +1,107 @@
+/*
+ * 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.dict;
+
+import java.util.*;
+
+/**
+ * Class managing the results of a dict query
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class DictResultset
+{
+ /**
+ * The index number of the last resultset for this DictResultset. This
+ * parametre is set to "-1" if there is no resultset.
+ */
+ private int cursor;
+
+ /**
+ * The list containing all the resultsets for this DictResultset.
+ */
+ private ArrayList<DictResult> data;
+
+ /**
+ * Initialize a resultset list
+ */
+ public DictResultset()
+ {
+ this.cursor = -1;
+ this.data = new ArrayList<DictResult>();
+ }
+
+ /**
+ * Create a new resultset
+ */
+ public void newResultset()
+ {
+ this.cursor++;
+ this.data.add(new DictResult());
+ }
+
+ /**
+ * Create a new resultset and save the database name
+ * @param dbn Database name
+ */
+ public void newResultset(String dbn)
+ {
+ this.cursor++;
+ this.data.add(new DictResult(dbn));
+ }
+
+ /**
+ * Set the database name for the current resultset
+ * @param dbn Database name
+ */
+ public void setDatabaseName(String dbn)
+ {
+ this.data.get(this.cursor).setDatabaseName(dbn);
+ }
+
+ /**
+ * Add a result in the current resultset
+ * @param res a result line from a dict query
+ */
+ public void addResult(String res)
+ {
+ this.data.get(this.cursor).add(res);
+ }
+
+ /**
+ * Return true if there is a resultset
+ * @return return true if there is a resultset - false otherwise
+ */
+ public boolean hasResult()
+ {
+ return this.data.size() > 0;
+ }
+
+ /**
+ * Return the resultset at the given index
+ * @param index Index of the wished resultset
+ * @return a DictResult - null otherwise
+ */
+ public DictResult getResultset(int index)
+ {
+ if (index < this.data.size())
+ {
+ return (DictResult) this.data.get(index);
+ }
+ return null;
+ }
+
+ /**
+ * Return the number of resultsets
+ * @return the number of resultsets
+ */
+ public int getNbResults()
+ {
+ return this.data.size();
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/DictStatusEnum.java b/src/net/java/sip/communicator/impl/protocol/dict/DictStatusEnum.java
new file mode 100644
index 0000000..26d6ac6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/DictStatusEnum.java
@@ -0,0 +1,104 @@
+/*
+ * 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.dict;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+import java.io.*;
+
+/**
+ * An implementation of <tt>PresenceStatus</tt> that enumerates all states that
+ * a Dict contact can fall into.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class DictStatusEnum
+ extends PresenceStatus
+{
+ private static final Logger logger
+ = Logger.getLogger(DictStatusEnum.class);
+
+ /**
+ * Indicates an Offline status or status with 0 connectivity.
+ */
+ public static final DictStatusEnum OFFLINE
+ = new DictStatusEnum(
+ 0
+ , "Offline"
+ , loadIcon("resources/images/protocol/dict/dict-16x16.png"));
+
+ /**
+ * The Online status. Indicate that the user is able and willing to
+ * communicate.
+ */
+ public static final DictStatusEnum ONLINE
+ = new DictStatusEnum(
+ 65
+ , "Online"
+ , loadIcon("resources/images/protocol/dict/dict-16x16.png"));
+
+ /**
+ * Initialize the list of supported status states.
+ */
+ private static List supportedStatusSet = new LinkedList();
+ static
+ {
+ supportedStatusSet.add(OFFLINE);
+ supportedStatusSet.add(ONLINE);
+ }
+
+ /**
+ * Creates an instance of <tt>RssPresneceStatus</tt> with the
+ * specified parameters.
+ * @param status the connectivity level of the new presence status instance
+ * @param statusName the name of the presence status.
+ * @param statusIcon the icon associated with this status
+ */
+ private DictStatusEnum(int status,
+ String statusName,
+ byte[] statusIcon)
+ {
+ super(status, statusName, statusIcon);
+ }
+
+ /**
+ * Returns an iterator over all status instances supproted by the rss
+ * provider.
+ * @return an <tt>Iterator</tt> over all status instances supported by the
+ * rss provider.
+ */
+ static Iterator supportedStatusSet()
+ {
+ return supportedStatusSet.iterator();
+ }
+
+ /**
+ * Loads an image from a given image path.
+ * @param imagePath The path to the image resource.
+ * @return The image extracted from the resource at the specified path.
+ */
+ public static byte[] loadIcon(String imagePath)
+ {
+ InputStream is = DictStatusEnum.class.getClassLoader().getResourceAsStream(imagePath);
+
+ byte[] icon = null;
+ try
+ {
+ icon = new byte[is.available()];
+ is.read(icon);
+ }
+ catch (IOException exc)
+ {
+ logger.error("Failed to load icon: " + imagePath, exc);
+ }
+ return icon;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/MessageDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/MessageDictImpl.java
new file mode 100644
index 0000000..256e54d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/MessageDictImpl.java
@@ -0,0 +1,138 @@
+/*
+ * 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.dict;
+
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * Very simple message implementation for the Dict protocol.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class MessageDictImpl
+ implements Message
+{
+ /**
+ * The actual message content.
+ */
+ private String textContent = null;
+
+ /**
+ * The content type of the message. (text/plain if null)
+ */
+ private String contentType = null;
+
+ /**
+ * The message encoding. (UTF8 if null).
+ */
+ private String contentEncoding = null;
+
+ /**
+ * A String uniquely identifying the message
+ */
+ private String messageUID = null;
+
+ /**
+ * The subject of the message. (most often is null)
+ */
+ private String subject = null;
+
+ /**
+ * Creates a message instance according to the specified parameters.
+ *
+ * @param content the message body
+ * @param contentType message content type or null for text/plain
+ * @param contentEncoding message encoding or null for UTF8
+ * @param subject the subject of the message or null for no subject.
+ */
+ public MessageDictImpl(String content,
+ String contentType,
+ String contentEncoding,
+ String subject)
+ {
+ this.textContent = content;
+ this.contentType = contentType;
+ this.contentEncoding = contentEncoding;
+ this.subject = subject;
+
+ //generate the uid
+ this.messageUID = String.valueOf(System.currentTimeMillis())
+ + String.valueOf(hashCode());
+
+ }
+
+ /**
+ * Returns the message body.
+ *
+ * @return the message content.
+ */
+ public String getContent()
+ {
+ return textContent;
+ }
+
+ /**
+ * Returns the type of the content of this message.
+ *
+ * @return the type of the content of this message.
+ */
+ public String getContentType()
+ {
+ return contentType;
+ }
+
+ /**
+ * Returns the encoding used for the message content.
+ *
+ * @return the encoding of the message body.
+ */
+ public String getEncoding()
+ {
+ return contentEncoding;
+ }
+
+ /**
+ * A string uniquely identifying the message.
+ *
+ * @return a <tt>String</tt> uniquely identifying the message.
+ */
+ public String getMessageUID()
+ {
+ return messageUID;
+ }
+
+ /**
+ * Returns the message body in a binary form.
+ *
+ * @return a <tt>byte[]</tt> representation of the message body.
+ */
+ public byte[] getRawData()
+ {
+ return getContent().getBytes();
+ }
+
+ /**
+ * Return the length of this message.
+ *
+ * @return the length of this message.
+ */
+ public int getSize()
+ {
+ return getContent().length();
+ }
+
+ /**
+ * Returns the message subject.
+ *
+ * @return the message subject.
+ */
+ public String getSubject()
+ {
+ return subject;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/OperationSetBasicInstantMessagingDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/OperationSetBasicInstantMessagingDictImpl.java
new file mode 100644
index 0000000..4dc2848
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/OperationSetBasicInstantMessagingDictImpl.java
@@ -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.protocol.dict;
+
+import java.util.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+
+import net.java.sip.communicator.util.*;
+
+/**
+ * Instant messaging functionalities for the Dict protocol.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class OperationSetBasicInstantMessagingDictImpl
+ implements OperationSetBasicInstantMessaging,
+ RegistrationStateChangeListener
+{
+ private static final Logger logger
+ = Logger.getLogger(OperationSetBasicInstantMessagingDictImpl.class);
+
+ /**
+ * Currently registered message listeners.
+ */
+ private Vector messageListeners = new Vector();
+
+ /**
+ * The currently valid persistent presence operation set.
+ */
+ private OperationSetPersistentPresenceDictImpl opSetPersPresence = null;
+
+ /**
+ * The protocol provider that created us.
+ */
+ private ProtocolProviderServiceDictImpl parentProvider = null;
+
+ /**
+ * Creates an instance of this operation set keeping a reference to the
+ * parent protocol provider and presence operation set.
+ *
+ * @param provider The provider instance that creates us.
+ * @param opSetPersPresence the currently valid
+ * <tt>OperationSetPersistentPresenceDictImpl</tt> instance.
+ */
+ public OperationSetBasicInstantMessagingDictImpl(
+ ProtocolProviderServiceDictImpl provider,
+ OperationSetPersistentPresenceDictImpl opSetPersPresence)
+ {
+ this.opSetPersPresence = opSetPersPresence;
+ this.parentProvider = provider;
+
+ parentProvider.addRegistrationStateChangeListener(this);
+ }
+
+ /**
+ * Registers a MessageListener with this operation set so that it gets
+ * notifications of successful message delivery, failure or reception of
+ * incoming messages.
+ *
+ * @param listener the <tt>MessageListener</tt> to register.
+ */
+ public void addMessageListener(MessageListener listener)
+ {
+ if(!messageListeners.contains(listener))
+ {
+ messageListeners.add(listener);
+ }
+ }
+
+ /**
+ * Create a Message instance for sending arbitrary MIME-encoding content.
+ *
+ * @param content content value
+ * @param contentType the MIME-type for <tt>content</tt>
+ * @param contentEncoding encoding used for <tt>content</tt>
+ * @param subject a <tt>String</tt> subject or <tt>null</tt> for now
+ * subject.
+ * @return the newly created message.
+ */
+ public Message createMessage(byte[] content, String contentType,
+ String contentEncoding, String subject)
+ {
+ return new MessageDictImpl(new String(content), contentType,
+ contentEncoding, subject);
+ }
+
+ /**
+ * Create a Message instance for sending a simple text messages with
+ * default (text/plain) content type and encoding.
+ *
+ * @param messageText the string content of the message.
+ * @return Message the newly created message
+ */
+ public Message createMessage(String messageText)
+ {
+ return new MessageDictImpl(messageText, DEFAULT_MIME_TYPE,
+ DEFAULT_MIME_ENCODING, null);
+ }
+
+ /**
+ * Unregisters <tt>listener</tt> so that it won't receive any further
+ * notifications upon successful message delivery, failure or reception
+ * of incoming messages..
+ *
+ * @param listener the <tt>MessageListener</tt> to unregister.
+ */
+ public void removeMessageListener(MessageListener listener)
+ {
+ messageListeners.remove(listener);
+ }
+
+ /**
+ * Sends the <tt>message</tt> to the destination indicated by the
+ * <tt>to</tt> contact.
+ *
+ * @param to the <tt>Contact</tt> to send <tt>message</tt> to
+ * @param message the <tt>Message</tt> to send.
+ * @throws IllegalStateException if the underlying ICQ stack is not
+ * registered and initialized.
+ * @throws IllegalArgumentException if <tt>to</tt> is not an instance
+ * belonging to the underlying implementation.
+ */
+ public void sendInstantMessage(Contact to, Message message)
+ throws IllegalStateException,
+ IllegalArgumentException
+ {
+ if( !(to instanceof ContactDictImpl) )
+ {
+ throw new IllegalArgumentException(
+ "The specified contact is not a Dict contact."
+ + to);
+ }
+
+ // Display the queried word
+ fireMessageDelivered(message, to);
+
+ this.submitDictQuery((ContactDictImpl) to, message);
+ }
+
+ /**
+ * Notifies all registered message listeners that a message has been
+ * delivered successfully to its addressee..
+ *
+ * @param message the <tt>Message</tt> that has been delivered.
+ * @param to the <tt>Contact</tt> that <tt>message</tt> was delivered to.
+ */
+ private void fireMessageDelivered(Message message, Contact to)
+ {
+ MessageDeliveredEvent evt
+ = new MessageDeliveredEvent(message, to, new Date());
+
+ Iterator listeners = null;
+ synchronized (messageListeners)
+ {
+ listeners = new ArrayList(messageListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ MessageListener listener
+ = (MessageListener) listeners.next();
+
+ listener.messageDelivered(evt);
+ }
+ }
+
+ /**
+ * Notifies all registered message listeners that a message has been
+ * received.
+ *
+ * @param message the <tt>Message</tt> that has been received.
+ * @param from the <tt>Contact</tt> that <tt>message</tt> was received from.
+ */
+ private void fireMessageReceived(Message message, Contact from)
+ {
+ MessageReceivedEvent evt
+ = new MessageReceivedEvent(message, from, new Date());
+
+ Iterator listeners = null;
+ synchronized (messageListeners)
+ {
+ listeners = new ArrayList(messageListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ MessageListener listener
+ = (MessageListener) listeners.next();
+
+ listener.messageReceived(evt);
+ }
+ }
+
+ /**
+ * Determines whether the protocol provider (or the protocol itself) supports
+ * sending and receiving offline messages. Most often this method would
+ * return true for protocols that support offline messages and false for
+ * those that don't. It is however possible for a protocol to support these
+ * messages and yet have a particular account that does not (i.e. feature
+ * not enabled on the protocol server). In cases like this it is possible
+ * for this method to return true even when offline messaging is not
+ * supported, and then have the sendMessage method throw an
+ * OperationFailedException with code - OFFLINE_MESSAGES_NOT_SUPPORTED.
+ *
+ * @return <tt>true</tt> if the protocol supports offline messages and
+ * <tt>false</tt> otherwise.
+ */
+ public boolean isOfflineMessagingSupported()
+ {
+ return false;
+ }
+
+ /**
+ * Determines whether the protocol supports the supplied content type.
+ *
+ * @param contentType the type we want to check
+ * @return <tt>true</tt> if the protocol supports it and
+ * <tt>false</tt> otherwise.
+ */
+ public boolean isContentTypeSupported(String contentType)
+ {
+ if(contentType.equals(DEFAULT_MIME_TYPE))
+ return true;
+ else if(contentType.equals("text/html"))
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Returns the protocol provider that this operation set belongs to.
+ *
+ * @return a reference to the <tt>ProtocolProviderServiceDictImpl</tt>
+ * instance that this operation set belongs to.
+ */
+ public ProtocolProviderServiceDictImpl getParentProvider()
+ {
+ return this.parentProvider;
+ }
+
+ /**
+ * Returns a reference to the presence operation set instance used by our
+ * source provider.
+ *
+ * @return a reference to the <tt>OperationSetPersistentPresenceDictImpl</tt>
+ * instance used by this provider.
+ */
+ public OperationSetPersistentPresenceDictImpl getOpSetPersPresence()
+ {
+ return this.opSetPersPresence;
+ }
+
+ /**
+ * The method is called by the ProtocolProvider whenever a change in the
+ * registration state of the corresponding provider has occurred.
+ *
+ * @param evt ProviderStatusChangeEvent the event describing the status
+ * change.
+ */
+ public void registrationStateChanged(RegistrationStateChangeEvent evt)
+ {
+
+ }
+
+
+ /**
+ * Create, execute and display a query to a dictionary (ContactDictImpl)
+ *
+ * @param dictContact the contact containing the database name
+ * @param message the message containing the word
+ */
+ private void submitDictQuery(ContactDictImpl dictContact, Message message)
+ {
+ Message msg = this.createMessage("");
+
+ String database = dictContact.getContactID();
+ DictAdapter dictAdapter = dictContact.getDictAdapter();
+ boolean doMatch = false;
+ DictResultset fctResult;
+
+ String word;
+
+ // Formatting the query message, if the word as one or more spaces we
+ // put it between quotes to prevent errors
+ word = message.getContent().replace("\"", "").trim();
+ if (word.indexOf(' ') > 0)
+ {
+ word = "\"" + word + "\"";
+ }
+
+ // Try to get the definition of the work
+ try
+ {
+ fctResult = dictAdapter.define(database, word);
+ msg = this.createMessage(this.retrieveDefine(fctResult, word));
+ }
+ catch(DictException dex)
+ {
+ if (dex.getErrorCode() == 552)
+ { // No word found, we are going to try the match command
+ doMatch = true;
+ }
+ else
+ { // Otherwise we display the error returned by the server
+ msg = this.createMessage(dex.getErrorMessage());
+ }
+ }
+ catch(Exception ex)
+ {
+ logger.error("Failed to retrieve Definition. Error was: "
+ + ex.getMessage()
+ , ex);
+ }
+
+ if (doMatch)
+ {
+ // Trying the match command
+ try
+ {
+ fctResult = dictAdapter.match(database, word);
+ msg = this.createMessage(this.retrieveMatch(fctResult, word));
+ }
+ catch(DictException dex)
+ {
+ msg = this.createMessage(dex.getErrorMessage());
+ }
+ catch(Exception ex)
+ {
+ logger.error("Failed to retrieve Match. Error was: "
+ + ex.getMessage()
+ , ex);
+ }
+ }
+
+ // Send message
+ fireMessageReceived(msg, dictContact);
+ }
+
+ /**
+ * Generate the display of the results of the Define command
+ *
+ * @param data the result of the Define command
+ * @param word the queried word
+ * @return the formatted result
+ */
+ private String retrieveDefine(DictResultset data, String word)
+ {
+ String result;
+ DictResult resultData;
+
+ result = data.getNbResults() + " definitions found for \"" + word + "\"";
+
+ for (int i=0; i<data.getNbResults(); i++)
+ {
+ resultData = data.getResultset(i);
+
+ result += "\n";
+
+ while (resultData.hasNext())
+ {
+ result += "\n" + resultData.next();
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Generate the display of the results of the Match command
+ *
+ * @param data the result of the Match command
+ * @param word the queried word
+ * @return the formatted result
+ */
+ private String retrieveMatch(DictResultset data, String word)
+ {
+ String result = "";
+ String temp;
+ DictResult resultData;
+ boolean isStart = true;
+
+ result = "No definitions found for \""+ word +"\", perhaps you mean:\n";
+
+ for (int i=0; i<data.getNbResults(); i++)
+ {
+ resultData = data.getResultset(i);
+
+ while(resultData.hasNext())
+ {
+ temp = resultData.next();
+
+ if (isStart)
+ {
+ isStart = false;
+ }
+ else
+ {
+ result += ", ";
+ }
+
+ // Return format : dictCode "match word"
+ temp = (temp.split(" ", 2))[1];
+
+ if (temp.indexOf(" ") == -1)
+ {
+ temp = temp.substring(1, temp.length() -1);
+ }
+
+ result += temp;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/OperationSetDirectoryDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/OperationSetDirectoryDictImpl.java
new file mode 100644
index 0000000..647ecc6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/OperationSetDirectoryDictImpl.java
@@ -0,0 +1,58 @@
+package net.java.sip.communicator.impl.protocol.dict;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+
+public class OperationSetDirectoryDictImpl
+ implements OperationSetDirectory
+{
+ private static final Logger logger
+ = Logger.getLogger(OperationSetDirectoryDictImpl.class);
+
+ /**
+ * The protocol provider that created us.
+ */
+ private ProtocolProviderServiceDictImpl parentProvider = null;
+
+ /**
+ * Creates an instance of this operation set keeping a reference to the
+ * parent protocol provider and presence operation set.
+ *
+ * @param provider The provider instance that creates us.
+ */
+ public OperationSetDirectoryDictImpl(ProtocolProviderServiceDictImpl provider)
+ {
+ this.parentProvider = provider;
+ }
+
+ /**
+ * Returns directory entries according to a search and a return type
+ *
+ * @param search the search, may be an empty String
+ * @param returnType entries type
+ * @return an HashTable which links ids with visual infos - NULL otherwise
+ * @throws Exception Sends a exception if the host isn't reachable or if there isn't any dictionary
+ */
+ public Hashtable<String,String> getEntries(String search, String returnType) throws Exception
+ {
+ DictAdapter adapter = this.parentProvider.getDictAdapter();
+ Hashtable<String, String> result = null;
+
+ String temp[];
+
+ result = new Hashtable<String,String>();
+ Vector<String> dlist = adapter.getDatabases();
+ for (int i=0; i<dlist.size(); i++)
+ {
+ temp = dlist.get(i).split(" ", 2);
+ temp[1] = temp[1].replace("\"", "");
+
+ result.put(temp[0], temp[1]);
+ }
+
+ return result;
+ }
+}
+
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/OperationSetPersistentPresenceDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/OperationSetPersistentPresenceDictImpl.java
new file mode 100644
index 0000000..0bbdfba
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/OperationSetPersistentPresenceDictImpl.java
@@ -0,0 +1,1298 @@
+/*
+ * 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.dict;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * A Dict implementation of a persistent presence operation set. In order
+ * to simulate server persistence, this operation set would simply accept all
+ * unresolved contacts and resolve them immediately. A real world protocol
+ * implementation would save it on a server using methods provided by the
+ * protocol stack.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class OperationSetPersistentPresenceDictImpl
+ implements OperationSetPersistentPresence
+{
+ private static final Logger logger =
+ Logger.getLogger(OperationSetPersistentPresenceDictImpl.class);
+ /**
+ */
+ private Vector subscriptionListeners = new Vector();
+
+ /**
+ * A list of listeners registered for <tt>ServerStoredGroupChangeEvent</tt>s.
+ */
+ private Vector serverStoredGroupListeners = new Vector();
+
+ /**
+ * A list of listeners registered for
+ * <tt>ProviderPresenceStatusChangeEvent</tt>s.
+ */
+ private Vector providerPresenceStatusListeners = new Vector();
+
+ /**
+ * A list of listeneres registered for
+ * <tt>ContactPresenceStatusChangeEvent</tt>s.
+ */
+ private Vector contactPresenceStatusListeners = new Vector();
+
+ /**
+ * The root of the dict contact list.
+ */
+ private ContactGroupDictImpl contactListRoot = null;
+
+ /**
+ * The provider that created us.
+ */
+ private ProtocolProviderServiceDictImpl parentProvider = null;
+
+ /**
+ * The currently active status message.
+ */
+ private String statusMessage = "Default Status Message";
+
+ /**
+ * Our presence status.
+ */
+ private PresenceStatus presenceStatus = DictStatusEnum.ONLINE;
+
+ /**
+ * The <tt>AuthorizationHandler</tt> instance that we'd have to transmit
+ * authorization requests to for approval.
+ */
+ private AuthorizationHandler authorizationHandler = null;
+
+ /**
+ * Creates an instance of this operation set keeping a reference to the
+ * specified parent <tt>provider</tt>.
+ * @param provider the ProtocolProviderServiceDictImpl instance that
+ * created us.
+ */
+ public OperationSetPersistentPresenceDictImpl(
+ ProtocolProviderServiceDictImpl provider)
+ {
+ this.parentProvider = provider;
+ contactListRoot = new ContactGroupDictImpl("RootGroup", provider);
+
+ //add our unregistration listener
+ parentProvider.addRegistrationStateChangeListener(
+ new UnregistrationListener());
+ }
+
+ /**
+ * Dict implementation of the corresponding ProtocolProviderService
+ * method.
+ *
+ * @param listener a dummy param.
+ */
+ public void addContactPresenceStatusListener(
+ ContactPresenceStatusListener listener)
+ {
+ synchronized(contactPresenceStatusListeners)
+ {
+ if (!contactPresenceStatusListeners.contains(listener))
+ contactPresenceStatusListeners.add(listener);
+ }
+ }
+
+ /**
+ * Notifies all registered listeners of the new event.
+ *
+ * @param source the contact that has caused the event.
+ * @param parentGroup the group that contains the source contact.
+ * @param oldValue the status that the source contact detained before
+ * changing it.
+ */
+ public void fireContactPresenceStatusChangeEvent(ContactDictImpl source,
+ ContactGroup parentGroup,
+ PresenceStatus oldValue)
+ {
+ ContactPresenceStatusChangeEvent evt
+ = new ContactPresenceStatusChangeEvent(source, parentProvider
+ , parentGroup, oldValue, source.getPresenceStatus());
+
+ Iterator listeners = null;
+ synchronized(contactPresenceStatusListeners)
+ {
+ listeners = new ArrayList(contactPresenceStatusListeners).iterator();
+ }
+
+
+ while(listeners.hasNext())
+ {
+ ContactPresenceStatusListener listener
+ = (ContactPresenceStatusListener)listeners.next();
+
+ listener.contactPresenceStatusChanged(evt);
+ }
+ }
+
+
+ /**
+ * Notifies all registered listeners of the new event.
+ *
+ * @param source the contact that has caused the event.
+ * @param parentGroup the group that contains the source contact.
+ * @param eventID an identifier of the event to dispatch.
+ */
+ public void fireSubscriptionEvent(ContactDictImpl source,
+ ContactGroup parentGroup,
+ int eventID)
+ {
+ SubscriptionEvent evt = new SubscriptionEvent(source
+ , this.parentProvider
+ , parentGroup
+ , eventID);
+
+ Iterator listeners = null;
+ synchronized (subscriptionListeners)
+ {
+ listeners = new ArrayList(subscriptionListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ SubscriptionListener listener
+ = (SubscriptionListener) listeners.next();
+
+ if(eventID == SubscriptionEvent.SUBSCRIPTION_CREATED)
+ {
+ listener.subscriptionCreated(evt);
+ }
+ else if (eventID == SubscriptionEvent.SUBSCRIPTION_FAILED)
+ {
+ listener.subscriptionFailed(evt);
+ }
+ else if (eventID == SubscriptionEvent.SUBSCRIPTION_REMOVED)
+ {
+ listener.subscriptionRemoved(evt);
+ }
+ }
+ }
+
+ /**
+ * Notifies all registered listeners of the new event.
+ *
+ * @param source the contact that has been moved..
+ * @param oldParent the group where the contact was located before being
+ * moved.
+ * @param newParent the group where the contact has been moved.
+ */
+ public void fireSubscriptionMovedEvent(Contact source,
+ ContactGroup oldParent,
+ ContactGroup newParent)
+ {
+ SubscriptionMovedEvent evt = new SubscriptionMovedEvent(source
+ , this.parentProvider
+ , oldParent
+ , newParent);
+
+ Iterator listeners = null;
+ synchronized (subscriptionListeners)
+ {
+ listeners = new ArrayList(subscriptionListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ SubscriptionListener listener
+ = (SubscriptionListener) listeners.next();
+
+ listener.subscriptionMoved(evt);
+ }
+ }
+
+
+ /**
+ * Notifies all registered listeners of the new event.
+ *
+ * @param source the contact that has caused the event.
+ * @param eventID an identifier of the event to dispatch.
+ */
+ public void fireServerStoredGroupEvent(ContactGroupDictImpl source,
+ int eventID)
+ {
+ ServerStoredGroupEvent evt = new ServerStoredGroupEvent(
+ source, eventID, (ContactGroupDictImpl)source.getParentContactGroup()
+ , this.parentProvider, this);
+
+ Iterator listeners = null;
+ synchronized (serverStoredGroupListeners)
+ {
+ listeners = new ArrayList(serverStoredGroupListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ ServerStoredGroupListener listener
+ = (ServerStoredGroupListener) listeners.next();
+
+ if(eventID == ServerStoredGroupEvent.GROUP_CREATED_EVENT)
+ {
+ listener.groupCreated(evt);
+ }
+ else if(eventID == ServerStoredGroupEvent.GROUP_RENAMED_EVENT)
+ {
+ listener.groupNameChanged(evt);
+ }
+ else if(eventID == ServerStoredGroupEvent.GROUP_REMOVED_EVENT)
+ {
+ listener.groupRemoved(evt);
+ }
+ }
+ }
+
+ /**
+ * Notifies all registered listeners of the new event.
+ *
+ * @param oldValue the presence status we were in before the change.
+ */
+ public void fireProviderStatusChangeEvent(PresenceStatus oldValue)
+ {
+ ProviderPresenceStatusChangeEvent evt
+ = new ProviderPresenceStatusChangeEvent(this.parentProvider,
+ oldValue, this.getPresenceStatus());
+
+ Iterator listeners = null;
+ synchronized (providerPresenceStatusListeners)
+ {
+ listeners = new ArrayList(providerPresenceStatusListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ ProviderPresenceStatusListener listener
+ = (ProviderPresenceStatusListener) listeners.next();
+
+ listener.providerStatusChanged(evt);
+ }
+ }
+
+ /**
+ * Dict implementation of the corresponding ProtocolProviderService
+ * method.
+ *
+ * @param listener a dummy param.
+ */
+ public void addProviderPresenceStatusListener(
+ ProviderPresenceStatusListener listener)
+ {
+ synchronized(providerPresenceStatusListeners)
+ {
+ if (!providerPresenceStatusListeners.contains(listener))
+ this.providerPresenceStatusListeners.add(listener);
+ }
+ }
+
+ /**
+ * Registers a listener that would receive events upon changes in server
+ * stored groups.
+ *
+ * @param listener a ServerStoredGroupChangeListener impl that would
+ * receive events upong group changes.
+ */
+ public void addServerStoredGroupChangeListener(ServerStoredGroupListener
+ listener)
+ {
+ synchronized(serverStoredGroupListeners)
+ {
+ if (!serverStoredGroupListeners.contains(listener))
+ serverStoredGroupListeners.add(listener);
+ }
+ }
+
+ /**
+ * Dict implementation of the corresponding ProtocolProviderService
+ * method.
+ *
+ * @param listener the SubscriptionListener to register
+ */
+ public void addSubsciptionListener(SubscriptionListener listener)
+ {
+ synchronized(subscriptionListeners)
+ {
+ if (!subscriptionListeners.contains(listener))
+ this.subscriptionListeners.add(listener);
+ }
+ }
+
+ /**
+ * Creates a group with the specified name and parent in the server
+ * stored contact list.
+ *
+ * @param parent the group where the new group should be created
+ * @param groupName the name of the new group to create.
+ */
+ public void createServerStoredContactGroup(ContactGroup parent,
+ String groupName)
+ {
+ ContactGroupDictImpl newGroup
+ = new ContactGroupDictImpl(groupName, parentProvider);
+
+ ((ContactGroupDictImpl)parent).addSubgroup(newGroup);
+
+ this.fireServerStoredGroupEvent(
+ newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
+ }
+
+ /**
+ * A Dict Provider method to use for fast filling of a contact list.
+ *
+ * @param contactGroup the group to add
+ */
+ public void addDictGroup(ContactGroupDictImpl contactGroup)
+ {
+ contactListRoot.addSubgroup(contactGroup);
+ }
+
+ /**
+ * A Dict Provider method to use for fast filling of a contact list.
+ * This method would add both the group and fire an event.
+ *
+ * @param parent the group where <tt>contactGroup</tt> should be added.
+ * @param contactGroup the group to add
+ */
+ public void addDictGroupAndFireEvent(
+ ContactGroupDictImpl parent
+ , ContactGroupDictImpl contactGroup)
+ {
+ parent.addSubgroup(contactGroup);
+
+ this.fireServerStoredGroupEvent(
+ contactGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
+ }
+
+
+ /**
+ * Returns a reference to the contact with the specified ID in case we
+ * have a subscription for it and null otherwise/
+ *
+ * @param contactID a String identifier of the contact which we're
+ * seeking a reference of.
+ * @return a reference to the Contact with the specified
+ * <tt>contactID</tt> or null if we don't have a subscription for the
+ * that identifier.
+ */
+ public Contact findContactByID(String contactID)
+ {
+ return contactListRoot.findContactByID(contactID);
+ }
+
+ /**
+ * Sets the specified status message.
+ * @param statusMessage a String containing the new status message.
+ */
+ public void setStatusMessage(String statusMessage)
+ {
+ this.statusMessage = statusMessage;
+ }
+
+ /**
+ * Returns the status message that was last set through
+ * setCurrentStatusMessage.
+ *
+ * @return the last status message that we have requested and the aim
+ * server has confirmed.
+ */
+ public String getCurrentStatusMessage()
+ {
+ return statusMessage;
+ }
+
+ /**
+ * Returns the protocol specific contact instance representing the local
+ * user.
+ *
+ * @return the Contact (address, phone number, or uin) that the Provider
+ * implementation is communicating on behalf of.
+ */
+ public Contact getLocalContact()
+ {
+ return null;
+ }
+
+ /**
+ * Returns a PresenceStatus instance representing the state this provider
+ * is currently in.
+ *
+ * @return the PresenceStatus last published by this provider.
+ */
+ public PresenceStatus getPresenceStatus()
+ {
+ return presenceStatus;
+ }
+
+ /**
+ * Returns the root group of the server stored contact list.
+ *
+ * @return the root ContactGroup for the ContactList stored by this
+ * service.
+ */
+ public ContactGroup getServerStoredContactListRoot()
+ {
+ return contactListRoot;
+ }
+
+ /**
+ * Returns the set of PresenceStatus objects that a user of this service
+ * may request the provider to enter.
+ *
+ * @return Iterator a PresenceStatus array containing "enterable" status
+ * instances.
+ */
+ public Iterator getSupportedStatusSet()
+ {
+ return DictStatusEnum.supportedStatusSet();
+ }
+
+ /**
+ * Removes the specified contact from its current parent and places it
+ * under <tt>newParent</tt>.
+ *
+ * @param contactToMove the <tt>Contact</tt> to move
+ * @param newParent the <tt>ContactGroup</tt> where <tt>Contact</tt>
+ * would be placed.
+ */
+ public void moveContactToGroup(Contact contactToMove,
+ ContactGroup newParent)
+ {
+ ContactDictImpl dictContact
+ = (ContactDictImpl)contactToMove;
+
+ ContactGroupDictImpl parentDictGroup
+ = findContactParent(dictContact);
+
+ parentDictGroup.removeContact(dictContact);
+
+ //if this is a volatile contact then we haven't really subscribed to
+ //them so we'd need to do so here
+ if(!dictContact.isPersistent())
+ {
+ //first tell everyone that the volatile contact was removed
+ fireSubscriptionEvent(dictContact
+ , parentDictGroup
+ , SubscriptionEvent.SUBSCRIPTION_REMOVED);
+
+ try
+ {
+ //now subscribe
+ this.subscribe(newParent, contactToMove.getAddress());
+
+ //now tell everyone that we've added the contact
+ fireSubscriptionEvent(dictContact
+ , newParent
+ , SubscriptionEvent.SUBSCRIPTION_CREATED);
+ }
+ catch (Exception ex)
+ {
+ logger.error("Failed to move contact "
+ + dictContact.getAddress()
+ , ex);
+ }
+ }
+ else
+ {
+ ( (ContactGroupDictImpl) newParent)
+ .addContact(dictContact);
+
+ fireSubscriptionMovedEvent(contactToMove
+ , parentDictGroup
+ , newParent);
+ }
+ }
+
+ /**
+ * Requests the provider to enter into a status corresponding to the
+ * specified paramters.
+ *
+ * @param status the PresenceStatus as returned by
+ * getRequestableStatusSet
+ * @param statusMessage the message that should be set as the reason to
+ * enter that status
+ * @throws IllegalArgumentException if the status requested is not a
+ * valid PresenceStatus supported by this provider.
+ * @throws IllegalStateException if the provider is not currently
+ * registered.
+ * @throws OperationFailedException with code NETWORK_FAILURE if
+ * publishing the status fails due to a network error.
+ */
+ public void publishPresenceStatus(PresenceStatus status,
+ String statusMessage) throws
+ IllegalArgumentException, IllegalStateException,
+ OperationFailedException
+ {
+ PresenceStatus oldPresenceStatus = this.presenceStatus;
+ this.presenceStatus = status;
+ this.statusMessage = statusMessage;
+
+ this.fireProviderStatusChangeEvent(oldPresenceStatus);
+
+ //since we are not a real protocol, we set the contact presence status
+ //ourselves and make them have the same status as ours.
+ changePresenceStatusForAllContacts( getServerStoredContactListRoot()
+ , getPresenceStatus());
+
+ //now check whether we are in someone else's contact list and modify
+ //our status there
+ List contacts = findContactsPointingToUs();
+
+ Iterator contactsIter = contacts.iterator();
+ while (contactsIter.hasNext())
+ {
+ ContactDictImpl contact
+ = (ContactDictImpl) contactsIter.next();
+
+ PresenceStatus oldStatus = contact.getPresenceStatus();
+ contact.setPresenceStatus(status);
+ contact.getParentPresenceOperationSet()
+ .fireContactPresenceStatusChangeEvent(
+ contact
+ , contact.getParentContactGroup()
+ , oldStatus);
+
+ }
+ }
+
+
+
+ /**
+ * Get the PresenceStatus for a particular contact.
+ *
+ * @param contactIdentifier the identifier of the contact whose status
+ * we're interested in.
+ * @return PresenceStatus the <tt>PresenceStatus</tt> of the specified
+ * <tt>contact</tt>
+ * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
+ * known to the underlying protocol provider
+ * @throws IllegalStateException if the underlying protocol provider is
+ * not registered/signed on a public service.
+ * @throws OperationFailedException with code NETWORK_FAILURE if
+ * retrieving the status fails due to errors experienced during
+ * network communication
+ */
+ public PresenceStatus queryContactStatus(String contactIdentifier) throws
+ IllegalArgumentException, IllegalStateException,
+ OperationFailedException
+ {
+ return findContactByID(contactIdentifier).getPresenceStatus();
+ }
+
+ /**
+ * Sets the presence status of <tt>contact</tt> to <tt>newStatus</tt>.
+ *
+ * @param contact the <tt>ContactDictImpl</tt> whose status we'd like
+ * to set.
+ * @param newStatus the new status we'd like to set to <tt>contact</tt>.
+ */
+ private void changePresenceStatusForContact(
+ ContactDictImpl contact
+ , PresenceStatus newStatus)
+ {
+ PresenceStatus oldStatus = contact.getPresenceStatus();
+ contact.setPresenceStatus(newStatus);
+
+ fireContactPresenceStatusChangeEvent(
+ contact, findContactParent(contact), oldStatus);
+ }
+
+ /**
+ * Sets the presence status of all <tt>contact</tt>s in our contact list
+ * (except those that correspond to another provider registered with SC)
+ * to <tt>newStatus</tt>.
+ *
+ * @param newStatus the new status we'd like to set to <tt>contact</tt>.
+ * @param parent the group in which we'd have to update the status of all
+ * direct and indirect child contacts.
+ */
+ private void changePresenceStatusForAllContacts(ContactGroup parent,
+ PresenceStatus newStatus)
+ {
+ //first set the status for contacts in this group
+ Iterator childContacts = parent.contacts();
+
+ while(childContacts.hasNext())
+ {
+ ContactDictImpl contact
+ = (ContactDictImpl)childContacts.next();
+
+ if(findProviderForDictUserID(contact.getAddress()) != null)
+ {
+ //this is a contact corresponding to another SIP Communicator
+ //provider so we won't change it's status here.
+ continue;
+ }
+ PresenceStatus oldStatus = contact.getPresenceStatus();
+ contact.setPresenceStatus(newStatus);
+
+ fireContactPresenceStatusChangeEvent(
+ contact, parent, oldStatus);
+ }
+
+ //now call this method recursively for all subgroups
+ Iterator subgroups = parent.subgroups();
+
+ while(subgroups.hasNext())
+ {
+ ContactGroup subgroup = (ContactGroup)subgroups.next();
+ changePresenceStatusForAllContacts(subgroup, newStatus);
+ }
+ }
+
+
+ /**
+ * Removes the specified listener so that it won't receive any further
+ * updates on contact presence status changes
+ *
+ * @param listener the listener to remove.
+ */
+ public void removeContactPresenceStatusListener(
+ ContactPresenceStatusListener listener)
+ {
+ synchronized(contactPresenceStatusListeners)
+ {
+ contactPresenceStatusListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Unregisters the specified listener so that it does not receive further
+ * events upon changes in local presence status.
+ *
+ * @param listener ProviderPresenceStatusListener
+ */
+ public void removeProviderPresenceStatusListener(
+ ProviderPresenceStatusListener listener)
+ {
+ synchronized(providerPresenceStatusListeners)
+ {
+ this.providerPresenceStatusListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Returns the group that is parent of the specified dictGroup or null
+ * if no parent was found.
+ * @param dictGroup the group whose parent we're looking for.
+ * @return the ContactGroupDictImpl instance that dictGroup
+ * belongs to or null if no parent was found.
+ */
+ public ContactGroupDictImpl findGroupParent(
+ ContactGroupDictImpl dictGroup)
+ {
+ return contactListRoot.findGroupParent(dictGroup);
+ }
+
+ /**
+ * Returns the group that is parent of the specified dictContact or
+ * null if no parent was found.
+ * @param dictContact the contact whose parent we're looking for.
+ * @return the ContactGroupDictImpl instance that dictContact
+ * belongs to or null if no parent was found.
+ */
+ public ContactGroupDictImpl findContactParent(
+ ContactDictImpl dictContact)
+ {
+ return (ContactGroupDictImpl)dictContact
+ .getParentContactGroup();
+ }
+
+
+ /**
+ * Removes the specified group from the server stored contact list.
+ *
+ * @param group the group to remove.
+ *
+ * @throws IllegalArgumentException if <tt>group</tt> was not found in this
+ * protocol's contact list.
+ */
+ public void removeServerStoredContactGroup(ContactGroup group)
+ throws IllegalArgumentException
+ {
+ ContactGroupDictImpl dictGroup
+ = (ContactGroupDictImpl)group;
+
+ ContactGroupDictImpl parent = findGroupParent(dictGroup);
+
+ if(parent == null){
+ throw new IllegalArgumentException(
+ "group " + group
+ + " does not seem to belong to this protocol's contact list.");
+ }
+
+ parent.removeSubGroup(dictGroup);
+
+ this.fireServerStoredGroupEvent(
+ dictGroup, ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
+ }
+
+
+ /**
+ * Removes the specified group change listener so that it won't receive
+ * any further events.
+ *
+ * @param listener the ServerStoredGroupChangeListener to remove
+ */
+ public void removeServerStoredGroupChangeListener(ServerStoredGroupListener
+ listener)
+ {
+ synchronized(serverStoredGroupListeners)
+ {
+ serverStoredGroupListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Removes the specified subscription listener.
+ *
+ * @param listener the listener to remove.
+ */
+ public void removeSubscriptionListener(SubscriptionListener listener)
+ {
+ synchronized(subscriptionListeners)
+ {
+ this.subscriptionListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Renames the specified group from the server stored contact list.
+ *
+ * @param group the group to rename.
+ * @param newName the new name of the group.
+ */
+ public void renameServerStoredContactGroup(ContactGroup group,
+ String newName)
+ {
+ ((ContactGroupDictImpl)group).setGroupName(newName);
+
+ this.fireServerStoredGroupEvent(
+ (ContactGroupDictImpl)group, ServerStoredGroupEvent.GROUP_RENAMED_EVENT);
+ }
+
+ /**
+ * Handler for incoming authorization requests.
+ *
+ * @param handler an instance of an AuthorizationHandler for
+ * authorization requests coming from other users requesting
+ * permission add us to their contact list.
+ */
+ public void setAuthorizationHandler(AuthorizationHandler handler)
+ {
+ this.authorizationHandler = handler;
+ }
+
+ /**
+ * Persistently adds a subscription for the presence status of the
+ * contact corresponding to the specified contactIdentifier and indicates
+ * that it should be added to the specified group of the server stored
+ * contact list.
+ *
+ * @param parent the parent group of the server stored contact list
+ * where the contact should be added. <p>
+ * @param contactIdentifier the contact whose status updates we are
+ * subscribing for.
+ * @throws IllegalArgumentException if <tt>contact</tt> or
+ * <tt>parent</tt> are not a contact known to the underlying protocol
+ * provider.
+ * @throws IllegalStateException if the underlying protocol provider is
+ * not registered/signed on a public service.
+ * @throws OperationFailedException with code NETWORK_FAILURE if
+ * subscribing fails due to errors experienced during network
+ * communication
+ */
+ public void subscribe(ContactGroup parent, String contactIdentifier) throws
+ IllegalArgumentException, IllegalStateException,
+ OperationFailedException
+ {
+ ContactDictImpl contact = new ContactDictImpl(
+ contactIdentifier
+ , parentProvider);
+
+ ((ContactGroupDictImpl)parent).addContact(contact);
+
+ fireSubscriptionEvent(contact,
+ parent,
+ SubscriptionEvent.SUBSCRIPTION_CREATED);
+
+ //notify presence listeners for the status change.
+ fireContactPresenceStatusChangeEvent(contact
+ , parent
+ , DictStatusEnum.ONLINE);
+ }
+
+
+ /**
+ * Depending on whether <tt>contact</tt> corresponds to another protocol
+ * provider installed in sip-communicator, this method would either deliver
+ * it to that provider or simulate a corresponding request from the
+ * destination contact and make return a response after it has received
+ * one If the destination contact matches us, then we'll ask the user to
+ * act upon the request, and return the response.
+ *
+ * @param request the authorization request that we'd like to deliver to the
+ * desination <tt>contact</tt>.
+ * @param contact the <tt>Contact</tt> to notify
+ *
+ * @return the <tt>AuthorizationResponse</tt> that has been given or
+ * generated in response to <tt>request</tt>.
+ */
+ private AuthorizationResponse deliverAuthorizationRequest(
+ AuthorizationRequest request,
+ Contact contact)
+ {
+ String userID = contact.getAddress();
+
+ //if the user id is our own id, then this request is being routed to us
+ //from another instance of the dict provider.
+ if (userID.equals(this.parentProvider.getAccountID().getUserID()))
+ {
+ //check who is the provider sending the message
+ String sourceUserID = contact.getProtocolProvider()
+ .getAccountID().getUserID();
+
+ //check whether they are in our contact list
+ Contact from = findContactByID(sourceUserID);
+
+ //and if not - add them there as volatile.
+ if (from == null)
+ {
+ from = createVolatileContact(sourceUserID);
+ }
+
+ //and now handle the request.
+ return authorizationHandler.processAuthorisationRequest(
+ request, from);
+ }
+ else
+ {
+ //if userID is not our own, try a check whether another provider
+ //has that id and if yes - deliver the request to them.
+ ProtocolProviderServiceDictImpl dictProvider
+ = this.findProviderForDictUserID(userID);
+ if (dictProvider != null)
+ {
+ OperationSetPersistentPresenceDictImpl opSetPersPresence
+ = (OperationSetPersistentPresenceDictImpl)
+ dictProvider.getOperationSet(
+ OperationSetPersistentPresence.class);
+ return opSetPersPresence
+ .deliverAuthorizationRequest(request, contact);
+ }
+ else
+ {
+ //if we got here then "to" is simply someone in our contact
+ //list so let's just simulate a reciproce request and generate
+ //a response accordingly.
+
+ //pretend that the remote contact is asking for authorization
+ authorizationHandler.processAuthorisationRequest(
+ request, contact);
+
+ //and now pretend that the remote contact has granted us
+ //authorization
+ return new AuthorizationResponse(AuthorizationResponse.ACCEPT
+ , "You are welcome!");
+ }
+ }
+ }
+
+ /**
+ * Adds a subscription for the presence status of the contact
+ * corresponding to the specified contactIdentifier.
+ *
+ * @param contactIdentifier the identifier of the contact whose status
+ * updates we are subscribing for. <p>
+ * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
+ * known to the underlying protocol provider
+ * @throws IllegalStateException if the underlying protocol provider is
+ * not registered/signed on a public service.
+ * @throws OperationFailedException with code NETWORK_FAILURE if
+ * subscribing fails due to errors experienced during network
+ * communication
+ */
+ public void subscribe(String contactIdentifier) throws
+ IllegalArgumentException, IllegalStateException,
+ OperationFailedException
+ {
+ //subscribe(contactListRoot, contactIdentifier);
+
+ }
+
+ /**
+ * Removes a subscription for the presence status of the specified
+ * contact.
+ *
+ * @param contact the contact whose status updates we are unsubscribing
+ * from.
+ * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
+ * known to the underlying protocol provider
+ * @throws IllegalStateException if the underlying protocol provider is
+ * not registered/signed on a public service.
+ * @throws OperationFailedException with code NETWORK_FAILURE if
+ * unsubscribing fails due to errors experienced during network
+ * communication
+ */
+ public void unsubscribe(Contact contact) throws IllegalArgumentException,
+ IllegalStateException, OperationFailedException
+ {
+ ContactGroupDictImpl parentGroup
+ = (ContactGroupDictImpl)((ContactDictImpl)contact)
+ .getParentContactGroup();
+
+ parentGroup.removeContact((ContactDictImpl)contact);
+
+ fireSubscriptionEvent((ContactDictImpl)contact,
+ ((ContactDictImpl)contact).getParentContactGroup()
+ , SubscriptionEvent.SUBSCRIPTION_REMOVED);
+ }
+
+ /**
+ * Creates and returns a unresolved contact from the specified
+ * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
+ * to establish a network connection and resolve the newly created Contact
+ * against the server. The protocol provider may will later try and resolve
+ * the contact. When this happens the corresponding event would notify
+ * interested subscription listeners.
+ *
+ * @param address an identifier of the contact that we'll be creating.
+ * @param persistentData a String returned Contact's getPersistentData()
+ * method during a previous run and that has been persistently stored
+ * locally.
+ * @return the unresolved <tt>Contact</tt> created from the specified
+ * <tt>address</tt> and <tt>persistentData</tt>
+ */
+ public Contact createUnresolvedContact(String address,
+ String persistentData)
+ {
+ return createUnresolvedContact(address
+ , persistentData
+ , getServerStoredContactListRoot());
+ }
+
+ /**
+ * Creates and returns a unresolved contact from the specified
+ * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
+ * to establish a network connection and resolve the newly created Contact
+ * against the server. The protocol provider may will later try and resolve
+ * the contact. When this happens the corresponding event would notify
+ * interested subscription listeners.
+ *
+ * @param address an identifier of the contact that we'll be creating.
+ * @param persistentData a String returned Contact's getPersistentData()
+ * method during a previous run and that has been persistently stored
+ * locally.
+ * @param parent the group where the unresolved contact is
+ * supposed to belong to.
+ *
+ * @return the unresolved <tt>Contact</tt> created from the specified
+ * <tt>address</tt> and <tt>persistentData</tt>
+ */
+ public Contact createUnresolvedContact(String address,
+ String persistentData,
+ ContactGroup parent)
+ {
+
+ ContactDictImpl contact = new ContactDictImpl(
+ address
+ , parentProvider);
+ contact.setResolved(false);
+
+ ( (ContactGroupDictImpl) parent).addContact(contact);
+
+ fireSubscriptionEvent(contact,
+ parent,
+ SubscriptionEvent.SUBSCRIPTION_CREATED);
+
+ //since we don't have any server, we'll simply resolve the contact
+ //ourselves as if we've just received an event from the server telling
+ //us that it has been resolved.
+ contact.setResolved(true);
+ fireSubscriptionEvent(contact, parent, SubscriptionEvent.SUBSCRIPTION_RESOLVED);
+
+ //since we are not a real protocol, we set the contact presence status
+ //ourselves
+ changePresenceStatusForContact( contact, getPresenceStatus());
+
+ return contact;
+ }
+
+ /**
+ * Looks for a dict protocol provider registered for a user id matching
+ * <tt>dictUserID</tt>.
+ *
+ * @param dictUserID the ID of the Dict user whose corresponding
+ * protocol provider we'd like to find.
+ * @return ProtocolProviderServiceDictImpl a dict protocol
+ * provider registered for a user with id <tt>dictUserID</tt> or null
+ * if there is no such protocol provider.
+ */
+ public ProtocolProviderServiceDictImpl
+ findProviderForDictUserID(String dictUserID)
+ {
+ BundleContext bc = DictActivator.getBundleContext();
+
+ String osgiQuery = "(&"
+ + "(" + ProtocolProviderFactory.PROTOCOL
+ + "=Dict)"
+ + "(" + ProtocolProviderFactory.USER_ID
+ + "=" + dictUserID + ")"
+ + ")";
+
+ ServiceReference[] refs = null;
+ try
+ {
+ refs = bc.getServiceReferences(
+ ProtocolProviderService.class.getName()
+ ,osgiQuery);
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ logger.error("Failed to execute the following osgi query: "
+ + osgiQuery
+ , ex);
+ }
+
+ if(refs != null && refs.length > 0)
+ {
+ return (ProtocolProviderServiceDictImpl)bc.getService(refs[0]);
+ }
+
+ return null;
+ }
+
+ /**
+ * Looks for dict protocol providers that have added us to their
+ * contact list and returns list of all contacts representing us in these
+ * providers.
+ *
+ * @return a list of all contacts in other providers' contact lists that
+ * point to us.
+ */
+ public List findContactsPointingToUs()
+ {
+ List contacts = new LinkedList();
+ BundleContext bc = DictActivator.getBundleContext();
+
+ String osgiQuery =
+ "(" + ProtocolProviderFactory.PROTOCOL
+ + "=Dict)";
+
+ ServiceReference[] refs = null;
+ try
+ {
+ refs = bc.getServiceReferences(
+ ProtocolProviderService.class.getName()
+ ,osgiQuery);
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ logger.error("Failed to execute the following osgi query: "
+ + osgiQuery
+ , ex);
+ }
+
+ for (int i =0; refs != null && i < refs.length; i++)
+ {
+ ProtocolProviderServiceDictImpl gibProvider
+ = (ProtocolProviderServiceDictImpl)bc.getService(refs[i]);
+
+ OperationSetPersistentPresenceDictImpl opSetPersPresence
+ = (OperationSetPersistentPresenceDictImpl)gibProvider
+ .getOperationSet(OperationSetPersistentPresence.class);
+
+ Contact contact = opSetPersPresence.findContactByID(
+ parentProvider.getAccountID().getUserID());
+
+ if (contact != null)
+ contacts.add(contact);
+ }
+
+ return contacts;
+ }
+
+
+ /**
+ * Creates and returns a unresolved contact group from the specified
+ * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
+ * to establish a network connection and resolve the newly created
+ * <tt>ContactGroup</tt> against the server or the contact itself. The
+ * protocol provider will later resolve the contact group. When this happens
+ * the corresponding event would notify interested subscription listeners.
+ *
+ * @param groupUID an identifier, returned by ContactGroup's getGroupUID,
+ * that the protocol provider may use in order to create the group.
+ * @param persistentData a String returned ContactGroups's
+ * getPersistentData() method during a previous run and that has been
+ * persistently stored locally.
+ * @param parentGroup the group under which the new group is to be created
+ * or null if this is group directly underneath the root.
+ * @return the unresolved <tt>ContactGroup</tt> created from the specified
+ * <tt>uid</tt> and <tt>persistentData</tt>
+ */
+ public ContactGroup createUnresolvedContactGroup(String groupUID,
+ String persistentData, ContactGroup parentGroup)
+ {
+ ContactGroupDictImpl newGroup
+ = new ContactGroupDictImpl(
+ ContactGroupDictImpl.createNameFromUID(groupUID)
+ , parentProvider);
+ newGroup.setResolved(false);
+
+ //if parent is null then we're adding under root.
+ if(parentGroup == null)
+ parentGroup = getServerStoredContactListRoot();
+
+ ((ContactGroupDictImpl)parentGroup).addSubgroup(newGroup);
+
+ this.fireServerStoredGroupEvent(
+ newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
+
+ return newGroup;
+ }
+
+ private class UnregistrationListener
+ implements RegistrationStateChangeListener
+ {
+ /**
+ * The method is called by a ProtocolProvider implementation whenver
+ * a change in the registration state of the corresponding provider had
+ * occurred. The method is particularly interested in events stating
+ * that the dict provider has unregistered so that it would fire
+ * status change events for all contacts in our buddy list.
+ *
+ * @param evt ProviderStatusChangeEvent the event describing the status
+ * change.
+ */
+ public void registrationStateChanged(RegistrationStateChangeEvent evt)
+ {
+ if (! evt.getNewState().equals(RegistrationState.UNREGISTERED)
+ && !evt.getNewState().equals(RegistrationState.AUTHENTICATION_FAILED)
+ && !evt.getNewState().equals(RegistrationState.CONNECTION_FAILED))
+ {
+ return;
+ }
+
+ //send event notifications saying that all our buddies are
+ //offline. The icq protocol does not implement top level buddies
+ //nor subgroups for top level groups so a simple nested loop
+ //would be enough.
+ Iterator groupsIter = getServerStoredContactListRoot()
+ .subgroups();
+ while (groupsIter.hasNext())
+ {
+ ContactGroupDictImpl group
+ = (ContactGroupDictImpl) groupsIter.next();
+
+ Iterator contactsIter = group.contacts();
+
+ while (contactsIter.hasNext())
+ {
+ ContactDictImpl contact
+ = (ContactDictImpl) contactsIter.next();
+
+ PresenceStatus oldContactStatus
+ = contact.getPresenceStatus();
+
+ if (!oldContactStatus.isOnline())
+ continue;
+
+ contact.setPresenceStatus(DictStatusEnum.OFFLINE);
+
+ fireContactPresenceStatusChangeEvent(
+ contact
+ , contact.getParentContactGroup()
+ , oldContactStatus);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the volatile group or null if this group has not yet been
+ * created.
+ *
+ * @return a volatile group existing in our contact list or <tt>null</tt>
+ * if such a group has not yet been created.
+ */
+ private ContactGroupDictImpl getNonPersistentGroup()
+ {
+ for (int i = 0
+ ; i < getServerStoredContactListRoot().countSubgroups()
+ ; i++)
+ {
+ ContactGroupDictImpl gr =
+ (ContactGroupDictImpl)getServerStoredContactListRoot()
+ .getGroup(i);
+
+ if(!gr.isPersistent())
+ return gr;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Creates a non persistent contact for the specified address. This would
+ * also create (if necessary) a group for volatile contacts that would not
+ * be added to the server stored contact list. This method would have no
+ * effect on the server stored contact list.
+ *
+ * @param contactAddress the address of the volatile contact we'd like to
+ * create.
+ * @return the newly created volatile contact.
+ */
+ public ContactDictImpl createVolatileContact(String contactAddress)
+ {
+ //First create the new volatile contact;
+ ContactDictImpl newVolatileContact
+ = new ContactDictImpl(contactAddress
+ , this.parentProvider);
+ newVolatileContact.setPersistent(false);
+
+
+ //Check whether a volatile group already exists and if not create
+ //one
+ ContactGroupDictImpl theVolatileGroup = getNonPersistentGroup();
+
+
+ //if the parent volatile group is null then we create it
+ if (theVolatileGroup == null)
+ {
+ List emptyBuddies = new LinkedList();
+ theVolatileGroup = new ContactGroupDictImpl(
+ "NotInContactList"
+ , parentProvider);
+ theVolatileGroup.setResolved(false);
+ theVolatileGroup.setPersistent(false);
+
+ this.contactListRoot.addSubgroup(theVolatileGroup);
+
+ fireServerStoredGroupEvent(theVolatileGroup
+ , ServerStoredGroupEvent.GROUP_CREATED_EVENT);
+ }
+
+ //now add the volatile contact instide it
+ theVolatileGroup.addContact(newVolatileContact);
+ fireSubscriptionEvent(newVolatileContact
+ , theVolatileGroup
+ , SubscriptionEvent.SUBSCRIPTION_CREATED);
+
+ return newVolatileContact;
+ }
+
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/ProtocolIconDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/ProtocolIconDictImpl.java
new file mode 100644
index 0000000..e906af1
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/ProtocolIconDictImpl.java
@@ -0,0 +1,98 @@
+/*
+ * 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.dict;
+
+import java.io.*;
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Reperesents the Dict protocol icon. Implements the <tt>ProtocolIcon</tt>
+ * interface in order to provide a dict logo image in two different sizes.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class ProtocolIconDictImpl
+ implements ProtocolIcon
+{
+ private static Logger logger = Logger.getLogger(ProtocolIconDictImpl.class);
+
+ /**
+ * A hash table containing the protocol icon in different sizes.
+ */
+ private static Hashtable<String,byte[]> iconsTable = new Hashtable<String,byte[]>();
+ static {
+ iconsTable.put(ProtocolIcon.ICON_SIZE_16x16,
+ loadIcon("resources/images/protocol/dict/dict-16x16.png"));
+
+ iconsTable.put(ProtocolIcon.ICON_SIZE_64x64,
+ loadIcon("resources/images/protocol/dict/dict-64x64.png"));
+ }
+
+ /**
+ * Implements the <tt>ProtocolIcon.getSupportedSizes()</tt> method. Returns
+ * an iterator to a set containing the supported icon sizes.
+ * @return Returns an iterator to a set containing the supported icon sizes
+ */
+ public Iterator getSupportedSizes()
+ {
+ return iconsTable.keySet().iterator();
+ }
+
+ /**
+ * Returns TRUE if an icon with the given size is supported, FALSE otherwise.
+ * @param iconSize The size of the icon, that we want to know if it is
+ * supported.
+ * @return Returns true if the size is supported. False otherwise.
+ */
+ public boolean isSizeSupported(String iconSize)
+ {
+ return iconsTable.containsKey(iconSize);
+ }
+
+ /**
+ * Returns the icon image in the given size.
+ * @param iconSize The icon size one of ICON_SIZE_XXX constants
+ * @return Returns a byte[] containing the pixels of the icon for the given
+ * size.
+ */
+ public byte[] getIcon(String iconSize)
+ {
+ return iconsTable.get(iconSize);
+ }
+
+ /**
+ * Returns the icon image used to represent the protocol connecting state.
+ * @return Returns the icon image used to represent the protocol connecting state.
+ */
+ public byte[] getConnectingIcon()
+ {
+ return iconsTable.get(ProtocolIcon.ICON_SIZE_16x16);
+ }
+
+ /**
+ * Loads an image from a given image path.
+ * @param imagePath The identifier of the image.
+ * @return The image for the given identifier.
+ */
+ public static byte[] loadIcon(String imagePath) {
+ InputStream is = ProtocolIconDictImpl.class
+ .getClassLoader().getResourceAsStream(imagePath);
+
+ byte[] icon = null;
+ try {
+ icon = new byte[is.available()];
+ is.read(icon);
+ } catch (IOException e) {
+ logger.error("Failed to load icon: " + imagePath, e);
+ }
+ return icon;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderFactoryDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderFactoryDictImpl.java
new file mode 100644
index 0000000..11fc521
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderFactoryDictImpl.java
@@ -0,0 +1,318 @@
+/*
+ * 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.dict;
+
+import java.util.*;
+
+import net.java.sip.communicator.impl.gui.i18n.*;
+import net.java.sip.communicator.service.contactlist.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * The Dict protocol provider factory creates instances of the Dict
+ * protocol provider service. One Service instance corresponds to one account.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class ProtocolProviderFactoryDictImpl
+ extends ProtocolProviderFactory
+{
+ private static final Logger logger
+ = Logger.getLogger(ProtocolProviderFactoryDictImpl.class);
+
+ /**
+ * The table that we store our accounts in.
+ */
+ private Hashtable registeredAccounts = new Hashtable();
+
+ /**
+ * Name for the auto-create group
+ */
+ private String groupName = "Dictionaries";
+
+ private BundleContext bundleContext;
+
+ /**
+ * Creates an instance of the ProtocolProviderFactoryDictImpl.
+ */
+ public ProtocolProviderFactoryDictImpl()
+ {
+ super();
+ bundleContext = DictActivator.getBundleContext();
+ }
+
+ /**
+ * 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
+ * provider factory.
+ */
+ public ServiceReference getProviderForAccount(AccountID accountID)
+ {
+ ServiceRegistration registration
+ = (ServiceRegistration)registeredAccounts.get(accountID);
+
+ return (registration == null )
+ ? null
+ : registration.getReference();
+ }
+
+ /**
+ * Returns a copy of the list containing the <tt>AccoudID</tt>s of all
+ * accounts currently registered in this protocol provider.
+ *
+ * @return a copy of the list containing the <tt>AccoudID</tt>s of all
+ * accounts currently registered in this protocol provider.
+ */
+ public ArrayList getRegisteredAccounts()
+ {
+ return new ArrayList(registeredAccounts.keySet());
+ }
+
+ /**
+ * Loads (and hence installs) all accounts previously stored in the
+ * configuration service.
+ */
+ public void loadStoredAccounts()
+ {
+ super.loadStoredAccounts(DictActivator.getBundleContext());
+ }
+
+
+ /**
+ * Initializaed and creates an account corresponding to the specified
+ * accountProperties and registers the resulting ProtocolProvider in the
+ * <tt>context</tt> BundleContext parameter.
+ *
+ * @param userIDStr tha/a user identifier uniquely representing the newly
+ * created account within the protocol namespace.
+ * @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( String userIDStr,
+ Map accountProperties)
+ {
+ BundleContext context = DictActivator.getBundleContext();
+ if (context == null)
+ {
+ throw new NullPointerException("The specified BundleContext was null");
+ }
+ if (userIDStr == null)
+ {
+ throw new NullPointerException("The specified AccountID was null");
+ }
+ if (accountProperties == null)
+ {
+ throw new NullPointerException("The specified property map was null");
+ }
+
+ accountProperties.put(USER_ID, userIDStr);
+
+ AccountID accountID = new DictAccountID(userIDStr, accountProperties);
+
+ //make sure we haven't seen this account id before.
+ if (registeredAccounts.containsKey(accountID))
+ {
+ throw new IllegalStateException("An account for id " + userIDStr + " was already installed!");
+ }
+
+ //first store the account and only then load it as the load generates
+ //an osgi event, the osgi event triggers (through the UI) a call to the
+ //ProtocolProviderService.register() method and it needs to acces
+ //the configuration service and check for a stored password.
+ this.storeAccount(DictActivator.getBundleContext(), accountID);
+
+ accountID = loadAccount(accountProperties);
+
+ // Creates the dict contact group
+ this.createGroup();
+
+ return accountID;
+ }
+
+ /**
+ * Initializes and creates an account corresponding to the specified
+ * accountProperties and registers the resulting ProtocolProvider in the
+ * <tt>context</tt> BundleContext parameter.
+ *
+ * @param accountProperties a set of protocol (or implementation)
+ * specific properties defining the new account.
+ * @return the AccountID of the newly loaded account
+ */
+ public AccountID loadAccount(Map accountProperties)
+ {
+ //BundleContext context = DictActivator.getBundleContext();
+
+ if(bundleContext == null)
+ {
+ throw new NullPointerException("The specified BundleContext was null");
+ }
+
+ String userIDStr = (String) accountProperties.get(USER_ID);
+
+ AccountID accountID = new DictAccountID(userIDStr, accountProperties);
+
+ //get a reference to the configuration service and register whatever
+ //properties we have in it.
+
+ Hashtable properties = new Hashtable();
+ properties.put(PROTOCOL, ProtocolNames.DICT);
+ properties.put(USER_ID, userIDStr);
+
+ ProtocolProviderServiceDictImpl dictProtocolProvider
+ = new ProtocolProviderServiceDictImpl();
+
+ dictProtocolProvider.initialize(userIDStr, accountID);
+
+ ServiceRegistration registration
+ = bundleContext.registerService( ProtocolProviderService.class.getName(),
+ dictProtocolProvider,
+ properties);
+
+ registeredAccounts.put(accountID, registration);
+ return accountID;
+ }
+
+
+ /**
+ * Removes the specified account from the list of accounts that this
+ * provider factory is handling.
+ *
+ * @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)
+ {
+ //unregister the protocol provider
+ ServiceReference serRef = getProviderForAccount(accountID);
+
+ ProtocolProviderService protocolProvider
+ = (ProtocolProviderService) DictActivator.getBundleContext()
+ .getService(serRef);
+
+ try
+ {
+ protocolProvider.unregister();
+ }
+ catch (OperationFailedException exc)
+ {
+ logger.error("Failed to unregister protocol provider for account : "
+ + accountID + " caused by : " + exc);
+ }
+
+ ServiceRegistration registration
+ = (ServiceRegistration) registeredAccounts.remove(accountID);
+
+ if(registration == null)
+ {
+ return false;
+ }
+
+ //kill the service
+ registration.unregister();
+
+ registeredAccounts.remove(accountID);
+
+ return removeStoredAccount(DictActivator.getBundleContext(), accountID);
+ }
+
+ /**
+ * Saves the password for the specified account after scrambling it a bit
+ * so that it is not visible from first sight (Method remains highly
+ * insecure).
+ *
+ * @param accountID the AccountID for the account whose password we're
+ * storing.
+ * @param passwd the password itself.
+ *
+ * @throws java.lang.IllegalArgumentException if no account corresponding
+ * to <tt>accountID</tt> has been previously stored.
+ */
+ public void storePassword(AccountID accountID, String passwd)
+ throws IllegalArgumentException
+ {
+ super.storePassword(DictActivator.getBundleContext(),
+ accountID,
+ passwd);
+ }
+
+ /**
+ * Returns the password last saved for the specified account.
+ *
+ * @param accountID the AccountID for the account whose password we're
+ * looking for..
+ *
+ * @return a String containing the password for the specified accountID.
+ *
+ * @throws java.lang.IllegalArgumentException if no account corresponding
+ * to <tt>accountID</tt> has been previously stored.
+ */
+ public String loadPassword(AccountID accountID)
+ throws IllegalArgumentException
+ {
+ return super.loadPassword(DictActivator.getBundleContext(), accountID );
+ }
+
+ /**
+ * Prepares the factory for bundle shutdown.
+ */
+ public void stop()
+ {
+ Enumeration registrations = this.registeredAccounts.elements();
+
+ while(registrations.hasMoreElements())
+ {
+ ServiceRegistration reg
+ = ((ServiceRegistration)registrations.nextElement());
+
+ reg.unregister();
+ }
+
+ Enumeration idEnum = registeredAccounts.keys();
+
+ while(idEnum.hasMoreElements())
+ {
+ registeredAccounts.remove(idEnum.nextElement());
+ }
+ }
+
+ /**
+ * Creates a group for the dict contacts
+ */
+ private void createGroup()
+ {
+ // Get MetaContactListService
+ ServiceReference mfcServiceRef = bundleContext
+ .getServiceReference(MetaContactListService.class.getName());
+
+ MetaContactListService mcl = (MetaContactListService)
+ bundleContext.getService(mfcServiceRef);
+
+ try
+ {
+ mcl.createMetaContactGroup(mcl.getRoot(), groupName);
+ }
+ catch (MetaContactListException ex)
+ {
+ int errorCode = ex.getErrorCode();
+ if (errorCode != MetaContactListException.CODE_GROUP_ALREADY_EXISTS_ERROR)
+ {
+ logger.error(ex);
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderServiceDictImpl.java b/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderServiceDictImpl.java
new file mode 100644
index 0000000..c60e8e5
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/ProtocolProviderServiceDictImpl.java
@@ -0,0 +1,451 @@
+/*
+ * 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.dict;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.service.version.*;
+import net.java.sip.communicator.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * A Dict implementation of the ProtocolProviderService.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class ProtocolProviderServiceDictImpl
+ implements ProtocolProviderService
+{
+ private static final Logger logger
+ = Logger.getLogger(ProtocolProviderServiceDictImpl.class);
+
+ /**
+ * The name of this protocol.
+ */
+ public static final String DICT_PROTOCOL_NAME = "Dict";
+
+ /**
+ * The id of the account that this protocol provider represents.
+ */
+ private AccountID accountID = null;
+
+ /**
+ * We use this to lock access to initialization.
+ */
+ private Object initializationLock = new Object();
+
+ /**
+ * The hashtable with the operation sets that we support locally.
+ */
+ private Hashtable supportedOperationSets = new Hashtable();
+
+ /**
+ * A list of listeners interested in changes in our registration state.
+ */
+ private Vector registrationStateListeners = new Vector();
+
+ /**
+ * Indicates whether or not the provider is initialized and ready for use.
+ */
+ private boolean isInitialized = false;
+
+ /**
+ * The logo corresponding to the gibberish protocol.
+ */
+ private ProtocolIconDictImpl dictIcon = new ProtocolIconDictImpl();
+
+ /**
+ * The registration state that we are currently in. Note that in a real
+ * world protocol implementation this field won't exist and the registration
+ * state would be retrieved from the protocol stack.
+ */
+ private RegistrationState currentRegistrationState
+ = RegistrationState.UNREGISTERED;
+
+ /**
+ * The default constructor for the Dict protocol provider.
+ */
+ public ProtocolProviderServiceDictImpl()
+ {
+ logger.trace("Creating a Dict provider.");
+ }
+
+ /**
+ * Initializes 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
+ * <tt>AccountProperties</tt>.
+ *
+ * @param userID the user id of the gibberish account we're currently
+ * initializing
+ * @param accountID the identifier of the account that this protocol
+ * provider represents.
+ *
+ * @see net.java.sip.communicator.service.protocol.AccountID
+ */
+ protected void initialize(String userID,
+ AccountID accountID)
+ {
+ synchronized(initializationLock)
+ {
+ this.accountID = accountID;
+
+ //initialize the presence operationset
+ OperationSetPersistentPresenceDictImpl persistentPresence =
+ new OperationSetPersistentPresenceDictImpl(this);
+
+ supportedOperationSets.put(
+ OperationSetPersistentPresence.class.getName(),
+ persistentPresence);
+
+
+ //register it once again for those that simply need presence and
+ //won't be smart enough to check for a persistent presence
+ //alternative
+ supportedOperationSets.put( OperationSetPresence.class.getName(),
+ persistentPresence);
+
+ //initialize the IM operation set
+ OperationSetBasicInstantMessagingDictImpl basicInstantMessaging
+ = new OperationSetBasicInstantMessagingDictImpl(
+ this
+ , (OperationSetPersistentPresenceDictImpl)
+ persistentPresence);
+
+ supportedOperationSets.put(
+ OperationSetBasicInstantMessaging.class.getName(),
+ basicInstantMessaging);
+
+ //initialize the typing notifications operation set
+ /*OperationSetTypingNotifications typingNotifications =
+ new OperationSetTypingNotificationsDictImpl(
+ this, persistentPresence);
+
+ supportedOperationSets.put(
+ OperationSetTypingNotifications.class.getName(),
+ typingNotifications);
+ */
+ isInitialized = true;
+ }
+ }
+
+ /**
+ * 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)
+ {
+ synchronized(registrationStateListeners)
+ {
+ if (!registrationStateListeners.contains(listener))
+ registrationStateListeners.add(listener);
+ }
+
+ }
+
+ /**
+ * Removes the specified registration listener so that it won't receive
+ * further notifications when our registration state changes.
+ *
+ * @param listener the listener to remove.
+ */
+ public void removeRegistrationStateChangeListener(
+ RegistrationStateChangeListener listener)
+ {
+ synchronized(registrationStateListeners)
+ {
+ registrationStateListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Creates a <tt>RegistrationStateChangeEvent</tt> corresponding to the
+ * specified old and new states and notifies all currently registered
+ * listeners.
+ *
+ * @param oldState the state that the provider had before the change
+ * occurred
+ * @param newState the state that the provider is currently in.
+ * @param reasonCode a value corresponding to one of the REASON_XXX fields
+ * of the RegistrationStateChangeEvent class, indicating the reason for
+ * this state transition.
+ * @param reason a String further explaining the reason code or null if
+ * no such explanation is necessary.
+ */
+ private void fireRegistrationStateChanged( RegistrationState oldState,
+ RegistrationState newState,
+ int reasonCode,
+ String reason)
+ {
+ RegistrationStateChangeEvent event =
+ new RegistrationStateChangeEvent(
+ this, oldState, newState, reasonCode, reason);
+
+ logger.debug("Dispatching " + event + " to "
+ + registrationStateListeners.size()+ " listeners.");
+
+ Iterator listeners = null;
+ synchronized (registrationStateListeners)
+ {
+ listeners = new ArrayList(registrationStateListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ RegistrationStateChangeListener listener
+ = (RegistrationStateChangeListener) listeners.next();
+
+ listener.registrationStateChanged(event);
+ }
+
+ logger.trace("Done.");
+ }
+
+ /**
+ * Retrieve the DictAdapter linked with the account. If there is no instance, one is created
+ * @return a DictAdapter instance
+ */
+ public DictAdapter getDictAdapter()
+ {
+ String host = (String) this.accountID.getAccountProperties()
+ .get(ProtocolProviderFactory.SERVER_ADDRESS);
+ int port = Integer.parseInt((String) this.accountID.getAccountProperties()
+ .get(ProtocolProviderFactory.SERVER_PORT));
+ String strategy = (String) this.accountID.getAccountProperties()
+ .get(ProtocolProviderFactory.STRATEGY);
+
+ String key = this.accountID.getUserID();
+ DictAdapter result = DictRegistry.get(key);
+
+ if (!(result instanceof DictAdapter))
+ {
+ result = new DictAdapter(host, port, strategy);
+
+
+ // Set the clientname from the current version
+ BundleContext bundleContext = DictActivator.getBundleContext();
+ ServiceReference versionServRef = bundleContext
+ .getServiceReference(VersionService.class.getName());
+
+ VersionService versionService = (VersionService) bundleContext
+ .getService(versionServRef);
+
+ result.setClientName(versionService.getCurrentVersion().toString());
+
+ // Store the DictAdapter
+ DictRegistry.put(key, result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Close the DictAdapter linked with the account ID
+ */
+ public void closeDictAdapter()
+ {
+ String key = this.accountID.getUserID();
+ DictAdapter result = DictRegistry.get(key);
+
+ if ((result instanceof DictAdapter))
+ {
+ try
+ {
+ result.close();
+ DictRegistry.remove(key);
+ }
+ catch (Exception ex)
+ {
+ logger.error(ex);
+ }
+ }
+ }
+
+ /**
+ * Returns the AccountID that uniquely identifies the account represented
+ * by this instance of the ProtocolProviderService.
+ *
+ * @return the id of the account represented by this provider.
+ */
+ public AccountID getAccountID()
+ {
+ return accountID;
+ }
+
+ /**
+ * Returns the operation set corresponding to the specified class or null
+ * if this operation set is not supported by the provider implementation.
+ *
+ * @param opsetClass the <tt>Class</tt> of the operation set that we're
+ * looking for.
+ * @return returns an OperationSet of the specified <tt>Class</tt> if
+ * the undelying implementation supports it or null otherwise.
+ */
+ public OperationSet getOperationSet(Class opsetClass)
+ {
+ return (OperationSet) getSupportedOperationSets()
+ .get(opsetClass.getName());
+ }
+
+ /**
+ * 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 implementing (most often that would be a name in
+ * ProtocolNames).
+ */
+ public String getProtocolName()
+ {
+ return DICT_PROTOCOL_NAME;
+ }
+
+ /**
+ * Returns the protocol display name. This is the name that would be used
+ * by the GUI to display the protocol name.
+ *
+ * @return a String containing the display name of the protocol this service
+ * is implementing
+ */
+ public String getProtocolDisplayName()
+ {
+ return DICT_PROTOCOL_NAME;
+ }
+
+ /**
+ * Returns the dict protocol icon.
+ * @return the dict protocol icon
+ */
+ public ProtocolIcon getProtocolIcon()
+ {
+ return this.dictIcon;
+ }
+
+ /**
+ * Returns the state of the registration of this protocol provider with
+ * the corresponding registration service.
+ *
+ * @return ProviderRegistrationState
+ */
+ public RegistrationState getRegistrationState()
+ {
+ return currentRegistrationState;
+ }
+
+ /**
+ * Returns an array containing all operation sets supported by the
+ * current implementation.
+ *
+ * @return a java.util.Map containing instance of all supported
+ * operation sets mapped against their class names (e.g.
+ * OperationSetPresence.class.getName()) .
+ */
+ public Map getSupportedOperationSets()
+ {
+ //Copy the map so that the caller is not able to modify it.
+ return (Map)supportedOperationSets.clone();
+ }
+
+ /**
+ * Indicates whether or not this provider is registered
+ *
+ * @return true if the provider is currently registered and false
+ * otherwise.
+ */
+ public boolean isRegistered()
+ {
+ return currentRegistrationState.equals(RegistrationState.REGISTERED);
+ }
+
+ /**
+ * Starts the registration process.
+ *
+ * @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.
+ * @throws OperationFailedException with the corresponding code it the
+ * registration fails for some reason (e.g. a networking error or an
+ * implementation problem).
+ */
+ public void register(SecurityAuthority authority)
+ throws OperationFailedException
+ {
+ RegistrationState oldState = currentRegistrationState;
+ currentRegistrationState = RegistrationState.REGISTERED;
+
+ fireRegistrationStateChanged(
+ oldState
+ , currentRegistrationState
+ , RegistrationStateChangeEvent.REASON_USER_REQUEST
+ , null);
+ }
+
+ /**
+ * 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()
+ {
+ if(!isInitialized)
+ {
+ return;
+ }
+ logger.trace("Killing the Dict Protocol Provider for account "
+ + this.accountID.getUserID());
+ this.closeDictAdapter();
+
+ if(isRegistered())
+ {
+ try
+ {
+ //do the unregistration
+ unregister();
+ }
+ catch (OperationFailedException ex)
+ {
+ //we're shutting down so we need to silence the exception here
+ logger.error(
+ "Failed to properly unregister before shutting down. "
+ + getAccountID()
+ , ex);
+ }
+ }
+
+ isInitialized = false;
+ }
+
+ /**
+ * Ends the registration of this protocol provider with the current
+ * registration service.
+ *
+ * @throws OperationFailedException with the corresponding code it the
+ * registration fails for some reason (e.g. a networking error or an
+ * implementation problem).
+ */
+ public void unregister()
+ throws OperationFailedException
+ {
+ RegistrationState oldState = currentRegistrationState;
+ currentRegistrationState = RegistrationState.UNREGISTERED;
+
+ fireRegistrationStateChanged(
+ oldState
+ , currentRegistrationState
+ , RegistrationStateChangeEvent.REASON_USER_REQUEST
+ , null);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/dict/dict.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/dict/dict.provider.manifest.mf
new file mode 100644
index 0000000..ff0b0d2
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/dict/dict.provider.manifest.mf
@@ -0,0 +1,13 @@
+Bundle-Activator: net.java.sip.communicator.impl.protocol.dict.DictActivator
+Bundle-Name: Dict Protocol Provider
+Bundle-Description: A bundle providing support for the Dict protocol.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: org.osgi.framework,
+ net.java.sip.communicator.service.contactlist,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.configuration.event,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.service.protocol.event,
+ net.java.sip.communicator.service.version
diff --git a/src/net/java/sip/communicator/impl/version/NightlyBuildID.java b/src/net/java/sip/communicator/impl/version/NightlyBuildID.java
index 32bba36..08d7931 100644
--- a/src/net/java/sip/communicator/impl/version/NightlyBuildID.java
+++ b/src/net/java/sip/communicator/impl/version/NightlyBuildID.java
@@ -13,5 +13,5 @@ package net.java.sip.communicator.impl.version;
*/
public class NightlyBuildID
{
- public static final String BUILD_ID="0.build.by.CVS";
+ public static final String BUILD_ID="0.build.by.lucas";
}
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccRegWizzActivator.java b/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccRegWizzActivator.java
new file mode 100644
index 0000000..7972841
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccRegWizzActivator.java
@@ -0,0 +1,136 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.dictaccregwizz;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.browserlauncher.*;
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+
+import org.osgi.framework.*;
+
+/**
+ * Registers the <tt>DictAccountRegistrationWizard</tt> in the UI Service.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class DictAccRegWizzActivator implements BundleActivator
+{
+ public static BundleContext bundleContext;
+
+ private static Logger logger = Logger.getLogger(
+ DictAccRegWizzActivator.class);
+
+ private static BrowserLauncherService browserLauncherService;
+
+ private static WizardContainer wizardContainer;
+
+ private static DictAccountRegistrationWizard dictWizard;
+
+ private static UIService uiService;
+
+ /**
+ * Starts this bundle.
+ *
+ * @param bc The bundle context.
+ */
+ public void start(BundleContext bc) throws Exception {
+
+ bundleContext = bc;
+
+ ServiceReference uiServiceRef = bundleContext
+ .getServiceReference(UIService.class.getName());
+
+ uiService = (UIService) bundleContext.getService(uiServiceRef);
+
+ wizardContainer = uiService.getAccountRegWizardContainer();
+
+ dictWizard = new DictAccountRegistrationWizard(wizardContainer);
+
+ //wizardContainer.addAccountRegistrationWizard(dictWizard);
+ Hashtable<String, String> containerFilter
+ = new Hashtable<String, String>();
+
+ containerFilter.put(
+ ProtocolProviderFactory.PROTOCOL,
+ ProtocolNames.DICT);
+
+ bundleContext.registerService(
+ AccountRegistrationWizard.class.getName(),
+ dictWizard,
+ containerFilter);
+ }
+
+
+ /**
+ * Stops this bundle.
+ *
+ * @param bundleContext The bundle context (unused).
+ *
+ * @throws Exception Throws an execption from the
+ * "wizardContainer.removeAccountRegistrationWizard" method.
+ *
+ */
+ public void stop(BundleContext bundleContext) throws Exception
+ {
+ //wizardContainer.removeAccountRegistrationWizard(dictWizard);
+ }
+
+ /**
+ * Returns the <tt>ProtocolProviderFactory</tt> for the Dict protocol.
+ * @return the <tt>ProtocolProviderFactory</tt> for the Dict protocol
+ */
+ public static ProtocolProviderFactory getDictProtocolProviderFactory() {
+
+ ServiceReference[] serRefs = null;
+
+ String osgiFilter = "("
+ + ProtocolProviderFactory.PROTOCOL
+ + "="+ProtocolNames.DICT+")";
+
+ try {
+ serRefs = bundleContext.getServiceReferences(
+ ProtocolProviderFactory.class.getName(), osgiFilter);
+ }
+ catch (InvalidSyntaxException ex){
+ logger.error("DictAccRegWizzActivator : " + ex);
+ }
+
+ return (ProtocolProviderFactory) bundleContext.getService(serRefs[0]);
+ }
+
+ /**
+ * Returns the <tt>BrowserLauncherService</tt> obtained from the bundle
+ * context.
+ * @return the <tt>BrowserLauncherService</tt> obtained from the bundle
+ * context
+ */
+ public static BrowserLauncherService getBrowserLauncher() {
+ if (browserLauncherService == null) {
+ ServiceReference serviceReference = bundleContext
+ .getServiceReference(BrowserLauncherService.class.getName());
+
+ browserLauncherService = (BrowserLauncherService) bundleContext
+ .getService(serviceReference);
+ }
+
+ return browserLauncherService;
+ }
+
+ /**
+ * Returns the <tt>UIService</tt>.
+ *
+ * @return the <tt>UIService</tt>
+ */
+ public static UIService getUIService()
+ {
+ return uiService;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccountRegistration.java b/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccountRegistration.java
new file mode 100644
index 0000000..5bda4e6
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccountRegistration.java
@@ -0,0 +1,123 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.dictaccregwizz;
+
+/**
+ * The <tt>DictAccountRegistration</tt> is used to store all user input data
+ * through the <tt>DictAccountRegistrationWizard</tt>.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class DictAccountRegistration
+{
+ private String userID;
+ private String password;
+
+ /**
+ * The hostname of the DICT server.
+ */
+ private String host;
+
+ /**
+ * The port of the DICT server.
+ */
+ private int port;
+
+ /**
+ * The code id of the strategie selected for the matching of words in dictionnaries.
+ */
+ private String strategyCode;
+
+ /**
+ * The real name of the strategie selected for the matching of words in dictionnaries.
+ */
+ private String strategy;
+
+ /**
+ * Returns the User ID of the dict registration account.
+ * @return the User ID of the dict registration account.
+ */
+ public String getUserID()
+ {
+ return userID;
+ }
+
+ /**
+ * Sets the password of the dict registration account.
+ *
+ * @param password the password of the dict registration account.
+ */
+ public void setPassword(String password)
+ {
+ this.password = password;
+ }
+
+ /**
+ * Returns the port of the dict registration account.
+ * @return the port of the dict registration account.
+ */
+ public int getPort() {
+ return this.port;
+ }
+
+ /**
+ * Sets the port of the dict registration account.
+ * @param port the port of the dict registration account.
+ */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ /**
+ * Returns the host of the dict registration account.
+ * @return the host of the dict registration account.
+ */
+ public String getHost() {
+ return this.host;
+ }
+
+ /**
+ * Sets the host of the dict registration account.
+ * @param uin the host of the dict registration account.
+ */
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ /**
+ * Returns the strategy that will be used for this dict account.
+ * @return the strategy that will be used for this dict account.
+ */
+ public String getStrategy() {
+ return this.strategy;
+ }
+
+ /**
+ * Sets the strategy for this dict account.
+ * @param strategy the strategy for this dict account.
+ */
+ public void setStrategy(String strategy) {
+ this.strategy = strategy;
+ }
+
+ /**
+ * Returns the strategy code that will be used for this dict account.
+ * @return the strategy code that will be used for this dict account.
+ */
+ public String getStrategyCode() {
+ return this.strategyCode;
+ }
+
+ /**
+ * Sets the strategy code for this dict account.
+ * @param strategyCode the strategy code for this dict account.
+ */
+ public void setStrategyCode(String strategyCode) {
+ this.strategyCode = strategyCode;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccountRegistrationWizard.java b/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccountRegistrationWizard.java
new file mode 100644
index 0000000..b2d2d5b
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAccountRegistrationWizard.java
@@ -0,0 +1,409 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.dictaccregwizz;
+
+import java.awt.*;
+import java.util.*;
+
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.protocol.*;
+
+import org.osgi.framework.*;
+
+/**
+ * The <tt>DictAccountRegistrationWizard</tt> is an implementation of the
+ * <tt>AccountRegistrationWizard</tt> for the Dict protocol. It should allow
+ * the user to create and configure a new Dict account.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class DictAccountRegistrationWizard
+ implements AccountRegistrationWizard
+{
+ /**
+ * The reference to the first page of the wizard.
+ */
+ private FirstWizardPage firstWizardPage;
+
+ /**
+ * The registration of the DICT account.
+ */
+ private DictAccountRegistration registration = new DictAccountRegistration();
+
+ /**
+ * The container of the wizard.
+ */
+ private WizardContainer wizardContainer;
+
+ /**
+ * The protocole provider.
+ */
+ private ProtocolProviderService protocolProvider;
+
+ /**
+ * Tells us if the is a modification wiazrd or not.
+ */
+ private boolean isModification;
+
+ /**
+ * Creates an instance of <tt>DictAccountRegistrationWizard</tt>.
+ *
+ * @param wizardContainer the wizard container, where this wizard is added
+ */
+ public DictAccountRegistrationWizard(WizardContainer wizardContainer)
+ {
+ this.wizardContainer = wizardContainer;
+ }
+
+ /**
+ * Implements the <code>AccountRegistrationWizard.getIcon</code> method.
+ * @return Returns the icon to be used for this wizard.
+ */
+ public byte[] getIcon()
+ {
+ return Resources.getImage(Resources.DICT_LOGO);
+ }
+
+ /**
+ * Implements the <code>AccountRegistrationWizard.getPageImage</code>
+ * method. Returns the image used to decorate the wizard page
+ *
+ * @return byte[] the image used to decorate the wizard page
+ */
+ public byte[] getPageImage()
+ {
+ return Resources.getImage(Resources.PAGE_IMAGE);
+ }
+
+ /**
+ * Implements the <code>AccountRegistrationWizard.getProtocolName</code>
+ * method.
+ * @return Returns the protocol name for this wizard.
+ */
+ public String getProtocolName()
+ {
+ return Resources.getString("protocolName");
+ }
+
+ /**
+ * Implements the <code>AccountRegistrationWizard.getProtocolDescription
+ * </code> method.
+ * @return Returns the description of the protocol for this wizard.
+ */
+ public String getProtocolDescription()
+ {
+ return Resources.getString("protocolDescription");
+ }
+
+ /**
+ * Returns the set of pages contained in this wizard.
+ *
+ * @return Returns the set of pages contained in this wizard.
+ */
+ public Iterator getPages()
+ {
+ ArrayList pages = new ArrayList();
+ this.firstWizardPage = new FirstWizardPage(this);
+ pages.add(this.firstWizardPage);
+ return pages.iterator();
+ }
+
+ /**
+ * Returns the set of data that user has entered through this wizard.
+ * @return Returns the set of data that user has entered through this wizard.
+ */
+ public Iterator getSummary()
+ {
+ LinkedHashMap<String, String> summaryTable = new LinkedHashMap<String, String>();
+
+ summaryTable.put("Host", registration.getHost());
+ summaryTable.put("Port", String.valueOf(registration.getPort()));
+ summaryTable.put("Strategy", registration.getStrategy());
+
+ return summaryTable.entrySet().iterator();
+ }
+
+ /**
+ * Installs the account created through this wizard.
+ *
+ * @return The ProtocoleProviderService installed for the account.
+ */
+ public ProtocolProviderService finish()
+ {
+ firstWizardPage = null;
+ ProtocolProviderFactory factory =
+ DictAccRegWizzActivator.getDictProtocolProviderFactory();
+
+ return this.installAccount(factory, registration.getHost(),
+ registration.getPort(),
+ registration.getStrategyCode());
+ }
+
+ /**
+ * Installs the account created through this wizard.
+ * @return ProtocolProviderService
+ */
+ public ProtocolProviderService signin()
+ {
+ return signin(registration.getUserID(), null);
+ }
+
+ /**
+ * Installs the account created through this wizard.
+ * @return ProtocolProviderService
+ */
+ public ProtocolProviderService signin(String userName, String password)
+ {
+ firstWizardPage = null;
+ ProtocolProviderFactory factory
+ = DictAccRegWizzActivator.getDictProtocolProviderFactory();
+
+ /*return this.installAccount(factory,
+ userName);*/
+ return this.installAccount(factory, registration.getHost(),
+ registration.getPort(),
+ registration.getStrategyCode());
+ }
+
+ /**
+ * Creates an account for the given user and password.
+ *
+ * @param providerFactory the ProtocolProviderFactory which will create the
+ * account.
+ * @param host The hostname of the DICT server.
+ * @param port The port used by the DICT server.
+ * @param strategy The strategy choosen for matching words in the
+ * dictionnaries.
+ * @return the <tt>ProtocolProviderService</tt> for the new account.
+ */
+ public ProtocolProviderService installAccount(
+ ProtocolProviderFactory providerFactory,
+ String host,
+ int port,
+ String strategy)
+ {
+ Hashtable accountProperties = new Hashtable();
+
+ // Save host
+ accountProperties.put(ProtocolProviderFactory.SERVER_ADDRESS, host);
+ // Save port
+ accountProperties.put(ProtocolProviderFactory.SERVER_PORT, String.valueOf(port));
+ // Save strategy
+ accountProperties.put(ProtocolProviderFactory.STRATEGY, strategy);
+
+ if (isModification)
+ {
+ providerFactory.uninstallAccount(protocolProvider.getAccountID());
+ this.protocolProvider = null;
+ this.isModification = false;
+ }
+
+ try
+ {
+ String uid = this.generateUID();
+ AccountID accountID =
+ providerFactory.installAccount(uid, accountProperties);
+
+ ServiceReference serRef =
+ providerFactory.getProviderForAccount(accountID);
+
+ protocolProvider =
+ (ProtocolProviderService) DictAccRegWizzActivator.bundleContext
+ .getService(serRef);
+ }
+ catch (IllegalArgumentException e)
+ {
+ DictAccRegWizzActivator.getUIService().getPopupDialog()
+ .showMessagePopupDialog(e.getMessage(),
+ Resources.getString("error"),
+ PopupDialog.ERROR_MESSAGE);
+ }
+ catch (IllegalStateException e)
+ {
+ DictAccRegWizzActivator.getUIService().getPopupDialog()
+ .showMessagePopupDialog(e.getMessage(),
+ Resources.getString("error"),
+ PopupDialog.ERROR_MESSAGE);
+ }
+
+ return protocolProvider;
+ }
+
+ /**
+ * Fills the UIN and Password fields in this panel with the data coming
+ * from the given protocolProvider.
+ *
+ * @param protocolProvider The <tt>ProtocolProviderService</tt> to load
+ * the data from.
+ */
+ public void loadAccount(ProtocolProviderService protocolProvider)
+ {
+ this.isModification = true;
+
+ this.protocolProvider = protocolProvider;
+
+ this.registration = new DictAccountRegistration();
+
+ this.firstWizardPage.loadAccount(protocolProvider);
+ }
+
+ /**
+ * Indicates if this wizard is opened for modification or for creating a
+ * new account.
+ *
+ * @return <code>true</code> if this wizard is opened for modification and
+ * <code>false</code> otherwise.
+ */
+ public boolean isModification()
+ {
+ return isModification;
+ }
+
+ /**
+ * Sets if this wizard is opened for modification or for creating a
+ * new account.
+ *
+ * @param b <code>True</code> if this wizard is opened for modification and
+ * <code>false</code> otherwise.
+ */
+ public void setModification(boolean b)
+ {
+ this.isModification = b;
+ }
+
+ /**
+ * Returns the wizard container, where all pages are added.
+ *
+ * @return the wizard container, where all pages are added
+ */
+ public WizardContainer getWizardContainer()
+ {
+ return wizardContainer;
+ }
+
+ /**
+ * Returns the registration object, which will store all the data through
+ * the wizard.
+ *
+ * @return the registration object, which will store all the data through
+ * the wizard
+ */
+ public DictAccountRegistration getRegistration()
+ {
+ return registration;
+ }
+
+ /**
+ * Returns the size of this wizard.
+ * @return the size of this wizard
+ */
+ public Dimension getSize()
+ {
+ return new Dimension(300, 150);
+ }
+
+ /**
+ * Returns the identifier of the page to show first in the wizard.
+ * @return the identifier of the page to show first in the wizard.
+ */
+ public Object getFirstPageIdentifier()
+ {
+ return firstWizardPage.getIdentifier();
+ }
+
+ /**
+ * Returns the identifier of the page to show last in the wizard.
+ * @return the identifier of the page to show last in the wizard.
+ */
+ public Object getLastPageIdentifier()
+ {
+ return firstWizardPage.getIdentifier();
+ }
+
+ /**
+ * Generate the UID for the acount
+ * @return the new UID
+ */
+ private String generateUID()
+ {
+ String uid;
+ int nbAccounts = this.getNumberOfAccounts();
+ String host = this.registration.getHost();
+ int nbAccountsForHost = this.getNbAccountForHost(host);
+
+ if (nbAccounts == 0 || (this.isModification() && nbAccounts == 1) ||
+ nbAccountsForHost == 0 || (this.isModification() && nbAccountsForHost == 1))
+ {
+ // We create the first account or we edit the onlyone
+ // Or we create the first account for this server or edit the onlyone
+ uid = host;
+ }
+ else
+ {
+ uid = host + ":" + this.registration.getPort();
+ }
+
+ return uid;
+ }
+
+ /**
+ * Returns the number of accounts stored for the protocol
+ * @return the number of accounts stored for the protocol
+ */
+ private int getNumberOfAccounts()
+ {
+ ProtocolProviderFactory factory =
+ DictAccRegWizzActivator.getDictProtocolProviderFactory();
+
+ return factory.getRegisteredAccounts().size();
+ }
+
+ /**
+ * Returns the number of account for a given host
+ * @param hostName the host
+ * @return the number of account for a given host
+ */
+ private int getNbAccountForHost(String host)
+ {
+ ProtocolProviderFactory factory =
+ DictAccRegWizzActivator.getDictProtocolProviderFactory();
+
+ ArrayList registeredAccounts = factory.getRegisteredAccounts();
+ int total = 0;
+
+ for (int i = 0; i < registeredAccounts.size(); i++)
+ {
+ AccountID accountID = (AccountID) registeredAccounts.get(i);
+
+ // The host is always stored at the start
+ if (accountID.getUserID().startsWith(host.toLowerCase()))
+ {
+ total++;
+ }
+ }
+ return total;
+ }
+
+ /**
+ * Returns an example string, which should indicate to the user how the
+ * user name should look like.
+ * @return an example string, which should indicate to the user how the
+ * user name should look like.
+ */
+ public String getUserNameExample()
+ {
+ return null;
+ }
+
+ /**
+ * Disables the simple "Sign in" form.
+ */
+ public boolean isSimpleFormEnabled()
+ {
+ return false;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAdapter.java b/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAdapter.java
new file mode 100644
index 0000000..e7329ab
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/DictAdapter.java
@@ -0,0 +1,183 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.dictaccregwizz;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import net.java.sip.communicator.util.Logger;
+
+/**
+ * Copy of DictAdapter class to solve the import problem
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+
+public class DictAdapter
+{
+ private static Logger logger = Logger.getLogger(DictAdapter.class);
+
+ /**
+ * The socket used to connect to the DICT server.
+ */
+ private Socket socket = null;
+
+ /**
+ * A output stream piped to the socket in order to send command to the server.
+ */
+ private PrintWriter out = null;
+
+ /**
+ * A input stream piped to the socket in order to receive messages from the server.
+ */
+ private BufferedReader in = null;
+
+ /**
+ * A boolean telling if we are currently connected to the DICT server.
+ */
+ private boolean connected = false;
+
+ /**
+ * Get the strategies allowed by the server for the MATCH command
+ * @return a HashMap containing the database list - otherwise null
+ */
+ public ArrayList<String> getStrategies()
+ {
+ String fromServer;
+ boolean quit = false;
+ ArrayList<String> result = null;
+
+ // Connexion
+ if (!this.connected)
+ {
+ // Not connected
+ return null;
+ }
+
+ try
+ {
+ this.out.println("SHOW STRAT");
+ fromServer = this.in.readLine();
+
+ if (fromServer.startsWith("111"))
+ { // OK - getting responses from the server
+ result = new ArrayList<String>();
+ while (quit == false && (fromServer = this.in.readLine()) != null)
+ {
+ if (fromServer.startsWith("250"))
+ {
+ quit = true;
+ }
+ else if (!fromServer.equals("."))
+ {
+ result.add(fromServer);
+ }
+ }
+ }
+ }
+ catch (IOException ioe)
+ {
+ logger.trace("Cannot get the strategies : " + ioe.getMessage());
+ result = null;
+ }
+ return result;
+ }
+
+
+ /**
+ * Open a connection to the given host on the given port
+ * @param host The hostname of the server.
+ * @param port The port used by the server.
+ * @return true, if a connection is open - false otherwise
+ */
+ public boolean connect(String host, int port)
+ {
+ this.connected = false;
+ String fromServer;
+
+ try
+ {
+ this.socket = new Socket(host, port);
+ this.out = new PrintWriter(new OutputStreamWriter(this.socket.getOutputStream(),
+ "UTF-8"), true);
+ this.in = new BufferedReader(new InputStreamReader(this.socket.getInputStream(),
+ "UTF-8"));
+
+ fromServer = this.in.readLine(); // Server banner
+
+ if (fromServer.startsWith("220"))
+ { // 220 = connect ok
+ this.connected = true;
+ }
+ }
+ catch(Exception ex)
+ { // If an exception is throw == connexion impossible
+ logger.trace("Cannot establish a connexion to the server ("
+ + host + ":" + port + ")", ex);
+ }
+
+ return this.connected;
+ }
+
+ /**
+ * Close the connexion to the server
+ */
+ public void close()
+ {
+ String fromServer;
+
+ try
+ {
+ this.out.println("QUIT");
+
+ // Clean the socket buffer
+ while ((fromServer = this.in.readLine()) != null)
+ {
+ if (fromServer.startsWith("221"))
+ { // Quit response
+ break;
+ }
+ }
+
+ this.out.close();
+ this.in.close();
+ this.socket.close();
+ }
+ catch (IOException ioe)
+ {
+ logger.info("Cannot close the connextion to the server", ioe);
+ }
+ }
+
+ /**
+ * Checks if the given url is correct and exists
+ * @param host The url that we have to test if it is correct and if it
+ * exists.
+ * @return true if the url exists - false otherwise
+ */
+ public static boolean isUrl(String host)
+ {
+ boolean ok = false;
+
+ if (host == null || host.length() == 0)
+ {
+ return false;
+ }
+
+ // If an exception is throw, the host format isn't correct or isn't recheable
+ try
+ {
+ InetAddress.getByName(host);
+ ok = true;
+ }
+ catch (UnknownHostException uhex)
+ {
+ logger.trace("Test URL ("+host+") : " + uhex.getMessage(), uhex);
+ }
+ return ok;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/FirstWizardPage.java b/src/net/java/sip/communicator/plugin/dictaccregwizz/FirstWizardPage.java
new file mode 100644
index 0000000..474bc6d
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/FirstWizardPage.java
@@ -0,0 +1,672 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.dictaccregwizz;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+import net.java.sip.communicator.service.gui.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * The <tt>FirstWizardPage</tt> is the page, where user could enter the host,
+ * port and the strategy of the account.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class FirstWizardPage
+ extends JPanel
+ implements WizardPage, DocumentListener, ActionListener
+{
+ private static Logger logger = Logger.getLogger(FirstWizardPage.class);
+
+ public static final String FIRST_PAGE_IDENTIFIER = "FirstPageIdentifier";
+
+ private JPanel hostPortPanel = new JPanel(new BorderLayout(10, 10));
+
+ private JPanel labelsPanel = new JPanel();
+
+ private JPanel valuesPanel = new JPanel();
+
+ private JLabel hostLabel = new JLabel("Host");
+
+ private JPanel emptyPanel = new JPanel();
+
+ private JLabel hostExampleLabel = new JLabel("Ex: dict.org");
+
+ private JLabel portLabel = new JLabel("Port");
+
+ private JLabel existingAccountLabel =
+ new JLabel(Resources.getString("existingAccount"));
+
+ private JTextField hostField = new JTextField();
+
+ private JTextField portField = new JTextField("2628");
+
+
+ private JPanel strategyPanel = new JPanel(new BorderLayout(10, 10));
+
+ private JPanel strategyTitleBloc = new JPanel(new BorderLayout());
+
+ private JLabel strategyTitle = new JLabel(Resources.getString("strategyList"));
+
+ private JButton strategyLoader = new JButton(Resources.getString("strategyActu"));
+
+ private Vector<String> strategyList;
+ private JScrollPane jScrollPane;
+ private JList strategyBox;
+ private JTextArea strategyDescription = new JTextArea(Resources.getString("strategyDesc"));
+ private JLabel strategyMessage;
+ private boolean strategyMessInstall = false;
+
+ private JPanel mainPanel = new JPanel();
+
+ private Object nextPageIdentifier = WizardPage.SUMMARY_PAGE_IDENTIFIER;
+
+ private DictAccountRegistrationWizard wizard;
+
+ private String initstrategy = "";
+
+ private ArrayList<String> strategiesAssoc = new ArrayList<String>();
+
+ private StrategyThread populateThread = null;
+
+ private boolean firstAccount = false;
+
+ /**
+ * Initial AccountID (null if new account)
+ * Used to check if there are modifications to the account
+ */
+ private AccountID initAccountID = null;
+
+ /**
+ * Creates an instance of <tt>FirstWizardPage</tt>.
+ *
+ * @param wizard the parent wizard
+ */
+ public FirstWizardPage(DictAccountRegistrationWizard wizard)
+ {
+ super(new BorderLayout());
+
+ this.wizard = wizard;
+
+ this.setPreferredSize(new Dimension(300, 150));
+
+ mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+
+ this.populateThread = new StrategyThread(this);
+
+ this.firstAccount = !this.hasAccount();
+
+ if (this.firstAccount)
+ {
+ this.initFirstAccount();
+ }
+ else
+ {
+ this.init();
+ }
+
+ this.populateThread = new StrategyThread(this);
+ this.populateThread.start();
+
+ this.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+ }
+
+ /**
+ * Initializes all panels, buttons, etc.
+ */
+ private void init()
+ {
+ // Host and port Field
+ this.hostField = new JTextField();
+ this.portField = new JTextField("2628");
+
+ this.hostField.getDocument().addDocumentListener(this);
+ this.portField.getDocument().addDocumentListener(this);
+
+ // Server informations
+ this.existingAccountLabel.setForeground(Color.RED);
+
+ this.hostExampleLabel.setForeground(Color.GRAY);
+ this.hostExampleLabel.setFont(hostExampleLabel.getFont().deriveFont(8));
+ this.emptyPanel.setMaximumSize(new Dimension(40, 35));
+ this.hostExampleLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 8,
+ 0));
+
+ labelsPanel.add(hostLabel);
+ labelsPanel.add(emptyPanel);
+ labelsPanel.add(portLabel);
+
+ valuesPanel.add(hostField);
+ valuesPanel.add(hostExampleLabel);
+ valuesPanel.add(portField);
+
+ hostPortPanel.add(labelsPanel, BorderLayout.WEST);
+ hostPortPanel.add(valuesPanel, BorderLayout.CENTER);
+
+ hostPortPanel.setBorder(BorderFactory.createTitledBorder("Server informations"));
+
+ this.labelsPanel.setLayout(new BoxLayout(labelsPanel, BoxLayout.Y_AXIS));
+ this.valuesPanel.setLayout(new BoxLayout(valuesPanel, BoxLayout.Y_AXIS));
+
+ mainPanel.add(hostPortPanel);
+
+ this.portField.addKeyListener(new KeyListener() {
+ public void keyTyped(KeyEvent evt)
+ {
+ // If evt isn't a digit, we don't add it
+ if (!Character.isDigit(evt.getKeyChar()))
+ {
+ evt.consume();
+ }
+ }
+
+ // Not used
+ public void keyPressed(KeyEvent evt) {;}
+ public void keyReleased(KeyEvent evt) {;}
+ });
+
+ // Strategies
+ this.strategyList = new Vector<String>();
+ this.strategyBox = new JList(this.strategyList);
+
+ for (int i=0; i<20; i++)
+ {
+ this.strategyList.add("Elem "+i);
+ }
+
+ this.strategyBox.setVisibleRowCount(6);
+
+ this.strategyBox.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+ this.jScrollPane = new JScrollPane();
+ this.jScrollPane.getViewport().add(this.strategyBox);
+ this.strategyPanel.add(this.jScrollPane);
+
+ // Strategy title + button
+ this.strategyTitleBloc.add(this.strategyTitle, BorderLayout.WEST);
+ this.strategyTitleBloc.add(this.strategyLoader, BorderLayout.EAST);
+
+ // Button action listener
+ this.strategyLoader.setActionCommand("populateList");
+ this.strategyLoader.addActionListener(this);
+
+ // South Panel
+ JPanel sSouthPanel = new JPanel(new BorderLayout());
+
+ // Description
+ this.strategyDescription.setLineWrap(true);
+ this.strategyDescription.setLineWrap(true);
+ this.strategyDescription.setRows(4);
+ this.strategyDescription.setWrapStyleWord(true);
+ this.strategyDescription.setAutoscrolls(false);
+ sSouthPanel.add(this.strategyDescription);
+
+ // Message
+ this.strategyMessage = new JLabel(" ");
+ sSouthPanel.add(this.strategyMessage, BorderLayout.SOUTH);
+
+ this.strategyPanel.add(sSouthPanel, BorderLayout.SOUTH);
+
+ this.strategyPanel.add(this.strategyTitleBloc, BorderLayout.NORTH);
+ this.strategyPanel.setBorder(BorderFactory.createTitledBorder("Strategy selection"));
+ mainPanel.add(this.strategyPanel);
+
+ this.add(mainPanel, BorderLayout.NORTH);
+ }
+
+ private void initFirstAccount()
+ {
+ // Data init
+ this.hostField = new JTextField("dict.org");
+ this.portField = new JTextField("2628");
+
+ // Init strategy box
+ this.strategyList = new Vector<String>();
+ this.strategyBox = new JList(this.strategyList);
+ this.strategyMessage = new JLabel(" ");
+
+
+ JPanel infoTitlePanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
+ JTextArea firstDescription = new JTextArea(Resources.getString("firstAccount"));
+ JLabel title = new JLabel(Resources.getString("dictAccountInfoTitle"));
+
+ // Title
+ title.setFont(title.getFont().deriveFont(Font.BOLD, 14.0f));
+ infoTitlePanel.add(title);
+ this.add(infoTitlePanel, BorderLayout.NORTH);
+ this.add(this.strategyMessage, BorderLayout.SOUTH);
+
+ // Description
+ firstDescription.setLineWrap(true);
+ firstDescription.setLineWrap(true);
+ firstDescription.setRows(6);
+ firstDescription.setWrapStyleWord(true);
+ firstDescription.setAutoscrolls(false);
+ this.add(firstDescription);
+ }
+
+ /**
+ * Implements the <code>WizardPage.getIdentifier</code> to return this
+ * page identifier.
+ *
+ * @return Returns the identifier of the current (the first) page of the wizard.
+ */
+ public Object getIdentifier()
+ {
+ return FIRST_PAGE_IDENTIFIER;
+ }
+
+ /**
+ * Implements the <code>WizardPage.getNextPageIdentifier</code> to return
+ * the next page identifier - the summary page.
+ *
+ * @return Returns the identifier of the next page of the wizard.
+ */
+ public Object getNextPageIdentifier()
+ {
+ return nextPageIdentifier;
+ }
+
+ /**
+ * Implements the <code>WizardPage.getBackPageIdentifier</code> to return
+ * the next back identifier - the default page.
+ *
+ * @return Returns the identifier of the previous page of the wizard.
+ */
+ public Object getBackPageIdentifier()
+ {
+ return WizardPage.DEFAULT_PAGE_IDENTIFIER;
+ }
+
+ /**
+ * Implements the <code>WizardPage.getWizardForm</code> to return this
+ * panel.
+ * @return Returns this form of the wizard.
+ */
+ public Object getWizardForm()
+ {
+ return this;
+ }
+
+ /**
+ * Before this page is displayed enables or disables the "Next" wizard
+ * button according to whether the UIN field is empty.
+ */
+ public void pageShowing()
+ {
+ this.setNextButtonEnabled();
+ }
+
+ /**
+ * Saves the user input when the "Next" wizard buttons is clicked.
+ */
+ public void pageNext()
+ {
+ //*
+ String host = hostField.getText();
+ int port = Integer.parseInt(portField.getText());
+ int stPos;
+ boolean isModified = false;
+
+ if (this.initAccountID instanceof AccountID)
+ { // We check if there is modifications to the server
+ String accHost = (String) this.initAccountID.getAccountProperties()
+ .get(ProtocolProviderFactory.SERVER_ADDRESS);
+ int accPort = Integer.parseInt((String) this.initAccountID.getAccountProperties()
+ .get(ProtocolProviderFactory.SERVER_PORT));
+
+ if (accHost != host || accPort != port)
+ {
+ isModified = true;
+ }
+ }
+
+ // We check if a strategy has been selected
+ if (this.strategyList.size() == 0)
+ { // No Strategy, we get them
+ this.populateStrategies();
+
+ while (this.populateThread.isRunning()) {;}
+ }
+
+ if (this.strategyList.size() == 0)
+ {
+ // No strategy, maybe not connected
+ // Information message is already on the wizard
+ nextPageIdentifier = FIRST_PAGE_IDENTIFIER;
+ this.revalidate();
+ }
+ else if ((!wizard.isModification() && isExistingAccount(host, port))
+ || (isModified && isExistingAccount(host, port)))
+ {
+ nextPageIdentifier = FIRST_PAGE_IDENTIFIER;
+ hostPortPanel.add(existingAccountLabel, BorderLayout.NORTH);
+ this.revalidate();
+ }
+ else
+ {
+ nextPageIdentifier = SUMMARY_PAGE_IDENTIFIER;
+ hostPortPanel.remove(existingAccountLabel);
+
+ DictAccountRegistration registration = wizard.getRegistration();
+
+ registration.setHost(host);
+ registration.setPort(port);
+
+ stPos = this.strategyBox.getSelectedIndex();
+ registration.setStrategyCode(this.strategiesAssoc.get(stPos));
+ registration.setStrategy(this.strategyBox.getSelectedValue().toString());
+ }
+ //*/
+ }
+
+ /**
+ * Enables or disables the "Next" wizard button according to whether the UIN
+ * field is empty.
+ */
+ private void setNextButtonEnabled()
+ {
+ boolean hostOK = DictAdapter.isUrl(hostField.getText());
+ boolean portOK = !this.portField.getText().isEmpty()
+ && Integer.parseInt(this.portField.getText()) > 10;
+
+ if (this.firstAccount)
+ {
+ wizard.getWizardContainer().setNextFinishButtonEnabled(true);
+ }
+ else if (hostOK && portOK)
+ {
+ this.strategyLoader.setEnabled(true);
+ wizard.getWizardContainer().setNextFinishButtonEnabled(true);
+ }
+ else
+ {
+ // Disable the finish button
+ wizard.getWizardContainer().setNextFinishButtonEnabled(false);
+
+ // Clear the list and disable the button
+ this.strategyList.clear();
+ this.strategyLoader.setEnabled(false);
+ }
+ }
+
+ /**
+ * Handles the <tt>DocumentEvent</tt> triggered when user types in the UIN
+ * field. Enables or disables the "Next" wizard button according to whether
+ * the UIN field is empty.
+ *
+ * @param e the <tt>DocumentEvent</tt> triggered when user types in the UIN
+ * field.
+ */
+ public void insertUpdate(DocumentEvent e)
+ {
+ this.setNextButtonEnabled();
+ }
+
+ /**
+ * Handles the <tt>DocumentEvent</tt> triggered when user deletes letters
+ * from the UIN field. Enables or disables the "Next" wizard button
+ * according to whether the UIN field is empty.
+ *
+ * @param e The <tt>DocumentEvent</tt> triggered when user deletes letters
+ * from the UIN field.
+ */
+ public void removeUpdate(DocumentEvent e)
+ {
+ this.setNextButtonEnabled();
+ }
+
+ /**
+ * Handles the <tt>DocumentEvent</tt> triggered when user changes an
+ * attribute or set of attributes from the UIN field.
+ * Currently this notification has no effect and is just here to implement
+ * the DocumentListener interface.
+ *
+ * @param e The <tt>DocumentEvent</tt> triggered when an attribute or set of
+ * attributes changed from the UIN field.
+ */
+ public void changedUpdate(DocumentEvent e)
+ {
+ }
+
+ /**
+ * Invoked when this WizardPage will be hidden eighter because the user has
+ * clicked "Back" or "Next".
+ * This function has no effect.
+ */
+ public void pageHiding()
+ {
+ }
+
+ /**
+ * Invoked when this WizardPage will be shown eighter because the user has
+ * clicked "Back" on the next wizard page or "Next" on the previous one.
+ * This function has no effect.
+ */
+ public void pageShown()
+ {
+ }
+
+ /**
+ * Invoked when user clicks on the "Back" wizard button.
+ * This function has no effect.
+ */
+ public void pageBack()
+ {
+ }
+
+ /**
+ * Fills the Host, Port and Strategy fields in this panel with the data comming
+ * from the given protocolProvider.
+ *
+ * @param protocolProvider The <tt>ProtocolProviderService</tt> to load
+ * the data from.
+ */
+ public void loadAccount(ProtocolProviderService protocolProvider)
+ {
+ AccountID accountID = protocolProvider.getAccountID();
+ String host = (String) accountID.getAccountProperties()
+ .get(ProtocolProviderFactory.SERVER_ADDRESS);
+ String port = (String) accountID.getAccountProperties()
+ .get(ProtocolProviderFactory.SERVER_PORT);
+ String strategy = (String) accountID.getAccountProperties()
+ .get(ProtocolProviderFactory.STRATEGY);
+
+ this.initAccountID = accountID;
+
+ // Host field
+ this.hostField.setText(host);
+
+ // Port Field
+ this.portField.setText(port);
+
+ // Load strategies
+ this.initstrategy = strategy;
+ this.populateStrategies();
+ }
+
+ /**
+ * Handles the action of the button.
+ *
+ * @param e The event generated when the button is pressed.
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ // Button action -> populate the list
+ if (e.getActionCommand().equals("populateList"))
+ {
+ this.populateStrategies();
+ }
+ }
+
+ /**
+ * Checks if an account is stored for this protocol
+ * @return TRUE, if an account is stored - FALSE otherwise
+ */
+ private boolean hasAccount()
+ {
+ ProtocolProviderFactory factory =
+ DictAccRegWizzActivator.getDictProtocolProviderFactory();
+
+ ArrayList registeredAccounts = factory.getRegisteredAccounts();
+ return !registeredAccounts.isEmpty();
+ }
+
+ /**
+ * Checks if an acount with the given account already exists.
+ *
+ * @param host the host of the account to check
+ * @param port the port of the account to check
+ * @return TRUE, if an account with the given name already exists, FALSE -
+ * otherwise
+ */
+ private boolean isExistingAccount(String host, int port)
+ {
+ //*
+ ProtocolProviderFactory factory =
+ DictAccRegWizzActivator.getDictProtocolProviderFactory();
+
+ ArrayList registeredAccounts = factory.getRegisteredAccounts();
+
+ String accHost;
+ int accPort;
+
+ for (int i = 0; i < registeredAccounts.size(); i++)
+ {
+ AccountID accountID = (AccountID) registeredAccounts.get(i);
+ accHost = (String) accountID.getAccountProperties()
+ .get(ProtocolProviderFactory.SERVER_ADDRESS);
+
+ if (host.equalsIgnoreCase(accHost))
+ {
+ // We check the port, only if there is an account with the same host
+ accPort = Integer.parseInt((String) accountID.getAccountProperties()
+ .get(ProtocolProviderFactory.SERVER_PORT));
+
+ if (port == accPort)
+ {
+ return true;
+ }
+ }
+ }
+ //*/
+ return false;
+ }
+
+ /**
+ * Start the thread which will populate the Strategy List
+ */
+ public void populateStrategies()
+ {
+ // Clear ArrayLists
+ this.strategiesAssoc.clear();
+ this.strategyList.clear();
+
+
+ //this.populateThread = new StrategyThread(this);
+ this.populateThread.setHost(this.hostField.getText())
+ .setPort(Integer.parseInt(this.portField.getText()))
+ .sendProcessRequest();
+ }
+
+ /**
+ * Called by the thread, display a message
+ * @param message a message
+ */
+ public void threadMessage(String message)
+ {
+ this.strategyMessage.setText(message);
+ }
+
+ /**
+ * Called by the thread, remove the special message section
+ */
+ public void threadRemoveMessage()
+ {
+ this.strategyMessage.setText(" ");
+ }
+
+ /**
+ * Called by the thread, add a strategy in the list
+ * @param code The strategy code
+ * @param description The strategy description
+ */
+ public void threadAddStrategy(String code, String description)
+ {
+ this.strategiesAssoc.add(code);
+ this.strategyList.add(description);
+ this.strategyBox.setListData(this.strategyList);
+ }
+
+ /**
+ * Automatic selection of a strategy
+ */
+ public void autoSelectStrategy()
+ {
+ int index = -1;
+
+ if (this.initstrategy.length() > 0)
+ { // saved strategy
+ index = this.strategiesAssoc.indexOf(this.initstrategy);
+ this.initstrategy = "";
+ }
+ if (index < 0)
+ {
+ // First case : levenstein distance
+ index = this.strategiesAssoc.indexOf("lev");
+ }
+ if (index < 0)
+ {
+ // Second case : soundex
+ index = this.strategiesAssoc.indexOf("soundex");
+ }
+ if (index < 0)
+ {
+ // Last case : prefix
+ index = this.strategiesAssoc.indexOf("prefix");
+ }
+
+ // If the index is still < 0, we select the first index
+ if (index < 0)
+ {
+ index = 0;
+ }
+ if (index < this.strategyBox.getVisibleRowCount())
+ {
+ // If the index is visible row, we don't need to scroll
+ this.strategyBox.setSelectedIndex(index);
+ }
+ else
+ {
+ // Otherwise, we scroll to the selected value
+ this.strategyBox.setSelectedValue(this.strategyList.get(index), true);
+ }
+
+ }
+
+ /**
+ * Enables or disable the Next Button and the Strategy Button
+ * @param e TRUE enables - FALSE disables
+ */
+ public void setStrategyButtonEnable(boolean e)
+ {
+ // During all the process the buttons and the fieldsset are in the same state
+
+ this.hostField.setEnabled(e);
+ this.portField.setEnabled(e);
+
+ this.strategyLoader.setEnabled(e);
+ wizard.getWizardContainer().setNextFinishButtonEnabled(e);
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/Resources.java b/src/net/java/sip/communicator/plugin/dictaccregwizz/Resources.java
new file mode 100644
index 0000000..c86ebd6
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/Resources.java
@@ -0,0 +1,116 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package net.java.sip.communicator.plugin.dictaccregwizz;
+
+import java.io.*;
+import java.util.*;
+
+import net.java.sip.communicator.util.*;
+
+/**
+ * The <tt>Resources</tt> class manages the access to the internationalization
+ * properties files and the image resources used in this plugin.
+ *
+ * @author ROTH Damien
+ * @author LITZELMAN Cédric
+ */
+public class Resources
+{
+ private static Logger log = Logger.getLogger(Resources.class);
+
+ /**
+ * The name of the resource, where internationalization strings for this
+ * plugin are stored.
+ */
+ private static final String STRING_RESOURCE_NAME
+ = "resources.languages.plugin.dictaccregwizz.resources";
+
+ /**
+ * The name of the resource, where paths to images used in this bundle are
+ * stored.
+ */
+ private static final String IMAGE_RESOURCE_NAME
+ = "net.java.sip.communicator.plugin.dictaccregwizz.resources";
+
+ /**
+ * The string resource bundle.
+ */
+ private static final ResourceBundle STRING_RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(STRING_RESOURCE_NAME);
+
+ /**
+ * The image resource bundle.
+ */
+ private static final ResourceBundle IMAGE_RESOURCE_BUNDLE
+ = ResourceBundle.getBundle(IMAGE_RESOURCE_NAME);
+
+ public static ImageID DICT_LOGO = new ImageID("protocolIcon");
+
+ public static ImageID PAGE_IMAGE = new ImageID("pageImage");
+
+ /**
+ * 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)
+ {
+ try
+ {
+ return STRING_RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return '!' + key + '!';
+ }
+ //return '!' + key + '!';
+ }
+
+ /**
+ * 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[] getImage(ImageID imageID)
+ {
+ byte[] image = new byte[100000];
+
+ String path = IMAGE_RESOURCE_BUNDLE.getString(imageID.getId());
+
+ try
+ {
+ Resources.class.getClassLoader()
+ .getResourceAsStream(path).read(image);
+ }
+ catch (IOException e)
+ {
+ log.error("Failed to load image:" + path, e);
+ }
+
+ return image;
+ }
+
+ /**
+ * Represents the Image Identifier.
+ */
+ public static class ImageID
+ {
+ private String id;
+
+ private ImageID(String id)
+ {
+ this.id = id;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/StrategyThread.java b/src/net/java/sip/communicator/plugin/dictaccregwizz/StrategyThread.java
new file mode 100644
index 0000000..24754e9
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/StrategyThread.java
@@ -0,0 +1,207 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.plugin.dictaccregwizz;
+
+import java.util.*;
+
+import net.java.sip.communicator.util.*;
+
+/**
+ * The <tt>StrategyThread</tt> is the thread called by the wizzard to populate
+ * the strategies list.
+ *
+ * @author ROTH Damien
+ * @author LITZELMANN Cédric
+ */
+public class StrategyThread
+ extends Thread
+{
+ private static Logger logger = Logger.getLogger(StrategyThread.class);
+
+ /**
+ * The hostname of the DICT server.
+ */
+ private String host;
+
+ /**
+ * The port used by the DICT server.
+ */
+ private int port;
+
+ /**
+ * True if the thread is running.
+ */
+ private boolean isRunning = false;
+
+ /**
+ * True if we need to search the strategies handled by the server in order
+ * to populate the list.
+ */
+ private boolean needProcess = false;
+
+ /**
+ * The first page wizard for the DICT protocole.
+ */
+ private FirstWizardPage wizard;
+
+ /**
+ * The java abstraction of the DICT server.
+ */
+ private DictAdapter adapter = null;
+
+ /**
+ * Create a new StrategyThread
+ * @param wizard the wizard for callback methods
+ */
+ public StrategyThread(FirstWizardPage wizard)
+ {
+ this.wizard = wizard;
+ }
+
+ /**
+ * Thread method running until it's destroy
+ */
+ public void run()
+ {
+ while (true)
+ {
+ if (this.needProcess())
+ {
+ this.setRunning(true);
+ this.process();
+ this.processDone();
+ this.setRunning(false);
+ }
+ try
+ {
+ this.sleep(500);
+ }
+ catch (InterruptedException ie)
+ {
+ // Action de log
+ logger.info("DICT THREAD : " + ie);
+ }
+ }
+ }
+
+ /**
+ * Search the strategies on the server and populate the list
+ */
+ private void process()
+ {
+ ArrayList<String> strategies = null;
+ String temp[];
+
+ if (adapter == null) {
+ adapter = new DictAdapter();
+ }
+
+ this.wizard.setStrategyButtonEnable(false);
+
+ // Initialize the connexion
+ this.wizard.threadMessage("Trying to connect to server");
+ if (!adapter.connect(this.host, this.port))
+ {
+ // Connexion attempt failed
+ this.wizard.threadMessage("Connexion attempt failed, this isn't a"
+ + "dict server or the server is offline");
+ return;
+ }
+
+ // Retrieving strategies
+ this.wizard.threadMessage("Retrieving strategies");
+ strategies = adapter.getStrategies();
+ if (strategies == null)
+ {
+ // No strategy found
+ this.wizard.threadMessage("No strategy found on the server");
+ return;
+ }
+
+
+ // Insert the strategies in the list
+ for (int i=0; i<strategies.size(); i++)
+ {
+ temp = strategies.get(i).split(" ", 2);
+
+ this.wizard.threadAddStrategy(temp[0], temp[1].replace("\"", ""));
+ }
+
+ this.wizard.autoSelectStrategy();
+
+ // Closing connexion
+ this.wizard.threadMessage("Closing connexion");
+ adapter.close();
+
+ this.wizard.threadRemoveMessage();
+ this.wizard.setStrategyButtonEnable(true);
+ }
+
+ /**
+ * Set the hostname of the dict server
+ * @param host The hostname of the server.
+ * @return The thread for populating strategie list.
+ */
+ public StrategyThread setHost(String host)
+ {
+ this.host = host;
+ return this;
+ }
+
+ /**
+ * Set the port of the dict server
+ * @param port The port of the DICT server.
+ * @return The thread for populating strategie list.
+ */
+ public StrategyThread setPort(int port)
+ {
+ this.port = port;
+ return this;
+ }
+
+ /**
+ * Checks if the thread is processing a query
+ * @return TRUE if the thread is processing a query - FALSE otherwise
+ */
+ public synchronized boolean isRunning()
+ {
+ return this.isRunning || this.needProcess;
+ }
+
+ /**
+ * Marks the thread as running or not
+ * @param r Activate or desactivate the strategie thread.
+ */
+ public synchronized void setRunning(boolean r)
+ {
+ this.isRunning = r;
+ }
+
+ /**
+ * Checks if we need to process a query
+ * @return Returns true if we need to search and populate the strategie list. False otherwise.
+ */
+ private synchronized boolean needProcess()
+ {
+ return this.needProcess;
+ }
+
+ /**
+ * Init the request
+ */
+ public synchronized void sendProcessRequest()
+ {
+ this.needProcess = true;
+ }
+
+ /**
+ * Defines that the thread has done the query
+ */
+ private synchronized void processDone()
+ {
+ this.needProcess = false;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/dictaccregwizz.manifest.mf b/src/net/java/sip/communicator/plugin/dictaccregwizz/dictaccregwizz.manifest.mf
new file mode 100644
index 0000000..4dcab77
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/dictaccregwizz.manifest.mf
@@ -0,0 +1,31 @@
+Bundle-Activator: net.java.sip.communicator.plugin.dictaccregwizz.DictAccRegWizzActivator
+Bundle-Name: Dict account registration wizard
+Bundle-Description: Dict account registration wizard.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+Import-Package: org.osgi.framework,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.configuration.event,
+ net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.service.protocol.icqconstants,
+ net.java.sip.communicator.service.protocol.event,
+ net.java.sip.communicator.service.contactlist,
+ net.java.sip.communicator.service.contactlist.event,
+ net.java.sip.communicator.service.gui,
+ net.java.sip.communicator.service.gui.event,
+ net.java.sip.communicator.service.browserlauncher,
+ javax.swing,
+ javax.swing.event,
+ javax.swing.table,
+ javax.swing.text,
+ javax.swing.text.html,
+ javax.accessibility,
+ javax.swing.plaf,
+ javax.swing.plaf.metal,
+ javax.swing.plaf.basic,
+ javax.imageio,
+ javax.swing.filechooser,
+ javax.swing.tree,
+ javax.swing.undo,
+ javax.swing.border
diff --git a/src/net/java/sip/communicator/plugin/dictaccregwizz/resources.properties b/src/net/java/sip/communicator/plugin/dictaccregwizz/resources.properties
new file mode 100644
index 0000000..b1146b3
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/dictaccregwizz/resources.properties
@@ -0,0 +1,2 @@
+protocolIcon=resources/images/protocol/dict/dict-16x16.png
+pageImage=resources/images/protocol/dict/dict-64x64.png