source: trunk/gtk/tr_torrent.c @ 249

Last change on this file since 249 was 249, checked in by joshe, 16 years ago

Some minor code cleanups.
Handle things a little better when quitting.

File size: 9.2 KB
Line 
1#include <string.h>
2#include <unistd.h>
3
4#include <gtk/gtk.h>
5#include <glib/gi18n.h>
6
7#define TR_WANT_BACKEND_PRIVATE
8
9#include "transmission.h"
10#include "bencode.h"
11
12#include "tr_backend.h"
13#include "tr_torrent.h"
14#include "util.h"
15
16enum {
17  TR_TORRENT_HANDLE = 1,
18  TR_TORRENT_BACKEND,
19  TR_TORRENT_DIR,
20  TR_TORRENT_PAUSED,
21};
22
23static void
24tr_torrent_init(GTypeInstance *instance, gpointer g_class);
25static void
26tr_torrent_set_property(GObject *object, guint property_id,
27                        const GValue *value, GParamSpec *pspec);
28static void
29tr_torrent_get_property(GObject *object, guint property_id,
30                        GValue *value, GParamSpec *pspec);
31static void
32tr_torrent_class_init(gpointer g_class, gpointer g_class_data);
33static void
34tr_torrent_dispose(GObject *obj);
35static void
36tr_torrent_set_folder(TrTorrent *tor);
37static gboolean
38tr_torrent_paused(TrTorrent *tor);
39
40GType
41tr_torrent_get_type(void) {
42  static GType type = 0;
43
44  if(0 == type) {
45    static const GTypeInfo info = {
46      sizeof (TrTorrentClass),
47      NULL,   /* base_init */
48      NULL,   /* base_finalize */
49      tr_torrent_class_init,   /* class_init */
50      NULL,   /* class_finalize */
51      NULL,   /* class_data */
52      sizeof (TrTorrent),
53      0,      /* n_preallocs */
54      tr_torrent_init, /* instance_init */
55      NULL,
56    };
57    type = g_type_register_static(G_TYPE_OBJECT, "TrTorrentType", &info, 0);
58  }
59  return type;
60}
61
62static void
63tr_torrent_class_init(gpointer g_class, gpointer g_class_data SHUTUP) {
64  GObjectClass *gobject_class = G_OBJECT_CLASS(g_class);
65  //TrTorrentClass *klass = TR_TORRENT_CLASS(g_class);
66  GParamSpec *pspec;
67
68  gobject_class->set_property = tr_torrent_set_property;
69  gobject_class->get_property = tr_torrent_get_property;
70  gobject_class->dispose = tr_torrent_dispose;
71
72  pspec = g_param_spec_pointer("torrent-handle", "Torrent handle",
73                               "Torrent handle from libtransmission",
74                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
75  g_object_class_install_property(gobject_class, TR_TORRENT_HANDLE, pspec);
76
77  pspec = g_param_spec_object("backend", "Backend",
78                              "Libtransmission backend object",
79                              TR_BACKEND_TYPE,
80                              G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
81  g_object_class_install_property(gobject_class, TR_TORRENT_BACKEND, pspec);
82
83  pspec = g_param_spec_string("download-directory", "Download directory",
84                              "Directory to download files to", NULL,
85                              G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
86  g_object_class_install_property(gobject_class, TR_TORRENT_DIR, pspec);
87
88  pspec = g_param_spec_boolean("paused", "Paused",
89                               "Is the torrent paused or running", TRUE,
90                               G_PARAM_READWRITE);
91  g_object_class_install_property(gobject_class, TR_TORRENT_PAUSED, pspec);
92}
93
94static void
95tr_torrent_init(GTypeInstance *instance, gpointer g_class SHUTUP) {
96  TrTorrent *self = (TrTorrent *)instance;
97
98  self->handle = NULL;
99  self->back = NULL;
100  self->dir = NULL;
101  self->disposed = FALSE;
102}
103
104static void
105tr_torrent_set_property(GObject *object, guint property_id,
106                        const GValue *value, GParamSpec *pspec) {
107  TrTorrent *self = (TrTorrent*)object;
108
109  if(self->disposed)
110    return;
111
112  switch(property_id) {
113    case TR_TORRENT_HANDLE:
114      g_assert(NULL == self->handle);
115      self->handle = g_value_get_pointer(value);
116      if(NULL != self->handle && NULL != self->dir)
117        tr_torrent_set_folder(self);
118      break;
119    case TR_TORRENT_BACKEND:
120      g_assert(NULL == self->back);
121      self->back = g_object_ref(g_value_get_object(value));
122      break;
123    case TR_TORRENT_DIR:
124      g_assert(NULL == self->dir);
125      self->dir = g_value_dup_string(value);
126      if(NULL != self->handle && NULL != self->dir)
127        tr_torrent_set_folder(self);
128      break;
129    case TR_TORRENT_PAUSED:
130      g_assert(NULL != self->handle);
131      if(tr_torrent_paused(self) != g_value_get_boolean(value))
132        (g_value_get_boolean(value) ? tr_torrentStop : tr_torrentStart)
133          (self->handle);
134      break;
135    default:
136      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
137      break;
138  }
139}
140
141static void
142tr_torrent_get_property(GObject *object, guint property_id,
143                        GValue *value, GParamSpec *pspec) {
144  TrTorrent *self = (TrTorrent*)object;
145
146  if(self->disposed)
147    return;
148
149  switch(property_id) {
150    case TR_TORRENT_HANDLE:
151      g_value_set_pointer(value, self->handle);
152      break;
153    case TR_TORRENT_BACKEND:
154      g_value_set_object(value, self->back);
155      break;
156    case TR_TORRENT_DIR:
157      g_value_set_string(value, (NULL != self->dir ? self->dir :
158                                 tr_torrentGetFolder(self->handle)));
159      break;
160    case TR_TORRENT_PAUSED:
161      g_value_set_boolean(value, tr_torrent_paused(self));
162      break;
163    default:
164      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
165      break;
166  }
167}
168
169static void
170tr_torrent_dispose(GObject *obj) {
171  GObjectClass *parent = g_type_class_peek(g_type_parent(TR_TORRENT_TYPE));
172  TrTorrent *self = (TrTorrent*)obj;
173
174  if(self->disposed)
175    return;
176  self->disposed = TRUE;
177
178  if(NULL != self->handle) {
179    if(!tr_torrent_paused(self))
180      tr_torrentStop(self->handle);
181    tr_torrentClose(tr_backend_handle(TR_BACKEND(self->back)), self->handle);
182    self->handle = NULL;
183  }
184
185  if(NULL != self->back) {
186    g_object_unref(self->back);
187    self->back = NULL;
188  }
189
190  /* Chain up to the parent class */
191  parent->dispose(obj);
192}
193
194tr_torrent_t *
195tr_torrent_handle(TrTorrent *tor) {
196  TR_IS_TORRENT(tor);
197
198  if(tor->disposed)
199    return NULL;
200
201  return tor->handle;
202}
203
204tr_stat_t *
205tr_torrent_stat(TrTorrent *tor) {
206  TR_IS_TORRENT(tor);
207
208  if(tor->disposed)
209    return NULL;
210
211  return tr_torrentStat(tor->handle);
212}
213
214tr_info_t *
215tr_torrent_info(TrTorrent *tor) {
216  TR_IS_TORRENT(tor);
217
218  if(tor->disposed)
219    return NULL;
220
221  return tr_torrentInfo(tor->handle);
222}
223
224TrTorrent *
225tr_torrent_new(GObject *backend, const char *torrent, const char *dir,
226               gboolean *paused, char **err) {
227  TrTorrent *ret;
228  tr_torrent_t *handle;
229  int errcode;
230
231  TR_IS_BACKEND(backend);
232  g_assert(NULL != dir);
233
234  *err = NULL;
235
236  errcode = -1;
237  handle = tr_torrentInit(tr_backend_handle(TR_BACKEND(backend)),
238                          torrent, &errcode);
239  if(NULL == handle) {
240    switch(errcode) {
241      case TR_EINVALID:
242        *err = g_strdup_printf(_("%s: not a valid torrent file"), torrent);
243        break;
244      case TR_EDUPLICATE:
245        *err = g_strdup_printf(_("%s: torrent is already open"), torrent);
246        break;
247      default:
248        *err = g_strdup(torrent);
249        break;
250    }
251    return NULL;
252  }
253
254  ret = g_object_new(TR_TORRENT_TYPE, "torrent-handle", handle,
255                     "backend", backend, "download-directory", dir, NULL);
256  tr_backend_add_torrent(TR_BACKEND(backend), G_OBJECT(ret));
257
258  g_object_set(ret, "paused", (NULL == paused ? FALSE : *paused), NULL);
259
260  return ret;
261}
262
263TrTorrent *
264tr_torrent_new_with_state(GObject *backend, benc_val_t *state, char **err) {
265  int ii;
266  benc_val_t *name, *data;
267  char *torrent, *dir;
268  gboolean hadpaused, paused;
269
270  *err = NULL;
271
272  if(TYPE_DICT != state->type)
273    return NULL;
274
275  torrent = dir = NULL;
276  hadpaused = FALSE;
277
278  for(ii = 0; ii + 1 < state->val.l.count; ii += 2) {
279    name = state->val.l.vals + ii;
280    data = state->val.l.vals + ii + 1;
281    if(TYPE_STR == name->type &&
282       (TYPE_STR == data->type || TYPE_INT == data->type)) {
283      if(0 == strcmp("torrent", name->val.s.s))
284        torrent = data->val.s.s;
285      else if(0 == strcmp("dir", name->val.s.s))
286        dir = data->val.s.s;
287      else if(0 == strcmp("paused", name->val.s.s)) {
288        hadpaused = TRUE;
289        paused = (data->val.i ? TRUE : FALSE);
290      }
291    }
292  }
293
294  if(NULL == torrent || NULL == dir)
295    return NULL;
296
297  return tr_torrent_new(backend, torrent, dir,
298                        (hadpaused ? &paused : NULL), err);
299}
300
301void
302tr_torrent_get_state(TrTorrent *tor, benc_val_t *state) {
303  tr_info_t *in = tr_torrentInfo(tor->handle);
304  const char *strs[] = {
305    "torrent", in->torrent, "dir", tr_torrentGetFolder(tor->handle), "paused", 
306  };
307  unsigned int ii;
308  const unsigned int len = 6;
309
310  TR_IS_TORRENT(tor);
311
312  if(tor->disposed)
313    return;
314
315  state->type = TYPE_DICT;
316  state->val.l.vals = g_new0(benc_val_t, len);
317  state->val.l.alloc = state->val.l.count = len;
318
319  g_assert(len > ALEN(strs));
320  for(ii = 0; ii < ALEN(strs); ii++) {
321    state->val.l.vals[ii].type = TYPE_STR;
322    state->val.l.vals[ii].val.s.s = g_strdup(strs[ii]);
323    state->val.l.vals[ii].val.s.i = strlen(strs[ii]);
324  }
325
326  state->val.l.vals[ii].type = TYPE_INT;
327  state->val.l.vals[ii].val.i = tr_torrent_paused(tor);
328  ii++;
329
330  g_assert(len == ii);
331}
332
333static void
334tr_torrent_set_folder(TrTorrent *tor) {
335  char *wd;
336
337  if(NULL != tor->dir)
338    tr_torrentSetFolder(tor->handle, tor->dir);
339  else {
340    wd = g_new(char, MAX_PATH_LENGTH + 1);
341    tr_torrentSetFolder(tor->handle,
342                        (NULL == getcwd(wd, MAX_PATH_LENGTH + 1) ? "." : wd));
343    g_free(wd);
344  }
345}
346
347static gboolean
348tr_torrent_paused(TrTorrent *tor) {
349  tr_stat_t *st = tr_torrentStat(tor->handle);
350
351  return (TR_STATUS_INACTIVE & st->status ? TRUE : FALSE);
352}
Note: See TracBrowser for help on using the repository browser.