summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers/Chat/ChatControllerBase.cpp')
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp164
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);
}
-
-
}