diff --git a/application.fam b/application.fam index 70437bc5e58..cc1287361be 100644 --- a/application.fam +++ b/application.fam @@ -15,7 +15,7 @@ App( ], stack_size=2 * 1024, order=20, - fap_version="4.02", + fap_version="4.03", fap_author="Alexander Kopachov (@akopachov)", fap_description="Software-based TOTP authenticator for Flipper Zero device", fap_weburl="https://github.com/akopachov/flipper-zero_authenticator", diff --git a/cli/cli.c b/cli/cli.c index 4cb68ce8320..a556c31acfa 100644 --- a/cli/cli.c +++ b/cli/cli.c @@ -47,7 +47,7 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) { } else if( furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_LIST) == 0 || furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_LIST_ALT) == 0) { - totp_cli_command_list_handle(plugin_state, cli); + totp_cli_command_list_handle(plugin_state, args, cli); } else if( furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_DELETE) == 0 || furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_DELETE_ALT) == 0) { diff --git a/cli/commands/details/details.c b/cli/commands/details/details.c index 7e714bf6995..cc4c9eeff74 100644 --- a/cli/commands/details/details.c +++ b/cli/commands/details/details.c @@ -7,33 +7,68 @@ #include "../../../ui/scene_director.h" #include "../../cli_helpers.h" #include "../../common_command_arguments.h" +#include "formatters/table/details_output_formatter_table.h" +#include "formatters/tsv/details_output_formatter_tsv.h" -#define TOTP_CLI_PRINTF_AUTOMATION_FEATURE(description, header_printed) \ - do { \ - TOTP_CLI_PRINTF( \ - "| %-20s | %-28.28s |\r\n", \ - header_printed ? "" : "Automation features", \ - description); \ - header_printed = true; \ - } while(false) +typedef void (*TOTP_CLI_DETAILS_HEADER_FORMATTER)(); +typedef void (*TOTP_CLI_DETAILS_FOOTER_FORMATTER)(); +typedef void (*TOTP_CLI_DETAILS_AUTOMATION_FEATURE_ITEM_FORMATTER)( + const char* key, + const char* feature, + bool* header_printed); +typedef void (*TOTP_CLI_DETAILS_CSTR_FORMATTER)(const char* key, const char* value); +typedef void (*TOTP_CLI_DETAILS_UINT8T_FORMATTER)(const char* key, uint8_t value); +typedef void (*TOTP_CLI_DETAILS_SIZET_FORMATTER)(const char* key, size_t value); -static void print_automation_features(const TokenInfo* token_info) { +typedef struct { + const TOTP_CLI_DETAILS_HEADER_FORMATTER header_formatter; + const TOTP_CLI_DETAILS_FOOTER_FORMATTER footer_formatter; + const TOTP_CLI_DETAILS_AUTOMATION_FEATURE_ITEM_FORMATTER automation_feature_item_formatter; + const TOTP_CLI_DETAILS_CSTR_FORMATTER cstr_formatter; + const TOTP_CLI_DETAILS_UINT8T_FORMATTER uint8t_formatter; + const TOTP_CLI_DETAILS_SIZET_FORMATTER sizet_formatter; +} TotpCliDetailsFormatter; + +static const TotpCliDetailsFormatter available_formatters[] = { + {.header_formatter = &details_output_formatter_print_header_table, + .footer_formatter = &details_output_formatter_print_footer_table, + .automation_feature_item_formatter = &details_output_formatter_print_automation_feature_table, + .cstr_formatter = &details_output_formatter_print_cstr_table, + .uint8t_formatter = &details_output_formatter_print_uint8t_table, + .sizet_formatter = &details_output_formatter_print_sizet_table}, + + {.header_formatter = &details_output_formatter_print_header_tsv, + .footer_formatter = &details_output_formatter_print_footer_tsv, + .automation_feature_item_formatter = &details_output_formatter_print_automation_feature_tsv, + .cstr_formatter = &details_output_formatter_print_cstr_tsv, + .uint8t_formatter = &details_output_formatter_print_uint8t_tsv, + .sizet_formatter = &details_output_formatter_print_sizet_tsv}, +}; + +static void print_automation_features( + const TokenInfo* token_info, + const TotpCliDetailsFormatter* formatter) { + bool header_printed = false; + const char* AUTOMATION_FEATURES_PRINT_KEY = "Automation features"; if(token_info->automation_features == TokenAutomationFeatureNone) { - TOTP_CLI_PRINTF("| %-20s | %-28.28s |\r\n", "Automation features", "None"); + (*formatter->automation_feature_item_formatter)( + AUTOMATION_FEATURES_PRINT_KEY, "None", &header_printed); return; } - bool header_printed = false; if(token_info->automation_features & TokenAutomationFeatureEnterAtTheEnd) { - TOTP_CLI_PRINTF_AUTOMATION_FEATURE("Type key at the end", header_printed); + (*formatter->automation_feature_item_formatter)( + AUTOMATION_FEATURES_PRINT_KEY, "Type key at the end", &header_printed); } if(token_info->automation_features & TokenAutomationFeatureTabAtTheEnd) { - TOTP_CLI_PRINTF_AUTOMATION_FEATURE("Type key at the end", header_printed); + (*formatter->automation_feature_item_formatter)( + AUTOMATION_FEATURES_PRINT_KEY, "Type key at the end", &header_printed); } if(token_info->automation_features & TokenAutomationFeatureTypeSlower) { - TOTP_CLI_PRINTF_AUTOMATION_FEATURE("Type slower", header_printed); + (*formatter->automation_feature_item_formatter)( + AUTOMATION_FEATURES_PRINT_KEY, "Type slower", &header_printed); } } @@ -64,6 +99,14 @@ void totp_cli_command_details_handle(PluginState* plugin_state, FuriString* args return; } + const TotpCliDetailsFormatter* formatter = &available_formatters[0]; + FuriString* arg = furi_string_alloc(); + if(args_read_string_and_trim(args, arg) && furi_string_cmpi_str(arg, "--tsv") == 0) { + formatter = &available_formatters[1]; + } + + furi_string_free(arg); + TOTP_CLI_LOCK_UI(plugin_state); size_t original_token_index = @@ -71,19 +114,14 @@ void totp_cli_command_details_handle(PluginState* plugin_state, FuriString* args if(totp_token_info_iterator_go_to(iterator_context, token_number - 1)) { const TokenInfo* token_info = totp_token_info_iterator_get_current_token(iterator_context); - TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n"); - TOTP_CLI_PRINTF("| %-20s | %-28s |\r\n", "Property", "Value"); - TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n"); - TOTP_CLI_PRINTF("| %-20s | %-28d |\r\n", "Index", token_number); - TOTP_CLI_PRINTF( - "| %-20s | %-28.28s |\r\n", "Name", furi_string_get_cstr(token_info->name)); - TOTP_CLI_PRINTF( - "| %-20s | %-28s |\r\n", "Hashing algorithm", token_info_get_algo_as_cstr(token_info)); - TOTP_CLI_PRINTF("| %-20s | %-28" PRIu8 " |\r\n", "Number of digits", token_info->digits); - TOTP_CLI_PRINTF( - "| %-20s | %" PRIu8 " sec.%-21s |\r\n", "Token lifetime", token_info->duration, " "); - print_automation_features(token_info); - TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n"); + (*formatter->header_formatter)(); + (*formatter->sizet_formatter)("Index", token_number); + (*formatter->cstr_formatter)("Name", furi_string_get_cstr(token_info->name)); + (*formatter->cstr_formatter)("Hashing algorithm", token_info_get_algo_as_cstr(token_info)); + (*formatter->uint8t_formatter)("Number of digits", token_info->digits); + (*formatter->uint8t_formatter)("Token lifetime", token_info->duration); + print_automation_features(token_info, formatter); + (*formatter->footer_formatter)(); } else { totp_cli_print_error_loading_token_info(); } diff --git a/cli/commands/details/formatters/table/details_output_formatter_table.c b/cli/commands/details/formatters/table/details_output_formatter_table.c new file mode 100644 index 00000000000..44290db6967 --- /dev/null +++ b/cli/commands/details/formatters/table/details_output_formatter_table.c @@ -0,0 +1,32 @@ +#include "details_output_formatter_table.h" +#include "../../../../cli_helpers.h" + +void details_output_formatter_print_header_table() { + TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n"); + TOTP_CLI_PRINTF("| %-20s | %-28s |\r\n", "Property", "Value"); + TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n"); +} + +void details_output_formatter_print_footer_table() { + TOTP_CLI_PRINTF("+----------------------+------------------------------+\r\n"); +} + +void details_output_formatter_print_automation_feature_table( + const char* key, + const char* feature, + bool* header_printed) { + TOTP_CLI_PRINTF("| %-20s | %-28.28s |\r\n", *header_printed ? "" : key, feature); + *header_printed = true; +} + +void details_output_formatter_print_cstr_table(const char* key, const char* value) { + TOTP_CLI_PRINTF("| %-20s | %-28.28s |\r\n", key, value); +} + +void details_output_formatter_print_uint8t_table(const char* key, uint8_t value) { + TOTP_CLI_PRINTF("| %-20s | %-28" PRIu8 " |\r\n", key, value); +} + +void details_output_formatter_print_sizet_table(const char* key, size_t value) { + TOTP_CLI_PRINTF("| %-20s | %-28" PRIu16 " |\r\n", key, value); +} diff --git a/cli/commands/details/formatters/table/details_output_formatter_table.h b/cli/commands/details/formatters/table/details_output_formatter_table.h new file mode 100644 index 00000000000..bdb6bf115bf --- /dev/null +++ b/cli/commands/details/formatters/table/details_output_formatter_table.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include + +void details_output_formatter_print_header_table(); +void details_output_formatter_print_footer_table(); +void details_output_formatter_print_automation_feature_table( + const char* key, + const char* feature, + bool* header_printed); +void details_output_formatter_print_cstr_table(const char* key, const char* value); +void details_output_formatter_print_uint8t_table(const char* key, uint8_t value); +void details_output_formatter_print_sizet_table(const char* key, size_t value); diff --git a/cli/commands/details/formatters/tsv/details_output_formatter_tsv.c b/cli/commands/details/formatters/tsv/details_output_formatter_tsv.c new file mode 100644 index 00000000000..39e61342c82 --- /dev/null +++ b/cli/commands/details/formatters/tsv/details_output_formatter_tsv.c @@ -0,0 +1,29 @@ +#include "details_output_formatter_tsv.h" +#include "../../../../cli_helpers.h" + +void details_output_formatter_print_header_tsv() { + TOTP_CLI_PRINTF("%s\t%s\r\n", "Property", "Value"); +} + +void details_output_formatter_print_footer_tsv() { +} + +void details_output_formatter_print_automation_feature_tsv( + const char* key, + const char* feature, + bool* header_printed) { + TOTP_CLI_PRINTF("%s\t%s\r\n", *header_printed ? "" : key, feature); + *header_printed = true; +} + +void details_output_formatter_print_cstr_tsv(const char* key, const char* value) { + TOTP_CLI_PRINTF("%s\t%s\r\n", key, value); +} + +void details_output_formatter_print_uint8t_tsv(const char* key, uint8_t value) { + TOTP_CLI_PRINTF("%s\t%" PRIu8 "\r\n", key, value); +} + +void details_output_formatter_print_sizet_tsv(const char* key, size_t value) { + TOTP_CLI_PRINTF("%s\t%" PRIu16 "\r\n", key, value); +} diff --git a/cli/commands/details/formatters/tsv/details_output_formatter_tsv.h b/cli/commands/details/formatters/tsv/details_output_formatter_tsv.h new file mode 100644 index 00000000000..15b20ffcb34 --- /dev/null +++ b/cli/commands/details/formatters/tsv/details_output_formatter_tsv.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include + +void details_output_formatter_print_header_tsv(); +void details_output_formatter_print_footer_tsv(); +void details_output_formatter_print_automation_feature_tsv( + const char* key, + const char* feature, + bool* header_printed); +void details_output_formatter_print_cstr_tsv(const char* key, const char* value); +void details_output_formatter_print_uint8t_tsv(const char* key, uint8_t value); +void details_output_formatter_print_sizet_tsv(const char* key, size_t value); diff --git a/cli/commands/list/formatters/table/list_output_formatter_table.c b/cli/commands/list/formatters/table/list_output_formatter_table.c new file mode 100644 index 00000000000..8774a6edc46 --- /dev/null +++ b/cli/commands/list/formatters/table/list_output_formatter_table.c @@ -0,0 +1,22 @@ +#include "list_output_formatter_table.h" +#include "../../../../cli_helpers.h" + +void list_output_formatter_print_header_table() { + TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n"); + TOTP_CLI_PRINTF("| %-3s | %-25s | %-6s | %-s | %-s |\r\n", "#", "Name", "Algo", "Ln", "Dur"); + TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n"); +} + +void list_output_formatter_print_body_item_table(size_t index, const TokenInfo* token_info) { + TOTP_CLI_PRINTF( + "| %-3" PRIu16 " | %-25.25s | %-6s | %-2" PRIu8 " | %-3" PRIu8 " |\r\n", + index + 1, + furi_string_get_cstr(token_info->name), + token_info_get_algo_as_cstr(token_info), + token_info->digits, + token_info->duration); +} + +void list_output_formatter_print_footer_table() { + TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n"); +} \ No newline at end of file diff --git a/cli/commands/list/formatters/table/list_output_formatter_table.h b/cli/commands/list/formatters/table/list_output_formatter_table.h new file mode 100644 index 00000000000..e2ed9c4dcb7 --- /dev/null +++ b/cli/commands/list/formatters/table/list_output_formatter_table.h @@ -0,0 +1,9 @@ +#pragma once + +#include "../../../../../types/token_info.h" + +void list_output_formatter_print_header_table(); + +void list_output_formatter_print_body_item_table(size_t index, const TokenInfo* token_info); + +void list_output_formatter_print_footer_table(); \ No newline at end of file diff --git a/cli/commands/list/formatters/tsv/list_output_formatter_tsv.c b/cli/commands/list/formatters/tsv/list_output_formatter_tsv.c new file mode 100644 index 00000000000..2bd4553973d --- /dev/null +++ b/cli/commands/list/formatters/tsv/list_output_formatter_tsv.c @@ -0,0 +1,19 @@ +#include "list_output_formatter_tsv.h" +#include "../../../../cli_helpers.h" + +void list_output_formatter_print_header_tsv() { + TOTP_CLI_PRINTF("%s\t%s\t%s\t%s\t%s\r\n", "#", "Name", "Algo", "Ln", "Dur"); +} + +void list_output_formatter_print_body_item_tsv(size_t index, const TokenInfo* token_info) { + TOTP_CLI_PRINTF( + "%" PRIu16 "\t%s\t%s\t%" PRIu8 "\t%" PRIu8 "\r\n", + index + 1, + furi_string_get_cstr(token_info->name), + token_info_get_algo_as_cstr(token_info), + token_info->digits, + token_info->duration); +} + +void list_output_formatter_print_footer_tsv() { +} \ No newline at end of file diff --git a/cli/commands/list/formatters/tsv/list_output_formatter_tsv.h b/cli/commands/list/formatters/tsv/list_output_formatter_tsv.h new file mode 100644 index 00000000000..e01c95d2e37 --- /dev/null +++ b/cli/commands/list/formatters/tsv/list_output_formatter_tsv.h @@ -0,0 +1,9 @@ +#pragma once + +#include "../../../../../types/token_info.h" + +void list_output_formatter_print_header_tsv(); + +void list_output_formatter_print_body_item_tsv(size_t index, const TokenInfo* token_info); + +void list_output_formatter_print_footer_tsv(); \ No newline at end of file diff --git a/cli/commands/list/list.c b/cli/commands/list/list.c index d5c97c6b06d..1c39f320387 100644 --- a/cli/commands/list/list.c +++ b/cli/commands/list/list.c @@ -1,10 +1,32 @@ #include "list.h" #include +#include #include "../../../types/token_info.h" #include "../../../services/config/constants.h" #include "../../../services/config/config.h" #include "../../../ui/scene_director.h" #include "../../cli_helpers.h" +#include "formatters/table/list_output_formatter_table.h" +#include "formatters/tsv/list_output_formatter_tsv.h" + +typedef void (*TOTP_CLI_LIST_HEADER_FORMATTER)(); +typedef void (*TOTP_CLI_LIST_FOOTER_FORMATTER)(); +typedef void (*TOTP_CLI_LIST_BODY_ITEM_FORMATTER)(size_t index, const TokenInfo* token_info); + +typedef struct { + const TOTP_CLI_LIST_HEADER_FORMATTER header_formatter; + const TOTP_CLI_LIST_FOOTER_FORMATTER footer_formatter; + const TOTP_CLI_LIST_BODY_ITEM_FORMATTER body_item_formatter; +} TotpCliListFormatter; + +static const TotpCliListFormatter available_formatters[] = { + {.header_formatter = &list_output_formatter_print_header_table, + .body_item_formatter = &list_output_formatter_print_body_item_table, + .footer_formatter = &list_output_formatter_print_footer_table}, + + {.header_formatter = &list_output_formatter_print_header_tsv, + .body_item_formatter = &list_output_formatter_print_body_item_tsv, + .footer_formatter = &list_output_formatter_print_footer_tsv}}; #ifdef TOTP_CLI_RICH_HELP_ENABLED void totp_cli_command_list_docopt_commands() { @@ -18,7 +40,7 @@ void totp_cli_command_list_docopt_usage() { } #endif -void totp_cli_command_list_handle(PluginState* plugin_state, Cli* cli) { +void totp_cli_command_list_handle(PluginState* plugin_state, FuriString* args, Cli* cli) { if(!totp_cli_ensure_authenticated(plugin_state, cli)) { return; } @@ -31,26 +53,26 @@ void totp_cli_command_list_handle(PluginState* plugin_state, Cli* cli) { return; } + const TotpCliListFormatter* formatter = &available_formatters[0]; + FuriString* arg = furi_string_alloc(); + if(args_read_string_and_trim(args, arg) && furi_string_cmpi_str(arg, "--tsv") == 0) { + formatter = &available_formatters[1]; + } + + furi_string_free(arg); + TOTP_CLI_LOCK_UI(plugin_state); size_t original_index = totp_token_info_iterator_get_current_token_index(iterator_context); - TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n"); - TOTP_CLI_PRINTF("| %-3s | %-25s | %-6s | %-s | %-s |\r\n", "#", "Name", "Algo", "Ln", "Dur"); - TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n"); + (*formatter->header_formatter)(); for(size_t i = 0; i < total_count; i++) { totp_token_info_iterator_go_to(iterator_context, i); const TokenInfo* token_info = totp_token_info_iterator_get_current_token(iterator_context); - TOTP_CLI_PRINTF( - "| %-3" PRIu16 " | %-25.25s | %-6s | %-2" PRIu8 " | %-3" PRIu8 " |\r\n", - i + 1, - furi_string_get_cstr(token_info->name), - token_info_get_algo_as_cstr(token_info), - token_info->digits, - token_info->duration); + (*formatter->body_item_formatter)(i, token_info); } - TOTP_CLI_PRINTF("+-----+---------------------------+--------+----+-----+\r\n"); + (*formatter->footer_formatter)(); totp_token_info_iterator_go_to(iterator_context, original_index); diff --git a/cli/commands/list/list.h b/cli/commands/list/list.h index 8237bfd2bdd..0527e8c5f36 100644 --- a/cli/commands/list/list.h +++ b/cli/commands/list/list.h @@ -7,7 +7,7 @@ #define TOTP_CLI_COMMAND_LIST "list" #define TOTP_CLI_COMMAND_LIST_ALT "ls" -void totp_cli_command_list_handle(PluginState* plugin_state, Cli* cli); +void totp_cli_command_list_handle(PluginState* plugin_state, FuriString* args, Cli* cli); #ifdef TOTP_CLI_RICH_HELP_ENABLED void totp_cli_command_list_docopt_commands(); void totp_cli_command_list_docopt_usage(); diff --git a/version.h b/version.h index 8b77b9cd39b..0b8597b0c08 100644 --- a/version.h +++ b/version.h @@ -2,4 +2,4 @@ #define TOTP_APP_VERSION_MAJOR (4) #define TOTP_APP_VERSION_MINOR (0) -#define TOTP_APP_VERSION_PATCH (1) \ No newline at end of file +#define TOTP_APP_VERSION_PATCH (3) \ No newline at end of file