source: trunk/gtk/tr_torrent.c @ 261

Last change on this file since 261 was 261, checked in by titer, 16 years ago

Updated svn:keywords

  • Property svn:keywords set to Date Rev Author Id
File size: 10.5 KB
Line 
1/*
2  $Id: tr_torrent.c 261 2006-05-29 21:27:31Z titer $
3
4  Copyright (c) 2006 Joshua Elsasser. All rights reserved.
5   
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions
8  are met:
9   
10   1. Redistributions of source code must retain the above copyright
11      notice, this list of conditions and the following disclaimer.
12   2. Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15   
16  THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS "AS IS" AND
17  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  POSSIBILITY OF SUCH DAMAGE.
27*/
28
29#include <string.h>
30#include <unistd.h>
31
32#include <gtk/gtk.h>
33#include <glib/gi18n.h>
34
35#define TR_WANT_BACKEND_PRIVATE
36
37#include "transmission.h"
38#include "bencode.h"
39
40#include "tr_backend.h"
41#include "tr_torrent.h"
42#include "util.h"
43
44enum {
45  TR_TORRENT_HANDLE = 1,
46  TR_TORRENT_BACKEND,
47  TR_TORRENT_DIR,
48  TR_TORRENT_PAUSED,
49};
50
51static void
52tr_torrent_init(GTypeInstance *instance, gpointer g_class);
53static void
54tr_torrent_set_property(GObject *object, guint property_id,
55                        const GValue *value, GParamSpec *pspec);
56static void
57tr_torrent_get_property(GObject *object, guint property_id,
58                        GValue *value, GParamSpec *pspec);
59static void
60tr_torrent_class_init(gpointer g_class, gpointer g_class_data);
61static void
62tr_torrent_dispose(GObject *obj);
63static void
64tr_torrent_set_folder(TrTorrent *tor);
65static gboolean
66tr_torrent_paused(TrTorrent *tor);
67
68GType
69tr_torrent_get_type(void) {
70  static GType type = 0;
71
72  if(0 == type) {
73    static const GTypeInfo info = {
74      sizeof (TrTorrentClass),
75      NULL,   /* base_init */
76      NULL,   /* base_finalize */
77      tr_torrent_class_init,   /* class_init */
78      NULL,   /* class_finalize */
79      NULL,   /* class_data */
80      sizeof (TrTorrent),
81      0,      /* n_preallocs */
82      tr_torrent_init, /* instance_init */
83      NULL,
84    };
85    type = g_type_register_static(G_TYPE_OBJECT, "TrTorrentType", &info, 0);
86  }
87  return type;
88}
89
90static void
91tr_torrent_class_init(gpointer g_class, gpointer g_class_data SHUTUP) {
92  GObjectClass *gobject_class = G_OBJECT_CLASS(g_class);
93  //TrTorrentClass *klass = TR_TORRENT_CLASS(g_class);
94  GParamSpec *pspec;
95
96  gobject_class->set_property = tr_torrent_set_property;
97  gobject_class->get_property = tr_torrent_get_property;
98  gobject_class->dispose = tr_torrent_dispose;
99
100  pspec = g_param_spec_pointer("torrent-handle", "Torrent handle",
101                               "Torrent handle from libtransmission",
102                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
103  g_object_class_install_property(gobject_class, TR_TORRENT_HANDLE, pspec);
104
105  pspec = g_param_spec_object("backend", "Backend",
106                              "Libtransmission backend object",
107                              TR_BACKEND_TYPE,
108                              G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
109  g_object_class_install_property(gobject_class, TR_TORRENT_BACKEND, pspec);
110
111  pspec = g_param_spec_string("download-directory", "Download directory",
112                              "Directory to download files to", NULL,
113                              G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
114  g_object_class_install_property(gobject_class, TR_TORRENT_DIR, pspec);
115
116  pspec = g_param_spec_boolean("paused", "Paused",
117                               "Is the torrent paused or running", TRUE,
118                               G_PARAM_READWRITE);
119  g_object_class_install_property(gobject_class, TR_TORRENT_PAUSED, pspec);
120}
121
122static void
123tr_torrent_init(GTypeInstance *instance, gpointer g_class SHUTUP) {
124  TrTorrent *self = (TrTorrent *)instance;
125
126  self->handle = NULL;
127  self->back = NULL;
128  self->dir = NULL;
129  self->disposed = FALSE;
130}
131
132static void
133tr_torrent_set_property(GObject *object, guint property_id,
134                        const GValue *value, GParamSpec *pspec) {
135  TrTorrent *self = (TrTorrent*)object;
136
137  if(self->disposed)
138    return;
139
140  switch(property_id) {
141    case TR_TORRENT_HANDLE:
142      g_assert(NULL == self->handle);
143      self->handle = g_value_get_pointer(value);
144      if(NULL != self->handle && NULL != self->dir)
145        tr_torrent_set_folder(self);
146      break;
147    case TR_TORRENT_BACKEND:
148      g_assert(NULL == self->back);
149      self->back = g_object_ref(g_value_get_object(value));
150      break;
151    case TR_TORRENT_DIR:
152      g_assert(NULL == self->dir);
153      self->dir = g_value_dup_string(value);
154      if(NULL != self->handle && NULL != self->dir)
155        tr_torrent_set_folder(self);
156      break;
157    case TR_TORRENT_PAUSED:
158      g_assert(NULL != self->handle);
159      if(tr_torrent_paused(self) != g_value_get_boolean(value))
160        (g_value_get_boolean(value) ? tr_torrentStop : tr_torrentStart)
161          (self->handle);
162      break;
163    default:
164      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
165      break;
166  }
167}
168
169static void
170tr_torrent_get_property(GObject *object, guint property_id,
171                        GValue *value, GParamSpec *pspec) {
172  TrTorrent *self = (TrTorrent*)object;
173
174  if(self->disposed)
175    return;
176
177  switch(property_id) {
178    case TR_TORRENT_HANDLE:
179      g_value_set_pointer(value, self->handle);
180      break;
181    case TR_TORRENT_BACKEND:
182      g_value_set_object(value, self->back);
183      break;
184    case TR_TORRENT_DIR:
185      g_value_set_string(value, (NULL != self->dir ? self->dir :
186                                 tr_torrentGetFolder(self->handle)));
187      break;
188    case TR_TORRENT_PAUSED:
189      g_value_set_boolean(value, tr_torrent_paused(self));
190      break;
191    default:
192      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
193      break;
194  }
195}
196
197static void
198tr_torrent_dispose(GObject *obj) {
199  GObjectClass *parent = g_type_class_peek(g_type_parent(TR_TORRENT_TYPE));
200  TrTorrent *self = (TrTorrent*)obj;
201
202  if(self->disposed)
203    return;
204  self->disposed = TRUE;
205
206  if(NULL != self->handle) {
207    if(!tr_torrent_paused(self))
208      tr_torrentStop(self->handle);
209    tr_torrentClose(tr_backend_handle(TR_BACKEND(self->back)), self->handle);
210    self->handle = NULL;
211  }
212
213  if(NULL != self->back) {
214    g_object_unref(self->back);
215    self->back = NULL;
216  }
217
218  /* Chain up to the parent class */
219  parent->dispose(obj);
220}
221
222tr_torrent_t *
223tr_torrent_handle(TrTorrent *tor) {
224  TR_IS_TORRENT(tor);
225
226  if(tor->disposed)
227    return NULL;
228
229  return tor->handle;
230}
231
232tr_stat_t *
233tr_torrent_stat(TrTorrent *tor) {
234  TR_IS_TORRENT(tor);
235
236  if(tor->disposed)
237    return NULL;
238
239  return tr_torrentStat(tor->handle);
240}
241
242tr_info_t *
243tr_torrent_info(TrTorrent *tor) {
244  TR_IS_TORRENT(tor);
245
246  if(tor->disposed)
247    return NULL;
248
249  return tr_torrentInfo(tor->handle);
250}
251
252TrTorrent *
253tr_torrent_new(GObject *backend, const char *torrent, const char *dir,
254               gboolean *paused, char **err) {
255  TrTorrent *ret;
256  tr_torrent_t *handle;
257  int errcode;
258
259  TR_IS_BACKEND(backend);
260  g_assert(NULL != dir);
261
262  *err = NULL;
263
264  errcode = -1;
265  handle = tr_torrentInit(tr_backend_handle(TR_BACKEND(backend)),
266                          torrent, &errcode);
267  if(NULL == handle) {
268    switch(errcode) {
269      case TR_EINVALID:
270        *err = g_strdup_printf(_("%s: not a valid torrent file"), torrent);
271        break;
272      case TR_EDUPLICATE:
273        *err = g_strdup_printf(_("%s: torrent is already open"), torrent);
274        break;
275      default:
276        *err = g_strdup(torrent);
277        break;
278    }
279    return NULL;
280  }
281
282  ret = g_object_new(TR_TORRENT_TYPE, "torrent-handle", handle,
283                     "backend", backend, "download-directory", dir, NULL);
284  tr_backend_add_torrent(TR_BACKEND(backend), G_OBJECT(ret));
285
286  g_object_set(ret, "paused", (NULL == paused ? FALSE : *paused), NULL);
287
288  return ret;
289}
290
291TrTorrent *
292tr_torrent_new_with_state(GObject *backend, benc_val_t *state, char **err) {
293  int ii;
294  benc_val_t *name, *data;
295  char *torrent, *dir;
296  gboolean hadpaused, paused;
297
298  *err = NULL;
299
300  if(TYPE_DICT != state->type)
301    return NULL;
302
303  torrent = dir = NULL;
304  hadpaused = FALSE;
305
306  for(ii = 0; ii + 1 < state->val.l.count; ii += 2) {
307    name = state->val.l.vals + ii;
308    data = state->val.l.vals + ii + 1;
309    if(TYPE_STR == name->type &&
310       (TYPE_STR == data->type || TYPE_INT == data->type)) {
311      if(0 == strcmp("torrent", name->val.s.s))
312        torrent = data->val.s.s;
313      else if(0 == strcmp("dir", name->val.s.s))
314        dir = data->val.s.s;
315      else if(0 == strcmp("paused", name->val.s.s)) {
316        hadpaused = TRUE;
317        paused = (data->val.i ? TRUE : FALSE);
318      }
319    }
320  }
321
322  if(NULL == torrent || NULL == dir)
323    return NULL;
324
325  return tr_torrent_new(backend, torrent, dir,
326                        (hadpaused ? &paused : NULL), err);
327}
328
329void
330tr_torrent_get_state(TrTorrent *tor, benc_val_t *state) {
331  tr_info_t *in = tr_torrentInfo(tor->handle);
332  const char *strs[] = {
333    "torrent", in->torrent, "dir", tr_torrentGetFolder(tor->handle), "paused", 
334  };
335  unsigned int ii;
336  const unsigned int len = 6;
337
338  TR_IS_TORRENT(tor);
339
340  if(tor->disposed)
341    return;
342
343  state->type = TYPE_DICT;
344  state->val.l.vals = g_new0(benc_val_t, len);
345  state->val.l.alloc = state->val.l.count = len;
346
347  g_assert(len > ALEN(strs));
348  for(ii = 0; ii < ALEN(strs); ii++) {
349    state->val.l.vals[ii].type = TYPE_STR;
350    state->val.l.vals[ii].val.s.s = g_strdup(strs[ii]);
351    state->val.l.vals[ii].val.s.i = strlen(strs[ii]);
352  }
353
354  state->val.l.vals[ii].type = TYPE_INT;
355  state->val.l.vals[ii].val.i = tr_torrent_paused(tor);
356  ii++;
357
358  g_assert(len == ii);
359}
360
361static void
362tr_torrent_set_folder(TrTorrent *tor) {
363  char *wd;
364
365  if(NULL != tor->dir)
366    tr_torrentSetFolder(tor->handle, tor->dir);
367  else {
368    wd = g_new(char, MAX_PATH_LENGTH + 1);
369    tr_torrentSetFolder(tor->handle,
370                        (NULL == getcwd(wd, MAX_PATH_LENGTH + 1) ? "." : wd));
371    g_free(wd);
372  }
373}
374
375static gboolean
376tr_torrent_paused(TrTorrent *tor) {
377  tr_stat_t *st = tr_torrentStat(tor->handle);
378
379  return (TR_STATUS_INACTIVE & st->status ? TRUE : FALSE);
380}
Note: See TracBrowser for help on using the repository browser.