16 Commits

Author SHA1 Message Date
ouwou
f1a39c006f fix potential crash when loading channel with no messages 2021-10-16 16:54:25 -04:00
ouwou
3e34f785c6 Merge pull request #39 from Zander671/master
Fix another unchecked optional
2021-10-12 18:41:10 +00:00
Alexander Rosenberg
9694813724 Fix another unchecked optional 2021-10-12 03:30:26 -07:00
ouwou
3393526876 make ixwebsocket find module work 2021-10-11 02:10:18 -04:00
ouwou
b6424c9d37 update simpleini submodule 2021-10-11 01:40:51 -04:00
ouwou
bf560ae9d2 use find modules for ixwebsocket/simpleini 2021-10-11 01:03:31 -04:00
ouwou
fa1a007dc1 fix unchecked optionals
also discard exceptions in file cache futures
2021-10-08 17:52:38 -04:00
ouwou
abc0a7931e skip audit log entries with no target id 2021-10-06 02:57:15 -04:00
ouwou
ad523f37c5 preserve scroll position when loading history
it still jumps around a bit sometimes but its acceptable. hopefully there is a better solution
2021-10-06 02:30:30 -04:00
ouwou
cf33d53809 add relative to root #includes 2021-10-06 02:27:06 -04:00
ouwou
e8b1bcd216 remove FOUND_VAR
should also fix compilation in some situations because of sigc++
2021-10-06 00:55:21 -04:00
ouwou
dead7f2f6a fix #includes (#35) 2021-10-06 00:50:25 -04:00
ouwou
df6b01a632 dont purge on socket close 2021-09-29 01:14:33 -04:00
ouwou
9755090c8c try and fix potential crash on ROLE_UPDATE 2021-09-24 01:55:41 -04:00
ouwou
3815d97f5f use GTK emoji rendering by default on Windows 2021-09-21 01:49:36 -04:00
ouwou
7cb4a75ca7 update README with new info 2021-09-21 01:48:49 -04:00
34 changed files with 147 additions and 85 deletions

View File

