commits
tags
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/stat.h>
#include <unistd.h>
static void set_defaults(Config *cfg)
{
memset(cfg, 0, sizeof(*cfg));
snprintf(cfg->host, sizeof(cfg->host), "127.0.0.1");
cfg->port = 9091;
cfg->poll_interval_ms = 2000;
cfg->show_splash = 1;
}
static int resolve_path(char *out, size_t n)
{
const char *xdg = getenv("XDG_CONFIG_HOME");
if (xdg && xdg[0]) {
snprintf(out, n, "%s/transtui/config.ini", xdg);
return 0;
}
const char *home = getenv("HOME");
if (!home || !home[0])
return -1;
snprintf(out, n, "%s/.config/transtui/config.ini", home);
return 0;
}
static void mkdir_parents(const char *path)
{
char tmp[1024];
snprintf(tmp, sizeof(tmp), "%s", path);
for (char *p = tmp + 1; *p; p++) {
if (*p == '/') {
*p = '\0';
mkdir(tmp, 0755);
*p = '/';
}
}
}
static int write_default_file(const char *path)
{
char dir[1024];
snprintf(dir, sizeof(dir), "%s", path);
char *slash = strrchr(dir, '/');
if (slash) {
*slash = '\0';
mkdir_parents(dir);
mkdir(dir, 0755);
}
FILE *f = fopen(path, "w");
if (!f)
return -1;
fprintf(f,
"# transtui config\n"
"host = 127.0.0.1\n"
"port = 9091\n"
"username =\n"
"password =\n"
"poll_interval_ms = 2000\n"
"show_splash = 1\n");
fclose(f);
return 0;
}
static char *trim(char *s)
{
while (*s == ' ' || *s == '\t')
s++;
size_t n = strlen(s);
while (n > 0 && (s[n - 1] == ' ' || s[n - 1] == '\t' || s[n - 1] == '\r' || s[n - 1] == '\n'))
s[--n] = '\0';
return s;
}
static void parse_file(Config *cfg, FILE *f)
{
char line[1024];
while (fgets(line, sizeof(line), f)) {
char *l = trim(line);
if (l[0] == '\0' || l[0] == '#' || l[0] == ';')
continue;
char *eq = strchr(l, '=');
if (!eq)
continue;
*eq = '\0';
char *key = trim(l);
char *val = trim(eq + 1);
if (strcmp(key, "host") == 0)
snprintf(cfg->host, sizeof(cfg->host), "%s", val);
else if (strcmp(key, "port") == 0)
cfg->port = atoi(val);
else if (strcmp(key, "username") == 0)
snprintf(cfg->username, sizeof(cfg->username), "%s", val);
else if (strcmp(key, "password") == 0)
snprintf(cfg->password, sizeof(cfg->password), "%s", val);
else if (strcmp(key, "poll_interval_ms") == 0)
cfg->poll_interval_ms = atoi(val);
else if (strcmp(key, "show_splash") == 0)
cfg->show_splash = (strcmp(val, "0") != 0 && strcasecmp(val, "false") != 0);
else if (strcmp(key, "session_cache_set") == 0)
cfg->session_cache_set = (strcmp(val, "0") != 0 && strcasecmp(val, "false") != 0);
else if (strcmp(key, "cache_download_dir") == 0)
snprintf(cfg->cache_download_dir, sizeof(cfg->cache_download_dir), "%s", val);
else if (strcmp(key, "cache_speed_down") == 0)
cfg->cache_speed_down = atol(val);
else if (strcmp(key, "cache_speed_down_enabled") == 0)
cfg->cache_speed_down_enabled = (strcmp(val, "0") != 0 && strcasecmp(val, "false") != 0);
else if (strcmp(key, "cache_speed_up") == 0)
cfg->cache_speed_up = atol(val);
else if (strcmp(key, "cache_speed_up_enabled") == 0)
cfg->cache_speed_up_enabled = (strcmp(val, "0") != 0 && strcasecmp(val, "false") != 0);
else if (strcmp(key, "cache_alt_enabled") == 0)
cfg->cache_alt_enabled = (strcmp(val, "0") != 0 && strcasecmp(val, "false") != 0);
else if (strcmp(key, "cache_alt_down") == 0)
cfg->cache_alt_down = atol(val);
else if (strcmp(key, "cache_alt_up") == 0)
cfg->cache_alt_up = atol(val);
else if (strcmp(key, "cache_alt_time_enabled") == 0)
cfg->cache_alt_time_enabled = (strcmp(val, "0") != 0 && strcasecmp(val, "false") != 0);
else if (strcmp(key, "cache_alt_time_begin") == 0)
cfg->cache_alt_time_begin = atoi(val);
else if (strcmp(key, "cache_alt_time_end") == 0)
cfg->cache_alt_time_end = atoi(val);
else if (strcmp(key, "cache_seed_ratio_limit") == 0)
cfg->cache_seed_ratio_limit = atof(val);
else if (strcmp(key, "cache_seed_ratio_enabled") == 0)
cfg->cache_seed_ratio_enabled = (strcmp(val, "0") != 0 && strcasecmp(val, "false") != 0);
}
}
int config_load(Config *cfg, char *err, size_t errlen)
{
set_defaults(cfg);
if (resolve_path(cfg->path, sizeof(cfg->path)) != 0) {
snprintf(err, errlen, "could not find HOME to resolve the config file");
return -1;
}
FILE *f = fopen(cfg->path, "r");
if (!f) {
if (write_default_file(cfg->path) != 0) {
snprintf(err, errlen, "could not create %s", cfg->path);
return -1;
}
return 0; /* defaults already set */
}
parse_file(cfg, f);
fclose(f);
if (cfg->port <= 0 || cfg->port > 65535)
cfg->port = 9091;
if (cfg->poll_interval_ms < 250)
cfg->poll_interval_ms = 250;
return 0;
}
int config_save(const Config *cfg, char *err, size_t errlen)
{
if (!cfg->path[0]) {
snprintf(err, errlen, "no config path known");
return -1;
}
FILE *f = fopen(cfg->path, "w");
if (!f) {
snprintf(err, errlen, "could not write %s", cfg->path);
return -1;
}
fprintf(f,
"# transtui config\n"
"host = %s\n"
"port = %d\n"
"username = %s\n"
"password = %s\n"
"poll_interval_ms = %d\n"
"show_splash = %d\n"
"session_cache_set = %d\n"
"cache_download_dir = %s\n"
"cache_speed_down = %ld\n"
"cache_speed_down_enabled = %d\n"
"cache_speed_up = %ld\n"
"cache_speed_up_enabled = %d\n"
"cache_alt_enabled = %d\n"
"cache_alt_down = %ld\n"
"cache_alt_up = %ld\n"
"cache_alt_time_enabled = %d\n"
"cache_alt_time_begin = %d\n"
"cache_alt_time_end = %d\n"
"cache_seed_ratio_limit = %.2f\n"
"cache_seed_ratio_enabled = %d\n",
cfg->host, cfg->port, cfg->username, cfg->password, cfg->poll_interval_ms,
cfg->show_splash, cfg->session_cache_set, cfg->cache_download_dir,
cfg->cache_speed_down, cfg->cache_speed_down_enabled, cfg->cache_speed_up,
cfg->cache_speed_up_enabled, cfg->cache_alt_enabled, cfg->cache_alt_down,
cfg->cache_alt_up, cfg->cache_alt_time_enabled, cfg->cache_alt_time_begin,
cfg->cache_alt_time_end, cfg->cache_seed_ratio_limit, cfg->cache_seed_ratio_enabled);
fclose(f);
return 0;
}
static void usage(const char *prog)
{
fprintf(stderr,
"Usage: %s [-H host] [-P port] [-u user] [-p pass] [-i ms]\n"
" %s --add <magnet|url|file> [-H host] [-P port] [-u user] [-p pass]\n"
" -H host Transmission daemon address (default 127.0.0.1)\n"
" -P port RPC port (default 9091)\n"
" -u user RPC username\n"
" -p pass RPC password\n"
" -i ms Poll interval in milliseconds (default 2000)\n"
" -A, --add <source>\n"
" Add a torrent (magnet link, URL, or .torrent file), then open\n"
" the UI - for registering transtui as the browser handler for\n"
" magnet links/.torrent files.\n"
" -h Show this help\n",
prog, prog);
}
void config_apply_args(Config *cfg, int argc, char **argv, char *add_source, size_t add_source_size)
{
if (add_source_size)
add_source[0] = '\0';
for (int i = 1; i < argc; i++) {
const char *a = argv[i];
if ((strcmp(a, "-H") == 0 || strcmp(a, "--host") == 0) && i + 1 < argc) {
snprintf(cfg->host, sizeof(cfg->host), "%s", argv[++i]);
} else if ((strcmp(a, "-P") == 0 || strcmp(a, "--port") == 0) && i + 1 < argc) {
cfg->port = atoi(argv[++i]);
} else if ((strcmp(a, "-u") == 0 || strcmp(a, "--user") == 0) && i + 1 < argc) {
snprintf(cfg->username, sizeof(cfg->username), "%s", argv[++i]);
} else if ((strcmp(a, "-p") == 0 || strcmp(a, "--pass") == 0) && i + 1 < argc) {
snprintf(cfg->password, sizeof(cfg->password), "%s", argv[++i]);
} else if ((strcmp(a, "-i") == 0 || strcmp(a, "--interval") == 0) && i + 1 < argc) {
cfg->poll_interval_ms = atoi(argv[++i]);
} else if ((strcmp(a, "-A") == 0 || strcmp(a, "--add") == 0) && i + 1 < argc) {
snprintf(add_source, add_source_size, "%s", argv[++i]);
} else if (strcmp(a, "-h") == 0 || strcmp(a, "--help") == 0) {
usage(argv[0]);
exit(0);
} else {
fprintf(stderr, "Unknown argument: %s\n\n", a);
usage(argv[0]);
exit(1);
}
}
}