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

chatcore.cpp

/***************************************************************************
 *   Copyright (C) 2007 by Anistratov Oleg                                 *
 *   ower@users.sourceforge.net                                            *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License version 2        *
 *   as published by the Free Software Foundation;                         *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 ***************************************************************************/

#include "chatcore.h"

#include <assert.h>
#include <string.h>
#include <time.h>

#include <QBuffer>
#include <QFile>
#include <QDateTime>
#include <QTextBlock>
#include <QCryptographicHash>

#include "chatwgt.h"
#include "channelwgt.h"
#include "userinfo.h"
#include "userwgt.h"
#include "preferences.h"
#include "receiverthread.h"
#include "senderthread.h"
#include "largedatagram.h"
#include "edituserinfodlg.h"
#include "nlamarok.h"
#include "userprofile.h"

#include "smileswgt.h"
#include "chattextwgt.h"

#include "userstatistics.h"

#include "message.h"
#include "singlemsgshistory.h"

QTimer* ChatCore::m_chatTimer = new QTimer;

ChatCore::ChatCore(QObject* parent)
 : QThread(parent),
  m_needCheckIp     (0),
  m_nowListening    (""),
  m_nlIsNew         (false),
  m_chatWgt         (NULL),
  m_myInfo          (0),
  m_currentProfile  (0),
  m_inputBuffer     (NULL),
  m_outputBuffer    (NULL),
  m_header          (NULL),
  m_data            (NULL),
  m_parametrs       (""),
  m_inputBufferSize (65535),
  m_outputBufferSize(0),
  m_dataSize        (0),
  m_headerSize      (0),
  m_settingsDirName (""),
  m_largeDtgrm      (false),
  m_chatTime        (0)
{
  Hdr        = new QC_DatagramHeader;
  m_sender   = new SenderThread  ();
  m_receiver = new ReceiverThread();
  m_prefs    = new Preferences;

  m_singleMsgsHistory = new SingleMsgsHistory;

#if defined(Q_OS_LINUX)
  m_nlAmarok = new NLAmarok(this);
#endif

  Globals::setInfo(m_myInfo);
  Globals::setPrefs(m_prefs);

  m_inputBuffer  = (char*)malloc(m_inputBufferSize);
  assert(NULL   != m_inputBuffer );

  m_outputBuffer = (char*)malloc(m_inputBufferSize);
  assert(NULL   != m_outputBuffer);

  m_statusTimer = new QTimer(this);

  m_chatTimer->start(1000);

  connect(m_chatTimer, SIGNAL(timeout()), this, SLOT(slot_updateChatTime()));

#if defined(Q_OS_LINUX)
  connect(m_nlAmarok, SIGNAL(updated   (const QString&, const QString&, const QString&)),
          this      , SLOT  (slot_setNl(const QString&, const QString&, const QString&)));
#endif
}

ChatCore::~ChatCore()
{
  qDebug("[ChatCore::~ChatCore]\n");
  free(m_outputBuffer);
  free(m_header);
  free(m_data);
}
//\*****************************************************************************
00111 void ChatCore::prepareDatagram(unsigned char  dtgrm_type            ,
                              quint32         dest_ip               ,
                              const QString & msg           /* = 0*/,
                              unsigned long   chnnl_type    /* = 0*/, // 0 - common, 1 - private, 2 - password
                              unsigned long   dtgrm_id      /* = 0*/,
                              unsigned long   dtgrm_num     /* = 0*/)
{
  m_largeDtgrm = false;

  quint32 src_ip  = m_prefs->ip();

  QByteArray msgData      = msg                 .toUtf8();
  QByteArray nameData     = m_myInfo->nickname().toUtf8();
  QByteArray compNameData = m_myInfo->compName().toUtf8();

  int   i;
  int   pr_len = 0; // protocol_len
  int   unl    = nameData    .size(); // user_name_len
  int   cnl    = compNameData.size(); // comp_name_len
  int*  pr     = (int*)Globals::Protocol;
  char* buf;

  for(i = 0; i < 18; i++)
    pr_len += pr[i];

  m_outputBufferSize = pr_len + unl + cnl + msgData.size() + m_parametrs.size();

  qDebug("[ChatCore::prepareDatagram]: pr_len = %d, unl = %d, cnl = %d, msgData.size() = %d, m_parametrs.size() = %d", pr_len, unl, cnl, msgData.size(), m_parametrs.size());

  m_headerSize = pr_len + unl + cnl;

  m_header = (char*)realloc(m_header, m_headerSize);
  assert(NULL != m_header);

  // 4 + 4 - dlya razmerov esli paket budet fragmented
  m_dataSize     = msgData.size() + m_parametrs.size() + 4 + 4;
  m_data         = (char*)realloc(m_data, m_dataSize);
  assert(NULL   != m_data);

  if(m_outputBufferSize > MAX_PACKET_LEN)
    m_largeDtgrm = true;

  buf = m_header;

  strncpy   (buf          , Globals::ProgramID, pr[0] );
  catUS2str (buf += pr[ 0], Globals::VersionID        );
  catUS2str (buf += pr[ 1], Globals::ProtocolVersionID);
  catULL2str(buf += pr[ 2], dest_ip          );
  catULL2str(buf += pr[ 3], src_ip           );
           *(buf += pr[ 4]) = dtgrm_type;
  catUL2str (buf += pr[ 5], dtgrm_id         );
  catUL2str (buf += pr[ 6], dtgrm_num        );
  catULL2str(buf += pr[ 7], (quint64)time(NULL));
  catUL2str (buf += pr[ 8], chnnl_type       );
           *(buf += pr[ 9]) = cnl;
           *(buf += pr[10]) = unl;
  catUL2str (buf += pr[11], msgData.size  () );
  catUL2str (buf += pr[12], m_parametrs.size() );
  strncpy   (buf += pr[13], compNameData, cnl);
  strncpy   (buf += cnl   , nameData    , unl);

  buf = m_data;

  if(m_largeDtgrm)
  {
    catUL2str(buf     , msgData  .size());
    catUL2str(buf += 4, m_parametrs.size());
    buf += 4;
  }

  memcpy   (buf, msgData.data(), msgData.size());

  if(!m_parametrs.isEmpty())
     memcpy (buf += msgData.size(), m_parametrs.data(), m_parametrs.size());

  if(!m_largeDtgrm)
  {
    memcpy(m_outputBuffer               , m_header, m_headerSize  );
    memcpy(m_outputBuffer + m_headerSize, m_data  , m_dataSize - 8); // -8, t.k. paket ne fragmented
    m_outputBufferSize = m_headerSize + m_dataSize - 8;
  }
}
//\*****************************************************************************
00194 void ChatCore::sendData(const QHostAddress & addr)
{
  if(m_largeDtgrm)
  {
    quint32 ID = m_sender->getValidID();

    if(ID)
    {
      emit wantSendLargeData(m_header, m_headerSize, m_data, m_dataSize, addr, ID);
      m_header = NULL;
      m_data   = NULL;
    }
  }
  else
  {
    quint16 size = m_outputBufferSize <= MAX_PACKET_LEN ? m_outputBufferSize : (MAX_PACKET_LEN);
    int bs = m_socketOut.writeDatagram(m_outputBuffer, size, addr, Globals::prefs()->portOut());

    qDebug("[ChatCore::sendData]: dtgrm size = %d, sent = %d\n", size, bs);
  }

  clearParametrs();
}
//\*****************************************************************************
void ChatCore::slot_prepareAndSend(const QString & ch_name_id, const QHostAddress & addr, uint data_type, const QString & msg, quint32 ch_type, QByteArray* add_pars)
{
  qDebug("[ChatCore::slot_prepareAndSend]: type = %u", data_type);
  qDebug("[ChatCore::slot_prepareAndSend]: 'channel_name' = '%s'", ch_name_id.toLocal8Bit().data());
  qDebug("[ChatCore::slot_prepareAndSend]: 'msg' = '%s'", msg.toLocal8Bit().data());

  if(data_type != Globals::SINGLE_MESSAGE)
    addParametr("Channel", ch_name_id.toUtf8());

  if(add_pars)
  {
    m_parametrs.append(*add_pars);
    add_pars->clear();
  }

  if(data_type == Globals::MESSAGE)
  {
    addParametr("Color", QByteArray().append(m_prefs->myColor().red  ())
                                     .append(m_prefs->myColor().green())
                                     .append(m_prefs->myColor().blue ()));
    processSmiles(msg);

    bool send_nl = m_nlIsNew && !m_nowListening.isEmpty() && (m_prefs->nlMode() & 1);

    if(send_nl)
    {
      m_nowListening = m_prefs->nlFormat();
      m_nowListening.replace("%a", m_nlArtist).replace("%b", m_nlAlbum).replace("%t", m_nlTitle);
    }

    prepareDatagram(Globals::MESSAGE,
                    addr.toIPv4Address(),
                    send_nl ? msg + "\n" + m_nowListening : msg,
                    ch_type);

    m_nlIsNew = (m_nlIsNew && !send_nl);
  }
  else
    prepareDatagram(data_type, addr.toIPv4Address(), msg, ch_type);

  sendData(addr);
}
//\*****************************************************************************
void ChatCore::slot_singleMessage(const QString & msg, const QHostAddress & addr, quint32 type)
{
  qDebug("[ChatCore::slot_singleMessage]: addr = '%s'", addr.toString().toLocal8Bit().data());
  qDebug("[ChatCore::slot_singleMessage]: msg  = '%s'", msg.toLocal8Bit().data());

  prepareDatagram(Globals::SINGLE_MESSAGE,
                  addr.toIPv4Address(),
                  msg,
                  type);
  sendData(addr);
}
//\*****************************************************************************
void ChatCore::slot_statusAnswer(const QString & name_id, const QHostAddress & addr, quint32 channel_type, bool changed, bool send_icon)
{
  if(m_myInfo->status() == Globals::INVISIBLE)
    return;

  if(send_icon)
  {
    QByteArray data;
    QBuffer    buffer;
    const QImage* icon = m_myInfo->newIconImg();

    buffer.setBuffer(&data);

    if(icon)
    {
      icon->save(&buffer, "PNG", 100);
      delete icon;
    }

    addParametr("Icon"   , data);
  }

  addParametr("Status" , QByteArray().append((char)m_myInfo->status()));
  addParametr("Channel", name_id.toUtf8());
  addParametr("Version", Globals::VersionStr.toUtf8());
  addParametr("StatusDescription", Globals::info()->statusDescription().toUtf8());
  addParametr("Gender" , QString().setNum(m_myInfo->gender()).toUtf8());
  addParametr("OS"     , UserStatistics::OsString().toUtf8());
  addParametr("Uptime" , QString().setNum(UserStatistics::getUptime()).toUtf8());
  addParametr("ChatTime", QString().setNum(m_chatTime).toUtf8());
  addParametr("FirstName", m_myInfo->firstName().toUtf8());

  if(!changed)
    prepareDatagram(Globals::STATUS_ANSWER,
                   addr.toIPv4Address(),
                   QString(""),
                   channel_type);
  else
  {
    QString str = "Status Changed : " + Globals::StatusStr[m_myInfo->status()];

    if(!Globals::info()->statusDescription().isEmpty())
      str += " (" + Globals::info()->statusDescription() + ")";

    prepareDatagram(Globals::INF_STATUS_CHNGD,
                   Globals::prefs()->broadcast().toIPv4Address(),
                   str);
  }

  qDebug("[ChatCore::slot_statusAnswer] ip = %s, ip = %u", addr.toString().toLocal8Bit().data(), addr.toIPv4Address());

  sendData(addr);
}
//\*****************************************************************************
void ChatCore::slot_infStatusChanged(const QString & name_id)
{
  addParametr("Channel", name_id.toUtf8());
  addParametr("Status" , QByteArray().append((char)m_myInfo->status()));

  prepareDatagram(Globals::INF_STATUS_CHNGD,
                   Globals::prefs()->broadcast().toIPv4Address(),
                   QString("STATUS CHANGED")
                 );
  sendData(Globals::prefs()->broadcast());
}
//\*****************************************************************************
void ChatCore::slot_infoAnswer(const QString & name_id, const QHostAddress & addr, quint32 type, uchar pics_ok)
{
  if(m_myInfo->status() == Globals::INVISIBLE)
    return;

  qDebug("\n[ChatCore::slot_infoAnswer] channel_name = %s, pics_ok = %d\n", name_id.toLocal8Bit().data(), pics_ok);

  QByteArray data;
  QBuffer    buffer;
  QImage*    pix;

  addParametr("LastName"   , m_myInfo->lastName   ().toUtf8());
  addParametr("FirstName"  , m_myInfo->firstName  ().toUtf8());
  addParametr("SecondName" , m_myInfo->secondName ().toUtf8());
  addParametr("DateOfBorn" , m_myInfo->dateOfBorn ().toString().toUtf8());
  addParametr("Address"    , m_myInfo->address    ().toUtf8());
  addParametr("HomePhone"  , m_myInfo->homePhone  ().toUtf8());
  addParametr("WorkPhone"  , m_myInfo->workPhone  ().toUtf8());
  addParametr("MobilePhone", m_myInfo->mobilePhone().toUtf8());
  addParametr("e-mail"     , m_myInfo->e_mail     ().toUtf8());
  addParametr("ICQ"        , m_myInfo->icq        ().toUtf8());
  addParametr("Homepage"   , m_myInfo->homepage   ().toUtf8());
  addParametr("AboutInfo"  , m_myInfo->aboutInfo  ().toUtf8());
  addParametr("Gender"     , QString().setNum(m_myInfo->gender()).toUtf8());

  // TODO sdelat' nastraivaemyi razmer kartinok
  buffer.setBuffer(&data);

  if(pics_ok & 1)
    addParametr("PictureOk", QByteArray());
  else
  {
    if((pix = m_myInfo->newPictureImg()))
    {
//       if(pix->height() > 500)
//         pix->scaledToHeight(500).save(&buffer);
//       else
        pix->save(&buffer, "PNG", 100);

      delete pix;
    }

    addParametr("Picture"    , data);
    addParametr("PictureHash", m_myInfo->pictureHash());
  }

  buffer.close ();

  data.clear();
  buffer.setBuffer(&data);
  buffer.setData(QByteArray());

  if(pics_ok & 2)
    addParametr("PhotoOk", QByteArray());
  else
  {
    if((pix = m_myInfo->newPhotoImg()))
    {
//       if(pix->height() > 500)
//         pix->scaledToHeight(500).save(&buffer);
//       else
        pix->save(&buffer, "PNG", 100);
      delete pix;
    }
    addParametr("Photo"    , data);
    addParametr("PhotoHash", m_myInfo->photoHash());
  }

  addParametr("Status" , QByteArray().append((char)m_myInfo->status()));
  addParametr("Version", Globals::VersionStr.toUtf8());
  addParametr("Channel", name_id.toUtf8());
  addParametr("StatusDescription", Globals::info()->statusDescription().toUtf8());

  prepareDatagram(Globals::INFO_ANSWER, addr.toIPv4Address(), QString(""), type);
  sendData(addr);
}
//\*****************************************************************************
void ChatCore::slot_requestFragments(char* fragments, quint32 len, quint32 ID, const QHostAddress & addr)
{
  char buf[2];

  catUS2str(buf, (quint16)len);

  qDebug("\n[ChatCore::slot_fragmentsRequest]:len = %lu, ID = %lu, addr = %s", (unsigned long)len, (unsigned long)ID, addr.toString().toLocal8Bit().data());

  clearParametrs();

  addParametr("FragmentsRequest", QByteArray(fragments, len));
  addParametr("FragmentsLen"    , QByteArray(buf      , 2));

  prepareDatagram(Globals::FRAGMENTS_REQUEST, addr.toIPv4Address(), QString(""), 0, ID);

  sendData(addr);

  clearParametrs();
}
//\*****************************************************************************
void ChatCore::slot_confirmReceivingFile(quint8 percents, quint16 dtgrmID, const QHostAddress & addr)
{
  prepareDatagram(Globals::CONFIRM, addr.toIPv4Address(), QString(""), 0, dtgrmID, percents);
  sendData(addr);
}
//\*****************************************************************************
void ChatCore::slot_acceptReceiving(quint16 dtgrmID, quint64 ip)
{
  qDebug("\n[ChatCore::slot_acceptReceiving] addr = %s", QHostAddress(ip).toString().toLocal8Bit().data());

  prepareDatagram(Globals::ACCEPT, ip, QString(""), 0, dtgrmID, 0);
  sendData(QHostAddress(ip));
}
//\*****************************************************************************
00450 void ChatCore::slot_rejectReceiving(quint16 dtgrmID, quint64 ip, int reason)
{
  qDebug("\n[ChatCore::slot_rejectReceiving] addr = %s", QHostAddress(ip).toString().toLocal8Bit().data());

  prepareDatagram(Globals::REJECT, ip, QString(""), 0, dtgrmID, reason);
  sendData(QHostAddress(ip));
}
//\*****************************************************************************
void ChatCore::slot_privateChatRequest(const QString & name_id, const QHostAddress & addr)
{
  addParametr("Channel", name_id.toUtf8());
  prepareDatagram(Globals::PRIVATE_CHAT_REQUEST, addr.toIPv4Address(), QString(""));
  sendData(addr);
}
//\*****************************************************************************
bool ChatCore::fillHeader()
{
  QHostAddress address;
  char* buf = m_inputBuffer;
  int*  pr  = (int*)Globals::Protocol;

  // Razbor Dannyh
  if(m_inputBufferSize < Globals::ProtocolLen)
  {
    qWarning("[ChatCore::fillHeader]: [LengthError!] (m_inputBufferSize < Globals::ProtocolLen). Ignoring this packet\n");
    return 0;
  }
  if(strncmp(m_inputBuffer, Globals::ProgramID, 18))
  {
    qWarning("[ChatCore::fillHeader]: [ID_ERROR!] (strncmp(m_inputBuffer, Globals::ProgramID, 18) != 0). Ignoring this packet\n");
    return 0;
  }

  Hdr->receive_tm      = time(NULL);
  Hdr->programVersion  = str2US (buf += pr[ 0]);

  if(Hdr->programVersion < 5)
  {
    // this may not ever happen outside my LAN because this versions was available only there :)
    qWarning("[ChatCore::fillHeader]: [error] packet from old version of qchat ( < 5). Ignoring this packet\n");
    return 0;
  }

  Hdr->protocolVersion = str2US (buf += pr[ 1]);

  if(Hdr->protocolVersion != Globals::ProtocolVersionID)
  {
    qWarning("[ChatCore::fillHeader]: [error] protocol version mismatch (%d != %d). Ignoring this packet\n", Hdr->protocolVersion, Globals::ProtocolVersionID);
    return 0;
  }

  Hdr->dest_ip         = str2ULL(buf += pr[ 2]);
  Hdr->src_ip          = str2ULL(buf += pr[ 3]);
  Hdr->type            =       *(buf += pr[ 4]);
  Hdr->id              = str2UL (buf += pr[ 5]);
  Hdr->num             = str2UL (buf += pr[ 6]);
  Hdr->tm              = str2ULL(buf += pr[ 7]);
  Hdr->chnnl_id        = str2UL (buf += pr[ 8]);
  Hdr->comp_name_len   =       *(buf += pr[ 9]);
  Hdr->name_len        =       *(buf += pr[10]);
  Hdr->msg_len         = str2UL (buf += pr[11]);
  Hdr->parametrs_len   = str2UL (buf += pr[12]);

  qDebug("[ChatCore::fillHeader]: type = %d", Hdr->type);

  if(m_inputBufferSize < Globals::ProtocolLen + Hdr->comp_name_len + Hdr->name_len + Hdr->msg_len + Hdr->parametrs_len)
  {
    qWarning("[ChatCore::fillHeader]: [error] wrong length of packet (actual size(%d) smaller than expected(%lu)). Ignoring this packet\n", m_inputBufferSize,  Globals::ProtocolLen + Hdr->comp_name_len + Hdr->name_len + Hdr->msg_len + Hdr->parametrs_len);

    qDebug("[ChatCore::fillHeader]: Globals::ProtocolLen = %d, Hdr->comp_name_len = %d, Hdr->name_len = %d, Hdr->msg_len = %lu, Hdr->parametrs_len = %lu", Globals::ProtocolLen, Hdr->comp_name_len, Hdr->name_len, Hdr->msg_len, Hdr->parametrs_len);

    return 0;
  }

  Hdr->comp_name = QString().fromUtf8(QByteArray(buf  += pr[12], Hdr->comp_name_len      ), Hdr->comp_name_len);
  Hdr->name      = QString().fromUtf8(QByteArray(buf  += Hdr->comp_name_len, Hdr->name_len), Hdr->name_len     );
  Hdr->msg       = QString().fromUtf8(QByteArray(buf  += Hdr->name_len, Hdr->msg_len      ), Hdr->msg_len      );

  Hdr->parametrs.clear();
  Hdr->parametrs = QByteArray(buf  += Hdr->msg_len, Hdr->parametrs_len);

  Hdr->color = getColorParametr(&Hdr->parametrs);

  //********* getting versionName *********
  QByteArray ba = ChatCore::getParametr("Version", Hdr->parametrs);

  if(!ba.isEmpty())
    Hdr->versionName = QString().fromUtf8(ba);
  else if(Hdr->programVersion <= Globals::VersionID)
    Hdr->versionName = QString(Globals::VersionsTable[Hdr->programVersion - 1]);
  else
    Hdr->versionName = QString("New Version[id = %1]").arg(Hdr->programVersion);

  //********* getting status *********
  Hdr->status = Globals::FREE;
  ba = getParametr("Status", Hdr->parametrs);
  if(!ba.isEmpty())
    Hdr->status = ba[0];

  return 1;
}
//\*****************************************************************************
void ChatCore::processData()
{
  QHostAddress src_ip = QHostAddress(Hdr->src_ip);
  QString chnnl_name = QString().fromUtf8(getParametr("Channel", Hdr->parametrs));

  qDebug("[ChatCore::processData]: chnnl_name = %s", chnnl_name.toLocal8Bit().data());

  QDateTime dt;
  dt.setTime_t(Hdr->receive_tm);

  switch(Hdr->type)
  {
     case Globals::SINGLE_MESSAGE :
     {
       Message* msg = new Message(Hdr);
       m_singleMsgsHistory->addMessage(msg);
       emit singleMessageIn(msg);
       break;
     }

     case Globals::FILE:
       break;

     case Globals::PRIVATE_CHAT_REQUEST:
       qDebug("[ChatCore::processData]: PRIVATE_CHAT_REQUEST chnnl_name = %s", chnnl_name.toLocal8Bit().data());
       privateChatRequest(chnnl_name, src_ip);
       break;

     default:
     {
       emit chatDataReceived(Hdr);
       Hdr = new QC_DatagramHeader;
       clearParametrs();
    }
  }
}
//\*****************************************************************************
void ChatCore::addParametr(const QString & name, const QByteArray & par, QByteArray & buf)
{
  char size[4];
  char nameSize[2];

  if(name.size() <= 65535)
  {
    catUS2str(nameSize, name.toUtf8().size());
    buf.append(nameSize[0]);
    buf.append(nameSize[1]);

    buf.append(name.toUtf8());

    catUL2str(size, par.size());
    buf.append(size[0]);
    buf.append(size[1]);
    buf.append(size[2]);
    buf.append(size[3]);

    buf.append(par);
  }
  else
    qWarning("[ChatCore::addParametr]: '%s' is too large (%d bytes). not added\n", name.toLocal8Bit().data(), name.size());
}
//\*****************************************************************************
void ChatCore::addParametr(const QString & name, const QByteArray & par)
{
  addParametr(name, par, m_parametrs);
}
//\*****************************************************************************
void ChatCore::addParametr(const QString & name, const QString & filename)
{
  QFile file(filename);
  QByteArray par;
  char size[4];
  char nameSize[2];

//   qDebug("[ChatCore::addParametr]: name = %s", name.toLocal8Bit().data());

  if(name.size() <= 65535)
  {
    file.open(QIODevice::ReadOnly);

    if(file.exists ())
    {
      par = file.readAll();

      catUS2str(nameSize, name.toUtf8().size());
      m_parametrs.append(nameSize[0]);
      m_parametrs.append(nameSize[1]);

      m_parametrs.append(name.toUtf8());

      catUL2str(size, file.size());
      m_parametrs.append(size[0]);
      m_parametrs.append(size[1]);
      m_parametrs.append(size[2]);
      m_parametrs.append(size[3]);

      m_parametrs.append(par);

      par.clear();
    }
  }
  else
    qWarning("[ChatCore::addParametr]: '%s' is too large (%d bytes). not added\n", name.toLocal8Bit().data(), name.size());

}
//\*****************************************************************************
void ChatCore::clearParametrs()
{
  m_parametrs.clear();
  Hdr->parametrs.clear();
  Hdr->color = Qt::black;
}
//\*****************************************************************************
QByteArray ChatCore::getParametr(const QString & par_name, const QByteArray& pars)
{
//   qDebug("[static ChatCore::getParametr]: req = '%s'", par_name.toLocal8Bit().data());

  qint32     idx = -1;
  quint32    size;
  quint32    pars_size = pars.size();
  QByteArray par("");
  uchar      n_size;
  char       arr2[2];
  char       par_size[4];
  QString    name;

  for(uint i = 0; i < pars_size; )
  {
    arr2[0] = pars.at(i++);
    arr2[1] = pars.at(i++);
    n_size  = str2US(arr2);

    name.clear();

    if(i + n_size >= pars_size)
      break;

    for(int j = 0; j < n_size; j++, i++)
      par.append(pars.at(i));
    name = QString().fromUtf8(par);

    par.resize(0);

//     qDebug("[static ChatCore::getParametr]: name = %s", name.toLocal8Bit().data());

    if(name == par_name)
    {
      idx = i - n_size;
      break;
    }

    if(i + 3 < pars_size)
    {
      par_size[0] = pars.at(i    );
      par_size[1] = pars.at(i + 1);
      par_size[2] = pars.at(i + 2);
      par_size[3] = pars.at(i + 3);

      size = str2UL(par_size);

      i += 4 + size;
    }

    else
      break;

  }

//   qDebug("[static ChatCore::getParametr]: pars.size() = %d", pars.size());
//   qDebug("[static ChatCore::getParametr]: idx = '%d'", idx);

  if(idx < 0)
    return QByteArray();
  idx += par_name.toUtf8().size();

  par_size[0] = pars.at(idx    );
  par_size[1] = pars.at(idx + 1);
  par_size[2] = pars.at(idx + 2);
  par_size[3] = pars.at(idx + 3);
  idx += 4;

  size = str2UL(par_size);

//   qDebug("[static ChatCore::getParametr]: size = %lu", (unsigned long)size);

  for(quint32 i = idx; i < idx + size && i < pars_size; i++)
    par.append(pars.at(i));

  return par;
}
//\*****************************************************************************
QByteArray ChatCore::getParametr(const QString & par_name)
{
  return getParametr(par_name, m_parametrs);
}
//\*****************************************************************************
QColor ChatCore::getColorParametr(QByteArray* pars)
{
  QByteArray par = getParametr("Color", *pars);
  QColor col(Qt::black);

  if(par.size() >= 3)
    col.setRgb((quint8)par[0], (quint8)par[1], (quint8)par[2]);
  else if(par.size() >= 4)
    col.setRgb(par[0], par[1], par[2], par[3]);

  return col;
}
//\*****************************************************************************
void ChatCore::slot_processData(char* data, quint16 dataSize)
{
  memcpy(m_inputBuffer, data, dataSize);

  free(data);

  m_inputBufferSize = dataSize;

  if(fillHeader())
    processData();
}
//\*****************************************************************************
void ChatCore::slot_processLargeData(LargeDatagram* dtgrm)
{
  Q_ASSERT(NULL != dtgrm);

  if(dtgrm->fillHeader(Hdr))
    processData();

  prepareDatagram(Globals::FINISHED, dtgrm->ip(), "", 0, dtgrm->id());

  sendData(QHostAddress(dtgrm->ip()));
}
//\*****************************************************************************
void ChatCore::startThreads()
{
  connect(m_receiver , SIGNAL(dataReceived    (char *, quint16)),
                 this, SLOT  (slot_processData(char *, quint16)));

  connect(m_receiver , SIGNAL(largeDataReceived    (LargeDatagram*)),
                 this, SLOT  (slot_processLargeData(LargeDatagram*)));

  connect(m_receiver , SIGNAL(wantFragments        (char*, quint32, quint32, QHostAddress)),
                 this, SLOT  (slot_requestFragments(char*, quint32, quint32, QHostAddress)));

  connect(m_receiver , SIGNAL(     fragmentsRequest(char*, quint32)),
            m_sender , SLOT  (slot_fragmentsRequest(char*, quint32)));

  connect(m_receiver , SIGNAL(     receivingAccepted(quint16)),
            m_sender , SLOT  (slot_acceptSending    (quint16)));

  connect(m_receiver , SIGNAL(openSocketError(quint16)),
                this , SLOT  (slot_openSocketError(quint16)));

  connect(m_receiver , SIGNAL(dtgrmFinished  (quint16)),
          m_sender   , SLOT  (slot_cancelTask(quint16)));

  connect(this       , SIGNAL(wantSendFile(char*, quint16, const QString &, const QHostAddress &, quint32)),
          m_sender   , SLOT  (addFileTask (char*, quint16, const QString &, const QHostAddress &, quint32)));

  connect(this       , SIGNAL(wantSendLargeData(char*, quint16, char*, quint32, const QHostAddress &, quint32)),
          m_sender   , SLOT  (addTask          (char*, quint16, char*, quint32, const QHostAddress &, quint32)));

  connect(this       , SIGNAL(wantChangeInputPort(quint16)),
          m_receiver , SLOT  (changePort         (quint16)));

  m_sender  ->setPort(m_prefs->portOut());
  m_receiver->start();
  m_sender  ->start();
  start();
  moveToThread(this);

  wantChangeInputPort(m_prefs->portIn());
}
//\*****************************************************************************
void ChatCore::stopThreads()
{
  m_receiver->exit();
  m_sender->exit();
  exit();
}
//\*****************************************************************************
void ChatCore::slot_openSocketError(quint16 port)
{
  Globals::addError(QString("Couldn't open UDP socket on port %1 ").arg(port));
  qWarning("Couldn't open UDP socket on port %d\n", port);
}
//\*****************************************************************************
void ChatCore::slot_bindInputPort(int port)
{
  Globals::prefs()->setPortIn(port);
  emit wantChangeInputPort(port);
}
//\*****************************************************************************
void ChatCore::slot_setNl(const QString & title, const QString & artist, const QString & album)
{
#if defined(Q_OS_LINUX)
  if(!title.isEmpty() || !artist.isEmpty() || !album.isEmpty())
  {
    m_nlTitle  = title;
    m_nlArtist = artist;
    m_nlAlbum  = album;

    m_nowListening = m_prefs->nlFormat();
    m_nowListening.replace("%a", artist).replace("%b", album).replace("%t", title);

    m_nlIsNew = true;
  }
  else
    m_nowListening = "";

  m_prefs->setNowListening(m_nowListening);

  if(m_prefs->nlMode() & 2)
  {
    m_myInfo->setStatusDescription(m_nowListening);
    slot_statusAnswer(m_chatWgt->currentChannelName(), Globals::prefs()->broadcast(), 0, 0);
  }

#endif
}
//\*****************************************************************************
quint32 ChatCore::initSendingFile(const QHostAddress & addr, const QString & filename, QObject* ftw)
{
  clearParametrs();
  prepareDatagram(Globals::FILE, addr.toIPv4Address());

  quint32 id = m_sender->getValidID();

  if(id)
  {
    qDebug("[ChatCore::sendFile]:str = %s", filename.right(filename.size() - 1 - filename.lastIndexOf("/")).toLocal8Bit().data());

    emit wantSendFile(m_header, m_headerSize, filename, addr, id);
    m_header = NULL;
    m_data   = NULL;

    connect(m_receiver, SIGNAL(percentsConfirmed(quint8, quint16, QHostAddress)),
            ftw       , SLOT  (slot_setProgress (quint8, quint16, QHostAddress)));
    connect(m_receiver, SIGNAL(receivingRejected       (quint16)),
            ftw       , SLOT  (slot_rejectedByReceiver (quint16)));
    connect(m_receiver, SIGNAL(receivingCancelled      (quint16)),
            ftw       , SLOT  (slot_cancelledByReceiver(quint16)));
    connect(m_receiver, SIGNAL(receivingCancelled      (quint16)),
            m_sender  , SLOT  (slot_cancelTask         (quint16)));
    connect(m_sender  , SIGNAL(sendingCancelled        (quint16)),
            ftw       , SLOT  (slot_cannotSend         (quint16)));
    connect(m_sender  , SIGNAL(sendingFinished         (quint16)),
            ftw       , SLOT  (slot_sendingTimeout     (quint16)));
    connect(ftw       , SIGNAL(rejected            (quint16, quint64, int)),
            this      , SLOT  (slot_rejectReceiving(quint16, quint64, int)));// slot_rejectReceiving, but here it working such 'cancel Sending' :)
    connect(ftw       , SIGNAL(cancel         (quint16)),
            m_sender  , SLOT  (slot_cancelTask(quint16)));
  }

  return id;
}
//\*****************************************************************************
void ChatCore::initReceivingFile(QObject* obj)
{
  connect(m_receiver, SIGNAL(percentsRemain      (quint8, quint16, QHostAddress)),
          obj       , SLOT  (slot_setProgress    (quint8, quint16, QHostAddress)));

  connect(obj       , SIGNAL(accepted            (QString, quint16, quint64)),
          m_receiver, SLOT  (slot_acceptDatagram (QString, quint16, quint64)));

  connect(obj       , SIGNAL(rejected            (quint16, quint64, int)),
          m_receiver, SLOT  (slot_rejectDatagram (quint16, quint64)));

  connect(m_receiver, SIGNAL(readyReceive          (quint16, quint64)),
          this      , SLOT  (slot_acceptReceiving  (quint16, quint64)));

  connect(m_receiver, SIGNAL(sendingCancelled      (quint16, quint64)),
          obj       , SLOT  (slot_cancelledBySender(quint16, quint64)));

  connect(obj       , SIGNAL(rejected            (quint16, quint64, int)),
          this      , SLOT  (slot_rejectReceiving(quint16, quint64, int)));

  connect(m_receiver, SIGNAL(percentsRemain           (quint8, quint16, QHostAddress)),
          this      , SLOT  (slot_confirmReceivingFile(quint8, quint16, QHostAddress)));

  connect(m_receiver, SIGNAL(receivingTimeout     (quint16, quint64)),
          obj       , SLOT  (slot_receivingTimeout(quint16, quint64)));
}
//\*****************************************************************************
00936 void ChatCore::slot_loadProfile(const QString & name)
{
  UserProfile* profile = m_profiles[name];
  QByteArray   data;
  QImage       pix;

  if(profile)
  {
    qDebug("[ChatCore::loadProfile]: %s", name.toLocal8Bit().data());

    m_currentProfile = profile;

    m_myInfo = profile->info();
    m_prefs  = profile->prefs();

    m_myInfo->setCompName(QHostInfo::localHostName());

    Globals::setInfo (m_myInfo);
    Globals::setPrefs(m_prefs);
  }

  else
  {
    m_myInfo = new UserInfo;
    m_prefs  = new Preferences;
    profile  = new UserProfile(name, m_prefs, m_myInfo);

    m_currentProfile = profile;

    Globals::setPrefs(m_prefs);
    Globals::setInfo(m_myInfo);

    m_profiles.insert(name, profile);

    m_myInfo->setNickname(name);
  }

  Globals::setProfileName(name);

  emit profileLoaded(name);
}
//\*****************************************************************************
QStringList ChatCore::profiles() const
{
  QStringList profiles;
  QMapIterator<QString, UserProfile*> i(m_profiles);

  while (i.hasNext())
  {
    i.next();
    profiles << i.key();
  }

  return profiles;
}
//\*****************************************************************************
const QString & ChatCore::currentProfile() const
{
  return m_currentProfile->name();
}
//\*****************************************************************************
void ChatCore::slot_renameProfile(const QString & old_name, const QString & new_name)
{
  UserProfile* profile = m_profiles[old_name];

  if(profile)
  {
    profile->rename(new_name);
    m_profiles.erase(m_profiles.find(old_name));
    m_profiles.insert(new_name, profile);
  }
}

void ChatCore::slot_deleteProfile(const QString & name)
{
  m_profiles.erase(m_profiles.find(name));

  delete m_currentProfile->info();
  delete m_currentProfile->prefs();
  delete m_currentProfile;

  slot_loadProfile(m_profiles.begin().key());
}

01020 void ChatCore::processSmiles(QString msg) // TODO perepisat'
{
  Smile*        smile;
  QList<Smile*> smiles;
  QString       sm_str;
  QString msg_ = msg;
  int idx_end = 0;
  QString str;

  smile   = 0;
  sm_str  = ChatTextWgt::nextSmile(msg, &smile);
  idx_end = msg.indexOf(sm_str);

  for(; idx_end != -1 && sm_str != "";)
  {
    if(smile)
    {
      if(sm_str != smile->smiles[0])
      {
        msg_.replace(sm_str, smile->smiles[0]);
        sm_str = smile->smiles[0];
      }

      if(!smiles.contains(smile))
      {
        smiles.append(smile);
        m_smilesParam.append(sm_str.toUtf8());
        m_smilesParam.append((char)0);
      }
    }

    str = msg.left(idx_end);
    msg = msg.right(msg.size() - idx_end - sm_str.size());

    sm_str   = ChatTextWgt::nextSmile(msg, &smile);
    if(sm_str == "")
      break;

    idx_end = msg.indexOf(smile->smiles[0]);
  }

  addParametr("Smiles", m_smilesParam);

  QList<Smile*>::const_iterator i;

  for (i = smiles.constBegin(); i != smiles.constEnd(); ++i)
  {
    str = Globals::prefs()->smilesThemePath() + (*i)->name;
    if(QFile(str).exists())
      addParametr(QString("Smile") + (*i)->smiles[0], str);
    else if(QFile(str + ".png").exists())
      addParametr(QString("Smile") + (*i)->smiles[0], str + ".png");
    else if(QFile(str + ".gif").exists())
      addParametr(QString("Smile") + (*i)->smiles[0], str + ".gif");
    else if(QFile(str + ".jpg").exists())
      addParametr(QString("Smile") + (*i)->smiles[0], str + ".jpg");
  }
}

