diff options
Diffstat (limited to '')
-rw-r--r-- | src/api.c | 179 |
1 files changed, 91 insertions, 88 deletions
@@ -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: |