Logo Search packages:      
Sourcecode: kmess version File versions

filetransferp2p.cpp

/***************************************************************************
                          filetransferp2p.cpp -  description
                             -------------------
    begin                : Sun 12 19 2004
    copyright            : (C) 2004 by Diederik van der Boor
    email                : vdboor --at-- codingdomain.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "filetransferp2p.h"

#include "../mimemessage.h"
#include "../p2pmessage.h"
#include "../../msnobject.h"
#include "../../kmessdebug.h"
#include "../../thumbnailprovider.h"
#include "../../dialogs/transferentryinterface.h"
#include "../../dialogs/transferentry.h"
#include "../../dialogs/transferwindow.h"

#include <qfile.h>
#include <qregexp.h>
#include <qstylesheet.h>

#include <kdebug.h>
#include <kmdcodec.h>
#include <klocale.h>
#include <kurl.h>
#include <kfiledialog.h>
#include <kiconloader.h>
#include <kmessagebox.h>


/**
 * The constructor for the FileTransferP2P class, without filename (sufficient for incoming sessions)
 *
 * @param  applicationList  The shared sources for the contact.
 */
00047 FileTransferP2P::FileTransferP2P(ApplicationList *applicationList)
  : P2PApplication(applicationList),
  file_(0),
  fileSize_(0),
  thumbnailProvider_(0),
  transferPanel_(0)
{
}



/**
 * The constructor for the FileTransferP2P, with filename to start a session
 *
 * @param  applicationList  The shared sources for the contact.
 * @param  filename         Filename of the file to send.
 */
00064 FileTransferP2P::FileTransferP2P(ApplicationList *applicationList, const QString &filename)
  : P2PApplication(applicationList),
  file_(0),
  fileName_(filename),
  fileSize_(0),
  thumbnailProvider_(0),
  transferPanel_(0)
{
}



/**
 * Destructor, closes the file if it's open.
 */
00079 FileTransferP2P::~FileTransferP2P()
{
  // Make sure the transfer panel displays the cancel state
  if(transferPanel_ != 0)
  {
    // The object can be deleted by the user
    transferPanel_->failTransfer();
    transferPanel_ = 0;
  }

  // Close the file
  // Delete thumbnail provider.
  delete file_;
  delete thumbnailProvider_;
}



/**
 * Step one of a contact-started chat: the contact invites the user
 *
 * @param  message  The invitation message
 */
