SSH support - by Jindal Shobhit - currently deactivated for security reasons

cusax-fix
Benoit Pradelle 19 years ago
parent 579f7015f0
commit b274b6eb8f

@ -875,7 +875,8 @@
bundle-rss, bundle-rss-slick,bundle-plugin-rssaccregwizz,
bundle-zeroconf,bundle-plugin-zeroconfaccregwizz,
bundle-irc,bundle-plugin-ircaccregwizz,
bundle-pluginmanager,bundle-notification"/>
bundle-pluginmanager,bundle-notification,
bundle-ssh,bundle-plugin-sshaccregwizz"/>
<!--BUNDLE-HISTORY-->
<target name="bundle-history">
@ -1273,6 +1274,31 @@ javax.swing.event, javax.swing.border"/>
<zipfileset src="${lib.noinst}/commons-logging.jar" prefix=""/>
</jar>
</target>
<!-- BUNDLE-SSH -->
<target name="bundle-ssh">
<!-- Creates a bundle containing the SSH impl of the protocol provider.-->
<jar compress="false" destfile="${bundles.dest}/protocol-ssh.jar"
manifest="src/net/java/sip/communicator/impl/protocol/ssh/ssh.provider.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/impl/protocol/ssh"
prefix="net/java/sip/communicator/impl/protocol/ssh"/>
<zipfileset src="${lib.noinst}/jsch-0.1.33.jar" prefix=""/>
<zipfileset dir="resources/images/ssh"
prefix="resources/images/ssh"/>
</jar>
</target>
<!-- BUNDLE-PLUGIN-SSHACCREGWIZZ -->
<target name="bundle-plugin-sshaccregwizz">
<!-- Creates a bundle for the plugin SSH Account Registration Wizard.-->
<jar compress="false" destfile="${bundles.dest}/sshaccregwizz.jar"
manifest="src/net/java/sip/communicator/plugin/sshaccregwizz/sshaccregwizz.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/plugin/sshaccregwizz"
prefix="net/java/sip/communicator/plugin/sshaccregwizz"/>
<zipfileset dir="resources/images/ssh"
prefix="resources/images/ssh"/>
</jar>
</target>
<!-- BUNDLE-YAHOO -->
<target name="bundle-yahoo">

@ -49,5 +49,6 @@
<classpathentry kind="var" path="ECLIPSE_HOME/plugins/org.apache.ant_1.7.0.v200706080842/lib/ant.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/aclibico-2.1.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/pircbot.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/jsch-0.1.33.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
</classpath>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

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

@ -19,7 +19,11 @@
public interface OperationSetFileTransfer
extends OperationSet
{
public void sendFile();
public void sendFile(
Contact toContact,
Contact fromContact,
String remotePath,
String localPath);
public void addFileListener(FileListener listener);
}

Loading…
Cancel
Save