Browse Source

i hope it's fixed now (magic?), though there's still a memory leak

dev
Anton Luka Šijanec 2 months ago
parent
commit
605cb0ca37
  1. 6
      Makefile
  2. 2
      README.md
  3. 47
      src/api.c
  4. 43
      src/h.c
  5. 4
      src/ui.c

6
Makefile

@ -17,6 +17,12 @@ default:
echo ', 0' >> tmp/identify.xxd
$(CC) $(CFLAGS) $(SRCFILE) $(LIBS)
# tests if code compiles under gcc, clang and tcc
cc:
make -e CC=gcc
make -e CC=tcc
make -e CC=clang
install:
mkdir -p $(DESTDIR)/usr/bin/
cp discord.c $(DESTDIR)/usr/bin/

2
README.md

@ -35,7 +35,7 @@ make
#### building requirements
* a POSIX build system - app is cross platform and should also be able to be compiled for all major OSes
* a C compiler, `gcc` 10 (faster) and `clang` (better warnings) tested working
* a C compiler, `tcc` (fast), `gcc` (10), and `clang` (better warnings) tested working
* `make`, with support for `.NOTPARALLEL:` or without executing in parallel, GNU `make` tested working
* `libwebsockets-dev` for http and ws client and json parser
* GTK+, `libgtk-3-dev` tested working

47
src/api.c

