- Some improvements in "feature" introducing in Jabber.

- Support for thumbnails in Jabber file transfer.
- Fixed some issues with the calculated file transfer speed and estimated transfer time.
- Shows open and open folder links also on the sender side when the transfer is completed.
cusax-fix
Yana Stamcheva 17 years ago
parent 425a1abaf8
commit c98f98655f

@ -30,5 +30,6 @@ Export-Package: org.jivesoftware.smack,
org.jivesoftware.smackx.jingle.provider,
org.jivesoftware.smackx.jingle.listeners,
org.jivesoftware.smackx.filetransfer,
org.jivesoftware.smackx.provider,
org.xmlpull.v1,
org.xmlpull.mxp1

@ -785,12 +785,12 @@ public void fileTransferCreated(FileTransferCreatedEvent event)
STRUCTURE_NAMES[4],
fileTransfer.getID(),
STRUCTURE_NAMES[0],
fileTransfer.getFile().getCanonicalPath());
fileTransfer.getLocalFile().getCanonicalPath());
}
else if (fileTransfer.getDirection() == FileTransfer.OUT)
{
historyWriter.addRecord(new String[]{
fileTransfer.getFile().getCanonicalPath(),
fileTransfer.getLocalFile().getCanonicalPath(),
getDirection(FileTransfer.OUT),
String.valueOf(event.getTimestamp().getTime()),
FILE_TRANSFER_ACTIVE,

@ -1906,6 +1906,7 @@ public void statusChanged(FileTransferStatusChangeEvent event)
|| newStatus == FileTransferStatusChangeEvent.REFUSED)
{
removeActiveFileTransfer(fileTransfer.getID());
fileTransfer.removeStatusListener(this);
}
}

@ -8,6 +8,9 @@
package net.java.sip.communicator.impl.gui.main.chat;
import java.io.*;
import java.net.*;
import javax.swing.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
@ -32,6 +35,10 @@ public class MetaContactChatTransport
private final OperationSetPresence presenceOpSet;
private static final int THUMBNAIL_WIDTH = 64;
private static final int THUMBNAIL_HEIGHT = 64;
public MetaContactChatTransport(ChatSession chatSession,
Contact contact)
{
@ -281,6 +288,27 @@ public FileTransfer sendFile(File file)
= (OperationSetFileTransfer) contact.getProtocolProvider()
.getOperationSet(OperationSetFileTransfer.class);
if (FileUtils.isImage(file.getName()))
{
// Create a thumbnailed file if possible.
OperationSetThumbnailedFileFactory tfOpSet
= (OperationSetThumbnailedFileFactory)
contact.getProtocolProvider()
.getOperationSet(OperationSetThumbnailedFileFactory.class);
if (tfOpSet != null)
{
byte[] thumbnail = getFileThumbnail(file);
if (thumbnail != null && thumbnail.length > 0)
{
file = tfOpSet.createFileWithThumbnail(
file, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT,
"image/png", thumbnail);
}
}
}
return ftOpSet.sendFile(contact, file);
}
@ -426,4 +454,42 @@ public Object getDescriptor()
{
return contact;
}
/**
* Sets the icon for the given file.
*
* @param file the file to set an icon for
*/
private byte[] getFileThumbnail(File file)
{
byte[] bytes = null;
if (FileUtils.isImage(file.getName()))
{
try
{
ImageIcon image = new ImageIcon(file.toURI().toURL());
if (image != null)
{
int width = image.getIconWidth();
int height = image.getIconHeight();
if (width > THUMBNAIL_WIDTH)
width = THUMBNAIL_WIDTH;
if (height > THUMBNAIL_HEIGHT)
height = THUMBNAIL_HEIGHT;
bytes = ImageUtils
.getScaledInstanceInBytes(image.getImage(),
width, height);
}
}
catch (MalformedURLException e)
{
logger.debug("Could not locate image.", e);
}
}
return bytes;
}
}

