aboutsummaryrefslogtreecommitdiff
path: root/src/transmission.c
blob: b9cb123797263e8bbfd71b81704bea00b2ec9c77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "transmission.h"
#include "program.h"
#include "buffer.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#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;
}