diff --git a/cli/transmissioncli.c b/cli/transmissioncli.c index 3b080d747..66a3d2e27 100644 --- a/cli/transmissioncli.c +++ b/cli/transmissioncli.c @@ -109,7 +109,7 @@ int main( int argc, char ** argv ) h = tr_init(); /* Open and parse torrent file */ - if( !( tor = tr_torrentInit( h, torrentPath, &error ) ) ) + if( !( tor = tr_torrentInit( h, torrentPath, 0, &error ) ) ) { printf( "Failed opening torrent file `%s'\n", torrentPath ); goto failed; diff --git a/gtk/tr_torrent.c b/gtk/tr_torrent.c index aae1a1946..61cbb2440 100644 --- a/gtk/tr_torrent.c +++ b/gtk/tr_torrent.c @@ -270,7 +270,7 @@ tr_torrent_new(GObject *backend, const char *torrent, const char *dir, errcode = -1; handle = tr_torrentInit(tr_backend_handle(TR_BACKEND(backend)), - torrent, &errcode); + torrent, 0, &errcode); if(NULL == handle) { switch(errcode) { case TR_EINVALID: diff --git a/libtransmission/fastresume.h b/libtransmission/fastresume.h index bc03ed516..8e72bc953 100644 --- a/libtransmission/fastresume.h +++ b/libtransmission/fastresume.h @@ -63,17 +63,10 @@ static char * fastResumeFileName( tr_io_t * io ) { - char * ret, * p; - int i; + char * ret; - asprintf( &ret, "%s/resume.%40d", tr_getPrefsDirectory(), 0 ); - - p = &ret[ strlen( ret ) - 2 * SHA_DIGEST_LENGTH ]; - for( i = 0; i < SHA_DIGEST_LENGTH; i++ ) - { - sprintf( p, "%02x", io->tor->info.hash[i] ); - p += 2; - } + asprintf( &ret, "%s/resume.%s", tr_getCacheDirectory(), + io->tor->info.hashString ); return ret; } diff --git a/libtransmission/inout.c b/libtransmission/inout.c index 96051acac..3f3513af1 100644 --- a/libtransmission/inout.c +++ b/libtransmission/inout.c @@ -216,24 +216,15 @@ static int createFiles( tr_io_t * io ) asprintf( &path, "%s/%s", tor->destination, inf->files[i].name ); /* Create folders */ - p = path; - while( ( p = strchr( p, '/' ) ) ) + if( NULL != ( p = strrchr( path, '/' ) ) ) { *p = '\0'; - if( stat( path, &sb ) ) + if( tr_mkdir( path ) ) { - /* Folder doesn't exist yet */ - mkdir( path, 0777 ); - } - else if( ( sb.st_mode & S_IFMT ) != S_IFDIR ) - { - /* Node exists but isn't a folder */ - printf( "Remove %s, it's in the way.\n", path ); free( path ); return 1; } *p = '/'; - p++; } if( stat( path, &sb ) ) diff --git a/libtransmission/internal.h b/libtransmission/internal.h index 12ded06bf..1a954e56e 100644 --- a/libtransmission/internal.h +++ b/libtransmission/internal.h @@ -45,6 +45,7 @@ #include #include #include +#include #ifdef BEOS_NETSERVER # define in_port_t uint16_t #else diff --git a/libtransmission/metainfo.c b/libtransmission/metainfo.c index 26cc50321..57d788563 100644 --- a/libtransmission/metainfo.c +++ b/libtransmission/metainfo.c @@ -34,7 +34,8 @@ static void strcatUTF8( char *, char * ); *********************************************************************** * **********************************************************************/ -int tr_metainfoParse( tr_info_t * inf, const char * path ) +int tr_metainfoParse( tr_info_t * inf, const char * path, + const char * savedHash, int saveCopy ) { FILE * file; char * buf; @@ -43,7 +44,16 @@ int tr_metainfoParse( tr_info_t * inf, const char * path ) int i; struct stat sb; - snprintf( inf->torrent, MAX_PATH_LENGTH, "%s", path ); + assert( NULL == path || NULL == savedHash ); + /* if savedHash isn't null, saveCopy should be false */ + assert( NULL == savedHash || !saveCopy ); + + if ( NULL != savedHash ) + { + snprintf( inf->torrent, MAX_PATH_LENGTH, "%s/%s", + tr_getTorrentsDirectory(), savedHash ); + path = inf->torrent; + } if( stat( path, &sb ) ) { @@ -97,8 +107,41 @@ int tr_metainfoParse( tr_info_t * inf, const char * path ) } SHA1( (uint8_t *) beInfo->begin, (long) beInfo->end - (long) beInfo->begin, inf->hash ); + for( i = 0; i < SHA_DIGEST_LENGTH; i++ ) + { + sprintf( inf->hashString + i * 2, "%02x", inf->hash[i] ); + } - /* No that we got the hash, we won't need this anymore */ + if( saveCopy ) + { + /* Save a copy of the torrent file in the private torrent directory */ + snprintf( inf->torrent, MAX_PATH_LENGTH, "%s/%s", + tr_getTorrentsDirectory(), inf->hashString ); + file = fopen( inf->torrent, "wb" ); + if( !file ) + { + fprintf( stderr, "Could not open file (%s) (%s)\n", inf->torrent, strerror(errno) ); + tr_bencFree( &meta ); + free( buf ); + return 1; + } + fseek( file, 0, SEEK_SET ); + if( fwrite( buf, sb.st_size, 1, file ) != 1 ) + { + fprintf( stderr, "Write error (%s)\n", inf->torrent ); + tr_bencFree( &meta ); + free( buf ); + fclose( file ); + return 1; + } + fclose( file ); + } + else + { + snprintf( inf->torrent, MAX_PATH_LENGTH, "%s", path ); + } + + /* We won't need this anymore */ free( buf ); if( !( val = tr_bencDictFind( &meta, "announce" ) ) ) @@ -224,6 +267,15 @@ int tr_metainfoParse( tr_info_t * inf, const char * path ) return 0; } +void tr_metainfoRemoveSaved( const char * hashString ) +{ + char file[MAX_PATH_LENGTH]; + + snprintf( file, MAX_PATH_LENGTH, "%s/%s", + tr_getTorrentsDirectory(), hashString ); + unlink(file); +} + /*********************************************************************** * strcatUTF8 *********************************************************************** diff --git a/libtransmission/metainfo.h b/libtransmission/metainfo.h index aaf2bc5b9..f1ebc53de 100644 --- a/libtransmission/metainfo.h +++ b/libtransmission/metainfo.h @@ -25,6 +25,8 @@ #ifndef TR_METAINFO_H #define TR_METAINFO_H 1 -int tr_metainfoParse( tr_info_t *, const char * ); +int tr_metainfoParse( tr_info_t *, const char * path, + const char * savedHash, int saveCopy ); +void tr_metainfoRemoveSaved( const char * hashString ); #endif diff --git a/libtransmission/platform.c b/libtransmission/platform.c index 446cde7d5..ed1b36879 100644 --- a/libtransmission/platform.c +++ b/libtransmission/platform.c @@ -26,13 +26,38 @@ #include #include #endif -#ifdef SYS_DARWIN - #include - #include -#endif +#include +#include #include "transmission.h" +static void +tr_migrateResume( const char *oldDirectory, const char *newDirectory ) +{ + DIR * dirh; + struct dirent * dirp; + char oldFile[MAX_PATH_LENGTH]; + char newFile[MAX_PATH_LENGTH]; + + if( ( dirh = opendir( oldDirectory ) ) ) + { + while( ( dirp = readdir( dirh ) ) ) + { + if( strncmp( "resume.", dirp->d_name, 7 ) ) + { + continue; + } + snprintf( oldFile, MAX_PATH_LENGTH, "%s/%s", + oldDirectory, dirp->d_name ); + snprintf( newFile, MAX_PATH_LENGTH, "%s/%s", + newDirectory, dirp->d_name ); + rename( oldFile, newFile ); + } + + closedir( dirh ); + } +} + char * tr_getPrefsDirectory() { static char prefsDirectory[MAX_PATH_LENGTH]; @@ -55,41 +80,82 @@ char * tr_getPrefsDirectory() getenv( "HOME" ) ); #endif - mkdir( prefsDirectory, 0755 ); + tr_mkdir( prefsDirectory ); init = 1; #ifdef SYS_DARWIN - DIR * dirh; - struct dirent * dirp; char oldDirectory[MAX_PATH_LENGTH]; - char oldFile[MAX_PATH_LENGTH]; - char newFile[MAX_PATH_LENGTH]; snprintf( oldDirectory, MAX_PATH_LENGTH, "%s/.transmission", getenv( "HOME" ) ); - if( ( dirh = opendir( oldDirectory ) ) ) - { - while( ( dirp = readdir( dirh ) ) ) - { - if( !strcmp( ".", dirp->d_name ) || - !strcmp( "..", dirp->d_name ) ) - { - continue; - } - snprintf( oldFile, MAX_PATH_LENGTH, "%s/%s", - oldDirectory, dirp->d_name ); - snprintf( newFile, MAX_PATH_LENGTH, "%s/%s", - prefsDirectory, dirp->d_name ); - rename( oldFile, newFile ); - } - - closedir( dirh ); - rmdir( oldDirectory ); - } + tr_migrateResume( oldDirectory, prefsDirectory ); + rmdir( oldDirectory ); #endif return prefsDirectory; } +char * tr_getCacheDirectory() +{ + static char cacheDirectory[MAX_PATH_LENGTH]; + static int init = 0; + + if( init ) + { + return cacheDirectory; + } + +#ifdef SYS_BEOS + /* XXX hey Bryan, is this fine with you? */ + snprintf( cacheDirectory, MAX_PATH_LENGTH, "%s/Cache", + tr_getPrefsDirectory() ); +#elif defined( SYS_DARWIN ) + snprintf( cacheDirectory, MAX_PATH_LENGTH, "%s", + tr_getPrefsDirectory() ); +#else + snprintf( cacheDirectory, MAX_PATH_LENGTH, "%s/cache", + tr_getPrefsDirectory() ); +#endif + + tr_mkdir( cacheDirectory ); + init = 1; + + if( strcmp( tr_getPrefsDirectory(), cacheDirectory ) ) + { + tr_migrateResume( tr_getPrefsDirectory(), cacheDirectory ); + } + + return cacheDirectory; +} + +char * tr_getTorrentsDirectory() +{ + static char torrentsDirectory[MAX_PATH_LENGTH]; + static int init = 0; + + if( init ) + { + return torrentsDirectory; + } + +#ifdef SYS_BEOS + /* XXX hey Bryan, is this fine with you? */ + snprintf( torrentsDirectory, MAX_PATH_LENGTH, "%s/Torrents", + tr_getPrefsDirectory() ); +#elif defined( SYS_DARWIN ) + snprintf( torrentsDirectory, MAX_PATH_LENGTH, + "%s/Library/Application Support/Transmission/Torrents", + getenv( "HOME" ) ); +#else + snprintf( torrentsDirectory, MAX_PATH_LENGTH, "%s/torrents", + tr_getPrefsDirectory() ); +#endif + + tr_mkdir( torrentsDirectory ); + init = 1; + + return torrentsDirectory; +} + void tr_threadCreate( tr_thread_t * t, void (*func)(void *), void * arg ) { #ifdef SYS_BEOS diff --git a/libtransmission/platform.h b/libtransmission/platform.h index 01d298986..83fc77ddb 100644 --- a/libtransmission/platform.h +++ b/libtransmission/platform.h @@ -34,6 +34,9 @@ typedef pthread_mutex_t tr_lock_t; #endif +char * tr_getCacheDirectory(); +char * tr_getTorrentsDirectory(); + void tr_threadCreate ( tr_thread_t *, void (*func)(void *), void * arg ); void tr_threadJoin ( tr_thread_t * ); void tr_lockInit ( tr_lock_t * ); diff --git a/libtransmission/transmission.c b/libtransmission/transmission.c index 4892aefc6..e46443402 100644 --- a/libtransmission/transmission.c +++ b/libtransmission/transmission.c @@ -27,6 +27,8 @@ /*********************************************************************** * Local prototypes **********************************************************************/ +static tr_torrent_t * torrentRealInit( tr_handle_t *, tr_torrent_t * tor, + int flags, int * error ); static void torrentReallyStop( tr_torrent_t * ); static void downloadLoop( void * ); static void acceptLoop( void * ); @@ -174,30 +176,55 @@ void tr_torrentRates( tr_handle_t * h, float * dl, float * ul ) } } +tr_torrent_t * tr_torrentInit( tr_handle_t * h, const char * path, + int flags, int * error ) +{ + tr_torrent_t * tor = calloc( sizeof( tr_torrent_t ), 1 ); + int saveCopy = ( TR_FSAVEPRIVATE & flags ); + + /* Parse torrent file */ + if( tr_metainfoParse( &tor->info, path, NULL, saveCopy ) ) + { + *error = TR_EINVALID; + free( tor ); + return NULL; + } + + return torrentRealInit( h, tor, flags, error ); +} + +tr_torrent_t * tr_torrentInitSaved( tr_handle_t * h, const char * hashStr, + int flags, int * error ) +{ + tr_torrent_t * tor = calloc( sizeof( tr_torrent_t ), 1 ); + + /* Parse torrent file */ + if( tr_metainfoParse( &tor->info, NULL, hashStr, 0 ) ) + { + *error = TR_EINVALID; + free( tor ); + return NULL; + } + + return torrentRealInit( h, tor, ( TR_FSAVEPRIVATE | flags ), error ); +} + /*********************************************************************** * tr_torrentInit *********************************************************************** * Allocates a tr_torrent_t structure, then relies on tr_metainfoParse * to fill it. **********************************************************************/ -tr_torrent_t * tr_torrentInit( tr_handle_t * h, const char * path, - int * error ) +static tr_torrent_t * torrentRealInit( tr_handle_t * h, tr_torrent_t * tor, + int flags, int * error ) { - tr_torrent_t * tor, * tor_tmp; + tr_torrent_t * tor_tmp; tr_info_t * inf; int i; char * s1, * s2; - tor = calloc( sizeof( tr_torrent_t ), 1 ); - inf = &tor->info; - - /* Parse torrent file */ - if( tr_metainfoParse( inf, path ) ) - { - *error = TR_EINVALID; - free( tor ); - return NULL; - } + inf = &tor->info; + inf->flags = flags; /* Make sure this torrent is not already open */ for( tor_tmp = h->torrentList; tor_tmp; tor_tmp = tor_tmp->next ) @@ -481,6 +508,10 @@ void tr_torrentAvailability( tr_torrent_t * tor, int8_t * tab, int size ) tr_lockUnlock( &tor->lock ); } +void tr_torrentRemoveSaved( tr_torrent_t * tor ) { + tr_metainfoRemoveSaved( tor->info.hashString ); +} + /*********************************************************************** * tr_torrentClose *********************************************************************** diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 4a1c6df18..d97e5f000 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -59,9 +59,8 @@ tr_handle_t * tr_init(); /*********************************************************************** * tr_getPrefsDirectory *********************************************************************** - * Returns the full path to the directory used by libtransmission to - * store the resume files. The string belongs to libtransmission, do - * not free it. + * Returns the full path to a directory which can be used to store + * preferences. The string belongs to libtransmission, do not free it. **********************************************************************/ char * tr_getPrefsDirectory(); @@ -123,14 +122,25 @@ void tr_close( tr_handle_t * ); * Opens and parses torrent file at 'path'. If the file exists and is a * valid torrent file, returns an handle and adds it to the list of * torrents (but doesn't start it). Returns NULL and sets *error - * otherwise. + * otherwise. If the TR_FSAVEPRIVATE flag is passed then a private copy + * of the torrent file will be saved. **********************************************************************/ #define TR_EINVALID 1 #define TR_EUNSUPPORTED 2 #define TR_EDUPLICATE 3 #define TR_EOTHER 666 tr_torrent_t * tr_torrentInit( tr_handle_t *, const char * path, - int * error ); + int flags, int * error ); + +/*********************************************************************** + * tr_torrentInitSaved + *********************************************************************** + * Opens and parses a torrent file as with tr_torrentInit, only taking + * the hash string of a saved torrent file instead of a filename. There + * are currently no valid flags for this function. + **********************************************************************/ +tr_torrent_t * tr_torrentInitSaved( tr_handle_t *, const char * hashStr, + int flags, int * error ); typedef struct tr_info_s tr_info_t; tr_info_t * tr_torrentInfo( tr_torrent_t * ); @@ -200,6 +210,14 @@ tr_stat_t * tr_torrentStat( tr_torrent_t * ); **********************************************************************/ void tr_torrentAvailability( tr_torrent_t *, int8_t * tab, int size ); +/*********************************************************************** + * tr_torrentRemoveSaved + *********************************************************************** + * Removes the private saved copy of a torrent file for torrents which + * the TR_FSAVEPRIVATE flag is set. + **********************************************************************/ +void tr_torrentRemoveSaved( tr_torrent_t * ); + /*********************************************************************** * tr_torrentClose *********************************************************************** @@ -208,7 +226,6 @@ void tr_torrentAvailability( tr_torrent_t *, int8_t * tab, int size ); **********************************************************************/ void tr_torrentClose( tr_handle_t *, tr_torrent_t * ); - /*********************************************************************** * tr_info_s **********************************************************************/ @@ -225,8 +242,13 @@ struct tr_info_s /* General info */ uint8_t hash[SHA_DIGEST_LENGTH]; + char hashString[2*SHA_DIGEST_LENGTH+1]; char name[MAX_PATH_LENGTH]; + /* Flags */ +#define TR_FSAVEPRIVATE 0x01 /* save a private copy of the torrent */ + int flags; + /* Tracker info */ char trackerAddress[256]; int trackerPort; diff --git a/libtransmission/utils.c b/libtransmission/utils.c index b50a9bb8b..caa3e1b17 100644 --- a/libtransmission/utils.c +++ b/libtransmission/utils.c @@ -93,3 +93,54 @@ void * tr_memmem( const void *vbig, size_t big_len, return NULL; } + +int tr_mkdir( char * path ) +{ + char * p, * pp; + struct stat sb; + int done; + + p = path; + while( '/' == *p ) + p++; + pp = p; + done = 0; + while( ( p = strchr( pp, '/' ) ) || ( p = strchr( pp, '\0' ) ) ) + { + if( '\0' == *p) + { + done = 1; + } + else + { + *p = '\0'; + } + if( stat( path, &sb ) ) + { + /* Folder doesn't exist yet */ + if( mkdir( path, 0777 ) ) + { + tr_err( "Could not create directory %s (%s)", path, + strerror( errno ) ); + *p = '/'; + return 1; + } + } + else if( ( sb.st_mode & S_IFMT ) != S_IFDIR ) + { + /* Node exists but isn't a folder */ + tr_err( "Remove %s, it's in the way.", path ); + *p = '/'; + return 1; + } + if( done ) + { + break; + } + *p = '/'; + p++; + pp = p; + } + + return 0; +} diff --git a/libtransmission/utils.h b/libtransmission/utils.h index 9196b291b..0d162bf45 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -37,6 +37,14 @@ int tr_rand ( int ); void * tr_memmem( const void *, size_t, const void *, size_t ); +/*********************************************************************** + * tr_mkdir + *********************************************************************** + * Create a directory and any needed parent directories. + * Note that the string passed in must be writable! + **********************************************************************/ +int tr_mkdir( char * path ); + /*********************************************************************** * tr_date *********************************************************************** diff --git a/macosx/Controller.h b/macosx/Controller.h index 9d7fd2081..1928b2562 100644 --- a/macosx/Controller.h +++ b/macosx/Controller.h @@ -96,17 +96,13 @@ - (void) stopTorrentWithIndex: (NSIndexSet *) indexSet; - (void) removeTorrent: (id) sender; -- (void) removeTorrentDeleteTorrent: (id) sender; - (void) removeTorrentDeleteData: (id) sender; -- (void) removeTorrentDeleteBoth: (id) sender; - (void) removeTorrentWithIndex: (NSIndexSet *) indexSet - deleteTorrent: (BOOL) deleteTorrent deleteData: (BOOL) deleteData; - (void) removeSheetDidEnd: (NSWindow *) sheet returnCode: (int) returnCode contextInfo: (NSDictionary *) dict; - (void) confirmRemoveTorrents: (NSArray *) torrents - deleteTorrent: (BOOL) deleteTorrent deleteData: (BOOL) deleteData; - (void) revealFile: (id) sender; diff --git a/macosx/Controller.m b/macosx/Controller.m index aed5b3e7c..448c5730f 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -524,7 +524,6 @@ static void sleepCallBack( void * controller, io_service_t y, } - (void) removeTorrentWithIndex: (NSIndexSet *) indexSet - deleteTorrent: (BOOL) deleteTorrent deleteData: (BOOL) deleteData { NSArray * torrents = [[self torrentsAtIndexes: indexSet] retain]; @@ -540,7 +539,6 @@ static void sleepCallBack( void * controller, io_service_t y, { NSDictionary * dict = [[NSDictionary alloc] initWithObjectsAndKeys: torrents, @"Torrents", - [NSNumber numberWithBool: deleteTorrent], @"DeleteTorrent", [NSNumber numberWithBool: deleteData], @"DeleteData", nil]; @@ -551,17 +549,22 @@ static void sleepCallBack( void * controller, io_service_t y, { title = [NSString stringWithFormat: @"Comfirm Removal of \"%@\"", [[fTorrents objectAtIndex: [fTableView selectedRow]] name]]; - message = @"This torrent is active. Do you really want to remove it?"; + message = @"This transfer is active." + " Onced removed, continuing the transfer will require the torrent file." + " Do you really want to remove it?"; } else { title = [NSString stringWithFormat: @"Comfirm Removal of %d Torrents", selected]; if (selected == active) message = [NSString stringWithFormat: - @"There are %d active torrents. Do you really want to remove them?", active]; + @"There are %d active transfers.", active]; else message = [NSString stringWithFormat: - @"There are %d torrents (%d active). Do you really want to remove them?", selected, active]; + @"There are %d transfers (%d active).", selected, active]; + message = [message stringByAppendingString: + @" Onced removed, continuing the transfers will require the torrent files." + " Do you really want to remove them?"]; } NSBeginAlertSheet(title, @@ -572,7 +575,6 @@ static void sleepCallBack( void * controller, io_service_t y, else { [self confirmRemoveTorrents: torrents - deleteTorrent: deleteTorrent deleteData: deleteData]; } } @@ -583,14 +585,12 @@ static void sleepCallBack( void * controller, io_service_t y, [NSApp stopModal]; NSArray * torrents = [dict objectForKey: @"Torrents"]; - BOOL deleteTorrent = [[dict objectForKey: @"DeleteTorrent"] boolValue]; BOOL deleteData = [[dict objectForKey: @"DeleteData"] boolValue]; [dict release]; if (returnCode == NSAlertDefaultReturn) { [self confirmRemoveTorrents: torrents - deleteTorrent: deleteTorrent deleteData: deleteData]; } else @@ -598,7 +598,6 @@ static void sleepCallBack( void * controller, io_service_t y, } - (void) confirmRemoveTorrents: (NSArray *) torrents - deleteTorrent: (BOOL) deleteTorrent deleteData: (BOOL) deleteData { Torrent * torrent; @@ -609,10 +608,8 @@ static void sleepCallBack( void * controller, io_service_t y, if( deleteData ) [torrent trashData]; - - if( deleteTorrent ) - [torrent trashTorrent]; + [torrent removeForever]; [fTorrents removeObject: torrent]; } [torrents release]; @@ -625,22 +622,12 @@ static void sleepCallBack( void * controller, io_service_t y, - (void) removeTorrent: (id) sender { - [self removeTorrentWithIndex: [fTableView selectedRowIndexes] deleteTorrent: NO deleteData: NO]; -} - -- (void) removeTorrentDeleteTorrent: (id) sender -{ - [self removeTorrentWithIndex: [fTableView selectedRowIndexes] deleteTorrent: YES deleteData: NO]; + [self removeTorrentWithIndex: [fTableView selectedRowIndexes] deleteData: NO]; } - (void) removeTorrentDeleteData: (id) sender { - [self removeTorrentWithIndex: [fTableView selectedRowIndexes] deleteTorrent: NO deleteData: YES]; -} - -- (void) removeTorrentDeleteBoth: (id) sender -{ - [self removeTorrentWithIndex: [fTableView selectedRowIndexes] deleteTorrent: YES deleteData: YES]; + [self removeTorrentWithIndex: [fTableView selectedRowIndexes] deleteData: YES]; } - (void) revealFile: (id) sender @@ -1207,10 +1194,7 @@ static void sleepCallBack( void * controller, io_service_t y, } //enable remove items - if (action == @selector(removeTorrent:) - || action == @selector(removeTorrentDeleteTorrent:) - || action == @selector(removeTorrentDeleteData:) - || action == @selector(removeTorrentDeleteBoth:)) + if (action == @selector(removeTorrent:) || action == @selector(removeTorrentDeleteData:)) { BOOL active = NO; Torrent * torrent; diff --git a/macosx/Defaults.plist b/macosx/Defaults.plist index 140655d71..5f76db5cd 100644 --- a/macosx/Defaults.plist +++ b/macosx/Defaults.plist @@ -18,6 +18,8 @@ CheckUpload + DeleteOriginalTorrent + DownloadChoice Constant DownloadFolder @@ -40,6 +42,8 @@ 2 SUScheduledCheckInterval 86400 + SavePrivateTorrent + ShowInspector Sort diff --git a/macosx/English.lproj/MainMenu.nib/classes.nib b/macosx/English.lproj/MainMenu.nib/classes.nib index 9eb5b01d3..5b0cdc51c 100644 --- a/macosx/English.lproj/MainMenu.nib/classes.nib +++ b/macosx/English.lproj/MainMenu.nib/classes.nib @@ -9,9 +9,7 @@ linkHomepage = id; openShowSheet = id; removeTorrent = id; - removeTorrentDeleteBoth = id; removeTorrentDeleteData = id; - removeTorrentDeleteTorrent = id; resumeAllTorrents = id; resumeTorrent = id; revealFile = id; diff --git a/macosx/English.lproj/MainMenu.nib/info.nib b/macosx/English.lproj/MainMenu.nib/info.nib index faf0de790..60c977211 100644 --- a/macosx/English.lproj/MainMenu.nib/info.nib +++ b/macosx/English.lproj/MainMenu.nib/info.nib @@ -9,11 +9,11 @@ 1041 344 478 208 99 0 0 1152 842 1480 - 366 548 420 60 0 0 1152 842 + 423 269 420 60 0 0 1152 842 29 - 154 771 451 44 0 0 1152 842 + 195 519 451 44 0 0 1152 842 456 - 212 488 144 137 0 0 1152 842 + 212 488 153 168 0 0 1152 842 581 324 628 112 68 0 0 1152 842 589 @@ -30,7 +30,6 @@ IBOpenObjects 21 - 1480 IBSystem Version 8I127 diff --git a/macosx/English.lproj/MainMenu.nib/keyedobjects.nib b/macosx/English.lproj/MainMenu.nib/keyedobjects.nib index 6b289e585..82cc2b94a 100644 Binary files a/macosx/English.lproj/MainMenu.nib/keyedobjects.nib and b/macosx/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/macosx/English.lproj/PrefsWindow.nib/classes.nib b/macosx/English.lproj/PrefsWindow.nib/classes.nib index 6971eea4c..864556480 100644 --- a/macosx/English.lproj/PrefsWindow.nib/classes.nib +++ b/macosx/English.lproj/PrefsWindow.nib/classes.nib @@ -10,6 +10,7 @@ setDownloadLocation = id; setLimit = id; setLimitCheck = id; + setMoveTorrent = id; setPort = id; setRatio = id; setRatioCheck = id; @@ -22,6 +23,8 @@ fAutoStartCheck = NSButton; fBadgeDownloadRateCheck = NSButton; fBadgeUploadRateCheck = NSButton; + fCopyTorrentCheck = NSButton; + fDeleteOriginalTorrentCheck = NSButton; fDownloadCheck = NSButton; fDownloadField = NSTextField; fFolderPopUp = NSPopUpButton; diff --git a/macosx/English.lproj/PrefsWindow.nib/info.nib b/macosx/English.lproj/PrefsWindow.nib/info.nib index 2cada2dda..7d6331bed 100644 --- a/macosx/English.lproj/PrefsWindow.nib/info.nib +++ b/macosx/English.lproj/PrefsWindow.nib/info.nib @@ -7,14 +7,18 @@ IBEditorPositions 28 - 347 472 462 212 0 0 1152 842 + 345 472 462 212 0 0 1152 842 41 - 345 461 462 234 0 0 1152 842 + 345 423 462 310 0 0 1152 842 66 347 526 462 104 0 0 1152 842 IBFramework Version 446.1 + IBOpenObjects + + 41 + IBSystem Version 8I127 diff --git a/macosx/English.lproj/PrefsWindow.nib/keyedobjects.nib b/macosx/English.lproj/PrefsWindow.nib/keyedobjects.nib index 6d2dfa957..b8ee8a903 100644 Binary files a/macosx/English.lproj/PrefsWindow.nib/keyedobjects.nib and b/macosx/English.lproj/PrefsWindow.nib/keyedobjects.nib differ diff --git a/macosx/PrefsController.h b/macosx/PrefsController.h index 141207200..c185975ce 100644 --- a/macosx/PrefsController.h +++ b/macosx/PrefsController.h @@ -36,7 +36,7 @@ IBOutlet NSPopUpButton * fFolderPopUp; IBOutlet NSButton * fQuitCheck, * fRemoveCheck, * fBadgeDownloadRateCheck, * fBadgeUploadRateCheck, - * fAutoStartCheck; + * fAutoStartCheck, * fCopyTorrentCheck, * fDeleteOriginalTorrentCheck; IBOutlet NSPopUpButton * fUpdatePopUp; IBOutlet NSTextField * fPortField, * fUploadField, * fDownloadField; @@ -58,6 +58,7 @@ - (void) setUpdate: (id) sender; - (void) checkUpdate; - (void) setAutoStart: (id) sender; +- (void) setMoveTorrent: (id) sender; - (void) setDownloadLocation: (id) sender; - (void) folderSheetShow: (id) sender; diff --git a/macosx/PrefsController.m b/macosx/PrefsController.m index 10bf7c5d7..83249b922 100644 --- a/macosx/PrefsController.m +++ b/macosx/PrefsController.m @@ -116,7 +116,7 @@ BOOL checkUpload = [fDefaults boolForKey: @"CheckUpload"]; int uploadLimit = [fDefaults integerForKey: @"UploadLimit"]; - [fUploadCheck setState: checkUpload ? NSOnState : NSOffState]; + [fUploadCheck setState: checkUpload]; [fUploadField setIntValue: uploadLimit]; [fUploadField setEnabled: checkUpload]; @@ -126,7 +126,7 @@ BOOL checkDownload = [fDefaults boolForKey: @"CheckDownload"]; int downloadLimit = [fDefaults integerForKey: @"DownloadLimit"]; - [fDownloadCheck setState: checkDownload ? NSOnState : NSOffState]; + [fDownloadCheck setState: checkDownload]; [fDownloadField setIntValue: downloadLimit]; [fDownloadField setEnabled: checkDownload]; @@ -134,15 +134,13 @@ //set ratio limit BOOL ratioCheck = [fDefaults boolForKey: @"RatioCheck"]; - [fRatioCheck setState: ratioCheck ? NSOnState : NSOffState]; + [fRatioCheck setState: ratioCheck]; [fRatioField setEnabled: ratioCheck]; [fRatioField setFloatValue: [fDefaults floatForKey: @"RatioLimit"]]; //set remove and quit prompts - [fQuitCheck setState: [fDefaults boolForKey: @"CheckQuit"] ? - NSOnState : NSOffState]; - [fRemoveCheck setState: [fDefaults boolForKey: @"CheckRemove"] ? - NSOnState : NSOffState]; + [fQuitCheck setState: [fDefaults boolForKey: @"CheckQuit"]]; + [fRemoveCheck setState: [fDefaults boolForKey: @"CheckRemove"]]; //set dock badging [fBadgeDownloadRateCheck setState: [fDefaults boolForKey: @"BadgeDownloadRate"]]; @@ -150,6 +148,13 @@ //set auto start [fAutoStartCheck setState: [fDefaults boolForKey: @"AutoStartDownload"]]; + + //set private torrents + BOOL copyTorrents = [fDefaults boolForKey: @"SavePrivateTorrent"]; + [fCopyTorrentCheck setState: copyTorrents]; + + [fDeleteOriginalTorrentCheck setEnabled: copyTorrents]; + [fDeleteOriginalTorrentCheck setState: [fDefaults boolForKey: @"DeleteOriginalTorrent"]]; //set update check NSString * updateCheck = [fDefaults stringForKey: @"UpdateCheck"]; @@ -419,6 +424,24 @@ [fDefaults setBool: [sender state] forKey: @"AutoStartDownload"]; } +- (void) setMoveTorrent: (id) sender +{ + int state = [sender state]; + if (sender == fCopyTorrentCheck) + { + [fDefaults setBool: state forKey: @"SavePrivateTorrent"]; + + [fDeleteOriginalTorrentCheck setEnabled: state]; + if (state == NSOffState) + { + [fDeleteOriginalTorrentCheck setState: NSOffState]; + [fDefaults setBool: NO forKey: @"DeleteOriginalTorrent"]; + } + } + else + [fDefaults setBool: state forKey: @"DeleteOriginalTorrent"]; +} + - (void) setDownloadLocation: (id) sender { //Download folder diff --git a/macosx/Torrent.h b/macosx/Torrent.h index 2a0aa7f59..0026b2888 100644 --- a/macosx/Torrent.h +++ b/macosx/Torrent.h @@ -35,8 +35,11 @@ tr_torrent_t * fHandle; tr_info_t * fInfo; tr_stat_t * fStat; + BOOL fResumeOnWake; NSDate * fDate; + + BOOL fPrivateTorrent; NSUserDefaults * fDefaults; @@ -55,11 +58,12 @@ - (NSString *) downloadFolder; - (void) getAvailability: (int8_t *) tab size: (int) size; -- (void) update; -- (void) start; -- (void) stop; -- (void) sleep; -- (void) wakeUp; +- (void) update; +- (void) start; +- (void) stop; +- (void) removeForever; +- (void) sleep; +- (void) wakeUp; - (float) ratio; - (int) stopRatioSetting; @@ -68,7 +72,6 @@ - (void) setRatioLimit: (float) limit; - (void) reveal; -- (void) trashTorrent; - (void) trashData; - (NSImage *) icon; diff --git a/macosx/Torrent.m b/macosx/Torrent.m index d028cbb4c..6476122ef 100644 --- a/macosx/Torrent.m +++ b/macosx/Torrent.m @@ -28,9 +28,14 @@ @interface Torrent (Private) -- (void) trashPath: (NSString *) path; - (id) initWithPath: (NSString *) path lib: (tr_handle_t *) lib date: (NSDate *) date stopRatioSetting: (NSNumber *) stopRatioSetting ratioLimit: (NSNumber *) ratioLimit; +- (id) initWithHash: (NSString *) hashString lib: (tr_handle_t *) lib date: (NSDate *) date + stopRatioSetting: (NSNumber *) stopRatioSetting ratioLimit: (NSNumber *) ratioLimit; +- (id) initForSuccessWithDate: (NSDate *) date stopRatioSetting: (NSNumber *) + stopRatioSetting ratioLimit: (NSNumber *) ratioLimit; + +- (void) trashPath: (NSString *) path; @end @@ -39,14 +44,29 @@ - (id) initWithPath: (NSString *) path lib: (tr_handle_t *) lib { - return [self initWithPath: path lib: lib - date: nil stopRatioSetting: nil - ratioLimit: nil]; + id torrent = [self initWithPath: path lib: lib date: nil + stopRatioSetting: nil ratioLimit: nil]; + + if (!torrent) + return nil; + + if (fPrivateTorrent && [fDefaults boolForKey: @"DeleteOriginalTorrent"]) + [self trashPath: path]; + + return torrent; } - (id) initWithHistory: (NSDictionary *) history lib: (tr_handle_t *) lib { - self = [self initWithPath: [history objectForKey: @"TorrentPath"] + //load from saved torrent file if set to, otherwise try to load from where torrent file should be + NSNumber * privateCopy; + if ((privateCopy = [history objectForKey: @"PrivateCopy"]) && [privateCopy boolValue]) + self = [self initWithHash: [history objectForKey: @"TorrentHash"] + lib: lib date: [history objectForKey: @"Date"] + stopRatioSetting: [history objectForKey: @"StopRatioSetting"] + ratioLimit: [history objectForKey: @"RatioLimit"]]; + else + self = [self initWithPath: [history objectForKey: @"TorrentPath"] lib: lib date: [history objectForKey: @"Date"] stopRatioSetting: [history objectForKey: @"StopRatioSetting"] ratioLimit: [history objectForKey: @"RatioLimit"]]; @@ -68,13 +88,20 @@ - (NSDictionary *) history { - return [NSDictionary dictionaryWithObjectsAndKeys: - [self torrentLocation], @"TorrentPath", - [self downloadFolder], @"DownloadFolder", - [self isActive] ? @"NO" : @"YES", @"Paused", - [self date], @"Date", - [NSNumber numberWithInt: fStopRatioSetting], @"StopRatioSetting", - [NSNumber numberWithFloat: fRatioLimit], @"RatioLimit", nil]; + NSMutableDictionary * history = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool: fPrivateTorrent], @"PrivateCopy", + [self downloadFolder], @"DownloadFolder", + [self isActive] ? @"NO" : @"YES", @"Paused", + [self date], @"Date", + [NSNumber numberWithInt: fStopRatioSetting], @"StopRatioSetting", + [NSNumber numberWithFloat: fRatioLimit], @"RatioLimit", nil]; + + if (fPrivateTorrent) + [history setObject: [self hashString] forKey: @"TorrentHash"]; + else + [history setObject: [self torrentLocation] forKey: @"TorrentPath"]; + + return history; } - (void) dealloc @@ -127,7 +154,7 @@ [fProgressString setString: @""]; if ([self progress] < 1.0) - [fProgressString appendFormat: @"%@ of %@ completed (%.2f%%)", [NSString stringForFileSize: + [fProgressString appendFormat: @"%@ of %@ (%.2f%%)", [NSString stringForFileSize: [self downloaded]], [NSString stringForFileSize: [self size]], 100 * [self progress]]; else [fProgressString appendFormat: @"%@, uploaded %@ (ratio: %@)", [NSString stringForFileSize: @@ -212,6 +239,12 @@ } } +- (void) removeForever +{ + if (fInfo->flags & TR_FSAVEPRIVATE) + tr_torrentRemoveSaved(fHandle); +} + - (void) sleep { if( ( fResumeOnWake = ( fStat->status & TR_STATUS_ACTIVE ) ) ) @@ -261,11 +294,6 @@ inFileViewerRootedAtPath: nil]; } -- (void) trashTorrent -{ - [self trashPath: [self torrentLocation]]; -} - - (void) trashData { [self trashPath: [self dataLocation]]; @@ -314,19 +342,12 @@ - (NSString *) hashString { - NSMutableString * string = [NSMutableString - stringWithCapacity: SHA_DIGEST_LENGTH]; - int i; - for( i = 0; i < SHA_DIGEST_LENGTH; i++ ) - { - [string appendFormat: @"%02x", fInfo->hash[i]]; - } - return string; + return [NSString stringWithUTF8String: fInfo->hashString]; } - (NSString *) torrentLocation { - return [NSString stringWithUTF8String: fInfo->torrent];; + return [NSString stringWithUTF8String: fInfo->torrent]; } - (NSString *) dataLocation @@ -487,17 +508,46 @@ return nil; fLib = lib; + fDefaults = [NSUserDefaults standardUserDefaults]; + + fPrivateTorrent = [fDefaults boolForKey: @"SavePrivateTorrent"]; int error; - if (!path || !(fHandle = tr_torrentInit(fLib, [path UTF8String], &error))) + if (!path || !(fHandle = tr_torrentInit(fLib, [path UTF8String], + fPrivateTorrent ? TR_FSAVEPRIVATE : 0, & error))) + { + [self release]; + return nil; + } + + return [self initForSuccessWithDate: date stopRatioSetting: stopRatioSetting ratioLimit: ratioLimit]; +} + +- (id) initWithHash: (NSString *) hashString lib: (tr_handle_t *) lib date: (NSDate *) date + stopRatioSetting: (NSNumber *) stopRatioSetting ratioLimit: (NSNumber *) ratioLimit +{ + if (!(self = [super init])) + return nil; + + fLib = lib; + fDefaults = [NSUserDefaults standardUserDefaults]; + + fPrivateTorrent = YES; + + int error; + if (!hashString || !(fHandle = tr_torrentInitSaved(fLib, [hashString UTF8String], TR_FSAVEPRIVATE, & error))) { [self release]; return nil; } + return [self initForSuccessWithDate: date stopRatioSetting: stopRatioSetting ratioLimit: ratioLimit]; +} + +- (id) initForSuccessWithDate: (NSDate *) date stopRatioSetting: (NSNumber *) + stopRatioSetting ratioLimit: (NSNumber *) ratioLimit +{ fInfo = tr_torrentInfo( fHandle ); - - fDefaults = [NSUserDefaults standardUserDefaults]; fDate = date ? [date retain] : [[NSDate alloc] init]; fStopRatioSetting = stopRatioSetting ? [stopRatioSetting intValue] : -1; @@ -518,6 +568,7 @@ return self; } + - (void) trashPath: (NSString *) path { if( ![[NSWorkspace sharedWorkspace] performFileOperation: