You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1355 lines
40 KiB
1355 lines
40 KiB
//=============================================================================
|
|
//
|
|
// File : kvi_ircconnection.cpp
|
|
// Created on Mon 03 May 2004 01:45:42 by Szymon Stefanek
|
|
//
|
|
// This file is part of the KVIrc IRC client distribution
|
|
// Copyright (C) 2004 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.
|
|
//
|
|
//=============================================================================
|
|
|
|
#define __KVIRC__
|
|
|
|
#include "kvi_ircconnection.h"
|
|
#include "kvi_ircconnectiontarget.h"
|
|
#include "kvi_ircconnectionuserinfo.h"
|
|
#include "kvi_ircconnectionserverinfo.h"
|
|
#include "kvi_ircconnectionstatedata.h"
|
|
#include "kvi_ircconnectionantictcpflooddata.h"
|
|
#include "kvi_ircconnectionnetsplitdetectordata.h"
|
|
#include "kvi_ircconnectionasyncwhoisdata.h"
|
|
#include "kvi_ircconnectionstatistics.h"
|
|
#include "kvi_irclink.h"
|
|
#include "kvi_ircsocket.h"
|
|
#include "kvi_locale.h"
|
|
#include "kvi_ircserverdb.h"
|
|
#include "kvi_proxydb.h"
|
|
#include "kvi_error.h"
|
|
#include "kvi_out.h"
|
|
#include "kvi_options.h"
|
|
#include "kvi_console.h"
|
|
#include "kvi_netutils.h"
|
|
#include "kvi_internalcmd.h"
|
|
#include "kvi_frame.h"
|
|
#include "kvi_mexlinkfilter.h"
|
|
#include "kvi_garbage.h"
|
|
#include "kvi_malloc.h"
|
|
#include "kvi_memmove.h"
|
|
#include "kvi_debug.h"
|
|
#include "kvi_channel.h"
|
|
#include "kvi_query.h"
|
|
#include "kvi_app.h"
|
|
#include "kvi_databuffer.h"
|
|
#include "kvi_notifylist.h"
|
|
#include "kvi_dns.h"
|
|
#include "kvi_defaults.h"
|
|
#include "kvi_sparser.h"
|
|
#include "kvi_ircdatastreammonitor.h"
|
|
#include "kvi_databuffer.h"
|
|
#include "kvi_lagmeter.h"
|
|
#include "kvi_kvs_eventtriggers.h"
|
|
#include "kvi_kvs_script.h"
|
|
#include "kvi_mirccntrl.h"
|
|
#include "kvi_useridentity.h"
|
|
|
|
#include <tqtimer.h>
|
|
#include <tqtextcodec.h>
|
|
|
|
extern KVIRC_API KviIrcServerDataBase * g_pIrcServerDataBase;
|
|
extern KVIRC_API KviProxyDataBase * g_pProxyDataBase;
|
|
extern KVIRC_API KviGarbageCollector * g_pGarbageCollector;
|
|
|
|
KviIrcConnection::KviIrcConnection(KviIrcContext * pContext,KviIrcConnectionTarget * pTarget,KviUserIdentity * pIdentity)
|
|
: TQObject()
|
|
{
|
|
m_bIdentdAttached = false;
|
|
m_pContext = pContext;
|
|
m_pConsole = pContext->console();
|
|
m_pFrame = m_pConsole->frame();
|
|
m_pTarget = pTarget;
|
|
m_pUserIdentity = pIdentity;
|
|
m_pChannelList = new KviPointerList<KviChannel>;
|
|
m_pChannelList->setAutoDelete(false);
|
|
m_pQueryList = new KviPointerList<KviQuery>;
|
|
m_pQueryList->setAutoDelete(false);
|
|
m_pLink = new KviIrcLink(this);
|
|
m_pUserDataBase = new KviIrcUserDataBase();
|
|
m_pUserInfo = new KviIrcConnectionUserInfo();
|
|
m_pServerInfo = new KviIrcConnectionServerInfo();
|
|
m_pStateData = new KviIrcConnectionStateData();
|
|
m_pAntiCtcpFloodData = new KviIrcConnectionAntiCtcpFloodData();
|
|
m_pNetsplitDetectorData = new KviIrcConnectionNetsplitDetectorData();
|
|
m_pAsyncWhoisData = new KviIrcConnectionAsyncWhoisData();
|
|
m_pStatistics = new KviIrcConnectionStatistics();
|
|
m_pNotifyListTimer = 0;
|
|
m_pNotifyListManager = 0;
|
|
m_pLocalhostDns = 0;
|
|
m_pLagMeter = 0;
|
|
m_eState = Idle;
|
|
setupTextCodec();
|
|
}
|
|
|
|
KviIrcConnection::~KviIrcConnection()
|
|
{
|
|
if(m_bIdentdAttached) g_pFrame->executeInternalCommand(KVI_INTERNALCOMMAND_IDENT_STOP);
|
|
m_bIdentdAttached = false;
|
|
if(m_pLocalhostDns)
|
|
{
|
|
TQObject::disconnect(m_pLocalhostDns,TQT_SIGNAL(lookupDone(KviDns *)),0,0);
|
|
if(m_pLocalhostDns->isRunning())
|
|
{
|
|
g_pGarbageCollector->collect(m_pLocalhostDns);
|
|
} else {
|
|
delete m_pLocalhostDns;
|
|
}
|
|
}
|
|
|
|
|
|
if(m_pNotifyListTimer)
|
|
{
|
|
delete m_pNotifyListTimer;
|
|
m_pNotifyListTimer = 0;
|
|
}
|
|
if(m_pNotifyListManager)
|
|
{
|
|
delete m_pNotifyListManager; // destroy this before the userDb
|
|
m_pNotifyListManager = 0;
|
|
}
|
|
if(m_pLagMeter)
|
|
{
|
|
delete m_pLagMeter;
|
|
m_pLagMeter = 0;
|
|
}
|
|
delete m_pLink; // <-- this MAY trigger a linkTerminated() or something like this!
|
|
delete m_pChannelList;
|
|
delete m_pQueryList;
|
|
delete m_pTarget;
|
|
delete m_pUserDataBase;
|
|
delete m_pUserInfo;
|
|
delete m_pServerInfo;
|
|
delete m_pStateData;
|
|
delete m_pAntiCtcpFloodData;
|
|
delete m_pNetsplitDetectorData;
|
|
delete m_pAsyncWhoisData;
|
|
delete m_pStatistics;
|
|
delete m_pUserIdentity;
|
|
}
|
|
|
|
void KviIrcConnection::setEncoding(const TQString &szEncoding)
|
|
{
|
|
TQTextCodec * c = KviLocale::codecForName(szEncoding.latin1());
|
|
if(c == m_pTextCodec)return;
|
|
if(!c)
|
|
{
|
|
m_pConsole->output(KVI_OUT_SYSTEMERROR,__tr2qs("Failed to set the encoding to %Q: mapping not available."),&szEncoding);
|
|
return;
|
|
}
|
|
TQString tmp = c->name();
|
|
for(KviChannel * ch = m_pChannelList->first();ch;ch = m_pChannelList->next())
|
|
{
|
|
if((ch->textCodec() != c) && (ch->textCodec() != ch->defaultTextCodec())) // actually not using the default!
|
|
{
|
|
ch->forceTextCodec(c);
|
|
if(_OUTPUT_VERBOSE)ch->output(KVI_OUT_VERBOSE,__tr2qs("Changed text encoding to %Q"),&tmp);
|
|
}
|
|
}
|
|
for(KviQuery * q = m_pQueryList->first();q;q = m_pQueryList->next())
|
|
{
|
|
if((q->textCodec() != c) && (q->textCodec() != q->defaultTextCodec())) // actually not using the default!
|
|
{
|
|
q->forceTextCodec(c);
|
|
if(_OUTPUT_VERBOSE)q->output(KVI_OUT_VERBOSE,__tr2qs("Changed text encoding to %Q"),&tmp);
|
|
}
|
|
}
|
|
m_pTextCodec = c;
|
|
m_pConsole->setTextEncoding(szEncoding);
|
|
}
|
|
|
|
void KviIrcConnection::setupTextCodec()
|
|
{
|
|
// grab the codec: first look it up in the server data
|
|
m_pTextCodec = 0;
|
|
if(!m_pTarget->server()->encoding().isEmpty())
|
|
{
|
|
m_pTextCodec = KviLocale::codecForName(m_pTarget->server()->encoding().latin1());
|
|
if(!m_pTextCodec)debug("KviIrcConnection: can't find TQTextCodec for encoding %s",m_pTarget->server()->encoding().utf8().data());
|
|
}
|
|
if(!m_pTextCodec)
|
|
{
|
|
// try the network
|
|
if(!m_pTarget->network()->encoding().isEmpty())
|
|
{
|
|
m_pTextCodec = KviLocale::codecForName(m_pTarget->network()->encoding().latin1());
|
|
if(!m_pTextCodec)debug("KviIrcConnection: can't find TQTextCodec for encoding %s",m_pTarget->network()->encoding().utf8().data());
|
|
}
|
|
}
|
|
if(!m_pTextCodec)
|
|
{
|
|
m_pTextCodec = KviApp::defaultTextCodec();
|
|
}
|
|
m_pConsole->setTextEncoding(TQString(m_pTextCodec->name()));
|
|
}
|
|
|
|
KviTQCString KviIrcConnection::encodeText(const TQString &szText)
|
|
{
|
|
if(!m_pTextCodec)return szText.utf8();
|
|
return m_pTextCodec->fromUnicode(szText);
|
|
}
|
|
|
|
TQString KviIrcConnection::decodeText(const char * szText)
|
|
{
|
|
if(!m_pTextCodec)return TQString(szText);
|
|
return m_pTextCodec->toUnicode(szText);
|
|
}
|
|
|
|
void KviIrcConnection::serverInfoReceived(const TQString &szServerName,const TQString &szUserModes,const TQString &szChanModes)
|
|
{
|
|
serverInfo()->setName(szServerName);
|
|
serverInfo()->setSupportedUserModes(szUserModes);
|
|
serverInfo()->setSupportedChannelModes(szChanModes);
|
|
m_pConsole->updateCaption(); // for server name
|
|
m_pFrame->childConnectionServerInfoChange(this);
|
|
}
|
|
|
|
const TQString & KviIrcConnection::currentServerName()
|
|
{
|
|
return serverInfo()->name();
|
|
}
|
|
|
|
const TQString & KviIrcConnection::currentNickName()
|
|
{
|
|
return userInfo()->nickName();
|
|
}
|
|
|
|
const TQString & KviIrcConnection::currentUserName()
|
|
{
|
|
return userInfo()->userName();
|
|
}
|
|
|
|
KviIrcServer * KviIrcConnection::server()
|
|
{
|
|
return m_pTarget->server();
|
|
}
|
|
|
|
KviProxy * KviIrcConnection::proxy()
|
|
{
|
|
return m_pTarget->proxy();
|
|
}
|
|
|
|
const TQString & KviIrcConnection::networkName()
|
|
{
|
|
return m_pTarget->networkName();
|
|
}
|
|
|
|
KviIrcSocket * KviIrcConnection::socket()
|
|
{
|
|
return m_pLink->socket();
|
|
}
|
|
|
|
void KviIrcConnection::abort()
|
|
{
|
|
// this WILL trigger linkAttemptFailed() or linkTerminated()
|
|
m_pLink->abort();
|
|
}
|
|
|
|
void KviIrcConnection::start()
|
|
{
|
|
m_eState = Connecting;
|
|
if(KVI_OPTION_BOOL(KviOption_boolUseIdentService) && KVI_OPTION_BOOL(KviOption_boolUseIdentServiceOnlyOnConnect))
|
|
{
|
|
g_pFrame->executeInternalCommand(KVI_INTERNALCOMMAND_IDENT_START);
|
|
m_bIdentdAttached=true;
|
|
}
|
|
m_pLink->start();
|
|
}
|
|
|
|
void KviIrcConnection::linkEstabilished()
|
|
{
|
|
m_eState = Connected;
|
|
|
|
// setup reasonable defaults before notifying anyone
|
|
m_pStatistics->setConnectionStartTime(kvi_unixTime());
|
|
m_pStatistics->setLastMessageTime(kvi_unixTime());
|
|
m_pServerInfo->setName(target()->server()->m_szHostname);
|
|
|
|
if(KviPointerList<KviIrcDataStreamMonitor> * l = context()->monitorList())
|
|
{
|
|
for(KviIrcDataStreamMonitor *m =l->first();m;m =l->next())
|
|
m->connectionInitiated();
|
|
}
|
|
|
|
context()->connectionEstabilished();
|
|
|
|
// Ok...we're loggin in now
|
|
resolveLocalHost();
|
|
loginToIrcServer();
|
|
}
|
|
|
|
void KviIrcConnection::linkTerminated()
|
|
{
|
|
if(m_bIdentdAttached)
|
|
{
|
|
g_pFrame->executeInternalCommand(KVI_INTERNALCOMMAND_IDENT_STOP);
|
|
m_bIdentdAttached=false;
|
|
}
|
|
m_eState = Idle;
|
|
|
|
if(m_pNotifyListManager)
|
|
{
|
|
delete m_pNotifyListManager;
|
|
m_pNotifyListManager = 0;
|
|
}
|
|
|
|
if(m_pLagMeter)
|
|
{
|
|
delete m_pLagMeter;
|
|
m_pLagMeter = 0;
|
|
}
|
|
|
|
if(KviPointerList<KviIrcDataStreamMonitor> * l = context()->monitorList())
|
|
{
|
|
for(KviIrcDataStreamMonitor *m =l->first();m;m =l->next())
|
|
m->connectionTerminated();
|
|
}
|
|
|
|
// Prepare data for an eventual reconnect
|
|
context()->connectionTerminated();
|
|
}
|
|
|
|
void KviIrcConnection::linkAttemptFailed(int iError)
|
|
{
|
|
if(m_bIdentdAttached)
|
|
{
|
|
g_pFrame->executeInternalCommand(KVI_INTERNALCOMMAND_IDENT_STOP);
|
|
m_bIdentdAttached=false;
|
|
}
|
|
m_eState = Idle;
|
|
context()->connectionFailed(iError);
|
|
}
|
|
|
|
KviChannel * KviIrcConnection::findChannel(const TQString &name)
|
|
{
|
|
for(KviChannel * c = m_pChannelList->first();c;c = m_pChannelList->next())
|
|
{
|
|
if(KviTQString::equalCI(name,c->windowName()))return c;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int KviIrcConnection::getCommonChannels(const TQString &nick,TQString &szChansBuffer,bool bAddEscapeSequences)
|
|
{
|
|
int count = 0;
|
|
for(KviChannel * c = m_pChannelList->first();c;c = m_pChannelList->next())
|
|
{
|
|
if(c->isOn(nick))
|
|
{
|
|
if(!szChansBuffer.isEmpty())szChansBuffer.append(", ");
|
|
char uFlag = c->getUserFlag(nick);
|
|
if(uFlag)
|
|
{
|
|
KviTQString::appendFormatted(szChansBuffer,bAddEscapeSequences ? "%c\r!c\r%Q\r" : "%c%Q",uFlag,&(c->windowName()));
|
|
} else {
|
|
if(bAddEscapeSequences)KviTQString::appendFormatted(szChansBuffer,"\r!c\r%Q\r",&(c->windowName()));
|
|
else szChansBuffer.append(c->windowName());
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void KviIrcConnection::unhighlightAllChannels()
|
|
{
|
|
for(KviChannel * c = m_pChannelList->first();c;c = m_pChannelList->next())
|
|
c->unhighlight();
|
|
}
|
|
|
|
void KviIrcConnection::unhighlightAllQueries()
|
|
{
|
|
for(KviQuery * c = m_pQueryList->first();c;c = m_pQueryList->next())
|
|
c->unhighlight();
|
|
}
|
|
|
|
void KviIrcConnection::partAllChannels()
|
|
{
|
|
for(KviChannel * c = m_pChannelList->first();c;c = m_pChannelList->next())
|
|
{
|
|
c->close();
|
|
}
|
|
}
|
|
|
|
void KviIrcConnection::closeAllChannels()
|
|
{
|
|
while(m_pChannelList->first())
|
|
{
|
|
m_pFrame->closeWindow(m_pChannelList->first());
|
|
}
|
|
}
|
|
|
|
void KviIrcConnection::closeAllQueries()
|
|
{
|
|
while(m_pQueryList->first())
|
|
{
|
|
m_pFrame->closeWindow(m_pQueryList->first());
|
|
}
|
|
}
|
|
|
|
KviChannel * KviIrcConnection::createChannel(const TQString &szName)
|
|
{
|
|
KviChannel * c = m_pContext->findDeadChannel(szName);
|
|
if(c)
|
|
{
|
|
c->setAliveChan();
|
|
if(!KVI_OPTION_BOOL(KviOption_boolCreateMinimizedChannels))
|
|
{
|
|
c->raise();
|
|
c->setFocus();
|
|
}
|
|
} else {
|
|
c = new KviChannel(m_pFrame,m_pConsole,szName);
|
|
m_pFrame->addWindow(c,!KVI_OPTION_BOOL(KviOption_boolCreateMinimizedChannels));
|
|
if(KVI_OPTION_BOOL(KviOption_boolCreateMinimizedChannels)) c->minimize();
|
|
}
|
|
return c;
|
|
}
|
|
|
|
KviQuery * KviIrcConnection::createQuery(const TQString &szNick)
|
|
{
|
|
KviQuery * q = m_pContext->findDeadQuery(szNick);
|
|
if(!q)
|
|
{
|
|
q = findQuery(szNick);
|
|
if(q)return q; // hm ?
|
|
}
|
|
if(q)
|
|
{
|
|
q->setAliveQuery();
|
|
if(!KVI_OPTION_BOOL(KviOption_boolCreateMinimizedQuery))
|
|
{
|
|
q->raise();
|
|
q->setFocus();
|
|
}
|
|
} else {
|
|
q = new KviQuery(m_pFrame,m_pConsole,szNick);
|
|
m_pFrame->addWindow(q,!KVI_OPTION_BOOL(KviOption_boolCreateMinimizedQuery));
|
|
if(KVI_OPTION_BOOL(KviOption_boolCreateMinimizedQuery))q->minimize();
|
|
}
|
|
return q;
|
|
}
|
|
|
|
KviQuery * KviIrcConnection::findQuery(const TQString &name)
|
|
{
|
|
for(KviQuery * c = m_pQueryList->first();c;c = m_pQueryList->next())
|
|
{
|
|
if(KviTQString::equalCI(name,c->windowName()))return c;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void KviIrcConnection::registerChannel(KviChannel * c)
|
|
{
|
|
m_pChannelList->append(c);
|
|
if(KVI_OPTION_BOOL(KviOption_boolLogChannelHistory))
|
|
g_pApp->addRecentChannel(c->windowName(),m_pTarget->networkName());
|
|
emit(channelRegistered(c));
|
|
emit(chanListChanged());
|
|
}
|
|
|
|
void KviIrcConnection::unregisterChannel(KviChannel * c)
|
|
{
|
|
m_pChannelList->removeRef(c);
|
|
emit(channelUnregistered(c));
|
|
emit(chanListChanged());
|
|
}
|
|
|
|
void KviIrcConnection::registerQuery(KviQuery * c)
|
|
{
|
|
m_pQueryList->append(c);
|
|
}
|
|
|
|
|
|
void KviIrcConnection::unregisterQuery(KviQuery * c)
|
|
{
|
|
if(m_pQueryList->removeRef(c))return;
|
|
}
|
|
|
|
void KviIrcConnection::keepChannelsOpenAfterDisconnect()
|
|
{
|
|
while(KviChannel * c = m_pChannelList->first())
|
|
{
|
|
c->outputNoFmt(KVI_OUT_SOCKETERROR,__tr2qs("Connection to server lost"));
|
|
c->setDeadChan();
|
|
}
|
|
}
|
|
|
|
void KviIrcConnection::keepQueriesOpenAfterDisconnect()
|
|
{
|
|
while(KviQuery * q = m_pQueryList->first())
|
|
{
|
|
q->outputNoFmt(KVI_OUT_SOCKETERROR,__tr2qs("Connection to server lost"));
|
|
q->setDeadQuery();
|
|
}
|
|
}
|
|
|
|
void KviIrcConnection::resurrectDeadQueries()
|
|
{
|
|
while(KviQuery * q = m_pContext->firstDeadQuery())
|
|
{
|
|
q->outputNoFmt(KVI_OUT_SOCKETMESSAGE,__tr2qs("Connection to server established"));
|
|
q->setAliveQuery();
|
|
}
|
|
}
|
|
|
|
|
|
//=== Message send stuff ====================================================//
|
|
// Max buffer that can be sent to an IRC server is 512 bytes
|
|
// including CRLF. (ircd simply 'cuts' messages to 512 bytes
|
|
// and discards the remainig part)
|
|
// Note that 510 bytes of data is a reasonably long message :)
|
|
//
|
|
// 01234567890123456789012345678901234567890123456789
|
|
// 01234567890123456789012345678901234567890123456789
|
|
// 01234567890123456789012345678901234567890123456789
|
|
// 01234567890123456789012345678901234567890123456789
|
|
// 01234567890123456789012345678901234567890123456789
|
|
// 01234567890123456789012345678901234567890123456789
|
|
// 01234567890123456789012345678901234567890123456789
|
|
// 01234567890123456789012345678901234567890123456789
|
|
// 01234567890123456789012345678901234567890123456789
|
|
// 01234567890123456789012345678901234567890123456789
|
|
// 0123456789\r\n
|
|
//
|
|
// We keep a list of data to send , and flush it as soon as we can.
|
|
//
|
|
|
|
bool KviIrcConnection::sendFmtData(const char *fmt,...)
|
|
{
|
|
KviDataBuffer * pData = new KviDataBuffer(512);
|
|
kvi_va_list(list);
|
|
kvi_va_start(list,fmt);
|
|
bool bTruncated;
|
|
//sprintf the buffer up to 512 chars (adds a CRLF too)
|
|
int iLen = kvi_irc_vsnprintf((char *)(pData->data()),fmt,list,&bTruncated);
|
|
kvi_va_end(list);
|
|
//adjust the buffer size
|
|
if(iLen < 512)pData->resize(iLen);
|
|
if(bTruncated)
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->outputNoFmt(KVI_OUT_SOCKETWARNING,__tr2qs("[LINK WARNING]: Socket message truncated to 512 bytes."));
|
|
}
|
|
|
|
// notify the monitors
|
|
if(KviPointerList<KviIrcDataStreamMonitor> * l = context()->monitorList())
|
|
{
|
|
for(KviIrcDataStreamMonitor *m = l->first();m;m = l->next())
|
|
m->outgoingMessage((const char *)(pData->data()),iLen - 2);
|
|
}
|
|
|
|
return m_pLink->sendPacket(pData);
|
|
}
|
|
|
|
bool KviIrcConnection::sendData(const char *buffer,int buflen)
|
|
{
|
|
if(buflen < 0)buflen = (int)strlen(buffer);
|
|
if(buflen > 510)
|
|
{
|
|
buflen = 510;
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->outputNoFmt(KVI_OUT_SOCKETWARNING,__tr2qs("[LINK WARNING]: Socket message truncated to 512 bytes."));
|
|
}
|
|
KviDataBuffer * pData = new KviDataBuffer(buflen + 2);
|
|
kvi_memmove(pData->data(),buffer,buflen);
|
|
*(pData->data()+buflen)='\r';
|
|
*(pData->data()+buflen+1)='\n';
|
|
|
|
// notify the monitors
|
|
if(KviPointerList<KviIrcDataStreamMonitor> * l = context()->monitorList())
|
|
{
|
|
for(KviIrcDataStreamMonitor *m = l->first();m;m = l->next())
|
|
m->outgoingMessage((const char *)(pData->data()),buflen);
|
|
}
|
|
|
|
return m_pLink->sendPacket(pData);
|
|
}
|
|
|
|
//==============================================================================================
|
|
// notify list management
|
|
//==============================================================================================
|
|
|
|
void KviIrcConnection::delayedStartNotifyList()
|
|
{
|
|
// start the notify list in 15 seconds
|
|
// We have this delay to wait an eventual RPL_PROTOCTL from the server
|
|
// telling us that the WATCH notify list method is supported
|
|
__range_invalid(m_pNotifyListTimer);
|
|
|
|
if(m_pNotifyListTimer)delete m_pNotifyListTimer;
|
|
m_pNotifyListTimer = new TQTimer();
|
|
connect(m_pNotifyListTimer,TQT_SIGNAL(timeout()),this,TQT_SLOT(restartNotifyList()));
|
|
m_pNotifyListTimer->start(15000,true);
|
|
|
|
// This delay is large enough to fire after the MOTD has been sent,
|
|
// even on the weirdest network.
|
|
// If there is no MOTD, this timer will fire after 15 secs,
|
|
// If there is a MOTD , restartNotifyList() will be triggered by RPL_ENDOFMOTD and
|
|
// will kill the timer before it has fired.
|
|
}
|
|
|
|
void KviIrcConnection::endOfMotdReceived()
|
|
{
|
|
// if the timer is still there running then just
|
|
if(m_pNotifyListTimer)restartNotifyList();
|
|
}
|
|
|
|
void KviIrcConnection::restartNotifyList()
|
|
{
|
|
if(m_pNotifyListTimer)
|
|
{
|
|
delete m_pNotifyListTimer;
|
|
m_pNotifyListTimer = 0;
|
|
}
|
|
|
|
// clear it
|
|
if(m_pNotifyListManager)
|
|
{
|
|
m_pNotifyListManager->stop(); // may need to remove watch entries
|
|
delete m_pNotifyListManager;
|
|
m_pNotifyListManager = 0;
|
|
}
|
|
|
|
if(!KVI_OPTION_BOOL(KviOption_boolUseNotifyList))return;
|
|
|
|
if(serverInfo()->supportsWatchList() && KVI_OPTION_BOOL(KviOption_boolUseWatchListIfAvailable))
|
|
{
|
|
if(_OUTPUT_VERBOSE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("The server seems to support the WATCH notify list method, will try to use it"));
|
|
m_pNotifyListManager = new KviWatchNotifyListManager(this);
|
|
} else {
|
|
if(KVI_OPTION_BOOL(KviOption_boolUseIntelligentNotifyListManager))
|
|
{
|
|
m_pNotifyListManager = new KviIsOnNotifyListManager(this);
|
|
} else {
|
|
m_pNotifyListManager = new KviStupidNotifyListManager(this);
|
|
}
|
|
}
|
|
m_pNotifyListManager->start();
|
|
}
|
|
|
|
void KviIrcConnection::restartLagMeter()
|
|
{
|
|
if(m_pLagMeter)
|
|
{
|
|
delete m_pLagMeter;
|
|
m_pLagMeter = 0;
|
|
}
|
|
if(!KVI_OPTION_BOOL(KviOption_boolUseLagMeterEngine))return;
|
|
m_pLagMeter = new KviLagMeter(this);
|
|
}
|
|
|
|
void KviIrcConnection::resolveLocalHost()
|
|
{
|
|
TQString szIp;
|
|
|
|
if(!socket()->getLocalHostIp(szIp,server()->isIpV6()))
|
|
{
|
|
bool bGotIp = false;
|
|
if(!KVI_OPTION_STRING(KviOption_stringLocalHostIp).isEmpty())
|
|
{
|
|
#ifdef COMPILE_IPV6_SUPPORT
|
|
if(server()->isIpV6())
|
|
{
|
|
if(KviNetUtils::isValidStringIp_V6(KVI_OPTION_STRING(KviOption_stringLocalHostIp)))bGotIp = true;
|
|
} else {
|
|
#endif
|
|
if(KviNetUtils::isValidStringIp(KVI_OPTION_STRING(KviOption_stringLocalHostIp)))bGotIp = true;
|
|
#ifdef COMPILE_IPV6_SUPPORT
|
|
}
|
|
#endif
|
|
}
|
|
if(bGotIp)
|
|
{
|
|
m_pUserInfo->setLocalHostIp(KVI_OPTION_STRING(KviOption_stringLocalHostIp));
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_SYSTEMWARNING,__tr2qs("Can't resolve local host address, using user supplied one (%Q)"),
|
|
&(m_pUserInfo->localHostIp()));
|
|
|
|
} else {
|
|
// FIXME : Maybe check for IPv6 here too ?
|
|
m_pUserInfo->setLocalHostIp("127.0.0.1");
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_SYSTEMWARNING,__tr2qs("Can't resolve local host address, using default 127.0.0.1"),
|
|
&(m_pUserInfo->localHostIp()));
|
|
}
|
|
} else {
|
|
m_pUserInfo->setLocalHostIp(szIp);
|
|
if(!_OUTPUT_QUIET)
|
|
m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Local host address is %Q"),
|
|
&(m_pUserInfo->localHostIp()));
|
|
}
|
|
|
|
// For now this is the only we know
|
|
m_pUserInfo->setHostName(m_pUserInfo->localHostIp());
|
|
m_pUserInfo->setHostIp(m_pUserInfo->localHostIp());
|
|
}
|
|
|
|
void KviIrcConnection::changeAwayState(bool bAway)
|
|
{
|
|
if(bAway)m_pUserInfo->setAway();
|
|
else m_pUserInfo->setBack();
|
|
|
|
m_pConsole->updateCaption();
|
|
m_pFrame->childConnectionAwayStateChange(this);
|
|
|
|
emit awayStateChanged();
|
|
}
|
|
|
|
void KviIrcConnection::userInfoReceived(const TQString &szUserName,const TQString &szHostName)
|
|
{
|
|
userInfo()->setUserName(szUserName);
|
|
TQString szUnmaskedHost = m_pUserInfo->unmaskedHostName();
|
|
// Update the user entry
|
|
KviIrcUserEntry * e = userDataBase()->find(userInfo()->nickName());
|
|
if(e) // should be there! (we have the permanent entry in the notify list view)
|
|
{
|
|
e->setUser(szUserName);
|
|
if(!szHostName.isEmpty())e->setHost(szHostName);
|
|
} // else buuug
|
|
|
|
if(szHostName.isEmpty())return; // nothing to do anyway
|
|
|
|
if(KviTQString::equalCS(m_pUserInfo->hostName(),szHostName))return; // again nothing to do
|
|
|
|
static bool warned_once = false;
|
|
|
|
if(!warned_once)
|
|
{
|
|
if(!(m_pUserInfo->hostName().isEmpty() || KviTQString::equalCS(m_pUserInfo->hostName(),m_pUserInfo->localHostIp())))
|
|
{
|
|
// ok, something weird is probably going on
|
|
// is is non-empty and it is NOT the IP address we have set
|
|
// at connection startup...
|
|
// ...the server (or more likely the bouncer) must have changed his mind...
|
|
if(!_OUTPUT_MUTE)
|
|
{
|
|
m_pConsole->output(KVI_OUT_SYSTEMWARNING,__tr2qs("The server seems to have changed the idea about the local hostname"));
|
|
m_pConsole->output(KVI_OUT_SYSTEMWARNING,__tr2qs("You're probably using a broken bouncer or maybe something weird is happening on the IRC server"));
|
|
}
|
|
warned_once = true;
|
|
}
|
|
}
|
|
|
|
// set it
|
|
m_pUserInfo->setHostName(szHostName);
|
|
|
|
bool bChangeIp = true;
|
|
|
|
// if we don't have any routable IP yet, then it is worth to lookup the new hostname
|
|
|
|
#ifdef COMPILE_IPV6_SUPPORT
|
|
if((KviNetUtils::isValidStringIp(m_pUserInfo->hostIp()) &&
|
|
KviNetUtils::isRoutableIpString(m_pUserInfo->hostIp())) ||
|
|
KviNetUtils::isValidStringIp_V6(m_pUserInfo->hostIp()))
|
|
#else
|
|
if((KviNetUtils::isValidStringIp(m_pUserInfo->hostIp()) &&
|
|
KviNetUtils::isRoutableIpString(m_pUserInfo->hostIp())))
|
|
#endif
|
|
{
|
|
if(KVI_OPTION_BOOL(KviOption_boolDccGuessIpFromServerWhenLocalIsUnroutable) &&
|
|
KVI_OPTION_BOOL(KviOption_boolDccBrokenBouncerHack))
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->outputNoFmt(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Here goes your \"broken bouncer hack\": The server has changed the hostname but I'll ignore the IP address change"));
|
|
bChangeIp = false;
|
|
}
|
|
}
|
|
|
|
if(bChangeIp)
|
|
{
|
|
// lookup the new hostname then...
|
|
#ifdef COMPILE_IPV6_SUPPORT
|
|
if(KviNetUtils::isValidStringIp(szHostName) || KviNetUtils::isValidStringIp_V6(szHostName))
|
|
#else
|
|
if(KviNetUtils::isValidStringIp(szHostName))
|
|
#endif
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("The local IP address as seen by the IRC server is %Q"),&szHostName);
|
|
m_pUserInfo->setHostIp(szHostName);
|
|
} else
|
|
#ifdef COMPILE_IPV6_SUPPORT
|
|
if(KviNetUtils::isValidStringIp(szUnmaskedHost) || KviNetUtils::isValidStringIp_V6(szUnmaskedHost))
|
|
#else
|
|
if(KviNetUtils::isValidStringIp(szUnmaskedHost))
|
|
#endif
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("The local IP address as seen by the IRC server is %Q"),&szUnmaskedHost);
|
|
m_pUserInfo->setHostIp(szUnmaskedHost);
|
|
|
|
} else {
|
|
// look it up too
|
|
if(m_pLocalhostDns)delete m_pLocalhostDns; // it could be only another local host lookup
|
|
m_pLocalhostDns = new KviDns();
|
|
connect(m_pLocalhostDns,TQT_SIGNAL(lookupDone(KviDns *)),this,TQT_SLOT(hostNameLookupTerminated(KviDns *)));
|
|
|
|
if(!m_pLocalhostDns->lookup(szHostName,KviDns::Any))
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
{
|
|
// don't change the string to aid the translators
|
|
TQString szTmp = __tr2qs("Can't start the DNS slave thread");
|
|
m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Unable to resolve the local hostname as seen by the IRC server: %Q"),&szTmp);
|
|
}
|
|
delete m_pLocalhostDns;
|
|
m_pLocalhostDns = 0;
|
|
} else {
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Looking up the local hostname as seen by the IRC server (%Q)"),&szHostName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void KviIrcConnection::hostNameLookupTerminated(KviDns *pDns)
|
|
{
|
|
//
|
|
// This is called when our hostname lookup terminates
|
|
//
|
|
if(!m_pLocalhostDns)
|
|
{
|
|
debug("Something weird is happening: pDns != 0 but m_pLocalhostDns == 0 :/");
|
|
return;
|
|
}
|
|
|
|
if(m_pLocalhostDns->state() != KviDns::Success)
|
|
{
|
|
TQString szErr = KviError::getDescription(m_pLocalhostDns->error());
|
|
if(!m_pUserInfo->hostIp().isEmpty())
|
|
m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Unable to resolve the local hostname as seen by the IRC server: %Q, using previously resolved %Q"),
|
|
&szErr,&(m_pUserInfo->hostIp()));
|
|
else
|
|
m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Unable to resolve the local hostname as seen by the IRC server: %Q"),
|
|
&szErr);
|
|
} else {
|
|
TQString szIpAddr = m_pLocalhostDns->firstIpAddress();
|
|
m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Local hostname as seen by the IRC server resolved to %Q"),&szIpAddr);
|
|
m_pUserInfo->setHostIp(m_pLocalhostDns->firstIpAddress());
|
|
}
|
|
|
|
delete m_pLocalhostDns;
|
|
m_pLocalhostDns = 0;
|
|
}
|
|
|
|
void KviIrcConnection::loginToIrcServer()
|
|
{
|
|
KviIrcServer * pServer = target()->server();
|
|
KviIrcNetwork * pNet = target()->network();
|
|
|
|
// Username
|
|
pServer->m_szUser.stripWhiteSpace();
|
|
if(!pServer->m_szUser.isEmpty())
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Using server specific username (%Q)"),&(pServer->m_szUser));
|
|
} else {
|
|
if(!pNet->userName().isEmpty())
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Using network specific username (%Q)"),&(pNet->userName()));
|
|
pServer->m_szUser = pNet->userName();
|
|
} else {
|
|
pServer->m_szUser = KVI_OPTION_STRING(KviOption_stringUsername);
|
|
}
|
|
}
|
|
|
|
pServer->m_szUser.stripWhiteSpace();
|
|
if(pServer->m_szUser.isEmpty())pServer->m_szUser = KVI_DEFAULT_USERNAME;
|
|
|
|
// For now this is the only we know
|
|
m_pUserInfo->setUserName(pServer->m_szUser);
|
|
m_pServerInfo->setName(pServer->m_szHostname);
|
|
|
|
// Nick stuff
|
|
pServer->m_szNick.stripWhiteSpace();
|
|
if(pServer->m_pReconnectInfo)
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Using reconnect specific nickname (%Q)"),&(pServer->m_pReconnectInfo->m_szNick));
|
|
m_pUserInfo->setNickName(pServer->m_pReconnectInfo->m_szNick);
|
|
m_pStateData->setLoginNickIndex(0);
|
|
}else if(!pServer->m_szNick.isEmpty())
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Using server specific nickname (%Q)"),&(pServer->m_szNick));
|
|
m_pUserInfo->setNickName(pServer->m_szNick);
|
|
m_pStateData->setLoginNickIndex(0);
|
|
} else {
|
|
if(!pNet->nickName().isEmpty())
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Using network specific nickname (%Q)"),&(pNet->nickName()));
|
|
m_pUserInfo->setNickName(pNet->nickName());
|
|
m_pStateData->setLoginNickIndex(0);
|
|
} else {
|
|
KVI_OPTION_STRING(KviOption_stringNickname1).stripWhiteSpace();
|
|
if(KVI_OPTION_STRING(KviOption_stringNickname1).isEmpty())
|
|
KVI_OPTION_STRING(KviOption_stringNickname1) = KVI_DEFAULT_NICKNAME1;
|
|
m_pUserInfo->setNickName(KVI_OPTION_STRING(KviOption_stringNickname1));
|
|
m_pStateData->setLoginNickIndex(1);
|
|
}
|
|
}
|
|
|
|
// Real name
|
|
pServer->m_szRealName.stripWhiteSpace();
|
|
if(!pServer->m_szRealName.isEmpty())
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Using server specific real name (%Q)"),
|
|
&(pServer->m_szRealName));
|
|
m_pUserInfo->setRealName(pServer->m_szRealName);
|
|
} else {
|
|
if(!pNet->realName().isEmpty())
|
|
{
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Using network specific real name (%Q)"),
|
|
&(pNet->realName()));
|
|
m_pUserInfo->setRealName(pNet->realName());
|
|
} else {
|
|
m_pUserInfo->setRealName(KVI_OPTION_STRING(KviOption_stringRealname));
|
|
}
|
|
}
|
|
|
|
// FIXME: The server's encoding!
|
|
setupTextCodec();
|
|
KviTQCString szNick = encodeText(m_pUserInfo->nickName()); // never empty
|
|
KviTQCString szUser = encodeText(m_pUserInfo->userName()); // never empty
|
|
KviTQCString szReal = encodeText(m_pUserInfo->realName()); // may be empty
|
|
|
|
if(!szReal.data())szReal = "";
|
|
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Logging in as %Q!%Q :%Q"),
|
|
&(m_pUserInfo->nickName()),&(m_pUserInfo->userName()),&(m_pUserInfo->realName()));
|
|
|
|
|
|
// spity, 27.03.2005: follow the RFC2812 suggested order for connection registration
|
|
// first the PASS, then NICK and then USER
|
|
|
|
// The pass ?
|
|
pServer->m_szPass.stripWhiteSpace();
|
|
if(!pServer->m_szPass.isEmpty())
|
|
{
|
|
KviStr szHidden;
|
|
int pLen = pServer->m_szPass.length();
|
|
for(int i=0;i<pLen;i++)szHidden.append('*');
|
|
|
|
if(!_OUTPUT_MUTE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Sending %s as password"),szHidden.ptr());
|
|
|
|
// The colon should allow user to use passwords with whitespaces.
|
|
// Non-whitespace passwords are unaffected.
|
|
if(!sendFmtData("PASS :%s",encodeText(pServer->m_szPass).data()))
|
|
{
|
|
// disconnected in the meantime
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if(!sendFmtData("NICK %s",szNick.data()))
|
|
{
|
|
// disconnected :(
|
|
return;
|
|
}
|
|
|
|
TQString szGenderTag;
|
|
if(KVI_OPTION_BOOL(KviOption_boolPrependGenderInfoToRealname) && !KVI_OPTION_STRING(KviOption_stringCtcpUserInfoGender).isEmpty())
|
|
{
|
|
szGenderTag.append(KVI_TEXT_COLOR);
|
|
if(KVI_OPTION_STRING(KviOption_stringCtcpUserInfoGender).startsWith("m",false))
|
|
{
|
|
szGenderTag.append("1");
|
|
} else if(KVI_OPTION_STRING(KviOption_stringCtcpUserInfoGender).startsWith("f",false))
|
|
{
|
|
szGenderTag.append("2");
|
|
}
|
|
szGenderTag.append(KVI_TEXT_RESET);
|
|
szReal.prepend(KviTQString::toUtf8(szGenderTag));
|
|
}
|
|
|
|
if(!sendFmtData("USER %s 0 %s :%s",szUser.data(),
|
|
KviTQString::toUtf8(pServer->m_szHostname).data(),szReal.data()))
|
|
{
|
|
// disconnected in the meantime!
|
|
return;
|
|
}
|
|
|
|
// permanent info in the user database
|
|
m_pConsole->notifyListView()->join(m_pUserInfo->nickName(),"*","*");
|
|
|
|
// set own avatar if we have it
|
|
KviIrcUserEntry * e = userDataBase()->find(userInfo()->nickName());
|
|
if(e) // should be there!
|
|
{
|
|
if(!e->avatar())
|
|
{
|
|
KviAvatar * av = m_pConsole->defaultAvatarFromOptions();
|
|
if(av)
|
|
{
|
|
e->setAvatar(av);
|
|
m_pConsole->notifyListView()->avatarChanged(userInfo()->nickName());
|
|
}
|
|
}
|
|
} // else buuug
|
|
|
|
if(KVI_OPTION_STRING(KviOption_stringCtcpUserInfoGender).startsWith("m",false)){
|
|
e->setGender(KviIrcUserEntry::Male);
|
|
} else if(KVI_OPTION_STRING(KviOption_stringCtcpUserInfoGender).startsWith("f",false)){
|
|
e->setGender(KviIrcUserEntry::Female);
|
|
}
|
|
|
|
// on connect stuff ?
|
|
|
|
TQString tmp = pNet->onConnectCommand();
|
|
tmp.stripWhiteSpace();
|
|
if(!tmp.isEmpty())
|
|
{
|
|
if(_OUTPUT_VERBOSE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Executing scheduled network specific \"on connect\" commands"));
|
|
KviKvsScript::run(tmp,m_pConsole);
|
|
}
|
|
|
|
tmp = pServer->onConnectCommand();
|
|
tmp.stripWhiteSpace();
|
|
if(!tmp.isEmpty())
|
|
{
|
|
if(_OUTPUT_VERBOSE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Executing scheduled server specific \"on connect\" commands"));
|
|
KviKvsScript::run(tmp,m_pConsole);
|
|
}
|
|
|
|
tmp = m_pUserIdentity->onConnectCommand();
|
|
tmp.stripWhiteSpace();
|
|
if(!tmp.isEmpty())
|
|
{
|
|
if(_OUTPUT_VERBOSE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Executing scheduled identity specific \"on connect\" commands"));
|
|
KviKvsScript::run(tmp,m_pConsole);
|
|
}
|
|
|
|
// and wait for the server to agree...
|
|
}
|
|
|
|
void KviIrcConnection::nickChange(const TQString &szNewNick)
|
|
{
|
|
// FIXME: should the new nickname be decoded in some way ?
|
|
m_pConsole->notifyListView()->nickChange(m_pUserInfo->nickName(),szNewNick);
|
|
m_pUserInfo->setNickName(szNewNick);
|
|
m_pConsole->output(KVI_OUT_NICK,__tr2qs("You have changed your nickname to %Q"),&szNewNick);
|
|
m_pConsole->updateCaption();
|
|
m_pFrame->childConnectionNickNameChange(this);
|
|
emit nickNameChanged();
|
|
g_pApp->addRecentNickname(szNewNick);
|
|
}
|
|
|
|
bool KviIrcConnection::changeUserMode(char mode,bool bSet)
|
|
{
|
|
__range_valid(m_pConnectionInfo);
|
|
if(bSet)
|
|
{
|
|
if(m_pUserInfo->hasUserMode(mode))return false;
|
|
m_pUserInfo->addUserMode(mode);
|
|
} else {
|
|
if(!m_pUserInfo->hasUserMode(mode))return false;
|
|
m_pUserInfo->removeUserMode(mode);
|
|
}
|
|
m_pConsole->updateCaption();
|
|
m_pFrame->childConnectionUserModeChange(this);
|
|
emit userModeChanged();
|
|
return true;
|
|
}
|
|
|
|
void KviIrcConnection::loginComplete(const TQString &szNickName)
|
|
{
|
|
if(context()->state() == KviIrcContext::Connected)return;
|
|
|
|
context()->loginComplete();
|
|
|
|
if(m_bIdentdAttached)
|
|
{
|
|
g_pFrame->executeInternalCommand(KVI_INTERNALCOMMAND_IDENT_STOP);
|
|
m_bIdentdAttached=false;
|
|
}
|
|
|
|
if(szNickName != m_pUserInfo->nickName())
|
|
{
|
|
m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("The server refused the suggested nickname (%s) and named you %s instead"),
|
|
m_pUserInfo->nickName().utf8().data(),szNickName.utf8().data());
|
|
m_pConsole->notifyListView()->nickChange(m_pUserInfo->nickName(),szNickName);
|
|
m_pUserInfo->setNickName(szNickName);
|
|
}
|
|
|
|
g_pApp->addRecentNickname(szNickName);
|
|
|
|
bool bHaltOutput = false;
|
|
bHaltOutput = KVS_TRIGGER_EVENT_0_HALTED(KviEvent_OnIrc,m_pConsole);
|
|
|
|
if(!bHaltOutput)
|
|
m_pConsole->outputNoFmt(KVI_OUT_IRC,__tr2qs("Login operations complete, happy ircing!"));
|
|
|
|
resurrectDeadQueries();
|
|
|
|
// on connect stuff ?
|
|
TQString tmp = target()->network()->onLoginCommand();
|
|
tmp.stripWhiteSpace();
|
|
if(!tmp.isEmpty())
|
|
{
|
|
if(_OUTPUT_VERBOSE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Executing scheduled network specific \"on login\" commands"));
|
|
KviKvsScript::run(tmp,m_pConsole);
|
|
}
|
|
|
|
tmp = target()->server()->onLoginCommand();
|
|
tmp.stripWhiteSpace();
|
|
if(!tmp.isEmpty())
|
|
{
|
|
if(_OUTPUT_VERBOSE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Executing scheduled server specific \"on login\" commands"));
|
|
KviKvsScript::run(tmp,m_pConsole);
|
|
}
|
|
|
|
tmp = m_pUserIdentity->onLoginCommand();
|
|
tmp.stripWhiteSpace();
|
|
if(!tmp.isEmpty())
|
|
{
|
|
if(_OUTPUT_VERBOSE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Executing scheduled identity specific \"on login\" commands"));
|
|
KviKvsScript::run(tmp,m_pConsole);
|
|
}
|
|
|
|
// Set the configured umode
|
|
KviStr modeStr = server()->initUMode();
|
|
|
|
if(modeStr.isEmpty())modeStr = KVI_OPTION_STRING(KviOption_stringDefaultUserMode);
|
|
|
|
if(!modeStr.isEmpty())
|
|
{
|
|
if(_OUTPUT_VERBOSE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Setting configured user mode"));
|
|
sendFmtData("MODE %s +%s",encodeText(TQString(m_pUserInfo->nickName())).data(),modeStr.ptr());
|
|
}
|
|
|
|
delayedStartNotifyList();
|
|
restartLagMeter();
|
|
|
|
if(KVI_OPTION_BOOL(KviOption_boolShowChannelsJoinOnIrc))
|
|
m_pFrame->executeInternalCommand(KVI_INTERNALCOMMAND_CHANNELSJOIN_OPEN);
|
|
|
|
|
|
// join saved channels
|
|
TQString szChannels,szProtectedChannels,szPasswords,szCurPass,szCurChan;
|
|
|
|
if(!(m_pStateData->commandToExecAfterConnect().isEmpty()))
|
|
{
|
|
KviStr tmp = m_pStateData->commandToExecAfterConnect();
|
|
KviKvsScript::run(tmp.ptr(),m_pConsole);
|
|
}
|
|
|
|
if(target()->server()->m_pReconnectInfo)
|
|
{
|
|
if(!target()->server()->m_pReconnectInfo->m_szJoinChannels.isEmpty())
|
|
sendFmtData("JOIN %s",encodeText(target()->server()->m_pReconnectInfo->m_szJoinChannels).data());
|
|
|
|
KviQuery * query;
|
|
|
|
for(TQStringList::Iterator it = target()->server()->m_pReconnectInfo->m_szOpenQueryes.begin();
|
|
it != target()->server()->m_pReconnectInfo->m_szOpenQueryes.end();it++)
|
|
{
|
|
TQString szNick = *it;
|
|
query = findQuery(szNick);
|
|
if(!query) {
|
|
query = createQuery(szNick);
|
|
TQString user;
|
|
TQString host;
|
|
KviIrcUserDataBase * db = userDataBase();
|
|
if(db)
|
|
{
|
|
KviIrcUserEntry * e = db->find(szNick);
|
|
if(e)
|
|
{
|
|
user = e->user();
|
|
host = e->host();
|
|
}
|
|
}
|
|
query->setTarget(szNick,user,host);
|
|
}
|
|
query->autoRaise();
|
|
query->setFocus();
|
|
}
|
|
delete target()->server()->m_pReconnectInfo;
|
|
target()->server()->m_pReconnectInfo=0;
|
|
}else {
|
|
if(target()->network()->autoJoinChannelList())
|
|
{
|
|
if(_OUTPUT_VERBOSE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Auto-joining network specific channels"));
|
|
|
|
TQStringList * l = target()->network()->autoJoinChannelList();
|
|
if(l->count()!=0)
|
|
{
|
|
for ( TQStringList::Iterator it = l->begin(); it != l->end(); ++it ) {
|
|
|
|
szCurPass=(*it).section(':',1);
|
|
if(szCurPass.isEmpty())
|
|
{
|
|
if(!szChannels.isEmpty())
|
|
szChannels.append(",");
|
|
szCurChan = (*it).section(':',0,0);
|
|
if(!(szCurChan[0]=='#' || szCurChan[0]=='&' || szCurChan[0]=='!'))
|
|
szCurChan.prepend('#');
|
|
szChannels.append(szCurChan);
|
|
} else {
|
|
if(!szProtectedChannels.isEmpty())
|
|
szProtectedChannels.append(",");
|
|
szCurChan = (*it).section(':',0,0);
|
|
if(!(szCurChan[0]=='#' || szCurChan[0]=='&' || szCurChan[0]=='!'))
|
|
szCurChan.prepend('#');
|
|
szProtectedChannels.append(szCurChan);
|
|
if(!szPasswords.isEmpty())
|
|
szPasswords.append(",");
|
|
szPasswords.append(szCurPass);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(server()->autoJoinChannelList())
|
|
{
|
|
if(_OUTPUT_VERBOSE)
|
|
m_pConsole->output(KVI_OUT_VERBOSE,__tr2qs("Auto-joining server specific channels"));
|
|
|
|
TQStringList * l = server()->autoJoinChannelList();
|
|
if(l->count()!=0)
|
|
{
|
|
for ( TQStringList::Iterator it = l->begin(); it != l->end(); ++it ) {
|
|
szCurPass=(*it).section(':',1);
|
|
if(szCurPass.isEmpty())
|
|
{
|
|
if(!szChannels.isEmpty())
|
|
szChannels.append(",");
|
|
szCurChan = (*it).section(':',0,0);
|
|
if(!(szCurChan[0]=='#' || szCurChan[0]=='&' || szCurChan[0]=='!'))
|
|
szCurChan.prepend(':');
|
|
szChannels.append(szCurChan);
|
|
} else {
|
|
if(!szProtectedChannels.isEmpty())
|
|
szProtectedChannels.append(",");
|
|
szCurChan = (*it).section(':',0,0);
|
|
if(!(szCurChan[0]=='#' || szCurChan[0]=='&' || szCurChan[0]=='!'))
|
|
szCurChan.prepend('#');
|
|
szProtectedChannels.append(szCurChan);
|
|
if(!szPasswords.isEmpty())
|
|
szPasswords.append(",");
|
|
szPasswords.append(szCurPass);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TQString szCommand;
|
|
if( (!szChannels.isEmpty()) || (!szProtectedChannels.isEmpty()) )
|
|
{
|
|
szCommand.append(szProtectedChannels);
|
|
if(!szProtectedChannels.isEmpty() && !szChannels.isEmpty())
|
|
szCommand.append(',');
|
|
szCommand.append(szChannels);
|
|
szCommand.append(" ");
|
|
szCommand.append(szPasswords);
|
|
|
|
sendFmtData("JOIN %s",encodeText(szCommand).data());
|
|
}
|
|
}
|
|
// minimize after connect
|
|
if(KVI_OPTION_BOOL(KviOption_boolMinimizeConsoleAfterConnect))
|
|
m_pConsole->minimize();
|
|
}
|
|
|
|
void KviIrcConnection::incomingMessage(const char * message)
|
|
{
|
|
// A message has arrived from the current server
|
|
// First of all , notify the monitors
|
|
if(KviPointerList<KviIrcDataStreamMonitor> * l = context()->monitorList())
|
|
{
|
|
for(KviIrcDataStreamMonitor *m = l->first();m;m = l->next())
|
|
{
|
|
m->incomingMessage(message);
|
|
}
|
|
}
|
|
// set the last message time
|
|
m_pStatistics->setLastMessageTime(kvi_unixTime());
|
|
// and pass it to the server parser for processing
|
|
g_pServerParser->parseMessage(message,this);
|
|
}
|
|
|
|
void KviIrcConnection::heartbeat(kvi_time_t tNow)
|
|
{
|
|
if(m_eState == Connected)
|
|
{
|
|
if(!KVI_OPTION_BOOL(KviOption_boolDisableAwayListUpdates))
|
|
{
|
|
// update the channel WHO lists (fixes users away state)
|
|
// first of all, we send our request not more often than every 50 secs
|
|
if((tNow - stateData()->lastSentChannelWhoRequest()) > 50)
|
|
{
|
|
// we also make sure that the last sent request is older than
|
|
// the last received reply
|
|
if(stateData()->lastSentChannelWhoRequest() <= stateData()->lastReceivedChannelWhoReply())
|
|
{
|
|
// find the channel that has the older list now
|
|
kvi_time_t tOldest = tNow;
|
|
KviChannel * pOldest = 0;
|
|
for(KviChannel * pChan = m_pChannelList->first();pChan;pChan = m_pChannelList->next())
|
|
{
|
|
if(pChan->lastReceivedWhoReply() < tOldest)
|
|
{
|
|
pOldest = pChan;
|
|
tOldest = pChan->lastReceivedWhoReply();
|
|
}
|
|
}
|
|
// if the oldest chan who list is older than 150 secs, update it
|
|
if((tNow - tOldest) > 150)
|
|
{
|
|
// ok, sent the request for this channel
|
|
stateData()->setLastSentChannelWhoRequest(tNow);
|
|
TQString szChanName = encodeText(pOldest->name());
|
|
if(_OUTPUT_PARANOIC)
|
|
console()->output(KVI_OUT_VERBOSE,__tr2qs("Updating away state for channel %Q"),&szChanName);
|
|
if(lagMeter())
|
|
{
|
|
KviStr tmp(KviStr::Format,"WHO %s",pOldest->name());
|
|
lagMeter()->lagCheckRegister(tmp.ptr(),70);
|
|
}
|
|
pOldest->setSentSyncWhoRequest();
|
|
if(!sendFmtData("WHO %s",encodeText(TQString(pOldest->name())).data()))return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|