Add filetransfer for icq protocol. Implement new request canceled event in tests and in yahoo protocol.

cusax-fix
Damian Minkov 17 years ago
parent 422560c705
commit 5d70236c72

@ -752,7 +752,7 @@ public void fileTransferRequestReceived(FileTransferRequestEvent event)
historyWriter.addRecord(new String[]{
req.getFileName(),
getDirection(FileTransfer.IN),
getDirection(FileTransfer.IN),
String.valueOf(event.getTimestamp().getTime()),
FILE_TRANSFER_ACTIVE,
req.getID()
@ -835,6 +835,24 @@ public void fileTransferRequestRejected(FileTransferRequestEvent event)
public void fileTransferRequestCanceled(FileTransferRequestEvent event)
{
try
{
IncomingFileTransferRequest req = event.getRequest();
History history = getHistory(null, req.getSender());
HistoryWriter historyWriter = history.getWriter();
historyWriter.updateRecord(
STRUCTURE_NAMES[4],
req.getID(),
STRUCTURE_NAMES[3],
FileRecord.CANCELED
);
}
catch (IOException e)
{
logger.error("Could not add file transfer log to history", e);
}
}
/**

@ -0,0 +1,241 @@
/*
* 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.icq;
import java.io.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import net.kano.joustsim.oscar.oscar.service.icbm.ft.*;
import net.kano.joustsim.oscar.oscar.service.icbm.ft.FileTransfer;
import net.kano.joustsim.oscar.oscar.service.icbm.ft.controllers.*;
import net.kano.joustsim.oscar.oscar.service.icbm.ft.events.*;
import net.kano.joustsim.oscar.oscar.service.icbm.ft.state.*;
/**
* The Filetransfer imeplementation for icq.
* @author Damian Minkov
*/
public class FileTransferImpl
extends AbstractFileTransfer
{
/**
* Logger
*/
private static final Logger logger =
Logger.getLogger(FileTransferImpl.class);
private String id = null;
private Contact contact = null;
private File file = null;
private int direction = -1;
private long transferedBytes;
private FileTransfer fileTransfer;
public FileTransferImpl(
FileTransfer fileTransfer,
String id, Contact contact, File file, int direction)
{
this.fileTransfer = fileTransfer;
this.id = id;
this.contact = contact;
this.file = file;
this.direction = direction;
fileTransfer.addEventListener(new IcqFileTransferEventListener());
}
/**
* Cancels this file transfer. When this method is called transfer should
* be interrupted.
*/
public void cancel()
{
fileTransfer.close();
}
/**
* Returns the number of bytes already transfered through this file transfer.
*
* @return the number of bytes already transfered through this file transfer
*/
public long getTransferedBytes()
{
return transferedBytes;
}
/**
* Uniquie ID that is identifying the FileTransfer
* if the request has been accepted.
*
* @return the id.
*/
public String getID()
{
return id;
}
/**
* The file transfer direction.
* @return returns the direction of the file transfer : IN or OUT.
*/
public int getDirection()
{
return direction;
}
/**
* Returns the file that is transfered.
*
* @return the file
*/
public File getFile()
{
return file;
}
/**
* Returns the contact that we are transfering files with.
* @return the contact.
*/
public Contact getContact()
{
return contact;
}
/**
* @param transferedBytes the transferedBytes to set
*/
public void setTransferedBytes(long transferedBytes)
{
this.transferedBytes = transferedBytes;
}
/**
* Provides support for files sent and received.
*/
class IcqFileTransferEventListener
implements RvConnectionEventListener
{
public void handleEventWithStateChange(
final RvConnection transfer,
RvConnectionState state,
RvConnectionEvent event)
{
if (state==FileTransferState.CONNECTING)
{
// this both are hacks that detects cancels while transfering
// as only connection is closed from other side
// we detect it by receiving ConnectionTimedOutEvent
if(transfer instanceof IncomingFileTransferImpl)
{
((IncomingFileTransferImpl)transfer).getStateController().
addControllerListener(new ControllerListener()
{
public void handleControllerSucceeded(
StateController controller, SuccessfulStateInfo info)
{
}
public void handleControllerFailed(
StateController controller, FailedStateInfo info)
{
if(info instanceof FailureEventInfo
&& ((FailureEventInfo)info).getEvent()
instanceof ConnectionTimedOutEvent)
{
FileTransferImpl.this.fireStatusChangeEvent(
FileTransferStatusChangeEvent.CANCELED);
fileTransfer.close();
}
}
});
}
else if(transfer instanceof OutgoingFileTransferImpl)
{
((OutgoingFileTransferImpl)transfer).getStateController().
addControllerListener(new ControllerListener()
{
public void handleControllerSucceeded(
StateController controller, SuccessfulStateInfo info)
{
}
public void handleControllerFailed(
StateController controller, FailedStateInfo info)
{
if(info instanceof FailureEventInfo
&& ((FailureEventInfo)info).getEvent()
instanceof ConnectionTimedOutEvent)
{
FileTransferImpl.this.fireStatusChangeEvent(
FileTransferStatusChangeEvent.CANCELED);
fileTransfer.close();
}
}
});
}
}
else if (state==FileTransferState.FINISHED)
{
fireStatusChangeEvent(FileTransferStatusChangeEvent.COMPLETED);
}
else if (state==FileTransferState.FAILED)
{
if(event instanceof LocallyCancelledEvent)
{
// sender cancels before other party accepts
fireStatusChangeEvent(FileTransferStatusChangeEvent.CANCELED);
}
else if(event instanceof BuddyCancelledEvent)
{
fireStatusChangeEvent(FileTransferStatusChangeEvent.REFUSED);
}
else
fireStatusChangeEvent(FileTransferStatusChangeEvent.FAILED);
}
else if (state==FileTransferState.TRANSFERRING)
{
if (event instanceof TransferringFileEvent)
{
fireStatusChangeEvent(
FileTransferStatusChangeEvent.IN_PROGRESS);
final ProgressStatusProvider psp = (
(TransferringFileEvent)event).getProgressProvider();
new Thread("Transfer for " + transfer.getBuddyScreenname())
{
public void run()
{
while (transfer.isOpen())
{
long transfered = psp.getPosition();
setTransferedBytes(transfered);
fireProgressChangeEvent(
System.currentTimeMillis(), (int)transfered);
try {
Thread.sleep(100);
}
catch (InterruptedException e)
{}
}
}
}.start();
}
}
}
public void handleEvent(RvConnection transfer, RvConnectionEvent event)
{
}
}
}

@ -0,0 +1,216 @@
/*
* 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.icq;
import java.io.File;
import java.util.*;
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.*;
import net.kano.joscar.rvcmd.*;
import net.kano.joustsim.oscar.oscar.service.icbm.ft.*;
/**
* Icq implementation of the incoming file transfer request
*
* @author Nicolas Riegel
* @author Damian Minkov
*/
public class IncomingFileTransferRequestIcqImpl
implements IncomingFileTransferRequest
{
/**
* Logger
*/
private static final Logger logger =
Logger.getLogger(IncomingFileTransferRequestIcqImpl.class);
/**
* The icq provider.
*/
private ProtocolProviderServiceIcqImpl icqProvider;
private OperationSetFileTransferIcqImpl fileTransferOpSet;
/**
* The icq file transfer request received
*/
private IncomingFileTransfer incomingFileTransfer = null;
private Contact sender = null;
private Date date;
private String id;
/**
* Constructor
*
* @param fileTransfer icq file transfer request that was received
*/
public IncomingFileTransferRequestIcqImpl(
ProtocolProviderServiceIcqImpl icqProvider,
OperationSetFileTransferIcqImpl fileTransferOpSet,
IncomingFileTransfer fileTransfer,
Contact sender,
Date date)
{
this.icqProvider = icqProvider;
this.fileTransferOpSet = fileTransferOpSet;
this.incomingFileTransfer = fileTransfer;
this.sender = sender;
this.date = date;
id = String.valueOf(incomingFileTransfer.getRvSessionInfo()
.getRvSession().getRvSessionId());
}
/**
* Uniquie ID that is identifying the request and then the FileTransfer
* if the request has been accepted.
*
* @return the id.
*/
public String getID()
{
return id;
}
/**
* Returns a String that represents the name of the file that is being
* received.
* If there is no name, returns null.
* @return a String that represents the name of the file
*/
public String getFileName()
{
return incomingFileTransfer.getRequestFileInfo().getFilename();
}
/**
* Returns a String that represents the description of the file that is
* being received.
* If there is no description available, returns null.
*
* @return a String that represents the description of the file
*/
public String getFileDescription()
{
return incomingFileTransfer.getInvitationMessage().getMessage();
}
/**
* Returns a long that represents the size of the file that is being
* received.
* If there is no file size available, returns null.
*
* @return a long that represents the size of the file
*/
public long getFileSize()
{
return incomingFileTransfer.getRequestFileInfo().getTotalFileSize();
}
/**
* Returns a String that represents the name of the sender of the file
* being received.
* If there is no sender name available, returns null.
*
* @return a String that represents the name of the sender
*/
public Contact getSender()
{
return sender;
}
/**
* Function called to accept and receive the file.
*
* @param file the file to accept
* @return the <tt>FileTransfer</tt> object managing the transfer
*/
public FileTransfer acceptFile(File file)
{
incomingFileTransfer.setFileMapper(new IcqFileMapper(file));
FileTransferImpl inFileTransfer =
new FileTransferImpl(
incomingFileTransfer,
id, sender, file,
FileTransfer.IN);
FileTransferCreatedEvent event
= new FileTransferCreatedEvent(inFileTransfer, date);
fileTransferOpSet.fireFileTransferCreated(event);
incomingFileTransfer.accept();
inFileTransfer.fireStatusChangeEvent(
FileTransferStatusChangeEvent.PREPARING);
return inFileTransfer;
}
/**
* Function called to refuse the file.
*/
public void rejectFile()
{
try
{
incomingFileTransfer.close();
fileTransferOpSet.fireFileTransferRequestRejected(
new FileTransferRequestEvent(fileTransferOpSet, this, date));
}
catch(IllegalStateException e)
{
logger.debug("Error rejecting file",e);
return;
}
}
/**
* Class to say where the incoming file should be save
*
* @author Nicolas Riegel
*/
private class IcqFileMapper
implements FileMapper
{
/**
* Destination file
*/
File file = null;
/**
* Constructor
*
* @param file is the destination file
*/
public IcqFileMapper(File file)
{
this.file = file;
}
public File getDestinationFile(SegmentedFilename filename)
{
return file;
}
public File getUnspecifiedFilename()
{
return file;
}
}
}

@ -0,0 +1,388 @@
/*
* 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.icq;
import java.io.*;
import java.util.*;
import net.java.sip.communicator.service.protocol.FileTransfer;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import net.kano.joscar.rvcmd.*;
import net.kano.joustsim.*;
import net.kano.joustsim.oscar.*;
import net.kano.joustsim.oscar.oscar.service.icbm.ft.*;
import net.kano.joustsim.oscar.oscar.service.icbm.ft.events.*;
/**
* The ICQ protocol filetransfer OperationSet.
*
* @author Anthony Schmitt
* @author Damian Minkov
*/
public class OperationSetFileTransferIcqImpl
implements OperationSetFileTransfer,
RvConnectionManagerListener
{
private static final Logger logger =
Logger.getLogger(OperationSetPersistentPresenceIcqImpl.class);
/**
* A call back to the ICQ provider that created us.
*/
private ProtocolProviderServiceIcqImpl icqProvider = null;
/**
* A list of listeners registered for file transfer events.
*/
private ArrayList<FileTransferListener> fileTransferListeners
= new ArrayList<FileTransferListener>();
/**
* Create a new FileTransfer OperationSet over the specified Icq provider
* @param provider
*/
public OperationSetFileTransferIcqImpl(
ProtocolProviderServiceIcqImpl icqProvider)
{
this.icqProvider = icqProvider;
icqProvider.addRegistrationStateChangeListener(
new RegistrationStateListener());
}
/**
* Sends a file transfer request to the given <tt>toContact</tt> by
* specifying the local and remote file path and the <tt>fromContact</tt>,
* sending the file.
*
* @param toContact the contact that should receive the file
* @param file the file to send
*
* @return the transfer object
*
* @throws IllegalStateException if the protocol provider is not registered
* or connected
* @throws IllegalArgumentException if some of the arguments doesn't fit the
* protocol requirements
*/
public FileTransfer sendFile( Contact toContact,
File file)
throws IllegalStateException,
IllegalArgumentException
{
assertConnected();
// Get the aim connection
AimConnection aimConnection = icqProvider.getAimConnection();
// Create an outgoing file transfer instance
OutgoingFileTransfer outgoingFileTransfer =
aimConnection.getIcbmService().getRvConnectionManager().
createOutgoingFileTransfer(new Screenname(toContact.getAddress()));
String id = String.valueOf(outgoingFileTransfer.getRvSessionInfo()
.getRvSession().getRvSessionId());
FileTransferImpl outFileTransfer = new FileTransferImpl(
outgoingFileTransfer,
id, toContact, file, FileTransfer.OUT);
// Adding the file to the outgoing file transfer
try
{
outgoingFileTransfer.setSingleFile(new File(file.getPath()));
}
catch (IOException e)
{
logger.debug("Error sending file",e);
return null;
}
// Notify all interested listeners that a file transfer has been
// created.
FileTransferCreatedEvent event
= new FileTransferCreatedEvent(outFileTransfer, new Date());
fireFileTransferCreated(event);
// Sending the file
outgoingFileTransfer.sendRequest(
new InvitationMessage(""));
outFileTransfer.fireStatusChangeEvent(
FileTransferStatusChangeEvent.PREPARING);
return outFileTransfer;
}
/**
* Sends a file transfer request to the given <tt>toContact</tt> by
* specifying the local and remote file path and the <tt>fromContact</tt>,
* sending the file.
*
* @param toContact the contact that should receive the file
* @param fromContact the contact sending the file
* @param remotePath the remote file path
* @param localPath the local file path
*
* @return the transfer object
*
* @throws IllegalStateException if the protocol provider is not registered
* or connected
* @throws IllegalArgumentException if some of the arguments doesn't fit the
* protocol requirements
*/
public FileTransfer sendFile( Contact toContact,
Contact fromContact,
String remotePath,
String localPath)
throws IllegalStateException,
IllegalArgumentException
{
return this.sendFile(toContact, new File(localPath));
}
/**
* Adds the given <tt>FileTransferListener</tt> that would listen for
* file transfer requests and created file transfers.
*
* @param listener the <tt>FileTransferListener</tt> to add
*/
public void addFileTransferListener(
FileTransferListener listener)
{
synchronized(fileTransferListeners)
{
if(!fileTransferListeners.contains(listener))
{
this.fileTransferListeners.add(listener);
}
}
}
/**
* Removes the given <tt>FileTransferListener</tt> that listens for
* file transfer requests and created file transfers.
*
* @param listener the <tt>FileTransferListener</tt> to remove
*/
public void removeFileTransferListener(
FileTransferListener listener)
{
synchronized(fileTransferListeners)
{
this.fileTransferListeners.remove(listener);
}
}
/**
* Utility method throwing an exception if the stack is not properly
* initialized.
* @throws java.lang.IllegalStateException if the underlying stack is
* not registered and initialized.
*/
private void assertConnected()
throws IllegalStateException
{
if (icqProvider == null)
throw new IllegalStateException(
"The provider must be non-null and signed on the "
+"service before being able to send a file.");
else if (!icqProvider.isRegistered())
throw new IllegalStateException(
"The provider must be signed on the service before "
+"being able to send a file.");
}
/**
* Function called when a icq file transfer request arrive
* @param manager the joustsim manager
* @param transfer the incoming transfer
*/
public void handleNewIncomingConnection(
RvConnectionManager manager, IncomingRvConnection transfer)
{
if (transfer instanceof IncomingFileTransfer)
{
logger.trace("Incoming Icq file transfer request " + transfer.getClass());
if(!(transfer instanceof IncomingFileTransfer))
{
logger.warn("Wrong file transfer.");
return;
}
OperationSetPersistentPresenceIcqImpl opSetPersPresence
= (OperationSetPersistentPresenceIcqImpl)
icqProvider.getOperationSet(
OperationSetPersistentPresence.class);
Contact sender =
opSetPersPresence.findContactByID(
transfer.getBuddyScreenname().getFormatted());
IncomingFileTransfer incomingFileTransfer =
(IncomingFileTransfer)transfer;
final Date newDate = new Date();
final IncomingFileTransferRequest req =
new IncomingFileTransferRequestIcqImpl(
icqProvider,
this,
incomingFileTransfer, sender, newDate);
// this handels when we receive request and before accept or decline
// it we receive cancel
transfer.addEventListener(new RvConnectionEventListener() {
public void handleEventWithStateChange(
RvConnection transfer,
RvConnectionState state,
RvConnectionEvent event)
{
if (state==FileTransferState.FAILED
&& event instanceof BuddyCancelledEvent)
{
fireFileTransferRequestCanceled(
new FileTransferRequestEvent(
OperationSetFileTransferIcqImpl.this,
req,
newDate));
}
}
public void handleEvent(RvConnection arg0, RvConnectionEvent arg1)
{}
});
fireFileTransferRequest(
new FileTransferRequestEvent(this, req, newDate));
}
}
/**
* Delivers the specified event to all registered file transfer listeners.
*
* @param event the <tt>EventObject</tt> that we'd like delivered to all
* registered file transfer listeners.
*/
private void fireFileTransferRequest(FileTransferRequestEvent event)
{
Iterator<FileTransferListener> listeners = null;
synchronized (fileTransferListeners)
{
listeners = new ArrayList<FileTransferListener>
(fileTransferListeners).iterator();
}
while (listeners.hasNext())
{
FileTransferListener listener = listeners.next();
listener.fileTransferRequestReceived(event);
}
}
/**
* Delivers the specified event to all registered file transfer listeners.
*
* @param event the <tt>EventObject</tt> that we'd like delivered to all
* registered file transfer listeners.
*/
void fireFileTransferRequestRejected(FileTransferRequestEvent event)
{
Iterator<FileTransferListener> listeners = null;
synchronized (fileTransferListeners)
{
listeners = new ArrayList<FileTransferListener>
(fileTransferListeners).iterator();
}
while (listeners.hasNext())
{
FileTransferListener listener = listeners.next();
listener.fileTransferRequestRejected(event);
}
}
/**
* Delivers the specified event to all registered file transfer listeners.
*
* @param event the <tt>EventObject</tt> that we'd like delivered to all
* registered file transfer listeners.
*/
void fireFileTransferRequestCanceled(FileTransferRequestEvent event)
{
Iterator<FileTransferListener> listeners = null;
synchronized (fileTransferListeners)
{
listeners = new ArrayList<FileTransferListener>
(fileTransferListeners).iterator();
}
while (listeners.hasNext())
{
FileTransferListener listener = listeners.next();
listener.fileTransferRequestCanceled(event);
}
}
/**
* Delivers the file transfer to all registered listeners.
*
* @param fileTransfer the <tt>FileTransfer</tt> that we'd like delivered to
* all registered file transfer listeners.
*/
void fireFileTransferCreated(FileTransferCreatedEvent event)
{
Iterator<FileTransferListener> listeners = null;
synchronized (fileTransferListeners)
{
listeners = new ArrayList<FileTransferListener>
(fileTransferListeners).iterator();
}
while (listeners.hasNext())
{
FileTransferListener listener = listeners.next();
listener.fileTransferCreated(event);
}
}
/**
* Our listener that will tell us when we're registered to
*/
private class RegistrationStateListener
implements RegistrationStateChangeListener
{
/**
* The method is called by a ProtocolProvider implementation whenever
* a change in the registration state of the corresponding provider had
* occurred.
* @param evt ProviderStatusChangeEvent the event describing the status
* change.
*/
public void registrationStateChanged(RegistrationStateChangeEvent evt)
{
logger.debug("The provider changed state from: "
+ evt.getOldState()
+ " to: " + evt.getNewState());
if (evt.getNewState() == RegistrationState.REGISTERED)
{
AimConnection aimConnection = icqProvider.getAimConnection();
aimConnection.getIcbmService().getRvConnectionManager().
addConnectionManagerListener(OperationSetFileTransferIcqImpl.this);
}
}
}
}

@ -528,6 +528,12 @@ protected void initialize(String screenname,
supportedOperationSets.put(
OperationSetExtendedAuthorizations.class.getName(),
extendedAuth);
OperationSetFileTransferIcqImpl fileTransferOpSet =
new OperationSetFileTransferIcqImpl(this);
supportedOperationSets.put(
OperationSetFileTransfer.class.getName(),
fileTransferOpSet);
}
isInitialized = true;

@ -262,6 +262,29 @@ private void fireFileTransferRequest(FileTransferRequestEvent event)
}
}
/**
* Delivers the specified event to all registered file transfer listeners.
*
* @param event the <tt>EventObject</tt> that we'd like delivered to all
* registered file transfer listeners.
*/
void fireFileTransferRequestCanceled(FileTransferRequestEvent event)
{
Iterator<FileTransferListener> listeners = null;
synchronized (fileTransferListeners)
{
listeners = new ArrayList<FileTransferListener>
(fileTransferListeners).iterator();
}
while (listeners.hasNext())
{
FileTransferListener listener = listeners.next();
listener.fileTransferRequestCanceled(event);
}
}
private int getStateMapping(int s)
{
switch(s)
@ -336,13 +359,23 @@ public void statusChanged(SessionFileTransferEvent ev)
int newState = ev.getState();
if(newState == SessionFileTransferEvent.CANCEL
|| newState == SessionFileTransferEvent.FAILED
|| newState == SessionFileTransferEvent.RECEIVED
|| newState == SessionFileTransferEvent.REFUSED
|| newState == SessionFileTransferEvent.SENT)
{
// this is an final state so remove it from active filetransfers
activeFileTransfers.remove(ev.getId());
}
if(ftObj instanceof IncomingFileTransferRequest)
{
if(newState == SessionFileTransferEvent.REFUSED)
{
IncomingFileTransferRequestYahooImpl req =
(IncomingFileTransferRequestYahooImpl)ftObj;
fireFileTransferRequestRejected(
fireFileTransferRequestCanceled(
new FileTransferRequestEvent(this, req, req.getDate()));
return;
}

@ -302,8 +302,8 @@ public void testSenderCancelBeforeAccepted()
fileTransferRequestEvent
= (FileTransferRequestEvent)receiverFTListerner.collectedEvents.get(0);
assertTrue("FileTransfer must be rejected"
,receiverFTListerner.isRejected());
assertTrue("FileTransfer must be canceled"
,receiverFTListerner.isCanceled());
}
finally
{
@ -730,6 +730,7 @@ public class FileTransferEventCollector
{
public ArrayList collectedEvents = new ArrayList();
private boolean rejected = false;
private boolean canceled = false;
private FileTransferStatusEventCollector statusCollector = null;
private String name = null;
@ -844,6 +845,15 @@ public void fileTransferRequestRejected(FileTransferRequestEvent event)
public void fileTransferRequestCanceled(FileTransferRequestEvent event)
{
synchronized(this)
{
logger.debug(
name + " Collected evt("+collectedEvents.size()+")= "+event);
canceled = true;
this.collectedEvents.add(event);
notifyAll();
}
}
public void clear()
@ -859,6 +869,14 @@ public boolean isRejected()
{
return rejected;
}
/**
* @return the rejected
*/
public boolean isCanceled()
{
return canceled;
}
}
/**

Loading…
Cancel
Save