Carbon copies basic support

This commit is contained in:
Blue 2019-04-12 18:22:10 +03:00
parent 6e9e100188
commit 48e735b0e9
10 changed files with 215 additions and 52 deletions

View File

@ -25,6 +25,7 @@ add_subdirectory(core)
target_link_libraries(squawk squawkUI)
target_link_libraries(squawk squawkCORE)
target_link_libraries(squawk uuid)
# Install the executable
install(TARGETS squawk DESTINATION bin)

View File

@ -1,5 +1,4 @@
#include "account.h"
#include <qxmpp/QXmppRosterManager.h>
#include <qxmpp/QXmppMessage.h>
#include <QDateTime>
@ -12,7 +11,8 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
config(),
presence(),
state(Shared::disconnected),
groups()
groups(),
cm(new QXmppCarbonManager())
{
config.setUser(p_login);
config.setDomain(p_server);
@ -30,6 +30,11 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
QObject::connect(&rm, SIGNAL(itemRemoved(const QString&)), this, SLOT(onRosterItemRemoved(const QString&)));
QObject::connect(&rm, SIGNAL(itemChanged(const QString&)), this, SLOT(onRosterItemChanged(const QString&)));
//QObject::connect(&rm, SIGNAL(presenceChanged(const QString&, const QString&)), this, SLOT(onRosterPresenceChanged(const QString&, const QString&)));
client.addExtension(cm);
QObject::connect(cm, SIGNAL(messageReceived(const QXmppMessage&)), this, SLOT(onCarbonMessageReceived(const QXmppMessage&)));
QObject::connect(cm, SIGNAL(messageSent(const QXmppMessage&)), this, SLOT(onCarbonMessageSent(const QXmppMessage&)));
}
Account::~Account()
@ -65,6 +70,7 @@ void Core::Account::onClientConnected()
{
if (state == Shared::connecting) {
state = Shared::connected;
cm->setCarbonsEnabled(true);
emit connectionStateChanged(state);
} else {
qDebug("Something weird had happened - xmpp client reported about successful connection but account wasn't in connecting state");
@ -335,36 +341,13 @@ void Core::Account::setResource(const QString& p_resource)
void Core::Account::onMessageReceived(const QXmppMessage& msg)
{
QString from = msg.from();
QString to = msg.to();
bool handled = false;
switch (msg.type()) {
case QXmppMessage::Normal:
qDebug() << "received a message with type \"Normal\", not sure what to do with it now, skipping";
break;
case QXmppMessage::Chat:{
QString body(msg.body());
if (body.size() != 0) {
QString id(msg.id());
QDateTime time(msg.stamp());
Shared::Message sMsg(Shared::Message::chat);
sMsg.setId(id);
sMsg.setFrom(from);
sMsg.setTo(to);
sMsg.setBody(body);
if (time.isValid()) {
sMsg.setTime(time);
}
emit message(sMsg);
if (msg.isReceiptRequested() && id.size() > 0) {
QXmppMessage receipt(getFullJid(), from, "");
receipt.setReceiptId(id);
client.sendPacket(receipt);
handled = true;
}
}
}
case QXmppMessage::Chat:
handled = handleChatMessage(msg);
break;
case QXmppMessage::GroupChat:
qDebug() << "received a message with type \"GroupChat\", not sure what to do with it now, skipping";
@ -377,10 +360,9 @@ void Core::Account::onMessageReceived(const QXmppMessage& msg)
break;
}
if (!handled) {
qDebug() << "Message wasn't handled: ";
qDebug() << "- from: " << from;
qDebug() << "- to: " << to;
qDebug() << "- from: " << msg.from();
qDebug() << "- to: " << msg.to();
qDebug() << "- body: " << msg.body();
qDebug() << "- type: " << msg.type();
qDebug() << "- state: " << msg.state();
@ -404,9 +386,52 @@ QString Core::Account::getFullJid() const
void Core::Account::sendMessage(const Shared::Message& data)
{
if (state == Shared::connected) {
client.sendMessage(data.getTo(), data.getBody());
QXmppMessage msg(data.getFrom(), data.getTo(), data.getBody(), data.getThread());
msg.setId(data.getId());
msg.setType(static_cast<QXmppMessage::Type>(data.getType())); //it is safe here, my type is compatible
client.sendPacket(msg);
} else {
qDebug() << "An attempt to send message with not connected account " << name << ", skipping";
}
}
void Core::Account::onCarbonMessageReceived(const QXmppMessage& msg)
{
handleChatMessage(msg, false, true);
}
void Core::Account::onCarbonMessageSent(const QXmppMessage& msg)
{
handleChatMessage(msg, true, true);
}
bool Core::Account::handleChatMessage(const QXmppMessage& msg, bool outgoing, bool forwarded)
{
QString body(msg.body());
if (body.size() != 0) {
QString id(msg.id());
QDateTime time(msg.stamp());
Shared::Message sMsg(Shared::Message::chat);
sMsg.setId(id);
sMsg.setFrom(msg.from());
sMsg.setTo(msg.to());
sMsg.setBody(body);
sMsg.setForwarded(forwarded);
sMsg.setOutgoing(outgoing);
if (time.isValid()) {
sMsg.setTime(time);
}
emit message(sMsg);
if (!forwarded && !outgoing) {
if (msg.isReceiptRequested() && id.size() > 0) {
QXmppMessage receipt(getFullJid(), msg.from(), "");
receipt.setReceiptId(id);
client.sendPacket(receipt);
}
}
return true;
}
return false;
}

View File

@ -5,6 +5,8 @@
#include <map>
#include <set>
#include <qxmpp/QXmppRosterManager.h>
#include <qxmpp/QXmppCarbonManager.h>
#include <qxmpp/QXmppClient.h>
#include "../global.h"
@ -58,6 +60,7 @@ private:
QXmppPresence presence;
Shared::ConnectionState state;
std::map<QString, std::set<QString>> groups;
QXmppCarbonManager* cm;
private slots:
void onClientConnected();
@ -69,9 +72,12 @@ private slots:
void onRosterPresenceChanged(const QString& bareJid, const QString& resource);
void onPresenceReceived(const QXmppPresence& presence);
void onMessageReceived(const QXmppMessage& message);
void onCarbonMessageReceived(const QXmppMessage& message);
void onCarbonMessageSent(const QXmppMessage& message);
private:
void addedAccount(const QString &bareJid);
bool handleChatMessage(const QXmppMessage& msg, bool outgoing = false, bool forwarded = false);
};
}

View File

@ -1,4 +1,5 @@
#include "global.h"
#include <uuid/uuid.h>
Shared::Message::Message(Shared::Message::Type p_type):
jFrom(),
@ -8,8 +9,10 @@ Shared::Message::Message(Shared::Message::Type p_type):
id(),
body(),
time(),
thread(),
type(p_type),
outgoing(false)
outgoing(false),
forwarded(false)
{
}
@ -21,8 +24,10 @@ Shared::Message::Message():
id(),
body(),
time(),
thread(),
type(Message::normal),
outgoing(false)
outgoing(false),
forwarded(false)
{
}
@ -164,3 +169,42 @@ void Shared::Message::setOutgoing(bool og)
outgoing = og;
}
bool Shared::Message::getForwarded() const
{
return forwarded;
}
void Shared::Message::generateRandomId()
{
uuid_t uuid;
uuid_generate(uuid);
char uuid_str[37];
uuid_unparse_lower(uuid, uuid_str);
id = uuid_str;
}
QString Shared::Message::getThread() const
{
return thread;
}
void Shared::Message::setForwarded(bool fwd)
{
forwarded = fwd;
}
void Shared::Message::setThread(const QString& p_body)
{
thread = p_body;
}
Shared::Message::Type Shared::Message::getType() const
{
return type;
}
void Shared::Message::setType(Shared::Message::Type t)
{
type = t;
}

View File

@ -73,7 +73,10 @@ public:
void setTime(const QDateTime& p_time);
void setId(const QString& p_id);
void setBody(const QString& p_body);
void setThread(const QString& p_body);
void setOutgoing(bool og);
void setForwarded(bool fwd);
void setType(Type t);
QString getFrom() const;
QString getFromJid() const;
@ -84,10 +87,14 @@ public:
QDateTime getTime() const;
QString getId() const;
QString getBody() const;
QString getThread() const;
bool getOutgoing() const;
bool getForwarded() const;
Type getType() const;
QString getPenPalJid() const;
QString getPenPalResource() const;
void generateRandomId();
private:
QString jFrom;
@ -97,8 +104,10 @@ private:
QString id;
QString body;
QDateTime time;
QString thread;
Type type;
bool outgoing;
bool forwarded;
};
};

