source: trunk/macosx/Torrent.m @ 291

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

Initial support of moving torrent files in Mac version. Some things are incomplete and it's not yet guaranteed to work (in other words, only I should be even trying to use it).

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