#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "rpc.h"
#include "torrent.h"
#include "util.h"
#include "ui/ui.h"
/* Browsers/file managers hand "Open with" targets a file:// URI (percent-
* encoded) rather than a plain path. Strip and decode that so torrent_add()
* gets a real filesystem path; magnet:/http(s):// sources pass through
* untouched since their own percent-encoding must stay intact. */
static void resolve_add_source(const char *in, char *out, size_t outsize)
{
if (!str_starts_with(in, "file://")) {
snprintf(out, outsize, "%s", in);
return;
}
const char *p = in + 7;
size_t o = 0;
for (size_t i = 0; p[i] && o + 1 < outsize; i++) {
if (p[i] == '%' && isxdigit((unsigned char)p[i + 1]) && isxdigit((unsigned char)p[i + 2])) {
char hex[3] = {p[i + 1], p[i + 2], '\0'};
out[o++] = (char)strtol(hex, NULL, 16);
i += 2;
} else {
out[o++] = p[i];
}
}
out[o] = '\0';
}
/* Adds a torrent handed in via -A/--add (e.g. from a browser's magnet-link
* handler) before the TUI starts, so the user sees it land in the list
* instead of a silent background add. msg is filled with the result either
* way, for display in the TUI's status bar. */
static void add_torrent_startup(RpcClient *rpc, const char *add_source, char *msg, size_t msg_size)
{
char source[1024];
resolve_add_source(add_source, source, sizeof(source));
char err[256];
if (torrent_add(rpc, source, NULL, err, sizeof(err)) != 0)
snprintf(msg, msg_size, "Could not add torrent: %s", err);
else
snprintf(msg, msg_size, "Torrent added: %s", source);
}
int main(int argc, char **argv)
{
Config cfg;
char err[256];
if (config_load(&cfg, err, sizeof(err)) != 0) {
fprintf(stderr, "transtui: %s\n", err);
return 1;
}
char add_source[1024];
config_apply_args(&cfg, argc, argv, add_source, sizeof(add_source));
RpcClient rpc;
rpc_init(&rpc, cfg.host, cfg.port, cfg.username[0] ? cfg.username : NULL,
cfg.password[0] ? cfg.password : NULL);
char msg[sizeof(add_source) + 32];
msg[0] = '\0';
if (add_source[0])
add_torrent_startup(&rpc, add_source, msg, sizeof(msg));
/* Only one TUI at a time: if another instance already holds the lock,
* a --add here has still reached the daemon above and will show up next
* time that instance polls, so just report the result and exit instead
* of opening a second ncurses screen. */
if (single_instance_lock() == 0) {
if (add_source[0]) {
printf("%s\n", msg);
return 0;
}
fprintf(stderr, "transtui: already running\n");
return 1;
}
return ui_run(&rpc, &cfg, msg[0] ? msg : NULL);
}