From 97bf8a9cbceeddb96abc65e1c61a3022b173b352 Mon Sep 17 00:00:00 2001 From: grunfink Date: Mon, 26 May 2025 07:40:08 +0200 Subject: Fixed search by url for piefed. Piefed returns 200 OK for webfinger queries, even it it doesn't return any valid data. --- html.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'html.c') diff --git a/html.c b/html.c index de2fdce..83dac0a 100644 --- a/html.c +++ b/html.c @@ -3748,7 +3748,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, /* may by an actor; try a webfinger */ xs *actor_obj = NULL; - if (valid_status(webfinger_request(q, &actor_obj, &url_acct))) { + if (valid_status(webfinger_request(q, &actor_obj, &url_acct)) && xs_is_string(url_acct)) { /* it's an actor; do the dirty trick of changing q to the account name */ q = url_acct; } -- cgit From 631e44a64a20741b5e4716bf75caf7fa743fef82 Mon Sep 17 00:00:00 2001 From: grunfink Date: Tue, 27 May 2025 21:08:57 +0200 Subject: Renamed timeline_here() to timeline_here_by_md5(), as it always should have been. --- data.c | 4 ++-- html.c | 6 +++--- main.c | 2 +- mastoapi.c | 2 +- snac.h | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'html.c') diff --git a/data.c b/data.c index f45e346..9eada38 100644 --- a/data.c +++ b/data.c @@ -1391,7 +1391,7 @@ xs_str *timeline_fn_by_md5(snac *snac, const char *md5) } -int timeline_here(snac *snac, const char *md5) +int timeline_here_by_md5(snac *snac, const char *md5) /* checks if an object is in the user cache */ { xs *fn = timeline_fn_by_md5(snac, md5); @@ -1515,7 +1515,7 @@ xs_list *timeline_top_level(snac *snac, const xs_list *list) break; /* well, there is a parent... but is it here? */ - if (!timeline_here(snac, line2)) + if (!timeline_here_by_md5(snac, line2)) break; /* it's here! try again with its own parent */ diff --git a/html.c b/html.c index 83dac0a..4aa0fa4 100644 --- a/html.c +++ b/html.c @@ -2117,7 +2117,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, if (!xs_is_null(parent) && *parent) { xs *md5 = xs_md5_hex(parent, strlen(parent)); - if (!timeline_here(user, md5)) { + if (!timeline_here_by_md5(user, md5)) { xs_html_add(post_header, xs_html_tag("div", xs_html_attr("class", "snac-origin"), @@ -3775,7 +3775,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, /* add the post to the timeline */ xs *md5 = xs_md5_hex(q, strlen(q)); - if (!timeline_here(&snac, md5)) + if (!timeline_here_by_md5(&snac, md5)) timeline_add(&snac, q, object); } } @@ -3917,7 +3917,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, xs *l = xs_split(p_path, "/"); const char *md5 = xs_list_get(l, -1); - if (md5 && *md5 && timeline_here(&snac, md5)) { + if (md5 && *md5 && timeline_here_by_md5(&snac, md5)) { xs *list0 = xs_list_append(xs_list_new(), md5); xs *list = timeline_top_level(&snac, list0); diff --git a/main.c b/main.c index 80df2d0..9cfbb0d 100644 --- a/main.c +++ b/main.c @@ -695,7 +695,7 @@ int main(int argc, char *argv[]) xs_json_dump(data, 4, stdout); enqueue_actor_refresh(&snac, xs_dict_get(data, "attributedTo"), 0); - if (!timeline_here(&snac, url)) + if (!timeline_here_by_md5(&snac, url)) timeline_add(&snac, url, data); else printf("Post %s already here\n", url); diff --git a/mastoapi.c b/mastoapi.c index 9875b12..c88fd1b 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -2510,7 +2510,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (xs_startswith(q, "https://")) { xs *md5 = xs_md5_hex(q, strlen(q)); - if (!timeline_here(&snac1, md5)) { + if (!timeline_here_by_md5(&snac1, md5)) { xs *object = NULL; int status; diff --git a/snac.h b/snac.h index 841c41e..621ab8a 100644 --- a/snac.h +++ b/snac.h @@ -164,7 +164,7 @@ int pending_count(snac *user); double timeline_mtime(snac *snac); int timeline_touch(snac *snac); -int timeline_here(snac *snac, const char *md5); +int timeline_here_by_md5(snac *snac, const char *md5); int timeline_get_by_md5(snac *snac, const char *md5, xs_dict **msg); int timeline_del(snac *snac, const char *id); xs_str *user_index_fn(snac *user, const char *idx_name); -- cgit From 5bc451159420d5d51a507fda82a623069cfae92b Mon Sep 17 00:00:00 2001 From: grunfink Date: Tue, 27 May 2025 21:14:23 +0200 Subject: New function timeline_here(). --- data.c | 8 ++++++++ html.c | 8 ++------ main.c | 2 +- mastoapi.c | 4 +--- snac.h | 1 + 5 files changed, 13 insertions(+), 10 deletions(-) (limited to 'html.c') diff --git a/data.c b/data.c index 9eada38..224976b 100644 --- a/data.c +++ b/data.c @@ -1400,6 +1400,14 @@ int timeline_here_by_md5(snac *snac, const char *md5) } +int timeline_here(snac *user, const char *id) +{ + xs *md5 = xs_md5_hex(id, strlen(id)); + + return timeline_here_by_md5(user, md5); +} + + int timeline_get_by_md5(snac *snac, const char *md5, xs_dict **msg) /* gets a message from the timeline */ { diff --git a/html.c b/html.c index 4aa0fa4..4c30355 100644 --- a/html.c +++ b/html.c @@ -2115,9 +2115,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, const char *parent = get_in_reply_to(msg); if (!xs_is_null(parent) && *parent) { - xs *md5 = xs_md5_hex(parent, strlen(parent)); - - if (!timeline_here_by_md5(user, md5)) { + if (!timeline_here(user, parent)) { xs_html_add(post_header, xs_html_tag("div", xs_html_attr("class", "snac-origin"), @@ -3773,9 +3771,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, q = url_acct; /* add the post to the timeline */ - xs *md5 = xs_md5_hex(q, strlen(q)); - - if (!timeline_here_by_md5(&snac, md5)) + if (!timeline_here(&snac, q)) timeline_add(&snac, q, object); } } diff --git a/main.c b/main.c index 9cfbb0d..80df2d0 100644 --- a/main.c +++ b/main.c @@ -695,7 +695,7 @@ int main(int argc, char *argv[]) xs_json_dump(data, 4, stdout); enqueue_actor_refresh(&snac, xs_dict_get(data, "attributedTo"), 0); - if (!timeline_here_by_md5(&snac, url)) + if (!timeline_here(&snac, url)) timeline_add(&snac, url, data); else printf("Post %s already here\n", url); diff --git a/mastoapi.c b/mastoapi.c index c88fd1b..df713a8 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -2508,9 +2508,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, /* reply something only for offset 0; otherwise, apps like Tusky keep asking again and again */ if (xs_startswith(q, "https://")) { - xs *md5 = xs_md5_hex(q, strlen(q)); - - if (!timeline_here_by_md5(&snac1, md5)) { + if (!timeline_here(&snac1, q)) { xs *object = NULL; int status; diff --git a/snac.h b/snac.h index 621ab8a..f32a90d 100644 --- a/snac.h +++ b/snac.h @@ -165,6 +165,7 @@ int pending_count(snac *user); double timeline_mtime(snac *snac); int timeline_touch(snac *snac); int timeline_here_by_md5(snac *snac, const char *md5); +int timeline_here(snac *snac, const char *id); int timeline_get_by_md5(snac *snac, const char *md5, xs_dict **msg); int timeline_del(snac *snac, const char *id); xs_str *user_index_fn(snac *user, const char *idx_name); -- cgit From 859de583d9b575a830bab92a6379f77c70910a93 Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 28 May 2025 07:44:34 +0200 Subject: Renamed timeline_to_rss() to rss_from_timeline(). --- html.c | 4 ++-- httpd.c | 2 +- snac.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'html.c') diff --git a/html.c b/html.c index 4c30355..d3d5075 100644 --- a/html.c +++ b/html.c @@ -4123,7 +4123,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, xs_dict_get(srv_config, "host")); xs *rss_link = xs_fmt("%s.rss", snac.actor); - *body = timeline_to_rss(&snac, elems, rss_title, rss_link, bio); + *body = rss_from_timeline(&snac, elems, rss_title, rss_link, bio); *b_size = strlen(*body); *ctype = "application/rss+xml; charset=utf-8"; status = HTTP_STATUS_OK; @@ -5022,7 +5022,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, } -xs_str *timeline_to_rss(snac *user, const xs_list *timeline, +xs_str *rss_from_timeline(snac *user, const xs_list *timeline, const char *title, const char *link, const char *desc) /* converts a timeline to rss */ { diff --git a/httpd.c b/httpd.c index 6f7d69b..41b2515 100644 --- a/httpd.c +++ b/httpd.c @@ -244,7 +244,7 @@ int server_get_handler(xs_dict *req, const char *q_path, if (!xs_is_null(accept) && strcmp(accept, "application/rss+xml") == 0) { xs *link = xs_fmt("%s/?t=%s", srv_baseurl, t); - *body = timeline_to_rss(NULL, tl, link, link, link); + *body = rss_from_timeline(NULL, tl, link, link, link); *ctype = "application/rss+xml; charset=utf-8"; } else { diff --git a/snac.h b/snac.h index f32a90d..9a5aca0 100644 --- a/snac.h +++ b/snac.h @@ -395,7 +395,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, int html_post_handler(const xs_dict *req, const char *q_path, char *payload, int p_size, char **body, int *b_size, char **ctype); -xs_str *timeline_to_rss(snac *user, const xs_list *timeline, +xs_str *rss_from_timeline(snac *user, const xs_list *timeline, const char *title, const char *link, const char *desc); int write_default_css(void); -- cgit From 97ff66116b7633066375bbc6cc88be5b8587453b Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 28 May 2025 07:48:47 +0200 Subject: New file rss.c. --- Makefile | 9 ++--- Makefile.NetBSD | 9 ++--- html.c | 97 --------------------------------------------------- rss.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ snac.h | 5 +-- 5 files changed, 118 insertions(+), 107 deletions(-) create mode 100644 rss.c (limited to 'html.c') diff --git a/Makefile b/Makefile index 46fdb09..bb4029c 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CFLAGS?=-g -Wall -Wextra -pedantic all: snac snac: snac.o main.o sandbox.o data.o http.o httpd.o webfinger.o \ - activitypub.o html.o utils.o format.o upgrade.o mastoapi.o + activitypub.o html.o utils.o format.o upgrade.o mastoapi.o rss.o $(CC) $(CFLAGS) -L$(PREFIX)/lib *.o -lcurl -lcrypto $(LDFLAGS) -pthread -o $@ test: tests/smtp @@ -48,12 +48,12 @@ update-po: 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 + xs_webmention.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 \ 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 + xs_time.h xs_match.h xs_unicode.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 xs_url.h \ xs_random.h snac.h http_codes.h @@ -66,7 +66,8 @@ 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 + xs_unicode.h snac.h http_codes.h +rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h snac.h http_codes.h 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 \ diff --git a/Makefile.NetBSD b/Makefile.NetBSD index ecf8205..a2bf83c 100644 --- a/Makefile.NetBSD +++ b/Makefile.NetBSD @@ -6,7 +6,7 @@ LDFLAGS=-lrt all: snac snac: snac.o main.o sandbox.o data.o http.o httpd.o webfinger.o \ - activitypub.o html.o utils.o format.o upgrade.o mastoapi.o + activitypub.o html.o utils.o format.o upgrade.o mastoapi.o rss.o $(CC) $(CFLAGS) -L/usr/pkg/lib *.o -lcurl -lcrypto -pthread $(LDFLAGS) -Wl,-rpath,/usr/lib -Wl,-rpath,/usr/pkg/lib -o $@ @@ -37,12 +37,12 @@ uninstall: 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 + xs_webmention.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 \ 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 + xs_time.h xs_match.h xs_unicode.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 xs_url.h \ xs_random.h snac.h http_codes.h @@ -55,7 +55,8 @@ 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 + xs_unicode.h snac.h http_codes.h +rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h snac.h http_codes.h 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 \ diff --git a/html.c b/html.c index d3d5075..fadcfb0 100644 --- a/html.c +++ b/html.c @@ -5020,100 +5020,3 @@ int html_post_handler(const xs_dict *req, const char *q_path, return status; } - - -xs_str *rss_from_timeline(snac *user, const xs_list *timeline, - const char *title, const char *link, const char *desc) -/* converts a timeline to rss */ -{ - xs_html *rss = xs_html_tag("rss", - xs_html_attr("xmlns:content", "http:/" "/purl.org/rss/1.0/modules/content/"), - xs_html_attr("version", "2.0"), - xs_html_attr("xmlns:atom", "http:/" "/www.w3.org/2005/Atom")); - - xs_html *channel = xs_html_tag("channel", - xs_html_tag("title", - xs_html_text(title)), - xs_html_tag("language", - xs_html_text("en")), - xs_html_tag("link", - xs_html_text(link)), - xs_html_sctag("atom:link", - xs_html_attr("href", link), - xs_html_attr("rel", "self"), - xs_html_attr("type", "application/rss+xml")), - xs_html_tag("generator", - xs_html_text(USER_AGENT)), - xs_html_tag("description", - xs_html_text(desc))); - - xs_html_add(rss, channel); - - int cnt = 0; - const char *v; - - xs_list_foreach(timeline, v) { - xs *msg = NULL; - - if (user) { - if (!valid_status(timeline_get_by_md5(user, v, &msg))) - continue; - } - else { - if (!valid_status(object_get_by_md5(v, &msg))) - continue; - } - - const char *id = xs_dict_get(msg, "id"); - const char *content = xs_dict_get(msg, "content"); - const char *published = xs_dict_get(msg, "published"); - - if (user && !xs_startswith(id, user->actor)) - continue; - - if (!id || !content || !published) - continue; - - /* create a title with the first line of the content */ - xs *title = xs_replace(content, "
", "\n"); - title = xs_regex_replace_i(title, "<[^>]+>", " "); - title = xs_regex_replace_i(title, "&[^;]+;", " "); - int i; - - for (i = 0; title[i] && title[i] != '\n' && i < 50; i++); - - if (title[i] != '\0') { - title[i] = '\0'; - title = xs_str_cat(title, "..."); - } - - title = xs_strip_i(title); - - /* convert the date */ - time_t t = xs_parse_iso_date(published, 0); - xs *rss_date = xs_str_utctime(t, "%a, %d %b %Y %T +0000"); - - /* if it's the first one, add it to the header */ - if (cnt == 0) - xs_html_add(channel, - xs_html_tag("lastBuildDate", - xs_html_text(rss_date))); - - xs_html_add(channel, - xs_html_tag("item", - xs_html_tag("title", - xs_html_text(title)), - xs_html_tag("link", - xs_html_text(id)), - xs_html_tag("guid", - xs_html_text(id)), - xs_html_tag("pubDate", - xs_html_text(rss_date)), - xs_html_tag("description", - xs_html_text(content)))); - - cnt++; - } - - return xs_html_render_s(rss, "\n"); -} diff --git a/rss.c b/rss.c new file mode 100644 index 0000000..61620fa --- /dev/null +++ b/rss.c @@ -0,0 +1,105 @@ +/* snac - A simple, minimalistic ActivityPub instance */ +/* copyright (c) 2025 grunfink et al. / MIT license */ + +#include "xs.h" +#include "xs_html.h" +#include "xs_regex.h" +#include "xs_time.h" + +#include "snac.h" + +xs_str *rss_from_timeline(snac *user, const xs_list *timeline, + const char *title, const char *link, const char *desc) +/* converts a timeline to rss */ +{ + xs_html *rss = xs_html_tag("rss", + xs_html_attr("xmlns:content", "http:/" "/purl.org/rss/1.0/modules/content/"), + xs_html_attr("version", "2.0"), + xs_html_attr("xmlns:atom", "http:/" "/www.w3.org/2005/Atom")); + + xs_html *channel = xs_html_tag("channel", + xs_html_tag("title", + xs_html_text(title)), + xs_html_tag("language", + xs_html_text("en")), + xs_html_tag("link", + xs_html_text(link)), + xs_html_sctag("atom:link", + xs_html_attr("href", link), + xs_html_attr("rel", "self"), + xs_html_attr("type", "application/rss+xml")), + xs_html_tag("generator", + xs_html_text(USER_AGENT)), + xs_html_tag("description", + xs_html_text(desc))); + + xs_html_add(rss, channel); + + int cnt = 0; + const char *v; + + xs_list_foreach(timeline, v) { + xs *msg = NULL; + + if (user) { + if (!valid_status(timeline_get_by_md5(user, v, &msg))) + continue; + } + else { + if (!valid_status(object_get_by_md5(v, &msg))) + continue; + } + + const char *id = xs_dict_get(msg, "id"); + const char *content = xs_dict_get(msg, "content"); + const char *published = xs_dict_get(msg, "published"); + + if (user && !xs_startswith(id, user->actor)) + continue; + + if (!id || !content || !published) + continue; + + /* create a title with the first line of the content */ + xs *title = xs_replace(content, "
", "\n"); + title = xs_regex_replace_i(title, "<[^>]+>", " "); + title = xs_regex_replace_i(title, "&[^;]+;", " "); + int i; + + for (i = 0; title[i] && title[i] != '\n' && i < 50; i++); + + if (title[i] != '\0') { + title[i] = '\0'; + title = xs_str_cat(title, "..."); + } + + title = xs_strip_i(title); + + /* convert the date */ + time_t t = xs_parse_iso_date(published, 0); + xs *rss_date = xs_str_utctime(t, "%a, %d %b %Y %T +0000"); + + /* if it's the first one, add it to the header */ + if (cnt == 0) + xs_html_add(channel, + xs_html_tag("lastBuildDate", + xs_html_text(rss_date))); + + xs_html_add(channel, + xs_html_tag("item", + xs_html_tag("title", + xs_html_text(title)), + xs_html_tag("link", + xs_html_text(id)), + xs_html_tag("guid", + xs_html_text(id)), + xs_html_tag("pubDate", + xs_html_text(rss_date)), + xs_html_tag("description", + xs_html_text(content)))); + + cnt++; + } + + return xs_html_render_s(rss, "\n"); +} diff --git a/snac.h b/snac.h index 9a5aca0..f95ba4d 100644 --- a/snac.h +++ b/snac.h @@ -395,8 +395,6 @@ int html_get_handler(const xs_dict *req, const char *q_path, int html_post_handler(const xs_dict *req, const char *q_path, char *payload, int p_size, char **body, int *b_size, char **ctype); -xs_str *rss_from_timeline(snac *user, const xs_list *timeline, - const char *title, const char *link, const char *desc); int write_default_css(void); int snac_init(const char *_basedir); @@ -462,3 +460,6 @@ 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); + +xs_str *rss_from_timeline(snac *user, const xs_list *timeline, + const char *title, const char *link, const char *desc); -- cgit From e2bb8078641f810b019635dd41f3e7ea191c5b52 Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 28 May 2025 08:45:44 +0200 Subject: Don't prepend a # before a hashtag that is really an URL. --- html.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'html.c') diff --git a/html.c b/html.c index fadcfb0..7fcc266 100644 --- a/html.c +++ b/html.c @@ -4956,9 +4956,16 @@ int html_post_handler(const xs_dict *req, const char *q_path, if (*s1 == '\0') continue; - xs *s2 = xs_utf8_to_lower(s1); - if (*s2 != '#') - s2 = xs_str_prepend_i(s2, "#"); + xs *s2 = NULL; + + if (xs_startswith(s1, "https:/")) + s2 = xs_dup(s1); + else { + s2 = xs_utf8_to_lower(s1); + + if (*s2 != '#') + s2 = xs_str_prepend_i(s2, "#"); + } new_hashtags = xs_list_append(new_hashtags, s2); } -- cgit From a1369b39c1bd3d2036af12368997648454ca5564 Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 28 May 2025 09:07:19 +0200 Subject: Activated hashtag RSS polling. --- activitypub.c | 4 ++++ html.c | 3 ++- httpd.c | 42 +++++++++++++++++++++++++++++++----------- rss.c | 9 +++++---- snac.h | 2 +- 5 files changed, 43 insertions(+), 17 deletions(-) (limited to 'html.c') diff --git a/activitypub.c b/activitypub.c index 0cc7bcb..2cffeac 100644 --- a/activitypub.c +++ b/activitypub.c @@ -3049,6 +3049,10 @@ void process_queue_item(xs_dict *q_item) } } } + else + if (strcmp(type, "rss_poll") == 0) { + rss_poll_hashtags(); + } else srv_log(xs_fmt("unexpected q_item type '%s'", type)); } diff --git a/html.c b/html.c index 7fcc266..3d213a2 100644 --- a/html.c +++ b/html.c @@ -1601,7 +1601,8 @@ xs_html *html_top_controls(snac *user) xs_html_attr("name", "followed_hashtags"), xs_html_attr("cols", "40"), xs_html_attr("rows", "4"), - xs_html_attr("placeholder", "#cats\n#windowfriday\n#classicalmusic"), + xs_html_attr("placeholder", "#cats\n#windowfriday\n#classicalmusic\nhttps:/" + "/mastodon.social/tags/dogs"), xs_html_text(followed_hashtags)), xs_html_tag("br", NULL), diff --git a/httpd.c b/httpd.c index 41b2515..c94a542 100644 --- a/httpd.c +++ b/httpd.c @@ -705,34 +705,36 @@ static pthread_cond_t sleep_cond; static void *background_thread(void *arg) /* background thread (queue management and other things) */ { - time_t purge_time; + time_t t, purge_time, rss_time; (void)arg; + t = time(NULL); + /* first purge time */ - purge_time = time(NULL) + 10 * 60; + purge_time = t + 10 * 60; + + /* first RSS polling time */ + rss_time = t + 15 * 60; srv_log(xs_fmt("background thread started")); while (p_state->srv_running) { - time_t t; int cnt = 0; p_state->th_state[0] = THST_QUEUE; { xs *list = user_list(); - char *p; const char *uid; /* process queues for all users */ - p = list; - while (xs_list_iter(&p, &uid)) { - snac snac; + xs_list_foreach(list, uid) { + snac user; - if (user_open(&snac, uid)) { - cnt += process_user_queue(&snac); - user_free(&snac); + if (user_open(&user, uid)) { + cnt += process_user_queue(&user); + user_free(&user); } } } @@ -740,8 +742,10 @@ static void *background_thread(void *arg) /* global queue */ cnt += process_queue(); + t = time(NULL); + /* time to purge? */ - if ((t = time(NULL)) > purge_time) { + if (t > purge_time) { /* next purge time is tomorrow */ purge_time = t + 24 * 60 * 60; @@ -750,6 +754,22 @@ static void *background_thread(void *arg) job_post(q_item, 0); } + /* time to poll the RSS? */ + if (t > rss_time) { + /* next RSS poll time */ + int hours = xs_number_get(xs_dict_get_def(srv_config, "rss_poll_hours", "4")); + + /* don't hammer servers too much */ + if (hours < 1) + hours = 1; + + rss_time = t + 60 * 60 * hours; + + xs *q_item = xs_dict_new(); + q_item = xs_dict_append(q_item, "type", "rss_poll"); + job_post(q_item, 0); + } + if (cnt == 0) { /* sleep 3 seconds */ diff --git a/rss.c b/rss.c index b31ffd3..ce3e184 100644 --- a/rss.c +++ b/rss.c @@ -110,6 +110,9 @@ xs_str *rss_from_timeline(snac *user, const xs_list *timeline, void rss_to_timeline(snac *user, const char *url) /* reads an RSS and inserts all ActivityPub posts into the user's timeline */ { + if (!xs_startswith(url, "https:/") && !xs_startswith(url, "http:/")) + return; + xs *hdrs = xs_dict_new(); hdrs = xs_dict_set(hdrs, "accept", "application/rss+xml"); hdrs = xs_dict_set(hdrs, "user-agent", USER_AGENT); @@ -204,10 +207,9 @@ void rss_to_timeline(snac *user, const char *url) } -void rss_process(void) +void rss_poll_hashtags(void) /* parses all RSS from all users */ { -#if 0 xs *list = user_list(); const char *uid; @@ -215,7 +217,7 @@ void rss_process(void) snac user; if (user_open(&user, uid)) { - const xs_list *rss = xs_dict_get(user.config, "rss"); + const xs_list *rss = xs_dict_get(user.config, "followed_hashtags"); if (xs_is_list(rss)) { const char *url; @@ -227,5 +229,4 @@ void rss_process(void) user_free(&user); } } -#endif } diff --git a/snac.h b/snac.h index db51a1c..06a36f1 100644 --- a/snac.h +++ b/snac.h @@ -464,4 +464,4 @@ const char *lang_str(const char *str, const snac *user); xs_str *rss_from_timeline(snac *user, const xs_list *timeline, const char *title, const char *link, const char *desc); void rss_to_timeline(snac *user, const char *url); -void rss_process(void); +void rss_poll_hashtags(void); -- cgit From 34d85b3e1bbda2e89191026b3815dd9b6f23afcb Mon Sep 17 00:00:00 2001 From: grunfink Date: Thu, 29 May 2025 13:12:43 +0200 Subject: mastoapi: fixed uploaded images name collision. --- html.c | 2 +- mastoapi.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'html.c') diff --git a/html.c b/html.c index 3d213a2..56dc2cc 100644 --- a/html.c +++ b/html.c @@ -4362,7 +4362,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, xs_rnd_buf(rnd, sizeof(rnd)); const char *ext = strrchr(fn, '.'); - xs *hash = xs_md5_hex(rnd, strlen(rnd)); + xs *hash = xs_md5_hex(rnd, sizeof(rnd)); xs *id = xs_fmt("post-%s%s", hash, ext ? ext : ""); xs *url = xs_fmt("%s/s/%s", snac.actor, id); int fo = xs_number_get(xs_list_get(attach_file, 1)); diff --git a/mastoapi.c b/mastoapi.c index df713a8..27c476e 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -2978,8 +2978,10 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, if (*fn != '\0') { char *ext = strrchr(fn, '.'); - xs *hash = xs_md5_hex(fn, strlen(fn)); - xs *id = xs_fmt("%s%s", hash, ext); + char rnd[32]; + xs_rnd_buf(rnd, sizeof(rnd)); + xs *hash = xs_md5_hex(rnd, sizeof(rnd)); + xs *id = xs_fmt("post-%s%s", hash, ext ? ext : ""); xs *url = xs_fmt("%s/s/%s", snac.actor, id); int fo = xs_number_get(xs_list_get(file, 1)); int fs = xs_number_get(xs_list_get(file, 2)); -- cgit From ffc7e52c6679d6cfeaa0567941cf803351031dcd Mon Sep 17 00:00:00 2001 From: grunfink Date: Fri, 30 May 2025 19:13:40 +0200 Subject: Added web UI to set the notify webhook. --- html.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'html.c') diff --git a/html.c b/html.c index 56dc2cc..a6e5f98 100644 --- a/html.c +++ b/html.c @@ -1290,6 +1290,7 @@ xs_html *html_top_controls(snac *user) 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", ""); + const char *webhook = xs_dict_get_def(user->config, "notify_webhook", ""); xs *metadata = NULL; const xs_dict *md = xs_dict_get(user->config, "metadata"); @@ -1451,6 +1452,14 @@ xs_html *html_top_controls(snac *user) xs_html_attr("name", "ntfy_token"), xs_html_attr("value", ntfy_token), xs_html_attr("placeholder", L("ntfy token - if needed")))), + xs_html_tag("p", + xs_html_text(L("Notify webhook:")), + xs_html_sctag("br", NULL), + xs_html_sctag("input", + xs_html_attr("type", "url"), + xs_html_attr("name", "notify_webhook"), + xs_html_attr("value", webhook), + xs_html_attr("placeholder", L("http://example.com/webhook")))), xs_html_tag("p", xs_html_text(L("Maximum days to keep posts (0: server settings):")), xs_html_sctag("br", NULL), @@ -4822,6 +4831,8 @@ int html_post_handler(const xs_dict *req, const char *q_path, 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", "")); + snac.config = xs_dict_set(snac.config, "notify_webhook", xs_dict_get_def(p_vars, "notify_webhook", "")); + if ((v = xs_dict_get(p_vars, "metadata")) != NULL) snac.config = xs_dict_set(snac.config, "metadata", v); -- cgit From cbf71ca0cabdf46a1eb595db01601858c8823acc Mon Sep 17 00:00:00 2001 From: grunfink Date: Fri, 6 Jun 2025 21:02:28 +0200 Subject: Skip incomplete attachments. --- html.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'html.c') diff --git a/html.c b/html.c index a6e5f98..d513d10 100644 --- a/html.c +++ b/html.c @@ -2427,6 +2427,9 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, const char *o_href = xs_dict_get(a, "href"); const char *name = xs_dict_get(a, "name"); + if (!xs_is_string(type) || !xs_is_string(o_href)) + continue; + /* if this URL is already in the post content, skip */ if (content && xs_str_in(content, o_href) != -1) continue; -- cgit From c9c1323e40080acbd8bffe904e8ba8fc3ff8bbd7 Mon Sep 17 00:00:00 2001 From: grunfink Date: Sat, 7 Jun 2025 06:43:58 +0200 Subject: Always show the 'pending follow confirmations' if there are any. Even if the toggle is off. --- html.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'html.c') diff --git a/html.c b/html.c index d513d10..892475c 100644 --- a/html.c +++ b/html.c @@ -3295,12 +3295,12 @@ xs_str *html_people(snac *user) xs *wing = following_list(user); xs *wers = follower_list(user); + xs *pending = pending_list(user); xs_html *lists = xs_html_tag("div", xs_html_attr("class", "snac-posts")); - if (xs_is_true(xs_dict_get(user->config, "approve_followers"))) { - xs *pending = pending_list(user); + if (xs_list_len(pending) || xs_is_true(xs_dict_get(user->config, "approve_followers"))) { xs_html_add(lists, html_people_list(user, pending, L("Pending follow confirmations"), "p", proxy)); } -- cgit From d5dbdad930d44d9345bec03d0f2ce4076cb028a8 Mon Sep 17 00:00:00 2001 From: grunfink Date: Sat, 7 Jun 2025 07:53:00 +0200 Subject: If a metadata value is an account handle, it's also verified using webfinger. --- html.c | 13 ++++++++++--- utils.c | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'html.c') diff --git a/html.c b/html.c index 892475c..f5d9aea 100644 --- a/html.c +++ b/html.c @@ -1077,10 +1077,17 @@ static xs_html *html_user_body(snac *user, int read_only) while (xs_dict_next(metadata, &k, &v, &c)) { xs_html *value; - if (xs_startswith(v, "https:/") || xs_startswith(v, "http:/")) { + if (xs_startswith(v, "https:/") || xs_startswith(v, "http:/") || *v == '@') { /* is this link validated? */ xs *verified_link = NULL; const xs_number *val_time = xs_dict_get(val_links, v); + const char *url = NULL; + + if (xs_is_string(val_time)) { + /* resolve again, as it may be an account handle */ + url = val_time; + val_time = xs_dict_get(val_links, val_time); + } if (xs_type(val_time) == XSTYPE_NUMBER) { time_t t = xs_number_get(val_time); @@ -1098,13 +1105,13 @@ static xs_html *html_user_body(snac *user, int read_only) xs_html_tag("a", xs_html_attr("rel", "me"), xs_html_attr("target", "_blank"), - xs_html_attr("href", v), + xs_html_attr("href", url ? url : v), xs_html_text(v))); } else { value = xs_html_tag("a", xs_html_attr("rel", "me"), - xs_html_attr("href", v), + xs_html_attr("href", url ? url : v), xs_html_text(v)); } } diff --git a/utils.c b/utils.c index d50707a..d8c55dc 100644 --- a/utils.c +++ b/utils.c @@ -488,6 +488,18 @@ void verify_links(snac *user) int c = 0; while (metadata && xs_dict_next(metadata, &k, &v, &c)) { + xs *wfinger = NULL; + const char *ov = NULL; + + /* is it an account handle? */ + if (*v == '@' && strchr(v + 1, '@')) { + /* resolve it via webfinger */ + if (valid_status(webfinger_request(v, &wfinger, NULL)) && xs_is_string(wfinger)) { + ov = v; + v = wfinger; + } + } + /* not an https link? skip */ if (!xs_startswith(v, "https:/" "/")) continue; @@ -563,6 +575,10 @@ void verify_links(snac *user) user->links = xs_dict_set(user->links, v, verified_time); + /* also add the original value if it was 'resolved' */ + if (xs_is_string(ov)) + user->links = xs_dict_set(user->links, ov, v); + vfied = 1; } else -- cgit From 13ffca1d029f47cc3f9fd92824d75aa1010a64db Mon Sep 17 00:00:00 2001 From: grunfink Date: Sat, 7 Jun 2025 10:05:23 +0200 Subject: Another search by URL tweak (for Pixelfed). --- html.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'html.c') diff --git a/html.c b/html.c index f5d9aea..b4588f7 100644 --- a/html.c +++ b/html.c @@ -3795,6 +3795,14 @@ int html_get_handler(const xs_dict *req, const char *q_path, timeline_add(&snac, q, object); } } + else { + /* retry webfinger, this time with the 'official' id */ + const char *id = xs_dict_get(object, "id"); + + if (xs_is_string(id) && valid_status(webfinger_request(id, &actor_obj, &url_acct)) && + xs_is_string(url_acct)) + q = url_acct; + } } } -- cgit From 0e30411f5890bfbe578a196a54ad46b72e3e49d7 Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 18 Jun 2025 09:40:10 +0200 Subject: New field 'favicon_url' in server.json. --- html.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'html.c') diff --git a/html.c b/html.c index b4588f7..c472e3b 100644 --- a/html.c +++ b/html.c @@ -636,13 +636,18 @@ static xs_html *html_base_head(void) xs_html_attr("content", USER_AGENT))); /* add server CSS and favicon */ - xs *f; - f = xs_fmt("%s/favicon.ico", srv_baseurl); + xs *f = NULL; + const char *favicon = xs_dict_get(srv_config, "favicon_url"); + + if (xs_is_string(favicon)) + f = xs_dup(favicon); + else + f = xs_fmt("%s/favicon.ico", srv_baseurl); + const xs_list *p = xs_dict_get(srv_config, "cssurls"); const char *v; - int c = 0; - while (xs_list_next(p, &v, &c)) { + xs_list_foreach(p, v) { xs_html_add(head, xs_html_sctag("link", xs_html_attr("rel", "stylesheet"), -- cgit From f88bdd796045dd206b38e07adb13b5af4489b4c5 Mon Sep 17 00:00:00 2001 From: grunfink Date: Tue, 24 Jun 2025 14:06:41 +0200 Subject: Added a webmention hook. --- html.c | 20 ++++++++++++++----- httpd.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ xs_webmention.h | 42 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 5 deletions(-) (limited to 'html.c') diff --git a/html.c b/html.c index c472e3b..672ea44 100644 --- a/html.c +++ b/html.c @@ -868,6 +868,14 @@ xs_html *html_user_head(snac *user, const char *desc, const char *url) xs_html_attr("type", "application/activity+json"), xs_html_attr("href", url ? url : user->actor))); + /* webmention hook */ + xs *wbh = xs_fmt("%s/webmention-hook", srv_baseurl); + + xs_html_add(head, + xs_html_sctag("link", + xs_html_attr("rel", "webmention"), + xs_html_attr("href", wbh))); + return head; } @@ -3407,13 +3415,15 @@ xs_str *html_notifications(snac *user, int skip, int show) const char *actor_id = xs_dict_get(noti, "actor"); xs *actor = NULL; + xs *a_name = NULL; - if (!valid_status(actor_get(actor_id, &actor))) - continue; + if (valid_status(actor_get(actor_id, &actor))) + a_name = actor_name(actor, proxy); + else + a_name = xs_dup(actor_id); - xs *a_name = actor_name(actor, proxy); - xs *label_sanatized = sanitize(type); - const char *label = label_sanatized; + xs *label_sanitized = sanitize(type); + const char *label = label_sanitized; if (strcmp(type, "Create") == 0) label = L("Mention"); diff --git a/httpd.c b/httpd.c index 15634d1..af78e09 100644 --- a/httpd.c +++ b/httpd.c @@ -12,6 +12,7 @@ #include "xs_openssl.h" #include "xs_fcgi.h" #include "xs_html.h" +#include "xs_webmention.h" #include "snac.h" @@ -373,6 +374,63 @@ int server_get_handler(xs_dict *req, const char *q_path, } +int server_post_handler(const xs_dict *req, const char *q_path, + char *payload, int p_size, + char **body, int *b_size, char **ctype) +{ + int status = 0; + + if (strcmp(q_path, "/webmention-hook") == 0) { + status = HTTP_STATUS_BAD_REQUEST; + + const xs_dict *p_vars = xs_dict_get(req, "p_vars"); + + if (!xs_is_dict(p_vars)) + return status; + + const char *source = xs_dict_get(p_vars, "source"); + const char *target = xs_dict_get(p_vars, "target"); + + if (!xs_is_string(source) || !xs_is_string(target)) { + srv_debug(1, xs_fmt("webmention-hook bad source or target")); + return status; + } + + if (!xs_startswith(target, srv_baseurl)) { + srv_debug(1, xs_fmt("webmention-hook unknown target %s", target)); + return status; + } + + if (!object_here(target)) { + srv_debug(0, xs_fmt("webmention-hook target %s not / no longer here", target)); + return status; + } + + /* get the user */ + xs *s1 = xs_replace(target, srv_baseurl, ""); + + xs *l1 = xs_split(s1, "/"); + const char *uid = xs_list_get(l1, 1); + snac user; + + if (!xs_is_string(uid) || !user_open(&user, uid)) + return status; + + int r = xs_webmention_hook(source, target, USER_AGENT); + + if (r > 0) + notify_add(&user, "Webmention", NULL, source, target, xs_stock(XSTYPE_DICT)); + + srv_log(xs_fmt("webmention-hook source=%s target=%s %d", source, target, r)); + + user_free(&user); + status = HTTP_STATUS_OK; + } + + return status; +} + + void httpd_connection(FILE *f) /* the connection processor */ { @@ -444,6 +502,10 @@ void httpd_connection(FILE *f) else if (strcmp(method, "POST") == 0) { + if (status == 0) + status = server_post_handler(req, q_path, + payload, p_size, &body, &b_size, &ctype); + #ifndef NO_MASTODON_API if (status == 0) status = oauth_post_handler(req, q_path, diff --git a/xs_webmention.h b/xs_webmention.h index 8415629..e177573 100644 --- a/xs_webmention.h +++ b/xs_webmention.h @@ -5,6 +5,7 @@ #define _XS_WEBMENTION_H int xs_webmention_send(const char *source, const char *target, const char *user_agent); +int xs_webmention_hook(const char *source, const char *target, const char *user_agent); #ifdef XS_IMPLEMENTATION @@ -118,6 +119,47 @@ int xs_webmention_send(const char *source, const char *target, const char *user_ } +int xs_webmention_hook(const char *source, const char *target, const char *user_agent) +/* a Webmention has been received for a target that is ours; check if the source + really contains a link to our target */ +{ + int status = 0; + + xs *ua = xs_fmt("%s (Webmention)", user_agent ? user_agent : "xs_webmention"); + xs *headers = xs_dict_new(); + headers = xs_dict_set(headers, "accept", "text/html"); + headers = xs_dict_set(headers, "user-agent", ua); + + xs *g_req = NULL; + xs *payload = NULL; + int p_size = 0; + + g_req = xs_http_request("GET", source, headers, NULL, 0, &status, &payload, &p_size, 0); + + if (status < 200 || status > 299) + return -1; + + if (!xs_is_string(payload)) + return -2; + + /* note: a "rogue" webmention can include a link to our target in commented-out HTML code */ + + xs *links = xs_regex_select(payload, "<(a +|link +)[^>]+>"); + const char *link; + + status = 0; + xs_list_foreach(links, link) { + /* if the link contains our target, it's valid */ + if (xs_str_in(link, target) != -1) { + status = 1; + break; + } + } + + return status; +} + + #endif /* XS_IMPLEMENTATION */ #endif /* _XS_WEBMENTION_H */ -- cgit From 9403fb41effc6da7a997898b07b6c6b46f8e2ba1 Mon Sep 17 00:00:00 2001 From: grunfink Date: Tue, 24 Jun 2025 14:34:55 +0200 Subject: More webmention hook tweaks. --- html.c | 7 +++++++ httpd.c | 13 ++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'html.c') diff --git a/html.c b/html.c index 672ea44..aeecdf5 100644 --- a/html.c +++ b/html.c @@ -3531,6 +3531,13 @@ xs_str *html_notifications(snac *user, int skip, int show) xs_html_text(L("Context")))), h); } + else + xs_html_add(entry, + xs_html_tag("p", + xs_html_text(L("Location: ")), + xs_html_tag("a", + xs_html_attr("href", id), + xs_html_text(id)))); } if (strcmp(v, n_time) > 0) { diff --git a/httpd.c b/httpd.c index 9216bdc..8f2ef4d 100644 --- a/httpd.c +++ b/httpd.c @@ -407,11 +407,6 @@ int server_post_handler(const xs_dict *req, const char *q_path, return status; } - if (!object_here(target)) { - srv_debug(0, xs_fmt("webmention-hook target %s not / no longer here", target)); - return status; - } - /* get the user */ xs *s1 = xs_replace(target, srv_baseurl, ""); @@ -419,13 +414,17 @@ int server_post_handler(const xs_dict *req, const char *q_path, const char *uid = xs_list_get(l1, 1); snac user; - if (!xs_is_string(uid) || !user_open(&user, uid)) + if (!xs_is_string(uid) || !user_open(&user, uid)) { + srv_debug(1, xs_fmt("webmention-hook cannot find user for %s", target)); return status; + } int r = xs_webmention_hook(source, target, USER_AGENT); - if (r > 0) + if (r > 0) { notify_add(&user, "Webmention", NULL, source, target, xs_stock(XSTYPE_DICT)); + timeline_touch(&user); + } srv_log(xs_fmt("webmention-hook source=%s target=%s %d", source, target, r)); -- cgit From 5d680a5ba227c5275624fbeefe0cce05cfb60ee6 Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 25 Jun 2025 12:47:07 +0200 Subject: Fixed crash. --- html.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'html.c') diff --git a/html.c b/html.c index aeecdf5..b482d10 100644 --- a/html.c +++ b/html.c @@ -3495,10 +3495,11 @@ xs_str *html_notifications(snac *user, int skip, int show) html_label); if (strcmp(type, "Follow") == 0 || strcmp(utype, "Follow") == 0 || strcmp(type, "Block") == 0) { - xs_html_add(entry, - xs_html_tag("div", - xs_html_attr("class", "snac-post"), - html_actor_icon(user, actor, NULL, NULL, NULL, 0, 0, proxy, NULL, NULL))); + if (actor) + xs_html_add(entry, + xs_html_tag("div", + xs_html_attr("class", "snac-post"), + html_actor_icon(user, actor, NULL, NULL, NULL, 0, 0, proxy, NULL, NULL))); } else if (strcmp(type, "Move") == 0) { -- cgit From a5ce94c824b0705da068420ca58e81bda7f8bef3 Mon Sep 17 00:00:00 2001 From: grunfink Date: Fri, 27 Jun 2025 15:24:27 +0200 Subject: Added an actor refresh in html_entry(). --- html.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'html.c') diff --git a/html.c b/html.c index b482d10..7d748f9 100644 --- a/html.c +++ b/html.c @@ -2008,8 +2008,13 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, } if ((user == NULL || strcmp(actor, user->actor) != 0) - && !valid_status(actor_get(actor, NULL))) + && !valid_status(actor_get(actor, NULL))) { + + if (user) + enqueue_actor_refresh(user, actor, 0); + return NULL; + } /** html_entry top tag **/ xs_html *entry_top = xs_html_tag("div", NULL); -- cgit