summaryrefslogtreecommitdiffstats
path: root/src/api.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/api.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/api.c')
-rw-r--r--src/api.c151
1 files changed, 114 insertions, 37 deletions
diff --git a/src/api.c b/src/api.c
index 1107d53..c0dfc48 100644
--- a/src/api.c
+++ b/src/api.c
@@ -16,7 +16,7 @@
/* libwebsockets information: libwebsockets works with event loops and discord.c primary targets debian for building (it must work on debian), but debian does not ship libwebsockets with glib or libevent event loop support, so loops are implemented in the classic poll() style. this reduces performance probably. if you use discord.c API with support for a platform specific event loop, you may rewrite LWS to do things differently. currently calls into API (dc_api_i and dc_api_o) will both do LWS stuff. */
void dc_api_stack (struct dc_api_io i) { /* stack output struct to be delivered via dc_api_o 2usr */
DC_MR(i.program->api_ios);
- i.program->api_ios[i.program->api_ios_length] = malloc(sizeof(i));
+ assert((i.program->api_ios[i.program->api_ios_length] = malloc(sizeof(i))));
*(i.program->api_ios[i.program->api_ios_length++]) = i;
return;
}
@@ -52,49 +52,48 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re
}
return '\0';
}
- if ((cp = startswith(ctx->path, dc_json_paths[DC_JSON_ME]))) {
+ if (startswith(ctx->path, dc_json_paths[DC_JSON_ME]) && reason & LEJP_FLAG_CB_IS_VALUE) {
if (!client->user) {
- DC_MR(program->users); /* we don't need DC_IN_PROGRESS cause we have ref in cl */
- program->users[program->users_length] = client->user = dc_user_init();
- }
- if (reason & LEJPCB_OBJECT_END) {
- pass->api_io.type = DC_API_USER;
- dc_api_stack(pass->api_io); /* inform api user */
+ 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();
+ client->user->status |= DC_INCOMPLETE; /* when ->disc is set, it's complete */
+ } /* we do not check on the object end */
+ switch (path) { /* email is already set from login */
+ case DC_JSON_ME_USERNAME:
+ if (!client->user->username) client->user->username = strdup(ctx->buf);
+ break;
+ case DC_JSON_ME_ID:
+ if (!client->user->id) client->user->id = strtoull(ctx->buf, NULL, 10);
+ break;
+ case DC_JSON_ME_DISCRIMINATOR:
+ 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 */
+ }
+ break;
+ default:
+ break;
}
- if (reason & LEJP_FLAG_CB_IS_VALUE && cp[0])
- switch (cp[1]) { /* email is already set from login */
- case 'u': /* sername */
- if (!client->user->username) client->user->username = strdup(ctx->buf);
- break;
- case 'i': /* d */
- if (!client->user->id) client->user->id = strtoull(ctx->buf, NULL, 10);
- break;
- case 'd': /* iscriminator */ /* check is for id, discriminator may b 0 */
- if (!client->user->id) client->user->discriminator = atoi(ctx->buf);
- break;
- }
}
if ((cp = startswith(ctx->path, dc_json_paths[DC_JSON_FRIEND]))) {
if (!client->user) /* for the client user */
client->user = dc_user_init();
- if (reason == LEJPCB_OBJECT_START) { /* DC_JSON_FRIEND may not be an object*/
- if (!pass->api_io.user) /* for the newly found friend (-; */
- pass->api_io.user = dc_user_init();
- pass->api_io.user->status &= ~(DC_IN_PROGRESS); /* if we never get here again */
+ if (path == DC_JSON_FRIEND && reason == LEJPCB_OBJECT_START) {
+ dc_user_free(pass->api_io.user); /* for the newly found friend (-; */
+ pass->api_io.user = dc_user_init();
+ pass->api_io.user->status |= DC_IN_PROGRESS; /* if we never get here again */
}
- if (reason == LEJPCB_OBJECT_END) {
- fprintf(stderr, "got a new friend (: %s#%d %llu", pass->api_io.user->username ? pass->api_io.user->username : "NULL", pass->api_io.user->discriminator, pass->api_io.user->id);
- struct dc_user * user = client->user; /* client->user->next is 1. friend */
- while (user->next) /* traverse to last friend */
- user = user->next;
- DC_MR(program->users);
- program->users[program->users_length++] = user->next = pass->api_io.user;
- pass->api_io.user->status &= ~(DC_IN_PROGRESS);
- pass->api_io.type = DC_API_USER;
- dc_api_stack(pass->api_io); /* inform api user */
+ if (path == DC_JSON_FRIEND && reason == LEJPCB_OBJECT_END) {
+ if (dc_find_user(client->users, client->users_length, pass->api_io.user->id) != pass->api_io.user)
+ dc_user_free(pass->api_io.user); /* already have */
+ else {
+ 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_addr_user(program, DC_ISAE(client->users), pass->api_io.user, DC_MAY_FREE);
+ pass->api_io.user->status &= ~(DC_IN_PROGRESS);
+ }
pass->api_io.user = NULL; /* we're done, NULL it or PROBLEMS WILL APPEAR!!! */
}
- if (reason & LEJP_FLAG_CB_IS_VALUE && cp[0])
+ if (reason & LEJP_FLAG_CB_IS_VALUE && cp[0] && pass->api_io.user)
switch(cp[1]) {
case 'u': /* sername */
free(pass->api_io.user->username); /* yup, we don't trust serv */
@@ -108,6 +107,77 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re
break; /* yeah, we don't care about nicknames */
}
}
+ if ((cp = 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;
+ 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);
+ pass->api_io.channel = dc_channel_init();
+ 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");
+ if (dc_find_ll_channel(client->guilds[0]->channel /* checks for NULL */, pass->api_io.channel->id)) {
+ dc_channel_free(pass->api_io.channel);
+ goto already_have;
+ }
+ struct dc_channel ** channel = &client->guilds[0]->channel; /* 1. guild = DMs */
+ while (*channel)
+ channel = &(*channel)->next;
+ pass->api_io.channel->status &= ~(DC_IN_PROGRESS);
+ pass->api_io.channel = *channel = dc_addr_channel(program, DC_ISAN, pass->api_io.channel, DC_MAY_FREE);
+already_have:
+ pass->api_io.channel->next = NULL;
+ 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;
+ }
+ }
+ if ((cp = startswith(ctx->path, dc_json_paths[DC_JSON_DM_USER]))) {
+ if (path == DC_JSON_DM_USER && reason == LEJPCB_OBJECT_START) {
+ if (!pass->api_io.user)
+ pass->api_io.user = dc_user_init();
+ pass->api_io.user->status |= DC_IN_PROGRESS;
+ }
+ if (path == DC_JSON_DM_USER && reason == LEJPCB_OBJECT_END) {
+ fprintf(stderr, "new DM participant (:\n");
+ pass->api_io.user = dc_addr_user(program, DC_ISAE(pass->api_io.channel->users), pass->api_io.user, DC_MAY_FREE);
+ pass->api_io.user->status &= ~(DC_IN_PROGRESS);
+ pass->api_io.user = NULL; /* we're done, NULL it or PROBLEMS WILL APPEAR!!! */
+ }
+ if (reason & LEJP_FLAG_CB_IS_VALUE && cp[0] && pass->api_io.channel)
+ switch (path) {
+ case DC_JSON_DM_USER_ID:
+ pass->api_io.user->id = strtoull(ctx->buf, NULL, 10);
+ break;
+ case DC_JSON_DM_USER_DISCRIMINATOR:
+ pass->api_io.user->discriminator = atoi(ctx->buf);
+ break;
+ case DC_JSON_DM_USER_NAME:
+ if (!pass->api_io.user->username)
+ pass->api_io.user->username = strdup(ctx->buf);
+ break;
+ default:
+ break;
+ }
+ }
if (pass->packet == DC_NONE) /* useless to do anything BELOW if we haven't recvd packet type */
return '\0';
if (reason == LEJPCB_COMPLETE) { /* NOT USED FOR ANYTHING, REMOVE */
@@ -225,9 +295,8 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
dc_api_i(pass->api_io);
pass->api_io.status &= ~DC_FROM_LWS;
}
- free(pass->body); /* body is always allocated on heap! */
pass->api_io.client->pass = NULL;
- free(pass); /* called at the final moment when user pointer and wsi is still */
+ dc_lws_pass_free(pass); /* called at the final time us ptr and wsi is still */
break; /* accessible - we can free the struct that was passed in as a heap ptr */
case LWS_CALLBACK_WSI_CREATE: /* first - outermost - call with wsi present */
if (pass->api_io.client && pass->api_io.status & DC_SET_PASS) {
@@ -400,6 +469,7 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun
strcpy(pass->headers[DC_LWS_AUTHORIZATION], i.client->authorization);
fprintf(stderr, "starting websocket session\n");
i.status = DC_UNSET; /* we clear the status */
+ i.client->status |= DC_WS_ACTIVE;
if (!lws_client_connect_via_info(&info)) {
i.client->status = DC_NET_ERROR;
dc_api_stack(i);
@@ -437,6 +507,13 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun
struct dc_api_io dc_api_o (struct dc_api_io i /* for ->program */) {
if (i.program->lws_context)
lws_service(i.program->lws_context, 0);
+ for (size_t x = 0; x < i.program->clients_length; x++) {
+ if (i.program->clients[x]->status & DC_WS_ACTIVE && !i.program->clients[x]->pass) {
+ i.client = i.program->clients[x];
+ i.type = DC_API_WS;
+ dc_api_i(i);
+ }
+ }
struct dc_api_io o = {
.type = DC_API_NONE,
.program = i.program