View File

@ -19,13 +19,16 @@
#include "conversation.h"
#include "ui_conversation.h"
#include <QDebug>
#include <QScrollBar>
Conversation::Conversation(Models::Contact* p_contact, QWidget* parent):
QWidget(parent),
contact(p_contact),
m_ui(new Ui::Conversation),
line(new MessageLine()),
ker()
ker(),
activePalResource(),
thread()
{
m_ui->setupUi(this);
m_ui->splitter->setSizes({300, 0});
@ -47,7 +50,10 @@ Conversation::Conversation(Models::Contact* p_contact, QWidget* parent):
addMessage(*itr);
}
line->setMyName(p_contact->getAccountName());
m_ui->scrollArea->setWidget(line);
m_ui->scrollArea->verticalScrollBar()->setBackgroundRole(QPalette::Base);
}
Conversation::~Conversation()
@ -61,6 +67,7 @@ void Conversation::setName(const QString& name)
m_ui->nameLabel->setText(getJid());
} else {
m_ui->nameLabel->setText(name);
line->setPalName(getJid(), name);
}
}
@ -101,7 +108,19 @@ void Conversation::onContactChanged(Models::Item* item, int row, int col)
void Conversation::addMessage(const Shared::Message& data)
{
int pos = m_ui->scrollArea->verticalScrollBar()->sliderPosition();
int max = m_ui->scrollArea->verticalScrollBar()->maximum();
line->message(data);
if (pos == max) {
m_ui->scrollArea->verticalScrollBar()->setSliderPosition(m_ui->scrollArea->verticalScrollBar()->maximum());
}
if (!data.getOutgoing()) {
const QString& res = data.getPenPalResource();
if (res.size() > 0) {
setPalResource(res);
}
}
}
KeyEnterReceiver::KeyEnterReceiver(QObject* parent): QObject(parent), ownEvent(false) {}
@ -133,17 +152,33 @@ bool KeyEnterReceiver::eventFilter(QObject* obj, QEvent* event)
return QObject::eventFilter(obj, event);
}
QString Conversation::getPalResource() const
{
return activePalResource;
}
void Conversation::setPalResource(const QString& res)
{
activePalResource = res;
}
void Conversation::onEnterPressed()
{
QString body(m_ui->messageEditor->toPlainText());
const QString& aJid = contact->getAccountJid();
m_ui->messageEditor->clear();
Shared::Message msg(Shared::Message::chat);
msg.setFromJid(aJid);
msg.setFromResource(contact->getAccountResource());
msg.setTo(contact->getJid());
msg.setBody(body);
msg.setOutgoing(true);
line->message(msg);
emit sendMessage(msg);
if (body.size() > 0) {
const QString& aJid = contact->getAccountJid();
m_ui->messageEditor->clear();
Shared::Message msg(Shared::Message::chat);
msg.setFromJid(aJid);
msg.setFromResource(contact->getAccountResource());
qDebug() << "sending message from " << contact->getAccountResource();
msg.setToJid(contact->getJid());
msg.setToResource(activePalResource);
msg.setBody(body);
msg.setOutgoing(true);
msg.generateRandomId();
line->message(msg);
emit sendMessage(msg);
}
}

