diff options
Diffstat (limited to 'kopete/protocols/irc/ircprotocol.cpp')
-rw-r--r-- | kopete/protocols/irc/ircprotocol.cpp | 1241 |
1 files changed, 1241 insertions, 0 deletions
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 <[email protected]> + + Kopete (c) 2002-2004 by the Kopete developers <[email protected]> + + ************************************************************************* + * * + * 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: |