aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2019-07-03 23:28:09 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2019-07-03 23:28:09 +0900
commit6a6857b9d4dbf22402f2871494bdd06cdccdf366 (patch)
tree1e8334bdf1a647d1936387f9c91d8419fde47b7a /lib
parentddc5a60184972e1449191ce77561b875a145a665 (diff)
downloadlibquotient-6a6857b9d4dbf22402f2871494bdd06cdccdf366.tar.gz
libquotient-6a6857b9d4dbf22402f2871494bdd06cdccdf366.zip
Room/Connection: make room aliases work properly
Closes #301.
Diffstat (limited to 'lib')
-rw-r--r--lib/connection.cpp49
-rw-r--r--lib/connection.h10
-rw-r--r--lib/room.cpp39
-rw-r--r--lib/room.h14
4 files changed, 83 insertions, 29 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 4c068b8f..783e12c0 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -82,8 +82,9 @@ class Connection::Private
// separately; specifically, we should keep objects for Invite and
// Leave state of the same room if the two happen to co-exist.
QHash<QPair<QString, bool>, Room*> roomMap;
- // Mapping from aliases to room ids, as per the last sync
- QHash<QString, QString> roomAliasMap;
+ /// Mapping from serverparts to alias/room id mappings,
+ /// as of the last sync
+ QHash<QString, QHash<QString, QString>> roomAliasMap;
QVector<QString> roomIdsToForget;
QVector<Room*> firstTimeRooms;
QVector<QString> pendingStateRoomIds;
@@ -158,20 +159,31 @@ Connection::~Connection()
stopSync();
}
-void Connection::resolveServer(const QString& mxidOrDomain)
+static const auto ServerPartRegEx = QStringLiteral(
+ "(\\[[^]]+\\]|[^:@]+)" // Either IPv6 address or hostname/IPv4 address
+ "(?::(\\d{1,5}))?" // Optional port
+);
+
+QString serverPart(const QString& mxId)
{
- // At this point we may have something as complex as
- // @username:[IPv6:address]:port, or as simple as a plain domain name.
+ static auto re = "^[@!#$+].+?:(" // Localpart and colon
+ % ServerPartRegEx % ")$";
+ static QRegularExpression parser(re,
+ QRegularExpression::UseUnicodePropertiesOption); // Because Asian digits
+ return parser.match(mxId).captured(1);
+}
- // Try to parse as an FQID; if there's no @ part, assume it's a domain name.
- QRegularExpression parser(
+void Connection::resolveServer(const QString& mxidOrDomain)
+{
+ // mxIdOrDomain may be something as complex as
+ // @username:[IPv6:address]:port, or as simple as a plain serverpart.
+ static QRegularExpression parser(
"^(@.+?:)?" // Optional username (allow everything for compatibility)
- "(\\[[^]]+\\]|[^:@]+)" // Either IPv6 address or hostname/IPv4 address
- "(:\\d{1,5})?$", // Optional port
- QRegularExpression::UseUnicodePropertiesOption); // Because asian digits
+ % ServerPartRegEx % '$',
+ QRegularExpression::UseUnicodePropertiesOption); // Because Asian digits
auto match = parser.match(mxidOrDomain);
- QUrl maybeBaseUrl = QUrl::fromUserInput(match.captured(2));
+ auto maybeBaseUrl = QUrl::fromUserInput(match.captured(2));
maybeBaseUrl.setScheme("https"); // Instead of the Qt-default "http"
if (!match.hasMatch() || !maybeBaseUrl.isValid())
{
@@ -883,33 +895,36 @@ Room* Connection::room(const QString& roomId, JoinStates states) const
Room* Connection::roomByAlias(const QString& roomAlias, JoinStates states) const
{
- const auto id = d->roomAliasMap.value(roomAlias);
+ const auto id =
+ d->roomAliasMap.value(serverPart(roomAlias)).value(roomAlias);
if (!id.isEmpty())
return room(id, states);
+
qCWarning(MAIN) << "Room for alias" << roomAlias
<< "is not found under account" << userId();
return nullptr;
}
void Connection::updateRoomAliases(const QString& roomId,
+ const QString& aliasServer,
const QStringList& previousRoomAliases,
const QStringList& roomAliases)
{
+ auto& aliasMap = d->roomAliasMap[aliasServer]; // Allocate if necessary
for (const auto& a: previousRoomAliases)
- if (d->roomAliasMap.remove(a) == 0)
+ if (aliasMap.remove(a) == 0)
qCWarning(MAIN) << "Alias" << a << "is not found (already deleted?)";
for (const auto& a: roomAliases)
{
- auto& mappedId = d->roomAliasMap[a];
+ auto& mappedId = aliasMap[a];
if (!mappedId.isEmpty())
{
if (mappedId == roomId)
- qCDebug(MAIN) << "Alias" << a << "is already mapped to room"
+ qCDebug(MAIN) << "Alias" << a << "is already mapped to"
<< roomId;
else
- qCWarning(MAIN) << "Alias" << a
- << "will be force-remapped from room"
+ qCWarning(MAIN) << "Alias" << a << "will be force-remapped from"
<< mappedId << "to" << roomId;
}
mappedId = roomId;
diff --git a/lib/connection.h b/lib/connection.h
index cc2feed8..f688c10b 100644
--- a/lib/connection.h
+++ b/lib/connection.h
@@ -250,11 +250,13 @@ namespace QMatrixClient
Q_INVOKABLE Room* roomByAlias(const QString& roomAlias,
JoinStates states = JoinState::Invite|JoinState::Join) const;
/** Update the internal map of room aliases to IDs */
- /// This is used for internal bookkeeping of rooms. Do NOT use
- /// it to try change aliases, use Room::setAliases instead
+ /// This is used to maintain the internal index of room aliases.
+ /// It does NOT change aliases on the server,
+ /// \sa Room::setLocalAliases
void updateRoomAliases(const QString& roomId,
- const QStringList& previousRoomAliases,
- const QStringList& roomAliases);
+ const QString& aliasServer,
+ const QStringList& previousRoomAliases,
+ const QStringList& roomAliases);
Q_INVOKABLE Room* invitation(const QString& roomId) const;
Q_INVOKABLE User* user(const QString& userId);
const User* user() const;
diff --git a/lib/room.cpp b/lib/room.cpp
index 9042130a..06f3490c 100644
--- a/lib/room.cpp
+++ b/lib/room.cpp
@@ -96,9 +96,14 @@ class Room::Private
/// The state of the room at timeline position after-maxTimelineIndex()
/// \sa Room::syncEdge
QHash<StateEventKey, const StateEventBase*> currentState;
+ /// Servers with aliases for this room except the one of the local user
+ /// \sa Room::remoteAliases
+ QSet<QString> aliasServers;
+
Timeline timeline;
PendingEvents unsyncedEvents;
QHash<QString, TimelineItem::index_t> eventsIndex;
+
QString displayname;
Avatar avatar;
int highlightCount = 0;
@@ -381,9 +386,18 @@ QString Room::name() const
return d->getCurrentState<RoomNameEvent>()->name();
}
-QStringList Room::aliases() const
+QStringList Room::localAliases() const
{
- return d->getCurrentState<RoomAliasesEvent>()->aliases();
+ return d->getCurrentState<RoomAliasesEvent>(
+ connection()->homeserver().authority())->aliases();
+}
+
+QStringList Room::remoteAliases() const
+{
+ QStringList result;
+ for (const auto& s: d->aliasServers)
+ result += d->getCurrentState<RoomAliasesEvent>(s)->aliases();
+ return result;
}
QString Room::canonicalAlias() const
@@ -1624,7 +1638,7 @@ void Room::setCanonicalAlias(const QString& newAlias)
d->requestSetState(RoomCanonicalAliasEvent(newAlias));
}
-void Room::setAliases(const QStringList& aliases)
+void Room::setLocalAliases(const QStringList& aliases)
{
d->requestSetState(RoomAliasesEvent(aliases));
}
@@ -2192,16 +2206,30 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
if (!is<RoomMemberEvent>(e)) // Room member events are too numerous
qCDebug(EVENTS) << "Room state event:" << e;
+ // clang-format off
return visit(e
, [] (const RoomNameEvent&) {
return NameChange;
}
, [this,oldStateEvent] (const RoomAliasesEvent& ae) {
+ // clang-format on
+ if (ae.aliases().isEmpty()) {
+ qDebug(MAIN).noquote() << ae.stateKey()
+ << "no more has aliases for room" << objectName();
+ d->aliasServers.remove(ae.stateKey());
+ } else {
+ d->aliasServers.insert(ae.stateKey());
+ qDebug(MAIN).nospace().noquote()
+ << "New server with aliases for room " << objectName()
+ << ": " << ae.stateKey();
+ }
const auto previousAliases = oldStateEvent
? static_cast<const RoomAliasesEvent*>(oldStateEvent)->aliases()
: QStringList();
- connection()->updateRoomAliases(id(), previousAliases, ae.aliases());
+ connection()->updateRoomAliases(id(), ae.stateKey(),
+ previousAliases, ae.aliases());
return OtherChange;
+ // clang-format off
}
, [this] (const RoomCanonicalAliasEvent& evt) {
setObjectName(evt.alias().isEmpty() ? d->id : evt.alias());
@@ -2216,6 +2244,7 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
return AvatarChange;
}
, [this,oldStateEvent] (const RoomMemberEvent& evt) {
+ // clang-format on
auto* u = user(evt.userId());
const auto* oldMemberEvent =
static_cast<const RoomMemberEvent*>(oldStateEvent);
@@ -2288,6 +2317,7 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
d->membersLeft.append(u);
}
return MembersChange;
+ // clang-format off
}
, [this] (const EncryptionEvent&) {
emit encryption(); // It can only be done once, so emit it here.
@@ -2310,6 +2340,7 @@ Room::Changes Room::processStateEvent(const RoomEvent& e)
return OtherChange;
}
);
+ // clang-format on
}
Room::Changes Room::processEphemeralEvent(EventPtr&& event)
diff --git a/lib/room.h b/lib/room.h
index d4a1b959..7c85e4ed 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -86,7 +86,8 @@ namespace QMatrixClient
Q_PROPERTY(QString predecessorId READ predecessorId NOTIFY baseStateLoaded)
Q_PROPERTY(QString successorId READ successorId NOTIFY upgraded)
Q_PROPERTY(QString name READ name NOTIFY namesChanged)
- Q_PROPERTY(QStringList aliases READ aliases NOTIFY namesChanged)
+ Q_PROPERTY(QStringList localAliases READ localAliases NOTIFY namesChanged)
+ Q_PROPERTY(QStringList remoteAliases READ remoteAliases NOTIFY namesChanged)
Q_PROPERTY(QString canonicalAlias READ canonicalAlias NOTIFY namesChanged)
Q_PROPERTY(QString displayName READ displayName NOTIFY displaynameChanged)
Q_PROPERTY(QString topic READ topic NOTIFY topicChanged)
@@ -156,7 +157,12 @@ namespace QMatrixClient
QString predecessorId() const;
QString successorId() const;
QString name() const;
- QStringList aliases() const;
+ /// Room aliases defined on the current user's server
+ /// \sa remoteAliases, setLocalAliases
+ QStringList localAliases() const;
+ /// Room aliases defined on other servers
+ /// \sa localAliases
+ QStringList remoteAliases() const;
QString canonicalAlias() const;
QString displayName() const;
QString topic() const;
@@ -436,7 +442,8 @@ namespace QMatrixClient
void discardMessage(const QString& txnId);
void setName(const QString& newName);
void setCanonicalAlias(const QString& newAlias);
- void setAliases(const QStringList& aliases);
+ /// Set room aliases on the user's current server
+ void setLocalAliases(const QStringList& aliases);
void setTopic(const QString& newTopic);
/// You shouldn't normally call this method; it's here for debugging
@@ -590,7 +597,6 @@ namespace QMatrixClient
void beforeDestruction(Room*);
protected:
- /// Returns true if any of room names/aliases has changed
virtual Changes processStateEvent(const RoomEvent& e);
virtual Changes processEphemeralEvent(EventPtr&& event);
virtual Changes processAccountDataEvent(EventPtr&& event);