diff options
| -rw-r--r-- | LICENSE | 2 | ||||
| -rw-r--r-- | RELEASE_NOTES.md | 12 | ||||
| -rw-r--r-- | activitypub.c | 7 | ||||
| -rw-r--r-- | data.c | 2 | ||||
| -rw-r--r-- | doc/snac.8 | 2 | ||||
| -rw-r--r-- | format.c | 2 | ||||
| -rw-r--r-- | html.c | 160 | ||||
| -rw-r--r-- | http.c | 2 | ||||
| -rw-r--r-- | httpd.c | 2 | ||||
| -rw-r--r-- | main.c | 4 | ||||
| -rw-r--r-- | mastoapi.c | 6 | ||||
| -rw-r--r-- | po/pt_BR.po | 12 | ||||
| -rw-r--r-- | rss.c | 12 | ||||
| -rw-r--r-- | snac.c | 2 | ||||
| -rw-r--r-- | snac.h | 4 | ||||
| -rw-r--r-- | upgrade.c | 2 | ||||
| -rw-r--r-- | utils.c | 2 | ||||
| -rw-r--r-- | webfinger.c | 2 | ||||
| -rw-r--r-- | xs.h | 2 | ||||
| -rw-r--r-- | xs_curl.h | 2 | ||||
| -rw-r--r-- | xs_fcgi.h | 2 | ||||
| -rw-r--r-- | xs_glob.h | 2 | ||||
| -rw-r--r-- | xs_hex.h | 2 | ||||
| -rw-r--r-- | xs_html.h | 2 | ||||
| -rw-r--r-- | xs_http.h | 2 | ||||
| -rw-r--r-- | xs_httpd.h | 2 | ||||
| -rw-r--r-- | xs_io.h | 2 | ||||
| -rw-r--r-- | xs_json.h | 4 | ||||
| -rw-r--r-- | xs_match.h | 2 | ||||
| -rw-r--r-- | xs_mime.h | 2 | ||||
| -rw-r--r-- | xs_openssl.h | 2 | ||||
| -rw-r--r-- | xs_po.h | 2 | ||||
| -rw-r--r-- | xs_random.h | 2 | ||||
| -rw-r--r-- | xs_regex.h | 2 | ||||
| -rw-r--r-- | xs_set.h | 2 | ||||
| -rw-r--r-- | xs_socket.h | 2 | ||||
| -rw-r--r-- | xs_time.h | 2 | ||||
| -rw-r--r-- | xs_unicode.h | 2 | ||||
| -rw-r--r-- | xs_unix_socket.h | 2 | ||||
| -rw-r--r-- | xs_url.h | 2 | ||||
| -rw-r--r-- | xs_version.h | 2 | ||||
| -rw-r--r-- | xs_webmention.h | 2 |
42 files changed, 233 insertions, 54 deletions
| @@ -1,6 +1,6 @@ | |||
| 1 | MIT License | 1 | MIT License |
| 2 | 2 | ||
| 3 | Copyright (c) 2022 - 2025 grunfink et al. (Fediverse: @grunfink@comam.es) | 3 | Copyright (c) 2022 - 2026 grunfink et al. (Fediverse: @grunfink@comam.es) |
| 4 | 4 | ||
| 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
| 6 | 6 | ||
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index d28b125..0dc7fc1 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md | |||
| @@ -2,6 +2,18 @@ | |||
| 2 | 2 | ||
| 3 | ## UNRELEASED | 3 | ## UNRELEASED |
| 4 | 4 | ||
| 5 | If `disable_emojireact` is set to `true` in `server.json`, EmojiReacts (incoming and outgoing) are totally disabled. | ||
| 6 | |||
| 7 | ## 2.87 | ||
| 8 | |||
| 9 | Hide EmojiReacts from muted actors and blocked instances. | ||
| 10 | |||
| 11 | ## 2.86 | ||
| 12 | |||
| 13 | Truncate RSS titles at UTF-8 character boundaries (contributed by lxo). | ||
| 14 | |||
| 15 | Link contacts to single-user people pages. Also, user's posts are shown (contributed by lxo). | ||
| 16 | |||
| 5 | Added emoji reactions (contributed by violette). | 17 | Added emoji reactions (contributed by violette). |
| 6 | 18 | ||
| 7 | Mastodon API: Fix for some client notifications (contributed by violette), fix for a status visibility error (contributed by fruye). | 19 | Mastodon API: Fix for some client notifications (contributed by violette), fix for a status visibility error (contributed by fruye). |
diff --git a/activitypub.c b/activitypub.c index 59df31a..5e55b8a 100644 --- a/activitypub.c +++ b/activitypub.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_json.h" | 5 | #include "xs_json.h" |
| @@ -2578,6 +2578,11 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) | |||
| 2578 | return -1; | 2578 | return -1; |
| 2579 | } | 2579 | } |
| 2580 | 2580 | ||
| 2581 | if (strcmp(type, "EmojiReact") == 0 && xs_is_true(xs_dict_get(srv_config, "disable_emojireact"))) { | ||
| 2582 | srv_log(xs_fmt("Dropping EmojiReact from %s due to admin configuration", actor)); | ||
| 2583 | return -1; | ||
| 2584 | } | ||
| 2585 | |||
| 2581 | const char *object, *utype; | 2586 | const char *object, *utype; |
| 2582 | 2587 | ||
| 2583 | object = xs_dict_get(msg, "object"); | 2588 | object = xs_dict_get(msg, "object"); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_hex.h" | 5 | #include "xs_hex.h" |
| @@ -296,6 +296,8 @@ outgoing messages (default: 15). Anyway, whenever any incoming activity from a | |||
| 296 | failed instance is detected, this counter is reset for it. | 296 | failed instance is detected, this counter is reset for it. |
| 297 | .It Ic vkey | 297 | .It Ic vkey |
| 298 | Public vapid key. Used for notification on some client. | 298 | Public vapid key. Used for notification on some client. |
| 299 | .It Ic disable_emojireact | ||
| 300 | If set to true, all EmojiReact support (for input and output) is disabled. | ||
| 299 | .El | 301 | .El |
| 300 | .Pp | 302 | .Pp |
| 301 | You must restart the server to make effective these changes. | 303 | You must restart the server to make effective these changes. |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_regex.h" | 5 | #include "xs_regex.h" |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_io.h" | 5 | #include "xs_io.h" |
| @@ -221,7 +221,7 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date, | |||
| 221 | anchored link to the people page instead of the actor url */ | 221 | anchored link to the people page instead of the actor url */ |
| 222 | if (fwer || fwing) { | 222 | if (fwer || fwing) { |
| 223 | xs *md5 = xs_md5_hex(actor_id, strlen(actor_id)); | 223 | xs *md5 = xs_md5_hex(actor_id, strlen(actor_id)); |
| 224 | href = xs_fmt("%s/people#%s", user->actor, md5); | 224 | href = xs_fmt("%s/people/%s", user->actor, md5); |
| 225 | } | 225 | } |
| 226 | } | 226 | } |
| 227 | 227 | ||
| @@ -2103,7 +2103,7 @@ xs_html *html_entry_controls(snac *user, const char *actor, | |||
| 2103 | xs_html_tag("p", NULL)); | 2103 | xs_html_tag("p", NULL)); |
| 2104 | } | 2104 | } |
| 2105 | 2105 | ||
| 2106 | { /** emoji react **/ | 2106 | if (!xs_is_true(xs_dict_get(srv_config, "disable_emojireact"))) { /** emoji react **/ |
| 2107 | /* the post textarea */ | 2107 | /* the post textarea */ |
| 2108 | xs *div_id = xs_fmt("%s_reply", md5); | 2108 | xs *div_id = xs_fmt("%s_reply", md5); |
| 2109 | xs *form_id = xs_fmt("%s_reply_form", md5); | 2109 | xs *form_id = xs_fmt("%s_reply_form", md5); |
| @@ -2355,7 +2355,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, | |||
| 2355 | } | 2355 | } |
| 2356 | 2356 | ||
| 2357 | if (!read_only && (fwers || fwing)) | 2357 | if (!read_only && (fwers || fwing)) |
| 2358 | href = xs_fmt("%s/people#%s", user->actor, p); | 2358 | href = xs_fmt("%s/people/%s", user->actor, p); |
| 2359 | else | 2359 | else |
| 2360 | href = xs_dup(id); | 2360 | href = xs_dup(id); |
| 2361 | 2361 | ||
| @@ -2447,7 +2447,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, | |||
| 2447 | 2447 | ||
| 2448 | /* add all emoji reacts */ | 2448 | /* add all emoji reacts */ |
| 2449 | int is_emoji = 0; | 2449 | int is_emoji = 0; |
| 2450 | { | 2450 | if (!xs_is_true(xs_dict_get(srv_config, "disable_emojireact"))) { |
| 2451 | int c = 0; | 2451 | int c = 0; |
| 2452 | const xs_dict *k; | 2452 | const xs_dict *k; |
| 2453 | xs *ls = xs_list_new(); | 2453 | xs *ls = xs_list_new(); |
| @@ -2460,6 +2460,10 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, | |||
| 2460 | const char *content = xs_dict_get(m, "content"); | 2460 | const char *content = xs_dict_get(m, "content"); |
| 2461 | const char *actor = xs_dict_get(m, "actor"); | 2461 | const char *actor = xs_dict_get(m, "actor"); |
| 2462 | const xs_list *contentl = xs_dict_get(sfrl, content); | 2462 | const xs_list *contentl = xs_dict_get(sfrl, content); |
| 2463 | |||
| 2464 | if ((user && is_muted(user, actor)) || is_instance_blocked(actor)) | ||
| 2465 | continue; | ||
| 2466 | |||
| 2463 | xs *actors = xs_list_new(); | 2467 | xs *actors = xs_list_new(); |
| 2464 | actors = xs_list_append(actors, actor); | 2468 | actors = xs_list_append(actors, actor); |
| 2465 | char me = actor && user && strcmp(actor, user->actor) == 0; | 2469 | char me = actor && user && strcmp(actor, user->actor) == 0; |
| @@ -3856,6 +3860,108 @@ xs_str *html_people(snac *user) | |||
| 3856 | return xs_html_render_s(html, "<!DOCTYPE html>\n"); | 3860 | return xs_html_render_s(html, "<!DOCTYPE html>\n"); |
| 3857 | } | 3861 | } |
| 3858 | 3862 | ||
| 3863 | /* Filter list to display only posts by actor. We'll probably show | ||
| 3864 | fewer than show posts. Should we try harder to find some? */ | ||
| 3865 | xs_str *html_people_one(snac *user, const char *actor, const xs_list *list, | ||
| 3866 | int skip, int show, int show_more, const char *page) | ||
| 3867 | { | ||
| 3868 | const char *proxy = NULL; | ||
| 3869 | xs_list *p = (xs_list *)list; | ||
| 3870 | const char *v; | ||
| 3871 | |||
| 3872 | if (xs_is_true(xs_dict_get(srv_config, "proxy_media"))) | ||
| 3873 | proxy = user->actor; | ||
| 3874 | |||
| 3875 | xs_html *body = html_user_body(user, 0); | ||
| 3876 | |||
| 3877 | xs_html *lists = xs_html_tag("div", | ||
| 3878 | xs_html_attr("class", "snac-posts")); | ||
| 3879 | |||
| 3880 | xs *foll = xs_list_append(xs_list_new(), actor); | ||
| 3881 | |||
| 3882 | xs_html_add(lists, | ||
| 3883 | html_people_list(user, foll, L("Contact's posts"), "p", proxy)); | ||
| 3884 | |||
| 3885 | xs_html_add(body, lists); | ||
| 3886 | |||
| 3887 | while (xs_list_iter(&p, &v)) { | ||
| 3888 | xs *msg = NULL; | ||
| 3889 | int status; | ||
| 3890 | |||
| 3891 | status = timeline_get_by_md5(user, v, &msg); | ||
| 3892 | |||
| 3893 | if (!valid_status(status)) | ||
| 3894 | continue; | ||
| 3895 | |||
| 3896 | const char *id = xs_dict_get(msg, "id"); | ||
| 3897 | const char *by = get_atto(msg); | ||
| 3898 | xs *actor_md5 = NULL; | ||
| 3899 | xs_list *boosts = NULL; | ||
| 3900 | xs_list *likes = NULL; | ||
| 3901 | xs_list *reacts = NULL; | ||
| 3902 | /* Besides actor's posts, also show actor's boosts, and also | ||
| 3903 | posts by user with likes or reacts by actor. I.e., any | ||
| 3904 | actor's actions that user could have seen in the timeline | ||
| 3905 | or in notifications. */ | ||
| 3906 | if (!(by && strcmp(actor, by) == 0) && | ||
| 3907 | xs_list_in((boosts = object_announces(id)), | ||
| 3908 | (actor_md5 = xs_md5_hex(actor, strlen(actor)))) == -1 && | ||
| 3909 | (!(by && strcmp(user->actor, by) == 0) || | ||
| 3910 | (xs_list_in((likes = object_likes(id)), actor_md5) == -1 && | ||
| 3911 | xs_list_in((reacts = object_get_emoji_reacts(id)), actor_md5) == -1))) | ||
| 3912 | continue; | ||
| 3913 | |||
| 3914 | xs_html *entry = html_entry(user, msg, 0, 0, v, 1); | ||
| 3915 | |||
| 3916 | if (entry != NULL) | ||
| 3917 | xs_html_add(lists, | ||
| 3918 | entry); | ||
| 3919 | } | ||
| 3920 | |||
| 3921 | if (show_more) { | ||
| 3922 | xs *m = NULL; | ||
| 3923 | xs *m10 = NULL; | ||
| 3924 | xs *ss = xs_fmt("skip=%d&show=%d", skip + show, show); | ||
| 3925 | |||
| 3926 | xs *url = xs_dup(user == NULL ? srv_baseurl : user->actor); | ||
| 3927 | |||
| 3928 | if (page != NULL) | ||
| 3929 | url = xs_str_cat(url, page); | ||
| 3930 | |||
| 3931 | if (xs_str_in(url, "?") != -1) | ||
| 3932 | m = xs_fmt("%s&%s", url, ss); | ||
| 3933 | else | ||
| 3934 | m = xs_fmt("%s?%s", url, ss); | ||
| 3935 | |||
| 3936 | m10 = xs_fmt("%s0", m); | ||
| 3937 | |||
| 3938 | xs_html *more_links = xs_html_tag("p", | ||
| 3939 | xs_html_tag("a", | ||
| 3940 | xs_html_attr("href", url), | ||
| 3941 | xs_html_attr("name", "snac-more"), | ||
| 3942 | xs_html_text(L("Back to top"))), | ||
| 3943 | xs_html_text(" - "), | ||
| 3944 | xs_html_tag("a", | ||
| 3945 | xs_html_attr("href", m), | ||
| 3946 | xs_html_attr("name", "snac-more"), | ||
| 3947 | xs_html_text(L("More..."))), | ||
| 3948 | xs_html_text(" - "), | ||
| 3949 | xs_html_tag("a", | ||
| 3950 | xs_html_attr("href", m10), | ||
| 3951 | xs_html_attr("name", "snac-more"), | ||
| 3952 | xs_html_text(L("More (x 10)...")))); | ||
| 3953 | |||
| 3954 | xs_html_add(body, | ||
| 3955 | more_links); | ||
| 3956 | } | ||
| 3957 | |||
| 3958 | xs_html *html = xs_html_tag("html", | ||
| 3959 | html_user_head(user, NULL, NULL), | ||
| 3960 | xs_html_add(body, | ||
| 3961 | html_footer(user))); | ||
| 3962 | |||
| 3963 | return xs_html_render_s(html, "<!DOCTYPE html>\n"); | ||
| 3964 | } | ||
| 3859 | 3965 | ||
| 3860 | xs_str *html_notifications(snac *user, int skip, int show) | 3966 | xs_str *html_notifications(snac *user, int skip, int show) |
| 3861 | { | 3967 | { |
| @@ -3924,6 +4030,9 @@ xs_str *html_notifications(snac *user, int skip, int show) | |||
| 3924 | if (xs_is_string(id2) && xs_set_add(&rep, id2) != 1) | 4030 | if (xs_is_string(id2) && xs_set_add(&rep, id2) != 1) |
| 3925 | continue; | 4031 | continue; |
| 3926 | 4032 | ||
| 4033 | if (strcmp(type, "EmojiReact") == 0 && xs_is_true(xs_dict_get(srv_config, "disable_emojireact"))) | ||
| 4034 | continue; | ||
| 4035 | |||
| 3927 | object_get(id, &obj); | 4036 | object_get(id, &obj); |
| 3928 | 4037 | ||
| 3929 | const char *msg_id = NULL; | 4038 | const char *msg_id = NULL; |
| @@ -4271,8 +4380,12 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 4271 | cache = 0; | 4380 | cache = 0; |
| 4272 | 4381 | ||
| 4273 | int skip = 0; | 4382 | int skip = 0; |
| 4383 | const char *max_show_default = "50"; | ||
| 4384 | int max_show = xs_number_get(xs_dict_get_def(srv_config, "max_timeline_entries", | ||
| 4385 | max_show_default)); | ||
| 4274 | int def_show = xs_number_get(xs_dict_get_def(srv_config, "def_timeline_entries", | 4386 | int def_show = xs_number_get(xs_dict_get_def(srv_config, "def_timeline_entries", |
| 4275 | xs_dict_get_def(srv_config, "max_timeline_entries", "50"))); | 4387 | xs_dict_get_def(srv_config, "max_timeline_entries", |
| 4388 | max_show_default))); | ||
| 4276 | int show = def_show; | 4389 | int show = def_show; |
| 4277 | 4390 | ||
| 4278 | if ((v = xs_dict_get(q_vars, "skip")) != NULL) | 4391 | if ((v = xs_dict_get(q_vars, "skip")) != NULL) |
| @@ -4298,6 +4411,8 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 4298 | /* a show of 0 has no sense */ | 4411 | /* a show of 0 has no sense */ |
| 4299 | if (show == 0) | 4412 | if (show == 0) |
| 4300 | show = def_show; | 4413 | show = def_show; |
| 4414 | if (show > max_show) | ||
| 4415 | show = max_show; | ||
| 4301 | 4416 | ||
| 4302 | if (p_path == NULL) { /** public timeline **/ | 4417 | if (p_path == NULL) { /** public timeline **/ |
| 4303 | xs *h = xs_str_localtime(0, "%Y-%m.html"); | 4418 | xs *h = xs_str_localtime(0, "%Y-%m.html"); |
| @@ -4415,7 +4530,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 4415 | actor_add(actor, actor_obj); | 4530 | actor_add(actor, actor_obj); |
| 4416 | 4531 | ||
| 4417 | /* create a people list with only one element */ | 4532 | /* create a people list with only one element */ |
| 4418 | l = xs_list_append(xs_list_new(), actor); | 4533 | l = xs_list_append(l, actor); |
| 4419 | 4534 | ||
| 4420 | xs *title = xs_fmt(L("Search results for account %s"), q); | 4535 | xs *title = xs_fmt(L("Search results for account %s"), q); |
| 4421 | 4536 | ||
| @@ -4555,6 +4670,37 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 4555 | } | 4670 | } |
| 4556 | } | 4671 | } |
| 4557 | else | 4672 | else |
| 4673 | if (xs_startswith(p_path, "people/")) { /** a single actor **/ | ||
| 4674 | if (!login(&snac, req)) { | ||
| 4675 | *body = xs_dup(uid); | ||
| 4676 | status = HTTP_STATUS_UNAUTHORIZED; | ||
| 4677 | } | ||
| 4678 | else { | ||
| 4679 | xs *actor_dict = NULL; | ||
| 4680 | const char *actor_id = NULL; | ||
| 4681 | xs *actor = NULL; | ||
| 4682 | xs_list *page_lst = xs_split_n(p_path, "?", 2); | ||
| 4683 | xs *page = xs_str_cat(xs_str_new("/"), xs_list_get(page_lst, 0)); | ||
| 4684 | xs_list *l = xs_split_n(page, "/", 3); | ||
| 4685 | const char *actor_md5 = xs_list_get(l, 2); | ||
| 4686 | |||
| 4687 | if (valid_status(object_get_by_md5(actor_md5, &actor_dict)) && | ||
| 4688 | (actor_id = xs_dict_get(actor_dict, "id")) != NULL && | ||
| 4689 | valid_status(actor_get(actor_id, &actor))) { | ||
| 4690 | int more = 0; | ||
| 4691 | xs *list = timeline_simple_list(&snac, "private", skip, show, &more); | ||
| 4692 | |||
| 4693 | *body = html_people_one(&snac, actor_id, list, skip, show, more, page); | ||
| 4694 | *b_size = strlen(*body); | ||
| 4695 | status = HTTP_STATUS_OK; | ||
| 4696 | } | ||
| 4697 | else { | ||
| 4698 | *body = xs_dup(uid); | ||
| 4699 | status = HTTP_STATUS_NOT_FOUND; | ||
| 4700 | } | ||
| 4701 | } | ||
| 4702 | } | ||
| 4703 | else | ||
| 4558 | if (strcmp(p_path, "notifications") == 0) { /** the list of notifications **/ | 4704 | if (strcmp(p_path, "notifications") == 0) { /** the list of notifications **/ |
| 4559 | if (!login(&snac, req)) { | 4705 | if (!login(&snac, req)) { |
| 4560 | *body = xs_dup(uid); | 4706 | *body = xs_dup(uid); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_io.h" | 5 | #include "xs_io.h" |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_io.h" | 5 | #include "xs_io.h" |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_io.h" | 5 | #include "xs_io.h" |
| @@ -18,7 +18,7 @@ | |||
| 18 | int usage(const char *cmd) | 18 | int usage(const char *cmd) |
| 19 | { | 19 | { |
| 20 | printf("snac " VERSION " - A simple, minimalistic ActivityPub instance\n"); | 20 | printf("snac " VERSION " - A simple, minimalistic ActivityPub instance\n"); |
| 21 | printf("Copyright (c) 2022 - 2025 grunfink et al. / MIT license\n"); | 21 | printf("Copyright (c) 2022 - 2026 grunfink et al. / MIT license\n"); |
| 22 | printf("\n"); | 22 | printf("\n"); |
| 23 | 23 | ||
| 24 | if (cmd == NULL) { | 24 | if (cmd == NULL) { |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #ifndef NO_MASTODON_API | 4 | #ifndef NO_MASTODON_API |
| 5 | 5 | ||
| @@ -1171,6 +1171,10 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) | |||
| 1171 | const char *content = xs_dict_get(msg, "content"); | 1171 | const char *content = xs_dict_get(msg, "content"); |
| 1172 | const char *actor = xs_dict_get(msg, "actor"); | 1172 | const char *actor = xs_dict_get(msg, "actor"); |
| 1173 | const xs_list *contentl = xs_dict_get(sfrl, content); | 1173 | const xs_list *contentl = xs_dict_get(sfrl, content); |
| 1174 | |||
| 1175 | if ((snac && is_muted(snac, actor)) || is_instance_blocked(actor)) | ||
| 1176 | continue; | ||
| 1177 | |||
| 1174 | /* NOTE: idk when there are no actor, but i encountered that bug. | 1178 | /* NOTE: idk when there are no actor, but i encountered that bug. |
| 1175 | * Probably because of one of my previous attempts. | 1179 | * Probably because of one of my previous attempts. |
| 1176 | * Keeping this just in case, can remove later */ | 1180 | * Keeping this just in case, can remove later */ |
diff --git a/po/pt_BR.po b/po/pt_BR.po index e930490..71b0132 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po | |||
| @@ -4,13 +4,13 @@ | |||
| 4 | msgid "" | 4 | msgid "" |
| 5 | msgstr "" | 5 | msgstr "" |
| 6 | "Project-Id-Version: snac\n" | 6 | "Project-Id-Version: snac\n" |
| 7 | "PO-Revision-Date: 2025-10-11 16:48-0300\n" | 7 | "PO-Revision-Date: 2025-12-22 07:55-0300\n" |
| 8 | "Last-Translator: Daltux <@daltux@snac.daltux.net>\n" | 8 | "Last-Translator: Daltux <@daltux@snac.daltux.net>\n" |
| 9 | "Language: pt_BR\n" | 9 | "Language: pt_BR\n" |
| 10 | "MIME-Version: 1.0\n" | 10 | "MIME-Version: 1.0\n" |
| 11 | "Content-Type: text/plain; charset=UTF-8\n" | 11 | "Content-Type: text/plain; charset=UTF-8\n" |
| 12 | "Content-Transfer-Encoding: 8bit\n" | 12 | "Content-Transfer-Encoding: 8bit\n" |
| 13 | "X-Generator: Poedit 3.7\n" | 13 | "X-Generator: Geany / PoHelper 2.0\n" |
| 14 | 14 | ||
| 15 | #: html.c:534 | 15 | #: html.c:534 |
| 16 | msgid "Sensitive content: " | 16 | msgid "Sensitive content: " |
| @@ -800,17 +800,17 @@ msgid "Direct Message" | |||
| 800 | msgstr "Mensagem direta" | 800 | msgstr "Mensagem direta" |
| 801 | 801 | ||
| 802 | #: html.c:488 html.c:2534 html.c:2559 html.c:5177 | 802 | #: html.c:488 html.c:2534 html.c:2559 html.c:5177 |
| 803 | msgid "EmojiUnreact" | 803 | msgid "Desfazer EmojiReação" |
| 804 | msgstr "" | 804 | msgstr "" |
| 805 | 805 | ||
| 806 | #: html.c:488 html.c:1440 html.c:2534 html.c:2559 html.c:5188 | 806 | #: html.c:488 html.c:1440 html.c:2534 html.c:2559 html.c:5188 |
| 807 | msgid "EmojiReact" | 807 | msgid "EmojiReact" |
| 808 | msgstr "" | 808 | msgstr "EmojiReação" |
| 809 | 809 | ||
| 810 | #: html.c:2115 | 810 | #: html.c:2115 |
| 811 | msgid "Emoji react..." | 811 | msgid "Emoji react..." |
| 812 | msgstr "" | 812 | msgstr "EmojiReagir..." |
| 813 | 813 | ||
| 814 | #: html.c:2609 | 814 | #: html.c:2609 |
| 815 | msgid "Emoji reactions: " | 815 | msgid "Emoji reactions: " |
| 816 | msgstr "" | 816 | msgstr "EmojiReações: " |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2025 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_html.h" | 5 | #include "xs_html.h" |
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "xs_openssl.h" | 10 | #include "xs_openssl.h" |
| 11 | #include "xs_json.h" | 11 | #include "xs_json.h" |
| 12 | #include "xs_http.h" | 12 | #include "xs_http.h" |
| 13 | #include "xs_unicode.h" | ||
| 13 | 14 | ||
| 14 | #include "snac.h" | 15 | #include "snac.h" |
| 15 | 16 | ||
| @@ -74,7 +75,14 @@ xs_str *rss_from_timeline(snac *user, const xs_list *timeline, | |||
| 74 | title = xs_regex_replace_i(title, "&[^;]+;", " "); | 75 | title = xs_regex_replace_i(title, "&[^;]+;", " "); |
| 75 | int i; | 76 | int i; |
| 76 | 77 | ||
| 77 | for (i = 0; title[i] && title[i] != '\n' && i < 50; i++); | 78 | for (i = 0; title[i] && title[i] != '\n' && i < 50; ) { |
| 79 | const char *p = &title[i]; | ||
| 80 | unsigned int cp = xs_utf8_dec(&p); | ||
| 81 | int n = p - title; | ||
| 82 | if (cp == 0xfffd || n > 50) | ||
| 83 | break; | ||
| 84 | i = n; | ||
| 85 | } | ||
| 78 | 86 | ||
| 79 | if (title[i] != '\0') { | 87 | if (title[i] != '\0') { |
| 80 | title[i] = '\0'; | 88 | title[i] = '\0'; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #define XS_IMPLEMENTATION | 4 | #define XS_IMPLEMENTATION |
| 5 | 5 | ||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #define VERSION "2.86-dev" | 4 | #define VERSION "2.87" |
| 5 | 5 | ||
| 6 | #define USER_AGENT "snac/" VERSION | 6 | #define USER_AGENT "snac/" VERSION |
| 7 | 7 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_io.h" | 5 | #include "xs_io.h" |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_io.h" | 5 | #include "xs_io.h" |
diff --git a/webfinger.c b/webfinger.c index 1ce5e76..264cb85 100644 --- a/webfinger.c +++ b/webfinger.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* snac - A simple, minimalistic ActivityPub instance */ | 1 | /* snac - A simple, minimalistic ActivityPub instance */ |
| 2 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 2 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 3 | 3 | ||
| 4 | #include "xs.h" | 4 | #include "xs.h" |
| 5 | #include "xs_json.h" | 5 | #include "xs_json.h" |
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_H | 3 | #ifndef _XS_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_CURL_H | 3 | #ifndef _XS_CURL_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | /* | 3 | /* |
| 4 | This is an intentionally-dead-simple FastCGI implementation; | 4 | This is an intentionally-dead-simple FastCGI implementation; |
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_GLOB_H | 3 | #ifndef _XS_GLOB_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_HEX_H | 3 | #ifndef _XS_HEX_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_HTML_H | 3 | #ifndef _XS_HTML_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_HTTP_H | 3 | #ifndef _XS_HTTP_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_HTTPD_H | 3 | #ifndef _XS_HTTPD_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_IO_H | 3 | #ifndef _XS_IO_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_JSON_H | 3 | #ifndef _XS_JSON_H |
| 4 | 4 | ||
| @@ -28,6 +28,8 @@ int xs_json_load_object(FILE *f, int maxdepth, xs_dict **d); | |||
| 28 | 28 | ||
| 29 | /** IMPLEMENTATION **/ | 29 | /** IMPLEMENTATION **/ |
| 30 | 30 | ||
| 31 | #include "xs_unicode.h" | ||
| 32 | |||
| 31 | /** JSON dumps **/ | 33 | /** JSON dumps **/ |
| 32 | 34 | ||
| 33 | static void _xs_json_dump_str(const char *data, FILE *f) | 35 | static void _xs_json_dump_str(const char *data, FILE *f) |
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_MATCH_H | 3 | #ifndef _XS_MATCH_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_MIME_H | 3 | #ifndef _XS_MIME_H |
| 4 | 4 | ||
diff --git a/xs_openssl.h b/xs_openssl.h index f215bcc..64b59dd 100644 --- a/xs_openssl.h +++ b/xs_openssl.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_OPENSSL_H | 3 | #ifndef _XS_OPENSSL_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2025 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_PO_H | 3 | #ifndef _XS_PO_H |
| 4 | 4 | ||
diff --git a/xs_random.h b/xs_random.h index f936099..357f9cb 100644 --- a/xs_random.h +++ b/xs_random.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_RANDOM_H | 3 | #ifndef _XS_RANDOM_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_REGEX_H | 3 | #ifndef _XS_REGEX_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_SET_H | 3 | #ifndef _XS_SET_H |
| 4 | 4 | ||
diff --git a/xs_socket.h b/xs_socket.h index 7bf5298..70bfe98 100644 --- a/xs_socket.h +++ b/xs_socket.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_SOCKET_H | 3 | #ifndef _XS_SOCKET_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_TIME_H | 3 | #ifndef _XS_TIME_H |
| 4 | 4 | ||
diff --git a/xs_unicode.h b/xs_unicode.h index 0b4de1c..7686dcd 100644 --- a/xs_unicode.h +++ b/xs_unicode.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_UNICODE_H | 3 | #ifndef _XS_UNICODE_H |
| 4 | 4 | ||
diff --git a/xs_unix_socket.h b/xs_unix_socket.h index 462a5b3..1ef7d39 100644 --- a/xs_unix_socket.h +++ b/xs_unix_socket.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_UNIX_SOCKET_H | 3 | #ifndef _XS_UNIX_SOCKET_H |
| 4 | 4 | ||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_URL_H | 3 | #ifndef _XS_URL_H |
| 4 | 4 | ||
diff --git a/xs_version.h b/xs_version.h index 34a7a45..598c72e 100644 --- a/xs_version.h +++ b/xs_version.h | |||
| @@ -1 +1 @@ | |||
| /* 0a8b987d7bb945fe7844411727d03ac73f417455 2025-10-14T05:21:05+02:00 */ | /* ad74258be9b1585840a5366cdb4b6ef707c0e95a 2026-01-01T16:58:39+01:00 */ | ||
diff --git a/xs_webmention.h b/xs_webmention.h index f9578b4..035b3a6 100644 --- a/xs_webmention.h +++ b/xs_webmention.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* copyright (c) 2025 grunfink et al. / MIT license */ | 1 | /* copyright (c) 2025 - 2026 grunfink et al. / MIT license */ |
| 2 | 2 | ||
| 3 | #ifndef _XS_WEBMENTION_H | 3 | #ifndef _XS_WEBMENTION_H |
| 4 | 4 | ||