Logo Search packages:      
Sourcecode: kmess version File versions  Download package

void FileTransferP2P::contactStarted1_ContactInvitesUser ( const MimeMessage message  )  [private, virtual]

Step one of a contact-started chat: the contact invites the user

Parameters:
message The invitation message

Reimplemented from P2PApplication.

Definition at line 99 of file filetransferp2p.cpp.

References MimeMessage::addField(), P2PMessage::extractBytes(), P2PApplication::getInvitationContentType(), MimeMessage::getValue(), P2PApplication::sendCancelMessage(), and P2PApplication::sendSlpOkMessage().

{
#ifdef KMESSDEBUG_FILETRANSFER_P2P
  kdDebug() << "FileTransferP2P - contactStarted1_ContactInvitesUser" << endl;
#endif

  // Get the content type
  QString contentType = getInvitationContentType();

  // Determine the content-type, and read those fields as well:
  if(contentType == "application/x-msnmsgr-sessionreqbody")
  {
#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)
    {
      kdDebug() << "FileTransferP2P: WARNING - Received unexpected AppID: " << appID << "." << endl;

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

      // Don't QUIT, this is the accept stage. The contact should ACK back.
      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)
    {
      kdDebug() << "KMess: File transfer context field has bad formatting, ignoring invite (context=" << context << ")." << endl;
      sendCancelMessage(CANCEL_SESSION);
      P2PApplication::endApplication( i18n("The file transfer invitation was cancelled.  Bad data was received.") );
      return;
    }

    // Extract the simple fields from the context string.
    unsigned int  length     = 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(length > decodedContext.size() || length < 24)
    {
      kdDebug() << "KMess: File transfer context field has bad formatting, rejecting invite (length=" << length << ")" << endl;
      sendCancelMessage(CANCEL_SESSION);
      emit appInitMessage( i18n("The file transfer invitation was cancelled.  Bad data was received.") );
      return;
    }


      // FIXME: The length argument doesn't really seam to be correct...

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

    unsigned int splitter = (unsigned int) decodedContext[length - 4];
    if(splitter != 0xFFFFFFFF)
    {
      kdDebug() << "KMess: File transfer context field has bad formatting, ignoring invite (splitter not found)." << endl;
      //return;
    }

*/

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

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

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


    // Everything seams OK, allow the user to accept the message:
    QString html = i18n("Do you want to accept the file: %1 (%2 bytes)")
                   .arg( "<font color=red>" + suggestedFileName_ + "</font>" )
                   .arg( fileSize_ );

    offerAcceptOrReject( html );
  }
  else if(contentType == "application/x-msnmsgr-transreqbody")
  {
    // Second stage of the file transfer: initiate the connection
    // (the progress dialog is also initialized now)

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

#ifdef KMESSDEBUG_FILETRANSFER_P2P
    kdDebug() << "FileTransferP2P: Received the file transfer-negotiation." << endl;
#endif

    // File should be opened in the contactStarted2_UserAccepts() step
    if(file_ == 0)
    {
      // File opening failed (file_ == 0)
#ifdef KMESSDEBUG_FILETRANSFER_P2P
      kdDebug() << "FileTransferP2P: Cannot open file: " << fileName_ << endl;
#endif

      // Reject the second invitation.
      sendCancelMessage( CANCEL_SESSION );

      // Tell the user about it
      emit appInitMessage( i18n("The transfer of %1 failed.  Couldn't open file.")
          .arg("<font color=red>" + fileName_ + "</font>") );
      if(transferPanel_ != 0)
      {
        transferPanel_->setStatusMessage( i18n("File transfer dialog message", "Couldn't open file.") );
      }
      return;
    }


    // This kind of message is always accepted, and we skip the
    // contactStarted2_UserAccepts() step because it would be a little
    // difficult otherwise.

    // Read the data from the message
    QString bridges        = message.getValue("Bridges");       // Transport layers the client supports
    int     netID          = message.getValue("NetID").toInt(); // Some ID
    QString connectionType = message.getValue("Conn-Type");     // Suggested connection type
    QString hasUPnPNat     = message.getValue("UPnPNat");       // uses UPnP-enabled NAT router
    QString hasICF         = message.getValue("ICF");           // uses Internet Connection Firewall


#ifdef KMESSDEBUG_FILETRANSFER_P2P
    kdDebug() << "FileTransferP2P: Begin of transfer " << file_->name() << endl;
#endif

    // Examine the network configuration of the other client
    if(connectionType == "Direct-Connect")
    {
      // Same IP, same port
    }
    else if(connectionType == "IP-Restrict-NAT")
    {
      // Different IP, same port
    }
    else if(connectionType == "Port-Restrict-NAT")
    {
      // Same IP, different port
    }
    else if(connectionType == "Symmetric-NAT" || connectionType == "Unknown-Connect")
    {
      // Different IP, different port
    }


    // Based on the contact's network configuration,
    // we choose how we want to send the file:

    // This configuration sends each file over the switchboard:
    MimeMessage acceptMessage;
    acceptMessage.addField( "Bridge",    "TCPv1" );
    acceptMessage.addField( "Listening", "false" );
    acceptMessage.addField( "Nonce",     "{00000000-0000-0000-0000-000000000000}");

    // Confirm the session
    sendSlpOkMessage( acceptMessage );

    // Update the progress dialog
    if(transferPanel_ != 0)
    {
      transferPanel_->setStatusMessage( i18n("File transfer dialog message",
                                              "Using the switchboard for file transfer (this could be slow).") );
    }
  }
  else
  {
    kdWarning() << "FileTransferP2P: Received unexpected Content-Type: " << contentType << "." << endl;

    // Indicate we don't like that content-type:
    sendCancelMessage( CANCEL_INVALID_SLP_CONTENT_TYPE );

    // Tell the user about it
    if(transferPanel_ != 0)
    {
      transferPanel_->failTransfer( i18n("File transfer dialog message", "Failed") );
      transferPanel_ = 0;
    }
    emit appInitMessage( i18n("The transfer failed.") + "  " +
                         i18n("The contact sent bad data, or KMess doesn't support it.") );

    // Don't quit yet, the SLP error message will be ACKed by the contact.
  }
}


Generated by  Doxygen 1.6.0   Back to index