source: branches/save_torrent_files/macosx/Torrent.m @ 294

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

Re-commit rev 291, in the right place this time.

  • Property svn:keywords set to Date Rev Author Id
File size: 15.6 KB
Line 
1/******************************************************************************
2 * $Id: Torrent.m 294 2006-06-08 05:01:42Z 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- (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        if ([self progress] < 1.0)
216            [fStatusString appendFormat: @" - DL: %@, ", [NSString stringForSpeed: [self downloadRate]]];
217        [fStatusString appendString: [@"UL: " stringByAppendingString:
218                                                [NSString stringForSpeed: [self uploadRate]]]];
219    }
220}
221
222- (void) start
223{
224    if( fStat->status & TR_STATUS_INACTIVE )
225    {
226        tr_torrentStart( fHandle );
227    }
228}
229
230- (void) stop
231{
232    if( fStat->status & TR_STATUS_ACTIVE )
233    {
234        tr_torrentStop( fHandle );
235    }
236}
237
238- (void) removeForever
239{
240    tr_torrentRemoveSaved(fHandle);
241}
242
243- (void) sleep
244{
245    if( ( fResumeOnWake = ( fStat->status & TR_STATUS_ACTIVE ) ) )
246    {
247        [self stop];
248    }
249}
250
251- (void) wakeUp
252{
253    if( fResumeOnWake )
254    {
255        [self start];
256    }
257}
258
259- (float) ratio
260{
261    float downloaded = [self downloaded];
262    return downloaded > 0 ? (float)[self uploaded] / downloaded : -1;
263}
264
265- (int) stopRatioSetting
266{
267        return fStopRatioSetting;
268}
269
270- (void) setStopRatioSetting: (int) setting
271{
272    fStopRatioSetting = setting;
273}
274
275- (float) ratioLimit
276{
277    return fRatioLimit;
278}
279
280- (void) setRatioLimit: (float) limit
281{
282    if (limit >= 0)
283        fRatioLimit = limit;
284}
285
286- (void) reveal
287{
288    [[NSWorkspace sharedWorkspace] selectFile: [self dataLocation]
289        inFileViewerRootedAtPath: nil];
290}
291
292- (void) trashData
293{
294    [self trashPath: [self dataLocation]];
295}
296
297- (NSImage *) icon
298{
299    return fIcon;
300}
301
302- (NSImage *) iconFlipped
303{
304    return fIconFlipped;
305}
306
307- (NSString *) name
308{
309    return [NSString stringWithUTF8String: fInfo->name];
310}
311
312- (uint64_t) size
313{
314    return fInfo->totalSize;
315}
316
317- (NSString *) tracker
318{
319    return [NSString stringWithFormat: @"%s:%d",
320            fInfo->trackerAddress, fInfo->trackerPort];
321}
322
323- (NSString *) announce
324{
325    return [NSString stringWithUTF8String: fInfo->trackerAnnounce];
326}
327
328- (int) pieceSize
329{
330    return fInfo->pieceSize;
331}
332
333- (int) pieceCount
334{
335    return fInfo->pieceCount;
336}
337
338- (NSString *) hashString
339{
340    /*NSMutableString * string = [NSMutableString
341        stringWithCapacity: SHA_DIGEST_LENGTH];
342    int i;
343    for( i = 0; i < SHA_DIGEST_LENGTH; i++ )
344    {
345        [string appendFormat: @"%02x", fInfo->hash[i]];
346    }
347    return string;*/
348   
349    return [NSString stringWithUTF8String: fInfo->hashString];
350}
351
352- (NSString *) torrentLocation
353{
354    return [NSString stringWithUTF8String: fInfo->torrent];
355}
356
357- (NSString *) dataLocation
358{
359    return [[self downloadFolder] stringByAppendingPathComponent: [self name]];
360}
361
362- (NSString *) state
363{
364    switch( fStat->status )
365    {
366        case TR_STATUS_PAUSE:
367            return @"Paused";
368            break;
369
370        case TR_STATUS_CHECK:
371            return [@"Checking existing files" stringByAppendingString: NS_ELLIPSIS];
372            break;
373
374        case TR_STATUS_DOWNLOAD:
375            return @"Downloading";
376            break;
377
378        case TR_STATUS_SEED:
379            return @"Seeding";
380            break;
381
382        case TR_STATUS_STOPPING:
383            return [@"Stopping" stringByAppendingString: NS_ELLIPSIS];
384            break;
385       
386        default:
387            return @"N/A";
388    }
389}
390
391- (float) progress
392{
393    return fStat->progress;
394}
395
396- (BOOL) isActive
397{
398    return ( fStat->status & TR_STATUS_ACTIVE );
399}
400
401- (BOOL) isSeeding
402{
403    return ( fStat->status == TR_STATUS_SEED );
404}
405
406- (BOOL) isPaused
407{
408    return ( fStat->status == TR_STATUS_PAUSE );
409}
410
411- (BOOL) justFinished
412{
413    return tr_getFinished( fHandle );
414}
415
416- (NSString *) progressString
417{
418    return fProgressString;
419}
420
421- (NSString *) statusString
422{
423    return fStatusString;
424}
425
426- (int) seeders
427{
428    return fStat->seeders;
429}
430
431- (int) leechers
432{
433    return fStat->leechers;
434}
435
436- (int) totalPeers
437{
438    return fStat->peersTotal;
439}
440
441//peers uploading to you
442- (int) peersUploading
443{
444    return fStat->peersUploading;
445}
446
447//peers downloading from you
448- (int) peersDownloading
449{
450    return fStat->peersDownloading;
451}
452
453- (float) downloadRate
454{
455    return fStat->rateDownload;
456}
457
458- (float) uploadRate
459{
460    return fStat->rateUpload;
461}
462
463- (uint64_t) downloaded
464{
465    return fStat->downloaded;
466}
467
468- (uint64_t) uploaded
469{
470    return fStat->uploaded;
471}
472
473- (NSArray *) fileList
474{
475    int count = fInfo->fileCount, i;
476    NSMutableArray * files = [NSMutableArray arrayWithCapacity: count];
477    for (i = 0; i < count; i++)
478        [files addObject: [[self downloadFolder] stringByAppendingPathComponent:
479            [NSString stringWithUTF8String: fInfo->files[i].name]]];
480    return files;
481}
482
483- (NSDate *) date
484{
485    return fDate;
486}
487
488- (NSNumber *) stateSortKey
489{
490    if (fStat->status & TR_STATUS_INACTIVE)
491        return [NSNumber numberWithInt: 0];
492    else if (fStat->status == TR_STATUS_SEED)
493        return [NSNumber numberWithInt: 1];
494    else
495        return [NSNumber numberWithInt: 2];
496}
497
498- (NSNumber *) progressSortKey
499{
500    return [NSNumber numberWithFloat: [self progress]];
501}
502
503@end
504
505
506@implementation Torrent (Private)
507
508- (id) initWithPath: (NSString *) path lib: (tr_handle_t *) lib date: (NSDate *) date
509        stopRatioSetting: (NSNumber *) stopRatioSetting ratioLimit: (NSNumber *) ratioLimit
510{
511    if (!(self = [super init]))
512        return nil;
513
514    fLib = lib;
515    fDefaults = [NSUserDefaults standardUserDefaults];
516
517    fPrivateSaved = [fDefaults boolForKey: @"SavePrivateTorrent"];
518
519    int error;
520    if (!path || !(fHandle = tr_torrentInit(fLib, [path UTF8String],
521                    fPrivateSaved ? TR_FSAVEPRIVATE : 0, &error)))
522    {
523        [self release];
524        return nil;
525    }
526   
527    return [self initForSuccessWithDate: date stopRatioSetting: stopRatioSetting ratioLimit: ratioLimit];
528}
529
530- (id) initWithHash: (NSString *) hashString lib: (tr_handle_t *) lib date: (NSDate *) date
531        stopRatioSetting: (NSNumber *) stopRatioSetting ratioLimit: (NSNumber *) ratioLimit
532{
533    if (!(self = [super init]))
534        return nil;
535
536    fLib = lib;
537    fDefaults = [NSUserDefaults standardUserDefaults];
538   
539    fPrivateSaved = YES;
540
541    int error;
542    if (!hashString || !(fHandle = tr_torrentInitSaved(fLib, [hashString UTF8String], TR_FSAVEPRIVATE, &error)))
543    {
544        [self release];
545        return nil;
546    }
547   
548    return [self initForSuccessWithDate: date stopRatioSetting: stopRatioSetting ratioLimit: ratioLimit];
549}
550
551- (id) initForSuccessWithDate: (NSDate *) date stopRatioSetting: (NSNumber *)
552            stopRatioSetting ratioLimit: (NSNumber *) ratioLimit
553{
554    fInfo = tr_torrentInfo( fHandle );
555
556    fDate = date ? [date retain] : [[NSDate alloc] init];
557    fStopRatioSetting = stopRatioSetting ? [stopRatioSetting intValue] : -1;
558    fRatioLimit = ratioLimit ? [ratioLimit floatValue] : [fDefaults floatForKey: @"RatioLimit"];
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.