2006-07-16 19:39:23 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* $ Id $
*
* Copyright ( c ) 2006 Transmission authors and contributors
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the "Software" ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
# import "Torrent.h"
# import "StringAdditions.h"
2006-09-12 00:08:30 +00:00
# define BAR_HEIGHT 12.0
2006-10-05 21:21:30 +00:00
# define MAX_PIECES 324
# define BLANK_PIECE -99
2006-07-16 19:39:23 +00:00
@ interface Torrent ( Private )
- ( id ) initWithHash : ( NSString * ) hashString path : ( NSString * ) path lib : ( tr_handle _t * ) lib
privateTorrent : ( NSNumber * ) privateTorrent publicTorrent : ( NSNumber * ) publicTorrent
date : ( NSDate * ) date stopRatioSetting : ( NSNumber * ) stopRatioSetting
ratioLimit : ( NSNumber * ) ratioLimit waitToStart : ( NSNumber * ) waitToStart
orderValue : ( NSNumber * ) orderValue ;
2006-09-12 00:08:30 +00:00
- ( NSImage * ) advancedBar ;
2006-07-16 19:39:23 +00:00
- ( void ) trashFile : ( NSString * ) path ;
@ end
@ implementation Torrent
2006-09-12 00:08:30 +00:00
// Used to optimize drawing . They contain packed RGBA pixels for every color needed .
# define BE OSSwapBigToHostConstInt32
static uint32_t kRed = BE ( 0 xFF6450FF ) , // 255 , 100 , 80
2006-10-06 20:45:59 +00:00
kBlue = BE ( 0 x50A0FFFF ) , // 80 , 160 , 255
kBlue2 = BE ( 0 x1E46B4FF ) , // 30 , 70 , 180
2006-09-25 18:37:45 +00:00
kGray = BE ( 0 x969696FF ) , // 150 , 150 , 150
2006-10-06 20:45:59 +00:00
kGreen1 = BE ( 0 x99FFCCFF ) , // 153 , 255 , 204
kGreen2 = BE ( 0 x66FF99FF ) , // 102 , 255 , 153
kGreen3 = BE ( 0 x00FF66FF ) , // 0 , 255 , 102
2006-09-12 00:56:37 +00:00
kWhite = BE ( 0 xFFFFFFFF ) ; // 255 , 255 , 255
2006-09-12 00:08:30 +00:00
2006-07-16 19:39:23 +00:00
- ( id ) initWithPath : ( NSString * ) path lib : ( tr_handle _t * ) lib
{
self = [ self initWithHash : nil path : path lib : lib privateTorrent : nil publicTorrent : nil
date : nil stopRatioSetting : nil ratioLimit : nil waitToStart : nil orderValue : nil ] ;
if ( self )
{
if ( ! fPublicTorrent )
[ self trashFile : path ] ;
}
return self ;
}
- ( id ) initWithHistory : ( NSDictionary * ) history lib : ( tr_handle _t * ) lib
{
self = [ self initWithHash : [ history objectForKey : @ "TorrentHash" ]
path : [ history objectForKey : @ "TorrentPath" ] lib : lib
privateTorrent : [ history objectForKey : @ "PrivateCopy" ]
publicTorrent : [ history objectForKey : @ "PublicCopy" ]
date : [ history objectForKey : @ "Date" ]
stopRatioSetting : [ history objectForKey : @ "StopRatioSetting" ]
ratioLimit : [ history objectForKey : @ "RatioLimit" ]
waitToStart : [ history objectForKey : @ "WaitToStart" ]
orderValue : [ history objectForKey : @ "OrderValue" ] ] ;
if ( self )
{
NSString * downloadFolder ;
if ( ! ( downloadFolder = [ history objectForKey : @ "DownloadFolder" ] ) )
downloadFolder = [ [ fDefaults stringForKey : @ "DownloadFolder" ] stringByExpandingTildeInPath ] ;
[ self setDownloadFolder : downloadFolder ] ;
NSString * paused ;
if ( ! ( paused = [ history objectForKey : @ "Paused" ] ) || [ paused isEqualToString : @ "NO" ] )
2006-09-28 23:32:59 +00:00
{
fStat = tr_torrentStat ( fHandle ) ;
2006-09-28 00:48:07 +00:00
[ self startTransfer ] ;
2006-09-28 23:32:59 +00:00
}
2006-07-16 19:39:23 +00:00
}
return self ;
}
- ( NSDictionary * ) history
{
NSMutableDictionary * history = [ NSMutableDictionary dictionaryWithObjectsAndKeys :
[ NSNumber numberWithBool : fPrivateTorrent ] , @ "PrivateCopy" ,
[ NSNumber numberWithBool : fPublicTorrent ] , @ "PublicCopy" ,
[ self downloadFolder ] , @ "DownloadFolder" ,
[ self isActive ] ? @ "NO" : @ "YES" , @ "Paused" ,
[ self date ] , @ "Date" ,
[ NSNumber numberWithInt : fStopRatioSetting ] , @ "StopRatioSetting" ,
[ NSNumber numberWithFloat : fRatioLimit ] , @ "RatioLimit" ,
[ NSNumber numberWithBool : fWaitToStart ] , @ "WaitToStart" ,
[ self orderValue ] , @ "OrderValue" , nil ] ;
if ( fPrivateTorrent )
[ history setObject : [ self hashString ] forKey : @ "TorrentHash" ] ;
if ( fPublicTorrent )
[ history setObject : [ self publicTorrentLocation ] forKey : @ "TorrentPath" ] ;
return history ;
}
- ( void ) dealloc
{
if ( fHandle )
{
tr_torrentClose ( fLib , fHandle ) ;
if ( fPublicTorrentLocation )
[ fPublicTorrentLocation release ] ;
[ fDate release ] ;
[ fIcon release ] ;
[ fIconFlipped release ] ;
[ fIconSmall release ] ;
[ fProgressString release ] ;
[ fStatusString release ] ;
[ fShortStatusString release ] ;
2006-07-25 00:59:14 +00:00
[ fRemainingTimeString release ] ;
2006-10-05 21:21:30 +00:00
[ fBitmap release ] ;
free ( fPieces ) ;
2006-07-16 19:39:23 +00:00
}
[ super dealloc ] ;
}
- ( void ) setDownloadFolder : ( NSString * ) path
{
tr_torrentSetFolder ( fHandle , [ path UTF8String ] ) ;
}
- ( NSString * ) downloadFolder
{
return [ NSString stringWithUTF8String : tr_torrentGetFolder ( fHandle ) ] ;
}
- ( void ) getAvailability : ( int8_t * ) tab size : ( int ) size
{
tr_torrentAvailability ( fHandle , tab , size ) ;
}
2006-10-13 01:34:15 +00:00
- ( void ) getAmountFinished : ( float * ) tab size : ( int ) size
2006-10-12 23:34:20 +00:00
{
tr_torrentAmountFinished ( fHandle , tab , size ) ;
}
2006-07-16 19:39:23 +00:00
- ( void ) update
{
fStat = tr_torrentStat ( fHandle ) ;
2006-07-30 18:37:29 +00:00
// notification when downloading finished
if ( [ self justFinished ] )
[ [ NSNotificationCenter defaultCenter ] postNotificationName : @ "TorrentFinishedDownloading" object : self ] ;
2006-07-16 19:39:23 +00:00
// check to stop for ratio
if ( [ self isSeeding ] && ( ( fStopRatioSetting = = RATIO_CHECK && [ self ratio ] >= fRatioLimit )
|| ( fStopRatioSetting = = RATIO_GLOBAL && [ fDefaults boolForKey : @ "RatioCheck" ]
&& [ self ratio ] >= [ fDefaults floatForKey : @ "RatioLimit" ] ) ) )
{
[ self stopTransfer ] ;
[ self setStopRatioSetting : RATIO_NO _CHECK ] ;
fFinishedSeeding = YES ;
fStat = tr_torrentStat ( fHandle ) ;
[ [ NSNotificationCenter defaultCenter ] postNotificationName : @ "TorrentStoppedForRatio" object : self ] ;
}
[ fProgressString setString : @ "" ] ;
if ( [ self progress ] < 1.0 )
2006-10-24 20:34:13 +00:00
[ fProgressString appendFormat : NSLocalizedString ( @ "%@ of %@ (%.2f%%)" , "Torrent -> progress string" ) , [ NSString stringForFileSize :
2006-07-16 19:39:23 +00:00
[ self downloadedValid ] ] , [ NSString stringForFileSize : [ self size ] ] , 100.0 * [ self progress ] ] ;
else
2006-10-24 20:34:13 +00:00
[ fProgressString appendFormat : NSLocalizedString ( @ "%@, uploaded %@ (Ratio: %@)" , "Torrent -> progress string" ) , [ NSString stringForFileSize :
2006-07-16 19:39:23 +00:00
[ self size ] ] , [ NSString stringForFileSize : [ self uploadedTotal ] ] ,
[ NSString stringForRatioWithDownload : [ self downloadedTotal ] upload : [ self uploadedTotal ] ] ] ;
switch ( fStat -> status )
{
NSString * tempString ;
case TR_STATUS _PAUSE :
if ( fFinishedSeeding )
2006-10-24 20:34:13 +00:00
tempString = NSLocalizedString ( @ "Seeding complete" , "Torrent -> status string" ) ;
2006-09-25 18:37:45 +00:00
else if ( fWaitToStart )
2006-10-24 20:34:13 +00:00
tempString = [ NSLocalizedString ( @ "Waiting to start" , "Torrent -> status string" ) stringByAppendingEllipsis ] ;
2006-07-16 19:39:23 +00:00
else
2006-10-24 20:34:13 +00:00
tempString = NSLocalizedString ( @ "Paused" , "Torrent -> status string" ) ;
2006-07-16 19:39:23 +00:00
[ fStatusString setString : tempString ] ;
[ fShortStatusString setString : tempString ] ;
break ;
case TR_STATUS _CHECK :
2006-10-24 20:34:13 +00:00
tempString = [ NSLocalizedString ( @ "Checking existing files" , "Torrent -> status string" ) stringByAppendingEllipsis ] ;
2006-07-16 19:39:23 +00:00
[ fStatusString setString : tempString ] ;
[ fShortStatusString setString : tempString ] ;
2006-07-25 00:59:14 +00:00
[ fRemainingTimeString setString : tempString ] ;
2006-07-16 19:39:23 +00:00
break ;
case TR_STATUS _DOWNLOAD :
[ fStatusString setString : @ "" ] ;
2006-10-24 20:34:13 +00:00
if ( [ self totalPeers ] > 1 )
[ fStatusString appendFormat : NSLocalizedString ( @ "Downloading from %d of %d peers" , "Torrent -> status string" ) , [ self peersUploading ] , [ self totalPeers ] ] ;
else
[ fStatusString appendFormat : NSLocalizedString ( @ "Downloading from %d of %d peer" , "Torrent -> status string" ) , [ self peersUploading ] , [ self totalPeers ] ] ;
2006-07-16 19:39:23 +00:00
2006-07-25 00:59:14 +00:00
[ fRemainingTimeString setString : @ "" ] ;
2006-07-16 19:39:23 +00:00
int eta = [ self eta ] ;
if ( eta < 0 )
2006-07-25 00:59:14 +00:00
{
2006-10-24 20:34:13 +00:00
[ fRemainingTimeString setString : NSLocalizedString ( @ "Unknown" , "Torrent -> remaining time" ) ] ;
[ fProgressString appendString : NSLocalizedString ( @ " - remaining time unknown" , "Torrent -> progress string" ) ] ;
2006-07-25 00:59:14 +00:00
}
2006-07-16 19:39:23 +00:00
else
2006-07-25 00:59:14 +00:00
{
if ( eta < 60 )
2006-10-24 20:34:13 +00:00
[ fRemainingTimeString appendFormat : NSLocalizedString ( @ "%d sec" , "Torrent -> remaining time" ) , eta ] ;
2006-07-25 00:59:14 +00:00
else if ( eta < 3600 ) // 60 * 60
2006-10-24 20:34:13 +00:00
[ fRemainingTimeString appendFormat : NSLocalizedString ( @ "%d min %02d sec" , "Torrent -> remaining time" ) , eta / 60 , eta % 60 ] ;
2006-07-25 00:59:14 +00:00
else if ( eta < 86400 ) // 24 * 60 * 60
2006-10-24 20:34:13 +00:00
[ fRemainingTimeString appendFormat : NSLocalizedString ( @ "%d hr %02d min" , "Torrent -> remaining time" ) , eta / 3600 , ( eta / 60 ) % 60 ] ;
2006-07-25 00:59:14 +00:00
else
2006-10-24 20:34:13 +00:00
{
if ( eta / 86400 > 1 )
[ fRemainingTimeString appendFormat : NSLocalizedString ( @ "%d days %d hr" , "Torrent -> remaining time" ) ,
eta / 86400 , ( eta / 3600 ) % 24 ] ;
else
[ fRemainingTimeString appendFormat : NSLocalizedString ( @ "%d day %d hr" , "Torrent -> remaining time" ) ,
eta / 86400 , ( eta / 3600 ) % 24 ] ;
}
2006-07-25 00:59:14 +00:00
2006-10-24 20:34:13 +00:00
[ fProgressString appendFormat : NSLocalizedString ( @ " - %@ remaining" , "Torrent -> progress string" ) , fRemainingTimeString ] ;
2006-07-25 00:59:14 +00:00
}
2006-07-16 19:39:23 +00:00
break ;
case TR_STATUS _SEED :
[ fStatusString setString : @ "" ] ;
2006-10-24 20:34:13 +00:00
if ( [ self totalPeers ] > 1 )
[ fStatusString appendFormat : NSLocalizedString ( @ "Seeding to %d of %d peers" , "Torrent -> status string" ) , [ self peersDownloading ] , [ self totalPeers ] ] ;
else
[ fStatusString appendFormat : NSLocalizedString ( @ "Seeding to %d of %d peer" , "Torrent -> status string" ) , [ self peersDownloading ] , [ self totalPeers ] ] ;
2006-07-16 19:39:23 +00:00
break ;
case TR_STATUS _STOPPING :
2006-10-24 20:34:13 +00:00
tempString = [ NSLocalizedString ( @ "Stopping" , "Torrent -> status string" ) stringByAppendingEllipsis ] ;
2006-07-16 19:39:23 +00:00
[ fStatusString setString : tempString ] ;
[ fShortStatusString setString : tempString ] ;
break ;
}
2006-09-29 05:30:36 +00:00
if ( fStat -> error & TR_ETRACKER )
{
2006-10-24 20:34:13 +00:00
[ fStatusString setString : [ NSLocalizedString ( @ "Error: " , "Torrent -> status string" ) stringByAppendingString : [ NSString stringWithUTF8String : fStat -> trackerError ] ] ] ;
2006-09-29 05:30:36 +00:00
if ( ! fError && [ self isActive ] )
{
fError = YES ;
if ( ! [ self isSeeding ] )
[ [ NSNotificationCenter defaultCenter ] postNotificationName : @ "StoppedDownloading" object : self ] ;
}
}
else
{
if ( fError )
fError = NO ;
}
2006-07-16 19:39:23 +00:00
if ( [ self isActive ] )
{
NSString * stringToAppend = @ "" ;
if ( [ self progress ] < 1.0 )
{
2006-10-24 20:34:13 +00:00
stringToAppend = [ NSString stringWithFormat : NSLocalizedString ( @ "DL: %@, " , "Torrent -> status string" ) , [ NSString stringForSpeed : [ self downloadRate ] ] ] ;
2006-07-16 19:39:23 +00:00
[ fShortStatusString setString : @ "" ] ;
}
else
2006-08-06 20:40:12 +00:00
{
NSString * ratioString = [ NSString stringForRatioWithDownload : [ self downloadedTotal ]
upload : [ self uploadedTotal ] ] ;
2006-10-24 20:34:13 +00:00
[ fShortStatusString setString : [ NSString stringWithFormat : NSLocalizedString ( @ "Ratio: %@, " , "Torrent -> status string" ) , ratioString ] ] ;
[ fRemainingTimeString setString : [ NSLocalizedString ( @ "Ratio: " , "Torrent -> status string" ) stringByAppendingString : ratioString ] ] ;
2006-08-06 20:40:12 +00:00
}
2006-07-16 19:39:23 +00:00
2006-10-24 20:34:13 +00:00
stringToAppend = [ stringToAppend stringByAppendingString : [ NSLocalizedString ( @ "UL: " , "Torrent -> status string" ) stringByAppendingString :
2006-07-16 19:39:23 +00:00
[ NSString stringForSpeed : [ self uploadRate ] ] ] ] ;
[ fStatusString appendFormat : @ " - %@" , stringToAppend ] ;
[ fShortStatusString appendString : stringToAppend ] ;
}
}
2006-09-11 23:52:03 +00:00
- ( NSDictionary * ) infoForCurrentView
{
NSMutableDictionary * info = [ NSMutableDictionary dictionaryWithObjectsAndKeys :
[ self name ] , @ "Name" ,
[ NSNumber numberWithBool : [ self isSeeding ] ] , @ "Seeding" ,
[ NSNumber numberWithFloat : [ self progress ] ] , @ "Progress" ,
[ NSNumber numberWithBool : [ self isActive ] ] , @ "Active" ,
[ NSNumber numberWithBool : [ self isError ] ] , @ "Error" , nil ] ;
if ( ! [ fDefaults boolForKey : @ "SmallView" ] )
{
[ info setObject : fIconFlipped forKey : @ "Icon" ] ;
[ info setObject : [ self progressString ] forKey : @ "ProgressString" ] ;
[ info setObject : [ self statusString ] forKey : @ "StatusString" ] ;
}
else
{
[ info setObject : fIconSmall forKey : @ "Icon" ] ;
[ info setObject : [ self remainingTimeString ] forKey : @ "RemainingTimeString" ] ;
[ info setObject : [ self shortStatusString ] forKey : @ "ShortStatusString" ] ;
}
2006-09-12 00:08:30 +00:00
if ( [ fDefaults boolForKey : @ "UseAdvancedBar" ] )
[ info setObject : [ self advancedBar ] forKey : @ "AdvancedBar" ] ;
2006-09-11 23:52:03 +00:00
return info ;
}
2006-07-16 19:39:23 +00:00
- ( void ) startTransfer
{
2006-09-28 00:32:26 +00:00
fWaitToStart = NO ;
fFinishedSeeding = NO ;
if ( ! [ self isActive ] && [ self remainingDiskSpaceForTorrent ] )
2006-07-16 19:39:23 +00:00
tr_torrentStart ( fHandle ) ;
}
- ( void ) stopTransfer
{
2006-09-29 05:30:36 +00:00
fError = NO ;
2006-07-16 19:39:23 +00:00
if ( [ self isActive ] )
{
BOOL wasSeeding = [ self isSeeding ] ;
tr_torrentStop ( fHandle ) ;
if ( ! wasSeeding )
[ [ NSNotificationCenter defaultCenter ] postNotificationName : @ "StoppedDownloading" object : self ] ;
}
}
- ( void ) stopTransferForQuit
{
if ( [ self isActive ] )
tr_torrentStop ( fHandle ) ;
}
- ( void ) removeForever
{
if ( fPrivateTorrent )
tr_torrentRemoveSaved ( fHandle ) ;
}
- ( void ) sleep
{
if ( ( fResumeOnWake = [ self isActive ] ) )
tr_torrentStop ( fHandle ) ;
}
- ( void ) wakeUp
{
if ( fResumeOnWake )
tr_torrentStart ( fHandle ) ;
}
- ( float ) ratio
{
float downloaded = [ self downloadedTotal ] ;
return downloaded > 0 ? ( float ) [ self uploadedTotal ] / downloaded : -1 ;
}
- ( int ) stopRatioSetting
{
return fStopRatioSetting ;
}
- ( void ) setStopRatioSetting : ( int ) setting
{
fStopRatioSetting = setting ;
}
- ( float ) ratioLimit
{
return fRatioLimit ;
}
- ( void ) setRatioLimit : ( float ) limit
{
if ( limit >= 0 )
fRatioLimit = limit ;
}
- ( void ) setWaitToStart : ( BOOL ) wait
{
fWaitToStart = wait ;
}
- ( BOOL ) waitingToStart
{
return fWaitToStart ;
}
- ( void ) revealData
{
[ [ NSWorkspace sharedWorkspace ] selectFile : [ self dataLocation ] inFileViewerRootedAtPath : nil ] ;
}
2006-10-15 19:57:40 +00:00
- ( void ) revealPublicTorrent
{
if ( fPublicTorrent )
[ [ NSWorkspace sharedWorkspace ] selectFile : fPublicTorrentLocation inFileViewerRootedAtPath : nil ] ;
}
2006-07-16 19:39:23 +00:00
- ( void ) trashData
{
[ self trashFile : [ self dataLocation ] ] ;
}
- ( void ) trashTorrent
{
if ( fPublicTorrent )
[ self trashFile : [ self publicTorrentLocation ] ] ;
}
2006-09-28 00:32:26 +00:00
- ( BOOL ) remainingDiskSpaceForTorrent
{
if ( [ self progress ] >= 1.0 )
return YES ;
2006-09-28 17:17:07 +00:00
NSString * location = [ self dataLocation ] ,
* volume = [ [ [ NSFileManager defaultManager ] componentsToDisplayForPath : location ] objectAtIndex : 0 ] ;
NSDictionary * fsAttributes = [ [ NSFileManager defaultManager ] fileSystemAttributesAtPath : location ] ;
2006-09-28 04:06:38 +00:00
uint64_t remainingSpace = [ [ fsAttributes objectForKey : NSFileSystemFreeSize ] unsignedLongLongValue ] ,
2006-09-28 17:38:10 +00:00
torrentRemaining = [ self size ] - ( uint64_t ) [ self downloadedValid ] ;
2006-09-28 04:06:38 +00:00
2006-09-28 17:17:07 +00:00
NSLog ( @ "Volume: %@" , volume ) ;
2006-09-28 16:54:44 +00:00
NSLog ( @ "Remaining disk space: %qu (%@)" , remainingSpace , [ NSString stringForFileSize : remainingSpace ] ) ;
NSLog ( @ "Torrent remaining size: %qu (%@)" , torrentRemaining , [ NSString stringForFileSize : torrentRemaining ] ) ;
2006-09-28 00:32:26 +00:00
2006-09-28 17:17:07 +00:00
if ( volume && remainingSpace <= torrentRemaining )
2006-09-28 00:32:26 +00:00
{
NSAlert * alert = [ [ NSAlert alloc ] init ] ;
2006-10-24 20:34:13 +00:00
[ alert setMessageText : [ NSString stringWithFormat : NSLocalizedString ( @ "Not enough remaining disk space to download \" % @ \ " completely." , "Torrent file disk space alert -> title" ) ,
2006-09-28 00:32:26 +00:00
[ self name ] ] ] ;
2006-09-28 00:48:07 +00:00
[ alert setInformativeText : [ NSString stringWithFormat :
2006-10-24 20:34:13 +00:00
NSLocalizedString ( @ "The transfer will be paused. Clear up space on %@ to continue." , "Torrent file disk space alert -> message" ) , volume ] ] ;
[ alert addButtonWithTitle : NSLocalizedString ( @ "OK" , "Torrent file disk space alert -> button" ) ] ;
[ alert addButtonWithTitle : NSLocalizedString ( @ "Download Anyway" , "Torrent file disk space alert -> button" ) ] ;
2006-09-28 00:32:26 +00:00
2006-10-11 19:01:49 +00:00
if ( [ alert runModal ] = = NSAlertFirstButtonReturn )
{
[ [ NSNotificationCenter defaultCenter ] postNotificationName : @ "StoppedDownloading" object : self ] ;
return NO ;
}
else
return YES ;
2006-09-28 00:32:26 +00:00
}
return YES ;
}
2006-07-16 19:39:23 +00:00
- ( NSImage * ) icon
{
return fIcon ;
}
- ( NSImage * ) iconFlipped
{
return fIconFlipped ;
}
- ( NSImage * ) iconSmall
{
return fIconSmall ;
}
- ( NSString * ) name
{
return [ NSString stringWithUTF8String : fInfo -> name ] ;
}
- ( uint64_t ) size
{
return fInfo -> totalSize ;
}
- ( NSString * ) tracker
{
return [ NSString stringWithFormat : @ "%s:%d" , fInfo -> trackerAddress , fInfo -> trackerPort ] ;
}
- ( NSString * ) announce
{
return [ NSString stringWithUTF8String : fInfo -> trackerAnnounce ] ;
}
- ( int ) pieceSize
{
return fInfo -> pieceSize ;
}
- ( int ) pieceCount
{
return fInfo -> pieceCount ;
}
- ( NSString * ) hashString
{
return [ NSString stringWithUTF8String : fInfo -> hashString ] ;
}
- ( NSString * ) torrentLocation
{
return [ NSString stringWithUTF8String : fInfo -> torrent ] ;
}
- ( NSString * ) publicTorrentLocation
{
return fPublicTorrentLocation ;
}
- ( NSString * ) torrentLocationString
{
2006-10-24 20:34:13 +00:00
return fPrivateTorrent ? NSLocalizedString ( @ "Transmission Support Folder" , "Torrent -> location" ) : [ fPublicTorrentLocation stringByAbbreviatingWithTildeInPath ] ;
2006-07-16 19:39:23 +00:00
}
- ( NSString * ) dataLocation
{
return [ [ self downloadFolder ] stringByAppendingPathComponent : [ self name ] ] ;
}
- ( BOOL ) publicTorrent
{
return fPublicTorrent ;
}
- ( BOOL ) privateTorrent
{
return fPrivateTorrent ;
}
- ( NSString * ) stateString
{
switch ( fStat -> status )
{
case TR_STATUS _PAUSE :
2006-10-24 20:34:13 +00:00
return NSLocalizedString ( @ "Paused" , "Torrent -> status string" ) ;
2006-07-16 19:39:23 +00:00
break ;
case TR_STATUS _CHECK :
2006-10-24 20:34:13 +00:00
return [ NSLocalizedString ( @ "Checking existing files" , "Torrent -> status string" ) stringByAppendingEllipsis ] ;
2006-07-16 19:39:23 +00:00
break ;
case TR_STATUS _DOWNLOAD :
2006-10-24 20:34:13 +00:00
return NSLocalizedString ( @ "Downloading" , "Torrent -> status string" ) ;
2006-07-16 19:39:23 +00:00
break ;
case TR_STATUS _SEED :
2006-10-24 20:34:13 +00:00
return NSLocalizedString ( @ "Seeding" , "Torrent -> status string" ) ;
2006-07-16 19:39:23 +00:00
break ;
case TR_STATUS _STOPPING :
2006-10-24 20:34:13 +00:00
return [ NSLocalizedString ( @ "Stopping" , "Torrent -> status string" ) stringByAppendingEllipsis ] ;
2006-07-16 19:39:23 +00:00
break ;
default :
2006-10-24 20:34:13 +00:00
return NSLocalizedString ( @ "N/A" , "Torrent -> status string" ) ;
2006-07-16 19:39:23 +00:00
}
}
- ( float ) progress
{
return fStat -> progress ;
}
- ( int ) eta
{
return fStat -> eta ;
}
- ( BOOL ) isActive
{
return fStat -> status & TR_STATUS _ACTIVE ;
}
- ( BOOL ) isSeeding
{
return fStat -> status = = TR_STATUS _SEED ;
}
- ( BOOL ) isPaused
{
return fStat -> status = = TR_STATUS _PAUSE ;
}
2006-08-29 00:09:49 +00:00
- ( BOOL ) isError
{
return fStat -> error & TR_ETRACKER ;
}
2006-07-16 19:39:23 +00:00
- ( BOOL ) justFinished
{
return tr_getFinished ( fHandle ) ;
}
2006-08-13 15:46:02 +00:00
- ( NSArray * ) peers
{
2006-08-13 21:16:18 +00:00
int totalPeers , i ;
tr_peer _stat _t * peers = tr_torrentPeers ( fHandle , & totalPeers ) ;
2006-08-13 15:46:02 +00:00
2006-08-13 21:16:18 +00:00
NSMutableArray * peerDics = [ NSMutableArray arrayWithCapacity : totalPeers ] ;
2006-08-14 03:13:34 +00:00
tr_peer _stat _t peer ;
2006-08-13 21:56:20 +00:00
NSString * client ;
2006-08-13 15:46:02 +00:00
for ( i = 0 ; i < totalPeers ; i + + )
{
2006-08-13 21:16:18 +00:00
peer = peers [ i ] ;
[ peerDics addObject : [ NSDictionary dictionaryWithObjectsAndKeys :
2006-08-15 00:59:44 +00:00
[ NSNumber numberWithBool : peer . isConnected ] , @ "Connected" ,
2006-10-06 03:38:31 +00:00
[ NSNumber numberWithBool : peer . isIncoming ] , @ "Incoming" ,
2006-08-14 22:59:30 +00:00
[ NSString stringWithCString : ( char * ) peer . addr encoding : NSUTF8StringEncoding ] , @ "IP" ,
2006-08-14 22:27:34 +00:00
[ NSString stringWithCString : ( char * ) peer . client encoding : NSUTF8StringEncoding ] , @ "Client" ,
2006-08-13 19:43:15 +00:00
[ NSNumber numberWithBool : peer . isDownloading ] , @ "UL To" ,
[ NSNumber numberWithBool : peer . isUploading ] , @ "DL From" , nil ] ] ;
2006-08-13 15:46:02 +00:00
}
2006-08-13 21:24:23 +00:00
tr_torrentPeersFree ( peers , totalPeers ) ;
2006-08-13 21:16:18 +00:00
return peerDics ;
2006-08-13 15:46:02 +00:00
}
2006-07-16 19:39:23 +00:00
- ( NSString * ) progressString
{
return fProgressString ;
}
- ( NSString * ) statusString
{
return fStatusString ;
}
- ( NSString * ) shortStatusString
{
return fShortStatusString ;
}
2006-07-25 00:59:14 +00:00
- ( NSString * ) remainingTimeString
{
return fRemainingTimeString ;
}
2006-07-16 19:39:23 +00:00
- ( int ) seeders
{
return fStat -> seeders ;
}
- ( int ) leechers
{
return fStat -> leechers ;
}
- ( int ) totalPeers
{
return fStat -> peersTotal ;
}
2006-10-13 18:58:12 +00:00
- ( int ) totalPeersIncoming
{
return fStat -> peersIncoming ;
}
- ( int ) totalPeersOutgoing
{
return [ self totalPeers ] - [ self totalPeersIncoming ] ;
}
2006-07-16 19:39:23 +00:00
// peers uploading to you
- ( int ) peersUploading
{
return fStat -> peersUploading ;
}
// peers downloading from you
- ( int ) peersDownloading
{
return fStat -> peersDownloading ;
}
- ( float ) downloadRate
{
return fStat -> rateDownload ;
}
- ( float ) uploadRate
{
return fStat -> rateUpload ;
}
- ( float ) downloadedValid
{
return [ self progress ] * [ self size ] ;
}
- ( uint64_t ) downloadedTotal
{
return fStat -> downloaded ;
}
- ( uint64_t ) uploadedTotal
{
return fStat -> uploaded ;
}
2006-08-17 03:12:40 +00:00
- ( float ) swarmSpeed
{
return fStat -> swarmspeed ;
}
2006-07-16 19:39:23 +00:00
- ( NSNumber * ) orderValue
{
return [ NSNumber numberWithInt : fOrderValue ] ;
}
- ( void ) setOrderValue : ( int ) orderValue
{
fOrderValue = orderValue ;
}
- ( NSArray * ) fileList
{
int count = fInfo -> fileCount , i ;
2006-08-20 18:32:55 +00:00
tr_file _t file ;
2006-07-16 19:39:23 +00:00
NSMutableArray * files = [ NSMutableArray arrayWithCapacity : count ] ;
2006-08-20 18:32:55 +00:00
2006-07-16 19:39:23 +00:00
for ( i = 0 ; i < count ; i + + )
2006-08-20 18:32:55 +00:00
{
file = fInfo -> files [ i ] ;
2006-09-03 17:06:43 +00:00
[ files addObject : [ NSDictionary dictionaryWithObjectsAndKeys :
[ [ self downloadFolder ] stringByAppendingPathComponent : [ NSString stringWithUTF8String : file . name ] ] , @ "Name" ,
2006-08-21 16:17:36 +00:00
[ NSNumber numberWithUnsignedLongLong : file . length ] , @ "Size" , nil ] ] ;
2006-08-20 18:32:55 +00:00
}
2006-07-16 19:39:23 +00:00
return files ;
}
- ( NSDate * ) date
{
return fDate ;
}
- ( NSNumber * ) stateSortKey
{
if ( ! [ self isActive ] )
return [ NSNumber numberWithInt : 0 ] ;
else if ( [ self isSeeding ] )
return [ NSNumber numberWithInt : 1 ] ;
else
return [ NSNumber numberWithInt : 2 ] ;
}
- ( NSNumber * ) progressSortKey
{
2006-07-18 23:40:37 +00:00
// if finished downloading sort by ratio instead of progress
float progress = [ self progress ] ;
return [ NSNumber numberWithFloat : progress < 1.0 ? progress : 2.0 + [ self ratio ] ] ;
2006-07-16 19:39:23 +00:00
}
@ end
@ implementation Torrent ( Private )
// if a hash is given , attempt to load that ; otherwise , attempt to open file at path
- ( id ) initWithHash : ( NSString * ) hashString path : ( NSString * ) path lib : ( tr_handle _t * ) lib
privateTorrent : ( NSNumber * ) privateTorrent publicTorrent : ( NSNumber * ) publicTorrent
date : ( NSDate * ) date stopRatioSetting : ( NSNumber * ) stopRatioSetting
ratioLimit : ( NSNumber * ) ratioLimit waitToStart : ( NSNumber * ) waitToStart
orderValue : ( NSNumber * ) orderValue
{
if ( ! ( self = [ super init ] ) )
return nil ;
fLib = lib ;
fDefaults = [ NSUserDefaults standardUserDefaults ] ;
fPrivateTorrent = privateTorrent ? [ privateTorrent boolValue ] : [ fDefaults boolForKey : @ "SavePrivateTorrent" ] ;
fPublicTorrent = ! fPrivateTorrent || ( publicTorrent ? [ publicTorrent boolValue ]
: ! [ fDefaults boolForKey : @ "DeleteOriginalTorrent" ] ) ;
int error ;
if ( fPrivateTorrent && hashString )
fHandle = tr_torrentInitSaved ( fLib , [ hashString UTF8String ] , TR_FSAVEPRIVATE , & error ) ;
if ( ! fHandle && path )
fHandle = tr_torrentInit ( fLib , [ path UTF8String ] , fPrivateTorrent ? TR_FSAVEPRIVATE : 0 , & error ) ;
if ( ! fHandle )
{
[ self release ] ;
return nil ;
}
fInfo = tr_torrentInfo ( fHandle ) ;
if ( fPublicTorrent )
fPublicTorrentLocation = [ path retain ] ;
fDate = date ? [ date retain ] : [ [ NSDate alloc ] init ] ;
fStopRatioSetting = stopRatioSetting ? [ stopRatioSetting intValue ] : -1 ;
fRatioLimit = ratioLimit ? [ ratioLimit floatValue ] : [ fDefaults floatForKey : @ "RatioLimit" ] ;
fFinishedSeeding = NO ;
2006-09-27 14:43:36 +00:00
fWaitToStart = waitToStart ? [ waitToStart boolValue ] : [ fDefaults boolForKey : @ "AutoStartDownload" ] ;
2006-07-16 19:39:23 +00:00
fOrderValue = orderValue ? [ orderValue intValue ] : tr_torrentCount ( fLib ) - 1 ;
2006-09-29 05:30:36 +00:00
fError = NO ;
2006-07-16 19:39:23 +00:00
NSString * fileType = fInfo -> multifile ? NSFileTypeForHFSTypeCode ( ' fldr ' ) : [ [ self name ] pathExtension ] ;
fIcon = [ [ NSWorkspace sharedWorkspace ] iconForFileType : fileType ] ;
[ fIcon retain ] ;
fIconFlipped = [ fIcon copy ] ;
[ fIconFlipped setFlipped : YES ] ;
fIconSmall = [ fIconFlipped copy ] ;
[ fIconSmall setScalesWhenResized : YES ] ;
[ fIconSmall setSize : NSMakeSize ( 16.0 , 16.0 ) ] ;
fProgressString = [ [ NSMutableString alloc ] initWithCapacity : 50 ] ;
fStatusString = [ [ NSMutableString alloc ] initWithCapacity : 75 ] ;
2006-07-25 00:59:14 +00:00
fShortStatusString = [ [ NSMutableString alloc ] initWithCapacity : 30 ] ;
fRemainingTimeString = [ [ NSMutableString alloc ] initWithCapacity : 30 ] ;
2006-10-05 21:21:30 +00:00
// set up advanced bar
fBitmap = [ [ NSBitmapImageRep alloc ] initWithBitmapDataPlanes : nil
pixelsWide : MAX_PIECES pixelsHigh : BAR_HEIGHT bitsPerSample : 8 samplesPerPixel : 4 hasAlpha : YES
isPlanar : NO colorSpaceName : NSCalibratedRGBColorSpace bytesPerRow : 0 bitsPerPixel : 0 ] ;
fPieces = malloc ( MAX_PIECES ) ;
int i ;
for ( i = 0 ; i < MAX_PIECES ; i + + )
fPieces [ i ] = BLANK_PIECE ;
2006-07-16 19:39:23 +00:00
[ self update ] ;
return self ;
}
2006-09-25 18:37:45 +00:00
- ( NSImage * ) advancedBar
{
int h , w ;
uint32_t * p ;
2006-10-05 21:21:30 +00:00
uint8_t * bitmapData = [ fBitmap bitmapData ] ;
int bytesPerRow = [ fBitmap bytesPerRow ] ;
2006-09-25 18:37:45 +00:00
2006-10-05 21:21:30 +00:00
int8_t * pieces = malloc ( MAX_PIECES ) ;
[ self getAvailability : pieces size : MAX_PIECES ] ;
2006-09-25 18:37:45 +00:00
2006-10-06 20:45:59 +00:00
// lines 2 to 14 : blue , green , or gray depending on whether we have the piece or not
2006-10-05 21:34:22 +00:00
int have = 0 , avail = 0 ;
2006-09-25 18:37:45 +00:00
uint32_t color ;
2006-10-05 21:21:30 +00:00
BOOL change ;
for ( w = 0 ; w < MAX_PIECES ; w + + )
2006-09-25 18:37:45 +00:00
{
2006-10-05 21:21:30 +00:00
change = NO ;
2006-09-25 18:37:45 +00:00
if ( pieces [ w ] < 0 )
2006-10-05 21:21:30 +00:00
{
if ( fPieces [ w ] ! = -1 )
{
2006-10-06 20:45:59 +00:00
color = kBlue ;
2006-10-05 21:21:30 +00:00
fPieces [ w ] = -1 ;
change = YES ;
}
2006-10-05 21:34:22 +00:00
have + + ;
2006-10-05 21:21:30 +00:00
}
2006-09-25 18:37:45 +00:00
else if ( pieces [ w ] = = 0 )
2006-10-05 21:21:30 +00:00
{
if ( fPieces [ w ] ! = 0 )
{
color = kGray ;
fPieces [ w ] = 0 ;
change = YES ;
}
}
2006-10-05 21:34:22 +00:00
else
2006-10-05 21:21:30 +00:00
{
2006-10-05 21:34:22 +00:00
if ( pieces [ w ] = = 1 )
2006-10-05 21:21:30 +00:00
{
2006-10-05 21:34:22 +00:00
if ( fPieces [ w ] ! = 1 )
{
2006-10-06 20:45:59 +00:00
color = kGreen1 ;
2006-10-05 21:34:22 +00:00
fPieces [ w ] = 1 ;
change = YES ;
}
2006-10-05 21:21:30 +00:00
}
2006-10-05 21:34:22 +00:00
else if ( pieces [ w ] = = 2 )
2006-10-05 21:21:30 +00:00
{
2006-10-05 21:34:22 +00:00
if ( fPieces [ w ] ! = 2 )
{
2006-10-06 20:45:59 +00:00
color = kGreen2 ;
2006-10-05 21:34:22 +00:00
fPieces [ w ] = 2 ;
change = YES ;
}
2006-10-05 21:21:30 +00:00
}
2006-10-05 21:34:22 +00:00
else
2006-10-05 21:21:30 +00:00
{
2006-10-05 21:34:22 +00:00
if ( fPieces [ w ] ! = 3 )
{
2006-10-06 20:45:59 +00:00
color = kGreen3 ;
2006-10-05 21:34:22 +00:00
fPieces [ w ] = 3 ;
change = YES ;
}
2006-10-05 21:21:30 +00:00
}
2006-10-05 21:34:22 +00:00
avail + + ;
2006-10-05 21:21:30 +00:00
}
2006-09-25 18:37:45 +00:00
2006-10-05 21:21:30 +00:00
if ( change )
2006-09-25 18:37:45 +00:00
{
2006-10-05 21:21:30 +00:00
// point to pixel ( w , 2 ) and draw "vertically"
p = ( uint32_t * ) ( bitmapData + 2 * bytesPerRow ) + w ;
for ( h = 2 ; h < BAR_HEIGHT ; h + + )
{
p [ 0 ] = color ;
p = ( uint32_t * ) ( ( uint8_t * ) p + bytesPerRow ) ;
}
2006-09-25 18:37:45 +00:00
}
}
2006-10-05 21:34:22 +00:00
// first two lines : dark blue to show progression , green to show available
p = ( uint32_t * ) bitmapData ;
for ( w = 0 ; w < have ; w + + )
{
2006-10-06 20:45:59 +00:00
p [ w ] = kBlue2 ;
p [ w + bytesPerRow / 4 ] = kBlue2 ;
2006-10-05 21:34:22 +00:00
}
for ( ; w < avail + have ; w + + )
{
2006-10-06 20:45:59 +00:00
p [ w ] = kGreen3 ;
p [ w + bytesPerRow / 4 ] = kGreen3 ;
2006-10-05 21:34:22 +00:00
}
for ( ; w < MAX_PIECES ; w + + )
{
p [ w ] = kWhite ;
p [ w + bytesPerRow / 4 ] = kWhite ;
}
2006-09-25 18:37:45 +00:00
free ( pieces ) ;
// actually draw image
2006-10-05 21:21:30 +00:00
NSImage * bar = [ [ NSImage alloc ] initWithSize : [ fBitmap size ] ] ;
[ bar addRepresentation : fBitmap ] ;
2006-09-25 18:37:45 +00:00
[ bar setScalesWhenResized : YES ] ;
return [ bar autorelease ] ;
}
2006-07-16 19:39:23 +00:00
- ( void ) trashFile : ( NSString * ) path
{
// attempt to move to trash
if ( ! [ [ NSWorkspace sharedWorkspace ] performFileOperation : NSWorkspaceRecycleOperation
source : [ path stringByDeletingLastPathComponent ] destination : @ ""
files : [ NSArray arrayWithObject : [ path lastPathComponent ] ] tag : nil ] )
{
// if cannot trash , just delete it ( will work if it is on a remote volume )
if ( ! [ [ NSFileManager defaultManager ] removeFileAtPath : path handler : nil ] )
NSLog ( [ @ "Could not trash " stringByAppendingString : path ] ) ;
}
}
@ end