diff --git a/perl/timeline.pm b/perl/timeline.pm new file mode 100644 index 0000000..ad088cd --- /dev/null +++ b/perl/timeline.pm @@ -0,0 +1,24 @@ +package timeline; +use strict; +use warnings; +use Exporter 'import'; + +our @EXPORT = qw( generate_attachment ); + +use template_helpers 'to_template'; +use icons 'get_icon'; + +sub content_timeline +{ + my ($ssn, $data, $statuses, $title, $show_post_box) = @_; + + my %vars = ( + prefix => '', + ssn => $ssn, + statuses => $statuses, + title => $title, + post_box => $show_post_box, + ); + + to_template(\&vars, \&data->{'attachment.tt'}); +} diff --git a/src/global_perl.h b/src/global_perl.h index 78e501b..bbe8a8a 100644 --- a/src/global_perl.h +++ b/src/global_perl.h @@ -32,8 +32,10 @@ static PerlInterpreter* perl; extern HV* template_files; extern pthread_mutex_t perl_mutex; -#define perl_lock() if(1) { pthread_mutex_lock(&perl_mutex); } -#define perl_unlock() if(1) { pthread_mutex_unlock(&perl_mutex); } +#define perl_lock() do { pthread_mutex_lock(&perl_mutex); } while (1) +#define perl_unlock() do { pthread_mutex_unlock(&perl_mutex); } while (1) + +#define ARG_UNDEFINED() do { XPUSHs(&PL_sv_undef); } while (1) void init_template_files(); void cleanup_template_files(); diff --git a/src/status.c b/src/status.c index e93ead7..fb1998e 100644 --- a/src/status.c +++ b/src/status.c @@ -948,15 +948,15 @@ void content_status(PATH_ARGS, uint8_t flags) PUSHMARK(SP); HV* session_hv = perlify_session(ssn); XPUSHs(newRV_inc((SV*)session_hv)); - XPUSHs(newRV_inc((SV*)template_files)); - XPUSHs(newRV_inc((SV*)perlify_status(&status))); + XPUSHs(newRV_noinc((SV*)template_files)); + XPUSHs(newRV_noinc((SV*)perlify_status(&status))); if (statuses_before) - XPUSHs(newRV_inc((AV*)perlify_statuses(statuses_before, stat_before_len))); + XPUSHs(newRV_noinc((AV*)perlify_statuses(statuses_before, stat_before_len))); else XPUSHs(&PL_sv_undef); if (statuses_after) - XPUSHs(newRV_inc((AV*)perlify_statuses(statuses_after, stat_after_len))); + XPUSHs(newRV_noinc((AV*)perlify_statuses(statuses_after, stat_after_len))); else XPUSHs(&PL_sv_undef); // ARGS diff --git a/src/timeline.c b/src/timeline.c index 445523f..0962d86 100644 --- a/src/timeline.c +++ b/src/timeline.c @@ -30,6 +30,7 @@ #include "query.h" #include "error.h" #include "string_helpers.h" +#include "perl_global.h" #include "../static/timeline_options.ctmpl" #include "../static/navigation.ctmpl" @@ -44,65 +45,41 @@ void content_timeline(FCGX_Request* req, char* header_text, int show_post_box) { - size_t statuses_html_count = 0; - char* status_format = NULL, - * header = NULL, - * post_box = NULL, - * navigation_box = NULL, - * timeline_options, - * output = NULL, - * start_id; - - if (storage->error) - status_format = construct_error(storage->error, E_ERROR, 1, NULL); - else - { - // Construct statuses into HTML - status_format = construct_statuses(ssn, api, statuses, statuses_len, NULL, &statuses_html_count); - if (!status_format) - status_format = construct_error("No statuses", E_NOTICE, 1, NULL); - } - - // Create post box - if (show_post_box) - post_box = construct_post_box(NULL, "", NULL); - - if (statuses) - { - // If not set, set it - start_id = keystr(ssn->post.start_id) ? keystr(ssn->post.start_id) : statuses[0].id; - navigation_box = construct_navigation_box(start_id, - statuses[0].id, - statuses[statuses_len-1].id, - NULL); - } - - // Create timeline options/menubar - struct timeline_options_template todata = { - .only_media = "Only media?", - .replies = "Replies?", - .only_media_active = keyint(ssn->post.only_media) ? "checked" : NULL, - }; - - timeline_options = tmpl_gen_timeline_options(&todata, NULL); - - // Display a header bar, usually customized for specific pages - if (header_text) - { - easprintf(&header, "

