summaryrefslogtreecommitdiffstats
path: root/src/kvirc/sparser/kvi_sp_numeric.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kvirc/sparser/kvi_sp_numeric.cpp')
-rw-r--r--src/kvirc/sparser/kvi_sp_numeric.cpp2003
1 files changed, 2003 insertions, 0 deletions
diff --git a/src/kvirc/sparser/kvi_sp_numeric.cpp b/src/kvirc/sparser/kvi_sp_numeric.cpp
new file mode 100644
index 0000000..a4481e8
--- /dev/null
+++ b/src/kvirc/sparser/kvi_sp_numeric.cpp
@@ -0,0 +1,2003 @@
+//=============================================================================
+//
+// File : kvi_sp_numeric.cpp
+// Creation date : Thu Aug 3 2000 01:30:45 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-2007 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_query.h"
+#include "kvi_out.h"
+#include "kvi_locale.h"
+#include "kvi_ircsocket.h"
+#include "kvi_options.h"
+#include "kvi_channel.h"
+#include "kvi_topicw.h"
+#include "kvi_ircuserdb.h"
+#include "kvi_defaults.h"
+#include "kvi_mirccntrl.h"
+#include "kvi_frame.h"
+#include "kvi_parameterlist.h"
+#include "kvi_app.h"
+#include "kvi_notifylist.h"
+#include "kvi_numeric.h"
+#include "kvi_ircconnection.h"
+#include "kvi_ircconnectionstatedata.h"
+#include "kvi_ircconnectionuserinfo.h"
+#include "kvi_ircconnectionserverinfo.h"
+#include "kvi_ircconnectionasyncwhoisdata.h"
+#include "kvi_ircconnectiontarget.h"
+#include "kvi_time.h"
+#include "kvi_lagmeter.h"
+#include "kvi_qcstring.h"
+
+#include <qpixmap.h>
+#include <qdatetime.h>
+#include <qtextcodec.h>
+#include <qregexp.h>
+
+#include "kvi_kvs_eventtriggers.h"
+#include "kvi_kvs_script.h"
+#include "kvi_kvs_variantlist.h"
+
+// #define IS_CHANNEL_TYPE_FLAG(_str) ((*(_str) == '#') || (*(_str) == '&') || (*(_str) == '!'))
+#define IS_CHANNEL_TYPE_FLAG(_qchar) (msg->connection()->serverInfo()->supportedChannelTypes().find(_qchar) != -1)
+#define IS_USER_MODE_PREFIX(_qchar) (msg->connection()->serverInfo()->supportedModePrefixes().find(_qchar) != -1)
+
+// Numeric message handlers
+
+// FIXME: #warning "IN ALL OUTPUT ADD ESCAPE SEQUENCES!!!!"
+// FIXME: #warning "parseErrorUnknownModeChar() for modes e and I , parseErrorUnknownCommand for WATCH"
+
+void KviServerParser::parseNumeric001(KviIrcMessage *msg)
+{
+ // 001: RPL_WELCOME
+ // :prefix 001 target :Welcome to the Internet Relay Network <usermask>
+ // FIXME: #warning "SET THE USERMASK FROM SERVER"
+ QString szText = msg->connection()->decodeText(msg->safeTrailing());
+ QRegExp rx( " ([^ ]+)!([^ ]+)@([^ ]+)$" );
+ if( rx.search(szText) != -1)
+ {
+ msg->connection()->userInfo()->setUnmaskedHostName(rx.cap(3));
+ msg->connection()->userInfo()->setNickName(rx.cap(1));
+ msg->connection()->userInfoReceived(rx.cap(2),rx.cap(3));
+ }
+ if(msg->connection()->context()->state() != KviIrcContext::Connected)
+ msg->connection()->loginComplete(msg->connection()->decodeText(msg->param(0)));
+ if(!msg->haltOutput())
+ msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,szText);
+}
+
+void KviServerParser::parseNumeric002(KviIrcMessage *msg)
+{
+ // 002: RPL_YOURHOST [I,E,U,D]
+ // :prefix 002 target :Your host is <server name>, running version <server version>
+ if(msg->connection()->context()->state() != KviIrcContext::Connected)
+ msg->connection()->loginComplete(msg->connection()->decodeText(msg->param(0)));
+ if(!msg->haltOutput())msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,msg->connection()->decodeText(msg->safeTrailing()));
+}
+
+void KviServerParser::parseNumeric003(KviIrcMessage *msg)
+{
+ // 003: RPL_CREATED [I,E,U,D]
+ // :prefix 003 target :This server was created <date>
+ if(msg->connection()->context()->state() != KviIrcContext::Connected)
+ msg->connection()->loginComplete(msg->connection()->decodeText(msg->param(0)));
+ if(!msg->haltOutput())msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,msg->connection()->decodeText(msg->safeTrailing()));
+}
+
+void KviServerParser::parseNumeric004(KviIrcMessage *msg)
+{
+ // 004: RPL_MYINFO [I,E,U,D]
+ // :prefix 004 target <server_name> <srv_version> <u_modes> <ch_modes>
+ if(msg->connection()->context()->state() != KviIrcContext::Connected)
+ msg->connection()->loginComplete(msg->connection()->decodeText(msg->param(0)));
+
+ int uParams = msg->paramCount();
+ int uModeParam = 3;
+
+ if(uParams < 2)uParams = 2;
+
+ KviStr version = msg->safeParam(2);
+ msg->connection()->serverInfo()->setServerVersion(msg->safeParam(2));
+
+ KviStr umodes;
+ // skip version number (great, thanks WEBMASTER INCORPORATED -_-)
+ do
+ {
+ umodes = msg->safeParam(uModeParam);
+ } while (((umodes.contains('.')) || (umodes.contains('-'))) && uModeParam++ < uParams);
+
+ KviStr chanmodes = msg->safeParam(uModeParam+1);
+
+ if(uModeParam > 3)
+ {
+ version.append(' ');
+ version.append(msg->safeParam(3));
+ }
+
+ if((umodes.occurences('o') != 1) || (chanmodes.occurences('o') != 1) ||
+ (chanmodes.occurences('b') != 1) || (chanmodes.occurences('v') != 1) ||
+ (chanmodes.occurences('t') != 1) || (chanmodes.occurences('n') != 1) ||
+ (chanmodes.contains('.')) || (chanmodes.contains('-')) || (chanmodes.contains('(')))
+ {
+ if(!_OUTPUT_QUIET)
+ {
+ msg->console()->output(KVI_OUT_SYSTEMWARNING,__tr2qs(
+ "One or more standard mode flags are missing in the server available modes.\n" \
+ "This is caused either by a non RFC1459-compliant IRC daemon or a broken server reply.\n" \
+ "Server umodes seem to be '%s' and channel modes seem to be '%s'.\n" \
+ "Ignoring this reply and assuming that the basic set of modes is available.\n" \
+ "If you have strange problems, try changing the server."),umodes.ptr(),chanmodes.ptr());
+ }
+ umodes = "oiws"; // standard support
+ chanmodes = "obtkmlvsn"; // standard support
+ }
+
+ if(KVI_OPTION_BOOL(KviOption_boolShowExtendedServerInfo) && (!msg->haltOutput()))
+ {
+ if(umodes.hasData())msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,__tr2qs("Available user modes:"));
+
+ const char * aux = umodes.ptr();
+ QString tmp;
+
+ while(*aux)
+ {
+ tmp = msg->connection()->serverInfo()->getUserModeDescription(*aux);
+ if(tmp.isEmpty())
+ {
+ QString tmp2 = __tr2qs(": Unknown user mode");
+ KviQString::sprintf(tmp,"%c: %Q",*aux,&tmp2);
+ }
+
+ msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,tmp);
+ aux++;
+ }
+
+ if(chanmodes.hasData())msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,__tr2qs("Available channel modes:"));
+
+ aux = chanmodes.ptr();
+
+ while(*aux)
+ {
+ KviQString::sprintf(tmp,"%c: %Q",*aux,&(msg->connection()->serverInfo()->getChannelModeDescription(*aux)));
+ msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,tmp);
+ aux++;
+ }
+ }
+
+ QString szServer = msg->connection()->decodeText(msg->safeParam(1));
+
+ msg->connection()->serverInfoReceived(szServer,umodes.ptr(),chanmodes.ptr());
+
+ // FIXME: #warning "TO ACTIVE ? OR TO CONSOLE ?"
+ if(!_OUTPUT_MUTE)
+ {
+ if(!msg->haltOutput())msg->console()->output(KVI_OUT_SERVERINFO,
+ __tr2qs("Server %Q version %S supporting user modes '%S' and channel modes '%S'"),
+ &szServer,&version,&umodes,&chanmodes);
+ }
+}
+
+void KviServerParser::parseNumeric005(KviIrcMessage *msg)
+{
+ // 005: RPL_PROTOCTL [D]
+ // :prefix 005 target <proto> <proto> .... :are available/supported on this server
+ // 005: RPL_BOUNCE [?]
+ // :prefix 005 target :Try server <server>, port <port>
+ // 005: RPL_ISUPPORT
+ if(msg->connection()->context()->state() != KviIrcContext::Connected)
+ msg->connection()->loginComplete(msg->connection()->decodeText(msg->param(0)));
+
+ bool bUhNames = false;
+ bool bNamesx = false;
+
+ unsigned int count = msg->paramCount();
+ if(count > 2)
+ {
+ count--;
+ for(unsigned int i = 1;i < count;i++)
+ {
+ const char * p = msg->param(i);
+ if(kvi_strEqualCIN("PREFIX=(",p,8))
+ {
+ p+=8;
+ const char * pModes = p;
+ while(*p && (*p != ')'))p++;
+ KviStr szModeFlags(pModes,p-pModes);
+ if(*p)p++;
+ KviStr szModePrefixes = p;
+ if(szModePrefixes.hasData() && (szModePrefixes.len() == szModeFlags.len()))
+ {
+ msg->connection()->serverInfo()->setSupportedModePrefixes(szModePrefixes.ptr(),szModeFlags.ptr());
+ }
+ } else if(kvi_strEqualCIN("CHANTYPES=",p,10))
+ {
+ p+=10;
+ KviStr tmp = p;
+ if(tmp.hasData())msg->connection()->serverInfo()->setSupportedChannelTypes(tmp.ptr());
+ } else if(kvi_strEqualCI("WATCH",p) || kvi_strEqualCIN("WATCH=",p,6))
+ {
+ msg->connection()->serverInfo()->setSupportsWatchList(true);
+ if((!_OUTPUT_MUTE) && (!msg->haltOutput()) && KVI_OPTION_BOOL(KviOption_boolShowExtendedServerInfo))
+ {
+ msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,__tr2qs("This server supports the WATCH notify list method, it will be used"));
+ }
+ } else if(kvi_strEqualCIN("TOPICLEN=",p,9))
+ {
+ p += 9;
+ QString tmp = p;
+ if(!tmp.isEmpty()) {
+ bool ok;
+ int len = tmp.toInt( &ok );
+ if(ok) msg->connection()->serverInfo()->setMaxTopicLen(len);
+ }
+ } else if(kvi_strEqualCIN("NETWORK=",p,8))
+ {
+ p += 8;
+ QString tmp = p;
+ if(!tmp.isEmpty())msg->console()->connection()->target()->setNetworkName(tmp);
+ if((!_OUTPUT_MUTE) && (!msg->haltOutput()) && KVI_OPTION_BOOL(KviOption_boolShowExtendedServerInfo))
+ {
+ msg->console()->output(KVI_OUT_SERVERINFO,__tr2qs("The current network is %Q"),&tmp);
+ }
+ } else if(kvi_strEqualCI("CODEPAGES",p))
+ {
+ msg->connection()->serverInfo()->setSupportsCodePages(true);
+ if((!_OUTPUT_MUTE) && (!msg->haltOutput()) && KVI_OPTION_BOOL(KviOption_boolShowExtendedServerInfo))
+ {
+ msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,__tr2qs("This server supports the CODEPAGE command, it will be used"));
+ }
+
+ //msg->connection()->sendFmtData("CODEPAGE %s",msg->console()->textCodec()->name());
+
+ } else if(kvi_strEqualCIN("CHANMODES=",p,10))
+ {
+ p+=10;
+ QString tmp = p;
+ msg->connection()->serverInfo()->setSupportedChannelModes(tmp);
+ }else if(kvi_strEqualCIN("MODES=",p,6))
+ {
+ p+=6;
+ QString tmp = p;
+ bool bok;
+ int num=tmp.toUInt(&bok);
+ if(bok)
+ msg->connection()->serverInfo()->setMaxModeChanges(num);
+ } else if(kvi_strEqualCIN("NAMESX",p,6))
+ {
+ p+=6;
+ bNamesx=true;
+ } else if(kvi_strEqualCIN("UHNAMES",p,7))
+ {
+ p+=7;
+ bUhNames=true;
+ }else if(kvi_strEqualCIN("CHARSET=",p,8))
+ {
+ p+=8;
+ QString tmp = p;
+ msg->connection()->serverInfo()->setSupportsCodePages(true);
+
+ if((!_OUTPUT_MUTE) && (!msg->haltOutput()) && KVI_OPTION_BOOL(KviOption_boolShowExtendedServerInfo))
+ {
+ msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,__tr2qs("This server supports the CODEPAGE command, it will be used"));
+ }
+
+ /*if( tmp.contains(msg->console()->textCodec()->name(),false) || tmp.contains("*",false) )
+ {
+ msg->connection()->sendFmtData("CODEPAGE %s",msg->console()->textCodec()->name());
+ }*/
+ }
+ }
+ if((!_OUTPUT_MUTE) && (!msg->haltOutput()))
+ {
+ const char * aux = msg->allParams();
+ while(*aux == ' ')aux++;
+ while(*aux && (*aux != ' '))aux++;
+ while(*aux == ' ')aux++;
+ if(*aux == ':')aux++;
+ if(!msg->haltOutput())msg->console()->output(KVI_OUT_SERVERINFO,__tr2qs("This server supports: %s"),msg->connection()->decodeText(aux).utf8().data());
+ if(bNamesx || bUhNames) {
+ msg->connection()->sendFmtData("PROTOCTL %s %s",bNamesx ? "NAMESX" : "", bUhNames ? "UHNAMES" : "");
+ }
+ }
+ } else {
+ QString inf = msg->connection()->decodeText(msg->safeTrailing());
+ if(!msg->haltOutput())msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,inf);
+ }
+ // } else {
+ // // RPL_BOUNCE prolly
+ // if(!msg->haltOutput())msg->console()->outputNoFmt(KVI_OUT_SERVERINFO,msg->safeTrailing());
+ // }
+}
+
+void KviServerParser::parseNumericMotd(KviIrcMessage *msg)
+{
+ // 372: RPL_MOTD [I,E,U,D]
+ // :prefix 372 target : - <motd>
+ // 377: RPL_MOTD2 [?]
+ // :prefix 377 target : - <motd>
+ // 378: RPL_MOTD3 [Austnet]
+ // :prefix 377 target : - <motd>
+ // 375: RPL_MOTDSTART [I,E,U,D]
+ // :prefix 375 target : - <server> Message of the Day -
+ // 372: RPL_ENDOFMOTD [I,E,U,D]
+ // :prefix 376 target :End of /MOTD command.
+ // FIXME: #warning "SKIP MOTD , MOTD IN A SEPARATE WINDOW , SILENT ENDOFMOTD , MOTD IN ACTIVE WINDOW"
+ if(!msg->haltOutput())msg->console()->outputNoFmt(KVI_OUT_MOTD,msg->connection()->decodeText(msg->safeTrailing()));
+
+ if(msg->numeric() == RPL_ENDOFMOTD)
+ {
+ msg->connection()->endOfMotdReceived();
+ }
+}
+
+void KviServerParser::parseNumericEndOfNames(KviIrcMessage *msg)
+{
+ // 366: RPL_ENDOFNAMES [I,E,U,D]
+ // :prefix 366 target <channel> :End of /NAMES list.
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ if(chan)
+ {
+ if(!chan->hasAllNames())
+ {
+ chan->setHasAllNames();
+ return;
+ }
+ }
+
+ if(!msg->haltOutput() && !_OUTPUT_MUTE)
+ {
+// FIXME: #warning "KVI_OUT_NAMES missing"
+ KviWindow * pOut = chan ? chan : KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_UNHANDLED,__tr2qs("End of NAMES for \r!c\r%Q\r"),&szChan);
+ }
+}
+
+void KviServerParser::parseNumeric020(KviIrcMessage *msg)
+{
+ // 020: RPL_CONNECTING
+ //:irc.dotsrc.org 020 * :Please wait while we process your connection.
+ QString szServer;
+ if(!msg->haltOutput())
+ {
+ QString szWText = msg->console()->decodeText(msg->safeTrailing());
+ msg->console()->output(
+ KVI_OUT_CONNECTION,"%c\r!s\r%s\r%c: %Q",KVI_TEXT_BOLD,
+ msg->safePrefix(),KVI_TEXT_BOLD,&szWText);
+ }
+}
+
+void KviServerParser::parseNumericNames(KviIrcMessage *msg)
+{
+ // 353: RPL_NAMREPLY [I,E,U,D]
+ // :prefix 353 target [=|*|@] <channel> :<space_separated_list_of_nicks>
+
+ // [=|*|@] is the type of the channel:
+ // = --> public * --> private @ --> secret
+ // ...but we ignore it
+ //QString szChan = msg->connection()->decodeText(msg->cSafeParam(2)->data()); // <-- KviQCString::data() is implicitly unsafe: it CAN return 0
+ QString szChan = msg->connection()->decodeText(msg->safeParam(2));
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ // and run to the first nickname
+ char * aux = msg->safeTrailingString().ptr();
+ while((*aux) && (*aux == ' '))aux++;
+ // now check if we have that channel
+
+ char * trailing = aux;
+
+ bool bHalt = msg->haltOutput();
+
+ if(chan)
+ {
+ bHalt = bHalt || (!chan->hasAllNames());
+
+ // K...time to parse a lot of data
+ chan->enableUserListUpdates(false);
+
+ int iPrevFlags = chan->myFlags();
+
+ KviIrcConnectionServerInfo * pServerInfo = msg->connection()->serverInfo();
+
+ while(*aux)
+ {
+ int iFlags = 0;
+ // @ = op (+o), + = voiced (+v), % = halfop (+h), - = userop (+u), ^ = protected (+a?), * = chan owner (+q), !, & = channel admin (+a?)
+ // ^ +a is a weird mode: it also breaks nicknames on some networks!
+ // not a valid first char(s) of nickname, must be a mode prefix
+
+ bool bContinue = true;
+
+ while(pServerInfo->isSupportedModePrefix((unsigned char)(*aux)))
+ {
+ // leading umode flag(s)
+ iFlags |= pServerInfo->modeFlagFromPrefixChar(*aux);
+ aux++;
+ }
+
+ char * begin = aux;
+ while(*aux && (*aux != ' '))aux++;
+ char save = *aux;
+ *aux = 0;
+ // NAMESX + UHNAMES support
+ KviIrcMask mask(msg->connection()->decodeText(begin));
+ // and make it join
+ if(!mask.nick().isEmpty())chan->join(mask.nick(),
+ mask.hasUser() ? mask.user() : QString::null,
+ mask.hasHost() ? mask.host() : QString::null,
+ iFlags);
+ *aux = ' ';
+ *aux = save;
+ // run to the next nick (or the end)
+ while((*aux) && (*aux == ' '))aux++;
+ }
+
+ if(iPrevFlags != chan->myFlags())chan->updateCaption();
+
+ chan->enableUserListUpdates(true);
+ // finished a block
+ }
+
+ // So it is a result of a /NAMES command or a local desync
+ // We handle it in a cool way.
+
+ if(!bHalt)
+ {
+ // FIXME: #warning "KVI_OUT_NAMES missing"
+ KviWindow * pOut = chan ? chan : KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ QString szTrailing = trailing ? msg->connection()->decodeText(trailing) : QString("");
+ pOut->output(KVI_OUT_UNHANDLED,__tr2qs("Names for \r!c\r%Q\r: %Q"),&szChan,&szTrailing);
+ }
+}
+
+void KviServerParser::parseNumericTopic(KviIrcMessage *msg)
+{
+ // 332: RPL_TOPIC [I,E,U,D]
+ // :prefix 332 target <channel> :<topic>
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ if(chan)
+ {
+ QString szTopic = chan->decodeText(msg->safeTrailing());
+
+ chan->topicWidget()->setTopic(szTopic);
+ chan->topicWidget()->setTopicSetBy(__tr2qs("(unknown)"));
+ if(KVI_OPTION_BOOL(KviOption_boolEchoNumericTopic))
+ {
+ if(!msg->haltOutput())
+ chan->output(KVI_OUT_TOPIC,__tr2qs("Channel topic is: %Q"),&szTopic);
+ }
+ } else {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+
+ QString szTopic = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->output(KVI_OUT_TOPIC,__tr2qs("Topic for \r!c\r%Q\r is: %Q"),
+ &szChan,&szTopic);
+ }
+
+}
+
+void KviServerParser::parseNumericNoTopic(KviIrcMessage *msg)
+{
+ // 331: RPL_NOTOPIC [I,E,U,D]
+ // :prefix 331 target <channel> :No topic is set
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ if(chan)
+ {
+ chan->topicWidget()->setTopic("");
+ if(KVI_OPTION_BOOL(KviOption_boolEchoNumericTopic))
+ {
+ if(!msg->haltOutput())
+ chan->outputNoFmt(KVI_OUT_TOPIC,__tr2qs("No channel topic is set"));
+ }
+ } else {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_TOPIC,__tr2qs("No topic is set for channel \r!c\r%Q\r"),
+ &szChan);
+ }
+}
+
+void KviServerParser::parseNumericTopicWhoTime(KviIrcMessage *msg)
+{
+ // 333: RPL_TOPICWHOTIME [e,U,D]
+ // :prefix 333 target <channel> <whoset> <time>
+
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+
+ KviStr tmp = msg->safeParam(3);
+ bool bOk = false;
+ unsigned long t = 0;
+ if(tmp.hasData())t = tmp.toUInt(&bOk);
+
+ QDateTime dt;
+ dt.setTime_t(t);
+
+ QString szDate = dt.toString();
+ QString szWho = msg->connection()->decodeText(msg->safeParam(2));
+ KviIrcMask who(szWho);
+ QString szDisplayableWho;
+ if( !(who.hasUser() && who.hasHost()) )
+ {
+ szDisplayableWho="\r!n\r"+szWho+"\r";
+ } else {
+ KviQString::sprintf(szDisplayableWho,"\r!n\r%Q\r!%Q@\r!h\r%Q\r",&(who.nick()),&(who.user()),&(who.host()));
+ }
+ if(chan)
+ {
+ chan->topicWidget()->setTopicSetBy(szWho);
+ if(bOk)chan->topicWidget()->setTopicSetAt(szDate);
+ if(KVI_OPTION_BOOL(KviOption_boolEchoNumericTopic))
+ {
+ if(!msg->haltOutput())
+ {
+ if(bOk)chan->output(KVI_OUT_TOPIC,__tr2qs("Topic was set by %Q on %Q"),&szDisplayableWho,&szDate);
+ else chan->output(KVI_OUT_TOPIC,__tr2qs("Topic was set by %Q"),&szDisplayableWho);
+ }
+ }
+ } else {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ if(bOk)
+ {
+ pOut->output(KVI_OUT_TOPIC,__tr2qs("Topic for \r!c\r%Q\r was set by %Q on %Q"),
+ &szChan,&szDisplayableWho,&szDate);
+ } else {
+ pOut->output(KVI_OUT_TOPIC,__tr2qs("Topic for \r!c\r%Q\r was set by %Q"),
+ &szChan,&szDisplayableWho);
+ }
+ }
+}
+
+void KviServerParser::parseNumericChannelModeIs(KviIrcMessage *msg)
+{
+ // 324: RPL_CHANNELMODEIS [I,E,U,D]
+ // :prefix 324 target <channel> +<chanmode>
+ QString szSource = msg->connection()->decodeText(msg->safePrefix());
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ KviStr modefl = msg->safeParam(2);
+ if(chan)parseChannelMode(szSource,"*","*",chan,modefl,msg,3);
+ else {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ if((!szChan.isEmpty()) && IS_CHANNEL_TYPE_FLAG(szChan[0]))
+ {
+ pOut->output(KVI_OUT_CHANMODE,__tr2qs("Channel mode for \r!c\r%Q\r is %s"),
+ &szChan,msg->safeParam(2));
+ } else {
+ pOut->output(KVI_OUT_MODE,__tr2qs("User mode for \r!n\r%Q\r is %s"),
+ &szChan,msg->safeParam(2));
+ }
+ }
+}
+
+void getDateTimeStringFromCharTimeT(QString &buffer,const char *time_t_string)
+{
+ KviStr tmp=time_t_string;
+ bool bOk=false;
+ unsigned int uTime = tmp.toUInt(&bOk);
+ if(bOk){
+ QDateTime dt;
+ dt.setTime_t(uTime);
+ buffer = dt.toString();
+ } else buffer = __tr2qs("(Unknown)");
+}
+
+#define PARSE_NUMERIC_ENDOFLIST(__funcname,__setGotIt,__didSendRequest,__setDone,__daicon,__szWhatQString) \
+ void KviServerParser::__funcname(KviIrcMessage *msg) \
+ { \
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1)); \
+ KviChannel * chan = msg->connection()->findChannel(szChan); \
+ if(chan) \
+ { \
+ chan->__setGotIt(); \
+ if(chan->__didSendRequest()) \
+ { \
+ chan->__setDone(); \
+ return; \
+ } \
+ } \
+ if(!msg->haltOutput()) \
+ { \
+ KviWindow * pOut = chan ? chan : KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ? \
+ msg->console()->activeWindow() : (KviWindow *)(msg->console()); \
+ pOut->output(__daicon,__tr2qs("End of channel %Q for \r!c\r%Q\r"),&(__szWhatQString),&szChan); \
+ } \
+ }
+
+PARSE_NUMERIC_ENDOFLIST(parseNumericEndOfBanList,setHasBanList,sentBanListRequest,setBanListDone,KVI_OUT_BAN,__tr2qs("ban list"))
+PARSE_NUMERIC_ENDOFLIST(parseNumericEndOfInviteList,setHasInviteList,sentInviteListRequest,setInviteListDone,KVI_OUT_INVITEEXCEPT,__tr2qs("invite list"))
+PARSE_NUMERIC_ENDOFLIST(parseNumericEndOfExceptList,setHasBanExceptionList,sentBanExceptionListRequest,setBanExceptionListDone,KVI_OUT_BANEXCEPT,__tr2qs("ban exception list"))
+
+#define PARSE_NUMERIC_LIST(__funcname,__modechar,__sentRequest,__ico,__szWhatQString) \
+ void KviServerParser::__funcname(KviIrcMessage *msg) \
+ { \
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1)); \
+ QString banmask = msg->connection()->decodeText(msg->safeParam(2)); \
+ QString bansetby = msg->connection()->decodeText(msg->safeParam(3)); \
+ QString bansetat; \
+ getDateTimeStringFromCharTimeT(bansetat,msg->safeParam(4)); \
+ if(bansetby.isEmpty())bansetby = __tr2qs("(Unknown)"); \
+ KviChannel * chan = msg->connection()->findChannel(szChan); \
+ if(chan) \
+ { \
+ chan->setMask(__modechar,banmask,true,bansetby,QString(msg->safeParam(4)).toUInt()); \
+ if(chan->__sentRequest())return; \
+ } \
+ if(!msg->haltOutput()) \
+ { \
+ KviWindow * pOut = chan ? chan : KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ? \
+ msg->console()->activeWindow() : (KviWindow *)(msg->console()); \
+ pOut->output(__ico,__tr2qs("%Q for \r!c\r%Q\r: \r!m-%c\r%Q\r (set by %Q on %Q)"), \
+ &(__szWhatQString),&szChan,__modechar,&banmask,&bansetby,&bansetat); \
+ } \
+ }
+
+// 367: RPL_BANLIST [I,E,U,D]
+// :prefix 367 target <channel> <banmask> [bansetby] [bansetat]
+PARSE_NUMERIC_LIST(parseNumericBanList,'b',sentBanListRequest,KVI_OUT_BAN,__tr2qs("Ban listing"))
+// 346: RPL_INVITELIST [I,E,U,D]
+// :prefix 346 target <channel> <invitemask> [invitesetby] [invitesetat]
+PARSE_NUMERIC_LIST(parseNumericInviteList,'I',sentInviteListRequest,KVI_OUT_INVITEEXCEPT,__tr2qs("Invite listing"))
+// 346: RPL_EXCEPTLIST [I,E,U,D]
+// :prefix 346 target <channel> <banmask> [bansetby] [bansetat]
+PARSE_NUMERIC_LIST(parseNumericExceptList,'e',sentBanExceptionListRequest,KVI_OUT_BANEXCEPT,__tr2qs("Ban exception listing"));
+
+
+void KviServerParser::parseNumericWhoReply(KviIrcMessage *msg)
+{
+ // 352: RPL_WHOREPLY [I,E,U,D]
+ // :prefix 352 target <chan> <usr> <hst> <srv> <nck> <stat> :<hops> <real>
+
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ QString szUser = msg->connection()->decodeText(msg->safeParam(2));
+ QString szHost = msg->connection()->decodeText(msg->safeParam(3));
+ QString szServ = msg->connection()->decodeText(msg->safeParam(4));
+ QString szNick = msg->connection()->decodeText(msg->safeParam(5));
+ QString szFlag = msg->connection()->decodeText(msg->safeParam(6));
+ bool bAway = szFlag.find('G') != -1;
+
+ KviStr trailing = msg->safeTrailing();
+ KviStr hops = trailing.getToken(' ');
+ bool bHopsOk = false;
+ int iHops = hops.toInt(&bHopsOk);
+
+ QString szReal = msg->connection()->decodeText(trailing.ptr());
+
+ // Update the user entry
+ KviIrcUserDataBase * db = msg->connection()->userDataBase();
+ KviIrcUserEntry * e = db->find(szNick);
+ if(e)
+ {
+ if(bHopsOk)e->setHops(iHops);
+ e->setUser(szUser);
+ e->setHost(szHost);
+ e->setServer(szServ);
+ e->setRealName(szReal);
+ e->setAway(bAway);
+ KviQuery * q = msg->connection()->findQuery(szNick);
+ if(q) q->updateLabelText();
+ if(!e->avatar())
+ {
+ // FIXME: #warning "THE AVATAR SHOULD BE RESIZED TO MATCH THE MAX WIDTH/HEIGHT"
+ // maybe now we can match this user ?
+ msg->console()->checkDefaultAvatar(e,szNick,szUser,szHost);
+ }
+ }
+
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ if(chan)
+ {
+ if(!chan->hasWhoList())
+ {
+ // FIXME: #warning "IF VERBOSE && SHOW INTERNAL WHO REPLIES...."
+ return;
+ }
+ if(chan->sentSyncWhoRequest())
+ {
+ // FIXME: #warning "IF VERBOSE && SHOW INTERNAL WHO REPLIES...."
+ return;
+ }
+ }
+
+ // FIXME: #warning "SYNC OP/VOICE on channel!!!"
+
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = chan ? chan : KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+
+ QString szAway = bAway ? __tr2qs("Yes") : __tr2qs("No");
+
+ pOut->output(KVI_OUT_WHO,
+ __tr2qs("WHO entry for %c\r!n\r%Q\r%c [%Q@\r!h\r%Q\r]: %cChannel%c: \r!c\r%Q\r, %cServer%c: \r!s\r%Q\r, %cHops%c: %d, %cFlags%c: %Q, %cAway%c: %Q, %cReal name%c: %Q"),
+ KVI_TEXT_BOLD,&szNick, KVI_TEXT_BOLD,
+ &szUser,&szHost,KVI_TEXT_UNDERLINE,
+ KVI_TEXT_UNDERLINE,&szChan,KVI_TEXT_UNDERLINE,
+ KVI_TEXT_UNDERLINE,&szServ,KVI_TEXT_UNDERLINE,
+ KVI_TEXT_UNDERLINE,iHops, KVI_TEXT_UNDERLINE, KVI_TEXT_UNDERLINE,
+ &szFlag, KVI_TEXT_UNDERLINE, KVI_TEXT_UNDERLINE,
+ &szAway, KVI_TEXT_UNDERLINE,
+ KVI_TEXT_UNDERLINE, &szReal);
+ }
+
+
+}
+
+void KviServerParser::parseNumericEndOfWho(KviIrcMessage *msg)
+{
+ // 315: RPL_ENDOFWHO [I,E,U,D]
+ // :prefix 315 target <channel/nick> :End of /WHO List.
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ if(chan)
+ {
+ chan->userListView()->updateArea();
+ kvi_time_t tNow = kvi_unixTime();
+ msg->connection()->stateData()->setLastReceivedChannelWhoReply(tNow);
+ chan->setLastReceivedWhoReply(tNow);
+ if(msg->connection()->lagMeter())
+ {
+ KviStr tmp(KviStr::Format,"WHO %s",msg->safeParam(1));
+ msg->connection()->lagMeter()->lagCheckComplete(tmp.ptr());
+ }
+
+ if(!chan->hasWhoList())
+ {
+ // FIXME: #warning "IF VERBOSE && SHOW INTERNAL WHO REPLIES...."
+ chan->setHasWhoList();
+ return;
+ }
+
+ if(chan->sentSyncWhoRequest())
+ {
+ // FIXME: #warning "IF VERBOSE && SHOW INTERNAL WHO REPLIES...."
+ chan->clearSentSyncWhoRequest();
+ return;
+ }
+ }
+
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = chan ? chan : KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ QString whoTarget = msg->connection()->decodeText(msg->safeParam(1));
+ if(IS_CHANNEL_TYPE_FLAG(whoTarget[0]))
+ whoTarget.prepend("\r!c\r");
+ else
+ whoTarget.prepend("\r!n\r");
+ whoTarget.append("\r");
+ pOut->output(KVI_OUT_WHO,__tr2qs("End of WHO list for %Q"),&whoTarget);
+ }
+}
+
+void KviServerParser::parseLoginNicknameProblem(KviIrcMessage *msg)
+{
+ // ops...not logged in yet...
+ QString nextNick;
+ unsigned int uNickCnt;
+ switch(msg->connection()->stateData()->loginNickIndex())
+ {
+ case 0:
+ // used a server specific nickname
+ KVI_OPTION_STRING(KviOption_stringNickname1).stripWhiteSpace();
+ if(KVI_OPTION_STRING(KviOption_stringNickname1).isEmpty())
+ KVI_OPTION_STRING(KviOption_stringNickname1) = KVI_DEFAULT_NICKNAME1;
+ nextNick = KVI_OPTION_STRING(KviOption_stringNickname1);
+ uNickCnt = 1;
+ case 1:
+ // used the first nickname of the identity
+ KVI_OPTION_STRING(KviOption_stringNickname2).stripWhiteSpace();
+ if(KVI_OPTION_STRING(KviOption_stringNickname2).isEmpty())
+ KVI_OPTION_STRING(KviOption_stringNickname2) = KVI_DEFAULT_NICKNAME2;
+ nextNick = KVI_OPTION_STRING(KviOption_stringNickname2);
+ uNickCnt = 2;
+ break;
+ case 2:
+ // used the second nickname of the identity
+ KVI_OPTION_STRING(KviOption_stringNickname3).stripWhiteSpace();
+ if(KVI_OPTION_STRING(KviOption_stringNickname3).isEmpty())
+ KVI_OPTION_STRING(KviOption_stringNickname3) = KVI_DEFAULT_NICKNAME3;
+ nextNick = KVI_OPTION_STRING(KviOption_stringNickname3);
+ uNickCnt = 3;
+ break;
+ default:
+ {
+ // used all the nicknames of the identity
+ // fall back to a random string...
+ nextNick = msg->safeParam(1);
+ nextNick.stripWhiteSpace();
+ if(nextNick.isEmpty())nextNick = KVI_DEFAULT_NICKNAME1;
+ nextNick = nextNick.left(7);
+ QString num;
+ num.setNum(msg->connection()->stateData()->loginNickIndex());
+ nextNick.append(num);
+ uNickCnt = msg->connection()->stateData()->loginNickIndex() + 1;
+ }
+ break;
+ }
+
+ QString szOldNick = msg->connection()->userInfo()->nickName();
+ msg->console()->notifyListView()->nickChange(szOldNick,nextNick);
+
+ msg->connection()->userInfo()->setNickName(nextNick);
+ msg->connection()->stateData()->setLoginNickIndex(uNickCnt);
+
+ if(uNickCnt > 7)
+ {
+ msg->console()->output(KVI_OUT_NICKNAMEPROBLEM,
+ __tr2qs("Something really weird is happening: the server is refusing all the login nicknames..."));
+
+ if(msg->connection()->stateData()->loginNickIndex() > 10)
+ {
+ msg->console()->output(KVI_OUT_NICKNAMEPROBLEM,
+ __tr2qs("The server is refusing all the login nicknames: giving up, you must send the nickname manually"));
+ return;
+ }
+ }
+
+ if(!msg->haltOutput())
+ {
+ QString szActual = msg->connection()->decodeText(msg->safeParam(1));
+ QString szWText = msg->connection()->decodeText(msg->safeTrailing());
+ msg->console()->output(KVI_OUT_NICKNAMEPROBLEM,
+ __tr2qs("No way to login as '\r!n\r%Q\r' (%d: %Q), trying '%Q'..."),
+ &szActual,msg->numeric(),&szWText,&nextNick);
+ }
+
+ KviQCString d = msg->connection()->encodeText(nextNick);
+ msg->connection()->sendFmtData("NICK %s",d.data());
+}
+
+void KviServerParser::parseNumericUnavailResource(KviIrcMessage *msg)
+{
+ // 437: ERR_UNAVAILRESOURCE [I]
+ // :prefix 437 <target> <nick/channel> :Nick/Channel is temporairly unavailable
+ if(!(msg->console()->isConnected()))
+ {
+ parseLoginNicknameProblem(msg);
+ } else {
+ // already connected... just say that we have problems
+ if(!msg->haltOutput())
+ {
+ QString szNk = msg->connection()->decodeText(msg->safeParam(1));
+ QString szWText = msg->connection()->decodeText(msg->safeTrailing());
+ msg->console()->output(KVI_OUT_NICKNAMEPROBLEM,
+ "\r!n\r%Q\r: %Q",&szNk,&szWText);
+ }
+ }
+}
+
+void KviServerParser::parseNumericCantJoinChannel(KviIrcMessage *msg)
+{
+ // 471: ERR_CHANNELISFULL [I,E,U,D]
+ // 473: ERR_INVITEONLYCHAN [I,E,U,D]
+ // 474: ERR_BANNEDFROMCHAN [I,E,U,D]
+ // 475: ERR_BADCHANNELKEY [I,E,U,D]
+ // :prefix 47* <target> <channel> :Can't join channel (+l/i/b/k)
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->connection()->findChannel(msg->safeParam(1)));
+ if(!pOut)pOut = (KviWindow *)(msg->console());
+ QString szChannel = msg->connection()->decodeText(msg->safeParam(1));
+ QString szWText = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->output(KVI_OUT_JOINERROR,
+ "\r!c\r%Q\r: %Q",&szChannel,&szWText);
+ }
+}
+
+// Keep the source ordered: this should be named "parseOtherChannelError"
+
+void KviServerParser::otherChannelError(KviIrcMessage *msg)
+{
+ // 482: ERR_CHANOPRIVSNEEDED
+ // 467: ERR_KEYSET
+ // 472: ERR_UNKNOWNMODE
+ // :prefix 4?? <target> <channel> :error text
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->connection()->findChannel(msg->safeParam(1)));
+ if(!pOut)pOut = (KviWindow *)(msg->console());
+ QString szChannel = msg->connection()->decodeText(msg->safeParam(1));
+ QString szWText = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->output(KVI_OUT_GENERICERROR,
+ "\r!c\r%Q\r: %Q",&szChannel,&szWText);
+ }
+}
+
+void KviServerParser::parseCommandSyntaxHelp(KviIrcMessage *msg)
+{
+ // 704 RPL_COMMANDSYNTAX
+ // :prefix 704 <target> <command> :text
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szCommand = msg->connection()->decodeText(msg->safeParam(1));
+ QString szWText = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->output(KVI_OUT_HELP,
+ __tr2qs("Command syntax %Q: %Q"),&szCommand,&szWText); // Pragma: wheee..... that should be in english :D
+ }
+}
+
+void KviServerParser::parseCommandHelp(KviIrcMessage *msg)
+{
+ // 705 RPL_COMMANDHELP
+ // :prefix 705 <target> <command> :text
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szCommand = msg->connection()->decodeText(msg->safeParam(1));
+ QString szWText = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->outputNoFmt(KVI_OUT_HELP,szWText);
+ }
+}
+
+void KviServerParser::parseChannelHelp(KviIrcMessage *msg)
+{
+ // 477 RPL_CHANNELHELP (freenode)
+ // :prefix 477 <target> <channel> :text
+ if(!msg->haltOutput())
+ {
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ QString szText = msg->connection()->decodeText(msg->safeTrailing());
+ KviWindow * pOut = msg->connection()->findChannel(szChan);
+ if(pOut)
+ {
+ pOut->output(KVI_OUT_HELP,__tr2qs("Tip: %Q"),&szText);
+ } else {
+ pOut = (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_HELP,__tr2qs("Tip for %Q: %Q"),&szChan,&szText);
+ }
+
+ }
+}
+
+
+void KviServerParser::parseCommandEndOfHelp(KviIrcMessage *msg)
+{
+ // 704 RPL_COMMANDSYNTAX
+ // 705 RPL_COMMANDHELP
+ // :prefix 706 <target> <command> :End of /HELP.
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szCommand = msg->connection()->decodeText(msg->safeParam(1));
+ pOut->output(KVI_OUT_HELP,
+ __tr2qs("End of help about %Q"),&szCommand);
+ }
+}
+
+void KviServerParser::parseNumericNicknameProblem(KviIrcMessage *msg)
+{
+ // 433: ERR_NICKNAMEINUSE [I,E,U,D]
+ // :prefix 433 <target> <nick> :Nickname is already in use.
+ // 432: ERR_ERRONEUSNICKNAME [I,E,U,D]
+ // :prefix 433 <target> <nick> :Erroneous nickname
+
+ if(!(msg->console()->isConnected()))
+ {
+ parseLoginNicknameProblem(msg);
+ } else {
+ // already connected... just say that we have problems
+ if(!msg->haltOutput())
+ {
+ QString szNk = msg->connection()->decodeText(msg->safeParam(1));
+ QString szWText = msg->connection()->decodeText(msg->safeTrailing());
+ msg->console()->output(KVI_OUT_NICKNAMEPROBLEM,
+ "\r!n\r%Q\r: %Q",&szNk,&szWText);
+ }
+ }
+}
+
+void KviServerParser::parseNumericWhoisAway(KviIrcMessage * msg)
+{
+// FIXME: #warning "Need an icon here too: sth like KVI_OUT_WHOISSERVER, but with 'A' letter"
+ msg->connection()->stateData()->setLastReceivedWhoisReply(kvi_unixTime());
+
+ QString szNk = msg->connection()->decodeText(msg->safeParam(1));
+ KviIrcUserDataBase * db = msg->connection()->userDataBase();
+ KviIrcUserEntry * e = db->find(szNk);
+ if(e)e->setAway(true);
+ KviQuery * q = msg->connection()->findQuery(szNk);
+ if(q) q->updateLabelText();
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->connection()->findQuery(szNk));
+ QString szWText = pOut ? pOut->decodeText(msg->safeTrailing()) : msg->connection()->decodeText(msg->safeTrailing());
+
+ if(!pOut)pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_WHOISUSER,__tr2qs("%c\r!n\r%Q\r%c is away: %Q"),
+ KVI_TEXT_BOLD,&szNk,KVI_TEXT_BOLD,&szWText);
+ }
+}
+
+void KviServerParser::parseNumericWhoisUser(KviIrcMessage *msg)
+{
+ // 311: RPL_WHOISUSER [I,E,U,D]
+ // :prefix 311 <target> <nick> <user> <host> * :<real_name>
+ msg->connection()->stateData()->setLastReceivedWhoisReply(kvi_unixTime());
+
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+ QString szUser = msg->connection()->decodeText(msg->safeParam(2));
+ QString szHost = msg->connection()->decodeText(msg->safeParam(3));
+ QString szReal = msg->connection()->decodeText(msg->safeTrailing());
+ KviIrcUserDataBase * db = msg->connection()->userDataBase();
+ KviIrcUserEntry * e = db->find(szNick);
+ if(e)
+ {
+ e->setUser(szUser);
+ e->setHost(szHost);
+ e->setRealName(szReal);
+ if(e->gender()!=KviIrcUserEntry::Unknown) {
+ if(KviQString::equalCS(g_pActiveWindow->className(),QString("KviChannel")))
+ {
+ ((KviChannel*)g_pActiveWindow)->userListView()->updateArea();
+ }
+ }
+ KviQuery * q = msg->connection()->findQuery(szNick);
+ if(q) q->updateLabelText();
+ if(!e->avatar())
+ {
+ // FIXME: #warning "THE AVATAR SHOULD BE RESIZED TO MATCH THE MAX WIDTH/HEIGHT"
+ // maybe now we can match this user ?
+ msg->console()->checkDefaultAvatar(e,szNick,szUser,szHost);
+ }
+ }
+
+ KviAsyncWhoisInfo * i = msg->connection()->asyncWhoisData()->lookup(szNick);
+ if(i)
+ {
+ i->szNick = szNick;
+ i->szUser = szUser;
+ i->szHost = szHost;
+ i->szReal = szReal;
+ return;
+ }
+
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(
+ KVI_OUT_WHOISUSER,__tr2qs("%c\r!n\r%Q\r%c is %c\r!n\r%Q\r!%Q@\r!h\r%Q\r%c"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,KVI_TEXT_UNDERLINE,&szNick,
+ &szUser,&szHost,KVI_TEXT_UNDERLINE);
+
+ pOut->output(
+ KVI_OUT_WHOISUSER,__tr2qs("%c\r!n\r%Q\r%c's real name: %Q"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,&szReal);
+ }
+}
+
+void KviServerParser::parseNumericWhowasUser(KviIrcMessage * msg)
+{
+ // 314: RPL_WHOWASUSER [I,E,U,D]
+ // :prefix 314 <target> <nick> <user> <host> * :<real_name>
+
+ if(!msg->haltOutput())
+ {
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+ QString szUser = msg->connection()->decodeText(msg->safeParam(2));
+ QString szHost = msg->connection()->decodeText(msg->safeParam(3));
+ QString szReal = msg->connection()->decodeText(msg->safeTrailing());
+
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(
+ KVI_OUT_WHOISUSER,__tr2qs("%c\r!n\r%Q\r%c was %c\r!n\r%Q\r!%Q@\r!h\r%Q\r%c"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,KVI_TEXT_UNDERLINE,&szNick,
+ &szUser,&szHost,KVI_TEXT_UNDERLINE);
+ pOut->output(
+ KVI_OUT_WHOISUSER,__tr2qs("%c\r!n\r%Q\r%c's real name was: %Q"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,&szReal);
+ }
+}
+
+
+void KviServerParser::parseNumericWhoisChannels(KviIrcMessage *msg)
+{
+ // 319: RPL_WHOISCHANNELS [I,E,U,D]
+ // :prefix 319 <target> <nick> :<channel list>
+
+ msg->connection()->stateData()->setLastReceivedWhoisReply(kvi_unixTime());
+
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+ QString szChans = msg->connection()->decodeText(msg->safeTrailing());
+
+ KviAsyncWhoisInfo * i = msg->connection()->asyncWhoisData()->lookup(szNick);
+ if(i)
+ {
+ i->szChannels = szChans;
+ return;
+ }
+
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+
+ QStringList sl = QStringList::split(" ",szChans);
+ QString szChanList;
+
+ for(QStringList::Iterator it = sl.begin();it != sl.end();++it)
+ {
+ QString szCur = *it;
+ // deals with <flag>[#channel] and [##channel]
+ int len = szCur.length();
+ int i =0;
+ while(i < len)
+ {
+
+ if(IS_CHANNEL_TYPE_FLAG(szCur[i]) && (!IS_USER_MODE_PREFIX(szCur[i])))break;
+ i++;
+ }
+ if(i < len)
+ {
+ if(i > 0)
+ {
+ len = szCur.length() - i;
+ if(szChanList.length() > 0)szChanList.append(", ");
+ szChanList += szCur.left(i);
+ QString szR = szCur.right(len);
+ KviQString::appendFormatted(szChanList,"\r!c\r%Q\r",&szR);
+ } else {
+ if(szChanList.length() > 0)szChanList.append(", ");
+ KviQString::appendFormatted(szChanList,"\r!c\r%Q\r",&szCur);
+ }
+ } else {
+ // we dunno what is this.. just append
+ if(szChanList.length() > 0)szChanList.append(", ");
+ szChanList.append(szCur);
+ }
+ }
+
+ pOut->output(
+ KVI_OUT_WHOISCHANNELS,__tr2qs("%c\r!n\r%Q\r%c's channels: %Q"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,&szChanList);
+ }
+}
+
+void KviServerParser::parseNumericWhoisIdle(KviIrcMessage *msg)
+{
+ // 317: RPL_WHOISIDLE [I,E,U,D]
+ // :prefix 317 <target> <nick> <number> <number> :seconds idle, signon time
+
+ // FIXME: #warning "and NICK LINKS"
+ msg->connection()->stateData()->setLastReceivedWhoisReply(kvi_unixTime());
+
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+
+ KviAsyncWhoisInfo * i = msg->connection()->asyncWhoisData()->lookup(szNick);
+ if(i)
+ {
+ i->szIdle = msg->safeParam(2);
+ i->szSignon = msg->safeParam(3);
+ bool bOk = false;
+ i->szSignon.toUInt(&bOk);
+ if(!bOk)i->szSignon = "";
+ return;
+ }
+
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ KviStr idle = msg->safeParam(2); // shouldn't be encoded
+ KviStr sign = msg->safeParam(3); // shouldn't be encoded
+
+ bool bOk;
+ unsigned int uTime = idle.toUInt(&bOk);
+ if(!bOk)
+ {
+ UNRECOGNIZED_MESSAGE(msg,__tr2qs("Received a broken RPL_WHOISIDLE, can't evaluate the idle time"));
+ return;
+ }
+ unsigned int uDays = uTime / 86400;
+ uTime = uTime % 86400;
+ unsigned int uHours = uTime / 3600;
+ uTime = uTime % 3600;
+ unsigned int uMins = uTime / 60;
+ uTime = uTime % 60;
+ pOut->output(
+ KVI_OUT_WHOISIDLE,__tr2qs("%c\r!n\r%Q\r%c's idle time: %ud %uh %um %us"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,uDays,uHours,uMins,uTime);
+
+ uTime = sign.toUInt(&bOk);
+ if(bOk)
+ {
+ QDateTime dt;
+ dt.setTime_t((time_t)uTime);
+ QString tmp = dt.toString();
+ pOut->output(
+ KVI_OUT_WHOISIDLE,__tr2qs("%c\r!n\r%Q\r%c's signon time: %Q"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,&tmp);
+ }
+ }
+}
+
+void KviServerParser::parseNumericWhoisServer(KviIrcMessage *msg)
+{
+ // 312: RPL_WHOISSERVER [I,E,U,D] (sent also in response to WHOWAS)
+ // :prefix 312 <target> <nick> <server> :<server description / last whowas date>
+ msg->connection()->stateData()->setLastReceivedWhoisReply(kvi_unixTime());
+
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+ QString szServ = msg->connection()->decodeText(msg->safeParam(2));
+
+ KviIrcUserDataBase * db = msg->connection()->userDataBase();
+ KviIrcUserEntry * e = db->find(szNick);
+ if(e)e->setServer(szServ);
+ KviQuery * q = msg->connection()->findQuery(szNick);
+ if(q) q->updateLabelText();
+ KviAsyncWhoisInfo * i = msg->connection()->asyncWhoisData()->lookup(msg->safeParam(1));
+ if(i)
+ {
+ i->szServer = szServ;
+ return;
+ }
+
+ // FIXME: #warning "AWHOIS HERE.... and NICK LINKS"
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ QString szWText = pOut->decodeText(msg->safeTrailing());
+ pOut->output(
+ KVI_OUT_WHOISSERVER,__tr2qs("%c\r!n\r%Q\r%c's server: \r!s\r%Q\r - %Q"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,&szServ,&szWText);
+ }
+}
+
+void KviServerParser::parseNumericWhoisAuth(KviIrcMessage *msg)
+{
+ // :prefix RPL_WHOISAUTH <target> <nick> :is authed as
+ // actually seen only on Quakenet
+ msg->connection()->stateData()->setLastReceivedWhoisReply(kvi_unixTime());
+
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+ QString szAuth = msg->connection()->decodeText(msg->safeParam(2));
+
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(
+ KVI_OUT_WHOISOTHER,__tr2qs("%c\r!n\r%Q\r%c is authenticated as %Q"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,&szAuth);
+ }
+}
+
+void KviServerParser::parseNumericWhoisOther(KviIrcMessage *msg)
+{
+ // *: RPL_WHOIS* [?]
+ // :prefix * <target> <nick> :<description>
+ // used for RPL_WHOISCHANOP,RPL_WHOISADMIN,
+ // RPL_WHOISSADMIN,RPL_WHOISOPERATOR,RPL_WHOISREGNICK,RPL_WHOISSSL
+ // and all the other unrecognized codes that look really like a RPL_WHOIS*
+
+ msg->connection()->stateData()->setLastReceivedWhoisReply(kvi_unixTime());
+
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+ QString szOth = msg->connection()->decodeText(msg->safeTrailing());
+
+ KviAsyncWhoisInfo * i = msg->connection()->asyncWhoisData()->lookup(szNick);
+ if(i)
+ {
+ if(!(i->szServer.isEmpty()))i->szServer.append(',');
+ i->szServer.append(szOth);
+ return;
+ }
+
+ // FIXME: #warning "NICK LINKS"
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(
+ KVI_OUT_WHOISOTHER,__tr2qs("%c\r!n\r%Q\r%c's info: %Q"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,&szOth);
+ }
+}
+
+// FIXME: #warning "WHOWAS MISSING"
+
+void KviServerParser::parseNumericEndOfWhois(KviIrcMessage *msg)
+{
+ // 318: RPL_ENDOFWHOIS [I,E,U,D]
+ // :prefix 318 <target> <nick> :End of /WHOIS list
+
+ msg->connection()->stateData()->setLastReceivedWhoisReply(0);
+
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+
+ KviAsyncWhoisInfo * i = msg->connection()->asyncWhoisData()->lookup(szNick);
+ if(i)
+ {
+ if(!g_pApp->windowExists(i->pWindow))i->pWindow = msg->console();
+
+ // that's the new KVS engine!
+ KviKvsVariantList vl;
+ vl.setAutoDelete(true);
+ vl.append(new KviKvsVariant(i->szNick));
+ vl.append(new KviKvsVariant(i->szUser));
+ vl.append(new KviKvsVariant(i->szHost));
+ vl.append(new KviKvsVariant(i->szReal));
+ vl.append(new KviKvsVariant(i->szServer));
+ vl.append(new KviKvsVariant(i->szIdle));
+ vl.append(new KviKvsVariant(i->szSignon));
+ vl.append(new KviKvsVariant(i->szChannels));
+ vl.append(new KviKvsVariant(QString(msg->safePrefix())));
+ vl.append(new KviKvsVariant(i->szSpecial));
+ vl.append(new KviKvsVariant(*(i->pMagic)));
+ i->pCallback->run(i->pWindow,&vl,0,KviKvsScript::PreserveParams);
+ msg->connection()->asyncWhoisData()->remove(i);
+ return;
+ }
+
+ // FIXME: #warning "NICK LINKS"
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ QString pref = msg->connection()->decodeText(msg->safePrefix());
+ pOut->output(
+ KVI_OUT_WHOISOTHER,__tr2qs("%c\r!n\r%Q\r%c WHOIS info from \r!s\r%Q\r"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,&pref);
+ }
+}
+
+
+void KviServerParser::parseNumericEndOfWhowas(KviIrcMessage *msg)
+{
+ // 369: RPL_ENDOFWHOWAS [I,E,U,D]
+ // :prefix 369 <target> <nick> :End of /WHOWAS list
+ if(!msg->haltOutput())
+ {
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ QString pref = msg->connection()->decodeText(msg->safePrefix());
+ pOut->output(
+ KVI_OUT_WHOISOTHER,__tr2qs("%c\r!n\r%Q\r%c WHOWAS info from \r!s\r%Q\r"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,&pref);
+ }
+}
+
+void KviServerParser::parseNumericNoSuchNick(KviIrcMessage *msg)
+{
+ // 401: ERR_NOSUCHNICK [I,E,U,D]
+ // 406: ERR_WASNOSUCHNICK [I,E,U,D]
+ // :prefix 401 <target> <nick> :No such nick/channel
+ // :prefix 406 <target> <nick> :There was no such nickname
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+
+ if(msg->numeric() == ERR_NOSUCHNICK)
+ {
+ KviAsyncWhoisInfo * i = msg->connection()->asyncWhoisData()->lookup(szNick);
+ if(i)
+ {
+ if(!g_pApp->windowExists(i->pWindow))i->pWindow = msg->console();
+ // that's the new KVS engine!
+ KviKvsVariantList vl;
+ vl.setAutoDelete(true);
+ vl.append(new KviKvsVariant(i->szNick));
+ vl.append(new KviKvsVariant());
+ vl.append(new KviKvsVariant());
+ vl.append(new KviKvsVariant());
+ vl.append(new KviKvsVariant());
+ vl.append(new KviKvsVariant());
+ vl.append(new KviKvsVariant());
+ vl.append(new KviKvsVariant());
+ vl.append(new KviKvsVariant());
+ vl.append(new KviKvsVariant());
+ vl.append(new KviKvsVariant(*(i->pMagic)));
+ i->pCallback->run(i->pWindow,&vl,0,KviKvsScript::PreserveParams);
+ msg->connection()->asyncWhoisData()->remove(i);
+ return;
+ }
+ }
+ // FIXME: #warning "KVI_OUT_NOSUCHNICKCHANNEL ?"
+ // FIXME: #warning "QUERIES SHOULD REPORT NO TARGET HERE! (?)"
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->connection()->findQuery(szNick));
+ if(!pOut)
+ {
+ pOut = (KviWindow *)(msg->console()->activeWindow());
+ }
+ //} else {
+ // ((KviQuery *)pOut)->removeTarget(msg->safeParam(1));
+ //}
+ QString szWText = pOut->decodeText(msg->safeTrailing());
+ pOut->output(KVI_OUT_NICKNAMEPROBLEM,"\r!n\r%Q\r: %Q",
+ &szNick,&szWText);
+ }
+}
+
+void KviServerParser::parseNumericCreationTime(KviIrcMessage *msg)
+{
+ // 329: RPL_CREATIONTIME
+ // :prefix 329 <target> <channel> <creation_time>
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ KviStr tmstr = msg->safeParam(2);
+ QDateTime dt;
+ dt.setTime_t((time_t)tmstr.toUInt());
+
+ if(!tmstr.isUnsignedNum())
+ {
+ UNRECOGNIZED_MESSAGE(msg,__tr2qs("Can't evaluate creation time"));
+ return;
+ }
+ QString szDate = dt.toString();
+ if(chan)
+ {
+ if(!msg->haltOutput())
+ {
+ chan->output(KVI_OUT_CREATIONTIME,__tr2qs("Channel was created at %Q"),&szDate);
+ }
+ } else {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_CREATIONTIME,__tr2qs("Channel \r!c\r%Q\r was created at %Q"),
+ &szChan,&szDate);
+ }
+}
+
+void KviServerParser::parseNumericIsOn(KviIrcMessage *msg)
+{
+ // 303: RPL_ISON
+ // :prefix 303 <target> :<ison replies>
+ if(msg->connection()->notifyListManager())
+ {
+ if(msg->connection()->notifyListManager()->handleIsOn(msg))return;
+ }
+ // not handled...output it
+
+ // FIXME: #warning "OUTPUT IT! (In a suitable way)"
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ QString szPrefix = msg->connection()->decodeText(msg->safePrefix());
+ QString szAllParms = msg->connection()->decodeText(msg->allParams());
+ pOut->output(KVI_OUT_UNHANDLED,
+ "[%Q][%s] %Q",&szPrefix,msg->command(),&szAllParms);
+ }
+}
+
+void KviServerParser::parseNumericUserhost(KviIrcMessage *msg)
+{
+ // 302: RPL_USERHOST
+ // :prefix 302 <target> :<userhost replies>
+ if(msg->connection()->notifyListManager())
+ {
+ if(msg->connection()->notifyListManager()->handleUserhost(msg))return;
+ }
+ // not handled...output it
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ QString szUser = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->output(KVI_OUT_WHOISUSER,__tr2qs("USERHOST info: %Q"),&szUser);
+ }
+}
+
+void KviServerParser::parseNumericListStart(KviIrcMessage *msg)
+{
+ // 321: RPL_LISTSTART [I,E,U,D]
+ // :prefix 321 <target> :Channel users name
+ if(msg->haltOutput())return; // stopped by raw
+
+ if(!(msg->console()->ircContext()->listWindow()))
+ {
+ // attempt to load the module...
+ msg->console()->ircContext()->createListWindow();
+ }
+
+ if(msg->console()->ircContext()->listWindow())
+ {
+ // module loaded
+ msg->console()->ircContext()->listWindow()->control(EXTERNAL_SERVER_DATA_PARSER_CONTROL_STARTOFDATA);
+ } else {
+ msg->console()->output(KVI_OUT_LIST,__tr2qs("Channel list begin: channel, users, topic"));
+ }
+}
+
+void KviServerParser::parseNumericList(KviIrcMessage *msg)
+{
+ // 322: RPL_LIST [I,E,U,D]
+ // :prefix 364 <target> <channel> <users> :<topic>
+ if(msg->haltOutput())return; // stopped by raw
+
+ if(!(msg->console()->ircContext()->listWindow()))
+ {
+ // attempt to load the module...
+ msg->console()->ircContext()->createListWindow();
+ if(msg->console()->ircContext()->listWindow())
+ {
+ msg->console()->ircContext()->listWindow()->control(EXTERNAL_SERVER_DATA_PARSER_CONTROL_STARTOFDATA);
+ }
+ }
+
+ if(msg->console()->ircContext()->listWindow())
+ {
+ // module loaded
+ msg->console()->ircContext()->listWindow()->processData(msg);
+ } else {
+ // ops...can't load the module...
+ QString szList = msg->connection()->decodeText(msg->allParams());
+ msg->console()->output(KVI_OUT_LIST,__tr2qs("List: %Q"),&szList);
+ }
+}
+
+void KviServerParser::parseNumericListEnd(KviIrcMessage *msg)
+{
+ // 323: RPL_LISTEND [I,E,U,D]
+ // :prefix 323 <target> :End of /LIST
+ if(msg->haltOutput())return; // stopped by raw
+
+ if(msg->console()->ircContext()->listWindow())
+ {
+ msg->console()->ircContext()->listWindow()->control(EXTERNAL_SERVER_DATA_PARSER_CONTROL_ENDOFDATA);
+ } else {
+ msg->console()->output(KVI_OUT_LIST,__tr2qs("End of LIST"));
+ }
+
+}
+
+void KviServerParser::parseNumericLinks(KviIrcMessage *msg)
+{
+ // 364: RPL_LINKS [I,E,U,D]
+ // :prefix 364 <target> <host> <parent> :<hops> <description>
+ if(!(msg->console()->ircContext()->linksWindow()))
+ {
+ // attempt to load the module...
+ msg->console()->ircContext()->createLinksWindow();
+ }
+
+ if(msg->console()->ircContext()->linksWindow())
+ {
+ // module loaded
+ msg->console()->ircContext()->linksWindow()->processData(msg);
+ } else {
+ // ops...can't load the module... or the event halted the window creation
+ if(!msg->haltOutput())
+ {
+ QString szList = msg->connection()->decodeText(msg->allParams());
+ msg->console()->output(KVI_OUT_LINKS,__tr2qs("Link: %Q"),&szList);
+ }
+ }
+}
+
+void KviServerParser::parseNumericEndOfLinks(KviIrcMessage *msg)
+{
+ // 365: RPL_ENDOFLINKS [I,E,U,D]
+ // :prefix 365 <target> :End of /LINKS
+ if(msg->console()->ircContext()->linksWindow())
+ {
+ msg->console()->ircContext()->linksWindow()->control(EXTERNAL_SERVER_DATA_PARSER_CONTROL_ENDOFDATA);
+ } else {
+ if(!msg->haltOutput())
+ {
+ msg->console()->output(KVI_OUT_LINKS,__tr2qs("End of LINKS"));
+ }
+ }
+}
+
+void KviServerParser::parseNumericBackFromAway(KviIrcMessage * msg)
+{
+ // 305: RPL_UNAWAY [I,E,U,D]
+ // :prefix 305 <target> :You are no longer away
+ bool bWasAway = msg->connection()->userInfo()->isAway();
+ QString szNickBeforeAway;
+ QString szWText = msg->connection()->decodeText(msg->safeTrailing());
+
+ if(bWasAway)szNickBeforeAway = msg->connection()->userInfo()->nickNameBeforeAway();
+ msg->connection()->changeAwayState(false);
+
+ // trigger the event
+ QString tmp;
+ KviQString::sprintf(tmp,"%u",bWasAway ? (unsigned int)(msg->connection()->userInfo()->awayTime()) : 0);
+ if(KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnMeBack,msg->console(),tmp,szWText))
+ msg->setHaltOutput();
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+
+ if(bWasAway)
+ {
+ int uTimeDiff = bWasAway ? (kvi_unixTime() - msg->connection()->userInfo()->awayTime()) : 0;
+ pOut->output(KVI_OUT_AWAY,__tr2qs("[Leaving away status after %ud %uh %um %us]: %Q"),
+ uTimeDiff / 86400,(uTimeDiff % 86400) / 3600,(uTimeDiff % 3600) / 60,uTimeDiff % 60,
+ &szWText);
+ } else {
+ pOut->output(KVI_OUT_AWAY,__tr2qs("[Leaving away status]: %Q"),&szWText);
+ }
+ }
+
+ if(KVI_OPTION_BOOL(KviOption_boolChangeNickAway) && bWasAway && (!(szNickBeforeAway.isEmpty())))
+ {
+ if(_OUTPUT_PARANOIC)
+ msg->console()->output(KVI_OUT_AWAY,__tr2qs("Restoring pre-away nickname (%Q)"),&szNickBeforeAway);
+ KviQCString szDat = msg->connection()->encodeText(szNickBeforeAway);
+ msg->connection()->sendFmtData("NICK %s",szDat.data());
+ }
+
+}
+
+void KviServerParser::parseNumericAway(KviIrcMessage * msg)
+{
+ // 306: RPL_NOWAWAY [I,E,U,D]
+ // :prefix 305 <target> :You're away man
+ msg->connection()->changeAwayState(true);
+ QString szWText = msg->connection()->decodeText(msg->safeTrailing());
+
+ if(KVS_TRIGGER_EVENT_1_HALTED(KviEvent_OnMeAway,msg->console(),szWText))msg->setHaltOutput();
+
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_AWAY,__tr2qs("[Entering away status]: %Q"),&szWText);
+ }
+
+ if(KVI_OPTION_BOOL(KviOption_boolChangeNickAway))
+ {
+ QString nick = msg->connection()->decodeText(msg->safeParam(0));
+ QString szNewNick;
+ if(KVI_OPTION_BOOL(KviOption_boolAutoGeneratedAwayNick))
+ {
+ if(nick.length() > 5)szNewNick = nick.left(5);
+ else szNewNick = nick;
+ szNewNick.append("AWAY");
+ } else {
+ szNewNick = KVI_OPTION_STRING(KviOption_stringCustomAwayNick);
+ szNewNick.replace("%nick%",nick);
+ }
+
+ if(_OUTPUT_PARANOIC)
+ msg->console()->output(KVI_OUT_AWAY,__tr2qs("Setting away nickname (%Q)"),&szNewNick);
+ KviQCString dat = msg->connection()->encodeText(szNewNick);
+ msg->connection()->sendFmtData("NICK %s",dat.data());
+ }
+}
+
+void KviServerParser::parseNumericWatch(KviIrcMessage *msg)
+{
+ // 600: RPL_LOGON
+ // :prefix 600 <target> <nick> <user> <host> <logintime> :logged online
+ // 601: RPL_LOGON
+ // :prefix 601 <target> <nick> <user> <host> <logintime> :logged offline
+ // 602: RPL_WATCHOFF
+ // :prefix 602 <target> <nick> <user> <host> <logintime> :stopped watching
+ // 604: PRL_NOWON
+ // :prefix 604 <target> <nick> <user> <host> <logintime> :is online
+ // 605: PRL_NOWOFF
+ // :prefix 605 <target> <nick> <user> <host> 0 :is offline
+
+ if(msg->connection()->notifyListManager())
+ {
+ if(msg->connection()->notifyListManager()->handleWatchReply(msg))return;
+ }
+ // not handled...output it
+
+// FIXME: #warning "OUTPUT IT! (In a suitable way) (And handle 602 , 603 , 606 and 607 gracefully)"
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_UNHANDLED,
+ "[%s][%s] %s",msg->prefix(),msg->command(),msg->allParams());
+ }
+}
+
+void KviServerParser::parseNumericStats(KviIrcMessage * msg)
+{
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ if(msg->paramCount() > 2)
+ {
+ KviStr szParms;
+ KviStr *p = msg->firstParam();
+ for(p = msg->nextParam();p;p = msg->nextParam())
+ {
+ if(szParms.hasData())szParms.append(' ');
+ szParms.append(*p);
+ }
+ pOut->outputNoFmt(KVI_OUT_STATS,msg->connection()->decodeText(szParms).utf8().data());
+ } else {
+ pOut->outputNoFmt(KVI_OUT_STATS,msg->connection()->decodeText(msg->safeTrailing()).utf8().data());
+ }
+ }
+}
+
+void KviServerParser::parseNumericServerAdminInfoTitle(KviIrcMessage * msg)
+{
+ //RPL_ADMINME 256
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ pOut->outputNoFmt(KVI_OUT_SERVERINFO,msg->connection()->decodeText(msg->safeTrailing()).utf8().data());
+ }
+}
+void KviServerParser::parseNumericServerAdminInfoServerName(KviIrcMessage * msg)
+{
+ //RPL_ADMINLOC1 257
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szInfo = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->output(KVI_OUT_SERVERINFO,__tr2qs("%c\r!s\r%s\r%c's server info: %s"),KVI_TEXT_BOLD,msg->prefix(),KVI_TEXT_BOLD,szInfo.utf8().data());
+ }
+}
+
+void KviServerParser::parseNumericServerAdminInfoAdminName(KviIrcMessage * msg)
+{
+ //RPL_ADMINLOC2 258
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szInfo = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->output(KVI_OUT_SERVERINFO,__tr2qs("%c\r!s\r%s\r%c's administrator is %s"),KVI_TEXT_BOLD,msg->prefix(),KVI_TEXT_BOLD,szInfo.utf8().data());
+ }
+}
+
+void KviServerParser::parseNumericServerAdminInfoAdminContact(KviIrcMessage * msg)
+{
+ //RPL_ADMINEMAIL 259
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szInfo = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->output(KVI_OUT_SERVERINFO,__tr2qs("%c\r!s\r%s\r%c's contact adress is %s"),KVI_TEXT_BOLD,msg->prefix(),KVI_TEXT_BOLD,szInfo.utf8().data());
+ }
+}
+
+void KviServerParser::parseNumericCommandSyntax(KviIrcMessage * msg)
+{
+ //RPL_COMMANDSYNTAX 334
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ pOut->outputNoFmt(KVI_OUT_STATS,msg->connection()->decodeText(msg->safeTrailing()));
+ }
+}
+
+void KviServerParser::parseNumericInviting(KviIrcMessage * msg)
+{
+ //RPL_INVITING 341
+ if(!msg->haltOutput())
+ {
+ QString szWho = msg->connection()->decodeText(msg->safeParam(0));
+ QString szTarget = msg->connection()->decodeText(msg->safeParam(1));
+ QString szChan = msg->connection()->decodeText(msg->safeParam(2));
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ if(chan)
+ {
+ chan->output(KVI_OUT_INVITE,__tr2qs("\r!n\r%Q\r invited %Q into channel %Q"),&szWho,&szTarget,&szChan);
+ } else {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_INVITE,__tr2qs("\r!n\r%Q\r invited %Q into channel %Q"),&szWho,&szTarget,&szChan);
+ }
+ }
+}
+
+void KviServerParser::parseNumericInfo(KviIrcMessage * msg)
+{
+ //RPL_INFO 371
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szInfo = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->outputNoFmt(KVI_OUT_SERVERINFO,szInfo);
+ }
+}
+
+void KviServerParser::parseNumericInfoStart(KviIrcMessage * msg)
+{
+ //RPL_INFOSTART 373
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_SERVERINFO,__tr2qs("%c\r!s\r%s\r%c's information:"),KVI_TEXT_BOLD,msg->prefix(),KVI_TEXT_BOLD);
+ }
+}
+
+void KviServerParser::parseNumericInfoEnd(KviIrcMessage * msg)
+{
+ //RPL_ENDOFINFO 374
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_SERVERINFO,__tr2qs("End of %c\r!s\r%s\r%c's information"),KVI_TEXT_BOLD,msg->prefix(),KVI_TEXT_BOLD);
+ }
+}
+
+void KviServerParser::parseNumericTime(KviIrcMessage * msg)
+{
+ //RPL_TIME 391
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szInfo = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->output(KVI_OUT_SERVERINFO,__tr2qs("%c\r!s\r%s\r%c's time is %Q"),KVI_TEXT_BOLD,msg->prefix(),KVI_TEXT_BOLD,&szInfo);
+ }
+}
+
+void KviServerParser::parseNumericNoSuchServer(KviIrcMessage * msg)
+{
+ //ERR_NOSUCHSERVER 402
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szWhat = msg->connection()->decodeText(msg->safeParam(1));
+ pOut->output(KVI_OUT_GENERICERROR,__tr2qs("%Q: no such server"),&szWhat);
+ }
+}
+
+void KviServerParser::parseNumericNoSuchChannel(KviIrcMessage * msg)
+{
+ // ERR_NOSUCHCHANNEL 403
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szWhat = msg->connection()->decodeText(msg->safeParam(1));
+ pOut->output(KVI_OUT_GENERICERROR,__tr2qs("%Q: no such channel"),&szWhat);
+ }
+}
+
+void KviServerParser::parseNumericCannotSendColor(KviIrcMessage * msg)
+{
+ // ERR_NOCOLORSONCHAN 408
+ if(!msg->haltOutput())
+ {
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ QString szInfo = msg->connection()->decodeText(msg->safeTrailing());
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ if(chan)
+ {
+ chan->output(KVI_OUT_GENERICERROR,__tr2qs("Cannot sent to channel: %Q"),&szInfo);
+ } else {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_GENERICERROR,__tr2qs("Cannot sent text to channel %Q: %Q"),&szChan,&szInfo);
+ }
+ }
+}
+
+void KviServerParser::parseNumericCannotSend(KviIrcMessage * msg)
+{
+ // ERR_CANNOTSENDTOCHAN 404
+ if(!msg->haltOutput())
+ {
+ QString szChan = msg->connection()->decodeText(msg->safeParam(1));
+ QString szInfo = msg->connection()->decodeText(msg->safeTrailing());
+ KviChannel * chan = msg->connection()->findChannel(szChan);
+ if(chan)
+ {
+ chan->output(KVI_OUT_GENERICERROR,__tr2qs("Cannot sent to channel"));
+ } else {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_GENERICERROR,__tr2qs("Cannot sent text to channel %Q"),&szChan);
+ }
+ }
+}
+
+
+void KviServerParser::parseNumericCodePageSet(KviIrcMessage *msg)
+{
+ // a nice extension for irc.wenet.ru
+ // 700: RPL_CODEPAGESET
+ // :prefix 700 target <encoding> :is now your translation scheme
+
+ QString encoding = msg->connection()->decodeText(msg->safeParam(1));
+ if(msg->connection()->serverInfo()->supportsCodePages())
+ {
+ if(encoding=="NONE") encoding="KOI8-R"; //RusNet default codepage
+ msg->console()->output(KVI_OUT_TEXTENCODING,__tr2qs("Your encoding is now %Q"),&encoding);
+ msg->console()->setTextEncoding(encoding);
+ msg->connection()->setEncoding(encoding);
+ } else {
+ QString szMe = msg->connection()->decodeText(msg->safeParam(0));
+ if( (szMe==msg->connection()->currentNickName() || szMe == "*" ) //fix for pre-login codepage message
+ && KviLocale::codecForName(encoding.utf8().data()))
+ {
+ msg->console()->output(KVI_OUT_TEXTENCODING,__tr2qs("Your encoding is now %Q"),&encoding);
+ msg->console()->setTextEncoding(encoding);
+ msg->connection()->setEncoding(encoding);
+ } else if(!msg->haltOutput()) // simply unhandled
+ {
+ QString szWText = msg->connection()->decodeText(msg->allParams());
+ msg->connection()->console()->output(KVI_OUT_UNHANDLED,
+ "[%s][%s] %Q",msg->prefix(),msg->command(),&szWText);
+ }
+ }
+}
+
+void KviServerParser::parseNumericCodePageScheme(KviIrcMessage *msg)
+{
+ // a nice extension for irc.wenet.ru
+ // 703: RPL_WHOISSCHEME
+ // :prefix 703 <mynick> <nick> <encoding> :translation scheme
+
+ msg->connection()->stateData()->setLastReceivedWhoisReply(kvi_unixTime());
+
+ if(msg->connection()->serverInfo()->supportsCodePages())
+ {
+ QString szNick = msg->connection()->decodeText(msg->safeParam(1));
+ QString szCodepage = msg->connection()->decodeText(msg->safeParam(2));
+
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolWhoisRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ QString szWText = pOut->decodeText(msg->safeTrailing());
+ pOut->output(
+ KVI_OUT_WHOISOTHER,__tr2qs("%c\r!n\r%Q\r%c's codepage is %Q: %Q"),KVI_TEXT_BOLD,
+ &szNick,KVI_TEXT_BOLD,&szCodepage,&szWText);
+ }
+ } else {
+ // simply unhandled
+ if(!msg->haltOutput())
+ {
+ QString szWText = msg->connection()->decodeText(msg->allParams());
+ msg->connection()->console()->output(KVI_OUT_UNHANDLED,
+ "[%s][%s] %Q",msg->prefix(),msg->command(),&szWText);
+ }
+ }
+}
+
+void KviServerParser::parseNumericUserMode(KviIrcMessage *msg)
+{
+ // 321: RPL_UMODEIS [I,E,U,D]
+ // :prefix 221 <target> <modeflags>
+ parseUserMode(msg,msg->safeParam(1));
+
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = KVI_OPTION_BOOL(KviOption_boolServerRepliesToActiveWindow) ?
+ msg->console()->activeWindow() : (KviWindow *)(msg->console());
+ pOut->output(KVI_OUT_MODE,__tr2qs("Your user mode is %s"),msg->safeParam(1));
+ }
+}
+
+void KviServerParser::parseNumericEndOfStats(KviIrcMessage *msg)
+{
+ if(!msg->haltOutput())
+ {
+ KviWindow * pOut = (KviWindow *)(msg->console());
+ QString szText = msg->connection()->decodeText(msg->safeTrailing());
+ pOut->outputNoFmt(KVI_OUT_STATS, szText);
+ }
+}