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(nTransferred length) ? 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); } } }