Finish cleaning up template stuff

FossilOrigin-Name: 1fa9a720bfca80c96264c4f7263f6de710bee40da23d92f874070de5f32412a7
This commit is contained in:
nekobit 2022-08-22 13:50:23 +00:00
parent 50e76ae712
commit 09ddb21d42
27 changed files with 38 additions and 1557 deletions

View File

@ -31,7 +31,6 @@
#include "base_page.h"
#include "scrobble.h"
#include "string_helpers.h"
#include "navigation.h"
#include "emoji.h"
#include "timeline.h"
@ -504,36 +503,6 @@ AV* perlify_accounts(const struct mstdnt_account* accounts, size_t len)
return av;
}
HV* perlify_scrobble(const struct mstdnt_scrobble* scrobble)
{
if (!scrobble) return NULL;
HV* scrobble_hv = newHV();
hvstores_ref(scrobble_hv, "account", perlify_account(&(scrobble->account)));
hvstores_str(scrobble_hv, "album", scrobble->album);
hvstores_str(scrobble_hv, "artist", scrobble->artist);
hvstores_int(scrobble_hv, "created_at", scrobble->created_at);
hvstores_str(scrobble_hv, "id", scrobble->id);
hvstores_int(scrobble_hv, "length", scrobble->length);
hvstores_str(scrobble_hv, "title", scrobble->title);
return scrobble_hv;
}
AV* perlify_scrobbles(const struct mstdnt_scrobble* scrobbles, size_t len)
{
if (!(scrobbles && len)) return NULL;
AV* av = newAV();
av_extend(av, len-1);
for (int i = 0; i < len; ++i)
{
av_store(av, i, newRV_inc((SV*)perlify_scrobble(scrobbles + i)));
}
return av;
}
HV* perlify_account(const struct mstdnt_account* acct)
{
if (!acct) return NULL;

View File

@ -72,8 +72,6 @@ void content_account_bookmarks(PATH_ARGS);
HV* perlify_account(const struct mstdnt_account* acct);
AV* perlify_accounts(const struct mstdnt_account* accounts, size_t len);
HV* perlify_scrobble(const struct mstdnt_scrobble* scrobble);
AV* perlify_scrobbles(const struct mstdnt_scrobble* scrobbles, size_t len);
HV* perlify_relationship(const struct mstdnt_relationship* rel);
#endif // ACCOUNT_H

View File

@ -109,7 +109,7 @@ char* construct_emoji_picker(char* status_id, size_t* size)
AV* av = newAV();
for (int i = 0; i < EMO_CAT_LEN; ++i)
{
av_store(av, i, newSVpv(emojis + i, len + i));
av_store(av, i, newSVpv(emojis[i], len[i]));
}
XPUSHs(newRV_inc((SV*)av));
PERL_STACK_SCALAR_CALL("emojis::emoji_picker");

View File

@ -21,46 +21,12 @@
#include "easprintf.h"
#include "l10n.h"
// Pages
#include "../static/error_404.ctmpl"
#include "../static/error.ctmpl"
char* construct_error(const char* error, enum error_type type, unsigned pad, size_t* size)
{
char* class;
switch (type)
{
case E_ERROR:
class = "error"; break;
case E_WARNING:
class = "warning"; break;
case E_NOTICE:
class = "notice"; break;
}
struct error_template data = {
.err_type = class,
.is_padded = pad ? "error-pad" : NULL,
.error = error ? error : "An error occured",
};
return tmpl_gen_error(&data, size);
}
void content_not_found(FCGX_Request* req, struct session* ssn, mastodont_t* api, char* path)
{
char* page;
struct error_404_template data = {
.error = L10N[L10N_EN_US][L10N_PAGE_NOT_FOUND]
};
page = tmpl_gen_error_404(&data, NULL);
struct base_page b = {
.content = page,
.content = "Content not found",
.sidebar_left = NULL
};
render_base_page(&b, req, ssn, api);
free(page);
}

View File

@ -23,14 +23,6 @@
#include "session.h"
#include "path.h"
enum error_type
{
E_ERROR,
E_WARNING,
E_NOTICE
};
char* construct_error(const char* error, enum error_type type, unsigned pad, size_t* size);
void content_not_found(FCGX_Request* req, struct session* ssn, mastodont_t* api, char* path);
#endif // ERROR_H

View File

@ -1,121 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <time.h>
#include "graphsnbars.h"
#include "easprintf.h"
#include "string_helpers.h"
// Pages
#include "../static/bar.ctmpl"
#include "../static/bar_graph.ctmpl"
struct hashtags_graph_args
{
struct mstdnt_tag* tags;
size_t tags_len;
unsigned max;
time_t rel_day;
size_t days;
};
char* construct_bar_graph_container(char* bars, size_t* size)
{
struct bar_graph_template data = {
.graph = bars,
};
return tmpl_gen_bar_graph(&data, size);
}
char* construct_bar(float value, size_t* size)
{
struct bar_template data = {
.value = value * 100
};
return tmpl_gen_bar(&data, size);
}
static char* construct_hashgraph_voidwrap(void* passed, size_t index, size_t* res)
{
unsigned curr_sum = 0;
struct hashtags_graph_args* args = passed;
struct mstdnt_tag* tags = args->tags;
size_t tags_len = args->tags_len;
unsigned max = args->max;
time_t rel_day = args->rel_day;
size_t days = args->days;
for (int i = 0; i < tags_len; ++i)
{
for (int j = 0; j < tags[i].history_len; ++j)
{
if (tags[i].history[j].day == rel_day-((days-index-1)*86400))
curr_sum += tags[i].history[j].uses;
}
}
return construct_bar((float)curr_sum / max, res);
}
char* construct_hashtags_graph(struct mstdnt_tag* tags,
size_t tags_len,
size_t days,
size_t* ret_size)
{
unsigned max_sum = 0;
unsigned curr_sum = 0;
size_t max_history_len = 0;
// Get current time at midnight for basis, copy over
time_t t = time(NULL);
struct tm* mn_ptr = gmtime(&t);
struct tm mn;
memcpy(&mn, mn_ptr, sizeof(mn));
mn.tm_hour = 0;
mn.tm_min = 0;
mn.tm_sec = 0;
time_t rel_day = timegm(&mn);
// Run a loop through all the hashtags, sum each set up,
// then get the largest sum
for (size_t i = 0; i < days; ++i)
{
for (size_t j = 0; j < tags_len && i < tags[j].history_len; ++j)
{
if (tags[j].history_len > max_history_len)
max_history_len = tags[j].history_len;
if (tags[j].history[i].day >= rel_day-(i*86400))
curr_sum += tags[j].history[i].uses;
}
if (curr_sum > max_sum)
max_sum = curr_sum;
curr_sum = 0;
}
struct hashtags_graph_args args = {
.tags = tags,
.tags_len = tags_len,
.max = max_sum,
.rel_day = rel_day,
.days = max_history_len,
};
return construct_func_strings(construct_hashgraph_voidwrap, &args, max_history_len, ret_size);
}

View File

@ -1,32 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef GRAPHS_N_BARS_H
#define GRAPHS_N_BARS_H
#include <stddef.h>
#include <mastodont.h>
#include "session.h"
char* construct_bar_graph_container(char* bars, size_t* size);
char* construct_bar(float value, size_t* size);
char* construct_hashtags_graph(struct mstdnt_tag* tags,
size_t tags_len,
size_t days,
size_t* ret_size);
#endif /* GRAPHS_N_BARS_H */

View File

@ -22,44 +22,7 @@
#include "easprintf.h"
#include "../config.h"
// Pages
#include "../static/hashtag.ctmpl"
#include "../static/hashtag_page.ctmpl"
#define TAG_SIZE_INITIAL 12
static unsigned hashtag_history_daily_uses(size_t max, struct mstdnt_history* history, size_t history_len)
{
unsigned total = 0;
for (int i = 0; i < history_len && i < max; ++i)
total += history[i].uses;
return total;
}
char* construct_hashtag(struct mstdnt_tag* hashtag, size_t* size)
{
// Lol!
unsigned hash_size = TAG_SIZE_INITIAL +
CLAMP(hashtag_history_daily_uses(7, hashtag->history, hashtag->history_len)*2, 0, 42);
struct hashtag_template data = {
.prefix = config_url_prefix,
.tag = hashtag->name,
.tag_size = hash_size,
};
return tmpl_gen_hashtag(&data, size);
}
static char* construct_hashtag_voidwrap(void* passed, size_t index, size_t* res)
{
return construct_hashtag((struct mstdnt_tag*)passed + index, res);
}
char* construct_hashtags(struct mstdnt_tag* hashtags, size_t size, size_t* ret_size)
{
if (!(hashtags && size)) return NULL;
return construct_func_strings(construct_hashtag_voidwrap, hashtags, size, ret_size);
}

View File

@ -21,7 +21,6 @@
#include <stddef.h>
#include <mastodont.h>
char* construct_hashtag(struct mstdnt_tag* hashtag, size_t* size);
char* construct_hashtags(struct mstdnt_tag* hashtags, size_t size, size_t* ret_size);
// TODO?
#endif /* HASHTAG_H */

View File

@ -29,10 +29,6 @@
#include "lists.h"
#include "string_helpers.h"
#include "http.h"
// Files
#include "../static/account.ctmpl"
#include "../static/list.ctmpl"
#include "../static/lists.ctmpl"
void content_lists(PATH_ARGS)
{

View File

@ -29,8 +29,6 @@
#include <curl/curl.h>
#include <fcgi_stdio.h>
// Files
#include "../static/login.ctmpl"
#define LOGIN_SCOPE "read+write+follow+push"
@ -163,7 +161,7 @@ void content_login(PATH_ARGS)
if (mastodont_register_app(api, &m_args, &args_app, &storage, &app) != 0)
{
error = construct_error(oauth_store.error, E_ERROR, 1, NULL);
// error = construct_error(oauth_store.error, E_ERROR, 1, NULL);
}
else {
struct mstdnt_application_args args_token = {
@ -183,7 +181,7 @@ void content_login(PATH_ARGS)
&oauth_store,
&token) != 0 && oauth_store.error)
{
error = construct_error(oauth_store.error, E_ERROR, 1, NULL);
//error = construct_error(oauth_store.error, E_ERROR, 1, NULL);
}
else {
if (url_link)

View File

@ -1,43 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "navigation.h"
#include "easprintf.h"
// Pages
#include "../static/navigation.ctmpl"
#define SUBMIT_HTML "<input type=\"submit\" class=\"hidden\">"
char* construct_navigation_box(char* start_id,
char* prev_id,
char* next_id,
size_t* size)
{
int is_start = start_id && prev_id ? strcmp(start_id, prev_id) == 0 : 0;
struct navigation_template tdata = {
.start_id = start_id,
.min_id = prev_id,
.prev_active = is_start ? "btn-disabled" : NULL,
.prev_submit = is_start ? "" : SUBMIT_HTML,
.max_id = next_id
};
return tmpl_gen_navigation(&tdata, size);
}

View File

@ -1,29 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef NAVIGATION_H
#define NAVIGATION_H
#include <stddef.h>
#include <mastodont.h>
char* construct_navigation_box(char* start_id,
char* prev_id,
char* next_id,
size_t* size);
#endif // NAVIGATION_H

View File

@ -25,7 +25,6 @@
#include "base_page.h"
#include "string_helpers.h"
#include "easprintf.h"
#include "navigation.h"
#include "http.h"
#include "status.h"
#include "error.h"
@ -33,165 +32,6 @@
#include "account.h"
#include "../config.h"
// Pages
#include "../static/notifications_page.ctmpl"
#include "../static/notifications.ctmpl"
#include "../static/notification_action.ctmpl"
#include "../static/notification.ctmpl"
#include "../static/notification_compact.ctmpl"
#include "../static/like_svg.ctmpl"
#include "../static/repeat_svg.ctmpl"
#include "../static/notifications_embed.ctmpl"
struct notification_args
{
struct session* ssn;
mastodont_t* api;
struct mstdnt_notification* notifs;
};
char* construct_notification(struct session* ssn,
mastodont_t* api,
struct mstdnt_notification* notif,
size_t* size)
{
char* notif_html;
if (notif->status)
{
// Construct status with notification_info
notif_html = construct_status(ssn, api, notif->status, size, notif, NULL, 0);
}
else {
notif_html = construct_notification_action(notif, size);
}
return notif_html;
}
char* construct_notification_action(struct mstdnt_notification* notif, size_t* size)
{
char* res;
char* serialized_display_name = sanitize_html(notif->account->display_name);
char* display_name = emojify(serialized_display_name,
notif->account->emojis,
notif->account->emojis_len);
struct notification_action_template tdata = {
.avatar = notif->account->avatar,
.acct = notif->account->acct,
.display_name = display_name,
.prefix = config_url_prefix,
.action = notification_type_compact_str(notif->type),
.notif_svg = notification_type_svg(notif->type)
};
res = tmpl_gen_notification_action(&tdata, size);
/* // Cleanup */
if (display_name != notif->account->display_name &&
display_name != serialized_display_name)
free(display_name);
if (serialized_display_name != notif->account->display_name)
free(serialized_display_name);
return res;
}
char* construct_notification_compact(struct session* ssn,
mastodont_t* api,
struct mstdnt_notification* notif,
size_t* size)
{
char* notif_html;
char* status_format = NULL;
char* notif_stats = NULL;
const char* type_str = notification_type_compact_str(notif->type);
const char* type_svg = notification_type_svg(notif->type);
if (notif->status)
{
if (notif->type == MSTDNT_NOTIFICATION_MENTION)
notif_stats = construct_interaction_buttons(ssn, notif->status, NULL,
STATUS_NO_LIKEBOOST | STATUS_NO_DOPAMEME);
status_format = reformat_status(ssn,
notif->status->content,
notif->status->emojis,
notif->status->emojis_len);
}
char* serialized_display_name = sanitize_html(notif->account->display_name);
char* display_name = emojify(serialized_display_name,
notif->account->emojis,
notif->account->emojis_len);
struct notification_compact_template tdata = {
.avatar = notif->account->avatar,
.has_icon = strlen(type_svg) == 0 ? "" : "-with-icon",
.acct = notif->account->acct,
.display_name = display_name,
.action = type_str,
.notif_svg = type_svg,
.is_status = (notif->type == MSTDNT_NOTIFICATION_STATUS ||
notif->type == MSTDNT_NOTIFICATION_MENTION ? "is-mention" : NULL),
/* Might show follower address */
.content = (notif->type == MSTDNT_NOTIFICATION_FOLLOW ?
notif->account->acct : status_format),
.stats = notif_stats
};
notif_html = tmpl_gen_notification_compact(&tdata, size);
if (status_format &&
status_format != notif->status->content) free(status_format);
if (notif_stats) free(notif_stats);
if (serialized_display_name != notif->account->display_name)
free(serialized_display_name);
if (display_name != notif->account->display_name &&
display_name != serialized_display_name)
free(display_name);
return notif_html;
}
static char* construct_notification_voidwrap(void* passed, size_t index, size_t* res)
{
struct notification_args* args = passed;
return construct_notification(args->ssn, args->api, args->notifs + index, res);
}
static char* construct_notification_compact_voidwrap(void* passed, size_t index, size_t* res)
{
struct notification_args* args = passed;
return construct_notification_compact(args->ssn, args->api, args->notifs + index, res);
}
char* construct_notifications(struct session* ssn,
mastodont_t* api,
struct mstdnt_notification* notifs,
size_t size,
size_t* ret_size)
{
struct notification_args args = {
.ssn = ssn,
.api = api,
.notifs = notifs
};
return construct_func_strings(construct_notification_voidwrap, &args, size, ret_size);
}
char* construct_notifications_compact(struct session* ssn,
mastodont_t* api,
struct mstdnt_notification* notifs,
size_t size,
size_t* ret_size)
{
struct notification_args args = {
.ssn = ssn,
.api = api,
.notifs = notifs
};
return construct_func_strings(construct_notification_compact_voidwrap,
&args,
size,
ret_size);
}
void content_notifications(PATH_ARGS)
{
struct mstdnt_args m_args;

View File

@ -23,29 +23,8 @@
#include <fcgiapp.h>
#include "session.h"
#include "path.h"
#include "type_string.h"
#include "global_perl.h"
char* construct_notification(struct session* ssn,
mastodont_t* api,
struct mstdnt_notification* notif,
size_t* size);
char* construct_notification_action(struct mstdnt_notification* notif, size_t* size);
char* construct_notification_compact(struct session* ssn,
mastodont_t* api,
struct mstdnt_notification* notif,
size_t* size);
char* construct_notifications(struct session* ssn,
mastodont_t* api,
struct mstdnt_notification* notifs,
size_t size,
size_t* ret_size);
char* construct_notifications_compact(struct session* ssn,
mastodont_t* api,
struct mstdnt_notification* notifs,
size_t size,
size_t* ret_size);
// Page contents
void content_notifications(PATH_ARGS);
void content_notifications_compact(PATH_ARGS);

View File

@ -31,11 +31,6 @@
#include "l10n.h"
#include <fcgi_stdio.h>
// Pages
#include "../static/config_general.ctmpl"
#include "../static/config_appearance.ctmpl"
#include "../static/config_sidebar.ctmpl"
#define bool_checked(key) (ssn->config.key ? "checked" : "")
enum config_category

View File

@ -1,183 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#include <stdlib.h>
#include <string.h>
#include "reply.h"
#include "easprintf.h"
#include "../config.h"
// Pages
#include "../static/post.ctmpl"
#define ID_REPLY_SIZE 256
#define ID_RESPONSE "<input type=\"hidden\" name=\"replyid\" value=\"%s\">"
char* construct_post_box(struct mstdnt_status* reply_status,
char* default_content,
size_t* size)
{
#define C_S "checked"
#define D_S "disabled"
char* reply_html;
char id_reply[ID_REPLY_SIZE];
enum mstdnt_visibility_type vis = MSTDNT_VISIBILITY_PUBLIC;
// Put hidden post request and check visibility
if (reply_status)
{
snprintf(id_reply, ID_REPLY_SIZE, ID_RESPONSE, reply_status->id);
vis = reply_status->visibility;
}
/*
* Mastodont-c orders the visibility type from smallest (PUBLIC) to
* largest (LOCAL), so we take advantage of the enum values
*/
struct post_template tdata = {
.prefix = config_url_prefix,
.reply_input = reply_status ? id_reply : NULL,
.content = default_content,
.public_checked = vis == MSTDNT_VISIBILITY_PUBLIC ? C_S : NULL,
// You can reply with public to unlisted posts
.public_disabled = vis > MSTDNT_VISIBILITY_UNLISTED ? D_S : NULL,
.unlisted_checked = vis == MSTDNT_VISIBILITY_UNLISTED ? C_S : NULL,
.unlisted_disabled = vis > MSTDNT_VISIBILITY_UNLISTED ? D_S : NULL,
.private_checked = vis == MSTDNT_VISIBILITY_PRIVATE ? C_S : NULL,
.private_disabled = vis > MSTDNT_VISIBILITY_PRIVATE ? D_S : NULL,
.direct_checked = vis == MSTDNT_VISIBILITY_DIRECT ? C_S : NULL,
.local_checked = vis == MSTDNT_VISIBILITY_LOCAL ? C_S : NULL,
};
return tmpl_gen_post(&tdata, size);
}
/* Some comments:
* - Misskey does not return <span>, but we still regex to make sure it's a highlight
* - The order of parameters in a tag can be changed (mastodon does this),
* so we just grep for regex href
* - Misskey/Mastodon adds an @ symbol in the href param, while pleroma adds /users and honk adds /u
*/
#define REGEX_REPLY "<a .*?href=\"https?:\\/\\/(.*?)\\/(?:@|users/|u/)?(.*?)?\".*?>@(?:<span>)?.*?(?:<\\/span>)?"
char* reply_status(struct session* ssn, char* id, struct mstdnt_status* status)
{
char* content = status->content;
size_t content_len = strlen(status->content);
char* stat_reply;
// Regex
pcre2_code* re;
PCRE2_SIZE* re_results;
pcre2_match_data* re_data;
// Regex data
int rc;
int error;
PCRE2_SIZE erroffset;
int url_off, url_len, name_off, name_len;
// Replies
size_t replies_size = 0, replies_size_orig;
char* replies = NULL;
char* instance_domain = malloc(sizeof(config_instance_url)+sizeof("https:///")+1);
// sscanf instead of regex works here and requires less work, we just need to trim off the slash at the end
if (sscanf(config_instance_url, "https://%s/", instance_domain) == 0)
if (sscanf(config_instance_url, "http://%s/", instance_domain) == 0)
{
free(instance_domain);
return NULL;
}
instance_domain[strlen(instance_domain)] = '\0';
// Remove ports, if any. Needed for development or if
// the server actually supports these
char* port_val = strchr(instance_domain, ':');
if (port_val) *port_val = '\0';
// Load first reply
if (ssn->logged_in && strcmp(status->account.acct, ssn->acct.acct) != 0)
{
replies = malloc(replies_size = strlen(status->account.acct)+2);
replies[0] = '@';
strcpy(replies+1, status->account.acct);
replies[replies_size-1] = ' ';
}
// Compile regex
re = pcre2_compile((PCRE2_SPTR)REGEX_REPLY, PCRE2_ZERO_TERMINATED, 0, &error, &erroffset, NULL);
if (re == NULL)
{
fprintf(stderr, "Couldn't parse regex at offset %ld: %d\n", erroffset, error);
free(replies);
pcre2_code_free(re);
}
re_data = pcre2_match_data_create_from_pattern(re, NULL);
for (int ind = 0;;)
{
rc = pcre2_match(re, (PCRE2_SPTR)content, content_len, ind, 0, re_data, NULL);
if (rc < 0)
break;
re_results = pcre2_get_ovector_pointer(re_data);
// Store to last result
ind = re_results[5];
// Read out
url_off = re_results[2];
url_len = re_results[3] - url_off;
name_off = re_results[4];
name_len = re_results[5] - name_off;
int instance_cmp = strncmp(instance_domain, content+url_off, url_len);
// Is this the same as us?
// Cut off url_len by one to slice the '/' at the end
if (instance_cmp == 0 &&
strncmp(ssn->acct.acct, content+name_off, name_len) == 0)
continue;
replies_size_orig = replies_size;
replies_size += (instance_cmp!=0?url_len:0)+name_len+3-(instance_cmp==0); // Bool as int :^)
// Realloc string
replies = realloc(replies, replies_size+1);
replies[replies_size_orig] = '@';
memcpy(replies + replies_size_orig + 1, content + name_off, name_len);
if (instance_cmp != 0)
{
replies[replies_size_orig+1+name_len] = '@';
memcpy(replies + replies_size_orig + 1 + name_len + 1, content + url_off, url_len);
}
replies[replies_size-1] = ' ';
}
if (replies)
replies[replies_size-1] = '\0';
pcre2_match_data_free(re_data);
stat_reply = construct_post_box(status, replies, NULL);
pcre2_code_free(re);
free(replies);
free(instance_domain);
return stat_reply;
}

View File

@ -1,34 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef REPLY_H
#define REPLY_H
#include "session.h"
#include <stddef.h>
#include <mastodont.h>
char* construct_post_box(struct mstdnt_status* reply_id,
char* default_content,
size_t* size);
char* reply_status(struct session* ssn,
char* id,
struct mstdnt_status* status);
#endif // REPLY_H

View File

@ -19,35 +19,36 @@
#include "scrobble.h"
#include "easprintf.h"
#include "string_helpers.h"
#include "account.h"
#include "../static/scrobble.ctmpl"
char* construct_scrobble(struct mstdnt_scrobble* scrobble, size_t* size)
// Converts it into a perl struct
HV* perlify_scrobble(struct mstdnt_scrobble* scrobble)
{
struct scrobble_template tdata = {
.scrobble_id = scrobble->id,
.avatar = scrobble->account.avatar,
.username = scrobble->account.display_name,
.activity = "is listening to...",
.title_key = "Title",
.title = scrobble->title,
.artist_key = "Artist",
.artist = scrobble->artist,
.album_key = "Album",
.album = scrobble->album,
.length_key = "Duration",
.length = scrobble->length
};
if (!scrobble) return NULL;
HV* scrobble_hv = newHV();
return tmpl_gen_scrobble(&tdata, size);
hvstores_str(scrobble_hv, "album", scrobble->album);
hvstores_str(scrobble_hv, "artist", scrobble->artist);
hvstores_str(scrobble_hv, "id", scrobble->id);
hvstores_str(scrobble_hv, "title", scrobble->title);
hvstores_int(scrobble_hv, "created_at", scrobble->created_at);
hvstores_int(scrobble_hv, "length", scrobble->created_at);
hvstores_ref(scrobble_hv, "account", perlify_account(&(scrobble->account)));
return scrobble_hv;
}
static char* construct_scrobble_voidwrap(void* passed, size_t index, size_t* res)
// The same as above, but for multiple
AV* perlify_scrobbles(struct mstdnt_scrobble* scrobble, size_t len)
{
return construct_scrobble((struct mstdnt_scrobble*)passed + index, res);
}
if (!(scrobble && len)) return NULL;
AV* av = newAV();
av_extend(av, len-1);
char* construct_scrobbles(struct mstdnt_scrobble* scrobbles, size_t scrobbles_len, size_t* ret_size)
{
return construct_func_strings(construct_scrobble_voidwrap, scrobbles, scrobbles_len, ret_size);
for (int i = 0; i < len; ++i)
{
av_store(av, i, newRV_inc((SV*)perlify_scrobble(scrobble + i)));
}
return av;
}

View File

@ -19,8 +19,9 @@
#ifndef SCROBBLE_H
#define SCROBBLE_H
#include <mastodont.h>
#include "global_perl.h"
char* construct_scrobble(struct mstdnt_scrobble* scrobble, size_t* size);
char* construct_scrobbles(struct mstdnt_scrobble* scrobbles, size_t scrobbles_len, size_t* ret_size);
HV* perlify_scrobble(struct mstdnt_scrobble* scrobble);
AV* perlify_scrobbles(struct mstdnt_scrobble* scrobble, size_t len);
#endif /* SCROBBLE_H */

View File

@ -28,42 +28,6 @@
#include "hashtag.h"
#include "error.h"
#include "account.h"
#include "graphsnbars.h"
// Pages
#include "../static/search.ctmpl"
#include "../static/search_all.ctmpl"
void search_page(FCGX_Request* req,
struct session* ssn,
mastodont_t* api,
enum search_tab tab,
char* content)
{
char* out_data;
struct search_template tdata = {
.prefix = config_url_prefix,
.query = keystr(ssn->query.query),
.accounts_active = MAKE_FOCUSED_IF(tab, SEARCH_ACCOUNTS),
.accounts = "Accounts",
.hashtags_active = MAKE_FOCUSED_IF(tab, SEARCH_HASHTAGS),
.hashtags = "Hashtags",
.statuses_active = MAKE_FOCUSED_IF(tab, SEARCH_STATUSES),
.statuses = "Statuses",
.results = content
};
out_data = tmpl_gen_search(&tdata, NULL);
struct base_page b = {
.category = BASE_CAT_NONE,
.content = out_data,
.sidebar_left = NULL
};
// Output
render_base_page(&b, req, ssn, api);
free(out_data);
}
void content_search_all(PATH_ARGS)
{

View File

@ -23,18 +23,6 @@
#include "path.h"
#include "global_perl.h"
enum search_tab
{
SEARCH_STATUSES,
SEARCH_ACCOUNTS,
SEARCH_HASHTAGS,
};
void search_page(FCGX_Request* req,
struct session* ssn,
mastodont_t* api,
enum search_tab tab,
char* content);
void content_search_all(PATH_ARGS);
void content_search_statuses(PATH_ARGS);
void content_search_accounts(PATH_ARGS);

View File

@ -30,50 +30,16 @@
#include "cookie.h"
#include "string_helpers.h"
#include "error.h"
#include "reply.h"
#include "attachments.h"
#include "emoji_reaction.h"
#include "../config.h"
#include "type_string.h"
#include "string.h"
#include "emoji.h"
#include "account.h"
// Pages
#include "../static/status.ctmpl"
#include "../static/notification.ctmpl"
#include "../static/in_reply_to.ctmpl"
#include "../static/status_interactions_label.ctmpl"
#include "../static/status_interactions.ctmpl"
#include "../static/status_interaction_profile.ctmpl"
#include "../static/interactions_page.ctmpl"
#include "../static/likeboost.ctmpl"
#include "../static/reactions_btn.ctmpl"
#include "../static/interaction_buttons.ctmpl"
#include "../static/reply_link.ctmpl"
#include "../static/reply_checkbox.ctmpl"
#include "../static/menu_item.ctmpl"
#include "../static/like_btn.ctmpl"
#include "../static/repeat_btn.ctmpl"
#include "../static/reply_btn.ctmpl"
#include "../static/expand_btn.ctmpl"
#include "../static/like_btn_img.ctmpl"
#include "../static/repeat_btn_img.ctmpl"
#include "../static/reply_btn_img.ctmpl"
#include "../static/expand_btn_img.ctmpl"
#include "../static/thread_page_btn.ctmpl"
#define ACCOUNT_INTERACTIONS_LIMIT 11
#define NUM_STR "%u"
struct status_args
{
mastodont_t* api;
struct mstdnt_status* status;
struct construct_statuses_args* args;
struct session* ssn;
};
int try_post_status(struct session* ssn, mastodont_t* api)
{
if (!(keystr(ssn->post.content))) return 1;
@ -185,27 +151,6 @@ void content_status_react(PATH_ARGS)
redirect(req, REDIRECT_303, referer);
}
const char* status_visibility_str(enum l10n_locale loc,
enum mstdnt_visibility_type vis)
{
switch (vis)
{
case MSTDNT_VISIBILITY_UNLISTED:
return L10N[loc][L10N_VIS_UNLISTED];
case MSTDNT_VISIBILITY_PRIVATE:
return L10N[loc][L10N_VIS_PRIVATE];
case MSTDNT_VISIBILITY_DIRECT:
return L10N[loc][L10N_VIS_DIRECT];
case MSTDNT_VISIBILITY_LOCAL:
return L10N[loc][L10N_VIS_LOCAL];
case MSTDNT_VISIBILITY_LIST:
return L10N[loc][L10N_VIS_LIST];
case MSTDNT_VISIBILITY_PUBLIC:
default:
return L10N[loc][L10N_VIS_PUBLIC];
}
}
int try_interact_status(struct session* ssn, mastodont_t* api, char* id)
{
struct mstdnt_args m_args;
@ -245,127 +190,6 @@ int try_interact_status(struct session* ssn, mastodont_t* api, char* id)
return res;
}
char* construct_status_interactions_label(char* status_id,
int is_favourites,
char* header,
int val,
size_t* size)
{
struct status_interactions_label_template tdata = {
.prefix = config_url_prefix,
.status_id = status_id,
.action = is_favourites ? "favourited_by" : "reblogged_by",
.header = header,
.value = val,
};
return tmpl_gen_status_interactions_label(&tdata, size);
}
char* construct_interaction_buttons(struct session* ssn,
struct mstdnt_status* status,
size_t* size,
uint8_t flags)
{
return "";
}
char* construct_status_interactions(char* status_id,
int fav_count,
int reblog_count,
struct mstdnt_account* fav_accounts,
size_t fav_accounts_len,
struct mstdnt_account* reblog_accounts,
size_t reblog_accounts_len,
size_t* size)
{
char* html;
char* reblogs_label = reblog_count ?
construct_status_interactions_label(status_id, 0, "Reblogs", reblog_count, NULL) : NULL;
char* favourites_label = fav_count ?
construct_status_interactions_label(status_id, 1, "Favorites", fav_count, NULL) : NULL;
char* profiles = construct_status_interaction_profiles(reblog_accounts,
fav_accounts,
reblog_accounts_len,
fav_accounts_len,
NULL);
struct status_interactions_template tdata = {
.favourites_count = favourites_label,
.reblogs_count = reblogs_label,
.users = profiles
};
html = tmpl_gen_status_interactions(&tdata, size);
if (reblogs_label) free(reblogs_label);
if (favourites_label) free(favourites_label);
if (profiles) free(profiles);
return html;
}
char* construct_status_interaction_profile(struct interact_profile_args* args, size_t index, size_t* size)
{
size_t s = 0;
// Might change
struct mstdnt_account* check_type = args->reblogs;
char* profile_html = NULL;
// Loop through reblogs first, then favourites
if (index >= args->reblogs_len)
{
index -= args->reblogs_len;
check_type = args->favourites;
}
// If favourites, loops through reblogs to verify no duplicates
if (check_type == args->favourites)
{
for (size_t i = 0; i < args->reblogs_len; ++i)
if (strcmp(check_type[index].id, args->reblogs[i].id) == 0)
{
if (size) *size = 0;
return NULL;
}
}
// Usually means no reblogs if check_type is NULL
if (check_type)
{
struct status_interaction_profile_template tdata = {
.acct = check_type[index].acct,
.avatar = check_type[index].avatar
};
profile_html = tmpl_gen_status_interaction_profile(&tdata, &s);
}
if (size) *size = s;
return profile_html;
}
static char* construct_status_interaction_profiles_voidwrap(void* passed, size_t index, size_t* res)
{
struct interact_profile_args* args = passed;
return construct_status_interaction_profile(args, index, res);
}
char* construct_status_interaction_profiles(struct mstdnt_account* reblogs,
struct mstdnt_account* favourites,
size_t reblogs_len,
size_t favourites_len,
size_t* ret_size)
{
size_t arr_size = reblogs_len + favourites_len;
// Set a limit to interactions
if (arr_size > ACCOUNT_INTERACTIONS_LIMIT)
arr_size = ACCOUNT_INTERACTIONS_LIMIT;
struct interact_profile_args args = {
.reblogs = reblogs,
.reblogs_len = reblogs_len,
.favourites = favourites,
.favourites_len = favourites_len
};
return construct_func_strings(construct_status_interaction_profiles_voidwrap, &args, arr_size, ret_size);
}
char* get_in_reply_to(mastodont_t* api,
struct session* ssn,
struct mstdnt_status* status,
@ -383,418 +207,15 @@ char* get_in_reply_to(mastodont_t* api,
&acct,
&storage);
char* html = construct_in_reply_to(status, res == 0 ? &acct : NULL, size);
char* html = "TODO";
// char* html = construct_in_reply_to(status, res == 0 ? &acct : NULL, size);
if (res == 0) mstdnt_cleanup_account(&acct);
mastodont_storage_cleanup(&storage);
return html;
}
char* construct_in_reply_to(struct mstdnt_status* status,
struct mstdnt_account* account,
size_t* size)
{
struct in_reply_to_template tdata = {
.prefix = config_url_prefix,
.in_reply_to_text = L10N[L10N_EN_US][L10N_IN_REPLY_TO],
.acct = account ? account->acct : status->in_reply_to_id,
.status_id = status->in_reply_to_id
};
return tmpl_gen_in_reply_to(&tdata, size);
}
#define REGEX_GREENTEXT "((?:^|<br/?>|\\s)&gt;.*?)(?:<br/?>|$)"
char* reformat_status(struct session* ssn,
char* content,
struct mstdnt_emoji* emos,
size_t emos_len)
{
if (!content) return NULL;
char* res = make_mentions_local(content);
char* gt_res, *emo_res;
if (emos)
{
emo_res = emojify(res, emos, emos_len);
if (emo_res != res && res != content)
free(res);
res = emo_res;
}
if (ssn->config.stat_greentexts)
{
gt_res = greentextify(res);
if (gt_res != res && res != content)
free(res);
res = gt_res;
}
return res;
}
#define REGEX_MENTION "(?=<a .*?mention.*?)<a .*?href=\"https?:\\/\\/(?<url>.*?)\\/(?:@|users\\/)?(?<>.*?)?\".*?>"
char* make_mentions_local(char* content)
{
char* url_format;
int error;
PCRE2_SIZE erroffset;
int substitute_success = 0;
// Initial size, will be increased by 30% if pcre2_substitute cannot fit into the size
// ...why can't pcre2 just allocate a string with the size for us? Thanks...
size_t res_len = 1024;
char* res = malloc(res_len);
pcre2_code* re = pcre2_compile((PCRE2_SPTR)REGEX_MENTION,
PCRE2_ZERO_TERMINATED, PCRE2_MULTILINE,
&error, &erroffset, NULL);
if (re == NULL)
{
fprintf(stderr, "Couldn't parse regex at offset %d: %s\n", error, REGEX_MENTION + erroffset);
pcre2_code_free(re);
return NULL;
}
int len = easprintf(&url_format,
"<a target=\"_parent\" class=\"mention\" href=\"http%s://%s/@$2@$1\">",
config_host_url_insecure ? "" : "s",
getenv("HTTP_HOST"));
int rc = -1;
PCRE2_SIZE res_len_str;
while (rc < 0)
{
res_len_str = res_len;
rc = pcre2_substitute(
re,
(PCRE2_SPTR)content,
PCRE2_ZERO_TERMINATED,
0,
PCRE2_SUBSTITUTE_EXTENDED | PCRE2_SUBSTITUTE_GLOBAL,
NULL,
NULL,
(PCRE2_SPTR)url_format,
len,
(PCRE2_UCHAR*)res,
&res_len_str
);
if (rc < 0)
{
switch (rc)
{
case PCRE2_ERROR_NOMEMORY:
// Increase by 30% and try again
res_len = (float)res_len + ((float)res_len * .3);
res = realloc(res, res_len);
break;
default:
{
char buf[256];
pcre2_get_error_message(rc, buf, 256);
goto out;
}
}
}
else
substitute_success = 1;
}
out:
if (!substitute_success)
free(res);
free(url_format);
pcre2_code_free(re);
return substitute_success ? res : content;
}
char* greentextify(char* content)
{
if (!content) return NULL;
int error;
PCRE2_SIZE erroffset;
int rc;
int gt_off;
int gt_len;
char* res = content;
// Malloc'd strings
char* reg_string;
char* gt_string;
char* oldres = NULL;
PCRE2_SIZE* re_results;
pcre2_code* re = pcre2_compile((PCRE2_SPTR)REGEX_GREENTEXT, PCRE2_ZERO_TERMINATED, 0, &error, &erroffset, NULL);
pcre2_match_data* re_data;
if (re == NULL)
{
fprintf(stderr, "Couldn't parse regex at offset %ld: %d\n", erroffset, error);
pcre2_code_free(re);
return res;
}
re_data = pcre2_match_data_create_from_pattern(re, NULL);
for (int ind = 0;;)
{
rc = pcre2_match(re, (PCRE2_SPTR)res, strlen(res), ind, 0, re_data, NULL);
if (rc < 0)
break;
re_results = pcre2_get_ovector_pointer(re_data);
// Store to last result
gt_off = re_results[2];
gt_len = re_results[3] - gt_off;
oldres = res;
// Malloc find/repl strings
reg_string = malloc(gt_len + 1);
strncpy(reg_string, res + gt_off, gt_len);
reg_string[gt_len] = '\0';
easprintf(&gt_string, "<span class=\"greentext\">%s</span>", reg_string);
res = strrepl(res, reg_string, gt_string, STRREPL_ALL );
if (oldres != content) free(oldres);
ind = re_results[2] + strlen(gt_string);
free(reg_string);
free(gt_string);
}
pcre2_match_data_free(re_data);
pcre2_code_free(re);
return res;
}
char* construct_status(struct session* ssn,
mastodont_t* api,
struct mstdnt_status* local_status,
size_t* size,
struct mstdnt_notification* local_notif,
struct construct_statuses_args* args,
uint8_t flags)
{
struct mstdnt_args m_args;
set_mstdnt_args(&m_args, ssn);
char* stat_html;
// Counts
char* formatted_display_name = NULL;
char* attachments = NULL;
char* emoji_reactions = NULL;
char* serialized_display_name = NULL;
char* interaction_btns = NULL;
char* notif_info = NULL;
char* post_response = NULL;
char* in_reply_to_str = NULL;
char* delete_status = NULL;
char* pin_status = NULL;
char* interactions_html = NULL;
enum l10n_locale locale = l10n_normalize(ssn->config.lang);
struct mstdnt_status* status = local_status;
// Create a "fake" notification header which contains information for
// the reblogged status
struct mstdnt_notification notif_reblog;
struct mstdnt_notification* notif = local_notif;
struct mstdnt_account* favourites = NULL;
struct mstdnt_account* reblogs = NULL;
struct mstdnt_storage favourites_storage = { 0 };
struct mstdnt_storage reblogs_storage = { 0 };
size_t favourites_len = 0;
size_t reblogs_len = 0;
if (!status) return NULL;
// If focused, show status interactions
if ((flags & STATUS_FOCUSED) == STATUS_FOCUSED &&
(status->reblogs_count || status->favourites_count))
{
if (status->favourites_count)
mastodont_status_favourited_by(api,
&m_args,
status->id,
&favourites_storage,
&favourites,
&favourites_len);
if (status->reblogs_count)
mastodont_status_reblogged_by(api,
&m_args,
status->id,
&reblogs_storage,
&reblogs,
&reblogs_len);
interactions_html = construct_status_interactions(status->id,
status->favourites_count,
status->reblogs_count,
favourites,
favourites_len,
reblogs,
reblogs_len,
NULL);
mastodont_storage_cleanup(&reblogs_storage);
mastodont_storage_cleanup(&favourites_storage);
mstdnt_cleanup_accounts(favourites, favourites_len);
mstdnt_cleanup_accounts(reblogs, reblogs_len);
}
// Repoint value if it's a reblog
if (status->reblog)
{
status = status->reblog;
// Point to our account
notif_reblog.account = &(local_status->account);
notif_reblog.type = MSTDNT_NOTIFICATION_REBLOG;
notif = &notif_reblog;
}
// Format username with emojis
serialized_display_name = sanitize_html(status->account.display_name);
formatted_display_name = emojify(serialized_display_name,
status->account.emojis,
status->account.emojis_len);
// Format status
char* parse_content = reformat_status(ssn, status->content, status->emojis, status->emojis_len);
interaction_btns = construct_interaction_buttons(ssn, status, NULL, flags);
// Find and replace
if (args && args->highlight_word && parse_content != status->content)
{
char* parse_content_tmp;
char* repl_str = NULL;
easprintf(&repl_str, "<span class=\"search-highlight\">%s</span>", args->highlight_word);
parse_content_tmp = parse_content;
parse_content = strrepl(parse_content, args->highlight_word, repl_str, STRREPL_ALL);
// Check if the old parse_content needed to be free'd
if (parse_content_tmp != status->content &&
parse_content != parse_content_tmp)
free(parse_content_tmp);
else // No results, move back
parse_content = parse_content_tmp;
free(repl_str);
}
if (ssn->logged_in)
post_response = reply_status(ssn, status->in_reply_to_account_id , status);
// Delete status menu item and pinned, logged in only
if (ssn->logged_in && strcmp(status->account.acct, ssn->acct.acct) == 0)
{
struct menu_item_template mdata = {
.prefix = config_url_prefix,
.status_id = status->id,
.itype = "delete",
.text = "Delete status"
};
delete_status = tmpl_gen_menu_item(&mdata, NULL);
mdata.itype = status->pinned ? "unpin" : "pin";
mdata.text = status->pinned ? "Unpin status" : "Pin status";
pin_status = tmpl_gen_menu_item(&mdata, NULL);
}
if (status->media_attachments_len)
attachments = construct_attachments(ssn, status->sensitive, status->media_attachments, status->media_attachments_len, NULL);
if (status->pleroma.emoji_reactions_len)
emoji_reactions = construct_emoji_reactions(status->id, status->pleroma.emoji_reactions, status->pleroma.emoji_reactions_len, NULL);
if (notif && notif->type != MSTDNT_NOTIFICATION_MENTION)
{
char* notif_serialized_name = sanitize_html(notif->account->display_name);
char* notif_display_name = emojify(notif_serialized_name,
notif->account->emojis,
notif->account->emojis_len);
struct notification_template tdata = {
.avatar = notif->account->avatar,
.username = notif_display_name,
.action = (local_status->reblog ? notification_type_compact_str(notif->type) : notification_type_str(notif->type)),
.action_item = notification_type_svg(notif->type),
};
notif_info = tmpl_gen_notification(&tdata, NULL);
if (notif_display_name != notif->account->display_name)
free(notif_display_name);
if (notif_serialized_name != notif_display_name &&
notif_serialized_name != notif->account->display_name)
free(notif_serialized_name);
}
if (status->in_reply_to_id && status->in_reply_to_account_id)
in_reply_to_str = get_in_reply_to(api, ssn, status, NULL);
struct status_template tmpl = {
.status_id = status->id,
.notif_info = notif_info,
.thread_hidden = status->muted ? "checked" : "",
// TODO doesn't even need to be a hashtag, this is a temporary hack
.is_cat = status->account.note && strstr(status->account.note, "isCat") ? "is-cat" : NULL,
.is_bun = status->account.note && strstr(status->account.note, "isBun") ? " is-bun" : NULL,
.avatar = status->account.avatar,
.username = formatted_display_name,
.prefix = config_url_prefix,
.acct = status->account.acct,
.visibility = status_visibility_str(locale, status->visibility),
.unmute = status->muted ? "un" : "",
.unmute_btn = status->muted ? "Unmute thread" : "Mute thread",
.unbookmark = status->bookmarked ? "un" : "",
.unbookmark_btn = status->bookmarked ? "Remove Bookmark" : "Bookmark",
.delete_status = delete_status,
.pin_status = pin_status,
.in_reply_to_str = in_reply_to_str,
.status_content = parse_content,
.attachments = attachments,
.interactions = interactions_html,
.emoji_reactions = emoji_reactions,
.interaction_btns = interaction_btns,
.reply = post_response,
};
stat_html = tmpl_gen_status(&tmpl, size);
// Cleanup
if (formatted_display_name != status->account.display_name &&
formatted_display_name != serialized_display_name)
free(formatted_display_name);
if (serialized_display_name != status->account.display_name)
free(serialized_display_name);
free(in_reply_to_str);
free(attachments);
free(post_response);
free(emoji_reactions);
if (notif) free(notif_info);
free(delete_status);
free(pin_status);
free(interactions_html);
if (parse_content != status->content)
free(parse_content);
return stat_html;
}
static char* construct_status_voidwrap(void* passed, size_t index, size_t* res)
{
struct status_args* args = passed;
return construct_status(args->ssn, args->api, args->status + index, res, NULL, args->args, 0);
}
char* construct_statuses(struct session* ssn,
mastodont_t* api,
struct mstdnt_status* statuses,
size_t size,
struct construct_statuses_args* args,
size_t* ret_size)
{
if (!(statuses && size)) return NULL;
struct status_args stat_args = {
.api = api,
.status = statuses,
.args = args,
.ssn = ssn,
};
return construct_func_strings(construct_status_voidwrap, &stat_args, size, ret_size);
}
void status_interact(PATH_ARGS)
{
char* referer = GET_ENV("HTTP_REFERER", req);

View File

@ -53,64 +53,17 @@ void content_status_create(PATH_ARGS);
void content_status_react(PATH_ARGS);
// HTML Builders
char* construct_status(struct session* ssn,
mastodont_t* api,
struct mstdnt_status* status,
size_t* size,
struct mstdnt_notification* notif,
struct construct_statuses_args* args,
uint8_t flags);
char* construct_statuses(struct session* ssn,
mastodont_t* api,
struct mstdnt_status* statuses,
size_t size,
struct construct_statuses_args* args,
size_t* ret_size);
char* construct_interaction_buttons(struct session* ssn,
struct mstdnt_status* status,
size_t* size,
uint8_t flags);
// Reply to
/** Deprecated: May be used in the future for Mastodon only */
char* get_in_reply_to(mastodont_t* api,
struct session* ssn,
struct mstdnt_status* status,
size_t* size);
char* construct_in_reply_to(struct mstdnt_status* status,
struct mstdnt_account* account,
size_t* size);
char* construct_status_interactions(char* status_id,
int fav_count,
int reblog_count,
struct mstdnt_account* fav_accounts,
size_t fav_accounts_len,
struct mstdnt_account* reblog_accounts,
size_t reblog_accounts_len,
size_t* size);
char* construct_status_interaction_profiles(struct mstdnt_account* reblogs,
struct mstdnt_account* favourites,
size_t reblogs_len,
size_t favourites_len,
size_t* ret_size);
char* construct_status_interaction_profile(struct interact_profile_args* args, size_t index, size_t* size);
char* construct_status_interactions_label(char* status_id,
int is_favourites,
char* header,
int val,
size_t* size);
char* reformat_status(struct session* ssn,
char* content,
struct mstdnt_emoji* emos,
size_t emos_len);
char* greentextify(char* content);
char* make_mentions_local(char* content);
void status_view_reblogs(PATH_ARGS);
void status_view_favourites(PATH_ARGS);
const char* status_visibility_str(enum l10n_locale locale, enum mstdnt_visibility_type visibility);
void content_status_interactions(FCGX_Request* req,
struct session* ssn,
mastodont_t* api,

View File

@ -26,15 +26,10 @@
#include "index.h"
#include "status.h"
#include "easprintf.h"
#include "reply.h"
#include "navigation.h"
#include "query.h"
#include "error.h"
#include "string_helpers.h"
#include "../static/timeline_options.ctmpl"
#include "../static/navigation.ctmpl"
void content_timeline(FCGX_Request* req,
struct session* ssn,
mastodont_t* api,

View File

@ -1,67 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "type_string.h"
// Icons
#include "../static/like_svg.ctmpl"
#include "../static/repeat_svg.ctmpl"
#include "../static/follow_svg.ctmpl"
const char* notification_type_str(mstdnt_notification_t type)
{
switch (type)
{
case MSTDNT_NOTIFICATION_FOLLOW: return L10N[L10N_EN_US][L10N_NOTIF_FOLLOW];
case MSTDNT_NOTIFICATION_FOLLOW_REQUEST: return L10N[L10N_EN_US][L10N_NOTIF_FOLLOW_REQUEST];
case MSTDNT_NOTIFICATION_REBLOG: return L10N[L10N_EN_US][L10N_NOTIF_REPEATED];
case MSTDNT_NOTIFICATION_FAVOURITE: return L10N[L10N_EN_US][L10N_NOTIF_LIKED];
case MSTDNT_NOTIFICATION_POLL: return L10N[L10N_EN_US][L10N_NOTIF_POLL];
case MSTDNT_NOTIFICATION_EMOJI_REACT: return L10N[L10N_EN_US][L10N_NOTIF_REACTED_WITH];
default: return "";
}
}
const char* notification_type_compact_str(mstdnt_notification_t type)
{
switch (type)
{
case MSTDNT_NOTIFICATION_FOLLOW: return L10N[L10N_EN_US][L10N_NOTIF_COMPACT_FOLLOW];
case MSTDNT_NOTIFICATION_FOLLOW_REQUEST: return L10N[L10N_EN_US][L10N_NOTIF_COMPACT_FOLLOW_REQUEST];
case MSTDNT_NOTIFICATION_REBLOG: return L10N[L10N_EN_US][L10N_NOTIF_COMPACT_REPEATED];
case MSTDNT_NOTIFICATION_FAVOURITE: return L10N[L10N_EN_US][L10N_NOTIF_COMPACT_LIKED];
case MSTDNT_NOTIFICATION_POLL: return L10N[L10N_EN_US][L10N_NOTIF_COMPACT_POLL];
case MSTDNT_NOTIFICATION_EMOJI_REACT: return L10N[L10N_EN_US][L10N_NOTIF_COMPACT_REACTED_WITH];
default: return "";
}
}
const char* notification_type_svg(mstdnt_notification_t type)
{
switch (type)
{
case MSTDNT_NOTIFICATION_FOLLOW: return data_follow_svg;
case MSTDNT_NOTIFICATION_FOLLOW_REQUEST: return "";
case MSTDNT_NOTIFICATION_REBLOG: return data_repeat_svg;
case MSTDNT_NOTIFICATION_FAVOURITE: return data_like_svg;
case MSTDNT_NOTIFICATION_POLL: return "";
case MSTDNT_NOTIFICATION_EMOJI_REACT: return "";
default: return "";
}
}

View File

@ -1,28 +0,0 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef TYPE_STRING_H
#define TYPE_STRING_H
#include <mastodont.h>
#include "l10n.h"
const char* notification_type_svg(mstdnt_notification_t type);
const char* notification_type_str(mstdnt_notification_t type);
const char* notification_type_compact_str(mstdnt_notification_t type);
#endif // TYPE_STRING_H