aboutsummaryrefslogtreecommitdiff
path: root/jiddb.cpp
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-06-12 23:47:17 +0200
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-06-29 14:09:46 +0200
commit05b2584fa4d773f5a88ed3ce98f5dd8304e11c34 (patch)
treef72e73c3259b8100e886f49f67ecc669b7667502 /jiddb.cpp
parent3b8fafc4122848219898245d52dabd669cacb4ba (diff)
First commit
Diffstat (limited to 'jiddb.cpp')
-rw-r--r--jiddb.cpp175
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;
+}