aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format2
-rw-r--r--lib/accountregistry.cpp73
-rw-r--r--lib/accountregistry.h49
-rw-r--r--lib/connection.cpp4
-rw-r--r--lib/connection.h11
-rw-r--r--lib/converters.h2
-rw-r--r--lib/events/accountdataevents.h29
-rw-r--r--lib/events/event.h6
-rw-r--r--lib/events/eventcontent.h4
-rw-r--r--lib/events/roommessageevent.cpp66
-rw-r--r--lib/function_traits.cpp2
-rw-r--r--lib/jobs/basejob.h4
-rw-r--r--lib/networkaccessmanager.cpp2
-rw-r--r--lib/networkaccessmanager.h2
-rw-r--r--lib/quotient_common.h8
-rw-r--r--lib/room.cpp14
-rw-r--r--lib/settings.cpp10
-rw-r--r--lib/ssosession.cpp42
-rw-r--r--lib/ssosession.h6
-rw-r--r--lib/uri.cpp25
-rw-r--r--lib/util.h8
21 files changed, 180 insertions, 189 deletions
diff --git a/.clang-format b/.clang-format
index 713d2165..8375204a 100644
--- a/.clang-format
+++ b/.clang-format
@@ -105,7 +105,7 @@ PenaltyBreakComment: 45
PenaltyBreakString: 200
#PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 40
-PenaltyReturnTypeOnItsOwnLine: 100
+PenaltyReturnTypeOnItsOwnLine: 150
#PointerAlignment: Left
#ReflowComments: true
#SortIncludes: true
diff --git a/lib/accountregistry.cpp b/lib/accountregistry.cpp
index a292ed45..616b54b4 100644
--- a/lib/accountregistry.cpp
+++ b/lib/accountregistry.cpp
@@ -8,90 +8,59 @@
using namespace Quotient;
-void AccountRegistry::add(Connection* c)
+void AccountRegistry::add(Connection* a)
{
- if (m_accounts.contains(c))
+ if (contains(a))
return;
- beginInsertRows(QModelIndex(), m_accounts.size(), m_accounts.size());
- m_accounts += c;
+ beginInsertRows(QModelIndex(), size(), size());
+ push_back(a);
endInsertRows();
}
-void AccountRegistry::drop(Connection* c)
+void AccountRegistry::drop(Connection* a)
{
- beginRemoveRows(QModelIndex(), m_accounts.indexOf(c), m_accounts.indexOf(c));
- m_accounts.removeOne(c);
+ const auto idx = indexOf(a);
+ beginRemoveRows(QModelIndex(), idx, idx);
+ remove(idx);
endRemoveRows();
- Q_ASSERT(!m_accounts.contains(c));
+ Q_ASSERT(!contains(a));
}
bool AccountRegistry::isLoggedIn(const QString &userId) const
{
- return std::any_of(m_accounts.cbegin(), m_accounts.cend(),
- [&userId](Connection* a) { return a->userId() == userId; });
+ return std::any_of(cbegin(), cend(), [&userId](const Connection* a) {
+ return a->userId() == userId;
+ });
}
-bool AccountRegistry::contains(Connection *c) const
+QVariant AccountRegistry::data(const QModelIndex& index, int role) const
{
- return m_accounts.contains(c);
-}
-
-AccountRegistry::AccountRegistry() = default;
-
-QVariant AccountRegistry::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid()) {
- return {};
- }
-
- if (index.row() >= m_accounts.count()) {
+ if (!index.isValid() || index.row() >= count())
return {};
- }
- auto account = m_accounts[index.row()];
-
- if (role == ConnectionRole) {
- return QVariant::fromValue(account);
- }
+ if (role == AccountRole)
+ return QVariant::fromValue(at(index.row()));
return {};
}
-int AccountRegistry::rowCount(const QModelIndex &parent) const
+int AccountRegistry::rowCount(const QModelIndex& parent) const
{
- if (parent.isValid()) {
- return 0;
- }
-
- return m_accounts.count();
+ return parent.isValid() ? 0 : count();
}
QHash<int, QByteArray> AccountRegistry::roleNames() const
{
- return {{ConnectionRole, "connection"}};
+ return { { AccountRole, "connection" } };
}
-bool AccountRegistry::isEmpty() const
-{
- return m_accounts.isEmpty();
-}
-int AccountRegistry::count() const
-{
- return m_accounts.count();
-}
-
-const QVector<Connection*> AccountRegistry::accounts() const
-{
- return m_accounts;
-}
Connection* AccountRegistry::get(const QString& userId)
{
- for (const auto &connection : m_accounts) {
- if(connection->userId() == userId) {
+ for (const auto &connection : *this) {
+ if (connection->userId() == userId)
return connection;
- }
}
return nullptr;
}
diff --git a/lib/accountregistry.h b/lib/accountregistry.h
index f7a864df..2f6dffdf 100644
--- a/lib/accountregistry.h
+++ b/lib/accountregistry.h
@@ -6,42 +6,55 @@
#include "quotient_export.h"
-#include <QtCore/QObject>
-#include <QtCore/QList>
#include <QtCore/QAbstractListModel>
namespace Quotient {
class Connection;
-class QUOTIENT_API AccountRegistry : public QAbstractListModel {
+class QUOTIENT_API AccountRegistry : public QAbstractListModel,
+ private QVector<Connection*> {
Q_OBJECT
public:
+ using const_iterator = QVector::const_iterator;
+ using const_reference = QVector::const_reference;
+
enum EventRoles {
- ConnectionRole = Qt::UserRole + 1,
+ AccountRole = Qt::UserRole + 1,
+ ConnectionRole = AccountRole
};
- static AccountRegistry &instance() {
- static AccountRegistry _instance;
- return _instance;
- }
+ [[deprecated("Use Accounts variable instead")]] //
+ static AccountRegistry& instance();
+
+ // Expose most of QVector's const-API but only provide add() and drop()
+ // for changing it. In theory other changing operations could be supported
+ // too; but then boilerplate begin/end*() calls has to be tucked into each
+ // and this class gives no guarantees on the order of entries, so why care.
- const QVector<Connection*> accounts() const;
+ const QVector<Connection*>& accounts() const { return *this; }
void add(Connection* a);
void drop(Connection* a);
+ const_iterator begin() const { return QVector::begin(); }
+ const_iterator end() const { return QVector::end(); }
+ const_reference front() const { return QVector::front(); }
+ const_reference back() const { return QVector::back(); }
bool isLoggedIn(const QString& userId) const;
- bool isEmpty() const;
- int count() const;
- bool contains(Connection*) const;
Connection* get(const QString& userId);
- [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ using QVector::isEmpty, QVector::empty;
+ using QVector::size, QVector::count, QVector::capacity;
+ using QVector::cbegin, QVector::cend, QVector::contains;
+
+ // QAbstractItemModel interface implementation
+ [[nodiscard]] QVariant data(const QModelIndex& index,
+ int role) const override;
+ [[nodiscard]] int rowCount(
+ const QModelIndex& parent = QModelIndex()) const override;
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
+};
-private:
- AccountRegistry();
+inline QUOTIENT_API AccountRegistry Accounts {};
- QVector<Connection *> m_accounts;
-};
+inline AccountRegistry& AccountRegistry::instance() { return Accounts; }
}
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 1915c2a9..67bc83f9 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -258,7 +258,7 @@ Connection::~Connection()
{
qCDebug(MAIN) << "deconstructing connection object for" << userId();
stopSync();
- AccountRegistry::instance().drop(this);
+ Accounts.drop(this);
}
void Connection::resolveServer(const QString& mxid)
@@ -438,7 +438,7 @@ void Connection::Private::completeSetup(const QString& mxId)
qCDebug(MAIN) << "Using server" << data->baseUrl().toDisplayString()
<< "by user" << data->userId()
<< "from device" << data->deviceId();
- AccountRegistry::instance().add(q);
+ Accounts.add(q);
#ifndef Quotient_E2EE_ENABLED
qCWarning(E2EE) << "End-to-end encryption (E2EE) support is turned off.";
#else // Quotient_E2EE_ENABLED
diff --git a/lib/connection.h b/lib/connection.h
index b4476347..28688cc1 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -443,6 +443,17 @@ public:
std::forward<JobArgTs>(jobArgs)...);
}
+ //! \brief Start a local HTTP server and generate a single sign-on URL
+ //!
+ //! This call does the preparatory steps to carry out single sign-on
+ //! sequence
+ //! \sa https://matrix.org/docs/guides/sso-for-client-developers
+ //! \return A proxy object holding two URLs: one for SSO on the chosen
+ //! homeserver and another for the local callback address. Normally
+ //! you won't need the callback URL unless you proxy the response
+ //! with a custom UI. You do not need to delete the SsoSession
+ //! object; the Connection that issued it will dispose of it once
+ //! the login sequence completes (with any outcome).
Q_INVOKABLE SsoSession* prepareForSso(const QString& initialDeviceName,
const QString& deviceId = {});
diff --git a/lib/converters.h b/lib/converters.h
index a6028f1b..8eea1cd3 100644
--- a/lib/converters.h
+++ b/lib/converters.h
@@ -355,7 +355,7 @@ namespace _impl {
};
} // namespace _impl
-static constexpr bool IfNotEmpty = false;
+constexpr bool IfNotEmpty = false;
/*! Add a key-value pair to QJsonObject or QUrlQuery
*
diff --git a/lib/events/accountdataevents.h b/lib/events/accountdataevents.h
index c0f2202d..12f1f00b 100644
--- a/lib/events/accountdataevents.h
+++ b/lib/events/accountdataevents.h
@@ -4,27 +4,24 @@
#pragma once
#include "event.h"
+#include "util.h"
namespace Quotient {
-constexpr const char* FavouriteTag = "m.favourite";
-constexpr const char* LowPriorityTag = "m.lowpriority";
-constexpr const char* ServerNoticeTag = "m.server_notice";
+constexpr auto FavouriteTag [[maybe_unused]] = "m.favourite"_ls;
+constexpr auto LowPriorityTag [[maybe_unused]] = "m.lowpriority"_ls;
+constexpr auto ServerNoticeTag [[maybe_unused]] = "m.server_notice"_ls;
struct TagRecord {
- using order_type = Omittable<float>;
-
- order_type order;
-
- TagRecord(order_type order = none) : order(order) {}
-
- bool operator<(const TagRecord& other) const
- {
- // Per The Spec, rooms with no order should be after those with order,
- // against std::optional<>::operator<() convention.
- return order && (!other.order || *order < *other.order);
- }
+ Omittable<float> order = none;
};
+inline bool operator<(TagRecord lhs, TagRecord rhs)
+{
+ // Per The Spec, rooms with no order should be after those with order,
+ // against std::optional<>::operator<() convention.
+ return lhs.order && (!rhs.order || *lhs.order < *rhs.order);
+}
+
template <>
struct JsonObjectConverter<TagRecord> {
static void fillFrom(const QJsonObject& jo, TagRecord& rec)
@@ -41,7 +38,7 @@ struct JsonObjectConverter<TagRecord> {
rec.order = none;
}
}
- static void dumpTo(QJsonObject& jo, const TagRecord& rec)
+ static void dumpTo(QJsonObject& jo, TagRecord rec)
{
addParam<IfNotEmpty>(jo, QStringLiteral("order"), rec.order);
}
diff --git a/lib/events/event.h b/lib/events/event.h
index f12e525e..f10f6a8d 100644
--- a/lib/events/event.h
+++ b/lib/events/event.h
@@ -264,9 +264,9 @@ using Events = EventsArray<Event>;
// provide matrixTypeId() and typeId().
#define DEFINE_EVENT_TYPEID(Id_, Type_) \
static constexpr event_type_t TypeId = Id_##_ls; \
- [[deprecated("Use _Type::TypeId directly instead")]] \
+ [[deprecated("Use " #Type_ "::TypeId directly instead")]] \
static constexpr event_mtype_t matrixTypeId() { return Id_; } \
- [[deprecated("Use _Type::TypeId directly instead")]] \
+ [[deprecated("Use " #Type_ "::TypeId directly instead")]] \
static event_type_t typeId() { return TypeId; } \
// End of macro
@@ -311,7 +311,7 @@ inline auto switchOnType(const BaseEventT& event, FnT&& fn)
namespace _impl {
// Using bool instead of auto below because auto apparently upsets MSVC
template <class BaseT, typename FnT>
- inline constexpr bool needs_downcast =
+ constexpr bool needs_downcast =
std::is_base_of_v<BaseT, std::decay_t<fn_arg_t<FnT>>>
&& !std::is_same_v<BaseT, std::decay_t<fn_arg_t<FnT>>>;
}
diff --git a/lib/events/eventcontent.h b/lib/events/eventcontent.h
index 87ea3672..de9a792b 100644
--- a/lib/events/eventcontent.h
+++ b/lib/events/eventcontent.h
@@ -149,10 +149,8 @@ namespace EventContent {
*/
class QUOTIENT_API Thumbnail : public ImageInfo {
public:
- Thumbnail() = default; // Allow empty thumbnails
- Thumbnail(const QJsonObject& infoJson, const Omittable<EncryptedFile> &file = none);
- Thumbnail(const ImageInfo& info) : ImageInfo(info) {}
using ImageInfo::ImageInfo;
+ Thumbnail(const QJsonObject& infoJson, const Omittable<EncryptedFile> &file = none);
/**
* Writes thumbnail information to "thumbnail_info" subobject
diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp
index 2b7b4166..5ab0f845 100644
--- a/lib/events/roommessageevent.cpp
+++ b/lib/events/roommessageevent.cpp
@@ -19,15 +19,15 @@ using namespace EventContent;
using MsgType = RoomMessageEvent::MsgType;
-static const auto RelatesToKeyL = "m.relates_to"_ls;
-static const auto MsgTypeKeyL = "msgtype"_ls;
-static const auto FormattedBodyKeyL = "formatted_body"_ls;
+namespace { // Supporting internal definitions
-static const auto TextTypeKey = "m.text";
-static const auto EmoteTypeKey = "m.emote";
-static const auto NoticeTypeKey = "m.notice";
-
-static const auto HtmlContentTypeId = QStringLiteral("org.matrix.custom.html");
+constexpr auto RelatesToKey = "m.relates_to"_ls;
+constexpr auto MsgTypeKey = "msgtype"_ls;
+constexpr auto FormattedBodyKey = "formatted_body"_ls;
+constexpr auto TextTypeKey = "m.text"_ls;
+constexpr auto EmoteTypeKey = "m.emote"_ls;
+constexpr auto NoticeTypeKey = "m.notice"_ls;
+constexpr auto HtmlContentTypeId = "org.matrix.custom.html"_ls;
template <typename ContentT>
TypedBase* make(const QJsonObject& json)
@@ -38,13 +38,13 @@ TypedBase* make(const QJsonObject& json)
template <>
TypedBase* make<TextContent>(const QJsonObject& json)
{
- return json.contains(FormattedBodyKeyL) || json.contains(RelatesToKeyL)
+ return json.contains(FormattedBodyKey) || json.contains(RelatesToKey)
? new TextContent(json)
: nullptr;
}
struct MsgTypeDesc {
- QString matrixType;
+ QLatin1String matrixType;
MsgType enumType;
TypedBase* (*maker)(const QJsonObject&);
};
@@ -53,11 +53,11 @@ const std::vector<MsgTypeDesc> msgTypes = {
{ TextTypeKey, MsgType::Text, make<TextContent> },
{ EmoteTypeKey, MsgType::Emote, make<TextContent> },
{ NoticeTypeKey, MsgType::Notice, make<TextContent> },
- { QStringLiteral("m.image"), MsgType::Image, make<ImageContent> },
- { QStringLiteral("m.file"), MsgType::File, make<FileContent> },
- { QStringLiteral("m.location"), MsgType::Location, make<LocationContent> },
- { QStringLiteral("m.video"), MsgType::Video, make<VideoContent> },
- { QStringLiteral("m.audio"), MsgType::Audio, make<AudioContent> }
+ { "m.image"_ls, MsgType::Image, make<ImageContent> },
+ { "m.file"_ls, MsgType::File, make<FileContent> },
+ { "m.location"_ls, MsgType::Location, make<LocationContent> },
+ { "m.video"_ls, MsgType::Video, make<VideoContent> },
+ { "m.audio"_ls, MsgType::Audio, make<AudioContent> }
};
QString msgTypeToJson(MsgType enumType)
@@ -89,17 +89,19 @@ inline bool isReplacement(const Omittable<RelatesTo>& rel)
return rel && rel->type == RelatesTo::ReplacementTypeId();
}
+} // anonymous namespace
+
QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody,
const QString& jsonMsgType,
TypedBase* content)
{
auto json = content ? content->toJson() : QJsonObject();
- if (json.contains(RelatesToKeyL)) {
+ if (json.contains(RelatesToKey)) {
if (jsonMsgType != TextTypeKey && jsonMsgType != NoticeTypeKey
&& jsonMsgType != EmoteTypeKey) {
- json.remove(RelatesToKeyL);
+ json.remove(RelatesToKey);
qCWarning(EVENTS)
- << RelatesToKeyL << "cannot be used in" << jsonMsgType
+ << RelatesToKey << "cannot be used in" << jsonMsgType
<< "messages; the relation has been stripped off";
} else {
// After the above, we know for sure that the content is TextContent
@@ -109,9 +111,9 @@ QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody,
if (textContent->relatesTo->type == RelatesTo::ReplacementTypeId()) {
auto newContentJson = json.take("m.new_content"_ls).toObject();
newContentJson.insert(BodyKey, plainBody);
- newContentJson.insert(MsgTypeKeyL, jsonMsgType);
+ newContentJson.insert(MsgTypeKey, jsonMsgType);
json.insert(QStringLiteral("m.new_content"), newContentJson);
- json[MsgTypeKeyL] = jsonMsgType;
+ json[MsgTypeKey] = jsonMsgType;
json[BodyKeyL] = "* " + plainBody;
return json;
}
@@ -177,8 +179,8 @@ RoomMessageEvent::RoomMessageEvent(const QJsonObject& obj)
if (isRedacted())
return;
const QJsonObject content = contentJson();
- if (content.contains(MsgTypeKeyL) && content.contains(BodyKeyL)) {
- auto msgtype = content[MsgTypeKeyL].toString();
+ if (content.contains(MsgTypeKey) && content.contains(BodyKeyL)) {
+ auto msgtype = content[MsgTypeKey].toString();
bool msgTypeFound = false;
for (const auto& mt : msgTypes)
if (mt.matrixType == msgtype) {
@@ -204,7 +206,7 @@ RoomMessageEvent::MsgType RoomMessageEvent::msgtype() const
QString RoomMessageEvent::rawMsgtype() const
{
- return contentPart<QString>(MsgTypeKeyL);
+ return contentPart<QString>(MsgTypeKey);
}
QString RoomMessageEvent::plainBody() const
@@ -295,7 +297,7 @@ Omittable<RelatesTo> fromJson(const QJsonValue& jv)
} // namespace Quotient
TextContent::TextContent(const QJsonObject& json)
- : relatesTo(fromJson<Omittable<RelatesTo>>(json[RelatesToKeyL]))
+ : relatesTo(fromJson<Omittable<RelatesTo>>(json[RelatesToKey]))
{
QMimeDatabase db;
static const auto PlainTextMimeType = db.mimeTypeForName("text/plain");
@@ -308,7 +310,7 @@ TextContent::TextContent(const QJsonObject& json)
// of sending HTML messages.
if (actualJson["format"_ls].toString() == HtmlContentTypeId) {
mimeType = HtmlMimeType;
- body = actualJson[FormattedBodyKeyL].toString();
+ body = actualJson[FormattedBodyKey].toString();
} else {
// Falling back to plain text, as there's no standard way to describe
// rich text in messages.
@@ -320,7 +322,6 @@ TextContent::TextContent(const QJsonObject& json)
void TextContent::fillJson(QJsonObject* json) const
{
static const auto FormatKey = QStringLiteral("format");
- static const auto FormattedBodyKey = QStringLiteral("formatted_body");
Q_ASSERT(json);
if (mimeType.inherits("text/html")) {
@@ -328,11 +329,14 @@ void TextContent::fillJson(QJsonObject* json) const
json->insert(FormattedBodyKey, body);
}
if (relatesTo) {
- json->insert(QStringLiteral("m.relates_to"),
- relatesTo->type == RelatesTo::ReplyTypeId() ?
- QJsonObject { { relatesTo->type, QJsonObject{ { EventIdKey, relatesTo->eventId } } } } :
- QJsonObject { { "rel_type", relatesTo->type }, { EventIdKey, relatesTo->eventId } }
- );
+ json->insert(
+ QStringLiteral("m.relates_to"),
+ relatesTo->type == RelatesTo::ReplyTypeId()
+ ? QJsonObject { { relatesTo->type,
+ QJsonObject {
+ { EventIdKey, relatesTo->eventId } } } }
+ : QJsonObject { { "rel_type", relatesTo->type },
+ { EventIdKey, relatesTo->eventId } });
if (relatesTo->type == RelatesTo::ReplacementTypeId()) {
QJsonObject newContentJson;
if (mimeType.inherits("text/html")) {
diff --git a/lib/function_traits.cpp b/lib/function_traits.cpp
index 20bcf30e..6542101a 100644
--- a/lib/function_traits.cpp
+++ b/lib/function_traits.cpp
@@ -47,7 +47,7 @@ static_assert(std::is_same_v<fn_arg_t<Fo1>, int>,
"Test fn_arg_t defaulting to first argument");
template <typename T>
-static void ft(const std::vector<T>&);
+[[maybe_unused]] static void ft(const std::vector<T>&);
static_assert(
std::is_same<fn_arg_t<decltype(ft<double>)>, const std::vector<double>&>(),
"Test function templates");
diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h
index c899170d..9ed58ba8 100644
--- a/lib/jobs/basejob.h
+++ b/lib/jobs/basejob.h
@@ -28,7 +28,7 @@ class QUOTIENT_API BaseJob : public QObject {
static QByteArray encodeIfParam(const QString& paramPart);
template <int N>
- static inline auto encodeIfParam(const char (&constPart)[N])
+ static auto encodeIfParam(const char (&constPart)[N])
{
return constPart;
}
@@ -248,7 +248,7 @@ public:
}
public Q_SLOTS:
- void initiate(ConnectionData* connData, bool inBackground);
+ void initiate(Quotient::ConnectionData* connData, bool inBackground);
/**
* Abandons the result of this job, arrived or unarrived.
diff --git a/lib/networkaccessmanager.cpp b/lib/networkaccessmanager.cpp
index 2c0f716b..58c3cc3a 100644
--- a/lib/networkaccessmanager.cpp
+++ b/lib/networkaccessmanager.cpp
@@ -97,7 +97,7 @@ QNetworkReply* NetworkAccessManager::createRequest(
// TODO: Make the best effort with a direct unauthenticated request
// to the media server
} else {
- auto* const connection = AccountRegistry::instance().get(accountId);
+ auto* const connection = Accounts.get(accountId);
if (!connection) {
qCWarning(NETWORK) << "Connection" << accountId << "not found";
return new MxcReply();
diff --git a/lib/networkaccessmanager.h b/lib/networkaccessmanager.h
index 5a9c134c..8ff1c6b5 100644
--- a/lib/networkaccessmanager.h
+++ b/lib/networkaccessmanager.h
@@ -8,8 +8,6 @@
#include <QtNetwork/QNetworkAccessManager>
namespace Quotient {
-class Room;
-class Connection;
class QUOTIENT_API NetworkAccessManager : public QNetworkAccessManager {
Q_OBJECT
diff --git a/lib/quotient_common.h b/lib/quotient_common.h
index 3d38ce1f..02a9f0cd 100644
--- a/lib/quotient_common.h
+++ b/lib/quotient_common.h
@@ -77,7 +77,7 @@ enum class Membership : unsigned int {
};
QUO_DECLARE_FLAGS_NS(MembershipMask, Membership)
-constexpr inline auto MembershipStrings = make_array(
+constexpr auto MembershipStrings = make_array(
// The order MUST be the same as the order in the original enum
"join", "leave", "invite", "knock", "ban");
@@ -95,7 +95,7 @@ enum class JoinState : std::underlying_type_t<Membership> {
};
QUO_DECLARE_FLAGS_NS(JoinStates, JoinState)
-constexpr inline auto JoinStateStrings = make_array(
+[[maybe_unused]] constexpr auto JoinStateStrings = make_array(
MembershipStrings[0], MembershipStrings[1], MembershipStrings[2],
MembershipStrings[3] /* same as MembershipStrings, sans "ban" */
);
@@ -125,9 +125,7 @@ enum RoomType {
};
Q_ENUM_NS(RoomType)
-constexpr inline auto RoomTypeStrings = make_array(
- "m.space"
-);
+[[maybe_unused]] constexpr auto RoomTypeStrings = make_array("m.space");
} // namespace Quotient
Q_DECLARE_OPERATORS_FOR_FLAGS(Quotient::MembershipMask)
diff --git a/lib/room.cpp b/lib/room.cpp
index edf5dcd9..55efb5b9 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -562,16 +562,14 @@ QStringList Room::pinnedEventIds() const {
return d->getCurrentState<RoomPinnedEvent>()->pinnedEvents();
}
-QVector< const Quotient::RoomEvent* > Quotient::Room::pinnedEvents() const
+QVector<const Quotient::RoomEvent*> Quotient::Room::pinnedEvents() const
{
- QStringList events = d->getCurrentState<RoomPinnedEvent>()->pinnedEvents();
+ const auto& pinnedIds = d->getCurrentState<RoomPinnedEvent>()->pinnedEvents();
QVector<const RoomEvent*> pinnedEvents;
- QStringList::iterator i;
- for (i = events.begin(); i != events.end(); ++i) {
- auto timelineItem = findInTimeline(*i);
- if (timelineItem != historyEdge())
- pinnedEvents.append(timelineItem->event());
- }
+ for (auto&& evtId: pinnedIds)
+ if (const auto& it = findInTimeline(evtId); it != historyEdge())
+ pinnedEvents.append(it->event());
+
return pinnedEvents;
}
diff --git a/lib/settings.cpp b/lib/settings.cpp
index 5549e4de..2491d89d 100644
--- a/lib/settings.cpp
+++ b/lib/settings.cpp
@@ -3,6 +3,7 @@
#include "settings.h"
+#include "util.h"
#include "logging.h"
#include <QtCore/QUrl>
@@ -109,10 +110,11 @@ QUO_DEFINE_SETTING(AccountSettings, QString, deviceName, "device_name", {},
QUO_DEFINE_SETTING(AccountSettings, bool, keepLoggedIn, "keep_logged_in", false,
setKeepLoggedIn)
-static const auto HomeserverKey = QStringLiteral("homeserver");
-static const auto AccessTokenKey = QStringLiteral("access_token");
-static const auto EncryptionAccountPickleKey =
- QStringLiteral("encryption_account_pickle");
+namespace {
+constexpr auto HomeserverKey = "homeserver"_ls;
+constexpr auto AccessTokenKey = "access_token"_ls;
+constexpr auto EncryptionAccountPickleKey = "encryption_account_pickle"_ls;
+}
QUrl AccountSettings::homeserver() const
{
diff --git a/lib/ssosession.cpp b/lib/ssosession.cpp
index 5f3479b8..93e252cc 100644
--- a/lib/ssosession.cpp
+++ b/lib/ssosession.cpp
@@ -15,10 +15,10 @@ using namespace Quotient;
class SsoSession::Private {
public:
- Private(SsoSession* q, const QString& initialDeviceName = {},
- const QString& deviceId = {}, Connection* connection = nullptr)
- : initialDeviceName(initialDeviceName)
- , deviceId(deviceId)
+ Private(SsoSession* q, QString initialDeviceName = {},
+ QString deviceId = {}, Connection* connection = nullptr)
+ : initialDeviceName(std::move(initialDeviceName))
+ , deviceId(std::move(deviceId))
, connection(connection)
{
auto* server = new QTcpServer(q);
@@ -29,7 +29,7 @@ public:
.arg(server->serverPort());
ssoUrl = connection->getUrlForApi<RedirectToSSOJob>(callbackUrl);
- QObject::connect(server, &QTcpServer::newConnection, q, [this, server] {
+ QObject::connect(server, &QTcpServer::newConnection, q, [this, q, server] {
qCDebug(MAIN) << "SSO callback initiated";
socket = server->nextPendingConnection();
server->close();
@@ -43,8 +43,14 @@ public:
});
QObject::connect(socket, &QTcpSocket::disconnected, socket,
&QTcpSocket::deleteLater);
+ QObject::connect(socket, &QObject::destroyed, q,
+ &QObject::deleteLater);
});
+ qCDebug(MAIN) << "SSO session constructed";
}
+ ~Private() { qCDebug(MAIN) << "SSO session deconstructed"; }
+ Q_DISABLE_COPY_MOVE(Private)
+
void processCallback();
void sendHttpResponse(const QByteArray& code, const QByteArray& msg);
void onError(const QByteArray& code, const QString& errorMsg);
@@ -62,14 +68,7 @@ SsoSession::SsoSession(Connection* connection, const QString& initialDeviceName,
const QString& deviceId)
: QObject(connection)
, d(makeImpl<Private>(this, initialDeviceName, deviceId, connection))
-{
- qCDebug(MAIN) << "SSO session constructed";
-}
-
-SsoSession::~SsoSession()
-{
- qCDebug(MAIN) << "SSO session deconstructed";
-}
+{}
QUrl SsoSession::ssoUrl() const { return d->ssoUrl; }
@@ -82,29 +81,29 @@ void SsoSession::Private::processCallback()
// (see at https://github.com/clementine-player/Clementine/)
const auto& requestParts = requestData.split(' ');
if (requestParts.size() < 2 || requestParts[1].isEmpty()) {
- onError("400 Bad Request", tr("No login token in SSO callback"));
+ onError("400 Bad Request", tr("Malformed single sign-on callback"));
return;
}
const auto& QueryItemName = QStringLiteral("loginToken");
QUrlQuery query { QUrl(requestParts[1]).query() };
if (!query.hasQueryItem(QueryItemName)) {
- onError("400 Bad Request", tr("Malformed single sign-on callback"));
+ onError("400 Bad Request", tr("No login token in SSO callback"));
+ return;
}
qCDebug(MAIN) << "Found the token in SSO callback, logging in";
connection->loginWithToken(query.queryItemValue(QueryItemName).toLatin1(),
initialDeviceName, deviceId);
connect(connection, &Connection::connected, socket, [this] {
- const QString msg =
- "The application '" % QCoreApplication::applicationName()
- % "' has successfully logged in as a user " % connection->userId()
- % " with device id " % connection->deviceId()
- % ". This window can be closed. Thank you.\r\n";
+ const auto msg =
+ tr("The application '%1' has successfully logged in as a user %2 "
+ "with device id %3. This window can be closed. Thank you.\r\n")
+ .arg(QCoreApplication::applicationName(), connection->userId(),
+ connection->deviceId());
sendHttpResponse("200 OK", msg.toHtmlEscaped().toUtf8());
socket->disconnectFromHost();
});
connect(connection, &Connection::loginError, socket, [this] {
onError("401 Unauthorised", tr("Login failed"));
- socket->disconnectFromHost();
});
}
@@ -128,4 +127,5 @@ void SsoSession::Private::onError(const QByteArray& code,
// [kitsune] Yeah, I know, dirty. Maybe the "right" way would be to have
// an intermediate signal but that seems just a fight for purity.
emit connection->loginError(errorMsg, requestData);
+ socket->disconnectFromHost();
}
diff --git a/lib/ssosession.h b/lib/ssosession.h
index 0f3fc3b8..e6a3f8fb 100644
--- a/lib/ssosession.h
+++ b/lib/ssosession.h
@@ -8,9 +8,6 @@
#include <QtCore/QUrl>
#include <QtCore/QObject>
-class QTcpServer;
-class QTcpSocket;
-
namespace Quotient {
class Connection;
@@ -36,7 +33,8 @@ class QUOTIENT_API SsoSession : public QObject {
public:
SsoSession(Connection* connection, const QString& initialDeviceName,
const QString& deviceId = {});
- ~SsoSession() override;
+ ~SsoSession() override = default;
+
QUrl ssoUrl() const;
QUrl callbackUrl() const;
diff --git a/lib/uri.cpp b/lib/uri.cpp
index c8843dda..6b7d1d20 100644
--- a/lib/uri.cpp
+++ b/lib/uri.cpp
@@ -3,29 +3,34 @@
#include "uri.h"
+#include "util.h"
#include "logging.h"
#include <QtCore/QRegularExpression>
using namespace Quotient;
-struct ReplacePair { QByteArray uriString; char sigil; };
+namespace {
+
+struct ReplacePair { QLatin1String uriString; char sigil; };
/// \brief Defines bi-directional mapping of path prefixes and sigils
///
/// When there are two prefixes for the same sigil, the first matching
/// entry for a given sigil is used.
-static const auto replacePairs = {
- ReplacePair { "u/", '@' },
- { "user/", '@' },
- { "roomid/", '!' },
- { "r/", '#' },
- { "room/", '#' },
+const ReplacePair replacePairs[] = {
+ { "u/"_ls, '@' },
+ { "user/"_ls, '@' },
+ { "roomid/"_ls, '!' },
+ { "r/"_ls, '#' },
+ { "room/"_ls, '#' },
// The notation for bare event ids is not proposed in MSC2312 but there's
// https://github.com/matrix-org/matrix-doc/pull/2644
- { "e/", '$' },
- { "event/", '$' }
+ { "e/"_ls, '$' },
+ { "event/"_ls, '$' }
};
+}
+
Uri::Uri(QByteArray primaryId, QByteArray secondaryId, QString query)
{
if (primaryId.isEmpty())
@@ -75,7 +80,7 @@ static auto decodeFragmentPart(QStringView part)
return QUrl::fromPercentEncoding(part.toLatin1()).toUtf8();
}
-static auto matrixToUrlRegexInit()
+static inline auto matrixToUrlRegexInit()
{
// See https://matrix.org/docs/spec/appendices#matrix-to-navigation
const QRegularExpression MatrixToUrlRE {
diff --git a/lib/util.h b/lib/util.h
index 66db0ece..3505b62f 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -54,9 +54,9 @@ using UnorderedMap = std::unordered_map<KeyT, ValT, HashQ<KeyT>>;
namespace _impl {
template <typename TT>
- constexpr inline auto IsOmittableValue = false;
+ constexpr auto IsOmittableValue = false;
template <typename TT>
- constexpr inline auto IsOmittable = IsOmittableValue<std::decay_t<TT>>;
+ constexpr auto IsOmittable = IsOmittableValue<std::decay_t<TT>>;
}
constexpr auto none = std::nullopt;
@@ -165,7 +165,7 @@ Omittable(T&&) -> Omittable<T>;
namespace _impl {
template <typename T>
- constexpr inline auto IsOmittableValue<Omittable<T>> = true;
+ constexpr auto IsOmittableValue<Omittable<T>> = true;
}
template <typename T1, typename T2>
@@ -191,7 +191,7 @@ inline auto merge(T1& lhs, const Omittable<T2>& rhs)
return true;
}
-inline constexpr auto operator"" _ls(const char* s, std::size_t size)
+constexpr auto operator"" _ls(const char* s, std::size_t size)
{
return QLatin1String(s, int(size));
}