diff options
Diffstat (limited to 'Swift/Controllers/Chat/ChatControllerBase.cpp')
-rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.cpp | 164 |
1 files changed, 108 insertions, 56 deletions
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index 3ff52a6..2c2540c 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -1,9 +1,9 @@ /* - * Copyright (c) 2010-2011 Kevin Smith + * Copyright (c) 2010-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swift/Controllers/Chat/ChatControllerBase.h" +#include <Swift/Controllers/Chat/ChatControllerBase.h> #include <sstream> @@ -14,8 +14,9 @@ #include <boost/smart_ptr/make_shared.hpp> #include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/numeric/conversion/cast.hpp> #include <boost/algorithm/string.hpp> -#include <Swift/Controllers/Intl.h> #include <Swiften/Base/format.h> +#include <Swiften/Base/Path.h> #include <Swiften/Base/String.h> #include <Swiften/Client/StanzaChannel.h> @@ -24,15 +25,23 @@ #include <Swiften/Elements/MUCUserPayload.h> #include <Swiften/Base/foreach.h> -#include <Swift/Controllers/XMPPEvents/EventController.h> #include <Swiften/Disco/EntityCapsProvider.h> -#include <Swift/Controllers/UIInterfaces/ChatWindow.h> -#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h> #include <Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h> #include <Swiften/Avatars/AvatarManager.h> + +#include <Swift/Controllers/Intl.h> +#include <Swift/Controllers/XMPPEvents/EventController.h> +#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UIInterfaces/ChatWindow.h> +#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h> #include <Swift/Controllers/XMPPEvents/MUCInviteEvent.h> +#include <Swift/Controllers/HighlightManager.h> +#include <Swift/Controllers/Highlighter.h> +#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h> +#include <Swift/Controllers/Chat/ChatMessageParser.h> namespace Swift { -ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider) { +ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, boost::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry), chatMessageParser_(chatMessageParser), autoAcceptMUCInviteDecider_(autoAcceptMUCInviteDecider), eventStream_(eventStream) { chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream); chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this)); @@ -40,4 +49,5 @@ ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaCha chatWindow_->onLogCleared.connect(boost::bind(&ChatControllerBase::handleLogCleared, this)); entityCapsProvider_->onCapsChanged.connect(boost::bind(&ChatControllerBase::handleCapsChanged, this, _1)); + highlighter_ = highlightManager->createHighlighter(); setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable()); createDayChangeTimer(); @@ -45,4 +55,5 @@ ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaCha ChatControllerBase::~ChatControllerBase() { + delete highlighter_; delete chatWindow_; } @@ -52,4 +63,10 @@ void ChatControllerBase::handleLogCleared() { } +ChatWindow* ChatControllerBase::detachChatWindow() { + ChatWindow* chatWindow = chatWindow_; + chatWindow_ = NULL; + return chatWindow; +} + void ChatControllerBase::handleCapsChanged(const JID& jid) { if (jid.compare(toJID_, JID::WithoutResource) == 0) { @@ -58,9 +75,15 @@ void ChatControllerBase::handleCapsChanged(const JID& jid) { } +void ChatControllerBase::setCanStartImpromptuChats(bool supportsImpromptu) { + if (chatWindow_) { + chatWindow_->setCanInitiateImpromptuChats(supportsImpromptu); + } +} + void ChatControllerBase::createDayChangeTimer() { if (timerFactory_) { boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); boost::posix_time::ptime midnight(now.date() + boost::gregorian::days(1)); - long millisecondsUntilMidnight = (midnight - now).total_milliseconds(); + int millisecondsUntilMidnight = boost::numeric_cast<int>((midnight - now).total_milliseconds()); dateChangeTimer_ = boost::shared_ptr<Timer>(timerFactory_->createTimer(millisecondsUntilMidnight)); dateChangeTimer_->onTick.connect(boost::bind(&ChatControllerBase::handleDayChangeTick, this)); @@ -72,5 +95,5 @@ void ChatControllerBase::handleDayChangeTick() { dateChangeTimer_->stop(); boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "The day is now %1%")) % std::string(boost::posix_time::to_iso_extended_string(now)).substr(0,10))); + chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "The day is now %1%")) % std::string(boost::posix_time::to_iso_extended_string(now)).substr(0,10))), ChatWindow::DefaultDirection); dayTicked(); createDayChangeTimer(); @@ -85,7 +108,11 @@ void ChatControllerBase::setOnline(bool online) { } +JID ChatControllerBase::getBaseJID() { + return JID(toJID_.toBare()); +} + void ChatControllerBase::setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> info) { if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::SecurityLabelsCatalogFeature)) { - GetSecurityLabelsCatalogRequest::ref request = GetSecurityLabelsCatalogRequest::create(JID(toJID_.toBare()), iqRouter_); + GetSecurityLabelsCatalogRequest::ref request = GetSecurityLabelsCatalogRequest::create(getBaseJID(), iqRouter_); request->onResponse.connect(boost::bind(&ChatControllerBase::handleSecurityLabelsCatalogResponse, this, _1, _2)); request->send(); @@ -109,5 +136,5 @@ void ChatControllerBase::handleAllMessagesRead() { int ChatControllerBase::getUnreadCount() { - return targetedUnreadMessages_.size(); + return boost::numeric_cast<int>(targetedUnreadMessages_.size()); } @@ -121,5 +148,8 @@ void ChatControllerBase::handleSendMessageRequest(const std::string &body, bool message->setBody(body); if (labelsEnabled_) { - SecurityLabelsCatalog::Item labelItem = chatWindow_->getSelectedSecurityLabel(); + if (!isCorrectionMessage) { + lastLabel_ = chatWindow_->getSelectedSecurityLabel(); + } + SecurityLabelsCatalog::Item labelItem = lastLabel_; if (labelItem.getLabel()) { message->addPayload(labelItem.getLabel()); @@ -127,6 +157,7 @@ void ChatControllerBase::handleSendMessageRequest(const std::string &body, bool } preSendMessageRequest(message); - if (useDelayForLatency_) { + boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); + if (useDelayForLatency_) { message->addPayload(boost::make_shared<Delay>(now, selfJID_)); } @@ -138,8 +169,12 @@ void ChatControllerBase::handleSendMessageRequest(const std::string &body, bool postSendMessage(message->getBody(), boost::dynamic_pointer_cast<Stanza>(message)); onActivity(message->getBody()); + +#ifdef SWIFT_EXPERIMENTAL_HISTORY + logMessage(body, selfJID_, toJID_, now, false); +#endif } void ChatControllerBase::handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog> catalog, ErrorPayload::ref error) { - if (!error) { + if (catalog && !error) { if (catalog->getItems().size() == 0) { chatWindow_->setSecurityLabelsEnabled(false); @@ -164,17 +199,21 @@ void ChatControllerBase::activateChatWindow() { } -std::string ChatControllerBase::addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const boost::posix_time::ptime& time) { +bool ChatControllerBase::hasOpenWindow() const { + return chatWindow_ && chatWindow_->isVisible(); +} + +std::string ChatControllerBase::addMessage(const std::string& message, const std::string& senderName, bool senderIsSelf, const boost::shared_ptr<SecurityLabel> label, const boost::filesystem::path& avatarPath, const boost::posix_time::ptime& time, const HighlightAction& highlight) { if (boost::starts_with(message, "/me ")) { - return chatWindow_->addAction(String::getSplittedAtFirst(message, ' ').second, senderName, senderIsSelf, label, avatarPath, time); + return chatWindow_->addAction(chatMessageParser_->parseMessageBody(String::getSplittedAtFirst(message, ' ').second), senderName, senderIsSelf, label, pathToString(avatarPath), time, highlight); } else { - return chatWindow_->addMessage(message, senderName, senderIsSelf, label, avatarPath, time); + return chatWindow_->addMessage(chatMessageParser_->parseMessageBody(message,highlighter_->getNick(),senderIsSelf), senderName, senderIsSelf, label, pathToString(avatarPath), time, highlight); } } -void ChatControllerBase::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) { +void ChatControllerBase::replaceMessage(const std::string& message, const std::string& id, bool senderIsSelf, const boost::posix_time::ptime& time, const HighlightAction& highlight) { if (boost::starts_with(message, "/me ")) { - chatWindow_->replaceWithAction(String::getSplittedAtFirst(message, ' ').second, id, time); + chatWindow_->replaceWithAction(chatMessageParser_->parseMessageBody(String::getSplittedAtFirst(message, ' ').second), id, time, highlight); } else { - chatWindow_->replaceMessage(message, id, time); + chatWindow_->replaceMessage(chatMessageParser_->parseMessageBody(message,highlighter_->getNick(),senderIsSelf), id, time, highlight); } } @@ -194,7 +233,10 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m boost::shared_ptr<Message> message = messageEvent->getStanza(); std::string body = message->getBody(); + HighlightAction highlight; if (message->isError()) { + if (!message->getTo().getResource().empty()) { std::string errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't send message: %1%")) % getErrorMessage(message->getPayload<ErrorPayload>())); - chatWindow_->addErrorMessage(errorMessage); + chatWindow_->addErrorMessage(chatMessageParser_->parseMessageBody(errorMessage)); + } } else if (messageEvent->getStanza()->getPayload<MUCInvitationPayload>()) { @@ -220,5 +262,5 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m std::ostringstream s; s << "The following message took " << (now - delayPayloads[i]->getStamp()).total_milliseconds() / 1000.0 << " seconds to be delivered from " << delayPayloads[i]->getFrom()->toString() << "."; - chatWindow_->addSystemMessage(std::string(s.str())); + chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(std::string(s.str())), ChatWindow::DefaultDirection); } boost::shared_ptr<SecurityLabel> label = message->getPayload<SecurityLabel>(); @@ -232,4 +274,9 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m onActivity(body); + // Highlight + if (!isIncomingMessageFromMe(message)) { + highlight = highlighter_->findAction(body, senderDisplayNameFromMessage(from)); + } + boost::shared_ptr<Replace> replace = message->getPayload<Replace>(); if (replace) { @@ -239,15 +286,17 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m lastMessage = lastMessagesUIID_.find(from); if (lastMessage != lastMessagesUIID_.end()) { - replaceMessage(body, lastMessagesUIID_[from], timeStamp); + replaceMessage(body, lastMessagesUIID_[from], isIncomingMessageFromMe(message), timeStamp, highlight); } } else { - lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp); + lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, avatarManager_->getAvatarPath(from), timeStamp, highlight); } + + logMessage(body, from, selfJID_, timeStamp, true); } chatWindow_->show(); - chatWindow_->setUnreadMessageCount(unreadMessages_.size()); + chatWindow_->setUnreadMessageCount(boost::numeric_cast<int>(unreadMessages_.size())); onUnreadCountChanged(); - postHandleIncomingMessage(messageEvent); + postHandleIncomingMessage(messageEvent, highlight); } @@ -259,28 +308,29 @@ std::string ChatControllerBase::getErrorMessage(boost::shared_ptr<ErrorPayload> else { switch (error->getCondition()) { - case ErrorPayload::BadRequest: return QT_TRANSLATE_NOOP("", "Bad request"); break; - case ErrorPayload::Conflict: return QT_TRANSLATE_NOOP("", "Conflict"); break; - case ErrorPayload::FeatureNotImplemented: return QT_TRANSLATE_NOOP("", "This feature is not implemented"); break; - case ErrorPayload::Forbidden: return QT_TRANSLATE_NOOP("", "Forbidden"); break; - case ErrorPayload::Gone: return QT_TRANSLATE_NOOP("", "Recipient can no longer be contacted"); break; - case ErrorPayload::InternalServerError: return QT_TRANSLATE_NOOP("", "Internal server error"); break; - case ErrorPayload::ItemNotFound: return QT_TRANSLATE_NOOP("", "Item not found"); break; - case ErrorPayload::JIDMalformed: return QT_TRANSLATE_NOOP("", "JID Malformed"); break; - case ErrorPayload::NotAcceptable: return QT_TRANSLATE_NOOP("", "Message was rejected"); break; - case ErrorPayload::NotAllowed: return QT_TRANSLATE_NOOP("", "Not allowed"); break; - case ErrorPayload::NotAuthorized: return QT_TRANSLATE_NOOP("", "Not authorized"); break; - case ErrorPayload::PaymentRequired: return QT_TRANSLATE_NOOP("", "Payment is required"); break; - case ErrorPayload::RecipientUnavailable: return QT_TRANSLATE_NOOP("", "Recipient is unavailable"); break; - case ErrorPayload::Redirect: return QT_TRANSLATE_NOOP("", "Redirect"); break; - case ErrorPayload::RegistrationRequired: return QT_TRANSLATE_NOOP("", "Registration required"); break; - case ErrorPayload::RemoteServerNotFound: return QT_TRANSLATE_NOOP("", "Recipient's server not found"); break; - case ErrorPayload::RemoteServerTimeout: return QT_TRANSLATE_NOOP("", "Remote server timeout"); break; - case ErrorPayload::ResourceConstraint: return QT_TRANSLATE_NOOP("", "The server is low on resources"); break; - case ErrorPayload::ServiceUnavailable: return QT_TRANSLATE_NOOP("", "The service is unavailable"); break; - case ErrorPayload::SubscriptionRequired: return QT_TRANSLATE_NOOP("", "A subscription is required"); break; - case ErrorPayload::UndefinedCondition: return QT_TRANSLATE_NOOP("", "Undefined condition"); break; - case ErrorPayload::UnexpectedRequest: return QT_TRANSLATE_NOOP("", "Unexpected request"); break; - } - } + case ErrorPayload::BadRequest: return QT_TRANSLATE_NOOP("", "Bad request"); + case ErrorPayload::Conflict: return QT_TRANSLATE_NOOP("", "Conflict"); + case ErrorPayload::FeatureNotImplemented: return QT_TRANSLATE_NOOP("", "This feature is not implemented"); + case ErrorPayload::Forbidden: return QT_TRANSLATE_NOOP("", "Forbidden"); + case ErrorPayload::Gone: return QT_TRANSLATE_NOOP("", "Recipient can no longer be contacted"); + case ErrorPayload::InternalServerError: return QT_TRANSLATE_NOOP("", "Internal server error"); + case ErrorPayload::ItemNotFound: return QT_TRANSLATE_NOOP("", "Item not found"); + case ErrorPayload::JIDMalformed: return QT_TRANSLATE_NOOP("", "JID Malformed"); + case ErrorPayload::NotAcceptable: return QT_TRANSLATE_NOOP("", "Message was rejected"); + case ErrorPayload::NotAllowed: return QT_TRANSLATE_NOOP("", "Not allowed"); + case ErrorPayload::NotAuthorized: return QT_TRANSLATE_NOOP("", "Not authorized"); + case ErrorPayload::PaymentRequired: return QT_TRANSLATE_NOOP("", "Payment is required"); + case ErrorPayload::RecipientUnavailable: return QT_TRANSLATE_NOOP("", "Recipient is unavailable"); + case ErrorPayload::Redirect: return QT_TRANSLATE_NOOP("", "Redirect"); + case ErrorPayload::RegistrationRequired: return QT_TRANSLATE_NOOP("", "Registration required"); + case ErrorPayload::RemoteServerNotFound: return QT_TRANSLATE_NOOP("", "Recipient's server not found"); + case ErrorPayload::RemoteServerTimeout: return QT_TRANSLATE_NOOP("", "Remote server timeout"); + case ErrorPayload::ResourceConstraint: return QT_TRANSLATE_NOOP("", "The server is low on resources"); + case ErrorPayload::ServiceUnavailable: return QT_TRANSLATE_NOOP("", "The service is unavailable"); + case ErrorPayload::SubscriptionRequired: return QT_TRANSLATE_NOOP("", "A subscription is required"); + case ErrorPayload::UndefinedCondition: return QT_TRANSLATE_NOOP("", "Undefined condition"); + case ErrorPayload::UnexpectedRequest: return QT_TRANSLATE_NOOP("", "Unexpected request"); + } + } + assert(false); return defaultMessage; } @@ -289,7 +339,7 @@ void ChatControllerBase::handleGeneralMUCInvitation(MUCInviteEvent::ref event) { unreadMessages_.push_back(event); chatWindow_->show(); - chatWindow_->setUnreadMessageCount(unreadMessages_.size()); + chatWindow_->setUnreadMessageCount(boost::numeric_cast<int>(unreadMessages_.size())); onUnreadCountChanged(); - chatWindow_->addMUCInvitation(senderDisplayNameFromMessage(event->getInviter()), event->getRoomJID(), event->getReason(), event->getPassword(), event->getDirect()); + chatWindow_->addMUCInvitation(senderDisplayNameFromMessage(event->getInviter()), event->getRoomJID(), event->getReason(), event->getPassword(), event->getDirect(), event->getImpromptu()); eventController_->handleIncomingEvent(event); } @@ -298,7 +348,11 @@ void ChatControllerBase::handleMUCInvitation(Message::ref message) { MUCInvitationPayload::ref invite = message->getPayload<MUCInvitationPayload>(); - MUCInviteEvent::ref inviteEvent = boost::make_shared<MUCInviteEvent>(toJID_, invite->getJID(), invite->getReason(), invite->getPassword(), true); + if (autoAcceptMUCInviteDecider_->isAutoAcceptedInvite(message->getFrom(), invite)) { + eventStream_->send(boost::make_shared<JoinMUCUIEvent>(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true)); + } else { + MUCInviteEvent::ref inviteEvent = boost::make_shared<MUCInviteEvent>(toJID_, invite->getJID(), invite->getReason(), invite->getPassword(), true, invite->getIsImpromptu()); handleGeneralMUCInvitation(inviteEvent); } +} void ChatControllerBase::handleMediatedMUCInvitation(Message::ref message) { @@ -314,9 +368,7 @@ void ChatControllerBase::handleMediatedMUCInvitation(Message::ref message) { } - MUCInviteEvent::ref inviteEvent = boost::make_shared<MUCInviteEvent>(invite.from, from, reason, password, false); + MUCInviteEvent::ref inviteEvent = boost::make_shared<MUCInviteEvent>(invite.from, from, reason, password, false, false); handleGeneralMUCInvitation(inviteEvent); } - - } |