MessageHandler.cpp 7.42 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 *  Kaidan - A user-friendly XMPP client for every device!
 *
 *  Copyright (C) 2017 LNJ <git@lnj.li>
 *
 *  Kaidan 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 3 of the License, or
 *  (at your option) any later version.
 *
 *  Kaidan is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Kaidan. If not, see <http://www.gnu.org/licenses/>.
 */

#include "MessageHandler.h"
// Std
#include <iostream>
// Qt
#include <QDateTime>
#include <QDebug>
#include <QString>
// gloox
#include <gloox/receipt.h>
Linus Jahn's avatar
Linus Jahn committed
29
#include <gloox/carbons.h>
30 31 32 33
// Kaidan
#include "MessageModel.h"
#include "Notifications.h"

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
QDateTime glooxStampToQDateTime(std::string stamp_)
{
	QString stamp = QString::fromStdString(stamp_);
	QDateTime dateTime;

	if (stamp.contains('Z')) {
		dateTime = QDateTime::fromString(stamp, "yyyy-MM-ddThh:mm:ss.zzzZ");
	} else if (stamp.contains('-') && stamp.contains(':') && stamp.contains('.')) {
		dateTime = QDateTime::fromString(stamp, "yyyy-MM-ddThh:mm:ss.zzz");
	} else if (stamp.contains('-') && stamp.contains(':')) {
		dateTime = QDateTime::fromString(stamp, "yyyy-MM-ddThh:mm:ss");
	} else if (stamp.contains(':') && stamp.contains('T')) {
		dateTime = QDateTime::fromString(stamp, "yyyyMMddThh:mm:ss");
	} else {
		dateTime = QDateTime::fromString(stamp, "hh:mm");
	}

	if (!dateTime.isValid())
		return QDateTime();

	dateTime.setTimeSpec(Qt::UTC);
	return dateTime;
}

58 59
MessageHandler::MessageHandler(gloox::Client *client, MessageModel *messageModel,
	RosterModel *rosterModel)
60
{
61 62
	this->messageModel = messageModel;
	this->rosterModel = rosterModel;
63
	this->client = client;
Linus Jahn's avatar
Linus Jahn committed
64
	this->chatPartner = new QString("");
65 66 67 68 69 70
}

MessageHandler::~MessageHandler()
{
}

71 72 73 74 75 76 77
void MessageHandler::setCurrentChatPartner(QString* chatPartner)
{
	this->chatPartner = chatPartner;

	resetUnreadMessagesForJid(chatPartner);
}

Linus Jahn's avatar
Linus Jahn committed
78
void MessageHandler::handleMessage(const gloox::Message &stanza, gloox::MessageSession *session)
79
{
Linus Jahn's avatar
Linus Jahn committed
80 81 82 83 84 85 86 87 88 89 90 91 92
	// 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());
93

94 95
	if (body.size() > 0) {
		//
Linus Jahn's avatar
Linus Jahn committed
96
		// Extract information of the message
97 98 99
		//

		// author is only the 'bare' JID: e.g. 'albert@einstein.ch'
Linus Jahn's avatar
Linus Jahn committed
100 101 102 103 104 105
		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());
106 107
		QString timestamp;

Linus Jahn's avatar
Linus Jahn committed
108
		//
109
		// If it is a delayed delivery (containing a timestamp), use its timestamp
Linus Jahn's avatar
Linus Jahn committed
110 111 112 113
		//

		const gloox::DelayedDelivery *delayedDelivery = message->when();
		if (delayedDelivery)
114 115
			timestamp = glooxStampToQDateTime(delayedDelivery->stamp()).toString(Qt::ISODate);

Linus Jahn's avatar
Linus Jahn committed
116 117 118
		// fallback: use current time from local clock
		if (timestamp.isEmpty())
			timestamp = QDateTime::currentDateTime().toString(Qt::ISODate);
119

120
		// add the message to the database
Linus Jahn's avatar
Linus Jahn committed
121 122
		messageModel->addMessage(&fromJid, &toJid, &timestamp, &body, &msgId,
								 isSentByMe, &fromJidResource, &toJidResource);
123

Linus Jahn's avatar
Linus Jahn committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137
		//
		// 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;
138 139

		// update the last message for this contact
Linus Jahn's avatar
Linus Jahn committed
140
		rosterModel->setLastMessageForJid(contactJid, &body);
141 142

		// update the last exchanged for this contact
Linus Jahn's avatar
Linus Jahn committed
143
		updateLastExchangedOfJid(contactJid);
144

Linus Jahn's avatar
Linus Jahn committed
145 146 147 148
		// 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);
149 150
	}

Linus Jahn's avatar
Linus Jahn committed
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
	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);

		if (receipt) {
			// get the type of the receipt
			gloox::Receipt::ReceiptType receiptType = receipt->rcpt();
			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());

				// add the receipt extension containing the request's message id
				gloox::Receipt *receiptPayload = new gloox::Receipt(gloox::Receipt::Received,
																	message->id());
				receiptMessage.addExtension(receiptPayload);

				// send the receipt message
				client->send(receiptMessage);
			} else if (receiptType == gloox::Receipt::Received) {
				// Delivery Receipt Received -> mark message as read in db
				messageModel->setMessageAsDelivered(QString::fromStdString(receipt->id()));
			}
175 176 177 178 179 180 181 182 183 184 185 186 187 188
		}
	}
}

void MessageHandler::sendMessage(QString *fromJid, QString *toJid, QString *body)
{
	// create a new message
	gloox::Message message(gloox::Message::Chat, gloox::JID(toJid->toStdString()),
						   body->toStdString());

	// add the message to the database
	const QString timestamp = QDateTime::currentDateTime().toString(Qt::ISODate);
	const QString id = QString::fromStdString(message.id());

189
	messageModel->addMessage(fromJid, toJid, &timestamp, body, &id, true);
190 191 192 193 194 195 196 197

	// XEP-0184: Message Delivery Receipts
	// request a delivery receipt from the other client
	gloox::Receipt *receiptPayload = new gloox::Receipt(gloox::Receipt::Request);
	message.addExtension(receiptPayload);

	// send the message
	client->send(message);
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223

	// update the last message for this contact
	rosterModel->setLastMessageForJid(toJid, body);
	// update the last exchanged date
	updateLastExchangedOfJid(toJid);
}

void MessageHandler::updateLastExchangedOfJid(const QString *jid)
{
	QString dateTime = QDateTime::currentDateTime().toString(Qt::ISODate);
	rosterModel->setLastExchangedOfJid(jid, &dateTime);
}

void MessageHandler::newUnreadMessageForJid(const QString *jid)
{
	// get the current unread message count
	int msgCount = rosterModel->getUnreadMessageCountOfJid(jid);
	// increase it by one
	msgCount++;
	// set the new increased count
	rosterModel->setUnreadMessageCountOfJid(jid, msgCount);
}

void MessageHandler::resetUnreadMessagesForJid(const QString *jid)
{
	rosterModel->setUnreadMessageCountOfJid(jid, 0);
224
}