www.pudn.com > fanccMSNr.src.rar > FileTransferModel.cpp


// TODO: Remove this #include and TRACE() 
#include "../stdafx.h" 
#include  
 
#include "MessengerModel.hpp" 
#include "ChatterModel.hpp" 
#include "BinaryMessage.hpp" 
 
namespace poral { 
	int FileTransferModel::newCookie=0; 
	int FileTransferModel::newAuthCookie=0; 
 
 
	FileTransferModel::FileTransferModel() { 
		messageDispatcher=NULL; 
		status=NOT_CONNECTED; 
		fileOut=NULL; 
		fileIn=NULL; 
		transferNotificationInterval=1; 
		retransmit=false; 
	} 
	FileTransferModel::~FileTransferModel() { 
		if(messageDispatcher!=NULL) { 
			delete messageDispatcher; 
		} 
		if(fileOut!=NULL) { 
			delete fileOut; 
			fileOut=NULL; 
		} 
		if(fileIn!=NULL) { 
			delete fileIn; 
			fileIn=NULL; 
		} 
	} 
	void FileTransferModel::connect( 
		ChatterModel &chatterModel,  
		const string &ip,  
		int port,  
		const string &authCookie,  
		const string &filename) { 
 
		this->chatterModel=&chatterModel; 
		this->authCookie=authCookie; 
		this->filename=filename; 
		if(fileOut!=NULL) { 
			delete fileOut; 
		} 
		fileOut=new ofstream(filename.data(), ios_base::out | ios_base::binary); 
 
		if(messageDispatcher==NULL) { 
			messageDispatcher=chatterModel.getMessengerModel().getMessageDispatcher()->newInstance(); 
			messageDispatcher->addMessageListener(*this); 
		} 
 
		messageDispatcher->connect(ip, port); 
		status=ATTEMPT_TO_RECEIVE; 
 
	} 
 
	int FileTransferModel::listen(ChatterModel &chatterModel, int preferredPort, const string &authCookie, const string &filename) { 
		this->chatterModel=&chatterModel; 
		this->authCookie=authCookie; 
		this->filename=filename; 
 
		if(fileIn!=NULL) { 
			delete fileIn; 
		} 
		fileIn=new ifstream(filename.data(), ios_base::in | ios_base::binary); 
 
		if(messageDispatcher==NULL) { 
			messageDispatcher=chatterModel.getMessengerModel().getMessageDispatcher()->newInstance(); 
			messageDispatcher->addMessageListener(*this); 
		} 
 
		int port=messageDispatcher->listen(preferredPort); 
		status=ATTEMPT_TO_SEND; 
 
		return port; 
	} 
 
	void FileTransferModel::connected() { 
		Message outMessage; 
 
		outMessage.setName("VER"); 
		outMessage.addArgument("MSNFTP"); 
 
		messageDispatcher->sendMessage(outMessage); 
	} 
 
