diff options
| author | 2024-12-05 22:53:40 +0100 | |
|---|---|---|
| committer | 2024-12-05 22:53:40 +0100 | |
| commit | bd74ffda5b25cc07e8d559815e027c8dab3b9d73 (patch) | |
| tree | 00725a5d5f53ed421b923de6fc1892c58815cc16 /html.c | |
| parent | Makefile: enable static compilation with musl (diff) | |
| parent | Updated RELEASE_NOTES. (diff) | |
| download | snac2-bd74ffda5b25cc07e8d559815e027c8dab3b9d73.tar.gz snac2-bd74ffda5b25cc07e8d559815e027c8dab3b9d73.tar.xz snac2-bd74ffda5b25cc07e8d559815e027c8dab3b9d73.zip | |
Merge branch 'master' into build-with-musl
Diffstat (limited to 'html.c')
| -rw-r--r-- | html.c | 234 |
1 files changed, 192 insertions, 42 deletions
| @@ -770,7 +770,7 @@ static xs_html *html_user_body(snac *user, int read_only) | |||
| 770 | xs_html_sctag("input", | 770 | xs_html_sctag("input", |
| 771 | xs_html_attr("type", "text"), | 771 | xs_html_attr("type", "text"), |
| 772 | xs_html_attr("name", "q"), | 772 | xs_html_attr("name", "q"), |
| 773 | xs_html_attr("title", L("Search posts by content (regular expression) or #tag")), | 773 | xs_html_attr("title", L("Search posts by content (regular expression), @user@host accounts, or #tag")), |
| 774 | xs_html_attr("placeholder", L("Content search"))))); | 774 | xs_html_attr("placeholder", L("Content search"))))); |
| 775 | } | 775 | } |
| 776 | 776 | ||
| @@ -829,21 +829,45 @@ static xs_html *html_user_body(snac *user, int read_only) | |||
| 829 | } | 829 | } |
| 830 | 830 | ||
| 831 | if (read_only) { | 831 | if (read_only) { |
| 832 | xs *es1 = encode_html(xs_dict_get(user->config, "bio")); | ||
| 833 | xs *tags = xs_list_new(); | 832 | xs *tags = xs_list_new(); |
| 834 | xs *bio1 = not_really_markdown(es1, NULL, &tags); | 833 | xs *bio1 = not_really_markdown(xs_dict_get(user->config, "bio"), NULL, &tags); |
| 835 | xs *bio2 = process_tags(user, bio1, &tags); | 834 | xs *bio2 = process_tags(user, bio1, &tags); |
| 835 | xs *bio3 = sanitize(bio2); | ||
| 836 | 836 | ||
| 837 | bio2 = replace_shortnames(bio2, tags, 2, proxy); | 837 | bio3 = replace_shortnames(bio3, tags, 2, proxy); |
| 838 | 838 | ||
| 839 | xs_html *top_user_bio = xs_html_tag("div", | 839 | xs_html *top_user_bio = xs_html_tag("div", |
| 840 | xs_html_attr("class", "p-note snac-top-user-bio"), | 840 | xs_html_attr("class", "p-note snac-top-user-bio"), |
| 841 | xs_html_raw(bio2)); /* already sanitized */ | 841 | xs_html_raw(bio3)); /* already sanitized */ |
| 842 | 842 | ||
| 843 | xs_html_add(top_user, | 843 | xs_html_add(top_user, |
| 844 | top_user_bio); | 844 | top_user_bio); |
| 845 | 845 | ||
| 846 | const xs_dict *metadata = xs_dict_get(user->config, "metadata"); | 846 | xs *metadata = NULL; |
| 847 | const xs_dict *md = xs_dict_get(user->config, "metadata"); | ||
| 848 | |||
| 849 | if (xs_type(md) == XSTYPE_DICT) | ||
| 850 | metadata = xs_dup(md); | ||
| 851 | else | ||
| 852 | if (xs_type(md) == XSTYPE_STRING) { | ||
| 853 | /* convert to dict for easier iteration */ | ||
| 854 | metadata = xs_dict_new(); | ||
| 855 | xs *l = xs_split(md, "\n"); | ||
| 856 | const char *ll; | ||
| 857 | |||
| 858 | xs_list_foreach(l, ll) { | ||
| 859 | xs *kv = xs_split_n(ll, "=", 1); | ||
| 860 | const char *k = xs_list_get(kv, 0); | ||
| 861 | const char *v = xs_list_get(kv, 1); | ||
| 862 | |||
| 863 | if (k && v) { | ||
| 864 | xs *kk = xs_strip_i(xs_dup(k)); | ||
| 865 | xs *vv = xs_strip_i(xs_dup(v)); | ||
| 866 | metadata = xs_dict_set(metadata, kk, vv); | ||
| 867 | } | ||
| 868 | } | ||
| 869 | } | ||
| 870 | |||
| 847 | if (xs_type(metadata) == XSTYPE_DICT) { | 871 | if (xs_type(metadata) == XSTYPE_DICT) { |
| 848 | const xs_str *k; | 872 | const xs_str *k; |
| 849 | const xs_str *v; | 873 | const xs_str *v; |
| @@ -914,6 +938,18 @@ static xs_html *html_user_body(snac *user, int read_only) | |||
| 914 | xs_html_add(top_user, | 938 | xs_html_add(top_user, |
| 915 | snac_metadata); | 939 | snac_metadata); |
| 916 | } | 940 | } |
| 941 | |||
| 942 | if (xs_is_true(xs_dict_get(user->config, "show_contact_metrics"))) { | ||
| 943 | xs *fwers = follower_list(user); | ||
| 944 | xs *fwing = following_list(user); | ||
| 945 | |||
| 946 | xs *s1 = xs_fmt(L("%d following %d followers"), | ||
| 947 | xs_list_len(fwing), xs_list_len(fwers)); | ||
| 948 | |||
| 949 | xs_html_add(top_user, | ||
| 950 | xs_html_tag("p", | ||
| 951 | xs_html_text(s1))); | ||
| 952 | } | ||
| 917 | } | 953 | } |
| 918 | 954 | ||
| 919 | xs_html_add(body, | 955 | xs_html_add(body, |
| @@ -1025,20 +1061,31 @@ xs_html *html_top_controls(snac *snac) | |||
| 1025 | const xs_val *a_private = xs_dict_get(snac->config, "private"); | 1061 | const xs_val *a_private = xs_dict_get(snac->config, "private"); |
| 1026 | const xs_val *auto_boost = xs_dict_get(snac->config, "auto_boost"); | 1062 | const xs_val *auto_boost = xs_dict_get(snac->config, "auto_boost"); |
| 1027 | const xs_val *coll_thrds = xs_dict_get(snac->config, "collapse_threads"); | 1063 | const xs_val *coll_thrds = xs_dict_get(snac->config, "collapse_threads"); |
| 1064 | const xs_val *pending = xs_dict_get(snac->config, "approve_followers"); | ||
| 1065 | const xs_val *show_foll = xs_dict_get(snac->config, "show_contact_metrics"); | ||
| 1028 | 1066 | ||
| 1029 | xs *metadata = xs_str_new(NULL); | 1067 | xs *metadata = NULL; |
| 1030 | const xs_dict *md = xs_dict_get(snac->config, "metadata"); | 1068 | const xs_dict *md = xs_dict_get(snac->config, "metadata"); |
| 1031 | const xs_str *k; | ||
| 1032 | const xs_str *v; | ||
| 1033 | 1069 | ||
| 1034 | int c = 0; | 1070 | if (xs_type(md) == XSTYPE_DICT) { |
| 1035 | while (xs_dict_next(md, &k, &v, &c)) { | 1071 | const xs_str *k; |
| 1036 | xs *kp = xs_fmt("%s=%s", k, v); | 1072 | const xs_str *v; |
| 1037 | 1073 | ||
| 1038 | if (*metadata) | 1074 | metadata = xs_str_new(NULL); |
| 1039 | metadata = xs_str_cat(metadata, "\n"); | 1075 | |
| 1040 | metadata = xs_str_cat(metadata, kp); | 1076 | xs_dict_foreach(md, k, v) { |
| 1077 | xs *kp = xs_fmt("%s=%s", k, v); | ||
| 1078 | |||
| 1079 | if (*metadata) | ||
| 1080 | metadata = xs_str_cat(metadata, "\n"); | ||
| 1081 | metadata = xs_str_cat(metadata, kp); | ||
| 1082 | } | ||
| 1041 | } | 1083 | } |
| 1084 | else | ||
| 1085 | if (xs_type(md) == XSTYPE_STRING) | ||
| 1086 | metadata = xs_dup(md); | ||
| 1087 | else | ||
| 1088 | metadata = xs_str_new(NULL); | ||
| 1042 | 1089 | ||
| 1043 | xs *user_setup_action = xs_fmt("%s/admin/user-setup", snac->actor); | 1090 | xs *user_setup_action = xs_fmt("%s/admin/user-setup", snac->actor); |
| 1044 | 1091 | ||
| @@ -1188,6 +1235,24 @@ xs_html *html_top_controls(snac *snac) | |||
| 1188 | xs_html_attr("for", "collapse_threads"), | 1235 | xs_html_attr("for", "collapse_threads"), |
| 1189 | xs_html_text(L("Collapse top threads by default")))), | 1236 | xs_html_text(L("Collapse top threads by default")))), |
| 1190 | xs_html_tag("p", | 1237 | xs_html_tag("p", |
| 1238 | xs_html_sctag("input", | ||
| 1239 | xs_html_attr("type", "checkbox"), | ||
| 1240 | xs_html_attr("name", "approve_followers"), | ||
| 1241 | xs_html_attr("id", "approve_followers"), | ||
| 1242 | xs_html_attr(xs_is_true(pending) ? "checked" : "", NULL)), | ||
| 1243 | xs_html_tag("label", | ||
| 1244 | xs_html_attr("for", "approve_followers"), | ||
| 1245 | xs_html_text(L("Follow requests must be approved")))), | ||
| 1246 | xs_html_tag("p", | ||
| 1247 | xs_html_sctag("input", | ||
| 1248 | xs_html_attr("type", "checkbox"), | ||
| 1249 | xs_html_attr("name", "show_contact_metrics"), | ||
| 1250 | xs_html_attr("id", "show_contact_metrics"), | ||
| 1251 | xs_html_attr(xs_is_true(show_foll) ? "checked" : "", NULL)), | ||
| 1252 | xs_html_tag("label", | ||
| 1253 | xs_html_attr("for", "show_contact_metrics"), | ||
| 1254 | xs_html_text(L("Publish follower and following metrics")))), | ||
| 1255 | xs_html_tag("p", | ||
| 1191 | xs_html_text(L("Profile metadata (key=value pairs in each line):")), | 1256 | xs_html_text(L("Profile metadata (key=value pairs in each line):")), |
| 1192 | xs_html_sctag("br", NULL), | 1257 | xs_html_sctag("br", NULL), |
| 1193 | xs_html_tag("textarea", | 1258 | xs_html_tag("textarea", |
| @@ -1481,6 +1546,9 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, | |||
| 1481 | if ((read_only || !user) && !is_msg_public(msg)) | 1546 | if ((read_only || !user) && !is_msg_public(msg)) |
| 1482 | return NULL; | 1547 | return NULL; |
| 1483 | 1548 | ||
| 1549 | if (id && is_instance_blocked(id)) | ||
| 1550 | return NULL; | ||
| 1551 | |||
| 1484 | if (user && level == 0 && xs_is_true(xs_dict_get(user->config, "collapse_threads"))) | 1552 | if (user && level == 0 && xs_is_true(xs_dict_get(user->config, "collapse_threads"))) |
| 1485 | collapse_threads = 1; | 1553 | collapse_threads = 1; |
| 1486 | 1554 | ||
| @@ -1670,7 +1738,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, | |||
| 1670 | if (strcmp(type, "Note") == 0) { | 1738 | if (strcmp(type, "Note") == 0) { |
| 1671 | if (level == 0) { | 1739 | if (level == 0) { |
| 1672 | /* is the parent not here? */ | 1740 | /* is the parent not here? */ |
| 1673 | const char *parent = xs_dict_get(msg, "inReplyTo"); | 1741 | const char *parent = get_in_reply_to(msg); |
| 1674 | 1742 | ||
| 1675 | if (user && !xs_is_null(parent) && *parent && !timeline_here(user, parent)) { | 1743 | if (user && !xs_is_null(parent) && *parent && !timeline_here(user, parent)) { |
| 1676 | xs_html_add(post_header, | 1744 | xs_html_add(post_header, |
| @@ -2329,7 +2397,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, | |||
| 2329 | 2397 | ||
| 2330 | /* is this message a non-public reply? */ | 2398 | /* is this message a non-public reply? */ |
| 2331 | if (user != NULL && !is_msg_public(msg)) { | 2399 | if (user != NULL && !is_msg_public(msg)) { |
| 2332 | const char *irt = xs_dict_get(msg, "inReplyTo"); | 2400 | const char *irt = get_in_reply_to(msg); |
| 2333 | 2401 | ||
| 2334 | /* is it a reply to something not in the storage? */ | 2402 | /* is it a reply to something not in the storage? */ |
| 2335 | if (!xs_is_null(irt) && !object_here(irt)) { | 2403 | if (!xs_is_null(irt) && !object_here(irt)) { |
| @@ -2437,10 +2505,9 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t, cons | |||
| 2437 | xs_html_tag("summary", | 2505 | xs_html_tag("summary", |
| 2438 | xs_html_text("...")))); | 2506 | xs_html_text("...")))); |
| 2439 | 2507 | ||
| 2440 | xs_list *p = list; | ||
| 2441 | const char *actor_id; | 2508 | const char *actor_id; |
| 2442 | 2509 | ||
| 2443 | while (xs_list_iter(&p, &actor_id)) { | 2510 | xs_list_foreach(list, actor_id) { |
| 2444 | xs *md5 = xs_md5_hex(actor_id, strlen(actor_id)); | 2511 | xs *md5 = xs_md5_hex(actor_id, strlen(actor_id)); |
| 2445 | xs *actor = NULL; | 2512 | xs *actor = NULL; |
| 2446 | 2513 | ||
| @@ -2509,6 +2576,15 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t, cons | |||
| 2509 | html_button("limit", L("Limit"), | 2576 | html_button("limit", L("Limit"), |
| 2510 | L("Block announces (boosts) from this user"))); | 2577 | L("Block announces (boosts) from this user"))); |
| 2511 | } | 2578 | } |
| 2579 | else | ||
| 2580 | if (pending_check(snac, actor_id)) { | ||
| 2581 | xs_html_add(form, | ||
| 2582 | html_button("approve", L("Approve"), | ||
| 2583 | L("Approve this follow request"))); | ||
| 2584 | |||
| 2585 | xs_html_add(form, | ||
| 2586 | html_button("discard", L("Discard"), L("Discard this follow request"))); | ||
| 2587 | } | ||
| 2512 | else { | 2588 | else { |
| 2513 | xs_html_add(form, | 2589 | xs_html_add(form, |
| 2514 | html_button("follow", L("Follow"), | 2590 | html_button("follow", L("Follow"), |
| @@ -2563,13 +2639,23 @@ xs_str *html_people(snac *user) | |||
| 2563 | xs *wing = following_list(user); | 2639 | xs *wing = following_list(user); |
| 2564 | xs *wers = follower_list(user); | 2640 | xs *wers = follower_list(user); |
| 2565 | 2641 | ||
| 2642 | xs_html *lists = xs_html_tag("div", | ||
| 2643 | xs_html_attr("class", "snac-posts")); | ||
| 2644 | |||
| 2645 | if (xs_is_true(xs_dict_get(user->config, "approve_followers"))) { | ||
| 2646 | xs *pending = pending_list(user); | ||
| 2647 | xs_html_add(lists, | ||
| 2648 | html_people_list(user, pending, L("Pending follow confirmations"), "p", proxy)); | ||
| 2649 | } | ||
| 2650 | |||
| 2651 | xs_html_add(lists, | ||
| 2652 | html_people_list(user, wing, L("People you follow"), "i", proxy), | ||
| 2653 | html_people_list(user, wers, L("People that follow you"), "e", proxy)); | ||
| 2654 | |||
| 2566 | xs_html *html = xs_html_tag("html", | 2655 | xs_html *html = xs_html_tag("html", |
| 2567 | html_user_head(user, NULL, NULL), | 2656 | html_user_head(user, NULL, NULL), |
| 2568 | xs_html_add(html_user_body(user, 0), | 2657 | xs_html_add(html_user_body(user, 0), |
| 2569 | xs_html_tag("div", | 2658 | lists, |
| 2570 | xs_html_attr("class", "snac-posts"), | ||
| 2571 | html_people_list(user, wing, L("People you follow"), "i", proxy), | ||
| 2572 | html_people_list(user, wers, L("People that follow you"), "e", proxy)), | ||
| 2573 | html_footer())); | 2659 | html_footer())); |
| 2574 | 2660 | ||
| 2575 | return xs_html_render_s(html, "<!DOCTYPE html>\n"); | 2661 | return xs_html_render_s(html, "<!DOCTYPE html>\n"); |
| @@ -2661,6 +2747,9 @@ xs_str *html_notifications(snac *user, int skip, int show) | |||
| 2661 | label = wrk; | 2747 | label = wrk; |
| 2662 | } | 2748 | } |
| 2663 | } | 2749 | } |
| 2750 | else | ||
| 2751 | if (strcmp(type, "Follow") == 0 && pending_check(user, actor_id)) | ||
| 2752 | label = L("Follow Request"); | ||
| 2664 | 2753 | ||
| 2665 | xs *s_date = xs_crop_i(xs_dup(date), 0, 10); | 2754 | xs *s_date = xs_crop_i(xs_dup(date), 0, 10); |
| 2666 | 2755 | ||
| @@ -2909,6 +2998,48 @@ int html_get_handler(const xs_dict *req, const char *q_path, | |||
| 2909 | const char *q = xs_dict_get(q_vars, "q"); | 2998 | const char *q = xs_dict_get(q_vars, "q"); |
| 2910 | 2999 | ||
| 2911 | if (q && *q) { | 3000 | if (q && *q) { |
| 3001 | if (xs_regex_match(q, "^@?[a-zA-Z0-9_]+@[a-zA-Z0-9-]+\\.")) { | ||
| 3002 | /** search account **/ | ||
| 3003 | xs *actor = NULL; | ||
| 3004 | xs *acct = NULL; | ||
| 3005 | xs *l = xs_list_new(); | ||
| 3006 | xs_html *page = NULL; | ||
| 3007 | |||
| 3008 | if (valid_status(webfinger_request(q, &actor, &acct))) { | ||
| 3009 | xs *actor_obj = NULL; | ||
| 3010 | |||
| 3011 | if (valid_status(actor_request(&snac, actor, &actor_obj))) { | ||
| 3012 | actor_add(actor, actor_obj); | ||
| 3013 | |||
| 3014 | /* create a people list with only one element */ | ||
| 3015 | l = xs_list_append(xs_list_new(), actor); | ||
| 3016 | |||
| 3017 | xs *title = xs_fmt(L("Search results for account %s"), q); | ||
| 3018 | |||
| 3019 | page = html_people_list(&snac, l, title, "wf", NULL); | ||
| 3020 | } | ||
| 3021 | } | ||
| 3022 | |||
| 3023 | if (page == NULL) { | ||
| 3024 | xs *title = xs_fmt(L("Account %s not found"), q); | ||
| 3025 | |||
| 3026 | page = xs_html_tag("div", | ||
| 3027 | xs_html_tag("h2", | ||
| 3028 | xs_html_attr("class", "snac-header"), | ||
| 3029 | xs_html_text(title))); | ||
| 3030 | } | ||
| 3031 | |||
| 3032 | xs_html *html = xs_html_tag("html", | ||
| 3033 | html_user_head(&snac, NULL, NULL), | ||
| 3034 | xs_html_add(html_user_body(&snac, 0), | ||
| 3035 | page, | ||
| 3036 | html_footer())); | ||
| 3037 | |||
| 3038 | *body = xs_html_render_s(html, "<!DOCTYPE html>\n"); | ||
| 3039 | *b_size = strlen(*body); | ||
| 3040 | status = HTTP_STATUS_OK; | ||
| 3041 | } | ||
| 3042 | else | ||
| 2912 | if (*q == '#') { | 3043 | if (*q == '#') { |
| 2913 | /** search by tag **/ | 3044 | /** search by tag **/ |
| 2914 | xs *tl = tag_search(q, skip, show + 1); | 3045 | xs *tl = tag_search(q, skip, show + 1); |
| @@ -3647,6 +3778,34 @@ int html_post_handler(const xs_dict *req, const char *q_path, | |||
| 3647 | timeline_touch(&snac); | 3778 | timeline_touch(&snac); |
| 3648 | } | 3779 | } |
| 3649 | else | 3780 | else |
| 3781 | if (strcmp(action, L("Approve")) == 0) { /** **/ | ||
| 3782 | xs *fwreq = pending_get(&snac, actor); | ||
| 3783 | |||
| 3784 | if (fwreq != NULL) { | ||
| 3785 | xs *reply = msg_accept(&snac, fwreq, actor); | ||
| 3786 | |||
| 3787 | enqueue_message(&snac, reply); | ||
| 3788 | |||
| 3789 | if (xs_is_null(xs_dict_get(fwreq, "published"))) { | ||
| 3790 | /* add a date if it doesn't include one (Mastodon) */ | ||
| 3791 | xs *date = xs_str_utctime(0, ISO_DATE_SPEC); | ||
| 3792 | fwreq = xs_dict_set(fwreq, "published", date); | ||
| 3793 | } | ||
| 3794 | |||
| 3795 | timeline_add(&snac, xs_dict_get(fwreq, "id"), fwreq); | ||
| 3796 | |||
| 3797 | follower_add(&snac, actor); | ||
| 3798 | |||
| 3799 | pending_del(&snac, actor); | ||
| 3800 | |||
| 3801 | snac_log(&snac, xs_fmt("new follower %s", actor)); | ||
| 3802 | } | ||
| 3803 | } | ||
| 3804 | else | ||
| 3805 | if (strcmp(action, L("Discard")) == 0) { /** **/ | ||
| 3806 | pending_del(&snac, actor); | ||
| 3807 | } | ||
| 3808 | else | ||
| 3650 | status = HTTP_STATUS_NOT_FOUND; | 3809 | status = HTTP_STATUS_NOT_FOUND; |
| 3651 | 3810 | ||
| 3652 | /* delete the cached timeline */ | 3811 | /* delete the cached timeline */ |
| @@ -3705,26 +3864,17 @@ int html_post_handler(const xs_dict *req, const char *q_path, | |||
| 3705 | snac.config = xs_dict_set(snac.config, "collapse_threads", xs_stock(XSTYPE_TRUE)); | 3864 | snac.config = xs_dict_set(snac.config, "collapse_threads", xs_stock(XSTYPE_TRUE)); |
| 3706 | else | 3865 | else |
| 3707 | snac.config = xs_dict_set(snac.config, "collapse_threads", xs_stock(XSTYPE_FALSE)); | 3866 | snac.config = xs_dict_set(snac.config, "collapse_threads", xs_stock(XSTYPE_FALSE)); |
| 3867 | if ((v = xs_dict_get(p_vars, "approve_followers")) != NULL && strcmp(v, "on") == 0) | ||
| 3868 | snac.config = xs_dict_set(snac.config, "approve_followers", xs_stock(XSTYPE_TRUE)); | ||
| 3869 | else | ||
| 3870 | snac.config = xs_dict_set(snac.config, "approve_followers", xs_stock(XSTYPE_FALSE)); | ||
| 3871 | if ((v = xs_dict_get(p_vars, "show_contact_metrics")) != NULL && strcmp(v, "on") == 0) | ||
| 3872 | snac.config = xs_dict_set(snac.config, "show_contact_metrics", xs_stock(XSTYPE_TRUE)); | ||
| 3873 | else | ||
| 3874 | snac.config = xs_dict_set(snac.config, "show_contact_metrics", xs_stock(XSTYPE_FALSE)); | ||
| 3708 | 3875 | ||
| 3709 | if ((v = xs_dict_get(p_vars, "metadata")) != NULL) { | 3876 | if ((v = xs_dict_get(p_vars, "metadata")) != NULL) |
| 3710 | /* split the metadata and store it as a dict */ | 3877 | snac.config = xs_dict_set(snac.config, "metadata", v); |
| 3711 | xs_dict *md = xs_dict_new(); | ||
| 3712 | xs *l = xs_split(v, "\n"); | ||
| 3713 | xs_list *p = l; | ||
| 3714 | const xs_str *kp; | ||
| 3715 | |||
| 3716 | while (xs_list_iter(&p, &kp)) { | ||
| 3717 | xs *kpl = xs_split_n(kp, "=", 1); | ||
| 3718 | if (xs_list_len(kpl) == 2) { | ||
| 3719 | xs *k2 = xs_strip_i(xs_dup(xs_list_get(kpl, 0))); | ||
| 3720 | xs *v2 = xs_strip_i(xs_dup(xs_list_get(kpl, 1))); | ||
| 3721 | |||
| 3722 | md = xs_dict_set(md, k2, v2); | ||
| 3723 | } | ||
| 3724 | } | ||
| 3725 | |||
| 3726 | snac.config = xs_dict_set(snac.config, "metadata", md); | ||
| 3727 | } | ||
| 3728 | 3878 | ||
| 3729 | /* uploads */ | 3879 | /* uploads */ |
| 3730 | const char *uploads[] = { "avatar", "header", NULL }; | 3880 | const char *uploads[] = { "avatar", "header", NULL }; |