/* ircprotocol - IRC Protocol Copyright (c) 2002 by Nick Betcher Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef KGenericFactory IRCProtocolFactory; K_EXPORT_COMPONENT_FACTORY( kopete_irc, IRCProtocolFactory( "kopete_irc" ) ) IRCProtocol *IRCProtocol::s_protocol = 0L; IRCProtocolHandler::IRCProtocolHandler() : Kopete::MimeTypeHandler( false ) { registerAsProtocolHandler( TQString::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; TQString chan = url.url().section('/',3); if( chan.isEmpty() ) return; KUser user( getuid() ); TQString accountId = TQString::fromLatin1("%1@%2:%3").arg( user.loginName(), url.host(), TQString::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( TQObject *parent, const char *name, const TQStringList & /* args */ ) : Kopete::Protocol( IRCProtocolFactory::instance(), parent, name ), m_ServerStatusOnline(Kopete::OnlineStatus::Online, 100, this, OnlineServer, TQString(), i18n("Online")), m_ServerStatusOffline(Kopete::OnlineStatus::Offline, 90, this, OfflineServer, TQString(), i18n("Offline")), m_ChannelStatusOnline(Kopete::OnlineStatus::Online, 80, this, OnlineChannel, TQString(), i18n("Online")), m_ChannelStatusOffline(Kopete::OnlineStatus::Offline, 70, this, OfflineChannel, TQString(), i18n("Offline")), m_UserStatusOpVoice(Kopete::OnlineStatus::Online, 60, this, Online | Operator | Voiced, TQStringList::split(' ',"irc_voice irc_op"), i18n("Op")), m_UserStatusOpVoiceAway(Kopete::OnlineStatus::Away, 55, this, Online | Operator | Voiced | Away, TQStringList::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, TQStringList::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, TQStringList::split(' ',"irc_voice contact_away_overlay"), i18n("Away")), m_UserStatusOnline(Kopete::OnlineStatus::Online, 25, this, Online, TQString(), 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, TQString(), i18n("Offline"), i18n("Offline"), Kopete::OnlineStatusManager::Offline), m_StatusUnknown(Kopete::OnlineStatus::Unknown, 999, this, 999, "status_unknown", i18n("Status not available")), propChannelTopic(TQString::fromLatin1("channelTopic"), i18n("Topic"), TQString(), false, true ), propChannelMembers(TQString::fromLatin1("channelMembers"), i18n("Members")), propHomepage(TQString::fromLatin1("homePage"), i18n("Home Page")), propLastSeen(Kopete::Global::Properties::self()->lastSeen()), propUserInfo(TQString::fromLatin1("userInfo"), i18n("IRC User")), propServer(TQString::fromLatin1("ircServer"), i18n("IRC Server")), propChannels( TQString::fromLatin1("ircChannels"), i18n("IRC Channels")), propHops(TQString::fromLatin1("ircHops"), i18n("IRC Hops")), propFullName(TQString::fromLatin1("FormattedName"), i18n("Full Name")), propIsIdentified(TQString::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, TQString::fromLatin1("raw"), TQT_SLOT( slotRawCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /raw - Sends the text in raw form to the server."), 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("quote"), TQT_SLOT( slotQuoteCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /quote - Sends the text in quoted form to the server."), 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("ctcp"), TQT_SLOT( slotCtcpCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /ctcp - Send the CTCP message to nick."), 2 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("ping"), TQT_SLOT( slotPingCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /ping - Alias for /CTCP PING."), 1, 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("motd"), TQT_SLOT( slotMotdCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /motd [] - Shows the message of the day for the current or the given server.") ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("list"), TQT_SLOT( slotListCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /list - List the public channels on the server.") ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("join"), TQT_SLOT( slotJoinCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /join <#channel 1> [] - Joins the specified channel."), 1, 2 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("topic"), TQT_SLOT( slotTopicCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /topic [] - Sets and/or displays the topic for the active channel.") ); //FIXME: Update help text Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("whois"), TQT_SLOT( slotWhoisCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /whois - Display whois info on this user."), 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("whowas"), TQT_SLOT( slotWhoWasCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /whowas - Display whowas info on this user."), 1, 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("who"), TQT_SLOT( slotWhoCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /who - Display who info on this user/channel."), 1, 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("query"), TQT_SLOT( slotQueryCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /query [] - Open a private chat with this user."), 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("mode"), TQT_SLOT( slotModeCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /mode - Set modes on the given channel."), 2 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("nick"), TQT_SLOT( slotNickCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /nick - Change your nickname to the given one."), 1, 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("me"), TQT_SLOT( slotMeCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /me - Do something."), 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("ame"), TQT_SLOT( slotAllMeCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /ame - Do something in every open chat."), 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("kick"), TQT_SLOT( slotKickCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /kick [] - Kick someone from the channel (requires operator status).") , 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("ban"), TQT_SLOT( slotBanCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /ban - Add someone to this channel's ban list. (requires operator status)."), 1, 1 ); Kopete::CommandHandler::commandHandler()->registerAlias( this, TQString::fromLatin1("bannick"), TQString::fromLatin1("ban %1!*@*"), i18n("USAGE: /bannick - 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, TQString::fromLatin1("op"), TQT_SLOT( slotOpCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /op [ <...>] - Give channel operator status to someone (requires operator status)."), 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("deop"), TQT_SLOT( slotDeopCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /deop [ <...>]- Remove channel operator status from someone (requires operator status)."), 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("voice"), TQT_SLOT( slotVoiceCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /voice [ <...>]- Give channel voice status to someone (requires operator status)."), 1); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("devoice"), TQT_SLOT( slotDevoiceCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /devoice [ <...>]- Remove channel voice status from someone (requires operator status)."), 1 ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("quit"), TQT_SLOT( slotQuitCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /quit [] - Disconnect from IRC, optionally leaving a message.") ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("part"), TQT_SLOT( slotPartCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /part [] - Part from a channel, optionally leaving a message.") ); Kopete::CommandHandler::commandHandler()->registerCommand( this, TQString::fromLatin1("invite"), TQT_SLOT( slotInviteCommand( const TQString &, Kopete::ChatSession*) ), i18n("USAGE: /invite [] - Invite a user to join a channel."), 1 ); Kopete::CommandHandler::commandHandler()->registerAlias( this, TQString::fromLatin1("j"), TQString::fromLatin1("join %1"), i18n("USAGE: /j <#channel 1> [] - Alias for JOIN."), Kopete::CommandHandler::SystemAlias, 1, 2 ); Kopete::CommandHandler::commandHandler()->registerAlias( this, TQString::fromLatin1("msg"), TQString::fromLatin1("query %s"), i18n("USAGE: /msg [] - Alias for QUERY ."), Kopete::CommandHandler::SystemAlias, 1 ); TQObject::connect( Kopete::ChatSessionManager::self(), TQT_SIGNAL(aboutToDisplay(Kopete::Message &)), this, TQT_SLOT(slotMessageFilter(Kopete::Message &)) ); TQObject::connect( Kopete::ChatSessionManager::self(), TQT_SIGNAL( viewCreated( KopeteView* ) ), this, TQT_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 ) { TQString messageText = msg.escapedBody(); //Add right click for channels, only replace text not in HTML tags messageText.replace( TQRegExp( TQString::fromLatin1("(?![^<]+>)(#[^#\\s]+)(?![^<]+>)") ), TQString::fromLatin1("\\1") ); msg.setBody( messageText, Kopete::Message::RichText ); } } TQPtrList *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( m.from()->account() ); if( e.getAttribute( TQString::fromLatin1("type") ) == TQString::fromLatin1("IRCChannel") ) return activeAccount->contactManager()->findChannel( e.innerText().string() )->customContextMenuActions(); } return 0L; } AddContactPage *IRCProtocol::createAddContactWidget(TQWidget *parent, Kopete::Account *account) { return new IRCAddContactPage(parent,static_cast(account)); } KopeteEditAccountWidget *IRCProtocol::createEditAccountWidget(Kopete::Account *account, TQWidget *parent) { return new IRCEditAccountWidget(this, static_cast(account),parent); } Kopete::Account *IRCProtocol::createNewAccount(const TQString &accountId) { return new IRCAccount( this, accountId ); } Kopete::Contact *IRCProtocol::deserializeContact( Kopete::MetaContact *metaContact, const TQMap &serializedData, const TQMap & /* addressBookData */ ) { kdDebug(14120) << k_funcinfo << endl; TQString contactId = serializedData[ "contactId" ]; TQString displayName = serializedData[ "displayName" ]; if( displayName.isEmpty() ) displayName = contactId; TQDict 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 TQString &args, Kopete::ChatSession *manager ) { IRCAccount *account = static_cast( 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 TQString &args, Kopete::ChatSession *manager ) { IRCAccount *account = static_cast( 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 TQString &args, Kopete::ChatSession *manager ) { if( !args.isEmpty() ) { TQString user = args.section( ' ', 0, 0 ); TQString message = args.section( ' ', 1 ); static_cast( manager->account() )->engine()->writeCtcpQueryMessage( user, TQString(), message ); } } void IRCProtocol::slotMotdCommand( const TQString &args, Kopete::ChatSession *manager ) { TQStringList argsList = Kopete::CommandHandler::parseArguments( args ); static_cast( manager->account() )->engine()->motd(argsList.front()); } void IRCProtocol::slotPingCommand( const TQString &args, Kopete::ChatSession *manager ) { TQStringList argsList = Kopete::CommandHandler::parseArguments(args); static_cast( manager->account() )->engine()->CtcpRequest_ping(argsList.front()); } void IRCProtocol::slotListCommand( const TQString &/*args*/, Kopete::ChatSession *manager ) { static_cast( manager->account() )->listChannels(); } void IRCProtocol::slotTopicCommand( const TQString &args, Kopete::ChatSession *manager ) { Kopete::ContactPtrList members = manager->members(); IRCChannelContact *chan = dynamic_cast( members.first() ); if( chan ) { if( !args.isEmpty() ) chan->setTopic( args ); else { static_cast(manager->account())->engine()-> writeRawMessage(TQString::fromLatin1("TOPIC %1").arg(chan->nickName())); } } else { static_cast( manager->account() )->appendMessage( i18n("You must be in a channel to use this command."), IRCAccount::ErrorReply ); } } void IRCProtocol::slotJoinCommand( const TQString &arg, Kopete::ChatSession *manager ) { TQStringList args = Kopete::CommandHandler::parseArguments( arg ); if( KIRC::Entity::isChannel(args[0]) ) { IRCChannelContact *chan = static_cast( manager->account() )->contactManager()->findChannel( args[0] ); if( args.count() == 2 ) chan->setPassword( args[1] ); static_cast( manager->account() )->engine()->join(args[0], chan->password()); } else { static_cast( manager->account() )->appendMessage( i18n("\"%1\" is an invalid channel. Channels must start with '#', '!', '+', or '&'.") .arg(args[0]), IRCAccount::ErrorReply ); } } void IRCProtocol::slotInviteCommand( const TQString &args, Kopete::ChatSession *manager ) { IRCChannelContact *c = 0L; TQStringList argsList = Kopete::CommandHandler::parseArguments( args ); if( argsList.count() > 1 ) { if( KIRC::Entity::isChannel(argsList[1]) ) { c = static_cast( manager->account() )->contactManager()-> findChannel( argsList[1] ); } else { static_cast( 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( members.first() ); } if( c && c->manager()->contactOnlineStatus( manager->myself() ) == m_UserStatusOp ) { static_cast( manager->account() )->engine()->writeMessage( TQString::fromLatin1("INVITE %1 %2").arg( argsList[0] ). arg( c->nickName() ) ); } else { static_cast( manager->account() )->appendMessage( i18n("You must be a channel operator to perform this operation."), IRCAccount::ErrorReply ); } } void IRCProtocol::slotQueryCommand( const TQString &args, Kopete::ChatSession *manager ) { TQString user = args.section( ' ', 0, 0 ); TQString rest = args.section( ' ', 1 ); if( !KIRC::Entity::isChannel(user) ) { IRCUserContact *c = static_cast( 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( manager->account() )->appendMessage( i18n("\"%1\" is an invalid nickname. Nicknames must not start with '#','!','+', or '&'.").arg(user), IRCAccount::ErrorReply ); } } void IRCProtocol::slotWhoisCommand( const TQString &args, Kopete::ChatSession *manager ) { static_cast( manager->account() )->engine()->whois( args ); static_cast( manager->account() )->setCurrentCommandSource( manager ); } void IRCProtocol::slotWhoCommand( const TQString &args, Kopete::ChatSession *manager ) { TQStringList argsList = Kopete::CommandHandler::parseArguments( args ); static_cast( manager->account() )->engine()->writeMessage( TQString::fromLatin1("WHO %1").arg( argsList.first() ) ); static_cast( manager->account() )->setCurrentCommandSource( manager ); } void IRCProtocol::slotWhoWasCommand( const TQString &args, Kopete::ChatSession *manager ) { TQStringList argsList = Kopete::CommandHandler::parseArguments( args ); static_cast( manager->account() )->engine()->writeMessage( TQString::fromLatin1("WHOWAS %1").arg( argsList.first() ) ); static_cast( manager->account() )->setCurrentCommandSource( manager ); } void IRCProtocol::slotQuitCommand( const TQString &args, Kopete::ChatSession *manager ) { static_cast( manager->account() )->quit( args ); } void IRCProtocol::slotNickCommand( const TQString &args, Kopete::ChatSession *manager ) { TQStringList argsList = Kopete::CommandHandler::parseArguments( args ); static_cast( manager->account() )->engine()->nick( argsList.front() ); } void IRCProtocol::slotModeCommand(const TQString &args, Kopete::ChatSession *manager) { TQStringList argsList = Kopete::CommandHandler::parseArguments( args ); static_cast( manager->account() )->engine()->mode( argsList.front(), args.section( TQRegExp(TQString::fromLatin1("\\s+")), 1 ) ); } void IRCProtocol::slotMeCommand(const TQString &args, Kopete::ChatSession *manager) { Kopete::ContactPtrList members = manager->members(); static_cast( manager->account() )->engine()->CtcpRequest_action( static_cast(members.first())->nickName(), args ); } void IRCProtocol::slotAllMeCommand(const TQString &args, Kopete::ChatSession *) { TQValueList sessions = Kopete::ChatSessionManager::self()->sessions(); for( TQValueList::iterator it = sessions.begin(); it != sessions.end(); ++it ) { Kopete::ChatSession *session = *it; if( session->protocol() == this ) slotMeCommand(args, session); } } void IRCProtocol::slotKickCommand(const TQString &args, Kopete::ChatSession *manager) { if (manager->contactOnlineStatus( manager->myself() ) == m_UserStatusOp) { TQRegExp spaces(TQString::fromLatin1("\\s+")); TQString nick = args.section( spaces, 0, 0); TQString reason = args.section( spaces, 1); Kopete::ContactPtrList members = manager->members(); TQString channel = static_cast( members.first() )->nickName(); if (KIRC::Entity::isChannel(channel)) static_cast(manager->account())->engine()->kick(nick, channel, reason); } else { static_cast( manager->account() )->appendMessage( i18n("You must be a channel operator to perform this operation."), IRCAccount::ErrorReply ); } } void IRCProtocol::slotBanCommand( const TQString &args, Kopete::ChatSession *manager ) { if( manager->contactOnlineStatus( manager->myself() ) == m_UserStatusOp ) { TQStringList argsList = Kopete::CommandHandler::parseArguments( args ); Kopete::ContactPtrList members = manager->members(); IRCChannelContact *chan = static_cast( members.first() ); if( chan && chan->locateUser( argsList.front() ) ) chan->setMode( TQString::fromLatin1("+b %1").arg( argsList.front() ) ); } else { static_cast( manager->account() )->appendMessage( i18n("You must be a channel operator to perform this operation."), IRCAccount::ErrorReply ); } } void IRCProtocol::slotPartCommand( const TQString &args, Kopete::ChatSession *manager ) { TQStringList argsList = Kopete::CommandHandler::parseArguments(args); Kopete::ContactPtrList members = manager->members(); IRCChannelContact *chan = static_cast(members.first()); if (chan) { if(!args.isEmpty()) static_cast(manager->account())->engine()->part(chan->nickName(), args); else chan->part(); if( manager->view() ) manager->view()->closeView(true); } else { static_cast( manager->account() )->appendMessage( i18n("You must be in a channel to use this command."), IRCAccount::ErrorReply ); } } void IRCProtocol::slotOpCommand( const TQString &args, Kopete::ChatSession *manager ) { simpleModeChange( args, manager, TQString::fromLatin1("+o") ); } void IRCProtocol::slotDeopCommand( const TQString &args, Kopete::ChatSession *manager ) { simpleModeChange( args, manager, TQString::fromLatin1("-o") ); } void IRCProtocol::slotVoiceCommand( const TQString &args, Kopete::ChatSession *manager ) { simpleModeChange( args, manager, TQString::fromLatin1("+v") ); } void IRCProtocol::slotDevoiceCommand( const TQString &args, Kopete::ChatSession *manager ) { simpleModeChange( args, manager, TQString::fromLatin1("-v") ); } void IRCProtocol::simpleModeChange( const TQString &args, Kopete::ChatSession *manager, const TQString &mode ) { if( manager->contactOnlineStatus( manager->myself() ) == m_UserStatusOp ) { TQStringList argsList = Kopete::CommandHandler::parseArguments( args ); Kopete::ContactPtrList members = manager->members(); IRCChannelContact *chan = static_cast( members.first() ); if( chan ) { for( TQStringList::iterator it = argsList.begin(); it != argsList.end(); ++it ) { if( chan->locateUser( *it ) ) chan->setMode( TQString::fromLatin1("%1 %2").arg( mode ).arg( *it ) ); } } } else { static_cast( manager->account() )->appendMessage( i18n("You must be a channel operator to perform this operation."), IRCAccount::ErrorReply ); } } void IRCProtocol::editNetworks( const TQString &networkName ) { if( !netConf ) { netConf = new NetworkConfig( Kopete::UI::Global::mainWidget(), "network_config", true ); netConf->host->setValidator( new TQRegExpValidator( TQString::fromLatin1("^[\\w-\\.]*$"), TQT_TQOBJECT(netConf) ) ); netConf->upButton->setIconSet( SmallIconSet( "go-up" ) ); netConf->downButton->setIconSet( SmallIconSet( "go-down" ) ); connect( netConf->networkList, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkConfig() ) ); connect( netConf->hostList, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkHostConfig() ) ); connect( netConf, TQT_SIGNAL( accepted() ), this, TQT_SLOT( slotSaveNetworkConfig() ) ); connect( netConf, TQT_SIGNAL( rejected() ), this, TQT_SLOT( slotReadNetworks() ) ); connect( netConf->upButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotMoveServerUp() ) ); connect( netConf->downButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotMoveServerDown() ) ); connect( netConf->removeNetwork, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotDeleteNetwork() ) ); connect( netConf->removeHost, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotDeleteHost() ) ); connect( netConf->newHost, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotNewHost() ) ); connect( netConf->newNetwork, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotNewNetwork() ) ); connect( netConf->renameNetwork, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotRenameNetwork() ) ); connect( netConf->port, TQT_SIGNAL( valueChanged( int ) ), this, TQT_SLOT( slotHostPortChanged( int ) ) ); connect( netConf->networkList, TQT_SIGNAL( doubleClicked ( TQListBoxItem * )), TQT_SLOT(slotRenameNetwork())); } disconnect( netConf->networkList, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkConfig() ) ); disconnect( netConf->hostList, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkHostConfig() ) ); netConf->networkList->clear(); for( TQDictIterator it( m_networks ); it.current(); ++it ) { IRCNetwork *net = it.current(); netConf->networkList->insertItem( net->name ); } netConf->networkList->sort(); connect( netConf->networkList, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkConfig() ) ); connect( netConf->hostList, TQT_SIGNAL( selectionChanged() ), this, TQT_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( TQValueList::iterator it = net->hosts.begin(); it != net->hosts.end(); ++it ) netConf->hostList->insertItem( (*it)->host + TQString::fromLatin1(":") + TQString::number((*it)->port) ); // prevent nested event loop crash disconnect( netConf->hostList, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkHostConfig() ) ); netConf->hostList->setSelected( 0, true ); slotUpdateNetworkHostConfig(); connect( netConf->hostList, TQT_SIGNAL( selectionChanged() ), this, TQT_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 ) { TQString entryText = m_uiCurrentHostSelection + TQString::fromLatin1(":") + TQString::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, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkHostConfig() ) ); netConf->hostList->changeItem( entryText, netConf->hostList->currentItem() ); connect( netConf->hostList, TQT_SIGNAL( selectionChanged() ), this, TQT_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, TQT_SIGNAL( valueChanged( int ) ), this, TQT_SLOT( slotHostPortChanged( int ) ) ); netConf->port->setValue( host->port ); connect( netConf->port, TQT_SIGNAL( valueChanged( int ) ), this, TQT_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 = TQString(); disconnect( netConf->port, TQT_SIGNAL( valueChanged( int ) ), this, TQT_SLOT( slotHostPortChanged( int ) ) ); netConf->host->clear(); netConf->password->clear(); netConf->port->setValue( 6667 ); netConf->useSSL->setChecked( false ); connect( netConf->port, TQT_SIGNAL( valueChanged( int ) ), this, TQT_SLOT( slotHostPortChanged( int ) ) ); } } void IRCProtocol::slotDeleteNetwork() { TQString network = netConf->networkList->currentText(); if( KMessageBox::warningContinueCancel( Kopete::UI::Global::mainWidget(), i18n("Are you sure you want to delete the network %1?
" "Any accounts which use this network will have to be modified.
") .arg(network), i18n("Deleting Network"), KGuiItem(i18n("&Delete Network"),"edit-delete"), TQString::fromLatin1("AskIRCDeleteNetwork") ) == KMessageBox::Continue ) { disconnect( netConf->networkList, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkConfig() ) ); disconnect( netConf->hostList, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkHostConfig() ) ); IRCNetwork *net = m_networks[ network ]; for( TQValueList::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, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkConfig() ) ); connect( netConf->hostList, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkHostConfig() ) ); slotUpdateNetworkHostConfig(); } } void IRCProtocol::slotDeleteHost() { TQString hostName = netConf->host->text(); if ( KMessageBox::warningContinueCancel( Kopete::UI::Global::mainWidget(), i18n("Are you sure you want to delete the host %1?") .arg(hostName), i18n("Deleting Host"), KGuiItem(i18n("&Delete Host"),"edit-delete"), TQString::fromLatin1("AskIRCDeleteHost")) == KMessageBox::Continue ) { IRCHost *host = m_hosts[ hostName ]; if ( host ) { disconnect( netConf->hostList, TQT_SIGNAL( selectionChanged() ), this, TQT_SLOT( slotUpdateNetworkHostConfig() ) ); TQString entryText = host->host + TQString::fromLatin1(":") + TQString::number(host->port); TQListBoxItem * justAdded = netConf->hostList->findItem( entryText ); netConf->hostList->removeItem( netConf->hostList->index( justAdded ) ); connect( netConf->hostList, TQT_SIGNAL( selectionChanged() ), this, TQT_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) TQString netName = TQString::fromLatin1( "New Network" ); if ( m_networks.find( netName ) ) { int newIdx = 1; do { netName = TQString::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 ); TQListBoxItem * 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; TQString name = KInputDialog::getText( i18n("New Host"), i18n("Enter the hostname of the new server:"), TQString(), &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 TQString entryText = host->host + TQString::fromLatin1(":") + TQString::number(host->port); netConf->hostList->insertItem( entryText ); // select it in the gui TQListBoxItem * 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 TQString 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(); TQDomDocument doc("irc-networks"); TQDomNode root = doc.appendChild( doc.createElement("networks") ); for( TQDictIterator it( m_networks ); it.current(); ++it ) { IRCNetwork *net = it.current(); TQDomNode networkNode = root.appendChild( doc.createElement("network") ); TQDomNode nameNode = networkNode.appendChild( doc.createElement("name") ); nameNode.appendChild( doc.createTextNode( net->name ) ); TQDomNode descNode = networkNode.appendChild( doc.createElement("description") ); descNode.appendChild( doc.createTextNode( net->description ) ); TQDomNode serversNode = networkNode.appendChild( doc.createElement("servers") ); for( TQValueList::iterator it2 = net->hosts.begin(); it2 != net->hosts.end(); ++it2 ) { TQDomNode serverNode = serversNode.appendChild( doc.createElement("server") ); TQDomNode hostNode = serverNode.appendChild( doc.createElement("host") ); hostNode.appendChild( doc.createTextNode( (*it2)->host ) ); TQDomNode portNode = serverNode.appendChild( doc.createElement("port" ) ); portNode.appendChild( doc.createTextNode( TQString::number( (*it2)->port ) ) ); TQDomNode sslNode = serverNode.appendChild( doc.createElement("useSSL") ); sslNode.appendChild( doc.createTextNode( (*it2)->ssl ? "true" : "false" ) ); } } // kdDebug(14121) << k_funcinfo << doc.toString(4) << endl; TQFile xmlFile( locateLocal( "appdata", "ircnetworks.xml" ) ); if (xmlFile.open(IO_WriteOnly)) { TQTextStream 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(); TQFile xmlFile( locate( "appdata", "ircnetworks.xml" ) ); xmlFile.open( IO_ReadOnly ); TQDomDocument doc; doc.setContent( &xmlFile ); TQDomElement networkNode = doc.documentElement().firstChild().toElement(); while( !networkNode.isNull () ) { IRCNetwork *net = new IRCNetwork; TQDomElement 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" ) { TQDomElement server = networkChild.firstChild().toElement(); while( !server.isNull() ) { IRCHost *host = new IRCHost; TQDomElement 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; TQValueList::iterator pos = selectedNetwork->hosts.find( selectedHost ); if( pos != selectedNetwork->hosts.begin() ) { TQValueList::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 ); TQString entryText = selectedHost->host + TQString::fromLatin1(":") + TQString::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; TQValueList::iterator pos = selectedNetwork->hosts.find( selectedHost ); if( *pos != selectedNetwork->hosts.back() ) { TQValueList::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 ); TQString entryText = selectedHost->host + TQString::fromLatin1(":") + TQString::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: