aboutsummaryrefslogtreecommitdiff
path: root/src/transmission.c
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-07-15 09:28:51 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-15 09:28:51 +0200
commit73393bfab65515c68159a649c10856659b5ac016 (patch)
tree67cb37484cccc0cf9d3cbe88a58095c2040bd79e /src/transmission.c
parent35aca1f0582c43b5f6818c8fc00b924247e45881 (diff)
Use transmission rpc, fixes rss torrent name
Diffstat (limited to 'src/transmission.c')
-rw-r--r--src/transmission.c208
1 files changed, 120 insertions, 88 deletions
diff --git a/src/transmission.c b/src/transmission.c
index b9cb123..d789053 100644
--- a/src/transmission.c
+++ b/src/transmission.c
@@ -1,13 +1,51 @@
#include "transmission.h"
#include "program.h"
#include "buffer.h"
+#include "json.h"
+#include "rss_html_common.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
+/* TODO: Make port configurable */
+
#define NUM_COLUMNS 10
+int transmission_connect(TransmissionSession *session) {
+ int result = 0;
+ Buffer buffer;
+ buffer_init(&buffer);
+
+ const char *args[] = { "curl", "-s", "-I", "http://127.0.0.1:9091/transmission/rpc", NULL };
+ result = program_exec(args, program_buffer_write_callback, &buffer);
+ if(result != 0) {
+ fprintf(stderr, "Failed to retrieve transmission session id\n");
+ goto cleanup;
+ }
+
+ char *session_id_start = strstr(buffer.data, "X-Transmission-Session-Id: ");
+ if(!session_id_start) {
+ fprintf(stderr, "Failed to find session id in transmission response\n");
+ result = -1;
+ goto cleanup;
+ }
+
+ char *session_id_end = strchr(session_id_start + 27, '\r');
+ if(!session_id_start) {
+ fprintf(stderr, "Failed to find session id in transmission response\n");
+ result = -1;
+ goto cleanup;
+ }
+
+ memcpy(session->session_header, session_id_start, session_id_end - session_id_start);
+ session->session_header[session_id_end - session_id_start] = '\0';
+
+ cleanup:
+ buffer_deinit(&buffer);
+ return result;
+}
+
int transmission_is_daemon_running(void) {
const char *args[] = { "transmission-remote", "-si", NULL };
return program_exec(args, NULL, NULL);
@@ -38,119 +76,113 @@ int transmission_start_daemon(const char *download_dir) {
return 0;
}
-int transmission_add_torrent(const char *url) {
- const char *args[] = { "transmission-remote", "-a", "--", url, NULL };
- return program_exec(args, NULL, NULL);
+static struct json_object_s* json_object_get_child_object_by_name(struct json_object_s *json_obj, const char *field_name) {
+ struct json_value_s *json_child_obj = json_object_get_field_by_name(json_obj, field_name);
+ if(!json_child_obj || json_child_obj->type != json_type_object)
+ return NULL;
+ return (struct json_object_s*)json_child_obj->payload;
}
-int transmission_get_all_torrents(TorrentListCallback callback, void *userdata) {
- int result = 0;
-
- Buffer buffer;
- buffer_init(&buffer);
-
- const char *args[] = { "transmission-remote", "--list", NULL };
- int exec_res = program_exec(args, program_buffer_write_callback, &buffer);
- if(exec_res != 0) {
- result = exec_res;
- goto cleanup;
- }
- buffer_append(&buffer, "\0", 1);
-
- char id[6];
- char done[6];
- char have[13];
- char format[7];
- char eta[33];
- char eta2[13];
- char up[11];
- char down[11];
- char ratio[11];
- char status[33];
- char name[256];
-
- char *end_of_first_line = strchr(buffer.data, '\n');
- if(!end_of_first_line)
- goto cleanup;
+static struct json_string_s* json_object_get_child_string_by_name(struct json_object_s *json_obj, const char *field_name) {
+ struct json_value_s *json_child_str = json_object_get_field_by_name(json_obj, field_name);
+ if(!json_child_str || json_child_str->type != json_type_string)
+ return NULL;
+ return (struct json_string_s*)json_child_str->payload;
+}
- int num_bytes_read = 0;
- size_t offset = end_of_first_line - (char*)buffer.data;
- while(offset < buffer.size) {
- /* ID, Done, Have (size, format), ETA, Up, Down, Ratio, Status, Name */
- int res = sscanf(buffer.data + offset, "%5s %5s %12s %6s %32s %12s %10s %10s %10s %32s %[^\n] %n", id, done, have, format, eta, eta2, up, down, ratio, status, name, &num_bytes_read);
- if(res == EOF || res != NUM_COLUMNS + 1) {
- int res = sscanf(buffer.data + offset, "%5s %5s %12s %6s %32s %10s %10s %10s %32s %[^\n] %n", id, done, have, format, eta, up, down, ratio, status, name, &num_bytes_read);
- if(res == EOF || res != NUM_COLUMNS)
- break;
- }
- callback(atoi(id), atof(done), name, userdata);
- offset += num_bytes_read;
+static int transmission_response_is_success(struct json_object_s *json_root) {
+ struct json_string_s *result_field = json_object_get_child_string_by_name(json_root, "result");
+ if(!result_field) {
+ fprintf(stderr, "Error: Transmission response is missing result field\n");
+ return -1;
}
- cleanup:
- buffer_deinit(&buffer);
- return result;
+ return strcmp(result_field->string, "success");
}
-static int find_start_of_line(const char *str, int offset) {
- for(int i = offset; i >= 0; --i) {
- if(*str == '\n')
- return i + 1;
+static int transmission_add_torrent_response_get_torrent_name(struct json_object_s *json_root, const char **torrent_name) {
+ struct json_object_s *arguments_obj = json_object_get_child_object_by_name(json_root, "arguments");
+ if(!arguments_obj) {
+ fprintf(stderr, "Error: transmission add torrent response is missing arguments field or its not an object\n");
+ return -1;
}
- return 0;
-}
-static int find_end_of_previous_line(const char *str, int offset) {
- for(int i = offset; i >= 0; --i) {
- if(*str == '\n')
- return i - 1;
+ struct json_object_s *torrent_added_obj = json_object_get_child_object_by_name(arguments_obj, "torrent-added");
+ if(!torrent_added_obj)
+ torrent_added_obj = json_object_get_child_object_by_name(arguments_obj, "torrent-duplicate");
+
+ if(!torrent_added_obj) {
+ fprintf(stderr, "Error: transmission add torrent response is missing both torrent-added and torrent-duplicate argument\n");
+ return -1;
}
+
+ struct json_string_s *torrent_name_field = json_object_get_child_string_by_name(torrent_added_obj, "name");
+ if(!torrent_name_field) {
+ fprintf(stderr, "Error: transmission add torrent response is missing torrent name\n");
+ return -1;
+ }
+
+ *torrent_name = torrent_name_field->string;
return 0;
}
-int transmission_get_last_added_torrent(int *id_result, float *percentage_finished_result, char *title_result) {
+int transmission_add_torrent(TransmissionSession *session, const char *url, char **torrent_name) {
int result = 0;
-
Buffer buffer;
buffer_init(&buffer);
-
- const char *args[] = { "transmission-remote", "--list", NULL };
- int exec_res = program_exec(args, program_buffer_write_callback, &buffer);
- if(exec_res != 0) {
- result = exec_res;
+ struct json_value_s *json_response_val = NULL;
+
+ /* TODO: json escape url */
+ char request[4096];
+ int written_bytes = snprintf(request, sizeof(request), "{ \"arguments\": { \"filename\": \"%s\" }, \"method\": \"torrent-add\" }", url);
+ if(written_bytes >= (int)sizeof(request)) {
+ fprintf(stderr, "Failed to write all bytes to request (this is a bug)\n");
+ result = -1;
goto cleanup;
}
- char id[6];
- char done[6];
- char have[13];
- char format[7];
- char eta[33];
- char eta2[13];
- char up[11];
- char down[11];
- char ratio[11];
- char status[33];
- char name[256];
-
- int end_of_second_last_line = find_end_of_previous_line(buffer.data, (int)buffer.size - 1);
- int start_of_second_last_line = find_start_of_line(buffer.data, end_of_second_last_line);
-
- /* ID, Done, Have (size, format), ETA, Up, Down, Ratio, Status, Name */
- int res = sscanf(buffer.data + start_of_second_last_line, "%5s %5s %12s %6s %32s %12s %10s %10s %10s %32s %[^\n]", id, done, have, format, eta, eta2, up, down, ratio, status, name);
- if(res == EOF || res != NUM_COLUMNS + 1) {
- int res = sscanf(buffer.data + start_of_second_last_line, "%5s %5s %12s %6s %32s %10s %10s %10s %32s %[^\n]", id, done, have, format, eta, up, down, ratio, status, name);
- if(res == EOF || res != NUM_COLUMNS) {
- result = -1;
+ const char *args[] = { "curl", "-s", "-f", "-d", request, "-H", session->session_header, "--", "http://127.0.0.1:9091/transmission/rpc", NULL };
+ result = program_exec(args, program_buffer_write_callback, &buffer);
+ if(result != 0) {
+ /* Maybe the request failed because the session is no longer valid? retry once with new session id */
+ if(transmission_connect(session) != 0) {
+ fprintf(stderr, "Failed to add torrent: %s\n", url);
goto cleanup;
}
+
+ buffer_clear(&buffer);
+ const char *new_args[] = { "curl", "-s", "-f", "-d", request, "-H", session->session_header, "--", "http://127.0.0.1:9091/transmission/rpc", NULL };
+ result = program_exec(new_args, program_buffer_write_callback, &buffer);
+ if(result != 0) {
+ fprintf(stderr, "Failed to add torrent: %s\n", url);
+ goto cleanup;
+ }
+ }
+
+ json_response_val = json_parse(buffer.data, buffer.size);
+ if(!json_response_val || json_response_val->type != json_type_object) {
+ fprintf(stderr, "Failed to parse torrent add response: %.*s as json\n", (int)buffer.size, (char*)buffer.data);
+ result = -1;
+ goto cleanup;
}
- *id_result = atoi(id);
- *percentage_finished_result = atof(done);
- strcpy(title_result, name);
+ struct json_object_s *json_response_obj = json_value_as_object(json_response_val);
+
+ if(transmission_response_is_success(json_response_obj) != 0) {
+ fprintf(stderr, "Error: transmission torrent add request failed, response: %.*s\n", (int)buffer.size, (char*)buffer.data);
+ result = -1;
+ goto cleanup;
+ }
+
+ const char *response_torrent_name;
+ result = transmission_add_torrent_response_get_torrent_name(json_response_obj, &response_torrent_name);
+ if(result != 0)
+ goto cleanup;
+
+ *torrent_name = strdup(response_torrent_name);
cleanup:
+ free(json_response_val);
buffer_deinit(&buffer);
return result;
}