summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2021-09-21 23:05:01 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2021-09-21 23:05:01 +0200
commit47da9bbedc7b30202fda404880a4d8762fcaf8ce (patch)
treeb2975506a46b733e12ca0320d66313bcd80d40f0
parentuntested, compiles (diff)
downloaddiscord.c-47da9bbedc7b30202fda404880a4d8762fcaf8ce.tar
discord.c-47da9bbedc7b30202fda404880a4d8762fcaf8ce.tar.gz
discord.c-47da9bbedc7b30202fda404880a4d8762fcaf8ce.tar.bz2
discord.c-47da9bbedc7b30202fda404880a4d8762fcaf8ce.tar.lz
discord.c-47da9bbedc7b30202fda404880a4d8762fcaf8ce.tar.xz
discord.c-47da9bbedc7b30202fda404880a4d8762fcaf8ce.tar.zst
discord.c-47da9bbedc7b30202fda404880a4d8762fcaf8ce.zip
-rw-r--r--Makefile2
-rw-r--r--README.md2
-rw-r--r--debian/control2
-rw-r--r--src/api.c179
-rw-r--r--src/h.c116
-rw-r--r--src/identify.json2
-rw-r--r--src/lib.c1
-rw-r--r--src/main.c1
8 files changed, 160 insertions, 145 deletions
diff --git a/Makefile b/Makefile
index 167d75a..9eae4b4 100644
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@ clean:
rm discord.c tmp -f
prepare:
- sudo apt install build-essential libwebsockets-dev libcjson-dev libsoundio-dev libgtk-3-dev xxd -y
+ apt install build-essential libwebsockets-dev libcjson-dev libsoundio-dev libgtk-3-dev xxd -y
# developing is to be done on i386. for example the default suppression file is hardcoded for i386 here:
# developing is to be done on bullseye. we download gtk.supp even though debian ships it, because that's how we "get rid of" more leaks.
diff --git a/README.md b/README.md
index b2d21a7..48ab1f6 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ make
* ~~`libsoundio-dev` for crossplatform sound io~~
* ~~`libopus-dev` for sound encoding~~
* ~~`libsodium-dev` for encrypting UDP packets to server~~
-* `xxd` for embedding XML GtkBuilder UI definitions directly in the binary
+* `xxd` for embedding files inside binary (via C unsigned char arrays without messing with object files)
## automatic building
diff --git a/debian/control b/debian/control
index 7ecbc03..0360e22 100644
--- a/debian/control
+++ b/debian/control
@@ -9,6 +9,8 @@ Build-Depends: debhelper (>=11~),
libwebsockets-dev,
libgtk-3-dev,
libsoundio-dev,
+ libopus-dev,
+ libsodium-dev,
gcc,
make
Standards-Version: 4.1.4
diff --git a/src/api.c b/src/api.c
index 20d7b4f..c8b44bc 100644
--- a/src/api.c
+++ b/src/api.c
@@ -25,11 +25,12 @@ void dc_api_stack (struct dc_api_io i) { /* stack output struct to be delivered
*(i.program->api_ios[i.program->api_ios_length++]) = i;
return;
}
-signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ reason) {
+signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warnings of incompatible pointer times, we create a new type with enum later on */
enum dc_json_paths path = ctx->path_match-1; /* we assume that the order of incoming data is */
struct dc_lws_pass * pass = ctx->user; /* correct. op and t should come first, etc. */
struct dc_client * client = pass->api_io.client;
struct dc_program * program = pass->api_io.program;
+ struct dc_user * user; /* don't confuse this with client->user, this is just a var for you use */
pass->json_reason = reason;
if (reason == LEJPCB_FAILED || reason == LEJPCB_COMPLETE || reason == LEJPCB_START) {
if (pass->parsing_status)
@@ -39,7 +40,8 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re
pass->parsing_status = NULL;
return '\0';
}
- fprintf(stderr, "JSON: %s %s\n", ctx->path, ctx->buf);
+ if (getenv("DC_J")) /* print json to standard error */
+ fprintf(stderr, "JSON: %s %s\n", ctx->path, ctx->buf);
if (ctx->path_match && reason & LEJP_FLAG_CB_IS_VALUE) {
switch (path) {
case DC_JSON_S: /* packet sequence number */
@@ -69,10 +71,10 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re
default: /* to prevent warning: enumeration value DC_JSON_* not handled */
break;
}
- return '\0';
}
- if (startswith(ctx->path, dc_json_paths[DC_JSON_ME]) && reason & LEJP_FLAG_CB_IS_VALUE
- && (!client->user || !client->user->username || !client->user->id || client->user->status & DC_INCOMPLETE)) { /* if filled, then it's someone else */
+ if (reason & LEJP_FLAG_CB_IS_VALUE && (path == DC_JSON_ME_USERNAME || path == DC_JSON_ME_ID || path == DC_JSON_ME_DISCRIMINATOR) && (!client->user || !client->user->username || !client->user->id || client->user->status & DC_INCOMPLETE)) { /* if filled, then it's someone else */
+ if (getenv("DC_R")) /* detect user parser */
+ raise(SIGINT);
if (!client->user) { /* on first d.user this is our user, subsequent are someone else! */
DC_MR(program->users); /* don't need DC_IN_PROGRESS, we have ref in cl */
program->users[program->users_length++] = client->user = dc_user_init();
@@ -89,6 +91,8 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re
if (client->user->status & DC_INCOMPLETE) { /* we can't just check if */
client->user->discriminator = atoi(ctx->buf); /* !discriminat, */
client->user->status &= ~DC_INCOMPLETE; /* because 0 is allowd */
+ if (getenv("DC_C"))
+ dc_interrupted++;
}
break;
default:
@@ -96,64 +100,32 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re
}
return '\0'; /* because we use same checks for parsing other users GUILD_MEMBER_UPDATE */
}
- if (startswith(ctx->path, dc_json_paths[DC_JSON_FRIEND]) || startswith(ctx->path, dc_json_paths[DC_JSON_ME])) {
- if ((path == DC_JSON_FRIEND || path == DC_JSON_ME) && reason == LEJPCB_OBJECT_START) {
- /* dc_user_free(pass->api_io.user); */ /* parser branches MUST ALWAYS set to 0 */
- pass->api_io.user = dc_user_init(); /* and possibly free api_io members after! */
- pass->api_io.user->status |= DC_IN_PROGRESS; /* if we never get here again */
- }
- if (path == DC_JSON_FRIEND && reason == LEJPCB_OBJECT_END) { /* if that's a friend */
- pass->api_io.user = dc_addr_user(program, DC_ISAE(program->users), pass->api_io.user, DC_MAY_FREE);
- if (!dc_find_user(client->users, client->users_length, pass->api_io.user->id)) {
- fprintf(stderr, "got a new friend (: %s#%d %llu\n", pass->api_io.user->username ? pass->api_io.user->username : "NULL", pass->api_io.user->discriminator, pass->api_io.user->id);
- pass->api_io.user = dc_add_user(DC_ISAE(client->users), pass->api_io.user, DC_UNSET); /* already reported, already inserted in program, nof */
- pass->api_io.user->status &= ~(DC_IN_PROGRESS);
- }
- pass->api_io.user = NULL; /* we're done, NULL it or PROBLEMS WILL APPEAR!!! */
- }
- if (path == DC_JSON_ME && reason == LEJPCB_OBJECT_END) { /* if it was just a user */
- pass->api_io.user = dc_addr_user(program, DC_ISAE(program->users), pass->api_io.user, DC_MAY_FREE);
- pass->api_io.user = NULL;
- }
- if (reason & LEJP_FLAG_CB_IS_VALUE && pass->api_io.user)
- switch(path) {
- case DC_JSON_FRIEND_USERNAME:
- if (!pass->api_io.user->username) /* yup, we don't trust serv */
- pass->api_io.user->username = strdup(ctx->buf);
- break;
- case DC_JSON_FRIEND_ID:
- pass->api_io.user->id = strtoll(ctx->buf, NULL, 10);
- break;
- case DC_JSON_FRIEND_DISCRIMINATOR:
- pass->api_io.user->discriminator = atoi(ctx->buf);
- break; /* yeah, we don't care about nicknames */
- default:
- break;
- }
+ if ((path == DC_JSON_ME || path == DC_JSON_USER || path == DC_JSON_MESSAGE_AUTHOR || path == DC_JSON_MESSAGE_REFOBJ_AUTHOR || path == DC_JSON_MESSAGE_MENTION_USER || path == DC_JSON_MESSAGE_REFOBJ_MENTION_USER) && reason == LEJPCB_OBJECT_START) { /* user parsing start */
+ /* dc_user_free(pass->api_io.user); */ /* parser branches MUST ALWAYS set to 0 */
+ pass->api_io.user = dc_user_init(); /* and possibly free api_io members after! */
+ pass->api_io.user->status |= DC_IN_PROGRESS; /* if we never get here again */
}
- if (startswith(ctx->path, dc_json_paths[DC_JSON_DM])) {
- if (!client->guilds_length) {
- DC_MR(program->guilds);
- DC_MR(client->guilds);
- program->guilds[program->guilds_length++] = client->guilds[0] = dc_guild_init();
- client->guilds_length = 1; /* we don't dc_add_guild because id=0 */
- client->guilds[0]->name = strdup("Direct messages"); /* TODO: gettext for i18n */
- client->guilds[0]->client = client;
- }
- if (path == DC_JSON_DM && reason == LEJPCB_OBJECT_START) {
- fprintf(stderr, "new DM start parsing object\n");
- /* dc_channel_free(pass->api_io.channel); */ /* parser branches must not leave */
- pass->api_io.channel = dc_channel_init(); /* behind any content in api_io */
- pass->api_io.channel->status |= DC_IN_PROGRESS;
- pass->api_io.channel->guild = client->guilds[0];
- }
- if (path == DC_JSON_DM && reason == LEJPCB_OBJECT_END) {
- fprintf(stderr, "new DM (:\n");
- struct dc_channel ** channel = &client->guilds[0]->channel; /* 1. guild = DMs */
- while (*channel)
- channel = &(*channel)->next;
- pass->api_io.channel->status &= ~(DC_IN_PROGRESS);
- free(pass->api_io.channel->name);
+ if ((path == DC_JSON_ME || path == DC_JSON_USER || path == DC_JSON_MESSAGE_AUTHOR || path == DC_JSON_MESSAGE_REFOBJ_AUTHOR || path == DC_JSON_MESSAGE_MENTION_USER || path == DC_JSON_MESSAGE_REFOBJ_MENTION_USER) && reason == LEJPCB_OBJECT_END) { /* if it was just a user */
+ pass->api_io.user->status &= ~DC_IN_PROGRESS;
+ pass->api_io.user = dc_addr_user(program, DC_ISAE(program->users), pass->api_io.user, DC_MAY_FREE);
+ if (path != DC_JSON_MESSAGE_AUTHOR && path != DC_JSON_MESSAGE_REFOBJ_AUTHOR && path != DC_JSON_MESSAGE_MENTION_USER && path != DC_JSON_MESSAGE_REFOBJ_MENTION_USER && !getenv("DC_0") /* override if those are disabled */) /* those expect a user parsed */
+ pass->api_io.user = NULL; /* when implementing parser: handle OBJECT_END */
+ else /* if something goes wrong - if those handlers do not null user, IO_MEMB_GC will */
+ pass->api_io.user->status |= DC_EXPLICIT_NULL; /* but will not free. */
+ } /* user parsing end */
+ if (path == DC_JSON_DM && reason == LEJPCB_OBJECT_START) { /* client->guild[0] always */
+ fprintf(stderr, "new DM start parsing object\n"); /* exists */
+ /* dc_channel_free(pass->api_io.channel); */ /* parser branches must not leave */
+ pass->api_io.channel = dc_channel_init(); /* behind any content in api_io */
+ pass->api_io.channel->status |= DC_IN_PROGRESS;
+ pass->api_io.channel->guild = client->guilds[0];
+ }
+ if (path == DC_JSON_DM && reason == LEJPCB_OBJECT_END) {
+ struct dc_channel ** channel = &client->guilds[0]->channel; /* 1. guild = DMs */
+ while (*channel)
+ channel = &(*channel)->next;
+ pass->api_io.channel->status &= ~(DC_IN_PROGRESS);
+ free(pass->api_io.channel->name);
pass->api_io.channel->name = strdup("");
for (size_t i = 0; i < pass->api_io.channel->users_length; i++) {
pass->api_io.channel->name = realloc(pass->api_io.channel->name, strlen(pass->api_io.channel->name)+strlen(pass->api_io.channel->users[i]->username)+1+2+1+4);
@@ -162,27 +134,19 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re
strcat(pass->api_io.channel->name, pass->api_io.channel->users[i]->username);
strcat(pass->api_io.channel->name, buf);
}
- pass->api_io.channel = *channel = dc_addr_channel(program, DC_ISAN, pass->api_io.channel, DC_MAY_FREE | DC_REPLACE);
- if ((*channel = dc_find_ll_channel(client->guilds[0]->channel, pass->api_io.channel->id)))
- if (*channel != pass->api_io.channel) {
- dc_channel_free(pass->api_io.channel, DC_REPLACE);
- memmove(*channel, pass->api_io.channel, sizeof(**channel));
- }
- pass->api_io.channel->guild = client->guilds[0];
- pass->api_io.channel = NULL; /* we're done, NULL it or PROBLEMS WILL APPEAR!!! */
- }
- if (reason & LEJP_FLAG_CB_IS_VALUE && pass->api_io.channel)
- switch (path) {
- case DC_JSON_DM_TYPE:
- pass->api_io.channel->type = atoi(ctx->buf);
- break;
- case DC_JSON_DM_ID:
- pass->api_io.channel->id = strtoull(ctx->buf, NULL, 10);
- break;
- default:
- break;
+ pass->api_io.channel = dc_addr_channel(program, DC_ISAN, pass->api_io.channel, DC_MAY_FREE | DC_REPLACE);
+ fprintf(stderr, "new DM id=%llu (:\n", pass->api_io.channel->id);
+ if ((*channel = dc_find_ll_channel(client->guilds[0]->channel, pass->api_io.channel->id))) {
+ fprintf(stderr, "DM already in LL, id=%llu\n", pass->api_io.channel->id);
+ if (*channel != pass->api_io.channel) {
+ dc_channel_free(*channel, DC_REPLACE);
+ memmove(*channel, pass->api_io.channel, sizeof(**channel));
}
+ }
+ pass->api_io.channel->guild = client->guilds[0];
+ pass->api_io.channel = NULL; /* we're done, NULL it or PROBLEMS WILL APPEAR!!! */
}
+#if 0
if (startswith(ctx->path, dc_json_paths[DC_JSON_DM_USER])) { /* we don't DC_REPLACE here bcoz */
if (path == DC_JSON_DM_USER && reason == LEJPCB_OBJECT_START) { /* users never update. */
pass->api_io.user = dc_user_init();
@@ -213,14 +177,53 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re
}
if (startswith(ctx->path, dc_json_paths[DC_JSON_GUILD])) {
if (path == DC_JSON_GUILD && reason == LEJPCB_OBJECT_START) {
- pass->api_io.guild = dc_guild_init();
- pass->api_io.guild->status |= DC_IN_PROGRESS;
+ /* pass->api_io.guild = dc_guild_init();
+ pass->api_io.guild->status |= DC_IN_PROGRESS; */
}
if (path == DC_JSON_GUILD && reason == LEJPCB_OBJECT_END) {
fprintf(stderr, "new guild");
- pass->api_io.guild = dc_addr_guild(program, DC_ISAE(program->guilds), pass->api_io.guild, DC_MAY_FREE);
+ /* pass->api_io.guild = dc_addr_guild(program, DC_ISAE(program->guilds), pass->api_io.guild, DC_MAY_FREE); */
}
}
+#endif
+ if (reason & LEJP_FLAG_CB_IS_VALUE)
+ switch (path) {
+ case DC_JSON_FRIEND: /* we assume we get users[] before relationships[] */
+ user = dc_find_user(program->users, program->users_length, strtoull(ctx->buf, NULL, 10));
+ if (user)
+ dc_add_user(DC_ISAE(client->users), user, DC_UNSET);
+ break;
+ case DC_JSON_DM_USER: /* we assume we get users[] before private_channels[] */
+ user = dc_find_user(program->users, program->users_length, strtoull(ctx->buf, NULL, 10));
+ if (user && pass->api_io.channel)
+ dc_add_user(DC_ISAE(pass->api_io.channel->users), user,DC_UNSET);
+ break;
+ 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 */
+ 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:
+ 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:
+ 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:
+ if (pass->api_io.channel)
+ pass->api_io.channel->type = atoi(ctx->buf);
+ break;
+ case DC_JSON_DM_ID:
+ if (pass->api_io.channel)
+ pass->api_io.channel->id = strtoull(ctx->buf, NULL, 10);
+ break;
+ default:
+ break;
+ }
if (pass->packet == DC_NONE) /* useless to do anything BELOW if we haven't recvd packet type */
return '\0';
switch (pass->packet) { /* we fill in structs, set DC_INCOMPLETE and pass->parsing_status */
@@ -366,7 +369,7 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
pass->api_io.status &= ~DC_FROM_LWS;
break;
case LWS_CALLBACK_CLIENT_RECEIVE: /* websocket receive, pass to json parser ? */
- if (getenv("DC_N"))
+ if (getenv("DC_N")) /* output received network to stdout */
fprintf(stdout, "%.*s", len, (const unsigned char *) in);
if (pass->json_reason == LEJPCB_COMPLETE || pass->json_reason == LEJPCB_FAILED || !(pass->api_io.status & DC_LEJP_CONSTRUCTED)) { /* we regenerate a new context in case we didn't do that yet or in case the previous one finished parsing */
pass->api_io.status |= DC_LEJP_CONSTRUCTED;
@@ -389,8 +392,8 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
return -1;
}
dc_payload_free(pass->api_io.client->payloads[i], DC_UNSET);
- pass->api_io.client->payloads[i] = NULL;
- }
+ pass->api_io.client->payloads[i] = NULL; /* THIS MUST BE DONE, otherws */
+ } /* _free function will double free, because it frees till _sizeof */
pass->api_io.client->payloads_length = 0;
break;
default:
@@ -478,7 +481,7 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun
goto ws; /* we could call dc_api_i but that just fills stack */
break;
case DC_API_WS:
- if (getenv("DC_R"))
+ if (getenv("DC_R")) /* detect _WS calls */
raise(SIGINT);
fprintf(stderr, "DC_API_WS called\n");
ws:
diff --git a/src/h.c b/src/h.c
index e090c96..1a0988b 100644
--- a/src/h.c
+++ b/src/h.c
@@ -44,6 +44,7 @@ enum dc_status { /* theese are flags and should be and-checked */
DC_NO_WRITE = 1 << 21, /* signaling dc_ws_stack not to call lws_callback_on_writeable */
DC_SET_WS_ACTIVE = 1 << 22, /* whether _CREATE _cb shall set client->status =| DC_WS_ACTIVE */
DC_REPLACE = 1 << 23, /* dc_add_x replace old with new on found, _free: only free members */
+ DC_EXPLICIT_NULL = 1 << 24, /* MEMB_GC will NULL this member (PROGRES?aftr free) (& clear bit) */
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 */
@@ -131,7 +132,11 @@ struct dc_api_io { /* output struct does NOT contain void * data (user pointer)
};
#define DC_API_IO_MEMB_GC(m, t) if (m && m->status & DC_IN_PROGRESS) { \
t##_free(m, DC_UNSET); \
- m = NULL; }
+ 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, */ \
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 */ \
@@ -174,17 +179,15 @@ enum dc_json_paths { /* lws reduces the following char array to uint8_t, so we c
DC_JSON_ME_USERNAME, /* note: _ME is client->user ONLY for first d.user object. subsequent */
DC_JSON_ME_ID, /* packets may contain user objects as well, they are other users */
DC_JSON_ME_DISCRIMINATOR,
- DC_JSON_FRIEND,
- DC_JSON_FRIEND_ID,
- DC_JSON_FRIEND_USERNAME,
- DC_JSON_FRIEND_DISCRIMINATOR,
+ DC_JSON_FRIEND, /* this is the id */
+ DC_JSON_USER, /* list of users at first connect */
+ DC_JSON_USER_ID,
+ DC_JSON_USER_NAME,
+ DC_JSON_USER_DISCRIMINATOR,
DC_JSON_DM,
DC_JSON_DM_TYPE,
DC_JSON_DM_ID,
- DC_JSON_DM_USER,
- DC_JSON_DM_USER_NAME,
- DC_JSON_DM_USER_ID,
- DC_JSON_DM_USER_DISCRIMINATOR,
+ DC_JSON_DM_USER, /* this is the ID */
DC_JSON_GUILD,
DC_JSON_GUILD_NAME,
DC_JSON_GUILD_ID,
@@ -253,21 +256,19 @@ char * dc_json_paths[] = { /* array of paths we are interested in */
"s",
"t",
"d.heartbeat_interval",
- "d.user", /* NOTE: presence updates have same format, so only set own user once */
+ "d.user",
"d.user.username",
"d.user.id",
"d.user.discriminator",
- "d.relationships[].user",
- "d.relationships[].user.id",
- "d.relationships[].user.username",
- "d.relationships[].user.discriminator",
+ "d.relationships[].id",
+ "d.users[]",
+ "d.users[].id",
+ "d.users[].username",
+ "d.users[].discriminator",
"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",
+ "d.private_channels[].recipients_ids[]",
"d.guilds[]",
"d.guilds[].name",
"d.guilds[].id",
@@ -357,7 +358,10 @@ struct dc_payload * dc_payload_init () {
return s;
}
void dc_payload_free (struct dc_payload * s, enum dc_status t) {
- free(s->body-LWS_PRE);
+ if (!s)
+ return;
+ if (s->body)
+ free(s->body-LWS_PRE);
if (!(t & DC_REPLACE))
free(s);
return;
@@ -366,9 +370,9 @@ void dc_payload_free (struct dc_payload * s, enum dc_status t) {
#define DC_ISAS_INIT(type/* w/o struct */, name) do { name##_sizeof = DC_ALLOC_CHUNK; /* structs ISA */ \
name = calloc(name##_sizeof, sizeof(struct type *)); } while (0) /* prep arr, NO INIT membrs */
#define DC_ISASIQ(shortname) DC_ISAS_INIT(dc_##shortname, s->shortname##s) /* ISAS init quick */
-#define DC_ISAF(shortname) for (size_t i = 0; i < s->shortname##s_sizeof; i++) /* ISA free */ \
- dc_##shortname##_free(s->shortname##s[i], DC_UNSET); \
- free(s->shortname##s); /* no problem if we free past _lenght, as uninited are NULL */
+#define DC_ISAF(shortname) for (size_t i = 0; i < s->shortname##s_sizeof; i++) /* hmm, I used to fre */ \
+ dc_##shortname##_free(s->shortname##s[i], DC_UNSET); /* till _sizeof, but now I fixd */ \
+ free(s->shortname##s); /* to only free till _length. is this problematic in any ways? */
struct dc_client {
DC_STRUCT_PREFIX
char * authorization; /* yesfree - authorization header value */
@@ -385,11 +389,42 @@ struct dc_client {
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_guild {
+ DC_STRUCT_PREFIX
+ char * name; /* yesfree */
+ unsigned long long int id; /* 0 for virtual DMs guild */
+ struct dc_client * client; /* nofree */
+ struct dc_channel * channel; /* nofree - first channel */
+ struct dc_role * role; /* nofree - first role. NOTE: role->id == guild->id => @everyone role */
+ enum dc_permissions permissions;
+ enum dc_status status;
+#ifdef DC_UI_GTK
+ GtkTreeIter iter; /* NOTE: only works when GtkTreeModel has a flag GTK_TREE_MODEL_ITERS_PERSIST; see paragraph 8 of description of file:///usr/share/doc/libgtk-3-doc/gtk3/GtkTreeModel.html */
+ gboolean is_iter;
+ /* GtkTreeRowReference * row; */ /* yesfree - indicating the row */ /* not used: IRC message: "00:51:29 @Company | also: Don't create too many tree row references, those things are slow" */
+#endif
+};
+struct dc_guild * dc_guild_init () {
+ struct dc_guild * s = calloc(1, sizeof(*s));
+ return s;
+}
+void dc_guild_free (struct dc_guild * s, enum dc_status t) {
+ if (!s)
+ return;
+ free(s->name);
+ if (!(t & DC_REPLACE)) /* we do this because we want to keep the pointer intact sometimes and */
+ free(s); /* reused; for example when replacing/updating structs */
+}
struct dc_client * dc_client_init () {
struct dc_client * s = calloc(1, sizeof(*s));
DC_ISASIQ(payload);
DC_ISASIQ(guild);
DC_ISASIQ(user);
+ DC_MR(s->guilds); /* direct messages virtual guild is not in program, to prevent confusion */
+ s->guilds_length = 1; /* because of duplicated 0 id value; freeing is therefore done from */
+ s->guilds[0] = dc_guild_init(); /* dc_client_free */
+ s->guilds[0]->name = strdup("Direct messages"); /* TODO: use gettext or similar for t9ns */
+ s->guilds[0]->client = s;
return s;
}
void dc_client_free (struct dc_client * s, enum dc_status t) {
@@ -399,6 +434,7 @@ void dc_client_free (struct dc_client * s, enum dc_status t) {
free(s->email);
free(s->password);
DC_ISAF(payload);
+ dc_guild_free(s->guilds[0], DC_UNSET); /* see dc_client_init for explanation */
free(s->guilds);
free(s->users);
if (!(t & DC_REPLACE))
@@ -415,32 +451,6 @@ void dc_ws_stack(struct dc_client * c, struct dc_payload * p, enum dc_status s)
lws_callback_on_writable(c->pass->wsi);
return;
}
-struct dc_guild {
- DC_STRUCT_PREFIX
- char * name; /* yesfree */
- unsigned long long int id; /* 0 for virtual DMs guild */
- struct dc_client * client; /* nofree */
- struct dc_channel * channel; /* nofree - first channel */
- struct dc_role * role; /* nofree - first role. NOTE: role->id == guild->id => @everyone role */
- enum dc_permissions permissions;
- enum dc_status status;
-#ifdef DC_UI_GTK
- GtkTreeIter iter; /* NOTE: only works when GtkTreeModel has a flag GTK_TREE_MODEL_ITERS_PERSIST; see paragraph 8 of description of file:///usr/share/doc/libgtk-3-doc/gtk3/GtkTreeModel.html */
- gboolean is_iter;
- /* GtkTreeRowReference * row; */ /* yesfree - indicating the row */ /* not used: IRC message: "00:51:29 @Company | also: Don't create too many tree row references, those things are slow" */
-#endif
-};
-struct dc_guild * dc_guild_init () {
- struct dc_guild * s = calloc(1, sizeof(*s));
- return s;
-}
-void dc_guild_free (struct dc_guild * s, enum dc_status t) {
- if (!s)
- return;
- free(s->name);
- if (!(t & DC_REPLACE)) /* we do this because we want to keep the pointer intact sometimes and */
- free(s); /* reused; for example when replacing/updating structs */
-}
struct dc_channel {
DC_STRUCT_PREFIX
char * name; /* yesfree - name */
@@ -677,8 +687,9 @@ struct dc_program * dc_program_init () {
}
void dc_program_free (struct dc_program * s, enum dc_status t) {
if (!s)
- return;
- DC_ISAF(client);
+ return; /* \/ call first because _cb is called several times during destroy ,,, */
+ lws_context_destroy(s->lws_context); /* closes all connections and destroys all wsis */
+ DC_ISAF(client); /* /\ ,,, and callback handlers (_CLOSED, _DESTROY) may do stuff with memory. */
DC_ISAF(guild);
DC_ISAF(channel);
DC_ISAF(message);
@@ -688,7 +699,6 @@ void dc_program_free (struct dc_program * s, enum dc_status t) {
DC_ISAF(permission);
DC_ISAF(attached_function);
DC_ISAF(api_io);
- lws_context_destroy(s->lws_context); /* closes all connections and destroys all wsis */
if (!(t & DC_REPLACE))
free(s);
}
@@ -715,6 +725,7 @@ void dc_api_stack (struct dc_api_io);
#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))) { \
+ fprintf(stderr, "debug: %s found already existing member\n", __func__); \
if (us == u) \
return us; \
if (s & DC_REPLACE) { \
@@ -726,15 +737,14 @@ void dc_api_stack (struct dc_api_io);
} \
if (s & DC_MAY_FREE) { \
dc_##x##_free(u, DC_UNSET); \
- 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__); \
} \
+ fprintf(stderr, "debug: %s inserted into ISA\n", __func__); \
(*p)[(*l)++] = u; \
return u; \
}
diff --git a/src/identify.json b/src/identify.json
index 571abf1..bf20503 100644
--- a/src/identify.json
+++ b/src/identify.json
@@ -1 +1 @@
-{"op":2,"d":{"token":"%s","capabilities":125,"properties":{"os":"Linux","browser":"Chrome","device":"","system_locale":"en-US","browser_user_agent":"Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36","browser_version":"90.0.4430.212","os_version":"","referrer":"http://of.sijanec.eu:7327/","referring_domain":"of.sijanec.eu:7327","referrer_current":"","referring_domain_current":"","release_channel":"stable","client_build_number":97662,"client_event_source":null},"presence":{"status":"online","since":0,"activities":[{"name":"Custom Status","type":4,"state":"mrt5hg","emoji":null}],"afk":false},"compress":false,"client_state":{"guild_hashes":{},"highest_last_message_id":"0","read_state_version":0,"user_guild_settings_version":-1}}}
+{"op":2,"d":{"token":"%s","capabilities":125,"intents":32767,"properties":{"os":"Linux","browser":"Chrome","device":"","system_locale":"en-US","browser_user_agent":"Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36","browser_version":"90.0.4430.212","os_version":"","referrer":"http://of.sijanec.eu:7327/","referring_domain":"of.sijanec.eu:7327","referrer_current":"","referring_domain_current":"","release_channel":"stable","client_build_number":97662,"client_event_source":null},"presence":{"status":"online","since":0,"activities":[{"name":"Custom Status","type":4,"state":"mrt5hg","emoji":null}],"afk":false},"compress":false,"client_state":{"guild_hashes":{},"highest_last_message_id":"0","read_state_version":0,"user_guild_settings_version":-1}}}
diff --git a/src/lib.c b/src/lib.c
index 989436c..48f185c 100644
--- a/src/lib.c
+++ b/src/lib.c
@@ -1,3 +1,4 @@
+int dc_interrupted = 0;
#ifndef _GNU_SOURCE /* glibc already provides asprintf, but some cucks tend not to use glibc */
int asprintf (char ** str, const char * format, ...) { /* allocates automaticalls (: */
va_list ap, aq; /* */
diff --git a/src/main.c b/src/main.c
index 7288332..b202cdc 100644
--- a/src/main.c
+++ b/src/main.c
@@ -7,7 +7,6 @@
#include <lib.c>
#include <ui.c>
#include <api.c>
-int dc_interrupted;
void dc_signal (int i) {
dc_interrupted++;
return;