@ -9,7 +9,6 @@
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
@ -35,7 +34,11 @@ public abstract class FileTransferConversationComponent
private final Logger logger
= Logger.getLogger(FileTransferConversationComponent.class);
private final FileImageLabel imageLabel = new FileImageLabel();
protected static final int IMAGE_WIDTH = 64;
protected static final int IMAGE_HEIGHT = 64;
protected final FileImageLabel imageLabel = new FileImageLabel();
protected final JLabel titleLabel = new JLabel();
protected final JLabel fileLabel = new JLabel();
private final JTextArea errorArea = new JTextArea();
@ -70,6 +73,10 @@ public abstract class FileTransferConversationComponent
private FileTransfer fileTransfer;
private final static int SPEED_CALCULATE_DELAY = 5000;
private long transferredFileSize = 0;
private long lastSpeedTimestamp = 0;
private long lastEstimatedTimeTimestamp = 0;
@ -293,43 +300,6 @@ protected void showErrorMessage(String message)
errorArea.setVisible(true);
}
/**
* Sets the icon for the given file.
*
* @param file the file to set an icon for
*/
protected void setFileIcon(File file)
{
if (FileUtils.isImage(file.getName()))
{
try
{
ImageIcon image = new ImageIcon(file.toURI().toURL());
imageLabel.setToolTipImage(image);
image = ImageUtils
.getScaledRoundedIcon(image.getImage(), 64, 64);
imageLabel.setIcon(image);
}
catch (MalformedURLException e)
{
logger.debug("Could not locate image.", e);
imageLabel.setIcon(new ImageIcon(
ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON)));
}
}
else
{
Icon icon = FileUtils.getIcon(file);
if (icon == null)
icon = new ImageIcon(
ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON));
imageLabel.setIcon(icon);
}
}
/**
* Sets the download file.
*
@ -361,9 +331,11 @@ public void mouseClicked(MouseEvent e)
*
* @param fileTransfer the file transfer
*/
protected void setFileTransfer(FileTransfer fileTransfer)
protected void setFileTransfer( FileTransfer fileTransfer,
long transferredFileSize)
{
this.fileTransfer = fileTransfer;
this.transferredFileSize = transferredFileSize;
fileTransfer.addProgressListener(this);
}
@ -450,7 +422,7 @@ else if (sourceButton.equals(cancelButton))
*/
public void progressChanged(FileTransferProgressEvent event)
{
progressBar.setValue((int) event.getProgress());
progressBar.setValue((int)event.getProgress());
long transferredBytes = event.getFileTransfer().getTransferedBytes();
long progressTimestamp = event.getTimestamp();
@ -458,7 +430,8 @@ public void progressChanged(FileTransferProgressEvent event)
ByteFormat format = new ByteFormat();
String bytesString = format.format(transferredBytes);
if ((progressTimestamp - lastSpeedTimestamp) >= 5000)
if ((progressTimestamp - lastSpeedTimestamp)
>= SPEED_CALCULATE_DELAY)
{
lastProgressSpeed
= Math.round(calculateProgressSpeed(transferredBytes));
@ -467,12 +440,13 @@ public void progressChanged(FileTransferProgressEvent event)
this.lastTransferredBytes = transferredBytes;
}
if ((progressTimestamp - lastEstimatedTimeTimestamp) >= 5000
if ((progressTimestamp - lastEstimatedTimeTimestamp)
>= SPEED_CALCULATE_DELAY
&& lastProgressSpeed > 0)
{
lastEstimatedTime = Math.round(calculateEstimatedTransferTime(
lastProgressSpeed,
event.getFileTransfer().getFile().length() - transferredBytes));
transferredFileSize - transferredBytes));
lastEstimatedTimeTimestamp = progressTimestamp;
}
@ -483,7 +457,7 @@ public void progressChanged(FileTransferProgressEvent event)
{
progressSpeedLabel.setText(
resources.getI18NString("service.gui.SPEED")
+ format.format(lastProgressSpeed));
+ format.format(lastProgressSpeed) + "/sec");
progressSpeedLabel.setVisible(true);
}
@ -499,6 +473,7 @@ public void progressChanged(FileTransferProgressEvent event)
/**
* Returns the string, showing information for the given file.
*
*
* @param file the file
* @return the name of the given file
*/
@ -556,15 +531,17 @@ protected void hideProgressRelatedComponents()
*/
private double calculateProgressSpeed(long transferredBytes)
{
// Bytes per second = bytes per 5000 miliseconds * 1000.
return (transferredBytes - lastTransferredBytes) / 5;
// Bytes per second = bytes / SPEED_CALCULATE_DELAY miliseconds * 1000.
return (transferredBytes - lastTransferredBytes)
/ SPEED_CALCULATE_DELAY * 1000;
}
/**
* Returns the estimated transfer time left.
*
* @param speed
* @param fileSize
* @return
* @param speed the speed of the transfer
* @param fileSize the size of the file
* @return the estimated transfer time left
*/
private double calculateEstimatedTransferTime(double speed, long bytesLeft)
{

@ -10,6 +10,8 @@
import java.io.*;
import java.util.*;
import javax.swing.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.chat.*;
import net.java.sip.communicator.service.protocol.*;
@ -43,6 +45,8 @@ public class ReceiveFileConversationComponent
private final String dateString;
private File downloadFile;
/**
* Creates a <tt>ReceiveFileConversationComponent</tt>.
*
@ -63,6 +67,23 @@ public ReceiveFileConversationComponent(
fileTransferOpSet.addFileTransferListener(this);
byte[] thumbnail = request.getThumbnail();
if (thumbnail != null && thumbnail.length > 0)
{
ImageIcon thumbnailIcon = new ImageIcon(thumbnail);
if (thumbnailIcon.getIconWidth() > IMAGE_WIDTH
|| thumbnailIcon.getIconHeight() > IMAGE_HEIGHT)
{
thumbnailIcon
= ImageUtils.getScaledRoundedIcon(
thumbnail, IMAGE_WIDTH, IMAGE_WIDTH);
}
imageLabel.setIcon(thumbnailIcon);
}
titleLabel.setText(
dateString
+ resources.getI18NString(
@ -89,7 +110,7 @@ public void actionPerformed(ActionEvent e)
cancelButton.setVisible(true);
progressBar.setVisible(true);
File downloadFile = createFile(fileTransferRequest);
downloadFile = createFile(fileTransferRequest);
new AcceptFile(downloadFile).start();
}
@ -175,12 +196,20 @@ private File createFile(IncomingFileTransferRequest fileTransferRequest)
*/
public void statusChanged(FileTransferStatusChangeEvent event)
{
int status = event.getNewStatus();
FileTransfer fileTransfer = event.getFileTransfer();
int status = event.getNewStatus();
String fromContactName
= fileTransferRequest.getSender().getDisplayName();
if (status == FileTransferStatusChangeEvent.COMPLETED
|| status == FileTransferStatusChangeEvent.CANCELED
|| status == FileTransferStatusChangeEvent.FAILED
|| status == FileTransferStatusChangeEvent.REFUSED)
{
fileTransfer.removeStatusListener(this);
}
if (status == FileTransferStatusChangeEvent.PREPARING)
{
hideProgressRelatedComponents();
@ -219,7 +248,7 @@ else if (status == FileTransferStatusChangeEvent.IN_PROGRESS)
}
else if (status == FileTransferStatusChangeEvent.COMPLETED)
{
this.setCompletedDownloadFile(fileTransfer.getFile());
this.setCompletedDownloadFile(downloadFile);
hideProgressRelatedComponents();
cancelButton.setVisible(false);
@ -312,7 +341,7 @@ public void finished()
{
if (fileTransfer != null)
{
setFileTransfer(fileTransfer);
setFileTransfer(fileTransfer, fileTransferRequest.getFileSize());
}
}
}

@ -34,6 +34,8 @@ public class SendFileConversationComponent
private final String dateString;
private final File file;
/**
* Creates a <tt>SendFileConversationComponent</tt> by specifying the parent
* chat panel, where this component is added, the destination contact of
@ -49,6 +51,7 @@ public SendFileConversationComponent( ChatPanel chatPanel,
{
this.parentChatPanel = chatPanel;
this.toContactName = toContactName;
this.file = file;
// Create the date that would be shown in the component.
this.date = new Date();
@ -93,7 +96,7 @@ public void actionPerformed(ActionEvent e)
*/
public void setProtocolFileTransfer(FileTransfer fileTransfer)
{
this.setFileTransfer(fileTransfer);
this.setFileTransfer(fileTransfer, file.length());
fileTransfer.addStatusListener(this);
}
@ -104,8 +107,18 @@ public void setProtocolFileTransfer(FileTransfer fileTransfer)
*/
public void statusChanged(FileTransferStatusChangeEvent event)
{
FileTransfer fileTransfer = event.getFileTransfer();
int status = event.getNewStatus();
if (status == FileTransferStatusChangeEvent.COMPLETED
|| status == FileTransferStatusChangeEvent.CANCELED
|| status == FileTransferStatusChangeEvent.FAILED
|| status == FileTransferStatusChangeEvent.REFUSED)
{
parentChatPanel.removeActiveFileTransfer(fileTransfer.getID());
fileTransfer.removeStatusListener(this);
}
if (status == FileTransferStatusChangeEvent.PREPARING)
{
hideProgressRelatedComponents();
@ -153,8 +166,12 @@ else if (status == FileTransferStatusChangeEvent.COMPLETED)
+ resources.getI18NString(
"service.gui.FILE_SEND_COMPLETED",
new String[]{toContactName}));
cancelButton.setVisible(false);
retryButton.setVisible(false);
openFileButton.setVisible(true);
openFolderButton.setVisible(true);
}
else if (status == FileTransferStatusChangeEvent.CANCELED)
{

@ -18,7 +18,7 @@
import net.kano.joustsim.oscar.oscar.service.icbm.ft.state.*;
/**
* The Filetransfer imeplementation for icq.
* The Filetransfer imeplementation for ICQ.
* @author Damian Minkov
*/
public class FileTransferImpl
@ -90,22 +90,22 @@ public int getDirection()
}
/**
* Returns the file that is transfered.
*
* @return the file
* Returns the contact that we are transferring files with.
* @return the contact.
*/
public File getFile()
public Contact getContact()
{
return file;
return contact;
}
/**
* Returns the contact that we are transfering files with.
* @return the contact.
* Returns the local file that is being transferred or to which we transfer.
*
* @return the file
*/
public Contact getContact()
public File getLocalFile()
{
return contact;
return file;
}
/**

@ -212,5 +212,14 @@ public File getUnspecifiedFilename()
return file;
}
}
/**
* Returns the thumbnail contained in this request.
*
* @return the thumbnail contained in this request
*/
public byte[] getThumbnail()
{
return null;
}
}

@ -20,10 +20,11 @@
public class IncomingFileTransferJabberImpl
extends AbstractFileTransfer
{
private String id = null;
private final String id;
private Contact sender = null;
private File file = null;
private final Contact sender;
private final File file;
/**
* The Jabber incoming file transfer.
@ -33,9 +34,9 @@ public class IncomingFileTransferJabberImpl
/**
* Creates an <tt>IncomingFileTransferJabberImpl</tt>.
*
* @param id the identifier of this transfer
* @param sender the sender of the file
* @param file the file
* @param date the date on which the request was received
* @param jabberTransfer the Jabber file transfer object
*/
public IncomingFileTransferJabberImpl( String id,
@ -43,10 +44,10 @@ public IncomingFileTransferJabberImpl( String id,
File file,
IncomingFileTransfer jabberTransfer)
{
this.jabberTransfer = jabberTransfer;
this.id = id;
this.sender = sender;
this.file = file;
this.jabberTransfer = jabberTransfer;
}
/**
@ -77,16 +78,6 @@ public int getDirection()
return IN;
}
/**
* The file we are receiving.
*
* @return file we are receiving
*/
public File getFile()
{
return file;
}
/**
* Returns the sender of the file.
*
@ -106,4 +97,14 @@ public String getID()
{
return id;
}
/**
* Returns the local file that is being transferred or to which we transfer.
*
* @return the file
*/
public File getLocalFile()
{
return file;
}
}

@ -6,23 +6,26 @@
*/
package net.java.sip.communicator.impl.protocol.jabber;
import java.io.File;
import java.io.*;
import java.util.*;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.util.*;
import org.jivesoftware.smackx.filetransfer.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.thumbnail.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.FileTransfer;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.Logger;
import net.java.sip.communicator.util.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.filter.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.util.*;
import org.jivesoftware.smackx.filetransfer.*;
/**
* Jabber implementation of the incoming file transfer request
*
* @author Nicolas Riegel
*
* @author Yana Stamcheva
*/
public class IncomingFileTransferRequestJabberImpl
implements IncomingFileTransferRequest
@ -42,9 +45,13 @@ public class IncomingFileTransferRequestJabberImpl
private final OperationSetFileTransferJabberImpl fileTransferOpSet;
private final ProtocolProviderServiceJabberImpl jabberProvider;
private Contact sender;
private Date date;
private String thumbnailCid;
private byte[] thumbnail;
/**
* Creates an <tt>IncomingFileTransferRequestJabberImpl</tt> based on the
@ -53,17 +60,17 @@ public class IncomingFileTransferRequestJabberImpl
* @param jabberProvider the protocol provider
* @param fileTransferOpSet file transfer operation set
* @param fileTransferRequest the request coming from the Jabber protocol
* @param date the date on which this request was received
* @param thumbnailCid the content-ID used to match the thumbnail that
* would be send after this request is created.
*/
public IncomingFileTransferRequestJabberImpl(
ProtocolProviderServiceJabberImpl jabberProvider,
OperationSetFileTransferJabberImpl fileTransferOpSet,
FileTransferRequest fileTransferRequest,
Date date)
FileTransferRequest fileTransferRequest)
{
this.jabberProvider = jabberProvider;
this.fileTransferOpSet = fileTransferOpSet;
this.fileTransferRequest = fileTransferRequest;
this.date = date;
String fromUserID
= StringUtils.parseBareAddress(fileTransferRequest.getRequestor());
@ -163,7 +170,7 @@ public void rejectFile()
fileTransferRequest.reject();
fileTransferOpSet.fireFileTransferRequestRejected(
new FileTransferRequestEvent(fileTransferOpSet, this, this.date));
new FileTransferRequestEvent(fileTransferOpSet, this, new Date()));
}
/**
@ -174,4 +181,78 @@ public String getID()
{
return id;
}
/**
* Returns the thumbnail contained in this request.
*
* @return the thumbnail contained in this request
*/
public byte[] getThumbnail()
{
return thumbnail;
}
/**
* Sets the thumbnail content-ID.
* @param cid the thumbnail content-ID
*/
public void createThumbnailListeners(String cid)
{
this.thumbnailCid = cid;
if (jabberProvider.getConnection() != null)
{
jabberProvider.getConnection().addPacketListener(
new ThumbnailResponseListener(),
new AndFilter( new PacketTypeFilter(IQ.class),
new IQTypeFilter(IQ.Type.RESULT)));
}
}
/**
* The <tt>ThumbnailResponseListener</tt> listens for events triggered by
* the reception of a <tt>ThumbnailIQ</tt> packet. The packet is examined
* and a file transfer request event is fired when the thumbnail is
* extracted.
*/
private class ThumbnailResponseListener implements PacketListener
{
public void processPacket(Packet packet)
{
// If this is not an IQ packet, we're not interested.
if (!(packet instanceof ThumbnailIQ))
return;
logger.debug("Thumbnail response received.");
ThumbnailIQ thumbnailResponse = (ThumbnailIQ) packet;
if (thumbnailResponse.getCid() != null
&& thumbnailResponse.getCid().equals(thumbnailCid))
{
thumbnail = thumbnailResponse.getData();
// Create an event associated to this global request.
FileTransferRequestEvent fileTransferRequestEvent
= new FileTransferRequestEvent(
fileTransferOpSet,
IncomingFileTransferRequestJabberImpl.this,
new Date());
// Notify the global listener that a request has arrived.
fileTransferOpSet.fireFileTransferRequest(
fileTransferRequestEvent);
}
else
{
//TODO: RETURN <item-not-found/>
}
if (jabberProvider.getConnection() != null)
{
jabberProvider.getConnection()
.removePacketListener(this);
}
}
}
}

