snac2

Fork of https://codeberg.org/grunfink/snac2
git clone https://git.inz.fi/snac2
Log | Files | Refs | README | LICENSE

commit 67431130162b1027cc3894f947be309b2daa3cd3
parent 972783fcb2d7855847f0ea0832da2abc71aa6b30
Author: shtrophic <christoph@liebender.dev>
Date:   Tue, 19 Nov 2024 21:40:18 +0100

Merge remote-tracking branch 'upstream/master'

Diffstat:
MTODO.md | 14++++++++++----
Mactivitypub.c | 20++++++++++++++++----
Mdata.c | 2+-
Mdoc/snac.5 | 2++
Mhtml.c | 4++--
Mhttpd.c | 14++++++++++++++
Mmain.c | 6+++++-
Mmastoapi.c | 24++++++++++++++++++------
Msnac.h | 1+
9 files changed, 69 insertions(+), 18 deletions(-)

diff --git a/TODO.md b/TODO.md @@ -16,10 +16,6 @@ Important: deleting a follower should do more that just delete the object, see h ## Wishlist -Implement Proxying for Media Links to Enhance User Privacy (see https://codeberg.org/grunfink/snac2/issues/219 for more information). - -Consider showing only posts by the account owner (not full trees) (see https://codeberg.org/grunfink/snac2/issues/217 for more information). - Add support for subscribing and posting to relays (see https://codeberg.org/grunfink/snac2/issues/216 for more information). The instance timeline should also show boosts from users. @@ -357,3 +353,13 @@ Fix a crash when posting from the links browser (2.63, 2024-11-08T15:57:25+0100) Fix some repeated images in Lemmy posts (2.63, 2024-11-08T15:57:25+0100). Fix a crash when posting an image from the tooot mobile app (2.63, 2024-11-11T19:42:11+0100). + +Fix some URL proxying (2.64, 2024-11-16T07:26:23+0100). + +Allow underscores in hashtags (2.64, 2024-11-16T07:26:23+0100). + +Add a pidfile (2.64, 2024-11-17T10:21:29+0100). + +Implement Proxying for Media Links to Enhance User Privacy (see https://codeberg.org/grunfink/snac2/issues/219 for more information) (2024-11-18T20:36:39+0100). + +Consider showing only posts by the account owner (not full trees) (see https://codeberg.org/grunfink/snac2/issues/217 for more information) (2024-11-18T20:36:39+0100). diff --git a/activitypub.c b/activitypub.c @@ -183,6 +183,18 @@ const char *get_atto(const xs_dict *msg) } +const char *get_in_reply_to(const xs_dict *msg) +/* gets the inReplyTo id */ +{ + const xs_val *in_reply_to = xs_dict_get(msg, "inReplyTo"); + + if (xs_type(in_reply_to) == XSTYPE_DICT) + in_reply_to = xs_dict_get(in_reply_to, "id"); + + return in_reply_to; +} + + xs_list *get_attachments(const xs_dict *msg) /* unify the garbage fire that are the attachments */ { @@ -373,7 +385,7 @@ int timeline_request(snac *snac, const char **id, xs_str **wrk, int level) } /* does it have an ancestor? */ - const char *in_reply_to = xs_dict_get(object, "inReplyTo"); + const char *in_reply_to = get_in_reply_to(object); /* store */ timeline_add(snac, nid, object); @@ -671,7 +683,7 @@ int is_msg_for_me(snac *snac, const xs_dict *c_msg) return 3; /* is this message a reply to another? */ - const char *irt = xs_dict_get(msg, "inReplyTo"); + const char *irt = get_in_reply_to(msg); if (!xs_is_null(irt)) { xs *r_msg = NULL; @@ -724,7 +736,7 @@ xs_str *process_tags(snac *snac, const char *content, xs_list **tag) /* use this same server */ def_srv = xs_dup(xs_dict_get(srv_config, "host")); - split = xs_regex_split(content, "(@[A-Za-z0-9_]+(@[A-Za-z0-9\\.-]+)?|&#[0-9]+;|#[^[:punct:][:space:]]+)"); + split = xs_regex_split(content, "(@[A-Za-z0-9_]+(@[A-Za-z0-9\\.-]+)?|&#[0-9]+;|#(_|[^[:punct:][:space:]])+)"); p = split; while (xs_list_iter(&p, &v)) { @@ -1957,7 +1969,7 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) if (xs_match(utype, "Note|Article")) { /** **/ const char *id = xs_dict_get(object, "id"); - const char *in_reply_to = xs_dict_get(object, "inReplyTo"); + const char *in_reply_to = get_in_reply_to(object); const char *atto = get_atto(object); xs *wrk = NULL; diff --git a/data.c b/data.c @@ -762,7 +762,7 @@ int _object_add(const char *id, const xs_dict *obj, int ow) fclose(f); /* does this object has a parent? */ - const char *in_reply_to = xs_dict_get(obj, "inReplyTo"); + const char *in_reply_to = get_in_reply_to(obj); if (!xs_is_null(in_reply_to) && *in_reply_to) { /* update the children index of the parent */ diff --git a/doc/snac.5 b/doc/snac.5 @@ -209,6 +209,8 @@ web interface. .It Pa history/ This directory contains generated HTML files. They may be snapshots of the local timeline in previous months or other cached data. +.It Pa server.pid +This file stores the server PID in a single text line. .El .Sh SEE ALSO .Xr snac 1 , diff --git a/html.c b/html.c @@ -1670,7 +1670,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, if (strcmp(type, "Note") == 0) { if (level == 0) { /* is the parent not here? */ - const char *parent = xs_dict_get(msg, "inReplyTo"); + const char *parent = get_in_reply_to(msg); if (user && !xs_is_null(parent) && *parent && !timeline_here(user, parent)) { xs_html_add(post_header, @@ -2329,7 +2329,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, /* is this message a non-public reply? */ if (user != NULL && !is_msg_public(msg)) { - const char *irt = xs_dict_get(msg, "inReplyTo"); + const char *irt = get_in_reply_to(msg); /* is it a reply to something not in the storage? */ if (!xs_is_null(irt) && !object_here(irt)) { diff --git a/httpd.c b/httpd.c @@ -774,6 +774,7 @@ void httpd(void) xs *sem_name = NULL; xs *shm_name = NULL; sem_t anon_job_sem; + xs *pidfile = xs_fmt("%s/server.pid", srv_basedir); address = xs_dict_get(srv_config, "address"); @@ -809,6 +810,17 @@ void httpd(void) srv_log(xs_fmt("httpd%s start %s %s", p_state->use_fcgi ? " (FastCGI)" : "", full_address, USER_AGENT)); + { + FILE *f; + + if ((f = fopen(pidfile, "w")) != NULL) { + fprintf(f, "%d\n", getpid()); + fclose(f); + } + else + srv_log(xs_fmt("Cannot create %s: %s", pidfile, strerror(errno))); + } + /* show the number of usable file descriptors */ struct rlimit r; getrlimit(RLIMIT_NOFILE, &r); @@ -894,4 +906,6 @@ void httpd(void) srv_log(xs_fmt("httpd%s stop %s (run time: %s)", p_state->use_fcgi ? " (FastCGI)" : "", full_address, uptime)); + + unlink(pidfile); } diff --git a/main.c b/main.c @@ -558,7 +558,11 @@ int main(int argc, char *argv[]) if (data != NULL) { xs_json_dump(data, 4, stdout); enqueue_actor_refresh(&snac, xs_dict_get(data, "attributedTo"), 0); - timeline_add(&snac, url, data); + + if (!timeline_here(&snac, url)) + timeline_add(&snac, url, data); + else + printf("Post %s already here\n", url); } return 0; diff --git a/mastoapi.c b/mastoapi.c @@ -171,7 +171,7 @@ const char *login_page = "" "<body><h1>%s OAuth identify</h1>\n" "<div style=\"background-color: red; color: white\">%s</div>\n" "<form method=\"post\" action=\"%s:/" "/%s/%s\">\n" -"<p>Login: <input type=\"text\" name=\"login\"></p>\n" +"<p>Login: <input type=\"text\" name=\"login\" autocapitalize=\"off\"></p>\n" "<p>Password: <input type=\"password\" name=\"passwd\"></p>\n" "<input type=\"hidden\" name=\"redir\" value=\"%s\">\n" "<input type=\"hidden\" name=\"cid\" value=\"%s\">\n" @@ -1024,7 +1024,7 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) st = xs_dict_append(st, "in_reply_to_id", xs_stock(XSTYPE_NULL)); st = xs_dict_append(st, "in_reply_to_account_id", xs_stock(XSTYPE_NULL)); - tmp = xs_dict_get(msg, "inReplyTo"); + tmp = get_in_reply_to(msg); if (!xs_is_null(tmp)) { xs *irto = NULL; @@ -1727,11 +1727,11 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (logged_in) { xs *l = notify_list(&snac1, 0, 64); xs *out = xs_list_new(); - xs_list *p = l; const xs_dict *v; const xs_list *excl = xs_dict_get(args, "exclude_types[]"); + const char *max_id = xs_dict_get(args, "max_id"); - while (xs_list_iter(&p, &v)) { + xs_list_foreach(l, v) { xs *noti = notify_get(&snac1, v); if (noti == NULL) @@ -1740,6 +1740,8 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, const char *type = xs_dict_get(noti, "type"); const char *utype = xs_dict_get(noti, "utype"); const char *objid = xs_dict_get(noti, "objid"); + const char *id = xs_dict_get(noti, "id"); + xs *fid = xs_replace(id, ".", ""); xs *actor = NULL; xs *entry = NULL; @@ -1752,6 +1754,13 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (is_hidden(&snac1, objid)) continue; + if (max_id) { + if (strcmp(fid, max_id) == 0) + max_id = NULL; + + continue; + } + /* convert the type */ if (strcmp(type, "Like") == 0 || strcmp(type, "EmojiReact") == 0) type = "favourite"; @@ -1778,12 +1787,15 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, mn = xs_dict_append(mn, "type", type); - xs *id = xs_replace(xs_dict_get(noti, "id"), ".", ""); - mn = xs_dict_append(mn, "id", id); + mn = xs_dict_append(mn, "id", fid); mn = xs_dict_append(mn, "created_at", xs_dict_get(noti, "date")); xs *acct = mastoapi_account(&snac1, actor); + + if (acct == NULL) + continue; + mn = xs_dict_append(mn, "account", acct); if (strcmp(type, "follow") != 0 && !xs_is_null(objid)) { diff --git a/snac.h b/snac.h @@ -298,6 +298,7 @@ const char *default_avatar_base64(void); xs_str *process_tags(snac *snac, const char *content, xs_list **tag); const char *get_atto(const xs_dict *msg); +const char *get_in_reply_to(const xs_dict *msg); xs_list *get_attachments(const xs_dict *msg); xs_dict *msg_admiration(snac *snac, const char *object, const char *type);