void ChatCore::slot_msgsHistoryAnswer(const QString & ch_name_id, const QHostAddress & addr, const QByteArray & msgs, uint type)
{
  addParametr("Channel"    , ch_name_id.toUtf8());
  addParametr("MsgsHistory", msgs);

  prepareDatagram(Globals::MSGS_HISTORY_ANSWER, addr.toIPv4Address(), QString(""), type);

  sendData(addr);
}

void ChatCore::slot_msgsNumAnswer(const QString & ch_name_id, const QHostAddress & addr, quint32 msgs_num, uint type)
{
  addParametr("Channel", ch_name_id.toUtf8());
  addParametr("MsgsNum", QString().setNum(msgs_num).toUtf8());

  prepareDatagram(Globals::MSGS_NUM_ANSWER, addr.toIPv4Address(), QString(""), type);

  sendData(addr);
}

void ChatCore::slot_sendMessage(const QString & ch_name_id, const QHostAddress & addr, quint32 ch_type, QTextDocument* doc)
{
  QString fname;
  QString smname;
  int sm_num = 0;
  QTextCursor cur(doc);
  QMap<QString, int> smiles;


  m_smilesParam.clear();

  for(QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
  {
    cur = QTextCursor(it);

    QTextBlock::iterator i = cur.block().begin();
    for (; i != cur.block().end(); i++)
    {
      QTextFormat fmt = i.fragment().charFormat();
      if(fmt.isImageFormat())
      {
        fname = fmt.stringProperty(QTextFormat::ImageName);

        if(!smiles.contains(fname))
        {
          smname = QString().setNum(sm_num) + QString(QChar(0xFFFC + 1));

          m_smilesParam.append(smname.toUtf8());
          m_smilesParam.append((char)0);

          smiles.insert(fname, sm_num);

          sm_num++;

          addParametr("Smile" + smname, fname);
        }
        else
          smname = QString().setNum(smiles.value(fname)) + QString(QChar(0xFFFC + 1));

        cur.beginEditBlock();

        cur.clearSelection();
        cur.setPosition(i.fragment().position());
        cur.deleteChar();
        cur.insertText(smname);

        cur.endEditBlock();

        i = cur.block().begin();
      }
    }
  }

//   slot_prepareAndSend(ch_name_id, addr, Globals::MESSAGE, doc->toHtml(), ch_type, NULL);
  slot_prepareAndSend(ch_name_id, addr, Globals::MESSAGE, doc->toPlainText(), ch_type, NULL);

  doc->deleteLater();
}

void ChatCore::slot_avatarAnswer(const QString & ch_name_id, const QHostAddress & addr, quint32 channel_type)
{
  if(m_myInfo->status() == Globals::INVISIBLE)
    return;

  QByteArray data;
  QBuffer    buffer;
  const QImage* icon = m_myInfo->newIconImg();

  buffer.setBuffer(&data);

  if(icon)
  {
    icon->save(&buffer, "PNG", 100);
    delete icon;
  }

  addParametr("Channel", ch_name_id.toUtf8());
  addParametr("Icon", data);
  addParametr("IconHash", Globals::info()->avatarHash());

  prepareDatagram(Globals::AVATAR_ANSWER,
                  addr.toIPv4Address(),
                  QString(""),
                  channel_type);

  sendData(addr);
}

#include "chatcore_settings.cpp"

Generated by  Doxygen 1.6.0   Back to index