summaryrefslogtreecommitdiffstats
path: root/src/h.c
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2022-02-25 00:54:36 +0100
committerAnton Luka Šijanec <anton@sijanec.eu>2022-02-25 00:54:36 +0100
commitdc07e4bf7f4628852eee26b114348498caad0182 (patch)
tree597cce2a6e81a13a959b1beae2508b761ef04773 /src/h.c
parenti suppose parsing json is easyer with cjson than lejp (: (diff)
downloaddiscord.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.c189
1 files changed, 108 insertions, 81 deletions
diff --git a/src/h.c b/src/h.c
index 04fb7e9..ae6c8e0 100644
--- a/src/h.c
+++ b/src/h.c
@@ -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&not 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)