summaryrefslogtreecommitdiffstats
path: root/src/h.c
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2021-09-18 21:33:34 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2021-09-18 21:33:34 +0200
commit93a241fc7d93aad6ad26857472d80ec58adae3d8 (patch)
treea499822c015bfe82bfd9cc18ca6a8ed6cc0bc624 /src/h.c
parentwow, this is really going somewhere (diff)
downloaddiscord.c-93a241fc7d93aad6ad26857472d80ec58adae3d8.tar
discord.c-93a241fc7d93aad6ad26857472d80ec58adae3d8.tar.gz
discord.c-93a241fc7d93aad6ad26857472d80ec58adae3d8.tar.bz2
discord.c-93a241fc7d93aad6ad26857472d80ec58adae3d8.tar.lz
discord.c-93a241fc7d93aad6ad26857472d80ec58adae3d8.tar.xz
discord.c-93a241fc7d93aad6ad26857472d80ec58adae3d8.tar.zst
discord.c-93a241fc7d93aad6ad26857472d80ec58adae3d8.zip
Diffstat (limited to 'src/h.c')
-rw-r--r--src/h.c108
1 files changed, 98 insertions, 10 deletions
diff --git a/src/h.c b/src/h.c
index 8e6a56c..dd1ba21 100644
--- a/src/h.c
+++ b/src/h.c
@@ -39,6 +39,8 @@ enum dc_status { /* theese are flags and should be and-checked */
DC_SET_PASS = 1 << 16, /* whether _CREATE _cb shall set client->passs. api sets on _WS create */
DC_IN_PROGRESS = 1 << 17, /* object is in parsing (by json_cb) */
DC_DESTROY_CB = 1 << 18, /* wether cb shall call api on DESTROY (used for http responses) */
+ DC_MAY_FREE = 1 << 19, /* whether dc_*_add() shall free passed in pointer if found one in ISA */
+ DC_WS_ACTIVE = 1 << 20, /* set at API_WS so that api_o will reconnect WS if connection dropps */
DC_INTERNAL = DC_FROM_LWS | DC_FROM_API, /* call originates from an internal function */
}; /* note: when checking status, first check for DC_OK, if it's set then disregard errors! */
enum dc_permissions { /* other permissions exist, but are not implemented/understood */
@@ -158,8 +160,17 @@ enum dc_json_paths { /* lws reduces the following char array to uint8_t, so we c
DC_JSON_S, /* packet sequence number */
DC_JSON_PING, /* interval */
DC_JSON_ME, /* never useful in path parser, but startswith() checks if we're in object */
+ DC_JSON_ME_USERNAME,
+ DC_JSON_ME_ID,
+ DC_JSON_ME_DISCRIMINATOR,
DC_JSON_FRIEND, /* never useful in path parser, but startswith() checks if we're in object */
DC_JSON_DM, /* never useful in path parser, but startswith() checks if we're in object */
+ DC_JSON_DM_TYPE,
+ DC_JSON_DM_ID,
+ DC_JSON_DM_USER, /* never useful in path parser, but startswith() checks if we're in object */
+ DC_JSON_DM_USER_NAME,
+ DC_JSON_DM_USER_ID,
+ DC_JSON_DM_USER_DISCRIMINATOR,
DC_JSON_PATHS_LENGTH
};
char * dc_json_paths[] = { /* array of paths we are interested in */
@@ -167,8 +178,17 @@ char * dc_json_paths[] = { /* array of paths we are interested in */
"s",
"d.heartbeat_interval",
"d.user", /* NOTE: presence updates have same format, so only set own user once */
+ "d.user.username",
+ "d.user.id",
+ "d.user.discriminator",
"d.relationships[].user",
- "d.private_channels[]"
+ "d.private_channels[]",
+ "d.private_channels[].type",
+ "d.private_channels[].id",
+ "d.private_channels[].recipients[]",
+ "d.private_channels[].recipients[].username",
+ "d.private_channels[].recipients[].id",
+ "d.private_channels[].recipients[].discriminator"
};
struct dc_lws_pass { /* struct that is allocated for in dc_lws_cb unique per connection in void * us */
DC_STRUCT_PREFIX
@@ -214,17 +234,20 @@ struct dc_client {
char * email; /* yesfree */
char * password; /* yesfree */
struct dc_user * user; /* nofree - logged in user */
- struct dc_guild * guild; /* nofree - first guild */
enum dc_status status;
struct dc_lws_pass * pass; /* pass of ws. _cb sets it on CREATE and NULLs on DESTROY */
unsigned long long int last_packet; /* last packet sequence number for ping */
time_t ping_interval;
time_t last_ping;
- DC_ISASQ(payload); /* array of payloads we must send over ws */
+ DC_ISASQ(payload); /* yesfree - array of payloads we must send over ws */
+ DC_ISASQ(guild); /* yesfree array of pointers only - guilds of this user */
+ DC_ISASQ(user); /* yesfree array of pointers only - friends of this user */
};
struct dc_client * dc_client_init () {
struct dc_client * s = calloc(1, sizeof(*s));
DC_ISASIQ(payload);
+ DC_ISASIQ(guild);
+ DC_ISASIQ(user);
return s;
}
void dc_client_free (struct dc_client * s) {
@@ -234,6 +257,8 @@ void dc_client_free (struct dc_client * s) {
free(s->email);
free(s->password);
DC_ISAF(payload);
+ free(s->guilds);
+ free(s->users);
free(s);
}
void dc_ws_stack(struct dc_client * c, struct dc_payload * p) { /* we could just use pass->body and */
@@ -249,12 +274,10 @@ void dc_ws_stack(struct dc_client * c, struct dc_payload * p) { /* we could just
struct dc_guild {
DC_STRUCT_PREFIX
char * name; /* yesfree */
- char * alternative_messages_url; /* yesfree, internal - for virtual DMs guild */
unsigned long long int id; /* 0 for virtual DMs guild */
struct dc_client * client; /* nofree */
- struct dc_guild * next; /* nofree - next guild (linked list of all guilds of dc_client) */
struct dc_channel * channel; /* nofree - first channel */
- struct dc_role * role; /* nofree - first role. NOTE: first role is always role with role ID that is same as guild ID and it is the @everyone role */
+ struct dc_role * role; /* nofree - first role. NOTE: 1. role->id == guild->id (@everyone role) */
enum dc_permissions permissions;
enum dc_status status;
#ifdef DC_UI_GTK
@@ -271,7 +294,6 @@ void dc_guild_free (struct dc_guild * s) {
if (!s)
return;
free(s->name);
- free(s->alternative_messages_url);
free(s);
}
struct dc_channel {
@@ -285,6 +307,7 @@ struct dc_channel {
struct dc_message * message; /* nofree - first message (ordered by time) */
struct dc_permission * permission; /* nofree - first permission */
enum dc_status status;
+ DC_ISASQ(user); /* yesfree array only - participants in DM channels */
#ifdef DC_UI_GTK
GtkTreeIter iter; /* see notes of struct dc_guild */
gboolean is_iter; /* XXX use this with caution: only if it's possible for treemodels to contains orphans, this works. otherwise, parents will be removed first and then channels will not het their is_iters invalidated. guild's is_iter will always get invalidated. file:///usr/share/doc/libgtk-3-doc/gtk3/GtkTreeStore.html#gtk-tree-store-iter-is-valid could be a solution but it's said to be slow. */
@@ -292,6 +315,7 @@ struct dc_channel {
};
struct dc_channel * dc_channel_init () {
struct dc_channel * s = calloc(1, sizeof(*s));
+ DC_ISASIQ(user);
return s;
}
void dc_channel_free (struct dc_channel * s) {
@@ -299,6 +323,7 @@ void dc_channel_free (struct dc_channel * s) {
return;
free(s->name);
free(s->topic);
+ free(s->users);
free(s);
}
struct dc_message {
@@ -366,8 +391,6 @@ struct dc_user {
unsigned long long int id;
short int discriminator;
enum dc_status status;
- char * path; /* yesfree, internal, so parser knows what object this user is from */
- struct dc_user * next; /* nofree, next friend in ll of friends, first is client->user->next */
};
struct dc_user * dc_user_init () {
struct dc_user * s = calloc(1, sizeof(*s));
@@ -377,7 +400,6 @@ void dc_user_free (struct dc_user * s) {
if (!s)
return;
free(s->username);
- free(s->path);
free(s);
}
struct dc_permission { /* permissions can be individual on a per-channel basis */
@@ -417,6 +439,13 @@ void dc_attached_function_free (struct dc_attached_function * s) {
return;
free(s);
}
+void dc_lws_pass_free (struct dc_lws_pass * s) {
+ if (!s)
+ return;
+ free(s->body);
+ DC_API_IO_GC(s->api_io);
+ free(s);
+}
static int dc_lws_cb (struct lws *, enum lws_callback_reasons, void *, void *, size_t);
static const struct lws_protocols dc_lws_protocols[] = {
{"dc", dc_lws_cb, /* sizeof(struct dc_lws_pass) */ 0 /* lws naj NE ALOCIRA */, DC_LWS_MAX_RX, 0, NULL, 0},
@@ -509,3 +538,62 @@ void dc_program_free (struct dc_program * s) {
lws_context_destroy(s->lws_context); /* closes all connections and destroys all wsis */
free(s);
}
+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) { \
+ for (size_t i = 0; i < l; i++) \
+ if (p[i]->id == id) { \
+ fprintf(stderr, "id %llu was found!\n", id); \
+ return p[i]; \
+ } \
+ return NULL; \
+}
+#define DC_FIND_LL_X(x) struct dc_##x * dc_find_ll_##x(struct dc_##x * u, unsigned long long int id) { \
+ struct dc_##x ** z = &u; \
+ if (!u) \
+ return NULL; \
+ while (*z) { \
+ if ((*z)->id == id) \
+ return *z; \
+ z = &(*z)->next; \
+ } \
+ return NULL; \
+} /* 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; \
+ if ((us = dc_find_##x(*p, *l, u->id))) { \
+ if (s & DC_MAY_FREE) { \
+ dc_##x##_free(u); \
+ fprintf(stderr, "debug: %s freed already existing member\n", __func__); \
+ } \
+ return us; \
+ } \
+ if (*so <= *l) { \
+ *so = ceil(*so*DC_REALLOC_K); \
+ *p = realloc(*p, sizeof(**p) * *so); \
+ fprintf(stderr, "debug: %s resized ISA\n", __func__); \
+ } \
+ (*p)[(*l)++] = u; \
+ return u; \
+}
+#define DC_ADDR_X(x, y) struct dc_##x * dc_addr_##x (struct dc_program * p, struct dc_##x *** a, size_t * so, size_t * l, struct dc_##x * u, enum dc_status s) { \
+ struct dc_##x * us; \
+ if (!a) { \
+ if (u == (us = dc_add_##x(&p->x##s, &p->x##s_sizeof, &p->x##s_length, u, s))) \
+ return us; \
+ } else \
+ if (u == (us = dc_add_##x(a, so, l, u, s))) \
+ return us; \
+ struct dc_api_io io; \
+ memset(&io, 0, sizeof(io)); \
+ io.type = DC_API_##y; \
+ io.program = p; \
+ io.x = u; \
+ dc_api_stack(io); \
+ return u; \
+} /* add with report */
+#define DC_GEN_X(x, y) DC_FIND_X(x) DC_ADD_X(x) DC_ADDR_X(x, y)
+DC_GEN_X(user, USER)
+DC_GEN_X(channel, CHANNEL)
+DC_FIND_LL_X(channel)
+#define DC_ISAE(a) &a, &a##_sizeof, &a##_length /* ISA Expand */
+#define DC_ISAN NULL, NULL, NULL /* ISA NULL */