@ -10,6 +10,7 @@
import java.io.*;
import java.util.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.thumbnail.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.FileTransfer;
import net.java.sip.communicator.service.protocol.event.*;
@ -17,9 +18,12 @@
import net.java.sip.communicator.util.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.filter.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.*;
import org.jivesoftware.smackx.filetransfer.*;
import org.jivesoftware.smackx.filetransfer.FileTransfer.*;
import org.jivesoftware.smackx.packet.*;
/**
* The Jabber implementation of the <tt>OperationSetFileTransfer</tt>
@ -51,7 +55,7 @@ public class OperationSetFileTransferJabberImpl
/**
* The Jabber file transfer listener.
*/
private JabberFileTransferListener jabberFileTransferListener;
private FileTransferRequestListener fileTransferRequestListener;
/**
* A list of listeners registered for file transfer events.
@ -87,23 +91,33 @@ public OperationSetFileTransferJabberImpl(
public FileTransfer sendFile( Contact toContact,
File file)
throws IllegalStateException,
IllegalArgumentException
IllegalArgumentException,
OperationNotSupportedException
{
AbstractFileTransfer outgoingTransfer = null;
OutgoingFileTransferJabberImpl outgoingTransfer = null;
try
{
assertConnected();
Roster roster = jabberProvider.getConnection().getRoster();
Presence presence = roster.getPresence(toContact.getAddress());
String fullJid = jabberProvider.getFullJid(toContact);
// First we check if file transfer is at all supported for this
// contact.
if (!jabberProvider.isFeatureListSupported(fullJid,
new String[]{"http://jabber.org/protocol/si",
"http://jabber.org/protocol/si/profile/file-transfer"}))
{
new OperationNotSupportedException(
"Contact client or server does not support file transfers.");
}
OutgoingFileTransfer transfer
= manager.createOutgoingFileTransfer(presence.getFrom());
= manager.createOutgoingFileTransfer(fullJid);
outgoingTransfer
= new OutgoingFileTransferJabberImpl(
toContact, file, transfer);
toContact, file, transfer, jabberProvider);
// Notify all interested listeners that a file transfer has been
// created.
@ -113,7 +127,7 @@ public FileTransfer sendFile( Contact toContact,
fireFileTransferCreated(event);
// Send the file through the Jabber file transfer.
transfer.sendFile(file, "Sending file.");
transfer.sendFile(file, "Sending file");
// Start the status and progress thread.
new FileTransferProgressThread(
@ -144,7 +158,8 @@ public FileTransfer sendFile( Contact toContact,
String remotePath,
String localPath)
throws IllegalStateException,
IllegalArgumentException
IllegalArgumentException,
OperationNotSupportedException
{
return this.sendFile(toContact, new File(localPath));
}
@ -226,23 +241,46 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt)
manager = new FileTransferManager(
jabberProvider.getConnection());
// Create the Jabber file transfer listener.
jabberFileTransferListener = new JabberFileTransferListener();
fileTransferRequestListener = new FileTransferRequestListener();
ProviderManager.getInstance().addIQProvider(
FileElement.ELEMENT_NAME,
FileElement.NAMESPACE,
new FileElement());
ProviderManager.getInstance().addIQProvider(
ThumbnailIQ.ELEMENT_NAME,
ThumbnailIQ.NAMESPACE,
new ThumbnailIQ());
// Add the Jabber file transfer listener to the manager.
manager.addFileTransferListener(jabberFileTransferListener);
jabberProvider.getConnection().addPacketListener(
fileTransferRequestListener,
new AndFilter( new PacketTypeFilter(StreamInitiation.class),
new IQTypeFilter(IQ.Type.SET)));
}
else if (evt.getNewState() == RegistrationState.UNREGISTERED)
{
if(jabberFileTransferListener != null
&& manager != null)
if(fileTransferRequestListener != null
&& jabberProvider.getConnection() != null)
{
manager.removeFileTransferListener(
jabberFileTransferListener);
jabberProvider.getConnection().removePacketListener(
fileTransferRequestListener);
}
ProviderManager providerManager = ProviderManager.getInstance();
if (providerManager != null)
{
ProviderManager.getInstance().removeIQProvider(
FileElement.ELEMENT_NAME,
FileElement.NAMESPACE);
manager = null;
jabberFileTransferListener = null;
ProviderManager.getInstance().removeIQProvider(
ThumbnailIQ.ELEMENT_NAME,
ThumbnailIQ.NAMESPACE);
}
fileTransferRequestListener = null;
manager = null;
}
}
}
@ -250,36 +288,69 @@ else if (evt.getNewState() == RegistrationState.UNREGISTERED)
/**
* Listener for Jabber incoming file transfer requests.
*/
private class JabberFileTransferListener
implements org.jivesoftware.smackx.filetransfer.FileTransferListener
private class FileTransferRequestListener implements PacketListener
{
/**
* Function called when a jabber file transfer request arrive.
*/
public void fileTransferRequest(FileTransferRequest request)
public void processPacket(Packet packet)
{
logger.debug("Incoming Jabber file transfer request.");
if (!(packet instanceof StreamInitiation))
return;
logger.debug("Incoming Jabber file transfer request.");
// Create the date on which the request was received.
Date requestDate = new Date();
StreamInitiation streamInitiation = (StreamInitiation) packet;
FileTransferRequest jabberRequest
= new FileTransferRequest(manager, streamInitiation);
// Create a global incoming file transfer request.
IncomingFileTransferRequest incomingFileTransferRequest
IncomingFileTransferRequestJabberImpl incomingFileTransferRequest
= new IncomingFileTransferRequestJabberImpl(
jabberProvider,
OperationSetFileTransferJabberImpl.this,
request,
requestDate);
// Create an event associated to this global request.
FileTransferRequestEvent fileTransferRequestEvent
= new FileTransferRequestEvent(
OperationSetFileTransferJabberImpl.this,
incomingFileTransferRequest,
requestDate);
// Notify the global listener that a request has arrived.
fireFileTransferRequest(fileTransferRequestEvent);
jabberRequest);
// Send a thumbnail request if a thumbnail is advertised in the
// streamInitiation packet.
org.jivesoftware.smackx.packet.StreamInitiation.File file
= streamInitiation.getFile();
boolean isThumbnailedFile = false;
if (file instanceof FileElement)
{
ThumbnailElement thumbnailElement
= ((FileElement) file).getThumbnailElement();
if (thumbnailElement != null)
{
isThumbnailedFile = true;
incomingFileTransferRequest
.createThumbnailListeners(thumbnailElement.getCid());
ThumbnailIQ thumbnailRequest
= new ThumbnailIQ( streamInitiation.getTo(),
streamInitiation.getFrom(),
thumbnailElement.getCid(),
IQ.Type.GET);
logger.debug("Sending thumbnail request:"
+ thumbnailRequest.toXML());
jabberProvider.getConnection().sendPacket(thumbnailRequest);
}
}
if (!isThumbnailedFile)
{
// Create an event associated to this global request.
FileTransferRequestEvent fileTransferRequestEvent
= new FileTransferRequestEvent(
OperationSetFileTransferJabberImpl.this,
incomingFileTransferRequest,
new Date());
// Notify the global listener that a request has arrived.
fireFileTransferRequest(fileTransferRequestEvent);
}
}
}
@ -289,7 +360,7 @@ public void fileTransferRequest(FileTransferRequest request)
* @param event the <tt>EventObject</tt> that we'd like delivered to all
* registered file transfer listeners.
*/
private void fireFileTransferRequest(FileTransferRequestEvent event)
void fireFileTransferRequest(FileTransferRequestEvent event)
{
Iterator<FileTransferListener> listeners = null;
synchronized (fileTransferListeners)
@ -386,6 +457,7 @@ public void run()
{
int status;
long progress;
String statusReason = "";
while (true)
{
@ -401,10 +473,17 @@ public void run()
|| status == FileTransferStatusChangeEvent.CANCELED
|| status == FileTransferStatusChangeEvent.REFUSED)
{
if (fileTransfer instanceof
OutgoingFileTransferJabberImpl)
{
((OutgoingFileTransferJabberImpl) fileTransfer)
.removeThumbnailRequestListener();
}
break;
}
fileTransfer.fireStatusChangeEvent(status);
fileTransfer.fireStatusChangeEvent(status, "Status changed");
fileTransfer.fireProgressChangeEvent(
System.currentTimeMillis(), progress);
}
@ -414,6 +493,20 @@ public void run()
}
}
if (jabberTransfer.getError() != null)
{
logger.error("An error occured while transfering file: "
+ jabberTransfer.getError().getMessage());
}
if (jabberTransfer.getException() != null)
{
logger.error("An exception occured while transfering file: ",
jabberTransfer.getException());
statusReason = jabberTransfer.getException().getMessage();
}
if (initialFileSize > 0
&& status == FileTransferStatusChangeEvent.COMPLETED
&& fileTransfer.getTransferedBytes() < initialFileSize)
@ -421,7 +514,7 @@ public void run()
status = FileTransferStatusChangeEvent.CANCELED;
}
fileTransfer.fireStatusChangeEvent(status);
fileTransfer.fireStatusChangeEvent(status, statusReason);
fileTransfer.fireProgressChangeEvent(
System.currentTimeMillis(), progress);
}

