/* irccontact.cpp - IRC Contact Copyright (c) 2002 by Nick Betcher Copyright (c) 2004 by Michel Hermier Copyright (c) 2005 by Tommi Rantala Kopete (c) 2002-2005 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 #include #include #include #include #include "ircaccount.h" #include "kopeteglobal.h" #include "kopeteuiglobal.h" #include "kopetemetacontact.h" #include "kopeteview.h" #include "ircusercontact.h" #include "irccontact.h" #include "ircprotocol.h" #include "ircservercontact.h" #include "irccontactmanager.h" #include "ksparser.h" IRCContact::IRCContact(IRCAccount *account, KIRC::EntityPtr entity, Kopete::MetaContact *metac, const QString& icon) : Kopete::Contact(account, entity->name(), metac, icon), m_chatSession(0) { } IRCContact::IRCContact(IRCContactManager *contactManager, const QString &nick, Kopete::MetaContact *metac, const QString& icon) : Kopete::Contact(contactManager->account(), nick, metac, icon), m_nickName(nick), m_chatSession(0) { KIRC::Engine *engine = kircEngine(); // Contact list display name setProperty( Kopete::Global::Properties::self()->nickName(), m_nickName ); // IRCContactManager stuff QObject::connect(contactManager, SIGNAL(privateMessage(IRCContact *, IRCContact *, const QString &)), this, SLOT(privateMessage(IRCContact *, IRCContact *, const QString &))); // Kopete::ChatSessionManager stuff mMyself.append( static_cast( this ) ); // KIRC stuff QObject::connect(engine, SIGNAL(incomingNickChange(const QString &, const QString &)), this, SLOT( slotNewNickChange(const QString&, const QString&))); QObject::connect(engine, SIGNAL(successfullyChangedNick(const QString &, const QString &)), this, SLOT(slotNewNickChange(const QString &, const QString &))); QObject::connect(engine, SIGNAL(incomingQuitIRC(const QString &, const QString &)), this, SLOT( slotUserDisconnected(const QString&, const QString&))); QObject::connect(engine, SIGNAL(statusChanged(KIRC::Engine::Status)), this, SLOT(updateStatus())); engine->setCodec( m_nickName, codec() ); } IRCContact::~IRCContact() { // kdDebug(14120) << k_funcinfo << m_nickName << endl; if (metaContact() && metaContact()->isTemporary() && !isChatting(m_chatSession)) metaContact()->deleteLater(); emit destroyed(this); } IRCAccount *IRCContact::ircAccount() const { return static_cast(account()); } KIRC::Engine *IRCContact::kircEngine() const { return ircAccount()->engine(); } bool IRCContact::isReachable() { if (onlineStatus().status() != Kopete::OnlineStatus::Offline && onlineStatus().status() != Kopete::OnlineStatus::Unknown) return true; return false; } const QString IRCContact::caption() const { return QString::null; } /* const QString IRCContact::formatedName() const { return QString::null; } */ void IRCContact::updateStatus() { } void IRCContact::privateMessage(IRCContact *, IRCContact *, const QString &) { } void IRCContact::setCodec(const QTextCodec *codec) { kircEngine()->setCodec(m_nickName, codec); metaContact()->setPluginData(m_protocol, QString::fromLatin1("Codec"), QString::number(codec->mibEnum())); } const QTextCodec *IRCContact::codec() { QString codecId = metaContact()->pluginData(m_protocol, QString::fromLatin1("Codec")); QTextCodec *codec = ircAccount()->codec(); if( !codecId.isEmpty() ) { bool test = true; uint mib = codecId.toInt(&test); if (test) codec = QTextCodec::codecForMib(mib); else codec = QTextCodec::codecForName(codecId.latin1()); } if( !codec ) return kircEngine()->codec(); return codec; } Kopete::ChatSession *IRCContact::manager(Kopete::Contact::CanCreateFlags canCreate) { IRCAccount *account = ircAccount(); KIRC::Engine *engine = kircEngine(); if (canCreate == Kopete::Contact::CanCreate && !m_chatSession) { if( engine->status() == KIRC::Engine::Idle && dynamic_cast(this) == 0 ) account->connect(); m_chatSession = Kopete::ChatSessionManager::self()->create(account->myself(), mMyself, account->protocol()); m_chatSession->setDisplayName(caption()); QObject::connect(m_chatSession, SIGNAL(messageSent(Kopete::Message&, Kopete::ChatSession *)), this, SLOT(slotSendMsg(Kopete::Message&, Kopete::ChatSession *))); QObject::connect(m_chatSession, SIGNAL(closing(Kopete::ChatSession *)), this, SLOT(chatSessionDestroyed())); initConversation(); } return m_chatSession; } void IRCContact::chatSessionDestroyed() { m_chatSession = 0; if (metaContact()->isTemporary() && !isChatting()) deleteLater(); } void IRCContact::slotUserDisconnected(const QString &user, const QString &reason) { if (m_chatSession) { QString nickname = user.section('!', 0, 0); Kopete::Contact *c = locateUser( nickname ); if ( c ) { m_chatSession->removeContact(c, i18n("Quit: \"%1\" ").arg(reason), Kopete::Message::RichText); c->setOnlineStatus(m_protocol->m_UserStatusOffline); } } } void IRCContact::setNickName( const QString &nickname ) { kdDebug(14120) << k_funcinfo << m_nickName << " changed to " << nickname << endl; m_nickName = nickname; Kopete::Contact::setNickName( nickname ); } void IRCContact::slotNewNickChange(const QString &oldnickname, const QString &newnickname) { IRCAccount *account = ircAccount(); IRCContact *user = static_cast( locateUser(oldnickname) ); if( user ) { user->setNickName( newnickname ); //If the user is in our contact list, then change the notify list nickname if (!user->metaContact()->isTemporary()) { account->contactManager()->removeFromNotifyList( oldnickname ); account->contactManager()->addToNotifyList( newnickname ); } } } void IRCContact::slotSendMsg(Kopete::Message &message, Kopete::ChatSession *) { QString htmlString = message.escapedBody(); // Messages we get with RichText enabled: // // Hello world in bold and color: // Hello World // // Two-liner in color: // Hello
World
if (htmlString.find(QString::fromLatin1(" -1) { QRegExp findTags( QString::fromLatin1("(.*)") ); findTags.setMinimal( true ); int pos = 0; while (pos >= 0) { pos = findTags.search(htmlString); if (pos > -1) { QString styleHTML = findTags.cap(1); QString replacement = findTags.cap(2); QStringList styleAttrs = QStringList::split(';', styleHTML); for (QStringList::Iterator attrPair = styleAttrs.begin(); attrPair != styleAttrs.end(); ++attrPair) { QString attribute = (*attrPair).section(':',0,0); QString value = (*attrPair).section(':',1); if( attribute == QString::fromLatin1("color") ) { int ircColor = KSParser::colorForHTML( value ); if( ircColor > -1 ) replacement.prepend( QString( QChar(0x03) ).append( QString::number(ircColor) ) ).append( QChar( 0x03 ) ); } else if( attribute == QString::fromLatin1("font-weight") && value == QString::fromLatin1("600") ) { // Bolding replacement.prepend( QChar(0x02) ).append( QChar(0x02) ); } else if( attribute == QString::fromLatin1("text-decoration") && value == QString::fromLatin1("underline") ) { replacement.prepend( QChar(31) ).append( QChar(31) ); } } htmlString = htmlString.left( pos ) + replacement + htmlString.mid( pos + findTags.matchedLength() ); } } } htmlString = Kopete::Message::unescape(htmlString); QStringList messages = QStringList::split( '\n', htmlString ); for( QStringList::Iterator it = messages.begin(); it != messages.end(); ++it ) { // Dont use the resulting string(s). The problem is that we'd have to parse them // back to format that would be suitable for appendMessage(). // // TODO: If the given message was plaintext, we could easily show what was // actually sent. sendMessage(*it); } if (message.requestedPlugin() != CHAT_VIEW) { Kopete::Message msg(message.from(), message.to(), message.escapedBody(), message.direction(), Kopete::Message::RichText, CHAT_VIEW, message.type()); msg.setBg(QColor()); msg.setFg(QColor()); appendMessage(msg); } else { // Lets not modify the given message object. Kopete::Message msg = message; msg.setBg(QColor()); appendMessage(msg); } manager(Kopete::Contact::CanCreate)->messageSucceeded(); } QStringList IRCContact::sendMessage( const QString &msg ) { QStringList messages; QString newMessage = msg; // IRC limits the message size to 512 characters. So split the given // message into pieces. // // This can of course give nasty results, but most of us dont write // that long lines anyway ;-)... And this is how other clients also // seem to behave. int l = 500 - m_nickName.length(); do { messages.append(newMessage.mid(0, l)); newMessage.remove(0, l); } while (!newMessage.isEmpty()); for (QStringList::const_iterator it = messages.begin(); it != messages.end(); ++it) kircEngine()->privmsg(m_nickName, *it); return messages; } Kopete::Contact *IRCContact::locateUser(const QString &nick) { IRCAccount *account = ircAccount(); if (m_chatSession) { if( nick == account->mySelf()->nickName() ) return account->mySelf(); else { Kopete::ContactPtrList mMembers = m_chatSession->members(); for (Kopete::Contact *it = mMembers.first(); it; it = mMembers.next()) { if (static_cast(it)->nickName() == nick) return it; } } } return 0; } bool IRCContact::isChatting(const Kopete::ChatSession *avoid) const { IRCAccount *account = ircAccount(); if (!account) return false; QValueList sessions = Kopete::ChatSessionManager::self()->sessions(); for (QValueList::Iterator it= sessions.begin(); it!=sessions.end() ; ++it) { if( (*it) != avoid && (*it)->account() == account && (*it)->members().contains(this) ) { return true; } } return false; } void IRCContact::deleteContact() { kdDebug(14120) << k_funcinfo << m_nickName << endl; delete m_chatSession; if (!isChatting()) { kdDebug(14120) << k_funcinfo << "will delete " << m_nickName << endl; Kopete::Contact::deleteContact(); } else { metaContact()->removeContact(this); Kopete::MetaContact *m = new Kopete::MetaContact(); m->setTemporary(true); setMetaContact(m); } } void IRCContact::appendMessage(Kopete::Message &msg) { manager(Kopete::Contact::CanCreate)->appendMessage(msg); } KopeteView *IRCContact::view() { if (m_chatSession) return m_chatSession->view(false); return 0L; } void IRCContact::serialize(QMap & /*serializedData*/, QMap &addressBookData) { // write the addressBookData[ protocol()->addressBookIndexField() ] = ( contactId() + QChar(0xE120) + account()->accountId() ); } void IRCContact::receivedMessage( KIRC::Engine::ServerMessageType type, const KIRC::EntityPtr &from, const KIRC::EntityPtrList &to, const QString &msg) { if (to.contains(m_entity)) { IRCContact *fromContact = ircAccount()->getContact(from); Kopete::Message message(fromContact, manager()->members(), msg, Kopete::Message::Inbound, Kopete::Message::RichText, CHAT_VIEW); appendMessage(message); } } #include "irccontact.moc"