00102 void FileTransferP2P::contactStarted1_ContactInvitesUser(const MimeMessage &message)
{
#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P - contactStarted1_ContactInvitesUser" << endl;
#endif
#ifdef KMESSTEST
  ASSERT( transferPanel_ == 0 );
#endif

  // First stage of the file transfer: initiate the session

  // Read the values from the message
  unsigned long int appID   = message.getValue("AppID").toUInt();
  QString           context = message.getValue("Context");

  if(appID != 2)
  {
    kdWarning() << "FileTransferP2P: Received unexpected AppID: " << appID << "." << endl;

    // Wouldn't know what to do if the AppID is not 2, so send an 500 Internal Error back.
    showMessage( i18n("The file transfer invitation was cancelled.  Bad data was received.") );
    sendCancelMessage( CANCEL_ABORT );
    return;
  }


  // The context field contains file transfer data.
  QByteArray encodedContext;
  QByteArray decodedContext;
  encodedContext.duplicate(context.data(), context.length());
  KCodecs::base64Decode(encodedContext, decodedContext);

  // Just to be on the safe side, check the buffer size before we start copying.
  if( context.length() <= 24 )
  {
    kdWarning() << "KMess: File transfer context field has bad formatting, "
                << "ignoring invite (context=" << context << ", contact=" << getContactHandle() << ")." << endl;
    showMessage( i18n("The file transfer invitation was cancelled.  Bad data was received.") );
    sendCancelMessage( CANCEL_ABORT );
    return;
  }


  // Extract the simple fields from the context string.
  unsigned int  fieldsLength = P2PMessage::extractBytes(decodedContext,  0);  // field 1: length of fields 1-6
  unsigned int  unknown      = P2PMessage::extractBytes(decodedContext,  4);  // field 2: unknown. (usually 2)
                fileSize_    = P2PMessage::extractBytes(decodedContext,  8);  // field 3: file size
  unsigned int  noPreview    = P2PMessage::extractBytes(decodedContext, 16);  // field 4: 1 if NO preview available.

  // Again, I don't want KMess to crash or being exploited.
  if( fieldsLength > decodedContext.size() || fieldsLength < 24 )
  {
    kdWarning() << "KMess: File transfer context field has bad formatting, rejecting invite"
                << " (length=" << fieldsLength << ", contact=" << getContactHandle() << ")" << endl;
    showMessage( i18n("The file transfer invitation was cancelled.  Bad data was received.") );
    sendCancelMessage( CANCEL_ABORT );
    return;
  }


  // field 6: most likely a splitter mark between the file name and preview fields. It's always 0xFFFFFFFF

  // TODO: fix detection of the splitter message.
  unsigned int splitter = P2PMessage::extractBytes( decodedContext, fieldsLength - 4 );
  if( splitter != 0xFFFFFFFF )
  {
    kdWarning() << "KMess: File transfer context field has bad formatting "
                << "(splitter not found, found 0x" << QString::number( splitter, 16 )
                << " contact=" << getContactHandle() << ")." << endl;
//    return;
  }

  // field 5: the file name
  unsigned int filenameLength = (fieldsLength - 40); // 24 bytes = 4 dwords, 1 qword (fields 1-4 and 6.)

  void    *pointer   = decodedContext.data() + 20;
  suggestedFileName_ = QString::fromUcs2( (unsigned short*) pointer );


  // After field 6: the preview data.
  QByteArray rawPreviewData;
  QString    previewData;
  if( noPreview )
  {
    // Generate a default preview icon
    KIconLoader *loader = KGlobal::iconLoader();
    QString iconTitle   = KMimeType::iconForURL( KURL( suggestedFileName_ ) );
    preview_            = QImage( loader->iconPath( iconTitle, 48, false ) );

    // Save as PNG for encoding
    QBuffer buffer( rawPreviewData );
    buffer.open( IO_WriteOnly );
    preview_.save( &buffer, "PNG" );

    // Encode to Base64 for inline image.
    previewData = KCodecs::base64Encode( rawPreviewData );

#ifdef KMESSDEBUG_FILETRANSFER_P2P
    kdDebug() << "FileTransferP2P: Using icon '" << iconTitle << "' as preview." << endl;
#endif
  }
  else
  {
    // Determine position of the preview data.
    const char *previewStart  = decodedContext.data() + fieldsLength;
    const uint  previewLength = decodedContext.size() - fieldsLength;

    // Temporary wrap the data as QByteArray to read id.
    rawPreviewData.setRawData( previewStart, previewLength );

    // Read preview data
    previewData = KCodecs::base64Encode( rawPreviewData );
    preview_    = QImage( rawPreviewData );

    // Reset it again
    rawPreviewData.resetRawData( previewStart, previewLength );

#ifdef KMESSDEBUG_FILETRANSFER_P2P
    kdDebug() << "FileTransferP2P: Encoded data size: " << previewData.length() << endl;
#endif
  }


  // Everything seams OK, allow the user to accept the file.
  // Generate accept message
  QString html = i18n( "Do you want to accept the file: %1 (%2 bytes)" )
                 .arg( "<span class=\"filename invitedFilename\">" + suggestedFileName_ + "</span>" )
                 .arg( fileSize_ );

  // Add preview to the top
  if( ! noPreview )
  {
    QString imageHtml = "<img src=\"data:image/png;base64," + previewData   + "\""
                        " width=\""  + QString::number( preview_.width() )  + "\""
                        " height=\"" + QString::number( preview_.height() ) + "\""
                        " alt=\""    + QStyleSheet::escape( suggestedFileName_ ) + "\" /><br />";
    html = imageHtml + html;
  }


  // Display the accept message.
#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P: File to transfer is " << suggestedFileName_ << ", "
            << "waiting for user to accept." << endl;
#endif

  offerAcceptOrReject( html );
}



/**
 * Step two of a contact-started chat: the user accepts.
 */
00256 void FileTransferP2P::contactStarted2_UserAccepts()
{
#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P - contactStarted2_UserAccepts" << endl;
#endif

#ifdef KMESSTEST
  ASSERT( file_ == 0          );
  ASSERT( fileName_.isEmpty() );
  ASSERT( transferPanel_ == 0 );
#endif

  bool success;
  QString startFolder;  // QString::null by default
  QString recentFolderTag = ":filedownload";

  // Open a file dialog so that the user can save the file to a particular directory and name.
  bool hasFile = false;
  while( ! hasFile )
  {
    // Set an initial path to the file
    KURL startDir = KFileDialog::getStartURL( startFolder, recentFolderTag );
    startDir.addPath( suggestedFileName_ );

    // Ask the user for a file.
    fileName_ = KFileDialog::getSaveFileName( startDir.url() );

    if( fileName_.isNull() )
    {
#ifdef KMESSDEBUG_FILETRANSFER_P2P
      kdDebug() << "FileTransferP2P::contactStarted2_UserAccepts: User cancelled in file save dialog" << endl;
#endif

      // Dialog cancelled, cancel afterall
      userRejected();
      return;
    }

    hasFile = true;
    QString shortName = fileName_.right( fileName_.length() - fileName_.findRev("/") - 1 );

    // Check if the selected file exists and if the user wants to overwrite it.
    // The while loop is for the prompt to keep appearing if the user
    // chooses the same filename but does not want to overwrite the file.
    if( QFile::exists(fileName_) )
    {
      if( KMessageBox::warningContinueCancel( 0,
            i18n("The file '%1' already exists.\ndo you want to overwrite it?").arg(shortName),
            i18n("Overwrite File"), KGuiItem( i18n("Over&write") ) ) == KMessageBox::Cancel )
      {
        // User does not want to override
        hasFile     = false;
        startFolder = fileName_.left( fileName_.findRev("/") );
      }
    }
  }


  // Now we try to open the file
  file_   = new QFile(fileName_);
  success = (file_ != 0) && file_->open(IO_WriteOnly);

  if( ! success )
  {
#ifdef KMESSDEBUG_FILETRANSFER_P2P
    kdDebug() << "FileTransferP2P::contactStarted2_UserAccepts: Cancelling session" << endl;
#endif

    // Notify the user, even if debug mode is not enabled.
    kdDebug() << "WARNING - Unable to open file: " << fileName_ << "!" << endl;

    // Close the file (also causes gotData() to fail)
    delete file_;
    file_ = 0;

    // Tell the user about it
    showMessage( i18n("The transfer of %1 failed.  Couldn't open file")
                 .arg("<span class=\"filename failedFilename\">" + fileName_ + "</span>") );

    // Send 500 Internal Error back if we failed (this is still the accept stage)
    sendCancelMessage(CANCEL_ABORT);
    return;
  }


#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P::contactStarted2_UserAccepts: Sending accept message" << endl;
#endif

  // Initialize the progress dialog
  initializeProgressDialog(true, fileSize_);
  showTransferMessage( i18n("File transfer dialog message", "Negotiating options to connect") );

  // Create the message
  MimeMessage message;
  message.addField( "SessionID", QString::number( getInvitationSessionID() ) );

  // Send the ACCEPT message
  sendSlpOkMessage(message);
}



/**
 * Step three of a contact-started chat: the contact confirms the accept
 *
 * @param  message  The message of the other contact, not usefull in P2P sessions because it's an ACK.
 */
00364 void FileTransferP2P::contactStarted3_ContactConfirmsAccept(const MimeMessage &/*message*/)
{
#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P - contactStarted3_ContactConfirmsAccept" << endl;
#endif

  // When the 200 OK message is accepted, the contact sends
  // another invitation with a different content-type, and the
  // contactStarted1_ContactInvitesUser() is called again.

  // The second time, the contact initiates the file transfer based
  // on the fields we sent in the second 200 OK message.
  // Once that message is received, the gotData() handles the rest.
}



/**
 * Step four in a contact-started chat: the contact confirms the data preparation message.
 */
00384 void FileTransferP2P::contactStarted4_ContactConfirmsPreparation()
{
#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P - contactStarted4_ContactConfirmsPreparation" << endl;
#endif
}



/**
 * @brief Create the context field.
 *
 * This field is used in the invitation message.
 *
 * @param  filename    Full path to the filename.
 * @param  fileData    The handle to the opened file.
 * @param  usePreview  Whether to use the preview in thumbnailProvider_
 */