@ -0,0 +1,44 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber;
import java.io.*;
import net.java.sip.communicator.service.protocol.*;
/**
* The <tt>OperationSetThumbnailedFileFactory</tt> is meant to be used by
* bundles interested in making files with thumbnails. For example the user
* interface can be interested in sending files with thumbnails through the
* <tt>OperationSetFileTransfer</tt>.
*
* @author Yana Stamcheva
*/
public class OperationSetThumbnailedFileFactoryImpl
implements OperationSetThumbnailedFileFactory
{
/**
* Creates a file, by attaching the thumbnail, given by the details, to it.
*
* @param file the base file
* @param thumbnailWidth the width of the thumbnail
* @param thumbnailHeight the height of the thumbnail
* @param thumbnailMimeType the mime type of the thumbnail
* @param thumbnail the thumbnail data
* @return a file with a thumbnail
*/
public File createFileWithThumbnail(File file,
int thumbnailWidth,
int thumbnailHeight,
String thumbnailMimeType,
byte[] thumbnail)
{
return new ThumbnailedFile(
file, thumbnailWidth, thumbnailHeight,
thumbnailMimeType, thumbnail);
}
}

@ -8,9 +8,16 @@
import java.io.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.thumbnail.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.filter.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.util.*;
import org.jivesoftware.smackx.filetransfer.*;
import org.jivesoftware.smackx.packet.*;
/**
* The Jabber protocol extension of the <tt>AbstractFileTransfer</tt>.
@ -19,35 +26,73 @@
*/
public class OutgoingFileTransferJabberImpl
extends AbstractFileTransfer
implements PacketInterceptor
{
private String id;
private final Logger logger
= Logger.getLogger(OutgoingFileTransferJabberImpl.class);
private Contact receiver;
private final String id;
private File file;
private final Contact receiver;
private final File file;
private ThumbnailElement thumbnailElement;
private final ThumbnailRequestListener thumbnailRequestListener
= new ThumbnailRequestListener();
/**
* The jabber outgoing file transfer.
*/
private OutgoingFileTransfer jabberTransfer;
private final OutgoingFileTransfer jabberTransfer;
private final ProtocolProviderServiceJabberImpl protocolProvider;
/**
* Creates an <tt>OutgoingFileTransferJabberImpl</tt> by specifying the
* Jabber transfer object.
*
* <tt>receiver</tt> contact, the <tt>file</tt>, the <tt>jabberTransfer</tt>,
* that would be used to send the file through Jabber and the
* <tt>protocolProvider</tt>.
*
* @param receiver the destination contact
* @param file the file to send
* @param jabberTransfer the Jabber transfer object, containing all transfer
* information
* @param protocolProvider the parent protocol provider
*/
public OutgoingFileTransferJabberImpl( Contact receiver,
File file,
OutgoingFileTransfer jabberTransfer)
public OutgoingFileTransferJabberImpl(
Contact receiver,
File file,
OutgoingFileTransfer jabberTransfer,
ProtocolProviderServiceJabberImpl protocolProvider)
{
this.jabberTransfer = jabberTransfer;
this.receiver = receiver;
this.file = file;
this.jabberTransfer = jabberTransfer;
this.protocolProvider = protocolProvider;
this.id = String.valueOf( System.currentTimeMillis())
// Create the identifier of this file transfer that is used from the
// history and the user interface to track this transfer.
this.id = String.valueOf(System.currentTimeMillis())
+ String.valueOf(hashCode());
// Add this outgoing transfer as a packet interceptor in
// order to manage thumbnails.
if (file instanceof ThumbnailedFile
&& ((ThumbnailedFile) file).getThumbnailData() != null
&& ((ThumbnailedFile) file).getThumbnailData().length > 0)
{
if (protocolProvider.isFeatureListSupported(
protocolProvider.getFullJid(receiver),
new String[]{"urn:xmpp:thumbs:0",
"urn:xmpp:bob"}))
{
protocolProvider.getConnection().addPacketWriterInterceptor(
this,
new IQTypeFilter(IQ.Type.SET));
}
}
}
/**
@ -78,10 +123,11 @@ public int getDirection()
}
/**
* The file we are sending.
* @return the file.
* Returns the local file that is being transferred or to which we transfer.
*
* @return the file
*/
public File getFile()
public File getLocalFile()
{
return file;
}
@ -103,4 +149,115 @@ public String getID()
{
return id;
}
/**
* Removes previously added thumbnail request listener.
*/
public void removeThumbnailRequestListener()
{
protocolProvider.getConnection()
.removePacketListener(thumbnailRequestListener);
}
/**
* Listens for all <tt>StreamInitiation</tt> packets and adds a thumbnail
* to them if a thumbnailed file is supported.
*
* @see PacketInterceptor#interceptPacket(Packet)
*/
public void interceptPacket(Packet packet)
{
if (!(packet instanceof StreamInitiation))
return;
// If our file is not a thumbnailed file we have nothing to do here.
if (!(file instanceof ThumbnailedFile))
return;
logger.debug("File transfer packet intercepted"
+ " in order to add thumbnail.");
StreamInitiation fileTransferPacket = (StreamInitiation) packet;
ThumbnailedFile thumbnailedFile = (ThumbnailedFile) file;
if (jabberTransfer.getStreamID()
.equals(fileTransferPacket.getSessionID()))
{
StreamInitiation.File file = fileTransferPacket.getFile();
thumbnailElement = new ThumbnailElement(
StringUtils.parseServer(fileTransferPacket.getTo()),
thumbnailedFile.getThumbnailData(),
thumbnailedFile.getThumbnailMimeType(),
thumbnailedFile.getThumbnailWidth(),
thumbnailedFile.getThumbnailHeight());
FileElement fileElement = new FileElement(file, thumbnailElement);
fileTransferPacket.setFile(fileElement);
logger.debug("The file transfer packet with thumbnail: "
+ fileTransferPacket.toXML());
// Add the request listener in order to listen for requests coming
// for the advertised thumbnail.
if (protocolProvider.getConnection() != null)
{
protocolProvider.getConnection().addPacketListener(
thumbnailRequestListener,
new AndFilter( new PacketTypeFilter(IQ.class),
new IQTypeFilter(IQ.Type.GET)));
}
}
// Remove this packet interceptor after we're done.
protocolProvider.getConnection().removePacketWriterInterceptor(this);
}
/**
* The <tt>ThumbnailRequestListener</tt> listens for events triggered by
* the reception of a <tt>ThumbnailIQ</tt> packet. The packet is examined
* and a <tt>ThumbnailIQ</tt> is created to respond to the thumbnail
* request received.
*/
private class ThumbnailRequestListener implements PacketListener
{
public void processPacket(Packet packet)
{
// If this is not an IQ packet, we're not interested.
if (!(packet instanceof ThumbnailIQ))
return;
ThumbnailIQ thumbnailIQ = (ThumbnailIQ) packet;
if (thumbnailIQ.getCid() != null
&& thumbnailIQ.getCid().equals(thumbnailElement.getCid()))
{
ThumbnailedFile thumbnailedFile = (ThumbnailedFile) file;
ThumbnailIQ thumbnailResponse = new ThumbnailIQ(
thumbnailIQ.getTo(),
thumbnailIQ.getFrom(),
thumbnailIQ.getCid(),
thumbnailedFile.getThumbnailMimeType(),
thumbnailedFile.getThumbnailData(),
IQ.Type.RESULT);
logger.debug("Send thumbnail response to the receiver: "
+ thumbnailResponse.toXML());
protocolProvider.getConnection()
.sendPacket(thumbnailResponse);
}
else
{
// RETURN <item-not-found/>
}
if (protocolProvider.getConnection() != null)
{
protocolProvider.getConnection().removePacketListener(this);
}
}
}
}

