forked from blue/squawk
458 lines
10 KiB
C++
458 lines
10 KiB
C++
/*
|
|
* Squawk messenger.
|
|
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
|
|
*
|
|
* 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 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "message.h"
|
|
#include "utils.h"
|
|
|
|
Shared::Message::Message(Shared::Message::Type p_type):
|
|
jFrom(),
|
|
rFrom(),
|
|
jTo(),
|
|
rTo(),
|
|
id(),
|
|
body(),
|
|
time(),
|
|
thread(),
|
|
type(p_type),
|
|
outgoing(false),
|
|
forwarded(false),
|
|
state(State::delivered),
|
|
edited(false),
|
|
errorText(),
|
|
originalMessage(),
|
|
lastModified(),
|
|
stanzaId(),
|
|
attachPath(),
|
|
encryption(EncryptionProtocol::none)
|
|
{}
|
|
|
|
Shared::Message::Message():
|
|
jFrom(),
|
|
rFrom(),
|
|
jTo(),
|
|
rTo(),
|
|
id(),
|
|
body(),
|
|
time(),
|
|
thread(),
|
|
type(Message::normal),
|
|
outgoing(false),
|
|
forwarded(false),
|
|
state(State::delivered),
|
|
edited(false),
|
|
errorText(),
|
|
originalMessage(),
|
|
lastModified(),
|
|
stanzaId(),
|
|
attachPath(),
|
|
encryption(EncryptionProtocol::none)
|
|
{}
|
|
|
|
QString Shared::Message::getBody() const {
|
|
return body;
|
|
}
|
|
|
|
QString Shared::Message::getFrom() const {
|
|
QString from = jFrom;
|
|
if (rFrom.size() > 0)
|
|
from += "/" + rFrom;
|
|
|
|
return from;
|
|
}
|
|
|
|
QString Shared::Message::getTo() const {
|
|
QString to = jTo;
|
|
if (rTo.size() > 0)
|
|
to += "/" + rTo;
|
|
|
|
return to;
|
|
}
|
|
|
|
QString Shared::Message::getId() const {
|
|
if (id.size() > 0)
|
|
return id;
|
|
else
|
|
return stanzaId;
|
|
}
|
|
|
|
QDateTime Shared::Message::getTime() const {
|
|
return time;
|
|
}
|
|
|
|
void Shared::Message::setBody(const QString& p_body) {
|
|
body = p_body;
|
|
}
|
|
|
|
void Shared::Message::setFrom(const QString& from) {
|
|
QStringList list = from.split("/");
|
|
if (list.size() == 1) {
|
|
jFrom = from.toLower();
|
|
} else {
|
|
jFrom = list.front().toLower();
|
|
rFrom = list.back();
|
|
}
|
|
}
|
|
|
|
void Shared::Message::setTo(const QString& to) {
|
|
QStringList list = to.split("/");
|
|
if (list.size() == 1) {
|
|
jTo = to.toLower();
|
|
} else {
|
|
jTo = list.front().toLower();
|
|
rTo = list.back();
|
|
}
|
|
}
|
|
|
|
void Shared::Message::setId(const QString& p_id) {
|
|
id = p_id;
|
|
}
|
|
|
|
void Shared::Message::setTime(const QDateTime& p_time) {
|
|
time = p_time;
|
|
}
|
|
|
|
QString Shared::Message::getFromJid() const {
|
|
return jFrom;
|
|
}
|
|
|
|
QString Shared::Message::getFromResource() const {
|
|
return rFrom;
|
|
}
|
|
|
|
QString Shared::Message::getToJid() const {
|
|
return jTo;
|
|
}
|
|
|
|
QString Shared::Message::getToResource() const {
|
|
return rTo;
|
|
}
|
|
|
|
QString Shared::Message::getErrorText() const {
|
|
return errorText;
|
|
}
|
|
|
|
QString Shared::Message::getPenPalJid() const {
|
|
if (outgoing)
|
|
return jTo;
|
|
else
|
|
return jFrom;
|
|
}
|
|
|
|
QString Shared::Message::getPenPalResource() const {
|
|
if (outgoing)
|
|
return rTo;
|
|
else
|
|
return rFrom;
|
|
}
|
|
|
|
Shared::Message::State Shared::Message::getState() const {
|
|
return state;
|
|
}
|
|
|
|
bool Shared::Message::getEdited() const {
|
|
return edited;
|
|
}
|
|
|
|
void Shared::Message::setFromJid(const QString& from) {
|
|
jFrom = from.toLower();
|
|
}
|
|
|
|
void Shared::Message::setFromResource(const QString& from) {
|
|
rFrom = from;
|
|
}
|
|
|
|
void Shared::Message::setToJid(const QString& to) {
|
|
jTo = to.toLower();
|
|
}
|
|
|
|
void Shared::Message::setToResource(const QString& to) {
|
|
rTo = to;
|
|
}
|
|
|
|
void Shared::Message::setErrorText(const QString& err) {
|
|
if (state == State::error)
|
|
errorText = err;
|
|
}
|
|
|
|
bool Shared::Message::getOutgoing() const {
|
|
return outgoing;
|
|
}
|
|
|
|
void Shared::Message::setOutgoing(bool og) {
|
|
outgoing = og;
|
|
}
|
|
|
|
bool Shared::Message::getForwarded() const {
|
|
return forwarded;
|
|
}
|
|
|
|
void Shared::Message::generateRandomId() {
|
|
id = generateUUID();
|
|
}
|
|
|
|
QString Shared::Message::getThread() const {
|
|
return thread;
|
|
}
|
|
|
|
void Shared::Message::setForwarded(bool fwd) {
|
|
forwarded = fwd;
|
|
}
|
|
|
|
void Shared::Message::setThread(const QString& p_body) {
|
|
thread = p_body;
|
|
}
|
|
|
|
QDateTime Shared::Message::getLastModified() const {
|
|
return lastModified;
|
|
}
|
|
|
|
QString Shared::Message::getOriginalBody() const {
|
|
return originalMessage;
|
|
}
|
|
|
|
Shared::Message::Type Shared::Message::getType() const {
|
|
return type;
|
|
}
|
|
|
|
void Shared::Message::setType(Shared::Message::Type t) {
|
|
type = t;
|
|
}
|
|
|
|
void Shared::Message::setState(Shared::Message::State p_state) {
|
|
state = p_state;
|
|
|
|
if (state != State::error)
|
|
errorText = "";
|
|
}
|
|
|
|
bool Shared::Message::serverStored() const {
|
|
return state == State::delivered || state == State::sent;
|
|
}
|
|
|
|
void Shared::Message::setEdited(bool p_edited) {
|
|
edited = p_edited;
|
|
}
|
|
|
|
Shared::EncryptionProtocol Shared::Message::getEncryption() const {
|
|
return encryption;
|
|
}
|
|
|
|
void Shared::Message::setEncryption(EncryptionProtocol encryption) {
|
|
Shared::Message::encryption = encryption;
|
|
}
|
|
|
|
void Shared::Message::setError(const QString& text) {
|
|
state = State::error;
|
|
errorText = text;
|
|
}
|
|
|
|
QDataStream& operator<<(QDataStream& out, const Shared::Message& info) {
|
|
out << info.jFrom;
|
|
out << info.rFrom;
|
|
out << info.jTo;
|
|
out << info.rTo;
|
|
out << info.id;
|
|
out << info.body;
|
|
quint64 msecs = info.time.toMSecsSinceEpoch();
|
|
out << msecs;
|
|
|
|
out << info.thread;
|
|
out << (quint8)info.type;
|
|
out << info.outgoing;
|
|
out << info.forwarded;
|
|
out << info.oob;
|
|
out << (quint8)info.state;
|
|
out << info.edited;
|
|
if (info.state == Shared::Message::State::error)
|
|
out << info.errorText;
|
|
|
|
if (info.edited) {
|
|
out << info.originalMessage;
|
|
out << info.lastModified;
|
|
}
|
|
out << info.stanzaId;
|
|
out << info.attachPath;
|
|
out << (quint8)info.encryption;
|
|
|
|
return out;
|
|
}
|
|
|
|
QDataStream & operator>>(QDataStream& in, Shared::Message& info) {
|
|
in >> info.jFrom;
|
|
in >> info.rFrom;
|
|
in >> info.jTo;
|
|
in >> info.rTo;
|
|
in >> info.id;
|
|
in >> info.body;
|
|
|
|
quint64 msecs;
|
|
in >> msecs;
|
|
info.time = QDateTime::fromMSecsSinceEpoch(msecs);
|
|
|
|
in >> info.thread;
|
|
quint8 t;
|
|
in >> t;
|
|
info.type = static_cast<Shared::Message::Type>(t);
|
|
in >> info.outgoing;
|
|
in >> info.forwarded;
|
|
in >> info.oob;
|
|
quint8 s;
|
|
in >> s;
|
|
info.state = static_cast<Shared::Message::State>(s);
|
|
in >> info.edited;
|
|
if (info.state == Shared::Message::State::error)
|
|
in >> info.errorText;
|
|
|
|
if (info.edited) {
|
|
in >> info.originalMessage;
|
|
in >> info.lastModified;
|
|
}
|
|
in >> info.stanzaId;
|
|
in >> info.attachPath;
|
|
quint8 e;
|
|
in >> e;
|
|
info.encryption = static_cast<Shared::EncryptionProtocol>(e);
|
|
|
|
return in;
|
|
}
|
|
|
|
bool Shared::Message::change(const QMap<QString, QVariant>& data)
|
|
{
|
|
QMap<QString, QVariant>::const_iterator itr = data.find("state");
|
|
if (itr != data.end())
|
|
setState(static_cast<State>(itr.value().toUInt()));
|
|
|
|
itr = data.find("outOfBandUrl");
|
|
if (itr != data.end())
|
|
setOutOfBandUrl(itr.value().toString());
|
|
|
|
itr = data.find("attachPath");
|
|
if (itr != data.end())
|
|
setAttachPath(itr.value().toString());
|
|
|
|
if (state == State::error) {
|
|
itr = data.find("errorText");
|
|
if (itr != data.end())
|
|
setErrorText(itr.value().toString());
|
|
}
|
|
|
|
bool idChanged = false;
|
|
itr = data.find("id");
|
|
if (itr != data.end()) {
|
|
QString newId = itr.value().toString();
|
|
if (id != newId) {
|
|
setId(newId);
|
|
idChanged = true;
|
|
}
|
|
}
|
|
|
|
itr = data.find("stanzaId");
|
|
if (itr != data.end()) {
|
|
QString newId = itr.value().toString();
|
|
if (stanzaId != newId) {
|
|
setStanzaId(newId);
|
|
if (id.size() == 0)
|
|
idChanged = true;
|
|
}
|
|
}
|
|
|
|
itr = data.find("body");
|
|
if (itr != data.end()) {
|
|
QString b = itr.value().toString();
|
|
if (body != b) {
|
|
QMap<QString, QVariant>::const_iterator dItr = data.find("stamp");
|
|
QDateTime correctionDate;
|
|
if (dItr != data.end())
|
|
correctionDate = dItr.value().toDateTime();
|
|
else
|
|
correctionDate = QDateTime::currentDateTimeUtc(); //in case there is no information about time of this correction it's applied
|
|
|
|
if (!edited || lastModified < correctionDate) {
|
|
if (!edited)
|
|
originalMessage = body;
|
|
|
|
lastModified = correctionDate;
|
|
setBody(b);
|
|
setEdited(true);
|
|
}
|
|
}
|
|
} else {
|
|
QMap<QString, QVariant>::const_iterator dItr = data.find("stamp");
|
|
if (dItr != data.end()) {
|
|
QDateTime ntime = dItr.value().toDateTime();
|
|
if (time != ntime)
|
|
setTime(ntime);
|
|
}
|
|
}
|
|
|
|
return idChanged;
|
|
}
|
|
|
|
void Shared::Message::setCurrentTime() {
|
|
time = QDateTime::currentDateTimeUtc();
|
|
}
|
|
|
|
QString Shared::Message::getOutOfBandUrl() const {
|
|
return oob;
|
|
}
|
|
|
|
bool Shared::Message::hasOutOfBandUrl() const {
|
|
return oob.size() > 0;
|
|
}
|
|
|
|
void Shared::Message::setOutOfBandUrl(const QString& url) {
|
|
oob = url;
|
|
}
|
|
|
|
bool Shared::Message::storable() const {
|
|
return id.size() > 0 && (body.size() > 0 || oob.size() > 0 || attachPath.size() > 0);
|
|
}
|
|
|
|
void Shared::Message::setStanzaId(const QString& sid) {
|
|
stanzaId = sid;
|
|
}
|
|
|
|
QString Shared::Message::getStanzaId() const {
|
|
return stanzaId;
|
|
}
|
|
|
|
QString Shared::Message::getAttachPath() const {
|
|
return attachPath;
|
|
}
|
|
|
|
void Shared::Message::setAttachPath(const QString& path) {
|
|
attachPath = path;
|
|
}
|
|
|
|
Shared::Message::Change::Change(const QMap<QString, QVariant>& _data):
|
|
data(_data),
|
|
idModified(false) {}
|
|
|
|
void Shared::Message::Change::operator()(Shared::Message& msg) {
|
|
idModified = msg.change(data);
|
|
}
|
|
|
|
void Shared::Message::Change::operator()(Shared::Message* msg) {
|
|
idModified = msg->change(data);
|
|
}
|
|
|
|
bool Shared::Message::Change::hasIdBeenModified() const {
|
|
return idModified;
|
|
}
|
|
|