//static
void LLTransferManager::processTransferAbort(LLMessageSystem *msgp, void **)
{
	//llinfos << "LLTransferManager::processTransferPacket" << llendl;

	LLUUID transfer_id;
	LLTransferChannelType channel_type;
	msgp->getUUID("TransferInfo", "TransferID", transfer_id);
	msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type);

	// See if it's a target that we're trying to abort
	// Find the transfer associated with this packet.
	LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type);
	if (ttcp)
	{
		LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id);
		if (ttp)
		{
			ttp->abortTransfer();
			ttcp->deleteTransfer(ttp);
			return;
		}
	}

	// Hmm, not a target.  Maybe it's a source.
	LLTransferSourceChannel *tscp = gTransferManager.getSourceChannel(msgp->getSender(), channel_type);
	if (tscp)
	{
		LLTransferSource *tsp = tscp->findTransferSource(transfer_id);
		if (tsp)
		{
			tsp->abortTransfer();
			tscp->deleteTransfer(tsp);
			return;
		}
	}

	llwarns << "Couldn't find transfer " << transfer_id << " to abort!" << llendl;
}
//static
void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **)
{
	//llinfos << "LLTransferManager::processTransferPacket" << llendl;

	LLUUID transfer_id;
	LLTransferChannelType channel_type;
	S32 packet_id;
	LLTSCode status;
	S32 size;
	msgp->getUUID("TransferData", "TransferID", transfer_id);
	msgp->getS32("TransferData", "ChannelType", (S32 &)channel_type);
	msgp->getS32("TransferData", "Packet", packet_id);
	msgp->getS32("TransferData", "Status", (S32 &)status);

	// Find the transfer associated with this packet.
	//llinfos << transfer_id << ":" << channel_type << llendl;
	LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type);
	if (!ttcp)
	{
		llwarns << "Target channel not found" << llendl;
		return;
	}

	LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id);
	if (!ttp)
	{
		llwarns << "Didn't find matching transfer for " << transfer_id
			<< " processing packet " << packet_id
			<< " from " << msgp->getSender() << llendl;
		return;
	}

	size = msgp->getSize("TransferData", "Data");

	S32 msg_bytes = 0;
	if (msgp->getReceiveCompressedSize())
	{
		msg_bytes = msgp->getReceiveCompressedSize();
	}
	else
	{
		msg_bytes = msgp->getReceiveSize();
	}
	gTransferManager.addTransferBitsIn(ttcp->mChannelType, msg_bytes*8);

	if ((size < 0) || (size > MAX_PACKET_DATA_SIZE))
	{
		llwarns << "Invalid transfer packet size " << size << llendl;
		return;
	}

	U8 tmp_data[MAX_PACKET_DATA_SIZE];
	if (size > 0)
	{
		// Only pull the data out if the size is > 0
		msgp->getBinaryData("TransferData", "Data", tmp_data, size);
	}

	if ((!ttp->gotInfo()) || (ttp->getNextPacketID() != packet_id))
	{
		// Put this on a list of packets to be delivered later.
		if(!ttp->addDelayedPacket(packet_id, status, tmp_data, size))
		{
			// Whoops - failed to add a delayed packet for some reason.
			llwarns << "Too many delayed packets processing transfer "
				<< transfer_id << " from " << msgp->getSender() << llendl;
			ttp->abortTransfer();
			ttcp->deleteTransfer(ttp);
			return;
		}
#if 0
		// Spammy!
		const S32 LL_TRANSFER_WARN_GAP = 10;
		if(!ttp->gotInfo())
		{
			llwarns << "Got data packet before information in transfer "
				<< transfer_id << " from " << msgp->getSender()
				<< ", got " << packet_id << llendl;
		}
		else if((packet_id - ttp->getNextPacketID()) > LL_TRANSFER_WARN_GAP)
		{
			llwarns << "Out of order packet in transfer " << transfer_id
				<< " from " << msgp->getSender() << ", got " << packet_id
				<< " expecting " << ttp->getNextPacketID() << llendl;
		}
#endif
		return;
	}

	// Loop through this until we're done with all delayed packets
	
	//
	// NOTE: THERE IS A CUT AND PASTE OF THIS CODE IN THE TRANSFERINFO HANDLER
	// SO WE CAN PLAY BACK DELAYED PACKETS THERE!!!!!!!!!!!!!!!!!!!!!!!!!
	//
	BOOL done = FALSE;
	while (!done)
	{
		LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size);
		if (ret_code == LLTS_OK)
		{
			ttp->setLastPacketID(packet_id);
		}

		if (status != LLTS_OK)
		{
			if (status != LLTS_DONE)
			{
				llwarns << "LLTransferManager::processTransferPacket Error in transfer!" << llendl;
			}
			else
			{
// 				llinfos << "LLTransferManager::processTransferPacket done for " << transfer_id << llendl;
			}
			// This transfer is done, either via error or not.
			ttp->completionCallback(status);
			ttcp->deleteTransfer(ttp);
			return;
		}

		// See if we've got any delayed packets
		packet_id = ttp->getNextPacketID();
		if (ttp->mDelayedPacketMap.find(packet_id) != ttp->mDelayedPacketMap.end())
		{
			// Perhaps this stuff should be inside a method in LLTransferPacket?
			// I'm too lazy to do it now, though.
// 			llinfos << "Playing back delayed packet " << packet_id << llendl;
			LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id];

			// This is somewhat inefficient, but avoids us having to duplicate
			// code between the off-the-wire and delayed paths.
			packet_id = packetp->mPacketID;
			size = packetp->mSize;
			if (size)
			{
				if ((packetp->mDatap != NULL) && (size<(S32)sizeof(tmp_data)))
				{
					memcpy(tmp_data, packetp->mDatap, size);	/*Flawfinder: ignore*/
				}
			}
			status = packetp->mStatus;
			ttp->mDelayedPacketMap.erase(packet_id);
			delete packetp;
		}
		else
		{
			// No matching delayed packet, abort it.
			done = TRUE;
		}
	}
}
//static
void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **)
{
	//llinfos << "LLTransferManager::processTransferInfo" << llendl;

	LLUUID transfer_id;
	LLTransferTargetType target_type;
	LLTransferChannelType channel_type;
	LLTSCode status;
	S32 size;

	msgp->getUUID("TransferInfo", "TransferID", transfer_id);
	msgp->getS32("TransferInfo", "TargetType", (S32 &)target_type);
	msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type);
	msgp->getS32("TransferInfo", "Status", (S32 &)status);
	msgp->getS32("TransferInfo", "Size", size);

	//llinfos << transfer_id << ":" << target_type<< ":" << channel_type << llendl;
	LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type);
	if (!ttcp)
	{
		llwarns << "Target channel not found" << llendl;
		// Should send a message to abort the transfer.
		return;
	}

	LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id);
	if (!ttp)
	{
		llwarns << "TransferInfo for unknown transfer!  Not able to handle this yet!" << llendl;
		// This could happen if we're doing a push transfer, although to avoid confusion,
		// maybe it should be a different message.
		return;
	}

	if (status != LLTS_OK)
	{
		llwarns << transfer_id << ": Non-ok status, cleaning up" << llendl;
		ttp->completionCallback(status);
		// Clean up the transfer.
		ttcp->deleteTransfer(ttp);
		return;
	}

	// unpack the params
	S32 params_size = msgp->getSize("TransferInfo", "Params");
	if(params_size > MAX_PARAMS_SIZE)
	{
		llwarns << "LLTransferManager::processTransferInfo params too big."
			<< llendl;
		return;
	}
	else if(params_size > 0)
	{
		U8 tmp[MAX_PARAMS_SIZE];
		msgp->getBinaryData("TransferInfo", "Params", tmp, params_size);
		LLDataPackerBinaryBuffer dpb(tmp, MAX_PARAMS_SIZE);
		if (!ttp->unpackParams(dpb))
		{
			// This should only happen if the data is corrupt or
			// incorrectly packed.
			llwarns << "LLTransferManager::processTransferRequest: bad params."
				<< llendl;
			ttp->abortTransfer();
			ttcp->deleteTransfer(ttp);
			return;
		}
	}

	llinfos << "Receiving " << transfer_id << ", size " << size << " bytes" << llendl;
	ttp->setSize(size);
	ttp->setGotInfo(TRUE);

	// OK, at this point we to handle any delayed transfer packets (which could happen
	// if this packet was lost)

	// This is a lame cut and paste of code down below.  If we change the logic down there,
	// we HAVE to change the logic up here.

	while (1)
	{
		S32 packet_id = 0;
		U8 tmp_data[MAX_PACKET_DATA_SIZE];
		// See if we've got any delayed packets
		packet_id = ttp->getNextPacketID();
		if (ttp->mDelayedPacketMap.find(packet_id) != ttp->mDelayedPacketMap.end())
		{
			// Perhaps this stuff should be inside a method in LLTransferPacket?
			// I'm too lazy to do it now, though.
// 			llinfos << "Playing back delayed packet " << packet_id << llendl;
			LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id];

			// This is somewhat inefficient, but avoids us having to duplicate
			// code between the off-the-wire and delayed paths.
			packet_id = packetp->mPacketID;
			size = packetp->mSize;
			if (size)
			{
				if ((packetp->mDatap != NULL) && (size<(S32)sizeof(tmp_data)))
				{
					memcpy(tmp_data, packetp->mDatap, size);	/*Flawfinder: ignore*/
				}
			}
			status = packetp->mStatus;
			ttp->mDelayedPacketMap.erase(packet_id);
			delete packetp;
		}
		else
		{
			// No matching delayed packet, we're done.
			break;
		}

		LLTSCode ret_code = ttp->dataCallback(packet_id, tmp_data, size);
		if (ret_code == LLTS_OK)
		{
			ttp->setLastPacketID(packet_id);
		}

		if (status != LLTS_OK)
		{
			if (status != LLTS_DONE)
			{
				llwarns << "LLTransferManager::processTransferInfo Error in playback!" << llendl;
			}
			else
			{
				llinfos << "LLTransferManager::processTransferInfo replay FINISHED for " << transfer_id << llendl;
			}
			// This transfer is done, either via error or not.
			ttp->completionCallback(status);
			ttcp->deleteTransfer(ttp);
			return;
		}
	}
}