#include "transmission.h" #include "program.h" #include "buffer.h" #include #include #include #include #define NUM_COLUMNS 10 int transmission_is_daemon_running(void) { const char *args[] = { "transmission-remote", "-si", NULL }; return program_exec(args, NULL, NULL); } int transmission_start_daemon(const char *download_dir) { /* TODO: Make seed ratio configurable */ const char *args[] = { "transmission-daemon", "--global-seedratio", "2.0", "--download-dir", download_dir, NULL }; int res = program_exec(args, NULL, NULL); if(res != 0) return res; fprintf(stderr, "Waiting for the transmission daemon to startup...\n"); int num_tries = 0; const int max_tries = 7; /* 7 seconds */ while(transmission_is_daemon_running() != 0 && num_tries < max_tries) { sleep(1); ++num_tries; } if(num_tries == max_tries) { fprintf(stderr, "Failed to launch transmission daemon in 7 seconds\n"); return -1; } fprintf(stderr, "The transmission daemon is now running!\n"); return 0; } int transmission_add_torrent(const char *url) { const char *args[] = { "transmission-remote", "-a", "--", url, NULL }; return program_exec(args, NULL, NULL); } 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; 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; } cleanup: buffer_deinit(&buffer); return result; } static int find_start_of_line(const char *str, int offset) { for(int i = offset; i >= 0; --i) { if(*str == '\n') return i + 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; } return 0; } int transmission_get_last_added_torrent(int *id_result, float *percentage_finished_result, char *title_result) { 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; } 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; goto cleanup; } } *id_result = atoi(id); *percentage_finished_result = atof(done); strcpy(title_result, name); cleanup: buffer_deinit(&buffer); return result; }