Logo Search packages:      
Sourcecode: kmess version File versions

multipacketmessage.cpp

/***************************************************************************
                          multipacketmessage.h -  description
                             -------------------
    begin                : Thu May 23 2005
    copyright            : (C) 2006 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 "multipacketmessage.h"
#include "../kmessdebug.h"


// Many thanks to Siebe Tolsma for the following documentation:
// http://siebe.bot2k3.net/docs/word/Sending Multi-Packet Messages.doc


// The constructor
MultiPacketMessage::MultiPacketMessage()
: chunks_(0)
, lastChunk_(0)
{
  buffer_.open( IO_ReadWrite );

  // TODO: add a live-time to the message, so it will be removed
  // automatically (avoiding yet another denial-of-service attack).
}



// The destructor
MultiPacketMessage::~MultiPacketMessage()
{
  buffer_.close();
}



// Add a message to the part
void MultiPacketMessage::addChunk( const MimeMessage &message )
{
  if( chunks_ > 20 )
  {
    // Method was called again for the next chunk.
    return;
  }

  if( isComplete() )
  {
    kdWarning() << "MultiPacketMessage::addChunk: already received last chunk!" << endl;
    return;
  }

#ifdef KMESSTEST
  ASSERT( message.hasField("Message-ID") );
#endif

  if( message.hasField("Chunks") )
  {
    // Test whether the object is already initialized.
    if( ! messageId_.isNull() )
    {
      kdWarning() << "MultiPacketMessage::addChunk: reveived message contains 'Chunks' header, but is not the first message!" << endl;
      return;
    }

    // This is the first message.
    messageId_ = message.getValue("Message-ID");
    chunks_    = message.getValue("Chunks").toInt();
    lastChunk_ = 0;

    // Avoid denial-of-service attacks.
    if( chunks_ > 20 )
    {
      kdWarning() << "MultiPacketMessage::addChunk: about to receive a message of more then 20 chunks, ignoring message!" << endl;
      return;
    }

    // Add message fields to result, except Message-ID and 'Chunks'
    int fields = message.getNoFields();
    QString fieldName;
    QString fieldValue;
    for( int i = 0; i < fields; i++ )
    {
      message.getFieldAndValue(fieldName, fieldValue, i);
      if( fieldName != "Message-ID" && fieldName != "Chunks" && fieldName != "Chunk" )
      {
        result_.addField(fieldName, fieldValue);
      }
    }
  }
  else if( message.hasField("Chunk") )
  {
    // This is a second message
    // Test whether this is the correct chunk
    if( message.getValue("Chunk").toInt() != lastChunk_ )
    {
      kdWarning() << "MultiPacketMessage::addChunk: received message chunk "
                  << message.getValue("Chunk") << ", expecting chunk " << lastChunk_ << "!" << endl;
      return;
    }
  }
  else
  {
    kdWarning() << "MultiPacketMessage::addChunk: received message without 'Chunks' or 'Chunk' field, ignoring message!" << endl;
    return;
  }


  // MimeMessage preserves chunk data as binary, so multibyte
  // UTF-8 characters will be correctly merged later.
  const QByteArray &chunkData = message.getBinaryBody();
#ifdef KMESSTEST
  ASSERT( message.getBinaryBody().size() > 0 );
#endif
  buffer_.writeBlock( chunkData );

  // Update chunk count
  lastChunk_++;


  // Test whether this was the last message.
  if( lastChunk_ == chunks_ )
  {
    // Read all data
    buffer_.reset();
    QByteArray bufferData = buffer_.readAll();

    // Determine how to merge the data.
    if( result_.getValue("Content-Type") == "application/x-msnmsgrp2p" )
    {
      // Merge as binary
      result_.setBinaryBody(bufferData);
    }
    else
    {
      // Merge as UTF-8 text
      result_.setBody( QString::fromUtf8(bufferData.data(), bufferData.size()) );
    }
  }
}



// Returh the complete message
const MimeMessage &MultiPacketMessage::getMessage() const
{
  return result_;
}



// Return whether the full message is received
bool MultiPacketMessage::isComplete() const
{
  return (chunks_ > 0 && lastChunk_ == chunks_);
}



Generated by  Doxygen 1.6.0   Back to index