@ -16,8 +16,10 @@
import net.java.sip.communicator.util.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.util.*;
import org.jivesoftware.smackx.*;
import org.jivesoftware.smackx.packet.*;
/**
* An implementation of the protocol provider service over the Jabber protocol
@ -25,6 +27,7 @@
* @author Damian Minkov
* @author Symphorien Wanko
* @author Lubomir Marinov
* @author Yana Stamcheva
*/
public class ProtocolProviderServiceJabberImpl
extends AbstractProtocolProviderService
@ -427,15 +430,37 @@ private synchronized void connectAndLogin(SecurityAuthority authority,
}
// we setup supported features
// List of features that smack already supports:
// http://jabber.org/protocol/xhtml-im
// http://jabber.org/protocol/muc
// http://jabber.org/protocol/commands
// http://jabber.org/protocol/chatstates
// http://jabber.org/protocol/si/profile/file-transfer
// http://jabber.org/protocol/si
// http://jabber.org/protocol/bytestreams
// http://jabber.org/protocol/ibb
if (getRegistrationState() == RegistrationState.REGISTERED)
{
discoveryManager = ServiceDiscoveryManager.
getInstanceFor(connection);
ServiceDiscoveryManager.setIdentityName("sip-comm");
ServiceDiscoveryManager.setIdentityType("registered");
ServiceDiscoveryManager.setIdentityType("pc");
Iterator<String> it = supportedFeatures.iterator();
// Remove features supported by smack, but not supported in
// SIP Communicator.
discoveryManager.removeFeature(
"http://jabber.org/protocol/commands");
// Add features the SIP Communicator supports in plus of smack.
while (it.hasNext())
discoveryManager.addFeature(it.next());
{
String feature = it.next();
if (!discoveryManager.includesFeature(feature))
discoveryManager.addFeature(feature);
}
}
}
@ -547,7 +572,6 @@ protected void initialize(String screenname,
// presence, if someone knows
// supportedFeatures.add(_PRESENCE_);
//register it once again for those that simply need presence
supportedOperationSets.put( OperationSetPresence.class.getName(),
persistentPresence);
@ -564,11 +588,8 @@ protected void initialize(String screenname,
OperationSetBasicInstantMessaging.class.getName(),
basicInstantMessaging);
// TODO: add the feature, if any, corresponding to IM if someone
// knows
// supportedFeatures.add(_IM_);
//XHTML-IM
supportedFeatures.add("http://jabber.org/protocol/xhtml-im");
// The http://jabber.org/protocol/xhtml-im feature is included
// already in smack.
//initialize the Whiteboard operation set
OperationSetWhiteboardingJabberImpl whiteboard =
@ -584,7 +605,9 @@ protected void initialize(String screenname,
supportedOperationSets.put(
OperationSetTypingNotifications.class.getName(),
typingNotifications);
supportedFeatures.add("http://jabber.org/protocol/chatstates");
// The http://jabber.org/protocol/chatstates feature implemented in
// OperationSetTypingNotifications is included already in smack.
//initialize the multi user chat operation set
OperationSetMultiUserChat multiUserChat =
@ -619,11 +642,30 @@ protected void initialize(String screenname,
OperationSetFileTransfer.class.getName(),
fileTransfer);
// Include features we're supporting in plus of the four that
// included by smack itself:
// http://jabber.org/protocol/si/profile/file-transfer
// http://jabber.org/protocol/si
// http://jabber.org/protocol/bytestreams
// http://jabber.org/protocol/ibb
supportedFeatures.add("urn:xmpp:thumbs:0");
supportedFeatures.add("urn:xmpp:bob");
// initialize the thumbnailed file factory operation set
OperationSetThumbnailedFileFactory thumbnailFactory
= new OperationSetThumbnailedFileFactoryImpl();
supportedOperationSets.put(
OperationSetThumbnailedFileFactory.class.getName(),
thumbnailFactory);
// TODO: this is the "main" feature to advertise when a client
// support muc. We have to add some features for
// specific functionnality we support in muc.
// specific functionality we support in muc.
// see http://www.xmpp.org/extensions/xep-0045.html
supportedFeatures.add("http://jabber.org/protocol/muc");
// The http://jabber.org/protocol/muc feature is already included in
// smack.
supportedFeatures.add("http://jabber.org/protocol/muc#rooms");
supportedFeatures.add("http://jabber.org/protocol/muc#traffic");
@ -642,6 +684,7 @@ protected void initialize(String screenname,
OperationSetBasicTelephony.class.getName(),
opSetBasicTelephony);
// Add Jingle features to supported features.
supportedFeatures.add("urn:xmpp:jingle:1");
supportedFeatures.add("urn:xmpp:jingle:apps:rtp:1");
supportedFeatures.add("urn:xmpp:jingle:apps:rtp:audio");
@ -727,7 +770,8 @@ private class JabberConnectionListener
public void connectionClosed()
{
OperationSetPersistentPresenceJabberImpl opSetPersPresence =
(OperationSetPersistentPresenceJabberImpl) getOperationSet(OperationSetPersistentPresence.class);
(OperationSetPersistentPresenceJabberImpl)
getOperationSet(OperationSetPersistentPresence.class);
opSetPersPresence.fireProviderStatusChangeEvent(
opSetPersPresence.getPresenceStatus(),
@ -799,4 +843,54 @@ JabberStatusEnum getJabberStatusEnum()
{
return jabberStatusEnum;
}
/**
* Checks if the given list of <tt>features</tt> is supported by the given
* jabber id.
* @param jid the jabber id for which to check
* @param features the list of features to check for
* @return <code>true</code> if the list of features is supported, otherwise
* returns <code>false</code>
*/
boolean isFeatureListSupported(String jid, String[] features)
{
boolean isFeatureListSupported = true;
ServiceDiscoveryManager disco = ServiceDiscoveryManager
.getInstanceFor(getConnection());
try
{
DiscoverInfo featureInfo = disco.discoverInfo(jid);
for (String feature : features)
{
if (!featureInfo.containsFeature(feature))
{
// If one is not supported we return false and don't check
// the others.
isFeatureListSupported = false;
break;
}
}
}
catch (XMPPException e)
{
logger.debug("Failed to discover info.", e);
}
return isFeatureListSupported;
}
/**
* Returns the full jabber id (jid) corresponding to the given contact.
* @param contact the contact, for which we're looking for a jid
* @return the jid
*/
String getFullJid(Contact contact)
{
Roster roster = getConnection().getRoster();
Presence presence = roster.getPresence(contact.getAddress());
return presence.getFrom();
}
}

@ -0,0 +1,86 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber;
import java.io.*;
/**
* A <tt>ThumbnailedFile</tt> is a file with a thumbnail.
*
* @author Yana Stamcheva
*/
public class ThumbnailedFile
extends File
{
private final int thumbnailWidth;
private final int thumbnailHeight;
private final String thumbnailMimeType;
private final byte[] thumbnail;
/**
* Creates a <tt>ThumbnailedFile</tt>, by specifying the base <tt>file</tt>,
* the <tt>thumbnailWidth</tt> and <tt>thumbnailHeight</tt>, the
* <tt>thumbnailMimeType</tt> and the <tt>thumbnail</tt> itself.
* @param file the base file
* @param thumbnailWidth the width of the thumbnail
* @param thumbnailHeight the height of the thumbnail
* @param thumbnailMimeType the mime type
* @param thumbnail the thumbnail
*/
public ThumbnailedFile( File file,
int thumbnailWidth,
int thumbnailHeight,
String thumbnailMimeType,
byte[] thumbnail)
{
super(file.getPath());
this.thumbnailWidth = thumbnailWidth;
this.thumbnailHeight = thumbnailHeight;
this.thumbnailMimeType = thumbnailMimeType;
this.thumbnail = thumbnail;
}
/**
* Returns the thumbnail of this file.
* @return the thumbnail of this file
*/
public byte[] getThumbnailData()
{
return thumbnail;
}
/**
* Returns the thumbnail width.
* @return the thumbnail width
*/
public int getThumbnailWidth()
{
return thumbnailWidth;
}
/**
* Returns the thumbnail height.
* @return the thumbnail height
*/
public int getThumbnailHeight()
{
return thumbnailHeight;
}
/**
* Returns the thumbnail mime type.
* @return the thumbnail mime type
*/
public String getThumbnailMimeType()
{
return thumbnailMimeType;
}
}

@ -241,7 +241,7 @@ public class GeolocationPacketExtension
private String timestamp = null;
/**
* Returns the XML reppresentation of the PacketExtension.
* Returns the XML representation of the PacketExtension.
*
* @return the packet extension as XML.
* @todo Implement this org.jivesoftware.smack.packet.PacketExtension

@ -0,0 +1,269 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.thumbnail;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.*;
import org.jivesoftware.smack.util.*;
import org.jivesoftware.smackx.packet.*;
import org.jivesoftware.smackx.packet.StreamInitiation.*;
import org.jivesoftware.smackx.provider.*;
import org.xmlpull.v1.*;
/**
* The <tt>FileElement</tt> extends the smackx <tt>StreamInitiation.File</tt>
* in order to provide a file that supports thumbnails.
*
* @author Yana Stamcheva
*/
public class FileElement
extends File
implements IQProvider
{
private ThumbnailElement thumbnail;
/**
* The element name of this <tt>IQProvider</tt>.
*/
public static final String ELEMENT_NAME = "si";
/**
* The namespace of this <tt>IQProvider</tt>.
*/
public static final String NAMESPACE = "http://jabber.org/protocol/si";
/**
* An empty constructor used to initialize this class as an
* <tt>IQProvider</tt>.
*/
public FileElement()
{
this("", 0);
}
/**
* Creates a <tt>FileElement</tt> by specifying a base file and a thumbnail
* to extend it with.
*
* @param baseFile the file used as a base
* @param thumbnail the thumbnail to add
*/
public FileElement(File baseFile, ThumbnailElement thumbnail)
{
this(baseFile.getName(), baseFile.getSize());
this.thumbnail = thumbnail;
}
/**
* Creates a <tt>FileElement</tt> by specifying the name and the size of the
* file.
*
* @param name the name of the file
* @param size the size of the file
*/
public FileElement(String name, long size)
{
super(name, size);
}
/**
* Represents this <tt>FileElement</tt> in an XML.
*
* @see File#toXML()
*/
public String toXML()
{
StringBuilder buffer = new StringBuilder();
buffer.append("<").append(getElementName()).append(" xmlns=\"")
.append(getNamespace()).append("\" ");
if (getName() != null)
{
buffer.append("name=\"").append(
StringUtils.escapeForXML(getName())).append("\" ");
}
if (getSize() > 0)
{
buffer.append("size=\"").append(getSize()).append("\" ");
}
if (getDate() != null)
{
buffer.append("date=\"").append(
DelayInformation.UTC_FORMAT
.format(this.getDate())).append("\" ");
}
if (getHash() != null)
{
buffer.append("hash=\"").append(getHash()).append("\" ");
}
if ((this.getDesc() != null && getDesc().length() > 0)
|| isRanged()
|| thumbnail != null)
{
buffer.append(">");
if (getDesc() != null && getDesc().length() > 0)
{
buffer.append("<desc>").append(
StringUtils.escapeForXML(getDesc())).append("</desc>");
}
if (isRanged())
{
buffer.append("<range/>");
}
if (thumbnail != null)
{
buffer.append(thumbnail.toXML());
}
buffer.append("</").append(getElementName()).append(">");
}
else
{
buffer.append("/>");
}
return buffer.toString();
}
/**
* Returns the <tt>ThumbnailElement</tt> contained in this
* <tt>FileElement</tt>.
* @return the <tt>ThumbnailElement</tt> contained in this
* <tt>FileElement</tt>
*/
public ThumbnailElement getThumbnailElement()
{
return thumbnail;
}
/**
* Sets the given <tt>thumbnail</tt> to this <tt>FileElement</tt>.
* @param thumbnail the <tt>ThumbnailElement</tt> to set
*/
public void setThumbnailElement(ThumbnailElement thumbnail)
{
this.thumbnail = thumbnail;
}
/**
* Parses the given <tt>parser</tt> in order to create a
* <tt>FileElement</tt> from it.
* @param parser the parser to parse
* @see IQProvider#parseIQ(XmlPullParser)
*/
public IQ parseIQ(final XmlPullParser parser)
throws Exception
{
boolean done = false;
// si
String id = parser.getAttributeValue("", "id");
String mimeType = parser.getAttributeValue("", "mime-type");
StreamInitiation initiation = new StreamInitiation();
// file
String name = null;
String size = null;
String hash = null;
String date = null;
String desc = null;
ThumbnailElement thumbnail = null;
boolean isRanged = false;
// feature
DataForm form = null;
DataFormProvider dataFormProvider = new DataFormProvider();
int eventType;
String elementName;
String namespace;
while (!done)
{
eventType = parser.next();
elementName = parser.getName();
namespace = parser.getNamespace();
if (eventType == XmlPullParser.START_TAG)
{
if (elementName.equals("file"))
{
name = parser.getAttributeValue("", "name");
size = parser.getAttributeValue("", "size");
hash = parser.getAttributeValue("", "hash");
date = parser.getAttributeValue("", "date");
}
else if (elementName.equals("desc"))
{
desc = parser.nextText();
}
else if (elementName.equals("range"))
{
isRanged = true;
}
else if (elementName.equals("x")
&& namespace.equals("jabber:x:data"))
{
form = (DataForm) dataFormProvider.parseExtension(parser);
}
else if (elementName.equals("thumbnail"))
{
thumbnail = new ThumbnailElement(parser.getText());
}
}
else if (eventType == XmlPullParser.END_TAG)
{
if (elementName.equals("si"))
done = true;
else if (elementName.equals("file"))
{
long fileSize = 0;
if(size != null && size.trim().length() !=0)
{
try
{
fileSize = Long.parseLong(size);
}
catch (NumberFormatException e)
{
e.printStackTrace();
}
}
FileElement file = new FileElement(name, fileSize);
file.setHash(hash);
if (date != null)
file.setDate(DelayInformation.UTC_FORMAT.parse(date));
if (thumbnail != null)
file.setThumbnailElement(thumbnail);
file.setDesc(desc);
file.setRanged(isRanged);
initiation.setFile(file);
}
}
}
initiation.setSesssionID(id);
initiation.setMimeType(mimeType);
initiation.setFeatureNegotiationForm(form);
return initiation;
}
}

@ -0,0 +1,298 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.thumbnail;
import java.io.*;
import java.security.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import net.java.sip.communicator.util.*;
/**
* The <tt>ThumbnailElement</tt> represents a "thumbnail" XML element, that is
* contained in the file element, we're sending to notify for a file transfer.
* The <tt>ThumbnailElement</tt>'s role is to advertise a thumbnail.
*
* @author Yana Stamcheva
*/
public class ThumbnailElement
{
private static final Logger logger
= Logger.getLogger(ThumbnailElement.class);
/**
* The name of the XML element used for transport of thumbnail parameters.
*/
public static final String ELEMENT_NAME = "thumbnail";
/**
* The names XMPP space that the thumbnail elements belong to.
*/
public static final String NAMESPACE = "urn:xmpp:thumbs:0";
/**
* The name of the thumbnail attribute "cid".
*/
public final static String CID = "cid";
/**
* The name of the thumbnail attribute "mime-type".
*/
public final static String MIME_TYPE = "mime-type";
/**
* The name of the thumbnail attribute "width".
*/
public final static String WIDTH = "width";
/**
* The name of the thumbnail attribute "height".
*/
public final static String HEIGHT = "height";
private String cid;
private String mimeType;
private int width;
private int height;
/**
* Creates a <tt>ThumbnailPacketExtension</tt> by specifying all extension
* attributes.
*
* @param serverAddress the Jabber address of the destination contact
* @param thumbnailData the byte array containing the thumbnail data
* @param mimeType the mime type attribute
* @param width the width of the thumbnail
* @param height the height of the thumbnail
*/
public ThumbnailElement(String serverAddress,
byte[] thumbnailData,
String mimeType,
int width,
int height)
{
this.cid = createCid(serverAddress, thumbnailData);
this.mimeType = mimeType;
this.width = width;
this.height = height;
}
/**
* Creates a <tt>ThumbnailElement</tt> by parsing the given <tt>xml</tt>.
*
* @param xml the XML from which we obtain the needed information to create
* this <tt>ThumbnailElement</tt>
*/
public ThumbnailElement(String xml)
{
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try
{
builder = factory.newDocumentBuilder();
InputStream in = new ByteArrayInputStream (xml.getBytes());
Document doc = builder.parse(in);
Element e = doc.getDocumentElement();
String elementName = e.getNodeName();
if (elementName.equals (ELEMENT_NAME))
{
this.setCid(e.getAttribute (CID));
this.setMimeType(e.getAttribute(MIME_TYPE));
this.setHeight(Integer.parseInt(e.getAttribute(HEIGHT)));
this.setHeight(Integer.parseInt(e.getAttribute(WIDTH)));
}
else
logger.debug ("Element name unknown!");
}
catch (ParserConfigurationException ex)
{
logger.debug ("Problem parsing Thumbnail Element : " + xml, ex);
}
catch (IOException ex)
{
logger.debug ("Problem parsing Thumbnail Element : " + xml, ex);
}
catch (Exception ex)
{
logger.debug ("Problem parsing Thumbnail Element : " + xml, ex);
}
}
/**
* Returns the XML representation of this PacketExtension.
*
* @return the packet extension as XML.
*/
public String toXML()
{
StringBuffer buf = new StringBuffer();
// open element
buf.append("<").append(ELEMENT_NAME).
append(" xmlns=\"").append(NAMESPACE).append("\"");
// adding thumbnail parameters
buf = addXmlAttribute(buf, CID, this.getCid());
buf = addXmlAttribute(buf, MIME_TYPE, this.getMimeType());
buf = addXmlIntAttribute(buf, WIDTH, this.getWidth());
buf = addXmlIntAttribute(buf, HEIGHT, this.getWidth());
// close element
buf.append("/>");
return buf.toString();
}
/**
* Returns the Content-ID, corresponding to this <tt>ThumbnailElement</tt>.
* @return the Content-ID, corresponding to this <tt>ThumbnailElement</tt>
*/
public String getCid()
{
return cid;
}
/**
* Returns the mime type of this <tt>ThumbnailElement</tt>.
* @return the mime type of this <tt>ThumbnailElement</tt>
*/
public String getMimeType()
{
return mimeType;
}
/**
* Returns the width of this <tt>ThumbnailElement</tt>.
* @return the width of this <tt>ThumbnailElement</tt>
*/
public int getWidth()
{
return width;
}
/**
* Returns the height of this <tt>ThumbnailElement</tt>.
* @return the height of this <tt>ThumbnailElement</tt>
*/
public int getHeight()
{
return height;
}
/**
* Sets the content-ID of this <tt>ThumbnailElement</tt>.
* @param cid the content-ID to set
*/
public void setCid(String cid)
{
this.cid = cid;
}
/**
* Sets the mime type of the thumbnail.
* @param mimeType the mime type of the thumbnail
*/
public void setMimeType(String mimeType)
{
this.mimeType = mimeType;
}
/**
* Sets the width of the thumbnail
* @param width the width of the thumbnail
*/
public void setWidth(int width)
{
this.width = width;
}
/**
* Sets the height of the thumbnail
* @param height the height of the thumbnail
*/
public void setHeight(int height)
{
this.height = height;
}
/**
* Creates the XML <tt>String</tt> corresponding to the specified attribute
* and value and adds them to the <tt>buff</tt> StringBuffer.
*
* @param buff the <tt>StringBuffer</tt> to add the attribute and value to.
* @param attrName the name of the thumbnail attribute that we're adding.
* @param attrValue the value of the attribute we're adding to the XML
* buffer.
* @return the <tt>StringBuffer</tt> that we've added the attribute and its
* value to.
*/
private StringBuffer addXmlAttribute( StringBuffer buff,
String attrName,
String attrValue)
{
buff.append(" " + attrName + "=\"").append(attrValue).append("\"");
return buff;
}
/**
* Creates the XML <tt>String</tt> corresponding to the specified attribute
* and value and adds them to the <tt>buff</tt> StringBuffer.
*
* @param buff the <tt>StringBuffer</tt> to add the attribute and value to.
* @param attrName the name of the thumbnail attribute that we're adding.
* @param attrValue the value of the attribute we're adding to the XML
* buffer.
* @return the <tt>StringBuffer</tt> that we've added the attribute and its
* value to.
*/
private StringBuffer addXmlIntAttribute(StringBuffer buff,
String attrName,
int attrValue)
{
return addXmlAttribute(buff, attrName, String.valueOf(attrValue));
}
/**
* Creates the cid attrubte value for the given <tt>contactJabberAddress</tt>
* and <tt>thumbnailData</tt>.
*
* @param serverAddress the Jabber server address
* @param thumbnailData the byte array containing the data
* @return the cid attrubte value for the thumbnail extension
*/
private String createCid( String serverAddress,
byte[] thumbnailData)
{
try
{
return "sha1+" + Sha1Crypto.encode(thumbnailData)
+ "@" + serverAddress;
}
catch (NoSuchAlgorithmException e)
{
logger.debug("Failed to encode the thumbnail in SHA-1.", e);
}
catch (UnsupportedEncodingException e)
{
logger.debug("Failed to encode the thumbnail in SHA-1.", e);
}
return null;
}
}

@ -0,0 +1,171 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.thumbnail;
import net.java.sip.communicator.util.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.*;
import org.xmlpull.v1.*;
/**
* The <tt>ThumbnailIQ</tt> is an IQ packet that is meant to be used for
* thumbnail requests and responses.
*
* @author Yana Stamcheva
*/
public class ThumbnailIQ
extends IQ
implements IQProvider
{
/**
* The names XMPP space that the thumbnail elements belong to.
*/
public static final String NAMESPACE = "urn:xmpp:bob";
/**
* The name of the "data" element.
*/
public static final String ELEMENT_NAME = "data";
/**
* The name of the thumbnail attribute "cid".
*/
public final static String CID = "cid";
/**
* The name of the thumbnail attribute "mime-type".
*/
public final static String TYPE = "type";
private String cid;
private String mimeType;
private byte[] data;
/**
* An empty constructor used to initialize this class as an
* <tt>IQProvier</tt>.
*/
public ThumbnailIQ() {}
/**
* Creates a <tt>ThumbnailIQ</tt> packet, by specifying the source, the
* destination, the content-ID and the type of this packet. The type could
* be one of the types defined in <tt>IQ.Type</tt>.
*
* @param from the source of the packet
* @param to the destination of the packet
* @param cid the content-ID used to identify this packet in the destination
* @param type the of the packet, which could be one of the types defined
* in <tt>IQ.Type</tt>
*/
public ThumbnailIQ(String from, String to, String cid, Type type)
{
this.cid = cid;
this.setFrom(from);
this.setTo(to);
this.setType(type);
}
/**
* Creates a <tt>ThumbnailIQ</tt> packet, by specifying the source, the
* destination, the content-ID, the type of data and the data of the
* thumbnail. We also precise the type of the packet to create.
*
* @param from the source of the packet
* @param to the destination of the packet
* @param cid the content-ID used to identify this packet in the destination
* @param mimeType the type of the data passed
* @param data the data of the thumbnail
* @param type the of the packet, which could be one of the types defined
* in <tt>IQ.Type</tt>
*/
public ThumbnailIQ( String from, String to, String cid,
String mimeType, byte[] data, Type type)
{
this(from, to, cid, type);
this.data = data;
this.mimeType = mimeType;
}
/**
* Parses the given <tt>XmlPullParser</tt> into a ThumbnailIQ packet and
* returns it.
* @see IQProvider#parseIQ(XmlPullParser)
*/
public IQ parseIQ(XmlPullParser parser) throws Exception
{
String elementName = parser.getName();
String namespace = parser.getNamespace();
if (elementName.equals(ELEMENT_NAME)
&& namespace.equals(NAMESPACE))
{
this.cid = parser.getAttributeValue("", CID);
this.mimeType = parser.getAttributeValue("", TYPE);
}
int eventType = parser.next();
if (eventType == XmlPullParser.TEXT)
{
this.data = Base64.decode(parser.getText());
}
return this;
}
/**
* Returns the xml representing the data element in this <tt>IQ</tt> packet.
*/
public String getChildElementXML()
{
StringBuffer buf = new StringBuffer();
// open extension
buf.append("<").append(ELEMENT_NAME)
.append(" xmlns=\"").append(NAMESPACE).append("\"")
.append(" " + CID).append("=\"").append(cid).append("\"");
if (mimeType != null)
buf.append(" " + TYPE).append("=\"").append(mimeType).append("\">");
else
buf.append(">");
if (data != null)
{
byte[] encodedData = Base64.encode(data);
buf.append(new String(encodedData));
}
buf.append("</data>");
return buf.toString();
}
/**
* Returns the content-ID of this thumbnail packet.
* @return the content-ID of this thumbnail packet
*/
public String getCid()
{
return cid;
}
/**
* Returns the data of the thumbnail.
* @return the data of the thumbnail
*/
public byte[] getData()
{
return data;
}
}

@ -20,6 +20,7 @@ Import-Package: org.osgi.framework,
org.jivesoftware.smackx.jingle.packet,
org.jivesoftware.smackx.jingle.provider,
org.jivesoftware.smackx.filetransfer,
org.jivesoftware.smackx.provider,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,

@ -18,8 +18,8 @@ public class MockFileTransferImpl
extends AbstractFileTransfer
{
private String id = null;
private int direction;
private File file = null;
private final int direction;
private final File file;
private Contact contact = null;
public MockFileTransferImpl(Contact c, File file, String id, int direction)
@ -61,7 +61,7 @@ public int getDirection()
return direction;
}
public File getFile()
public File getLocalFile()
{
return file;
}

@ -132,7 +132,11 @@ public FileTransfer acceptFile(File file)
public void rejectFile()
{
}
public byte[] getThumbnail()
{
return null;
}
}, requestDate));
}

