From a45c1ce152011e8fe25eb1d25594ac5705f65404 Mon Sep 17 00:00:00 2001 From: rako Date: Fri, 28 Nov 2025 10:37:49 +0100 Subject: Fix user matching In order to be a proper prefix, the actor url must end with a '/' otherwise it can match another user that starts with the same prefix: for example 'testuser' will match anything made by 'testuser2' --- mastoapi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 94912f1..acb95a0 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1919,7 +1919,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, /* add only posts by the author */ if (!xs_is_null(msg_id) && strcmp(xs_dict_get(msg, "type"), "Note") == 0 && - xs_startswith(xs_dict_get(msg, "id"), snac2.actor) && is_msg_public(msg)) { + is_msg_mine(&snac2, xs_dict_get(msg, "id")) && is_msg_public(msg)) { /* if max_id is set, skip entries until we find it */ if (skip_until_max) { @@ -3824,7 +3824,7 @@ int mastoapi_delete_handler(const xs_dict *req, const char *q_path, if (valid_status(object_get_by_md5(p, &obj))) { const char *id = xs_dict_get(obj, "id"); - if (xs_is_string(id) && xs_startswith(id, snac.actor)) { + if (xs_is_string(id) && is_msg_mine(&snac, id)) { xs *out = mastoapi_status(&snac, obj); xs *msg = msg_delete(&snac, id); -- cgit v1.2.3 From 4102a6a7ac7ab7c651fe0b03358148e8d15418cc Mon Sep 17 00:00:00 2001 From: violette p. Date: Tue, 9 Dec 2025 04:58:13 +0100 Subject: make webpush use our notification server vkey instead of a random, ill-formated key (necessary for some client notifications, such as moshidon) --- mastoapi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index acb95a0..9aa29d8 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -3044,7 +3044,10 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, xs *app = xs_dict_new(); xs *id = xs_replace_i(tid(0), ".", ""); xs *csec = random_str(); - xs *vkey = random_str(); + char *vkey = (char *)xs_dict_get(srv_config, "vkey"); + if (vkey == NULL) + vkey = random_str(); + xs *cid = NULL; /* pick a non-existent random cid */ -- cgit v1.2.3 From a8b706b193d8d22191fa85ac290b90491be54ee3 Mon Sep 17 00:00:00 2001 From: grunfink Date: Tue, 9 Dec 2025 05:01:06 +0100 Subject: Fixed small memory leak. --- mastoapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 9aa29d8..9503447 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -3044,7 +3044,7 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, xs *app = xs_dict_new(); xs *id = xs_replace_i(tid(0), ".", ""); xs *csec = random_str(); - char *vkey = (char *)xs_dict_get(srv_config, "vkey"); + xs *vkey = xs_dup(xs_dict_get(srv_config, "vkey")); if (vkey == NULL) vkey = random_str(); -- cgit v1.2.3 From 85ed0eb0d535700a5df837c37f51848811e461a0 Mon Sep 17 00:00:00 2001 From: violette Date: Thu, 18 Dec 2025 07:58:24 +0100 Subject: Added emoji reactions (contributed by violette). --- mastoapi.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 156 insertions(+), 4 deletions(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 9503447..1d99cd5 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1158,6 +1158,97 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) st = xs_dict_append(st, "tags", htl); st = xs_dict_append(st, "emojis", eml); } + { + xs *rl = object_get_emoji_reacts(id); + xs *frl = xs_list_new(); /* final */ + xs *sfrl = xs_dict_new(); /* seen */ + int c = 0; + const char *v; + + xs_dict *msg = NULL; + while (xs_list_next(rl, &v, &c)) { + if (valid_status(object_get_by_md5(v, &msg))) { + const char *content = xs_dict_get(msg, "content"); + const char *actor = xs_dict_get(msg, "actor"); + const xs_list *contentl = xs_dict_get(sfrl, content); + /* NOTE: idk when there are no actor, but i encountered that bug. + * Probably because of one of my previous attempts. + * Keeping this just in case, can remove later */ + const char *me = actor && strcmp(actor, snac->actor) == 0 ? + xs_stock(XSTYPE_TRUE) : xs_stock(XSTYPE_FALSE); + int count = 1; + + if (contentl) { + count = atoi(xs_list_get(contentl, 0)) + 1; + if (strncmp(xs_list_get(contentl, 1), xs_stock(XSTYPE_TRUE), 1) == 0) + me = xs_stock(XSTYPE_TRUE); + } + + xs *fl = xs_list_new(); + fl = xs_list_append(fl, xs_fmt("%d", count), me); + sfrl = xs_dict_append(sfrl, content, fl); + } + } + + c = 0; + + while (xs_list_next(rl, &v, &c)) { + if (valid_status(object_get_by_md5(v, &msg))) { + xs *d1 = xs_dict_new(); + + const xs_dict *icon = xs_dict_get(xs_list_get(xs_dict_get(msg, "tag"), 0), "icon"); + const char *o_url = xs_dict_get(icon, "url"); + const char *name = xs_dict_get(msg, "content"); + const char *actor = xs_dict_get(msg, "actor"); + + xs *nm = xs_dup(name); + xs *url = NULL; + + if (!xs_is_null(o_url)) { + if (actor && snac && !strcmp(actor, snac->actor)) + url = make_url(o_url, NULL, 1); + else + url = xs_dup(o_url); + } + + xs *accounts = xs_list_new(); + if (actor) { + xs *d2 = xs_dict_new(); + object_get(actor, &d2); + xs *e_acct = mastoapi_account(snac, d2); + accounts = xs_list_append(accounts, e_acct); + } + + const xs_list *item = xs_dict_get(sfrl, nm); + const xs_str *nb = xs_list_get(item, 0); + const xs_val *me = xs_list_get(item, 1); + if (item == NULL) + continue; + + if (nm && strcmp(nm, "")) { + if (url && strcmp(url, "")) { + d1 = xs_dict_append(d1, "name", nm); + d1 = xs_dict_append(d1, "shortcode", nm); + d1 = xs_dict_append(d1, "accounts", accounts); + d1 = xs_dict_append(d1, "me", me); + d1 = xs_dict_append(d1, "url", url); + d1 = xs_dict_append(d1, "static_url", url); + d1 = xs_dict_append(d1, "visible_in_picker", xs_stock(XSTYPE_TRUE)); + d1 = xs_dict_append(d1, "count", nb); + } else { + d1 = xs_dict_append(d1, "name", nm); + d1 = xs_dict_append(d1, "count", nb); + d1 = xs_dict_append(d1, "me", me); + d1 = xs_dict_append(d1, "visible_in_picker", xs_stock(XSTYPE_TRUE)); + } + sfrl = xs_dict_del(sfrl, nm); + frl = xs_list_append(frl, d1); + } + } + } + + st = xs_dict_append(st, "reactions", frl); + } xs_free(idx); xs_free(ixc); @@ -2202,15 +2293,24 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (noti == NULL) continue; + const xs_dict *tag = xs_list_get(xs_dict_get_path(noti, "msg.tag"), 0); + const char *type = xs_dict_get(noti, "type"); const char *utype = xs_dict_get(noti, "utype"); const char *objid = xs_dict_get(noti, "objid"); const char *id = xs_dict_get(noti, "id"); const char *actid = xs_dict_get(noti, "actor"); + + int isEmoji = 0; + xs *fid = xs_replace(id, ".", ""); xs *actor = NULL; xs *entry = NULL; + if (tag) { + isEmoji = strcmp(xs_dict_get(tag, "type"), "Emoji") ? 0 : 1; + } + if (!valid_status(actor_get(actid, &actor))) continue; @@ -2234,9 +2334,12 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, } /* convert the type */ - if (strcmp(type, "Like") == 0 || strcmp(type, "EmojiReact") == 0) + if (strcmp(type, "Like") == 0 && !isEmoji) type = "favourite"; else + if (isEmoji || strcmp(type, "EmojiReact") == 0) + type = "reaction"; + else if (strcmp(type, "Announce") == 0) type = "reblog"; else @@ -2277,8 +2380,29 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (strcmp(type, "follow") != 0 && !xs_is_null(objid)) { xs *st = mastoapi_status(&snac1, entry); - if (st) + if (st) { mn = xs_dict_append(mn, "status", st); + + if (strcmp(type, "reaction") == 0 && !xs_is_null(objid)) { + const char *eid = NULL; + const char *url = NULL; + int utf = 0; + + const xs_dict *tag = xs_list_get(xs_dict_get_path(noti, "msg.tag"), 0); + const char *content = xs_dict_get_path(noti, "msg.content"); + + url = xs_dict_get(xs_dict_get(tag, "icon"), "url"); + eid = xs_dict_get(tag, "name"); + + if (eid && url) { + mn = xs_dict_append(mn, "emoji", eid); + mn = xs_dict_append(mn, "emoji_url", url); + } + + if (xs_is_emoji((utf = xs_utf8_dec(&content)))) + mn = xs_dict_append(mn, "name", xs_fmt("&#%d;", utf)); + } + } } out = xs_list_append(out, mn); @@ -2594,6 +2718,11 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, "\"max_expiration\":2629746," "\"max_options\":8,\"min_expiration\":300}"); cfg = xs_dict_append(cfg, "polls", d14); + + + xs *d15 = xs_json_loads("{\"max_reactions\":50}"); + cfg = xs_dict_append(cfg, "reactions", d15); + } ins = xs_dict_append(ins, "configuration", cfg); @@ -3219,7 +3348,7 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, if (n_msg != NULL) { enqueue_message(&snac, n_msg); - timeline_admire(&snac, xs_dict_get(n_msg, "object"), snac.actor, 1); + timeline_admire(&snac, xs_dict_get(n_msg, "object"), snac.actor, 1, msg); out = mastoapi_status(&snac, msg); } @@ -3234,13 +3363,36 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, out = mastoapi_status(&snac, msg); } } + else + if (strcmp(op, "react") == 0) { /** **/ + const char *eid = xs_list_get(l, 5); + xs *n_msg = msg_emoji_init(&snac, id, eid); + if (n_msg) + out = mastoapi_status(&snac, n_msg); + } + else + if (strcmp(op, "unreact") == 0) { /** **/ + const char *eid = xs_list_get(l, 5); + xs *content = xs_fmt("%s", eid); + + if (eid) { + xs *n_msg = msg_emoji_unreact(&snac, id, content); + + if (n_msg != NULL) { + enqueue_message(&snac, n_msg); + + out = mastoapi_status(&snac, msg); + } + } + } + else if (strcmp(op, "reblog") == 0) { /** **/ xs *n_msg = msg_admiration(&snac, id, "Announce"); if (n_msg != NULL) { enqueue_message(&snac, n_msg); - timeline_admire(&snac, xs_dict_get(n_msg, "object"), snac.actor, 0); + timeline_admire(&snac, xs_dict_get(n_msg, "object"), snac.actor, 0, msg); out = mastoapi_status(&snac, msg); } -- cgit v1.2.3 From c8ee70f6df7276b7c02f902cc544d209139697b2 Mon Sep 17 00:00:00 2001 From: grunfink Date: Thu, 18 Dec 2025 08:20:15 +0100 Subject: Fixed some xs_fmt() usages. --- mastoapi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 1d99cd5..72379b5 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1185,7 +1185,8 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) } xs *fl = xs_list_new(); - fl = xs_list_append(fl, xs_fmt("%d", count), me); + xs *c1 = xs_fmt("%d", count); + fl = xs_list_append(fl, c1, me); sfrl = xs_dict_append(sfrl, content, fl); } } @@ -2399,8 +2400,10 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, mn = xs_dict_append(mn, "emoji_url", url); } - if (xs_is_emoji((utf = xs_utf8_dec(&content)))) - mn = xs_dict_append(mn, "name", xs_fmt("&#%d;", utf)); + if (xs_is_emoji((utf = xs_utf8_dec(&content)))) { + xs *s1 = xs_fmt("&#%d;", utf); + mn = xs_dict_append(mn, "name", s1); + } } } } -- cgit v1.2.3 From 2903b29e653d8549319ceabbb65de408d2e5c073 Mon Sep 17 00:00:00 2001 From: grunfink Date: Thu, 18 Dec 2025 08:58:04 +0100 Subject: Fixed more minor leaks. --- mastoapi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 72379b5..041f37e 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1165,8 +1165,8 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) int c = 0; const char *v; - xs_dict *msg = NULL; while (xs_list_next(rl, &v, &c)) { + xs *msg = NULL; if (valid_status(object_get_by_md5(v, &msg))) { const char *content = xs_dict_get(msg, "content"); const char *actor = xs_dict_get(msg, "actor"); @@ -1194,6 +1194,7 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) c = 0; while (xs_list_next(rl, &v, &c)) { + xs *msg = NULL; if (valid_status(object_get_by_md5(v, &msg))) { xs *d1 = xs_dict_new(); -- cgit v1.2.3 From e233f3f904e64d6ecaffdf68f8532e1587681fe3 Mon Sep 17 00:00:00 2001 From: violette Date: Fri, 19 Dec 2025 09:54:50 +0100 Subject: Some fixes. --- mastoapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 041f37e..d38e902 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1174,7 +1174,7 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) /* NOTE: idk when there are no actor, but i encountered that bug. * Probably because of one of my previous attempts. * Keeping this just in case, can remove later */ - const char *me = actor && strcmp(actor, snac->actor) == 0 ? + const char *me = actor && snac && strcmp(actor, snac->actor) == 0 ? xs_stock(XSTYPE_TRUE) : xs_stock(XSTYPE_FALSE); int count = 1; -- cgit v1.2.3 From c5824038b88e4dc5a5d121361ad7078084fb60c9 Mon Sep 17 00:00:00 2001 From: fruye Date: Mon, 22 Dec 2025 20:52:14 +0100 Subject: mastoapi: fixed status visibility error. --- mastoapi.c | 82 ++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 43 insertions(+), 39 deletions(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index d38e902..6a12ced 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1985,60 +1985,64 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, } else if (strcmp(opt, "statuses") == 0) { /** **/ - /* the public list of posts of a user */ - const char *limit_s = xs_dict_get(args, "limit"); - const char *o_max_id = xs_dict_get(args, "max_id"); - int limit = limit_s ? atoi(limit_s) : 20; - xs *max_id = o_max_id ? xs_tolower_i(xs_dup(o_max_id)) : NULL; + if (logged_in || xs_type(xs_dict_get(snac2.config, "private")) == XSTYPE_FALSE) { + /* the public list of posts of a user */ + const char *limit_s = xs_dict_get(args, "limit"); + const char *o_max_id = xs_dict_get(args, "max_id"); + int limit = limit_s ? atoi(limit_s) : 20; + xs *max_id = o_max_id ? xs_tolower_i(xs_dup(o_max_id)) : NULL; - srv_debug(1, xs_fmt("account statuses: max_id=%s limit=%d", max_id ? max_id : "(null)", limit)); + srv_debug(1, xs_fmt("account statuses: max_id=%s limit=%d", max_id ? max_id : "(null)", limit)); - xs *timeline = timeline_simple_list(&snac2, "public", 0, 256, NULL); - xs_list *p = timeline; - const xs_str *v; - xs_set seen; - int cnt = 0; - int skip_until_max = max_id != NULL; + xs *timeline = timeline_simple_list(&snac2, "public", 0, 256, NULL); + xs_list *p = timeline; + const xs_str *v; + xs_set seen; + int cnt = 0; + int skip_until_max = max_id != NULL; - out = xs_list_new(); - xs_set_init(&seen); + out = xs_list_new(); + xs_set_init(&seen); - while (xs_list_iter(&p, &v) && cnt < limit) { - xs *msg = NULL; + while (xs_list_iter(&p, &v) && cnt < limit) { + xs *msg = NULL; - if (valid_status(timeline_get_by_md5(&snac2, v, &msg))) { - const char *msg_id = xs_dict_get(msg, "id"); + if (valid_status(timeline_get_by_md5(&snac2, v, &msg))) { + const char *msg_id = xs_dict_get(msg, "id"); - /* add only posts by the author */ - if (!xs_is_null(msg_id) && - strcmp(xs_dict_get(msg, "type"), "Note") == 0 && - is_msg_mine(&snac2, xs_dict_get(msg, "id")) && is_msg_public(msg)) { + /* add only posts by the author */ + if (!xs_is_null(msg_id) && + strcmp(xs_dict_get(msg, "type"), "Note") == 0 && + is_msg_mine(&snac2, xs_dict_get(msg, "id")) && is_msg_public(msg)) { - /* if max_id is set, skip entries until we find it */ - if (skip_until_max) { - xs *mid = mastoapi_id(msg); - if (strcmp(mid, max_id) == 0) { - skip_until_max = 0; - srv_debug(2, xs_fmt("account statuses: found max_id, starting from next post")); + /* if max_id is set, skip entries until we find it */ + if (skip_until_max) { + xs *mid = mastoapi_id(msg); + if (strcmp(mid, max_id) == 0) { + skip_until_max = 0; + srv_debug(2, xs_fmt("account statuses: found max_id, starting from next post")); + } + continue; } - continue; - } - /* deduplicate by message id */ - if (xs_set_add(&seen, msg_id) == 1) { - xs *st = mastoapi_status(&snac2, msg); + /* deduplicate by message id */ + if (xs_set_add(&seen, msg_id) == 1) { + xs *st = mastoapi_status(&snac2, msg); - if (st) { - out = xs_list_append(out, st); - cnt++; + if (st) { + out = xs_list_append(out, st); + cnt++; + } } } } } - } - srv_debug(1, xs_fmt("account statuses: returning %d posts (requested %d)", cnt, limit)); - xs_set_free(&seen); + srv_debug(1, xs_fmt("account statuses: returning %d posts (requested %d)", cnt, limit)); + xs_set_free(&seen); + } + else + status = HTTP_STATUS_UNAUTHORIZED; } else if (strcmp(opt, "featured_tags") == 0) { -- cgit v1.2.3 From 11af00194e3e0ec15e17a23556dc2929f92e0210 Mon Sep 17 00:00:00 2001 From: grunfink Date: Thu, 1 Jan 2026 17:01:03 +0100 Subject: Bumped copyright year. --- mastoapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 6a12ced..0cadf2c 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1,5 +1,5 @@ /* snac - A simple, minimalistic ActivityPub instance */ -/* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ +/* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ #ifndef NO_MASTODON_API -- cgit v1.2.3 From b6414bd2c48dd54699f3bfbdae10bb0209841f0c Mon Sep 17 00:00:00 2001 From: grunfink Date: Tue, 6 Jan 2026 15:00:45 +0100 Subject: mastoapi: hide EmojiReacts from muted actors and block instances. --- mastoapi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 0cadf2c..52aca08 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1171,6 +1171,10 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) const char *content = xs_dict_get(msg, "content"); const char *actor = xs_dict_get(msg, "actor"); const xs_list *contentl = xs_dict_get(sfrl, content); + + if ((snac && is_muted(snac, actor)) || is_instance_blocked(actor)) + continue; + /* NOTE: idk when there are no actor, but i encountered that bug. * Probably because of one of my previous attempts. * Keeping this just in case, can remove later */ -- cgit v1.2.3 From 54bb1626d2c6b55b4c331946606a9986ba963225 Mon Sep 17 00:00:00 2001 From: violette Date: Mon, 12 Jan 2026 05:33:48 +0100 Subject: mastoapi: also return children of children. --- mastoapi.c | 51 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 17 deletions(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 52aca08..8187115 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1809,6 +1809,37 @@ xs_list *mastoapi_account_lists(snac *user, const char *uid) } +xs_list *build_childrens(const xs_dict *msg, snac *snac1) { + xs_list *ret = xs_list_new(); + xs *children = object_children(xs_dict_get(msg, "id")); + char *p = children; + const xs_str *v; + + while (xs_list_iter(&p, &v)) { + xs *m2 = NULL; + + if (valid_status(timeline_get_by_md5(snac1, v, &m2))) { + if (xs_is_null(xs_dict_get(m2, "name"))) { + xs *st = mastoapi_status(snac1, m2); + + if (st) { + /* childrens children */ + xs *childs = build_childrens(m2, snac1); + ret = xs_list_append(ret, st); + if (xs_list_len(childs)) { + char *p2 = childs; + while (xs_list_iter(&p2, &v)) + ret = xs_list_append(ret, v); + + } + } + } + } + } + return ret; +} + + int mastoapi_get_handler(const xs_dict *req, const char *q_path, char **body, int *b_size, char **ctype, xs_str **link) { @@ -2821,8 +2852,6 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, /* return ancestors and children */ xs *anc = xs_list_new(); xs *des = xs_list_new(); - xs_list *p; - const xs_str *v; char pid[MD5_HEX_SIZE]; /* build the [grand]parent list, moving up */ @@ -2842,21 +2871,9 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, } /* build the children list */ - xs *children = object_children(xs_dict_get(msg, "id")); - p = children; - - while (xs_list_iter(&p, &v)) { - xs *m2 = NULL; - - if (valid_status(timeline_get_by_md5(&snac1, v, &m2))) { - if (xs_is_null(xs_dict_get(m2, "name"))) { - xs *st = mastoapi_status(&snac1, m2); - - if (st) - des = xs_list_append(des, st); - } - } - } + xs *childs = build_childrens(msg, &snac1); + if (xs_list_len(childs) > 0) + des = xs_list_cat(des, childs); out = xs_dict_new(); out = xs_dict_append(out, "ancestors", anc); -- cgit v1.2.3 From de9d546d70cfcbf3b2450b70039470c9a68ecdc6 Mon Sep 17 00:00:00 2001 From: violette Date: Mon, 12 Jan 2026 06:03:04 +0100 Subject: Added emoji categories. --- mastoapi.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'mastoapi.c') diff --git a/mastoapi.c b/mastoapi.c index 8187115..dd80abc 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -2647,19 +2647,33 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (strcmp(cmd, "/v1/custom_emojis") == 0) { /** **/ xs *emo = emojis(); xs *list = xs_list_new(); - int c = 0; const xs_str *k; const xs_val *v; - while(xs_dict_next(emo, &k, &v, &c)) { + xs_dict_foreach(emo, k, v) { xs *current = xs_dict_new(); - if (xs_startswith(v, "https://") && xs_startswith((xs_mime_by_ext(v)), "image/")) { + if ((xs_startswith(v, "https://") && xs_startswith((xs_mime_by_ext(v)), "image/")) || xs_type(v) == XSTYPE_DICT) { /* remove first and last colon */ - xs *shortcode = xs_replace(k, ":", ""); - current = xs_dict_append(current, "shortcode", shortcode); - current = xs_dict_append(current, "url", v); - current = xs_dict_append(current, "static_url", v); - current = xs_dict_append(current, "visible_in_picker", xs_stock(XSTYPE_TRUE)); - list = xs_list_append(list, current); + if (xs_type(v) == XSTYPE_DICT) { + const char *v2; + const char *cat = k; + xs_dict_foreach(v, k, v2) { + xs *shortcode = xs_replace(k, ":", ""); + current = xs_dict_append(current, "shortcode", shortcode); + current = xs_dict_append(current, "url", v2); + current = xs_dict_append(current, "static_url", v2); + current = xs_dict_append(current, "visible_in_picker", xs_stock(XSTYPE_TRUE)); + current = xs_dict_append(current, "category", cat); + list = xs_list_append(list, current); + } + } + else { + xs *shortcode = xs_replace(k, ":", ""); + current = xs_dict_append(current, "shortcode", shortcode); + current = xs_dict_append(current, "url", v); + current = xs_dict_append(current, "static_url", v); + current = xs_dict_append(current, "visible_in_picker", xs_stock(XSTYPE_TRUE)); + list = xs_list_append(list, current); + } } } *body = xs_json_dumps(list, 0); -- cgit v1.2.3