From 8275a5f4d8764ebc9f9f82a4db377bacfa9fbc75 Mon Sep 17 00:00:00 2001 From: default Date: Mon, 29 Apr 2024 07:43:01 +0200 Subject: Start of list support. --- snac.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'snac.h') diff --git a/snac.h b/snac.h index cac09a9..1cd8603 100644 --- a/snac.h +++ b/snac.h @@ -174,6 +174,8 @@ int is_hidden(snac *snac, const char *id); void tag_index(const char *id, const xs_dict *obj); xs_list *tag_search(char *tag, int skip, int show); +xs_list *list_maint(snac *user, const char *list, int op); + int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); int actor_get_refresh(snac *user, const char *actor, xs_dict **data); -- cgit v1.2.3 From 9a13e330f12aaf0fc1535e922efbf315308d252b Mon Sep 17 00:00:00 2001 From: default Date: Mon, 29 Apr 2024 08:29:18 +0200 Subject: More work in lists. --- data.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-------------- mastoapi.c | 51 +++++++++++++++++++++++++++++++++++++++++---------- snac.h | 2 +- 3 files changed, 90 insertions(+), 25 deletions(-) (limited to 'snac.h') diff --git a/data.c b/data.c index ab597e7..46d95b4 100644 --- a/data.c +++ b/data.c @@ -1731,9 +1731,9 @@ xs_list *tag_search(char *tag, int skip, int show) /** lists **/ -xs_list *list_maint(snac *user, const char *list, int op) +xs_val *list_maint(snac *user, const char *list, int op) { - xs_list *l = NULL; + xs_val *l = NULL; switch (op) { case 0: /** list of lists **/ @@ -1752,10 +1752,12 @@ xs_list *list_maint(snac *user, const char *list, int op) fclose(f); title = xs_strip_i(title); - xs *md5 = xs_md5_hex(title, strlen(title)); + + xs *v2 = xs_replace(v, ".id", ""); + xs *l2 = xs_split(v2, "/"); /* return [ list_id, list_title ] */ - l = xs_list_append(l, xs_list_append(xs_list_new(), md5, title)); + l = xs_list_append(l, xs_list_append(xs_list_new(), xs_list_get(l2, -1), title)); } } } @@ -1764,26 +1766,58 @@ xs_list *list_maint(snac *user, const char *list, int op) case 1: /** create new list (list is the name) **/ { - FILE *f; - xs *dir = xs_fmt("%s/list/", user->basedir); - xs *md5 = xs_md5_hex(list, strlen(list)); + xs *lol = list_maint(user, NULL, 0); + int c = 0; + xs_list *v; + int add = 1; - mkdirx(dir); + /* check if this list name already exists */ + while (xs_list_next(lol, &v, &c)) { + if (strcmp(xs_list_get(v, 1), list) == 0) { + add = 0; + break; + } + } - xs *fn = xs_fmt("%s%s.id", dir, md5); + if (add) { + FILE *f; + xs *dir = xs_fmt("%s/list/", user->basedir); + xs *id = xs_fmt("%010x", time(NULL)); - if ((f = fopen(fn, "w")) != NULL) { - fprintf(f, "%s\n", list); - fclose(f); + mkdirx(dir); + + xs *fn = xs_fmt("%s%s.id", dir, id); + + if ((f = fopen(fn, "w")) != NULL) { + fprintf(f, "%s\n", list); + fclose(f); + } + + l = xs_stock(XSTYPE_TRUE); } + else + l = xs_stock(XSTYPE_FALSE); } break; - case 2: /** delete list (list is md5 id) **/ + case 2: /** delete list (list is the id) **/ + { + if (xs_is_hex(list)) { + xs *fn = xs_fmt("%s/list/%s.id", user->basedir, list); + unlink(fn); + + fn = xs_replace_i(fn, ".id", ".lst"); + unlink(fn); + + fn = xs_replace_i(fn, ".list", ".idx"); + unlink(fn); + } + } + break; - case 3: /** list content (list is md5 id) **/ + case 3: /** list content (list is the id) **/ break; } diff --git a/mastoapi.c b/mastoapi.c index 20d6208..54d2777 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1766,7 +1766,6 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, } else if (strcmp(cmd, "/v1/lists") == 0) { /** **/ - /* snac does not support lists */ if (logged_in) { xs *lol = list_maint(&snac1, NULL, 0); xs *l = xs_list_new(); @@ -2656,17 +2655,22 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, if (xs_type(title) == XSTYPE_STRING) { /* add the list */ - list_maint(&snac, title, 1); - xs *out = xs_dict_new(); - out = xs_dict_append(out, "title", title); - out = xs_dict_append(out, "replies_policy", xs_dict_get_def(args, "replies_policy", "list")); - out = xs_dict_append(out, "exclusive", xs_stock(XSTYPE_FALSE)); + if (xs_type(list_maint(&snac, title, 1)) == XSTYPE_TRUE) { + out = xs_dict_append(out, "title", title); + out = xs_dict_append(out, "replies_policy", xs_dict_get_def(args, "replies_policy", "list")); + out = xs_dict_append(out, "exclusive", xs_stock(XSTYPE_FALSE)); + + status = 200; + } + else { + out = xs_dict_append(out, "error", "cannot create list"); + status = 422; + } *body = xs_json_dumps(out, 4); *ctype = "application/json"; - status = 200; } else status = 422; @@ -2691,16 +2695,43 @@ int mastoapi_delete_handler(const xs_dict *req, const char *q_path, (void)b_size; (void)ctype; + int status = 404; + if (!xs_startswith(q_path, "/api/v1/") && !xs_startswith(q_path, "/api/v2/")) return 0; - srv_debug(1, xs_fmt("mastoapi_delete_handler %s", q_path)); + snac snac = {0}; + int logged_in = process_auth_token(&snac, req); + xs *cmd = xs_replace_n(q_path, "/api", "", 1); + if (xs_startswith(cmd, "/v1/push/subscription") || xs_startswith(cmd, "/v2/push/subscription")) { /** **/ // pretend we deleted it, since it doesn't exist anyway - return 200; + status = 200; } - return 0; + else + if (xs_startswith(cmd, "/v1/lists/")) { + if (logged_in) { + xs *l = xs_split(cmd, "/"); + char *id = xs_list_get(l, -1); + + if (xs_is_hex(id)) { + list_maint(&snac, id, 2); + } + + status = 200; + } + else + status = 401; + } + + /* user cleanup */ + if (logged_in) + user_free(&snac); + + srv_debug(1, xs_fmt("mastoapi_delete_handler %s %d", q_path, status)); + + return status; } diff --git a/snac.h b/snac.h index 1cd8603..f76f8e0 100644 --- a/snac.h +++ b/snac.h @@ -174,7 +174,7 @@ int is_hidden(snac *snac, const char *id); void tag_index(const char *id, const xs_dict *obj); xs_list *tag_search(char *tag, int skip, int show); -xs_list *list_maint(snac *user, const char *list, int op); +xs_val *list_maint(snac *user, const char *list, int op); int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); -- cgit v1.2.3 From 29fb43079761796e34209611ec93bd651b871cab Mon Sep 17 00:00:00 2001 From: default Date: Mon, 29 Apr 2024 09:26:37 +0200 Subject: More work in lists. --- data.c | 38 +++++++++++++++++++-- httpd.c | 2 +- mastoapi.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------ snac.h | 6 ++-- 4 files changed, 141 insertions(+), 15 deletions(-) (limited to 'snac.h') diff --git a/data.c b/data.c index 46d95b4..ed65d32 100644 --- a/data.c +++ b/data.c @@ -1732,6 +1732,7 @@ xs_list *tag_search(char *tag, int skip, int show) /** lists **/ xs_val *list_maint(snac *user, const char *list, int op) +/* list maintenance */ { xs_val *l = NULL; @@ -1810,15 +1811,48 @@ xs_val *list_maint(snac *user, const char *list, int op) fn = xs_replace_i(fn, ".id", ".lst"); unlink(fn); - fn = xs_replace_i(fn, ".list", ".idx"); + fn = xs_replace_i(fn, ".lst", ".idx"); unlink(fn); } } break; + } + + return l; +} + + +xs_val *list_content(snac *user, const char *list, const char *actor_md5, int op) +/* list content management */ +{ + xs_val *l = NULL; + + if (!xs_is_hex(list)) + return NULL; + + if (actor_md5 != NULL && !xs_is_hex(actor_md5)) + return NULL; + + xs *fn = xs_fmt("%s/list/%s.lst", user->basedir, list); + + switch (op) { + case 0: /** list content **/ + l = index_list(fn, XS_ALL); - case 3: /** list content (list is the id) **/ break; + + case 1: /** append actor to list **/ + if (actor_md5 != NULL) { + if (!index_in(fn, actor_md5)) + index_add_md5(fn, actor_md5); + } + + break; + + case 2: /** delete actor from list **/ + if (actor_md5 != NULL) + index_del_md5(fn, actor_md5); } return l; diff --git a/httpd.c b/httpd.c index e402e61..bda8159 100644 --- a/httpd.c +++ b/httpd.c @@ -360,7 +360,7 @@ void httpd_connection(FILE *f) #ifndef NO_MASTODON_API if (status == 0) status = mastoapi_delete_handler(req, q_path, - &body, &b_size, &ctype); + payload, p_size, &body, &b_size, &ctype); #endif } diff --git a/mastoapi.c b/mastoapi.c index 54d2777..8c41efb 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1765,7 +1765,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, status = 200; } else - if (strcmp(cmd, "/v1/lists") == 0) { /** **/ + if (strcmp(cmd, "/v1/lists") == 0) { /** list of lists **/ if (logged_in) { xs *lol = list_maint(&snac1, NULL, 0); xs *l = xs_list_new(); @@ -1789,6 +1789,36 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, } } else + if (xs_startswith(cmd, "/v1/lists/")) { /** list information **/ + if (logged_in) { + xs *l = xs_split(cmd, "/"); + char *op = xs_list_get(l, -1); + char *id = xs_list_get(l, -2); + + if (op && id && xs_is_hex(id)) { + if (strcmp(op, "accounts") == 0) { + xs *actors = list_content(&snac1, id, NULL, 0); + xs *out = xs_list_new(); + int c = 0; + char *v; + + while (xs_list_next(actors, &v, &c)) { + xs *actor = NULL; + + if (valid_status(object_get_by_md5(v, &actor))) { + xs *acct = mastoapi_account(actor); + out = xs_list_append(out, acct); + } + } + + *body = xs_json_dumps(out, 4); + *ctype = "application/json"; + status = 200; + } + } + } + } + else if (strcmp(cmd, "/v1/scheduled_statuses") == 0) { /** **/ /* snac does not schedule notes */ *body = xs_dup("[]"); @@ -2676,6 +2706,29 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, status = 422; } } + if (xs_startswith(cmd, "/v1/lists/")) { /** list maintenance **/ + if (logged_in) { + xs *l = xs_split(cmd, "/"); + char *op = xs_list_get(l, -1); + char *id = xs_list_get(l, -2); + + if (op && id && xs_is_hex(id)) { + if (strcmp(op, "accounts") == 0) { + xs_list *accts = xs_dict_get(args, "account_ids[]"); + int c = 0; + char *v; + + while (xs_list_next(accts, &v, &c)) { + list_content(&snac, id, v, 1); + } + + status = 200; + } + } + } + else + status = 422; + } /* user cleanup */ if (logged_in) @@ -2688,18 +2741,39 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, int mastoapi_delete_handler(const xs_dict *req, const char *q_path, - char **body, int *b_size, char **ctype) { - - (void)req; + const char *payload, int p_size, + char **body, int *b_size, char **ctype) +{ + (void)p_size; (void)body; (void)b_size; (void)ctype; - int status = 404; - if (!xs_startswith(q_path, "/api/v1/") && !xs_startswith(q_path, "/api/v2/")) return 0; + int status = 404; + xs *args = NULL; + char *i_ctype = xs_dict_get(req, "content-type"); + + if (i_ctype && xs_startswith(i_ctype, "application/json")) { + if (!xs_is_null(payload)) + args = xs_json_loads(payload); + } + else if (i_ctype && xs_startswith(i_ctype, "application/x-www-form-urlencoded")) + { + // Some apps send form data instead of json so we should cater for those + if (!xs_is_null(payload)) { + xs *upl = xs_url_dec(payload); + args = xs_url_vars(upl); + } + } + else + args = xs_dup(xs_dict_get(req, "p_vars")); + + if (args == NULL) + return 400; + snac snac = {0}; int logged_in = process_auth_token(&snac, req); @@ -2713,10 +2787,26 @@ int mastoapi_delete_handler(const xs_dict *req, const char *q_path, if (xs_startswith(cmd, "/v1/lists/")) { if (logged_in) { xs *l = xs_split(cmd, "/"); - char *id = xs_list_get(l, -1); - - if (xs_is_hex(id)) { - list_maint(&snac, id, 2); + char *p = xs_list_get(l, -1); + + if (p) { + if (strcmp(p, "accounts") == 0) { + /* delete account from list */ + p = xs_list_get(l, -2); + xs_list *accts = xs_dict_get(args, "account_ids[]"); + int c = 0; + char *v; + + while (xs_list_next(accts, &v, &c)) { + list_content(&snac, p, v, 2); + } + } + else { + /* delete list */ + if (xs_is_hex(p)) { + list_maint(&snac, p, 2); + } + } } status = 200; diff --git a/snac.h b/snac.h index f76f8e0..da8b6f9 100644 --- a/snac.h +++ b/snac.h @@ -175,6 +175,7 @@ void tag_index(const char *id, const xs_dict *obj); xs_list *tag_search(char *tag, int skip, int show); xs_val *list_maint(snac *user, const char *list, int op); +xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); @@ -339,11 +340,12 @@ int oauth_post_handler(const xs_dict *req, const char *q_path, char **body, int *b_size, char **ctype); int mastoapi_get_handler(const xs_dict *req, const char *q_path, char **body, int *b_size, char **ctype); -int mastoapi_delete_handler(const xs_dict *req, const char *q_path, - char **body, int *b_size, char **ctype); int mastoapi_post_handler(const xs_dict *req, const char *q_path, const char *payload, int p_size, char **body, int *b_size, char **ctype); +int mastoapi_delete_handler(const xs_dict *req, const char *q_path, + const char *payload, int p_size, + char **body, int *b_size, char **ctype); int mastoapi_put_handler(const xs_dict *req, const char *q_path, const char *payload, int p_size, char **body, int *b_size, char **ctype); -- cgit v1.2.3 From 7f322302e5b5cf0345de110afe78767bfb03ae51 Mon Sep 17 00:00:00 2001 From: default Date: Mon, 29 Apr 2024 09:50:22 +0200 Subject: New function list_distribute(). --- data.c | 28 ++++++++++++++++++++++++++++ snac.h | 1 + 2 files changed, 29 insertions(+) (limited to 'snac.h') diff --git a/data.c b/data.c index ed65d32..07b38ec 100644 --- a/data.c +++ b/data.c @@ -1154,6 +1154,8 @@ int timeline_add(snac *snac, const char *id, const xs_dict *o_msg) tag_index(id, o_msg); + list_distribute(snac, o_msg); + snac_debug(snac, 1, xs_fmt("timeline_add %s", id)); return ret; @@ -1859,6 +1861,32 @@ xs_val *list_content(snac *user, const char *list, const char *actor_md5, int op } +void list_distribute(snac *user, const xs_dict *post) +/* distributes the post to all appropriate lists */ +{ + char *atto = get_atto(post); + char *id = xs_dict_get(post, "id"); + + if (xs_type(atto) == XSTYPE_STRING && xs_type(id) == XSTYPE_STRING) { + xs *a_md5 = xs_md5_hex(atto, strlen(atto)); + xs *i_md5 = xs_md5_hex(id, strlen(id)); + xs *spec = xs_fmt("%s/list/" "*.lst", user->basedir); + xs *ls = xs_glob(spec, 0, 0); + int c = 0; + char *v; + + while (xs_list_next(ls, &v, &c)) { + /* is the actor in this list? */ + if (index_in_md5(v, a_md5)) { + /* it is; add post md5 to its timeline */ + xs *idx = xs_replace(v, ".lst", ".idx"); + index_add(idx, i_md5); + } + } + } +} + + /** static data **/ static int _load_raw_file(const char *fn, xs_val **data, int *size, diff --git a/snac.h b/snac.h index da8b6f9..b478c7e 100644 --- a/snac.h +++ b/snac.h @@ -176,6 +176,7 @@ xs_list *tag_search(char *tag, int skip, int show); xs_val *list_maint(snac *user, const char *list, int op); xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); +void list_distribute(snac *user, const xs_dict *post); int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); -- cgit v1.2.3 From 6a77c634ad9938744bae6d718b209557fa37018c Mon Sep 17 00:00:00 2001 From: default Date: Tue, 30 Apr 2024 19:41:08 +0200 Subject: Also add announces to lists. --- activitypub.c | 3 +++ data.c | 15 +++++++++------ snac.h | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) (limited to 'snac.h') diff --git a/activitypub.c b/activitypub.c index 94c0d30..2691a6a 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2099,6 +2099,9 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) snac_log(snac, xs_fmt("repeated 'Announce' from %s to %s", actor, object)); + /* distribute the post with the actor as 'proxy' */ + list_distribute(snac, actor, a_msg); + do_notify = 1; } else diff --git a/data.c b/data.c index 82d0acc..db544f4 100644 --- a/data.c +++ b/data.c @@ -1165,7 +1165,7 @@ int timeline_add(snac *snac, const char *id, const xs_dict *o_msg) tag_index(id, o_msg); - list_distribute(snac, o_msg); + list_distribute(snac, NULL, o_msg); snac_debug(snac, 1, xs_fmt("timeline_add %s", id)); @@ -1881,14 +1881,17 @@ xs_val *list_content(snac *user, const char *list, const char *actor_md5, int op } -void list_distribute(snac *user, const xs_dict *post) +void list_distribute(snac *user, const char *who, const xs_dict *post) /* distributes the post to all appropriate lists */ { - char *atto = get_atto(post); - char *id = xs_dict_get(post, "id"); + char *id = xs_dict_get(post, "id"); - if (xs_type(atto) == XSTYPE_STRING && xs_type(id) == XSTYPE_STRING) { - xs *a_md5 = xs_md5_hex(atto, strlen(atto)); + /* if who is not set, use the attributedTo in the message */ + if (xs_is_null(who)) + who = get_atto(post); + + if (xs_type(who) == XSTYPE_STRING && xs_type(id) == XSTYPE_STRING) { + xs *a_md5 = xs_md5_hex(who, strlen(who)); xs *i_md5 = xs_md5_hex(id, strlen(id)); xs *spec = xs_fmt("%s/list/" "*.lst", user->basedir); xs *ls = xs_glob(spec, 0, 0); diff --git a/snac.h b/snac.h index b478c7e..74e58cd 100644 --- a/snac.h +++ b/snac.h @@ -176,7 +176,7 @@ xs_list *tag_search(char *tag, int skip, int show); xs_val *list_maint(snac *user, const char *list, int op); xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); -void list_distribute(snac *user, const xs_dict *post); +void list_distribute(snac *user, const char *who, const xs_dict *post); int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); -- cgit v1.2.3 From fc76ae4e9e721a1ec5fbcf3b509d5a47cf48cd61 Mon Sep 17 00:00:00 2001 From: default Date: Sun, 5 May 2024 01:38:22 +0200 Subject: New function enqueue_object_request(). --- activitypub.c | 16 ++++++++++++++++ data.c | 15 +++++++++++++++ main.c | 6 ++++++ snac.h | 1 + 4 files changed, 38 insertions(+) (limited to 'snac.h') diff --git a/activitypub.c b/activitypub.c index a8a7db7..bb919ed 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2313,6 +2313,22 @@ void process_user_queue_item(snac *snac, xs_dict *q_item) timeline_request_replies(snac, id); } else + if (strcmp(type, "object_request") == 0) { + const char *id = xs_dict_get(q_item, "message"); + + if (!xs_is_null(id)) { + int status; + xs *data = NULL; + + status = activitypub_request(snac, id, &data); + + if (valid_status(status)) + object_add_ow(id, data); + + snac_debug(snac, 1, xs_fmt("object_request %s %d", id, status)); + } + } + else if (strcmp(type, "verify_links") == 0) { verify_links(snac); } diff --git a/data.c b/data.c index db544f4..4d753a9 100644 --- a/data.c +++ b/data.c @@ -2651,6 +2651,21 @@ void enqueue_close_question(snac *user, const char *id, int end_secs) } +void enqueue_object_request(snac *user, const char *id, int forward_secs) +/* enqueues the request of an object in the future */ +{ + xs *qmsg = _new_qmsg("object_request", id, 0); + xs *ntid = tid(forward_secs); + xs *fn = xs_fmt("%s/queue/%s.json", user->basedir, ntid); + + qmsg = xs_dict_set(qmsg, "ntid", ntid); + + qmsg = _enqueue_put(fn, qmsg); + + snac_debug(user, 0, xs_fmt("enqueue_object_request %s", id)); +} + + void enqueue_verify_links(snac *user) /* enqueues a link verification */ { diff --git a/main.c b/main.c index 06cae78..6a38412 100644 --- a/main.c +++ b/main.c @@ -458,6 +458,12 @@ int main(int argc, char *argv[]) return 0; } + if (strcmp(cmd, "request2") == 0) { /** **/ + enqueue_object_request(&snac, url, 2); + + return 0; + } + if (strcmp(cmd, "actor") == 0) { /** **/ int status; xs *data = NULL; diff --git a/snac.h b/snac.h index 74e58cd..721d088 100644 --- a/snac.h +++ b/snac.h @@ -226,6 +226,7 @@ void enqueue_telegram(const xs_str *msg, const char *bot, const char *chat_id); void enqueue_ntfy(const xs_str *msg, const char *ntfy_server, const char *ntfy_token); void enqueue_message(snac *snac, const xs_dict *msg); void enqueue_close_question(snac *user, const char *id, int end_secs); +void enqueue_object_request(snac *user, const char *id, int forward_secs); void enqueue_verify_links(snac *user); void enqueue_actor_refresh(snac *user, const char *actor); void enqueue_request_replies(snac *user, const char *id); -- cgit v1.2.3 From 45357b8e6e36f973fc09c0a82a633e2d08b34eda Mon Sep 17 00:00:00 2001 From: default Date: Sun, 5 May 2024 11:00:29 +0200 Subject: New function timeline_to_rss(). --- html.c | 111 ++++++++++++++++++++++++++++++++++++----------------------------- snac.h | 1 + 2 files changed, 63 insertions(+), 49 deletions(-) (limited to 'snac.h') diff --git a/html.c b/html.c index 9de1cca..fe070c1 100644 --- a/html.c +++ b/html.c @@ -2728,55 +2728,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, xs_dict_get(srv_config, "host")); xs *rss_link = xs_fmt("%s.rss", snac.actor); - xs_html *rss = xs_html_tag("rss", - xs_html_attr("version", "0.91")); - - xs_html *channel = xs_html_tag("channel", - xs_html_tag("title", - xs_html_text(rss_title)), - xs_html_tag("language", - xs_html_text("en")), - xs_html_tag("link", - xs_html_text(rss_link)), - xs_html_tag("description", - xs_html_text(bio))); - - xs_html_add(rss, channel); - - xs_list *p = elems; - char *v; - - while (xs_list_iter(&p, &v)) { - xs *msg = NULL; - - if (!valid_status(timeline_get_by_md5(&snac, v, &msg))) - continue; - - char *id = xs_dict_get(msg, "id"); - char *content = xs_dict_get(msg, "content"); - - if (!xs_startswith(id, snac.actor)) - continue; - - /* create a title with the first line of the content */ - xs *es_title = xs_replace(content, "
", "\n"); - xs *title = xs_str_new(NULL); - int i; - - for (i = 0; es_title[i] && es_title[i] != '\n' && es_title[i] != '&' && i < 50; i++) - title = xs_append_m(title, &es_title[i], 1); - - xs_html_add(channel, - xs_html_tag("item", - xs_html_tag("title", - xs_html_text(title)), - xs_html_tag("link", - xs_html_text(id)), - xs_html_tag("description", - xs_html_text(content)))); - } - - *body = xs_html_render_s(rss, "\n"); + *body = timeline_to_rss(&snac, elems, rss_title, rss_link, bio); *b_size = strlen(*body); *ctype = "application/rss+xml; charset=utf-8"; status = 200; @@ -3336,3 +3288,64 @@ int html_post_handler(const xs_dict *req, const char *q_path, return status; } + + +xs_str *timeline_to_rss(snac *user, const xs_list *timeline, char *title, char *link, char *desc) +/* converts a timeline to rss */ +{ + xs_html *rss = xs_html_tag("rss", + xs_html_attr("version", "0.91")); + + xs_html *channel = xs_html_tag("channel", + xs_html_tag("title", + xs_html_text(title)), + xs_html_tag("language", + xs_html_text("en")), + xs_html_tag("link", + xs_html_text(link)), + xs_html_tag("description", + xs_html_text(desc))); + + xs_html_add(rss, channel); + + int c = 0; + char *v; + + while (xs_list_next(timeline, &v, &c)) { + xs *msg = NULL; + + if (user) { + if (!valid_status(timeline_get_by_md5(user, v, &msg))) + continue; + } + else { + if (!valid_status(object_get_by_md5(v, &msg))) + continue; + } + + char *id = xs_dict_get(msg, "id"); + char *content = xs_dict_get(msg, "content"); + + if (user && !xs_startswith(id, user->actor)) + continue; + + /* create a title with the first line of the content */ + xs *es_title = xs_replace(content, "
", "\n"); + xs *title = xs_str_new(NULL); + int i; + + for (i = 0; es_title[i] && es_title[i] != '\n' && es_title[i] != '&' && i < 50; i++) + title = xs_append_m(title, &es_title[i], 1); + + xs_html_add(channel, + xs_html_tag("item", + xs_html_tag("title", + xs_html_text(title)), + xs_html_tag("link", + xs_html_text(id)), + xs_html_tag("description", + xs_html_text(content)))); + } + + return xs_html_render_s(rss, "\n"); +} diff --git a/snac.h b/snac.h index 721d088..ae6e975 100644 --- a/snac.h +++ b/snac.h @@ -324,6 +324,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, int html_post_handler(const xs_dict *req, const char *q_path, char *payload, int p_size, char **body, int *b_size, char **ctype); +xs_str *timeline_to_rss(snac *user, const xs_list *timeline, char *title, char *link, char *desc); int snac_init(const char *_basedir); int adduser(const char *uid); -- cgit v1.2.3 From c5ae10af862d3c76c79e848fc4dbe69f80cfc214 Mon Sep 17 00:00:00 2001 From: default Date: Tue, 7 May 2024 10:24:38 +0200 Subject: Version 2.52 RELEASED. --- snac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'snac.h') diff --git a/snac.h b/snac.h index ae6e975..481a1ae 100644 --- a/snac.h +++ b/snac.h @@ -1,7 +1,7 @@ /* snac - A simple, minimalistic ActivityPub instance */ /* copyright (c) 2022 - 2024 grunfink et al. / MIT license */ -#define VERSION "2.52-dev" +#define VERSION "2.52" #define USER_AGENT "snac/" VERSION -- cgit v1.2.3 From 6b1721c977294ee28f54150579c36514aa3ee62a Mon Sep 17 00:00:00 2001 From: default Date: Tue, 7 May 2024 19:40:28 +0200 Subject: List timelines can now be (manually) navigated from the web UI. URLs are {srv_baseurl}/{user}/list/{list_id} (you must know the list id). --- data.c | 24 +++++++++++++++++++----- html.c | 23 +++++++++++++++++++++++ mastoapi.c | 2 +- snac.h | 1 + 4 files changed, 44 insertions(+), 6 deletions(-) (limited to 'snac.h') diff --git a/data.c b/data.c index b9c1141..5b4936b 100644 --- a/data.c +++ b/data.c @@ -1836,6 +1836,23 @@ xs_val *list_maint(snac *user, const char *list, int op) } +xs_list *list_timeline(snac *user, const char *list, int skip, int show) +/* returns the timeline of a list */ +{ + xs_list *l = NULL; + + if (!xs_is_hex(list)) + return NULL; + + xs *fn = xs_fmt("%s/list/%s.idx", user->basedir, list); + + if (mtime(fn) > 0.0) + l = index_list_desc(fn, skip, show); + + return l; +} + + xs_val *list_content(snac *user, const char *list, const char *actor_md5, int op) /* list content management */ { @@ -1869,11 +1886,8 @@ xs_val *list_content(snac *user, const char *list, const char *actor_md5, int op break; - case 3: /** list timeline **/ - fn = xs_replace_i(fn, ".lst", ".idx"); - - l = index_list_desc(fn, 0, 2048); - + default: + srv_log(xs_fmt("ERROR: list_content: bad op %d", op)); break; } diff --git a/html.c b/html.c index ee5c2cd..b34fc81 100644 --- a/html.c +++ b/html.c @@ -2658,6 +2658,29 @@ int html_get_handler(const xs_dict *req, const char *q_path, } } else + if (xs_startswith(p_path, "list/")) { /** list timelines **/ + if (!login(&snac, req)) { + *body = xs_dup(uid); + status = 401; + } + else { + xs *l = xs_split(p_path, "/"); + char *lid = xs_list_get(l, -1); + + xs *list = list_timeline(&snac, lid, skip, show); + xs *next = list_timeline(&snac, lid, skip + show, 1); + + if (list != NULL) { + xs *base = xs_fmt("/list/%s", lid); + + *body = html_timeline(&snac, list, 0, skip, show, + xs_list_len(next), NULL, base, 0); + *b_size = strlen(*body); + status = 200; + } + } + } + else if (xs_startswith(p_path, "p/")) { /** a timeline with just one entry **/ if (xs_type(xs_dict_get(snac.config, "private")) == XSTYPE_TRUE) return 403; diff --git a/mastoapi.c b/mastoapi.c index 1f7f0b2..d39a6f9 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1669,7 +1669,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, xs *l = xs_split(cmd, "/"); char *list = xs_list_get(l, -1); - xs *timeline = list_content(&snac1, list, NULL, 3); + xs *timeline = list_timeline(&snac1, list, 0, 2048); xs *out = xs_list_new(); int c = 0; char *md5; diff --git a/snac.h b/snac.h index 481a1ae..ab8fc7c 100644 --- a/snac.h +++ b/snac.h @@ -175,6 +175,7 @@ void tag_index(const char *id, const xs_dict *obj); xs_list *tag_search(char *tag, int skip, int show); xs_val *list_maint(snac *user, const char *list, int op); +xs_list *list_timeline(snac *user, const char *list, int skip, int show); xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); void list_distribute(snac *user, const char *who, const xs_dict *post); -- cgit v1.2.3 From 82ec4ea95cb1040c5b9b983ec649dbde024d20f8 Mon Sep 17 00:00:00 2001 From: default Date: Tue, 7 May 2024 20:32:13 +0200 Subject: Minor "Back to top" "More..." link refactoring. --- html.c | 34 ++++++++++++++-------------------- httpd.c | 10 +++++++--- snac.h | 2 +- 3 files changed, 22 insertions(+), 24 deletions(-) (limited to 'snac.h') diff --git a/html.c b/html.c index 536879c..bd3179d 100644 --- a/html.c +++ b/html.c @@ -509,7 +509,7 @@ xs_html *html_instance_head(void) } -static xs_html *html_instance_body(char *tag) +static xs_html *html_instance_body(char *title) { char *host = xs_dict_get(srv_config, "host"); char *sdesc = xs_dict_get(srv_config, "short_description"); @@ -560,14 +560,11 @@ static xs_html *html_instance_body(char *tag) xs_html_text(handle))))); } - { - xs *l = tag ? xs_fmt(L("Search results for #%s"), tag) : - xs_dup(L("Recent posts by users in this instance")); - + if (title != NULL) { xs_html_add(body, xs_html_tag("h2", xs_html_attr("class", "snac-header"), - xs_html_text(l))); + xs_html_text(title))); } return body; @@ -1996,7 +1993,7 @@ xs_html *html_footer(void) xs_str *html_timeline(snac *user, const xs_list *list, int read_only, int skip, int show, int show_more, - char *tag, char *page, int utl) + char *title, char *page, int utl) /* returns the HTML for the timeline */ { xs_list *p = (xs_list *)list; @@ -2026,7 +2023,7 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, } else { head = html_instance_head(); - body = html_instance_body(tag); + body = html_instance_body(title); } xs_html *html = xs_html_tag("html", @@ -2126,25 +2123,22 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, } if (show_more) { - xs *t = NULL; xs *m = NULL; xs *ss = xs_fmt("skip=%d&show=%d", skip + show, show); - xs *url = page == NULL || user == NULL ? - xs_dup(srv_baseurl) : xs_fmt("%s%s", user->actor, page); + xs *url = xs_dup(user == NULL ? srv_baseurl : user->actor); - if (tag) { - t = xs_fmt("%s?t=%s", url, tag); - m = xs_fmt("%s&%s", t, ss); - } - else { - t = xs_dup(url); - m = xs_fmt("%s?%s", t, ss); - } + if (page != NULL) + url = xs_str_cat(url, page); + + if (xs_str_in(url, "?") != -1) + m = xs_fmt("%s&%s", url, ss); + else + m = xs_fmt("%s?%s", url, ss); xs_html *more_links = xs_html_tag("p", xs_html_tag("a", - xs_html_attr("href", t), + xs_html_attr("href", url), xs_html_attr("name", "snac-more"), xs_html_text(L("Back to top"))), xs_html_text(" - "), diff --git a/httpd.c b/httpd.c index 30367c8..81b0853 100644 --- a/httpd.c +++ b/httpd.c @@ -200,14 +200,18 @@ int server_get_handler(xs_dict *req, const char *q_path, *body = timeline_to_rss(NULL, tl, link, link, link); *ctype = "application/rss+xml; charset=utf-8"; } - else - *body = html_timeline(NULL, tl, 0, skip, show, more, t, NULL, 0); + else { + xs *page = xs_fmt("?t=%s", t); + xs *title = xs_fmt(L("Search results for #%s"), t); + *body = html_timeline(NULL, tl, 0, skip, show, more, title, page, 0); + } } else if (xs_type(xs_dict_get(srv_config, "show_instance_timeline")) == XSTYPE_TRUE) { /** instance timeline **/ xs *tl = timeline_instance_list(0, 30); - *body = html_timeline(NULL, tl, 0, 0, 0, 0, NULL, NULL, 0); + *body = html_timeline(NULL, tl, 0, 0, 0, 0, + L("Recent posts by users in this instance"), NULL, 0); } else *body = greeting_html(); diff --git a/snac.h b/snac.h index ab8fc7c..2a988f1 100644 --- a/snac.h +++ b/snac.h @@ -318,7 +318,7 @@ xs_str *encode_html(const char *str); xs_str *html_timeline(snac *user, const xs_list *list, int read_only, int skip, int show, int show_more, - char *tag, char *page, int utl); + char *title, char *page, int utl); int html_get_handler(const xs_dict *req, const char *q_path, char **body, int *b_size, char **ctype, xs_str **etag); -- cgit v1.2.3 From 3ab733cdf5a71b9a27399e8336e0c236c13d67fb Mon Sep 17 00:00:00 2001 From: default Date: Wed, 8 May 2024 10:20:25 +0200 Subject: New function search_by_content(). --- data.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 18 ++++++++++++++++++ snac.h | 3 +++ 3 files changed, 79 insertions(+) (limited to 'snac.h') diff --git a/data.c b/data.c index 4e1682c..bc9f979 100644 --- a/data.c +++ b/data.c @@ -2488,6 +2488,64 @@ void notify_clear(snac *snac) } +/** searches **/ + +xs_list *search_by_content(snac *user, const xs_list *timeline, + const char *regex, int timeout) +/* returns a list of posts which content matches the regex */ +{ + xs_list *r = xs_list_new(); + + if (timeout == 0) + timeout = 3; + + int c = 0; + char *v; + + time_t t = time(NULL) + timeout; + + while (xs_list_next(timeline, &v, &c)) { + xs *post = NULL; + + /* timeout? */ + if (time(NULL) > t) + break; + + int status; + + if (user) + status = timeline_get_by_md5(user, v, &post); + else + status = object_get_by_md5(v, &post); + + if (!valid_status(status)) + continue; + + /* must be a Note */ + if (strcmp(xs_dict_get_def(post, "type", ""), "Note")) + continue; + + char *content = xs_dict_get(post, "content"); + + if (xs_is_null(content)) + continue; + + /* strip HTML */ + xs *c = xs_regex_replace(content, "<[^>]+>", " "); + c = xs_regex_replace_i(c, " {2,}", " "); + c = xs_tolower_i(c); + + /* apply regex */ + xs *l = xs_regex_select_n(c, regex, 1); + + if (xs_list_len(l)) + r = xs_list_append(r, v); + } + + return r; +} + + /** the queue **/ static xs_dict *_enqueue_put(const char *fn, xs_dict *msg) diff --git a/main.c b/main.c index 6a38412..2e1a77c 100644 --- a/main.c +++ b/main.c @@ -44,6 +44,7 @@ int usage(void) printf("limit {basedir} {uid} {actor} Limits an actor (drops their announces)\n"); printf("unlimit {basedir} {uid} {actor} Unlimits an actor\n"); printf("verify_links {basedir} {uid} Verifies a user's links (in the metadata)\n"); + printf("search {basedir} {uid} {regex} Searches posts by content\n"); return 1; } @@ -374,6 +375,23 @@ int main(int argc, char *argv[]) return 0; } + if (strcmp(cmd, "search") == 0) { /** **/ + xs *tl = timeline_simple_list(&snac, "private", 0, XS_ALL); + + /* 'url' contains the regex */ + xs *r = search_by_content(&snac, tl, url, 10); + + int c = 0; + char *v; + + /* print results as standalone links */ + while (xs_list_next(r, &v, &c)) { + printf("%s/admin/p/%s\n", snac.actor, v); + } + + return 0; + } + if (strcmp(cmd, "ping") == 0) { /** **/ xs *actor_o = NULL; diff --git a/snac.h b/snac.h index 2a988f1..ae8fc59 100644 --- a/snac.h +++ b/snac.h @@ -179,6 +179,9 @@ xs_list *list_timeline(snac *user, const char *list, int skip, int show); xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); void list_distribute(snac *user, const char *who, const xs_dict *post); +xs_list *search_by_content(snac *user, const xs_list *timeline, + const char *regex, int timeout); + int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); int actor_get_refresh(snac *user, const char *actor, xs_dict **data); -- cgit v1.2.3 From dc74cac6c9c3f6e9edc848381422a1f124abac73 Mon Sep 17 00:00:00 2001 From: default Date: Wed, 8 May 2024 10:27:30 +0200 Subject: Added a timeout flag to search_by_content(). --- data.c | 13 ++++++++----- main.c | 3 ++- snac.h | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'snac.h') diff --git a/data.c b/data.c index bc9f979..82f36a4 100644 --- a/data.c +++ b/data.c @@ -2491,25 +2491,28 @@ void notify_clear(snac *snac) /** searches **/ xs_list *search_by_content(snac *user, const xs_list *timeline, - const char *regex, int timeout) + const char *regex, int max_secs, int *timeout) /* returns a list of posts which content matches the regex */ { xs_list *r = xs_list_new(); - if (timeout == 0) - timeout = 3; + if (max_secs == 0) + max_secs = 3; int c = 0; char *v; - time_t t = time(NULL) + timeout; + time_t t = time(NULL) + max_secs; + *timeout = 0; while (xs_list_next(timeline, &v, &c)) { xs *post = NULL; /* timeout? */ - if (time(NULL) > t) + if (time(NULL) > t) { + *timeout = 1; break; + } int status; diff --git a/main.c b/main.c index 2e1a77c..9244b5a 100644 --- a/main.c +++ b/main.c @@ -377,9 +377,10 @@ int main(int argc, char *argv[]) if (strcmp(cmd, "search") == 0) { /** **/ xs *tl = timeline_simple_list(&snac, "private", 0, XS_ALL); + int to; /* 'url' contains the regex */ - xs *r = search_by_content(&snac, tl, url, 10); + xs *r = search_by_content(&snac, tl, url, 10, &to); int c = 0; char *v; diff --git a/snac.h b/snac.h index ae8fc59..7f069ab 100644 --- a/snac.h +++ b/snac.h @@ -180,7 +180,7 @@ xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int void list_distribute(snac *user, const char *who, const xs_dict *post); xs_list *search_by_content(snac *user, const xs_list *timeline, - const char *regex, int timeout); + const char *regex, int max_secs, int *timeout); int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); -- cgit v1.2.3 From 52ba7f030ed50f22b7fbf437e83c9415ed0e91ed Mon Sep 17 00:00:00 2001 From: default Date: Wed, 8 May 2024 11:00:50 +0200 Subject: Renamed to content_search(). --- data.c | 2 +- main.c | 21 ++++++++++++++++++++- snac.h | 4 ++-- 3 files changed, 23 insertions(+), 4 deletions(-) (limited to 'snac.h') diff --git a/data.c b/data.c index 82f36a4..e3292c8 100644 --- a/data.c +++ b/data.c @@ -2490,7 +2490,7 @@ void notify_clear(snac *snac) /** searches **/ -xs_list *search_by_content(snac *user, const xs_list *timeline, +xs_list *content_search(snac *user, const xs_list *timeline, const char *regex, int max_secs, int *timeout) /* returns a list of posts which content matches the regex */ { diff --git a/main.c b/main.c index 9244b5a..240e02e 100644 --- a/main.c +++ b/main.c @@ -380,7 +380,26 @@ int main(int argc, char *argv[]) int to; /* 'url' contains the regex */ - xs *r = search_by_content(&snac, tl, url, 10, &to); + xs *r = content_search(&snac, tl, url, 10, &to); + + int c = 0; + char *v; + + /* print results as standalone links */ + while (xs_list_next(r, &v, &c)) { + printf("%s/admin/p/%s\n", snac.actor, v); + } + + return 0; + } + + if (strcmp(cmd, "search2") == 0) { /** **/ + /* undocumented (for testing only) */ + xs *tl = timeline_simple_list(&snac, "public", 0, XS_ALL); + int to; + + /* 'url' contains the regex */ + xs *r = content_search(&snac, tl, url, 10, &to); int c = 0; char *v; diff --git a/snac.h b/snac.h index 7f069ab..e3b76f6 100644 --- a/snac.h +++ b/snac.h @@ -179,8 +179,8 @@ xs_list *list_timeline(snac *user, const char *list, int skip, int show); xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); void list_distribute(snac *user, const char *who, const xs_dict *post); -xs_list *search_by_content(snac *user, const xs_list *timeline, - const char *regex, int max_secs, int *timeout); +xs_list *content_search(snac *user, const xs_list *timeline, + const char *regex, int max_secs, int *timeout); int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); -- cgit v1.2.3 From 979f2ad1400111bcd36da980ba8f78f25bb5390e Mon Sep 17 00:00:00 2001 From: default Date: Wed, 8 May 2024 16:43:02 +0200 Subject: Rewritten content_search() to read from both timelines. --- data.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ main.c | 22 +------------------ snac.h | 3 +-- 3 files changed, 65 insertions(+), 37 deletions(-) (limited to 'snac.h') diff --git a/data.c b/data.c index 1421f17..d9449d8 100644 --- a/data.c +++ b/data.c @@ -2490,23 +2490,35 @@ void notify_clear(snac *snac) /** searches **/ -xs_list *content_search(snac *user, const xs_list *timeline, - const char *regex, int max_secs, int *timeout) +xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, int *timeout) /* returns a list of posts which content matches the regex */ { - xs_list *r = xs_list_new(); + xs_set seen; + + xs_set_init(&seen); if (max_secs == 0) max_secs = 3; - int c = 0; - char *v; - time_t t = time(NULL) + max_secs; *timeout = 0; - while (xs_list_next(timeline, &v, &c)) { - xs *post = NULL; + /* iterate both timelines simultaneously */ + xs *pub_tl = timeline_simple_list(user, "public", 0, XS_ALL); + int pub_c = 0; + char *pub_md5 = NULL; + + xs *priv_tl = priv ? timeline_simple_list(user, "private", 0, XS_ALL) : xs_list_new(); + int priv_c = 0; + char *priv_md5 = NULL; + + /* first positioning */ + xs_list_next(pub_tl, &pub_md5, &pub_c); + xs_list_next(priv_tl, &priv_md5, &priv_c); + + for (;;) { + char *md5 = NULL; + enum { NONE, PUBLIC, PRIVATE } from = NONE; /* timeout? */ if (time(NULL) > t) { @@ -2514,11 +2526,48 @@ xs_list *content_search(snac *user, const xs_list *timeline, break; } - /* if from a user, must be in any timeline */ - if (user && !timeline_here(user, v)) - continue; + if (pub_md5 == NULL) { + /* out of both lists? done */ + if (priv_md5 == NULL) + break; - if (!valid_status(object_get_by_md5(v, &post))) + /* out of public: take element from the private timeline and advance */ + from = PRIVATE; + } + else + if (priv_md5 == NULL) { + /* out of private: take element from the public timeline and advance */ + from = PUBLIC; + } + else { + /* candidates from both: choose one from the file dates */ + xs *pub_fn = xs_fmt("%s/public/%s.json", user->basedir, pub_md5); + xs *priv_fn = xs_fmt("%s/private/%s.json", user->basedir, priv_md5); + + if (mtime(pub_fn) < mtime(priv_fn)) + from = PRIVATE; + else + from = PUBLIC; + } + + if (from == PUBLIC) { /* public */ + md5 = pub_md5; + if (!xs_list_next(pub_tl, &pub_md5, &pub_c)) + pub_md5 = NULL; + } + else + if (from == PRIVATE) { /* private */ + md5 = priv_md5; + if (!xs_list_next(priv_tl, &priv_md5, &priv_c)) + priv_md5 = NULL; + } + + if (md5 == NULL) + break; + + xs *post = NULL; + + if (!valid_status(timeline_get_by_md5(user, md5, &post))) continue; /* must be a Note */ @@ -2539,10 +2588,10 @@ xs_list *content_search(snac *user, const xs_list *timeline, xs *l = xs_regex_select_n(c, regex, 1); if (xs_list_len(l)) - r = xs_list_append(r, v); + xs_set_add(&seen, md5); } - return r; + return xs_set_result(&seen); } diff --git a/main.c b/main.c index 240e02e..bd52b19 100644 --- a/main.c +++ b/main.c @@ -376,30 +376,10 @@ int main(int argc, char *argv[]) } if (strcmp(cmd, "search") == 0) { /** **/ - xs *tl = timeline_simple_list(&snac, "private", 0, XS_ALL); int to; /* 'url' contains the regex */ - xs *r = content_search(&snac, tl, url, 10, &to); - - int c = 0; - char *v; - - /* print results as standalone links */ - while (xs_list_next(r, &v, &c)) { - printf("%s/admin/p/%s\n", snac.actor, v); - } - - return 0; - } - - if (strcmp(cmd, "search2") == 0) { /** **/ - /* undocumented (for testing only) */ - xs *tl = timeline_simple_list(&snac, "public", 0, XS_ALL); - int to; - - /* 'url' contains the regex */ - xs *r = content_search(&snac, tl, url, 10, &to); + xs *r = content_search(&snac, url, 1, 10, &to); int c = 0; char *v; diff --git a/snac.h b/snac.h index e3b76f6..e04dc65 100644 --- a/snac.h +++ b/snac.h @@ -179,8 +179,7 @@ xs_list *list_timeline(snac *user, const char *list, int skip, int show); xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); void list_distribute(snac *user, const char *who, const xs_dict *post); -xs_list *content_search(snac *user, const xs_list *timeline, - const char *regex, int max_secs, int *timeout); +xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, int *timeout); int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); -- cgit v1.2.3 From cccc5454c259d0d4ca600b3e1165979c352be54f Mon Sep 17 00:00:00 2001 From: default Date: Thu, 9 May 2024 09:31:10 +0200 Subject: Added a maximum results argument to content_search(). --- data.c | 11 ++++++++--- main.c | 2 +- mastoapi.c | 4 ++-- snac.h | 2 +- 4 files changed, 12 insertions(+), 7 deletions(-) (limited to 'snac.h') diff --git a/data.c b/data.c index 75149e2..78de21b 100644 --- a/data.c +++ b/data.c @@ -2491,9 +2491,12 @@ void notify_clear(snac *snac) /** searches **/ -xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, int *timeout) +xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, int max_res, int *timeout) /* returns a list of posts which content matches the regex */ { + if (regex == NULL || *regex == '\0') + return xs_list_new(); + xs_set seen; xs_set_init(&seen); @@ -2517,7 +2520,7 @@ xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, i xs_list_next(pub_tl, &pub_md5, &pub_c); xs_list_next(priv_tl, &priv_md5, &priv_c); - for (;;) { + while (max_res > 0) { char *md5 = NULL; enum { NONE, PUBLIC, PRIVATE } from = NONE; @@ -2587,8 +2590,10 @@ xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, i /* apply regex */ xs *l = xs_regex_select_n(c, regex, 1); - if (xs_list_len(l)) + if (xs_list_len(l)) { xs_set_add(&seen, md5); + max_res--; + } } return xs_set_result(&seen); diff --git a/main.c b/main.c index bd52b19..5e37340 100644 --- a/main.c +++ b/main.c @@ -379,7 +379,7 @@ int main(int argc, char *argv[]) int to; /* 'url' contains the regex */ - xs *r = content_search(&snac, url, 1, 10, &to); + xs *r = content_search(&snac, url, 1, 10, XS_ALL, &to); int c = 0; char *v; diff --git a/mastoapi.c b/mastoapi.c index 253021b..cbc965c 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -2260,10 +2260,10 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (xs_is_null(type) || strcmp(type, "statuses") == 0) { int to = 0; - xs *tl = content_search(&snac1, q, 1, 0, &to); + int cnt = 40; + xs *tl = content_search(&snac1, q, 1, 0, cnt, &to); int c = 0; char *v; - int cnt = 40; while (xs_list_next(tl, &v, &c) && --cnt) { xs *post = NULL; diff --git a/snac.h b/snac.h index e04dc65..579d149 100644 --- a/snac.h +++ b/snac.h @@ -179,7 +179,7 @@ xs_list *list_timeline(snac *user, const char *list, int skip, int show); xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); void list_distribute(snac *user, const char *who, const xs_dict *post); -xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, int *timeout); +xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, int max_res, int *timeout); int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); -- cgit v1.2.3 From 1531e81a310311656d06c9ee0d31da31493e6de2 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 10 May 2024 11:29:18 +0200 Subject: Added a skip argument to content_search(). --- data.c | 13 +++++++++---- html.c | 10 ++++++---- main.c | 2 +- mastoapi.c | 2 +- snac.h | 3 ++- 5 files changed, 19 insertions(+), 11 deletions(-) (limited to 'snac.h') diff --git a/data.c b/data.c index 78de21b..e284696 100644 --- a/data.c +++ b/data.c @@ -2491,7 +2491,8 @@ void notify_clear(snac *snac) /** searches **/ -xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, int max_res, int *timeout) +xs_list *content_search(snac *user, const char *regex, + int priv, int skip, int show, int max_secs, int *timeout) /* returns a list of posts which content matches the regex */ { if (regex == NULL || *regex == '\0') @@ -2520,7 +2521,7 @@ xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, i xs_list_next(pub_tl, &pub_md5, &pub_c); xs_list_next(priv_tl, &priv_md5, &priv_c); - while (max_res > 0) { + while (show > 0) { char *md5 = NULL; enum { NONE, PUBLIC, PRIVATE } from = NONE; @@ -2591,8 +2592,12 @@ xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, i xs *l = xs_regex_select_n(c, regex, 1); if (xs_list_len(l)) { - xs_set_add(&seen, md5); - max_res--; + if (skip) + skip--; + else { + xs_set_add(&seen, md5); + show--; + } } } diff --git a/html.c b/html.c index 9eefeec..d50333a 100644 --- a/html.c +++ b/html.c @@ -2563,20 +2563,22 @@ int html_get_handler(const xs_dict *req, const char *q_path, char *q = xs_dict_get(q_vars, "q"); if (q && *q) { - /* search by content */ + /** search by content **/ int to = 0; - xs *tl = content_search(&snac, q, 1, skip ? 10 : 0, skip + show, &to); + xs *tl = content_search(&snac, q, 1, skip, show, skip ? 10 : 0, &to); xs *title = NULL; xs *page = xs_fmt("/admin?q=%s", q); int tl_len = xs_list_len(tl); if (tl_len) title = xs_fmt(L("Search results for '%s'"), q); + else + if (skip) + title = xs_fmt(L("No more matches for '%s'"), q); else title = xs_fmt(L("Nothing found for '%s'"), q); - *body = html_timeline(&snac, tl, 0, 0, tl_len, - (to || tl_len == skip + show), title, page, 1); + *body = html_timeline(&snac, tl, 0, skip, show, tl_len > 0, title, page, 1); *b_size = strlen(*body); status = 200; } diff --git a/main.c b/main.c index 5e37340..819922f 100644 --- a/main.c +++ b/main.c @@ -379,7 +379,7 @@ int main(int argc, char *argv[]) int to; /* 'url' contains the regex */ - xs *r = content_search(&snac, url, 1, 10, XS_ALL, &to); + xs *r = content_search(&snac, url, 1, 0, XS_ALL, 10, &to); int c = 0; char *v; diff --git a/mastoapi.c b/mastoapi.c index cbc965c..1071bfd 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -2261,7 +2261,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (xs_is_null(type) || strcmp(type, "statuses") == 0) { int to = 0; int cnt = 40; - xs *tl = content_search(&snac1, q, 1, 0, cnt, &to); + xs *tl = content_search(&snac1, q, 1, 0, cnt, 0, &to); int c = 0; char *v; diff --git a/snac.h b/snac.h index 579d149..64d48f2 100644 --- a/snac.h +++ b/snac.h @@ -179,7 +179,8 @@ xs_list *list_timeline(snac *user, const char *list, int skip, int show); xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); void list_distribute(snac *user, const char *who, const xs_dict *post); -xs_list *content_search(snac *user, const char *regex, int priv, int max_secs, int max_res, int *timeout); +xs_list *content_search(snac *user, const char *regex, + int priv, int skip, int show, int max_secs, int *timeout); int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); -- cgit v1.2.3 From a0d98f3d2ad06571983caa155e1bbd8b2012fbb3 Mon Sep 17 00:00:00 2001 From: default Date: Sat, 11 May 2024 09:37:34 +0200 Subject: Bumped version. --- snac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'snac.h') diff --git a/snac.h b/snac.h index 64d48f2..c4e062b 100644 --- a/snac.h +++ b/snac.h @@ -1,7 +1,7 @@ /* snac - A simple, minimalistic ActivityPub instance */ /* copyright (c) 2022 - 2024 grunfink et al. / MIT license */ -#define VERSION "2.52" +#define VERSION "2.53-dev" #define USER_AGENT "snac/" VERSION -- cgit v1.2.3 From e1ce85debd5b192b5dc56a4e9810839cc52b0f8b Mon Sep 17 00:00:00 2001 From: default Date: Sat, 11 May 2024 18:46:15 +0200 Subject: Unified post-like object type match. --- activitypub.c | 2 +- data.c | 2 +- html.c | 4 ++-- mastoapi.c | 4 ++-- snac.h | 2 ++ 5 files changed, 8 insertions(+), 6 deletions(-) (limited to 'snac.h') diff --git a/activitypub.c b/activitypub.c index 301fd4c..4a04000 100644 --- a/activitypub.c +++ b/activitypub.c @@ -355,7 +355,7 @@ int timeline_request(snac *snac, char **id, xs_str **wrk, int level) type = "(null)"; } - if (xs_match(type, "Note|Page|Article|Video")) { + if (xs_match(type, POSTLIKE_OBJECT_TYPE)) { const char *actor = get_atto(object); if (content_check("filter_reject.txt", object)) diff --git a/data.c b/data.c index d037af0..108354c 100644 --- a/data.c +++ b/data.c @@ -2577,7 +2577,7 @@ xs_list *content_search(snac *user, const char *regex, if (!valid_status(timeline_get_by_md5(user, md5, &post))) continue; - if (!xs_match(xs_dict_get_def(post, "type", "-"), "Note|Question|Page|Article|Video")) + if (!xs_match(xs_dict_get_def(post, "type", "-"), POSTLIKE_OBJECT_TYPE)) continue; char *content = xs_dict_get(post, "content"); diff --git a/html.c b/html.c index 0cdb608..12dba6b 100644 --- a/html.c +++ b/html.c @@ -256,7 +256,7 @@ xs_html *html_msg_icon(snac *user, char *actor_id, const xs_dict *msg) int priv = 0; const char *type = xs_dict_get(msg, "type"); - if (xs_match(type, "Note|Question|Page|Article|Video")) + if (xs_match(type, POSTLIKE_OBJECT_TYPE)) url = xs_dict_get(msg, "id"); priv = !is_msg_public(msg); @@ -1405,7 +1405,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, html_msg_icon(read_only ? NULL : user, xs_dict_get(msg, "actor"), msg))); } else - if (!xs_match(type, "Note|Question|Page|Article|Video")) { + if (!xs_match(type, POSTLIKE_OBJECT_TYPE)) { /* skip oddities */ return NULL; } diff --git a/mastoapi.c b/mastoapi.c index 1071bfd..2bf5fdc 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -1504,7 +1504,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, /* discard non-Notes */ const char *id = xs_dict_get(msg, "id"); const char *type = xs_dict_get(msg, "type"); - if (!xs_match(type, "Note|Question|Page|Article|Video")) + if (!xs_match(type, POSTLIKE_OBJECT_TYPE)) continue; const char *from = NULL; @@ -1681,7 +1681,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, /* discard non-Notes */ const char *id = xs_dict_get(msg, "id"); const char *type = xs_dict_get(msg, "type"); - if (!xs_match(type, "Note|Question|Page|Article|Video")) + if (!xs_match(type, POSTLIKE_OBJECT_TYPE)) continue; const char *from = NULL; diff --git a/snac.h b/snac.h index c4e062b..c585e3f 100644 --- a/snac.h +++ b/snac.h @@ -29,6 +29,8 @@ extern int dbglevel; #define L(s) (s) +#define POSTLIKE_OBJECT_TYPE "Note|Question|Page|Article|Video" + int mkdirx(const char *pathname); int valid_status(int status); -- cgit v1.2.3 From 6f3763f452ba55ee6ddd9f63f5bc523807e7288f Mon Sep 17 00:00:00 2001 From: default Date: Sat, 11 May 2024 19:15:18 +0200 Subject: Show 'Event' object types as Notes. --- format.c | 5 ++--- html.c | 1 + snac.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'snac.h') diff --git a/format.c b/format.c index 8d51351..631c11c 100644 --- a/format.c +++ b/format.c @@ -311,9 +311,8 @@ xs_str *sanitize(const char *content) s = xs_str_cat(s, s2); } else { - /* else? just show it with encoded code.. that's it. */ - xs *el = encode_html(v); - s = xs_str_cat(s, el); + if (strcmp(v, "")) + s = xs_str_cat(s, "

"); } } else { diff --git a/html.c b/html.c index 12dba6b..201456e 100644 --- a/html.c +++ b/html.c @@ -1407,6 +1407,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, else if (!xs_match(type, POSTLIKE_OBJECT_TYPE)) { /* skip oddities */ + snac_debug(user, 1, xs_fmt("html_entry: ignoring object type '%s' %s", type, id)); return NULL; } diff --git a/snac.h b/snac.h index c585e3f..239f27a 100644 --- a/snac.h +++ b/snac.h @@ -29,7 +29,7 @@ extern int dbglevel; #define L(s) (s) -#define POSTLIKE_OBJECT_TYPE "Note|Question|Page|Article|Video" +#define POSTLIKE_OBJECT_TYPE "Note|Question|Page|Article|Video|Event" int mkdirx(const char *pathname); -- cgit v1.2.3 From 4d53a7b6f7f45f524313980461f5d2a6ef965949 Mon Sep 17 00:00:00 2001 From: default Date: Sat, 11 May 2024 19:16:54 +0200 Subject: In timeline_request(), call enqueue_actor_request on actor errors. --- activitypub.c | 26 +++++++++++++++----------- data.c | 11 ++++++----- snac.h | 2 +- 3 files changed, 22 insertions(+), 17 deletions(-) (limited to 'snac.h') diff --git a/activitypub.c b/activitypub.c index 301fd4c..280ac87 100644 --- a/activitypub.c +++ b/activitypub.c @@ -356,23 +356,27 @@ int timeline_request(snac *snac, char **id, xs_str **wrk, int level) } if (xs_match(type, "Note|Page|Article|Video")) { - const char *actor = get_atto(object); - if (content_check("filter_reject.txt", object)) snac_log(snac, xs_fmt("timeline_request rejected by content %s", nid)); else { - /* request (and drop) the actor for this entry */ - if (!xs_is_null(actor)) - actor_request(snac, actor, NULL); + const char *actor = get_atto(object); + + if (!xs_is_null(actor)) { + /* request (and drop) the actor for this entry */ + if (!valid_status(actor_request(snac, actor, NULL))) { + /* failed? retry later */ + enqueue_actor_refresh(snac, actor, 60); + } - /* does it have an ancestor? */ - char *in_reply_to = xs_dict_get(object, "inReplyTo"); + /* does it have an ancestor? */ + char *in_reply_to = xs_dict_get(object, "inReplyTo"); - /* store */ - timeline_add(snac, nid, object); + /* store */ + timeline_add(snac, nid, object); - /* recurse! */ - timeline_request(snac, &in_reply_to, NULL, level + 1); + /* recurse! */ + timeline_request(snac, &in_reply_to, NULL, level + 1); + } } } } diff --git a/data.c b/data.c index d037af0..8016ce1 100644 --- a/data.c +++ b/data.c @@ -1632,7 +1632,7 @@ int actor_get_refresh(snac *user, const char *actor, xs_dict **data) int status = actor_get(actor, data); if (status == 205 && user && !xs_startswith(actor, srv_baseurl)) - enqueue_actor_refresh(user, actor); + enqueue_actor_refresh(user, actor, 0); return status; } @@ -2830,13 +2830,14 @@ void enqueue_verify_links(snac *user) } -void enqueue_actor_refresh(snac *user, const char *actor) +void enqueue_actor_refresh(snac *user, const char *actor, int forward_secs) /* enqueues an actor refresh */ { - xs *qmsg = _new_qmsg("actor_refresh", "", 0); - char *ntid = xs_dict_get(qmsg, "ntid"); - xs *fn = xs_fmt("%s/queue/%s.json", user->basedir, ntid); + xs *qmsg = _new_qmsg("actor_refresh", "", 0); + xs *ntid = tid(forward_secs); + xs *fn = xs_fmt("%s/queue/%s.json", user->basedir, ntid); + qmsg = xs_dict_set(qmsg, "ntid", ntid); qmsg = xs_dict_append(qmsg, "actor", actor); qmsg = _enqueue_put(fn, qmsg); diff --git a/snac.h b/snac.h index c4e062b..de2ee1e 100644 --- a/snac.h +++ b/snac.h @@ -232,7 +232,7 @@ void enqueue_message(snac *snac, const xs_dict *msg); void enqueue_close_question(snac *user, const char *id, int end_secs); void enqueue_object_request(snac *user, const char *id, int forward_secs); void enqueue_verify_links(snac *user); -void enqueue_actor_refresh(snac *user, const char *actor); +void enqueue_actor_refresh(snac *user, const char *actor, int forward_secs); void enqueue_request_replies(snac *user, const char *id); int was_question_voted(snac *user, const char *id); -- cgit v1.2.3 From 0a6df8e504569be4caf39930c473f12b328e5b2a Mon Sep 17 00:00:00 2001 From: default Date: Wed, 15 May 2024 13:31:53 +0200 Subject: Renamed content_check() to content_match(). --- activitypub.c | 4 ++-- data.c | 6 +++--- snac.h | 7 +++---- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'snac.h') diff --git a/activitypub.c b/activitypub.c index dee127d..231715b 100644 --- a/activitypub.c +++ b/activitypub.c @@ -356,7 +356,7 @@ int timeline_request(snac *snac, char **id, xs_str **wrk, int level) } if (xs_match(type, POSTLIKE_OBJECT_TYPE)) { - if (content_check("filter_reject.txt", object)) + if (content_match("filter_reject.txt", object)) snac_log(snac, xs_fmt("timeline_request rejected by content %s", nid)); else { const char *actor = get_atto(object); @@ -2005,7 +2005,7 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) snac_debug(snac, 0, xs_fmt("dropped reply %s to hidden post %s", id, in_reply_to)); } else { - if (content_check("filter_reject.txt", object)) { + if (content_match("filter_reject.txt", object)) { snac_log(snac, xs_fmt("rejected by content %s", id)); return 1; } diff --git a/data.c b/data.c index 61045c6..5abbeaf 100644 --- a/data.c +++ b/data.c @@ -2272,7 +2272,7 @@ int instance_unblock(const char *instance) /** operations by content **/ -int content_check(const char *file, const xs_dict *msg) +int content_match(const char *file, const xs_dict *msg) /* checks if a message's content matches any of the regexes in file */ /* file format: one regex per line */ { @@ -2283,7 +2283,7 @@ int content_check(const char *file, const xs_dict *msg) if (xs_type(v) == XSTYPE_STRING && *v) { if ((f = fopen(fn, "r")) != NULL) { - srv_debug(1, xs_fmt("content_check: loading regexes from %s", fn)); + srv_debug(1, xs_fmt("content_match: loading regexes from %s", fn)); /* massage content (strip HTML tags, etc.) */ xs *c = xs_regex_replace(v, "<[^>]+>", " "); @@ -2294,7 +2294,7 @@ int content_check(const char *file, const xs_dict *msg) xs *rx = xs_strip_i(xs_readline(f)); if (*rx && xs_regex_match(c, rx)) { - srv_debug(1, xs_fmt("content_check: match for '%s'", rx)); + srv_debug(1, xs_fmt("content_match: match for '%s'", rx)); r = 1; } } diff --git a/snac.h b/snac.h index 91033cf..e679d8c 100644 --- a/snac.h +++ b/snac.h @@ -181,9 +181,6 @@ xs_list *list_timeline(snac *user, const char *list, int skip, int show); xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); void list_distribute(snac *user, const char *who, const xs_dict *post); -xs_list *content_search(snac *user, const char *regex, - int priv, int skip, int show, int max_secs, int *timeout); - int actor_add(const char *actor, xs_dict *msg); int actor_get(const char *actor, xs_dict **data); int actor_get_refresh(snac *user, const char *actor, xs_dict **data); @@ -219,7 +216,9 @@ int is_instance_blocked(const char *instance); int instance_block(const char *instance); int instance_unblock(const char *instance); -int content_check(const char *file, const xs_dict *msg); +int content_match(const char *file, const xs_dict *msg); +xs_list *content_search(snac *user, const char *regex, + int priv, int skip, int show, int max_secs, int *timeout); void enqueue_input(snac *snac, const xs_dict *msg, const xs_dict *req, int retries); void enqueue_shared_input(const xs_dict *msg, const xs_dict *req, int retries); -- cgit v1.2.3 From b95fbe4e438a2ab8a8625875e2eedac38dae572f Mon Sep 17 00:00:00 2001 From: default Date: Thu, 16 May 2024 15:47:43 +0200 Subject: Version 2.53 RELEASED. --- snac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'snac.h') diff --git a/snac.h b/snac.h index e679d8c..b49fbe7 100644 --- a/snac.h +++ b/snac.h @@ -1,7 +1,7 @@ /* snac - A simple, minimalistic ActivityPub instance */ /* copyright (c) 2022 - 2024 grunfink et al. / MIT license */ -#define VERSION "2.53-dev" +#define VERSION "2.53" #define USER_AGENT "snac/" VERSION -- cgit v1.2.3 From 4777fc86cb962917a8f34afb3bfa40f26290815d Mon Sep 17 00:00:00 2001 From: default Date: Tue, 21 May 2024 14:12:15 +0200 Subject: Added const everywhere. --- activitypub.c | 283 ++++++++++++++++++++++------------------------------------ data.c | 130 ++++++++++----------------- html.c | 278 ++++++++++++++++++++++++++++---------------------------- http.c | 27 +++--- httpd.c | 16 ++-- main.c | 2 +- mastoapi.c | 109 +++++++++++----------- snac.h | 45 +++++----- upgrade.c | 40 ++++++--- utils.c | 2 +- webfinger.c | 23 ++--- xs.h | 110 ++++++++++++++++------- xs_curl.h | 2 +- xs_html.h | 34 +++---- xs_httpd.h | 5 +- xs_json.h | 9 +- xs_set.h | 2 +- xs_unicode.h | 6 +- xs_url.h | 4 +- xs_version.h | 2 +- 20 files changed, 549 insertions(+), 580 deletions(-) (limited to 'snac.h') diff --git a/activitypub.c b/activitypub.c index 231715b..f4b4eac 100644 --- a/activitypub.c +++ b/activitypub.c @@ -67,7 +67,7 @@ int activitypub_request(snac *user, const char *url, xs_dict **data) xs *response = NULL; xs *payload = NULL; int p_size; - char *ctype; + const char *ctype; *data = NULL; @@ -154,20 +154,21 @@ int actor_request(snac *user, const char *actor, xs_dict **data) } -char *get_atto(const xs_dict *msg) +const char *get_atto(const xs_dict *msg) /* gets the attributedTo field (an actor) */ { - char *actor = xs_dict_get(msg, "attributedTo"); + const xs_val *actor = xs_dict_get(msg, "attributedTo"); /* if the actor is a list of objects (like on Peertube videos), pick the Person */ if (xs_type(actor) == XSTYPE_LIST) { - xs_list *p = actor; + const xs_list *p = actor; + int c = 0; xs_dict *v; actor = NULL; - while (actor == NULL && xs_list_iter(&p, &v)) { + while (actor == NULL && xs_list_next(p, &v, &c)) { if (xs_type(v) == XSTYPE_DICT) { - char *type = xs_dict_get(v, "type"); + const char *type = xs_dict_get(v, "type"); if (xs_type(type) == XSTYPE_STRING && strcmp(type, "Person") == 0) { actor = xs_dict_get(v, "id"); @@ -186,7 +187,7 @@ xs_list *get_attachments(const xs_dict *msg) /* unify the garbage fire that are the attachments */ { xs_list *l = xs_list_new(); - xs_list *p; + const xs_list *p; /* try first the attachments list */ if (!xs_is_null(p = xs_dict_get(msg, "attachment"))) { @@ -203,23 +204,24 @@ xs_list *get_attachments(const xs_dict *msg) if (xs_type(attach) == XSTYPE_LIST) { /* does the message have an image? */ - if (xs_type(v = xs_dict_get(msg, "image")) == XSTYPE_DICT) { + const xs_dict *d = xs_dict_get(msg, "image"); + if (xs_type(d) == XSTYPE_DICT) { /* add it to the attachment list */ - attach = xs_list_append(attach, v); + attach = xs_list_append(attach, d); } } /* now iterate the list */ - p = attach; - while (xs_list_iter(&p, &v)) { - char *type = xs_dict_get(v, "mediaType"); + int c = 0; + while (xs_list_next(attach, &v, &c)) { + const char *type = xs_dict_get(v, "mediaType"); if (xs_is_null(type)) type = xs_dict_get(v, "type"); if (xs_is_null(type)) continue; - char *href = xs_dict_get(v, "url"); + const char *href = xs_dict_get(v, "url"); if (xs_is_null(href)) href = xs_dict_get(v, "href"); if (xs_is_null(href)) @@ -233,7 +235,7 @@ xs_list *get_attachments(const xs_dict *msg) type = mt; } - char *name = xs_dict_get(v, "name"); + const char *name = xs_dict_get(v, "name"); if (xs_is_null(name)) name = xs_dict_get(msg, "name"); if (xs_is_null(name)) @@ -252,29 +254,31 @@ xs_list *get_attachments(const xs_dict *msg) p = xs_dict_get(msg, "url"); if (xs_type(p) == XSTYPE_LIST) { - char *href = NULL; - char *type = NULL; + const char *href = NULL; + const char *type = NULL; + int c = 0; xs_val *v; - while (href == NULL && xs_list_iter(&p, &v)) { + while (href == NULL && xs_list_next(p, &v, &c)) { if (xs_type(v) == XSTYPE_DICT) { - char *mtype = xs_dict_get(v, "type"); + const char *mtype = xs_dict_get(v, "type"); if (xs_type(mtype) == XSTYPE_STRING && strcmp(mtype, "Link") == 0) { mtype = xs_dict_get(v, "mediaType"); - xs_list *tag = xs_dict_get(v, "tag"); + const xs_list *tag = xs_dict_get(v, "tag"); if (xs_type(mtype) == XSTYPE_STRING && strcmp(mtype, "application/x-mpegURL") == 0 && xs_type(tag) == XSTYPE_LIST) { /* now iterate the tag list, looking for a video URL */ xs_dict *d; + int c = 0; - while (href == NULL && xs_list_iter(&tag, &d)) { + while (href == NULL && xs_list_next(tag, &d, &c)) { if (xs_type(d) == XSTYPE_DICT) { if (xs_type(mtype = xs_dict_get(d, "mediaType")) == XSTYPE_STRING && xs_startswith(mtype, "video/")) { - char *h = xs_dict_get(d, "href"); + const char *h = xs_dict_get(d, "href"); /* this is probably it */ if (xs_type(h) == XSTYPE_STRING) { @@ -303,7 +307,7 @@ xs_list *get_attachments(const xs_dict *msg) } -int timeline_request(snac *snac, char **id, xs_str **wrk, int level) +int timeline_request(snac *snac, const char **id, xs_str **wrk, int level) /* ensures that an entry and its ancestors are in the timeline */ { int status = 0; @@ -323,7 +327,7 @@ int timeline_request(snac *snac, char **id, xs_str **wrk, int level) status = activitypub_request(snac, *id, &msg); if (valid_status(status)) { - xs_dict *object = msg; + const xs_dict *object = msg; const char *type = xs_dict_get(object, "type"); /* get the id again from the object, as it may be different */ @@ -369,7 +373,7 @@ int timeline_request(snac *snac, char **id, xs_str **wrk, int level) } /* does it have an ancestor? */ - char *in_reply_to = xs_dict_get(object, "inReplyTo"); + const char *in_reply_to = xs_dict_get(object, "inReplyTo"); /* store */ timeline_add(snac, nid, object); @@ -381,83 +385,12 @@ int timeline_request(snac *snac, char **id, xs_str **wrk, int level) } } } - - enqueue_request_replies(snac, *id); } return status; } -void timeline_request_replies(snac *user, const char *id) -/* requests all replies of a message */ -/* FIXME: experimental -- needs more testing */ -{ - /* FIXME: TEMPORARILY DISABLED */ - /* Reason: I've found that many of the posts in the 'replies' Collection - do not have an inReplyTo field (why??? aren't they 'replies'???). - For this reason, these requested objects are not stored as children - of the original post and they are shown as out-of-context, top level posts. - This process is disabled until I find an elegant way of providing a parent - for these 'stray' children. */ - return; - - xs *msg = NULL; - - if (!valid_status(object_get(id, &msg))) - return; - - /* does it have a replies collection? */ - const xs_dict *replies = xs_dict_get(msg, "replies"); - - if (!xs_is_null(replies)) { - const char *type = xs_dict_get(replies, "type"); - const char *first = xs_dict_get(replies, "first"); - - if (!xs_is_null(type) && !xs_is_null(first) && strcmp(type, "Collection") == 0) { - const char *next = xs_dict_get(first, "next"); - - if (!xs_is_null(next)) { - xs *rpls = NULL; - int status = activitypub_request(user, next, &rpls); - - /* request the Collection of replies */ - if (valid_status(status)) { - xs_list *items = xs_dict_get(rpls, "items"); - - if (xs_type(items) == XSTYPE_LIST) { - xs_val *v; - - /* request them all */ - while (xs_list_iter(&items, &v)) { - if (xs_type(v) == XSTYPE_DICT) { - /* not an id, but the object itself (!) */ - const char *c_id = xs_dict_get(v, "id"); - - if (!xs_is_null(id)) { - snac_debug(user, 0, xs_fmt("embedded reply %s", c_id)); - - object_add(c_id, v); - - /* get its own children */ - timeline_request_replies(user, v); - } - } - else { - snac_debug(user, 0, xs_fmt("request reply %s", v)); - timeline_request(user, &v, NULL, 0); - } - } - } - } - else - snac_debug(user, 0, xs_fmt("replies request error %s %d", next, status)); - } - } - } -} - - int send_to_inbox_raw(const char *keyid, const char *seckey, const xs_str *inbox, const xs_dict *msg, xs_val **payload, int *p_size, int timeout) @@ -480,7 +413,7 @@ int send_to_inbox(snac *snac, const xs_str *inbox, const xs_dict *msg, xs_val **payload, int *p_size, int timeout) /* sends a message to an Inbox */ { - char *seckey = xs_dict_get(snac->key, "secret"); + const char *seckey = xs_dict_get(snac->key, "secret"); return send_to_inbox_raw(snac->actor, seckey, inbox, msg, payload, p_size, timeout); } @@ -490,7 +423,7 @@ xs_str *get_actor_inbox(const char *actor) /* gets an actor's inbox */ { xs *data = NULL; - char *v = NULL; + const char *v = NULL; if (valid_status(actor_request(NULL, actor, &data))) { /* try first endpoints/sharedInbox */ @@ -539,16 +472,16 @@ void post_message(snac *snac, const char *actor, const xs_dict *msg) xs_list *recipient_list(snac *snac, const xs_dict *msg, int expand_public) /* returns the list of recipients for a message */ { - char *to = xs_dict_get(msg, "to"); - char *cc = xs_dict_get(msg, "cc"); + const xs_val *to = xs_dict_get(msg, "to"); + const xs_val *cc = xs_dict_get(msg, "cc"); xs_set rcpts; int n; xs_set_init(&rcpts); - char *lists[] = { to, cc, NULL }; + const xs_list *lists[] = { to, cc, NULL }; for (n = 0; lists[n]; n++) { - char *l = lists[n]; + xs_list *l = (xs_list *)lists[n]; char *v; xs *tl = NULL; @@ -671,13 +604,13 @@ int is_msg_for_me(snac *snac, const xs_dict *c_msg) /* if it's a Follow, it must be explicitly for us */ if (xs_match(type, "Follow")) { - char *object = xs_dict_get(c_msg, "object"); + const char *object = xs_dict_get(c_msg, "object"); return !xs_is_null(object) && strcmp(snac->actor, object) == 0; } /* only accept Ping directed to us */ if (xs_match(type, "Ping")) { - char *dest = xs_dict_get(c_msg, "to"); + const char *dest = xs_dict_get(c_msg, "to"); return !xs_is_null(dest) && strcmp(snac->actor, dest) == 0; } @@ -692,7 +625,7 @@ int is_msg_for_me(snac *snac, const xs_dict *c_msg) if (pub_msg && following_check(snac, actor)) return 1; - xs_dict *msg = xs_dict_get(c_msg, "object"); + const xs_dict *msg = xs_dict_get(c_msg, "object"); xs *rcpts = recipient_list(snac, msg, 0); xs_list *p = rcpts; xs_str *v; @@ -704,8 +637,9 @@ int is_msg_for_me(snac *snac, const xs_dict *c_msg) xs *actor_obj = NULL; if (valid_status(object_get(actor, &actor_obj))) { - if ((v = xs_dict_get(actor_obj, "followers"))) - actor_followers = xs_dup(v); + const xs_val *fw = xs_dict_get(actor_obj, "followers"); + if (fw) + actor_followers = xs_dup(fw); } } @@ -728,13 +662,13 @@ int is_msg_for_me(snac *snac, const xs_dict *c_msg) } /* accept if it's by someone we follow */ - char *atto = get_atto(msg); + const char *atto = get_atto(msg); if (pub_msg && !xs_is_null(atto) && following_check(snac, atto)) return 3; /* is this message a reply to another? */ - char *irt = xs_dict_get(msg, "inReplyTo"); + const char *irt = xs_dict_get(msg, "inReplyTo"); if (!xs_is_null(irt)) { xs *r_msg = NULL; @@ -987,8 +921,8 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor, /* telegram */ - char *bot = xs_dict_get(snac->config, "telegram_bot"); - char *chat_id = xs_dict_get(snac->config, "telegram_chat_id"); + const char *bot = xs_dict_get(snac->config, "telegram_bot"); + const char *chat_id = xs_dict_get(snac->config, "telegram_chat_id"); if (!xs_is_null(bot) && !xs_is_null(chat_id) && *bot && *chat_id) enqueue_telegram(body, bot, chat_id); @@ -1001,8 +935,8 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor, objid = actor; /* ntfy */ - char *ntfy_server = xs_dict_get(snac->config, "ntfy_server"); - char *ntfy_token = xs_dict_get(snac->config, "ntfy_token"); + const char *ntfy_server = xs_dict_get(snac->config, "ntfy_server"); + const char *ntfy_token = xs_dict_get(snac->config, "ntfy_token"); if (!xs_is_null(ntfy_server) && *ntfy_server) enqueue_ntfy(body, ntfy_server, ntfy_token); @@ -1088,7 +1022,7 @@ xs_dict *msg_base(snac *snac, const char *type, const char *id, } -xs_dict *msg_collection(snac *snac, char *id) +xs_dict *msg_collection(snac *snac, const char *id) /* creates an empty OrderedCollection message */ { xs_dict *msg = msg_base(snac, "OrderedCollection", id, NULL, NULL, NULL); @@ -1102,7 +1036,7 @@ xs_dict *msg_collection(snac *snac, char *id) } -xs_dict *msg_accept(snac *snac, char *object, char *to) +xs_dict *msg_accept(snac *snac, const xs_val *object, const char *to) /* creates an Accept message (as a response to a Follow) */ { xs_dict *msg = msg_base(snac, "Accept", "@dummy", snac->actor, NULL, object); @@ -1113,12 +1047,12 @@ xs_dict *msg_accept(snac *snac, char *object, char *to) } -xs_dict *msg_update(snac *snac, xs_dict *object) +xs_dict *msg_update(snac *snac, const xs_dict *object) /* creates an Update message */ { xs_dict *msg = msg_base(snac, "Update", "@object", snac->actor, "@now", object); - char *type = xs_dict_get(object, "type"); + const char *type = xs_dict_get(object, "type"); if (strcmp(type, "Note") == 0) { msg = xs_dict_append(msg, "to", xs_dict_get(object, "to")); @@ -1141,7 +1075,7 @@ xs_dict *msg_update(snac *snac, xs_dict *object) } -xs_dict *msg_admiration(snac *snac, char *object, char *type) +xs_dict *msg_admiration(snac *snac, const char *object, const char *type) /* creates a Like or Announce message */ { xs *a_msg = NULL; @@ -1172,7 +1106,7 @@ xs_dict *msg_admiration(snac *snac, char *object, char *type) } -xs_dict *msg_repulsion(snac *user, char *id, char *type) +xs_dict *msg_repulsion(snac *user, const char *id, const char *type) /* creates an Undo + admiration message */ { xs *a_msg = NULL; @@ -1210,7 +1144,7 @@ xs_dict *msg_actor(snac *snac) xs *kid = NULL; xs *f_bio = NULL; xs_dict *msg = msg_base(snac, "Person", snac->actor, NULL, NULL, NULL); - char *p; + const char *p; int n; /* change the @context (is this really necessary?) */ @@ -1268,7 +1202,7 @@ xs_dict *msg_actor(snac *snac) } /* add the metadata as attachments of PropertyValue */ - xs_dict *metadata = xs_dict_get(snac->config, "metadata"); + const xs_dict *metadata = xs_dict_get(snac->config, "metadata"); if (xs_type(metadata) == XSTYPE_DICT) { xs *attach = xs_list_new(); xs_str *k; @@ -1314,7 +1248,7 @@ xs_dict *msg_create(snac *snac, const xs_dict *object) /* creates a 'Create' message */ { xs_dict *msg = msg_base(snac, "Create", "@wrapper", snac->actor, NULL, object); - xs_val *v; + const xs_val *v; if ((v = get_atto(object))) msg = xs_dict_append(msg, "attributedTo", v); @@ -1331,7 +1265,7 @@ xs_dict *msg_create(snac *snac, const xs_dict *object) } -xs_dict *msg_undo(snac *snac, char *object) +xs_dict *msg_undo(snac *snac, const xs_val *object) /* creates an 'Undo' message */ { xs_dict *msg = msg_base(snac, "Undo", "@object", snac->actor, "@now", object); @@ -1344,7 +1278,7 @@ xs_dict *msg_undo(snac *snac, char *object) } -xs_dict *msg_delete(snac *snac, char *id) +xs_dict *msg_delete(snac *snac, const char *id) /* creates a 'Delete' + 'Tombstone' for a local entry */ { xs *tomb = xs_dict_new(); @@ -1386,7 +1320,7 @@ xs_dict *msg_follow(snac *snac, const char *q) if (valid_status(status)) { /* check if the actor is an alias */ - char *r_actor = xs_dict_get(actor_o, "id"); + const char *r_actor = xs_dict_get(actor_o, "id"); if (r_actor && strcmp(actor, r_actor) != 0) { snac_log(snac, xs_fmt("actor to follow is an alias %s -> %s", actor, r_actor)); @@ -1402,7 +1336,7 @@ xs_dict *msg_follow(snac *snac, const char *q) xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts, - xs_str *in_reply_to, xs_list *attach, int priv) + const xs_str *in_reply_to, const xs_list *attach, int priv) /* creates a 'Note' message */ { xs *ntid = tid(0); @@ -1442,7 +1376,7 @@ xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts, if (valid_status(object_get(in_reply_to, &p_msg))) { /* add this author as recipient */ - char *a, *v; + const char *a, *v; if ((a = get_atto(p_msg)) && xs_list_in(to, a) == -1) to = xs_list_append(to, a); @@ -1453,7 +1387,7 @@ xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts, xs *actor_o = NULL; if (xs_list_len(l) > 3 && valid_status(object_get(a, &actor_o))) { - char *uname = xs_dict_get(actor_o, "preferredUsername"); + 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)); @@ -1492,7 +1426,8 @@ xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts, /* create the attachment list, if there are any */ if (!xs_is_null(attach)) { - while (xs_list_iter(&attach, &v)) { + int c = 0; + while (xs_list_next(attach, &v, &c)) { xs *d = xs_dict_new(); const char *url = xs_list_get(v, 0); const char *alt = xs_list_get(v, 1); @@ -1515,7 +1450,7 @@ xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts, p = tag; while (xs_list_iter(&p, &v)) { if (xs_type(v) == XSTYPE_DICT) { - char *t; + const char *t; if (!xs_is_null(t = xs_dict_get(v, "type")) && strcmp(t, "Mention") == 0) { if (!xs_is_null(t = xs_dict_get(v, "href"))) @@ -1639,7 +1574,7 @@ int update_question(snac *user, const char *id) xs *msg = NULL; xs *rcnt = xs_dict_new(); xs *lopts = xs_list_new(); - xs_list *opts; + const xs_list *opts; xs_list *p; xs_val *v; @@ -1657,8 +1592,8 @@ int update_question(snac *user, const char *id) return -3; /* fill the initial count */ - p = opts; - while (xs_list_iter(&p, &v)) { + int c = 0; + while (xs_list_next(opts, &v, &c)) { const char *name = xs_dict_get(v, "name"); if (name) { lopts = xs_list_append(lopts, name); @@ -1764,13 +1699,13 @@ int update_question(snac *user, const char *id) /** queues **/ -int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) +int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) /* processes an ActivityPub message from the input queue */ /* return values: -1, fatal error; 0, transient error, retry; 1, processed and done; 2, propagate to users (only when no user is set) */ { - char *actor = xs_dict_get(msg, "actor"); - char *type = xs_dict_get(msg, "type"); + const char *actor = xs_dict_get(msg, "actor"); + const char *type = xs_dict_get(msg, "type"); xs *actor_o = NULL; int a_status; int do_notify = 0; @@ -1790,7 +1725,7 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) return -1; } - char *object, *utype; + const char *object, *utype; object = xs_dict_get(msg, "object"); if (object != NULL && xs_type(object) == XSTYPE_DICT) @@ -1813,7 +1748,7 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) } /* also discard if the object to be deleted is not here */ - char *obj_id = object; + const char *obj_id = object; if (xs_type(obj_id) == XSTYPE_DICT) obj_id = xs_dict_get(obj_id, "id"); @@ -1885,7 +1820,7 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) int min_account_age = xs_number_get(xs_dict_get(srv_config, "min_account_age")); if (min_account_age > 0) { - char *actor_date = xs_dict_get(actor_o, "published"); + const char *actor_date = xs_dict_get(actor_o, "published"); if (!xs_is_null(actor_date)) { time_t actor_t = xs_parse_iso_date(actor_date, 0); @@ -1945,7 +1880,7 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) } else if (strcmp(type, "Undo") == 0) { /** **/ - char *id = xs_dict_get(object, "object"); + const char *id = xs_dict_get(object, "object"); if (xs_type(object) != XSTYPE_DICT) utype = "Follow"; @@ -1990,9 +1925,9 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) } if (xs_match(utype, "Note|Article")) { /** **/ - char *id = xs_dict_get(object, "id"); - char *in_reply_to = xs_dict_get(object, "inReplyTo"); - char *atto = get_atto(object); + const char *id = xs_dict_get(object, "id"); + const char *in_reply_to = xs_dict_get(object, "inReplyTo"); + const char *atto = get_atto(object); xs *wrk = NULL; if (xs_is_null(id)) @@ -2029,14 +1964,14 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) } else if (strcmp(utype, "Question") == 0) { /** **/ - char *id = xs_dict_get(object, "id"); + const char *id = xs_dict_get(object, "id"); if (timeline_add(snac, id, object)) snac_log(snac, xs_fmt("new 'Question' %s %s", actor, id)); } else if (strcmp(utype, "Video") == 0) { /** **/ - char *id = xs_dict_get(object, "id"); + const char *id = xs_dict_get(object, "id"); if (timeline_add(snac, id, object)) snac_log(snac, xs_fmt("new 'Video' %s %s", actor, id)); @@ -2212,7 +2147,7 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) } -int send_email(char *msg) +int send_email(const char *msg) /* invoke sendmail with email headers and body in msg */ { FILE *f; @@ -2244,14 +2179,14 @@ int send_email(char *msg) void process_user_queue_item(snac *snac, xs_dict *q_item) /* processes an item from the user queue */ { - char *type; + const char *type; int queue_retry_max = xs_number_get(xs_dict_get(srv_config, "queue_retry_max")); if ((type = xs_dict_get(q_item, "type")) == NULL) type = "output"; if (strcmp(type, "message") == 0) { - xs_dict *msg = xs_dict_get(q_item, "message"); + const xs_dict *msg = xs_dict_get(q_item, "message"); xs *rcpts = recipient_list(snac, msg, 1); xs_set inboxes; xs_list *p; @@ -2292,8 +2227,8 @@ void process_user_queue_item(snac *snac, xs_dict *q_item) else if (strcmp(type, "input") == 0) { /* process the message */ - xs_dict *msg = xs_dict_get(q_item, "message"); - xs_dict *req = xs_dict_get(q_item, "req"); + const xs_dict *msg = xs_dict_get(q_item, "message"); + const xs_dict *req = xs_dict_get(q_item, "req"); int retries = xs_number_get(xs_dict_get(q_item, "retries")); if (xs_is_null(msg)) @@ -2320,13 +2255,6 @@ void process_user_queue_item(snac *snac, xs_dict *q_item) update_question(snac, id); } else - if (strcmp(type, "request_replies") == 0) { - const char *id = xs_dict_get(q_item, "message"); - - if (!xs_is_null(id)) - timeline_request_replies(snac, id); - } - else if (strcmp(type, "object_request") == 0) { const char *id = xs_dict_get(q_item, "message"); @@ -2395,15 +2323,15 @@ int process_user_queue(snac *snac) void process_queue_item(xs_dict *q_item) /* processes an item from the global queue */ { - char *type = xs_dict_get(q_item, "type"); + const char *type = xs_dict_get(q_item, "type"); int queue_retry_max = xs_number_get(xs_dict_get(srv_config, "queue_retry_max")); if (strcmp(type, "output") == 0) { int status; - xs_str *inbox = xs_dict_get(q_item, "inbox"); - xs_str *keyid = xs_dict_get(q_item, "keyid"); - xs_str *seckey = xs_dict_get(q_item, "seckey"); - xs_dict *msg = xs_dict_get(q_item, "message"); + const xs_str *inbox = xs_dict_get(q_item, "inbox"); + const xs_str *keyid = xs_dict_get(q_item, "keyid"); + const xs_str *seckey = xs_dict_get(q_item, "seckey"); + const xs_dict *msg = xs_dict_get(q_item, "message"); int retries = xs_number_get(xs_dict_get(q_item, "retries")); int p_status = xs_number_get(xs_dict_get(q_item, "p_status")); xs *payload = NULL; @@ -2475,7 +2403,7 @@ void process_queue_item(xs_dict *q_item) else if (strcmp(type, "email") == 0) { /* send this email */ - xs_str *msg = xs_dict_get(q_item, "message"); + const xs_str *msg = xs_dict_get(q_item, "message"); int retries = xs_number_get(xs_dict_get(q_item, "retries")); if (!send_email(msg)) @@ -2497,8 +2425,8 @@ void process_queue_item(xs_dict *q_item) else if (strcmp(type, "telegram") == 0) { /* send this via telegram */ - char *bot = xs_dict_get(q_item, "bot"); - char *msg = xs_dict_get(q_item, "message"); + const char *bot = xs_dict_get(q_item, "bot"); + const char *msg = xs_dict_get(q_item, "message"); xs *chat_id = xs_dup(xs_dict_get(q_item, "chat_id")); int status = 0; @@ -2521,9 +2449,9 @@ void process_queue_item(xs_dict *q_item) else if (strcmp(type, "ntfy") == 0) { /* send this via ntfy */ - char *ntfy_server = xs_dict_get(q_item, "ntfy_server"); - char *msg = xs_dict_get(q_item, "message"); - char *ntfy_token = xs_dict_get(q_item, "ntfy_token"); + const char *ntfy_server = xs_dict_get(q_item, "ntfy_server"); + const char *msg = xs_dict_get(q_item, "message"); + const char *ntfy_token = xs_dict_get(q_item, "ntfy_token"); int status = 0; xs *url = xs_fmt("%s", ntfy_server); @@ -2552,8 +2480,8 @@ void process_queue_item(xs_dict *q_item) } else if (strcmp(type, "input") == 0) { - xs_dict *msg = xs_dict_get(q_item, "message"); - xs_dict *req = xs_dict_get(q_item, "req"); + const xs_dict *msg = xs_dict_get(q_item, "message"); + const xs_dict *req = xs_dict_get(q_item, "req"); int retries = xs_number_get(xs_dict_get(q_item, "retries")); /* do some instance-level checks */ @@ -2572,7 +2500,7 @@ void process_queue_item(xs_dict *q_item) else if (r == 2) { /* redistribute the input message to all users */ - char *ntid = xs_dict_get(q_item, "ntid"); + const char *ntid = xs_dict_get(q_item, "ntid"); xs *tmpfn = xs_fmt("%s/tmp/%s.json", srv_basedir, ntid); FILE *f; @@ -2647,7 +2575,7 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path, char **body, int *b_size, char **ctype) { int status = 200; - char *accept = xs_dict_get(req, "accept"); + const char *accept = xs_dict_get(req, "accept"); snac snac; xs *msg = NULL; @@ -2659,7 +2587,8 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path, return 0; xs *l = xs_split_n(q_path, "/", 2); - char *uid, *p_path; + const char *uid; + const char *p_path; uid = xs_list_get(l, 1); if (!user_open(&snac, uid)) { @@ -2677,7 +2606,7 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path, msg = msg_actor(&snac); *ctype = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""; - char *ua = xs_dict_get(req, "user-agent"); + const char *ua = xs_dict_get(req, "user-agent"); snac_debug(&snac, 0, xs_fmt("serving actor [%s]", ua ? ua : "No UA")); } @@ -2694,8 +2623,8 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path, xs *i = NULL; if (valid_status(object_get_by_md5(v, &i))) { - char *type = xs_dict_get(i, "type"); - char *id = xs_dict_get(i, "id"); + const char *type = xs_dict_get(i, "type"); + const char *id = xs_dict_get(i, "id"); if (type && id && strcmp(type, "Note") == 0 && xs_startswith(id, snac.actor)) { xs *c_msg = msg_create(&snac, i); @@ -2748,9 +2677,9 @@ int activitypub_post_handler(const xs_dict *req, const char *q_path, (void)b_size; int status = 202; /* accepted */ - char *i_ctype = xs_dict_get(req, "content-type"); + const char *i_ctype = xs_dict_get(req, "content-type"); snac snac; - char *v; + const char *v; if (i_ctype == NULL) { *body = xs_str_new("no content-type"); diff --git a/data.c b/data.c index 0cceefd..3377f3e 100644 --- a/data.c +++ b/data.c @@ -29,7 +29,7 @@ pthread_mutex_t data_mutex = {0}; int snac_upgrade(xs_str **error); -int srv_open(char *basedir, int auto_upgrade) +int srv_open(const char *basedir, int auto_upgrade) /* opens a server */ { int ret = 0; @@ -58,10 +58,10 @@ int srv_open(char *basedir, int auto_upgrade) if (srv_config == NULL) error = xs_fmt("ERROR: cannot parse '%s'", cfg_file); else { - char *host; - char *prefix; - char *dbglvl; - char *proto; + const char *host; + const char *prefix; + const char *dbglvl; + const char *proto; host = xs_dict_get(srv_config, "host"); prefix = xs_dict_get(srv_config, "prefix"); @@ -710,7 +710,7 @@ int _object_add(const char *id, const xs_dict *obj, int ow) fclose(f); /* does this object has a parent? */ - char *in_reply_to = xs_dict_get(obj, "inReplyTo"); + const char *in_reply_to = xs_dict_get(obj, "inReplyTo"); if (!xs_is_null(in_reply_to) && *in_reply_to) { /* update the children index of the parent */ @@ -1124,7 +1124,7 @@ int timeline_get_by_md5(snac *snac, const char *md5, xs_dict **msg) } -int timeline_del(snac *snac, char *id) +int timeline_del(snac *snac, const char *id) /* deletes a message from the timeline */ { /* delete from the user's caches */ @@ -1192,17 +1192,16 @@ int timeline_admire(snac *snac, const char *id, const char *admirer, int like) } -xs_list *timeline_top_level(snac *snac, xs_list *list) +xs_list *timeline_top_level(snac *snac, const xs_list *list) /* returns the top level md5 entries from this index */ { xs_set seen; - xs_list *p; xs_str *v; xs_set_init(&seen); - p = list; - while (xs_list_iter(&p, &v)) { + int c = 0; + while (xs_list_next(list, &v, &c)) { char line[256] = ""; strncpy(line, v, sizeof(line)); @@ -1290,7 +1289,7 @@ int following_add(snac *snac, const char *actor, const xs_dict *msg) /* object already exists; if it's of type Accept, the actor is already being followed and confirmed, so do nothing */ - char *type = xs_dict_get(p_object, "type"); + const char *type = xs_dict_get(p_object, "type"); if (!xs_is_null(type) && strcmp(type, "Accept") == 0) { snac_debug(snac, 1, xs_fmt("following_add actor already confirmed %s", actor)); @@ -1546,8 +1545,9 @@ void hide(snac *snac, const char *id) /* resolve to get the id */ if (valid_status(object_get_by_md5(v, &co))) { - if ((v = xs_dict_get(co, "id")) != NULL) - hide(snac, v); + const char *id = xs_dict_get(co, "id"); + if (id != NULL) + hide(snac, id); } } } @@ -1563,7 +1563,7 @@ int is_hidden(snac *snac, const char *id) } -int actor_add(const char *actor, xs_dict *msg) +int actor_add(const char *actor, const xs_dict *msg) /* adds an actor */ { return object_add_ow(actor, msg); @@ -1687,7 +1687,7 @@ int limited(snac *user, const char *id, int cmd) void tag_index(const char *id, const xs_dict *obj) /* update the tag indexes for this object */ { - xs_list *tags = xs_dict_get(obj, "tag"); + const xs_list *tags = xs_dict_get(obj, "tag"); if (is_msg_public(obj) && xs_type(tags) == XSTYPE_LIST && xs_list_len(tags) > 0) { xs *g_tag_dir = xs_fmt("%s/tag", srv_basedir); @@ -1695,9 +1695,10 @@ void tag_index(const char *id, const xs_dict *obj) mkdirx(g_tag_dir); xs_dict *v; - while (xs_list_iter(&tags, &v)) { - char *type = xs_dict_get(v, "type"); - char *name = xs_dict_get(v, "name"); + int ct = 0; + while (xs_list_next(tags, &v, &ct)) { + const char *type = xs_dict_get(v, "type"); + const char *name = xs_dict_get(v, "name"); if (!xs_is_null(type) && !xs_is_null(name) && strcmp(type, "Hashtag") == 0) { while (*name == '#' || *name == '@') @@ -1706,7 +1707,7 @@ void tag_index(const char *id, const xs_dict *obj) if (*name == '\0') continue; - name = xs_tolower_i(name); + name = xs_tolower_i((xs_str *)name); xs *md5_tag = xs_md5_hex(name, strlen(name)); xs *tag_dir = xs_fmt("%s/%c%c", g_tag_dir, md5_tag[0], md5_tag[1]); @@ -1729,7 +1730,7 @@ void tag_index(const char *id, const xs_dict *obj) } -xs_list *tag_search(char *tag, int skip, int show) +xs_list *tag_search(const char *tag, int skip, int show) /* returns the list of posts tagged with tag */ { if (*tag == '#') @@ -1912,7 +1913,7 @@ xs_val *list_content(snac *user, const char *list, const char *actor_md5, int op void list_distribute(snac *user, const char *who, const xs_dict *post) /* distributes the post to all appropriate lists */ { - char *id = xs_dict_get(post, "id"); + const char *id = xs_dict_get(post, "id"); /* if who is not set, use the attributedTo in the message */ if (xs_is_null(who)) @@ -2164,7 +2165,7 @@ void inbox_add(const char *inbox) void inbox_add_by_actor(const xs_dict *actor) /* collects an actor's shared inbox, if it has one */ { - char *v; + const char *v; if (!xs_is_null(v = xs_dict_get(actor, "endpoints")) && !xs_is_null(v = xs_dict_get(v, "sharedInbox"))) { @@ -2210,7 +2211,7 @@ xs_str *_instance_block_fn(const char *instance) xs *s = xs_replace(instance, "http:/" "/", ""); xs *s1 = xs_replace(s, "https:/" "/", ""); xs *l = xs_split(s1, "/"); - char *p = xs_list_get(l, 0); + const char *p = xs_list_get(l, 0); xs *md5 = xs_md5_hex(p, strlen(p)); return xs_fmt("%s/block/%s", srv_basedir, md5); @@ -2279,7 +2280,7 @@ int content_match(const char *file, const xs_dict *msg) xs *fn = xs_fmt("%s/%s", srv_basedir, file); FILE *f; int r = 0; - char *v = xs_dict_get(msg, "content"); + const char *v = xs_dict_get(msg, "content"); if (xs_type(v) == XSTYPE_STRING && *v) { if ((f = fopen(fn, "r")) != NULL) { @@ -2386,7 +2387,7 @@ xs_list *content_search(snac *user, const char *regex, if (id == NULL || is_hidden(user, id)) continue; - char *content = xs_dict_get(post, "content"); + const char *content = xs_dict_get(post, "content"); if (xs_is_null(content)) continue; @@ -2639,7 +2640,7 @@ void enqueue_input(snac *snac, const xs_dict *msg, const xs_dict *req, int retri /* enqueues an input message */ { xs *qmsg = _new_qmsg("input", msg, retries); - char *ntid = xs_dict_get(qmsg, "ntid"); + const char *ntid = xs_dict_get(qmsg, "ntid"); xs *fn = xs_fmt("%s/queue/%s.json", snac->basedir, ntid); qmsg = xs_dict_append(qmsg, "req", req); @@ -2654,7 +2655,7 @@ void enqueue_shared_input(const xs_dict *msg, const xs_dict *req, int retries) /* enqueues an input message from the shared input */ { xs *qmsg = _new_qmsg("input", msg, retries); - char *ntid = xs_dict_get(qmsg, "ntid"); + const char *ntid = xs_dict_get(qmsg, "ntid"); xs *fn = xs_fmt("%s/queue/%s.json", srv_basedir, ntid); qmsg = xs_dict_append(qmsg, "req", req); @@ -2666,11 +2667,12 @@ void enqueue_shared_input(const xs_dict *msg, const xs_dict *req, int retries) void enqueue_output_raw(const char *keyid, const char *seckey, - xs_dict *msg, xs_str *inbox, int retries, int p_status) + const xs_dict *msg, const xs_str *inbox, + int retries, int p_status) /* enqueues an output message to an inbox */ { xs *qmsg = _new_qmsg("output", msg, retries); - char *ntid = xs_dict_get(qmsg, "ntid"); + const char *ntid = xs_dict_get(qmsg, "ntid"); xs *fn = xs_fmt("%s/queue/%s.json", srv_basedir, ntid); xs *ns = xs_number_new(p_status); @@ -2690,7 +2692,8 @@ void enqueue_output_raw(const char *keyid, const char *seckey, } -void enqueue_output(snac *snac, xs_dict *msg, xs_str *inbox, int retries, int p_status) +void enqueue_output(snac *snac, const xs_dict *msg, + const xs_str *inbox, int retries, int p_status) /* enqueues an output message to an inbox */ { if (xs_startswith(inbox, snac->actor)) { @@ -2698,13 +2701,14 @@ void enqueue_output(snac *snac, xs_dict *msg, xs_str *inbox, int retries, int p_ return; } - char *seckey = xs_dict_get(snac->key, "secret"); + const char *seckey = xs_dict_get(snac->key, "secret"); enqueue_output_raw(snac->actor, seckey, msg, inbox, retries, p_status); } -void enqueue_output_by_actor(snac *snac, xs_dict *msg, const xs_str *actor, int retries) +void enqueue_output_by_actor(snac *snac, const xs_dict *msg, + const xs_str *actor, int retries) /* enqueues an output message for an actor */ { xs *inbox = get_actor_inbox(actor); @@ -2716,11 +2720,11 @@ void enqueue_output_by_actor(snac *snac, xs_dict *msg, const xs_str *actor, int } -void enqueue_email(xs_str *msg, int retries) +void enqueue_email(const xs_str *msg, int retries) /* enqueues an email message to be sent */ { xs *qmsg = _new_qmsg("email", msg, retries); - char *ntid = xs_dict_get(qmsg, "ntid"); + const char *ntid = xs_dict_get(qmsg, "ntid"); xs *fn = xs_fmt("%s/queue/%s.json", srv_basedir, ntid); qmsg = _enqueue_put(fn, qmsg); @@ -2733,7 +2737,7 @@ void enqueue_telegram(const xs_str *msg, const char *bot, const char *chat_id) /* enqueues a message to be sent via Telegram */ { xs *qmsg = _new_qmsg("telegram", msg, 0); - char *ntid = xs_dict_get(qmsg, "ntid"); + const char *ntid = xs_dict_get(qmsg, "ntid"); xs *fn = xs_fmt("%s/queue/%s.json", srv_basedir, ntid); qmsg = xs_dict_append(qmsg, "bot", bot); @@ -2748,7 +2752,7 @@ void enqueue_ntfy(const xs_str *msg, const char *ntfy_server, const char *ntfy_t /* enqueues a message to be sent via ntfy */ { xs *qmsg = _new_qmsg("ntfy", msg, 0); - char *ntid = xs_dict_get(qmsg, "ntid"); + const char *ntid = xs_dict_get(qmsg, "ntid"); xs *fn = xs_fmt("%s/queue/%s.json", srv_basedir, ntid); qmsg = xs_dict_append(qmsg, "ntfy_server", ntfy_server); @@ -2764,7 +2768,7 @@ void enqueue_message(snac *snac, const xs_dict *msg) /* enqueues an output message */ { xs *qmsg = _new_qmsg("message", msg, 0); - char *ntid = xs_dict_get(qmsg, "ntid"); + const char *ntid = xs_dict_get(qmsg, "ntid"); xs *fn = xs_fmt("%s/queue/%s.json", snac->basedir, ntid); qmsg = _enqueue_put(fn, qmsg); @@ -2807,7 +2811,7 @@ void enqueue_verify_links(snac *user) /* enqueues a link verification */ { xs *qmsg = _new_qmsg("verify_links", "", 0); - char *ntid = xs_dict_get(qmsg, "ntid"); + const char *ntid = xs_dict_get(qmsg, "ntid"); xs *fn = xs_fmt("%s/queue/%s.json", user->basedir, ntid); qmsg = _enqueue_put(fn, qmsg); @@ -2832,42 +2836,6 @@ void enqueue_actor_refresh(snac *user, const char *actor, int forward_secs) } -void enqueue_request_replies(snac *user, const char *id) -/* enqueues a request for the replies of a message */ -{ - /* test first if this precise request is already in the queue */ - xs *queue = user_queue(user); - xs_list *p = queue; - xs_str *v; - - while (xs_list_iter(&p, &v)) { - xs *q_item = queue_get(v); - - if (q_item != NULL) { - const char *type = xs_dict_get(q_item, "type"); - const char *msg = xs_dict_get(q_item, "message"); - - if (type && msg && strcmp(type, "request_replies") == 0 && strcmp(msg, id) == 0) { - /* don't requeue */ - snac_debug(user, 1, xs_fmt("enqueue_request_replies already here %s", id)); - return; - } - } - } - - /* not there; enqueue the request with a small delay */ - xs *qmsg = _new_qmsg("request_replies", id, 0); - xs *ntid = tid(10); - xs *fn = xs_fmt("%s/queue/%s.json", user->basedir, ntid); - - qmsg = xs_dict_set(qmsg, "ntid", ntid); - - qmsg = _enqueue_put(fn, qmsg); - - snac_debug(user, 2, xs_fmt("enqueue_request_replies %s", id)); -} - - int was_question_voted(snac *user, const char *id) /* returns true if the user voted in this poll */ { @@ -2881,7 +2849,7 @@ int was_question_voted(snac *user, const char *id) xs *obj = NULL; if (valid_status(object_get_by_md5(md5, &obj))) { - char *atto = get_atto(obj); + const char *atto = get_atto(obj); if (atto && strcmp(atto, user->actor) == 0 && !xs_is_null(xs_dict_get(obj, "name"))) { voted = 1; @@ -3055,7 +3023,7 @@ void purge_server(void) if (mtime_nl(v2, &n_link) < mt && n_link < 2) { xs *s1 = xs_replace(v2, ".json", ""); xs *l = xs_split(s1, "/"); - char *md5 = xs_list_get(l, -1); + const char *md5 = xs_list_get(l, -1); object_del_by_md5(md5); cnt++; @@ -3147,7 +3115,7 @@ void purge_user(snac *snac) /* do the purge for this user */ { int priv_days, pub_days, user_days = 0; - char *v; + const char *v; int n; priv_days = xs_number_get(xs_dict_get(srv_config, "timeline_purge_days")); @@ -3256,7 +3224,7 @@ void srv_archive(const char *direction, const char *url, xs_dict *req, if (p_size && payload) { xs *payload_fn = NULL; xs *payload_fn_raw = NULL; - char *v = xs_dict_get(req, "content-type"); + const char *v = xs_dict_get(req, "content-type"); if (v && xs_str_in(v, "json") != -1) { payload_fn = xs_fmt("%s/payload.json", dir); @@ -3287,7 +3255,7 @@ void srv_archive(const char *direction, const char *url, xs_dict *req, if (b_size && body) { xs *body_fn = NULL; - char *v = xs_dict_get(headers, "content-type"); + const char *v = xs_dict_get(headers, "content-type"); if (v && xs_str_in(v, "json") != -1) { body_fn = xs_fmt("%s/body.json", dir); @@ -3356,7 +3324,7 @@ void srv_archive_error(const char *prefix, const xs_str *err, } -void srv_archive_qitem(char *prefix, xs_dict *q_item) +void srv_archive_qitem(const char *prefix, xs_dict *q_item) /* archives a q_item in the error folder */ { xs *ntid = tid(0); diff --git a/html.c b/html.c index 6351823..6521726 100644 --- a/html.c +++ b/html.c @@ -41,7 +41,7 @@ int login(snac *snac, const xs_dict *headers) } -xs_str *replace_shortnames(xs_str *s, xs_list *tag, int ems) +xs_str *replace_shortnames(xs_str *s, const xs_list *tag, int ems) /* replaces all the :shortnames: with the emojis in tag */ { if (!xs_is_null(tag)) { @@ -57,18 +57,18 @@ xs_str *replace_shortnames(xs_str *s, xs_list *tag, int ems) xs *style = xs_fmt("height: %dem; width: %dem; vertical-align: middle;", ems, ems); - xs_list *p = tag_list; char *v; + int c = 0; - while (xs_list_iter(&p, &v)) { - char *t = xs_dict_get(v, "type"); + while (xs_list_next(tag_list, &v, &c)) { + const char *t = xs_dict_get(v, "type"); if (t && strcmp(t, "Emoji") == 0) { - char *n = xs_dict_get(v, "name"); - char *i = xs_dict_get(v, "icon"); + const char *n = xs_dict_get(v, "name"); + const char *i = xs_dict_get(v, "icon"); if (n && i) { - char *u = xs_dict_get(i, "url"); + const char *u = xs_dict_get(i, "url"); xs_html *img = xs_html_sctag("img", xs_html_attr("loading", "lazy"), xs_html_attr("src", u), @@ -88,7 +88,7 @@ xs_str *replace_shortnames(xs_str *s, xs_list *tag, int ems) xs_str *actor_name(xs_dict *actor) /* gets the actor name */ { - char *v; + const char *v; if (xs_is_null((v = xs_dict_get(actor, "name"))) || *v == '\0') { if (xs_is_null(v = xs_dict_get(actor, "preferredUsername")) || *v == '\0') { @@ -106,7 +106,7 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date, xs_html *actor_icon = xs_html_tag("p", NULL); xs *avatar = NULL; - char *v; + const char *v; int fwing = 0; int fwer = 0; @@ -125,7 +125,7 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date, if (avatar == NULL) avatar = xs_fmt("data:image/png;base64, %s", default_avatar_base64()); - char *actor_id = xs_dict_get(actor, "id"); + const char *actor_id = xs_dict_get(actor, "id"); xs *href = NULL; if (user) { @@ -216,7 +216,7 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date, } { - char *username, *id; + const char *username, *id; if (xs_is_null(username = xs_dict_get(actor, "preferredUsername")) || *username == '\0') { /* This should never be reached */ @@ -244,15 +244,15 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date, } -xs_html *html_msg_icon(snac *user, char *actor_id, const xs_dict *msg) +xs_html *html_msg_icon(snac *user, const char *actor_id, const xs_dict *msg) { xs *actor = NULL; xs_html *actor_icon = NULL; if (actor_id && valid_status(actor_get_refresh(user, actor_id, &actor))) { - char *date = NULL; - char *udate = NULL; - char *url = NULL; + const char *date = NULL; + const char *udate = NULL; + const char *url = NULL; int priv = 0; const char *type = xs_dict_get(msg, "type"); @@ -271,14 +271,14 @@ xs_html *html_msg_icon(snac *user, char *actor_id, const xs_dict *msg) } -xs_html *html_note(snac *user, char *summary, - char *div_id, char *form_id, - char *ta_plh, char *ta_content, - char *edit_id, char *actor_id, - xs_val *cw_yn, char *cw_text, - xs_val *mnt_only, char *redir, - char *in_reply_to, int poll, - char *att_file, char *att_alt_text) +xs_html *html_note(snac *user, const char *summary, + const char *div_id, const char *form_id, + const char *ta_plh, const char *ta_content, + const char *edit_id, const char *actor_id, + const xs_val *cw_yn, const char *cw_text, + const xs_val *mnt_only, const char *redir, + const char *in_reply_to, int poll, + const char *att_file, const char *att_alt_text) { xs *action = xs_fmt("%s/admin/note", user->actor); @@ -460,9 +460,11 @@ static xs_html *html_base_head(void) /* add server CSS and favicon */ xs *f; f = xs_fmt("%s/favicon.ico", srv_baseurl); - xs_list *p = xs_dict_get(srv_config, "cssurls"); + const xs_list *p = xs_dict_get(srv_config, "cssurls"); char *v; - while (xs_list_iter(&p, &v)) { + int c = 0; + + while (xs_list_next(p, &v, &c)) { xs_html_add(head, xs_html_sctag("link", xs_html_attr("rel", "stylesheet"), @@ -498,8 +500,8 @@ xs_html *html_instance_head(void) } } - char *host = xs_dict_get(srv_config, "host"); - char *title = xs_dict_get(srv_config, "title"); + const char *host = xs_dict_get(srv_config, "host"); + const char *title = xs_dict_get(srv_config, "title"); xs_html_add(head, xs_html_tag("title", @@ -511,10 +513,10 @@ xs_html *html_instance_head(void) static xs_html *html_instance_body(void) { - char *host = xs_dict_get(srv_config, "host"); - char *sdesc = xs_dict_get(srv_config, "short_description"); - char *email = xs_dict_get(srv_config, "admin_email"); - char *acct = xs_dict_get(srv_config, "admin_account"); + const char *host = xs_dict_get(srv_config, "host"); + const char *sdesc = xs_dict_get(srv_config, "short_description"); + const char *email = xs_dict_get(srv_config, "admin_email"); + const char *acct = xs_dict_get(srv_config, "admin_account"); xs *blurb = xs_replace(snac_blurb, "%host%", host); @@ -760,7 +762,7 @@ static xs_html *html_user_body(snac *user, int read_only) xs_html_attr("class", "h-card snac-top-user")); if (read_only) { - char *header = xs_dict_get(user->config, "header"); + const char *header = xs_dict_get(user->config, "header"); if (header && *header) { xs_html_add(top_user, xs_html_tag("div", @@ -797,7 +799,7 @@ static xs_html *html_user_body(snac *user, int read_only) xs_html_add(top_user, top_user_bio); - xs_dict *metadata = xs_dict_get(user->config, "metadata"); + const xs_dict *metadata = xs_dict_get(user->config, "metadata"); if (xs_type(metadata) == XSTYPE_DICT) { xs_str *k; xs_str *v; @@ -816,7 +818,7 @@ static xs_html *html_user_body(snac *user, int read_only) if (xs_startswith(v, "https:/") || xs_startswith(v, "http:/")) { /* is this link validated? */ xs *verified_link = NULL; - xs_number *val_time = xs_dict_get(val_links, v); + const xs_number *val_time = xs_dict_get(val_links, v); if (xs_type(val_time) == XSTYPE_NUMBER) { time_t t = xs_number_get(val_time); @@ -928,7 +930,7 @@ xs_html *html_top_controls(snac *snac) /** user settings **/ - char *email = "[disabled by admin]"; + const char *email = "[disabled by admin]"; if (xs_type(xs_dict_get(srv_config, "disable_email_notifications")) != XSTYPE_TRUE) { email = xs_dict_get(snac->config_o, "email"); @@ -940,38 +942,38 @@ xs_html *html_top_controls(snac *snac) } } - char *cw = xs_dict_get(snac->config, "cw"); + const char *cw = xs_dict_get(snac->config, "cw"); if (xs_is_null(cw)) cw = ""; - char *telegram_bot = xs_dict_get(snac->config, "telegram_bot"); + const char *telegram_bot = xs_dict_get(snac->config, "telegram_bot"); if (xs_is_null(telegram_bot)) telegram_bot = ""; - char *telegram_chat_id = xs_dict_get(snac->config, "telegram_chat_id"); + const char *telegram_chat_id = xs_dict_get(snac->config, "telegram_chat_id"); if (xs_is_null(telegram_chat_id)) telegram_chat_id = ""; - char *ntfy_server = xs_dict_get(snac->config, "ntfy_server"); + const char *ntfy_server = xs_dict_get(snac->config, "ntfy_server"); if (xs_is_null(ntfy_server)) ntfy_server = ""; - char *ntfy_token = xs_dict_get(snac->config, "ntfy_token"); + const char *ntfy_token = xs_dict_get(snac->config, "ntfy_token"); if (xs_is_null(ntfy_token)) ntfy_token = ""; - char *purge_days = xs_dict_get(snac->config, "purge_days"); + const char *purge_days = xs_dict_get(snac->config, "purge_days"); if (!xs_is_null(purge_days) && xs_type(purge_days) == XSTYPE_NUMBER) purge_days = (char *)xs_number_str(purge_days); else purge_days = "0"; - xs_val *d_dm_f_u = xs_dict_get(snac->config, "drop_dm_from_unknown"); - xs_val *bot = xs_dict_get(snac->config, "bot"); - xs_val *a_private = xs_dict_get(snac->config, "private"); + const xs_val *d_dm_f_u = xs_dict_get(snac->config, "drop_dm_from_unknown"); + const xs_val *bot = xs_dict_get(snac->config, "bot"); + const xs_val *a_private = xs_dict_get(snac->config, "private"); xs *metadata = xs_str_new(NULL); - xs_dict *md = xs_dict_get(snac->config, "metadata"); + const xs_dict *md = xs_dict_get(snac->config, "metadata"); xs_str *k; xs_str *v; @@ -1158,13 +1160,14 @@ xs_str *build_mentions(snac *snac, const xs_dict *msg) /* returns a string with the mentions in msg */ { xs_str *s = xs_str_new(NULL); - char *list = xs_dict_get(msg, "tag"); + const char *list = xs_dict_get(msg, "tag"); char *v; + int c = 0; - while (xs_list_iter(&list, &v)) { - char *type = xs_dict_get(v, "type"); - char *href = xs_dict_get(v, "href"); - char *name = xs_dict_get(v, "name"); + while (xs_list_next(list, &v, &c)) { + const char *type = xs_dict_get(v, "type"); + const char *href = xs_dict_get(v, "href"); + const char *name = xs_dict_get(v, "name"); if (type && strcmp(type, "Mention") == 0 && href && strcmp(href, snac->actor) != 0 && name) { @@ -1208,10 +1211,11 @@ xs_str *build_mentions(snac *snac, const xs_dict *msg) } -xs_html *html_entry_controls(snac *snac, char *actor, const xs_dict *msg, const char *md5) +xs_html *html_entry_controls(snac *snac, const char *actor, + const xs_dict *msg, const char *md5) { - char *id = xs_dict_get(msg, "id"); - char *group = xs_dict_get(msg, "audience"); + const char *id = xs_dict_get(msg, "id"); + const char *group = xs_dict_get(msg, "audience"); xs *likes = object_likes(id); xs *boosts = object_announces(id); @@ -1310,7 +1314,7 @@ xs_html *html_entry_controls(snac *snac, char *actor, const xs_dict *msg, const html_button("delete", L("Delete"), L("Delete this post")), html_button("hide", L("Hide"), L("Hide this post and its children"))); - char *prev_src = xs_dict_get(msg, "sourceContent"); + const char *prev_src = xs_dict_get(msg, "sourceContent"); if (!xs_is_null(prev_src) && strcmp(actor, snac->actor) == 0) { /** edit **/ /* post can be edited */ @@ -1318,13 +1322,13 @@ xs_html *html_entry_controls(snac *snac, char *actor, const xs_dict *msg, const xs *form_id = xs_fmt("%s_edit_form", md5); xs *redir = xs_fmt("%s_entry", md5); - char *att_file = ""; - char *att_alt_text = ""; - xs_list *att_list = xs_dict_get(msg, "attachment"); + const char *att_file = ""; + const char *att_alt_text = ""; + const xs_list *att_list = xs_dict_get(msg, "attachment"); /* does it have an attachment? */ if (xs_type(att_list) == XSTYPE_LIST && xs_list_len(att_list)) { - xs_dict *d = xs_list_get(att_list, 0); + const xs_dict *d = xs_list_get(att_list, 0); if (xs_type(d) == XSTYPE_DICT) { att_file = xs_dict_get_def(d, "url", ""); @@ -1370,10 +1374,10 @@ xs_html *html_entry_controls(snac *snac, char *actor, const xs_dict *msg, const xs_html *html_entry(snac *user, xs_dict *msg, int read_only, int level, char *md5, int hide_children) { - char *id = xs_dict_get(msg, "id"); - char *type = xs_dict_get(msg, "type"); - char *actor; - char *v; + const char *id = xs_dict_get(msg, "id"); + const char *type = xs_dict_get(msg, "type"); + const char *actor; + const char *v; int has_title = 0; /* do not show non-public messages in the public timeline */ @@ -1509,7 +1513,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, if (xs_list_len(boosts)) { /* if somebody boosted this, show as origin */ - char *p = xs_list_get(boosts, -1); + const char *p = xs_list_get(boosts, -1); xs *actor_r = NULL; if (user && xs_list_in(boosts, user->md5) != -1) { @@ -1529,7 +1533,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, if (!xs_is_null(name)) { xs *href = NULL; - char *id = xs_dict_get(actor_r, "id"); + const char *id = xs_dict_get(actor_r, "id"); int fwers = 0; int fwing = 0; @@ -1558,7 +1562,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, if (strcmp(type, "Note") == 0) { if (level == 0) { /* is the parent not here? */ - char *parent = xs_dict_get(msg, "inReplyTo"); + const char *parent = xs_dict_get(msg, "inReplyTo"); if (user && !xs_is_null(parent) && *parent && !timeline_here(user, parent)) { xs_html_add(post_header, @@ -1603,7 +1607,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, v = "..."; /* only show it when not in the public timeline and the config setting is "open" */ - char *cw = xs_dict_get(user->config, "cw"); + const char *cw = xs_dict_get(user->config, "cw"); if (xs_is_null(cw) || read_only) cw = ""; @@ -1632,7 +1636,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, { /** build the content string **/ - char *content = xs_dict_get(msg, "content"); + const char *content = xs_dict_get(msg, "content"); xs *c = sanitize(xs_is_null(content) ? "" : content); @@ -1650,7 +1654,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, c = replace_shortnames(c, xs_dict_get(msg, "tag"), 2); /* Peertube videos content is in markdown */ - char *mtype = xs_dict_get(msg, "mediaType"); + const char *mtype = xs_dict_get(msg, "mediaType"); if (xs_type(mtype) == XSTYPE_STRING && strcmp(mtype, "text/markdown") == 0) { /* a full conversion could be better */ c = xs_replace_i(c, "\r", ""); @@ -1663,12 +1667,12 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, } if (strcmp(type, "Question") == 0) { /** question content **/ - xs_list *oo = xs_dict_get(msg, "oneOf"); - xs_list *ao = xs_dict_get(msg, "anyOf"); - xs_list *p; + const xs_list *oo = xs_dict_get(msg, "oneOf"); + const xs_list *ao = xs_dict_get(msg, "anyOf"); + const xs_list *p; xs_dict *v; int closed = 0; - char *f_closed = NULL; + const char *f_closed = NULL; xs_html *poll = xs_html_tag("div", NULL); @@ -1697,10 +1701,11 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, /* closed poll */ xs_html *poll_result = xs_html_tag("table", xs_html_attr("class", "snac-poll-result")); + int c = 0; - while (xs_list_iter(&p, &v)) { - char *name = xs_dict_get(v, "name"); - xs_dict *replies = xs_dict_get(v, "replies"); + while (xs_list_next(p, &v, &c)) { + const char *name = xs_dict_get(v, "name"); + const xs_dict *replies = xs_dict_get(v, "replies"); if (name && replies) { char *ti = (char *)xs_number_str(xs_dict_get(replies, "totalItems")); @@ -1737,9 +1742,10 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, xs_html_attr("name", "irt"), xs_html_attr("value", id)))); - while (xs_list_iter(&p, &v)) { - char *name = xs_dict_get(v, "name"); - xs_dict *replies = xs_dict_get(v, "replies"); + int c = 0; + while (xs_list_next(p, &v, &c)) { + const char *name = xs_dict_get(v, "name"); + const xs_dict *replies = xs_dict_get(v, "replies"); if (name) { char *ti = (char *)xs_number_str(xs_dict_get(replies, "totalItems")); @@ -1777,7 +1783,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, } else { /* show when the poll closes */ - char *end_time = xs_dict_get(msg, "endTime"); + const char *end_time = xs_dict_get(msg, "endTime"); /* Pleroma does not have an endTime field; it has a closed time in the future */ @@ -1820,12 +1826,12 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, xs_html_add(snac_content, content_attachments); - xs_list *p = attach; - - while (xs_list_iter(&p, &v)) { - char *type = xs_dict_get(v, "type"); - char *href = xs_dict_get(v, "href"); - char *name = xs_dict_get(v, "name"); + int c = 0; + xs_dict *a; + while (xs_list_next(attach, &a, &c)) { + const char *type = xs_dict_get(a, "type"); + const char *href = xs_dict_get(a, "href"); + const char *name = xs_dict_get(a, "name"); if (xs_startswith(type, "image/") || strcmp(type, "Image") == 0) { xs_html_add(content_attachments, @@ -1889,7 +1895,7 @@ xs_html *html_entry(snac *user, xs_dict *msg, int read_only, } /* has this message an audience (i.e., comes from a channel or community)? */ - char *audience = xs_dict_get(msg, "audience"); + const char *audience = xs_dict_get(msg, "audience"); if (strcmp(type, "Page") == 0 && !xs_is_null(audience)) { xs_html *au_tag = xs_html_tag("p", xs_html_text("("), @@ -2023,11 +2029,12 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, if (xs_list_len(list) == 1) { /* only one element? pick the description from the source */ - char *id = xs_list_get(list, 0); + const char *id = xs_list_get(list, 0); xs *d = NULL; object_get_by_md5(id, &d); - if (d && (v = xs_dict_get(d, "sourceContent")) != NULL) - desc = xs_dup(v); + const char *sc = xs_dict_get(d, "sourceContent"); + if (d && sc != NULL) + desc = xs_dup(sc); alternate = xs_dup(xs_dict_get(d, "id")); } @@ -2087,13 +2094,13 @@ xs_str *html_timeline(snac *user, const xs_list *list, int read_only, /* is this message a non-public reply? */ if (user != NULL && !is_msg_public(msg)) { - char *irt = xs_dict_get(msg, "inReplyTo"); + const char *irt = xs_dict_get(msg, "inReplyTo"); /* is it a reply to something not in the storage? */ if (!xs_is_null(irt) && !object_here(irt)) { /* is it for me? */ - xs_list *to = xs_dict_get_def(msg, "to", xs_stock(XSTYPE_LIST)); - xs_list *cc = xs_dict_get_def(msg, "cc", xs_stock(XSTYPE_LIST)); + const xs_list *to = xs_dict_get_def(msg, "to", xs_stock(XSTYPE_LIST)); + const xs_list *cc = xs_dict_get_def(msg, "cc", xs_stock(XSTYPE_LIST)); if (xs_list_in(to, user->actor) == -1 && xs_list_in(cc, user->actor) == -1) { snac_debug(user, 1, xs_fmt("skipping non-public reply to an unknown post %s", v)); @@ -2212,7 +2219,7 @@ xs_html *html_people_list(snac *snac, xs_list *list, char *header, char *t) html_actor_icon(snac, actor, xs_dict_get(actor, "published"), NULL, NULL, 0, 1))); /* content (user bio) */ - char *c = xs_dict_get(actor, "summary"); + const char *c = xs_dict_get(actor, "summary"); if (!xs_is_null(c)) { xs *sc = sanitize(c); @@ -2364,10 +2371,10 @@ xs_str *html_notifications(snac *user, int skip, int show) continue; xs *obj = NULL; - char *type = xs_dict_get(noti, "type"); - char *utype = xs_dict_get(noti, "utype"); - char *id = xs_dict_get(noti, "objid"); - char *date = xs_dict_get(noti, "date"); + const char *type = xs_dict_get(noti, "type"); + const char *utype = xs_dict_get(noti, "utype"); + const char *id = xs_dict_get(noti, "objid"); + const char *date = xs_dict_get(noti, "date"); if (xs_is_null(id) || !valid_status(object_get(id, &obj))) continue; @@ -2375,14 +2382,14 @@ xs_str *html_notifications(snac *user, int skip, int show) if (is_hidden(user, id)) continue; - char *actor_id = xs_dict_get(noti, "actor"); + const char *actor_id = xs_dict_get(noti, "actor"); xs *actor = NULL; if (!valid_status(actor_get(actor_id, &actor))) continue; xs *a_name = actor_name(actor); - char *label = type; + const char *label = type; if (strcmp(type, "Create") == 0) label = L("Mention"); @@ -2494,14 +2501,14 @@ xs_str *html_notifications(snac *user, int skip, int show) int html_get_handler(const xs_dict *req, const char *q_path, char **body, int *b_size, char **ctype, xs_str **etag) { - char *accept = xs_dict_get(req, "accept"); + const char *accept = xs_dict_get(req, "accept"); int status = 404; snac snac; xs *uid = NULL; - char *p_path; + const char *p_path; int cache = 1; int save = 1; - char *v; + const char *v; xs *l = xs_split_n(q_path, "/", 2); v = xs_list_get(l, 1); @@ -2540,7 +2547,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, int skip = 0; int show = xs_number_get(xs_dict_get(srv_config, "max_timeline_entries")); - xs_dict *q_vars = xs_dict_get(req, "q_vars"); + const xs_dict *q_vars = xs_dict_get(req, "q_vars"); if ((v = xs_dict_get(q_vars, "skip")) != NULL) skip = atoi(v), cache = 0, save = 0; if ((v = xs_dict_get(q_vars, "show")) != NULL) @@ -2585,7 +2592,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, status = 401; } else { - char *q = xs_dict_get(q_vars, "q"); + const char *q = xs_dict_get(q_vars, "q"); if (q && *q) { if (*q == '#') { @@ -2669,7 +2676,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, } else { xs *l = xs_split(p_path, "/"); - char *md5 = xs_list_get(l, -1); + const char *md5 = xs_list_get(l, -1); if (md5 && *md5 && timeline_here(&snac, md5)) { xs *list = xs_list_append(xs_list_new(), md5); @@ -2728,7 +2735,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, } else { xs *l = xs_split(p_path, "/"); - char *lid = xs_list_get(l, -1); + const char *lid = xs_list_get(l, -1); xs *list = list_timeline(&snac, lid, skip, show); xs *next = list_timeline(&snac, lid, skip + show, 1); @@ -2767,7 +2774,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, else if (xs_startswith(p_path, "s/")) { /** a static file **/ xs *l = xs_split(p_path, "/"); - char *id = xs_list_get(l, 1); + const char *id = xs_list_get(l, 1); int sz; if (id && *id) { @@ -2788,8 +2795,8 @@ int html_get_handler(const xs_dict *req, const char *q_path, if (xs_type(xs_dict_get(srv_config, "disable_history")) == XSTYPE_TRUE) return 403; - xs *l = xs_split(p_path, "/"); - char *id = xs_list_get(l, 1); + xs *l = xs_split(p_path, "/"); + const char *id = xs_list_get(l, 1); if (id && *id) { if (xs_endswith(id, "timeline.html_")) { @@ -2845,8 +2852,9 @@ int html_post_handler(const xs_dict *req, const char *q_path, int status = 0; snac snac; - char *uid, *p_path; - xs_dict *p_vars; + const char *uid; + const char *p_path; + const xs_dict *p_vars; xs *l = xs_split_n(q_path, "/", 2); @@ -2874,15 +2882,15 @@ int html_post_handler(const xs_dict *req, const char *q_path, if (p_path && strcmp(p_path, "admin/note") == 0) { /** **/ /* post note */ - xs_str *content = xs_dict_get(p_vars, "content"); - xs_str *in_reply_to = xs_dict_get(p_vars, "in_reply_to"); - xs_str *attach_url = xs_dict_get(p_vars, "attach_url"); - xs_list *attach_file = xs_dict_get(p_vars, "attach"); - xs_str *to = xs_dict_get(p_vars, "to"); - xs_str *sensitive = xs_dict_get(p_vars, "sensitive"); - xs_str *summary = xs_dict_get(p_vars, "summary"); - xs_str *edit_id = xs_dict_get(p_vars, "edit_id"); - xs_str *alt_text = xs_dict_get(p_vars, "alt_text"); + const xs_str *content = xs_dict_get(p_vars, "content"); + const xs_str *in_reply_to = xs_dict_get(p_vars, "in_reply_to"); + const xs_str *attach_url = xs_dict_get(p_vars, "attach_url"); + const xs_list *attach_file = xs_dict_get(p_vars, "attach"); + const xs_str *to = xs_dict_get(p_vars, "to"); + const xs_str *sensitive = xs_dict_get(p_vars, "sensitive"); + const xs_str *summary = xs_dict_get(p_vars, "summary"); + const xs_str *edit_id = xs_dict_get(p_vars, "edit_id"); + const xs_str *alt_text = xs_dict_get(p_vars, "alt_text"); int priv = !xs_is_null(xs_dict_get(p_vars, "mentioned_only")); xs *attach_list = xs_list_new(); @@ -2902,7 +2910,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, /* is attach_file set? */ if (!xs_is_null(attach_file) && xs_type(attach_file) == XSTYPE_LIST) { - char *fn = xs_list_get(attach_file, 0); + const char *fn = xs_list_get(attach_file, 0); if (*fn != '\0') { char *ext = strrchr(fn, '.'); @@ -2978,7 +2986,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, int n; for (n = 0; fields[n]; n++) { - char *v = xs_dict_get(p_msg, fields[n]); + const char *v = xs_dict_get(p_msg, fields[n]); msg = xs_dict_set(msg, fields[n], v); } @@ -3007,10 +3015,10 @@ int html_post_handler(const xs_dict *req, const char *q_path, else if (p_path && strcmp(p_path, "admin/action") == 0) { /** **/ /* action on an entry */ - char *id = xs_dict_get(p_vars, "id"); - char *actor = xs_dict_get(p_vars, "actor"); - char *action = xs_dict_get(p_vars, "action"); - char *group = xs_dict_get(p_vars, "group"); + const char *id = xs_dict_get(p_vars, "id"); + const char *actor = xs_dict_get(p_vars, "actor"); + const char *action = xs_dict_get(p_vars, "action"); + const char *group = xs_dict_get(p_vars, "group"); if (action == NULL) return 404; @@ -3134,7 +3142,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, } else if (strcmp(action, L("Delete")) == 0) { /** **/ - char *actor_form = xs_dict_get(p_vars, "actor-form"); + const char *actor_form = xs_dict_get(p_vars, "actor-form"); if (actor_form != NULL) { /* delete follower */ if (valid_status(follower_del(&snac, actor))) @@ -3178,8 +3186,8 @@ int html_post_handler(const xs_dict *req, const char *q_path, else if (p_path && strcmp(p_path, "admin/user-setup") == 0) { /** **/ /* change of user data */ - char *v; - char *p1, *p2; + const char *v; + const char *p1, *p2; if ((v = xs_dict_get(p_vars, "name")) != NULL) snac.config = xs_dict_set(snac.config, "name", v); @@ -3245,7 +3253,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, for (n = 0; uploads[n]; n++) { xs *var_name = xs_fmt("%s_file", uploads[n]); - xs_list *uploaded_file = xs_dict_get(p_vars, var_name); + const xs_list *uploaded_file = xs_dict_get(p_vars, var_name); if (xs_type(uploaded_file) == XSTYPE_LIST) { const char *fn = xs_list_get(uploaded_file, 0); @@ -3310,7 +3318,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, } else if (p_path && strcmp(p_path, "admin/vote") == 0) { /** **/ - char *irt = xs_dict_get(p_vars, "irt"); + const char *irt = xs_dict_get(p_vars, "irt"); const char *opt = xs_dict_get(p_vars, "question"); const char *actor = xs_dict_get(p_vars, "actor"); @@ -3345,7 +3353,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, xs *poll = NULL; if (valid_status(object_get(irt, &poll))) { - char *date = xs_dict_get(poll, "endTime"); + const char *date = xs_dict_get(poll, "endTime"); if (xs_is_null(date)) date = xs_dict_get(poll, "closed"); @@ -3363,7 +3371,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, } if (status == 303) { - char *redir = xs_dict_get(p_vars, "redir"); + const char *redir = xs_dict_get(p_vars, "redir"); if (xs_is_null(redir)) redir = "top"; @@ -3411,8 +3419,8 @@ xs_str *timeline_to_rss(snac *user, const xs_list *timeline, char *title, char * continue; } - char *id = xs_dict_get(msg, "id"); - char *content = xs_dict_get(msg, "content"); + const char *id = xs_dict_get(msg, "id"); + const char *content = xs_dict_get(msg, "content"); if (user && !xs_startswith(id, user->actor)) continue; diff --git a/http.c b/http.c index f7ff9ba..4d85631 100644 --- a/http.c +++ b/http.c @@ -12,7 +12,7 @@ xs_dict *http_signed_request_raw(const char *keyid, const char *seckey, const char *method, const char *url, - xs_dict *headers, + const xs_dict *headers, const char *body, int b_size, int *status, xs_str **payload, int *p_size, int timeout) @@ -24,8 +24,8 @@ xs_dict *http_signed_request_raw(const char *keyid, const char *seckey, xs *s64 = NULL; xs *signature = NULL; xs *hdrs = NULL; - char *host; - char *target; + const char *host; + const char *target; char *k, *v; xs_dict *response; @@ -106,13 +106,13 @@ xs_dict *http_signed_request_raw(const char *keyid, const char *seckey, xs_dict *http_signed_request(snac *snac, const char *method, const char *url, - xs_dict *headers, + const xs_dict *headers, const char *body, int b_size, int *status, xs_str **payload, int *p_size, int timeout) /* does a signed HTTP request */ { - char *seckey = xs_dict_get(snac->key, "secret"); + const char *seckey = xs_dict_get(snac->key, "secret"); xs_dict *response; response = http_signed_request_raw(snac->actor, seckey, method, url, @@ -122,17 +122,18 @@ xs_dict *http_signed_request(snac *snac, const char *method, const char *url, } -int check_signature(xs_dict *req, xs_str **err) +int check_signature(const xs_dict *req, xs_str **err) /* check the signature */ { - char *sig_hdr = xs_dict_get(req, "signature"); + const char *sig_hdr = xs_dict_get(req, "signature"); xs *keyId = NULL; xs *headers = NULL; xs *signature = NULL; xs *created = NULL; xs *expires = NULL; - char *pubkey; char *p; + const char *pubkey; + const char *k; if (xs_is_null(sig_hdr)) { *err = xs_fmt("missing 'signature' header"); @@ -142,10 +143,10 @@ int check_signature(xs_dict *req, xs_str **err) { /* extract the values */ xs *l = xs_split(sig_hdr, ","); - xs_list *p = l; + int c = 0; xs_val *v; - while (xs_list_iter(&p, &v)) { + while (xs_list_next(l, &v, &c)) { xs *kv = xs_split_n(v, "=", 1); if (xs_list_len(kv) != 2) @@ -192,8 +193,8 @@ int check_signature(xs_dict *req, xs_str **err) return 0; } - if ((p = xs_dict_get(actor, "publicKey")) == NULL || - ((pubkey = xs_dict_get(p, "publicKeyPem")) == NULL)) { + if ((k = xs_dict_get(actor, "publicKey")) == NULL || + ((pubkey = xs_dict_get(k, "publicKeyPem")) == NULL)) { *err = xs_fmt("cannot get pubkey from %s", keyId); return 0; } @@ -208,7 +209,7 @@ int check_signature(xs_dict *req, xs_str **err) p = l; while (xs_list_iter(&p, &v)) { - char *hc; + const char *hc; xs *ss = NULL; if (*sig_str != '\0') diff --git a/httpd.c b/httpd.c index 71cce5e..d63fa0f 100644 --- a/httpd.c +++ b/httpd.c @@ -125,7 +125,7 @@ static xs_str *greeting_html(void) /* does it have a %userlist% mark? */ if (xs_str_in(s, "%userlist%") != -1) { - char *host = xs_dict_get(srv_config, "host"); + const char *host = xs_dict_get(srv_config, "host"); xs *list = user_list(); xs_list *p = list; xs_str *uid; @@ -171,14 +171,14 @@ int server_get_handler(xs_dict *req, const char *q_path, /* is it the server root? */ if (*q_path == '\0') { - xs_dict *q_vars = xs_dict_get(req, "q_vars"); - char *t = NULL; + const xs_dict *q_vars = xs_dict_get(req, "q_vars"); + const char *t = NULL; if (xs_type(q_vars) == XSTYPE_DICT && (t = xs_dict_get(q_vars, "t"))) { /** search by tag **/ int skip = 0; int show = xs_number_get(xs_dict_get(srv_config, "max_timeline_entries")); - char *v; + const char *v; if ((v = xs_dict_get(q_vars, "skip")) != NULL) skip = atoi(v); @@ -193,7 +193,7 @@ int server_get_handler(xs_dict *req, const char *q_path, more = 1; } - char *accept = xs_dict_get(req, "accept"); + const char *accept = xs_dict_get(req, "accept"); if (!xs_is_null(accept) && strcmp(accept, "application/rss+xml") == 0) { xs *link = xs_fmt("%s/?t=%s", srv_baseurl, t); @@ -268,7 +268,7 @@ void httpd_connection(FILE *f) /* the connection processor */ { xs *req; - char *method; + const char *method; int status = 0; xs_str *body = NULL; int b_size = 0; @@ -278,7 +278,7 @@ void httpd_connection(FILE *f) xs *payload = NULL; xs *etag = NULL; int p_size = 0; - char *p; + const char *p; int fcgi_id; if (p_state->use_fcgi) @@ -411,7 +411,7 @@ void httpd_connection(FILE *f) headers = xs_dict_append(headers, "etag", etag); /* if there are any additional headers, add them */ - xs_dict *more_headers = xs_dict_get(srv_config, "http_headers"); + const xs_dict *more_headers = xs_dict_get(srv_config, "http_headers"); if (xs_type(more_headers) == XSTYPE_DICT) { char *k, *v; int c = 0; diff --git a/main.c b/main.c index 819922f..9c906a6 100644 --- a/main.c +++ b/main.c @@ -315,7 +315,7 @@ int main(int argc, char *argv[]) xs *msg = msg_follow(&snac, url); if (msg != NULL) { - char *actor = xs_dict_get(msg, "object"); + const char *actor = xs_dict_get(msg, "object"); following_add(&snac, actor, msg); diff --git a/mastoapi.c b/mastoapi.c index 2bf5fdc..852713e 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -175,7 +175,7 @@ int oauth_get_handler(const xs_dict *req, const char *q_path, return 0; int status = 404; - xs_dict *msg = xs_dict_get(req, "q_vars"); + const xs_dict *msg = xs_dict_get(req, "q_vars"); xs *cmd = xs_replace_n(q_path, "/oauth", "", 1); srv_debug(1, xs_fmt("oauth_get_handler %s", q_path)); @@ -239,7 +239,7 @@ int oauth_post_handler(const xs_dict *req, const char *q_path, int status = 404; - char *i_ctype = xs_dict_get(req, "content-type"); + const char *i_ctype = xs_dict_get(req, "content-type"); xs *args = NULL; if (i_ctype && xs_startswith(i_ctype, "application/json")) { @@ -568,10 +568,10 @@ xs_dict *mastoapi_account(const xs_dict *actor) acct = xs_dict_append(acct, "uri", id); xs *avatar = NULL; - xs_dict *av = xs_dict_get(actor, "icon"); + const xs_dict *av = xs_dict_get(actor, "icon"); if (xs_type(av) == XSTYPE_DICT) { - char *url = xs_dict_get(av, "url"); + const char *url = xs_dict_get(av, "url"); if (url != NULL) avatar = xs_dup(url); @@ -584,7 +584,7 @@ xs_dict *mastoapi_account(const xs_dict *actor) acct = xs_dict_append(acct, "avatar_static", avatar); xs *header = NULL; - xs_dict *hd = xs_dict_get(actor, "image"); + const xs_dict *hd = xs_dict_get(actor, "image"); if (xs_type(hd) == XSTYPE_DICT) header = xs_dup(xs_dict_get(hd, "url")); @@ -596,12 +596,13 @@ xs_dict *mastoapi_account(const xs_dict *actor) acct = xs_dict_append(acct, "header_static", header); /* emojis */ - xs_list *p; + const xs_list *p; if (!xs_is_null(p = xs_dict_get(actor, "tag"))) { xs *eml = xs_list_new(); xs_dict *v; + int c = 0; - while (xs_list_iter(&p, &v)) { + while (xs_list_next(p, &v, &c)) { const char *type = xs_dict_get(v, "type"); if (!xs_is_null(type) && strcmp(type, "Emoji") == 0) { @@ -640,7 +641,7 @@ xs_dict *mastoapi_account(const xs_dict *actor) /* dict of validated links */ xs_dict *val_links = NULL; - xs_dict *metadata = xs_stock(XSTYPE_DICT); + const xs_dict *metadata = xs_stock(XSTYPE_DICT); snac user = {0}; if (xs_startswith(id, srv_baseurl)) { @@ -654,19 +655,20 @@ xs_dict *mastoapi_account(const xs_dict *actor) if (xs_is_null(val_links)) val_links = xs_stock(XSTYPE_DICT); - while (xs_list_iter(&p, &v)) { - char *type = xs_dict_get(v, "type"); - char *name = xs_dict_get(v, "name"); - char *value = xs_dict_get(v, "value"); + int c = 0; + while (xs_list_next(p, &v, &c)) { + const char *type = xs_dict_get(v, "type"); + const char *name = xs_dict_get(v, "name"); + const char *value = xs_dict_get(v, "value"); if (!xs_is_null(type) && !xs_is_null(name) && !xs_is_null(value) && strcmp(type, "PropertyValue") == 0) { xs *val_date = NULL; - char *url = xs_dict_get(metadata, name); + const char *url = xs_dict_get(metadata, name); if (!xs_is_null(url) && xs_startswith(url, "https:/" "/")) { - xs_number *verified_time = xs_dict_get(val_links, url); + const xs_number *verified_time = xs_dict_get(val_links, url); if (xs_type(verified_time) == XSTYPE_NUMBER) { time_t t = xs_number_get(verified_time); @@ -695,7 +697,7 @@ xs_dict *mastoapi_account(const xs_dict *actor) } -xs_str *mastoapi_date(char *date) +xs_str *mastoapi_date(const char *date) /* converts an ISO 8601 date to whatever format Mastodon uses */ { xs_str *s = xs_crop_i(xs_dup(date), 0, 19); @@ -710,13 +712,13 @@ xs_dict *mastoapi_poll(snac *snac, const xs_dict *msg) { xs_dict *poll = xs_dict_new(); xs *mid = mastoapi_id(msg); - xs_list *opts = NULL; + const xs_list *opts = NULL; xs_val *v; int num_votes = 0; xs *options = xs_list_new(); poll = xs_dict_append(poll, "id", mid); - char *date = xs_dict_get(msg, "endTime"); + const char *date = xs_dict_get(msg, "endTime"); if (date == NULL) date = xs_dict_get(msg, "closed"); if (date == NULL) @@ -741,7 +743,8 @@ xs_dict *mastoapi_poll(snac *snac, const xs_dict *msg) poll = xs_dict_append(poll, "multiple", xs_stock(XSTYPE_TRUE)); } - while (xs_list_iter(&opts, &v)) { + int c = 0; + while (xs_list_next(opts, &v, &c)) { const char *title = xs_dict_get(v, "name"); const char *replies = xs_dict_get(v, "replies"); @@ -794,7 +797,7 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) xs *idx = NULL; xs *ixc = NULL; - char *tmp; + const char *tmp; xs *mid = mastoapi_id(msg); xs_dict *st = xs_dict_new(); @@ -851,9 +854,9 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) xs *matt = xs_list_new(); while (xs_list_iter(&p, &v)) { - char *type = xs_dict_get(v, "type"); - char *href = xs_dict_get(v, "href"); - char *name = xs_dict_get(v, "name"); + const char *type = xs_dict_get(v, "type"); + const char *href = xs_dict_get(v, "href"); + const char *name = xs_dict_get(v, "name"); if (xs_match(type, "image/*|video/*|Image|Video")) { /* */ xs *matteid = xs_fmt("%s_%d", id, xs_list_len(matt)); @@ -879,7 +882,7 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) xs *ml = xs_list_new(); xs *htl = xs_list_new(); xs *eml = xs_list_new(); - xs_list *tag = xs_dict_get(msg, "tag"); + const xs_list *tag = xs_dict_get(msg, "tag"); int n = 0; xs *tag_list = NULL; @@ -897,7 +900,8 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) tag = tag_list; xs_dict *v; - while (xs_list_iter(&tag, &v)) { + int c = 0; + while (xs_list_next(tag, &v, &c)) { const char *type = xs_dict_get(v, "type"); if (xs_is_null(type)) @@ -1006,7 +1010,7 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) xs *irt_mid = mastoapi_id(irto); st = xs_dict_set(st, "in_reply_to_id", irt_mid); - char *at = NULL; + const char *at = NULL; if (!xs_is_null(at = get_atto(irto))) { xs *at_md5 = xs_md5_hex(at, strlen(at)); st = xs_dict_set(st, "in_reply_to_account_id", at_md5); @@ -1118,7 +1122,7 @@ int process_auth_token(snac *snac, const xs_dict *req) /* processes an authorization token, if there is one */ { int logged_in = 0; - char *v; + const char *v; /* if there is an authorization field, try to validate it */ if (!xs_is_null(v = xs_dict_get(req, "authorization")) && xs_startswith(v, "Bearer ")) { @@ -1156,7 +1160,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, return 0; int status = 404; - xs_dict *args = xs_dict_get(req, "q_vars"); + const xs_dict *args = xs_dict_get(req, "q_vars"); xs *cmd = xs_replace_n(q_path, "/api", "", 1); snac snac1 = {0}; @@ -1182,7 +1186,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, acct = xs_dict_append(acct, "source", src); xs *avatar = NULL; - char *av = xs_dict_get(snac1.config, "avatar"); + const char *av = xs_dict_get(snac1.config, "avatar"); if (xs_is_null(av) || *av == '\0') avatar = xs_fmt("%s/susie.png", srv_baseurl); @@ -1193,7 +1197,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, acct = xs_dict_append(acct, "avatar_static", avatar); xs *header = NULL; - char *hd = xs_dict_get(snac1.config, "header"); + const char *hd = xs_dict_get(snac1.config, "header"); if (!xs_is_null(hd)) header = xs_dup(hd); @@ -1203,7 +1207,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, acct = xs_dict_append(acct, "header", header); acct = xs_dict_append(acct, "header_static", header); - xs_dict *metadata = xs_dict_get(snac1.config, "metadata"); + const xs_dict *metadata = xs_dict_get(snac1.config, "metadata"); if (xs_type(metadata) == XSTYPE_DICT) { xs *fields = xs_list_new(); xs_str *k; @@ -1217,7 +1221,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, while (xs_dict_next(metadata, &k, &v, &c)) { xs *val_date = NULL; - xs_number *verified_time = xs_dict_get(val_links, v); + const xs_number *verified_time = xs_dict_get(val_links, v); if (xs_type(verified_time) == XSTYPE_NUMBER) { time_t t = xs_number_get(verified_time); @@ -1283,13 +1287,13 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, else if (strcmp(cmd, "/v1/accounts/lookup") == 0) { /** **/ /* lookup an account */ - char *acct = xs_dict_get(args, "acct"); + const char *acct = xs_dict_get(args, "acct"); if (!xs_is_null(acct)) { xs *s = xs_strip_chars_i(xs_dup(acct), "@"); xs *l = xs_split_n(s, "@", 1); - char *uid = xs_list_get(l, 0); - char *host = xs_list_get(l, 1); + const char *uid = xs_list_get(l, 0); + const char *host = xs_list_get(l, 1); if (uid && (!host || strcmp(host, xs_dict_get(srv_config, "host")) == 0)) { snac user; @@ -1624,7 +1628,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, /* get the tag */ xs *l = xs_split(cmd, "/"); - char *tag = xs_list_get(l, -1); + const char *tag = xs_list_get(l, -1); xs *timeline = tag_search(tag, 0, limit); xs *out = xs_list_new(); @@ -1664,7 +1668,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, /* get the list id */ if (logged_in) { xs *l = xs_split(cmd, "/"); - char *list = xs_list_get(l, -1); + const char *list = xs_list_get(l, -1); xs *timeline = list_timeline(&snac1, list, 0, 2048); xs *out = xs_list_new(); @@ -1744,7 +1748,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, xs *out = xs_list_new(); xs_list *p = l; xs_dict *v; - xs_list *excl = xs_dict_get(args, "exclude_types[]"); + const xs_list *excl = xs_dict_get(args, "exclude_types[]"); while (xs_list_iter(&p, &v)) { xs *noti = notify_get(&snac1, v); @@ -1876,7 +1880,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, if (xs_startswith(cmd, "/v1/lists/")) { /** list information **/ if (logged_in) { xs *l = xs_split(cmd, "/"); - char *p = xs_list_get(l, -1); + const char *p = xs_list_get(l, -1); if (p) { if (strcmp(p, "accounts") == 0) { @@ -1910,7 +1914,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, xs_list *v; while (xs_list_next(lol, &v, &c)) { - char *id = xs_list_get(v, 0); + const char *id = xs_list_get(v, 0); if (id && strcmp(id, p) == 0) { xs *d = xs_dict_new(); @@ -2314,7 +2318,7 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, int status = 404; xs *args = NULL; - char *i_ctype = xs_dict_get(req, "content-type"); + const char *i_ctype = xs_dict_get(req, "content-type"); if (i_ctype && xs_startswith(i_ctype, "application/json")) { if (!xs_is_null(payload)) @@ -2487,7 +2491,7 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, mid = MID_TO_MD5(mid); if (valid_status(timeline_get_by_md5(&snac, mid, &msg))) { - char *id = xs_dict_get(msg, "id"); + const char *id = xs_dict_get(msg, "id"); if (op == NULL) { /* no operation (?) */ @@ -2593,7 +2597,7 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, if (strcmp(cmd, "/v1/push/subscription") == 0) { /** **/ /* I don't know what I'm doing */ if (logged_in) { - char *v; + const char *v; xs *wpush = xs_dict_new(); @@ -2765,7 +2769,7 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, const char *id = xs_dict_get(msg, "id"); const char *atto = get_atto(msg); - xs_list *opts = xs_dict_get(msg, "oneOf"); + const xs_list *opts = xs_dict_get(msg, "oneOf"); if (opts == NULL) opts = xs_dict_get(msg, "anyOf"); @@ -2773,7 +2777,7 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, } else if (strcmp(op, "votes") == 0) { - xs_list *choices = xs_dict_get(args, "choices[]"); + const xs_list *choices = xs_dict_get(args, "choices[]"); if (xs_is_null(choices)) choices = xs_dict_get(args, "choices"); @@ -2781,7 +2785,8 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, if (xs_type(choices) == XSTYPE_LIST) { xs_str *v; - while (xs_list_iter(&choices, &v)) { + int c = 0; + while (xs_list_next(choices, &v, &c)) { int io = atoi(v); const xs_dict *o = xs_list_get(opts, io); @@ -2843,12 +2848,12 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, if (xs_startswith(cmd, "/v1/lists/")) { /** list maintenance **/ if (logged_in) { xs *l = xs_split(cmd, "/"); - char *op = xs_list_get(l, -1); - char *id = xs_list_get(l, -2); + const char *op = xs_list_get(l, -1); + const char *id = xs_list_get(l, -2); if (op && id && xs_is_hex(id)) { if (strcmp(op, "accounts") == 0) { - xs_list *accts = xs_dict_get(args, "account_ids[]"); + const xs_list *accts = xs_dict_get(args, "account_ids[]"); int c = 0; char *v; @@ -2888,7 +2893,7 @@ int mastoapi_delete_handler(const xs_dict *req, const char *q_path, int status = 404; xs *args = NULL; - char *i_ctype = xs_dict_get(req, "content-type"); + const char *i_ctype = xs_dict_get(req, "content-type"); if (i_ctype && xs_startswith(i_ctype, "application/json")) { if (!xs_is_null(payload)) @@ -2921,13 +2926,13 @@ int mastoapi_delete_handler(const xs_dict *req, const char *q_path, if (xs_startswith(cmd, "/v1/lists/")) { if (logged_in) { xs *l = xs_split(cmd, "/"); - char *p = xs_list_get(l, -1); + const char *p = xs_list_get(l, -1); if (p) { if (strcmp(p, "accounts") == 0) { /* delete account from list */ p = xs_list_get(l, -2); - xs_list *accts = xs_dict_get(args, "account_ids[]"); + const xs_list *accts = xs_dict_get(args, "account_ids[]"); int c = 0; char *v; @@ -2971,7 +2976,7 @@ int mastoapi_put_handler(const xs_dict *req, const char *q_path, int status = 404; xs *args = NULL; - char *i_ctype = xs_dict_get(req, "content-type"); + const char *i_ctype = xs_dict_get(req, "content-type"); if (i_ctype && xs_startswith(i_ctype, "application/json")) { if (!xs_is_null(payload)) diff --git a/snac.h b/snac.h index b49fbe7..79e144a 100644 --- a/snac.h +++ b/snac.h @@ -69,7 +69,7 @@ void snac_log(snac *user, xs_str *str); #define snac_debug(user, level, str) do { if (dbglevel >= (level)) \ { snac_log((user), (str)); } } while (0) -int srv_open(char *basedir, int auto_upgrade); +int srv_open(const char *basedir, int auto_upgrade); void srv_free(void); int user_open(snac *snac, const char *uid); @@ -88,7 +88,7 @@ void srv_archive(const char *direction, const char *url, xs_dict *req, const char *body, int b_size); void srv_archive_error(const char *prefix, const xs_str *err, const xs_dict *req, const xs_val *data); -void srv_archive_qitem(char *prefix, xs_dict *q_item); +void srv_archive_qitem(const char *prefix, xs_dict *q_item); double mtime_nl(const char *fn, int *n_link); #define mtime(fn) mtime_nl(fn, NULL) @@ -139,13 +139,13 @@ double timeline_mtime(snac *snac); int timeline_touch(snac *snac); int timeline_here(snac *snac, const char *md5); int timeline_get_by_md5(snac *snac, const char *md5, xs_dict **msg); -int timeline_del(snac *snac, char *id); +int timeline_del(snac *snac, const char *id); xs_list *timeline_simple_list(snac *snac, const char *idx_name, int skip, int show); xs_list *timeline_list(snac *snac, const char *idx_name, int skip, int show); int timeline_add(snac *snac, const char *id, const xs_dict *o_msg); int timeline_admire(snac *snac, const char *id, const char *admirer, int like); -xs_list *timeline_top_level(snac *snac, xs_list *list); +xs_list *timeline_top_level(snac *snac, const xs_list *list); xs_list *local_list(snac *snac, int max); xs_list *timeline_instance_list(int skip, int show); @@ -174,14 +174,14 @@ void hide(snac *snac, const char *id); int is_hidden(snac *snac, const char *id); void tag_index(const char *id, const xs_dict *obj); -xs_list *tag_search(char *tag, int skip, int show); +xs_list *tag_search(const char *tag, int skip, int show); xs_val *list_maint(snac *user, const char *list, int op); xs_list *list_timeline(snac *user, const char *list, int skip, int show); xs_val *list_content(snac *user, const char *list_id, const char *actor_md5, int op); void list_distribute(snac *user, const char *who, const xs_dict *post); -int actor_add(const char *actor, xs_dict *msg); +int actor_add(const char *actor, const xs_dict *msg); int actor_get(const char *actor, xs_dict **data); int actor_get_refresh(snac *user, const char *actor, xs_dict **data); @@ -223,10 +223,13 @@ xs_list *content_search(snac *user, const char *regex, void enqueue_input(snac *snac, const xs_dict *msg, const xs_dict *req, int retries); void enqueue_shared_input(const xs_dict *msg, const xs_dict *req, int retries); void enqueue_output_raw(const char *keyid, const char *seckey, - xs_dict *msg, xs_str *inbox, int retries, int p_status); -void enqueue_output(snac *snac, xs_dict *msg, xs_str *inbox, int retries, int p_status); -void enqueue_output_by_actor(snac *snac, xs_dict *msg, const xs_str *actor, int retries); -void enqueue_email(xs_str *msg, int retries); + const xs_dict *msg, const xs_str *inbox, + int retries, int p_status); +void enqueue_output(snac *snac, const xs_dict *msg, + const xs_str *inbox, int retries, int p_status); +void enqueue_output_by_actor(snac *snac, const xs_dict *msg, + const xs_str *actor, int retries); +void enqueue_email(const xs_str *msg, int retries); void enqueue_telegram(const xs_str *msg, const char *bot, const char *chat_id); void enqueue_ntfy(const xs_str *msg, const char *ntfy_server, const char *ntfy_token); void enqueue_message(snac *snac, const xs_dict *msg); @@ -234,7 +237,6 @@ void enqueue_close_question(snac *user, const char *id, int end_secs); void enqueue_object_request(snac *user, const char *id, int forward_secs); void enqueue_verify_links(snac *user); void enqueue_actor_refresh(snac *user, const char *actor, int forward_secs); -void enqueue_request_replies(snac *user, const char *id); int was_question_voted(snac *user, const char *id); xs_list *user_queue(snac *snac); @@ -247,16 +249,16 @@ void purge_all(void); xs_dict *http_signed_request_raw(const char *keyid, const char *seckey, const char *method, const char *url, - xs_dict *headers, + const xs_dict *headers, const char *body, int b_size, int *status, xs_str **payload, int *p_size, int timeout); xs_dict *http_signed_request(snac *snac, const char *method, const char *url, - xs_dict *headers, + const xs_dict *headers, const char *body, int b_size, int *status, xs_str **payload, int *p_size, int timeout); -int check_signature(xs_dict *req, xs_str **err); +int check_signature(const xs_dict *req, xs_str **err); srv_state *srv_state_op(xs_str **fname, int op); void httpd(void); @@ -270,21 +272,21 @@ const char *default_avatar_base64(void); xs_str *process_tags(snac *snac, const char *content, xs_list **tag); -char *get_atto(const xs_dict *msg); +const char *get_atto(const xs_dict *msg); xs_list *get_attachments(const xs_dict *msg); -xs_dict *msg_admiration(snac *snac, char *object, char *type); -xs_dict *msg_repulsion(snac *user, char *id, char *type); +xs_dict *msg_admiration(snac *snac, const char *object, const char *type); +xs_dict *msg_repulsion(snac *user, const char *id, const char *type); xs_dict *msg_create(snac *snac, const xs_dict *object); xs_dict *msg_follow(snac *snac, const char *actor); xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts, - xs_str *in_reply_to, xs_list *attach, int priv); + const xs_str *in_reply_to, const xs_list *attach, int priv); -xs_dict *msg_undo(snac *snac, char *object); -xs_dict *msg_delete(snac *snac, char *id); +xs_dict *msg_undo(snac *snac, const xs_val *object); +xs_dict *msg_delete(snac *snac, const char *id); xs_dict *msg_actor(snac *snac); -xs_dict *msg_update(snac *snac, xs_dict *object); +xs_dict *msg_update(snac *snac, const xs_dict *object); xs_dict *msg_ping(snac *user, const char *rcpt); xs_dict *msg_pong(snac *user, const char *rcpt, const char *object); xs_dict *msg_question(snac *user, const char *content, xs_list *attach, @@ -292,7 +294,6 @@ xs_dict *msg_question(snac *user, const char *content, xs_list *attach, int activitypub_request(snac *snac, const char *url, xs_dict **data); int actor_request(snac *user, const char *actor, xs_dict **data); -void timeline_request_replies(snac *user, const char *id); int send_to_inbox_raw(const char *keyid, const char *seckey, const xs_str *inbox, const xs_dict *msg, xs_val **payload, int *p_size, int timeout); diff --git a/upgrade.c b/upgrade.c index 7510ac8..266a4be 100644 --- a/upgrade.c +++ b/upgrade.c @@ -18,7 +18,7 @@ int snac_upgrade(xs_str **error) double f = 0.0; for (;;) { - char *layout = xs_dict_get(srv_config, "layout"); + const char *layout = xs_dict_get(srv_config, "layout"); double nf; f = nf = xs_number_get(layout); @@ -56,8 +56,8 @@ int snac_upgrade(xs_str **error) g = list; while (xs_list_iter(&g, &fn)) { - xs *l = xs_split(fn, "/"); - char *b = xs_list_get(l, -1); + xs *l = xs_split(fn, "/"); + const char *b = xs_list_get(l, -1); xs *dir = xs_fmt("%s/object/%c%c", srv_basedir, b[0], b[1]); xs *nfn = xs_fmt("%s/%s", dir, b); @@ -152,12 +152,12 @@ int snac_upgrade(xs_str **error) xs *o = xs_json_loads(s); fclose(f); - char *type = xs_dict_get(o, "type"); + const char *type = xs_dict_get(o, "type"); if (!xs_is_null(type) && strcmp(type, "Follow") == 0) { unlink(v); - char *actor = xs_dict_get(o, "actor"); + const char *actor = xs_dict_get(o, "actor"); if (!xs_is_null(actor)) follower_add(&snac, actor); @@ -198,22 +198,29 @@ int snac_upgrade(xs_str **error) xs *meta = xs_dup(xs_dict_get(o, "_snac")); o = xs_dict_del(o, "_snac"); - char *id = xs_dict_get(o, "id"); + const char *id = xs_dict_get(o, "id"); /* store object */ object_add_ow(id, o); /* if it's from us, add to public */ if (xs_startswith(id, snac.actor)) { - char *p, *v; + const xs_list *p; + char *v; + int c; object_user_cache_add(&snac, id, "public"); p = xs_dict_get(meta, "announced_by"); - while (xs_list_iter(&p, &v)) + + c = 0; + while (xs_list_next(p, &v, &c)) object_admire(id, v, 0); + p = xs_dict_get(meta, "liked_by"); - while (xs_list_iter(&p, &v)) + + c = 0; + while (xs_list_next(p, &v, &c)) object_admire(id, v, 1); } @@ -257,21 +264,28 @@ int snac_upgrade(xs_str **error) xs *meta = xs_dup(xs_dict_get(o, "_snac")); o = xs_dict_del(o, "_snac"); - char *id = xs_dict_get(o, "id"); + const char *id = xs_dict_get(o, "id"); /* store object */ object_add_ow(id, o); { - char *p, *v; + const xs_list *p; + char *v; + int c = 0; object_user_cache_add(&snac, id, "private"); p = xs_dict_get(meta, "announced_by"); - while (xs_list_iter(&p, &v)) + + c = 0; + while (xs_list_next(p, &v, &c)) object_admire(id, v, 0); + p = xs_dict_get(meta, "liked_by"); - while (xs_list_iter(&p, &v)) + + c = 0; + while (xs_list_next(p, &v, &c)) object_admire(id, v, 1); } diff --git a/utils.c b/utils.c index 0523cac..daaa583 100644 --- a/utils.c +++ b/utils.c @@ -418,7 +418,7 @@ int deluser(snac *user) void verify_links(snac *user) /* verifies a user's links */ { - xs_dict *p = xs_dict_get(user->config, "metadata"); + const xs_dict *p = xs_dict_get(user->config, "metadata"); char *k, *v; int changed = 0; diff --git a/webfinger.c b/webfinger.c index 7255ae2..a12134d 100644 --- a/webfinger.c +++ b/webfinger.c @@ -16,7 +16,7 @@ int webfinger_request_signed(snac *snac, const char *qs, char **actor, char **us int p_size = 0; xs *headers = xs_dict_new(); xs *l = NULL; - xs_str *host = NULL; + const char *host = NULL; xs *resource = NULL; if (xs_startswith(qs, "https:/") || xs_startswith(qs, "http:/")) { @@ -87,19 +87,20 @@ int webfinger_request_signed(snac *snac, const char *qs, char **actor, char **us if (obj) { if (user != NULL) { - char *subject = xs_dict_get(obj, "subject"); + const char *subject = xs_dict_get(obj, "subject"); if (subject) *user = xs_replace_n(subject, "acct:", "", 1); } if (actor != NULL) { - char *list = xs_dict_get(obj, "links"); + const xs_list *list = xs_dict_get(obj, "links"); + int c = 0; char *v; - while (xs_list_iter(&list, &v)) { + while (xs_list_next(list, &v, &c)) { if (xs_type(v) == XSTYPE_DICT) { - char *type = xs_dict_get(v, "type"); + const char *type = xs_dict_get(v, "type"); if (type && (strcmp(type, "application/activity+json") == 0 || strcmp(type, "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") == 0)) { @@ -133,8 +134,8 @@ int webfinger_get_handler(xs_dict *req, char *q_path, if (strcmp(q_path, "/.well-known/webfinger") != 0) return 0; - char *q_vars = xs_dict_get(req, "q_vars"); - char *resource = xs_dict_get(q_vars, "resource"); + const char *q_vars = xs_dict_get(req, "q_vars"); + const char *resource = xs_dict_get(q_vars, "resource"); if (resource == NULL) return 400; @@ -145,7 +146,7 @@ int webfinger_get_handler(xs_dict *req, char *q_path, if (xs_startswith(resource, "https:/") || xs_startswith(resource, "http:/")) { /* actor search: find a user with this actor */ xs *l = xs_split(resource, "/"); - char *uid = xs_list_get(l, -1); + const char *uid = xs_list_get(l, -1); if (uid) found = user_open(&snac, uid); @@ -163,8 +164,8 @@ int webfinger_get_handler(xs_dict *req, char *q_path, l = xs_split_n(an, "@", 1); if (xs_list_len(l) == 2) { - char *uid = xs_list_get(l, 0); - char *host = xs_list_get(l, 1); + const char *uid = xs_list_get(l, 0); + const char *host = xs_list_get(l, 1); if (strcmp(host, xs_dict_get(srv_config, "host")) == 0) found = user_open(&snac, uid); @@ -194,7 +195,7 @@ int webfinger_get_handler(xs_dict *req, char *q_path, links = xs_list_append(links, prof); - char *avatar = xs_dict_get(snac.config, "avatar"); + const char *avatar = xs_dict_get(snac.config, "avatar"); if (!xs_is_null(avatar) && *avatar) { xs *d = xs_dict_new(); diff --git a/xs.h b/xs.h index f5c87ef..b46f0e1 100644 --- a/xs.h +++ b/xs.h @@ -21,8 +21,8 @@ typedef enum { XSTYPE_FALSE = 0x15, /* Boolean */ XSTYPE_LIST = 0x1d, /* Sequence of LITEMs up to EOM (with size) */ XSTYPE_LITEM = 0x1f, /* Element of a list (any type) */ - XSTYPE_DICT = 0x1c, /* Sequence of DITEMs up to EOM (with size) */ - XSTYPE_DITEM = 0x1e, /* Element of a dict (STRING key + any type) */ + XSTYPE_DICT = 0x1c, /* Sequence of KEYVALs up to EOM (with size) */ + XSTYPE_KEYVAL = 0x1e, /* key + value (STRING key + any type) */ XSTYPE_EOM = 0x19, /* End of Multiple (LIST or DICT) */ XSTYPE_DATA = 0x10 /* A block of anonymous data */ } xstype; @@ -32,6 +32,7 @@ typedef enum { typedef char xs_val; typedef char xs_str; typedef char xs_list; +typedef char xs_keyval; typedef char xs_dict; typedef char xs_number; typedef char xs_data; @@ -96,7 +97,7 @@ xs_list *_xs_list_append(xs_list *list, const xs_val *vals[]); int xs_list_iter(xs_list **list, xs_val **value); int xs_list_next(const xs_list *list, xs_val **value, int *ctxt); int xs_list_len(const xs_list *list); -xs_val *xs_list_get(const xs_list *list, int num); +const xs_val *xs_list_get(const xs_list *list, int num); xs_list *xs_list_del(xs_list *list, int num); xs_list *xs_list_insert(xs_list *list, int num, const xs_val *data); xs_list *xs_list_set(xs_list *list, int num, const xs_val *data); @@ -109,14 +110,20 @@ xs_list *xs_split_n(const char *str, const char *sep, int times); #define xs_split(str, sep) xs_split_n(str, sep, XS_ALL) xs_list *xs_list_cat(xs_list *l1, const xs_list *l2); +int xs_keyval_size(const xs_str *key, const xs_val *value); +xs_str *xs_keyval_key(const xs_keyval *keyval); +xs_val *xs_keyval_value(const xs_keyval *keyval); +xs_keyval *xs_keyval_make(xs_keyval *keyval, const xs_str *key, const xs_val *value); + xs_dict *xs_dict_new(void); xs_dict *xs_dict_append(xs_dict *dict, const xs_str *key, const xs_val *value); xs_dict *xs_dict_prepend(xs_dict *dict, const xs_str *key, const xs_val *value); int xs_dict_next(const xs_dict *dict, xs_str **key, xs_val **value, int *ctxt); -xs_val *xs_dict_get_def(const xs_dict *dict, const xs_str *key, const xs_val *def); +const xs_val *xs_dict_get_def(const xs_dict *dict, const xs_str *key, const xs_val *def); #define xs_dict_get(dict, key) xs_dict_get_def(dict, key, NULL) xs_dict *xs_dict_del(xs_dict *dict, const xs_str *key); xs_dict *xs_dict_set(xs_dict *dict, const xs_str *key, const xs_val *data); +xs_dict *xs_dict_gc(xs_dict *dict); xs_val *xs_val_new(xstype t); xs_number *xs_number_new(double f); @@ -244,7 +251,7 @@ xstype xs_type(const xs_val *data) case XSTYPE_LIST: case XSTYPE_LITEM: case XSTYPE_DICT: - case XSTYPE_DITEM: + case XSTYPE_KEYVAL: case XSTYPE_NUMBER: case XSTYPE_EOM: case XSTYPE_DATA: @@ -262,7 +269,7 @@ xstype xs_type(const xs_val *data) void _xs_put_size(xs_val *ptr, int i) /* must match _XS_TYPE_SIZE */ { - memcpy(ptr, &i, sizeof(i)); + memcpy(ptr + 1, &i, sizeof(i)); } @@ -296,7 +303,7 @@ int xs_size(const xs_val *data) break; - case XSTYPE_DITEM: + case XSTYPE_KEYVAL: /* calculate the size of the key and the value */ p = data + 1; p += xs_size(p); @@ -380,7 +387,7 @@ xs_val *xs_expand(xs_val *data, int offset, int size) if (xs_type(data) == XSTYPE_LIST || xs_type(data) == XSTYPE_DICT || xs_type(data) == XSTYPE_DATA) - _xs_put_size(data + 1, sz); + _xs_put_size(data, sz); return data; } @@ -405,7 +412,7 @@ xs_val *xs_collapse(xs_val *data, int offset, int size) if (xs_type(data) == XSTYPE_LIST || xs_type(data) == XSTYPE_DICT || xs_type(data) == XSTYPE_DATA) - _xs_put_size(data + 1, sz); + _xs_put_size(data, sz); return xs_realloc(data, _xs_blk_size(sz)); } @@ -666,10 +673,10 @@ xs_list *xs_list_new(void) { int sz = 1 + _XS_TYPE_SIZE + 1; xs_list *l = xs_realloc(NULL, sz); - memset(l, '\0', sz); + memset(l, XSTYPE_EOM, sz); l[0] = XSTYPE_LIST; - _xs_put_size(&l[1], sz); + _xs_put_size(l, sz); return l; } @@ -802,7 +809,7 @@ int xs_list_len(const xs_list *list) } -xs_val *xs_list_get(const xs_list *list, int num) +const xs_val *xs_list_get(const xs_list *list, int num) /* returns the element #num */ { XS_ASSERT_TYPE(list, XSTYPE_LIST); @@ -830,7 +837,7 @@ xs_list *xs_list_del(xs_list *list, int num) { XS_ASSERT_TYPE(list, XSTYPE_LIST); - xs_val *v; + const xs_val *v; if ((v = xs_list_get(list, num)) != NULL) list = xs_collapse(list, v - 1 - list, xs_size(v - 1)); @@ -844,7 +851,7 @@ xs_list *xs_list_insert(xs_list *list, int num, const xs_val *data) { XS_ASSERT_TYPE(list, XSTYPE_LIST); - xs_val *v; + const xs_val *v; int offset; if ((v = xs_list_get(list, num)) != NULL) @@ -999,6 +1006,40 @@ xs_list *xs_list_cat(xs_list *l1, const xs_list *l2) } +/** keyvals **/ + +int xs_keyval_size(const xs_str *key, const xs_val *value) +/* returns the needed size for a keyval */ +{ + return 1 + xs_size(key) + xs_size(value); +} + + +xs_str *xs_keyval_key(const xs_keyval *keyval) +/* returns a pointer to the key of the keyval */ +{ + return (xs_str *)&keyval[1]; +} + + +xs_val *xs_keyval_value(const xs_keyval *keyval) +/* returns a pointer to the value of the keyval */ +{ + return (xs_val *)&keyval[1 + xs_size(xs_keyval_key(keyval))]; +} + + +xs_keyval *xs_keyval_make(xs_keyval *keyval, const xs_str *key, const xs_val *value) +/* builds a keyval into mem (should have enough size) */ +{ + keyval[0] = XSTYPE_KEYVAL; + memcpy(xs_keyval_key(keyval), key, xs_size(key)); + memcpy(xs_keyval_value(keyval), value, xs_size(value)); + + return keyval; +} + + /** dicts **/ xs_dict *xs_dict_new(void) @@ -1006,34 +1047,27 @@ xs_dict *xs_dict_new(void) { int sz = 1 + _XS_TYPE_SIZE + 1; xs_dict *d = xs_realloc(NULL, sz); - memset(d, '\0', sz); + memset(d, XSTYPE_EOM, sz); d[0] = XSTYPE_DICT; - _xs_put_size(&d[1], sz); + _xs_put_size(d, sz); return d; } -xs_dict *_xs_dict_write_ditem(xs_dict *dict, int offset, const xs_str *key, - const xs_val *data, int dsz) -/* inserts a memory block into the dict */ +xs_dict *_xs_dict_write_keyval(xs_dict *dict, int offset, const xs_str *key, const xs_val *value) +/* adds a new keyval to the dict */ { XS_ASSERT_TYPE(dict, XSTYPE_DICT); XS_ASSERT_TYPE(key, XSTYPE_STRING); - if (data == NULL) { - data = xs_stock(XSTYPE_NULL); - dsz = xs_size(data); - } - - int ksz = xs_size(key); + if (value == NULL) + value = xs_stock(XSTYPE_NULL); - dict = xs_expand(dict, offset, 1 + ksz + dsz); + dict = xs_expand(dict, offset, xs_keyval_size(key, value)); - dict[offset] = XSTYPE_DITEM; - memcpy(&dict[offset + 1], key, ksz); - memcpy(&dict[offset + 1 + ksz], data, dsz); + xs_keyval_make(&dict[offset], key, value); return dict; } @@ -1042,14 +1076,14 @@ xs_dict *_xs_dict_write_ditem(xs_dict *dict, int offset, const xs_str *key, xs_dict *xs_dict_append(xs_dict *dict, const xs_str *key, const xs_val *value) /* appends a memory block to the dict */ { - return _xs_dict_write_ditem(dict, xs_size(dict) - 1, key, value, xs_size(value)); + return _xs_dict_write_keyval(dict, xs_size(dict) - 1, key, value); } xs_dict *xs_dict_prepend(xs_dict *dict, const xs_str *key, const xs_val *value) /* prepends a memory block to the dict */ { - return _xs_dict_write_ditem(dict, 1 + _XS_TYPE_SIZE, key, value, xs_size(value)); + return _xs_dict_write_keyval(dict, 1 + _XS_TYPE_SIZE, key, value); } @@ -1070,7 +1104,7 @@ int xs_dict_next(const xs_dict *dict, xs_str **key, xs_val **value, int *ctxt) p += *ctxt; /* an element? */ - if (xs_type(p) == XSTYPE_DITEM) { + if (xs_type(p) == XSTYPE_KEYVAL) { p++; *key = p; @@ -1091,7 +1125,7 @@ int xs_dict_next(const xs_dict *dict, xs_str **key, xs_val **value, int *ctxt) } -xs_val *xs_dict_get_def(const xs_dict *dict, const xs_str *key, const xs_val *def) +const xs_val *xs_dict_get_def(const xs_dict *dict, const xs_str *key, const xs_val *def) /* returns the value directed by key, or the default value */ { XS_ASSERT_TYPE(dict, XSTYPE_DICT); @@ -1150,6 +1184,14 @@ xs_dict *xs_dict_set(xs_dict *dict, const xs_str *key, const xs_val *data) } +xs_dict *xs_dict_gc(xs_dict *dict) +/* collects garbage (leaked values) inside a dict */ +{ + /* this kind of dicts does not get garbage */ + return dict; +} + + /** other values **/ xs_val *xs_val_new(xstype t) @@ -1235,7 +1277,7 @@ xs_data *xs_data_new(const void *data, int size) v = xs_realloc(NULL, _xs_blk_size(total_size)); v[0] = XSTYPE_DATA; - _xs_put_size(v + 1, total_size); + _xs_put_size(v, total_size); memcpy(&v[1 + _XS_TYPE_SIZE], data, size); diff --git a/xs_curl.h b/xs_curl.h index f7783b9..2628d91 100644 --- a/xs_curl.h +++ b/xs_curl.h @@ -28,7 +28,7 @@ static size_t _header_callback(char *buffer, size_t size, if (xs_str_in(l, ": ") != -1) { xs *knv = xs_split_n(l, ": ", 1); - xs_tolower_i(xs_list_get(knv, 0)); + xs_tolower_i((xs_str *)xs_list_get(knv, 0)); headers = xs_dict_set(headers, xs_list_get(knv, 0), xs_list_get(knv, 1)); } diff --git a/xs_html.h b/xs_html.h index 80ae652..a95d45a 100644 --- a/xs_html.h +++ b/xs_html.h @@ -6,26 +6,26 @@ typedef struct xs_html xs_html; -xs_str *xs_html_encode(char *str); +xs_str *xs_html_encode(const char *str); -xs_html *xs_html_attr(char *key, char *value); -xs_html *xs_html_text(char *content); -xs_html *xs_html_raw(char *content); +xs_html *xs_html_attr(const char *key, const char *value); +xs_html *xs_html_text(const char *content); +xs_html *xs_html_raw(const char *content); xs_html *_xs_html_add(xs_html *tag, xs_html *var[]); #define xs_html_add(tag, ...) _xs_html_add(tag, (xs_html *[]) { __VA_ARGS__, NULL }) -xs_html *_xs_html_tag(char *tag, xs_html *var[]); +xs_html *_xs_html_tag(const char *tag, xs_html *var[]); #define xs_html_tag(tag, ...) _xs_html_tag(tag, (xs_html *[]) { __VA_ARGS__, NULL }) -xs_html *_xs_html_sctag(char *tag, xs_html *var[]); +xs_html *_xs_html_sctag(const char *tag, xs_html *var[]); #define xs_html_sctag(tag, ...) _xs_html_sctag(tag, (xs_html *[]) { __VA_ARGS__, NULL }) xs_html *_xs_html_container(xs_html *var[]); #define xs_html_container(...) _xs_html_container((xs_html *[]) { __VA_ARGS__, NULL }) void xs_html_render_f(xs_html *h, FILE *f); -xs_str *xs_html_render_s(xs_html *tag, char *prefix); +xs_str *xs_html_render_s(xs_html *tag, const char *prefix); #define xs_html_render(tag) xs_html_render_s(tag, NULL) @@ -47,16 +47,16 @@ struct xs_html { xs_html *next; }; -xs_str *xs_html_encode(char *str) +xs_str *xs_html_encode(const char *str) /* encodes str using HTML entities */ { xs_str *s = xs_str_new(NULL); int o = 0; - char *e = str + strlen(str); + const char *e = str + strlen(str); for (;;) { char *ec = "<>\"'&"; /* characters to escape */ - char *q = e; + const char *q = e; int z; /* find the nearest happening of a char */ @@ -90,7 +90,7 @@ xs_str *xs_html_encode(char *str) #define XS_HTML_NEW() memset(xs_realloc(NULL, sizeof(xs_html)), '\0', sizeof(xs_html)) -xs_html *xs_html_attr(char *key, char *value) +xs_html *xs_html_attr(const char *key, const char *value) /* creates an HTML block with an attribute */ { xs_html *a = XS_HTML_NEW(); @@ -108,7 +108,7 @@ xs_html *xs_html_attr(char *key, char *value) } -xs_html *xs_html_text(char *content) +xs_html *xs_html_text(const char *content) /* creates an HTML block of text, escaping it previously */ { xs_html *a = XS_HTML_NEW(); @@ -120,7 +120,7 @@ xs_html *xs_html_text(char *content) } -xs_html *xs_html_raw(char *content) +xs_html *xs_html_raw(const char *content) /* creates an HTML block without escaping (for pre-formatted HTML, comments, etc) */ { xs_html *a = XS_HTML_NEW(); @@ -152,7 +152,7 @@ xs_html *_xs_html_add(xs_html *tag, xs_html *var[]) } -static xs_html *_xs_html_tag_t(xs_html_type type, char *tag, xs_html *var[]) +static xs_html *_xs_html_tag_t(xs_html_type type, const char *tag, xs_html *var[]) /* creates a tag with a variable list of attributes and subtags */ { xs_html *a = XS_HTML_NEW(); @@ -169,13 +169,13 @@ static xs_html *_xs_html_tag_t(xs_html_type type, char *tag, xs_html *var[]) } -xs_html *_xs_html_tag(char *tag, xs_html *var[]) +xs_html *_xs_html_tag(const char *tag, xs_html *var[]) { return _xs_html_tag_t(XS_HTML_TAG, tag, var); } -xs_html *_xs_html_sctag(char *tag, xs_html *var[]) +xs_html *_xs_html_sctag(const char *tag, xs_html *var[]) { return _xs_html_tag_t(XS_HTML_SCTAG, tag, var); } @@ -239,7 +239,7 @@ void xs_html_render_f(xs_html *h, FILE *f) } -xs_str *xs_html_render_s(xs_html *tag, char *prefix) +xs_str *xs_html_render_s(xs_html *tag, const char *prefix) /* renders to a string */ { xs_str *s = NULL; diff --git a/xs_httpd.h b/xs_httpd.h index 4d006d7..60933c8 100644 --- a/xs_httpd.h +++ b/xs_httpd.h @@ -16,7 +16,7 @@ xs_dict *xs_httpd_request(FILE *f, xs_str **payload, int *p_size) xs *q_vars = NULL; xs *p_vars = NULL; xs *l1, *l2; - char *v; + const char *v; xs_socket_timeout(fileno(f), 2.0, 0.0); @@ -60,7 +60,8 @@ xs_dict *xs_httpd_request(FILE *f, xs_str **payload, int *p_size) p = xs_split_n(l, ": ", 1); if (xs_list_len(p) == 2) - req = xs_dict_append(req, xs_tolower_i(xs_list_get(p, 0)), xs_list_get(p, 1)); + req = xs_dict_append(req, xs_tolower_i( + (xs_str *)xs_list_get(p, 0)), xs_list_get(p, 1)); } xs_socket_timeout(fileno(f), 5.0, 0.0); diff --git a/xs_json.h b/xs_json.h index 6706d7e..3a7742d 100644 --- a/xs_json.h +++ b/xs_json.h @@ -71,12 +71,12 @@ static void _xs_json_indent(int level, int indent, FILE *f) } -static void _xs_json_dump(const xs_val *s_data, int level, int indent, FILE *f) +static void _xs_json_dump(const xs_val *data, int level, int indent, FILE *f) /* dumps partial data as JSON */ { int c = 0; + int ct = 0; xs_val *v; - xs_val *data = (xs_val *)s_data; switch (xs_type(data)) { case XSTYPE_NULL: @@ -98,7 +98,7 @@ static void _xs_json_dump(const xs_val *s_data, int level, int indent, FILE *f) case XSTYPE_LIST: fputc('[', f); - while (xs_list_iter(&data, &v)) { + while (xs_list_next(data, &v, &ct)) { if (c != 0) fputc(',', f); @@ -117,9 +117,8 @@ static void _xs_json_dump(const xs_val *s_data, int level, int indent, FILE *f) fputc('{', f); xs_str *k; - int ct = 0; - while (xs_dict_next(s_data, &k, &v, &ct)) { + while (xs_dict_next(data, &k, &v, &ct)) { if (c != 0) fputc(',', f); diff --git a/xs_set.h b/xs_set.h index 3a334e4..b7eb091 100644 --- a/xs_set.h +++ b/xs_set.h @@ -104,7 +104,7 @@ int xs_set_add(xs_set *s, const xs_val *data) /* if it's new, add the data */ if (ret) - s->list = xs_list_append_m(s->list, data, xs_size(data)); + s->list = xs_list_append(s->list, data); return ret; } diff --git a/xs_unicode.h b/xs_unicode.h index 6654da4..1799d89 100644 --- a/xs_unicode.h +++ b/xs_unicode.h @@ -6,7 +6,7 @@ int _xs_utf8_enc(char buf[4], unsigned int cpoint); int xs_is_utf8_cont_byte(char c); - unsigned int xs_utf8_dec(char **str); + unsigned int xs_utf8_dec(const char **str); int xs_unicode_width(unsigned int cpoint); int xs_is_surrogate(unsigned int cpoint); unsigned int xs_surrogate_dec(unsigned int p1, unsigned int p2); @@ -66,10 +66,10 @@ int xs_is_utf8_cont_byte(char c) } -unsigned int xs_utf8_dec(char **str) +unsigned int xs_utf8_dec(const char **str) /* decodes an utf-8 char inside str and updates the pointer */ { - char *p = *str; + const char *p = *str; unsigned int cpoint = 0; unsigned char c = *p++; int cb = 0; diff --git a/xs_url.h b/xs_url.h index 6c9c8b5..69313b6 100644 --- a/xs_url.h +++ b/xs_url.h @@ -119,8 +119,8 @@ xs_dict *xs_multipart_form_data(const char *payload, int p_size, const char *hea while ((p = xs_memmem(payload + offset, p_size - offset, boundary, bsz)) != NULL) { xs *s1 = NULL; xs *l1 = NULL; - char *vn = NULL; - char *fn = NULL; + const char *vn = NULL; + const char *fn = NULL; char *q; int po, ps; diff --git a/xs_version.h b/xs_version.h index 16faf2b..9ecf9b8 100644 --- a/xs_version.h +++ b/xs_version.h @@ -1 +1 @@ -/* 6e75e8736f7f1b6ea6c6774d4bd922b3ad56b771 2024-05-15T11:42:19+02:00 */ +/* 34850dcdec50b669a2c0bbe9f16f6d9c4b16eafd 2024-05-21T14:06:02+02:00 */ -- cgit v1.2.3