@ -61,7 +61,7 @@ public int getDirection()
return IN;
}
public File getFile()
public File getLocalFile()
{
return null;
}

@ -155,36 +155,49 @@ 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)));
try
{
sshContact.getFileTransferOperationSet().sendFile(
sshContact,
null,
message.substring(message.indexOf(' ', firstSpace+1) + 1),
message.substring(
firstSpace+1,
message.indexOf(' ', firstSpace+1)));
}
catch (Exception e)
{
e.printStackTrace();
}
return true;
}
else if(message.startsWith("/download"))
{
int firstSpace = message.indexOf(' ');
sshContact.getFileTransferOperationSet().sendFile(
try
{
sshContact.getFileTransferOperationSet().sendFile(
null,
sshContact,
message.substring(firstSpace+1, message.indexOf(' ',
firstSpace+1)),
message.substring(message.indexOf(' ', firstSpace+1) + 1));
}
catch(Exception e)
{
e.printStackTrace();
}
return true;
}
return false;
}
/**
* In case the <tt>to</tt> Contact corresponds to another ssh
* protocol provider registered with SIP Communicator, we deliver

@ -14,6 +14,8 @@
import java.io.*;
import java.util.*;
import javax.management.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;

@ -79,7 +79,7 @@ public int getDirection()
*
* @return the file
*/
public File getFile()
public File getLocalFile()
{
return file;
}

