diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 730169ba..8a8330dc 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2586,6 +2586,20 @@ static struct cmd_t command_defs[] = { CMD_NOEXAMPLES }, + { "/editor", + parse_args, 0, 0, NULL, + CMD_NOSUBFUNCS + CMD_MAINFUNC(cmd_editor) + CMD_TAGS( + CMD_TAG_CHAT) + CMD_SYN( + "/editor") + CMD_DESC( + "Call editor") + CMD_NOARGS + CMD_NOEXAMPLES + }, + // NEXT-COMMAND (search helper) }; @@ -2894,7 +2908,7 @@ command_mangen(void) GDateTime* now = g_date_time_new_now_local(); gchar* date = g_date_time_format(now, "%F"); - gchar *header = g_strdup_printf(".TH man 1 \"%s\" \"" PACKAGE_VERSION "\" \"Profanity XMPP client\"\n", date); + gchar* header = g_strdup_printf(".TH man 1 \"%s\" \"" PACKAGE_VERSION "\" \"Profanity XMPP client\"\n", date); if (!header) { log_error("command_mangen(): could not allocate memory"); return; diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 90c41dfd..fc38a2b0 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -52,6 +52,12 @@ #include #include +// fork / execl +#include +#include +#include +#include + #include "profanity.h" #include "log.h" #include "common.h" @@ -6861,7 +6867,7 @@ cmd_plugins_sourcepath(ProfWin* window, const char* const command, gchar** args) return TRUE; } - char *path = get_expanded_path(args[2]); + char* path = get_expanded_path(args[2]); if (!is_dir(path)) { cons_show("Plugins sourcepath must be a directory."); @@ -6882,7 +6888,7 @@ cmd_plugins_sourcepath(ProfWin* window, const char* const command, gchar** args) gboolean cmd_plugins_install(ProfWin* window, const char* const command, gchar** args) { - char *path; + char* path; if (args[1] == NULL) { char* sourcepath = prefs_get_string(PREF_PLUGINS_SOURCEPATH); @@ -9304,3 +9310,84 @@ cmd_change_password(ProfWin* window, const char* const command, gchar** args) return TRUE; } + +gboolean +cmd_editor(ProfWin* window, const char* const command, gchar** args) +{ + xmpp_ctx_t* const ctx = connection_get_ctx(); + if (!ctx) { + log_debug("Editor: no connection"); + return TRUE; + } + + // build temp file name. Example: /tmp/profanity-f2f271dd-98c8-4118-8d47-3bd49c8e2e63.txt + char* uuid = xmpp_uuid_gen(ctx); + char* filename = g_strdup_printf("%s%s%s.txt", g_get_tmp_dir(), "/profanity-", uuid); + if (uuid) { + xmpp_free(ctx, uuid); + } + + // Check if file exists and create file + if (g_file_test(filename, G_FILE_TEST_EXISTS)) { + cons_show("Editor: temp file exists already"); + return TRUE; + } + + GError* creation_error = NULL; + GFile* file = g_file_new_for_path(filename); + GFileOutputStream* fos = g_file_create(file, + G_FILE_CREATE_PRIVATE, NULL, + &creation_error); + if (creation_error) { + cons_show_error("Editor: could not create temp file"); + return TRUE; + } + g_object_unref(fos); + + char* editor = prefs_get_string(PREF_COMPOSE_EDITOR); + if (!g_file_test(editor, G_FILE_TEST_EXISTS)) { + cons_show_error("Editor: binary %s not exist", editor); + return TRUE; + } + + // Fork / exec + pid_t pid = fork(); + if (pid == 0) { + int x = execl(editor, editor, g_file_get_path(file), (char*)NULL); + if (x == -1) { + cons_show_error("Editor:Failed to exec %s", editor); + } + _exit(EXIT_FAILURE); + } else { + if (pid == -1) { + return TRUE; + } + int status = 0; + waitpid(pid, &status, 0); + int fd_input_file = open(g_file_get_path(file), O_RDONLY); + const size_t COUNT = 8192; + char buf[COUNT]; + ssize_t size_read = read(fd_input_file, buf, COUNT); + if (size_read > 0 && size_read <= COUNT) { + buf[size_read - 1] = '\0'; + GString* text = g_string_new(buf); + ProfWin* win = wins_get_current(); + win_println(win, THEME_DEFAULT, "!", "EDITOR PREVIEW: %s", text->str); + rl_insert_text(text->str); + g_string_free(text, TRUE); + } + close(fd_input_file); + + GError* deletion_error = NULL; + g_file_delete(file, NULL, &deletion_error); + if (deletion_error) { + cons_show("Editor: error during file deletion"); + return TRUE; + } + g_object_unref(file); + ui_resize(); + rl_point = rl_end; + rl_forced_update_display(); + } + return TRUE; +} diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index 5a192efb..f4ca72ed 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -242,5 +242,6 @@ gboolean cmd_executable_avatar(ProfWin* window, const char* const command, gchar gboolean cmd_executable_urlopen(ProfWin* window, const char* const command, gchar** args); gboolean cmd_executable_urlsave(ProfWin* window, const char* const command, gchar** args); gboolean cmd_mam(ProfWin* window, const char* const command, gchar** args); +gboolean cmd_editor(ProfWin* window, const char* const command, gchar** args); #endif diff --git a/src/config/preferences.c b/src/config/preferences.c index f09cb746..a11a5d42 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -1868,6 +1868,7 @@ _get_group(preference_t pref) case PREF_TITLEBAR_MUC_TITLE_JID: case PREF_TITLEBAR_MUC_TITLE_NAME: case PREF_SLASH_GUARD: + case PREF_COMPOSE_EDITOR: return PREF_GROUP_UI; case PREF_STATES: case PREF_OUTTYPE: @@ -2189,6 +2190,8 @@ _get_key(preference_t pref) return "url.open.cmd"; case PREF_URL_SAVE_CMD: return "url.save.cmd"; + case PREF_COMPOSE_EDITOR: + return "compose.editor"; default: return NULL; } @@ -2326,6 +2329,8 @@ _get_default_string(preference_t pref) return "xdg-open"; case PREF_URL_OPEN_CMD: return "xdg-open %u"; + case PREF_COMPOSE_EDITOR: + return "/usr/bin/vim"; case PREF_URL_SAVE_CMD: return NULL; // Default to built-in method. default: diff --git a/src/config/preferences.h b/src/config/preferences.h index 49c2c438..4e254917 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -173,6 +173,7 @@ typedef enum { PREF_MAM, PREF_URL_OPEN_CMD, PREF_URL_SAVE_CMD, + PREF_COMPOSE_EDITOR, } preference_t; typedef struct prof_alias_t