/* * nheko Copyright (C) 2017 Konstantinos Sideris * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "RoomState.h" RoomState::RoomState() {} RoomState::RoomState(const mtx::responses::Timeline &timeline) { updateFromEvents(timeline.events); } RoomState::RoomState(const mtx::responses::State &state) { updateFromEvents(state.events); } void RoomState::resolveName() { name_ = "Empty Room"; userAvatar_.clear(); if (!name.content.name.empty()) { name_ = QString::fromStdString(name.content.name).simplified(); return; } if (!canonical_alias.content.alias.empty()) { name_ = QString::fromStdString(canonical_alias.content.alias).simplified(); return; } // FIXME: Doesn't follow the spec guidelines. if (aliases.content.aliases.size() != 0) { name_ = QString::fromStdString(aliases.content.aliases[0]).simplified(); return; } QSettings settings; auto user_id = settings.value("auth/user_id"); // TODO: Display names should be sorted alphabetically. for (const auto membership : memberships) { const auto stateKey = QString::fromStdString(membership.second.state_key); if (stateKey == user_id) continue; if (membership.second.content.membership == mtx::events::state::Membership::Join) { userAvatar_ = stateKey; auto displayName = QString::fromStdString(membership.second.content.display_name); if (displayName.isEmpty()) name_ = stateKey; else name_ = displayName; break; } } // TODO: pluralization if (memberships.size() > 2) name_ = QString("%1 and %2 others").arg(name_).arg(memberships.size()); } void RoomState::resolveAvatar() { if (userAvatar_.isEmpty()) { avatar_ = QString::fromStdString(avatar.content.url); return; } if (memberships.count(userAvatar_.toStdString()) != 0) { avatar_ = QString::fromStdString(memberships[userAvatar_.toStdString()].content.avatar_url); } else { qWarning() << "Setting room avatar from unknown user id" << userAvatar_; } } // Should be used only after initial sync. void RoomState::removeLeaveMemberships() { for (auto it = memberships.cbegin(); it != memberships.cend();) { if (it->second.content.membership == mtx::events::state::Membership::Leave) { it = memberships.erase(it); } else { ++it; } } } void RoomState::update(const RoomState &state) { bool needsNameCalculation = false; bool needsAvatarCalculation = false; if (aliases.event_id != state.aliases.event_id) aliases = state.aliases; if (avatar.event_id != state.avatar.event_id) { avatar = state.avatar; needsAvatarCalculation = true; } if (canonical_alias.event_id != state.canonical_alias.event_id) { canonical_alias = state.canonical_alias; needsNameCalculation = true; } if (create.event_id != state.create.event_id) create = state.create; if (history_visibility.event_id != state.history_visibility.event_id) history_visibility = state.history_visibility; if (join_rules.event_id != state.join_rules.event_id) join_rules = state.join_rules; if (name.event_id != state.name.event_id) { name = state.name; needsNameCalculation = true; } if (power_levels.event_id != state.power_levels.event_id) power_levels = state.power_levels; if (topic.event_id != state.topic.event_id) topic = state.topic; for (auto it = state.memberships.cbegin(); it != state.memberships.cend(); ++it) { auto membershipState = it->second.content.membership; if (it->first == userAvatar_.toStdString()) { needsNameCalculation = true; needsAvatarCalculation = true; } if (membershipState == mtx::events::state::Membership::Leave) this->memberships.erase(it->first); else this->memberships.emplace(it->first, it->second); } if (needsNameCalculation) resolveName(); if (needsAvatarCalculation) resolveAvatar(); } std::string RoomState::serialize() const { nlohmann::json obj; if (!aliases.event_id.empty()) obj["aliases"] = aliases; if (!avatar.event_id.empty()) obj["avatar"] = avatar; if (!canonical_alias.event_id.empty()) obj["canonical_alias"] = canonical_alias; if (!create.event_id.empty()) obj["create"] = create; if (!history_visibility.event_id.empty()) obj["history_visibility"] = history_visibility; if (!join_rules.event_id.empty()) obj["join_rules"] = join_rules; if (!name.event_id.empty()) obj["name"] = name; if (!power_levels.event_id.empty()) obj["power_levels"] = power_levels; if (!topic.event_id.empty()) obj["topic"] = topic; return obj.dump(); } void RoomState::parse(const nlohmann::json &object) { if (object.count("aliases") != 0) { try { aliases = object.at("aliases") .get>(); } catch (std::exception &e) { qWarning() << "RoomState::parse - aliases" << e.what(); } } if (object.count("avatar") != 0) { try { avatar = object.at("avatar") .get>(); } catch (std::exception &e) { qWarning() << "RoomState::parse - avatar" << e.what(); } } if (object.count("canonical_alias") != 0) { try { canonical_alias = object.at("canonical_alias") .get>(); } catch (std::exception &e) { qWarning() << "RoomState::parse - canonical_alias" << e.what(); } } if (object.count("create") != 0) { try { create = object.at("create") .get>(); } catch (std::exception &e) { qWarning() << "RoomState::parse - create" << e.what(); } } if (object.count("history_visibility") != 0) { try { history_visibility = object.at("history_visibility") .get>(); } catch (std::exception &e) { qWarning() << "RoomState::parse - history_visibility" << e.what(); } } if (object.count("join_rules") != 0) { try { join_rules = object.at("join_rules") .get>(); } catch (std::exception &e) { qWarning() << "RoomState::parse - join_rules" << e.what(); } } if (object.count("name") != 0) { try { name = object.at("name") .get>(); } catch (std::exception &e) { qWarning() << "RoomState::parse - name" << e.what(); } } if (object.count("power_levels") != 0) { try { power_levels = object.at("power_levels") .get>(); } catch (std::exception &e) { qWarning() << "RoomState::parse - power_levels" << e.what(); } } if (object.count("topic") != 0) { try { topic = object.at("topic") .get>(); } catch (std::exception &e) { qWarning() << "RoomState::parse - topic" << e.what(); } } }