From 165e38050c81ee6700232527c72dec96000cdd2b Mon Sep 17 00:00:00 2001 From: default Date: Tue, 11 Feb 2025 09:16:50 +0100 Subject: Updated documentation. --- doc/snac.8 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/snac.8 b/doc/snac.8 index 7e3213b..c0a110c 100644 --- a/doc/snac.8 +++ b/doc/snac.8 @@ -23,8 +23,12 @@ Ultrix machine in your grandfather basement, probably MacOS) support hard links on their native filesystems. Don't do fancy things like moving the subdirectories to different filesystems. Also, if you move your .Nm -installation to another server, do it with a tool that respect hard -link counts. Remember: +installation to another server, do it with a tool that keeps hard +links, like +.Xr tar 1 +or +.Xr rsync 1 +with the -H switch. Remember: .Nm is a very UNIXy program that loves hard links. .Ss Building and Installation -- cgit v1.2.3 From 5c27885a2f35106dc7934b8e9c08986004ba0a58 Mon Sep 17 00:00:00 2001 From: default Date: Tue, 11 Feb 2025 18:45:52 +0100 Subject: In sanitize(), also accept attribute values between single quotes. --- format.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format.c b/format.c index 4c8ed29..755aeb2 100644 --- a/format.c +++ b/format.c @@ -458,7 +458,7 @@ xs_str *sanitize(const char *content) if (valid_tags[i]) { /* accepted tag: rebuild it with only the accepted elements */ - xs *el = xs_regex_select(v, "(src|href|rel|class|target)=\"[^\"]*\""); + xs *el = xs_regex_select(v, "(src|href|rel|class|target)=(\"[^\"]*\"|'[^']*')"); xs *s3 = xs_join(el, " "); s2 = xs_fmt("<%s%s%s%s>", -- cgit v1.2.3 From f58642b4396f1433f270f15a2a19e50e08179be4 Mon Sep 17 00:00:00 2001 From: default Date: Tue, 11 Feb 2025 18:50:14 +0100 Subject: Added some checks to xs_regex_split_n(). --- xs_regex.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xs_regex.h b/xs_regex.h index a4db447..1e157d2 100644 --- a/xs_regex.h +++ b/xs_regex.h @@ -43,11 +43,13 @@ xs_list *xs_regex_split_n(const char *str, const char *rx, int count) while (count > 0 && !regexec(&re, (p = str + offset), 1, &rm, offset > 0 ? REG_NOTBOL : 0)) { /* add first the leading part of the string */ xs *s1 = xs_str_new_sz(p, rm.rm_so); - list = xs_list_append(list, s1); + + list = xs_list_append(list, xs_is_string(s1) ? s1 : ""); /* add now the matched text as the separator */ xs *s2 = xs_str_new_sz(p + rm.rm_so, rm.rm_eo - rm.rm_so); - list = xs_list_append(list, s2); + + list = xs_list_append(list, xs_is_string(s2) ? s2 : ""); /* move forward */ offset += rm.rm_eo; -- cgit v1.2.3 From 2f4e7a21dc7fc2096b37179a677c1a765409cb51 Mon Sep 17 00:00:00 2001 From: default Date: Tue, 11 Feb 2025 18:53:36 +0100 Subject: Bumped version. --- snac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snac.h b/snac.h index 2ff3235..9d349fd 100644 --- a/snac.h +++ b/snac.h @@ -1,7 +1,7 @@ /* snac - A simple, minimalistic ActivityPub instance */ /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ -#define VERSION "2.72" +#define VERSION "2.73-dev" #define USER_AGENT "snac/" VERSION -- cgit v1.2.3 From 09803021648ea958a889cc2aa743d5f8c65ecbae Mon Sep 17 00:00:00 2001 From: default Date: Tue, 11 Feb 2025 19:40:30 +0100 Subject: Don't show the bookmark emoji to strangers. --- html.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html.c b/html.c index e742e94..7b6495b 100644 --- a/html.c +++ b/html.c @@ -1839,7 +1839,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, xs_html_raw(" 📌 "))); } - if (user && is_bookmarked(user, id)) { + if (user && !read_only && is_bookmarked(user, id)) { /* add a bookmark emoji */ xs_html_add(score, xs_html_tag("span", -- cgit v1.2.3 From af8a95bbf0b3709d605175da92b93ad1d0aa0bd3 Mon Sep 17 00:00:00 2001 From: Santtu Lakkala Date: Thu, 13 Feb 2025 08:36:34 +0100 Subject: Limit JSON depth --- snac.h | 4 ++++ xs_json.h | 36 +++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/snac.h b/snac.h index 9d349fd..d2d73af 100644 --- a/snac.h +++ b/snac.h @@ -16,6 +16,10 @@ #define MAX_THREADS 256 #endif +#ifndef MAX_JSON_DEPTH +#define MAX_JSON_DEPTH 8 +#endif + #ifndef MAX_CONVERSATION_LEVELS #define MAX_CONVERSATION_LEVELS 48 #endif diff --git a/xs_json.h b/xs_json.h index d1b18e4..b9421e4 100644 --- a/xs_json.h +++ b/xs_json.h @@ -7,14 +7,16 @@ int xs_json_dump(const xs_val *data, int indent, FILE *f); xs_str *xs_json_dumps(const xs_val *data, int indent); -xs_val *xs_json_load(FILE *f); -xs_val *xs_json_loads(const xs_str *json); +xs_val *xs_json_load_full(FILE *f, int maxdepth); +xs_val *xs_json_loads_full(const xs_str *json, int maxdepth); +#define xs_json_load(f) xs_json_load_full(f, MAX_JSON_DEPTH) +#define xs_json_loads(s) xs_json_loads_full(s, MAX_JSON_DEPTH) xstype xs_json_load_type(FILE *f); int xs_json_load_array_iter(FILE *f, xs_val **value, xstype *pt, int *c); int xs_json_load_object_iter(FILE *f, xs_str **key, xs_val **value, xstype *pt, int *c); -xs_list *xs_json_load_array(FILE *f); -xs_dict *xs_json_load_object(FILE *f); +xs_list *xs_json_load_array(FILE *f, int maxdepth); +xs_dict *xs_json_load_object(FILE *f, int maxdepth); #ifdef XS_IMPLEMENTATION @@ -371,7 +373,7 @@ int xs_json_load_array_iter(FILE *f, xs_val **value, xstype *pt, int *c) } -xs_list *xs_json_load_array(FILE *f) +xs_list *xs_json_load_array(FILE *f, int maxdepth) /* loads a full JSON array (after the initial OBRACK) */ { xstype t; @@ -387,12 +389,12 @@ xs_list *xs_json_load_array(FILE *f) if (r == 1) { /* partial load? */ - if (v == NULL) { + if (v == NULL && maxdepth != 0) { if (t == XSTYPE_LIST) - v = xs_json_load_array(f); + v = xs_json_load_array(f, maxdepth - 1); else if (t == XSTYPE_DICT) - v = xs_json_load_object(f); + v = xs_json_load_object(f, maxdepth - 1); } /* still null? fail */ @@ -459,7 +461,7 @@ int xs_json_load_object_iter(FILE *f, xs_str **key, xs_val **value, xstype *pt, } -xs_dict *xs_json_load_object(FILE *f) +xs_dict *xs_json_load_object(FILE *f, int maxdepth) /* loads a full JSON object (after the initial OCURLY) */ { xstype t; @@ -476,12 +478,12 @@ xs_dict *xs_json_load_object(FILE *f) if (r == 1) { /* partial load? */ - if (v == NULL) { + if (v == NULL && maxdepth != 0) { if (t == XSTYPE_LIST) - v = xs_json_load_array(f); + v = xs_json_load_array(f, maxdepth - 1); else if (t == XSTYPE_DICT) - v = xs_json_load_object(f); + v = xs_json_load_object(f, maxdepth - 1); } /* still null? fail */ @@ -500,14 +502,14 @@ xs_dict *xs_json_load_object(FILE *f) } -xs_val *xs_json_loads(const xs_str *json) +xs_val *xs_json_loads_full(const xs_str *json, int maxdepth) /* loads a string in JSON format and converts to a multiple data */ { FILE *f; xs_val *v = NULL; if ((f = fmemopen((char *)json, strlen(json), "r")) != NULL) { - v = xs_json_load(f); + v = xs_json_load_full(f, maxdepth); fclose(f); } @@ -533,17 +535,17 @@ xstype xs_json_load_type(FILE *f) } -xs_val *xs_json_load(FILE *f) +xs_val *xs_json_load_full(FILE *f, int maxdepth) /* loads a JSON file */ { xs_val *v = NULL; xstype t = xs_json_load_type(f); if (t == XSTYPE_LIST) - v = xs_json_load_array(f); + v = xs_json_load_array(f, maxdepth); else if (t == XSTYPE_DICT) - v = xs_json_load_object(f); + v = xs_json_load_object(f, maxdepth); return v; } -- cgit v1.2.3 From 4ccb52de741c90b086847193c425be0b97bdbf53 Mon Sep 17 00:00:00 2001 From: default Date: Thu, 13 Feb 2025 08:37:58 +0100 Subject: Added a default MAX_JSON_DEPTH inside xs_json.h. --- xs_json.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xs_json.h b/xs_json.h index b9421e4..8b449a9 100644 --- a/xs_json.h +++ b/xs_json.h @@ -4,6 +4,10 @@ #define _XS_JSON_H +#ifndef MAX_JSON_DEPTH +#define MAX_JSON_DEPTH 32 +#endif + int xs_json_dump(const xs_val *data, int indent, FILE *f); xs_str *xs_json_dumps(const xs_val *data, int indent); -- cgit v1.2.3 From e237a35f0d51683511e87e68c2fe3fd9bdf3ef9e Mon Sep 17 00:00:00 2001 From: default Date: Thu, 13 Feb 2025 19:38:54 +0100 Subject: Drop SVG attachments, as they may include JavaScript. --- html.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/html.c b/html.c index 7b6495b..d713fbb 100644 --- a/html.c +++ b/html.c @@ -2242,6 +2242,11 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, if (content && xs_str_in(content, o_href) != -1) continue; + /* drop silently any attachment that may include JavaScript */ + if (strcmp(type, "image/svg+xml") == 0 || + strcmp(type, "text/html") == 0) + continue; + /* do this attachment include an icon? */ const xs_dict *icon = xs_dict_get(a, "icon"); if (xs_type(icon) == XSTYPE_DICT) { -- cgit v1.2.3 From 292b2fd1224a40fd3fa5bc33248a7b11316abc22 Mon Sep 17 00:00:00 2001 From: default Date: Thu, 13 Feb 2025 19:44:21 +0100 Subject: Force the Content-Security-Policy header, instead of just suggesting it in the docs. --- doc/snac.8 | 4 +--- httpd.c | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/snac.8 b/doc/snac.8 index c0a110c..7a7352c 100644 --- a/doc/snac.8 +++ b/doc/snac.8 @@ -198,9 +198,7 @@ By setting this to true, no inbox collection is done. Inbox collection helps being discovered from remote instances, but also increases network traffic. .It Ic http_headers If you need to add more HTTP response headers for whatever reason, you can -fill this object with the required header/value pairs. For example, for enhanced -XSS security, you can set the "Content-Security-Policy" header to "script-src ;" -to be totally sure that no JavaScript is executed. +fill this object with the required header/value pairs. .It Ic show_instance_timeline If this is set to true, the instance base URL will show a timeline with the latest user posts instead of the default greeting static page. If other information diff --git a/httpd.c b/httpd.c index 5a38aff..d22bb14 100644 --- a/httpd.c +++ b/httpd.c @@ -553,6 +553,9 @@ void httpd_connection(FILE *f) headers = xs_dict_append(headers, "access-control-allow-origin", "*"); headers = xs_dict_append(headers, "access-control-allow-headers", "*"); + /* disable any form of fucking JavaScript */ + headers = xs_dict_append(headers, "Content-Security-Policy", "script-src ;"); + if (p_state->use_fcgi) xs_fcgi_response(f, status, headers, body, b_size, fcgi_id); else -- cgit v1.2.3 From 92a70be7f23577949bc8c50b736fa37086176e20 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 07:04:14 +0100 Subject: Minor string tweak. --- html.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/html.c b/html.c index d713fbb..10ce4ce 100644 --- a/html.c +++ b/html.c @@ -1052,8 +1052,8 @@ static xs_html *html_user_body(snac *user, int read_only) const char *longitude = xs_dict_get_def(user->config, "longitude", ""); if (*latitude && *longitude) { - xs *label = xs_fmt(L("%s,%s"), latitude, longitude); - xs *url = xs_fmt(L("https://openstreetmap.org/search?query=%s,%s"), + xs *label = xs_fmt("%s,%s", latitude, longitude); + xs *url = xs_fmt("https://openstreetmap.org/search?query=%s,%s", latitude, longitude); xs_html_add(top_user, -- cgit v1.2.3 From 722eb6830b8dd1ead5718ce6b9fb83248783b5e4 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 07:04:52 +0100 Subject: New Makefile target. --- Makefile | 7 + po/en.po | 693 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 700 insertions(+) create mode 100644 po/en.po diff --git a/Makefile b/Makefile index 75d9562..1fddbb2 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,13 @@ uninstall: rm $(PREFIX_MAN)/man5/snac.5 rm $(PREFIX_MAN)/man8/snac.8 +update-po: + mkdir -p po + [ -f "po/en.po" ] || xgettext -o po/en.po --language=C --keyword=L --from-code=utf-8 *.c + for a in po/*.po ; do \ + xgettext --omit-header -j -o $$a --language=C --keyword=L --from-code=utf-8 *.c ; \ + done + activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \ xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \ snac.h http_codes.h diff --git a/po/en.po b/po/en.po new file mode 100644 index 0000000..cb19c67 --- /dev/null +++ b/po/en.po @@ -0,0 +1,693 @@ +# snac message translation file +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: snac\n" +"Last-Translator: grunfink\n" +"Language: en\n" +"Content-Type: text/plain; charset=UTF-8\n" + +#: html.c:361 +msgid "Sensitive content: " +msgstr "" + +#: html.c:369 +msgid "Sensitive content description" +msgstr "" + +#: html.c:382 +msgid "Only for mentioned people: " +msgstr "" + +#: html.c:405 +msgid "Reply to (URL): " +msgstr "" + +#: html.c:414 +msgid "Don't send, but store as a draft" +msgstr "" + +#: html.c:415 +msgid "Draft:" +msgstr "" + +#: html.c:435 +msgid "Attachments..." +msgstr "" + +#: html.c:458 +msgid "File:" +msgstr "" + +#: html.c:462 +msgid "Clear this field to delete the attachment" +msgstr "" + +#: html.c:471 html.c:496 +msgid "Attachment description" +msgstr "" + +#: html.c:507 +msgid "Poll..." +msgstr "" + +#: html.c:509 +msgid "Poll options (one per line, up to 8):" +msgstr "" + +#: html.c:521 +msgid "One choice" +msgstr "" + +#: html.c:524 +msgid "Multiple choices" +msgstr "" + +#: html.c:530 +msgid "End in 5 minutes" +msgstr "" + +#: html.c:534 +msgid "End in 1 hour" +msgstr "" + +#: html.c:537 +msgid "End in 1 day" +msgstr "" + +#: html.c:545 +msgid "Post" +msgstr "" + +#: html.c:639 html.c:646 +msgid "Site description" +msgstr "" + +#: html.c:657 +msgid "Admin email" +msgstr "" + +#: html.c:670 +msgid "Admin account" +msgstr "" + +#: html.c:738 +#, c-format +msgid "%d following, %d followers " +msgstr "" + +#: html.c:826 +msgid "RSS" +msgstr "" + +#: html.c:831 html.c:859 +msgid "private" +msgstr "" + +#: html.c:855 +msgid "public" +msgstr "" + +#: html.c:863 +msgid "notifications" +msgstr "" + +#: html.c:868 +msgid "people" +msgstr "" + +#: html.c:872 +msgid "instance" +msgstr "" + +#: html.c:881 +msgid "" +"Search posts by URL or content (regular expression), @user@host accounts, or " +"#tag" +msgstr "" + +#: html.c:882 +msgid "Content search" +msgstr "" + +#: html.c:1004 +msgid "verified link" +msgstr "" + +#: html.c:1061 html.c:2382 html.c:2395 html.c:2404 +msgid "Location: " +msgstr "" + +#: html.c:1072 +#, c-format +msgid "%d following %d followers" +msgstr "" + +#: html.c:1097 +msgid "New Post..." +msgstr "" + +#: html.c:1099 +msgid "What's on your mind?" +msgstr "" + +#: html.c:1108 +msgid "Operations..." +msgstr "" + +#: html.c:1123 html.c:1639 html.c:2978 html.c:4276 +msgid "Follow" +msgstr "" + +#: html.c:1125 +msgid "(by URL or user@host)" +msgstr "" + +#: html.c:1140 html.c:1615 html.c:4228 +msgid "Boost" +msgstr "" + +#: html.c:1142 html.c:1159 +msgid "(by URL)" +msgstr "" + +#: html.c:1157 html.c:1594 html.c:4219 +msgid "Like" +msgstr "" + +#: html.c:1240 +msgid "User Settings..." +msgstr "" + +#: html.c:1249 +msgid "Display name:" +msgstr "" + +#: html.c:1255 +msgid "Your name" +msgstr "" + +#: html.c:1257 +msgid "Avatar: " +msgstr "" + +#: html.c:1265 +msgid "Delete current avatar" +msgstr "" + +#: html.c:1267 +msgid "Header image (banner): " +msgstr "" + +#: html.c:1275 +msgid "Delete current header image" +msgstr "" + +#: html.c:1277 +msgid "Bio:" +msgstr "" + +#: html.c:1283 +msgid "Write about yourself here..." +msgstr "" + +#: html.c:1292 +msgid "Always show sensitive content" +msgstr "" + +#: html.c:1294 +msgid "Email address for notifications:" +msgstr "" + +#: html.c:1302 +msgid "Telegram notifications (bot key and chat id):" +msgstr "" + +#: html.c:1316 +msgid "ntfy notifications (ntfy server and token):" +msgstr "" + +#: html.c:1330 +msgid "Maximum days to keep posts (0: server settings):" +msgstr "" + +#: html.c:1344 +msgid "Drop direct messages from people you don't follow" +msgstr "" + +#: html.c:1353 +msgid "This account is a bot" +msgstr "" + +#: html.c:1362 +msgid "Auto-boost all mentions to this account" +msgstr "" + +#: html.c:1371 +msgid "This account is private (posts are not shown through the web)" +msgstr "" + +#: html.c:1381 +msgid "Collapse top threads by default" +msgstr "" + +#: html.c:1390 +msgid "Follow requests must be approved" +msgstr "" + +#: html.c:1399 +msgid "Publish follower and following metrics" +msgstr "" + +#: html.c:1401 +msgid "Current location:" +msgstr "" + +#: html.c:1415 +msgid "Profile metadata (key=value pairs in each line):" +msgstr "" + +#: html.c:1426 +msgid "New password:" +msgstr "" + +#: html.c:1433 +msgid "Repeat new password:" +msgstr "" + +#: html.c:1443 +msgid "Update user info" +msgstr "" + +#: html.c:1454 +msgid "Followed hashtags..." +msgstr "" + +#: html.c:1456 +msgid "One hashtag per line" +msgstr "" + +#: html.c:1477 +msgid "Update hashtags" +msgstr "" + +#: html.c:1594 +msgid "Say you like this post" +msgstr "" + +#: html.c:1599 html.c:4237 +msgid "Unlike" +msgstr "" + +#: html.c:1599 +msgid "Nah don't like it that much" +msgstr "" + +#: html.c:1605 html.c:4369 +msgid "Unpin" +msgstr "" + +#: html.c:1605 +msgid "Unpin this post from your timeline" +msgstr "" + +#: html.c:1608 html.c:4364 +msgid "Pin" +msgstr "" + +#: html.c:1608 +msgid "Pin this post to the top of your timeline" +msgstr "" + +#: html.c:1615 +msgid "Announce this post to your followers" +msgstr "" + +#: html.c:1620 html.c:4245 +msgid "Unboost" +msgstr "" + +#: html.c:1620 +msgid "I regret I boosted this" +msgstr "" + +#: html.c:1626 html.c:4379 +msgid "Unbookmark" +msgstr "" + +#: html.c:1626 +msgid "Delete this post from your bookmarks" +msgstr "" + +#: html.c:1629 html.c:4374 +msgid "Bookmark" +msgstr "" + +#: html.c:1629 +msgid "Add this post to your bookmarks" +msgstr "" + +#: html.c:1635 html.c:2964 html.c:3152 html.c:4289 +msgid "Unfollow" +msgstr "" + +#: html.c:1635 html.c:2965 +msgid "Stop following this user's activity" +msgstr "" + +#: html.c:1639 html.c:2979 +msgid "Start following this user's activity" +msgstr "" + +#: html.c:1645 html.c:4319 +msgid "Unfollow Group" +msgstr "" + +#: html.c:1646 +msgid "Stop following this group or channel" +msgstr "" + +#: html.c:1650 html.c:4306 +msgid "Follow Group" +msgstr "" + +#: html.c:1651 +msgid "Start following this group or channel" +msgstr "" + +#: html.c:1656 html.c:3001 html.c:4253 +msgid "MUTE" +msgstr "" + +#: html.c:1657 +msgid "Block any activity from this user forever" +msgstr "" + +#: html.c:1662 html.c:2983 html.c:4336 +msgid "Delete" +msgstr "" + +#: html.c:1662 +msgid "Delete this post" +msgstr "" + +#: html.c:1665 html.c:4261 +msgid "Hide" +msgstr "" + +#: html.c:1665 +msgid "Hide this post and its children" +msgstr "" + +#: html.c:1696 +msgid "Edit..." +msgstr "" + +#: html.c:1715 +msgid "Reply..." +msgstr "" + +#: html.c:1766 +msgid "Truncated (too deep)" +msgstr "" + +#: html.c:1775 +msgid "follows you" +msgstr "" + +#: html.c:1838 +msgid "Pinned" +msgstr "" + +#: html.c:1846 +msgid "Bookmarked" +msgstr "" + +#: html.c:1854 +msgid "Poll" +msgstr "" + +#: html.c:1861 +msgid "Voted" +msgstr "" + +#: html.c:1870 +msgid "Event" +msgstr "" + +#: html.c:1902 html.c:1931 +msgid "boosted" +msgstr "" + +#: html.c:1947 +msgid "in reply to" +msgstr "" + +#: html.c:1998 +msgid " [SENSITIVE CONTENT]" +msgstr "" + +#: html.c:2175 +msgid "Vote" +msgstr "" + +#: html.c:2185 +msgid "Closed" +msgstr "" + +#: html.c:2210 +msgid "Closes in" +msgstr "" + +#: html.c:2289 +msgid "Video" +msgstr "" + +#: html.c:2304 +msgid "Audio" +msgstr "" + +#: html.c:2326 +msgid "Attachment" +msgstr "" + +#: html.c:2340 +msgid "Alt..." +msgstr "" + +#: html.c:2353 +msgid "Source channel or community" +msgstr "" + +#: html.c:2447 +msgid "Time: " +msgstr "" + +#: html.c:2522 +msgid "Older..." +msgstr "" + +#: html.c:2585 +msgid "about this site" +msgstr "" + +#: html.c:2587 +msgid "powered by " +msgstr "" + +#: html.c:2652 +msgid "Dismiss" +msgstr "" + +#: html.c:2669 +#, c-format +msgid "Timeline for list '%s'" +msgstr "" + +#: html.c:2688 html.c:3714 +msgid "Pinned posts" +msgstr "" + +#: html.c:2700 html.c:3729 +msgid "Bookmarked posts" +msgstr "" + +#: html.c:2712 html.c:3744 +msgid "Post drafts" +msgstr "" + +#: html.c:2771 +msgid "No more unseen posts" +msgstr "" + +#: html.c:2775 html.c:2875 +msgid "Back to top" +msgstr "" + +#: html.c:2828 +msgid "History" +msgstr "" + +#: html.c:2880 html.c:3300 +msgid "More..." +msgstr "" + +#: html.c:2969 html.c:4272 +msgid "Unlimit" +msgstr "" + +#: html.c:2970 +msgid "Allow announces (boosts) from this user" +msgstr "" + +#: html.c:2973 html.c:4268 +msgid "Limit" +msgstr "" + +#: html.c:2974 +msgid "Block announces (boosts) from this user" +msgstr "" + +#: html.c:2983 +msgid "Delete this user" +msgstr "" + +#: html.c:2988 html.c:4384 +msgid "Approve" +msgstr "" + +#: html.c:2989 +msgid "Approve this follow request" +msgstr "" + +#: html.c:2992 html.c:4408 +msgid "Discard" +msgstr "" + +#: html.c:2992 +msgid "Discard this follow request" +msgstr "" + +#: html.c:2997 html.c:4257 +msgid "Unmute" +msgstr "" + +#: html.c:2998 +msgid "Stop blocking activities from this user" +msgstr "" + +#: html.c:3002 +msgid "Block any activity from this user" +msgstr "" + +#: html.c:3010 +msgid "Direct Message..." +msgstr "" + +#: html.c:3045 +msgid "Pending follow confirmations" +msgstr "" + +#: html.c:3049 +msgid "People you follow" +msgstr "" + +#: html.c:3050 +msgid "People that follow you" +msgstr "" + +#: html.c:3089 +msgid "Clear all" +msgstr "" + +#: html.c:3146 +msgid "Mention" +msgstr "" + +#: html.c:3149 +msgid "Finished poll" +msgstr "" + +#: html.c:3164 +msgid "Follow Request" +msgstr "" + +#: html.c:3247 +msgid "Context" +msgstr "" + +#: html.c:3258 +msgid "New" +msgstr "" + +#: html.c:3273 +msgid "Already seen" +msgstr "" + +#: html.c:3288 +msgid "None" +msgstr "" + +#: html.c:3539 +#, c-format +msgid "Search results for account %s" +msgstr "" + +#: html.c:3546 +#, c-format +msgid "Account %s not found" +msgstr "" + +#: html.c:3577 +#, c-format +msgid "Search results for tag %s" +msgstr "" + +#: html.c:3577 +#, c-format +msgid "Nothing found for tag %s" +msgstr "" + +#: html.c:3593 +#, c-format +msgid "Search results for '%s' (may be more)" +msgstr "" + +#: html.c:3596 +#, c-format +msgid "Search results for '%s'" +msgstr "" + +#: html.c:3599 +#, c-format +msgid "No more matches for '%s'" +msgstr "" + +#: html.c:3601 +#, c-format +msgid "Nothing found for '%s'" +msgstr "" + +#: html.c:3699 +msgid "Showing instance timeline" +msgstr "" + +#: html.c:3767 +#, c-format +msgid "Showing timeline for list '%s'" +msgstr "" + +#: httpd.c:248 +#, c-format +msgid "Search results for tag #%s" +msgstr "" + +#: httpd.c:257 +msgid "Recent posts by users in this instance" +msgstr "" + +#: html.c:738 +#, c-format +msgid "%d following, %d followers · " +msgstr "" -- cgit v1.2.3 From b19b7154534c04de68792175e19eeacbcefe7c44 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 08:58:59 +0100 Subject: Disable "shortnames" of the image/svg+xml mediaType. --- html.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/html.c b/html.c index d713fbb..e45b0b2 100644 --- a/html.c +++ b/html.c @@ -69,7 +69,7 @@ xs_str *replace_shortnames(xs_str *s, const xs_list *tag, int ems, const char *p xs *style = xs_fmt("height: %dem; width: %dem; vertical-align: middle;", ems, ems); - const char *v; + const xs_dict *v; int c = 0; while (xs_list_next(tag_list, &v, &c)) { @@ -77,19 +77,25 @@ xs_str *replace_shortnames(xs_str *s, const xs_list *tag, int ems, const char *p if (t && strcmp(t, "Emoji") == 0) { const char *n = xs_dict_get(v, "name"); - const char *i = xs_dict_get(v, "icon"); + const xs_dict *i = xs_dict_get(v, "icon"); - if (n && i) { + if (xs_is_string(n) && xs_is_dict(i)) { const char *u = xs_dict_get(i, "url"); - xs *url = make_url(u, proxy, 0); + const char *mt = xs_dict_get(i, "mediaType"); + + if (xs_is_string(u) && xs_is_string(mt) && strcmp(mt, "image/svg+xml")) { + xs *url = make_url(u, proxy, 0); - xs_html *img = xs_html_sctag("img", - xs_html_attr("loading", "lazy"), - xs_html_attr("src", url), - xs_html_attr("style", style)); + xs_html *img = xs_html_sctag("img", + xs_html_attr("loading", "lazy"), + xs_html_attr("src", url), + xs_html_attr("style", style)); - xs *s1 = xs_html_render(img); - s = xs_replace_i(s, n, s1); + xs *s1 = xs_html_render(img); + s = xs_replace_i(s, n, s1); + } + else + s = xs_replace_i(s, n, ""); } } } -- cgit v1.2.3 From 26d0f5cbc3e07ecec2418b3377d3597c610e5a70 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 09:17:24 +0100 Subject: Some variable renaming. --- html.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/html.c b/html.c index 42b9b48..94e55fd 100644 --- a/html.c +++ b/html.c @@ -17,7 +17,7 @@ #include "snac.h" -int login(snac *snac, const xs_dict *headers) +int login(snac *user, const xs_dict *headers) /* tries a login */ { int logged_in = 0; @@ -31,23 +31,23 @@ int login(snac *snac, const xs_dict *headers) xs *l1 = xs_split_n(s2, ":", 1); if (xs_list_len(l1) == 2) { - const char *user = xs_list_get(l1, 0); + const char *uid = xs_list_get(l1, 0); const char *pwd = xs_list_get(l1, 1); const char *addr = xs_or(xs_dict_get(headers, "remote-addr"), xs_dict_get(headers, "x-forwarded-for")); - if (badlogin_check(user, addr)) { - logged_in = check_password(user, pwd, - xs_dict_get(snac->config, "passwd")); + if (badlogin_check(uid, addr)) { + logged_in = check_password(uid, pwd, + xs_dict_get(user->config, "passwd")); if (!logged_in) - badlogin_inc(user, addr); + badlogin_inc(uid, addr); } } } if (logged_in) - lastlog_write(snac, "web"); + lastlog_write(user, "web"); return logged_in; } -- cgit v1.2.3 From fc6a975f7b26aaa12136769be20b23a9f67e5a91 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 09:23:56 +0100 Subject: More variable renaming. --- html.c | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/html.c b/html.c index 94e55fd..78a7d32 100644 --- a/html.c +++ b/html.c @@ -1091,16 +1091,16 @@ static xs_html *html_user_body(snac *user, int read_only) } -xs_html *html_top_controls(snac *snac) +xs_html *html_top_controls(snac *user) /* generates the top controls */ { - xs *ops_action = xs_fmt("%s/admin/action", snac->actor); + xs *ops_action = xs_fmt("%s/admin/action", user->actor); xs_html *top_controls = xs_html_tag("div", xs_html_attr("class", "snac-top-controls"), /** new post **/ - html_note(snac, L("New Post..."), + html_note(user, L("New Post..."), "new_post_div", "new_post_form", L("What's on your mind?"), "", NULL, NULL, @@ -1170,53 +1170,53 @@ xs_html *html_top_controls(snac *snac) const char *email = "[disabled by admin]"; if (xs_type(xs_dict_get(srv_config, "disable_email_notifications")) != XSTYPE_TRUE) { - email = xs_dict_get(snac->config_o, "email"); + email = xs_dict_get(user->config_o, "email"); if (xs_is_null(email)) { - email = xs_dict_get(snac->config, "email"); + email = xs_dict_get(user->config, "email"); if (xs_is_null(email)) email = ""; } } - const char *cw = xs_dict_get(snac->config, "cw"); + const char *cw = xs_dict_get(user->config, "cw"); if (xs_is_null(cw)) cw = ""; - const char *telegram_bot = xs_dict_get(snac->config, "telegram_bot"); + const char *telegram_bot = xs_dict_get(user->config, "telegram_bot"); if (xs_is_null(telegram_bot)) telegram_bot = ""; - const char *telegram_chat_id = xs_dict_get(snac->config, "telegram_chat_id"); + const char *telegram_chat_id = xs_dict_get(user->config, "telegram_chat_id"); if (xs_is_null(telegram_chat_id)) telegram_chat_id = ""; - const char *ntfy_server = xs_dict_get(snac->config, "ntfy_server"); + const char *ntfy_server = xs_dict_get(user->config, "ntfy_server"); if (xs_is_null(ntfy_server)) ntfy_server = ""; - const char *ntfy_token = xs_dict_get(snac->config, "ntfy_token"); + const char *ntfy_token = xs_dict_get(user->config, "ntfy_token"); if (xs_is_null(ntfy_token)) ntfy_token = ""; - const char *purge_days = xs_dict_get(snac->config, "purge_days"); + const char *purge_days = xs_dict_get(user->config, "purge_days"); if (!xs_is_null(purge_days) && xs_type(purge_days) == XSTYPE_NUMBER) purge_days = (char *)xs_number_str(purge_days); else purge_days = "0"; - const xs_val *d_dm_f_u = xs_dict_get(snac->config, "drop_dm_from_unknown"); - const xs_val *bot = xs_dict_get(snac->config, "bot"); - const xs_val *a_private = xs_dict_get(snac->config, "private"); - const xs_val *auto_boost = xs_dict_get(snac->config, "auto_boost"); - const xs_val *coll_thrds = xs_dict_get(snac->config, "collapse_threads"); - const xs_val *pending = xs_dict_get(snac->config, "approve_followers"); - const xs_val *show_foll = xs_dict_get(snac->config, "show_contact_metrics"); - const char *latitude = xs_dict_get_def(snac->config, "latitude", ""); - const char *longitude = xs_dict_get_def(snac->config, "longitude", ""); + const xs_val *d_dm_f_u = xs_dict_get(user->config, "drop_dm_from_unknown"); + const xs_val *bot = xs_dict_get(user->config, "bot"); + const xs_val *a_private = xs_dict_get(user->config, "private"); + const xs_val *auto_boost = xs_dict_get(user->config, "auto_boost"); + const xs_val *coll_thrds = xs_dict_get(user->config, "collapse_threads"); + const xs_val *pending = xs_dict_get(user->config, "approve_followers"); + const xs_val *show_foll = xs_dict_get(user->config, "show_contact_metrics"); + const char *latitude = xs_dict_get_def(user->config, "latitude", ""); + const char *longitude = xs_dict_get_def(user->config, "longitude", ""); xs *metadata = NULL; - const xs_dict *md = xs_dict_get(snac->config, "metadata"); + const xs_dict *md = xs_dict_get(user->config, "metadata"); if (xs_type(md) == XSTYPE_DICT) { const xs_str *k; @@ -1238,7 +1238,7 @@ xs_html *html_top_controls(snac *snac) else metadata = xs_str_new(NULL); - xs *user_setup_action = xs_fmt("%s/admin/user-setup", snac->actor); + xs *user_setup_action = xs_fmt("%s/admin/user-setup", user->actor); xs_html_add(top_controls, xs_html_tag("details", @@ -1257,7 +1257,7 @@ xs_html *html_top_controls(snac *snac) xs_html_sctag("input", xs_html_attr("type", "text"), xs_html_attr("name", "name"), - xs_html_attr("value", xs_dict_get(snac->config, "name")), + xs_html_attr("value", xs_dict_get(user->config, "name")), xs_html_attr("placeholder", L("Your name")))), xs_html_tag("p", xs_html_text(L("Avatar: ")), @@ -1287,7 +1287,7 @@ xs_html *html_top_controls(snac *snac) xs_html_attr("cols", "40"), xs_html_attr("rows", "4"), xs_html_attr("placeholder", L("Write about yourself here...")), - xs_html_text(xs_dict_get(snac->config, "bio")))), + xs_html_text(xs_dict_get(user->config, "bio")))), xs_html_sctag("input", xs_html_attr("type", "checkbox"), xs_html_attr("name", "cw"), @@ -1450,8 +1450,8 @@ xs_html *html_top_controls(snac *snac) xs_html_tag("p", NULL))))); - xs *followed_hashtags_action = xs_fmt("%s/admin/followed-hashtags", snac->actor); - xs *followed_hashtags = xs_join(xs_dict_get_def(snac->config, + xs *followed_hashtags_action = xs_fmt("%s/admin/followed-hashtags", user->actor); + xs *followed_hashtags = xs_join(xs_dict_get_def(user->config, "followed_hashtags", xs_stock(XSTYPE_LIST)), "\n"); xs_html_add(top_controls, -- cgit v1.2.3 From bf9d8cb202b625b277b775ee5dd0d6a4de336040 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 09:25:57 +0100 Subject: More variable renaming. --- html.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/html.c b/html.c index 78a7d32..09a078b 100644 --- a/html.c +++ b/html.c @@ -1502,7 +1502,7 @@ static xs_html *html_button(char *clss, char *label, char *hint) } -xs_str *build_mentions(snac *snac, const xs_dict *msg) +xs_str *build_mentions(snac *user, const xs_dict *msg) /* returns a string with the mentions in msg */ { xs_str *s = xs_str_new(NULL); @@ -1516,7 +1516,7 @@ xs_str *build_mentions(snac *snac, const xs_dict *msg) const char *name = xs_dict_get(v, "name"); if (type && strcmp(type, "Mention") == 0 && - href && strcmp(href, snac->actor) != 0 && name) { + href && strcmp(href, user->actor) != 0 && name) { xs *s1 = NULL; if (name[0] != '@') { -- cgit v1.2.3 From 866050306a94f5484bc1bfb3dc20d8761f9bb161 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 09:29:37 +0100 Subject: More variable renaming. --- html.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/html.c b/html.c index 09a078b..f860dc1 100644 --- a/html.c +++ b/html.c @@ -1557,7 +1557,7 @@ xs_str *build_mentions(snac *user, const xs_dict *msg) } -xs_html *html_entry_controls(snac *snac, const char *actor, +xs_html *html_entry_controls(snac *user, const char *actor, const xs_dict *msg, const char *md5) { const char *id = xs_dict_get(msg, "id"); @@ -1566,7 +1566,7 @@ xs_html *html_entry_controls(snac *snac, const char *actor, xs *likes = object_likes(id); xs *boosts = object_announces(id); - xs *action = xs_fmt("%s/admin/action", snac->actor); + xs *action = xs_fmt("%s/admin/action", user->actor); xs *redir = xs_fmt("%s_entry", md5); xs_html *form; @@ -1593,8 +1593,8 @@ xs_html *html_entry_controls(snac *snac, const char *actor, xs_html_attr("name", "redir"), xs_html_attr("value", redir)))); - if (!xs_startswith(id, snac->actor)) { - if (xs_list_in(likes, snac->md5) == -1) { + if (!xs_startswith(id, user->actor)) { + if (xs_list_in(likes, user->md5) == -1) { /* not already liked; add button */ xs_html_add(form, html_button("like", L("Like"), L("Say you like this post"))); @@ -1606,7 +1606,7 @@ xs_html *html_entry_controls(snac *snac, const char *actor, } } else { - if (is_pinned(snac, id)) + if (is_pinned(user, id)) xs_html_add(form, html_button("unpin", L("Unpin"), L("Unpin this post from your timeline"))); else @@ -1615,7 +1615,7 @@ xs_html *html_entry_controls(snac *snac, const char *actor, } if (is_msg_public(msg)) { - if (xs_list_in(boosts, snac->md5) == -1) { + if (xs_list_in(boosts, user->md5) == -1) { /* not already boosted; add button */ xs_html_add(form, html_button("boost", L("Boost"), L("Announce this post to your followers"))); @@ -1627,16 +1627,16 @@ xs_html *html_entry_controls(snac *snac, const char *actor, } } - if (is_bookmarked(snac, id)) + if (is_bookmarked(user, id)) xs_html_add(form, html_button("unbookmark", L("Unbookmark"), L("Delete this post from your bookmarks"))); else xs_html_add(form, html_button("bookmark", L("Bookmark"), L("Add this post to your bookmarks"))); - if (strcmp(actor, snac->actor) != 0) { + if (strcmp(actor, user->actor) != 0) { /* controls for other actors than this one */ - if (following_check(snac, actor)) { + if (following_check(user, actor)) { xs_html_add(form, html_button("unfollow", L("Unfollow"), L("Stop following this user's activity"))); } @@ -1646,7 +1646,7 @@ xs_html *html_entry_controls(snac *snac, const char *actor, } if (!xs_is_null(group)) { - if (following_check(snac, group)) { + if (following_check(user, group)) { xs_html_add(form, html_button("unfollow", L("Unfollow Group"), L("Stop following this group or channel"))); @@ -1672,7 +1672,7 @@ xs_html *html_entry_controls(snac *snac, const char *actor, const char *prev_src = xs_dict_get(msg, "sourceContent"); - if (!xs_is_null(prev_src) && strcmp(actor, snac->actor) == 0) { /** edit **/ + if (!xs_is_null(prev_src) && strcmp(actor, user->actor) == 0) { /** edit **/ /* post can be edited */ xs *div_id = xs_fmt("%s_edit", md5); xs *form_id = xs_fmt("%s_edit_form", md5); @@ -1699,26 +1699,26 @@ xs_html *html_entry_controls(snac *snac, const char *actor, xs_html_add(controls, xs_html_tag("div", xs_html_tag("p", NULL), - html_note(snac, L("Edit..."), + html_note(user, L("Edit..."), div_id, form_id, "", prev_src, id, NULL, xs_dict_get(msg, "sensitive"), xs_dict_get(msg, "summary"), xs_stock(is_msg_public(msg) ? XSTYPE_FALSE : XSTYPE_TRUE), redir, - NULL, 0, att_files, att_alt_texts, is_draft(snac, id))), + NULL, 0, att_files, att_alt_texts, is_draft(user, id))), xs_html_tag("p", NULL)); } { /** reply **/ /* the post textarea */ - xs *ct = build_mentions(snac, msg); + xs *ct = build_mentions(user, msg); xs *div_id = xs_fmt("%s_reply", md5); xs *form_id = xs_fmt("%s_reply_form", md5); xs *redir = xs_fmt("%s_entry", md5); xs_html_add(controls, xs_html_tag("div", xs_html_tag("p", NULL), - html_note(snac, L("Reply..."), + html_note(user, L("Reply..."), div_id, form_id, "", ct, NULL, NULL, -- cgit v1.2.3 From c523216bf3fbee74897f15b4526e0ea5bef22c90 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 09:32:37 +0100 Subject: More variable renaming. --- html.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/html.c b/html.c index f860dc1..140d955 100644 --- a/html.c +++ b/html.c @@ -2896,7 +2896,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, } -xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t, const char *proxy) +xs_html *html_people_list(snac *user, xs_list *list, char *header, char *t, const char *proxy) { xs_html *snac_posts; xs_html *people = xs_html_tag("div", @@ -2921,7 +2921,7 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t, cons xs_html_attr("name", md5)), xs_html_tag("div", xs_html_attr("class", "snac-post-header"), - html_actor_icon(snac, actor, xs_dict_get(actor, "published"), + html_actor_icon(user, actor, xs_dict_get(actor, "published"), NULL, NULL, 0, 1, proxy, NULL, NULL))); /* content (user bio) */ @@ -2945,7 +2945,7 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t, cons } /* buttons */ - xs *btn_form_action = xs_fmt("%s/admin/action", snac->actor); + xs *btn_form_action = xs_fmt("%s/admin/action", user->actor); xs_html *snac_controls = xs_html_tag("div", xs_html_attr("class", "snac-controls")); @@ -2965,12 +2965,12 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t, cons xs_html_add(snac_controls, form); - if (following_check(snac, actor_id)) { + if (following_check(user, actor_id)) { xs_html_add(form, html_button("unfollow", L("Unfollow"), L("Stop following this user's activity"))); - if (is_limited(snac, actor_id)) + if (is_limited(user, actor_id)) xs_html_add(form, html_button("unlimit", L("Unlimit"), L("Allow announces (boosts) from this user"))); @@ -2984,12 +2984,12 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t, cons html_button("follow", L("Follow"), L("Start following this user's activity"))); - if (follower_check(snac, actor_id)) + if (follower_check(user, actor_id)) xs_html_add(form, html_button("delete", L("Delete"), L("Delete this user"))); } - if (pending_check(snac, actor_id)) { + if (pending_check(user, actor_id)) { xs_html_add(form, html_button("approve", L("Approve"), L("Approve this follow request"))); @@ -2998,7 +2998,7 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t, cons html_button("discard", L("Discard"), L("Discard this follow request"))); } - if (is_muted(snac, actor_id)) + if (is_muted(user, actor_id)) xs_html_add(form, html_button("unmute", L("Unmute"), L("Stop blocking activities from this user"))); @@ -3013,7 +3013,7 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t, cons xs_html_add(snac_controls, xs_html_tag("p", NULL), - html_note(snac, L("Direct Message..."), + html_note(user, L("Direct Message..."), dm_div_id, dm_form_id, "", "", NULL, actor_id, -- cgit v1.2.3 From 9a56475f4c1566925536bdf8bbd7a36c1d0c39f8 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 09:54:58 +0100 Subject: New function lang_str(). --- data.c | 25 +++++++++++++++++++++++++ snac.c | 1 + snac.h | 3 +++ 3 files changed, 29 insertions(+) diff --git a/data.c b/data.c index 9fc54a0..3aba471 100644 --- a/data.c +++ b/data.c @@ -4064,3 +4064,28 @@ void badlogin_inc(const char *user, const char *addr) pthread_mutex_unlock(&data_mutex); } } + + +/** language strings **/ + +const char *lang_str(const char *str, const snac *user) +/* returns a translated string */ +{ + if (user && xs_is_string(str) && xs_is_dict(srv_langs)) { + /* get user preference */ + const char *lang = xs_dict_get(user->config, "lang"); + + if (xs_is_string(lang)) { + const xs_dict *strs = xs_dict_get(srv_langs, lang); + + if (xs_is_dict(strs)) { + const char *n_str = xs_dict_get(strs, str); + + if (xs_is_string(n_str)) + str = n_str; + } + } + } + + return str; +} diff --git a/snac.c b/snac.c index 9f5b50e..541828e 100644 --- a/snac.c +++ b/snac.c @@ -34,6 +34,7 @@ xs_str *srv_basedir = NULL; xs_dict *srv_config = NULL; xs_str *srv_baseurl = NULL; xs_str *srv_proxy_token_seed = NULL; +xs_dict *srv_langs = NULL; int dbglevel = 0; diff --git a/snac.h b/snac.h index d2d73af..69b1b74 100644 --- a/snac.h +++ b/snac.h @@ -33,6 +33,7 @@ extern xs_str *srv_basedir; extern xs_dict *srv_config; extern xs_str *srv_baseurl; extern xs_str *srv_proxy_token_seed; +extern xs_dict *srv_langs; extern int dbglevel; @@ -444,3 +445,5 @@ xs_str *make_url(const char *href, const char *proxy, int by_token); int badlogin_check(const char *user, const char *addr); void badlogin_inc(const char *user, const char *addr); + +const char *lang_str(const char *str, const snac *user); -- cgit v1.2.3 From 02bc18eb118fcd93f5cd90a056f7b78dfe64382f Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 10:04:46 +0100 Subject: Redefined L() to use lang_str(). --- html.c | 15 +++++++++++++-- httpd.c | 2 ++ snac.h | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/html.c b/html.c index 140d955..f81cab2 100644 --- a/html.c +++ b/html.c @@ -627,6 +627,9 @@ static xs_html *html_instance_body(void) const char *email = xs_dict_get(srv_config, "admin_email"); const char *acct = xs_dict_get(srv_config, "admin_account"); + /* for L() */ + const snac *user = NULL; + xs *blurb = xs_replace(snac_blurb, "%host%", host); xs_html *dl; @@ -1486,7 +1489,7 @@ xs_html *html_top_controls(snac *user) } -static xs_html *html_button(char *clss, char *label, char *hint) +static xs_html *html_button(const char *clss, const char *label, const char *hint) { xs *c = xs_fmt("snac-btn-%s", clss); @@ -2584,6 +2587,8 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, xs_html *html_footer(void) { + const snac *user = NULL; + return xs_html_tag("div", xs_html_attr("class", "snac-footer"), xs_html_tag("a", @@ -2896,7 +2901,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, } -xs_html *html_people_list(snac *user, xs_list *list, char *header, char *t, const char *proxy) +xs_html *html_people_list(snac *user, xs_list *list, const char *header, const char *t, const char *proxy) { xs_html *snac_posts; xs_html *people = xs_html_tag("div", @@ -3327,6 +3332,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, { const char *accept = xs_dict_get(req, "accept"); int status = HTTP_STATUS_NOT_FOUND; + const snac *user = NULL; snac snac; xs *uid = NULL; const char *p_path; @@ -3393,6 +3399,8 @@ int html_get_handler(const xs_dict *req, const char *q_path, return HTTP_STATUS_NOT_FOUND; } + user = &snac; + if (xs_is_true(xs_dict_get(srv_config, "proxy_media"))) proxy = 1; @@ -4016,6 +4024,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, (void)ctype; int status = 0; + const snac *user = NULL; snac snac; const char *uid; const char *p_path; @@ -4039,6 +4048,8 @@ int html_post_handler(const xs_dict *req, const char *q_path, return HTTP_STATUS_UNAUTHORIZED; } + user = &snac; + p_vars = xs_dict_get(req, "p_vars"); if (p_path && strcmp(p_path, "admin/note") == 0) { /** **/ diff --git a/httpd.c b/httpd.c index d22bb14..22a148d 100644 --- a/httpd.c +++ b/httpd.c @@ -211,6 +211,8 @@ int server_get_handler(xs_dict *req, const char *q_path, { int status = 0; + const snac *user = NULL; + /* is it the server root? */ if (*q_path == '\0' || strcmp(q_path, "/") == 0) { const xs_dict *q_vars = xs_dict_get(req, "q_vars"); diff --git a/snac.h b/snac.h index 69b1b74..e2b6b5f 100644 --- a/snac.h +++ b/snac.h @@ -37,7 +37,7 @@ extern xs_dict *srv_langs; extern int dbglevel; -#define L(s) (s) +#define L(s) lang_str((s), user) #define POSTLIKE_OBJECT_TYPE "Note|Question|Page|Article|Video|Audio|Event" -- cgit v1.2.3 From 78bd0263ce56ce8d8544389971daa3d6cdd5c25e Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 10:08:26 +0100 Subject: html_footer() now receives an optional snac *user argument. --- html.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/html.c b/html.c index f81cab2..6a71035 100644 --- a/html.c +++ b/html.c @@ -2585,10 +2585,8 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, } -xs_html *html_footer(void) +xs_html *html_footer(const snac *user) { - const snac *user = NULL; - return xs_html_tag("div", xs_html_attr("class", "snac-footer"), xs_html_tag("a", @@ -2895,7 +2893,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, } xs_html_add(body, - html_footer()); + html_footer(user)); return xs_html_render_s(html, "\n"); } @@ -3064,7 +3062,7 @@ xs_str *html_people(snac *user) html_user_head(user, NULL, NULL), xs_html_add(html_user_body(user, 0), lists, - html_footer())); + html_footer(user))); return xs_html_render_s(html, "\n"); } @@ -3314,7 +3312,7 @@ xs_str *html_notifications(snac *user, int skip, int show) xs_set_free(&rep); xs_html_add(body, - html_footer()); + html_footer(user)); /* set the check time to now */ xs *dummy = notify_check_time(user, 1); @@ -3569,7 +3567,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, html_user_head(&snac, NULL, NULL), xs_html_add(html_user_body(&snac, 0), page, - html_footer())); + html_footer(user))); *body = xs_html_render_s(html, "\n"); *b_size = strlen(*body); -- cgit v1.2.3 From e020ca84718d99401a99af0363992b4661a1d16e Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 10:24:13 +0100 Subject: xs_po.h new file. --- Makefile | 14 +++++----- Makefile.NetBSD | 14 +++++----- data.c | 1 + snac.c | 1 + xs_po.h | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ xs_version.h | 2 +- 6 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 xs_po.h diff --git a/Makefile b/Makefile index 1fddbb2..178cfdd 100644 --- a/Makefile +++ b/Makefile @@ -44,20 +44,20 @@ activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \ xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \ snac.h http_codes.h data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \ - xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h xs_random.h snac.h \ - http_codes.h + xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h xs_random.h \ + xs_po.h snac.h http_codes.h format.o: format.c xs.h xs_regex.h xs_mime.h xs_html.h xs_json.h \ xs_time.h xs_match.h snac.h http_codes.h html.o: html.c xs.h xs_io.h xs_json.h xs_regex.h xs_set.h xs_openssl.h \ - xs_time.h xs_mime.h xs_match.h xs_html.h xs_curl.h xs_unicode.h snac.h \ - http_codes.h + xs_time.h xs_mime.h xs_match.h xs_html.h xs_curl.h xs_unicode.h xs_url.h \ + snac.h http_codes.h http.o: http.c xs.h xs_io.h xs_openssl.h xs_curl.h xs_time.h xs_json.h \ snac.h http_codes.h httpd.o: httpd.c xs.h xs_io.h xs_json.h xs_socket.h xs_unix_socket.h \ xs_httpd.h xs_mime.h xs_time.h xs_openssl.h xs_fcgi.h xs_html.h snac.h \ http_codes.h -main.o: main.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h snac.h \ - http_codes.h +main.o: main.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h xs_match.h \ + snac.h http_codes.h mastoapi.o: mastoapi.c xs.h xs_hex.h xs_openssl.h xs_json.h xs_io.h \ xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \ snac.h http_codes.h @@ -65,7 +65,7 @@ sandbox.o: sandbox.c xs.h snac.h http_codes.h snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \ xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \ xs_httpd.h xs_mime.h xs_regex.h xs_set.h xs_time.h xs_glob.h xs_random.h \ - xs_match.h xs_fcgi.h xs_html.h snac.h http_codes.h + xs_match.h xs_fcgi.h xs_html.h xs_po.h snac.h http_codes.h upgrade.o: upgrade.c xs.h xs_io.h xs_json.h xs_glob.h snac.h http_codes.h utils.o: utils.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h \ xs_random.h xs_glob.h xs_curl.h xs_regex.h snac.h http_codes.h diff --git a/Makefile.NetBSD b/Makefile.NetBSD index 93222b2..51c8181 100644 --- a/Makefile.NetBSD +++ b/Makefile.NetBSD @@ -39,20 +39,20 @@ activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \ xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \ snac.h http_codes.h data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \ - xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h xs_random.h snac.h \ - http_codes.h + xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h xs_random.h \ + xs_po.h snac.h http_codes.h format.o: format.c xs.h xs_regex.h xs_mime.h xs_html.h xs_json.h \ xs_time.h xs_match.h snac.h http_codes.h html.o: html.c xs.h xs_io.h xs_json.h xs_regex.h xs_set.h xs_openssl.h \ - xs_time.h xs_mime.h xs_match.h xs_html.h xs_curl.h xs_unicode.h snac.h \ - http_codes.h + xs_time.h xs_mime.h xs_match.h xs_html.h xs_curl.h xs_unicode.h xs_url.h \ + snac.h http_codes.h http.o: http.c xs.h xs_io.h xs_openssl.h xs_curl.h xs_time.h xs_json.h \ snac.h http_codes.h httpd.o: httpd.c xs.h xs_io.h xs_json.h xs_socket.h xs_unix_socket.h \ xs_httpd.h xs_mime.h xs_time.h xs_openssl.h xs_fcgi.h xs_html.h snac.h \ http_codes.h -main.o: main.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h snac.h \ - http_codes.h +main.o: main.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h xs_match.h \ + snac.h http_codes.h mastoapi.o: mastoapi.c xs.h xs_hex.h xs_openssl.h xs_json.h xs_io.h \ xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \ snac.h http_codes.h @@ -60,7 +60,7 @@ sandbox.o: sandbox.c xs.h snac.h http_codes.h snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \ xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \ xs_httpd.h xs_mime.h xs_regex.h xs_set.h xs_time.h xs_glob.h xs_random.h \ - xs_match.h xs_fcgi.h xs_html.h snac.h http_codes.h + xs_match.h xs_fcgi.h xs_html.h xs_po.h snac.h http_codes.h upgrade.o: upgrade.c xs.h xs_io.h xs_json.h xs_glob.h snac.h http_codes.h utils.o: utils.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h \ xs_random.h xs_glob.h xs_curl.h xs_regex.h snac.h http_codes.h diff --git a/data.c b/data.c index 3aba471..f935b39 100644 --- a/data.c +++ b/data.c @@ -13,6 +13,7 @@ #include "xs_match.h" #include "xs_unicode.h" #include "xs_random.h" +#include "xs_po.h" #include "snac.h" diff --git a/snac.c b/snac.c index 541828e..d4a96e9 100644 --- a/snac.c +++ b/snac.c @@ -24,6 +24,7 @@ #include "xs_match.h" #include "xs_fcgi.h" #include "xs_html.h" +#include "xs_po.h" #include "snac.h" diff --git a/xs_po.h b/xs_po.h new file mode 100644 index 0000000..c6feec9 --- /dev/null +++ b/xs_po.h @@ -0,0 +1,86 @@ +/* copyright (c) 2025 grunfink et al. / MIT license */ + +#ifndef _XS_PO_H + +#define _XS_PO_H + +xs_dict *xs_po_to_dict(const char *fn); + +#ifdef XS_IMPLEMENTATION + +xs_dict *xs_po_to_dict(const char *fn) +/* converts a PO file to a dict */ +{ + xs_dict *d = NULL; + FILE *f; + + if ((f = fopen(fn, "r")) != NULL) { + d = xs_dict_new(); + + xs *k = NULL; + xs *v = NULL; + enum { IN_NONE, IN_K, IN_V } mode = IN_NONE; + + while (!feof(f)) { + xs *l = xs_strip_i(xs_readline(f)); + + /* discard empty lines and comments */ + if (*l == '\0' || *l == '#') + continue; + + if (xs_startswith(l, "msgid ")) { + if (mode == IN_V) { + /* flush */ + if (xs_is_string(k) && xs_is_string(v) && *v) + d = xs_dict_set(d, k, v); + + k = xs_free(k); + v = xs_free(v); + } + + l = xs_replace_i(l, "msgid ", ""); + mode = IN_K; + + k = xs_str_new(NULL); + } + else + if (xs_startswith(l, "msgstr ")) { + if (mode != IN_K) + break; + + l = xs_replace_i(l, "msgstr ", ""); + mode = IN_V; + + v = xs_str_new(NULL); + } + + l = xs_replace_i(l, "\\n", "\n"); + l = xs_strip_chars_i(l, "\""); + + switch (mode) { + case IN_K: + k = xs_str_cat(k, l); + break; + + case IN_V: + v = xs_str_cat(v, l); + break; + + case IN_NONE: + break; + } + } + + /* final flush */ + if (xs_is_string(k) && xs_is_string(v) && *v) + d = xs_dict_set(d, k, v); + + fclose(f); + } + + return d; +} + +#endif /* XS_IMPLEMENTATION */ + +#endif /* XS_PO_H */ diff --git a/xs_version.h b/xs_version.h index 7314133..f899dcb 100644 --- a/xs_version.h +++ b/xs_version.h @@ -1 +1 @@ -/* 2f43b93e9d2b63360c802e09f4c68adfef74c673 2025-01-28T07:40:50+01:00 */ +/* d467dc71e518603250a55c8a67e26cf40e1710e9 2025-02-14T10:21:15+01:00 */ -- cgit v1.2.3 From d8ae88e779d8d27868c5357424132eab48bf18a5 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 14 Feb 2025 18:19:21 +0100 Subject: Some message tweaks. --- html.c | 6 +- po/en.po | 342 +++++++++++++++++++++++++++++++-------------------------------- 2 files changed, 170 insertions(+), 178 deletions(-) diff --git a/html.c b/html.c index 6a71035..e11abd1 100644 --- a/html.c +++ b/html.c @@ -744,9 +744,11 @@ xs_html *html_user_head(snac *user, const char *desc, const char *url) xs *fwers = follower_list(user); xs *fwing = following_list(user); - xs *s1 = xs_fmt(L("%d following, %d followers · "), + xs *s1 = xs_fmt(L("%d following, %d followers"), xs_list_len(fwing), xs_list_len(fwers)); + s1 = xs_str_cat(s1, " · "); + s_desc = xs_str_prepend_i(s_desc, s1); } @@ -1078,7 +1080,7 @@ static xs_html *html_user_body(snac *user, int read_only) xs *fwers = follower_list(user); xs *fwing = following_list(user); - xs *s1 = xs_fmt(L("%d following %d followers"), + xs *s1 = xs_fmt(L("%d following, %d followers"), xs_list_len(fwing), xs_list_len(fwers)); xs_html_add(top_user, diff --git a/po/en.po b/po/en.po index cb19c67..303b7a5 100644 --- a/po/en.po +++ b/po/en.po @@ -8,686 +8,676 @@ msgstr "" "Language: en\n" "Content-Type: text/plain; charset=UTF-8\n" -#: html.c:361 +#: html.c:367 msgid "Sensitive content: " msgstr "" -#: html.c:369 +#: html.c:375 msgid "Sensitive content description" msgstr "" -#: html.c:382 +#: html.c:388 msgid "Only for mentioned people: " msgstr "" -#: html.c:405 +#: html.c:411 msgid "Reply to (URL): " msgstr "" -#: html.c:414 +#: html.c:420 msgid "Don't send, but store as a draft" msgstr "" -#: html.c:415 +#: html.c:421 msgid "Draft:" msgstr "" -#: html.c:435 +#: html.c:441 msgid "Attachments..." msgstr "" -#: html.c:458 +#: html.c:464 msgid "File:" msgstr "" -#: html.c:462 +#: html.c:468 msgid "Clear this field to delete the attachment" msgstr "" -#: html.c:471 html.c:496 +#: html.c:477 html.c:502 msgid "Attachment description" msgstr "" -#: html.c:507 +#: html.c:513 msgid "Poll..." msgstr "" -#: html.c:509 +#: html.c:515 msgid "Poll options (one per line, up to 8):" msgstr "" -#: html.c:521 +#: html.c:527 msgid "One choice" msgstr "" -#: html.c:524 +#: html.c:530 msgid "Multiple choices" msgstr "" -#: html.c:530 +#: html.c:536 msgid "End in 5 minutes" msgstr "" -#: html.c:534 +#: html.c:540 msgid "End in 1 hour" msgstr "" -#: html.c:537 +#: html.c:543 msgid "End in 1 day" msgstr "" -#: html.c:545 +#: html.c:551 msgid "Post" msgstr "" -#: html.c:639 html.c:646 +#: html.c:648 html.c:655 msgid "Site description" msgstr "" -#: html.c:657 +#: html.c:666 msgid "Admin email" msgstr "" -#: html.c:670 +#: html.c:679 msgid "Admin account" msgstr "" -#: html.c:738 +#: html.c:747 html.c:1083 #, c-format -msgid "%d following, %d followers " +msgid "%d following, %d followers" msgstr "" -#: html.c:826 +#: html.c:837 msgid "RSS" msgstr "" -#: html.c:831 html.c:859 +#: html.c:842 html.c:870 msgid "private" msgstr "" -#: html.c:855 +#: html.c:866 msgid "public" msgstr "" -#: html.c:863 +#: html.c:874 msgid "notifications" msgstr "" -#: html.c:868 +#: html.c:879 msgid "people" msgstr "" -#: html.c:872 +#: html.c:883 msgid "instance" msgstr "" -#: html.c:881 +#: html.c:892 msgid "" "Search posts by URL or content (regular expression), @user@host accounts, or " "#tag" msgstr "" -#: html.c:882 +#: html.c:893 msgid "Content search" msgstr "" -#: html.c:1004 +#: html.c:1015 msgid "verified link" msgstr "" -#: html.c:1061 html.c:2382 html.c:2395 html.c:2404 +#: html.c:1072 html.c:2393 html.c:2406 html.c:2415 msgid "Location: " msgstr "" -#: html.c:1072 -#, c-format -msgid "%d following %d followers" -msgstr "" - -#: html.c:1097 +#: html.c:1108 msgid "New Post..." msgstr "" -#: html.c:1099 +#: html.c:1110 msgid "What's on your mind?" msgstr "" -#: html.c:1108 +#: html.c:1119 msgid "Operations..." msgstr "" -#: html.c:1123 html.c:1639 html.c:2978 html.c:4276 +#: html.c:1134 html.c:1650 html.c:2989 html.c:4293 msgid "Follow" msgstr "" -#: html.c:1125 +#: html.c:1136 msgid "(by URL or user@host)" msgstr "" -#: html.c:1140 html.c:1615 html.c:4228 +#: html.c:1151 html.c:1626 html.c:4245 msgid "Boost" msgstr "" -#: html.c:1142 html.c:1159 +#: html.c:1153 html.c:1170 msgid "(by URL)" msgstr "" -#: html.c:1157 html.c:1594 html.c:4219 +#: html.c:1168 html.c:1605 html.c:4236 msgid "Like" msgstr "" -#: html.c:1240 +#: html.c:1251 msgid "User Settings..." msgstr "" -#: html.c:1249 +#: html.c:1260 msgid "Display name:" msgstr "" -#: html.c:1255 +#: html.c:1266 msgid "Your name" msgstr "" -#: html.c:1257 +#: html.c:1268 msgid "Avatar: " msgstr "" -#: html.c:1265 +#: html.c:1276 msgid "Delete current avatar" msgstr "" -#: html.c:1267 +#: html.c:1278 msgid "Header image (banner): " msgstr "" -#: html.c:1275 +#: html.c:1286 msgid "Delete current header image" msgstr "" -#: html.c:1277 +#: html.c:1288 msgid "Bio:" msgstr "" -#: html.c:1283 +#: html.c:1294 msgid "Write about yourself here..." msgstr "" -#: html.c:1292 +#: html.c:1303 msgid "Always show sensitive content" msgstr "" -#: html.c:1294 +#: html.c:1305 msgid "Email address for notifications:" msgstr "" -#: html.c:1302 +#: html.c:1313 msgid "Telegram notifications (bot key and chat id):" msgstr "" -#: html.c:1316 +#: html.c:1327 msgid "ntfy notifications (ntfy server and token):" msgstr "" -#: html.c:1330 +#: html.c:1341 msgid "Maximum days to keep posts (0: server settings):" msgstr "" -#: html.c:1344 +#: html.c:1355 msgid "Drop direct messages from people you don't follow" msgstr "" -#: html.c:1353 +#: html.c:1364 msgid "This account is a bot" msgstr "" -#: html.c:1362 +#: html.c:1373 msgid "Auto-boost all mentions to this account" msgstr "" -#: html.c:1371 +#: html.c:1382 msgid "This account is private (posts are not shown through the web)" msgstr "" -#: html.c:1381 +#: html.c:1392 msgid "Collapse top threads by default" msgstr "" -#: html.c:1390 +#: html.c:1401 msgid "Follow requests must be approved" msgstr "" -#: html.c:1399 +#: html.c:1410 msgid "Publish follower and following metrics" msgstr "" -#: html.c:1401 +#: html.c:1412 msgid "Current location:" msgstr "" -#: html.c:1415 +#: html.c:1426 msgid "Profile metadata (key=value pairs in each line):" msgstr "" -#: html.c:1426 +#: html.c:1437 msgid "New password:" msgstr "" -#: html.c:1433 +#: html.c:1444 msgid "Repeat new password:" msgstr "" -#: html.c:1443 +#: html.c:1454 msgid "Update user info" msgstr "" -#: html.c:1454 +#: html.c:1465 msgid "Followed hashtags..." msgstr "" -#: html.c:1456 +#: html.c:1467 msgid "One hashtag per line" msgstr "" -#: html.c:1477 +#: html.c:1488 msgid "Update hashtags" msgstr "" -#: html.c:1594 +#: html.c:1605 msgid "Say you like this post" msgstr "" -#: html.c:1599 html.c:4237 +#: html.c:1610 html.c:4254 msgid "Unlike" msgstr "" -#: html.c:1599 +#: html.c:1610 msgid "Nah don't like it that much" msgstr "" -#: html.c:1605 html.c:4369 +#: html.c:1616 html.c:4386 msgid "Unpin" msgstr "" -#: html.c:1605 +#: html.c:1616 msgid "Unpin this post from your timeline" msgstr "" -#: html.c:1608 html.c:4364 +#: html.c:1619 html.c:4381 msgid "Pin" msgstr "" -#: html.c:1608 +#: html.c:1619 msgid "Pin this post to the top of your timeline" msgstr "" -#: html.c:1615 +#: html.c:1626 msgid "Announce this post to your followers" msgstr "" -#: html.c:1620 html.c:4245 +#: html.c:1631 html.c:4262 msgid "Unboost" msgstr "" -#: html.c:1620 +#: html.c:1631 msgid "I regret I boosted this" msgstr "" -#: html.c:1626 html.c:4379 +#: html.c:1637 html.c:4396 msgid "Unbookmark" msgstr "" -#: html.c:1626 +#: html.c:1637 msgid "Delete this post from your bookmarks" msgstr "" -#: html.c:1629 html.c:4374 +#: html.c:1640 html.c:4391 msgid "Bookmark" msgstr "" -#: html.c:1629 +#: html.c:1640 msgid "Add this post to your bookmarks" msgstr "" -#: html.c:1635 html.c:2964 html.c:3152 html.c:4289 +#: html.c:1646 html.c:2975 html.c:3163 html.c:4306 msgid "Unfollow" msgstr "" -#: html.c:1635 html.c:2965 +#: html.c:1646 html.c:2976 msgid "Stop following this user's activity" msgstr "" -#: html.c:1639 html.c:2979 +#: html.c:1650 html.c:2990 msgid "Start following this user's activity" msgstr "" -#: html.c:1645 html.c:4319 +#: html.c:1656 html.c:4336 msgid "Unfollow Group" msgstr "" -#: html.c:1646 +#: html.c:1657 msgid "Stop following this group or channel" msgstr "" -#: html.c:1650 html.c:4306 +#: html.c:1661 html.c:4323 msgid "Follow Group" msgstr "" -#: html.c:1651 +#: html.c:1662 msgid "Start following this group or channel" msgstr "" -#: html.c:1656 html.c:3001 html.c:4253 +#: html.c:1667 html.c:3012 html.c:4270 msgid "MUTE" msgstr "" -#: html.c:1657 +#: html.c:1668 msgid "Block any activity from this user forever" msgstr "" -#: html.c:1662 html.c:2983 html.c:4336 +#: html.c:1673 html.c:2994 html.c:4353 msgid "Delete" msgstr "" -#: html.c:1662 +#: html.c:1673 msgid "Delete this post" msgstr "" -#: html.c:1665 html.c:4261 +#: html.c:1676 html.c:4278 msgid "Hide" msgstr "" -#: html.c:1665 +#: html.c:1676 msgid "Hide this post and its children" msgstr "" -#: html.c:1696 +#: html.c:1707 msgid "Edit..." msgstr "" -#: html.c:1715 +#: html.c:1726 msgid "Reply..." msgstr "" -#: html.c:1766 +#: html.c:1777 msgid "Truncated (too deep)" msgstr "" -#: html.c:1775 +#: html.c:1786 msgid "follows you" msgstr "" -#: html.c:1838 +#: html.c:1849 msgid "Pinned" msgstr "" -#: html.c:1846 +#: html.c:1857 msgid "Bookmarked" msgstr "" -#: html.c:1854 +#: html.c:1865 msgid "Poll" msgstr "" -#: html.c:1861 +#: html.c:1872 msgid "Voted" msgstr "" -#: html.c:1870 +#: html.c:1881 msgid "Event" msgstr "" -#: html.c:1902 html.c:1931 +#: html.c:1913 html.c:1942 msgid "boosted" msgstr "" -#: html.c:1947 +#: html.c:1958 msgid "in reply to" msgstr "" -#: html.c:1998 +#: html.c:2009 msgid " [SENSITIVE CONTENT]" msgstr "" -#: html.c:2175 +#: html.c:2186 msgid "Vote" msgstr "" -#: html.c:2185 +#: html.c:2196 msgid "Closed" msgstr "" -#: html.c:2210 +#: html.c:2221 msgid "Closes in" msgstr "" -#: html.c:2289 +#: html.c:2300 msgid "Video" msgstr "" -#: html.c:2304 +#: html.c:2315 msgid "Audio" msgstr "" -#: html.c:2326 +#: html.c:2337 msgid "Attachment" msgstr "" -#: html.c:2340 +#: html.c:2351 msgid "Alt..." msgstr "" -#: html.c:2353 +#: html.c:2364 msgid "Source channel or community" msgstr "" -#: html.c:2447 +#: html.c:2458 msgid "Time: " msgstr "" -#: html.c:2522 +#: html.c:2533 msgid "Older..." msgstr "" -#: html.c:2585 +#: html.c:2596 msgid "about this site" msgstr "" -#: html.c:2587 +#: html.c:2598 msgid "powered by " msgstr "" -#: html.c:2652 +#: html.c:2663 msgid "Dismiss" msgstr "" -#: html.c:2669 +#: html.c:2680 #, c-format msgid "Timeline for list '%s'" msgstr "" -#: html.c:2688 html.c:3714 +#: html.c:2699 html.c:3728 msgid "Pinned posts" msgstr "" -#: html.c:2700 html.c:3729 +#: html.c:2711 html.c:3743 msgid "Bookmarked posts" msgstr "" -#: html.c:2712 html.c:3744 +#: html.c:2723 html.c:3758 msgid "Post drafts" msgstr "" -#: html.c:2771 +#: html.c:2782 msgid "No more unseen posts" msgstr "" -#: html.c:2775 html.c:2875 +#: html.c:2786 html.c:2886 msgid "Back to top" msgstr "" -#: html.c:2828 +#: html.c:2839 msgid "History" msgstr "" -#: html.c:2880 html.c:3300 +#: html.c:2891 html.c:3311 msgid "More..." msgstr "" -#: html.c:2969 html.c:4272 +#: html.c:2980 html.c:4289 msgid "Unlimit" msgstr "" -#: html.c:2970 +#: html.c:2981 msgid "Allow announces (boosts) from this user" msgstr "" -#: html.c:2973 html.c:4268 +#: html.c:2984 html.c:4285 msgid "Limit" msgstr "" -#: html.c:2974 +#: html.c:2985 msgid "Block announces (boosts) from this user" msgstr "" -#: html.c:2983 +#: html.c:2994 msgid "Delete this user" msgstr "" -#: html.c:2988 html.c:4384 +#: html.c:2999 html.c:4401 msgid "Approve" msgstr "" -#: html.c:2989 +#: html.c:3000 msgid "Approve this follow request" msgstr "" -#: html.c:2992 html.c:4408 +#: html.c:3003 html.c:4425 msgid "Discard" msgstr "" -#: html.c:2992 +#: html.c:3003 msgid "Discard this follow request" msgstr "" -#: html.c:2997 html.c:4257 +#: html.c:3008 html.c:4274 msgid "Unmute" msgstr "" -#: html.c:2998 +#: html.c:3009 msgid "Stop blocking activities from this user" msgstr "" -#: html.c:3002 +#: html.c:3013 msgid "Block any activity from this user" msgstr "" -#: html.c:3010 +#: html.c:3021 msgid "Direct Message..." msgstr "" -#: html.c:3045 +#: html.c:3056 msgid "Pending follow confirmations" msgstr "" -#: html.c:3049 +#: html.c:3060 msgid "People you follow" msgstr "" -#: html.c:3050 +#: html.c:3061 msgid "People that follow you" msgstr "" -#: html.c:3089 +#: html.c:3100 msgid "Clear all" msgstr "" -#: html.c:3146 +#: html.c:3157 msgid "Mention" msgstr "" -#: html.c:3149 +#: html.c:3160 msgid "Finished poll" msgstr "" -#: html.c:3164 +#: html.c:3175 msgid "Follow Request" msgstr "" -#: html.c:3247 +#: html.c:3258 msgid "Context" msgstr "" -#: html.c:3258 +#: html.c:3269 msgid "New" msgstr "" -#: html.c:3273 +#: html.c:3284 msgid "Already seen" msgstr "" -#: html.c:3288 +#: html.c:3299 msgid "None" msgstr "" -#: html.c:3539 +#: html.c:3553 #, c-format msgid "Search results for account %s" msgstr "" -#: html.c:3546 +#: html.c:3560 #, c-format msgid "Account %s not found" msgstr "" -#: html.c:3577 +#: html.c:3591 #, c-format msgid "Search results for tag %s" msgstr "" -#: html.c:3577 +#: html.c:3591 #, c-format msgid "Nothing found for tag %s" msgstr "" -#: html.c:3593 +#: html.c:3607 #, c-format msgid "Search results for '%s' (may be more)" msgstr "" -#: html.c:3596 +#: html.c:3610 #, c-format msgid "Search results for '%s'" msgstr "" -#: html.c:3599 +#: html.c:3613 #, c-format msgid "No more matches for '%s'" msgstr "" -#: html.c:3601 +#: html.c:3615 #, c-format msgid "Nothing found for '%s'" msgstr "" -#: html.c:3699 +#: html.c:3713 msgid "Showing instance timeline" msgstr "" -#: html.c:3767 +#: html.c:3781 #, c-format msgid "Showing timeline for list '%s'" msgstr "" -#: httpd.c:248 +#: httpd.c:250 #, c-format msgid "Search results for tag #%s" msgstr "" -#: httpd.c:257 +#: httpd.c:259 msgid "Recent posts by users in this instance" msgstr "" - -#: html.c:738 -#, c-format -msgid "%d following, %d followers · " -msgstr "" -- cgit v1.2.3 From f0f93b84bec5373f9c6567b7b415ea77ca0bd064 Mon Sep 17 00:00:00 2001 From: default Date: Sat, 15 Feb 2025 06:00:19 +0100 Subject: Optimized lang_str(). --- data.c | 19 ++++++------------- html.c | 17 +++++++++++++++-- snac.h | 1 + 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/data.c b/data.c index f935b39..4308aa5 100644 --- a/data.c +++ b/data.c @@ -4072,21 +4072,14 @@ void badlogin_inc(const char *user, const char *addr) const char *lang_str(const char *str, const snac *user) /* returns a translated string */ { - if (user && xs_is_string(str) && xs_is_dict(srv_langs)) { - /* get user preference */ - const char *lang = xs_dict_get(user->config, "lang"); + const char *n_str = str; - if (xs_is_string(lang)) { - const xs_dict *strs = xs_dict_get(srv_langs, lang); + if (user && xs_is_dict(user->lang) && xs_is_string(str)) { + n_str = xs_dict_get(user->lang, str); - if (xs_is_dict(strs)) { - const char *n_str = xs_dict_get(strs, str); - - if (xs_is_string(n_str)) - str = n_str; - } - } + if (xs_is_null(n_str) || *n_str == '\0') + n_str = str; } - return str; + return n_str; } diff --git a/html.c b/html.c index e11abd1..5068b49 100644 --- a/html.c +++ b/html.c @@ -3326,6 +3326,17 @@ xs_str *html_notifications(snac *user, int skip, int show) } +void set_user_lang(snac *user) +/* sets the language dict according to user configuration */ +{ + user->lang = NULL; + const char *lang = xs_dict_get(user->config, "lang"); + + if (xs_is_string(lang)) + user->lang = xs_dict_get(srv_langs, lang); +} + + int html_get_handler(const xs_dict *req, const char *q_path, char **body, int *b_size, char **ctype, xs_str **etag, xs_str **last_modified) @@ -3399,7 +3410,8 @@ int html_get_handler(const xs_dict *req, const char *q_path, return HTTP_STATUS_NOT_FOUND; } - user = &snac; + user = &snac; /* for L() */ + set_user_lang(&snac); if (xs_is_true(xs_dict_get(srv_config, "proxy_media"))) proxy = 1; @@ -4048,7 +4060,8 @@ int html_post_handler(const xs_dict *req, const char *q_path, return HTTP_STATUS_UNAUTHORIZED; } - user = &snac; + user = &snac; /* for L() */ + set_user_lang(&snac); p_vars = xs_dict_get(req, "p_vars"); diff --git a/snac.h b/snac.h index e2b6b5f..ac1abcd 100644 --- a/snac.h +++ b/snac.h @@ -60,6 +60,7 @@ typedef struct { xs_dict *links; /* validated links */ xs_str *actor; /* actor url */ xs_str *md5; /* actor url md5 */ + const xs_dict *lang;/* string translation dict */ } snac; typedef struct { -- cgit v1.2.3 From 91d2beb267020fa632cace5b0b475a9febfa0439 Mon Sep 17 00:00:00 2001 From: default Date: Sat, 15 Feb 2025 06:11:47 +0100 Subject: srv_open() now loads all .po files into srv_langs. --- data.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/data.c b/data.c index 4308aa5..e0b4936 100644 --- a/data.c +++ b/data.c @@ -149,6 +149,28 @@ int srv_open(const char *basedir, int auto_upgrade) mkdirx(expdir); } + /* languages */ + srv_langs = xs_dict_new(); + + xs *l_dir = xs_fmt("%s/lang/", srv_basedir); + mkdirx(l_dir); + + l_dir = xs_str_cat(l_dir, "*.po"); + xs *pos = xs_glob(l_dir, 0, 0); + const char *po; + + xs_list_foreach(pos, po) { + xs *d = xs_po_to_dict(po); + + if (xs_is_dict(d)) { + xs *l = xs_split(po, "/"); + xs *id = xs_dup(xs_list_get(l, -1)); + id = xs_replace_i(id, ".po", ""); + + srv_langs = xs_dict_set(srv_langs, id, d); + } + } + return ret; } -- cgit v1.2.3 From 1554a207e653d626c194b7d8113a55358c0dcdf7 Mon Sep 17 00:00:00 2001 From: default Date: Sat, 15 Feb 2025 06:35:47 +0100 Subject: The interface language preference can now be set. --- data.c | 1 + html.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/data.c b/data.c index e0b4936..e9837bb 100644 --- a/data.c +++ b/data.c @@ -151,6 +151,7 @@ int srv_open(const char *basedir, int auto_upgrade) /* languages */ srv_langs = xs_dict_new(); + srv_langs = xs_dict_set(srv_langs, "en", xs_stock(XSTYPE_NULL)); xs *l_dir = xs_fmt("%s/lang/", srv_basedir); mkdirx(l_dir); diff --git a/html.c b/html.c index 5068b49..6573630 100644 --- a/html.c +++ b/html.c @@ -1243,6 +1243,28 @@ xs_html *html_top_controls(snac *user) else metadata = xs_str_new(NULL); + /* ui language */ + xs_html *lang_select = xs_html_tag("select", + xs_html_attr("name", "web_ui_lang")); + + const char *u_lang = xs_dict_get_def(user->config, "lang", "en"); + const char *lang; + const xs_dict *langs; + + xs_dict_foreach(srv_langs, lang, langs) { + if (strcmp(u_lang, lang) == 0) + xs_html_add(lang_select, + xs_html_tag("option", + xs_html_text(lang), + xs_html_attr("value", lang), + xs_html_attr("selected", "selected"))); + else + xs_html_add(lang_select, + xs_html_tag("option", + xs_html_text(lang), + xs_html_attr("value", lang))); + } + xs *user_setup_action = xs_fmt("%s/admin/user-setup", user->actor); xs_html_add(top_controls, @@ -1433,6 +1455,11 @@ xs_html *html_top_controls(snac *user) "/example.com/my-blog\nGPG Key=1FA54\n..."), xs_html_text(metadata))), + xs_html_tag("p", + xs_html_text(L("Web interface language:")), + xs_html_sctag("br", NULL), + lang_select), + xs_html_tag("p", xs_html_text(L("New password:")), xs_html_sctag("br", NULL), @@ -4505,6 +4532,8 @@ int html_post_handler(const xs_dict *req, const char *q_path, snac.config = xs_dict_set(snac.config, "show_contact_metrics", xs_stock(XSTYPE_TRUE)); else snac.config = xs_dict_set(snac.config, "show_contact_metrics", xs_stock(XSTYPE_FALSE)); + if ((v = xs_dict_get(p_vars, "web_ui_lang")) != NULL) + snac.config = xs_dict_set(snac.config, "lang", v); snac.config = xs_dict_set(snac.config, "latitude", xs_dict_get_def(p_vars, "latitude", "")); snac.config = xs_dict_set(snac.config, "longitude", xs_dict_get_def(p_vars, "longitude", "")); -- cgit v1.2.3 From ef80717a1c8963135bafcc35dddc069305e5e182 Mon Sep 17 00:00:00 2001 From: default Date: Sat, 15 Feb 2025 06:40:53 +0100 Subject: Updated po. --- po/en.po | 258 ++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 131 insertions(+), 127 deletions(-) diff --git a/po/en.po b/po/en.po index 303b7a5..ca5e816 100644 --- a/po/en.po +++ b/po/en.po @@ -135,7 +135,7 @@ msgstr "" msgid "verified link" msgstr "" -#: html.c:1072 html.c:2393 html.c:2406 html.c:2415 +#: html.c:1072 html.c:2420 html.c:2433 html.c:2442 msgid "Location: " msgstr "" @@ -151,7 +151,7 @@ msgstr "" msgid "Operations..." msgstr "" -#: html.c:1134 html.c:1650 html.c:2989 html.c:4293 +#: html.c:1134 html.c:1677 html.c:3016 html.c:4333 msgid "Follow" msgstr "" @@ -159,7 +159,7 @@ msgstr "" msgid "(by URL or user@host)" msgstr "" -#: html.c:1151 html.c:1626 html.c:4245 +#: html.c:1151 html.c:1653 html.c:4285 msgid "Boost" msgstr "" @@ -167,508 +167,512 @@ msgstr "" msgid "(by URL)" msgstr "" -#: html.c:1168 html.c:1605 html.c:4236 +#: html.c:1168 html.c:1632 html.c:4276 msgid "Like" msgstr "" -#: html.c:1251 +#: html.c:1273 msgid "User Settings..." msgstr "" -#: html.c:1260 +#: html.c:1282 msgid "Display name:" msgstr "" -#: html.c:1266 +#: html.c:1288 msgid "Your name" msgstr "" -#: html.c:1268 +#: html.c:1290 msgid "Avatar: " msgstr "" -#: html.c:1276 +#: html.c:1298 msgid "Delete current avatar" msgstr "" -#: html.c:1278 +#: html.c:1300 msgid "Header image (banner): " msgstr "" -#: html.c:1286 +#: html.c:1308 msgid "Delete current header image" msgstr "" -#: html.c:1288 +#: html.c:1310 msgid "Bio:" msgstr "" -#: html.c:1294 +#: html.c:1316 msgid "Write about yourself here..." msgstr "" -#: html.c:1303 +#: html.c:1325 msgid "Always show sensitive content" msgstr "" -#: html.c:1305 +#: html.c:1327 msgid "Email address for notifications:" msgstr "" -#: html.c:1313 +#: html.c:1335 msgid "Telegram notifications (bot key and chat id):" msgstr "" -#: html.c:1327 +#: html.c:1349 msgid "ntfy notifications (ntfy server and token):" msgstr "" -#: html.c:1341 +#: html.c:1363 msgid "Maximum days to keep posts (0: server settings):" msgstr "" -#: html.c:1355 +#: html.c:1377 msgid "Drop direct messages from people you don't follow" msgstr "" -#: html.c:1364 +#: html.c:1386 msgid "This account is a bot" msgstr "" -#: html.c:1373 +#: html.c:1395 msgid "Auto-boost all mentions to this account" msgstr "" -#: html.c:1382 +#: html.c:1404 msgid "This account is private (posts are not shown through the web)" msgstr "" -#: html.c:1392 +#: html.c:1414 msgid "Collapse top threads by default" msgstr "" -#: html.c:1401 +#: html.c:1423 msgid "Follow requests must be approved" msgstr "" -#: html.c:1410 +#: html.c:1432 msgid "Publish follower and following metrics" msgstr "" -#: html.c:1412 +#: html.c:1434 msgid "Current location:" msgstr "" -#: html.c:1426 +#: html.c:1448 msgid "Profile metadata (key=value pairs in each line):" msgstr "" -#: html.c:1437 +#: html.c:1459 +msgid "Web interface language:" +msgstr "" + +#: html.c:1464 msgid "New password:" msgstr "" -#: html.c:1444 +#: html.c:1471 msgid "Repeat new password:" msgstr "" -#: html.c:1454 +#: html.c:1481 msgid "Update user info" msgstr "" -#: html.c:1465 +#: html.c:1492 msgid "Followed hashtags..." msgstr "" -#: html.c:1467 +#: html.c:1494 msgid "One hashtag per line" msgstr "" -#: html.c:1488 +#: html.c:1515 msgid "Update hashtags" msgstr "" -#: html.c:1605 +#: html.c:1632 msgid "Say you like this post" msgstr "" -#: html.c:1610 html.c:4254 +#: html.c:1637 html.c:4294 msgid "Unlike" msgstr "" -#: html.c:1610 +#: html.c:1637 msgid "Nah don't like it that much" msgstr "" -#: html.c:1616 html.c:4386 +#: html.c:1643 html.c:4426 msgid "Unpin" msgstr "" -#: html.c:1616 +#: html.c:1643 msgid "Unpin this post from your timeline" msgstr "" -#: html.c:1619 html.c:4381 +#: html.c:1646 html.c:4421 msgid "Pin" msgstr "" -#: html.c:1619 +#: html.c:1646 msgid "Pin this post to the top of your timeline" msgstr "" -#: html.c:1626 +#: html.c:1653 msgid "Announce this post to your followers" msgstr "" -#: html.c:1631 html.c:4262 +#: html.c:1658 html.c:4302 msgid "Unboost" msgstr "" -#: html.c:1631 +#: html.c:1658 msgid "I regret I boosted this" msgstr "" -#: html.c:1637 html.c:4396 +#: html.c:1664 html.c:4436 msgid "Unbookmark" msgstr "" -#: html.c:1637 +#: html.c:1664 msgid "Delete this post from your bookmarks" msgstr "" -#: html.c:1640 html.c:4391 +#: html.c:1667 html.c:4431 msgid "Bookmark" msgstr "" -#: html.c:1640 +#: html.c:1667 msgid "Add this post to your bookmarks" msgstr "" -#: html.c:1646 html.c:2975 html.c:3163 html.c:4306 +#: html.c:1673 html.c:3002 html.c:3190 html.c:4346 msgid "Unfollow" msgstr "" -#: html.c:1646 html.c:2976 +#: html.c:1673 html.c:3003 msgid "Stop following this user's activity" msgstr "" -#: html.c:1650 html.c:2990 +#: html.c:1677 html.c:3017 msgid "Start following this user's activity" msgstr "" -#: html.c:1656 html.c:4336 +#: html.c:1683 html.c:4376 msgid "Unfollow Group" msgstr "" -#: html.c:1657 +#: html.c:1684 msgid "Stop following this group or channel" msgstr "" -#: html.c:1661 html.c:4323 +#: html.c:1688 html.c:4363 msgid "Follow Group" msgstr "" -#: html.c:1662 +#: html.c:1689 msgid "Start following this group or channel" msgstr "" -#: html.c:1667 html.c:3012 html.c:4270 +#: html.c:1694 html.c:3039 html.c:4310 msgid "MUTE" msgstr "" -#: html.c:1668 +#: html.c:1695 msgid "Block any activity from this user forever" msgstr "" -#: html.c:1673 html.c:2994 html.c:4353 +#: html.c:1700 html.c:3021 html.c:4393 msgid "Delete" msgstr "" -#: html.c:1673 +#: html.c:1700 msgid "Delete this post" msgstr "" -#: html.c:1676 html.c:4278 +#: html.c:1703 html.c:4318 msgid "Hide" msgstr "" -#: html.c:1676 +#: html.c:1703 msgid "Hide this post and its children" msgstr "" -#: html.c:1707 +#: html.c:1734 msgid "Edit..." msgstr "" -#: html.c:1726 +#: html.c:1753 msgid "Reply..." msgstr "" -#: html.c:1777 +#: html.c:1804 msgid "Truncated (too deep)" msgstr "" -#: html.c:1786 +#: html.c:1813 msgid "follows you" msgstr "" -#: html.c:1849 +#: html.c:1876 msgid "Pinned" msgstr "" -#: html.c:1857 +#: html.c:1884 msgid "Bookmarked" msgstr "" -#: html.c:1865 +#: html.c:1892 msgid "Poll" msgstr "" -#: html.c:1872 +#: html.c:1899 msgid "Voted" msgstr "" -#: html.c:1881 +#: html.c:1908 msgid "Event" msgstr "" -#: html.c:1913 html.c:1942 +#: html.c:1940 html.c:1969 msgid "boosted" msgstr "" -#: html.c:1958 +#: html.c:1985 msgid "in reply to" msgstr "" -#: html.c:2009 +#: html.c:2036 msgid " [SENSITIVE CONTENT]" msgstr "" -#: html.c:2186 +#: html.c:2213 msgid "Vote" msgstr "" -#: html.c:2196 +#: html.c:2223 msgid "Closed" msgstr "" -#: html.c:2221 +#: html.c:2248 msgid "Closes in" msgstr "" -#: html.c:2300 +#: html.c:2327 msgid "Video" msgstr "" -#: html.c:2315 +#: html.c:2342 msgid "Audio" msgstr "" -#: html.c:2337 +#: html.c:2364 msgid "Attachment" msgstr "" -#: html.c:2351 +#: html.c:2378 msgid "Alt..." msgstr "" -#: html.c:2364 +#: html.c:2391 msgid "Source channel or community" msgstr "" -#: html.c:2458 +#: html.c:2485 msgid "Time: " msgstr "" -#: html.c:2533 +#: html.c:2560 msgid "Older..." msgstr "" -#: html.c:2596 +#: html.c:2623 msgid "about this site" msgstr "" -#: html.c:2598 +#: html.c:2625 msgid "powered by " msgstr "" -#: html.c:2663 +#: html.c:2690 msgid "Dismiss" msgstr "" -#: html.c:2680 +#: html.c:2707 #, c-format msgid "Timeline for list '%s'" msgstr "" -#: html.c:2699 html.c:3728 +#: html.c:2726 html.c:3767 msgid "Pinned posts" msgstr "" -#: html.c:2711 html.c:3743 +#: html.c:2738 html.c:3782 msgid "Bookmarked posts" msgstr "" -#: html.c:2723 html.c:3758 +#: html.c:2750 html.c:3797 msgid "Post drafts" msgstr "" -#: html.c:2782 +#: html.c:2809 msgid "No more unseen posts" msgstr "" -#: html.c:2786 html.c:2886 +#: html.c:2813 html.c:2913 msgid "Back to top" msgstr "" -#: html.c:2839 +#: html.c:2866 msgid "History" msgstr "" -#: html.c:2891 html.c:3311 +#: html.c:2918 html.c:3338 msgid "More..." msgstr "" -#: html.c:2980 html.c:4289 +#: html.c:3007 html.c:4329 msgid "Unlimit" msgstr "" -#: html.c:2981 +#: html.c:3008 msgid "Allow announces (boosts) from this user" msgstr "" -#: html.c:2984 html.c:4285 +#: html.c:3011 html.c:4325 msgid "Limit" msgstr "" -#: html.c:2985 +#: html.c:3012 msgid "Block announces (boosts) from this user" msgstr "" -#: html.c:2994 +#: html.c:3021 msgid "Delete this user" msgstr "" -#: html.c:2999 html.c:4401 +#: html.c:3026 html.c:4441 msgid "Approve" msgstr "" -#: html.c:3000 +#: html.c:3027 msgid "Approve this follow request" msgstr "" -#: html.c:3003 html.c:4425 +#: html.c:3030 html.c:4465 msgid "Discard" msgstr "" -#: html.c:3003 +#: html.c:3030 msgid "Discard this follow request" msgstr "" -#: html.c:3008 html.c:4274 +#: html.c:3035 html.c:4314 msgid "Unmute" msgstr "" -#: html.c:3009 +#: html.c:3036 msgid "Stop blocking activities from this user" msgstr "" -#: html.c:3013 +#: html.c:3040 msgid "Block any activity from this user" msgstr "" -#: html.c:3021 +#: html.c:3048 msgid "Direct Message..." msgstr "" -#: html.c:3056 +#: html.c:3083 msgid "Pending follow confirmations" msgstr "" -#: html.c:3060 +#: html.c:3087 msgid "People you follow" msgstr "" -#: html.c:3061 +#: html.c:3088 msgid "People that follow you" msgstr "" -#: html.c:3100 +#: html.c:3127 msgid "Clear all" msgstr "" -#: html.c:3157 +#: html.c:3184 msgid "Mention" msgstr "" -#: html.c:3160 +#: html.c:3187 msgid "Finished poll" msgstr "" -#: html.c:3175 +#: html.c:3202 msgid "Follow Request" msgstr "" -#: html.c:3258 +#: html.c:3285 msgid "Context" msgstr "" -#: html.c:3269 +#: html.c:3296 msgid "New" msgstr "" -#: html.c:3284 +#: html.c:3311 msgid "Already seen" msgstr "" -#: html.c:3299 +#: html.c:3326 msgid "None" msgstr "" -#: html.c:3553 +#: html.c:3592 #, c-format msgid "Search results for account %s" msgstr "" -#: html.c:3560 +#: html.c:3599 #, c-format msgid "Account %s not found" msgstr "" -#: html.c:3591 +#: html.c:3630 #, c-format msgid "Search results for tag %s" msgstr "" -#: html.c:3591 +#: html.c:3630 #, c-format msgid "Nothing found for tag %s" msgstr "" -#: html.c:3607 +#: html.c:3646 #, c-format msgid "Search results for '%s' (may be more)" msgstr "" -#: html.c:3610 +#: html.c:3649 #, c-format msgid "Search results for '%s'" msgstr "" -#: html.c:3613 +#: html.c:3652 #, c-format msgid "No more matches for '%s'" msgstr "" -#: html.c:3615 +#: html.c:3654 #, c-format msgid "Nothing found for '%s'" msgstr "" -#: html.c:3713 +#: html.c:3752 msgid "Showing instance timeline" msgstr "" -#: html.c:3781 +#: html.c:3820 #, c-format msgid "Showing timeline for list '%s'" msgstr "" -- cgit v1.2.3 From c12a7e38adbce6058ee7d9d4113cce2649c87977 Mon Sep 17 00:00:00 2001 From: default Date: Mon, 17 Feb 2025 07:49:11 +0100 Subject: Return ASAP if srv_open() fails. --- data.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/data.c b/data.c index e9837bb..ce040dd 100644 --- a/data.c +++ b/data.c @@ -99,6 +99,9 @@ int srv_open(const char *basedir, int auto_upgrade) if (error != NULL) srv_log(error); + if (!ret) + return ret; + /* create the queue/ subdir, just in case */ xs *qdir = xs_fmt("%s/queue", srv_basedir); mkdirx(qdir); -- cgit v1.2.3 From 3844bbf04f9b417ee9fc97f6f43db259a063a1da Mon Sep 17 00:00:00 2001 From: default Date: Mon, 17 Feb 2025 07:53:06 +0100 Subject: Add fake HTTP status error 399 to http_status_text(). --- snac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/snac.c b/snac.c index d4a96e9..4e5aaba 100644 --- a/snac.c +++ b/snac.c @@ -181,6 +181,7 @@ const char *http_status_text(int status) /* translate status codes to canonical status texts */ { switch (status) { + case 399: return "Timeout"; #define HTTP_STATUS(code, name, text) case HTTP_STATUS_ ## name: return #text; #include "http_codes.h" #undef HTTP_STATUS -- cgit v1.2.3 From 349d6603e4cd4a8baff1db718afa83413b0dae5f Mon Sep 17 00:00:00 2001 From: default Date: Mon, 17 Feb 2025 08:13:39 +0100 Subject: Show the POST status also as string. --- activitypub.c | 14 +++++++++++--- xs_curl.h | 11 +++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/activitypub.c b/activitypub.c index bcb733a..104110d 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2724,6 +2724,12 @@ int process_user_queue(snac *snac) } +xs_str *str_status(int status) +{ + return xs_fmt("%d %s", status, status < 0 ? xs_curl_strerr(status) : http_status_text(status)); +} + + void process_queue_item(xs_dict *q_item) /* processes an item from the global queue */ { @@ -2780,7 +2786,9 @@ void process_queue_item(xs_dict *q_item) else payload = xs_str_new(NULL); - srv_log(xs_fmt("output message: sent to inbox %s %d%s", inbox, status, payload)); + xs *s_status = str_status(status); + + srv_log(xs_fmt("output message: sent to inbox %s (%s)%s", inbox, s_status, payload)); if (!valid_status(status)) { retries++; @@ -2798,10 +2806,10 @@ void process_queue_item(xs_dict *q_item) || status == HTTP_STATUS_UNPROCESSABLE_CONTENT || status < 0) /* explicit error: discard */ - srv_log(xs_fmt("output message: error %s %d", inbox, status)); + srv_log(xs_fmt("output message: error %s (%s)", inbox, s_status)); else if (retries > queue_retry_max) - srv_log(xs_fmt("output message: giving up %s %d", inbox, status)); + srv_log(xs_fmt("output message: giving up %s (%s)", inbox, s_status)); else { /* requeue */ enqueue_output_raw(keyid, seckey, msg, inbox, retries, status); diff --git a/xs_curl.h b/xs_curl.h index f0cfd98..657644a 100644 --- a/xs_curl.h +++ b/xs_curl.h @@ -9,6 +9,8 @@ xs_dict *xs_http_request(const char *method, const char *url, const xs_str *body, int b_size, int *status, xs_str **payload, int *p_size, int timeout); +const char *xs_curl_strerr(int errnum); + #ifdef XS_IMPLEMENTATION #include @@ -194,6 +196,15 @@ xs_dict *xs_http_request(const char *method, const char *url, return response; } + +const char *xs_curl_strerr(int errnum) +{ + CURLcode cc = errnum < 0 ? -errnum : errnum; + + return curl_easy_strerror(cc); +} + + #endif /* XS_IMPLEMENTATION */ #endif /* _XS_CURL_H */ -- cgit v1.2.3 From 0af0c28633f5c1788965861928edb8acd9f62ed2 Mon Sep 17 00:00:00 2001 From: Menelmacar Date: Mon, 17 Feb 2025 08:33:12 +0000 Subject: doc/snac8: elaborate regex blocking It seems regex blocking only works with lower case letters, since the case will be ignored anyway this is fine. This updates the documentation to express this. --- doc/snac.8 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/snac.8 b/doc/snac.8 index 7a7352c..f1e5590 100644 --- a/doc/snac.8 +++ b/doc/snac.8 @@ -329,8 +329,9 @@ These weapons of mass destruction can be written into the file in the server base directory, one per line; if this file exists, all posts' content will be matched (after being stripped of HTML tags) against these regexes, one by one, and any match will make the post to -be rejected. If you don't know about regular expressions, don't use this -option (or learn about them in some tutorial, there are gazillions of +be rejected. Use lower case, the regex will be case insensitive by default. +If you don't know about regular expressions, don't use this +option (or learn about them inw some tutorial, there are gazillions of them out there), as you and your users may start missing posts. Also, given that every regular expression implementation supports a different set of features, consider reading the documentation about the one -- cgit v1.2.3