/* * jabberfiletransfer.cpp * * Copyright (c) 2004 by Till Gerken * * Kopete (c) by the Kopete developers * * ************************************************************************* * * * * * 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 #include #include #include "jabberfiletransfer.h" #include #include #include #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 " << TQString::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 (), 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 & ) ) ); initializeVariables (); mTransferId = Kopete::TransferManager::transferManager()->askIncomingTransfer ( contact, mXMPPTransfer->fileName (), mXMPPTransfer->fileSize (), mXMPPTransfer->description () ); } JabberFileTransfer::JabberFileTransfer ( JabberAccount *account, JabberBaseContact *contact, const TQString &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, TQT_SIGNAL ( result ( KIO::Job * ) ), this, TQT_SLOT ( slotTransferResult () ) ); mXMPPTransfer = mAccount->client()->fileTransferManager()->createTransfer (); initializeVariables (); connect ( mXMPPTransfer, TQT_SIGNAL ( connected () ), this, TQT_SLOT ( slotOutgoingConnected () ) ); connect ( mXMPPTransfer, TQT_SIGNAL ( bytesWritten ( int ) ), this, TQT_SLOT ( slotOutgoingBytesWritten ( int ) ) ); connect ( mXMPPTransfer, TQT_SIGNAL ( error ( int ) ), this, TQT_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 TQString &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, TQT_SIGNAL ( result ( KIO::Job * ) ), this, TQT_SLOT ( slotTransferResult () ) ); connect ( mXMPPTransfer, TQT_SIGNAL ( readyRead ( const TQByteArray& ) ), this, TQT_SLOT ( slotIncomingDataReady ( const TQByteArray & ) ) ); connect ( mXMPPTransfer, TQT_SIGNAL ( error ( int ) ), this, TQT_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 TQByteArray &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 (); TQByteArray 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"