@@ -7,23 +7,27 @@ set(ABADDON_RESOURCE_DIR "/usr/share/abaddon" CACHE PATH "Fallback directory for
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
set(USE_TLS TRUE)
set(USE_OPEN_SSL TRUE)
find_package(nlohmann_json REQUIRED)
find_package(CURL)
find_package(ZLIB REQUIRED)
find_package(SQLite3 REQUIRED)
find_package(gtkmm REQUIRED)
find_path(IXWEBSOCKET_INCLUDE_DIRS ixwebsocket/IXWebSocket.h)
find_library(IXWEBSOCKET_LIBRARY ixwebsocket)
if (NOT IXWEBSOCKET_LIBRARY)
set(USE_TLS TRUE)
set(USE_OPEN_SSL TRUE)
find_package(IXWebSocket QUIET)
if (NOT IXWebSocket_FOUND)
message("ixwebsocket was not found and will be included as a submodule")
add_subdirectory(thirdparty/IXWebSocket)
include_directories(IXWEBSOCKET_INCLUDE_DIRS)
endif()
include_directories(thirdparty/simpleini)
add_compile_definitions(SI_NO_CONVERSION) # only CSimpleIniA is used
find_package(simpleini QUIET)
if (NOT simpleini_FOUND)
message("simpleini was not found and will be included as a submodule")
include_directories(thirdparty/simpleini)
endif()
if(MINGW OR WIN32)
link_libraries(ws2_32)
@@ -58,6 +62,7 @@ file(GLOB ABADDON_SOURCES
)
add_executable(abaddon ${ABADDON_SOURCES})
target_include_directories(abaddon PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(abaddon PUBLIC ${PROJECT_BINARY_DIR})
target_include_directories(abaddon PUBLIC ${GTKMM_INCLUDE_DIRS})
target_include_directories(abaddon PUBLIC ${ZLIB_INCLUDE_DIRS})
@@ -70,8 +75,8 @@ if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
target_link_libraries(abaddon stdc++fs)
endif()
if (IXWEBSOCKET_LIBRARY)
target_link_libraries(abaddon ${IXWEBSOCKET_LIBRARY})
if (IXWebSocket_LIBRARIES)
target_link_libraries(abaddon ${IXWebSocket_LIBRARIES})
find_library(MBEDTLS_X509_LIBRARY mbedx509)
find_library(MBEDTLS_TLS_LIBRARY mbedtls)
find_library(MBEDTLS_CRYPTO_LIBRARY mbedcrypto)

View File

@@ -10,7 +10,7 @@ Current features:
* Not Electron
* Handles most types of chat messages including embeds, images, and replies
* Completely styleable/customizable with CSS (if you have a system GTK theme it won't really use it though)
* Identifies to gateway as the web client unlike other clients so less likely to be falsely flagged as spam<sup>1</sup>
* Identifies to Discord as the web client unlike other clients so less likely to be falsely flagged as spam<sup>1</sup>
* Set status
* Start new DMs and group DMs
* View user profiles (notes, mutual servers, mutual friends)
@@ -20,10 +20,14 @@ Current features:
* Manage emojis
* View audit log
* Emojis<sup>2</sup>
* Thread support<sup>3</sup>
* Animated avatars, server icons, emojis (can be turned off)
1 - Other third-party clients send the IDENTIFY message that bots use which makes Discord more likely to think you are selfbotting or spamming. However, Discord still loves to ban people's accounts for no good reason, even users of the official clients. If you want to be really careful avoid joining servers really fast or cold DMing people.
2 - Getting emojis to function properly on GTK is still something I've yet to figure out ([#5](../../issues/5)). Unicode emojis are manually searched for and replaced in several places as opposed to allowing GTK to figure it out since GTK's way of doing it doesn't work very well.
1 - Abaddon tries its best to make Discord think it's a legitimate web client. Some of the things done to do this include: using a browser user agent, sending the same IDENTIFY message that the official web client does, using API v9 endpoints in all cases, and not using endpoints the web client does not normally use. There are still a few smaller inconsistencies, however. For example the web client sends lots of telemetry via the `/science` endpoint (uBlock origin stops this) as well as in the headers of all requests. **In any case,** you should use an official client for joining servers, sending new DMs, or managing your friends list if you are afraid of being caught in Discord's spam filters (unlikely).
2 - Unicode emojis are subtituted manually as opposed to rendered by GTK on non-Windows platforms. This can be changed with the `stock_emojis` setting as shown at the bottom of this README. A CBDT-based font using Twemoji is provided to allow GTK to render emojis natively on Windows.
3 - There are some inconsistencies with thread state that might be encountered in some more uncommon cases, but they are the result of fundamental issues with Discord's thread implementation.
### Building manually (recommended if not on Windows):
#### Windows:
@@ -49,14 +53,19 @@ Or, do steps 1 and 2, and open CMakeLists.txt in Visual Studio if `vcpkg integra
4. `cmake ..`
5. `make`
### Downloads (from CI):
### Downloads:
Latest release version: https://github.com/uowuo/abaddon/releases/latest
**CI:**
- Windows: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-windows-RelWithDebInfo.zip)
- MacOS: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-macos-RelWithDebInfo.zip) unsigned, unpackaged, requires gtkmm3 (e.g. from homebrew)
- Linux: [here](https://nightly.link/uowuo/abaddon/workflows/ci/master/build-linux-MinSizeRel.zip) unpackaged (for now), requires gtkmm3. built on Ubuntu 18.04 + gcc9
⚠️ If you use Windows, make sure to start from the directory containing `css` and `res`
If you don't use Windows, `css` and `res` can be loaded from `/usr/share/abaddon`
On Linux, `css` and `res` can also be loaded from `~/.local/share/abaddon` or `/usr/share/abaddon`
`abaddon.ini` will also be automatically used if located at `~/.config/abaddon/abaddon.ini` and there is no `abaddon.ini` in the working directory

View File

@@ -31,7 +31,6 @@ set(HARFBUZZ_INCLUDE_DIRS ${HARFBUZZ_INCLUDE_DIR};${HARFBUZZ_CONFIG_INCLUDE_DIRS
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(HarfBuzz
FOUND_VAR HARFBUZZ_FOUND
REQUIRED_VARS
HARFBUZZ_LIBRARY
HARFBUZZ_INCLUDE_DIR

View File

@@ -31,7 +31,6 @@ set(ATK_INCLUDE_DIRS ${ATK_INCLUDE_DIR};${ATK_CONFIG_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(atk
FOUND_VAR ATK_FOUND
REQUIRED_VARS
ATK_LIBRARY
ATK_INCLUDE_DIR

View File

@@ -42,7 +42,6 @@ set(ATKMM_INCLUDE_DIRS ${ATKMM_INCLUDE_DIR};${ATKMM_CONFIG_INCLUDE_DIR};${ATK_IN
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(atkmm
FOUND_VAR ATKMM_FOUND
REQUIRED_VARS
ATKMM_LIBRARY
ATKMM_INCLUDE_DIRS

View File

@@ -31,7 +31,6 @@ set(CAIRO_INCLUDE_DIRS ${CAIRO_INCLUDE_DIR};${CAIRO_CONFIG_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cairo
FOUND_VAR CAIRO_FOUND
REQUIRED_VARS
CAIRO_LIBRARY
CAIRO_INCLUDE_DIR

View File

@@ -45,7 +45,6 @@ set(CAIROMM_INCLUDE_DIRS ${CAIROMM_INCLUDE_DIR};${CAIROMM_CONFIG_INCLUDE_DIRS};$
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cairomm
FOUND_VAR CAIROMM_FOUND
REQUIRED_VARS
CAIROMM_LIBRARY
CAIROMM_INCLUDE_DIR

View File

@@ -40,7 +40,6 @@ set(GDKMM_INCLUDE_DIRS ${GDKMM_INCLUDE_DIR};${GDKMM_CONFIG_INCLUDE_DIRS};${GDKMM
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gdkmm
FOUND_VAR GDKMM_FOUND
REQUIRED_VARS
GDKMM_LIBRARY
GDKMM_INCLUDE_DIRS

View File

@@ -33,7 +33,6 @@ set(GDKPIXBUF_INCLUDE_DIRS ${GDKPIXBUF_INCLUDE_DIR};${GDKPIXBUF_CONFIG_INCLUDE_D
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gdkpixbuf
FOUND_VAR GDKPIXBUF_FOUND
REQUIRED_VARS
GDKPIXBUF_LIBRARY
GDKPIXBUF_INCLUDE_DIR

View File

@@ -50,7 +50,6 @@ endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(glib
FOUND_VAR GLIB_FOUND
REQUIRED_VARS
GLIB_LIBRARIES
GLIB_INCLUDE_DIRS

View File

@@ -60,7 +60,6 @@ set(GLIBMM_INCLUDE_DIRS ${GLIBMM_INCLUDE_DIR};${GLIBMM_CONFIG_INCLUDE_DIR};${GIO
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(glibmm
FOUND_VAR GLIBMM_FOUND
REQUIRED_VARS
GLIBMM_LIBRARY
GLIBMM_INCLUDE_DIR

View File

@@ -47,7 +47,6 @@ set(GTK_INCLUDE_DIRS ${GTK_INCLUDE_DIR};${GDK_CONFIG_INCLUDE_DIR};${GDKPIXBUF_IN
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gtk
FOUND_VAR GTK_FOUND
REQUIRED_VARS
GTK_LIBRARY
GTK_INCLUDE_DIR

View File

@@ -51,7 +51,6 @@ set(GTKMM_INCLUDE_DIRS ${GTKMM_INCLUDE_DIR};${GTKMM_CONFIG_INCLUDE_DIR};${GDKMM
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gtkmm
FOUND_VAR GTKMM_FOUND
REQUIRED_VARS
GTKMM_LIB
GTKMM_INCLUDE_DIRS

View File

@@ -1,17 +1,30 @@
find_path(IXWEBSOCKET_INCLUDE_DIR
NAMES ixwebsocket/IXWebSocket.h)
set(IXWebSocket_LIBRARY_NAME ixwebsocket)
find_library(IXWEBSOCKET_LIBRARY
NAMES ixwebsocket
HINTS ${IXWEBSOCKET_LIBRARY_ROOT})
find_path(IXWebSocket_INCLUDE_DIR
NAMES ixwebsocket/IXWebSocket.h
HINTS /usr/include
/usr/local/include
/opt/local/include
PATH_SUFFIXES ${IXWebSocket_LIBRARY_NAME})
set(IXWEBSOCKET_LIBRARIES ${IXWEBSOCKET_LIBRARY})
set(IXWEBSOCKET_INCLUDE_DIRS ${IXWEBSOCKET_INCLUDE_DIR})
find_library(IXWebSocket_LIBRARY
NAMES ${IXWebSocket_LIBRARY_NAME}
PATH_SUFFIXES ${IXWebSocket_LIBRARY_NAME}
${IXWebSocket_LIBRARY_NAME}/include)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ixwebsocket
FOUND_VAR IXWEBSOCKET_FOUND
find_package_handle_standard_args(IXWebSocket
REQUIRED_VARS
IXWEBSOCKET_LIBRARY
IXWEBSOCKET_INCLUDE_DIR
VERSION_VAR IXWEBSOCKET_VERSION)
IXWebSocket_LIBRARY
IXWebSocket_INCLUDE_DIR)
mark_as_advanced(IXWebSocket_LIBRARY IXWebSocket_INCLUDE_DIR)
if (IXWebSocket_FOUND)
find_package(OpenSSL QUIET)
set(IXWebSocket_INCLUDE_DIRS "${IXWebSocket_INCLUDE_DIR};${OPENSSL_INCLUDE_DIR}")
set(IXWebSocket_LIBRARIES "${IXWebSocket_LIBRARY};${OPENSSL_LIBRARIES}")
endif()

View File

@@ -22,7 +22,6 @@ set(NLOHMANN_JSON_LIBRARIES "")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(nlohmann_json
FOUND_VAR NLOHMANN_JSON_FOUND
REQUIRED_VARS
NLOHMANN_JSON_INCLUDE_DIR
VERSION_VAR NLOHMANN_JSON_VERSION)

View File

@@ -69,7 +69,6 @@ set(PANGO_INCLUDE_DIRS ${PANGO_INCLUDE_DIR};${PANGO_CONFIG_INCLUDE_DIRS};${HARFB
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(pango
FOUND_VAR PANGO_FOUND
REQUIRED_VARS
PANGO_LIBRARY
PANGO_INCLUDE_DIR

View File

@@ -56,7 +56,6 @@ set(PANGOMM_INCLUDE_DIRS ${PANGOMM_INCLUDE_DIR};${PANGOMM_CONFIG_INCLUDE_DIR};${
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(pangomm
FOUND_VAR PANGOMM_FOUND
REQUIRED_VARS
PANGOMM_LIBRARY
PANGOMM_INCLUDE_DIRS

View File

@@ -32,7 +32,6 @@ set(SIGC++_INCLUDE_DIRS ${SIGC++_INCLUDE_DIR};${SIGC++_CONFIG_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(sigc++
FOUND_VAR SIGC++_FOUND
REQUIRED_VARS
SIGC++_INCLUDE_DIR
SIGC++_LIBRARY

15
cmake/Findsimpleini.cmake Normal file
View File

@@ -0,0 +1,15 @@
set(simpleini_LIBRARY_NAME simpleini)
find_path(simpleini_INCLUDE_DIR
NAMES SimpleIni.h
HINTS /usr/include
/usr/local/include
/opt/local/include
PATH_SUFFIXES ${simpleini_LIBRARY_NAME})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(simpleini
REQUIRED_VARS
simpleini_INCLUDE_DIR)
mark_as_advanced(simpleini_INCLUDE_DIR)

View File

@@ -227,7 +227,7 @@ void ChannelList::UpdateChannel(Snowflake id) {
Gtk::TreeModel::iterator new_parent;
if (channel->ParentID.has_value())
new_parent = GetIteratorForChannelFromID(*channel->ParentID);
else
else if (channel->GuildID.has_value())
new_parent = GetIteratorForGuildFromID(*channel->GuildID);
if (new_parent && iter->parent() != new_parent)

View File

@@ -1,7 +1,7 @@
#include "chatmessage.hpp"
#include "chatlist.hpp"
#include "../abaddon.hpp"
#include "../constants.hpp"
#include "abaddon.hpp"
#include "constants.hpp"
ChatList::ChatList() {
m_list.get_style_context()->add_class("messages");
@@ -139,7 +139,10 @@ void ChatList::ProcessNewMessage(const Message &data, bool prepend) {
if (should_attach) {
header = last_row;
} else {
const auto guild_id = *discord.GetChannel(m_active_channel)->GuildID;
const auto chan = discord.GetChannel(m_active_channel);
Snowflake guild_id;
if (chan.has_value() && chan->GuildID.has_value())
guild_id = *chan->GuildID;
const auto user_id = data.Author.ID;
const auto user = discord.GetUser(user_id);
if (!user.has_value()) return;
@@ -170,13 +173,14 @@ void ChatList::ProcessNewMessage(const Message &data, bool prepend) {
if (!data.has_value()) return false;
const auto channel = client.GetChannel(m_active_channel);
bool is_dm = channel.has_value() && (channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM);
const bool has_manage = client.HasChannelPermission(client.GetUserData().ID, m_active_channel, Permission::MANAGE_MESSAGES);
bool has_manage = channel.has_value() && (channel->Type == ChannelType::DM || channel->Type == ChannelType::GROUP_DM);
if (!has_manage)
has_manage = client.HasChannelPermission(client.GetUserData().ID, m_active_channel, Permission::MANAGE_MESSAGES);
m_menu_edit_message->set_visible(!m_use_pinned_menu);
m_menu_reply_to->set_visible(!m_use_pinned_menu);
m_menu_unpin->set_visible((is_dm || has_manage) && data->IsPinned);
m_menu_pin->set_visible((is_dm || has_manage) && !data->IsPinned);
m_menu_unpin->set_visible(has_manage && data->IsPinned);
m_menu_pin->set_visible(has_manage && !data->IsPinned);
if (data->IsDeleted()) {
m_menu_delete_message->set_sensitive(false);
@@ -239,7 +243,10 @@ void ChatList::RefetchMessage(Snowflake id) {
}
Snowflake ChatList::GetOldestListedMessage() {
return m_id_to_widget.begin()->first;
if (m_id_to_widget.size() > 0)
return m_id_to_widget.begin()->first;
else
return Snowflake::Invalid;
}
void ChatList::UpdateMessageReactions(Snowflake id) {

View File

@@ -2,7 +2,7 @@
#include <gtkmm.h>
#include <map>
#include <vector>
#include "../discord/snowflake.hpp"
#include "discord/snowflake.hpp"
class ChatList : public Gtk::ScrolledWindow {
public:
@@ -21,7 +21,7 @@ public:
void SetFailedByNonce(const std::string &nonce);
std::vector<Snowflake> GetRecentAuthors();
void SetSeparateAll(bool separate);
void SetUsePinnedMenu(); // i think i need a better way to do menus
void SetUsePinnedMenu(); // i think i need a better way to do menus
void ActuallyRemoveMessage(Snowflake id); // perhaps not the best method name
private:
@@ -101,6 +101,15 @@ inline void ChatList::SetMessages(Iter begin, Iter end) {
template<typename Iter>
inline void ChatList::PrependMessages(Iter begin, Iter end) {
const auto old_upper = get_vadjustment()->get_upper();
const auto old_value = get_vadjustment()->get_value();
for (Iter it = begin; it != end; it++)
ProcessNewMessage(*it, true);
// force everything to process before getting new values
while (Gtk::Main::events_pending())
Gtk::Main::iteration();
const auto new_upper = get_vadjustment()->get_upper();
if (old_value == 0.0 && (new_upper - old_upper) > 0.0)
get_vadjustment()->set_value(new_upper - old_upper);
// this isn't ideal
}

View File

@@ -692,7 +692,10 @@ Gtk::Widget *ChatMessageItemContainer::CreateReplyComponent(const Message &data)
// which of course would not be an issue if i could figure out how to get fonts to work on this god-forsaken framework
// oh well
// but ill manually get colors for the user who is being replied to
lbl->set_markup(get_author_markup(referenced.Author.ID, *referenced.GuildID) + ": " + text);
if (referenced.GuildID.has_value())
lbl->set_markup(get_author_markup(referenced.Author.ID, *referenced.GuildID) + ": " + text);
else
lbl->set_markup(get_author_markup(referenced.Author.ID) + ": " + text);
}
} else {
lbl->set_markup("<i>reply unavailable</i>");
@@ -1163,19 +1166,21 @@ ChatMessageHeader::ChatMessageHeader(const Message &data)
void ChatMessageHeader::UpdateNameColor() {
const auto &discord = Abaddon::Get().GetDiscordClient();
const auto guild_id = discord.GetChannel(ChannelID)->GuildID;
const auto role_id = discord.GetMemberHoistedRole(*guild_id, UserID, true);
const auto user = discord.GetUser(UserID);
if (!user.has_value()) return;
const auto role = discord.GetRole(role_id);
const auto chan = discord.GetChannel(ChannelID);
bool is_guild = chan.has_value() && chan->GuildID.has_value();
if (is_guild) {
const auto role_id = discord.GetMemberHoistedRole(*chan->GuildID, UserID, true);
const auto role = discord.GetRole(role_id);
std::string md;
if (role.has_value())
md = "<span weight='bold' color='#" + IntToCSSColor(role->Color) + "'>" + user->GetEscapedName() + "</span>";
else
md = "<span weight='bold'>" + user->GetEscapedName() + "</span>";
m_author.set_markup(md);
std::string md;
if (role.has_value())
m_author.set_markup("<span weight='bold' color='#" + IntToCSSColor(role->Color) + "'>" + user->GetEscapedName() + "</span>");
else
m_author.set_markup("<span weight='bold'>" + user->GetEscapedName() + "</span>");
} else
m_author.set_markup("<span weight='bold'>" + user->GetEscapedName() + "</span>");
}
std::vector<Gtk::Widget *> ChatMessageHeader::GetChildContent() {

View File

@@ -94,7 +94,7 @@ void MemberList::SetActiveChannel(Snowflake id) {
m_guild_id = Snowflake::Invalid;
if (m_chan_id.IsValid()) {
const auto chan = Abaddon::Get().GetDiscordClient().GetChannel(id);
if (chan.has_value()) m_guild_id = *chan->GuildID;
if (chan.has_value() && chan->GuildID.has_value()) m_guild_id = *chan->GuildID;
}
}

View File

@@ -106,6 +106,7 @@ bool RateLimitIndicator::UpdateIndicator() {
void RateLimitIndicator::OnMessageCreate(const Message &message) {
auto &discord = Abaddon::Get().GetDiscordClient();
if (message.Author.ID != discord.GetUserData().ID) return;
if (!message.GuildID.has_value()) return;
const bool can_bypass = discord.HasAnyChannelPermission(discord.GetUserData().ID, m_active_channel, Permission::MANAGE_MESSAGES | Permission::MANAGE_CHANNELS);
const auto rate_limit = GetRateLimit();
if (rate_limit > 0 && !can_bypass) {

View File

@@ -1,5 +1,5 @@
#include "verificationgate.hpp"
#include "../../abaddon.hpp"
#include "../abaddon.hpp"
VerificationGateDialog::VerificationGateDialog(Gtk::Window &parent, Snowflake guild_id)
: Gtk::Dialog("Verification Required", parent, true)

View File

@@ -1,7 +1,7 @@
#pragma once
#include <gtkmm.h>
#include <optional>
#include "../../discord/objects.hpp"
#include "../discord/objects.hpp"
class VerificationGateDialog : public Gtk::Dialog {
public:

View File

@@ -152,7 +152,8 @@ void DiscordClient::FetchMessagesInChannel(Snowflake id, sigc::slot<void(const s
m_store.BeginTransaction();
for (auto &msg : msgs) {
StoreMessageData(msg);
AddUserToGuild(msg.Author.ID, *msg.GuildID);
if (msg.GuildID.has_value())
AddUserToGuild(msg.Author.ID, *msg.GuildID);
}
m_store.EndTransaction();
@@ -172,7 +173,8 @@ void DiscordClient::FetchMessagesInChannelBefore(Snowflake channel_id, Snowflake
m_store.BeginTransaction();
for (auto &msg : msgs) {
StoreMessageData(msg);
AddUserToGuild(msg.Author.ID, *msg.GuildID);
if (msg.GuildID.has_value())
AddUserToGuild(msg.Author.ID, *msg.GuildID);
}
m_store.EndTransaction();
@@ -300,7 +302,7 @@ bool DiscordClient::HasGuildPermission(Snowflake user_id, Snowflake guild_id, Pe
bool DiscordClient::HasAnyChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const {
const auto channel = m_store.GetChannel(channel_id);
if (!channel.has_value()) return false;
if (!channel.has_value() || !channel->GuildID.has_value()) return false;
const auto base = ComputePermissions(user_id, *channel->GuildID);
const auto overwrites = ComputeOverwrites(base, user_id, channel_id);
return (overwrites & perm) != Permission::NONE;
@@ -1400,7 +1402,8 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
void DiscordClient::HandleGatewayMessageCreate(const GatewayMessage &msg) {
Message data = msg.Data;
StoreMessageData(data);
AddUserToGuild(data.Author.ID, *data.GuildID);
if (data.GuildID.has_value())
AddUserToGuild(data.Author.ID, *data.GuildID);
m_signal_message_create.emit(data);
}
@@ -2077,9 +2080,6 @@ void DiscordClient::HandleSocketClose(uint16_t code) {
if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join();
m_client_connected = false;
m_store.ClearAll();
m_guild_to_users.clear();
if (m_client_started && !m_reconnecting && close_code == GatewayCloseCode::Abnormal) {
Glib::signal_timeout().connect_once([this] { if (m_client_started) HandleGatewayReconnect(GatewayMessage()); }, 1000);
m_reconnecting = true;

View File

@@ -17,8 +17,13 @@ Cache::Cache() {
Cache::~Cache() {
m_worker.stop();
for (auto &future : m_futures)
if (future.valid()) future.get();
for (auto &future : m_futures) {
if (future.valid()) {
try { // dont care about stored exceptions
future.get();
} catch (...) {}
}
}
std::error_code err;
if (!std::filesystem::remove_all(m_tmp_path, err))

View File

@@ -55,7 +55,11 @@ bool SettingsManager::GetShowMemberListDiscriminators() const {
}
bool SettingsManager::GetShowStockEmojis() const {
#ifdef _WIN32
return GetSettingBool("gui", "stock_emojis", false);
#else
return GetSettingBool("gui", "stock_emojis", true);
#endif
}
bool SettingsManager::GetShowCustomEmojis() const {

View File

@@ -30,6 +30,8 @@ void GuildSettingsAuditLogPane::OnAuditLogFetch(const AuditLogData &data) {
auto &discord = Abaddon::Get().GetDiscordClient();
auto guild = *discord.GetGuild(GuildID);
for (const auto &entry : data.Entries) {
if (entry.TargetID == "") continue;
auto expander = Gtk::manage(new Gtk::Expander);
auto label = Gtk::manage(new Gtk::Label);
label->set_ellipsize(Pango::ELLIPSIZE_END);

View File

@@ -159,15 +159,7 @@ GuildSettingsRolesPaneRolesListItem::GuildSettingsRolesPaneRolesListItem(const G
UpdateItem(role);
discord.signal_role_update().connect([this, &discord](Snowflake guild_id, Snowflake role_id) {
if (guild_id != GuildID || role_id != RoleID) return;
const auto role = discord.GetRole(RoleID);
if (!role.has_value())
printf("nullopt??? %llu\n", (uint64_t)RoleID);
Position = role->Position;
UpdateItem(*role);
changed();
});
discord.signal_role_update().connect(sigc::mem_fun(*this, &GuildSettingsRolesPaneRolesListItem::OnRoleUpdate));
m_name.set_ellipsize(Pango::ELLIPSIZE_END);
@@ -190,6 +182,15 @@ void GuildSettingsRolesPaneRolesListItem::UpdateItem(const RoleData &role) {
m_name.set_text(role.Name);
}
void GuildSettingsRolesPaneRolesListItem::OnRoleUpdate(Snowflake guild_id, Snowflake role_id) {
if (guild_id != GuildID || role_id != RoleID) return;
const auto role = Abaddon::Get().GetDiscordClient().GetRole(RoleID);
if (!role.has_value()) return;
Position = role->Position;
UpdateItem(*role);
changed();
}
GuildSettingsRolesPaneInfo::GuildSettingsRolesPaneInfo(Snowflake guild_id)
: GuildID(guild_id)
, m_layout(Gtk::ORIENTATION_VERTICAL)

View File

@@ -16,6 +16,7 @@ public:
private:
void UpdateItem(const RoleData &role);
void OnRoleUpdate(Snowflake guild_id, Snowflake role_id);
Gtk::EventBox m_ev;
Gtk::Label m_name;