diff options
Diffstat (limited to 'kopete/protocols/gadu/gadudcctransaction.cpp')
-rw-r--r-- | kopete/protocols/gadu/gadudcctransaction.cpp | 454 |
1 files changed, 454 insertions, 0 deletions
diff --git a/kopete/protocols/gadu/gadudcctransaction.cpp b/kopete/protocols/gadu/gadudcctransaction.cpp new file mode 100644 index 00000000..561852fe --- /dev/null +++ b/kopete/protocols/gadu/gadudcctransaction.cpp @@ -0,0 +1,454 @@ +// -*- Mode: c++-mode; c-basic-offset: 2; indent-tabs-mode: t; tab-width: 2; -*- +// +// Copyright (C) 2004 Grzegorz Jaskiewicz <gj at pointblue.com.pl> +// +// 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., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. + +#include <fcntl.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include "kopetetransfermanager.h" +#include "kopetemetacontact.h" +#include "kopeteuiglobal.h" + +#include <qsocketnotifier.h> +#include <qfile.h> + +#include "gadudcctransaction.h" +#include "gaducontact.h" +#include "gaduaccount.h" +#include "gadudcc.h" + +#include "libgadu.h" + +GaduDCCTransaction::GaduDCCTransaction( GaduDCC* parent, const char* name ) +:QObject( 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, QString& filePath ) +{ + GaduContact* me; + GaduAccount* metoo; + + if ( !peerContact ) { + return false; + } + + me = static_cast<GaduContact*>( peerContact->account()->myself() ); + + QString aaa = peerContact->contactIp().toString(); + kdDebug( 14100 ) << "slotOutgoin for UIN: " << peerContact->uin() << " port " << peerContact->contactPort() << " ip " <<aaa<< endl; + kdDebug( 14100 ) << "File path is " << filePath << endl; + + if ( peerContact->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<GaduAccount*>( 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; + } + + QString aaa = peerContact->contactIp().toString(); + kdDebug( 14100 ) << "setupIncoming for UIN: " << uin << " port " << peerContact->contactPort() << " ip " <<aaa<< endl; + + peer = peerContact->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(), SIGNAL( accepted( Kopete::Transfer *, const QString & ) ), + this, SLOT( slotIncomingTransferAccepted ( Kopete::Transfer *, const QString & ) ) ); + connect ( Kopete::TransferManager::transferManager(), SIGNAL( refused( const Kopete::FileTransferInfo & ) ), + this, 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 QSocketNotifier( dccSock_->fd, QSocketNotifier::Read, this ); + read_->setEnabled( false ); + + write_ = new QSocketNotifier( dccSock_->fd, QSocketNotifier::Write, this ); + write_->setEnabled( false ); + + if ( connect ) { + QObject::connect( read_, SIGNAL( activated( int ) ), SLOT( watcher() ) ); + QObject::connect( write_, SIGNAL( activated( int ) ), 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 QString& 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 ( KIO::ERR_COULD_NOT_WRITE, fileName ); + closeDCC(); + deleteLater (); + return; + } + dccSock_->offset = 0; + dccSock_->file_fd = localFile_.handle(); + } + + connect ( transfer, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotTransferResult() ) ); + + // reenable notifiers + enableNotifiers( dccSock_->check ); + +} + +void +GaduDCCTransaction::slotTransferResult() +{ + if ( transfer_->error() == KIO::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, + QString( (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 fucked + 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, fuck it; + + // 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<GaduContact*> (account->contacts()[ QString::number( dccSock_->peer_uin ) ]); + } + else { + contact = static_cast<GaduContact*> (account->contacts()[ QString::number( peer ) ]); + } + + if ( contact == NULL ) { + // refusing, contact on the list + kdDebug(14100) << " dcc connection from " << dccSock_->peer_uin << " refused, UIN not on the list " <<endl; + gg_free_event( dccEvent ); + closeDCC(); + // emit error + deleteLater(); + return; + } + else { + // ask user to accept that transfer + kdDebug(14100) << " dcc accepted from " << dccSock_->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)) { + QString 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( KIO::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( KIO::ERR_SLAVE_DEFINED, i18n( "File transfer transaction was not agreed by peer." ) ); + break; + + case GG_ERROR_DCC_HANDSHAKE: + transfer_->slotError( KIO::ERR_SLAVE_DEFINED, i18n( "File-transfer handshake failure." ) ); + break; + case GG_ERROR_DCC_FILE: + transfer_->slotError( KIO::ERR_SLAVE_DEFINED, i18n( "File transfer had problems with the file." ) ); + break; + case GG_ERROR_DCC_NET: + transfer_->slotError( KIO::ERR_SLAVE_DEFINED, i18n( "There was network error during file transfer." ) ); + break; + default: + transfer_->slotError( KIO::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" |