You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
455 lines
12 KiB
455 lines
12 KiB
// -*- 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
// 02110-1301, 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 <tqsocketnotifier.h>
|
|
#include <tqfile.h>
|
|
|
|
#include "gadudcctransaction.h"
|
|
#include "gaducontact.h"
|
|
#include "gaduaccount.h"
|
|
#include "gadudcc.h"
|
|
|
|
#include "libgadu.h"
|
|
|
|
GaduDCCTransaction::GaduDCCTransaction( GaduDCC* tqparent, const char* name )
|
|
:TQObject( tqparent, name ), gaduDCC_( tqparent )
|
|
{
|
|
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<GaduContact*>( peerContact->account()->myself() );
|
|
|
|
TQString 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;
|
|
}
|
|
|
|
TQString 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(), 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?" ).tqarg( fileName ),
|
|
i18n( "File Exists: %1" ).tqarg( 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, TQT_SIGNAL( result( KIO::Job * ) ), this, TQT_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,
|
|
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 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()[ TQString::number( dccSock_->peer_uin ) ]);
|
|
}
|
|
else {
|
|
contact = static_cast<GaduContact*> (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 " <<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.tqcontains(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( 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"
|