@ -107,10 +107,27 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
}
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. */
switch (path) {
case DC_JSON_MESSAGE_AUTHOR:
if (pass->api_io.message)
pass->api_io.message->user = pass->api_io.user;
break;
case DC_JSON_MESSAGE_REFOBJ_AUTHOR:
if (pass->api_io.message && pass->api_io.message->reply)
pass->api_io.message->reply->user = pass->api_io.user;
break;
case DC_JSON_MESSAGE_MENTION_USER:
if (pass->api_io.message)
dc_add_user(DC_ISAE(pass->api_io.message->users), pass->api_io.user, DC_UNSET);
break;
case DC_JSON_MESSAGE_REFOBJ_MENTION_USER:
if (pass->api_io.message && pass->api_io.message->reply)
dc_add_user(DC_ISAE(pass->api_io.message->reply->users), pass->api_io.user, DC_UNSET);
break;
default:
break;
}
pass->api_io.user = NULL;
}
if ((path == DC_JSON_DM || path == DC_JSON_GUILD_CHANNEL) && reason == LEJPCB_OBJECT_START) {
pass->api_io.channel = dc_channel_init();
@ -140,9 +157,10 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
struct dc_channel * ch;
if ((ch = dc_find_channel(program->channels, program->channels_length, pass->api_io.channel->id)))
DC_TRANSFER_CHANNEL(pass->api_io.channel, ch);
pass->api_io.channel = dc_addr_channel(program, DC_ISAN, pass->api_io.channel, DC_MAY_FREE | DC_REPLACE);
pass->api_io.channel = dc_addr_channel(program, DC_ISAE(program->channels), pass->api_io.channel, DC_MAY_FREE | DC_REPLACE);
if (!dc_find_ll_channel(client->guilds[0]->channel, pass->api_io.channel->id)) {
fprintf(stderr, "new DM id=%llu (:\n", pass->api_io.channel->id);
pass->api_io.channel->next = NULL;
*channel = pass->api_io.channel;
}
pass->api_io.channel->guild = client->guilds[0];
@ -160,7 +178,12 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
struct dc_channel * ch;
if ((ch = dc_find_channel(program->channels, program->channels_length, pass->api_io.channel->id)))
DC_TRANSFER_CHANNEL(pass->api_io.channel, ch);
pass->api_io.channel = *channel = dc_addr_channel(program, DC_ISAN, pass->api_io.channel, DC_MAY_FREE | DC_REPLACE);
pass->api_io.channel = dc_addr_channel(program, DC_ISAE(program->channels), pass->api_io.channel, DC_MAY_FREE | DC_REPLACE);
if (!dc_find_ll_channel(pass->api_io.guild->channel, pass->api_io.channel->id)) {
fprintf(stderr, "new channel id=%llu (:\n", pass->api_io.channel->id);
pass->api_io.channel->next = NULL;
*channel = pass->api_io.channel;
}
struct dc_permission ** pe = &pass->api_io.channel->permission;
while (*pe) { /* fix all permission pointers to channel to this new channel */
(*pe)->channel = pass->api_io.channel;
@ -196,7 +219,6 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
dc_add_guild(DC_ISAE(client->guilds), pass->api_io.guild, DC_UNSET);
pass->api_io.guild = NULL; /* we're done, NULL it or PROBLEMS WILL APPEAR!!! */
}
#if 0
if (path == DC_JSON_GUILD_ROLE && reason == LEJPCB_OBJECT_START) {
pass->api_io.role = dc_role_init();
pass->api_io.role->status |= DC_IN_PROGRESS;
@ -211,7 +233,7 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
struct dc_role * ro;
if ((ro = dc_find_role(program->roles, program->roles_length, pass->api_io.role->id)))
dc_transfer_role(pass->api_io.role, ro);
pass->api_io.role = dc_addr_role(program, DC_ISAE(program->roles), pass->api_io.role, DC_MAY_FREE | DC_REPLACE);
pass->api_io.role = dc_add_role(DC_ISAE(program->roles), pass->api_io.role, DC_MAY_FREE | DC_REPLACE);
struct dc_role ** role;
role = &pass->api_io.guild->role;
while (*role)
@ -224,7 +246,6 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
}
if (path == DC_JSON_MEMBERSHIP && (reason == LEJPCB_OBJECT_END || reason == LEJPCB_OBJECT_START))
pass->api_io.id = 0;
#endif
if (reason & LEJP_FLAG_CB_IS_VALUE) {
struct dc_user * user; /* this is just a var for you use */
struct dc_role * role; /* now we rely on -Wuninitialized to detect weird stuff */
@ -286,7 +307,6 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
if (pass->api_io.channel && !pass->api_io.channel->topic)
pass->api_io.channel->topic = strdup(ctx->buf);
break;
#if 0
case DC_JSON_GUILD_ROLE_ID:
if (pass->api_io.role)
pass->api_io.role->id = strtoull(ctx->buf, NULL, 10);
@ -297,10 +317,10 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
break;
case DC_JSON_GUILD_ROLE_PERMISSION:
if (pass->api_io.role) {
if (atoi(ctx->buf) & DC_ADMIN)
if (strtoull(ctx->buf, NULL, 10) & DC_ADMIN)
pass->api_io.role->permissions = DC_ALL_PERMISSIONS;
else
pass->api_io.role->permissions = atoi(ctx->buf);
pass->api_io.role->permissions = strtoull(ctx->buf, NULL, 10);
}
break;
case DC_JSON_MEMBERSHIP_USER:
@ -331,7 +351,6 @@ signed char dc_json_cb (struct lejp_ctx * ctx, char reason) { /* to prevent warn
fprintf(stderr, "new role membership user %s#%d (usr=%llu role=%llu)\n", user->username ? user->username : "", user->discriminator, user->id, role->id);
pass->api_io.id = 0;
break;
#endif
default:
break;
}
@ -439,6 +458,8 @@ 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;
}
DC_API_IO_GC(pass->api_io); /* frees all unfinished parsing objects */
pass->packet = DC_NONE;
pass->api_io.client->pass = NULL;
dc_lws_pass_free(pass, DC_UNSET); /* called the last time us ptr & wsi r still */
break; /* accessible - we can free the struct that was passed in as a heap ptr */

43
src/h.c

@ -53,15 +53,13 @@ enum dc_status { /* theese are flags and should be and-checked */
DC_EVERYONE = 1 << 25, /* role applies to all guild users */
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! */
enum dc_permissions { /* other permissions exist, but are not implemented/understood */
DC_ADMIN = 1 << 3, /* this is incredibly retarded, why is this SEPARATE?!? - admins */
DC_CHANNEL_VIEW = 1 << 10, /* all enum fields here have values same as the server values */
DC_MESSAGE_SEND = 1 << 11,
DC_MESSAGE_READ = 1 << 16, /* na tistem vegova serverju sem lahko pošiljal ne pa bral sporočil */
DC_VOICE_LISTEN = 1 << 20,
DC_VOICE_SPEAK = 1 << 21,
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 */
}; /* all enum fields here have values same as the values that the server sends */
#define DC_ADMIN (1 << 3) /* not all enum fields are implemented/understood */
#define DC_CHANNEL_VIEW (1 << 10) /* all enum fields here have values same as the server values */
#define DC_MESSAGE_SEND (1 << 11) /* this is not an enum as there are over 40 permissions */
#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 */
enum dc_channel_type { /* other types exist, but are not implemented/understood */
DC_GC = 0, /* guild channel */
DC_DM = 1, /* direct messages channel */
@ -515,9 +513,15 @@ struct dc_message {
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;
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_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) {
@ -525,6 +529,9 @@ void dc_message_free (struct dc_message * s, enum dc_status t) {
return;
free(s->message);
free(s->attachment);
free(s->users);
free(s->roles);
free(s->channel);
if (!(t & DC_REPLACE))
free(s);
}
@ -532,7 +539,7 @@ struct dc_role {
DC_STRUCT_PREFIX
char * name; /* yesfree */
unsigned long long int id;
enum dc_permissions permissions; /* this are guild permission */
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 */
@ -571,8 +578,8 @@ void dc_user_free (struct dc_user * s, enum dc_status t) {
}
struct dc_permission { /* permissions can be individual on a per-channel basis */
DC_STRUCT_PREFIX /* assume all permissions */
enum dc_permissions allow;
enum dc_permissions deny;
unsigned long long int allow;
unsigned long long int deny;
struct dc_channel * channel; /* nofree - on which channel does it apply */
struct dc_user * user; /* nofree - non-null if permission applies to a user */
struct dc_role * role; /* nofree - non-null if it applies to a role */
@ -753,12 +760,12 @@ void dc_api_stack (struct dc_api_io);
}
#define DC_ADDR_X(x, y) struct dc_##x * dc_addr_##x (struct dc_program * p, struct dc_##x *** a, size_t * so, size_t * l, struct dc_##x * u, enum dc_status s) { \
struct dc_##x * us; \
if (!a) { \
if (u != (us = dc_add_##x(&p->x##s, &p->x##s_sizeof, &p->x##s_length, u, s))) \
return us; \
} else \
if (u != (us = dc_add_##x(a, so, l, u, s))) \
return us; \
if (!a) \
us = dc_add_##x(&p->x##s, &p->x##s_sizeof, &p->x##s_length, u, s); \
else \
us = dc_add_##x(a, so, l, u, s); \
if (us != u) \
return us; \
struct dc_api_io io; \
memset(&io, 0, sizeof(io)); \
io.type = DC_API_##y; \

4
src/ui.c

@ -29,7 +29,7 @@ void dc_ui_spawn_message (struct dc_message * m, struct dc_ui_data * d) { /* !m
GtkWidget * w, * w2;
#define DC_USMTL 32
char t[DC_USMTL];
g_autoptr(gchar) c = g_key_file_get_string(d->k, "discord.c", "strftime", NULL);
char * c;
GtkGrid * g = GTK_GRID(gtk_builder_get_object(d->b, "dc_main_messages"));
if (!m) {
while (gtk_grid_get_child_at(g, 0, 0))
@ -60,7 +60,9 @@ void dc_ui_spawn_message (struct dc_message * m, struct dc_ui_data * d) { /* !m
snprintf(t, DC_USMTL, "%s#%04d", m->user->username, m->user->discriminator);
gtk_container_add(GTK_CONTAINER(b), gtk_label_new(t));
/* TODO: implement parsing markup here: bold, italic, underline; REMOVE < character; implement tags, timestamps, channels and spoilers with GTK ahrefs */
c = g_key_file_get_string(d->k, "discord.c", "strftime", NULL);
strftime(t, DC_USMTL, c ? strcmp(c, "") ? c : "%c" : "%c", localtime(&m->time)); /* singlethreaded only */
free(c);
gtk_container_add(GTK_CONTAINER(b), gtk_label_new(t));
g_object_set_data(G_OBJECT(b), "message", m);
gtk_grid_attach(g /* grid */, b /* widget to insert */, 0 /* left */, i /* top */, 1 /* width */, 1 /* height */);

Loading…
Cancel
Save

Med zimskimi počitnicami so pričakovani občasni izpadi podomrežja O, ker bodo izvajana testiranja varnosti komunikacijsko-informacijske opreme.