	void FileTransferModel::sendable() { 
		if(status==SENDING) { 
			if(retransmit) { 
				if(messageDispatcher->sendBytes(buffer, nData+3)==false) { 
					retransmit=true; 
					return; 
				} 
				retransmit=false; 
			} 
			while(nTransferredlength) ? int(length-nTransferred) : maxBytesPerPacket; 
				 
				//TODO: handle read error!! 
				fileIn->read((char *)buffer+3, nData); 
				nTransferred+=nData; 
				nPackets++; 
				buffer[0]='0'; 
				buffer[1]=nData%256; 
				buffer[2]=nData/256; 
 
				if(transferNotificationInterval!=-1 && nPackets%transferNotificationInterval==0) { 
					fireFileTransferUpdate(FileTransferListener::PACKET_SEND); 
				} 
 
				if(messageDispatcher->sendBytes(buffer, nData+3)==false) { 
					retransmit=true; 
					return; 
				} 
			} 
		} 
	} 
 
 
	void FileTransferModel::messageArrived(const Message &message) { 
		const string &name=message.getName(); 
		Message outMessage; 
 
		if(name=="VER") { 
			if(status==ATTEMPT_TO_RECEIVE) { 
				MessengerModel &messengerModel=chatterModel->getMessengerModel(); 
				outMessage.setName("USR"); 
				outMessage.addArgument(messengerModel.getMy().ID); 
				outMessage.addArgument(authCookie); 
 
				messageDispatcher->sendMessage(outMessage); 
			} 
			else if(status==ATTEMPT_TO_SEND) { 
				outMessage.setName("VER"); 
				outMessage.addArgument("MSNFTP"); 
 
				messageDispatcher->sendMessage(outMessage); 
			} 
		} 
		else if(name=="USR") { 
			//TODO: check username and cookie 
			outMessage.setName("FIL"); 
			outMessage.addArgument((int)length); 
 
			messageDispatcher->sendMessage(outMessage); 
		} 
		else if(name=="TFR") { 
			status=SENDING; 
			nTransferred=0; 
			nPackets=0; 
			fireFileTransferUpdate(FileTransferListener::SENDING_STARTED); 
 
			sendable(); 
			// The bytes remaining will be send in sendable() 
		} 
		else if(name=="FIL") { 
			const string &lengthStr=message.getArgument(0); 
			istrstream lengthStream(lengthStr.data()); 
			lengthStream >> length; 
			 
			nTransferred=0; 
			nPackets=0; 
 
			outMessage.setName("TFR"); 
			messageDispatcher->sendMessage(outMessage); 
 
			status=RECEIVING; 
			fireFileTransferUpdate(FileTransferListener::RECEIVING_STARTED); 
		} 
		else if(name=="CCL") { 
			status=NOT_CONNECTED; 
			fireFileTransferUpdate(FileTransferListener::ABORT_BY_PEER); 
 
			messageDispatcher->close(); 
		} 
		else if(name=="BYE") { 
			status=NOT_CONNECTED; 
			TRACE("TRANSFER ENDED\n"); 
			messageDispatcher->close(); 
			fileIn->close(); 
			fireFileTransferUpdate(FileTransferListener::SENDING_ENDED); 
		} 
		else if(name=="BINARY") { 
			try { 
				const BinaryMessage &binaryMessage=dynamic_cast(message); 
				nTransferred+=binaryMessage.length; 
				const char *buffer=binaryMessage.data.data(); 
				fileOut->write(buffer, binaryMessage.data.size()); 
				nPackets++; 
				if(transferNotificationInterval!=-1 && nPackets%transferNotificationInterval==0) { 
					fireFileTransferUpdate(FileTransferListener::PACKET_RECEIVED); 
				} 
 
				if(nTransferred>=length) { 
					fileOut->close(); 
 
					outMessage.setName("BYE"); 
					outMessage.addArgument(16777989); 
					messageDispatcher->sendMessage(outMessage); 
					status=NOT_CONNECTED; 
					fireFileTransferUpdate(FileTransferListener::RECEIVING_ENDED); 
				} 
			} catch(bad_cast) { 
				// does noting 
			} 
 
		} 
		if(name=="CANCEL") { 
			failed(); 
		} 
	} 
	void FileTransferModel::failed() { 
		status=NOT_CONNECTED; 
		fireFileTransferUpdate(FileTransferListener::RECEIVEING_CANCELED); 
		if(fileOut!=NULL) { 
			delete fileOut; 
			fileOut=NULL; 
		} 
		if(fileIn!=NULL) { 
			delete fileIn; 
			fileIn=NULL; 
		} 
	} 
 
	void FileTransferModel::addFileTransferListener(FileTransferListener &listener) { 
		listeners.push_back(&listener); 
	} 
	void FileTransferModel::removeFileTransferListener(FileTransferListener &listener) { 
		list::iterator location=find(listeners.begin(), listeners.end(), &listener); 
		listeners.erase(location); 
	} 
 
 
	void FileTransferModel::fireFileTransferUpdate(FileTransferListener::Event event) { 
		list::iterator listener; 
		for(listener=listeners.begin(); listener!=listeners.end(); listener++) { 
			(*listener)->fileTransferUpdate(*this, event); 
		} 
	} 
 
}