summaryrefslogtreecommitdiff
path: root/mastoapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'mastoapi.c')
-rw-r--r--mastoapi.c202
1 files changed, 142 insertions, 60 deletions
diff --git a/mastoapi.c b/mastoapi.c
index 52aca08..f15c9c0 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -1459,6 +1459,7 @@ void credentials_get(char **body, char **ctype, int *status, snac snac)
1459 acct = xs_dict_append(acct, "last_status_at", xs_dict_get(snac.config, "published")); 1459 acct = xs_dict_append(acct, "last_status_at", xs_dict_get(snac.config, "published"));
1460 acct = xs_dict_append(acct, "note", xs_dict_get(snac.config, "bio")); 1460 acct = xs_dict_append(acct, "note", xs_dict_get(snac.config, "bio"));
1461 acct = xs_dict_append(acct, "url", snac.actor); 1461 acct = xs_dict_append(acct, "url", snac.actor);
1462 acct = xs_dict_append(acct, "uri", snac.actor);
1462 1463
1463 acct = xs_dict_append(acct, "locked", 1464 acct = xs_dict_append(acct, "locked",
1464 xs_stock(xs_is_true(xs_dict_get(snac.config, "approve_followers")) ? XSTYPE_TRUE : XSTYPE_FALSE)); 1465 xs_stock(xs_is_true(xs_dict_get(snac.config, "approve_followers")) ? XSTYPE_TRUE : XSTYPE_FALSE));
@@ -1809,6 +1810,37 @@ xs_list *mastoapi_account_lists(snac *user, const char *uid)
1809} 1810}
1810 1811
1811 1812
1813xs_list *build_childrens(const xs_dict *msg, snac *snac1) {
1814 xs_list *ret = xs_list_new();
1815 xs *children = object_children(xs_dict_get(msg, "id"));
1816 char *p = children;
1817 const xs_str *v;
1818
1819 while (xs_list_iter(&p, &v)) {
1820 xs *m2 = NULL;
1821
1822 if (valid_status(timeline_get_by_md5(snac1, v, &m2))) {
1823 if (xs_is_null(xs_dict_get(m2, "name"))) {
1824 xs *st = mastoapi_status(snac1, m2);
1825
1826 if (st) {
1827 /* childrens children */
1828 xs *childs = build_childrens(m2, snac1);
1829 ret = xs_list_append(ret, st);
1830 if (xs_list_len(childs)) {
1831 char *p2 = childs;
1832 while (xs_list_iter(&p2, &v))
1833 ret = xs_list_append(ret, v);
1834
1835 }
1836 }
1837 }
1838 }
1839 }
1840 return ret;
1841}
1842
1843
1812int mastoapi_get_handler(const xs_dict *req, const char *q_path, 1844int mastoapi_get_handler(const xs_dict *req, const char *q_path,
1813 char **body, int *b_size, char **ctype, xs_str **link) 1845 char **body, int *b_size, char **ctype, xs_str **link)
1814{ 1846{
@@ -2616,19 +2648,33 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
2616 if (strcmp(cmd, "/v1/custom_emojis") == 0) { /** **/ 2648 if (strcmp(cmd, "/v1/custom_emojis") == 0) { /** **/
2617 xs *emo = emojis(); 2649 xs *emo = emojis();
2618 xs *list = xs_list_new(); 2650 xs *list = xs_list_new();
2619 int c = 0;
2620 const xs_str *k; 2651 const xs_str *k;
2621 const xs_val *v; 2652 const xs_val *v;
2622 while(xs_dict_next(emo, &k, &v, &c)) { 2653 xs_dict_foreach(emo, k, v) {
2623 xs *current = xs_dict_new(); 2654 xs *current = xs_dict_new();
2624 if (xs_startswith(v, "https://") && xs_startswith((xs_mime_by_ext(v)), "image/")) { 2655 if ((xs_startswith(v, "https://") && xs_startswith((xs_mime_by_ext(v)), "image/")) || xs_type(v) == XSTYPE_DICT) {
2625 /* remove first and last colon */ 2656 /* remove first and last colon */
2626 xs *shortcode = xs_replace(k, ":", ""); 2657 if (xs_type(v) == XSTYPE_DICT) {
2627 current = xs_dict_append(current, "shortcode", shortcode); 2658 const char *v2;
2628 current = xs_dict_append(current, "url", v); 2659 const char *cat = k;
2629 current = xs_dict_append(current, "static_url", v); 2660 xs_dict_foreach(v, k, v2) {
2630 current = xs_dict_append(current, "visible_in_picker", xs_stock(XSTYPE_TRUE)); 2661 xs *shortcode = xs_replace(k, ":", "");
2631 list = xs_list_append(list, current); 2662 current = xs_dict_append(current, "shortcode", shortcode);
2663 current = xs_dict_append(current, "url", v2);
2664 current = xs_dict_append(current, "static_url", v2);
2665 current = xs_dict_append(current, "visible_in_picker", xs_stock(XSTYPE_TRUE));
2666 current = xs_dict_append(current, "category", cat);
2667 list = xs_list_append(list, current);
2668 }
2669 }
2670 else {
2671 xs *shortcode = xs_replace(k, ":", "");
2672 current = xs_dict_append(current, "shortcode", shortcode);
2673 current = xs_dict_append(current, "url", v);
2674 current = xs_dict_append(current, "static_url", v);
2675 current = xs_dict_append(current, "visible_in_picker", xs_stock(XSTYPE_TRUE));
2676 list = xs_list_append(list, current);
2677 }
2632 } 2678 }
2633 } 2679 }
2634 *body = xs_json_dumps(list, 0); 2680 *body = xs_json_dumps(list, 0);
@@ -2821,8 +2867,6 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
2821 /* return ancestors and children */ 2867 /* return ancestors and children */
2822 xs *anc = xs_list_new(); 2868 xs *anc = xs_list_new();
2823 xs *des = xs_list_new(); 2869 xs *des = xs_list_new();
2824 xs_list *p;
2825 const xs_str *v;
2826 char pid[MD5_HEX_SIZE]; 2870 char pid[MD5_HEX_SIZE];
2827 2871
2828 /* build the [grand]parent list, moving up */ 2872 /* build the [grand]parent list, moving up */
@@ -2842,21 +2886,9 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
2842 } 2886 }
2843 2887
2844 /* build the children list */ 2888 /* build the children list */
2845 xs *children = object_children(xs_dict_get(msg, "id")); 2889 xs *childs = build_childrens(msg, &snac1);
2846 p = children; 2890 if (xs_list_len(childs) > 0)
2847 2891 des = xs_list_cat(des, childs);
2848 while (xs_list_iter(&p, &v)) {
2849 xs *m2 = NULL;
2850
2851 if (valid_status(timeline_get_by_md5(&snac1, v, &m2))) {
2852 if (xs_is_null(xs_dict_get(m2, "name"))) {
2853 xs *st = mastoapi_status(&snac1, m2);
2854
2855 if (st)
2856 des = xs_list_append(des, st);
2857 }
2858 }
2859 }
2860 2892
2861 out = xs_dict_new(); 2893 out = xs_dict_new();
2862 out = xs_dict_append(out, "ancestors", anc); 2894 out = xs_dict_append(out, "ancestors", anc);
@@ -3208,6 +3240,7 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path,
3208 app = xs_dict_append(app, "client_secret", csec); 3240 app = xs_dict_append(app, "client_secret", csec);
3209 app = xs_dict_append(app, "vapid_key", vkey); 3241 app = xs_dict_append(app, "vapid_key", vkey);
3210 app = xs_dict_append(app, "id", id); 3242 app = xs_dict_append(app, "id", id);
3243 app = xs_dict_append(app, "client_secret_expires_at", xs_stock(0));
3211 3244
3212 *body = xs_json_dumps(app, 4); 3245 *body = xs_json_dumps(app, 4);
3213 *ctype = "application/json"; 3246 *ctype = "application/json";
@@ -3227,12 +3260,16 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path,
3227 if (strcmp(cmd, "/v1/statuses") == 0) { /** **/ 3260 if (strcmp(cmd, "/v1/statuses") == 0) { /** **/
3228 if (logged_in) { 3261 if (logged_in) {
3229 /* post a new Note */ 3262 /* post a new Note */
3230 const char *content = xs_dict_get(args, "status"); 3263 const char *content = xs_dict_get(args, "status");
3231 const char *mid = xs_dict_get(args, "in_reply_to_id"); 3264 const char *mid = xs_dict_get(args, "in_reply_to_id");
3232 const char *visibility = xs_dict_get(args, "visibility"); 3265 const char *visibility = xs_dict_get(args, "visibility");
3233 const char *summary = xs_dict_get(args, "spoiler_text"); 3266 const char *summary = xs_dict_get(args, "spoiler_text");
3234 const char *media_ids = xs_dict_get(args, "media_ids"); 3267 const char *poll_opts = xs_dict_get(args, "poll[options][]");
3235 const char *language = xs_dict_get(args, "language"); 3268 const char *poll_end_secs = xs_dict_get(args, "poll[expires_in]");
3269 const char *poll_multiple = xs_dict_get(args, "poll[multiple]");
3270 // const char *poll_hide_totals = xs_dict_get(args, "poll[hide_totals]");
3271 const char *media_ids = xs_dict_get(args, "media_ids");
3272 const char *language = xs_dict_get(args, "language");
3236 3273
3237 if (xs_is_null(media_ids)) 3274 if (xs_is_null(media_ids))
3238 media_ids = xs_dict_get(args, "media_ids[]"); 3275 media_ids = xs_dict_get(args, "media_ids[]");
@@ -3255,8 +3292,8 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path,
3255 irt = xs_dup(xs_dict_get(r_msg, "id")); 3292 irt = xs_dup(xs_dict_get(r_msg, "id"));
3256 } 3293 }
3257 3294
3258 /* does it have attachments? */ 3295 /* does it have attachments (and no poll)? */
3259 if (!xs_is_null(media_ids)) { 3296 if (!xs_is_null(media_ids) && xs_is_null(poll_end_secs) && xs_is_null(poll_opts)) {
3260 xs *mi = NULL; 3297 xs *mi = NULL;
3261 3298
3262 if (xs_type(media_ids) == XSTYPE_LIST) 3299 if (xs_type(media_ids) == XSTYPE_LIST)
@@ -3282,6 +3319,8 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path,
3282 } 3319 }
3283 3320
3284 /* prepare the message */ 3321 /* prepare the message */
3322 xs *msg = NULL;
3323
3285 int scope = SCOPE_MENTIONED; 3324 int scope = SCOPE_MENTIONED;
3286 if (strcmp(visibility, "unlisted") == 0) 3325 if (strcmp(visibility, "unlisted") == 0)
3287 scope = SCOPE_UNLISTED; 3326 scope = SCOPE_UNLISTED;
@@ -3292,7 +3331,29 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path,
3292 if (strcmp(visibility, "private") == 0) 3331 if (strcmp(visibility, "private") == 0)
3293 scope = SCOPE_FOLLOWERS; 3332 scope = SCOPE_FOLLOWERS;
3294 3333
3295 xs *msg = msg_note(&snac, content, NULL, irt, attach_list, scope, language, NULL); 3334 /* does it have a poll? */
3335 if (!xs_is_null(poll_opts) && !xs_is_null(poll_end_secs)) {
3336 xs *po = NULL;
3337 int end_secs = atoi(poll_end_secs);
3338 int multiple = 0;
3339
3340 if (xs_type(poll_opts) == XSTYPE_LIST)
3341 po = xs_dup(poll_opts);
3342 else {
3343 po = xs_list_new();
3344 po = xs_list_append(po, poll_opts);
3345 }
3346
3347 if (!xs_is_null(poll_multiple) && strcmp(poll_multiple, "true") == 0)
3348 multiple = 1;
3349
3350 msg = msg_question(&snac, content, attach_list,
3351 poll_opts, multiple, end_secs);
3352
3353 enqueue_close_question(&snac, xs_dict_get(msg, "id"), end_secs);
3354 }
3355 else
3356 msg = msg_note(&snac, content, NULL, irt, attach_list, scope, language, NULL);
3296 3357
3297 if (!xs_is_null(summary) && *summary) { 3358 if (!xs_is_null(summary) && *summary) {
3298 msg = xs_dict_set(msg, "sensitive", xs_stock(XSTYPE_TRUE)); 3359 msg = xs_dict_set(msg, "sensitive", xs_stock(XSTYPE_TRUE));
@@ -3654,44 +3715,65 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path,
3654 /* skip the 'fake' part of the id */ 3715 /* skip the 'fake' part of the id */
3655 mid = MID_TO_MD5(mid); 3716 mid = MID_TO_MD5(mid);
3656 3717
3657 if (valid_status(timeline_get_by_md5(&snac, mid, &msg))) { 3718 /* try timeline first, then global object store for remote posts */
3719 int found = valid_status(timeline_get_by_md5(&snac, mid, &msg));
3720 if (!found)
3721 found = valid_status(object_get_by_md5(mid, &msg));
3722
3723 if (found) {
3658 const char *id = xs_dict_get(msg, "id"); 3724 const char *id = xs_dict_get(msg, "id");
3659 const char *atto = get_atto(msg); 3725 const char *atto = get_atto(msg);
3726 int closed = 0;
3727 const char *f_closed = NULL;
3660 3728
3661 const xs_list *opts = xs_dict_get(msg, "oneOf"); 3729 if ((f_closed = xs_dict_get(msg, "closed")) != NULL) {
3662 if (opts == NULL) 3730 /* it has a closed date... but is it in the past? */
3663 opts = xs_dict_get(msg, "anyOf"); 3731 time_t t0 = time(NULL);
3732 time_t t1 = xs_parse_iso_date(f_closed, 0);
3664 3733
3665 if (op == NULL) { 3734 if (t1 < t0)
3735 closed = 1;
3666 } 3736 }
3667 else
3668 if (strcmp(op, "votes") == 0) {
3669 const xs_list *choices = xs_dict_get(args, "choices[]");
3670 3737
3671 if (xs_is_null(choices)) 3738 if (closed || was_question_voted(&snac, id))
3672 choices = xs_dict_get(args, "choices"); 3739 status = HTTP_STATUS_UNPROCESSABLE_CONTENT;
3740 else {
3741 const xs_list *opts = xs_dict_get(msg, "oneOf");
3742 if (opts == NULL)
3743 opts = xs_dict_get(msg, "anyOf");
3673 3744
3674 if (xs_type(choices) == XSTYPE_LIST) { 3745 if (op == NULL) {
3675 const xs_str *v; 3746 }
3747 else {
3748 if (strcmp(op, "votes") == 0) {
3749 const xs_list *choices = xs_dict_get(args, "choices[]");
3676 3750
3677 int c = 0; 3751 if (xs_is_null(choices))
3678 while (xs_list_next(choices, &v, &c)) { 3752 choices = xs_dict_get(args, "choices");
3679 int io = atoi(v);
3680 const xs_dict *o = xs_list_get(opts, io);
3681 3753
3682 if (o) { 3754 if (xs_type(choices) == XSTYPE_LIST) {
3683 const char *name = xs_dict_get(o, "name"); 3755 const xs_str *v;
3684 3756
3685 xs *msg = msg_note(&snac, "", atto, (char *)id, NULL, 1, NULL, NULL); 3757 int c = 0;
3686 msg = xs_dict_append(msg, "name", name); 3758 while (xs_list_next(choices, &v, &c)) {
3759 int io = atoi(v);
3760 const xs_dict *o = xs_list_get(opts, io);
3687 3761
3688 xs *c_msg = msg_create(&snac, msg); 3762 if (o) {
3689 enqueue_message(&snac, c_msg); 3763 const char *name = xs_dict_get(o, "name");
3690 timeline_add(&snac, xs_dict_get(msg, "id"), msg); 3764
3765 xs *msg = msg_note(&snac, "", atto, (char *)id, NULL, 1, NULL, NULL);
3766 msg = xs_dict_append(msg, "name", name);
3767
3768 xs *c_msg = msg_create(&snac, msg);
3769 enqueue_message(&snac, c_msg);
3770 timeline_add(&snac, xs_dict_get(msg, "id"), msg);
3771 }
3772 }
3773
3774 out = mastoapi_poll(&snac, msg);
3691 } 3775 }
3692 } 3776 }
3693
3694 out = mastoapi_poll(&snac, msg);
3695 } 3777 }
3696 } 3778 }
3697 } 3779 }