diff options
| author | 2025-03-08 22:29:50 +0100 | |
|---|---|---|
| committer | 2025-03-08 22:29:50 +0100 | |
| commit | 398b733b2c0ff4c96f4de9731a864373842e86d6 (patch) | |
| tree | e2a381ee39d7139cf13c953c5ddad8e59bf8163f /html.c | |
| parent | Merge branch 'master' into curl-smtp (diff) | |
| parent | Updated RELEASE_NOTES. (diff) | |
| download | snac2-398b733b2c0ff4c96f4de9731a864373842e86d6.tar.gz snac2-398b733b2c0ff4c96f4de9731a864373842e86d6.tar.xz snac2-398b733b2c0ff4c96f4de9731a864373842e86d6.zip | |
Merge remote-tracking branch 'upstream/master' into curl-smtp
Diffstat (limited to 'html.c')
| -rw-r--r-- | html.c | 111 |
1 files changed, 89 insertions, 22 deletions
| @@ -83,16 +83,20 @@ xs_str *replace_shortnames(xs_str *s, const xs_list *tag, int ems, const char *p | |||
| 83 | const char *u = xs_dict_get(i, "url"); | 83 | const char *u = xs_dict_get(i, "url"); |
| 84 | const char *mt = xs_dict_get(i, "mediaType"); | 84 | const char *mt = xs_dict_get(i, "mediaType"); |
| 85 | 85 | ||
| 86 | if (xs_is_string(u) && xs_is_string(mt) && strcmp(mt, "image/svg+xml")) { | 86 | if (xs_is_string(u) && xs_is_string(mt)) { |
| 87 | xs *url = make_url(u, proxy, 0); | 87 | if (strcmp(mt, "image/svg+xml") == 0 && !xs_is_true(xs_dict_get(srv_config, "enable_svg"))) |
| 88 | s = xs_replace_i(s, n, ""); | ||
| 89 | else { | ||
| 90 | xs *url = make_url(u, proxy, 0); | ||
| 88 | 91 | ||
| 89 | xs_html *img = xs_html_sctag("img", | 92 | xs_html *img = xs_html_sctag("img", |
| 90 | xs_html_attr("loading", "lazy"), | 93 | xs_html_attr("loading", "lazy"), |
| 91 | xs_html_attr("src", url), | 94 | xs_html_attr("src", url), |
| 92 | xs_html_attr("style", style)); | 95 | xs_html_attr("style", style)); |
| 93 | 96 | ||
| 94 | xs *s1 = xs_html_render(img); | 97 | xs *s1 = xs_html_render(img); |
| 95 | s = xs_replace_i(s, n, s1); | 98 | s = xs_replace_i(s, n, s1); |
| 99 | } | ||
| 96 | } | 100 | } |
| 97 | else | 101 | else |
| 98 | s = xs_replace_i(s, n, ""); | 102 | s = xs_replace_i(s, n, ""); |
| @@ -412,7 +416,7 @@ xs_html *html_note(snac *user, const char *summary, | |||
| 412 | xs_html_sctag("input", | 416 | xs_html_sctag("input", |
| 413 | xs_html_attr("type", "url"), | 417 | xs_html_attr("type", "url"), |
| 414 | xs_html_attr("name", "in_reply_to"), | 418 | xs_html_attr("name", "in_reply_to"), |
| 415 | xs_html_attr("placeholder", "Optional URL to reply to"))); | 419 | xs_html_attr("placeholder", L("Optional URL to reply to")))); |
| 416 | 420 | ||
| 417 | xs_html_add(form, | 421 | xs_html_add(form, |
| 418 | xs_html_tag("p", NULL), | 422 | xs_html_tag("p", NULL), |
| @@ -519,7 +523,7 @@ xs_html *html_note(snac *user, const char *summary, | |||
| 519 | xs_html_attr("name", "poll_options"), | 523 | xs_html_attr("name", "poll_options"), |
| 520 | xs_html_attr("rows", "4"), | 524 | xs_html_attr("rows", "4"), |
| 521 | xs_html_attr("wrap", "virtual"), | 525 | xs_html_attr("wrap", "virtual"), |
| 522 | xs_html_attr("placeholder", "Option 1...\nOption 2...\nOption 3...\n..."))), | 526 | xs_html_attr("placeholder", L("Option 1...\nOption 2...\nOption 3...\n...")))), |
| 523 | xs_html_tag("select", | 527 | xs_html_tag("select", |
| 524 | xs_html_attr("name", "poll_multiple"), | 528 | xs_html_attr("name", "poll_multiple"), |
| 525 | xs_html_tag("option", | 529 | xs_html_tag("option", |
| @@ -1338,13 +1342,13 @@ xs_html *html_top_controls(snac *user) | |||
| 1338 | xs_html_attr("type", "text"), | 1342 | xs_html_attr("type", "text"), |
| 1339 | xs_html_attr("name", "telegram_bot"), | 1343 | xs_html_attr("name", "telegram_bot"), |
| 1340 | xs_html_attr("value", telegram_bot), | 1344 | xs_html_attr("value", telegram_bot), |
| 1341 | xs_html_attr("placeholder", "Bot API key")), | 1345 | xs_html_attr("placeholder", L("Bot API key"))), |
| 1342 | xs_html_text(" "), | 1346 | xs_html_text(" "), |
| 1343 | xs_html_sctag("input", | 1347 | xs_html_sctag("input", |
| 1344 | xs_html_attr("type", "text"), | 1348 | xs_html_attr("type", "text"), |
| 1345 | xs_html_attr("name", "telegram_chat_id"), | 1349 | xs_html_attr("name", "telegram_chat_id"), |
| 1346 | xs_html_attr("value", telegram_chat_id), | 1350 | xs_html_attr("value", telegram_chat_id), |
| 1347 | xs_html_attr("placeholder", "Chat id"))), | 1351 | xs_html_attr("placeholder", L("Chat id")))), |
| 1348 | xs_html_tag("p", | 1352 | xs_html_tag("p", |
| 1349 | xs_html_text(L("ntfy notifications (ntfy server and token):")), | 1353 | xs_html_text(L("ntfy notifications (ntfy server and token):")), |
| 1350 | xs_html_sctag("br", NULL), | 1354 | xs_html_sctag("br", NULL), |
| @@ -1352,13 +1356,13 @@ xs_html *html_top_controls(snac *user) | |||
| 1352 | xs_html_attr("type", "text"), | 1356 | xs_html_attr("type", "text"), |
| 1353 | xs_html_attr("name", "ntfy_server"), | 1357 | xs_html_attr("name", "ntfy_server"), |
| 1354 | xs_html_attr("value", ntfy_server), | 1358 | xs_html_attr("value", ntfy_server), |
| 1355 | xs_html_attr("placeholder", "ntfy server - full URL (example: https://ntfy.sh/YourTopic)")), | 1359 | xs_html_attr("placeholder", L("ntfy server - full URL (example: https://ntfy.sh/YourTopic)"))), |
| 1356 | xs_html_text(" "), | 1360 | xs_html_text(" "), |
| 1357 | xs_html_sctag("input", | 1361 | xs_html_sctag("input", |
| 1358 | xs_html_attr("type", "text"), | 1362 | xs_html_attr("type", "text"), |
| 1359 | xs_html_attr("name", "ntfy_token"), | 1363 | xs_html_attr("name", "ntfy_token"), |
| 1360 | xs_html_attr("value", ntfy_token), | 1364 | xs_html_attr("value", ntfy_token), |
| 1361 | xs_html_attr("placeholder", "ntfy token - if needed"))), | 1365 | xs_html_attr("placeholder", L("ntfy token - if needed")))), |
| 1362 | xs_html_tag("p", | 1366 | xs_html_tag("p", |
| 1363 | xs_html_text(L("Maximum days to keep posts (0: server settings):")), | 1367 | xs_html_text(L("Maximum days to keep posts (0: server settings):")), |
| 1364 | xs_html_sctag("br", NULL), | 1368 | xs_html_sctag("br", NULL), |
| @@ -1514,6 +1518,38 @@ xs_html *html_top_controls(snac *user) | |||
| 1514 | xs_html_attr("class", "button"), | 1518 | xs_html_attr("class", "button"), |
| 1515 | xs_html_attr("value", L("Update hashtags"))))))); | 1519 | xs_html_attr("value", L("Update hashtags"))))))); |
| 1516 | 1520 | ||
| 1521 | xs *blocked_hashtags_action = xs_fmt("%s/admin/blocked-hashtags", user->actor); | ||
| 1522 | xs *blocked_hashtags = xs_join(xs_dict_get_def(user->config, | ||
| 1523 | "blocked_hashtags", xs_stock(XSTYPE_LIST)), "\n"); | ||
| 1524 | |||
| 1525 | xs_html_add(top_controls, | ||
| 1526 | xs_html_tag("details", | ||
| 1527 | xs_html_tag("summary", | ||
| 1528 | xs_html_text(L("Blocked hashtags..."))), | ||
| 1529 | xs_html_tag("p", | ||
| 1530 | xs_html_text(L("One hashtag per line"))), | ||
| 1531 | xs_html_tag("div", | ||
| 1532 | xs_html_attr("class", "snac-blocked-hashtags"), | ||
| 1533 | xs_html_tag("form", | ||
| 1534 | xs_html_attr("autocomplete", "off"), | ||
| 1535 | xs_html_attr("method", "post"), | ||
| 1536 | xs_html_attr("action", blocked_hashtags_action), | ||
| 1537 | xs_html_attr("enctype", "multipart/form-data"), | ||
| 1538 | |||
| 1539 | xs_html_tag("textarea", | ||
| 1540 | xs_html_attr("name", "blocked_hashtags"), | ||
| 1541 | xs_html_attr("cols", "40"), | ||
| 1542 | xs_html_attr("rows", "4"), | ||
| 1543 | xs_html_attr("placeholder", "#cats\n#windowfriday\n#classicalmusic"), | ||
| 1544 | xs_html_text(blocked_hashtags)), | ||
| 1545 | |||
| 1546 | xs_html_tag("br", NULL), | ||
| 1547 | |||
| 1548 | xs_html_sctag("input", | ||
| 1549 | xs_html_attr("type", "submit"), | ||
| 1550 | xs_html_attr("class", "button"), | ||
| 1551 | xs_html_attr("value", L("Update hashtags"))))))); | ||
| 1552 | |||
| 1517 | return top_controls; | 1553 | return top_controls; |
| 1518 | } | 1554 | } |
| 1519 | 1555 | ||
| @@ -2281,8 +2317,10 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, | |||
| 2281 | continue; | 2317 | continue; |
| 2282 | 2318 | ||
| 2283 | /* drop silently any attachment that may include JavaScript */ | 2319 | /* drop silently any attachment that may include JavaScript */ |
| 2284 | if (strcmp(type, "image/svg+xml") == 0 || | 2320 | if (strcmp(type, "text/html") == 0) |
| 2285 | strcmp(type, "text/html") == 0) | 2321 | continue; |
| 2322 | |||
| 2323 | if (strcmp(type, "image/svg+xml") == 0 && !xs_is_true(xs_dict_get(srv_config, "enable_svg"))) | ||
| 2286 | continue; | 2324 | continue; |
| 2287 | 2325 | ||
| 2288 | /* do this attachment include an icon? */ | 2326 | /* do this attachment include an icon? */ |
| @@ -2724,7 +2762,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, | |||
| 2724 | xs_html_attr("href", url), | 2762 | xs_html_attr("href", url), |
| 2725 | xs_html_attr("class", "snac-list-link"), | 2763 | xs_html_attr("class", "snac-list-link"), |
| 2726 | xs_html_attr("title", L("Pinned posts")), | 2764 | xs_html_attr("title", L("Pinned posts")), |
| 2727 | xs_html_text("pinned")))); | 2765 | xs_html_text(L("pinned"))))); |
| 2728 | } | 2766 | } |
| 2729 | 2767 | ||
| 2730 | { | 2768 | { |
| @@ -2736,7 +2774,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, | |||
| 2736 | xs_html_attr("href", url), | 2774 | xs_html_attr("href", url), |
| 2737 | xs_html_attr("class", "snac-list-link"), | 2775 | xs_html_attr("class", "snac-list-link"), |
| 2738 | xs_html_attr("title", L("Bookmarked posts")), | 2776 | xs_html_attr("title", L("Bookmarked posts")), |
| 2739 | xs_html_text("bookmarks")))); | 2777 | xs_html_text(L("bookmarks"))))); |
| 2740 | } | 2778 | } |
| 2741 | 2779 | ||
| 2742 | { | 2780 | { |
| @@ -2748,7 +2786,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, | |||
| 2748 | xs_html_attr("href", url), | 2786 | xs_html_attr("href", url), |
| 2749 | xs_html_attr("class", "snac-list-link"), | 2787 | xs_html_attr("class", "snac-list-link"), |
| 2750 | xs_html_attr("title", L("Post drafts")), | 2788 | xs_html_attr("title", L("Post drafts")), |
| 2751 | xs_html_text("drafts")))); | 2789 | xs_html_text(L("drafts"))))); |
| 2752 | } | 2790 | } |
| 2753 | 2791 | ||
| 2754 | /* the list of followed hashtags */ | 2792 | /* the list of followed hashtags */ |
| @@ -3982,7 +4020,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 3982 | const char *b64 = xs_dict_get(q_vars, "content"); | 4020 | const char *b64 = xs_dict_get(q_vars, "content"); |
| 3983 | int sz; | 4021 | int sz; |
| 3984 | xs *content = xs_base64_dec(b64, &sz); | 4022 | xs *content = xs_base64_dec(b64, &sz); |
| 3985 | xs *msg = msg_note(&snac, content, NULL, NULL, NULL, 0, NULL); | 4023 | xs *msg = msg_note(&snac, content, NULL, NULL, NULL, 0, NULL, NULL); |
| 3986 | xs *c_msg = msg_create(&snac, msg); | 4024 | xs *c_msg = msg_create(&snac, msg); |
| 3987 | 4025 | ||
| 3988 | timeline_add(&snac, xs_dict_get(msg, "id"), msg); | 4026 | timeline_add(&snac, xs_dict_get(msg, "id"), msg); |
| @@ -4182,7 +4220,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, | |||
| 4182 | enqueue_close_question(&snac, xs_dict_get(msg, "id"), end_secs); | 4220 | enqueue_close_question(&snac, xs_dict_get(msg, "id"), end_secs); |
| 4183 | } | 4221 | } |
| 4184 | else | 4222 | else |
| 4185 | msg = msg_note(&snac, content_2, to, in_reply_to, attach_list, priv, NULL); | 4223 | msg = msg_note(&snac, content_2, to, in_reply_to, attach_list, priv, NULL, NULL); |
| 4186 | 4224 | ||
| 4187 | if (sensitive != NULL) { | 4225 | if (sensitive != NULL) { |
| 4188 | msg = xs_dict_set(msg, "sensitive", xs_stock(XSTYPE_TRUE)); | 4226 | msg = xs_dict_set(msg, "sensitive", xs_stock(XSTYPE_TRUE)); |
| @@ -4621,7 +4659,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, | |||
| 4621 | int c = 0; | 4659 | int c = 0; |
| 4622 | 4660 | ||
| 4623 | while (xs_list_next(ls, &v, &c)) { | 4661 | while (xs_list_next(ls, &v, &c)) { |
| 4624 | xs *msg = msg_note(&snac, "", actor, irt, NULL, 1, NULL); | 4662 | xs *msg = msg_note(&snac, "", actor, irt, NULL, 1, NULL, NULL); |
| 4625 | 4663 | ||
| 4626 | /* set the option */ | 4664 | /* set the option */ |
| 4627 | msg = xs_dict_append(msg, "name", v); | 4665 | msg = xs_dict_append(msg, "name", v); |
| @@ -4683,6 +4721,35 @@ int html_post_handler(const xs_dict *req, const char *q_path, | |||
| 4683 | 4721 | ||
| 4684 | status = HTTP_STATUS_SEE_OTHER; | 4722 | status = HTTP_STATUS_SEE_OTHER; |
| 4685 | } | 4723 | } |
| 4724 | else | ||
| 4725 | if (p_path && strcmp(p_path, "admin/blocked-hashtags") == 0) { /** **/ | ||
| 4726 | const char *hashtags = xs_dict_get(p_vars, "blocked_hashtags"); | ||
| 4727 | |||
| 4728 | if (xs_is_string(hashtags)) { | ||
| 4729 | xs *new_hashtags = xs_list_new(); | ||
| 4730 | xs *l = xs_split(hashtags, "\n"); | ||
| 4731 | const char *v; | ||
| 4732 | |||
| 4733 | xs_list_foreach(l, v) { | ||
| 4734 | xs *s1 = xs_strip_i(xs_dup(v)); | ||
| 4735 | s1 = xs_replace_i(s1, " ", ""); | ||
| 4736 | |||
| 4737 | if (*s1 == '\0') | ||
| 4738 | continue; | ||
| 4739 | |||
| 4740 | xs *s2 = xs_utf8_to_lower(s1); | ||
| 4741 | if (*s2 != '#') | ||
| 4742 | s2 = xs_str_prepend_i(s2, "#"); | ||
| 4743 | |||
| 4744 | new_hashtags = xs_list_append(new_hashtags, s2); | ||
| 4745 | } | ||
| 4746 | |||
| 4747 | snac.config = xs_dict_set(snac.config, "blocked_hashtags", new_hashtags); | ||
| 4748 | user_persist(&snac, 0); | ||
| 4749 | } | ||
| 4750 | |||
| 4751 | status = HTTP_STATUS_SEE_OTHER; | ||
| 4752 | } | ||
| 4686 | 4753 | ||
| 4687 | if (status == HTTP_STATUS_SEE_OTHER) { | 4754 | if (status == HTTP_STATUS_SEE_OTHER) { |
| 4688 | const char *redir = xs_dict_get(p_vars, "redir"); | 4755 | const char *redir = xs_dict_get(p_vars, "redir"); |