commit 97ff661
grunfink
·
2025-05-28 05:48:47 +0000 UTC
parent 859de58
New file rss.c.
5 files changed,
+118,
-107
M
Makefile
+5,
-4
1@@ -5,7 +5,7 @@ CFLAGS?=-g -Wall -Wextra -pedantic
2 all: snac
3
4 snac: snac.o main.o sandbox.o data.o http.o httpd.o webfinger.o \
5- activitypub.o html.o utils.o format.o upgrade.o mastoapi.o
6+ activitypub.o html.o utils.o format.o upgrade.o mastoapi.o rss.o
7 $(CC) $(CFLAGS) -L$(PREFIX)/lib *.o -lcurl -lcrypto $(LDFLAGS) -pthread -o $@
8
9 test: tests/smtp
10@@ -48,12 +48,12 @@ update-po:
11
12 activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \
13 xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \
14- snac.h http_codes.h
15+ xs_webmention.h snac.h http_codes.h
16 data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \
17 xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h xs_random.h \
18 xs_po.h snac.h http_codes.h
19 format.o: format.c xs.h xs_regex.h xs_mime.h xs_html.h xs_json.h \
20- xs_time.h xs_match.h snac.h http_codes.h
21+ xs_time.h xs_match.h xs_unicode.h snac.h http_codes.h
22 html.o: html.c xs.h xs_io.h xs_json.h xs_regex.h xs_set.h xs_openssl.h \
23 xs_time.h xs_mime.h xs_match.h xs_html.h xs_curl.h xs_unicode.h xs_url.h \
24 xs_random.h snac.h http_codes.h
25@@ -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 \
26 snac.h http_codes.h
27 mastoapi.o: mastoapi.c xs.h xs_hex.h xs_openssl.h xs_json.h xs_io.h \
28 xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \
29- snac.h http_codes.h
30+ xs_unicode.h snac.h http_codes.h
31+rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h snac.h http_codes.h
32 sandbox.o: sandbox.c xs.h snac.h http_codes.h
33 snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \
34 xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \
+5,
-4
1@@ -6,7 +6,7 @@ LDFLAGS=-lrt
2 all: snac
3
4 snac: snac.o main.o sandbox.o data.o http.o httpd.o webfinger.o \
5- activitypub.o html.o utils.o format.o upgrade.o mastoapi.o
6+ activitypub.o html.o utils.o format.o upgrade.o mastoapi.o rss.o
7 $(CC) $(CFLAGS) -L/usr/pkg/lib *.o -lcurl -lcrypto -pthread $(LDFLAGS) -Wl,-rpath,/usr/lib -Wl,-rpath,/usr/pkg/lib -o $@
8
9
10@@ -37,12 +37,12 @@ uninstall:
11
12 activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \
13 xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \
14- snac.h http_codes.h
15+ xs_webmention.h snac.h http_codes.h
16 data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \
17 xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h xs_random.h \
18 xs_po.h snac.h http_codes.h
19 format.o: format.c xs.h xs_regex.h xs_mime.h xs_html.h xs_json.h \
20- xs_time.h xs_match.h snac.h http_codes.h
21+ xs_time.h xs_match.h xs_unicode.h snac.h http_codes.h
22 html.o: html.c xs.h xs_io.h xs_json.h xs_regex.h xs_set.h xs_openssl.h \
23 xs_time.h xs_mime.h xs_match.h xs_html.h xs_curl.h xs_unicode.h xs_url.h \
24 xs_random.h snac.h http_codes.h
25@@ -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 \
26 snac.h http_codes.h
27 mastoapi.o: mastoapi.c xs.h xs_hex.h xs_openssl.h xs_json.h xs_io.h \
28 xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \
29- snac.h http_codes.h
30+ xs_unicode.h snac.h http_codes.h
31+rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h snac.h http_codes.h
32 sandbox.o: sandbox.c xs.h snac.h http_codes.h
33 snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \
34 xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \
M
html.c
+0,
-97
1@@ -5020,100 +5020,3 @@ int html_post_handler(const xs_dict *req, const char *q_path,
2
3 return status;
4 }
5-
6-
7-xs_str *rss_from_timeline(snac *user, const xs_list *timeline,
8- const char *title, const char *link, const char *desc)
9-/* converts a timeline to rss */
10-{
11- xs_html *rss = xs_html_tag("rss",
12- xs_html_attr("xmlns:content", "http:/" "/purl.org/rss/1.0/modules/content/"),
13- xs_html_attr("version", "2.0"),
14- xs_html_attr("xmlns:atom", "http:/" "/www.w3.org/2005/Atom"));
15-
16- xs_html *channel = xs_html_tag("channel",
17- xs_html_tag("title",
18- xs_html_text(title)),
19- xs_html_tag("language",
20- xs_html_text("en")),
21- xs_html_tag("link",
22- xs_html_text(link)),
23- xs_html_sctag("atom:link",
24- xs_html_attr("href", link),
25- xs_html_attr("rel", "self"),
26- xs_html_attr("type", "application/rss+xml")),
27- xs_html_tag("generator",
28- xs_html_text(USER_AGENT)),
29- xs_html_tag("description",
30- xs_html_text(desc)));
31-
32- xs_html_add(rss, channel);
33-
34- int cnt = 0;
35- const char *v;
36-
37- xs_list_foreach(timeline, v) {
38- xs *msg = NULL;
39-
40- if (user) {
41- if (!valid_status(timeline_get_by_md5(user, v, &msg)))
42- continue;
43- }
44- else {
45- if (!valid_status(object_get_by_md5(v, &msg)))
46- continue;
47- }
48-
49- const char *id = xs_dict_get(msg, "id");
50- const char *content = xs_dict_get(msg, "content");
51- const char *published = xs_dict_get(msg, "published");
52-
53- if (user && !xs_startswith(id, user->actor))
54- continue;
55-
56- if (!id || !content || !published)
57- continue;
58-
59- /* create a title with the first line of the content */
60- xs *title = xs_replace(content, "<br>", "\n");
61- title = xs_regex_replace_i(title, "<[^>]+>", " ");
62- title = xs_regex_replace_i(title, "&[^;]+;", " ");
63- int i;
64-
65- for (i = 0; title[i] && title[i] != '\n' && i < 50; i++);
66-
67- if (title[i] != '\0') {
68- title[i] = '\0';
69- title = xs_str_cat(title, "...");
70- }
71-
72- title = xs_strip_i(title);
73-
74- /* convert the date */
75- time_t t = xs_parse_iso_date(published, 0);
76- xs *rss_date = xs_str_utctime(t, "%a, %d %b %Y %T +0000");
77-
78- /* if it's the first one, add it to the header */
79- if (cnt == 0)
80- xs_html_add(channel,
81- xs_html_tag("lastBuildDate",
82- xs_html_text(rss_date)));
83-
84- xs_html_add(channel,
85- xs_html_tag("item",
86- xs_html_tag("title",
87- xs_html_text(title)),
88- xs_html_tag("link",
89- xs_html_text(id)),
90- xs_html_tag("guid",
91- xs_html_text(id)),
92- xs_html_tag("pubDate",
93- xs_html_text(rss_date)),
94- xs_html_tag("description",
95- xs_html_text(content))));
96-
97- cnt++;
98- }
99-
100- return xs_html_render_s(rss, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
101-}
A
rss.c
+105,
-0
1@@ -0,0 +1,105 @@
2+/* snac - A simple, minimalistic ActivityPub instance */
3+/* copyright (c) 2025 grunfink et al. / MIT license */
4+
5+#include "xs.h"
6+#include "xs_html.h"
7+#include "xs_regex.h"
8+#include "xs_time.h"
9+
10+#include "snac.h"
11+
12+xs_str *rss_from_timeline(snac *user, const xs_list *timeline,
13+ const char *title, const char *link, const char *desc)
14+/* converts a timeline to rss */
15+{
16+ xs_html *rss = xs_html_tag("rss",
17+ xs_html_attr("xmlns:content", "http:/" "/purl.org/rss/1.0/modules/content/"),
18+ xs_html_attr("version", "2.0"),
19+ xs_html_attr("xmlns:atom", "http:/" "/www.w3.org/2005/Atom"));
20+
21+ xs_html *channel = xs_html_tag("channel",
22+ xs_html_tag("title",
23+ xs_html_text(title)),
24+ xs_html_tag("language",
25+ xs_html_text("en")),
26+ xs_html_tag("link",
27+ xs_html_text(link)),
28+ xs_html_sctag("atom:link",
29+ xs_html_attr("href", link),
30+ xs_html_attr("rel", "self"),
31+ xs_html_attr("type", "application/rss+xml")),
32+ xs_html_tag("generator",
33+ xs_html_text(USER_AGENT)),
34+ xs_html_tag("description",
35+ xs_html_text(desc)));
36+
37+ xs_html_add(rss, channel);
38+
39+ int cnt = 0;
40+ const char *v;
41+
42+ xs_list_foreach(timeline, v) {
43+ xs *msg = NULL;
44+
45+ if (user) {
46+ if (!valid_status(timeline_get_by_md5(user, v, &msg)))
47+ continue;
48+ }
49+ else {
50+ if (!valid_status(object_get_by_md5(v, &msg)))
51+ continue;
52+ }
53+
54+ const char *id = xs_dict_get(msg, "id");
55+ const char *content = xs_dict_get(msg, "content");
56+ const char *published = xs_dict_get(msg, "published");
57+
58+ if (user && !xs_startswith(id, user->actor))
59+ continue;
60+
61+ if (!id || !content || !published)
62+ continue;
63+
64+ /* create a title with the first line of the content */
65+ xs *title = xs_replace(content, "<br>", "\n");
66+ title = xs_regex_replace_i(title, "<[^>]+>", " ");
67+ title = xs_regex_replace_i(title, "&[^;]+;", " ");
68+ int i;
69+
70+ for (i = 0; title[i] && title[i] != '\n' && i < 50; i++);
71+
72+ if (title[i] != '\0') {
73+ title[i] = '\0';
74+ title = xs_str_cat(title, "...");
75+ }
76+
77+ title = xs_strip_i(title);
78+
79+ /* convert the date */
80+ time_t t = xs_parse_iso_date(published, 0);
81+ xs *rss_date = xs_str_utctime(t, "%a, %d %b %Y %T +0000");
82+
83+ /* if it's the first one, add it to the header */
84+ if (cnt == 0)
85+ xs_html_add(channel,
86+ xs_html_tag("lastBuildDate",
87+ xs_html_text(rss_date)));
88+
89+ xs_html_add(channel,
90+ xs_html_tag("item",
91+ xs_html_tag("title",
92+ xs_html_text(title)),
93+ xs_html_tag("link",
94+ xs_html_text(id)),
95+ xs_html_tag("guid",
96+ xs_html_text(id)),
97+ xs_html_tag("pubDate",
98+ xs_html_text(rss_date)),
99+ xs_html_tag("description",
100+ xs_html_text(content))));
101+
102+ cnt++;
103+ }
104+
105+ return xs_html_render_s(rss, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
106+}
M
snac.h
+3,
-2
1@@ -395,8 +395,6 @@ int html_get_handler(const xs_dict *req, const char *q_path,
2 int html_post_handler(const xs_dict *req, const char *q_path,
3 char *payload, int p_size,
4 char **body, int *b_size, char **ctype);
5-xs_str *rss_from_timeline(snac *user, const xs_list *timeline,
6- const char *title, const char *link, const char *desc);
7
8 int write_default_css(void);
9 int snac_init(const char *_basedir);
10@@ -462,3 +460,6 @@ int badlogin_check(const char *user, const char *addr);
11 void badlogin_inc(const char *user, const char *addr);
12
13 const char *lang_str(const char *str, const snac *user);
14+
15+xs_str *rss_from_timeline(snac *user, const xs_list *timeline,
16+ const char *title, const char *link, const char *desc);