/***************************************************************************
                          msnobject.cpp  -  description
                             -------------------
    begin                : Tue Jul 15 2003
    copyright            : (C) 2003 by Mike K. Bennett
    email                : mike@kmess.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 "msnobject.h"

#include "crypt/sha1.h"

#include <qregexp.h>
#include <kmdcodec.h>

#include <kdebug.h>

// The constructor
MsnObject::MsnObject()
 : size_(0)
{
}


MsnObject::MsnObject(const QString &object)
{
  loadObject(object);
}


MsnObject::MsnObject(const QString &creator, const QString &location,
               const QString &friendly, MsnObjectType type,
               const QByteArray &fileData)
  : creator_(creator), location_(location), type_(type)
{
  if( friendly != "" )
    friendly_ = KCodecs::base64Encode(friendly.latin1());
  else
    friendly_ = "AAA=";

  size_= fileData.size();

  // Hash data
  Sha1 sha1;
  QByteArray hash;
  hash.duplicate((const char *)sha1.calcSha1((const byte *)fileData.data(),
     fileData.size()), 20);
  sha1d_= KCodecs::base64Encode(hash);


  // Very last thing we do
  sha1c_= generateObjectHash();
}





// The destructor
MsnObject::~MsnObject()
{
}



// Parse an attribute from the object string
QString MsnObject::getAttribute( const QString& name, const QString& object )
{
  QString      value;
  int          index;
  QRegExp      findAttribute( name + "=\"([^ ]*)\"" );

  index = findAttribute.search( object );
  if ( index >= 0 )
  {
    if ( findAttribute.numCaptures() > 0 )
    {
      value = findAttribute.capturedTexts()[1];
    }
  }

  return value;
}


// Get the sha1c hash
const QString MsnObject::getContentHash() const
{
  return sha1c_;
}


// Get the object's creator
const QString& MsnObject::getCreator() const
{
  return creator_;
}


// Get the sha1d hash
const QString MsnObject::getDataHash() const
{
  return sha1d_;
}


// Get the object's location
const QString& MsnObject::getLocation() const
{
  return location_;
}


const QString MsnObject::getFriendly() const
{
  // This is actually base-64 encoded. We must decode it before
  // returning the information.
  return KCodecs::base64Decode(friendly_);
}


// Get the object's size
int MsnObject::getSize() const
{
  return size_;
}



// Get the object's type
MsnObject::MsnObjectType MsnObject::getType() const
{
  return type_;
}



// Use an MSN object descriptor from the server to load data
void MsnObject::loadObject( const QString& object )
{
  creator_  = getAttribute( "Creator", object );
  location_ = getAttribute( "Location", object );
  size_     = getAttribute( "Size", object ).toInt();
  type_     = (MsnObjectType)getAttribute( "Type", object ).toInt();
  friendly_ = getAttribute( "Friendly", object ).utf8();
  sha1d_    = getAttribute("SHA1D", object).utf8();
  sha1c_    = getAttribute("SHA1C", object).utf8();

  // Bah! Verification is for the weak.
  //if(!verifyObjectHash())
  //{
  //  kdDebug() << "Hash does not match!";
  //  kdDebug() << "MSN6 data for contact: " << creator_ << " " << location_ << " " << size_ << " " << type_ << " " << getFriendly() <<  endl;  //  kdDebug() << "Real sha1c " << sha1c_ << " vs. calculated " << generateObjectHash() << endl;
  //}
}


bool MsnObject::verifyObjectHash() const
{
  // And yes, QCString overloads operator==
  return generateObjectHash() == sha1c_;
}

const QCString MsnObject::generateObjectHash() const
{
  // First, we must build the string that needs to be hashed.
  // See amsn protocol.tcl (create_msnobj) for an example.
  // We concatenate field names with their values, in the following order:
  // Creator, Size, Type, Location, Friendly, SHA1D
  QCString baseString= "Creator" + creator_.utf8() +
    "Size" + QString::number(size_).utf8() +
    "Type" + QString::number((int)type_).utf8() +
    "Location" + location_.utf8() +
    "Friendly" + friendly_ +
    "SHA1D" + sha1d_;

  // Sha1 the thing
  QByteArray shaData(20); // 160 bits of output
  Sha1 sha1;
  shaData.duplicate((const char *)sha1.calcSha1((const byte*)baseString.data(),
            baseString.length()), 20);

  // Return the base64-encoded version
  // No worry about linefeeds: should come out to 28 bytes
  return KCodecs::base64Encode(shaData);
}


const QString MsnObject::objectString() const
{
  return QString("<msnobj Creator=\"%1\" Size=\"%2\" Type=\"%3\""
                            " Location=\"%4\" Friendly=\"%5\""
          " SHA1D=\"%6\" SHA1C=\"%7\"/>")
    .arg(creator_).arg(size_).arg(type_).arg(location_).arg(friendly_)
    .arg(sha1d_).arg(sha1c_);
}


bool MsnObject::hasChanged(const QString &newObj) const
{
  if(getAttribute("SHA1C", newObj).utf8() == sha1c_) // == should be overridden to match on QCStrings or char*'s
    return false;
  else
    return true;
}


#include "msnobject.moc"
