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/h.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/h.c')
-rw-r--r-- | src/h.c | 189 |
1 files changed, 108 insertions, 81 deletions
@@ -10,7 +10,11 @@ } while (0) /* note that sizeof(name[0]) does not dereferencec name */ #define DC_MR(n) if (n##_sizeof <= n##_length) /* make room */ \ DC_BIGGER_ARRAY(n) -#define DC_STRUCT_PREFIX void * data; /* some user data to be kind to api library users */ +#define DC_STRUCT_PREFIX void * data; /* some user data to be kind to api library users ... */ +#define DC_TRANSFER_PREFIX if (!n->data) { \ + n->data = o->data; \ + o->data = NULL; \ + } /* ... and what happens with this data with _transfer_ */ #define DC_LWS_BUF 65535 /* 2^16 SMALL FUCKING HINT: ^ je XOR operator v C (in povsod drugje) */ #define DC_LWS_MAX_RX DC_LWS_BUF /* max bytes a websocket may handle in a single receive */ #define DC_LWS_MAX_FD 64 /* max file descriptors LWS will have open. if unset, LWS acquires all unused */ @@ -24,11 +28,11 @@ #endif /* it's strongly recommended to calloc structs during initialization. */ enum dc_status { /* theese are flags and should be and-checked */ - DC_UNSET = 0, /* default value when enum is calloced */ - DC_INCOMPLETE = 1 << 0, /* struct SHALL NOT be used by the ui, it is yet to be filled by api */ + DC_UNSET = 0, /* default value when enum is calloced */ /* \/ USEFUL FOR ->next!!! */ + DC_INCOMPLETE = 1 << 0, /* _add_ w/ DC_REPLACE: new gets empty data from old w/ _transfer_ */ DC_OK = 1 << 1, /* success status and also ws established*/ DC_BAD_LOGIN = 1 << 2, /* login failed because of wrong credentials */ - DC_VERIFICATION_NEEDED = 1 << 3, /* login: check email, click link/reg: tough luck ur IP flagd */ + DC_VERIFICATION_NEEDED = 1 << 3, /* login: check email, click link/reg: ur IP flagd */ DC_CAPTCHA_NEEDED = 1 << 4, /* must solve captcha, tough luck, not impl, use browser login */ DC_BAD_USERNAME = 1 << 5, /* provided username can't be registered */ DC_BAD_EMAIL = 1 << 6, /* provided email can't be registered */ @@ -41,17 +45,16 @@ enum dc_status { /* theese are flags and should be and-checked */ DC_ERROR = 1 << 13, /* unknown error, non implemented non expected response */ DC_NET_ERROR = 1 << 14, /* network failed or ws closed */ DC_LEJP_CONSTRUCTED = 1 << 15, /* json parser was constructed */ - DC_SET_PASS = 1 << 16, /* whether _CREATE _cb shall set client->passs. api sets on _WS create */ + DC_SET_PASS = 1 << 16, /* if _CREATE _cb shall set client->passs. api sets on _WS create */ DC_IN_PROGRESS = 1 << 17, /* object is in parsing (by json_cb) */ DC_DESTROY_CB = 1 << 18, /* wether cb shall call api on DESTROY (used for http responses) */ - DC_MAY_FREE = 1 << 19, /* whether dc_*_add() shall free passed in pointer if found one in ISA */ - DC_WS_ACTIVE = 1 << 20, /* set at WSI_CREATE so api_o will reconnect WS if connection dropps */ + DC_MAY_FREE = 1 << 19, /* if dc_*_add() shall free passed in pointer if found one in ISA */ + DC_WS_ACTIVE = 1 << 20, /* set at WSI_CREATE so api_o'll reconnect WS if connection dropps */ 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_SET_WS_ACTIVE = 1 << 22, /* if _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_EVERYONE = 1 << 25, /* role applies to all guild users */ - DC_USER_ERROR = 1 << 26, /* lib user made an error, passed NULL pointer to _o for example */ + DC_EXPLICIT_NULL = 1 << 24, /* MEMB_GC'll NULL this memb (PROGRES?aftr free) (& clear bit) */ + DC_USER_ERROR = 1 << 25, /* lib user made an error, passed NULL pointer to _o for example */ 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! */ #define DC_ADMIN (1 << 3) /* not all enum fields are implemented/understood */ @@ -60,14 +63,16 @@ enum dc_status { /* theese are flags and should be and-checked */ #define DC_MESSAGE_READ (1 << 16) /* na tistem vegova serverju sem lahko pošiljal ne pa bral sporočil */ #define DC_VOICE_LISTEN (1 << 20) /* ISO C enums are at most int-wide */ #define DC_VOICE_SPEAK (1 << 21) -#define DC_ALL_PERMISSIONS (DC_ADMIN | DC_CHANNEL_VIEW | DC_MESSAGE_SEND | DC_MESSAGE_READ | DC_VOICE_LISTEN | DC_VOICE_SPEAK) /* admins get this@parsing, UI need not check admin separatly */ +#define DC_ALL_PERMISSIONS (DC_ADMIN | DC_CHANNEL_VIEW | DC_MESSAGE_SEND | DC_MESSAGE_READ \ + | DC_VOICE_LISTEN | DC_VOICE_SPEAK) /* UI need not check ADMIN for WRITE 4example */ enum dc_channel_type { /* other types exist, but are not implemented/understood */ DC_GC, /* guild channel */ DC_DM, /* direct messages channel */ DC_VOICE, /* all enum fields here have values same as the values that the server sends */ DC_GROUP_DM }; -#define DC_CHANNEL_SUPPORTED(x) (x == DC_GC || x == DC_DM || x == DC_VOICE || x == DC_GROUP_DM) +#define DC_CHANNEL_SUPPORTED(x) ((x) == DC_GC || (x) == DC_DM || (x) == DC_VOICE || (x)==DC_GROUP_DM) +char * dc_channel_type_str[] = { "DC_GC", "DC_DM", "DC_VOICE", "DC_GROUP_DM" }; enum dc_ws_packet { /* op numbers of websocket packets or json objects in other words */ DC_PING = 1, DC_STRPKTOFF = 100, /* here follow string types (t) */ @@ -398,13 +403,13 @@ void dc_payload_free (struct dc_payload * s, enum dc_status t) { free(s); return; } -#define DC_ISASQ(shortname) DC_ISA(struct dc_##shortname, shortname##s) /* in struct array of structs quick */ -#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_ISASQ(shortname) DC_ISA(struct dc_##shortname, shortname##s) /* ISA of structs quick */ +#define DC_ISAS_INIT(type/* w/o struct */, name) do { name##_sizeof = DC_ALLOC_CHUNK; \ + name = calloc(name##_sizeof, sizeof(struct type *)); } while (0) /* prep arr, NO INIT mmbs */ #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_length; 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? */ +#define DC_ISAF(shortname) for (size_t i = 0; i < s->shortname##s_length; i++) \ + dc_##shortname##_free(s->shortname##s[i], DC_UNSET); \ + free(s->shortname##s); /* only free till _length */ struct dc_client { DC_STRUCT_PREFIX char * authorization; /* yesfree - authorization header value */ @@ -416,7 +421,7 @@ struct dc_client { unsigned long long int last_packet; /* last packet sequence number for ping */ time_t ping_interval; time_t last_ping; - time_t disconnect_time; /* set at disconnect, so that reconnection is delayed for some seconds */ + time_t disconnect_time; /* set at disconnect, so that reconn is delayed for some secs */ DC_ISASQ(payload); /* yesfree - array of payloads we must send over ws */ DC_ISASQ(guild); /* yesfree array of pointers only - guilds of this user */ DC_ISASQ(user); /* yesfree array of pointers only - friends of this user */ @@ -426,13 +431,12 @@ struct dc_guild { char * name; /* yesfree */ unsigned long long int id; /* 0 for virtual DMs guild */ struct dc_channel * channel; /* nofree - first channel */ - struct dc_role * role; /* nofree - first role. NOTE: role->id == guild->id => @everyone role */ + struct dc_role * role; /* nofree - first role. NOTE: role->id==guild->id => @everyone */ enum dc_status status; /* /\ if NULL then assume all permissions - a DM guild */ #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 + GtkTreeIter iter; /* GtkTreeModel needs GTK_TREE_MODEL_ITERS_PERSIST for this to work */ + gboolean is_iter; /* see parag 8 file:///usr/share/doc/libgtk-3-doc/gtk3/GtkTreeModel.html */ +#endif /* GtkTreeRowReference is not used, because it's slow (notice trimmed, see older commits) */ }; struct dc_guild * dc_guild_init () { struct dc_guild * s = calloc(1, sizeof(*s)); @@ -489,8 +493,8 @@ struct dc_channel { struct dc_guild * guild; /* nofree */ struct dc_channel * next; /* nofree - next channel (linked list of all channel of dc_guild) */ struct dc_message * message; /* nofree - first message (ordered by time) */ - DC_ISASQ(permission); /* yesfree array and members - ch permissions for users/roles */ enum dc_status status; + DC_ISASQ(permission); /* yesfree array and members - ch permissions for users/roles */ DC_ISASQ(user); /* yesfree array only - participants in DM channels */ #ifdef DC_UI_GTK GtkTreeIter iter; /* see notes of struct dc_guild */ @@ -514,39 +518,31 @@ void dc_channel_free (struct dc_channel * s, enum dc_status t) { if (!(t & DC_REPLACE)) free(s); } -struct dc_message { +struct dc_message { /* mentions are not "cached" or parsed by API. UI should extract them. */ DC_STRUCT_PREFIX char * message; /* yesfree */ struct dc_channel * channel; /* nofree */ struct dc_user * user; /* nofree */ - time_t time; /* obtained with DC_ID2TIME, edited timestamp is in ISO string format¬ implemt */ + time_t time; /* obtained with DC_ID2TIME, edited timestamp in ISO string format is N/I */ unsigned long long int id; struct dc_message * next; /* next message (linked list of all messages of dc_channel) */ struct dc_message * reply; /* nofree - this message replies to another message or NULL */ enum dc_status status; enum dc_message_type type; - struct dc_client * client; /* nofree - set when sending message to the client that should send */ - DC_ISASQ(user); /* yesfree pointer array only - mentions */ - DC_ISASQ(role); /* yesfree pointer array only - mentions */ - DC_ISASQ(channel); /* yesfree pointer array only - mentions */ + struct dc_client * client; /* nofree - set when sending message - which client should send */ }; struct dc_message * dc_message_init () { struct dc_message * s = calloc(1, sizeof(*s)); - DC_ISASIQ(user); - DC_ISASIQ(role); - DC_ISASIQ(channel); return s; } void dc_message_free (struct dc_message * s, enum dc_status t) { if (!s) return; free(s->message); - free(s->users); - free(s->roles); - free(s->channels); if (!(t & DC_REPLACE)) free(s); } +#define DC_ROLE_EVERYONE(role) ((role)->guild && (role)->id == (role)->guild->id) /* triple eval!1 */ struct dc_role { DC_STRUCT_PREFIX char * name; /* yesfree */ @@ -554,8 +550,8 @@ struct dc_role { unsigned long long int permissions; /* this are guild permission */ struct dc_guild * guild; /* nofree - owner of the role */ struct dc_role * next; /* nofree - next role (linked list of all roles of dc_guild) */ - DC_ISASQ(user); /* yesfree pointer array only - users with this role */ enum dc_status status; + DC_ISASQ(user); /* yesfree pointer array only - users with this role */ }; struct dc_role * dc_role_init () { struct dc_role * s = calloc(1, sizeof(*s)); @@ -575,7 +571,6 @@ struct dc_user { char * username; /* yesfree */ unsigned long long int id; short int discriminator; - struct dc_program * program; /* nofree - for dc_calculate_permissions */ enum dc_status status; }; struct dc_user * dc_user_init () { @@ -760,15 +755,16 @@ void dc_api_stack (struct dc_api_io); if (us == u) \ return us; \ if (s & DC_REPLACE) { \ + if (s & DC_INCOMPLETE) \ + dc_transfer_##x(u /* this is then memmoved */, us); \ dc_##x##_free(us, s); \ memmove(us, u, sizeof(*us)); \ if (s & DC_MAY_FREE) \ free(u); /* we don't free members, they've been copied */ \ return us; \ } \ - if (s & DC_MAY_FREE) { \ + if (s & DC_MAY_FREE) \ dc_##x##_free(u, DC_UNSET); \ - } \ return us; \ } \ if (*so <= *l) { \ @@ -797,53 +793,84 @@ void dc_api_stack (struct dc_api_io); return u; \ } /* add with report */ #define DC_GEN_X(x, y) DC_FIND_X(x) DC_ADD_X(x) DC_ADDR_X(x, y) -DC_GEN_X(user, USER) -DC_GEN_X(channel, CHANNEL) -DC_FIND_LL_X(channel) -DC_GEN_X(guild, GUILD) -DC_GEN_X(role, ROLE) -DC_FIND_LL_X(role) -DC_GEN_X(message, MESSAGE) -DC_FIND_LL_X(message) #define DC_ISAE(a) &(a), &(a##_sizeof), &(a##_length) /* ISA Expand */ #define DC_ISAN NULL, NULL, NULL /* ISA NULL */ -void dc_transfer_channel(struct dc_channel * n, struct dc_channel * o) { /* n is going to _REPLACE o */ \ - n->message = o->message; /* don't transfer perms because we get them in the new */ \ - n->next = o->next; /* new channel object */ \ +#define DC_TRANSFER_MEMBER(member) if (!n->member) { \ + n->member = o->member; \ + o->member = 0; \ + } +#define DC_TRANSFER_ISA(what) if (!n->what##s_length) { \ + free(n->what##s); \ + n->what##s = o->what##s; \ + n->what##s_sizeof = o->what##s_sizeof; \ + n->what##s_length = o->what##s_sizeof; \ + o->what##s = NULL; \ + o->what##s_sizeof = 0; \ + o->what##s_length = 0; \ + } +void dc_transfer_channel (struct dc_channel * n, struct dc_channel * o) { /* n will _REPLACE o */ \ + DC_TRANSFER_PREFIX + DC_TRANSFER_MEMBER(name) /* all _transfer_ functions assume old will be discarded */ + DC_TRANSFER_MEMBER(topic) /* and passed to _free_ after use. */ + DC_TRANSFER_MEMBER(id) + DC_TRANSFER_MEMBER(type) + DC_TRANSFER_MEMBER(guild) + DC_TRANSFER_MEMBER(next) + DC_TRANSFER_MEMBER(message) + DC_TRANSFER_ISA(permission) + DC_TRANSFER_ISA(user) DC_IF_UI_GTK( memmove(&n->iter, &o->iter, sizeof(GtkTreeIter)); n->is_iter = o->is_iter; ) - if (!n->permissions_length) { - free(n->permissions); - n->permissions = o->permissions; - n->permissions_sizeof = o->permissions_sizeof; - n->permissions_length = o->permissions_length; - o->permissions = NULL; - o->permissions_sizeof = 0; - o->permissions_length = 0; - } } -#define DC_TRANSFER_GUILD(n, o) do { \ - DC_IF_UI_GTK( \ - memmove(&(n)->iter, &(o)->iter, sizeof(GtkTreeIter)); \ - (n)->is_iter = (o)->is_iter; \ - ) \ - } while (0) +void dc_transfer_guild (struct dc_guild * n, struct dc_guild * o) { + DC_TRANSFER_PREFIX + DC_TRANSFER_MEMBER(name) + DC_TRANSFER_MEMBER(id) + DC_TRANSFER_MEMBER(channel); + DC_TRANSFER_MEMBER(role); + DC_TRANSFER_MEMBER(status); + DC_IF_UI_GTK( + memmove(&n->iter, &o->iter, sizeof(GtkTreeIter)); + n->is_iter = o->is_iter; + ) +} void dc_transfer_role (struct dc_role * n, struct dc_role * o) { - n->next = o->next; - if (!n->users_length) { /* if we didn't update users array in the new role object */ - free(n->users); /* thanks, clang, we have to free pointer array before overwriting it! */ - n->users = o->users; - n->users_sizeof = o->users_sizeof; - n->users_length = o->users_sizeof; - o->users = NULL; /* so that free does not free array of pointers */ - o->users_sizeof = 0; - o->users_length = 0; - } + DC_TRANSFER_PREFIX + DC_TRANSFER_MEMBER(name) + DC_TRANSFER_MEMBER(id) + DC_TRANSFER_MEMBER(permissions) + DC_TRANSFER_MEMBER(guild) + DC_TRANSFER_MEMBER(next) + DC_TRANSFER_MEMBER(status) + DC_TRANSFER_ISA(user) } void dc_transfer_message (struct dc_message * n, struct dc_message * o) { - n->next = o->next; - if (!n->reply) - n->reply = o->reply; + DC_TRANSFER_PREFIX + DC_TRANSFER_MEMBER(message) + DC_TRANSFER_MEMBER(channel) + DC_TRANSFER_MEMBER(user) + DC_TRANSFER_MEMBER(time) + DC_TRANSFER_MEMBER(id) + DC_TRANSFER_MEMBER(next) + DC_TRANSFER_MEMBER(reply) + DC_TRANSFER_MEMBER(status) + DC_TRANSFER_MEMBER(type) + DC_TRANSFER_MEMBER(client) } +void dc_transfer_user (struct dc_user * n, struct dc_user * o) { + DC_TRANSFER_PREFIX + DC_TRANSFER_MEMBER(username) + DC_TRANSFER_MEMBER(id) + DC_TRANSFER_MEMBER(discriminator) + DC_TRANSFER_MEMBER(status) +} +DC_GEN_X(user, USER) +DC_GEN_X(channel, CHANNEL) +DC_FIND_LL_X(channel) +DC_GEN_X(guild, GUILD) +DC_GEN_X(role, ROLE) +DC_FIND_LL_X(role) +DC_GEN_X(message, MESSAGE) +DC_FIND_LL_X(message) |