summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2021-09-24 22:53:01 +0200
committerAnton Luka Šijanec <anton@sijanec.eu>2021-09-24 22:53:01 +0200
commit605cb0ca371517c7a5cff79b4ef2dfdfe22ab4fe (patch)
treeebe76db9117a7f64f7e958fb264c05f45825d4c6
parentshit (diff)
downloaddiscord.c-605cb0ca371517c7a5cff79b4ef2dfdfe22ab4fe.tar
discord.c-605cb0ca371517c7a5cff79b4ef2dfdfe22ab4fe.tar.gz
discord.c-605cb0ca371517c7a5cff79b4ef2dfdfe22ab4fe.tar.bz2
discord.c-605cb0ca371517c7a5cff79b4ef2dfdfe22ab4fe.tar.lz
discord.c-605cb0ca371517c7a5cff79b4ef2dfdfe22ab4fe.tar.xz
discord.c-605cb0ca371517c7a5cff79b4ef2dfdfe22ab4fe.tar.zst
discord.c-605cb0ca371517c7a5cff79b4ef2dfdfe22ab4fe.zip
Diffstat (limited to '')
-rw-r--r--Makefile6
-rw-r--r--README.md2
-rw-r--r--src/api.c47
-rw-r--r--src/h.c43
-rw-r--r--src/ui.c4
5 files changed, 69 insertions, 33 deletions
diff --git a/Makefile b/Makefile
index 86a4621..8bc8aa4 100644
--- a/Makefile
+++ b/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/
diff --git a/README.md b/README.md
index 48ab1f6..8721154 100644
--- a/README.md
+++ b/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
diff --git a/src/api.c b/src/api.c
index 43aca84..c405cff 100644
--- a/src/api.c
+++ b/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 */
diff --git a/src/h.c b/src/h.c
index 499885b..bd20bf8 100644
--- a/src/h.c
+++ b/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; \
diff --git a/src/ui.c b/src/ui.c
index f2dbe7a..279ef4f 100644
--- a/src/ui.c
+++ b/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 */);