00402 QString FileTransferP2P::createContextField( const QString &filename, const QFile *fileData, bool usePreview ) const
{
  // Get the thumbnail results.
  bool hasPreview = ( usePreview && thumbnailProvider_ != 0 && thumbnailProvider_->isSuccessful() );
  QByteArray previewData;

  // Only generate preview if requested and object exists.
  if( hasPreview )
  {
    previewData = thumbnailProvider_->getData();
  }

#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P: creating context field "
            << ( usePreview ? "with thumbnail." : "without thumbnail." ) << endl;
#endif

  // Create the short name
  QString shortName       = filename.right( filename.length() - filename.findRev( QRegExp("/") ) - 1 );
  uint    shortNameLength = shortName.length();

  // Get the file data (preview
  int  filesize      = fileData->size();
  int  flags         = (hasPreview ? 0 : 1);

  // Determine the context length
  uint length         = 574;  // Somehow MSN always uses 550 bytes for the filename (+24 for the size of fields 1-6).
  uint totalLength    = length + previewData.size();


  // Fill the context parameter
  QByteArray context( totalLength );
  context.fill(0x00);

  P2PMessage::insertBytes( context, length,    0 );  // Field 1: Length of fields 1-6
  P2PMessage::insertBytes( context, 2,         4 );  // Field 2: somehow this is always 2
  P2PMessage::insertBytes( context, filesize,  8 );  // Field 3: file size (QWord)
  P2PMessage::insertBytes( context, flags,    16 );  // Field 4: 1 if NO preview data

  // Field 5: the file name
  const unsigned short * utf16Name = shortName.ucs2();
  int offset = 20;
  for(uint i = 0; i < shortNameLength; ++i)
  {
    P2PMessage::insertShortBytes(context, utf16Name[i], offset);
    offset += 2;
  }

  P2PMessage::insertBytes(context, 0xFFFFFFFF, 570); // Field 6: some splitter field.

  // Insert preview data
  if( hasPreview )
  {
    memcpy( context.data() + 574, previewData.data(), previewData.size() );
  }

  // Encode the context
  QByteArray encodedContext;
  KCodecs::base64Encode( context, encodedContext );
  QString base64Context = QString::fromUtf8( encodedContext.data(), encodedContext.size() );

#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P: context size=" << context.size() << " base64 size=" << base64Context.length() << "." << endl;
#endif

  // Return it.
  return base64Context;
}



/**
 * End the application with another message in the file transfer dialog as well.
 */
00476 void FileTransferP2P::endApplication(const QString &reason, const QString &transferDialogMessage)
{
  QString html;

#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P::endApplication: " << reason << endl;
#endif
#ifdef KMESSTEST
    ASSERT( transferPanel_ != 0 );
#endif

  // Display a message to the user, and terminate this application
  QString message = reason.arg("<span class=\"filename failedFilename\">" + fileName_ + "</span>");

  if( transferPanel_ != 0)
  {
    transferPanel_->failTransfer(transferDialogMessage);
    transferPanel_ = 0;
  }

  P2PApplication::endApplication(message);
}



/**
 * Return the application's GUID.
 */
00504 QString FileTransferP2P::getAppId()
{
  return "{5D3E02AB-6190-11D3-BBBB-00C04F795683}";
}



/**
 * Return a cancel message to display.
 */
00514 QString FileTransferP2P::getContactAbortMessage() const
{
  // Application::getUserAbortMessage() returns "The contact cancelled the session".
  return i18n("The contact cancelled the transfer.");
}



/**
 * Return a cancel message to display.
 */
00525 QString FileTransferP2P::getUserAbortMessage() const
{
  // Application::getUserAbortMessage() returns "You have cancelled the session".
  return i18n("The transfer was cancelled");
}



/**
 * Called when data is received.
 * Once all data is received, the SLP BYE message will be sent.
 *
 * @param  message  P2P message with the data.
 */
