1 | #include <string.h> |
---|
2 | |
---|
3 | #include <gtk/gtk.h> |
---|
4 | #include <glib/gi18n.h> |
---|
5 | |
---|
6 | #define TR_WANT_TORRENT_PRIVATE |
---|
7 | |
---|
8 | #include "transmission.h" |
---|
9 | #include "bencode.h" |
---|
10 | |
---|
11 | #include "conf.h" |
---|
12 | #include "tr_backend.h" |
---|
13 | #include "tr_torrent.h" |
---|
14 | #include "util.h" |
---|
15 | |
---|
16 | /* |
---|
17 | enum { |
---|
18 | TR_BACKEND_HANDLE = 1, |
---|
19 | }; |
---|
20 | */ |
---|
21 | |
---|
22 | static void |
---|
23 | tr_backend_init(GTypeInstance *instance, gpointer g_class); |
---|
24 | static void |
---|
25 | tr_backend_set_property(GObject *object, guint property_id, |
---|
26 | const GValue *value, GParamSpec *pspec); |
---|
27 | static void |
---|
28 | tr_backend_get_property(GObject *object, guint property_id, |
---|
29 | GValue *value, GParamSpec *pspec); |
---|
30 | static void |
---|
31 | tr_backend_class_init(gpointer g_class, gpointer g_class_data); |
---|
32 | static void |
---|
33 | tr_backend_dispose(GObject *obj); |
---|
34 | static void |
---|
35 | tr_backend_finalize(GObject *obj); |
---|
36 | static void |
---|
37 | tr_backend_torrent_finalized(gpointer gdata, GObject *tor); |
---|
38 | |
---|
39 | GType |
---|
40 | tr_backend_get_type(void) { |
---|
41 | static GType type = 0; |
---|
42 | |
---|
43 | if(0 == type) { |
---|
44 | static const GTypeInfo info = { |
---|
45 | sizeof (TrBackendClass), |
---|
46 | NULL, /* base_init */ |
---|
47 | NULL, /* base_finalize */ |
---|
48 | tr_backend_class_init, /* class_init */ |
---|
49 | NULL, /* class_finalize */ |
---|
50 | NULL, /* class_data */ |
---|
51 | sizeof (TrBackend), |
---|
52 | 0, /* n_preallocs */ |
---|
53 | tr_backend_init, /* instance_init */ |
---|
54 | NULL, |
---|
55 | }; |
---|
56 | type = g_type_register_static(G_TYPE_OBJECT, "TrBackendType", &info, 0); |
---|
57 | } |
---|
58 | return type; |
---|
59 | } |
---|
60 | |
---|
61 | static void |
---|
62 | tr_backend_class_init(gpointer g_class, gpointer g_class_data SHUTUP) { |
---|
63 | GObjectClass *gobject_class = G_OBJECT_CLASS(g_class); |
---|
64 | //GParamSpec *pspec; |
---|
65 | |
---|
66 | gobject_class->set_property = tr_backend_set_property; |
---|
67 | gobject_class->get_property = tr_backend_get_property; |
---|
68 | gobject_class->dispose = tr_backend_dispose; |
---|
69 | gobject_class->finalize = tr_backend_finalize; |
---|
70 | |
---|
71 | /* |
---|
72 | pspec = g_param_spec_pointer("backend-handle", _("Backend handle"), |
---|
73 | _("Backend handle from libtransmission"), |
---|
74 | G_PARAM_READWRITE); |
---|
75 | g_object_class_install_property(gobject_class, TR_BACKEND_HANDLE, pspec); |
---|
76 | */ |
---|
77 | } |
---|
78 | |
---|
79 | static void |
---|
80 | tr_backend_init(GTypeInstance *instance, gpointer g_class SHUTUP) { |
---|
81 | TrBackend *self = (TrBackend *)instance; |
---|
82 | |
---|
83 | self->handle = tr_init(); |
---|
84 | self->disposed = FALSE; |
---|
85 | } |
---|
86 | |
---|
87 | static void |
---|
88 | tr_backend_set_property(GObject *object, guint property_id, |
---|
89 | const GValue *value SHUTUP, GParamSpec *pspec) { |
---|
90 | TrBackend *self = (TrBackend*)object; |
---|
91 | |
---|
92 | if(self->disposed) |
---|
93 | return; |
---|
94 | |
---|
95 | switch(property_id) { |
---|
96 | /* |
---|
97 | case TR_BACKEND_HANDLE: |
---|
98 | g_assert(NULL == self->handle); |
---|
99 | self->handle = g_value_get_pointer(value); |
---|
100 | break; |
---|
101 | */ |
---|
102 | default: |
---|
103 | G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); |
---|
104 | break; |
---|
105 | } |
---|
106 | } |
---|
107 | |
---|
108 | static void |
---|
109 | tr_backend_get_property(GObject *object, guint property_id, |
---|
110 | GValue *value SHUTUP, GParamSpec *pspec) { |
---|
111 | TrBackend *self = (TrBackend*)object; |
---|
112 | |
---|
113 | if(self->disposed) |
---|
114 | return; |
---|
115 | |
---|
116 | switch(property_id) { |
---|
117 | /* |
---|
118 | case TR_BACKEND_HANDLE: |
---|
119 | g_value_set_pointer(value, self->handle); |
---|
120 | break; |
---|
121 | */ |
---|
122 | default: |
---|
123 | G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); |
---|
124 | break; |
---|
125 | } |
---|
126 | } |
---|
127 | |
---|
128 | static void |
---|
129 | tr_backend_dispose(GObject *obj) { |
---|
130 | GObjectClass *parent = g_type_class_peek(g_type_parent(TR_BACKEND_TYPE)); |
---|
131 | TrBackend *self = (TrBackend*)obj; |
---|
132 | GList *ii; |
---|
133 | |
---|
134 | if(self->disposed) |
---|
135 | return; |
---|
136 | self->disposed = TRUE; |
---|
137 | |
---|
138 | if(NULL != self->torrents) { |
---|
139 | for(ii = self->torrents; NULL != ii; ii = ii->next) |
---|
140 | g_object_weak_unref(ii->data, tr_backend_torrent_finalized, self); |
---|
141 | g_list_free(self->torrents); |
---|
142 | self->torrents = NULL; |
---|
143 | } |
---|
144 | |
---|
145 | /* Chain up to the parent class */ |
---|
146 | parent->dispose(obj); |
---|
147 | } |
---|
148 | |
---|
149 | static void |
---|
150 | tr_backend_finalize(GObject *obj) { |
---|
151 | GObjectClass *parent = g_type_class_peek(g_type_parent(TR_BACKEND_TYPE)); |
---|
152 | TrBackend *self = (TrBackend *)obj; |
---|
153 | |
---|
154 | if(NULL != self->handle) |
---|
155 | tr_close(self->handle); |
---|
156 | |
---|
157 | /* Chain up to the parent class */ |
---|
158 | parent->finalize(obj); |
---|
159 | } |
---|
160 | |
---|
161 | TrBackend * |
---|
162 | tr_backend_new(void) { |
---|
163 | return g_object_new(TR_BACKEND_TYPE, NULL); |
---|
164 | } |
---|
165 | |
---|
166 | tr_handle_t * |
---|
167 | tr_backend_handle(TrBackend *back) { |
---|
168 | TR_IS_BACKEND(back); |
---|
169 | |
---|
170 | return back->handle; |
---|
171 | } |
---|
172 | |
---|
173 | void |
---|
174 | tr_backend_save_state(TrBackend *back, char **errstr) { |
---|
175 | benc_val_t state; |
---|
176 | int ii; |
---|
177 | GList *jj; |
---|
178 | |
---|
179 | TR_IS_BACKEND(back); |
---|
180 | |
---|
181 | bzero(&state, sizeof(state)); |
---|
182 | state.type = TYPE_LIST; |
---|
183 | state.val.l.alloc = state.val.l.count = g_list_length(back->torrents); |
---|
184 | state.val.l.vals = g_new0(benc_val_t, state.val.l.alloc); |
---|
185 | |
---|
186 | for(ii = 0, jj = back->torrents; NULL != jj; ii++, jj = jj->next) |
---|
187 | tr_torrent_get_state(jj->data, state.val.l.vals + ii); |
---|
188 | |
---|
189 | cf_savestate(&state, errstr); |
---|
190 | tr_bencFree(&state); |
---|
191 | } |
---|
192 | |
---|
193 | GList * |
---|
194 | tr_backend_load_state(TrBackend *back, benc_val_t *state, GList **errors) { |
---|
195 | GList *ret = NULL; |
---|
196 | int ii; |
---|
197 | TrTorrent *tor; |
---|
198 | char *errstr; |
---|
199 | |
---|
200 | TR_IS_BACKEND(back); |
---|
201 | |
---|
202 | if(TYPE_LIST != state->type) |
---|
203 | return NULL; |
---|
204 | |
---|
205 | for(ii = 0; ii < state->val.l.count; ii++) { |
---|
206 | errstr = NULL; |
---|
207 | tor = tr_torrent_new_with_state(G_OBJECT(back), state->val.l.vals + ii, |
---|
208 | &errstr); |
---|
209 | if(NULL != errstr) |
---|
210 | *errors = g_list_append(*errors, errstr); |
---|
211 | if(NULL != tor) |
---|
212 | ret = g_list_append(ret, tor); |
---|
213 | } |
---|
214 | |
---|
215 | return ret; |
---|
216 | } |
---|
217 | |
---|
218 | void |
---|
219 | tr_backend_add_torrent(TrBackend *back, GObject *tor) { |
---|
220 | TR_IS_BACKEND(back); |
---|
221 | TR_IS_TORRENT(tor); |
---|
222 | |
---|
223 | g_object_weak_ref(tor, tr_backend_torrent_finalized, back); |
---|
224 | back->torrents = g_list_append(back->torrents, tor); |
---|
225 | } |
---|
226 | |
---|
227 | static void |
---|
228 | tr_backend_torrent_finalized(gpointer gdata, GObject *tor) { |
---|
229 | TrBackend *back = gdata; |
---|
230 | |
---|
231 | TR_IS_BACKEND(back); |
---|
232 | |
---|
233 | back->torrents = g_list_remove(back->torrents, tor); |
---|
234 | } |
---|
235 | |
---|
236 | void |
---|
237 | tr_backend_stop_torrents(TrBackend *back) { |
---|
238 | GList *ii; |
---|
239 | |
---|
240 | TR_IS_BACKEND(back); |
---|
241 | |
---|
242 | for(ii = back->torrents; NULL != ii; ii = ii->next) |
---|
243 | if(TR_STATUS_ACTIVE & tr_torrent_stat(ii->data)->status) |
---|
244 | tr_torrentStop(tr_torrent_handle(ii->data)); |
---|
245 | } |
---|
246 | |
---|
247 | gboolean |
---|
248 | tr_backend_torrents_stopped(TrBackend *back) { |
---|
249 | GList *ii; |
---|
250 | |
---|
251 | TR_IS_BACKEND(back); |
---|
252 | |
---|
253 | for(ii = back->torrents; NULL != ii; ii = ii->next) |
---|
254 | if(TR_STATUS_ACTIVE & tr_torrent_stat(ii->data)->status) |
---|
255 | return FALSE; |
---|
256 | |
---|
257 | return TRUE; |
---|
258 | } |
---|