See http://bugzilla.gnome.org/show_bug.cgi?id=576405#c4 for reference.
As said on IRC we can't know when the remote peer cancel the FT:
<cassidy> problem is, the SI FT XEP doesn't have any protocol to tell that you are cancelling the FT
<cassidy> so the the only way is to close the bytestream
<cassidy> but we can't distinguish if it has been closed because of an error or because cancelling
Remaining problem is when the receiver close the channel and the state reason is set to ERROR instead of CANCEL. I think Gabble's code is right. According to my test, Empathy close the local socket (the once used to receive the file) and then call Close() on the FT channel.
But when Gabble detects that the local socket has been broken, he changes the state to LOCAL_ERROR (as something did wrong on our side). A possible fix would be in Empathy to wait that Close() returned before closing the socket.