%s

", - header_text); - } + perl_lock(); + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + HV* session_hv = perlify_session(ssn); + XPUSHs(newRV_noinc((SV*)session_hv)); + XPUSHs(newRV_noinc((SV*)template_files)); - easprintf(&output, "%s%s%s%s%s", - STR_NULL_EMPTY(header), - STR_NULL_EMPTY(post_box), - STR_NULL_EMPTY(timeline_options), - STR_NULL_EMPTY(status_format), - STR_NULL_EMPTY(navigation_box)); + if (statuses) + XPUSHs(newRV_noinc((AV*)perlify_statuses(statuses, statuses_len))); + else ARG_UNDEFINED(); + if (title) + XPUSHs(newSVpv(header_text, 0)); + else ARG_UNDEFINED(); + + XPUSHi(show_post_box); + + PUTBACK; + call_pv("status::content_timeline", G_SCALAR); + SPAGAIN; + + // Duplicate to free temps + char* dup = savesharedsvpv(POPs); + + PUTBACK; + FREETMPS; + LEAVE; + perl_unlock(); + struct base_page b = { .category = cat, .content = output, + .session = session_hv, .sidebar_left = NULL }; @@ -112,12 +89,7 @@ void content_timeline(FCGX_Request* req, // Cleanup mastodont_storage_cleanup(storage); mstdnt_cleanup_statuses(statuses, statuses_len); - free(status_format); - free(post_box); - free(header); - free(timeline_options); - free(navigation_box); - free(output); + Safefree(dup); } void tl_home(FCGX_Request* req, struct session* ssn, mastodont_t* api, int local) diff --git a/src/timeline.h b/src/timeline.h index c2cfcd3..ae20632 100644 --- a/src/timeline.h +++ b/src/timeline.h @@ -26,19 +26,58 @@ #include "session.h" #include "base_page.h" -// Federated and local are here +/** Wrapper for content_tl_federated */ void tl_home(FCGX_Request* req, struct session* ssn, mastodont_t* api, int local); + +/** Wrapper for content_tl_direct */ void tl_direct(FCGX_Request* req, struct session* ssn, mastodont_t* api); + +/** Wrapper for content_tl_federated */ void tl_public(FCGX_Request* req, struct session* ssn, mastodont_t* api, int local, enum base_category cat); + +/** Wrapper for content_tl_list */ void tl_list(FCGX_Request* req, struct session* ssn, mastodont_t* api, char* list_id); + +/** Wrapper for content_tl_tag */ void tl_tag(FCGX_Request* req, struct session* ssn, mastodont_t* api, char* tag); +/* ------------------------------------------------ */ + +/** Federated timeline */ void content_tl_federated(PATH_ARGS); + +/** Home timeline. Shows federated timeline if not logged in */ void content_tl_home(PATH_ARGS); + +/** Direct message timeline */ void content_tl_direct(PATH_ARGS); + +/** Local/instance timeline */ void content_tl_local(PATH_ARGS); + +/** List timeline */ void content_tl_list(PATH_ARGS); + +/** Hashtag timeline */ void content_tl_tag(PATH_ARGS); + +/** + * Used to create generic timeline content. This timeline includes other features + * such as viewing only media, hiding muted, etc. as options on the top of the + * timeline, so this should only be used for API's which are considered "timelines" + * to Pleroma/Mastodon. + * + * @param req This request + * @param ssn This session + * @param api The api + * @param storage The storage for statuses, will be cleaned up in this function, do NOT + * cleanup yourself. + * @param statuses The statuses, will be cleaned up in this function, do NOT cleanup yourself. + * @param statuses_len Length of `statuses` + * @param cat The category to "highlight" on the sidebar + * @param header A header that is displayed above the timeline. + * @param show_post_box If the post box should be shown or not. + */ void content_timeline(FCGX_Request* req, struct session* ssn, mastodont_t* api,