@ -174,4 +174,14 @@ public Date getDate()
{
return date;
}
/**
* Returns the thumbnail contained in this request.
*
* @return the thumbnail contained in this request
*/
public byte[] getThumbnail()
{
return null;
}
}

@ -124,8 +124,20 @@ public int getStatus()
/**
* Notifies all status listeners that a new
* <tt>FileTransferStatusChangeEvent</tt> occured.
* @param newStatus the new status
*/
public void fireStatusChangeEvent(int newStatus)
{
this.fireStatusChangeEvent(newStatus, null);
}
/**
* Notifies all status listeners that a new
* <tt>FileTransferStatusChangeEvent</tt> occured.
* @param newStatus the new status
* @param reason the reason of the status change
*/
public void fireStatusChangeEvent(int newStatus, String reason)
{
// ignore if status is the same
if(this.status == newStatus)
@ -139,7 +151,8 @@ public void fireStatusChangeEvent(int newStatus)
}
FileTransferStatusChangeEvent statusEvent
= new FileTransferStatusChangeEvent(this, status, newStatus);
= new FileTransferStatusChangeEvent(
this, status, newStatus, reason);
// Updates the status.
this.status = newStatus;

@ -50,11 +50,11 @@ public interface FileTransfer
public int getDirection();
/**
* Returns the file that is transfered.
* Returns the local file that is being transferred or to which we transfer.
*
* @return the file
*/
public File getFile();
public File getLocalFile();
/**
* Returns the contact that we are transfering files with.

@ -62,7 +62,7 @@ public interface IncomingFileTransferRequest
/**
* Function called to accept and receive the file.
*
*
* @param file the file to accept
* @return the <tt>FileTransfer</tt> object managing the transfer
*/
@ -72,4 +72,11 @@ public interface IncomingFileTransferRequest
* Function called to refuse the file.
*/
public void rejectFile();
/**
* Returns the thumbnail contained in this request.
*
* @return the thumbnail contained in this request
*/
public byte[] getThumbnail();
}

