summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2021-09-26 22:27:42 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2021-09-26 22:27:42 +0200
commitda015427f35fb249e5b94f8d9b35474ec53be47b (patch)
treec3d7f42e95089cce9e3b47235341e4a135fc472c
parentgrem spat (diff)
downloaddiscord.c-da015427f35fb249e5b94f8d9b35474ec53be47b.tar
discord.c-da015427f35fb249e5b94f8d9b35474ec53be47b.tar.gz
discord.c-da015427f35fb249e5b94f8d9b35474ec53be47b.tar.bz2
discord.c-da015427f35fb249e5b94f8d9b35474ec53be47b.tar.lz
discord.c-da015427f35fb249e5b94f8d9b35474ec53be47b.tar.xz
discord.c-da015427f35fb249e5b94f8d9b35474ec53be47b.tar.zst
discord.c-da015427f35fb249e5b94f8d9b35474ec53be47b.zip
-rw-r--r--README.md4
-rw-r--r--src/api.c170
-rw-r--r--src/h.c57
3 files changed, 200 insertions, 31 deletions
diff --git a/README.md b/README.md
index 36647f4..6c28aa0 100644
--- a/README.md
+++ b/README.md
@@ -79,6 +79,10 @@ completing this task would make `discord.c` the first and the only alternative c
it would be useful to have an android port, and luckily this is possible with little effort due to the GTK broadway backend that interfaces with a HTML renderer, WebView for example.
+### misc
+
+* message attachments
+
## developer notes
* use an `i386` compatible machine with `debian` `bullseye` (I use a Dell Latitude D620)
diff --git a/src/api.c b/src/api.c
index a9d9f77..afbdfd8 100644
--- a/src/api.c
+++ b/src/api.c
@@ -31,7 +31,8 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
struct dc_client * client = pass->api_io.client;
struct dc_program * program = pass->api_io.program;
pass->json_reason = reason;
- if (reason == LEJPCB_FAILED || reason == LEJPCB_COMPLETE || reason == LEJPCB_START) {
+ if (reason == LEJPCB_FAILED || reason == LEJPCB_START || (reason == LEJPCB_COMPLETE && pass->packet != DC_MESSAGE_CREATE /* hack for lejp bug with wrong path on OBJECT_END */)) {
+ if (reason == LEJPCB_COMPLETE)
DC_API_IO_GC(pass->api_io);
pass->packet = DC_NONE;
return '\0';
@@ -59,7 +60,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
break;
case DC_JSON_T:
for (size_t i = 0; i < sizeof(dc_ws_packet)/sizeof(dc_ws_packet[0]); i++)
- if (strcmp(dc_ws_packet[i], ctx->buf)) {
+ if (!strcmp(dc_ws_packet[i], ctx->buf)) {
pass->packet = DC_STRPKTOFF+i;
break;
}
@@ -129,9 +130,10 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
}
pass->api_io.user = NULL;
}
- if ((path == DC_JSON_DM || path == DC_JSON_GUILD_CHANNEL) && reason == LEJPCB_OBJECT_START) {
+ if ((path == DC_JSON_DM || path == DC_JSON_GUILD_CHANNEL || path == DC_JSON_MESSAGE_MENTION_CHANNEL) && reason == LEJPCB_OBJECT_START) {
pass->api_io.channel = dc_channel_init();
pass->api_io.channel->status |= DC_IN_PROGRESS;
+ pass->api_io.id = 0;
}
if (path == DC_JSON_DM && reason == LEJPCB_OBJECT_END) {
struct dc_channel ** channel = &client->guilds[0]->channel; /* 1. guild = DMs */
@@ -166,20 +168,23 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
pass->api_io.channel->guild = client->guilds[0];
pass->api_io.channel = NULL; /* we're done, NULL it or PROBLEMS WILL APPEAR!!! */
}
- if (path == DC_JSON_GUILD_CHANNEL && reason == LEJPCB_OBJECT_END) {
- if (!pass->api_io.channel->id || !DC_CHANNEL_SUPPORTED(pass->api_io.channel->type)) {
+ if ((path == DC_JSON_GUILD_CHANNEL || path == DC_JSON_MESSAGE_MENTION_CHANNEL || path == DC_JSON_MESSAGE_REFOBJ_MENTION_CHANNEL) && reason == LEJPCB_OBJECT_END) {
+ struct dc_guild * gu = NULL;
+ if (!pass->api_io.channel->id || !DC_CHANNEL_SUPPORTED(pass->api_io.channel->type) || (path == DC_JSON_MESSAGE_MENTION_CHANNEL && (!pass->api_io.id || !(gu = dc_find_guild(program->guilds, program->guilds_length, pass->api_io.id)))) || (path == DC_JSON_MESSAGE_REFOBJ_MENTION_CHANNEL && (!pass->api_io.id || !(gu = dc_find_guild(program->guilds, program->guilds_length, pass->api_io.id))))) {
dc_channel_free(pass->api_io.channel, DC_UNSET);
pass->api_io.channel = NULL;
return '\0';
}
- struct dc_channel ** channel = &pass->api_io.guild->channel;
+ if (!gu)
+ gu = pass->api_io.guild;
+ struct dc_channel ** channel = &gu->channel;
while (*channel)
channel = &(*channel)->next;
struct dc_channel * ch;
if ((ch = dc_find_channel(program->channels, program->channels_length, pass->api_io.channel->id)))
DC_TRANSFER_CHANNEL(pass->api_io.channel, ch);
pass->api_io.channel = dc_addr_channel(program, DC_ISAE(program->channels), pass->api_io.channel, DC_MAY_FREE | DC_REPLACE);
- if (!dc_find_ll_channel(pass->api_io.guild->channel, pass->api_io.channel->id)) {
+ if (!dc_find_ll_channel(gu->channel, pass->api_io.channel->id)) {
fprintf(stderr, "new channel id=%llu (:\n", pass->api_io.channel->id);
pass->api_io.channel->next = NULL;
*channel = pass->api_io.channel;
@@ -189,6 +194,19 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
(*pe)->channel = pass->api_io.channel;
pe = &(*pe)->next;
}
+ switch (path) {
+ case DC_JSON_MESSAGE_MENTION_CHANNEL:
+ if (pass->api_io.message)
+ dc_add_channel(DC_ISAE(pass->api_io.message->channels), pass->api_io.channel, DC_UNSET);
+ pass->api_io.id = 0;
+ break;
+ case DC_JSON_MESSAGE_REFOBJ_MENTION_CHANNEL:
+ if (pass->api_io.message && pass->api_io.message->reply)
+ dc_add_channel(DC_ISAE(pass->api_io.message->reply->channels), pass->api_io.channel, DC_UNSET);
+ pass->api_io.id = 0;
+ default:
+ break;
+ }
pass->api_io.channel = NULL; /* we're done, NULL it or */
}
if (path == DC_JSON_GUILD && reason == LEJPCB_OBJECT_START) {
@@ -233,7 +251,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
struct dc_role * ro;
if ((ro = dc_find_role(program->roles, program->roles_length, pass->api_io.role->id)))
dc_transfer_role(pass->api_io.role, ro);
- pass->api_io.role = dc_add_role(DC_ISAE(program->roles), pass->api_io.role, DC_MAY_FREE | DC_REPLACE);
+ pass->api_io.role = dc_addr_role(program, DC_ISAE(program->roles), pass->api_io.role, DC_MAY_FREE | DC_REPLACE);
struct dc_role ** role;
role = &pass->api_io.guild->role;
while (*role)
@@ -250,6 +268,69 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
}
if (path == DC_JSON_MEMBERSHIP && (reason == LEJPCB_OBJECT_END || reason == LEJPCB_OBJECT_START))
pass->api_io.id = 0;
+ if (pass->packet == DC_MESSAGE_CREATE && reason == LEJPCB_COMPLETE) {
+ pass->api_io.message = dc_message_init();
+ pass->api_io.message->reply = dc_message_init();
+ pass->api_io.message->reply->status |= DC_IN_PROGRESS;
+ pass->api_io.message->status |= DC_IN_PROGRESS;
+ }
+ if (pass->packet == DC_MESSAGE_CREATE && pass->api_io.message && path == DC_JSON_MESSAGE && reason == LEJPCB_COMPLETE /* hack for lejp bug with wrong path on OBJECT_END */ ) {
+ struct dc_message * me;
+ if (!pass->api_io.message->id || !pass->api_io.message->channel || !DC_MESSAGE_SUPPORTED(pass->api_io.message->type)) {
+ dc_message_free(pass->api_io.message, DC_UNSET);
+ pass->api_io.message = NULL;
+ return '\0';
+ }
+ if (pass->api_io.message->reply) {
+ if (!pass->api_io.message->reply->id || !pass->api_io.message->reply->channel || !DC_MESSAGE_SUPPORTED(pass->api_io.message->reply->type)) {
+ dc_message_free(pass->api_io.message->reply, DC_UNSET);
+ pass->api_io.message->reply = NULL;
+ }
+ pass->api_io.message->reply->status &= ~DC_IN_PROGRESS;
+ pass->api_io.message->reply->time = DC_ID2TIME(pass->api_io.message->reply->id);
+ if ((me = dc_find_message(program->messages, program->messages_length, pass->api_io.message->reply->id)))
+ dc_transfer_message(pass->api_io.message, me);
+ pass->api_io.message->reply = dc_addr_message(program, DC_ISAE(program->messages), pass->api_io.message->reply, DC_MAY_FREE | DC_REPLACE);
+ struct dc_message ** message = &pass->api_io.message->reply->channel->message;
+ while (*message) {
+ if ((*message)->time < pass->api_io.message->reply->time && (*message)->next && (*message)->next->time > pass->api_io.message->reply->time)
+ break;
+ message = &(*message)->next;
+ }
+ if (!dc_find_ll_message(pass->api_io.message->reply->channel->message, pass->api_io.message->reply->id)) {
+ fprintf(stderr, "new message reply id=%llu (:\n", pass->api_io.message->reply->id);
+ if (*message) {
+ pass->api_io.message->reply->next = (*message)->next;
+ (*message)->next = pass->api_io.message->reply;
+ } else {
+ pass->api_io.message->reply->next = NULL;
+ *message = pass->api_io.message->reply;
+ }
+ }
+ }
+ pass->api_io.message->status &= ~DC_IN_PROGRESS;
+ pass->api_io.message->time = DC_ID2TIME(pass->api_io.message->id);
+ if ((me = dc_find_message(program->messages, program->messages_length, pass->api_io.message->id)))
+ dc_transfer_message(pass->api_io.message, me);
+ pass->api_io.message = dc_addr_message(program, DC_ISAE(program->messages), pass->api_io.message, DC_MAY_FREE | DC_REPLACE);
+ struct dc_message ** message = &pass->api_io.message->channel->message;
+ while (*message) {
+ if ((*message)->time < pass->api_io.message->time && (*message)->next && (*message)->next->time > pass->api_io.message->time) /* if *message is not NULL, */
+ break; /* we should insert new message after message into linked list */
+ message = &(*message)->next; /* otherwise just insert at the end */
+ }
+ if (!dc_find_ll_message(pass->api_io.message->channel->message, pass->api_io.message->id)) {
+ fprintf(stderr, "new message id=%llu (:\n", pass->api_io.message->id);
+ if (*message) {
+ pass->api_io.message->next = (*message)->next; /* based linked lists */
+ (*message)->next = pass->api_io.message;
+ } else {
+ pass->api_io.message->next = NULL;
+ *message = pass->api_io.message;
+ }
+ }
+ pass->api_io.message = NULL;
+ }
if (reason & LEJP_FLAG_CB_IS_VALUE) {
struct dc_user * user; /* this is just a var for you use */
struct dc_role * role; /* now we rely on -Wuninitialized to detect weird stuff */
@@ -269,36 +350,50 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
case DC_JSON_ME_USERNAME: /* we are always checking for user because evil srv */
case DC_JSON_USER_NAME: /* might insert dots in keys and prevent OBJECT_CREATE */
case DC_JSON_MEMBER_USERNAME:
+ case DC_JSON_MESSAGE_AUTHOR_USERNAME:
if (pass->api_io.user && !pass->api_io.user->username) /* no trust srv */
pass->api_io.user->username = strdup(ctx->buf);
break;
case DC_JSON_ME_ID:
case DC_JSON_USER_ID:
case DC_JSON_MEMBER_ID:
+ case DC_JSON_MESSAGE_AUTHOR_ID:
if (pass->api_io.user)
pass->api_io.user->id = strtoll(ctx->buf, NULL, 10);
break;
case DC_JSON_ME_DISCRIMINATOR:
case DC_JSON_USER_DISCRIMINATOR:
case DC_JSON_MEMBER_DISCRIMINATOR:
+ case DC_JSON_MESSAGE_AUTHOR_DISCRIMINATOR:
if (pass->api_io.user)
pass->api_io.user->discriminator = atoi(ctx->buf);
break; /* yeah, we don't care about nicknames */
case DC_JSON_DM_TYPE:
case DC_JSON_GUILD_CHANNEL_TYPE:
+ case DC_JSON_MESSAGE_MENTION_CHANNEL_TYPE:
+ case DC_JSON_MESSAGE_REFOBJ_MENTION_CHANNEL_TYPE:
if (pass->api_io.channel)
pass->api_io.channel->type = atoi(ctx->buf);
break;
case DC_JSON_DM_ID:
case DC_JSON_GUILD_CHANNEL_ID:
+ case DC_JSON_MESSAGE_MENTION_CHANNEL_ID:
+ case DC_JSON_MESSAGE_REFOBJ_MENTION_CHANNEL_ID:
if (pass->api_io.channel)
pass->api_io.channel->id = strtoull(ctx->buf, NULL, 10);
break;
case DC_JSON_DM_NAME:
case DC_JSON_GUILD_CHANNEL_NAME:
+ case DC_JSON_MESSAGE_MENTION_CHANNEL_NAME:
+ case DC_JSON_MESSAGE_REFOBJ_MENTION_CHANNEL_NAME:
if (pass->api_io.channel && !pass->api_io.channel->name)
pass->api_io.channel->name = strdup(ctx->buf);
break;
+ case DC_JSON_MESSAGE_MENTION_CHANNEL_GUILD:
+ case DC_JSON_MESSAGE_REFOBJ_MENTION_CHANNEL_GUILD:
+ if (pass->api_io.channel)
+ pass->api_io.id = strtoull(ctx->buf, NULL, 10);
+ break;
case DC_JSON_GUILD_NAME:
if (pass->api_io.guild && !pass->api_io.guild->name)
pass->api_io.guild->name = strdup(ctx->buf);
@@ -341,20 +436,75 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
if (!(user = dc_find_user(program->users, program->users_length, pass->api_io.id))) {
št |= 1;
user = dc_user_init();
+ user->id = pass->api_io.id;
}
if (!(role = dc_find_role(program->roles, program->roles_length, id))) {
št |= 2;
role = dc_role_init();
role->id = id;
}
+ if (!dc_find_user(role->users, role->users_length, user->id))
+ fprintf(stderr, "new role membership user %s#%d (usr=%llu role=%llu)\n", user->username ? user->username : "", user->discriminator, user->id, role->id);
dc_add_user(DC_ISAE(role->users), user, DC_UNSET);
if (št & 1)
dc_addr_user(program, DC_ISAE(program->users), user, DC_UNSET);
if (št & 2)
dc_addr_role(program, DC_ISAE(program->roles), role, DC_UNSET);
- fprintf(stderr, "new role membership user %s#%d (usr=%llu role=%llu)\n", user->username ? user->username : "", user->discriminator, user->id, role->id);
pass->api_io.id = 0;
break;
+ case DC_JSON_MESSAGE_ID:
+ if (pass->api_io.message)
+ pass->api_io.message->id = strtoull(ctx->buf, NULL, 10);
+ break;
+ case DC_JSON_MESSAGE_TYPE:
+ if (pass->api_io.message)
+ pass->api_io.message->type = atoi(ctx->buf);
+ break;
+ case DC_JSON_MESSAGE_CHANNEL:
+ if (pass->api_io.message)
+ pass->api_io.message->channel = dc_find_channel(program->channels, program->channels_length, strtoull(ctx->buf, NULL, 10)); /* if we don't find it, too bad, we won't store msg */
+ break;
+ case DC_JSON_MESSAGE_CONTENT:
+ if (pass->api_io.message) { /* lejp parses in chunks of 256, msg is 2k */
+ if (!pass->api_io.message->message) /* so we don't have garbag */
+ pass->api_io.message->message = strdup("");
+ pass->api_io.message->message = realloc(pass->api_io.message->message, strlen(pass->api_io.message->message)+strlen(ctx->buf)+1);
+ strcat(pass->api_io.message->message, ctx->buf);
+ }
+ break;
+ case DC_JSON_MESSAGE_MENTION_ROLE:
+ if (pass->api_io.message) {
+ struct dc_role * role = dc_find_role(program->roles, program->roles_length, strtoull(ctx->buf, NULL, 10));
+ if (role)
+ dc_add_role(DC_ISAE(pass->api_io.message->roles), role, DC_UNSET);
+ }
+ break;
+ case DC_JSON_MESSAGE_REFOBJ_MENTION_ROLE:
+ if (pass->api_io.message && pass->api_io.message->reply) {
+ struct dc_role * role = dc_find_role(program->roles, program->roles_length, strtoull(ctx->buf, NULL, 10));
+ if (role)
+ dc_add_role(DC_ISAE(pass->api_io.message->reply->roles), role, DC_UNSET);
+ }
+ break;
+ case DC_JSON_MESSAGE_REFOBJ_ID:
+ if (pass->api_io.message && pass->api_io.message->reply)
+ pass->api_io.message->reply->id = strtoull(ctx->buf, NULL, 10);
+ break;
+ case DC_JSON_MESSAGE_REFOBJ_TYPE:
+ if (pass->api_io.message && pass->api_io.message->reply)
+ pass->api_io.message->reply->type = atoi(ctx->buf);
+ break;
+ case DC_JSON_MESSAGE_REFOBJ_CHANNEL:
+ if (pass->api_io.message && pass->api_io.message->reply)
+ pass->api_io.message->reply->channel = dc_find_channel(program->channels, program->channels_length, strtoull(ctx->buf, NULL, 10));
+ break;
+ case DC_JSON_MESSAGE_REFOBJ_CONTENT:
+ if (pass->api_io.message && pass->api_io.message->reply) {
+ if (!pass->api_io.message->reply->message)
+ pass->api_io.message->reply->message = strdup("");
+ pass->api_io.message->reply->message = realloc(pass->api_io.message->reply->message, strlen(pass->api_io.message->reply->message)+strlen(ctx->buf)+1);
+ strcat(pass->api_io.message->reply->message, ctx->buf);
+ }
default:
break;
}
@@ -362,8 +512,6 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
if (pass->packet == DC_NONE) /* useless to do anything BELOW if we haven't recvd packet type */
return '\0';
switch (pass->packet) {
- case DC_MESSAGE_CREATE:
- break;
default:
break;
}
diff --git a/src/h.c b/src/h.c
index 7ace971..81d7179 100644
--- a/src/h.c
+++ b/src/h.c
@@ -16,6 +16,7 @@
#define DC_LWS_MAX_FD 64 /* max file descriptors LWS will have open. if unset, LWS acquires all unused */
#define DC_LWS_MAX_HEADER_LENGTH 64 /* _MAX_HEADER_LENGTH*_HEADERS_LENGTH is allocated for every reque */
#define DC_WS_PING_FORMAT "{\"op\":1,\"d\":%lld}"
+#define DC_ID2TIME(x) ((x >> 22 /* this gives us ms since 2015 */)/1000 + 1420070400 /* UNIX 2015 */)
#ifdef DC_UI_GTK
#define DC_IF_UI_GTK(...) __VA_ARGS__
#else
@@ -71,12 +72,11 @@ enum dc_ws_packet { /* op numbers of websocket packets or json objects in other
DC_PING = 1,
DC_STRPKTOFF = 100, /* here follow string types (t) */
DC_NONE = DC_STRPKTOFF + 0, /* unknown packet or packet type not yet defermined */
- DC_MESSAGE_CREATE = DC_STRPKTOFF + 0,
+ DC_MESSAGE_CREATE = DC_STRPKTOFF + 1,
}; /* intents enum was removed - intents're for bots, clients have capabilities - are not understood */
char * dc_ws_packet[] = {
"",
- "MESSAGE_CREATE",
- ""
+ "MESSAGE_CREATE"
};
enum dc_message_type { /* other types exist, but are not implemented/understood, same values as server */
DC_MESSAGE = 0,
@@ -136,14 +136,19 @@ struct dc_api_io { /* output struct does NOT contain void * data (user pointer)
struct dc_lws_pass * pass;
unsigned long long int id;
};
-#define DC_API_IO_MEMB_GC(m, t) if (m && m->status & DC_IN_PROGRESS) { \
- t##_free(m, DC_UNSET); \
- m = NULL; } \
+#define DC_API_IO_MEMB_GC(m, t) do { \
+ if (m && m->status & DC_IN_PROGRESS) { \
+ t##_free(m, DC_UNSET); \
+ m = NULL; \
+ } \
if (m && m->status & DC_EXPLICIT_NULL) { \
m->status &= ~DC_EXPLICIT_NULL; \
m = NULL; \
- }
-#define DC_API_IO_GC(s) do { /* this is called if: json_cb will start parsing another before callback, */ \
+ } \
+ } while (0)
+#define DC_API_IO_GC(s) do { /* this is called if: */ \
+ if (s.message) \
+ DC_API_IO_MEMB_GC(s.message->reply, dc_message); \
DC_API_IO_MEMB_GC(s.message, dc_message); /* WS connection closed, meaning json_cb */ \
DC_API_IO_MEMB_GC(s.channel, dc_channel); /* will never be called again */ \
DC_API_IO_MEMB_GC(s.guild, dc_guild); \
@@ -220,8 +225,8 @@ enum dc_json_paths { /* lws reduces the following char array to uint8_t, so we c
DC_JSON_MEMBER_ID,
DC_JSON_MEMBER_DISCRIMINATOR,
DC_JSON_MEMBER_ROLE, /* id, array */
- DC_JSON_MESSAGE,
- DC_JSON_MESSAGE_ATTACHMENTS,
+ DC_JSON_MESSAGE, /* also check if pass->packet == DC_MESSAGE_CREATE */
+ DC_JSON_MESSAGE_ATTACHMENTS, /* not implemented yet */
DC_JSON_MESSAGE_ID,
DC_JSON_MESSAGE_TYPE,
DC_JSON_MESSAGE_CHANNEL, /* id */
@@ -230,8 +235,8 @@ enum dc_json_paths { /* lws reduces the following char array to uint8_t, so we c
DC_JSON_MESSAGE_AUTHOR_USERNAME,
DC_JSON_MESSAGE_AUTHOR_DISCRIMINATOR,
DC_JSON_MESSAGE_AUTHOR_ID,
- DC_JSON_MESSAGE_REFERENCE, /* id */
- DC_JSON_MESSAGE_MENTION_CHANNEL, /* TODO: implement role and user mentions fetching */
+ DC_JSON_MESSAGE_REFERENCE, /* id, not implemented, only DC_JSON_MESSAGE_REFOBJ is used */
+ DC_JSON_MESSAGE_MENTION_CHANNEL,
DC_JSON_MESSAGE_MENTION_CHANNEL_ID,
DC_JSON_MESSAGE_MENTION_CHANNEL_GUILD, /* id */
DC_JSON_MESSAGE_MENTION_CHANNEL_NAME,
@@ -241,6 +246,7 @@ enum dc_json_paths { /* lws reduces the following char array to uint8_t, so we c
DC_JSON_MESSAGE_MENTION_USER_ROLE,
DC_JSON_MESSAGE_MENTION_USER_ID,
DC_JSON_MESSAGE_MENTION_USER_DISCRIMINATOR,
+ DC_JSON_MESSAGE_MENTION_ROLE, /* id, array */
DC_JSON_MESSAGE_REFOBJ, /* server only sends reference object one level deep */
DC_JSON_MESSAGE_REFOBJ_ATTACHMENTS,
DC_JSON_MESSAGE_REFOBJ_ID,
@@ -263,6 +269,7 @@ enum dc_json_paths { /* lws reduces the following char array to uint8_t, so we c
DC_JSON_MESSAGE_REFOBJ_MENTION_USER_ROLE,
DC_JSON_MESSAGE_REFOBJ_MENTION_USER_ID,
DC_JSON_MESSAGE_REFOBJ_MENTION_USER_DISCRIMINATOR,
+ DC_JSON_MESSAGE_REFOBJ_MENTION_ROLE, /* id */
DC_JSON_PATHS_LENGTH /* we have 256 max length, because that's what library supports */
};
char * dc_json_paths[] = { /* array of paths we are interested in */
@@ -327,11 +334,12 @@ char * dc_json_paths[] = { /* array of paths we are interested in */
"d.mention_channels[].type",
"d.mentions[]",
"d.mentions[].username",
- "d.mentions[].member.roles[]",
+ "d.mentions[].member.roles",
"d.mentions[].id",
"d.mentions[].discriminator",
+ "d.mentions[].mention_roles",
"d.referenced_message",
- "d.referenced_message.attachments[]",
+ "d.referenced_message.attachments",
"d.referenced_message.id",
"d.referenced_message.type",
"d.referenced_message.channel_id",
@@ -340,7 +348,7 @@ char * dc_json_paths[] = { /* array of paths we are interested in */
"d.referenced_message.author.username",
"d.referenced_message.author.discriminator",
"d.referenced_message.author.id",
- "d.referenced_message.member.roles[]",
+ "d.referenced_message.member.roles",
"d.referenced_message.message_reference", /* this is ID */
"d.referenced_message.mention_channels[]",
"d.referenced_message.mention_channels[].id",
@@ -349,9 +357,10 @@ char * dc_json_paths[] = { /* array of paths we are interested in */
"d.referenced_message.mention_channels[].type",
"d.referenced_message.mentions[]",
"d.referenced_message.mentions[].username",
- "d.referenced_message.mentions[].member.roles[]",
+ "d.referenced_message.mentions[].member.roles",
"d.referenced_message.mentions[].id",
"d.referenced_message.mentions[].discriminator",
+ "d.referenced_message.mention_roles"
};
struct dc_lws_pass { /* struct that is allocated for in dc_lws_cb unique per connection in void * us */
DC_STRUCT_PREFIX
@@ -505,14 +514,14 @@ void dc_channel_free (struct dc_channel * s, enum dc_status t) {
struct dc_message {
DC_STRUCT_PREFIX
char * message; /* yesfree */
- char * attachment; /* yesfree - this is a HTTP URL. it would be nice to request file and store to ~/.cache/discord.c/ and only then use (RENDER IMAGE) from disk */
struct dc_channel * channel; /* nofree */
struct dc_user * user; /* nofree */
- time_t time;
+ time_t time; /* obtained with DC_ID2TIME, edited timestamp is in ISO string format&not implemt */
unsigned long long int id;
struct dc_message * next; /* next message (linked list of all messages of dc_channel) */
struct dc_message * reply; /* nofree - this message replies to another message or NULL */
enum dc_status status;
+ enum dc_message_type type;
DC_ISASQ(user); /* yesfree pointer array only - mentions */
DC_ISASQ(role); /* yesfree pointer array only - mentions */
DC_ISASQ(channel); /* yesfree pointer array only - mentions */
@@ -528,10 +537,9 @@ void dc_message_free (struct dc_message * s, enum dc_status t) {
if (!s)
return;
free(s->message);
- free(s->attachment);
free(s->users);
free(s->roles);
- free(s->channel);
+ free(s->channels);
if (!(t & DC_REPLACE))
free(s);
}
@@ -715,6 +723,7 @@ void dc_program_free (struct dc_program * s, enum dc_status t) {
}
void dc_api_stack (struct dc_api_io);
#define DC_FIND_X(x) struct dc_##x * dc_find_##x(struct dc_##x ** p, size_t l, unsigned long long int id) { \
+ assert(id); \
for (size_t i = 0; i < l; i++) \
if (p[i]->id == id) { \
/* fprintf(stderr, "id %llu was found!\n", id); */ /* too much */ \
@@ -735,6 +744,7 @@ void dc_api_stack (struct dc_api_io);
} /* untested, not sure if works!!! */
#define DC_ADD_X(x) struct dc_##x * dc_add_##x (struct dc_##x *** p, size_t * so, size_t * l, struct dc_##x * u, enum dc_status s) { \
struct dc_##x * us; \
+ assert(u); \
if ((us = dc_find_##x(*p, *l, u->id))) { \
/* fprintf(stderr, "debug: %s found already existing member\n", __func__); */ \
if (us == u) \
@@ -782,6 +792,8 @@ DC_FIND_LL_X(channel)
DC_GEN_X(guild, GUILD)
DC_GEN_X(role, ROLE)
DC_FIND_LL_X(role)
+DC_GEN_X(message, MESSAGE)
+DC_FIND_LL_X(message)
#define DC_ISAE(a) &(a), &(a##_sizeof), &(a##_length) /* ISA Expand */
#define DC_ISAN NULL, NULL, NULL /* ISA NULL */
#define DC_TRANSFER_CHANNEL(n, o) do { /* n is going to DC_REPLACE o, transfer important data */ \
@@ -810,3 +822,8 @@ void dc_transfer_role (struct dc_role * n, struct dc_role * o) {
o->users_length = 0;
}
}
+void dc_transfer_message (struct dc_message * n, struct dc_message * o) {
+ n->next = o->next;
+ if (!n->reply)
+ n->reply = o->reply;
+}