begin my work on the IRC-protocol, making the editaccount dialog and the network...
[kdenetwork.git] / kopete / protocols / irc / ircprotocol.cpp
blob48d1198a67a0daf71b5d284285a3115825f1980a
1 /*
2 ircprotocol - IRC Protocol
4 Copyright (c) 2002 by Nick Betcher <nbetcher@kde.org>
5 Copyright (c) 2003-2007 by Michel Hermier <michel.hermier@gmail.com>
7 Kopete (c) 2002-2007 by the Kopete developers <kopete-devel@kde.org>
9 *************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 *************************************************************************
19 #include "ircprotocol.moc"
21 #include "ircaccount.h"
22 #include "irccontact.h"
23 #include "irctransferhandler.h"
24 #include "ksparser.h"
26 #include "networkconfigwidget.h"
27 //#include "channellist.h"
28 #include "ircaddcontactpage.h"
29 //#include "ircguiclient.h"
30 #include "irceditaccountwidget.h"
32 #include "kircclientsocket.h"
34 #include "kopeteaccountmanager.h"
35 #include "kopetechatsessionmanager.h"
36 #include "kopetecommandhandler.h"
37 #include "kopeteglobal.h"
38 #include "kopeteonlinestatusmanager.h"
39 #include "kopeteonlinestatus.h"
40 #include "kopeteview.h"
41 #include "kopeteuiglobal.h"
43 #include <kaboutdata.h>
44 #include <kaction.h>
45 #include <kcharsets.h>
46 #include <kdebug.h>
47 #include <kgenericfactory.h>
48 #include <kglobal.h>
49 #include <kinputdialog.h>
50 #include <kiconloader.h>
51 #include <kmessagebox.h>
52 #include <kstandarddirs.h>
53 #include <kuser.h>
55 #include <qcheckbox.h>
56 #include <qdom.h>
57 #include <qfile.h>
58 #include <qlineedit.h>
59 #include <qpushbutton.h>
60 #include <qregexp.h>
61 #include <qspinbox.h>
62 #include <qvalidator.h>
64 #include <dom/html_element.h>
65 #include <unistd.h>
67 using namespace Kopete;
69 K_PLUGIN_FACTORY( IRCProtocolFactory, registerPlugin<IRCProtocol>(); )
70 K_EXPORT_PLUGIN( IRCProtocolFactory( "kopete_irc" ) )
72 static IRCProtocol *s_protocol = 0L;
74 IRCProtocolHandler::IRCProtocolHandler()
75 : MimeTypeHandler(false)
77 registerAsProtocolHandler(QString::fromLatin1("irc"));
80 void IRCProtocolHandler::handleURL(const KUrl &url) const
82 kDebug(14120) << url;
83 if (!url.isValid())
84 return;
86 unsigned short port = url.port();
87 if (port == 0)
88 port = 6667;
90 QString chan = url.url().section('/',3);
91 if (chan.isEmpty())
92 return;
94 KUser user(getuid());
95 QString accountId = QString::fromLatin1("%1@%2:%3").arg(
96 user.loginName(),
97 url.host(),
98 QString::number(port)
101 kDebug(14120) << accountId;
103 IRCAccount *newAccount = new IRCAccount( accountId, chan );
104 newAccount->setNickName( user.loginName() );
105 newAccount->setUserName( user.loginName() );
106 newAccount->connect();
109 IRCProtocol::IRCProtocol( QObject *parent, const QVariantList & /* args */ )
110 : Protocol(IRCProtocolFactory::componentData(), parent)
111 // , m_StatusUnknown(OnlineStatus::Unknown, 999, this, 999, "status_unknown", i18n("Status not available"))
113 kDebug(14120) ;
115 s_protocol = this;
117 initOnlineStatus();
119 //m_status = m_unknownStatus = m_Unknown;
121 addAddressBookField("messaging/irc", Plugin::MakeIndexField);
123 CommandHandler *commandHandler = CommandHandler::self();
125 // Statically implemented commands
126 commandHandler->registerCommand(this, QString::fromLatin1("all"),
127 SLOT( slotAllCommand(const QString &, Kopete::ChatSession*)),
128 i18n("USAGE: /all <command> - Exectute the given command in all the chats."), 2);
130 commandHandler->registerCommand(this, QString::fromLatin1("ctcp"),
131 SLOT( slotCtcpCommand(const QString &, Kopete::ChatSession *)),
132 i18n("USAGE: /ctcp <nick> <message> - Send the CTCP message to nick."), 2);
134 commandHandler->registerCommand(this, QString::fromLatin1("quote"),
135 SLOT( slotQuoteCommand(const QString &, Kopete::ChatSession*)),
136 i18n("USAGE: /quote <text> - Sends the text in quoted form to the server."), 1);
138 commandHandler->registerCommand(this, QString::fromLatin1("raw"),
139 SLOT( slotRawCommand( const QString &, Kopete::ChatSession*)),
140 i18n("USAGE: /raw <text> - Sends the text in raw form to the server."), 1);
142 // Alias implemented commands
143 commandHandler->registerAlias(this, QString::fromLatin1("ame"),
144 QString::fromLatin1("all ME"),
145 i18n("USAGE: /ame <action> - Do something in every open chat."),
146 CommandHandler::SystemAlias, 1);
148 commandHandler->registerAlias(this, QString::fromLatin1("ban"),
149 SLOT(slotBanCommand(const QString &, Kopete::ChatSession*)),
150 i18n("USAGE: /ban <mask> - Add someone to this channel's ban list. (requires operator status)."),
151 CommandHandler::SystemAlias, 1, 1);
153 /* commandHandler->registerAlias(this, QString::fromLatin1("bannick"),
154 QString::fromLatin1("ban %1!*@*"),
155 i18n("USAGE: /bannick <nickname> - Add someone to this channel's ban list. Uses the hostmask nickname!*@* (requires operator status)."),
156 CommandHandler::SystemAlias, 1, 1);
158 commandHandler->registerAlias(this, QString::fromLatin1("deop"),
159 SLOT(slotDeopCommand(const QString &, Kopete::ChatSession*)),
160 i18n("USAGE: /deop <nickname> [<nickname 2> <...>] - Remove channel operator status from someone (requires operator status)."),
161 CommandHandler::SystemAlias, 1);
163 commandHandler->registerAlias(this, QString::fromLatin1("devoice"),
164 SLOT( slotDevoiceCommand( const QString &, Kopete::ChatSession*) ),
165 i18n("USAGE: /devoice <nickname> [<nickname 2> <...>] - Remove channel voice status from someone (requires operator status)."),
166 CommandHandler::SystemAlias, 1);
168 commandHandler->registerAlias(this, QString::fromLatin1("invite"),
169 QString::fromLatin1("raw invite %s"),
170 i18n("USAGE: /invite <nickname> [<channel>] - Invite a user to join a channel."),
171 CommandHandler::SystemAlias, 1);
173 commandHandler->registerAlias(this, QString::fromLatin1("join"),
174 QString::fromLatin1("raw join %s"),
175 i18n("USAGE: /join <#channel 1> [<password>] - Joins the specified channel."),
176 CommandHandler::SystemAlias, 1, 2);
178 commandHandler->registerAlias( this, QString::fromLatin1("kick"),
179 SLOT( slotKickCommand( const QString &, Kopete::ChatSession*) ),
180 i18n("USAGE: /kick <nickname> [<reason>] - Kick someone from the channel (requires operator status)."),
181 CommandHandler::SystemAlias, 1);
183 commandHandler->registerAlias(this, QString::fromLatin1("list"),
184 QString::fromLatin1( "raw list %s"),
185 i18n("USAGE: /list - List the public channels on the server."),
186 CommandHandler::SystemAlias );
188 commandHandler->registerAlias(this, QString::fromLatin1("me"),
189 QString::fromLatin1("ctcp me"),
190 i18n("USAGE: /me <action> - Do something."),
191 CommandHandler::SystemAlias, 1 );
193 // FIX help string, MODE is also available for user
194 commandHandler->registerAlias( this, QString::fromLatin1("mode"),
195 QString::fromLatin1("raw mode %s"),
196 i18n("USAGE: /mode <channel> <modes> - Set modes on the given channel."),
197 CommandHandler::SystemAlias, 2);
199 commandHandler->registerAlias(this, QString::fromLatin1("motd"),
200 QString::fromLatin1("raw motd %s"),
201 i18n("USAGE: /motd [<server>] - Shows the message of the day for the current or the given server."),
202 CommandHandler::SystemAlias);
204 commandHandler->registerAlias(this, QString::fromLatin1("nick"),
205 QString::fromLatin1 ("raw nick %s"),
206 i18n("USAGE: /nick <nickname> - Change your nickname to the given one."),
207 CommandHandler::SystemAlias, 1, 1);
209 commandHandler->registerAlias(this, QString::fromLatin1("op"),
210 SLOT( slotOpCommand(const QString &, Kopete::ChatSession*)),
211 i18n("USAGE: /op <nickname 1> [<nickname 2> <...>] - Give channel operator status to someone (requires operator status)."),
212 CommandHandler::SystemAlias, 1);
214 commandHandler->registerAlias(this, QString::fromLatin1("part"),
215 QString::fromLatin1( "raw part %c :%s" ),
216 i18n("USAGE: /part [<reason>] - Part from a channel, optionally leaving a message."),
217 CommandHandler::SystemAlias);
219 commandHandler->registerAlias(this, QString::fromLatin1("ping"),
220 QString::fromLatin1( "ctcp %1 PING" ),
221 i18n("USAGE: /ping <nickname> - Alias for /CTCP <nickname> PING."),
222 CommandHandler::SystemAlias, 1, 1);*/
224 commandHandler->registerCommand(this, QString::fromLatin1("query"),
225 SLOT(slotQueryCommand(const QString &, Kopete::ChatSession*)),
226 i18n("USAGE: /query <nickname> [<message>] - Open a private chat with this user."),
227 CommandHandler::SystemAlias, 1);
229 /* commandHandler->registerAlias(this, QString::fromLatin1("quit"),
230 QString::fromLatin1("raw quit :%s"),
231 i18n("USAGE: /quit [<reason>] - Disconnect from IRC, optionally leaving a message."),
232 CommandHandler::SystemAlias);*/
234 commandHandler->registerAlias(this, QString::fromLatin1("topic"),
235 QString::fromLatin1("raw TOPIC :%s"),
236 i18n("USAGE: /topic [<topic>] - Sets and/or displays the topic for the active channel."),
237 CommandHandler::SystemAlias);
239 commandHandler->registerAlias(this, QString::fromLatin1("voice"),
240 SLOT(slotVoiceCommand( const QString &, Kopete::ChatSession*)),
241 i18n("USAGE: /voice <nickname> [<nickname 2> <...>] - Give channel voice status to someone (requires operator status)."),
242 CommandHandler::SystemAlias, 1);
244 /* commandHandler->registerAlias( this, QString::fromLatin1("who"),
245 QString::fromLatin1( "raw WHO %1" ),
246 i18n("USAGE: /who <nickname|channel> - Display who info on this user/channel."),
247 CommandHandler::SystemAlias, 1, 1 );
249 commandHandler->registerAlias( this, QString::fromLatin1("whois"),
250 QString::fromLatin1("raw WHOIS %1"),
251 i18n("USAGE: /whois <nickname> - Display whois info on this user."),
252 CommandHandler::SystemAlias, 1, 1);
254 commandHandler->registerAlias( this, QString::fromLatin1("whowas"),
255 QString::fromLatin1( "raw WHOWAS %1" ),
256 i18n("USAGE: /whowas <nickname> - Display whowas info on this user."),
257 CommandHandler::SystemAlias, 1, 1);
259 // Alias of alias
260 commandHandler->registerAlias( this, QString::fromLatin1("j"),
261 QString::fromLatin1("join %1"),
262 i18n("USAGE: /j <#channel 1> [<password>] - Alias for JOIN."),
263 CommandHandler::SystemAlias, 1, 2);
265 commandHandler->registerAlias( this, QString::fromLatin1("msg"),
266 QString::fromLatin1("query %s"),
267 i18n("USAGE: /msg <nickname> [<message>] - Alias for QUERY <nickname> <message>."),
268 CommandHandler::SystemAlias, 1);
271 // Utility alias
273 commandHandler->registerAlias( this, QString::fromLatin1("ns"),
274 QString::fromLatin1("msg nickserv %s"),
275 i18n("USAGE: /ns <message> - Alias for MSG NickServ <message>."),
276 CommandHandler::SystemAlias, 1);
278 QObject::connect( ChatSessionManager::self(), SIGNAL(aboutToDisplay(Kopete::Message &)),
279 this, SLOT(slotMessageFilter(Kopete::Message &)) );
281 QObject::connect( ChatSessionManager::self(), SIGNAL( viewCreated( KopeteView* ) ),
282 this, SLOT( slotViewCreated( KopeteView* ) ) );
284 setCapabilities(Protocol::RichBFormatting | Kopete::Protocol::RichUFormatting | Kopete::Protocol::RichColor);
286 m_protocolHandler = new IRCProtocolHandler();
289 IRCProtocol * IRCProtocol::self()
291 return s_protocol;
294 IRCProtocol::~IRCProtocol()
296 delete m_protocolHandler;
299 void IRCProtocol::initOnlineStatus()
302 OnlineStatus ServerOnline(OnlineStatus::Online, 100, this, 0,
303 QString(), i18n("Online"));
305 OnlineStatus ServerOffline(OnlineStatus::Offline, 90, this, 0,
306 QString(), i18n("Offline"));
308 m_statusMap.insert(ServerOnline.internalStatus(), ServerOnline);
309 m_statusMap.insert(ServerOffline.internalStatus(), ServerOffline);
311 ChannelOnline(OnlineStatus::Online, 80, this, EntityType::Channel|EntityType::Online,
312 QString(), i18n("Online")),
313 m_statusMap.insert(ChannelOnline.internalStatus(), ChannelOnline);
315 ChannelOffline(OnlineStatus::Offline, 70, this, EntityType::Channel|EntityType::OfflineChannel,
316 QString(), i18n("Offline")),
317 m_statusMap.insert(ChannelOffline.internalStatus(), ChannelOffline);
319 KIrc::EntityStatus status;
320 status.type = KIrc::User;
322 onlineStatusFor(status, OnlineStatusManager::Offline);
324 status.online = true;
325 onlineStatusFor(status, OnlineStatusManager::Online);
327 status.mode_a = true;
328 onlineStatusFor(status, OnlineStatusManager::Away);
330 OnlineStatus UserOnline(OnlineStatus::Online, 25, this, 0,
331 QString(), i18n("Online"), i18n("Online"), OnlineStatusManager::Online);
333 OnlineStatus UserAway(OnlineStatus::Away, 2, this, 0,
334 "contact_away_overlay", i18n("Away"), i18n("Away"), OnlineStatusManager::Away);
336 OnlineStatus UserConnecting(OnlineStatus::Connecting, 1, this, 0,
337 "irc_connecting", i18n("Connecting"));
339 OnlineStatus UserOffline(OnlineStatus::Offline, 0, this, 0,
340 QString(), i18n("Offline"), i18n("Offline"), OnlineStatusManager::Offline);
344 OnlineStatus IRCProtocol::onlineStatusFor(const KIrc::Entity::Ptr &entity)
346 // return onlineStatusFor(entity, 0);
347 return OnlineStatus::Unknown;
350 OnlineStatus IRCProtocol::onlineStatusFor(const KIrc::Entity::Ptr &entity, unsigned categories)
352 // Only copy the needed status
353 KIrc::EntityStatus status;
354 status.online = _status.online;
355 status.mode_a = _status.mode_a;
356 // status.mode_i = _status.mode_i;
357 status.mode_o = _status.mode_o;
358 status.mode_v = _status.mode_v;
359 status.mode_O = _status.mode_O;
361 OnlineStatus ret = m_statusMap[status];
362 if (ret.status() == OnlineStatus::Unknown)
364 kDebug(14120) << "New online status.";
366 OnlineStatus::StatusType statusType;
367 unsigned weight = 0;
368 QStringList overlayIcons;
369 QString description;
371 if (status.online)
373 statusType = OnlineStatus::Online;
375 weight += 1;
376 description = i18n("Online");
377 weight <<= 1;
379 // Is operator
380 if (status.mode_o || status.mode_O)
382 weight += 1;
383 overlayIcons << "irc_op";
384 description = i18n("Operator");
386 weight <<= 1;
388 // Is Voiced
389 if (status.mode_v)
391 weight += 1;
392 overlayIcons << "irc_voice";
393 description = i18n("Voiced");
395 weight <<= 1;
397 // Is away
398 if (status.mode_a)
400 statusType = OnlineStatus::Away;
401 weight += 1;
402 overlayIcons << "contact_away_overlay";
403 description = i18n("Away");
405 weight <<= 1;
407 // Is Invisible
408 if (status.mode_i)
410 statusType = OnlineStatus::Invisible;
411 weight += 1;
413 weight <<= 1;
416 else
418 statusType = OnlineStatus::Offline;
419 description = i18n("Offline");
422 OnlineStatus onlineStatus(statusType, weight, this,
423 0, overlayIcons, description, description, categories);
425 m_statusMap.insert(status, onlineStatus);
428 return ret;
431 void IRCProtocol::slotViewCreated(KopeteView *view)
433 // if (view->msgManager()->protocol() == this)
434 // new IRCGUIClient(view->msgManager());
437 void IRCProtocol::slotMessageFilter(Message &msg)
439 if (msg.from()->protocol() == this)
441 QString messageText = msg.escapedBody();
443 //Add right click for channels, only replace text not in HTML tags
444 messageText.replace(QRegExp( QString::fromLatin1("(?![^<]+>)(#[^#\\s]+)(?![^<]+>)")), QString::fromLatin1("<span class=\"KopeteLink\" type=\"IRCChannel\">\\1</span>") );
446 msg.setHtmlBody(messageText);
450 QList<KAction *> *IRCProtocol::customChatWindowPopupActions(const Message &m, DOM::Node &n)
452 DOM::HTMLElement e = n;
454 //isNull checks that the cast was successful
455 if (!e.isNull() && !m.to().isEmpty())
457 activeNode = n;
458 activeAccount = static_cast<IRCAccount*>( m.from()->account() );
459 // if (e.getAttribute(QString::fromLatin1("type")) == QString::fromLatin1("IRCChannel"))
460 // return activeAccount->contactManager()->findChannel(
461 // e.innerText().string() )->customContextMenuActions();
463 return 0;
466 AddContactPage *IRCProtocol::createAddContactWidget(QWidget *parent, Account *account)
468 return new IRCAddContactPage(parent,static_cast<IRCAccount*>(account));
471 KopeteEditAccountWidget *IRCProtocol::createEditAccountWidget(Account *account, QWidget *parent)
473 return new IRCEditAccountWidget(qobject_cast<IRCAccount*>(account), parent);
476 Account *IRCProtocol::createNewAccount(const QString &accountId)
478 return new IRCAccount(accountId);
481 Contact *IRCProtocol::deserializeContact(MetaContact *metaContact, const QMap<QString, QString> &serializedData,
482 const QMap<QString, QString> &/*addressBookData*/)
484 kDebug(14120) ;
486 QString contactId = serializedData[ "contactId" ];
487 QString displayName = serializedData[ "displayName" ];
489 if( displayName.isEmpty() )
490 displayName = contactId;
492 QList<Account*> accounts = AccountManager::self()->accounts( this );
493 if( !accounts.isEmpty() )
495 /* Account *a = accounts[ serializedData[ "accountId" ] ];
496 if( a )
498 a->addContact( contactId, metaContact );
499 return a->contacts()[contactId];
501 else
502 kDebug(14120) << serializedData[ "accountId" ] << " was a contact's account,"
503 " but we don't have it in the accounts list" << endl; */
505 else
506 kDebug(14120) << "No accounts loaded!";
508 return 0;
511 void IRCProtocol::slotAllCommand(const QString &args, ChatSession *manager)
513 #ifdef __GNUC__
514 #warning IMPLEMENT ME
515 #endif
518 void IRCProtocol::slotCtcpCommand(const QString &args, ChatSession *manager)
520 if (!args.isEmpty())
522 QString user = args.section( ' ', 0, 0 );
523 QString message = args.section( ' ', 1 );
524 // static_cast<IRCAccount*>(manager->account())->client()->writeCtcpQueryMessage(
525 // user, QString(), message);
529 void IRCProtocol::slotQuoteCommand( const QString &args, ChatSession *manager )
531 // static_cast<IRCAccount *>(manager->account())->client()->writeRawMessage(args);
534 void IRCProtocol::slotRawCommand( const QString &args, ChatSession *manager )
536 // static_cast<IRCAccount*>(manager->account())->client()->writeRawMessage(args);
539 void IRCProtocol::editNetworks(const QString &networkName)
542 IRCNetworkConfigWidget *netConf = new IRCNetworkConfigWidget(UI::Global::mainWidget() );
543 netConf->setAttribute( Qt::WA_DeleteOnClose );
544 netConf->editNetworks(networkName);
545 netConf->show();