summaryrefslogtreecommitdiffstats
path: root/src/api.c
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2021-09-17 14:36:09 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2021-09-17 14:36:09 +0200
commit876b012e1aae1cfc9687536edc302987ce899963 (patch)
tree8ac295bc789cf7eafacd52b9cc45bc433906fe99 /src/api.c
parentnot tested yet, but added parsing users: myself and friends (diff)
downloaddiscord.c-876b012e1aae1cfc9687536edc302987ce899963.tar
discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar.gz
discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar.bz2
discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar.lz
discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar.xz
discord.c-876b012e1aae1cfc9687536edc302987ce899963.tar.zst
discord.c-876b012e1aae1cfc9687536edc302987ce899963.zip
Diffstat (limited to 'src/api.c')
-rw-r--r--src/api.c109
1 files changed, 59 insertions, 50 deletions
diff --git a/src/api.c b/src/api.c
index 850ae30..1107d53 100644
--- a/src/api.c
+++ b/src/api.c
@@ -44,7 +44,8 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re
pass->packet = atoi(ctx->buf);
break;
case DC_JSON_PING:
- pass->api_io.client->ping_interval = atoi(ctx->buf);
+ fprintf(stderr, "found ping interval %d\n", atoi(ctx->buf)/1000-5);
+ pass->api_io.client->ping_interval = atoi(ctx->buf)/1000-5;
break;
default: /* to prevent warning: enumeration value DC_JSON_* not handled */
break;
@@ -60,43 +61,41 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char /* enum lejp_callbacks */ re
pass->api_io.type = DC_API_USER;
dc_api_stack(pass->api_io); /* inform api user */
}
- if (reason & LEJP_FLAG_CB_IS_VALUE)
- switch (cp[0]) { /* email is already set from login */
+ if (reason & LEJP_FLAG_CB_IS_VALUE && cp[0])
+ switch (cp[1]) { /* email is already set from login */
case 'u': /* sername */
- free(client->user->username);
- client->user->username = strdup(ctx->buf);
+ if (!client->user->username) client->user->username = strdup(ctx->buf);
break;
case 'i': /* d */
- client->user->id = strtoull(ctx->buf, NULL, 10);
+ if (!client->user->id) client->user->id = strtoull(ctx->buf, NULL, 10);
break;
- case 'd': /* iscriminator */
- client->user->discriminator = atoi(ctx->buf);
+ 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 ((cp = startswith(ctx->path, dc_json_paths[DC_JSON_FRIEND]))) {
if (!client->user) /* for the client user */
client->user = dc_user_init();
- struct dc_user * user = client->user->next; /* client->user->next is 1. friend */
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 */
- } else {
- free(pass->api_io.user); /* just in case */
- pass->api_io.user = NULL;
}
if (reason == LEJPCB_OBJECT_END) {
- while (user->next)
+ 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 = user->next = pass->api_io.user;
+ 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 */
+ pass->api_io.user = NULL; /* we're done, NULL it or PROBLEMS WILL APPEAR!!! */
}
- if (reason & LEJP_FLAG_CB_IS_VALUE)
- switch(cp[0]) {
+ if (reason & LEJP_FLAG_CB_IS_VALUE && cp[0])
+ switch(cp[1]) {
case 'u': /* sername */
free(pass->api_io.user->username); /* yup, we don't trust serv */
pass->api_io.user->username = strdup(ctx->buf);
@@ -176,9 +175,6 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
return 1;
}
lws_client_http_body_pending(wsi, 0);
- if (pass->api_io.status & DC_MUST_FREE)
- free(pass->body);
- pass->body = NULL;
pass->body_length = 0;
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
@@ -200,16 +196,11 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
#endif
break;
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: /* chunked body, without headers */
- fprintf(stderr, "RECEIVE_CLIENT_HTTP_READ: read %d\n", len);
- lwsl_hexdump_notice(in, len); /* for debugging purposes, kek */
- if (!(pass->api_io.status & DC_MUST_FREE)) { /* we start filling the ->body */
- pass->api_io.status |= DC_MUST_FREE; /* buffer, on end of wsi session */
- pass->body = NULL; /* dc_api_i is called from DC_CALLBACK_WSI_DESTROY */
- } /* if ->body from input was not freed and it should be, res body is appended */
- pass->body_length += len; /* if ->body was static, pointer is changed to NULL */
- pass->body = realloc(pass->body, pass->body_length + 1); /* normally - no edge */
- memcpy(pass->body+pass->body_length-len, in, len); /* case - resp body will be */
- pass->body[pass->body_length] = '\0'; /* on heap and freed on _DESTROY. */
+ fprintf(stderr, "RECEIVE_CLIENT_HTTP_READ: read %d, current pass->body_length %d\n", len, pass->body_length);
+ pass->body = realloc(pass->body, pass->body_length + len + 1);
+ memcpy(pass->body+pass->body_length, in, len);
+ pass->body[(pass->body_length += len)] = '\0';
+ fprintf(stderr, "contents of pass->body: %s\n", pass->body);
return 0; /* don't pass to lws_callback_http_dummy */
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: /* uninterpreted http content */
;
@@ -229,12 +220,12 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
case LWS_CALLBACK_WSI_DESTROY: /* if I understand the docs correctly, this is allways */
if (pass->api_io.pass != pass)
fprintf(stderr, "[!!!] REPORT THIS BUG: pass->api_io.pass != pass\n");
- pass->api_io.status |= DC_FROM_LWS;
- dc_api_i(pass->api_io);
- pass->api_io.status &= ~DC_FROM_LWS;
- fprintf(stderr, "pass before freed is %p\n", (void *) pass);
- if (pass->api_io.status & DC_MUST_FREE) /* we still do this check in case */
- free(pass->body); /* _READ was not called and pointer was static */
+ if (pass->api_io.status & DC_DESTROY_CB) {
+ pass->api_io.status |= DC_FROM_LWS;
+ 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 */
break; /* accessible - we can free the struct that was passed in as a heap ptr */
@@ -252,6 +243,16 @@ 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;
break;
+ case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
+ pass->reason = 0;
+ if (len < 2)
+ fprintf(stderr, "SERVER CLOSED CONNECTION WITHOUT PROIVIDING REASON!\n");
+ else
+ pass->reason = ntohs(*(uint16_t *) in /* i sure hope this is legal */);
+ fprintf(stderr, "SERVER CLOSED CONNECTION WITH REASON %d\n", pass->reason);
+ if (len > 2)
+ fprintf(stderr, "with additional message: %.*s\n", len-2, (char *) in+2);
+ break;
case LWS_CALLBACK_CLIENT_CLOSED: /* websocket closed */
DC_API_IO_GC(pass->api_io); /* frees all unfinished parsing objects */
pass->packet = DC_NONE;
@@ -262,8 +263,8 @@ 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 ? */
- fprintf(stdout, "%.*s", len, (const unsigned char *) in);
- fflush(stdout);
+ if (getenv("DC_N"))
+ 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;
pass->packet = DC_NONE;
@@ -274,13 +275,19 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us,
lejp_parse(&pass->json_ctx, (const unsigned char *) in, len);
break;
case LWS_CALLBACK_CLIENT_WRITEABLE: /* invoke with lws_callback_on_writeable(wsi) 4 ws */
- memcpy(buf+LWS_PRE, pass->body, pass->body_length);
- (buf+LWS_PRE)[pass->body_length] = '\0';
- lwsl_hexdump_notice(buf+LWS_PRE, pass->body_length);
- if (lws_write(wsi, (unsigned char *) buf+LWS_PRE, pass->body_length, LWS_WRITE_BINARY) != (int) pass->body_length) {
+ if (!pass->api_io.client)
+ break;
+ if (!pass->api_io.client->payloads_length)
+ break;
+ char * body = pass->api_io.client->payloads[--pass->api_io.client->payloads_length]->body;
+ size_t length = pass->api_io.client->payloads[pass->api_io.client->payloads_length]->length;
+ fprintf(stderr, "going to write to ws: %.*s\n", length, body);
+ if (lws_write(wsi, (unsigned char *) body, length, LWS_WRITE_BINARY) != (int) length) { /* body already has LWS_PRE bytes allocated before it */
fprintf(stderr, "ws lws_write failed!\n");
return -1;
}
+ dc_payload_free(pass->api_io.client->payloads[pass->api_io.client->payloads_length]);
+ pass->api_io.client->payloads[pass->api_io.client->payloads_length] = NULL; /* dc_ws_pop(); */
break;
default:
break;
@@ -319,7 +326,7 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun
info.method = "POST";
pass = calloc(1, sizeof(struct dc_lws_pass)); /* cb frees */
fprintf(stderr, "allocated pass at %p\n", (void *) pass);
- i.status |= DC_MUST_FREE;
+ i.status |= DC_DESTROY_CB; /* so that lws_cb will call api on destroy - fin rq */
pass->body_length = smprintf(&pass->body, DC_LOGIN_FORMAT, i.client->email, i.client->password);
fprintf(stderr, "length: %u string: %s\n", pass->body_length, pass->body);
i.type = DC_API_LOGIN_CB;
@@ -385,6 +392,7 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun
pass = calloc(1, sizeof(struct dc_lws_pass));
i.type = DC_API_WS_CB;
i.status |= DC_SET_PASS;
+ i.status &= ~DC_DESTROY_CB; /* this is only for http requests */
memcpy(&pass->api_io, &i, sizeof(i));
pass->api_io.pass = pass;
info.userdata = pass;
@@ -400,14 +408,13 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun
case DC_API_WS_CB:
i.client->status &= ~(DC_NET_ERROR | DC_OK);
i.client->status |= i.status;
- if (i.status & DC_NET_ERROR)
+ if (i.status & DC_NET_ERROR) { /* pass and pass->body were freed on _DESTROY */
fprintf(stderr, "websocket connection was closed by the remote host\n");
- else { /* commerce identify */
- if (i.pass->api_io.status & DC_MUST_FREE)
- free(i.pass->body);
- i.pass->api_io.status |= DC_MUST_FREE;
- i.pass->body_length = smprintf(&i.pass->body, DC_IDENTIFY_FORMAT, i.client->authorization, DC_INTENTS);
- lws_callback_on_writable(i.pass->wsi);
+ i.pass = NULL; /* pass was/will be freed on _DESTROY, discard it! */
+ } else { /* commerce identify */
+ struct dc_payload * p = calloc(1, sizeof(struct dc_payload));
+ p->length = smprintf(&p->body, DC_IDENTIFY_FORMAT, i.client->authorization, DC_INTENTS); /* body buffer to identify packet */
+ dc_ws_stack(i.client, p);
}
dc_api_stack(i); /* cl.stat is either NET_ERROR 4 closed or error or OK 4 esta */
break;
@@ -438,6 +445,8 @@ struct dc_api_io dc_api_o (struct dc_api_io i /* for ->program */) {
if (i.program->api_ios_length) {
memcpy(&o, (i.program->api_ios[--i.program->api_ios_length]), sizeof(o));
dc_api_io_free(i.program->api_ios[i.program->api_ios_length]);
+ i.program->api_ios[i.program->api_ios_length] = NULL;
+
}
int is_broken = 0;
for (size_t j = 0; j < i.program->attached_functions_length; j++) { /* call attached functions */