aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules/dcc/DccChatWindow.cpp
diff options
context:
space:
mode:
authorGravatar Szymon Tomasz Stefanek2011-01-01 20:19:56 +0000
committerGravatar Szymon Tomasz Stefanek2011-01-01 20:19:56 +0000
commitc601b5a27f74b16158adafe429faefbe573e64a2 (patch)
treea3cde3206a45628f8ac86e8dfbdab70b20c3a831 /src/modules/dcc/DccChatWindow.cpp
parentprobable compilation fix for rijndaled/crypto++ (diff)
downloadKVIrc-c601b5a27f74b16158adafe429faefbe573e64a2.tar.gz
KVIrc-c601b5a27f74b16158adafe429faefbe573e64a2.tar.bz2
KVIrc-c601b5a27f74b16158adafe429faefbe573e64a2.zip
The big rename for modules. Still some details remaining.
git-svn-id: https://svn.kvirc.de/svn/trunk/kvirc@5284 17fca916-40b9-46aa-a4ea-0a15b648b75c
Diffstat (limited to 'src/modules/dcc/DccChatWindow.cpp')
-rw-r--r--src/modules/dcc/DccChatWindow.cpp893
1 files changed, 893 insertions, 0 deletions
diff --git a/src/modules/dcc/DccChatWindow.cpp b/src/modules/dcc/DccChatWindow.cpp
new file mode 100644
index 000000000..bf5a935c9
--- /dev/null
+++ b/src/modules/dcc/DccChatWindow.cpp
@@ -0,0 +1,893 @@
+//=============================================================================
+//
+// File : DccChatWindow.cpp
+// Creation date : Tue Sep 20 09 2000 15:13:13 by Szymon Stefanek
+//
+// This file is part of the KVIrc irc client distribution
+// Copyright (C) 2000-2010 Szymon Stefanek (pragma at kvirc dot net)
+//
+// 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 opinion) any later version.
+//
+// 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.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#include "DccChatWindow.h"
+#include "DccMarshal.h"
+#include "DccBroker.h"
+
+#ifdef COMPILE_ON_WINDOWS
+ // Ugly Windoze compiler...
+ #include "DccDialog.h"
+#endif
+
+#include "kvi_debug.h"
+#include "KviOptions.h"
+#include "KviInput.h"
+#include "KviIrcView.h"
+#include "KviIconManager.h"
+#include "KviLocale.h"
+#include "kvi_out.h"
+#include "KviNetUtils.h"
+#include "KviConsoleWindow.h"
+#include "KviMainWindow.h"
+#include "KviMemory.h"
+#include "KviMemory.h"
+#include "KviThread.h"
+#include "KviIrcSocket.h"
+#include "kvi_settings.h"
+#include "kvi_socket.h"
+#include "KviApplication.h"
+#include "KviParameterList.h"
+#include "KviIrcConnection.h"
+#include "KviIrcConnectionUserInfo.h"
+#include "KviKvsEventTriggers.h"
+#include "KviMircCntrl.h"
+#include "KviTalVBox.h"
+
+#include <QEvent>
+#include <QResizeEvent>
+#include <QByteArray>
+#include <QTextDocument> //for Qt::escape
+
+#ifdef COMPILE_CRYPT_SUPPORT
+ #include "KviCryptEngine.h"
+ #include "KviCryptController.h"
+#endif
+
+#ifdef COMPILE_SSL_SUPPORT
+ #include "KviSSLMaster.h"
+#endif
+
+extern DccBroker * g_pDccBroker;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////
+////// WINDOW
+//////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+DccChatWindow::DccChatWindow(KviMainWindow *pFrm,DccDescriptor * dcc,const char * name)
+: DccWindow(KVI_WINDOW_TYPE_DCCCHAT,pFrm,name,dcc)
+{
+ m_pButtonBox = new KviTalHBox(this);
+
+ m_pLabel = new KviThemedLabel(m_pButtonBox, this, "dcc_chat_label");
+ m_pLabel->setText(name);
+ m_pButtonBox->setStretchFactor(m_pLabel,1);
+
+ m_pButtonContainer= new KviTalHBox(m_pButtonBox);
+ createTextEncodingButton(m_pButtonContainer);
+
+#ifdef COMPILE_CRYPT_SUPPORT
+ createCryptControllerButton(m_pButtonContainer);
+#endif
+
+ m_pSplitter = new KviTalSplitter(Qt::Horizontal,this);
+ m_pSplitter->setObjectName("dcc_chat_splitter");
+ m_pSplitter->setChildrenCollapsible(false);
+
+ m_pIrcView = new KviIrcView(m_pSplitter,pFrm,this);
+ connect(m_pIrcView,SIGNAL(rightClicked()),this,SLOT(textViewRightClicked()));
+ m_pInput = new KviInput(this);
+
+ //setFocusHandler(m_pInput,this);
+
+ m_pSlaveThread = 0;
+
+ if(KVI_OPTION_BOOL(KviOption_boolAutoLogDccChat))m_pIrcView->startLogging();
+
+ m_pMarshal = new DccMarshal(this);
+ connect(m_pMarshal,SIGNAL(error(int)),this,SLOT(handleMarshalError(int)));
+ connect(m_pMarshal,SIGNAL(connected()),this,SLOT(connected()));
+ connect(m_pMarshal,SIGNAL(inProgress()),this,SLOT(connectionInProgress()));
+#ifdef COMPILE_SSL_SUPPORT
+ connect(m_pMarshal,SIGNAL(startingSSLHandshake()),this,SLOT(startingSSLHandshake()));
+ connect(m_pMarshal,SIGNAL(sslError(const char *)),this,SLOT(sslError(const char *)));
+#endif
+
+ m_pSlaveThread = 0;
+
+ startConnection();
+}
+
+DccChatWindow::~DccChatWindow()
+{
+ g_pDccBroker->unregisterDccWindow(this);
+ if(m_pSlaveThread)
+ {
+ m_pSlaveThread->terminate();
+ delete m_pSlaveThread;
+ m_pSlaveThread = 0;
+ }
+ KviThreadManager::killPendingEvents(this);
+}
+
+void DccChatWindow::textViewRightClicked()
+{
+ KVS_TRIGGER_EVENT_1(KviEvent_OnDCCChatPopupRequest,this,m_pDescriptor->idString());
+}
+
+void DccChatWindow::triggerCreationEvents()
+{
+ KVS_TRIGGER_EVENT_1(KviEvent_OnDCCChatWindowCreated,this,m_pDescriptor->idString());
+}
+
+void DccChatWindow::triggerDestructionEvents()
+{
+ KVS_TRIGGER_EVENT_1(KviEvent_OnDCCChatWindowClosing,this,m_pDescriptor->idString());
+}
+
+void DccChatWindow::startConnection()
+{
+ if(!(m_pDescriptor->bActive))
+ {
+ // PASSIVE CONNECTION
+ output(KVI_OUT_DCCMSG,__tr2qs_ctx("Attempting a passive DCC %s connection","dcc"),m_pDescriptor->szType.toUtf8().data());
+#ifdef COMPILE_SSL_SUPPORT
+ KviError::Code eError = m_pMarshal->dccListen(m_pDescriptor->szListenIp,m_pDescriptor->szListenPort,m_pDescriptor->bDoTimeout,m_pDescriptor->bIsSSL);
+#else
+ KviError::Code eError = m_pMarshal->dccListen(m_pDescriptor->szListenIp,m_pDescriptor->szListenPort,m_pDescriptor->bDoTimeout);
+#endif
+ if(eError != KviError::Success)
+ handleMarshalError(eError);
+ } else {
+ // ACTIVE CONNECTION
+ output(KVI_OUT_DCCMSG,__tr2qs_ctx("Attempting an active DCC %s connection","dcc"),m_pDescriptor->szType.toUtf8().data());
+#ifdef COMPILE_SSL_SUPPORT
+ KviError::Code eError = m_pMarshal->dccConnect(m_pDescriptor->szIp.toUtf8().data(),m_pDescriptor->szPort.toUtf8().data(),m_pDescriptor->bDoTimeout,m_pDescriptor->bIsSSL);
+#else
+ KviError::Code eError = m_pMarshal->dccConnect(m_pDescriptor->szIp.toUtf8().data(),m_pDescriptor->szPort.toUtf8().data(),m_pDescriptor->bDoTimeout);
+#endif
+ if(eError != KviError::Success)
+ handleMarshalError(eError);
+ }
+}
+
+void DccChatWindow::connectionInProgress()
+{
+ if(m_pDescriptor->bActive)
+ {
+ output(KVI_OUT_DCCMSG,__tr2qs_ctx("Contacting host %Q on port %Q","dcc"),&(m_pDescriptor->szIp),&(m_pDescriptor->szPort));
+ } else {
+ output(KVI_OUT_DCCMSG,__tr2qs_ctx("Listening on interface %Q port %Q","dcc"),&(m_pMarshal->localIp()),&(m_pMarshal->localPort()));
+
+ if(m_pDescriptor->bSendRequest)
+ {
+ KviCString ip;
+ if(!m_pDescriptor->szFakeIp.isEmpty())
+ {
+ ip = m_pDescriptor->szFakeIp;
+ } else {
+ ip = m_pDescriptor->szListenIp;
+
+ if(KVI_OPTION_BOOL(KviOption_boolDccGuessIpFromServerWhenLocalIsUnroutable))
+ {
+ if(!kvi_isRoutableIpString(ip.ptr()))
+ {
+ // try to get the IP that the IRC server can see
+ if(m_pDescriptor->console())
+ {
+ KviCString tmp = m_pDescriptor->console()->connection() ? m_pDescriptor->console()->connection()->userInfo()->hostIp().toUtf8().data() : "";
+ if(tmp.hasData())
+ {
+ ip = tmp;
+ output(KVI_OUT_DCCMSG,__tr2qs_ctx("The local IP address is private, determining from IRC server: %s","dcc"),ip.ptr());
+ } else {
+ output(KVI_OUT_DCCMSG,__tr2qs_ctx("The local IP address is private, but unable to determine it from the IRC server","dcc"));
+ }
+ } else {
+ output(KVI_OUT_DCCMSG,__tr2qs_ctx("The local IP address is private, but have no IRC server to determine it from","dcc"));
+ }
+ }
+ }
+ }
+
+ QString port = !m_pDescriptor->szFakePort.isEmpty() ? m_pDescriptor->szFakePort : QString(m_pMarshal->localPort());
+
+ //FIXME: #warning "OPTION FOR SENDING 127.0.0.1 and so on (not an unsigned number)"
+ struct in_addr a;
+ if(KviNetUtils::stringIpToBinaryIp(ip.ptr(),&a))ip.setNum(htonl(a.s_addr));
+
+ QString szReq = QString("PRIVMSG %1 :%2DCC %3 chat %4 %5").arg(m_pDescriptor->szNick, QChar(0x01), m_pDescriptor->szType, ip.ptr(), port);
+
+ if(m_pDescriptor->isZeroPortRequest())
+ {
+ szReq.append(" ");
+ szReq+=m_pDescriptor->zeroPortRequestTag();
+ }
+ szReq.append((char)(0x01));
+
+ m_pDescriptor->console()->connection()->sendData(m_pDescriptor->console()->connection()->encodeText(szReq).data());
+ output(KVI_OUT_DCCMSG,__tr2qs_ctx("Sent DCC %Q request to %Q, waiting for the remote client to connect...","dcc"),
+ &(m_pDescriptor->szType),&(m_pDescriptor->szNick));
+ //qDebug(m_pDescriptor->szNick);
+ } else output(KVI_OUT_DCCMSG,__tr2qs_ctx("DCC %Q request not sent, awaiting manual connection","dcc"),&(m_pDescriptor->szType));
+ }
+ KVS_TRIGGER_EVENT_1(KviEvent_OnDCCChatConnectionInProgress,this,m_pDescriptor->idString());
+}
+
+void DccChatWindow::startingSSLHandshake()
+{
+#ifdef COMPILE_SSL_SUPPORT
+ outputNoFmt(KVI_OUT_SSL,__tr2qs_ctx("Low-level transport connection established","dcc"));
+ outputNoFmt(KVI_OUT_SSL,__tr2qs_ctx("Starting Secure Socket Layer handshake","dcc"));
+#endif
+}
+
+void DccChatWindow::sslError(const char * msg)
+{
+#ifdef COMPILE_SSL_SUPPORT
+ if(!KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnDCCChatError,this,QString(msg),m_pDescriptor->idString()))
+ output(KVI_OUT_DCCERROR,__tr2qs_ctx("[SSL ERROR]: %s","dcc"),msg);
+#endif
+}
+
+const QString & DccChatWindow::target()
+{
+ // This may change on the fly...
+ m_szTarget = m_pDescriptor->szNick;
+ m_szTarget += "@";
+ m_szTarget += m_pDescriptor->szIp;
+ m_szTarget += ":";
+ m_szTarget += m_pDescriptor->szPort;
+ return m_szTarget;
+}
+
+void DccChatWindow::fillCaptionBuffers()
+{
+ QString tmp = QString("DCC %1 %2@%3:%4").arg(
+#ifdef COMPILE_SSL_SUPPORT
+ m_pDescriptor->bIsSSL ? "SChat" : "Chat",
+#else
+ "Chat",
+#endif
+ m_pDescriptor->szNick, m_pDescriptor->szIp, m_pDescriptor->szPort);
+
+ m_szPlainTextCaption = tmp;
+}
+
+QPixmap * DccChatWindow::myIconPtr()
+{
+ return g_pIconManager->getSmallIcon(KVI_SMALLICON_DCCMSG);
+}
+
+void DccChatWindow::getBaseLogFileName(QString &buffer)
+{
+ buffer.sprintf("%s_%s_%s",m_pDescriptor->szNick.toUtf8().data(),m_pDescriptor->szIp.toUtf8().data(),m_pDescriptor->szPort.toUtf8().data());
+}
+
+void DccChatWindow::ownMessage(const QString &text, bool bUserFeedback)
+{
+ if(!m_pSlaveThread)
+ {
+ output(KVI_OUT_SYSTEMWARNING,__tr2qs_ctx("Cannot send data: No active connection","dcc"));
+ return;
+ }
+
+ QByteArray szData = encodeText(text);
+ const char * d = szData.data();
+ if(!d)return;
+
+#ifdef COMPILE_CRYPT_SUPPORT
+ if(cryptSessionInfo())
+ {
+ if(cryptSessionInfo()->m_bDoEncrypt)
+ {
+ if(*d != KviMircCntrl::CryptEscape)
+ {
+ KviCString encrypted;
+ cryptSessionInfo()->m_pEngine->setMaxEncryptLen(-1);
+ switch(cryptSessionInfo()->m_pEngine->encrypt(d,encrypted))
+ {
+ case KviCryptEngine::Encrypted:
+ {
+ KviCString buf(KviCString::Format,"%s\r\n",encrypted.ptr());
+ m_pSlaveThread->sendRawData(buf.ptr(),buf.len());
+ if(bUserFeedback)
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_OWNPRIVMSGCRYPTED,
+ m_pDescriptor->szLocalNick.toUtf8().data(),m_pDescriptor->szLocalUser.toUtf8().data(),
+ m_pDescriptor->szLocalHost.toUtf8().data(),text,KviConsoleWindow::NoNotifications);
+ }
+ break;
+ case KviCryptEngine::Encoded:
+ {
+ KviCString buf(KviCString::Format,"%s\r\n",encrypted.ptr());
+ m_pSlaveThread->sendRawData(buf.ptr(),buf.len());
+ if(bUserFeedback)
+ {
+ QString encr = decodeText(encrypted.ptr());
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_OWNPRIVMSG,
+ m_pDescriptor->szLocalNick.toUtf8().data(),m_pDescriptor->szLocalUser.toUtf8().data(),
+ m_pDescriptor->szLocalHost.toUtf8().data(),encr,KviConsoleWindow::NoNotifications);
+ }
+ }
+ break;
+ default: // also case KviCryptEngine::EncryptError
+ {
+ QString szErr = cryptSessionInfo()->m_pEngine->lastError();
+ output(KVI_OUT_SYSTEMERROR,
+ __tr2qs_ctx("The crypto engine was not able to encrypt the current message (%Q): %Q, no data was sent to the remote end","dcc"),
+ &text,&szErr);
+ }
+ break;
+ }
+ return;
+ } else {
+ d++; //eat the escape code
+ KviCString buf(KviCString::Format,"%s\r\n",d);
+ QString tmp = text.right(text.length() - 1);
+ m_pSlaveThread->sendRawData(buf.ptr(),buf.len());
+
+ if(bUserFeedback)
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_OWNPRIVMSG,
+ m_pDescriptor->szLocalNick.toUtf8().data(),m_pDescriptor->szLocalUser.toUtf8().data(),
+ m_pDescriptor->szLocalHost.toUtf8().data(),tmp,KviConsoleWindow::NoNotifications);
+ return;
+ }
+ }
+ }
+#endif
+ KviCString buf(KviCString::Format,"%s\r\n",d);
+ m_pSlaveThread->sendRawData(buf.ptr(),buf.len());
+
+ if(bUserFeedback)
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_OWNPRIVMSG,
+ m_pDescriptor->szLocalNick.toUtf8().data(),m_pDescriptor->szLocalUser.toUtf8().data(),
+ m_pDescriptor->szLocalHost.toUtf8().data(),text,KviConsoleWindow::NoNotifications);
+}
+
+const QString & DccChatWindow::localNick()
+{
+ // FIXME: This is just a complete HACK
+ m_szLocalNick = m_pDescriptor->szLocalNick;
+ return m_szLocalNick;
+}
+
+void DccChatWindow::ownAction(const QString &text)
+{
+ if(m_pSlaveThread)
+ {
+ QString szTmpBuffer;
+ //see bug ticket #220
+ if(KVI_OPTION_BOOL(KviOption_boolStripMircColorsInUserMessages))
+ {
+ szTmpBuffer = KviMircCntrl::stripControlBytes(text);
+ } else {
+ szTmpBuffer = text;
+ }
+
+ QByteArray szData = encodeText(szTmpBuffer);
+ const char * d = szData.data();
+ if(!d)
+ return;
+ KviCString buf(KviCString::Format,"%cACTION %s%c\r\n",0x01,d,0x01);
+ m_pSlaveThread->sendRawData(buf.ptr(),buf.len());
+ output(KVI_OUT_ACTION,"%Q %Q",&(m_pDescriptor->szLocalNick),&szTmpBuffer);
+ } else {
+ output(KVI_OUT_SYSTEMWARNING,__tr2qs_ctx("Cannot send data: No active connection","dcc"));
+ }
+}
+
+bool DccChatWindow::event(QEvent *e)
+{
+ if(e->type() == KVI_THREAD_EVENT)
+ {
+ switch(((KviThreadEvent *)e)->id())
+ {
+ case KVI_DCC_THREAD_EVENT_ERROR:
+ {
+ KviError::Code * pError = ((KviThreadDataEvent<KviError::Code> *)e)->getData();
+ QString szErr = KviError::getDescription(*pError);
+ if(!KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnDCCChatError,this,szErr,m_pDescriptor->idString()))
+ output(KVI_OUT_DCCERROR,__tr2qs_ctx("ERROR: %Q","dcc"),&szErr);
+ KVS_TRIGGER_EVENT_1(KviEvent_OnDCCChatDisconnected,this,m_pDescriptor->idString());
+ delete pError;
+ return true;
+ }
+ break;
+ case KVI_DCC_THREAD_EVENT_DATA:
+ {
+ KviCString * encoded = ((KviThreadDataEvent<KviCString> *)e)->getData();
+ KviCString d=KviCString(decodeText(encoded->ptr()));
+ if(d.firstCharIs(0x01))
+ {
+ d.cutLeft(1);
+ if(d.lastCharIs(0x01))d.cutRight(1);
+ if(kvi_strEqualCIN("ACTION",d.ptr(),6))d.cutLeft(6);
+ d.stripLeftWhiteSpace();
+ output(KVI_OUT_ACTION,"%Q %s",&(m_pDescriptor->szNick),d.ptr());
+ if(!hasAttention())
+ {
+ if(KVI_OPTION_BOOL(KviOption_boolFlashDccChatWindowOnNewMessages))
+ {
+ demandAttention();
+ }
+ if(KVI_OPTION_BOOL(KviOption_boolPopupNotifierOnNewDccChatMessages))
+ {
+ QString szMsg = "<b>";
+ szMsg += m_pDescriptor->szNick;
+ szMsg += "</b> ";
+ szMsg += Qt::escape(QString(d.ptr()));
+ //qDebug("KviIrcServerParser_ctcp.cpp:975 debug: %s",szMsg.data());
+ g_pApp->notifierMessage(this,KVI_OPTION_MSGTYPE(KVI_OUT_ACTION).pixId(),szMsg,KVI_OPTION_UINT(KviOption_uintNotifierAutoHideTime));
+ }
+ }
+ } else {
+
+#ifdef COMPILE_CRYPT_SUPPORT
+ if(KviCryptSessionInfo * cinf = cryptSessionInfo())
+ {
+ if(cinf->m_bDoDecrypt)
+ {
+ KviCString decryptedStuff;
+ switch(cinf->m_pEngine->decrypt(d.ptr(),decryptedStuff))
+ {
+ case KviCryptEngine::DecryptOkWasEncrypted:
+ case KviCryptEngine::DecryptOkWasEncoded:
+ case KviCryptEngine::DecryptOkWasPlainText:
+ if(!KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnDCCChatMessage,this,QString(decryptedStuff.ptr()),m_pDescriptor->idString()))
+ {
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_DCCCHATMSG,
+ m_pDescriptor->szNick.toUtf8().data(),m_pDescriptor->szUser.toUtf8().data(),
+ m_pDescriptor->szHost.toUtf8().data(),decryptedStuff.ptr());
+ }
+ delete encoded;
+ return true;
+ break;
+
+ default: // also case KviCryptEngine::DecryptError
+ {
+ QString szErr = cinf->m_pEngine->lastError();
+ output(KVI_OUT_SYSTEMERROR,
+ __tr2qs_ctx("The following message appears to be encrypted, but the crypto engine failed to decode it: %Q","dcc"),
+ &szErr);
+ }
+ break;
+ }
+ }
+ } else {
+#endif
+ // FIXME!
+ if(!KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnDCCChatMessage,this,QString(d.ptr()),m_pDescriptor->idString()))
+ {
+ m_pFrm->firstConsole()->outputPrivmsg(this,KVI_OUT_DCCCHATMSG,
+ m_pDescriptor->szNick.toUtf8().data(),m_pDescriptor->szUser.toUtf8().data(),
+ m_pDescriptor->szHost.toUtf8().data(),d.ptr());
+ if(!hasAttention())
+ {
+ if(KVI_OPTION_BOOL(KviOption_boolFlashDccChatWindowOnNewMessages))
+ {
+ demandAttention();
+ }
+ if(KVI_OPTION_BOOL(KviOption_boolPopupNotifierOnNewDccChatMessages))
+ {
+ QString szMsg = Qt::escape(QString(d.ptr()));
+ g_pApp->notifierMessage(this,KVI_SMALLICON_DCCCHATMSG,szMsg,KVI_OPTION_UINT(KviOption_uintNotifierAutoHideTime));
+ }
+ }
+ }
+#ifdef COMPILE_CRYPT_SUPPORT
+ }
+#endif
+ }
+ delete encoded;
+ return true;
+ }
+ break;
+ }
+ }
+ return KviWindow::event(e);
+}
+
+void DccChatWindow::resizeEvent(QResizeEvent *)
+{
+ int hght = m_pInput->heightHint();
+ int hght2 = m_pButtonBox->sizeHint().height();
+ m_pButtonBox->setGeometry(0,0,width(),hght2);
+ m_pSplitter->setGeometry(0,hght2,width(),height() - (hght + hght2));
+ m_pInput->setGeometry(0,height() - hght,width(),hght);
+}
+
+QSize DccChatWindow::sizeHint() const
+{
+ QSize ret(m_pIrcView->sizeHint().width(),
+ m_pIrcView->sizeHint().height() + m_pInput->heightHint());
+ return ret;
+}
+
+void DccChatWindow::handleMarshalError(KviError::Code eError)
+{
+ QString szErr = KviError::getDescription(eError);
+ if(!KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnDCCChatError,this,szErr,m_pDescriptor->idString()))
+ output(KVI_OUT_DCCERROR,__tr2qs_ctx("DCC %Q failed: %Q","dcc"),&(m_pDescriptor->szType),&szErr);
+}
+
+void DccChatWindow::connected()
+{
+ if(!(m_pDescriptor->bActive))
+ {
+ // PASSIVE CONNECTION...Find out the remote end
+ m_pDescriptor->szIp = m_pMarshal->remoteIp();
+ m_pDescriptor->szPort = m_pMarshal->remotePort();
+ m_pDescriptor->szHost = m_pMarshal->remoteIp();
+ }
+
+ updateCaption();
+
+ m_pSlaveThread = new DccChatThread(this,m_pMarshal->releaseSocket());
+
+#ifdef COMPILE_SSL_SUPPORT
+ KviSSL * s = m_pMarshal->releaseSSL();
+ if(s)
+ {
+ KviSSLMaster::printSSLConnectionInfo(this,s);
+ m_pSlaveThread->setSSL(s);
+ }
+#endif
+ m_pSlaveThread->start();
+
+ if(!KVS_TRIGGER_EVENT_1_HALTED(KviEvent_OnDCCChatConnected,this,m_pDescriptor->idString()))
+ {
+ output(KVI_OUT_DCCMSG,__tr2qs_ctx("Connected to %Q:%Q","dcc"),
+ &(m_pMarshal->remoteIp()),&(m_pMarshal->remotePort()));
+ output(KVI_OUT_DCCMSG,__tr2qs_ctx("Local end is %Q:%Q","dcc"),
+ &(m_pMarshal->localIp()),&(m_pMarshal->localPort()));
+#ifdef COMPILE_SSL_SUPPORT
+ QString tmp = QString("dcc: %1 %2@%3:%4").arg(m_pDescriptor->bIsSSL ? "SChat" : "Chat", m_pDescriptor->szNick, m_pDescriptor->szIp, m_pDescriptor->szPort);
+#else
+ QString tmp = QString("dcc: %1 %2@%3:%4").arg("Chat", m_pDescriptor->szNick, m_pDescriptor->szIp, m_pDescriptor->szPort);
+#endif
+ m_pLabel->setText(tmp);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////
+////// THREAD
+//////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+DccChatThread::DccChatThread(KviWindow *wnd,kvi_socket_t fd)
+: DccThread(wnd,fd)
+{
+ m_pOutBuffers = new KviPointerList<KviDataBuffer>;
+ m_pOutBuffers->setAutoDelete(true);
+}
+
+DccChatThread::~DccChatThread()
+{
+ if(m_pOutBuffers)delete m_pOutBuffers;
+}
+
+void DccChatThread::run()
+{
+ KviDccThreadIncomingData data;
+ data.iLen = 0;
+ data.buffer = 0;
+
+ for(;;)
+ {
+ // Dequeue events
+ while(KviThreadEvent * e = dequeueEvent())
+ {
+ if(e->id() == KVI_THREAD_EVENT_TERMINATE)
+ {
+ delete e;
+ goto out_of_the_loop;
+ } else {
+ // Other events are senseless to us
+ delete e;
+ }
+ }
+
+ bool bCanRead;
+ bool bCanWrite;
+ if(kvi_select(m_fd,&bCanRead,&bCanWrite))
+ {
+ if(bCanWrite)
+ {
+ if(!tryFlushOutBuffers())goto out_of_the_loop;
+ }
+ if(bCanRead)
+ {
+ data.buffer = (char *) KviMemory::reallocate(data.buffer,(data.iLen + 512) * sizeof(char));
+ int readLen;
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ readLen = m_pSSL->read(data.buffer + data.iLen,512);
+ } else {
+#endif
+ readLen = kvi_socket_recv(m_fd,data.buffer + data.iLen,512);
+#ifdef COMPILE_SSL_SUPPORT
+ }
+#endif
+ if(readLen > 0)
+ {
+ data.iLen += readLen;
+ data.buffer = (char *)KviMemory::reallocate(data.buffer,data.iLen * sizeof(char));
+ if(!handleIncomingData(&data,false))break; // non critical...
+ } else {
+
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ // ssl error....?
+ switch(m_pSSL->getProtocolError(readLen))
+ {
+ case KviSSL::ZeroReturn:
+ readLen = 0;
+ break;
+ case KviSSL::WantRead:
+ case KviSSL::WantWrite:
+ // hmmm...
+ break;
+ case KviSSL::SyscallError:
+ {
+ int iE = m_pSSL->getLastError(true);
+ if(iE != 0)
+ {
+ raiseSSLError();
+ postErrorEvent(KviError::SSLError);
+ goto out_of_the_loop;
+ }
+ }
+ break;
+ case KviSSL::SSLError:
+ {
+ raiseSSLError();
+ postErrorEvent(KviError::SSLError);
+ goto out_of_the_loop;
+ }
+ break;
+ default:
+ // Raise unknown SSL ERROR
+ postErrorEvent(KviError::SSLError);
+ goto out_of_the_loop;
+ break;
+ }
+ }
+#endif
+ if(data.iLen > 0)
+ {
+ data.buffer = (char *)KviMemory::reallocate(data.buffer,data.iLen * sizeof(char));
+ } else {
+ KviMemory::free(data.buffer);
+ data.buffer = 0;
+ }
+
+ if(!handleInvalidSocketRead(readLen))
+ {
+ if(data.iLen)handleIncomingData(&data,true); // critical
+ KVI_ASSERT(!data.iLen);
+ break; // error
+ }
+ }
+ }
+ msleep(100);
+ }
+ }
+
+out_of_the_loop:
+
+
+ if(data.iLen)KviMemory::free(data.buffer);
+
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ KviSSLMaster::freeSSL(m_pSSL);
+ m_pSSL = 0;
+ }
+#endif
+
+ if(m_fd != KVI_INVALID_SOCKET)::kvi_socket_close(m_fd);
+ m_fd = KVI_INVALID_SOCKET;
+}
+
+bool DccChatThread::handleIncomingData(KviDccThreadIncomingData * data,bool bCritical)
+{
+ KVI_ASSERT(data->iLen);
+ KVI_ASSERT(data->buffer);
+ char * aux = data->buffer;
+ char * end = data->buffer + data->iLen;
+ while(aux != end)
+ {
+ if((*aux == '\n') || (*aux == '\0'))
+ {
+ KviThreadDataEvent<KviCString> * e = new KviThreadDataEvent<KviCString>(KVI_DCC_THREAD_EVENT_DATA);
+ // The left part is len chars long
+ int len = aux - data->buffer;
+// qDebug("LEN = %d, iLen = %d",len,data->iLen);
+//#warning "DO IT BETTER (the \r cutting)"
+ KviCString * s = new KviCString(data->buffer,len);
+ if(s->lastCharIs('\r'))s->cutRight(1);
+ e->setData(s);
+ // but we cut also \n (or \0)
+ ++aux;
+ // so len += 1; --> new data->iLen -= len;
+ data->iLen -= (len + 1);
+// qDebug("iLen now = %d",data->iLen);
+ KVI_ASSERT(data->iLen >= 0);
+ if(data->iLen > 0)
+ {
+ // memmove the remaining part to the beginning
+ // aux points after \n or \0
+ KviMemory::move(data->buffer,aux,data->iLen);
+ data->buffer = (char *)KviMemory::reallocate(data->buffer,data->iLen);
+ end = data->buffer + data->iLen;
+ aux = data->buffer;
+ } else {
+ // no more data in the buffer
+ KVI_ASSERT(data->iLen == 0);
+ KviMemory::free(data->buffer);
+ data->buffer = end = aux = 0;
+ }
+ postEvent(parent(),e);
+ } else aux++;
+// qDebug("PASSING CHAR %c",*aux);
+ }
+ // now aux == end
+ if(bCritical)
+ {
+ // need to flush everything...
+ if(data->iLen > 0)
+ {
+ // in the last part there are no NULL and \n chars
+ KviThreadDataEvent<KviCString> * e = new KviThreadDataEvent<KviCString>(KVI_DCC_THREAD_EVENT_DATA);
+ KviCString * s = new KviCString(data->buffer,data->iLen);
+ if(s->lastCharIs('\r'))s->cutRight(1);
+ e->setData(s);
+ data->iLen = 0;
+ KviMemory::free(data->buffer);
+ data->buffer = 0;
+ postEvent(parent(),e);
+ }
+ }
+ return true;
+}
+
+void DccChatThread::sendRawData(const void * buffer,int len)
+{
+ m_pMutex->lock();
+ m_pOutBuffers->append(new KviDataBuffer((unsigned int)len,(const unsigned char *)buffer));
+ m_pMutex->unlock();
+}
+
+bool DccChatThread::tryFlushOutBuffers()
+{
+ bool bRet = true;
+ m_pMutex->lock();
+ while(KviDataBuffer * b = m_pOutBuffers->first())
+ {
+ int sentLen;
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ sentLen = m_pSSL->write((const char *)b->data(),b->size());
+ } else {
+#endif
+ sentLen = kvi_socket_send(m_fd,b->data(),b->size());
+#ifdef COMPILE_SSL_SUPPORT
+ }
+#endif
+ if(sentLen > 0)
+ {
+ if(sentLen == b->size())m_pOutBuffers->removeFirst();
+ else {
+ // just a part
+ b->remove((unsigned int)sentLen);
+ break;
+ }
+ } else {
+#ifdef COMPILE_SSL_SUPPORT
+ if(m_pSSL)
+ {
+ // ops...might be an SSL error
+ switch(m_pSSL->getProtocolError(sentLen))
+ {
+ case KviSSL::WantWrite:
+ case KviSSL::WantRead:
+ // Async continue...
+ goto handle_system_error;
+ break;
+ case KviSSL::SyscallError:
+ if(sentLen == 0)
+ {
+ raiseSSLError();
+ postErrorEvent(KviError::RemoteEndClosedConnection);
+ bRet = false;
+ goto out_of_the_loop;
+ } else {
+ int iSSLErr = m_pSSL->getLastError(true);
+ if(iSSLErr != 0)
+ {
+ raiseSSLError();
+ postErrorEvent(KviError::SSLError);
+ bRet = false;
+ goto out_of_the_loop;
+ } else {
+ goto handle_system_error;
+ }
+ }
+ break;
+ case KviSSL::SSLError:
+ raiseSSLError();
+ postErrorEvent(KviError::SSLError);
+ bRet = false;
+ goto out_of_the_loop;
+ break;
+ default:
+ postErrorEvent(KviError::SSLError);
+ bRet = false;
+ goto out_of_the_loop;
+ break;
+ }
+ }
+#endif
+handle_system_error:
+ if(sentLen < 0)
+ {
+ int err = kvi_socket_error();
+#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
+ if((err != EAGAIN) || (err != EINTR) || (err != WSAEWOULDBLOCK))
+#else
+ if((err != EAGAIN)||(err != EINTR))
+#endif
+ {
+ postErrorEvent(KviError::translateSystemError(err));
+ bRet = false;
+ goto out_of_the_loop;
+ }
+ }
+ break; // send error
+ }
+ }
+out_of_the_loop:
+ m_pMutex->unlock();
+ return bRet;
+}
+
+#ifndef COMPILE_USE_STANDALONE_MOC_SOURCES
+#include "m_DccChatWindow.moc"
+#endif //!COMPILE_USE_STANDALONE_MOC_SOURCES