diff options
Diffstat (limited to 'src/command')
-rw-r--r-- | src/command/cmd_ac.c | 13 | ||||
-rw-r--r-- | src/command/cmd_defs.c | 134 | ||||
-rw-r--r-- | src/command/cmd_funcs.c | 481 | ||||
-rw-r--r-- | src/command/cmd_funcs.h | 5 |
4 files changed, 335 insertions, 298 deletions
diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 3aeedc60..f7414bad 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -193,7 +193,6 @@ static Autocomplete otr_sendfile_ac; static Autocomplete omemo_ac; static Autocomplete omemo_log_ac; static Autocomplete omemo_policy_ac; -static Autocomplete omemo_sendfile_ac; #endif static Autocomplete connect_property_ac; static Autocomplete tls_property_ac; @@ -683,7 +682,6 @@ cmd_ac_init(void) autocomplete_add(omemo_ac, "clear_device_list"); autocomplete_add(omemo_ac, "policy"); autocomplete_add(omemo_ac, "char"); - autocomplete_add(omemo_ac, "sendfile"); omemo_log_ac = autocomplete_new(); autocomplete_add(omemo_log_ac, "on"); @@ -694,10 +692,6 @@ cmd_ac_init(void) autocomplete_add(omemo_policy_ac, "manual"); autocomplete_add(omemo_policy_ac, "automatic"); autocomplete_add(omemo_policy_ac, "always"); - - omemo_sendfile_ac = autocomplete_new(); - autocomplete_add(omemo_sendfile_ac, "on"); - autocomplete_add(omemo_sendfile_ac, "off"); #endif connect_property_ac = autocomplete_new(); @@ -1292,7 +1286,6 @@ cmd_ac_reset(ProfWin* window) autocomplete_reset(omemo_ac); autocomplete_reset(omemo_log_ac); autocomplete_reset(omemo_policy_ac); - autocomplete_reset(omemo_sendfile_ac); #endif autocomplete_reset(connect_property_ac); autocomplete_reset(tls_property_ac); @@ -1450,7 +1443,6 @@ cmd_ac_uninit(void) autocomplete_free(omemo_ac); autocomplete_free(omemo_log_ac); autocomplete_free(omemo_policy_ac); - autocomplete_free(omemo_sendfile_ac); #endif autocomplete_free(connect_property_ac); autocomplete_free(tls_property_ac); @@ -2510,11 +2502,6 @@ _omemo_autocomplete(ProfWin* window, const char* const input, gboolean previous) return found; } - found = autocomplete_param_with_ac(input, "/omemo sendfile", omemo_sendfile_ac, TRUE, previous); - if (found) { - return found; - } - jabber_conn_status_t conn_status = connection_get_status(); if (conn_status == JABBER_CONNECTED) { diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 51772a27..5058a573 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2274,55 +2274,52 @@ static struct cmd_t command_defs[] = { }, { "/omemo", - parse_args, 1, 3, NULL, - CMD_SUBFUNCS( - { "gen", cmd_omemo_gen }, - { "log", cmd_omemo_log }, - { "start", cmd_omemo_start }, - { "end", cmd_omemo_end }, - { "trust", cmd_omemo_trust }, - { "untrust", cmd_omemo_untrust }, - { "fingerprint", cmd_omemo_fingerprint }, - { "char", cmd_omemo_char }, - { "policy", cmd_omemo_policy }, - { "clear_device_list", cmd_omemo_clear_device_list }, - { "sendfile", cmd_omemo_sendfile }) - CMD_NOMAINFUNC - CMD_TAGS( - CMD_TAG_CHAT, - CMD_TAG_UI) - CMD_SYN( - "/omemo gen", - "/omemo log on|off|redact", - "/omemo start [<contact>]", - "/omemo trust [<contact>] <fingerprint>", - "/omemo end", - "/omemo fingerprint [<contact>]", - "/omemo char <char>", - "/omemo policy manual|automatic|always", - "/omemo sendfile on|off", - "/omemo clear_device_list") - CMD_DESC( - "OMEMO commands to manage keys, and perform encryption during chat sessions.") - CMD_ARGS( - { "gen", "Generate OMEMO crytographic materials for current account." }, - { "start [<contact>]", "Start an OMEMO session with contact, or current recipient if omitted." }, - { "end", "End the current OMEMO session." }, - { "log on|off", "Enable or disable plaintext logging of OMEMO encrypted messages." }, - { "log redact", "Log OMEMO encrypted messages, but replace the contents with [redacted]. This is the default." }, - { "fingerprint [<contact>]", "Show contact fingerprints, or current recipient if omitted." }, - { "char <char>", "Set the character to be displayed next to OMEMO encrypted messages." }, - { "policy manual", "Set the global OMEMO policy to manual, OMEMO sessions must be started manually." }, - { "policy automatic", "Set the global OMEMO policy to opportunistic, an OMEMO session will be attempted upon starting a conversation." }, - { "policy always", "Set the global OMEMO policy to always, an error will be displayed if an OMEMO session cannot be initiated upon starting a conversation." }, - { "sendfile on|off", "Allow /sendfile to send unencrypted files while in an OMEMO session." }, - { "clear_device_list", "Clear your own device list on server side. Each client will reannounce itself when connected back." }) - CMD_EXAMPLES( - "/omemo gen", - "/omemo start odin@valhalla.edda", - "/omemo trust c4f9c875-144d7a3b-0c4a05b6-ca3be51a-a037f329-0bd3ae62-07f99719-55559d2a", - "/omemo untrust loki@valhalla.edda c4f9c875-144d7a3b-0c4a05b6-ca3be51a-a037f329-0bd3ae62-07f99719-55559d2a", - "/omemo char *") + parse_args, 1, 3, NULL, + CMD_SUBFUNCS( + { "gen", cmd_omemo_gen }, + { "log", cmd_omemo_log }, + { "start", cmd_omemo_start }, + { "end", cmd_omemo_end }, + { "trust", cmd_omemo_trust }, + { "untrust", cmd_omemo_untrust }, + { "fingerprint", cmd_omemo_fingerprint }, + { "char", cmd_omemo_char }, + { "policy", cmd_omemo_policy }, + { "clear_device_list", cmd_omemo_clear_device_list }) + CMD_NOMAINFUNC + CMD_TAGS( + CMD_TAG_CHAT, + CMD_TAG_UI) + CMD_SYN( + "/omemo gen", + "/omemo log on|off|redact", + "/omemo start [<contact>]", + "/omemo trust [<contact>] <fingerprint>", + "/omemo end", + "/omemo fingerprint [<contact>]", + "/omemo char <char>", + "/omemo policy manual|automatic|always", + "/omemo clear_device_list") + CMD_DESC( + "OMEMO commands to manage keys, and perform encryption during chat sessions.") + CMD_ARGS( + { "gen", "Generate OMEMO crytographic materials for current account." }, + { "start [<contact>]", "Start an OMEMO session with contact, or current recipient if omitted." }, + { "end", "End the current OMEMO session." }, + { "log on|off", "Enable or disable plaintext logging of OMEMO encrypted messages." }, + { "log redact", "Log OMEMO encrypted messages, but replace the contents with [redacted]. This is the default." }, + { "fingerprint [<contact>]", "Show contact fingerprints, or current recipient if omitted." }, + { "char <char>", "Set the character to be displayed next to OMEMO encrypted messages." }, + { "policy manual", "Set the global OMEMO policy to manual, OMEMO sessions must be started manually." }, + { "policy automatic", "Set the global OMEMO policy to opportunistic, an OMEMO session will be attempted upon starting a conversation." }, + { "policy always", "Set the global OMEMO policy to always, an error will be displayed if an OMEMO session cannot be initiated upon starting a conversation." }, + { "clear_device_list", "Clear your own device list on server side. Each client will reannounce itself when connected back."}) + CMD_EXAMPLES( + "/omemo gen", + "/omemo start odin@valhalla.edda", + "/omemo trust c4f9c875-144d7a3b-0c4a05b6-ca3be51a-a037f329-0bd3ae62-07f99719-55559d2a", + "/omemo untrust loki@valhalla.edda c4f9c875-144d7a3b-0c4a05b6-ca3be51a-a037f329-0bd3ae62-07f99719-55559d2a", + "/omemo char *") }, { "/save", @@ -2377,7 +2374,7 @@ static struct cmd_t command_defs[] = { "Settings for consistent color generation for nicks (XEP-0392). Including corrections for Color Vision Deficiencies. " "Your terminal needs to support 256 colors.") CMD_ARGS( - { "on|off|redgreen|blue", "Enable or disable nick colorization for MUC nicks. 'redgreen' is for people with red/green blindess and 'blue' for people with blue blindness." }, + { "on|off|redgreen|blue", "Enable or disable nick colorization for MUC nicks. 'redgreen' is for people with red/green blindness and 'blue' for people with blue blindness." }, { "own on|off", "Enable color generation for own nick. If disabled the color from the color from the theme ('me') will get used." }) CMD_EXAMPLES( "/color off", @@ -2496,26 +2493,35 @@ static struct cmd_t command_defs[] = { { "/executable", parse_args, 2, 4, &cons_executable_setting, - CMD_NOSUBFUNCS - CMD_MAINFUNC(cmd_executable) + CMD_SUBFUNCS( + { "avatar", cmd_executable_avatar }, + { "urlopen", cmd_executable_urlopen }, + { "urlsave", cmd_executable_urlsave }) + CMD_NOMAINFUNC CMD_TAGS( CMD_TAG_DISCOVERY) CMD_SYN( "/executable avatar <cmd>", - "/executable urlopen (<fileType>|DEF <require_save> <cmd>", - "/executable urlsave (<protocol>|DEF) <cmd>") - CMD_DESC( - "Configure executable that should be called upon a certain command." - "Default is xdg-open.") - CMD_ARGS( - { "avatar", "Set executable that is run in /avatar open. Use your favourite image viewer." }, - { "urlopen", "Set executable that is run in /url open for a given file type. It may be your favorite browser or a specific viewer. Use DEF to set default command for undefined file type." }, - { "urlsave", "Set executable that is run in /url save for a given protocol. Use your favourite downloader. Use DEF to set default command for undefined protocol." }) + "/executable urlopen set <cmdtemplate>", + "/executable urlopen default", + "/executable urlsave set <cmdtemplate>", + "/executable urlsave default") + CMD_DESC( + "Configure executable that should be called upon a certain command.") + CMD_ARGS( + { "avatar", "Set executable that is run by /avatar open. Use your favorite image viewer." }, + { "urlopen set", "Set executable that is run by /url open. It may be your favorite browser or a specific viewer." }, + { "urlopen default", "Restore to default settings." }, + { "urlsave set", "Set executable that is run by /url save. It may be your favorite downloader.'" }, + { "urlsave default", "Use the built-in download method for saving." }) CMD_EXAMPLES( "/executable avatar xdg-open", - "/executable urlopen DEF false \"xdg-open %u\"", - "/executable urlopen html false \"firefox %u\"", - "/executable urlsave aesgcm \"omut -d -o %p %u\"") + "/executable urlopen set \"xdg-open %u\"", + "/executable urlopen set \"firefox %u\"", + "/executable urlopen default", + "/executable urlsave set \"wget %u -O %p\"", + "/executable urlsave set \"curl %u -o %p\"", + "/executable urlsave default") }, { "/url", diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 0837f630..fd9d2ffd 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -4,6 +4,7 @@ * * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com> * Copyright (C) 2019 Michael Vetter <jubalh@iodoru.org> + * Copyright (C) 2020 William Wennerström <william@wstrm.dev> * * This file is part of Profanity. * @@ -59,6 +60,7 @@ #include "command/cmd_funcs.h" #include "command/cmd_defs.h" #include "command/cmd_ac.h" +#include "config/files.h" #include "config/accounts.h" #include "config/account.h" #include "config/preferences.h" @@ -67,6 +69,7 @@ #include "config/scripts.h" #include "event/client_events.h" #include "tools/http_upload.h" +#include "tools/http_download.h" #include "tools/autocomplete.h" #include "tools/parser.h" #include "tools/bookmark_ignore.h" @@ -94,6 +97,7 @@ #ifdef HAVE_OMEMO #include "omemo/omemo.h" #include "xmpp/omemo.h" +#include "tools/aesgcm_download.h" #endif #ifdef HAVE_GTK @@ -1086,7 +1090,7 @@ _writecsv(int fd, const char* const str) size_t len = strlen(str); char* s = malloc(2 * len * sizeof(char)); char* c = s; - for (int i =0; i < strlen(str); i++) { + for (int i = 0; i < strlen(str); i++) { if (str[i] != '"') *c++ = str[i]; else { @@ -4805,11 +4809,54 @@ cmd_disco(ProfWin* window, const char* const command, gchar** args) return TRUE; } +// TODO: Move this into its own tools such as HTTPUpload or AESGCMDownload. +#ifdef HAVE_OMEMO +char* +_add_omemo_stream(int* fd, FILE** fh, char** err) +{ + // Create temporary file for writing ciphertext. + int tmpfd; + char* tmpname = NULL; + if ((tmpfd = g_file_open_tmp("profanity.XXXXXX", &tmpname, NULL)) == -1) { + *err = "Unable to create temporary file for encrypted transfer."; + return NULL; + } + FILE* tmpfh = fdopen(tmpfd, "wb"); + + // The temporary ciphertext file should be removed after it has + // been closed. + remove(tmpname); + free(tmpname); + + int crypt_res; + char* fragment; + fragment = omemo_encrypt_file(*fh, tmpfh, file_size(*fd), &crypt_res); + if (crypt_res != 0) { + fclose(tmpfh); + return NULL; + } + + // Force flush as the upload will read from the same stream. + fflush(tmpfh); + rewind(tmpfh); + + fclose(*fh); // Also closes descriptor. + + // Switch original stream with temporary ciphertext stream. + *fd = tmpfd; + *fh = tmpfh; + + return fragment; +} +#endif + gboolean cmd_sendfile(ProfWin* window, const char* const command, gchar** args) { jabber_conn_status_t conn_status = connection_get_status(); char* filename = args[0]; + char* alt_scheme = NULL; + char* alt_fragment = NULL; // expand ~ to $HOME if (filename[0] == '~' && filename[1] == '/') { @@ -4820,80 +4867,101 @@ cmd_sendfile(ProfWin* window, const char* const command, gchar** args) filename = strdup(filename); } + if (access(filename, R_OK) != 0) { + cons_show_error("Uploading '%s' failed: File not found!", filename); + goto out; + } + + if (!is_regular_file(filename)) { + cons_show_error("Uploading '%s' failed: Not a file!", filename); + goto out; + } + if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); - free(filename); - return TRUE; + goto out; } if (window->type != WIN_CHAT && window->type != WIN_PRIVATE && window->type != WIN_MUC) { cons_show_error("Unsupported window for file transmission."); - free(filename); - return TRUE; + goto out; + } + + int fd; + if ((fd = open(filename, O_RDONLY)) == -1) { + cons_show_error("Unable to open file descriptor for '%s'.", filename); + goto out; } + FILE* fh = fdopen(fd, "rb"); + switch (window->type) { case WIN_MUC: - { - ProfMucWin* mucwin = (ProfMucWin*)window; - assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); - - // only omemo, no pgp/otr available in MUCs - if (mucwin->is_omemo && !prefs_get_boolean(PREF_OMEMO_SENDFILE)) { - cons_show_error("Uploading unencrypted files disabled. See /omemo sendfile, /otr sendfile, /pgp sendfile."); - win_println(window, THEME_ERROR, "-", "Sending encrypted files via http_upload is not possible yet."); - free(filename); - return TRUE; - } - break; - } case WIN_CHAT: { ProfChatWin* chatwin = (ProfChatWin*)window; - assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); - if ((chatwin->is_omemo && !prefs_get_boolean(PREF_OMEMO_SENDFILE)) - || (chatwin->pgp_send && !prefs_get_boolean(PREF_PGP_SENDFILE)) - || (chatwin->is_otr && !prefs_get_boolean(PREF_OTR_SENDFILE))) { - cons_show_error("Uploading unencrypted files disabled. See /omemo sendfile, /otr sendfile, /pgp sendfile."); - win_println(window, THEME_ERROR, "-", "Sending encrypted files via http_upload is not possible yet."); - free(filename); - return TRUE; +#ifdef HAVE_OMEMO + if (chatwin->is_omemo) { + char* err = NULL; + alt_scheme = OMEMO_AESGCM_URL_SCHEME; + alt_fragment = _add_omemo_stream(&fd, &fh, &err); + if (err != NULL) { + cons_show_error(err); + win_println(window, THEME_ERROR, "-", err); + goto out; + } + break; + } +#endif + + if (window->type == WIN_CHAT) { + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + if ((chatwin->pgp_send && !prefs_get_boolean(PREF_PGP_SENDFILE)) + || (chatwin->is_otr && !prefs_get_boolean(PREF_OTR_SENDFILE))) { + cons_show_error("Uploading unencrypted files disabled. See /otr sendfile or /pgp sendfile."); + win_println(window, THEME_ERROR, "-", "Sending encrypted files via http_upload is not possible yet."); + goto out; + } } break; } - case WIN_PRIVATE: - { - //we don't support encryption in private muc windows - break; - } + case WIN_PRIVATE: // We don't support encryption in private MUC windows. default: cons_show_error("Unsupported window for file transmission."); - free(filename); - return TRUE; - } - - if (access(filename, R_OK) != 0) { - cons_show_error("Uploading '%s' failed: File not found!", filename); - free(filename); - return TRUE; - } - - if (!is_regular_file(filename)) { - cons_show_error("Uploading '%s' failed: Not a file!", filename); - free(filename); - return TRUE; + goto out; } HTTPUpload* upload = malloc(sizeof(HTTPUpload)); upload->window = window; - upload->filename = filename; - upload->filesize = file_size(filename); + upload->filename = strdup(filename); + upload->filehandle = fh; + upload->filesize = file_size(fd); upload->mime_type = file_mime_type(filename); + if (alt_scheme != NULL) { + upload->alt_scheme = strdup(alt_scheme); + } else { + upload->alt_scheme = NULL; + } + + if (alt_fragment != NULL) { + upload->alt_fragment = strdup(alt_fragment); + } else { + upload->alt_fragment = NULL; + } + iq_http_upload_request(upload); +out: +#ifdef HAVE_OMEMO + if (alt_fragment != NULL) + omemo_free(alt_fragment); +#endif + if (filename != NULL) + free(filename); + return TRUE; } @@ -8773,19 +8841,6 @@ cmd_omemo_policy(ProfWin* window, const char* const command, gchar** args) } gboolean -cmd_omemo_sendfile(ProfWin* window, const char* const command, gchar** args) -{ -#ifdef HAVE_OMEMO - _cmd_set_boolean_preference(args[1], command, "Sending unencrypted files in an OMEMO session via /sendfile", PREF_OMEMO_SENDFILE); - - return TRUE; -#else - cons_show("This version of Profanity has not been built with OMEMO support enabled"); - return TRUE; -#endif -} - -gboolean cmd_save(ProfWin* window, const char* const command, gchar** args) { log_info("Saving preferences to configuration file"); @@ -9005,6 +9060,57 @@ cmd_slashguard(ProfWin* window, const char* const command, gchar** args) return TRUE; } +#ifdef HAVE_OMEMO +void +_url_aesgcm_method(ProfWin* window, const char* cmd_template, const char* url, const char* filename) +{ + AESGCMDownload* download = malloc(sizeof(AESGCMDownload)); + download->window = window; + download->url = strdup(url); + download->filename = strdup(filename); + if (cmd_template != NULL) { + download->cmd_template = strdup(cmd_template); + } else { + download->cmd_template = NULL; + } + + pthread_create(&(download->worker), NULL, &aesgcm_file_get, download); + aesgcm_download_add_download(download); +} +#endif + +void +_url_http_method(ProfWin* window, const char* cmd_template, const char* url, const char* filename) +{ + + HTTPDownload* download = malloc(sizeof(HTTPDownload)); + download->window = window; + download->url = strdup(url); + download->filename = strdup(filename); + if (cmd_template != NULL) { + download->cmd_template = strdup(cmd_template); + } else { + download->cmd_template = NULL; + } + + pthread_create(&(download->worker), NULL, &http_file_get, download); + http_download_add_download(download); +} + +void +_url_external_method(const char* cmd_template, const char* url, const char* filename) +{ + gchar** argv = format_call_external_argv(cmd_template, url, filename); + + if (!call_external(argv, NULL, NULL)) { + cons_show_error("Unable to call external executable for url: check the logs for more information."); + } else { + cons_show("URL '%s' has been called with '%s'.", url, cmd_template); + } + + g_strfreev(argv); +} + gboolean cmd_url_open(ProfWin* window, const char* const command, gchar** args) { @@ -9013,91 +9119,45 @@ cmd_url_open(ProfWin* window, const char* const command, gchar** args) return TRUE; } - if (args[1] == NULL) { + gchar* url = args[1]; + if (url == NULL) { cons_bad_cmd_usage(command); return TRUE; } - gboolean require_save = false; + gchar* scheme = NULL; + char* cmd_template = NULL; + char* filename = NULL; - gchar* fileStart = g_strrstr(args[1], "/"); - if (fileStart == NULL) { + scheme = g_uri_parse_scheme(url); + if (scheme == NULL) { cons_show("URL '%s' is not valid.", args[1]); - return TRUE; - } - - fileStart++; - if (((char*)(fileStart - 2))[0] == '/' && ((char*)(fileStart - 3))[0] == ':') { - // If the '/' is last character of the '://' string, there will be no suffix - // Therefore, it is considered that there is no file name in the URL and - // fileStart is set to the end of the URL. - fileStart = args[1] + strlen(args[1]); - } - - gchar* suffix = NULL; - gchar* suffixStart = g_strrstr(fileStart, "."); - if (suffixStart != NULL) { - suffixStart++; - gchar* suffixEnd = g_strrstr(suffixStart, "#"); - if (suffixEnd == NULL) { - suffix = g_strdup(suffixStart); - } else { - suffix = g_strndup(suffixStart, suffixEnd - suffixStart); - } + goto out; } - gchar** suffix_cmd_pref = prefs_get_string_list_with_option(PREF_URL_OPEN_CMD, NULL); - if (suffix != NULL) { - gchar* lowercase_suffix = g_ascii_strdown(suffix, -1); - g_strfreev(suffix_cmd_pref); - suffix_cmd_pref = prefs_get_string_list_with_option(PREF_URL_OPEN_CMD, lowercase_suffix); - g_free(lowercase_suffix); - g_free(suffix); + cmd_template = prefs_get_string(PREF_URL_OPEN_CMD); + if (cmd_template == NULL) { + cons_show("No default `url open` command found in executables preferences."); + goto out; } - if (0 == g_strcmp0(suffix_cmd_pref[0], "true")) { - require_save = true; - } - - gchar* suffix_cmd = g_strdup(suffix_cmd_pref[1]); - g_strfreev(suffix_cmd_pref); - - gchar* scheme = g_uri_parse_scheme(args[1]); +#ifdef HAVE_OMEMO + // OMEMO URLs (aesgcm://) must be saved and decrypted before being opened. if (0 == g_strcmp0(scheme, "aesgcm")) { - require_save = true; - } - g_free(scheme); - - if (require_save) { - gchar* save_args[] = { "open", args[1], "/tmp/profanity.tmp", NULL }; - cmd_url_save(window, command, save_args); + filename = unique_filename_from_url(url, files_get_data_path(DIR_DOWNLOADS)); + _url_aesgcm_method(window, cmd_template, url, filename); + goto out; } +#endif - gchar** argv = g_strsplit(suffix_cmd, " ", 0); - guint num_args = 0; - while (argv[num_args]) { - if (0 == g_strcmp0(argv[num_args], "%u")) { - g_free(argv[num_args]); - if (require_save) { - argv[num_args] = g_strdup("/tmp/profanity.tmp"); - } else { - argv[num_args] = g_strdup(args[1]); - } - break; - } - num_args++; - } + _url_external_method(cmd_template, url, NULL); - if (!call_external(argv, NULL, NULL)) { - cons_show_error("Unable to open url: check the logs for more information."); - } +out: - if (require_save) { - g_unlink("/tmp/profanity.tmp"); - } + free(cmd_template); + free(filename); - g_strfreev(argv); - g_free(suffix_cmd); + g_free(scheme); return TRUE; } @@ -9106,7 +9166,7 @@ gboolean cmd_url_save(ProfWin* window, const char* const command, gchar** args) { if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) { - cons_show("url save not supported in this window"); + cons_show_error("`/url save` is not supported in this window."); return TRUE; } @@ -9115,121 +9175,104 @@ cmd_url_save(ProfWin* window, const char* const command, gchar** args) return TRUE; } - gchar* uri = args[1]; - gchar* target_path = g_strdup(args[2]); + gchar* url = args[1]; + gchar* path = g_strdup(args[2]); + gchar* scheme = NULL; + char* filename = NULL; + char* cmd_template = NULL; - GFile* file = g_file_new_for_uri(uri); - - gchar* target_dir = NULL; - gchar* base_name = NULL; - - if (target_path == NULL) { - target_dir = g_strdup("./"); - base_name = g_file_get_basename(file); - if (0 == g_strcmp0(base_name, ".")) { - g_free(base_name); - base_name = g_strdup("saved_url_content.html"); - } - target_path = g_strconcat(target_dir, base_name, NULL); - } - - if (g_file_test(target_path, G_FILE_TEST_EXISTS) && g_file_test(target_path, G_FILE_TEST_IS_DIR)) { - target_dir = g_strdup(target_path); - base_name = g_file_get_basename(file); - g_free(target_path); - target_path = g_strconcat(target_dir, "/", base_name, NULL); - } - - g_object_unref(file); - file = NULL; - - if (base_name == NULL) { - base_name = g_path_get_basename(target_path); - target_dir = g_path_get_dirname(target_path); + scheme = g_uri_parse_scheme(url); + if (scheme == NULL) { + cons_show("URL '%s' is not valid.", args[1]); + goto out; } - if (!g_file_test(target_dir, G_FILE_TEST_EXISTS) || !g_file_test(target_dir, G_FILE_TEST_IS_DIR)) { - cons_show("%s does not exist or is not a directory.", target_dir); - g_free(target_path); - g_free(target_dir); - g_free(base_name); - return TRUE; + filename = unique_filename_from_url(url, path); + if (filename == NULL) { + cons_show("Failed to generate unique filename" + "from URL '%s' for path '%s'", + url, path); + goto out; } - gchar* scheme = g_uri_parse_scheme(uri); - if (scheme == NULL) { - cons_show("URL '%s' is not valid.", uri); - g_free(target_path); - g_free(target_dir); - g_free(base_name); - return TRUE; + cmd_template = prefs_get_string(PREF_URL_SAVE_CMD); + if (cmd_template == NULL && (g_strcmp0(scheme, "http") == 0 || g_strcmp0(scheme, "https") == 0)) { + _url_http_method(window, cmd_template, url, filename); +#ifdef HAVE_OMEMO + } else if (g_strcmp0(scheme, "aesgcm") == 0) { + _url_aesgcm_method(window, cmd_template, url, filename); +#endif + } else if (cmd_template != NULL) { + _url_external_method(cmd_template, url, filename); + } else { + cons_show_error("No download method defined for the scheme '%s'.", scheme); } - gchar* scheme_cmd = NULL; +out: - if (0 == g_strcmp0(scheme, "http") - || 0 == g_strcmp0(scheme, "https") - || 0 == g_strcmp0(scheme, "aesgcm")) { - scheme_cmd = prefs_get_string_with_option(PREF_URL_SAVE_CMD, scheme); - } + free(filename); + free(cmd_template); g_free(scheme); + g_free(path); - gchar** argv = g_strsplit(scheme_cmd, " ", 0); - g_free(scheme_cmd); + return TRUE; +} - guint num_args = 0; - while (argv[num_args]) { - if (0 == g_strcmp0(argv[num_args], "%u")) { - g_free(argv[num_args]); - argv[num_args] = g_strdup(uri); - } else if (0 == g_strcmp0(argv[num_args], "%p")) { - g_free(argv[num_args]); - argv[num_args] = target_path; - } - num_args++; +gboolean +cmd_executable_avatar(ProfWin* window, const char* const command, gchar** args) +{ + prefs_set_string(PREF_AVATAR_CMD, args[1]); + cons_show("`avatar` command set to invoke '%s'", args[1]); + return TRUE; +} + +gboolean +cmd_executable_urlopen(ProfWin* window, const char* const command, gchar** args) +{ + guint num_args = g_strv_length(args); + if (num_args < 2) { + cons_bad_cmd_usage(command); + return TRUE; } - if (!call_external(argv, NULL, NULL)) { - cons_show_error("Unable to save url: check the logs for more information."); + if (g_strcmp0(args[1], "set") == 0 && num_args >= 3) { + gchar* str = g_strjoinv(" ", &args[2]); + prefs_set_string(PREF_URL_OPEN_CMD, str); + cons_show("`url open` command set to invoke '%s'", str); + g_free(str); + + } else if (g_strcmp0(args[1], "default") == 0) { + prefs_set_string(PREF_URL_SAVE_CMD, NULL); + gchar* def = prefs_get_string(PREF_URL_SAVE_CMD); + cons_show("`url open` command set to invoke %s (default)", def); + g_free(def); } else { - cons_show("URL '%s' has been saved into '%s'.", uri, target_path); + cons_bad_cmd_usage(command); } - g_free(target_dir); - g_free(base_name); - g_strfreev(argv); - return TRUE; } gboolean -cmd_executable(ProfWin* window, const char* const command, gchar** args) +cmd_executable_urlsave(ProfWin* window, const char* const command, gchar** args) { - if (g_strcmp0(args[0], "avatar") == 0) { - prefs_set_string(PREF_AVATAR_CMD, args[1]); - cons_show("Avatar command set to: %s", args[1]); - } else if (g_strcmp0(args[0], "urlopen") == 0) { - if (g_strv_length(args) < 4) { - cons_bad_cmd_usage(command); - return TRUE; - } - gchar* str = g_strjoinv(" ", &args[3]); - const gchar* const list[] = { args[2], str, NULL }; - prefs_set_string_list_with_option(PREF_URL_OPEN_CMD, args[1], list); - cons_show("`url open` command set to: %s for %s files", str, args[1]); - g_free(str); - } else if (g_strcmp0(args[0], "urlsave") == 0) { - if (g_strv_length(args) < 3) { - cons_bad_cmd_usage(command); - return TRUE; - } + guint num_args = g_strv_length(args); + if (num_args < 2) { + cons_bad_cmd_usage(command); + return TRUE; + } + if (g_strcmp0(args[1], "set") == 0 && num_args >= 3) { gchar* str = g_strjoinv(" ", &args[2]); - prefs_set_string_with_option(PREF_URL_SAVE_CMD, args[1], str); - cons_show("`url save` command set to: %s for scheme %s", str, args[1]); + prefs_set_string(PREF_URL_SAVE_CMD, str); + cons_show("`url save` command set to invoke '%s'", str); g_free(str); + + } else if (g_strcmp0(args[1], "default") == 0) { + prefs_set_string(PREF_URL_SAVE_CMD, NULL); + cons_show("`url save` will use built-in download method (default)"); } else { cons_bad_cmd_usage(command); } diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index 92c81364..4955972c 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -223,7 +223,6 @@ gboolean cmd_omemo_trust(ProfWin* window, const char* const command, gchar** arg gboolean cmd_omemo_untrust(ProfWin* window, const char* const command, gchar** args); gboolean cmd_omemo_policy(ProfWin* window, const char* const command, gchar** args); gboolean cmd_omemo_clear_device_list(ProfWin* window, const char* const command, gchar** args); -gboolean cmd_omemo_sendfile(ProfWin* window, const char* const command, gchar** args); gboolean cmd_save(ProfWin* window, const char* const command, gchar** args); gboolean cmd_reload(ProfWin* window, const char* const command, gchar** args); @@ -238,6 +237,8 @@ gboolean cmd_slashguard(ProfWin* window, const char* const command, gchar** args gboolean cmd_serversoftware(ProfWin* window, const char* const command, gchar** args); gboolean cmd_url_open(ProfWin* window, const char* const command, gchar** args); gboolean cmd_url_save(ProfWin* window, const char* const command, gchar** args); -gboolean cmd_executable(ProfWin* window, const char* const command, gchar** args); +gboolean cmd_executable_avatar(ProfWin* window, const char* const command, gchar** args); +gboolean cmd_executable_urlopen(ProfWin* window, const char* const command, gchar** args); +gboolean cmd_executable_urlsave(ProfWin* window, const char* const command, gchar** args); #endif |