transmission 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,63 @@
1
+ /******************************************************************************
2
+ * $Id: platform.h 310 2006-06-09 19:53:35Z joshe $
3
+ *
4
+ * Copyright (c) 2005 Transmission authors and contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ * DEALINGS IN THE SOFTWARE.
23
+ *****************************************************************************/
24
+ #ifndef TR_PLATFORM_H
25
+ #define TR_PLATFORM_H 1
26
+
27
+ #ifdef SYS_BEOS
28
+ #include <kernel/OS.h>
29
+ typedef thread_id tr_thread_t;
30
+ typedef sem_id tr_lock_t;
31
+ #else
32
+ #include <pthread.h>
33
+ typedef pthread_t tr_thread_t;
34
+ typedef pthread_mutex_t tr_lock_t;
35
+ #endif
36
+
37
+ char * tr_getCacheDirectory();
38
+ char * tr_getTorrentsDirectory();
39
+
40
+ void tr_threadCreate ( tr_thread_t *, void (*func)(void *), void * arg );
41
+ void tr_threadJoin ( tr_thread_t * );
42
+ void tr_lockInit ( tr_lock_t * );
43
+ void tr_lockClose ( tr_lock_t * );
44
+
45
+ static inline void tr_lockLock( tr_lock_t * l )
46
+ {
47
+ #ifdef SYS_BEOS
48
+ acquire_sem( *l );
49
+ #else
50
+ pthread_mutex_lock( l );
51
+ #endif
52
+ }
53
+
54
+ static inline void tr_lockUnlock( tr_lock_t * l )
55
+ {
56
+ #ifdef SYS_BEOS
57
+ release_sem( *l );
58
+ #else
59
+ pthread_mutex_unlock( l );
60
+ #endif
61
+ }
62
+
63
+ #endif
@@ -0,0 +1,1135 @@
1
+ #include <ruby.h>
2
+ #include "transmission.h"
3
+
4
+ #define VERSION "0.1"
5
+
6
+ static VALUE cTransmission;
7
+ static VALUE cTorrent;
8
+ static VALUE cFileInfo;
9
+ static VALUE cStat;
10
+
11
+ static VALUE eTransmissionError;
12
+ static VALUE eParseError;
13
+ static VALUE eUnsupportedError;
14
+ static VALUE eDuplicateError;
15
+ static VALUE eTorrentError;
16
+
17
+ typedef struct {
18
+ tr_handle_t *handle;
19
+ VALUE torrents;
20
+ } r_transmission_t;
21
+
22
+ typedef struct {
23
+ VALUE transmission;
24
+ tr_torrent_t *handle;
25
+ int flags;
26
+ } r_torrent_t;
27
+
28
+ #define TORRENT_CLOSED 0x1
29
+ #define CLOSED(torrent) ((torrent)->flags & TORRENT_CLOSED)
30
+ #define SET_CLOSED(torrent) (torrent)->flags |= TORRENT_CLOSED;
31
+
32
+ #define STARTED(torrent) (tr_torrentStat((torrent)->handle)->status & TR_STATUS_ACTIVE)
33
+
34
+ #define CHECK_TORRENT(torrent) if(CLOSED(torrent)) rb_raise(eTorrentError, "Torrrent is already closed.");
35
+
36
+ static void r_torrent_close(r_torrent_t *);
37
+ static VALUE r_torrent_get_folder(VALUE);
38
+ static VALUE r_torrent_set_folder(VALUE, VALUE);
39
+
40
+ static void
41
+ r_transmission_mark(void *data)
42
+ {
43
+ r_transmission_t *transmission;
44
+
45
+ transmission = (r_transmission_t *) data;
46
+ rb_gc_mark(transmission -> torrents);
47
+ }
48
+
49
+ static void
50
+ r_transmission_free(void *data)
51
+ {
52
+ r_transmission_t *transmission;
53
+ r_torrent_t *torrent;
54
+ int i;
55
+ transmission = (r_transmission_t *) data;
56
+ for( i = 0; i < RARRAY(transmission->torrents)->len; i += 1 )
57
+ {
58
+ Data_Get_Struct(RARRAY(transmission->torrents)->ptr[i], r_torrent_t, torrent);
59
+ r_torrent_close(torrent);
60
+ }
61
+ tr_close(transmission->handle);
62
+ xfree(data);
63
+ }
64
+
65
+ static VALUE
66
+ r_transmission_alloc(VALUE klass)
67
+ {
68
+ tr_handle_t *handle;
69
+ r_transmission_t *transmission;
70
+ VALUE obj;
71
+
72
+ handle = tr_init();
73
+ transmission = ALLOC(r_transmission_t);
74
+ transmission->handle = handle;
75
+ transmission->torrents = rb_ary_new();
76
+ obj = Data_Wrap_Struct(klass, r_transmission_mark, r_transmission_free, transmission);
77
+ return obj;
78
+ }
79
+
80
+ /*
81
+ * call-seq:
82
+ * Transmission.pref_directory -> string
83
+ *
84
+ * Returns the full path to a directory which can be used to store preferences.
85
+ *
86
+ */
87
+ static VALUE
88
+ r_transmission_pref_dir(VALUE self)
89
+ {
90
+ return rb_str_new2(tr_getPrefsDirectory());
91
+ }
92
+
93
+ /*
94
+ * call-seq:
95
+ * transmission.bind_port = port -> port
96
+ *
97
+ * Sets a "starting" bind port. Everytime a torrent is started, the library tries to bind
98
+ * this port, then the next one and so on until it is successful.
99
+ *
100
+ */
101
+ static VALUE
102
+ r_transmission_set_bind_port(VALUE self, VALUE port)
103
+ {
104
+ r_transmission_t *transmission;
105
+
106
+ Data_Get_Struct(self, r_transmission_t, transmission);
107
+ tr_setBindPort(transmission->handle, FIX2INT(port));
108
+ return port;
109
+ }
110
+
111
+ static void
112
+ r_torrent_mark(void *data)
113
+ {
114
+ r_torrent_t *torrent;
115
+ torrent = (r_torrent_t *)data;
116
+ rb_gc_mark(torrent->transmission);
117
+ }
118
+
119
+ static void
120
+ r_torrent_free(void *data)
121
+ {
122
+ r_torrent_t *torrent;
123
+ torrent = (r_torrent_t *) data;
124
+ r_torrent_close(torrent);
125
+ xfree(data);
126
+ }
127
+
128
+ /*
129
+ * call-seq:
130
+ * transmission.open(path) -> torrent
131
+ *
132
+ * Opens and parses torrent file at 'path'. If the file exists and is a
133
+ * valid torrent file, returns a Torrent instance and adds it to the list of
134
+ * torrents (but doesn't start it).
135
+ *
136
+ */
137
+ static VALUE
138
+ r_transmission_open(int argc, VALUE *argv, VALUE self)
139
+ {
140
+ VALUE file, save = Qnil, saved = Qnil, excp, result;
141
+ r_transmission_t *transmission;
142
+ tr_torrent_t *torrent_h;
143
+ r_torrent_t *torrent;
144
+ int flags = 0;
145
+ int error = 0;
146
+
147
+ rb_scan_args(argc, argv, "12", &file, &save, &saved);
148
+
149
+ if( RTEST(save) && !RTEST(saved))
150
+ flags = TR_FSAVEPRIVATE;
151
+
152
+ Data_Get_Struct(self, r_transmission_t, transmission);
153
+
154
+ torrent_h = RTEST(saved) ?
155
+ tr_torrentInitSaved(transmission->handle, StringValuePtr(file), flags, &error) :
156
+ tr_torrentInit(transmission->handle, StringValuePtr(file), flags, &error);
157
+ if(torrent_h == NULL) {
158
+ switch(error)
159
+ {
160
+ case TR_EINVALID:
161
+ excp = eParseError;
162
+ break;
163
+ case TR_EUNSUPPORTED:
164
+ excp = eUnsupportedError;
165
+ break;
166
+ case TR_EDUPLICATE:
167
+ excp = eDuplicateError;
168
+ case TR_EOTHER:
169
+ default:
170
+ excp = eTorrentError;
171
+ }
172
+ rb_raise(excp, "Failed to open torrent file");
173
+ }
174
+ torrent = ALLOC(r_torrent_t);
175
+ torrent->transmission = self;
176
+ torrent->handle = torrent_h;
177
+ torrent->flags = 0;
178
+
179
+ result = Data_Wrap_Struct(cTorrent, r_torrent_mark, r_torrent_free, torrent);
180
+ rb_ary_push(transmission->torrents, result);
181
+ if(r_torrent_get_folder(result) == Qnil)
182
+ r_torrent_set_folder(result, rb_str_new2("."));
183
+ return result;
184
+ }
185
+
186
+ /*
187
+ * call-seq:
188
+ * transmission.size -> int
189
+ *
190
+ * Returns the count of open torrents.
191
+ */
192
+ static VALUE
193
+ r_transmission_size(VALUE self)
194
+ {
195
+ r_transmission_t *transmission;
196
+ Data_Get_Struct(self, r_transmission_t, transmission);
197
+ return INT2FIX(tr_torrentCount(transmission->handle));
198
+ }
199
+
200
+ static VALUE
201
+ r_transmission_find(r_transmission_t *transmission, tr_torrent_t *h)
202
+ {
203
+ r_torrent_t *torrent;
204
+ VALUE result;
205
+ int i;
206
+ for( i = 0; i < RARRAY(transmission->torrents)->len; i += 1 )
207
+ {
208
+ result = RARRAY(transmission->torrents)->ptr[i];
209
+ Data_Get_Struct(result, r_torrent_t, torrent);
210
+ if(torrent->handle == h && !CLOSED(torrent)) return result;
211
+ }
212
+ return Qnil;
213
+ }
214
+
215
+
216
+ static void
217
+ r_transmission_each_i(tr_torrent_t *h, void *data)
218
+ {
219
+ r_transmission_t *transmission;
220
+ VALUE torrent;
221
+
222
+ transmission = (r_transmission_t *)data;
223
+ torrent = r_transmission_find(transmission, h);
224
+ if(torrent != Qnil) rb_yield(torrent);
225
+ }
226
+
227
+ /*
228
+ * call-seq:
229
+ * transmission.each {|torrent| ...} -> transmission
230
+ *
231
+ * Iterate through all opened torrents.
232
+ */
233
+ static VALUE
234
+ r_transmission_each(VALUE self)
235
+ {
236
+ r_transmission_t *transmission;
237
+ Data_Get_Struct(self, r_transmission_t, transmission);
238
+
239
+ tr_torrentIterate(transmission->handle, r_transmission_each_i, (void *)transmission);
240
+ return self;
241
+ }
242
+
243
+ /*
244
+ * call-seq:
245
+ * transmission.rates -> [int, int]
246
+ *
247
+ * Returns total download and upload rates.
248
+ */
249
+ static VALUE
250
+ r_transmission_rates(VALUE self)
251
+ {
252
+ r_transmission_t *transmission;
253
+ float down, up;
254
+
255
+ Data_Get_Struct(self, r_transmission_t, transmission);
256
+ tr_torrentRates(transmission->handle, &down, &up);
257
+ return rb_ary_new3(2, rb_float_new(down), rb_float_new(up));
258
+ }
259
+
260
+ /*
261
+ * call-seq:
262
+ * transmission.upload_limit = limit -> limit
263
+ *
264
+ * Sets upload limit in Kb.
265
+ */
266
+ static VALUE
267
+ r_transmission_set_upload_limit(VALUE self, VALUE limit)
268
+ {
269
+ r_transmission_t *transmission;
270
+ Data_Get_Struct(self, r_transmission_t, transmission);
271
+ tr_setUploadLimit(transmission->handle, FIX2INT(limit));
272
+ return limit;
273
+ }
274
+
275
+ /*
276
+ * call-seq:
277
+ * transmission.download_limit = limit -> limit
278
+ *
279
+ * Sets download limit in Kb.
280
+ */
281
+ static VALUE
282
+ r_transmission_set_download_limit(VALUE self, VALUE limit)
283
+ {
284
+ r_transmission_t *transmission;
285
+ Data_Get_Struct(self, r_transmission_t, transmission);
286
+ tr_setDownloadLimit(transmission->handle, FIX2INT(limit));
287
+ return limit;
288
+ }
289
+
290
+ static void
291
+ r_torrent_close(r_torrent_t *torrent)
292
+ {
293
+ r_transmission_t *transmission;
294
+
295
+ if(CLOSED(torrent)) return;
296
+
297
+ Data_Get_Struct(torrent->transmission, r_transmission_t, transmission);
298
+
299
+ if(STARTED(torrent))
300
+ tr_torrentStop(torrent->handle);
301
+
302
+ tr_torrentClose(transmission->handle, torrent->handle);
303
+ SET_CLOSED(torrent);
304
+ }
305
+
306
+ /*
307
+ * call-seq:
308
+ * torrent.remove(saved = false) -> nil
309
+ *
310
+ * Removes torrent from the current session. If 'saved' parameter is true,
311
+ * it also deletes a private torrent copy if there is one.
312
+ */
313
+ static VALUE
314
+ r_torrent_remove(int argc, VALUE *argv, VALUE self)
315
+ {
316
+ r_transmission_t *transmission;
317
+ r_torrent_t *torrent;
318
+ VALUE remove_saved = Qfalse;
319
+
320
+ rb_scan_args(argc, argv, "01", &remove_saved);
321
+
322
+ Data_Get_Struct(self, r_torrent_t, torrent);
323
+ CHECK_TORRENT(torrent);
324
+ Data_Get_Struct(torrent->transmission, r_transmission_t, transmission);
325
+ if(RTEST(remove_saved))
326
+ tr_torrentRemoveSaved(torrent->handle);
327
+ rb_ary_delete(transmission->torrents, self);
328
+ r_torrent_close(torrent);
329
+ return Qnil;
330
+ }
331
+
332
+ static char *
333
+ r_torrent_scrape_error(int code)
334
+ {
335
+ switch(code)
336
+ {
337
+ case TR_SCRAPE_RESOLVE:
338
+ return "Could not resolve address";
339
+ case TR_SCRAPE_CONNECT:
340
+ return "Could not connect to the tracker";
341
+ case TR_SCRAPE_READ:
342
+ return "Failed to read from the tracker";
343
+ default:
344
+ return "Failed to scrape the tracker";
345
+ }
346
+ }
347
+
348
+ /*
349
+ * call-seq:
350
+ * torrent.scrape -> [int, int]
351
+ *
352
+ * Scrapes the tracker and returns a number of seeders and leechers.
353
+ */
354
+ static VALUE
355
+ r_torrent_scrape(VALUE self)
356
+ {
357
+ r_torrent_t *torrent;
358
+ int seeders, leechers;
359
+ int ret_code;
360
+
361
+ Data_Get_Struct(self, r_torrent_t, torrent);
362
+ CHECK_TORRENT(torrent);
363
+
364
+ if((ret_code = tr_torrentScrape(torrent->handle, &seeders, &leechers)) != 0)
365
+ {
366
+ rb_raise(eTorrentError, r_torrent_scrape_error(ret_code));
367
+ }
368
+ return rb_ary_new3(2, INT2FIX(seeders), INT2FIX(leechers));
369
+ }
370
+
371
+ static tr_info_t *
372
+ r_torrent_info(VALUE self)
373
+ {
374
+ r_torrent_t *torrent;
375
+
376
+ Data_Get_Struct(self, r_torrent_t, torrent);
377
+ CHECK_TORRENT(torrent);
378
+ return tr_torrentInfo(torrent->handle);
379
+ }
380
+
381
+ /*
382
+ * call-seq:
383
+ * torrent.file_name -> string
384
+ *
385
+ * Returns file name of the torrent file.
386
+ */
387
+ static VALUE
388
+ r_torrent_file_name(VALUE self)
389
+ {
390
+ return rb_str_new2(r_torrent_info(self)->torrent);
391
+ }
392
+
393
+ /*
394
+ * call-seq:
395
+ * torrent.name -> string
396
+ *
397
+ * Returns the description of the torrent file.
398
+ */
399
+ static VALUE
400
+ r_torrent_name(VALUE self)
401
+ {
402
+ return rb_str_new2(r_torrent_info(self)->name);
403
+ }
404
+
405
+ /*
406
+ * call-seq:
407
+ * torrent.hash_string -> string
408
+ *
409
+ * Returns the hash string of the torrent file.
410
+ */
411
+ static VALUE
412
+ r_torrent_hash_string(VALUE self)
413
+ {
414
+ return rb_str_new2(r_torrent_info(self)->hashString);
415
+ }
416
+
417
+ /*
418
+ * call-seq:
419
+ * torrent.tracker_address -> string
420
+ *
421
+ * Returns the tracker address.
422
+ */
423
+ static VALUE
424
+ r_torrent_tracker_address(VALUE self)
425
+ {
426
+ return rb_str_new2(r_torrent_info(self)->trackerAddress);
427
+ }
428
+
429
+ /*
430
+ * call-seq:
431
+ * torrent.tracker_port -> int
432
+ *
433
+ * Returns the tracker port.
434
+ */
435
+ static VALUE
436
+ r_torrent_tracker_port(VALUE self)
437
+ {
438
+ return INT2FIX(r_torrent_info(self)->trackerPort);
439
+ }
440
+
441
+ /*
442
+ * call-seq:
443
+ * torrent.tracker_announce -> string
444
+ *
445
+ * Returns the tracker announce address.
446
+ */
447
+ static VALUE
448
+ r_torrent_tracker_announce(VALUE self)
449
+ {
450
+ return rb_str_new2(r_torrent_info(self)->trackerAnnounce);
451
+ }
452
+
453
+ /*
454
+ * call-seq:
455
+ * torrent.piece_size -> int
456
+ *
457
+ * Returns piece size in bytes.
458
+ */
459
+ static VALUE
460
+ r_torrent_piece_size(VALUE self)
461
+ {
462
+ return INT2FIX(r_torrent_info(self)->pieceSize);
463
+ }
464
+
465
+ /*
466
+ * call-seq:
467
+ * torrent.piece_count -> string
468
+ *
469
+ * Returns piece count.
470
+ */
471
+ static VALUE
472
+ r_torrent_piece_count(VALUE self)
473
+ {
474
+ return INT2FIX(r_torrent_info(self)->pieceCount);
475
+ }
476
+
477
+ /*
478
+ * call-seq:
479
+ * torrent.total_size -> string
480
+ *
481
+ * Returns the total size of all pieces in bytes.
482
+ */
483
+ static VALUE
484
+ r_torrent_total_size(VALUE self)
485
+ {
486
+ return ULONG2NUM(r_torrent_info(self)->totalSize);
487
+ }
488
+
489
+ /*
490
+ * call-seq:
491
+ * torrent.pieces -> array
492
+ *
493
+ * Returns the array of pieces.
494
+ */
495
+ static VALUE
496
+ r_torrent_pieces(VALUE self)
497
+ {
498
+ VALUE *pieces;
499
+ tr_info_t *info;
500
+ VALUE result;
501
+ int i;
502
+
503
+ info = r_torrent_info(self);
504
+
505
+ pieces = ALLOC_N(VALUE, info->pieceCount);
506
+ for( i = 0; i < info->pieceCount; i += 1 )
507
+ {
508
+ pieces[i] = INT2FIX(info->pieces[i]);
509
+ }
510
+
511
+ result = rb_ary_new4(info->pieceCount, pieces);
512
+ xfree(pieces);
513
+ return result;
514
+ }
515
+
516
+ /*
517
+ * call-seq:
518
+ * torrent.file_count -> int
519
+ *
520
+ * Returns the total number of files for this torrent.
521
+ */
522
+ static VALUE
523
+ r_torrent_file_count(VALUE self)
524
+ {
525
+ return INT2FIX(r_torrent_info(self)->fileCount);
526
+ }
527
+
528
+ /*
529
+ * call-seq:
530
+ * torrent.files -> array
531
+ *
532
+ * Returns the array of FileInfo.
533
+ */
534
+ static VALUE
535
+ r_torrent_files(VALUE self)
536
+ {
537
+ VALUE *files;
538
+ VALUE result;
539
+ tr_info_t *info;
540
+ tr_file_t *f;
541
+ int i;
542
+
543
+ info = r_torrent_info(self);
544
+
545
+ files = ALLOC_N(VALUE, info->fileCount);
546
+ for( i = 0; i < info->fileCount; i += 1 )
547
+ {
548
+ f = ALLOC(tr_file_t);
549
+ MEMCPY(f, &info->files[i], tr_file_t, 1);
550
+ files[i] = Data_Wrap_Struct(cFileInfo, NULL, xfree, f);
551
+ }
552
+ result = rb_ary_new4(info->fileCount, files);
553
+ xfree(files);
554
+ return result;
555
+ }
556
+
557
+ /*
558
+ * call-seq:
559
+ * torrent.stat -> Stat
560
+ *
561
+ * Returns the stat of this torrent.
562
+ */
563
+ static VALUE
564
+ r_torrent_stat(VALUE self)
565
+ {
566
+ r_torrent_t *torrent;
567
+ tr_stat_t *stat;
568
+
569
+ Data_Get_Struct(self, r_torrent_t, torrent);
570
+ CHECK_TORRENT(torrent);
571
+
572
+ stat = ALLOC(tr_stat_t);
573
+ MEMCPY(stat, tr_torrentStat(torrent->handle), tr_stat_t, 1);
574
+ return Data_Wrap_Struct(cStat, NULL, xfree, stat);
575
+ }
576
+
577
+ /*
578
+ * call-seq:
579
+ * torrent.folder -> string
580
+ *
581
+ * Returns the path where torrent files will be stored.
582
+ */
583
+ static VALUE
584
+ r_torrent_get_folder(VALUE self)
585
+ {
586
+ r_torrent_t *torrent;
587
+ char *folder;
588
+
589
+ Data_Get_Struct(self, r_torrent_t, torrent);
590
+ CHECK_TORRENT(torrent);
591
+
592
+ folder = tr_torrentGetFolder(torrent->handle);
593
+ if(folder)
594
+ return rb_str_new2(folder);
595
+ return Qnil;
596
+ }
597
+
598
+ /*
599
+ * call-seq:
600
+ * torrent.folder = folder -> folder
601
+ *
602
+ * Changes the directory wher torrent file will be stored.
603
+ */
604
+ static VALUE
605
+ r_torrent_set_folder(VALUE self, VALUE file)
606
+ {
607
+ r_torrent_t *torrent;
608
+
609
+ Data_Get_Struct(self, r_torrent_t, torrent);
610
+ CHECK_TORRENT(torrent);
611
+
612
+ tr_torrentSetFolder(torrent->handle, StringValuePtr(file));
613
+ return file;
614
+ }
615
+
616
+ /*
617
+ * call-seq:
618
+ * torrent.start -> nil
619
+ *
620
+ * Starts the torrent downloading. The download is launched in a seperate thread,
621
+ * therefore torrent.start returns immediately.
622
+ */
623
+ static VALUE
624
+ r_torrent_start(VALUE self)
625
+ {
626
+ r_torrent_t *torrent;
627
+
628
+ Data_Get_Struct(self, r_torrent_t, torrent);
629
+ CHECK_TORRENT(torrent);
630
+
631
+ if(!STARTED(torrent))
632
+ {
633
+ tr_torrentStart(torrent->handle);
634
+ }
635
+
636
+ return Qnil;
637
+ }
638
+
639
+ /*
640
+ * call-seq:
641
+ * torrent.stop -> nil
642
+ *
643
+ * Stops the torrent downloading.
644
+ */
645
+ static VALUE
646
+ r_torrent_stop(VALUE self)
647
+ {
648
+ r_torrent_t *torrent;
649
+
650
+ Data_Get_Struct(self, r_torrent_t, torrent);
651
+ CHECK_TORRENT(torrent);
652
+
653
+ if(STARTED(torrent))
654
+ {
655
+ tr_torrentStop(torrent->handle);
656
+ }
657
+
658
+ return Qnil;
659
+ }
660
+
661
+ /*
662
+ * call-seq:
663
+ * torrent.active? -> bool
664
+ *
665
+ * Returns true if torrent is in active state.
666
+ */
667
+ static VALUE
668
+ r_torrent_active(VALUE self)
669
+ {
670
+ r_torrent_t *torrent;
671
+
672
+ Data_Get_Struct(self, r_torrent_t, torrent);
673
+ CHECK_TORRENT(torrent);
674
+
675
+ return STARTED(torrent) ? Qtrue : Qfalse;
676
+ }
677
+
678
+ /*
679
+ * call-seq:
680
+ * torrent.closed? -> bool
681
+ *
682
+ * Returns true if torrent is closed and can't be used anymore.
683
+ */
684
+ static VALUE
685
+ r_torrent_closed(VALUE self)
686
+ {
687
+ r_torrent_t *torrent;
688
+
689
+ Data_Get_Struct(self, r_torrent_t, torrent);
690
+
691
+ return CLOSED(torrent) ? Qtrue : Qfalse;
692
+ }
693
+
694
+ /*
695
+ * call-seq:
696
+ * torrent.availability(size) -> array of integers
697
+ *
698
+ * Use this to draw an advanced progress bar which is 'size' pixels
699
+ * wide. Returns an array of integer where each integer is set
700
+ * to either -1 if we have the piece, otherwise it is set to the number
701
+ * of connected peers who have the piece.
702
+ */
703
+ static VALUE
704
+ r_torrent_availability(VALUE self, VALUE size)
705
+ {
706
+ r_torrent_t *torrent;
707
+ int8_t *data;
708
+ VALUE *result_data;
709
+ VALUE result;
710
+ int length, i;
711
+
712
+ Data_Get_Struct(self, r_torrent_t, torrent);
713
+ CHECK_TORRENT(torrent);
714
+
715
+ length = FIX2INT(size);
716
+ data = ALLOC_N(int8_t, length);
717
+ result_data = ALLOC_N(VALUE, length);
718
+ tr_torrentAvailability(torrent->handle, data, length);
719
+ for( i = 0; i < length; i += 1 )
720
+ {
721
+ result_data[i] = INT2FIX(data[i]);
722
+ }
723
+ result = rb_ary_new4(length, result_data);
724
+ xfree(data);
725
+ xfree(result_data);
726
+ return result;
727
+ }
728
+
729
+ /*
730
+ * call-seq:
731
+ * torrent.just_finished? -> bool
732
+ *
733
+ * The first call after a torrent is completed returns true. Returns false
734
+ * in other cases.
735
+ */
736
+ static VALUE
737
+ r_torrent_just_finished(VALUE self)
738
+ {
739
+ r_torrent_t *torrent;
740
+
741
+ Data_Get_Struct(self, r_torrent_t, torrent);
742
+
743
+ return tr_getFinished(torrent->handle) ? Qtrue : Qfalse;
744
+ }
745
+
746
+ /*
747
+ * call-seq:
748
+ * file_info.name -> string
749
+ *
750
+ * Returns the name of the file.
751
+ */
752
+ static VALUE
753
+ r_file_info_name(VALUE self)
754
+ {
755
+ tr_file_t *file;
756
+ Data_Get_Struct(self, tr_file_t, file);
757
+ return rb_str_new2(file->name);
758
+ }
759
+
760
+ /*
761
+ * call-seq:
762
+ * file_info.size -> int
763
+ *
764
+ * Returns the size of the file.
765
+ */
766
+ static VALUE
767
+ r_file_info_size(VALUE self)
768
+ {
769
+ tr_file_t *file;
770
+ Data_Get_Struct(self, tr_file_t, file);
771
+ return INT2FIX(file->length);
772
+ }
773
+
774
+ /*
775
+ * call-seq:
776
+ * stat.status -> int
777
+ *
778
+ * Returns the status of the torrent.
779
+ */
780
+ static VALUE
781
+ r_stat_status(VALUE self)
782
+ {
783
+ tr_stat_t *stat;
784
+ Data_Get_Struct(self, tr_stat_t, stat);
785
+ return INT2FIX(stat->status);
786
+ }
787
+
788
+ /*
789
+ * call-seq:
790
+ * stat.error -> int
791
+ *
792
+ * Returns the error code of the torrent, 0 otherwise.
793
+ */
794
+ static VALUE
795
+ r_stat_error(VALUE self)
796
+ {
797
+ tr_stat_t *stat;
798
+ Data_Get_Struct(self, tr_stat_t, stat);
799
+ return INT2FIX(stat->error);
800
+ }
801
+
802
+ /*
803
+ * call-seq:
804
+ * stat.tracker_error -> string
805
+ *
806
+ * Returns the tracker error or empty string.
807
+ */
808
+ static VALUE
809
+ r_stat_tracker_error(VALUE self)
810
+ {
811
+ tr_stat_t *stat;
812
+ Data_Get_Struct(self, tr_stat_t, stat);
813
+ return rb_str_new2(stat->trackerError);
814
+ }
815
+
816
+ /*
817
+ * call-seq:
818
+ * stat.progress -> float
819
+ *
820
+ * Returns the progress of the torrent from 0.0 to 1.0.
821
+ */
822
+ static VALUE
823
+ r_stat_progress(VALUE self)
824
+ {
825
+ tr_stat_t *stat;
826
+ Data_Get_Struct(self, tr_stat_t, stat);
827
+ return rb_float_new(stat->progress);
828
+ }
829
+
830
+ /*
831
+ * call-seq:
832
+ * stat.down_rate -> float
833
+ *
834
+ * Returns downloading rate.
835
+ */
836
+ static VALUE
837
+ r_stat_down_rate(VALUE self)
838
+ {
839
+ tr_stat_t *stat;
840
+ Data_Get_Struct(self, tr_stat_t, stat);
841
+ return rb_float_new(stat->rateDownload);
842
+ }
843
+
844
+ /*
845
+ * call-seq:
846
+ * stat.up_rate -> float
847
+ *
848
+ * Returns uploading rate.
849
+ */
850
+ static VALUE
851
+ r_stat_up_rate(VALUE self)
852
+ {
853
+ tr_stat_t *stat;
854
+ Data_Get_Struct(self, tr_stat_t, stat);
855
+ return rb_float_new(stat->rateUpload);
856
+ }
857
+
858
+ /*
859
+ * call-seq:
860
+ * stat.rates -> [float, float]
861
+ *
862
+ * Returns an array of downloading and uploading rates.
863
+ */
864
+ static VALUE
865
+ r_stat_rates(VALUE self)
866
+ {
867
+ tr_stat_t *stat;
868
+ Data_Get_Struct(self, tr_stat_t, stat);
869
+ return rb_ary_new3(2, rb_float_new(stat->rateDownload), rb_float_new(stat->rateUpload));
870
+ }
871
+
872
+ /*
873
+ * call-seq:
874
+ * stat.eta -> int
875
+ *
876
+ * Returns eta until the torrent finishes downloading.
877
+ */
878
+ static VALUE
879
+ r_stat_eta(VALUE self)
880
+ {
881
+ tr_stat_t *stat;
882
+ Data_Get_Struct(self, tr_stat_t, stat);
883
+ return INT2FIX(stat->eta);
884
+ }
885
+
886
+ /*
887
+ * call-seq:
888
+ * stat.peers_total -> int
889
+ *
890
+ * Returns the total number of peers.
891
+ */
892
+ static VALUE
893
+ r_stat_peers_total(VALUE self)
894
+ {
895
+ tr_stat_t *stat;
896
+ Data_Get_Struct(self, tr_stat_t, stat);
897
+ return INT2FIX(stat->peersTotal);
898
+ }
899
+
900
+ /*
901
+ * call-seq:
902
+ * stat.up_peers -> int
903
+ *
904
+ * Returns a number of uploading peers.
905
+ */
906
+ static VALUE
907
+ r_stat_up_peers(VALUE self)
908
+ {
909
+ tr_stat_t *stat;
910
+ Data_Get_Struct(self, tr_stat_t, stat);
911
+ return INT2FIX(stat->peersUploading);
912
+ }
913
+
914
+ /*
915
+ * call-seq:
916
+ * stat.down_peers -> int
917
+ *
918
+ * Returns a number of downloaded peers.
919
+ */
920
+ static VALUE
921
+ r_stat_down_peers(VALUE self)
922
+ {
923
+ tr_stat_t *stat;
924
+ Data_Get_Struct(self, tr_stat_t, stat);
925
+ return INT2FIX(stat->peersDownloading);
926
+ }
927
+
928
+ /*
929
+ * call-seq:
930
+ * stat.peers -> [int, int]
931
+ *
932
+ * Returns an array of numbers of downloading and uploading peers.
933
+ */
934
+ static VALUE
935
+ r_stat_peers(VALUE self)
936
+ {
937
+ tr_stat_t *stat;
938
+ Data_Get_Struct(self, tr_stat_t, stat);
939
+ return rb_ary_new3(2, INT2FIX(stat->peersDownloading), INT2FIX(stat->peersUploading));
940
+ }
941
+
942
+ /*
943
+ * call-seq:
944
+ * stat.seeders -> int
945
+ *
946
+ * Returns a number of seeders.
947
+ */
948
+ static VALUE
949
+ r_stat_seeders(VALUE self)
950
+ {
951
+ tr_stat_t *stat;
952
+ Data_Get_Struct(self, tr_stat_t, stat);
953
+ return INT2FIX(stat->seeders);
954
+ }
955
+
956
+ /*
957
+ * call-seq:
958
+ * stat.leechers -> int
959
+ *
960
+ * Returns a number of leechers.
961
+ */
962
+ static VALUE
963
+ r_stat_leechers(VALUE self)
964
+ {
965
+ tr_stat_t *stat;
966
+ Data_Get_Struct(self, tr_stat_t, stat);
967
+ return INT2FIX(stat->leechers);
968
+ }
969
+
970
+ /*
971
+ * call-seq:
972
+ * stat.downloaded -> int
973
+ *
974
+ * Returns the total number of downloaded bytes.
975
+ */
976
+ static VALUE
977
+ r_stat_downloaded(VALUE self)
978
+ {
979
+ tr_stat_t *stat;
980
+ Data_Get_Struct(self, tr_stat_t, stat);
981
+ return ULONG2NUM(stat->downloaded);
982
+ }
983
+
984
+ /*
985
+ * call-seq:
986
+ * stat.uploaded -> int
987
+ *
988
+ * Returns the total number of uploaded bytes.
989
+ */
990
+ static VALUE
991
+ r_stat_uploaded(VALUE self)
992
+ {
993
+ tr_stat_t *stat;
994
+ Data_Get_Struct(self, tr_stat_t, stat);
995
+ return ULONG2NUM(stat->uploaded);
996
+ }
997
+
998
+ /*
999
+ * Document-class: Transmission::Torrent
1000
+ *
1001
+ * == Summary
1002
+ *
1003
+ * The Torrent class represent a torrent instance. You can use this instance
1004
+ * start and stop downloading process and keep track of its progress.
1005
+ */
1006
+ static void
1007
+ Init_torrent()
1008
+ {
1009
+ cTorrent = rb_define_class_under(cTransmission, "Torrent", rb_cObject);
1010
+ rb_define_method(cTorrent, "remove", r_torrent_remove, -1);
1011
+ rb_define_method(cTorrent, "scrape", r_torrent_scrape, 0);
1012
+ rb_define_method(cTorrent, "file_name", r_torrent_file_name, 0);
1013
+ rb_define_method(cTorrent, "name", r_torrent_name, 0);
1014
+ rb_define_method(cTorrent, "hash_string", r_torrent_hash_string, 0);
1015
+ rb_define_method(cTorrent, "tracker_addr", r_torrent_tracker_address, 0);
1016
+ rb_define_method(cTorrent, "tracker_address", r_torrent_tracker_address, 0);
1017
+ rb_define_method(cTorrent, "tracker_port", r_torrent_tracker_port, 0);
1018
+ rb_define_method(cTorrent, "tracker_announce", r_torrent_tracker_announce, 0);
1019
+ rb_define_method(cTorrent, "tracker_ann", r_torrent_tracker_announce, 0);
1020
+ rb_define_method(cTorrent, "piece_size", r_torrent_piece_size, 0);
1021
+ rb_define_method(cTorrent, "piece_count", r_torrent_piece_count, 0);
1022
+ rb_define_method(cTorrent, "total_size", r_torrent_total_size, 0);
1023
+ rb_define_method(cTorrent, "size", r_torrent_total_size, 0);
1024
+ rb_define_method(cTorrent, "pieces", r_torrent_pieces, 0);
1025
+ rb_define_method(cTorrent, "file_count", r_torrent_file_count, 0);
1026
+ rb_define_method(cTorrent, "files", r_torrent_files, 0);
1027
+ rb_define_method(cTorrent, "stat", r_torrent_stat, 0);
1028
+ rb_define_method(cTorrent, "download_to", r_torrent_set_folder, 1);
1029
+ rb_define_method(cTorrent, "folder", r_torrent_get_folder, 0);
1030
+ rb_define_method(cTorrent, "folder=", r_torrent_set_folder, 1);
1031
+ rb_define_method(cTorrent, "start", r_torrent_start, 0);
1032
+ rb_define_method(cTorrent, "stop", r_torrent_stop, 0);
1033
+ rb_define_method(cTorrent, "active?", r_torrent_active, 0);
1034
+ rb_define_method(cTorrent, "closed?", r_torrent_closed, 0);
1035
+ rb_define_method(cTorrent, "availability", r_torrent_availability, 1);
1036
+ rb_define_method(cTorrent, "just_finished?", r_torrent_just_finished, 0);
1037
+ }
1038
+
1039
+ /*
1040
+ * Document-class: Transmission::Torrent::FileInfo
1041
+ *
1042
+ * == Summary
1043
+ *
1044
+ * The FileInfo class containts the information about a file which is part of this torrent.
1045
+ */
1046
+ static void
1047
+ Init_fileinfo()
1048
+ {
1049
+ cFileInfo = rb_define_class_under(cTorrent, "FileInfo", rb_cObject);
1050
+ rb_define_method(cFileInfo, "name", r_file_info_name, 0);
1051
+ rb_define_method(cFileInfo, "file_name", r_file_info_name, 0);
1052
+ rb_define_method(cFileInfo, "size", r_file_info_size, 0);
1053
+ rb_define_method(cFileInfo, "length", r_file_info_size, 0);
1054
+ }
1055
+
1056
+ /*
1057
+ * Document-class: Transmission::Torrent::Stat
1058
+ *
1059
+ * == Summary
1060
+ *
1061
+ * The Stat class containts the information about the torrent.
1062
+ */
1063
+ static void
1064
+ Init_stat()
1065
+ {
1066
+ cStat = rb_define_class_under(cTorrent, "Stat", rb_cObject);
1067
+ rb_define_method(cStat, "status", r_stat_status, 0);
1068
+ rb_define_method(cStat, "error", r_stat_error, 0);
1069
+ rb_define_method(cStat, "tracker_error", r_stat_tracker_error, 0);
1070
+ rb_define_method(cStat, "progress", r_stat_progress, 0);
1071
+ rb_define_method(cStat, "rates", r_stat_rates, 0);
1072
+ rb_define_method(cStat, "down_rate", r_stat_down_rate, 0);
1073
+ rb_define_method(cStat, "up_rate", r_stat_up_rate, 0);
1074
+ rb_define_method(cStat, "eta", r_stat_eta, 0);
1075
+ rb_define_method(cStat, "peers_total", r_stat_peers_total, 0);
1076
+ rb_define_method(cStat, "peers", r_stat_peers, 0);
1077
+ rb_define_method(cStat, "up_peers", r_stat_up_peers, 0);
1078
+ rb_define_method(cStat, "down_peers", r_stat_down_peers, 0);
1079
+ rb_define_method(cStat, "seeders", r_stat_seeders, 0);
1080
+ rb_define_method(cStat, "leechers", r_stat_leechers, 0);
1081
+ rb_define_method(cStat, "downloaded", r_stat_downloaded, 0);
1082
+ rb_define_method(cStat, "uploaded", r_stat_uploaded, 0);
1083
+
1084
+ rb_define_const(cStat, "STATUS_CHECK", INT2FIX(TR_STATUS_CHECK));
1085
+ rb_define_const(cStat, "STATUS_DOWNLOAD", INT2FIX(TR_STATUS_DOWNLOAD));
1086
+ rb_define_const(cStat, "STATUS_SEED", INT2FIX(TR_STATUS_SEED));
1087
+ rb_define_const(cStat, "STATUS_STOPPING", INT2FIX(TR_STATUS_STOPPING));
1088
+ rb_define_const(cStat, "STATUS_STOPPED", INT2FIX(TR_STATUS_STOPPED));
1089
+ rb_define_const(cStat, "STATUS_PAUSE", INT2FIX(TR_STATUS_PAUSE));
1090
+ rb_define_const(cStat, "STATUS_ACTIVE", INT2FIX(TR_STATUS_ACTIVE));
1091
+ rb_define_const(cStat, "STATUS_INACTIVE", INT2FIX(TR_STATUS_INACTIVE));
1092
+
1093
+ rb_define_const(cStat, "ERR_TRACKER", INT2FIX(TR_ETRACKER));
1094
+ rb_define_const(cStat, "ERR_INOUT", INT2FIX(TR_EINOUT));
1095
+ }
1096
+
1097
+ /*
1098
+ * Document-class: Transmission
1099
+ *
1100
+ * == Summary
1101
+ *
1102
+ * The Transmission class represent a bittorrent session. You can use an instance of
1103
+ * this class to open a torrent and start its downloading process.
1104
+ */
1105
+ void
1106
+ Init_transmission()
1107
+ {
1108
+ cTransmission = rb_define_class("Transmission", rb_cObject);
1109
+
1110
+ rb_define_const(cTransmission, "VERSION", rb_obj_freeze(rb_str_new2(VERSION)));
1111
+
1112
+ rb_define_module_function(cTransmission, "pref_directory", r_transmission_pref_dir, 0);
1113
+
1114
+ rb_define_alloc_func(cTransmission, r_transmission_alloc);
1115
+ rb_define_method(cTransmission, "bind_port=", r_transmission_set_bind_port, 1);
1116
+ rb_define_method(cTransmission, "open", r_transmission_open, -1);
1117
+ rb_define_method(cTransmission, "size", r_transmission_size, 0);
1118
+ rb_define_method(cTransmission, "length", r_transmission_size, 0);
1119
+ rb_define_method(cTransmission, "each", r_transmission_each, 0);
1120
+ rb_define_method(cTransmission, "rates", r_transmission_rates, 0);
1121
+ rb_define_method(cTransmission, "upload_limit=", r_transmission_set_upload_limit, 1);
1122
+ rb_define_method(cTransmission, "download_limit=", r_transmission_set_download_limit, 1);
1123
+
1124
+ rb_include_module(cTransmission, rb_mEnumerable);
1125
+
1126
+ eTransmissionError = rb_define_class_under(cTransmission, "TransmissionError", rb_eStandardError);
1127
+ eParseError = rb_define_class_under(cTransmission, "ParseError", eTransmissionError);
1128
+ eUnsupportedError = rb_define_class_under(cTransmission, "UnsupportedError", eTransmissionError);
1129
+ eDuplicateError = rb_define_class_under(cTransmission, "DuplicateError", eTransmissionError);
1130
+ eTorrentError = rb_define_class_under(cTransmission, "TorrentError", eTransmissionError);
1131
+
1132
+ Init_torrent();
1133
+ Init_fileinfo();
1134
+ Init_stat();
1135
+ }