/* * Treebird - Lightweight frontend for Pleroma * Copyright (C) 2022 Nekobit * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include #include "base_page.h" #include "error.h" #include "../config.h" #include "account.h" #include "easprintf.h" #include "status.h" #include "http.h" // Files #include "../static/index.chtml" #include "../static/account.chtml" #include "../static/account_info.chtml" #define FOLLOWS_YOU_HTML "%s" #define MAKE_FOCUSED_IF(test_tab) (tab == test_tab ? "focused" : "") char* construct_account_info(struct mstdnt_account* acct, size_t* size) { char* acct_info_html; size_t s; s = easprintf(&acct_info_html, data_account_info_html, acct->note); if (size) *size = s; return acct_info_html; } static char* account_statuses_cb(struct session* ssn, mastodont_t* api, struct mstdnt_account* acct) { (void)ssn; char* statuses_html; struct mstdnt_storage storage; struct mstdnt_status* statuses = NULL; size_t statuses_len = 0; if (mastodont_get_account_statuses(api, acct->id, NULL, &storage, &statuses, &statuses_len)) { statuses_html = construct_error(storage.error, E_ERROR, 1, NULL); } else { statuses_html = construct_statuses(api, statuses, statuses_len, NULL); if (!statuses_html) statuses_html = construct_error("No statuses", E_NOTICE, 1, NULL); } mastodont_storage_cleanup(&storage); mstdnt_cleanup_statuses(statuses, statuses_len); return statuses_html; } static char* account_scrobbles_cb(struct session* ssn, mastodont_t* api, struct mstdnt_account* acct) { (void)ssn; char* scrobbles_html = NULL; struct mstdnt_storage storage; struct mstdnt_scrobble* scrobbles = NULL; size_t scrobbles_len = 0; struct mstdnt_get_scrobbles_args args = { .max_id = NULL, .min_id = NULL, .since_id = NULL, .offset = 0, .limit = 0 }; if (mastodont_get_scrobbles(api, acct->id, &args, &storage, &scrobbles, &scrobbles_len)) { scrobbles_html = construct_error(storage.error, E_ERROR, 1, NULL); } else { /* scrobble_html = construct_statuses(api, statuses, statuses_len, NULL); */ if (!scrobbles_html) scrobbles_html = construct_error("No scrobbles", E_NOTICE, 1, NULL); } mastodont_storage_cleanup(&storage); free(scrobbles); return scrobbles_html; } static void fetch_account_page(struct session* ssn, mastodont_t* api, char* id, enum account_tab tab, char* (*callback)(struct session* ssn, mastodont_t* api, struct mstdnt_account* acct)) { char* account_page; char* data; struct mstdnt_storage storage = { 0 }, relations_storage = { 0 }; struct mstdnt_account acct = { 0 }; struct mstdnt_relationship* relationships = NULL; size_t relationships_len = 0; int lookup_type = config_experimental_lookup ? MSTDNT_LOOKUP_ACCT : MSTDNT_LOOKUP_ID; if (mastodont_get_account(api, lookup_type, id, &acct, &storage, NULL) || mastodont_get_relationships(api, &(acct.id), 1, &relations_storage, &relationships, &relationships_len)) { account_page = construct_error(storage.error, E_ERROR, 1, NULL); } else { data = callback(ssn, api, &acct); account_page = construct_account_page(api, &acct, relationships, tab, data, NULL); if (!account_page) account_page = construct_error("Couldn't load page", E_ERROR, 1, NULL); free(data); } struct base_page b = { .category = BASE_CAT_NONE, .locale = L10N_EN_US, .content = account_page, .sidebar_left = NULL }; render_base_page(&b, ssn, api); /* Output */ mastodont_storage_cleanup(&storage); mastodont_storage_cleanup(&relations_storage); mstdnt_cleanup_relationships(relationships); free(account_page); } char* construct_account_page(mastodont_t* api, struct mstdnt_account* acct, struct mstdnt_relationship* relationship, enum account_tab tab, char* content, size_t* res_size) { int cleanup = 0; int result_size; char* follows_you = NULL; char* info_html = NULL; char* is_blocked = NULL; char* result; // Load statuses html if (acct->note && strcmp(acct->note, "") != 0) { info_html = construct_account_info(acct, NULL); } if (relationship) { if (MSTDNT_FLAG_ISSET(relationship->flags, MSTDNT_RELATIONSHIP_FOLLOWED_BY)) easprintf(&follows_you, FOLLOWS_YOU_HTML, "Follows you"); if (MSTDNT_FLAG_ISSET(relationship->flags, MSTDNT_RELATIONSHIP_BLOCKED_BY)) is_blocked = construct_error("You are blocked by this user", E_NOTICE, 0, NULL); } result_size = easprintf(&result, data_account_html, is_blocked ? is_blocked : "", acct->header, follows_you ? follows_you : "", acct->display_name, acct->acct, config_url_prefix, acct->id, !relationship ? "" : MSTDNT_FLAG_ISSET(relationship->flags, MSTDNT_RELATIONSHIP_NOTIFYING) ? "un" : "", !relationship ? "" : MSTDNT_FLAG_ISSET(relationship->flags, MSTDNT_RELATIONSHIP_NOTIFYING) ? "Unsubscribe" : "Subscribe", config_url_prefix, acct->id, !relationship ? "" : MSTDNT_FLAG_ISSET(relationship->flags, MSTDNT_RELATIONSHIP_BLOCKING) ? "un" : "", !relationship ? "" : MSTDNT_FLAG_ISSET(relationship->flags, MSTDNT_RELATIONSHIP_BLOCKING) ? "Unblock" : "Block", config_url_prefix, acct->id, !relationship ? "" : MSTDNT_FLAG_ISSET(relationship->flags, MSTDNT_RELATIONSHIP_MUTING) ? "un" : "", !relationship ? "" : MSTDNT_FLAG_ISSET(relationship->flags, MSTDNT_RELATIONSHIP_MUTING) ? "Unmute" : "Mute", "Statuses", acct->statuses_count, "Following", acct->following_count, "Followers", acct->followers_count, !relationship ? "" : MSTDNT_FLAG_ISSET(relationship->flags, MSTDNT_RELATIONSHIP_FOLLOWING) ? "active" : "", !relationship ? "" : MSTDNT_FLAG_ISSET(relationship->flags, MSTDNT_RELATIONSHIP_FOLLOWING) ? "Following!" : "Follow", acct->avatar, info_html ? info_html : "", config_url_prefix, acct->acct, MAKE_FOCUSED_IF(ACCT_TAB_STATUSES), "Statuses", config_url_prefix, acct->acct, MAKE_FOCUSED_IF(ACCT_TAB_SCROBBLES), "Scrobbles", config_url_prefix, acct->acct, MAKE_FOCUSED_IF(ACCT_TAB_MEDIA), "Media", config_url_prefix, acct->acct, MAKE_FOCUSED_IF(ACCT_TAB_PINNED), "Pinned", content); if (result_size == -1) result = NULL; if (res_size) *res_size = result_size; if (info_html) free(info_html); if (follows_you) free(follows_you); if (is_blocked) free(is_blocked); return result; } void content_account_statuses(struct session* ssn, mastodont_t* api, char** data) { fetch_account_page(ssn, api, data[0], ACCT_TAB_STATUSES, account_statuses_cb); } void content_account_scrobbles(struct session* ssn, mastodont_t* api, char** data) { fetch_account_page(ssn, api, data[0], ACCT_TAB_SCROBBLES, account_scrobbles_cb); } void content_account_pinned(struct session* ssn, mastodont_t* api, char** data) { fetch_account_page(ssn, api, data[0], ACCT_TAB_PINNED, account_statuses_cb); } void content_account_media(struct session* ssn, mastodont_t* api, char** data) { fetch_account_page(ssn, api, data[0], ACCT_TAB_MEDIA, account_statuses_cb); } void content_account_action(struct session* ssn, mastodont_t* api, char** data) { char* referer = getenv("HTTP_REFERER"); struct mstdnt_storage storage = { 0 }; struct mstdnt_relationship acct = { 0 }; if (strcmp(data[1], "follow") == 0) mastodont_follow_account(api, data[0], &storage, &acct); else if (strcmp(data[1], "unfollow") == 0) mastodont_unfollow_account(api, data[0], &storage, &acct); else if (strcmp(data[1], "mute") == 0) mastodont_mute_account(api, data[0], &storage, &acct); else if (strcmp(data[1], "unmute") == 0) mastodont_unmute_account(api, data[0], &storage, &acct); else if (strcmp(data[1], "block") == 0) mastodont_block_account(api, data[0], &storage, &acct); else if (strcmp(data[1], "unblock") == 0) mastodont_unblock_account(api, data[0], &storage, &acct); else if (strcmp(data[1], "subscribe") == 0) mastodont_subscribe_account(api, data[0], &storage, &acct); else if (strcmp(data[1], "unsubscribe") == 0) mastodont_unsubscribe_account(api, data[0], &storage, &acct); mastodont_storage_cleanup(&storage); redirect(REDIRECT_303, referer); }