aboutsummaryrefslogtreecommitdiff
path: root/html.c
diff options
context:
space:
mode:
Diffstat (limited to 'html.c')
-rw-r--r--html.c164
1 files changed, 123 insertions, 41 deletions
diff --git a/html.c b/html.c
index 4484fc2..a12b47e 100644
--- a/html.c
+++ b/html.c
@@ -321,13 +321,11 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date,
name_link);
if (!xs_is_null(url)) {
- xs *md5 = xs_md5_hex(url, strlen(url));
-
xs_html_add(actor_icon,
xs_html_text(" "),
xs_html_tag("a",
xs_html_attr("href", (char *)url),
- xs_html_attr("title", md5),
+ xs_html_attr("title", xs_is_string(md5) ? md5 : ""),
xs_html_text("ยป")));
}
@@ -347,6 +345,14 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date,
xs_html_attr("title", "mutual relation"),
xs_html_raw("🤝")));
}
+ else
+ if (fwer) {
+ xs_html_add(actor_icon,
+ xs_html_text(" "),
+ xs_html_tag("span",
+ xs_html_attr("title", "follows you"),
+ xs_html_raw("👍")));
+ }
if (instance_failure(actor_id, 0) == -1) {
xs_html_add(actor_icon,
@@ -1634,6 +1640,7 @@ xs_html *html_top_controls(snac *user)
const char *longitude = xs_dict_get_def(user->config, "longitude", "");
const char *webhook = xs_dict_get_def(user->config, "notify_webhook", "");
const char *post_langs = xs_dict_get_def(user->config, "post_langs", "");
+ const char *excluded_langs = xs_dict_get_def(user->config, "excluded_langs", "");
xs *metadata = NULL;
const xs_dict *md = xs_dict_get(user->config, "metadata");
@@ -1872,6 +1879,15 @@ xs_html *html_top_controls(snac *user)
xs_html_attr("placeholder", L("en fr es de_AT")))),
xs_html_tag("p",
+ xs_html_text(L("Don't show posts written in these languages:")),
+ xs_html_sctag("br", NULL),
+ xs_html_sctag("input",
+ xs_html_attr("type", "text"),
+ xs_html_attr("name", "excluded_langs"),
+ xs_html_attr("value", excluded_langs),
+ xs_html_attr("placeholder", L("en fr es de_AT")))),
+
+ xs_html_tag("p",
xs_html_text(L("New password:")),
xs_html_sctag("br", NULL),
xs_html_sctag("input",
@@ -2056,6 +2072,27 @@ xs_str *build_mentions(snac *user, const xs_dict *msg)
}
}
+ /* also add the author of this post as a mention */
+ const char *atto = get_atto(msg);
+
+ if (xs_is_string(atto) && *atto && strcmp(atto, user->actor) != 0) {
+ /* check if this author is already in the mentions string */
+ xs *l = xs_split(atto, "/");
+
+ if (xs_list_len(l) > 3) {
+ xs *actor_o = NULL;
+ if (valid_status(object_get(atto, &actor_o))) {
+ const char *uname = xs_dict_get(actor_o, "preferredUsername");
+ if (!xs_is_null(uname) && *uname) {
+ xs *handle = xs_fmt("@%s@%s ", uname, xs_list_get(l, 2));
+ if (xs_str_in(s, handle) == -1) {
+ s = xs_str_cat(s, handle);
+ }
+ }
+ }
+ }
+ }
+
if (*s) {
xs *s1 = s;
s = xs_fmt("\n\n\nCC: %s", s1);
@@ -2339,6 +2376,17 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only,
int c = 0;
xs_dict_next(cmap, &lang, &dummy, &c);
+
+ if (user && xs_is_string(lang)) {
+ /* discard posts in excluded languages */
+ const char *excluded_langs = xs_dict_get(user->config, "excluded_langs");
+
+ if (xs_is_string(excluded_langs) &&
+ xs_str_in(excluded_langs, lang) != -1) {
+ snac_debug(user, 1, xs_fmt("excluded post in language '%s'", lang));
+ return NULL;
+ }
+ }
}
if (strcmp(type, "Follow") == 0) {
@@ -2837,7 +2885,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only,
/* quoted post */
const char *quoted_id = xs_or(xs_dict_get(msg, "quoteUri"), xs_dict_get(msg, "quoteUrl"));
- if (xs_is_string(quoted_id) && xs_match(quoted_id, "https://*|http://*")) { /** **/
+ if (level < 3 && xs_is_string(quoted_id) && xs_match(quoted_id, "https://*|http://*")) { /** **/
xs *quoted_post = NULL;
if (valid_status(object_get(quoted_id, &quoted_post))) {
@@ -3447,7 +3495,6 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
int utl, const char *error, int terse)
/* returns the HTML for the timeline */
{
- xs_list *p = (xs_list *)list;
const char *v;
double t = ftime();
int hide_children = xs_is_true(xs_dict_get(srv_config, "strict_public_timelines")) && read_only;
@@ -3543,6 +3590,18 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
{
/* show the list of bookmarked posts */
+ xs *url = xs_fmt("%s/admirations", user->actor);
+ xs_html_add(lol,
+ xs_html_tag("li",
+ xs_html_tag("a",
+ xs_html_attr("href", url),
+ xs_html_attr("class", "snac-list-link"),
+ xs_html_attr("title", L("Liked, boosted or reacted posts")),
+ xs_html_text(L("admirations")))));
+ }
+
+ {
+ /* show the list of bookmarked posts */
xs *url = xs_fmt("%s/bookmarks", user->actor);
xs_html_add(lol,
xs_html_tag("li",
@@ -3627,7 +3686,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only,
int show_unlisted = user ? xs_is_true(xs_dict_get(user->config, "show_unlisted")) : 0;
- while (xs_list_iter(&p, &v)) {
+ xs_list_foreach(list, v) {
xs *msg = NULL;
int status;
@@ -4790,54 +4849,52 @@ int html_get_handler(const xs_dict *req, const char *q_path,
/* searching for an URL? */
if (q && xs_match(q, "https://*|http://*")) {
- /* may by an actor; try a webfinger */
+ /* bring it to the user's timeline */
xs *actor_obj = NULL;
+ xs *object = NULL;
+ int status;
- 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;
- }
- else {
- /* bring it to the user's timeline */
- xs *object = NULL;
- int status;
-
- status = activitypub_request(&snac, q, &object);
- snac_debug(&snac, 1, xs_fmt("Request searched URL %s %d", q, status));
+ status = activitypub_request(&snac, q, &object);
+ snac_debug(&snac, 1, xs_fmt("Request searched URL %s %d", q, status));
- if (valid_status(status)) {
- /* got it; also request the actor */
- const char *attr_to = get_atto(object);
+ if (valid_status(status) && xs_is_dict(object)) {
+ /* got it; also request the actor */
+ const char *attr_to = get_atto(object);
- if (!xs_is_null(attr_to)) {
- status = actor_request(&snac, attr_to, &actor_obj);
+ if (!xs_is_null(attr_to)) {
+ status = actor_request(&snac, attr_to, &actor_obj);
- if (valid_status(status)) {
- /* reset the query string to be the real id */
- url_acct = xs_dup(xs_dict_get(object, "id"));
- q = url_acct;
+ if (valid_status(status)) {
+ /* reset the query string to be the real id */
+ url_acct = xs_dup(xs_dict_get(object, "id"));
+ q = url_acct;
- /* add the post to the timeline */
- if (!timeline_here(&snac, q))
- timeline_add(&snac, q, object);
- }
+ /* add the post to the timeline */
+ if (!timeline_here(&snac, q))
+ timeline_add(&snac, q, object);
}
- else {
- /* retry webfinger, this time with the 'official' id */
- const char *id = xs_dict_get(object, "id");
+ }
+ 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;
- }
+ if (xs_is_string(id) && valid_status(webfinger_request_fake(id, &actor_obj, &url_acct)) &&
+ xs_is_string(url_acct))
+ q = url_acct;
}
}
+ else
+ /* may by an actor; try a webfinger */
+ 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;
+ }
/* fall through */
}
if (q && *q) {
- if (xs_regex_match(q, "^@?[a-zA-Z0-9._]+@[a-zA-Z0-9-]+\\.")) {
+ if (xs_regex_match(q, "^@?[^@]+@[a-zA-Z0-9-]+\\.")) {
/** search account **/
xs *actor = NULL;
xs *acct = NULL;
@@ -5065,6 +5122,22 @@ int html_get_handler(const xs_dict *req, const char *q_path,
}
}
else
+ if (strcmp(p_path, "admirations") == 0) { /** list of admired posts **/
+ if (!login(&snac, req)) {
+ *body = xs_dup(uid);
+ status = HTTP_STATUS_UNAUTHORIZED;
+ }
+ else {
+ int more = 0;
+ xs *list = timeline_list(&snac, "admire", skip, show, &more);
+
+ *body = html_timeline(&snac, list, 0, skip, show,
+ more, L("Liked, boosted or reacted posts"), "/admirations", 0, error, terse);
+ *b_size = strlen(*body);
+ status = HTTP_STATUS_OK;
+ }
+ }
+ else
if (strcmp(p_path, "bookmarks") == 0) { /** list of bookmarked posts **/
if (!login(&snac, req)) {
*body = xs_dup(uid);
@@ -5385,7 +5458,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
uid = xs_list_get(l, 1);
if (!uid || !user_open(&snac, uid)) {
/* invalid user */
- srv_debug(1, xs_fmt("html_post_handler bad user %s", uid));
+ srv_debug(1, xs_fmt("html_post_handler bad user %s", xs_or(uid, "(null)")));
return HTTP_STATUS_NOT_FOUND;
}
@@ -5656,6 +5729,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
const char *eid = xs_dict_get(p_vars, "eid");
if (eid != NULL) {
+ object_user_cache_del(&snac, id, "admire");
xs *n_msg = msg_emoji_unreact(&snac, id, eid);
if (n_msg != NULL)
@@ -5670,8 +5744,10 @@ int html_post_handler(const xs_dict *req, const char *q_path,
xs *ret = msg_emoji_init(&snac, id, eid);
/* fails if either invalid or already reacted */
- if (!ret)
+ if (!ret) {
+ object_user_cache_del(&snac, id, "admire");
ret = msg_emoji_unreact(&snac, id, eid);
+ }
if (!ret)
status = HTTP_STATUS_NOT_FOUND;
}
@@ -5698,6 +5774,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
xs *msg = msg_repulsion(&snac, id, "Like");
if (msg != NULL) {
+ object_user_cache_del(&snac, id, "admire");
enqueue_message(&snac, msg);
}
}
@@ -5706,6 +5783,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
xs *msg = msg_repulsion(&snac, id, "Announce");
if (msg != NULL) {
+ object_user_cache_del(&snac, id, "admire");
enqueue_message(&snac, msg);
}
}
@@ -5950,6 +6028,10 @@ int html_post_handler(const xs_dict *req, const char *q_path,
snac.config = xs_dict_set(snac.config, "tz", v);
if ((v = xs_dict_get(p_vars, "post_langs")) != NULL)
snac.config = xs_dict_set(snac.config, "post_langs", v);
+ if ((v = xs_dict_get(p_vars, "excluded_langs")) != NULL)
+ snac.config = xs_dict_set(snac.config, "excluded_langs", v);
+ else
+ snac.config = xs_dict_del(snac.config, "excluded_langs");
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", ""));