View File

@ -52,8 +52,11 @@ public:
QString getJid() const;
QString getAccount() const;
QString getPalResource() const;
void addMessage(const Shared::Message& data);
void setPalResource(const QString& res);
signals:
void sendMessage(const Shared::Message& message);
@ -71,6 +74,8 @@ private:
MessageLine* line;
QScopedPointer<Ui::Conversation> m_ui;
KeyEnterReceiver ker;
QString activePalResource;
QString thread;
};
#endif // CONVERSATION_H

View File

@ -1,6 +1,6 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2019 Юрий Губич <y.gubich@initi.ru>
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,7 +22,9 @@ MessageLine::MessageLine(QWidget* parent):
QWidget(parent),
messageIndex(),
messageOrder(),
layout(new QVBoxLayout())
layout(new QVBoxLayout()),
myName(),
palNames()
{
setLayout(layout);
setBackgroundRole(QPalette::Base);
@ -39,12 +41,11 @@ void MessageLine::message(const Shared::Message& msg)
QHBoxLayout* hBox = new QHBoxLayout();
QWidget* message = new QWidget();
message->setLayout(vBox);
//message->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
message->setBackgroundRole(QPalette::AlternateBase);
message->setAutoFillBackground(true);;
QLabel* body = new QLabel(msg.getBody());
QLabel* sender = new QLabel(msg.getFrom());
QLabel* sender = new QLabel();
QFont f;
f.setBold(true);
sender->setFont(f);
@ -57,9 +58,17 @@ void MessageLine::message(const Shared::Message& msg)
if (msg.getOutgoing()) {
body->setAlignment(Qt::AlignRight);
sender->setAlignment(Qt::AlignRight);
sender->setText(myName);
hBox->addStretch();
hBox->addWidget(message);
} else {
QString jid = msg.getFromJid();
std::map<QString, QString>::iterator itr = palNames.find(jid);
if (itr != palNames.end()) {
sender->setText(itr->second);
} else {
sender->setText(jid);
}
hBox->addWidget(message);
hBox->addStretch();
}
@ -67,3 +76,17 @@ void MessageLine::message(const Shared::Message& msg)
layout->addLayout(hBox);
}
void MessageLine::setMyName(const QString& name)
{
myName = name;
}
void MessageLine::setPalName(const QString& jid, const QString& name)
{
std::map<QString, QString>::iterator itr = palNames.find(jid);
if (itr == palNames.end()) {
palNames.insert(std::make_pair(jid, name));
} else {
itr->second = name;
}
}

