source: trunk/macosx/Torrent.m @ 450

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

Update the inspector when necessary through notifications, which will help once the wait check is added to the inspector.

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