1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

style: reformat current C++ codebase using clang-format

This commit is contained in:
Zetok Zalbavar 2017-02-26 11:52:45 +00:00
parent 4367dc601d
commit 80f5de31b3
No known key found for this signature in database
GPG Key ID: C953D3880212068A
259 changed files with 5914 additions and 7772 deletions

View File

@ -27,8 +27,8 @@
#include <QMutexLocker>
#include <QPointer>
#include <QThread>
#include <QtMath>
#include <QWaitCondition>
#include <QtMath>
#include <cassert>
@ -102,7 +102,8 @@ private:
* @param s Name of the sound to get the path of.
* @return The path of the requested sound.
*
* @fn void Audio::frameAvailable(const int16_t *pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate);
* @fn void Audio::frameAvailable(const int16_t *pcm, size_t sample_count, uint8_t channels,
* uint32_t sampling_rate);
*
* When there are input subscribers, we regularly emit captured audio frames with this signal
* Always connect with a blocking queued connection lambda, else the behaviour is undefined
@ -191,8 +192,7 @@ qreal Audio::outputVolume() const
ALfloat volume = 0.0;
if (alOutDev)
{
if (alOutDev) {
alGetListenerf(AL_GAIN, &volume);
checkAlError();
}
@ -302,8 +302,7 @@ void Audio::subscribeInput()
{
QMutexLocker locker(&audioLock);
if (!autoInitInput())
{
if (!autoInitInput()) {
qWarning("Failed to subscribe to audio input device.");
return;
}
@ -325,7 +324,8 @@ void Audio::unsubscribeInput()
return;
inSubscriptions--;
qDebug() << "Unsubscribed from audio input device [" << inSubscriptions << "subscriptions left ]";
qDebug() << "Unsubscribed from audio input device [" << inSubscriptions
<< "subscriptions left ]";
if (!inSubscriptions)
cleanupInput();
@ -367,14 +367,11 @@ bool Audio::initInput(const QString& deviceName)
const ALCsizei bufSize = (frameDuration * sampleRate * 4) / 1000 * chnls;
const QByteArray qDevName = deviceName.toUtf8();
const ALchar* tmpDevName = qDevName.isEmpty()
? nullptr
: qDevName.constData();
const ALchar* tmpDevName = qDevName.isEmpty() ? nullptr : qDevName.constData();
alInDev = alcCaptureOpenDevice(tmpDevName, sampleRate, stereoFlag, bufSize);
// Restart the capture if necessary
if (!alInDev)
{
if (!alInDev) {
qWarning() << "Failed to initialize audio input device:" << deviceName;
return false;
}
@ -402,13 +399,10 @@ bool Audio::initOutput(const QString& deviceName)
assert(!alOutDev);
const QByteArray qDevName = deviceName.toUtf8();
const ALchar* tmpDevName = qDevName.isEmpty()
? nullptr
: qDevName.constData();
const ALchar* tmpDevName = qDevName.isEmpty() ? nullptr : qDevName.constData();
alOutDev = alcOpenDevice(tmpDevName);
if (!alOutDev)
{
if (!alOutDev) {
qWarning() << "Cannot open output audio device" << deviceName;
return false;
}
@ -417,8 +411,7 @@ bool Audio::initOutput(const QString& deviceName)
alOutContext = alcCreateContext(alOutDev, nullptr);
checkAlcError(alOutDev);
if (!alcMakeContextCurrent(alOutContext))
{
if (!alcMakeContextCurrent(alOutContext)) {
qWarning() << "Cannot create output audio context";
return false;
}
@ -431,8 +424,7 @@ bool Audio::initOutput(const QString& deviceName)
checkAlError();
Core* core = Core::getInstance();
if (core)
{
if (core) {
// reset each call's audio source
core->getAv()->invalidateCallSources();
}
@ -466,8 +458,7 @@ void Audio::playMono16Sound(const QByteArray& data)
ALint state;
alGetSourcei(alMainSource, AL_SOURCE_STATE, &state);
if (state == AL_PLAYING)
{
if (state == AL_PLAYING) {
alSourceStop(alMainSource);
alSourcei(alMainSource, AL_BUFFER, AL_NONE);
}
@ -480,7 +471,8 @@ void Audio::playMono16Sound(const QByteArray& data)
playMono16Timer.start(durationMs + 50);
}
void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate)
void Audio::playAudioBuffer(ALuint alSource, const int16_t* data, int samples, unsigned channels,
int sampleRate)
{
assert(channels == 1 || channels == 2);
QMutexLocker locker(&audioLock);
@ -494,19 +486,14 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u
alGetSourcei(alSource, AL_BUFFERS_QUEUED, &queued);
alSourcei(alSource, AL_LOOPING, AL_FALSE);
if (processed)
{
if (processed) {
ALuint bufids[processed];
alSourceUnqueueBuffers(alSource, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
}
else if (queued < 16)
{
} else if (queued < 16) {
alGenBuffers(1, &bufid);
}
else
{
} else {
return;
}
@ -543,14 +530,12 @@ void Audio::cleanupOutput()
{
outputInitialized = false;
if (alOutDev)
{
if (alOutDev) {
alSourcei(alMainSource, AL_LOOPING, AL_FALSE);
alSourceStop(alMainSource);
alDeleteSources(1, &alMainSource);
if (alMainBuffer)
{
if (alMainBuffer) {
alDeleteBuffers(1, &alMainBuffer);
alMainBuffer = 0;
}
@ -578,8 +563,7 @@ void Audio::playMono16SoundCleanup()
ALint state;
alGetSourcei(alMainSource, AL_SOURCE_STATE, &state);
if (state == AL_STOPPED)
{
if (state == AL_STOPPED) {
alSourcei(alMainSource, AL_BUFFER, AL_NONE);
alDeleteBuffers(1, &alMainBuffer);
alMainBuffer = 0;
@ -604,11 +588,10 @@ void Audio::doCapture()
int16_t buf[AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS];
alcCaptureSamples(alInDev, buf, AUDIO_FRAME_SAMPLE_COUNT);
for (quint32 i = 0; i < AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS; ++i)
{
for (quint32 i = 0; i < AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS; ++i) {
// gain amplification with clipping to 16-bit boundaries
int ampPCM = qBound<int>(std::numeric_limits<int16_t>::min(),
qRound(buf[i] * d->inputGainFactor()),
int ampPCM =
qBound<int>(std::numeric_limits<int16_t>::min(), qRound(buf[i] * d->inputGainFactor()),
std::numeric_limits<int16_t>::max());
buf[i] = static_cast<int16_t>(ampPCM);
@ -631,10 +614,8 @@ QStringList Audio::outDeviceNames()
QStringList list;
const ALchar* pDeviceList = Private::outDeviceNames();
if (pDeviceList)
{
while (*pDeviceList)
{
if (pDeviceList) {
while (*pDeviceList) {
int len = static_cast<int>(strlen(pDeviceList));
list << QString::fromUtf8(pDeviceList, len);
pDeviceList += len + 1;
@ -649,10 +630,8 @@ QStringList Audio::inDeviceNames()
QStringList list;
const ALchar* pDeviceList = Private::inDeviceNames();
if (pDeviceList)
{
while (*pDeviceList)
{
if (pDeviceList) {
while (*pDeviceList) {
int len = static_cast<int>(strlen(pDeviceList));
list << QString::fromUtf8(pDeviceList, len);
pDeviceList += len + 1;
@ -666,14 +645,12 @@ void Audio::subscribeOutput(ALuint& sid)
{
QMutexLocker locker(&audioLock);
if (!autoInitOutput())
{
if (!autoInitOutput()) {
qWarning("Failed to subscribe to audio output device.");
return;
}
if (!alcMakeContextCurrent(alOutContext))
{
if (!alcMakeContextCurrent(alOutContext)) {
qWarning("Failed to activate output context.");
return;
}
@ -682,8 +659,7 @@ void Audio::subscribeOutput(ALuint& sid)
assert(sid);
outSources << sid;
qDebug() << "Audio source" << sid << "created. Sources active:"
<< outSources.size();
qDebug() << "Audio source" << sid << "created. Sources active:" << outSources.size();
}
void Audio::unsubscribeOutput(ALuint& sid)
@ -692,13 +668,10 @@ void Audio::unsubscribeOutput(ALuint &sid)
outSources.removeAll(sid);
if (sid)
{
if (alIsSource(sid))
{
if (sid) {
if (alIsSource(sid)) {
alDeleteSources(1, &sid);
qDebug() << "Audio source" << sid << "deleted. Sources active:"
<< outSources.size();
qDebug() << "Audio source" << sid << "deleted. Sources active:" << outSources.size();
} else {
qWarning() << "Trying to delete invalid audio source" << sid;
}
@ -724,8 +697,7 @@ void Audio::stopLoop()
ALint state;
alGetSourcei(alMainSource, AL_SOURCE_STATE, &state);
if (state == AL_STOPPED)
{
if (state == AL_STOPPED) {
alSourcei(alMainSource, AL_BUFFER, AL_NONE);
alDeleteBuffers(1, &alMainBuffer);
alMainBuffer = 0;

View File

@ -24,8 +24,8 @@
#include <atomic>
#include <cmath>
#include <QObject>
#include <QMutex>
#include <QObject>
#include <QTimer>
#include <cassert>
@ -51,12 +51,16 @@ class Audio : public QObject
class Private;
public:
enum class Sound { NewMessage, Test, IncomingCall };
inline static QString getSound(Sound s) {
switch (s)
enum class Sound
{
NewMessage,
Test,
IncomingCall
};
inline static QString getSound(Sound s)
{
switch (s) {
case Sound::Test:
return QStringLiteral(":/audio/notification.pcm");
case Sound::NewMessage:
@ -100,8 +104,8 @@ public:
void playMono16Sound(const QByteArray& data);
void playMono16Sound(const QString& path);
void playAudioBuffer(ALuint alSource, const int16_t *data, int samples,
unsigned channels, int sampleRate);
void playAudioBuffer(ALuint alSource, const int16_t* data, int samples, unsigned channels,
int sampleRate);
public:
// Public default audio settings
@ -111,7 +115,8 @@ public:
static constexpr uint32_t AUDIO_CHANNELS = 2;
signals:
void frameAvailable(const int16_t *pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate);
void frameAvailable(const int16_t* pcm, size_t sample_count, uint8_t channels,
uint32_t sampling_rate);
private:
Audio();

View File

@ -25,13 +25,11 @@
ChatLine::ChatLine()
{
}
ChatLine::~ChatLine()
{
for (ChatLineContent* c : content)
{
for (ChatLineContent* c : content) {
if (c->scene())
c->scene()->removeItem(c);
@ -49,8 +47,7 @@ void ChatLine::setRow(int idx)
void ChatLine::visibilityChanged(bool visible)
{
if (isVisible != visible)
{
if (isVisible != visible) {
for (ChatLineContent* c : content)
c->visibilityChanged(visible);
}
@ -73,8 +70,7 @@ ChatLineContent *ChatLine::getContent(int col) const
ChatLineContent* ChatLine::getContent(QPointF scenePos) const
{
for (ChatLineContent* c: content)
{
for (ChatLineContent* c : content) {
if (c->sceneBoundingRect().contains(scenePos))
return c;
}
@ -84,8 +80,7 @@ ChatLineContent *ChatLine::getContent(QPointF scenePos) const
void ChatLine::removeFromScene()
{
for (ChatLineContent* c : content)
{
for (ChatLineContent* c : content) {
if (c->scene())
c->scene()->removeItem(c);
}
@ -135,7 +130,8 @@ void ChatLine::updateBBox()
bbox.setWidth(width);
for (ChatLineContent* c : content)
bbox.setHeight(qMax(c->sceneBoundingRect().top() - bbox.top() + c->sceneBoundingRect().height(), bbox.height()));
bbox.setHeight(qMax(c->sceneBoundingRect().top() - bbox.top() + c->sceneBoundingRect().height(),
bbox.height()));
}
QRectF ChatLine::sceneBoundingRect() const
@ -154,8 +150,7 @@ void ChatLine::addColumn(ChatLineContent* item, ColumnFormat fmt)
void ChatLine::replaceContent(int col, ChatLineContent* lineContent)
{
if (col >= 0 && col < static_cast<int>(content.size()) && lineContent)
{
if (col >= 0 && col < static_cast<int>(content.size()) && lineContent) {
QGraphicsScene* scene = content[col]->scene();
delete content[col];
@ -182,8 +177,7 @@ void ChatLine::layout(qreal w, QPointF scenePos)
qreal fixedWidth = (content.size() - 1) * columnSpacing;
qreal varWidth = 0.0; // used for normalisation
for (int i = 0; i < format.size(); ++i)
{
for (int i = 0; i < format.size(); ++i) {
if (format[i].policy == ColumnFormat::FixedSize)
fixedWidth += format[i].size;
else
@ -199,8 +193,7 @@ void ChatLine::layout(qreal w, QPointF scenePos)
qreal xOffset = 0.0;
QVector<qreal> xPos(content.size());
for (int i = 0; i < content.size(); ++i)
{
for (int i = 0; i < content.size(); ++i) {
// calculate the effective width of the current column
qreal width;
if (format[i].policy == ColumnFormat::FixedSize)
@ -214,8 +207,7 @@ void ChatLine::layout(qreal w, QPointF scenePos)
// calculate horizontal alignment
qreal xAlign = 0.0;
switch(format[i].hAlign)
{
switch (format[i].hAlign) {
case ColumnFormat::Left:
break;
case ColumnFormat::Right:
@ -233,8 +225,7 @@ void ChatLine::layout(qreal w, QPointF scenePos)
maxVOffset = qMax(maxVOffset, content[i]->getAscent());
}
for (int i = 0; i < content.size(); ++i)
{
for (int i = 0; i < content.size(); ++i) {
// calculate vertical alignment
// vertical alignment may depend on width, so we do it in a second pass
qreal yOffset = maxVOffset - content[i]->getAscent();

View File

@ -20,10 +20,10 @@
#ifndef CHATLINE_H
#define CHATLINE_H
#include <memory>
#include <QPointF>
#include <QRectF>
#include <QVector>
#include <memory>
class ChatLog;
class ChatLineContent;
@ -33,23 +33,28 @@ class QFont;
struct ColumnFormat
{
enum Policy {
enum Policy
{
FixedSize,
VariableSize,
};
enum Align {
enum Align
{
Left,
Center,
Right,
};
ColumnFormat() {}
ColumnFormat()
{
}
ColumnFormat(qreal s, Policy p, Align halign = Left)
: size(s)
, policy(p)
, hAlign(halign)
{}
{
}
qreal size = 1.0;
Policy policy = VariableSize;
@ -109,7 +114,6 @@ private:
qreal columnSpacing = 15.0;
QRectF bbox;
bool isVisible = false;
};
#endif // CHATLINE_H

View File

@ -42,27 +42,22 @@ int ChatLineContent::type() const
void ChatLineContent::selectionMouseMove(QPointF)
{
}
void ChatLineContent::selectionStarted(QPointF)
{
}
void ChatLineContent::selectionCleared()
{
}
void ChatLineContent::selectionDoubleClick(QPointF)
{
}
void ChatLineContent::selectionFocusChanged(bool)
{
}
bool ChatLineContent::isOverSelection(QPointF) const
@ -86,7 +81,6 @@ qreal ChatLineContent::getAscent() const
void ChatLineContent::visibilityChanged(bool)
{
}
QString ChatLineContent::getText() const

View File

@ -19,10 +19,10 @@
#include "chatlinecontentproxy.h"
#include "src/chatlog/content/filetransferwidget.h"
#include <QLayout>
#include <QWidget>
#include <QPainter>
#include <QDebug>
#include <QLayout>
#include <QPainter>
#include <QWidget>
/**
* @enum ChatLineContentProxy::ChatLineContentProxyType
@ -32,7 +32,8 @@
* @value FileTransferWidgetType = 0
*/
ChatLineContentProxy::ChatLineContentProxy(QWidget* widget, ChatLineContentProxyType type, int minWidth, float widthInPercent)
ChatLineContentProxy::ChatLineContentProxy(QWidget* widget, ChatLineContentProxyType type,
int minWidth, float widthInPercent)
: widthPercent(widthInPercent)
, widthMin(minWidth)
, widgetType{type}
@ -58,7 +59,8 @@ QRectF ChatLineContentProxy::boundingRect() const
return result;
}
void ChatLineContentProxy::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
void ChatLineContentProxy::paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
QWidget* widget)
{
painter->setClipRect(boundingRect());
proxy->paint(painter, option, widget);

View File

@ -20,8 +20,8 @@
#ifndef CHATLINECONTENTPROXY_H
#define CHATLINECONTENTPROXY_H
#include <QGraphicsProxyWidget>
#include "chatlinecontent.h"
#include <QGraphicsProxyWidget>
class FileTransferWidget;
@ -49,7 +49,8 @@ public:
ChatLineContentProxyType getWidgetType() const;
protected:
ChatLineContentProxy(QWidget* widget, ChatLineContentProxyType type, int minWidth, float widthInPercent);
ChatLineContentProxy(QWidget* widget, ChatLineContentProxyType type, int minWidth,
float widthInPercent);
private:
QGraphicsProxyWidget* proxy;

View File

@ -18,20 +18,20 @@
*/
#include "chatlog.h"
#include "chatmessage.h"
#include "chatlinecontent.h"
#include "chatlinecontentproxy.h"
#include "chatmessage.h"
#include "content/filetransferwidget.h"
#include "src/widget/translator.h"
#include <QDebug>
#include <QScrollBar>
#include <QAction>
#include <QApplication>
#include <QClipboard>
#include <QAction>
#include <QTimer>
#include <QDebug>
#include <QMouseEvent>
#include <QScrollBar>
#include <QShortcut>
#include <QTimer>
/**
* @var ChatLog::repNameAfter
@ -76,27 +76,18 @@ ChatLog::ChatLog(QWidget* parent)
copyAction->setIcon(QIcon::fromTheme("edit-copy"));
copyAction->setShortcut(QKeySequence::Copy);
copyAction->setEnabled(false);
connect(copyAction, &QAction::triggered, this, [this]()
{
copySelectedText();
});
connect(copyAction, &QAction::triggered, this, [this]() { copySelectedText(); });
addAction(copyAction);
// Ctrl+Insert shortcut
QShortcut* copyCtrlInsShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Insert), this);
connect(copyCtrlInsShortcut, &QShortcut::activated, this, [this]()
{
copySelectedText();
});
connect(copyCtrlInsShortcut, &QShortcut::activated, this, [this]() { copySelectedText(); });
// select all action (ie. Ctrl+A)
selectAllAction = new QAction(this);
selectAllAction->setIcon(QIcon::fromTheme("edit-select-all"));
selectAllAction->setShortcut(QKeySequence::SelectAll);
connect(selectAllAction, &QAction::triggered, this, [this]()
{
selectAll();
});
connect(selectAllAction, &QAction::triggered, this, [this]() { selectAll(); });
addAction(selectAllAction);
// This timer is used to scroll the view while the user is
@ -183,8 +174,7 @@ void ChatLog::layout(int start, int end, qreal width)
start = clamp<int>(start, 0, lines.size());
end = clamp<int>(end + 1, 0, lines.size());
for (int i = start; i < end; ++i)
{
for (int i = start; i < end; ++i) {
ChatLine* l = lines[i].get();
l->layout(width, QPointF(0.0, h));
@ -196,8 +186,7 @@ void ChatLog::mousePressEvent(QMouseEvent* ev)
{
QGraphicsView::mousePressEvent(ev);
if (ev->button() == Qt::LeftButton)
{
if (ev->button() == Qt::LeftButton) {
clickPos = ev->pos();
clearSelection();
}
@ -216,8 +205,7 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev)
QPointF scenePos = mapToScene(ev->pos());
if (ev->buttons() & Qt::LeftButton)
{
if (ev->buttons() & Qt::LeftButton) {
// autoscroll
if (ev->pos().y() < 0)
selectionScrollDir = Up;
@ -227,14 +215,13 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev)
selectionScrollDir = NoDirection;
// select
if (selectionMode == None && (clickPos - ev->pos()).manhattanLength() > QApplication::startDragDistance())
{
if (selectionMode == None
&& (clickPos - ev->pos()).manhattanLength() > QApplication::startDragDistance()) {
QPointF sceneClickPos = mapToScene(clickPos.toPoint());
ChatLine::Ptr line = findLineByPosY(scenePos.y());
ChatLineContent* content = getContentFromPos(sceneClickPos);
if (content)
{
if (content) {
selClickedRow = content->getRow();
selClickedCol = content->getColumn();
selFirstRow = content->getRow();
@ -247,9 +234,7 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev)
// ungrab mouse grabber
if (scene->mouseGrabberItem())
scene->mouseGrabberItem()->ungrabMouse();
}
else if (line.get())
{
} else if (line.get()) {
selClickedRow = line->getRow();
selFirstRow = selClickedRow;
selLastRow = selClickedRow;
@ -258,44 +243,34 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev)
}
}
if (selectionMode != None)
{
if (selectionMode != None) {
ChatLineContent* content = getContentFromPos(scenePos);
ChatLine::Ptr line = findLineByPosY(scenePos.y());
int row;
if (content)
{
if (content) {
row = content->getRow();
int col = content->getColumn();
if (row == selClickedRow && col == selClickedCol)
{
if (row == selClickedRow && col == selClickedCol) {
selectionMode = Precise;
content->selectionMouseMove(scenePos);
selGraphItem->hide();
}
else if (col != selClickedCol)
{
} else if (col != selClickedCol) {
selectionMode = Multi;
lines[selClickedRow]->selectionCleared();
}
}
else if (line.get())
{
} else if (line.get()) {
row = line->getRow();
if (row != selClickedRow)
{
if (row != selClickedRow) {
selectionMode = Multi;
lines[selClickedRow]->selectionCleared();
}
}
else
{
} else {
return;
}
@ -318,7 +293,8 @@ ChatLineContent* ChatLog::getContentFromPos(QPointF scenePos) const
if (lines.empty())
return nullptr;
auto itr = std::lower_bound(lines.cbegin(), lines.cend(), scenePos.y(), ChatLine::lessThanBSRectBottom);
auto itr =
std::lower_bound(lines.cbegin(), lines.cend(), scenePos.y(), ChatLine::lessThanBSRectBottom);
// find content
if (itr != lines.cend() && (*itr)->sceneBoundingRect().contains(scenePos))
@ -329,15 +305,12 @@ ChatLineContent* ChatLog::getContentFromPos(QPointF scenePos) const
bool ChatLog::isOverSelection(QPointF scenePos) const
{
if (selectionMode == Precise)
{
if (selectionMode == Precise) {
ChatLineContent* content = getContentFromPos(scenePos);
if (content)
return content->isOverSelection(scenePos);
}
else if (selectionMode == Multi)
{
} else if (selectionMode == Multi) {
if (selGraphItem->rect().contains(scenePos))
return true;
}
@ -358,8 +331,7 @@ void ChatLog::reposition(int start, int end, qreal deltaY)
start = clamp<int>(start, 0, lines.size() - 1);
end = clamp<int>(end + 1, 0, lines.size());
for (int i = start; i < end; ++i)
{
for (int i = start; i < end; ++i) {
ChatLine* l = lines[i].get();
l->moveBy(deltaY);
}
@ -410,8 +382,7 @@ void ChatLog::insertChatlineOnTop(const QList<ChatLine::Ptr>& newLines)
// add the new lines
int i = 0;
for (ChatLine::Ptr l : newLines)
{
for (ChatLine::Ptr l : newLines) {
l->addToScene(scene);
l->visibilityChanged(false);
l->setRow(i++);
@ -419,8 +390,7 @@ void ChatLog::insertChatlineOnTop(const QList<ChatLine::Ptr>& newLines)
}
// add the old lines
for (ChatLine::Ptr l : lines)
{
for (ChatLine::Ptr l : lines) {
l->setRow(i++);
combLines.push_back(l);
}
@ -450,8 +420,7 @@ void ChatLog::startResizeWorker()
return;
// (re)start the worker
if (!workerTimer->isActive())
{
if (!workerTimer->isActive()) {
// these values must not be reevaluated while the worker is running
workerStb = stickToBottom();
@ -462,8 +431,7 @@ void ChatLog::startResizeWorker()
// switch to busy scene displaying the busy notification if there is a lot
// of text to be resized
int txt = 0;
for (ChatLine::Ptr line : lines)
{
for (ChatLine::Ptr line : lines) {
if (txt > 500000)
break;
for (ChatLineContent* content : line->content)
@ -483,8 +451,7 @@ void ChatLog::mouseDoubleClickEvent(QMouseEvent *ev)
QPointF scenePos = mapToScene(ev->pos());
ChatLineContent* content = getContentFromPos(scenePos);
if (content)
{
if (content) {
content->selectionDoubleClick(scenePos);
selClickedCol = content->getColumn();
selClickedRow = content->getRow();
@ -498,25 +465,24 @@ void ChatLog::mouseDoubleClickEvent(QMouseEvent *ev)
QString ChatLog::getSelectedText() const
{
if (selectionMode == Precise)
{
if (selectionMode == Precise) {
return lines[selClickedRow]->content[selClickedCol]->getSelectedText();
}
else if (selectionMode == Multi)
{
} else if (selectionMode == Multi) {
// build a nicely formatted message
QString out;
for (int i=selFirstRow; i<=selLastRow; ++i)
{
for (int i = selFirstRow; i <= selLastRow; ++i) {
if (lines[i]->content[1]->getText().isEmpty())
continue;
QString timestamp = lines[i]->content[2]->getText().isEmpty() ? tr("pending") : lines[i]->content[2]->getText();
QString timestamp = lines[i]->content[2]->getText().isEmpty()
? tr("pending")
: lines[i]->content[2]->getText();
QString author = lines[i]->content[0]->getText();
QString msg = lines[i]->content[1]->getText();
out += QString(out.isEmpty() ? "[%2] %1: %3" : "\n[%2] %1: %3").arg(author, timestamp, msg);
out +=
QString(out.isEmpty() ? "[%2] %1: %3" : "\n[%2] %1: %3").arg(author, timestamp, msg);
}
return out;
@ -547,8 +513,7 @@ QVector<ChatLine::Ptr> ChatLog::getLines()
ChatLine::Ptr ChatLog::getLatestLine() const
{
if (!lines.empty())
{
if (!lines.empty()) {
return lines.last();
}
return nullptr;
@ -570,8 +535,7 @@ void ChatLog::clear()
QVector<ChatLine::Ptr> savedLines;
for (ChatLine::Ptr l : lines)
{
for (ChatLine::Ptr l : lines) {
if (isActiveFileTransfer(l))
savedLines.push_back(l);
else
@ -616,8 +580,7 @@ void ChatLog::setTypingNotification(ChatLine::Ptr notification)
void ChatLog::setTypingNotificationVisible(bool visible)
{
if (typingNotification.get())
{
if (typingNotification.get()) {
typingNotification->setVisible(visible);
updateTypingNotification();
}
@ -649,8 +612,7 @@ void ChatLog::selectAll()
void ChatLog::fontChanged(const QFont& font)
{
for (ChatLine::Ptr l : lines)
{
for (ChatLine::Ptr l : lines) {
l->fontChanged(font);
}
}
@ -666,15 +628,16 @@ void ChatLog::checkVisibility()
return;
// find first visible line
auto lowerBound = std::lower_bound(lines.cbegin(), lines.cend(), getVisibleRect().top(), ChatLine::lessThanBSRectBottom);
auto lowerBound = std::lower_bound(lines.cbegin(), lines.cend(), getVisibleRect().top(),
ChatLine::lessThanBSRectBottom);
// find last visible line
auto upperBound = std::lower_bound(lowerBound, lines.cend(), getVisibleRect().bottom(), ChatLine::lessThanBSRectTop);
auto upperBound = std::lower_bound(lowerBound, lines.cend(), getVisibleRect().bottom(),
ChatLine::lessThanBSRectTop);
// set visibilty
QList<ChatLine::Ptr> newVisibleLines;
for (auto itr = lowerBound; itr != upperBound; ++itr)
{
for (auto itr = lowerBound; itr != upperBound; ++itr) {
newVisibleLines.append(*itr);
if (!visibleLines.contains(*itr))
@ -693,7 +656,8 @@ void ChatLog::checkVisibility()
std::sort(visibleLines.begin(), visibleLines.end(), ChatLine::lessThanRowIndex);
// if (!visibleLines.empty())
// qDebug() << "visible from " << visibleLines.first()->getRow() << "to " << visibleLines.last()->getRow() << " total " << visibleLines.size();
// qDebug() << "visible from " << visibleLines.first()->getRow() << "to " <<
// visibleLines.last()->getRow() << " total " << visibleLines.size();
}
void ChatLog::scrollContentsBy(int dx, int dy)
@ -706,8 +670,7 @@ void ChatLog::resizeEvent(QResizeEvent* ev)
{
bool stb = stickToBottom();
if (ev->size().width() != ev->oldSize().width())
{
if (ev->size().width() != ev->oldSize().width()) {
startResizeWorker();
stb = false; // let the resize worker handle it
}
@ -722,8 +685,7 @@ void ChatLog::resizeEvent(QResizeEvent* ev)
void ChatLog::updateMultiSelectionRect()
{
if (selectionMode == Multi && selFirstRow >= 0 && selLastRow >= 0)
{
if (selectionMode == Multi && selFirstRow >= 0 && selLastRow >= 0) {
QRectF selBBox;
selBBox = selBBox.united(lines[selFirstRow]->sceneBoundingRect());
selBBox = selBBox.united(lines[selLastRow]->sceneBoundingRect());
@ -733,9 +695,7 @@ void ChatLog::updateMultiSelectionRect()
selGraphItem->setRect(selBBox);
selGraphItem->show();
}
else
{
} else {
selGraphItem->hide();
}
}
@ -756,10 +716,10 @@ void ChatLog::updateTypingNotification()
void ChatLog::updateBusyNotification()
{
if (busyNotification.get())
{
if (busyNotification.get()) {
// repoisition the busy notification (centered)
busyNotification->layout(useableWidth(), getVisibleRect().topLeft() + QPointF(0, getVisibleRect().height()/2.0));
busyNotification->layout(useableWidth(), getVisibleRect().topLeft()
+ QPointF(0, getVisibleRect().height() / 2.0));
}
}
@ -780,15 +740,15 @@ QRectF ChatLog::calculateSceneRect() const
if (typingNotification.get() != nullptr)
bottom += typingNotification->sceneBoundingRect().height() + lineSpacing;
return QRectF(-margins.left(), -margins.top(), useableWidth(), bottom + margins.bottom() + margins.top());
return QRectF(-margins.left(), -margins.top(), useableWidth(),
bottom + margins.bottom() + margins.top());
}
void ChatLog::onSelectionTimerTimeout()
{
const int scrollSpeed = 10;
switch(selectionScrollDir)
{
switch (selectionScrollDir) {
case Up:
verticalScrollBar()->setValue(verticalScrollBar()->value() - scrollSpeed);
break;
@ -810,8 +770,7 @@ void ChatLog::onWorkerTimeout()
workerLastIndex += stepSize;
// done?
if (workerLastIndex >= lines.size())
{
if (workerLastIndex >= lines.size()) {
workerTimer->stop();
// switch back to the scene containing the chat messages
@ -848,8 +807,7 @@ void ChatLog::focusInEvent(QFocusEvent* ev)
{
QGraphicsView::focusInEvent(ev);
if (selectionMode != None)
{
if (selectionMode != None) {
selGraphItem->setBrush(QBrush(selectionRectColor));
for (int i = selFirstRow; i <= selLastRow; ++i)
@ -861,8 +819,7 @@ void ChatLog::focusOutEvent(QFocusEvent* ev)
{
QGraphicsView::focusOutEvent(ev);
if (selectionMode != None)
{
if (selectionMode != None) {
selGraphItem->setBrush(QBrush(selectionRectColor.lighter(120)));
for (int i = selFirstRow; i <= selLastRow; ++i)
@ -879,8 +836,7 @@ void ChatLog::retranslateUi()
bool ChatLog::isActiveFileTransfer(ChatLine::Ptr l)
{
int count = l->getColumnCount();
for (int i = 0; i < count; ++i)
{
for (int i = 0; i < count; ++i) {
ChatLineContent* content = l->getContent(i);
ChatLineContentProxy* proxy = qobject_cast<ChatLineContentProxy*>(content);
if (!proxy)

View File

@ -20,8 +20,8 @@
#ifndef CHATLOG_H
#define CHATLOG_H
#include <QGraphicsView>
#include <QDateTime>
#include <QGraphicsView>
#include <QMargins>
#include "chatline.h"
@ -113,13 +113,15 @@ private:
bool isActiveFileTransfer(ChatLine::Ptr l);
private:
enum SelectionMode {
enum SelectionMode
{
None,
Precise,
Multi,
};
enum AutoScrollDirection {
enum AutoScrollDirection
{
NoDirection,
Up,
Down,

View File

@ -20,12 +20,12 @@
#include "chatmessage.h"
#include "chatlinecontentproxy.h"
#include "textformatter.h"
#include "content/text.h"
#include "content/timestamp.h"
#include "content/spinner.h"
#include "content/filetransferwidget.h"
#include "content/image.h"
#include "content/notificationicon.h"
#include "content/spinner.h"
#include "content/text.h"
#include "content/timestamp.h"
#include <QDebug>
@ -37,17 +37,18 @@
ChatMessage::ChatMessage()
{
}
ChatMessage::Ptr ChatMessage::createChatMessage(const QString &sender, const QString &rawMessage, MessageType type, bool isMe, const QDateTime &date)
ChatMessage::Ptr ChatMessage::createChatMessage(const QString& sender, const QString& rawMessage,
MessageType type, bool isMe, const QDateTime& date)
{
ChatMessage::Ptr msg = ChatMessage::Ptr(new ChatMessage);
QString text = rawMessage.toHtmlEscaped();
QString senderText = sender;
const QColor actionColor = QColor("#1818FF"); // has to match the color in innerStyle.css (div.action)
const QColor actionColor =
QColor("#1818FF"); // has to match the color in innerStyle.css (div.action)
// smileys
if (Settings::getInstance().getUseEmoticons())
@ -58,15 +59,13 @@ ChatMessage::Ptr ChatMessage::createChatMessage(const QString &sender, const QSt
// text styling
Settings::StyleType styleType = Settings::getInstance().getStylePreference();
if (styleType != Settings::StyleType::NONE)
{
if (styleType != Settings::StyleType::NONE) {
TextFormatter tf = TextFormatter(text);
text = tf.applyStyling(styleType == Settings::StyleType::WITH_CHARS);
}
switch(type)
{
switch (type) {
case NORMAL:
text = wrapDiv(text, "msg");
break;
@ -86,9 +85,15 @@ ChatMessage::Ptr ChatMessage::createChatMessage(const QString &sender, const QSt
if (isMe)
authorFont.setBold(true);
msg->addColumn(new Text(senderText, authorFont, true, sender, type == ACTION ? actionColor : Qt::black), ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new Text(text, baseFont, false, ((type == ACTION) && isMe) ? QString("%1 %2").arg(sender, rawMessage) : rawMessage), ColumnFormat(1.0, ColumnFormat::VariableSize));
msg->addColumn(new Spinner(":/ui/chatArea/spinner.svg", QSize(16, 16), 360.0/1.6), ColumnFormat(TIME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new Text(senderText, authorFont, true, sender,
type == ACTION ? actionColor : Qt::black),
ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new Text(text, baseFont, false, ((type == ACTION) && isMe)
? QString("%1 %2").arg(sender, rawMessage)
: rawMessage),
ColumnFormat(1.0, ColumnFormat::VariableSize));
msg->addColumn(new Spinner(":/ui/chatArea/spinner.svg", QSize(16, 16), 360.0 / 1.6),
ColumnFormat(TIME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
if (!date.isNull())
msg->markAsSent(date);
@ -96,29 +101,39 @@ ChatMessage::Ptr ChatMessage::createChatMessage(const QString &sender, const QSt
return msg;
}
ChatMessage::Ptr ChatMessage::createChatInfoMessage(const QString &rawMessage, SystemMessageType type, const QDateTime &date)
ChatMessage::Ptr ChatMessage::createChatInfoMessage(const QString& rawMessage,
SystemMessageType type, const QDateTime& date)
{
ChatMessage::Ptr msg = ChatMessage::Ptr(new ChatMessage);
QString text = rawMessage.toHtmlEscaped();
QString img;
switch(type)
{
case INFO: img = ":/ui/chatArea/info.svg"; break;
case ERROR: img = ":/ui/chatArea/error.svg"; break;
case TYPING: img = ":/ui/chatArea/typing.svg"; break;
switch (type) {
case INFO:
img = ":/ui/chatArea/info.svg";
break;
case ERROR:
img = ":/ui/chatArea/error.svg";
break;
case TYPING:
img = ":/ui/chatArea/typing.svg";
break;
}
QFont baseFont = Settings::getInstance().getChatMessageFont();
msg->addColumn(new Image(QSize(18, 18), img), ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new Text("<b>" + text + "</b>", baseFont, false, ""), ColumnFormat(1.0, ColumnFormat::VariableSize, ColumnFormat::Left));
msg->addColumn(new Timestamp(date, Settings::getInstance().getTimestampFormat(), baseFont), ColumnFormat(TIME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new Image(QSize(18, 18), img),
ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new Text("<b>" + text + "</b>", baseFont, false, ""),
ColumnFormat(1.0, ColumnFormat::VariableSize, ColumnFormat::Left));
msg->addColumn(new Timestamp(date, Settings::getInstance().getTimestampFormat(), baseFont),
ColumnFormat(TIME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
return msg;
}
ChatMessage::Ptr ChatMessage::createFileTransferMessage(const QString& sender, ToxFile file, bool isMe, const QDateTime& date)
ChatMessage::Ptr ChatMessage::createFileTransferMessage(const QString& sender, ToxFile file,
bool isMe, const QDateTime& date)
{
ChatMessage::Ptr msg = ChatMessage::Ptr(new ChatMessage);
@ -127,9 +142,12 @@ ChatMessage::Ptr ChatMessage::createFileTransferMessage(const QString& sender, T
if (isMe)
authorFont.setBold(true);
msg->addColumn(new Text(sender, authorFont, true), ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new ChatLineContentProxy(new FileTransferWidget(0, file), 320, 0.6f), ColumnFormat(1.0, ColumnFormat::VariableSize));
msg->addColumn(new Timestamp(date, Settings::getInstance().getTimestampFormat(), baseFont), ColumnFormat(TIME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new Text(sender, authorFont, true),
ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new ChatLineContentProxy(new FileTransferWidget(0, file), 320, 0.6f),
ColumnFormat(1.0, ColumnFormat::VariableSize));
msg->addColumn(new Timestamp(date, Settings::getInstance().getTimestampFormat(), baseFont),
ColumnFormat(TIME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
return msg;
}
@ -140,14 +158,17 @@ ChatMessage::Ptr ChatMessage::createTypingNotification()
QFont baseFont = Settings::getInstance().getChatMessageFont();
// Note: "[user]..." is just a placeholder. The actual text is set in ChatForm::setFriendTyping()
// Note: "[user]..." is just a placeholder. The actual text is set in
// ChatForm::setFriendTyping()
//
// FIXME: Due to circumstances, placeholder is being used in a case where
// user received typing notifications constantly since contact came online.
// This causes "[user]..." to be displayed in place of user nick, as long
// as user will keep typing. Issue #1280
msg->addColumn(new NotificationIcon(QSize(18, 18)), ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new Text("[user]...", baseFont, false, ""), ColumnFormat(1.0, ColumnFormat::VariableSize, ColumnFormat::Left));
msg->addColumn(new NotificationIcon(QSize(18, 18)),
ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
msg->addColumn(new Text("[user]...", baseFont, false, ""),
ColumnFormat(1.0, ColumnFormat::VariableSize, ColumnFormat::Left));
return msg;
}
@ -159,7 +180,8 @@ ChatMessage::Ptr ChatMessage::createBusyNotification()
baseFont.setPixelSize(baseFont.pixelSize() + 2);
baseFont.setBold(true);
msg->addColumn(new Text(QObject::tr("Resizing"), baseFont, false, ""), ColumnFormat(1.0, ColumnFormat::VariableSize, ColumnFormat::Center));
msg->addColumn(new Text(QObject::tr("Resizing"), baseFont, false, ""),
ColumnFormat(1.0, ColumnFormat::VariableSize, ColumnFormat::Center));
return msg;
}
@ -210,7 +232,8 @@ QString ChatMessage::detectAnchors(const QString &str)
QString out = str;
// detect URIs
QRegExp exp("("
QRegExp exp(
"("
"(?:\\b)((www\\.)|(http[s]?|ftp)://)" // (protocol)://(printable - non-special character)
// http://ONEORMOREALHPA-DIGIT
"\\w+\\S+)" // any other character, lets domains and other
@ -223,12 +246,10 @@ QString ChatMessage::detectAnchors(const QString &str)
// also accepts tox:agilob@net as simplified TOX ID
int offset = 0;
while ((offset = exp.indexIn(out, offset)) != -1)
{
while ((offset = exp.indexIn(out, offset)) != -1) {
QString url = exp.cap();
// If there's a trailing " it's a HTML attribute, e.g. a smiley img's title=":tox:"
if (url == "tox:\"")
{
if (url == "tox:\"") {
offset += url.length();
continue;
}
@ -250,25 +271,20 @@ QString ChatMessage::detectQuotes(const QString& str, MessageType type)
// detect text quotes
QStringList messageLines = str.split("\n");
QString quotedText;
for (int i = 0; i < messageLines.size(); ++i)
{
for (int i = 0; i < messageLines.size(); ++i) {
// don't quote first line in action message. This makes co-existence of
// quotes and action messages possible, since only first line can cause
// problems in case where there is quote in it used.
if (QRegExp("^(&gt;|).*").exactMatch(messageLines[i]))
{
if (QRegExp("^(&gt;|).*").exactMatch(messageLines[i])) {
if (i > 0 || type != ACTION)
quotedText += "<span class=quote>" + messageLines[i] + "</span>";
else
quotedText += messageLines[i];
}
else
{
} else {
quotedText += messageLines[i];
}
if (i < messageLines.size() - 1)
{
if (i < messageLines.size() - 1) {
quotedText += '\n';
}
}

View File

@ -47,9 +47,13 @@ public:
ChatMessage();
static ChatMessage::Ptr createChatMessage(const QString& sender, const QString& rawMessage, MessageType type, bool isMe, const QDateTime& date = QDateTime());
static ChatMessage::Ptr createChatInfoMessage(const QString& rawMessage, SystemMessageType type, const QDateTime& date);
static ChatMessage::Ptr createFileTransferMessage(const QString& sender, ToxFile file, bool isMe, const QDateTime& date);
static ChatMessage::Ptr createChatMessage(const QString& sender, const QString& rawMessage,
MessageType type, bool isMe,
const QDateTime& date = QDateTime());
static ChatMessage::Ptr createChatInfoMessage(const QString& rawMessage, SystemMessageType type,
const QDateTime& date);
static ChatMessage::Ptr createFileTransferMessage(const QString& sender, ToxFile file,
bool isMe, const QDateTime& date);
static ChatMessage::Ptr createTypingNotification();
static ChatMessage::Ptr createBusyNotification();

View File

@ -20,23 +20,23 @@
#include "filetransferwidget.h"
#include "ui_filetransferwidget.h"
#include "src/nexus.h"
#include "src/core/core.h"
#include "src/nexus.h"
#include "src/persistence/settings.h"
#include "src/widget/gui.h"
#include "src/widget/style.h"
#include "src/widget/widget.h"
#include "src/persistence/settings.h"
#include <QMouseEvent>
#include <QFileDialog>
#include <QFile>
#include <QBuffer>
#include <QMessageBox>
#include <QDebug>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QMouseEvent>
#include <QPainter>
#include <QVariantAnimation>
#include <QDebug>
#include <math.h>
@ -63,7 +63,8 @@ FileTransferWidget::FileTransferWidget(QWidget* parent, ToxFile file)
backgroundColorAnimation = new QVariantAnimation(this);
backgroundColorAnimation->setDuration(500);
backgroundColorAnimation->setEasingCurve(QEasingCurve::OutCubic);
connect(backgroundColorAnimation, &QVariantAnimation::valueChanged, this, [this](const QVariant& val) {
connect(backgroundColorAnimation, &QVariantAnimation::valueChanged, this,
[this](const QVariant& val) {
backgroundColor = val.value<QColor>();
update();
});
@ -78,27 +79,32 @@ FileTransferWidget::FileTransferWidget(QWidget* parent, ToxFile file)
setBackgroundColor(Style::getColor(Style::LightGrey), false);
connect(Core::getInstance(), &Core::fileTransferInfo, this, &FileTransferWidget::onFileTransferInfo);
connect(Core::getInstance(), &Core::fileTransferAccepted, this, &FileTransferWidget::onFileTransferAccepted);
connect(Core::getInstance(), &Core::fileTransferCancelled, this, &FileTransferWidget::onFileTransferCancelled);
connect(Core::getInstance(), &Core::fileTransferPaused, this, &FileTransferWidget::onFileTransferPaused);
connect(Core::getInstance(), &Core::fileTransferFinished, this, &FileTransferWidget::onFileTransferFinished);
connect(Core::getInstance(), &Core::fileTransferRemotePausedUnpaused, this, &FileTransferWidget::fileTransferRemotePausedUnpaused);
connect(Core::getInstance(), &Core::fileTransferBrokenUnbroken, this, &FileTransferWidget::fileTransferBrokenUnbroken);
connect(Core::getInstance(), &Core::fileTransferInfo, this,
&FileTransferWidget::onFileTransferInfo);
connect(Core::getInstance(), &Core::fileTransferAccepted, this,
&FileTransferWidget::onFileTransferAccepted);
connect(Core::getInstance(), &Core::fileTransferCancelled, this,
&FileTransferWidget::onFileTransferCancelled);
connect(Core::getInstance(), &Core::fileTransferPaused, this,
&FileTransferWidget::onFileTransferPaused);
connect(Core::getInstance(), &Core::fileTransferFinished, this,
&FileTransferWidget::onFileTransferFinished);
connect(Core::getInstance(), &Core::fileTransferRemotePausedUnpaused, this,
&FileTransferWidget::fileTransferRemotePausedUnpaused);
connect(Core::getInstance(), &Core::fileTransferBrokenUnbroken, this,
&FileTransferWidget::fileTransferBrokenUnbroken);
connect(ui->topButton, &QPushButton::clicked, this, &FileTransferWidget::onTopButtonClicked);
connect(ui->bottomButton, &QPushButton::clicked, this, &FileTransferWidget::onBottomButtonClicked);
connect(ui->previewButton, &QPushButton::clicked, this, &FileTransferWidget::onPreviewButtonClicked);
connect(ui->previewButton, &QPushButton::clicked, this,
&FileTransferWidget::onPreviewButtonClicked);
setupButtons();
// preview
if (fileInfo.direction == ToxFile::SENDING)
{
if (fileInfo.direction == ToxFile::SENDING) {
showPreview(fileInfo.filePath);
ui->progressLabel->setText(tr("Waiting to send...", "file transfer widget"));
}
else
{
} else {
ui->progressLabel->setText(tr("Accept to receive this file", "file transfer widget"));
}
@ -118,12 +124,13 @@ void FileTransferWidget::autoAcceptTransfer(const QString &path)
QString suffix = QFileInfo(fileInfo.fileName).completeSuffix();
QString base = QFileInfo(fileInfo.fileName).baseName();
do
{
filepath = QString("%1/%2%3.%4").arg(path, base, number > 0 ? QString(" (%1)").arg(QString::number(number)) : QString(), suffix);
do {
filepath = QString("%1/%2%3.%4")
.arg(path, base,
number > 0 ? QString(" (%1)").arg(QString::number(number)) : QString(),
suffix);
++number;
}
while (QFileInfo(filepath).exists());
} while (QFileInfo(filepath).exists());
// Do not automatically accept the file-transfer if the path is not writable.
// The user can still accept it manually.
@ -144,10 +151,11 @@ void FileTransferWidget::acceptTransfer(const QString &filepath)
return;
// test if writable
if (!Nexus::tryRemoveFile(filepath))
{
if (!Nexus::tryRemoveFile(filepath)) {
GUI::showWarning(tr("Location not writable", "Title of permissions popup"),
tr("You do not have permission to write that location. Choose another, or cancel the save dialog.", "text of permissions popup"));
tr("You do not have permission to write that location. Choose another, or "
"cancel the save dialog.",
"text of permissions popup"));
return;
}
@ -157,8 +165,7 @@ void FileTransferWidget::acceptTransfer(const QString &filepath)
void FileTransferWidget::setBackgroundColor(const QColor& c, bool whiteFont)
{
if (c != backgroundColor)
{
if (c != backgroundColor) {
backgroundColorAnimation->setStartValue(backgroundColor);
backgroundColorAnimation->setEndValue(c);
backgroundColorAnimation->start();
@ -174,8 +181,7 @@ void FileTransferWidget::setBackgroundColor(const QColor &c, bool whiteFont)
void FileTransferWidget::setButtonColor(const QColor& c)
{
if (c != buttonColor)
{
if (c != buttonColor) {
buttonColorAnimation->setStartValue(buttonColor);
buttonColorAnimation->setEndValue(c);
buttonColorAnimation->start();
@ -184,8 +190,8 @@ void FileTransferWidget::setButtonColor(const QColor &c)
bool FileTransferWidget::drawButtonAreaNeeded() const
{
return (ui->bottomButton->isVisible() || ui->topButton->isVisible()) &&
!(ui->topButton->isVisible() && ui->topButton->objectName() == "ok");
return (ui->bottomButton->isVisible() || ui->topButton->isVisible())
&& !(ui->topButton->isVisible() && ui->topButton->objectName() == "ok");
}
void FileTransferWidget::paintEvent(QPaintEvent*)
@ -207,16 +213,17 @@ void FileTransferWidget::paintEvent(QPaintEvent *)
painter.setBrush(QBrush(backgroundColor));
painter.drawRoundRect(geometry(), r * ratio, r);
if (drawButtonAreaNeeded())
{
if (drawButtonAreaNeeded()) {
// draw button background (top)
painter.setBrush(QBrush(buttonColor));
painter.setClipRect(QRect(width()-buttonFieldWidth+lineWidth,0,buttonFieldWidth,height()/2-ceil(lineWidth/2.0)));
painter.setClipRect(QRect(width() - buttonFieldWidth + lineWidth, 0, buttonFieldWidth,
height() / 2 - ceil(lineWidth / 2.0)));
painter.drawRoundRect(geometry(), r * ratio, r);
// draw button background (bottom)
painter.setBrush(QBrush(buttonColor));
painter.setClipRect(QRect(width()-buttonFieldWidth+lineWidth,height()/2+lineWidth/2,buttonFieldWidth,height()/2));
painter.setClipRect(QRect(width() - buttonFieldWidth + lineWidth,
height() / 2 + lineWidth / 2, buttonFieldWidth, height() / 2));
painter.drawRoundRect(geometry(), r * ratio, r);
}
}
@ -231,8 +238,7 @@ void FileTransferWidget::onFileTransferInfo(ToxFile file)
fileInfo = file;
if (fileInfo.status == ToxFile::TRANSMITTING)
{
if (fileInfo.status == ToxFile::TRANSMITTING) {
// update progress
qreal progress = static_cast<qreal>(file.bytesSent) / static_cast<qreal>(file.filesize);
ui->progressBar->setValue(static_cast<int>(progress * 100.0));
@ -241,8 +247,7 @@ void FileTransferWidget::onFileTransferInfo(ToxFile file)
qreal deltaSecs = dt / 1000.0;
// (can't use ::abs or ::max on unsigned types substraction, they'd just overflow)
quint64 deltaBytes = file.bytesSent > lastBytesSent
? file.bytesSent - lastBytesSent
quint64 deltaBytes = file.bytesSent > lastBytesSent ? file.bytesSent - lastBytesSent
: lastBytesSent - file.bytesSent;
qreal bytesPerSec = static_cast<int>(static_cast<qreal>(deltaBytes) / deltaSecs);
@ -257,15 +262,12 @@ void FileTransferWidget::onFileTransferInfo(ToxFile file)
meanBytesPerSec /= static_cast<qreal>(TRANSFER_ROLLING_AVG_COUNT);
// update UI
if (meanBytesPerSec > 0)
{
if (meanBytesPerSec > 0) {
// ETA
QTime toGo = QTime(0, 0).addSecs((file.filesize - file.bytesSent) / meanBytesPerSec);
QString format = toGo.hour() > 0 ? "hh:mm:ss" : "mm:ss";
ui->etaLabel->setText(toGo.toString(format));
}
else
{
} else {
ui->etaLabel->setText("");
}
@ -415,8 +417,7 @@ void FileTransferWidget::hideWidgets()
void FileTransferWidget::setupButtons()
{
switch(fileInfo.status)
{
switch (fileInfo.status) {
case ToxFile::TRANSMITTING:
ui->topButton->setIcon(QIcon(":/ui/fileTransferInstance/pause.svg"));
ui->topButton->setObjectName("pause");
@ -447,14 +448,11 @@ void FileTransferWidget::setupButtons()
ui->bottomButton->setObjectName("cancel");
ui->bottomButton->setToolTip(tr("Cancel transfer"));
if (fileInfo.direction == ToxFile::SENDING)
{
if (fileInfo.direction == ToxFile::SENDING) {
ui->topButton->setIcon(QIcon(":/ui/fileTransferInstance/pause.svg"));
ui->topButton->setObjectName("pause");
ui->topButton->setToolTip(tr("Pause transfer"));
}
else
{
} else {
ui->topButton->setIcon(QIcon(":/ui/fileTransferInstance/yes.svg"));
ui->topButton->setObjectName("accept");
ui->topButton->setToolTip(tr("Accept transfer"));
@ -465,16 +463,14 @@ void FileTransferWidget::setupButtons()
void FileTransferWidget::handleButton(QPushButton* btn)
{
if (fileInfo.direction == ToxFile::SENDING)
{
if (fileInfo.direction == ToxFile::SENDING) {
if (btn->objectName() == "cancel")
Core::getInstance()->cancelFileSend(fileInfo.friendId, fileInfo.fileNum);
else if (btn->objectName() == "pause")
Core::getInstance()->pauseResumeFileSend(fileInfo.friendId, fileInfo.fileNum);
else if (btn->objectName() == "resume")
Core::getInstance()->pauseResumeFileSend(fileInfo.friendId, fileInfo.fileNum);
}
else // receiving or paused
} else // receiving or paused
{
if (btn->objectName() == "cancel")
Core::getInstance()->cancelFileRecv(fileInfo.friendId, fileInfo.fileNum);
@ -482,28 +478,23 @@ void FileTransferWidget::handleButton(QPushButton *btn)
Core::getInstance()->pauseResumeFileRecv(fileInfo.friendId, fileInfo.fileNum);
else if (btn->objectName() == "resume")
Core::getInstance()->pauseResumeFileRecv(fileInfo.friendId, fileInfo.fileNum);
else if (btn->objectName() == "accept")
{
QString path = QFileDialog::getSaveFileName(parentWidget(),
else if (btn->objectName() == "accept") {
QString path =
QFileDialog::getSaveFileName(parentWidget(),
tr("Save a file", "Title of the file saving dialog"),
Settings::getInstance().getGlobalAutoAcceptDir() + "/" + fileInfo.fileName,
0,
0,
QFileDialog::DontUseNativeDialog);
Settings::getInstance().getGlobalAutoAcceptDir() + "/"
+ fileInfo.fileName,
0, 0, QFileDialog::DontUseNativeDialog);
acceptTransfer(path);
}
}
if (btn->objectName() == "ok" || btn->objectName() == "previewButton")
{
if (btn->objectName() == "ok" || btn->objectName() == "previewButton") {
Widget::confirmExecutableOpen(QFileInfo(fileInfo.filePath));
}
else if (btn->objectName() == "dir")
{
} else if (btn->objectName() == "dir") {
QString dirPath = QFileInfo(fileInfo.filePath).dir().path();
QDesktopServices::openUrl(QUrl::fromLocalFile(dirPath));
}
}
void FileTransferWidget::showPreview(const QString& filename)
@ -511,8 +502,7 @@ void FileTransferWidget::showPreview(const QString &filename)
static const QStringList previewExtensions = {"png", "jpeg", "jpg", "gif", "svg",
"PNG", "JPEG", "JPG", "GIF", "SVG"};
if (previewExtensions.contains(QFileInfo(filename).suffix()))
{
if (previewExtensions.contains(QFileInfo(filename).suffix())) {
// Subtract to make border visible
const int size = qMax(ui->previewButton->width(), ui->previewButton->height()) - 4;
@ -524,15 +514,15 @@ void FileTransferWidget::showPreview(const QString &filename)
ui->previewButton->show();
// Show mouseover preview, but make sure it's not larger than 50% of the screen width/height
const QRect desktopSize = QApplication::desktop()->screenGeometry();
const QImage previewImage = image.scaled(0.5 * desktopSize.width(),
0.5 * desktopSize.height(),
const QImage previewImage = image.scaled(0.5 * desktopSize.width(), 0.5 * desktopSize.height(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
QByteArray imageData;
QBuffer buffer(&imageData);
buffer.open(QIODevice::WriteOnly);
previewImage.save(&buffer, "PNG");
buffer.close();
ui->previewButton->setToolTip("<img src=data:image/png;base64," + imageData.toBase64() + "/>");
ui->previewButton->setToolTip("<img src=data:image/png;base64," + imageData.toBase64()
+ "/>");
}
}
@ -556,14 +546,10 @@ QPixmap FileTransferWidget::scaleCropIntoSquare(const QPixmap &source, const int
QPixmap result;
// Make sure smaller-than-icon images (at least one dimension is smaller) will not be upscaled
if (source.width() < targetSize || source.height() < targetSize)
{
if (source.width() < targetSize || source.height() < targetSize) {
result = source;
}
else
{
result = source.scaled(targetSize, targetSize,
Qt::KeepAspectRatioByExpanding,
} else {
result = source.scaled(targetSize, targetSize, Qt::KeepAspectRatioByExpanding,
Qt::SmoothTransformation);
}

View File

@ -20,8 +20,8 @@
#ifndef FILETRANSFERWIDGET_H
#define FILETRANSFERWIDGET_H
#include <QWidget>
#include <QTime>
#include <QWidget>
#include "src/chatlog/chatlinecontent.h"
#include "src/core/corestructs.h"

View File

@ -30,14 +30,14 @@ public:
Image(QSize size, const QString& filename);
virtual QRectF boundingRect() const override;
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
QWidget* widget) override;
virtual void setWidth(qreal width) override;
virtual qreal getAscent() const override;
private:
QSize size;
QPixmap pmap;
};
#endif // IMAGE_H

View File

@ -20,9 +20,9 @@
#include "notificationicon.h"
#include "../pixmapcache.h"
#include <QGraphicsScene>
#include <QPainter>
#include <QTimer>
#include <QGraphicsScene>
NotificationIcon::NotificationIcon(QSize Size)
: size(Size)

View File

@ -34,7 +34,8 @@ public:
explicit NotificationIcon(QSize size);
virtual QRectF boundingRect() const override;
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
QWidget* widget) override;
virtual void setWidth(qreal width) override;
virtual qreal getAscent() const override;
@ -49,7 +50,6 @@ private:
qreal dotWidth = 0.2;
qreal alpha = 0.0;
};
#endif // NOTIFICATIONICON_H

View File

@ -20,11 +20,11 @@
#include "spinner.h"
#include "../pixmapcache.h"
#include <QPainter>
#include <QDebug>
#include <QGraphicsScene>
#include <QPainter>
#include <QTime>
#include <QVariantAnimation>
#include <QDebug>
Spinner::Spinner(const QString& img, QSize Size, qreal speed)
: size(Size)
@ -41,7 +41,8 @@ Spinner::Spinner(const QString &img, QSize Size, qreal speed)
blendAnimation->setDuration(350);
blendAnimation->setEasingCurve(QEasingCurve::InCubic);
blendAnimation->start(QAbstractAnimation::DeleteWhenStopped);
connect(blendAnimation, &QVariantAnimation::valueChanged, this, [this](const QVariant& val) { alpha = val.toDouble(); });
connect(blendAnimation, &QVariantAnimation::valueChanged, this,
[this](const QVariant& val) { alpha = val.toDouble(); });
QObject::connect(&timer, &QTimer::timeout, this, &Spinner::timeout);
}
@ -55,7 +56,8 @@ void Spinner::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, Q
{
painter->setClipRect(boundingRect());
QTransform trans = QTransform().rotate(QTime::currentTime().msecsSinceStartOfDay() / 1000.0 * rotSpeed)
QTransform trans = QTransform()
.rotate(QTime::currentTime().msecsSinceStartOfDay() / 1000.0 * rotSpeed)
.translate(-size.width() / 2.0, -size.height() / 2.0);
painter->setOpacity(alpha);
painter->setTransform(trans, true);

View File

@ -22,9 +22,9 @@
#include "../chatlinecontent.h"
#include <QTimer>
#include <QObject>
#include <QPixmap>
#include <QTimer>
class QVariantAnimation;
@ -35,7 +35,8 @@ public:
Spinner(const QString& img, QSize size, qreal speed);
virtual QRectF boundingRect() const override;
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
QWidget* widget) override;
virtual void setWidth(qreal width) override;
virtual void visibilityChanged(bool visible) override;
virtual qreal getAscent() const override;
@ -50,7 +51,6 @@ private:
QTimer timer;
qreal alpha = 0.0;
QVariantAnimation* blendAnimation;
};
#endif // SPINNER_H

View File

@ -20,20 +20,21 @@
#include "text.h"
#include "../documentcache.h"
#include <QFontMetrics>
#include <QPainter>
#include <QPalette>
#include <QDebug>
#include <QTextBlock>
#include <QAbstractTextDocumentLayout>
#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
#include <QDesktopServices>
#include <QFontMetrics>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QPalette>
#include <QTextBlock>
#include <QTextFragment>
#include "src/widget/style.h"
Text::Text(const QString& txt, const QFont& font, bool enableElide, const QString &rwText, const QColor c)
Text::Text(const QString& txt, const QFont& font, bool enableElide, const QString& rwText,
const QColor c)
: rawText(rwText)
, elide(enableElide)
, defFont(font)
@ -71,8 +72,7 @@ void Text::selectionMouseMove(QPointF scenePos)
return;
int cur = cursorFromPos(scenePos);
if (cur >= 0)
{
if (cur >= 0) {
selectionEnd = cur;
selectedText = extractSanitizedText(getSelectionStart(), getSelectionEnd());
}
@ -83,8 +83,7 @@ void Text::selectionMouseMove(QPointF scenePos)
void Text::selectionStarted(QPointF scenePos)
{
int cur = cursorFromPos(scenePos);
if (cur >= 0)
{
if (cur >= 0) {
selectionEnd = cur;
selectionAnchor = cur;
}
@ -108,8 +107,7 @@ void Text::selectionDoubleClick(QPointF scenePos)
int cur = cursorFromPos(scenePos);
if (cur >= 0)
{
if (cur >= 0) {
QTextCursor cursor(doc);
cursor.setPosition(cur);
cursor.select(QTextCursor::WordUnderCursor);
@ -167,8 +165,7 @@ void Text::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWid
QAbstractTextDocumentLayout::PaintContext ctx;
QAbstractTextDocumentLayout::Selection sel;
if (hasSelection())
{
if (hasSelection()) {
sel.cursor = QTextCursor(doc);
sel.cursor.setPosition(getSelectionStart());
sel.cursor.setPosition(getSelectionEnd(), QTextCursor::KeepAnchor);
@ -250,25 +247,20 @@ QString Text::getLinkAt(QPointF scenePos) const
void Text::regenerate()
{
if (!doc)
{
if (!doc) {
doc = DocumentCache::getInstance().pop();
dirty = true;
}
if (dirty)
{
if (dirty) {
doc->setDefaultFont(defFont);
if (elide)
{
if (elide) {
QFontMetrics metrics = QFontMetrics(defFont);
QString elidedText = metrics.elidedText(text, Qt::ElideRight, qRound(width));
doc->setPlainText(elidedText);
}
else
{
} else {
doc->setDefaultStyleSheet(defStyleSheet);
doc->setHtml(text);
}
@ -318,7 +310,8 @@ QSizeF Text::idealSize()
int Text::cursorFromPos(QPointF scenePos, bool fuzzy) const
{
if (doc)
return doc->documentLayout()->hitTest(mapFromScene(scenePos), fuzzy ? Qt::FuzzyHit : Qt::ExactHit);
return doc->documentLayout()->hitTest(mapFromScene(scenePos),
fuzzy ? Qt::FuzzyHit : Qt::ExactHit);
return -1;
}
@ -346,26 +339,22 @@ QString Text::extractSanitizedText(int from, int to) const
QString txt;
QTextBlock block = doc->firstBlock();
for (QTextBlock::Iterator itr = block.begin(); itr!=block.end(); ++itr)
{
int pos = itr.fragment().position(); //fragment position -> position of the first character in the fragment
for (QTextBlock::Iterator itr = block.begin(); itr != block.end(); ++itr) {
int pos =
itr.fragment()
.position(); // fragment position -> position of the first character in the fragment
if (itr.fragment().charFormat().isImageFormat())
{
if (itr.fragment().charFormat().isImageFormat()) {
QTextImageFormat imgFmt = itr.fragment().charFormat().toImageFormat();
QString key = imgFmt.name(); // img key (eg. key::D for :D)
QString rune = key.mid(4);
if (pos >= from && pos < to)
{
if (pos >= from && pos < to) {
txt += rune;
++pos;
}
}
else
{
for (QChar c : itr.fragment().text())
{
} else {
for (QChar c : itr.fragment().text()) {
if (pos >= from && pos < to)
txt += c;
@ -379,10 +368,8 @@ QString Text::extractSanitizedText(int from, int to) const
QString Text::extractImgTooltip(int pos) const
{
for (QTextBlock::Iterator itr = doc->firstBlock().begin(); itr!=doc->firstBlock().end(); ++itr)
{
if (itr.fragment().contains(pos) && itr.fragment().charFormat().isImageFormat())
{
for (QTextBlock::Iterator itr = doc->firstBlock().begin(); itr != doc->firstBlock().end(); ++itr) {
if (itr.fragment().contains(pos) && itr.fragment().charFormat().isImageFormat()) {
QTextImageFormat imgFmt = itr.fragment().charFormat().toImageFormat();
return imgFmt.toolTip();
}

View File

@ -31,7 +31,8 @@ class Text : public ChatLineContent
Q_OBJECT
public:
Text(const QString& txt = "", const QFont& font = QFont(), bool enableElide = false, const QString& rawText = QString(), const QColor c = Qt::black);
Text(const QString& txt = "", const QFont& font = QFont(), bool enableElide = false,
const QString& rawText = QString(), const QColor c = Qt::black);
virtual ~Text();
void setText(const QString& txt);
@ -90,7 +91,6 @@ private:
QFont defFont;
QString defStyleSheet;
QColor color;
};
#endif // TEXT_H

View File

@ -20,8 +20,8 @@
#ifndef TIMESTAMP_H
#define TIMESTAMP_H
#include <QDateTime>
#include "text.h"
#include <QDateTime>
class Timestamp : public Text
{

View File

@ -22,8 +22,8 @@
#include "src/persistence/smileypack.h"
#include "src/widget/style.h"
#include <QIcon>
#include <QDebug>
#include <QIcon>
#include <QUrl>
CustomTextDocument::CustomTextDocument(QObject* parent)
@ -35,9 +35,9 @@ CustomTextDocument::CustomTextDocument(QObject *parent)
QVariant CustomTextDocument::loadResource(int type, const QUrl& name)
{
if (type == QTextDocument::ImageResource && name.scheme() == "key")
{
QSize size = QSize(Settings::getInstance().getEmojiFontPointSize(),Settings::getInstance().getEmojiFontPointSize());
if (type == QTextDocument::ImageResource && name.scheme() == "key") {
QSize size = QSize(Settings::getInstance().getEmojiFontPointSize(),
Settings::getInstance().getEmojiFontPointSize());
QString fileName = QUrl::fromPercentEncoding(name.toEncoded()).mid(4).toHtmlEscaped();
return SmileyPack::getInstance().getAsIcon(fileName).pixmap(size);

View File

@ -36,8 +36,7 @@ QTextDocument* DocumentCache::pop()
void DocumentCache::push(QTextDocument* doc)
{
if (doc)
{
if (doc) {
doc->clear();
documents.push(doc);
}

View File

@ -23,8 +23,7 @@ QPixmap PixmapCache::get(const QString &filename, QSize size)
{
auto itr = cache.find(filename);
if (itr == cache.end())
{
if (itr == cache.end()) {
QIcon icon;
icon.addFile(filename);
@ -43,4 +42,3 @@ PixmapCache &PixmapCache::getInstance()
static PixmapCache instance;
return instance;
}

View File

@ -20,9 +20,9 @@
#ifndef ICONCACHE_H
#define ICONCACHE_H
#include <QHash>
#include <QIcon>
#include <QPixmap>
#include <QHash>
class PixmapCache
{
@ -31,7 +31,9 @@ public:
static PixmapCache& getInstance();
protected:
PixmapCache() {}
PixmapCache()
{
}
PixmapCache(PixmapCache&) = delete;
PixmapCache& operator=(const PixmapCache&) = delete;

View File

@ -24,7 +24,8 @@
#include <QRegularExpression>
#include <QVector>
enum TextStyle {
enum TextStyle
{
BOLD = 0,
ITALIC,
UNDERLINE,
@ -49,18 +50,15 @@ static const QString MULTILINE_CODE = QStringLiteral("(?<=^|[^`])"
"(?=$|[^`])");
// Items in vector associated with TextStyle values respectively. Do NOT change this order
static const QVector<QString> fontStylePatterns
{
QStringLiteral("<b>%1</b>"),
static const QVector<QString> fontStylePatterns{QStringLiteral("<b>%1</b>"),
QStringLiteral("<i>%1</i>"),
QStringLiteral("<u>%1</u>"),
QStringLiteral("<s>%1</s>"),
QStringLiteral("<font color=#595959><code>%1</code></font>")
};
QStringLiteral(
"<font color=#595959><code>%1</code></font>")};
// Unfortunately, can't use simple QMap because ordered applying of styles is required
static const QVector<QPair<QRegularExpression, QString>> textPatternStyle
{
static const QVector<QPair<QRegularExpression, QString>> textPatternStyle{
{QRegularExpression(COMMON_PATTERN.arg("*", "1")), fontStylePatterns[BOLD]},
{QRegularExpression(COMMON_PATTERN.arg("/", "1")), fontStylePatterns[ITALIC]},
{QRegularExpression(COMMON_PATTERN.arg("_", "1")), fontStylePatterns[UNDERLINE]},
@ -70,8 +68,7 @@ static const QVector<QPair<QRegularExpression, QString>> textPatternStyle
{QRegularExpression(COMMON_PATTERN.arg("/", "2")), fontStylePatterns[ITALIC]},
{QRegularExpression(COMMON_PATTERN.arg("_", "2")), fontStylePatterns[UNDERLINE]},
{QRegularExpression(COMMON_PATTERN.arg("~", "2")), fontStylePatterns[STRIKE]},
{ QRegularExpression(MULTILINE_CODE), fontStylePatterns[CODE] }
};
{QRegularExpression(MULTILINE_CODE), fontStylePatterns[CODE]}};
TextFormatter::TextFormatter(const QString& str)
: sourceString(str)
@ -88,8 +85,7 @@ static int patternSignsCount(const QString& str)
QChar escapeSign = str.at(0);
int result = 0;
int length = str.length();
while (result < length && str[result] == escapeSign)
{
while (result < length && str[result] == escapeSign) {
++result;
}
return result;
@ -108,34 +104,29 @@ static bool isTagIntersection(const QString& str)
int closingTagCount = 0;
QRegularExpressionMatchIterator iter = TAG_PATTERN.globalMatch(str);
while (iter.hasNext())
{
iter.next().captured()[0] == '/'
? ++closingTagCount
: ++openingTagCount;
while (iter.hasNext()) {
iter.next().captured()[0] == '/' ? ++closingTagCount : ++openingTagCount;
}
return openingTagCount != closingTagCount;
}
/**
* @brief Applies styles to the font of text that was passed to the constructor
* @param showFormattingSymbols True, if it is supposed to include formatting symbols into resulting string
* @param showFormattingSymbols True, if it is supposed to include formatting symbols into resulting
* string
* @return Source text with styled font
*/
QString TextFormatter::applyHtmlFontStyling(bool showFormattingSymbols)
{
QString out = sourceString;
for (QPair<QRegularExpression, QString> pair : textPatternStyle)
{
for (QPair<QRegularExpression, QString> pair : textPatternStyle) {
QRegularExpressionMatchIterator matchesIterator = pair.first.globalMatch(out);
int insertedTagSymbolsCount = 0;
while (matchesIterator.hasNext())
{
while (matchesIterator.hasNext()) {
QRegularExpressionMatch match = matchesIterator.next();
if (isTagIntersection(match.captured()))
{
if (isTagIntersection(match.captured())) {
continue;
}
@ -159,7 +150,8 @@ QString TextFormatter::applyHtmlFontStyling(bool showFormattingSymbols)
/**
* @brief Applies all styling for the text
* @param showFormattingSymbols True, if it is supposed to include formatting symbols into resulting string
* @param showFormattingSymbols True, if it is supposed to include formatting symbols into resulting
* string
* @return Styled string
*/
QString TextFormatter::applyStyling(bool showFormattingSymbols)

View File

@ -25,7 +25,6 @@
class TextFormatter
{
private:
QString sourceString;
QString applyHtmlFontStyling(bool showFormattingSymbols);

View File

@ -19,37 +19,37 @@
*/
#include "core.h"
#include "src/nexus.h"
#include "src/core/cstring.h"
#include "src/core/coreav.h"
#include "src/persistence/settings.h"
#include "src/widget/gui.h"
#include "src/persistence/profilelocker.h"
#include "src/net/avatarbroadcaster.h"
#include "src/persistence/profile.h"
#include "corefile.h"
#include "src/core/coreav.h"
#include "src/core/cstring.h"
#include "src/net/avatarbroadcaster.h"
#include "src/nexus.h"
#include "src/persistence/profile.h"
#include "src/persistence/profilelocker.h"
#include "src/persistence/settings.h"
#include "src/video/camerasource.h"
#include "src/widget/gui.h"
#include <tox/tox.h>
#include <tox/toxav.h>
#include <ctime>
#include <cassert>
#include <limits>
#include <ctime>
#include <functional>
#include <limits>
#include <QBuffer>
#include <QCoreApplication>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QList>
#include <QMutexLocker>
#include <QSaveFile>
#include <QStandardPaths>
#include <QThread>
#include <QTimer>
#include <QCoreApplication>
#include <QDateTime>
#include <QList>
#include <QBuffer>
#include <QMutexLocker>
const QString Core::CONFIG_FILE_NAME = "data";
const QString Core::TOX_EXT = ".tox";
@ -57,8 +57,11 @@ QThread* Core::coreThread{nullptr};
#define MAX_GROUP_MESSAGE_LEN 1024
Core::Core(QThread *CoreThread, Profile& profile) :
tox(nullptr), av(nullptr), profile(profile), ready{false}
Core::Core(QThread* CoreThread, Profile& profile)
: tox(nullptr)
, av(nullptr)
, profile(profile)
, ready{false}
{
coreThread = CoreThread;
@ -66,18 +69,15 @@ Core::Core(QThread *CoreThread, Profile& profile) :
toxTimer->setSingleShot(true);
connect(toxTimer, &QTimer::timeout, this, &Core::process);
connect(&Settings::getInstance(), &Settings::dhtServerListChanged, this, &Core::process);
}
void Core::deadifyTox()
{
if (av)
{
if (av) {
delete av;
av = nullptr;
}
if (tox)
{
if (tox) {
tox_kill(tox);
tox = nullptr;
}
@ -85,8 +85,7 @@ void Core::deadifyTox()
Core::~Core()
{
if (coreThread->isRunning())
{
if (coreThread->isRunning()) {
if (QThread::currentThread() == coreThread)
killTimers(false);
else
@ -94,10 +93,8 @@ Core::~Core()
Q_ARG(bool, false));
}
coreThread->exit(0);
if (QThread::currentThread() != coreThread)
{
while (coreThread->isRunning())
{
if (QThread::currentThread() != coreThread) {
while (coreThread->isRunning()) {
qApp->processEvents();
coreThread->wait(500);
}
@ -126,7 +123,8 @@ CoreAV *Core::getAv()
void Core::makeTox(QByteArray savedata)
{
// IPv6 needed for LAN discovery, but can crash some weird routers. On by default, can be disabled in options.
// IPv6 needed for LAN discovery, but can crash some weird routers. On by default, can be
// disabled in options.
bool enableIPv6 = Settings::getInstance().getEnableIPv6();
bool forceTCP = Settings::getInstance().getForceTCP();
Settings::ProxyType proxyType = Settings::getInstance().getProxyType();
@ -150,18 +148,15 @@ void Core::makeTox(QByteArray savedata)
toxOptions.proxy_host = nullptr;
toxOptions.proxy_port = 0;
toxOptions.savedata_type = (!savedata.isNull() ? TOX_SAVEDATA_TYPE_TOX_SAVE : TOX_SAVEDATA_TYPE_NONE);
toxOptions.savedata_type =
(!savedata.isNull() ? TOX_SAVEDATA_TYPE_TOX_SAVE : TOX_SAVEDATA_TYPE_NONE);
toxOptions.savedata_data = (uint8_t*)savedata.data();
toxOptions.savedata_length = savedata.size();
if (proxyType != Settings::ProxyType::ptNone)
{
if (proxyAddr.length() > 255)
{
if (proxyType != Settings::ProxyType::ptNone) {
if (proxyAddr.length() > 255) {
qWarning() << "proxy address" << proxyAddr << "is too long";
}
else if (proxyAddr != "" && proxyPort > 0)
{
} else if (proxyAddr != "" && proxyPort > 0) {
qDebug() << "using proxy" << proxyAddr << ":" << proxyPort;
// protection against changings in TOX_PROXY_TYPE enum
if (proxyType == Settings::ProxyType::ptSOCKS5)
@ -177,21 +172,19 @@ void Core::makeTox(QByteArray savedata)
TOX_ERR_NEW tox_err;
tox = tox_new(&toxOptions, &tox_err);
switch (tox_err)
{
switch (tox_err) {
case TOX_ERR_NEW_OK:
break;
case TOX_ERR_NEW_LOAD_BAD_FORMAT:
qWarning() << "failed to parse Tox save data";
break;
case TOX_ERR_NEW_PORT_ALLOC:
if (enableIPv6)
{
if (enableIPv6) {
toxOptions.ipv6_enabled = false;
tox = tox_new(&toxOptions, &tox_err);
if (tox_err == TOX_ERR_NEW_OK)
{
qWarning() << "Core failed to start with IPv6, falling back to IPv4. LAN discovery may not work properly.";
if (tox_err == TOX_ERR_NEW_OK) {
qWarning() << "Core failed to start with IPv6, falling back to IPv4. LAN discovery "
"may not work properly.";
break;
}
}
@ -228,8 +221,7 @@ void Core::makeTox(QByteArray savedata)
}
av = new CoreAV(tox);
if (av->getToxAv() == nullptr)
{
if (av->getToxAv() == nullptr) {
qCritical() << "Toxav core failed to start";
emit failedToStart();
return;
@ -242,19 +234,15 @@ void Core::makeTox(QByteArray savedata)
void Core::start()
{
bool isNewProfile = profile.isNewProfile();
if (isNewProfile)
{
if (isNewProfile) {
qDebug() << "Creating a new profile";
makeTox(QByteArray());
setStatusMessage(tr("Toxing on qTox"));
setUsername(profile.getName());
}
else
{
} else {
qDebug() << "Loading user profile";
QByteArray savedata = profile.loadToxSave();
if (savedata.isEmpty())
{
if (savedata.isEmpty()) {
emit failedToStart();
return;
}
@ -263,8 +251,7 @@ void Core::start()
qsrand(time(nullptr));
if (!tox)
{
if (!tox) {
ready = true;
GUI::setEnabled(true);
return;
@ -303,25 +290,21 @@ void Core::start()
tox_callback_file_recv_control(tox, CoreFile::onFileControlCallback);
QPixmap pic = profile.loadAvatar();
if (!pic.isNull() && !pic.size().isEmpty())
{
if (!pic.isNull() && !pic.size().isEmpty()) {
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
pic.save(&buffer, "PNG");
buffer.close();
setAvatar(data);
}
else
{
} else {
qDebug() << "Self avatar not found, will broadcast empty avatar to friends";
setAvatar({});
}
ready = true;
if (isNewProfile)
{
if (isNewProfile) {
profile.saveToxSave();
}
@ -346,8 +329,7 @@ void Core::start()
*/
void Core::process()
{
if (!isReady())
{
if (!isReady()) {
av->stop();
return;
}
@ -360,12 +342,9 @@ void Core::process()
fflush(stdout);
#endif
if (checkConnection())
{
if (checkConnection()) {
tolerance = CORE_DISCONNECT_TOLERANCE;
}
else if (!(--tolerance))
{
} else if (!(--tolerance)) {
bootstrapDht();
tolerance = 3 * CORE_DISCONNECT_TOLERANCE;
}
@ -380,16 +359,13 @@ bool Core::checkConnection()
// static int count = 0;
bool toxConnected = tox_self_get_connection_status(tox) != TOX_CONNECTION_NONE;
if (toxConnected && !isConnected)
{
if (toxConnected && !isConnected) {
qDebug() << "Connected to the DHT";
emit connected();
isConnected = true;
// if (count) qDebug() << "disconnect count:" << count;
// count = 0;
}
else if (!toxConnected && isConnected)
{
} else if (!toxConnected && isConnected) {
qDebug() << "Disconnected from the DHT";
emit disconnected();
isConnected = false;
@ -407,19 +383,19 @@ void Core::bootstrapDht()
QList<DhtServer> dhtServerList = s.getDhtServerList();
int listSize = dhtServerList.size();
if (listSize == 0)
{
if (listSize == 0) {
qWarning() << "no bootstrap list?!?";
return;
}
static int j = qrand() % listSize;
int i = 0;
while (i < 2) // i think the more we bootstrap, the more we jitter because the more we overwrite nodes
while (i < 2) // i think the more we bootstrap, the more we jitter because the more we overwrite
// nodes
{
const DhtServer& dhtServer = dhtServerList[j % listSize];
qDebug() << "Connecting to "+QString(dhtServer.address.toLatin1().data())
+':'+QString().setNum(dhtServer.port)+" ("+dhtServer.name+')';
qDebug() << "Connecting to " + QString(dhtServer.address.toLatin1().data()) + ':'
+ QString().setNum(dhtServer.port) + " (" + dhtServer.name + ')';
QByteArray address = dhtServer.address.toLatin1();
// TODO: constucting the pk via ToxId is a workaround
@ -427,13 +403,11 @@ void Core::bootstrapDht()
const uint8_t* pkPtr = reinterpret_cast<const uint8_t*>(pk.getBytes());
if (!tox_bootstrap(tox, address.constData(), dhtServer.port, pkPtr, nullptr))
{
if (!tox_bootstrap(tox, address.constData(), dhtServer.port, pkPtr, nullptr)) {
qDebug() << "Error bootstrapping from " + dhtServer.name;
}
if (!tox_add_tcp_relay(tox, address.constData(), dhtServer.port, pkPtr, nullptr))
{
if (!tox_add_tcp_relay(tox, address.constData(), dhtServer.port, pkPtr, nullptr)) {
qDebug() << "Error adding TCP relay from " + dhtServer.name;
}
@ -442,22 +416,25 @@ void Core::bootstrapDht()
}
}
void Core::onFriendRequest(Tox*/* tox*/, const uint8_t* cFriendPk,
const uint8_t* cMessage, size_t cMessageSize, void* core)
void Core::onFriendRequest(Tox* /* tox*/, const uint8_t* cFriendPk, const uint8_t* cMessage,
size_t cMessageSize, void* core)
{
ToxPk friendPk(cFriendPk);
emit static_cast<Core*>(core)->friendRequestReceived(friendPk, CString::toString(cMessage, cMessageSize));
emit static_cast<Core*>(core)->friendRequestReceived(friendPk,
CString::toString(cMessage, cMessageSize));
}
void Core::onFriendMessage(Tox* /* tox*/, uint32_t friendId, TOX_MESSAGE_TYPE type,
const uint8_t* cMessage, size_t cMessageSize, void* core)
{
bool isAction = (type == TOX_MESSAGE_TYPE_ACTION);
emit static_cast<Core*>(core)->friendMessageReceived(friendId,CString::toString(cMessage, cMessageSize), isAction);
emit static_cast<Core*>(core)->friendMessageReceived(friendId,
CString::toString(cMessage, cMessageSize),
isAction);
}
void Core::onFriendNameChange(Tox*/* tox*/, uint32_t friendId,
const uint8_t* cName, size_t cNameSize, void* core)
void Core::onFriendNameChange(Tox* /* tox*/, uint32_t friendId, const uint8_t* cName,
size_t cNameSize, void* core)
{
emit static_cast<Core*>(core)->friendUsernameChanged(friendId, CString::toString(cName, cNameSize));
}
@ -470,14 +447,14 @@ void Core::onFriendTypingChange(Tox*/* tox*/, uint32_t friendId, bool isTyping,
void Core::onStatusMessageChanged(Tox* /* tox*/, uint32_t friendId, const uint8_t* cMessage,
size_t cMessageSize, void* core)
{
emit static_cast<Core*>(core)->friendStatusMessageChanged(friendId, CString::toString(cMessage, cMessageSize));
emit static_cast<Core*>(core)->friendStatusMessageChanged(friendId,
CString::toString(cMessage, cMessageSize));
}
void Core::onUserStatusChanged(Tox* /* tox*/, uint32_t friendId, TOX_USER_STATUS userstatus, void* core)
{
Status status;
switch (userstatus)
{
switch (userstatus) {
case TOX_USER_STATUS_NONE:
status = Status::Online;
break;
@ -501,26 +478,22 @@ void Core::onConnectionStatusChanged(Tox*/* tox*/, uint32_t friendId, TOX_CONNEC
emit static_cast<Core*>(core)->friendStatusChanged(friendId, friendStatus);
if (friendStatus == Status::Offline)
static_cast<Core*>(core)->checkLastOnline(friendId);
CoreFile::onConnectionStatusChanged(static_cast<Core*>(core), friendId, friendStatus != Status::Offline);
CoreFile::onConnectionStatusChanged(static_cast<Core*>(core), friendId,
friendStatus != Status::Offline);
}
void Core::onGroupInvite(Tox*, uint32_t friendId, TOX_CONFERENCE_TYPE type,
const uint8_t* data, size_t length, void* vCore)
void Core::onGroupInvite(Tox*, uint32_t friendId, TOX_CONFERENCE_TYPE type, const uint8_t* data,
size_t length, void* vCore)
{
Core* core = static_cast<Core*>(vCore);
QByteArray pk((char*)data, length);
if (type == TOX_CONFERENCE_TYPE_TEXT)
{
if (type == TOX_CONFERENCE_TYPE_TEXT) {
qDebug() << QString("Text group invite by %1").arg(friendId);
emit core->groupInviteReceived(friendId, type, pk);
}
else if (type == TOX_CONFERENCE_TYPE_AV)
{
} else if (type == TOX_CONFERENCE_TYPE_AV) {
qDebug() << QString("AV group invite by %1").arg(friendId);
emit core->groupInviteReceived(friendId, type, pk);
}
else
{
} else {
qWarning() << "Group invite with unknown type " << type;
}
}
@ -545,8 +518,8 @@ void Core::onGroupNamelistChange(Tox*, uint32_t groupId, uint32_t peerId,
emit static_cast<Core*>(core)->groupNamelistChanged(groupId, peerId, change);
}
void Core::onGroupTitleChange(Tox*, uint32_t groupId, uint32_t peerId,
const uint8_t* cTitle, size_t length, void* vCore)
void Core::onGroupTitleChange(Tox*, uint32_t groupId, uint32_t peerId, const uint8_t* cTitle,
size_t length, void* vCore)
{
Core* core = static_cast<Core*>(vCore);
QString author = core->getGroupPeerName(groupId, peerId);
@ -563,12 +536,9 @@ void Core::acceptFriendRequest(const ToxPk& friendPk)
{
// TODO: error handling
uint32_t friendId = tox_friend_add_norequest(tox, friendPk.getBytes(), nullptr);
if (friendId == std::numeric_limits<uint32_t>::max())
{
if (friendId == std::numeric_limits<uint32_t>::max()) {
emit failedToAddFriend(friendPk);
}
else
{
} else {
profile.saveToxSave();
emit friendAdded(friendId, friendPk);
emit friendshipChanged(friendId);
@ -579,39 +549,23 @@ void Core::requestFriendship(const ToxId& friendAddress, const QString& message)
{
ToxPk friendPk = friendAddress.getPublicKey();
if (!friendAddress.isValid())
{
emit failedToAddFriend(friendPk,
tr("Invalid Tox ID"));
}
else if (message.isEmpty())
{
emit failedToAddFriend(friendPk,
tr("You need to write a message with your request"));
}
else if (message.size() > TOX_MAX_FRIEND_REQUEST_LENGTH)
{
emit failedToAddFriend(friendPk,
tr("Your message is too long!"));
}
else if (hasFriendWithPublicKey(friendPk))
{
emit failedToAddFriend(friendPk,
tr("Friend is already added"));
}
else
{
if (!friendAddress.isValid()) {
emit failedToAddFriend(friendPk, tr("Invalid Tox ID"));
} else if (message.isEmpty()) {
emit failedToAddFriend(friendPk, tr("You need to write a message with your request"));
} else if (message.size() > TOX_MAX_FRIEND_REQUEST_LENGTH) {
emit failedToAddFriend(friendPk, tr("Your message is too long!"));
} else if (hasFriendWithPublicKey(friendPk)) {
emit failedToAddFriend(friendPk, tr("Friend is already added"));
} else {
CString cMessage(message);
uint32_t friendId = tox_friend_add(tox, friendAddress.getBytes(),
cMessage.data(), cMessage.size(), nullptr);
if (friendId == std::numeric_limits<uint32_t>::max())
{
uint32_t friendId =
tox_friend_add(tox, friendAddress.getBytes(), cMessage.data(), cMessage.size(), nullptr);
if (friendId == std::numeric_limits<uint32_t>::max()) {
qDebug() << "Failed to request friendship";
emit failedToAddFriend(friendPk);
}
else
{
} else {
qDebug() << "Requested friendship of " << friendId;
// Update our friendAddresses
Settings::getInstance().updateFriendAddress(friendAddress.toString());
@ -622,14 +576,10 @@ void Core::requestFriendship(const ToxId& friendAddress, const QString& message)
inviteStr = tr("/me offers friendship, \"%1\"").arg(message);
Profile* profile = Nexus::getProfile();
if (profile->isHistoryEnabled())
{
profile->getHistory()->addNewMessage(friendAddress.toString(),
inviteStr,
if (profile->isHistoryEnabled()) {
profile->getHistory()->addNewMessage(friendAddress.toString(), inviteStr,
getSelfId().getPublicKey().toString(),
QDateTime::currentDateTime(),
true,
QString());
QDateTime::currentDateTime(), true, QString());
}
// TODO: end
@ -644,8 +594,8 @@ int Core::sendMessage(uint32_t friendId, const QString& message)
{
QMutexLocker ml(&messageSendMutex);
CString cMessage(message);
int receipt = tox_friend_send_message(tox, friendId, TOX_MESSAGE_TYPE_NORMAL,
cMessage.data(), cMessage.size(), nullptr);
int receipt = tox_friend_send_message(tox, friendId, TOX_MESSAGE_TYPE_NORMAL, cMessage.data(),
cMessage.size(), nullptr);
emit messageSentResult(friendId, message, receipt);
return receipt;
}
@ -654,8 +604,8 @@ int Core::sendAction(uint32_t friendId, const QString &action)
{
QMutexLocker ml(&messageSendMutex);
CString cMessage(action);
int receipt = tox_friend_send_message(tox, friendId, TOX_MESSAGE_TYPE_ACTION,
cMessage.data(), cMessage.size(), nullptr);
int receipt = tox_friend_send_message(tox, friendId, TOX_MESSAGE_TYPE_ACTION, cMessage.data(),
cMessage.size(), nullptr);
emit messageSentResult(friendId, action, receipt);
return receipt;
}
@ -671,20 +621,17 @@ void Core::sendGroupMessageWithType(int groupId, const QString& message, TOX_MES
{
QList<CString> cMessages = splitMessage(message, MAX_GROUP_MESSAGE_LEN);
for (auto &cMsg :cMessages)
{
for (auto& cMsg : cMessages) {
TOX_ERR_CONFERENCE_SEND_MESSAGE error;
bool success = tox_conference_send_message(tox, groupId, type,
cMsg.data(), cMsg.size(), &error);
bool success =
tox_conference_send_message(tox, groupId, type, cMsg.data(), cMsg.size(), &error);
if (success && error == TOX_ERR_CONFERENCE_SEND_MESSAGE_OK)
{
if (success && error == TOX_ERR_CONFERENCE_SEND_MESSAGE_OK) {
return;
}
qCritical() << "Fail of tox_conference_send_message";
switch (error)
{
switch (error) {
case TOX_ERR_CONFERENCE_SEND_MESSAGE_CONFERENCE_NOT_FOUND:
qCritical() << "Conference not found";
return;
@ -718,18 +665,15 @@ void Core::changeGroupTitle(int groupId, const QString& title)
{
CString cTitle(title);
TOX_ERR_CONFERENCE_TITLE error;
bool success = tox_conference_set_title(tox, groupId, cTitle.data(),
cTitle.size(), &error);
bool success = tox_conference_set_title(tox, groupId, cTitle.data(), cTitle.size(), &error);
if (success && error == TOX_ERR_CONFERENCE_TITLE_OK)
{
if (success && error == TOX_ERR_CONFERENCE_TITLE_OK) {
emit groupTitleChanged(groupId, getUsername(), title);
return;
}
qCritical() << "Fail of tox_conference_set_title";
switch (error)
{
switch (error) {
case TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND:
qCritical() << "Conference not found";
break;
@ -789,8 +733,7 @@ void Core::removeFriend(uint32_t friendId, bool fake)
if (!isReady() || fake)
return;
if (!tox_friend_delete(tox, friendId, nullptr))
{
if (!tox_friend_delete(tox, friendId, nullptr)) {
emit failedToRemoveFriend(friendId);
return;
}
@ -807,15 +750,13 @@ void Core::removeGroup(int groupId, bool fake)
TOX_ERR_CONFERENCE_DELETE error;
bool success = tox_conference_delete(tox, groupId, &error);
if (success && error == TOX_ERR_CONFERENCE_DELETE_OK)
{
if (success && error == TOX_ERR_CONFERENCE_DELETE_OK) {
av->leaveGroupCall(groupId);
return;
}
qCritical() << "Fail of tox_conference_delete";
switch (error)
{
switch (error) {
case TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND:
qCritical() << "Conference not found";
break;
@ -847,8 +788,7 @@ void Core::setUsername(const QString& username)
CString cUsername(username);
if (!tox_self_set_name(tox, cUsername.data(), cUsername.size(), nullptr))
{
if (!tox_self_set_name(tox, cUsername.data(), cUsername.size(), nullptr)) {
emit failedToSetUsername(username);
return;
}
@ -860,15 +800,12 @@ void Core::setUsername(const QString& username)
void Core::setAvatar(const QByteArray& data)
{
if (!data.isEmpty())
{
if (!data.isEmpty()) {
QPixmap pic;
pic.loadFromData(data);
profile.saveAvatar(data, getSelfId().getPublicKey().toString());
emit selfAvatarChanged(pic);
}
else
{
} else {
emit selfAvatarChanged(QPixmap(":/img/contact_dark.svg"));
}
@ -937,8 +874,7 @@ void Core::setStatusMessage(const QString& message)
CString cMessage(message);
if (!tox_self_set_status_message(tox, cMessage.data(), cMessage.size(), nullptr))
{
if (!tox_self_set_status_message(tox, cMessage.data(), cMessage.size(), nullptr)) {
emit failedToSetStatusMessage(message);
return;
}
@ -951,8 +887,7 @@ void Core::setStatusMessage(const QString& message)
void Core::setStatus(Status status)
{
TOX_USER_STATUS userstatus;
switch (status)
{
switch (status) {
case Status::Online:
userstatus = TOX_USER_STATUS_NONE;
break;
@ -1004,47 +939,43 @@ QByteArray Core::getToxSaveData()
void Core::loadFriends()
{
const uint32_t friendCount = tox_self_get_friend_list_size(tox);
if (friendCount > 0)
{
if (friendCount > 0) {
// assuming there are not that many friends to fill up the whole stack
uint32_t* ids = new uint32_t[friendCount];
tox_self_get_friend_list(tox, ids);
uint8_t friendPk[TOX_PUBLIC_KEY_SIZE] = {0x00};
for (int32_t i = 0; i < static_cast<int32_t>(friendCount); ++i)
{
if (tox_friend_get_public_key(tox, ids[i], friendPk, nullptr))
{
for (int32_t i = 0; i < static_cast<int32_t>(friendCount); ++i) {
if (tox_friend_get_public_key(tox, ids[i], friendPk, nullptr)) {
emit friendAdded(ids[i], ToxPk(friendPk));
const size_t nameSize = tox_friend_get_name_size(tox, ids[i], nullptr);
if (nameSize && nameSize != SIZE_MAX)
{
if (nameSize && nameSize != SIZE_MAX) {
uint8_t* name = new uint8_t[nameSize];
if (tox_friend_get_name(tox, ids[i], name, nullptr))
emit friendUsernameChanged(ids[i], CString::toString(name, nameSize));
delete[] name;
}
const size_t statusMessageSize = tox_friend_get_status_message_size(tox, ids[i], nullptr);
if (statusMessageSize != SIZE_MAX)
{
const size_t statusMessageSize =
tox_friend_get_status_message_size(tox, ids[i], nullptr);
if (statusMessageSize != SIZE_MAX) {
uint8_t* statusMessage = new uint8_t[statusMessageSize];
if (tox_friend_get_status_message(tox, ids[i], statusMessage, nullptr))
{
emit friendStatusMessageChanged(ids[i], CString::toString(statusMessage, statusMessageSize));
if (tox_friend_get_status_message(tox, ids[i], statusMessage, nullptr)) {
emit friendStatusMessageChanged(ids[i], CString::toString(statusMessage,
statusMessageSize));
}
delete[] statusMessage;
}
checkLastOnline(ids[i]);
}
}
delete[] ids;
}
}
void Core::checkLastOnline(uint32_t friendId) {
void Core::checkLastOnline(uint32_t friendId)
{
const uint64_t lastOnline = tox_friend_get_last_online(tox, friendId, nullptr);
if (lastOnline != std::numeric_limits<uint64_t>::max())
emit friendLastSeenChanged(friendId, QDateTime::fromTime_t(lastOnline));
@ -1068,8 +999,7 @@ QVector<uint32_t> Core::getFriendList() const
*/
bool Core::parsePeerQueryError(TOX_ERR_CONFERENCE_PEER_QUERY error) const
{
switch (error)
{
switch (error) {
case TOX_ERR_CONFERENCE_PEER_QUERY_OK:
return true;
case TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND:
@ -1113,8 +1043,7 @@ QString Core::getGroupPeerName(int groupId, int peerId) const
return QString{};
bool success = tox_conference_peer_get_name(tox, groupId, peerId, nameArray, &error);
if (!parsePeerQueryError(error) || !success)
{
if (!parsePeerQueryError(error) || !success) {
qWarning() << "getGroupPeerName: Unknown error";
return QString{};
}
@ -1130,8 +1059,7 @@ ToxPk Core::getGroupPeerPk(int groupId, int peerId) const
uint8_t friendPk[TOX_PUBLIC_KEY_SIZE] = {0x00};
TOX_ERR_CONFERENCE_PEER_QUERY error;
bool success = tox_conference_peer_get_public_key(tox, groupId, peerId, friendPk, &error);
if (!parsePeerQueryError(error) || !success)
{
if (!parsePeerQueryError(error) || !success) {
qWarning() << "getGroupPeerToxId: Unknown error";
return ToxPk();
}
@ -1144,45 +1072,38 @@ ToxPk Core::getGroupPeerPk(int groupId, int peerId) const
*/
QList<QString> Core::getGroupPeerNames(int groupId) const
{
if (!tox)
{
if (!tox) {
qWarning() << "Can't get group peer names, tox is null";
return {};
}
uint32_t nPeers = getGroupNumberPeers(groupId);
if (nPeers == std::numeric_limits<uint32_t>::max())
{
if (nPeers == std::numeric_limits<uint32_t>::max()) {
qWarning() << "getGroupPeerNames: Unable to get number of peers";
return {};
}
// TODO: Change to std::vector
std::unique_ptr<uint8_t[][TOX_MAX_NAME_LENGTH]> namesArray{
new uint8_t[nPeers][TOX_MAX_NAME_LENGTH]};
std::unique_ptr<uint8_t[][TOX_MAX_NAME_LENGTH]> namesArray{new uint8_t[nPeers][TOX_MAX_NAME_LENGTH]};
std::unique_ptr<uint16_t[]> lengths{new uint16_t[nPeers]};
TOX_ERR_CONFERENCE_PEER_QUERY error;
uint32_t count = tox_conference_peer_count(tox, groupId, &error);
if (!parsePeerQueryError(error))
{
if (!parsePeerQueryError(error)) {
return {};
}
if (count != nPeers)
{
if (count != nPeers) {
qWarning() << "getGroupPeerNames: Unexpected peer count";
return {};
}
QList<QString> names;
for (uint32_t i = 0; i < nPeers; ++i)
{
for (uint32_t i = 0; i < nPeers; ++i) {
lengths[i] = tox_conference_peer_get_name_size(tox, groupId, i, &error);
bool ok = tox_conference_peer_get_name(tox, groupId, i, namesArray[i], &error);
if (parsePeerQueryError(error) && ok)
{
if (parsePeerQueryError(error) && ok) {
names.push_back(CString::toString(namesArray[i], lengths[i]));
}
}
@ -1197,8 +1118,7 @@ QList<QString> Core::getGroupPeerNames(int groupId) const
*/
bool Core::parseConferenceJoinError(TOX_ERR_CONFERENCE_JOIN error) const
{
switch (error)
{
switch (error) {
case TOX_ERR_CONFERENCE_JOIN_OK:
return true;
case TOX_ERR_CONFERENCE_JOIN_DUPLICATE:
@ -1236,25 +1156,20 @@ bool Core::parseConferenceJoinError(TOX_ERR_CONFERENCE_JOIN error) const
uint32_t Core::joinGroupchat(int32_t friendnumber, uint8_t type,
const uint8_t* friend_group_public_key, uint16_t length) const
{
if (type == TOX_CONFERENCE_TYPE_TEXT)
{
if (type == TOX_CONFERENCE_TYPE_TEXT) {
qDebug() << QString("Trying to join text groupchat invite sent by friend %1").arg(friendnumber);
TOX_ERR_CONFERENCE_JOIN error;
uint32_t groupId = tox_conference_join(tox, friendnumber, friend_group_public_key, length, &error);
uint32_t groupId =
tox_conference_join(tox, friendnumber, friend_group_public_key, length, &error);
if (parseConferenceJoinError(error))
return groupId;
else
return std::numeric_limits<uint32_t>::max();
}
else if (type == TOX_CONFERENCE_TYPE_AV)
{
} else if (type == TOX_CONFERENCE_TYPE_AV) {
qDebug() << QString("Trying to join AV groupchat invite sent by friend %1").arg(friendnumber);
return toxav_join_av_groupchat(tox, friendnumber, friend_group_public_key, length,
CoreAV::groupCallCallback,
const_cast<Core*>(this));
}
else
{
CoreAV::groupCallCallback, const_cast<Core*>(this));
} else {
qWarning() << "joinGroupchat: Unknown groupchat type " << type;
return std::numeric_limits<uint32_t>::max();
}
@ -1268,8 +1183,7 @@ void Core::quitGroupChat(int groupId) const
TOX_ERR_CONFERENCE_DELETE error;
tox_conference_delete(tox, groupId, &error);
switch (error)
{
switch (error) {
case TOX_ERR_CONFERENCE_DELETE_OK:
return;
case TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND:
@ -1285,8 +1199,7 @@ void Core::groupInviteFriend(uint32_t friendId, int groupId)
TOX_ERR_CONFERENCE_INVITE error;
tox_conference_invite(tox, friendId, groupId, &error);
switch (error)
{
switch (error) {
case TOX_ERR_CONFERENCE_INVITE_OK:
break;
case TOX_ERR_CONFERENCE_INVITE_CONFERENCE_NOT_FOUND:
@ -1302,13 +1215,11 @@ void Core::groupInviteFriend(uint32_t friendId, int groupId)
int Core::createGroup(uint8_t type)
{
if (type == TOX_CONFERENCE_TYPE_TEXT)
{
if (type == TOX_CONFERENCE_TYPE_TEXT) {
TOX_ERR_CONFERENCE_NEW error;
uint32_t groupId = tox_conference_new(tox, &error);
switch (error)
{
switch (error) {
case TOX_ERR_CONFERENCE_NEW_OK:
emit emptyGroupCreated(groupId);
return groupId;
@ -1318,15 +1229,11 @@ int Core::createGroup(uint8_t type)
default:
return std::numeric_limits<uint32_t>::max();
}
}
else if (type == TOX_CONFERENCE_TYPE_AV)
{
} else if (type == TOX_CONFERENCE_TYPE_AV) {
uint32_t groupId = toxav_add_av_groupchat(tox, CoreAV::groupCallCallback, this);
emit emptyGroupCreated(groupId);
return groupId;
}
else
{
} else {
qWarning() << "createGroup: Unknown type " << type;
return -1;
}
@ -1347,8 +1254,7 @@ bool Core::isFriendOnline(uint32_t friendId) const
bool Core::hasFriendWithPublicKey(const ToxPk& publicKey) const
{
// Validity check
if (publicKey.isEmpty())
{
if (publicKey.isEmpty()) {
return false;
}
@ -1364,8 +1270,7 @@ bool Core::hasFriendWithPublicKey(const ToxPk &publicKey) const
ToxPk Core::getFriendPublicKey(uint32_t friendNumber) const
{
uint8_t rawid[TOX_PUBLIC_KEY_SIZE];
if (!tox_friend_get_public_key(tox, friendNumber, rawid, nullptr))
{
if (!tox_friend_get_public_key(tox, friendNumber, rawid, nullptr)) {
qWarning() << "getFriendPublicKey: Getting public key failed";
return ToxPk();
}
@ -1379,8 +1284,7 @@ ToxPk Core::getFriendPublicKey(uint32_t friendNumber) const
QString Core::getFriendUsername(uint32_t friendnumber) const
{
size_t namesize = tox_friend_get_name_size(tox, friendnumber, nullptr);
if (namesize == SIZE_MAX)
{
if (namesize == SIZE_MAX) {
qWarning() << "getFriendUsername: Failed to get name size for friend " << friendnumber;
return QString();
}
@ -1396,14 +1300,11 @@ QList<CString> Core::splitMessage(const QString &message, int maxLen)
QList<CString> splittedMsgs;
QByteArray ba_message(message.toUtf8());
while (ba_message.size() > maxLen)
{
while (ba_message.size() > maxLen) {
int splitPos = ba_message.lastIndexOf(' ', maxLen - 1);
if (splitPos <= 0)
{
if (splitPos <= 0) {
splitPos = maxLen;
if (ba_message[splitPos] & 0x80)
{
if (ba_message[splitPos] & 0x80) {
do {
splitPos--;
} while (!(ba_message[splitPos] & 0x40));
@ -1424,8 +1325,7 @@ QString Core::getPeerName(const ToxPk& id) const
{
QString name;
uint32_t friendId = tox_friend_by_public_key(tox, id.getBytes(), nullptr);
if (friendId == std::numeric_limits<uint32_t>::max())
{
if (friendId == std::numeric_limits<uint32_t>::max()) {
qWarning() << "getPeerName: No such peer";
return name;
}
@ -1435,8 +1335,7 @@ QString Core::getPeerName(const ToxPk& id) const
return name;
uint8_t* cname = new uint8_t[nameSize < TOX_MAX_NAME_LENGTH ? TOX_MAX_NAME_LENGTH : nameSize];
if (!tox_friend_get_name(tox, friendId, cname, nullptr))
{
if (!tox_friend_get_name(tox, friendId, cname, nullptr)) {
qWarning() << "getPeerName: Can't get name of friend " + QString().setNum(friendId);
delete[] cname;
return name;
@ -1475,8 +1374,7 @@ void Core::killTimers(bool onlyStop)
assert(QThread::currentThread() == coreThread);
av->stop();
toxTimer->stop();
if (!onlyStop)
{
if (!onlyStop) {
delete toxTimer;
toxTimer = nullptr;
}

View File

@ -21,19 +21,20 @@
#ifndef CORE_HPP
#define CORE_HPP
#include <cstdint>
#include <QObject>
#include <QMutex>
#include <QObject>
#include <cstdint>
#include <tox/tox.h>
#include <tox/toxencryptsave.h>
#include "corestructs.h"
#include "coredefines.h"
#include "corestructs.h"
#include "toxid.h"
class Profile;
template <typename T> class QList;
template <typename T>
class QList;
class QTimer;
class QString;
class CString;
@ -186,35 +187,28 @@ signals:
void fileSendFailed(uint32_t friendId, const QString& fname);
private:
static void onFriendRequest(Tox* tox, const uint8_t* cUserId,
const uint8_t* cMessage, size_t cMessageSize,
void* core);
static void onFriendMessage(Tox* tox, uint32_t friendId,
TOX_MESSAGE_TYPE type, const uint8_t* cMessage,
static void onFriendRequest(Tox* tox, const uint8_t* cUserId, const uint8_t* cMessage,
size_t cMessageSize, void* core);
static void onFriendNameChange(Tox* tox, uint32_t friendId,
const uint8_t* cName, size_t cNameSize,
void* core);
static void onFriendTypingChange(Tox* tox, uint32_t friendId, bool isTyping,
void* core);
static void onStatusMessageChanged(Tox* tox, uint32_t friendId,
const uint8_t* cMessage,
static void onFriendMessage(Tox* tox, uint32_t friendId, TOX_MESSAGE_TYPE type,
const uint8_t* cMessage, size_t cMessageSize, void* core);
static void onFriendNameChange(Tox* tox, uint32_t friendId, const uint8_t* cName,
size_t cNameSize, void* core);
static void onFriendTypingChange(Tox* tox, uint32_t friendId, bool isTyping, void* core);
static void onStatusMessageChanged(Tox* tox, uint32_t friendId, const uint8_t* cMessage,
size_t cMessageSize, void* core);
static void onUserStatusChanged(Tox* tox, uint32_t friendId,
TOX_USER_STATUS userstatus, void* core);
static void onConnectionStatusChanged(Tox* tox, uint32_t friendId,
TOX_CONNECTION status, void* core);
static void onUserStatusChanged(Tox* tox, uint32_t friendId, TOX_USER_STATUS userstatus,
void* core);
static void onConnectionStatusChanged(Tox* tox, uint32_t friendId, TOX_CONNECTION status,
void* core);
static void onGroupInvite(Tox* tox, uint32_t friendId, TOX_CONFERENCE_TYPE type,
const uint8_t* data, size_t length, void* vCore);
static void onGroupMessage(Tox* tox, uint32_t groupId, uint32_t peerId,
TOX_MESSAGE_TYPE type, const uint8_t* cMessage,
size_t length, void* vCore);
static void onGroupMessage(Tox* tox, uint32_t groupId, uint32_t peerId, TOX_MESSAGE_TYPE type,
const uint8_t* cMessage, size_t length, void* vCore);
static void onGroupNamelistChange(Tox* tox, uint32_t groupId, uint32_t peerId,
TOX_CONFERENCE_STATE_CHANGE change, void* core);
static void onGroupTitleChange(Tox* tox, uint32_t groupId, uint32_t peerId,
const uint8_t* cTitle, size_t length, void* vCore);
static void onReadReceiptCallback(Tox* tox, uint32_t friendId,
uint32_t receipt, void* core);
static void onReadReceiptCallback(Tox* tox, uint32_t friendId, uint32_t receipt, void* core);
void sendGroupMessageWithType(int groupId, const QString& message, TOX_MESSAGE_TYPE type);
bool parsePeerQueryError(TOX_ERR_CONFERENCE_PEER_QUERY error) const;
@ -248,4 +242,3 @@ private:
};
#endif // CORE_HPP

View File

@ -24,14 +24,14 @@
#include "src/friend.h"
#include "src/group.h"
#include "src/persistence/settings.h"
#include "src/video/videoframe.h"
#include "src/video/corevideosource.h"
#include <cassert>
#include "src/video/videoframe.h"
#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>
#include <QDebug>
#include <QCoreApplication>
#include <QtConcurrent/QtConcurrentRun>
#include <cassert>
/**
* @fn void CoreAV::avInvite(uint32_t friendId, bool video)
@ -57,16 +57,19 @@
/**
* @var std::atomic_flag CoreAV::threadSwitchLock
* @brief This flag is to be acquired before switching in a blocking way between the UI and CoreAV thread.
* @brief This flag is to be acquired before switching in a blocking way between the UI and CoreAV
* thread.
*
* The CoreAV thread must have priority for the flag, other threads should back off or release it quickly.
* The CoreAV thread must have priority for the flag, other threads should back off or release it
* quickly.
* CoreAV needs to interface with three threads, the toxcore/Core thread that fires non-payload
* toxav callbacks, the toxav/CoreAV thread that fires AV payload callbacks and manages
* most of CoreAV's members, and the UI thread, which calls our [start/answer/cancel]Call functions
* and which we call via signals.
* When the UI calls us, we switch from the UI thread to the CoreAV thread to do the processing,
* when toxcore fires a non-payload av callback, we do the processing in the CoreAV thread and then
* switch to the UI thread to send it a signal. Both switches block both threads, so this would deadlock.
* switch to the UI thread to send it a signal. Both switches block both threads, so this would
* deadlock.
*/
/**
@ -80,8 +83,9 @@ IndexedList<ToxFriendCall> CoreAV::calls;
IndexedList<ToxGroupCall> CoreAV::groupCalls;
CoreAV::CoreAV(Tox* tox)
: coreavThread{new QThread}, iterateTimer{new QTimer{this}},
threadSwitchLock{false}
: coreavThread{new QThread}
, iterateTimer{new QTimer{this}}
, threadSwitchLock{false}
{
coreavThread->setObjectName("qTox CoreAV");
moveToThread(coreavThread.get());
@ -107,8 +111,7 @@ CoreAV::~CoreAV()
killTimerFromThread();
toxav_kill(toxav);
coreavThread->exit(0);
while (coreavThread->isRunning())
{
while (coreavThread->isRunning()) {
qApp->processEvents();
coreavThread->wait(100);
}
@ -148,7 +151,8 @@ void CoreAV::killTimerFromThread()
{
// Timers can only be touched from their own thread
if (QThread::currentThread() != coreavThread.get())
return (void)QMetaObject::invokeMethod(this, "killTimerFromThread", Qt::BlockingQueuedConnection);
return (void)QMetaObject::invokeMethod(this, "killTimerFromThread",
Qt::BlockingQueuedConnection);
iterateTimer.release();
}
@ -195,9 +199,7 @@ bool CoreAV::isCallStarted(const Group* g) const
*/
bool CoreAV::isCallActive(const Friend* f) const
{
return isCallStarted(f)
? !(calls[f->getFriendId()].inactive)
: false;
return isCallStarted(f) ? !(calls[f->getFriendId()].inactive) : false;
}
/**
@ -207,24 +209,18 @@ bool CoreAV::isCallActive(const Friend* f) const
*/
bool CoreAV::isCallActive(const Group* g) const
{
return isCallStarted(g)
? !(groupCalls[g->getGroupId()].inactive)
: false;
return isCallStarted(g) ? !(groupCalls[g->getGroupId()].inactive) : false;
}
bool CoreAV::isCallVideoEnabled(const Friend* f) const
{
return isCallStarted(f)
? calls[f->getFriendId()].videoEnabled
: false;
return isCallStarted(f) ? calls[f->getFriendId()].videoEnabled : false;
}
bool CoreAV::answerCall(uint32_t friendNum)
{
if (QThread::currentThread() != coreavThread.get())
{
if (threadSwitchLock.test_and_set(std::memory_order_acquire))
{
if (QThread::currentThread() != coreavThread.get()) {
if (threadSwitchLock.test_and_set(std::memory_order_acquire)) {
qDebug() << "CoreAV::answerCall: Backed off of thread-switch lock";
return false;
}
@ -240,13 +236,10 @@ bool CoreAV::answerCall(uint32_t friendNum)
qDebug() << QString("answering call %1").arg(friendNum);
assert(calls.contains(friendNum));
TOXAV_ERR_ANSWER err;
if (toxav_answer(toxav, friendNum, AUDIO_DEFAULT_BITRATE, VIDEO_DEFAULT_BITRATE, &err))
{
if (toxav_answer(toxav, friendNum, AUDIO_DEFAULT_BITRATE, VIDEO_DEFAULT_BITRATE, &err)) {
calls[friendNum].inactive = false;
return true;
}
else
{
} else {
qWarning() << "Failed to answer call with error" << err;
toxav_call_control(toxav, friendNum, TOXAV_CALL_CONTROL_CANCEL, nullptr);
calls.remove(friendNum);
@ -256,18 +249,15 @@ bool CoreAV::answerCall(uint32_t friendNum)
bool CoreAV::startCall(uint32_t friendNum, bool video)
{
if (QThread::currentThread() != coreavThread.get())
{
if (threadSwitchLock.test_and_set(std::memory_order_acquire))
{
if (QThread::currentThread() != coreavThread.get()) {
if (threadSwitchLock.test_and_set(std::memory_order_acquire)) {
qDebug() << "CoreAV::startCall: Backed off of thread-switch lock";
return false;
}
bool ret;
QMetaObject::invokeMethod(this, "startCall", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret),
Q_ARG(uint32_t, friendNum),
Q_RETURN_ARG(bool, ret), Q_ARG(uint32_t, friendNum),
Q_ARG(bool, video));
threadSwitchLock.clear(std::memory_order_release);
@ -275,8 +265,7 @@ bool CoreAV::startCall(uint32_t friendNum, bool video)
}
qDebug() << QString("Starting call with %1").arg(friendNum);
if (calls.contains(friendNum))
{
if (calls.contains(friendNum)) {
qWarning() << QString("Can't start call with %1, we're already in this call!").arg(friendNum);
return false;
}
@ -292,27 +281,22 @@ bool CoreAV::startCall(uint32_t friendNum, bool video)
bool CoreAV::cancelCall(uint32_t friendNum)
{
if (QThread::currentThread() != coreavThread.get())
{
if (threadSwitchLock.test_and_set(std::memory_order_acquire))
{
if (QThread::currentThread() != coreavThread.get()) {
if (threadSwitchLock.test_and_set(std::memory_order_acquire)) {
qDebug() << "CoreAV::cancelCall: Backed off of thread-switch lock";
return false;
}
bool ret;
QMetaObject::invokeMethod(this, "cancelCall",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret),
Q_ARG(uint32_t, friendNum));
QMetaObject::invokeMethod(this, "cancelCall", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret), Q_ARG(uint32_t, friendNum));
threadSwitchLock.clear(std::memory_order_release);
return ret;
}
qDebug() << QString("Cancelling call with %1").arg(friendNum);
if (!toxav_call_control(toxav, friendNum, TOXAV_CALL_CONTROL_CANCEL, nullptr))
{
if (!toxav_call_control(toxav, friendNum, TOXAV_CALL_CONTROL_CANCEL, nullptr)) {
qWarning() << QString("Failed to cancel call with %1").arg(friendNum);
return false;
}
@ -326,15 +310,13 @@ void CoreAV::timeoutCall(uint32_t friendNum)
{
// Non-blocking switch to the CoreAV thread, we really don't want to be coming
// blocking-queued from the UI thread while we emit blocking-queued to it
if (QThread::currentThread() != coreavThread.get())
{
if (QThread::currentThread() != coreavThread.get()) {
QMetaObject::invokeMethod(this, "timeoutCall", Qt::QueuedConnection,
Q_ARG(uint32_t, friendNum));
return;
}
if (!cancelCall(friendNum))
{
if (!cancelCall(friendNum)) {
qWarning() << QString("Failed to timeout call with %1").arg(friendNum);
return;
}
@ -350,16 +332,15 @@ void CoreAV::timeoutCall(uint32_t friendNum)
* @param rate Audio sampling rate used in this frame.
* @return False only on error, but not if there's nothing to send.
*/
bool CoreAV::sendCallAudio(uint32_t callId, const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate)
bool CoreAV::sendCallAudio(uint32_t callId, const int16_t* pcm, size_t samples, uint8_t chans,
uint32_t rate)
{
if (!calls.contains(callId))
return false;
ToxFriendCall& call = calls[callId];
if (call.muteMic || call.inactive
|| !(call.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A))
{
if (call.muteMic || call.inactive || !(call.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A)) {
return true;
}
@ -367,15 +348,11 @@ bool CoreAV::sendCallAudio(uint32_t callId, const int16_t *pcm, size_t samples,
TOXAV_ERR_SEND_FRAME err;
int retries = 0;
do {
if (!toxav_audio_send_frame(toxav, callId, pcm, samples, chans, rate, &err))
{
if (err == TOXAV_ERR_SEND_FRAME_SYNC)
{
if (!toxav_audio_send_frame(toxav, callId, pcm, samples, chans, rate, &err)) {
if (err == TOXAV_ERR_SEND_FRAME_SYNC) {
++retries;
QThread::usleep(500);
}
else
{
} else {
qDebug() << "toxav_audio_send_frame error: " << err;
}
}
@ -395,12 +372,10 @@ void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr<VideoFrame> vframe)
ToxFriendCall& call = calls[callId];
if (!call.videoEnabled || call.inactive
|| !(call.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V))
if (!call.videoEnabled || call.inactive || !(call.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V))
return;
if (call.nullVideoBitrate)
{
if (call.nullVideoBitrate) {
qDebug() << "Restarting video stream to friend" << callId;
toxav_bit_rate_set(toxav, call.callId, -1, VIDEO_DEFAULT_BITRATE, nullptr);
call.nullVideoBitrate = false;
@ -408,8 +383,7 @@ void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr<VideoFrame> vframe)
ToxYUVFrame frame = vframe->toToxYUVFrame();
if(!frame)
{
if (!frame) {
return;
}
@ -418,16 +392,12 @@ void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr<VideoFrame> vframe)
TOXAV_ERR_SEND_FRAME err;
int retries = 0;
do {
if (!toxav_video_send_frame(toxav, callId, frame.width, frame.height,
frame.y, frame.u, frame.v, &err))
{
if (err == TOXAV_ERR_SEND_FRAME_SYNC)
{
if (!toxav_video_send_frame(toxav, callId, frame.width, frame.height, frame.y, frame.u,
frame.v, &err)) {
if (err == TOXAV_ERR_SEND_FRAME_SYNC) {
++retries;
QThread::usleep(500);
}
else
{
} else {
qDebug() << "toxav_video_send_frame error: " << err;
}
}
@ -442,8 +412,7 @@ void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr<VideoFrame> vframe)
*/
void CoreAV::toggleMuteCallInput(const Friend* f)
{
if (f && calls.contains(f->getFriendId()))
{
if (f && calls.contains(f->getFriendId())) {
ToxCall& call = calls[f->getFriendId()];
call.muteMic = !call.muteMic;
}
@ -455,8 +424,7 @@ void CoreAV::toggleMuteCallInput(const Friend* f)
*/
void CoreAV::toggleMuteCallOutput(const Friend* f)
{
if (f && calls.contains(f->getFriendId()))
{
if (f && calls.contains(f->getFriendId())) {
ToxCall& call = calls[f->getFriendId()];
call.muteVol = !call.muteVol;
}
@ -474,18 +442,15 @@ void CoreAV::toggleMuteCallOutput(const Friend* f)
* @param[in] sample_rate the audio sample rate
* @param[in] core the qTox Core class
*/
void CoreAV::groupCallCallback(void* tox, int group, int peer,
const int16_t* data, unsigned samples,
uint8_t channels, unsigned sample_rate,
void* core)
void CoreAV::groupCallCallback(void* tox, int group, int peer, const int16_t* data,
unsigned samples, uint8_t channels, unsigned sample_rate, void* core)
{
Q_UNUSED(tox);
Core* c = static_cast<Core*>(core);
CoreAV* cav = c->getAv();
if (!cav->groupCalls.contains(group))
{
if (!cav->groupCalls.contains(group)) {
return;
}
@ -500,8 +465,7 @@ void CoreAV::groupCallCallback(void* tox, int group, int peer,
if (!call.peers[peer])
audio.subscribeOutput(call.peers[peer]);
audio.playAudioBuffer(call.peers[peer], data, samples, channels,
sample_rate);
audio.playAudioBuffer(call.peers[peer], data, samples, channels, sample_rate);
}
/**
@ -509,7 +473,8 @@ void CoreAV::groupCallCallback(void* tox, int group, int peer,
* @param group Group Index
* @param peer Peer Index
*/
void CoreAV::invalidateGroupCallPeerSource(int group, int peer) {
void CoreAV::invalidateGroupCallPeerSource(int group, int peer)
{
Audio& audio = Audio::getInstance();
audio.unsubscribeOutput(groupCalls[group].peers[peer]);
groupCalls[group].peers[peer] = 0;
@ -522,9 +487,9 @@ void CoreAV::invalidateGroupCallPeerSource(int group, int peer) {
*/
VideoSource* CoreAV::getVideoSourceFromCall(int friendNum)
{
if (!calls.contains(friendNum))
{
qWarning() << "CoreAV::getVideoSourceFromCall: No such call, did it die before we finished answering?";
if (!calls.contains(friendNum)) {
qWarning() << "CoreAV::getVideoSourceFromCall: No such call, did it die before we finished "
"answering?";
return nullptr;
}
@ -556,7 +521,8 @@ void CoreAV::leaveGroupCall(int groupId)
groupCalls.remove(groupId);
}
bool CoreAV::sendGroupCallAudio(int groupId, const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate)
bool CoreAV::sendGroupCallAudio(int groupId, const int16_t* pcm, size_t samples, uint8_t chans,
uint32_t rate)
{
if (!groupCalls.contains(groupId))
return false;
@ -601,9 +567,7 @@ void CoreAV::muteCallOutput(const Group* g, bool mute)
*/
bool CoreAV::isGroupCallInputMuted(const Group* g) const
{
return g && groupCalls.contains(g->getGroupId())
? groupCalls[g->getGroupId()].muteMic
: false;
return g && groupCalls.contains(g->getGroupId()) ? groupCalls[g->getGroupId()].muteMic : false;
}
/**
@ -613,9 +577,7 @@ bool CoreAV::isGroupCallInputMuted(const Group* g) const
*/
bool CoreAV::isGroupCallOutputMuted(const Group* g) const
{
return g && groupCalls.contains(g->getGroupId())
? groupCalls[g->getGroupId()].muteVol
: false;
return g && groupCalls.contains(g->getGroupId()) ? groupCalls[g->getGroupId()].muteVol : false;
}
/**
@ -628,8 +590,7 @@ bool CoreAV::isGroupAvEnabled(int groupId) const
Tox* tox = Core::getInstance()->tox;
TOX_ERR_CONFERENCE_GET_TYPE error;
TOX_CONFERENCE_TYPE type = tox_conference_get_type(tox, groupId, &error);
switch (error)
{
switch (error) {
case TOX_ERR_CONFERENCE_GET_TYPE_OK:
break;
case TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND:
@ -649,9 +610,7 @@ bool CoreAV::isGroupAvEnabled(int groupId) const
*/
bool CoreAV::isCallInputMuted(const Friend* f) const
{
return f && calls.contains(f->getFriendId())
? calls[f->getFriendId()].muteMic
: false;
return f && calls.contains(f->getFriendId()) ? calls[f->getFriendId()].muteMic : false;
}
/**
@ -661,9 +620,7 @@ bool CoreAV::isCallInputMuted(const Friend* f) const
*/
bool CoreAV::isCallOutputMuted(const Friend* f) const
{
return f && calls.contains(f->getFriendId())
? calls[f->getFriendId()].muteVol
: false;
return f && calls.contains(f->getFriendId()) ? calls[f->getFriendId()].muteVol : false;
}
/**
@ -671,13 +628,11 @@ bool CoreAV::isCallOutputMuted(const Friend* f) const
*/
void CoreAV::invalidateCallSources()
{
for (ToxGroupCall& call : groupCalls)
{
for (ToxGroupCall& call : groupCalls) {
call.peers.clear();
}
for (ToxFriendCall& call : calls)
{
for (ToxFriendCall& call : calls) {
call.alSource = 0;
}
}
@ -690,8 +645,7 @@ void CoreAV::sendNoVideo()
{
// We don't change the audio bitrate, but we signal that we're not sending video anymore
qDebug() << "CoreAV: Signaling end of video sending";
for (ToxFriendCall& call : calls)
{
for (ToxFriendCall& call : calls) {
toxav_bit_rate_set(toxav, call.callId, -1, 0, nullptr);
call.nullVideoBitrate = true;
}
@ -701,11 +655,11 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid
{
CoreAV* self = static_cast<CoreAV*>(vSelf);
// Run this slow callback asynchronously on the AV thread to avoid deadlocks with what our caller (toxcore) holds
// Run this slow callback asynchronously on the AV thread to avoid deadlocks with what our
// caller (toxcore) holds
// Also run the code to switch to the CoreAV thread in yet another thread, in case CoreAV
// has threadSwitchLock and wants a toxcore lock that our call stack is holding...
if (QThread::currentThread() != self->coreavThread.get())
{
if (QThread::currentThread() != self->coreavThread.get()) {
QtConcurrent::run([=]() {
// We assume the original caller doesn't come from the CoreAV thread here
while (self->threadSwitchLock.test_and_set(std::memory_order_acquire))
@ -718,11 +672,11 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid
return;
}
if (self->calls.contains(friendNum))
{
if (self->calls.contains(friendNum)) {
/// Hanging up from a callback is supposed to be UB,
/// but since currently the toxav callbacks are fired from the toxcore thread,
/// we'll always reach this point through a non-blocking queud connection, so not in the callback.
/// we'll always reach this point through a non-blocking queud connection, so not in the
/// callback.
qWarning() << QString("Rejecting call invite from %1, we're already in that call!").arg(friendNum);
toxav_call_control(toxav, friendNum, TOXAV_CALL_CONTROL_CANCEL, nullptr);
return;
@ -746,11 +700,11 @@ void CoreAV::stateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t state, voi
{
CoreAV* self = static_cast<CoreAV*>(vSelf);
// Run this slow callback asynchronously on the AV thread to avoid deadlocks with what our caller (toxcore) holds
// Run this slow callback asynchronously on the AV thread to avoid deadlocks with what our
// caller (toxcore) holds
// Also run the code to switch to the CoreAV thread in yet another thread, in case CoreAV
// has threadSwitchLock and wants a toxcore lock that our call stack is holding...
if (QThread::currentThread() != self->coreavThread.get())
{
if (QThread::currentThread() != self->coreavThread.get()) {
QtConcurrent::run([=]() {
// We assume the original caller doesn't come from the CoreAV thread here
while (self->threadSwitchLock.test_and_set(std::memory_order_acquire))
@ -763,8 +717,7 @@ void CoreAV::stateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t state, voi
return;
}
if (!self->calls.contains(friendNum))
{
if (!self->calls.contains(friendNum)) {
qWarning() << QString("stateCallback called, but call %1 is already dead").arg(friendNum);
self->threadSwitchLock.clear(std::memory_order_release);
return;
@ -772,40 +725,32 @@ void CoreAV::stateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t state, voi
ToxFriendCall& call = self->calls[friendNum];
if (state & TOXAV_FRIEND_CALL_STATE_ERROR)
{
if (state & TOXAV_FRIEND_CALL_STATE_ERROR) {
qWarning() << "Call with friend" << friendNum << "died of unnatural causes!";
calls.remove(friendNum);
emit self->avEnd(friendNum);
}
else if (state & TOXAV_FRIEND_CALL_STATE_FINISHED)
{
} else if (state & TOXAV_FRIEND_CALL_STATE_FINISHED) {
qDebug() << "Call with friend" << friendNum << "finished quietly";
calls.remove(friendNum);
emit self->avEnd(friendNum);
}
else
{
} else {
// If our state was null, we started the call and were still ringing
if (!call.state && state)
{
if (!call.state && state) {
call.stopTimeout();
call.inactive = false;
emit self->avStart(friendNum, call.videoEnabled);
}
else if ((call.state & TOXAV_FRIEND_CALL_STATE_SENDING_V)
&& !(state & TOXAV_FRIEND_CALL_STATE_SENDING_V))
{
} else if ((call.state & TOXAV_FRIEND_CALL_STATE_SENDING_V)
&& !(state & TOXAV_FRIEND_CALL_STATE_SENDING_V)) {
qDebug() << "Friend" << friendNum << "stopped sending video";
if (call.videoSource)
call.videoSource->stopSource();
}
else if (!(call.state & TOXAV_FRIEND_CALL_STATE_SENDING_V)
&& (state & TOXAV_FRIEND_CALL_STATE_SENDING_V))
{
// Workaround toxav sometimes firing callbacks for "send last frame" -> "stop sending video"
} else if (!(call.state & TOXAV_FRIEND_CALL_STATE_SENDING_V)
&& (state & TOXAV_FRIEND_CALL_STATE_SENDING_V)) {
// Workaround toxav sometimes firing callbacks for "send last frame" -> "stop sending
// video"
// out of orders (even though they were sent in order by the other end).
// We simply stop the videoSource from emitting anything while the other end says it's not sending
// We simply stop the videoSource from emitting anything while the other end says it's
// not sending
if (call.videoSource)
call.videoSource->restartSource();
}
@ -815,23 +760,25 @@ void CoreAV::stateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t state, voi
self->threadSwitchLock.clear(std::memory_order_release);
}
void CoreAV::bitrateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t arate, uint32_t vrate, void* vSelf)
void CoreAV::bitrateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t arate, uint32_t vrate,
void* vSelf)
{
CoreAV* self = static_cast<CoreAV*>(vSelf);
// Run this slow path callback asynchronously on the AV thread to avoid deadlocks
if (QThread::currentThread() != self->coreavThread.get())
{
if (QThread::currentThread() != self->coreavThread.get()) {
return (void)QMetaObject::invokeMethod(self, "bitrateCallback", Qt::QueuedConnection,
Q_ARG(ToxAV*, toxav), Q_ARG(uint32_t, friendNum),
Q_ARG(uint32_t, arate), Q_ARG(uint32_t, vrate), Q_ARG(void*, vSelf));
Q_ARG(uint32_t, arate), Q_ARG(uint32_t, vrate),
Q_ARG(void*, vSelf));
}
qDebug() << "Recommended bitrate with"<<friendNum<<" is now "<<arate<<"/"<<vrate<<", ignoring it";
qDebug() << "Recommended bitrate with" << friendNum << " is now " << arate << "/" << vrate
<< ", ignoring it";
}
void CoreAV::audioFrameCallback(ToxAV *, uint32_t friendNum, const int16_t *pcm,
size_t sampleCount, uint8_t channels, uint32_t samplingRate, void* vSelf)
void CoreAV::audioFrameCallback(ToxAV*, uint32_t friendNum, const int16_t* pcm, size_t sampleCount,
uint8_t channels, uint32_t samplingRate, void* vSelf)
{
CoreAV* self = static_cast<CoreAV*>(vSelf);
if (!self->calls.contains(friendNum))

View File

@ -21,10 +21,10 @@
#ifndef COREAV_H
#define COREAV_H
#include <QObject>
#include <memory>
#include <atomic>
#include "src/core/toxcall.h"
#include <QObject>
#include <atomic>
#include <memory>
#include <tox/toxav.h>
class Friend;
@ -54,9 +54,11 @@ public:
bool isCallActive(const Friend* f) const;
bool isCallActive(const Group* g) const;
bool isCallVideoEnabled(const Friend* f) const;
bool sendCallAudio(uint32_t friendNum, const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate);
bool sendCallAudio(uint32_t friendNum, const int16_t* pcm, size_t samples, uint8_t chans,
uint32_t rate);
void sendCallVideo(uint32_t friendNum, std::shared_ptr<VideoFrame> frame);
bool sendGroupCallAudio(int groupNum, const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate);
bool sendGroupCallAudio(int groupNum, const int16_t* pcm, size_t samples, uint8_t chans,
uint32_t rate);
VideoSource* getVideoSourceFromCall(int callNumber);
void invalidateCallSources();
@ -75,10 +77,8 @@ public:
void toggleMuteCallInput(const Friend* f);
void toggleMuteCallOutput(const Friend* f);
static void groupCallCallback(void* tox, int group, int peer,
const int16_t* data, unsigned samples,
uint8_t channels, unsigned sample_rate,
void* core);
static void groupCallCallback(void* tox, int group, int peer, const int16_t* data, unsigned samples,
uint8_t channels, unsigned sample_rate, void* core);
static void invalidateGroupCallPeerSource(int group, int peer);
public slots:
@ -97,13 +97,15 @@ signals:
private slots:
static void callCallback(ToxAV* toxAV, uint32_t friendNum, bool audio, bool video, void* self);
static void stateCallback(ToxAV*, uint32_t friendNum, uint32_t state, void* self);
static void bitrateCallback(ToxAV *toxAV, uint32_t friendNum, uint32_t arate, uint32_t vrate, void* self);
static void bitrateCallback(ToxAV* toxAV, uint32_t friendNum, uint32_t arate, uint32_t vrate,
void* self);
void killTimerFromThread();
private:
void process();
static void audioFrameCallback(ToxAV *toxAV, uint32_t friendNum, const int16_t *pcm, size_t sampleCount,
uint8_t channels, uint32_t samplingRate, void* self);
static void audioFrameCallback(ToxAV* toxAV, uint32_t friendNum, const int16_t* pcm,
size_t sampleCount, uint8_t channels, uint32_t samplingRate,
void* self);
static void videoFrameCallback(ToxAV* toxAV, uint32_t friendNum, uint16_t w, uint16_t h,
const uint8_t* y, const uint8_t* u, const uint8_t* v,
int32_t ystride, int32_t ustride, int32_t vstride, void* self);

View File

@ -22,12 +22,12 @@
#include "corefile.h"
#include "corestructs.h"
#include "src/core/cstring.h"
#include "src/persistence/settings.h"
#include "src/persistence/profile.h"
#include "src/persistence/settings.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QThread>
#include <QDir>
#include <memory>
/**
@ -55,13 +55,10 @@ unsigned CoreFile::corefileIterationInterval()
comes to CPU usage just keep the CPU usage low when there are no file
transfers, and speed things up when there is an ongoing file transfer.
*/
constexpr unsigned fileInterval = 10,
idleInterval = 1000;
constexpr unsigned fileInterval = 10, idleInterval = 1000;
for (ToxFile& file : fileMap)
{
if (file.status == ToxFile::TRANSMITTING)
{
for (ToxFile& file : fileMap) {
if (file.status == ToxFile::TRANSMITTING) {
return fileInterval;
}
}
@ -72,10 +69,8 @@ void CoreFile::sendAvatarFile(Core* core, uint32_t friendId, const QByteArray& d
{
QMutexLocker mlocker(&fileSendMutex);
if (data.isEmpty())
{
tox_file_send(core->tox, friendId, TOX_FILE_KIND_AVATAR, 0,
nullptr, nullptr, 0, nullptr);
if (data.isEmpty()) {
tox_file_send(core->tox, friendId, TOX_FILE_KIND_AVATAR, 0, nullptr, nullptr, 0, nullptr);
return;
}
@ -88,8 +83,7 @@ void CoreFile::sendAvatarFile(Core* core, uint32_t friendId, const QByteArray& d
uint32_t fileNum = tox_file_send(core->tox, friendId, TOX_FILE_KIND_AVATAR, filesize,
avatarHash, avatarHash, TOX_HASH_LENGTH, &error);
switch (error)
{
switch (error) {
case TOX_ERR_FILE_SEND_OK:
break;
case TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED:
@ -121,15 +115,15 @@ void CoreFile::sendAvatarFile(Core* core, uint32_t friendId, const QByteArray& d
addFile(friendId, fileNum, file);
}
void CoreFile::sendFile(Core* core, uint32_t friendId, QString filename, QString filePath, long long filesize)
void CoreFile::sendFile(Core* core, uint32_t friendId, QString filename, QString filePath,
long long filesize)
{
QMutexLocker mlocker(&fileSendMutex);
QByteArray fileName = filename.toUtf8();
uint32_t fileNum = tox_file_send(core->tox, friendId, TOX_FILE_KIND_DATA, filesize, nullptr,
(uint8_t*)fileName.data(), fileName.size(), nullptr);
if (fileNum == std::numeric_limits<uint32_t>::max())
{
if (fileNum == std::numeric_limits<uint32_t>::max()) {
qWarning() << "sendFile: Can't create the Tox file sender";
emit core->fileSendFailed(friendId, filename);
return;
@ -140,8 +134,7 @@ void CoreFile::sendFile(Core* core, uint32_t friendId, QString filename, QString
file.filesize = filesize;
file.resumeFileId.resize(TOX_FILE_ID_LENGTH);
tox_file_get_file_id(core->tox, friendId, fileNum, (uint8_t*)file.resumeFileId.data(), nullptr);
if (!file.open(false))
{
if (!file.open(false)) {
qWarning() << QString("sendFile: Can't open file, error: %1").arg(file.file->errorString());
}
@ -153,25 +146,19 @@ void CoreFile::sendFile(Core* core, uint32_t friendId, QString filename, QString
void CoreFile::pauseResumeFileSend(Core* core, uint32_t friendId, uint32_t fileId)
{
ToxFile* file = findFile(friendId, fileId);
if (!file)
{
if (!file) {
qWarning("pauseResumeFileSend: No such file in queue");
return;
}
if (file->status == ToxFile::TRANSMITTING)
{
if (file->status == ToxFile::TRANSMITTING) {
file->status = ToxFile::PAUSED;
emit core->fileTransferPaused(*file);
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE, nullptr);
}
else if (file->status == ToxFile::PAUSED)
{
} else if (file->status == ToxFile::PAUSED) {
file->status = ToxFile::TRANSMITTING;
emit core->fileTransferAccepted(*file);
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
}
else
{
} else {
qWarning() << "pauseResumeFileSend: File is stopped";
}
}
@ -179,25 +166,19 @@ void CoreFile::pauseResumeFileSend(Core* core, uint32_t friendId, uint32_t fileI
void CoreFile::pauseResumeFileRecv(Core* core, uint32_t friendId, uint32_t fileId)
{
ToxFile* file = findFile(friendId, fileId);
if (!file)
{
if (!file) {
qWarning("cancelFileRecv: No such file in queue");
return;
}
if (file->status == ToxFile::TRANSMITTING)
{
if (file->status == ToxFile::TRANSMITTING) {
file->status = ToxFile::PAUSED;
emit core->fileTransferPaused(*file);
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE, nullptr);
}
else if (file->status == ToxFile::PAUSED)
{
} else if (file->status == ToxFile::PAUSED) {
file->status = ToxFile::TRANSMITTING;
emit core->fileTransferAccepted(*file);
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
}
else
{
} else {
qWarning() << "pauseResumeFileRecv: File is stopped or broken";
}
}
@ -205,8 +186,7 @@ void CoreFile::pauseResumeFileRecv(Core* core, uint32_t friendId, uint32_t fileI
void CoreFile::cancelFileSend(Core* core, uint32_t friendId, uint32_t fileId)
{
ToxFile* file = findFile(friendId, fileId);
if (!file)
{
if (!file) {
qWarning("cancelFileSend: No such file in queue");
return;
}
@ -220,8 +200,7 @@ void CoreFile::cancelFileSend(Core* core, uint32_t friendId, uint32_t fileId)
void CoreFile::cancelFileRecv(Core* core, uint32_t friendId, uint32_t fileId)
{
ToxFile* file = findFile(friendId, fileId);
if (!file)
{
if (!file) {
qWarning("cancelFileRecv: No such file in queue");
return;
}
@ -234,8 +213,7 @@ void CoreFile::cancelFileRecv(Core* core, uint32_t friendId, uint32_t fileId)
void CoreFile::rejectFileRecvRequest(Core* core, uint32_t friendId, uint32_t fileId)
{
ToxFile* file = findFile(friendId, fileId);
if (!file)
{
if (!file) {
qWarning("rejectFileRecvRequest: No such file in queue");
return;
}
@ -248,14 +226,12 @@ void CoreFile::rejectFileRecvRequest(Core* core, uint32_t friendId, uint32_t fil
void CoreFile::acceptFileRecvRequest(Core* core, uint32_t friendId, uint32_t fileId, QString path)
{
ToxFile* file = findFile(friendId, fileId);
if (!file)
{
if (!file) {
qWarning("acceptFileRecvRequest: No such file in queue");
return;
}
file->setFilePath(path);
if (!file->open(true))
{
if (!file->open(true)) {
qWarning() << "acceptFileRecvRequest: Unable to open file";
return;
}
@ -267,13 +243,11 @@ void CoreFile::acceptFileRecvRequest(Core* core, uint32_t friendId, uint32_t fil
ToxFile* CoreFile::findFile(uint32_t friendId, uint32_t fileId)
{
uint64_t key = getFriendKey(friendId, fileId);
if (fileMap.contains(key))
{
if (fileMap.contains(key)) {
return &fileMap[key];
}
qWarning() << "findFile: File transfer with ID" << friendId << ':'
<< fileId << "doesn't exist";
qWarning() << "findFile: File transfer with ID" << friendId << ':' << fileId << "doesn't exist";
return nullptr;
}
@ -281,10 +255,9 @@ void CoreFile::addFile(uint32_t friendId, uint32_t fileId, const ToxFile& file)
{
uint64_t key = getFriendKey(friendId, fileId);
if (fileMap.contains(key))
{
qWarning() << "addFile: Overwriting existing file transfer with same ID"
<< friendId << ':' << fileId;
if (fileMap.contains(key)) {
qWarning() << "addFile: Overwriting existing file transfer with same ID" << friendId << ':'
<< fileId;
}
fileMap.insert(key, file);
@ -293,8 +266,7 @@ void CoreFile::addFile(uint32_t friendId, uint32_t fileId, const ToxFile& file)
void CoreFile::removeFile(uint32_t friendId, uint32_t fileId)
{
uint64_t key = getFriendKey(friendId, fileId);
if (!fileMap.contains(key))
{
if (!fileMap.contains(key)) {
qWarning() << "removeFile: No such file in queue";
return;
}
@ -302,49 +274,46 @@ void CoreFile::removeFile(uint32_t friendId, uint32_t fileId)
fileMap.remove(key);
}
void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId,
uint32_t kind, uint64_t filesize,
const uint8_t* fname, size_t fnameLen,
void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, uint32_t kind,
uint64_t filesize, const uint8_t* fname, size_t fnameLen,
void* vCore)
{
Core* core = static_cast<Core*>(vCore);
if (kind == TOX_FILE_KIND_AVATAR)
{
if (kind == TOX_FILE_KIND_AVATAR) {
// TODO: port this to ToxPk
QString friendAddr = core->getFriendPublicKey(friendId).toString();
if (!filesize)
{
if (!filesize) {
qDebug() << QString("Received empty avatar request %1:%2").arg(friendId).arg(fileId);
// Avatars of size 0 means explicitely no avatar
emit core->friendAvatarRemoved(friendId);
core->profile.removeAvatar(friendAddr);
return;
}
else
{
static_assert(TOX_HASH_LENGTH <= TOX_FILE_ID_LENGTH, "TOX_HASH_LENGTH > TOX_FILE_ID_LENGTH!");
} else {
static_assert(TOX_HASH_LENGTH <= TOX_FILE_ID_LENGTH,
"TOX_HASH_LENGTH > TOX_FILE_ID_LENGTH!");
uint8_t avatarHash[TOX_FILE_ID_LENGTH];
tox_file_get_file_id(core->tox, friendId, fileId, avatarHash, nullptr);
if (core->profile.getAvatarHash(friendAddr) == QByteArray((char*)avatarHash, TOX_HASH_LENGTH))
{
if (core->profile.getAvatarHash(friendAddr)
== QByteArray((char*)avatarHash, TOX_HASH_LENGTH)) {
// If it's an avatar but we already have it cached, cancel
qDebug() << QString("Received avatar request %1:%2, reject, since we have it in cache.").arg(friendId).arg(fileId);
qDebug() << QString(
"Received avatar request %1:%2, reject, since we have it in cache.")
.arg(friendId)
.arg(fileId);
tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
return;
}
else
{
} else {
// It's an avatar and we don't have it, autoaccept the transfer
qDebug() << QString("Received avatar request %1:%2, accept, since we don't have it in cache.").arg(friendId).arg(fileId);
qDebug() << QString("Received avatar request %1:%2, accept, since we don't have it "
"in cache.")
.arg(friendId)
.arg(fileId);
tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_RESUME, nullptr);
}
}
}
else
{
qDebug() << QString("Received file request %1:%2 kind %3")
.arg(friendId).arg(fileId).arg(kind);
} else {
qDebug() << QString("Received file request %1:%2 kind %3").arg(friendId).arg(fileId).arg(kind);
}
ToxFile file{fileId, friendId, QByteArray((char*)fname, fnameLen), "", ToxFile::RECEIVING};
@ -360,56 +329,45 @@ void CoreFile::onFileControlCallback(Tox*, uint32_t friendId, uint32_t fileId,
TOX_FILE_CONTROL control, void* core)
{
ToxFile* file = findFile(friendId, fileId);
if (!file)
{
if (!file) {
qWarning("onFileControlCallback: No such file in queue");
return;
}
if (control == TOX_FILE_CONTROL_CANCEL)
{
if (control == TOX_FILE_CONTROL_CANCEL) {
if (file->fileKind != TOX_FILE_KIND_AVATAR)
qDebug() << "File tranfer" << friendId << ":" << fileId << "cancelled by friend";
emit static_cast<Core*>(core)->fileTransferCancelled(*file);
removeFile(friendId, fileId);
}
else if (control == TOX_FILE_CONTROL_PAUSE)
{
} else if (control == TOX_FILE_CONTROL_PAUSE) {
qDebug() << "onFileControlCallback: Received pause for file " << friendId << ":" << fileId;
file->status = ToxFile::PAUSED;
emit static_cast<Core*>(core)->fileTransferRemotePausedUnpaused(*file, true);
}
else if (control == TOX_FILE_CONTROL_RESUME)
{
} else if (control == TOX_FILE_CONTROL_RESUME) {
if (file->direction == ToxFile::SENDING && file->fileKind == TOX_FILE_KIND_AVATAR)
qDebug() << "Avatar transfer" << fileId << "to friend" << friendId << "accepted";
else
qDebug() << "onFileControlCallback: Received resume for file " << friendId << ":" << fileId;
file->status = ToxFile::TRANSMITTING;
emit static_cast<Core*>(core)->fileTransferRemotePausedUnpaused(*file, false);
}
else
{
} else {
qWarning() << "Unhandled file control " << control << " for file " << friendId << ':' << fileId;
}
}
void CoreFile::onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
uint64_t pos, size_t length, void* core)
void CoreFile::onFileDataCallback(Tox* tox, uint32_t friendId, uint32_t fileId, uint64_t pos,
size_t length, void* core)
{
ToxFile* file = findFile(friendId, fileId);
if (!file)
{
if (!file) {
qWarning("onFileDataCallback: No such file in queue");
return;
}
// If we reached EOF, ack and cleanup the transfer
if (!length)
{
if (file->fileKind != TOX_FILE_KIND_AVATAR)
{
if (!length) {
if (file->fileKind != TOX_FILE_KIND_AVATAR) {
emit static_cast<Core*>(core)->fileTransferFinished(*file);
emit static_cast<Core*>(core)->fileUploadFinished(file->filePath);
}
@ -420,18 +378,14 @@ void CoreFile::onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
unique_ptr<uint8_t[]> data(new uint8_t[length]);
int64_t nread;
if (file->fileKind == TOX_FILE_KIND_AVATAR)
{
if (file->fileKind == TOX_FILE_KIND_AVATAR) {
QByteArray chunk = file->avatarData.mid(pos, length);
nread = chunk.size();
memcpy(data.get(), chunk.data(), nread);
}
else
{
} else {
file->file->seek(pos);
nread = file->file->read((char*)data.get(), length);
if (nread <= 0)
{
if (nread <= 0) {
qWarning("onFileDataCallback: Failed to read from file");
emit static_cast<Core*>(core)->fileTransferCancelled(*file);
tox_file_send_chunk(tox, friendId, fileId, pos, nullptr, 0, nullptr);
@ -441,8 +395,7 @@ void CoreFile::onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
file->bytesSent += length;
}
if (!tox_file_send_chunk(tox, friendId, fileId, pos, data.get(), nread, nullptr))
{
if (!tox_file_send_chunk(tox, friendId, fileId, pos, data.get(), nread, nullptr)) {
qWarning("onFileDataCallback: Failed to send data chunk");
return;
}
@ -450,22 +403,18 @@ void CoreFile::onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
emit static_cast<Core*>(core)->fileTransferInfo(*file);
}
void CoreFile::onFileRecvChunkCallback(Tox *tox, uint32_t friendId,
uint32_t fileId, uint64_t position,
const uint8_t* data, size_t length,
void* vCore)
void CoreFile::onFileRecvChunkCallback(Tox* tox, uint32_t friendId, uint32_t fileId, uint64_t position,
const uint8_t* data, size_t length, void* vCore)
{
Core* core = static_cast<Core*>(vCore);
ToxFile* file = findFile(friendId, fileId);
if (!file)
{
if (!file) {
qWarning("onFileRecvChunkCallback: No such file in queue");
tox_file_control(tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
return;
}
if (file->bytesSent != position)
{
if (file->bytesSent != position) {
qWarning("onFileRecvChunkCallback: Received a chunk out-of-order, aborting transfer");
if (file->fileKind != TOX_FILE_KIND_AVATAR)
emit core->fileTransferCancelled(*file);
@ -474,21 +423,17 @@ void CoreFile::onFileRecvChunkCallback(Tox *tox, uint32_t friendId,
return;
}
if (!length)
{
if (file->fileKind == TOX_FILE_KIND_AVATAR)
{
if (!length) {
if (file->fileKind == TOX_FILE_KIND_AVATAR) {
QPixmap pic;
pic.loadFromData(file->avatarData);
if (!pic.isNull())
{
if (!pic.isNull()) {
qDebug() << "Got" << file->avatarData.size() << "bytes of avatar data from" << friendId;
core->profile.saveAvatar(file->avatarData, core->getFriendPublicKey(friendId).toString());
core->profile.saveAvatar(file->avatarData,
core->getFriendPublicKey(friendId).toString());
emit core->friendAvatarChanged(friendId, pic);
}
}
else
{
} else {
emit core->fileTransferFinished(*file);
emit core->fileDownloadFinished(file->filePath);
}
@ -513,10 +458,10 @@ void CoreFile::onConnectionStatusChanged(Core* core, uint32_t friendId, bool onl
// - Start a new file transfer with the same 32byte file ID with toxcore
// - Seek to the correct position again
// - Update the fileNum in our ToxFile
// - Update the users of our signals to check the 32byte tox file ID, not the uint32_t file_num (fileId)
// - Update the users of our signals to check the 32byte tox file ID, not the uint32_t file_num
// (fileId)
ToxFile::FileStatus status = online ? ToxFile::TRANSMITTING : ToxFile::BROKEN;
for (uint64_t key : fileMap.keys())
{
for (uint64_t key : fileMap.keys()) {
if (key >> 32 != friendId)
continue;
fileMap[key].status = status;

View File

@ -21,16 +21,16 @@
#ifndef COREFILE_H
#define COREFILE_H
#include <cstdint>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <tox/tox.h>
#include "corestructs.h"
#include <QString>
#include <QMutex>
#include <QHash>
#include <QMutex>
#include <QString>
struct Tox;
class Core;
@ -44,33 +44,15 @@ private:
// Internal file sending APIs, used by Core. Public API in core.h
private:
static void sendFile(Core *core,
uint32_t friendId,
QString filename,
QString filePath,
static void sendFile(Core* core, uint32_t friendId, QString filename, QString filePath,
long long filesize);
static void sendAvatarFile(Core* core,
uint32_t friendId,
const QByteArray& data);
static void pauseResumeFileSend(Core* core,
uint32_t friendId,
uint32_t fileId);
static void pauseResumeFileRecv(Core* core,
uint32_t friendId,
uint32_t fileId);
static void cancelFileSend(Core* core,
uint32_t friendId,
uint32_t fileId);
static void cancelFileRecv(Core* core,
uint32_t friendId,
uint32_t fileId);
static void rejectFileRecvRequest(Core* core,
uint32_t friendId,
uint32_t fileId);
static void acceptFileRecvRequest(Core* core,
uint32_t friendId,
uint32_t fileId,
QString path);
static void sendAvatarFile(Core* core, uint32_t friendId, const QByteArray& data);
static void pauseResumeFileSend(Core* core, uint32_t friendId, uint32_t fileId);
static void pauseResumeFileRecv(Core* core, uint32_t friendId, uint32_t fileId);
static void cancelFileSend(Core* core, uint32_t friendId, uint32_t fileId);
static void cancelFileRecv(Core* core, uint32_t friendId, uint32_t fileId);
static void rejectFileRecvRequest(Core* core, uint32_t friendId, uint32_t fileId);
static void acceptFileRecvRequest(Core* core, uint32_t friendId, uint32_t fileId, QString path);
static ToxFile* findFile(uint32_t friendId, uint32_t fileId);
static void addFile(uint32_t friendId, uint32_t fileId, const ToxFile& file);
static void removeFile(uint32_t friendId, uint32_t fileId);
@ -81,28 +63,16 @@ private:
}
private:
static void onFileReceiveCallback(Tox*,
uint32_t friendId,
uint32_t fileId,
uint32_t kind,
uint64_t filesize,
const uint8_t* fname,
size_t fnameLen,
static void onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, uint32_t kind,
uint64_t filesize, const uint8_t* fname, size_t fnameLen,
void* vCore);
static void onFileControlCallback(Tox* tox, uint32_t friendId, uint32_t fileId,
TOX_FILE_CONTROL control, void* core);
static void onFileDataCallback(Tox *tox, uint32_t friendId, uint32_t fileId,
uint64_t pos, size_t length, void *core);
static void onFileRecvChunkCallback(Tox *tox,
uint32_t friendId,
uint32_t fileId,
uint64_t position,
const uint8_t* data,
size_t length,
void *vCore);
static void onConnectionStatusChanged(Core* core,
uint32_t friendId,
bool online);
static void onFileDataCallback(Tox* tox, uint32_t friendId, uint32_t fileId, uint64_t pos,
size_t length, void* core);
static void onFileRecvChunkCallback(Tox* tox, uint32_t friendId, uint32_t fileId, uint64_t position,
const uint8_t* data, size_t length, void* vCore);
static void onConnectionStatusChanged(Core* core, uint32_t friendId, bool online);
private:
static QMutex fileSendMutex;

View File

@ -1,8 +1,8 @@
#include "src/core/corestructs.h"
#include "src/core/core.h"
#include <tox/tox.h>
#include <QFile>
#include <QRegularExpression>
#include <tox/tox.h>
#define TOX_HEX_ID_LENGTH 2 * TOX_ADDRESS_SIZE
@ -23,9 +23,8 @@
*/
bool DhtServer::operator==(const DhtServer& other) const
{
return this == &other ||
(port == other.port && address == other.address &&
userId == other.userId && name == other.name);
return this == &other || (port == other.port && address == other.address
&& userId == other.userId && name == other.name);
}
/**
@ -41,16 +40,25 @@ bool DhtServer::operator!=(const DhtServer& other) const
/**
* @brief ToxFile constructor
*/
ToxFile::ToxFile(uint32_t fileNum, uint32_t friendId, QByteArray filename, QString filePath, FileDirection Direction)
: fileKind{TOX_FILE_KIND_DATA}, fileNum(fileNum), friendId(friendId), fileName{filename},
filePath{filePath}, file{new QFile(filePath)}, bytesSent{0}, filesize{0},
status{STOPPED}, direction{Direction}
ToxFile::ToxFile(uint32_t fileNum, uint32_t friendId, QByteArray filename, QString filePath,
FileDirection Direction)
: fileKind{TOX_FILE_KIND_DATA}
, fileNum(fileNum)
, friendId(friendId)
, fileName{filename}
, filePath{filePath}
, file{new QFile(filePath)}
, bytesSent{0}
, filesize{0}
, status{STOPPED}
, direction{Direction}
{
}
bool ToxFile::operator==(const ToxFile& other) const
{
return (fileNum == other.fileNum) && (friendId == other.friendId) && (direction == other.direction);
return (fileNum == other.fileNum) && (friendId == other.friendId)
&& (direction == other.direction);
}
bool ToxFile::operator!=(const ToxFile& other) const

View File

@ -7,7 +7,13 @@
class QFile;
class QTimer;
enum class Status : int {Online = 0, Away, Busy, Offline};
enum class Status : int
{
Online = 0,
Away,
Busy,
Offline
};
struct DhtServer
{
@ -37,8 +43,11 @@ struct ToxFile
};
ToxFile() = default;
ToxFile(uint32_t FileNum, uint32_t FriendId, QByteArray FileName, QString filePath, FileDirection Direction);
~ToxFile(){}
ToxFile(uint32_t FileNum, uint32_t FriendId, QByteArray FileName, QString filePath,
FileDirection Direction);
~ToxFile()
{
}
bool operator==(const ToxFile& other) const;
bool operator!=(const ToxFile& other) const;

View File

@ -21,8 +21,8 @@
#include "cstring.h"
#include <QString>
CString::CString(const QString& string) :
CString(string.toUtf8())
CString::CString(const QString& string)
: CString(string.toUtf8())
{
}

View File

@ -1,8 +1,8 @@
#ifndef INDEXEDLIST_H
#define INDEXEDLIST_H
#include <vector>
#include <algorithm>
#include <vector>
template <typename T>
class IndexedList
@ -19,28 +19,22 @@ public:
template <typename cmp_type>
bool contains(cmp_type i)
{
return std::find_if(begin(), end(), [i](T& t)
{
return static_cast<cmp_type>(t) == i;
}) != end();
return std::find_if(begin(), end(), [i](T& t) { return static_cast<cmp_type>(t) == i; })
!= end();
}
template <typename cmp_type>
void remove(cmp_type i)
{
v.erase(std::remove_if(begin(), end(), [i](T& t)
{
return static_cast<cmp_type>(t) == i;
}), end());
v.erase(std::remove_if(begin(), end(), [i](T& t) { return static_cast<cmp_type>(t) == i; }),
end());
}
template <typename cmp_type>
T& operator[](cmp_type i)
{
iterator it = std::find_if(begin(), end(), [i](T& t)
{
return static_cast<cmp_type>(t) == i;
});
iterator it =
std::find_if(begin(), end(), [i](T& t) { return static_cast<cmp_type>(t) == i; });
if (it == end())
it = insert({});

View File

@ -53,8 +53,7 @@ void RecursiveSignalBlocker::recursiveBlock(QObject* object)
{
mBlockers << new QSignalBlocker(object);
for (QObject* child : object->children())
{
for (QObject* child : object->children()) {
recursiveBlock(child);
}
}

View File

@ -1,5 +1,5 @@
#include "src/audio/audio.h"
#include "src/core/toxcall.h"
#include "src/audio/audio.h"
#include "src/core/coreav.h"
#include "src/persistence/settings.h"
#include "src/video/camerasource.h"
@ -12,7 +12,8 @@
* @brief Could be a friendNum or groupNum, must uniquely identify the call. Do not modify!
*
* @var bool ToxCall::inactive
* @brief True while we're not participating. (stopped group call, ringing but hasn't started yet, ...)
* @brief True while we're not participating. (stopped group call, ringing but hasn't started yet,
* ...)
*
* @var bool ToxFriendCall::videoEnabled
* @brief True if our user asked for a video call, sending and recieving.
@ -30,17 +31,23 @@
using namespace std;
ToxCall::ToxCall(uint32_t CallId)
: callId{CallId}, alSource{0},
inactive{true}, muteMic{false}, muteVol{false}
: callId{CallId}
, alSource{0}
, inactive{true}
, muteMic{false}
, muteVol{false}
{
Audio& audio = Audio::getInstance();
audio.subscribeInput();
audio.subscribeOutput(alSource);
}
ToxCall::ToxCall(ToxCall&& other) noexcept
: audioInConn{other.audioInConn}, callId{other.callId}, alSource{other.alSource},
inactive{other.inactive}, muteMic{other.muteMic}, muteVol{other.muteVol}
ToxCall::ToxCall(ToxCall&& other) noexcept : audioInConn{other.audioInConn},
callId{other.callId},
alSource{other.alSource},
inactive{other.inactive},
muteMic{other.muteMic},
muteVol{other.muteVol}
{
other.audioInConn = QMetaObject::Connection();
other.callId = numeric_limits<decltype(callId)>::max();
@ -81,15 +88,13 @@ ToxCall& ToxCall::operator=(ToxCall&& other) noexcept
void ToxFriendCall::startTimeout()
{
if (!timeoutTimer)
{
if (!timeoutTimer) {
timeoutTimer = new QTimer();
// We might move, so we need copies of members. CoreAV won't move while we're alive
CoreAV* avCopy = av;
auto callIdCopy = callId;
QObject::connect(timeoutTimer, &QTimer::timeout, [avCopy, callIdCopy](){
avCopy->timeoutCall(callIdCopy);
});
QObject::connect(timeoutTimer, &QTimer::timeout,
[avCopy, callIdCopy]() { avCopy->timeoutCall(callIdCopy); });
}
if (!timeoutTimer->isActive())
@ -107,19 +112,21 @@ void ToxFriendCall::stopTimeout()
}
ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av)
: ToxCall(FriendNum),
videoEnabled{VideoEnabled}, nullVideoBitrate{false}, videoSource{nullptr},
state{static_cast<TOXAV_FRIEND_CALL_STATE>(0)},
av{&av}, timeoutTimer{nullptr}
: ToxCall(FriendNum)
, videoEnabled{VideoEnabled}
, nullVideoBitrate{false}
, videoSource{nullptr}
, state{static_cast<TOXAV_FRIEND_CALL_STATE>(0)}
, av{&av}
, timeoutTimer{nullptr}
{
audioInConn = QObject::connect(&Audio::getInstance(), &Audio::frameAvailable,
[&av,FriendNum](const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate)
{
[&av, FriendNum](const int16_t* pcm, size_t samples,
uint8_t chans, uint32_t rate) {
av.sendCallAudio(FriendNum, pcm, samples, chans, rate);
});
if (videoEnabled)
{
if (videoEnabled) {
videoSource = new CoreVideoSource;
CameraSource& source = CameraSource::getInstance();
@ -127,15 +134,20 @@ ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av)
source.open();
source.subscribe();
QObject::connect(&source, &VideoSource::frameAvailable,
[FriendNum,&av](shared_ptr<VideoFrame> frame){av.sendCallVideo(FriendNum,frame);});
[FriendNum, &av](shared_ptr<VideoFrame> frame) {
av.sendCallVideo(FriendNum, frame);
});
}
}
ToxFriendCall::ToxFriendCall(ToxFriendCall&& other) noexcept
: ToxCall(move(other)),
videoEnabled{other.videoEnabled}, nullVideoBitrate{other.nullVideoBitrate},
videoSource{other.videoSource}, state{other.state},
av{other.av}, timeoutTimer{other.timeoutTimer}
videoEnabled{other.videoEnabled},
nullVideoBitrate{other.nullVideoBitrate},
videoSource{other.videoSource},
state{other.state},
av{other.av},
timeoutTimer{other.timeoutTimer}
{
other.videoEnabled = false;
other.videoSource = nullptr;
@ -147,14 +159,14 @@ ToxFriendCall::~ToxFriendCall()
if (timeoutTimer)
delete timeoutTimer;
if (videoEnabled)
{
if (videoEnabled) {
// This destructor could be running in a toxav callback while holding toxav locks.
// If the CameraSource thread calls toxav *_send_frame, we might deadlock the toxav and CameraSource locks,
// so we unsuscribe asynchronously, it's fine if the webcam takes a couple milliseconds more to poweroff.
// If the CameraSource thread calls toxav *_send_frame, we might deadlock the toxav and
// CameraSource locks,
// so we unsuscribe asynchronously, it's fine if the webcam takes a couple milliseconds more
// to poweroff.
QtConcurrent::run([]() { CameraSource::getInstance().unsubscribe(); });
if (videoSource)
{
if (videoSource) {
videoSource->setDeleteOnClose(true);
videoSource = nullptr;
}
@ -180,18 +192,18 @@ ToxFriendCall& ToxFriendCall::operator=(ToxFriendCall&& other) noexcept
ToxGroupCall::ToxGroupCall(int GroupNum, CoreAV& av)
: ToxCall(static_cast<decltype(callId)>(GroupNum))
{
static_assert(numeric_limits<decltype(callId)>::max() >= numeric_limits<decltype(GroupNum)>::max(),
static_assert(
numeric_limits<decltype(callId)>::max() >= numeric_limits<decltype(GroupNum)>::max(),
"The callId must be able to represent any group number, change its type if needed");
audioInConn = QObject::connect(&Audio::getInstance(), &Audio::frameAvailable,
[&av,GroupNum](const int16_t *pcm, size_t samples, uint8_t chans, uint32_t rate)
{
[&av, GroupNum](const int16_t* pcm, size_t samples,
uint8_t chans, uint32_t rate) {
av.sendGroupCallAudio(GroupNum, pcm, samples, chans, rate);
});
}
ToxGroupCall::ToxGroupCall(ToxGroupCall&& other) noexcept
: ToxCall(move(other))
ToxGroupCall::ToxGroupCall(ToxGroupCall&& other) noexcept : ToxCall(move(other))
{
}
@ -199,8 +211,7 @@ ToxGroupCall::~ToxGroupCall()
{
Audio& audio = Audio::getInstance();
for(quint32 v : peers)
{
for (quint32 v : peers) {
audio.unsubscribeOutput(v);
}
}

View File

@ -1,10 +1,10 @@
#ifndef TOXCALL_H
#define TOXCALL_H
#include <cstdint>
#include <QtGlobal>
#include <QMetaObject>
#include <QMap>
#include <QMetaObject>
#include <QtGlobal>
#include <cstdint>
#include "src/core/indexedlist.h"
@ -21,11 +21,15 @@ protected:
ToxCall() = default;
explicit ToxCall(uint32_t CallId);
~ToxCall();
public:
ToxCall(const ToxCall& other) = delete;
ToxCall(ToxCall&& other) noexcept;
inline operator int() {return callId;}
inline operator int()
{
return callId;
}
ToxCall& operator=(const ToxCall& other) = delete;
ToxCall& operator=(ToxCall&& other) noexcept;
@ -80,4 +84,3 @@ struct ToxGroupCall : public ToxCall
};
#endif // TOXCALL_H

View File

@ -20,10 +20,10 @@
#include "toxencrypt.h"
#include <tox/toxencryptsave.h>
#include <memory>
#include <QByteArray>
#include <QDebug>
#include <QString>
#include <memory>
// functions for nice debug output
static QString getKeyDerivationError(TOX_ERR_KEY_DERIVATION error);
@ -51,9 +51,10 @@ ToxEncrypt::~ToxEncrypt()
* @brief Constructs a ToxEncrypt object from a Tox_Pass_Key.
* @param key Derived key to use for encryption and decryption.
*/
ToxEncrypt::ToxEncrypt(Tox_Pass_Key* key) :
passKey{key}
{}
ToxEncrypt::ToxEncrypt(Tox_Pass_Key* key)
: passKey{key}
{
}
/**
* @brief Gets the minimum number of bytes needed for isEncrypted()
@ -72,8 +73,7 @@ int ToxEncrypt::getMinBytes()
*/
bool ToxEncrypt::isEncrypted(const QByteArray& ciphertext)
{
if (ciphertext.length() < TOX_PASS_ENCRYPTION_EXTRA_LENGTH)
{
if (ciphertext.length() < TOX_PASS_ENCRYPTION_EXTRA_LENGTH) {
return false;
}
@ -89,8 +89,7 @@ bool ToxEncrypt::isEncrypted(const QByteArray& ciphertext)
*/
QByteArray ToxEncrypt::encryptPass(const QString& password, const QByteArray& plaintext)
{
if (password.length() == 0)
{
if (password.length() == 0) {
qWarning() << "Empty password supplied, probably not what you intended.";
}
@ -103,8 +102,7 @@ QByteArray ToxEncrypt::encryptPass(const QString& password, const QByteArray& pl
static_cast<size_t>(pass.size()),
reinterpret_cast<uint8_t*>(ciphertext.data()), &error);
if (error != TOX_ERR_ENCRYPTION_OK)
{
if (error != TOX_ERR_ENCRYPTION_OK) {
qCritical() << getEncryptionError(error);
return QByteArray{};
}
@ -121,14 +119,12 @@ QByteArray ToxEncrypt::encryptPass(const QString& password, const QByteArray& pl
*/
QByteArray ToxEncrypt::decryptPass(const QString& password, const QByteArray& ciphertext)
{
if (!isEncrypted(ciphertext))
{
if (!isEncrypted(ciphertext)) {
qWarning() << "The data was not encrypted using this module or it's corrupted.";
return QByteArray{};
}
if (password.length() == 0)
{
if (password.length() == 0) {
qDebug() << "Empty password supplied, probably not what you intended.";
}
@ -138,11 +134,10 @@ QByteArray ToxEncrypt::decryptPass(const QString& password, const QByteArray& ci
tox_pass_decrypt(reinterpret_cast<const uint8_t*>(ciphertext.constData()),
static_cast<size_t>(ciphertext.size()),
reinterpret_cast<const uint8_t*>(pass.constData()),
static_cast<size_t>(pass.size()),
reinterpret_cast<uint8_t*>(plaintext.data()), &error);
static_cast<size_t>(pass.size()), reinterpret_cast<uint8_t*>(plaintext.data()),
&error);
if (error != TOX_ERR_DECRYPTION_OK)
{
if (error != TOX_ERR_DECRYPTION_OK) {
qWarning() << getDecryptionError(error);
return QByteArray{};
}
@ -166,8 +161,7 @@ std::unique_ptr<ToxEncrypt> ToxEncrypt::makeToxEncrypt(const QString& password)
tox_pass_key_derive(passKey, reinterpret_cast<const uint8_t*>(pass.constData()),
static_cast<size_t>(pass.length()), &error);
if (error != TOX_ERR_KEY_DERIVATION_OK)
{
if (error != TOX_ERR_KEY_DERIVATION_OK) {
tox_pass_key_free(passKey);
qCritical() << getKeyDerivationError(error);
return std::unique_ptr<ToxEncrypt>{};
@ -187,8 +181,7 @@ std::unique_ptr<ToxEncrypt> ToxEncrypt::makeToxEncrypt(const QString& password)
*/
std::unique_ptr<ToxEncrypt> ToxEncrypt::makeToxEncrypt(const QString& password, const QByteArray& toxSave)
{
if (!isEncrypted(toxSave))
{
if (!isEncrypted(toxSave)) {
qWarning() << "The data was not encrypted using this module or it's corrupted.";
return std::unique_ptr<ToxEncrypt>{};
}
@ -197,8 +190,7 @@ std::unique_ptr<ToxEncrypt> ToxEncrypt::makeToxEncrypt(const QString& password,
uint8_t salt[TOX_PASS_SALT_LENGTH];
tox_get_salt(reinterpret_cast<const uint8_t*>(toxSave.constData()), salt, &saltError);
if (saltError != TOX_ERR_GET_SALT_OK)
{
if (saltError != TOX_ERR_GET_SALT_OK) {
qWarning() << getSaltError(saltError);
return std::unique_ptr<ToxEncrypt>{};
}
@ -209,8 +201,7 @@ std::unique_ptr<ToxEncrypt> ToxEncrypt::makeToxEncrypt(const QString& password,
tox_pass_key_derive_with_salt(passKey, reinterpret_cast<const uint8_t*>(pass.constData()),
static_cast<size_t>(pass.length()), salt, &keyError);
if (keyError != TOX_ERR_KEY_DERIVATION_OK)
{
if (keyError != TOX_ERR_KEY_DERIVATION_OK) {
tox_pass_key_free(passKey);
qWarning() << getKeyDerivationError(keyError);
return std::unique_ptr<ToxEncrypt>{};
@ -226,21 +217,18 @@ std::unique_ptr<ToxEncrypt> ToxEncrypt::makeToxEncrypt(const QString& password,
*/
QByteArray ToxEncrypt::encrypt(const QByteArray& plaintext) const
{
if (!passKey)
{
if (!passKey) {
qCritical() << "The passKey is invalid.";
return QByteArray{};
}
QByteArray ciphertext(plaintext.length() + TOX_PASS_ENCRYPTION_EXTRA_LENGTH, 0x00);
TOX_ERR_ENCRYPTION error;
tox_pass_key_encrypt(passKey,
reinterpret_cast<const uint8_t*>(plaintext.constData()),
tox_pass_key_encrypt(passKey, reinterpret_cast<const uint8_t*>(plaintext.constData()),
static_cast<size_t>(plaintext.size()),
reinterpret_cast<uint8_t*>(ciphertext.data()), &error);
if (error != TOX_ERR_ENCRYPTION_OK)
{
if (error != TOX_ERR_ENCRYPTION_OK) {
qCritical() << getEncryptionError(error);
return QByteArray{};
}
@ -256,21 +244,18 @@ QByteArray ToxEncrypt::encrypt(const QByteArray& plaintext) const
*/
QByteArray ToxEncrypt::decrypt(const QByteArray& ciphertext) const
{
if (!isEncrypted(ciphertext))
{
if (!isEncrypted(ciphertext)) {
qWarning() << "The data was not encrypted using this module or it's corrupted.";
return QByteArray{};
}
QByteArray plaintext(ciphertext.length() - TOX_PASS_ENCRYPTION_EXTRA_LENGTH, 0x00);
TOX_ERR_DECRYPTION error;
tox_pass_key_decrypt(passKey,
reinterpret_cast<const uint8_t*>(ciphertext.constData()),
tox_pass_key_decrypt(passKey, reinterpret_cast<const uint8_t*>(ciphertext.constData()),
static_cast<size_t>(ciphertext.size()),
reinterpret_cast<uint8_t*>(plaintext.data()), &error);
if (error != TOX_ERR_DECRYPTION_OK)
{
if (error != TOX_ERR_DECRYPTION_OK) {
qWarning() << getDecryptionError(error);
return QByteArray{};
}
@ -285,14 +270,15 @@ QByteArray ToxEncrypt::decrypt(const QByteArray& ciphertext) const
*/
QString getKeyDerivationError(TOX_ERR_KEY_DERIVATION error)
{
switch(error)
{
switch (error) {
case TOX_ERR_KEY_DERIVATION_OK:
return QStringLiteral("The function returned successfully.");
case TOX_ERR_KEY_DERIVATION_NULL:
return QStringLiteral("One of the arguments to the function was NULL when it was not expected.");
return QStringLiteral(
"One of the arguments to the function was NULL when it was not expected.");
case TOX_ERR_KEY_DERIVATION_FAILED:
return QStringLiteral("The crypto lib was unable to derive a key from the given passphrase.");
return QStringLiteral(
"The crypto lib was unable to derive a key from the given passphrase.");
default:
return QStringLiteral("Unknown key derivation error.");
}
@ -305,14 +291,15 @@ QString getKeyDerivationError(TOX_ERR_KEY_DERIVATION error)
*/
QString getEncryptionError(TOX_ERR_ENCRYPTION error)
{
switch(error)
{
switch (error) {
case TOX_ERR_ENCRYPTION_OK:
return QStringLiteral("The function returned successfully.");
case TOX_ERR_ENCRYPTION_NULL:
return QStringLiteral("One of the arguments to the function was NULL when it was not expected.");
return QStringLiteral(
"One of the arguments to the function was NULL when it was not expected.");
case TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED:
return QStringLiteral("The crypto lib was unable to derive a key from the given passphrase.");
return QStringLiteral(
"The crypto lib was unable to derive a key from the given passphrase.");
case TOX_ERR_ENCRYPTION_FAILED:
return QStringLiteral("The encryption itself failed.");
default:
@ -327,14 +314,15 @@ QString getEncryptionError(TOX_ERR_ENCRYPTION error)
*/
QString getDecryptionError(TOX_ERR_DECRYPTION error)
{
switch(error)
{
switch (error) {
case TOX_ERR_DECRYPTION_OK:
return QStringLiteral("The function returned successfully.");
case TOX_ERR_DECRYPTION_NULL:
return QStringLiteral("One of the arguments to the function was NULL when it was not expected.");
return QStringLiteral(
"One of the arguments to the function was NULL when it was not expected.");
case TOX_ERR_DECRYPTION_INVALID_LENGTH:
return QStringLiteral("The input data was shorter than TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes.");
return QStringLiteral(
"The input data was shorter than TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes.");
case TOX_ERR_DECRYPTION_BAD_FORMAT:
return QStringLiteral("The input data is missing the magic number or is corrupted.");
default:
@ -349,12 +337,12 @@ QString getDecryptionError(TOX_ERR_DECRYPTION error)
*/
QString getSaltError(TOX_ERR_GET_SALT error)
{
switch(error)
{
switch (error) {
case TOX_ERR_GET_SALT_OK:
return QStringLiteral("The function returned successfully.");
case TOX_ERR_GET_SALT_NULL:
return QStringLiteral("One of the arguments to the function was NULL when it was not expected.");
return QStringLiteral(
"One of the arguments to the function was NULL when it was not expected.");
case TOX_ERR_GET_SALT_BAD_FORMAT:
return QStringLiteral("The input data is missing the magic number or is corrupted.");
default:

View File

@ -17,8 +17,8 @@
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QString>
#include <QByteArray>
#include <QString>
#ifndef TOXENCRYPT_H
#define TOXENCRYPT_H
@ -40,7 +40,8 @@ public:
static QByteArray encryptPass(const QString& password, const QByteArray& plaintext);
static QByteArray decryptPass(const QString& password, const QByteArray& ciphertext);
static std::unique_ptr<ToxEncrypt> makeToxEncrypt(const QString& password);
static std::unique_ptr<ToxEncrypt> makeToxEncrypt(const QString& password, const QByteArray& toxSave);
static std::unique_ptr<ToxEncrypt> makeToxEncrypt(const QString& password,
const QByteArray& toxSave);
QByteArray encrypt(const QByteArray& plaintext) const;
QByteArray decrypt(const QByteArray& ciphertext) const;

View File

@ -24,8 +24,8 @@
#include <tox/tox.h>
#include <cstdint>
#include <QRegularExpression>
#include <cstdint>
// Tox doesn't publicly define these
#define NOSPAM_BYTES 4
@ -60,7 +60,8 @@ const QRegularExpression ToxId::ToxIdRegEx(QString("(^|\\s)[A-Fa-f0-9]{%1}($|\\s
*/
ToxId::ToxId()
: toxId()
{}
{
}
/**
* @brief The copy constructor.
@ -68,7 +69,8 @@ ToxId::ToxId()
*/
ToxId::ToxId(const ToxId& other)
: toxId(other.toxId)
{}
{
}
/**
* @brief Create a Tox ID from a QString.
@ -82,16 +84,11 @@ ToxId::ToxId(const ToxId& other)
ToxId::ToxId(const QString& id)
{
// TODO: remove construction from PK only
if (isToxId(id))
{
if (isToxId(id)) {
toxId = QByteArray::fromHex(id.toLatin1());
}
else if(id.length() >= PUBLIC_KEY_HEX_CHARS)
{
} else if (id.length() >= PUBLIC_KEY_HEX_CHARS) {
toxId = QByteArray::fromHex(id.left(PUBLIC_KEY_HEX_CHARS).toLatin1());
}
else
{
} else {
toxId = QByteArray(); // invalid id string
}
}
@ -131,17 +128,11 @@ ToxId::ToxId(const uint8_t* rawId, int len)
void ToxId::constructToxId(const QByteArray& rawId)
{
// TODO: remove construction from PK only
if(rawId.length() == TOX_SECRET_KEY_SIZE)
{
if (rawId.length() == TOX_SECRET_KEY_SIZE) {
toxId = QByteArray(rawId); // construct from PK only
}
else if (rawId.length() == TOX_ADDRESS_SIZE
&& isToxId(rawId.toHex().toUpper()))
{
} else if (rawId.length() == TOX_ADDRESS_SIZE && isToxId(rawId.toHex().toUpper())) {
toxId = QByteArray(rawId); // construct from full toxid
}
else
{
} else {
toxId = QByteArray(); // invalid id
}
}
@ -190,8 +181,7 @@ void ToxId::clear()
*/
const uint8_t* ToxId::getBytes() const
{
if(isValid())
{
if (isValid()) {
return reinterpret_cast<const uint8_t*>(toxId.constData());
}
@ -213,8 +203,7 @@ ToxPk ToxId::getPublicKey() const
*/
QString ToxId::getNoSpamString() const
{
if(toxId.length() == TOX_ADDRESS_SIZE)
{
if (toxId.length() == TOX_ADDRESS_SIZE) {
return toxId.mid(TOX_PUBLIC_KEY_SIZE, NOSPAM_BYTES).toHex().toUpper();
}
@ -249,8 +238,7 @@ bool ToxId::isToxId(const QString& id)
*/
bool ToxId::isValid() const
{
if(toxId.length() != TOX_ADDRESS_SIZE)
{
if (toxId.length() != TOX_ADDRESS_SIZE) {
return false;
}
@ -260,8 +248,7 @@ bool ToxId::isValid() const
QByteArray checksum = toxId.right(CHECKSUM_BYTES);
QByteArray calculated(CHECKSUM_BYTES, 0x00);
for (int i = 0; i < size; i++)
{
for (int i = 0; i < size; i++) {
calculated[i % 2] = calculated[i % 2] ^ data[i];
}

View File

@ -23,9 +23,9 @@
#include "toxpk.h"
#include <cstdint>
#include <QByteArray>
#include <QString>
#include <cstdint>
class ToxId
{

View File

@ -15,7 +15,8 @@
*/
ToxPk::ToxPk()
: key()
{}
{
}
/**
* @brief The copy constructor.
@ -23,7 +24,8 @@ ToxPk::ToxPk()
*/
ToxPk::ToxPk(const ToxPk& other)
: key(other.key)
{}
{
}
/**
* @brief Constructs a ToxPk from bytes.
@ -32,12 +34,9 @@ ToxPk::ToxPk(const ToxPk& other)
*/
ToxPk::ToxPk(const QByteArray& rawId)
{
if(rawId.length() == TOX_PUBLIC_KEY_SIZE)
{
if (rawId.length() == TOX_PUBLIC_KEY_SIZE) {
key = QByteArray(rawId);
}
else
{
} else {
key = QByteArray();
}
}
@ -88,8 +87,7 @@ QString ToxPk::toString() const
*/
const uint8_t* ToxPk::getBytes() const
{
if(key.isEmpty())
{
if (key.isEmpty()) {
return nullptr;
}

View File

@ -1,9 +1,9 @@
#ifndef TOXPK_H
#define TOXPK_H
#include <cstdint>
#include <QByteArray>
#include <QString>
#include <cstdint>
class ToxPk
{
@ -21,6 +21,7 @@ public:
bool isEmpty() const;
static int getPkSize();
private:
QByteArray key;
};

View File

@ -23,8 +23,8 @@
#include "src/group.h"
#include "src/grouplist.h"
#include "src/nexus.h"
#include "src/persistence/settings.h"
#include "src/persistence/profile.h"
#include "src/persistence/settings.h"
#include "src/widget/form/chatform.h"
Friend::Friend(uint32_t friendId, const ToxPk& friendPk)
@ -35,8 +35,7 @@ Friend::Friend(uint32_t friendId, const ToxPk& friendPk)
, hasNewEvents(false)
, friendStatus(Status::Offline)
{
if (userName.isEmpty())
{
if (userName.isEmpty()) {
userName = friendPk.toString();
}
@ -55,8 +54,7 @@ Friend::~Friend()
*/
void Friend::loadHistory()
{
if (Nexus::getProfile()->isHistoryEnabled())
{
if (Nexus::getProfile()->isHistoryEnabled()) {
chatForm->loadHistory(QDateTime::currentDateTime().addDays(-7), true);
}
@ -65,13 +63,11 @@ void Friend::loadHistory()
void Friend::setName(QString name)
{
if (name.isEmpty())
{
if (name.isEmpty()) {
name = friendPk.toString();
}
if (userName != name)
{
if (userName != name) {
userName = name;
emit nameChanged(friendId, name);
}
@ -79,8 +75,7 @@ void Friend::setName(QString name)
void Friend::setAlias(QString alias)
{
if (userAlias != alias)
{
if (userAlias != alias) {
userAlias = alias;
emit aliasChanged(friendId, alias);
}
@ -88,8 +83,7 @@ void Friend::setAlias(QString alias)
void Friend::setStatusMessage(QString message)
{
if (statusMessage != message)
{
if (statusMessage != message) {
statusMessage = message;
emit statusMessageChanged(friendId, message);
}
@ -102,8 +96,7 @@ QString Friend::getStatusMessage()
QString Friend::getDisplayedName() const
{
if (userAlias.isEmpty())
{
if (userAlias.isEmpty()) {
return userName;
}
@ -137,8 +130,7 @@ bool Friend::getEventFlag() const
void Friend::setStatus(Status s)
{
if (friendStatus != s)
{
if (friendStatus != s) {
friendStatus = s;
emit statusChanged(friendId, friendStatus);
}

View File

@ -20,10 +20,10 @@
#ifndef FRIEND_H
#define FRIEND_H
#include "core/toxid.h"
#include "src/core/corestructs.h"
#include <QObject>
#include <QString>
#include "src/core/corestructs.h"
#include "core/toxid.h"
class FriendWidget;
class ChatForm;

View File

@ -20,9 +20,9 @@
#include "friend.h"
#include "friendlist.h"
#include "src/persistence/settings.h"
#include <QMenu>
#include <QDebug>
#include <QHash>
#include <QMenu>
QHash<int, Friend*> FriendList::friendList;
QHash<QByteArray, int> FriendList::key2id;
@ -52,8 +52,7 @@ Friend* FriendList::findFriend(int friendId)
void FriendList::removeFriend(int friendId, bool fake)
{
auto f_it = friendList.find(friendId);
if (f_it != friendList.end())
{
if (f_it != friendList.end()) {
if (!fake)
Settings::getInstance().removeFriendSettings(f_it.value()->getPublicKey());
friendList.erase(f_it);
@ -70,8 +69,7 @@ void FriendList::clear()
Friend* FriendList::findFriend(const ToxPk& friendPk)
{
auto id = key2id.find(friendPk.getKey());
if (id != key2id.end())
{
if (id != key2id.end()) {
Friend* f = findFriend(*id);
if (!f)
return nullptr;

View File

@ -20,8 +20,10 @@
#ifndef FRIENDLIST_H
#define FRIENDLIST_H
template <class T> class QList;
template <class A, class B> class QHash;
template <class T>
class QList;
template <class A, class B>
class QHash;
class Friend;
class QByteArray;
class ToxPk;

View File

@ -18,17 +18,19 @@
*/
#include "group.h"
#include "widget/groupwidget.h"
#include "widget/form/groupchatform.h"
#include "friendlist.h"
#include "friend.h"
#include "friendlist.h"
#include "src/core/core.h"
#include "widget/form/groupchatform.h"
#include "widget/groupwidget.h"
#include "widget/gui.h"
#include <QDebug>
#include <QTimer>
Group::Group(int GroupId, QString Name, bool IsAvGroupchat)
: groupId(GroupId), nPeers{0}, avGroupchat{IsAvGroupchat}
: groupId(GroupId)
, nPeers{0}
, avGroupchat{IsAvGroupchat}
{
widget = new GroupWidget(groupId, Name);
chatForm = new GroupChatForm(this);
@ -54,13 +56,10 @@ void Group::updatePeer(int peerId, QString name)
toxids[peerPk] = name;
Friend* f = FriendList::findFriend(peerKey);
if (f != nullptr && f->hasAlias())
{
if (f != nullptr && f->hasAlias()) {
peers[peerId] = f->getDisplayedName();
toxids[peerPk] = f->getDisplayedName();
}
else
{
} else {
widget->onUserListChanged();
chatForm->onUserListChanged();
emit userListChanged(getGroupWidget());
@ -88,8 +87,7 @@ void Group::regeneratePeerList()
peers = core->getGroupPeerNames(groupId);
toxids.clear();
nPeers = peers.size();
for (int i = 0; i < nPeers; ++i)
{
for (int i = 0; i < nPeers; ++i) {
ToxPk id = core->getGroupPeerPk(groupId, i);
ToxPk self = core->getSelfId().getPublicKey();
if (id == self)
@ -98,11 +96,11 @@ void Group::regeneratePeerList()
QByteArray peerPk = id.getKey();
toxids[peerPk] = peers[i];
if (toxids[peerPk].isEmpty())
toxids[peerPk] = tr("<Empty>", "Placeholder when someone's name in a group chat is empty");
toxids[peerPk] =
tr("<Empty>", "Placeholder when someone's name in a group chat is empty");
Friend* f = FriendList::findFriend(id);
if (f != nullptr && f->hasAlias())
{
if (f != nullptr && f->hasAlias()) {
peers[i] = f->getDisplayedName();
toxids[peerPk] = f->getDisplayedName();
}

View File

@ -74,7 +74,6 @@ private:
int nPeers;
int selfPeerNum = -1;
bool avGroupchat;
};
#endif // GROUP_H

View File

@ -35,10 +35,8 @@ GroupInvite::GroupInvite(int32_t friendID, uint8_t inviteType, const QByteArray&
bool GroupInvite::operator==(const GroupInvite& other) const
{
return friendId == other.friendId &&
type == other.type &&
invite == other.invite &&
date == other.date;
return friendId == other.friendId && type == other.type && invite == other.invite
&& date == other.date;
}
int32_t GroupInvite::getFriendId() const

View File

@ -20,9 +20,9 @@
#ifndef GROUPINVITE_H
#define GROUPINVITE_H
#include <cstdint>
#include <QByteArray>
#include <QDateTime>
#include <cstdint>
class GroupInvite
{

View File

@ -19,8 +19,8 @@
#include "grouplist.h"
#include "group.h"
#include <QHash>
#include <QDebug>
#include <QHash>
QHash<int, Group*> GroupList::groupList;
@ -48,8 +48,7 @@ Group* GroupList::findGroup(int groupId)
void GroupList::removeGroup(int groupId, bool /*fake*/)
{
auto g_it = groupList.find(groupId);
if (g_it != groupList.end())
{
if (g_it != groupList.end()) {
groupList.erase(g_it);
}
}

View File

@ -20,8 +20,10 @@
#ifndef GROUPLIST_H
#define GROUPLIST_H
template <class A, class B> class QHash;
template <class T> class QList;
template <class A, class B>
class QHash;
template <class T>
class QList;
class Group;
class QString;

View File

@ -51,33 +51,26 @@ IPC::IPC()
// Every time it processes events it updates the global shared timestamp "lastProcessed"
// If the timestamp isn't updated, that's a timeout and someone else can take ownership
// This is a safety measure, in case one of the clients crashes
// If the owner exits normally, it can set the timestamp to 0 first to immediately give ownership
// If the owner exits normally, it can set the timestamp to 0 first to immediately give
// ownership
std::default_random_engine randEngine((std::random_device())());
std::uniform_int_distribution<uint64_t> distribution;
globalId = distribution(randEngine);
qDebug() << "Our global IPC ID is " << globalId;
if (globalMemory.create(sizeof(IPCMemory)))
{
if (globalMemory.lock())
{
if (globalMemory.create(sizeof(IPCMemory))) {
if (globalMemory.lock()) {
IPCMemory* mem = global();
memset(mem, 0, sizeof(IPCMemory));
mem->globalId = globalId;
mem->lastProcessed = time(0);
globalMemory.unlock();
}
else
{
} else {
qWarning() << "Couldn't lock to take ownership";
}
}
else if (globalMemory.attach())
{
} else if (globalMemory.attach()) {
qDebug() << "Attaching to the global shared memory";
}
else
{
} else {
qDebug() << "Failed to attach to the global shared memory, giving up";
return; // We won't be able to do any IPC without being attached, let's get outta here
}
@ -87,10 +80,8 @@ IPC::IPC()
IPC::~IPC()
{
if (isCurrentOwner())
{
if (globalMemory.lock())
{
if (isCurrentOwner()) {
if (globalMemory.lock()) {
global()->globalId = 0;
globalMemory.unlock();
}
@ -122,20 +113,17 @@ time_t IPC::postEvent(const QString &name, const QByteArray& data, uint32_t dest
if (data.length() > (int32_t)sizeof(IPCEvent::data))
return 0;
if (globalMemory.lock())
{
if (globalMemory.lock()) {
IPCEvent* evt = nullptr;
IPCMemory* mem = global();
time_t result = 0;
for (uint32_t i = 0; !evt && i < EVENT_QUEUE_SIZE; ++i)
{
for (uint32_t i = 0; !evt && i < EVENT_QUEUE_SIZE; ++i) {
if (mem->events[i].posted == 0)
evt = &mem->events[i];
}
if (evt)
{
if (evt) {
memset(evt, 0, sizeof(IPCEvent));
memcpy(evt->name, binName.constData(), binName.length());
memcpy(evt->data, data.constData(), data.length());
@ -146,8 +134,7 @@ time_t IPC::postEvent(const QString &name, const QByteArray& data, uint32_t dest
}
globalMemory.unlock();
return result;
}
else
} else
qDebug() << "Failed to lock in postEvent()";
return 0;
@ -155,11 +142,9 @@ time_t IPC::postEvent(const QString &name, const QByteArray& data, uint32_t dest
bool IPC::isCurrentOwner()
{
if (globalMemory.lock())
{
if (globalMemory.lock()) {
void* data = globalMemory.data();
if (!data)
{
if (!data) {
qWarning() << "isCurrentOwner failed to access the memory, returning false";
globalMemory.unlock();
return false;
@ -167,9 +152,7 @@ bool IPC::isCurrentOwner()
bool isOwner = ((*(uint64_t*)data) == globalId);
globalMemory.unlock();
return isOwner;
}
else
{
} else {
qWarning() << "isCurrentOwner failed to lock, returning false";
return false;
}
@ -187,15 +170,11 @@ void IPC::registerEventHandler(const QString &name, IPCEventHandler handler)
bool IPC::isEventAccepted(time_t time)
{
bool result = false;
if (globalMemory.lock())
{
if (difftime(global()->lastProcessed, time) > 0)
{
if (globalMemory.lock()) {
if (difftime(global()->lastProcessed, time) > 0) {
IPCMemory* mem = global();
for (uint32_t i = 0; i < EVENT_QUEUE_SIZE; ++i)
{
if (mem->events[i].posted == time && mem->events[i].processed)
{
for (uint32_t i = 0; i < EVENT_QUEUE_SIZE; ++i) {
if (mem->events[i].posted == time && mem->events[i].processed) {
result = mem->events[i].accepted;
break;
}
@ -229,15 +208,14 @@ bool IPC::waitUntilAccepted(time_t postTime, int32_t timeout/*=-1*/)
IPC::IPCEvent* IPC::fetchEvent()
{
IPCMemory* mem = global();
for (uint32_t i = 0; i < EVENT_QUEUE_SIZE; ++i)
{
for (uint32_t i = 0; i < EVENT_QUEUE_SIZE; ++i) {
IPCEvent* evt = &mem->events[i];
// Garbage-collect events that were not processed in EVENT_GC_TIMEOUT
// and events that were processed and EVENT_GC_TIMEOUT passed after
// so sending instance has time to react to those events.
if ((evt->processed && difftime(time(0), evt->processed) > EVENT_GC_TIMEOUT) ||
(!evt->processed && difftime(time(0), evt->posted) > EVENT_GC_TIMEOUT))
if ((evt->processed && difftime(time(0), evt->processed) > EVENT_GC_TIMEOUT)
|| (!evt->processed && difftime(time(0), evt->posted) > EVENT_GC_TIMEOUT))
memset(evt, 0, sizeof(IPCEvent));
if (evt->posted && !evt->processed && evt->sender != getpid()
@ -255,10 +233,8 @@ bool IPC::runEventHandler(IPCEventHandler handler, const QByteArray& arg)
if (QThread::currentThread() == qApp->thread())
result = handler(arg);
else
QMetaObject::invokeMethod(this, "runEventHandler",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, result),
Q_ARG(IPCEventHandler, handler),
QMetaObject::invokeMethod(this, "runEventHandler", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, result), Q_ARG(IPCEventHandler, handler),
Q_ARG(const QByteArray&, arg));
return result;
@ -266,21 +242,18 @@ bool IPC::runEventHandler(IPCEventHandler handler, const QByteArray& arg)
void IPC::processEvents()
{
if (globalMemory.lock())
{
if (globalMemory.lock()) {
IPCMemory* mem = global();
if (mem->globalId == globalId)
{
if (mem->globalId == globalId) {
// We're the owner, let's process those events
mem->lastProcessed = time(0);
}
else
{
// Only the owner processes events. But if the previous owner's dead, we can take ownership now
if (difftime(time(0), mem->lastProcessed) >= OWNERSHIP_TIMEOUT_S)
{
qDebug() << "Previous owner timed out, taking ownership" << mem->globalId << "->" << globalId;
} else {
// Only the owner processes events. But if the previous owner's dead, we can take
// ownership now
if (difftime(time(0), mem->lastProcessed) >= OWNERSHIP_TIMEOUT_S) {
qDebug() << "Previous owner timed out, taking ownership" << mem->globalId << "->"
<< globalId;
// Ignore events that were not meant for this instance
memset(mem, 0, sizeof(IPCMemory));
mem->globalId = globalId;
@ -289,27 +262,22 @@ void IPC::processEvents()
// Non-main instance is limited to events destined for specific profile it runs
}
while (IPCEvent* evt = fetchEvent())
{
while (IPCEvent* evt = fetchEvent()) {
QString name = QString::fromUtf8(evt->name);
auto it = eventHandlers.find(name);
if (it != eventHandlers.end())
{
if (it != eventHandlers.end()) {
qDebug() << "Processing event: " << name << ":" << evt->posted << "=" << evt->accepted;
evt->accepted = runEventHandler(it.value(), evt->data);
if (evt->dest == 0)
{
// Global events should be processed only by instance that accepted event. Otherwise global
if (evt->dest == 0) {
// Global events should be processed only by instance that accepted event.
// Otherwise global
// event would be consumed by very first instance that gets to check it.
if (evt->accepted)
evt->processed = time(0);
}
else
{
} else {
evt->processed = time(0);
}
}
}
globalMemory.unlock();

View File

@ -21,13 +21,13 @@
#ifndef IPC_H
#define IPC_H
#include <ctime>
#include <functional>
#include <QMap>
#include <QObject>
#include <QSharedMemory>
#include <QTimer>
#include <QVector>
#include <ctime>
#include <functional>
using IPCEventHandler = std::function<bool(const QByteArray&)>;
@ -37,6 +37,7 @@ class IPC : public QObject
{
Q_OBJECT
IPC();
protected:
static const int EVENT_TIMER_MS = 1000;
static const int EVENT_GC_TIMEOUT = 5;

View File

@ -17,25 +17,25 @@
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "widget/widget.h"
#include "persistence/settings.h"
#include "src/nexus.h"
#include "src/ipc.h"
#include "src/net/toxuri.h"
#include "src/net/autoupdate.h"
#include "src/persistence/toxsave.h"
#include "src/net/toxuri.h"
#include "src/nexus.h"
#include "src/persistence/profile.h"
#include "src/persistence/toxsave.h"
#include "src/video/camerasource.h"
#include "src/widget/loginscreen.h"
#include "src/widget/translator.h"
#include "src/video/camerasource.h"
#include "widget/widget.h"
#include <QApplication>
#include <QCommandLineParser>
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QMutex>
#include <QFontDatabase>
#include <QMutex>
#include <QMutexLocker>
#include <sodium.h>
@ -47,7 +47,8 @@
#ifdef LOG_TO_FILE
static QAtomicPointer<FILE> logFileFile = nullptr;
static QList<QByteArray>* logBuffer = new QList<QByteArray>(); //Store log messages until log file opened
static QList<QByteArray>* logBuffer =
new QList<QByteArray>(); // Store log messages until log file opened
QMutex* logBufferMutex = new QMutex();
#endif
@ -63,17 +64,15 @@ void logMessageHandler(QtMsgType type, const QMessageLogContext& ctxt, const QSt
// nullptr in release builds.
QString path = QString(__FILE__);
path = path.left(path.lastIndexOf('/') + 1);
if (file.startsWith(path))
{
if (file.startsWith(path)) {
file = file.mid(path.length());
}
// Time should be in UTC to save user privacy on log sharing
QTime time = QDateTime::currentDateTime().toUTC().time();
QString LogMsg = QString("[%1 UTC] %2:%3 : ")
.arg(time.toString("HH:mm:ss.zzz")).arg(file).arg(ctxt.line);
switch (type)
{
QString LogMsg =
QString("[%1 UTC] %2:%3 : ").arg(time.toString("HH:mm:ss.zzz")).arg(file).arg(ctxt.line);
switch (type) {
case QtDebugMsg:
LogMsg += "Debug";
break;
@ -96,19 +95,15 @@ void logMessageHandler(QtMsgType type, const QMessageLogContext& ctxt, const QSt
#ifdef LOG_TO_FILE
FILE* logFilePtr = logFileFile.load(); // atomically load the file pointer
if (!logFilePtr)
{
if (!logFilePtr) {
logBufferMutex->lock();
if (logBuffer)
logBuffer->append(LogMsgBytes);
logBufferMutex->unlock();
}
else
{
} else {
logBufferMutex->lock();
if (logBuffer)
{
if (logBuffer) {
// empty logBuffer to file
foreach (QByteArray msg, *logBuffer)
fwrite(msg.constData(), 1, msg.size(), logFilePtr);
@ -151,11 +146,14 @@ int main(int argc, char *argv[])
// Process arguments
QCommandLineParser parser;
parser.setApplicationDescription("qTox, version: " + QString(GIT_VERSION) + "\nBuilt: " + __TIME__ + " " + __DATE__);
parser.setApplicationDescription("qTox, version: " + QString(GIT_VERSION) + "\nBuilt: "
+ __TIME__ + " " + __DATE__);
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("uri", QObject::tr("Tox URI to parse"));
parser.addOption(QCommandLineOption("p", QObject::tr("Starts new instance and loads specified profile."), QObject::tr("profile")));
parser.addOption(
QCommandLineOption("p", QObject::tr("Starts new instance and loads specified profile."),
QObject::tr("profile")));
parser.process(a);
IPC& ipc = IPC::getInstance();
@ -174,8 +172,7 @@ int main(int argc, char *argv[])
FILE* mainLogFilePtr = fopen(logfile.toLocal8Bit().constData(), "a");
// Trim log file if over 1MB
if (QFileInfo(logfile).size() > 1000000)
{
if (QFileInfo(logfile).size() > 1000000) {
qDebug() << "Log file over 1MB, rotating...";
// close old logfile (need for windows)
@ -229,64 +226,49 @@ int main(int argc, char *argv[])
uint32_t ipcDest = 0;
QString eventType, firstParam;
if (parser.isSet("p"))
{
if (parser.isSet("p")) {
profileName = parser.value("p");
if (!Profile::exists(profileName))
{
qCritical() << "-p profile" << profileName + ".tox" << "doesn't exist";
if (!Profile::exists(profileName)) {
qCritical() << "-p profile" << profileName + ".tox"
<< "doesn't exist";
return EXIT_FAILURE;
}
ipcDest = Settings::makeProfileId(profileName);
autoLogin = true;
}
else
{
} else {
profileName = Settings::getInstance().getCurrentProfile();
}
if (parser.positionalArguments().size() == 0)
{
if (parser.positionalArguments().size() == 0) {
eventType = "activate";
}
else
{
} else {
firstParam = parser.positionalArguments()[0];
// Tox URIs. If there's already another qTox instance running, we ask it to handle the URI and we exit
// Tox URIs. If there's already another qTox instance running, we ask it to handle the URI
// and we exit
// Otherwise we start a new qTox instance and process it ourselves
if (firstParam.startsWith("tox:"))
{
if (firstParam.startsWith("tox:")) {
eventType = "uri";
}
else if (firstParam.endsWith(".tox"))
{
} else if (firstParam.endsWith(".tox")) {
eventType = "save";
}
else
{
} else {
qCritical() << "Invalid argument";
return EXIT_FAILURE;
}
}
if (!ipc.isCurrentOwner())
{
if (!ipc.isCurrentOwner()) {
time_t event = ipc.postEvent(eventType, firstParam.toUtf8(), ipcDest);
// If someone else processed it, we're done here, no need to actually start qTox
if (ipc.waitUntilAccepted(event, 2))
{
if (ipc.waitUntilAccepted(event, 2)) {
qDebug() << "Event" << eventType << "was handled by other client.";
return EXIT_SUCCESS;
}
}
// Autologin
if (autoLogin)
{
if (Profile::exists(profileName))
{
if (!Profile::isEncrypted(profileName))
{
if (autoLogin) {
if (Profile::exists(profileName)) {
if (!Profile::isEncrypted(profileName)) {
Profile* profile = Profile::loadProfile(profileName);
if (profile)
Nexus::getInstance().setProfile(profile);

View File

@ -18,32 +18,34 @@
*/
#include "src/net/autoupdate.h"
#include "src/nexus.h"
#include "src/persistence/serialize.h"
#include "src/persistence/settings.h"
#include "src/widget/widget.h"
#include "src/widget/gui.h"
#include "src/nexus.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include "src/widget/widget.h"
#include <QCoreApplication>
#include <QFile>
#include <QDir>
#include <QProcess>
#include <QtConcurrent/QtConcurrent>
#include <QFile>
#include <QMessageBox>
#include <QMutexLocker>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QProcess>
#include <QtConcurrent/QtConcurrent>
#include <iostream>
#ifdef Q_OS_WIN
#include <windows.h>
#include <shellapi.h>
#include <windows.h>
#endif
/**
* @file autoupdate.cpp
*
* For now we only support auto updates on Windows and OS X, although extending it is not a technical issue.
* Linux users are expected to use their package managers or update manually through official channels.
* For now we only support auto updates on Windows and OS X, although extending it is not a
* technical issue.
* Linux users are expected to use their package managers or update manually through official
* channels.
*/
#ifdef Q_OS_WIN
@ -55,22 +57,24 @@ const QString AutoUpdater::platform = "win32";
const QString AutoUpdater::updaterBin = "qtox-updater.exe";
const QString AutoUpdater::updateServer = "https://qtox-win.pkg.tox.chat";
unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES] =
{
0x20, 0x89, 0x39, 0xaa, 0x9a, 0xe8, 0xb5, 0x21, 0x0e, 0xac, 0x02, 0xa9, 0xc4, 0x92, 0xd9, 0xa2,
0x17, 0x83, 0xbd, 0x78, 0x0a, 0xda, 0x33, 0xcd, 0xa5, 0xc6, 0x44, 0xc7, 0xfc, 0xed, 0x00, 0x13
};
unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES] = {0x20, 0x89, 0x39, 0xaa, 0x9a, 0xe8,
0xb5, 0x21, 0x0e, 0xac, 0x02, 0xa9,
0xc4, 0x92, 0xd9, 0xa2, 0x17, 0x83,
0xbd, 0x78, 0x0a, 0xda, 0x33, 0xcd,
0xa5, 0xc6, 0x44, 0xc7, 0xfc, 0xed,
0x00, 0x13};
#elif defined(Q_OS_OSX)
const QString AutoUpdater::platform = "osx";
const QString AutoUpdater::updaterBin = "/Applications/qtox.app/Contents/MacOS/updater";
const QString AutoUpdater::updateServer = "https://dist-build.tox.im";
unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00};
#else
const QString AutoUpdater::platform;
@ -122,9 +126,12 @@ unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES];
* @brief No, we can't just make the QString atomic
*/
const QString AutoUpdater::checkURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/version";
const QString AutoUpdater::flistURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/flist";
const QString AutoUpdater::filesURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/files/";
const QString AutoUpdater::checkURI =
AutoUpdater::updateServer + "/qtox/" + AutoUpdater::platform + "/version";
const QString AutoUpdater::flistURI =
AutoUpdater::updateServer + "/qtox/" + AutoUpdater::platform + "/flist";
const QString AutoUpdater::filesURI =
AutoUpdater::updateServer + "/qtox/" + AutoUpdater::platform + "/files/";
std::atomic_bool AutoUpdater::abortFlag{false};
std::atomic_bool AutoUpdater::isDownloadingUpdate{false};
std::atomic<float> AutoUpdater::progressValue{0};
@ -149,7 +156,8 @@ bool AutoUpdater::isUpdateAvailable()
if (isDownloadingUpdate)
return false;
QString updaterPath = updaterBin.startsWith('/') ? updaterBin : qApp->applicationDirPath()+'/'+updaterBin;
QString updaterPath =
updaterBin.startsWith('/') ? updaterBin : qApp->applicationDirPath() + '/' + updaterBin;
if (!QFile::exists(updaterPath))
return false;
@ -178,15 +186,13 @@ AutoUpdater::VersionInfo AutoUpdater::getUpdateVersion()
QNetworkAccessManager* manager = new QNetworkAccessManager;
manager->setProxy(Settings::getInstance().getProxy());
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(checkURI)));
while (!reply->isFinished())
{
while (!reply->isFinished()) {
if (abortFlag)
return versionInfo;
qApp->processEvents();
}
if (reply->error() != QNetworkReply::NoError)
{
if (reply->error() != QNetworkReply::NoError) {
qWarning() << "getUpdateVersion: network error: " + reply->errorString();
reply->deleteLater();
manager->deleteLater();
@ -200,8 +206,7 @@ AutoUpdater::VersionInfo AutoUpdater::getUpdateVersion()
return versionInfo;
// Check updater protocol version
if ((int)data[0] != '3')
{
if ((int)data[0] != '3') {
qWarning() << "getUpdateVersion: Bad version " << (uint8_t)data[0];
return versionInfo;
}
@ -212,8 +217,7 @@ AutoUpdater::VersionInfo AutoUpdater::getUpdateVersion()
QByteArray msgData = data.mid(1 + crypto_sign_BYTES);
unsigned char* msg = (unsigned char*)msgData.data();
if (crypto_sign_verify_detached(sig, msg, msgData.size(), key) != 0)
{
if (crypto_sign_verify_detached(sig, msg, msgData.size(), key) != 0) {
qCritical() << "getUpdateVersion: RECEIVED FORGED VERSION FILE FROM " << updateServer;
return versionInfo;
}
@ -236,32 +240,27 @@ QList<AutoUpdater::UpdateFileMeta> AutoUpdater::parseFlist(QByteArray flistData)
{
QList<UpdateFileMeta> flist;
if (flistData.isEmpty())
{
if (flistData.isEmpty()) {
qWarning() << "parseflist: Empty data";
return flist;
}
// Check version
if (flistData[0] != '1')
{
if (flistData[0] != '1') {
qWarning() << "parseflist: Bad version " << (uint8_t)flistData[0];
return flist;
}
flistData = flistData.mid(1);
// Check signature
if (flistData.size() < (int)(crypto_sign_BYTES))
{
if (flistData.size() < (int)(crypto_sign_BYTES)) {
qWarning() << "parseflist: Truncated data";
return flist;
}
else
{
} else {
QByteArray msgData = flistData.mid(crypto_sign_BYTES);
unsigned char* msg = (unsigned char*)msgData.data();
if (crypto_sign_verify_detached((unsigned char*)flistData.data(), msg, msgData.size(), key) != 0)
{
if (crypto_sign_verify_detached((unsigned char*)flistData.data(), msg, msgData.size(), key)
!= 0) {
qCritical() << "parseflist: FORGED FLIST FILE";
return flist;
}
@ -269,8 +268,7 @@ QList<AutoUpdater::UpdateFileMeta> AutoUpdater::parseFlist(QByteArray flistData)
}
// Parse. We assume no errors handling needed since the signature is valid.
while (!flistData.isEmpty())
{
while (!flistData.isEmpty()) {
UpdateFileMeta newFile;
memcpy(newFile.sig, flistData.data(), crypto_sign_BYTES);
@ -303,15 +301,13 @@ QByteArray AutoUpdater::getUpdateFlist()
QNetworkAccessManager* manager = new QNetworkAccessManager;
manager->setProxy(Settings::getInstance().getProxy());
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(flistURI)));
while (!reply->isFinished())
{
while (!reply->isFinished()) {
if (abortFlag)
return flist;
qApp->processEvents();
}
if (reply->error() != QNetworkReply::NoError)
{
if (reply->error() != QNetworkReply::NoError) {
qWarning() << "getUpdateFlist: network error: " + reply->errorString();
reply->deleteLater();
manager->deleteLater();
@ -363,10 +359,12 @@ bool AutoUpdater::isUpToDate(AutoUpdater::UpdateFileMeta fileMeta)
/**
* @brief Tries to fetch the file from the update server.
* @note Note that a file with an empty but non-null QByteArray is not an error, merely a file of size 0.
* @note Note that a file with an empty but non-null QByteArray is not an error, merely a file of
* size 0.
* @note Will try to follow qTox's proxy settings, may block and processEvents.
* @param fileMeta Meta data fo file to update.
* @param progressCallback Callback function, which will connected with QNetworkReply::downloadProgress
* @param progressCallback Callback function, which will connected with
* QNetworkReply::downloadProgress
* @return A file with a null QByteArray on error.
*/
AutoUpdater::UpdateFile AutoUpdater::getUpdateFile(UpdateFileMeta fileMeta,
@ -379,15 +377,13 @@ AutoUpdater::UpdateFile AutoUpdater::getUpdateFile(UpdateFileMeta fileMeta,
manager->setProxy(Settings::getInstance().getProxy());
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(filesURI + fileMeta.id)));
QObject::connect(reply, &QNetworkReply::downloadProgress, progressCallback);
while (!reply->isFinished())
{
while (!reply->isFinished()) {
if (abortFlag)
return file;
qApp->processEvents();
}
if (reply->error() != QNetworkReply::NoError)
{
if (reply->error() != QNetworkReply::NoError) {
qWarning() << "getUpdateFile: network error: " + reply->errorString();
reply->deleteLater();
manager->deleteLater();
@ -424,8 +420,7 @@ bool AutoUpdater::downloadUpdate()
// Progress
progressValue = 0;
if (abortFlag)
{
if (abortFlag) {
isDownloadingUpdate = false;
return false;
}
@ -438,8 +433,7 @@ bool AutoUpdater::downloadUpdate()
if (!updateDir.exists())
QDir().mkdir(updateDirStr);
updateDir = QDir(updateDirStr);
if (!updateDir.exists())
{
if (!updateDir.exists()) {
qWarning() << "downloadUpdate: Can't create update directory, aborting...";
isDownloadingUpdate = false;
return false;
@ -447,8 +441,7 @@ bool AutoUpdater::downloadUpdate()
// Write the new flist for the updater
QFile newFlistFile(updateDirStr + "flist");
if (!newFlistFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
if (!newFlistFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qWarning() << "downloadUpdate: Can't save new flist file, aborting...";
isDownloadingUpdate = false;
return false;
@ -459,24 +452,20 @@ bool AutoUpdater::downloadUpdate()
progressValue = 1;
// Download and write each new file
for (UpdateFileMeta fileMeta : diff)
{
for (UpdateFileMeta fileMeta : diff) {
float initialProgress = progressValue, step = 99. / diff.size();
auto stepProgressCallback = [&](int current, int total)
{
auto stepProgressCallback = [&](int current, int total) {
progressValue = initialProgress + step * (float)current / total;
};
if (abortFlag)
{
if (abortFlag) {
isDownloadingUpdate = false;
return false;
}
// Skip files we already have
QFile fileFile(updateDirStr + fileMeta.installpath);
if (fileFile.open(QIODevice::ReadOnly) && fileFile.size() == (qint64)fileMeta.size)
{
if (fileFile.open(QIODevice::ReadOnly) && fileFile.size() == (qint64)fileMeta.size) {
qDebug() << "Skipping already downloaded file '" + fileMeta.installpath + "'";
progressValue = initialProgress + step;
continue;
@ -494,23 +483,21 @@ bool AutoUpdater::downloadUpdate()
UpdateFile file = getUpdateFile(fileMeta, stepProgressCallback);
if (abortFlag)
goto fail;
if (file.data.isNull())
{
if (file.data.isNull()) {
qCritical() << "downloadUpdate: Error downloading a file, aborting...";
goto fail;
}
// Check signature
if (crypto_sign_verify_detached(file.metadata.sig, (unsigned char*)file.data.data(),
file.data.size(), key) != 0)
{
file.data.size(), key)
!= 0) {
qCritical() << "downloadUpdate: RECEIVED FORGED FILE, aborting...";
goto fail;
}
// Save
if (!fileFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
if (!fileFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qCritical() << "downloadUpdate: Can't save new update file, aborting...";
goto fail;
}
@ -566,8 +553,7 @@ bool AutoUpdater::isLocalUpdateReady()
QList<UpdateFileMeta> diff = genUpdateDiff(updateFlist);
// Check that we have every file
for (UpdateFileMeta fileMeta : diff)
{
for (UpdateFileMeta fileMeta : diff) {
if (!QFile::exists(updateDirStr + fileMeta.installpath))
return false;
@ -591,8 +577,7 @@ void AutoUpdater::installLocalUpdate()
qDebug() << "About to start the qTox updater to install a local update";
// Prepare to delete the update if we fail so we don't fail again.
auto failExit = []()
{
auto failExit = []() {
qCritical() << "Failed to start the qTox updater, removing the update and exiting";
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
QDir(updateDirStr).removeRecursively();
@ -607,13 +592,12 @@ void AutoUpdater::installLocalUpdate()
// QProcess fails silently when elevation is required instead of showing a UAC prompt on Win7/Vista
#ifdef Q_OS_WIN
QString modulePath = qApp->applicationDirPath().replace('/', '\\');
HINSTANCE result = ::ShellExecuteW(0, L"open", updaterBin.toStdWString().c_str(),
0, modulePath.toStdWString().c_str(), SW_SHOWNORMAL);
if (result == (HINSTANCE)SE_ERR_ACCESSDENIED)
{
HINSTANCE result = ::ShellExecuteW(0, L"open", updaterBin.toStdWString().c_str(), 0,
modulePath.toStdWString().c_str(), SW_SHOWNORMAL);
if (result == (HINSTANCE)SE_ERR_ACCESSDENIED) {
// Requesting elevation
result = ::ShellExecuteW(0, L"runas", updaterBin.toStdWString().c_str(),
0, modulePath.toStdWString().c_str(), SW_SHOWNORMAL);
result = ::ShellExecuteW(0, L"runas", updaterBin.toStdWString().c_str(), 0,
modulePath.toStdWString().c_str(), SW_SHOWNORMAL);
}
if (result <= (HINSTANCE)32)
failExit();
@ -656,9 +640,7 @@ void AutoUpdater::checkUpdatesAsyncInteractiveWorker()
QDir updateDir(updateDirStr);
if (updateDir.exists() && QFile(updateDirStr+"flist").exists())
{
if (updateDir.exists() && QFile(updateDirStr + "flist").exists()) {
setProgressVersion(getUpdateVersion().versionString);
downloadUpdate();
return;
@ -668,16 +650,17 @@ void AutoUpdater::checkUpdatesAsyncInteractiveWorker()
QString contentText = QObject::tr("An update is available, do you want to download it now?\n"
"It will be installed when qTox restarts.");
if (!newVersion.versionString.isEmpty())
contentText += "\n\n" + QObject::tr("Version %1, %2").arg(newVersion.versionString,
contentText +=
"\n\n"
+ QObject::tr("Version %1, %2")
.arg(newVersion.versionString,
QDateTime::fromMSecsSinceEpoch(newVersion.timestamp * 1000).toString());
if (abortFlag)
return;
if (GUI::askQuestion(QObject::tr("Update", "The title of a message box"),
contentText, true, false))
{
if (GUI::askQuestion(QObject::tr("Update", "The title of a message box"), contentText, true, false)) {
setProgressVersion(newVersion.versionString);
GUI::showUpdateDownloadProgress();
downloadUpdate();

View File

@ -21,12 +21,12 @@
#ifndef AUTOUPDATE_H
#define AUTOUPDATE_H
#include <QString>
#include <QList>
#include <QMutex>
#include <sodium.h>
#include <QString>
#include <atomic>
#include <functional>
#include <sodium.h>
#ifdef Q_OS_WIN
#define AUTOUPDATE_ENABLED 1
@ -48,8 +48,7 @@ public:
bool operator==(const UpdateFileMeta& other)
{
return (size == other.size
&& id == other.id && installpath == other.installpath
return (size == other.size && id == other.id && installpath == other.installpath
&& memcmp(sig, other.sig, crypto_sign_BYTES) == 0);
}
};
@ -82,7 +81,8 @@ protected:
static QByteArray getUpdateFlist();
static QList<UpdateFileMeta> genUpdateDiff(QList<UpdateFileMeta> updateFlist);
static bool isUpToDate(UpdateFileMeta file);
static UpdateFile getUpdateFile(UpdateFileMeta fileMeta, std::function<void(int,int)> progressCallback);
static UpdateFile getUpdateFile(UpdateFileMeta fileMeta,
std::function<void(int, int)> progressCallback);
static void checkUpdatesAsyncInteractiveWorker();
static void setProgressVersion(QString version);

View File

@ -20,8 +20,8 @@
#include "avatarbroadcaster.h"
#include "src/core/core.h"
#include <QObject>
#include <QDebug>
#include <QObject>
/**
* @class AvatarBroadcaster
@ -35,8 +35,7 @@ QByteArray AvatarBroadcaster::avatarData;
QMap<uint32_t, bool> AvatarBroadcaster::friendsSentTo;
static QMetaObject::Connection autoBroadcastConn;
static auto autoBroadcast = [](uint32_t friendId, Status)
{
static auto autoBroadcast = [](uint32_t friendId, Status) {
AvatarBroadcaster::sendAvatarTo(friendId);
};
@ -79,5 +78,6 @@ void AvatarBroadcaster::enableAutoBroadcast(bool state)
{
QObject::disconnect(autoBroadcastConn);
if (state)
autoBroadcastConn = QObject::connect(Core::getInstance(), &Core::friendStatusChanged, autoBroadcast);
autoBroadcastConn =
QObject::connect(Core::getInstance(), &Core::friendStatusChanged, autoBroadcast);
}

View File

@ -19,16 +19,16 @@
#include "toxme.h"
#include "src/core/core.h"
#include <src/persistence/settings.h>
#include <QtDebug>
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QCoreApplication>
#include <QThread>
#include <QtDebug>
#include <ctime>
#include <sodium/crypto_box.h>
#include <sodium/randombytes.h>
#include <src/persistence/settings.h>
#include <string>
#include <ctime>
/**
* @class Toxme
@ -49,8 +49,7 @@ QByteArray Toxme::makeJsonRequest(QString url, QString json, QNetworkReply::Netw
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QNetworkReply* reply = netman.post(request, json.toUtf8());
while (!reply->isFinished())
{
while (!reply->isFinished()) {
QThread::msleep(1);
qApp->processEvents();
}
@ -72,15 +71,13 @@ QByteArray Toxme::getServerPubkey(QString url, QNetworkReply::NetworkError &erro
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QNetworkReply* reply = netman.get(request);
while (!reply->isFinished())
{
while (!reply->isFinished()) {
QThread::msleep(1);
qApp->processEvents();
}
error = reply->error();
if (error)
{
if (error) {
qWarning() << "getServerPubkey: A network error occured:" << reply->errorString();
return QByteArray();
}
@ -109,8 +106,7 @@ QByteArray Toxme::getServerPubkey(QString url, QNetworkReply::NetworkError &erro
QByteArray Toxme::prepareEncryptedJson(QString url, int action, QString payload)
{
QPair<QByteArray, QByteArray> keypair = Core::getInstance()->getKeypair();
if (keypair.first.isEmpty() || keypair.second.isEmpty())
{
if (keypair.first.isEmpty() || keypair.second.isEmpty()) {
qWarning() << "prepareEncryptedJson: Couldn't get our keypair, aborting";
return QByteArray();
}
@ -138,9 +134,12 @@ QByteArray Toxme::prepareEncryptedJson(QString url, int action, QString payload)
delete[] payloadEnc;
const QString json{"{\"action\":" + QString().setNum(action) + ","
"\"public_key\":\""+keypair.first.toHex()+"\","
"\"encrypted\":\""+payloadEncData.toBase64()+"\","
"\"nonce\":\""+nonce.toBase64()+"\"}"};
"\"public_key\":\""
+ keypair.first.toHex() + "\","
"\"encrypted\":\""
+ payloadEncData.toBase64() + "\","
"\"nonce\":\""
+ nonce.toBase64() + "\"}"};
return json.toUtf8();
}
@ -201,8 +200,7 @@ Toxme::ExecCode Toxme::extractError(QString json)
json = json.mid(start + pattern.size());
int end = json.indexOf(",");
if (end == -1)
{
if (end == -1) {
end = json.indexOf("}");
if (end == -1)
return IncorrectResponse;
@ -245,10 +243,14 @@ QString Toxme::createAddress(ExecCode &code, QString server, ToxId id, QString a
server = "https://" + server;
const QString payload{"{\"tox_id\":\"" + id.toString() + "\","
"\"name\":\""+address+"\","
"\"privacy\":"+QString().setNum(privacy)+","
"\"bio\":\""+bio+"\","
"\"timestamp\":"+QString().setNum(time(0))+"}"};
"\"name\":\""
+ address + "\","
"\"privacy\":"
+ QString().setNum(privacy) + ","
"\"bio\":\""
+ bio + "\","
"\"timestamp\":"
+ QString().setNum(time(0)) + "}"};
QString pubkeyUrl = server + "/pk";
QString apiUrl = server + "/api";
@ -263,28 +265,26 @@ QString Toxme::createAddress(ExecCode &code, QString server, ToxId id, QString a
return getPass(response, code);
}
QString Toxme::getPass(QString json, ExecCode &code) {
QString Toxme::getPass(QString json, ExecCode& code)
{
static const QByteArray pattern{"password\":"};
json = json.remove(' ');
const int start = json.indexOf(pattern);
if (start == -1)
{
if (start == -1) {
code = NoPassword;
return QString();
}
json = json.mid(start + pattern.size());
if (json.startsWith("null"))
{
if (json.startsWith("null")) {
code = Updated;
return QString();
}
json = json.mid(1, json.length());
int end = json.indexOf("\"");
if (end == -1)
{
if (end == -1) {
code = IncorrectResponse;
return QString();
}
@ -303,7 +303,8 @@ QString Toxme::getPass(QString json, ExecCode &code) {
Toxme::ExecCode Toxme::deleteAddress(QString server, ToxPk id)
{
const QString payload{"{\"public_key\":\"" + id.toString() + "\","
"\"timestamp\":"+QString().setNum(time(0))+"}"};
"\"timestamp\":"
+ QString().setNum(time(0)) + "}"};
server = server.trimmed();
if (!server.contains("://"))

View File

@ -21,19 +21,20 @@
#ifndef TOXME_H
#define TOXME_H
#include <QString>
#include "src/core/toxid.h"
#include <QMap>
#include <QMutex>
#include <QNetworkReply>
#include <QString>
#include <memory>
#include "src/core/toxid.h"
class QNetworkAccessManager;
class Toxme
{
public:
enum ExecCode {
enum ExecCode
{
ExecError = -50,
Ok = 0,
Updated = 1,

View File

@ -19,21 +19,21 @@
#include "src/net/toxuri.h"
#include "src/net/toxme.h"
#include "src/widget/tool/friendrequestdialog.h"
#include "src/nexus.h"
#include "src/core/core.h"
#include "src/net/toxme.h"
#include "src/nexus.h"
#include "src/widget/tool/friendrequestdialog.h"
#include <QByteArray>
#include <QString>
#include <QMessageBox>
#include <QVBoxLayout>
#include <QCoreApplication>
#include <QDialogButtonBox>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QCoreApplication>
#include <QString>
#include <QThread>
#include <QVBoxLayout>
bool toxURIEventHandler(const QByteArray& eventData)
{
@ -55,8 +55,7 @@ bool handleToxURI(const QString &toxURI)
Nexus& nexus = Nexus::getInstance();
Core* core = nexus.getCore();
while (!core)
{
while (!core) {
if (!nexus.isRunning())
return false;
@ -65,8 +64,7 @@ bool handleToxURI(const QString &toxURI)
QThread::msleep(10);
}
while (!core->isReady())
{
while (!core->isReady()) {
if (!nexus.isRunning())
return false;
@ -77,15 +75,13 @@ bool handleToxURI(const QString &toxURI)
QString toxaddr = toxURI.mid(4);
ToxId toxId(toxaddr);
if (!toxId.isValid())
{
if (!toxId.isValid()) {
toxId = Toxme::lookup(toxaddr);
if (!toxId.isValid())
{
QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning,
QMessageBox::tr("Couldn't add friend"),
QMessageBox::tr("%1 is not a valid Toxme address.")
.arg(toxaddr), QMessageBox::Ok, nullptr);
if (!toxId.isValid()) {
QMessageBox* messageBox =
new QMessageBox(QMessageBox::Warning, QMessageBox::tr("Couldn't add friend"),
QMessageBox::tr("%1 is not a valid Toxme address.").arg(toxaddr),
QMessageBox::Ok, nullptr);
messageBox->setButtonText(QMessageBox::Ok, QMessageBox::tr("Ok"));
QObject::connect(messageBox, &QMessageBox::finished, messageBox, &QMessageBox::deleteLater);
messageBox->show();
@ -93,10 +89,9 @@ bool handleToxURI(const QString &toxURI)
}
}
if (toxId == core->getSelfId())
{
QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning,
QMessageBox::tr("Couldn't add friend"),
if (toxId == core->getSelfId()) {
QMessageBox* messageBox =
new QMessageBox(QMessageBox::Warning, QMessageBox::tr("Couldn't add friend"),
QMessageBox::tr("You can't add yourself as a friend!",
"When trying to add your own Tox ID as friend"),
QMessageBox::Ok, nullptr);
@ -106,7 +101,9 @@ bool handleToxURI(const QString &toxURI)
return false;
}
ToxURIDialog *dialog = new ToxURIDialog(0, toxaddr, QObject::tr("%1 here! Tox me maybe?",
ToxURIDialog* dialog = new ToxURIDialog(
0, toxaddr,
QObject::tr("%1 here! Tox me maybe?",
"Default message in Tox URI friend requests. Write something appropriate!")
.arg(Nexus::getCore()->getUsername()));
QObject::connect(dialog, &ToxURIDialog::finished, [=](int result) {
@ -120,8 +117,8 @@ bool handleToxURI(const QString &toxURI)
return true;
}
ToxURIDialog::ToxURIDialog(QWidget* parent, const QString &userId, const QString &message) :
QDialog(parent)
ToxURIDialog::ToxURIDialog(QWidget* parent, const QString& userId, const QString& message)
: QDialog(parent)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setWindowTitle(tr("Add a friend", "Title of the window to add a friend through Tox URI"));

View File

@ -19,28 +19,28 @@
#include "nexus.h"
#include "src/persistence/profile.h"
#include "persistence/settings.h"
#include "src/core/core.h"
#include "src/core/coreav.h"
#include "src/persistence/profile.h"
#include "src/widget/widget.h"
#include "persistence/settings.h"
#include "video/camerasource.h"
#include "widget/gui.h"
#include "widget/loginscreen.h"
#include <QThread>
#include <QDebug>
#include <QImageReader>
#include <QFile>
#include <QApplication>
#include <QDebug>
#include <QDesktopWidget>
#include <QFile>
#include <QImageReader>
#include <QThread>
#include <cassert>
#include <vpx/vpx_image.h>
#include <QDesktopWidget>
#ifdef Q_OS_MAC
#include <QWindow>
#include <QMenuBar>
#include <QActionGroup>
#include <QMenuBar>
#include <QSignalMapper>
#include <QWindow>
#endif
/**
@ -55,13 +55,13 @@ Q_DECLARE_OPAQUE_POINTER(ToxAV*)
static Nexus* nexus{nullptr};
Nexus::Nexus(QObject *parent) :
QObject(parent),
profile{nullptr},
widget{nullptr},
loginScreen{nullptr},
running{true},
quitOnLastWindowClosed{true}
Nexus::Nexus(QObject* parent)
: QObject(parent)
, profile{nullptr}
, widget{nullptr}
, loginScreen{nullptr}
, running{true}
, quitOnLastWindowClosed{true}
{
}
@ -132,8 +132,7 @@ void Nexus::start()
minimizeAction = windowMenu->addAction(QString());
minimizeAction->setShortcut(Qt::CTRL + Qt::Key_M);
connect(minimizeAction, &QAction::triggered, [this]()
{
connect(minimizeAction, &QAction::triggered, [this]() {
minimizeAction->setEnabled(false);
QApplication::focusWindow()->showMinimized();
});
@ -172,7 +171,8 @@ void Nexus::showLogin()
profile = nullptr;
loginScreen->reset();
loginScreen->move(QApplication::desktop()->screen()->rect().center() - loginScreen->rect().center());
loginScreen->move(QApplication::desktop()->screen()->rect().center()
- loginScreen->rect().center());
loginScreen->show();
quitOnLastWindowClosed = true;
}
@ -201,7 +201,8 @@ void Nexus::showMainGUI()
Core* core = profile->getCore();
connect(core, &Core::connected, widget, &Widget::onConnected);
connect(core, &Core::disconnected, widget, &Widget::onDisconnected);
connect(core, &Core::failedToStart, widget, &Widget::onFailedToStartCore, Qt::BlockingQueuedConnection);
connect(core, &Core::failedToStart, widget, &Widget::onFailedToStartCore,
Qt::BlockingQueuedConnection);
connect(core, &Core::badProxy, widget, &Widget::onBadProxyCore, Qt::BlockingQueuedConnection);
connect(core, &Core::statusSet, widget, &Widget::onStatusSet);
connect(core, &Core::usernameSet, widget, &Widget::setUsername);
@ -362,8 +363,7 @@ void Nexus::onWindowStateChanged(Qt::WindowStates state)
{
minimizeAction->setEnabled(QApplication::activeWindow() != nullptr);
if (QApplication::activeWindow() != nullptr && sender() == QApplication::activeWindow())
{
if (QApplication::activeWindow() != nullptr && sender() == QApplication::activeWindow()) {
if (state & Qt::WindowFullScreen)
minimizeAction->setEnabled(false);
@ -404,8 +404,7 @@ void Nexus::updateWindowsArg(QWindow* closedWindow)
else
activeWindow = nullptr;
for (int i = 0; i < windowList.size(); ++i)
{
for (int i = 0; i < windowList.size(); ++i) {
if (closedWindow == windowList[i])
continue;
@ -432,10 +431,8 @@ void Nexus::updateWindowsStates()
bool exists = false;
QWindowList windowList = QApplication::topLevelWindows();
for (QWindow* window : windowList)
{
if (!(window->windowState() & Qt::WindowMinimized))
{
for (QWindow* window : windowList) {
if (!(window->windowState() & Qt::WindowMinimized)) {
exists = true;
break;
}

View File

@ -42,7 +42,8 @@
* @brief Implements a low level RAII interface to a SQLCipher (SQlite3) database.
*
* Thread-safe, does all database operations on a worker thread.
* The queries must not contain transaction commands (BEGIN/COMMIT/...) or the behavior is undefined.
* The queries must not contain transaction commands (BEGIN/COMMIT/...) or the behavior is
* undefined.
*
* @var QMutex RawDatabase::transactionsMutex;
* @brief Protects pendingTransactions
@ -102,8 +103,7 @@ RawDatabase::RawDatabase(const QString& path, const QString& password, const QBy
workerThread->start();
// first try with the new salt
if (open(path, currentHexKey))
{
if (open(path, currentHexKey)) {
return;
}
@ -112,32 +112,24 @@ RawDatabase::RawDatabase(const QString& path, const QString& password, const QBy
// create a backup before trying to upgrade to new salt
bool upgrade = true;
if(!QFile::copy(path, path + ".bak"))
{
if (!QFile::copy(path, path + ".bak")) {
qDebug() << "Couldn't create the backup of the database, won't upgrade";
upgrade = false;
}
// fall back to the old salt
currentHexKey = deriveKey(password);
if(open(path, currentHexKey))
{
if (open(path, currentHexKey)) {
// upgrade only if backup successful
if(upgrade)
{
if (upgrade) {
// still using old salt, upgrade
if(setPassword(password))
{
if (setPassword(password)) {
qDebug() << "Successfully upgraded to dynamic salt";
}
else
{
} else {
qWarning() << "Failed to set password with new salt";
}
}
}
else
{
} else {
qDebug() << "Failed to open database with old salt";
}
}
@ -158,38 +150,34 @@ RawDatabase::~RawDatabase()
*/
bool RawDatabase::open(const QString& path, const QString& hexKey)
{
if (QThread::currentThread() != workerThread.get())
{
if (QThread::currentThread() != workerThread.get()) {
bool ret;
QMetaObject::invokeMethod(this, "open", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ret),
Q_ARG(const QString&, path), Q_ARG(const QString&, hexKey));
return ret;
}
if (!QFile::exists(path) && QFile::exists(path+".tmp"))
{
qWarning() << "Restoring database from temporary export file! Did we crash while changing the password?";
if (!QFile::exists(path) && QFile::exists(path + ".tmp")) {
qWarning() << "Restoring database from temporary export file! Did we crash while changing "
"the password?";
QFile::rename(path + ".tmp", path);
}
if (sqlite3_open_v2(path.toUtf8().data(), &sqlite,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX, nullptr) != SQLITE_OK)
{
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX, nullptr)
!= SQLITE_OK) {
qWarning() << "Failed to open database" << path << "with error:" << sqlite3_errmsg(sqlite);
return false;
}
if (!hexKey.isEmpty())
{
if (!execNow("PRAGMA key = \"x'"+hexKey+"'\""))
{
if (!hexKey.isEmpty()) {
if (!execNow("PRAGMA key = \"x'" + hexKey + "'\"")) {
qWarning() << "Failed to set encryption key";
close();
return false;
}
if (!execNow("SELECT count(*) FROM sqlite_master"))
{
if (!execNow("SELECT count(*) FROM sqlite_master")) {
qWarning() << "Database is unusable, check that the password is correct";
close();
return false;
@ -252,8 +240,7 @@ bool RawDatabase::execNow(const RawDatabase::Query &statement)
*/
bool RawDatabase::execNow(const QVector<RawDatabase::Query>& statements)
{
if (!sqlite)
{
if (!sqlite) {
qWarning() << "Trying to exec, but the database is not open";
return false;
}
@ -295,8 +282,7 @@ void RawDatabase::execLater(const RawDatabase::Query &statement)
void RawDatabase::execLater(const QVector<RawDatabase::Query>& statements)
{
if (!sqlite)
{
if (!sqlite) {
qWarning() << "Trying to exec, but the database is not open";
return;
}
@ -327,14 +313,12 @@ void RawDatabase::sync()
*/
bool RawDatabase::setPassword(const QString& password)
{
if (!sqlite)
{
if (!sqlite) {
qWarning() << "Trying to change the password, but the database is not open";
return false;
}
if (QThread::currentThread() != workerThread.get())
{
if (QThread::currentThread() != workerThread.get()) {
bool ret;
QMetaObject::invokeMethod(this, "setPassword", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret), Q_ARG(const QString&, password));
@ -345,59 +329,50 @@ bool RawDatabase::setPassword(const QString& password)
// so we always process the pending queue before rekeying for consistency
process();
if (QFile::exists(path+".tmp"))
{
if (QFile::exists(path + ".tmp")) {
qWarning() << "Found old temporary export file while rekeying, deleting it";
QFile::remove(path + ".tmp");
}
if (!password.isEmpty())
{
if (!password.isEmpty()) {
QString newHexKey = deriveKey(password, currentSalt);
if (!currentHexKey.isEmpty())
{
if (!execNow("PRAGMA rekey = \"x'"+newHexKey+"'\""))
{
if (!currentHexKey.isEmpty()) {
if (!execNow("PRAGMA rekey = \"x'" + newHexKey + "'\"")) {
qWarning() << "Failed to change encryption key";
close();
return false;
}
}
else
{
} else {
// Need to encrypt the database
if (!execNow("ATTACH DATABASE '"+path+".tmp' AS encrypted KEY \"x'"+newHexKey+"'\";"
if (!execNow("ATTACH DATABASE '" + path + ".tmp' AS encrypted KEY \"x'" + newHexKey
+ "'\";"
"SELECT sqlcipher_export('encrypted');"
"DETACH DATABASE encrypted;"))
{
"DETACH DATABASE encrypted;")) {
qWarning() << "Failed to export encrypted database";
close();
return false;
}
// This is racy as hell, but nobody will race with us since we hold the profile lock
// If we crash or die here, the rename should be atomic, so we can recover no matter what
// If we crash or die here, the rename should be atomic, so we can recover no matter
// what
close();
QFile::remove(path);
QFile::rename(path + ".tmp", path);
currentHexKey = newHexKey;
if (!open(path, currentHexKey))
{
if (!open(path, currentHexKey)) {
qWarning() << "Failed to open encrypted database";
return false;
}
}
}
else
{
} else {
if (currentHexKey.isEmpty())
return true;
// Need to decrypt the database
if (!execNow("ATTACH DATABASE '" + path + ".tmp' AS plaintext KEY '';"
"SELECT sqlcipher_export('plaintext');"
"DETACH DATABASE plaintext;"))
{
"DETACH DATABASE plaintext;")) {
qWarning() << "Failed to export decrypted database";
close();
return false;
@ -409,8 +384,7 @@ bool RawDatabase::setPassword(const QString& password)
QFile::remove(path);
QFile::rename(path + ".tmp", path);
currentHexKey.clear();
if (!open(path))
{
if (!open(path)) {
qCritical() << "Failed to open decrypted database";
return false;
}
@ -427,14 +401,12 @@ bool RawDatabase::setPassword(const QString& password)
*/
bool RawDatabase::rename(const QString& newPath)
{
if (!sqlite)
{
if (!sqlite) {
qWarning() << "Trying to change the password, but the database is not open";
return false;
}
if (QThread::currentThread() != workerThread.get())
{
if (QThread::currentThread() != workerThread.get()) {
bool ret;
QMetaObject::invokeMethod(this, "rename", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret), Q_ARG(const QString&, newPath));
@ -463,16 +435,15 @@ bool RawDatabase::rename(const QString &newPath)
*/
bool RawDatabase::remove()
{
if (!sqlite)
{
if (!sqlite) {
qWarning() << "Trying to remove the database, but it is not open";
return false;
}
if (QThread::currentThread() != workerThread.get())
{
if (QThread::currentThread() != workerThread.get()) {
bool ret;
QMetaObject::invokeMethod(this, "remove", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, ret));
QMetaObject::invokeMethod(this, "remove", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret));
return ret;
}
@ -489,7 +460,8 @@ bool RawDatabase::remove()
*/
struct PassKeyDeleter
{
void operator()(Tox_Pass_Key *pass_key) {
void operator()(Tox_Pass_Key* pass_key)
{
tox_pass_key_free(pass_key);
}
};
@ -509,11 +481,13 @@ QString RawDatabase::deriveKey(const QString &password)
static_assert(TOX_PASS_KEY_LENGTH >= 32, "toxcore must provide 256bit or longer keys");
static const uint8_t expandConstant[TOX_PASS_SALT_LENGTH+1] = "L'ignorance est le pire des maux";
static const uint8_t expandConstant[TOX_PASS_SALT_LENGTH + 1] =
"L'ignorance est le pire des maux";
std::unique_ptr<Tox_Pass_Key, PassKeyDeleter> key(tox_pass_key_new());
tox_pass_key_derive_with_salt(key.get(), reinterpret_cast<uint8_t*>(passData.data()),
static_cast<std::size_t>(passData.size()), expandConstant, nullptr);
return QByteArray(reinterpret_cast<char*>(key.get()) + 32, 32).toHex();;
return QByteArray(reinterpret_cast<char*>(key.get()) + 32, 32).toHex();
;
}
/**
@ -524,13 +498,11 @@ QString RawDatabase::deriveKey(const QString &password)
*/
QString RawDatabase::deriveKey(const QString& password, const QByteArray& salt)
{
if (password.isEmpty())
{
if (password.isEmpty()) {
return {};
}
if (salt.length() != TOX_PASS_SALT_LENGTH)
{
if (salt.length() != TOX_PASS_SALT_LENGTH) {
qWarning() << "Salt length doesn't match toxencryptsave expections";
return {};
}
@ -543,7 +515,8 @@ QString RawDatabase::deriveKey(const QString& password, const QByteArray& salt)
tox_pass_key_derive_with_salt(key.get(), reinterpret_cast<uint8_t*>(passData.data()),
static_cast<std::size_t>(passData.size()),
reinterpret_cast<const uint8_t*>(salt.constData()), nullptr);
return QByteArray(reinterpret_cast<char*>(key.get()) + 32, 32).toHex();;
return QByteArray(reinterpret_cast<char*>(key.get()) + 32, 32).toHex();
;
}
/**
@ -575,15 +548,13 @@ void RawDatabase::process()
trans.success->store(false, std::memory_order_release);
// Add transaction commands if necessary
if (trans.queries.size() > 1)
{
if (trans.queries.size() > 1) {
trans.queries.prepend({"BEGIN;"});
trans.queries.append({"COMMIT;"});
}
// Compile queries
for (Query& query : trans.queries)
{
for (Query& query : trans.queries) {
assert(query.statements.isEmpty());
// sqlite3_prepare_v2 only compiles one statement at a time in the query,
// we need to loop over them all
@ -594,9 +565,10 @@ void RawDatabase::process()
sqlite3_stmt* stmt;
int r;
if ((r = sqlite3_prepare_v2(sqlite, compileTail,
query.query.size() - static_cast<int>(compileTail - query.query.data()),
&stmt, &compileTail)) != SQLITE_OK)
{
query.query.size()
- static_cast<int>(compileTail - query.query.data()),
&stmt, &compileTail))
!= SQLITE_OK) {
qWarning() << "Failed to prepare statement" << anonymizeQuery(query.query)
<< "with error" << r;
goto cleanupStatements;
@ -605,19 +577,17 @@ void RawDatabase::process()
// Now we can bind our params to this statement
int nParams = sqlite3_bind_parameter_count(stmt);
if (query.blobs.size() < curParam+nParams)
{
if (query.blobs.size() < curParam + nParams) {
qWarning() << "Not enough parameters to bind to query "
<< anonymizeQuery(query.query);
goto cleanupStatements;
}
for (int i=0; i<nParams; ++i)
{
for (int i = 0; i < nParams; ++i) {
const QByteArray& blob = query.blobs[curParam + i];
if (sqlite3_bind_blob(stmt, i+1, blob.data(), blob.size(), SQLITE_STATIC) != SQLITE_OK)
{
qWarning() << "Failed to bind param" << curParam + i
<< "to query" << anonymizeQuery(query.query);
if (sqlite3_bind_blob(stmt, i + 1, blob.data(), blob.size(), SQLITE_STATIC)
!= SQLITE_OK) {
qWarning() << "Failed to bind param" << curParam + i << "to query"
<< anonymizeQuery(query.query);
goto cleanupStatements;
}
}
@ -626,18 +596,15 @@ void RawDatabase::process()
}
// Execute each statement of each query of our transaction
for (Query& query : trans.queries)
{
for (sqlite3_stmt* stmt : query.statements)
{
for (Query& query : trans.queries) {
for (sqlite3_stmt* stmt : query.statements) {
int column_count = sqlite3_column_count(stmt);
int result;
do {
result = sqlite3_step(stmt);
// Execute our row callback
if (result == SQLITE_ROW && query.rowCallback)
{
if (result == SQLITE_ROW && query.rowCallback) {
QVector<QVariant> row;
for (int i = 0; i < column_count; ++i)
row += extractData(stmt, i);
@ -661,8 +628,7 @@ void RawDatabase::process()
qWarning() << "Constraint error executing query" << anonQuery;
goto cleanupStatements;
default:
qWarning() << "Unknown error" << result
<< "executing query" << anonQuery;
qWarning() << "Unknown error" << result << "executing query" << anonQuery;
goto cleanupStatements;
}
}
@ -676,8 +642,7 @@ void RawDatabase::process()
// Free our statements
cleanupStatements:
for (Query& query : trans.queries)
{
for (Query& query : trans.queries) {
for (sqlite3_stmt* stmt : query.statements)
sqlite3_finalize(stmt);
query.statements.clear();
@ -714,22 +679,15 @@ QString RawDatabase::anonymizeQuery(const QByteArray& query)
QVariant RawDatabase::extractData(sqlite3_stmt* stmt, int col)
{
int type = sqlite3_column_type(stmt, col);
if (type == SQLITE_INTEGER)
{
if (type == SQLITE_INTEGER) {
return sqlite3_column_int64(stmt, col);
}
else if (type == SQLITE_TEXT)
{
} else if (type == SQLITE_TEXT) {
const char* str = reinterpret_cast<const char*>(sqlite3_column_text(stmt, col));
int len = sqlite3_column_bytes(stmt, col);
return QString::fromUtf8(str, len);
}
else if (type == SQLITE_NULL)
{
} else if (type == SQLITE_NULL) {
return QVariant{};
}
else
{
} else {
const char* data = reinterpret_cast<const char*>(sqlite3_column_blob(stmt, col));
int len = sqlite3_column_bytes(stmt, col);
return QByteArray::fromRawData(data, len);

View File

@ -1,16 +1,16 @@
#ifndef RAWDATABASE_H
#define RAWDATABASE_H
#include <QString>
#include <QByteArray>
#include <QThread>
#include <QQueue>
#include <QVector>
#include <QPair>
#include <QMutex>
#include <QPair>
#include <QQueue>
#include <QString>
#include <QThread>
#include <QVariant>
#include <memory>
#include <QVector>
#include <atomic>
#include <memory>
struct sqlite3;
struct sqlite3_stmt;
@ -23,13 +23,25 @@ public:
class Query
{
public:
Query(QString query, QVector<QByteArray> blobs = {}, std::function<void(int64_t)> insertCallback={})
: query{query.toUtf8()}, blobs{blobs}, insertCallback{insertCallback} {}
Query(QString query, QVector<QByteArray> blobs = {},
std::function<void(int64_t)> insertCallback = {})
: query{query.toUtf8()}
, blobs{blobs}
, insertCallback{insertCallback}
{
}
Query(QString query, std::function<void(int64_t)> insertCallback)
: query{query.toUtf8()}, insertCallback{insertCallback} {}
: query{query.toUtf8()}
, insertCallback{insertCallback}
{
}
Query(QString query, std::function<void(const QVector<QVariant>&)> rowCallback)
: query{query.toUtf8()}, rowCallback{rowCallback} {}
: query{query.toUtf8()}
, rowCallback{rowCallback}
{
}
Query() = default;
private:
QByteArray query;
QVector<QByteArray> blobs;
@ -64,6 +76,7 @@ protected slots:
bool open(const QString& path, const QString& hexKey = {});
void close();
void process();
private:
QString anonymizeQuery(const QByteArray& query);

View File

@ -20,10 +20,10 @@
#include <QDebug>
#include <cassert>
#include "db/rawdatabase.h"
#include "history.h"
#include "profile.h"
#include "settings.h"
#include "db/rawdatabase.h"
/**
* @class History
@ -41,13 +41,14 @@
History::History(std::shared_ptr<RawDatabase> db)
: db(db)
{
if (!isValid())
{
if (!isValid()) {
qWarning() << "Database not open, init failed";
return;
}
db->execLater("CREATE TABLE IF NOT EXISTS peers (id INTEGER PRIMARY KEY, public_key TEXT NOT NULL UNIQUE);"
db->execLater(
"CREATE TABLE IF NOT EXISTS peers (id INTEGER PRIMARY KEY, public_key TEXT NOT NULL "
"UNIQUE);"
"CREATE TABLE IF NOT EXISTS aliases (id INTEGER PRIMARY KEY, owner INTEGER,"
"display_name BLOB NOT NULL, UNIQUE(owner, display_name));"
"CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY, timestamp INTEGER NOT NULL, "
@ -56,16 +57,15 @@ History::History(std::shared_ptr<RawDatabase> db)
"CREATE TABLE IF NOT EXISTS faux_offline_pending (id INTEGER PRIMARY KEY);");
// Cache our current peers
db->execLater(RawDatabase::Query{"SELECT public_key, id FROM peers;", [this](const QVector<QVariant>& row)
{
db->execLater(RawDatabase::Query{"SELECT public_key, id FROM peers;",
[this](const QVector<QVariant>& row) {
peers[row[0].toString()] = row[1].toInt();
}});
}
History::~History()
{
if (!isValid())
{
if (!isValid()) {
return;
}
@ -88,8 +88,7 @@ bool History::isValid()
*/
void History::eraseHistory()
{
if (!isValid())
{
if (!isValid()) {
return;
}
@ -106,20 +105,17 @@ void History::eraseHistory()
*/
void History::removeFriendHistory(const QString& friendPk)
{
if (!isValid())
{
if (!isValid()) {
return;
}
if (!peers.contains(friendPk))
{
if (!peers.contains(friendPk)) {
return;
}
int64_t id = peers[friendPk];
QString queryText = QString(
"DELETE FROM faux_offline_pending "
QString queryText = QString("DELETE FROM faux_offline_pending "
"WHERE faux_offline_pending.id IN ( "
" SELECT faux_offline_pending.id FROM faux_offline_pending "
" LEFT JOIN history ON faux_offline_pending.id = history.id "
@ -128,14 +124,12 @@ void History::removeFriendHistory(const QString& friendPk)
"DELETE FROM history WHERE chat_id=%1; "
"DELETE FROM aliases WHERE owner=%1; "
"DELETE FROM peers WHERE id=%1; "
"VACUUM;").arg(id);
"VACUUM;")
.arg(id);
if (db->execNow(queryText))
{
if (db->execNow(queryText)) {
peers.remove(friendPk);
}
else
{
} else {
qWarning() << "Failed to remove friend's history";
}
}
@ -150,76 +144,71 @@ void History::removeFriendHistory(const QString& friendPk)
* @param dispName Name, which should be displayed.
* @param insertIdCallback Function, called after query execution.
*/
QVector<RawDatabase::Query> History::generateNewMessageQueries(const QString& friendPk, const QString& message,
const QString& sender, const QDateTime& time, bool isSent, QString dispName,
std::function<void(int64_t)> insertIdCallback)
QVector<RawDatabase::Query>
History::generateNewMessageQueries(const QString& friendPk, const QString& message,
const QString& sender, const QDateTime& time, bool isSent,
QString dispName, std::function<void(int64_t)> insertIdCallback)
{
QVector<RawDatabase::Query> queries;
// Get the db id of the peer we're chatting with
int64_t peerId;
if (peers.contains(friendPk))
{
if (peers.contains(friendPk)) {
peerId = peers[friendPk];
}
else
{
if (peers.isEmpty())
{
} else {
if (peers.isEmpty()) {
peerId = 0;
}
else
{
} else {
peerId = *std::max_element(peers.begin(), peers.end()) + 1;
}
peers[friendPk] = peerId;
queries += RawDatabase::Query(("INSERT INTO peers (id, public_key) "
"VALUES (%1, '" + friendPk + "');")
"VALUES (%1, '"
+ friendPk + "');")
.arg(peerId));
}
// Get the db id of the sender of the message
int64_t senderId;
if (peers.contains(sender))
{
if (peers.contains(sender)) {
senderId = peers[sender];
}
else
{
if (peers.isEmpty())
{
} else {
if (peers.isEmpty()) {
senderId = 0;
}
else
{
} else {
senderId = *std::max_element(peers.begin(), peers.end()) + 1;
}
peers[sender] = senderId;
queries += RawDatabase::Query{("INSERT INTO peers (id, public_key) "
"VALUES (%1, '" + sender + "');")
"VALUES (%1, '"
+ sender + "');")
.arg(senderId)};
}
queries += RawDatabase::Query(QString("INSERT OR IGNORE INTO aliases (owner, display_name) VALUES (%1, ?);")
.arg(senderId), {dispName.toUtf8()});
queries += RawDatabase::Query(
QString("INSERT OR IGNORE INTO aliases (owner, display_name) VALUES (%1, ?);").arg(senderId),
{dispName.toUtf8()});
// If the alias already existed, the insert will ignore the conflict and last_insert_rowid() will return garbage,
// If the alias already existed, the insert will ignore the conflict and last_insert_rowid()
// will return garbage,
// so we have to check changes() and manually fetch the row ID in this case
queries += RawDatabase::Query(QString("INSERT INTO history (timestamp, chat_id, message, sender_alias) "
queries +=
RawDatabase::Query(QString(
"INSERT INTO history (timestamp, chat_id, message, sender_alias) "
"VALUES (%1, %2, ?, ("
" CASE WHEN changes() IS 0 THEN ("
" SELECT id FROM aliases WHERE owner=%3 AND display_name=?)"
" ELSE last_insert_rowid() END"
"));")
.arg(time.toMSecsSinceEpoch()).arg(peerId).arg(senderId),
.arg(time.toMSecsSinceEpoch())
.arg(peerId)
.arg(senderId),
{message.toUtf8(), dispName.toUtf8()}, insertIdCallback);
if (!isSent)
{
queries += RawDatabase::Query{
"INSERT INTO faux_offline_pending (id) VALUES ("
if (!isSent) {
queries += RawDatabase::Query{"INSERT INTO faux_offline_pending (id) VALUES ("
" last_insert_rowid()"
");"};
}
@ -237,18 +226,16 @@ QVector<RawDatabase::Query> History::generateNewMessageQueries(const QString& fr
* @param dispName Name, which should be displayed.
* @param insertIdCallback Function, called after query execution.
*/
void History::addNewMessage(const QString& friendPk, const QString& message,
const QString& sender, const QDateTime& time,
bool isSent, QString dispName,
void History::addNewMessage(const QString& friendPk, const QString& message, const QString& sender,
const QDateTime& time, bool isSent, QString dispName,
std::function<void(int64_t)> insertIdCallback)
{
if (!isValid())
{
if (!isValid()) {
return;
}
db->execLater(generateNewMessageQueries(friendPk, message, sender, time,
isSent, dispName, insertIdCallback));
db->execLater(generateNewMessageQueries(friendPk, message, sender, time, isSent, dispName,
insertIdCallback));
}
/**
@ -258,19 +245,16 @@ void History::addNewMessage(const QString& friendPk, const QString& message,
* @param to End of period to fetch.
* @return List of messages.
*/
QList<History::HistMessage> History::getChatHistory(const QString& friendPk,
const QDateTime& from,
QList<History::HistMessage> History::getChatHistory(const QString& friendPk, const QDateTime& from,
const QDateTime& to)
{
if (!isValid())
{
if (!isValid()) {
return {};
}
QList<HistMessage> messages;
auto rowCallback = [&messages](const QVector<QVariant>& row)
{
auto rowCallback = [&messages](const QVector<QVariant>& row) {
// dispName and message could have null bytes, QString::fromUtf8
// truncates on null bytes so we strip them
messages += {row[0].toLongLong(),
@ -283,8 +267,8 @@ QList<History::HistMessage> History::getChatHistory(const QString& friendPk,
};
// Don't forget to update the rowCallback if you change the selected columns!
QString queryText = QString(
"SELECT history.id, faux_offline_pending.id, timestamp, "
QString queryText =
QString("SELECT history.id, faux_offline_pending.id, timestamp, "
"chat.public_key, aliases.display_name, sender.public_key, "
"message FROM history "
"LEFT JOIN faux_offline_pending ON history.id = faux_offline_pending.id "
@ -292,7 +276,9 @@ QList<History::HistMessage> History::getChatHistory(const QString& friendPk,
"JOIN aliases ON sender_alias = aliases.id "
"JOIN peers sender ON aliases.owner = sender.id "
"WHERE timestamp BETWEEN %1 AND %2 AND chat.public_key='%3';")
.arg(from.toMSecsSinceEpoch()).arg(to.toMSecsSinceEpoch()).arg(friendPk);
.arg(from.toMSecsSinceEpoch())
.arg(to.toMSecsSinceEpoch())
.arg(friendPk);
db->execNow({queryText, rowCallback});
@ -307,11 +293,9 @@ QList<History::HistMessage> History::getChatHistory(const QString& friendPk,
*/
void History::markAsSent(qint64 messageId)
{
if (!isValid())
{
if (!isValid()) {
return;
}
db->execLater(QString("DELETE FROM faux_offline_pending WHERE id=%1;")
.arg(messageId));
db->execLater(QString("DELETE FROM faux_offline_pending WHERE id=%1;").arg(messageId));
}

View File

@ -21,8 +21,8 @@
#define HISTORY_H
#include <QDateTime>
#include <QVector>
#include <QHash>
#include <QVector>
#include <cstdint>
#include <tox/toxencryptsave.h>
@ -37,10 +37,15 @@ class History
public:
struct HistMessage
{
HistMessage(qint64 id, bool isSent, QDateTime timestamp, QString chat,
QString dispName, QString sender, QString message)
: chat{chat}, sender{sender}, message{message}, dispName{dispName}
, timestamp{timestamp}, id{id}, isSent{isSent}
HistMessage(qint64 id, bool isSent, QDateTime timestamp, QString chat, QString dispName,
QString sender, QString message)
: chat{chat}
, sender{sender}
, message{message}
, dispName{dispName}
, timestamp{timestamp}
, id{id}
, isSent{isSent}
{
}
@ -62,21 +67,19 @@ public:
void eraseHistory();
void removeFriendHistory(const QString& friendPk);
void addNewMessage(const QString& friendPk, const QString& message,
const QString& sender, const QDateTime& time,
bool isSent, QString dispName,
void addNewMessage(const QString& friendPk, const QString& message, const QString& sender,
const QDateTime& time, bool isSent, QString dispName,
std::function<void(int64_t)> insertIdCallback = {});
QList<HistMessage> getChatHistory(const QString& friendPk,
const QDateTime& from,
QList<HistMessage> getChatHistory(const QString& friendPk, const QDateTime& from,
const QDateTime& to);
void markAsSent(qint64 messageId);
protected:
QVector<RawDatabase::Query> generateNewMessageQueries(
const QString& friendPk, const QString& message,
const QString& sender, const QDateTime& time,
bool isSent, QString dispName,
std::function<void(int64_t)> insertIdCallback={});
QVector<RawDatabase::Query>
generateNewMessageQueries(const QString& friendPk, const QString& message,
const QString& sender, const QDateTime& time, bool isSent,
QString dispName, std::function<void(int64_t)> insertIdCallback = {});
private:
std::shared_ptr<RawDatabase> db;

View File

@ -18,11 +18,11 @@
*/
#include "offlinemsgengine.h"
#include "src/friend.h"
#include "src/persistence/settings.h"
#include "src/core/core.h"
#include "src/friend.h"
#include "src/nexus.h"
#include "src/persistence/profile.h"
#include "src/persistence/settings.h"
#include <QMutexLocker>
#include <QTimer>
@ -38,9 +38,9 @@
const int OfflineMsgEngine::offlineTimeout = 20000;
QMutex OfflineMsgEngine::globalMutex;
OfflineMsgEngine::OfflineMsgEngine(Friend* frnd) :
mutex(QMutex::Recursive),
f(frnd)
OfflineMsgEngine::OfflineMsgEngine(Friend* frnd)
: mutex(QMutex::Recursive)
, f(frnd)
{
}
@ -54,12 +54,10 @@ void OfflineMsgEngine::dischargeReceipt(int receipt)
Profile* profile = Nexus::getProfile();
auto it = receipts.find(receipt);
if (it != receipts.end())
{
if (it != receipts.end()) {
int mID = it.value();
auto msgIt = undeliveredMsgs.find(mID);
if (msgIt != undeliveredMsgs.end())
{
if (msgIt != undeliveredMsgs.end()) {
if (profile->isHistoryEnabled())
profile->getHistory()->markAsSent(mID);
msgIt.value().msg->markAsSent(QDateTime::currentDateTime());
@ -69,7 +67,8 @@ void OfflineMsgEngine::dischargeReceipt(int receipt)
}
}
void OfflineMsgEngine::registerReceipt(int receipt, int64_t messageID, ChatMessage::Ptr msg, const QDateTime &timestamp)
void OfflineMsgEngine::registerReceipt(int receipt, int64_t messageID, ChatMessage::Ptr msg,
const QDateTime& timestamp)
{
QMutexLocker ml(&mutex);
@ -94,24 +93,19 @@ void OfflineMsgEngine::deliverOfflineMsgs()
removeAllReceipts();
undeliveredMsgs.clear();
for (auto iter = msgs.begin(); iter != msgs.end(); ++iter)
{
for (auto iter = msgs.begin(); iter != msgs.end(); ++iter) {
auto val = iter.value();
auto key = iter.key();
if (val.timestamp.msecsTo(QDateTime::currentDateTime()) < offlineTimeout)
{
if (val.timestamp.msecsTo(QDateTime::currentDateTime()) < offlineTimeout) {
registerReceipt(val.receipt, key, val.msg, val.timestamp);
continue;
}
QString messageText = val.msg->toString();
int rec;
if (val.msg->isAction())
{
if (val.msg->isAction()) {
rec = Core::getInstance()->sendAction(f->getFriendId(), messageText);
}
else
{
} else {
rec = Core::getInstance()->sendMessage(f->getFriendId(), messageText);
}

View File

@ -20,12 +20,12 @@
#ifndef OFFLINEMSGENGINE_H
#define OFFLINEMSGENGINE_H
#include <QObject>
#include <QSet>
#include <QMutex>
#include "src/chatlog/chatmessage.h"
#include <QDateTime>
#include <QMap>
#include "src/chatlog/chatmessage.h"
#include <QMutex>
#include <QObject>
#include <QSet>
class Friend;
class QTimer;
@ -39,14 +39,16 @@ public:
static QMutex globalMutex;
void dischargeReceipt(int receipt);
void registerReceipt(int receipt, int64_t messageID, ChatMessage::Ptr msg, const QDateTime &timestamp = QDateTime::currentDateTime());
void registerReceipt(int receipt, int64_t messageID, ChatMessage::Ptr msg,
const QDateTime& timestamp = QDateTime::currentDateTime());
public slots:
void deliverOfflineMsgs();
void removeAllReceipts();
private:
struct MsgPtr {
struct MsgPtr
{
ChatMessage::Ptr msg;
QDateTime timestamp;
int receipt;

View File

@ -50,8 +50,10 @@
QVector<QString> Profile::profiles;
Profile::Profile(QString name, const QString& password, bool isNewProfile)
: name{name}, password{password}
, newProfile{isNewProfile}, isRemoved{false}
: name{name}
, password{password}
, newProfile{isNewProfile}
, isRemoved{false}
{
Settings& s = Settings::getInstance();
s.setCurrentProfile(name);
@ -75,14 +77,13 @@ Profile::Profile(QString name, const QString& password, bool isNewProfile)
*/
Profile* Profile::loadProfile(QString name, const QString& password)
{
if (ProfileLocker::hasLock())
{
qCritical() << "Tried to load profile "<<name<<", but another profile is already locked!";
if (ProfileLocker::hasLock()) {
qCritical() << "Tried to load profile " << name
<< ", but another profile is already locked!";
return nullptr;
}
if (!ProfileLocker::lock(name))
{
if (!ProfileLocker::lock(name)) {
qWarning() << "Failed to lock profile " << name;
return nullptr;
}
@ -95,58 +96,48 @@ Profile* Profile::loadProfile(QString name, const QString& password)
QFile saveFile(path);
qDebug() << "Loading tox save " << path;
if (!saveFile.exists())
{
if (!saveFile.exists()) {
qWarning() << "The tox save file " << path << " was not found";
ProfileLocker::unlock();
return nullptr;
}
if (!saveFile.open(QIODevice::ReadOnly))
{
if (!saveFile.open(QIODevice::ReadOnly)) {
qCritical() << "The tox save file " << path << " couldn't' be opened";
ProfileLocker::unlock();
return nullptr;
}
qint64 fileSize = saveFile.size();
if (fileSize <= 0)
{
if (fileSize <= 0) {
qWarning() << "The tox save file" << path << " is empty!";
ProfileLocker::unlock();
return nullptr;
}
QByteArray data = saveFile.readAll();
if (ToxEncrypt::isEncrypted(data))
{
if (password.isEmpty())
{
if (ToxEncrypt::isEncrypted(data)) {
if (password.isEmpty()) {
qCritical() << "The tox save file is encrypted, but we don't have a password!";
ProfileLocker::unlock();
return nullptr;
}
tmpKey = ToxEncrypt::makeToxEncrypt(password, data);
if (!tmpKey)
{
if (!tmpKey) {
qCritical() << "Failed to derive key of the tox save file";
ProfileLocker::unlock();
return nullptr;
}
data = tmpKey->decrypt(data);
if (data.isEmpty())
{
if (data.isEmpty()) {
qCritical() << "Failed to decrypt the tox save file";
ProfileLocker::unlock();
return nullptr;
}
}
else
{
if (!password.isEmpty())
{
} else {
if (!password.isEmpty()) {
qWarning() << "We have a password, but the tox save file is not encrypted";
}
}
@ -169,30 +160,26 @@ Profile* Profile::loadProfile(QString name, const QString& password)
Profile* Profile::createProfile(QString name, QString password)
{
std::unique_ptr<ToxEncrypt> tmpKey;
if(!password.isEmpty())
{
if (!password.isEmpty()) {
tmpKey = ToxEncrypt::makeToxEncrypt(password);
if (!tmpKey)
{
if (!tmpKey) {
qCritical() << "Failed to derive key for the tox save";
return nullptr;
}
}
if (ProfileLocker::hasLock())
{
qCritical() << "Tried to create profile "<<name<<", but another profile is already locked!";
if (ProfileLocker::hasLock()) {
qCritical() << "Tried to create profile " << name
<< ", but another profile is already locked!";
return nullptr;
}
if (exists(name))
{
if (exists(name)) {
qCritical() << "Tried to create profile " << name << ", but it already exists!";
return nullptr;
}
if (!ProfileLocker::lock(name))
{
if (!ProfileLocker::lock(name)) {
qWarning() << "Failed to lock profile " << name;
return nullptr;
}
@ -206,8 +193,7 @@ Profile* Profile::createProfile(QString name, QString password)
Profile::~Profile()
{
if (!isRemoved && core->isReady())
{
if (!isRemoved && core->isReady()) {
saveToxSave();
}
@ -216,8 +202,7 @@ Profile::~Profile()
qApp->processEvents();
delete coreThread;
if (!isRemoved)
{
if (!isRemoved) {
Settings::getInstance().savePersonal(this);
Settings::getInstance().sync();
ProfileLocker::assertLock();
@ -239,8 +224,7 @@ QVector<QString> Profile::getFilesByExt(QString extension)
dir.setNameFilters(QStringList("*." + extension));
QFileInfoList list = dir.entryInfoList();
out.reserve(list.size());
for (QFileInfo file : list)
{
for (QFileInfo file : list) {
out += file.completeBaseName();
}
@ -255,10 +239,8 @@ void Profile::scanProfiles()
{
profiles.clear();
QVector<QString> toxfiles = getFilesByExt("tox"), inifiles = getFilesByExt("ini");
for (QString toxfile : toxfiles)
{
if (!inifiles.contains(toxfile))
{
for (QString toxfile : toxfiles) {
if (!inifiles.contains(toxfile)) {
Settings::getInstance().createPersonal(toxfile);
}
@ -308,47 +290,38 @@ QByteArray Profile::loadToxSave()
qint64 fileSize;
qDebug() << "Loading tox save " << path;
if (!saveFile.exists())
{
if (!saveFile.exists()) {
qWarning() << "The tox save file " << path << " was not found";
goto fail;
}
if (!saveFile.open(QIODevice::ReadOnly))
{
if (!saveFile.open(QIODevice::ReadOnly)) {
qCritical() << "The tox save file " << path << " couldn't' be opened";
goto fail;
}
fileSize = saveFile.size();
if (fileSize <= 0)
{
if (fileSize <= 0) {
qWarning() << "The tox save file" << path << " is empty!";
goto fail;
}
data = saveFile.readAll();
if (ToxEncrypt::isEncrypted(data))
{
if (password.isEmpty())
{
if (ToxEncrypt::isEncrypted(data)) {
if (password.isEmpty()) {
qCritical() << "The tox save file is encrypted, but we don't have a password!";
data.clear();
goto fail;
}
data = passkey->decrypt(data);
if (data.isEmpty())
{
if (data.isEmpty()) {
qCritical() << "Failed to decrypt the tox save file";
data.clear();
goto fail;
}
}
else
{
if (!password.isEmpty())
{
} else {
if (!password.isEmpty()) {
qWarning() << "We have a password, but the tox save file is not encrypted";
}
}
@ -384,17 +357,14 @@ void Profile::saveToxSave(QByteArray data)
QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox";
qDebug() << "Saving tox save to " << path;
QSaveFile saveFile(path);
if (!saveFile.open(QIODevice::WriteOnly))
{
if (!saveFile.open(QIODevice::WriteOnly)) {
qCritical() << "Tox save file " << path << " couldn't be opened";
return;
}
if (!password.isEmpty())
{
if (!password.isEmpty()) {
data = passkey->encrypt(data);
if (data.isEmpty())
{
if (data.isEmpty()) {
qCritical() << "Failed to encrypt, can't save!";
saveFile.cancelWriting();
return;
@ -404,22 +374,21 @@ void Profile::saveToxSave(QByteArray data)
saveFile.write(data);
// check if everything got written
if (saveFile.flush())
{
if (saveFile.flush()) {
saveFile.commit();
newProfile = false;
}
else
{
} else {
saveFile.cancelWriting();
qCritical() << "Failed to write, can't save!";
}
}
/**
* @brief Gets the path of the avatar file cached by this profile and corresponding to this owner ID.
* @brief Gets the path of the avatar file cached by this profile and corresponding to this owner
* ID.
* @param ownerId Path to avatar of friend with this ID will returned.
* @param forceUnencrypted If true, return the path to the plaintext file even if this is an encrypted profile.
* @param forceUnencrypted If true, return the path to the plaintext file even if this is an
* encrypted profile.
* @return Path to the avatar.
*/
QString Profile::avatarPath(const QString& ownerId, bool forceUnencrypted)
@ -430,13 +399,16 @@ QString Profile::avatarPath(const QString& ownerId, bool forceUnencrypted)
QByteArray idData = ownerId.toUtf8();
QByteArray pubkeyData = core->getSelfId().getPublicKey().getKey();
constexpr int hashSize = TOX_PUBLIC_KEY_SIZE;
static_assert(hashSize >= crypto_generichash_BYTES_MIN
&& hashSize <= crypto_generichash_BYTES_MAX, "Hash size not supported by libsodium");
static_assert(hashSize >= crypto_generichash_BYTES_MIN && hashSize <= crypto_generichash_BYTES_MAX,
"Hash size not supported by libsodium");
static_assert(hashSize >= crypto_generichash_KEYBYTES_MIN
&& hashSize <= crypto_generichash_KEYBYTES_MAX, "Key size not supported by libsodium");
&& hashSize <= crypto_generichash_KEYBYTES_MAX,
"Key size not supported by libsodium");
QByteArray hash(hashSize, 0);
crypto_generichash((uint8_t*)hash.data(), hashSize, (uint8_t*)idData.data(), idData.size(), (uint8_t*)pubkeyData.data(), pubkeyData.size());
return Settings::getInstance().getSettingsDirPath() + "avatars/" + hash.toHex().toUpper() + ".png";
crypto_generichash((uint8_t*)hash.data(), hashSize, (uint8_t*)idData.data(), idData.size(),
(uint8_t*)pubkeyData.data(), pubkeyData.size());
return Settings::getInstance().getSettingsDirPath() + "avatars/" + hash.toHex().toUpper()
+ ".png";
}
/**
@ -482,21 +454,18 @@ QByteArray Profile::loadAvatarData(const QString& ownerId, const QString& passwo
bool encrypted = !password.isEmpty();
// If the encrypted avatar isn't found, try loading the unencrypted one for the same ID
if (!password.isEmpty() && !QFile::exists(path))
{
if (!password.isEmpty() && !QFile::exists(path)) {
encrypted = false;
path = avatarPath(ownerId, true);
}
QFile file(path);
if (!file.open(QIODevice::ReadOnly))
{
if (!file.open(QIODevice::ReadOnly)) {
return {};
}
QByteArray pic = file.readAll();
if (encrypted && !pic.isEmpty())
{
if (encrypted && !pic.isEmpty()) {
// TODO: check if we can use passkey-decrypt(pic) here
pic = ToxEncrypt::decryptPass(password, pic);
}
@ -506,29 +475,27 @@ QByteArray Profile::loadAvatarData(const QString& ownerId, const QString& passwo
void Profile::loadDatabase(const ToxId& id)
{
if(isRemoved)
{
if (isRemoved) {
qDebug() << "Can't load database of removed profile";
return;
}
QByteArray salt = id.getPublicKey().getKey();
if(salt.size() != TOX_PASS_SALT_LENGTH)
{
if (salt.size() != TOX_PASS_SALT_LENGTH) {
qWarning() << "Couldn't compute salt from public key" << name;
GUI::showError(QObject::tr("Error"), QObject::tr("qTox couldn't open your chat logs, they will be disabled."));
GUI::showError(QObject::tr("Error"),
QObject::tr("qTox couldn't open your chat logs, they will be disabled."));
}
// At this point it's too early to load the personal settings (Nexus will do it), so we always load
// At this point it's too early to load the personal settings (Nexus will do it), so we always
// load
// the history, and if it fails we can't change the setting now, but we keep a nullptr
database = std::make_shared<RawDatabase>(getDbPath(name), password, salt);
if (database && database->isOpen())
{
if (database && database->isOpen()) {
history.reset(new History(database));
}
else
{
} else {
qWarning() << "Failed to open database for profile" << name;
GUI::showError(QObject::tr("Error"), QObject::tr("qTox couldn't open your chat logs, they will be disabled."));
GUI::showError(QObject::tr("Error"),
QObject::tr("qTox couldn't open your chat logs, they will be disabled."));
}
}
@ -539,22 +506,17 @@ void Profile::loadDatabase(const ToxId& id)
*/
void Profile::saveAvatar(QByteArray pic, const QString& ownerId)
{
if (!password.isEmpty() && !pic.isEmpty())
{
if (!password.isEmpty() && !pic.isEmpty()) {
pic = passkey->encrypt(pic);
}
QString path = avatarPath(ownerId);
QDir(Settings::getInstance().getSettingsDirPath()).mkdir("avatars");
if (pic.isEmpty())
{
if (pic.isEmpty()) {
QFile::remove(path);
}
else
{
} else {
QSaveFile file(path);
if (!file.open(QIODevice::WriteOnly))
{
if (!file.open(QIODevice::WriteOnly)) {
qWarning() << "Tox avatar " << path << " couldn't be saved";
return;
}
@ -585,7 +547,8 @@ void Profile::removeAvatar()
}
/**
* @brief Checks that the history is enabled in the settings, and loaded successfully for this profile.
* @brief Checks that the history is enabled in the settings, and loaded successfully for this
* profile.
* @return True if enabled, false otherwise.
*/
bool Profile::isHistoryEnabled()
@ -639,8 +602,7 @@ bool Profile::isEncrypted(QString name)
uint8_t data[TOX_PASS_ENCRYPTION_EXTRA_LENGTH] = {0};
QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox";
QFile saveFile(path);
if (!saveFile.open(QIODevice::ReadOnly))
{
if (!saveFile.open(QIODevice::ReadOnly)) {
qWarning() << "Couldn't open tox save " << path;
return false;
}
@ -659,18 +621,15 @@ bool Profile::isEncrypted(QString name)
*/
QVector<QString> Profile::remove()
{
if (isRemoved)
{
if (isRemoved) {
qWarning() << "Profile " << name << " is already removed!";
return {};
}
isRemoved = true;
qDebug() << "Removing profile" << name;
for (int i=0; i<profiles.size(); ++i)
{
if (profiles[i] == name)
{
for (int i = 0; i < profiles.size(); ++i) {
if (profiles[i] == name) {
profiles.removeAt(i);
i--;
}
@ -683,20 +642,17 @@ QVector<QString> Profile::remove()
QVector<QString> ret;
if (!profileMain.remove() && profileMain.exists())
{
if (!profileMain.remove() && profileMain.exists()) {
ret.push_back(profileMain.fileName());
qWarning() << "Could not remove file " << profileMain.fileName();
}
if (!profileConfig.remove() && profileConfig.exists())
{
if (!profileConfig.remove() && profileConfig.exists()) {
ret.push_back(profileConfig.fileName());
qWarning() << "Could not remove file " << profileConfig.fileName();
}
QString dbPath = getDbPath(name);
if (database && database->isOpen() && !database->remove() && QFile::exists(dbPath))
{
if (database && database->isOpen() && !database->remove() && QFile::exists(dbPath)) {
ret.push_back(dbPath);
qWarning() << "Could not remove file " << dbPath;
}
@ -717,23 +673,20 @@ bool Profile::rename(QString newName)
QString path = Settings::getInstance().getSettingsDirPath() + name,
newPath = Settings::getInstance().getSettingsDirPath() + newName;
if (!ProfileLocker::lock(newName))
{
if (!ProfileLocker::lock(newName)) {
return false;
}
QFile::rename(path + ".tox", newPath + ".tox");
QFile::rename(path + ".ini", newPath + ".ini");
if (database)
{
if (database) {
database->rename(newName);
}
bool resetAutorun = Settings::getInstance().getAutorun();
Settings::getInstance().setAutorun(false);
Settings::getInstance().setCurrentProfile(newName);
if (resetAutorun)
{
if (resetAutorun) {
Settings::getInstance().setAutorun(true); // fixes -p flag in autostart command line
}
@ -747,8 +700,7 @@ bool Profile::rename(QString newName)
*/
bool Profile::checkPassword()
{
if (isRemoved)
{
if (isRemoved) {
return false;
}
@ -771,8 +723,7 @@ const ToxEncrypt& Profile::getPasskey() const
void Profile::restartCore()
{
GUI::setEnabled(false); // Core::reset re-enables it
if (!isRemoved && core->isReady())
{
if (!isRemoved && core->isReady()) {
saveToxSave();
}
@ -790,8 +741,7 @@ void Profile::setPassword(const QString& newPassword)
std::unique_ptr<ToxEncrypt> oldpasskey = std::move(passkey);
password = newPassword;
passkey = ToxEncrypt::makeToxEncrypt(password);
if(!passkey)
{
if (!passkey) {
qCritical() << "Failed to derive key from password, the profile won't use the new password";
password = oldPassword;
passkey = std::move(oldpasskey);
@ -800,8 +750,7 @@ void Profile::setPassword(const QString& newPassword)
saveToxSave();
// TODO: ensure the database and the tox save file use the same password
if (database)
{
if (database) {
database->setPassword(newPassword);
}
@ -810,8 +759,7 @@ void Profile::setPassword(const QString& newPassword)
QVector<uint32_t> friendList = core->getFriendList();
QVectorIterator<uint32_t> i(friendList);
while (i.hasNext())
{
while (i.hasNext()) {
QString friendPublicKey = core->getFriendPublicKey(i.next()).toString();
saveAvatar(loadAvatarData(friendPublicKey, oldPassword), friendPublicKey);
}

View File

@ -21,17 +21,17 @@
#ifndef PROFILE_H
#define PROFILE_H
#include "src/core/toxid.h"
#include "src/core/toxencrypt.h"
#include "src/core/toxid.h"
#include "src/persistence/history.h"
#include <memory>
#include <QByteArray>
#include <QObject>
#include <QPixmap>
#include <QString>
#include <QVector>
#include <memory>
class Core;
class QThread;
@ -86,6 +86,7 @@ public:
private slots:
void loadDatabase(const ToxId& id);
private:
Profile(QString name, const QString& password, bool newProfile);
static QVector<QString> getFilesByExt(QString extension);

View File

@ -20,8 +20,8 @@
#include "profilelocker.h"
#include "src/persistence/settings.h"
#include <QDir>
#include <QDebug>
#include <QDir>
/**
* @class ProfileLocker
@ -71,8 +71,7 @@ bool ProfileLocker::lock(QString profile)
QLockFile* newLock = new QLockFile(lockPathFromName(profile));
newLock->setStaleLockTime(0);
if (!newLock->tryLock())
{
if (!newLock->tryLock()) {
delete newLock;
return false;
}
@ -105,22 +104,17 @@ void ProfileLocker::unlock()
*/
void ProfileLocker::assertLock()
{
if (!lockfile)
{
if (!lockfile) {
qCritical() << "assertLock: We don't seem to own any lock!";
deathByBrokenLock();
}
if (!QFile(lockPathFromName(curLockName)).exists())
{
if (!QFile(lockPathFromName(curLockName)).exists()) {
QString tmp = curLockName;
unlock();
if (lock(tmp))
{
if (lock(tmp)) {
qCritical() << "assertLock: Lock file was lost, but could be restored";
}
else
{
} else {
qCritical() << "assertLock: Lock file was lost, and could *NOT* be restored";
deathByBrokenLock();
}

View File

@ -31,8 +31,7 @@ QString dataToString(QByteArray data)
int strlen = 0;
int num2 = 0;
int i = 0;
do
{
do {
num3 = data[i++];
strlen |= (num3 & 0x7f) << num2;
num2 += 7;
@ -50,14 +49,10 @@ QString dataToString(QByteArray data)
uint64_t dataToUint64(const QByteArray& data)
{
return static_cast<uint64_t>(data[0])
| (static_cast<uint64_t>(data[1]) << 8)
| (static_cast<uint64_t>(data[2]) << 16)
| (static_cast<uint64_t>(data[3]) << 24)
| (static_cast<uint64_t>(data[4]) << 32)
| (static_cast<uint64_t>(data[5]) << 40)
| (static_cast<uint64_t>(data[6]) << 48)
| (static_cast<uint64_t>(data[7]) << 56);
return static_cast<uint64_t>(data[0]) | (static_cast<uint64_t>(data[1]) << 8)
| (static_cast<uint64_t>(data[2]) << 16) | (static_cast<uint64_t>(data[3]) << 24)
| (static_cast<uint64_t>(data[4]) << 32) | (static_cast<uint64_t>(data[5]) << 40)
| (static_cast<uint64_t>(data[6]) << 48) | (static_cast<uint64_t>(data[7]) << 56);
}
int dataToVInt(const QByteArray& data)
@ -66,8 +61,7 @@ int dataToVInt(const QByteArray& data)
int num = 0;
int num2 = 0;
int i = 0;
do
{
do {
num3 = data[i++];
num |= static_cast<int>(num3 & 0x7f) << num2;
num2 += 7;
@ -81,8 +75,7 @@ size_t dataToVUint(const QByteArray& data)
size_t num = 0;
int num2 = 0;
int i = 0;
do
{
do {
num3 = data[i++];
num |= static_cast<size_t>(num3 & 0x7f) << num2;
num2 += 7;
@ -108,8 +101,7 @@ QByteArray vintToData(int num)
QByteArray data(sizeof(int), 0);
// Write the size in a Uint of variable lenght (8-32 bits)
int i = 0;
while (num >= 0x80)
{
while (num >= 0x80) {
data[i] = static_cast<char>(num | 0x80);
++i;
num = num >> 7;
@ -124,8 +116,7 @@ QByteArray vuintToData(size_t num)
QByteArray data(sizeof(size_t), 0);
// Write the size in a Uint of variable lenght (8-32 bits)
int i = 0;
while (num >= 0x80)
{
while (num >= 0x80) {
data[i] = static_cast<char>(num | 0x80);
++i;
num = num >> 7;

View File

@ -21,9 +21,9 @@
#ifndef SERIALIZE_H
#define SERIALIZE_H
#include <cstdint>
#include <QByteArray>
#include <QString>
#include <cstdint>
QString dataToString(QByteArray data);
uint64_t dataToUint64(const QByteArray& data);

File diff suppressed because it is too large Load Diff

View File

@ -21,15 +21,15 @@
#ifndef SETTINGS_HPP
#define SETTINGS_HPP
#include "src/core/corestructs.h"
#include <QDate>
#include <QFlags>
#include <QFont>
#include <QHash>
#include <QMutex>
#include <QNetworkProxy>
#include <QObject>
#include <QPixmap>
#include <QMutex>
#include <QDate>
#include <QNetworkProxy>
#include <QFlags>
#include "src/core/corestructs.h"
class ToxPk;
class Profile;
@ -46,92 +46,80 @@ class Settings : public QObject
Q_ENUMS(StyleType)
// general
Q_PROPERTY(bool compactLayout READ getCompactLayout WRITE setCompactLayout
NOTIFY compactLayoutChanged FINAL)
Q_PROPERTY(bool autorun READ getAutorun WRITE setAutorun
NOTIFY autorunChanged FINAL)
Q_PROPERTY(bool compactLayout READ getCompactLayout WRITE setCompactLayout NOTIFY compactLayoutChanged FINAL)
Q_PROPERTY(bool autorun READ getAutorun WRITE setAutorun NOTIFY autorunChanged FINAL)
// GUI
Q_PROPERTY(bool separateWindow READ getSeparateWindow
WRITE setSeparateWindow NOTIFY separateWindowChanged FINAL)
Q_PROPERTY(QString smileyPack READ getSmileyPack WRITE setSmileyPack
NOTIFY smileyPackChanged FINAL)
Q_PROPERTY(int emojiFontPointSize READ getEmojiFontPointSize
WRITE setEmojiFontPointSize NOTIFY emojiFontPointSizeChanged
FINAL)
Q_PROPERTY(bool minimizeOnClose READ getMinimizeOnClose
WRITE setMinimizeOnClose NOTIFY minimizeOnCloseChanged FINAL)
Q_PROPERTY(QByteArray windowGeometry READ getWindowGeometry
WRITE setWindowGeometry NOTIFY windowGeometryChanged FINAL)
Q_PROPERTY(QByteArray windowState READ getWindowState WRITE setWindowState
NOTIFY windowStateChanged FINAL)
Q_PROPERTY(QByteArray splitterState READ getSplitterState
WRITE setSplitterState NOTIFY splitterStateChanged FINAL)
Q_PROPERTY(QByteArray dialogGeometry READ getDialogGeometry
WRITE setDialogGeometry NOTIFY dialogGeometryChanged FINAL)
Q_PROPERTY(QByteArray dialogSplitterState READ getDialogSplitterState
WRITE setDialogSplitterState NOTIFY dialogSplitterStateChanged
FINAL)
Q_PROPERTY(QByteArray dialogSettingsGeometry READ getDialogSettingsGeometry
WRITE setDialogSettingsGeometry
NOTIFY dialogSettingsGeometryChanged FINAL)
Q_PROPERTY(QString style READ getStyle WRITE setStyle NOTIFY styleChanged
FINAL)
Q_PROPERTY(bool showSystemTray READ getShowSystemTray
WRITE setShowSystemTray NOTIFY showSystemTrayChanged FINAL)
Q_PROPERTY(bool separateWindow READ getSeparateWindow WRITE setSeparateWindow NOTIFY
separateWindowChanged FINAL)
Q_PROPERTY(QString smileyPack READ getSmileyPack WRITE setSmileyPack NOTIFY smileyPackChanged FINAL)
Q_PROPERTY(int emojiFontPointSize READ getEmojiFontPointSize WRITE setEmojiFontPointSize NOTIFY
emojiFontPointSizeChanged FINAL)
Q_PROPERTY(bool minimizeOnClose READ getMinimizeOnClose WRITE setMinimizeOnClose NOTIFY
minimizeOnCloseChanged FINAL)
Q_PROPERTY(QByteArray windowGeometry READ getWindowGeometry WRITE setWindowGeometry NOTIFY
windowGeometryChanged FINAL)
Q_PROPERTY(QByteArray windowState READ getWindowState WRITE setWindowState NOTIFY windowStateChanged FINAL)
Q_PROPERTY(QByteArray splitterState READ getSplitterState WRITE setSplitterState NOTIFY
splitterStateChanged FINAL)
Q_PROPERTY(QByteArray dialogGeometry READ getDialogGeometry WRITE setDialogGeometry NOTIFY
dialogGeometryChanged FINAL)
Q_PROPERTY(QByteArray dialogSplitterState READ getDialogSplitterState WRITE
setDialogSplitterState NOTIFY dialogSplitterStateChanged FINAL)
Q_PROPERTY(QByteArray dialogSettingsGeometry READ getDialogSettingsGeometry WRITE
setDialogSettingsGeometry NOTIFY dialogSettingsGeometryChanged FINAL)
Q_PROPERTY(QString style READ getStyle WRITE setStyle NOTIFY styleChanged FINAL)
Q_PROPERTY(bool showSystemTray READ getShowSystemTray WRITE setShowSystemTray NOTIFY
showSystemTrayChanged FINAL)
// ChatView
Q_PROPERTY(bool groupchatPosition READ getGroupchatPosition
WRITE setGroupchatPosition NOTIFY groupchatPositionChanged FINAL)
Q_PROPERTY(QFont chatMessageFont READ getChatMessageFont
WRITE setChatMessageFont NOTIFY chatMessageFontChanged FINAL)
Q_PROPERTY(StyleType stylePreference READ getStylePreference
WRITE setStylePreference NOTIFY stylePreferenceChanged FINAL)
Q_PROPERTY(QString timestampFormat READ getTimestampFormat
WRITE setTimestampFormat NOTIFY timestampFormatChanged FINAL)
Q_PROPERTY(QString dateFormat READ getDateFormat WRITE setDateFormat
NOTIFY dateFormatChanged FINAL)
Q_PROPERTY(bool statusChangeNotificationEnabled
READ getStatusChangeNotificationEnabled
WRITE setStatusChangeNotificationEnabled
NOTIFY statusChangeNotificationEnabledChanged FINAL)
Q_PROPERTY(bool groupchatPosition READ getGroupchatPosition WRITE setGroupchatPosition NOTIFY
groupchatPositionChanged FINAL)
Q_PROPERTY(QFont chatMessageFont READ getChatMessageFont WRITE setChatMessageFont NOTIFY
chatMessageFontChanged FINAL)
Q_PROPERTY(StyleType stylePreference READ getStylePreference WRITE setStylePreference NOTIFY
stylePreferenceChanged FINAL)
Q_PROPERTY(QString timestampFormat READ getTimestampFormat WRITE setTimestampFormat NOTIFY
timestampFormatChanged FINAL)
Q_PROPERTY(QString dateFormat READ getDateFormat WRITE setDateFormat NOTIFY dateFormatChanged FINAL)
Q_PROPERTY(bool statusChangeNotificationEnabled READ getStatusChangeNotificationEnabled WRITE
setStatusChangeNotificationEnabled NOTIFY statusChangeNotificationEnabledChanged FINAL)
// Privacy
Q_PROPERTY(bool typingNotification READ getTypingNotification
WRITE setTypingNotification NOTIFY typingNotificationChanged
FINAL)
Q_PROPERTY(bool typingNotification READ getTypingNotification WRITE setTypingNotification NOTIFY
typingNotificationChanged FINAL)
// Audio
Q_PROPERTY(QString inDev READ getInDev WRITE setInDev
NOTIFY inDevChanged FINAL)
Q_PROPERTY(bool audioInDevEnabled READ getAudioInDevEnabled
WRITE setAudioInDevEnabled NOTIFY audioInDevEnabledChanged FINAL)
Q_PROPERTY(qreal audioInGainDecibel READ getAudioInGainDecibel
WRITE setAudioInGainDecibel NOTIFY audioInGainDecibelChanged
FINAL)
Q_PROPERTY(QString outDev READ getOutDev WRITE setOutDev
NOTIFY outDevChanged FINAL)
Q_PROPERTY(bool audioOutDevEnabled READ getAudioOutDevEnabled
WRITE setAudioOutDevEnabled NOTIFY audioOutDevEnabledChanged
FINAL)
Q_PROPERTY(int outVolume READ getOutVolume WRITE setOutVolume
NOTIFY outVolumeChanged FINAL)
Q_PROPERTY(QString inDev READ getInDev WRITE setInDev NOTIFY inDevChanged FINAL)
Q_PROPERTY(bool audioInDevEnabled READ getAudioInDevEnabled WRITE setAudioInDevEnabled NOTIFY
audioInDevEnabledChanged FINAL)
Q_PROPERTY(qreal audioInGainDecibel READ getAudioInGainDecibel WRITE setAudioInGainDecibel
NOTIFY audioInGainDecibelChanged FINAL)
Q_PROPERTY(QString outDev READ getOutDev WRITE setOutDev NOTIFY outDevChanged FINAL)
Q_PROPERTY(bool audioOutDevEnabled READ getAudioOutDevEnabled WRITE setAudioOutDevEnabled NOTIFY
audioOutDevEnabledChanged FINAL)
Q_PROPERTY(int outVolume READ getOutVolume WRITE setOutVolume NOTIFY outVolumeChanged FINAL)
// Video
Q_PROPERTY(QString videoDev READ getVideoDev WRITE setVideoDev
NOTIFY videoDevChanged FINAL)
Q_PROPERTY(QRect camVideoRes READ getCamVideoRes WRITE setCamVideoRes
NOTIFY camVideoResChanged FINAL)
Q_PROPERTY(QRect screenRegion READ getScreenRegion WRITE setScreenRegion
NOTIFY screenRegionChanged FINAL)
Q_PROPERTY(bool screenGrabbed READ getScreenGrabbed WRITE setScreenGrabbed
NOTIFY screenGrabbedChanged FINAL)
Q_PROPERTY(quint16 camVideoFPS READ getCamVideoFPS
WRITE setCamVideoFPS NOTIFY camVideoFPSChanged FINAL)
Q_PROPERTY(QString videoDev READ getVideoDev WRITE setVideoDev NOTIFY videoDevChanged FINAL)
Q_PROPERTY(QRect camVideoRes READ getCamVideoRes WRITE setCamVideoRes NOTIFY camVideoResChanged FINAL)
Q_PROPERTY(QRect screenRegion READ getScreenRegion WRITE setScreenRegion NOTIFY screenRegionChanged FINAL)
Q_PROPERTY(bool screenGrabbed READ getScreenGrabbed WRITE setScreenGrabbed NOTIFY screenGrabbedChanged FINAL)
Q_PROPERTY(quint16 camVideoFPS READ getCamVideoFPS WRITE setCamVideoFPS NOTIFY camVideoFPSChanged FINAL)
public:
enum class ProxyType {ptNone = 0, ptSOCKS5 = 1, ptHTTP = 2};
enum class StyleType {NONE = 0, WITH_CHARS = 1, WITHOUT_CHARS = 2};
enum class ProxyType
{
ptNone = 0,
ptSOCKS5 = 1,
ptHTTP = 2
};
enum class StyleType
{
NONE = 0,
WITH_CHARS = 1,
WITHOUT_CHARS = 2
};
enum class AutoAcceptCall
{
None = 0x00,

View File

@ -23,11 +23,11 @@
#include "src/core/toxencrypt.h"
#include "src/persistence/profile.h"
#include <QSaveFile>
#include <QFile>
#include <QDebug>
#include <memory>
#include <QFile>
#include <QSaveFile>
#include <cassert>
#include <memory>
/**
* @class SettingsSerializer
@ -89,8 +89,7 @@ QDataStream& readStream(QDataStream& dataStream, QByteArray& data)
char num3;
int num = 0;
int num2 = 0;
do
{
do {
dataStream.readRawData(&num3, 1);
num |= (num3 & 0x7f) << num2;
num2 += 7;
@ -101,8 +100,11 @@ QDataStream& readStream(QDataStream& dataStream, QByteArray& data)
}
SettingsSerializer::SettingsSerializer(QString filePath, const QString& password)
: path{filePath}, password{password},
group{-1}, array{-1}, arrayIndex{-1}
: path{filePath}
, password{password}
, group{-1}
, array{-1}
, arrayIndex{-1}
{
}
@ -111,12 +113,9 @@ void SettingsSerializer::beginGroup(const QString &prefix)
if (prefix.isEmpty())
endGroup();
int index = groups.indexOf(prefix);
if (index >= 0)
{
if (index >= 0) {
group = index;
}
else
{
} else {
group = groups.size();
groups.append(prefix);
}
@ -130,19 +129,13 @@ void SettingsSerializer::endGroup()
int SettingsSerializer::beginReadArray(const QString& prefix)
{
auto index = std::find_if(std::begin(arrays), std::end(arrays),
[=](const Array& a)
{
return a.name==prefix;
});
[=](const Array& a) { return a.name == prefix; });
if (index != std::end(arrays))
{
if (index != std::end(arrays)) {
array = static_cast<int>(index - std::begin(arrays));
arrayIndex = -1;
return index->size;
}
else
{
} else {
array = arrays.size();
arrays.push_back({group, 0, prefix, {}});
arrayIndex = -1;
@ -153,20 +146,14 @@ int SettingsSerializer::beginReadArray(const QString &prefix)
void SettingsSerializer::beginWriteArray(const QString& prefix, int size)
{
auto index = std::find_if(std::begin(arrays), std::end(arrays),
[=](const Array& a)
{
return a.name==prefix;
});
[=](const Array& a) { return a.name == prefix; });
if (index != std::end(arrays))
{
if (index != std::end(arrays)) {
array = static_cast<int>(index - std::begin(arrays));
arrayIndex = -1;
if (size > 0)
index->size = std::max(index->size, size);
}
else
{
} else {
if (size < 0)
size = 0;
array = arrays.size();
@ -188,12 +175,9 @@ void SettingsSerializer::setArrayIndex(int i)
void SettingsSerializer::setValue(const QString& key, const QVariant& value)
{
Value* v = findValue(key);
if (v)
{
if (v) {
v->value = value;
}
else
{
} else {
Value nv{group, array, arrayIndex, key, value};
if (array >= 0)
arrays[array].values.append(values.size());
@ -212,23 +196,18 @@ QVariant SettingsSerializer::value(const QString &key, const QVariant &defaultVa
const SettingsSerializer::Value* SettingsSerializer::findValue(const QString& key) const
{
if (array != -1)
{
for (const Array& a : arrays)
{
if (array != -1) {
for (const Array& a : arrays) {
if (a.group != group)
continue;
for (int vi : a.values)
{
for (int vi : a.values) {
const Value& v = values[vi];
if (v.arrayIndex == arrayIndex && v.key == key)
return &v;
}
}
}
else
{
} else {
for (const Value& v : values)
if (v.group == group && v.array == -1 && v.key == key)
return &v;
@ -274,8 +253,7 @@ void SettingsSerializer::load()
void SettingsSerializer::save()
{
QSaveFile f(path);
if (!f.open(QIODevice::Truncate | QIODevice::WriteOnly))
{
if (!f.open(QIODevice::Truncate | QIODevice::WriteOnly)) {
qWarning() << "Couldn't open file";
return;
}
@ -284,18 +262,15 @@ void SettingsSerializer::save()
QDataStream stream(&data, QIODevice::ReadWrite | QIODevice::Append);
stream.setVersion(QDataStream::Qt_5_0);
for (int g=-1; g<groups.size(); ++g)
{
for (int g = -1; g < groups.size(); ++g) {
// Save the group name, if any
if (g!=-1)
{
if (g != -1) {
writeStream(stream, RecordTag::GroupStart);
writeStream(stream, groups[g].toUtf8());
}
// Save all the arrays of this group
for (const Array& a : arrays)
{
for (const Array& a : arrays) {
if (a.group != g)
continue;
if (a.size <= 0)
@ -304,8 +279,7 @@ void SettingsSerializer::save()
writeStream(stream, a.name.toUtf8());
writeStream(stream, vintToData(a.size));
for (int vi : a.values)
{
for (int vi : a.values) {
const Value& v = values[vi];
writeStream(stream, RecordTag::ArrayValue);
writeStream(stream, vintToData(values[vi].arrayIndex));
@ -316,8 +290,7 @@ void SettingsSerializer::save()
}
// Save all the values of this group that aren't in an array
for (const Value& v : values)
{
for (const Value& v : values) {
if (v.group != g || v.array != -1)
continue;
writeStream(stream, RecordTag::Value);
@ -327,8 +300,7 @@ void SettingsSerializer::save()
}
// Encrypt
if (!password.isEmpty())
{
if (!password.isEmpty()) {
// TODO: use passkey
data = ToxEncrypt::encryptPass(password, data);
}
@ -336,12 +308,9 @@ void SettingsSerializer::save()
f.write(data);
// check if everything got written
if (f.flush())
{
if (f.flush()) {
f.commit();
}
else
{
} else {
f.cancelWriting();
qCritical() << "Failed to write, can't save!";
}
@ -350,8 +319,7 @@ void SettingsSerializer::save()
void SettingsSerializer::readSerialized()
{
QFile f(path);
if (!f.open(QIODevice::ReadOnly))
{
if (!f.open(QIODevice::ReadOnly)) {
qWarning() << "Couldn't open file";
return;
}
@ -359,29 +327,23 @@ void SettingsSerializer::readSerialized()
f.close();
// Decrypt
if (tox_is_data_encrypted(reinterpret_cast<uint8_t*>(data.data())))
{
if (password.isEmpty())
{
if (tox_is_data_encrypted(reinterpret_cast<uint8_t*>(data.data()))) {
if (password.isEmpty()) {
qCritical() << "The settings file is encrypted, but we don't have a password!";
return;
}
data = ToxEncrypt::decryptPass(password, data);
if (data.isEmpty())
{
if (data.isEmpty()) {
qCritical() << "Failed to decrypt the settings file";
return;
}
}
else
{
} else {
if (!password.isEmpty())
qWarning() << "We have a password, but the settings file is not encrypted";
}
if (memcmp(data.data(), magic, 4))
{
if (memcmp(data.data(), magic, 4)) {
qWarning() << "Bad magic!";
return;
}
@ -390,45 +352,35 @@ void SettingsSerializer::readSerialized()
QDataStream stream(&data, QIODevice::ReadOnly);
stream.setVersion(QDataStream::Qt_5_0);
while (!stream.atEnd())
{
while (!stream.atEnd()) {
RecordTag tag;
readStream(stream, tag);
if (tag == RecordTag::Value)
{
if (tag == RecordTag::Value) {
QByteArray key;
QByteArray value;
readStream(stream, key);
readStream(stream, value);
setValue(QString::fromUtf8(key), QVariant(QString::fromUtf8(value)));
}
else if (tag == RecordTag::GroupStart)
{
} else if (tag == RecordTag::GroupStart) {
QByteArray prefix;
readStream(stream, prefix);
beginGroup(QString::fromUtf8(prefix));
}
else if (tag == RecordTag::ArrayStart)
{
} else if (tag == RecordTag::ArrayStart) {
QByteArray prefix;
readStream(stream, prefix);
beginReadArray(QString::fromUtf8(prefix));
QByteArray sizeData;
readStream(stream, sizeData);
if (sizeData.isEmpty())
{
if (sizeData.isEmpty()) {
qWarning("The personal save file is corrupted!");
return;
}
int size = dataToVInt(sizeData);
arrays[array].size = qMax(size, arrays[array].size);
}
else if (tag == RecordTag::ArrayValue)
{
} else if (tag == RecordTag::ArrayValue) {
QByteArray indexData;
readStream(stream, indexData);
if (indexData.isEmpty())
{
if (indexData.isEmpty()) {
qWarning("The personal save file is corrupted!");
return;
}
@ -438,9 +390,7 @@ void SettingsSerializer::readSerialized()
readStream(stream, key);
readStream(stream, value);
setValue(QString::fromUtf8(key), QVariant(QString::fromUtf8(value)));
}
else if (tag == RecordTag::ArrayEnd)
{
} else if (tag == RecordTag::ArrayEnd) {
endArray();
}
}
@ -459,8 +409,7 @@ void SettingsSerializer::readIni()
if (!s.group().isEmpty())
beginGroup(s.group());
for (QString k : s.childKeys())
{
for (QString k : s.childKeys()) {
setValue(k, s.value(k));
}
@ -470,18 +419,14 @@ void SettingsSerializer::readIni()
gstack.push_back(g);
// Visit the next group, if any
while (!gstack.isEmpty())
{
while (!gstack.isEmpty()) {
QString g = gstack.takeLast();
if (g.isEmpty())
{
if (g.isEmpty()) {
if (gstack.isEmpty())
break;
else
s.endGroup();
}
else
{
} else {
s.beginGroup(g);
break;
}
@ -495,8 +440,7 @@ void SettingsSerializer::readIni()
// Find groups that only have 1 key
std::unique_ptr<int[]> groupSizes{new int[groups.size()]};
memset(groupSizes.get(), 0, static_cast<size_t>(groups.size()) * sizeof(int));
for (const Value& v : values)
{
for (const Value& v : values) {
if (v.group < 0 || v.group > groups.size())
continue;
groupSizes[static_cast<size_t>(v.group)]++;
@ -504,8 +448,7 @@ void SettingsSerializer::readIni()
// Find arrays, remove their size key from the values, and add them to `arrays`
QVector<int> groupsToKill;
for (int i=values.size()-1; i>=0; i--)
{
for (int i = values.size() - 1; i >= 0; i--) {
const Value& v = values[i];
if (v.group < 0 || v.group > groups.size())
continue;
@ -519,20 +462,16 @@ void SettingsSerializer::readIni()
Array a;
a.size = v.value.toInt();
int slashIndex = groups[static_cast<int>(v.group)].lastIndexOf('/');
if (slashIndex == -1)
{
if (slashIndex == -1) {
a.group = -1;
a.name = groups[static_cast<int>(v.group)];
a.size = v.value.toInt();
}
else
{
} else {
a.group = -1;
for (int i = 0; i < groups.size(); ++i)
if (groups[i] == groups[static_cast<int>(v.group)].left(slashIndex))
a.group = i;
a.name = groups[static_cast<int>(v.group)].mid(slashIndex + 1);
}
groupSizes[static_cast<size_t>(v.group)]--;
groupsToKill.append(static_cast<int>(v.group));
@ -541,8 +480,7 @@ void SettingsSerializer::readIni()
}
// Associate each array's values with the array
for (int ai=0; ai<arrays.size(); ++ai)
{
for (int ai = 0; ai < arrays.size(); ++ai) {
Array& a = arrays[ai];
QString arrayPrefix;
if (a.group != -1)
@ -550,8 +488,7 @@ void SettingsSerializer::readIni()
arrayPrefix += a.name + '/';
// Find groups which represent each array index
for (int g=0; g<groups.size(); ++g)
{
for (int g = 0; g < groups.size(); ++g) {
if (!groups[g].startsWith(arrayPrefix))
continue;
bool ok;
@ -564,8 +501,7 @@ void SettingsSerializer::readIni()
a.size = groupArrayIndex;
// Associate the values for this array index
for (int vi = values.size() - 1; vi >= 0; vi--)
{
for (int vi = values.size() - 1; vi >= 0; vi--) {
Value& v = values[vi];
if (v.group != g)
continue;
@ -579,11 +515,9 @@ void SettingsSerializer::readIni()
}
// Clean up spurious array element groups
std::sort(std::begin(groupsToKill), std::end(groupsToKill),
std::greater_equal<int>());
std::sort(std::begin(groupsToKill), std::end(groupsToKill), std::greater_equal<int>());
for (int g : groupsToKill)
{
for (int g : groupsToKill) {
if (groupSizes[static_cast<size_t>(g)])
continue;
@ -601,14 +535,12 @@ void SettingsSerializer::readIni()
void SettingsSerializer::removeGroup(int group)
{
assert(group < groups.size());
for (Array& a : arrays)
{
for (Array& a : arrays) {
assert(a.group != group);
if (a.group > group)
a.group--;
}
for (Value& v : values)
{
for (Value& v : values) {
assert(v.group != group);
if (v.group > group)
v.group--;

View File

@ -20,10 +20,10 @@
#ifndef SETTINGSSERIALIZER_H
#define SETTINGSSERIALIZER_H
#include <QSettings>
#include <QVector>
#include <QString>
#include <QDataStream>
#include <QSettings>
#include <QString>
#include <QVector>
class SettingsSerializer
{
@ -60,9 +60,22 @@ private:
struct Value
{
Value() : group{-2},array{-2},arrayIndex{-2},key{QString()},value{}{}
Value()
: group{-2}
, array{-2}
, arrayIndex{-2}
, key{QString()}
, value{}
{
}
Value(qint64 group, qint64 array, int arrayIndex, QString key, QVariant value)
: group{group}, array{array}, arrayIndex{arrayIndex}, key{key}, value{value} {}
: group{group}
, array{array}
, arrayIndex{arrayIndex}
, key{key}
, value{value}
{
}
qint64 group;
qint64 array;
int arrayIndex;

View File

@ -22,9 +22,14 @@
#include "src/widget/style.h"
#include <QBuffer>
#include <QBuffer>
#include <QCoreApplication>
#include <QCoreApplication>
#include <QDir>
#include <QDir>
#include <QDomDocument>
#include <QDomDocument>
#include <QDomElement>
#include <QDomElement>
#include <QFile>
#include <QFileInfo>
@ -32,11 +37,6 @@
#include <QFontInfo>
#include <QIcon>
#include <QPixmap>
#include <QDir>
#include <QCoreApplication>
#include <QDomDocument>
#include <QDomElement>
#include <QBuffer>
#include <QStandardPaths>
#include <QStringBuilder>
#include <QtConcurrent/QtConcurrentRun>
@ -73,8 +73,8 @@ SmileyPack::SmileyPack()
{
loadingMutex.lock();
QtConcurrent::run(this, &SmileyPack::load, Settings::getInstance().getSmileyPack());
connect(&Settings::getInstance(), &Settings::smileyPackChanged,
this, &SmileyPack::onSmileyPackChanged);
connect(&Settings::getInstance(), &Settings::smileyPackChanged, this,
&SmileyPack::onSmileyPackChanged);
}
/**
@ -93,7 +93,8 @@ QStringList SmileyPack::loadDefaultPaths()
// Workaround to fix https://bugreports.qt.io/browse/QTBUG-57522
setlocale(LC_ALL, "");
#endif
QStringList paths = QStringList{":/smileys", "~/.kde4/share/emoticons", "~/.kde/share/emoticons"};
QStringList paths =
QStringList{":/smileys", "~/.kde4/share/emoticons", "~/.kde/share/emoticons"};
// qTox should find emoticons next to the binary
paths.append('.' + QDir::separator() + EMOTICONS_SUB_DIR);
@ -105,21 +106,17 @@ QStringList SmileyPack::loadDefaultPaths()
#warning "Qt < 5.4.0 has a trouble with unicode symbols in path on few systems"
location = QStandardPaths::DataLocation;
#endif
for(auto qtoxPath : QStandardPaths::standardLocations(location))
{
for (auto qtoxPath : QStandardPaths::standardLocations(location)) {
qtoxPath += QDir::separator() + EMOTICONS_SUB_DIR;
if(!paths.contains(qtoxPath))
{
if (!paths.contains(qtoxPath)) {
paths << qtoxPath;
}
}
// system wide emoticons
for(auto genericPath : QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation))
{
for (auto genericPath : QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) {
genericPath += QDir::separator() + EMOTICONS_SUB_DIR;
if(!paths.contains(genericPath))
{
if (!paths.contains(genericPath)) {
paths << genericPath;
}
}
@ -136,31 +133,25 @@ QList<QPair<QString, QString>> SmileyPack::listSmileyPacks(const QStringList& pa
{
QList<QPair<QString, QString>> smileyPacks;
for (QString path : paths)
{
if (path.leftRef(1) == "~")
{
for (QString path : paths) {
if (path.leftRef(1) == "~") {
path.replace(0, 1, QDir::homePath());
}
QDir dir(path);
if (!dir.exists())
{
if (!dir.exists()) {
continue;
}
for (const QString& subdirectory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
{
for (const QString& subdirectory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
dir.cd(subdirectory);
QFileInfoList entries = dir.entryInfoList(QStringList() << "emoticons.xml", QDir::Files);
// Does it contain a file called emoticons.xml?
if (entries.size() > 0)
{
if (entries.size() > 0) {
QString packageName = dir.dirName();
QString absPath = entries[0].absoluteFilePath();
if (!smileyPacks.contains(QPair<QString, QString>(packageName, absPath)))
{
if (!smileyPacks.contains(QPair<QString, QString>(packageName, absPath))) {
smileyPacks << QPair<QString, QString>(packageName, absPath);
}
}
@ -193,8 +184,7 @@ bool SmileyPack::load(const QString& filename)
// open emoticons.xml
QFile xmlFile(filename);
if (!xmlFile.open(QIODevice::ReadOnly))
{
if (!xmlFile.open(QIODevice::ReadOnly)) {
loadingMutex.unlock();
return false; // cannot open file
}
@ -220,32 +210,26 @@ bool SmileyPack::load(const QString& filename)
doc.setContent(xmlFile.readAll());
QDomNodeList emoticonElements = doc.elementsByTagName("emoticon");
for (int i = 0; i < emoticonElements.size(); ++i)
{
for (int i = 0; i < emoticonElements.size(); ++i) {
QString file = emoticonElements.at(i).attributes().namedItem("file").nodeValue();
QDomElement stringElement = emoticonElements.at(i).firstChildElement("string");
QStringList emoticonSet; // { ":)", ":-)" } etc.
while (!stringElement.isNull())
{
QString emoticon = stringElement.text()
.replace("<","&lt;").replace(">","&gt;");
while (!stringElement.isNull()) {
QString emoticon = stringElement.text().replace("<", "&lt;").replace(">", "&gt;");
filenameTable.insert(emoticon, file);
cacheSmiley(file); // preload all smileys
if (!getCachedSmiley(emoticon).isNull())
{
if (!getCachedSmiley(emoticon).isNull()) {
emoticonSet.push_back(emoticon);
}
stringElement = stringElement.nextSibling().toElement();
}
if (emoticonSet.size() > 0)
{
if (emoticonSet.size() > 0) {
emoticons.push_back(emoticonSet);
}
}
@ -264,11 +248,9 @@ QString SmileyPack::smileyfied(QString msg)
int index = msg.indexOf(exp);
// if a word is key of a smiley, replace it by its corresponding image in Rich Text
while (index >= 0)
{
while (index >= 0) {
QString key = exp.cap();
if (filenameTable.contains(key))
{
if (filenameTable.contains(key)) {
QString imgRichText = getAsRichText(key);
msg.replace(index, key.length(), imgRichText);
@ -309,15 +291,13 @@ void SmileyPack::cacheSmiley(const QString& name)
QIcon SmileyPack::getCachedSmiley(const QString& key)
{
// valid key?
if (!filenameTable.contains(key))
{
if (!filenameTable.contains(key)) {
return QPixmap();
}
// cache it if needed
QString file = filenameTable.value(key);
if (!iconCache.contains(file))
{
if (!iconCache.contains(file)) {
cacheSmiley(file);
}

View File

@ -21,11 +21,11 @@
#define SMILEYPACK_H
#include <QHash>
#include <QIcon>
#include <QMutex>
#include <QObject>
#include <QString>
#include <QStringList>
#include <QIcon>
#include <QMutex>
class SmileyPack : public QObject
{

View File

@ -18,9 +18,9 @@
*/
#include "toxsave.h"
#include "src/widget/gui.h"
#include "src/core/core.h"
#include "src/persistence/settings.h"
#include "src/widget/gui.h"
#include "src/widget/tool/profileimporter.h"
#include <QCoreApplication>
#include <QFileInfo>
@ -44,8 +44,7 @@ bool handleToxSave(const QString& path)
{
Core* core = Core::getInstance();
while (!core)
{
while (!core) {
core = Core::getInstance();
qApp->processEvents();
}

View File

@ -23,8 +23,7 @@
#define PLATFORM_AUTORUN_H
namespace Platform
{
namespace Platform {
bool setAutorun(bool on);
bool getAutorun();
}

View File

@ -19,19 +19,22 @@
#if defined(__APPLE__) && defined(__MACH__)
#include "src/platform/autorun.h"
#include <QSettings>
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QSettings>
#include <QStandardPaths>
#include <QCoreApplication>
int state;
bool Platform::setAutorun(bool on)
{
QString qtoxPlist = QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() +
"Library" + QDir::separator() + "LaunchAgents" + QDir::separator() + "chat.tox.qtox.autorun.plist");
QString qtoxDir = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + "qtox");
QString qtoxPlist =
QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
+ QDir::separator() + "Library" + QDir::separator() + "LaunchAgents"
+ QDir::separator() + "chat.tox.qtox.autorun.plist");
QString qtoxDir =
QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + "qtox");
QSettings autoRun(qtoxPlist, QSettings::NativeFormat);
autoRun.setValue("Label", "chat.tox.qtox.autorun");
autoRun.setValue("Program", qtoxDir);

View File

@ -19,10 +19,10 @@
#include <QApplication>
#ifdef Q_OS_WIN32
#include "src/platform/autorun.h"
#include "src/persistence/settings.h"
#include <windows.h>
#include "src/platform/autorun.h"
#include <string>
#include <windows.h>
#ifdef UNICODE
/**
@ -31,18 +31,23 @@
* easier to reuse and compatible with both setups.
*/
using tstring = std::wstring;
static inline tstring toTString(QString s) { return s.toStdWString(); }
static inline tstring toTString(QString s)
{
return s.toStdWString();
}
#else
using tstring = std::string;
static inline tstring toTString(QString s) { return s.toStdString(); }
static inline tstring toTString(QString s)
{
return s.toStdString();
}
#endif
namespace Platform
{
namespace Platform {
inline tstring currentCommandLine()
{
return toTString("\"" + QApplication::applicationFilePath().replace('/', '\\') + "\" -p \"" +
Settings::getInstance().getCurrentProfile() + "\"");
return toTString("\"" + QApplication::applicationFilePath().replace('/', '\\') + "\" -p \""
+ Settings::getInstance().getCurrentProfile() + "\"");
}
inline tstring currentRegistryKeyName()
@ -55,19 +60,19 @@ bool Platform::setAutorun(bool on)
{
HKEY key = 0;
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS)
0, KEY_ALL_ACCESS, &key)
!= ERROR_SUCCESS)
return false;
bool result = false;
tstring keyName = currentRegistryKeyName();
if (on)
{
if (on) {
tstring path = currentCommandLine();
result = RegSetValueEx(key, keyName.c_str(), 0, REG_SZ, (PBYTE)path.c_str(),
path.length() * sizeof(TCHAR)) == ERROR_SUCCESS;
}
else
path.length() * sizeof(TCHAR))
== ERROR_SUCCESS;
} else
result = RegDeleteValue(key, keyName.c_str()) == ERROR_SUCCESS;
RegCloseKey(key);
@ -78,7 +83,8 @@ bool Platform::getAutorun()
{
HKEY key = 0;
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS)
0, KEY_ALL_ACCESS, &key)
!= ERROR_SUCCESS)
return false;
tstring keyName = currentRegistryKeyName();
@ -88,7 +94,8 @@ bool Platform::getAutorun()
DWORD type = REG_SZ;
bool result = false;
if (RegQueryValueEx(key, keyName.c_str(), 0, &type, (PBYTE)path, &length) == ERROR_SUCCESS && type == REG_SZ)
if (RegQueryValueEx(key, keyName.c_str(), 0, &type, (PBYTE)path, &length) == ERROR_SUCCESS
&& type == REG_SZ)
result = true;
RegCloseKey(key);

View File

@ -19,13 +19,12 @@
#include <QApplication>
#if defined(Q_OS_UNIX) && !defined(__APPLE__) && !defined(__MACH__)
#include "src/platform/autorun.h"
#include "src/persistence/settings.h"
#include <QProcessEnvironment>
#include "src/platform/autorun.h"
#include <QDir>
#include <QProcessEnvironment>
namespace Platform
{
namespace Platform {
QString getAutostartDirPath()
{
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
@ -37,14 +36,13 @@ namespace Platform
QString getAutostartFilePath(QString dir)
{
return dir + "/qTox - " + Settings::getInstance().getCurrentProfile() +
".desktop";
return dir + "/qTox - " + Settings::getInstance().getCurrentProfile() + ".desktop";
}
inline QString currentCommandLine()
{
return "\"" + QApplication::applicationFilePath() + "\" -p \"" +
Settings::getInstance().getCurrentProfile() + "\"";
return "\"" + QApplication::applicationFilePath() + "\" -p \""
+ Settings::getInstance().getCurrentProfile() + "\"";
}
}
@ -52,10 +50,8 @@ bool Platform::setAutorun(bool on)
{
QString dirPath = getAutostartDirPath();
QFile desktop(getAutostartFilePath(dirPath));
if (on)
{
if (!QDir().mkpath(dirPath) ||
!desktop.open(QFile::WriteOnly | QFile::Truncate))
if (on) {
if (!QDir().mkpath(dirPath) || !desktop.open(QFile::WriteOnly | QFile::Truncate))
return false;
desktop.write("[Desktop Entry]\n");
desktop.write("Type=Application\n");
@ -65,8 +61,7 @@ bool Platform::setAutorun(bool on)
desktop.write("\n");
desktop.close();
return true;
}
else
} else
return desktop.remove();
}

View File

@ -19,17 +19,16 @@
#ifndef AVFOUNDATION_H
#define AVFOUNDATION_H
#include "src/video/videomode.h"
#include <QPair>
#include <QString>
#include <QVector>
#include <QPair>
#include "src/video/videomode.h"
#ifndef Q_OS_MACX
#error "This file is only meant to be compiled for Mac OS X targets"
#endif
namespace avfoundation
{
namespace avfoundation {
const QString CAPTURE_SCREEN{"Capture screen"};
QVector<VideoMode> getDeviceModes(QString devName);

View File

@ -21,14 +21,14 @@
#include "directshow.h"
#include <QDebug>
#include <amvideo.h>
#include <cassert>
#include <cstdint>
#include <dvdmedia.h>
#include <objbase.h>
#include <strmif.h>
#include <amvideo.h>
#include <dvdmedia.h>
#include <uuids.h>
#include <cassert>
#include <QDebug>
/**
* Most of this file is adapted from libavdevice's dshow.c,
@ -51,17 +51,17 @@ QVector<QPair<QString,QString>> DirectShow::getDeviceList()
QVector<QPair<QString, QString>> devices;
ICreateDevEnum* devenum = nullptr;
if (CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**) &devenum) != S_OK)
if (CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
(void**)&devenum)
!= S_OK)
return devices;
IEnumMoniker* classenum = nullptr;
if (devenum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
(IEnumMoniker**)&classenum, 0) != S_OK)
if (devenum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, (IEnumMoniker**)&classenum, 0)
!= S_OK)
return devices;
while (classenum->Next(1, &m, nullptr) == S_OK)
{
while (classenum->Next(1, &m, nullptr) == S_OK) {
VARIANT var;
IPropertyBag* bag = nullptr;
LPMALLOC coMalloc = nullptr;
@ -120,17 +120,17 @@ static IBaseFilter* getDevFilter(QString devName)
IMoniker* m = nullptr;
ICreateDevEnum* devenum = nullptr;
if (CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**) &devenum) != S_OK)
if (CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
(void**)&devenum)
!= S_OK)
return devFilter;
IEnumMoniker* classenum = nullptr;
if (devenum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
(IEnumMoniker**)&classenum, 0) != S_OK)
if (devenum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, (IEnumMoniker**)&classenum, 0)
!= S_OK)
return devFilter;
while (classenum->Next(1, &m, nullptr) == S_OK)
{
while (classenum->Next(1, &m, nullptr) == S_OK) {
LPMALLOC coMalloc = nullptr;
IBindCtx* bindCtx = nullptr;
LPOLESTR olestr = nullptr;
@ -188,8 +188,7 @@ QVector<VideoMode> DirectShow::getDeviceModes(QString devName)
if (devFilter->EnumPins(&pins) != S_OK)
return modes;
while (pins->Next(1, &pin, nullptr) == S_OK)
{
while (pins->Next(1, &pin, nullptr) == S_OK) {
IKsPropertySet* p = nullptr;
PIN_INFO info;
@ -199,8 +198,8 @@ QVector<VideoMode> DirectShow::getDeviceModes(QString devName)
goto next;
if (pin->QueryInterface(IID_IKsPropertySet, (void**)&p) != S_OK)
goto next;
if (p->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
nullptr, 0, &category, sizeof(GUID), &r2) != S_OK)
if (p->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, nullptr, 0, &category, sizeof(GUID), &r2)
!= S_OK)
goto next;
if (!IsEqualGUID(category, PIN_CATEGORY_CAPTURE))
goto next;
@ -219,8 +218,7 @@ QVector<VideoMode> DirectShow::getDeviceModes(QString devName)
assert(size == sizeof(VIDEO_STREAM_CONFIG_CAPS));
vcaps = new VIDEO_STREAM_CONFIG_CAPS;
for (int i = 0; i < n; ++i)
{
for (int i = 0; i < n; ++i) {
AM_MEDIA_TYPE* type = nullptr;
VideoMode mode;
if (config->GetStreamCaps(i, &type, (BYTE*)vcaps) != S_OK)

View File

@ -21,17 +21,16 @@
#ifndef DIRECTSHOW_H
#define DIRECTSHOW_H
#include "src/video/videomode.h"
#include <QPair>
#include <QString>
#include <QVector>
#include <QPair>
#include "src/video/videomode.h"
#ifndef Q_OS_WIN
#error "This file is only meant to be compiled for Windows targets"
#endif
namespace DirectShow
{
namespace DirectShow {
QVector<QPair<QString, QString>> getDeviceList();
QVector<VideoMode> getDeviceModes(QString devName);
}

View File

@ -22,14 +22,14 @@
#include "v4l2.h"
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <dirent.h>
#include <map>
#include <QDebug>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <map>
#include <sys/ioctl.h>
#include <unistd.h>
/**
* Most of this file is adapted from libavdevice's v4l2.c,
@ -90,7 +90,8 @@ fail:
return -1;
}
static QVector<unsigned short> getDeviceModeFramerates(int fd, unsigned w, unsigned h, uint32_t pixelFormat)
static QVector<unsigned short> getDeviceModeFramerates(int fd, unsigned w, unsigned h,
uint32_t pixelFormat)
{
QVector<unsigned short> rates;
v4l2_frmivalenum vfve{};
@ -129,15 +130,13 @@ QVector<VideoMode> v4l2::getDeviceModes(QString devName)
v4l2_fmtdesc vfd{};
vfd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (!ioctl(fd, VIDIOC_ENUM_FMT, &vfd))
{
while (!ioctl(fd, VIDIOC_ENUM_FMT, &vfd)) {
vfd.index++;
v4l2_frmsizeenum vfse{};
vfse.pixel_format = vfd.pixelformat;
while (!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse))
{
while (!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) {
VideoMode mode;
mode.pixel_format = vfse.pixel_format;
switch (vfse.type) {
@ -154,9 +153,9 @@ QVector<VideoMode> v4l2::getDeviceModes(QString devName)
continue;
}
QVector<unsigned short> rates = getDeviceModeFramerates(fd, mode.width, mode.height, vfd.pixelformat);
for (unsigned short rate : rates)
{
QVector<unsigned short> rates =
getDeviceModeFramerates(fd, mode.width, mode.height, vfd.pixelformat);
for (unsigned short rate : rates) {
mode.FPS = rate;
if (!modes.contains(mode))
modes.append(std::move(mode));
@ -183,8 +182,7 @@ QVector<QPair<QString, QString>> v4l2::getDeviceList()
deviceFiles += QString("/dev/") + e->d_name;
closedir(dir);
for (QString file : deviceFiles)
{
for (QString file : deviceFiles) {
int fd = open(file.toStdString().c_str(), O_RDWR);
if (fd < 0)
continue;
@ -200,8 +198,7 @@ QVector<QPair<QString, QString>> v4l2::getDeviceList()
QString v4l2::getPixelFormatString(uint32_t pixel_format)
{
if (pixFmtToName.find(pixel_format) == pixFmtToName.end())
{
if (pixFmtToName.find(pixel_format) == pixFmtToName.end()) {
qWarning() << "Pixel format not found";
return QString("unknown");
}
@ -210,14 +207,10 @@ QString v4l2::getPixelFormatString(uint32_t pixel_format)
bool v4l2::betterPixelFormat(uint32_t a, uint32_t b)
{
if (pixFmtToQuality.find(a) == pixFmtToQuality.end())
{
if (pixFmtToQuality.find(a) == pixFmtToQuality.end()) {
return false;
}
else if (pixFmtToQuality.find(b) == pixFmtToQuality.end())
{
} else if (pixFmtToQuality.find(b) == pixFmtToQuality.end()) {
return true;
}
return pixFmtToQuality.at(a) > pixFmtToQuality.at(b);
}

View File

@ -19,17 +19,16 @@
#ifndef V4L2_H
#define V4L2_H
#include "src/video/videomode.h"
#include <QPair>
#include <QString>
#include <QVector>
#include <QPair>
#include "src/video/videomode.h"
#if !(defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD))
#error "This file is only meant to be compiled for Linux or FreeBSD targets"
#endif
namespace v4l2
{
namespace v4l2 {
QVector<VideoMode> getDeviceModes(QString devName);
QVector<QPair<QString, QString>> getDeviceList();
QString getPixelFormatString(uint32_t pixel_format);
@ -37,4 +36,3 @@ namespace v4l2
}
#endif // V4L2_H

View File

@ -23,8 +23,7 @@
#define PLATFORM_CAPSLOCK_H
namespace Platform
{
namespace Platform {
bool capsLockEnabled();
}

View File

@ -19,8 +19,8 @@
#include <QtCore/qsystemdetection.h>
#ifdef Q_OS_WIN32
#include <windows.h>
#include "src/platform/capslock.h"
#include <windows.h>
bool Platform::capsLockEnabled()
{

View File

@ -19,8 +19,8 @@
#include <QtCore/qsystemdetection.h>
#if defined(Q_OS_UNIX) && !defined(__APPLE__) && !defined(__MACH__)
#include <X11/XKBlib.h>
#include "src/platform/capslock.h"
#include <X11/XKBlib.h>
#undef KeyPress
#undef KeyRelease
#undef FocusIn
@ -30,8 +30,7 @@ bool Platform::capsLockEnabled()
{
Display* d = XOpenDisplay((char*)0);
bool caps_state = false;
if (d)
{
if (d) {
unsigned n;
XkbGetIndicatorState(d, XkbUseCoreKbd, &n);
caps_state = (n & 0x01) == 1;

View File

@ -20,33 +20,32 @@
#include "install_osx.h"
#include <QApplication>
#include <QMessageBox>
#include <QDebug>
#include <QProcess>
#include <QDir>
#include <QFileInfo>
#include <QMessageBox>
#include <QProcess>
#include <QStandardPaths>
#include <unistd.h>
void osx::moveToAppFolder()
{
if (qApp->applicationDirPath() != "/Applications/qtox.app/Contents/MacOS")
{
if (qApp->applicationDirPath() != "/Applications/qtox.app/Contents/MacOS") {
qDebug() << "OS X: Not in Applications folder";
QMessageBox AskInstall;
AskInstall.setIcon(QMessageBox::Question);
AskInstall.setWindowModality(Qt::ApplicationModal);
AskInstall.setText("Move to Applications folder?");
AskInstall.setInformativeText("I can move myself to the Applications folder, keeping your downloads folder less cluttered.\r\n");
AskInstall.setInformativeText("I can move myself to the Applications folder, keeping your "
"downloads folder less cluttered.\r\n");
AskInstall.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
AskInstall.setDefaultButton(QMessageBox::Yes);
int AskInstallAttempt = AskInstall.exec(); // Actually ask the user
if (AskInstallAttempt == QMessageBox::Yes)
{
if (AskInstallAttempt == QMessageBox::Yes) {
QProcess* sudoprocess = new QProcess;
QProcess* qtoxprocess = new QProcess;
@ -84,34 +83,39 @@ void osx::moveToAppFolder()
}
}
}
// migrateProfiles() is compatabilty code that can be removed down the line when the time seems right.
// migrateProfiles() is compatabilty code that can be removed down the line when the time seems
// right.
void osx::migrateProfiles()
{
QString oldPath = QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() +
"Library" + QDir::separator() + "Preferences" + QDir::separator() + "tox");
QString oldPath = QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
+ QDir::separator() + "Library" + QDir::separator()
+ "Preferences" + QDir::separator() + "tox");
QFileInfo checkDir(oldPath);
QString newPath = QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator()
+ "Library" + QDir::separator() + "Application Support" + QDir::separator() + "Tox");
QString newPath = QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
+ QDir::separator() + "Library" + QDir::separator()
+ "Application Support" + QDir::separator() + "Tox");
QDir dir;
if (!checkDir.exists() || !checkDir.isDir())
{
if (!checkDir.exists() || !checkDir.isDir()) {
qDebug() << "OS X: Old settings directory not detected";
return;
}
qDebug() << "OS X: Old settings directory detected migrating to default";
if (!dir.rename(oldPath, newPath))
{
qDebug() << "OS X: Profile migration failed. ~/Library/Application Support/Tox already exists. Using alternate migration method.";
if (!dir.rename(oldPath, newPath)) {
qDebug() << "OS X: Profile migration failed. ~/Library/Application Support/Tox already "
"exists. Using alternate migration method.";
QString OSXMigrater = "../Resources/OSX-Migrater.sh";
QProcess::execute(OSXMigrater);
QMessageBox MigrateProfile;
MigrateProfile.setIcon(QMessageBox::Information);
MigrateProfile.setWindowModality(Qt::ApplicationModal);
MigrateProfile.setText("Alternate profile migration method used.");
MigrateProfile.setInformativeText("It has been detected that your profiles \nwhere migrated to the new settings directory; \nusing the alternate migration method. \n\nA backup can be found in your: \n/Users/[USER]/.Tox-Backup[DATE-TIME] \n\nJust in case. \r\n");
MigrateProfile.setInformativeText(
"It has been detected that your profiles \nwhere migrated to the new settings "
"directory; \nusing the alternate migration method. \n\nA backup can be found in your: "
"\n/Users/[USER]/.Tox-Backup[DATE-TIME] \n\nJust in case. \r\n");
MigrateProfile.exec();
}
}

View File

@ -25,9 +25,9 @@
#error "This file is only meant to be compiled for Mac OSX targets"
#endif
namespace osx
{
static constexpr int EXIT_UPDATE_MACX = 218; // We track our state using unique exit codes when debugging
namespace osx {
static constexpr int EXIT_UPDATE_MACX =
218; // We track our state using unique exit codes when debugging
static constexpr int EXIT_UPDATE_MACX_FAIL = 216;
void moveToAppFolder();

View File

@ -28,14 +28,10 @@
G_BEGIN_DECLS
/* BOOLEAN:INT,INT (closures.def:1) */
extern void g_cclosure_user_marshal_BOOLEAN__INT_INT (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
extern void g_cclosure_user_marshal_BOOLEAN__INT_INT(GClosure* closure, GValue* return_value,
guint n_param_values, const GValue* param_values,
gpointer invocation_hint, gpointer marshal_data);
G_END_DECLS
#endif /* __g_cclosure_user_marshal_MARSHAL_H__ */

View File

@ -25,7 +25,6 @@
#include "statusnotifier.h"
GType status_notifier_error_get_type(void);
#define TYPE_STATUS_NOTIFIER_ERROR (status_notifier_error_get_type())
GType status_notifier_state_get_type(void);
@ -41,6 +40,3 @@ GType status_notifier_scroll_orientation_get_type (void);
G_END_DECLS
#endif /* __STATUS_NOTIFIER_ENUMS_H__ */

Some files were not shown because too many files have changed in this diff Show More