#include "yc.h" #include "client.h" #include "direction.h" #include #include #include #include #include #include #include #include void Yc::connectAccounts(const QList &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(p.first); addAccount(client); client->connectToServer(cfg); } } void Yc::send(const QString to, const QString msg, const bool omemo) { if (!selected) throw std::runtime_error("Expected non-null selected client"); const auto from = selected->jidBare(); QXmppMessage out(from, to, msg); const auto dt = QDateTime::currentDateTimeUtc(); out.setStamp(dt); auto fn = [=](const QXmpp::SendResult &&result) mutable { if (std::holds_alternative(result)) { const auto &success = std::get(result); addOutMessage(msg, dt); storeMessage(from, to, msg, dt, Direction::Out); Q_EMIT sent(); } else if (std::holds_alternative(result)) { const auto &error = std::get(result); Q_EMIT sendError(error.description); } }; if (omemo) { out.setE2eeFallbackBody("[xxcc: This is an OMEMO-encrypted message]"); // TODO: QXmpp forces OMEMO 2 (XEP-0384 version >= 0.8.0). // This breaks compatibility with Dino and Gajim, who still use 0.1.0. // out.setEncryptionMethod(QXmpp::Omemo0); selected->sendSensitive(std::move(out)).then(this, fn); } else selected->send(std::move(out)).then(this, fn); } void Yc::startChat(const QString from, const QString to) { for (const auto c : clients) if (c->jidBare() == from) { selected = c; break; } } void Yc::addInMessage(const QXmppMessage &msg) { #if 0 new Message(msg.body(), msg.stamp().toLocalTime(), Direction::In, ui.messages); #endif } void Yc::addOutMessage(const QString &msg, const QDateTime &dt) { #if 0 new Message(msg, dt.toLocalTime(), Direction::Out, ui.messages); #endif } void Yc::storeAccount(Client *c) { creds.store(c); } void Yc::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(); if (roster) roster->connect(roster, &QXmppRosterManager::rosterReceived, c, [this, c, roster] { c->database().addToRoster(roster->getRosterBareJids()); }); else throw std::runtime_error("Expected non-null QXmppRosterManager"); } void Yc::storeMessage(const QString &from, const QString &to, const QString &msg, const QDateTime &dt, const Direction dir) const { QString jid, contact; switch (dir) { case Direction::In: jid = QXmppUtils::jidToBareJid(to); contact = QXmppUtils::jidToBareJid(from); break; case Direction::Out: jid = from; contact = to; break; } for (const auto c : clients) { if (c->jidBare() == jid) { const auto &db = c->database(); JidDb::Message m; m.body = msg; m.dt = dt; m.direction = dir; m.contact = contact; db.store(m); } } } void Yc::storeMessage(const QXmppMessage &msg, const Direction dir) const { storeMessage(msg.from(), msg.to(), msg.body(), msg.stamp(), dir); } void Yc::retrieveConversations() { for (const auto c : clients) { const auto &db = c->database(); for (const auto &conv : db.conversations()) { #if 0 new Conversation(db.jid, conv.to, ui.conversations_list, conv.last_msg, conv.dt); #else emit newConversation(db.jid, conv.to, conv.last_msg); #endif } } } QStringList Yc::accounts() const { QStringList ret; for (const auto c : clients) ret << c->jidBare(); return ret; } void Yc::init() { creds.load().then(this, [=] (Credentials::PairListResult &&result) { if (std::holds_alternative(result)) { const auto &pairs = std::get(result); connectAccounts(pairs); retrieveConversations(); } else if (std::holds_alternative(result)) { const auto &error = std::get(result); std::cerr << qPrintable(error.description) << std::endl; } }); } Yc::~Yc() { for (const auto c : clients) delete c; } Yc::Yc(QObject *parent) : QObject(parent), selected(nullptr) { }