aboutsummaryrefslogtreecommitdiff
path: root/xxcc.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 /xxcc.cpp
parent3b8fafc4122848219898245d52dabd669cacb4ba (diff)
First commit
Diffstat (limited to 'xxcc.cpp')
-rw-r--r--xxcc.cpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/xxcc.cpp b/xxcc.cpp
new file mode 100644
index 0000000..9001aaa
--- /dev/null
+++ b/xxcc.cpp
@@ -0,0 +1,264 @@
+#include "xxcc.h"
+#include "client.h"
+#include "direction.h"
+#include "accounts.h"
+#include "contacts.h"
+#include "conversation.h"
+#include "message.h"
+#include <QXmppMessage.h>
+#include <QXmppRosterManager.h>
+#include <QXmppUtils.h>
+#include <QKeyEvent>
+#include <QPushButton>
+#include <QScroller>
+#include <stdexcept>
+#include <utility>
+
+xxcc::xxcc(QWidget *const parent) :
+ QWidget(parent),
+ selected(nullptr)
+{
+ const auto pairs = creds.load();
+
+ ui.setupUi(this);
+ QScroller::grabGesture(ui.conversations_list, QScroller::TouchGesture);
+ QScroller::grabGesture(ui.messages, QScroller::TouchGesture);
+ setupDatabases(pairs);
+ connectAccounts(pairs);
+ retrieveConversations();
+ connect(ui.accounts, &QPushButton::released, this,
+ [this]
+ {
+ Accounts a(clients, this);
+
+ a.connect(&a, &Accounts::new_account, this, &xxcc::addAccount);
+ a.connect(&a, &Accounts::new_account, &creds, &Credentials::store);
+ a.exec();
+ });
+
+ connect(ui.contacts, &QPushButton::released, this,
+ [this]
+ {
+ Contacts c(databases, this);
+
+ connect(&c, &Contacts::startChat, this, &xxcc::startChat);
+
+ for (const auto db : databases)
+ c.connect(db, &JidDb::addedToRoster, &c,
+ [&c, db] (const QString jid)
+ {
+ c.add(db->jid, jid);
+ });
+
+ c.exec();
+ });
+
+ connect(ui.send, &QPushButton::released, this, &xxcc::send);
+ connect(ui.back, &QPushButton::released, this,
+ [this]
+ {
+ ui.sw->setCurrentIndex(Tab::Conversations);
+ ui.messages->clear();
+ selected = nullptr;
+ });
+
+ connect(ui.conversations_list, &QListWidget::itemActivated, this,
+ [this] (QListWidgetItem *const it)
+ {
+ const auto conv = static_cast<const Conversation *>(it);
+
+ for (const auto c : clients)
+ if (c->jidBare() == conv->from)
+ {
+ selected = c;
+ break;
+ }
+
+ for (const auto *const db : databases)
+ if (db->jid == selected->jidBare())
+ {
+ static const auto n_messages = 20;
+ const auto messages = db->getMessages(conv->to, n_messages);
+
+ for (auto it = messages.rbegin(); it != messages.rend(); it++)
+ new Message(it->body, it->dt, it->direction, ui.messages);
+
+ break;
+ }
+
+ ui.sw->setCurrentIndex(Tab::Chat);
+ ui.jid->setText(conv->to);
+ ui.messages->scrollToBottom();
+ });
+
+ connect(ui.messages->model(), &QAbstractItemModel::rowsInserted,
+ ui.messages, &QListWidget::scrollToBottom);
+}
+
+xxcc::~xxcc()
+{
+ for (const auto c : clients)
+ delete c;
+
+ for (const auto db : databases)
+ delete db;
+}
+
+void xxcc::connectAccounts(const QList<Credentials::Pair> &pairs)
+{
+ for (const auto &p : pairs)
+ {
+ QXmppConfiguration cfg;
+
+ cfg.setStreamSecurityMode(QXmppConfiguration::TLSRequired);
+ cfg.setJid(p.first);
+ cfg.setPassword(p.second);
+ cfg.setAutoReconnectionEnabled(true);
+
+ const auto client = new Client;
+
+ addAccount(client);
+ client->connectToServer(cfg);
+ }
+}
+
+void xxcc::setupDatabases(const QList<Credentials::Pair> &pairs)
+{
+ for (const auto &p : pairs)
+ databases.append(new JidDb(p.first));
+}
+
+void xxcc::startChat(const QString from, const QString to)
+{
+ bool found = false;
+
+ for (int i = 0; i < ui.conversations_list->count(); i++)
+ {
+ const auto it =
+ static_cast<const Conversation *>(ui.conversations_list->item(i));
+
+ if (it->from == from && it->to == to)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ new Conversation(from, to, ui.conversations_list);
+
+ for (const auto c : clients)
+ if (c->jidBare() == from)
+ {
+ selected = c;
+ break;
+ }
+
+ ui.sw->setCurrentIndex(Tab::Chat);
+ ui.jid->setText(to);
+ ui.messages->scrollToBottom();
+}
+
+void xxcc::addInMessage(const QXmppMessage &msg)
+{
+ new Message(msg.body(), msg.stamp().toLocalTime(), Direction::In,
+ ui.messages);
+}
+
+void xxcc::addOutMessage(const QXmppMessage &msg)
+{
+ new Message(msg.body(), msg.stamp().toLocalTime(), Direction::Out,
+ ui.messages);
+}
+
+void xxcc::addAccount(Client *const c)
+{
+ c->configuration().setAutoReconnectionEnabled(true);
+ clients.append(c);
+
+ c->connect(c, &Client::messageReceived, this,
+ [this] (QXmppMessage msg)
+ {
+ if (msg.body().isEmpty())
+ return;
+ else if (msg.stamp().isNull())
+ msg.setStamp(QDateTime::currentDateTimeUtc());
+
+ storeMessage(msg, Direction::In);
+
+ if (selected)
+ addInMessage(msg);
+ });
+
+ const auto roster = c->findExtension<QXmppRosterManager>();
+
+ if (roster)
+ roster->connect(roster, &QXmppRosterManager::rosterReceived, c,
+ [this, c, roster]
+ {
+ for (const auto db : databases)
+ if (db->jid == c->jidBare())
+ {
+ db->addToRoster(roster->getRosterBareJids());
+ break;
+ }
+ });
+ else
+ throw std::runtime_error("Expected non-null QXmppRosterManager");
+}
+
+void xxcc::send(void)
+{
+ if (!selected)
+ throw std::runtime_error("Expected non-null selected client");
+
+ const auto from = selected->jidBare(),
+ to = ui.jid->text(), msg = ui.chatinput->toPlainText();
+
+ QXmppMessage out(from, to, msg);
+
+ out.setStamp(QDateTime::currentDateTimeUtc());
+ selected->sendPacket(out);
+ addOutMessage(out);
+ storeMessage(out, Direction::Out);
+ ui.chatinput->clear();
+}
+
+void xxcc::storeMessage(const QXmppMessage &msg, const Direction dir) const
+{
+ QString jid, contact;
+
+ switch (dir)
+ {
+ case Direction::In:
+ jid = QXmppUtils::jidToBareJid(msg.to());
+ contact = QXmppUtils::jidToBareJid(msg.from());
+ break;
+
+ case Direction::Out:
+ jid = msg.from();
+ contact = msg.to();
+ break;
+ }
+
+ for (const auto db : databases)
+ if (db->jid == jid)
+ {
+ JidDb::Message m;
+
+ m.body = msg.body();
+ m.dt = msg.stamp();
+ m.direction = dir;
+ m.contact = contact;
+ db->storeMessage(m);
+ break;
+ }
+}
+
+void xxcc::retrieveConversations()
+{
+ for (const auto *const db : databases)
+ for (const auto &conv : db->getConversations())
+ new Conversation(db->jid, conv.to,
+ ui.conversations_list, conv.last_msg, conv.dt);
+}