Transfer (large) data from sender to receiver.

def transfer(sendContext, receiveContext, chunkSize):
    """ Transfer (large) data from sender to receiver. """
    try:
        chunkSize = receiveContext.chunkSize
    except AttributeError:
        pass

    if sendContext is not None and receiveContext is not None:
        with receiveContext as writer:
            # Open reader after writer,
            # so any raised errors will abort write before writer closes.
            with sendContext as reader:
                checkBefore = None
                if hasattr(writer, 'skipChunk'):
                    checkBefore = hasattr(reader, 'checkSum')

                while True:
                    if checkBefore is True:
                        (size, checkSum) = reader.checkSum(chunkSize)

                        if writer.skipChunk(size, checkSum):
                            reader.seek(size, io.SEEK_CUR)
                            continue

                    data = reader.read(chunkSize)
                    if len(data) == 0:
                        break

                    if checkBefore is False:
                        checkSum = hashlib.md5(data).hexdigest()

                        if writer.skipChunk(len(data), checkSum, data):
                            continue

                    writer.write(data)