diff options
Diffstat (limited to 'kopete/protocols/jabber/jabberfiletransfer.cpp')
-rw-r--r-- | kopete/protocols/jabber/jabberfiletransfer.cpp | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/kopete/protocols/jabber/jabberfiletransfer.cpp b/kopete/protocols/jabber/jabberfiletransfer.cpp new file mode 100644 index 00000000..fde5b105 --- /dev/null +++ b/kopete/protocols/jabber/jabberfiletransfer.cpp @@ -0,0 +1,326 @@ + /* + * jabberfiletransfer.cpp + * + * Copyright (c) 2004 by Till Gerken <till@tantalo.net> + * + * Kopete (c) by the Kopete developers <kopete-devel@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 <kdebug.h> +#include <im.h> +#include <xmpp.h> +#include "jabberfiletransfer.h" +#include <klocale.h> +#include <kmessagebox.h> +#include <kconfig.h> +#include "kopeteuiglobal.h" +#include "kopetemetacontact.h" +#include "kopetecontactlist.h" +#include "kopetetransfermanager.h" +#include "jabberaccount.h" +#include "jabberprotocol.h" +#include "jabberclient.h" +#include "jabbercontactpool.h" +#include "jabberbasecontact.h" +#include "jabbercontact.h" + +JabberFileTransfer::JabberFileTransfer ( JabberAccount *account, XMPP::FileTransfer *incomingTransfer ) +{ + kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "New incoming transfer from " << incomingTransfer->peer().full () << ", filename " << incomingTransfer->fileName () << ", size " << QString::number ( incomingTransfer->fileSize () ) << endl; + + mAccount = account; + mXMPPTransfer = incomingTransfer; + + // try to locate an exact match in our pool first + JabberBaseContact *contact = mAccount->contactPool()->findExactMatch ( mXMPPTransfer->peer () ); + + if ( !contact ) + { + // we have no exact match, try a broader search + contact = mAccount->contactPool()->findRelevantRecipient ( mXMPPTransfer->peer () ); + } + + if ( !contact ) + { + kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "No matching local contact found, creating a new one." << endl; + + Kopete::MetaContact *metaContact = new Kopete::MetaContact (); + + metaContact->setTemporary (true); + + contact = mAccount->contactPool()->addContact ( mXMPPTransfer->peer (), metaContact, false ); + + Kopete::ContactList::self ()->addMetaContact ( metaContact ); + } + + 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 & ) ) ); + + initializeVariables (); + + mTransferId = Kopete::TransferManager::transferManager()->askIncomingTransfer ( contact, + mXMPPTransfer->fileName (), + mXMPPTransfer->fileSize (), + mXMPPTransfer->description () ); + +} + +JabberFileTransfer::JabberFileTransfer ( JabberAccount *account, JabberBaseContact *contact, const QString &file ) +{ + kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "New outgoing transfer for " << contact->contactId() << ": " << file << endl; + + mAccount = account; + mLocalFile.setName ( file ); + mLocalFile.open ( IO_ReadOnly ); + + mKopeteTransfer = Kopete::TransferManager::transferManager()->addTransfer ( contact, + mLocalFile.name (), + mLocalFile.size (), + contact->contactId (), + Kopete::FileTransferInfo::Outgoing ); + + connect ( mKopeteTransfer, SIGNAL ( result ( KIO::Job * ) ), this, SLOT ( slotTransferResult () ) ); + + mXMPPTransfer = mAccount->client()->fileTransferManager()->createTransfer (); + + initializeVariables (); + + connect ( mXMPPTransfer, SIGNAL ( connected () ), this, SLOT ( slotOutgoingConnected () ) ); + connect ( mXMPPTransfer, SIGNAL ( bytesWritten ( int ) ), this, SLOT ( slotOutgoingBytesWritten ( int ) ) ); + connect ( mXMPPTransfer, SIGNAL ( error ( int ) ), this, SLOT ( slotTransferError ( int ) ) ); + + mXMPPTransfer->sendFile ( XMPP::Jid ( contact->fullAddress () ), KURL(file).fileName (), mLocalFile.size (), "" ); + +} + +JabberFileTransfer::~JabberFileTransfer () +{ + kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Destroying Jabber file transfer object." << endl; + + mLocalFile.close (); + + mXMPPTransfer->close (); + delete mXMPPTransfer; + +} + +void JabberFileTransfer::initializeVariables () +{ + + mTransferId = -1; + mBytesTransferred = 0; + mBytesToTransfer = 0; + mXMPPTransfer->setProxy ( XMPP::Jid ( mAccount->configGroup()->readEntry ( "ProxyJID" ) ) ); + +} + +void JabberFileTransfer::slotIncomingTransferAccepted ( Kopete::Transfer *transfer, const QString &fileName ) +{ + + if ( (long)transfer->info().transferId () != mTransferId ) + return; + + kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Accepting transfer for " << mXMPPTransfer->peer().full () << endl; + + mKopeteTransfer = transfer; + mLocalFile.setName ( fileName ); + + bool couldOpen = false; + Q_LLONG offset = 0; + Q_LLONG length = 0; + + mBytesTransferred = 0; + mBytesToTransfer = mXMPPTransfer->fileSize (); + + if ( mXMPPTransfer->rangeSupported () && mLocalFile.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 ) ) + { + case KMessageBox::Yes: // resume + couldOpen = mLocalFile.open ( IO_ReadWrite ); + if ( couldOpen ) + { + offset = mLocalFile.size (); + length = mXMPPTransfer->fileSize () - offset; + mBytesTransferred = offset; + mBytesToTransfer = length; + mLocalFile.at ( mLocalFile.size () ); + } + break; + + case KMessageBox::No: // overwrite + couldOpen = mLocalFile.open ( IO_WriteOnly ); + break; + + default: // cancel + deleteLater (); + return; + } + } + else + { + // overwrite by default + couldOpen = mLocalFile.open ( IO_WriteOnly ); + } + + if ( !couldOpen ) + { + transfer->slotError ( KIO::ERR_COULD_NOT_WRITE, fileName ); + + deleteLater (); + } + else + { + connect ( mKopeteTransfer, SIGNAL ( result ( KIO::Job * ) ), this, SLOT ( slotTransferResult () ) ); + connect ( mXMPPTransfer, SIGNAL ( readyRead ( const QByteArray& ) ), this, SLOT ( slotIncomingDataReady ( const QByteArray & ) ) ); + connect ( mXMPPTransfer, SIGNAL ( error ( int ) ), this, SLOT ( slotTransferError ( int ) ) ); + mXMPPTransfer->accept ( offset, length ); + } + +} + +void JabberFileTransfer::slotTransferRefused ( const Kopete::FileTransferInfo &transfer ) +{ + + if ( (long)transfer.transferId () != mTransferId ) + return; + + kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Local user refused transfer from " << mXMPPTransfer->peer().full () << endl; + + deleteLater (); + +} + +void JabberFileTransfer::slotTransferResult () +{ + + if ( mKopeteTransfer->error () == KIO::ERR_USER_CANCELED ) + { + kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Transfer with " << mXMPPTransfer->peer().full () << " has been canceled." << endl; + mXMPPTransfer->close (); + deleteLater (); + } + +} + +void JabberFileTransfer::slotTransferError ( int errorCode ) +{ + + switch ( errorCode ) + { + case XMPP::FileTransfer::ErrReject: + // user rejected the transfer request + mKopeteTransfer->slotError ( KIO::ERR_ACCESS_DENIED, + mXMPPTransfer->peer().full () ); + break; + + case XMPP::FileTransfer::ErrNeg: + // unable to negotiate a suitable connection for the file transfer with the user + mKopeteTransfer->slotError ( KIO::ERR_COULD_NOT_LOGIN, + mXMPPTransfer->peer().full () ); + break; + + case XMPP::FileTransfer::ErrConnect: + // could not connect to the user + mKopeteTransfer->slotError ( KIO::ERR_COULD_NOT_CONNECT, + mXMPPTransfer->peer().full () ); + break; + + case XMPP::FileTransfer::ErrStream: + // data stream was disrupted, probably cancelled + mKopeteTransfer->slotError ( KIO::ERR_CONNECTION_BROKEN, + mXMPPTransfer->peer().full () ); + break; + + default: + // unknown error + mKopeteTransfer->slotError ( KIO::ERR_UNKNOWN, + mXMPPTransfer->peer().full () ); + break; + } + + deleteLater (); + +} + +void JabberFileTransfer::slotIncomingDataReady ( const QByteArray &data ) +{ + + mBytesTransferred += data.size (); + mBytesToTransfer -= data.size (); + + mKopeteTransfer->slotProcessed ( mBytesTransferred ); + + mLocalFile.writeBlock ( data ); + + if ( mBytesToTransfer <= 0 ) + { + kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Transfer from " << mXMPPTransfer->peer().full () << " done." << endl; + + mKopeteTransfer->slotComplete (); + + deleteLater (); + } + +} + +void JabberFileTransfer::slotOutgoingConnected () +{ + + kdDebug ( JABBER_DEBUG_GLOBAL ) << k_funcinfo << "Outgoing data connection is open." << endl; + + mBytesTransferred = mXMPPTransfer->offset (); + mLocalFile.at ( mXMPPTransfer->offset () ); + mBytesToTransfer = ( mXMPPTransfer->fileSize () > mXMPPTransfer->length () ) ? mXMPPTransfer->length () : mXMPPTransfer->fileSize (); + + slotOutgoingBytesWritten ( 0 ); + +} + +void JabberFileTransfer::slotOutgoingBytesWritten ( int nrWritten ) +{ + + mBytesTransferred += nrWritten; + mBytesToTransfer -= nrWritten; + + mKopeteTransfer->slotProcessed ( mBytesTransferred ); + + if ( mBytesToTransfer ) + { + int nrToWrite = mXMPPTransfer->dataSizeNeeded (); + + QByteArray readBuffer ( nrToWrite ); + + mLocalFile.readBlock ( readBuffer.data (), nrToWrite ); + + mXMPPTransfer->writeFileData ( readBuffer ); + } + else + { + kdDebug(JABBER_DEBUG_GLOBAL) << k_funcinfo << "Transfer to " << mXMPPTransfer->peer().full () << " done." << endl; + + mKopeteTransfer->slotComplete (); + + deleteLater (); + } + +} + +#include "jabberfiletransfer.moc" |