diff options
author | Anton Luka Šijanec <anton@sijanec.eu> | 2022-02-25 00:54:36 +0100 |
---|---|---|
committer | Anton Luka Šijanec <anton@sijanec.eu> | 2022-02-25 00:54:36 +0100 |
commit | dc07e4bf7f4628852eee26b114348498caad0182 (patch) | |
tree | 597cce2a6e81a13a959b1beae2508b761ef04773 /src/api.c | |
parent | i suppose parsing json is easyer with cjson than lejp (: (diff) | |
download | discord.c-dc07e4bf7f4628852eee26b114348498caad0182.tar discord.c-dc07e4bf7f4628852eee26b114348498caad0182.tar.gz discord.c-dc07e4bf7f4628852eee26b114348498caad0182.tar.bz2 discord.c-dc07e4bf7f4628852eee26b114348498caad0182.tar.lz discord.c-dc07e4bf7f4628852eee26b114348498caad0182.tar.xz discord.c-dc07e4bf7f4628852eee26b114348498caad0182.tar.zst discord.c-dc07e4bf7f4628852eee26b114348498caad0182.zip |
Diffstat (limited to 'src/api.c')
-rw-r--r-- | src/api.c | 152 |
1 files changed, 106 insertions, 46 deletions
@@ -24,6 +24,17 @@ cJSON_GetObjectItem(cJSON_GetObjectItem3(ro, na1, na2, na3), na4) : NULL) #define cJSON_GetObjectItem5(r, n1, n2, n3, n4, n5) (cJSON_GetObjectItem4(r, n1, n2, n3, n4) ? \ cJSON_GetObjectItem(cJSON_GetObjectItem4(r, n1, n2, n3, n4), n5) : NULL) +#define cJSON_GSV cJSON_GetStringValue +#define cJSON_GNV cJSON_GetNumberValue +#define cJSON_GAS cJSON_GetArraySize +#define cJSON_GOI cJSON_GetObjectItem +#define cJSON_GOI2 cJSON_GetObjectItem2 +#define cJSON_GOI3 cJSON_GetObjectItem3 +#define cJSON_GOI4 cJSON_GetObjectItem4 +#define cJSON_GOI5 cJSON_GetObjectItem5 +#define cJSON_GSV cJSON_GetStringValue +#define cJSON_IN cJSON_IsNumber +#define cJSON_AFE cJSON_ArrayForEach unsigned char dc_api_identify_u[] = { #include <identify.xxd> }; @@ -37,19 +48,26 @@ void dc_api_stack (struct dc_api_io i) { /* stack output struct to be delivered } unsigned long long int dc_calculate_permissions (struct dc_user * u, struct dc_channel * c) { unsigned long long int p = 0; /* note: this is NOT according to server's implementation of */ - struct dc_role ** role = &c->guild->role; /* permission parsing, but should suffice for most */ - while (*role) { /* cases. */ - if ((*role)->status & DC_EVERYONE || dc_find_user((*role)->users, (*role)->users_length, u->id)) + struct dc_role ** role = &c->guild->role; /* perm parsing, but should suffice 4 most cases */ + if (!*role) /* see struct dc_guild: if NULL then assume all permissions - a DM guild */ + return DC_ALL_PERMISSIONS; + while (*role) { + if (DC_ROLE_EVERYONE(*role) + || dc_find_user((*role)->users, (*role)->users_length, u->id)) p |= (*role)->permissions; role = &(*role)->next; } if (p & DC_ADMIN) return DC_ALL_PERMISSIONS; for (size_t i = 0; i < c->permissions_length; i++) - if (c->permissions[i]->user == u || dc_find_user(c->permissions[i]->role->users, c->permissions[i]->role->users_length, u->id) || c->permissions[i]->role->status & DC_EVERYONE) { + if (c->permissions[i]->user + ? c->permissions[i]->user == u + : dc_find_user(c->permissions[i]->role->users, + c->permissions[i]->role->users_length, u->id) + || DC_ROLE_EVERYONE(c->permissions[i]->role)) { p &= ~c->permissions[i]->deny; p |= c->permissions[i]->allow; - if ((*role)->permissions & DC_ADMIN) + if (p & DC_ADMIN) return DC_ALL_PERMISSIONS; } return p; @@ -57,15 +75,17 @@ unsigned long long int dc_calculate_permissions (struct dc_user * u, struct dc_c struct dc_user * dc_parse_user (struct dc_user * dst, const cJSON * src) { char * cp; if (!dst) - dst = dc_user_init(); - if ((cp = cJSON_GetStringValue(cJSON_GetObjectItem(src, "username")))) + dst = dc_user_init(); + if ((cp = cJSON_GSV(cJSON_GOI(src, "username")))) dst->username = strdup(cp); - if ((cp = cJSON_GetStringValue(cJSON_GetObjectItem(src, "discriminator")))) + if ((cp = cJSON_GSV(cJSON_GOI(src, "discriminator")))) dst->discriminator = atoi(cp); - else - dst->discriminator = -1; - if ((cp = cJSON_GetStringValue(cJSON_GetObjectItem(src, "id")))) + if ((cp = cJSON_GSV(cJSON_GOI(src, "id")))) dst->id = strtoull(cp, NULL, 10); + if (!dst->username || dst->discriminator == -1) { /* it's quite useless to store only ids */ + dc_user_free(dst, DC_UNSET); + return NULL; + } return dst; } static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us, void * in, size_t len) { @@ -207,60 +227,100 @@ static int dc_lws_cb (struct lws * wsi, enum lws_callback_reasons rs, void * us, fprintf(stdout, "%.*s", len, (const unsigned char *) in); char * serialized = dc_json(pass->json, in, len); while (serialized) { - cJSON * json = cJSON_Parse(serialized); - cJSON * obj; + cJSON * obj, * obje, * json = cJSON_Parse(serialized); char * st; if (getenv("DC_J")) { st = cJSON_Print(json); - if (st) { - printf("%s\n", st); - cJSON_free(st); - } else - fprintf(stderr, "_RECEIVE: _Print NULL: %s\n", serialized); + printf("%s\n", st); + cJSON_free(st); + } +#define DC_PTYP(t) ((st = cJSON_GSV(cJSON_GOI(json, "t"))) && !strcmp(st, t)) + if (DC_PTYP("READY") && getenv("DC_R")) { + printf("%s\n", (st = cJSON_Print(json))); + cJSON_free(st); } - pass->api_io.client->last_packet - = cJSON_GetNumberValue(cJSON_GetObjectItem(json, "s")); - if (cJSON_GetNumberValue(cJSON_GetObjectItem(json, "op")) - == DC_PING) { + if ((st = cJSON_GSV(cJSON_GOI(json, "t")))) + fprintf(stderr, "t: %s\n", st); + pass->api_io.client->last_packet = cJSON_GNV(cJSON_GOI(json, "s")); + if (cJSON_GNV(cJSON_GOI(json, "op")) == DC_PING) { pass->api_io.client->last_ping = 0; dc_handle_ping(pass->api_io, NULL); } - if (cJSON_IsNumber((obj - = cJSON_GetObjectItem2(json, "d", "heartbeat_interval")))) { - pass->api_io.client->ping_interval - = cJSON_GetNumberValue(obj)/1000-1; + if (cJSON_IN((obj = cJSON_GOI2(json, "d", "heartbeat_interval")))) { + pass->api_io.client->ping_interval = cJSON_GNV(obj)/1000-1; pass->api_io.client->last_ping = 1; } #define DC_PARSEOBJ(w, object, also) if ((obj = object)) { \ struct dc_##w * w; \ - w = dc_parse_##w(NULL, obj); \ - w = dc_addr_##w(pass->api_io.program, \ + if ((w = dc_parse_##w(NULL, obj))) \ + w = dc_addr_##w(pass->api_io.program, \ DC_ISAE(pass->api_io.program->w##s), w, \ - DC_MAY_FREE | DC_REPLACE);\ + DC_MAY_FREE | DC_REPLACE | DC_INCOMPLETE);\ also \ } - DC_PARSEOBJ(user, cJSON_GetObjectItem2(json, "d", "user"), - if (!pass->api_io.client->user) pass->api_io.client->user = user;) - DC_PARSEOBJ(user, cJSON_GetObjectItem3(json, "d", "member", "user"),) - DC_PARSEOBJ(user, cJSON_GetObjectItem2(json, "d", "author"), ) - DC_PARSEOBJ(user, cJSON_GetObjectItem3(json, "d", - "referenced_message", "author"), ) -#define DC_PARSEARR(what, arr) cJSON_ArrayForEach(obj, arr) { \ + DC_PARSEOBJ(user, cJSON_GOI2(json, "d", "user"), + if (!pass->api_io.client->user) + pass->api_io.client->user = user; + ) + DC_PARSEOBJ(user, cJSON_GOI3(json, "d", "member", "user"),) + DC_PARSEOBJ(user, cJSON_GOI2(json, "d", "author"),) + DC_PARSEOBJ(user, cJSON_GOI3(json, + "d", "referenced_message", "author"),) +#define DC_PARSEARR(what, arr, also) cJSON_AFE(obj, arr) { \ struct dc_##what * what = dc_parse_##what(NULL, obj); \ if (!what) \ continue; \ dc_addr_##what(pass->api_io.program, \ DC_ISAE(pass->api_io.program->what##s), \ - what, DC_MAY_FREE | DC_REPLACE); \ + what, DC_MAY_FREE|DC_REPLACE|DC_INCOMPLETE);\ + also \ } - DC_PARSEARR(user, cJSON_GetObjectItem2(json, "d", "users")); - DC_PARSEARR(user, cJSON_GetObjectItem2(json, "d", "mentions")); - DC_PARSEARR(user, cJSON_GetObjectItem3(json, "d", - "referenced_message", "mentions")); -#define DC_PTYP(t) ((st = cJSON_GetStringValue(cJSON_GetObjectItem(json, "t"))) && !strcmp(st, t)) - if (DC_PTYP("MESSAGE_CREATE")) { - + DC_PARSEARR(user, cJSON_GOI2(json, "d", "users"),) + DC_PARSEARR(user, cJSON_GOI2(json, "d", "mentions"),) + DC_PARSEARR(user, cJSON_GOI3(json, + "d", "referenced_message", "mentions"),) + cJSON_AFE(obj, cJSON_GOI2(json, "d", "private_channels")) { + if (/* !cJSON_GAS(cJSON_GOI(obj, "recipient_ids")) || */ + /* commented. DMs with 0 members're shown /\ */ !cJSON_GSV(cJSON_GOI(obj, "id")) || + !DC_CHANNEL_SUPPORTED( + /* cJSON is called many times here but I don't care */ cJSON_GNV(cJSON_GOI(obj, "type")))) + continue; + struct dc_channel * ch = dc_channel_init(); + if ((st = cJSON_GSV(cJSON_GOI(obj, "name")))) + ch->name = strdup(st); + ch->type = cJSON_GNV(cJSON_GOI(obj, "type")); + ch->id = strtoull(cJSON_GSV(cJSON_GOI(obj, "id")), NULL, 10); + cJSON_AFE(obje, cJSON_GOI(obj, "recipient_ids")) { + struct dc_user * part = dc_user_init(); + part->username = strdup("Private channel recipient"); + part = dc_add_user( + DC_ISAE(pass->api_io.program->users), + /* no replace here. stored user can be better. */ part, DC_MAY_FREE); + DC_MR(ch->users); /* needn't dc_add here coz start */ + ch->users[ch->users_length++] = part; /* empty ch. */ + } + ch = dc_addr_channel(pass->api_io.program, + DC_ISAE(pass->api_io.program->channels), ch, + /* replace here. ours is better - fresher. */ DC_MAY_FREE | DC_REPLACE | DC_INCOMPLETE); + ch->guild = pass->api_io.client->guilds[0]; } + cJSON_AFE(obj, cJSON_GOI2(json, "d", "merged_members")) + cJSON_AFE(obje, cJSON_GOI(obj, "roles")) { + if (!(st = cJSON_GSV(obje))) + continue; + struct dc_role * role = dc_role_init(); + role->id = strtoull(st, NULL, 10); + role = dc_add_role( + DC_ISAE(pass->api_io.program->roles), + role, DC_MAY_FREE); + struct dc_user * user = dc_user_init(); + user->id = strtoull(cJSON_GSV(cJSON_GOI( + obj, "user_id")), NULL, 10); + user = dc_add_user( + DC_ISAE(pass->api_io.program->users), + /* again, no replace here, because we only have ID */ user, DC_MAY_FREE); + /* role may have users */ dc_add_user(DC_ISAE(role->users), user, DC_UNSET); + } cJSON_Delete(json); json = NULL; serialized = dc_json(pass->json, NULL, 0); @@ -292,7 +352,7 @@ void dc_api_i (struct dc_api_io i) { /* this function does not call attached fun struct dc_lws_pass * pass; assert(i.program); if (i.program->lws_context && !(i.status & DC_FROM_LWS)) - lws_service(i.program->lws_context, 0); /* DO NOT CALL THIS FROM _cb! */ + lws_service(i.program->lws_context, -1); /* DO NOT CALL THIS FROM _cb! */ switch (i.type) { case DC_API_MESSAGE: break; @@ -440,7 +500,7 @@ struct dc_api_io dc_api_o (struct dc_api_io i /* for ->program */) { return i; } if (i.program->lws_context) - lws_service(i.program->lws_context, 0); + lws_service(i.program->lws_context, -1); /* with -1 this takes ~0 time */ 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.program->clients[x]->disconnect_time+DC_RECONNECT_DELAY<time(NULL)) { |