add the beginnings of ipc to the mac front end

This commit is contained in:
Mitchell Livingston
2007-05-28 02:27:13 +00:00
parent f156e2bf27
commit b679945ea6
11 changed files with 1189 additions and 9 deletions

View File

@@ -1430,8 +1430,10 @@
GCC_WARN_UNUSED_VARIABLE = NO;
MACOSX_DEPLOYMENT_TARGET_i386 = 10.4;
MACOSX_DEPLOYMENT_TARGET_ppc = 10.4;
OTHER_CFLAGS = "$(inherited)";
PREBINDING = NO;
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
ZERO_LINK = NO;
};
name = Debug;
};

View File

@@ -76,26 +76,26 @@ pushdir( char * path, const char * file, size_t size )
void
confpath( char * buf, size_t len, const char * file, enum confpathtype type )
{
const char * typestr;
strlcpy( buf, tr_getPrefsDirectory(), len );
switch( type )
{
case CONF_PATH_TYPE_DAEMON:
typestr = "daemon";
pushdir( buf, "daemon", len );
break;
case CONF_PATH_TYPE_GTK:
typestr = "gtk";
pushdir( buf, "gtk", len );
break;
case CONF_PATH_TYPE_OSX:
break;
default:
assert( 0 );
break;
}
strlcpy( buf, tr_getPrefsDirectory(), len );
pushdir( buf, typestr, len );
if( NULL != file )
{
pushdir( buf, file, len );
pushdir( buf, file, len );
}
}

View File

@@ -39,6 +39,7 @@ enum confpathtype
{
CONF_PATH_TYPE_DAEMON,
CONF_PATH_TYPE_GTK,
CONF_PATH_TYPE_OSX,
};
struct bufferevent;

View File

@@ -132,7 +132,8 @@ usage( const char * msg, ... )
"\n"
" -h --help Display this message and exit\n"
" -t --type daemon Use the daemon frontend, transmission-daemon\n"
" -t --type gtk Use the GTK+ frontend, transmission-gtk\n",
" -t --type gtk Use the GTK+ frontend, transmission-gtk\n"
" -t --type mac Use the Mac OS X frontend\n",
getmyname(), VERSION_STRING, VERSION_REVISION );
exit( EXIT_SUCCESS );
}
@@ -168,6 +169,14 @@ readargs( int argc, char ** argv, char ** sockpath )
type = CONF_PATH_TYPE_GTK;
*sockpath = NULL;
}
else if( 0 == strcasecmp( "mac", optarg ) ||
0 == strcasecmp( "osx", optarg ) ||
0 == strcasecmp( "macos", optarg ) ||
0 == strcasecmp( "macosx", optarg ) )
{
type = CONF_PATH_TYPE_OSX;
*sockpath = NULL;
}
else
{
*sockpath = optarg;

View File

@@ -248,6 +248,7 @@ usage( const char * msg, ... )
" -S --stop all Stop all running torrents\n"
" -t --type daemon Use the daemon frontend, transmission-daemon\n"
" -t --type gtk Use the GTK+ frontend, transmission-gtk\n"
" -t --type mac Use the MacOS X frontend\n"
" -u --upload-limit <int> Max upload rate in KiB/s\n"
" -U --upload-unlimited No upload rate limit\n"
" -x --proxy Use proxy command to connect to frontend\n",
@@ -373,6 +374,14 @@ readargs( int argc, char ** argv, struct opts * opts )
opts->type = CONF_PATH_TYPE_GTK;
opts->sock = NULL;
}
else if( 0 == strcasecmp( "mac", optarg ) ||
0 == strcasecmp( "osx", optarg ) ||
0 == strcasecmp( "macos", optarg ) ||
0 == strcasecmp( "macosx", optarg ) )
{
opts->type = CONF_PATH_TYPE_OSX;
opts->sock = NULL;
}
else
{
opts->sock = optarg;

View File

@@ -34,6 +34,7 @@
#import "Badger.h"
#import "ImageBackgroundView.h"
#import "FilterBarButton.h"
#import "IPCController.h"
#import <Growl/Growl.h>
@@ -49,6 +50,7 @@
NSUserDefaults * fDefaults;
InfoWindowController * fInfoController;
MessageWindowController * fMessageController;
IPCController * fIPCController;
IBOutlet NSWindow * fWindow;
DragOverlayWindow * fOverlayWindow;
@@ -97,6 +99,8 @@
NSMutableArray * fAutoImportedNames;
NSMutableDictionary * fPendingTorrentDownloads;
NSTimer * fAutoImportTimer;
BOOL fRemoteQuit;
}
- (void) openFiles: (NSArray *) filenames;