00539 void FileTransferP2P::gotData(const P2PMessage &message)
{
  if(file_ == 0)
  {
#ifdef KMESSDEBUG_FILETRANSFER_P2P
    kdDebug() << "FileTransferP2P: Unable to handle file data: no file open!" << endl;
#endif

    // Cancel if we can't receive it.
    // If this happens we're dealing with a very stubborn client,
    // because we already rejected the data-preparation message.
    sendCancelMessage(CANCEL_FAILED);
    return;
  }


#ifdef KMESSTEST
  ASSERT( transferPanel_ != 0 );
#endif


#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P: Data part received, saving data to file." << endl;
#endif

  // Write the data in the file
  Q_LONG status = file_->writeBlock( message.getData(), message.getDataSize() );

  // Check whether the write failed
  if(status == -1)
  {
    kdDebug() << "FileTransferP2P: Failed to write the datablock in the file" << endl;

    // Close the file
    file_->flush();
    file_->close();
    delete file_;
    file_ = 0;

    if(transferPanel_ != 0 )
    {
      transferPanel_->failTransfer( i18n("File transfer dialog message", "File could not be written") );
      transferPanel_ = 0;
    }

    sendCancelMessage(CANCEL_FAILED);
    // endApplication();  // I expect the other client sends more data.. :-(
    return;
  }
}



/**
 * Create and initilize the progress dialog.
 *
 * @param incoming  Set to indicate whether this is an incoming file transfer or not.
 * @param filesize  Size of the file to transfer.
 */
00598 void FileTransferP2P::initializeProgressDialog(bool incoming, uint filesize)
{
  // Create a new entry in the tranfer window
  TransferWindow  *transferWindow = TransferWindow::instance();
  transferPanel_ = transferWindow->addEntry( fileName_, filesize, incoming, preview_ );

  // Connect the dialog so that if the user closes it, it's deleted.
  connect( transferPanel_, SIGNAL( cancelTransfer()             ) ,
           this,             SLOT( slotCancelTransfer()         ) );

  transferWindow->show();
}



/**
 * Called when the transfer is complete.
 * This function is also called from the P2PApplication base class.
 * The application will terminate automatically.
 */
00618 void FileTransferP2P::showTransferComplete()
{
#ifdef KMESSDEBUG_P2PAPPLICATION_GENERAL
  kdDebug() << "P2PApplication: Transfer is complete." << endl;
#endif

  if(file_ != 0)
  {
    // Clean up
    file_->flush();
    file_->close();
    delete file_;
    file_ = 0;
  }

  if(transferPanel_ != 0 )
  {
    transferPanel_->finishTransfer();
    transferPanel_ = 0;
  }

  // Send an event to the switchboard:
  emit fileTransferred(fileName_);
}



/**
 * Show a message to inform about a transfer event (shown in the transfer dialog, e.g. connecting to host).
 * This function is also called from the P2PApplication base class.
 */
00649 void FileTransferP2P::showTransferMessage(const QString &message)
{
  if(transferPanel_ != 0)
  {
    transferPanel_->setStatusMessage( message );
  }
  else
  {
#ifdef KMESSDEBUG_FILETRANSFER_P2P
    kdWarning() << "FileTransferP2P::showTransferMessage: Transfer panel is not initialized yet!" << endl;
#endif
  }
}



/**
 * Show the progress made during a transfer.
 * This function is also called from the P2PApplication base class.
 */
00669 void FileTransferP2P::showTransferProgress(const uint bytesTransferred)
{
  if(transferPanel_ != 0)
  {
    transferPanel_->updateProgress( bytesTransferred );
  }
  else
  {
#ifdef KMESSDEBUG_FILETRANSFER_P2P
    kdWarning() << "Application::showTransferProgress: Transfer panel is not initialized yet!" << endl;
#endif
  }
}



/**
 * Cancelled the file transfer from the TransferWindow
 */
00688 void FileTransferP2P::slotCancelTransfer()
{
  // This method is activated from the transferPanel,
  // it will delete itself.
  // make sure we never call updateProcess() on it again.
  transferPanel_ = 0;

  // Use the same route as closing the chat window.
  userAborted();

  // Now we wait for the contact to end the session
}



/**
 * The user cancelled the session
 */
00706 void FileTransferP2P::userAborted()
{
#ifdef KMESSDEBUG_FILETRANSFER_GENERAL
  kdDebug() << "FileTransferP2P - userAborted" << endl;
#endif

  // Make sure the transfer panel displays the cancel state
  if(transferPanel_ != 0)
  {
    // The object can be deleted by the user
    transferPanel_->failTransfer( i18n("File transfer dialog message", "Cancelled") );
    transferPanel_ = 0;
  }

  // Let the parent class handle the rest
  P2PApplication::userAborted();
}



