source: trunk/macosx/Torrent.m @ 292

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

Revert the last commit, it wasn't supposed to go on the trunk.

  • Property svn:keywords set to Date Rev Author Id
File size: 13.4 KB
Line 
1/******************************************************************************
2 * $Id: Torrent.m 292 2006-06-08 04:44:45Z joshe $
3 *
4 * Copyright (c) 2006 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
25#import "Torrent.h"
26#import "StringAdditions.h"
27#import "Utils.h"
28
29@interface Torrent (Private)
30
31- (void) trashPath: (NSString *) path;
32- (id) initWithPath: (NSString *) path lib: (tr_handle_t *) lib date: (NSDate *) date
33        stopRatioSetting: (NSNumber *) stopRatioSetting ratioLimit: (NSNumber *) ratioLimit;
34
35@end
36
37
38@implementation Torrent
39
40- (id) initWithPath: (NSString *) path lib: (tr_handle_t *) lib
41{
42    return [self initWithPath: path lib: lib
43            date: nil stopRatioSetting: nil
44            ratioLimit: nil];
45}
46
47- (id) initWithHistory: (NSDictionary *) history lib: (tr_handle_t *) lib
48{
49    self = [self initWithPath: [history objectForKey: @"TorrentPath"]
50            lib: lib date: [history objectForKey: @"Date"]
51            stopRatioSetting: [history objectForKey: @"StopRatioSetting"]
52            ratioLimit: [history objectForKey: @"RatioLimit"]];
53           
54    if (self)
55    {
56        NSString * downloadFolder;
57        if (!(downloadFolder = [history objectForKey: @"DownloadFolder"]))
58            downloadFolder = [[fDefaults stringForKey: @"DownloadFolder"]
59                                stringByExpandingTildeInPath];
60        [self setDownloadFolder: downloadFolder];
61
62        NSString * paused;
63        if (!(paused = [history objectForKey: @"Paused"]) || [paused isEqualToString: @"NO"])
64            [self start];
65    }
66    return self;
67}
68
69- (NSDictionary *) history
70{
71    return [NSDictionary dictionaryWithObjectsAndKeys:
72            [self torrentLocation], @"TorrentPath",
73            [self downloadFolder], @"DownloadFolder",
74            [self isActive] ? @"NO" : @"YES", @"Paused",
75            [self date], @"Date",
76            [NSNumber numberWithInt: fStopRatioSetting], @"StopRatioSetting",
77            [NSNumber numberWithFloat: fRatioLimit], @"RatioLimit", nil];
78}
79
80- (void) dealloc
81{
82    if( fHandle )
83    {
84        tr_torrentClose( fLib, fHandle );
85       
86        [fDate release];
87        [fIcon release];
88        [fIconFlipped release];
89        [fProgressString release];
90        [fStatusString release];
91    }
92    [super dealloc];
93}
94
95- (void) setDownloadFolder: (NSString *) path
96{
97    tr_torrentSetFolder( fHandle, [path UTF8String] );
98}
99
100- (NSString *) downloadFolder
101{
102    return [NSString stringWithUTF8String: tr_torrentGetFolder( fHandle )];
103}
104
105- (void) getAvailability: (int8_t *) tab size: (int) size
106{
107    tr_torrentAvailability( fHandle, tab, size );
108}
109
110- (void) update
111{
112    fStat = tr_torrentStat( fHandle );
113   
114    if ([self isSeeding])
115        if ((fStopRatioSetting == RATIO_CHECK && [self ratio] >= fRatioLimit)
116            || (fStopRatioSetting == RATIO_GLOBAL && [fDefaults boolForKey: @"RatioCheck"]
117                && [self ratio] >= [fDefaults floatForKey: @"RatioLimit"]))
118        {
119            [self stop];
120            [self setStopRatioSetting: RATIO_NO_CHECK];
121           
122            fStat = tr_torrentStat( fHandle );
123           
124            [[NSNotificationCenter defaultCenter] postNotificationName:
125                @"TorrentRatioChanged" object: self];
126        }
127   
128    [fProgressString setString: @""];
129    if ([self progress] < 1.0)
130        [fProgressString appendFormat: @"%@ of %@ completed (%.2f%%)", [NSString stringForFileSize:
131                [self downloaded]], [NSString stringForFileSize: [self size]], 100 * [self progress]];
132    else
133        [fProgressString appendFormat: @"%@, uploaded %@ (ratio: %@)", [NSString stringForFileSize:
134                [self size]], [NSString stringForFileSize: [self uploaded]],
135                [NSString stringForRatioWithDownload: [self downloaded] upload: [self uploaded]]];
136
137    switch( fStat->status )
138    {
139        case TR_STATUS_PAUSE:
140            [fStatusString setString: @"Paused"];
141            break;
142
143        case TR_STATUS_CHECK:
144            [fStatusString setString: [@"Checking existing files" stringByAppendingString: NS_ELLIPSIS]];
145            break;
146
147        case TR_STATUS_DOWNLOAD:
148            [fStatusString setString: @""];
149            [fStatusString appendFormat:
150                @"Downloading from %d of %d peer%s",
151                [self peersUploading], [self totalPeers],
152                ([self totalPeers] == 1) ? "" : "s"];
153           
154            int eta = fStat->eta;
155            if (eta < 0)
156                [fProgressString appendString: @" - remaining time unknown"];
157            else
158            {
159                if (eta < 60)
160                    [fProgressString appendFormat: @" - %d sec remaining", eta];
161                else if (eta < 3600)
162                    [fProgressString appendFormat: @" - %d min %02d sec remaining",
163                                                    eta / 60, eta % 60];
164                else
165                    [fProgressString appendFormat: @" - %d hr %02d min remaining",
166                                                    eta / 3600, (eta / 60) % 60];
167            }
168            break;
169
170        case TR_STATUS_SEED:
171            [fStatusString setString: @""];
172            [fStatusString appendFormat:
173                @"Seeding to %d of %d peer%s",
174                [self peersDownloading], [self totalPeers],
175                ([self totalPeers] == 1) ? "" : "s"];
176            break;
177
178        case TR_STATUS_STOPPING:
179            [fStatusString setString: [@"Stopping" stringByAppendingString: NS_ELLIPSIS]];
180            break;
181    }
182   
183    if( fStat->error & TR_ETRACKER )
184    {
185        [fStatusString setString: [@"Error: " stringByAppendingString:
186            [NSString stringWithUTF8String: fStat->trackerError]]];
187    }
188
189    if ([self isActive])
190    {
191        [fStatusString appendString: @" - "];
192        if ([self progress] < 1.0)
193            [fStatusString appendFormat: @"DL: %@, ", [NSString stringForSpeed: [self downloadRate]]];
194        [fStatusString appendString: [@"UL: " stringByAppendingString:
195                                                [NSString stringForSpeed: [self uploadRate]]]];
196    }
197}
198
199- (void) start
200{
201    if( fStat->status & TR_STATUS_INACTIVE )
202    {
203        tr_torrentStart( fHandle );
204    }
205}
206
207- (void) stop
208{
209    if( fStat->status & TR_STATUS_ACTIVE )
210    {
211        tr_torrentStop( fHandle );
212    }
213}
214
215- (void) sleep
216{
217    if( ( fResumeOnWake = ( fStat->status & TR_STATUS_ACTIVE ) ) )
218    {
219        [self stop];
220    }
221}
222
223- (void) wakeUp
224{
225    if( fResumeOnWake )
226    {
227        [self start];
228    }
229}
230
231- (float) ratio
232{
233    float downloaded = [self downloaded];
234    return downloaded > 0 ? (float)[self uploaded] / downloaded : -1;
235}
236
237- (int) stopRatioSetting
238{
239        return fStopRatioSetting;
240}
241
242- (void) setStopRatioSetting: (int) setting
243{
244    fStopRatioSetting = setting;
245}
246
247- (float) ratioLimit
248{
249    return fRatioLimit;
250}
251
252- (void) setRatioLimit: (float) limit
253{
254    if (limit >= 0)
255        fRatioLimit = limit;
256}
257
258- (void) reveal
259{
260    [[NSWorkspace sharedWorkspace] selectFile: [self dataLocation]
261        inFileViewerRootedAtPath: nil];
262}
263
264- (void) trashTorrent
265{
266    [self trashPath: [self torrentLocation]];
267}
268
269- (void) trashData
270{
271    [self trashPath: [self dataLocation]];
272}
273
274- (NSImage *) icon
275{
276    return fIcon;
277}
278
279- (NSImage *) iconFlipped
280{
281    return fIconFlipped;
282}
283
284- (NSString *) name
285{
286    return [NSString stringWithUTF8String: fInfo->name];
287}
288
289- (uint64_t) size
290{
291    return fInfo->totalSize;
292}
293
294- (NSString *) tracker
295{
296    return [NSString stringWithFormat: @"%s:%d",
297            fInfo->trackerAddress, fInfo->trackerPort];
298}
299
300- (NSString *) announce
301{
302    return [NSString stringWithUTF8String: fInfo->trackerAnnounce];
303}
304
305- (int) pieceSize
306{
307    return fInfo->pieceSize;
308}
309
310- (int) pieceCount
311{
312    return fInfo->pieceCount;
313}
314
315- (NSString *) hashString
316{
317    NSMutableString * string = [NSMutableString
318        stringWithCapacity: SHA_DIGEST_LENGTH];
319    int i;
320    for( i = 0; i < SHA_DIGEST_LENGTH; i++ )
321    {
322        [string appendFormat: @"%02x", fInfo->hash[i]];
323    }
324    return string;
325}
326
327- (NSString *) torrentLocation
328{
329    return [NSString stringWithUTF8String: fInfo->torrent];;
330}
331
332- (NSString *) dataLocation
333{
334    return [[self downloadFolder] stringByAppendingPathComponent: [self name]];
335}
336
337- (NSString *) state
338{
339    switch( fStat->status )
340    {
341        case TR_STATUS_PAUSE:
342            return @"Paused";
343            break;
344
345        case TR_STATUS_CHECK:
346            return [@"Checking existing files" stringByAppendingString: NS_ELLIPSIS];
347            break;
348
349        case TR_STATUS_DOWNLOAD:
350            return @"Downloading";
351            break;
352
353        case TR_STATUS_SEED:
354            return @"Seeding";
355            break;
356
357        case TR_STATUS_STOPPING:
358            return [@"Stopping" stringByAppendingString: NS_ELLIPSIS];
359            break;
360       
361        default:
362            return @"N/A";
363    }
364}
365
366- (float) progress
367{
368    return fStat->progress;
369}
370
371- (BOOL) isActive
372{
373    return ( fStat->status & TR_STATUS_ACTIVE );
374}
375
376- (BOOL) isSeeding
377{
378    return ( fStat->status == TR_STATUS_SEED );
379}
380
381- (BOOL) isPaused
382{
383    return ( fStat->status == TR_STATUS_PAUSE );
384}
385
386- (BOOL) justFinished
387{
388    return tr_getFinished( fHandle );
389}
390
391- (NSString *) progressString
392{
393    return fProgressString;
394}
395
396- (NSString *) statusString
397{
398    return fStatusString;
399}
400
401- (int) seeders
402{
403    return fStat->seeders;
404}
405
406- (int) leechers
407{
408    return fStat->leechers;
409}
410
411- (int) totalPeers
412{
413    return fStat->peersTotal;
414}
415
416//peers uploading to you
417- (int) peersUploading
418{
419    return fStat->peersUploading;
420}
421
422//peers downloading from you
423- (int) peersDownloading
424{
425    return fStat->peersDownloading;
426}
427
428- (float) downloadRate
429{
430    return fStat->rateDownload;
431}
432
433- (float) uploadRate
434{
435    return fStat->rateUpload;
436}
437
438- (uint64_t) downloaded
439{
440    return fStat->downloaded;
441}
442
443- (uint64_t) uploaded
444{
445    return fStat->uploaded;
446}
447
448- (NSArray *) fileList
449{
450    int count = fInfo->fileCount, i;
451    NSMutableArray * files = [NSMutableArray arrayWithCapacity: count];
452    for (i = 0; i < count; i++)
453        [files addObject: [[self downloadFolder] stringByAppendingPathComponent:
454            [NSString stringWithUTF8String: fInfo->files[i].name]]];
455    return files;
456}
457
458- (NSDate *) date
459{
460    return fDate;
461}
462
463- (NSNumber *) stateSortKey
464{
465    if (fStat->status & TR_STATUS_INACTIVE)
466        return [NSNumber numberWithInt: 0];
467    else if (fStat->status == TR_STATUS_SEED)
468        return [NSNumber numberWithInt: 1];
469    else
470        return [NSNumber numberWithInt: 2];
471}
472
473- (NSNumber *) progressSortKey
474{
475    return [NSNumber numberWithFloat: [self progress]];
476}
477
478@end
479
480
481@implementation Torrent (Private)
482
483- (id) initWithPath: (NSString *) path lib: (tr_handle_t *) lib date: (NSDate *) date
484        stopRatioSetting: (NSNumber *) stopRatioSetting ratioLimit: (NSNumber *) ratioLimit
485{
486    if (!(self = [super init]))
487        return nil;
488
489    fLib = lib;
490
491    int error;
492    if (!path || !(fHandle = tr_torrentInit(fLib, [path UTF8String], &error)))
493    {
494        [self release];
495        return nil;
496    }
497   
498    fInfo = tr_torrentInfo( fHandle );
499   
500    fDefaults = [NSUserDefaults standardUserDefaults];
501
502    fDate = date ? [date retain] : [[NSDate alloc] init];
503    fStopRatioSetting = stopRatioSetting ? [stopRatioSetting intValue] : -1;
504    fRatioLimit = ratioLimit ? [ratioLimit floatValue] : [fDefaults floatForKey: @"RatioLimit"];
505   
506    NSString * fileType = ( fInfo->fileCount > 1 ) ?
507        NSFileTypeForHFSTypeCode('fldr') : [[self name] pathExtension];
508    fIcon = [[NSWorkspace sharedWorkspace] iconForFileType: fileType];
509    [fIcon retain];
510   
511    fIconFlipped = [fIcon copy];
512    [fIconFlipped setFlipped: YES];
513
514    fProgressString = [[NSMutableString alloc] initWithCapacity: 50];
515    fStatusString = [[NSMutableString alloc] initWithCapacity: 75];
516
517    [self update];
518    return self;
519}
520
521- (void) trashPath: (NSString *) path
522{
523    if( ![[NSWorkspace sharedWorkspace] performFileOperation:
524           NSWorkspaceRecycleOperation source:
525           [path stringByDeletingLastPathComponent]
526           destination: @""
527           files: [NSArray arrayWithObject: [path lastPathComponent]]
528           tag: nil] )
529    {
530        /* We can't move it to the trash, let's try just to delete it
531           (will work if it is on a remote volume) */
532        if( ![[NSFileManager defaultManager]
533                removeFileAtPath: path handler: nil] )
534        {
535            NSLog( [@"Could not trash " stringByAppendingString: path] );
536        }
537    }
538}
539
540@end
Note: See TracBrowser for help on using the repository browser.