diff options
Diffstat (limited to 'kopete/protocols/msn/msnfiletransfersocket.cpp')
-rw-r--r-- | kopete/protocols/msn/msnfiletransfersocket.cpp | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/kopete/protocols/msn/msnfiletransfersocket.cpp b/kopete/protocols/msn/msnfiletransfersocket.cpp new file mode 100644 index 00000000..b7121c30 --- /dev/null +++ b/kopete/protocols/msn/msnfiletransfersocket.cpp @@ -0,0 +1,481 @@ +/*************************************************************************** + msnfiletransfersocket.cpp - description + ------------------- + begin : mer jui 31 2002 + copyright : (C) 2002 by Olivier Goffart + email : ogoffart @ kde.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "msnfiletransfersocket.h" + +#include <stdlib.h> +#include <math.h> + +//qt +#include <tqtimer.h> + +// kde +#include <kdebug.h> +#include <kserversocket.h> +#include <kbufferedsocket.h> +#include <tdefiledialog.h> +#include <tdelocale.h> + +#include "kopetetransfermanager.h" +#include "kopetecontact.h" +#include "kopetemetacontact.h" +#include "msnchatsession.h" +#include "msnswitchboardsocket.h" +#include "msnnotifysocket.h" +#include "msnaccount.h" + +using namespace KNetwork; + +MSNFileTransferSocket::MSNFileTransferSocket(const TQString &handle, Kopete::Contact *c,bool incoming, TQObject* parent) + : MSNSocket(parent) , MSNInvitation(incoming, MSNFileTransferSocket::applicationID() , i18n("File Transfer - MSN Plugin")) +{ + m_handle=handle; + m_kopeteTransfer=0l; + m_file=0L; + m_server=0L; + m_contact=c; + ready=true; + + TQObject::connect( this, TQT_SIGNAL( socketClosed() ), this, TQT_SLOT( slotSocketClosed() ) ); + TQObject::connect( this, TQT_SIGNAL( blockRead( const TQByteArray & ) ), this, TQT_SLOT(slotReadBlock( const TQByteArray & ) ) ); +} + +MSNFileTransferSocket::~MSNFileTransferSocket() +{ + delete m_file; + delete m_server; + kdDebug(14140) << "MSNFileTransferSocket::~MSNFileTransferSocket" <<endl; +} + +void MSNFileTransferSocket::parseCommand(const TQString & cmd, uint id, const TQString & data) +{ + if( cmd == "VER" ) + { + if(data.section( ' ', 0, 0 ) != "MSNFTP") + { + kdDebug(14140) << "MSNFileTransferSocket::parseCommand (VER): bad version: disconnect" <<endl; + disconnect(); + } + else + { + if( m_incoming ) + sendCommand( "USR", m_handle + " " + m_authcook, false ); + else + sendCommand( "VER", "MSNFTP" , false ); + } + } + else if( cmd == "FIL" ) + { + m_size=id; //data.toUInt(); //BUG: the size is take as id bye MSNSocket because it is a number + + m_downsize=0; + m_file=new TQFile(m_fileName); + + if( m_file->open( IO_WriteOnly )) + sendCommand( "TFR" ,NULL,false); + else + { + kdDebug(14140) << "MSNFileTransferSocket::parseCommand: ERROR: unable to open file - disconnect " <<endl; + disconnect(); + } + } + else if( cmd == "BYE" ) + { + kdDebug(14140) << "MSNFileTransferSocket::parseCommand : end of transfer " <<endl; + disconnect(); + } + else if( cmd == "USR" ) + { + if(data.section( ' ', 1, 1 )!= m_authcook) + { + kdDebug(14140) << "MSNFileTransferSocket::parseCommand (USR): bad auth" <<endl; + disconnect(); + } + else + sendCommand("FIL" , TQString::number(size()) , false); + } + else if( cmd == "TFR" ) + { + m_downsize=0; + ready=true; + TQTimer::singleShot( 0, this, TQT_SLOT(slotSendFile()) ); + } + else if( cmd == "CCL" ) + { + disconnect(); + } + else + kdDebug(14140) << "MSNFileTransferSocket::parseCommand : unknown command " <<cmd <<endl; + +// kdDebug(14140) << "MSNFileTransferSocket::parseCommand : done " <<cmd <<endl; +} + +void MSNFileTransferSocket::doneConnect() +{ + if(m_incoming) + sendCommand( "VER", "MSNFTP", false ); + MSNSocket::doneConnect(); +} + +void MSNFileTransferSocket::bytesReceived(const TQByteArray & head) +{ + if(head[0]!='\0') + { + kdDebug(14140) << "MSNFileTransferSocket::bytesReceived: transfer aborted" <<endl; + TQTimer::singleShot(0,this,TQT_SLOT(disconnect())); + } + unsigned int sz=(int)((unsigned char)head.data()[2])*256+(int)((unsigned char)head.data()[1]); +// kdDebug(14140) << "MSNFileTransferSocket::bytesReceived: " << sz <<endl; + readBlock(sz); +} + +void MSNFileTransferSocket::slotSocketClosed() +{ + kdDebug(14140) << "MSNFileTransferSocket::slotSocketClose "<< endl; + if(m_file) + m_file->close(); + delete m_file; + m_file=0L; + delete m_server; + m_server=0L; + if(m_kopeteTransfer) + { + if( (m_downsize!=m_size || m_downsize==0 ) ) + m_kopeteTransfer->slotError( TDEIO::ERR_UNKNOWN , i18n( "An unknown error occurred" ) ); + else + m_kopeteTransfer->slotComplete(); + } + emit done(this); +} + +void MSNFileTransferSocket::slotReadBlock(const TQByteArray &block) +{ + m_file->writeBlock( block.data(), block.size() ); // write to file + + m_downsize+=block.size(); + if(m_kopeteTransfer) m_kopeteTransfer->slotProcessed(m_downsize); + kdDebug(14140) << "MSNFileTransferSocket - " << m_downsize << " of " << m_size <<" done"<<endl; + + if(m_downsize==m_size) + { + //the transfer seems to be finished. + sendCommand( "BYE" ,"16777989",false); + // if we are not already disconected in 30 seconds, do it. + TQTimer::singleShot( 30000 , this, TQT_SLOT(disconnect() ) ); + + } +} + +void MSNFileTransferSocket::setKopeteTransfer(Kopete::Transfer *kt) +{ + m_kopeteTransfer=kt; + if(kt) + { + TQObject::connect(kt , TQT_SIGNAL(transferCanceled()), this, TQT_SLOT(abort())); + TQObject::connect(kt, TQT_SIGNAL(destroyed()) , this , TQT_SLOT(slotKopeteTransferDestroyed())); + } +} + +void MSNFileTransferSocket::listen(int port) +{ + m_server = new TDEServerSocket(); + + TQObject::connect( m_server, TQT_SIGNAL(readyAccept()), this, TQT_SLOT(slotAcceptConnection())); + m_server->setAddress(TQString::number(port)); + + kdDebug(14140) << "MSNFileTransferSocket::listen: about to listen"<<endl; + bool listenResult = m_server->listen(1); + kdDebug(14140) << "MSNFileTransferSocket::listen: result: "<< listenResult <<endl; + TQTimer::singleShot( 60000, this, TQT_SLOT(slotTimer()) ); + kdDebug(14140) << "MSNFileTransferSocket::listen done" <<endl; +} + +void MSNFileTransferSocket::slotAcceptConnection() +{ + kdDebug(14140) << "MSNFileTransferSocket::slotAcceptConnection" <<endl; + if(!accept(m_server)) + { + if( m_kopeteTransfer) + m_kopeteTransfer->slotError( TDEIO::ERR_UNKNOWN , i18n( "An unknown error occurred" ) ); + emit done(this); + } +} + +void MSNFileTransferSocket::slotTimer() +{ + if(onlineStatus() != Disconnected) + return; + kdDebug(14140) << "MSNFileTransferSocket::slotTimer: timeout "<< endl; + if( m_kopeteTransfer) + { + m_kopeteTransfer->slotError( TDEIO::ERR_CONNECTION_BROKEN , i18n( "Connection timed out" ) ); + } + + MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager()); + if(manager && manager->service()) + manager->service()->sendCommand( "MSG" , "N", true, rejectMessage("TIMEOUT") ); + + emit done(this); +} + +void MSNFileTransferSocket::abort() +{ + if(m_incoming) + { + sendCommand( "CCL" , NULL ,false); + } + else + { + TQByteArray bytes(3); + bytes[0]='\1'; + bytes[1]='\0'; + bytes[2]='\0'; + sendBytes( bytes ); + m_downsize=m_size; //we don't want to send data anymore; + } + //the timer wait one second, the time to send the CCL or the binary header + //retarding the disconnection keep away from a crash. (in TDEIO::Job::emitResult when `delete this`) + TQTimer::singleShot( 1000, this, TQT_SLOT(disconnect()) ); + ready=false; +} + +void MSNFileTransferSocket::setFile( const TQString &fn, long unsigned int fileSize ) +{ + m_fileName=fn; + if(!m_incoming) + { + if(m_file) + { + kdDebug(14140) << "MSNFileTransferSocket::setFileName: WARNING m_file already exists" << endl; + delete m_file; + } + m_file = new TQFile( fn ); + if(!m_file->open(IO_ReadOnly)) + { + //FIXME: abort transfer here + kdDebug(14140) << "MSNFileTransferSocket::setFileName: WARNING unable to open the file" << endl; + } + + //If the fileSize is 0 it was not given, we are to get it from the file + if(fileSize == 0L) + m_size = m_file->size(); + else + m_size = fileSize; + } +} + + +void MSNFileTransferSocket::slotSendFile() +{ +// kdDebug(14140) <<"MSNFileTransferSocket::slotSendFile()" <<endl; + if( m_downsize >= m_size) + { + //the transfer seems to be finished. + // if we are not already disconected in 30 seconds, do it. + TQTimer::singleShot( 30000 , this, TQT_SLOT(disconnect() ) ); + return; + } + + if(ready) + { + char data[2046]; + int bytesRead = m_file->readBlock( data, 2045 ); + + TQByteArray block(bytesRead+3); +// char i1= (char)fmod( bytesRead, 256 ) ; +// char i2= (char)floor( bytesRead / 256 ) ; +// kdDebug(14140) << "MSNFileTransferSocket::slotSendFile: " << (int)i1 <<" + 256* "<< (int)i2 <<" = " << bytesRead <<endl; + block[0]='\0'; + block[1]= (char)fmod( bytesRead, 256 ); + block[2]= (char)floor( bytesRead / 256 ); + + for ( int f = 0; f < bytesRead; f++ ) + { + block[f+3] = data[f]; + } + + sendBytes(block); + + m_downsize+=bytesRead; + if(m_kopeteTransfer) + m_kopeteTransfer->slotProcessed(m_downsize); + kdDebug(14140) << "MSNFileTransferSocket::slotSendFile: " << m_downsize << " of " << m_size <<" done"<<endl; + } + ready=false; + + TQTimer::singleShot( 10, this, TQT_SLOT(slotSendFile()) ); +} + +void MSNFileTransferSocket::slotReadyWrite() +{ + ready=true; + MSNSocket::slotReadyWrite(); +} + +TQString MSNFileTransferSocket::invitationHead() +{ + TQTimer::singleShot( 10 * 60000, this, TQT_SLOT(slotTimer()) ); //the user has 10 mins to accept or refuse or initiate the transfer + + return TQString( MSNInvitation::invitationHead()+ + "Application-File: "+ m_fileName.right( m_fileName.length() - m_fileName.findRev( '/' ) - 1 ) +"\r\n" + "Application-FileSize: "+ TQString::number(size()) +"\r\n\r\n").utf8(); +} + +void MSNFileTransferSocket::parseInvitation(const TQString& msg) +{ + TQRegExp rx("Invitation-Command: ([A-Z]*)"); + rx.search(msg); + TQString command=rx.cap(1); + if( msg.contains("Invitation-Command: INVITE") ) + { + rx=TQRegExp("Application-File: ([^\\r\\n]*)"); + rx.search(msg); + TQString filename = rx.cap(1); + rx=TQRegExp("Application-FileSize: ([0-9]*)"); + rx.search(msg); + unsigned long int filesize= rx.cap(1).toUInt(); + + MSNInvitation::parseInvitation(msg); //for the cookie + + Kopete::TransferManager::transferManager()->askIncomingTransfer( m_contact , filename, filesize, TQString(), TQString::number( cookie() ) ); + + TQObject::connect( Kopete::TransferManager::transferManager(), TQT_SIGNAL( accepted( Kopete::Transfer *, const TQString& ) ),this, TQT_SLOT( slotFileTransferAccepted( Kopete::Transfer *, const TQString& ) ) ); + TQObject::connect( Kopete::TransferManager::transferManager(), TQT_SIGNAL( refused( const Kopete::FileTransferInfo & ) ), this, TQT_SLOT( slotFileTransferRefused( const Kopete::FileTransferInfo & ) ) ); + + } + else if( msg.contains("Invitation-Command: ACCEPT") ) + { + if(incoming()) + { + rx=TQRegExp("IP-Address: ([0-9\\.]*)"); + rx.search(msg); + TQString ip_address = rx.cap(1); + rx=TQRegExp("AuthCookie: ([0-9]*)"); + rx.search(msg); + TQString authcook = rx.cap(1); + rx=TQRegExp("Port: ([0-9]*)"); + rx.search(msg); + TQString port = rx.cap(1); + + setAuthCookie(authcook); + connect(ip_address, port.toUInt()); + } + else + { + unsigned long int auth = (rand()%(999999))+1; + setAuthCookie(TQString::number(auth)); + + setKopeteTransfer(Kopete::TransferManager::transferManager()->addTransfer(m_contact, fileName(), size(), m_contact->metaContact() ? m_contact->metaContact()->displayName() : m_contact->contactId() , Kopete::FileTransferInfo::Outgoing)); + + MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager()); + if(manager && manager->service()) + { + MSNNotifySocket *notify=static_cast<MSNAccount*>(manager->account())->notifySocket(); + if(notify){ + + TQCString message=TQString( + "MIME-Version: 1.0\r\n" + "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n" + "\r\n" + "Invitation-Command: ACCEPT\r\n" + "Invitation-Cookie: " + TQString::number(cookie()) + "\r\n" + "IP-Address: " + notify->localIP() + "\r\n" + "Port: 6891\r\n" + "AuthCookie: "+TQString::number(auth)+"\r\n" + "Launch-Application: FALSE\r\n" + "Request-Data: IP-Address:\r\n\r\n").utf8(); + + manager->service()->sendCommand( "MSG" , "N", true, message ); + } + } + + listen(6891); + } + } + else //CANCEL + { + MSNInvitation::parseInvitation(msg); + if( m_kopeteTransfer) + m_kopeteTransfer->slotError( TDEIO::ERR_ABORTED , i18n( "The remote user aborted" ) ); + emit done(this); + + } +} + +void MSNFileTransferSocket::slotFileTransferAccepted(Kopete::Transfer *trans, const TQString& fileName) +{ + if(trans->info().internalId().toULong() != cookie()) + return; + + if(!trans->info().contact()) + return; + + setKopeteTransfer(trans); + + MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager()); + + if(manager && manager->service()) + { + setFile(fileName); + + TQCString message=TQString( + "MIME-Version: 1.0\r\n" + "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n" + "\r\n" + "Invitation-Command: ACCEPT\r\n" + "Invitation-Cookie: " + TQString::number(cookie()) + "\r\n" + "Launch-Application: FALSE\r\n" + "Request-Data: IP-Address:\r\n" ).utf8(); + manager->service()->sendCommand( "MSG" , "N", true, message ); + + TQTimer::singleShot( 3 * 60000, this, TQT_SLOT(slotTimer()) ); //if after 3 minutes the transfer has not begin, delete this + } + else + { + if( m_kopeteTransfer) + m_kopeteTransfer->slotError( TDEIO::ERR_UNKNOWN , i18n( "An unknown error occurred" ) ); + emit done(this); + + } +} + +void MSNFileTransferSocket::slotFileTransferRefused(const Kopete::FileTransferInfo &info) +{ + if(info.internalId().toULong() != cookie()) + return; + + if(!info.contact()) + return; + + MSNChatSession* manager=dynamic_cast<MSNChatSession*>(m_contact->manager()); + + if(manager && manager->service()) + { + manager->service()->sendCommand( "MSG" , "N", true, rejectMessage() ); + } + + emit done(this); +} + +void MSNFileTransferSocket::slotKopeteTransferDestroyed() +{ + m_kopeteTransfer=0L; +} + + +#include "msnfiletransfersocket.moc" + |