diff options
| author | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2023-06-12 23:47:17 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi.dcr@tutanota.com> | 2023-06-29 14:09:46 +0200 |
| commit | 05b2584fa4d773f5a88ed3ce98f5dd8304e11c34 (patch) | |
| tree | f72e73c3259b8100e886f49f67ecc669b7667502 /jiddb.cpp | |
| parent | 3b8fafc4122848219898245d52dabd669cacb4ba (diff) | |
First commit
Diffstat (limited to 'jiddb.cpp')
| -rw-r--r-- | jiddb.cpp | 175 |
1 files changed, 175 insertions, 0 deletions
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 <QDir> +#include <QSqlQuery> +#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; +} + +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::Message> JidDb::getMessages(const QString &jid, + const int tail) const +{ + QList<Message> 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::Conversation> 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<Conversation> 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; +} |
