|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 789 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,592 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* ContactGroupSSHImpl.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.util.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* A simple, straightforward implementation of a ssh ContactGroup. Since
|
||||
* the SSH 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 Shobhit Jindal
|
||||
*/
|
||||
public class ContactGroupSSHImpl
|
||||
implements ContactGroup
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(ContactGroupSSHImpl.class);
|
||||
|
||||
/**
|
||||
* The name of this SSH 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 ContactGroupSSHImpl 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 ProtocolProviderServiceSSHImpl 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 ContactGroupSSHImpl with the specified name.
|
||||
*
|
||||
* @param groupName the name of the group.
|
||||
* @param parentProvider the protocol provider that created this group.
|
||||
*/
|
||||
public ContactGroupSSHImpl(
|
||||
String groupName,
|
||||
ProtocolProviderServiceSSHImpl 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 ContactSSHImpl to add to this group.
|
||||
*/
|
||||
public void addContact(ContactSSH 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 ContactGroupSSHImpl to add as a subgroup to this group.
|
||||
*/
|
||||
public void addSubgroup(ContactGroupSSHImpl subgroup)
|
||||
{
|
||||
this.subGroups.add(subgroup);
|
||||
subgroup.setParentGroup(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the group that is the new parent of this group
|
||||
* @param parent ContactGroupSSHImpl
|
||||
*/
|
||||
void setParentGroup(ContactGroupSSHImpl 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 ContactGroupSSHImpl subgroup to remove.
|
||||
*/
|
||||
public void removeSubGroup(ContactGroupSSHImpl 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 (ContactSSHImpl) contacts.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the group that is parent of the specified sshGroup or null
|
||||
* if no parent was found.
|
||||
* @param sshGroup the group whose parent we're looking for.
|
||||
* @return the ContactGroupSSHImpl instance that sshGroup
|
||||
* belongs to or null if no parent was found.
|
||||
*/
|
||||
public ContactGroupSSHImpl findGroupParent(
|
||||
ContactGroupSSHImpl sshGroup)
|
||||
{
|
||||
if ( subGroups.contains(sshGroup) )
|
||||
return this;
|
||||
|
||||
Iterator subGroupsIter = subgroups();
|
||||
while (subGroupsIter.hasNext())
|
||||
{
|
||||
ContactGroupSSHImpl subgroup
|
||||
= (ContactGroupSSHImpl) subGroupsIter.next();
|
||||
|
||||
ContactGroupSSHImpl parent
|
||||
= subgroup.findGroupParent(sshGroup);
|
||||
|
||||
if(parent != null)
|
||||
return parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the group that is parent of the specified sshContact or
|
||||
* null if no parent was found.
|
||||
*
|
||||
* @param sshContact the contact whose parent we're looking for.
|
||||
* @return the ContactGroupSSHImpl instance that sshContact
|
||||
* belongs to or <tt>null</tt> if no parent was found.
|
||||
*/
|
||||
public ContactGroupSSHImpl findContactParent(
|
||||
ContactSSHImpl sshContact)
|
||||
{
|
||||
if ( contacts.contains(sshContact) )
|
||||
return this;
|
||||
|
||||
Iterator subGroupsIter = subgroups();
|
||||
while (subGroupsIter.hasNext())
|
||||
{
|
||||
ContactGroupSSHImpl subgroup
|
||||
= (ContactGroupSSHImpl) subGroupsIter.next();
|
||||
|
||||
ContactGroupSSHImpl parent
|
||||
= subgroup.findContactParent(sshContact);
|
||||
|
||||
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())
|
||||
{
|
||||
ContactSSHImpl contact = (ContactSSHImpl) 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())
|
||||
{
|
||||
ContactGroupSSHImpl contactGroup
|
||||
= (ContactGroupSSHImpl) 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 ContactSSHImpl to remove from this group
|
||||
*/
|
||||
public void removeContact(ContactSSHImpl 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 ContactSSHImpl
|
||||
*/
|
||||
public ContactSSHImpl findContactByID(String id)
|
||||
{
|
||||
//first go through the contacts that are direct children.
|
||||
Iterator contactsIter = contacts();
|
||||
|
||||
while(contactsIter.hasNext())
|
||||
{
|
||||
ContactSSHImpl mContact = (ContactSSHImpl)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() )
|
||||
{
|
||||
ContactGroupSSHImpl mGroup = (ContactGroupSSHImpl)groupsIter.next();
|
||||
|
||||
ContactSSHImpl 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())
|
||||
{
|
||||
ContactGroupSSHImpl group = (ContactGroupSSHImpl)subGroups.next();
|
||||
buff.append(group.toString());
|
||||
if (subGroups.hasNext())
|
||||
buff.append("\n");
|
||||
}
|
||||
|
||||
buff.append("\nChildContacts="+countContacts()+":[");
|
||||
|
||||
Iterator contacts = contacts();
|
||||
while (contacts.hasNext())
|
||||
{
|
||||
ContactSSHImpl contact = (ContactSSHImpl) 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 ContactGroupSSHImpl))
|
||||
return false;
|
||||
|
||||
ContactGroupSSHImpl sshGroup
|
||||
= (ContactGroupSSHImpl)obj;
|
||||
|
||||
if( ! sshGroup.getGroupName().equals(getGroupName())
|
||||
|| ! sshGroup.getUID().equals(getUID())
|
||||
|| sshGroup.countContacts() != countContacts()
|
||||
|| sshGroup.countSubgroups() != countSubgroups())
|
||||
return false;
|
||||
|
||||
//traverse child contacts
|
||||
Iterator theirContacts = sshGroup.contacts();
|
||||
|
||||
while(theirContacts.hasNext())
|
||||
{
|
||||
ContactSSHImpl theirContact
|
||||
= (ContactSSHImpl)theirContacts.next();
|
||||
|
||||
ContactSSHImpl ourContact
|
||||
= (ContactSSHImpl)getContact(theirContact.getAddress());
|
||||
|
||||
if(ourContact == null
|
||||
|| !ourContact.equals(theirContact))
|
||||
return false;
|
||||
}
|
||||
|
||||
//traverse subgroups
|
||||
Iterator theirSubgroups = sshGroup.subgroups();
|
||||
|
||||
while(theirSubgroups.hasNext())
|
||||
{
|
||||
ContactGroupSSHImpl theirSubgroup
|
||||
= (ContactGroupSSHImpl)theirSubgroups.next();
|
||||
|
||||
ContactGroupSSHImpl ourSubgroup
|
||||
= (ContactGroupSSHImpl)getGroup(
|
||||
theirSubgroup.getGroupName());
|
||||
|
||||
if(ourSubgroup == null
|
||||
|| !ourSubgroup.equals(theirSubgroup))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,364 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* ContactSSH.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.io.*;
|
||||
import com.jcraft.jsch.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* This interface represents a Contact of SSH Type
|
||||
* As a SSH Session is specific to a contact, additional information needed
|
||||
* to maintain its state with the remote server is present here
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
interface ContactSSH
|
||||
extends Contact
|
||||
{
|
||||
/**
|
||||
* An event type indicating that the message being received is a standard
|
||||
* conversation message sent by another contact.
|
||||
*/
|
||||
public static final int CONVERSATION_MESSAGE_RECEIVED = 1;
|
||||
|
||||
/**
|
||||
* An event type indicting that the message being received is a system
|
||||
* message being sent by the server or a system administrator.
|
||||
*/
|
||||
public static final int SYSTEM_MESSAGE_RECEIVED = 2;
|
||||
|
||||
//Following eight function declations to be moved to Contact
|
||||
|
||||
/**
|
||||
* This method is only called when the contact is added to a new
|
||||
* <tt>ContactGroupSSHImpl</tt> by the
|
||||
* <tt>ContactGroupSSHImpl</tt> itself.
|
||||
*
|
||||
* @param newParentGroup the <tt>ContactGroupSSHImpl</tt> that is now
|
||||
* parent of this <tt>ContactSSHImpl</tt>
|
||||
*/
|
||||
void setParentGroup (ContactGroupSSHImpl newParentGroup);
|
||||
|
||||
/**
|
||||
* Sets <tt>sshPresenceStatus</tt> as the PresenceStatus that this
|
||||
* contact is currently in.
|
||||
* @param sshPresenceStatus the <tt>SSHPresenceStatus</tt>
|
||||
* currently valid for this contact.
|
||||
*/
|
||||
public void setPresenceStatus (PresenceStatus sshPresenceStatus);
|
||||
|
||||
/**
|
||||
* Returns the persistent presence operation set that this contact belongs
|
||||
* to.
|
||||
*
|
||||
* @return the <tt>OperationSetPersistentPresenceSSHImpl</tt> that
|
||||
* this contact belongs to.
|
||||
*/
|
||||
public OperationSetPersistentPresence
|
||||
getParentPresenceOperationSet ();
|
||||
|
||||
/**
|
||||
* Returns the BasicInstant Messaging operation set that this contact
|
||||
* belongs to.
|
||||
*
|
||||
* @return the <tt>OperationSetBasicInstantMessagingSSHImpl</tt> that
|
||||
* this contact belongs to.
|
||||
*/
|
||||
public OperationSetBasicInstantMessaging
|
||||
getParentBasicInstantMessagingOperationSet ();
|
||||
|
||||
/**
|
||||
* Returns the File Transfer operation set that this contact belongs
|
||||
* to.
|
||||
*
|
||||
* @return the <tt>OperationSetFileTransferSSHImpl</tt> that
|
||||
* this contact belongs to.
|
||||
*/
|
||||
public OperationSetFileTransfer
|
||||
getFileTransferOperationSet ();
|
||||
|
||||
/**
|
||||
* Return the type of message received from remote server
|
||||
*
|
||||
* @return messageType
|
||||
*/
|
||||
public int getMessageType ();
|
||||
|
||||
/**
|
||||
* Sets the type of message received from remote server
|
||||
*
|
||||
* @param messageType
|
||||
*/
|
||||
public void setMessageType (int messageType);
|
||||
|
||||
/**
|
||||
* Stores persistent data of the contact.
|
||||
*
|
||||
* @param persistentData of the contact
|
||||
*/
|
||||
public void setPersistentData (String persistentData);
|
||||
|
||||
/**
|
||||
* Makes the contact resolved or unresolved.
|
||||
*
|
||||
* @param resolved true to make the contact resolved; false to
|
||||
* make it unresolved
|
||||
*/
|
||||
public void setResolved (boolean resolved);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Returns true if a command has been sent whos reply was not received yet
|
||||
* false otherwise
|
||||
*
|
||||
* @return commandSent
|
||||
*/
|
||||
public boolean isCommandSent ();
|
||||
|
||||
/**
|
||||
* Set the state of commandSent variable which determines whether a reply
|
||||
* to a command sent is awaited
|
||||
*
|
||||
* @param commandSent
|
||||
*/
|
||||
public void setCommandSent (boolean commandSent);
|
||||
|
||||
/**
|
||||
* Initializes the reader and writers associated with shell of this contact
|
||||
*
|
||||
* @param shellInputStream The InputStream of stack
|
||||
* @param shellOutputStream The OutputStream of stack
|
||||
*/
|
||||
void initializeShellIO (InputStream shellInputStream,
|
||||
OutputStream shellOutputStream);
|
||||
|
||||
/**
|
||||
* Closes the readers and writer associated with shell of this contact
|
||||
*/
|
||||
void closeShellIO ();
|
||||
|
||||
/**
|
||||
* Determines whether a connection to a remote server is already underway
|
||||
*
|
||||
* @return connectionInProgress
|
||||
*/
|
||||
public boolean isConnectionInProgress ();
|
||||
|
||||
/**
|
||||
* Sets the status of connection attempt to remote server
|
||||
*
|
||||
* @param connectionInProgress
|
||||
*/
|
||||
public void setConnectionInProgress (boolean connectionInProgress);
|
||||
|
||||
// /**
|
||||
// * Sets the PS1 prompt of the current shell of Contact
|
||||
// * This method is synchronized
|
||||
// *
|
||||
// * @param sshPrompt to be associated
|
||||
// */
|
||||
// public void setShellPrompt(String sshPrompt);
|
||||
//
|
||||
// /**
|
||||
// * Returns the PS1 prompt of the current shell of Contact
|
||||
// *
|
||||
// * @return sshPrompt
|
||||
// */
|
||||
// public String getShellPrompt();
|
||||
|
||||
|
||||
/**
|
||||
* Saves the details of contact in persistentData
|
||||
*/
|
||||
public void savePersistentDetails ();
|
||||
|
||||
/*
|
||||
* Returns the OperationSetContactInfo associated with this contact
|
||||
*
|
||||
* @return sshConfigurationForm
|
||||
*/
|
||||
public OperationSetContactInfo getSSHConfigurationForm ();
|
||||
|
||||
/**
|
||||
* Returns the JSch Stack identified associated with this contact
|
||||
*
|
||||
* @return jsch
|
||||
*/
|
||||
JSch getJSch ();
|
||||
|
||||
/**
|
||||
* Starts the timer and its task to periodically update the status of
|
||||
* remote machine
|
||||
*/
|
||||
void startTimerTask ();
|
||||
|
||||
/**
|
||||
* Stops the timer and its task to stop updating the status of
|
||||
* remote machine
|
||||
*/
|
||||
void stopTimerTask ();
|
||||
|
||||
/**
|
||||
* Sets the JSch Stack identified associated with this contact
|
||||
*
|
||||
* @param jsch to be associated
|
||||
*/
|
||||
void setJSch (JSch jsch);
|
||||
|
||||
/**
|
||||
* Returns the Username associated with this contact
|
||||
*
|
||||
* @return userName
|
||||
*/
|
||||
String getUserName ();
|
||||
|
||||
/**
|
||||
* Returns the Hostname associated with this contact
|
||||
*
|
||||
* @return hostName
|
||||
*/
|
||||
String getHostName ();
|
||||
|
||||
/**
|
||||
* Returns the Password associated with this contact
|
||||
*
|
||||
* @return password
|
||||
*/
|
||||
String getPassword ();
|
||||
|
||||
/**
|
||||
* Sets the Password associated with this contact
|
||||
*
|
||||
* @param password
|
||||
*/
|
||||
void setPassword (String password);
|
||||
|
||||
/**
|
||||
* Returns the SSH Session associated with this contact
|
||||
*
|
||||
* @return sshSession
|
||||
*/
|
||||
Session getSSHSession ();
|
||||
|
||||
/**
|
||||
* Sets the SSH Session associated with this contact
|
||||
*
|
||||
* @param sshSession the newly created SSH Session to be associated
|
||||
*/
|
||||
void setSSHSession (Session sshSession);
|
||||
|
||||
/**
|
||||
* Returns the SSH Shell Channel associated with this contact
|
||||
*
|
||||
* @return shellChannel
|
||||
*/
|
||||
Channel getShellChannel ();
|
||||
|
||||
/**
|
||||
* Sets the SSH Shell channel associated with this contact
|
||||
*
|
||||
* @param shellChannel to be associated with SSH Session of this contact
|
||||
*/
|
||||
void setShellChannel (Channel shellChannel);
|
||||
|
||||
/**
|
||||
* Sends a message a line to remote machine via the Shell Writer
|
||||
*
|
||||
* @param message to be sent
|
||||
*/
|
||||
public void sendLine (String message)
|
||||
throws IOException;
|
||||
|
||||
// /**
|
||||
// * Reads a line from the remote machine via the Shell Reader
|
||||
// *
|
||||
// * @return message read
|
||||
// */
|
||||
// public String getLine()
|
||||
// throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the Input Stream associated with SSH Channel of this contact
|
||||
*
|
||||
* @return shellInputStream associated with SSH Channel of this contact
|
||||
*/
|
||||
public InputStream getShellInputStream ();
|
||||
|
||||
// /**
|
||||
// * Sets the Input Stream associated with SSH Channel of this contact
|
||||
// *
|
||||
// * @param shellInputStream to be associated with SSH Channel of this
|
||||
// * contact
|
||||
// */
|
||||
// public void setShellInputStream(InputStream shellInputStream);
|
||||
|
||||
/**
|
||||
* Returns the Output Stream associated with SSH Channel of this contact
|
||||
*
|
||||
* @return shellOutputStream associated with SSH Channel of this contact
|
||||
*/
|
||||
public OutputStream getShellOutputStream ();
|
||||
|
||||
// /**
|
||||
// * Sets the Output Stream associated with SSH Channel of this contact
|
||||
// *
|
||||
// * @param shellOutputStream to be associated with SSH Channel of this
|
||||
// * contact
|
||||
// */
|
||||
// public void setShellOutputStream(OutputStream shellOutputStream);
|
||||
//
|
||||
/**
|
||||
* Returns the BufferedReader associated with SSH Channel of this contact
|
||||
*
|
||||
* @return shellReader associated with SSH Channel of this contact
|
||||
*/
|
||||
public InputStreamReader getShellReader ();
|
||||
//
|
||||
// /**
|
||||
// * Sets the BufferedReader associated with SSH Channel of this contact
|
||||
// *
|
||||
// * @param shellReader to be associated with SSH Channel of this contact
|
||||
// */
|
||||
// public void setShellReader(BufferedReader shellReader);
|
||||
|
||||
/**
|
||||
* Returns the PrintWriter associated with SSH Channel of this contact
|
||||
*
|
||||
* @return shellWriter associated with SSH Channel of this contact
|
||||
*/
|
||||
public PrintWriter getShellWriter ();
|
||||
|
||||
// /**
|
||||
// * Sets the PrintWriter associated with SSH Channel of this contact
|
||||
// *
|
||||
// * @param shellWriter to be associated with SSH Channel of this contact
|
||||
// */
|
||||
// public void setShellWriter(PrintWriter shellWriter);
|
||||
}
|
||||
@ -0,0 +1,468 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* ContactSSHFileTransferDaemon.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.io.*;
|
||||
import javax.swing.*;
|
||||
import com.jcraft.jsch.*;
|
||||
|
||||
import net.java.sip.communicator.util.Logger;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class ContactSSHFileTransferDaemon
|
||||
extends Thread
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ContactSSHFileTransferDaemon .class);
|
||||
|
||||
/**
|
||||
* The contact of the remote machine
|
||||
*/
|
||||
private ContactSSH sshContact;
|
||||
|
||||
/**
|
||||
* The currently valid ssh protocol provider
|
||||
*/
|
||||
private ProtocolProviderServiceSSHImpl ppService;
|
||||
|
||||
/**
|
||||
* JSch Channel to be used for file transfer
|
||||
*/
|
||||
private Channel fileTransferChannel;
|
||||
|
||||
/**
|
||||
* The identifier for the Input Stream associated with SCP Channel
|
||||
*/
|
||||
private InputStream scpInputStream = null;
|
||||
|
||||
/**
|
||||
* The identifier for the Output Stream associated with SCP Channel
|
||||
*/
|
||||
private OutputStream scpOutputStream = null;
|
||||
|
||||
/**
|
||||
* Identifier of local file
|
||||
*/
|
||||
private String localPath;
|
||||
|
||||
/**
|
||||
* Identifier of remote file
|
||||
*/
|
||||
private String remotePath;
|
||||
|
||||
/**
|
||||
* File to be uploaded or saved
|
||||
*/
|
||||
private File file;
|
||||
|
||||
/**
|
||||
* The file input stream associated with the file to be uploaded
|
||||
*/
|
||||
private FileInputStream fileInputStream;
|
||||
|
||||
/**
|
||||
* The file output stream associated with the file to be uploaded
|
||||
*/
|
||||
private FileOutputStream fileOutputStream;
|
||||
|
||||
/**
|
||||
* The boolean which determines whether we are uploading or downloading
|
||||
* files
|
||||
*/
|
||||
private boolean uploadFile;
|
||||
|
||||
/**
|
||||
* The currently valid ssh persistent presence operation set
|
||||
*/
|
||||
private OperationSetPersistentPresenceSSHImpl opSetPersPresence = null;
|
||||
|
||||
/**
|
||||
* The currently valid ssh instant messaging operation set
|
||||
*/
|
||||
private OperationSetBasicInstantMessagingSSHImpl instantMessaging = null;
|
||||
|
||||
/**
|
||||
* Creates a new instance of ContactSSHFileTransferDaemon
|
||||
*
|
||||
* @param sshContact The contact of the remote machine
|
||||
* @param opSetPersPresence The current ssh presence operation set
|
||||
* @param instantMessaging The current ssh instant messaging operation set
|
||||
* @param ppService The current ssh protocol provider
|
||||
*/
|
||||
public ContactSSHFileTransferDaemon(
|
||||
ContactSSH sshContact,
|
||||
OperationSetPersistentPresenceSSHImpl opSetPersPresence,
|
||||
OperationSetBasicInstantMessagingSSHImpl instantMessaging,
|
||||
ProtocolProviderServiceSSHImpl ppService)
|
||||
{
|
||||
super();
|
||||
this.sshContact = sshContact;
|
||||
this.opSetPersPresence = opSetPersPresence;
|
||||
this.instantMessaging = instantMessaging;
|
||||
this.ppService = ppService;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when file is to be transfered from local machine
|
||||
* to remote machine
|
||||
*
|
||||
* @param remotePath - the identifier for the remote file
|
||||
* @param localPath - the identifier for the local file
|
||||
*/
|
||||
public void uploadFile(
|
||||
String remotePath,
|
||||
String localPath)
|
||||
{
|
||||
this.uploadFile = true;
|
||||
this.remotePath = remotePath;
|
||||
this.localPath = localPath;
|
||||
|
||||
file = new File(localPath);
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when a file is to be downloaded from remote machine
|
||||
* to local machine
|
||||
*
|
||||
* @param remotePath - the identifier for the remote file
|
||||
* @param localPath - the identifier for the local file
|
||||
*/
|
||||
public void downloadFile(
|
||||
String remotePath,
|
||||
String localPath)
|
||||
{
|
||||
this.uploadFile = false;
|
||||
this.remotePath = remotePath;
|
||||
this.localPath = localPath;
|
||||
|
||||
file = new File(localPath);
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Background thread for the file transfer
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
//oldStatus to be resumed earlier
|
||||
PresenceStatus oldStatus = sshContact.getPresenceStatus();
|
||||
|
||||
opSetPersPresence.changeContactPresenceStatus(
|
||||
sshContact,
|
||||
SSHStatusEnum.CONNECTING);
|
||||
|
||||
try
|
||||
{
|
||||
//create a new JSch session if current is invalid
|
||||
if( !ppService.isSessionValid(sshContact))
|
||||
ppService.createSSHSessionAndLogin(sshContact);
|
||||
|
||||
fileTransferChannel = sshContact.getSSHSession()
|
||||
.openChannel("exec");
|
||||
String command;
|
||||
|
||||
// -p = Preserves modification times, access times, and modes from
|
||||
// the original file
|
||||
if(uploadFile)
|
||||
command = "scp -p -t " + remotePath;
|
||||
else
|
||||
command = "scp -f " + remotePath;
|
||||
|
||||
//the command to be executed on the remote terminal
|
||||
((ChannelExec)fileTransferChannel).setCommand(command);
|
||||
|
||||
scpInputStream = fileTransferChannel.getInputStream();
|
||||
scpOutputStream = fileTransferChannel.getOutputStream();
|
||||
|
||||
fileTransferChannel.connect();
|
||||
|
||||
//file transfer is setup
|
||||
opSetPersPresence.changeContactPresenceStatus(
|
||||
sshContact,
|
||||
SSHStatusEnum.FILE_TRANSFER);
|
||||
|
||||
if(uploadFile)
|
||||
{
|
||||
instantMessaging.deliverMessage(
|
||||
instantMessaging.createMessage(
|
||||
"Uploading " + file.getName() + " to server"),
|
||||
sshContact);
|
||||
|
||||
upload();
|
||||
}
|
||||
else
|
||||
{
|
||||
instantMessaging.deliverMessage(
|
||||
instantMessaging.createMessage(
|
||||
"Downloading " + file.getName() + " from server"),
|
||||
sshContact);
|
||||
|
||||
download();
|
||||
}
|
||||
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
//presently errors(any type) are directly logged directly in chat
|
||||
instantMessaging.deliverMessage(
|
||||
instantMessaging.createMessage(ex.getMessage()),
|
||||
sshContact);
|
||||
|
||||
ex.printStackTrace();
|
||||
logger.error(ex.getMessage());
|
||||
|
||||
try
|
||||
{
|
||||
if(fileInputStream!=null)
|
||||
{
|
||||
fileInputStream.close();
|
||||
}
|
||||
|
||||
if(fileOutputStream!=null)
|
||||
{
|
||||
fileOutputStream.close();
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{}
|
||||
}
|
||||
|
||||
// restore old status
|
||||
opSetPersPresence.changeContactPresenceStatus(
|
||||
sshContact,
|
||||
oldStatus);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for error in reading stream of remote machine
|
||||
*
|
||||
* @return 0 for success
|
||||
* @return 1 for error
|
||||
* @return 2 for fatal error
|
||||
* @return -1 otherwise
|
||||
*
|
||||
* @throws IOException when the network goes down
|
||||
*/
|
||||
private int checkAck(InputStream inputStream)
|
||||
throws IOException
|
||||
{
|
||||
int result = inputStream.read();
|
||||
|
||||
// read error message
|
||||
if(result==1 || result==2)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
int ch;
|
||||
|
||||
do
|
||||
{
|
||||
//read a line of message
|
||||
ch = inputStream.read();
|
||||
buffer.append((char)ch);
|
||||
|
||||
}while(ch != '\n');
|
||||
|
||||
ppService.getUIService().getPopupDialog().showMessagePopupDialog(
|
||||
buffer.toString(),
|
||||
"File Transfer Error: " + sshContact.getDisplayName(),
|
||||
ppService.getUIService().getPopupDialog().ERROR_MESSAGE);
|
||||
|
||||
logger.error(buffer.toString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the file to the remote server
|
||||
*
|
||||
* @throws IOException when the network goes down
|
||||
* @throws OperationFailedException when server behaves unexpectedly
|
||||
*/
|
||||
private void upload()
|
||||
throws IOException,
|
||||
OperationFailedException
|
||||
{
|
||||
fileInputStream = new FileInputStream(file);
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int result, bytesRead;
|
||||
|
||||
if( (result = checkAck(scpInputStream)) !=0)
|
||||
throw new OperationFailedException("Error in Ack", result);
|
||||
|
||||
// send "C0644 filesize filename", where filename should not include '/'
|
||||
long filesize= file.length();
|
||||
String command = "C0644 " + filesize + " ";
|
||||
|
||||
// if(lfile.lastIndexOf('/')>0)
|
||||
// {
|
||||
// command+=lfile.substring(lfile.lastIndexOf('/')+1);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// command+=lfile;
|
||||
// }
|
||||
|
||||
command += file.getName() + "\n";
|
||||
logger.trace(command);
|
||||
scpOutputStream.write(command.getBytes());
|
||||
scpOutputStream.flush();
|
||||
|
||||
if( (result = checkAck(scpInputStream)) !=0)
|
||||
throw new OperationFailedException("Error in Ack", result);
|
||||
|
||||
while(true)
|
||||
{
|
||||
bytesRead = fileInputStream.read(buffer, 0, buffer.length);
|
||||
if(bytesRead <= 0)
|
||||
break;
|
||||
|
||||
scpOutputStream.write(buffer, 0, bytesRead); //out.flush();
|
||||
}
|
||||
fileInputStream.close();
|
||||
fileInputStream = null;
|
||||
|
||||
// send '\0'
|
||||
buffer[0]=0; scpOutputStream.write(buffer, 0, 1);
|
||||
scpOutputStream.flush();
|
||||
|
||||
if( (result = checkAck(scpInputStream)) !=0)
|
||||
throw new OperationFailedException("Error in Ack", result);
|
||||
|
||||
scpInputStream.close();
|
||||
scpOutputStream.close();
|
||||
|
||||
fileTransferChannel.disconnect();
|
||||
|
||||
instantMessaging.deliverMessage(
|
||||
instantMessaging.createMessage(file.getName()
|
||||
+ " uploaded to Server"),
|
||||
sshContact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a file from the remote machine
|
||||
*
|
||||
* @throws IOException when the network goes down
|
||||
* @throws OperationFailedException when server behaves unexpectedly
|
||||
*/
|
||||
private void download()
|
||||
throws IOException,
|
||||
OperationFailedException
|
||||
{
|
||||
fileOutputStream = new FileOutputStream(file);
|
||||
|
||||
int result;
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
|
||||
// send '\0'
|
||||
buffer[0]=0;
|
||||
|
||||
scpOutputStream.write(buffer, 0, 1);
|
||||
scpOutputStream.flush();
|
||||
|
||||
int ch = checkAck(scpInputStream);
|
||||
|
||||
if(ch!='C')
|
||||
{
|
||||
throw new OperationFailedException("Invalid reply from server", 12);
|
||||
}
|
||||
|
||||
// read '0644 '
|
||||
scpInputStream.read(buffer, 0, 5);
|
||||
|
||||
long filesize=0L;
|
||||
while(true)
|
||||
{
|
||||
if(scpInputStream.read(buffer, 0, 1) < 0)
|
||||
{
|
||||
// error
|
||||
break;
|
||||
}
|
||||
if(buffer[0]==' ')break;
|
||||
filesize=filesize*10L+(long)(buffer[0]-'0');
|
||||
}
|
||||
|
||||
String file=null;
|
||||
for(int i=0;;i++)
|
||||
{
|
||||
scpInputStream.read(buffer, i, 1);
|
||||
if(buffer[i]==(byte)0x0a)
|
||||
{
|
||||
file=new String(buffer, 0, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("filesize="+filesize+", file="+file);
|
||||
|
||||
// send '\0'
|
||||
buffer[0]=0;
|
||||
scpOutputStream.write(buffer, 0, 1);
|
||||
scpOutputStream.flush();
|
||||
|
||||
// read a content of lfile
|
||||
int foo;
|
||||
while(true)
|
||||
{
|
||||
if(buffer.length<filesize)
|
||||
foo=buffer.length;
|
||||
else
|
||||
foo=(int)filesize;
|
||||
|
||||
foo = scpInputStream.read(buffer, 0, foo);
|
||||
if(foo<0)
|
||||
{
|
||||
// error
|
||||
break;
|
||||
}
|
||||
fileOutputStream.write(buffer, 0, foo);
|
||||
filesize-=foo;
|
||||
if(filesize==0L) break;
|
||||
}
|
||||
fileOutputStream.close();
|
||||
fileOutputStream=null;
|
||||
|
||||
if( (result = checkAck(scpInputStream)) !=0)
|
||||
throw new OperationFailedException("Error in Ack", result);
|
||||
|
||||
// send '\0'
|
||||
buffer[0]=0;
|
||||
scpOutputStream.write(buffer, 0, 1);
|
||||
scpOutputStream.flush();
|
||||
|
||||
scpInputStream.close();
|
||||
scpOutputStream.close();
|
||||
|
||||
fileTransferChannel.disconnect();
|
||||
|
||||
instantMessaging.deliverMessage(
|
||||
instantMessaging.createMessage(
|
||||
this.file.getName() + " downloaded from Server"),
|
||||
sshContact);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,905 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* ContactSSHImpl.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Projec
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import com.jcraft.jsch.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import net.java.sip.communicator.impl.protocol.ssh.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import net.java.sip.communicator.util.Logger;
|
||||
|
||||
/**
|
||||
* A Contact of SSH Type
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class ContactSSHImpl
|
||||
implements ContactSSH
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(ContactSSHImpl.class);
|
||||
|
||||
/**
|
||||
* This acts as a seperator between details stored in persistent data
|
||||
*/
|
||||
private final String detailsSeperator = Resources
|
||||
.getString("detailsSeperator");
|
||||
|
||||
/**
|
||||
* The identifier for SSH Stack
|
||||
* Java Secure Channel JSch
|
||||
*/
|
||||
private JSch jsch;
|
||||
|
||||
/**
|
||||
* Interface for user to provide details about machine
|
||||
*/
|
||||
private OperationSetContactInfo sshConfigurationForm;
|
||||
|
||||
/**
|
||||
* A Timer Daemon to update the status of this contact
|
||||
*/
|
||||
private Timer timer = new Timer(true);
|
||||
|
||||
/**
|
||||
* A Daemon to retrieve and fire messages received from remote machine
|
||||
*/
|
||||
private ContactSSHReaderDaemon contactSSHReaderDaemon;
|
||||
|
||||
/**
|
||||
* The id of the contact.
|
||||
*/
|
||||
private String contactID = null;
|
||||
|
||||
/**
|
||||
* The persistentData of the contact.
|
||||
*/
|
||||
private String persistentData = null;
|
||||
|
||||
// /**
|
||||
// * This stores the prompt string of shell
|
||||
// */
|
||||
// private String sshPrompt;
|
||||
|
||||
/**
|
||||
* The provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceSSHImpl parentProvider = null;
|
||||
|
||||
/**
|
||||
* The identifier of the type of message received from server
|
||||
*/
|
||||
private int messageType;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The identifier for SSH Session with the remote server
|
||||
*/
|
||||
private Session sshSession = null;
|
||||
|
||||
/**
|
||||
* The identifier for a sshShellChannel with the remote server is of type
|
||||
* shell - for an interactive SSH Session with the remote machine
|
||||
*
|
||||
* Other types
|
||||
* sftp - to tranfer files from/to the remote machine
|
||||
* exec - X forwarding
|
||||
* direct-tcpip - stream forwarding
|
||||
*/
|
||||
private Channel sshShellChannel = null;
|
||||
|
||||
/**
|
||||
* The identifier for the Shell Input Stream associated with SSH Sesion
|
||||
*/
|
||||
private InputStream shellInputStream = null;
|
||||
|
||||
/**
|
||||
* The identifier for the Shell Output Stream associated with SSH Sesion
|
||||
*/
|
||||
private OutputStream shellOutputStream = null;
|
||||
|
||||
/**
|
||||
* Higher wrapper for shellInputStream
|
||||
*/
|
||||
private InputStreamReader shellReader = null;
|
||||
|
||||
/**
|
||||
* Higher wrapper for shellOutputStream
|
||||
*/
|
||||
private PrintWriter shellWriter = null;
|
||||
|
||||
/**
|
||||
* The group that belong to.
|
||||
*/
|
||||
private ContactGroupSSHImpl parentGroup = null;
|
||||
|
||||
/**
|
||||
* The presence status of the contact.
|
||||
*/
|
||||
private PresenceStatus presenceStatus = SSHStatusEnum.NOT_AVAILABLE;
|
||||
|
||||
/**
|
||||
* Determines whether this contact is persistent, i.e. member of the contact
|
||||
* list or whether it is here only temporarily.
|
||||
*/
|
||||
private boolean isPersistent = false;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Determines whether an connection attempt to remote server is already
|
||||
* underway
|
||||
*/
|
||||
private boolean isConnectionInProgress = false;
|
||||
|
||||
/**
|
||||
* Determines whether the message received from remote machine is as a
|
||||
* result of command sent to it
|
||||
*/
|
||||
private boolean commandSent = false;
|
||||
|
||||
/**
|
||||
* A lock to synchronize the access of commandSent boolean object
|
||||
* with the reader thread.
|
||||
*/
|
||||
private final Object lock = new Object();
|
||||
|
||||
/**
|
||||
* 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 ContactSSHImpl(
|
||||
String id,
|
||||
ProtocolProviderServiceSSHImpl parentProvider)
|
||||
{
|
||||
this.contactID = id;
|
||||
this.parentProvider = parentProvider;
|
||||
|
||||
this.sshConfigurationForm =
|
||||
new OperationSetContactInfo(this);
|
||||
|
||||
this.savePersistentDetails();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the reader and writers associated with shell of this contact
|
||||
*
|
||||
* @param shellInputStream The InputStream of stack
|
||||
* @param shellOutputStream The OutputStream of stack
|
||||
*/
|
||||
public void initializeShellIO(
|
||||
InputStream shellInputStream,
|
||||
OutputStream shellOutputStream)
|
||||
{
|
||||
this.shellInputStream = shellInputStream;
|
||||
this.shellOutputStream = shellOutputStream;
|
||||
shellReader = new InputStreamReader(shellInputStream);
|
||||
shellWriter = new PrintWriter(shellOutputStream);
|
||||
|
||||
contactSSHReaderDaemon = new ContactSSHReaderDaemon(this);
|
||||
contactSSHReaderDaemon.setDaemon(true);
|
||||
contactSSHReaderDaemon.isActive(true);
|
||||
contactSSHReaderDaemon.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the readers and writer associated with shell of this contact
|
||||
*/
|
||||
public void closeShellIO()
|
||||
{
|
||||
try
|
||||
{
|
||||
shellReader.close();
|
||||
shellInputStream.close();
|
||||
}
|
||||
catch(IOException ex)
|
||||
{}
|
||||
|
||||
try
|
||||
{
|
||||
shellWriter.close();
|
||||
shellOutputStream.close();
|
||||
}
|
||||
catch(IOException ex)
|
||||
{}
|
||||
|
||||
shellInputStream = null;
|
||||
|
||||
shellReader = null;
|
||||
|
||||
shellOutputStream = null;
|
||||
|
||||
shellWriter = null;
|
||||
|
||||
try
|
||||
{
|
||||
sshShellChannel.disconnect();
|
||||
}
|
||||
catch(Exception e)
|
||||
{}
|
||||
|
||||
// Removing the reference to current channel
|
||||
// a new shell channel will be created for the next message
|
||||
sshShellChannel = null;
|
||||
|
||||
// remove the reference of session if it were also disconnected
|
||||
// like in the case of exit command
|
||||
if(!sshSession.isConnected())
|
||||
{
|
||||
sshSession = null;
|
||||
jsch = null;
|
||||
}
|
||||
|
||||
((OperationSetPersistentPresenceSSHImpl)getParentPresenceOperationSet()).
|
||||
changeContactPresenceStatus(this, SSHStatusEnum.ONLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message a line to remote machine via the Shell Writer
|
||||
*
|
||||
* @param message to be sent
|
||||
*/
|
||||
public void sendLine(String message)
|
||||
throws IOException
|
||||
{
|
||||
// logger.debug("SSH TO: " + this.contactID + ": " + message);
|
||||
shellWriter.println(message);
|
||||
shellWriter.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a line from the remote machine via the Shell Reader
|
||||
*
|
||||
* @return message read
|
||||
*/
|
||||
// public String getLine()
|
||||
// throws IOException
|
||||
// {
|
||||
// String line = shellReader.readLine();
|
||||
//// logger.debug("SSH FROM: " + this.contactID + ": " + line);
|
||||
//
|
||||
// // null is never returned normally, the reading attempt returs a string
|
||||
// // or blocks until one line is available
|
||||
// if(line == null)
|
||||
// {
|
||||
// sshShellChannel.disconnect();
|
||||
// sshShellChannel = null;
|
||||
// sshSession = null;
|
||||
// throw(new IOException("Unexpected Reply from remote Server"));
|
||||
// }
|
||||
// return line;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Starts the timer and its task to periodically update the status of
|
||||
* remote machine
|
||||
*/
|
||||
public void startTimerTask()
|
||||
{
|
||||
timer.scheduleAtFixedRate(new OperationSetContactTimerSSHImpl(this),
|
||||
2000, sshConfigurationForm.getUpdateInterval()*1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the timer and its task to stop updating the status of
|
||||
* remote machine
|
||||
*/
|
||||
public void stopTimerTask()
|
||||
{
|
||||
timer.cancel();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Saves the details of contact in persistentData seperated by detailsSeperator
|
||||
* Passowrd is saved unsecurely using Base64 encoding
|
||||
*/
|
||||
public void savePersistentDetails()
|
||||
{
|
||||
persistentData =
|
||||
this.sshConfigurationForm.getHostName() +
|
||||
detailsSeperator +
|
||||
this.sshConfigurationForm.getUserName() +
|
||||
detailsSeperator +
|
||||
new String(Base64.encode(this.sshConfigurationForm.getPassword()
|
||||
.getBytes())) +
|
||||
detailsSeperator + sshConfigurationForm.getPort() +
|
||||
detailsSeperator +
|
||||
sshConfigurationForm.getTerminalType() +
|
||||
detailsSeperator +
|
||||
sshConfigurationForm.getUpdateInterval();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores persistent data in fields of the contact seperated by
|
||||
* detailsSeperator.
|
||||
*
|
||||
* @param persistentData of the contact
|
||||
*/
|
||||
public void setPersistentData(String persistentData)
|
||||
{
|
||||
this.persistentData = persistentData;
|
||||
int firstCommaIndex = this.persistentData.indexOf(detailsSeperator);
|
||||
int secondCommaIndex = this.persistentData.indexOf(detailsSeperator,
|
||||
firstCommaIndex +1);
|
||||
int thirdCommaIndex = this.persistentData.indexOf(detailsSeperator,
|
||||
secondCommaIndex +1);
|
||||
int fourthCommaIndex = this.persistentData.indexOf(detailsSeperator,
|
||||
thirdCommaIndex +1);
|
||||
int fifthCommaIndex = this.persistentData.indexOf(detailsSeperator,
|
||||
fourthCommaIndex +1);
|
||||
|
||||
logger.debug("Commas: " + firstCommaIndex + " " + secondCommaIndex + " "
|
||||
+ thirdCommaIndex + " " +fourthCommaIndex + " "
|
||||
+fifthCommaIndex);
|
||||
|
||||
this.sshConfigurationForm.setHostNameField(
|
||||
this.persistentData.substring(0,firstCommaIndex));
|
||||
|
||||
this.sshConfigurationForm.setUserNameField(
|
||||
this.persistentData.substring(firstCommaIndex+1,
|
||||
secondCommaIndex));
|
||||
|
||||
if( (thirdCommaIndex - secondCommaIndex) > 1)
|
||||
{
|
||||
if(this.persistentData.substring(secondCommaIndex+1).length()>0)
|
||||
this.sshConfigurationForm.setPasswordField(
|
||||
new String(Base64.decode(this.persistentData
|
||||
.substring(secondCommaIndex+1, thirdCommaIndex))));
|
||||
}
|
||||
|
||||
|
||||
this.sshConfigurationForm.setPort(
|
||||
this.persistentData.substring(thirdCommaIndex + 1,
|
||||
fourthCommaIndex));
|
||||
|
||||
this.sshConfigurationForm.setTerminalType(
|
||||
this.persistentData.substring(fourthCommaIndex + 1,
|
||||
fifthCommaIndex));
|
||||
|
||||
this.sshConfigurationForm.setUpdateInterval(new Integer(Integer
|
||||
.parseInt(this.persistentData.substring(fifthCommaIndex+1)) ));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a connection to a remote server is already underway
|
||||
*
|
||||
* @return isConnectionInProgress
|
||||
*/
|
||||
public boolean isConnectionInProgress()
|
||||
{
|
||||
return this.isConnectionInProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status of connection attempt to remote server
|
||||
* This method is synchronized
|
||||
*
|
||||
* @param isConnectionInProgress
|
||||
*/
|
||||
public synchronized void setConnectionInProgress(boolean isConnectionInProgress)
|
||||
{
|
||||
this.isConnectionInProgress = isConnectionInProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OperationSetContactInfo associated with this contact
|
||||
*
|
||||
* @return sshConfigurationForm
|
||||
*/
|
||||
public OperationSetContactInfo getSSHConfigurationForm()
|
||||
{
|
||||
return this.sshConfigurationForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSch Stack identified associated with this contact
|
||||
*
|
||||
* @return jsch
|
||||
*/
|
||||
public JSch getJSch()
|
||||
{
|
||||
return this.jsch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the JSch Stack identified associated with this contact
|
||||
*
|
||||
* @param jsch to be associated
|
||||
*/
|
||||
public void setJSch(JSch jsch)
|
||||
{
|
||||
this.jsch = jsch;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is only called when the contact is added to a new
|
||||
* <tt>ContactGroupSSHImpl</tt> by the
|
||||
* <tt>ContactGroupSSHImpl</tt> itself.
|
||||
*
|
||||
* @param newParentGroup the <tt>ContactGroupSSHImpl</tt> that is now
|
||||
* parent of this <tt>ContactSSHImpl</tt>
|
||||
*/
|
||||
public void setParentGroup(ContactGroupSSHImpl newParentGroup)
|
||||
{
|
||||
this.parentGroup = newParentGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Hostname associated with this contact
|
||||
*
|
||||
* @return hostName
|
||||
*/
|
||||
public String getHostName()
|
||||
{
|
||||
return sshConfigurationForm.getHostName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 true if a command has been sent whos reply was not received yet
|
||||
* false otherwise
|
||||
*
|
||||
* @return commandSent
|
||||
*/
|
||||
public boolean isCommandSent()
|
||||
{
|
||||
return this.commandSent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of commandSent variable which determines whether a reply
|
||||
* to a command sent is awaited
|
||||
*/
|
||||
public void setCommandSent(boolean commandSent)
|
||||
{
|
||||
synchronized(lock)
|
||||
{
|
||||
this.commandSent = commandSent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of message received from remote server
|
||||
*
|
||||
* @return messageType
|
||||
*/
|
||||
public int getMessageType()
|
||||
{
|
||||
return this.messageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of message received from remote server
|
||||
*
|
||||
* @param messageType
|
||||
*/
|
||||
public void setMessageType(int messageType)
|
||||
{
|
||||
this.messageType = messageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the contact.
|
||||
*
|
||||
* @return presenceStatus
|
||||
*/
|
||||
public PresenceStatus getPresenceStatus()
|
||||
{
|
||||
return this.presenceStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets <tt>sshPresenceStatus</tt> as the PresenceStatus that this
|
||||
* contact is currently in.
|
||||
* @param sshPresenceStatus the <tt>SSHPresenceStatus</tt>
|
||||
* currently valid for this contact.
|
||||
*/
|
||||
public void setPresenceStatus(PresenceStatus sshPresenceStatus)
|
||||
{
|
||||
this.presenceStatus = sshPresenceStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact represents our own identity.
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public boolean isLocal()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the group that contains this contact.
|
||||
* @return a reference to the <tt>ContactGroupSSHImpl</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("ContactSSHImpl[ 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 persistent data of the contact.
|
||||
*
|
||||
* @return persistentData of the contact
|
||||
*/
|
||||
public String getPersistentData()
|
||||
{
|
||||
return persistentData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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 ContactSSHImpl))
|
||||
return false;
|
||||
|
||||
ContactSSHImpl sshContact = (ContactSSHImpl) obj;
|
||||
|
||||
return this.getAddress().equals(sshContact.getAddress());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the persistent presence operation set that this contact belongs
|
||||
* to.
|
||||
*
|
||||
* @return the <tt>OperationSetPersistentPresenceSSHImpl</tt> that
|
||||
* this contact belongs to.
|
||||
*/
|
||||
public OperationSetPersistentPresence
|
||||
getParentPresenceOperationSet()
|
||||
{
|
||||
return (OperationSetPersistentPresence)parentProvider
|
||||
.getOperationSet(OperationSetPersistentPresence.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the BasicInstant Messaging operation set that this contact belongs
|
||||
* to.
|
||||
*
|
||||
* @return the <tt>OperationSetBasicInstantMessagingSSHImpl</tt> that
|
||||
* this contact belongs to.
|
||||
*/
|
||||
public OperationSetBasicInstantMessaging
|
||||
getParentBasicInstantMessagingOperationSet()
|
||||
{
|
||||
return (OperationSetBasicInstantMessaging)parentProvider
|
||||
.getOperationSet(OperationSetBasicInstantMessaging.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the File Transfer operation set that this contact belongs
|
||||
* to.
|
||||
*
|
||||
* @return the <tt>OperationSetFileTransferSSHImpl</tt> that
|
||||
* this contact belongs to.
|
||||
*/
|
||||
public OperationSetFileTransfer
|
||||
getFileTransferOperationSet()
|
||||
{
|
||||
return (OperationSetFileTransfer)parentProvider
|
||||
.getOperationSet(OperationSetFileTransfer.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the SSH Session associated with this contact
|
||||
*
|
||||
* @return sshSession
|
||||
*/
|
||||
public Session getSSHSession()
|
||||
{
|
||||
return this.sshSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SSH Session associated with this contact
|
||||
*
|
||||
* @param sshSession the newly created SSH Session to be associated
|
||||
*/
|
||||
public void setSSHSession(Session sshSession)
|
||||
{
|
||||
this.sshSession = sshSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SSH Shell Channel associated with this contact
|
||||
*
|
||||
* @return sshShellChannel
|
||||
*/
|
||||
public Channel getShellChannel()
|
||||
{
|
||||
return this.sshShellChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SSH Shell channel associated with this contact
|
||||
*
|
||||
* @param sshShellChannel to be associated with SSH Session of this contact
|
||||
*/
|
||||
public void setShellChannel(Channel sshShellChannel)
|
||||
{
|
||||
this.sshShellChannel = sshShellChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Input Stream associated with SSH Channel of this contact
|
||||
*
|
||||
* @return shellInputStream associated with SSH Channel of this contact
|
||||
*/
|
||||
public InputStream getShellInputStream()
|
||||
{
|
||||
return this.shellInputStream;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Sets the Input Stream associated with SSH Channel of this contact
|
||||
// *
|
||||
// * @param shellInputStream to be associated with SSH Channel of this contact
|
||||
// */
|
||||
// public void setShellInputStream(InputStream shellInputStream)
|
||||
// {
|
||||
// this.shellInputStream = shellInputStream;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns the Output Stream associated with SSH Channel of this contact
|
||||
*
|
||||
* @return shellOutputStream associated with SSH Channel of this contact
|
||||
*/
|
||||
public OutputStream getShellOutputStream()
|
||||
{
|
||||
return this.shellOutputStream;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Sets the Output Stream associated with SSH Channel of this contact
|
||||
// *
|
||||
// * @param shellOutputStream to be associated with SSH Channel of this contact
|
||||
// */
|
||||
// public void setShellOutputStream(OutputStream shellOutputStream)
|
||||
// {
|
||||
// this.shellOutputStream = shellOutputStream;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns the BufferedReader associated with SSH Channel of this contact
|
||||
*
|
||||
* @return shellReader associated with SSH Channel of this contact
|
||||
*/
|
||||
public InputStreamReader getShellReader()
|
||||
{
|
||||
return this.shellReader;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Sets the BufferedReader associated with SSH Channel of this contact
|
||||
// *
|
||||
// * @param shellReader to be associated with SSH Channel of this contact
|
||||
// */
|
||||
// public void setShellReader(BufferedReader shellReader)
|
||||
// {
|
||||
// this.shellReader = shellReader;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns the PrintWriter associated with SSH Channel of this contact
|
||||
*
|
||||
* @return shellWriter associated with SSH Channel of this contact
|
||||
*/
|
||||
public PrintWriter getShellWriter()
|
||||
{
|
||||
return this.shellWriter;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Sets the PrintWriter associated with SSH Channel of this contact
|
||||
// *
|
||||
// * @param shellWriter to be associated with SSH Channel of this contact
|
||||
// */
|
||||
// public void setShellWriter(PrintWriter shellWriter)
|
||||
// {
|
||||
// this.shellWriter = shellWriter;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns the userName associated with SSH Channel of this contact
|
||||
*
|
||||
* @return userName associated with SSH Channel of this contact
|
||||
*/
|
||||
public String getUserName()
|
||||
{
|
||||
return sshConfigurationForm.getUserName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password associated with SSH Channel of this contact
|
||||
*
|
||||
* @return password associated with SSH Channel of this contact
|
||||
*/
|
||||
public String getPassword()
|
||||
{
|
||||
return sshConfigurationForm.getPassword();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Password associated with this contact
|
||||
*
|
||||
* @param password
|
||||
*/
|
||||
public void setPassword(String password)
|
||||
{
|
||||
this.sshConfigurationForm.setPasswordField(password);
|
||||
savePersistentDetails();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Sets the PS1 prompt of the current shell of Contact
|
||||
// *
|
||||
// * @param sshPrompt to be associated
|
||||
// */
|
||||
// public void setShellPrompt(String sshPrompt)
|
||||
// {
|
||||
// this.sshPrompt = sshPrompt;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Returns the PS1 prompt of the current shell of Contact
|
||||
// *
|
||||
// * @return sshPrompt
|
||||
// */
|
||||
// public String getShellPrompt()
|
||||
// {
|
||||
// return this.sshPrompt;
|
||||
// }
|
||||
}
|
||||
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* ContactSSHReaderDaemon.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.io.*;
|
||||
import javax.swing.*;
|
||||
|
||||
import net.java.sip.communicator.util.Logger;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class ContactSSHReaderDaemon
|
||||
extends Thread
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ContactSSHReaderDaemon.class);
|
||||
|
||||
/**
|
||||
* A Buffer to aggregate replies to be sent as one message
|
||||
*/
|
||||
private StringBuffer replyBuffer;
|
||||
|
||||
/**
|
||||
* The identifier of Contact representing the remote machine
|
||||
*/
|
||||
private ContactSSHImpl sshContact;
|
||||
|
||||
/**
|
||||
* The identifier of the message received from server
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* An identifier representing the state of Reader Daemon
|
||||
*/
|
||||
private boolean isActive = false;
|
||||
|
||||
/**
|
||||
* This OperationSet delivers incoming message
|
||||
*/
|
||||
private OperationSetBasicInstantMessagingSSHImpl instantMessaging;
|
||||
|
||||
/**
|
||||
* Input Stream of remote user to be read
|
||||
*/
|
||||
private InputStream shellInputStream;
|
||||
|
||||
/**
|
||||
* Buffered Reader associated with above input stream
|
||||
*/
|
||||
private InputStreamReader shellReader;
|
||||
|
||||
// /**
|
||||
// * This OperationSet delivers incoming message
|
||||
// */
|
||||
// private OperationSetPersistentPresenceSSHImpl persistentPresence;
|
||||
|
||||
/**
|
||||
* Bytes available in Input Stream before reading
|
||||
*/
|
||||
private int bytesAvailable;
|
||||
|
||||
private int bytesRead;
|
||||
|
||||
char buffer[] = new char[1024], buf;
|
||||
|
||||
/**
|
||||
* Creates a new instance of ContactSSHReaderDaemon
|
||||
*/
|
||||
public ContactSSHReaderDaemon(ContactSSH sshContact)
|
||||
{
|
||||
this.sshContact = (ContactSSHImpl)sshContact;
|
||||
instantMessaging = (OperationSetBasicInstantMessagingSSHImpl) sshContact
|
||||
.getProtocolProvider().getOperationSet(
|
||||
OperationSetBasicInstantMessaging.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the remote machine, updating the chat window as necessary
|
||||
* in a background thread
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
shellInputStream = sshContact.getShellInputStream();
|
||||
shellReader = sshContact.getShellReader();
|
||||
replyBuffer = new StringBuffer();
|
||||
|
||||
try
|
||||
{
|
||||
do
|
||||
{
|
||||
bytesAvailable = shellInputStream.available();
|
||||
|
||||
if(bytesAvailable == 0 )
|
||||
{
|
||||
// wait if more data is available
|
||||
// for a slower connection this value need to be raised
|
||||
// to avoid splitting of messages
|
||||
Thread.sleep(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if(replyBuffer > 0)
|
||||
do
|
||||
{
|
||||
// store the responses in a buffer
|
||||
storeMessage(replyBuffer);
|
||||
|
||||
Thread.sleep(250);
|
||||
|
||||
bytesAvailable = shellInputStream.available();
|
||||
|
||||
}while(bytesAvailable > 0 );
|
||||
|
||||
message = replyBuffer.toString();
|
||||
|
||||
if(sshContact.isCommandSent())
|
||||
{
|
||||
// if the response is as a result of a command sent
|
||||
sshContact.setMessageType(sshContact
|
||||
.CONVERSATION_MESSAGE_RECEIVED);
|
||||
|
||||
message = message.substring(message.indexOf('\n') + 1);
|
||||
|
||||
sshContact.setCommandSent(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// server sent an asynchronous message to the terminal
|
||||
// display it as a system message
|
||||
sshContact.setMessageType(sshContact
|
||||
.SYSTEM_MESSAGE_RECEIVED);
|
||||
|
||||
//popup disabled
|
||||
// JOptionPane.showMessageDialog(
|
||||
// null,
|
||||
// message,
|
||||
// "Message from " + sshContact.getDisplayName(),
|
||||
// JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
|
||||
instantMessaging.deliverMessage(
|
||||
instantMessaging.createMessage(message),
|
||||
sshContact);
|
||||
|
||||
replyBuffer.delete(0, replyBuffer.length());
|
||||
|
||||
}while(isActive);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the response from server in a temporary buffer
|
||||
* the bytes available are determined before the function is called
|
||||
*
|
||||
* @param replyBuffer to store the response from server
|
||||
*
|
||||
* @throws IOException if the network goes down
|
||||
*/
|
||||
private void storeMessage(StringBuffer replyBuffer) throws IOException
|
||||
{
|
||||
do
|
||||
{
|
||||
buf = (char)shellInputStream.read();
|
||||
|
||||
// System.out.println(String.valueOf(buf)+ " " + (int)buf);
|
||||
|
||||
replyBuffer.append(String.valueOf(buf));
|
||||
|
||||
// logger.debug(shellReader.readLine());
|
||||
|
||||
bytesAvailable--;
|
||||
|
||||
}while(bytesAvailable>0);
|
||||
}
|
||||
|
||||
public void isActive(boolean isActive)
|
||||
{
|
||||
this.isActive = isActive;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* MessageSSHImpl.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* Very simple message implementation for the SSH protocol.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class MessageSSHImpl
|
||||
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 MessageSSHImpl(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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* OperationSetBasicInstantMessagingSSHImpl.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import net.java.sip.communicator.util.Logger;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
|
||||
/**
|
||||
* Instant messaging functionalites for the SSH protocol.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class OperationSetBasicInstantMessagingSSHImpl
|
||||
implements OperationSetBasicInstantMessaging
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(OperationSetBasicInstantMessagingSSHImpl.class);
|
||||
|
||||
/**
|
||||
* Currently registered message listeners.
|
||||
*/
|
||||
private Vector messageListeners = new Vector();
|
||||
|
||||
/**
|
||||
* The currently valid persistent presence operation set..
|
||||
*/
|
||||
private OperationSetPersistentPresenceSSHImpl opSetPersPresence = null;
|
||||
|
||||
/**
|
||||
* The currently valid file transfer operation set
|
||||
*/
|
||||
private OperationSetFileTransferSSHImpl fileTransfer;
|
||||
|
||||
/**
|
||||
* The protocol provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceSSHImpl parentProvider = null;
|
||||
|
||||
/**
|
||||
* The test command given after each command to determine the reply length
|
||||
* of the command
|
||||
*/
|
||||
private final String testCommand = Resources.getString("testCommand");
|
||||
|
||||
|
||||
private String testCommandResponse = Resources
|
||||
.getString("testCommandResponse");
|
||||
|
||||
/**
|
||||
* 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>OperationSetPersistentPresenceSSHImpl</tt> instance.
|
||||
*/
|
||||
public OperationSetBasicInstantMessagingSSHImpl(
|
||||
ProtocolProviderServiceSSHImpl provider,
|
||||
OperationSetPersistentPresenceSSHImpl opSetPersPresence)
|
||||
// OperationSetFileTransferSSHImpl fileTransfer)
|
||||
{
|
||||
this.opSetPersPresence = opSetPersPresence;
|
||||
this.parentProvider = provider;
|
||||
// this.fileTransfer = fileTransfer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 MessageSSHImpl(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 MessageSSHImpl(messageText, DEFAULT_MIME_TYPE
|
||||
, DEFAULT_MIME_ENCODING, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisteres <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. An attempt is made to re-establish the shell
|
||||
* connection if the current one is invalid.
|
||||
* The reply from server is sent by a seperate reader thread
|
||||
*
|
||||
* @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 ContactSSHImpl) )
|
||||
throw new IllegalArgumentException(
|
||||
"The specified contact is not a SSH contact."
|
||||
+ to);
|
||||
|
||||
ContactSSH sshContact = (ContactSSH)to;
|
||||
|
||||
// making sure no messages are sent and no new threads are triggered,
|
||||
// until a thread trying to connect to remote server returns
|
||||
if(sshContact.isConnectionInProgress())
|
||||
{
|
||||
deliverMessage(
|
||||
createMessage("A connection attempt is in progress"),
|
||||
(ContactSSHImpl)to);
|
||||
return;
|
||||
}
|
||||
|
||||
if( !parentProvider.isShellConnected(sshContact) )
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
/**
|
||||
* creating a new SSH session / shell channel
|
||||
* - first message
|
||||
* - session is timed out
|
||||
* - network problems
|
||||
*/
|
||||
parentProvider.connectShell(sshContact, message);
|
||||
|
||||
//the first message is ignored
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new IllegalStateException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if(wrappedMessage(message.getContent(), sshContact))
|
||||
{
|
||||
fireMessageDelivered(message, to);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
sshContact.sendLine(message.getContent());
|
||||
sshContact.setCommandSent(true);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
// Closing IO Streams
|
||||
sshContact.closeShellIO();
|
||||
|
||||
throw new IllegalStateException(ex.getMessage());
|
||||
}
|
||||
|
||||
fireMessageDelivered(message, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the message for wrapped Commands
|
||||
* All commands begin with /
|
||||
*
|
||||
* @param message from user
|
||||
* @param sshContact of the remote machine
|
||||
*
|
||||
* @return true if the message had commands, false otherwise
|
||||
*/
|
||||
private boolean wrappedMessage(
|
||||
String message,
|
||||
ContactSSH sshContact)
|
||||
{
|
||||
|
||||
if(message.startsWith("/upload"))
|
||||
{
|
||||
int firstSpace = message.indexOf(' ');
|
||||
sshContact.getFileTransferOperationSet().sendFile(
|
||||
sshContact,
|
||||
null,
|
||||
message.substring(message.indexOf(' ', firstSpace+1) + 1),
|
||||
message.substring(firstSpace+1, message.indexOf(' ', firstSpace+1))
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(message.startsWith("/download"))
|
||||
{
|
||||
int firstSpace = message.indexOf(' ');
|
||||
sshContact.getFileTransferOperationSet().sendFile(
|
||||
null,
|
||||
sshContact,
|
||||
message.substring(firstSpace+1, message.indexOf(' ', firstSpace+1)),
|
||||
message.substring(message.indexOf(' ', firstSpace+1) + 1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* In case the <tt>to</tt> Contact corresponds to another ssh
|
||||
* protocol provider registered with SIP Communicator, we deliver
|
||||
* the message to them, in case the <tt>to</tt> Contact represents us, we
|
||||
* fire a <tt>MessageReceivedEvent</tt>, and if <tt>to</tt> is simply
|
||||
* a contact in our contact list, then we simply echo the message.
|
||||
*
|
||||
* @param message the <tt>Message</tt> the message to deliver.
|
||||
* @param to the <tt>Contact</tt> that we should deliver the message to.
|
||||
*/
|
||||
void deliverMessage(
|
||||
Message message,
|
||||
ContactSSH to)
|
||||
{
|
||||
String userID = to.getAddress();
|
||||
|
||||
//if the user id is owr own id, then this message is being routed to us
|
||||
//from another instance of the ssh provider.
|
||||
if (userID.equals(this.parentProvider.getAccountID().getUserID()))
|
||||
{
|
||||
//check who is the provider sending the message
|
||||
String sourceUserID
|
||||
= to.getProtocolProvider().getAccountID().getUserID();
|
||||
|
||||
//check whether they are in our contact list
|
||||
Contact from = opSetPersPresence.findContactByID(sourceUserID);
|
||||
|
||||
//and if not - add them there as volatile.
|
||||
if(from == null)
|
||||
{
|
||||
from = opSetPersPresence.createVolatileContact(sourceUserID);
|
||||
}
|
||||
|
||||
//and now fire the message received event.
|
||||
fireMessageReceived(message, from);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if userID is not our own, try an check whether another provider
|
||||
//has that id and if yes - deliver the message to them.
|
||||
ProtocolProviderServiceSSHImpl sshProvider
|
||||
= this.opSetPersPresence.findProviderForSSHUserID(userID);
|
||||
if(sshProvider != null)
|
||||
{
|
||||
OperationSetBasicInstantMessagingSSHImpl opSetIM
|
||||
= (OperationSetBasicInstantMessagingSSHImpl)
|
||||
sshProvider.getOperationSet(
|
||||
OperationSetBasicInstantMessaging.class);
|
||||
opSetIM.deliverMessage(message, to);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if we got here then "to" is simply someone in our contact
|
||||
//list so let's just echo the message.
|
||||
fireMessageReceived(message, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(),
|
||||
((ContactSSH)from).getMessageType());
|
||||
|
||||
Iterator listeners = null;
|
||||
synchronized (messageListeners)
|
||||
{
|
||||
listeners = new ArrayList(messageListeners).iterator();
|
||||
}
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
MessageListener listener
|
||||
= (MessageListener) listeners.next();
|
||||
|
||||
listener.messageReceived(evt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines wheter the SSH protocol provider supports
|
||||
* sending and receiving offline messages.
|
||||
*
|
||||
* @return <tt>false</tt>
|
||||
*/
|
||||
public boolean isOfflineMessagingSupported()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines wheter 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)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* OperationSetContactInfo.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
class OperationSetContactInfo extends JDialog
|
||||
implements ConfigurationForm
|
||||
{
|
||||
private ContactSSH sshContact;
|
||||
|
||||
private JPanel mainPanel = new JPanel();
|
||||
private JPanel machinePanel = new JPanel();
|
||||
private JPanel detailNamesPanel = new JPanel();
|
||||
private JPanel detailFieldsPanel = new JPanel();
|
||||
private JPanel detailsPanel = new JPanel();
|
||||
|
||||
private JCheckBox addDetailsCheckBox = new JCheckBox("Add Details");
|
||||
|
||||
private JButton doneButton = new JButton("Done");
|
||||
private JLabel machineID = new JLabel("Hostname / IP: ");
|
||||
private JTextField machineIDField = new JTextField();
|
||||
private JLabel userName = new JLabel("User Name: ");
|
||||
private JTextField userNameField = new JTextField();
|
||||
private JLabel password = new JLabel("Password: ");
|
||||
private JTextField passwordField = new JPasswordField();
|
||||
private JLabel port = new JLabel("Port: ");
|
||||
private JTextField portField = new JTextField("22");
|
||||
private JLabel secs = new JLabel("secs");
|
||||
private JLabel statusUpdate = new JLabel("Update Interval: ");
|
||||
private JLabel terminalType = new JLabel("Terminal Type: ");
|
||||
private JTextField terminalTypeField = new JTextField("SIP Communicator");
|
||||
private JSpinner updateTimer = new JSpinner();
|
||||
|
||||
private JPanel emptyPanel1 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel2 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel3 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel4 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel5 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel6 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel7 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel8 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel9 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel10 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel11 = new JPanel();
|
||||
|
||||
// private ContactGroup contactGroup = null;
|
||||
|
||||
/**
|
||||
* Creates a new instance of OperationSetContactInfo
|
||||
*
|
||||
* @param sshContact the concerned contact
|
||||
*/
|
||||
public OperationSetContactInfo(ContactSSH sshContact)
|
||||
{
|
||||
super(new JFrame(), true);
|
||||
this.sshContact = sshContact;
|
||||
initForm();
|
||||
|
||||
this.getContentPane().add(mainPanel);
|
||||
|
||||
this.setSize(370, 325);
|
||||
|
||||
this.setResizable(false);
|
||||
|
||||
this.setTitle("SSH: Account Details of " + sshContact.getDisplayName());
|
||||
|
||||
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||
Dimension screenSize = toolkit.getScreenSize();
|
||||
|
||||
int x = (screenSize.width - this.getWidth()) / 2;
|
||||
int y = (screenSize.height - this.getHeight()) / 2;
|
||||
|
||||
this.setLocation(x,y);
|
||||
|
||||
// ProtocolProviderServiceSSHImpl.getUIService().getConfigurationWindow().
|
||||
// addConfigurationForm(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize the form.
|
||||
*/
|
||||
public void initForm()
|
||||
{
|
||||
updateTimer.setValue(new Integer(30));
|
||||
|
||||
userNameField.setEnabled(false);
|
||||
passwordField.setEditable(false);
|
||||
portField.setEnabled(false);
|
||||
terminalTypeField.setEnabled(false);
|
||||
updateTimer.setEnabled(false);
|
||||
|
||||
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
|
||||
machinePanel.setLayout(new BoxLayout(machinePanel, BoxLayout.X_AXIS));
|
||||
detailNamesPanel.setLayout(new BoxLayout(detailNamesPanel,
|
||||
BoxLayout.Y_AXIS));
|
||||
detailFieldsPanel.setLayout(new BoxLayout(detailFieldsPanel,
|
||||
BoxLayout.Y_AXIS));
|
||||
detailsPanel.setLayout(new BoxLayout(detailsPanel, BoxLayout.X_AXIS));
|
||||
|
||||
machinePanel.add(machineID);
|
||||
machinePanel.add(machineIDField);
|
||||
|
||||
detailNamesPanel.add(userName);
|
||||
detailNamesPanel.add(emptyPanel1);
|
||||
detailNamesPanel.add(password);
|
||||
detailNamesPanel.add(emptyPanel2);
|
||||
detailNamesPanel.add(port);
|
||||
detailNamesPanel.add(emptyPanel3);
|
||||
detailNamesPanel.add(statusUpdate);
|
||||
detailNamesPanel.add(emptyPanel4);
|
||||
detailNamesPanel.add(terminalType);
|
||||
|
||||
detailFieldsPanel.add(userNameField);
|
||||
detailFieldsPanel.add(emptyPanel5);
|
||||
detailFieldsPanel.add(passwordField);
|
||||
detailFieldsPanel.add(emptyPanel6);
|
||||
detailFieldsPanel.add(portField);
|
||||
detailFieldsPanel.add(emptyPanel7);
|
||||
detailFieldsPanel.add(updateTimer);
|
||||
detailFieldsPanel.add(emptyPanel8);
|
||||
detailFieldsPanel.add(terminalTypeField);
|
||||
|
||||
detailsPanel.add(detailNamesPanel);
|
||||
detailsPanel.add(detailFieldsPanel);
|
||||
|
||||
detailsPanel.setBorder(BorderFactory.createTitledBorder("Details"));
|
||||
|
||||
mainPanel.add(emptyPanel9);
|
||||
mainPanel.add(machinePanel);
|
||||
mainPanel.add(addDetailsCheckBox);
|
||||
mainPanel.add(detailsPanel);
|
||||
mainPanel.add(emptyPanel10);
|
||||
mainPanel.add(doneButton);
|
||||
mainPanel.add(emptyPanel11);
|
||||
|
||||
addDetailsCheckBox.addActionListener(new ActionListener()
|
||||
{
|
||||
public void actionPerformed(ActionEvent event)
|
||||
{
|
||||
addDetailsCheckBox.setEnabled(false);
|
||||
userNameField.setEnabled(true);
|
||||
passwordField.setEditable(true);
|
||||
portField.setEnabled(true);
|
||||
terminalTypeField.setEnabled(true);
|
||||
updateTimer.setEnabled(true);
|
||||
|
||||
userNameField.grabFocus();
|
||||
}
|
||||
});
|
||||
|
||||
doneButton.addActionListener(new ActionListener()
|
||||
{
|
||||
public void actionPerformed(ActionEvent event)
|
||||
{
|
||||
if(machineIDField.getText().equals(""))
|
||||
{
|
||||
machineIDField.setText("Field needed");
|
||||
return;
|
||||
}
|
||||
|
||||
sshContact.savePersistentDetails();
|
||||
// ((OperationSetPersistentPresenceSSHImpl)sshContact
|
||||
// .getParentPresenceOperationSet())
|
||||
// .addContactToList(contactGroup, sshContact);
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ssh icon
|
||||
*
|
||||
* @return the ssh icon
|
||||
*/
|
||||
public byte[] getIcon()
|
||||
{
|
||||
return Resources.getImage(Resources.SSH_LOGO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the main panel
|
||||
*
|
||||
* @return the main panel
|
||||
*/
|
||||
public Object getForm()
|
||||
{
|
||||
return mainPanel;
|
||||
}
|
||||
//
|
||||
// public void setContactGroup(ContactGroup contactGroup)
|
||||
// {
|
||||
// this.contactGroup = contactGroup;
|
||||
// }
|
||||
//
|
||||
// public ContactGroup getContactGroup()
|
||||
// {
|
||||
// return this.contactGroup;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Sets the UserName of the dialog
|
||||
*
|
||||
* @param userName to be associated
|
||||
*/
|
||||
public void setUserNameField(String userName)
|
||||
{
|
||||
this.userNameField.setText(userName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Password of the dialog
|
||||
*
|
||||
* @param password to be associated
|
||||
*/
|
||||
public void setPasswordField(String password)
|
||||
{
|
||||
this.passwordField.setText(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hostname
|
||||
*
|
||||
* @return the hostname
|
||||
*/
|
||||
public String getHostName()
|
||||
{
|
||||
return this.machineIDField.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the username
|
||||
*
|
||||
* @return the username
|
||||
*/
|
||||
public String getUserName()
|
||||
{
|
||||
return this.userNameField.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the password
|
||||
*
|
||||
* @return the password in a clear form
|
||||
*/
|
||||
public String getPassword()
|
||||
{
|
||||
return this.passwordField.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the terminal type
|
||||
*
|
||||
* @return the terminal type
|
||||
*/
|
||||
public String getTerminalType()
|
||||
{
|
||||
return this.terminalTypeField.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the port
|
||||
*
|
||||
* @return the port value
|
||||
*/
|
||||
public int getPort()
|
||||
{
|
||||
return Integer.parseInt(this.portField.getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the update interval
|
||||
*
|
||||
* @return the update interval
|
||||
*/
|
||||
public int getUpdateInterval()
|
||||
{
|
||||
return Integer.parseInt(String.valueOf(this.updateTimer.getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the HostName of the dialog
|
||||
*
|
||||
* @param hostName to be associated
|
||||
*/
|
||||
public void setHostNameField(String hostName)
|
||||
{
|
||||
this.machineIDField.setText(hostName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Terminal Type of the dialog
|
||||
*
|
||||
* @param termType to be associated
|
||||
*/
|
||||
public void setTerminalType(String termType)
|
||||
{
|
||||
this.terminalTypeField.setText(termType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Update Interval of the dialog
|
||||
*
|
||||
* @param interval to be associated
|
||||
*/
|
||||
public void setUpdateInterval(Integer interval)
|
||||
{
|
||||
this.updateTimer.setValue(interval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Port of the dialog
|
||||
*
|
||||
* @param port to be associated
|
||||
*/
|
||||
public void setPort(String port)
|
||||
{
|
||||
this.portField.setText(port);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging clitent.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* OperationSetContactTimerSSHImpl.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Timer Task to update the reachability status of SSH Contact in contact list
|
||||
* The timer is started at either of the two places
|
||||
* - A new contact - OperationSetPersistentPresenceSSHImpl
|
||||
* .createUnresolvedContact
|
||||
* - Existing Contact - OperationSetPersistentPresenceSSHImpl.subscribe
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class OperationSetContactTimerSSHImpl
|
||||
extends TimerTask
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(OperationSetFileTransferSSHImpl.class);
|
||||
|
||||
/**
|
||||
* The contact ID of the remote machine
|
||||
*/
|
||||
private ContactSSH sshContact;
|
||||
|
||||
/**
|
||||
* PersistentPresence Identifer assoiciated with SSH Contact
|
||||
*/
|
||||
private OperationSetPersistentPresenceSSHImpl persistentPresence;
|
||||
|
||||
/**
|
||||
* The method which is called at regular intervals to update the status
|
||||
* of remote machines
|
||||
*
|
||||
* Presently only ONLINE and OFFILINE status are checked
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
/* InetAddress remoteMachine = InetAddress.getByName(
|
||||
sshContact.getSSHConfigurationForm().getHostName());
|
||||
|
||||
//check if machine is reachable
|
||||
if(remoteMachine.isReachable(
|
||||
sshContact.getSSHConfigurationForm().getUpdateInterval()))
|
||||
{
|
||||
if(
|
||||
! sshContact.getPresenceStatus().equals(SSHStatusEnum
|
||||
.ONLINE)
|
||||
&&
|
||||
! sshContact.getPresenceStatus().equals(SSHStatusEnum
|
||||
.CONNECTING)
|
||||
&&
|
||||
! sshContact.getPresenceStatus().equals(SSHStatusEnum
|
||||
.CONNECTED)
|
||||
)
|
||||
*/
|
||||
|
||||
Socket socket = new Socket(
|
||||
sshContact.getSSHConfigurationForm().getHostName(),
|
||||
sshContact.getSSHConfigurationForm().getPort());
|
||||
|
||||
|
||||
socket.close();
|
||||
|
||||
if (sshContact.getPresenceStatus().equals(SSHStatusEnum.OFFLINE)
|
||||
|| sshContact.getPresenceStatus().equals(SSHStatusEnum
|
||||
.NOT_AVAILABLE))
|
||||
{
|
||||
// change status to online
|
||||
persistentPresence.changeContactPresenceStatus(
|
||||
sshContact, SSHStatusEnum.ONLINE);
|
||||
|
||||
logger.debug("SSH Host " + sshContact.getSSHConfigurationForm()
|
||||
.getHostName() + ": Online");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (sshContact.getPresenceStatus().equals(SSHStatusEnum.ONLINE)
|
||||
|| sshContact.getPresenceStatus().equals(SSHStatusEnum
|
||||
.NOT_AVAILABLE))
|
||||
{
|
||||
persistentPresence.changeContactPresenceStatus(
|
||||
sshContact, SSHStatusEnum.OFFLINE);
|
||||
|
||||
logger.debug("SSH Host " + sshContact.getSSHConfigurationForm()
|
||||
.getHostName() + ": Offline");
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates a new instance of OperationSetContactTimerSSHImpl
|
||||
*/
|
||||
public OperationSetContactTimerSSHImpl(ContactSSH sshContact)
|
||||
{
|
||||
super();
|
||||
this.sshContact = sshContact;
|
||||
this.persistentPresence = (OperationSetPersistentPresenceSSHImpl)
|
||||
sshContact.getParentPresenceOperationSet();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* OperationSetFileTransferSSHImpl.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* This class provides operations to upload/download files to remote machines
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class OperationSetFileTransferSSHImpl
|
||||
implements OperationSetFileTransfer
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(OperationSetFileTransferSSHImpl.class);
|
||||
|
||||
/**
|
||||
* Currently registered message listeners.
|
||||
*/
|
||||
private Vector fileTransferListeners = new Vector();
|
||||
|
||||
/**
|
||||
* The currently valid persistent presence operation set..
|
||||
*/
|
||||
private OperationSetPersistentPresenceSSHImpl opSetPersPresence = null;
|
||||
|
||||
/**
|
||||
* The currently valid ssh instant messaging operation set
|
||||
*/
|
||||
private OperationSetBasicInstantMessagingSSHImpl instantMessaging = null;
|
||||
|
||||
/**
|
||||
* The protocol provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceSSHImpl parentProvider = null;
|
||||
|
||||
|
||||
/** Creates a new instance of OperationSetFileTransferSSHImpl */
|
||||
public OperationSetFileTransferSSHImpl(
|
||||
ProtocolProviderServiceSSHImpl parentProvider,
|
||||
OperationSetPersistentPresenceSSHImpl opSetPersPresence,
|
||||
OperationSetBasicInstantMessagingSSHImpl instantMessaging)
|
||||
{
|
||||
this.parentProvider = parentProvider;
|
||||
this.opSetPersPresence = opSetPersPresence;
|
||||
this.instantMessaging = instantMessaging;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a FileTransferListener with this operation set so that it gets
|
||||
* notifications of start, complete, failure of file transfers
|
||||
*
|
||||
* @param listener the <tt>FileListener</tt> to register.
|
||||
*/
|
||||
public void addFileListener(FileListener listener)
|
||||
{
|
||||
if(!fileTransferListeners.contains(listener))
|
||||
fileTransferListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* The file transfer method to/from the remote machine
|
||||
* either toContact is null(we are downloading file from remote machine
|
||||
* or fromContact is null(we are uploading file to remote machine
|
||||
*
|
||||
* @param toContact - the file recipient
|
||||
* @param fromContact - the file sender
|
||||
* @param remotePath - the identifier for the remote file
|
||||
* @param localPath - the identifier for the local file
|
||||
*/
|
||||
public void sendFile(
|
||||
Contact toContact,
|
||||
Contact fromContact,
|
||||
String remotePath,
|
||||
String localPath)
|
||||
{
|
||||
if(toContact == null)
|
||||
{
|
||||
ContactSSHFileTransferDaemon fileTransferDaemon
|
||||
= new ContactSSHFileTransferDaemon(
|
||||
(ContactSSH)fromContact,
|
||||
opSetPersPresence,
|
||||
instantMessaging,
|
||||
parentProvider);
|
||||
|
||||
if(localPath.endsWith(System.getProperty("file.separator")))
|
||||
localPath += remotePath.substring(remotePath.lastIndexOf('/')
|
||||
+ 1);
|
||||
|
||||
fileTransferDaemon.downloadFile(
|
||||
remotePath,
|
||||
localPath);
|
||||
|
||||
return;
|
||||
}
|
||||
else if(fromContact == null)
|
||||
{
|
||||
ContactSSHFileTransferDaemon fileTransferDaemon
|
||||
= new ContactSSHFileTransferDaemon(
|
||||
(ContactSSH) toContact,
|
||||
opSetPersPresence,
|
||||
instantMessaging,
|
||||
parentProvider);
|
||||
|
||||
fileTransferDaemon.uploadFile(
|
||||
remotePath,
|
||||
localPath);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// code should not reach here
|
||||
//assert false;
|
||||
logger.error("we should not be here !");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* ProtocolIconSSHImpl.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.io.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Reperesents the SSH protocol icon. Implements the <tt>ProtocolIcon</tt>
|
||||
* interface in order to provide a ssh logo image in two different sizes.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class ProtocolIconSSHImpl
|
||||
implements ProtocolIcon
|
||||
{
|
||||
private static Logger logger
|
||||
= Logger.getLogger(ProtocolIconSSHImpl.class);
|
||||
|
||||
/**
|
||||
* A hash table containing the protocol icon in different sizes.
|
||||
*/
|
||||
private static Hashtable iconsTable = new Hashtable();
|
||||
static {
|
||||
iconsTable.put(ProtocolIcon.ICON_SIZE_16x16,
|
||||
loadIcon("resources/images/ssh/ssh-online.png"));
|
||||
|
||||
iconsTable.put(ProtocolIcon.ICON_SIZE_64x64,
|
||||
loadIcon("resources/images/ssh/ssh64x64.png"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <tt>ProtocolIcon.getSupportedSizes()</tt> method. Returns
|
||||
* an iterator to a set containing the supported icon sizes.
|
||||
* @return an iterator to a set containing the supported icon sizes
|
||||
*/
|
||||
public Iterator getSupportedSizes()
|
||||
{
|
||||
return iconsTable.keySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returne TRUE if a icon with the given size is supported, FALSE-otherwise.
|
||||
*
|
||||
* @return TRUE if a icon with the given 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 the icon
|
||||
*/
|
||||
public byte[] getIcon(String iconSize)
|
||||
{
|
||||
return (byte[])iconsTable.get(iconSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icon image used to represent the protocol connecting state.
|
||||
* @return the icon image used to represent the protocol connecting state
|
||||
*/
|
||||
public byte[] getConnectingIcon()
|
||||
{
|
||||
return loadIcon("resources/images/ssh/ssh-online.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = ProtocolIconSSHImpl.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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* ProtocolProviderFactorySSH.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public abstract class ProtocolProviderFactorySSH
|
||||
extends ProtocolProviderFactory
|
||||
{
|
||||
/**
|
||||
* The name of a property representing the IDENTITY_FILE of the protocol for
|
||||
* a ProtocolProviderFactory.
|
||||
*/
|
||||
public static final String IDENTITY_FILE = "IDENTITY_FILE";
|
||||
|
||||
/**
|
||||
* The name of a property representing the KNOWN_HOSTS_FILE of the protocol
|
||||
* for a ProtocolProviderFactory.
|
||||
*/
|
||||
public static final String KNOWN_HOSTS_FILE = "KNOWN_HOSTS_FILE";
|
||||
|
||||
}
|
||||
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* ProtocolProviderFactorySSHImpl.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* The SSH protocol provider factory creates instances of the SSH
|
||||
* protocol provider service. One Service instance corresponds to one account.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class ProtocolProviderFactorySSHImpl
|
||||
extends ProtocolProviderFactorySSH
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(ProtocolProviderFactorySSHImpl.class);
|
||||
|
||||
/**
|
||||
* The table that we store our accounts in.
|
||||
*/
|
||||
private Hashtable registeredAccounts = new Hashtable();
|
||||
|
||||
|
||||
/**
|
||||
* Creates an instance of the ProtocolProviderFactorySSHImpl.
|
||||
*/
|
||||
public ProtocolProviderFactorySSHImpl()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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( SSHActivator.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 = SSHActivator.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 SSHAccountID(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(
|
||||
SSHActivator.getBundleContext()
|
||||
, accountID);
|
||||
|
||||
accountID = loadAccount(accountProperties);
|
||||
|
||||
/* ServiceReference ppServiceRef = context
|
||||
.getServiceReference(ProtocolProviderService.class.getName());
|
||||
|
||||
ProtocolProviderService ppService = (ProtocolProviderService)
|
||||
context.getService(ppServiceRef);
|
||||
|
||||
OperationSetPersistentPresence operationSetPersistentPresence =
|
||||
(OperationSetPersistentPresence) ppService.getOperationSet(
|
||||
OperationSetPersistentPresence.class);
|
||||
|
||||
try
|
||||
{
|
||||
// The below should never fail for SSH accounts
|
||||
operationSetPersistentPresence.subscribe(userIDStr);
|
||||
|
||||
}
|
||||
catch(OperationFailedException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
*/
|
||||
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 = SSHActivator.getBundleContext();
|
||||
if(context == null)
|
||||
throw new NullPointerException("The specified BundleContext was" +
|
||||
" null");
|
||||
|
||||
String userIDStr = (String) accountProperties.get(USER_ID);
|
||||
AccountID accountID = new SSHAccountID(userIDStr, accountProperties);
|
||||
|
||||
//get a reference to the configuration service and register whatever
|
||||
//properties we have in it.
|
||||
|
||||
Hashtable properties = new Hashtable();
|
||||
properties.put(PROTOCOL, "SSH");
|
||||
properties.put(USER_ID, userIDStr);
|
||||
|
||||
ProtocolProviderServiceSSHImpl sshProtocolProvider
|
||||
= new ProtocolProviderServiceSSHImpl();
|
||||
|
||||
sshProtocolProvider.initialize(userIDStr, accountID);
|
||||
|
||||
ServiceRegistration registration = context.registerService(
|
||||
ProtocolProviderService.class.getName(),
|
||||
sshProtocolProvider,
|
||||
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) SSHActivator.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(
|
||||
SSHActivator.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(SSHActivator.getBundleContext(),
|
||||
// accountID,
|
||||
// String.valueOf(Base64.encode(passwd.getBytes())));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 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
|
||||
// {
|
||||
// String password = super.loadPassword(SSHActivator.getBundleContext()
|
||||
// , accountID );
|
||||
// return(String.valueOf(Base64.decode(password)));
|
||||
// }
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,760 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* ProtocolProviderServiceSSHImpl.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import com.jcraft.jsch.*;
|
||||
import javax.swing.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import net.java.sip.communicator.util.Logger;
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
|
||||
/**
|
||||
* A SSH implementation of the ProtocolProviderService.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class ProtocolProviderServiceSSHImpl
|
||||
implements ProtocolProviderService
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(ProtocolProviderServiceSSHImpl.class);
|
||||
|
||||
/**
|
||||
* The name of this protocol.
|
||||
*/
|
||||
public static final String SSH_PROTOCOL_NAME = "SSH";
|
||||
|
||||
// /**
|
||||
// * The identifier for SSH Stack
|
||||
// * Java Secure Channel JSch
|
||||
// */
|
||||
// JSch jsch = new JSch();
|
||||
|
||||
/**
|
||||
* The test command given after each command to determine the reply length
|
||||
* of the command
|
||||
*/
|
||||
private final String testCommand = Resources.getString("testCommand");
|
||||
|
||||
/**
|
||||
* A reference to the protocol provider of UIService
|
||||
*/
|
||||
private static ServiceReference ppUIServiceRef;
|
||||
|
||||
/**
|
||||
* Connection timeout to a remote server in milliseconds
|
||||
*/
|
||||
private static int connectionTimeout = 30000;
|
||||
|
||||
/**
|
||||
* A reference to UI Service
|
||||
*/
|
||||
private static UIService uiService;
|
||||
|
||||
/**
|
||||
* 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 final Hashtable supportedOperationSets = new Hashtable();
|
||||
|
||||
private OperationSetBasicInstantMessagingSSHImpl basicInstantMessaging;
|
||||
|
||||
private OperationSetFileTransferSSHImpl fileTranfer;
|
||||
|
||||
/**
|
||||
* 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 ssh protocol.
|
||||
*/
|
||||
private ProtocolIconSSHImpl sshIcon
|
||||
= new ProtocolIconSSHImpl();
|
||||
|
||||
/**
|
||||
* The registration state of SSH Provider is taken to be registered by
|
||||
* default as it doesn't correspond to the state on remote server
|
||||
*/
|
||||
private RegistrationState currentRegistrationState
|
||||
= RegistrationState.REGISTERED;
|
||||
|
||||
/**
|
||||
* The default constructor for the SSH protocol provider.
|
||||
*/
|
||||
public ProtocolProviderServiceSSHImpl()
|
||||
{
|
||||
logger.trace("Creating a ssh provider.");
|
||||
|
||||
try
|
||||
{
|
||||
// converting to milliseconds
|
||||
connectionTimeout = Integer.parseInt(Resources.getString(
|
||||
"connectionTimeout")) * 1000;
|
||||
}
|
||||
catch(NumberFormatException ex)
|
||||
{
|
||||
logger.error("Connection Timeout set to 30 seconds");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ssh 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
|
||||
OperationSetPersistentPresenceSSHImpl persistentPresence =
|
||||
new OperationSetPersistentPresenceSSHImpl(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
|
||||
basicInstantMessaging = new
|
||||
OperationSetBasicInstantMessagingSSHImpl(
|
||||
this,
|
||||
persistentPresence);
|
||||
|
||||
supportedOperationSets.put(
|
||||
OperationSetBasicInstantMessaging.class.getName(),
|
||||
basicInstantMessaging);
|
||||
|
||||
//initialze the file transfer operation set
|
||||
fileTranfer = new OperationSetFileTransferSSHImpl(
|
||||
this,
|
||||
persistentPresence,
|
||||
basicInstantMessaging);
|
||||
|
||||
supportedOperationSets.put(
|
||||
OperationSetFileTransfer.class.getName(),
|
||||
fileTranfer);
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a vaild session exists for the contact of remote
|
||||
* machine.
|
||||
*
|
||||
* @param sshContact ID of SSH Contact
|
||||
*
|
||||
* @return <tt>true</tt> if the session is connected
|
||||
* <tt>false</tt> otherwise
|
||||
*/
|
||||
public boolean isSessionValid(ContactSSH sshContact)
|
||||
{
|
||||
Session sshSession = sshContact.getSSHSession();
|
||||
if( sshSession != null)
|
||||
if(sshSession.isConnected())
|
||||
return true;
|
||||
|
||||
// remove reference to an unconnected SSH Session, if any
|
||||
sshContact.setSSHSession(null);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the contact is connected to shell of remote machine
|
||||
* as a precheck for any further operation
|
||||
*
|
||||
* @param sshContact ID of SSH Contact
|
||||
*
|
||||
* @return <tt>true</tt> if the contact is connected
|
||||
* <tt>false</tt> if the contact is not connected
|
||||
*/
|
||||
public boolean isShellConnected(ContactSSH sshContact)
|
||||
{
|
||||
// a test command may also be run here
|
||||
|
||||
if(isSessionValid(sshContact))
|
||||
{
|
||||
return(sshContact.getShellChannel() != null);
|
||||
}
|
||||
|
||||
/*
|
||||
* Above should be return(sshContact.getShellChannel() != null
|
||||
* && sshContact.getShellChannel().isConnected());
|
||||
*
|
||||
* but incorrect reply from stack for isConnected()
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shell channel to the remote machine
|
||||
* a new jsch session is also created if the current one is invalid
|
||||
*
|
||||
* @param sshContact the contact of the remote machine
|
||||
* @param Message the first message
|
||||
*/
|
||||
public void connectShell(
|
||||
final ContactSSH sshContact,
|
||||
final Message firstMessage)
|
||||
{
|
||||
sshContact.setConnectionInProgress(true);
|
||||
|
||||
final UIService uiService = this.uiService;
|
||||
|
||||
final Thread newConnection = new Thread((new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
OperationSetPersistentPresenceSSHImpl persistentPresence
|
||||
= (OperationSetPersistentPresenceSSHImpl)sshContact
|
||||
.getParentPresenceOperationSet();
|
||||
|
||||
persistentPresence.changeContactPresenceStatus(
|
||||
sshContact,
|
||||
SSHStatusEnum.CONNECTING);
|
||||
|
||||
try
|
||||
{
|
||||
if(!isSessionValid(sshContact))
|
||||
createSSHSessionAndLogin(sshContact);
|
||||
|
||||
createShellChannel(sshContact);
|
||||
|
||||
//initalizing the reader and writers of ssh contact
|
||||
|
||||
persistentPresence.changeContactPresenceStatus(
|
||||
sshContact,
|
||||
SSHStatusEnum.CONNECTED);
|
||||
|
||||
showWelcomeMessage(sshContact);
|
||||
|
||||
sshContact.setMessageType(sshContact
|
||||
.CONVERSATION_MESSAGE_RECEIVED);
|
||||
|
||||
sshContact.setConnectionInProgress(false);
|
||||
|
||||
Thread.sleep(1500);
|
||||
|
||||
sshContact.setCommandSent(true);
|
||||
|
||||
basicInstantMessaging.sendInstantMessage(
|
||||
sshContact,
|
||||
firstMessage);
|
||||
}
|
||||
// rigoruos Exception Checking in future
|
||||
catch (Exception ex)
|
||||
{
|
||||
persistentPresence.changeContactPresenceStatus(
|
||||
sshContact,
|
||||
SSHStatusEnum.NOT_AVAILABLE);
|
||||
|
||||
ex.printStackTrace();
|
||||
}
|
||||
finally
|
||||
{
|
||||
sshContact.setConnectionInProgress(false);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
newConnection.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a channel for shell type in the current session
|
||||
* channel types = shell, sftp, exec(X forwarding),
|
||||
* direct-tcpip(stream forwarding) etc
|
||||
*
|
||||
* @param sshContact ID of SSH Contact
|
||||
*
|
||||
*/
|
||||
public void createShellChannel(ContactSSH sshContact)
|
||||
throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
Channel shellChannel = sshContact.getSSHSession()
|
||||
.openChannel("shell");
|
||||
|
||||
//initalizing the reader and writers of ssh contact
|
||||
sshContact.initializeShellIO(shellChannel.getInputStream(),
|
||||
shellChannel.getOutputStream());
|
||||
|
||||
((ChannelShell)shellChannel).setPtyType(
|
||||
sshContact.getSSHConfigurationForm().getTerminalType());
|
||||
|
||||
//initializing the shell
|
||||
shellChannel.connect(1000);
|
||||
|
||||
sshContact.setShellChannel(shellChannel);
|
||||
|
||||
sshContact.sendLine("export PS1=");
|
||||
}
|
||||
catch (JSchException ex)
|
||||
{
|
||||
sshContact.setSSHSession(null);
|
||||
throw new IOException("Unable to create shell channel to remote" +
|
||||
" server");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the Shell channel are associated IO Streams
|
||||
*
|
||||
* @param sshContact ID of SSH Contact
|
||||
*/
|
||||
public void closeShellChannel(ContactSSH sshContact) throws
|
||||
JSchException,
|
||||
IOException
|
||||
{
|
||||
sshContact.closeShellIO();
|
||||
sshContact.getShellChannel().disconnect();
|
||||
sshContact.setShellChannel(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SSH Session with a remote machine and tries to login
|
||||
* according to the details specified by Contact
|
||||
* An appropriate message is shown to the end user in case the login fails
|
||||
*
|
||||
* @param sshContact ID of SSH Contact
|
||||
*
|
||||
* @throws JSchException if a JSch is unable to create a SSH Session with the remote machine
|
||||
* @throws InterruptedException if the thread is interrupted before session
|
||||
* connected or is timed out
|
||||
* @throws OperationFailedException if not of above reasons :-)
|
||||
*/
|
||||
public void createSSHSessionAndLogin(ContactSSH sshContact) throws
|
||||
JSchException,
|
||||
OperationFailedException,
|
||||
InterruptedException
|
||||
{
|
||||
logger.info("Creating a new SSH Session to "
|
||||
+ sshContact.getHostName());
|
||||
|
||||
// creating a new JSch Stack identifier for contact
|
||||
JSch jsch = new JSch();
|
||||
|
||||
String knownHosts = (String)accountID
|
||||
.getAccountProperties().get("KNOWN_HOSTS_FILE");
|
||||
|
||||
if(!knownHosts.equals("Optional"))
|
||||
jsch.setKnownHosts(knownHosts);
|
||||
|
||||
String identitiyKey = (String)accountID
|
||||
.getAccountProperties().get("IDENTITY_FILE");
|
||||
|
||||
String userName = sshContact.getUserName();
|
||||
|
||||
// use the name of system user if the contact has not supplied SSH
|
||||
// details
|
||||
if(userName.equals(""))
|
||||
userName = System.getProperty("user.name");
|
||||
|
||||
if(!identitiyKey.equals("Optional"))
|
||||
jsch.addIdentity(identitiyKey);
|
||||
|
||||
// creating a new session for the contact
|
||||
Session session = jsch.getSession(
|
||||
userName,
|
||||
sshContact.getHostName(),
|
||||
sshContact.getSSHConfigurationForm().getPort());
|
||||
|
||||
/**
|
||||
* Creating and associating User Info with the session
|
||||
* User Info passes authentication from sshContact to SSH Stack
|
||||
*/
|
||||
SSHUserInfo sshUserInfo = new SSHUserInfo(sshContact);
|
||||
|
||||
session.setUserInfo(sshUserInfo);
|
||||
|
||||
/**
|
||||
* initializing the session
|
||||
*/
|
||||
session.connect(connectionTimeout);
|
||||
|
||||
int count = 0;
|
||||
|
||||
// wait for session to get connected
|
||||
while(!session.isConnected() && count<=30000)
|
||||
{
|
||||
Thread.sleep(1000);
|
||||
count += 1000;
|
||||
logger.trace("SSH:" + sshContact.getHostName()
|
||||
+ ": Sleep zzz .. " );
|
||||
}
|
||||
|
||||
// if timeout have exceeded
|
||||
if(count>30000)
|
||||
{
|
||||
sshContact.setSSHSession(null);
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"SSH Connection attempt to "
|
||||
+ sshContact.getHostName() + " timed out");
|
||||
|
||||
// error codes are not defined yet
|
||||
throw new OperationFailedException("SSH Connection attempt to " +
|
||||
sshContact.getHostName() + " timed out", 2);
|
||||
}
|
||||
|
||||
sshContact.setJSch(jsch);
|
||||
sshContact.setSSHSession(session);
|
||||
|
||||
logger.info("A new SSH Session to " + sshContact.getHostName()
|
||||
+ " Created");
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the SSH Session associated with the contact
|
||||
*
|
||||
* @param sshContact ID of SSH Contact
|
||||
*/
|
||||
void closeSSHSession(ContactSSH sshContact)
|
||||
{
|
||||
sshContact.getSSHSession().disconnect();
|
||||
sshContact.setSSHSession(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Presents the login welcome message to user
|
||||
*
|
||||
* @param sshContact ID of SSH Contact
|
||||
*/
|
||||
public void showWelcomeMessage(ContactSSH sshContact)
|
||||
throws IOException
|
||||
{
|
||||
/* //sending the command
|
||||
sshContact.sendLine(testCommand);
|
||||
|
||||
String reply = "", line = "";
|
||||
|
||||
// message is extracted until the test Command ie echoed back
|
||||
while(line.indexOf(testCommand) == -1)
|
||||
{
|
||||
reply += line + "\n";
|
||||
line = sshContact.getLine();
|
||||
}
|
||||
|
||||
uiService.getPopupDialog().showMessagePopupDialog
|
||||
(reply,"Message from " + sshContact.getDisplayName(),
|
||||
uiService.getPopupDialog().INFORMATION_MESSAGE);
|
||||
|
||||
if(line.startsWith(testCommand))
|
||||
while(!sshContact.getLine().contains(testCommand));
|
||||
|
||||
//one line output of testCommand
|
||||
sshContact.getLine();
|
||||
*/
|
||||
logger.debug("SSH: Welcome message shown");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to UIServce for accessing UI related services
|
||||
*
|
||||
* @return uiService a reference to UIService
|
||||
*/
|
||||
public static UIService getUIService()
|
||||
{
|
||||
return uiService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 SSH_PROTOCOL_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
//get a reference to UI Service via its Service Reference
|
||||
ppUIServiceRef = SSHActivator.getBundleContext()
|
||||
.getServiceReference(UIService.class.getName());
|
||||
|
||||
uiService = (UIService)SSHActivator.getBundleContext()
|
||||
.getService(ppUIServiceRef);
|
||||
|
||||
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 SSH Protocol Provider.");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ssh protocol icon.
|
||||
* @return the ssh protocol icon
|
||||
*/
|
||||
public ProtocolIcon getProtocolIcon()
|
||||
{
|
||||
return sshIcon;
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
*
|
||||
* Resources.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class Resources
|
||||
{
|
||||
private static Logger log = Logger.getLogger(Resources.class);
|
||||
|
||||
private static final String BUNDLE_NAME
|
||||
= "net.java.sip.communicator.impl.protocol.ssh.resources";
|
||||
|
||||
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
||||
.getBundle(BUNDLE_NAME);
|
||||
|
||||
public static ImageID SSH_LOGO = new ImageID("protocolIcon");
|
||||
|
||||
/**
|
||||
* Returns an string corresponding to the given key.
|
||||
*
|
||||
* @param key The key of the string.
|
||||
*
|
||||
* @return a string corresponding to the given key.
|
||||
*/
|
||||
public static String getString(String key)
|
||||
{
|
||||
try
|
||||
{
|
||||
return RESOURCE_BUNDLE.getString(key);
|
||||
|
||||
}
|
||||
catch (MissingResourceException exc)
|
||||
{
|
||||
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 = Resources.getString(imageID.getId());
|
||||
try
|
||||
{
|
||||
Resources.class.getClassLoader()
|
||||
.getResourceAsStream(path).read(image);
|
||||
|
||||
}
|
||||
catch (IOException exc)
|
||||
{
|
||||
log.error("Failed to load image:" + path, exc);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* SSHAccountID.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The SSH implementation of a sip-communicator account id.
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class SSHAccountID
|
||||
extends AccountID
|
||||
{
|
||||
/**
|
||||
* Creates an account id from the specified id and account properties.
|
||||
*
|
||||
* @param userID the user identifier correspnding to thi account
|
||||
* @param accountProperties any other properties necessary for the account.
|
||||
*/
|
||||
SSHAccountID(String userID, Map accountProperties)
|
||||
{
|
||||
super(userID
|
||||
, accountProperties
|
||||
, "SSH"
|
||||
, "sip-communicator.org");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* SSHActivator.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* Loads the SSH provider factory and registers its services in the OSGI
|
||||
* bundle context.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class SSHActivator
|
||||
implements BundleActivator
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(SSHActivator.class);
|
||||
|
||||
/**
|
||||
* A reference to the registration of our SSH protocol provider
|
||||
* factory.
|
||||
*/
|
||||
private ServiceRegistration sshPpFactoryServReg = null;
|
||||
|
||||
/**
|
||||
* A reference to the SSH protocol provider factory.
|
||||
*/
|
||||
private static ProtocolProviderFactorySSHImpl
|
||||
sshProviderFactory = null;
|
||||
|
||||
/**
|
||||
* The currently valid bundle context.
|
||||
*/
|
||||
private static BundleContext bundleContext = null;
|
||||
|
||||
|
||||
/**
|
||||
* Called when this bundle is started. In here we'll export the
|
||||
* ssh 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
|
||||
{
|
||||
this.bundleContext = context;
|
||||
|
||||
Hashtable hashtable = new Hashtable();
|
||||
hashtable.put(ProtocolProviderFactory.PROTOCOL, "SSH");
|
||||
|
||||
sshProviderFactory = new ProtocolProviderFactorySSHImpl();
|
||||
|
||||
//load all stored SSH accounts.
|
||||
sshProviderFactory.loadStoredAccounts();
|
||||
|
||||
//reg the ssh provider factory.
|
||||
sshPpFactoryServReg = context.registerService(
|
||||
ProtocolProviderFactory.class.getName(),
|
||||
sshProviderFactory,
|
||||
hashtable);
|
||||
|
||||
logger.info("SSH protocol implementation [STARTED].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the bundle context that we were started with.
|
||||
* @return bundleContext a reference to the BundleContext instance
|
||||
* that we were started with.
|
||||
*/
|
||||
public static BundleContext getBundleContext()
|
||||
{
|
||||
return bundleContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrurns a reference to the protocol provider factory that we have
|
||||
* registered.
|
||||
* @return a reference to the <tt>ProtocolProviderFactoryJabberImpl</tt>
|
||||
* instance that we have registered from this package.
|
||||
*/
|
||||
public static ProtocolProviderFactorySSHImpl
|
||||
getProtocolProviderFactory()
|
||||
{
|
||||
return sshProviderFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.sshProviderFactory.stop();
|
||||
sshPpFactoryServReg.unregister();
|
||||
logger.info("SSH protocol implementation [STOPPED].");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* SSHStatusEnum.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
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 SSH contact can fall into.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class SSHStatusEnum
|
||||
extends PresenceStatus
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(SSHStatusEnum.class);
|
||||
|
||||
/**
|
||||
* Indicates an Offline status or status with 0 connectivity.
|
||||
*/
|
||||
public static final SSHStatusEnum OFFLINE
|
||||
= new SSHStatusEnum(
|
||||
0
|
||||
, "Offline"
|
||||
, loadIcon("resources/images/ssh/ssh-offline.png"));
|
||||
|
||||
/**
|
||||
* The Not Available status. Indicates that the user has connectivity
|
||||
* but might not be able to immediately act (i.e. even less immediately than
|
||||
* when in an Away status ;-P ) upon initiation of communication.
|
||||
*
|
||||
*/
|
||||
public static final SSHStatusEnum NOT_AVAILABLE
|
||||
= new SSHStatusEnum(
|
||||
35
|
||||
, "Not Available"
|
||||
, loadIcon("resources/images/ssh/ssh-na.png"));
|
||||
|
||||
/**
|
||||
* The Connecting status. Indicate that the user is connecting to remote
|
||||
* server
|
||||
*/
|
||||
public static final SSHStatusEnum CONNECTING
|
||||
= new SSHStatusEnum(
|
||||
55
|
||||
, "Connecting"
|
||||
, loadIcon("resources/images/ssh/ssh-connecting.png"));
|
||||
|
||||
/**
|
||||
* The Online status. Indicate that the user is able and willing to
|
||||
* communicate.
|
||||
*/
|
||||
public static final SSHStatusEnum ONLINE
|
||||
= new SSHStatusEnum(
|
||||
65
|
||||
, "Online"
|
||||
, loadIcon("resources/images/ssh/ssh-online.png"));
|
||||
|
||||
|
||||
/**
|
||||
* The Connecting status. Indicate that the user is connecting to remote
|
||||
* server
|
||||
*/
|
||||
public static final SSHStatusEnum CONNECTED
|
||||
= new SSHStatusEnum(
|
||||
70
|
||||
, "Connecting"
|
||||
, loadIcon("resources/images/ssh/ssh-connected.png"));
|
||||
|
||||
/**
|
||||
* The File Transfer status. Indicate that the user is transfering a file
|
||||
* to/from a remote server
|
||||
*/
|
||||
public static final SSHStatusEnum FILE_TRANSFER
|
||||
= new SSHStatusEnum(
|
||||
75
|
||||
, "Transfering File"
|
||||
, loadIcon("resources/images/ssh/ssh-filetransfer.png"));
|
||||
|
||||
/**
|
||||
* Initialize the list of supported status states.
|
||||
*/
|
||||
private static List supportedStatusSet = new LinkedList();
|
||||
static
|
||||
{
|
||||
supportedStatusSet.add(OFFLINE);
|
||||
// supportedStatusSet.add(NOT_AVAILABLE);
|
||||
supportedStatusSet.add(ONLINE);
|
||||
// supportedStatusSet.add(CONNECTING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of <tt>SSHPresneceStatus</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 SSHStatusEnum(int status,
|
||||
String statusName,
|
||||
byte[] statusIcon)
|
||||
{
|
||||
super(status, statusName, statusIcon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over all status instances supproted by the ssh
|
||||
* provider.
|
||||
* @return an <tt>Iterator</tt> over all status instances supported by the
|
||||
* ssh 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 = SSHStatusEnum.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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* SSHUserInfo.java
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.impl.protocol.ssh;
|
||||
|
||||
import com.jcraft.jsch.*;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* SSHUserInfo passes authentication details to JSch SSH Stack
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
class SSHUserInfo
|
||||
implements UserInfo,
|
||||
UIKeyboardInteractive
|
||||
{
|
||||
/**
|
||||
* The Contact of the remote machine
|
||||
*/
|
||||
private ContactSSH sshContact;
|
||||
|
||||
/**
|
||||
* Identifier for failure of authentication
|
||||
* more explanation below in promptPassword function
|
||||
*/
|
||||
private boolean failedOnce = false;
|
||||
|
||||
/**
|
||||
* Password field for requesting auth details from user
|
||||
*/
|
||||
JTextField passwordField=(JTextField)new JPasswordField(20);
|
||||
|
||||
/**
|
||||
* Creates a UserInfo instance
|
||||
*
|
||||
* @param sshContact the contact concerned
|
||||
*/
|
||||
SSHUserInfo(ContactSSH sshContact)
|
||||
{
|
||||
this.sshContact = sshContact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password of account associated with this contact
|
||||
*
|
||||
* @return the password of account associated with this contact
|
||||
*/
|
||||
public String getPassword()
|
||||
{
|
||||
return sshContact.getPassword();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt for accepting the cipher information of the remote server
|
||||
*
|
||||
* @param str the string to display
|
||||
*
|
||||
* @return the user's answer
|
||||
*/
|
||||
public boolean promptYesNo(String str)
|
||||
{
|
||||
Object[] options={ "yes", "no" };
|
||||
int foo=JOptionPane.showOptionDialog(null,
|
||||
str,
|
||||
"Warning",
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.WARNING_MESSAGE,
|
||||
null, options, options[0]);
|
||||
return foo==0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passphrase authentication presently not implemented
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public String getPassphrase()
|
||||
{ return null; }
|
||||
|
||||
/**
|
||||
* Passphrase authentication presently not implemented
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public boolean promptPassphrase(String message)
|
||||
{ return true; }
|
||||
|
||||
/**
|
||||
* Asks user to re-enter password information in case of an auth failure
|
||||
*
|
||||
* @param message the message to display
|
||||
*
|
||||
* @return the user's answer
|
||||
*/
|
||||
public boolean promptPassword(String message)
|
||||
{
|
||||
/**
|
||||
* Auth always fails for the first time for Redhat based machines.
|
||||
* Trying again with the same password
|
||||
*/
|
||||
if(!failedOnce)
|
||||
{
|
||||
failedOnce = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Object[] ob={passwordField};
|
||||
int result=JOptionPane.showConfirmDialog(null, ob, "Auth Failed: "
|
||||
+ message,
|
||||
JOptionPane.OK_CANCEL_OPTION);
|
||||
|
||||
if(result==JOptionPane.OK_OPTION)
|
||||
{
|
||||
sshContact.setPassword(passwordField.getText());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a message from server
|
||||
*
|
||||
* @param message The message to display
|
||||
*/
|
||||
public void showMessage(String message)
|
||||
{
|
||||
JOptionPane.showMessageDialog(null, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keyboard Interactive Auth - not implemented
|
||||
*/
|
||||
public String[] promptKeyboardInteractive(
|
||||
String destination,
|
||||
String name,
|
||||
String instruction,
|
||||
String[] prompt,
|
||||
boolean[] echo)
|
||||
{
|
||||
String response[] = new String[prompt.length];
|
||||
response[0] = sshContact.getPassword();
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
#The test command should be choosen uniquely i.e. it should not appear in output
|
||||
# of any other command(including its own), else the reply of the offending
|
||||
# command will be cut short
|
||||
testCommand=uname
|
||||
#First line of reply of test command (must be independent of state of remote
|
||||
# machine)
|
||||
testCommandResponse=Linux
|
||||
#Contact Details Seperator(must not be part of contact data stored as persistent
|
||||
# data)
|
||||
detailsSeperator=~
|
||||
#Connection timeout to a remote server in seconds
|
||||
connectionTimeout=30
|
||||
protocolIcon=resources/images/ssh/ssh-online.png
|
||||
@ -0,0 +1,17 @@
|
||||
Bundle-Activator: net.java.sip.communicator.impl.protocol.ssh.SSHActivator
|
||||
Bundle-Name: SSH Protocol Provider
|
||||
Bundle-Description: A bundle providing support for the SSH protocol.
|
||||
Bundle-Vendor: sip-communicator.org
|
||||
Bundle-Version: 0.0.1
|
||||
Import-Package: org.osgi.framework,
|
||||
javax.swing,
|
||||
javax.swing.border,
|
||||
javax.crypto,
|
||||
javax.crypto.spec,
|
||||
javax.crypto.interfaces,
|
||||
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.gui
|
||||
@ -0,0 +1,419 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* FirstWizardPage.java
|
||||
*
|
||||
* Created on 22 May, 2007, 8:44 AM
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.plugin.sshaccregwizz;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
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.impl.protocol.ssh.*;
|
||||
|
||||
/**
|
||||
* The <tt>FirstWizardPage</tt> is the page, where user could enter the user ID
|
||||
* and the password of the account.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class FirstWizardPage
|
||||
extends JPanel implements WizardPage, DocumentListener
|
||||
{
|
||||
|
||||
public static final String FIRST_PAGE_IDENTIFIER = "FirstPageIdentifier";
|
||||
|
||||
private JPanel accountPanel = new JPanel(new BorderLayout(10, 10));
|
||||
|
||||
private JPanel labelsPanel = new JPanel();
|
||||
|
||||
private JPanel valuesPanel = new JPanel();
|
||||
|
||||
private JLabel accountID = new JLabel(Resources.getString("accountID"));
|
||||
|
||||
private JLabel identityFile = new JLabel(Resources.getString(
|
||||
"identityFile"));
|
||||
|
||||
private JLabel knownHostsFile = new JLabel(Resources.getString(
|
||||
"knownHosts"));
|
||||
|
||||
private JLabel existingAccountLabel
|
||||
= new JLabel(Resources.getString("existingAccount"));
|
||||
|
||||
private JPanel emptyPanel1 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel2 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel3 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel4 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel5 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel6 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel7 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel8 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel9 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel10 = new JPanel();
|
||||
|
||||
private JPanel emptyPanel11 = new JPanel();
|
||||
|
||||
private JTextField accountIDField = new JTextField();
|
||||
|
||||
private JTextField identityFileField = new JTextField("Optional");
|
||||
|
||||
private JButton identityFileButton = new JButton("Browse");
|
||||
|
||||
private JFileChooser identityFileChooser = new JFileChooser();
|
||||
|
||||
private JPanel identityFilePanel = new JPanel();
|
||||
|
||||
private JTextField knownHostsFileField = new JTextField("Optional");
|
||||
|
||||
private JButton knownHostsFileButton = new JButton("Browse");
|
||||
|
||||
private JFileChooser knownHostsFileChooser = new JFileChooser();
|
||||
|
||||
private JPanel knownHostsFilePanel = new JPanel();
|
||||
|
||||
private JPanel mainPanel = new JPanel();
|
||||
|
||||
private Object nextPageIdentifier = WizardPage.SUMMARY_PAGE_IDENTIFIER;
|
||||
|
||||
private SSHAccountRegistration registration = null;
|
||||
|
||||
private WizardContainer wizardContainer;
|
||||
|
||||
/**
|
||||
* Creates an instance of <tt>FirstWizardPage</tt>.
|
||||
* @param registration the <tt>SSHAccountRegistration</tt>, where
|
||||
* all data through the wizard are stored
|
||||
* @param wizardContainer the wizardContainer, where this page will
|
||||
* be added
|
||||
*/
|
||||
public FirstWizardPage(SSHAccountRegistration registration,
|
||||
WizardContainer wizardContainer)
|
||||
{
|
||||
|
||||
super(new BorderLayout());
|
||||
|
||||
this.wizardContainer = wizardContainer;
|
||||
|
||||
this.registration = registration;
|
||||
|
||||
this.setPreferredSize(new Dimension(300, 150));
|
||||
|
||||
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
identityFileField.setEditable(false);
|
||||
|
||||
knownHostsFileField.setEditable(false);
|
||||
|
||||
identityFileChooser.setFileHidingEnabled(false);
|
||||
|
||||
knownHostsFileChooser.setFileHidingEnabled(false);
|
||||
|
||||
this.init();
|
||||
|
||||
this.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
|
||||
this.labelsPanel.setLayout(new BoxLayout(labelsPanel,
|
||||
BoxLayout.Y_AXIS));
|
||||
|
||||
this.valuesPanel.setLayout(new BoxLayout(valuesPanel,
|
||||
BoxLayout.Y_AXIS));
|
||||
|
||||
this.identityFilePanel.setLayout(new BoxLayout(identityFilePanel,
|
||||
BoxLayout.X_AXIS));
|
||||
|
||||
this.knownHostsFilePanel.setLayout(new BoxLayout(knownHostsFilePanel,
|
||||
BoxLayout.X_AXIS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all panels, buttons, etc.
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
|
||||
this.accountIDField.getDocument().addDocumentListener(this);
|
||||
this.existingAccountLabel.setForeground(Color.RED);
|
||||
|
||||
/*
|
||||
* Following empty panels cover the space needed between key labels
|
||||
* WRT Height 2 key lables = 1 text field
|
||||
*/
|
||||
this.emptyPanel1.setMaximumSize(new Dimension(40, 35));
|
||||
this.emptyPanel2.setMaximumSize(new Dimension(40, 35));
|
||||
this.emptyPanel3.setMaximumSize(new Dimension(40, 35));
|
||||
this.emptyPanel4.setMaximumSize(new Dimension(40, 35));
|
||||
this.emptyPanel5.setMaximumSize(new Dimension(40, 35));
|
||||
this.emptyPanel6.setMaximumSize(new Dimension(40, 35));
|
||||
this.emptyPanel7.setMaximumSize(new Dimension(40, 35));
|
||||
|
||||
identityFilePanel.add(identityFileField);
|
||||
identityFilePanel.add(identityFileButton);
|
||||
|
||||
knownHostsFilePanel.add(knownHostsFileField);
|
||||
knownHostsFilePanel.add(knownHostsFileButton);
|
||||
|
||||
labelsPanel.add(emptyPanel1);
|
||||
labelsPanel.add(accountID);
|
||||
labelsPanel.add(emptyPanel2);
|
||||
labelsPanel.add(emptyPanel3);
|
||||
labelsPanel.add(identityFile);
|
||||
labelsPanel.add(emptyPanel4);
|
||||
labelsPanel.add(emptyPanel5);
|
||||
labelsPanel.add(knownHostsFile);
|
||||
labelsPanel.add(emptyPanel6);
|
||||
|
||||
valuesPanel.add(accountIDField);
|
||||
valuesPanel.add(emptyPanel7);
|
||||
valuesPanel.add(identityFilePanel);
|
||||
valuesPanel.add(emptyPanel8);
|
||||
valuesPanel.add(knownHostsFilePanel);
|
||||
labelsPanel.add(emptyPanel9);
|
||||
|
||||
accountPanel.add(labelsPanel, BorderLayout.WEST);
|
||||
accountPanel.add(valuesPanel, BorderLayout.CENTER);
|
||||
|
||||
identityFileButton.addActionListener(new ActionListener()
|
||||
{
|
||||
public void actionPerformed(ActionEvent event)
|
||||
{
|
||||
int returnVal = identityFileChooser.showDialog
|
||||
(FirstWizardPage.this, "Select Identify File");
|
||||
|
||||
if(returnVal == JFileChooser.APPROVE_OPTION)
|
||||
identityFileField.setText(identityFileChooser
|
||||
.getSelectedFile().getAbsolutePath());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
knownHostsFileButton.addActionListener(new ActionListener()
|
||||
{
|
||||
public void actionPerformed(ActionEvent event)
|
||||
{
|
||||
int returnVal = knownHostsFileChooser.showDialog
|
||||
(FirstWizardPage.this, "Select Identify File");
|
||||
|
||||
if(returnVal == JFileChooser.APPROVE_OPTION)
|
||||
knownHostsFileField.setText(knownHostsFileChooser
|
||||
.getSelectedFile().getAbsolutePath());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
accountPanel.setBorder(BorderFactory
|
||||
.createTitledBorder(Resources.getString(
|
||||
"accountDetails")));
|
||||
|
||||
this.add(accountPanel, BorderLayout.NORTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the Account ID, Identity File and Known Hosts File 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)
|
||||
{
|
||||
ProtocolProviderFactorySSH protocolProviderSSH =
|
||||
(ProtocolProviderFactorySSH)protocolProvider;
|
||||
|
||||
AccountID accountID = protocolProvider.getAccountID();
|
||||
|
||||
String identityFile = (String) accountID.getAccountProperties()
|
||||
.get(ProtocolProviderFactorySSH.IDENTITY_FILE);
|
||||
|
||||
String knownHostsFile = (String) accountID.getAccountProperties()
|
||||
.get(ProtocolProviderFactorySSH.KNOWN_HOSTS_FILE);
|
||||
|
||||
this.accountIDField.setText(accountID.getUserID());
|
||||
|
||||
this.identityFileField.setText(identityFile);
|
||||
|
||||
this.knownHostsFileField.setText(knownHostsFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getIdentifier</code> to return
|
||||
* this page identifier.
|
||||
*
|
||||
* @return the Identifier of the first page in this wizard.
|
||||
*/
|
||||
public Object getIdentifier()
|
||||
{
|
||||
return FIRST_PAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getNextPageIdentifier</code> to return
|
||||
* the next page identifier - the summary page.
|
||||
*
|
||||
* @return the identifier of the page following this one.
|
||||
*/
|
||||
public Object getNextPageIdentifier()
|
||||
{
|
||||
return nextPageIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getBackPageIdentifier</code> to return
|
||||
* the next back identifier - the default page.
|
||||
*
|
||||
* @return the identifier of the default wizard page.
|
||||
*/
|
||||
public Object getBackPageIdentifier()
|
||||
{
|
||||
return WizardPage.DEFAULT_PAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getWizardForm</code> to return
|
||||
* this panel.
|
||||
*
|
||||
* @return the component to be displayed in this wizard page.
|
||||
*/
|
||||
public Object getWizardForm()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before this page is displayed enables or disables the "Next" wizard
|
||||
* button according to whether the UserID field is empty.
|
||||
*/
|
||||
public void pageShowing()
|
||||
{
|
||||
this.setNextButtonAccordingToUserID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the user input when the "Next" wizard buttons is clicked.
|
||||
*/
|
||||
public void pageNext()
|
||||
{
|
||||
String userID = accountIDField.getText();
|
||||
|
||||
if (isExistingAccount(userID))
|
||||
{
|
||||
nextPageIdentifier = FIRST_PAGE_IDENTIFIER;
|
||||
accountPanel.add(existingAccountLabel, BorderLayout.NORTH);
|
||||
this.revalidate();
|
||||
}
|
||||
else
|
||||
{
|
||||
nextPageIdentifier = SUMMARY_PAGE_IDENTIFIER;
|
||||
accountPanel.remove(existingAccountLabel);
|
||||
|
||||
registration.setAccountID(accountIDField.getText());
|
||||
registration.setIdentityFile(identityFileField.getText());
|
||||
registration.setKnownHostsFile(knownHostsFileField.getText());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the "Next" wizard button according to whether the
|
||||
* User ID field is empty.
|
||||
*/
|
||||
private void setNextButtonAccordingToUserID()
|
||||
{
|
||||
if (accountIDField.getText() == null || accountIDField.getText()
|
||||
.equals(""))
|
||||
{
|
||||
wizardContainer.setNextFinishButtonEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
wizardContainer.setNextFinishButtonEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the <tt>DocumentEvent</tt> triggered when user types in the
|
||||
* User ID field. Enables or disables the "Next" wizard button according to
|
||||
* whether the User ID field is empty.
|
||||
*
|
||||
* @param event the event containing the update.
|
||||
*/
|
||||
public void insertUpdate(DocumentEvent event)
|
||||
{
|
||||
this.setNextButtonAccordingToUserID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the <tt>DocumentEvent</tt> triggered when user deletes letters
|
||||
* from the UserID field. Enables or disables the "Next" wizard button
|
||||
* according to whether the UserID field is empty.
|
||||
*
|
||||
* @param event the event containing the update.
|
||||
*/
|
||||
public void removeUpdate(DocumentEvent event)
|
||||
{
|
||||
this.setNextButtonAccordingToUserID();
|
||||
}
|
||||
|
||||
public void changedUpdate(DocumentEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
public void pageHiding()
|
||||
{
|
||||
}
|
||||
|
||||
public void pageShown()
|
||||
{
|
||||
}
|
||||
|
||||
public void pageBack()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies whether there is already an account installed with the same
|
||||
* details as the one that the user has just entered.
|
||||
*
|
||||
* @param accountID the name of the user that the account is registered for
|
||||
* @return true if there is already an account for this accountID and false
|
||||
* otherwise.
|
||||
*/
|
||||
private boolean isExistingAccount(String userID)
|
||||
{
|
||||
ProtocolProviderFactory factory
|
||||
= SSHAccRegWizzActivator.getSSHProtocolProviderFactory();
|
||||
|
||||
ArrayList registeredAccounts = factory.getRegisteredAccounts();
|
||||
|
||||
for (int i = 0; i < registeredAccounts.size(); i++)
|
||||
{
|
||||
AccountID accountID = (AccountID) registeredAccounts.get(i);
|
||||
|
||||
if (userID.equalsIgnoreCase(accountID.getUserID()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* Resources.java
|
||||
*
|
||||
* Created on 22 May, 2007, 8:53 AM
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.plugin.sshaccregwizz;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* The Messages class manages the access to the internationalization
|
||||
* properties files.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class Resources
|
||||
{
|
||||
|
||||
private static Logger log = Logger.getLogger(Resources.class);
|
||||
|
||||
private static final String BUNDLE_NAME
|
||||
= "net.java.sip.communicator.plugin.sshaccregwizz.resources";
|
||||
|
||||
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
||||
.getBundle(BUNDLE_NAME);
|
||||
|
||||
public static ImageID SSH_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 RESOURCE_BUNDLE.getString(key);
|
||||
|
||||
}
|
||||
catch (MissingResourceException exc)
|
||||
{
|
||||
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 = Resources.getString(imageID.getId());
|
||||
try
|
||||
{
|
||||
Resources.class.getClassLoader()
|
||||
.getResourceAsStream(path).read(image);
|
||||
|
||||
}
|
||||
catch (IOException exc)
|
||||
{
|
||||
log.error("Failed to load image:" + path, exc);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* SSHAccRegWizzActivator.java
|
||||
*
|
||||
* Created on 22 May, 2007, 8:48 AM
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.plugin.sshaccregwizz;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
|
||||
import net.java.sip.communicator.service.configuration.*;
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Registers the <tt>SSHAccountRegistrationWizard</tt> in the UI Service.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class SSHAccRegWizzActivator
|
||||
implements BundleActivator
|
||||
{
|
||||
private static Logger logger = Logger.getLogger(
|
||||
SSHAccRegWizzActivator.class.getName());
|
||||
|
||||
/**
|
||||
* A currently valid bundle context.
|
||||
*/
|
||||
public static BundleContext bundleContext;
|
||||
|
||||
/**
|
||||
* A currently valid reference to the configuration service.
|
||||
*/
|
||||
private static ConfigurationService configService;
|
||||
|
||||
private static AccountRegistrationWizardContainer wizardContainer;
|
||||
|
||||
private static SSHAccountRegistrationWizard sshWizard;
|
||||
|
||||
/**
|
||||
* Starts this bundle.
|
||||
* @param bc the currently valid <tt>BundleContext</tt>.
|
||||
*/
|
||||
public void start(BundleContext bc)
|
||||
{
|
||||
logger.info("Loading ssh account wizard.");
|
||||
|
||||
bundleContext = bc;
|
||||
|
||||
ServiceReference uiServiceRef = bundleContext
|
||||
.getServiceReference(UIService.class.getName());
|
||||
|
||||
UIService uiService = (UIService) bundleContext
|
||||
.getService(uiServiceRef);
|
||||
|
||||
wizardContainer = uiService.getAccountRegWizardContainer();
|
||||
|
||||
sshWizard
|
||||
= new SSHAccountRegistrationWizard(wizardContainer);
|
||||
|
||||
wizardContainer.addAccountRegistrationWizard(sshWizard);
|
||||
|
||||
logger.info("SSH account registration wizard [STARTED].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this bundle is stopped so the Framework can perform the
|
||||
* bundle-specific activities necessary to stop the bundle.
|
||||
*
|
||||
* @param bundleContext The execution context of the bundle being stopped.
|
||||
*/
|
||||
public void stop(BundleContext bundleContext) throws Exception
|
||||
{
|
||||
wizardContainer.removeAccountRegistrationWizard(sshWizard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <tt>ProtocolProviderFactory</tt> for the SSH protocol.
|
||||
* @return the <tt>ProtocolProviderFactory</tt> for the SSH protocol
|
||||
*/
|
||||
public static ProtocolProviderFactory getSSHProtocolProviderFactory()
|
||||
{
|
||||
|
||||
ServiceReference[] serRefs = null;
|
||||
|
||||
String osgiFilter = "("
|
||||
+ ProtocolProviderFactory.PROTOCOL
|
||||
+ "=" + "SSH" + ")";
|
||||
|
||||
try
|
||||
{
|
||||
serRefs = bundleContext.getServiceReferences(
|
||||
ProtocolProviderFactory.class.getName(), osgiFilter);
|
||||
}
|
||||
catch (InvalidSyntaxException ex)
|
||||
{
|
||||
logger.error(ex);
|
||||
}
|
||||
|
||||
return (ProtocolProviderFactory) bundleContext.getService(serRefs[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundleContext that we received when we were started.
|
||||
*
|
||||
* @return a currently valid instance of a bundleContext.
|
||||
*/
|
||||
public BundleContext getBundleContext()
|
||||
{
|
||||
return bundleContext;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* SSHAccountRegistration.java
|
||||
*
|
||||
* Created on 22 May, 2007, 8:49 AM
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.plugin.sshaccregwizz;
|
||||
|
||||
/**
|
||||
* The <tt>SSHAccountRegistration</tt> is used to store all user input data
|
||||
* through the <tt>SSHAccountRegistrationWizard</tt>.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class SSHAccountRegistration
|
||||
{
|
||||
private String accountID;
|
||||
private String knownHostsFile;
|
||||
private String identityFile;
|
||||
|
||||
/**
|
||||
* Returns the Account ID of the ssh registration account.
|
||||
* @return accountID
|
||||
*/
|
||||
public String getAccountID()
|
||||
{
|
||||
return accountID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Account ID of the ssh registration account.
|
||||
*
|
||||
* @param accountID the accountID of the ssh registration account.
|
||||
*/
|
||||
public void setAccountID(String accountID)
|
||||
{
|
||||
this.accountID = accountID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Known Hosts of the ssh registration account.
|
||||
*
|
||||
* @return knownHostsFile
|
||||
*/
|
||||
public String getKnownHostsFile()
|
||||
{
|
||||
return knownHostsFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Known Hosts of the ssh registration account.
|
||||
*
|
||||
* @param knownHostsFile
|
||||
*/
|
||||
public void setKnownHostsFile(String knownHostsFile)
|
||||
{
|
||||
this.knownHostsFile = knownHostsFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Identity File of the ssh registration account.
|
||||
*
|
||||
* @return identityFile
|
||||
*/
|
||||
public String getIdentityFile()
|
||||
{
|
||||
return identityFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Machine Port of the ssh registration account.
|
||||
*
|
||||
* @param machinePort
|
||||
*/
|
||||
public void setIdentityFile(String machinePort)
|
||||
{
|
||||
this.identityFile = machinePort;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*
|
||||
* SSHAccountRegistrationWizard.java
|
||||
*
|
||||
* Created on 22 May, 2007, 8:51 AM
|
||||
*
|
||||
* SSH Suport in SIP Communicator - GSoC' 07 Project
|
||||
*
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.plugin.sshaccregwizz;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.impl.gui.customcontrols.*;
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.impl.protocol.ssh.*;
|
||||
|
||||
/**
|
||||
* The <tt>SSHAccountRegistrationWizard</tt> is an implementation of the
|
||||
* <tt>AccountRegistrationWizard</tt> for the SSH protocol. It allows
|
||||
* the user to create and configure a new SSH account.
|
||||
*
|
||||
* @author Shobhit Jindal
|
||||
*/
|
||||
public class SSHAccountRegistrationWizard
|
||||
implements AccountRegistrationWizard
|
||||
{
|
||||
|
||||
/**
|
||||
* The first page of the ssh account registration wizard.
|
||||
*/
|
||||
private FirstWizardPage firstWizardPage;
|
||||
|
||||
/**
|
||||
* The object that we use to store details on an account that we will be
|
||||
* creating.
|
||||
*/
|
||||
private SSHAccountRegistration registration
|
||||
= new SSHAccountRegistration();
|
||||
|
||||
private WizardContainer wizardContainer;
|
||||
|
||||
private ProtocolProviderService protocolProvider;
|
||||
|
||||
private String propertiesPackage
|
||||
= "net.java.sip.communicator.plugin.sshaccregwizz";
|
||||
|
||||
private boolean isModification;
|
||||
|
||||
/**
|
||||
* Creates an instance of <tt>SSHAccountRegistrationWizard</tt>.
|
||||
* @param wizardContainer the wizard container, where this wizard
|
||||
* is added
|
||||
*/
|
||||
public SSHAccountRegistrationWizard(WizardContainer wizardContainer)
|
||||
{
|
||||
this.wizardContainer = wizardContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>AccountRegistrationWizard.getIcon</code> method.
|
||||
* Returns the icon to be used for this wizard.
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getIcon()
|
||||
{
|
||||
return Resources.getImage(Resources.SSH_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. Returns the protocol name for this wizard.
|
||||
* @return String
|
||||
*/
|
||||
public String getProtocolName()
|
||||
{
|
||||
return Resources.getString("protocolName");
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>AccountRegistrationWizard.getProtocolDescription
|
||||
* </code> method. Returns the description of the protocol for this wizard.
|
||||
* @return String
|
||||
*/
|
||||
public String getProtocolDescription()
|
||||
{
|
||||
return Resources.getString("protocolDescription");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of pages contained in this wizard.
|
||||
* @return Iterator
|
||||
*/
|
||||
public Iterator getPages()
|
||||
{
|
||||
ArrayList pages = new ArrayList();
|
||||
firstWizardPage = new FirstWizardPage(registration, wizardContainer);
|
||||
|
||||
pages.add(firstWizardPage);
|
||||
|
||||
return pages.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of data that user has entered through this wizard.
|
||||
* @return Iterator
|
||||
*/
|
||||
public Iterator getSummary()
|
||||
{
|
||||
Hashtable summaryTable = new Hashtable();
|
||||
|
||||
/*
|
||||
* Hashtable arranges the entries alphabetically so the order of appearance is
|
||||
* - Computer Name / IP
|
||||
* - Port
|
||||
* - User ID
|
||||
*/
|
||||
|
||||
summaryTable.put("Account ID", registration.getAccountID());
|
||||
summaryTable.put("Known Hosts", registration.getKnownHostsFile());
|
||||
summaryTable.put("Identity", registration.getIdentityFile());
|
||||
|
||||
return summaryTable.entrySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs the account created through this wizard.
|
||||
* @return ProtocolProviderService
|
||||
*/
|
||||
public ProtocolProviderService finish()
|
||||
{
|
||||
firstWizardPage = null;
|
||||
ProtocolProviderFactory factory
|
||||
= SSHAccRegWizzActivator.getSSHProtocolProviderFactory();
|
||||
|
||||
return this.installAccount(factory,
|
||||
registration.getAccountID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an account for the given Account ID, Identity File and Known
|
||||
* Hosts File
|
||||
*
|
||||
* @param providerFactory the ProtocolProviderFactory which will create
|
||||
* the account
|
||||
* @param user the user identifier
|
||||
* @return the <tt>ProtocolProviderService</tt> for the new account.
|
||||
*/
|
||||
public ProtocolProviderService installAccount(
|
||||
ProtocolProviderFactory providerFactory,
|
||||
String user)
|
||||
{
|
||||
|
||||
Hashtable accountProperties = new Hashtable();
|
||||
|
||||
accountProperties.put(ProtocolProviderFactorySSHImpl.IDENTITY_FILE,
|
||||
registration.getIdentityFile());
|
||||
|
||||
accountProperties.put(ProtocolProviderFactorySSH.KNOWN_HOSTS_FILE,
|
||||
String.valueOf(registration.getKnownHostsFile()));
|
||||
|
||||
try
|
||||
{
|
||||
AccountID accountID = providerFactory.installAccount(
|
||||
user, accountProperties);
|
||||
|
||||
ServiceReference serRef = providerFactory
|
||||
.getProviderForAccount(accountID);
|
||||
|
||||
protocolProvider = (ProtocolProviderService)
|
||||
SSHAccRegWizzActivator.bundleContext
|
||||
.getService(serRef);
|
||||
}
|
||||
catch (IllegalArgumentException exc)
|
||||
{
|
||||
new ErrorDialog(null, exc.getMessage(), exc).showDialog();
|
||||
}
|
||||
catch (IllegalStateException exc)
|
||||
{
|
||||
new ErrorDialog(null, exc.getMessage(), exc).showDialog();
|
||||
}
|
||||
|
||||
return protocolProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the UserID and Password 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)
|
||||
{
|
||||
|
||||
this.protocolProvider = protocolProvider;
|
||||
|
||||
this.firstWizardPage.loadAccount(protocolProvider);
|
||||
|
||||
isModification = true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
protocolName=SSH
|
||||
protocolDescription=A Protocol to connect to remote machines over SSH.
|
||||
accountID=Account ID:
|
||||
identityFile=Identitity File:
|
||||
knownHosts=Known Hosts:
|
||||
accountDetails=SSH Account Details
|
||||
existingAccount=* The account you entered is already installed.
|
||||
|
||||
protocolIcon=resources/images/ssh/ssh-online.png
|
||||
pageImage=resources/images/ssh/ssh64x64.png
|
||||
@ -0,0 +1,30 @@
|
||||
Bundle-Activator: net.java.sip.communicator.plugin.sshaccregwizz.SSHAccRegWizzActivator
|
||||
Bundle-Name: SSH account registration wizard
|
||||
Bundle-Description: SSH 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.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
|
||||