/**
 * Step one of a user-started chat: the user invites the contact
 */
00729 void FileTransferP2P::userStarted1_UserInvitesContact()
{
#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P - userStarted1_UserInvitesContact - starting file transfer" << endl;
#endif
#ifdef KMESSTEST
  ASSERT( file_ == 0 );
#endif

  /*
   * Many thanks to Siebe Tolsma for providing this documentation:
   * http://siebe.bot2k3.net/docs/
   */

  file_        = new QFile(fileName_);
  bool success = (file_ != 0) && file_->open(IO_ReadOnly);

  // Stop if the file can't be openend.
  if( ! success )
  {
#ifdef KMESSDEBUG_FILETRANSFER_P2P
    kdDebug() << "FileTransferP2P::userStarted1_UserInvitesContact: Cancelling session" << endl;
#endif

    // Notify the user, even if debug mode is not enabled.
    kdWarning() << "Unable to open file: " << fileName_ << "!" << endl;

    // Close the file
    delete file_;
    file_ = 0;

    // Tell the user about it
    if( ! QFile::exists(fileName_) )
    {
      showMessage( i18n("The transfer of %1 failed.  The file does not exist.")
                   .arg("<span class=\"filename failedFilename\">" + fileName_ + "</span>") );
    }
    else
    {
      showMessage( i18n("The transfer of %1 failed.  The file could not be read.")
                   .arg("<span class=\"filename failedFilename\">" + fileName_ + "</span>") );
    }
    return;
  }


  // Read the filename parameters
  fileSize_ = file_->size();

  // Create a thumbnail, continue when it completes
  // Windows Live Messenger scales the received image down depending on the users settings.
  // The preview however, is always sent as 96x96
  thumbnailProvider_ = new ThumbnailProvider( fileName_, 96 );
  connect( thumbnailProvider_, SIGNAL(gotResult()), this, SLOT(userStarted1_gotThumbnailResult()) );
}


/**
 * @brief Called when the thumbnail is generated.
 */
00789 void FileTransferP2P::userStarted1_gotThumbnailResult()
{
  bool hasPreview = thumbnailProvider_->isSuccessful();

  // Create the session id and context field
  QString context   = createContextField( fileName_, file_, hasPreview );
  uint    sessionID = P2PApplication::generateID();

  // Send the invitation
  sendSlpSessionInvitation(sessionID, getAppId(), 2, context);


  // Generate the HTML to cancel the transfer
  QString shortName = fileName_.right( fileName_.length() - fileName_.findRev( QRegExp("/") ) - 1 );
  QString html = i18n("Sending file %1").arg("<span class=\"filename invitationFilename\">" + shortName + "</span>");


  // Generate fallback image so there is always an icon in the chat window.
  if( ! hasPreview )
  {
    thumbnailProvider_->generateFallbackImage();
    hasPreview = thumbnailProvider_->isSuccessful();
  }

  // Insert the preview image if this is available.
  if( hasPreview )
  {
    html = thumbnailProvider_->getImageTag( shortName ) + "<br />" + html;
  }

  // Display the link in the chat window
  offerCancel( html );
}



/**
 * Step two of a user-started chat: the contact accepts
 *
 * @param  message  Accept message of the other contact
 */
00830 void FileTransferP2P::userStarted2_ContactAccepts(const MimeMessage & /*message*/)
{
#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P - userStarted2_ContactAccepts" << endl;
#endif

  // Update the GUI
  showEventMessage( i18n("Transfer accepted.") );
  initializeProgressDialog(false, fileSize_);

  // Send the invite to negatiate the transfer mode.
  sendSlpTransferInvitation();
}



/**
 * Step three of a user-started chat: the user prepares for the session.
 */
00849 void FileTransferP2P::userStarted3_UserPrepares()
{
#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P - userStarted3_UserPrepares" << endl;
#endif
#ifdef KMESSTEST
  ASSERT( file_ != 0 );
#endif

  // A connection is available to send the file.
  // The base class handles the transfer transparently (e.g. using direct connections, etc).
  sendData( file_, P2P_TYPE_FILE );
}


#include "filetransferp2p.moc"

Generated by  Doxygen 1.6.0   Back to index