diff options
| -rw-r--r-- | activitypub.c | 4 | ||||
| -rw-r--r-- | format.c | 5 | ||||
| -rw-r--r-- | html.c | 57 | ||||
| -rw-r--r-- | httpd.c | 4 | ||||
| -rw-r--r-- | snac.h | 1 | ||||
| -rw-r--r-- | xs_mime.h | 1 |
6 files changed, 54 insertions, 18 deletions
diff --git a/activitypub.c b/activitypub.c index 53a1e74..dcbb79f 100644 --- a/activitypub.c +++ b/activitypub.c | |||
| @@ -1332,6 +1332,10 @@ xs_dict *msg_actor(snac *snac) | |||
| 1332 | msg = xs_dict_set(msg, "preferredUsername", snac->uid); | 1332 | msg = xs_dict_set(msg, "preferredUsername", snac->uid); |
| 1333 | msg = xs_dict_set(msg, "published", xs_dict_get(snac->config, "published")); | 1333 | msg = xs_dict_set(msg, "published", xs_dict_get(snac->config, "published")); |
| 1334 | 1334 | ||
| 1335 | // this exists so we get the emoji tags from our name too. | ||
| 1336 | // and then we just throw away the result, because it's kinda useless to have markdown in the display name. | ||
| 1337 | xs *name_dummy = not_really_markdown(xs_dict_get(snac->config, "name"), NULL, &tags); | ||
| 1338 | |||
| 1335 | xs *f_bio_2 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL, &tags); | 1339 | xs *f_bio_2 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL, &tags); |
| 1336 | f_bio = process_tags(snac, f_bio_2, &tags); | 1340 | f_bio = process_tags(snac, f_bio_2, &tags); |
| 1337 | msg = xs_dict_set(msg, "summary", f_bio); | 1341 | msg = xs_dict_set(msg, "summary", f_bio); |
| @@ -405,10 +405,11 @@ xs_str *not_really_markdown(const char *content, xs_list **attach, xs_list **tag | |||
| 405 | const char *k, *v; | 405 | const char *k, *v; |
| 406 | 406 | ||
| 407 | while (xs_dict_next(d, &k, &v, &c)) { | 407 | while (xs_dict_next(d, &k, &v, &c)) { |
| 408 | const char *t = NULL; | 408 | const char *t = xs_mime_by_ext(v); |
| 409 | 409 | ||
| 410 | /* is it an URL to an image? */ | 410 | /* is it an URL to an image? */ |
| 411 | if (xs_startswith(v, "https:/" "/") && xs_startswith((t = xs_mime_by_ext(v)), "image/")) { | 411 | if (xs_startswith(v, "https:/" "/") && |
| 412 | (xs_startswith(t, "image/") || strcmp(t, "application/octet-stream") == 0)) { | ||
| 412 | if (tag && xs_str_in(s, k) != -1) { | 413 | if (tag && xs_str_in(s, k) != -1) { |
| 413 | /* add the emoji to the tag list */ | 414 | /* add the emoji to the tag list */ |
| 414 | xs *e = xs_dict_new(); | 415 | xs *e = xs_dict_new(); |
| @@ -69,6 +69,7 @@ xs_str *replace_shortnames(xs_str *s, const xs_list *tag, int ems, const char *p | |||
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | xs *style = xs_fmt("height: %dem; width: %dem; vertical-align: middle;", ems, ems); | 71 | xs *style = xs_fmt("height: %dem; width: %dem; vertical-align: middle;", ems, ems); |
| 72 | xs *class = xs_fmt("snac-emoji snac-emoji-%d-em", ems); | ||
| 72 | 73 | ||
| 73 | const xs_dict *v; | 74 | const xs_dict *v; |
| 74 | int c = 0; | 75 | int c = 0; |
| @@ -91,7 +92,13 @@ xs_str *replace_shortnames(xs_str *s, const xs_list *tag, int ems, const char *p | |||
| 91 | const char *u = xs_dict_get(i, "url"); | 92 | const char *u = xs_dict_get(i, "url"); |
| 92 | const char *mt = xs_dict_get(i, "mediaType"); | 93 | const char *mt = xs_dict_get(i, "mediaType"); |
| 93 | 94 | ||
| 94 | if (xs_is_string(u) && xs_is_string(mt)) { | 95 | if (xs_is_string(u)) { |
| 96 | // on akkoma instances mediaType is not present. | ||
| 97 | // but we need to to know if the image is an svg or not. | ||
| 98 | // for now, i just use the file extention, which may not be the most reliable... | ||
| 99 | if (!xs_is_string(mt)) | ||
| 100 | mt = xs_mime_by_ext(u); | ||
| 101 | |||
| 95 | if (strcmp(mt, "image/svg+xml") == 0 && !xs_is_true(xs_dict_get(srv_config, "enable_svg"))) | 102 | if (strcmp(mt, "image/svg+xml") == 0 && !xs_is_true(xs_dict_get(srv_config, "enable_svg"))) |
| 96 | s = xs_replace_i(s, n, ""); | 103 | s = xs_replace_i(s, n, ""); |
| 97 | else { | 104 | else { |
| @@ -102,7 +109,7 @@ xs_str *replace_shortnames(xs_str *s, const xs_list *tag, int ems, const char *p | |||
| 102 | xs_html_attr("src", url), | 109 | xs_html_attr("src", url), |
| 103 | xs_html_attr("alt", n), | 110 | xs_html_attr("alt", n), |
| 104 | xs_html_attr("title", n), | 111 | xs_html_attr("title", n), |
| 105 | xs_html_attr("class", "snac-emoji"), | 112 | xs_html_attr("class", class), |
| 106 | xs_html_attr("style", style)); | 113 | xs_html_attr("style", style)); |
| 107 | 114 | ||
| 108 | xs *s1 = xs_html_render(img); | 115 | xs *s1 = xs_html_render(img); |
| @@ -137,6 +144,26 @@ xs_str *actor_name(xs_dict *actor, const char *proxy) | |||
| 137 | } | 144 | } |
| 138 | 145 | ||
| 139 | 146 | ||
| 147 | xs_str *format_text_with_emoji(snac *user, const char *text, int ems, const char *proxy) | ||
| 148 | /* needed when we have local text with no tags attached */ | ||
| 149 | { | ||
| 150 | xs *tags = xs_list_new(); | ||
| 151 | xs *name1 = not_really_markdown(text, NULL, &tags); | ||
| 152 | |||
| 153 | xs_str *name3; | ||
| 154 | if (user) { | ||
| 155 | xs *name2 = process_tags(user, name1, &tags); | ||
| 156 | name3 = sanitize(name2); | ||
| 157 | } | ||
| 158 | else { | ||
| 159 | name3 = sanitize(name1); | ||
| 160 | name3 = xs_replace_i(name3, "<br>", ""); | ||
| 161 | } | ||
| 162 | |||
| 163 | return replace_shortnames(name3, tags, ems, proxy); | ||
| 164 | } | ||
| 165 | |||
| 166 | |||
| 140 | xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date, | 167 | xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date, |
| 141 | const char *udate, const char *url, int priv, | 168 | const char *udate, const char *url, int priv, |
| 142 | int in_people, const char *proxy, const char *lang, | 169 | int in_people, const char *proxy, const char *lang, |
| @@ -970,10 +997,12 @@ static xs_html *html_user_body(snac *user, int read_only) | |||
| 970 | xs_dict_get(user->config, "uid"), | 997 | xs_dict_get(user->config, "uid"), |
| 971 | xs_dict_get(srv_config, "host")); | 998 | xs_dict_get(srv_config, "host")); |
| 972 | 999 | ||
| 1000 | xs *display_name = format_text_with_emoji(NULL, xs_dict_get(user->config, "name"), 1, proxy); | ||
| 1001 | |||
| 973 | xs_html_add(top_user, | 1002 | xs_html_add(top_user, |
| 974 | xs_html_tag("p", | 1003 | xs_html_tag("p", |
| 975 | xs_html_attr("class", "p-name snac-top-user-name"), | 1004 | xs_html_attr("class", "p-name snac-top-user-name"), |
| 976 | xs_html_text(xs_dict_get(user->config, "name"))), | 1005 | xs_html_raw(display_name)), |
| 977 | xs_html_tag("p", | 1006 | xs_html_tag("p", |
| 978 | xs_html_attr("class", "snac-top-user-id"), | 1007 | xs_html_attr("class", "snac-top-user-id"), |
| 979 | xs_html_text(handle))); | 1008 | xs_html_text(handle))); |
| @@ -1001,16 +1030,11 @@ static xs_html *html_user_body(snac *user, int read_only) | |||
| 1001 | } | 1030 | } |
| 1002 | 1031 | ||
| 1003 | if (read_only) { | 1032 | if (read_only) { |
| 1004 | xs *tags = xs_list_new(); | 1033 | xs *bio = format_text_with_emoji(user, xs_dict_get(user->config, "bio"), 2, proxy); |
| 1005 | xs *bio1 = not_really_markdown(xs_dict_get(user->config, "bio"), NULL, &tags); | ||
| 1006 | xs *bio2 = process_tags(user, bio1, &tags); | ||
| 1007 | xs *bio3 = sanitize(bio2); | ||
| 1008 | |||
| 1009 | bio3 = replace_shortnames(bio3, tags, 2, proxy); | ||
| 1010 | 1034 | ||
| 1011 | xs_html *top_user_bio = xs_html_tag("div", | 1035 | xs_html *top_user_bio = xs_html_tag("div", |
| 1012 | xs_html_attr("class", "p-note snac-top-user-bio"), | 1036 | xs_html_attr("class", "p-note snac-top-user-bio"), |
| 1013 | xs_html_raw(bio3)); /* already sanitized */ | 1037 | xs_html_raw(bio)); /* already sanitized */ |
| 1014 | 1038 | ||
| 1015 | xs_html_add(top_user, | 1039 | xs_html_add(top_user, |
| 1016 | top_user_bio); | 1040 | top_user_bio); |
| @@ -3134,6 +3158,7 @@ xs_html *html_people_list(snac *user, xs_list *list, const char *header, const c | |||
| 3134 | 3158 | ||
| 3135 | if (!xs_is_null(c)) { | 3159 | if (!xs_is_null(c)) { |
| 3136 | xs *sc = sanitize(c); | 3160 | xs *sc = sanitize(c); |
| 3161 | sc = replace_shortnames(sc, xs_dict_get(actor, "tag"), 2, proxy); | ||
| 3137 | 3162 | ||
| 3138 | xs_html *snac_content = xs_html_tag("div", | 3163 | xs_html *snac_content = xs_html_tag("div", |
| 3139 | xs_html_attr("class", "snac-content")); | 3164 | xs_html_attr("class", "snac-content")); |
| @@ -3351,7 +3376,8 @@ xs_str *html_notifications(snac *user, int skip, int show) | |||
| 3351 | continue; | 3376 | continue; |
| 3352 | 3377 | ||
| 3353 | xs *a_name = actor_name(actor, proxy); | 3378 | xs *a_name = actor_name(actor, proxy); |
| 3354 | const char *label = type; | 3379 | xs *label_sanatized = sanitize(type); |
| 3380 | const char *label = label_sanatized; | ||
| 3355 | 3381 | ||
| 3356 | if (strcmp(type, "Create") == 0) | 3382 | if (strcmp(type, "Create") == 0) |
| 3357 | label = L("Mention"); | 3383 | label = L("Mention"); |
| @@ -3362,11 +3388,12 @@ xs_str *html_notifications(snac *user, int skip, int show) | |||
| 3362 | if (strcmp(type, "Undo") == 0 && strcmp(utype, "Follow") == 0) | 3388 | if (strcmp(type, "Undo") == 0 && strcmp(utype, "Follow") == 0) |
| 3363 | label = L("Unfollow"); | 3389 | label = L("Unfollow"); |
| 3364 | else | 3390 | else |
| 3365 | if (strcmp(type, "EmojiReact") == 0) { | 3391 | if (strcmp(type, "EmojiReact") == 0 || strcmp(type, "Like") == 0) { |
| 3366 | const char *content = xs_dict_get_path(noti, "msg.content"); | 3392 | const char *content = xs_dict_get_path(noti, "msg.content"); |
| 3367 | 3393 | ||
| 3368 | if (xs_type(content) == XSTYPE_STRING) { | 3394 | if (xs_type(content) == XSTYPE_STRING) { |
| 3369 | wrk = xs_fmt("%s (%s)", type, content); | 3395 | xs *emoji = replace_shortnames(xs_dup(content), xs_dict_get_path(noti, "msg.tag"), 1, proxy); |
| 3396 | wrk = xs_fmt("%s (%s️)", type, emoji); | ||
| 3370 | label = wrk; | 3397 | label = wrk; |
| 3371 | } | 3398 | } |
| 3372 | } | 3399 | } |
| @@ -3378,7 +3405,7 @@ xs_str *html_notifications(snac *user, int skip, int show) | |||
| 3378 | 3405 | ||
| 3379 | xs_html *this_html_label = xs_html_container( | 3406 | xs_html *this_html_label = xs_html_container( |
| 3380 | xs_html_tag("b", | 3407 | xs_html_tag("b", |
| 3381 | xs_html_text(label), | 3408 | xs_html_raw(label), |
| 3382 | xs_html_text(" by "), | 3409 | xs_html_text(" by "), |
| 3383 | xs_html_tag("a", | 3410 | xs_html_tag("a", |
| 3384 | xs_html_attr("href", actor_id), | 3411 | xs_html_attr("href", actor_id), |
| @@ -3678,7 +3705,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 3678 | 3705 | ||
| 3679 | if (xs_is_true(xs_dict_get(srv_config, "strict_public_timelines"))) | 3706 | if (xs_is_true(xs_dict_get(srv_config, "strict_public_timelines"))) |
| 3680 | list = timeline_simple_list(&snac, "public", skip, show, &more); | 3707 | list = timeline_simple_list(&snac, "public", skip, show, &more); |
| 3681 | else | 3708 | else |
| 3682 | list = timeline_list(&snac, "public", skip, show, &more); | 3709 | list = timeline_list(&snac, "public", skip, show, &more); |
| 3683 | 3710 | ||
| 3684 | xs *pins = pinned_list(&snac); | 3711 | xs *pins = pinned_list(&snac); |
| @@ -139,6 +139,8 @@ static xs_str *greeting_html(void) | |||
| 139 | snac user; | 139 | snac user; |
| 140 | 140 | ||
| 141 | if (strcmp(uid, "relay") && user_open(&user, uid)) { | 141 | if (strcmp(uid, "relay") && user_open(&user, uid)) { |
| 142 | xs *formatted_name = format_text_with_emoji(NULL, xs_dict_get(user.config, "name"), 1, NULL); | ||
| 143 | |||
| 142 | xs_html_add(ul, | 144 | xs_html_add(ul, |
| 143 | xs_html_tag("li", | 145 | xs_html_tag("li", |
| 144 | xs_html_tag("a", | 146 | xs_html_tag("a", |
| @@ -148,7 +150,7 @@ static xs_str *greeting_html(void) | |||
| 148 | xs_html_text("@"), | 150 | xs_html_text("@"), |
| 149 | xs_html_text(host), | 151 | xs_html_text(host), |
| 150 | xs_html_text(" ("), | 152 | xs_html_text(" ("), |
| 151 | xs_html_text(xs_dict_get(user.config, "name")), | 153 | xs_html_raw(formatted_name), |
| 152 | xs_html_text(")")))); | 154 | xs_html_text(")")))); |
| 153 | 155 | ||
| 154 | user_free(&user); | 156 | user_free(&user); |
| @@ -375,6 +375,7 @@ int activitypub_post_handler(const xs_dict *req, const char *q_path, | |||
| 375 | char **body, int *b_size, char **ctype); | 375 | char **body, int *b_size, char **ctype); |
| 376 | 376 | ||
| 377 | xs_dict *emojis(void); | 377 | xs_dict *emojis(void); |
| 378 | xs_str *format_text_with_emoji(snac *user, const char *text, int ems, const char *proxy); | ||
| 378 | xs_str *not_really_markdown(const char *content, xs_list **attach, xs_list **tag); | 379 | xs_str *not_really_markdown(const char *content, xs_list **attach, xs_list **tag); |
| 379 | xs_str *sanitize(const char *content); | 380 | xs_str *sanitize(const char *content); |
| 380 | xs_str *encode_html(const char *str); | 381 | xs_str *encode_html(const char *str); |
| @@ -16,6 +16,7 @@ extern const char *xs_mime_types[]; | |||
| 16 | const char *xs_mime_types[] = { | 16 | const char *xs_mime_types[] = { |
| 17 | "3gp", "video/3gpp", | 17 | "3gp", "video/3gpp", |
| 18 | "aac", "audio/aac", | 18 | "aac", "audio/aac", |
| 19 | "apng", "image/apng", | ||
| 19 | "avif", "image/avif", | 20 | "avif", "image/avif", |
| 20 | "css", "text/css", | 21 | "css", "text/css", |
| 21 | "flac", "audio/flac", | 22 | "flac", "audio/flac", |