// -*- Mode: c++-mode; c-basic-offset: 2; indent-tabs-mode: t; tab-width: 2; -*- // // Copyright (C) 2004 Grzegorz Jaskiewicz // // gadudcctransaction.cpp // // 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. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. #include #include #include #include #include #include #include #include #include "kopetetransfermanager.h" #include "kopetemetacontact.h" #include "kopeteuiglobal.h" #include #include #include "gadudcctransaction.h" #include "gaducontact.h" #include "gaduaccount.h" #include "gadudcc.h" #include "libgadu.h" GaduDCCTransaction::GaduDCCTransaction( GaduDCC* parent, const char* name ) :TQObject( parent, name ), gaduDCC_( parent ) { read_ = NULL; write_ = NULL; contact = NULL; transfer_ = NULL; dccSock_ = NULL; peer = 0; } GaduDCCTransaction::~GaduDCCTransaction() { closeDCC(); } unsigned int GaduDCCTransaction::recvUIN() { if ( dccSock_ ) { return dccSock_->uin; } return 0; } unsigned int GaduDCCTransaction::peerUIN() { if ( dccSock_ ) { return dccSock_->peer_uin; } return 0; } bool GaduDCCTransaction::setupOutgoing( GaduContact* peerContact, TQString& filePath ) { GaduContact* me; GaduAccount* metoo; if ( !peerContact ) { return false; } me = static_cast( peerContact->account()->myself() ); TQString aaa = peerContact->contactIp().toString(); kdDebug( 14100 ) << "slotOutgoin for UIN: " << peerContact->uin() << " port " << peerContact->contactPort() << " ip " <contactPort() >= 10 ) { dccSock_ = gg_dcc_send_file( htonl( peerContact->contactIp().ip4Addr() ), peerContact->contactPort(), me->uin(), peerContact->uin() ); gg_dcc_fill_file_info(dccSock_,filePath.ascii()); transfer_ = Kopete::TransferManager::transferManager()->addTransfer ( peerContact, filePath, dccSock_->file_info.size, peerContact->metaContact()->displayName(), Kopete::FileTransferInfo::Outgoing ); createNotifiers( true ); enableNotifiers( dccSock_->check ); } else { kdDebug( 14100 ) << "Peer " << peerContact->uin() << " is passive, requesting reverse connection" << endl; metoo = static_cast( me->account() ); gaduDCC_->requests[peerContact->uin()]=filePath; metoo->dccRequest( peerContact ); } return false; } bool GaduDCCTransaction::setupIncoming( const unsigned int uin, GaduContact* peerContact ) { if ( !peerContact ) { kdDebug( 14100 ) << "setupIncoming called with peerContact == NULL " << endl; return false; } TQString aaa = peerContact->contactIp().toString(); kdDebug( 14100 ) << "setupIncoming for UIN: " << uin << " port " << peerContact->contactPort() << " ip " <uin(); dccSock_ = gg_dcc_get_file( htonl( peerContact->contactIp().ip4Addr() ), peerContact->contactPort(), uin, peer ); contact = peerContact; return setupIncoming( dccSock_ ); } bool GaduDCCTransaction::setupIncoming( gg_dcc* dccS ) { if ( !dccS ) { kdDebug(14100) << "gg_dcc_get_file failed in GaduDCCTransaction::setupIncoming" << endl; return false; } dccSock_ = dccS; peer = dccS->uin; connect ( Kopete::TransferManager::transferManager(), TQT_SIGNAL( accepted( Kopete::Transfer *, const TQString & ) ), this, TQT_SLOT( slotIncomingTransferAccepted ( Kopete::Transfer *, const TQString & ) ) ); connect ( Kopete::TransferManager::transferManager(), TQT_SIGNAL( refused( const Kopete::FileTransferInfo & ) ), this, TQT_SLOT( slotTransferRefused( const Kopete::FileTransferInfo & ) ) ); incoming = true; createNotifiers( true ); enableNotifiers( dccSock_->check ); return true; } void GaduDCCTransaction::closeDCC() { kdDebug(14100) << "closeDCC()" << endl; disableNotifiers(); destroyNotifiers(); gg_dcc_free( dccSock_ ); dccSock_ = NULL; } void GaduDCCTransaction::destroyNotifiers() { disableNotifiers(); if ( read_ ) { delete read_; read_ = NULL; } if ( write_ ) { delete write_; write_ = NULL; } } void GaduDCCTransaction::createNotifiers( bool connect ) { if ( !dccSock_ ){ return; } read_ = new TQSocketNotifier( dccSock_->fd, TQSocketNotifier::Read, this ); read_->setEnabled( false ); write_ = new TQSocketNotifier( dccSock_->fd, TQSocketNotifier::Write, this ); write_->setEnabled( false ); if ( connect ) { TQObject::connect( read_, TQT_SIGNAL( activated( int ) ), TQT_SLOT( watcher() ) ); TQObject::connect( write_, TQT_SIGNAL( activated( int ) ), TQT_SLOT( watcher() ) ); } } void GaduDCCTransaction::enableNotifiers( int checkWhat ) { if( (checkWhat & GG_CHECK_READ) && read_ ) { read_->setEnabled( true ); } if( (checkWhat & GG_CHECK_WRITE) && write_ ) { write_->setEnabled( true ); } } void GaduDCCTransaction::disableNotifiers() { if ( read_ ) { read_->setEnabled( false ); } if ( write_ ) { write_->setEnabled( false ); } } void GaduDCCTransaction::slotIncomingTransferAccepted ( Kopete::Transfer* transfer, const TQString& fileName ) { if ( (long)transfer->info().transferId () != transferId_ ) { return; } transfer_ = transfer; localFile_.setName( fileName ); if ( localFile_.exists() ) { KGuiItem resumeButton( i18n ( "&Resume" ) ); KGuiItem overwriteButton( i18n ( "Over&write" ) ); switch ( KMessageBox::questionYesNoCancel( Kopete::UI::Global::mainWidget (), i18n( "The file %1 already exists, do you want to resume or overwrite it?" ).arg( fileName ), i18n( "File Exists: %1" ).arg( fileName ), resumeButton, overwriteButton ) ) { // resume case KMessageBox::Yes: if ( localFile_.open( IO_WriteOnly | IO_Append ) ) { dccSock_->offset = localFile_.size(); dccSock_->file_fd = localFile_.handle(); } break; // overwrite case KMessageBox::No: if ( localFile_.open( IO_ReadWrite ) ) { dccSock_->offset = 0; dccSock_->file_fd = localFile_.handle(); } break; // cancel default: closeDCC(); deleteLater(); return; break; } if ( localFile_.handle() < 1 ) { closeDCC(); deleteLater(); return; } } else { // overwrite by default if ( localFile_.open( IO_ReadWrite ) == FALSE ) { transfer->slotError ( TDEIO::ERR_COULD_NOT_WRITE, fileName ); closeDCC(); deleteLater (); return; } dccSock_->offset = 0; dccSock_->file_fd = localFile_.handle(); } connect ( transfer, TQT_SIGNAL( result( TDEIO::Job * ) ), this, TQT_SLOT( slotTransferResult() ) ); // reenable notifiers enableNotifiers( dccSock_->check ); } void GaduDCCTransaction::slotTransferResult() { if ( transfer_->error() == TDEIO::ERR_USER_CANCELED ) { closeDCC(); deleteLater(); } } void GaduDCCTransaction::slotTransferRefused ( const Kopete::FileTransferInfo& transfer ) { if ( (long)transfer.transferId () != transferId_ ) return; closeDCC(); deleteLater(); } void GaduDCCTransaction::askIncommingTransfer() { transferId_ = Kopete::TransferManager::transferManager()->askIncomingTransfer ( contact, TQString( (const char*)dccSock_->file_info.filename ), dccSock_->file_info.size ); } void GaduDCCTransaction::watcher() { gg_event* dccEvent; GaduAccount* account; disableNotifiers(); dccEvent = gg_dcc_watch_fd( dccSock_ ); if ( ! dccEvent ) { // connection is bad closeDCC(); return; } switch ( dccEvent->type ) { case GG_EVENT_DCC_CLIENT_ACCEPT: kdDebug(14100) << " GG_EVENT_DCC_CLIENT_ACCEPT " << endl; // check dccsock->peer_uin, if unknown, oh well; // is it for us ? account = gaduDCC_->account( dccSock_->uin ); if ( !account ) { kdDebug( 14100 ) << " this dcc transaction is for uin " << dccSock_->uin << ", which is not quite for me... closing" << endl; // unknown 'to' ?, we're off gg_free_event( dccEvent ); closeDCC(); deleteLater(); return; } if ( !peer ) { contact = static_cast (account->contacts()[ TQString::number( dccSock_->peer_uin ) ]); } else { contact = static_cast (account->contacts()[ TQString::number( peer ) ]); } if ( contact == NULL ) { // refusing, contact on the list kdDebug(14100) << " dcc connection from " << dccSock_->peer_uin << " refused, UIN not on the list " <peer_uin << endl; } break; case GG_EVENT_DCC_CALLBACK: kdDebug(14100) << "GG_DCC_EVENT_CALLBACK" << endl; break; case GG_EVENT_NONE: kdDebug(14100) << " GG_EVENT_NONE" << endl; // update gui with progress if ( transfer_ ) { transfer_->slotProcessed( dccSock_->offset ); } break; case GG_EVENT_DCC_NEED_FILE_ACK: kdDebug(14100) << " GG_EVENT_DCC_NEED_FILE_ACK " << endl; gg_free_event( dccEvent ); askIncommingTransfer(); return; break; case GG_EVENT_DCC_NEED_FILE_INFO: if (gaduDCC_->requests.contains(dccSock_->peer_uin)) { TQString filePath = gaduDCC_->requests[dccSock_->peer_uin]; kdDebug() << "Callback request found. Sending " << filePath << endl; gaduDCC_->requests.remove(dccSock_->peer_uin); gg_dcc_fill_file_info(dccSock_,filePath.ascii()); transfer_ = Kopete::TransferManager::transferManager()->addTransfer ( contact, filePath, dccSock_->file_info.size, contact->metaContact()->displayName(), Kopete::FileTransferInfo::Outgoing ); } else { gg_free_event( dccEvent ); closeDCC(); deleteLater(); return; } break; case GG_EVENT_DCC_ERROR: kdDebug(14100) << " GG_EVENT_DCC_ERROR :" << dccEvent->event.dcc_error << endl; if ( transfer_ ) { switch( dccEvent->event.dcc_error ) { case GG_ERROR_DCC_REFUSED: transfer_->slotError( TDEIO::ERR_SLAVE_DEFINED, i18n( "Connection to peer was refused; it possibly does not listen for incoming connections." ) ); break; case GG_ERROR_DCC_EOF: transfer_->slotError( TDEIO::ERR_SLAVE_DEFINED, i18n( "File transfer transaction was not agreed by peer." ) ); break; case GG_ERROR_DCC_HANDSHAKE: transfer_->slotError( TDEIO::ERR_SLAVE_DEFINED, i18n( "File-transfer handshake failure." ) ); break; case GG_ERROR_DCC_FILE: transfer_->slotError( TDEIO::ERR_SLAVE_DEFINED, i18n( "File transfer had problems with the file." ) ); break; case GG_ERROR_DCC_NET: transfer_->slotError( TDEIO::ERR_SLAVE_DEFINED, i18n( "There was network error during file transfer." ) ); break; default: transfer_->slotError( TDEIO::ERR_SLAVE_DEFINED, i18n( "Unknown File-Transfer error." ) ); break; } } gg_free_event( dccEvent ); closeDCC(); deleteLater(); return; case GG_EVENT_DCC_DONE: if ( transfer_ ) { transfer_->slotComplete(); } closeDCC(); deleteLater(); return; default: kdDebug(14100) << "unknown/unhandled DCC EVENT: " << dccEvent->type << endl; break; } if ( dccEvent ) { gg_free_event( dccEvent ); } enableNotifiers( dccSock_->check ); } #include "gadudcctransaction.moc"