From 05b2584fa4d773f5a88ed3ce98f5dd8304e11c34 Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Mon, 12 Jun 2023 23:47:17 +0200 Subject: First commit --- jiddb.cpp | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 jiddb.cpp (limited to 'jiddb.cpp') diff --git a/jiddb.cpp b/jiddb.cpp new file mode 100644 index 0000000..3102e81 --- /dev/null +++ b/jiddb.cpp @@ -0,0 +1,175 @@ +#include "jiddb.h" +#include +#include +#include +#include +#include +#include +#include + +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; +} + +void JidDb::addToRoster(const QString &jid) +{ + QSqlQuery q(db); + + if (!q.exec("insert or ignore into roster (jid) values ('" + jid + "');")) + throw std::runtime_error("JidDb::addToRoster: query exec failed"); + + Q_EMIT addedToRoster(jid); +} + +void JidDb::addToRoster(const QStringList &roster) +{ + for (const auto &r : roster) + addToRoster(r); +} + +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; +} + +void JidDb::ensureContactDb(const QString &jid) const +{ + QSqlQuery q(db); + + if (!q.exec("create table if not exists '" + jid + + "' (direction TEXT, time INTEGER, body TEXT) strict;")) + throw std::runtime_error("JidDb::storeMessage: query exec failed"); +} + +QList JidDb::getMessages(const QString &jid, + const int tail) const +{ + QList ret; + QSqlQuery q(db); + + ensureContactDb(jid); + + if (tail < 0) + { + if (!q.exec("select * from '" + jid + "' order by time;")) + throw std::runtime_error("JidDb::getMessages: query exec failed"); + } + else if (!q.exec("select * from '" + jid + "' order by time desc limit " + + QString::number(tail) + ";")) + throw std::runtime_error("JidDb::getMessages: query exec failed"); + + while (q.next()) + { + Message m; + bool ok; + qlonglong t = q.value("time").toLongLong(&ok); + + if (!ok) + throw std::runtime_error("JidDb::getMessages: invalid time"); + + 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 + throw std::invalid_argument("JidDb::getMessages: invalid direction"); + + ret << m; + } + + return ret; +} + +void JidDb::storeMessage(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; + } + + ensureContactDb(msg.contact); + + if (!q.exec("insert into '" + msg.contact + + "' (direction, time, body) values " + "('" + dir + "', " + + QString::number(msg.dt.toSecsSinceEpoch()) + ", " + "'" + msg.body + "')")) + throw std::runtime_error("JidDb::storeMessage: query exec 2 failed"); +} + +QList JidDb::getConversations() const +{ + QSqlQuery q(db); + + if (!q.exec("select name from sqlite_schema where " + "type = 'table' and name not like 'sqlite_%'")) + throw std::runtime_error("JidDb::getConversations: query failed"); + + QStringList conversations; + + while (q.next()) + conversations << q.value("name").toString(); + + QList ret; + + for (const auto &jid : conversations) + if (jid.contains('@')) + { + const auto messages = getMessages(jid, 1); + + if (!messages.isEmpty()) + { + const auto &m = messages.first(); + + ret << Conversation(jid, m.body, m.dt); + } + } + + return ret; +} -- cgit v1.2.3