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 /xxcc.cpp | |
| parent | 3b8fafc4122848219898245d52dabd669cacb4ba (diff) | |
First commit
Diffstat (limited to 'xxcc.cpp')
| -rw-r--r-- | xxcc.cpp | 264 |
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); +} |