View File

@ -1,6 +1,6 @@
/*
* <one line to give the program's name and a brief idea of what it does.>
* Copyright (C) 2019 Юрий Губич <y.gubich@initi.ru>
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -34,12 +34,17 @@ public:
~MessageLine();
void message(const Shared::Message& msg);
void setMyName(const QString& name);
void setPalName(const QString& jid, const QString& name);
private:
typedef W::Order<Shared::Message*> Order;
std::map<QString, Shared::Message*> messageIndex;
Order messageOrder;
QVBoxLayout* layout;
QString myName;
std::map<QString, QString> palNames;
};
#endif // MESSAGELINE_H

View File

@ -156,12 +156,14 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item)
if (item.isValid()) {
Models::Item* node = static_cast<Models::Item*>(item.internalPointer());
Models::Contact* contact = 0;
QString res;
switch (node->type) {
case Models::Item::contact:
contact = static_cast<Models::Contact*>(node);
break;
case Models::Item::presence:
contact = static_cast<Models::Contact*>(node->parentItem());
res = node->getName();
break;
default:
m_ui->roster->expand(item);
@ -177,6 +179,10 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item)
itr->second->show();
itr->second->raise();
itr->second->activateWindow();
if (res.size() > 0) {
itr->second->setPalResource(res);
}
} else {
Conversation* conv = new Conversation(contact);
@ -188,6 +194,10 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item)
rosterModel.dropMessages(account, jid);
conv->show();
if (res.size() > 0) {
itr->second->setPalResource(res);
}
}
}
}
@ -209,11 +219,11 @@ void Squawk::accountMessage(const QString& account, const Shared::Message& data)
const QString& from = data.getPenPalJid();
Conversations::iterator itr = conversations.find({account, from});
if (itr != conversations.end()) {
qDebug() << "adding message";
itr->second->addMessage(data);
} else {
qDebug() << "pending message";
rosterModel.addMessage(account, data);
if (!data.getForwarded()) {
rosterModel.addMessage(account, data);
}
}
}