View File

@@ -168,6 +168,8 @@ static void sleepCallBack(void * controller, io_service_t y, natural_t messageTy
fBadger = [[Badger alloc] initWithLib: fLib];
fOverlayWindow = [[DragOverlayWindow alloc] initWithLib: fLib];
fIPCController = [[IPCController alloc] init];
[fIPCController setDelegate: self];
[GrowlApplicationBridge setGrowlDelegate: self];
@@ -189,6 +191,7 @@ static void sleepCallBack(void * controller, io_service_t y, natural_t messageTy
[fDisplayedTorrents release];
[fBadger release];
[fOverlayWindow release];
[fIPCController release];
[fAutoImportedNames release];
[fPendingTorrentDownloads release];
@@ -456,7 +459,7 @@ static void sleepCallBack(void * controller, io_service_t y, natural_t messageTy
- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) sender
{
if (!fUpdateInProgress && [fDefaults boolForKey: @"CheckQuit"])
if (!fUpdateInProgress && !fRemoteQuit && [fDefaults boolForKey: @"CheckQuit"])
{
int active = 0, downloading = 0;
Torrent * torrent;
@@ -2979,4 +2982,148 @@ static void sleepCallBack(void * controller, io_service_t y, natural_t messageTy
stringByAppendingPathComponent: [[NSProcessInfo processInfo] processName]];
}
- (void) ipcQuit
{
fRemoteQuit = YES;
[NSApp terminate: self];
}
- (NSArray *) ipcGetTorrentsByID: (NSArray *) idlist
{
NSEnumerator * torenum, * idenum;
Torrent * tor;
NSNumber * num;
NSMutableArray * ret;
if (!idlist)
{
return fTorrents;
}
ret = [NSMutableArray array];
torenum = [fTorrents objectEnumerator];
while ((tor = [torenum nextObject]))
{
idenum = [idlist objectEnumerator];
while ((num = [idenum nextObject]))
{
if ([num intValue] == [tor getID])
{
[ret addObject: tor];
break;
}
}
}
return ret;
}
- (NSArray *) ipcGetTorrentsByHash: (NSArray *) hashlist
{
NSEnumerator * torenum, * hashenum;
Torrent * tor;
NSString * torhash, * listhash;
NSMutableArray * ret;
if (!hashlist)
return fTorrents;
ret = [NSMutableArray array];
torenum = [fTorrents objectEnumerator];
while ((tor = [torenum nextObject]))
{
torhash = [tor hashString];
hashenum = [hashlist objectEnumerator];
while ((listhash = [hashenum nextObject]))
{
if (NSOrderedSame == [torhash caseInsensitiveCompare: listhash])
{
[ret addObject: tor];
break;
}
}
}
return ret;
}
- (BOOL) ipcAddTorrents: (NSArray *) torrents
{
/* 'torrents' is NSArray of NSString torrent file paths, should
return NO if torrent fails to load */
return NO;
}
- (BOOL) ipcAddTorrentFile: (NSString *) path
directory: (NSString *) dir
{
/* 'path' is path to torrent file, 'dir' is the directory it
should download it's files to and may be nil, should return NO
if torrent fails to load */
return NO;
}
- (BOOL) ipcAddTorrentFileAutostart: (NSString *) path
directory: (NSString *) dir
autostart: (BOOL) autostart
{
/* 'path' is path to torrent file, 'dir' is the directory it
should download it's files to and may be nil, 'autostart' is a
boolean indicating if the torrent should be automatically
started (or queued to start, I guess), should return NO if
torrent fails to load */
return NO;
}
- (BOOL) ipcAddTorrentData: (NSData *) data
directory: (NSString *) dir
{
/* 'data' is the contents of a torrent file, 'dir' is the
directory it should download it's files to and may be nil,
should return NO if torrent fails to load */
return NO;
}
- (BOOL) ipcAddTorrentDataAutostart: (NSData *) path
directory: (NSString *) dir
autostart: (BOOL) autostart
{
/* 'data' is the contents of a torrent file, 'dir' is the
directory it should download it's files to and may be nil,
'autostart' is a boolean indicating if the torrent should be
automatically started (or queued to start, I guess), should
return NO if torrent fails to load */
return NO;
}
- (BOOL) ipcStartTorrents: (NSArray *) torrents
{
if (!torrents)
[self resumeAllTorrents: self];
else
[self resumeTorrents: torrents];
return YES;
}
- (BOOL) ipcStopTorrents: (NSArray *) torrents
{
if (!torrents)
[self stopAllTorrents: self];
else
[self stopTorrents: torrents];
return YES;
}
- (BOOL) ipcRemoveTorrents: (NSArray *) torrents
{
if (!torrents)
torrents = [NSArray arrayWithArray: fTorrents];
[self confirmRemoveTorrents: torrents deleteData: NO deleteTorrent: NO];
return YES;
}
@end

70
macosx/IPCController.h Normal file
View File

@@ -0,0 +1,70 @@
/******************************************************************************
* $Id$
*
* Copyright (c) 2007 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.
*****************************************************************************/
#ifndef IPCCONTROLLER_H
#define IPCCONTROLLER_H
#import <Cocoa/Cocoa.h>
#include "ipcparse.h"
@interface NSObject (IPCControllerDelegate)
- (void) ipcQuit;
- (NSArray *) ipcGetTorrentsByID: (NSArray *) idlist;
- (NSArray *) ipcGetTorrentsByHash: (NSArray *) hashlist;
- (BOOL) ipcAddTorrents: (NSArray *) torrents;
- (BOOL) ipcAddTorrentFile: (NSString *) path
directory: (NSString *) dir;
- (BOOL) ipcAddTorrentFileAutostart: (NSString *) path
directory: (NSString *) dir
autostart: (BOOL) autostart;
- (BOOL) ipcAddTorrentData: (NSData *) data
directory: (NSString *) dir;
- (BOOL) ipcAddTorrentDataAutostart: (NSData *) data
directory: (NSString *) dir
autostart: (BOOL) autostart;
- (BOOL) ipcStartTorrents: (NSArray *) torrents;
- (BOOL) ipcStopTorrents: (NSArray *) torrents;
- (BOOL) ipcRemoveTorrents: (NSArray *) torrents;
/* XXX how to get and set prefs nicely? */
@end
@interface IPCController : NSObject
{
NSSocketPort * _sock;
NSFileHandle * _listen;
struct ipc_funcs * _funcs;
NSMutableArray * _clients;
id _delegate;
}
- (id) init;
- (id) delegate;
- (void) setDelegate: (id) newdelegate;
@end
#endif

912
macosx/IPCController.m Normal file
View File

@@ -0,0 +1,912 @@
/******************************************************************************
* $Id$
*
* Copyright (c) 2007 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.
*****************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "bencode.h"
#include "ipcparse.h"
#include "transmission.h"
#import "IPCController.h"
#import "Torrent.h"
static void
getaddr( struct sockaddr_un * );
static NSArray *
bencarray( benc_val_t * val, int type );
static void
msg_lookup ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
static void
msg_info ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_infoall ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_action ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_actionall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_addold ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_addnew ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_getbool ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_getint ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_getstr ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_setbool ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_setint ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
void
msg_setstr ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
static void
msg_default ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
@interface IPCClient : NSObject
{
NSFileHandle * _handle;
struct ipc_info _ipc;
IPCController * _controller;
NSMutableData * _buf;
}
- (id) initClient: (IPCController *) controller
funcs: (struct ipc_funcs *) funcs
handle: (NSFileHandle *) handle;
- (IPCController *) controller;
- (struct ipc_info *) ipc;
- (void) gotdata: (NSNotification *) notification;
- (BOOL) sendresp: (uint8_t *) buf
size: (size_t) size;
- (BOOL) sendrespEmpty: (enum ipc_msg) msgid
tag: (int64_t) tag;
- (BOOL) sendrespInt: (enum ipc_msg) msgid
tag: (int64_t) tag
val: (int64_t) val;
- (BOOL) sendrespStr: (enum ipc_msg) msgid
tag: (int64_t) tag
val: (NSString *) val;
- (void) sendrespInfo: (enum ipc_msg) respid
tag: (int64_t) tag
torrents: (NSArray *) tors
types: (int) types;
@end
@interface IPCController (Private)
- (void) newclient: (NSNotification *) notification;
- (void) killclient: (IPCClient *) client;
@end
@implementation IPCController
- (id) init
{
struct sockaddr_un sun;
self = [super init];
if( nil == self )
return nil;
getaddr( &sun );
unlink( sun.sun_path );
_sock = [[NSSocketPort alloc]
initWithProtocolFamily: PF_UNIX
socketType: SOCK_STREAM
protocol: 0
address: [NSData dataWithBytes: &sun
length: sizeof(sun)]];
_listen = [[NSFileHandle alloc]
initWithFileDescriptor: [_sock socket]
closeOnDealloc: YES];
_funcs = ipc_initmsgs();
_clients = [[NSMutableArray alloc] init];
/* XXX is this error checking bogus? */
if( nil == _sock ||
nil == _listen ||
NULL == _funcs ||
nil == _clients ||
0 > ipc_addmsg( _funcs, IPC_MSG_ADDMANYFILES, msg_addold ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_ADDONEFILE, msg_addnew ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_AUTOMAP, msg_setbool ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_AUTOSTART, msg_setbool ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_DIR, msg_setstr ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_DOWNLIMIT, msg_setint ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETAUTOMAP, msg_getbool ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETAUTOSTART, msg_getbool ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETDIR, msg_getstr ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETDOWNLIMIT, msg_getint ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETINFO, msg_info ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETINFOALL, msg_infoall ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETPEX, msg_getbool ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETPORT, msg_getint ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETSTAT, msg_info ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETSTATALL, msg_infoall ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_GETUPLIMIT, msg_getint ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_LOOKUP, msg_lookup ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_PEX, msg_setbool ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_PORT, msg_setint ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_REMOVE, msg_action ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_REMOVEALL, msg_actionall ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_START, msg_action ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_STARTALL, msg_actionall ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_STOP, msg_action ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_STOPALL, msg_actionall ) ||
0 > ipc_addmsg( _funcs, IPC_MSG_UPLIMIT, msg_setint ) )
{
[self release];
return nil;
}
ipc_setdefmsg( _funcs, msg_default );
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(newclient:)
name: NSFileHandleConnectionAcceptedNotification
object: _listen];
[_listen acceptConnectionInBackgroundAndNotify];
return self;
}
- (void) dealloc
{
struct sockaddr_un sun;
[[NSNotificationCenter defaultCenter] removeObserver: self];
[_listen release];
[_sock release];
[_clients release];
ipc_freemsgs( _funcs );
getaddr( &sun );
unlink( sun.sun_path );
[super dealloc];
}
- (id) delegate
{
return _delegate;
}
- (void) setDelegate: (id) newdelegate
{
_delegate = newdelegate;
}
@end
@implementation IPCController (Private)
- (void) newclient: (NSNotification *) notification
{
NSDictionary * info;
NSFileHandle * handle;
NSNumber * error;
IPCClient * client;
info = [notification userInfo];
handle = [info objectForKey: NSFileHandleNotificationFileHandleItem];
error = [info objectForKey: @"NSFileHandleError"];
if( nil != error )
{
NSLog( @"Failed to accept IPC socket connection: %@", error );
return;
}
[_listen acceptConnectionInBackgroundAndNotify];
if( nil == handle )
return;
client = [[IPCClient alloc]
initClient: self
funcs: _funcs
handle: handle];
if( nil == client )
return;
[_clients addObject:client];
[client release];
}
- (void) killclient: (IPCClient *) client
{
[_clients removeObject: client];
}
@end
@implementation IPCClient
- (id) initClient: (IPCController *) controller
funcs: (struct ipc_funcs *) funcs
handle: (NSFileHandle *) handle
{
uint8_t * buf;
size_t size;
self = [super init];
if( nil == self )
return nil;
_handle = [handle retain];
ipc_newcon( &_ipc, funcs );
_controller = controller;
_buf = [[NSMutableData alloc] init];
buf = ipc_mkvers( &size );
if( nil == _buf || NULL == buf || ![self sendresp: buf size: size] )
{
[self release];
return nil;
}
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(gotdata:)
name: NSFileHandleReadCompletionNotification
object: _handle];
[_handle readInBackgroundAndNotify];
return self;
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
[_handle release];
[_buf release];
[super dealloc];
}
- (IPCController *) controller
{
return _controller;
}
- (struct ipc_info *) ipc
{
return &_ipc;
}
- (void) gotdata: (NSNotification *) notification
{
NSDictionary * info;
NSData * data;
NSNumber * error;
ssize_t res;
info = [notification userInfo];
data = [info objectForKey: NSFileHandleNotificationDataItem];
error = [info objectForKey: @"NSFileHandleError"];
if( nil != error )
{
NSLog( @"Failed to read from IPC socket connection: %@", error );
[_controller killclient: self];
return;
}
if( nil == data || 0 == [data length] )
{
[_controller killclient: self];
return;
}
[_handle readInBackgroundAndNotify];
[_buf appendData: data];
if( IPC_MIN_MSG_LEN > [_buf length] )
return;
res = ipc_parse( &_ipc, [_buf mutableBytes], [_buf length], self );
if( 0 > res )
{
switch( errno )
{
case EPERM:
NSLog( @"IPC client has unsupported protocol version" );
break;
case EINVAL:
NSLog( @"IPC protocol parse error" );
break;
default:
NSLog( @"IPC parsing failed" );
break;
}
[_controller killclient: self];
return;
}
else if( 0 < res )
{
if( res > [_buf length])
{
memmove( [_buf mutableBytes], [_buf bytes] + res,
[_buf length] - res );
}
[_buf setLength: ([_buf length] - res)];
}
}
- (BOOL) sendresp: (uint8_t *) buf
size: (size_t) size
{
@try
{
[_handle writeData: [NSData dataWithBytesNoCopy: buf
length: size
freeWhenDone: YES]];
return YES;
}
@catch( NSException * ex )
{
NSLog( @"Failed to write to IPC socket connection" );
return NO;
}
}
- (BOOL) sendrespEmpty: (enum ipc_msg) msgid
tag: (int64_t) tag
{
uint8_t * buf;
size_t size;
buf = ipc_mkempty( &_ipc, &size, msgid, tag );
if( NULL == buf )
return FALSE;
return [self sendresp: buf
size: size];
}
- (BOOL) sendrespInt: (enum ipc_msg) msgid
tag: (int64_t) tag
val: (int64_t) val
{
uint8_t * buf;
size_t size;
buf = ipc_mkint( &_ipc, &size, msgid, tag, val );
if( NULL == buf )
return FALSE;
return [self sendresp: buf
size: size];
}
- (BOOL) sendrespStr: (enum ipc_msg) msgid
tag: (int64_t) tag
val: (NSString *) val
{
uint8_t * buf;
size_t size;
NSData * data;
NSMutableData * sucky;
if( [val canBeConvertedToEncoding: NSUTF8StringEncoding] )
buf = ipc_mkstr( &_ipc, &size, msgid, tag,
[val cStringUsingEncoding: NSUTF8StringEncoding] );
else
{
data = [val dataUsingEncoding: NSUTF8StringEncoding
allowLossyConversion: YES];
/* XXX this sucks, I should add a length argument to ipc_mkstr() */
sucky = [NSMutableData dataWithData: data];
[sucky appendBytes: "" length: 1];
buf = ipc_mkstr( &_ipc, &size, msgid, tag, [sucky bytes] );
}
if( NULL == buf )
return FALSE;
return [self sendresp: buf
size: size];
}
- (void) sendrespInfo: (enum ipc_msg) respid
tag: (int64_t) tag
torrents: (NSArray *) tors
types: (int) types
{
benc_val_t packet, * pkinf;
NSEnumerator * enumerator;
Torrent * tor;
uint8_t * buf;
size_t size;
int res;
pkinf = ipc_initval( &_ipc, respid, tag, &packet, TYPE_LIST );
if( NULL == pkinf )
goto fail;
if( tr_bencListReserve( pkinf, [tors count] ) )
{
tr_bencFree( &packet );
goto fail;
}
enumerator = [tors objectEnumerator];
while( nil != ( tor = [enumerator nextObject] ) )
{
if( IPC_MSG_INFO == respid )
res = ipc_addinfo( pkinf, [tor getID], [tor getInfo], types );
else
res = ipc_addstat( pkinf, [tor getID], [tor getInfo],
[tor getStat], types );
if( 0 > res )
{
tr_bencFree( &packet );
goto fail;
}
}
buf = ipc_mkval( &packet, &size );
tr_bencFree( &packet );
if( NULL == buf )
goto fail;
[self sendresp: buf size: size ];
return;
fail:
NSLog( @"Failed to create IPC reply packet" );
[_controller killclient: self];
}
@end
void
getaddr( struct sockaddr_un * sun )
{
bzero( sun, sizeof *sun );
sun->sun_family = AF_LOCAL;
strlcpy( sun->sun_path, tr_getPrefsDirectory(), sizeof sun->sun_path );
strlcat( sun->sun_path, "/socket", sizeof sun->sun_path );
}
NSArray *
bencarray( benc_val_t * val, int type )
{
int ii;
NSMutableArray * ret;
benc_val_t * item;
assert( TYPE_STR == type || TYPE_INT == type );
if( NULL == val || TYPE_LIST != val->type )
return nil;
ret = [NSMutableArray arrayWithCapacity: val->val.l.count];
for( ii = 0; ii < val->val.l.count; ii++ )
{
item = &val->val.l.vals[ii];
if( type != item->type )
return nil;
if( TYPE_STR == type )
{
[ret addObject: [NSString stringWithCString: item->val.s.s
encoding: NSUTF8StringEncoding]];
}
else
{
[ret addObject: [NSNumber numberWithLongLong: (long long) item->val.i]];
}
}
return ret;
}
void
msg_lookup( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
NSArray * hashes, * tors;
benc_val_t packet, * pkinf;
NSEnumerator * enumerator;
Torrent * tor;
uint8_t * buf;
size_t size;
hashes = bencarray( val, TYPE_STR );
if( NULL == hashes )
{
[client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
return;
}
tors = [[[client controller] delegate] ipcGetTorrentsByHash: hashes];
[client sendrespInfo: IPC_MSG_INFO
tag: tag
torrents: tors
types: IPC_INF_HASH];
}
void
msg_info( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
enum ipc_msg respid;
benc_val_t * typesval;
int types;
NSArray * ids, * tors;
if( NULL == val || TYPE_DICT != val->type )
goto bad;
typesval = tr_bencDictFind( val, "type" );
if( NULL == typesval || TYPE_LIST != typesval->type ||
nil == ( ids = bencarray( tr_bencDictFind( val, "id" ), TYPE_INT ) ) )
goto bad;
respid = ( IPC_MSG_GETINFO == msgid ? IPC_MSG_INFO : IPC_MSG_STAT );
tors = [[[client controller] delegate] ipcGetTorrentsByID: ids];
types = ipc_infotypes( respid, typesval );
[client sendrespInfo: respid tag: tag torrents: tors types: types];
return;
bad:
NSLog( @"Got bad IPC packet" );
[client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
}
void
msg_infoall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
enum ipc_msg respid;
int types;
NSArray * tors;
if( NULL == val || TYPE_LIST != val->type )
{
NSLog( @"Got bad IPC packet" );
[client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
return;
}
respid = ( IPC_MSG_GETINFOALL == msgid ? IPC_MSG_INFO : IPC_MSG_STAT );
tors = [[[client controller] delegate] ipcGetTorrentsByID: nil];
types = ipc_infotypes( respid, val );
[client sendrespInfo: respid tag: tag torrents: tors types: types];
}
void
msg_action( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
BOOL res;
NSArray * ids, * tors;
id delegate;
ids = bencarray( val, TYPE_INT );
if( nil == ids )
{
NSLog( @"Got bad IPC packet" );
[client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
return;
}
delegate = [[client controller] delegate];
tors = [delegate ipcGetTorrentsByID: ids];
switch( msgid )
{
case IPC_MSG_REMOVE:
res = [delegate ipcRemoveTorrents: tors];
break;
case IPC_MSG_START:
res = [delegate ipcStartTorrents: tors];
break;
case IPC_MSG_STOP:
res = [delegate ipcStopTorrents: tors];
break;
default:
assert( 0 );
return;
}
if( res )
[client sendrespEmpty: IPC_MSG_OK tag: tag];
else
[client sendrespEmpty: IPC_MSG_FAIL tag: tag];
}
void
msg_actionall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
BOOL res;
NSArray * tors;
id delegate;
delegate = [[client controller] delegate];
tors = [delegate ipcGetTorrentsByID: nil];
switch( msgid )
{
case IPC_MSG_REMOVEALL:
res = [delegate ipcRemoveTorrents: tors];
break;
case IPC_MSG_STARTALL:
res = [delegate ipcStartTorrents: tors];
break;
case IPC_MSG_STOPALL:
res = [delegate ipcStopTorrents: tors];
break;
default:
assert( 0 );
return;
}
if( res )
[client sendrespEmpty: IPC_MSG_OK tag: tag];
else
[client sendrespEmpty: IPC_MSG_FAIL tag: tag];
}
void
msg_addold( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
NSArray * paths;
BOOL res;
paths = bencarray( val, TYPE_STR );
if( nil == paths )
{
NSLog( @"Got bad IPC packet" );
[client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
return;
}
/* XXX should send back info message with torrent IDs */
if( [[[client controller] delegate] ipcAddTorrents: paths] )
[client sendrespEmpty: IPC_MSG_OK tag: tag];
else
[client sendrespEmpty: IPC_MSG_FAIL tag: tag];
}
void
msg_addnew( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
benc_val_t * fileval, * dataval, * dirval, * autoval;
NSString * file, * dir;
NSData * data;
BOOL autobool, res;
if( NULL == val || TYPE_DICT != val->type )
goto bad;
fileval = tr_bencDictFind( val, "file" );
dataval = tr_bencDictFind( val, "data" );
dirval = tr_bencDictFind( val, "directory" );
autoval = tr_bencDictFind( val, "autostart" );
if( ( ( NULL == fileval || TYPE_STR != fileval->type ) &&
( NULL == dataval || TYPE_STR != dataval->type ) ) ||
( ( NULL != fileval && TYPE_STR == fileval->type ) &&
( NULL != dataval && TYPE_STR == dataval->type ) ) ||
( NULL != dirval && TYPE_STR != dirval->type ) ||
( NULL != autoval && TYPE_INT != autoval->type ) )
goto bad;
dir = ( NULL == dirval ? nil :
[NSString stringWithCString: dirval->val.s.s
encoding: NSUTF8StringEncoding] );
autobool = ( NULL == autoval || 0 == autoval->val.i ? NO : YES );
if( NULL != fileval )
{
file = [NSString stringWithCString: fileval->val.s.s
encoding: NSUTF8StringEncoding];
if( NULL == autoval )
res = [[[client controller] delegate]
ipcAddTorrentFile: file
directory: dir];
else
res = [[[client controller] delegate]
ipcAddTorrentFileAutostart: file
directory: dir
autostart: autobool];
}
else
{
data = [NSData dataWithBytes: dataval->val.s.s
length: dataval->val.s.i];
if( NULL == autoval )
res = [[[client controller] delegate]
ipcAddTorrentData: data
directory: dir];
else
res = [[[client controller] delegate]
ipcAddTorrentDataAutostart: data
directory: dir
autostart: autobool];
}
/* XXX should send back info message with torrent ID */
if( res )
[client sendrespEmpty: IPC_MSG_OK tag: tag];
else
[client sendrespEmpty: IPC_MSG_FAIL tag: tag];
return;
bad:
NSLog( @"Got bad IPC packet" );
[client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
}
void
msg_getbool( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
switch( msgid )
{
case IPC_MSG_GETAUTOMAP:
case IPC_MSG_GETAUTOSTART:
case IPC_MSG_GETPEX:
[client sendrespEmpty: IPC_MSG_FAIL tag: tag];
break;
default:
assert( 0 );
break;
}
}
void
msg_getint( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
switch( msgid )
{
case IPC_MSG_GETDOWNLIMIT:
case IPC_MSG_GETPORT:
case IPC_MSG_GETUPLIMIT:
[client sendrespEmpty: IPC_MSG_FAIL tag: tag];
break;
default:
assert( 0 );
break;
}
}
void
msg_getstr( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
switch( msgid )
{
case IPC_MSG_GETDIR:
[client sendrespEmpty: IPC_MSG_FAIL tag: tag];
break;
default:
assert( 0 );
break;
}
}
void
msg_setbool( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
if( NULL == val || TYPE_INT != val->type )
{
NSLog( @"Got bad IPC packet" );
[client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
return;
}
switch( msgid )
{
case IPC_MSG_AUTOMAP:
case IPC_MSG_AUTOSTART:
case IPC_MSG_PEX:
[client sendrespEmpty: IPC_MSG_FAIL tag: tag];
break;
default:
assert( 0 );
break;
}
}
void
msg_setint( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
if( NULL == val || TYPE_INT != val->type )
{
NSLog( @"Got bad IPC packet" );
[client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
return;
}
switch( msgid )
{
case IPC_MSG_DOWNLIMIT:
case IPC_MSG_PORT:
case IPC_MSG_UPLIMIT:
[client sendrespEmpty: IPC_MSG_FAIL tag: tag];
break;
default:
assert( 0 );
break;
}
}
void
msg_setstr( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
if( NULL == val || TYPE_STR != val->type )
{
NSLog( @"Got bad IPC packet" );
[client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
return;
}
switch( msgid )
{
case IPC_MSG_DIR:
[client sendrespEmpty: IPC_MSG_FAIL tag: tag];
break;
default:
assert( 0 );
break;
}
}
void
msg_default( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
{
IPCClient * client = arg;
switch( msgid )
{
case IPC_MSG_NOOP:
[client sendrespEmpty: IPC_MSG_OK tag: tag];
break;
case IPC_MSG_QUIT:
[[[client controller] delegate] ipcQuit];
[client sendrespEmpty: IPC_MSG_OK tag: tag];
break;
default:
[client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
break;
}
}

View File

@@ -34,6 +34,8 @@
tr_info_t * fInfo;
tr_stat_t * fStat;
int fID;
BOOL fResumeOnWake;
NSDate * fDateAdded, * fDateCompleted, * fAnnounceDate,
* fDateActivity;
@@ -212,4 +214,8 @@
- (NSNumber *) progressSortKey;
- (NSNumber *) ratioSortKey;
- (int) getID;
- (tr_info_t *) getInfo;
- (tr_stat_t *) getStat;
@end

View File

@@ -30,6 +30,8 @@
#define MAX_PIECES 324
#define BLANK_PIECE -99
static int static_lastid = 0;
@interface Torrent (Private)
- (id) initWithHash: (NSString *) hashString path: (NSString *) path lib: (tr_handle_t *) lib
@@ -1400,6 +1402,21 @@ static uint32_t kRed = BE(0xFF6450FF), //255, 100, 80
return [NSNumber numberWithFloat: [self ratio]];
}
- (int) getID
{
return fID;
}
- (tr_info_t *) getInfo
{
return fInfo;
}
- (tr_stat_t *) getStat
{
return fStat;
}
@end
@implementation Torrent (Private)
@@ -1418,7 +1435,10 @@ static uint32_t kRed = BE(0xFF6450FF), //255, 100, 80
{
if (!(self = [super init]))
return nil;
static_lastid++;
fID = static_lastid;
fLib = lib;
fDefaults = [NSUserDefaults standardUserDefaults];