915 lines
24 KiB
C++
915 lines
24 KiB
C++
#include "jiddb.h"
|
|
#include <QDir>
|
|
#include <QSqlQuery>
|
|
#include <QSqlError>
|
|
#include <QStandardPaths>
|
|
#include <QTimeZone>
|
|
#include <QVariant>
|
|
#include <iostream>
|
|
#include <stdexcept>
|
|
|
|
JidDb::JidDb(const QString &jid) :
|
|
jid(jid),
|
|
db(QSqlDatabase::addDatabase("QSQLITE"))
|
|
{
|
|
const auto path = QStandardPaths::writableLocation(
|
|
QStandardPaths::AppDataLocation);
|
|
const QDir dir;
|
|
|
|
if (!dir.exists(path) && !dir.mkdir(path))
|
|
throw std::runtime_error("Failed to create app dir");
|
|
|
|
const auto abspath = path + "/" + jid + ".db";
|
|
|
|
db.setDatabaseName(abspath);
|
|
|
|
if (!db.open())
|
|
throw std::runtime_error(qPrintable("database" + abspath
|
|
+ "could not be created"));
|
|
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("create table if not exists roster "
|
|
"(jid TEXT unique) strict;"))
|
|
std::cerr << "JidDb::JidDb: query exec failed" << std::endl;
|
|
}
|
|
|
|
int JidDb::addToRoster(const QString &jid)
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("insert or ignore into roster (jid) values ('" + jid + "');"))
|
|
{
|
|
std::cerr << "JidDb::addToRoster: query exec failed" << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
Q_EMIT addedToRoster(jid);
|
|
return 0;
|
|
}
|
|
|
|
int JidDb::addToRoster(const QStringList &roster)
|
|
{
|
|
for (const auto &r : roster)
|
|
if (addToRoster(r))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
QStringList JidDb::roster() const
|
|
{
|
|
QStringList ret;
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("select jid from roster;"))
|
|
std::cerr << "query exec failed" << std::endl;
|
|
else
|
|
while (q.next())
|
|
ret.append(q.value("jid").toString());
|
|
|
|
return ret;
|
|
}
|
|
|
|
int JidDb::ensureContactTable(const QString &jid) const
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("create table if not exists '" + jid +
|
|
"' (direction TEXT, time INTEGER, body TEXT) strict;"))
|
|
{
|
|
std::cerr << "JidDb::storeMessage: query exec failed" << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static QString securityPolicyTableName(const QString &encryption)
|
|
{
|
|
return "securityPolicy/" + encryption;
|
|
}
|
|
|
|
int JidDb::ensureSecurityPolicyTable(const QString &encryption,
|
|
QString &table) const
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
table = securityPolicyTableName(encryption);
|
|
|
|
if (!q.exec("create table if not exists '" + table
|
|
+ "' (policy TEXT unique) strict;"))
|
|
{
|
|
std::cerr << "JidDb::ensureSecurityPolicyTable: query exec failed"
|
|
<< std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static QString keysTableName(const QString &encryption)
|
|
{
|
|
return "keys/" + encryption;
|
|
}
|
|
|
|
int JidDb::ensureKeysTable(const QString &encryption, QString &table) const
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
table = keysTableName(encryption);
|
|
|
|
if (!q.exec("create table if not exists '" + table
|
|
+ "' (owner TEXT, trustlevel TEXT, key TEXT) strict;"))
|
|
{
|
|
std::cerr << "JidDb::ensureKeysTable: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
QList<JidDb::Message> JidDb::messages(const QString &jid,
|
|
const int tail) const
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (ensureContactTable(jid))
|
|
return QList<Message>();
|
|
else if (tail < 0)
|
|
{
|
|
if (!q.exec("select * from '" + jid + "' order by time;"))
|
|
{
|
|
std::cerr << "JidDb::messages: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return QList<Message>();
|
|
}
|
|
}
|
|
else if (!q.exec("select * from '" + jid + "' order by time desc limit "
|
|
+ QString::number(tail) + ";"))
|
|
{
|
|
std::cerr << "JidDb::messages: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return QList<Message>();
|
|
}
|
|
|
|
QList<Message> ret;
|
|
|
|
while (q.next())
|
|
{
|
|
Message m;
|
|
bool ok;
|
|
qlonglong t = q.value("time").toLongLong(&ok);
|
|
|
|
if (!ok)
|
|
{
|
|
std::cerr << "JidDb::messages: invalid time" << std::endl;
|
|
// Attempt to read other messages.
|
|
continue;
|
|
}
|
|
|
|
m.body = q.value("body").toString();
|
|
m.dt = QDateTime::fromSecsSinceEpoch(t, QTimeZone::systemTimeZone());
|
|
|
|
const auto dirstr = q.value("direction").toString();
|
|
|
|
if (dirstr == "in")
|
|
m.direction = Direction::In;
|
|
else if (dirstr == "out")
|
|
m.direction = Direction::Out;
|
|
else
|
|
{
|
|
std::cerr << "JidDb::messages: invalid direction" << std::endl;
|
|
// Attempt to read other messages.
|
|
continue;
|
|
}
|
|
|
|
ret << m;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int JidDb::store(const JidDb::Message &msg) const
|
|
{
|
|
QSqlQuery q(db);
|
|
QString dir;
|
|
|
|
switch (msg.direction)
|
|
{
|
|
case Direction::In:
|
|
dir = "in";
|
|
break;
|
|
|
|
case Direction::Out:
|
|
dir = "out";
|
|
break;
|
|
}
|
|
|
|
ensureContactTable(msg.contact);
|
|
|
|
if (!q.exec("insert into '" + msg.contact
|
|
+ "' (direction, time, body) values "
|
|
"('" + dir + "', "
|
|
+ QString::number(msg.dt.toSecsSinceEpoch()) + ", "
|
|
"'" + msg.body + "')"))
|
|
{
|
|
std::cerr << "JidDb::storeMessage: query exec 2 failed" << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
QStringList JidDb::tables() const
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("select name from sqlite_schema where "
|
|
"type = 'table' and name not like 'sqlite_%'"))
|
|
{
|
|
std::cerr << "JidDb::conversations: query failed" << std::endl;
|
|
return QStringList();
|
|
}
|
|
|
|
QStringList ret;
|
|
|
|
while (q.next())
|
|
ret << q.value("name").toString();
|
|
|
|
return ret;
|
|
}
|
|
|
|
QList<JidDb::Conversation> JidDb::conversations() const
|
|
{
|
|
const auto conversations = tables();
|
|
QList<Conversation> ret;
|
|
|
|
for (const auto &jid : conversations)
|
|
if (jid.contains('@'))
|
|
{
|
|
const auto msgs = messages(jid, 1);
|
|
|
|
if (!msgs.isEmpty())
|
|
{
|
|
const auto &m = msgs.first();
|
|
|
|
ret << Conversation(jid, m.body, m.dt);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
QString JidDb::securityPolicy(const QString &encryption) const
|
|
{
|
|
const auto tb = tables();
|
|
const auto name = securityPolicyTableName(encryption);
|
|
|
|
for (const auto &t : tb)
|
|
{
|
|
if (t == name)
|
|
{
|
|
QStringList ret;
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("select policy from '" + name + "';"))
|
|
std::cerr << "query exec failed" << std::endl;
|
|
else
|
|
while (q.next())
|
|
return q.value("policy").toString();
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
std::optional<QXmppOmemoStorage::OwnDevice> JidDb::omemoOwnDevice() const
|
|
{
|
|
return std::optional<QXmppOmemoStorage::OwnDevice>();
|
|
}
|
|
|
|
int JidDb::store(const QString &encryption, const QString &policy) const
|
|
{
|
|
QString table;
|
|
|
|
if (ensureSecurityPolicyTable(encryption, table))
|
|
return -1;
|
|
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("insert or ignore into '" + table
|
|
+ "' (policy) values ('" + policy + "');"))
|
|
{
|
|
std::cerr << "JidDb::store: query exec failed"
|
|
<< std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
QList<JidDb::Keys> JidDb::keys(const QString &encryption) const
|
|
{
|
|
QList<Keys> ret;
|
|
QString table;
|
|
|
|
if (ensureKeysTable(encryption, table))
|
|
{
|
|
std::cerr << "JidDb::keys: ensureKeysTable failed" << std::endl;
|
|
return QList<Keys>();
|
|
}
|
|
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("select owner, trustlevel, key from '" + table + "';"))
|
|
std::cerr << "JidDb::keys: query exec failed" << std::endl;
|
|
else
|
|
while (q.next())
|
|
{
|
|
const auto owner = q.value("owner").toString();
|
|
const auto trust_level = q.value("trustlevel").toString();
|
|
const auto key_b64 = q.value("key").toString();
|
|
const auto key = QByteArray::fromBase64(key_b64.toLatin1());
|
|
bool found = false;
|
|
|
|
for (auto &k : ret)
|
|
if (k.owner == owner)
|
|
{
|
|
k.keys.append(key);
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
Keys keys;
|
|
|
|
keys.owner = owner;
|
|
keys.trust_level = trust_level;
|
|
keys.keys.append(key);
|
|
ret.append(keys);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int JidDb::store(const QString &encryption, const JidDb::Keys &keys) const
|
|
{
|
|
QString table;
|
|
|
|
if (ensureKeysTable(encryption, table))
|
|
{
|
|
std::cerr << "JidDb::store: ensureKeysTable failed" << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
for (const auto &k : keys.keys)
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
const auto kstr = k.isEmpty() ? "\"\""
|
|
: "'" + QString::fromLatin1(k.toBase64()) + "'";
|
|
|
|
if (!q.exec("insert or replace into '" + table
|
|
+ "' (owner, trustlevel, key) values ("
|
|
"'" + keys.owner + "', "
|
|
"'" + keys.trust_level + "',"
|
|
+ kstr
|
|
+ ");"))
|
|
{
|
|
std::cerr << "JidDb::store: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int JidDb::ensureOmemoDeviceTable() const
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("create table if not exists 'omemo/devices' "
|
|
"(jid TEXT, deviceID INTEGER, keyID TEXT, session TEXT, "
|
|
"unresp_sent INTEGER, unresp_recv INTEGER, removal INTEGER) "
|
|
"strict;"))
|
|
{
|
|
std::cerr << "JidDb::ensureOmemoTable: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int JidDb::store(const QString &jid, const uint32_t id,
|
|
const QXmppOmemoStorage::Device &d) const
|
|
{
|
|
if (ensureOmemoDeviceTable())
|
|
{
|
|
std::cerr << "JidDb::store: ensureOmemoTable failed" << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
QSqlQuery q(db);
|
|
const auto keyId = d.keyId.isEmpty() ? "\"\""
|
|
: "'" + QString::fromLatin1(d.keyId.toBase64()) + "'",
|
|
session = d.session.isEmpty() ? "\"\""
|
|
: "'" + QString::fromLatin1(d.session.toBase64()) + "'",
|
|
query = "insert or replace into 'omemo/devices' "
|
|
"(jid, deviceID, keyID, session, "
|
|
"unresp_sent, unresp_recv , removal) values ("
|
|
"'" + jid + "', "
|
|
+ QString::number(id) + ", "
|
|
+ keyId + ", "
|
|
+ session + ", "
|
|
+ QString::number(d.unrespondedSentStanzasCount) + ", "
|
|
+ QString::number(d.unrespondedReceivedStanzasCount) + ", "
|
|
+ QString::number(d.removalFromDeviceListDate.toSecsSinceEpoch())
|
|
+ ");";
|
|
|
|
if (!q.exec(query))
|
|
{
|
|
std::cerr << "JidDb::store(id, jid, d): query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int JidDb::ensureOmemoSignedPreKeyTable() const
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("create table if not exists 'omemo/signedprekeys' "
|
|
"(id INTEGER, creation INTEGER, data TEXT) strict;"))
|
|
{
|
|
std::cerr << "JidDb::ensureOmemoSignedPreKeyTable: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int JidDb::store(uint32_t id, const QXmppOmemoStorage::SignedPreKeyPair &spk)
|
|
const
|
|
{
|
|
if (ensureOmemoSignedPreKeyTable())
|
|
{
|
|
std::cerr << "JidDb::store: ensureOmemoSignedPreKeyTable failed"
|
|
<< std::endl;
|
|
return -1;
|
|
}
|
|
|
|
QSqlQuery q(db);
|
|
const auto data = spk.data.isEmpty() ? "\"\""
|
|
: "'" + QString::fromLatin1(spk.data.toBase64()) + "'",
|
|
query = "insert or replace into 'omemo/signedprekeys' "
|
|
"(id, creation, data) values ("
|
|
+ QString::number(id) + ", "
|
|
+ QString::number(spk.creationDate.toSecsSinceEpoch()) + ", "
|
|
+ data
|
|
+ ");";
|
|
|
|
if (!q.exec(query))
|
|
{
|
|
std::cerr << "JidDb::store(spk): query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int JidDb::ensureOmemoPreKeyTable() const
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("create table if not exists 'omemo/prekeys' "
|
|
"(id INTEGER, data TEXT) strict;"))
|
|
{
|
|
std::cerr << "JidDb::ensureOmemoPreKeyTable: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int JidDb::store(const QHash<uint32_t, QByteArray> &pairs) const
|
|
{
|
|
if (ensureOmemoPreKeyTable())
|
|
{
|
|
std::cerr << "JidDb::store: ensureOmemoPreKeyTable failed"
|
|
<< std::endl;
|
|
return -1;
|
|
}
|
|
|
|
for (const auto id : pairs.keys())
|
|
{
|
|
const auto data = pairs.value(id);
|
|
const auto datastr = data.isEmpty() ? "\"\""
|
|
: "'" + QString::fromLatin1(data.toBase64()) + "'",
|
|
query = "insert or replace into 'omemo/prekeys' "
|
|
"(id, data) values ("
|
|
+ QString::number(id) + ", "
|
|
+ datastr
|
|
+ ");";
|
|
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec(query))
|
|
{
|
|
std::cerr << "JidDb::store(pairs): query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int JidDb::ensureOmemoOwnDeviceTable() const
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("create table if not exists 'omemo/owndevice' "
|
|
"(id INTEGER, label TEXT, privkey TEXT, pubkey TEXT, "
|
|
"latestSignedPreKeyId INTEGER, latestPreKeyId INTEGER) strict;"))
|
|
{
|
|
std::cerr << "JidDb::ensureOmemoOwnDeviceTable: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int JidDb::store(const QXmppOmemoStorage::OwnDevice &own) const
|
|
{
|
|
if (ensureOmemoOwnDeviceTable())
|
|
{
|
|
std::cerr << "JidDb::store: ensureOmemoOwnDeviceTable failed"
|
|
<< std::endl;
|
|
return -1;
|
|
}
|
|
|
|
QSqlQuery q(db);
|
|
const auto privkey = own.privateIdentityKey.isEmpty() ? "\"\""
|
|
: "'" + QString::fromLatin1(own.privateIdentityKey.toBase64()) + "'",
|
|
pubkey = own.publicIdentityKey.isEmpty() ? "\"\""
|
|
: "'" + QString::fromLatin1(own.publicIdentityKey.toBase64()) + "'",
|
|
query = "insert or replace into 'omemo/owndevice' "
|
|
"(id, label, privkey, pubkey, latestSignedPreKeyId, "
|
|
"latestPreKeyId) values ("
|
|
+ QString::number(own.id) + ", "
|
|
"'" + own.label + "', "
|
|
+ privkey + ", "
|
|
+ pubkey + ", "
|
|
+ QString::number(own.latestSignedPreKeyId) + ", "
|
|
+ QString::number(own.latestPreKeyId)
|
|
+ ");";
|
|
|
|
if (!q.exec(query))
|
|
{
|
|
std::cerr << "JidDb::store(own): query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
std::cerr << "Query was: " << qPrintable(query) << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
QList<JidDb::OmemoDevice> JidDb::omemoDevices() const
|
|
{
|
|
QList<OmemoDevice> ret;
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("select * from 'omemo/devices';"))
|
|
{
|
|
std::cerr << "JidDb::omemoDevices: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return QList<OmemoDevice>();
|
|
}
|
|
|
|
while (q.next())
|
|
{
|
|
QXmppOmemoStorage::Device device;
|
|
bool ok;
|
|
const uint32_t deviceId = q.value("deviceID").toULongLong(&ok);
|
|
|
|
if (!ok)
|
|
{
|
|
std::cerr << "JidDb::messages: invalid deviceID" << std::endl;
|
|
// Attempt to read other messages.
|
|
continue;
|
|
}
|
|
|
|
device.unrespondedReceivedStanzasCount =
|
|
q.value("unresp_recv").toInt(&ok);
|
|
|
|
if (!ok)
|
|
{
|
|
std::cerr << "JidDb::messages: invalid unresp_recv" << std::endl;
|
|
// Attempt to read other messages.
|
|
continue;
|
|
}
|
|
|
|
device.unrespondedSentStanzasCount = q.value("unresp_sent").toInt(&ok);
|
|
|
|
if (!ok)
|
|
{
|
|
std::cerr << "JidDb::messages: invalid unresp_sent" << std::endl;
|
|
// Attempt to read other messages.
|
|
continue;
|
|
}
|
|
|
|
const QByteArray keyId = q.value("keyID").toByteArray(),
|
|
session = q.value("session").toByteArray();
|
|
const auto jid = q.value("jid").toString();
|
|
bool found = false;
|
|
|
|
for (auto &r : ret)
|
|
if (jid == r.jid)
|
|
{
|
|
r.devices.insert(deviceId, device);
|
|
break;
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
OmemoDevice d;
|
|
|
|
d.jid = jid;
|
|
d.devices.insert(deviceId, device);
|
|
ret << d;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
QHash<uint32_t, QXmppOmemoStorage::SignedPreKeyPair> JidDb::signedPreKeyPairs()
|
|
const
|
|
{
|
|
QHash<uint32_t, QXmppOmemoStorage::SignedPreKeyPair> ret;
|
|
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("select * from 'omemo/signedprekeys';"))
|
|
{
|
|
std::cerr << "JidDb::signedPreKeyPairs: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return QHash<uint32_t, QXmppOmemoStorage::SignedPreKeyPair>();
|
|
}
|
|
|
|
while (q.next())
|
|
{
|
|
QXmppOmemoStorage::SignedPreKeyPair spk;
|
|
bool ok;
|
|
const uint32_t id = q.value("id").toULongLong(&ok);
|
|
|
|
if (!ok)
|
|
{
|
|
std::cerr << "JidDb::messages: invalid id" << std::endl;
|
|
// Attempt to read other entries.
|
|
continue;
|
|
}
|
|
|
|
const auto creation = q.value("creation").toInt(&ok);
|
|
|
|
if (!ok)
|
|
{
|
|
std::cerr << "JidDb::messages: invalid creation date" << std::endl;
|
|
// Attempt to read other entries.
|
|
continue;
|
|
}
|
|
|
|
spk.creationDate = QDateTime::fromSecsSinceEpoch(creation);
|
|
spk.data = q.value("data").toString().toLatin1().toBase64();
|
|
ret.insert(id, spk);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
QHash<uint32_t, QByteArray> JidDb::preKeyPairs() const
|
|
{
|
|
QHash<uint32_t, QByteArray> ret;
|
|
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("select * from 'omemo/signedprekeys';"))
|
|
{
|
|
std::cerr << "JidDb::signedPreKeyPairs: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return QHash<uint32_t, QByteArray>();
|
|
}
|
|
|
|
while (q.next())
|
|
{
|
|
bool ok;
|
|
const uint32_t id = q.value("id").toULongLong(&ok);
|
|
|
|
if (!ok)
|
|
{
|
|
std::cerr << "JidDb::messages: invalid id" << std::endl;
|
|
// Attempt to read other entries.
|
|
continue;
|
|
}
|
|
|
|
const auto data = q.value("data").toString().toLatin1().toBase64();
|
|
ret.insert(id, data);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void JidDb::removeKeys(const QString &encryption) const
|
|
{
|
|
QString table;
|
|
|
|
if (ensureKeysTable(encryption, table))
|
|
std::cerr << "JidDb::removeKeys: ensureKeysTable failed" << std::endl;
|
|
else
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("delete from '" + table + "'"))
|
|
std::cerr << "JidDb::removeKeys: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
}
|
|
}
|
|
|
|
void JidDb::removeOmemoDevice(const QString &jid, const uint32_t id) const
|
|
{
|
|
if (ensureOmemoDeviceTable())
|
|
std::cerr << "JidDb::removeOmemoDevice: ensureOmemoDeviceTable failed"
|
|
<< std::endl;
|
|
else
|
|
{
|
|
QSqlQuery q(db);
|
|
const auto idstr = QString::number(id);
|
|
|
|
if (!q.exec("delete from 'omemo/devices' "
|
|
"where (jid = '" + jid + "' "
|
|
"and id = " + idstr + ")"))
|
|
std::cerr << "JidDb::removeOmemoDevice: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
}
|
|
}
|
|
|
|
void JidDb::removeOmemoDevices(const QString &jid) const
|
|
{
|
|
if (ensureOmemoDeviceTable())
|
|
std::cerr << "JidDb::removeOmemoDevices: ensureOmemoDeviceTable failed"
|
|
<< std::endl;
|
|
else
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("delete from 'omemo/devices' "
|
|
"where jid = '" + jid + "'"))
|
|
std::cerr << "JidDb::removeOmemoDevices: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
}
|
|
}
|
|
|
|
int JidDb::ensureOwnIdTable(const QString &encryption, QString &table)
|
|
const
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
table = encryption + "/ownID";
|
|
|
|
if (!q.exec("create table if not exists '" + table + "' "
|
|
"(ID TEXT) strict;"))
|
|
{
|
|
std::cerr << "JidDb::ensureOwnIdTable: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
QByteArray JidDb::ownKeyId(const QString &encryption) const
|
|
{
|
|
QString table;
|
|
|
|
if (ensureOwnIdTable(encryption, table))
|
|
{
|
|
std::cerr << "JidDb::store: ensureOwnIdTable failed" << std::endl;
|
|
return QByteArray();
|
|
}
|
|
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("select * from '" + table + "';"))
|
|
{
|
|
std::cerr << "JidDb::ownKeyId: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
return QByteArray();
|
|
}
|
|
|
|
while (q.next())
|
|
{
|
|
const auto id = q.value("id").toString();
|
|
|
|
return QByteArray::fromBase64(id.toLatin1());
|
|
}
|
|
|
|
return QByteArray();
|
|
}
|
|
|
|
int JidDb::store(const QString &encryption, const QByteArray &ownId) const
|
|
{
|
|
QString table;
|
|
|
|
if (ensureOwnIdTable(encryption, table))
|
|
{
|
|
std::cerr << "JidDb::store: ensureOmemoOwnDeviceTable failed"
|
|
<< std::endl;
|
|
return -1;
|
|
}
|
|
|
|
QSqlQuery q(db);
|
|
const auto id = ownId.isEmpty() ? "\"\""
|
|
: "'" + QString::fromLatin1(ownId.toBase64()) + "'",
|
|
query = "insert or replace into '" + table + "' "
|
|
"(id) values ("
|
|
+ id
|
|
+ ");";
|
|
|
|
return 0;
|
|
}
|
|
|
|
void JidDb::removeSignedPreKeyPair(const uint32_t id) const
|
|
{
|
|
if (ensureOmemoSignedPreKeyTable())
|
|
std::cerr << "JidDb::removeSignedPreKeyPair: "
|
|
"ensureOmemoSignedPreKeyTable failed" << std::endl;
|
|
else
|
|
{
|
|
QSqlQuery q(db);
|
|
const auto idstr = QString::number(id);
|
|
|
|
if (!q.exec("delete from 'omemo/signedprekeys'"
|
|
"where id = " + id))
|
|
std::cerr << "JidDb::removeSignedPreKeyPair: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
}
|
|
}
|
|
|
|
void JidDb::removePreKeyPair(const uint32_t id) const
|
|
{
|
|
if (ensureOmemoPreKeyTable())
|
|
std::cerr << "JidDb::removePreKeyPair: "
|
|
"ensureOmemoPreKeyTable failed" << std::endl;
|
|
else
|
|
{
|
|
QSqlQuery q(db);
|
|
const auto idstr = QString::number(id);
|
|
|
|
if (!q.exec("delete from 'omemo/prekeys'"
|
|
"where id = " + id))
|
|
std::cerr << "JidDb::removePreKeyPair: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
}
|
|
}
|
|
|
|
void JidDb::removeOmemo() const
|
|
{
|
|
if (ensureOmemoSignedPreKeyTable())
|
|
std::cerr << "JidDb::removeOmemo: "
|
|
"ensureOmemoSignedPreKeyTable failed" << std::endl;
|
|
else if (ensureOmemoPreKeyTable())
|
|
std::cerr << "JidDb::removeOmemo: "
|
|
"ensureOmemoPreKeyTable failed" << std::endl;
|
|
else
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("delete from 'omemo/signedprekeys'"))
|
|
std::cerr << "JidDb::removeOmemo: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
else
|
|
{
|
|
QSqlQuery q(db);
|
|
|
|
if (!q.exec("delete from 'omemo/prekeys'"))
|
|
std::cerr << "JidDb::removeOmemo: query exec failed: "
|
|
<< qPrintable(q.lastError().text()) << std::endl;
|
|
}
|
|
}
|
|
}
|