source: trunk/macosx/Torrent.m @ 344

Last change on this file since 344 was 344, checked in by livings124, 16 years ago

This should make the borders of the new progress bar a bit more consistent.

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