summaryrefslogtreecommitdiff
path: root/rss.c
diff options
context:
space:
mode:
authorGravatar grunfink2025-05-28 07:56:44 +0200
committerGravatar grunfink2025-05-28 07:56:44 +0200
commitb783f287c8b3e77bbd1eb94892ea645ba05e8770 (patch)
treea80f8cf79f21159606ee5fb1c7fbf46e6da0a884 /rss.c
parentNew file rss.c. (diff)
downloadsnac2-b783f287c8b3e77bbd1eb94892ea645ba05e8770.tar.gz
snac2-b783f287c8b3e77bbd1eb94892ea645ba05e8770.tar.xz
snac2-b783f287c8b3e77bbd1eb94892ea645ba05e8770.zip
New function rss_to_timeline().
Diffstat (limited to 'rss.c')
-rw-r--r--rss.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/rss.c b/rss.c
index 61620fa..a3a092e 100644
--- a/rss.c
+++ b/rss.c
@@ -5,6 +5,8 @@
5#include "xs_html.h" 5#include "xs_html.h"
6#include "xs_regex.h" 6#include "xs_regex.h"
7#include "xs_time.h" 7#include "xs_time.h"
8#include "xs_match.h"
9#include "xs_curl.h"
8 10
9#include "snac.h" 11#include "snac.h"
10 12
@@ -103,3 +105,125 @@ xs_str *rss_from_timeline(snac *user, const xs_list *timeline,
103 105
104 return xs_html_render_s(rss, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 106 return xs_html_render_s(rss, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
105} 107}
108
109
110void rss_to_timeline(snac *user, const char *url)
111/* reads an RSS and inserts all ActivityPub posts into the user's timeline */
112{
113 xs *hdrs = xs_dict_new();
114 hdrs = xs_dict_set(hdrs, "accept", "application/rss+xml");
115 hdrs = xs_dict_set(hdrs, "user-agent", USER_AGENT);
116
117 xs *payload = NULL;
118 int status;
119 int p_size;
120
121 xs *rsp = xs_http_request("GET", url, hdrs, NULL, 0, &status, &payload, &p_size, 0);
122
123 if (!valid_status(status) || !xs_is_string(payload))
124 return;
125
126 /* not an RSS? done */
127 const char *ctype = xs_dict_get(rsp, "content-type");
128 if (!xs_is_string(ctype) || xs_str_in(ctype, "application/rss+xml") == -1)
129 return;
130
131 snac_log(user, xs_fmt("parsing RSS %s", url));
132
133 /* yes, parsing is done with regexes (now I have two problems blah blah blah) */
134 xs *links = xs_regex_select(payload, "<link>[^<]+</link>");
135 const char *link;
136
137 xs_list_foreach(links, link) {
138 xs *l = xs_replace(link, "<link>", "");
139 char *p = strchr(l, '<');
140
141 if (p == NULL)
142 continue;
143 *p = '\0';
144
145 /* skip this same URL */
146 if (strcmp(l, url) == 0)
147 continue;
148
149 snac_debug(user, 1, xs_fmt("RSS link: %s", l));
150
151 if (timeline_here(user, l)) {
152 snac_debug(user, 1, xs_fmt("RSS entry already in timeline %s", l));
153 continue;
154 }
155
156 /* special trick for Mastodon: convert from the alternate format */
157 if (strchr(l, '@') != NULL) {
158 xs *l2 = xs_split(l, "/");
159
160 if (xs_list_len(l2) == 5) {
161 const char *uid = xs_list_get(l2, 3);
162 if (*uid == '@') {
163 xs *guessed_id = xs_fmt("https:/" "/%s/users/%s/statuses/%s",
164 xs_list_get(l2, 2), uid + 1, xs_list_get(l2, -1));
165
166 if (timeline_here(user, guessed_id)) {
167 snac_debug(user, 1, xs_fmt("RSS entry already in timeline (alt) %s", guessed_id));
168 continue;
169 }
170 }
171 }
172 }
173
174 xs *obj = NULL;
175
176 if (!valid_status(object_get(l, &obj))) {
177 /* object is not here: bring it */
178 if (!valid_status(activitypub_request(user, l, &obj)))
179 continue;
180 }
181
182 if (xs_is_dict(obj)) {
183 const char *id = xs_dict_get(obj, "id");
184 const char *type = xs_dict_get(obj, "type");
185 const char *attr_to = get_atto(obj);
186
187 if (!xs_is_string(id) || !xs_is_string(type) || !xs_is_string(attr_to))
188 continue;
189
190 if (!xs_match(type, POSTLIKE_OBJECT_TYPE))
191 continue;
192
193 if (timeline_here(user, id)) {
194 snac_debug(user, 1, xs_fmt("RSS entry already in timeline (id) %s", id));
195 continue;
196 }
197
198 if (!valid_status(actor_request(user, attr_to, NULL)))
199 continue;
200
201 timeline_add(user, id, obj);
202 }
203 }
204}
205
206
207void rss_process(void)
208/* parses all RSS from all users */
209{
210 xs *list = user_list();
211 const char *uid;
212
213 xs_list_foreach(list, uid) {
214 snac user;
215
216 if (user_open(&user, uid)) {
217 const xs_list *rss = xs_dict_get(user.config, "rss");
218
219 if (xs_is_list(rss)) {
220 const char *url;
221
222 xs_list_foreach(rss, url)
223 rss_to_timeline(&user, url);
224 }
225
226 user_free(&user);
227 }
228 }
229}