aboutsummaryrefslogtreecommitdiff
path: root/src/transmission.c
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-07-15 18:13:49 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-15 18:13:49 +0200
commit21208ecc1c6223cdfd2dbfeaff3bcfad8d0b8937 (patch)
tree67f151d022fdcd71bf2ddc5fff8046a4d3a8bfa1 /src/transmission.c
parent9946c0363648b44d396b07d8a1a4557c568edc88 (diff)
Add torrent complete notification
Diffstat (limited to 'src/transmission.c')
-rw-r--r--src/transmission.c141
1 files changed, 132 insertions, 9 deletions
diff --git a/src/transmission.c b/src/transmission.c
index d789053..39b355f 100644
--- a/src/transmission.c
+++ b/src/transmission.c
@@ -90,6 +90,13 @@ static struct json_string_s* json_object_get_child_string_by_name(struct json_ob
return (struct json_string_s*)json_child_str->payload;
}
+static struct json_number_s* json_object_get_child_number_by_name(struct json_object_s *json_obj, const char *field_name) {
+ struct json_value_s *json_number_str = json_object_get_field_by_name(json_obj, field_name);
+ if(!json_number_str || json_number_str->type != json_type_number)
+ return NULL;
+ return (struct json_number_s*)json_number_str->payload;
+}
+
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) {
@@ -100,7 +107,7 @@ static int transmission_response_is_success(struct json_object_s *json_root) {
return strcmp(result_field->string, "success");
}
-static int transmission_add_torrent_response_get_torrent_name(struct json_object_s *json_root, const char **torrent_name) {
+static int transmission_add_torrent_response_get_torrent_name(struct json_object_s *json_root, int *torrent_id, 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");
@@ -116,17 +123,33 @@ static int transmission_add_torrent_response_get_torrent_name(struct json_object
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;
+ if(torrent_id) {
+ struct json_number_s *torrent_id_field = json_object_get_child_number_by_name(torrent_added_obj, "id");
+ if(!torrent_id_field) {
+ fprintf(stderr, "Error: transmission add torrent response is missing torrent id\n");
+ return -1;
+ }
+
+ *torrent_id = atoi(torrent_id_field->number);
+ if(*torrent_id == 0) {
+ fprintf(stderr, "Error: transmission add torrent response has invalid torrent id\n");
+ return -1;
+ }
+ }
+
+ if(torrent_name) {
+ 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;
}
- *torrent_name = torrent_name_field->string;
return 0;
}
-int transmission_add_torrent(TransmissionSession *session, const char *url, char **torrent_name) {
+int transmission_add_torrent(TransmissionSession *session, const char *url, int *torrent_id, char **torrent_name) {
int result = 0;
Buffer buffer;
buffer_init(&buffer);
@@ -174,12 +197,112 @@ int transmission_add_torrent(TransmissionSession *session, const char *url, char
goto cleanup;
}
+ int response_torrent_id;
const char *response_torrent_name;
- result = transmission_add_torrent_response_get_torrent_name(json_response_obj, &response_torrent_name);
+ result = transmission_add_torrent_response_get_torrent_name(json_response_obj,
+ torrent_id ? &response_torrent_id : NULL,
+ torrent_name ? &response_torrent_name : NULL);
+
if(result != 0)
goto cleanup;
- *torrent_name = strdup(response_torrent_name);
+ if(torrent_id)
+ *torrent_id = response_torrent_id;
+
+ if(torrent_name)
+ *torrent_name = strdup(response_torrent_name);
+
+ cleanup:
+ free(json_response_val);
+ buffer_deinit(&buffer);
+ return result;
+}
+
+int transmission_list_torrents(TransmissionSession *session, TorrentListCallback callback, void *userdata) {
+ int result = 0;
+ Buffer buffer;
+ buffer_init(&buffer);
+ struct json_value_s *json_response_val = NULL;
+
+ char request[100];
+ int written_bytes = snprintf(request, sizeof(request), "{ \"arguments\": { \"fields\": [ \"id\", \"name\", \"percentDone\" ] }, \"method\": \"torrent-get\" }");
+ if(written_bytes >= (int)sizeof(request)) {
+ fprintf(stderr, "Failed to write all bytes to request (this is a bug)\n");
+ result = -1;
+ goto cleanup;
+ }
+
+ 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 list torrents\n");
+ 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 list torrents\n");
+ 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 list response: %.*s as json\n", (int)buffer.size, (char*)buffer.data);
+ result = -1;
+ goto cleanup;
+ }
+
+ 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 list request failed, response: %.*s\n", (int)buffer.size, (char*)buffer.data);
+ result = -1;
+ goto cleanup;
+ }
+
+ struct json_value_s *arguments_field = json_object_get_field_by_name(json_response_obj, "arguments");
+ if(!arguments_field || arguments_field->type != json_type_object) {
+ fprintf(stderr, "Error: transmission torrent list response is missing arguments or its not an object\n");
+ result = -1;
+ goto cleanup;
+ }
+
+ struct json_object_s *arguments_field_obj = json_value_as_object(arguments_field);
+ struct json_value_s *torrents_field = json_object_get_field_by_name(arguments_field_obj, "torrents");
+ if(!torrents_field || torrents_field->type != json_type_array) {
+ fprintf(stderr, "Error: transmission torrent list response is missing torrents or its not an array\n");
+ result = -1;
+ goto cleanup;
+ }
+
+ struct json_array_element_s *torrent_item = json_value_as_array(torrents_field)->start;
+ while(torrent_item) {
+ struct json_object_s *torrent_item_obj = json_value_as_object(torrent_item->value);
+ if(!torrent_item_obj)
+ continue;
+
+ struct json_value_s *id_field = json_object_get_field_by_name(torrent_item_obj, "id");
+ struct json_value_s *name_field = json_object_get_field_by_name(torrent_item_obj, "name");
+ struct json_value_s *percent_done_field = json_object_get_field_by_name(torrent_item_obj, "percentDone");
+ if(!id_field || id_field->type != json_type_number
+ || !name_field || name_field->type != json_type_string
+ || !percent_done_field || percent_done_field->type != json_type_number)
+ {
+ continue;
+ }
+
+ callback(atoi(json_value_as_number(id_field)->number),
+ json_value_as_string(name_field)->string,
+ atof(json_value_as_number(percent_done_field)->number),
+ userdata);
+
+ torrent_item = torrent_item->next;
+ }
cleanup:
free(json_response_val);