Commit 07eab2b9 authored by Linus Jahn's avatar Linus Jahn Committed by Jonah Brüchert
Browse files

Add XEP-0280: Message Carbons

Message carbons allow you to receive the outgoing message of another client of the
same account. In short: messages are synced between the clients.

The handleMessage function of the MessageHandler can now handle both types of messages,
normal, direct messages by a contact and forwarded messages (possibly) written from the same
account.

Notfications and unread message counters are only used, if the message written by somebody
else, so you're not getting annoyed by notifications of your own messages. :)

Closes #116.
parent 8b36766f
......@@ -32,6 +32,8 @@
// gloox
#include <gloox/rostermanager.h>
#include <gloox/receipt.h>
#include <gloox/forward.h>
#include <gloox/carbons.h>
// Kaidan
#include "RosterModel.h"
#include "MessageModel.h"
......@@ -108,12 +110,14 @@ void Kaidan::mainConnect()
client->registerPresenceHandler(presenceHandler);
// Service Discovery
serviceDiscoveryManager = new ServiceDiscoveryManager(client->disco());
serviceDiscoveryManager = new ServiceDiscoveryManager(client, client->disco());
// Register Stanza Extensions
client->registerStanzaExtension(new gloox::Receipt(gloox::Receipt::Request));
client->registerStanzaExtension(new gloox::Receipt(gloox::Receipt::Received));
client->registerStanzaExtension(new gloox::DelayedDelivery(gloox::JID(), std::string("")));
client->registerStanzaExtension(new gloox::Forward());
client->registerStanzaExtension(new gloox::Carbons());
// Logging
client->logInstance().registerLogHandler(gloox::LogLevelDebug,
......
......@@ -26,6 +26,7 @@
#include <QString>
// gloox
#include <gloox/receipt.h>
#include <gloox/carbons.h>
// Kaidan
#include "MessageModel.h"
#include "Notifications.h"
......@@ -60,6 +61,7 @@ MessageHandler::MessageHandler(gloox::Client *client, MessageModel *messageModel
this->messageModel = messageModel;
this->rosterModel = rosterModel;
this->client = client;
this->chatPartner = new QString("");
}
MessageHandler::~MessageHandler()
......@@ -73,56 +75,83 @@ void MessageHandler::setCurrentChatPartner(QString* chatPartner)
resetUnreadMessagesForJid(chatPartner);
}
void MessageHandler::handleMessage(const gloox::Message &message, gloox::MessageSession *session)
void MessageHandler::handleMessage(const gloox::Message &stanza, gloox::MessageSession *session)
{
QString body = QString::fromStdString(message.body());
// this should contain the real message (e.g. containing the body)
gloox::Message *message = const_cast<gloox::Message*>(&stanza);
// if the real message is in a message carbon extract it from there
if (stanza.hasEmbeddedStanza()) {
// get the possible carbon extension
const gloox::Carbons *carbon = stanza.findExtension<const gloox::Carbons>(gloox::ExtCarbons);
// if the extension exists and contains a message, use it as the real message
if(carbon && carbon->embeddedStanza())
message = static_cast<gloox::Message*>(carbon->embeddedStanza());
}
QString body = QString::fromStdString(message->body());
if (body.size() > 0) {
//
// add the message to the db
// Extract information of the message
//
// author is only the 'bare' JID: e.g. 'albert@einstein.ch'
const QString author = QString::fromStdString(message.from().bare());
const QString author_resource = QString::fromStdString(message.from().resource());
const QString recipient = QString::fromStdString(message.to().bare());
const QString recipient_resource = QString::fromStdString(message.to().resource());
const QString fromJid = QString::fromStdString(message->from().bare());
const QString fromJidResource = QString::fromStdString(message->from().resource());
const QString toJid = QString::fromStdString(message->to().bare());
const QString toJidResource = QString::fromStdString(message->to().resource());
const QString msgId = QString::fromStdString(message->id());
const bool isSentByMe = fromJid == QString::fromStdString(client->jid().bare());
QString timestamp;
//
// If it is a delayed delivery (containing a timestamp), use its timestamp
const gloox::DelayedDelivery *delayedDelivery = message.when();
if (delayedDelivery) {
//
const gloox::DelayedDelivery *delayedDelivery = message->when();
if (delayedDelivery)
timestamp = glooxStampToQDateTime(delayedDelivery->stamp()).toString(Qt::ISODate);
}
if (timestamp.isEmpty()) {
timestamp = QDateTime::currentDateTime().toString(Qt::ISODate);
}
const QString msgId = QString::fromStdString(message.id());
// fallback: use current time from local clock
if (timestamp.isEmpty())
timestamp = QDateTime::currentDateTime().toString(Qt::ISODate);
// add the message to the database
messageModel->addMessage(&author, &recipient, &timestamp, &body, &msgId,
false, &author_resource, &recipient_resource);
messageModel->addMessage(&fromJid, &toJid, &timestamp, &body, &msgId,
isSentByMe, &fromJidResource, &toJidResource);
// send a new notification | TODO: Resolve nickname from JID
Notifications::sendMessageNotification(message.from().full(), body.toStdString());
//
// Send a new notification | TODO: Resolve nickname from JID
//
if (!isSentByMe)
Notifications::sendMessageNotification(message->from().full(), body.toStdString());
//
// Update contact sort (lastExchanged), last message and unread message count
//
// the contact can differ if the message is really from a contact or just
// a forward of another of the user's clients
const QString *contactJid = isSentByMe ? &toJid : & fromJid;
// update the last message for this contact
rosterModel->setLastMessageForJid(&author, &body);
rosterModel->setLastMessageForJid(contactJid, &body);
// update the last exchanged for this contact
updateLastExchangedOfJid(&author);
updateLastExchangedOfJid(contactJid);
// if chat is not opened, add a new unread message
if (author != *chatPartner) {
newUnreadMessageForJid(&author);
}
// Increase unread message counter
// don't add new unread message if chat is opened or we wrote the message
if (*contactJid != *chatPartner && !isSentByMe)
newUnreadMessageForJid(contactJid);
}
if (message->hasEmbeddedStanza()) {
// XEP-0184: Message Delivery Receipts
// try to get a possible delivery receipt
gloox::Receipt *receipt = (gloox::Receipt*) message.findExtension<gloox::Receipt>(
gloox::ExtReceipt);
gloox::Receipt *receipt = (gloox::Receipt*) message->findExtension<gloox::Receipt>(gloox::ExtReceipt);
if (receipt) {
// get the type of the receipt
......@@ -130,11 +159,11 @@ void MessageHandler::handleMessage(const gloox::Message &message, gloox::Message
if (receiptType == gloox::Receipt::Request) {
// send the asked confirmation, that the message has been arrived
// new message to the author of the request
gloox::Message receiptMessage(gloox::Message::Chat, message.from());
gloox::Message receiptMessage(gloox::Message::Chat, message->from());
// add the receipt extension containing the request's message id
gloox::Receipt *receiptPayload = new gloox::Receipt(gloox::Receipt::Received,
message.id());
message->id());
receiptMessage.addExtension(receiptPayload);
// send the receipt message
......@@ -144,6 +173,7 @@ void MessageHandler::handleMessage(const gloox::Message &message, gloox::Message
messageModel->setMessageAsDelivered(QString::fromStdString(receipt->id()));
}
}
}
}
void MessageHandler::sendMessage(QString *fromJid, QString *toJid, QString *body)
......
......@@ -25,13 +25,17 @@
#include <QString>
#include <QDebug>
#include <qsysinfo.h>
#include <gloox/carbons.h>
ServiceDiscoveryManager::ServiceDiscoveryManager(gloox::Disco *disco)
ServiceDiscoveryManager::ServiceDiscoveryManager(gloox::Client *client, gloox::Disco *disco)
{
this->disco = disco;
this->client = client;
// register as disco handler
disco->registerDiscoHandler(this);
// register as connection listener
client->registerConnectionListener(this);
setFeaturesAndIdentity();
}
......@@ -40,6 +44,20 @@ ServiceDiscoveryManager::~ServiceDiscoveryManager()
{
}
void ServiceDiscoveryManager::onConnect()
{
// request the disco info from the server
disco->getDiscoInfo(gloox::JID(client->server()), std::string(), this, 0);
}
void ServiceDiscoveryManager::onDisconnect(gloox::ConnectionError error)
{
}
bool ServiceDiscoveryManager::onTLSConnect(const gloox::CertInfo &info)
{
}
void ServiceDiscoveryManager::setFeaturesAndIdentity()
{
//
......@@ -63,6 +81,14 @@ void ServiceDiscoveryManager::setFeaturesAndIdentity()
void ServiceDiscoveryManager::handleDiscoInfo(const gloox::JID& from, const gloox::Disco::Info& info, int context)
{
if (from.bare() == client->server()) {
// XEP-0280: Message Carbons
if (info.hasFeature(gloox::XMLNS_MESSAGE_CARBONS)) {
gloox::IQ iq(gloox::IQ::Set, gloox::JID(), client->getID());
iq.addExtension(new gloox::Carbons(gloox::Carbons::Enable));
client->send(iq);
}
}
}
void ServiceDiscoveryManager::handleDiscoItems(const gloox::JID& from, const gloox::Disco::Items& items, int context)
......
......@@ -28,11 +28,12 @@
#include <gloox/client.h>
#include <gloox/disco.h>
#include <gloox/discohandler.h>
#include <gloox/connectionlistener.h>
class ServiceDiscoveryManager : gloox::DiscoHandler
class ServiceDiscoveryManager : public gloox::DiscoHandler, public gloox::ConnectionListener
{
public:
ServiceDiscoveryManager(gloox::Disco *disco);
ServiceDiscoveryManager(gloox::Client *client, gloox::Disco *disco);
~ServiceDiscoveryManager();
void setFeaturesAndIdentity();
......@@ -42,7 +43,12 @@ public:
void handleDiscoError(const gloox::JID &from, const gloox::Error *error, int context);
bool handleDiscoSet(const gloox::IQ &iq);
virtual void onConnect();
virtual void onDisconnect(gloox::ConnectionError error);
virtual bool onTLSConnect(const gloox::CertInfo &info);
private:
gloox::Client *client;
gloox::Disco *disco;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment