diff --git a/src/bootstrap.c b/src/bootstrap.c
index 2058c9734..c0d062170 100644
--- a/src/bootstrap.c
+++ b/src/bootstrap.c
@@ -36,6 +36,7 @@
#include "line_info.h"
#include "misc_tools.h"
#include "prompt.h"
+#include "run_options.h"
#include "settings.h"
#include "windows.h"
diff --git a/src/misc_tools.c b/src/misc_tools.c
index 2ae2bf0a9..c61e2f80f 100644
--- a/src/misc_tools.c
+++ b/src/misc_tools.c
@@ -559,7 +559,7 @@ size_t copy_tox_str(char *msg, size_t size, const char *data, size_t length)
returns length of s if char not found or 0 if s is NULL. */
int char_find(int idx, const char *s, char ch)
{
- if (!s) {
+ if (s == NULL) {
return 0;
}
@@ -578,7 +578,7 @@ int char_find(int idx, const char *s, char ch)
returns 0 if char not found or s is NULL (skips 0th index). */
int char_rfind(const char *s, char ch, int len)
{
- if (!s) {
+ if (s == NULL) {
return 0;
}
diff --git a/src/name_lookup.c b/src/name_lookup.c
index fb0beff4c..c1b696af5 100644
--- a/src/name_lookup.c
+++ b/src/name_lookup.c
@@ -30,6 +30,7 @@
#include "global_commands.h"
#include "line_info.h"
#include "misc_tools.h"
+#include "run_options.h"
#include "toxic.h"
#include "windows.h"
diff --git a/src/run_options.h b/src/run_options.h
new file mode 100644
index 000000000..07bb2dae1
--- /dev/null
+++ b/src/run_options.h
@@ -0,0 +1,57 @@
+/* run_options.h
+ *
+ *
+ * Copyright (C) 2024 Toxic All Rights Reserved.
+ *
+ * This file is part of Toxic.
+ *
+ * Toxic 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.
+ *
+ * Toxic 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 Toxic. If not, see .
+ *
+ */
+
+#ifndef RUN_OPTIONS_H
+
+#include
+#include // needed for FILE
+#include
+
+#include "toxic_constants.h"
+
+typedef struct Run_Options {
+ bool use_ipv4;
+ bool force_tcp;
+ bool disable_local_discovery;
+ bool debug;
+ bool default_locale;
+ bool use_custom_data;
+ bool use_custom_config_file;
+ bool no_connect;
+ bool encrypt_data;
+ bool unencrypt_data;
+
+ char nameserver_path[MAX_STR_SIZE];
+ char config_path[MAX_STR_SIZE];
+ char nodes_path[MAX_STR_SIZE];
+
+ bool logging;
+ FILE *log_fp;
+
+ char proxy_address[256];
+ uint8_t proxy_type;
+ uint16_t proxy_port;
+
+ uint16_t tcp_port;
+} Run_Options;
+
+#endif /* RUN_OPTIONS_H */
diff --git a/src/settings.c b/src/settings.c
index a087c5126..b3feff0b2 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -31,6 +31,7 @@
#include "groupchats.h"
#include "misc_tools.h"
#include "notify.h"
+#include "run_options.h"
#include "toxic.h"
#include "windows.h"
@@ -340,29 +341,50 @@ static void set_key_binding(int *key, const char **bind)
}
}
-static bool get_settings_path(char *path, unsigned int path_size, const char *patharg)
+#define TOXIC_CONF_FILE_EXT ".conf"
+
+bool settings_load_config_file(Run_Options *run_opts, const char *data_path)
{
- if (patharg != NULL) {
- snprintf(path, path_size, "%s", patharg);
- return true;
- }
+ char tmp_path[MAX_STR_SIZE] = {0};
+
+ if (run_opts->use_custom_config_file) {
+ snprintf(tmp_path, sizeof(tmp_path), "%s", run_opts->config_path);
+ } else if (run_opts->use_custom_data) {
+ char tmp_data[MAX_STR_SIZE - strlen(TOXIC_CONF_FILE_EXT)];
+
+ if (strlen(data_path) >= sizeof(tmp_data)) {
+ return false;
+ }
- char *user_config_dir = get_user_config_dir();
- snprintf(path, path_size, "%s%stoxic.conf", user_config_dir, CONFIGDIR);
- free(user_config_dir);
+ snprintf(tmp_data, sizeof(tmp_data), "%s", data_path);
+
+ const int dot_idx = char_rfind(tmp_data, '.', strlen(tmp_data));
+
+ if (dot_idx > 0) {
+ tmp_data[dot_idx] = '\0'; // remove .tox file extension (or any others) if it exists
+ }
+
+ snprintf(tmp_path, sizeof(tmp_path), "%s%s", tmp_data, TOXIC_CONF_FILE_EXT);
+ } else {
+ char *user_config_dir = get_user_config_dir();
+ snprintf(tmp_path, sizeof(tmp_path), "%s%stoxic%s", user_config_dir, CONFIGDIR, TOXIC_CONF_FILE_EXT);
+ free(user_config_dir);
+ }
/* make sure path exists or is created on first time running */
- if (!file_exists(path)) {
- FILE *fp = fopen(path, "w");
+ if (!file_exists(tmp_path)) {
+ FILE *fp = fopen(tmp_path, "w");
if (fp == NULL) {
- fprintf(stderr, "failed to open config path: %s\n", path);
+ fprintf(stderr, "failed to create config path `%s`\n", tmp_path);
return false;
}
fclose(fp);
}
+ snprintf(run_opts->config_path, sizeof(run_opts->config_path), "%s", tmp_path);
+
return true;
}
@@ -404,22 +426,17 @@ static const char *extract_setting_public_key(const config_setting_t *keys)
/*
* Initializes `cfg` with the contents from the toxic config file.
*
- * `patharg` points to a user specified config path. If `patharg` is NULL
- * the default config path will be used.
- *
* Return 0 on success.
- * Return -1 if we failed to fetch or create the config path.
+ * Return -1 if the config file was not set by the client.
* Return -2 if the config file cannot be read or is invalid.
*/
-static int settings_init_config(config_t *cfg, const char *patharg)
+static int settings_init_config(config_t *cfg, const Run_Options *run_opts)
{
- char path[MAX_STR_SIZE] = {0};
-
- if (!get_settings_path(path, sizeof(path), patharg)) {
+ if (string_is_empty(run_opts->config_path)) {
return -1;
}
- if (!config_read_file(cfg, path)) {
+ if (!config_read_file(cfg, run_opts->config_path)) {
fprintf(stderr, "config_read_file() error: %s:%d - %s\n", config_error_file(cfg),
config_error_line(cfg), config_error_text(cfg));
return -2;
@@ -428,12 +445,12 @@ static int settings_init_config(config_t *cfg, const char *patharg)
return 0;
}
-int settings_load_conferences(const char *patharg)
+int settings_load_conferences(const Run_Options *run_opts)
{
config_t cfg[1];
config_init(cfg);
- const int c_ret = settings_init_config(cfg, patharg);
+ const int c_ret = settings_init_config(cfg, run_opts);
if (c_ret < 0) {
config_destroy(cfg);
@@ -480,12 +497,12 @@ int settings_load_conferences(const char *patharg)
return 0;
}
-int settings_load_groups(const char *patharg)
+int settings_load_groups(const Run_Options *run_opts)
{
config_t cfg[1];
config_init(cfg);
- const int c_ret = settings_init_config(cfg, patharg);
+ const int c_ret = settings_init_config(cfg, run_opts);
if (c_ret < 0) {
config_destroy(cfg);
@@ -532,12 +549,12 @@ int settings_load_groups(const char *patharg)
return 0;
}
-int settings_load_friends(const char *patharg)
+int settings_load_friends(const Run_Options *run_opts)
{
config_t cfg[1];
config_init(cfg);
- const int c_ret = settings_init_config(cfg, patharg);
+ const int c_ret = settings_init_config(cfg, run_opts);
if (c_ret < 0) {
config_destroy(cfg);
@@ -600,7 +617,7 @@ int settings_load_friends(const char *patharg)
return 0;
}
-int settings_load_main(Client_Config *s, const char *patharg)
+int settings_load_main(Client_Config *s, const Run_Options *run_opts)
{
config_t cfg[1];
config_init(cfg);
@@ -616,7 +633,7 @@ int settings_load_main(Client_Config *s, const char *patharg)
audio_defaults(s);
#endif
- const int c_ret = settings_init_config(cfg, patharg);
+ const int c_ret = settings_init_config(cfg, run_opts);
if (c_ret < 0) {
config_destroy(cfg);
diff --git a/src/settings.h b/src/settings.h
index 354bc8a83..7c3d82428 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -141,6 +141,27 @@ enum settings_values {
#define LOG_TIMESTAMP_DEFAULT "%Y/%m/%d [%H:%M:%S]"
#define MPLEX_AWAY_NOTE "Away from keyboard, be back soon!"
+typedef struct Run_Options Run_Options;
+
+/*
+ * Loads the config file into `run_opts` and creates an empty file if it does not
+ * already exist. This function must be called before any other `settings_load` function.
+ *
+ * If the client has set a custom config file via the run option it will be
+ * prioritized.
+ *
+ * If the client is using the default tox data file and has not specified a custom
+ * config file, the default config file in the user config directory is used
+ *
+ * If the client is using a custom tox data file, the config path and filename will be
+ * identical to those of the data file, but with a `.conf` file extension.
+ *
+ * `data_path` is the name of the tox profile being used.
+ *
+ * Returns true if config file is successfully loaded.
+ */
+bool settings_load_config_file(Run_Options *run_opts, const char *data_path);
+
/*
* Loads general toxic settings from the toxic config file pointed to by `patharg'.
*
@@ -148,7 +169,7 @@ enum settings_values {
* Return -1 if we fail to open the file path.
* Return -2 if libconfig fails to read the config file.
*/
-int settings_load_main(Client_Config *s, const char *patharg);
+int settings_load_main(Client_Config *s, const Run_Options *run_opts);
/*
* Loads friend config settings from the toxic config file pointed to by `patharg`.
@@ -160,7 +181,7 @@ int settings_load_main(Client_Config *s, const char *patharg);
*
* This function will have no effect on friends that are added in the future.
*/
-int settings_load_friends(const char *patharg);
+int settings_load_friends(const Run_Options *run_opts);
/*
* Loads groupchat config settings from the toxic config file pointed to by `patharg`.
@@ -172,7 +193,7 @@ int settings_load_friends(const char *patharg);
*
* This function will have no effect on groupchat instances that are created in the future.
*/
-int settings_load_groups(const char *patharg);
+int settings_load_groups(const Run_Options *run_opts);
/*
* Loads conference config settings from the toxic config file pointed to by `patharg`.
@@ -184,6 +205,6 @@ int settings_load_groups(const char *patharg);
*
* This function will have no effect on conference instances that are created in the future.
*/
-int settings_load_conferences(const char *patharg);
+int settings_load_conferences(const Run_Options *run_opts);
#endif /* SETTINGS_H */
diff --git a/src/toxic.c b/src/toxic.c
index 0acdc7273..b4d3ee117 100644
--- a/src/toxic.c
+++ b/src/toxic.c
@@ -62,6 +62,7 @@
#include "name_lookup.h"
#include "notify.h"
#include "prompt.h"
+#include "run_options.h"
#include "settings.h"
#include "term_mplex.h"
#include "toxic.h"
@@ -1397,11 +1398,9 @@ static void parse_args(Toxic *toxic, int argc, char *argv[])
}
snprintf(run_opts->config_path, sizeof(run_opts->config_path), "%s", optarg);
+ run_opts->use_custom_config_file = true;
- if (!file_exists(run_opts->config_path)) {
- queue_init_message("Config file not found");
- }
-
+ queue_init_message("Using '%s' custom config file", run_opts->config_path);
break;
}
@@ -1453,7 +1452,7 @@ static void parse_args(Toxic *toxic, int argc, char *argv[])
strcpy(client_data->block_path, optarg);
strcat(client_data->block_path, "-blocklist");
- queue_init_message("Using '%s' data file", client_data->data_path);
+ queue_init_message("Using '%s' tox profile", client_data->data_path);
break;
}
@@ -1708,14 +1707,20 @@ int main(int argc, char **argv)
first_time_encrypt(&toxic->client_data, "Encrypt existing data file? Y/n (q to quit)");
}
- const char *config_path = !string_is_empty(run_opts->config_path) ? run_opts->config_path : NULL;
+ if (!settings_load_config_file(run_opts, toxic->client_data.data_path)) {
+ queue_init_message("Failed to load config file");
+ }
- const int ms_ret = settings_load_main(toxic->c_config, config_path);
+ const int ms_ret = settings_load_main(toxic->c_config, run_opts);
if (ms_ret < 0) {
queue_init_message("Failed to load user settings: error %d", ms_ret);
}
+ if (!run_opts->use_custom_config_file && run_opts->use_custom_data) {
+ queue_init_message("Using '%s' config file", run_opts->config_path);
+ }
+
const int curl_init = curl_global_init(CURL_GLOBAL_ALL);
const int nameserver_ret = name_lookup_init(run_opts->nameserver_path, curl_init);
@@ -1753,19 +1758,19 @@ int main(int argc, char **argv)
load_groups(toxic);
load_conferences(toxic);
- const int fs_ret = settings_load_friends(config_path);
+ const int fs_ret = settings_load_friends(run_opts);
if (fs_ret != 0) {
queue_init_message("Failed to load friend config settings: error %d", fs_ret);
}
- const int gs_ret = settings_load_groups(config_path);
+ const int gs_ret = settings_load_groups(run_opts);
if (gs_ret != 0) {
queue_init_message("Failed to load groupchat config settings: error %d", gs_ret);
}
- const int cs_ret = settings_load_conferences(config_path);
+ const int cs_ret = settings_load_conferences(run_opts);
if (cs_ret != 0) {
queue_init_message("Failed to load conference config settings: error %d", cs_ret);
diff --git a/src/toxic.h b/src/toxic.h
index 9c9ad0ebd..102b49ecd 100644
--- a/src/toxic.h
+++ b/src/toxic.h
@@ -51,31 +51,6 @@
#include "settings.h"
#include "toxic_constants.h"
-typedef struct Run_Options {
- bool use_ipv4;
- bool force_tcp;
- bool disable_local_discovery;
- bool debug;
- bool default_locale;
- bool use_custom_data;
- bool no_connect;
- bool encrypt_data;
- bool unencrypt_data;
-
- char nameserver_path[MAX_STR_SIZE];
- char config_path[MAX_STR_SIZE];
- char nodes_path[MAX_STR_SIZE];
-
- bool logging;
- FILE *log_fp;
-
- char proxy_address[256];
- uint8_t proxy_type;
- uint16_t proxy_port;
-
- uint16_t tcp_port;
-} Run_Options;
-
typedef struct Client_Data {
bool is_encrypted;
char pass[MAX_PASSWORD_LEN + 1];
@@ -86,6 +61,7 @@ typedef struct Client_Data {
typedef struct ToxAV ToxAV;
typedef struct ToxWindow ToxWindow;
+typedef struct Run_Options Run_Options;
typedef struct Toxic {
Tox *tox;