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.
kvirc/src/kvirc/sparser/kvi_sp_literal.cpp

1868 lines
61 KiB

//====================================================================================
//
// File : kvi_sp_literal.cpp
// Creation date : Thu Aug 3 2000 01:29:12 by Szymon Stefanek
//
// This file is part of the KVirc irc client distribution
// Copyright (C) 1999-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_sparser.h"
#include "kvi_window.h"
#include "kvi_console.h"
#include "kvi_out.h"
#include "kvi_locale.h"
#include "kvi_ircsocket.h"
#include "kvi_options.h"
#include "kvi_ircmask.h"
#include "kvi_channel.h"
#include "kvi_topicw.h"
#include "kvi_frame.h"
#include "kvi_mirccntrl.h"
#include "kvi_query.h"
#include "kvi_userlistview.h"
#include "kvi_antispam.h"
#include "kvi_nickserv.h"
#include "kvi_parameterlist.h"
#include "kvi_ircuserdb.h"
#include "kvi_app.h"
#include "kvi_regusersdb.h"
#include "kvi_debug.h"
#include "kvi_time.h"
#include "kvi_useraction.h"
#include "kvi_ircconnection.h"
#include "kvi_ircconnectionuserinfo.h"
#include "kvi_ircconnectiontarget.h"
#include "kvi_ircconnectionserverinfo.h"
#include "kvi_ircconnectionstatedata.h"
#include "kvi_ircconnectionnetsplitdetectordata.h"
#include "kvi_iconmanager.h"
#include "kvi_lagmeter.h"
#include "kvi_ircserver.h"
#include "kvi_kvs_eventtriggers.h"
#include "kvi_qcstring.h"
#include "kvi_settings.h"
#ifdef COMPILE_CRYPT_SUPPORT
#include "kvi_crypt.h"
#include "kvi_cryptcontroller.h"
#endif
#include "kvi_kvs_script.h"
//#include "kvi_regusersdb.h"
//#include "kvi_iconmanager.h"
#include <tqdatetime.h>
#ifdef COMPILE_USE_QT4
#include <TQTextDocument>
#else
#include <tqstylesheet.h>
#endif
extern KviNickServRuleSet * g_pNickServRuleSet;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PING
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void KviServerParser::parseLiteralPing(KviIrcMessage *msg)
{
// PING
// <optional_prefix> PING :<argument>
msg->connection()->sendFmtData("PONG %s",msg->console()->connection()->encodeText(msg->allParams()).data());
TQString szPrefix = msg->connection()->decodeText(msg->safePrefix());
TQString szAllParams = msg->connection()->decodeText(msg->allParams());
if(KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnPing,msg->console(),szPrefix,szAllParams))
msg->setHaltOutput();
if((!msg->haltOutput()) && KVI_OPTION_BOOL(KviOption_boolShowPingPong))
{
msg->console()->output(KVI_OUT_SERVERPING,
__tr2qs("Received ping from \r!s\r%Q\r (PING %Q), replied pong"),
&szPrefix,&szAllParams);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PONG
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void KviServerParser::parseLiteralPong(KviIrcMessage *msg)
{
TQString szPrefix = msg->connection()->decodeText(msg->safePrefix());
TQString szAllParams = msg->connection()->decodeText(msg->allParams());
if(KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnPong,msg->console(),szPrefix,szAllParams))
msg->setHaltOutput();
if(msg->console()->connection()->lagMeter())
{
if(msg->console()->connection()->lagMeter()->lagCheckComplete("@ping@"))
msg->setHaltOutput(); // was internally generated!
}
if((!msg->haltOutput()) && KVI_OPTION_BOOL(KviOption_boolShowPingPong))
{
msg->console()->output(KVI_OUT_SERVERPING,
__tr2qs("Received pong from \r!s\r%s\r (PONG %s)"),msg->safePrefix(),msg->allParams());
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ERROR
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void KviServerParser::parseLiteralError(KviIrcMessage *msg)
{
// ERROR
// <optional_prefix> ERROR :<argument>
// ERROR :Closing Link: phoenix.pragmaware.net (Ping timeout)
TQString szPrefix = msg->connection()->decodeText(msg->safePrefix());
TQString szParams = msg->connection()->decodeText(msg->allParams());
if(KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnError,msg->console(),szPrefix,szParams))
msg->setHaltOutput();
if(!msg->haltOutput())
{
msg->console()->output(KVI_OUT_SERVERERROR,
__tr2qs("Server ERROR: %Q"),&szParams);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// JOIN
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void KviServerParser::parseLiteralJoin(KviIrcMessage *msg)
{
// JOIN
// :<joiner_mask> JOIN :<channel>
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
const char * encodedChan = msg->safeTrailing();
TQString channel = msg->connection()->decodeText(encodedChan);
if(channel.isEmpty())
{
// This is broken....
UNRECOGNIZED_MESSAGE(msg,__tr2qs("Missing channel parameter in join message"));
return;
}
// check for extended join syntax.
// it is used in splits only (AFAIK)
// nick!user@host JOIN :#channel\x07[o|v]
const TQChar * pExt = KviTQString::nullTerminatedArray(channel);
char chExtMode = 0;
while(pExt->tqunicode() && (pExt->tqunicode() != 0x07))pExt++;
if(pExt->tqunicode())
{
++pExt;
if(pExt->tqunicode())
{
chExtMode = (char)pExt->tqunicode();
channel.remove(channel.length() - 2,2); // assuming that we're at the end (we should be)
} // else { senseless 0x07 in channel name ?
}
// Now lookup the channel
KviConsole * console = msg->console();
KviChannel * chan = msg->connection()->findChannel(channel);
bool bIsMe = IS_ME(msg,szNick);
if(!chan)
{
// This must be me...(or desync)
if(bIsMe)
{
msg->connection()->userInfoReceived(szUser,szHost);
chan = msg->connection()->createChannel(channel); // New channel (will resurrect an eventual dead one too!)
} else {
// Someone is joining an inexsisting channel!!!
UNRECOGNIZED_MESSAGE(msg,__tr("Received a join message for an unknown channel, possible desync"));
return;
}
int iFlags = 0;
iFlags = msg->connection()->serverInfo()->modeFlagFromModeChar(chExtMode);
KviUserListEntry * it = chan->join(szNick,szUser,szHost,iFlags);
if(iFlags)chan->updateCaption();
// FIXME: #warning "Trigger also OnMeVoice and OnMeOp here ?"
if(!(it->globalData()->avatar()))
{
KviAvatar * av = console->defaultAvatarFromOptions();
if(av)
{
it->globalData()->setAvatar(av);
console->avatarChanged(av,szNick,szUser,szHost,TQString());
}
}
if(KVS_TRIGGER_EVENT_0_HALTED(KviEvent_OnMeJoin,chan))
msg->setHaltOutput();
// the channel requests must be sent AFTER we have created and accessed the chan
// since it MAY happen that a sendFmtData() call fails by detecting a disconnect
// and thus destroys the channel window!
// If this problem persists in other parts of the KVIrc core then
// we should disable disconnection detection during the parsing of a single
// message in KviIrcSocket. See the comment in KviIrcSocket::processData() for more info.
// FIXME: #warning "IF VERBOSE SAY THAT WE'RE REQUESTING MODES & BAN LIST" (Synching channel)
if(!msg->connection()->sendFmtData("MODE %s",encodedChan))return; // disconnected
if(msg->connection()->serverInfo()->supportsModesIe())
{
if(!KVI_OPTION_BOOL(KviOption_boolDisableBanExceptionListRequestOnJoin))
{
if(!msg->connection()->sendFmtData("MODE %s e",encodedChan))return; // disconnected
chan->setSentBanExceptionListRequest();
}
if(!KVI_OPTION_BOOL(KviOption_boolDisableInviteListRequestOnJoin))
{
if(!msg->connection()->sendFmtData("MODE %s I",encodedChan))return; // disconnected
chan->setSentInviteListRequest();
}
}
// MODE %s b MUST BE THE LAST AUTOMATIC CHANNEL TQUERY
// so we get RPL_ENDOFBANLIST as the last reply
// and we know that the channel is in sync
if(!KVI_OPTION_BOOL(KviOption_boolDisableWhoRequestOnJoin))
{
msg->connection()->stateData()->setLastSentChannelWhoRequest(kvi_unixTime());
if(msg->connection()->lagMeter())
{
KviStr tmp(KviStr::Format,"WHO %s",encodedChan);
msg->connection()->lagMeter()->lagCheckRegister(tmp.ptr(),60);
}
if(!msg->connection()->sendFmtData("WHO %s",encodedChan))return; // disconnected
chan->setSentWhoRequest();
}
if(!KVI_OPTION_BOOL(KviOption_boolDisableBanListRequestOnJoin))
{
if(!msg->connection()->sendFmtData("MODE %s b",encodedChan))return; // disconnected
chan->setSentBanListRequest();
}
} else {
// This must be someone else...(or desync)
int iFlags = 0;
iFlags = msg->connection()->serverInfo()->modeFlagFromModeChar(chExtMode);
KviUserListEntry * it = chan->join(szNick,szUser,szHost,iFlags);
// FIXME: #warning "Trigger also OnVoice and OnOp here ?"
// Note: checkDefaultAvatar() makes a KviRegisteredUser lookup
// if later it is needed, make it return a pointer
if(!(it->globalData()->avatar()))console->checkDefaultAvatar(it->globalData(),szNick,szUser,szHost);
if(KVS_TRIGGER_EVENT_3_HALTED(KviEvent_OnJoin,chan,szNick,szUser,szHost))
msg->setHaltOutput();
// FIXME: #warning "WE COULD OPTIONALLY REQUEST A /WHO FOR THE USERS JOINING THAT WE DON'T KNOW THE HOST OF"
}
// Now say it to the world
if(!msg->haltOutput())
{
// FIXME: #warning "CHECK IF MESSAGES GO TO CONSOLE OR NOT"
if(chExtMode != 0)
{
chan->output(KVI_OUT_JOIN,
__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] has joined \r!c\r%Q\r [implicit +%c umode change]"),
&szNick,&szUser,&szHost,&channel,chExtMode);
} else {
chan->output(KVI_OUT_JOIN,
__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] has joined \r!c\r%Q\r"),
&szNick,&szUser,&szHost,&channel);
}
}
//if(!bisMe) deleted because we can open query with our nick
TQString szChans;
int iChans = msg->connection()->getCommonChannels(szNick,szChans);
KviQuery * q = console->connection()->findQuery(szNick);
if(q)
{
if(KVI_OPTION_BOOL(KviOption_boolEnableQueryTracing))
{
q->output(KVI_OUT_TQUERYTRACE,
__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] has just joined \r!c\r%Q\r"),&szNick,&szUser,
&szHost,&channel);
q->notifyCommonChannels(szNick,szUser,szHost,iChans,szChans);
} else {
q->updateLabelText();
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PART
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void KviServerParser::parseLiteralPart(KviIrcMessage *msg)
{
// PART
// :<source_mask> PART <channel> :<part message>
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
TQString szChan = msg->connection()->decodeText(msg->safeParam(0));
// Now lookup the channel
KviConsole * console = msg->console();
KviChannel * chan = msg->connection()->findChannel(szChan);
if(!chan)
{
//chan = msg->context()->findDeadChannel(msg->safeParam(0));
UNRECOGNIZED_MESSAGE(msg,__tr("Received a part message for an unknown channel, possible desync"));
return;
}
// always decode with the textEncoding of the channel
TQString partMsg = msg->paramCount() > 1 ? chan->decodeText(msg->safeTrailing()) : TQString();
if(IS_ME(msg,szNick))
{
if(KVS_TRIGGER_EVENT_1_HALTED(KviEvent_OnMePart,chan,partMsg))
msg->setHaltOutput();
KviWindow * pOut = console;
// It's me!
if(chan->closeOnPart() && !KVI_OPTION_BOOL(KviOption_boolKeepChannelOpenOnPart))
{
chan->frame()->closeWindow(chan); // <-- deleted path
} else {
chan->part(szNick); // this will trigger the action too
chan->setDeadChan();
pOut = chan;
}
if(!msg->haltOutput())
{
if(KVI_OPTION_BOOL(KviOption_boolShowOwnParts))
{
if(partMsg.isEmpty())
pOut->output(KVI_OUT_PART,__tr2qs("You have left channel \r!c\r%Q\r"),&szChan);
else
pOut->output(KVI_OUT_PART,__tr2qs("You have left channel \r!c\r%Q\r: %Q"),&szChan,&partMsg);
}
}
} else {
// Someone else
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnPart,chan,szNick,szUser,szHost,partMsg))
msg->setHaltOutput();
chan->part(szNick);
if(!msg->haltOutput())
{
if(!partMsg.isEmpty())
chan->output(KVI_OUT_PART,
__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] has left \r!c\r%Q\r: %Q"),&szNick,&szUser,
&szHost,&szChan,&partMsg);
else
chan->output(KVI_OUT_PART,
__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] has left \r!c\r%Q\r"),&szNick,&szUser,
&szHost,&szChan);
}
if(KVI_OPTION_BOOL(KviOption_boolEnableQueryTracing))
{
TQString szChans;
int iChans = console->connection()->getCommonChannels(szNick,szChans);
KviQuery * q = console->connection()->findQuery(szNick);
if(q)
{
if(!partMsg.isEmpty())
q->output(KVI_OUT_TQUERYTRACE,
__tr2qs("\r!nc\r%Q\r [%Q@\r!h\r%Q\r] has just left \r!c\r%Q\r: %Q"),
&szNick,&szUser,&szHost,&szChan,&partMsg);
else
q->output(KVI_OUT_TQUERYTRACE,
__tr2qs("\r!nc\r%Q\r [%Q@\r!h\r%Q\r] has just left \r!c\r%Q\r"),
&szNick,&szUser,&szHost,&szChan);
q->notifyCommonChannels(szNick,szUser,szHost,iChans,szChans);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TQUIT
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void KviServerParser::parseLiteralQuit(KviIrcMessage *msg)
{
// TQUIT
// :<source_mask> TQUIT :<quit message>
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
KviConsole * console = msg->console();
// NETSPLIT DETECTION STUFF
// this doesn't need to be decoded for the moment
const char * aux = msg->safeTrailing();
bool bWasSplit = false;
//determine if signoff string matches "%.% %.%", and only one space (from eggdrop code)
char *p = (char *)strchr(aux, ' ');
if (p && (p == (char *)strrchr(aux,' ')))
{
char *daSpace = p;
// one space detected. go ahead
char *z1, *z2;
*p = 0;
z1 = (char *)strchr(p + 1, '.');
z2 = (char *)strchr(aux, '.');
if (z1 && z2 && (*(z1 + 1) > 47) && (z1 - 1 != p) && (z2 + 1 != p) && (z2 != aux) && console->connection())
{
// server split, or else it looked like it anyway
KviIrcConnectionNetsplitDetectorData * ndd = msg->connection()->netsplitDetectorData();
*p=' ';
bWasSplit = true;
time_t curTime = kvi_unixTime();
int diff = ((unsigned int)curTime) - ((unsigned int)ndd->lastNetsplitOnQuitTime());
bool bDuplicate = false;
TQString szReason = aux;
if(diff < 6)
{
if(KviTQString::equalCI(ndd->lastNetsplitOnQuitReason(),szReason))
{
bDuplicate = true;
}
}
ndd->setLastNetsplitOnQuitTime(curTime);
ndd->setLastNetsplitOnQuitReason(szReason);
if(!bDuplicate)
{
KviStr sz1(aux,daSpace - aux);
KviStr sz2(daSpace + 1);
TQString szD1 = msg->connection()->decodeText(sz1.ptr());
TQString szD2 = msg->connection()->decodeText(sz2.ptr());
if(!KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnNetsplit,console,szD1,szD2))
{
if(!msg->haltOutput())
console->output(KVI_OUT_SPLIT,__tr2qs("Netsplit detected: %s"),aux);
}
}
} else *p = ' ';
}
// FIXME: #warning "Add a netsplit parameter ?"
if(KviKvsEventManager::instance()->hasAppHandlers(KviEvent_OnQuit))
{
// compute the channel list
TQString chanlist;
TQString szReason = msg->connection()->decodeText(msg->safeTrailing());
for(KviChannel *daChan=console->channelList()->first();daChan;daChan=console->channelList()->next())
{
if(daChan->isOn(szNick))
{
if(chanlist.isEmpty())chanlist = daChan->windowName();
else {
chanlist.append(',');
chanlist.append(daChan->windowName());
}
}
}
KviKvsVariantList vList;
vList.append(szNick);
vList.append(szUser);
vList.append(szHost);
vList.append(szReason);
vList.append(chanlist);
if(KviKvsEventManager::instance()->trigger(KviEvent_OnQuit,console,&vList))
msg->setHaltOutput();
}
for(KviChannel *c=console->channelList()->first();c;c=console->channelList()->next())
{
if(c->part(szNick))
{
if(!msg->haltOutput())
{
TQString quitMsg = c->decodeText(msg->safeTrailing());
if(bWasSplit)
{
quitMsg.prepend("NETSPLIT ");
}
if(!msg->haltOutput())c->output(KVI_OUT_TQUIT,
__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] has quit IRC: %Q"),
&szNick,&szUser,&szHost,&quitMsg);
}
}
}
if(!msg->haltOutput())
{
KviQuery * q = msg->connection()->findQuery(szNick);
if(q)
{
TQString quitMsg = q->decodeText(msg->safeTrailing());
if(bWasSplit)
{
quitMsg.prepend("NETSPLIT ");
}
q->output(KVI_OUT_TQUIT,__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] has quit IRC: %Q"),
&szNick,&szUser,&szHost,&quitMsg);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// KICK
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void KviServerParser::parseLiteralKick(KviIrcMessage *msg)
{
// KICK
// :<source_mask> KICK <channel> <nick> :<kick message>
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
TQString szChan = msg->connection()->decodeText(msg->safeParam(0));
TQString victim = msg->connection()->decodeText(msg->safeParam(1));
KviConsole * console = msg->console();
KviChannel * chan = msg->connection()->findChannel(szChan);
if(!chan){
// Ooops , desync with the server.
UNRECOGNIZED_MESSAGE(msg,__tr("Received a kick message for an unknown channel, possible desync"));
return;
}
TQString szKickMsg = chan->decodeText(msg->safeTrailing());
if(IS_ME(msg,victim))
{
// ops...I have been kicked
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnMeKick,chan,
szNick,szUser,szHost,szKickMsg))
msg->setHaltOutput();
if(!KVI_OPTION_STRING(KviOption_stringOnMeKickedSound).isEmpty()) KviKvsScript::run("snd.play $0",0,new KviKvsVariantList(new KviKvsVariant(KVI_OPTION_STRING(KviOption_stringOnMeKickedSound))));
TQString szPass = chan->channelKey();
if(KVI_OPTION_BOOL(KviOption_boolKeepChannelOpenOnKick))
{
chan->userAction(szNick,szUser,szHost,KVI_USERACTION_KICK);
chan->part(victim);
chan->setDeadChan();
if(!msg->haltOutput())
{
// FIXME: #warning "OPTION FOR THIS TO GO TO THE CONSOLE!"
chan->output(KVI_OUT_MEKICK,
__tr2qs("You have been kicked from \r!c\r%Q\r by \r!n\r%Q\r [%Q@\r!h\r%Q\r]: %Q"),
&szChan,&szNick,&szUser,&szHost,&szKickMsg);
}
} else {
chan->frame()->closeWindow(chan); // <-- deleted path
if(!msg->haltOutput())
{
// FIXME: #warning "This could go also to the active window!"
console->output(KVI_OUT_MEKICK,
__tr2qs("You have been kicked from \r!c\r%Q\r by \r!n\r%Q\r [%Q@\r!h\r%Q\r]: %Q"),
&szChan,&szNick,&szUser,&szHost,&szKickMsg);
}
}
if(KVI_OPTION_BOOL(KviOption_boolRejoinChannelOnKick))
{
if(_OUTPUT_VERBOSE)
console->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Attempting to rejoin \r!c\r%Q\r..."),&szChan);
KviTQCString szC = msg->connection()->encodeText(szChan);
if(!szPass.isEmpty())
{
KviTQCString szP = msg->connection()->encodeText(szChan);
msg->connection()->sendFmtData("JOIN %s %s",szC.data(),szP.data());
} else msg->connection()->sendFmtData("JOIN %s",szC.data());
}
} else {
// ok...someone else has been kicked
if(KVS_TRIGGER_EVENT_5_HALTED(KviEvent_OnKick,chan,
szNick,szUser,szHost,victim,szKickMsg))
msg->setHaltOutput();
KviIrcUserEntry * e = msg->connection()->userDataBase()->find(victim);
TQString szVHost;
TQString szVUser;
if(e)
{
szVHost = e->host();
szVUser = e->user();
} else {
szVHost = "*";
szVUser = "*";
}
chan->userAction(szNick,szUser,szHost,KVI_USERACTION_KICK);
chan->part(victim);
if(!msg->haltOutput())
{
// FIXME: #warning "OPTION FOR THIS TO GO TO THE CONSOLE!"
chan->output(KVI_OUT_KICK,
__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] has been kicked from \r!c\r%Q\r by \r!n\r%Q\r [%Q@\r!h\r%Q\r]: %Q"),
&victim,&szVUser,&szVHost,&szChan,&szNick,&szUser,&szHost,&szKickMsg);
}
if(KVI_OPTION_BOOL(KviOption_boolEnableQueryTracing))
{
KviQuery * q = console->connection()->findQuery(victim);
if(q)
{
TQString szChans;
int iChans = console->connection()->getCommonChannels(victim,szChans);
q->output(KVI_OUT_TQUERYTRACE,
__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] has just been kicked from \r!c\r%Q\r by \r!n\r%Q\r [%Q@\r!h\r%Q\r]: %Q"),
&victim,&szVUser,&szVHost,&szChan,
&szNick,&szUser,&szHost,&szKickMsg);
q->notifyCommonChannels(victim,szVUser,szVHost,iChans,szChans);
}
}
}
}
#ifdef COMPILE_CRYPT_SUPPORT
#define DECRYPT_IF_NEEDED(_target,_txt,_type,_type2,_buffer,_retptr,_retmsgtype) \
if(KviCryptSessionInfo * cinf = _target->cryptSessionInfo()){ \
if(cinf->bDoDecrypt){ \
switch(cinf->pEngine->decrypt(_txt,_buffer)) \
{ \
case KviCryptEngine::DecryptOkWasEncrypted: \
_retptr = _buffer.ptr(); \
_retmsgtype = _type2; \
break; \
case KviCryptEngine::DecryptOkWasPlainText: \
case KviCryptEngine::DecryptOkWasEncoded: \
_retptr = _buffer.ptr(); \
_retmsgtype = _type; \
break; \
default: /* also case KviCryptEngine::DecryptError: */ \
{ \
TQString szEngineError = cinf->pEngine->lastError(); \
_target->output(KVI_OUT_SYSTEMERROR, \
__tr2qs("The following message appears to be encrypted, but the crypto engine failed to decode it: %Q"), \
&szEngineError); \
_retptr = _txt + 1; _retmsgtype=_type; \
} \
break; \
} \
} else _retptr = _txt, _retmsgtype=_type; \
} else _retptr = _txt, _retmsgtype=_type;
#else //!COMPILE_CRYPT_SUPPORT
#define DECRYPT_IF_NEEDED(_target,_txt,_type,_type2,_buffer,_retptr,_retmsgtype) \
_retptr = _txt; _retmsgtype = _type;
#endif //!COMPILE_CRYPT_SUPPORT
void KviServerParser::parseLiteralPrivmsg(KviIrcMessage *msg)
{
// PRIVMSG
// :source PRIVMSG <target> :<message>
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
TQString szTarget = msg->connection()->decodeText(msg->safeParam(0));
TQString szMsg = msg->connection()->decodeText(msg->safeTrailing());
KviConsole * console = msg->console();
KviRegisteredUser * u = msg->connection()->userDataBase()->registeredUser(szNick,szUser,szHost);
//Highlight it?
// FIXME: #warning "DEDICATED CTCP WINDOW ?"
KviStr * pTrailing = msg->trailingString();
if(pTrailing)
{
if(*(pTrailing->ptr()) == 0x01)
{
if(pTrailing->len() > 1)
{
if(pTrailing->lastCharIs(0x01))pTrailing->cutRight(1);
pTrailing->cutLeft(1);
KviCtcpMessage ctcp;
ctcp.msg = msg;
ctcp.pData = pTrailing->ptr();
KviIrcMask talker(szNick,szUser,szHost); // FIXME!
ctcp.pSource = &talker;
ctcp.szTarget = msg->connection()->decodeText(msg->safeParam(0));
ctcp.bIgnored = false;
ctcp.bIsFlood = false;
ctcp.bUnknown = false;
parseCtcpRequest(&ctcp);
return;
}
}
}
// Normal PRIVMSG
if(IS_ME(msg,szTarget))
{
//Ignore it?
if (u)
{
if (u->isIgnoreEnabledFor(KviRegisteredUser::Query))
{
if(KVS_TRIGGER_EVENT_5_HALTED(KviEvent_OnIgnoredMessage,msg->console(),szNick,szUser,szHost,szTarget,szMsg)) return;
if (KVI_OPTION_BOOL(KviOption_boolVerboseIgnore))
{
console->output(KVI_OUT_IGNORE,__tr2qs("Ignoring query-PRIVMSG from \r!nc\r%Q\r [%Q@\r!h\r%Q\r]: %Q"),&szNick,&szUser,&szHost,&szMsg);
}
return;
}
}
// FIXME: #warning "PROCESS MULTIMEDIA FILE REQUESTS"
// if(g_pOptions->m_bListenToMultimediaFileRequests)
// {
// if(*aux == '!')
// {
// const char *tmp = aux;
// tmp++;
// if(kvi_strEqualCI(tmp,m_pFrm->m_global.szCurrentNick.ptr()))
// {
// // A multimedia file request ?
// tmp += m_pFrm->m_global.szCurrentNick.len();
// if(((*tmp) == ' ') || ((*tmp) == '\t'))
// {
// while(((*tmp) == ' ') || ((*tmp) == '\t'))tmp++;
// if(*tmp)
// {
// KviStr file = tmp;
// KviStr filePath;
// m_pFrm->findMultimediaFileOffert(filePath,file);
// if(filePath.hasData())
// {
// m_pFrm->activeWindow()->output(KVI_OUT_INTERNAL,__tr("%s requests previously offered file %s: sending (%s)"),talker.nick(),file.ptr(),filePath.ptr());
// KviStr cmd(KviStr::Format,"DCC SEND %s %s",talker.nick(),filePath.ptr());
// m_pFrm->m_pUserParser->parseUserCommand(cmd,m_pConsole);
// return;
// } else {
// m_pFrm->activeWindow()->output(KVI_OUT_INTERNAL,__tr("%s requests file %s: no such file was offered , ignoring"),talker.nick(),file.ptr());
// return;
// }
// }
// }
// }
// }
// }
// A query request
// do we have a matching window ?
KviQuery * query = msg->connection()->findQuery(szNick);
if(!query)
{
// New query requested. Check if we really should create it or not
// first of all the anti spam , if desired.
// the antispam blocks anything else
// Eventually we could trigger a special event to notify the user of the
// spam message...
if(KVI_OPTION_BOOL(KviOption_boolUseAntiSpamOnPrivmsg))
{
KviStr * theMsg = msg->trailingString();
if(theMsg)
{
KviStr spamWord;
if(kvi_mayBeSpam(theMsg,spamWord))
{
// FIXME: OnSpam ?
if(!(msg->haltOutput() || KVI_OPTION_BOOL(KviOption_boolSilentAntiSpam)))
{
TQString szMsg = msg->connection()->decodeText(msg->safeTrailing());
console->output(KVI_OUT_SPAM,
__tr2qs("Spam privmsg from \r!n\r%Q\r [%Q@\r!h\r%Q\r]: %Q (matching spamword \"%s\")"),
&szNick,&szUser,&szHost,&szMsg,spamWord.ptr());
}
return;
}
}
}
// this is not a spam, or at least it hasn't been recognized as spam
// user option ? (this should again override any script)
// if the scripters want really to force the query creation they can do
// it manually or they can set the option to true at KVIrc startup
if(KVI_OPTION_BOOL(KviOption_boolCreateQueryOnPrivmsg))
{
TQString szMsg = msg->connection()->decodeText(msg->safeTrailing());
// We still want to create it
// Give the scripter a chance to filter it out again
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnQueryWindowRequest,
console,szNick,szUser,szHost,szMsg))
{
// check if the scripter hasn't created it
query = msg->connection()->findQuery(szNick);
} else {
// no query yet, create it!
// this will trigger OnQueryWindowCreated
query = console->connection()->createQuery(szNick);
// and this will trigger OnQueryTargetAdded
query->setTarget(szNick,szUser,szHost);
}
}
}
// ok, now we either have a query or not
if(query)
{
// ok, we have the query. Trigger the user action anyway
query->userAction(szNick,szUser,szHost,KVI_USERACTION_PRIVMSG);
// decrypt the message if needed
KviStr szBuffer; const char * txtptr; int msgtype;
DECRYPT_IF_NEEDED(query,msg->safeTrailing(),KVI_OUT_TQUERYPRIVMSG,KVI_OUT_TQUERYPRIVMSGCRYPTED,szBuffer,txtptr,msgtype)
// trigger the script event and eventually kill the output
TQString szMsgText = query->decodeText(txtptr);
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnQueryMessage,query,szNick,szUser,szHost,szMsgText))
msg->setHaltOutput();
if(!KVI_OPTION_STRING(KviOption_stringOnQueryMessageSound).isEmpty() && query!=g_pActiveWindow)
{
// KviKvsScript does NOT take parameters ownership
KviKvsVariantList soundParams(new KviKvsVariant(KVI_OPTION_STRING(KviOption_stringOnQueryMessageSound)));
//KviKvsScript::run("snd.play $0",0,&soundParams); <-- we also should provide a window for the script: it's always a good idea
KviKvsScript::run("snd.play $0",query,&soundParams);
}
// spit out the message text
if(!msg->haltOutput())
{
int iFlags = 0;
if(!query->hasAttention())
{
if(KVI_OPTION_BOOL(KviOption_boolFlashQueryWindowOnNewMessages))
{
// avoid double window flashing
iFlags |= KviConsole::NoWindowFlashing;
query->demandAttention();
}
if(KVI_OPTION_BOOL(KviOption_boolPopupNotifierOnNewQueryMessages))
{
// don't send the message to the notifier twice
iFlags |= KviConsole::NoNotifier;
#ifdef COMPILE_USE_QT4
TQString szMsg = TQt::escape(szMsgText);
#else
TQString szMsg = TQStyleSheet::escape(szMsgText);
#endif
//debug("kvi_sp_literal.cpp:908 debug: %s",szMsg.data());
g_pApp->notifierMessage(query,KVI_SMALLICON_TQUERYPRIVMSG,szMsg,1800);
}
}
console->outputPrivmsg(query,msgtype,szNick,szUser,szHost,szMsgText,iFlags);
}
} else {
// no query creation: no decryption possible
// trigger the query message event in the console
TQString szMsgText = msg->connection()->decodeText(msg->safeTrailing());
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnQueryMessage,console,szNick,szUser,szHost,szMsgText))
msg->setHaltOutput();
// we don't have a query here!
//if(!KVI_OPTION_STRING(KviOption_stringOnQueryMessageSound).isEmpty() && query!=g_pActiveWindow)
if(!KVI_OPTION_STRING(KviOption_stringOnQueryMessageSound).isEmpty() && console!=g_pActiveWindow)
{
// same as above
KviKvsVariantList soundParams(new KviKvsVariant(KVI_OPTION_STRING(KviOption_stringOnQueryMessageSound)));
KviKvsScript::run("snd.play $0",console,&soundParams);
}
// spit the message text out
if(!msg->haltOutput())
{
KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolExternalMessagesToActiveWindow) ?
console->activeWindow() : (KviWindow *)(console);
if(KviIrcConnection * pConnection = console->connection())
{
KviWindow * aWin = console->activeWindow();
if((aWin->type() == KVI_WINDOW_TYPE_CHANNEL) && ((KviChannel *)aWin)->isOn(szNick))
pOut = aWin;
else {
for(KviChannel * c = pConnection->channelList()->first();c;c = pConnection->channelList()->next())
if(c->isOn(szNick))
{
pOut = (KviWindow *) c;
break;
}
}
}
pOut->output(KVI_OUT_TQUERYPRIVMSG,"[PRIVMSG \r!nc\r%Q\r]: %Q",&szNick,&szMsgText);
}
}
} else {
// Channel PRIVMSG
KviChannel * chan = msg->connection()->findChannel(szTarget);
TQString szOriginalTarget = szTarget;
TQString szPrefixes;
//Ignore it?
if(u)
{
if(u->isIgnoreEnabledFor(KviRegisteredUser::Channel))
{
if(KVS_TRIGGER_EVENT_5_HALTED(KviEvent_OnIgnoredMessage,msg->console(),szNick,szUser,szHost,szTarget,szMsg))
return;
if (KVI_OPTION_BOOL(KviOption_boolVerboseIgnore))
{
console->output(KVI_OUT_IGNORE,__tr2qs("Ignoring channel-PRIVMSG from \r!nc\r%Q\r [%Q@\r!h\r%Q\r]: %Q"),&szNick,&szUser,&szHost,&szMsg);
}
return;
}
}
if(!chan)
{
// check if the channel has some leading mode prefixes
while((szTarget.length() > 0) && console->connection()->serverInfo()->isSupportedModePrefix(szTarget[0].tqunicode()))
{
szPrefixes += szTarget[0];
szTarget.remove(0,1);
}
chan = msg->connection()->findChannel(szTarget);
}
if(!chan)
{
if(!msg->haltOutput())
{
TQString szMsgText = msg->connection()->decodeText(msg->safeTrailing());
KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolOperatorMessagesToActiveWindow) ?
console->activeWindow() : (KviWindow *)(console);
TQString broad;
KviTQString::sprintf(broad,"[>> %Q] %Q",&szOriginalTarget,&szMsgText);
console->outputPrivmsg(pOut,KVI_OUT_BROADCASTPRIVMSG,szNick,szUser,szHost,broad,0);
}
} else {
chan->userAction(szNick,szUser,szHost,KVI_USERACTION_PRIVMSG);
KviStr szBuffer; const char * txtptr; int msgtype;
DECRYPT_IF_NEEDED(chan,msg->safeTrailing(),KVI_OUT_CHANPRIVMSG,KVI_OUT_CHANPRIVMSGCRYPTED,szBuffer,txtptr,msgtype)
TQString szMsgText = chan->decodeText(txtptr);
if(KVS_TRIGGER_EVENT_5_HALTED(KviEvent_OnChannelMessage,chan,szNick,szUser,szHost,szMsgText,szPrefixes))
msg->setHaltOutput();
if(!msg->haltOutput())
{
if(szPrefixes.length() > 0)
{
TQString szBroad;
KviTQString::sprintf(szBroad,"[>> %Q\r!c\r%Q\r] %Q",&szPrefixes,&szTarget,&szMsgText);
console->outputPrivmsg(chan,msgtype,szNick,szUser,szHost,szBroad,0);
} else {
console->outputPrivmsg(chan,msgtype,szNick,szUser,szHost,szMsgText,0);
}
}
}
}
}
void KviServerParser::parseLiteralNotice(KviIrcMessage *msg)
{
// NOTICE
// :source NOTICE <target> :<message>
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
KviConsole * console = msg->console();
if(szHost == "*")
{
if(szUser == "*")
{
if(szNick.find('.') != -1)
{
// server notice
// FIXME: "Dedicated window for server notices ?"
TQString szMsgText = msg->connection()->decodeText(msg->safeTrailing());
if(KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnServerNotice,console,szNick,szMsgText))
msg->setHaltOutput();
if(!msg->haltOutput())
{
KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerNoticesToActiveWindow) ?
console->activeWindow() : (KviWindow *)(console);
pOut->output(KVI_OUT_SERVERNOTICE,"[\r!s\r%Q\r]: %Q",&szNick,&szMsgText);
}
return;
}
}
}
// FIXME: "DEDICATED CTCP WINDOW ?"
KviStr * pTrailing = msg->trailingString();
if(pTrailing)
{
if(*(pTrailing->ptr()) == 0x01){
if(pTrailing->len() > 1)
{
if(pTrailing->lastCharIs(0x01))pTrailing->cutRight(1);
pTrailing->cutLeft(1);
KviCtcpMessage ctcp;
ctcp.msg = msg;
ctcp.pData = pTrailing->ptr();
KviIrcMask talker(szNick,szUser,szHost); // FIXME
ctcp.pSource = &talker;
ctcp.szTarget = msg->connection()->decodeText(msg->safeParam(0));
ctcp.bIgnored = false;
ctcp.bIsFlood = false;
ctcp.bUnknown = false;
parseCtcpReply(&ctcp);
return;
}
}
}
TQString szTarget = msg->connection()->decodeText(msg->safeParam(0));
KviRegisteredUser * u = msg->connection()->userDataBase()->registeredUser(szNick,szUser,szHost);
//Ignore it?
if(u)
{
if(u->isIgnoreEnabledFor(KviRegisteredUser::Notice))
{
if(KVI_OPTION_BOOL(KviOption_boolVerboseIgnore))
{
TQString szMsg = msg->connection()->decodeText(msg->safeTrailing());
console->output(KVI_OUT_IGNORE,__tr2qs("Ignoring Notice from \r!nc\r%Q\r [%Q@\r!h\r%Q\r]: %Q"),&szNick,&szUser,&szHost,&szMsg);
}
return;
}
}
// Normal NOTICE
if(IS_ME(msg,szTarget))
{
// FIXME: "The NickServ and ChanServ handling should be optional!"
if(KviTQString::equalCI(szNick,"NickServ"))
{
TQString szMsgText = msg->connection()->decodeText(msg->safeTrailing());
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnNickServNotice,console,szNick,szUser,szHost,szMsgText))
msg->setHaltOutput();
// nickname service... does it ask for identification ?
if(!msg->haltOutput())
{
KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServicesNoticesToActiveWindow) ?
console->activeWindow() : (KviWindow *)(console);
pOut->output(KVI_OUT_NICKSERV,"\r!n\r%Q\r [%Q@\r!h\r%Q\r]: %Q",&szNick,&szUser,&szHost,&szMsgText);
}
bool bAuthDone = false;
KviNickServRuleSet * r = msg->connection()->target()->network()->nickServRuleSet();
if(r)
{
if(r->isEnabled() && !r->isEmpty())
{
KviIrcMask talker(szNick,szUser,szHost);
KviNickServRule * rule = r->matchRule(msg->connection()->currentNickName(),&talker,szMsgText);
if(rule)
{
bAuthDone = true;
console->outputNoFmt(KVI_OUT_SYSTEMMESSAGE,__tr2qs("NickServ requests authentication, executing scheduled command"));
if(!KviKvsScript::run(rule->identifyCommand(),console))
{
console->outputNoFmt(KVI_OUT_SYSTEMERROR,__tr2qs("The scheduled NickServ identification command appears to be broken, please change the setting"));
}
}
}
}
if(!bAuthDone)
{
if(g_pNickServRuleSet->isEnabled() && !g_pNickServRuleSet->isEmpty())
{
KviIrcMask talker(szNick,szUser,szHost);
KviNickServRule * rule = g_pNickServRuleSet->matchRule(msg->connection()->currentNickName(),&talker,szMsgText,msg->connection()->currentServerName());
if(rule)
{
console->outputNoFmt(KVI_OUT_SYSTEMMESSAGE,__tr2qs("NickServ requests authentication, executing scheduled command"));
if(!KviKvsScript::run(rule->identifyCommand(),console))
{
console->outputNoFmt(KVI_OUT_SYSTEMERROR,__tr2qs("The scheduled NickServ identification command appears to be broken, please change the setting"));
}
}
}
}
return;
}
if(KviTQString::equalCI(szNick,"ChanServ"))
{
TQString szMsgText = msg->connection()->decodeText(msg->safeTrailing());
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnChanServNotice,console,szNick,szUser,szHost,szMsgText))
msg->setHaltOutput();
if(!msg->haltOutput())
{
KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServicesNoticesToActiveWindow) ?
console->activeWindow() : (KviWindow *)(console);
pOut->output(KVI_OUT_CHANSERV,"\r!n\r%Q\r [%Q@\r!h\r%Q\r]: %Q",&szNick,&szUser,&szHost,&szMsgText);
}
return;
}
// FIXME: PROCESS MULTIMEDIA FILE REQUESTS
// A query request
// do we have a matching window ?
KviQuery * query = msg->connection()->findQuery(szNick);
if(!query)
{
// New query requested. Check if we really should create it or not
// first of all the anti spam , if desired.
// the antispam blocks anything else
// Eventually we could trigger a special event to notify the user of the
// spam message...
if(KVI_OPTION_BOOL(KviOption_boolUseAntiSpamOnNotice))
{
KviStr * theMsg = msg->trailingString(); // FIXME
if(theMsg)
{
KviStr spamWord;
if(kvi_mayBeSpam(theMsg,spamWord))
{
// FIXME: OnSpam ?
if(!(msg->haltOutput() || KVI_OPTION_BOOL(KviOption_boolSilentAntiSpam)))
{
TQString szMsgText = msg->connection()->decodeText(msg->safeTrailing());
TQString szSpamWord = spamWord.ptr();
console->output(KVI_OUT_SPAM,__tr2qs("Spam notice from \r!n\r%Q\r [%Q@\r!h\r%Q\r]: %Q (matching spamword \"%Q\")"),
&szNick,&szUser,&szHost,&szMsgText,&szSpamWord);
}
return;
}
}
}
// this is not a spam, or at least it hasn't been recognized as spam
// user option ? (this should again override any script)
// if the scripters want really to force the query creation they can do
// it manually or they can set the option to true at KVIrc startup
if(KVI_OPTION_BOOL(KviOption_boolCreateQueryOnNotice))
{
TQString szMsgText = msg->connection()->decodeText(msg->safeTrailing());
// We still want to create it
// Give the scripter a chance to filter it out again
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnQueryWindowRequest,console,szNick,szUser,szHost,szMsgText))
{
// check if the scripter hasn't created it
query = msg->connection()->findQuery(szNick);
} else {
// no query yet, create it!
// this will trigger OnQueryWindowCreated
query = console->connection()->createQuery(szNick);
// and this will trigger OnQueryTargetAdded
query->setTarget(szNick,szUser,szHost);
}
}
}
// ok, now we either have a query or not
if(query)
{
// ok, we have the query. Trigger the user action anyway
query->userAction(szNick,szUser,szHost,KVI_USERACTION_NOTICE);
// decrypt it if needed
KviStr szBuffer; const char * txtptr; int msgtype;
DECRYPT_IF_NEEDED(query,msg->safeTrailing(),KVI_OUT_TQUERYNOTICE,KVI_OUT_TQUERYNOTICECRYPTED,szBuffer,txtptr,msgtype)
TQString szMsgText = query->decodeText(txtptr);
// trigger the script event and eventually kill the output
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnQueryNotice,query,szNick,szUser,szHost,szMsgText))
msg->setHaltOutput();
// spit out the message text
if(!msg->haltOutput())
{
int iFlags = 0;
if(!query->hasAttention())
{
if(KVI_OPTION_BOOL(KviOption_boolFlashQueryWindowOnNewMessages))
{
// avoid double window flashing
iFlags |= KviConsole::NoWindowFlashing;
query->demandAttention();
}
if(KVI_OPTION_BOOL(KviOption_boolPopupNotifierOnNewQueryMessages))
{
// don't send the message twice to the notifier
iFlags |= KviConsole::NoNotifier;
#ifdef COMPILE_USE_QT4
TQString szMsg = TQt::escape(szMsgText);
#else
TQString szMsg = TQStyleSheet::escape(szMsgText);
#endif
//debug("kvi_sp_literal.cpp:908 debug: %s",szMsg.data());
g_pApp->notifierMessage(query,KVI_SMALLICON_TQUERYNOTICE,szMsg,1800);
}
}
console->outputPrivmsg(query,msgtype,szNick,szUser,szHost,szMsgText,iFlags);
}
} else {
TQString szMsgText = msg->connection()->decodeText(msg->safeTrailing());
// no query creation: no decryption possible
// trigger the query message event in the console
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnQueryNotice,console,szNick,szUser,szHost,szMsgText))
msg->setHaltOutput();
// spit the message text out
if(!msg->haltOutput())
{
KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolExternalMessagesToActiveWindow) ?
console->activeWindow() : (KviWindow *)(console);
if(KviIrcConnection * pConnection = console->connection())
{
KviWindow * aWin = console->activeWindow();
if((aWin->type() == KVI_WINDOW_TYPE_CHANNEL) && ((KviChannel *)aWin)->isOn(szNick))
pOut = aWin;
else {
for(KviChannel * c = pConnection->channelList()->first();c;c = pConnection->channelList()->next())
if(c->isOn(szNick))
{
pOut = (KviWindow *) c;
break;
}
}
}
pOut->output(KVI_OUT_TQUERYNOTICE,"*\r!n\r%Q\r* %Q",&szNick,&szMsgText);
}
}
return;
}
// Channel NOTICE
KviChannel * chan = msg->connection()->findChannel(szTarget);
TQString szOriginalTarget = szTarget;
TQString szPrefixes;
if(!chan)
{
// check if the channel has some leading mode prefixes
while((szTarget.length() > 0) && console->connection()->serverInfo()->isSupportedModePrefix(szTarget[0].tqunicode()))
{
szPrefixes += szTarget[0];
szTarget.remove(0,1);
}
chan = msg->connection()->findChannel(szTarget);
}
if(!chan)
{
if(!msg->haltOutput())
{
KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolOperatorMessagesToActiveWindow) ?
console->activeWindow() : (KviWindow *)(console);
TQString szBroad;
TQString szMsgText = msg->connection()->decodeText(msg->safeTrailing());
KviTQString::sprintf(szBroad,"[>> %Q] %Q",&szOriginalTarget,&szMsgText);
console->outputPrivmsg(pOut,KVI_OUT_BROADCASTNOTICE,szNick,szUser,szHost,szBroad,0);
return;
}
} else {
chan->userAction(szNick,szUser,szHost,KVI_USERACTION_NOTICE);
KviStr szBuffer; const char * txtptr; int msgtype;
DECRYPT_IF_NEEDED(chan,msg->safeTrailing(),KVI_OUT_CHANNELNOTICE,KVI_OUT_CHANNELNOTICECRYPTED,szBuffer,txtptr,msgtype)
TQString szMsgText = chan->decodeText(txtptr);
if(KVS_TRIGGER_EVENT_3_HALTED(KviEvent_OnChannelNotice,chan,szNick,szMsgText,szOriginalTarget))msg->setHaltOutput();
if(!msg->haltOutput())
{
if(szPrefixes.length() > 0)
{
TQString szBroad;
KviTQString::sprintf(szBroad,"[>> %Q\r!c\r%Q\r] %Q",&szPrefixes,&szTarget,&szMsgText);
console->outputPrivmsg(chan,msgtype,szNick,szUser,szHost,szBroad,0);
} else {
console->outputPrivmsg(chan,msgtype,szNick,szUser,szHost,szMsgText,0);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TOPIC
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void KviServerParser::parseLiteralTopic(KviIrcMessage *msg)
{
// TOPIC
// :<source_mask> TOPIC <channel> :<topic>
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
TQString szTarget = msg->connection()->decodeText(msg->safeParam(0));
// Now lookup the channel
KviChannel * chan = msg->connection()->findChannel(szTarget);
if(!chan)
{
UNRECOGNIZED_MESSAGE(msg,__tr2qs("Received a topic message for an unknown channel, possible desync"));
return;
}
TQString szTopic = chan->decodeText(msg->safeTrailing());
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnTopic,chan,szNick,szUser,szHost,szTopic))
msg->setHaltOutput();
chan->topicWidget()->setTopic(szTopic);
chan->topicWidget()->setTopicSetBy(szNick);
TQString tmp = TQDateTime::currentDateTime().toString();
chan->topicWidget()->setTopicSetAt(tmp);
chan->userAction(szNick,szUser,szHost,KVI_USERACTION_TOPIC);
if(!msg->haltOutput())
{
chan->output(KVI_OUT_TOPIC,
__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] has changed topic to \"%Q%c\""),
&szNick,&szUser,&szHost,&szTopic,KVI_TEXT_RESET);
}
}
void KviServerParser::parseLiteralNick(KviIrcMessage *msg)
{
// NICK
// :source NICK <newnick>
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
KviConsole * console = msg->console();
TQString szNewNick = msg->connection()->decodeText(msg->safeTrailing());
bool bIsMe = IS_ME(msg,szNick);
if(bIsMe)
{
// We have changed our nick
msg->connection()->nickChange(szNewNick);
if(KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnMeNickChange,console,szNick,szNewNick))
msg->setHaltOutput();
} else {
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnNickChange,console,szNick,szUser,szHost,szNewNick))
msg->setHaltOutput();
}
for(KviChannel * c = console->channelList()->first();c;c = console->channelList()->next())
{
if(c->nickChange(szNick,szNewNick))
{
if(!msg->haltOutput())
c->output(KVI_OUT_NICK,__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] is now known as \r!n\r%Q\r"),
&szNick,&szUser,&szHost,&szNewNick);
// FIXME if(bIsMe)output(YOU ARE now known as.. ?)
}
if(bIsMe)c->updateCaption();
}
// FIXME: #warning "NEW NICK MIGHT BE REGISTERED AND HAVE AN AVATAR!"
if(bIsMe)
{
// just update all the captions : we have changed OUR nick
for(KviQuery * q = console->queryList()->first();q;q = console->queryList()->next())
{
if(!msg->haltOutput())
q->output(KVI_OUT_NICK,__tr2qs("You have changed your nickname to %Q"),&szNewNick);
q->updateCaption();
}
}
KviQuery * q = console->connection()->findQuery(szNick);
// It CAN happen that szNewNick first queries us without being
// on any channel then he TQUITS , he reconnects , he joins
// a channel with szNick , queries us and changes nick to szNewNick : gotcha!
// should merge the queries!
KviQuery * old = console->connection()->findQuery(szNewNick);
if(old && (old != q))
{
if(KVI_OPTION_BOOL(KviOption_boolEnableQueryTracing) && (!_OUTPUT_TQUIET))
{
old->output(KVI_OUT_TQUERYTRACE,
__tr2qs("The target of this query was lost and has been found when \r!n\r%Q\r [%Q@\r!h\r%Q\r] changed his nickname to \r!n\r%Q\r"),
&szNick,&szUser,&szHost,&szNewNick);
}
if(q)
{
bool bTQWasActive = (q == g_pActiveWindow);
if(!_OUTPUT_MUTE)
{
old->output(KVI_OUT_SYSTEMWARNING,
__tr2qs("The recent nickname change from \r!n\r%Q\r to \r!n\r%Q\r caused a query collision: merging output"),
&szNick,&szNewNick);
}
old->mergeQuery(q);
q->frame()->closeWindow(q); // deleted path
if(!msg->haltOutput())
old->output(KVI_OUT_NICK,__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] is now known as \r!n\r%Q\r"),
&szNick,&szUser,&szHost,&szNewNick);
if(!_OUTPUT_MUTE)
old->output(KVI_OUT_SYSTEMWARNING,__tr2qs("End of merged output"));
old->userAction(szNewNick,szUser,szHost,KVI_USERACTION_NICK);
if(bTQWasActive)old->delayedAutoRaise();
}
if(KVI_OPTION_BOOL(KviOption_boolEnableQueryTracing))
{
TQString szChans;
int iChans = console->connection()->getCommonChannels(szNewNick,szChans);
old->notifyCommonChannels(szNewNick,szUser,szHost,iChans,szChans);
}
} else {
if(q)
{
// the target SHOULD have changed his nick here
if(!q->nickChange(szNick,szNewNick))
debug("Internal error: query %s failed to change nick from %s to s",szNick.utf8().data(),szNick.utf8().data(),szNewNick.utf8().data());
if(!msg->haltOutput())
q->output(KVI_OUT_NICK,__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] is now known as \r!n\r%Q\r"),
&szNick,&szUser,&szHost,&szNewNick);
q->userAction(szNewNick,szUser,szHost,KVI_USERACTION_NICK);
}
}
// FIXME: #warning "UPDATE ALL THE OTHER CONNECTION RELATED WINDOW CAPTIONS WHEN bIsMe!!"
}
void KviServerParser::parseLiteralInvite(KviIrcMessage *msg)
{
// INVITE
// :source INVITE <target> <channel>
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
TQString szTarget = msg->connection()->decodeText(msg->safeParam(0));
TQString szChannel = msg->connection()->decodeText(msg->safeParam(1));
KviConsole * console = msg->console();
KviRegisteredUser * u = msg->connection()->userDataBase()->registeredUser(szNick,szUser,szHost);
//Ignore it?
if(u)
{
if(u->isIgnoreEnabledFor(KviRegisteredUser::Invite))
{
if(KVI_OPTION_BOOL(KviOption_boolVerboseIgnore))
{
console->output(KVI_OUT_IGNORE,__tr2qs("Ignoring invite from \r!nc\r%Q\r [%Q@\r!h\r%Q\r]"),&szNick,&szUser,&szHost);
}
return;
}
}
if(IS_ME(msg,szTarget))
{
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnInvite,msg->console(),szNick,szUser,szHost,szChannel))
msg->setHaltOutput();
if(!msg->haltOutput())
{
KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolInvitesToActiveWindow) ?
msg->console()->activeWindow() : (KviWindow *)(msg->console());
TQString szAction = KVI_OPTION_BOOL(KviOption_boolAutoJoinOnInvite) ? __tr2qs("autojoining") : __tr2qs("double-click the channel name to join");
pOut->output(KVI_OUT_INVITE,__tr2qs("\r!n\r%Q\r [%Q@\r!h\r%Q\r] invites you to channel \r!c\r%Q\r (%Q)"),
&szNick,&szUser,&szHost,&szChannel,&szAction);
}
if(KVI_OPTION_BOOL(KviOption_boolAutoJoinOnInvite))
msg->connection()->sendFmtData("JOIN %s",msg->safeParam(1));
} else {
UNRECOGNIZED_MESSAGE(msg,__tr("Received an invite message directed to another nick, possible desync"));
}
}
void KviServerParser::parseLiteralWallops(KviIrcMessage *msg)
{
// WALLOPS
// :source WALLOPS :msg
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
TQString szMsg = msg->connection()->decodeText(msg->safeTrailing());
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnWallops,msg->console(),szNick,szUser,szHost,szMsg))
msg->setHaltOutput();
if(!msg->haltOutput())
{
KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolOperatorMessagesToActiveWindow) ?
msg->console()->activeWindow() : (KviWindow *)(msg->console());
pOut->output(KVI_OUT_WALLOPS,__tr2qs("WALLOPS from \r!n\r%Q\r [%Q@\r!h\r%Q\r]: %Q"),
&szNick,&szUser,&szHost,&szMsg);
}
}
void KviServerParser::parseUserMode(KviIrcMessage *msg,const char * modeflptr)
{
// changed my user mode
bool bSet = true;
while(*modeflptr)
{
switch(*modeflptr)
{
case '+': bSet = true; break;
case '-': bSet = false; break;
default:
if(msg->connection()->changeUserMode(*modeflptr,bSet))
{
if(msg->connection()->serverInfo()->registerModeChar()==*modeflptr)
{
KviKvsVariantList vList;
KviKvsEventManager::instance()->trigger(KviEvent_OnNickServAuth,msg->console(),&vList);
}
// There was a mode change
if(KviKvsEventManager::instance()->hasAppHandlers(KviEvent_OnUserMode))
{
TQString szModeFlag(bSet ? TQChar('+') : TQChar('-'));
szModeFlag += TQChar(*modeflptr);
KviKvsVariantList vList(new KviKvsVariant(szModeFlag));
if(KviKvsEventManager::instance()->trigger(KviEvent_OnUserMode,msg->console(),&vList))
msg->setHaltOutput();
}
}
break;
}
++modeflptr;
}
}
void KviServerParser::parseLiteralMode(KviIrcMessage *msg)
{
// NICK
// :source MODE target <params>
// :source MODE <me> +|-modeflag
// :source MODE <channel> +-modeflags [parameters]
TQString szNick,szUser,szHost;
msg->decodeAndSplitPrefix(szNick,szUser,szHost);
// if(!source.hasHost())
// {
// // This is a server or a channel service
// KviStr snick = source.nick();
// if(snick.contains('.'))source.setHost(source.nick()); // this is a server
// }
TQString szTarget = msg->connection()->decodeText(msg->safeParam(0));
KviStr modefl(msg->safeParam(1));
if(IS_ME(msg,szTarget))
{
parseUserMode(msg,modefl.ptr());
if(!msg->haltOutput())
msg->console()->output(KVI_OUT_MODE,__tr2qs("You have set user mode %s"),modefl.ptr());
} else {
// a channel mode
KviChannel * chan = msg->connection()->findChannel(szTarget);
if(!chan){
// Ooops , desync with the server.
UNRECOGNIZED_MESSAGE(msg,__tr("Received a mode change for an unknown channel, possible desync"));
return;
}
chan->userAction(szNick,szUser,szHost,KVI_USERACTION_CHANMODE);
parseChannelMode(szNick,szUser,szHost,chan,modefl,msg,2);
}
}
void KviServerParser::parseChannelMode(const TQString &szNick,const TQString &szUser,const TQString &szHost,KviChannel * chan,KviStr &modefl,KviIrcMessage *msg,int curParam)
{
// FIXME: freenode has two ugly incompatible extensions:
// mode e: that is NOT viewable (???)
// mode q that stands for "quiet-ban"
// mode #chan +q mask
// adds mask to the banlist with the prefix %
// and doesn't allow the users matching the mask to talk to the channel
bool bSet = true;
const char * aux = modefl.ptr();
TQString aParam;
TQString nickBuffer;
TQString hostBuffer;
if(szHost != "*")
{
KviTQString::sprintf(nickBuffer,"\r!n\r%Q\r",&szNick);
KviTQString::sprintf(hostBuffer,"\r!h\r%Q\r",&szHost);
} else {
if(nickBuffer.find('.') != -1)
{
// This looks a lot like a server!
KviTQString::sprintf(nickBuffer,"\r!s\r%Q\r",&szNick);
} else {
// Probably a service....whois should work
KviTQString::sprintf(nickBuffer,"\r!n\r%Q\r",&szNick);
}
hostBuffer = szHost;
}
KviIrcMask * auxMask;
int curParamSave = curParam;
bool bIsMe;
//FIXME: Use PREFIX in 005 numeric instead of bServerSupportsModeIe - get rid of it altogether
//bool bModeIe = console->connection()->serverInfo()->supportsModesIe();
while(*aux)
{
switch(*aux)
{
case '+':
bSet = true;
break;
case '-':
bSet = false;
break;
case 'k':
if(bSet)aParam = msg->safeParam(curParam++);
else aParam = "";
chan->setChannelKey(aParam);
if(bSet) {
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnKeySet,chan,szNick,szUser,szHost,aParam))
msg->setHaltOutput();
} else {
if(KVS_TRIGGER_EVENT_3_HALTED(KviEvent_OnKeyUnset,chan,szNick,szUser,szHost))
msg->setHaltOutput();
}
if(!(msg->haltOutput() || KVI_OPTION_BOOL(KviOption_boolShowCompactModeChanges)))
{
if(bSet)chan->output(KVI_OUT_KEY,
__tr2qs("%Q [%Q@%Q] has set channel key to \"\r!m-k\r%Q\r\""),
&nickBuffer,&szUser,&hostBuffer,&aParam);
else chan->output(KVI_OUT_KEY,
__tr2qs("%Q [%Q@%Q] has unset the channel key"),
&nickBuffer,&szUser,&hostBuffer);
}
break;
case 'l':
if(bSet)aParam = msg->safeParam(curParam++);
else aParam = "";
chan->setChannelLimit(aParam);
if(bSet) {
if(KVS_TRIGGER_EVENT_4_HALTED(KviEvent_OnLimitSet,chan,szNick,szUser,szHost,aParam))
msg->setHaltOutput();
} else {
if(KVS_TRIGGER_EVENT_3_HALTED(KviEvent_OnLimitUnset,chan,szNick,szUser,szHost))
msg->setHaltOutput();
}
if(!(msg->haltOutput() || KVI_OPTION_BOOL(KviOption_boolShowCompactModeChanges)))
{
if(bSet)chan->output(KVI_OUT_LIMIT,
__tr2qs("%Q [%Q@%Q] has set channel \r!m-l\rlimit to %Q\r"),
&nickBuffer,&szUser,&hostBuffer,&aParam);
else chan->output(KVI_OUT_LIMIT,
__tr2qs("%Q [%Q@%Q] has unset the channel limit"),
&nickBuffer,&szUser,&hostBuffer);
}
break;
#define CHANUSER_MODE(__modechar,__chanfunc,__evmeset,__evmeunset,__evset,__evunset,__icomeset,__icomeunset,__icoset,__icounset) \
case __modechar: \
if(msg->connection()->serverInfo()->isSupportedModeFlag(__modechar)) \
{ \
aParam = msg->connection()->decodeText(msg->safeParam(curParam++)); \
chan->__chanfunc(aParam,bSet); \
bIsMe = IS_ME(msg,aParam); \
if(bIsMe) \
{ \
if(KVS_TRIGGER_EVENT_3_HALTED(bSet ? __evmeset : __evmeunset,chan,szNick,szUser,szHost))msg->setHaltOutput(); \
chan->updateCaption(); \
} else { \
if(KVS_TRIGGER_EVENT_4_HALTED(bSet ? __evset : __evunset,chan,szNick,szUser,szHost,aParam))msg->setHaltOutput(); \
} \
if(!(msg->haltOutput() || KVI_OPTION_BOOL(KviOption_boolShowCompactModeChanges))) \
{ \
chan->output(bSet ? (bIsMe ? __icomeset : __icoset) : (bIsMe ? __icomeunset : __icounset), \
__tr2qs("%Q [%Q@%Q] has set mode %c%c \r!n\r%Q\r"), \
&nickBuffer,&szUser,&hostBuffer,bSet ? '+' : '-',__modechar,&aParam); \
} \
} else {\
chan->setChannelMode(__modechar,bSet);\
if(!(msg->haltOutput() || KVI_OPTION_BOOL(KviOption_boolShowCompactModeChanges)))\
{\
chan->output(KVI_OUT_CHANMODE,\
__tr2qs("%Q [%Q@%Q] has set channel \r!m%c%c\rmode %c%c\r"),\
&nickBuffer,&szUser,&hostBuffer,\
bSet ? '-' : '+',__modechar,bSet ? '+' : '-',__modechar);\
}\
}\
break;
CHANUSER_MODE('q',setChanOwner,KviEvent_OnMeChanOwner,KviEvent_OnMeDeChanOwner,KviEvent_OnChanOwner,KviEvent_OnDeChanOwner,KVI_OUT_MECHANOWNER,KVI_OUT_MEDECHANOWNER,KVI_OUT_CHANOWNER,KVI_OUT_DECHANOWNER)
CHANUSER_MODE('a',setChanAdmin,KviEvent_OnMeChanAdmin,KviEvent_OnMeDeChanAdmin,KviEvent_OnChanAdmin,KviEvent_OnDeChanAdmin,KVI_OUT_MECHANADMIN,KVI_OUT_MEDECHANADMIN,KVI_OUT_CHANADMIN,KVI_OUT_DECHANADMIN)
CHANUSER_MODE('o',op,KviEvent_OnMeOp,KviEvent_OnMeDeOp,KviEvent_OnOp,KviEvent_OnDeOp,KVI_OUT_MEOP,KVI_OUT_MEDEOP,KVI_OUT_OP,KVI_OUT_DEOP)
CHANUSER_MODE('h',halfop,KviEvent_OnMeHalfOp,KviEvent_OnMeDeHalfOp,KviEvent_OnHalfOp,KviEvent_OnDeHalfOp,KVI_OUT_MEHALFOP,KVI_OUT_MEDEHALFOP,KVI_OUT_HALFOP,KVI_OUT_HALFDEOP)
CHANUSER_MODE('v',voice,KviEvent_OnMeVoice,KviEvent_OnMeDeVoice,KviEvent_OnVoice,KviEvent_OnDeVoice,KVI_OUT_MEVOICE,KVI_OUT_MEDEVOICE,KVI_OUT_VOICE,KVI_OUT_DEVOICE)
CHANUSER_MODE('u',userop,KviEvent_OnMeUserOp,KviEvent_OnMeDeUserOp,KviEvent_OnUserOp,KviEvent_OnDeUserOp,KVI_OUT_MEUSEROP,KVI_OUT_MEDEUSEROP,KVI_OUT_USEROP,KVI_OUT_USERDEOP)
#define CHANNEL_MODE(__modefl,__evmeset,__evmeunset,__evset,__evunset,__icomeset,__icomeunset,__icoset,__icounset) \
case __modefl: \
aParam = msg->connection()->decodeText(msg->safeParam(curParam++)); \
chan->setMask(*aux,aParam,bSet,msg->connection()->decodeText(msg->safePrefix()),TQDateTime::currentDateTime().toTime_t()); \
auxMask = new KviIrcMask(aParam); \
bIsMe = auxMask->matchesFixed( \
msg->connection()->userInfo()->nickName(), \
msg->connection()->userInfo()->userName(), \
msg->connection()->userInfo()->hostName()); \
delete auxMask; \
if(bIsMe) \
{ \
if(KVS_TRIGGER_EVENT_4_HALTED(bSet ? __evmeset : __evmeunset,chan,szNick,szUser,szHost,aParam))msg->setHaltOutput(); \
} else { \
if(KVS_TRIGGER_EVENT_4_HALTED(bSet ? __evset : __evunset,chan,szNick,szUser,szHost,aParam))msg->setHaltOutput(); \
} \
if(!(msg->haltOutput() || KVI_OPTION_BOOL(KviOption_boolShowCompactModeChanges))) \
{ \
chan->output(bSet ? (bIsMe ? __icomeset : __icoset) : (bIsMe ? __icomeunset : __icounset), \
__tr2qs("%Q [%Q@%Q] has set mode %c%c \r!m%c%c\r%Q\r"), \
&nickBuffer,&szUser,&hostBuffer, \
bSet ? '+' : '-',__modefl,bSet ? '-' : '+',__modefl,&aParam); \
} \
break;
CHANNEL_MODE('b',KviEvent_OnMeBan,KviEvent_OnMeUnban,KviEvent_OnBan,KviEvent_OnUnban,KVI_OUT_MEBAN,KVI_OUT_MEUNBAN,KVI_OUT_BAN,KVI_OUT_UNBAN)
CHANNEL_MODE('I',KviEvent_OnMeInviteException,KviEvent_OnMeInviteExceptionRemove,KviEvent_OnInviteException,KviEvent_OnInviteExceptionRemove,KVI_OUT_MEINVITEEXCEPT,KVI_OUT_MEINVITEUNEXCEPT,KVI_OUT_INVITEEXCEPT,KVI_OUT_INVITEUNEXCEPT)
CHANNEL_MODE('e',KviEvent_OnMeBanException,KviEvent_OnMeBanExceptionRemove,KviEvent_OnBanException,KviEvent_OnBanExceptionRemove,KVI_OUT_MEBANEXCEPT,KVI_OUT_MEBANUNEXCEPT,KVI_OUT_BANEXCEPT,KVI_OUT_BANUNEXCEPT)
default:
chan->setChannelMode(*aux,bSet);
if(!(msg->haltOutput() || KVI_OPTION_BOOL(KviOption_boolShowCompactModeChanges)))
{
chan->output(KVI_OUT_CHANMODE,
__tr2qs("%Q [%Q@%Q] has set channel \r!m%c%c\rmode %c%c\r"),
&nickBuffer,&szUser,&hostBuffer,
bSet ? '-' : '+',*aux,bSet ? '+' : '-',*aux);
}
break;
}
++aux;
}
TQString param;
TQString params;
param = msg->connection()->decodeText(msg->safeParam(curParamSave++));
while(!param.isEmpty())
{
if(!params.isEmpty())params.append(' ');
params.append(param);
param = msg->connection()->decodeText(msg->safeParam(curParamSave++));
}
if(KVS_TRIGGER_EVENT_5_HALTED(KviEvent_OnChannelModeChange,chan,szNick,szUser,szHost,modefl.ptr(),params))
msg->setHaltOutput();
if(KVI_OPTION_BOOL(KviOption_boolShowCompactModeChanges) && (!msg->haltOutput()) && (!kvi_strEqualCS(modefl.ptr(),"+")))
{
if(!params.isEmpty())
{
chan->output(KVI_OUT_CHANMODE,__tr2qs("%Q [%Q@%Q] has set mode %s %Q"),
&nickBuffer,&szUser,&hostBuffer,modefl.ptr(),&params);
} else {
chan->output(KVI_OUT_CHANMODE,__tr2qs("%Q [%Q@%Q] has set channel mode %s"),
&nickBuffer,&szUser,&hostBuffer,modefl.ptr());
}
}
}