summaryrefslogtreecommitdiff
path: root/activitypub.c
diff options
context:
space:
mode:
Diffstat (limited to 'activitypub.c')
-rw-r--r--activitypub.c121
1 files changed, 96 insertions, 25 deletions
diff --git a/activitypub.c b/activitypub.c
index 0b2fc6a..773df78 100644
--- a/activitypub.c
+++ b/activitypub.c
@@ -183,6 +183,18 @@ const char *get_atto(const xs_dict *msg)
183} 183}
184 184
185 185
186const char *get_in_reply_to(const xs_dict *msg)
187/* gets the inReplyTo id */
188{
189 const xs_val *in_reply_to = xs_dict_get(msg, "inReplyTo");
190
191 if (xs_type(in_reply_to) == XSTYPE_DICT)
192 in_reply_to = xs_dict_get(in_reply_to, "id");
193
194 return in_reply_to;
195}
196
197
186xs_list *get_attachments(const xs_dict *msg) 198xs_list *get_attachments(const xs_dict *msg)
187/* unify the garbage fire that are the attachments */ 199/* unify the garbage fire that are the attachments */
188{ 200{
@@ -373,7 +385,7 @@ int timeline_request(snac *snac, const char **id, xs_str **wrk, int level)
373 } 385 }
374 386
375 /* does it have an ancestor? */ 387 /* does it have an ancestor? */
376 const char *in_reply_to = xs_dict_get(object, "inReplyTo"); 388 const char *in_reply_to = get_in_reply_to(object);
377 389
378 /* store */ 390 /* store */
379 timeline_add(snac, nid, object); 391 timeline_add(snac, nid, object);
@@ -671,7 +683,7 @@ int is_msg_for_me(snac *snac, const xs_dict *c_msg)
671 return 3; 683 return 3;
672 684
673 /* is this message a reply to another? */ 685 /* is this message a reply to another? */
674 const char *irt = xs_dict_get(msg, "inReplyTo"); 686 const char *irt = get_in_reply_to(msg);
675 if (!xs_is_null(irt)) { 687 if (!xs_is_null(irt)) {
676 xs *r_msg = NULL; 688 xs *r_msg = NULL;
677 689
@@ -724,7 +736,7 @@ xs_str *process_tags(snac *snac, const char *content, xs_list **tag)
724 /* use this same server */ 736 /* use this same server */
725 def_srv = xs_dup(xs_dict_get(srv_config, "host")); 737 def_srv = xs_dup(xs_dict_get(srv_config, "host"));
726 738
727 split = xs_regex_split(content, "(@[A-Za-z0-9_]+(@[A-Za-z0-9\\.-]+)?|&#[0-9]+;|#[^[:punct:][:space:]]+)"); 739 split = xs_regex_split(content, "(@[A-Za-z0-9_]+(@[A-Za-z0-9\\.-]+)?|&#[0-9]+;|#(_|[^[:punct:][:space:]])+)");
728 740
729 p = split; 741 p = split;
730 while (xs_list_iter(&p, &v)) { 742 while (xs_list_iter(&p, &v)) {
@@ -1026,15 +1038,14 @@ xs_dict *msg_base(snac *snac, const char *type, const char *id,
1026} 1038}
1027 1039
1028 1040
1029xs_dict *msg_collection(snac *snac, const char *id) 1041xs_dict *msg_collection(snac *snac, const char *id, int items)
1030/* creates an empty OrderedCollection message */ 1042/* creates an empty OrderedCollection message */
1031{ 1043{
1032 xs_dict *msg = msg_base(snac, "OrderedCollection", id, NULL, NULL, NULL); 1044 xs_dict *msg = msg_base(snac, "OrderedCollection", id, NULL, NULL, NULL);
1033 xs *ol = xs_list_new(); 1045 xs *n = xs_number_new(items);
1034 1046
1035 msg = xs_dict_append(msg, "attributedTo", snac->actor); 1047 msg = xs_dict_append(msg, "attributedTo", snac->actor);
1036 msg = xs_dict_append(msg, "orderedItems", ol); 1048 msg = xs_dict_append(msg, "totalItems", n);
1037 msg = xs_dict_append(msg, "totalItems", xs_stock(0));
1038 1049
1039 return msg; 1050 return msg;
1040} 1051}
@@ -1206,7 +1217,30 @@ xs_dict *msg_actor(snac *snac)
1206 } 1217 }
1207 1218
1208 /* add the metadata as attachments of PropertyValue */ 1219 /* add the metadata as attachments of PropertyValue */
1209 const xs_dict *metadata = xs_dict_get(snac->config, "metadata"); 1220 xs *metadata = NULL;
1221 const xs_dict *md = xs_dict_get(snac->config, "metadata");
1222
1223 if (xs_type(md) == XSTYPE_DICT)
1224 metadata = xs_dup(md);
1225 else
1226 if (xs_type(md) == XSTYPE_STRING) {
1227 metadata = xs_dict_new();
1228 xs *l = xs_split(md, "\n");
1229 const char *ll;
1230
1231 xs_list_foreach(l, ll) {
1232 xs *kv = xs_split_n(ll, "=", 1);
1233 const char *k = xs_list_get(kv, 0);
1234 const char *v = xs_list_get(kv, 1);
1235
1236 if (k && v) {
1237 xs *kk = xs_strip_i(xs_dup(k));
1238 xs *vv = xs_strip_i(xs_dup(v));
1239 metadata = xs_dict_set(metadata, kk, vv);
1240 }
1241 }
1242 }
1243
1210 if (xs_type(metadata) == XSTYPE_DICT) { 1244 if (xs_type(metadata) == XSTYPE_DICT) {
1211 xs *attach = xs_list_new(); 1245 xs *attach = xs_list_new();
1212 const xs_str *k; 1246 const xs_str *k;
@@ -1252,6 +1286,10 @@ xs_dict *msg_actor(snac *snac)
1252 msg = xs_dict_set(msg, "alsoKnownAs", loaka); 1286 msg = xs_dict_set(msg, "alsoKnownAs", loaka);
1253 } 1287 }
1254 1288
1289 const xs_val *manually = xs_dict_get(snac->config, "approve_followers");
1290 msg = xs_dict_set(msg, "manuallyApprovesFollowers",
1291 xs_stock(xs_is_true(manually) ? XSTYPE_TRUE : XSTYPE_FALSE));
1292
1255 return msg; 1293 return msg;
1256} 1294}
1257 1295
@@ -1888,22 +1926,31 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req)
1888 object_add(actor, actor_obj); 1926 object_add(actor, actor_obj);
1889 } 1927 }
1890 1928
1891 xs *f_msg = xs_dup(msg); 1929 if (xs_is_true(xs_dict_get(snac->config, "approve_followers"))) {
1892 xs *reply = msg_accept(snac, f_msg, actor); 1930 pending_add(snac, actor, msg);
1893
1894 post_message(snac, actor, reply);
1895 1931
1896 if (xs_is_null(xs_dict_get(f_msg, "published"))) { 1932 snac_log(snac, xs_fmt("new pending follower approval %s", actor));
1897 /* add a date if it doesn't include one (Mastodon) */
1898 xs *date = xs_str_utctime(0, ISO_DATE_SPEC);
1899 f_msg = xs_dict_set(f_msg, "published", date);
1900 } 1933 }
1934 else {
1935 /* automatic following */
1936 xs *f_msg = xs_dup(msg);
1937 xs *reply = msg_accept(snac, f_msg, actor);
1938
1939 post_message(snac, actor, reply);
1901 1940
1902 timeline_add(snac, id, f_msg); 1941 if (xs_is_null(xs_dict_get(f_msg, "published"))) {
1942 /* add a date if it doesn't include one (Mastodon) */
1943 xs *date = xs_str_utctime(0, ISO_DATE_SPEC);
1944 f_msg = xs_dict_set(f_msg, "published", date);
1945 }
1946
1947 timeline_add(snac, id, f_msg);
1903 1948
1904 follower_add(snac, actor); 1949 follower_add(snac, actor);
1950
1951 snac_log(snac, xs_fmt("new follower %s", actor));
1952 }
1905 1953
1906 snac_log(snac, xs_fmt("new follower %s", actor));
1907 do_notify = 1; 1954 do_notify = 1;
1908 } 1955 }
1909 else 1956 else
@@ -1925,6 +1972,11 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req)
1925 do_notify = 1; 1972 do_notify = 1;
1926 } 1973 }
1927 else 1974 else
1975 if (pending_check(snac, actor)) {
1976 pending_del(snac, actor);
1977 snac_log(snac, xs_fmt("cancelled pending follow from %s", actor));
1978 }
1979 else
1928 snac_log(snac, xs_fmt("error deleting follower %s", actor)); 1980 snac_log(snac, xs_fmt("error deleting follower %s", actor));
1929 } 1981 }
1930 } 1982 }
@@ -1957,7 +2009,7 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req)
1957 2009
1958 if (xs_match(utype, "Note|Article")) { /** **/ 2010 if (xs_match(utype, "Note|Article")) { /** **/
1959 const char *id = xs_dict_get(object, "id"); 2011 const char *id = xs_dict_get(object, "id");
1960 const char *in_reply_to = xs_dict_get(object, "inReplyTo"); 2012 const char *in_reply_to = get_in_reply_to(object);
1961 const char *atto = get_atto(object); 2013 const char *atto = get_atto(object);
1962 xs *wrk = NULL; 2014 xs *wrk = NULL;
1963 2015
@@ -2784,6 +2836,8 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path,
2784 2836
2785 *ctype = "application/activity+json"; 2837 *ctype = "application/activity+json";
2786 2838
2839 int show_contact_metrics = xs_is_true(xs_dict_get(snac.config, "show_contact_metrics"));
2840
2787 if (p_path == NULL) { 2841 if (p_path == NULL) {
2788 /* if there was no component after the user, it's an actor request */ 2842 /* if there was no component after the user, it's an actor request */
2789 msg = msg_actor(&snac); 2843 msg = msg_actor(&snac);
@@ -2797,7 +2851,6 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path,
2797 if (strcmp(p_path, "outbox") == 0 || strcmp(p_path, "featured") == 0) { 2851 if (strcmp(p_path, "outbox") == 0 || strcmp(p_path, "featured") == 0) {
2798 xs *id = xs_fmt("%s/%s", snac.actor, p_path); 2852 xs *id = xs_fmt("%s/%s", snac.actor, p_path);
2799 xs *list = xs_list_new(); 2853 xs *list = xs_list_new();
2800 msg = msg_collection(&snac, id);
2801 const char *v; 2854 const char *v;
2802 int tc = 0; 2855 int tc = 0;
2803 2856
@@ -2819,14 +2872,32 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path,
2819 } 2872 }
2820 2873
2821 /* replace the 'orderedItems' with the latest posts */ 2874 /* replace the 'orderedItems' with the latest posts */
2822 xs *items = xs_number_new(xs_list_len(list)); 2875 msg = msg_collection(&snac, id, xs_list_len(list));
2823 msg = xs_dict_set(msg, "orderedItems", list); 2876 msg = xs_dict_set(msg, "orderedItems", list);
2824 msg = xs_dict_set(msg, "totalItems", items);
2825 } 2877 }
2826 else 2878 else
2827 if (strcmp(p_path, "followers") == 0 || strcmp(p_path, "following") == 0) { 2879 if (strcmp(p_path, "followers") == 0) {
2880 int total = 0;
2881
2882 if (show_contact_metrics) {
2883 xs *l = follower_list(&snac);
2884 total = xs_list_len(l);
2885 }
2886
2887 xs *id = xs_fmt("%s/%s", snac.actor, p_path);
2888 msg = msg_collection(&snac, id, total);
2889 }
2890 else
2891 if (strcmp(p_path, "following") == 0) {
2892 int total = 0;
2893
2894 if (show_contact_metrics) {
2895 xs *l = following_list(&snac);
2896 total = xs_list_len(l);
2897 }
2898
2828 xs *id = xs_fmt("%s/%s", snac.actor, p_path); 2899 xs *id = xs_fmt("%s/%s", snac.actor, p_path);
2829 msg = msg_collection(&snac, id); 2900 msg = msg_collection(&snac, id, total);
2830 } 2901 }
2831 else 2902 else
2832 if (xs_startswith(p_path, "p/")) { 2903 if (xs_startswith(p_path, "p/")) {