From eebf54c8596abd5c28b405d8860c173207bbec64 Mon Sep 17 00:00:00 2001 From: William Wennerström Date: Sun, 5 Jul 2020 17:21:20 +0200 Subject: Infer filename from content-disposition or URL The Content-Disposition inferring is probably a bad idea security wise, so I am going to remove it. --- Makefile.am | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Makefile.am') diff --git a/Makefile.am b/Makefile.am index 1228e1ad..a2cf5598 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,6 +43,8 @@ core_sources = \ src/tools/parser.h \ src/tools/http_upload.c \ src/tools/http_upload.h \ + src/tools/http_download.c \ + src/tools/http_download.h \ src/tools/bookmark_ignore.c \ src/tools/bookmark_ignore.h \ src/tools/autocomplete.c src/tools/autocomplete.h \ @@ -89,6 +91,8 @@ unittest_sources = \ src/tools/clipboard.c src/tools/clipboard.h \ src/tools/bookmark_ignore.c \ src/tools/bookmark_ignore.h \ + src/tools/http_download.c \ + src/tools/http_download.h \ src/config/accounts.h \ src/config/account.c src/config/account.h \ src/config/files.c src/config/files.h \ @@ -119,6 +123,7 @@ unittest_sources = \ tests/unittests/database/stub_database.c \ tests/unittests/config/stub_accounts.c \ tests/unittests/tools/stub_http_upload.c \ + tests/unittests/tools/stub_http_download.c \ tests/unittests/helpers.c tests/unittests/helpers.h \ tests/unittests/test_form.c tests/unittests/test_form.h \ tests/unittests/test_common.c tests/unittests/test_common.h \ @@ -145,6 +150,7 @@ unittest_sources = \ tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \ tests/unittests/test_callbacks.c tests/unittests/test_callbacks.h \ tests/unittests/test_plugins_disco.c tests/unittests/test_plugins_disco.h \ + tests/unittests/test_http_download.c tests/unittests/test_http_download.h \ tests/unittests/unittests.c functionaltest_sources = \ -- cgit 1.4.1-2-gfad0 From 73f313b9212d652fecb13bcb82a0f162abb897a0 Mon Sep 17 00:00:00 2001 From: William Wennerström Date: Mon, 20 Jul 2020 22:49:50 +0200 Subject: Refactor OMEMO download into AESGCMDownload tool --- Makefile.am | 2 + src/command/cmd_funcs.c | 61 ++++++++++++++++++-- src/omemo/crypto.c | 8 +-- src/omemo/crypto.h | 3 - src/omemo/omemo.c | 106 ++++++++++++++++++++++++++++++++--- src/omemo/omemo.h | 6 +- src/tools/aesgcm_download.c | 134 ++++++++++++++++++++++++++++++++++++++++++++ src/tools/aesgcm_download.h | 66 ++++++++++++++++++++++ src/tools/aesgcm_upload.c | 0 src/tools/aesgcm_upload.h | 0 src/tools/http_download.c | 20 ++++++- src/tools/http_download.h | 3 + 12 files changed, 386 insertions(+), 23 deletions(-) create mode 100644 src/tools/aesgcm_download.c create mode 100644 src/tools/aesgcm_download.h create mode 100644 src/tools/aesgcm_upload.c create mode 100644 src/tools/aesgcm_upload.h (limited to 'Makefile.am') diff --git a/Makefile.am b/Makefile.am index a2cf5598..5c34b35a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,6 +45,8 @@ core_sources = \ src/tools/http_upload.h \ src/tools/http_download.c \ src/tools/http_download.h \ + src/tools/aesgcm_download.c \ + src/tools/aesgcm_download.h \ src/tools/bookmark_ignore.c \ src/tools/bookmark_ignore.h \ src/tools/autocomplete.c src/tools/autocomplete.h \ diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index b3914e0d..bf6d6843 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -69,6 +69,7 @@ #include "event/client_events.h" #include "tools/http_upload.h" #include "tools/http_download.h" +#include "tools/aesgcm_download.h" #include "tools/autocomplete.h" #include "tools/parser.h" #include "tools/bookmark_ignore.h" @@ -9154,6 +9155,40 @@ cmd_url_open(ProfWin* window, const char* const command, gchar** args) return TRUE; } +void +_url_open_fallback_method(ProfWin* window, const char* url) +{ + /* + gboolean is_omemo_aesgcm = false; + gchar* scheme = g_uri_parse_scheme(url); + if (g_strcmp0(scheme, "aesgcm")) { + is_omemo_aesgcm = true; + } + free(scheme); + + if (is_omemo_aesgcm) { + int tmpfd; + char* tmpname = NULL; + if ((tmpfd = g_file_open_tmp("profanity.XXXXXX", &tmpname, NULL)) == -1) { + *err = "Unable to create temporary file for decryption stream."; + return NULL; + } + FILE* tmpfh = fdopen(tmpfd, "wb"); + + unsigned char* nonce; + unsigned char* key; + char* https_url = omemo_parse_aesgcm_url(url, nonce, key); + + _url_save_fallback_method(window, https_url, tmpname); + + int crypt_res = omemo_decrypt_file(tmpfh, + + remove(tmpname); + free(tmpname); + } + */ +} + void _url_save_fallback_method(ProfWin* window, const char* url, const char* filename) { @@ -9163,13 +9198,27 @@ _url_save_fallback_method(ProfWin* window, const char* url, const char* filename return; } - HTTPDownload* download = malloc(sizeof(HTTPDownload)); - download->window = window; - download->url = strdup(url); - download->filehandle = fh; + gchar* scheme = g_uri_parse_scheme(url); + + if (g_strcmp0(scheme, "aesgcm") == 0) { + AESGCMDownload* download = malloc(sizeof(AESGCMDownload)); + download->window = window; + download->url = strdup(url); + download->filehandle = fh; + + pthread_create(&(download->worker), NULL, &aesgcm_file_get, download); + aesgcm_download_add_download(download); + } else { + HTTPDownload* download = malloc(sizeof(HTTPDownload)); + download->window = window; + download->url = strdup(url); + download->filehandle = fh; + + pthread_create(&(download->worker), NULL, &http_file_get, download); + http_download_add_download(download); + } - pthread_create(&(download->worker), NULL, &http_file_get, download); - http_download_add_download(download); + free(scheme); } void diff --git a/src/omemo/crypto.c b/src/omemo/crypto.c index a9f72626..a05e160e 100644 --- a/src/omemo/crypto.c +++ b/src/omemo/crypto.c @@ -400,12 +400,12 @@ aes256gcm_crypt_file(FILE* in, FILE* out, off_t file_size, goto out; } - res = gcry_cipher_setkey(hd, key, AES256_GCM_KEY_LENGTH); + res = gcry_cipher_setkey(hd, key, OMEMO_AESGCM_KEY_LENGTH); if (res != GPG_ERR_NO_ERROR) { goto out; } - res = gcry_cipher_setiv(hd, nonce, AES256_GCM_NONCE_LENGTH); + res = gcry_cipher_setiv(hd, nonce, OMEMO_AESGCM_NONCE_LENGTH); if (res != GPG_ERR_NO_ERROR) { goto out; } @@ -468,8 +468,8 @@ out: char* aes256gcm_create_secure_fragment(unsigned char* key, unsigned char* nonce) { - int key_size = AES256_GCM_KEY_LENGTH; - int nonce_size = AES256_GCM_NONCE_LENGTH; + int key_size = OMEMO_AESGCM_KEY_LENGTH; + int nonce_size = OMEMO_AESGCM_NONCE_LENGTH; char* fragment = gcry_malloc_secure((nonce_size + key_size) * 2 + 1); diff --git a/src/omemo/crypto.h b/src/omemo/crypto.h index f0090daf..c1d508b9 100644 --- a/src/omemo/crypto.h +++ b/src/omemo/crypto.h @@ -40,9 +40,6 @@ #define AES128_GCM_IV_LENGTH 12 #define AES128_GCM_TAG_LENGTH 16 -#define AES256_GCM_KEY_LENGTH 32 -#define AES256_GCM_NONCE_LENGTH 12 - int omemo_crypto_init(void); /** * Callback for a secure random number generator. diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index e08d3f06..e19b724e 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -62,6 +62,9 @@ #include "xmpp/roster_list.h" #include "xmpp/xmpp.h" +#define AESGCM_URL_NONCE_LEN (2 * OMEMO_AESGCM_NONCE_LENGTH) +#define AESGCM_URL_KEY_LEN (2 * OMEMO_AESGCM_KEY_LENGTH) + static gboolean loaded; static void _generate_pre_keys(int count); @@ -1664,12 +1667,12 @@ char* omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res) { unsigned char* key = gcry_random_bytes_secure( - AES256_GCM_KEY_LENGTH, + OMEMO_AESGCM_KEY_LENGTH, GCRY_VERY_STRONG_RANDOM); // Create nonce/IV with random bytes. - unsigned char nonce[AES256_GCM_NONCE_LENGTH]; - gcry_create_nonce(nonce, AES256_GCM_NONCE_LENGTH); + unsigned char nonce[OMEMO_AESGCM_NONCE_LENGTH]; + gcry_create_nonce(nonce, OMEMO_AESGCM_NONCE_LENGTH); char* fragment = aes256gcm_create_secure_fragment(key, nonce); *gcry_res = aes256gcm_crypt_file(in, out, file_size, key, nonce, true); @@ -1684,7 +1687,96 @@ omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res) return fragment; } -//int omemo_decrypt_file(FILE *in, FILE *out, off_t file_size, -// unsigned char key[], unsigned char nonce[]) { -// return aes256gcm_crypt_file(in, out, file_size, key, nonce, false); -//} +void +_bytes_from_hex(const char* hex, size_t hex_size, + unsigned char* bytes, size_t bytes_size) +{ + const unsigned char ht[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567 + 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>? + 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG + }; + const size_t ht_size = sizeof(ht); + + unsigned char b0; + unsigned char b1; + + memset(bytes, 0, bytes_size); + + for (int i = 0; (i < hex_size) && (i / 2 < bytes_size); i += 2) { + b0 = ((unsigned char)hex[i + 0] & 0x1f) ^ 0x10; + b1 = ((unsigned char)hex[i + 1] & 0x1f) ^ 0x10; + + if (b0 <= ht_size && b1 <= ht_size) { + bytes[i / 2] = (unsigned char)(ht[b0] << 4) | ht[b1]; + } + } +} + +int +omemo_decrypt_file(FILE* in, FILE* out, off_t file_size, const char* fragment) +{ + char nonce_hex[AESGCM_URL_NONCE_LEN]; + char key_hex[AESGCM_URL_KEY_LEN]; + + const int nonce_pos = 0; + const int key_pos = AESGCM_URL_NONCE_LEN; + + memcpy(nonce_hex, &(fragment[nonce_pos]), AESGCM_URL_NONCE_LEN); + memcpy(key_hex, &(fragment[key_pos]), AESGCM_URL_KEY_LEN); + + unsigned char nonce[OMEMO_AESGCM_NONCE_LENGTH]; + unsigned char* key = gcry_malloc_secure(OMEMO_AESGCM_KEY_LENGTH); + + _bytes_from_hex(nonce_hex, AESGCM_URL_NONCE_LEN, + nonce, OMEMO_AESGCM_NONCE_LENGTH); + _bytes_from_hex(key_hex, AESGCM_URL_KEY_LEN, + key, OMEMO_AESGCM_KEY_LENGTH); + + int crypt_res = aes256gcm_crypt_file(in, out, file_size, key, nonce, false); + + gcry_free(key); + + return crypt_res; +} + +int +omemo_parse_aesgcm_url(const char* aesgcm_url, + char** https_url, + char** fragment) +{ + CURLUcode ret; + CURLU* url = curl_url(); + + // Required to allow for the "aesgcm://" scheme that OMEMO Media Sharing + // uses. + unsigned int curl_flags = CURLU_NON_SUPPORT_SCHEME; + + ret = curl_url_set(url, CURLUPART_URL, aesgcm_url, curl_flags); + if (ret) { + goto out; + } + + ret = curl_url_get(url, CURLUPART_FRAGMENT, fragment, curl_flags); + if (ret) { + goto out; + } + + if (strlen(*fragment) != AESGCM_URL_NONCE_LEN + AESGCM_URL_KEY_LEN) { + goto out; + } + + ret = curl_url_set(url, CURLUPART_SCHEME, "https", curl_flags); + if (ret) { + goto out; + } + + ret = curl_url_get(url, CURLUPART_URL, https_url, curl_flags); + if (ret) { + goto out; + } + +out: + curl_url_cleanup(url); + return ret; +} diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index e875dadd..a0e89916 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -40,7 +40,9 @@ #define OMEMO_ERR_UNSUPPORTED_CRYPTO -10000 #define OMEMO_ERR_GCRYPT -20000 -#define OMEMO_AESGCM_URL_SCHEME "aesgcm" +#define OMEMO_AESGCM_NONCE_LENGTH 12 +#define OMEMO_AESGCM_KEY_LENGTH 32 +#define OMEMO_AESGCM_URL_SCHEME "aesgcm" typedef enum { PROF_OMEMOPOLICY_MANUAL, @@ -99,4 +101,6 @@ char* omemo_on_message_send(ProfWin* win, const char* const message, gboolean re char* omemo_on_message_recv(const char* const from, uint32_t sid, const unsigned char* const iv, size_t iv_len, GList* keys, const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted); char* omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res); +int omemo_decrypt_file(FILE* in, FILE* out, off_t file_size, const char* fragment); void omemo_free(void* a); +int omemo_parse_aesgcm_url(const char* aesgcm_url, char** https_url, char** fragment); diff --git a/src/tools/aesgcm_download.c b/src/tools/aesgcm_download.c new file mode 100644 index 00000000..693eabe7 --- /dev/null +++ b/src/tools/aesgcm_download.c @@ -0,0 +1,134 @@ +/* + * aesgcm_download.c + * vim: expandtab:ts=4:sts=4:sw=4 + * + * Copyright (C) 2012 - 2019 James Booth + * Copyright (C) 2020 William Wennerström + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see . + * + * In addition, as a special exception, the copyright holders give permission to + * link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. + * + * You must obey the GNU General Public License in all respects for all of the + * code used other than OpenSSL. If you modify file(s) with this exception, you + * may extend this exception to your version of the file(s), but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. If you delete this exception statement from all + * source files in the program, then also delete it here. + * + */ + +#define _GNU_SOURCE 1 + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "profanity.h" +#include "event/client_events.h" +#include "tools/aesgcm_download.h" +#include "omemo/omemo.h" +#include "config/preferences.h" +#include "ui/ui.h" +#include "ui/window.h" +#include "common.h" + +#define FALLBACK_MSG "" + +void* +aesgcm_file_get(void* userdata) +{ + AESGCMDownload* aesgcm_dl = (AESGCMDownload*)userdata; + + char* https_url = NULL; + char* fragment = NULL; + + if (omemo_parse_aesgcm_url(aesgcm_dl->url, &https_url, &fragment) != 0) { + http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->url, + "Download failed: Cannot parse URL."); + return NULL; + } + + int tmpfd; + char* tmpname = NULL; + if ((tmpfd = g_file_open_tmp("profanity.XXXXXX", &tmpname, NULL)) == -1) { + http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->url, + "Downloading '%s' failed: Unable to create " + "temporary ciphertext file for writing.", + https_url); + return NULL; + } + FILE* tmpfh = fdopen(tmpfd, "wb"); + + // Remove the file once it is closed. + remove(tmpname); + free(tmpname); + + HTTPDownload* http_dl = malloc(sizeof(HTTPDownload)); + http_dl->window = aesgcm_dl->window; + http_dl->worker = aesgcm_dl->worker; + http_dl->url = https_url; + http_dl->filehandle = tmpfh; + http_dl->close = 0; + + aesgcm_dl->http_dl = http_dl; + + // TODO: Verify result. + http_file_get(http_dl); + + // Force flush as the decrypt function will read from the same stream. + fflush(tmpfh); + rewind(tmpfh); + + int crypt_res = omemo_decrypt_file(tmpfh, aesgcm_dl->filehandle, + http_dl->bytes_received, fragment); + + fclose(tmpfh); + + if (crypt_res != 0) { + http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->url, + "Downloading '%s' failed: Failed to decrypt" + "file.", + https_url); + } + + fclose(aesgcm_dl->filehandle); + + return NULL; +} + +void +aesgcm_download_cancel_processes(ProfWin* window) +{ + http_download_cancel_processes(window); +} + +void +aesgcm_download_add_download(AESGCMDownload* aesgcm_dl) +{ + http_download_add_download(aesgcm_dl->http_dl); +} diff --git a/src/tools/aesgcm_download.h b/src/tools/aesgcm_download.h new file mode 100644 index 00000000..fc29a99e --- /dev/null +++ b/src/tools/aesgcm_download.h @@ -0,0 +1,66 @@ +/* + * aesgcm_download.h + * vim: expandtab:ts=4:sts=4:sw=4 + * + * Copyright (C) 2012 - 2019 James Booth + * Copyright (C) 2020 William Wennerström + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see . + * + * In addition, as a special exception, the copyright holders give permission to + * link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. + * + * You must obey the GNU General Public License in all respects for all of the + * code used other than OpenSSL. If you modify file(s) with this exception, you + * may extend this exception to your version of the file(s), but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. If you delete this exception statement from all + * source files in the program, then also delete it here. + * + */ + +#ifndef TOOLS_AESGCM_DOWNLOAD_H +#define TOOLS_AESGCM_DOWNLOAD_H + +#ifdef PLATFORM_CYGWIN +#define SOCKET int +#endif + +#include +#include +#include "tools/http_download.h" + +#include "ui/win_types.h" + +typedef struct aesgcm_download_t +{ + char* url; + FILE* filehandle; + ProfWin* window; + pthread_t worker; + HTTPDownload* http_dl; +} AESGCMDownload; + +void* aesgcm_file_get(void* userdata); + +void aesgcm_download_cancel_processes(ProfWin* window); +void aesgcm_download_add_download(AESGCMDownload* download); + +char* http_basename_from_url(const char* url); + +#endif diff --git a/src/tools/aesgcm_upload.c b/src/tools/aesgcm_upload.c new file mode 100644 index 00000000..e69de29b diff --git a/src/tools/aesgcm_upload.h b/src/tools/aesgcm_upload.h new file mode 100644 index 00000000..e69de29b diff --git a/src/tools/http_download.c b/src/tools/http_download.c index 09e6bb6e..a86af172 100644 --- a/src/tools/http_download.c +++ b/src/tools/http_download.c @@ -157,13 +157,12 @@ http_file_get(void* userdata) curl_easy_cleanup(curl); curl_global_cleanup(); - if (download->filehandle) { + if (download->filehandle && download->close) { fclose(download->filehandle); } pthread_mutex_lock(&lock); g_free(cert_path); - if (err) { char* msg; if (download->cancel) { @@ -237,3 +236,20 @@ http_basename_from_url(const char* url) return filename; } + +void +http_print_transfer_update(ProfWin* window, char* url, + const char* fmt, ...) +{ + va_list args; + + va_start(args, fmt); + char* msg; + if (vasprintf(&msg, fmt, args) == -1) { + msg = strdup(FALLBACK_MSG); + } + va_end(args); + + win_print_http_transfer(window, msg, url); + free(msg); +} diff --git a/src/tools/http_download.h b/src/tools/http_download.h index ba8b5023..797e1603 100644 --- a/src/tools/http_download.h +++ b/src/tools/http_download.h @@ -54,6 +54,7 @@ typedef struct http_download_t ProfWin* window; pthread_t worker; int cancel; + int close; } HTTPDownload; void* http_file_get(void* userdata); @@ -62,5 +63,7 @@ void http_download_cancel_processes(ProfWin* window); void http_download_add_download(HTTPDownload* download); char* http_basename_from_url(const char* url); +void http_print_transfer_update(ProfWin* window, char* url, + const char* fmt, ...); #endif -- cgit 1.4.1-2-gfad0 From 3d344cfeaa7708b5786e55d18af0cbcfc8ed25ab Mon Sep 17 00:00:00 2001 From: William Wennerström Date: Tue, 21 Jul 2020 10:34:29 +0200 Subject: Move common http tool code to http_common --- Makefile.am | 2 + src/tools/aesgcm_download.c | 1 + src/tools/aesgcm_download.h | 3 +- src/tools/http_common.c | 98 +++++++++++++++++++++++++++++++++++++++++++++ src/tools/http_common.h | 48 ++++++++++++++++++++++ src/tools/http_download.c | 52 +++--------------------- src/tools/http_download.h | 5 +-- 7 files changed, 156 insertions(+), 53 deletions(-) create mode 100644 src/tools/http_common.c create mode 100644 src/tools/http_common.h (limited to 'Makefile.am') diff --git a/Makefile.am b/Makefile.am index 5c34b35a..e6c38066 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,6 +41,8 @@ core_sources = \ src/command/cmd_ac.h src/command/cmd_ac.c \ src/tools/parser.c \ src/tools/parser.h \ + src/tools/http_common.c \ + src/tools/http_common.h \ src/tools/http_upload.c \ src/tools/http_upload.h \ src/tools/http_download.c \ diff --git a/src/tools/aesgcm_download.c b/src/tools/aesgcm_download.c index 6e8b89c5..6b60ba08 100644 --- a/src/tools/aesgcm_download.c +++ b/src/tools/aesgcm_download.c @@ -50,6 +50,7 @@ #include "profanity.h" #include "event/client_events.h" +#include "tools/http_common.h" #include "tools/aesgcm_download.h" #include "omemo/omemo.h" #include "config/preferences.h" diff --git a/src/tools/aesgcm_download.h b/src/tools/aesgcm_download.h index ebc8a5f9..e172b89a 100644 --- a/src/tools/aesgcm_download.h +++ b/src/tools/aesgcm_download.h @@ -43,6 +43,7 @@ #include #include +#include "tools/http_common.h" #include "tools/http_download.h" #include "ui/win_types.h" @@ -61,6 +62,4 @@ void* aesgcm_file_get(void* userdata); void aesgcm_download_cancel_processes(ProfWin* window); void aesgcm_download_add_download(AESGCMDownload* download); -char* http_basename_from_url(const char* url); - #endif diff --git a/src/tools/http_common.c b/src/tools/http_common.c new file mode 100644 index 00000000..df6f9a64 --- /dev/null +++ b/src/tools/http_common.c @@ -0,0 +1,98 @@ +/* + * http_common.c + * vim: expandtab:ts=4:sts=4:sw=4 + * + * Copyright (C) 2020 William Wennerström + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see . + * + * In addition, as a special exception, the copyright holders give permission to + * link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. + * + * You must obey the GNU General Public License in all respects for all of the + * code used other than OpenSSL. If you modify file(s) with this exception, you + * may extend this exception to your version of the file(s), but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. If you delete this exception statement from all + * source files in the program, then also delete it here. + * + */ + +#define _GNU_SOURCE 1 + +#include +#include +#include +#include + +#include "tools/http_common.h" + +#define FALLBACK_MSG "" + +char* +http_basename_from_url(const char* url) +{ + const char* default_name = "index.html"; + + GFile* file = g_file_new_for_uri(url); + char* filename = g_file_get_basename(file); + g_object_unref(file); + + if (g_strcmp0(filename, ".") == 0 + || g_strcmp0(filename, "..") == 0 + || g_strcmp0(filename, G_DIR_SEPARATOR_S) == 0) { + g_free(filename); + return strdup(default_name); + } + + return filename; +} + +void +http_print_transfer_update(ProfWin* window, char* url, + const char* fmt, ...) +{ + va_list args; + + va_start(args, fmt); + char* msg; + if (vasprintf(&msg, fmt, args) == -1) { + msg = strdup(FALLBACK_MSG); + } + va_end(args); + + win_update_entry_message(window, url, msg); + free(msg); +} + +void +http_print_transfer(ProfWin* window, char* url, + const char* fmt, ...) +{ + va_list args; + + va_start(args, fmt); + char* msg; + if (vasprintf(&msg, fmt, args) == -1) { + msg = strdup(FALLBACK_MSG); + } + va_end(args); + + win_print_http_transfer(window, msg, url); + free(msg); +} diff --git a/src/tools/http_common.h b/src/tools/http_common.h new file mode 100644 index 00000000..41f16200 --- /dev/null +++ b/src/tools/http_common.h @@ -0,0 +1,48 @@ +/* + * http_common.h + * vim: expandtab:ts=4:sts=4:sw=4 + * + * Copyright (C) 2020 William Wennerström + * + * This file is part of Profanity. + * + * Profanity is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Profanity 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Profanity. If not, see . + * + * In addition, as a special exception, the copyright holders give permission to + * link the code of portions of this program with the OpenSSL library under + * certain conditions as described in each individual source file, and + * distribute linked combinations including the two. + * + * You must obey the GNU General Public License in all respects for all of the + * code used other than OpenSSL. If you modify file(s) with this exception, you + * may extend this exception to your version of the file(s), but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. If you delete this exception statement from all + * source files in the program, then also delete it here. + * + */ + +#ifndef TOOLS_HTTP_COMMON_H +#define TOOLS_HTTP_COMMON_H + +#define _GNU_SOURCE 1 + +#include "ui/window.h" + +char* http_basename_from_url(const char* url); +void http_print_transfer(ProfWin* window, char* url, const char* fmt, ...); +void http_print_transfer_update(ProfWin* window, char* url, + const char* fmt, ...); + +#endif diff --git a/src/tools/http_download.c b/src/tools/http_download.c index 5859dc70..a470feec 100644 --- a/src/tools/http_download.c +++ b/src/tools/http_download.c @@ -56,8 +56,6 @@ #include "ui/window.h" #include "common.h" -#define FALLBACK_MSG "" - GSList* download_processes = NULL; static int @@ -84,12 +82,8 @@ _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultot dlperc = (100 * dlnow) / dltotal; } - char* msg; - if (asprintf(&msg, "Downloading '%s': %d%%", download->url, dlperc) == -1) { - msg = strdup(FALLBACK_MSG); - } - win_update_entry_message(download->window, download->url, msg); - free(msg); + http_print_transfer_update(download->window, download->url, + "Downloading '%s': %d%%", download->url, dlperc); pthread_mutex_unlock(&lock); @@ -121,8 +115,8 @@ http_file_get(void* userdata) download->bytes_received = 0; pthread_mutex_lock(&lock); - http_print_transfer_update(download->window, download->url, - "Downloading '%s': 0%%", download->url); + http_print_transfer(download->window, download->url, + "Downloading '%s': 0%%", download->url); FILE* outfh = fopen(download->filename, "wb"); if (outfh == NULL) { @@ -188,7 +182,7 @@ http_file_get(void* userdata) } else { if (!download->cancel) { http_print_transfer_update(download->window, download->url, - "Downloading '%s': 100%%", + "Downloading '%s': done", download->url); win_mark_received(download->window, download->url); } @@ -223,39 +217,3 @@ http_download_add_download(HTTPDownload* download) { download_processes = g_slist_append(download_processes, download); } - -char* -http_basename_from_url(const char* url) -{ - const char* default_name = "index.html"; - - GFile* file = g_file_new_for_uri(url); - char* filename = g_file_get_basename(file); - g_object_unref(file); - - if (g_strcmp0(filename, ".") == 0 - || g_strcmp0(filename, "..") == 0 - || g_strcmp0(filename, G_DIR_SEPARATOR_S) == 0) { - g_free(filename); - return strdup(default_name); - } - - return filename; -} - -void -http_print_transfer_update(ProfWin* window, char* url, - const char* fmt, ...) -{ - va_list args; - - va_start(args, fmt); - char* msg; - if (vasprintf(&msg, fmt, args) == -1) { - msg = strdup(FALLBACK_MSG); - } - va_end(args); - - win_print_http_transfer(window, msg, url); - free(msg); -} diff --git a/src/tools/http_download.h b/src/tools/http_download.h index 077e3e3d..b6ce42ca 100644 --- a/src/tools/http_download.h +++ b/src/tools/http_download.h @@ -45,6 +45,7 @@ #include #include "ui/win_types.h" +#include "tools/http_common.h" typedef struct http_download_t { @@ -61,8 +62,4 @@ void* http_file_get(void* userdata); void http_download_cancel_processes(ProfWin* window); void http_download_add_download(HTTPDownload* download); -char* http_basename_from_url(const char* url); -void http_print_transfer_update(ProfWin* window, char* url, - const char* fmt, ...); - #endif -- cgit 1.4.1-2-gfad0 From be62b446f778ba6c064d6e054dfb7b5eacb1f1ae Mon Sep 17 00:00:00 2001 From: William Wennerström Date: Tue, 21 Jul 2020 11:36:09 +0200 Subject: Add stubs --- Makefile.am | 2 ++ src/command/cmd_funcs.c | 22 ++++++++++++++-------- tests/unittests/tools/stub_aesgcm_download.c | 23 +++++++++++++++++++++++ tests/unittests/tools/stub_http_common.c | 16 ++++++++++++++++ tests/unittests/tools/stub_http_download.c | 2 -- 5 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 tests/unittests/tools/stub_aesgcm_download.c create mode 100644 tests/unittests/tools/stub_http_common.c (limited to 'Makefile.am') diff --git a/Makefile.am b/Makefile.am index e6c38066..9f2a99de 100644 --- a/Makefile.am +++ b/Makefile.am @@ -126,8 +126,10 @@ unittest_sources = \ tests/unittests/log/stub_log.c \ tests/unittests/database/stub_database.c \ tests/unittests/config/stub_accounts.c \ + tests/unittests/tools/stub_http_common.c \ tests/unittests/tools/stub_http_upload.c \ tests/unittests/tools/stub_http_download.c \ + tests/unittests/tools/stub_aesgcm_download.c \ tests/unittests/helpers.c tests/unittests/helpers.h \ tests/unittests/test_form.c tests/unittests/test_form.h \ tests/unittests/test_common.c tests/unittests/test_common.h \ diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index ada53f9d..c6557159 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -69,7 +69,6 @@ #include "event/client_events.h" #include "tools/http_upload.h" #include "tools/http_download.h" -#include "tools/aesgcm_download.h" #include "tools/autocomplete.h" #include "tools/parser.h" #include "tools/bookmark_ignore.h" @@ -97,6 +96,7 @@ #ifdef HAVE_OMEMO #include "omemo/omemo.h" #include "xmpp/omemo.h" +#include "tools/aesgcm_download.h" #endif #ifdef HAVE_GTK @@ -9168,6 +9168,7 @@ _url_save_fallback_method(ProfWin* window, const char* url, const char* filename { gchar* scheme = g_uri_parse_scheme(url); +#ifdef HAVE_OMEMO if (g_strcmp0(scheme, "aesgcm") == 0) { AESGCMDownload* download = malloc(sizeof(AESGCMDownload)); download->window = window; @@ -9176,15 +9177,20 @@ _url_save_fallback_method(ProfWin* window, const char* url, const char* filename pthread_create(&(download->worker), NULL, &aesgcm_file_get, download); aesgcm_download_add_download(download); - } else { - HTTPDownload* download = malloc(sizeof(HTTPDownload)); - download->window = window; - download->url = strdup(url); - download->filename = strdup(filename); - pthread_create(&(download->worker), NULL, &http_file_get, download); - http_download_add_download(download); + free(scheme); + + return; } +#endif + + HTTPDownload* download = malloc(sizeof(HTTPDownload)); + download->window = window; + download->url = strdup(url); + download->filename = strdup(filename); + + pthread_create(&(download->worker), NULL, &http_file_get, download); + http_download_add_download(download); free(scheme); } diff --git a/tests/unittests/tools/stub_aesgcm_download.c b/tests/unittests/tools/stub_aesgcm_download.c new file mode 100644 index 00000000..58696e80 --- /dev/null +++ b/tests/unittests/tools/stub_aesgcm_download.c @@ -0,0 +1,23 @@ +#ifndef TOOLS_AESGCM_DOWNLOAD_H +#define TOOLS_AESGCM_DOWNLOAD_H + +#include + +typedef struct prof_win_t ProfWin; +typedef struct http_download_t HTTPDownload; + +typedef struct aesgcm_download_t +{ + char* url; + char* filename; + ProfWin* window; + pthread_t worker; + HTTPDownload* http_dl; +} AESGCMDownload; + +void* aesgcm_file_get(void* userdata); + +void aesgcm_download_cancel_processes(ProfWin* window); +void aesgcm_download_add_download(AESGCMDownload* download); + +#endif diff --git a/tests/unittests/tools/stub_http_common.c b/tests/unittests/tools/stub_http_common.c new file mode 100644 index 00000000..23e0a23f --- /dev/null +++ b/tests/unittests/tools/stub_http_common.c @@ -0,0 +1,16 @@ +#ifndef TOOLS_HTTP_COMMON_H +#define TOOLS_HTTP_COMMON_H + +typedef struct prof_win_t ProfWin; + +char* +http_basename_from_url(const char* url) +{ + return ""; +} + +void http_print_transfer(ProfWin* window, char* url, const char* fmt, ...); +void http_print_transfer_update(ProfWin* window, char* url, + const char* fmt, ...); + +#endif diff --git a/tests/unittests/tools/stub_http_download.c b/tests/unittests/tools/stub_http_download.c index 202c9cbf..fb2cb1b8 100644 --- a/tests/unittests/tools/stub_http_download.c +++ b/tests/unittests/tools/stub_http_download.c @@ -23,6 +23,4 @@ void* http_file_get(void* userdata); void http_download_cancel_processes(ProfWin* window); void http_download_add_download(HTTPDownload* download); -char* http_filename_from_url(const char* url); - #endif -- cgit 1.4.1-2-gfad0 From 1bb6cecee69d5167220a18cc4c125c215784de66 Mon Sep 17 00:00:00 2001 From: William Wennerström Date: Tue, 21 Jul 2020 13:11:50 +0200 Subject: Fix stubs and move some tests to http_common --- Makefile.am | 3 +- src/tools/http_common.c | 28 +++++------ src/tools/http_common.h | 2 - tests/unittests/test_http_common.c | 75 ++++++++++++++++++++++++++++ tests/unittests/test_http_common.h | 1 + tests/unittests/test_http_download.c | 75 ---------------------------- tests/unittests/test_http_download.h | 1 - tests/unittests/tools/stub_aesgcm_download.c | 10 ++-- tests/unittests/tools/stub_http_common.c | 16 ------ tests/unittests/tools/stub_http_download.c | 5 -- tests/unittests/tools/stub_http_upload.c | 3 +- tests/unittests/unittests.c | 2 +- 12 files changed, 98 insertions(+), 123 deletions(-) create mode 100644 tests/unittests/test_http_common.c create mode 100644 tests/unittests/test_http_common.h delete mode 100644 tests/unittests/test_http_download.c delete mode 100644 tests/unittests/test_http_download.h delete mode 100644 tests/unittests/tools/stub_http_common.c (limited to 'Makefile.am') diff --git a/Makefile.am b/Makefile.am index 9f2a99de..aeb52abd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -126,7 +126,6 @@ unittest_sources = \ tests/unittests/log/stub_log.c \ tests/unittests/database/stub_database.c \ tests/unittests/config/stub_accounts.c \ - tests/unittests/tools/stub_http_common.c \ tests/unittests/tools/stub_http_upload.c \ tests/unittests/tools/stub_http_download.c \ tests/unittests/tools/stub_aesgcm_download.c \ @@ -156,7 +155,7 @@ unittest_sources = \ tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \ tests/unittests/test_callbacks.c tests/unittests/test_callbacks.h \ tests/unittests/test_plugins_disco.c tests/unittests/test_plugins_disco.h \ - tests/unittests/test_http_download.c tests/unittests/test_http_download.h \ + tests/unittests/test_http_common.c tests/unittests/test_http_common.h \ tests/unittests/unittests.c functionaltest_sources = \ diff --git a/src/tools/http_common.c b/src/tools/http_common.c index df6f9a64..dfd0aa87 100644 --- a/src/tools/http_common.c +++ b/src/tools/http_common.c @@ -64,35 +64,31 @@ http_basename_from_url(const char* url) } void -http_print_transfer_update(ProfWin* window, char* url, - const char* fmt, ...) +http_print_transfer_update(ProfWin* window, char* url, const char* fmt, ...) { va_list args; va_start(args, fmt); - char* msg; - if (vasprintf(&msg, fmt, args) == -1) { - msg = strdup(FALLBACK_MSG); - } + GString* msg = g_string_new(FALLBACK_MSG); + g_string_vprintf(msg, fmt, args); va_end(args); - win_update_entry_message(window, url, msg); - free(msg); + win_update_entry_message(window, url, msg->str); + + g_string_free(msg, TRUE); } void -http_print_transfer(ProfWin* window, char* url, - const char* fmt, ...) +http_print_transfer(ProfWin* window, char* url, const char* fmt, ...) { va_list args; va_start(args, fmt); - char* msg; - if (vasprintf(&msg, fmt, args) == -1) { - msg = strdup(FALLBACK_MSG); - } + GString* msg = g_string_new(FALLBACK_MSG); + g_string_vprintf(msg, fmt, args); va_end(args); - win_print_http_transfer(window, msg, url); - free(msg); + win_print_http_transfer(window, msg->str, url); + + g_string_free(msg, TRUE); } diff --git a/src/tools/http_common.h b/src/tools/http_common.h index 41f16200..3fbc6fcd 100644 --- a/src/tools/http_common.h +++ b/src/tools/http_common.h @@ -36,8 +36,6 @@ #ifndef TOOLS_HTTP_COMMON_H #define TOOLS_HTTP_COMMON_H -#define _GNU_SOURCE 1 - #include "ui/window.h" char* http_basename_from_url(const char* url); diff --git a/tests/unittests/test_http_common.c b/tests/unittests/test_http_common.c new file mode 100644 index 00000000..195f370b --- /dev/null +++ b/tests/unittests/test_http_common.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "tools/http_common.c" + +typedef struct +{ + char* url; + char* basename; +} url_test_t; + +void +http_basename_from_url_td(void** state) +{ + int num_tests = 11; + url_test_t tests[] = { + (url_test_t){ + .url = "https://host.test/image.jpeg", + .basename = "image.jpeg", + }, + (url_test_t){ + .url = "https://host.test/image.jpeg#somefragment", + .basename = "image.jpeg", + }, + (url_test_t){ + .url = "https://host.test/image.jpeg?query=param", + .basename = "image.jpeg", + }, + (url_test_t){ + .url = "https://host.test/image.jpeg?query=param&another=one", + .basename = "image.jpeg", + }, + (url_test_t){ + .url = "https://host.test/images/", + .basename = "images", + }, + (url_test_t){ + .url = "https://host.test/images/../../file", + .basename = "file", + }, + (url_test_t){ + .url = "https://host.test/images/../../file/..", + .basename = "index.html", + }, + (url_test_t){ + .url = "https://host.test/images/..//", + .basename = "index.html", + }, + (url_test_t){ + .url = "https://host.test/", + .basename = "index.html", + }, + (url_test_t){ + .url = "https://host.test", + .basename = "index.html", + }, + (url_test_t){ + .url = "aesgcm://host.test", + .basename = "index.html", + }, + }; + + char* basename; + for (int i = 0; i < num_tests; i++) { + basename = http_basename_from_url(tests[i].url); + assert_string_equal(basename, tests[i].basename); + } +} diff --git a/tests/unittests/test_http_common.h b/tests/unittests/test_http_common.h new file mode 100644 index 00000000..a1c62a7f --- /dev/null +++ b/tests/unittests/test_http_common.h @@ -0,0 +1 @@ +void http_basename_from_url_td(void** state); diff --git a/tests/unittests/test_http_download.c b/tests/unittests/test_http_download.c deleted file mode 100644 index 96d45d03..00000000 --- a/tests/unittests/test_http_download.c +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#include "tools/http_download.h" - -typedef struct -{ - char* url; - char* basename; -} url_test_t; - -void -http_basename_from_url_td(void** state) -{ - int num_tests = 11; - url_test_t tests[] = { - (url_test_t){ - .url = "https://host.test/image.jpeg", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/image.jpeg#somefragment", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/image.jpeg?query=param", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/image.jpeg?query=param&another=one", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/images/", - .basename = "images", - }, - (url_test_t){ - .url = "https://host.test/images/../../file", - .basename = "file", - }, - (url_test_t){ - .url = "https://host.test/images/../../file/..", - .basename = "index.html", - }, - (url_test_t){ - .url = "https://host.test/images/..//", - .basename = "index.html", - }, - (url_test_t){ - .url = "https://host.test/", - .basename = "index.html", - }, - (url_test_t){ - .url = "https://host.test", - .basename = "index.html", - }, - (url_test_t){ - .url = "aesgcm://host.test", - .basename = "index.html", - }, - }; - - char* basename; - for (int i = 0; i < num_tests; i++) { - basename = http_basename_from_url(tests[i].url); - assert_string_equal(basename, tests[i].basename); - } -} diff --git a/tests/unittests/test_http_download.h b/tests/unittests/test_http_download.h deleted file mode 100644 index a1c62a7f..00000000 --- a/tests/unittests/test_http_download.h +++ /dev/null @@ -1 +0,0 @@ -void http_basename_from_url_td(void** state); diff --git a/tests/unittests/tools/stub_aesgcm_download.c b/tests/unittests/tools/stub_aesgcm_download.c index 58696e80..6f4cc0ce 100644 --- a/tests/unittests/tools/stub_aesgcm_download.c +++ b/tests/unittests/tools/stub_aesgcm_download.c @@ -15,9 +15,13 @@ typedef struct aesgcm_download_t HTTPDownload* http_dl; } AESGCMDownload; -void* aesgcm_file_get(void* userdata); +void* +aesgcm_file_get(void* userdata) +{ + return NULL; +}; -void aesgcm_download_cancel_processes(ProfWin* window); -void aesgcm_download_add_download(AESGCMDownload* download); +void aesgcm_download_cancel_processes(ProfWin* window){}; +void aesgcm_download_add_download(AESGCMDownload* download){}; #endif diff --git a/tests/unittests/tools/stub_http_common.c b/tests/unittests/tools/stub_http_common.c deleted file mode 100644 index 23e0a23f..00000000 --- a/tests/unittests/tools/stub_http_common.c +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef TOOLS_HTTP_COMMON_H -#define TOOLS_HTTP_COMMON_H - -typedef struct prof_win_t ProfWin; - -char* -http_basename_from_url(const char* url) -{ - return ""; -} - -void http_print_transfer(ProfWin* window, char* url, const char* fmt, ...); -void http_print_transfer_update(ProfWin* window, char* url, - const char* fmt, ...); - -#endif diff --git a/tests/unittests/tools/stub_http_download.c b/tests/unittests/tools/stub_http_download.c index fb2cb1b8..5fa1c46e 100644 --- a/tests/unittests/tools/stub_http_download.c +++ b/tests/unittests/tools/stub_http_download.c @@ -18,9 +18,4 @@ typedef struct http_download_t int cancel; } HTTPDownload; -void* http_file_get(void* userdata); - -void http_download_cancel_processes(ProfWin* window); -void http_download_add_download(HTTPDownload* download); - #endif diff --git a/tests/unittests/tools/stub_http_upload.c b/tests/unittests/tools/stub_http_upload.c index 25a81708..1b79e02d 100644 --- a/tests/unittests/tools/stub_http_upload.c +++ b/tests/unittests/tools/stub_http_upload.c @@ -20,8 +20,6 @@ typedef struct http_upload_t int cancel; } HTTPUpload; -//GSList *upload_processes; - void* http_file_put(void* userdata) { @@ -33,6 +31,7 @@ file_mime_type(const char* const file_name) { return NULL; } + off_t file_size(const char* const file_name) { diff --git a/tests/unittests/unittests.c b/tests/unittests/unittests.c index 06c1b307..cab99bf5 100644 --- a/tests/unittests/unittests.c +++ b/tests/unittests/unittests.c @@ -38,7 +38,7 @@ #include "test_form.h" #include "test_callbacks.h" #include "test_plugins_disco.h" -#include "test_http_download.h" +#include "test_http_common.h" int main(int argc, char* argv[]) -- cgit 1.4.1-2-gfad0 From 3a6597ee2967f91f49a1b4e17cf0595f37064587 Mon Sep 17 00:00:00 2001 From: William Wennerström Date: Thu, 3 Dec 2020 16:43:07 +0100 Subject: Refactor for threaded external executable for built-in download methods --- Makefile.am | 5 +- src/command/cmd_funcs.c | 289 ++++++++++++++++++-------------------------- src/common.c | 20 +++ src/common.h | 1 + src/config/files.h | 19 +-- src/config/preferences.c | 49 +------- src/config/preferences.h | 1 - src/omemo/omemo.c | 1 - src/omemo/omemo.h | 1 + src/tools/aesgcm_download.c | 21 ++++ src/tools/aesgcm_download.h | 1 + src/tools/http_common.h | 4 +- src/tools/http_download.c | 20 +++ src/tools/http_download.h | 1 + src/ui/console.c | 4 +- 15 files changed, 203 insertions(+), 234 deletions(-) (limited to 'Makefile.am') diff --git a/Makefile.am b/Makefile.am index aeb52abd..9b2f75c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,8 +47,6 @@ core_sources = \ src/tools/http_upload.h \ src/tools/http_download.c \ src/tools/http_download.h \ - src/tools/aesgcm_download.c \ - src/tools/aesgcm_download.h \ src/tools/bookmark_ignore.c \ src/tools/bookmark_ignore.h \ src/tools/autocomplete.c src/tools/autocomplete.h \ @@ -200,7 +198,8 @@ otr4_sources = \ omemo_sources = \ src/omemo/omemo.h src/omemo/omemo.c src/omemo/crypto.h src/omemo/crypto.c \ - src/omemo/store.h src/omemo/store.c src/xmpp/omemo.h src/xmpp/omemo.c + src/omemo/store.h src/omemo/store.c src/xmpp/omemo.h src/xmpp/omemo.c \ + src/tools/aesgcm_download.h src/tools/aesgcm_download.c omemo_unittest_sources = \ tests/unittests/omemo/stub_omemo.c diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index c6557159..88461f1d 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -60,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" @@ -1089,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 { @@ -9058,169 +9059,59 @@ cmd_slashguard(ProfWin* window, const char* const command, gchar** args) return TRUE; } -gboolean -cmd_url_open(ProfWin* window, const char* const command, gchar** args) +#ifdef HAVE_OMEMO +void +_url_aesgcm_method(ProfWin* window, const char* cmd_template, const char* url, const char* filename) { - if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) { - cons_show("url open not supported in this window"); - return TRUE; - } - - if (args[1] == NULL) { - cons_bad_cmd_usage(command); - return TRUE; - } - - gboolean require_save = false; - - gchar* fileStart = g_strrstr(args[1], "/"); - if (fileStart == 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); - } - } - - 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); - } - - 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]); - 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); - } - - 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++; - } - - if (!call_external(argv, NULL, NULL)) { - cons_show_error("Unable to open url: check the logs for more information."); - } - - if (require_save) { - g_unlink("/tmp/profanity.tmp"); + 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; } - g_strfreev(argv); - g_free(suffix_cmd); - - return TRUE; -} - -void -_url_open_fallback_method(ProfWin* window, const char* url, const char* filename) -{ - // TODO(wstrm): Use _url_save_fallback_method?. - // We probably want to do the cmd_url_open in a separate thread and wait for - // the transfer to be finished before calling call_external. + pthread_create(&(download->worker), NULL, &aesgcm_file_get, download); + aesgcm_download_add_download(download); } +#endif void -_url_save_fallback_method(ProfWin* window, const char* url, const char* filename) +_url_http_method(ProfWin* window, const char* cmd_template, const char* url, const char* filename) { - gchar* scheme = g_uri_parse_scheme(url); - -#ifdef HAVE_OMEMO - if (g_strcmp0(scheme, "aesgcm") == 0) { - AESGCMDownload* download = malloc(sizeof(AESGCMDownload)); - download->window = window; - download->url = strdup(url); - download->filename = strdup(filename); - - pthread_create(&(download->worker), NULL, &aesgcm_file_get, download); - aesgcm_download_add_download(download); - - free(scheme); - - return; - } -#endif 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); - - free(scheme); } void -_url_save_external_method(const char* scheme_cmd, const char* url, const char* filename) +_url_external_method(const char* cmd_template, const char* url, const char* filename) { - gchar** argv = g_strsplit(scheme_cmd, " ", 0); - - 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(url); - } else if (0 == g_strcmp0(argv[num_args], "%p")) { - g_free(argv[num_args]); - argv[num_args] = strdup(filename); - } - num_args++; - } + gchar** argv = format_call_external_argv(cmd_template, url, filename); if (!call_external(argv, NULL, NULL)) { - cons_show_error("Unable to save url: check the logs for more information."); + cons_show_error("Unable to call external executable for url: check the logs for more information."); } else { - cons_show("URL '%s' has been saved to '%s'.", url, filename); + cons_show("URL '%s' has been called with '%s'.", cmd_template); } + + g_strfreev(argv); } char* -_make_unique_filename(const char* filename) +_unique_filename(const char* filename) { char* unique = strdup(filename); @@ -9242,29 +9133,9 @@ _make_unique_filename(const char* filename) return unique; } -gboolean -cmd_url_save(ProfWin* window, const char* const command, gchar** args) +char* +_unique_filename_from_url(char* url, char* path) { - if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) { - cons_show_error("`/url save` is not supported in this window."); - return TRUE; - } - - if (args[1] == NULL) { - cons_bad_cmd_usage(command); - return TRUE; - } - - gchar* url = args[1]; - gchar* path = g_strdup(args[2]); - - gchar* scheme = g_uri_parse_scheme(url); - if (scheme == NULL) { - cons_show("URL '%s' is not valid.", url); - g_free(url); - return TRUE; - } - gchar* directory = NULL; gchar* basename = NULL; if (path != NULL) { @@ -9279,7 +9150,7 @@ cmd_url_save(ProfWin* window, const char* const command, gchar** args) if (!g_file_test(directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { cons_show_error("Directory '%s' does not exist or is not a directory.", directory); - return TRUE; + return NULL; } if (!basename) { @@ -9289,30 +9160,106 @@ cmd_url_save(ProfWin* window, const char* const command, gchar** args) char* filename = NULL; filename = g_build_filename(directory, basename, NULL); - char* unique_filename = _make_unique_filename(filename); + char* unique_filename = _unique_filename(filename); if (!unique_filename) { cons_show_error("Failed to generate an unique filename from '%s'.", filename); free(filename); - return TRUE; + return NULL; } free(filename); - filename = unique_filename; + return unique_filename; +} + +gboolean +cmd_url_open(ProfWin* window, const char* const command, gchar** args) +{ + if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) { + cons_show("url open not supported in this window"); + return TRUE; + } + + gchar* url = args[1]; + if (url == NULL) { + cons_bad_cmd_usage(command); + return TRUE; + } + + gchar* scheme = g_uri_parse_scheme(url); + if (scheme == NULL) { + cons_show("URL '%s' is not valid.", args[1]); + return TRUE; + } + + char* cmd_template = prefs_get_string_with_option(PREF_URL_OPEN_CMD, scheme); + if (cmd_template == NULL) { + cons_show("No default open command found in url open preferences"); + return TRUE; + } + +#ifdef HAVE_OMEMO + // OMEMO URLs (aesgcm://) must be saved and decrypted before being opened. + if (0 == g_strcmp0(scheme, "aesgcm")) { + char* filename = _unique_filename_from_url(url, files_get_data_path(DIR_DOWNLOADS)); + _url_aesgcm_method(window, cmd_template, url, filename); - gchar* scheme_cmd = prefs_get_string_with_option(PREF_URL_SAVE_CMD, scheme); - if (scheme_cmd == NULL) { + free(filename); + goto out; + } +#endif + + _url_external_method(cmd_template, url, NULL); + +#ifdef HAVE_OMEMO +out: +#endif + free(cmd_template); + free(scheme); + + return TRUE; +} + +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_error("`/url save` is not supported in this window."); + return TRUE; + } + + if (args[1] == NULL) { + cons_bad_cmd_usage(command); + return TRUE; + } + + gchar* url = args[1]; + gchar* path = g_strdup(args[2]); + + gchar* scheme = g_uri_parse_scheme(url); + if (scheme == NULL) { + cons_show("URL '%s' is not valid.", args[1]); + return TRUE; + } + + char* filename = _unique_filename_from_url(url, path); + + char* cmd_template = prefs_get_string_with_option(PREF_URL_SAVE_CMD, scheme); + if (cmd_template == NULL) { if (g_strcmp0(scheme, "http") == 0 - || g_strcmp0(scheme, "https") == 0 - || g_strcmp0(scheme, "aesgcm") == 0) { - _url_save_fallback_method(window, url, filename); + || g_strcmp0(scheme, "https") == 0) { + _url_http_method(window, url, filename, cmd_template); +#ifdef HAVE_OMEMO + } else if (g_strcmp0(scheme, "aesgcm") == 0) { + _url_aesgcm_method(window, url, filename, cmd_template); +#endif } else { cons_show_error("No download method defined for the scheme '%s'.", scheme); } } else { - _url_save_external_method(scheme_cmd, url, filename); + _url_external_method(cmd_template, url, filename); } - g_free(scheme_cmd); + free(cmd_template); return TRUE; } diff --git a/src/common.c b/src/common.c index c0bd6525..079c3af5 100644 --- a/src/common.c +++ b/src/common.c @@ -555,3 +555,23 @@ call_external(gchar** argv, gchar*** const output_ptr, gchar*** const error_ptr) return TRUE; } + +gchar** +format_call_external_argv(const char* template, const char* url, const char* filename) +{ + gchar** argv = g_strsplit(template, " ", 0); + + guint num_args = 0; + while (argv[num_args]) { + if (0 == g_strcmp0(argv[num_args], "%u") && url != NULL) { + g_free(argv[num_args]); + argv[num_args] = g_strdup(url); + } else if (0 == g_strcmp0(argv[num_args], "%p") && filename != NULL) { + g_free(argv[num_args]); + argv[num_args] = strdup(filename); + } + num_args++; + } + + return argv; +} diff --git a/src/common.h b/src/common.h index 13332f7a..b56d31d4 100644 --- a/src/common.h +++ b/src/common.h @@ -105,5 +105,6 @@ void get_file_paths_recursive(const char* directory, GSList** contents); char* get_random_string(int length); gboolean call_external(gchar** argv, gchar*** const output_ptr, gchar*** const error_ptr); +gchar** format_call_external_argv(const char* template, const char* url, const char* filename); #endif diff --git a/src/config/files.h b/src/config/files.h index d5c96b0f..42499663 100644 --- a/src/config/files.h +++ b/src/config/files.h @@ -48,15 +48,16 @@ #define FILE_PROFANITY_IDENTIFIER "profident" #define FILE_BOOKMARK_AUTOJOIN_IGNORE "bookmark_ignore" -#define DIR_THEMES "themes" -#define DIR_ICONS "icons" -#define DIR_SCRIPTS "scripts" -#define DIR_CHATLOGS "chatlogs" -#define DIR_OTR "otr" -#define DIR_PGP "pgp" -#define DIR_OMEMO "omemo" -#define DIR_PLUGINS "plugins" -#define DIR_DATABASE "database" +#define DIR_THEMES "themes" +#define DIR_ICONS "icons" +#define DIR_SCRIPTS "scripts" +#define DIR_CHATLOGS "chatlogs" +#define DIR_OTR "otr" +#define DIR_PGP "pgp" +#define DIR_OMEMO "omemo" +#define DIR_PLUGINS "plugins" +#define DIR_DATABASE "database" +#define DIR_DOWNLOADS "downloads" void files_create_directories(void); diff --git a/src/config/preferences.c b/src/config/preferences.c index c7a74429..4b524fcf 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -81,7 +81,6 @@ static const char* _get_group(preference_t pref); static const char* _get_key(preference_t pref); static gboolean _get_default_boolean(preference_t pref); static char* _get_default_string(preference_t pref); -static char** _get_default_string_list(preference_t pref); static void _prefs_load(void) @@ -544,33 +543,6 @@ prefs_get_string_with_option(preference_t pref, gchar* option) return result; } -gchar** -prefs_get_string_list_with_option(preference_t pref, gchar* option) -{ - const char* group = _get_group(pref); - const char* key = _get_key(pref); - char** def = _get_default_string_list(pref); - - gchar** result = g_key_file_get_locale_string_list(prefs, group, key, option, NULL, NULL); - if (result) { - g_strfreev(def); - return result; - } - - result = g_key_file_get_string_list(prefs, group, key, NULL, NULL); - if (result) { - g_strfreev(def); - return result; - } - - if (def) { - return def; - } else { - g_strfreev(def); - return NULL; - } -} - void prefs_set_string(preference_t pref, char* value) { @@ -1893,6 +1865,7 @@ _get_group(preference_t pref) return PREF_GROUP_LOGGING; case PREF_AVATAR_CMD: case PREF_URL_OPEN_CMD: + return PREF_GROUP_EXECUTABLES; case PREF_URL_SAVE_CMD: return PREF_GROUP_EXECUTABLES; case PREF_AUTOAWAY_CHECK: @@ -2318,24 +2291,10 @@ _get_default_string(preference_t pref) return "false"; case PREF_AVATAR_CMD: return "xdg-open"; - default: - return NULL; - } -} - -// the default setting for a string list type preference -// if it is not specified in .profrc -static char** -_get_default_string_list(preference_t pref) -{ - char** str_array = NULL; - - switch (pref) { case PREF_URL_OPEN_CMD: - str_array = g_malloc0(3); - str_array[0] = g_strdup("false"); - str_array[1] = g_strdup("xdg-open %u"); - return str_array; + return "xdg-open %u"; + case PREF_URL_SAVE_CMD: + return NULL; // Default to built-in method. default: return NULL; } diff --git a/src/config/preferences.h b/src/config/preferences.h index 141d8fce..bfad7d6b 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -320,7 +320,6 @@ gboolean prefs_get_boolean(preference_t pref); void prefs_set_boolean(preference_t pref, gboolean value); char* prefs_get_string(preference_t pref); char* prefs_get_string_with_option(preference_t pref, gchar* option); -gchar** prefs_get_string_list_with_option(preference_t pref, gchar* option); void prefs_set_string(preference_t pref, char* value); void prefs_set_string_with_option(preference_t pref, char* option, char* value); void prefs_set_string_list_with_option(preference_t pref, char* option, const gchar* const* values); diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index 2e698591..22ada3a8 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -45,7 +45,6 @@ #include #include #include -#include #include "config/account.h" #include "config/files.h" diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h index b8d84498..8c17f48d 100644 --- a/src/omemo/omemo.h +++ b/src/omemo/omemo.h @@ -33,6 +33,7 @@ * */ #include +#include #include "ui/ui.h" #include "config/account.h" diff --git a/src/tools/aesgcm_download.c b/src/tools/aesgcm_download.c index d6a85d06..d75cabe3 100644 --- a/src/tools/aesgcm_download.c +++ b/src/tools/aesgcm_download.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "profanity.h" #include "event/client_events.h" @@ -146,8 +147,28 @@ aesgcm_file_get(void* userdata) free(https_url); free(fragment); + if (aesgcm_dl->cmd_template != NULL) { + gchar** argv = format_call_external_argv(aesgcm_dl->cmd_template, + aesgcm_dl->url, + aesgcm_dl->filename); + + // TODO(wstrm): Log the error. + if (!call_external(argv, NULL, NULL)) { + http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->url, + "Downloading '%s' failed: Unable to call " + "command '%s' with file at '%s' (%s).", + aesgcm_dl->url, + aesgcm_dl->cmd_template, + aesgcm_dl->filename, + "TODO(wstrm): Log the error"); + } + + g_strfreev(argv); + } + free(aesgcm_dl->filename); free(aesgcm_dl->url); + free(aesgcm_dl->cmd_template); free(aesgcm_dl); return NULL; diff --git a/src/tools/aesgcm_download.h b/src/tools/aesgcm_download.h index e172b89a..c0096f1d 100644 --- a/src/tools/aesgcm_download.h +++ b/src/tools/aesgcm_download.h @@ -52,6 +52,7 @@ typedef struct aesgcm_download_t { char* url; char* filename; + char* cmd_template; ProfWin* window; pthread_t worker; HTTPDownload* http_dl; diff --git a/src/tools/http_common.h b/src/tools/http_common.h index 3fbc6fcd..c0a553de 100644 --- a/src/tools/http_common.h +++ b/src/tools/http_common.h @@ -40,7 +40,7 @@ char* http_basename_from_url(const char* url); void http_print_transfer(ProfWin* window, char* url, const char* fmt, ...); -void http_print_transfer_update(ProfWin* window, char* url, - const char* fmt, ...); +void http_print_transfer_update(ProfWin* window, char* url, const char* fmt, ...); +gchar** http_format_external_argv(const char* cmd, const char* url, const char* filename); #endif diff --git a/src/tools/http_download.c b/src/tools/http_download.c index d14ab0e8..ef7e2906 100644 --- a/src/tools/http_download.c +++ b/src/tools/http_download.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "profanity.h" #include "event/client_events.h" @@ -187,6 +188,25 @@ http_file_get(void* userdata) download_processes = g_slist_remove(download_processes, download); pthread_mutex_unlock(&lock); + if (download->cmd_template != NULL) { + gchar** argv = format_call_external_argv(download->cmd_template, + download->url, + download->filename); + + // TODO(wstrm): Log the error. + if (!call_external(argv, NULL, NULL)) { + http_print_transfer_update(download->window, download->url, + "Downloading '%s' failed: Unable to call " + "command '%s' with file at '%s' (%s).", + download->url, + download->cmd_template, + download->filename, + "TODO(wstrm): Log the error"); + } + + g_strfreev(argv); + } + free(download->url); free(download->filename); free(download); diff --git a/src/tools/http_download.h b/src/tools/http_download.h index b6ce42ca..23344f6c 100644 --- a/src/tools/http_download.h +++ b/src/tools/http_download.h @@ -51,6 +51,7 @@ typedef struct http_download_t { char* url; char* filename; + char* cmd_template; curl_off_t bytes_received; ProfWin* window; pthread_t worker; diff --git a/src/ui/console.c b/src/ui/console.c index 8d028139..dd217105 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -2074,9 +2074,9 @@ cons_executable_setting(void) //TODO: there needs to be a way to get all the "locales"/schemes so we can //display the defualt openers for all filetypes - gchar** urlopen = prefs_get_string_list_with_option(PREF_URL_OPEN_CMD, ""); + char* urlopen = prefs_get_string_with_option(PREF_URL_OPEN_CMD, ""); cons_show("Default '/url open' command (/executable urlopen) : %s", urlopen[1]); - g_strfreev(urlopen); + g_free(urlopen); char* urlsave = prefs_get_string(PREF_URL_SAVE_CMD); cons_show("Default '/url save' command (/executable urlsave) : %s", urlsave); -- cgit 1.4.1-2-gfad0 From 1d2c0a8836123c3b484826b974f87a0061bc110b Mon Sep 17 00:00:00 2001 From: William Wennerström Date: Fri, 4 Dec 2020 16:13:13 +0100 Subject: Move unique_filename_from_url functions to common --- Makefile.am | 3 -- src/command/cmd_funcs.c | 65 +----------------------- src/common.c | 80 ++++++++++++++++++++++++++++++ src/common.h | 2 + src/config/preferences.c | 1 - src/tools/http_common.c | 19 ------- src/tools/http_common.h | 2 - tests/unittests/test_common.c | 77 ++++++++++++++++++++++++++++ tests/unittests/test_common.h | 1 + tests/unittests/test_http_common.c | 75 ---------------------------- tests/unittests/test_http_common.h | 1 - tests/unittests/tools/stub_http_download.c | 9 ++++ tests/unittests/unittests.c | 4 +- 13 files changed, 172 insertions(+), 167 deletions(-) delete mode 100644 tests/unittests/test_http_common.c delete mode 100644 tests/unittests/test_http_common.h (limited to 'Makefile.am') diff --git a/Makefile.am b/Makefile.am index 9b2f75c6..c554f11c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -93,8 +93,6 @@ unittest_sources = \ src/tools/clipboard.c src/tools/clipboard.h \ src/tools/bookmark_ignore.c \ src/tools/bookmark_ignore.h \ - src/tools/http_download.c \ - src/tools/http_download.h \ src/config/accounts.h \ src/config/account.c src/config/account.h \ src/config/files.c src/config/files.h \ @@ -153,7 +151,6 @@ unittest_sources = \ tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \ tests/unittests/test_callbacks.c tests/unittests/test_callbacks.h \ tests/unittests/test_plugins_disco.c tests/unittests/test_plugins_disco.h \ - tests/unittests/test_http_common.c tests/unittests/test_http_common.h \ tests/unittests/unittests.c functionaltest_sources = \ diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 88461f1d..147eca4d 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -9110,67 +9110,6 @@ _url_external_method(const char* cmd_template, const char* url, const char* file g_strfreev(argv); } -char* -_unique_filename(const char* filename) -{ - char* unique = strdup(filename); - - unsigned int i = 0; - while (g_file_test(unique, G_FILE_TEST_EXISTS)) { - free(unique); - - if (i > 1000) { // Give up after 1000 attempts. - return NULL; - } - - if (asprintf(&unique, "%s.%u", filename, i) < 0) { - return NULL; - } - - i++; - } - - return unique; -} - -char* -_unique_filename_from_url(char* url, char* path) -{ - gchar* directory = NULL; - gchar* basename = NULL; - if (path != NULL) { - directory = g_path_get_dirname(path); - basename = g_path_get_basename(path); - } - - if (directory == NULL) { - // Explicitly use "./" as directory if no directory has been passed. - directory = "./"; - } - - if (!g_file_test(directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { - cons_show_error("Directory '%s' does not exist or is not a directory.", directory); - return NULL; - } - - if (!basename) { - basename = http_basename_from_url(url); - } - - char* filename = NULL; - filename = g_build_filename(directory, basename, NULL); - - char* unique_filename = _unique_filename(filename); - if (!unique_filename) { - cons_show_error("Failed to generate an unique filename from '%s'.", filename); - free(filename); - return NULL; - } - - free(filename); - return unique_filename; -} - gboolean cmd_url_open(ProfWin* window, const char* const command, gchar** args) { @@ -9200,7 +9139,7 @@ cmd_url_open(ProfWin* window, const char* const command, gchar** args) #ifdef HAVE_OMEMO // OMEMO URLs (aesgcm://) must be saved and decrypted before being opened. if (0 == g_strcmp0(scheme, "aesgcm")) { - char* filename = _unique_filename_from_url(url, files_get_data_path(DIR_DOWNLOADS)); + char* filename = unique_filename_from_url(url, files_get_data_path(DIR_DOWNLOADS)); _url_aesgcm_method(window, cmd_template, url, filename); free(filename); @@ -9241,7 +9180,7 @@ cmd_url_save(ProfWin* window, const char* const command, gchar** args) return TRUE; } - char* filename = _unique_filename_from_url(url, path); + char* filename = unique_filename_from_url(url, path); char* cmd_template = prefs_get_string_with_option(PREF_URL_SAVE_CMD, scheme); if (cmd_template == NULL) { diff --git a/src/common.c b/src/common.c index 079c3af5..66e344c5 100644 --- a/src/common.c +++ b/src/common.c @@ -33,6 +33,9 @@ * source files in the program, then also delete it here. * */ + +#define _GNU_SOURCE 1 + #include "config.h" #include @@ -575,3 +578,80 @@ format_call_external_argv(const char* template, const char* url, const char* fil return argv; } + +gchar* +_unique_filename(const char* filename) +{ + gchar* unique = g_strdup(filename); + + unsigned int i = 0; + while (g_file_test(unique, G_FILE_TEST_EXISTS)) { + free(unique); + + if (i > 1000) { // Give up after 1000 attempts. + return NULL; + } + + if (asprintf(&unique, "%s.%u", filename, i) < 0) { + return NULL; + } + + i++; + } + + return unique; +} + +gchar* +_basename_from_url(const char* url) +{ + const char* default_name = "index.html"; + + GFile* file = g_file_new_for_uri(url); + gchar* filename = g_file_get_basename(file); + g_object_unref(file); + + if (g_strcmp0(filename, ".") == 0 + || g_strcmp0(filename, "..") == 0 + || g_strcmp0(filename, G_DIR_SEPARATOR_S) == 0) { + g_free(filename); + return strdup(default_name); + } + + return filename; +} + +gchar* +unique_filename_from_url(const char* url, const char* path) +{ + gchar* directory = NULL; + gchar* basename = NULL; + if (path != NULL) { + directory = g_path_get_dirname(path); + basename = g_path_get_basename(path); + } + + if (!directory) { + // Explicitly use "./" as directory if no directory has been passed. + directory = "./"; + } + + if (!g_file_test(directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + return NULL; + } + + if (g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + basename = _basename_from_url(url); + } + + gchar* filename = g_build_filename(directory, basename, NULL); + + gchar* unique_filename = _unique_filename(filename); + if (!unique_filename) { + g_free(filename); + return NULL; + } + + g_free(filename); + return unique_filename; +} diff --git a/src/common.h b/src/common.h index b56d31d4..088ba953 100644 --- a/src/common.h +++ b/src/common.h @@ -107,4 +107,6 @@ char* get_random_string(int length); gboolean call_external(gchar** argv, gchar*** const output_ptr, gchar*** const error_ptr); gchar** format_call_external_argv(const char* template, const char* url, const char* filename); +gchar* unique_filename_from_url(const char* url, const char* path); + #endif diff --git a/src/config/preferences.c b/src/config/preferences.c index 4b524fcf..7a9b842b 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -1865,7 +1865,6 @@ _get_group(preference_t pref) return PREF_GROUP_LOGGING; case PREF_AVATAR_CMD: case PREF_URL_OPEN_CMD: - return PREF_GROUP_EXECUTABLES; case PREF_URL_SAVE_CMD: return PREF_GROUP_EXECUTABLES; case PREF_AUTOAWAY_CHECK: diff --git a/src/tools/http_common.c b/src/tools/http_common.c index dfd0aa87..e066a6f6 100644 --- a/src/tools/http_common.c +++ b/src/tools/http_common.c @@ -44,25 +44,6 @@ #define FALLBACK_MSG "" -char* -http_basename_from_url(const char* url) -{ - const char* default_name = "index.html"; - - GFile* file = g_file_new_for_uri(url); - char* filename = g_file_get_basename(file); - g_object_unref(file); - - if (g_strcmp0(filename, ".") == 0 - || g_strcmp0(filename, "..") == 0 - || g_strcmp0(filename, G_DIR_SEPARATOR_S) == 0) { - g_free(filename); - return strdup(default_name); - } - - return filename; -} - void http_print_transfer_update(ProfWin* window, char* url, const char* fmt, ...) { diff --git a/src/tools/http_common.h b/src/tools/http_common.h index c0a553de..ac51b5a8 100644 --- a/src/tools/http_common.h +++ b/src/tools/http_common.h @@ -38,9 +38,7 @@ #include "ui/window.h" -char* http_basename_from_url(const char* url); void http_print_transfer(ProfWin* window, char* url, const char* fmt, ...); void http_print_transfer_update(ProfWin* window, char* url, const char* fmt, ...); -gchar** http_format_external_argv(const char* cmd, const char* url, const char* filename); #endif diff --git a/tests/unittests/test_common.c b/tests/unittests/test_common.c index b8958dda..462676cc 100644 --- a/tests/unittests/test_common.c +++ b/tests/unittests/test_common.c @@ -330,6 +330,83 @@ strip_quotes_strips_both(void** state) free(result); } +typedef struct +{ + char* url; + char* path; + char* filename; +} unique_filename_from_url_t; + +void +unique_filename_from_url_td(void** state) +{ + enum table { num_tests = 11 }; + + unique_filename_from_url_t tests[num_tests] = { + (unique_filename_from_url_t){ + .url = "https://host.test/image.jpeg", + .path = "./", + .filename = "./image.jpeg", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/image.jpeg#somefragment", + .path = "./", + .filename = "./image.jpeg", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/image.jpeg?query=param", + .path = "./", + .filename = "./image.jpeg", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/image.jpeg?query=param&another=one", + .path = "./", + .filename = "./image.jpeg", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/images/", + .path = "./", + .filename = "./images", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/images/../../file", + .path = "./", + .filename = "./file", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/images/../../file/..", + .path = "./", + .filename = "./index.html", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/images/..//", + .path = "./", + .filename = "./index.html", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/", + .path = "./", + .filename = "./index.html", + }, + (unique_filename_from_url_t){ + .url = "https://host.test", + .path = "./", + .filename = "./index.html", + }, + (unique_filename_from_url_t){ + .url = "aesgcm://host.test", + .path = "./", + .filename = "./index.html", + }, + }; + + char* filename; + for (int i = 0; i < num_tests; i++) { + filename = unique_filename_from_url(tests[i].url, tests[i].path); + assert_string_equal(filename, tests[i].filename); + } +} + gboolean _lists_equal(GSList* a, GSList* b) { diff --git a/tests/unittests/test_common.h b/tests/unittests/test_common.h index b9e7291e..a1ef7c6e 100644 --- a/tests/unittests/test_common.h +++ b/tests/unittests/test_common.h @@ -31,3 +31,4 @@ void strip_quotes_strips_last(void** state); void strip_quotes_strips_both(void** state); void prof_partial_occurrences_tests(void** state); void prof_whole_occurrences_tests(void** state); +void unique_filename_from_url_td(void** state); diff --git a/tests/unittests/test_http_common.c b/tests/unittests/test_http_common.c deleted file mode 100644 index 195f370b..00000000 --- a/tests/unittests/test_http_common.c +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#include "tools/http_common.c" - -typedef struct -{ - char* url; - char* basename; -} url_test_t; - -void -http_basename_from_url_td(void** state) -{ - int num_tests = 11; - url_test_t tests[] = { - (url_test_t){ - .url = "https://host.test/image.jpeg", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/image.jpeg#somefragment", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/image.jpeg?query=param", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/image.jpeg?query=param&another=one", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/images/", - .basename = "images", - }, - (url_test_t){ - .url = "https://host.test/images/../../file", - .basename = "file", - }, - (url_test_t){ - .url = "https://host.test/images/../../file/..", - .basename = "index.html", - }, - (url_test_t){ - .url = "https://host.test/images/..//", - .basename = "index.html", - }, - (url_test_t){ - .url = "https://host.test/", - .basename = "index.html", - }, - (url_test_t){ - .url = "https://host.test", - .basename = "index.html", - }, - (url_test_t){ - .url = "aesgcm://host.test", - .basename = "index.html", - }, - }; - - char* basename; - for (int i = 0; i < num_tests; i++) { - basename = http_basename_from_url(tests[i].url); - assert_string_equal(basename, tests[i].basename); - } -} diff --git a/tests/unittests/test_http_common.h b/tests/unittests/test_http_common.h deleted file mode 100644 index a1c62a7f..00000000 --- a/tests/unittests/test_http_common.h +++ /dev/null @@ -1 +0,0 @@ -void http_basename_from_url_td(void** state); diff --git a/tests/unittests/tools/stub_http_download.c b/tests/unittests/tools/stub_http_download.c index 5fa1c46e..cc7bddc5 100644 --- a/tests/unittests/tools/stub_http_download.c +++ b/tests/unittests/tools/stub_http_download.c @@ -18,4 +18,13 @@ typedef struct http_download_t int cancel; } HTTPDownload; +void* +http_file_get(void* userdata) +{ + return NULL; +} + +void http_download_cancel_processes(){}; +void http_download_add_download(){}; + #endif diff --git a/tests/unittests/unittests.c b/tests/unittests/unittests.c index cab99bf5..c63a3783 100644 --- a/tests/unittests/unittests.c +++ b/tests/unittests/unittests.c @@ -38,7 +38,6 @@ #include "test_form.h" #include "test_callbacks.h" #include "test_plugins_disco.h" -#include "test_http_common.h" int main(int argc, char* argv[]) @@ -91,6 +90,7 @@ main(int argc, char* argv[]) unit_test(strip_quotes_strips_first), unit_test(strip_quotes_strips_last), unit_test(strip_quotes_strips_both), + unit_test(unique_filename_from_url_td), unit_test(clear_empty), unit_test(reset_after_create), @@ -627,8 +627,6 @@ main(int argc, char* argv[]) unit_test(does_not_add_duplicate_feature), unit_test(removes_plugin_features), unit_test(does_not_remove_feature_when_more_than_one_reference), - - unit_test(http_basename_from_url_td), }; return run_tests(all_tests); -- cgit 1.4.1-2-gfad0