From be4e5cedc3b9e732c4a2e70d6e283c387900a737 Mon Sep 17 00:00:00 2001 From: Florian Stinglmayr Date: Thu, 4 Jul 2019 20:58:08 +0200 Subject: [PATCH] build channel object for chat channels --- libdc/CMakeLists.txt | 3 +- libdc/include/dc/account.h | 5 + libdc/include/dc/channel.h | 53 +++++++++ libdc/src/account.c | 50 ++++++++ libdc/src/api-friends.c | 8 +- libdc/src/api-util.c | 53 --------- libdc/src/channel.c | 227 +++++++++++++++++++++++++++++++++++++ libdc/src/internal.h | 6 - 8 files changed, 341 insertions(+), 64 deletions(-) create mode 100644 libdc/include/dc/channel.h delete mode 100644 libdc/src/api-util.c create mode 100644 libdc/src/channel.c diff --git a/libdc/CMakeLists.txt b/libdc/CMakeLists.txt index 6ec4911..c6d94d8 100644 --- a/libdc/CMakeLists.txt +++ b/libdc/CMakeLists.txt @@ -11,6 +11,7 @@ SET(SOURCES "include/dc/account.h" "include/dc/api.h" "include/dc/apisync.h" + "include/dc/channel.h" "include/dc/guild.h" "include/dc/loop.h" "include/dc/refable.h" @@ -18,8 +19,8 @@ SET(SOURCES "src/account.c" "src/api.c" "src/api-friends.c" - "src/api-util.c" "src/apisync.c" + "src/channel.c" "src/guild.c" "src/loop.c" "src/refable.c" diff --git a/libdc/include/dc/account.h b/libdc/include/dc/account.h index a38e1fe..d48b56a 100644 --- a/libdc/include/dc/account.h +++ b/libdc/include/dc/account.h @@ -5,6 +5,8 @@ #include #include +#include + struct dc_account_; typedef struct dc_account_ *dc_account_t; @@ -43,6 +45,9 @@ dc_account_t dc_account_new(void); dc_account_t dc_account_new2(char const *email, char const *pass); dc_account_t dc_account_from_fullname(char const *fullid); +dc_account_t dc_account_from_json(json_t *j); +json_t *dc_account_to_json(dc_account_t a); + void dc_account_set_email(dc_account_t a, char const *email); char const *dc_account_email(dc_account_t a); diff --git a/libdc/include/dc/channel.h b/libdc/include/dc/channel.h new file mode 100644 index 0000000..3dbd890 --- /dev/null +++ b/libdc/include/dc/channel.h @@ -0,0 +1,53 @@ +#ifndef DC_CHANNEL_H +#define DC_CHANNEL_H + +#include +#include + +/** + * A discord channel. Exactly what it says on the tin. A place where one + * or more guardsmen can exchange Slaaneshi heresy without their commissars + * finding out about it. What's important here is that there are channel + * types, and that each channel has various recipients. + */ + +typedef enum { + /* standard text channel in a guild + */ + CHANNEL_TYPE_GUILD_TEXT = 0, + + /* A direct message channel for 1:1 communication + */ + CHANNEL_TYPE_DM_TEXT, + + /* A guild voice channel + */ + CHANNEL_TYPE_GUILD_VOICE, + + /* Group direct message channel 1:N communication + */ + CHANNEL_TYPE_GROUP_DM, + + /* Category within a GUILD + */ + CHANNEL_TYPE_GUILD_CATEGORY, + + /* News channel + */ + CHANNEL_TYPE_GUILD_NEWS, + + /* Guild store, no idea what this is + */ + CHANNEL_TYPE_GUILD_STORE, +} dc_channel_type_t; + +struct dc_channel_; +typedef struct dc_channel_ *dc_channel_t; + +dc_channel_t dc_channel_new(void); +dc_channel_t dc_channel_from_json(json_t *j); + +dc_channel_type_t dc_channel_type(dc_channel_t c); +void dc_channel_set_type(dc_channel_t c, dc_channel_type_t t); + +#endif diff --git a/libdc/src/account.c b/libdc/src/account.c index 8a8a153..3293c36 100644 --- a/libdc/src/account.c +++ b/libdc/src/account.c @@ -116,6 +116,56 @@ dc_account_t dc_account_from_fullname(char const *fullid) return acc; } +dc_account_t dc_account_from_json(json_t *j) +{ + dc_account_t user = dc_account_new(); + json_t *val = NULL; + + goto_if_true(!json_is_object(j), error); + + val = json_object_get(j, "username"); + goto_if_true(val == NULL || !json_is_string(val), error); + dc_account_set_username(user, json_string_value(val)); + + val = json_object_get(j, "discriminator"); + goto_if_true(val == NULL || !json_is_string(val), error); + dc_account_set_discriminator(user, json_string_value(val)); + + val = json_object_get(j, "id"); + goto_if_true(val == NULL || !json_is_string(val), error); + dc_account_set_id(user, json_string_value(val)); + + return user; + +error: + + dc_unref(user); + return NULL; +} + +json_t *dc_account_to_json(dc_account_t a) +{ + json_t *j = NULL; + + return_if_true(a == NULL, NULL); + return_if_true(dc_account_username(a) == NULL || + dc_account_discriminator(a) == NULL, + NULL + ); + + j = json_object(); + return_if_true(j == NULL, NULL); + + if (a->id != NULL) { + json_object_set_new(j, "id", json_string(a->id)); + } + + json_object_set_new(j, "username", json_string(a->username)); + json_object_set_new(j, "discriminator", json_string(a->discriminator)); + + return j; +} + void dc_account_set_email(dc_account_t a, char const *email) { return_if_true(a == NULL,); diff --git a/libdc/src/api-friends.c b/libdc/src/api-friends.c index 261530f..94d109d 100644 --- a/libdc/src/api-friends.c +++ b/libdc/src/api-friends.c @@ -27,7 +27,7 @@ bool dc_api_get_friends(dc_api_t api, dc_account_t login) continue; } - dc_account_t a = dc_api_account_from_json(val); + dc_account_t a = dc_account_from_json(val); if (a == NULL) { continue; } @@ -72,7 +72,7 @@ bool dc_api_remove_friend(dc_api_t api, dc_account_t login, dc_account_t friend) asprintf(&url, "users/@me/relationships/%s", dc_account_id(friend)); - post = dc_api_account_to_json(friend); + post = dc_account_to_json(friend); return_if_true(post == NULL, false); reply = dc_api_call_sync(api, "DELETE", dc_account_token(login), url, post); @@ -103,7 +103,7 @@ bool dc_api_accept_friend(dc_api_t api, dc_account_t login, dc_account_t friend) asprintf(&url, "users/@me/relationships/%s", dc_account_id(friend)); - post = dc_api_account_to_json(friend); + post = dc_account_to_json(friend); return_if_true(post == NULL, false); reply = dc_api_call_sync(api, "PUT", dc_account_token(login), url, post); @@ -131,7 +131,7 @@ bool dc_api_add_friend(dc_api_t api, dc_account_t login, dc_account_t friend) return_if_true(api == NULL, false); return_if_true(login == NULL, false); - post = dc_api_account_to_json(friend); + post = dc_account_to_json(friend); return_if_true(post == NULL, false); reply = dc_api_call_sync(api, "POST", dc_account_token(login), url, post); diff --git a/libdc/src/api-util.c b/libdc/src/api-util.c deleted file mode 100644 index d90223c..0000000 --- a/libdc/src/api-util.c +++ /dev/null @@ -1,53 +0,0 @@ -#include - -#include "internal.h" - -dc_account_t dc_api_account_from_json(json_t *j) -{ - dc_account_t user = dc_account_new(); - json_t *val = NULL; - - goto_if_true(!json_is_object(j), error); - - val = json_object_get(j, "username"); - goto_if_true(val == NULL || !json_is_string(val), error); - dc_account_set_username(user, json_string_value(val)); - - val = json_object_get(j, "discriminator"); - goto_if_true(val == NULL || !json_is_string(val), error); - dc_account_set_discriminator(user, json_string_value(val)); - - val = json_object_get(j, "id"); - goto_if_true(val == NULL || !json_is_string(val), error); - dc_account_set_id(user, json_string_value(val)); - - return user; - -error: - - dc_unref(user); - return NULL; -} - -json_t *dc_api_account_to_json(dc_account_t a) -{ - json_t *j = NULL; - - return_if_true(a == NULL, NULL); - return_if_true(dc_account_username(a) == NULL || - dc_account_discriminator(a) == NULL, - NULL - ); - - j = json_object(); - return_if_true(j == NULL, NULL); - - json_object_set_new(j, "username", - json_string(dc_account_username(a)) - ); - json_object_set_new(j, "discriminator", - json_string(dc_account_discriminator(a)) - ); - - return j; -} diff --git a/libdc/src/channel.c b/libdc/src/channel.c new file mode 100644 index 0000000..946dbf1 --- /dev/null +++ b/libdc/src/channel.c @@ -0,0 +1,227 @@ +#include + +#include "internal.h" + +struct dc_channel_ +{ + dc_refable_t ref; + + dc_channel_type_t type; + + /* snowflake of the channel + */ + char *id; + + /* Guild ID this channel belongs to, may be NULL + */ + char *guild_id; + + /* Name of the channel + */ + char *name; + + /* Slaneeshi filth? + */ + bool nsfw; + + /* ID of last message in the channel + */ + char *last_message_id; + + /* list of recipients, array of dc_account_t + */ + GPtrArray *recipients; + + /* Snowflake of the owner + */ + char *owner_id; + + /* ID of the parent channel or bot + */ + char *parent_id; + + /* application ID of the group DM creator if it is bot-created + */ + char *application_id; +}; + +static void dc_channel_free(dc_channel_t c) +{ + return_if_true(c == NULL,); + + free(c->id); + free(c->guild_id); + free(c->name); + free(c->last_message_id); + free(c->owner_id); + free(c->parent_id); + free(c->application_id); + + if (c->recipients != NULL) { + g_ptr_array_unref(c->recipients); + c->recipients = NULL; + } + + free(c); +} + +dc_channel_t dc_channel_new(void) +{ + dc_channel_t c = calloc(1, sizeof(struct dc_channel_)); + return_if_true(c == NULL, NULL); + + c->ref.cleanup = (dc_cleanup_t)dc_channel_free; + + c->recipients = g_ptr_array_new_with_free_func( + (GDestroyNotify)dc_unref + ); + + return dc_ref(c); +} + +dc_channel_t dc_channel_from_json(json_t *j) +{ + json_t *v = NULL; + + dc_channel_t c = dc_channel_new(); + + goto_if_true(!json_is_object(j), error); + + v = json_object_get(j, "id"); + goto_if_true(v == NULL || !json_is_string(v), error); + c->id = strdup(json_string_value(v)); + + v = json_object_get(j, "type"); + goto_if_true(v == NULL || !json_is_integer(v), error); + c->type = json_integer_value(v); + + v = json_object_get(j, "guild_id"); + if (v != NULL && json_is_string(v)) { + c->guild_id = strdup(json_string_value(v)); + } + + v = json_object_get(j, "name"); + if (v == NULL && json_is_string(v)) { + c->name = strdup(json_string_value(v)); + } + + v = json_object_get(j, "nsfw"); + if (v != NULL && json_is_boolean(v)) { + c->nsfw = json_boolean_value(v); + } + + v = json_object_get(j, "last_message_id"); + if (v != NULL && json_is_string(v)) { + c->last_message_id = strdup(json_string_value(v)); + } + + v = json_object_get(j, "owner_id"); + if (v != NULL && json_is_string(v)) { + c->owner_id = strdup(json_string_value(v)); + } + + v = json_object_get(j, "parent_id"); + if (v != NULL && json_is_string(v)) { + c->parent_id = strdup(json_string_value(v)); + } + + v = json_object_get(j, "application_id"); + if (v != NULL && json_is_string(v)) { + c->application_id = strdup(json_string_value(v)); + } + + v = json_object_get(j, "recipients"); + if (v != NULL && json_is_array(v)) { + json_t *i = NULL; + size_t idx = 0; + + json_array_foreach(v, idx, i) { + dc_account_t a = dc_account_from_json(i); + if (a != NULL) { + g_ptr_array_add(c->recipients, a); + } + } + } + + return c; + +error: + + dc_unref(c); + return NULL; +} + +json_t *dc_channel_to_json(dc_channel_t c) +{ + json_t *j = NULL; + + return_if_true(c->id == NULL, NULL); + + j = json_object(); + return_if_true(j == NULL, NULL); + + /* I was so close in making a J_SET() macro for my lazy ass. + */ + json_object_set_new(j, "id", json_string(c->id)); + json_object_set_new(j, "type", json_integer(c->type)); + + /* TODO: tribool to see if it was actually set, or assume "false" + * is a sane default and continue on. + */ + json_object_set_new(j, "nsfw", json_boolean(c->nsfw)); + + if (c->guild_id != NULL) { + json_object_set_new(j, "guild_id", json_string(c->guild_id)); + } + + if (c->name != NULL) { + json_object_set_new(j, "name", json_string(c->name)); + } + + if (c->last_message_id != NULL) { + json_object_set_new(j, "last_message_id", + json_string(c->last_message_id)); + } + + if (c->owner_id != NULL) { + json_object_set_new(j, "owner_id", json_string(c->owner_id)); + } + + if (c->parent_id != NULL) { + json_object_set_new(j, "parent_id", json_string(c->parent_id)); + } + + if (c->application_id != NULL) { + json_object_set_new(j, "application_id", + json_string(c->application_id)); + } + + if (c->recipients != NULL && c->recipients->len > 0) { + size_t i = 0; + json_t *arr = json_array(); + + for (i = 0; i < c->recipients->len; i++) { + dc_account_t acc = g_ptr_array_index(c->recipients, i); + json_t *a = dc_account_to_json(acc); + if (a != NULL) { + json_array_append_new(arr, a); + } + } + + json_object_set_new(j, "recipients", arr); + } + + return j; +} + +dc_channel_type_t dc_channel_type(dc_channel_t c) +{ + return_if_true(c == NULL, -1); + return c->type; +} + +void dc_channel_set_type(dc_channel_t c, dc_channel_type_t t) +{ + return_if_true(c == NULL,); + c->type = t; +} diff --git a/libdc/src/internal.h b/libdc/src/internal.h index 9c967c4..8ad02e4 100644 --- a/libdc/src/internal.h +++ b/libdc/src/internal.h @@ -30,10 +30,4 @@ #define return_if_true(v,r) do { if (v) return r; } while(0) #define goto_if_true(v,l) do { if (v) goto l; } while(0) -/* These are internal helper methods, their ABI, and API stability - * is not garuanteed. So please beware - */ -json_t *dc_api_account_to_json(dc_account_t a); -dc_account_t dc_api_account_from_json(json_t *j); - #endif