/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.impl.protocol.jabber;
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.StringUtils;
import org.jivesoftware.smackx.filetransfer.*;
import org.jivesoftware.smackx.packet.*;
/**
* The Jabber protocol extension of the AbstractFileTransfer.
*
* @author Yana Stamcheva
*/
public class OutgoingFileTransferJabberImpl
extends AbstractFileTransfer
implements PacketInterceptor
{
/**
* The logger of this class.
*/
private final Logger logger
= Logger.getLogger(OutgoingFileTransferJabberImpl.class);
private final String id;
private final Contact receiver;
private final File file;
private ThumbnailElement thumbnailElement;
private final ThumbnailRequestListener thumbnailRequestListener
= new ThumbnailRequestListener();
/**
* The jabber outgoing file transfer.
*/
private final OutgoingFileTransfer jabberTransfer;
private final ProtocolProviderServiceJabberImpl protocolProvider;
/**
* Creates an OutgoingFileTransferJabberImpl by specifying the
* receiver contact, the file, the jabberTransfer,
* that would be used to send the file through Jabber and the
* protocolProvider.
*
* @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,
ProtocolProviderServiceJabberImpl protocolProvider)
{
this.receiver = receiver;
this.file = file;
this.jabberTransfer = jabberTransfer;
this.protocolProvider = protocolProvider;
// 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().addPacketInterceptor(
this,
new IQTypeFilter(IQ.Type.SET));
}
}
}
/**
* Cancels the file transfer.
*/
@Override
public void cancel()
{
this.jabberTransfer.cancel();
}
/**
* Returns the number of bytes already sent to the recipient.
*
* @return the number of bytes already sent to the recipient.
*/
@Override
public long getTransferedBytes()
{
return jabberTransfer.getBytesSent();
}
/**
* The direction is outgoing.
* @return OUT.
*/
public int getDirection()
{
return OUT;
}
/**
* Returns the local file that is being transferred or to which we transfer.
*
* @return the file
*/
public File getLocalFile()
{
return file;
}
/**
* The contact we are sending the file.
* @return the receiver.
*/
public Contact getContact()
{
return receiver;
}
/**
* The unique id.
* @return the id.
*/
public String getID()
{
return id;
}
/**
* Removes previously added thumbnail request listener.
*/
public void removeThumbnailRequestListener()
{
protocolProvider.getConnection()
.removePacketListener(thumbnailRequestListener);
}
/**
* Listens for all StreamInitiation 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;
if (logger.isDebugEnabled())
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);
if (logger.isDebugEnabled())
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().removePacketInterceptor(this);
}
/**
* The ThumbnailRequestListener listens for events triggered by
* the reception of a ThumbnailIQ packet. The packet is examined
* and a ThumbnailIQ 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;
String thumbnailIQCid = thumbnailIQ.getCid();
Connection connection = protocolProvider.getConnection();
if ((thumbnailIQCid != null)
&& thumbnailIQCid.equals(thumbnailElement.getCid()))
{
ThumbnailedFile thumbnailedFile = (ThumbnailedFile) file;
ThumbnailIQ thumbnailResponse = new ThumbnailIQ(
thumbnailIQ.getTo(),
thumbnailIQ.getFrom(),
thumbnailIQCid,
thumbnailedFile.getThumbnailMimeType(),
thumbnailedFile.getThumbnailData(),
IQ.Type.RESULT);
if (logger.isDebugEnabled())
logger.debug("Send thumbnail response to the receiver: "
+ thumbnailResponse.toXML());
connection.sendPacket(thumbnailResponse);
}
else
{
// RETURN
}
if (connection != null)
connection.removePacketListener(this);
}
}
}