summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/irc
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitbcb704366cb5e333a626c18c308c7e0448a8e69f (patch)
treef0d6ab7d78ecdd9207cf46536376b44b91a1ca71 /kopete/protocols/irc
downloadtdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.tar.gz
tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kopete/protocols/irc')
-rw-r--r--kopete/protocols/irc/Makefile.am40
-rw-r--r--kopete/protocols/irc/icons/Makefile.am2
-rw-r--r--kopete/protocols/irc/icons/cr16-action-irc_away.pngbin0 -> 703 bytes
-rw-r--r--kopete/protocols/irc/icons/cr16-action-irc_channel.pngbin0 -> 937 bytes
-rw-r--r--kopete/protocols/irc/icons/cr16-action-irc_connecting.mngbin0 -> 3986 bytes
-rw-r--r--kopete/protocols/irc/icons/cr16-action-irc_normal.pngbin0 -> 996 bytes
-rw-r--r--kopete/protocols/irc/icons/cr16-action-irc_online.pngbin0 -> 812 bytes
-rw-r--r--kopete/protocols/irc/icons/cr16-action-irc_op.pngbin0 -> 651 bytes
-rw-r--r--kopete/protocols/irc/icons/cr16-action-irc_server.pngbin0 -> 996 bytes
-rw-r--r--kopete/protocols/irc/icons/cr16-action-irc_voice.pngbin0 -> 919 bytes
-rw-r--r--kopete/protocols/irc/icons/cr16-app-irc_protocol.pngbin0 -> 812 bytes
-rw-r--r--kopete/protocols/irc/icons/cr32-app-irc_protocol.pngbin0 -> 1778 bytes
-rw-r--r--kopete/protocols/irc/irc.protocol12
-rw-r--r--kopete/protocols/irc/ircaccount.cpp904
-rw-r--r--kopete/protocols/irc/ircaccount.h248
-rw-r--r--kopete/protocols/irc/ircaddcontactpage.cpp83
-rw-r--r--kopete/protocols/irc/ircaddcontactpage.h61
-rw-r--r--kopete/protocols/irc/ircchannelcontact.cpp749
-rw-r--r--kopete/protocols/irc/ircchannelcontact.h156
-rw-r--r--kopete/protocols/irc/ircchatui.rc10
-rw-r--r--kopete/protocols/irc/irccontact.cpp425
-rw-r--r--kopete/protocols/irc/irccontact.h153
-rw-r--r--kopete/protocols/irc/irccontactmanager.cpp297
-rw-r--r--kopete/protocols/irc/irccontactmanager.h117
-rw-r--r--kopete/protocols/irc/ircguiclient.cpp100
-rw-r--r--kopete/protocols/irc/ircguiclient.h42
-rw-r--r--kopete/protocols/irc/ircnetworks.xml1463
-rw-r--r--kopete/protocols/irc/ircprotocol.cpp1241
-rw-r--r--kopete/protocols/irc/ircprotocol.h228
-rw-r--r--kopete/protocols/irc/ircservercontact.cpp220
-rw-r--r--kopete/protocols/irc/ircservercontact.h80
-rw-r--r--kopete/protocols/irc/ircsignalhandler.cpp173
-rw-r--r--kopete/protocols/irc/ircsignalhandler.h334
-rw-r--r--kopete/protocols/irc/irctransferhandler.cpp183
-rw-r--r--kopete/protocols/irc/irctransferhandler.h65
-rw-r--r--kopete/protocols/irc/ircusercontact.cpp734
-rw-r--r--kopete/protocols/irc/ircusercontact.h146
-rw-r--r--kopete/protocols/irc/kcodecaction.cpp87
-rw-r--r--kopete/protocols/irc/kcodecaction.h47
-rw-r--r--kopete/protocols/irc/kopete_irc.desktop79
-rw-r--r--kopete/protocols/irc/ksparser.cpp265
-rw-r--r--kopete/protocols/irc/ksparser.h56
-rw-r--r--kopete/protocols/irc/libkirc/Makefile.am20
-rw-r--r--kopete/protocols/irc/libkirc/kircengine.cpp497
-rw-r--r--kopete/protocols/irc/libkirc/kircengine.h532
-rw-r--r--kopete/protocols/irc/libkirc/kircengine_commands.cpp312
-rw-r--r--kopete/protocols/irc/libkirc/kircengine_ctcp.cpp351
-rw-r--r--kopete/protocols/irc/libkirc/kircengine_numericreplies.cpp570
-rw-r--r--kopete/protocols/irc/libkirc/kircentity.cpp132
-rw-r--r--kopete/protocols/irc/libkirc/kircentity.h128
-rw-r--r--kopete/protocols/irc/libkirc/kircmessage.cpp370
-rw-r--r--kopete/protocols/irc/libkirc/kircmessage.h198
-rw-r--r--kopete/protocols/irc/libkirc/kircmessageredirector.cpp97
-rw-r--r--kopete/protocols/irc/libkirc/kircmessageredirector.h86
-rw-r--r--kopete/protocols/irc/libkirc/kirctransfer.cpp365
-rw-r--r--kopete/protocols/irc/libkirc/kirctransfer.h191
-rw-r--r--kopete/protocols/irc/libkirc/kirctransferhandler.cpp97
-rw-r--r--kopete/protocols/irc/libkirc/kirctransferhandler.h79
-rw-r--r--kopete/protocols/irc/libkirc/kirctransferserver.cpp154
-rw-r--r--kopete/protocols/irc/libkirc/kirctransferserver.h81
-rw-r--r--kopete/protocols/irc/libkirc/ksslsocket.cpp458
-rw-r--r--kopete/protocols/irc/libkirc/ksslsocket.h68
-rw-r--r--kopete/protocols/irc/ui/Makefile.am12
-rw-r--r--kopete/protocols/irc/ui/channellist.cpp346
-rw-r--r--kopete/protocols/irc/ui/channellist.h80
-rw-r--r--kopete/protocols/irc/ui/channellistdialog.cpp61
-rw-r--r--kopete/protocols/irc/ui/channellistdialog.h45
-rw-r--r--kopete/protocols/irc/ui/empty.cpp1
-rw-r--r--kopete/protocols/irc/ui/ircadd.ui163
-rw-r--r--kopete/protocols/irc/ui/irceditaccount.ui1022
-rw-r--r--kopete/protocols/irc/ui/irceditaccountwidget.cpp282
-rw-r--r--kopete/protocols/irc/ui/irceditaccountwidget.h60
-rw-r--r--kopete/protocols/irc/ui/networkconfig.ui382
-rw-r--r--kopete/protocols/irc/ui/networkconfig.ui.h26
74 files changed, 16066 insertions, 0 deletions
diff --git a/kopete/protocols/irc/Makefile.am b/kopete/protocols/irc/Makefile.am
new file mode 100644
index 00000000..7bd37813
--- /dev/null
+++ b/kopete/protocols/irc/Makefile.am
@@ -0,0 +1,40 @@
+METASOURCES = AUTO
+
+SUBDIRS = icons libkirc ui
+AM_CPPFLAGS = -I$(srcdir)/ui $(KOPETE_INCLUDES) \
+ -I./ui \
+ -I$(srcdir)/libkirc \
+ $(all_includes)
+kde_module_LTLIBRARIES = kopete_irc.la
+
+kopete_irc_la_SOURCES = \
+ ircaccount.cpp \
+ ircaddcontactpage.cpp \
+ ircchannelcontact.cpp \
+ irccontact.cpp \
+ ircguiclient.cpp \
+ ircprotocol.cpp \
+ ircservercontact.cpp \
+ ircsignalhandler.cpp \
+ irctransferhandler.cpp \
+ ircusercontact.cpp \
+ irccontactmanager.cpp \
+ kcodecaction.cpp \
+ ksparser.cpp
+
+kopete_irc_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+kopete_irc_la_LIBADD = ../../libkopete/libkopete.la \
+ ./ui/libkopeteircui.la \
+ ./libkirc/libkirc.la \
+ $(LIB_KIO)
+
+service_DATA = kopete_irc.desktop irc.protocol
+servicedir = $(kde_servicesdir)
+
+xmldata_DATA = ircnetworks.xml
+xmldatadir = $(kde_datadir)/kopete
+
+EXTRA_DIST = $(xmldata_DATA)
+
+mydatadir = $(kde_datadir)/kopete
+mydata_DATA = ircchatui.rc
diff --git a/kopete/protocols/irc/icons/Makefile.am b/kopete/protocols/irc/icons/Makefile.am
new file mode 100644
index 00000000..9143c6b4
--- /dev/null
+++ b/kopete/protocols/irc/icons/Makefile.am
@@ -0,0 +1,2 @@
+kopeteicondir = $(kde_datadir)/kopete/icons
+kopeteicon_ICON = AUTO
diff --git a/kopete/protocols/irc/icons/cr16-action-irc_away.png b/kopete/protocols/irc/icons/cr16-action-irc_away.png
new file mode 100644
index 00000000..d7572e1f
--- /dev/null
+++ b/kopete/protocols/irc/icons/cr16-action-irc_away.png
Binary files differ
diff --git a/kopete/protocols/irc/icons/cr16-action-irc_channel.png b/kopete/protocols/irc/icons/cr16-action-irc_channel.png
new file mode 100644
index 00000000..0353e7dc
--- /dev/null
+++ b/kopete/protocols/irc/icons/cr16-action-irc_channel.png
Binary files differ
diff --git a/kopete/protocols/irc/icons/cr16-action-irc_connecting.mng b/kopete/protocols/irc/icons/cr16-action-irc_connecting.mng
new file mode 100644
index 00000000..486102e4
--- /dev/null
+++ b/kopete/protocols/irc/icons/cr16-action-irc_connecting.mng
Binary files differ
diff --git a/kopete/protocols/irc/icons/cr16-action-irc_normal.png b/kopete/protocols/irc/icons/cr16-action-irc_normal.png
new file mode 100644
index 00000000..b7a3cc24
--- /dev/null
+++ b/kopete/protocols/irc/icons/cr16-action-irc_normal.png
Binary files differ
diff --git a/kopete/protocols/irc/icons/cr16-action-irc_online.png b/kopete/protocols/irc/icons/cr16-action-irc_online.png
new file mode 100644
index 00000000..c5678d1e
--- /dev/null
+++ b/kopete/protocols/irc/icons/cr16-action-irc_online.png
Binary files differ
diff --git a/kopete/protocols/irc/icons/cr16-action-irc_op.png b/kopete/protocols/irc/icons/cr16-action-irc_op.png
new file mode 100644
index 00000000..6b14cf14
--- /dev/null
+++ b/kopete/protocols/irc/icons/cr16-action-irc_op.png
Binary files differ
diff --git a/kopete/protocols/irc/icons/cr16-action-irc_server.png b/kopete/protocols/irc/icons/cr16-action-irc_server.png
new file mode 100644
index 00000000..b7a3cc24
--- /dev/null
+++ b/kopete/protocols/irc/icons/cr16-action-irc_server.png
Binary files differ
diff --git a/kopete/protocols/irc/icons/cr16-action-irc_voice.png b/kopete/protocols/irc/icons/cr16-action-irc_voice.png
new file mode 100644
index 00000000..6a9b5aaf
--- /dev/null
+++ b/kopete/protocols/irc/icons/cr16-action-irc_voice.png
Binary files differ
diff --git a/kopete/protocols/irc/icons/cr16-app-irc_protocol.png b/kopete/protocols/irc/icons/cr16-app-irc_protocol.png
new file mode 100644
index 00000000..c5678d1e
--- /dev/null
+++ b/kopete/protocols/irc/icons/cr16-app-irc_protocol.png
Binary files differ
diff --git a/kopete/protocols/irc/icons/cr32-app-irc_protocol.png b/kopete/protocols/irc/icons/cr32-app-irc_protocol.png
new file mode 100644
index 00000000..f2747b49
--- /dev/null
+++ b/kopete/protocols/irc/icons/cr32-app-irc_protocol.png
Binary files differ
diff --git a/kopete/protocols/irc/irc.protocol b/kopete/protocols/irc/irc.protocol
new file mode 100644
index 00000000..f57982bb
--- /dev/null
+++ b/kopete/protocols/irc/irc.protocol
@@ -0,0 +1,12 @@
+[Protocol]
+exec=kopete %u
+protocol=irc
+input=none
+output=none
+helper=true
+listing=
+reading=false
+writing=false
+makedir=false
+deleting=false
+Icon=irc_normal
diff --git a/kopete/protocols/irc/ircaccount.cpp b/kopete/protocols/irc/ircaccount.cpp
new file mode 100644
index 00000000..1a1bf75f
--- /dev/null
+++ b/kopete/protocols/irc/ircaccount.cpp
@@ -0,0 +1,904 @@
+/*
+ ircaccount.cpp - IRC Account
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+ Copyright (c) 2003-2004 by Jason Keirstead <jason@keirstead.org>
+ Copyright (c) 2003-2005 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "ircaccount.h"
+#include "irccontact.h"
+#include "irccontactmanager.h"
+#include "ircprotocol.h"
+
+#include "ircservercontact.h"
+#include "ircchannelcontact.h"
+#include "ircusercontact.h"
+
+#include "channellistdialog.h"
+
+#include "kircengine.h"
+
+#include "kopeteaccountmanager.h"
+#include "kopeteaway.h"
+#include "kopeteawayaction.h"
+#include "kopetecommandhandler.h"
+#include "kopetecontactlist.h"
+#include "kopetemetacontact.h"
+#include "kopeteuiglobal.h"
+#include "kopeteview.h"
+#include "kopetepassword.h"
+
+#include <kaction.h>
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcompletionbox.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kinputdialog.h>
+#include <klineedit.h>
+#include <klineeditdlg.h>
+#include <kmessagebox.h>
+#include <knotifyclient.h>
+#include <kpopupmenu.h>
+
+#include <qlayout.h>
+#include <qtimer.h>
+
+const QString IRCAccount::CONFIG_CODECMIB = QString::fromLatin1("Codec");
+const QString IRCAccount::CONFIG_NETWORKNAME = QString::fromLatin1("NetworkName");
+const QString IRCAccount::CONFIG_NICKNAME = QString::fromLatin1("NickName");
+const QString IRCAccount::CONFIG_USERNAME = QString::fromLatin1("UserName");
+const QString IRCAccount::CONFIG_REALNAME = QString::fromLatin1("RealName");
+
+IRCAccount::IRCAccount(IRCProtocol *protocol, const QString &accountId, const QString &autoChan, const QString& netName, const QString &nickName)
+ : Kopete::PasswordedAccount(protocol, accountId, 0, true), autoConnect( autoChan ), commandSource(0)
+{
+ m_manager = 0L;
+ m_channelList = 0L;
+ m_network = 0L;
+
+ triedAltNick = false;
+
+ m_contactManager = 0;
+ m_engine = new KIRC::Engine(this);
+
+ QMap< QString, QString> replies = customCtcpReplies();
+ for( QMap< QString, QString >::ConstIterator it = replies.begin(); it != replies.end(); ++it )
+ m_engine->addCustomCtcp( it.key(), it.data() );
+
+ QString version=i18n("Kopete IRC Plugin %1 [http://kopete.kde.org]").arg(kapp->aboutData()->version());
+ m_engine->setVersionString( version );
+
+ QObject::connect(m_engine, SIGNAL(successfullyChangedNick(const QString &, const QString &)),
+ this, SLOT(successfullyChangedNick(const QString &, const QString &)));
+
+ QObject::connect(m_engine, SIGNAL(incomingFailedServerPassword()),
+ this, SLOT(slotFailedServerPassword()));
+
+ QObject::connect(m_engine, SIGNAL(incomingNickInUse(const QString &)),
+ this, SLOT(slotNickInUseAlert( const QString &)) );
+
+ QObject::connect(m_engine, SIGNAL(incomingFailedNickOnLogin(const QString &)),
+ this, SLOT(slotNickInUse( const QString &)) );
+
+ QObject::connect(m_engine, SIGNAL(incomingJoinedChannel(const QString &, const QString &)),
+ this, SLOT(slotJoinedUnknownChannel(const QString &, const QString &)));
+
+ QObject::connect(m_engine, SIGNAL(incomingCtcpReply(const QString &, const QString &, const QString &)),
+ this, SLOT( slotNewCtcpReply(const QString&, const QString &, const QString &)));
+
+ QObject::connect(m_engine, SIGNAL(statusChanged(KIRC::Engine::Status)),
+ this, SLOT(engineStatusChanged(KIRC::Engine::Status)));
+
+ QObject::connect(m_engine, SIGNAL(incomingServerLoadTooHigh()),
+ this, SLOT(slotServerBusy()));
+
+ QObject::connect(m_engine, SIGNAL(incomingNoSuchNickname(const QString &)),
+ this, SLOT(slotNoSuchNickname(const QString &)));
+
+ mAwayAction = new Kopete::AwayAction ( i18n("Set Away"),
+ m_protocol->m_UserStatusAway.iconFor( this ), 0, this,
+ SLOT(slotGoAway( const QString & )), this );
+
+ currentHost = 0;
+
+ KConfigGroup *config = configGroup();
+
+ QString networkName = netName;
+ if (networkName.isNull())
+ networkName = config->readEntry(CONFIG_NETWORKNAME);
+
+ if (!nickName.isNull())
+ setNickName(nickName);
+ else
+ mNickName = config->readEntry(CONFIG_NICKNAME);
+
+ QString codecMib = config->readEntry(CONFIG_CODECMIB);
+ // int codecMib = config->readNumEntry(CONFIG_CODECMIB, UTF-8);
+
+ m_serverNotices = (MessageDestination)config->readNumEntry( "ServerNotices", ServerWindow );
+ m_serverMessages = (MessageDestination)config->readNumEntry( "ServerMessages", ServerWindow );
+ m_informationReplies = (MessageDestination)config->readNumEntry( "InformationReplies", ActiveWindow );
+ m_errorMessages = (MessageDestination)config->readNumEntry( "ErrorMessages", ActiveWindow );
+ autoShowServerWindow = config->readBoolEntry( "AutoShowServerWindow", false );
+
+ if( !codecMib.isEmpty() )
+ {
+ mCodec = QTextCodec::codecForMib( codecMib.toInt() );
+ m_engine->setDefaultCodec( mCodec );
+ }
+ else
+ mCodec = 0;
+
+ QString m_accountId = this->accountId();
+ if( networkName.isEmpty() && QRegExp( "[^#+&\\s]+@[\\w-\\.]+:\\d+" ).exactMatch( m_accountId ) )
+ {
+ kdDebug(14120) << "Creating account from " << m_accountId << endl;
+
+ mNickName = m_accountId.section('@',0,0);
+ QString serverInfo = m_accountId.section('@',1);
+ QString hostName = serverInfo.section(':',0,0);
+
+ for( QDictIterator<IRCNetwork> it( m_protocol->networks() ); it.current(); ++it )
+ {
+ IRCNetwork *net = it.current();
+ for( QValueList<IRCHost*>::iterator it2 = net->hosts.begin(); it2 != net->hosts.end(); ++it2 )
+ {
+ if( (*it2)->host == hostName )
+ {
+ setNetwork(net->name);
+ break;
+ }
+ }
+
+ if( !networkName.isEmpty() )
+ break;
+ }
+
+ if( networkName.isEmpty() )
+ {
+ /* Could not find this host. Add it to the networks structure */
+
+ m_network = new IRCNetwork;
+ m_network->name = i18n("Temporary Network - %1").arg( hostName );
+ m_network->description = i18n("Network imported from previous version of Kopete, or an IRC URI");
+
+ IRCHost *host = new IRCHost;
+ host->host = hostName;
+ host->port = serverInfo.section(':',1).toInt();
+ if( !password().cachedValue().isEmpty() )
+ host->password = password().cachedValue();
+ host->ssl = false;
+
+ m_network->hosts.append( host );
+ m_protocol->addNetwork( m_network );
+
+ config->writeEntry(CONFIG_NETWORKNAME, m_network->name);
+ config->writeEntry(CONFIG_NICKNAME, mNickName);
+ }
+ }
+ else if( !networkName.isEmpty() )
+ {
+ setNetwork(networkName);
+ }
+ else
+ {
+ kdError() << "No network name defined, and could not import network information from ID" << endl;
+ }
+
+ m_engine->setUserName(userName());
+ m_engine->setRealName(realName());
+
+ m_contactManager = new IRCContactManager(mNickName, this);
+ setMyself( m_contactManager->mySelf() );
+ setAccountLabel( QString::fromLatin1("%1@%2").arg(mNickName,networkName) );
+ m_myServer = m_contactManager->myServer();
+
+ m_joinChannelAction = new KAction ( i18n("Join Channel..."), QString::null, 0, this,
+ SLOT(slotJoinChannel()), this);
+ m_searchChannelAction = new KAction ( i18n("Search Channels..."), QString::null, 0, this,
+ SLOT(slotSearchChannels()), this);
+}
+
+IRCAccount::~IRCAccount()
+{
+ if (m_engine->isConnected())
+ m_engine->quit(i18n("Plugin Unloaded"), true);
+}
+
+void IRCAccount::slotNickInUse( const QString &nick )
+{
+ QString altNickName = altNick();
+ if( triedAltNick || altNickName.isEmpty() )
+ {
+ QString newNick = KInputDialog::getText(
+ i18n("IRC Plugin"),
+ i18n("The nickname %1 is already in use. Please enter an alternate nickname:").arg(nick),
+ nick);
+
+ if (newNick.isNull())
+ disconnect();
+ else
+ m_engine->nick(newNick);
+ }
+ else
+ {
+ triedAltNick = true;
+ m_engine->nick(altNickName);
+ }
+}
+
+void IRCAccount::slotNickInUseAlert( const QString &nick )
+{
+ KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n("The nickname %1 is already in use").arg(nick), i18n("IRC Plugin"));
+}
+
+void IRCAccount::setAltNick( const QString &altNick )
+{
+ configGroup()->writeEntry(QString::fromLatin1( "altNick" ), altNick);
+}
+
+const QString IRCAccount::altNick() const
+{
+ return configGroup()->readEntry(QString::fromLatin1("altNick"));
+}
+
+void IRCAccount::setAutoShowServerWindow( bool show )
+{
+ autoShowServerWindow = show;
+ configGroup()->writeEntry(QString::fromLatin1( "AutoShowServerWindow" ), autoShowServerWindow);
+}
+
+const QString IRCAccount::networkName() const
+{
+ if( m_network )
+ return m_network->name;
+ else
+ return i18n("Unknown");
+}
+
+void IRCAccount::setUserName( const QString &userName )
+{
+ m_engine->setUserName(userName);
+ configGroup()->writeEntry(CONFIG_USERNAME, userName);
+}
+
+const QString IRCAccount::userName() const
+{
+ return configGroup()->readEntry(CONFIG_USERNAME);
+}
+
+void IRCAccount::setRealName( const QString &userName )
+{
+ m_engine->setRealName(userName);
+ configGroup()->writeEntry(CONFIG_REALNAME, userName);
+}
+
+const QString IRCAccount::realName() const
+{
+ return configGroup()->readEntry(CONFIG_REALNAME);
+}
+
+void IRCAccount::setNetwork( const QString &network )
+{
+ IRCNetwork *net = m_protocol->networks()[ network ];
+ if( net )
+ {
+ m_network = net;
+ configGroup()->writeEntry(CONFIG_NETWORKNAME, network);
+ setAccountLabel(network);
+ }
+ else
+ {
+ KMessageBox::queuedMessageBox(
+ Kopete::UI::Global::mainWidget(), KMessageBox::Error,
+ i18n("<qt>The network associated with this account, <b>%1</b>, no longer exists. Please"
+ " ensure that the account has a valid network. The account will not be enabled until you do so.</qt>").arg(network),
+ i18n("Problem Loading %1").arg( accountId() ), 0 );
+ }
+}
+
+void IRCAccount::setNickName( const QString &nick )
+{
+ mNickName = nick;
+ configGroup()->writeEntry(CONFIG_NICKNAME, mNickName);
+
+ if( mySelf() )
+ mySelf()->setNickName( mNickName );
+}
+
+// FIXME: Possible null pointer usage here
+void IRCAccount::setCodec( QTextCodec *codec )
+{
+ mCodec = codec;
+ configGroup()->writeEntry(CONFIG_CODECMIB, codec->mibEnum());
+
+ if( mCodec )
+ m_engine->setDefaultCodec( mCodec );
+}
+
+QTextCodec *IRCAccount::codec() const
+{
+ return mCodec;
+}
+
+// FIXME: Move this to a dictionnary
+void IRCAccount::setDefaultPart( const QString &defaultPart )
+{
+ configGroup()->writeEntry( QString::fromLatin1( "defaultPart" ), defaultPart );
+}
+
+// FIXME: Move this to a dictionnary
+void IRCAccount::setDefaultQuit( const QString &defaultQuit )
+{
+ configGroup()->writeEntry( QString::fromLatin1( "defaultQuit" ), defaultQuit );
+}
+
+// FIXME: Move this to a dictionnary
+const QString IRCAccount::defaultPart() const
+{
+ QString partMsg = configGroup()->readEntry(QString::fromLatin1("defaultPart"));
+ if( partMsg.isEmpty() )
+ return QString::fromLatin1("Kopete %1 : http://kopete.kde.org").arg( kapp->aboutData()->version() );
+ return partMsg;
+}
+
+const QString IRCAccount::defaultQuit() const
+{
+ QString quitMsg = configGroup()->readEntry(QString::fromLatin1("defaultQuit"));
+ if( quitMsg.isEmpty() )
+ return QString::fromLatin1("Kopete %1 : http://kopete.kde.org").arg(kapp->aboutData()->version());
+ return quitMsg;
+}
+
+void IRCAccount::setCustomCtcpReplies( const QMap< QString, QString > &replies ) const
+{
+ QStringList val;
+ for( QMap< QString, QString >::ConstIterator it = replies.begin(); it != replies.end(); ++it )
+ {
+ m_engine->addCustomCtcp( it.key(), it.data() );
+ val.append( QString::fromLatin1("%1=%2").arg( it.key() ).arg( it.data() ) );
+ }
+
+ configGroup()->writeEntry( "CustomCtcp", val );
+}
+
+const QMap< QString, QString > IRCAccount::customCtcpReplies() const
+{
+ QMap< QString, QString > replies;
+ QStringList replyList;
+
+ replyList = configGroup()->readListEntry( "CustomCtcp" );
+
+ for( QStringList::Iterator it = replyList.begin(); it != replyList.end(); ++it )
+ replies[ (*it).section('=', 0, 0 ) ] = (*it).section('=', 1 );
+
+ return replies;
+}
+
+void IRCAccount::setConnectCommands( const QStringList &commands ) const
+{
+ configGroup()->writeEntry( "ConnectCommands", commands );
+}
+
+const QStringList IRCAccount::connectCommands() const
+{
+ return configGroup()->readListEntry( "ConnectCommands" );
+}
+
+void IRCAccount::setMessageDestinations( int serverNotices, int serverMessages,
+ int informationReplies, int errorMessages )
+{
+ KConfigGroup *config = configGroup();
+ config->writeEntry( "ServerNotices", serverNotices );
+ config->writeEntry( "ServerMessages", serverMessages );
+ config->writeEntry( "InformationReplies", informationReplies );
+ config->writeEntry( "ErrorMessages", errorMessages );
+
+ m_serverNotices = (MessageDestination)serverNotices;
+ m_serverMessages = (MessageDestination)serverMessages;
+ m_informationReplies = (MessageDestination)informationReplies;
+ m_errorMessages = (MessageDestination)errorMessages;
+}
+
+KActionMenu *IRCAccount::actionMenu()
+{
+ QString menuTitle = QString::fromLatin1( " %1 <%2> " ).arg( accountId() ).arg( myself()->onlineStatus().description() );
+
+ KActionMenu *mActionMenu = Kopete::Account::actionMenu();
+
+ m_joinChannelAction->setEnabled( isConnected() );
+ m_searchChannelAction->setEnabled( isConnected() );
+
+ mActionMenu->popupMenu()->insertSeparator();
+ mActionMenu->insert(m_joinChannelAction);
+ mActionMenu->insert(m_searchChannelAction);
+ mActionMenu->insert( new KAction ( i18n("Show Server Window"), QString::null, 0, this, SLOT(slotShowServerWindow()), mActionMenu ) );
+
+ if( m_engine->isConnected() && m_engine->useSSL() )
+ {
+ mActionMenu->insert( new KAction ( i18n("Show Security Information"), "", 0, m_engine,
+ SLOT(showInfoDialog()), mActionMenu ) );
+ }
+
+ return mActionMenu;
+}
+
+void IRCAccount::connectWithPassword(const QString &password)
+{
+ //TODO: honor the initial status
+
+ if( m_engine->isConnected() )
+ {
+ if( isAway() )
+ setAway( false );
+ }
+ else if( m_engine->isDisconnected() )
+ {
+ if( m_network )
+ {
+ QValueList<IRCHost*> &hosts = m_network->hosts;
+ if( hosts.count() == 0 )
+ {
+ KMessageBox::queuedMessageBox(
+ Kopete::UI::Global::mainWidget(), KMessageBox::Error,
+ i18n("<qt>The network associated with this account, <b>%1</b>, has no valid hosts. Please ensure that the account has a valid network.</qt>").arg(m_network->name),
+ i18n("Network is Empty"), 0 );
+ }
+ else if( currentHost == hosts.count() )
+ {
+ KMessageBox::queuedMessageBox(
+ Kopete::UI::Global::mainWidget(), KMessageBox::Error,
+ i18n("<qt>Kopete could not connect to any of the servers in the network associated with this account (<b>%1</b>). Please try again later.</qt>").arg(m_network->name),
+ i18n("Network is Unavailable"), 0 );
+
+ currentHost = 0;
+ }
+ else
+ {
+ // if prefer SSL is set, sort by SSL first
+ if (configGroup()->readBoolEntry("PreferSSL"))
+ {
+ typedef QValueList<IRCHost*> IRCHostList;
+ IRCHostList sslFirst;
+ IRCHostList::iterator it;
+ for ( it = hosts.begin(); it != hosts.end(); ++it )
+ {
+ if ( (*it)->ssl == true )
+ {
+ sslFirst.append( *it );
+ it = hosts.remove( it );
+ }
+ }
+ for ( it = hosts.begin(); it != hosts.end(); ++it )
+ sslFirst.append( *it );
+
+ hosts = sslFirst;
+ }
+
+ IRCHost *host = hosts[ currentHost++ ];
+ myServer()->appendMessage( i18n("Connecting to %1...").arg( host->host ) );
+ if( host->ssl )
+ myServer()->appendMessage( i18n("Using SSL") );
+
+ m_engine->setPassword(password);
+ m_engine->connectToServer( host->host, host->port, mNickName, host->ssl );
+ }
+ }
+ else
+ {
+ kdWarning() << "No network defined!" << endl;
+ }
+ }
+}
+
+void IRCAccount::engineStatusChanged(KIRC::Engine::Status newStatus)
+{
+ kdDebug(14120) << k_funcinfo << endl;
+
+ mySelf()->updateStatus();
+
+ switch (newStatus)
+ {
+ case KIRC::Engine::Idle:
+ // Do nothing.
+ break;
+ case KIRC::Engine::Connecting:
+ {
+ if( autoShowServerWindow )
+ myServer()->startChat();
+ break;
+ }
+ case KIRC::Engine::Authentifying:
+ break;
+ case KIRC::Engine::Connected:
+ {
+ //Reset the host so re-connection will start over at first server
+ currentHost = 0;
+ m_contactManager->addToNotifyList( m_engine->nickName() );
+
+ // HACK! See bug #85200 for details. Some servers still cannot accept commands
+ // after the 001 is sent, you need to wait until all the init junk is done.
+ // Unfortunatly, there is no way for us to know when it is done (it could be
+ // spewing out any number of replies), so just try delaying it
+ QTimer::singleShot( 250, this, SLOT( slotPerformOnConnectCommands() ) );
+ }
+ break;
+ case KIRC::Engine::Closing:
+ triedAltNick = false;
+// mySelf()->setOnlineStatus( m_protocol->m_UserStatusOffline );
+ m_contactManager->removeFromNotifyList( m_engine->nickName() );
+
+// if (m_contactManager && !autoConnect.isNull())
+// Kopete::AccountManager::self()->removeAccount( this );
+ break;
+ case KIRC::Engine::AuthentifyingFailed:
+ break;
+ case KIRC::Engine::Timeout:
+ //Try next server
+ connect();
+ break;
+ case KIRC::Engine::Disconnected:
+ break;
+ }
+}
+
+void IRCAccount::slotPerformOnConnectCommands()
+{
+ Kopete::ChatSession *manager = myServer()->manager(Kopete::Contact::CanCreate);
+ if (!manager)
+ return;
+
+ if (!autoConnect.isEmpty())
+ Kopete::CommandHandler::commandHandler()->processMessage( QString::fromLatin1("/join %1").arg(autoConnect), manager);
+
+ QStringList commands(connectCommands());
+ for (QStringList::Iterator it=commands.begin(); it != commands.end(); ++it)
+ Kopete::CommandHandler::commandHandler()->processMessage(*it, manager);
+}
+
+void IRCAccount::slotJoinedUnknownChannel(const QString &channel, const QString &nick)
+{
+ if ( nick.lower() == m_contactManager->mySelf()->nickName().lower() )
+ {
+ m_contactManager->findChannel(channel)->join();
+ }
+}
+
+void IRCAccount::disconnect()
+{
+ quit();
+}
+
+void IRCAccount::slotServerBusy()
+{
+ KMessageBox::queuedMessageBox(
+ Kopete::UI::Global::mainWidget(), KMessageBox::Error,
+ i18n("The IRC server is currently too busy to respond to this request."),
+ i18n("Server is Busy"), 0
+ );
+}
+
+void IRCAccount::slotSearchChannels()
+{
+ if( !m_channelList )
+ {
+ m_channelList = new ChannelListDialog( m_engine,
+ i18n("Channel List for %1").arg( m_engine->currentHost() ), this,
+ SLOT( slotJoinNamedChannel( const QString & ) ) );
+ }
+ else
+ m_channelList->clear();
+
+ m_channelList->show();
+}
+
+void IRCAccount::listChannels()
+{
+ slotSearchChannels();
+ m_channelList->search();
+}
+
+void IRCAccount::quit( const QString &quitMessage )
+{
+ kdDebug(14120) << "Quitting IRC: " << quitMessage << endl;
+
+ if( quitMessage.isNull() || quitMessage.isEmpty() )
+ m_engine->quit( defaultQuit() );
+ else
+ m_engine->quit( quitMessage );
+}
+
+void IRCAccount::setAway(bool isAway, const QString &awayMessage)
+{
+ kdDebug(14120) << k_funcinfo << isAway << " " << awayMessage << endl;
+ if(m_engine->isConnected())
+ {
+ static_cast<IRCUserContact *>( myself() )->setAway( isAway );
+ engine()->away(isAway, awayMessage);
+ }
+}
+
+/*
+ * Ask for server password, and reconnect
+ */
+void IRCAccount::slotFailedServerPassword()
+{
+ // JLN
+ password().setWrong();
+ connect();
+}
+void IRCAccount::slotGoAway( const QString &reason )
+{
+ setAway( true, reason );
+}
+
+void IRCAccount::slotShowServerWindow()
+{
+ m_myServer->startChat();
+}
+
+bool IRCAccount::isConnected()
+{
+// return ( myself()->onlineStatus().status() != Kopete::OnlineStatus::Offline );
+ return m_engine->isConnected();
+}
+
+void IRCAccount::setOnlineStatus( const Kopete::OnlineStatus& status , const QString &reason )
+{
+ if ( status.status() == Kopete::OnlineStatus::Online &&
+ myself()->onlineStatus().status() == Kopete::OnlineStatus::Offline )
+ connect();
+ else if (status.status() == Kopete::OnlineStatus::Online &&
+ myself()->onlineStatus().status() == Kopete::OnlineStatus::Away )
+ setAway( false );
+ else if ( status.status() == Kopete::OnlineStatus::Offline )
+ disconnect();
+ else if ( status.status() == Kopete::OnlineStatus::Away )
+ slotGoAway( reason );
+}
+
+
+void IRCAccount::successfullyChangedNick(const QString &oldnick, const QString &newnick)
+{
+ kdDebug(14120) << k_funcinfo << "Changing nick to " << newnick << endl;
+ mNickName = newnick;
+ mySelf()->setNickName( mNickName );
+ m_contactManager->removeFromNotifyList( oldnick );
+ m_contactManager->addToNotifyList( newnick );
+}
+
+bool IRCAccount::createContact( const QString &contactId, Kopete::MetaContact *m )
+{
+ kdDebug(14120) << k_funcinfo << contactManager() << endl;
+ IRCContact *c;
+
+ if( !m )
+ {//This should NEVER happen
+ m = new Kopete::MetaContact();
+ Kopete::ContactList::self()->addMetaContact(m);
+ }
+
+ if( contactId == mNickName )
+ {
+ KMessageBox::error( Kopete::UI::Global::mainWidget(),
+ i18n("\"You are not allowed to add yourself to your contact list."), i18n("IRC Plugin")
+ );
+
+ return false;
+ }
+ else if (contactId.startsWith(QString::fromLatin1("#")))
+ {
+ c = static_cast<IRCContact*>(contactManager()->findChannel(contactId, m));
+ }
+ else
+ {
+ m_contactManager->addToNotifyList( contactId );
+ c = static_cast<IRCContact*>(contactManager()->findUser(contactId, m));
+ }
+
+ if( c->metaContact() != m )
+ {//This should NEVER happen
+ Kopete::MetaContact *old = c->metaContact();
+ c->setMetaContact( m );
+ Kopete::ContactPtrList children = old->contacts();
+ if (children.isEmpty())
+ Kopete::ContactList::self()->removeMetaContact( old );
+ }
+ else if( c->metaContact()->isTemporary() )
+ m->setTemporary(false);
+
+ return true;
+}
+
+void IRCAccount::slotJoinNamedChannel(const QString &chan)
+{
+ contactManager()->findChannel(chan)->startChat();
+}
+
+void IRCAccount::setCurrentCommandSource( Kopete::ChatSession *session )
+{
+ commandSource = session;
+}
+
+Kopete::ChatSession *IRCAccount::currentCommandSource()
+{
+ return commandSource;
+}
+
+void IRCAccount::slotJoinChannel()
+{
+ if (!isConnected())
+ return;
+
+ QStringList chans = configGroup()->readListEntry( "Recent Channel list" );
+ //kdDebug(14120) << "Recent channel list from config: " << chans << endl;
+
+ KLineEditDlg dlg(
+ i18n("Please enter name of the channel you want to join:"),
+ QString::null,
+ Kopete::UI::Global::mainWidget()
+ );
+
+ KCompletion comp;
+ comp.insertItems( chans );
+
+ dlg.lineEdit()->setCompletionObject( &comp );
+ dlg.lineEdit()->setCompletionMode( KGlobalSettings::CompletionPopup );
+
+ while( true )
+ {
+ if( dlg.exec() != QDialog::Accepted )
+ break;
+
+ QString chan = dlg.text();
+ if( chan.isNull() )
+ break;
+
+ if( KIRC::Entity::isChannel( chan ) )
+ {
+ contactManager()->findChannel( chan )->startChat();
+
+ // push the joined channel to first in list
+ chans.remove( chan );
+ chans.prepend( chan );
+
+ configGroup()->writeEntry( "Recent Channel list", chans );
+ break;
+ }
+
+ KMessageBox::error( Kopete::UI::Global::mainWidget(),
+ i18n("\"%1\" is an invalid channel. Channels must start with '#', '!', '+', or '&'.").arg(chan),
+ i18n("IRC Plugin")
+ );
+ }
+}
+
+void IRCAccount::slotNewCtcpReply(const QString &type, const QString &/*target*/, const QString &messageReceived)
+{
+ appendMessage( i18n("CTCP %1 REPLY: %2").arg(type).arg(messageReceived), InfoReply );
+}
+
+void IRCAccount::slotNoSuchNickname( const QString &nick )
+{
+ if( KIRC::Entity::isChannel(nick) )
+ appendMessage( i18n("The channel \"%1\" does not exist").arg(nick), UnknownReply );
+ else
+ appendMessage( i18n("The nickname \"%1\" does not exist").arg(nick), UnknownReply );
+}
+
+void IRCAccount::appendMessage( const QString &message, MessageType type )
+{
+ // TODO: Impliment a UI where people can pick multiple destinations
+ // for a message type, and make codethis handle it
+
+ MessageDestination destination;
+
+ switch( type )
+ {
+ case ConnectReply:
+ destination = m_serverMessages;
+ break;
+ case InfoReply:
+ destination = m_informationReplies;
+ break;
+ case NoticeReply:
+ destination = m_serverNotices;
+ break;
+ case ErrorReply:
+ destination = m_errorMessages;
+ break;
+ case UnknownReply:
+ default:
+ destination = ActiveWindow;
+ break;
+ }
+
+ if( destination == ActiveWindow )
+ {
+ KopeteView *activeView = Kopete::ChatSessionManager::self()->activeView();
+ if( activeView && activeView->msgManager()->account() == this )
+ {
+ Kopete::ChatSession *manager = activeView->msgManager();
+ Kopete::Message msg( manager->myself(), manager->members(), message,
+ Kopete::Message::Internal, Kopete::Message::RichText, CHAT_VIEW );
+ activeView->appendMessage(msg);
+ }
+ }
+
+ if( destination == AnonymousWindow )
+ {
+ //TODO: Create an anonymous window??? What will this mean...
+ }
+
+ if( destination == ServerWindow )
+ {
+ myServer()->appendMessage(message);
+ }
+
+ if( destination == KNotify )
+ {
+ KNotifyClient::event(
+ Kopete::UI::Global::mainWidget()->winId(), QString::fromLatin1("irc_event"), message
+ );
+ }
+}
+
+IRCUserContact *IRCAccount::mySelf() const
+{
+ return static_cast<IRCUserContact *>( myself() );
+}
+
+IRCServerContact *IRCAccount::myServer() const
+{
+ return m_myServer;
+}
+
+IRCContact *IRCAccount::getContact(const QString &name, Kopete::MetaContact *metac)
+{
+ return getContact(m_engine->getEntity(name), metac);
+}
+
+IRCContact *IRCAccount::getContact(KIRC::EntityPtr entity, Kopete::MetaContact *metac)
+{
+ IRCContact *contact = 0;
+
+#ifdef __GNUC__
+ #warning Do the search code here.
+#endif
+
+ if (!contact)
+ {
+#ifdef __GNUC__
+ #warning Make a temporary meta contact if metac is null
+#endif
+ contact = new IRCContact(this, entity, metac);
+ m_contacts.append(contact);
+ }
+
+ QObject::connect(contact, SIGNAL(destroyed(IRCContact *)), SLOT(destroyed(IRCContact *)));
+ return contact;
+}
+
+void IRCAccount::destroyed(IRCContact *contact)
+{
+ m_contacts.remove(contact);
+}
+
+#include "ircaccount.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/protocols/irc/ircaccount.h b/kopete/protocols/irc/ircaccount.h
new file mode 100644
index 00000000..e5917360
--- /dev/null
+++ b/kopete/protocols/irc/ircaccount.h
@@ -0,0 +1,248 @@
+/*
+ ircaccount.h - IRC Account
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef IRCACCOUNT_H
+#define IRCACCOUNT_H
+
+#include "ircprotocol.h"
+
+#include "kircengine.h"
+
+#include "kopetepasswordedaccount.h"
+
+#include <kdialogbase.h>
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+class ChannelListDialog;
+
+class IRCContact;
+class IRCChannelContact;
+class IRCContactManager;
+class IRCServerContact;
+class IRCProtocol;
+class IRCUserContact;
+
+namespace Kopete
+{
+class AwayAction;
+class Contact;
+class Message;
+class ChatSession;
+class MetaContact;
+}
+
+class KAction;
+class KActionMenu;
+
+struct IRCHost
+{
+ QString host;
+ uint port;
+ QString password;
+ bool ssl;
+};
+
+struct IRCNetwork
+{
+ QString name;
+ QString description;
+ QValueList<IRCHost*> hosts;
+};
+
+class IRCAccount
+ : public Kopete::PasswordedAccount
+{
+ friend class IRCEditAccountWidget;
+ friend class IRCProtocolHandler;
+
+ Q_OBJECT
+
+public:
+ static const QString CONFIG_CODECMIB;
+ static const QString CONFIG_NETWORKNAME;
+ static const QString CONFIG_NICKNAME;
+ static const QString CONFIG_USERNAME;
+ static const QString CONFIG_REALNAME;
+
+ enum MessageType
+ {
+ ConnectReply = 1,
+ InfoReply = 2,
+ NoticeReply = 4,
+ ErrorReply = 8,
+ UnknownReply = 16,
+ Default = 32
+ };
+
+ enum MessageDestination
+ {
+ ActiveWindow = 1,
+ ServerWindow = 2,
+ AnonymousWindow = 3,
+ KNotify = 4,
+ Ignore = 5
+ };
+
+ IRCAccount(IRCProtocol *p, const QString &accountid, const QString &autoConnect = QString::null,
+ const QString& networkName = QString::null, const QString &nickName = QString::null);
+ virtual ~IRCAccount();
+
+ void setNickName( const QString & );
+
+ void setAutoShowServerWindow( bool show );
+
+ void setAltNick( const QString & );
+ const QString altNick() const;
+
+ void setUserName( const QString & );
+ const QString userName() const;
+
+ void setRealName( const QString & );
+ const QString realName() const;
+
+ const QStringList connectCommands() const;
+
+ void setConnectCommands( const QStringList & ) const;
+
+ void setDefaultPart( const QString & );
+
+ void setNetwork( const QString & );
+
+ void setDefaultQuit( const QString & );
+
+ void setCodec( QTextCodec *codec );
+
+ void setMessageDestinations( int serverNotices, int serverMessages,
+ int informationReplies, int errorMessages );
+
+ QTextCodec *codec() const;
+
+ const QString defaultPart() const;
+
+ const QString defaultQuit() const;
+
+ const QString networkName() const;
+
+ QMap< QString, QString > customCtcp() const;
+
+ void setCustomCtcpReplies( const QMap< QString, QString > &replys ) const;
+
+ const QMap<QString, QString> customCtcpReplies() const;
+
+ void setCurrentCommandSource( Kopete::ChatSession *session );
+
+ Kopete::ChatSession *currentCommandSource();
+
+ IRCContact *getContact(const QString &name, Kopete::MetaContact *metac=0);
+ IRCContact *getContact(KIRC::EntityPtr entity, Kopete::MetaContact *metac=0);
+
+public slots:
+
+ virtual KActionMenu *actionMenu();
+
+ virtual void setAway( bool isAway, const QString &awayMessage = QString::null );
+
+ virtual bool isConnected();
+
+ /** Reimplemented from Kopete::Account */
+ void setOnlineStatus( const Kopete::OnlineStatus& status , const QString &reason = QString::null);
+
+ // Returns the KIRC engine instance
+ KIRC::Engine *engine() const { return m_engine; }
+
+ // Returns the IRCProtocol instance for contacts
+ IRCProtocol *protocol() const { return m_protocol; }
+
+ IRCContactManager *contactManager() const { return m_contactManager; }
+
+ // Returns the Kopete::Contact of the user
+ IRCUserContact *mySelf() const;
+
+ // Returns the Kopete::Contact of the server of the user
+ IRCServerContact *myServer() const;
+
+ void successfullyChangedNick(const QString &, const QString &);
+
+ virtual void connectWithPassword( const QString & );
+ virtual void disconnect();
+
+ void quit( const QString &quitMessage = QString::null );
+
+ void listChannels();
+
+ void appendMessage( const QString &message, MessageType type = Default );
+
+protected:
+ virtual bool createContact( const QString &contactId, Kopete::MetaContact *parentContact ) ;
+
+private slots:
+ void engineStatusChanged(KIRC::Engine::Status newStatus);
+
+ void destroyed(IRCContact *contact);
+
+ void slotFailedServerPassword();
+ void slotGoAway( const QString &reason );
+ void slotJoinNamedChannel( const QString &channel );
+ void slotJoinChannel();
+ void slotShowServerWindow();
+ void slotNickInUse( const QString &nick );
+ void slotNickInUseAlert( const QString &nick );
+ void slotServerBusy();
+ void slotNoSuchNickname( const QString &nick );
+ void slotSearchChannels();
+ void slotNewCtcpReply(const QString &type, const QString &target, const QString &messageReceived);
+ void slotJoinedUnknownChannel( const QString &channel, const QString &nick );
+ void slotPerformOnConnectCommands();
+
+private:
+ Kopete::ChatSession *m_manager;
+ QString mNickName;
+ Kopete::AwayAction *mAwayAction;
+ bool triedAltNick;
+ bool autoShowServerWindow;
+ QString autoConnect;
+
+ KIRC::Engine *m_engine;
+ IRCNetwork *m_network;
+ uint currentHost;
+ QTextCodec *mCodec;
+
+ MessageDestination m_serverNotices;
+ MessageDestination m_serverMessages;
+ MessageDestination m_informationReplies;
+ MessageDestination m_errorMessages;
+
+ ChannelListDialog *m_channelList;
+
+ QValueList<IRCContact *> m_contacts;
+ IRCContactManager *m_contactManager;
+ IRCServerContact *m_myServer;
+
+ QMap< QString, QString > m_customCtcp;
+ Kopete::ChatSession *commandSource;
+
+ KAction *m_joinChannelAction;
+ KAction *m_searchChannelAction;
+};
+
+#endif
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/protocols/irc/ircaddcontactpage.cpp b/kopete/protocols/irc/ircaddcontactpage.cpp
new file mode 100644
index 00000000..db4ca3b2
--- /dev/null
+++ b/kopete/protocols/irc/ircaddcontactpage.cpp
@@ -0,0 +1,83 @@
+/*
+ ircaddcontactpage.cpp - IRC Add Contact Widget
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+
+ Kopete (c) 2002 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "ircadd.h"
+#include "ircaddcontactpage.h"
+#include "channellist.h"
+
+#include "kircengine.h"
+
+#include "ircaccount.h"
+
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qframe.h>
+#include <qtabwidget.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+IRCAddContactPage::IRCAddContactPage( QWidget *parent, IRCAccount *a ) : AddContactPage(parent, 0)
+{
+ (new QVBoxLayout(this))->setAutoAdd(true);
+ ircdata = new ircAddUI(this);
+ mSearch = new ChannelList( (QWidget*)ircdata->hbox, a->engine() );
+ mAccount = a;
+
+ connect( mSearch, SIGNAL( channelSelected( const QString & ) ),
+ this, SLOT( slotChannelSelected( const QString & ) ) );
+
+ connect( mSearch, SIGNAL( channelDoubleClicked( const QString & ) ),
+ this, SLOT( slotChannelDoubleClicked( const QString & ) ) );
+}
+
+IRCAddContactPage::~IRCAddContactPage()
+{
+}
+
+void IRCAddContactPage::slotChannelSelected( const QString &channel )
+{
+ ircdata->addID->setText( channel );
+}
+
+void IRCAddContactPage::slotChannelDoubleClicked( const QString &channel )
+{
+ ircdata->addID->setText( channel );
+ ircdata->tabWidget3->setCurrentPage(0);
+}
+
+bool IRCAddContactPage::apply(Kopete::Account *account , Kopete::MetaContact *m)
+{
+ QString name = ircdata->addID->text();
+ return account->addContact(name, m, Kopete::Account::ChangeKABC );
+}
+
+bool IRCAddContactPage::validateData()
+{
+ QString name = ircdata->addID->text();
+ if (name.isEmpty() == true)
+ {
+ KMessageBox::sorry(this, i18n("<qt>You need to specify a channel to join, or query to open.</qt>"), i18n("You Must Specify a Channel"));
+ return false;
+ }
+ return true;
+}
+
+#include "ircaddcontactpage.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/protocols/irc/ircaddcontactpage.h b/kopete/protocols/irc/ircaddcontactpage.h
new file mode 100644
index 00000000..c6b897ff
--- /dev/null
+++ b/kopete/protocols/irc/ircaddcontactpage.h
@@ -0,0 +1,61 @@
+/*
+ ircaddcontactpage.h - IRC Add Contact Widget
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+
+ Kopete (c) 2002 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef IRCADDCONTACTPAGE_H
+#define IRCADDCONTACTPAGE_H
+
+#include "addcontactpage.h"
+
+class ircAddUI;
+namespace Kopete { class MetaContact; }
+class IRCAccount;
+class QListViewItem;
+class ChannelList;
+
+/**
+ *@author Nick Betcher <nbetcher@kde.org>
+ */
+class IRCAddContactPage : public AddContactPage
+{
+ Q_OBJECT
+public:
+ IRCAddContactPage(QWidget *parent=0, IRCAccount* account = 0);
+ ~IRCAddContactPage();
+ ircAddUI *ircdata;
+
+public slots:
+ virtual bool apply(Kopete::Account *account , Kopete::MetaContact *m);
+
+private slots:
+ virtual bool validateData();
+ void slotChannelSelected( const QString &channel );
+ void slotChannelDoubleClicked( const QString &channel );
+private:
+ IRCAccount *mAccount;
+ ChannelList *mSearch;
+};
+
+#endif
+/*
+ * Local variables:
+ * c-indentation-style: k&r
+ * c-basic-offset: 8
+ * indent-tabs-mode: t
+ * End:
+ */
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/protocols/irc/ircchannelcontact.cpp b/kopete/protocols/irc/ircchannelcontact.cpp
new file mode 100644
index 00000000..cc99acf3
--- /dev/null
+++ b/kopete/protocols/irc/ircchannelcontact.cpp
@@ -0,0 +1,749 @@
+/*
+ ircchannelcontact.cpp - IRC Channel Contact
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+
+ Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "irccontactmanager.h"
+#include "ircchannelcontact.h"
+#include "ircusercontact.h"
+#include "ircservercontact.h"
+#include "ircaccount.h"
+#include "ircprotocol.h"
+
+#include "kopeteview.h"
+#include "kopeteuiglobal.h"
+#include "kcodecaction.h"
+#include "kopetemetacontact.h"
+#include "kopetestdaction.h"
+#include "kopetechatsessionmanager.h"
+
+#include <kdebug.h>
+#include <krun.h>
+#include <kinputdialog.h>
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kglobal.h>
+#include <kmessagebox.h>
+
+#include <qtimer.h>
+
+//This is the number of nicknames we will process concurrently when joining a channel
+//Lower numbers ensure less GUI blocking, but take marginally longer to complete.
+//Higher numbers are absolute fastest, but block GUI until all members are added
+#define NICK_BATCH_LENGTH 1
+
+IRCChannelContact::IRCChannelContact(IRCContactManager *contactManager, const QString &channel, Kopete::MetaContact *metac)
+ : IRCContact(contactManager, channel, metac, "irc_channel")
+{
+ KIRC::Engine *engine = kircEngine();
+
+ mInfoTimer = new QTimer( this );
+ QObject::connect(mInfoTimer, SIGNAL(timeout()), this, SLOT( slotUpdateInfo() ) );
+
+ QObject::connect(engine, SIGNAL(incomingUserIsAway(const QString &, const QString &)),
+ this, SLOT(slotIncomingUserIsAway(const QString &, const QString &)));
+
+ QObject::connect(engine, SIGNAL(incomingListedChan(const QString &, uint, const QString &)),
+ this, SLOT(slotChannelListed(const QString &, uint, const QString &)));
+
+ actionJoin = 0L;
+ actionModeT = new KToggleAction(i18n("Only Operators Can Change &Topic"), 0, this, SLOT(slotModeChanged()), this );
+ actionModeN = new KToggleAction(i18n("&No Outside Messages"), 0, this, SLOT(slotModeChanged()), this );
+ actionModeS = new KToggleAction(i18n("&Secret"), 0, this, SLOT(slotModeChanged()), this );
+ actionModeM = new KToggleAction(i18n("&Moderated"), 0, this, SLOT(slotModeChanged()), this );
+ actionModeI = new KToggleAction(i18n("&Invite Only"), 0, this, SLOT(slotModeChanged()), this );
+ actionHomePage = 0L;
+
+ updateStatus();
+}
+
+IRCChannelContact::~IRCChannelContact()
+{
+}
+
+void IRCChannelContact::slotUpdateInfo()
+{
+ /** This woudl be nice, but it generates server errors too often
+
+ if( !manager(Kopete::Contact::CannotCreate) && onlineStatus() == m_protocol->m_ChannelStatusOnline )
+ kircEngine()->writeMessage( QString::fromLatin1("LIST %1").arg(m_nickName) );
+ else
+ setProperty( QString::fromLatin1("channelMembers"), i18n("Members"), manager()->members().count() );
+
+ */
+ KIRC::Engine *engine = kircEngine();
+
+ if (manager(Kopete::Contact::CannotCreate))
+ {
+ setProperty(m_protocol->propChannelMembers, manager()->members().count());
+ engine->writeMessage(QString::fromLatin1("WHO %1").arg(m_nickName));
+ }
+ else
+ {
+ removeProperty(m_protocol->propChannelMembers);
+ removeProperty(m_protocol->propChannelTopic);
+ }
+
+ mInfoTimer->start( 45000, true );
+}
+
+void IRCChannelContact::slotChannelListed( const QString &channel, uint members, const QString &topic )
+{
+ if (!manager(Kopete::Contact::CannotCreate) &&
+ onlineStatus() == m_protocol->m_ChannelStatusOnline &&
+ channel.lower() == m_nickName.lower())
+ {
+ mTopic = topic;
+ setProperty(m_protocol->propChannelMembers, members);
+ setProperty(m_protocol->propChannelTopic, topic);
+ }
+}
+
+void IRCChannelContact::toggleOperatorActions(bool enabled)
+{
+ if (enabled) {
+ actionTopic->setEnabled(true);
+ } else if (modeEnabled('t')) {
+ actionTopic->setEnabled(false);
+ }
+
+ actionModeT->setEnabled(enabled);
+ actionModeN->setEnabled(enabled);
+ actionModeS->setEnabled(enabled);
+ actionModeM->setEnabled(enabled);
+ actionModeI->setEnabled(enabled);
+}
+
+void IRCChannelContact::slotOnlineStatusChanged(Kopete::Contact *c, const Kopete::OnlineStatus &status, const Kopete::OnlineStatus &oldStatus)
+{
+ Q_UNUSED(oldStatus);
+
+ if (c == account()->myself()) {
+ if (status.internalStatus() & IRCProtocol::Operator) {
+ kdDebug(14120) << k_funcinfo << "WE NOW HAVE OP STATUS" << endl;
+ toggleOperatorActions(true);
+ } else {
+ kdDebug(14120) << k_funcinfo << "WE NOW dont HAVE OP STATUS" << endl;
+ toggleOperatorActions(false);
+ }
+ }
+}
+
+void IRCChannelContact::updateStatus()
+{
+ KIRC::Engine::Status status = kircEngine()->status();
+ switch (status)
+ {
+ case KIRC::Engine::Idle:
+ case KIRC::Engine::Connecting:
+ case KIRC::Engine::Authentifying:
+ setOnlineStatus(m_protocol->m_ChannelStatusOffline);
+ break;
+ case KIRC::Engine::Connected:
+ case KIRC::Engine::Closing:
+ setOnlineStatus(m_protocol->m_ChannelStatusOnline);
+ break;
+ default:
+ setOnlineStatus(m_protocol->m_StatusUnknown);
+ }
+}
+
+void IRCChannelContact::chatSessionDestroyed()
+{
+ if (manager(Kopete::Contact::CannotCreate))
+ {
+ part();
+ Kopete::ContactPtrList contacts = manager()->members();
+
+ // remove all the users on the channel
+ for (Kopete::Contact *c = contacts.first(); c; c = contacts.next())
+ {
+ if (c->metaContact()->isTemporary() &&
+ !static_cast<IRCContact*>(c)->isChatting(manager()))
+ c->deleteLater();
+ }
+ }
+
+ IRCContact::chatSessionDestroyed();
+}
+
+void IRCChannelContact::initConversation()
+{
+ kircEngine()->join(m_nickName, password());
+}
+
+void IRCChannelContact::slotConnectedToServer()
+{
+ setOnlineStatus(m_protocol->m_ChannelStatusOnline);
+ if (manager(Kopete::Contact::CannotCreate))
+ kircEngine()->join(m_nickName, password());
+}
+
+void IRCChannelContact::namesList(const QStringList &nicknames)
+{
+ mInfoTimer->stop();
+ mJoinedNicks += nicknames;
+ slotAddNicknames();
+}
+
+void IRCChannelContact::endOfNames()
+{
+ setMode(QString::null);
+ slotUpdateInfo();
+}
+
+void IRCChannelContact::slotAddNicknames()
+{
+ if( !manager(Kopete::Contact::CannotCreate) || mJoinedNicks.isEmpty())
+ {
+ return;
+ }
+
+ IRCAccount *account = ircAccount();
+
+ for( uint i = 0; !mJoinedNicks.isEmpty() && i < NICK_BATCH_LENGTH; ++i )
+ {
+ // Pick a nick from the front of the list.
+
+ QString nickToAdd = mJoinedNicks.front();
+ QChar firstChar = nickToAdd[0];
+ if( firstChar == '@' || firstChar == '%' || firstChar == '+' )
+ nickToAdd = nickToAdd.remove(0, 1);
+
+ IRCUserContact *user;
+
+ if ( nickToAdd.lower() != account->mySelf()->nickName().lower() )
+ {
+ //kdDebug(14120) << k_funcinfo << m_nickName << " nick to add: " << nickToAdd << endl;
+
+ user = account->contactManager()->findUser(nickToAdd);
+
+ // If the user is already present in some channel, dont flip the status
+ // back to online, because the other channels listen to
+ // onlineStatusChanged() emits, and they would adjust their statuses.
+
+ if (account->contactManager()->findChannelsByMember(user).isEmpty()) {
+ //kdDebug(14120) << k_funcinfo << "Setting nick ONLINE" << endl;
+ user->setOnlineStatus(m_protocol->m_UserStatusOnline);
+ }
+ }
+ else
+ {
+ // Handling my nick in the list.
+ user = account->mySelf();
+ }
+
+ Kopete::OnlineStatus status;
+ if ( firstChar == '@' || firstChar == '%' )
+ status = m_protocol->m_UserStatusOp;
+ else if( firstChar == '+')
+ status = m_protocol->m_UserStatusVoice;
+ else
+ status = user->onlineStatus();
+
+ if( user != account->mySelf() )
+ manager()->addContact(user , status, true);
+ else
+ manager()->setContactOnlineStatus(user, status);
+
+ mJoinedNicks.pop_front();
+ }
+
+ QTimer::singleShot( 0, this, SLOT( slotAddNicknames() ) );
+}
+
+void IRCChannelContact::channelTopic(const QString &topic)
+{
+ mTopic = topic;
+ setProperty( m_protocol->propChannelTopic, mTopic );
+ manager()->setDisplayName(caption());
+
+ if (mTopic.isEmpty()) {
+ Kopete::Message msg((Kopete::Contact*)this, mMyself,
+ i18n("Topic for %1 is set empty.").arg(m_nickName),
+ Kopete::Message::Internal, Kopete::Message::RichText, CHAT_VIEW);
+ appendMessage(msg);
+ } else {
+ Kopete::Message msg((Kopete::Contact*)this, mMyself,
+ i18n("Topic for %1 is %2").arg(m_nickName).arg(mTopic),
+ Kopete::Message::Internal, Kopete::Message::RichText, CHAT_VIEW);
+ appendMessage(msg);
+ }
+}
+
+void IRCChannelContact::channelHomePage(const QString &url)
+{
+ kdDebug(14120) << k_funcinfo << endl;
+ setProperty( m_protocol->propHomepage, url );
+}
+
+void IRCChannelContact::join()
+{
+ if (!manager(Kopete::Contact::CannotCreate) &&
+ onlineStatus().status() == Kopete::OnlineStatus::Online)
+ {
+ kdDebug() << k_funcinfo << "My nickname:" << m_nickName << endl;
+ kdDebug() << k_funcinfo << "My manager:" << manager(Kopete::Contact::CannotCreate) << endl;
+ if( manager(Kopete::Contact::CannotCreate) )
+ kdDebug() << k_funcinfo << "My view:" << manager(Kopete::Contact::CannotCreate)->view(false) << endl;
+ startChat();
+ }
+
+ if (manager()) {
+ connect(manager(),
+ SIGNAL(onlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus &,
+ const Kopete::OnlineStatus &)),
+ SLOT(slotOnlineStatusChanged(Kopete::Contact *, const Kopete::OnlineStatus &,
+ const Kopete::OnlineStatus &)));
+ }
+}
+
+void IRCChannelContact::partAction()
+{
+ if (manager())
+ manager()->view()->closeView();
+}
+
+void IRCChannelContact::part()
+{
+ if (manager() && !kircEngine()->isDisconnected())
+ kircEngine()->part(m_nickName, ircAccount()->defaultPart());
+}
+
+void IRCChannelContact::slotIncomingUserIsAway( const QString &nick, const QString & )
+{
+ IRCAccount *account = ircAccount();
+
+ if( nick.lower() == account->mySelf()->nickName().lower() )
+ {
+ IRCUserContact *c = account->mySelf();
+ if (manager() && manager()->members().contains(c))
+ {
+ Kopete::OnlineStatus status = manager()->contactOnlineStatus(c);
+ if (status == m_protocol->m_UserStatusOp)
+ manager()->setContactOnlineStatus(c, m_protocol->m_UserStatusOpAway );
+ else if (status == m_protocol->m_UserStatusOpAway)
+ manager()->setContactOnlineStatus(c, m_protocol->m_UserStatusOp);
+ else if (status == m_protocol->m_UserStatusVoice)
+ manager()->setContactOnlineStatus(c, m_protocol->m_UserStatusVoiceAway);
+ else if (status == m_protocol->m_UserStatusVoiceAway)
+ manager()->setContactOnlineStatus(c, m_protocol->m_UserStatusVoice);
+ else if (status == m_protocol->m_UserStatusAway)
+ manager()->setContactOnlineStatus(c, m_protocol->m_UserStatusOnline);
+ else
+ manager()->setContactOnlineStatus(c, m_protocol->m_UserStatusAway);
+ }
+ }
+}
+
+void IRCChannelContact::userJoinedChannel(const QString &nickname)
+{
+ IRCAccount *account = ircAccount();
+
+ if (nickname.lower() == account->mySelf()->nickName().lower())
+ {
+ kdDebug() << k_funcinfo << "Me:" << this << endl;
+ kdDebug() << k_funcinfo << "My nickname:" << m_nickName << endl;
+ kdDebug() << k_funcinfo << "My manager:" << manager(Kopete::Contact::CannotCreate) << endl;
+
+ if (manager(Kopete::Contact::CannotCreate))
+ kdDebug() << k_funcinfo << "My view:" << manager(Kopete::Contact::CannotCreate)->view(false) << endl;
+
+ Kopete::Message msg((Kopete::Contact *)this, mMyself,
+ i18n("You have joined channel %1").arg(m_nickName),
+ Kopete::Message::Internal, Kopete::Message::PlainText,
+ CHAT_VIEW);
+ msg.setImportance( Kopete::Message::Low); //set the importance manualy to low
+ appendMessage(msg);
+ }
+ else
+ {
+ // If we have lag or huge channels, we might receive a JOIN after we have left a channel.
+ if (!manager())
+ return;
+
+ IRCUserContact *contact = account->contactManager()->findUser( nickname );
+ contact->setOnlineStatus( m_protocol->m_UserStatusOnline );
+ manager()->addContact((Kopete::Contact *)contact, true);
+ Kopete::Message msg((Kopete::Contact *)this, mMyself,
+ i18n("User <b>%1</b> joined channel %2").arg(nickname).arg(m_nickName),
+ Kopete::Message::Internal, Kopete::Message::RichText, CHAT_VIEW);
+ msg.setImportance( Kopete::Message::Low); //set the importance manualy to low
+ manager()->appendMessage(msg);
+ }
+}
+
+void IRCChannelContact::userPartedChannel(const QString &nickname,const QString &reason)
+{
+ IRCAccount *account = ircAccount();
+
+ if (nickname.lower() != account->engine()->nickName().lower())
+ {
+ Kopete::Contact *c = locateUser( nickname );
+ if ( c )
+ {
+ manager()->removeContact( c, Kopete::Message::unescape(reason) );
+ if( c->metaContact()->isTemporary() && !static_cast<IRCContact*>(c)->isChatting( manager(Kopete::Contact::CannotCreate) ) )
+ c->deleteLater();
+ }
+ }
+}
+
+void IRCChannelContact::userKicked(const QString &nick, const QString &nickKicked, const QString &reason)
+{
+ IRCAccount *account = ircAccount();
+
+ if( nickKicked.lower() != account->engine()->nickName().lower() )
+ {
+ Kopete::Contact *c = locateUser( nickKicked );
+ if (c)
+ {
+ QString r;
+
+ if ((reason != nick) && (reason != nickKicked)) {
+ r = i18n( "%1 was kicked by %2. Reason: %3" ).arg(nickKicked, nick, reason);
+ } else {
+ r = i18n( "%1 was kicked by %2." ).arg(nickKicked, nick);
+ }
+
+ manager()->removeContact( c, r );
+ Kopete::Message msg( this, mMyself, r,
+ Kopete::Message::Internal, Kopete::Message::PlainText, CHAT_VIEW);
+ msg.setImportance(Kopete::Message::Low);
+ appendMessage(msg);
+
+ if( c->metaContact()->isTemporary() &&
+ !static_cast<IRCContact*>(c)->isChatting( manager() ) )
+ c->deleteLater();
+ }
+ }
+ else
+ {
+ QString r;
+
+ if ((reason != nick) && (reason != nickKicked)) {
+ r = i18n( "You were kicked from %1 by %2. Reason: %3" ).arg(m_nickName, nickKicked, reason);
+ } else {
+ r = i18n( "You were kicked from %1 by %2." ).arg(m_nickName, nickKicked);
+ }
+
+ KMessageBox::error(Kopete::UI::Global::mainWidget(), r, i18n("IRC Plugin"));
+ manager()->view()->closeView();
+ }
+}
+
+void IRCChannelContact::setTopic(const QString &topic)
+{
+ IRCAccount *account = ircAccount();
+
+ if (manager(Kopete::Contact::CannotCreate))
+ {
+ if( manager()->contactOnlineStatus( manager()->myself() ) ==
+ m_protocol->m_UserStatusOp || !modeEnabled('t') )
+ {
+ bool okPressed = true;
+ QString newTopic = topic;
+ if( newTopic.isNull() )
+ newTopic = KInputDialog::getText( i18n("New Topic"), i18n("Enter the new topic:"),
+ Kopete::Message::unescape(mTopic), &okPressed, 0L );
+
+ if( okPressed )
+ {
+ mTopic = newTopic;
+ kircEngine()->topic(m_nickName, newTopic);
+ }
+ }
+ else
+ {
+ Kopete::Message msg(account->myServer(), manager()->members(),
+ i18n("You must be a channel operator on %1 to do that.").arg(m_nickName),
+ Kopete::Message::Internal, Kopete::Message::PlainText, CHAT_VIEW);
+ manager()->appendMessage(msg);
+ }
+ }
+}
+
+void IRCChannelContact::topicChanged(const QString &nick, const QString &newtopic)
+{
+ IRCAccount *account = ircAccount();
+
+ mTopic = newtopic;
+ setProperty( m_protocol->propChannelTopic, mTopic );
+ manager()->setDisplayName( caption() );
+ Kopete::Message msg(account->myServer(), mMyself,
+ i18n("%1 has changed the topic to: %2").arg(nick).arg(newtopic),
+ Kopete::Message::Internal, Kopete::Message::RichText, CHAT_VIEW);
+ msg.setImportance(Kopete::Message::Low); //set the importance manualy to low
+ appendMessage(msg);
+}
+
+void IRCChannelContact::topicUser(const QString &nick, const QDateTime &time)
+{
+ IRCAccount *account = ircAccount();
+
+ Kopete::Message msg(account->myServer(), mMyself,
+ i18n("Topic set by %1 at %2").arg(nick).arg(
+ KGlobal::locale()->formatDateTime(time, true)
+ ), Kopete::Message::Internal, Kopete::Message::PlainText, CHAT_VIEW);
+ msg.setImportance(Kopete::Message::Low); //set the importance manualy to low
+ appendMessage(msg);
+}
+
+void IRCChannelContact::incomingModeChange( const QString &nick, const QString &mode )
+{
+ Kopete::Message msg(this, mMyself, i18n("%1 sets mode %2 on %3").arg(nick).arg(mode).arg(m_nickName), Kopete::Message::Internal, Kopete::Message::PlainText, CHAT_VIEW);
+ msg.setImportance( Kopete::Message::Low); //set the importance manualy to low
+ appendMessage(msg);
+
+ bool inParams = false;
+ bool modeEnabled = false;
+ QString params = QString::null;
+ for( uint i=0; i < mode.length(); i++ )
+ {
+ switch( mode[i] )
+ {
+ case '+':
+ modeEnabled = true;
+ break;
+
+ case '-':
+ modeEnabled = false;
+ break;
+
+ case ' ':
+ inParams = true;
+ break;
+ default:
+ if( inParams )
+ params.append( mode[i] );
+ else
+ toggleMode( mode[i], modeEnabled, false );
+ break;
+ }
+ }
+}
+
+void IRCChannelContact::incomingChannelMode( const QString &mode,
+ const QString &/*params*/ )
+{
+ for( uint i=1; i < mode.length(); i++ )
+ {
+ if( mode[i] != 'l' && mode[i] != 'k' )
+ toggleMode( mode[i], true, false );
+ }
+}
+
+void IRCChannelContact::setMode(const QString &mode)
+{
+ if (manager(Kopete::Contact::CannotCreate))
+ kircEngine()->mode(m_nickName, mode);
+}
+
+void IRCChannelContact::slotModeChanged()
+{
+ toggleMode( 't', actionModeT->isChecked(), true );
+ toggleMode( 'n', actionModeN->isChecked(), true );
+ toggleMode( 's', actionModeS->isChecked(), true );
+ toggleMode( 'm', actionModeM->isChecked(), true );
+ toggleMode( 'i', actionModeI->isChecked(), true );
+}
+
+void IRCChannelContact::failedChanBanned()
+{
+ manager()->deleteLater();
+ KMessageBox::error( Kopete::UI::Global::mainWidget(),
+ i18n("<qt>You can not join %1 because you have been banned.</qt>").arg(m_nickName),
+ i18n("IRC Plugin") );
+}
+
+void IRCChannelContact::failedChanInvite()
+{
+ manager()->deleteLater();
+ KMessageBox::error( Kopete::UI::Global::mainWidget(),
+ i18n("<qt>You can not join %1 because it is set to invite only, and no one has invited you.</qt>").arg(m_nickName), i18n("IRC Plugin") );
+}
+
+void IRCChannelContact::failedChanFull()
+{
+ manager()->deleteLater();
+ KMessageBox::error( Kopete::UI::Global::mainWidget(),
+ i18n("<qt>You can not join %1 because it has reached its user limit.</qt>").arg(m_nickName),
+ i18n("IRC Plugin") );
+}
+
+void IRCChannelContact::failedChankey()
+{
+ bool ok;
+ QString diaPassword = KInputDialog::getText( i18n( "IRC Plugin" ),
+ i18n( "Please enter key for channel %1: ").arg(m_nickName),
+ QString::null,
+ &ok );
+
+ if ( !ok )
+ manager()->deleteLater();
+ else
+ {
+ setPassword(diaPassword);
+ kircEngine()->join(m_nickName, password());
+ }
+}
+
+void IRCChannelContact::toggleMode( QChar mode, bool enabled, bool update )
+{
+ if( manager(Kopete::Contact::CannotCreate) )
+ {
+ switch( mode )
+ {
+ case 't':
+ actionModeT->setChecked( enabled );
+
+ // If someones sets +t and we're not channel operators, disable the action.
+ if (enabled && !(manager()->contactOnlineStatus(ircAccount()->myself()).internalStatus() & IRCProtocol::Operator)) {
+ actionTopic->setEnabled( false );
+ } else {
+ actionTopic->setEnabled( true );
+ }
+ break;
+ case 'n':
+ actionModeN->setChecked( enabled );
+ break;
+ case 's':
+ actionModeS->setChecked( enabled );
+ break;
+ case 'm':
+ actionModeM->setChecked( enabled );
+ break;
+ case 'i':
+ actionModeI->setChecked( enabled );
+ break;
+ }
+ }
+
+ if( update )
+ {
+ if( modeMap[mode] != enabled )
+ {
+ if( enabled )
+ setMode( QString::fromLatin1("+") + mode );
+ else
+ setMode( QString::fromLatin1("-") + mode );
+ }
+ }
+
+ modeMap[mode] = enabled;
+}
+
+bool IRCChannelContact::modeEnabled( QChar mode, QString *value )
+{
+ if( !value )
+ return modeMap[mode];
+
+ return false;
+}
+
+QPtrList<KAction> *IRCChannelContact::customContextMenuActions()
+{
+ QPtrList<KAction> *mCustomActions = new QPtrList<KAction>();
+ if( !actionJoin )
+ {
+ actionJoin = new KAction(i18n("&Join"), 0, this, SLOT(join()), this, "actionJoin");
+ actionPart = new KAction(i18n("&Part"), 0, this, SLOT(partAction()), this, "actionPart");
+ actionTopic = new KAction(i18n("Change &Topic..."), 0, this, SLOT(setTopic()), this, "actionTopic");
+ actionModeMenu = new KActionMenu(i18n("Channel Modes"), 0, this, "actionModeMenu");
+
+ if( !property(m_protocol->propHomepage).value().isNull() )
+ {
+ actionHomePage = new KAction( i18n("Visit &Homepage"), 0, this,
+ SLOT(slotHomepage()), this, "actionHomepage");
+ }
+ else if( actionHomePage )
+ {
+ delete actionHomePage;
+ }
+
+ actionModeMenu->insert( actionModeT );
+ actionModeMenu->insert( actionModeN );
+ actionModeMenu->insert( actionModeS );
+ actionModeMenu->insert( actionModeM );
+ actionModeMenu->insert( actionModeI );
+ actionModeMenu->setEnabled( true );
+
+ codecAction = new KCodecAction( i18n("&Encoding"), 0, this, "selectcharset" );
+ connect( codecAction, SIGNAL( activated( const QTextCodec * ) ),
+ this, SLOT( setCodec( const QTextCodec *) ) );
+ codecAction->setCodec( codec() );
+ }
+
+ mCustomActions->append( actionJoin );
+ mCustomActions->append( actionPart );
+ mCustomActions->append( actionTopic );
+ mCustomActions->append( actionModeMenu );
+ mCustomActions->append( codecAction );
+ if( actionHomePage )
+ mCustomActions->append( actionHomePage );
+
+ bool isOperator = manager(Kopete::Contact::CannotCreate) &&
+ (manager()->contactOnlineStatus(ircAccount()->myself()).internalStatus() & IRCProtocol::Operator);
+
+ actionJoin->setEnabled( !manager(Kopete::Contact::CannotCreate) );
+ actionPart->setEnabled( manager(Kopete::Contact::CannotCreate) );
+ actionTopic->setEnabled( manager(Kopete::Contact::CannotCreate) && ( !modeEnabled('t') || isOperator ) );
+
+ toggleOperatorActions(isOperator);
+
+ return mCustomActions;
+}
+
+void IRCChannelContact::slotHomepage()
+{
+ QString homePage = property(m_protocol->propHomepage).value().toString();
+ if( !homePage.isEmpty() )
+ {
+ new KRun( KURL( homePage ), 0, false);
+ }
+}
+
+const QString IRCChannelContact::caption() const
+{
+ QString cap = QString::fromLatin1("%1 @ %2").arg(m_nickName).arg(kircEngine()->currentHost());
+ if(!mTopic.isEmpty())
+ cap.append( QString::fromLatin1(" - %1").arg(Kopete::Message::unescape(mTopic)) );
+
+ return cap;
+}
+
+void IRCChannelContact::privateMessage(IRCContact *from, IRCContact *to, const QString &message)
+{
+ if(to == this)
+ {
+ Kopete::Message msg(from, manager()->members(), message, Kopete::Message::Inbound,
+ Kopete::Message::RichText, CHAT_VIEW);
+ appendMessage(msg);
+ }
+}
+
+void IRCChannelContact::newAction(const QString &from, const QString &action)
+{
+ IRCAccount *account = ircAccount();
+
+ IRCUserContact *f = account->contactManager()->findUser(from);
+ Kopete::Message::MessageDirection dir =
+ (f == account->mySelf()) ? Kopete::Message::Outbound : Kopete::Message::Inbound;
+ Kopete::Message msg(f, manager()->members(), action, dir, Kopete::Message::RichText,
+ CHAT_VIEW, Kopete::Message::TypeAction);
+ appendMessage(msg);
+}
+
+#include "ircchannelcontact.moc"
diff --git a/kopete/protocols/irc/ircchannelcontact.h b/kopete/protocols/irc/ircchannelcontact.h
new file mode 100644
index 00000000..15a72e17
--- /dev/null
+++ b/kopete/protocols/irc/ircchannelcontact.h
@@ -0,0 +1,156 @@
+/*
+ ircchannelcontact.h - IRC Channel Contact
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef IRCCHANNELCONTACT_H
+#define IRCCHANNELCONTACT_H
+
+#include "irccontact.h"
+
+class KActionCollection;
+class KAction;
+class KActionMenu;
+class KCodecAction;
+class KToggleAction;
+
+namespace Kopete { class MetaContact; }
+namespace Kopete { class ChatSession; }
+namespace Kopete { class Message; }
+class KopeteView;
+
+class IRCAccount;
+class IRCContactManager;
+
+/**
+ * @author Jason Keirstead <jason@keirstead.org>
+ *
+ * This class is the @ref Kopete::Contact object representing IRC Channels, not users.
+ * It is derived from IRCContact where much of its functionality is shared with @ref IRCUserContact.
+ */
+class IRCChannelContact
+ : public IRCContact
+{
+ friend class IRCSignalMapper;
+
+ Q_OBJECT
+
+public:
+ IRCChannelContact(IRCContactManager *, const QString &channel, Kopete::MetaContact *metac);
+ ~IRCChannelContact();
+
+ /**
+ * Returns the current topic for this channel.
+ */
+ const QString &topic() const { return mTopic; };
+
+ /* Set password for a channel */
+ void setPassword(const QString &password) { mPassword = password; }
+ /* Get password for a channel */
+ const QString &password() const { return mPassword; }
+
+ /**
+ * Returns if a mode is enabled for this channel.
+ * @param mode The mode you want to check ( 't', 'n', etc. )
+ * @param value This is a pointer to a QString which is set to
+ * the value of the mode if it has one. Example, the mode 'l' or
+ * the mode 'k'. If the mode has no such value then the pointer
+ * is always returned null.
+ */
+ bool modeEnabled( QChar mode, QString *value = 0 );
+
+ // Kopete::Contact stuff
+ virtual QPtrList<KAction> *customContextMenuActions();
+ virtual const QString caption() const;
+
+ //Methods handled by the signal mapper
+ void userJoinedChannel(const QString &user);
+ void userPartedChannel(const QString &user, const QString &reason);
+ void userKicked(const QString &nick, const QString &nickKicked, const QString &reason);
+ void channelTopic(const QString &topic);
+ void channelHomePage(const QString &url);
+ void topicChanged(const QString &nick, const QString &newtopic);
+ void topicUser(const QString &nick, const QDateTime &time);
+ void namesList(const QStringList &nicknames);
+ void endOfNames();
+ void incomingModeChange(const QString &nick, const QString &mode);
+ void incomingChannelMode(const QString &mode, const QString &params );
+ void failedChankey();
+ void failedChanBanned();
+ void failedChanInvite();
+ void failedChanFull();
+ void newAction(const QString &from, const QString &action);
+
+public slots:
+ void updateStatus();
+
+ /**
+ * Sets the topic of this channel
+ * @param topic The topic you want set
+ */
+ void setTopic( const QString &topic = QString::null );
+
+ /**
+ * Sets or unsets a mode on this channel
+ * @param mode The full text of the mode change you want performed
+ */
+ void setMode( const QString &mode = QString::null );
+
+ void part();
+ void partAction();
+ void join();
+
+protected slots:
+ void chatSessionDestroyed();
+
+ virtual void privateMessage(IRCContact *from, IRCContact *to, const QString &message);
+ virtual void initConversation();
+
+private slots:
+ void slotIncomingUserIsAway( const QString &nick, const QString &reason );
+ void slotModeChanged();
+ void slotAddNicknames();
+ void slotConnectedToServer();
+ void slotUpdateInfo();
+ void slotHomepage();
+ void slotChannelListed(const QString &channel, uint members, const QString &topic);
+ void slotOnlineStatusChanged(Kopete::Contact *c, const Kopete::OnlineStatus &status, const Kopete::OnlineStatus &oldStatus);
+
+private:
+ KAction *actionJoin;
+ KAction *actionPart;
+ KAction *actionTopic;
+ KAction *actionHomePage;
+ KActionMenu *actionModeMenu;
+ KCodecAction *codecAction;
+
+ KToggleAction *actionModeT; // Only Operators Can Change Topic
+ KToggleAction *actionModeN; // No Outside Messages
+ KToggleAction *actionModeS; // Secret
+ KToggleAction *actionModeI; // Invite Only
+ KToggleAction *actionModeM; // Moderated
+
+ QString mTopic;
+ QString mPassword;
+ QStringList mJoinedNicks;
+ QMap<QString, bool> modeMap;
+ QTimer *mInfoTimer;
+
+ void toggleMode( QChar mode, bool enabled, bool update );
+ void toggleOperatorActions( bool enabled );
+};
+
+#endif
diff --git a/kopete/protocols/irc/ircchatui.rc b/kopete/protocols/irc/ircchatui.rc
new file mode 100644
index 00000000..9c1b9dbb
--- /dev/null
+++ b/kopete/protocols/irc/ircchatui.rc
@@ -0,0 +1,10 @@
+<!DOCTYPE kpartgui>
+<kpartgui version="26" name="kopetechatwindow">
+ <MenuBar>
+ <Menu name="irc" >
+ <text>IRC</text>
+ <ActionList name="irccontactactionlist" />
+ </Menu>
+ </MenuBar>
+
+</kpartgui>
diff --git a/kopete/protocols/irc/irccontact.cpp b/kopete/protocols/irc/irccontact.cpp
new file mode 100644
index 00000000..64f89322
--- /dev/null
+++ b/kopete/protocols/irc/irccontact.cpp
@@ -0,0 +1,425 @@
+/*
+ irccontact.cpp - IRC Contact
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+ Copyright (c) 2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+ Copyright (c) 2005 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <qregexp.h>
+
+#include <qtimer.h>
+#include <qtextcodec.h>
+
+#include "ircaccount.h"
+#include "kopeteglobal.h"
+#include "kopeteuiglobal.h"
+#include "kopetemetacontact.h"
+#include "kopeteview.h"
+#include "ircusercontact.h"
+#include "irccontact.h"
+#include "ircprotocol.h"
+#include "ircservercontact.h"
+#include "irccontactmanager.h"
+#include "ksparser.h"
+
+IRCContact::IRCContact(IRCAccount *account, KIRC::EntityPtr entity, Kopete::MetaContact *metac, const QString& icon)
+ : Kopete::Contact(account, entity->name(), metac, icon),
+ m_chatSession(0)
+{
+}
+
+IRCContact::IRCContact(IRCContactManager *contactManager, const QString &nick, Kopete::MetaContact *metac, const QString& icon)
+ : Kopete::Contact(contactManager->account(), nick, metac, icon),
+ m_nickName(nick),
+ m_chatSession(0)
+{
+ KIRC::Engine *engine = kircEngine();
+
+ // Contact list display name
+ setProperty( Kopete::Global::Properties::self()->nickName(), m_nickName );
+
+ // IRCContactManager stuff
+ QObject::connect(contactManager, SIGNAL(privateMessage(IRCContact *, IRCContact *, const QString &)),
+ this, SLOT(privateMessage(IRCContact *, IRCContact *, const QString &)));
+
+ // Kopete::ChatSessionManager stuff
+ mMyself.append( static_cast<Kopete::Contact*>( this ) );
+
+ // KIRC stuff
+ QObject::connect(engine, SIGNAL(incomingNickChange(const QString &, const QString &)),
+ this, SLOT( slotNewNickChange(const QString&, const QString&)));
+ QObject::connect(engine, SIGNAL(successfullyChangedNick(const QString &, const QString &)),
+ this, SLOT(slotNewNickChange(const QString &, const QString &)));
+ QObject::connect(engine, SIGNAL(incomingQuitIRC(const QString &, const QString &)),
+ this, SLOT( slotUserDisconnected(const QString&, const QString&)));
+
+ QObject::connect(engine, SIGNAL(statusChanged(KIRC::Engine::Status)),
+ this, SLOT(updateStatus()));
+
+ engine->setCodec( m_nickName, codec() );
+}
+
+IRCContact::~IRCContact()
+{
+// kdDebug(14120) << k_funcinfo << m_nickName << endl;
+ if (metaContact() && metaContact()->isTemporary() && !isChatting(m_chatSession))
+ metaContact()->deleteLater();
+
+ emit destroyed(this);
+}
+
+IRCAccount *IRCContact::ircAccount() const
+{
+ return static_cast<IRCAccount *>(account());
+}
+
+KIRC::Engine *IRCContact::kircEngine() const
+{
+ return ircAccount()->engine();
+}
+
+bool IRCContact::isReachable()
+{
+ if (onlineStatus().status() != Kopete::OnlineStatus::Offline &&
+ onlineStatus().status() != Kopete::OnlineStatus::Unknown)
+ return true;
+
+ return false;
+}
+
+const QString IRCContact::caption() const
+{
+ return QString::null;
+}
+/*
+const QString IRCContact::formatedName() const
+{
+ return QString::null;
+}
+*/
+void IRCContact::updateStatus()
+{
+}
+
+void IRCContact::privateMessage(IRCContact *, IRCContact *, const QString &)
+{
+}
+
+void IRCContact::setCodec(const QTextCodec *codec)
+{
+ kircEngine()->setCodec(m_nickName, codec);
+ metaContact()->setPluginData(m_protocol, QString::fromLatin1("Codec"), QString::number(codec->mibEnum()));
+}
+
+const QTextCodec *IRCContact::codec()
+{
+ QString codecId = metaContact()->pluginData(m_protocol, QString::fromLatin1("Codec"));
+ QTextCodec *codec = ircAccount()->codec();
+
+ if( !codecId.isEmpty() )
+ {
+ bool test = true;
+ uint mib = codecId.toInt(&test);
+ if (test)
+ codec = QTextCodec::codecForMib(mib);
+ else
+ codec = QTextCodec::codecForName(codecId.latin1());
+ }
+
+ if( !codec )
+ return kircEngine()->codec();
+
+ return codec;
+}
+
+Kopete::ChatSession *IRCContact::manager(Kopete::Contact::CanCreateFlags canCreate)
+{
+ IRCAccount *account = ircAccount();
+ KIRC::Engine *engine = kircEngine();
+
+ if (canCreate == Kopete::Contact::CanCreate && !m_chatSession)
+ {
+ if( engine->status() == KIRC::Engine::Idle && dynamic_cast<IRCServerContact*>(this) == 0 )
+ account->connect();
+
+ m_chatSession = Kopete::ChatSessionManager::self()->create(account->myself(), mMyself, account->protocol());
+ m_chatSession->setDisplayName(caption());
+
+ QObject::connect(m_chatSession, SIGNAL(messageSent(Kopete::Message&, Kopete::ChatSession *)),
+ this, SLOT(slotSendMsg(Kopete::Message&, Kopete::ChatSession *)));
+ QObject::connect(m_chatSession, SIGNAL(closing(Kopete::ChatSession *)),
+ this, SLOT(chatSessionDestroyed()));
+
+ initConversation();
+ }
+
+ return m_chatSession;
+}
+
+void IRCContact::chatSessionDestroyed()
+{
+ m_chatSession = 0;
+
+ if (metaContact()->isTemporary() && !isChatting())
+ deleteLater();
+}
+
+void IRCContact::slotUserDisconnected(const QString &user, const QString &reason)
+{
+ if (m_chatSession)
+ {
+ QString nickname = user.section('!', 0, 0);
+ Kopete::Contact *c = locateUser( nickname );
+ if ( c )
+ {
+ m_chatSession->removeContact(c, i18n("Quit: \"%1\" ").arg(reason), Kopete::Message::RichText);
+ c->setOnlineStatus(m_protocol->m_UserStatusOffline);
+ }
+ }
+}
+
+void IRCContact::setNickName( const QString &nickname )
+{
+ kdDebug(14120) << k_funcinfo << m_nickName << " changed to " << nickname << endl;
+ m_nickName = nickname;
+ Kopete::Contact::setNickName( nickname );
+}
+
+void IRCContact::slotNewNickChange(const QString &oldnickname, const QString &newnickname)
+{
+ IRCAccount *account = ircAccount();
+
+ IRCContact *user = static_cast<IRCContact*>( locateUser(oldnickname) );
+ if( user )
+ {
+ user->setNickName( newnickname );
+
+ //If the user is in our contact list, then change the notify list nickname
+ if (!user->metaContact()->isTemporary())
+ {
+ account->contactManager()->removeFromNotifyList( oldnickname );
+ account->contactManager()->addToNotifyList( newnickname );
+ }
+ }
+}
+
+void IRCContact::slotSendMsg(Kopete::Message &message, Kopete::ChatSession *)
+{
+ QString htmlString = message.escapedBody();
+
+ // Messages we get with RichText enabled:
+ //
+ // Hello world in bold and color:
+ // <span style="font-weight:600;color:#403897">Hello World</span>
+ //
+ // Two-liner in color:
+ // <span style="color:#403897">Hello<br />World</span>
+
+ if (htmlString.find(QString::fromLatin1("</span")) > -1)
+ {
+ QRegExp findTags( QString::fromLatin1("<span style=\"(.*)\">(.*)</span>") );
+ findTags.setMinimal( true );
+ int pos = 0;
+
+ while (pos >= 0)
+ {
+ pos = findTags.search(htmlString);
+ if (pos > -1)
+ {
+ QString styleHTML = findTags.cap(1);
+ QString replacement = findTags.cap(2);
+ QStringList styleAttrs = QStringList::split(';', styleHTML);
+
+ for (QStringList::Iterator attrPair = styleAttrs.begin(); attrPair != styleAttrs.end(); ++attrPair)
+ {
+ QString attribute = (*attrPair).section(':',0,0);
+ QString value = (*attrPair).section(':',1);
+
+ if( attribute == QString::fromLatin1("color") )
+ {
+ int ircColor = KSParser::colorForHTML( value );
+ if( ircColor > -1 )
+ replacement.prepend( QString( QChar(0x03) ).append( QString::number(ircColor) ) ).append( QChar( 0x03 ) );
+ }
+ else if( attribute == QString::fromLatin1("font-weight") &&
+ value == QString::fromLatin1("600") ) {
+ // Bolding
+ replacement.prepend( QChar(0x02) ).append( QChar(0x02) );
+ }
+ else if( attribute == QString::fromLatin1("text-decoration") &&
+ value == QString::fromLatin1("underline") ) {
+ replacement.prepend( QChar(31) ).append( QChar(31) );
+ }
+ }
+
+ htmlString = htmlString.left( pos ) + replacement + htmlString.mid( pos + findTags.matchedLength() );
+ }
+ }
+ }
+
+ htmlString = Kopete::Message::unescape(htmlString);
+
+ QStringList messages = QStringList::split( '\n', htmlString );
+
+ for( QStringList::Iterator it = messages.begin(); it != messages.end(); ++it )
+ {
+ // Dont use the resulting string(s). The problem is that we'd have to parse them
+ // back to format that would be suitable for appendMessage().
+ //
+ // TODO: If the given message was plaintext, we could easily show what was
+ // actually sent.
+
+ sendMessage(*it);
+ }
+
+ if (message.requestedPlugin() != CHAT_VIEW) {
+ Kopete::Message msg(message.from(), message.to(), message.escapedBody(), message.direction(),
+ Kopete::Message::RichText, CHAT_VIEW, message.type());
+
+ msg.setBg(QColor());
+ msg.setFg(QColor());
+
+ appendMessage(msg);
+ } else {
+ // Lets not modify the given message object.
+ Kopete::Message msg = message;
+ msg.setBg(QColor());
+ appendMessage(msg);
+ }
+
+ manager(Kopete::Contact::CanCreate)->messageSucceeded();
+}
+
+QStringList IRCContact::sendMessage( const QString &msg )
+{
+ QStringList messages;
+
+ QString newMessage = msg;
+
+ // IRC limits the message size to 512 characters. So split the given
+ // message into pieces.
+ //
+ // This can of course give nasty results, but most of us dont write
+ // that long lines anyway ;-)... And this is how other clients also
+ // seem to behave.
+
+ int l = 500 - m_nickName.length();
+
+ do {
+ messages.append(newMessage.mid(0, l));
+ newMessage.remove(0, l);
+ } while (!newMessage.isEmpty());
+
+ for (QStringList::const_iterator it = messages.begin();
+ it != messages.end(); ++it)
+ kircEngine()->privmsg(m_nickName, *it);
+
+ return messages;
+}
+
+Kopete::Contact *IRCContact::locateUser(const QString &nick)
+{
+ IRCAccount *account = ircAccount();
+
+ if (m_chatSession)
+ {
+ if( nick == account->mySelf()->nickName() )
+ return account->mySelf();
+ else
+ {
+ Kopete::ContactPtrList mMembers = m_chatSession->members();
+ for (Kopete::Contact *it = mMembers.first(); it; it = mMembers.next())
+ {
+ if (static_cast<IRCContact*>(it)->nickName() == nick)
+ return it;
+ }
+ }
+ }
+ return 0;
+}
+
+bool IRCContact::isChatting(const Kopete::ChatSession *avoid) const
+{
+ IRCAccount *account = ircAccount();
+
+ if (!account)
+ return false;
+
+ QValueList<Kopete::ChatSession*> sessions = Kopete::ChatSessionManager::self()->sessions();
+ for (QValueList<Kopete::ChatSession*>::Iterator it= sessions.begin(); it!=sessions.end() ; ++it)
+ {
+ if( (*it) != avoid && (*it)->account() == account &&
+ (*it)->members().contains(this) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void IRCContact::deleteContact()
+{
+ kdDebug(14120) << k_funcinfo << m_nickName << endl;
+
+ delete m_chatSession;
+
+ if (!isChatting())
+ {
+ kdDebug(14120) << k_funcinfo << "will delete " << m_nickName << endl;
+ Kopete::Contact::deleteContact();
+ }
+ else
+ {
+ metaContact()->removeContact(this);
+ Kopete::MetaContact *m = new Kopete::MetaContact();
+ m->setTemporary(true);
+ setMetaContact(m);
+ }
+}
+
+void IRCContact::appendMessage(Kopete::Message &msg)
+{
+ manager(Kopete::Contact::CanCreate)->appendMessage(msg);
+}
+
+KopeteView *IRCContact::view()
+{
+ if (m_chatSession)
+ return m_chatSession->view(false);
+ return 0L;
+}
+void IRCContact::serialize(QMap<QString, QString> & /*serializedData*/, QMap<QString, QString> &addressBookData)
+{
+ // write the
+ addressBookData[ protocol()->addressBookIndexField() ] = ( contactId() + QChar(0xE120) + account()->accountId() );
+}
+
+void IRCContact::receivedMessage( KIRC::Engine::ServerMessageType type,
+ const KIRC::EntityPtr &from,
+ const KIRC::EntityPtrList &to,
+ const QString &msg)
+{
+ if (to.contains(m_entity))
+ {
+ IRCContact *fromContact = ircAccount()->getContact(from);
+ Kopete::Message message(fromContact, manager()->members(), msg, Kopete::Message::Inbound,
+ Kopete::Message::RichText, CHAT_VIEW);
+ appendMessage(message);
+ }
+}
+
+#include "irccontact.moc"
diff --git a/kopete/protocols/irc/irccontact.h b/kopete/protocols/irc/irccontact.h
new file mode 100644
index 00000000..058315fb
--- /dev/null
+++ b/kopete/protocols/irc/irccontact.h
@@ -0,0 +1,153 @@
+/*
+ irccontact.h - IRC Contact
+
+ Copyright (c) 2005 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
+ Copyright (c) 2003-2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef IRCCONTACT_H
+#define IRCCONTACT_H
+
+#include "kircengine.h"
+#include "kircentity.h"
+
+#include "kopetecontact.h"
+#include "kopetemessage.h"
+
+#include <qptrlist.h>
+#include <qmap.h>
+
+class IRCProtocol;
+class IRCAccount;
+class IRCContactManager;
+
+namespace KIRC
+{
+class Engine;
+}
+
+namespace Kopete
+{
+class ChatSession;
+class MetaContact;
+}
+
+class KopeteView;
+
+class QTextCodec;
+
+/**
+ * @author Jason Keirstead <jason@keirstead.org>
+ * @author Michel Hermier <michel.hermier@wanadoo.fr>
+ *
+ * This class is the base class for @ref IRCUserContact and @ref IRCChannelContact.
+ * Common routines and signal connections that are required for both types of
+ * contacts reside here, to avoid code duplication between these two classes.
+ */
+class IRCContact
+ : public Kopete::Contact
+{
+ Q_OBJECT
+
+public:
+ IRCContact(IRCAccount *account, KIRC::EntityPtr entity, Kopete::MetaContact *metac, const QString& icon = QString::null);
+ IRCContact(IRCContactManager *contactManager, const QString &nick, Kopete::MetaContact *metac, const QString& icon = QString::null);
+ virtual ~IRCContact();
+
+ IRCAccount *ircAccount() const;
+ KIRC::Engine *kircEngine() const;
+
+ /**
+ * Sets the nickname of this contact. The nickname is distinct from the displayName
+ * in case trackNameChanges is disabled.
+ */
+ void setNickName(const QString &nickname);
+
+ /**
+ * Returns the nickname / channel name
+ */
+ const QString &nickName() const { return m_nickName; }
+
+ /**
+ * This function attempts to find the nickname specified within the current chat
+ * session. Returns a pointer to that IRCUserContact, or 0L if the user does not
+ * exist in this session. More useful for channels. Calling IRCChannelContact::locateUser()
+ * for example tells you if a user is in a certain channel.
+ */
+ Kopete::Contact *locateUser( const QString &nickName );
+
+ virtual bool isReachable();
+
+ /**
+ * return true if the contact is in a chat. false if the contact is in no chats
+ * that loop over all manager, and checks the presence of the user
+ */
+ bool isChatting( const Kopete::ChatSession *avoid = 0L ) const;
+
+ virtual const QString caption() const;
+// virtual const QString formatedName() const;
+
+ virtual Kopete::ChatSession *manager(Kopete::Contact::CanCreateFlags = Kopete::Contact::CannotCreate);
+
+ virtual void appendMessage( Kopete::Message & );
+
+ const QTextCodec *codec();
+
+ KopeteView *view();
+
+ /**
+ * We serialise the contactId and the server group in 'contactId'
+ * so that other IRC programs reading this from KAddressBook have a chance of figuring
+ * which server the contact relates to
+ */
+ virtual void serialize( QMap<QString, QString> &serializedData, QMap<QString, QString> &addressBookData );
+
+signals:
+ void destroyed(IRCContact *self);
+
+public slots:
+ void setCodec( const QTextCodec *codec );
+ virtual void updateStatus();
+
+protected slots:
+ virtual void slotSendMsg(Kopete::Message &message, Kopete::ChatSession *);
+ QStringList sendMessage( const QString &msg );
+
+ virtual void chatSessionDestroyed();
+
+ void slotNewNickChange( const QString &oldnickname, const QString &newnickname);
+ void slotUserDisconnected( const QString &nickname, const QString &reason);
+
+ virtual void deleteContact();
+ virtual void privateMessage(IRCContact *from, IRCContact *to, const QString &message);
+ virtual void initConversation() {};
+
+ void receivedMessage( KIRC::Engine::ServerMessageType type,
+ const KIRC::EntityPtr &from,
+ const KIRC::EntityPtrList &to,
+ const QString &msg);
+
+protected:
+ KIRC::EntityPtr m_entity;
+
+ QString m_nickName;
+ Kopete::ChatSession *m_chatSession;
+
+ QPtrList<Kopete::Contact> mMyself;
+ Kopete::Message::MessageDirection execDir;
+};
+
+#endif
diff --git a/kopete/protocols/irc/irccontactmanager.cpp b/kopete/protocols/irc/irccontactmanager.cpp
new file mode 100644
index 00000000..7808668b
--- /dev/null
+++ b/kopete/protocols/irc/irccontactmanager.cpp
@@ -0,0 +1,297 @@
+/*
+ irccontactmanager.cpp - Manager of IRC Contacts
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "ircusercontact.h"
+#include "ircaccount.h"
+#include "irccontactmanager.h"
+#include "ircprotocol.h"
+#include "ircsignalhandler.h"
+
+#include "ircservercontact.h"
+#include "ircchannelcontact.h"
+
+#include "kircengine.h"
+
+#include <kopeteaccountmanager.h>
+#include <kopetemetacontact.h>
+#include <kopetecontactlist.h>
+#include <kopeteview.h>
+
+#include <kconfig.h>
+#include <kstandarddirs.h>
+
+#include <qtimer.h>
+
+IRCContactManager::IRCContactManager(const QString &nickName, IRCAccount *account, const char *name)
+ : QObject(account, name),
+ m_channels( QDict<IRCChannelContact>( 17, false ) ),
+ m_users( QDict<IRCUserContact>( 577, false ) ),
+ m_account( account )
+{
+ m_mySelf = findUser(nickName);
+
+ Kopete::MetaContact *m = new Kopete::MetaContact();
+// m->setTemporary( true );
+ m_myServer = new IRCServerContact(this, account->networkName(), m);
+
+ QObject::connect(account->engine(), SIGNAL(incomingMessage(const QString &, const QString &, const QString &)),
+ this, SLOT(slotNewMessage(const QString &, const QString &, const QString &)));
+
+ QObject::connect(account->engine(), SIGNAL(incomingPrivMessage(const QString &, const QString &, const QString &)),
+ this, SLOT(slotNewPrivMessage(const QString &, const QString &, const QString &)));
+
+ QObject::connect(account->engine(), SIGNAL(incomingNickChange(const QString &, const QString &)),
+ this, SLOT( slotNewNickChange(const QString&, const QString&)));
+
+ QObject::connect(account->engine(), SIGNAL(successfullyChangedNick(const QString &, const QString &)),
+ this, SLOT( slotNewNickChange(const QString &, const QString &)));
+
+ QObject::connect(account->engine(), SIGNAL(incomingUserOnline(const QString &)),
+ this, SLOT( slotIsonRecieved()));
+
+ QObject::connect(Kopete::ContactList::self(), SIGNAL(metaContactAdded( Kopete::MetaContact * )),
+ this, SLOT( slotContactAdded( Kopete::MetaContact* )));
+
+ socketTimeout = 15000;
+ QString timeoutPath = locate( "config", "kioslaverc" );
+ if( !timeoutPath.isEmpty() )
+ {
+ KConfig config( timeoutPath );
+ socketTimeout = config.readNumEntry( "ReadTimeout", 15 ) * 1000;
+ }
+
+ m_NotifyTimer = new QTimer(this);
+ QObject::connect(m_NotifyTimer, SIGNAL(timeout()),
+ this, SLOT(checkOnlineNotifyList()));
+ m_NotifyTimer->start(30000); // check online every 30sec
+
+ new IRCSignalHandler(this);
+}
+
+void IRCContactManager::slotNewNickChange(const QString &oldnick, const QString &newnick)
+{
+ IRCUserContact *c = m_users[ oldnick ];
+ if( c )
+ {
+ m_users.insert(newnick, c);
+ m_users.remove(oldnick);
+ }
+}
+
+void IRCContactManager::slotNewMessage(const QString &originating, const QString &channel, const QString &message)
+{
+ IRCContact *from = findUser(originating);
+ IRCChannelContact *to = findChannel(channel);
+ emit privateMessage(from, to, message);
+}
+
+void IRCContactManager::slotNewPrivMessage(const QString &originating, const QString &user, const QString &message)
+{
+ IRCContact *from = findUser(originating);
+ IRCUserContact *to = findUser(user);
+ emit privateMessage(from, to, message);
+}
+
+void IRCContactManager::unregister(Kopete::Contact *contact)
+{
+ unregisterChannel(contact, true);
+ unregisterUser(contact, true);
+}
+
+QValueList<IRCChannelContact*> IRCContactManager::findChannelsByMember( IRCUserContact *contact )
+{
+ QValueList<IRCChannelContact*> retVal;
+ for( QDictIterator<IRCChannelContact> it(m_channels); it.current(); ++it )
+ {
+ if( it.current()->manager(Kopete::Contact::CannotCreate) )
+ {
+ if( contact == m_mySelf )
+ retVal.push_back( it.current() );
+ else
+ {
+ bool c = true;
+
+ Kopete::ContactPtrList members = it.current()->manager()->members();
+ for( QPtrListIterator<Kopete::Contact> it2( members ); c && it2.current(); ++it2 )
+ {
+ if( it2.current() == contact )
+ {
+ retVal.push_back( it.current() );
+ c = false;
+ }
+ }
+ }
+ }
+ }
+
+ return retVal;
+}
+
+IRCChannelContact *IRCContactManager::findChannel(const QString &name, Kopete::MetaContact *m)
+{
+ IRCChannelContact *channel = m_channels[ name ];
+
+ if ( !channel )
+ {
+ if( !m )
+ {
+ m = new Kopete::MetaContact();
+ m->setTemporary( true );
+ }
+
+ channel = new IRCChannelContact(this, name, m);
+ m_channels.insert( name, channel );
+ QObject::connect(channel, SIGNAL(contactDestroyed(Kopete::Contact *)),
+ this, SLOT(unregister(Kopete::Contact *)));
+ }
+
+ return channel;
+}
+
+IRCChannelContact *IRCContactManager::existChannel( const QString &channel ) const
+{
+ return m_channels[ channel ];
+}
+
+void IRCContactManager::unregisterChannel(Kopete::Contact *contact, bool force )
+{
+ IRCChannelContact *channel = (IRCChannelContact*)contact;
+ if( force || (
+ channel!=0 &&
+ !channel->isChatting() &&
+ channel->metaContact()->isTemporary() ) )
+ {
+ m_channels.remove( channel->nickName() );
+ }
+}
+
+IRCUserContact *IRCContactManager::findUser(const QString &name, Kopete::MetaContact *m)
+{
+ IRCUserContact *user = m_users[name.section('!', 0, 0)];
+
+ if ( !user )
+ {
+ if( !m )
+ {
+ m = new Kopete::MetaContact();
+ m->setTemporary( true );
+ }
+
+ user = new IRCUserContact(this, name, m);
+ m_users.insert( name, user );
+ QObject::connect(user, SIGNAL(contactDestroyed(Kopete::Contact *)),
+ this, SLOT(unregister(Kopete::Contact *)));
+ }
+
+ return user;
+}
+
+IRCUserContact *IRCContactManager::existUser( const QString &user ) const
+{
+ return m_users[user];
+}
+
+IRCContact *IRCContactManager::findContact( const QString &id, Kopete::MetaContact *m )
+{
+ if( KIRC::Entity::isChannel(id) )
+ return findChannel( id, m );
+ else
+ return findUser( id, m );
+}
+
+IRCContact *IRCContactManager::existContact( const KIRC::Engine *engine, const QString &id )
+{
+ QDict<Kopete::Account> accounts = Kopete::AccountManager::self()->accounts( IRCProtocol::protocol() );
+ QDictIterator<Kopete::Account> it(accounts);
+ for( ; it.current(); ++it )
+ {
+ IRCAccount *account = (IRCAccount *)it.current();
+ if( account && account->engine() == engine )
+ return account->contactManager()->existContact(id);
+ }
+ return 0L;
+}
+
+IRCContact *IRCContactManager::existContact( const QString &id ) const
+{
+ if( KIRC::Entity::isChannel(id) )
+ return existChannel( id );
+ else
+ return existUser( id );
+}
+
+void IRCContactManager::unregisterUser(Kopete::Contact *contact, bool force )
+{
+ IRCUserContact *user = (IRCUserContact *)contact;
+ if( force || (
+ user!=0 &&
+ user!=mySelf() &&
+ !user->isChatting() &&
+ user->metaContact()->isTemporary() ) )
+ {
+ m_users.remove( user->nickName() );
+ }
+}
+
+void IRCContactManager::slotContactAdded( Kopete::MetaContact *contact )
+{
+ for( QPtrListIterator<Kopete::Contact> it( contact->contacts() ); it.current(); ++it )
+ {
+ if( it.current()->account() == m_account )
+ {
+ addToNotifyList( static_cast<IRCContact*>( it.current() )->nickName() );
+ }
+ }
+}
+
+void IRCContactManager::addToNotifyList(const QString &nick)
+{
+ if (!m_NotifyList.contains(nick.lower()))
+ {
+ m_NotifyList.append(nick);
+ checkOnlineNotifyList();
+ }
+}
+
+void IRCContactManager::removeFromNotifyList(const QString &nick)
+{
+ if (m_NotifyList.contains(nick.lower()))
+ m_NotifyList.remove(nick.lower());
+}
+
+void IRCContactManager::checkOnlineNotifyList()
+{
+ if( m_account->engine()->isConnected() )
+ {
+ isonRecieved = false;
+ m_account->engine()->ison( m_NotifyList );
+ //QTimer::singleShot( socketTimeout, this, SLOT( slotIsonTimeout() ) );
+ }
+}
+
+void IRCContactManager::slotIsonRecieved()
+{
+ isonRecieved = true;
+}
+
+void IRCContactManager::slotIsonTimeout()
+{
+ if( !isonRecieved )
+ m_account->engine()->quit("", true);
+}
+
+#include "irccontactmanager.moc"
diff --git a/kopete/protocols/irc/irccontactmanager.h b/kopete/protocols/irc/irccontactmanager.h
new file mode 100644
index 00000000..4a8ae05f
--- /dev/null
+++ b/kopete/protocols/irc/irccontactmanager.h
@@ -0,0 +1,117 @@
+/*
+ irccontactmanager.h - Manager of IRC Contacts
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef IRCCONTACTMANAGER_H
+#define IRCCONTACTMANAGER_H
+
+#include <qdict.h>
+#include <qobject.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+class IRCContact;
+class IRCAccount;
+
+class IRCServerContact;
+class IRCChannelContact;
+class IRCUserContact;
+
+namespace KIRC
+{
+class Engine;
+}
+
+namespace Kopete
+{
+class Contact;
+class MetaContact;
+}
+
+class KopeteView;
+
+class QTimer;
+
+/**
+ * @author Michel Hermier <michel.hermier@wanadoo.fr>
+ *
+ * This class is the repository for all the reference of the @ref IRCContact childs.
+ * It manage the life cycle of all the @ref IRCServerContact, @ref IRCChannelContact and @ref IRCUserContact objects for the given account.
+ */
+class IRCContactManager
+ : public QObject
+{
+ Q_OBJECT
+
+ public:
+ IRCContactManager(const QString &nickName, IRCAccount *account, const char *name=0);
+
+ IRCAccount *account() const { return m_account; }
+
+ IRCServerContact *myServer() const { return m_myServer; }
+ IRCUserContact *mySelf() const { return m_mySelf; }
+
+ IRCChannelContact *findChannel(const QString &channel, Kopete::MetaContact *m=0);
+ IRCChannelContact *existChannel(const QString &channel) const;
+
+ IRCUserContact *findUser(const QString &nick, Kopete::MetaContact *m=0);
+ IRCUserContact *existUser(const QString &nick) const;
+
+ IRCContact *findContact(const QString &nick, Kopete::MetaContact *m=0);
+ IRCContact *existContact( const QString &id ) const;
+
+ QValueList<IRCChannelContact*> findChannelsByMember( IRCUserContact *contact );
+
+ static IRCContact *existContact(const KIRC::Engine *engine, const QString &nick);
+
+ public slots:
+ void unregister(Kopete::Contact *contact);
+ void unregisterUser(Kopete::Contact *contact, bool force = false );
+ void unregisterChannel(Kopete::Contact *contact, bool force = false );
+
+ void addToNotifyList(const QString &nick);
+ void removeFromNotifyList(const QString &nick);
+ void checkOnlineNotifyList();
+
+ signals:
+ void privateMessage(IRCContact *from, IRCContact *to, const QString &message);
+
+ private slots:
+ void slotNewMessage(const QString &originating, const QString &channel, const QString &message);
+ void slotNewPrivMessage(const QString &originating, const QString &, const QString &message);
+ void slotIsonRecieved();
+ void slotIsonTimeout();
+ void slotNewNickChange(const QString &oldnick, const QString &newnick);
+ void slotContactAdded( Kopete::MetaContact *contact );
+
+ private:
+ QDict<IRCChannelContact> m_channels;
+ QDict<IRCUserContact> m_users;
+
+ IRCAccount *m_account;
+ IRCServerContact *m_myServer;
+ IRCUserContact *m_mySelf;
+
+ QStringList m_NotifyList;
+ QTimer *m_NotifyTimer;
+ bool isonRecieved;
+ int socketTimeout;
+
+ static const QRegExp isChannel;
+};
+
+#endif
+
diff --git a/kopete/protocols/irc/ircguiclient.cpp b/kopete/protocols/irc/ircguiclient.cpp
new file mode 100644
index 00000000..b4c36973
--- /dev/null
+++ b/kopete/protocols/irc/ircguiclient.cpp
@@ -0,0 +1,100 @@
+/*
+ ircguiclient.cpp
+
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <klocale.h>
+
+#include <kdeversion.h>
+#if KDE_IS_VERSION( 3, 1, 90 )
+ #include <kactioncollection.h>
+#else
+// ------------------------------------------------------------
+// TODO: UGLY HACK, remove when we drop KDE 3.1 compatibility
+#ifdef KDE_NO_COMPAT
+#undef KDE_NO_COMPAT
+#include <kaction.h>
+#define KDE_NO_COMPAT 1
+#endif
+// ------------------------------------------------------------
+#endif
+
+#include <qptrlist.h>
+#include <kdebug.h>
+#include <qdom.h>
+
+#include "kopetechatsession.h"
+#include "kcodecaction.h"
+#include "ircguiclient.h"
+#include "ircaccount.h"
+#include "irccontact.h"
+
+IRCGUIClient::IRCGUIClient( Kopete::ChatSession *parent ) : QObject(parent) , KXMLGUIClient(parent)
+{
+ Kopete::ContactPtrList members = parent->members();
+ if( members.count() > 0 )
+ {
+ m_user = static_cast<IRCContact*>( members.first() );
+
+ /***
+ FIXME: Why doesn't this work???? Have to use DOM hack below now...
+
+ setXMLFile("ircchatui.rc");
+
+ unplugActionList( "irccontactactionlist" );
+ QPtrList<KAction> *actions = m_user->customContextMenuActions( parent );
+ plugActionList( "irccontactactionlist", *actions );
+ delete actions;
+ */
+
+ setXMLFile("ircchatui.rc");
+
+ QDomDocument doc = domDocument();
+ QDomNode menu = doc.documentElement().firstChild().firstChild();
+ QPtrList<KAction> *actions = m_user->customContextMenuActions( parent );
+ if( actions )
+ {
+ for( KAction *a = actions->first(); a; a = actions->next() )
+ {
+ actionCollection()->insert( a );
+ QDomElement newNode = doc.createElement( "Action" );
+ newNode.setAttribute( "name", a->name() );
+ menu.appendChild( newNode );
+ }
+ }
+ else
+ {
+ kdDebug(14120) << k_funcinfo << "Actions == 0" << endl;
+ }
+
+ delete actions;
+
+ setDOMDocument( doc );
+ }
+ else
+ {
+ kdDebug(14120) << k_funcinfo << "Members == 0" << endl;
+ }
+}
+
+IRCGUIClient::~IRCGUIClient()
+{
+}
+
+void IRCGUIClient::slotSelectCodec( const QTextCodec *codec )
+{
+ m_user->setCodec( codec );
+}
+
+#include "ircguiclient.moc"
diff --git a/kopete/protocols/irc/ircguiclient.h b/kopete/protocols/irc/ircguiclient.h
new file mode 100644
index 00000000..b81aa632
--- /dev/null
+++ b/kopete/protocols/irc/ircguiclient.h
@@ -0,0 +1,42 @@
+/*
+ ircguiclient.h
+
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+#ifndef IRCGUICLIENT_H
+#define IRCGUICLIENT_H
+
+#include <qobject.h>
+#include <kxmlguiclient.h>
+
+namespace Kopete { class ChatSession; }
+class IRCContact;
+
+/**
+ *@author Jason Keirstead
+ */
+class IRCGUIClient : public QObject , public KXMLGUIClient
+{
+ Q_OBJECT
+ public:
+ IRCGUIClient( Kopete::ChatSession *parent = 0 );
+ ~IRCGUIClient();
+
+ private slots:
+ void slotSelectCodec( const QTextCodec *codec );
+
+ private:
+ IRCContact *m_user;
+};
+
+#endif
diff --git a/kopete/protocols/irc/ircnetworks.xml b/kopete/protocols/irc/ircnetworks.xml
new file mode 100644
index 00000000..c743e9e0
--- /dev/null
+++ b/kopete/protocols/irc/ircnetworks.xml
@@ -0,0 +1,1463 @@
+<!DOCTYPE irc-networks>
+<networks>
+ <network>
+ <name>AnyNet</name>
+ <description>AnyNet</description>
+ <servers>
+ <server>
+ <host>irc.anynet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>IRCNet</name>
+ <description>IRCNet</description>
+ <servers>
+ <server>
+ <host>eu.ircnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.ircd.it</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>au.ircnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.stealth.net</host>
+ <port>6660</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>KewlNet</name>
+ <description>KewlNet</description>
+ <servers>
+ <server>
+ <host>irc.kewl.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>la.defense.fr.eu.kewl.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>nanterre.fr.eu.kewl.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>TrekLink</name>
+ <description>TrekLink</description>
+ <servers>
+ <server>
+ <host>neutron.treklink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.treklink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>SlashNET</name>
+ <description>SlashNET</description>
+ <servers>
+ <server>
+ <host>irc.slashnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>area51.slashnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>moo.slashnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>radon.slashnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>devnull.slashnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>NeverNET</name>
+ <description>NeverNET</description>
+ <servers>
+ <server>
+ <host>irc.nevernet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>imagine.nevernet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>dimension.nevernet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>universe.nevernet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>wayland.nevernet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>forte.nevernet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>CoolChat</name>
+ <description>CoolChat</description>
+ <servers>
+ <server>
+ <host>irc.coolchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>unix.coolchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>south.coolchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>toronto.coolchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>UnderNet</name>
+ <description>UnderNet</description>
+ <servers>
+ <server>
+ <host>us.undernet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>eu.undernet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>MagicStar</name>
+ <description>MagicStar</description>
+ <servers>
+ <server>
+ <host>irc.magicstar.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>PTNet, UNI</name>
+ <description>PTNet, UNI</description>
+ <servers>
+ <server>
+ <host>irc.PTNet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>rccn.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>uevora.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>umoderna.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ist.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>aaum.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>uc.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ualg.ptnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>madinfo.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>isep.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ua.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ipg.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>isec.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>utad.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>iscte.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ubi.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>FDFNet</name>
+ <description>FDFNet</description>
+ <servers>
+ <server>
+ <host>irc.fdfnet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.eu.fdfnet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>FEFNet</name>
+ <description>FEFNet</description>
+ <servers>
+ <server>
+ <host>irc.fef.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.villagenet.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.ggn.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.vendetta.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>KrushNet.Org</name>
+ <description>KrushNet.Org</description>
+ <servers>
+ <server>
+ <host>Jeffersonville.IN.US.KrushNet.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Auckland.NZ.KrushNet.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Hastings.NZ.KrushNet.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Seattle-R.WA.US.KrushNet.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Minneapolis.MN.US.KrushNet.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Cullowhee.NC.US.KrushNet.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Asheville-R.NC.US.KrushNet.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>San-Antonio.TX.US.KrushNet.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>AfterNET</name>
+ <description>AfterNET</description>
+ <servers>
+ <server>
+ <host>irc.afternet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ic5.eu.afternet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>baltimore.md.us.afternet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>boston.afternet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>DragonLynk</name>
+ <description>DragonLynk</description>
+ <servers>
+ <server>
+ <host>irc.dragonlynk.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>EFNet</name>
+ <description>EFNet</description>
+ <servers>
+ <server>
+ <host>us.rr.efnet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.arcti.ca</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>eu.rr.efnet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>au.rr.efnet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.efnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.light.se</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.stanford.edu</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.solidstreaming.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>IrcLink</name>
+ <description>IrcLink</description>
+ <servers>
+ <server>
+ <host>irc.irclink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Alesund.no.eu.irclink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Oslo.no.eu.irclink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>frogn.no.eu.irclink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>tonsberg.no.eu.irclink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>AstroLINK.Org</name>
+ <description>AstroLINK.Org</description>
+ <servers>
+ <server>
+ <host>irc.astrolink.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>GalaxyNet</name>
+ <description>GalaxyNet</description>
+ <servers>
+ <server>
+ <host>sprynet.us.galaxynet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>atlanta.ga.us.galaxynet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.galaxynet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>SceneNet</name>
+ <description>SceneNet</description>
+ <servers>
+ <server>
+ <host>irc.scene.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.eu.scene.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.us.scene.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>EUIrc</name>
+ <description>EUIrc</description>
+ <servers>
+ <server>
+ <host>irc.euirc.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.ham.de.euirc.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.ber.de.euirc.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.ffm.de.euirc.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.bre.de.euirc.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.hes.de.euirc.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.vie.at.euirc.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.inn.at.euirc.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.bas.ch.euirc.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>RebelChat</name>
+ <description>RebelChat</description>
+ <servers>
+ <server>
+ <host>irc.rebelchat.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>interquad.rebelchat.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>rebel.rebelchat.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>bigcove.rebelchat.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>ARCNet</name>
+ <description>ARCNet</description>
+ <servers>
+ <server>
+ <host>se1.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>us1.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>us2.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>us3.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ca1.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>de1.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>de3.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ch1.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>be1.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>nl3.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>uk1.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>uk2.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>uk3.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>fr1.arcnet.vapor.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>Librenet</name>
+ <description>Librenet</description>
+ <servers>
+ <server>
+ <host>irc.librenet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>famipow.fr.librenet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ielf.fr.librenet.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>SubCultNet</name>
+ <description>SubCultNet</description>
+ <servers>
+ <server>
+ <host>irc.subcult.ch</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.phuncrew.ch</host>
+ <port>6668</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.mgz.ch</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>freenode</name>
+ <description>freenode, a service by Peer-directed Projects Center</description>
+ <servers>
+ <server>
+ <host>irc.kde.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>chat.freenode.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>chat.us.freenode.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>chat.eu.freenode.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>chat.au.freenode.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>OFTC</name>
+ <description>The Open and Free Technology Community</description>
+ <servers>
+ <server>
+ <host>irc.oftc.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ircs.oftc.net</host>
+ <port>9999</port>
+ <useSSL>true</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>XWorld</name>
+ <description>XWorld</description>
+ <servers>
+ <server>
+ <host>Buffalo.NY.US.XWorld.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Minneapolis.MN.US.Xworld.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>PalmSprings.CA.US.XWorld.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Quebec.QC.CA.XWorld.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Rochester.NY.US.XWorld.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Bayern.DE.EU.XWorld.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Chicago.IL.US.XWorld.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>ChatNet</name>
+ <description>ChatNet</description>
+ <servers>
+ <server>
+ <host>US.ChatNet.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>EU.ChatNet.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>Neohorizon</name>
+ <description>Neohorizon</description>
+ <servers>
+ <server>
+ <host>irc.nhn.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>QChat.net</name>
+ <description>QChat.net</description>
+ <servers>
+ <server>
+ <host>irc.qchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>StarChat</name>
+ <description>StarChat</description>
+ <servers>
+ <server>
+ <host>irc.starchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>galatea.starchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>stargate.starchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>powerzone.starchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>utopia.starchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>cairns.starchat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>Infinity-IRC.org</name>
+ <description>Infinity-IRC.org</description>
+ <servers>
+ <server>
+ <host>Atlanta.GA.US.Infinity-IRC.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Babylon.NY.US.Infinity-IRC.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Dewspeak.TX.US.Infinity-IRC.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Sunshine.Ca.US.Infinity-IRC.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>MNC.MD.Infinity-IRC.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>IRC.Infinity-IRC.Org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>HabberNet</name>
+ <description>HabberNet</description>
+ <servers>
+ <server>
+ <host>irc.habber.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>Mellorien</name>
+ <description>Mellorien</description>
+ <servers>
+ <server>
+ <host>Irc.mellorien.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>us.mellorien.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>eu.mellorien.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>DwarfStarNet</name>
+ <description>DwarfStarNet</description>
+ <servers>
+ <server>
+ <host>IRC.dwarfstar.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>US.dwarfstar.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>EU.dwarfstar.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>AU.dwarfstar.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>ChatJunkiesNet</name>
+ <description>ChatJunkiesNet</description>
+ <servers>
+ <server>
+ <host>irc.xchat.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>us.xchat.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>OtherNet</name>
+ <description>OtherNet</description>
+ <servers>
+ <server>
+ <host>irc.othernet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>AxeNet</name>
+ <description>AxeNet</description>
+ <servers>
+ <server>
+ <host>irc.axenet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>angel.axenet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>energy.axenet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>python.axenet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>unsecurity.org</name>
+ <description>unsecurity.org</description>
+ <servers>
+ <server>
+ <host>irc.unsecurity.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>wc.unsecurity.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>thegift.unsecurity.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>sysgate.unsecurity.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>DALNet</name>
+ <description>DALNet</description>
+ <servers>
+ <server>
+ <host>irc.dal.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.eu.dal.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>AustNet</name>
+ <description>AustNet</description>
+ <servers>
+ <server>
+ <host>us.austnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ca.austnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>au.austnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>PTNet, ISP's</name>
+ <description>PTNet, ISP's</description>
+ <servers>
+ <server>
+ <host>irc.PTNet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>rccn.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>EUnet.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>madinfo.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>netc2.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>netc1.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>teleweb.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>netway.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>telepac1.ptnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>services.ptnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>esoterica.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ip-hub.ptnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>telepac1.ptnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>nortenet.PTnet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>NixHelpNet</name>
+ <description>NixHelpNet</description>
+ <servers>
+ <server>
+ <host>irc.nixhelp.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>us.nixhelp.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>uk.nixhelp.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>uk2.nixhelp.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>uk3.nixhelp.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>nl.nixhelp.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>ca.ld.nixhelp.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>us.co.nixhelp.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>us.ca.nixhelp.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>us.pa.nixhelp.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>Gamma Force</name>
+ <description>Gamma Force</description>
+ <servers>
+ <server>
+ <host>irc.gammaforce.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>sphinx.or.us.gammaforce.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>monolith.ok.us.gammaforce.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>PTlink</name>
+ <description>PTlink</description>
+ <servers>
+ <server>
+ <host>irc.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>dark.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>uc.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>kungfoo.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>matrix.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>illusion.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>Cibercultura.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>aaia.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>gaesi.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>BuBix.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>montijo.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>queima.PTlink.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>OzNet</name>
+ <description>OzNet</description>
+ <servers>
+ <server>
+ <host>sydney.oz.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>melbourne.oz.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>FoxChat</name>
+ <description>FoxChat</description>
+ <servers>
+ <server>
+ <host>irc.FoxChat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.ac6.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>beastie.ac6.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>wild.FoxChat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>roadkill.FoxChat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>slick.FoxChat.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>AzzurraNet</name>
+ <description>AzzurraNet</description>
+ <servers>
+ <server>
+ <host>irc.bitchx.it</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.jnet.it</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.net36.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.noflyzone.net</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.swappoint.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.azzurra.com</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.leonet.it</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.libero.it</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.estranet.it</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.filmaker.it</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+ <network>
+ <name>AbleNET</name>
+ <description>AbleNET</description>
+ <servers>
+ <server>
+ <host>california.ablenet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>amazon.ablenet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>agora.ablenet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>extreme.ablenet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ <server>
+ <host>irc.ablenet.org</host>
+ <port>6667</port>
+ <useSSL>false</useSSL>
+ </server>
+ </servers>
+ </network>
+</networks>
diff --git a/kopete/protocols/irc/ircprotocol.cpp b/kopete/protocols/irc/ircprotocol.cpp
new file mode 100644
index 00000000..176c74d7
--- /dev/null
+++ b/kopete/protocols/irc/ircprotocol.cpp
@@ -0,0 +1,1241 @@
+/*
+ ircprotocol - IRC Protocol
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+
+ Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "ircaccount.h"
+#include "ircprotocol.h"
+#include "ksparser.h"
+
+#include "ircaddcontactpage.h"
+#include "ircchannelcontact.h"
+#include "irccontactmanager.h"
+
+#include "networkconfig.h"
+#include "channellist.h"
+#include "ircguiclient.h"
+#include "ircusercontact.h"
+#include "irceditaccountwidget.h"
+#include "irctransferhandler.h"
+
+#include "kircengine.h"
+
+#include "kopeteaccountmanager.h"
+#include "kopetecommandhandler.h"
+#include "kopeteglobal.h"
+#include "kopeteonlinestatusmanager.h"
+#include "kopeteonlinestatus.h"
+#include "kopeteview.h"
+#include "kopeteuiglobal.h"
+
+#undef KDE_NO_COMPAT
+#include <kaction.h>
+#include <kcharsets.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <kglobal.h>
+#include <kinputdialog.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+#include <kuser.h>
+
+#include <qcheckbox.h>
+#include <qdom.h>
+#include <qfile.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qregexp.h>
+#include <qspinbox.h>
+#include <qvalidator.h>
+
+#include <dom/html_element.h>
+#include <unistd.h>
+
+typedef KGenericFactory<IRCProtocol> IRCProtocolFactory;
+K_EXPORT_COMPONENT_FACTORY( kopete_irc, IRCProtocolFactory( "kopete_irc" ) )
+
+IRCProtocol *IRCProtocol::s_protocol = 0L;
+
+IRCProtocolHandler::IRCProtocolHandler() : Kopete::MimeTypeHandler( false )
+{
+ registerAsProtocolHandler( QString::fromLatin1("irc") );
+}
+
+void IRCProtocolHandler::handleURL( const KURL &url ) const
+{
+ kdDebug(14120) << url << endl;
+ if( !url.isValid() )
+ return;
+
+ unsigned short port = url.port();
+ if( port == 0 )
+ port = 6667;
+
+ QString chan = url.url().section('/',3);
+ if( chan.isEmpty() )
+ return;
+
+ KUser user( getuid() );
+ QString accountId = QString::fromLatin1("%1@%2:%3").arg(
+ user.loginName(),
+ url.host(),
+ QString::number(port)
+ );
+
+ kdDebug(14120) << accountId << endl;
+
+ IRCAccount *newAccount = new IRCAccount( IRCProtocol::protocol(), accountId, chan );
+ newAccount->setNickName( user.loginName() );
+ newAccount->setUserName( user.loginName() );
+ newAccount->connect();
+}
+
+IRCProtocol::IRCProtocol( QObject *parent, const char *name, const QStringList & /* args */ )
+: Kopete::Protocol( IRCProtocolFactory::instance(), parent, name ),
+
+ m_ServerStatusOnline(Kopete::OnlineStatus::Online,
+ 100, this, OnlineServer, QString::null, i18n("Online")),
+ m_ServerStatusOffline(Kopete::OnlineStatus::Offline,
+ 90, this, OfflineServer, QString::null, i18n("Offline")),
+
+ m_ChannelStatusOnline(Kopete::OnlineStatus::Online,
+ 80, this, OnlineChannel, QString::null, i18n("Online")),
+ m_ChannelStatusOffline(Kopete::OnlineStatus::Offline,
+ 70, this, OfflineChannel, QString::null, i18n("Offline")),
+
+ m_UserStatusOpVoice(Kopete::OnlineStatus::Online,
+ 60, this, Online | Operator | Voiced, QStringList::split(' ',"irc_voice irc_op"), i18n("Op")),
+ m_UserStatusOpVoiceAway(Kopete::OnlineStatus::Away,
+ 55, this, Online | Operator | Voiced | Away,
+ QStringList::split(' ',"irc_voice irc_op contact_away_overlay"), i18n("Away")),
+
+ m_UserStatusOp(Kopete::OnlineStatus::Online,
+ 50, this, Online | Operator, "irc_op", i18n("Op")),
+ m_UserStatusOpAway(Kopete::OnlineStatus::Away,
+ 45, this, Online | Operator | Away,
+ QStringList::split(' ',"irc_op contact_away_overlay"), i18n("Away")),
+
+ m_UserStatusVoice(Kopete::OnlineStatus::Online,
+ 40, this, Online | Voiced, "irc_voice", i18n("Voice")),
+ m_UserStatusVoiceAway(Kopete::OnlineStatus::Away,
+ 35, this, Online | Voiced | Away,
+ QStringList::split(' ',"irc_voice contact_away_overlay"), i18n("Away")),
+
+ m_UserStatusOnline(Kopete::OnlineStatus::Online,
+ 25, this, Online, QString::null, i18n("Online"), i18n("Online"), Kopete::OnlineStatusManager::Online),
+
+ m_UserStatusAway(Kopete::OnlineStatus::Away,
+ 2, this, Online | Away, "contact_away_overlay",
+ i18n("Away"), i18n("Away"), Kopete::OnlineStatusManager::Away),
+ m_UserStatusConnecting(Kopete::OnlineStatus::Connecting,
+ 1, this, Connecting, "irc_connecting", i18n("Connecting")),
+ m_UserStatusOffline(Kopete::OnlineStatus::Offline,
+ 0, this, Offline, QString::null, i18n("Offline"), i18n("Offline"), Kopete::OnlineStatusManager::Offline),
+
+ m_StatusUnknown(Kopete::OnlineStatus::Unknown,
+ 999, this, 999, "status_unknown", i18n("Status not available")),
+
+ propChannelTopic(QString::fromLatin1("channelTopic"), i18n("Topic"), QString::null, false, true ),
+ propChannelMembers(QString::fromLatin1("channelMembers"), i18n("Members")),
+ propHomepage(QString::fromLatin1("homePage"), i18n("Home Page")),
+ propLastSeen(Kopete::Global::Properties::self()->lastSeen()),
+ propUserInfo(QString::fromLatin1("userInfo"), i18n("IRC User")),
+ propServer(QString::fromLatin1("ircServer"), i18n("IRC Server")),
+ propChannels( QString::fromLatin1("ircChannels"), i18n("IRC Channels")),
+ propHops(QString::fromLatin1("ircHops"), i18n("IRC Hops")),
+ propFullName(QString::fromLatin1("FormattedName"), i18n("Full Name")),
+ propIsIdentified(QString::fromLatin1("identifiedUser"), i18n("User Is Authenticated"))
+{
+// kdDebug(14120) << k_funcinfo << endl;
+
+ s_protocol = this;
+
+ //m_status = m_unknownStatus = m_Unknown;
+
+ addAddressBookField("messaging/irc", Kopete::Plugin::MakeIndexField);
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("raw"),
+ SLOT( slotRawCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /raw <text> - Sends the text in raw form to the server."), 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("quote"),
+ SLOT( slotQuoteCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /quote <text> - Sends the text in quoted form to the server."), 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("ctcp"),
+ SLOT( slotCtcpCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /ctcp <nick> <message> - Send the CTCP message to nick<action>."), 2 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("ping"),
+ SLOT( slotPingCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /ping <nickname> - Alias for /CTCP <nickname> PING."), 1, 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("motd"),
+ SLOT( slotMotdCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /motd [<server>] - Shows the message of the day for the current or the given server.") );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("list"),
+ SLOT( slotListCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /list - List the public channels on the server.") );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("join"),
+ SLOT( slotJoinCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /join <#channel 1> [<password>] - Joins the specified channel."), 1, 2 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("topic"),
+ SLOT( slotTopicCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /topic [<topic>] - Sets and/or displays the topic for the active channel.") );
+
+ //FIXME: Update help text
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("whois"),
+ SLOT( slotWhoisCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /whois <nickname> - Display whois info on this user."), 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("whowas"),
+ SLOT( slotWhoWasCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /whowas <nickname> - Display whowas info on this user."), 1, 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("who"),
+ SLOT( slotWhoCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /who <nickname|channel> - Display who info on this user/channel."), 1, 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("query"),
+ SLOT( slotQueryCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /query <nickname> [<message>] - Open a private chat with this user."), 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("mode"),
+ SLOT( slotModeCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /mode <channel> <modes> - Set modes on the given channel."), 2 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("nick"),
+ SLOT( slotNickCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /nick <nickname> - Change your nickname to the given one."), 1, 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("me"),
+ SLOT( slotMeCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /me <action> - Do something."), 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("ame"),
+ SLOT( slotAllMeCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /ame <action> - Do something in every open chat."), 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("kick"),
+ SLOT( slotKickCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /kick <nickname> [<reason>] - Kick someone from the channel (requires operator status).")
+ , 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("ban"),
+ SLOT( slotBanCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /ban <mask> - Add someone to this channel's ban list. (requires operator status)."),
+ 1, 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerAlias( this, QString::fromLatin1("bannick"),
+ QString::fromLatin1("ban %1!*@*"),
+ i18n("USAGE: /bannick <nickname> - Add someone to this channel's ban list. Uses the hostmask nickname!*@* (requires operator status)."), Kopete::CommandHandler::SystemAlias, 1, 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("op"),
+ SLOT( slotOpCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /op <nickname 1> [<nickname 2> <...>] - Give channel operator status to someone (requires operator status)."),
+ 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("deop"),
+ SLOT( slotDeopCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /deop <nickname> [<nickname 2> <...>]- Remove channel operator status from someone (requires operator status)."), 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("voice"),
+ SLOT( slotVoiceCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /voice <nickname> [<nickname 2> <...>]- Give channel voice status to someone (requires operator status)."),
+ 1);
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("devoice"),
+ SLOT( slotDevoiceCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /devoice <nickname> [<nickname 2> <...>]- Remove channel voice status from someone (requires operator status)."), 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("quit"),
+ SLOT( slotQuitCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /quit [<reason>] - Disconnect from IRC, optionally leaving a message.") );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("part"),
+ SLOT( slotPartCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /part [<reason>] - Part from a channel, optionally leaving a message.") );
+
+ Kopete::CommandHandler::commandHandler()->registerCommand( this, QString::fromLatin1("invite"),
+ SLOT( slotInviteCommand( const QString &, Kopete::ChatSession*) ),
+ i18n("USAGE: /invite <nickname> [<channel>] - Invite a user to join a channel."), 1 );
+
+ Kopete::CommandHandler::commandHandler()->registerAlias( this, QString::fromLatin1("j"),
+ QString::fromLatin1("join %1"),
+ i18n("USAGE: /j <#channel 1> [<password>] - Alias for JOIN."), Kopete::CommandHandler::SystemAlias,
+ 1, 2 );
+
+ Kopete::CommandHandler::commandHandler()->registerAlias( this, QString::fromLatin1("msg"),
+ QString::fromLatin1("query %s"),
+ i18n("USAGE: /msg <nickname> [<message>] - Alias for QUERY <nickname> <message>."), Kopete::CommandHandler::SystemAlias, 1 );
+
+ QObject::connect( Kopete::ChatSessionManager::self(), SIGNAL(aboutToDisplay(Kopete::Message &)),
+ this, SLOT(slotMessageFilter(Kopete::Message &)) );
+
+ QObject::connect( Kopete::ChatSessionManager::self(), SIGNAL( viewCreated( KopeteView* ) ),
+ this, SLOT( slotViewCreated( KopeteView* ) ) );
+
+ setCapabilities( Kopete::Protocol::RichBFormatting | Kopete::Protocol::RichUFormatting | Kopete::Protocol::RichColor );
+
+ netConf = 0L;
+
+ slotReadNetworks();
+
+ m_protocolHandler = new IRCProtocolHandler();
+
+ IRCTransferHandler::self(); // Initiate the transfer handling system.
+}
+
+IRCProtocol * IRCProtocol::protocol()
+{
+ return s_protocol;
+}
+
+IRCProtocol::~IRCProtocol()
+{
+ delete m_protocolHandler;
+}
+
+const Kopete::OnlineStatus IRCProtocol::statusLookup( IRCStatus status ) const
+{
+ kdDebug(14120) << k_funcinfo << "Looking up status for " << status << endl;
+
+ switch( status )
+ {
+ case Offline:
+ return m_UserStatusOffline;
+ case Connecting:
+ return m_UserStatusConnecting;
+
+ // Regular user
+ case Online:
+ return m_UserStatusOnline;
+ case Online | Away:
+ return m_UserStatusAway;
+
+ // Voiced
+ case Online | Voiced:
+ return m_UserStatusVoice;
+ case Online | Away | Voiced:
+ return m_UserStatusVoiceAway;
+
+ // Operator
+ case Online | Operator:
+ return m_UserStatusOp;
+ case Online | Away | Operator:
+ return m_UserStatusOpAway;
+ case Online | Operator | Voiced:
+ return m_UserStatusOpVoice;
+ case Online | Operator | Voiced | Away:
+ return m_UserStatusOpVoiceAway;
+
+ // Server
+ case OnlineServer:
+ return m_ServerStatusOnline;
+ case OfflineServer:
+ return m_ServerStatusOffline;
+
+ // Channel
+ case OnlineChannel:
+ return m_ChannelStatusOnline;
+ case OfflineChannel:
+ return m_ChannelStatusOffline;
+
+ default:
+ return m_StatusUnknown;
+ }
+}
+
+void IRCProtocol::slotViewCreated( KopeteView *view )
+{
+ if( view->msgManager()->protocol() == this )
+ new IRCGUIClient( view->msgManager() );
+}
+
+void IRCProtocol::slotMessageFilter( Kopete::Message &msg )
+{
+ if( msg.from()->protocol() == this )
+ {
+ QString messageText = msg.escapedBody();
+
+ //Add right click for channels, only replace text not in HTML tags
+ messageText.replace( QRegExp( QString::fromLatin1("(?![^<]+>)(#[^#\\s]+)(?![^<]+>)") ), QString::fromLatin1("<span class=\"KopeteLink\" type=\"IRCChannel\">\\1</span>") );
+
+ msg.setBody( messageText, Kopete::Message::RichText );
+ }
+}
+
+QPtrList<KAction> *IRCProtocol::customChatWindowPopupActions( const Kopete::Message &m, DOM::Node &n )
+{
+ DOM::HTMLElement e = n;
+
+ //isNull checks that the cast was successful
+ if( !e.isNull() && !m.to().isEmpty() )
+ {
+ activeNode = n;
+ activeAccount = static_cast<IRCAccount*>( m.from()->account() );
+ if( e.getAttribute( QString::fromLatin1("type") ) == QString::fromLatin1("IRCChannel") )
+ return activeAccount->contactManager()->findChannel(
+ e.innerText().string() )->customContextMenuActions();
+ }
+
+ return 0L;
+}
+
+AddContactPage *IRCProtocol::createAddContactWidget(QWidget *parent, Kopete::Account *account)
+{
+ return new IRCAddContactPage(parent,static_cast<IRCAccount*>(account));
+}
+
+KopeteEditAccountWidget *IRCProtocol::createEditAccountWidget(Kopete::Account *account, QWidget *parent)
+{
+ return new IRCEditAccountWidget(this, static_cast<IRCAccount*>(account),parent);
+}
+
+Kopete::Account *IRCProtocol::createNewAccount(const QString &accountId)
+{
+ return new IRCAccount( this, accountId );
+}
+
+Kopete::Contact *IRCProtocol::deserializeContact( Kopete::MetaContact *metaContact, const QMap<QString, QString> &serializedData,
+ const QMap<QString, QString> & /* addressBookData */ )
+{
+ kdDebug(14120) << k_funcinfo << endl;
+
+ QString contactId = serializedData[ "contactId" ];
+ QString displayName = serializedData[ "displayName" ];
+
+ if( displayName.isEmpty() )
+ displayName = contactId;
+
+ QDict<Kopete::Account> accounts = Kopete::AccountManager::self()->accounts( this );
+ if( !accounts.isEmpty() )
+ {
+ Kopete::Account *a = accounts[ serializedData[ "accountId" ] ];
+ if( a )
+ {
+ a->addContact( contactId, metaContact );
+ return a->contacts()[contactId];
+ }
+ else
+ kdDebug(14120) << k_funcinfo << serializedData[ "accountId" ] << " was a contact's account,"
+ " but we don't have it in the accounts list" << endl;
+ }
+ else
+ kdDebug(14120) << k_funcinfo << "No accounts loaded!" << endl;
+
+ return 0;
+}
+
+void IRCProtocol::slotRawCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ IRCAccount *account = static_cast<IRCAccount*>( manager->account() );
+
+ if (!args.isEmpty())
+ {
+ account->engine()->writeRawMessage(args);
+ }
+ else
+ {
+ account->appendMessage(i18n("You must enter some text to send to the server."),
+ IRCAccount::ErrorReply );
+ }
+}
+
+void IRCProtocol::slotQuoteCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ IRCAccount *account = static_cast<IRCAccount*>( manager->account() );
+
+ if( !args.isEmpty() )
+ {
+ account->engine()->writeMessage( args );
+ }
+ else
+ {
+ account->appendMessage(i18n("You must enter some text to send to the server."),
+ IRCAccount::ErrorReply );
+ }
+}
+
+void IRCProtocol::slotCtcpCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ if( !args.isEmpty() )
+ {
+ QString user = args.section( ' ', 0, 0 );
+ QString message = args.section( ' ', 1 );
+ static_cast<IRCAccount*>( manager->account() )->engine()->writeCtcpQueryMessage( user, QString::null, message );
+ }
+}
+
+void IRCProtocol::slotMotdCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ QStringList argsList = Kopete::CommandHandler::parseArguments( args );
+ static_cast<IRCAccount*>( manager->account() )->engine()->motd(argsList.front());
+}
+
+void IRCProtocol::slotPingCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ QStringList argsList = Kopete::CommandHandler::parseArguments(args);
+ static_cast<IRCAccount*>( manager->account() )->engine()->CtcpRequest_ping(argsList.front());
+}
+
+void IRCProtocol::slotListCommand( const QString &/*args*/, Kopete::ChatSession *manager )
+{
+ static_cast<IRCAccount*>( manager->account() )->listChannels();
+}
+
+void IRCProtocol::slotTopicCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ Kopete::ContactPtrList members = manager->members();
+ IRCChannelContact *chan = dynamic_cast<IRCChannelContact*>( members.first() );
+ if( chan )
+ {
+ if( !args.isEmpty() )
+ chan->setTopic( args );
+ else
+ {
+ static_cast<IRCAccount*>(manager->account())->engine()->
+ writeRawMessage(QString::fromLatin1("TOPIC %1").arg(chan->nickName()));
+ }
+ }
+ else
+ {
+ static_cast<IRCAccount*>( manager->account() )->appendMessage(
+ i18n("You must be in a channel to use this command."), IRCAccount::ErrorReply );
+ }
+}
+
+void IRCProtocol::slotJoinCommand( const QString &arg, Kopete::ChatSession *manager )
+{
+ QStringList args = Kopete::CommandHandler::parseArguments( arg );
+ if( KIRC::Entity::isChannel(args[0]) )
+ {
+ IRCChannelContact *chan = static_cast<IRCAccount*>( manager->account() )->contactManager()->findChannel( args[0] );
+ if( args.count() == 2 )
+ chan->setPassword( args[1] );
+ static_cast<IRCAccount*>( manager->account() )->engine()->join(args[0], chan->password());
+ }
+ else
+ {
+ static_cast<IRCAccount*>( manager->account() )->appendMessage(
+ i18n("\"%1\" is an invalid channel. Channels must start with '#', '!', '+', or '&'.")
+ .arg(args[0]), IRCAccount::ErrorReply );
+ }
+}
+
+void IRCProtocol::slotInviteCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ IRCChannelContact *c = 0L;
+ QStringList argsList = Kopete::CommandHandler::parseArguments( args );
+
+ if( argsList.count() > 1 )
+ {
+ if( KIRC::Entity::isChannel(argsList[1]) )
+ {
+ c = static_cast<IRCAccount*>( manager->account() )->contactManager()->
+ findChannel( argsList[1] );
+ }
+ else
+ {
+ static_cast<IRCAccount*>( manager->account() )->appendMessage(
+ i18n("\"%1\" is an invalid channel. Channels must start with '#', '!', '+', or '&'.")
+ .arg(argsList[1]), IRCAccount::ErrorReply );
+ }
+ }
+ else
+ {
+ Kopete::ContactPtrList members = manager->members();
+ c = dynamic_cast<IRCChannelContact*>( members.first() );
+ }
+
+ if( c && c->manager()->contactOnlineStatus( manager->myself() ) == m_UserStatusOp )
+ {
+ static_cast<IRCAccount*>( manager->account() )->engine()->writeMessage(
+ QString::fromLatin1("INVITE %1 %2").arg( argsList[0] ).
+ arg( c->nickName() )
+ );
+ }
+ else
+ {
+ static_cast<IRCAccount*>( manager->account() )->appendMessage(
+ i18n("You must be a channel operator to perform this operation."), IRCAccount::ErrorReply );
+ }
+}
+
+void IRCProtocol::slotQueryCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ QString user = args.section( ' ', 0, 0 );
+ QString rest = args.section( ' ', 1 );
+
+ if( !KIRC::Entity::isChannel(user) )
+ {
+ IRCUserContact *c = static_cast<IRCAccount*>( manager->account() )->
+ contactManager()->findUser( user );
+ c->startChat();
+ if( !rest.isEmpty() )
+ {
+ Kopete::Message msg( c->manager()->myself(), c->manager()->members(), rest,
+ Kopete::Message::Outbound, Kopete::Message::PlainText, CHAT_VIEW);
+ c->manager()->sendMessage(msg);
+ }
+ }
+ else
+ {
+ static_cast<IRCAccount*>( manager->account() )->appendMessage(
+ i18n("\"%1\" is an invalid nickname. Nicknames must not start with '#','!','+', or '&'.").arg(user),
+ IRCAccount::ErrorReply );
+ }
+}
+
+void IRCProtocol::slotWhoisCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ static_cast<IRCAccount*>( manager->account() )->engine()->whois( args );
+ static_cast<IRCAccount*>( manager->account() )->setCurrentCommandSource( manager );
+}
+
+void IRCProtocol::slotWhoCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ QStringList argsList = Kopete::CommandHandler::parseArguments( args );
+ static_cast<IRCAccount*>( manager->account() )->engine()->writeMessage(
+ QString::fromLatin1("WHO %1").arg( argsList.first() ) );
+ static_cast<IRCAccount*>( manager->account() )->setCurrentCommandSource( manager );
+}
+
+void IRCProtocol::slotWhoWasCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ QStringList argsList = Kopete::CommandHandler::parseArguments( args );
+ static_cast<IRCAccount*>( manager->account() )->engine()->writeMessage(
+ QString::fromLatin1("WHOWAS %1").arg( argsList.first() ) );
+ static_cast<IRCAccount*>( manager->account() )->setCurrentCommandSource( manager );
+}
+
+void IRCProtocol::slotQuitCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ static_cast<IRCAccount*>( manager->account() )->quit( args );
+}
+
+void IRCProtocol::slotNickCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ QStringList argsList = Kopete::CommandHandler::parseArguments( args );
+ static_cast<IRCAccount*>( manager->account() )->engine()->nick( argsList.front() );
+}
+
+void IRCProtocol::slotModeCommand(const QString &args, Kopete::ChatSession *manager)
+{
+ QStringList argsList = Kopete::CommandHandler::parseArguments( args );
+ static_cast<IRCAccount*>( manager->account() )->engine()->mode( argsList.front(),
+ args.section( QRegExp(QString::fromLatin1("\\s+")), 1 ) );
+}
+
+void IRCProtocol::slotMeCommand(const QString &args, Kopete::ChatSession *manager)
+{
+ Kopete::ContactPtrList members = manager->members();
+ static_cast<IRCAccount*>( manager->account() )->engine()->CtcpRequest_action(
+ static_cast<const IRCContact*>(members.first())->nickName(), args
+ );
+}
+
+void IRCProtocol::slotAllMeCommand(const QString &args, Kopete::ChatSession *)
+{
+ QValueList<Kopete::ChatSession*> sessions = Kopete::ChatSessionManager::self()->sessions();
+
+ for( QValueList<Kopete::ChatSession*>::iterator it = sessions.begin(); it != sessions.end(); ++it )
+ {
+ Kopete::ChatSession *session = *it;
+ if( session->protocol() == this )
+ slotMeCommand(args, session);
+ }
+}
+
+void IRCProtocol::slotKickCommand(const QString &args, Kopete::ChatSession *manager)
+{
+ if (manager->contactOnlineStatus( manager->myself() ) == m_UserStatusOp)
+ {
+ QRegExp spaces(QString::fromLatin1("\\s+"));
+ QString nick = args.section( spaces, 0, 0);
+ QString reason = args.section( spaces, 1);
+ Kopete::ContactPtrList members = manager->members();
+ QString channel = static_cast<IRCContact*>( members.first() )->nickName();
+ if (KIRC::Entity::isChannel(channel))
+ static_cast<IRCAccount*>(manager->account())->engine()->kick(nick, channel, reason);
+ }
+ else
+ {
+ static_cast<IRCAccount*>( manager->account() )->appendMessage(
+ i18n("You must be a channel operator to perform this operation."), IRCAccount::ErrorReply );
+ }
+}
+
+void IRCProtocol::slotBanCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ if( manager->contactOnlineStatus( manager->myself() ) == m_UserStatusOp )
+ {
+ QStringList argsList = Kopete::CommandHandler::parseArguments( args );
+ Kopete::ContactPtrList members = manager->members();
+ IRCChannelContact *chan = static_cast<IRCChannelContact*>( members.first() );
+ if( chan && chan->locateUser( argsList.front() ) )
+ chan->setMode( QString::fromLatin1("+b %1").arg( argsList.front() ) );
+ }
+ else
+ {
+ static_cast<IRCAccount*>( manager->account() )->appendMessage(
+ i18n("You must be a channel operator to perform this operation."), IRCAccount::ErrorReply );
+ }
+}
+
+void IRCProtocol::slotPartCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ QStringList argsList = Kopete::CommandHandler::parseArguments(args);
+ Kopete::ContactPtrList members = manager->members();
+ IRCChannelContact *chan = static_cast<IRCChannelContact*>(members.first());
+
+ if (chan)
+ {
+ if(!args.isEmpty())
+ static_cast<IRCAccount*>(manager->account())->engine()->part(chan->nickName(), args);
+ else
+ chan->part();
+ if( manager->view() )
+ manager->view()->closeView(true);
+ }
+ else
+ {
+ static_cast<IRCAccount*>( manager->account() )->appendMessage(
+ i18n("You must be in a channel to use this command."), IRCAccount::ErrorReply );
+ }
+}
+
+void IRCProtocol::slotOpCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ simpleModeChange( args, manager, QString::fromLatin1("+o") );
+}
+
+void IRCProtocol::slotDeopCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ simpleModeChange( args, manager, QString::fromLatin1("-o") );
+}
+
+void IRCProtocol::slotVoiceCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ simpleModeChange( args, manager, QString::fromLatin1("+v") );
+}
+
+void IRCProtocol::slotDevoiceCommand( const QString &args, Kopete::ChatSession *manager )
+{
+ simpleModeChange( args, manager, QString::fromLatin1("-v") );
+}
+
+void IRCProtocol::simpleModeChange( const QString &args, Kopete::ChatSession *manager, const QString &mode )
+{
+ if( manager->contactOnlineStatus( manager->myself() ) == m_UserStatusOp )
+ {
+ QStringList argsList = Kopete::CommandHandler::parseArguments( args );
+ Kopete::ContactPtrList members = manager->members();
+ IRCChannelContact *chan = static_cast<IRCChannelContact*>( members.first() );
+ if( chan )
+ {
+ for( QStringList::iterator it = argsList.begin(); it != argsList.end(); ++it )
+ {
+ if( chan->locateUser( *it ) )
+ chan->setMode( QString::fromLatin1("%1 %2").arg( mode ).arg( *it ) );
+ }
+ }
+ }
+ else
+ {
+ static_cast<IRCAccount*>( manager->account() )->appendMessage(
+ i18n("You must be a channel operator to perform this operation."), IRCAccount::ErrorReply );
+ }
+}
+
+void IRCProtocol::editNetworks( const QString &networkName )
+{
+ if( !netConf )
+ {
+ netConf = new NetworkConfig( Kopete::UI::Global::mainWidget(), "network_config", true );
+ netConf->host->setValidator( new QRegExpValidator( QString::fromLatin1("^[\\w-\\.]*$"), netConf ) );
+ netConf->upButton->setIconSet( SmallIconSet( "up" ) );
+ netConf->downButton->setIconSet( SmallIconSet( "down" ) );
+
+ connect( netConf->networkList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkConfig() ) );
+ connect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+ connect( netConf, SIGNAL( accepted() ), this, SLOT( slotSaveNetworkConfig() ) );
+ connect( netConf, SIGNAL( rejected() ), this, SLOT( slotReadNetworks() ) );
+ connect( netConf->upButton, SIGNAL( clicked() ), this, SLOT( slotMoveServerUp() ) );
+ connect( netConf->downButton, SIGNAL( clicked() ), this, SLOT( slotMoveServerDown() ) );
+ connect( netConf->removeNetwork, SIGNAL( clicked() ), this, SLOT( slotDeleteNetwork() ) );
+ connect( netConf->removeHost, SIGNAL( clicked() ), this, SLOT( slotDeleteHost() ) );
+ connect( netConf->newHost, SIGNAL( clicked() ), this, SLOT( slotNewHost() ) );
+ connect( netConf->newNetwork, SIGNAL( clicked() ), this, SLOT( slotNewNetwork() ) );
+ connect( netConf->renameNetwork, SIGNAL( clicked() ), this, SLOT( slotRenameNetwork() ) );
+ connect( netConf->port, SIGNAL( valueChanged( int ) ), this, SLOT( slotHostPortChanged( int ) ) );
+ connect( netConf->networkList, SIGNAL( doubleClicked ( QListBoxItem * )), SLOT(slotRenameNetwork()));
+
+ }
+
+ disconnect( netConf->networkList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkConfig() ) );
+ disconnect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+
+ netConf->networkList->clear();
+
+ for( QDictIterator<IRCNetwork> it( m_networks ); it.current(); ++it )
+ {
+ IRCNetwork *net = it.current();
+ netConf->networkList->insertItem( net->name );
+ }
+
+ netConf->networkList->sort();
+
+ connect( netConf->networkList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkConfig() ) );
+ connect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+
+ if( !networkName.isEmpty() )
+ netConf->networkList->setSelected( netConf->networkList->findItem( networkName ), true );
+
+ //slotUpdateNetworkConfig(); // unnecessary, setSelected emits selectionChanged
+
+ netConf->show();
+}
+
+void IRCProtocol::slotUpdateNetworkConfig()
+{
+ // update the data structure of the previous selection from the UI
+ storeCurrentNetwork();
+
+ // update the UI from the data for the current selection
+ IRCNetwork *net = m_networks[ netConf->networkList->currentText() ];
+ if( net )
+ {
+ netConf->description->setText( net->description );
+ netConf->hostList->clear();
+
+ for( QValueList<IRCHost*>::iterator it = net->hosts.begin(); it != net->hosts.end(); ++it )
+ netConf->hostList->insertItem( (*it)->host + QString::fromLatin1(":") + QString::number((*it)->port) );
+
+ // prevent nested event loop crash
+ disconnect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+ netConf->hostList->setSelected( 0, true );
+ slotUpdateNetworkHostConfig();
+ connect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+ }
+
+ // record the current selection
+ m_uiCurrentNetworkSelection = netConf->networkList->currentText();
+}
+
+void IRCProtocol::storeCurrentNetwork()
+{
+ if ( !m_uiCurrentNetworkSelection.isEmpty() )
+ {
+ IRCNetwork *net = m_networks[ m_uiCurrentNetworkSelection ];
+ if ( net )
+ {
+ net->description = netConf->description->text(); // crash on 2nd dialog show here!
+ }
+ else
+ kdDebug( 14120 ) << m_uiCurrentNetworkSelection << " was already gone from the cache!" << endl;
+ }
+}
+
+void IRCProtocol::storeCurrentHost()
+{
+ if ( !m_uiCurrentHostSelection.isEmpty() )
+ {
+ IRCHost *host = m_hosts[ m_uiCurrentHostSelection ];
+ if ( host )
+ {
+ host->host = netConf->host->text();
+ host->password = netConf->password->text();
+ host->port = netConf->port->text().toInt();
+ host->ssl = netConf->useSSL->isChecked();
+ }
+ }
+}
+
+void IRCProtocol::slotHostPortChanged( int value )
+{
+ QString entryText = m_uiCurrentHostSelection + QString::fromLatin1(":") + QString::number( value );
+ // changeItem causes a take() and insert, and we don't want a selectionChanged() signal that sets all this off again.
+ disconnect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+ netConf->hostList->changeItem( entryText, netConf->hostList->currentItem() );
+ connect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+}
+
+void IRCProtocol::slotUpdateNetworkHostConfig()
+{
+ storeCurrentHost();
+
+ if ( netConf->hostList->selectedItem() )
+ {
+ m_uiCurrentHostSelection = netConf->hostList->currentText().section(':', 0, 0);
+ IRCHost *host = m_hosts[ m_uiCurrentHostSelection ];
+
+ if( host )
+ {
+ netConf->host->setText( host->host );
+ netConf->password->setText( host->password );
+ disconnect( netConf->port, SIGNAL( valueChanged( int ) ), this, SLOT( slotHostPortChanged( int ) ) );
+ netConf->port->setValue( host->port );
+ connect( netConf->port, SIGNAL( valueChanged( int ) ), this, SLOT( slotHostPortChanged( int ) ) );
+ netConf->useSSL->setChecked( host->ssl );
+
+ netConf->upButton->setEnabled( netConf->hostList->currentItem() > 0 );
+ netConf->downButton->setEnabled( netConf->hostList->currentItem() < (int)( netConf->hostList->count() - 1 ) );
+ }
+ }
+ else
+ {
+ m_uiCurrentHostSelection = QString();
+ disconnect( netConf->port, SIGNAL( valueChanged( int ) ), this, SLOT( slotHostPortChanged( int ) ) );
+ netConf->host->clear();
+ netConf->password->clear();
+ netConf->port->setValue( 6667 );
+ netConf->useSSL->setChecked( false );
+ connect( netConf->port, SIGNAL( valueChanged( int ) ), this, SLOT( slotHostPortChanged( int ) ) );
+ }
+}
+
+void IRCProtocol::slotDeleteNetwork()
+{
+ QString network = netConf->networkList->currentText();
+ if( KMessageBox::warningContinueCancel(
+ Kopete::UI::Global::mainWidget(), i18n("<qt>Are you sure you want to delete the network <b>%1</b>?<br>"
+ "Any accounts which use this network will have to be modified.</qt>")
+ .arg(network), i18n("Deleting Network"),
+ KGuiItem(i18n("&Delete Network"),"editdelete"), QString::fromLatin1("AskIRCDeleteNetwork") ) == KMessageBox::Continue )
+ {
+ disconnect( netConf->networkList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkConfig() ) );
+ disconnect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+ IRCNetwork *net = m_networks[ network ];
+ for( QValueList<IRCHost*>::iterator it = net->hosts.begin(); it != net->hosts.end(); ++it )
+ {
+ m_hosts.remove( (*it)->host );
+ delete (*it);
+ }
+ m_networks.remove( network );
+ delete net;
+ netConf->networkList->removeItem( netConf->networkList->currentItem() );
+ connect( netConf->networkList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkConfig() ) );
+ connect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+ slotUpdateNetworkHostConfig();
+
+ }
+}
+
+void IRCProtocol::slotDeleteHost()
+{
+ QString hostName = netConf->host->text();
+ if ( KMessageBox::warningContinueCancel(
+ Kopete::UI::Global::mainWidget(), i18n("<qt>Are you sure you want to delete the host <b>%1</b>?</qt>")
+ .arg(hostName), i18n("Deleting Host"),
+ KGuiItem(i18n("&Delete Host"),"editdelete"), QString::fromLatin1("AskIRCDeleteHost")) == KMessageBox::Continue )
+ {
+ IRCHost *host = m_hosts[ hostName ];
+ if ( host )
+ {
+ disconnect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+ QString entryText = host->host + QString::fromLatin1(":") + QString::number(host->port);
+ QListBoxItem * justAdded = netConf->hostList->findItem( entryText );
+ netConf->hostList->removeItem( netConf->hostList->index( justAdded ) );
+ connect( netConf->hostList, SIGNAL( selectionChanged() ), this, SLOT( slotUpdateNetworkHostConfig() ) );
+
+ // remove from network as well
+ IRCNetwork *net = m_networks[ m_uiCurrentNetworkSelection ];
+ net->hosts.remove( host );
+
+ m_hosts.remove( host->host );
+ delete host;
+ }
+ }
+}
+
+void IRCProtocol::slotNewNetwork()
+{
+ // create a new network struct
+ IRCNetwork *net = new IRCNetwork;
+ // give it the name of 'New Network' (incrementing number if needed)
+ QString netName = QString::fromLatin1( "New Network" );
+ if ( m_networks.find( netName ) )
+ {
+ int newIdx = 1;
+ do {
+ netName = QString::fromLatin1( "New Network #%1" ).arg( newIdx++ );
+ }
+ while ( m_networks.find( netName ) && newIdx < 100 );
+ if ( newIdx == 100 ) // pathological case
+ return;
+ }
+ net->name = netName;
+ // and add it to the networks dict and list
+ m_networks.insert( net->name, net );
+ netConf->networkList->insertItem( net->name );
+ QListBoxItem * justAdded = netConf->networkList->findItem( net->name );
+ netConf->networkList->setSelected( justAdded, true );
+ netConf->networkList->setBottomItem( netConf->networkList->index( justAdded ) );
+}
+
+void IRCProtocol::slotNewHost()
+{
+ // create a new host
+ IRCHost *host = new IRCHost;
+ // prompt for a name
+ bool ok;
+ QString name = KInputDialog::getText(
+ i18n("New Host"),
+ i18n("Enter the hostname of the new server:"),
+ QString::null, &ok, Kopete::UI::Global::mainWidget() );
+ if ( ok )
+ {
+ // dupe check
+ if ( m_hosts[ name ] )
+ {
+ KMessageBox::sorry(netConf, i18n( "A host already exists with that name" ) );
+ return;
+ }
+ // set defaults on others
+ host->host = name;
+ host->port = 6667;
+ host->ssl = false;
+ // add it to the dict
+ m_hosts.insert( host->host, host );
+ // add it to the network!
+ IRCNetwork *net = m_networks[ netConf->networkList->currentText() ];
+ net->hosts.append( host );
+ // add it to the gui
+ QString entryText = host->host + QString::fromLatin1(":") + QString::number(host->port);
+ netConf->hostList->insertItem( entryText );
+ // select it in the gui
+ QListBoxItem * justAdded = netConf->hostList->findItem( entryText );
+ netConf->hostList->setSelected( justAdded, true );
+ //netConf->hostList->setBottomItem( netConf->hostList->index( justAdded ) );
+ }
+}
+
+void IRCProtocol::slotRenameNetwork()
+{
+ IRCNetwork *net = m_networks[ m_uiCurrentNetworkSelection ];
+ if ( net )
+ {
+ bool ok;
+ // popup up a dialog containing the current name
+ QString name = KInputDialog::getText(
+ i18n("Rename Network"),
+ i18n("Enter the new name for this network:"),
+ m_uiCurrentNetworkSelection, &ok,
+ Kopete::UI::Global::mainWidget() );
+ if ( ok )
+ {
+ if ( m_uiCurrentNetworkSelection != name )
+ {
+ // dupe check
+ if ( m_networks[ name ] )
+ {
+ KMessageBox::sorry(netConf, i18n( "A network already exists with that name" ) );
+ return;
+ }
+
+ net->name = name;
+ // dict
+ m_networks.remove( m_uiCurrentNetworkSelection );
+ m_networks.insert( net->name, net );
+ // ui
+ int idx = netConf->networkList->index( netConf->networkList->findItem( m_uiCurrentNetworkSelection ) );
+ m_uiCurrentNetworkSelection = net->name;
+ netConf->networkList->changeItem( net->name, idx ); // changes the selection!!!
+ netConf->networkList->sort();
+ }
+ }
+ }
+}
+
+void IRCProtocol::addNetwork( IRCNetwork *network )
+{
+ m_networks.insert( network->name, network );
+ slotSaveNetworkConfig();
+}
+
+void IRCProtocol::slotSaveNetworkConfig()
+{
+ // store any changes in the UI
+ storeCurrentNetwork();
+ kdDebug( 14120 ) << k_funcinfo << m_uiCurrentHostSelection << endl;
+ storeCurrentHost();
+
+ QDomDocument doc("irc-networks");
+ QDomNode root = doc.appendChild( doc.createElement("networks") );
+
+ for( QDictIterator<IRCNetwork> it( m_networks ); it.current(); ++it )
+ {
+ IRCNetwork *net = it.current();
+
+ QDomNode networkNode = root.appendChild( doc.createElement("network") );
+ QDomNode nameNode = networkNode.appendChild( doc.createElement("name") );
+ nameNode.appendChild( doc.createTextNode( net->name ) );
+
+ QDomNode descNode = networkNode.appendChild( doc.createElement("description") );
+ descNode.appendChild( doc.createTextNode( net->description ) );
+
+ QDomNode serversNode = networkNode.appendChild( doc.createElement("servers") );
+
+ for( QValueList<IRCHost*>::iterator it2 = net->hosts.begin(); it2 != net->hosts.end(); ++it2 )
+ {
+ QDomNode serverNode = serversNode.appendChild( doc.createElement("server") );
+
+ QDomNode hostNode = serverNode.appendChild( doc.createElement("host") );
+ hostNode.appendChild( doc.createTextNode( (*it2)->host ) );
+
+ QDomNode portNode = serverNode.appendChild( doc.createElement("port" ) );
+ portNode.appendChild( doc.createTextNode( QString::number( (*it2)->port ) ) );
+
+ QDomNode sslNode = serverNode.appendChild( doc.createElement("useSSL") );
+ sslNode.appendChild( doc.createTextNode( (*it2)->ssl ? "true" : "false" ) );
+ }
+ }
+
+// kdDebug(14121) << k_funcinfo << doc.toString(4) << endl;
+ QFile xmlFile( locateLocal( "appdata", "ircnetworks.xml" ) );
+
+ if (xmlFile.open(IO_WriteOnly))
+ {
+ QTextStream stream(&xmlFile);
+ stream << doc.toString(4);
+ xmlFile.close();
+ }
+ else
+ kdDebug(14121) << k_funcinfo << "Failed to save the Networks definition file" << endl;
+
+ if (netConf)
+ emit networkConfigUpdated( netConf->networkList->currentText() );
+}
+
+void IRCProtocol::slotReadNetworks()
+{
+ m_networks.clear();
+ m_hosts.clear();
+
+ QFile xmlFile( locate( "appdata", "ircnetworks.xml" ) );
+ xmlFile.open( IO_ReadOnly );
+
+ QDomDocument doc;
+ doc.setContent( &xmlFile );
+ QDomElement networkNode = doc.documentElement().firstChild().toElement();
+ while( !networkNode.isNull () )
+ {
+ IRCNetwork *net = new IRCNetwork;
+
+ QDomElement networkChild = networkNode.firstChild().toElement();
+ while( !networkChild.isNull() )
+ {
+ if( networkChild.tagName() == "name" )
+ net->name = networkChild.text();
+ else if( networkChild.tagName() == "description" )
+ net->description = networkChild.text();
+ else if( networkChild.tagName() == "servers" )
+ {
+ QDomElement server = networkChild.firstChild().toElement();
+ while( !server.isNull() )
+ {
+ IRCHost *host = new IRCHost;
+
+ QDomElement serverChild = server.firstChild().toElement();
+ while( !serverChild.isNull() )
+ {
+ if( serverChild.tagName() == "host" )
+ host->host = serverChild.text();
+ else if( serverChild.tagName() == "port" )
+ host->port = serverChild.text().toInt();
+ else if( serverChild.tagName() == "useSSL" )
+ host->ssl = ( serverChild.text() == "true" );
+
+ serverChild = serverChild.nextSibling().toElement();
+ }
+
+ net->hosts.append( host );
+ m_hosts.insert( host->host, host );
+ server = server.nextSibling().toElement();
+ }
+ }
+ networkChild = networkChild.nextSibling().toElement();
+ }
+
+ m_networks.insert( net->name, net );
+ networkNode = networkNode.nextSibling().toElement();
+ }
+
+ xmlFile.close();
+}
+
+void IRCProtocol::slotMoveServerUp()
+{
+ IRCHost *selectedHost = m_hosts[ netConf->hostList->currentText().section(':', 0, 0) ];
+ IRCNetwork *selectedNetwork = m_networks[ netConf->networkList->currentText() ];
+
+ if( !selectedNetwork || !selectedHost )
+ return;
+
+ QValueList<IRCHost*>::iterator pos = selectedNetwork->hosts.find( selectedHost );
+ if( pos != selectedNetwork->hosts.begin() )
+ {
+ QValueList<IRCHost*>::iterator lastPos = pos;
+ lastPos--;
+ selectedNetwork->hosts.insert( lastPos, selectedHost );
+ selectedNetwork->hosts.remove( pos );
+ }
+
+ unsigned int currentPos = netConf->hostList->currentItem();
+ if( currentPos > 0 )
+ {
+ netConf->hostList->removeItem( currentPos );
+ QString entryText = selectedHost->host + QString::fromLatin1(":") + QString::number( selectedHost->port );
+ netConf->hostList->insertItem( entryText, --currentPos );
+ netConf->hostList->setSelected( currentPos, true );
+ }
+}
+
+void IRCProtocol::slotMoveServerDown()
+{
+ IRCHost *selectedHost = m_hosts[ netConf->hostList->currentText().section(':', 0, 0) ];
+ IRCNetwork *selectedNetwork = m_networks[ netConf->networkList->currentText() ];
+
+ if( !selectedNetwork || !selectedHost )
+ return;
+
+ QValueList<IRCHost*>::iterator pos = selectedNetwork->hosts.find( selectedHost );
+ if( *pos != selectedNetwork->hosts.back() )
+ {
+ QValueList<IRCHost*>::iterator nextPos = selectedNetwork->hosts.remove( pos );
+ selectedNetwork->hosts.insert( ++nextPos, selectedHost );
+ }
+
+ unsigned int currentPos = netConf->hostList->currentItem();
+ if( currentPos < ( netConf->hostList->count() - 1 ) )
+ {
+ netConf->hostList->removeItem( currentPos );
+ QString entryText = selectedHost->host + QString::fromLatin1(":") + QString::number( selectedHost->port );
+ netConf->hostList->insertItem( entryText, ++currentPos );
+ netConf->hostList->setSelected( currentPos, true );
+ }
+}
+
+
+
+#include "ircprotocol.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
diff --git a/kopete/protocols/irc/ircprotocol.h b/kopete/protocols/irc/ircprotocol.h
new file mode 100644
index 00000000..2a1700e5
--- /dev/null
+++ b/kopete/protocols/irc/ircprotocol.h
@@ -0,0 +1,228 @@
+/*
+ ircprotocol.h - IRC Protocol
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+
+ Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef IRCPROTOCOL_H
+#define IRCPROTOCOL_H
+
+#include "kopeteonlinestatus.h"
+#include "kopeteprotocol.h"
+#include "kopetecontactproperty.h"
+#include "kopetemimetypehandler.h"
+
+#include <dom/dom_node.h>
+#include <qdict.h>
+
+#define m_protocol (IRCProtocol::protocol())
+
+namespace Kopete
+{
+class Account;
+class MetaContact;
+}
+
+class AddContactPage;
+
+class EditAccountWidget;
+class IRCAccount;
+
+class QStringList;
+class QWidget;
+class KopeteView;
+
+class IRCNetwork;
+class IRCHost;
+class NetworkConfig;
+
+class IRCProtocolHandler : public Kopete::MimeTypeHandler
+{
+ public:
+
+ IRCProtocolHandler();
+
+ void handleURL( const KURL &url ) const;
+};
+
+static const QString CHAT_VIEW( QString::fromLatin1("kopete_chatwindow") );
+
+/**
+ * @author Nick Betcher <nbetcher@kde.org>
+ */
+class IRCProtocol : public Kopete::Protocol
+{
+ Q_OBJECT
+
+public:
+ enum IRCStatus
+ {
+ Offline = 1, //! An offline user.
+ Connecting = 2, //! User that is connecting.
+ Away = 4, //! User that is away. May be regular user, voiced user or (server) operator.
+ Online = 8, //! This user is online.
+ Voiced = 16, //! This user is voiced.
+ Operator = 32, //! This user is a channel operator.
+ ServerOperator = 1024, //! This user is a server operator.
+ OfflineChannel = 4096, //! This channel is offline.
+ OnlineChannel = 8192, //! This channel is online.
+ OfflineServer = 16384, //! This server is offline.
+ OnlineServer = 32768 //! This server is online.
+ };
+
+ IRCProtocol( QObject *parent, const char *name, const QStringList &args );
+ ~IRCProtocol();
+
+ /** Kopete::Protocol reimplementation */
+ virtual AddContactPage *createAddContactWidget(QWidget *parent, Kopete::Account *account);
+
+ /**
+ * Deserialize contact data
+ */
+ virtual Kopete::Contact *deserializeContact( Kopete::MetaContact *metaContact,
+ const QMap<QString, QString> &serializedData, const QMap<QString, QString> &addressBookData );
+
+ virtual KopeteEditAccountWidget* createEditAccountWidget(Kopete::Account *account, QWidget *parent);
+
+ virtual Kopete::Account* createNewAccount(const QString &accountId);
+
+ virtual QPtrList<KAction> *customChatWindowPopupActions( const Kopete::Message &, DOM::Node & );
+
+ static IRCProtocol *protocol();
+
+ /**
+ * Maps the given IRC status to Kopete::OnlineStatus.
+ */
+ const Kopete::OnlineStatus statusLookup( IRCStatus status ) const;
+
+ const Kopete::OnlineStatus m_ServerStatusOnline;
+ const Kopete::OnlineStatus m_ServerStatusOffline;
+
+ const Kopete::OnlineStatus m_ChannelStatusOnline;
+ const Kopete::OnlineStatus m_ChannelStatusOffline;
+
+ const Kopete::OnlineStatus m_UserStatusOpVoice;
+ const Kopete::OnlineStatus m_UserStatusOpVoiceAway;
+ const Kopete::OnlineStatus m_UserStatusOp;
+ const Kopete::OnlineStatus m_UserStatusOpAway;
+ const Kopete::OnlineStatus m_UserStatusVoice;
+ const Kopete::OnlineStatus m_UserStatusVoiceAway;
+ const Kopete::OnlineStatus m_UserStatusOnline;
+ const Kopete::OnlineStatus m_UserStatusAway;
+ const Kopete::OnlineStatus m_UserStatusConnecting;
+ const Kopete::OnlineStatus m_UserStatusOffline;
+
+ const Kopete::OnlineStatus m_StatusUnknown;
+
+ // irc channnel-contact properties
+ const Kopete::ContactPropertyTmpl propChannelTopic;
+ const Kopete::ContactPropertyTmpl propChannelMembers;
+ const Kopete::ContactPropertyTmpl propHomepage;
+
+ // irc user-contact properties
+ const Kopete::ContactPropertyTmpl propLastSeen;
+ const Kopete::ContactPropertyTmpl propUserInfo;
+ const Kopete::ContactPropertyTmpl propServer;
+ const Kopete::ContactPropertyTmpl propChannels;
+ const Kopete::ContactPropertyTmpl propHops;
+ const Kopete::ContactPropertyTmpl propFullName;
+ const Kopete::ContactPropertyTmpl propIsIdentified;
+
+ bool commandInProgress(){ return m_commandInProgress; }
+ void setCommandInProgress( bool ip ) { m_commandInProgress = ip; }
+
+ QDict<IRCNetwork> &networks(){ return m_networks; }
+ void addNetwork( IRCNetwork *network );
+
+ void editNetworks( const QString &networkName = QString::null );
+
+signals:
+ void networkConfigUpdated( const QString &selectedNetwork );
+
+private slots:
+ // FIXME: All the code for managing the networks list should be in another class - Will
+ void slotUpdateNetworkConfig();
+ void slotUpdateNetworkHostConfig();
+ void slotMoveServerUp();
+ void slotMoveServerDown();
+ void slotSaveNetworkConfig();
+ void slotReadNetworks();
+ void slotDeleteNetwork();
+ void slotDeleteHost();
+ void slotNewNetwork();
+ void slotRenameNetwork();
+ void slotNewHost();
+ void slotHostPortChanged( int value );
+ // end of network list specific code
+
+ void slotMessageFilter( Kopete::Message &msg );
+
+ void slotRawCommand( const QString &args, Kopete::ChatSession *manager );
+ void slotQuoteCommand( const QString &args, Kopete::ChatSession *manager );
+ void slotCtcpCommand( const QString &args, Kopete::ChatSession *manager );
+ void slotPingCommand( const QString &args, Kopete::ChatSession *manager );
+
+ void slotMotdCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotListCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotTopicCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotJoinCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotNickCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotWhoisCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotWhoWasCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotWhoCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotMeCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotAllMeCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotModeCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotQueryCommand( const QString &args, Kopete::ChatSession *manager);
+
+ void slotKickCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotBanCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotOpCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotDeopCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotVoiceCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotDevoiceCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotQuitCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotPartCommand( const QString &args, Kopete::ChatSession *manager);
+ void slotInviteCommand( const QString &args, Kopete::ChatSession *manager);
+
+ void slotViewCreated( KopeteView * );
+
+private:
+ static IRCProtocol *s_protocol;
+
+ void simpleModeChange( const QString &, Kopete::ChatSession *, const QString &mode );
+
+ // FIXME: All the code for managing the networks list should be in another class - Will
+ void storeCurrentNetwork();
+ void storeCurrentHost();
+
+ NetworkConfig *netConf;
+ QString m_uiCurrentNetworkSelection;
+ QString m_uiCurrentHostSelection;
+ // end of network list specific code
+
+ DOM::Node activeNode;
+ IRCAccount *activeAccount;
+
+ bool m_commandInProgress;
+
+ QDict<IRCNetwork> m_networks;
+ QDict<IRCHost> m_hosts;
+ IRCProtocolHandler *m_protocolHandler;
+};
+
+#endif
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/protocols/irc/ircservercontact.cpp b/kopete/protocols/irc/ircservercontact.cpp
new file mode 100644
index 00000000..3ca21643
--- /dev/null
+++ b/kopete/protocols/irc/ircservercontact.cpp
@@ -0,0 +1,220 @@
+/*
+ ircservercontact.cpp - IRC Server Contact
+
+ Copyright (c) 2003 by Michel Hermier <mhermier@kde.org>
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "ircusercontact.h"
+#include "ircservercontact.h"
+#include "ircaccount.h"
+#include "ircprotocol.h"
+
+#include "kopetechatsessionmanager.h"
+#include "kopeteview.h"
+
+#include <kaction.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <qtimer.h>
+
+IRCServerContact::IRCServerContact(IRCContactManager *contactManager, const QString &servername, Kopete::MetaContact *m)
+ : IRCContact(contactManager, servername, m, "irc_server")
+{
+ KIRC::Engine *engine = kircEngine();
+
+ QObject::connect(engine, SIGNAL(internalError(KIRC::Engine::Error, KIRC::Message &)),
+ this, SLOT(engineInternalError(KIRC::Engine::Error, KIRC::Message &)));
+/*
+ //FIXME: Have some kind of a debug option for raw input/ouput display??
+ QObject::connect(engine, SIGNAL(sentMessage(KIRC::Message &)),
+ this, SLOT(engineSentMessage(KIRC::Message &)));
+ QObject::connect(engine, SIGNAL(receivedMessage(KIRC::Message &)),
+ this, SLOT(engineReceivedMessage(KIRC::Message &)));
+*/
+
+ QObject::connect(engine, SIGNAL(incomingNotice(const QString &, const QString &)),
+ this, SLOT(slotIncomingNotice(const QString &, const QString &)));
+
+ QObject::connect(engine, SIGNAL(incomingCannotSendToChannel(const QString &, const QString &)),
+ this, SLOT(slotCannotSendToChannel(const QString &, const QString &)));
+
+ QObject::connect(engine, SIGNAL(incomingUnknown(const QString &)),
+ this, SLOT(slotIncomingUnknown(const QString &)));
+
+ QObject::connect(engine, SIGNAL(incomingConnectString(const QString &)),
+ this, SLOT(slotIncomingConnect(const QString &)));
+
+ QObject::connect(engine, SIGNAL(incomingMotd(const QString &)),
+ this, SLOT(slotIncomingMotd(const QString &)));
+
+ QObject::connect(Kopete::ChatSessionManager::self(), SIGNAL(viewCreated(KopeteView*)),
+ this, SLOT(slotViewCreated(KopeteView*)) );
+
+ updateStatus();
+}
+
+void IRCServerContact::updateStatus()
+{
+ KIRC::Engine::Status status = kircEngine()->status();
+ switch( status )
+ {
+ case KIRC::Engine::Idle:
+ case KIRC::Engine::Connecting:
+ if( m_chatSession )
+ m_chatSession->setDisplayName( caption() );
+ setOnlineStatus( m_protocol->m_ServerStatusOffline );
+ break;
+
+ case KIRC::Engine::Authentifying:
+ case KIRC::Engine::Connected:
+ case KIRC::Engine::Closing:
+ // should make some extra check here
+ setOnlineStatus( m_protocol->m_ServerStatusOnline );
+ break;
+
+ default:
+ setOnlineStatus( m_protocol->m_StatusUnknown );
+ }
+}
+
+const QString IRCServerContact::caption() const
+{
+ return i18n("%1 @ %2").arg(ircAccount()->mySelf()->nickName() ).arg(
+ kircEngine()->currentHost().isEmpty() ? ircAccount()->networkName() : kircEngine()->currentHost()
+ );
+}
+
+void IRCServerContact::engineInternalError(KIRC::Engine::Error engineError, KIRC::Message &ircmsg)
+{
+ QString error;
+ switch (engineError)
+ {
+ case KIRC::Engine::ParsingFailed:
+ error = i18n("KIRC Error - Parse error: ");
+ break;
+ case KIRC::Engine::UnknownCommand:
+ error = i18n("KIRC Error - Unknown command: ");
+ break;
+ case KIRC::Engine::UnknownNumericReply:
+ error = i18n("KIRC Error - Unknown numeric reply: ");
+ break;
+ case KIRC::Engine::InvalidNumberOfArguments:
+ error = i18n("KIRC Error - Invalid number of arguments: ");
+ break;
+ case KIRC::Engine::MethodFailed:
+ error = i18n("KIRC Error - Method failed: ");
+ break;
+ default:
+ error = i18n("KIRC Error - Unknown error: ");
+ }
+
+ ircAccount()->appendMessage(error + QString(ircmsg.raw()), IRCAccount::ErrorReply);
+}
+
+void IRCServerContact::slotSendMsg(Kopete::Message &, Kopete::ChatSession *manager)
+{
+ manager->messageSucceeded();
+ Kopete::Message msg( manager->myself(), manager->members(),
+ i18n("You can not talk to the server, you can only issue commands here. Type /help for supported commands."), Kopete::Message::Internal, Kopete::Message::PlainText, CHAT_VIEW);
+ manager->appendMessage(msg);
+}
+
+void IRCServerContact::appendMessage( const QString &message )
+{
+ Kopete::ContactPtrList members;
+ members.append( this );
+ Kopete::Message msg( this, members, message, Kopete::Message::Internal,
+ Kopete::Message::RichText, CHAT_VIEW );
+ appendMessage(msg);
+}
+
+void IRCServerContact::slotIncomingNotice( const QString &orig, const QString &notice )
+{
+ if (orig.isEmpty()) {
+ // Prefix missing.
+ // NOTICE AUTH :*** Checking Ident
+
+ ircAccount()->appendMessage(i18n("NOTICE from %1: %2").arg(kircEngine()->currentHost(), notice),
+ IRCAccount::NoticeReply);
+
+ } else {
+ // :Global!service@rizon.net NOTICE foobar :[Logon News - Oct 12 2005] Due to growing problems ...
+ // :somenick!~fooobar@somehostname.fi NOTICE foobar :hello
+
+ if (orig.contains('!')) {
+ ircAccount()->appendMessage(i18n("NOTICE from %1 (%2): %3").arg(
+ orig.section('!', 0, 0),
+ orig.section('!', 1, 1),
+ notice),
+ IRCAccount::NoticeReply);
+ } else {
+ ircAccount()->appendMessage(i18n("NOTICE from %1: %2").arg(
+ orig, notice), IRCAccount::NoticeReply);
+ }
+ }
+}
+
+void IRCServerContact::slotIncomingUnknown(const QString &message)
+{
+ ircAccount()->appendMessage(message, IRCAccount::UnknownReply);
+}
+
+void IRCServerContact::slotIncomingConnect(const QString &message)
+{
+ ircAccount()->appendMessage(message, IRCAccount::ConnectReply);
+}
+
+void IRCServerContact::slotIncomingMotd(const QString &message)
+{
+ ircAccount()->appendMessage(message, IRCAccount::InfoReply);
+}
+
+void IRCServerContact::slotCannotSendToChannel(const QString &channel, const QString &message)
+{
+ ircAccount()->appendMessage(QString::fromLatin1("%1: %2").arg(channel).arg(message), IRCAccount::ErrorReply);
+}
+
+void IRCServerContact::appendMessage(Kopete::Message &msg)
+{
+ msg.setImportance( Kopete::Message::Low ); //to don't distrub the user
+
+ if (m_chatSession && m_chatSession->view(false))
+ m_chatSession->appendMessage(msg);
+/*
+// disable the buffering for now: cause a memleak since we don't made it a *fixed size fifo*
+ else
+ mMsgBuffer.append( msg );
+*/
+}
+
+void IRCServerContact::slotDumpMessages()
+{
+ if (!mMsgBuffer.isEmpty())
+ {
+ manager()->appendMessage( mMsgBuffer.front() );
+ mMsgBuffer.pop_front();
+ QTimer::singleShot( 0, this, SLOT( slotDumpMessages() ) );
+ }
+}
+
+void IRCServerContact::slotViewCreated( KopeteView *v )
+{
+ kdDebug(14121) << k_funcinfo << "Created: " << v << ", mgr: " << v->msgManager() << ", Mine: " << m_chatSession << endl;
+ if (m_chatSession && v->msgManager() == m_chatSession)
+ QTimer::singleShot(500, this, SLOT(slotDumpMessages()));
+}
+
+#include "ircservercontact.moc"
diff --git a/kopete/protocols/irc/ircservercontact.h b/kopete/protocols/irc/ircservercontact.h
new file mode 100644
index 00000000..1ca1475b
--- /dev/null
+++ b/kopete/protocols/irc/ircservercontact.h
@@ -0,0 +1,80 @@
+/*
+ ircservercontact.h - IRC User Contact
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef IRCSERVERCONTACT_H
+#define IRCSERVERCONTACT_H
+
+#include "irccontact.h"
+
+#include "kircengine.h"
+
+#include "kopetechatsessionmanager.h"
+
+#include <qvaluelist.h>
+#include <qstringlist.h>
+
+class KActionCollection;
+class KAction;
+class KActionMenu;
+class KopeteView;
+
+class IRCContactManager;
+class IRCChannelContact;
+
+/**
+ * @author Michel Hermier <michel.hermier@wanadoo.fr>
+ *
+ * This class is the @ref Kopete::Contact object representing IRC Servers.
+ * It is derrived from @ref IRCContact where much of its functionality is shared with @ref IRCChannelContact and @ref IRCUserContact.
+ */
+class IRCServerContact
+ : public IRCContact
+{
+ Q_OBJECT
+
+ public:
+ // This class provides a Kopete::Contact for each server of a given IRC connection.
+ IRCServerContact(IRCContactManager *, const QString &servername, Kopete::MetaContact *mc);
+
+ virtual const QString caption() const;
+
+ virtual void appendMessage(Kopete::Message &);
+ void appendMessage( const QString &message );
+
+ protected slots:
+ void engineInternalError(KIRC::Engine::Error error, KIRC::Message &ircmsg);
+ virtual void slotSendMsg(Kopete::Message &message, Kopete::ChatSession *);
+
+ private slots:
+ virtual void updateStatus();
+ void slotViewCreated( KopeteView* );
+ void slotDumpMessages();
+
+ void slotIncomingUnknown( const QString &message );
+ void slotIncomingConnect( const QString &message );
+ void slotIncomingMotd( const QString &motd );
+ void slotIncomingNotice( const QString &orig, const QString &notice );
+ void slotCannotSendToChannel( const QString &channel, const QString &msg );
+
+ private:
+ QValueList<Kopete::Message> mMsgBuffer;
+};
+
+#endif
+
+// vim: set noet ts=4 sts=4 tw=4:
+
diff --git a/kopete/protocols/irc/ircsignalhandler.cpp b/kopete/protocols/irc/ircsignalhandler.cpp
new file mode 100644
index 00000000..5bfab0cc
--- /dev/null
+++ b/kopete/protocols/irc/ircsignalhandler.cpp
@@ -0,0 +1,173 @@
+
+/*
+ ircsignalhandler.cpp - Maps signals from the IRC engine to contacts
+
+ Copyright (c) 2004 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "ircusercontact.h"
+#include "ircchannelcontact.h"
+#include "ircsignalhandler.h"
+
+#include "kircengine.h"
+
+IRCSignalHandler::IRCSignalHandler(IRCContactManager *m)
+ : QObject(m),
+ manager(m)
+{
+ KIRC::Engine *m_engine = static_cast<IRCAccount*>( manager->mySelf()->account() )->engine();
+
+ //Channel Connections to ourself
+ QObject::connect(m_engine, SIGNAL(incomingNamesList(const QString &, const QStringList &)),
+ this, SLOT(slotNamesList(const QString &, const QStringList &)));
+
+ QObject::connect(m_engine, SIGNAL(incomingEndOfNames(const QString &)),
+ this, SLOT(slotEndOfNames(const QString &)));
+
+ QObject::connect(m_engine, SIGNAL(incomingTopicUser(const QString &, const QString &, const QDateTime &)),
+ this, SLOT(slotTopicUser(const QString&,const QString&,const QDateTime&)));
+
+ //Channel String mappings
+ map<IRCChannelContact>( m, SIGNAL(incomingFailedChankey(const QString &)),
+ &IRCChannelContact::failedChankey );
+
+ map<IRCChannelContact>( m, SIGNAL(incomingFailedChanFull(const QString &)),
+ &IRCChannelContact::failedChanInvite );
+
+ map<IRCChannelContact>( m, SIGNAL(incomingFailedChanInvite(const QString &)),
+ &IRCChannelContact::failedChanInvite );
+
+ map<IRCChannelContact>( m, SIGNAL(incomingFailedChanBanned(const QString &)),
+ &IRCChannelContact::failedChanBanned );
+
+ mapSingle<IRCChannelContact>( m, SIGNAL(incomingJoinedChannel(const QString &, const QString &)),
+ &IRCChannelContact::userJoinedChannel );
+
+ mapSingle<IRCChannelContact>( m, SIGNAL(incomingExistingTopic(const QString &, const QString &)),
+ &IRCChannelContact::channelTopic );
+
+ mapSingle<IRCChannelContact>( m, SIGNAL(incomingChannelHomePage(const QString &, const QString &)),
+ &IRCChannelContact::channelHomePage );
+
+ mapDouble<IRCChannelContact>( m,
+ SIGNAL(incomingPartedChannel(const QString &, const QString &,const QString &)),
+ &IRCChannelContact::userPartedChannel );
+
+ mapDouble<IRCChannelContact>( m,
+ SIGNAL(incomingTopicChange(const QString &, const QString &,const QString &)),
+ &IRCChannelContact::topicChanged );
+
+ mapDouble<IRCChannelContact>( m,
+ SIGNAL(incomingChannelModeChange(const QString &, const QString &,const QString &)),
+ &IRCChannelContact::incomingModeChange );
+
+ mapDouble<IRCChannelContact>( m,
+ SIGNAL(incomingChannelMode(const QString &, const QString &,const QString &)),
+ &IRCChannelContact::incomingChannelMode );
+
+ mapTriple<IRCChannelContact>( m,
+ SIGNAL(incomingKick(const QString &, const QString &,const QString &,const QString &)),
+ &IRCChannelContact::userKicked );
+
+ //User connections to ourself
+ QObject::connect(m_engine, SIGNAL(incomingWhoIsIdle(const QString &, unsigned long )),
+ this, SLOT(slotNewWhoIsIdle(const QString &, unsigned long )));
+
+ QObject::connect(m_engine, SIGNAL(incomingWhoReply(const QString &, const QString &, const QString &,
+ const QString &, const QString &, bool, const QString &, uint, const QString & )),
+ this, SLOT( slotNewWhoReply(const QString &, const QString &, const QString &, const QString &,
+ const QString &, bool, const QString &, uint, const QString &)));
+
+ //User signal mappings
+ map<IRCUserContact>( m, SIGNAL(incomingUserOnline( const QString & )), &IRCUserContact::userOnline );
+
+ map<IRCUserContact>( m, SIGNAL(incomingWhoIsOperator( const QString & )), &IRCUserContact::newWhoIsOperator );
+
+ map<IRCUserContact>( m, SIGNAL(incomingWhoIsIdentified( const QString & )), &IRCUserContact::newWhoIsIdentified );
+
+ map<IRCUserContact>( m, SIGNAL(incomingEndOfWhois( const QString & )), &IRCUserContact::whoIsComplete );
+
+ map<IRCUserContact>( m, SIGNAL(incomingEndOfWhoWas( const QString & )), &IRCUserContact::whoWasComplete );
+
+ mapSingle<IRCUserContact>( m, SIGNAL(incomingUserIsAway( const QString &, const QString & )),
+ &IRCUserContact::incomingUserIsAway );
+
+ mapSingle<IRCUserContact>( m, SIGNAL(incomingWhoIsChannels( const QString &, const QString & )),
+ &IRCUserContact::newWhoIsChannels );
+
+ mapDouble<IRCUserContact>( m,
+ SIGNAL(incomingWhoIsServer(const QString &, const QString &, const QString &)),
+ &IRCUserContact::newWhoIsServer );
+
+ mapDouble<IRCUserContact>( m,
+ SIGNAL(incomingPrivAction(const QString &, const QString &, const QString &)),
+ &IRCUserContact::newAction );
+
+ mapDouble<IRCChannelContact>( m,
+ SIGNAL(incomingAction(const QString &, const QString &, const QString &)),
+ &IRCChannelContact::newAction );
+
+ mapTriple<IRCUserContact>( m,
+ SIGNAL(incomingWhoIsUser(const QString &, const QString &, const QString &, const QString &)),
+ &IRCUserContact::newWhoIsUser );
+
+ mapTriple<IRCUserContact>( m,
+ SIGNAL(incomingWhoWasUser(const QString &, const QString &, const QString &, const QString &)),
+ &IRCUserContact::newWhoIsUser );
+}
+
+IRCSignalHandler::~IRCSignalHandler()
+{
+ //Delete our mapping pointers
+ for( QValueList<IRCSignalMappingBase*>::iterator it = mappings.begin(); it != mappings.end(); ++it )
+ delete *it;
+}
+
+void IRCSignalHandler::slotNamesList( const QString &chan, const QStringList &list )
+{
+ IRCChannelContact *c = manager->existChannel( chan );
+ if( c )
+ c->namesList( list );
+}
+
+void IRCSignalHandler::slotEndOfNames( const QString &chan )
+{
+ IRCChannelContact *c = manager->existChannel( chan );
+ if ( c )
+ c->endOfNames();
+}
+
+void IRCSignalHandler::slotTopicUser(const QString &chan, const QString &user,const QDateTime &time)
+{
+ IRCChannelContact *c = manager->existChannel( chan );
+ if( c )
+ c->topicUser( user, time );
+}
+
+void IRCSignalHandler::slotNewWhoIsIdle(const QString &nick, unsigned long val )
+{
+ IRCUserContact *c = manager->findUser( nick );
+ if( c )
+ c->newWhoIsIdle( val );
+}
+
+void IRCSignalHandler::slotNewWhoReply(const QString &nick, const QString &arg1, const QString &arg2,
+ const QString &arg3, const QString &arg4, bool arg5, const QString &arg6, uint arg7, const QString &arg8 )
+{
+ IRCUserContact *c = manager->findUser( nick );
+ if( c )
+ c->newWhoReply( arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 );
+}
+
+#include "ircsignalhandler.moc"
diff --git a/kopete/protocols/irc/ircsignalhandler.h b/kopete/protocols/irc/ircsignalhandler.h
new file mode 100644
index 00000000..a87f814c
--- /dev/null
+++ b/kopete/protocols/irc/ircsignalhandler.h
@@ -0,0 +1,334 @@
+
+/*
+ ircsignalhandler.h - Maps signals from the IRC engine to contacts
+
+ Copyright (c) 2004 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef _IRC_SIGNAL_HANDLER_H
+#define _IRC_SIGNAL_HANDLER_H
+
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+
+#include <kdebug.h>
+
+#include "ircaccount.h"
+#include "irccontactmanager.h"
+
+/***
+* IRC Signal handler. Mapps a KIRC engine signal to the right contact. Avoids
+* Having a signal connected to 500+ slots where only one is valid, instead
+* uses the contact dictionary.
+*
+* Warning: This file has a lot of black magic in it. Avoid it if
+* you don't want your eyes to bleed. More below...
+*
+* Define some templated classes and methods to map a KIRC signal to the
+* right contact. Having these templates greatly cuts down *A LOT* on the amount of
+* code that would need to be in the signal mapper, at the expense of some readability.
+*
+* There are four IRCSignalMapping classes, one each for signals with 0, 1, 2,
+* and 3 arguments ( plus the contact ID ). The classes take the signal, look
+* up the contact it is for, and call the function passed into the class by the
+* mapping function.
+*
+* Since QObjects cannot be inside templates, the QMember classes that connect
+* to the slots are seperate.
+*/
+
+/*** Pre-declare mapping types for the QObjects **/
+struct IRCSignalMappingBase{};
+
+struct IRCSignalMappingT : IRCSignalMappingBase
+{
+ virtual void exec( const QString & ) = 0;
+ virtual ~IRCSignalMappingT() {};
+};
+
+struct IRCSignalMappingSingleT : IRCSignalMappingBase
+{
+ virtual void exec( const QString &, const QString & ) = 0;
+ virtual ~IRCSignalMappingSingleT() {};
+};
+
+struct IRCSignalMappingDoubleT : IRCSignalMappingBase
+{
+ virtual void exec( const QString &, const QString &, const QString & ) = 0;
+ virtual ~IRCSignalMappingDoubleT() {};
+};
+
+struct IRCSignalMappingTripleT : IRCSignalMappingBase
+{
+ virtual void exec( const QString &, const QString &, const QString &, const QString & ) = 0;
+ virtual ~IRCSignalMappingTripleT() {};
+};
+
+/***
+QObject members, these connect to the KIRC signals and call
+the Mapping functions when they emit.
+**/
+
+class QMember : public QObject
+{
+ Q_OBJECT
+
+ public:
+ QMember( IRCSignalMappingT *m, QObject *p ) : QObject( p ), mapping( m ){};
+
+ public slots:
+ void slotEmit( const QString &id )
+ {
+ //kdDebug(14120) << k_funcinfo << id << endl;
+ mapping->exec(id);
+ }
+
+ private:
+ IRCSignalMappingT *mapping;
+};
+
+class QMemberSingle : public QObject
+{
+ Q_OBJECT
+
+ public:
+ QMemberSingle( IRCSignalMappingSingleT *m, QObject *p ) : QObject( p ), mapping( m ){}
+
+ public slots:
+ void slotEmit( const QString &id, const QString &arg )
+ {
+ //kdDebug(14120) << k_funcinfo << id << " : " << arg << endl;
+ mapping->exec(id,arg);
+ }
+
+ private:
+ IRCSignalMappingSingleT *mapping;
+};
+
+class QMemberDouble : public QObject
+{
+ Q_OBJECT
+
+ public:
+ QMemberDouble( IRCSignalMappingDoubleT *m, QObject *p ) : QObject( p ), mapping( m ){}
+
+ public slots:
+ void slotEmit( const QString &id, const QString &arg, const QString &arg2 )
+ {
+ //kdDebug(14120) << k_funcinfo << id << " : " << arg << " : " << arg2 << endl;
+ mapping->exec(id,arg,arg2);
+ }
+
+ private:
+ IRCSignalMappingDoubleT *mapping;
+};
+
+class QMemberTriple : public QObject
+{
+ Q_OBJECT
+
+ public:
+ QMemberTriple( IRCSignalMappingTripleT *m, QObject *p ) : QObject( p ), mapping( m ){}
+
+ public slots:
+ void slotEmit( const QString &id, const QString &arg, const QString &arg2, const QString &arg3 )
+ {
+ //kdDebug(14120) << k_funcinfo << id << " : " << arg << " : " << arg2 << " : " << arg3 << endl;
+ mapping->exec(id,arg,arg2,arg3);
+ }
+
+ private:
+ IRCSignalMappingTripleT *mapping;
+};
+
+/***
+Mapping classes. These contain pointers to the functions to call. We first
+look up the right contact in the contact manager's dictionary, and then
+call the method
+**/
+
+template <class TClass>
+class IRCSignalMapping : public IRCSignalMappingT
+{
+ public:
+ IRCSignalMapping( IRCContactManager *mgr, const char * /*signal*/,
+ void (TClass::*m)() ) : manager(mgr), method(m){}
+
+ void exec( const QString &id )
+ {
+ TClass *c = (TClass*)manager->findContact( id );
+ if( c )
+ {
+ void (TClass::*tmp)() = (void (TClass::*)())method;
+ (*c.*tmp)();
+ }
+ }
+
+ private:
+ IRCContactManager *manager;
+ void (TClass::*method)();
+};
+
+template <class TClass>
+class IRCSignalMappingSingle : public IRCSignalMappingSingleT
+{
+ public:
+ IRCSignalMappingSingle<TClass>( IRCContactManager *mgr, const char * /*signal*/,
+ void (TClass::*m)(const QString&) ) : manager(mgr), method(m){}
+
+ void exec( const QString &id, const QString &arg )
+ {
+ TClass *c = (TClass*)manager->findContact( id );
+ if( c )
+ {
+ void (TClass::*tmp)(const QString&) = (void (TClass::*)(const QString&))method;
+ (*c.*tmp)( arg );
+ }
+ }
+
+ private:
+ IRCContactManager *manager;
+ void (TClass::*method)(const QString &);
+};
+
+template <class TClass>
+class IRCSignalMappingDouble : public IRCSignalMappingDoubleT
+{
+ public:
+ IRCSignalMappingDouble<TClass>( IRCContactManager *mgr, const char * /*signal*/,
+ void (TClass::*m)(const QString&,const QString&) ) : manager(mgr), method(m){}
+
+ void exec( const QString &id,const QString &arg, const QString &arg2 )
+ {
+ TClass *c = (TClass*)manager->findContact( id );
+ if( c )
+ {
+ void (TClass::*tmp)(const QString&,const QString&) =
+ (void (TClass::*)(const QString&,const QString&))method;
+ (*c.*tmp)(arg,arg2);
+ }
+ }
+
+ private:
+ IRCContactManager *manager;
+ void (TClass::*method)(const QString &,const QString &);
+};
+
+template <class TClass>
+class IRCSignalMappingTriple : public IRCSignalMappingTripleT
+{
+ public:
+ IRCSignalMappingTriple<TClass>( IRCContactManager *mgr, const char * /*signal*/,
+ void (TClass::*m)(const QString&,const QString&,const QString&) )
+ : manager(mgr), method(m){}
+
+ void exec( const QString &id,const QString&arg, const QString &arg2, const QString &arg3 )
+ {
+ TClass *c = (TClass*)manager->findContact( id );
+ if( c )
+ {
+ void (TClass::*tmp)(const QString&,const QString&,const QString&) =
+ (void (TClass::*)(const QString&,const QString&,const QString&))method;
+ (*c.*tmp)(arg,arg2,arg3);
+ }
+ }
+
+ private:
+ IRCContactManager *manager;
+ void (TClass::*method)(const QString &,const QString &,const QString &);
+};
+
+class IRCSignalHandler : public QObject
+{
+ Q_OBJECT
+
+ public:
+ IRCSignalHandler( IRCContactManager *manager );
+ ~IRCSignalHandler();
+
+ private slots:
+
+ /****
+ Slots for signals with non-QString types
+ */
+
+ //Channel contact slots
+ void slotNamesList( const QString &, const QStringList & );
+ void slotEndOfNames( const QString & );
+ void slotTopicUser( const QString &, const QString&, const QDateTime &);
+
+ //User contact slots
+ void slotNewWhoIsIdle(const QString &, unsigned long );
+ void slotNewWhoReply(const QString &, const QString &, const QString &, const QString &,
+ const QString &, bool , const QString &, uint , const QString & );
+
+ private:
+ IRCContactManager *manager;
+ QValueList<IRCSignalMappingBase*> mappings;
+
+ /****
+ Signal mapping functions
+ */
+
+ template <class TClass>
+ inline void map( IRCContactManager *m, const char* signal, void (TClass::*method)() )
+ {
+ IRCSignalMappingT *mapping = new IRCSignalMapping<TClass>( m, signal, method );
+ mappings.append(mapping);
+ QObject::connect( static_cast<IRCAccount*>( m->mySelf()->account() )->engine(), signal,
+ new QMember( mapping, this),
+ SLOT( slotEmit( const QString &) )
+ );
+ }
+
+ template <class TClass>
+ inline void mapSingle( IRCContactManager *m,
+ const char* signal, void (TClass::*method)(const QString&) )
+ {
+ IRCSignalMappingSingleT *mapping = new IRCSignalMappingSingle<TClass>( m, signal, method );
+ mappings.append(mapping);
+ QObject::connect( static_cast<IRCAccount*>( m->mySelf()->account() )->engine(), signal,
+ new QMemberSingle( mapping, this),
+ SLOT( slotEmit( const QString &, const QString &) )
+ );
+ }
+
+ template <class TClass>
+ inline void mapDouble( IRCContactManager *m,
+ const char* signal, void (TClass::*method)(const QString&,const QString&) )
+ {
+ IRCSignalMappingDoubleT *mapping = new IRCSignalMappingDouble<TClass>( m, signal, method );
+ mappings.append(mapping);
+ QObject::connect( static_cast<IRCAccount*>( m->mySelf()->account() )->engine(), signal,
+ new QMemberDouble( mapping, this),
+ SLOT( slotEmit( const QString &, const QString &,const QString &) )
+ );
+ }
+
+ template <class TClass>
+ inline void mapTriple( IRCContactManager *m,
+ const char* signal,
+ void (TClass::*method)(const QString&,const QString &, const QString &) )
+ {
+ IRCSignalMappingTripleT *mapping = new IRCSignalMappingTriple<TClass>( m, signal, method );
+ mappings.append(mapping);
+ QObject::connect( static_cast<IRCAccount*>( m->mySelf()->account() )->engine(), signal,
+ new QMemberTriple( mapping, this),
+ SLOT( slotEmit( const QString &, const QString &,const QString &,const QString &) )
+ );
+ }
+};
+
+#endif
diff --git a/kopete/protocols/irc/irctransferhandler.cpp b/kopete/protocols/irc/irctransferhandler.cpp
new file mode 100644
index 00000000..4715679e
--- /dev/null
+++ b/kopete/protocols/irc/irctransferhandler.cpp
@@ -0,0 +1,183 @@
+/*
+ irctransferhandler.cpp - IRC transfer.
+
+ Copyright (c) 2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <kdebug.h>
+
+#include <kopetetransfermanager.h>
+
+#include "libkirc/kirctransfer.h"
+#include "libkirc/kirctransferhandler.h"
+
+#include "kopetemetacontact.h"
+#include "irccontact.h"
+#include "irccontactmanager.h"
+
+#include "irctransferhandler.h"
+
+IRCTransferHandler *IRCTransferHandler::self()
+{
+ static IRCTransferHandler sm_self;
+ return &sm_self;
+}
+
+KIRC::TransferHandler *IRCTransferHandler::handler()
+{
+ return KIRC::TransferHandler::self();
+}
+
+IRCTransferHandler::IRCTransferHandler()
+{
+ connect(handler(), SIGNAL(transferCreated(KIRC::Transfer *)),
+ this, SLOT(transferCreated(KIRC::Transfer *)));
+
+ connect(Kopete::TransferManager::transferManager(), SIGNAL(accepted(Kopete::Transfer *, const QString &)),
+ this, SLOT(transferAccepted(Kopete::Transfer *, const QString&)));
+ connect( Kopete::TransferManager::transferManager(), SIGNAL(refused(const Kopete::FileTransferInfo &)),
+ this, SLOT(transferRefused(const Kopete::FileTransferInfo &)));
+}
+
+void IRCTransferHandler::transferCreated(KIRC::Transfer *t)
+{
+ kdDebug(14120) << k_funcinfo << endl;
+
+ IRCContact *contact = IRCContactManager::existContact(t->engine(), t->nick());
+ QString fileName = t->fileName();
+ unsigned long fileSize = t->fileSize();
+
+ if(!contact)
+ {
+ kdDebug(14120) << k_funcinfo << "Trying to create transfer for a non existing contact(" << t->nick() << ")." << endl;
+ return;
+ }
+
+ switch(t->type())
+ {
+// case KIRC::Transfer::Chat:
+ case KIRC::Transfer::FileOutgoing:
+ {
+ Kopete::Transfer *kt = Kopete::TransferManager::transferManager()->addTransfer(
+ contact, fileName, fileSize, contact->metaContact()->displayName(),
+ Kopete::FileTransferInfo::Outgoing);
+ connectKopeteTransfer(kt, t);
+ }
+ break;
+ case KIRC::Transfer::FileIncoming:
+ {
+ int ID = Kopete::TransferManager::transferManager()->askIncomingTransfer(
+ contact , fileName, fileSize);
+ m_idMap.insert(ID, t);
+ }
+ break;
+ default:
+ kdDebug(14120) << k_funcinfo << "Unknown transfer type" << endl;
+ t->deleteLater();
+ }
+}
+
+void IRCTransferHandler::transferAccepted(Kopete::Transfer *kt, const QString &file)
+{
+ kdDebug(14120) << k_funcinfo << endl;
+
+ KIRC::Transfer *t = getKIRCTransfer(kt->info());
+ if(t)
+ {
+ t->setFileName(file);
+ connectKopeteTransfer(kt, t);
+ }
+}
+void IRCTransferHandler::transferRefused(const Kopete::FileTransferInfo &info)
+{
+ kdDebug(14120) << k_funcinfo << endl;
+
+ KIRC::Transfer *t = getKIRCTransfer(info);
+ if(t)
+ {
+ t->deleteLater();
+ }
+}
+
+void IRCTransferHandler::connectKopeteTransfer(Kopete::Transfer *kt, KIRC::Transfer *t)
+{
+ kdDebug(14120) << k_funcinfo << endl;
+
+ if(kt && t)
+ {
+ switch(t->type())
+ {
+// case KIRC::Transfer::Chat:
+ case KIRC::Transfer::FileOutgoing:
+ case KIRC::Transfer::FileIncoming:
+ connect(t , SIGNAL(fileSizeAcknowledge(unsigned int)),
+ kt, SLOT(slotProcessed(unsigned int)));
+ break;
+ default:
+ kdDebug(14120) << k_funcinfo << "Unknown transfer connections for type" << endl;
+ t->deleteLater();
+ return;
+ }
+
+ connect(t , SIGNAL(complete()),
+ kt, SLOT(slotComplete()));
+
+// connect(kt , SIGNAL(transferCanceled()),
+// t, SLOT(abort()));
+// connect(kt, SIGNAL(destroyed()),
+// t, SLOT(slotKopeteTransferDestroyed()));
+
+ connect(kt, SIGNAL(result(KIO::Job *)),
+ this , SLOT(kioresult(KIO::Job *)));
+
+ t->initiate();
+ }
+}
+
+void IRCTransferHandler::kioresult(KIO::Job *job)
+{
+ Kopete::Transfer *kt= (Kopete::Transfer *)job; // FIXME: move to *_cast
+ if(!kt)
+ {
+ kdDebug(14120) << k_funcinfo << "Kopete::Transfer not found from kio:" << job << endl;
+ return;
+ }
+
+ switch(kt->error())
+ {
+ case 0: // 0 means no error
+ break;
+ case KIO::ERR_USER_CANCELED:
+ kdDebug(14120) << k_funcinfo << "User canceled transfer." << endl;
+ // KIO::buildErrorString form error don't provide a result string ...
+// if (t->)
+// kt->userAbort(i18n("User canceled transfer."));
+// else
+// kt->userAbort(i18n("User canceled transfer for file:%1").arg(t->fileName()));
+ break;
+ default:
+ kdDebug(14120) << k_funcinfo << "Transfer halted:" << kt->error() << endl;
+// kt->userAbort(KIO::buildErrorString(kt->error(), kt->fileName()));
+ break;
+ }
+}
+
+KIRC::Transfer *IRCTransferHandler::getKIRCTransfer(const Kopete::FileTransferInfo &info)
+{
+ KIRC::Transfer *t = m_idMap[info.transferId()];
+ m_idMap.remove(info.transferId());
+ return t;
+}
+
+#include "irctransferhandler.moc"
diff --git a/kopete/protocols/irc/irctransferhandler.h b/kopete/protocols/irc/irctransferhandler.h
new file mode 100644
index 00000000..17c419ae
--- /dev/null
+++ b/kopete/protocols/irc/irctransferhandler.h
@@ -0,0 +1,65 @@
+/*
+ irctransferhandler.h - IRC transfer.
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef IRCTRANSFERHANDLER_H
+#define IRCTRANSFERHANDLER_H
+
+#include <qintdict.h>
+
+#include <kopetetransfermanager.h>
+
+namespace Kopete
+{
+ class Transfer;
+}
+
+namespace KIRC
+{
+class Transfer;
+class TransferHandler;
+}
+
+class IRCTransferHandler
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ static IRCTransferHandler *self();
+
+private slots:
+ void transferCreated(KIRC::Transfer *);
+ void transferAccepted(Kopete::Transfer *kt, const QString&file);
+ void transferRefused(const Kopete::FileTransferInfo &info);
+
+ void kioresult(KIO::Job *job);
+
+private:
+ IRCTransferHandler();
+
+ void connectKopeteTransfer(Kopete::Transfer *kt, KIRC::Transfer *t);
+
+ /* warning: After calling this method the KIRC::Transfer is removed from the m_idMap.
+ */
+ KIRC::Transfer *getKIRCTransfer(const Kopete::FileTransferInfo &info);
+
+ KIRC::TransferHandler *handler();
+
+ QIntDict<KIRC::Transfer> m_idMap;
+};
+
+#endif
diff --git a/kopete/protocols/irc/ircusercontact.cpp b/kopete/protocols/irc/ircusercontact.cpp
new file mode 100644
index 00000000..dc9dcbf2
--- /dev/null
+++ b/kopete/protocols/irc/ircusercontact.cpp
@@ -0,0 +1,734 @@
+/*
+ ircusercontact.cpp - IRC User Contact
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+
+ Kopete (c) 2002 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "ircusercontact.h"
+#include "ircservercontact.h"
+#include "ircchannelcontact.h"
+#include "irccontactmanager.h"
+#include "ircaccount.h"
+#include "ircprotocol.h"
+#include "kcodecaction.h"
+
+#include "kopetemetacontact.h"
+#include "kopeteview.h"
+
+#include <kaction.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+
+#include <qtimer.h>
+
+IRCUserContact::IRCUserContact(IRCContactManager *contactManager, const QString &nickname, Kopete::MetaContact *m )
+ : IRCContact(contactManager, nickname, m ),
+ actionCtcpMenu(0L)
+{
+ setFileCapable(true);
+
+ mOnlineTimer = new QTimer( this );
+
+ QObject::connect(mOnlineTimer, SIGNAL(timeout()), this, SLOT( slotUserOffline() ) );
+
+ QObject::connect(kircEngine(), SIGNAL(incomingChannelModeChange(const QString&, const QString&, const QString&)),
+ this, SLOT(slotIncomingModeChange(const QString&,const QString&, const QString&)));
+
+ mInfo.isOperator = false;
+ mInfo.isIdentified = false;
+ mInfo.idle = 0;
+ mInfo.hops = 0;
+ mInfo.away = false;
+ mInfo.online = metaContact()->isTemporary();
+
+ updateStatus();
+}
+
+void IRCUserContact::updateStatus()
+{
+ //kdDebug(14120) << k_funcinfo << endl;
+
+ Kopete::OnlineStatus newStatus;
+
+ switch (kircEngine()->status())
+ {
+ case KIRC::Engine::Idle:
+ newStatus = m_protocol->m_UserStatusOffline;
+ break;
+
+ case KIRC::Engine::Connecting:
+ case KIRC::Engine::Authentifying:
+ if (this == ircAccount()->mySelf())
+ newStatus = m_protocol->m_UserStatusConnecting;
+ else
+ newStatus = m_protocol->m_UserStatusOffline;
+ break;
+
+ case KIRC::Engine::Connected:
+ case KIRC::Engine::Closing:
+ if (mInfo.away)
+ newStatus = m_protocol->m_UserStatusAway;
+ else if (mInfo.online)
+ newStatus = m_protocol->m_UserStatusOnline;
+ break;
+
+ default:
+ newStatus = m_protocol->m_StatusUnknown;
+ }
+
+ // Try hard not to emit several onlineStatusChanged() signals.
+ bool onlineStatusChanged = false;
+
+
+ /* The away status is global, so if the user goes away, we must set
+ * the new status on all channels.
+ */
+
+
+ // This may not be created yet ( for myself() on startup )
+ if( ircAccount()->contactManager() )
+ {
+ QValueList<IRCChannelContact*> channels = ircAccount()->contactManager()->findChannelsByMember(this);
+
+ for( QValueList<IRCChannelContact*>::iterator it = channels.begin(); it != channels.end(); ++it )
+ {
+ IRCChannelContact *channel = *it;
+ Kopete::OnlineStatus currentStatus = channel->manager()->contactOnlineStatus(this);
+
+ //kdDebug(14120) << k_funcinfo << "iterating channel " << channel->nickName() << " internal status: " << currentStatus.internalStatus() << endl;
+
+ if( currentStatus.internalStatus() >= IRCProtocol::Online )
+ {
+ onlineStatusChanged = true;
+
+ if( !(currentStatus.internalStatus() & IRCProtocol::Away) && newStatus == m_protocol->m_UserStatusAway )
+ {
+ setOnlineStatus( newStatus );
+ //kdDebug(14120) << k_funcinfo << "was NOT away, but is now, channel " << channel->nickName() << endl;
+ adjustInternalOnlineStatusBits(channel, IRCProtocol::Away, AddBits);
+ }
+ else if( (currentStatus.internalStatus() & IRCProtocol::Away) && newStatus == m_protocol->m_UserStatusOnline )
+ {
+ setOnlineStatus( newStatus );
+ //kdDebug(14120) << k_funcinfo << "was away, but not anymore, channel " << channel->nickName() << endl;
+ adjustInternalOnlineStatusBits(channel, IRCProtocol::Away, RemoveBits);
+
+ }
+ else if( newStatus.internalStatus() < IRCProtocol::Away )
+ {
+ //kdDebug(14120) << k_funcinfo << "offline or connecting?" << endl;
+ channel->manager()->setContactOnlineStatus( this, newStatus );
+ }
+ }
+ }
+ }
+
+ if (!onlineStatusChanged) {
+ //kdDebug(14120) << k_funcinfo << "setting status at last" << endl;
+ setOnlineStatus( newStatus );
+ }
+}
+
+void IRCUserContact::sendFile(const KURL &sourceURL, const QString&, unsigned int)
+{
+ QString filePath;
+
+ //If the file location is null, then get it from a file open dialog
+ if( !sourceURL.isValid() )
+ filePath = KFileDialog::getOpenFileName(QString::null, "*", 0l , i18n("Kopete File Transfer"));
+ else
+ filePath = sourceURL.path(-1);
+
+ kdDebug(14120) << k_funcinfo << "File chosen to send:" << filePath << endl;
+
+ if (!filePath.isEmpty())
+ kircEngine()->CtcpRequest_dcc( m_nickName, filePath, 0, KIRC::Transfer::FileOutgoing);
+}
+
+void IRCUserContact::slotUserOffline()
+{
+ mInfo.online = false;
+ mInfo.away = false;
+
+ updateStatus();
+
+ if( !metaContact()->isTemporary() )
+ kircEngine()->writeMessage( QString::fromLatin1("WHOWAS %1").arg(m_nickName) );
+
+ removeProperty( m_protocol->propUserInfo );
+ removeProperty( m_protocol->propServer );
+ removeProperty( m_protocol->propChannels );
+}
+
+void IRCUserContact::setAway(bool isAway)
+{
+ //kdDebug(14120) << k_funcinfo << isAway << endl;
+
+ mInfo.away = isAway;
+ updateStatus();
+}
+
+void IRCUserContact::incomingUserIsAway(const QString &reason)
+{
+ if( manager( Kopete::Contact::CannotCreate ) )
+ {
+ Kopete::Message msg( (Kopete::Contact*)ircAccount()->myServer(), mMyself,
+ i18n("%1 is away (%2)").arg( m_nickName ).arg( reason ),
+ Kopete::Message::Internal, Kopete::Message::RichText, CHAT_VIEW );
+ manager(Kopete::Contact::CanCreate)->appendMessage(msg);
+ }
+}
+
+void IRCUserContact::userOnline()
+{
+ mInfo.online = true;
+ updateStatus();
+ if (this != ircAccount()->mySelf() && !metaContact()->isTemporary() && ircAccount()->isConnected())
+ {
+ mOnlineTimer->start( 45000, true );
+ ircAccount()->setCurrentCommandSource(0);
+ kircEngine()->whois(m_nickName);
+ }
+
+ removeProperty( m_protocol->propLastSeen );
+}
+
+void IRCUserContact::slotUserInfo()
+{
+ if (isChatting())
+ {
+ ircAccount()->setCurrentCommandSource(manager());
+ kircEngine()->whois(m_nickName);
+ }
+}
+
+const QString IRCUserContact::caption() const
+{
+ return i18n("%1 @ %2").arg(m_nickName).arg(kircEngine()->currentHost());
+}
+
+void IRCUserContact::slotOp()
+{
+ contactMode( QString::fromLatin1("+o") );
+}
+
+void IRCUserContact::slotDeop()
+{
+ contactMode( QString::fromLatin1("-o") );
+}
+
+void IRCUserContact::slotVoice()
+{
+ contactMode( QString::fromLatin1("+v") );
+}
+
+void IRCUserContact::slotDevoice()
+{
+ contactMode( QString::fromLatin1("-v") );
+}
+
+void IRCUserContact::slotBanHost()
+{
+ // MODE #foofoofoo +b *!*@host.domain.net
+
+ if (mInfo.hostName.isEmpty()) {
+ if (kircEngine()->isConnected()) {
+ kircEngine()->whois(m_nickName);
+ QTimer::singleShot( 750, this, SLOT( slotBanHostOnce() ) );
+ }
+ } else {
+ slotBanHostOnce();
+ }
+}
+void IRCUserContact::slotBanHostOnce()
+{
+ if (mInfo.hostName.isEmpty())
+ return;
+
+ Kopete::ContactPtrList members = mActiveManager->members();
+ QString channelName = static_cast<IRCContact*>(members.first())->nickName();
+
+ kircEngine()->mode(channelName, QString::fromLatin1("+b *!*@%1").arg(mInfo.hostName));
+}
+
+void IRCUserContact::slotBanUserHost()
+{
+ // MODE #foofoofoo +b *!*user@host.domain.net
+
+ if (mInfo.hostName.isEmpty()) {
+ if (kircEngine()->isConnected()) {
+ kircEngine()->whois(m_nickName);
+ QTimer::singleShot( 750, this, SLOT( slotBanUserHostOnce() ) );
+ }
+ } else {
+ slotBanUserHostOnce();
+ }
+}
+void IRCUserContact::slotBanUserHostOnce()
+{
+ if (mInfo.hostName.isEmpty())
+ return;
+
+ Kopete::ContactPtrList members = mActiveManager->members();
+ QString channelName = static_cast<IRCContact*>(members.first())->nickName();
+
+ kircEngine()->mode(channelName, QString::fromLatin1("+b *!*%1@%2").arg(mInfo.userName, mInfo.hostName));
+}
+
+void IRCUserContact::slotBanDomain()
+{
+ // MODE #foofoofoo +b *!*@*.domain.net
+
+ if (mInfo.hostName.isEmpty()) {
+ if (kircEngine()->isConnected()) {
+ kircEngine()->whois(m_nickName);
+ QTimer::singleShot( 750, this, SLOT( slotBanDomainOnce() ) );
+ }
+ } else {
+ slotBanDomainOnce();
+ }
+}
+void IRCUserContact::slotBanDomainOnce()
+{
+ if (mInfo.hostName.isEmpty())
+ return;
+
+ Kopete::ContactPtrList members = mActiveManager->members();
+ QString channelName = static_cast<IRCContact*>(members.first())->nickName();
+
+ QString domain = mInfo.hostName.section('.', 1);
+
+ kircEngine()->mode(channelName, QString::fromLatin1("+b *!*@*.%1").arg(domain));
+}
+
+void IRCUserContact::slotBanUserDomain()
+{
+ // MODE #foofoofoo +b *!*user@*.domain.net
+
+ if (mInfo.hostName.isEmpty()) {
+ if (kircEngine()->isConnected()) {
+ kircEngine()->whois(m_nickName);
+ QTimer::singleShot( 750, this, SLOT( slotBanUserDomainOnce() ) );
+ }
+ } else {
+ slotBanUserDomainOnce();
+ }
+}
+void IRCUserContact::slotBanUserDomainOnce()
+{
+ if (mInfo.hostName.isEmpty())
+ return;
+
+ Kopete::ContactPtrList members = mActiveManager->members();
+ QString channelName = static_cast<IRCContact*>(members.first())->nickName();
+
+ QString domain = mInfo.hostName.section('.', 1);
+
+ kircEngine()->mode(channelName, QString::fromLatin1("+b *!*%1@*.%2").arg(mInfo.userName, domain));
+}
+
+void IRCUserContact::slotKick()
+{
+ Kopete::ContactPtrList members = mActiveManager->members();
+ QString channelName = static_cast<IRCContact*>(members.first())->nickName();
+ kircEngine()->kick(m_nickName, channelName, QString::null);
+}
+
+void IRCUserContact::contactMode(const QString &mode)
+{
+ Kopete::ContactPtrList members = mActiveManager->members();
+ QString channelName = static_cast<IRCContact*>(members.first())->nickName();
+ kircEngine()->mode(channelName, QString::fromLatin1("%1 %2").arg(mode).arg(m_nickName));
+}
+
+void IRCUserContact::slotCtcpPing()
+{
+ kircEngine()->CtcpRequest_ping(m_nickName);
+}
+
+void IRCUserContact::slotCtcpVersion()
+{
+ kircEngine()->CtcpRequest_version(m_nickName);
+}
+
+void IRCUserContact::newWhoIsUser(const QString &username, const QString &hostname, const QString &realname)
+{
+ mInfo.channels.clear();
+ mInfo.userName = username;
+ mInfo.hostName = hostname;
+ mInfo.realName = realname;
+
+ if( onlineStatus().status() == Kopete::OnlineStatus::Offline )
+ {
+ setProperty( m_protocol->propUserInfo, QString::fromLatin1("%1@%2")
+ .arg(mInfo.userName).arg(mInfo.hostName) );
+ setProperty( m_protocol->propServer, mInfo.serverName );
+ setProperty( m_protocol->propFullName, mInfo.realName );
+ }
+}
+
+void IRCUserContact::newWhoIsServer(const QString &servername, const QString &serverinfo)
+{
+ mInfo.serverName = servername;
+ if( metaContact()->isTemporary() || onlineStatus().status() == Kopete::OnlineStatus::Online
+ || onlineStatus().status() == Kopete::OnlineStatus::Away )
+ mInfo.serverInfo = serverinfo;
+ else
+ {
+ //kdDebug(14120)<< "Setting last online: " << serverinfo << endl;
+
+ // Try to convert first, since server can return depending if
+ // user is online or not:
+ //
+ // 312 mynick othernick localhost.localdomain :FooNet Server
+ // 312 mynick othernick localhost.localdomain :Thu Jun 16 21:00:36 2005
+
+ QDateTime lastSeen = QDateTime::fromString( serverinfo );
+ if( lastSeen.isValid() )
+ setProperty( m_protocol->propLastSeen, lastSeen );
+ }
+}
+
+void IRCUserContact::newWhoIsIdle(unsigned long idle)
+{
+ mInfo.idle = idle;
+}
+
+void IRCUserContact::newWhoIsOperator()
+{
+ mInfo.isOperator = true;
+}
+
+void IRCUserContact::newWhoIsIdentified()
+{
+ mInfo.isIdentified = true;
+ setProperty( m_protocol->propIsIdentified, i18n("True") );
+}
+
+void IRCUserContact::newWhoIsChannels(const QString &channel)
+{
+ mInfo.channels.append( channel );
+}
+
+void IRCUserContact::whoIsComplete()
+{
+ Kopete::ChatSession *commandSource = ircAccount()->currentCommandSource();
+
+ updateInfo();
+
+ if( isChatting() && commandSource &&
+ commandSource == manager(Kopete::Contact::CannotCreate) )
+ {
+ //User info
+ QString msg = i18n("%1 is (%2@%3): %4<br/>")
+ .arg(m_nickName)
+ .arg(mInfo.userName)
+ .arg(mInfo.hostName)
+ .arg(mInfo.realName);
+
+ if( mInfo.isIdentified )
+ msg += i18n("%1 is authenticated with NICKSERV<br/>").arg(m_nickName);
+
+ if( mInfo.isOperator )
+ msg += i18n("%1 is an IRC operator<br/>").arg(m_nickName);
+
+ //Channels
+ msg += i18n("on channels %1<br/>").arg(mInfo.channels.join(" ; "));
+
+ //Server
+ msg += i18n("on IRC via server %1 ( %2 )<br/>").arg(mInfo.serverName).arg(mInfo.serverInfo);
+
+ //Idle
+ QString idleTime = formattedIdleTime();
+ msg += i18n("idle: %2<br/>").arg( idleTime.isEmpty() ? QString::number(0) : idleTime );
+
+ //End
+ ircAccount()->appendMessage(msg, IRCAccount::InfoReply );
+ ircAccount()->setCurrentCommandSource(0);
+ }
+}
+
+void IRCUserContact::whoWasComplete()
+{
+ if( isChatting() && ircAccount()->currentCommandSource() == manager() )
+ {
+ //User info
+ QString msg = i18n("%1 was (%2@%3): %4\n")
+ .arg(m_nickName)
+ .arg(mInfo.userName)
+ .arg(mInfo.hostName)
+ .arg(mInfo.realName);
+
+ msg += i18n("Last Online: %1\n").arg(
+ KGlobal::locale()->formatDateTime(
+ property( m_protocol->propLastSeen ).value().toDateTime()
+ )
+ );
+
+ ircAccount()->appendMessage(msg, IRCAccount::InfoReply );
+ ircAccount()->setCurrentCommandSource(0);
+ }
+}
+
+QString IRCUserContact::formattedName() const
+{
+ return mInfo.realName;
+}
+
+void IRCUserContact::updateInfo()
+{
+ setProperty( m_protocol->propUserInfo, QString::fromLatin1("%1@%2")
+ .arg(mInfo.userName).arg(mInfo.hostName) );
+ setProperty( m_protocol->propServer, mInfo.serverName );
+ setProperty( m_protocol->propChannels, mInfo.channels.join(" ") );
+ setProperty( m_protocol->propHops, QString::number(mInfo.hops) );
+ setProperty( m_protocol->propFullName, mInfo.realName );
+
+ setIdleTime( mInfo.idle );
+
+ mInfo.lastUpdate = QTime::currentTime();
+}
+
+void IRCUserContact::newWhoReply( const QString &channel, const QString &user, const QString &host,
+ const QString &server, bool away, const QString &flags, uint hops, const QString &realName )
+{
+ if( !mInfo.channels.contains( channel ) )
+ mInfo.channels.append( channel );
+
+ mInfo.userName = user;
+ mInfo.hostName = host;
+ mInfo.serverName = server;
+ mInfo.flags = flags;
+ mInfo.hops = hops;
+ mInfo.realName = realName;
+
+ setAway(away);
+
+ updateInfo();
+
+ if( isChatting() && ircAccount()->currentCommandSource() == manager() )
+ {
+ ircAccount()->setCurrentCommandSource(0);
+ }
+}
+
+QPtrList<KAction> *IRCUserContact::customContextMenuActions( Kopete::ChatSession *manager )
+{
+ if( manager )
+ {
+ QPtrList<KAction> *mCustomActions = new QPtrList<KAction> ();
+ mActiveManager = manager;
+ Kopete::ContactPtrList members = mActiveManager->members();
+ IRCChannelContact *isChannel = dynamic_cast<IRCChannelContact*>( members.first() );
+
+ if( !actionCtcpMenu )
+ {
+ actionCtcpMenu = new KActionMenu(i18n("C&TCP"), 0, this );
+ actionCtcpMenu->insert( new KAction(i18n("&Version"), 0, this,
+ SLOT(slotCtcpVersion()), actionCtcpMenu) );
+ actionCtcpMenu->insert( new KAction(i18n("&Ping"), 0, this,
+ SLOT(slotCtcpPing()), actionCtcpMenu) );
+
+ actionModeMenu = new KActionMenu(i18n("&Modes"), 0, this, "actionModeMenu");
+ actionModeMenu->insert( new KAction(i18n("&Op"), 0, this,
+ SLOT(slotOp()), actionModeMenu, "actionOp") );
+ actionModeMenu->insert( new KAction(i18n("&Deop"), 0, this,
+ SLOT(slotDeop()), actionModeMenu, "actionDeop") );
+ actionModeMenu->insert( new KAction(i18n("&Voice"), 0, this,
+ SLOT(slotVoice()), actionModeMenu, "actionVoice") );
+ actionModeMenu->insert( new KAction(i18n("Devoice"), 0, this,
+ SLOT(slotDevoice()), actionModeMenu, "actionDevoice") );
+ actionModeMenu->setEnabled( false );
+
+ actionKick = new KAction(i18n("&Kick"), 0, this, SLOT(slotKick()), this);
+ actionKick->setEnabled( false );
+
+ actionBanMenu = new KActionMenu(i18n("&Ban"), 0, this, "actionBanMenu");
+ actionBanMenu->insert( new KAction(i18n("Host (*!*@host.domain.net)"), 0, this,
+ SLOT(slotBanHost()), actionBanMenu ) );
+ actionBanMenu->insert( new KAction(i18n("Domain (*!*@*.domain.net)"), 0, this,
+ SLOT(slotBanDomain()), actionBanMenu ) );
+ actionBanMenu->insert( new KAction(i18n("User@Host (*!*user@host.domain.net)"), 0, this,
+ SLOT(slotBanUserHost()), actionBanMenu ) );
+ actionBanMenu->insert( new KAction(i18n("User@Domain (*!*user@*.domain.net)"), 0, this,
+ SLOT(slotBanUserDomain()), actionBanMenu ) );
+ actionBanMenu->setEnabled( false );
+
+ codecAction = new KCodecAction( i18n("&Encoding"), 0, this, "selectcharset" );
+ connect( codecAction, SIGNAL( activated( const QTextCodec * ) ),
+ this, SLOT( setCodec( const QTextCodec *) ) );
+ codecAction->setCodec( codec() );
+ }
+
+ mCustomActions->append( actionCtcpMenu );
+ mCustomActions->append( actionModeMenu );
+ mCustomActions->append( actionKick );
+ mCustomActions->append( actionBanMenu );
+ mCustomActions->append( codecAction );
+
+ if( isChannel )
+ {
+ bool isOperator = ( manager->contactOnlineStatus( account()->myself() ).internalStatus() & IRCProtocol::Operator );
+ actionModeMenu->setEnabled(isOperator);
+ actionBanMenu->setEnabled(isOperator);
+ actionKick->setEnabled(isOperator);
+ }
+
+ return mCustomActions;
+ }
+
+ mActiveManager = 0L;
+
+ return 0L;
+}
+
+void IRCUserContact::slotIncomingModeChange( const QString &channel, const QString &, const QString &mode_ )
+{
+ kdDebug(14120) << k_funcinfo << "channel: " << channel << " mode: " << mode_ << endl;
+
+ IRCChannelContact *chan = ircAccount()->contactManager()->findChannel( channel );
+
+ if( !chan->locateUser( m_nickName ) )
+ return;
+
+ // :foobar_!~fooobar@dhcp.inet.fi MODE #foofoofoo2 +o kakkonen
+ // :foobar_!~fooobar@dhcp.inet.fi MODE #foofoofoo2 +o-o foobar001 kakkonen
+ // :foobar_!~fooobar@dhcp.inet.fi MODE #foofoofoo2 +oo kakkonen foobar001
+ // :foobar_!~fooobar@dhcp.inet.fi MODE #foofoofoo2 +o-ov foobar001 kakkonen foobar001
+ //
+ // irssi manual example: /MODE #channel +nto-o+v nick1 nick2 nick3
+
+ QStringList users = QStringList::split(' ', mode_);
+ users.pop_front();
+
+ const QString mode = mode_.section(' ', 0, 0);
+
+ bitAdjustment adjMode = RemoveBits;
+ QStringList::iterator user = users.begin();
+
+ //kdDebug(14120) << "me: " << m_nickName << " users: " << users << " mode: " << mode << endl;
+
+ for( uint i=0; i < mode.length(); i++ )
+ {
+ switch( mode[i] )
+ {
+ case '+':
+ adjMode = AddBits;
+ break;
+
+ case '-':
+ adjMode = RemoveBits;
+ break;
+
+ default:
+ //kdDebug(14120) << "got " << mode[i] << ", user: " << *user << endl;
+
+ if (mode[i] == 'o') {
+ if (user == users.end())
+ return;
+
+ if ((*user).lower() == m_nickName.lower())
+ adjustInternalOnlineStatusBits(chan, IRCProtocol::Operator, adjMode);
+
+ ++user;
+ }
+ else if (mode[i] == 'v') {
+ if (user == users.end())
+ return;
+
+ if ((*user).lower() == m_nickName.lower())
+ adjustInternalOnlineStatusBits(chan, IRCProtocol::Voiced, adjMode);
+
+ ++user;
+ }
+
+ break;
+ }
+ }
+}
+
+
+/* Remove or add the given bits for the given channel from the current internal online status.
+ *
+ * You could fiddle with bits like IRCProtocol::Operator, IRCProtocol::Voiced, etc.
+ */
+
+void IRCUserContact::adjustInternalOnlineStatusBits(IRCChannelContact *channel, unsigned statusAdjustment, bitAdjustment adj)
+{
+ Kopete::OnlineStatus currentStatus = channel->manager()->contactOnlineStatus(this);
+ Kopete::OnlineStatus newStatus;
+
+ if (adj == RemoveBits) {
+
+ // If the bit is not set in the current internal status, stop here.
+ if ((currentStatus.internalStatus() & ~statusAdjustment) == currentStatus.internalStatus())
+ return;
+
+ newStatus = m_protocol->statusLookup(
+ (IRCProtocol::IRCStatus)(currentStatus.internalStatus() & ~statusAdjustment)
+ );
+
+ } else if (adj == AddBits) {
+
+ // If the bit is already set in the current internal status, stop here.
+ if ((currentStatus.internalStatus() | statusAdjustment) == currentStatus.internalStatus())
+ return;
+
+ newStatus = m_protocol->statusLookup(
+ (IRCProtocol::IRCStatus)(currentStatus.internalStatus() | statusAdjustment)
+ );
+
+ }
+
+ channel->manager()->setContactOnlineStatus(this, newStatus);
+}
+
+void IRCUserContact::privateMessage(IRCContact *from, IRCContact *to, const QString &message)
+{
+ if (to == this)
+ {
+ if(to==account()->myself())
+ {
+ Kopete::Message msg(from, from->manager(Kopete::Contact::CanCreate)->members(), message,
+ Kopete::Message::Inbound, Kopete::Message::RichText, CHAT_VIEW);
+ from->appendMessage(msg);
+ }
+ else
+ {
+ kdDebug(14120) << "IRC Server error: Received a private message for " << to->nickName() << ":" << message << endl;
+ // emit/call something on main ircservercontact
+ }
+ }
+}
+
+void IRCUserContact::newAction(const QString &to, const QString &action)
+{
+ IRCAccount *account = ircAccount();
+
+ IRCContact *t = account->contactManager()->findUser(to);
+
+ Kopete::Message::MessageDirection dir =
+ (this == account->mySelf()) ? Kopete::Message::Outbound : Kopete::Message::Inbound;
+ Kopete::Message msg(this, t, action, dir, Kopete::Message::RichText,
+ CHAT_VIEW, Kopete::Message::TypeAction);
+
+ //Either this is from me to a guy, or from a guy to me. Either way its a PM
+ if (dir == Kopete::Message::Outbound)
+ t->appendMessage(msg);
+ else
+ appendMessage(msg);
+}
+
+#include "ircusercontact.moc"
diff --git a/kopete/protocols/irc/ircusercontact.h b/kopete/protocols/irc/ircusercontact.h
new file mode 100644
index 00000000..3373fa9c
--- /dev/null
+++ b/kopete/protocols/irc/ircusercontact.h
@@ -0,0 +1,146 @@
+/*
+ ircusercontact.h - IRC User Contact
+
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org
+
+ Kopete (c) 2002 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef IRCUSERCONTACT_H
+#define IRCUSERCONTACT_H
+
+#include "kopetechatsessionmanager.h"
+#include "irccontact.h"
+#include "kopeteonlinestatus.h"
+
+class QTimer;
+
+class KActionCollection;
+class KAction;
+class KActionMenu;
+class KCodecAction;
+
+class IRCContactManager;
+class IRCChannelContact;
+
+struct IRCUserInfo
+{
+ QString userName;
+ QString hostName;
+ QString realName;
+ QString serverName;
+ QString serverInfo;
+ QString flags;
+ QStringList channels;
+ unsigned long idle;
+ bool isOperator;
+ bool isIdentified;
+ bool away;
+ bool online;
+ uint hops;
+ QDateTime lastOnline;
+ QTime lastUpdate;
+};
+
+/**
+ * @author Jason Keirstead <jason@keirstead.org
+ *
+ * This class is the @ref Kopete::Contact object representing IRC Users, not channels.
+ * It is derrived from IRCContact where much of its functionality is shared with @ref IRCChannelContact.
+ */
+class IRCUserContact : public IRCContact
+{
+ Q_OBJECT
+
+public:
+ // This class provides a Kopete::Contact for each user on the channel.
+ IRCUserContact(IRCContactManager *, const QString &nickname, Kopete::MetaContact *mc);
+
+ // Kopete::Contact stuff
+ virtual QPtrList<KAction> *customContextMenuActions( Kopete::ChatSession *manager );
+ virtual const QString caption() const;
+
+ void setAway(bool isAway);
+
+ QString formattedName() const;
+
+ //Methods handled by the signal mapper
+ void incomingUserIsAway(const QString &message );
+ void userOnline();
+ void newAction( const QString &from, const QString &action );
+ void newWhoIsUser(const QString &username, const QString &hostname, const QString &realname);
+ void newWhoIsServer(const QString &server, const QString &serverInfo);
+ void newWhoIsOperator();
+ void newWhoIsIdentified();
+ void newWhoIsIdle(unsigned long seconds);
+ void newWhoIsChannels(const QString &channel);
+ void whoIsComplete();
+ void whoWasComplete();
+ void newWhoReply( const QString &channel, const QString &user, const QString &host,
+ const QString &server, bool away, const QString &flags, uint hops,
+ const QString &realName );
+
+public slots:
+ /** \brief Updates online status for channels based on current internal status.
+ */
+ virtual void updateStatus();
+
+ virtual void sendFile(const KURL &sourceURL, const QString&, unsigned int);
+
+protected slots:
+ virtual void privateMessage(IRCContact *from, IRCContact *to, const QString &message);
+
+private slots:
+ void slotOp();
+ void slotDeop();
+ void slotVoice();
+ void slotDevoice();
+ void slotCtcpPing();
+ void slotCtcpVersion();
+ void slotBanHost();
+ void slotBanUserHost();
+ void slotBanDomain();
+ void slotBanUserDomain();
+ void slotKick();
+ void slotUserOffline();
+
+ void slotBanHostOnce();
+ void slotBanUserHostOnce();
+ void slotBanDomainOnce();
+ void slotBanUserDomainOnce();
+
+ virtual void slotUserInfo();
+
+ //This can't be handled by the contact manager since
+ void slotIncomingModeChange(const QString &nick, const QString &channel, const QString &mode);
+
+private:
+ enum bitAdjustment { RemoveBits, AddBits };
+ void adjustInternalOnlineStatusBits(IRCChannelContact *channel, unsigned statusAdjustment, bitAdjustment adj);
+
+ void contactMode(const QString &mode);
+ void updateInfo();
+
+ KActionMenu *actionModeMenu;
+ KActionMenu *actionCtcpMenu;
+ KAction *actionKick;
+ KActionMenu *actionBanMenu;
+ KCodecAction *codecAction;
+ Kopete::ChatSession *mActiveManager;
+ QTimer *mOnlineTimer;
+ IRCUserInfo mInfo;
+};
+
+#endif
+
+// vim: set noet ts=4 sts=4 tw=4:
diff --git a/kopete/protocols/irc/kcodecaction.cpp b/kopete/protocols/irc/kcodecaction.cpp
new file mode 100644
index 00000000..e32a1787
--- /dev/null
+++ b/kopete/protocols/irc/kcodecaction.cpp
@@ -0,0 +1,87 @@
+/*
+ kcodecaction.cpp
+
+ Copyright (c) 2005 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+ Kopete (c) 2003-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+#include <qstringlist.h>
+#include <qtextcodec.h>
+#include <kcharsets.h>
+
+#include "kcodecaction.h"
+
+KCodecAction::KCodecAction( const QString &text, const KShortcut &cut,
+ QObject *parent, const char *name ) : KSelectAction( text, "", cut, parent, name )
+{
+ QObject::connect( this, SIGNAL( activated( const QString & ) ),
+ this, SLOT( slotActivated( const QString & ) ) );
+
+ setItems( KCodecAction::supportedEncodings() );
+}
+
+void KCodecAction::slotActivated( const QString & text )
+{
+ /* text is something like "Western European ( iso-8859-1 )", but we must give
+ * codecForName() only the "iso-8859-1" part.
+ */
+ QString encoding = KGlobal::charsets()->encodingForName(text);
+
+ emit activated( KGlobal::charsets()->codecForName(encoding) );
+}
+
+void KCodecAction::setCodec( const QTextCodec *codec )
+{
+ QStringList items = this->items();
+ int i = 0;
+ for (QStringList::ConstIterator it = items.begin(), end = items.end(); it != end; ++it, ++i) {
+ QString encoding = KGlobal::charsets()->encodingForName(*it);
+
+ if (KGlobal::charsets()->codecForName(encoding)->mibEnum() == codec->mibEnum()) {
+ setCurrentItem(i);
+ break;
+ }
+ }
+}
+
+/* Create a list of supported encodings, and keep only one of each encoding
+ * mime name.
+ *
+ * This piece of code from kdepim/kmail/kmmsgbase.cpp
+ */
+
+QStringList KCodecAction::supportedEncodings(bool usAscii)
+{
+ QStringList encodingNames = KGlobal::charsets()->availableEncodingNames();
+ QStringList encodings;
+ QMap<QString, bool> mimeNames;
+
+ for (QStringList::ConstIterator it = encodingNames.begin();
+ it != encodingNames.end(); ++it)
+ {
+ QTextCodec *codec = KGlobal::charsets()->codecForName(*it);
+ QString mimeName = (codec) ? QString(codec->mimeName()).lower() : (*it);
+ if (mimeNames.find(mimeName) == mimeNames.end())
+ {
+ encodings.append(KGlobal::charsets()->languageForEncoding(*it)
+ + " ( " + mimeName + " )");
+ mimeNames.insert(mimeName, true);
+ }
+ }
+
+ encodings.sort();
+ if (usAscii) encodings.prepend(KGlobal::charsets()
+ ->languageForEncoding("us-ascii") + " ( us-ascii )");
+ return encodings;
+}
+
+#include "kcodecaction.moc"
diff --git a/kopete/protocols/irc/kcodecaction.h b/kopete/protocols/irc/kcodecaction.h
new file mode 100644
index 00000000..93f9d6c1
--- /dev/null
+++ b/kopete/protocols/irc/kcodecaction.h
@@ -0,0 +1,47 @@
+/*
+ kcodecaction.h
+
+ Copyright (c) 2005 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+ Kopete (c) 2003-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+#ifndef KCODECACTION_H
+#define KCODECACTION_H
+
+#include <kdeversion.h>
+#include <qintdict.h>
+
+#if KDE_IS_VERSION( 3, 1, 90 )
+ #include <kactionclasses.h>
+#else
+ #include <kaction.h>
+#endif
+
+class KCodecAction : public KSelectAction
+{
+ Q_OBJECT
+ public:
+ KCodecAction( const QString &text, const KShortcut &cut = KShortcut(),
+ QObject *parent = 0, const char *name = 0 );
+
+ void setCodec( const QTextCodec *codec );
+
+ static QStringList supportedEncodings( bool usAscii = false );
+
+ signals:
+ void activated( const QTextCodec * );
+
+ private slots:
+ void slotActivated( const QString & );
+};
+
+#endif
diff --git a/kopete/protocols/irc/kopete_irc.desktop b/kopete/protocols/irc/kopete_irc.desktop
new file mode 100644
index 00000000..6e3cf144
--- /dev/null
+++ b/kopete/protocols/irc/kopete_irc.desktop
@@ -0,0 +1,79 @@
+[Desktop Entry]
+Type=Service
+X-Kopete-Version=1000900
+Icon=irc_protocol
+ServiceTypes=Kopete/Protocol
+X-KDE-Library=kopete_irc
+X-Kopete-Messaging-Protocol=messaging/irc
+X-KDE-PluginInfo-Author=Kopete Developers
+X-KDE-PluginInfo-Email=kopete-devel@kde.org
+X-KDE-PluginInfo-Name=kopete_irc
+X-KDE-PluginInfo-Version=0.8.0
+X-KDE-PluginInfo-Website=http://kopete.kde.org
+X-KDE-PluginInfo-Category=Protocols
+X-KDE-PluginInfo-Depends=
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=false
+Name=IRC
+Name[bn]=আই-আর-সি
+Name[hi]=आईआरसी
+Name[ne]=आइआरसी
+Comment=Protocol to connect to IRC
+Comment[ar]=البروتوكل سيتصل بـ IRC
+Comment[be]=Пратакол IRC
+Comment[bg]=Протокол за връзка с IRC
+Comment[bn]=আই-আর-সিতে সংযোগ করতে প্রোটোকল
+Comment[br]=Komenad kevreañ ouzh IRC
+Comment[bs]=IRC protokol
+Comment[ca]=Protocol per a connectar-se a l'IRC
+Comment[cs]=Protokol k připojení k IRC
+Comment[cy]=Protocol i gysylltu ag IRC
+Comment[da]=Protokol til at forbinde til IRC
+Comment[de]=Protokoll zur Verbindung mit IRC
+Comment[el]=Πρωτόκολλο για σύνδεση στο IRC
+Comment[es]=Protocolo de conexión al IRC
+Comment[et]=Protokoll ühendumiseks IRC-ga
+Comment[eu]=IRC-ra konektatzeko protokoloa
+Comment[fa]=قرار داد برای اتصال به IRC
+Comment[fi]=Yhteyskäytänötö IRC-verkkoon kytkeytymiseen
+Comment[fr]=Protocole pour se connecter sur IRC
+Comment[ga]=Prótacal chun ceangal le IRC
+Comment[gl]=Protocolo para conectar a IRC
+Comment[he]=פרוטוקול התחברות ל- IRC
+Comment[hi]=आईआरसी से जुड़ने का प्रोटोकॉल
+Comment[hr]=Protokol za povezivanje na IRC
+Comment[hu]=Protokoll az IRC használatához
+Comment[is]=Samskiptamáti til að tengjast IRC
+Comment[it]=Protocollo per connessione a IRC
+Comment[ja]=IRC に接続するプロトコル
+Comment[ka]=IRC-თან დაკავშირების ოქმი
+Comment[kk]=IRC-ге қосылу протоколы
+Comment[km]=ពិធីការ​​ភ្ជាប់​ទៅ IRC
+Comment[lt]=Protokolas prisijungimui prie IRC
+Comment[mk]=Протокол за поврзување на IRC
+Comment[nb]=Protokoll for å koble til IRC
+Comment[nds]=Protokoll för't Tokoppeln na IRC
+Comment[ne]=आइआरसी मा जडान गर्ने प्रोटोकल
+Comment[nl]=Protocol voor Internet Relay Chat (IRC)
+Comment[nn]=Protokoll for å kopla til IRC
+Comment[pl]=Protokół połączenia z serwerem IRC
+Comment[pt]=Protocolo para ligar ao IRC
+Comment[pt_BR]=Protocolo de conexão ao IRC
+Comment[ro]=Protocol de conectare la IRC
+Comment[ru]=Протокол для подключения к IRC
+Comment[sk]=Protokol pre pripojenie k IRC
+Comment[sl]=Protokol za povezavo na IRC
+Comment[sr]=Протокол за повезивање на IRC
+Comment[sr@Latn]=Protokol za povezivanje na IRC
+Comment[sv]=Protokoll för att ansluta till IRC
+Comment[ta]=IRC உடன் இணைக்க விதிமுறை
+Comment[tg]=Қарордоди пайвастшавӣ ба IRC
+Comment[tr]=IRC'ye bağlantı iletişim kuralı
+Comment[uk]=Протокол для з'єднання з IRC
+Comment[uz]=IRC bilan aloqa oʻrnatish uchun protokol
+Comment[uz@cyrillic]=IRC билан алоқа ўрнатиш учун протокол
+Comment[wa]=Protocole po s' raloyî so les canås IRC
+Comment[zh_CN]=连接到 IRC 协议
+Comment[zh_HK]=用來連接至 IRC 的通訊協定
+Comment[zh_TW]=連線到 IRC 的協定
+
diff --git a/kopete/protocols/irc/ksparser.cpp b/kopete/protocols/irc/ksparser.cpp
new file mode 100644
index 00000000..c101a79e
--- /dev/null
+++ b/kopete/protocols/irc/ksparser.cpp
@@ -0,0 +1,265 @@
+/* This file is part of ksirc
+ Copyright (c) 2001 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+Color parser code courtesy of ksirc <http://www.kde.org>
+Modified by Jason Keirstead <jason@keirstead.org>
+*/
+
+#include <knotifyclient.h>
+#include <kdebug.h>
+#include <qbuffer.h>
+#include <qdatastream.h>
+#include <qstylesheet.h>
+#include "ksparser.h"
+#include <stdlib.h>
+
+KSParser KSParser::m_parser;
+
+const QColor KSParser::IRC_Colors[17]=
+{
+ Qt::white,
+ Qt::black,
+ Qt::darkBlue,
+ Qt::darkGreen,
+ Qt::red,
+ Qt::darkRed,
+ Qt::darkMagenta,
+ Qt::darkYellow,
+ Qt::yellow,
+ Qt::green,
+ Qt::darkCyan,
+ Qt::cyan,
+ Qt::blue,
+ Qt::magenta,
+ Qt::darkGray,
+ Qt::gray,
+ QColor() // default invalid color, must be the last
+};
+
+const QRegExp KSParser::sm_colorsModeRegexp("(\\d{1,2})(?:,(\\d{1,2}))?");
+
+template <typename _TYPE_>
+ inline void swap(_TYPE_ &o1, _TYPE_ &o2)
+{
+ _TYPE_ tmp = o1;
+ o1 = o2;
+ o2 = tmp;
+}
+
+KSParser::KSParser()
+{
+ kdDebug(14120) << k_funcinfo << endl;
+}
+
+KSParser::~KSParser()
+{
+ kdDebug(14120) << k_funcinfo << endl;
+}
+
+/* NOTE: If thread corruption are seen simply ad a qlock here */
+QCString KSParser::parse(const QCString &message)
+{
+ return m_parser._parse(message);
+}
+
+QCString KSParser::_parse(const QCString &message)
+{
+ QCString data( message.size() * 2 );
+ QBuffer buff( data );
+ buff.open( IO_WriteOnly );
+
+ m_tags.clear();
+ m_attributes.clear();
+
+ QRegExp colorsModeRegexp(sm_colorsModeRegexp);
+
+ // should be set to the current default colors ....
+ QColor fgColor; /*KopeteMesage::fg().name()*/
+ QColor bgColor; /*KopeteMesage::bg().name()*/
+
+ uint chars = 0;
+ for(uint i = 0; i < message.length(); ++i)
+ {
+ const QChar &cur = message[i];
+ QString toAppend;
+
+ switch (cur)
+ {
+ case 0x02: //Bold: ^B
+ toAppend= toggleTag("b");
+ break;
+ case 0x03: //Color code: ^C
+ if (colorsModeRegexp.search(message, i+1) == (int)i+1)
+ {
+ i += colorsModeRegexp.matchedLength(); // + 1 will be added by ++
+ QString tagStyle;
+
+ fgColor = ircColor(colorsModeRegexp.cap(1));
+ bgColor = ircColor(colorsModeRegexp.cap(2));
+
+ toAppend = pushColorTag(fgColor, bgColor);
+ }
+ else
+ {
+ toAppend = popTag(QString::fromLatin1("span"));
+ }
+ break;
+ case 0x07: //System bell: ^G
+ KNotifyClient::beep( QString::fromLatin1("IRC beep event received in a message") );
+ break;
+ case '\t': // 0x09
+ toAppend = QString::fromLatin1("&nbsp;&nbsp;&nbsp;&nbsp;");
+ break;
+ case '\n': // 0x0D
+ toAppend= QString::fromLatin1("<br/>");
+ break;
+ case 0x0D: // Italics: ^N
+ toAppend = toggleTag("i");
+ break;
+ case 0x0F: //Plain Text, close all tags: ^O
+ toAppend = popAll();
+ break;
+ // case 0x12: // Reverse original text colors: ^R
+ // break;
+ case 0x16: //Invert Colors: ^V
+ swap(fgColor, bgColor);
+ toAppend = pushColorTag(fgColor, bgColor);
+ break;
+ case 0x1F: //Underline
+ toAppend = toggleTag("u");
+ break;
+ case '<':
+ toAppend = QString::fromLatin1("&lt;");
+ break;
+ case '>':
+ toAppend = QString::fromLatin1("&gt;");
+ break;
+ default:
+ if (cur < QChar(' ')) // search for control characters
+ toAppend = QString::fromLatin1("&lt;%1&gt;").arg(cur, 2, 16).upper();
+ else
+ toAppend = QStyleSheet::escape(cur);
+ }
+
+ chars += toAppend.length();
+ buff.writeBlock( toAppend.latin1(), toAppend.length() );
+ }
+
+ QString toAppend = popAll();
+ chars += toAppend.length();
+ buff.writeBlock( toAppend.latin1(), toAppend.length() );
+
+ // Make sure we have enough room for NULL character.
+ if (data.size() < chars+1)
+ data.resize(chars+1);
+
+ data[chars] = '\0';
+
+ return data;
+}
+
+QString KSParser::pushTag(const QString &tag, const QString &attributes)
+{
+ QString res;
+ m_tags.push(tag);
+ if(!m_attributes.contains(tag))
+ m_attributes.insert(tag, attributes);
+ else if(!attributes.isEmpty())
+ m_attributes.replace(tag, attributes);
+ res.append("<" + tag);
+ if(!m_attributes[tag].isEmpty())
+ res.append(" " + m_attributes[tag]);
+ return res + ">";
+}
+
+QString KSParser::pushColorTag(const QColor &fgColor, const QColor &bgColor)
+{
+ QString tagStyle;
+
+ if (fgColor.isValid())
+ tagStyle += QString::fromLatin1("color:%1;").arg(fgColor.name());
+ if (bgColor.isValid())
+ tagStyle += QString::fromLatin1("background-color:%1;").arg(bgColor.name());
+
+ if(!tagStyle.isEmpty())
+ tagStyle = QString::fromLatin1("style=\"%1\"").arg(tagStyle);
+
+ return pushTag(QString::fromLatin1("span"), tagStyle);;
+}
+
+QString KSParser::popTag(const QString &tag)
+{
+ if (!m_tags.contains(tag))
+ return QString::null;
+
+ QString res;
+ QValueStack<QString> savedTags;
+ while(m_tags.top() != tag)
+ {
+ savedTags.push(m_tags.pop());
+ res.append("</" + savedTags.top() + ">");
+ }
+ res.append("</" + m_tags.pop() + ">");
+ m_attributes.remove(tag);
+ while(!savedTags.isEmpty())
+ res.append(pushTag(savedTags.pop()));
+ return res;
+}
+
+QString KSParser::toggleTag(const QString &tag)
+{
+ return m_attributes.contains(tag)?popTag(tag):pushTag(tag);
+}
+
+QString KSParser::popAll()
+{
+ QString res;
+ while(!m_tags.isEmpty())
+ res.append("</" + m_tags.pop() + ">");
+ m_attributes.clear();
+ return res;
+}
+
+QColor KSParser::ircColor(const QString &color)
+{
+ bool success;
+ unsigned int intColor = color.toUInt(&success);
+
+ if (success)
+ return ircColor(intColor);
+ else
+ return QColor();
+}
+
+QColor KSParser::ircColor(unsigned int color)
+{
+ unsigned int maxcolor = sizeof(IRC_Colors)/sizeof(QColor);
+ return color<=maxcolor?IRC_Colors[color]:IRC_Colors[maxcolor];
+}
+
+int KSParser::colorForHTML(const QString &html)
+{
+ QColor color(html);
+ for(uint i=0; i<sizeof(IRC_Colors)/sizeof(QColor); i++)
+ {
+ if(IRC_Colors[i] == color)
+ return i;
+ }
+ return -1;
+}
diff --git a/kopete/protocols/irc/ksparser.h b/kopete/protocols/irc/ksparser.h
new file mode 100644
index 00000000..dda7b7c1
--- /dev/null
+++ b/kopete/protocols/irc/ksparser.h
@@ -0,0 +1,56 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Simon Hausmann <hausmann@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the Artistic License.
+*/
+#ifndef __ksparser_h__
+#define __ksparser_h__
+
+#include <qcolor.h>
+#include <qmap.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qvaluestack.h>
+
+/*
+ * Helper class to parse IRC color/style codes and convert them to
+ * richtext. The parser maintains an internal stack of the styles
+ * applied because the IRC message could contain sequences as
+ * (bold)Hello (red)World(endbold)! (blue)blue text
+ * which needs to be converted to
+ * <b>Hello </b><font color="red"><b>World</b>! </font><font color="blue">blue text</font>
+ * to get correctly nested tags. (malte)
+ */
+class KSParser
+{
+public:
+ static QCString parse(const QCString &);
+ static int colorForHTML( const QString &html );
+
+ static QColor ircColor(const QString &color);
+ static QColor ircColor(unsigned int color);
+
+ ~KSParser();
+private:
+ KSParser();
+
+ QCString _parse(const QCString &);
+ QString pushTag(const QString &, const QString & = QString::null);
+ QString pushColorTag(const QColor &fgColor, const QColor &bgColor);
+ QString popTag(const QString &);
+ QString toggleTag(const QString &);
+ QString popAll();
+
+private:
+ static KSParser m_parser;
+ static const QColor IRC_Colors[17];
+ static const QRegExp sm_colorsModeRegexp;
+
+ QValueStack<QString> m_tags;
+ QMap<QString, QString> m_attributes;
+};
+
+#endif
+
+
diff --git a/kopete/protocols/irc/libkirc/Makefile.am b/kopete/protocols/irc/libkirc/Makefile.am
new file mode 100644
index 00000000..e2ebe543
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/Makefile.am
@@ -0,0 +1,20 @@
+KDE_OPTIONS = nofinal
+noinst_LTLIBRARIES = libkirc.la
+
+libkirc_la_SOURCES = \
+ kircengine.cpp \
+ kircengine_commands.cpp \
+ kircengine_ctcp.cpp \
+ kircengine_numericreplies.cpp \
+ kircentity.cpp \
+ kircmessage.cpp \
+ kircmessageredirector.cpp \
+ kirctransfer.cpp \
+ kirctransferhandler.cpp \
+ kirctransferserver.cpp \
+ ksslsocket.cpp
+libkirc_la_LDFLAGS = -no-undefined $(KDE_PLUGIN) $(all_libraries)
+libkirc_la_LIBADD = $(LIB_KIO)
+
+AM_CPPFLAGS = -I$(top_srcdir)/kopete/protocols/irc $(KOPETE_INCLUDES) $(all_includes)
+METASOURCES = AUTO
diff --git a/kopete/protocols/irc/libkirc/kircengine.cpp b/kopete/protocols/irc/libkirc/kircengine.cpp
new file mode 100644
index 00000000..5b70d5fc
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircengine.cpp
@@ -0,0 +1,497 @@
+/*
+ kirc.cpp - IRC Client
+
+ Copyright (c) 2005 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
+ Copyright (c) 2003-2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "kircengine.h"
+#include "ksslsocket.h"
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kextsock.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include <qtextcodec.h>
+#include <qtimer.h>
+
+//Needed for getuid / getpwuid
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <kopetemessage.h>
+
+#ifndef KIRC_SSL_SUPPORT
+#define KIRC_SSL_SUPPORT
+#endif
+
+using namespace KIRC;
+
+// FIXME: Remove slotConnected() and error(int errCode) while going to KNetwork namespace
+
+/* Please note that the regular expression "[\\r\\n]*$" is used in a QString::replace statement many times.
+ * This gets rid of trailing \r\n, \r, \n, and \n\r characters.
+ */
+const QRegExp Engine::m_RemoveLinefeeds( QString::fromLatin1("[\\r\\n]*$") );
+
+Engine::Engine(QObject *parent, const char *name)
+ : QObject(parent, QString::fromLatin1("[KIRC::Engine]%1").arg(name).latin1()),
+ m_status(Idle),
+ m_FailedNickOnLogin(false),
+ m_useSSL(false),
+ m_commands(101, false),
+// m_numericCommands(101),
+ m_ctcpQueries(17, false),
+ m_ctcpReplies(17, false),
+ codecs(577,false)
+{
+ setUserName(QString::null);
+
+ m_commands.setAutoDelete(true);
+ m_ctcpQueries.setAutoDelete(true);
+ m_ctcpReplies.setAutoDelete(true);
+
+ bindCommands();
+ bindNumericReplies();
+ bindCtcp();
+
+ m_VersionString = QString::fromLatin1("Anonymous client using the KIRC engine.");
+ m_UserString = QString::fromLatin1("Response not supplied by user.");
+ m_SourceString = QString::fromLatin1("Unknown client, known source.");
+
+ defaultCodec = QTextCodec::codecForMib(106); // UTF8 mib is 106
+ kdDebug(14120) << "Setting default engine codec, " << defaultCodec->name() << endl;
+
+ m_sock = 0L;
+}
+
+Engine::~Engine()
+{
+ kdDebug(14120) << k_funcinfo << m_Host << endl;
+ quit("KIRC Deleted", true);
+ if( m_sock )
+ delete m_sock;
+}
+
+void Engine::setUseSSL( bool useSSL )
+{
+ kdDebug(14120) << k_funcinfo << useSSL << endl;
+
+ if( !m_sock || useSSL != m_useSSL )
+ {
+ if( m_sock )
+ delete m_sock;
+
+ m_useSSL = useSSL;
+
+
+ if( m_useSSL )
+ {
+ #ifdef KIRC_SSL_SUPPORT
+ m_sock = new KSSLSocket;
+ m_sock->setSocketFlags( KExtendedSocket::inetSocket );
+
+ connect(m_sock, SIGNAL(certificateAccepted()), SLOT(slotConnected()));
+ connect(m_sock, SIGNAL(certificateRejected()), SLOT(slotConnectionClosed()));
+ connect(m_sock, SIGNAL(sslFailure()), SLOT(slotConnectionClosed()));
+ }
+ else
+ #else
+ kdWarning(14120) << "You tried to use SSL, but this version of Kopete was"
+ " not compiled with IRC SSL support. A normal IRC connection will be attempted." << endl;
+ }
+ #endif
+ {
+ m_sock = new KExtendedSocket;
+ m_sock->setSocketFlags( KExtendedSocket::inputBufferedSocket | KExtendedSocket::inetSocket );
+
+ connect(m_sock, SIGNAL(connectionSuccess()), SLOT(slotConnected()));
+ connect(m_sock, SIGNAL(connectionFailed(int)), SLOT(error(int)));
+ }
+
+ connect(m_sock, SIGNAL(closed(int)), SLOT(slotConnectionClosed()));
+ connect(m_sock, SIGNAL(readyRead()), SLOT(slotReadyRead()));
+ }
+}
+
+void Engine::setStatus(Engine::Status status)
+{
+ kdDebug(14120) << k_funcinfo << status << endl;
+
+ if (m_status == status)
+ return;
+
+// Engine::Status oldStatus = m_status;
+ m_status = status;
+ emit statusChanged(status);
+
+ switch (m_status)
+ {
+ case Idle:
+ // Do nothing.
+ break;
+ case Connecting:
+ // Do nothing.
+ break;
+ case Authentifying:
+ m_sock->enableRead(true);
+
+ // If password is given for this server, send it now, and don't expect a reply
+ if (!(password()).isEmpty())
+ pass(password());
+
+ user(m_Username, 0, m_realName);
+ nick(m_Nickname);
+
+ break;
+ case Connected:
+ // Do nothing.
+ break;
+ case Closing:
+ m_sock->close();
+ m_sock->reset();
+ setStatus(Idle);
+ break;
+ case AuthentifyingFailed:
+ setStatus(Closing);
+ break;
+ case Timeout:
+ setStatus(Closing);
+ break;
+ case Disconnected:
+ setStatus(Closing);
+ break;
+ }
+}
+
+void Engine::connectToServer(const QString &host, Q_UINT16 port, const QString &nickname, bool useSSL )
+{
+ setUseSSL(useSSL);
+
+ m_Nickname = nickname;
+ m_Host = host;
+ m_Port = port;
+
+ kdDebug(14120) << "Trying to connect to server " << m_Host << ":" << m_Port << endl;
+ kdDebug(14120) << "Sock status: " << m_sock->socketStatus() << endl;
+
+ if( !m_sock->setAddress(m_Host, m_Port) )
+ kdDebug(14120) << k_funcinfo << "setAddress failed. Status: " << m_sock->socketStatus() << endl;
+
+ if( m_sock->startAsyncConnect() == 0 )
+ {
+ kdDebug(14120) << k_funcinfo << "Success!. Status: " << m_sock->socketStatus() << endl;
+ setStatus(Connecting);
+ }
+ else
+ {
+ kdDebug(14120) << k_funcinfo << "Failed. Status: " << m_sock->socketStatus() << endl;
+ setStatus(Disconnected);
+ }
+}
+
+void Engine::slotConnected()
+{
+ setStatus(Authentifying);
+}
+
+void Engine::slotConnectionClosed()
+{
+ setStatus(Disconnected);
+}
+
+void Engine::error(int errCode)
+{
+ kdDebug(14120) << k_funcinfo << "Socket error: " << errCode << endl;
+ if (m_sock->socketStatus () != KExtendedSocket::connecting)
+ {
+ // Connection in progress.. This is a signal fired wrong
+ setStatus(Disconnected);
+ }
+}
+
+void Engine::setVersionString(const QString &newString)
+{
+ m_VersionString = newString;
+ m_VersionString.remove(m_RemoveLinefeeds);
+}
+
+void Engine::setUserString(const QString &newString)
+{
+ m_UserString = newString;
+ m_UserString.remove(m_RemoveLinefeeds);
+}
+
+void Engine::setSourceString(const QString &newString)
+{
+ m_SourceString = newString;
+ m_SourceString.remove(m_RemoveLinefeeds);
+}
+
+void Engine::setUserName(const QString &newName)
+{
+ if(newName.isEmpty())
+ m_Username = QString::fromLatin1(getpwuid(getuid())->pw_name);
+ else
+ m_Username = newName;
+ m_Username.remove(m_RemoveLinefeeds);
+}
+
+void Engine::setRealName(const QString &newName)
+{
+ if(newName.isEmpty())
+ m_realName = QString::fromLatin1(getpwuid(getuid())->pw_gecos);
+ else
+ m_realName = newName;
+ m_realName.remove(m_RemoveLinefeeds);
+}
+
+bool Engine::_bind(QDict<KIRC::MessageRedirector> &dict,
+ QString command, QObject *object, const char *member,
+ int minArgs, int maxArgs, const QString &helpMessage)
+{
+// FIXME: Force upper case.
+// FIXME: Force number format.
+
+ MessageRedirector *mr = dict[command];
+
+ if (!mr)
+ {
+ mr = new MessageRedirector(this, minArgs, maxArgs, helpMessage);
+ dict.replace(command, mr);
+ }
+
+ return mr->connect(object, member);
+}
+
+bool Engine::bind(const QString &command, QObject *object, const char *member,
+ int minArgs, int maxArgs, const QString &helpMessage)
+{
+ return _bind(m_commands, command, object, member,
+ minArgs, maxArgs, helpMessage);
+}
+
+bool Engine::bind(int id, QObject *object, const char *member,
+ int minArgs, int maxArgs, const QString &helpMessage)
+{
+ return _bind(m_commands, QString::number(id), object, member,
+ minArgs, maxArgs, helpMessage);
+}
+
+bool Engine::bindCtcpQuery(const QString &command, QObject *object, const char *member,
+ int minArgs, int maxArgs, const QString &helpMessage)
+{
+ return _bind(m_ctcpQueries, command, object, member,
+ minArgs, maxArgs, helpMessage);
+}
+
+bool Engine::bindCtcpReply(const QString &command, QObject *object, const char *member,
+ int minArgs, int maxArgs, const QString &helpMessage)
+{
+ return _bind(m_ctcpReplies, command, object, member,
+ minArgs, maxArgs, helpMessage);
+}
+
+/* Message will be send as passed.
+ */
+void Engine::writeRawMessage(const QString &rawMsg)
+{
+ Message::writeRawMessage(this, defaultCodec, rawMsg);
+}
+
+/* Message will be quoted before beeing send.
+ */
+void Engine::writeMessage(const QString &msg, const QTextCodec *codec)
+{
+ Message::writeMessage(this, codec ? codec : defaultCodec, msg);
+}
+
+void Engine::writeMessage(const QString &command, const QStringList &args, const QString &suffix, const QTextCodec *codec)
+{
+ Message::writeMessage(this, codec ? codec : defaultCodec, command, args, suffix );
+}
+
+void Engine::writeCtcpMessage(const QString &command, const QString &to, const QString &ctcpMessage)
+{
+ Message::writeCtcpMessage(this, defaultCodec, command, to, ctcpMessage);
+}
+
+void Engine::writeCtcpMessage(const QString &command, const QString &to, const QString &suffix,
+ const QString &ctcpCommand, const QStringList &ctcpArgs, const QString &ctcpSuffix, bool )
+{
+ QString nick = Entity::userNick(to);
+
+ Message::writeCtcpMessage(this, codecForNick( nick ), command, nick, suffix,
+ ctcpCommand, ctcpArgs, ctcpSuffix );
+}
+
+void Engine::slotReadyRead()
+{
+ // This condition is buggy when the peer server
+ // close the socket unexpectedly
+ bool parseSuccess;
+
+ if (m_sock->socketStatus() == KExtendedSocket::connected && m_sock->canReadLine())
+ {
+ Message msg = Message::parse(this, defaultCodec, &parseSuccess);
+ if (parseSuccess)
+ {
+ emit receivedMessage(msg);
+
+ KIRC::MessageRedirector *mr;
+ if (msg.isNumeric())
+// mr = m_numericCommands[ msg.command().toInt() ];
+ // we do this conversion because some dummy servers sends 1 instead of 001
+ // numbers are stored as "1" instead of "001" to make convertion faster (no 0 pading).
+ mr = m_commands[ QString::number(msg.command().toInt()) ];
+ else
+ mr = m_commands[ msg.command() ];
+
+ if (mr)
+ {
+ QStringList errors = mr->operator()(msg);
+
+ if (!errors.isEmpty())
+ {
+ kdDebug(14120) << "Method error for line:" << msg.raw() << endl;
+ emit internalError(MethodFailed, msg);
+ }
+ }
+ else if (msg.isNumeric())
+ {
+ kdWarning(14120) << "Unknown IRC numeric reply for line:" << msg.raw() << endl;
+ emit incomingUnknown(msg.raw());
+ }
+ else
+ {
+ kdWarning(14120) << "Unknown IRC command for line:" << msg.raw() << endl;
+ emit internalError(UnknownCommand, msg);
+ }
+ }
+ else
+ {
+ emit incomingUnknown(msg.raw());
+ emit internalError(ParsingFailed, msg);
+ }
+
+ QTimer::singleShot( 0, this, SLOT( slotReadyRead() ) );
+ }
+
+ if(m_sock->socketStatus() != KExtendedSocket::connected)
+ error();
+}
+
+const QTextCodec *Engine::codecForNick( const QString &nick ) const
+{
+ if( nick.isEmpty() )
+ return defaultCodec;
+
+ QTextCodec *codec = codecs[ nick ];
+ kdDebug(14120) << nick << " has codec " << codec << endl;
+
+ if( !codec )
+ return defaultCodec;
+ else
+ return codec;
+}
+
+void Engine::showInfoDialog()
+{
+ if( m_useSSL )
+ {
+ static_cast<KSSLSocket*>( m_sock )->showInfoDialog();
+ }
+}
+
+/*
+ * The ctcp commands seems to follow the same message behaviours has normal IRC command.
+ * (Only missing the \n\r final characters)
+ * So applying the same parsing rules to the messages.
+ */
+bool Engine::invokeCtcpCommandOfMessage(const QDict<MessageRedirector> &map, Message &msg)
+{
+ if(msg.hasCtcpMessage() && msg.ctcpMessage().isValid())
+ {
+ Message &ctcpMsg = msg.ctcpMessage();
+
+ MessageRedirector *mr = map[ctcpMsg.command()];
+ if (mr)
+ {
+ QStringList errors = mr->operator()(msg);
+
+ if (errors.isEmpty())
+ return true;
+
+ kdDebug(14120) << "Method error for line:" << ctcpMsg.raw() << endl;
+ writeCtcpErrorMessage(msg.prefix(), msg.ctcpRaw(),
+ QString::fromLatin1("%1 internal error(s)").arg(errors.size()));
+ }
+ else
+ {
+ kdDebug(14120) << "Unknow IRC/CTCP command for line:" << ctcpMsg.raw() << endl;
+ // Don't send error message on unknown CTCP command
+ // None of the client send it, and it makes the client as infected by virus for IRC network scanners
+ // writeCtcpErrorMessage(msg.prefix(), msg.ctcpRaw(), "Unknown CTCP command");
+
+ emit incomingUnknownCtcp(msg.ctcpRaw());
+ }
+ }
+ else
+ {
+ kdDebug(14120) << "Message do not embed a CTCP message:" << msg.raw();
+ }
+ return false;
+}
+
+EntityPtr Engine::getEntity(const QString &name)
+{
+ Entity *entity = 0;
+
+ #pragma warning Do the searching code here.
+
+ if (!entity)
+ {
+ entity = new Entity(name);
+ m_entities.append(entity);
+ }
+
+ connect(entity, SIGNAL(destroyed(KIRC::Entity *)), SLOT(destroyed(KIRC::Entity *)));
+ return EntityPtr(entity);
+}
+
+void Engine::destroyed(KIRC::Entity *entity)
+{
+ m_entities.remove(entity);
+}
+
+void Engine::ignoreMessage(KIRC::Message &/*msg*/)
+{
+}
+
+void Engine::emitSuffix(KIRC::Message &msg)
+{
+ emit receivedMessage(InfoMessage, m_server, m_server, msg.suffix());
+}
+
+#include "kircengine.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
diff --git a/kopete/protocols/irc/libkirc/kircengine.h b/kopete/protocols/irc/libkirc/kircengine.h
new file mode 100644
index 00000000..50cb8f49
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircengine.h
@@ -0,0 +1,532 @@
+/*
+ kircengine.h - IRC Client
+
+ Copyright (c) 2003-2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+
+ Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KIRCENGINE_H
+#define KIRCENGINE_H
+
+#include "kircentity.h"
+#include "kircmessage.h"
+#include "kircmessageredirector.h"
+#include "kirctransfer.h"
+
+#include <kdeversion.h>
+
+// FIXME: Move the following kdedebug class to the *.cpp.
+#include <kdebug.h>
+#if KDE_VERSION < KDE_MAKE_VERSION( 3, 1, 90 )
+#include <kdebugclasses.h>
+#endif
+
+#include <qdatetime.h>
+#include <qdict.h>
+#include <qintdict.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+class QRegExp;
+
+namespace KIRC
+{
+
+/**
+ * @author Nick Betcher <nbetcher@kde.org>
+ * @author Michel Hermier <michel.hermier@wanadoo.fr>
+ * @author Jason Keirstead <jason@keirstead.org>
+ */
+class Engine
+ : public QObject
+{
+ Q_OBJECT
+
+// Q_PROPERTY(QUrl serverURL READ serverURL WRITE setServerURL)
+
+// Extracted from the base of the serverURL.
+// Q_PROPERTY(bool useSSL);
+// Q_PROPERTY(QString user READ user);
+// Q_PROPERTY(QString password);
+// Q_PROPERTY(QString host READ host);
+// Q_PROPERTY(int port READ host);
+
+// Extracted from the query of the serverURL.
+// Q_PROPERTY(bool reqsPasswd);
+// Q_PROPERTY(QString name); // real name
+// Q_PROPERTY(QStringList nickList READ nickList WRITE setNickList)
+// Q_PROPERTY(QString nick READ nick)
+// Q_PROPERTY(QStringList portList)
+
+ Q_ENUMS(Status)
+
+public:
+ enum Error
+ {
+ ParsingFailed,
+ UnknownCommand,
+ UnknownNumericReply,
+ InvalidNumberOfArguments,
+ MethodFailed
+ };
+
+ enum Status
+ {
+ Idle,
+ Connecting,
+ Authentifying,
+ Connected,
+ Closing,
+ AuthentifyingFailed,
+ Timeout,
+ Disconnected
+ };
+
+ enum ServerMessageType
+ {
+ ErrorMessage = -1,
+ PrivateMessage,
+ InfoMessage,
+
+ MessageOfTheDayMessage,
+ MessageOfTheDayCondensedMessage
+ };
+
+ Engine( QObject *parent = 0, const char* name = 0 );
+ ~Engine();
+
+// QString nick() const;
+// QStringList nickList() const;
+// void setNickList(const QStringList& nickList);
+
+// QUrl serverURL() const;
+// bool setServerURL(const QUrl &url);
+
+ inline const QString &currentHost() const
+ { return m_Host; };
+
+ inline Q_UINT16 currentPort()
+ { return m_Port; }
+
+ inline const QString &nickName() const
+ { return m_Nickname; };
+
+ inline const QString &password() const
+ { return m_Passwd; }
+
+ inline void setPassword(const QString &passwd)
+ { m_Passwd = passwd; };
+
+ inline const QString &userName() const
+ { return m_Username; }
+
+ void setUserName(const QString &newName);
+
+ void setRealName(const QString &newName);
+ inline const QString &realName() const
+ { return m_realName; }
+
+ inline const bool reqsPassword() const
+ { return m_ReqsPasswd; };
+
+ inline void setReqsPassword(bool b)
+ { m_ReqsPasswd = b; };
+
+ const bool useSSL() const { return m_useSSL; };
+ void setUseSSL( bool useSSL );
+
+ inline const QTextCodec *codec() const
+ { return defaultCodec; };
+
+ const QTextCodec *codecForNick( const QString &nick ) const;
+
+ inline void setDefaultCodec( QTextCodec* codec )
+ { defaultCodec = codec; };
+
+ void setVersionString(const QString &versionString);
+ void setUserString(const QString &userString);
+ void setSourceString(const QString &sourceString);
+ void connectToServer(const QString &host, Q_UINT16 port, const QString &nickname, bool useSSL = false);
+
+ KExtendedSocket *socket()
+ { return m_sock; };
+
+ inline KIRC::Engine::Status status() const
+ { return m_status; }
+
+ inline bool isDisconnected() const
+ { return m_status == Disconnected || m_status == Idle; }
+
+ inline bool isConnected() const
+ { return m_status == Connected; }
+
+ inline void setCodec( const QString &nick, const QTextCodec *codec )
+ { codecs.replace( nick, codec ); }
+
+ /* Custom CTCP replies handling */
+ inline QString &customCtcp( const QString &s )
+ { return customCtcpMap[s]; }
+
+ inline void addCustomCtcp( const QString &ctcp, const QString &reply )
+ { customCtcpMap[ ctcp.lower() ] = reply; }
+
+ KIRC::EntityPtr getEntity(const QString &name);
+
+public slots:
+ //Message output
+ void writeRawMessage(const QString &message);
+
+ void writeMessage(const QString &message, const QTextCodec *codec = 0 );
+ void writeMessage(const QString &command, const QStringList &args,
+ const QString &suffix = QString::null, const QTextCodec *codec = 0);
+
+ void writeCtcpMessage(const QString &command, const QString &to, const QString &ctcpMessage);
+
+ void writeCtcpMessage(const QString &command, const QString &to, const QString &suffix,
+ const QString &ctcpCommand, const QStringList &ctcpArgs, const QString &ctcpSuffix = QString::null,
+ bool emitRepliedCtcp = true);
+
+ inline void writeCtcpQueryMessage(const QString &to, const QString &suffix,
+ const QString &ctcpCommand, const QStringList &ctcpArgs = QStringList(), const QString &ctcpSuffix = QString::null,
+ bool emitRepliedCtcp = true)
+ { return writeCtcpMessage("PRIVMSG", to, suffix, ctcpCommand, ctcpArgs, ctcpSuffix, emitRepliedCtcp); }
+
+ inline void writeCtcpReplyMessage(const QString &to, const QString &ctcpMessage)
+ { writeCtcpMessage("NOTICE", to, ctcpMessage); }
+
+ inline void writeCtcpReplyMessage(const QString &to, const QString &suffix,
+ const QString &ctcpCommand, const QStringList &ctcpArgs = QStringList(), const QString &ctcpSuffix = QString::null,
+ bool emitRepliedCtcp = true)
+ { return writeCtcpMessage("NOTICE", to, suffix, ctcpCommand, ctcpArgs, ctcpSuffix, emitRepliedCtcp); }
+
+ inline void writeCtcpErrorMessage(const QString &to, const QString &ctcpLine, const QString &errorMsg,
+ bool emitRepliedCtcp=true)
+ { return writeCtcpReplyMessage(to, QString::null, "ERRMSG", ctcpLine, errorMsg, emitRepliedCtcp); }
+
+ bool bind(const QString &command, QObject *object, const char *member,
+ int minArgs = KIRC::MessageRedirector::Unknown,
+ int maxArgs = KIRC::MessageRedirector::Unknown,
+ const QString &helpMessage = QString::null);
+
+ bool bind(int id, QObject *object, const char *member,
+ int minArgs = KIRC::MessageRedirector::Unknown,
+ int maxArgs = KIRC::MessageRedirector::Unknown,
+ const QString &helpMessage = QString::null);
+
+ bool bindCtcpQuery(const QString &command, QObject *object, const char *member,
+ int minArgs = KIRC::MessageRedirector::Unknown,
+ int maxArgs = KIRC::MessageRedirector::Unknown,
+ const QString &helpMessage = QString::null);
+
+ bool bindCtcpReply(const QString &command, QObject *object, const char *member,
+ int minArgs = KIRC::MessageRedirector::Unknown,
+ int maxArgs = KIRC::MessageRedirector::Unknown,
+ const QString &helpMessage = QString::null);
+
+
+ void away(bool isAway, const QString &awayMessage = QString::null);
+ void ison(const QStringList &nickList);
+ void join(const QString &name, const QString &key);
+ void kick(const QString &user, const QString &channel, const QString &reason);
+ void list();
+ void mode(const QString &target, const QString &mode);
+ void motd(const QString &server = QString::null);
+ void nick(const QString &newNickname);
+ void notice(const QString &target, const QString &message);
+ void part(const QString &name, const QString &reason);
+ void pass(const QString &password);
+ void privmsg(const QString &contact, const QString &message);
+
+ /**
+ * Send a quit message for the given reason.
+ * If now is set to true the connection is closed and no event message is sent.
+ * Therefore setting now to true should only be used while destroying the object.
+ */
+ void quit(const QString &reason, bool now=false);
+
+ void topic(const QString &channel, const QString &topic);
+ void user(const QString &newUsername, const QString &hostname, const QString &newRealname);
+ void user(const QString &newUsername, Q_UINT8 mode, const QString &newRealname);
+ void whois(const QString &user);
+
+
+ /* CTCP commands */
+ void CtcpRequestCommand(const QString &contact, const QString &command);
+ void CtcpRequest_action(const QString &contact, const QString &message);
+ void CtcpRequest_dcc(const QString &, const QString &, unsigned int port, KIRC::Transfer::Type type);
+ void CtcpRequest_ping(const QString &target);
+ void CtcpRequest_version(const QString &target);
+
+public slots:
+ void showInfoDialog();
+
+signals:
+ void statusChanged(KIRC::Engine::Status newStatus);
+ void internalError(KIRC::Engine::Error, KIRC::Message &);
+
+ void receivedMessage(KIRC::Message &);
+
+ /**
+ * Emit a received message.
+ * The received message could have been translated to your locale.
+ *
+ * @param type the message type.
+ * @param from the originator of the message.
+ * @param to is the list of entities that are related to this message.
+ * @param msg the message (usually translated).
+ *
+ * @note Most of the following numeric messages should be deprecated, and call this method instead.
+ * Most of the methods, using it, update KIRC::Entities.
+ * Lists based messages are sent via dedicated API, therefore they don't use this.
+ */
+ // @param args the args to apply to this message.
+ void receivedMessage( KIRC::Engine::ServerMessageType type,
+ const KIRC::EntityPtr &from,
+ const KIRC::EntityPtrList &to,
+ const QString &msg);
+
+ void successfullyChangedNick(const QString &, const QString &);
+
+ //ServerContact Signals
+ void incomingMotd(const QString &motd);
+ void incomingNotice(const QString &originating, const QString &message);
+ void incomingHostInfo(const QString &servername, const QString &version,
+ const QString &userModes, const QString &channelModes);
+ void incomingYourHostInfo(const QString &servername, const QString &version,
+ const QString &userModes, const QString &channelModes);
+ void incomingConnectString(const QString &clients);
+
+ //Channel Contact Signals
+ void incomingMessage(const QString &originating, const QString &target, const QString &message);
+ void incomingTopicChange(const QString &, const QString &, const QString &);
+ void incomingExistingTopic(const QString &, const QString &);
+ void incomingTopicUser(const QString &channel, const QString &user, const QDateTime &time);
+ void incomingJoinedChannel(const QString &channel,const QString &nick);
+ void incomingPartedChannel(const QString &channel,const QString &nick, const QString &reason);
+ void incomingNamesList(const QString &channel, const QStringList &nicknames);
+ void incomingEndOfNames(const QString &channel);
+ void incomingChannelMode(const QString &channel, const QString &mode, const QString &params);
+ void incomingCannotSendToChannel(const QString &channel, const QString &message);
+ void incomingChannelModeChange(const QString &channel, const QString &nick, const QString &mode);
+ void incomingChannelHomePage(const QString &channel, const QString &url);
+
+ //Contact Signals
+ void incomingPrivMessage(const QString &, const QString &, const QString &);
+ void incomingQuitIRC(const QString &user, const QString &reason);
+ void incomingUserModeChange(const QString &nick, const QString &mode);
+ void incomingNoSuchNickname(const QString &nick);
+
+ // CTCP Signals
+// void action(const QString &from, const QString &to, const QString &message);
+ void incomingAction(const QString &channel, const QString &originating, const QString &message);
+ void incomingPrivAction(const QString &target, const QString &originating, const QString &message);
+
+ //Response Signals
+ void incomingUserOnline(const QString &nick);
+ void incomingWhoIsUser(const QString &nickname, const QString &username,
+ const QString &hostname, const QString &realname);
+ void incomingWhoWasUser(const QString &nickname, const QString &username,
+ const QString &hostname, const QString &realname);
+ void incomingWhoIsServer(const QString &nickname, const QString &server, const QString &serverInfo);
+ void incomingWhoIsOperator(const QString &nickname);
+ void incomingWhoIsIdentified(const QString &nickname);
+ void incomingWhoIsChannels(const QString &nickname, const QString &channel);
+ void incomingWhoIsIdle(const QString &nickname, unsigned long seconds); /* 317 */
+ void incomingSignOnTime(const QString &nickname, unsigned long seconds); /* 317 */
+ void incomingEndOfWhois(const QString &nickname);
+ void incomingEndOfWhoWas(const QString &nickname);
+
+ void incomingWhoReply( const QString &nick, const QString &channel, const QString &user, const QString &host,
+ const QString &server,bool away, const QString &flag, uint hops, const QString &realName );
+
+ void incomingEndOfWho( const QString &query );
+
+ //Error Message Signals
+ void incomingServerLoadTooHigh();
+ void incomingNickInUse(const QString &usingNick);
+ void incomingNickChange(const QString &, const QString &);
+ void incomingFailedServerPassword();
+ void incomingFailedChankey(const QString &);
+ void incomingFailedChanBanned(const QString &);
+ void incomingFailedChanInvite(const QString &);
+ void incomingFailedChanFull(const QString &);
+ void incomingFailedNickOnLogin(const QString &);
+ void incomingNoNickChan(const QString &);
+ void incomingWasNoNick(const QString &);
+
+ //General Signals
+ void incomingUnknown(const QString &);
+ void incomingUnknownCtcp(const QString &);
+ void incomingKick(const QString &channel, const QString &nick,
+ const QString &nickKicked, const QString &reason);
+
+ void incomingUserIsAway(const QString &nick, const QString &awayMessage);
+ void incomingListedChan(const QString &chan, uint users, const QString &topic);
+ void incomingEndOfList();
+
+ void incomingCtcpReply(const QString &type, const QString &target, const QString &messageReceived);
+
+private slots:
+ void destroyed(KIRC::Entity *entity);
+
+ void slotReadyRead();
+
+ void slotConnected();
+ void slotConnectionClosed();
+ void error(int errCode = 0);
+
+ void ignoreMessage(KIRC::Message &msg);
+ void emitSuffix(KIRC::Message &);
+
+ void error(KIRC::Message &msg);
+ void join(KIRC::Message &msg);
+ void kick(KIRC::Message &msg);
+ void mode(KIRC::Message &msg);
+ void nick(KIRC::Message &msg);
+ void notice(KIRC::Message &msg);
+ void part(KIRC::Message &msg);
+ void ping(KIRC::Message &msg);
+ void pong(KIRC::Message &msg);
+ void privmsg(KIRC::Message &msg);
+// void squit(KIRC::Message &msg);
+ void quit(KIRC::Message &msg);
+ void topic(KIRC::Message &msg);
+
+ void numericReply_001(KIRC::Message &msg);
+ void numericReply_002(KIRC::Message &msg);
+ void numericReply_003(KIRC::Message &msg);
+ void numericReply_004(KIRC::Message &msg);
+ void numericReply_005(KIRC::Message &msg);
+ void numericReply_250(KIRC::Message &msg);
+ void numericReply_251(KIRC::Message &msg);
+ void numericReply_252(KIRC::Message &msg);
+ void numericReply_253(KIRC::Message &msg);
+ void numericReply_254(KIRC::Message &msg);
+ void numericReply_255(KIRC::Message &msg);
+ void numericReply_263(KIRC::Message &msg);
+ void numericReply_265(KIRC::Message &msg);
+ void numericReply_266(KIRC::Message &msg);
+ void numericReply_301(KIRC::Message &msg);
+ void numericReply_303(KIRC::Message &msg);
+// void numericReply_305(KIRC::Message &msg);
+// void numericReply_306(KIRC::Message &msg);
+ void numericReply_307(KIRC::Message &msg);
+ void numericReply_311(KIRC::Message &msg);
+ void numericReply_312(KIRC::Message &msg);
+ void numericReply_313(KIRC::Message &msg);
+ void numericReply_314(KIRC::Message &msg);
+ void numericReply_315(KIRC::Message &msg);
+ void numericReply_317(KIRC::Message &msg);
+ void numericReply_318(KIRC::Message &msg);
+ void numericReply_319(KIRC::Message &msg);
+ void numericReply_320(KIRC::Message &msg);
+ void numericReply_322(KIRC::Message &msg);
+ void numericReply_323(KIRC::Message &msg);
+ void numericReply_324(KIRC::Message &msg);
+ void numericReply_328(KIRC::Message &msg);
+ void numericReply_329(KIRC::Message &msg);
+ void numericReply_331(KIRC::Message &msg);
+ void numericReply_332(KIRC::Message &msg);
+ void numericReply_333(KIRC::Message &msg);
+ void numericReply_352(KIRC::Message &msg);
+ void numericReply_353(KIRC::Message &msg);
+ void numericReply_366(KIRC::Message &msg);
+ void numericReply_369(KIRC::Message &msg);
+ void numericReply_372(KIRC::Message &msg);
+// void numericReply_376(KIRC::Message &msg);
+
+ void numericReply_401(KIRC::Message &msg);
+ void numericReply_406(KIRC::Message &msg);
+ void numericReply_422(KIRC::Message &msg);
+ void numericReply_433(KIRC::Message &msg);
+ void numericReply_464(KIRC::Message &msg);
+ void numericReply_471(KIRC::Message &msg);
+ void numericReply_473(KIRC::Message &msg);
+ void numericReply_474(KIRC::Message &msg);
+ void numericReply_475(KIRC::Message &msg);
+
+
+ void CtcpQuery_action(KIRC::Message &msg);
+ void CtcpQuery_clientinfo(KIRC::Message &msg);
+ void CtcpQuery_finger(KIRC::Message &msg);
+ void CtcpQuery_dcc(KIRC::Message &msg);
+ void CtcpQuery_ping(KIRC::Message &msg);
+ void CtcpQuery_source(KIRC::Message &msg);
+ void CtcpQuery_time(KIRC::Message &msg);
+ void CtcpQuery_userinfo(KIRC::Message &msg);
+ void CtcpQuery_version(KIRC::Message &msg);
+
+ void CtcpReply_errmsg(KIRC::Message &msg);
+ void CtcpReply_ping(KIRC::Message &msg);
+ void CtcpReply_version(KIRC::Message &msg);
+
+private:
+ void bindCommands();
+ void bindNumericReplies();
+ void bindCtcp();
+
+ void setStatus(KIRC::Engine::Status status);
+ bool invokeCtcpCommandOfMessage(const QDict<KIRC::MessageRedirector> &map, KIRC::Message &message);
+
+ /*
+ * Methods that handles all the bindings creations.
+ * This methods is used by all the bind(...) methods.
+ */
+ bool _bind(QDict<KIRC::MessageRedirector> &dict,
+ QString command, QObject *object, const char *member,
+ int minArgs, int maxArgs, const QString &helpMessage);
+
+ //Static regexes
+ static const QRegExp m_RemoveLinefeeds;
+
+ KIRC::Engine::Status m_status;
+ QString m_Host;
+ Q_UINT16 m_Port;
+
+// QUrl serverURL;
+// QUrl currentServerURL;
+ QString m_Nickname;
+ QString m_Username;
+ QString m_realName;
+ QString m_Passwd;
+ bool m_ReqsPasswd;
+ bool m_FailedNickOnLogin;
+ bool m_useSSL;
+
+ QValueList<KIRC::Entity *> m_entities;
+ KIRC::EntityPtr m_server;
+ KIRC::EntityPtr m_self;
+
+ QString m_VersionString;
+ QString m_UserString;
+ QString m_SourceString;
+ QString m_PendingNick;
+
+ QDict<KIRC::MessageRedirector> m_commands;
+// QIntDict<KIRC::MessageRedirector> m_numericCommands;
+ QDict<KIRC::MessageRedirector> m_ctcpQueries;
+ QDict<KIRC::MessageRedirector> m_ctcpReplies;
+
+ QMap<QString, QString> customCtcpMap;
+ QDict<QTextCodec> codecs;
+ QTextCodec *defaultCodec;
+
+ KExtendedSocket *m_sock;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/irc/libkirc/kircengine_commands.cpp b/kopete/protocols/irc/libkirc/kircengine_commands.cpp
new file mode 100644
index 00000000..0a0f9002
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircengine_commands.cpp
@@ -0,0 +1,312 @@
+/*
+ kirc_commands.h - IRC Client
+
+ Copyright (c) 2003-2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "kircengine.h"
+
+#include <kextsock.h>
+
+#include <qtimer.h>
+
+using namespace KIRC;
+
+void Engine::bindCommands()
+{
+ bind("ERROR", this, SLOT(error(KIRC::Message &)), 0, 0);
+ bind("JOIN", this, SLOT(join(KIRC::Message &)), 0, 1);
+ bind("KICK", this, SLOT(kick(KIRC::Message &)), 2, 2);
+ bind("NICK", this, SLOT(nick(KIRC::Message &)), 0, 0);
+ bind("MODE", this, SLOT(mode(KIRC::Message &)), 1, 1);
+ bind("NOTICE", this, SLOT(notice(KIRC::Message &)), 1, 1);
+ bind("PART", this, SLOT(part(KIRC::Message &)), 1, 1);
+ bind("PING", this, SLOT(ping(KIRC::Message &)), 0, 0);
+ bind("PONG", this, SLOT(pong(KIRC::Message &)), 0, 0);
+ bind("PRIVMSG", this, SLOT(privmsg(KIRC::Message &)), 1, 1);
+ bind("QUIT", this, SLOT(quit(KIRC::Message &)), 0, 0);
+// bind("SQUIT", this, SLOT(squit(KIRC::Message &)), 1, 1);
+ bind("TOPIC", this, SLOT(topic(KIRC::Message &)), 1, 1);
+}
+
+void Engine::away(bool isAway, const QString &awayMessage)
+{
+ if(isAway)
+ if( !awayMessage.isEmpty() )
+ writeMessage("AWAY", QString::null, awayMessage);
+ else
+ writeMessage("AWAY", QString::null, QString::fromLatin1("I'm away."));
+ else
+ writeMessage("AWAY", QString::null);
+}
+
+// FIXME: Really handle this message
+void Engine::error(Message &)
+{
+ setStatus(Closing);
+}
+
+void Engine::ison(const QStringList &nickList)
+{
+ if (!nickList.isEmpty())
+ {
+ QString statement = QString::fromLatin1("ISON");
+ for (QStringList::ConstIterator it = nickList.begin(); it != nickList.end(); ++it)
+ {
+ if ((statement.length()+(*it).length())>509) // 512(max buf)-2("\r\n")-1(<space separator>)
+ {
+ writeMessage(statement);
+ statement = QString::fromLatin1("ISON ") + (*it);
+ }
+ else
+ statement.append(QChar(' ') + (*it));
+ }
+ writeMessage(statement);
+ }
+}
+
+void Engine::join(const QString &name, const QString &key)
+{
+ QStringList args(name);
+ if ( !key.isNull() )
+ args << key;
+
+ writeMessage("JOIN", args);
+}
+
+void Engine::join(Message &msg)
+{
+ /* RFC say: "( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0""
+ * suspected: ":<channel> *(" "/"," <channel>)"
+ * assumed ":<channel>"
+ * This is the response of someone joining a channel.
+ * Remember that this will be emitted when *you* /join a room for the first time */
+
+ if (msg.argsSize()==1)
+ emit incomingJoinedChannel(Kopete::Message::unescape(msg.arg(0)), msg.nickFromPrefix());
+ else
+ emit incomingJoinedChannel(Kopete::Message::unescape(msg.suffix()), msg.nickFromPrefix());
+}
+
+void Engine::kick(const QString &user, const QString &channel, const QString &reason)
+{
+ writeMessage("KICK", QStringList(channel) << user << reason);
+}
+
+void Engine::kick(Message &msg)
+{
+ /* The given user is kicked.
+ * "<channel> *( "," <channel> ) <user> *( "," <user> ) [<comment>]"
+ */
+ emit incomingKick( Kopete::Message::unescape(msg.arg(0)), msg.nickFromPrefix(), msg.arg(1), msg.suffix());
+}
+
+void Engine::mode(const QString &target, const QString &mode)
+{
+ writeMessage("MODE", QStringList(target) << mode);
+}
+
+void Engine::mode(Message &msg)
+{
+ /* Change the mode of a user.
+ * "<nickname> *( ( "+" / "-" ) *( "i" / "w" / "o" / "O" / "r" ) )"
+ */
+ QStringList args = msg.args();
+ args.pop_front();
+ if( Entity::isChannel( msg.arg(0) ) )
+ emit incomingChannelModeChange( msg.arg(0), msg.nickFromPrefix(), args.join(" "));
+ else
+ emit incomingUserModeChange( msg.nickFromPrefix(), args.join(" "));
+}
+
+void Engine::nick(const QString &newNickname)
+{
+ m_PendingNick = newNickname;
+ writeMessage("NICK", newNickname);
+}
+
+void Engine::nick(Message &msg)
+{
+ /* Nick name of a user changed
+ * "<nickname>" */
+ QString oldNick = msg.prefix().section('!', 0, 0);
+ QString newNick = msg.suffix();
+
+ if( codecs[ oldNick ] )
+ {
+ QTextCodec *c = codecs[ oldNick ];
+ codecs.remove( oldNick );
+ codecs.insert( newNick, c );
+ }
+
+ if (oldNick.lower() == m_Nickname.lower())
+ {
+ emit successfullyChangedNick(oldNick, msg.suffix());
+ m_Nickname = msg.suffix();
+ }
+ else
+ emit incomingNickChange(oldNick, msg.suffix());
+}
+
+void Engine::part(const QString &channel, const QString &reason)
+{
+ /* This will part a channel with 'reason' as the reason for parting
+ */
+ writeMessage("PART", channel, reason);
+}
+
+void Engine::part(Message &msg)
+{
+ /* This signal emits when a user parts a channel
+ * "<channel> *( "," <channel> ) [ <Part Message> ]"
+ */
+ kdDebug(14120) << "User parting" << endl;
+ emit incomingPartedChannel(msg.arg(0), msg.nickFromPrefix(), msg.suffix());
+}
+
+void Engine::pass(const QString &password)
+{
+ writeMessage("PASS", password);
+}
+
+void Engine::ping(Message &msg)
+{
+ writeMessage("PONG", msg.arg(0), msg.suffix());
+}
+
+void Engine::pong(Message &/*msg*/)
+{
+}
+
+void Engine::quit(const QString &reason, bool /*now*/)
+{
+ kdDebug(14120) << k_funcinfo << reason << endl;
+
+ if (isDisconnected())
+ return;
+
+ if (isConnected())
+ writeMessage("QUIT", QString::null, reason);
+
+ setStatus(Closing);
+}
+
+void Engine::quit(Message &msg)
+{
+ /* This signal emits when a user quits irc.
+ */
+ kdDebug(14120) << "User quiting" << endl;
+ emit incomingQuitIRC(msg.prefix(), msg.suffix());
+}
+
+void Engine::user(const QString &newUserName, const QString &hostname, const QString &newRealName)
+{
+ /* RFC1459: "<username> <hostname> <servername> <realname>"
+ * The USER command is used at the beginning of connection to specify
+ * the username, hostname and realname of a new user.
+ * hostname is usualy set to "127.0.0.1" */
+ m_Username = newUserName;
+ m_realName = newRealName;
+
+ writeMessage("USER", QStringList(m_Username) << hostname << m_Host, m_realName);
+}
+
+void Engine::user(const QString &newUserName, Q_UINT8 mode, const QString &newRealName)
+{
+ /* RFC2812: "<user> <mode> <unused> <realname>"
+ * mode is a numeric value (from a bit mask).
+ * 0x00 normal
+ * 0x04 request +w
+ * 0x08 request +i */
+ m_Username = newUserName;
+ m_realName = newRealName;
+
+ writeMessage("USER", QStringList(m_Username) << QString::number(mode) << QChar('*'), m_realName);
+}
+
+void Engine::topic(const QString &channel, const QString &topic)
+{
+ writeMessage("TOPIC", channel, topic);
+}
+
+void Engine::topic(Message &msg)
+{
+ /* The topic of a channel changed. emit the channel, new topic, and the person who changed it.
+ * "<channel> [ <topic> ]"
+ */
+ emit incomingTopicChange(msg.arg(0), msg.nickFromPrefix(), msg.suffix());
+}
+
+void Engine::list()
+{
+ writeMessage("LIST", QString::null);
+}
+
+void Engine::motd(const QString &server)
+{
+ writeMessage("MOTD", server);
+}
+
+void Engine::privmsg(const QString &contact, const QString &message)
+{
+ writeMessage("PRIVMSG", contact, message, codecForNick( contact ) );
+}
+
+void Engine::privmsg(Message &msg)
+{
+ /* This is a signal that indicates there is a new message.
+ * This can be either from a channel or from a specific user. */
+ Message m = msg;
+ if (!m.suffix().isEmpty())
+ {
+ QString user = m.arg(0);
+ QString message = m.suffix();
+ const QTextCodec *codec = codecForNick( user );
+ if (codec != defaultCodec) {
+ m.decodeAgain( codec );
+ message = m.suffix();
+ }
+ if (Entity::isChannel(user))
+ emit incomingMessage(m.nickFromPrefix(), Kopete::Message::unescape(m.arg(0)), message );
+ else
+ emit incomingPrivMessage(m.nickFromPrefix(), Kopete::Message::unescape(m.arg(0)), message );
+// emit receivedMessage(PrivateMessage, msg.entityFrom(), msg.entityTo(), message);
+ }
+
+ if( m.hasCtcpMessage() )
+ {
+ invokeCtcpCommandOfMessage(m_ctcpQueries, m);
+ }
+}
+
+void Engine::notice(const QString &target, const QString &message)
+{
+ writeMessage("NOTICE", target, message);
+}
+
+void Engine::notice(Message &msg)
+{
+ if(!msg.suffix().isEmpty())
+ emit incomingNotice(msg.prefix(), msg.suffix());
+
+ if(msg.hasCtcpMessage())
+ invokeCtcpCommandOfMessage(m_ctcpReplies, msg);
+}
+
+void Engine::whois(const QString &user)
+{
+ writeMessage("WHOIS", user);
+}
diff --git a/kopete/protocols/irc/libkirc/kircengine_ctcp.cpp b/kopete/protocols/irc/libkirc/kircengine_ctcp.cpp
new file mode 100644
index 00000000..db1903f3
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircengine_ctcp.cpp
@@ -0,0 +1,351 @@
+/*
+ kirc_ctcp.h - IRC Client
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "config.h"
+
+#include "kircengine.h"
+#include "kirctransferhandler.h"
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <kextsock.h>
+
+#include <qfileinfo.h>
+#include <qregexp.h>
+
+using namespace KIRC;
+
+void Engine::bindCtcp()
+{
+ bindCtcpQuery("ACTION", this, SLOT(CtcpQuery_action(KIRC::Message &)),
+ -1, -1);
+ bindCtcpQuery("CLIENTINFO", this, SLOT(CtcpQuery_clientinfo(KIRC::Message &)),
+ -1, 1);
+ bindCtcpQuery("DCC", this, SLOT(CtcpQuery_dcc(KIRC::Message &)),
+ 4, 5);
+ bindCtcpQuery("FINGER", this, SLOT(CtcpQuery_finger(KIRC::Message &)),
+ -1, 0);
+ bindCtcpQuery("PING", this, SLOT(CtcpQuery_ping(KIRC::Message &)),
+ 1, 1);
+ bindCtcpQuery("SOURCE", this, SLOT(CtcpQuery_source(KIRC::Message &)),
+ -1, 0);
+ bindCtcpQuery("TIME", this, SLOT(CtcpQuery_time(KIRC::Message &)),
+ -1, 0);
+ bindCtcpQuery("USERINFO", this, SLOT(CtcpQuery_userinfo(KIRC::Message &)),
+ -1, 0);
+ bindCtcpQuery("VERSION", this, SLOT(CtcpQuery_version(KIRC::Message &)),
+ -1, 0);
+
+ bindCtcpReply("ERRMSG", this, SLOT(CtcpReply_errmsg(KIRC::Message &)),
+ 1, -1);
+ bindCtcpReply("PING", this, SLOT(CtcpReply_ping(KIRC::Message &)),
+ 1, 1, "");
+ bindCtcpReply("VERSION", this, SLOT(CtcpReply_version(KIRC::Message &)),
+ -1, -1, "");
+}
+
+// Normal order for a ctcp command:
+// CtcpRequest_*
+// CtcpQuery_*
+// CtcpReply_* (if any)
+
+/* Generic ctcp commnd for the /ctcp trigger */
+void Engine::CtcpRequestCommand(const QString &contact, const QString &command)
+{
+ if(m_status == Connected)
+ {
+ writeCtcpQueryMessage(contact, QString::null, command);
+// emit ctcpCommandMessage( contact, command );
+ }
+}
+
+void Engine::CtcpRequest_action(const QString &contact, const QString &message)
+{
+ if(m_status == Connected)
+ {
+ writeCtcpQueryMessage(contact, QString::null, "ACTION", message);
+
+ if( Entity::isChannel(contact) )
+ emit incomingAction(Kopete::Message::unescape(contact), Kopete::Message::unescape(m_Nickname), message);
+ else
+ emit incomingPrivAction(Kopete::Message::unescape(m_Nickname), Kopete::Message::unescape(contact), message);
+ }
+}
+
+void Engine::CtcpQuery_action(Message &msg)
+{
+ QString target = msg.arg(0);
+ if (target[0] == '#' || target[0] == '!' || target[0] == '&')
+ emit incomingAction(target, msg.nickFromPrefix(), msg.ctcpMessage().ctcpRaw());
+ else
+ emit incomingPrivAction(msg.nickFromPrefix(), Kopete::Message::unescape(target), msg.ctcpMessage().ctcpRaw());
+}
+
+/*
+NO REPLY EXIST FOR THE CTCP ACTION COMMAND !
+bool Engine::CtcpReply_action(Message &msg)
+{
+}
+*/
+
+// FIXME: the API can now answer to help commands.
+void Engine::CtcpQuery_clientinfo(Message &msg)
+{
+ QString clientinfo = customCtcpMap[ QString::fromLatin1("clientinfo") ];
+
+ if (clientinfo.isNull())
+ clientinfo = QString::fromLatin1("The following commands are supported, but "
+ "without sub-command help: VERSION, CLIENTINFO, USERINFO, TIME, SOURCE, PING,"
+ "ACTION.");
+
+ writeCtcpReplyMessage( msg.nickFromPrefix(), QString::null,
+ msg.ctcpMessage().command(), QString::null, clientinfo);
+}
+
+void Engine::CtcpRequest_dcc(const QString &nickname, const QString &fileName, uint port, Transfer::Type type)
+{
+ if( m_status != Connected ||
+ m_sock->localAddress() == 0 ||
+ m_sock->localAddress()->nodeName().isNull())
+ return;
+
+ switch(type)
+ {
+ case Transfer::Chat:
+ {
+ writeCtcpQueryMessage(nickname, QString::null,
+ QString::fromLatin1("DCC"),
+ QStringList(QString::fromLatin1("CHAT")) << QString::fromLatin1("chat") <<
+ m_sock->localAddress()->nodeName() << QString::number(port)
+ );
+ break;
+ }
+
+ case Transfer::FileOutgoing:
+ {
+ QFileInfo file(fileName);
+ QString noWhiteSpace = file.fileName();
+ if (noWhiteSpace.contains(' ') > 0)
+ noWhiteSpace.replace(QRegExp("\\s+"), "_");
+
+ TransferServer *server = TransferHandler::self()->createServer(this, nickname, type, fileName, file.size());
+
+ QString ip = m_sock->localAddress()->nodeName();
+ QString ipNumber = QString::number( ntohl( inet_addr( ip.latin1() ) ) );
+
+ kdDebug(14120) << "Starting DCC file outgoing transfer." << endl;
+
+ writeCtcpQueryMessage(nickname, QString::null,
+ QString::fromLatin1("DCC"),
+ QStringList(QString::fromLatin1("SEND")) << noWhiteSpace << ipNumber <<
+ QString::number(server->port()) << QString::number(file.size())
+ );
+ break;
+ }
+
+ case Transfer::FileIncoming:
+ case Transfer::Unknown:
+ default:
+ break;
+ }
+}
+
+void Engine::CtcpQuery_dcc(Message &msg)
+{
+ Message &ctcpMsg = msg.ctcpMessage();
+ QString dccCommand = ctcpMsg.arg(0).upper();
+
+ if (dccCommand == QString::fromLatin1("CHAT"))
+ {
+// if(ctcpMsg.argsSize()!=4) return false;
+
+ /* DCC CHAT type longip port
+ *
+ * type = Either Chat or Talk, but almost always Chat these days
+ * longip = 32-bit Internet address of originator's machine
+ * port = Port on which the originator is waitng for a DCC chat
+ */
+ bool okayHost, okayPort;
+ // should ctctMsg.arg(1) be tested?
+ QHostAddress address(ctcpMsg.arg(2).toUInt(&okayHost));
+ unsigned int port = ctcpMsg.arg(3).toUInt(&okayPort);
+ if (okayHost && okayPort)
+ {
+ kdDebug(14120) << "Starting DCC chat window." << endl;
+ TransferHandler::self()->createClient(
+ this, msg.nickFromPrefix(),
+ address, port,
+ Transfer::Chat );
+ }
+ }
+ else if (dccCommand == QString::fromLatin1("SEND"))
+ {
+// if(ctcpMsg.argsSize()!=5) return false;
+
+ /* DCC SEND (filename) (longip) (port) (filesize)
+ *
+ * filename = Name of file being sent
+ * longip = 32-bit Internet address of originator's machine
+ * port = Port on which the originator is waiitng for a DCC chat
+ * filesize = Size of file being sent
+ */
+ bool okayHost, okayPort, okaySize;
+// QFileInfo realfile(msg.arg(1));
+ QHostAddress address(ctcpMsg.arg(2).toUInt(&okayHost));
+ unsigned int port = ctcpMsg.arg(3).toUInt(&okayPort);
+ unsigned int size = ctcpMsg.arg(4).toUInt(&okaySize);
+ if (okayHost && okayPort && okaySize)
+ {
+ kdDebug(14120) << "Starting DCC send file transfert for file:" << ctcpMsg.arg(1) << endl;
+ TransferHandler::self()->createClient(
+ this, msg.nickFromPrefix(),
+ address, port,
+ Transfer::FileIncoming,
+ ctcpMsg.arg(1), size );
+ }
+ }
+// else
+// ((MessageRedirector *)sender())->error("Unknow dcc command");
+}
+
+/*
+NO REPLY EXIST FOR THE CTCP DCC COMMAND !
+bool Engine::CtcpReply_dcc(Message &msg)
+{
+}
+*/
+
+void Engine::CtcpReply_errmsg(Message &)
+{
+ // should emit one signal
+}
+
+void Engine::CtcpQuery_finger( Message &)
+{
+ // To be implemented
+}
+
+void Engine::CtcpRequest_ping(const QString &target)
+{
+ kdDebug(14120) << k_funcinfo << endl;
+
+ timeval time;
+ if (gettimeofday(&time, 0) == 0)
+ {
+ QString timeReply;
+
+ if( Entity::isChannel(target) )
+ timeReply = QString::fromLatin1("%1.%2").arg(time.tv_sec).arg(time.tv_usec);
+ else
+ timeReply = QString::number( time.tv_sec );
+
+ writeCtcpQueryMessage( target, QString::null, "PING", timeReply);
+ }
+// else
+// ((MessageRedirector *)sender())->error("failed to get current time");
+}
+
+void Engine::CtcpQuery_ping(Message &msg)
+{
+ writeCtcpReplyMessage( msg.nickFromPrefix(), QString::null,
+ msg.ctcpMessage().command(), msg.ctcpMessage().arg(0));
+}
+
+void Engine::CtcpReply_ping(Message &msg)
+{
+ timeval time;
+ if (gettimeofday(&time, 0) == 0)
+ {
+ // FIXME: the time code is wrong for usec
+ QString timeReply = QString::fromLatin1("%1.%2").arg(time.tv_sec).arg(time.tv_usec);
+ double newTime = timeReply.toDouble();
+ double oldTime = msg.suffix().section(' ',0, 0).toDouble();
+ double difference = newTime - oldTime;
+ QString diffString;
+
+ if (difference < 1)
+ {
+ diffString = QString::number(difference);
+ diffString.remove((diffString.find('.') -1), 2);
+ diffString.truncate(3);
+ diffString.append("milliseconds");
+ }
+ else
+ {
+ diffString = QString::number(difference);
+ QString seconds = diffString.section('.', 0, 0);
+ QString millSec = diffString.section('.', 1, 1);
+ millSec.remove(millSec.find('.'), 1);
+ millSec.truncate(3);
+ diffString = QString::fromLatin1("%1 seconds, %2 milliseconds").arg(seconds).arg(millSec);
+ }
+
+ emit incomingCtcpReply(QString::fromLatin1("PING"), msg.nickFromPrefix(), diffString);
+ }
+// else
+// ((MessageRedirector *)sender())->error("failed to get current time");
+}
+
+void Engine::CtcpQuery_source(Message &msg)
+{
+ writeCtcpReplyMessage(msg.nickFromPrefix(), QString::null,
+ msg.ctcpMessage().command(), m_SourceString);
+}
+
+void Engine::CtcpQuery_time(Message &msg)
+{
+ writeCtcpReplyMessage(msg.nickFromPrefix(), QString::null,
+ msg.ctcpMessage().command(), QDateTime::currentDateTime().toString(),
+ QString::null, false);
+}
+
+void Engine::CtcpQuery_userinfo(Message &msg)
+{
+ QString userinfo = customCtcpMap[ QString::fromLatin1("userinfo") ];
+
+ if (userinfo.isNull())
+ userinfo = m_UserString;
+
+ writeCtcpReplyMessage(msg.nickFromPrefix(), QString::null,
+ msg.ctcpMessage().command(), QString::null, userinfo);
+}
+
+void Engine::CtcpRequest_version(const QString &target)
+{
+ writeCtcpQueryMessage(target, QString::null, "VERSION");
+}
+
+void Engine::CtcpQuery_version(Message &msg)
+{
+ QString response = customCtcpMap[ QString::fromLatin1("version") ];
+ kdDebug(14120) << "Version check: " << response << endl;
+
+ if (response.isNull())
+ response = m_VersionString;
+
+ writeCtcpReplyMessage(msg.nickFromPrefix(),
+ msg.ctcpMessage().command() + " " + response);
+}
+
+void Engine::CtcpReply_version(Message &msg)
+{
+ emit incomingCtcpReply(msg.ctcpMessage().command(), msg.nickFromPrefix(), msg.ctcpMessage().ctcpRaw());
+}
diff --git a/kopete/protocols/irc/libkirc/kircengine_numericreplies.cpp b/kopete/protocols/irc/libkirc/kircengine_numericreplies.cpp
new file mode 100644
index 00000000..c47b8b05
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircengine_numericreplies.cpp
@@ -0,0 +1,570 @@
+
+/*
+ kircnumericreplies.cpp - IRC Client
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+ Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "kircengine.h"
+
+#include <qtimer.h>
+
+using namespace KIRC;
+
+/* IMPORTANT NOTE:
+ * Numeric replies always have the current nick or * as first argmuent.
+ * NOTE: * means undefined in most (all ?) of the cases.
+ */
+
+void Engine::bindNumericReplies()
+{
+ bind(1, this, SLOT(numericReply_001(KIRC::Message &)), 1, 1);
+ bind(2, this, SLOT(numericReply_002(KIRC::Message &)), 1, 1);
+ bind(3, this, SLOT(numericReply_003(KIRC::Message &)), 1, 1);
+ bind(4, this, SLOT(numericReply_004(KIRC::Message &)), 5, 5);
+ bind(5, this, SLOT(numericReply_004(KIRC::Message &)), 1, 1);
+
+ bind(250, this, SLOT(numericReply_250(KIRC::Message &)));
+ bind(251, this, SLOT(numericReply_251(KIRC::Message &)));
+ bind(252, this, SLOT(numericReply_252(KIRC::Message &)), 2, 2);
+ bind(253, this, SLOT(numericReply_253(KIRC::Message &)), 2, 2);
+ bind(254, this, SLOT(numericReply_254(KIRC::Message &)), 2, 2);
+ bind(255, this, SLOT(numericReply_255(KIRC::Message &)), 1, 1); // incomingConnectString
+
+ bind(263, this, SLOT(numericReply_263(KIRC::Message &))); // incomingServerLoadTooHigh
+ bind(265, this, SLOT(numericReply_265(KIRC::Message &)));
+ bind(266, this, SLOT(numericReply_266(KIRC::Message &)));
+
+ bind(301, this, SLOT(numericReply_301(KIRC::Message &)), 2, 2);
+ bind(303, this, SLOT(numericReply_303(KIRC::Message &)), 1, 1);
+ bind(305, this, SLOT(ignoreMessage(KIRC::Message &)), 0, 0 ); // You are no longer marked as away
+ bind(306, this, SLOT(ignoreMessage(KIRC::Message &)), 0, 0 ); // You are marked as away
+ bind(307, this, SLOT(numericReply_307(KIRC::Message &)), 1, 1);
+ bind(311, this, SLOT(numericReply_311(KIRC::Message &)), 5, 5);
+ bind(312, this, SLOT(numericReply_312(KIRC::Message &)), 3, 3);
+ bind(313, this, SLOT(numericReply_313(KIRC::Message &)), 2, 2);
+ bind(314, this, SLOT(numericReply_314(KIRC::Message &)), 5, 5);
+ bind(315, this, SLOT(numericReply_315(KIRC::Message &)), 2, 2);
+ bind(317, this, SLOT(numericReply_317(KIRC::Message &)), 3, 4);
+ bind(318, this, SLOT(numericReply_318(KIRC::Message &)), 2, 2);
+ bind(319, this, SLOT(numericReply_319(KIRC::Message &)), 2, 2);
+ bind(320, this, SLOT(numericReply_320(KIRC::Message &)), 2, 2);
+ bind(321, this, SLOT(ignoreMessage(KIRC::Message &)), 0, 0 );
+ bind(322, this, SLOT(numericReply_322(KIRC::Message &)), 3, 3);
+ bind(323, this, SLOT(numericReply_323(KIRC::Message &)), 1, 1);
+ bind(324, this, SLOT(numericReply_324(KIRC::Message &)), 2, 4);
+ bind(328, this, SLOT(numericReply_328(KIRC::Message &)), 2, 2);
+ bind(329, this, SLOT(numericReply_329(KIRC::Message &)), 3, 3);
+ bind(330, this, SLOT(ignoreMessage(KIRC::Message &)), 0, 0); // ???
+ bind(331, this, SLOT(numericReply_331(KIRC::Message &)), 2, 2);
+ bind(332, this, SLOT(numericReply_332(KIRC::Message &)), 2, 2);
+ bind(333, this, SLOT(numericReply_333(KIRC::Message &)), 4, 4);
+ bind(352, this, SLOT(numericReply_352(KIRC::Message &)), 5, 10);
+ bind(353, this, SLOT(numericReply_353(KIRC::Message &)), 3, 3);
+ bind(366, this, SLOT(numericReply_366(KIRC::Message &)), 2, 2);
+ bind(369, this, SLOT(numericReply_369(KIRC::Message &)), 2, 2);
+ bind(372, this, SLOT(numericReply_372(KIRC::Message &)), 1, 1);
+ bind(375, this, SLOT(ignoreMessage(KIRC::Message&)), 0, 0 );
+ bind(376, this, SLOT(ignoreMessage(KIRC::Message&)), 0, 0 );
+
+ bind(401, this, SLOT(numericReply_401(KIRC::Message &)), 2, 2); // incomingNoNickChan
+// bind(404, this, SLOT(numericReply_404(KIRC::Message &)), 2, 2); // incomingCannotSendToChannel
+ bind(406, this, SLOT(numericReply_406(KIRC::Message &)), 2, 2); // incomingWasNoNick
+ bind(422, this, SLOT(numericReply_422(KIRC::Message &)), 1, 1);
+ bind(433, this, SLOT(numericReply_433(KIRC::Message &)), 2, 2);
+// bind(442, this, SLOT(numericReply_442(KIRC::Message &)), 2, 2); // incomingCannotSendToChannel
+ bind(464, this, SLOT(numericReply_464(KIRC::Message &)), 1, 1);
+ bind(471, this, SLOT(numericReply_471(KIRC::Message &)), 2, 2);
+ bind(473, this, SLOT(numericReply_473(KIRC::Message &)), 2, 2);
+ bind(474, this, SLOT(numericReply_474(KIRC::Message &)), 2, 2);
+ bind(475, this, SLOT(numericReply_475(KIRC::Message &)), 2, 2);
+
+ //Freenode seems to use this for a non-RFC compliant purpose, as does Unreal
+ bind(477, this, SLOT(emitSuffix(KIRC::Message&)),0,0);
+}
+
+/* 001: "Welcome to the Internet Relay Network <nick>!<user>@<host>"
+ * Gives a welcome message in the form of:
+ */
+void Engine::numericReply_001(Message &msg)
+{
+ kdDebug(14121) << k_funcinfo << endl;
+
+ if (m_FailedNickOnLogin)
+ {
+ // this is if we had a "Nickname in use" message when connecting and we set another nick.
+ // This signal emits that the nick was accepted and we are now logged in
+ emit successfullyChangedNick(m_Nickname, m_PendingNick);
+ m_Nickname = m_PendingNick;
+ m_FailedNickOnLogin = false;
+ }
+
+ /* At this point we are connected and the server is ready for us to being taking commands
+ * although the MOTD comes *after* this.
+ */
+ emitSuffix(msg);
+
+ setStatus(Connected);
+}
+
+/* 002: ":Your host is <servername>, running version <ver>"
+ * Gives information about the host. The given informations are close to 004.
+ */
+void Engine::numericReply_002(Message &msg)
+{
+ emitSuffix(msg);
+}
+
+/* 003: "This server was created <date>"
+ * Gives the date that this server was created.
+ * NOTE: This is useful for determining the uptime of the server).
+ */
+void Engine::numericReply_003(Message &msg)
+{
+ emitSuffix(msg);
+}
+
+/* 004: "<servername> <version> <available user modes> <available channel modes>"
+ * Gives information about the servername, version, available modes, etc.
+ */
+void Engine::numericReply_004(Message &msg)
+{
+ emit incomingHostInfo(msg.arg(1),msg.arg(2),msg.arg(3),msg.arg(4));
+}
+
+/* 005:
+ * Gives capability information. TODO: This is important!
+ */
+void Engine::numericReply_005(Message &msg)
+{
+ emit incomingConnectString( msg.toString() );
+}
+
+/* 250: ":Highest connection count: <integer> (<integer> clients)
+ * (<integer> since server was (re)started)"
+ * Tells connections statistics about the server for the uptime activity.
+ * NOT IN RFC1459 NOR RFC2812
+ */
+void Engine::numericReply_250(Message &msg)
+{
+ emit incomingConnectString( msg.suffix() );
+}
+
+/* 251: ":There are <integer> users and <integer> services on <integer> servers"
+ * Tells how many user there are on all the different servers in the form of:
+ */
+void Engine::numericReply_251(Message &msg)
+{
+ emit incomingConnectString( msg.suffix() );
+}
+/* 252: "<integer> :operator(s) online"
+ * Issues a number of operators on the server in the form of:
+ */
+void Engine::numericReply_252(Message &msg)
+{
+ emit incomingConnectString( msg.arg(1) + ' ' + msg.suffix() );
+}
+
+/* 253: "<integer> :unknown connection(s)"
+ * Tells how many unknown connections the server has in the form of:
+ */
+void Engine::numericReply_253(Message &msg)
+{
+ emit incomingConnectString( msg.arg(1) + ' ' + msg.suffix() );
+}
+
+/* Tells how many total channels there are on this network in the form of:
+ * "<integer> :channels formed" */
+void Engine::numericReply_254(Message &msg)
+{
+ emit incomingConnectString( msg.arg(1) + ' ' + msg.suffix() );
+}
+
+/* 255: ":I have <integer> clients and <integer> servers"
+ * Tells how many clients and servers *this* server handles.
+ */
+void Engine::numericReply_255(Message &msg)
+{
+ emit incomingConnectString( msg.suffix() );
+}
+
+/* 263:
+ * Server is too busy.
+ */
+void Engine::numericReply_263(Message &)
+{
+ emit incomingServerLoadTooHigh();
+}
+
+/* 265: ":Current local users: <integer> Max: <integer>"
+ * Tells statistics about the current local server state.
+ * NOT IN RFC2812
+ */
+void Engine::numericReply_265(Message &msg)
+{
+ emit incomingConnectString( msg.suffix() );
+}
+
+/* 266: ":Current global users: <integer> Max: <integer>"
+ * Tells statistics about the current global(the whole irc server chain) server state:
+ */
+void Engine::numericReply_266(Message &msg)
+{
+ emit incomingConnectString( msg.suffix() );
+}
+
+/* 301: "<nick> :<away message>"
+ */
+void Engine::numericReply_301(Message &msg)
+{
+ emit incomingUserIsAway(Kopete::Message::unescape(msg.arg(1)), msg.suffix());
+}
+
+/* 303: ":*1<nick> *(" " <nick> )"
+ */
+void Engine::numericReply_303(Message &msg)
+{
+ QStringList nicks = QStringList::split(QRegExp(QChar(' ')), msg.suffix());
+ for(QStringList::Iterator it = nicks.begin(); it != nicks.end(); ++it)
+ {
+ if (!(*it).stripWhiteSpace().isEmpty())
+ emit incomingUserOnline(Kopete::Message::unescape(*it));
+ }
+}
+
+/* 305: ":You are no longer marked as being away"
+ */
+// void Engine::numericReply_305(Message &msg)
+// {
+// }
+
+
+/* 306: ":You have been marked as being away"
+ */
+// void Engine::numericReply_306(Message &msg)
+// {
+// }
+
+/* 307: ":is a registered nick"
+ * DALNET: Indicates that this user is identified with NICSERV.
+ */
+void Engine::numericReply_307(Message & /*msg*/)
+{
+// emit incomingWhoiIsUserNickIsRegistered(Kopete::Message::unescape(msg.arg(1)));
+}
+
+/* 311: "<nick> <user> <host> * :<real name>"
+ * Show info about a user (part of a /whois) in the form of:
+ */
+void Engine::numericReply_311(Message &msg)
+{
+ emit incomingWhoIsUser(Kopete::Message::unescape(msg.arg(1)), msg.arg(2), msg.arg(3), msg.suffix());
+}
+
+/* 312: "<nick> <server> :<server info>"
+ * Show info about a server (part of a /whois).
+ */
+void Engine::numericReply_312(Message &msg)
+{
+ emit incomingWhoIsServer(Kopete::Message::unescape(msg.arg(1)), msg.arg(2), msg.suffix());
+}
+
+/* 313: "<nick> :is an IRC operator"
+ * Show info about an operator (part of a /whois).
+ */
+void Engine::numericReply_313(Message & /*msg*/)
+{
+}
+
+/* 314: "<nick> <user> <host> * :<real name>"
+ * Show WHOWAS Info
+ */
+void Engine::numericReply_314(Message &msg)
+{
+ emit incomingWhoWasUser(Kopete::Message::unescape(msg.arg(1)), msg.arg(2), msg.arg(3), msg.suffix());
+}
+
+void Engine::numericReply_315(Message &msg)
+{
+ emit incomingEndOfWho(Kopete::Message::unescape(msg.arg(1)));
+}
+
+void Engine::numericReply_317(Message &msg)
+{
+ /* RFC say: "<nick> <integer> :seconds idle"
+ * Some servers say: "<nick> <integer> <integer> :seconds idle, signon time"
+ * Show info about someone who is idle (part of a /whois) in the form of:
+ */
+ emit incomingWhoIsIdle(Kopete::Message::unescape(msg.arg(1)), msg.arg(2).toULong());
+ if (msg.argsSize()==4)
+ emit incomingSignOnTime(Kopete::Message::unescape(msg.arg(1)),msg.arg(3).toULong());
+}
+
+/* 318: "<nick>{<space><realname>} :End of /WHOIS list"
+ * End of WHOIS for a given nick.
+ */
+void Engine::numericReply_318(Message &msg)
+{
+ emit incomingEndOfWhois(Kopete::Message::unescape(msg.arg(1)));
+}
+
+void Engine::numericReply_319(Message &msg)
+{
+ /* Show info a channel a user is logged in (part of a /whois) in the form of:
+ * "<nick> :{[@|+]<channel><space>}"
+ */
+ emit incomingWhoIsChannels(Kopete::Message::unescape(msg.arg(1)), msg.suffix());
+}
+
+/* 320:
+ * Indicates that this user is identified with NICSERV on FREENODE.
+ */
+void Engine::numericReply_320(Message &msg)
+{
+ emit incomingWhoIsIdentified(Kopete::Message::unescape(msg.arg(1)));
+}
+
+/* 321: "<channel> :Users Name" ("Channel :Users Name")
+ * RFC1459: Declared.
+ * RFC2812: Obsoleted.
+ */
+
+/* 322: "<channel> <# visible> :<topic>"
+ * Received one channel from the LIST command.
+ */
+void Engine::numericReply_322(Message &msg)
+{
+ //kdDebug(14120) << k_funcinfo << "Listed " << msg.arg(1) << endl;
+
+ emit incomingListedChan(Kopete::Message::unescape(msg.arg(1)), msg.arg(2).toUInt(), msg.suffix());
+}
+
+/* 323: ":End of LIST"
+ * End of the LIST command.
+ */
+void Engine::numericReply_323(Message &)
+{
+ emit incomingEndOfList();
+}
+
+/* 324: "<channel> <mode> <mode params>"
+ */
+void Engine::numericReply_324(Message &msg)
+{
+ emit incomingChannelMode(Kopete::Message::unescape(msg.arg(1)), msg.arg(2), msg.arg(3));
+}
+
+/* 328: "<channel> <mode> <mode params>"
+ */
+void Engine::numericReply_328(Message &msg)
+{
+ kdDebug(14120) << k_funcinfo << endl;
+ emit incomingChannelHomePage(Kopete::Message::unescape(msg.arg(1)), msg.suffix());
+}
+
+/* 329: "%s %lu"
+ * NOTE: What is the meaning of this arguments. DAL-ircd say it's a RPL_CREATIONTIME
+ * NOT IN RFC1459 NOR RFC2812
+ */
+void Engine::numericReply_329( Message &)
+{
+}
+
+/* 331: "<channel> :No topic is set"
+ * Gives the existing topic for a channel after a join.
+ */
+void Engine::numericReply_331( Message &)
+{
+// emit incomingExistingTopic(msg.arg(1), suffix);
+}
+
+/* 332: "<channel> :<topic>"
+ * Gives the existing topic for a channel after a join.
+ */
+void Engine::numericReply_332(Message &msg)
+{
+ emit incomingExistingTopic(Kopete::Message::unescape(msg.arg(1)), msg.suffix());
+}
+
+/* 333:
+ * Gives the nickname and time who changed the topic
+ */
+void Engine::numericReply_333( Message &msg )
+{
+ kdDebug(14120) << k_funcinfo << endl;
+ QDateTime d;
+ d.setTime_t( msg.arg(3).toLong() );
+ emit incomingTopicUser( Kopete::Message::unescape(msg.arg(1)), Kopete::Message::unescape(msg.arg(2)), d );
+}
+
+/* 352:
+ * WHO Reply
+ *
+ * "<channel> <user> <host> <server> <nick> ("H" / "G") ["*"] [("@" / "+")] :<hopcount> <real name>"
+ *
+ * :efnet.cs.hut.fi 352 userNick #foobar username some.host.name efnet.cs.hut.fi someNick H :0 foobar
+ * :efnet.cs.hut.fi 352 userNick #foobar ~fooobar other.hostname irc.dkom.at anotherNick G+ :3 Unknown
+ */
+void Engine::numericReply_352(Message &msg)
+{
+ emit incomingWhoReply(
+ Kopete::Message::unescape(msg.arg(5)), // nick name
+ Kopete::Message::unescape(msg.arg(1)), // channel name
+ msg.arg(2), // user name
+ msg.arg(3), // host name
+ msg.arg(4), // server name
+ msg.arg(6)[0] != 'H', // G=away (true), H=not away (false)
+ msg.arg(7), // @ (op), + (voiced)
+ msg.suffix().section(' ', 0, 1 ).toUInt(), // hopcount
+ msg.suffix().section(' ', 1 ) // real name
+ );
+}
+
+
+/* 353:
+ * NAMES list
+ */
+void Engine::numericReply_353(Message &msg)
+{
+ emit incomingNamesList(Kopete::Message::unescape(msg.arg(2)), QStringList::split(' ', msg.suffix()));
+}
+
+/* 366: "<channel> :End of NAMES list"
+ * Gives a signal to indicate that the NAMES list has ended for channel.
+ */
+void Engine::numericReply_366(Message &msg)
+{
+ emit incomingEndOfNames(msg.arg(1));
+}
+
+/* 369:
+ * End of WHOWAS Request
+ */
+void Engine::numericReply_369(Message & /*msg*/)
+{
+}
+
+/* 372: ":- <text>"
+ * Part of the MOTD.
+ */
+void Engine::numericReply_372(Message &msg)
+{
+ emit incomingMotd(msg.suffix());
+}
+
+/* 375: ":- <server> Message of the day - "
+ * Beginging the motd. This isn't emitted because the MOTD is sent out line by line.
+ */
+
+/* 376: ":End of MOTD command"
+ * End of the motd.
+ */
+
+/* 401: "<nickname> :No such nick/channel"
+ * Gives a signal to indicate that the command issued failed because the person/channel not being on IRC.
+ * - Used to indicate the nickname parameter supplied to a command is currently unused.
+ */
+void Engine::numericReply_401(Message &msg)
+{
+ emit incomingNoSuchNickname( Kopete::Message::unescape(msg.arg(1)) );
+}
+
+/* 406: "<nickname> :There was no such nickname"
+ * Like case 401, but when there *was* no such nickname.
+ */
+void Engine::numericReply_406(Message &msg)
+{
+ emit incomingNoSuchNickname( Kopete::Message::unescape(msg.arg(1)) );
+}
+
+/* 422: ":MOTD File is missing"
+ *
+ * Server's MOTD file could not be opened by the server.
+ */
+void Engine::numericReply_422(Message &msg)
+{
+ emit incomingMotd(msg.suffix());
+}
+
+/* 433: "<nick> :Nickname is already in use"
+ * Tells us that our nickname is already in use.
+ */
+void Engine::numericReply_433(Message &msg)
+{
+ if(m_status == Authentifying)
+ {
+ // This tells us that our nickname is, but we aren't logged in.
+ // This differs because the server won't send us a response back telling us our nick changed
+ // (since we aren't logged in).
+ m_FailedNickOnLogin = true;
+ emit incomingFailedNickOnLogin(Kopete::Message::unescape(msg.arg(1)));
+ }
+ else
+ {
+ // And this is the signal for if someone is trying to use the /nick command or such when already logged in,
+ // but it's already in use
+ emit incomingNickInUse(Kopete::Message::unescape(msg.arg(1)));
+ }
+}
+
+/* 464: ":Password Incorrect"
+ * Bad server password
+ */
+void Engine::numericReply_464(Message &/*msg*/)
+{
+ /* Server need pass.. Call disconnect*/
+ emit incomingFailedServerPassword();
+}
+
+/* 471:
+ * Channel is Full
+ */
+void Engine::numericReply_471(Message &msg)
+{
+ emit incomingFailedChanFull(Kopete::Message::unescape(msg.arg(1)));
+}
+
+/* 473:
+ * Invite Only.
+ */
+void Engine::numericReply_473(Message &msg)
+{
+ emit incomingFailedChanInvite(Kopete::Message::unescape(msg.arg(1)));
+}
+
+/* 474:
+ * Banned.
+ */
+void Engine::numericReply_474(Message &msg)
+{
+ emit incomingFailedChanBanned(Kopete::Message::unescape(msg.arg(1)));
+}
+
+/* 475:
+ * Wrong Chan-key.
+ */
+void Engine::numericReply_475(Message &msg)
+{
+ emit incomingFailedChankey(Kopete::Message::unescape(msg.arg(1)));
+}
+
+/* 477: "<channel> :You need a registered nick to join that channel."
+ * Available on DALNET servers only ?
+ */
+// void Engine::numericReply_477(Message &msg)
+// {
+// emit incomingChannelNeedRegistration(msg.arg(2), msg.suffix());
+// }
diff --git a/kopete/protocols/irc/libkirc/kircentity.cpp b/kopete/protocols/irc/libkirc/kircentity.cpp
new file mode 100644
index 00000000..6aa6fd55
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircentity.cpp
@@ -0,0 +1,132 @@
+/*
+ kircentity.cpp - IRC Client
+
+ Copyright (c) 2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "kircengine.h"
+#include "kircentity.h"
+
+#include <kdebug.h>
+
+using namespace KIRC;
+using namespace KNetwork;
+
+/**
+ * Match a possible user definition:
+ * nick!user@host
+ * where user and host are optionnal.
+ * NOTE: If changes are done to the regexp string, update also the sm_userStrictRegExp regexp string.
+ */
+const QRegExp Entity::sm_userRegExp(QString::fromLatin1("^([^\\s,:!@]+)(?:(?:!([^\\s,:!@]+))?(?:@([^\\s,!@]+)))?$"));
+
+/**
+ * Regexp to match strictly the complete user definition:
+ * nick!user@host
+ * NOTE: If changes are done to the regexp string, update also the sm_userRegExp regexp string.
+ */
+const QRegExp Entity::sm_userStrictRegExp(QString::fromLatin1("^([^\\s,:!@]+)!([^\\s,:!@]+)@([^\\s,:!@]+)$"));
+
+const QRegExp Entity::sm_channelRegExp( QString::fromLatin1("^[#!+&][^\\s,]+$") );
+
+Entity::Entity(const QString &, const Type type)
+ : QObject(0, "KIRC::Entity"),
+ m_type(type)
+{
+// rename(name, type);
+}
+
+Entity::~Entity()
+{
+ emit destroyed(this);
+}
+
+QString Entity::name() const
+{
+ return m_name;
+}
+
+QString Entity::host() const
+{
+ switch(m_type)
+ {
+// case Unknown:
+ case Server:
+ return m_name;
+// case Channel:
+ case Service:
+ case User:
+ return userHost();
+ default:
+ kdDebug(14121) << k_funcinfo << "No host defined for type:" << m_type;
+ return QString::null;
+ }
+}
+
+KIRC::Entity::Type Entity::type() const
+{
+ return m_type;
+}
+
+KIRC::Entity::Type Entity::guessType()
+{
+ m_type = guessType(m_name);
+ return m_type;
+}
+
+// FIXME: Implement me
+KIRC::Entity::Type Entity::guessType(const QString &)
+{
+ return Unknown;
+}
+
+QString Entity::userNick() const
+{
+ return userNick(m_name);
+}
+
+QString Entity::userNick(const QString &s)
+{
+ return userInfo(s, 1);
+}
+
+QString Entity::userName() const
+{
+ return userName(m_name);
+}
+
+QString Entity::userName(const QString &s)
+{
+ return userInfo(s, 2);
+}
+
+QString Entity::userHost() const
+{
+ return userHost(m_name);
+}
+
+QString Entity::userHost(const QString &s)
+{
+ return userInfo(s, 3);
+}
+
+QString Entity::userInfo(const QString &s, int num)
+{
+ QRegExp userRegExp(sm_userRegExp);
+ userRegExp.search(s);
+ return userRegExp.cap(num);
+}
+
+#include "kircentity.moc"
+
diff --git a/kopete/protocols/irc/libkirc/kircentity.h b/kopete/protocols/irc/libkirc/kircentity.h
new file mode 100644
index 00000000..c9336439
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircentity.h
@@ -0,0 +1,128 @@
+/*
+ kircentity.h - IRC Client
+
+ Copyright (c) 2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KIRCENTITY_H
+#define KIRCENTITY_H
+
+#include <kdeversion.h>
+#include <kresolver.h>
+#include <ksharedptr.h>
+
+#include <qobject.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qvaluelist.h>
+
+namespace KIRC
+{
+
+class Engine;
+
+class Entity
+ : public QObject,
+ public KShared
+{
+ Q_OBJECT
+
+public:
+ typedef enum Type
+ {
+ Unknown,
+ Server,
+ Channel,
+ Service,
+ User
+ };
+
+ Entity(const QString &name, const Type type = Unknown);
+ virtual ~Entity();
+
+ QString name() const;
+ QString host() const;
+
+ KIRC::Entity::Type type() const;
+ KIRC::Entity::Type guessType();
+ static KIRC::Entity::Type guessType(const QString &name);
+
+ // FIXME: Remove these is* functions ... They are duplicate with the ::guessType(const QString&)
+ inline static bool isUser( const QString &s )
+ { return sm_userRegExp.exactMatch(s); };
+ inline bool isChannel()
+ { return isChannel(m_name); };
+ inline static bool isChannel( const QString &s )
+ { return sm_channelRegExp.exactMatch(s); };
+
+ QString userNick() const;
+ static QString userNick(const QString &s);
+
+ QString userName() const;
+ static QString userName(const QString &s);
+
+ QString userHost() const;
+ static QString userHost(const QString &s);
+
+signals:
+ void destroyed(KIRC::Entity *self);
+
+private:
+
+ static QString userInfo(const QString &s, int num_cap);
+
+ static const QRegExp sm_userRegExp;
+ static const QRegExp sm_userStrictRegExp;
+ static const QRegExp sm_channelRegExp;
+
+ KIRC::Entity::Type m_type;
+ QString m_name;
+
+ // peer ip address if the entity is a User.
+ QString m_address;
+};
+
+class EntityPtr
+ : public KSharedPtr<KIRC::Entity>
+{
+public:
+ EntityPtr(KIRC::Entity *entity = 0)
+ : KSharedPtr<KIRC::Entity>(entity)
+ { }
+
+ EntityPtr(const KIRC::EntityPtr &entity)
+ : KSharedPtr<KIRC::Entity>(entity)
+ { }
+};
+
+class EntityPtrList
+ : public QValueList<EntityPtr>
+{
+public:
+ EntityPtrList()
+ { }
+
+ EntityPtrList(const EntityPtr &entity)
+ {
+ append(entity);
+ }
+
+ EntityPtrList(const QValueList<EntityPtr> &list)
+ : QValueList<EntityPtr>(list)
+ { }
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/irc/libkirc/kircmessage.cpp b/kopete/protocols/irc/libkirc/kircmessage.cpp
new file mode 100644
index 00000000..f1a5b61f
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircmessage.cpp
@@ -0,0 +1,370 @@
+/*
+ kircmessage.cpp - IRC Client
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003 by the Kopete engineelopers <kopete-engineel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "kircengine.h"
+#include "kircmessage.h"
+
+// FIXME: Remove the following dependencies.
+#include "kopetemessage.h"
+#include "ksparser.h"
+
+#include <kdebug.h>
+#include <kextsock.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+using namespace KIRC;
+
+#ifndef _IRC_STRICTNESS_
+QRegExp Message::m_IRCNumericCommand("^\\d{1,3}$");
+
+// TODO: This regexp parsing is no good. It's slower than it needs to be, and
+// is not codec-safe since QString requires a codec. NEed to parse this with
+// our own parsing class that operates on the raw QCStrings
+QRegExp Message::m_IRCCommandType1(
+ "^(?::([^ ]+) )?([A-Za-z]+|\\d{1,3})((?: [^ :][^ ]*)*) ?(?: :(.*))?$");
+ // Extra end arg space check -------------------------^
+#else // _IRC_STRICTNESS_
+QRegExp Message::m_IRCNumericCommand("^\\d{3,3}$");
+
+QRegExp Message::m_IRCCommandType1(
+ "^(?::([^ ]+) )?([A-Za-z]+|\\d{3,3})((?: [^ :][^ ]*){0,13})(?: :(.*))?$");
+QRegExp Message::m_IRCCommandType2(
+ "^(?::[[^ ]+) )?([A-Za-z]+|\\d{3,3})((?: [^ :][^ ]*){14,14})(?: (.*))?$");
+#endif // _IRC_STRICTNESS_
+
+Message::Message()
+ : m_ctcpMessage(0)
+{
+}
+
+Message::Message(const Message &obj)
+ : m_ctcpMessage(0)
+{
+ m_raw = obj.m_raw;
+
+ m_prefix = obj.m_prefix;
+ m_command = obj.m_command;
+ m_args = obj.m_args;
+ m_suffix = obj.m_suffix;
+
+ m_ctcpRaw = obj.m_ctcpRaw;
+
+ if (obj.m_ctcpMessage)
+ m_ctcpMessage = new Message(obj.m_ctcpMessage);
+}
+
+Message::Message(const Message *obj)
+ : m_ctcpMessage(0)
+{
+ m_raw = obj->m_raw;
+
+ m_prefix = obj->m_prefix;
+ m_command = obj->m_command;
+ m_args = obj->m_args;
+ m_suffix = obj->m_suffix;
+
+ m_ctcpRaw = obj->m_ctcpRaw;
+
+ if (obj->m_ctcpMessage)
+ m_ctcpMessage = new Message(obj->m_ctcpMessage);
+}
+
+Message::~Message()
+{
+ if (m_ctcpMessage)
+ delete m_ctcpMessage;
+}
+
+void Message::writeRawMessage(Engine *engine, const QTextCodec *codec, const QString &str)
+{
+ // FIXME: Really handle this
+ if (!engine->socket())
+ {
+ kdDebug(14121) << k_funcinfo << "Not connected while attempting to write:" << str << endl;
+ return;
+ }
+
+ QString txt = str + QString::fromLatin1("\r\n");
+
+ QCString s(codec->fromUnicode(txt));
+ kdDebug(14120) << "Message is " << s.length() << " chars" << endl;
+ // FIXME: Should check the amount of data really writen.
+ int wrote = engine->socket()->writeBlock(s.data(), s.length());
+
+ kdDebug(14121) << QString::fromLatin1("(%1 bytes) >> %2").arg(wrote).arg(str) << endl;
+}
+
+void Message::writeMessage(Engine *engine, const QTextCodec *codec, const QString &message)
+{
+ writeRawMessage(engine, codec, quote(message));
+}
+
+void Message::writeMessage(Engine *engine, const QTextCodec *codec,
+ const QString &command, const QStringList &args, const QString &suffix)
+{
+ QString msg = command;
+
+ if (!args.isEmpty())
+ msg += QChar(' ') + args.join(QChar(' ')).stripWhiteSpace(); // some extra check should be done here
+
+ if (!suffix.isNull())
+ msg = msg.stripWhiteSpace() + QString::fromLatin1(" :") + suffix;
+
+ writeMessage(engine, codec, msg);
+}
+
+void Message::writeCtcpMessage(Engine *engine, const QTextCodec *codec,
+ const QString &command, const QString&to,
+ const QString &ctcpMessage)
+{
+ writeMessage(engine, codec, command, to, QChar(0x01) + ctcpQuote(ctcpMessage) + QChar(0x01));
+}
+
+void Message::writeCtcpMessage(Engine *engine, const QTextCodec *codec,
+ const QString &command, const QString &to, const QString &suffix,
+ const QString &ctcpCommand, const QStringList &ctcpArgs, const QString &ctcpSuffix )
+{
+ QString ctcpMsg = ctcpCommand;
+
+ if (!ctcpArgs.isEmpty())
+ ctcpMsg += QChar(' ') + ctcpArgs.join(QChar(' ')).stripWhiteSpace(); // some extra check should be done here
+
+ if (!ctcpSuffix.isNull())
+ ctcpMsg += QString::fromLatin1(" :") + ctcpSuffix;
+
+ writeMessage(engine, codec, command, to, suffix + QChar(0x01) + ctcpQuote(ctcpMsg) + QChar(0x01));
+}
+
+Message Message::parse(Engine *engine, const QTextCodec *codec, bool *parseSuccess)
+{
+ if (parseSuccess)
+ *parseSuccess=false;
+
+ if (engine->socket()->canReadLine())
+ {
+ QCString raw(engine->socket()->bytesAvailable()+1);
+ Q_LONG length = engine->socket()->readLine(raw.data(), raw.count());
+
+ if( length > -1 )
+ {
+ raw.resize( length );
+
+ // Remove trailing '\r\n' or '\n'.
+ //
+ // Some servers send '\n' instead of '\r\n' that the RFCs say they should be sending.
+
+ if (length > 1 && raw.at(length-2) == '\n') {
+ raw.at(length-2) = '\0';
+ }
+ if (length > 2 && raw.at(length-3) == '\r') {
+ raw.at(length-3) = '\0';
+ }
+
+ kdDebug(14121) << "<< " << raw << endl;
+
+ Message msg;
+ if(matchForIRCRegExp(raw, codec, msg))
+ {
+ if(parseSuccess)
+ *parseSuccess = true;
+ }
+ else
+ {
+ kdDebug(14120) << k_funcinfo << "Unmatched line: \"" << raw << "\"" << endl;
+ }
+
+ return msg;
+ }
+ else
+ kdWarning(14121) << k_funcinfo << "Failed to read a line while canReadLine returned true!" << endl;
+ }
+
+ return Message();
+}
+
+QString Message::quote(const QString &str)
+{
+ QString tmp = str;
+ QChar q('\020');
+ tmp.replace(q, q+QString(q));
+ tmp.replace(QChar('\r'), q+QString::fromLatin1("r"));
+ tmp.replace(QChar('\n'), q+QString::fromLatin1("n"));
+ tmp.replace(QChar('\0'), q+QString::fromLatin1("0"));
+ return tmp;
+}
+
+// FIXME: The unquote system is buggy.
+QString Message::unquote(const QString &str)
+{
+ QString tmp = str;
+
+ char b[3] = { 020, 020, '\0' };
+ const char b2[2] = { 020, '\0' };
+
+ tmp.replace( b, b2 );
+ b[1] = 'r';
+ tmp.replace( b, "\r");
+ b[1] = 'n';
+ tmp.replace( b, "\n");
+ b[1] = '0';
+ tmp.replace( b, "\0");
+
+ return tmp;
+}
+
+QString Message::ctcpQuote(const QString &str)
+{
+ QString tmp = str;
+ tmp.replace( QChar('\\'), QString::fromLatin1("\\\\"));
+ tmp.replace( (char)1, QString::fromLatin1("\\1"));
+ return tmp;
+}
+
+QString Message::ctcpUnquote(const QString &str)
+{
+ QString tmp = str;
+ tmp.replace("\\\\", "\\");
+ tmp.replace("\\1", "\1" );
+ return tmp;
+}
+
+bool Message::matchForIRCRegExp(const QCString &line, const QTextCodec *codec, Message &message)
+{
+ if(matchForIRCRegExp(m_IRCCommandType1, codec, line, message))
+ return true;
+#ifdef _IRC_STRICTNESS_
+ if(!matchForIRCRegExp(m_IRCCommandType2, codec, line, message))
+ return true;
+#endif // _IRC_STRICTNESS_
+ return false;
+}
+
+// FIXME: remove the decodeStrings calls or update them.
+// FIXME: avoid the recursive call, it make the ctcp command unquoted twice (wich is wrong, but valid in most of the cases)
+bool Message::matchForIRCRegExp(QRegExp &regexp, const QTextCodec *codec, const QCString &line, Message &msg )
+{
+ if( regexp.exactMatch( codec->toUnicode(line) ) )
+ {
+ msg.m_raw = line;
+ msg.m_prefix = unquote(regexp.cap(1));
+ msg.m_command = unquote(regexp.cap(2));
+ msg.m_args = QStringList::split(' ', regexp.cap(3));
+
+ QCString suffix = codec->fromUnicode(unquote(regexp.cap(4)));
+ if (!suffix.isNull() && suffix.length() > 0)
+ {
+ QCString ctcpRaw;
+ if (extractCtcpCommand(suffix, ctcpRaw))
+ {
+ msg.m_ctcpRaw = codec->toUnicode(ctcpRaw);
+
+ msg.m_ctcpMessage = new Message();
+ msg.m_ctcpMessage->m_raw = codec->fromUnicode(ctcpUnquote(msg.m_ctcpRaw));
+
+ int space = ctcpRaw.find(' ');
+ if (!matchForIRCRegExp(msg.m_ctcpMessage->m_raw, codec, *msg.m_ctcpMessage))
+ {
+ QCString command;
+ if (space > 0)
+ command = ctcpRaw.mid(0, space).upper();
+ else
+ command = ctcpRaw.upper();
+ msg.m_ctcpMessage->m_command =
+ Kopete::Message::decodeString( KSParser::parse(command), codec );
+ }
+
+ if (space > 0)
+ msg.m_ctcpMessage->m_ctcpRaw =
+ Kopete::Message::decodeString( KSParser::parse(ctcpRaw.mid(space)), codec );
+ }
+
+ msg.m_suffix = Kopete::Message::decodeString( KSParser::parse(suffix), codec );
+ }
+ else
+ msg.m_suffix = QString::null;
+ return true;
+ }
+ return false;
+}
+
+void Message::decodeAgain( const QTextCodec *codec )
+{
+ matchForIRCRegExp(m_raw, codec, *this);
+}
+
+// FIXME: there are missing parts
+QString Message::toString() const
+{
+ if( !isValid() )
+ return QString::null;
+
+ QString msg = m_command;
+ for (QStringList::ConstIterator it = m_args.begin(); it != m_args.end(); ++it)
+ msg += QChar(' ') + *it;
+ if (!m_suffix.isNull())
+ msg += QString::fromLatin1(" :") + m_suffix;
+
+ return msg;
+}
+
+bool Message::isNumeric() const
+{
+ return m_IRCNumericCommand.exactMatch(m_command);
+}
+
+bool Message::isValid() const
+{
+// This could/should be more complex but the message validity is tested durring the parsing
+// So this is enougth as we don't allow the editing the content.
+ return !m_command.isEmpty();
+}
+
+/* Return true if the given string is a special command string
+ * (i.e start and finish with the ascii code \001), and the given
+ * string is splited to get the first part of the message and fill the ctcp command.
+ * FIXME: The code currently only match for a textual message or a ctcp message not both mixed as it can be (even if very rare).
+ */
+bool Message::extractCtcpCommand(QCString &message, QCString &ctcpline)
+{
+ uint len = message.length();
+
+ if( message[0] == 1 && message[len-1] == 1 )
+ {
+ ctcpline = message.mid(1,len-2);
+ message.truncate(0);
+
+ return true;
+ }
+
+ return false;
+}
+
+void Message::dump() const
+{
+ kdDebug(14120) << "Raw:" << m_raw << endl
+ << "Prefix:" << m_prefix << endl
+ << "Command:" << m_command << endl
+ << "Args:" << m_args << endl
+ << "Suffix:" << m_suffix << endl
+ << "CtcpRaw:" << m_ctcpRaw << endl;
+ if(m_ctcpMessage)
+ {
+ kdDebug(14120) << "Contains CTCP Message:" << endl;
+ m_ctcpMessage->dump();
+ }
+}
diff --git a/kopete/protocols/irc/libkirc/kircmessage.h b/kopete/protocols/irc/libkirc/kircmessage.h
new file mode 100644
index 00000000..e37f3fb2
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircmessage.h
@@ -0,0 +1,198 @@
+/*
+ kircmessage.h - IRC Client
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KIRCMESSAGE_H
+#define KIRCMESSAGE_H
+
+#include "kircentity.h"
+
+#include <kbufferedio.h>
+
+#include <qdict.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextcodec.h>
+#include <qregexp.h>
+
+#include <kopetemessage.h>
+
+// Uncoment this if you want a really rfc compliant message handling.
+// This is due to some changes of the message encoding with 14 arguments.(not very frequent :)
+// #define _IRC_STRICTNESS_
+
+namespace KIRC
+{
+
+class Engine;
+
+class Message
+{
+public:
+ /** \brief Sends the message as-is to the server.
+ */
+ static void writeRawMessage(KIRC::Engine *engine, const QTextCodec *codec, const QString &str);
+
+ static void writeMessage(KIRC::Engine *engine, const QTextCodec *codec, const QString &str);
+
+ static void writeMessage(KIRC::Engine *engine, const QTextCodec *codec,
+ const QString &command, const QStringList &args, const QString &suffix);
+
+ static void writeCtcpMessage(KIRC::Engine *engine, const QTextCodec *codec,
+ const QString &command, const QString &to,
+ const QString &ctcpMessage);
+
+ static void writeCtcpMessage(KIRC::Engine *engine, const QTextCodec *codec,
+ const QString &command, const QString &to, const QString &suffix,
+ const QString &ctcpCommand, const QStringList &ctcpArgs = QStringList(), const QString &ctcpSuffix = QString::null );
+
+ Message();
+ Message(const KIRC::Message &obj);
+ Message(const KIRC::Message *obj);
+
+ ~Message();
+
+ inline const QString nickFromPrefix() const
+ { return Kopete::Message::unescape(KIRC::Entity::userNick(m_prefix)); }
+
+ QString toString() const;
+
+ /** \brief Returns true if the message command is numeric.
+ */
+ bool isNumeric() const;
+
+ /** \brief Message is valid if it was parsed correctly.
+ */
+ bool isValid() const;
+
+ /** \brief Writes internal message information about this message through kdDebug().
+ */
+ void dump() const;
+
+ /** \brief Re-decodes the message with given codec.
+ */
+ void decodeAgain( const QTextCodec *codec );
+
+ /** \brief The whole message as received.
+ */
+ inline const QCString &raw() const
+ { return m_raw; }
+
+ /** \brief Prefix of this message.
+ *
+ * Returns the prefix of the message. Note that it can be empty.
+ *
+ * Prefix is the server name or the nick name of the sender.
+ *
+ * message = [ ":" prefix SPACE ] command [ params ] crlf
+ * prefix = servername / ( nickname [ [ "!" user ] "@" host ] )
+ */
+ inline const QString &prefix() const
+ { return m_prefix; }
+
+ /** \brief The command part of this message.
+ *
+ * Returns the command of this message. Can be numerical.
+ *
+ * Examples: "MODE", "PRIVMSG", 303, 001, ...
+ */
+ inline const QString &command() const
+ { return m_command; }
+
+ /** \brief The number of command arguments this message contains.
+ */
+ inline size_t argsSize() const
+ { return m_args.size(); }
+
+ /** \brief i:th command argument.
+ */
+ inline const QString &arg(size_t i) const
+ { return m_args[i]; }
+
+ /** \brief All command arguments.
+ */
+ inline const QStringList &args() const
+ { return m_args; }
+
+ /** \brief Message suffix.
+ */
+ inline const QString &suffix() const
+ { return m_suffix; }
+ inline const QString &ctcpRaw() const
+ { return m_ctcpRaw; }
+
+ inline bool hasCtcpMessage() const
+ { return m_ctcpMessage!=0; }
+ inline class KIRC::Message &ctcpMessage() const
+ { return *m_ctcpMessage; }
+
+ static KIRC::Message parse(KIRC::Engine *engine, const QTextCodec *codec, bool *parseSuccess=0);
+
+private:
+ /**
+ * Contains the low level dequoted message.
+ */
+ QCString m_raw;
+
+ /**
+ * Contains the completely dequoted prefix.
+ */
+ QString m_prefix;
+ /**
+ * Contains the completely dequoted command.
+ */
+ QString m_command;
+ /**
+ * Contains the completely dequoted args.
+ */
+ QStringList m_args;
+ /**
+ * Contains the completely dequoted suffix.
+ */
+ QString m_suffix;
+
+ /**
+ * If it is a message contains the completely dequoted rawCtcpLine.
+ * If it is a ctcp message contains the completely dequoted rawCtcpArgsLine.
+ */
+ QString m_ctcpRaw;
+
+ // low level quoting, message quoting
+ static QString quote(const QString &str);
+ static QString unquote(const QString &str);
+
+ // ctcp level quoting
+ static QString ctcpQuote(const QString &str);
+ static QString ctcpUnquote(const QString &str);
+
+ static bool extractCtcpCommand(QCString &str, QCString &ctcpline);
+
+ static bool matchForIRCRegExp(const QCString &line, const QTextCodec *codec, KIRC::Message &message);
+ static bool matchForIRCRegExp(QRegExp &regexp, const QTextCodec *codec, const QCString &line, KIRC::Message &message);
+
+ class KIRC::Message *m_ctcpMessage;
+
+ static QRegExp m_IRCCommandType1;
+ #ifdef _IRC_STRICTNESS_
+ static QRegExp m_IRCCommandType2;
+ #endif // _IRC_STRICTNESS_
+
+ static QRegExp m_IRCNumericCommand;
+};
+
+}
+
+#endif // KIRCMESSAGE_H
diff --git a/kopete/protocols/irc/libkirc/kircmessageredirector.cpp b/kopete/protocols/irc/libkirc/kircmessageredirector.cpp
new file mode 100644
index 00000000..49194ce0
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircmessageredirector.cpp
@@ -0,0 +1,97 @@
+/*
+ kircmessageredirector.cpp - IRC Client
+
+ Copyright (c) 2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "kircengine.h"
+#include "kircmessage.h"
+#include "kircmessageredirector.h"
+
+using namespace KIRC;
+
+MessageRedirector::MessageRedirector(KIRC::Engine *engine,
+ int argsSize_min, int argsSize_max, const QString &helpMessage)
+ : QObject(engine, "KIRC::MessageRedirector"),
+ m_argsSize_min(argsSize_min),
+ m_argsSize_max(argsSize_max),
+ m_helpMessage(helpMessage)
+{
+}
+
+bool MessageRedirector::connect(QObject *object, const char *member)
+{
+ return QObject::connect(this, SIGNAL(redirect(KIRC::Message &)),
+ object, member);
+}
+
+QStringList MessageRedirector::operator () (Message &msg)
+{
+ m_errors.clear();
+
+// if (m_connectedObjects == 0)
+// m_errors.append(i18n("Internal error: no more connected object, triggered by:")+msg);
+
+ if (checkValidity(msg))
+ emit redirect(msg);
+
+ return m_errors;
+}
+
+QString MessageRedirector::helpMessage()
+{
+ return m_helpMessage;
+}
+
+void MessageRedirector::error(QString &message)
+{
+ m_errors.append(message);
+}
+
+bool MessageRedirector::checkValidity(const Message &msg)
+{
+ bool success = true;
+ int argsSize = msg.argsSize();
+
+ if (m_argsSize_min >= 0 && argsSize < m_argsSize_min)
+ {
+// m_errors.append(i18n("Not enougth arguments in message:")+msg);
+ success = false;
+ }
+
+#ifdef _IRC_STRICTNESS_
+ if (m_argsSize_max >= 0 && argsSize > m_argsSize_max)
+ {
+// m_errors.append(i18n("Too many arguments in message:")+msg);
+ success = false;
+ }
+#endif
+/*
+ if ( msg.isNumeric() &&
+ ( msg.argsSize() > 0 && (
+ msg.arg(0) == m_Nickname ||
+ msg.arg(0) == m_PendingNick ||
+ msg.arg(0) == QString::fromLatin1("*")
+ )
+ )
+ )
+ {
+// m_errors.append(i18n("Too many arguments in message:")+msg);
+ success = false;
+ }
+*/
+ return success;
+}
+
+#include "kircmessageredirector.moc"
diff --git a/kopete/protocols/irc/libkirc/kircmessageredirector.h b/kopete/protocols/irc/libkirc/kircmessageredirector.h
new file mode 100644
index 00000000..f87a2af6
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kircmessageredirector.h
@@ -0,0 +1,86 @@
+/*
+ kircmessageredirector.h - IRC Client
+
+ Copyright (c) 2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KIRC_MESSAGEREDIRECTOR_H
+#define KIRC_MESSAGEREDIRECTOR_H
+
+#include <qobject.h>
+#include <qstring.h>
+
+namespace KIRC
+{
+
+class Engine;
+
+class Message;
+
+class MessageRedirector
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum {
+ Unknown = -1,
+ Unlimited = -2
+ };
+
+ MessageRedirector(KIRC::Engine *engine,
+ int argsSize_min = KIRC::MessageRedirector::Unknown,
+ int argsSize_max = KIRC::MessageRedirector::Unknown,
+ const QString &helpMessage = QString::null);
+
+ /**
+ * Connects the given object member signal/slot to this message redirector.
+ * The member signal slot should be looking like:
+ * SIGNAL(mysignal(KIRC::Message &msg))
+ * or
+ * SIGNAL(myslot(KIRC::Message &msg))
+ */
+ bool connect(QObject *object, const char *member);
+
+ /**
+ * Attempt to send the message.
+ * @return a not empty QStringList on errors or no slots connected.
+ * The returned string list contains all the errors.
+ */
+ QStringList operator()(KIRC::Message &msg);
+
+ void error(QString &errorMessage);
+
+ QString helpMessage();
+
+signals:
+ void redirect(KIRC::Message &);
+
+private:
+ /**
+ * Check that the given message as the correct number of args
+ * and do some message format checks.
+ */
+ bool checkValidity(const KIRC::Message &msg);
+
+ QStringList m_errors;
+
+ int m_argsSize_min;
+ int m_argsSize_max;
+ QString m_helpMessage;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/irc/libkirc/kirctransfer.cpp b/kopete/protocols/irc/libkirc/kirctransfer.cpp
new file mode 100644
index 00000000..2466d6a9
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kirctransfer.cpp
@@ -0,0 +1,365 @@
+/*
+ kirctransfer.cpp - IRC transfer.
+
+ Copyright (c) 2003-2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003-2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <kdebug.h>
+#include <kextsock.h>
+#include <klocale.h>
+
+#include <qfile.h>
+#include <qtimer.h>
+
+#include "kirctransfer.h"
+
+using namespace KIRC;
+
+Transfer::Transfer( Engine *engine, QString nick,// QString nick_peer_adress
+ Type type,
+ QObject *parent, const char *name )
+ : QObject( parent, name ),
+ m_engine(engine), m_nick(nick),
+ m_type(type), m_socket(0),
+ m_initiated(false),
+ m_file(0), m_fileName(QString::null), m_fileSize(0), m_fileSizeCur(0), m_fileSizeAck(0),
+ m_receivedBytes(0), m_receivedBytesLimit(0), m_sentBytes(0), m_sentBytesLimit(0)
+{
+}
+
+Transfer::Transfer( Engine *engine, QString nick,// QString nick_peer_adress
+ Transfer::Type type,
+ QString fileName, Q_UINT32 fileSize, // put this in a QVariant ?
+ QObject *parent, const char *name )
+ : QObject( parent, name ),
+ m_engine(engine), m_nick(nick),
+ m_type(type), m_socket(0),
+ m_initiated(false),
+ m_file(0), m_fileName(fileName), m_fileSize(fileSize), m_fileSizeCur(0), m_fileSizeAck(0),
+ m_receivedBytes(0), m_receivedBytesLimit(0), m_sentBytes(0), m_sentBytesLimit(0)
+{
+}
+
+Transfer::Transfer( Engine *engine, QString nick,// QString nick_peer_adress
+ QHostAddress hostAdress, Q_UINT16 port, // put this in a QVariant ?
+ Transfer::Type type,
+ QString fileName, Q_UINT32 fileSize, // put this in a QVariant ?
+ QObject *parent, const char *name )
+ : QObject( parent, name ),
+ m_engine(engine), m_nick(nick),
+ m_type(type), m_socket(0),
+ m_initiated(false),
+ m_file(0), m_fileName(fileName), m_fileSize(fileSize), m_fileSizeCur(0), m_fileSizeAck(0),
+ m_receivedBytes(0), m_receivedBytesLimit(0), m_sentBytes(0), m_sentBytesLimit(0)
+{
+ setSocket(new KExtendedSocket(hostAdress.toString(), port));
+}
+/*
+Transfer::Transfer( Engine *engine, QString nick,// QString nick_peer_adress
+ Transfer::Type type, QVariant properties,
+ QObject *parent, const char *name )
+ : QObject( parent, name ),
+ m_engine(engine), m_nick(nick),
+ m_type(type), m_socket(properties[socket]),
+ m_initiated(false),
+ m_file(0), m_fileName(properties[fileName]), m_fileSize(properties[fileSize]), m_fileSizeCur(0), m_fileSizeAck(0),
+ m_receivedBytes(0), m_receivedBytesLimit(0), m_sentBytes(0), m_sentBytesLimit(0)
+{
+ if(!properites["socket"].isNull())
+ setSocket(properites["socket"]);
+ else if(!properites["hostAddress"].isNull() && !properites["hostPort"].isNull())
+ setSocket(new KExtendedSocket(properites["hostAddress"], properites["hostPort"]));
+
+ connect(this, SIGNAL(complete()),
+ this, SLOT(closeSocket()));
+
+ connect(this, SIGNAL(abort(QString)),
+ this, SLOT(closeSocket()));
+}
+*/
+Transfer::~Transfer()
+{
+ closeSocket();
+ // m_file is automatically closed on destroy.
+}
+
+Transfer::Status Transfer::status() const
+{
+ if(m_socket)
+ {
+// return (Transfer::Status)m_socket->socketStatus();
+ return Connected;
+ }
+ return Error_NoSocket;
+}
+
+void Transfer::slotError( int error )
+{
+ // Connection in progress.. This is a signal fired wrong
+ if (m_socket->socketStatus () != KExtendedSocket::connecting)
+ {
+ abort(KExtendedSocket::strError(m_socket->status(), m_socket->systemError()));
+// closeSocket();
+ }
+}
+
+bool Transfer::initiate()
+{
+ QTimer *timer = 0;
+
+ if(m_initiated)
+ {
+ kdDebug(14121) << k_funcinfo << "Transfer allready initiated" << endl;
+ return false;
+ }
+
+ if(!m_socket)
+ {
+ kdDebug(14121) << k_funcinfo << "Socket not set" << endl;
+ return false;
+ }
+
+ m_initiated = true;
+
+ m_file.setName(m_fileName);
+
+ connect(this, SIGNAL(complete()),
+ this, SLOT(closeSocket()));
+ connect(this, SIGNAL(abort(QString)),
+ this, SLOT(closeSocket()));
+
+// connect(m_socket, SIGNAL(connectionClosed()),
+// this, SLOT(slotConnectionClosed()));
+// connect(m_socket, SIGNAL(delayedCloseFinished()),
+// this, SLOT(slotConnectionClosed()));
+ connect(m_socket, SIGNAL(error(int)), // FIXME: connection failed: No such signal KExtendedSocket::error(int)
+ this, SLOT(slotError(int)));
+
+ switch( m_type )
+ {
+ case Chat:
+ kdDebug(14121) << k_funcinfo << "Stting up a chat." << endl;
+ connect(m_socket, SIGNAL(readyRead()),
+ this, SLOT(readyReadFileIncoming()));
+ break;
+ case FileIncoming:
+ kdDebug(14121) << k_funcinfo << "Stting up an incoming file transfer." << endl;
+ m_file.open(IO_WriteOnly);
+ connect(m_socket, SIGNAL(readyRead()),
+ this, SLOT(readyReadFileIncoming()));
+ break;
+ case FileOutgoing:
+ kdDebug(14121) << k_funcinfo << "Stting up an outgoing file transfer." << endl;
+ m_file.open(IO_ReadOnly);
+ connect(m_socket, SIGNAL(readyRead()),
+ this, SLOT(readyReadFileOutgoing()));
+// timer = new QTimer(this);
+// connect(timer, SIGNAL(timeout()),
+// this, SLOT(writeFileOutgoing()));
+// timer->start(1000, false);
+ writeFileOutgoing(); // send a first packet.
+ break;
+ default:
+ kdDebug(14121) << k_funcinfo << "Closing transfer: Unknown extra initiation for type:" << m_type << endl;
+ m_socket->close();
+ return false;
+ break;
+ }
+
+// if(status()==Idle)
+ if(m_socket->status()==KExtendedSocket::nothing)
+ m_socket->connect();
+
+ m_socket->enableRead(true);
+ m_socket->enableWrite(true);
+
+ m_socketDataStream.setDevice(m_socket);
+
+ // I wonder if calling this is really necessary
+ // As far as I understand, buffer (socket buffer at least) should be flushed while event-looping.
+ // But I'm not really sure of this, so I force the flush.
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()),
+ this, SLOT(flush()));
+ timer->start(1000, FALSE); // flush the streams at every seconds
+
+ return true;
+}
+
+bool Transfer::setSocket( KExtendedSocket *socket )
+{
+ if (!m_socket)
+ {
+ m_socket = socket;
+ return true;
+ }
+ else
+ kdDebug(14121) << k_funcinfo << "Socket allready set" << endl;
+ return false;
+}
+
+void Transfer::closeSocket()
+{
+ if(m_socket)
+ {
+ m_socket->close();
+// m_socket->reset();
+ m_socket->deleteLater();
+ }
+ m_socket = 0;
+}
+
+/*
+ * This slot ensure that all the stream are flushed.
+ * This slot is called periodically internaly.
+ */
+ void Transfer::flush()
+{
+ /*
+ * Enure the incoming file content in case of a crash.
+ */
+ if(m_file.isOpen() && m_file.isWritable())
+ m_file.flush();
+
+ /*
+ * Ensure that non interactive streams outputs (i.e file transfer acknowledge by example)
+ * are sent (Don't stay in a local buffer).
+ */
+ if(m_socket && status() == Connected)
+ m_socket->flush();
+}
+
+void Transfer::userAbort(QString msg)
+{
+ emit abort(msg);
+}
+
+void Transfer::setCodec( QTextCodec *codec )
+{
+ switch( m_type )
+ {
+ case Chat:
+ m_socket_textStream.setCodec( codec );
+ break;
+ default:
+// operation not permitted on this type.
+ break;
+ }
+}
+
+void Transfer::writeLine( const QString &line )
+{
+ switch( m_type )
+ {
+ case Chat:
+// m_socket.flush();
+ break;
+ default:
+// operation not permitted on this type.
+ break;
+ }
+}
+
+void Transfer::readyReadLine()
+{
+ if( m_socket->canReadLine() )
+ {
+ QString msg = m_socket_textStream.readLine();
+ emit readLine(msg);
+ }
+}
+
+void Transfer::readyReadFileIncoming()
+{
+ kdDebug(14121) << k_funcinfo << endl;
+
+ m_bufferLength = m_socket->readBlock(m_buffer, sizeof(m_buffer));
+
+ if(m_bufferLength > 0)
+ {
+ int written = m_file.writeBlock(m_buffer, m_bufferLength);
+ if(m_bufferLength == written)
+ {
+ m_fileSizeCur += written;
+ m_fileSizeAck = m_fileSizeCur;
+ m_socketDataStream << m_fileSizeAck;
+ checkFileTransferEnd(m_fileSizeAck);
+ return;
+ }
+ else
+ // Something bad happened while writting.
+ abort(m_file.errorString());
+ }
+ else if(m_bufferLength == -1)
+ abort("Error while reading socket.");
+}
+
+void Transfer::readyReadFileOutgoing()
+{
+ kdDebug(14121) << k_funcinfo << "Available bytes:" << m_socket->bytesAvailable() << endl;
+
+ bool hadData = false;
+ Q_UINT32 fileSizeAck = 0;
+
+// if (m_socket->bytesAvailable() >= sizeof(fileSizeAck)) // BUGGY: bytesAvailable() that allways return 0 on unbuffered sockets.
+ {
+ m_socketDataStream >> fileSizeAck;
+ hadData = true;
+ }
+
+ if (hadData)
+ {
+ checkFileTransferEnd(fileSizeAck);
+ writeFileOutgoing();
+ }
+}
+
+void Transfer::writeFileOutgoing()
+{
+ kdDebug(14121) << k_funcinfo << endl;
+
+ if (m_fileSizeAck < m_fileSize)
+ {
+ m_bufferLength = m_file.readBlock(m_buffer, sizeof(m_buffer));
+ if (m_bufferLength > 0)
+ {
+ Q_UINT32 read = m_socket->writeBlock(m_buffer, m_bufferLength); // should check written == read
+
+// if(read != m_buffer_length)
+// buffer is not cleared still
+
+ m_fileSizeCur += read;
+// m_socket->flush(); // Should think on using this
+ emit fileSizeCurrent( m_fileSizeCur );
+ }
+ else if(m_bufferLength == -1)
+ abort("Error while reading file.");
+ }
+}
+
+void Transfer::checkFileTransferEnd(Q_UINT32 fileSizeAck)
+{
+ kdDebug(14121) << k_funcinfo << "Acknowledged:" << fileSizeAck << endl;
+
+ m_fileSizeAck = fileSizeAck;
+ emit fileSizeAcknowledge(m_fileSizeAck);
+
+ if(m_fileSizeAck > m_fileSize)
+ abort(i18n("Acknowledge size is greater than the expected file size"));
+
+ if(m_fileSizeAck == m_fileSize)
+ emit complete();
+}
+
+#include "kirctransfer.moc"
diff --git a/kopete/protocols/irc/libkirc/kirctransfer.h b/kopete/protocols/irc/libkirc/kirctransfer.h
new file mode 100644
index 00000000..3453f5cb
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kirctransfer.h
@@ -0,0 +1,191 @@
+/*
+ kirctransfer.h - DCC Handler
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KIRCTRANSFER_H
+#define KIRCTRANSFER_H
+
+#include <qdatastream.h>
+#include <qfile.h>
+#include <qhostaddress.h>
+#include <qobject.h>
+#include <qtextstream.h>
+
+class KExtendedSocket;
+
+class QFile;
+class QTextCodec;
+
+namespace KIRC
+{
+class Engine;
+
+class Transfer
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Type {
+ Unknown,
+ Chat,
+ FileOutgoing,
+ FileIncoming
+ };
+
+ enum Status {
+ Error_NoSocket = -2,
+ Error = -1,
+ Idle = 0,
+ HostLookup,
+ Connecting,
+ Connected,
+ Closed
+ };
+public:
+ Transfer( KIRC::Engine *engine, QString nick,// QString nick_peer_adress
+ Type type = Unknown,
+ QObject *parent = 0L, const char *name = 0L );
+
+ Transfer( KIRC::Engine *engine, QString nick,// QString nick_peer_adress,
+ QHostAddress peer_address, Q_UINT16 peer_port,
+ Transfer::Type type,
+ QObject *parent = 0L, const char *name = 0L );
+
+ Transfer( KIRC::Engine *engine, QString nick,// QString nick_peer_adress,
+ Transfer::Type type,
+ QString fileName, Q_UINT32 fileSize,
+ QObject *parent = 0L, const char *name = 0L );
+
+ Transfer( KIRC::Engine *engine, QString nick,// QString nick_peer_adress,
+ QHostAddress peer_address, Q_UINT16 peer_port,
+ Transfer::Type type,
+ QString fileName, Q_UINT32 fileSize,
+ QObject *parent = 0L, const char *name = 0L );
+/*
+ For a file transfer properties are:
+
+ KExntendedSocket *socket
+ or
+ QHostAddress peerAddress
+ Q_UINT16 peerPort
+ for determining the socket.
+
+ QString fileName
+ Q_UINT32 fileSize
+ for detemining the file propeties.
+*//*
+ Transfer( KIRC *engine, QString nick,// QString nick_peer_adress,
+ Transfer::Type type, QVariant properties,
+ QObject *parent = 0L, const char *name = 0L );
+*/
+ ~Transfer();
+
+ KIRC::Engine *engine() const
+ { return m_engine; }
+ QString nick() const
+ { return m_nick; }
+ Type type() const
+ { return m_type; }
+ Status status() const;
+
+ /* Start the transfer.
+ * If not connected connect to client.
+ * Allow receiving/emitting data.
+ */
+ bool initiate();
+
+ QString fileName() const
+ { return m_fileName; }
+ /* Change the file name.
+ */
+ void setFileName(QString fileName)
+ { m_fileName = fileName; }
+ unsigned long fileSize() const
+ { return m_fileSize; }
+public slots:
+ bool setSocket( KExtendedSocket *socket );
+ void closeSocket();
+
+ void setCodec( QTextCodec *codec );
+ void writeLine( const QString &msg );
+
+ void flush();
+
+ void userAbort(QString);
+
+signals:
+ void readLine( const QString &msg );
+
+ void fileSizeCurrent( unsigned int );
+ void fileSizeAcknowledge( unsigned int );
+
+// void received(Q_UINT32);
+// void sent(Q_UINT32);
+
+ void abort(QString);
+
+ /* Emited when the transfer is complete.
+ * Usually it means that the file transfer has successfully finished.
+ */
+ void complete();
+
+protected slots:
+ void slotError(int);
+
+ void readyReadLine();
+
+ void readyReadFileIncoming();
+
+ void writeFileOutgoing();
+ void readyReadFileOutgoing();
+
+protected:
+// void emitSignals();
+ void checkFileTransferEnd( Q_UINT32 fileSizeAck );
+
+ KIRC::Engine * m_engine;
+ QString m_nick;
+
+ Type m_type;
+ KExtendedSocket *m_socket;
+ bool m_initiated;
+
+ // Text member data
+ QTextStream m_socket_textStream;
+// QTextCodec * m_socket_codec;
+
+ // File member data
+ QFile m_file;
+ QString m_fileName;
+ Q_UINT32 m_fileSize;
+ Q_UINT32 /*usize_t*/ m_fileSizeCur;
+ Q_UINT32 /*usize_t*/ m_fileSizeAck;
+ QDataStream m_socketDataStream;
+ char m_buffer[1024];
+ int m_bufferLength;
+
+ // Data transfer measures
+ Q_UINT32 m_receivedBytes;
+ Q_UINT32 m_receivedBytesLimit;
+
+ Q_UINT32 m_sentBytes;
+ Q_UINT32 m_sentBytesLimit;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/irc/libkirc/kirctransferhandler.cpp b/kopete/protocols/irc/libkirc/kirctransferhandler.cpp
new file mode 100644
index 00000000..3fa73dff
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kirctransferhandler.cpp
@@ -0,0 +1,97 @@
+/*
+ kirctransferhandler.cpp - DCC Handler
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kextsock.h>
+
+#include <qfile.h>
+#include <qregexp.h>
+#include <qtextcodec.h>
+
+#include "kirctransferserver.h"
+
+#include "kirctransferhandler.h"
+
+using namespace KIRC;
+
+TransferHandler *TransferHandler::self()
+{
+ static TransferHandler sm_self;
+ return &sm_self;
+}
+
+TransferServer *TransferHandler::server()
+{
+ if( m_server )
+// server( m_default_server_port, m_default_server_backlog );
+ server( 0, 1 );
+ return m_server;
+}
+
+TransferServer *TransferHandler::server( Q_UINT16 port, int backlog )
+{
+// if( m_server )
+// m_server->terminate();
+ TransferServer *m_server = new TransferServer( port, backlog, this );
+
+ // here connect the slots of the server
+
+ return m_server;
+}
+
+TransferServer *TransferHandler::createServer(Engine *engine, QString m_userName,
+ Transfer::Type type,
+ QString fileName, Q_UINT32 fileSize)
+{
+ TransferServer *server = new TransferServer(engine, m_userName, type, fileName, fileSize, this);
+ transferServerCreated(server);
+ return server;
+}
+
+Transfer *TransferHandler::createClient(
+ Engine *engine, QString nick,// QString nick_peer_adress,
+ QHostAddress peer_address, Q_UINT16 peer_port,
+ Transfer::Type type,
+ QString fileName, Q_UINT32 fileSize )
+{
+ Transfer *client = new Transfer(
+ engine, nick,// QString nick_peer_adress,
+ peer_address, peer_port,
+ type,
+ fileName, fileSize,
+ this );
+ transferCreated(client);
+ return client;
+}
+
+/*
+File *DCCHandler::openFile( QString file, int mode = IO_ReadWrite )
+{
+ QFile *file = new QFile(filename);
+ if (!file->open(mode))
+ {
+ delete file;
+ file = 0L;
+ }
+ return file;
+}
+*/
+
+#include "kirctransferhandler.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
diff --git a/kopete/protocols/irc/libkirc/kirctransferhandler.h b/kopete/protocols/irc/libkirc/kirctransferhandler.h
new file mode 100644
index 00000000..81774c02
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kirctransferhandler.h
@@ -0,0 +1,79 @@
+/*
+ kirctransferhandler.h - DCC Handler
+
+ Copyright (c) 2003-2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003-2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KIRCTRANSFERHANDLER_H
+#define KIRCTRANSFERHANDLER_H
+
+#include <qhostaddress.h>
+
+#include "kirctransfer.h"
+#include "kirctransferserver.h"
+
+class QFile;
+class QTextCodec;
+
+class KExtendedSocket;
+
+namespace KIRC
+{
+
+class TransferHandler
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+ static TransferHandler *self();
+
+ TransferServer *server();
+ TransferServer *server( Q_UINT16 port, int backlog = 1 );
+
+ TransferServer *createServer(KIRC::Engine *engine, QString m_userName,
+ Transfer::Type type,
+ QString fileName, Q_UINT32 fileSize);
+
+ Transfer *createClient(
+ KIRC::Engine *engine, QString nick,// QString nick_peer_adress,
+ QHostAddress peer_address, Q_UINT16 peer_port,
+ Transfer::Type type,
+ QString file = QString::null, Q_UINT32 fileSize = 0 );
+
+// void registerServer( DCCServer * );
+// QPtrList<DCCServer> getRegisteredServers();
+// static QPtrList<DCCServer> getAllRegisteredServers();
+// void unregisterServer( DCCServer * );
+
+// void registerClient( DCCClient * );
+// QPtrList<DCCClient> getRegisteredClients();
+// static QPtrList<DCCClient> getAllRegisteredClients();
+// void unregisterClient( DCCClient * );
+
+signals:
+ void transferServerCreated(KIRC::TransferServer *server);
+ void transferCreated(KIRC::Transfer *transfer);
+
+private:
+// TransferHandler();
+
+ TransferServer *m_server;
+// QPtrList<TransferServer> m_servers;
+// QPtrList<Transfer> m_clients;
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/irc/libkirc/kirctransferserver.cpp b/kopete/protocols/irc/libkirc/kirctransferserver.cpp
new file mode 100644
index 00000000..96cc66fb
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kirctransferserver.cpp
@@ -0,0 +1,154 @@
+/*
+ kirctransfer.cpp - IRC transfer.
+
+ Copyright (c) 2003 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <kdebug.h>
+#include <kextsock.h>
+
+#include "kirctransferhandler.h"
+
+#include "kirctransferserver.h"
+
+using namespace KIRC;
+
+/*
+TransferServer::TransferServer( QObject *parent, const char *name )
+ : QObject( parent, name ),
+ m_socket( 0 ),
+ m_port( 0 ),
+ m_backlog( 1 )
+{
+}
+*/
+TransferServer::TransferServer(Q_UINT16 port, int backlog, QObject *parent, const char *name)
+ : QObject( parent, name ),
+ m_socket( 0 ),
+ m_port( port ),
+ m_backlog( backlog )
+{
+}
+
+TransferServer::TransferServer(Engine *engine, QString nick,// QString nick_peer_adress,
+ Transfer::Type type,
+ QString fileName, Q_UINT32 fileSize,
+ QObject *parent, const char *name)
+ : QObject( parent, name ),
+ m_socket(0),
+ m_port(0),
+ m_backlog(1),
+ m_engine(engine),
+ m_nick(nick),
+ m_type(type),
+ m_fileName(fileName),
+ m_fileSize(fileSize)
+{
+ initServer();
+}
+
+TransferServer::~TransferServer()
+{
+ if (m_socket)
+ delete m_socket;
+}
+
+bool TransferServer::initServer()
+{
+ if (!m_socket)
+ {
+ QObject::connect(this, SIGNAL(incomingNewTransfer(Transfer *)),
+ TransferHandler::self(), SIGNAL(transferCreated(Transfer *)));
+
+ m_socket = new KExtendedSocket();
+
+// m_socket->setHost(m_socket->localAddress()->nodeName());
+ if (!m_socket->setPort(m_port))
+ kdDebug(14120) << k_funcinfo << "Failed to set port to" << m_port << endl;
+ m_socket->setSocketFlags(KExtendedSocket::noResolve
+ |KExtendedSocket::passiveSocket
+ |KExtendedSocket::inetSocket );
+
+ if (!m_socket->setTimeout(2*60)) // FIXME: allow configuration of this.
+ kdDebug(14120) << k_funcinfo << "Failed to set timeout." << endl;
+
+ QObject::connect(m_socket, SIGNAL(readyAccept()),
+ this, SLOT(readyAccept()));
+ QObject::connect(m_socket, SIGNAL(connectionFailed(int)),
+ this, SLOT(connectionFailed(int)));
+
+ m_socket->listen(m_backlog);
+ m_socket->setBlockingMode(true);
+
+ const KInetSocketAddress *localAddress = static_cast<const KInetSocketAddress *>(m_socket->localAddress());
+ if (!localAddress)
+ {
+ kdDebug(14120) << k_funcinfo << "Not a KInetSocketAddress." << endl;
+ deleteLater();
+ return false;
+ }
+
+ m_port = localAddress->port();
+ }
+ return (m_socket->socketStatus() != KExtendedSocket::error);
+}
+
+bool TransferServer::initServer( Q_UINT16 port, int backlog )
+{
+ if (m_socket)
+ {
+ m_port = port;
+ m_backlog = backlog;
+ }
+ return initServer();
+}
+
+void TransferServer::readyAccept()
+{
+ KExtendedSocket *socket;
+ m_socket->accept( socket );
+ Transfer *transfer = new Transfer(m_engine, m_nick, m_type, m_fileName, m_fileSize);
+ transfer->setSocket(socket);
+ transfer->initiate();
+ emit incomingNewTransfer(transfer);
+}
+
+void TransferServer::connectionFailed(int error)
+{
+ if (error!=0)
+ {
+ kdDebug(14120) << k_funcinfo << "Connection failed with " << m_nick << endl;
+ deleteLater();
+ }
+}
+/*
+void Transfer::initClient()
+{
+ if(!m_socket)
+ {
+ connect(m_socket, SIGNAL(connectionClosed()),
+ this, SLOT(slotConnectionClosed()));
+ connect(m_socket, SIGNAL(delayedCloseFinished()),
+ this, SLOT(slotConnectionClosed()));
+ connect(m_socket, SIGNAL(error(int)),
+ this, SLOT(slotError(int)));
+ connect(m_socket, SIGNAL(readyRead()),
+ this, SLOT(readyReadFileOut));
+
+ m_socket->enableRead( true );
+ m_socket->enableWrite( true );
+ }
+}
+*/
+#include "kirctransferserver.moc"
diff --git a/kopete/protocols/irc/libkirc/kirctransferserver.h b/kopete/protocols/irc/libkirc/kirctransferserver.h
new file mode 100644
index 00000000..8ac016ef
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/kirctransferserver.h
@@ -0,0 +1,81 @@
+/*
+ kirctransfer.h - DCC Handler
+
+ Copyright (c) 2003-2004 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2003-2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KIRCTRANSFERSERVER_H
+#define KIRCTRANSFERSERVER_H
+
+#include "kirctransfer.h"
+
+#include <qobject.h>
+
+class KExtendedSocket;
+
+class QFile;
+class QTextCodec;
+
+namespace KIRC
+{
+
+class TransferServer
+ : public QObject
+{
+ Q_OBJECT
+
+public:
+// TransferServer(QObject *parent = 0, const char *name = 0);
+ TransferServer(Q_UINT16 port, int backlog = 1, QObject *parent = 0, const char *name = 0);
+ TransferServer(KIRC::Engine *engine, QString nick,// QString nick_peer_adress,
+ Transfer::Type type,
+ QString fileName, Q_UINT32 fileSize,
+ QObject *parent = 0, const char *name = 0);
+
+ ~TransferServer();
+
+ int port()
+ { return m_port; }
+
+protected:
+ bool initServer();
+ bool initServer( Q_UINT16 port, int backlog = 1 );
+
+signals:
+ void incomingNewTransfer(Transfer *transfer);
+
+protected slots:
+ void readyAccept();
+ void connectionFailed(int error);
+
+private:
+ KExtendedSocket * m_socket;
+ Q_UINT16 m_port;
+ int m_backlog;
+
+ // The following will be deprecated ...
+ KIRC::Engine * m_engine;
+ QString m_nick;
+ Transfer::Type m_type;
+ QString m_fileName;
+ Q_UINT32 m_fileSize;
+ // by
+ // QPtrList<Transfer> m_pendingTransfers;
+ // QPtrList<Transfer> m_activeTransfers;
+
+};
+
+}
+
+#endif
diff --git a/kopete/protocols/irc/libkirc/ksslsocket.cpp b/kopete/protocols/irc/libkirc/ksslsocket.cpp
new file mode 100644
index 00000000..fb2d5161
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/ksslsocket.cpp
@@ -0,0 +1,458 @@
+/*
+ ksslsocket.cpp - KDE SSL Socket
+
+ Copyright (c) 2005 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
+ Copyright (c) 2004 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <qsocketnotifier.h>
+
+#include <dcopclient.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kssl.h>
+#include <ksslinfodlg.h>
+#include <ksslpeerinfo.h>
+#include <ksslcertchain.h>
+#include <ksslcertificatecache.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+
+#include "ksslsocket.h"
+
+struct KSSLSocketPrivate
+{
+ mutable KSSL *kssl;
+ KSSLCertificateCache *cc;
+ DCOPClient *dcc;
+ QMap<QString,QString> metaData;
+ QSocketNotifier *socketNotifier;
+};
+
+KSSLSocket::KSSLSocket() : KExtendedSocket()
+{
+ d = new KSSLSocketPrivate;
+ d->kssl = 0;
+ d->dcc = KApplication::kApplication()->dcopClient();
+ d->cc = new KSSLCertificateCache;
+ d->cc->reload();
+
+ //No blocking
+ setBlockingMode(false);
+
+ //Connect internal slots
+ QObject::connect( this, SIGNAL(connectionSuccess()), this, SLOT(slotConnected()) );
+ QObject::connect( this, SIGNAL(closed(int)), this, SLOT(slotDisconnected()) );
+ QObject::connect( this, SIGNAL(connectionFailed(int)), this, SLOT(slotDisconnected()));
+}
+
+KSSLSocket::~KSSLSocket()
+{
+ //Close connection
+ closeNow();
+
+ if( d->kssl )
+ {
+ d->kssl->close();
+ delete d->kssl;
+ }
+
+ delete d->cc;
+
+ delete d;
+}
+
+Q_LONG KSSLSocket::readBlock( char* data, Q_ULONG maxLen )
+{
+ //Re-implemented because KExtSocket doesn't use this when not in buffered mode
+ Q_LONG retval = consumeReadBuffer(maxLen, data);
+
+ if( retval == 0 )
+ {
+ if (sockfd == -1)
+ return 0;
+
+ retval = -1;
+ }
+
+ return retval;
+}
+
+int KSSLSocket::peekBlock( char* data, uint maxLen )
+{
+ //Re-implemented because KExtSocket doesn't use this when not in buffered mode
+ if( socketStatus() < connected )
+ return -2;
+
+ if( sockfd == -1 )
+ return -2;
+
+ return consumeReadBuffer(maxLen, data, false);
+}
+
+Q_LONG KSSLSocket::writeBlock( const char* data, Q_ULONG len )
+{
+ return d->kssl->write( data, len );
+}
+
+int KSSLSocket::bytesAvailable() const
+{
+ if( socketStatus() < connected )
+ return -2;
+
+ //Re-implemented because KExtSocket doesn't use this when not in buffered mode
+ return KBufferedIO::bytesAvailable();
+}
+
+void KSSLSocket::slotReadData()
+{
+ kdDebug(14120) << k_funcinfo << d->kssl->pending() << endl;
+ QByteArray buff(512);
+ int bytesRead = d->kssl->read( buff.data(), 512 );
+
+ //Fill the read buffer
+ feedReadBuffer( bytesRead, buff.data() );
+ emit readyRead();
+}
+
+void KSSLSocket::slotConnected()
+{
+ if (!KSSL::doesSSLWork()) {
+ kdError(14120) << k_funcinfo << "SSL not functional!" << endl;
+
+ closeNow();
+ emit sslFailure();
+ return;
+ }
+
+ delete d->kssl;
+ d->kssl = new KSSL();
+
+ if (d->kssl->connect( sockfd ) != 1) {
+ kdError(14120) << k_funcinfo << "SSL connect() failed." << endl;
+
+ closeNow();
+ emit sslFailure();
+ return;
+ }
+
+ //Disconnect the KExtSocket notifier slot, we use our own
+ QObject::disconnect( readNotifier(), SIGNAL(activated( int )),
+ this, SLOT(socketActivityRead()) );
+
+ QObject::connect( readNotifier(), SIGNAL(activated( int )),
+ this, SLOT(slotReadData()) );
+
+ readNotifier()->setEnabled(true);
+
+ if (verifyCertificate() != 1) {
+ closeNow();
+ emit certificateRejected();
+ return;
+ }
+
+ emit certificateAccepted();
+}
+
+void KSSLSocket::slotDisconnected()
+{
+ kdDebug(14120) << k_funcinfo << "Disconnected" << endl;
+
+ if( readNotifier() )
+ readNotifier()->setEnabled(false);
+
+ delete d->kssl;
+ d->kssl = 0L;
+}
+
+void KSSLSocket::showInfoDialog()
+{
+ if( socketStatus() == connected )
+ {
+ if (!d->dcc->isApplicationRegistered("kio_uiserver"))
+ {
+ KApplication::startServiceByDesktopPath("kio_uiserver.desktop",QStringList());
+ }
+
+ QByteArray data, ignore;
+ QCString ignoretype;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << "irc://" + peerAddress()->pretty() + ":" + port() << d->metaData;
+ d->dcc->call("kio_uiserver", "UIServer",
+ "showSSLInfoDialog(QString,KIO::MetaData)", data, ignoretype, ignore);
+ }
+}
+
+void KSSLSocket::setMetaData( const QString &key, const QVariant &data )
+{
+ QVariant v = data;
+ d->metaData[key] = v.asString();
+}
+
+bool KSSLSocket::hasMetaData( const QString &key )
+{
+ return d->metaData.contains(key);
+}
+
+QString KSSLSocket::metaData( const QString &key )
+{
+ if( d->metaData.contains(key) )
+ return d->metaData[key];
+ return QString::null;
+}
+
+/*
+I basically copied the below from tcpKIO::SlaveBase.hpp, with some modificaions and formatting.
+
+ * Copyright (C) 2000 Alex Zepeda <zipzippy@sonic.net
+ * Copyright (C) 2001-2003 George Staikos <staikos@kde.org>
+ * Copyright (C) 2001 Dawit Alemayehu <adawit@kde.org>
+*/
+
+int KSSLSocket::messageBox( KIO::SlaveBase::MessageBoxType type, const QString &text, const QString &caption,
+ const QString &buttonYes, const QString &buttonNo )
+{
+ kdDebug(14120) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl;
+ QByteArray data, result;
+ QCString returnType;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << (int)1 << (int)type << text << caption << buttonYes << buttonNo;
+
+ if (!d->dcc->isApplicationRegistered("kio_uiserver"))
+ {
+ KApplication::startServiceByDesktopPath("kio_uiserver.desktop",QStringList());
+ }
+
+ d->dcc->call("kio_uiserver", "UIServer",
+ "messageBox(int,int,QString,QString,QString,QString)", data, returnType, result);
+
+ if( returnType == "int" )
+ {
+ int res;
+ QDataStream r(result, IO_ReadOnly);
+ r >> res;
+ return res;
+ }
+ else
+ return 0; // communication failure
+}
+
+
+// Returns 0 for failed verification, -1 for rejected cert and 1 for ok
+int KSSLSocket::verifyCertificate()
+{
+ int rc = 0;
+ bool permacache = false;
+ bool _IPmatchesCN = false;
+ int result;
+ bool doAddHost = false;
+ QString ourHost = host();
+ QString ourIp = peerAddress()->pretty();
+
+ QString theurl = "irc://" + ourHost + ":" + port();
+
+ if (!d->cc)
+ d->cc = new KSSLCertificateCache;
+
+ KSSLCertificate& pc = d->kssl->peerInfo().getPeerCertificate();
+
+ KSSLCertificate::KSSLValidationList ksvl = pc.validateVerbose(KSSLCertificate::SSLServer);
+
+ _IPmatchesCN = d->kssl->peerInfo().certMatchesAddress();
+
+ if (!_IPmatchesCN)
+ {
+ ksvl << KSSLCertificate::InvalidHost;
+ }
+
+ KSSLCertificate::KSSLValidation ksv = KSSLCertificate::Ok;
+ if (!ksvl.isEmpty())
+ ksv = ksvl.first();
+
+ /* Setting the various bits of meta-info that will be needed. */
+ setMetaData("ssl_cipher", d->kssl->connectionInfo().getCipher());
+ setMetaData("ssl_cipher_desc", d->kssl->connectionInfo().getCipherDescription());
+ setMetaData("ssl_cipher_version", d->kssl->connectionInfo().getCipherVersion());
+ setMetaData("ssl_cipher_used_bits", QString::number(d->kssl->connectionInfo().getCipherUsedBits()));
+ setMetaData("ssl_cipher_bits", QString::number(d->kssl->connectionInfo().getCipherBits()));
+ setMetaData("ssl_peer_ip", ourIp );
+
+ QString errorStr;
+ for(KSSLCertificate::KSSLValidationList::ConstIterator it = ksvl.begin();
+ it != ksvl.end(); ++it)
+ {
+ errorStr += QString::number(*it)+":";
+ }
+
+ setMetaData("ssl_cert_errors", errorStr);
+ setMetaData("ssl_peer_certificate", pc.toString());
+
+ if (pc.chain().isValid() && pc.chain().depth() > 1)
+ {
+ QString theChain;
+ QPtrList<KSSLCertificate> chain = pc.chain().getChain();
+ for (KSSLCertificate *c = chain.first(); c; c = chain.next())
+ {
+ theChain += c->toString();
+ theChain += "\n";
+ }
+ setMetaData("ssl_peer_chain", theChain);
+ }
+ else
+ {
+ setMetaData("ssl_peer_chain", "");
+ }
+
+ setMetaData("ssl_cert_state", QString::number(ksv));
+
+ if (ksv == KSSLCertificate::Ok)
+ {
+ rc = 1;
+ setMetaData("ssl_action", "accept");
+ }
+
+ // Since we're the parent, we need to teach the child.
+ setMetaData("ssl_parent_ip", ourIp );
+ setMetaData("ssl_parent_cert", pc.toString());
+
+ // - Read from cache and see if there is a policy for this
+ KSSLCertificateCache::KSSLCertificatePolicy cp = d->cc->getPolicyByCertificate(pc);
+
+ // - validation code
+ if (ksv != KSSLCertificate::Ok)
+ {
+ if( cp == KSSLCertificateCache::Unknown || cp == KSSLCertificateCache::Ambiguous)
+ {
+ cp = KSSLCertificateCache::Prompt;
+ }
+ else
+ {
+ // A policy was already set so let's honor that.
+ permacache = d->cc->isPermanent(pc);
+ }
+
+ if (!_IPmatchesCN && cp == KSSLCertificateCache::Accept)
+ {
+ cp = KSSLCertificateCache::Prompt;
+ }
+
+ // Precondition: cp is one of Reject, Accept or Prompt
+ switch (cp)
+ {
+ case KSSLCertificateCache::Accept:
+ rc = 1;
+ break;
+
+ case KSSLCertificateCache::Reject:
+ rc = -1;
+ break;
+
+ case KSSLCertificateCache::Prompt:
+ {
+ do
+ {
+ if (ksv == KSSLCertificate::InvalidHost)
+ {
+ QString msg = i18n("The IP address of the host %1 "
+ "does not match the one the "
+ "certificate was issued to.");
+ result = messageBox( KIO::SlaveBase::WarningYesNoCancel,
+ msg.arg(ourHost),
+ i18n("Server Authentication"),
+ i18n("&Details"),
+ i18n("Co&ntinue") );
+ }
+ else
+ {
+ QString msg = i18n("The server certificate failed the "
+ "authenticity test (%1).");
+ result = messageBox( KIO::SlaveBase::WarningYesNoCancel,
+ msg.arg(ourHost),
+ i18n("Server Authentication"),
+ i18n("&Details"),
+ i18n("Co&ntinue") );
+ }
+
+ if (result == KMessageBox::Yes)
+ {
+ showInfoDialog();
+ }
+ }
+ while (result == KMessageBox::Yes);
+
+ if (result == KMessageBox::No)
+ {
+ rc = 1;
+ cp = KSSLCertificateCache::Accept;
+ doAddHost = true;
+ result = messageBox( KIO::SlaveBase::WarningYesNo,
+ i18n("Would you like to accept this "
+ "certificate forever without "
+ "being prompted?"),
+ i18n("Server Authentication"),
+ i18n("&Forever"),
+ i18n("&Current Sessions Only"));
+ if (result == KMessageBox::Yes)
+ permacache = true;
+ else
+ permacache = false;
+ }
+ else
+ {
+ rc = -1;
+ cp = KSSLCertificateCache::Prompt;
+ }
+
+ break;
+ }
+ default:
+ kdDebug(14120) << "SSL error in cert code."
+ << "Please report this to kopete-devel@kde.org."
+ << endl;
+ break;
+ }
+ }
+
+ // - cache the results
+ d->cc->addCertificate(pc, cp, permacache);
+ if (doAddHost)
+ d->cc->addHost(pc, ourHost);
+
+
+ if (rc == -1)
+ return rc;
+
+
+ kdDebug(14120) << "SSL connection information follows:" << endl
+ << "+-----------------------------------------------" << endl
+ << "| Cipher: " << d->kssl->connectionInfo().getCipher() << endl
+ << "| Description: " << d->kssl->connectionInfo().getCipherDescription() << endl
+ << "| Version: " << d->kssl->connectionInfo().getCipherVersion() << endl
+ << "| Strength: " << d->kssl->connectionInfo().getCipherUsedBits()
+ << " of " << d->kssl->connectionInfo().getCipherBits()
+ << " bits used." << endl
+ << "| PEER:" << endl
+ << "| Subject: " << d->kssl->peerInfo().getPeerCertificate().getSubject() << endl
+ << "| Issuer: " << d->kssl->peerInfo().getPeerCertificate().getIssuer() << endl
+ << "| Validation: " << (int)ksv << endl
+ << "| Certificate matches IP: " << _IPmatchesCN << endl
+ << "+-----------------------------------------------"
+ << endl;
+
+ // sendMetaData(); Do not call this function!!
+ return rc;
+}
+
+
+#include "ksslsocket.moc"
diff --git a/kopete/protocols/irc/libkirc/ksslsocket.h b/kopete/protocols/irc/libkirc/ksslsocket.h
new file mode 100644
index 00000000..692d5288
--- /dev/null
+++ b/kopete/protocols/irc/libkirc/ksslsocket.h
@@ -0,0 +1,68 @@
+
+#ifndef _K_SSL_SOCKET_H_
+#define _K_SSL_SOCKET_H_
+
+/*
+ ksslsocket.h - KDE SSL Socket
+
+ Copyright (c) 2005 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
+ Copyright (c) 2004 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <qvariant.h>
+#include <kextsock.h>
+#include <kio/slavebase.h>
+
+class KSSLSocketPrivate;
+
+class KSSLSocket : public KExtendedSocket
+{
+ Q_OBJECT
+
+ public:
+ KSSLSocket();
+ ~KSSLSocket();
+
+ Q_LONG readBlock( char* data, Q_ULONG maxLen );
+ Q_LONG writeBlock( const char* data, Q_ULONG len );
+ int peekBlock( char *data, uint maxLen );
+ int bytesAvailable() const;
+
+ void showInfoDialog();
+
+ signals:
+ void sslFailure();
+ void certificateAccepted();
+ void certificateRejected();
+
+ private slots:
+ void slotConnected();
+ void slotDisconnected();
+ void slotReadData();
+
+ private:
+ int verifyCertificate();
+ int messageBox( KIO::SlaveBase::MessageBoxType type, const QString &text,
+ const QString &caption, const QString &buttonYes, const QString &buttonNo );
+
+
+ //Copied frm tcpslavebase to simply integrating their dialog function
+ void setMetaData( const QString &, const QVariant & );
+ bool hasMetaData( const QString & );
+ QString metaData( const QString & );
+
+ KSSLSocketPrivate *d;
+};
+
+#endif
diff --git a/kopete/protocols/irc/ui/Makefile.am b/kopete/protocols/irc/ui/Makefile.am
new file mode 100644
index 00000000..854a7398
--- /dev/null
+++ b/kopete/protocols/irc/ui/Makefile.am
@@ -0,0 +1,12 @@
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libkopeteircui.la
+AM_CPPFLAGS = $(KOPETE_INCLUDES) \
+ -I$(srcdir)/..\
+ -I$(srcdir)/../libkirc \
+ $(all_includes)
+
+
+libkopeteircui_la_SOURCES = ircadd.ui empty.cpp irceditaccountwidget.cpp \
+ irceditaccount.ui channellist.cpp channellistdialog.cpp networkconfig.ui
+EXTRA_DIST = ircadd.ui ircprefs.ui empty.cpp
diff --git a/kopete/protocols/irc/ui/channellist.cpp b/kopete/protocols/irc/ui/channellist.cpp
new file mode 100644
index 00000000..5c66ede0
--- /dev/null
+++ b/kopete/protocols/irc/ui/channellist.cpp
@@ -0,0 +1,346 @@
+/*
+ channellist.cpp - IRC Channel Search Widget
+
+ Copyright (c) 2004 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "channellist.h"
+
+#include "kircengine.h"
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <qvariant.h>
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qapplication.h>
+#include <qsimplerichtext.h>
+#include <qstyle.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qheader.h>
+#include <klistview.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qtimer.h>
+#include <qspinbox.h>
+#include <qwhatsthis.h>
+
+class ChannelListItem : public KListViewItem
+{
+ public:
+ ChannelListItem( KListView *parent, QString arg1, QString arg2, QString arg3 );
+ virtual int compare( QListViewItem *i, int col, bool ascending ) const;
+ virtual void paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int align );
+
+ private:
+ KListView *parentList;
+};
+
+ChannelListItem::ChannelListItem( KListView *parent, QString arg1, QString arg2, QString arg3 ) :
+ KListViewItem( parent, parent->lastItem() ), parentList( parent )
+{
+ setText(0, arg1);
+ setText(1, arg2);
+ setText(2, arg3);
+}
+
+int ChannelListItem::compare( QListViewItem *i, int col, bool ascending ) const
+{
+ if( col == 1 )
+ {
+ if( text(1).toUInt() < i->text(1).toUInt() )
+ return -1;
+ else if ( text(1).toUInt() == i->text(1).toUInt() )
+ return 0;
+ else
+ return 1;
+ }
+ else
+ return QListViewItem::compare( i, col, ascending );
+}
+
+void ChannelListItem::paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int align )
+{
+ QPixmap back( width, height() );
+ QPainter paint( &back );
+ //KListViewItem::paintCell( &paint, cg, column, width, align );
+ // PASTED FROM KLISTVIEWITEM:
+ // set the alternate cell background colour if necessary
+ QColorGroup _cg = cg;
+ if (isAlternate())
+ if (listView()->viewport()->backgroundMode()==Qt::FixedColor)
+ _cg.setColor(QColorGroup::Background, static_cast< KListView* >(listView())->alternateBackground());
+ else
+ _cg.setColor(QColorGroup::Base, static_cast< KListView* >(listView())->alternateBackground());
+ // PASTED FROM QLISTVIEWITEM
+ {
+ QPainter *p = &paint;
+
+ QListView *lv = listView();
+ if ( !lv )
+ return;
+ QFontMetrics fm( p->fontMetrics() );
+
+ // any text we render is done by the Components, not by this class, so make sure we've nothing to write
+ QString t;
+
+ // removed text truncating code from Qt - we do that differently, further on
+
+ int marg = lv->itemMargin();
+ int r = marg;
+ // const QPixmap * icon = pixmap( column );
+
+ const BackgroundMode bgmode = lv->viewport()->backgroundMode();
+ const QColorGroup::ColorRole crole = QPalette::backgroundRoleFromMode( bgmode );
+
+ if ( _cg.brush( crole ) != lv->colorGroup().brush( crole ) )
+ p->fillRect( 0, 0, width, height(), _cg.brush( crole ) );
+ else
+ {
+ // all copied from QListView::paintEmptyArea
+
+ //lv->paintEmptyArea( p, QRect( 0, 0, width, height() ) );
+ QStyleOption opt( lv->sortColumn(), 0 ); // ### hack; in 3.1, add a property in QListView and QHeader
+ QStyle::SFlags how = QStyle::Style_Default;
+ if ( lv->isEnabled() )
+ how |= QStyle::Style_Enabled;
+
+ lv->style().drawComplexControl( QStyle::CC_ListView,
+ p, lv, QRect( 0, 0, width, height() ), lv->colorGroup(),
+ how, QStyle::SC_ListView, QStyle::SC_None,
+ opt );
+ }
+
+
+
+ if ( isSelected() &&
+ (column == 0 || lv->allColumnsShowFocus()) ) {
+ p->fillRect( r - marg, 0, width - r + marg, height(),
+ _cg.brush( QColorGroup::Highlight ) );
+ // removed text pen setting code from Qt
+ }
+
+ // removed icon drawing code from Qt
+
+ // draw the tree gubbins
+ if ( multiLinesEnabled() && column == 0 && isOpen() && childCount() ) {
+ int textheight = fm.size( align, t ).height() + 2 * lv->itemMargin();
+ textheight = QMAX( textheight, QApplication::globalStrut().height() );
+ if ( textheight % 2 > 0 )
+ textheight++;
+ if ( textheight < height() ) {
+ int w = lv->treeStepSize() / 2;
+ lv->style().drawComplexControl( QStyle::CC_ListView, p, lv,
+ QRect( 0, textheight, w + 1, height() - textheight + 1 ), _cg,
+ lv->isEnabled() ? QStyle::Style_Enabled : QStyle::Style_Default,
+ QStyle::SC_ListViewExpand,
+ (uint)QStyle::SC_All, QStyleOption( this ) );
+ }
+ }
+ }
+ // END OF PASTE
+
+
+ //do you see a better way to tell the TextComponent we are selected ? - Olivier 2004-09-02
+ if ( isSelected() )
+ _cg.setColor(QColorGroup::Text , _cg.highlightedText() );
+
+ QSimpleRichText myrichtext( text(column), paint.font() );
+ myrichtext.draw( &paint, 0, 0, paint.window(), _cg );
+
+ paint.end();
+ p->drawPixmap( 0, 0, back );
+}
+
+ChannelList::ChannelList( QWidget* parent, KIRC::Engine *engine )
+ : QWidget( parent ), m_engine( engine )
+{
+ ChannelListLayout = new QVBoxLayout( this, 11, 6, "ChannelListLayout");
+
+ layout72_2 = new QHBoxLayout( 0, 0, 6, "layout72_2");
+
+ textLabel1_2 = new QLabel( this, "textLabel1_2" );
+ layout72_2->addWidget( textLabel1_2 );
+
+ channelSearch = new QLineEdit( this, "channelSearch" );
+ layout72_2->addWidget( channelSearch );
+
+ numUsers = new QSpinBox( 0, 32767, 1, this, "num_users" );
+ numUsers->setSuffix( i18n(" members") );
+ layout72_2->addWidget( numUsers );
+
+ mSearchButton = new QPushButton( this, "mSearchButton" );
+ layout72_2->addWidget( mSearchButton );
+ ChannelListLayout->addLayout( layout72_2 );
+
+ mChannelList = new KListView( this, "mChannelList" );
+ mChannelList->addColumn( i18n( "Channel" ) );
+ mChannelList->addColumn( i18n( "Users" ) );
+ mChannelList->header()->setResizeEnabled( FALSE, mChannelList->header()->count() - 1 );
+ mChannelList->addColumn( i18n( "Topic" ) );
+ mChannelList->setAllColumnsShowFocus( TRUE );
+ mChannelList->setShowSortIndicator( TRUE );
+ ChannelListLayout->addWidget( mChannelList );
+
+ clearWState( WState_Polished );
+
+ textLabel1_2->setText( i18n( "Search for:" ) );
+ QToolTip::add( textLabel1_2, i18n( "You may search for channels on the IRC server for a text string entered here." ) );
+ QToolTip::add( numUsers, i18n( "Channels returned must have at least this many members." ) );
+ QWhatsThis::add( numUsers, i18n( "Channels returned must have at least this many members." ) );
+ QWhatsThis::add( textLabel1_2, i18n( "You may search for channels on the IRC server for a text string entered here. For instance, you may type 'linux' to find channels that have something to do with linux." ) );
+ QToolTip::add( channelSearch, i18n( "You may search for channels on the IRC server for a text string entered here." ) );
+ QWhatsThis::add( channelSearch, i18n( "You may search for channels on the IRC server for a text string entered here. For instance, you may type 'linux' to find channels that have something to do with linux." ) );
+ mSearchButton->setText( i18n( "S&earch" ) );
+ QToolTip::add( mSearchButton, i18n( "Perform a channel search." ) );
+ QWhatsThis::add( mSearchButton, i18n( "Perform a channel search. Please be patient, as this can be slow depending on the number of channels on the server." ) );
+ QToolTip::add( mChannelList, i18n( "Double click on a channel to select it." ) );
+ mChannelList->header()->setLabel( 0, i18n( "Channel" ) );
+ mChannelList->header()->setLabel( 1, i18n( "Users" ) );
+ mChannelList->header()->setLabel( 2, i18n( "Topic" ) );
+
+ // signals and slots connections
+ connect( mChannelList, SIGNAL( doubleClicked(QListViewItem*) ),
+ this, SLOT( slotItemDoubleClicked(QListViewItem*) ) );
+
+ connect( mSearchButton, SIGNAL( clicked() ), this, SLOT( search() ) );
+
+ connect( mChannelList, SIGNAL( selectionChanged( QListViewItem*) ), this,
+ SLOT( slotItemSelected( QListViewItem *) ) );
+
+ connect( m_engine, SIGNAL( incomingListedChan( const QString &, uint, const QString & ) ),
+ this, SLOT( slotChannelListed( const QString &, uint, const QString & ) ) );
+
+ connect( m_engine, SIGNAL( incomingEndOfList() ), this, SLOT( slotListEnd() ) );
+
+ connect( m_engine, SIGNAL( statusChanged(KIRC::Engine::Status) ),
+ this, SLOT( slotStatusChanged(KIRC::Engine::Status) ) );
+
+ show();
+}
+
+void ChannelList::slotItemDoubleClicked( QListViewItem *i )
+{
+ emit channelDoubleClicked( i->text(0) );
+}
+
+void ChannelList::slotItemSelected( QListViewItem *i )
+{
+ emit channelSelected( i->text(0) );
+}
+
+void ChannelList::slotStatusChanged(KIRC::Engine::Status newStatus)
+{
+ switch(newStatus) {
+ case KIRC::Engine::Connected:
+ this->reset();
+ break;
+ case KIRC::Engine::Disconnected:
+ if (mSearching) {
+ KMessageBox::queuedMessageBox(
+ this, KMessageBox::Error,
+ i18n("You have been disconnected from the IRC server."),
+ i18n("Disconnected"), 0
+ );
+ }
+
+ slotListEnd();
+ break;
+ default:
+ break;
+ }
+}
+
+void ChannelList::reset()
+{
+ channelCache.clear();
+ clear();
+}
+
+void ChannelList::clear()
+{
+ mChannelList->clear();
+ channelSearch->clear();
+ channelSearch->setFocus();
+}
+
+void ChannelList::search()
+{
+ if( m_engine->isConnected() || !channelCache.isEmpty() )
+ {
+ mChannelList->clear();
+ mChannelList->setSorting( -1 );
+ mSearchButton->setEnabled(false);
+ mSearch = channelSearch->text();
+ mSearching = true;
+ mUsers = numUsers->value();
+
+ if( channelCache.isEmpty() )
+ m_engine->list();
+ else
+ {
+ cacheIterator = channelCache.begin();
+ slotSearchCache();
+ }
+ }
+ else
+ {
+ KMessageBox::queuedMessageBox(
+ this, KMessageBox::Error,
+ i18n("You must be connected to the IRC server to perform a channel listing."),
+ i18n("Not Connected"), 0
+ );
+ }
+}
+
+void ChannelList::slotChannelListed( const QString &channel, uint users, const QString &topic )
+{
+ checkSearchResult( channel, users, topic );
+ channelCache.insert( channel, QPair< uint, QString >( users, topic ) );
+}
+
+void ChannelList::checkSearchResult( const QString &channel, uint users, const QString &topic )
+{
+ if( ( mUsers == 0 || mUsers <= users ) &&
+ ( mSearch.isEmpty() || channel.contains( mSearch, false ) || topic.contains( mSearch, false ) )
+ )
+ {
+ new ChannelListItem( mChannelList, channel, QString::number(users), topic );
+ }
+}
+
+void ChannelList::slotSearchCache()
+{
+ if( cacheIterator != channelCache.end() )
+ {
+ checkSearchResult( cacheIterator.key(), cacheIterator.data().first, cacheIterator.data().second );
+ ++cacheIterator;
+ QTimer::singleShot( 0, this, SLOT( slotSearchCache() ) );
+ }
+ else
+ {
+ slotListEnd();
+ }
+}
+
+void ChannelList::slotListEnd()
+{
+ mChannelList->setSorting(0, true);
+ mSearchButton->setEnabled(true);
+ mSearching = false;
+}
+
+#include "channellist.moc"
diff --git a/kopete/protocols/irc/ui/channellist.h b/kopete/protocols/irc/ui/channellist.h
new file mode 100644
index 00000000..c6f435a0
--- /dev/null
+++ b/kopete/protocols/irc/ui/channellist.h
@@ -0,0 +1,80 @@
+ /*
+ channellist.h - IRC Channel Search Widget
+
+ Copyright (c) 2004 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef CHANNELLIST_H
+#define CHANNELLIST_H
+
+#include <qwidget.h>
+#include <qmap.h>
+#include <qpair.h>
+
+#include "kircengine.h"
+
+class QVBoxLayout;
+class QHBoxLayout;
+class QGridLayout;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class KListView;
+class QSpinBox;
+class QListViewItem;
+
+class ChannelList
+ : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ ChannelList( QWidget *parent, KIRC::Engine *engine );
+
+ public slots:
+ void search();
+ void reset();
+ void clear();
+
+ signals:
+ void channelDoubleClicked( const QString &channel );
+ void channelSelected( const QString &channel );
+
+ private slots:
+ void slotItemDoubleClicked( QListViewItem * i );
+ void slotItemSelected( QListViewItem * i );
+ void slotChannelListed( const QString & channel, uint users, const QString & topic );
+ void slotListEnd();
+ void slotSearchCache();
+ void slotStatusChanged( KIRC::Engine::Status );
+
+ private:
+ void checkSearchResult( const QString & channel, uint users, const QString & topic );
+
+ QLabel* textLabel1_2;
+ QLineEdit* channelSearch;
+ QSpinBox* numUsers;
+ QPushButton* mSearchButton;
+ KListView* mChannelList;
+ QVBoxLayout* ChannelListLayout;
+ QHBoxLayout* layout72_2;
+ KIRC::Engine *m_engine;
+ bool mSearching;
+ QString mSearch;
+ uint mUsers;
+ QMap< QString, QPair< uint, QString > > channelCache;
+ QMap< QString, QPair< uint, QString > >::const_iterator cacheIterator;
+};
+
+#endif
diff --git a/kopete/protocols/irc/ui/channellistdialog.cpp b/kopete/protocols/irc/ui/channellistdialog.cpp
new file mode 100644
index 00000000..46128730
--- /dev/null
+++ b/kopete/protocols/irc/ui/channellistdialog.cpp
@@ -0,0 +1,61 @@
+/*
+ channellistdialog.cpp - IRC Channel Search Dialog
+
+ Copyright (c) 2004 by Jason Keirstead <jason@keirstead.org>
+ Copyright (c) 2005 by Michel Hermier <michel.hermier@wanadoo.fr>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "channellistdialog.h"
+
+#include "kircengine.h"
+
+#include "kopeteuiglobal.h"
+
+#include "qlayout.h"
+
+ChannelListDialog::ChannelListDialog(KIRC::Engine *engine, const QString &caption, QObject *target, const char* slotJoinChan)
+ : KDialogBase(Kopete::UI::Global::mainWidget(), "channel_list_widget", false, caption, Close)
+{
+ m_engine = engine;
+ m_list = new ChannelList( this, engine );
+
+ connect( m_list, SIGNAL( channelDoubleClicked( const QString & ) ),
+ target, slotJoinChan );
+
+ connect( m_list, SIGNAL( channelDoubleClicked( const QString & ) ),
+ this, SLOT( slotChannelDoubleClicked( const QString & ) ) );
+
+ new QHBoxLayout( m_list, 0, spacingHint() );
+
+ setInitialSize( QSize( 500, 400 ) );
+ setMainWidget( m_list );
+ show();
+}
+
+void ChannelListDialog::clear()
+{
+ m_list->clear();
+}
+
+void ChannelListDialog::search()
+{
+ m_list->search();
+}
+
+void ChannelListDialog::slotChannelDoubleClicked( const QString & )
+{
+ close();
+}
+
+#include "channellistdialog.moc"
diff --git a/kopete/protocols/irc/ui/channellistdialog.h b/kopete/protocols/irc/ui/channellistdialog.h
new file mode 100644
index 00000000..2bb85f5b
--- /dev/null
+++ b/kopete/protocols/irc/ui/channellistdialog.h
@@ -0,0 +1,45 @@
+ /*
+ channellist.h - IRC Channel Search Widget
+
+ Copyright (c) 2004 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2004 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef CHANNELLISTDIALOG_H
+#define CHANNELLISTDIALOG_H
+
+#include "channellist.h"
+
+#include "kdialogbase.h"
+
+class ChannelListDialog
+ : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ ChannelListDialog(KIRC::Engine *engine, const QString &caption, QObject *target, const char* slotJoinChan);
+
+ void clear();
+
+ void search();
+
+ private slots:
+ void slotChannelDoubleClicked( const QString & );
+
+ private:
+ KIRC::Engine *m_engine;
+ ChannelList *m_list;
+};
+
+#endif
diff --git a/kopete/protocols/irc/ui/empty.cpp b/kopete/protocols/irc/ui/empty.cpp
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/kopete/protocols/irc/ui/empty.cpp
@@ -0,0 +1 @@
+
diff --git a/kopete/protocols/irc/ui/ircadd.ui b/kopete/protocols/irc/ui/ircadd.ui
new file mode 100644
index 00000000..f1025112
--- /dev/null
+++ b/kopete/protocols/irc/ui/ircadd.ui
@@ -0,0 +1,163 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>ircAddUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ircAddUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>389</width>
+ <height>350</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget3</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Add Contact</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout70</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>N&amp;ickname/channel to add:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>addID</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The name of the IRC contact or channel you would like to add.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The name of the IRC contact or channel you would like to add. You may type simply the text of a person's nickname, or you may type a channel name, preceded by a pound sign ('#').</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>addID</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The name of the IRC contact or channel you would like to add.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The name of the IRC contact or channel you would like to add. You may type simply the text of a person's nickname, or you may type a channel name, preceded by a pound sign ('#')</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;i&gt;(for example: joe_bob or #somechannel)&lt;/i&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer25</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>110</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Search Channels</string>
+ </attribute>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QHBox">
+ <property name="name">
+ <cstring>hbox</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>QHBox</class>
+ <header>qhbox.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="XPM.GZ" length="4462">789c9d97c76e24490e86effd1442f3d65870d2451a0ce6206f5adeb4cc620f8c34f2553225b5a4c1befb46927fe6a1d4c0ccac4287fa8a0c26834193f5dbb785b3fd9d856fbf7d799ec9ecba5ea8afe469e15bf3727ffffeeffffcf1e797af49b2d0ffc7d142f2f55f5fbe1ecc16ea85dde9a4ed81290045faa77ca49cf4ab67ba1e3953969173651ab9d4fdf1c8a27c3872ad7c3c72d3b32c2a67c3f3444636fbef23eb7e590267e68fcc4656395d8dacf6d938ef97eaef289781cddebdb2846fccff44b989ba58e3411f3dc75158e6df1d3889539517ca49bf54fe43398d1dec4f46567f685fd9c539f43fc025f80c1c3ce8d93f28e77185f8bf0c6cfae4c0b5f9c3c6e5c0542a4b5876fe13708df39d2bd7716372aa8c93c4e4723bb2f977aadc26ceec4bdb7310e6b0bfab9c2445ecd49f1370694cebca65d260ffa6711a41aef14d24e94cee6be3348e0ae5e9c8765f07ca3e8db17f0f9c825794eb3489351fe9bb7217e4969f29388bd51ee9fda5715a19730696b852fea95c6471647ca95cf64bcf43e0cef4657b647bfe6acf213d6bb32f9a9f5992b5a64f9a8f990b6cf9ecc15d6cf9acf6b2da55a8a75cb973dee4b2d1b38b5c05de02434e87e01aacfb351df5bebddea74b5c67f9c795711ea15e357e2ecde358fb87efc0a867df8cac728a074e62e527706afb59f3cf6583be5c28bb3c35f693812d1fbdc6dbe57966fec932d899ffa4f7e38adca17e34beaeca4b9c271a18f1d5fc739257b0d70d9c68be7bed7fcee7827ab91cd8e4740cf6b19d4ffb87ab07b9bf516e72d4a3ac821b9cef6e60d84f47367ded2fae1d9f7704f6163f79000ffde27660f387ed3c5dbf54dfeebb0bf6acbe6b706bfa5ef32f8f8b18f5bf0f463f20edb77956a4e68fbc80b3c4facd163847be6bfde72ec86dbeac82715fbc0286be683cf3bc081d44f7df80d344fb0b6b7de64581fb916765297263d6fccd9b7ee97e566e8b06cfdb1f59cf2bda2f8bbc2c11df0c5c41aefdb328ca22b1feb0012eedbce24736f91b18fb796d64eb87cb60817dcdafb07d906bfd14d22f659d8785ef97b2f6d7b2df6ef1d6fb2babaac6f92e8c25b27ecc1f239b7f3a5fca5a8678ea7c2d9bc0e6ef1238b3fca2c7814d5f4cbf9334b5f833384bed3c7a5f5514f4adbe2ec07962e7590457f06f6f649b977afe2a16f42f5e070bfc591e18f7a5f1a812a9e0df39d827da4fbd8c6ccfd7785569bf945f953371a9d5a3de67950bfa2d75c63eb2fb15bdcfaaf011e6c7263846bf8f4636f91618f3c7d3c0f047fb69550efab2074e12bd6fd27957553ec33c5b043bcc7f9d0795f818fdb501a3df8ae673e507ff69021eea37063bc45ffb73550736ff36c0a84f3e0317a86f8b5f139e6ffe1f821de6d9127898ff3be00a7c3ab2cd03e3d697560ff40016e47b3bb2e96bbd559d8f32bbff4b7065f193042c98873acf240af6adbf3c83c5f2954bb0c7bcd77c107d81d2fdebc63e33ff640aaecc9e1c8151df5c803dfaadc64b52dfa03ed64636ffb4ff4b2867f453ede7227586fcd3f9264ded91fffafe236d5da37fe83c91ceb7b9e5b7f6731ff92ed7f747d6fbf7e185cf58347e3e6932e47b3430fa893edf87d795c2fc3f003b67f5f902cec17abfde0dfa3c053b3c5ffb832fc2eb8fddcf233887fc195c801f46b6f3cdc02558fba72f7d2d1a7f7e321ee58fe0cad86bbff24dd3e2fe74fef836b0c6eb60d62fa6bf5e07b3419f853dd7dc70fb8bd5f1255fd90ed30f9f3c5ff30ddff21ddff384a7fcc08ffcc4cf61cdf8855ff9e79c7e1db4dff89d3f7891977899577895d7789d377893b7f83b6fcfe937bc13b477798ff7f9800ff928ac633ee11f7cca6761d7f99c7e1b3cb908da11c7413be1943376e153cc39175c72f549ff9e17c31744429e6a6aa8a58e2ee98aaee9866e7f617fc24b7417a4f734a1293dd0233dd133cd8285177aa5f9f3b63ca5377aa78f607b919668995682e62aadd17ab0b1419b9ff41f682b48bed336edd02eed05ed7d5ea3033a0cdf1ed1f127fd273ae123fa41a774a6b685cee982228a837e42e927fd47caf8985c38651eb40b2ac38e4a5842658a97fab33fd248cb87d2c9a55cc9b5dcc82d1fc99ddccb44a6f230af2f8ff224cf417f262ff22a3fe54ddee543166549966545567f617f4dd66523dc6b2c9bb225df655b7682f692ecca9eeccfe97772c09b722847722c27c1f3eb70f66bf9116c9fca999ccbc59cfe25bf4a143a5ef8992561324a78bd92522acf9ebc78efe7cf7b153276db37bef59dbff457fedadff85b7f27abfede4ffcd4cf9ff76faeff4fffefeff8c7f5fedfdfbffc0fa355c495</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>addID</tabstop>
+ <tabstop>tabWidget3</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kopete/protocols/irc/ui/irceditaccount.ui b/kopete/protocols/irc/ui/irceditaccount.ui
new file mode 100644
index 00000000..682e9be9
--- /dev/null
+++ b/kopete/protocols/irc/ui/irceditaccount.ui
@@ -0,0 +1,1022 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>IRCEditAccountBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>IRCEditAccountBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>689</width>
+ <height>528</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>440</width>
+ <height>575</height>
+ </size>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTabWidget">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>B&amp;asic Setup</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>150</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32767</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt; Most IRC servers do not require a password, and only a nickname is required to connect&lt;/p&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignTop</set>
+ </property>
+ </widget>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>groupBox59</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>GroupBoxPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="title">
+ <string>Account Information</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>N&amp;ickname:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mNickName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This is the name that everyone will see everytime you say something</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Alternate ni&amp;ckname:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mAltNickname</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>When the nickname is already in use when connecting, this name will be used instead</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>mNickName</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>This is the name that everyone will see everytime you say something</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The alias you would like to use on IRC. You may change this once online with the /nick command.</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>mAltNickname</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>When the nickname is already in use when connecting, this name will be used instead</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>When the nickname is already in use when connecting, this name will be used instead</string>
+ </property>
+ </widget>
+ <widget class="Kopete::UI::PasswordWidget" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>mPasswordWidget</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>m_realNameLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Real name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_realNameLineEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Username:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mUserName</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The username you would prefer to use on IRC, if your system does not have identd support. Leave blank to use your system account name.</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>mUserName</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="echoMode">
+ <enum>Normal</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The username you would prefer to use on IRC, if your system does not have identd support. Leave blank to use your system account name.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The username you would prefer to use on IRC, if your system does not have identd support. Leave blank to use your system account name.</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>m_realNameLineEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="echoMode">
+ <enum>Normal</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The username you would prefer to use on IRC, if your system does not have identd support.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The username you would prefer to use on IRC, if your system does not have identd support. Leave blank to use your system account name.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Connection</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout21</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>description</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>161</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout20</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>network</cstring>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>editButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Edit...</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>392</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Network:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>network</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Connection Preferences</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>preferSSL</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Prefer SSL-based connections</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>autoConnect</cstring>
+ </property>
+ <property name="text">
+ <string>E&amp;xclude from connect all</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If you check that case, the account will not be connected when you press the "Connect All" button, or at startup even if you selected to automatically connect at startup</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout25</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Default &amp;charset:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>charset</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>charset</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>141</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox5</cstring>
+ </property>
+ <property name="title">
+ <string>Default Messages</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Part message:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>partMessage</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Quit message:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>quitMessage</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>partMessage</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The message you want people to see when you part a channel without giving a reason. Leave this field blank to use the Kopete default message.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The message you want people to see when you part a channel without giving a reason. Leave this field blank to use the Kopete default message.</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>quitMessage</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The message you want people to see when you disconnect from IRC without giving a reason. Leave this field blank to use the Kopete default message.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The message you want people to see when you disconnect from IRC without giving a reason. Leave this field blank to use the Kopete default message.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer72</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>150</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>A&amp;dvanced Configuration</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox7</cstring>
+ </property>
+ <property name="title">
+ <string>Message Destinations</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>autoShowAnonWindows</cstring>
+ </property>
+ <property name="text">
+ <string>Auto-show anonymous windows</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>autoShowServerWindow</cstring>
+ </property>
+ <property name="text">
+ <string>Auto-show the server window</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Server messages:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel4_3</cstring>
+ </property>
+ <property name="text">
+ <string>Server notices:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Active Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Server Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Anonymous Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>KNotify</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Ignore</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>serverNotices</cstring>
+ </property>
+ <property name="currentItem">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Active Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Server Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Anonymous Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>KNotify</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Ignore</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>serverMessages</cstring>
+ </property>
+ <property name="currentItem">
+ <number>1</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout23</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3_3</cstring>
+ </property>
+ <property name="text">
+ <string>Error messages:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Active Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Server Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Anonymous Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>KNotify</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Ignore</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>informationReplies</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Information replies:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Active Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Server Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Anonymous Window</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>KNotify</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Ignore</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>errorMessages</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox6</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>130</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Custom CTCP Replies</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>CTCP</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Reply</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>ctcpList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>2</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>false</bool>
+ </property>
+ <property name="defaultRenameAction">
+ <enum>Accept</enum>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ <property name="itemsRenameable">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>You can use this dialog to add custom replies for when people send CTCP requests to you. You can also use this dialog to override the built-in replies for VERSION, USERINFO, and CLIENTINFO.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout153</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;CTCP:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>newCTCP</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>newCTCP</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel4_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Reply:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>newReply</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>newReply</cstring>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>addReply</cstring>
+ </property>
+ <property name="text">
+ <string>Add Repl&amp;y</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox60</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>130</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Run Following Commands on Connect</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <property name="name">
+ <cstring>layout29</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>commandEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>addButton</cstring>
+ </property>
+ <property name="text">
+ <string>Add Co&amp;mmand</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="KListView" row="0" column="0">
+ <column>
+ <property name="text">
+ <string>Command</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>commandList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>2</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="defaultRenameAction">
+ <enum>Accept</enum>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ <property name="itemsRenameable">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Any commands added here will be run as soon as you are connected to the IRC server.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Any commands added here will be run as soon as you are connected to the IRC server.</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ </hbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>Kopete::UI::PasswordWidget</class>
+ <header location="local">kopetepasswordwidget.h</header>
+ <sizehint>
+ <width>50</width>
+ <height>50</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>1</hordata>
+ <verdata>0</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ <signal>changed()</signal>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="826">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000030149444154388db59531681b5718c77f0e377c070e3c810a3a70e0041eac51852e0a19e45134830a1d9a4c69a04bc8928e990a693a640e1d0c8642b08742321894c1507991b484c890902bb8701a047760c3bd21701fe4201dde49b6a41a32b8df72dcbbeffdbefffbbfefbd5b1b0c07cce266ebe667ae2006c3c1dada0cdc3be87d6e6c35b0d692a409d9c7ec8b20d65ae29398d19b1114e7e3de4ce98b3f5e10dc0053cf0951b4506496e1b964bf7ce6c585d9054c62d01d617ca48be0596553cf496d8f2c8b01c5f795fc93904e85ec4c01a152857a5d9175d0b2805c872080f18595ccc1499a10a225d4e2fbc2877786fe81253ab6c04c8d106e09db5d43ab0d146e5c64d1a23938fb98a185cea1c33eecfd9eba49eb427dcb201e245365f2b7b2fb5b4a3a31dcb927178afe07d86901df870fefa4842aed6f6b74ba42e52b4014d580e1eb9cbd9d94de7e4aad16d2f9be02d805f0b5e532f927a1ffcacea1777f122a8105b164a7c25faf323a5d9f1f1fd600e1e5bec59e2d4b5c7ef5209d0ad17b8b31864e57c0b3e0815ac3ee33253ab664a770ff5185d1a1cb8d2267d3e58aa1dc7d2508cbe597d0e74fdd269aaaf0f52d414c4ea3e9762c996869e42560d7a72e41c4799a2586e74f95e8d8151481fa86efbe7b3398ac58b1a2b8527589f15451ad303ac2293542ad6648a796278f13a27185e4c4754310facb98c53a79e19a3fdc1426ff28c3d7399d1f7cb25343eb96106cf83c790ce9c4f2eb831855c55485663327992eb6dc8a6259874ed700b0b793323cccb9ffa842b30d6133e3e75fea989ac15a8b16ca76b746b0b92278d919774c5b6d48a78697fb29bbcf52468742a32120909c24e899ce67beed5be2db01e22d1e9485bb620e47f9ee9e606a21bd3f5d3744c7e7c54d55e87443867d8b554515ac5db4620e8e4f62263170fd1cdee90aad7640141992891b0f367c9adfe4049bb07d3b7022bd8c687c0978f46684ee084150b65ac1fcca94591b7a90a496e4c095164fb016a2b192a497795cc0f84817aebe25f7bf70ccc54a575c555c03f78ffa5fc0570d1f0c076bff0232285a09643cc7ce0000000049454e44ae426082</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>tabWidget2</tabstop>
+ <tabstop>mNickName</tabstop>
+ <tabstop>mAltNickname</tabstop>
+ <tabstop>mUserName</tabstop>
+ <tabstop>m_realNameLineEdit</tabstop>
+ <tabstop>network</tabstop>
+ <tabstop>editButton</tabstop>
+ <tabstop>preferSSL</tabstop>
+ <tabstop>autoConnect</tabstop>
+ <tabstop>charset</tabstop>
+ <tabstop>partMessage</tabstop>
+ <tabstop>quitMessage</tabstop>
+ <tabstop>serverMessages</tabstop>
+ <tabstop>serverNotices</tabstop>
+ <tabstop>informationReplies</tabstop>
+ <tabstop>errorMessages</tabstop>
+ <tabstop>autoShowServerWindow</tabstop>
+ <tabstop>autoShowAnonWindows</tabstop>
+ <tabstop>ctcpList</tabstop>
+ <tabstop>newCTCP</tabstop>
+ <tabstop>newReply</tabstop>
+ <tabstop>addReply</tabstop>
+ <tabstop>commandList</tabstop>
+ <tabstop>commandEdit</tabstop>
+ <tabstop>addButton</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klistview.h</includehint>
+</includehints>
+</UI>
diff --git a/kopete/protocols/irc/ui/irceditaccountwidget.cpp b/kopete/protocols/irc/ui/irceditaccountwidget.cpp
new file mode 100644
index 00000000..4a1e6ed3
--- /dev/null
+++ b/kopete/protocols/irc/ui/irceditaccountwidget.cpp
@@ -0,0 +1,282 @@
+/*
+ irceditaccountwidget.cpp - IRC Account Widget
+
+ Copyright (c) 2005 by Tommi Rantala <tommi.rantala@cs.helsinki.fi>
+ Copyright (c) 2003 by Olivier Goffart <ogoffart @ kde.org>
+ Copyright (c) 2003 by Jason Keirstead <jason@keirstead.org>
+ Kopete (c) 2003-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "irceditaccountwidget.h"
+
+#include "ircaccount.h"
+#include "ircusercontact.h"
+#include "ircprotocol.h"
+#include "kcodecaction.h"
+
+#include "kircengine.h"
+
+#include "kopetepasswordwidget.h"
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <klistview.h>
+#include <kdebug.h>
+#include <kextsock.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kcharsets.h>
+
+#include <qlabel.h>
+#include <qpopupmenu.h>
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <qconnection.h>
+#include <qvalidator.h>
+#include <qcombobox.h>
+#include <qlistbox.h>
+#include <qlineedit.h>
+
+IRCEditAccountWidget::IRCEditAccountWidget(IRCProtocol *proto, IRCAccount *ident, QWidget *parent, const char * )
+ : IRCEditAccountBase(parent), KopeteEditAccountWidget(ident)
+{
+ mProtocol = proto;
+
+ // default charset/encoding for new accounts: utf-8, see http://www.iana.org/assignments/character-sets
+ int currentCodec = 106;
+
+ if( account() )
+ {
+ QString nickName = account()->mySelf()->nickName();
+ QString serverInfo = account()->accountId();
+
+ mNickName->setText( nickName );
+ mAltNickname->setText( account()->altNick() );
+ mUserName->setText( account()->userName() );
+ m_realNameLineEdit->setText( account()->realName() );
+
+ partMessage->setText( account()->defaultPart() );
+ quitMessage->setText( account()->defaultQuit() );
+ if( account()->codec() )
+ currentCodec = account()->codec()->mibEnum();
+
+ mPasswordWidget->load ( &account()->password() );
+
+ preferSSL->setChecked(account()->configGroup()->readBoolEntry("PreferSSL"));
+ autoShowServerWindow->setChecked( account()->configGroup()->readBoolEntry("AutoShowServerWindow") );
+ autoConnect->setChecked( static_cast<Kopete::Account*>(account())->excludeConnect() );
+
+ KConfigGroup *config = account()->configGroup();
+
+ serverNotices->setCurrentItem( config->readNumEntry( "ServerNotices", IRCAccount::ServerWindow ) - 1 );
+ serverMessages->setCurrentItem( config->readNumEntry( "ServerMessages", IRCAccount::ServerWindow ) - 1 );
+ informationReplies->setCurrentItem( config->readNumEntry( "InformationReplies", IRCAccount::ActiveWindow ) - 1 );
+ errorMessages->setCurrentItem( config->readNumEntry( "ErrorMessages", IRCAccount::ActiveWindow ) - 1 );
+
+ QStringList cmds = account()->connectCommands();
+ for( QStringList::Iterator i = cmds.begin(); i != cmds.end(); ++i )
+ new QListViewItem( commandList, *i );
+
+ const QMap< QString, QString > replies = account()->customCtcpReplies();
+ for( QMap< QString, QString >::ConstIterator it = replies.begin(); it != replies.end(); ++it )
+ new QListViewItem( ctcpList, it.key(), it.data() );
+ }
+
+ mUserName->setValidator( new QRegExpValidator( QString::fromLatin1("^[^\\s]*$"), mUserName ) );
+ mNickName->setValidator( new QRegExpValidator( QString::fromLatin1("^[^#+&][^\\s]*$"), mNickName ) );
+ mAltNickname->setValidator( new QRegExpValidator( QString::fromLatin1("^[^#+&][^\\s]*$"), mAltNickname ) );
+
+ charset->insertStringList( KCodecAction::supportedEncodings() );
+
+ for (int i = 0; i < charset->count(); ++i) {
+ QString encoding = KGlobal::charsets()->encodingForName(charset->text(i));
+
+ if (KGlobal::charsets()->codecForName(encoding)->mibEnum() == currentCodec) {
+ charset->setCurrentItem( i );
+ break;
+ }
+ }
+
+ connect( commandList, SIGNAL( contextMenu( KListView *, QListViewItem *, const QPoint & ) ),
+ this, SLOT( slotCommandContextMenu( KListView *, QListViewItem *, const QPoint & ) ) );
+
+ connect( ctcpList, SIGNAL( contextMenu( KListView *, QListViewItem *, const QPoint & ) ),
+ this, SLOT( slotCtcpContextMenu( KListView *, QListViewItem *, const QPoint & ) ) );
+
+ connect( addButton, SIGNAL( clicked() ), this, SLOT( slotAddCommand() ) );
+ connect( editButton, SIGNAL( clicked() ), this, SLOT(slotEditNetworks() ) );
+ connect( addReply, SIGNAL( clicked() ), this, SLOT( slotAddCtcp() ) );
+
+ connect( network, SIGNAL( activated( const QString & ) ),
+ this, SLOT( slotUpdateNetworkDescription( const QString &) ) );
+
+ connect( IRCProtocol::protocol(), SIGNAL( networkConfigUpdated( const QString & ) ),
+ this, SLOT( slotUpdateNetworks( const QString & ) ) );
+
+ slotUpdateNetworks( QString::null );
+}
+
+IRCEditAccountWidget::~IRCEditAccountWidget()
+{
+}
+
+IRCAccount *IRCEditAccountWidget::account ()
+{
+ return dynamic_cast<IRCAccount *>(KopeteEditAccountWidget::account () );
+}
+
+void IRCEditAccountWidget::slotUpdateNetworks( const QString & selectedNetwork )
+{
+ network->clear();
+
+ uint i = 0;
+ QStringList keys;
+ for( QDictIterator<IRCNetwork> it( IRCProtocol::protocol()->networks() ); it.current(); ++it )
+ keys.append( it.currentKey() );
+
+ keys.sort();
+
+ QStringList::Iterator end = keys.end();
+ for( QStringList::Iterator it = keys.begin(); it != end; ++it )
+ {
+ IRCNetwork * current = IRCProtocol::protocol()->networks()[*it];
+ network->insertItem( current->name );
+ if ( ( account() && account()->networkName() == current->name ) || current->name == selectedNetwork )
+ {
+ network->setCurrentItem( i );
+ description->setText( current->description );
+ }
+ ++i;
+ }
+}
+
+void IRCEditAccountWidget::slotEditNetworks()
+{
+ IRCProtocol::protocol()->editNetworks( network->currentText() );
+}
+
+void IRCEditAccountWidget::slotUpdateNetworkDescription( const QString &network )
+{
+ description->setText(
+ IRCProtocol::protocol()->networks()[ network ]->description
+ );
+}
+
+void IRCEditAccountWidget::slotCommandContextMenu( KListView *, QListViewItem *item, const QPoint &p )
+{
+ QPopupMenu popup;
+ popup.insertItem( i18n("Remove Command"), 1 );
+ if( popup.exec( p ) == 1 )
+ delete item;
+}
+
+void IRCEditAccountWidget::slotCtcpContextMenu( KListView *, QListViewItem *item, const QPoint &p )
+{
+ QPopupMenu popup;
+ popup.insertItem( i18n("Remove CTCP Reply"), 1 );
+ if( popup.exec( p ) == 1 )
+ delete item;
+}
+
+void IRCEditAccountWidget::slotAddCommand()
+{
+ if ( !commandEdit->text().isEmpty() )
+ {
+ new QListViewItem( commandList, commandEdit->text() );
+ commandEdit->clear();
+ }
+}
+
+void IRCEditAccountWidget::slotAddCtcp()
+{
+ if ( !newCTCP->text().isEmpty() && !newReply->text().isEmpty() )
+ {
+ new QListViewItem( ctcpList, newCTCP->text(), newReply->text() );
+ newCTCP->clear();
+ newReply->clear();
+ }
+}
+
+QString IRCEditAccountWidget::generateAccountId( const QString &network )
+{
+ KConfig *config = KGlobal::config();
+ QString nextId = network;
+
+ uint accountNumber = 1;
+ while( config->hasGroup( QString("Account_%1_%2").arg( m_protocol->pluginId() ).arg( nextId ) ) )
+ {
+ nextId = QString::fromLatin1("%1_%2").arg( network ).arg( ++accountNumber );
+ }
+ kdDebug( 14120 ) << k_funcinfo << " ID IS: " << nextId << endl;
+ return nextId;
+}
+
+Kopete::Account *IRCEditAccountWidget::apply()
+{
+ QString nickName = mNickName->text();
+ QString networkName = network->currentText();
+
+ if( !account() )
+ {
+ setAccount( new IRCAccount( mProtocol, generateAccountId(networkName), QString::null, networkName, nickName ) );
+
+ }
+ else
+ {
+ account()->setNickName( nickName );
+ account()->setNetwork( networkName );
+ }
+
+ mPasswordWidget->save( &account()->password() );
+
+ account()->setAltNick( mAltNickname->text() );
+ account()->setUserName( mUserName->text() );
+ account()->setRealName( m_realNameLineEdit->text() );
+ account()->setDefaultPart( partMessage->text() );
+ account()->setDefaultQuit( quitMessage->text() );
+ account()->setAutoShowServerWindow( autoShowServerWindow->isChecked() );
+ account()->setExcludeConnect( autoConnect->isChecked() );
+ account()->setMessageDestinations( serverNotices->currentItem() + 1, serverMessages->currentItem() + 1,
+ informationReplies->currentItem() + 1, errorMessages->currentItem() + 1
+ );
+
+ account()->configGroup()->writeEntry("PreferSSL", preferSSL->isChecked());
+
+ QStringList cmds;
+ for( QListViewItem *i = commandList->firstChild(); i; i = i->nextSibling() )
+ cmds.append( i->text(0) );
+
+ QMap< QString, QString > replies;
+ for( QListViewItem *i = ctcpList->firstChild(); i; i = i->nextSibling() )
+ replies[ i->text(0) ] = i->text(1);
+
+ account()->setCustomCtcpReplies( replies );
+ account()->setConnectCommands( cmds );
+
+ KCharsets *c = KGlobal::charsets();
+ account()->setCodec( c->codecForName( c->encodingForName( charset->currentText() ) ) );
+
+ return account();
+}
+
+
+bool IRCEditAccountWidget::validateData()
+{
+ if( mNickName->text().isEmpty() )
+ KMessageBox::sorry(this, i18n("<qt>You must enter a nickname.</qt>"), i18n("Kopete"));
+ else
+ return true;
+
+ return false;
+}
+
+#include "irceditaccountwidget.moc"
diff --git a/kopete/protocols/irc/ui/irceditaccountwidget.h b/kopete/protocols/irc/ui/irceditaccountwidget.h
new file mode 100644
index 00000000..365acaf3
--- /dev/null
+++ b/kopete/protocols/irc/ui/irceditaccountwidget.h
@@ -0,0 +1,60 @@
+/*
+ irceditaccountwidget.h - IRC Account Widget
+
+ Kopete (c) 2003 by the Kopete developers <kopete-devel@kde.org>
+
+ *************************************************************************
+ * *
+ * 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 option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+
+
+#ifndef IRCEDITACCOUNTWIDEGET_H
+#define IRCEDITACCOUNTWIDEGET_H
+
+#include "editaccountwidget.h"
+#include "irceditaccount.h"
+
+class IRCProtocol;
+class IRCAccount;
+class KListView;
+class QListViewItem;
+
+class IRCEditAccountWidget : public IRCEditAccountBase, public KopeteEditAccountWidget
+{
+ Q_OBJECT
+
+ public:
+ IRCEditAccountWidget(IRCProtocol *proto, IRCAccount *, QWidget *parent=0, const char *name=0);
+ ~IRCEditAccountWidget();
+
+ IRCAccount *account();
+ virtual bool validateData();
+ virtual Kopete::Account *apply();
+
+ private slots:
+ void slotCommandContextMenu( KListView*, QListViewItem*, const QPoint & );
+ void slotCtcpContextMenu( KListView*, QListViewItem*, const QPoint & );
+ void slotAddCommand();
+ void slotAddCtcp();
+ void slotEditNetworks();
+ void slotUpdateNetworks( const QString & );
+ void slotUpdateNetworkDescription( const QString & );
+
+ private:
+ void readNetworks();
+ QString generateAccountId( const QString &network );
+
+ IRCProtocol *mProtocol;
+};
+
+#endif
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/protocols/irc/ui/networkconfig.ui b/kopete/protocols/irc/ui/networkconfig.ui
new file mode 100644
index 00000000..d1000e37
--- /dev/null
+++ b/kopete/protocols/irc/ui/networkconfig.ui
@@ -0,0 +1,382 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>NetworkConfig</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>NetworkConfig</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>670</width>
+ <height>468</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Network Configuration</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLineEdit" row="1" column="4" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>description</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="3">
+ <property name="name">
+ <cstring>textLabel10</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Description:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>description</cstring>
+ </property>
+ </widget>
+ <widget class="QGroupBox" row="2" column="3" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="margin">
+ <number>4</number>
+ </property>
+ <property name="title">
+ <string>Host Con&amp;figuration</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListBox" row="0" column="0" rowspan="3" colspan="4">
+ <property name="name">
+ <cstring>hostList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The IRC servers associated with this network</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The IRC servers associated with this network. Use the up and down buttons to alter the order in which connections are attempted.</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="1" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>password</cstring>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Most IRC servers do not require a password</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="2">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Por&amp;t:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>port</cstring>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="3" column="3" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>port</cstring>
+ </property>
+ <property name="maxValue">
+ <number>65536</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>6667</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Password:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>password</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Host:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>host</cstring>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>host</cstring>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="5" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>useSSL</cstring>
+ </property>
+ <property name="text">
+ <string>Use SS&amp;L</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Check this to enable SSL for this connection</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="6" column="3" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>removeHost</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="6" column="2">
+ <property name="name">
+ <cstring>newHost</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;New...</string>
+ </property>
+ </widget>
+ <spacer row="6" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>210</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="2" column="4">
+ <property name="name">
+ <cstring>downButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Down</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Move this server down</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Move this server down in connection attempt priority</string>
+ </property>
+ </widget>
+ <spacer row="0" column="4">
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>151</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="1" column="4">
+ <property name="name">
+ <cstring>upButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Up</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Move this server up</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Move this server up in connection attempt priority</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QPushButton" row="3" column="6">
+ <property name="name">
+ <cstring>cancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="5">
+ <property name="name">
+ <cstring>saveButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Save</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="0">
+ <property name="name">
+ <cstring>newNetwork</cstring>
+ </property>
+ <property name="text">
+ <string>Ne&amp;w</string>
+ </property>
+ </widget>
+ <widget class="QListBox" row="0" column="0" rowspan="3" colspan="3">
+ <property name="name">
+ <cstring>networkList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer row="3" column="3" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>260</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>renameNetwork</cstring>
+ </property>
+ <property name="text">
+ <string>Rena&amp;me...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="2">
+ <property name="name">
+ <cstring>removeNetwork</cstring>
+ </property>
+ <property name="text">
+ <string>Remo&amp;ve</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>NetworkConfig</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>saveButton</sender>
+ <signal>clicked()</signal>
+ <receiver>NetworkConfig</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>networkList</tabstop>
+ <tabstop>newNetwork</tabstop>
+ <tabstop>renameNetwork</tabstop>
+ <tabstop>removeNetwork</tabstop>
+ <tabstop>description</tabstop>
+ <tabstop>hostList</tabstop>
+ <tabstop>upButton</tabstop>
+ <tabstop>downButton</tabstop>
+ <tabstop>host</tabstop>
+ <tabstop>port</tabstop>
+ <tabstop>password</tabstop>
+ <tabstop>useSSL</tabstop>
+ <tabstop>newHost</tabstop>
+ <tabstop>removeHost</tabstop>
+ <tabstop>saveButton</tabstop>
+ <tabstop>cancelButton</tabstop>
+</tabstops>
+<signals>
+ <signal>accepted()</signal>
+ <signal>rejected()</signal>
+</signals>
+<slots>
+ <slot access="protected">accept()</slot>
+ <slot access="protected">reject()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kopete/protocols/irc/ui/networkconfig.ui.h b/kopete/protocols/irc/ui/networkconfig.ui.h
new file mode 100644
index 00000000..7716e75f
--- /dev/null
+++ b/kopete/protocols/irc/ui/networkconfig.ui.h
@@ -0,0 +1,26 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+
+
+
+
+
+void NetworkConfig::accept()
+{
+ emit accepted();
+ QDialog::accept();
+}
+
+
+void NetworkConfig::reject()
+{
+ emit rejected();
+ QDialog::reject();
+}