commit 86de22f

grunfink  ·  2025-08-16 14:42:50 +0000 UTC
parent 9558136
New function collect_replies().
3 files changed,  +96, -0
M main.c
M snac.h
+88, -0
 1@@ -936,6 +936,94 @@ xs_str *process_tags(snac *snac, const char *content, xs_list **tag)
 2 }
 3 
 4 
 5+void collect_replies(snac *user, const char *id)
 6+/* collects all replies for a post */
 7+{
 8+    xs *obj = NULL;
 9+
10+    if (!valid_status(object_get(id, &obj))) {
11+        snac_debug(user, 1, xs_fmt("collect_replies: object '%s' is not here", id));
12+        return;
13+    }
14+
15+    const char *next = xs_dict_get_path(obj, "replies.first.next");
16+    if (!xs_is_string(next)) {
17+        snac_debug(user, 1, xs_fmt("collect_replies: object '%s' does not have a replies.first.next URL", id));
18+        return;
19+    }
20+
21+    /* pick the first level replies (may be empty) */
22+    const xs_list *level0_replies = xs_dict_get_path(obj, "replies.first.items");
23+
24+    xs *reply_obj = NULL;
25+
26+    if (!valid_status(object_get(next, &reply_obj))) {
27+        if (!valid_status(activitypub_request(user, next, &reply_obj))) {
28+            snac_debug(user, 1, xs_fmt("collect_replies: cannot get replies object '%s'", next));
29+            return;
30+        }
31+    }
32+
33+    const xs_list *level1_replies = xs_dict_get(reply_obj, "items");
34+    if (!xs_is_list(level1_replies)) {
35+        snac_debug(user, 1, xs_fmt("collect_replies: cannot get reply items from object '%s'", next));
36+        return;
37+    }
38+
39+    xs *items = NULL;
40+
41+    if (xs_is_list(level0_replies))
42+        items = xs_list_cat(xs_dup(level0_replies), level1_replies);
43+    else
44+        items = xs_dup(level1_replies);
45+
46+    const xs_val *v;
47+
48+    xs_list_foreach(items, v) {
49+        xs *reply = NULL;
50+
51+        if (xs_is_string(v)) {
52+            /* request the object */
53+            if (!valid_status(object_get(v, &reply))) {
54+                if (!valid_status(activitypub_request(user, v, &reply))) {
55+                    snac_debug(user, 1, xs_fmt("collect_replies: error requesting object '%s'", v));
56+                    continue;
57+                }
58+            }
59+        }
60+        else
61+        if (xs_is_dict(v)) {
62+            /* actually the post object */
63+            reply = xs_dup(v);
64+        }
65+
66+        if (!xs_is_dict(reply))
67+            continue;
68+
69+        const char *id      = xs_dict_get(reply, "id");
70+        const char *type    = xs_dict_get(reply, "type");
71+        const char *attr_to = get_atto(reply);
72+
73+        if (!xs_is_string(id) || !xs_is_string(type) || !xs_is_string(attr_to))
74+            continue;
75+
76+        if (!xs_match(type, POSTLIKE_OBJECT_TYPE))
77+            continue;
78+
79+        if (timeline_here(user, id)) {
80+            snac_debug(user, 1, xs_fmt("collect_replies: item already in timeline %s", id));
81+            continue;
82+        }
83+
84+        enqueue_actor_refresh(user, attr_to, 0);
85+
86+        timeline_add(user, id, reply);
87+
88+        snac_log(user, xs_fmt("new '%s' (collect_replies) %s %s", type, attr_to, id));
89+    }
90+}
91+
92+
93 void notify(snac *snac, const char *type, const char *utype, const char *actor, const xs_dict *msg)
94 /* notifies the user of relevant events */
95 {
M main.c
+6, -0
 1@@ -730,6 +730,12 @@ int main(int argc, char *argv[])
 2         return 0;
 3     }
 4 
 5+    if (strcmp(cmd, "collect_replies") == 0) { /** **/
 6+        collect_replies(&snac, url);
 7+
 8+        return 0;
 9+    }
10+
11     if (strcmp(cmd, "insert") == 0) { /** **/
12         int status;
13         xs *data = NULL;
M snac.h
+2, -0
1@@ -334,6 +334,8 @@ const char *default_avatar_base64(void);
2 
3 xs_str *process_tags(snac *snac, const char *content, xs_list **tag);
4 
5+void collect_replies(snac *user, const char *id);
6+
7 const char *get_atto(const xs_dict *msg);
8 const char *get_in_reply_to(const xs_dict *msg);
9 xs_list *get_attachments(const xs_dict *msg);