@ -34,11 +34,14 @@ public interface OperationSetFileTransfer
* or connected
* @throws IllegalArgumentException if some of the arguments doesn't fit the
* protocol requirements
* @throws OperationNotSupportedException if the given contact client or
* server does not support file transfers
*/
public FileTransfer sendFile( Contact toContact,
File file)
throws IllegalStateException,
IllegalArgumentException;
IllegalArgumentException,
OperationNotSupportedException;
/**
* Sends a file transfer request to the given <tt>toContact</tt> by
@ -56,13 +59,16 @@ public FileTransfer sendFile( Contact toContact,
* or connected
* @throws IllegalArgumentException if some of the arguments doesn't fit the
* protocol requirements
* @throws OperationNotSupportedException if the given contact client or
* server does not support file transfers.
*/
public FileTransfer sendFile( Contact toContact,
Contact fromContact,
String remotePath,
String localPath)
throws IllegalStateException,
IllegalArgumentException;
IllegalArgumentException,
OperationNotSupportedException;
/**
* Adds the given <tt>FileTransferListener</tt> that would listen for

@ -0,0 +1,37 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.protocol;
import java.io.*;
/**
* The <tt>OperationSetThumbnailedFileFactory</tt> is meant to be used by
* bundles interested in making files with thumbnails. For example the user
* interface can be interested in sending files with thumbnails through the
* <tt>OperationSetFileTransfer</tt>.
*
* @author Yana Stamcheva
*/
public interface OperationSetThumbnailedFileFactory
extends OperationSet
{
/**
* Creates a file, by attaching the thumbnail, given by the details, to it.
*
* @param file the base file
* @param thumbnailWidth the width of the thumbnail
* @param thumbnailHeight the height of the thumbnail
* @param thumbnailMimeType the mime type of the thumbnail
* @param thumbnail the thumbnail data
* @return a file with a thumbnail
*/
public File createFileWithThumbnail(File file,
int thumbnailWidth,
int thumbnailHeight,
String thumbnailMimeType,
byte[] thumbnail);
}

@ -65,6 +65,11 @@ public class FileTransferStatusChangeEvent
*/
private final int newStatus;
/**
* The reason of this status change.
*/
private String reason;
/**
* Creates a <tt>FileTransferStatusChangeEvent</tt> by specifying the
* source <tt>fileTransfer</tt>, the old transfer status and the new status.
@ -73,15 +78,18 @@ public class FileTransferStatusChangeEvent
* change occured
* @param oldStatus the old status
* @param newStatus the new status
* @param reason the reason of this status change
*/
public FileTransferStatusChangeEvent( FileTransfer fileTransfer,
int oldStatus,
int newStatus)
int newStatus,
String reason)
{
super(fileTransfer);
this.oldStatus = oldStatus;
this.newStatus = newStatus;
this.reason = reason;
}
/**
@ -113,4 +121,13 @@ public int getNewStatus()
{
return newStatus;
}
/**
* Returns the reason of the status change.
* @return the reason of the status change
*/
public String getReason()
{
return reason;
}
}

@ -107,6 +107,41 @@ public static Image getScaledRoundedImage(Image image, int width, int height)
return destImage;
}
public static byte[] getScaledInstanceInBytes(
Image image, int width, int height)
{
byte[] scaledBytes = null;
BufferedImage scaledImage
= (BufferedImage) getScaledRoundedImage(image, width, height);
if (scaledImage != null)
{
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
try
{
ImageIO.write(scaledImage, "png", outStream);
scaledBytes = outStream.toByteArray();
}
catch (IOException e)
{
logger.debug("Could not scale image in bytes.", e);
}
}
return scaledBytes;
}
/**
* Returns a scaled rounded icon from the given <tt>image</tt>, scaled
* within the given <tt>width</tt> and <tt>height</tt>.
* @param image the image to scale
* @param width the maximum width of the scaled icon
* @param height the maximum height of the scaled icon
* @return a scaled rounded icon
*/
public static ImageIcon getScaledRoundedIcon(Image image, int width,
int height)
{

@ -0,0 +1,76 @@
package net.java.sip.communicator.util;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Sha1Crypto
{
/**
* Encodes the given text with the SHA-1 algorithm.
*
* @param text the text to encode
* @return the encoded text
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
public static String encode(String text)
throws NoSuchAlgorithmException,
UnsupportedEncodingException
{
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
byte[] sha1hash;
messageDigest.update(text.getBytes("iso-8859-1"), 0, text.length());
sha1hash = messageDigest.digest();
return convertToHex(sha1hash);
}
/**
* Encodes the given text with the SHA-1 algorithm.
*
* @param byteArreay the byte array to encode
* @return the encoded text
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
public static String encode(byte[] byteArray)
throws NoSuchAlgorithmException,
UnsupportedEncodingException
{
MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
byte[] sha1hash;
messageDigest.update(byteArray);
sha1hash = messageDigest.digest();
return convertToHex(sha1hash);
}
/**
* Converts the given byte data into Hex string.
*
* @param data the byte array to convert
* @return the Hex string representation of the given byte array
*/
private static String convertToHex(byte[] data)
{
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++)
{
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do
{
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
}
while(two_halfs++ < 1);
}
return buf.toString();
}
}

@ -119,7 +119,7 @@ public void testSendAndReceive()
= (FileTransferCreatedEvent)senderFTListerner.collectedEvents.get(0);
assertEquals("FileTransfer file"
,fileTransferCreatedEvent.getFileTransfer().getFile()
,fileTransferCreatedEvent.getFileTransfer().getLocalFile()
,fileToTransfer);
assertEquals("A file transfer status changed - preparing received on send side"
@ -169,7 +169,7 @@ public void testSendAndReceive()
= (FileTransferCreatedEvent)receiverFTListerner.collectedEvents.get(0);
assertEquals("FileTransfer file"
,fileTransferCreatedEvent.getFileTransfer().getFile()
,fileTransferCreatedEvent.getFileTransfer().getLocalFile()
,receiveFile);
receiverStatusListener.waitForEvent(30000, 3);
@ -251,7 +251,7 @@ public void testSenderCancelBeforeAccepted()
= (FileTransferCreatedEvent)senderFTListerner.collectedEvents.get(0);
assertEquals("FileTransfer file"
,fileTransferCreatedEvent.getFileTransfer().getFile()
,fileTransferCreatedEvent.getFileTransfer().getLocalFile()
,fileToTransfer);
assertEquals("A file transfer status changed - preparing received on send side"
@ -361,7 +361,7 @@ public void testReceiverDecline()
= (FileTransferCreatedEvent)senderFTListerner.collectedEvents.get(0);
assertEquals("FileTransfer file"
,fileTransferCreatedEvent.getFileTransfer().getFile()
,fileTransferCreatedEvent.getFileTransfer().getLocalFile()
,fileToTransfer);
assertEquals("A file transfer status changed - preparing received on send side"
@ -475,7 +475,7 @@ public void testReceiverCancelsWhileTransfering()
= (FileTransferCreatedEvent)senderFTListerner.collectedEvents.get(0);
assertEquals("FileTransfer file"
,fileTransferCreatedEvent.getFileTransfer().getFile()
,fileTransferCreatedEvent.getFileTransfer().getLocalFile()
,fileToTransfer);
assertEquals("A file transfer status changed - preparing received on send side"
@ -562,7 +562,7 @@ public void testReceiverCancelsWhileTransfering()
= (FileTransferCreatedEvent)receiverFTListerner.collectedEvents.get(0);
assertEquals("FileTransfer file"
,fileTransferCreatedEvent.getFileTransfer().getFile()
,fileTransferCreatedEvent.getFileTransfer().getLocalFile()
,receiveFile);
// sender
@ -618,7 +618,7 @@ public void testSenderCancelsWhileTransfering()
= (FileTransferCreatedEvent)senderFTListerner.collectedEvents.get(0);
assertEquals("FileTransfer file"
,fileTransferCreatedEvent.getFileTransfer().getFile()
,fileTransferCreatedEvent.getFileTransfer().getLocalFile()
,fileToTransfer);
assertEquals("A file transfer status changed - preparing received on send side"
@ -691,7 +691,7 @@ public void testSenderCancelsWhileTransfering()
= (FileTransferCreatedEvent)receiverFTListerner.collectedEvents.get(0);
assertEquals("FileTransfer file"
,fileTransferCreatedEvent.getFileTransfer().getFile()
,fileTransferCreatedEvent.getFileTransfer().getLocalFile()
,receiveFile);
receiverStatusListener.waitForEvent(4000, 3);
@ -920,17 +920,20 @@ public void waitForEvent(long waitFor, int eventsNum)
synchronized(this)
{
if(collectedEvents.size() > (eventsNum - 1)){
if(collectedEvents.size() > (eventsNum - 1))
{
logger.trace("Event already received. " + collectedEvents);
return;
}
try{
try
{
wait(waitFor);
if(collectedEvents.size() > (eventsNum - 1))
logger.trace("Received a FileTransferEvent.");
else
logger.trace("No FileTransferEvent received for "+waitFor+"ms.");
logger.trace("No FileTransferEvent received for "
+ waitFor + "ms.");
}
catch (InterruptedException ex)
{

Loading…
Cancel
Save