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.
1868 lines
61 KiB
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->unicode() && (pExt->unicode() != 0x07))pExt++;
|
|
if(pExt->unicode())
|
|
{
|
|
++pExt;
|
|
if(pExt->unicode())
|
|
{
|
|
chExtMode = (char)pExt->unicode();
|
|
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 QUERY
|
|
// 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_QUERYTRACE,
|
|
__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_QUERYTRACE,
|
|
__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_QUERYTRACE,
|
|
__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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// QUIT
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void KviServerParser::parseLiteralQuit(KviIrcMessage *msg)
|
|
{
|
|
// QUIT
|
|
// :<source_mask> QUIT :<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_QUIT,
|
|
__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_QUIT,__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_QUERYTRACE,
|
|
__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_QUERYPRIVMSG,KVI_OUT_QUERYPRIVMSGCRYPTED,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_QUERYPRIVMSG,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_QUERYPRIVMSG,"[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].unicode()))
|
|
{
|
|
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_QUERYNOTICE,KVI_OUT_QUERYNOTICECRYPTED,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_QUERYNOTICE,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_QUERYNOTICE,"*\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].unicode()))
|
|
{
|
|
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 QUITS , 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_QUIET))
|
|
{
|
|
old->output(KVI_OUT_QUERYTRACE,
|
|
__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(),¶ms);
|
|
} else {
|
|
chan->output(KVI_OUT_CHANMODE,__tr2qs("%Q [%Q@%Q] has set channel mode %s"),
|
|
&nickBuffer,&szUser,&hostBuffer,modefl.ptr());
|
|
}
|
|
}
|
|
}
|