source: trunk/macosx/IPCController.m @ 5499

Last change on this file since 5499 was 5499, checked in by charles, 14 years ago

hudson took me too seriously

  • Property svn:keywords set to Date Rev Author Id
File size: 31.5 KB
Line 
1/******************************************************************************
2 * $Id: IPCController.m 5499 2008-04-03 21:41:37Z charles $
3 *
4 * Copyright (c) 2007-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <sys/un.h>
28#include <assert.h>
29#include <errno.h>
30#include <string.h>
31#include <unistd.h>
32
33#include "bencode.h"
34#include "ipcparse.h"
35#include "transmission.h"
36
37#import "IPCController.h"
38#import "Torrent.h"
39#import "PrefsController.h"
40
41static void
42getaddr( struct sockaddr_un * );
43static NSArray *
44bencarray( benc_val_t * val, int type );
45static void
46msg_lookup   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
47static void
48msg_info     ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
49void
50msg_infoall  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
51void
52msg_action   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
53void
54msg_actionall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
55void
56msg_addold   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
57void
58msg_addnew   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
59void
60msg_getbool  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
61void
62msg_getint   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
63void
64msg_getstr   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
65void
66msg_setbool  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
67void
68msg_setint   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
69void
70msg_setstr   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
71void
72msg_empty    ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
73void
74msg_sup      ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
75static void
76msg_default  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
77
78@interface IPCClient : NSObject
79{
80    NSFileHandle    * _handle;
81    struct ipc_info * _ipc;
82    IPCController   * _controller;
83    NSMutableData   * _buf;
84}
85
86- (id)              initClient: (IPCController *) controller
87                         funcs: (struct ipc_funcs *) funcs
88                        handle: (NSFileHandle *) handle;
89- (IPCController *) controller;
90- (struct ipc_info *)      ipc;
91- (void)               gotdata: (NSNotification *) notification;
92- (BOOL)              sendresp: (uint8_t *) buf
93                          size: (size_t) size;
94- (BOOL)         sendrespEmpty: (enum ipc_msg) msgid
95                           tag: (int64_t) tag;
96- (BOOL)           sendrespInt: (enum ipc_msg) msgid
97                           tag: (int64_t) tag
98                           val: (int64_t) val;
99- (BOOL)           sendrespStr: (enum ipc_msg) msgid
100                           tag: (int64_t) tag
101                           val: (NSString *) val;
102- (void)          sendrespInfo: (enum ipc_msg) respid
103                           tag: (int64_t) tag
104                      torrents: (NSArray *) tors
105                         types: (int) types;
106
107@end
108
109@interface IPCController (Private)
110
111- (void)  newclient: (NSNotification *) notification;
112- (void) killclient: (IPCClient *) client;
113
114NSUserDefaults          * fDefaults;
115PrefsController         * fPrefsController;
116
117
118@end
119
120@implementation IPCController
121
122- (id) init
123{
124    struct sockaddr_un sun;
125
126    self = [super init];
127    if( nil == self )
128        return nil;
129
130    getaddr( &sun );
131    unlink( sun.sun_path );
132    _sock    = [[NSSocketPort alloc]
133                   initWithProtocolFamily: PF_UNIX
134                               socketType: SOCK_STREAM
135                                 protocol: 0
136                                  address: [NSData dataWithBytes: &sun
137                                                          length: sizeof(sun)]];
138    _listen  = [[NSFileHandle alloc]
139                   initWithFileDescriptor: [_sock socket]
140                           closeOnDealloc: YES];
141    _funcs   = ipc_initmsgs();
142    _clients = [[NSMutableArray alloc] init];
143
144    /* XXX is this error checking bogus? */
145    if( nil  == _sock    ||
146        nil  == _listen  ||
147        NULL == _funcs   ||
148        nil  == _clients )
149    {
150        [self release];
151        return nil;
152    }
153
154    ipc_addmsg( _funcs, IPC_MSG_ADDMANYFILES, msg_addold    );
155    ipc_addmsg( _funcs, IPC_MSG_ADDONEFILE,   msg_addnew    );
156    ipc_addmsg( _funcs, IPC_MSG_AUTOMAP,      msg_setbool   );
157    ipc_addmsg( _funcs, IPC_MSG_AUTOSTART,    msg_setbool   );
158    ipc_addmsg( _funcs, IPC_MSG_CRYPTO,       msg_setstr    );
159    ipc_addmsg( _funcs, IPC_MSG_DIR,          msg_setstr    );
160    ipc_addmsg( _funcs, IPC_MSG_DOWNLIMIT,    msg_setint    );
161    ipc_addmsg( _funcs, IPC_MSG_GETAUTOMAP,   msg_getbool   );
162    ipc_addmsg( _funcs, IPC_MSG_GETAUTOSTART, msg_getbool   );
163    ipc_addmsg( _funcs, IPC_MSG_GETCRYPTO,    msg_getstr    );
164    ipc_addmsg( _funcs, IPC_MSG_GETDIR,       msg_getstr    );
165    ipc_addmsg( _funcs, IPC_MSG_GETDOWNLIMIT, msg_getint    );
166    ipc_addmsg( _funcs, IPC_MSG_GETINFO,      msg_info      );
167    ipc_addmsg( _funcs, IPC_MSG_GETINFOALL,   msg_infoall   );
168    ipc_addmsg( _funcs, IPC_MSG_GETPEX,       msg_getbool   );
169    ipc_addmsg( _funcs, IPC_MSG_GETPORT,      msg_getint    );
170    ipc_addmsg( _funcs, IPC_MSG_GETSTAT,      msg_info      );
171    ipc_addmsg( _funcs, IPC_MSG_GETSTATALL,   msg_infoall   );
172    ipc_addmsg( _funcs, IPC_MSG_GETUPLIMIT,   msg_getint    );
173    ipc_addmsg( _funcs, IPC_MSG_LOOKUP,       msg_lookup    );
174    ipc_addmsg( _funcs, IPC_MSG_NOOP,         msg_empty     );
175    ipc_addmsg( _funcs, IPC_MSG_PEX,          msg_setbool   );
176    ipc_addmsg( _funcs, IPC_MSG_PORT,         msg_setint    );
177    ipc_addmsg( _funcs, IPC_MSG_QUIT,         msg_empty     );
178    ipc_addmsg( _funcs, IPC_MSG_REMOVE,       msg_action    );
179    ipc_addmsg( _funcs, IPC_MSG_REMOVEALL,    msg_actionall );
180    ipc_addmsg( _funcs, IPC_MSG_START,        msg_action    );
181    ipc_addmsg( _funcs, IPC_MSG_STARTALL,     msg_actionall );
182    ipc_addmsg( _funcs, IPC_MSG_STOP,         msg_action    );
183    ipc_addmsg( _funcs, IPC_MSG_STOPALL,      msg_actionall );
184    ipc_addmsg( _funcs, IPC_MSG_SUP,          msg_sup       );
185    ipc_addmsg( _funcs, IPC_MSG_UPLIMIT,      msg_setint    );
186    ipc_addmsg( _funcs, IPC_MSG_VERIFY,       msg_action    );
187    ipc_setdefmsg( _funcs, msg_default );
188
189    [[NSNotificationCenter defaultCenter]
190        addObserver: self
191           selector: @selector(newclient:)
192               name: NSFileHandleConnectionAcceptedNotification
193             object: _listen];
194    [_listen acceptConnectionInBackgroundAndNotify];
195
196    return self;
197}
198
199- (void) dealloc
200{
201    struct sockaddr_un sun;
202
203    [[NSNotificationCenter defaultCenter] removeObserver: self];
204    [_listen  release];
205    [_sock    release];
206    [_clients release];
207    ipc_freemsgs( _funcs );
208    getaddr( &sun );
209    unlink( sun.sun_path );
210    [super dealloc];
211}
212
213- (id) delegate
214{
215    return _delegate;
216}
217
218- (void) setDelegate: (id) newdelegate
219{
220    _delegate = newdelegate;
221}
222
223- (void) setPrefsController: (id) thePrefsController
224{
225    fPrefsController = thePrefsController;
226}
227
228@end
229
230@implementation IPCController (Private)
231
232- (void) newclient: (NSNotification *) notification
233{
234    NSDictionary * info;
235    NSFileHandle * handle;
236    NSNumber     * error;
237    IPCClient    * client;
238   
239
240    info   = [notification userInfo];
241    handle = [info objectForKey: NSFileHandleNotificationFileHandleItem];
242    error  = [info objectForKey: @"NSFileHandleError"];
243
244    if( nil != error )
245    {
246        NSLog( @"Failed to accept IPC socket connection: %@", error );
247        return;
248    }
249
250    [_listen acceptConnectionInBackgroundAndNotify];
251
252    if( nil == handle )
253        return;
254
255    client = [[IPCClient alloc]
256                 initClient: self
257                      funcs: _funcs
258                     handle: handle];
259    if( nil == client )
260        return;
261
262    [_clients addObject:client];
263    [client release];
264}
265
266- (void) killclient: (IPCClient *) client
267{
268    [_clients removeObject: client];
269}
270
271@end
272
273@implementation IPCClient
274
275- (id) initClient: (IPCController *) controller
276            funcs: (struct ipc_funcs *) funcs
277           handle: (NSFileHandle *) handle
278{
279    uint8_t * buf;
280    size_t    size;
281
282    self = [super init];
283    if( nil == self )
284        return nil;
285
286    _handle     = [handle retain];
287    _ipc        = ipc_newcon( funcs );
288    _controller = controller;
289    _buf        = [[NSMutableData alloc] init];
290
291    buf = ipc_mkvers( &size, "Transmission Mac OS X " LONG_VERSION_STRING );
292    if( NULL == _ipc || nil == _buf || NULL == buf ||
293        ![self sendresp: buf size: size] )
294    {
295        [self release];
296        return nil;
297    }
298
299    [[NSNotificationCenter defaultCenter]
300        addObserver: self
301           selector: @selector(gotdata:)
302               name: NSFileHandleReadCompletionNotification
303             object: _handle];
304    [_handle readInBackgroundAndNotify];
305
306    return self;
307}
308
309- (void) dealloc
310{
311    [[NSNotificationCenter defaultCenter] removeObserver: self];
312    [_handle release];
313    [_buf    release];
314    ipc_freecon( _ipc );
315    [super   dealloc];
316}
317
318- (IPCController *) controller
319{
320    return _controller;
321}
322
323- (struct ipc_info *) ipc
324{
325    return _ipc;
326}
327
328- (void) gotdata: (NSNotification *) notification
329{
330    NSDictionary * info;
331    NSData       * data;
332    NSNumber     * error;
333    ssize_t        res;
334
335    info  = [notification userInfo];
336    data  = [info objectForKey: NSFileHandleNotificationDataItem];
337    error = [info objectForKey: @"NSFileHandleError"];
338
339    if( nil != error )
340    {
341        NSLog( @"Failed to read from IPC socket connection: %@", error );
342        [_controller killclient: self];
343        return;
344    }
345
346    if( nil == data || 0 == [data length] )
347    {
348        [_controller killclient: self];
349        return;
350    }
351
352    [_handle readInBackgroundAndNotify];
353    [_buf appendData: data];
354
355    if( IPC_MIN_MSG_LEN > [_buf length] )
356        return;
357
358    res = ipc_parse( _ipc, [_buf mutableBytes], [_buf length], self );
359
360    if( 0 > res )
361    {
362        switch( errno )
363        {
364            case EPERM:
365                NSLog( @"IPC client has unsupported protocol version" );
366                break;
367            case EINVAL:
368                NSLog( @"IPC protocol parse error" );
369                break;
370            default:
371                NSLog( @"IPC parsing failed" );
372                break;
373        }
374        [_controller killclient: self];
375        return;
376    }
377    else if( 0 < res )
378    {
379        assert( res <= [_buf length]);
380        if( res < [_buf length])
381        {
382            memmove( [_buf mutableBytes], [_buf bytes] + res,
383                     [_buf length] - res );
384        }
385        [_buf setLength: ([_buf length] - res)];
386    }
387}
388
389- (BOOL) sendresp: (uint8_t *) buf
390             size: (size_t) size
391{
392    @try
393    {
394        [_handle writeData: [NSData dataWithBytesNoCopy: buf
395                                                 length: size
396                                           freeWhenDone: YES]];
397        return YES;
398    }
399    @catch( NSException * ex )
400    {
401        NSLog( @"Failed to write to IPC socket connection" );
402        return NO;
403    }
404}
405
406- (BOOL) sendrespEmpty: (enum ipc_msg) msgid
407                   tag: (int64_t) tag
408{
409    uint8_t * buf;
410    size_t    size;
411
412    buf = ipc_mkempty( _ipc, &size, msgid, tag );
413    if( NULL == buf )
414        return NO;
415
416    return [self sendresp: buf
417                     size: size];
418}
419
420- (BOOL) sendrespInt: (enum ipc_msg) msgid
421                 tag: (int64_t) tag
422                 val: (int64_t) val
423{
424    uint8_t * buf;
425    size_t    size;
426
427    buf = ipc_mkint( _ipc, &size, msgid, tag, val );
428    if( NULL == buf )
429        return NO;
430
431    return [self sendresp: buf
432                     size: size];
433}
434
435- (BOOL) sendrespStr: (enum ipc_msg) msgid
436                 tag: (int64_t) tag
437                 val: (NSString *) val
438{
439    uint8_t       * buf;
440    size_t          size;
441    NSData        * data;
442    NSMutableData * sucky;
443
444    if( [val canBeConvertedToEncoding: NSUTF8StringEncoding] )
445        buf = ipc_mkstr( _ipc, &size, msgid, tag,
446                         [val cStringUsingEncoding: NSUTF8StringEncoding] );
447    else
448    {
449        data = [val dataUsingEncoding: NSUTF8StringEncoding
450                 allowLossyConversion: YES];
451        /* XXX this sucks, I should add a length argument to ipc_mkstr() */
452        sucky = [NSMutableData dataWithData: data];
453        [sucky appendBytes: "" length: 1];
454        buf = ipc_mkstr( _ipc, &size, msgid, tag, [sucky bytes] );
455    }
456    if( NULL == buf )
457        return NO;
458
459    return [self sendresp: buf
460                     size: size];
461}
462
463- (void) sendrespInfo: (enum ipc_msg) respid
464                  tag: (int64_t) tag
465             torrents: (NSArray *) tors
466                types: (int) types
467{
468    benc_val_t     packet, * pkinf;
469    NSEnumerator * enumerator;
470    Torrent      * tor;
471    uint8_t      * buf;
472    size_t         size;
473    int            res;
474
475    pkinf = ipc_initval( _ipc, respid, tag, &packet, TYPE_LIST );
476    if( NULL == pkinf )
477        goto fail;
478    if( tr_bencListReserve( pkinf, [tors count] ) )
479    {
480        tr_bencFree( &packet );
481        goto fail;
482    }
483
484    enumerator = [tors objectEnumerator];
485    while( nil != ( tor = [enumerator nextObject] ) )
486    {
487        if( IPC_MSG_INFO == respid )
488            res = ipc_addinfo( pkinf, [tor torrentID], [tor torrentInfo], types );
489        else
490            res = ipc_addstat( pkinf, [tor torrentID], [tor torrentStat], types );
491        if( 0 > res )
492        {
493            tr_bencFree( &packet );
494            goto fail;
495        }
496    }
497
498    buf = ipc_serialize( &packet, &size );
499    tr_bencFree( &packet );
500    if( NULL == buf )
501        goto fail;
502    [self sendresp: buf size: size ];
503    return;
504
505  fail:
506    NSLog( @"Failed to create IPC reply packet" );
507    [_controller killclient: self];
508}
509
510
511@end
512
513void getaddr( struct sockaddr_un * sun )
514{
515    bzero( sun, sizeof *sun );
516    sun->sun_family = AF_LOCAL;
517    strlcpy( sun->sun_path, tr_getPrefsDirectory(), sizeof sun->sun_path );
518    strlcat( sun->sun_path, "/socket", sizeof sun->sun_path );
519}
520
521NSArray * bencarray( benc_val_t * val, int type )
522{
523    int              ii;
524    NSMutableArray * ret;
525    benc_val_t     * item;
526
527    assert( TYPE_STR == type || TYPE_INT == type );
528
529    if( NULL == val || TYPE_LIST != val->type )
530        return nil;
531
532    ret = [NSMutableArray arrayWithCapacity: val->val.l.count];
533    for( ii = 0; ii < val->val.l.count; ii++ )
534    {
535        item = &val->val.l.vals[ii];
536        if( type != item->type )
537            return nil;
538        if( TYPE_STR == type )
539        {
540            [ret addObject: [NSString stringWithCString: item->val.s.s
541                                               encoding: NSUTF8StringEncoding]];
542        }
543        else
544        {
545            [ret addObject: [NSNumber numberWithLongLong: (long long) item->val.i]];
546        }
547    }
548
549    return ret;
550}
551
552void msg_lookup( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
553{
554    IPCClient      * client = arg;
555    NSArray        * hashes, * tors;
556
557    hashes = bencarray( val, TYPE_STR );
558    if( NULL == hashes )
559    {
560        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
561        return;
562    }
563
564    tors  = [[[client controller] delegate] ipcGetTorrentsByHash: hashes];
565    [client sendrespInfo: IPC_MSG_INFO
566                     tag: tag
567                torrents: tors
568                   types: IPC_INF_HASH];
569}
570
571void msg_info( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
572{
573    IPCClient  * client = arg;
574    enum ipc_msg respid;
575    benc_val_t * typesval;
576    int          types;
577    NSArray    * ids, * tors;
578
579    if( NULL == val || TYPE_DICT != val->type )
580        goto bad;
581
582    typesval = tr_bencDictFind( val, "type" );
583    if( NULL == typesval || TYPE_LIST != typesval->type ||
584        nil == ( ids = bencarray( tr_bencDictFind( val, "id" ), TYPE_INT ) ) )
585        goto bad;
586
587    respid = ( IPC_MSG_GETINFO == msgid ? IPC_MSG_INFO : IPC_MSG_STAT );
588    tors   = [[[client controller] delegate] ipcGetTorrentsByID: ids];
589    types  = ipc_infotypes( respid, typesval );
590    [client sendrespInfo: respid tag: tag torrents: tors types: types];
591    return;
592
593  bad:
594    NSLog( @"Got bad IPC packet" );
595    [client sendrespEmpty: IPC_MSG_BAD tag: tag];
596}
597
598void msg_infoall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
599{
600    IPCClient  * client = arg;
601    enum ipc_msg respid;
602    int          types;
603    NSArray    * tors;
604
605    if( NULL == val || TYPE_LIST != val->type )
606    {
607        NSLog( @"Got bad IPC packet" );
608        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
609        return;
610    }
611
612    respid = ( IPC_MSG_GETINFOALL == msgid ? IPC_MSG_INFO : IPC_MSG_STAT );
613    tors   = [[[client controller] delegate] ipcGetTorrentsByID: nil];
614    types  = ipc_infotypes( respid, val );
615    [client sendrespInfo: respid tag: tag torrents: tors types: types];
616}
617
618void msg_action( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
619{
620    IPCClient * client = arg;
621    BOOL        res;
622    NSArray   * ids, * tors;
623    id          delegate;
624
625    ids = bencarray( val, TYPE_INT );
626    if( nil == ids )
627    {
628        NSLog( @"Got bad IPC packet" );
629        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
630        return;
631    }
632
633    delegate = [[client controller] delegate];
634    tors     = [delegate ipcGetTorrentsByID: ids];
635    switch( msgid )
636    {
637        case IPC_MSG_REMOVE:
638            res = [delegate ipcRemoveTorrents: tors];
639            break;
640        case IPC_MSG_START:
641            res = [delegate ipcStartTorrents: tors];
642            break;
643        case IPC_MSG_STOP:
644            res = [delegate ipcStopTorrents: tors];
645            break;
646        case IPC_MSG_VERIFY:
647            res = [delegate ipcVerifyTorrents: tors];
648            break;
649        default:
650            assert( 0 );
651            return;
652    }
653
654    if( res )
655        [client sendrespEmpty: IPC_MSG_OK tag: tag];
656    else
657        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
658}
659
660void msg_actionall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
661{
662    IPCClient * client = arg;
663    BOOL        res;
664    NSArray   * tors;
665    id          delegate;
666
667    delegate = [[client controller] delegate];
668    tors     = [delegate ipcGetTorrentsByID: nil];
669    switch( msgid )
670    {
671        case IPC_MSG_REMOVEALL:
672            res = [delegate ipcRemoveTorrents: tors];
673            break;
674        case IPC_MSG_STARTALL:
675            res = [delegate ipcStartTorrents: tors];
676            break;
677        case IPC_MSG_STOPALL:
678            res = [delegate ipcStopTorrents: tors];
679            break;
680        default:
681            assert( 0 );
682            return;
683    }
684
685    if( res )
686        [client sendrespEmpty: IPC_MSG_OK tag: tag];
687    else
688        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
689}
690
691void msg_addold( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
692{
693    IPCClient * client = arg;
694    NSArray   * paths;
695
696    paths = bencarray( val, TYPE_STR );
697    if( nil == paths )
698    {
699        NSLog( @"Got bad IPC packet" );
700        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
701        return;
702    }
703
704    /* XXX should send back info message with torrent IDs */
705    if( [[[client controller] delegate] ipcAddTorrents: paths] )
706        [client sendrespEmpty: IPC_MSG_OK tag: tag];
707    else
708        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
709}
710
711void msg_addnew( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
712{
713    IPCClient  * client = arg;
714    benc_val_t * fileval, * dataval, * dirval, * autoval;
715    NSString   * file, * dir;
716    NSData     * data;
717    BOOL         autobool, res;
718
719    if( NULL == val || TYPE_DICT != val->type )
720        goto bad;
721
722    fileval = tr_bencDictFind( val, "file" );
723    dataval = tr_bencDictFind( val, "data" );
724    dirval  = tr_bencDictFind( val, "directory" );
725    autoval = tr_bencDictFind( val, "autostart" );
726    if( ( ( NULL == fileval || TYPE_STR != fileval->type )   &&
727          ( NULL == dataval || TYPE_STR != dataval->type ) ) ||
728        ( ( NULL != fileval && TYPE_STR == fileval->type )   &&
729          ( NULL != dataval && TYPE_STR == dataval->type ) ) ||
730          ( NULL != dirval  && TYPE_STR != dirval->type  )   ||
731          ( NULL != autoval && TYPE_INT != autoval->type ) )
732        goto bad;
733
734    dir = ( NULL == dirval ? nil :
735            [NSString stringWithCString: dirval->val.s.s
736                               encoding: NSUTF8StringEncoding] );
737    autobool = ( NULL == autoval || 0 == autoval->val.i ? NO : YES );
738
739    if( NULL != fileval )
740    {
741        file = [NSString stringWithCString: fileval->val.s.s
742                                  encoding: NSUTF8StringEncoding];
743        if( NULL == autoval )
744            res = [[[client controller] delegate]
745                      ipcAddTorrentFile: file
746                              directory: dir];
747        else
748            res = [[[client controller] delegate]
749                      ipcAddTorrentFileAutostart: file
750                                       directory: dir
751                                       autostart: autobool];
752    }
753    else
754    {
755        data = [NSData dataWithBytes: dataval->val.s.s
756                              length: dataval->val.s.i];
757        if( NULL == autoval )
758            res = [[[client controller] delegate]
759                      ipcAddTorrentData: data
760                              directory: dir];
761        else
762            res = [[[client controller] delegate]
763                      ipcAddTorrentDataAutostart: data
764                                       directory: dir
765                                       autostart: autobool];
766    }
767
768    /* XXX should send back info message with torrent ID */
769    if( res )
770        [client sendrespEmpty: IPC_MSG_OK tag: tag];
771    else
772        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
773    return;
774
775  bad:
776    NSLog( @"Got bad IPC packet" );
777    [client sendrespEmpty: IPC_MSG_BAD tag: tag];
778}
779
780void msg_getbool( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
781{
782    IPCClient * client = arg;
783   
784    fDefaults = [NSUserDefaults standardUserDefaults];
785
786    switch( msgid )
787    {
788        case IPC_MSG_GETAUTOMAP:
789            [client sendrespInt:IPC_MSG_AUTOMAP tag:tag val:[fDefaults boolForKey:@"NatTraversal"]];
790            break;
791        case IPC_MSG_GETAUTOSTART:
792            [client sendrespInt:IPC_MSG_AUTOSTART tag:tag val:[fDefaults boolForKey:@"AutoStartDownload"]];
793            break;
794        case IPC_MSG_GETPEX:
795            [client sendrespInt:IPC_MSG_PEX tag:tag val:[fDefaults boolForKey:@"PEXGlobal"]];
796            break;
797        default:
798            assert( 0 );
799            break;
800    }
801}
802
803void msg_getint( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
804{
805    IPCClient * client = arg;
806   
807    fDefaults = [NSUserDefaults standardUserDefaults];
808   
809    int theValue;
810   
811    switch( msgid )
812    {
813        case IPC_MSG_GETDOWNLIMIT:
814            if ( [fDefaults boolForKey:@"CheckDownload"] )
815                theValue = [fDefaults integerForKey:@"DownloadLimit"];
816            else
817                theValue = -1;
818            [client sendrespInt:IPC_MSG_DOWNLIMIT tag:tag val:theValue];
819            break;
820        case IPC_MSG_GETPORT:
821            [client sendrespInt:IPC_MSG_PORT tag:tag val:[fDefaults integerForKey:@"BindPort"]];
822            break;
823        case IPC_MSG_GETUPLIMIT:
824            if ( [fDefaults boolForKey:@"CheckUpload"] )
825                theValue = [fDefaults integerForKey:@"UploadLimit"];
826            else
827                theValue = -1;
828            [client sendrespInt:IPC_MSG_UPLIMIT tag:tag val:theValue];
829            break;
830        default:
831            assert( 0 );
832            break;
833    }
834}
835
836void msg_getstr( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
837{
838    IPCClient * client = arg;
839    NSString    * cryptoValue;
840
841    fDefaults = [NSUserDefaults standardUserDefaults];
842   
843    switch( msgid )
844    {
845           
846        case IPC_MSG_GETDIR:
847            [client sendrespStr:IPC_MSG_DIR tag:tag val:[fDefaults stringForKey:@"DownloadFolder"]];
848            break;
849           
850        case IPC_MSG_GETCRYPTO:
851            if ([fDefaults boolForKey: @"EncryptionPrefer"])
852                if ([fDefaults boolForKey: @"EncryptionRequire"])
853                    cryptoValue = @"required";
854                else
855                    cryptoValue = @"preferred";
856            else
857                cryptoValue = @"plaintext";
858           
859            [client sendrespStr:IPC_MSG_CRYPTO tag:tag val:cryptoValue];
860            break;
861           
862        default:
863            assert( 0 );
864            break;
865    }
866}
867
868void msg_setbool( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
869{
870    IPCClient * client = arg;
871
872    if( NULL == val || TYPE_INT != val->type )
873    {
874        NSLog( @"Got bad IPC packet" );
875        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
876        return;
877    }
878   
879    fDefaults = [NSUserDefaults standardUserDefaults];
880   
881    switch( msgid )
882    {
883        case IPC_MSG_AUTOMAP:
884            [fDefaults setBool:(bool)val->val.i forKey:@"NatTraversal"];
885            [fPrefsController setNat:nil];
886            [client sendrespEmpty:IPC_MSG_OK tag:tag];
887            break;
888        case IPC_MSG_AUTOSTART:
889            [fDefaults setBool:(bool)val->val.i forKey:@"AutoStartDownload"];
890            [client sendrespEmpty:IPC_MSG_OK tag:tag];
891            break;
892        case IPC_MSG_PEX:
893            [fDefaults setBool:(bool)val->val.i forKey:@"PEXGlobal"];
894            [fPrefsController setPEX:nil];
895            [client sendrespEmpty: IPC_MSG_OK tag: tag];
896            break;
897        default:
898            assert( 0 );
899            break;
900    }
901}
902
903void msg_setint( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
904{
905    IPCClient * client = arg;
906
907    if( NULL == val || TYPE_INT != val->type )
908    {
909        NSLog( @"Got bad IPC packet" );
910        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
911        return;
912    }
913   
914    fDefaults = [NSUserDefaults standardUserDefaults];
915    switch( msgid )
916    {
917        case IPC_MSG_DOWNLIMIT:
918            if ( val->val.i < 0 )
919                [fDefaults setBool:NO forKey:@"CheckDownload"];
920            else
921            {
922                [fDefaults setBool:YES forKey:@"CheckDownload"];
923                [fDefaults setInteger:val->val.i forKey:@"DownloadLimit"];
924            }
925            [fPrefsController updateLimitFields];
926            [fPrefsController applySpeedSettings: nil];
927            break;
928        case IPC_MSG_PORT:
929            [fPrefsController setPort:[NSNumber numberWithInt:val->val.i]];
930            [fPrefsController updatePortField];
931            break;
932        case IPC_MSG_UPLIMIT:
933            if ( val->val.i < 0 )
934                [fDefaults setBool:NO forKey:@"CheckUpload"];
935            else
936            {
937                [fDefaults setBool:YES forKey:@"CheckUpload"];
938                [fDefaults setInteger:val->val.i forKey:@"UploadLimit"];
939            }
940            [fPrefsController updateLimitFields];
941            [fPrefsController applySpeedSettings: nil];
942            break;
943        default:
944            assert( 0 );
945            break;
946    }
947    [client sendrespEmpty:IPC_MSG_OK tag:tag];
948}
949
950void msg_setstr( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
951{
952    IPCClient * client = arg;
953
954    if( NULL == val || TYPE_STR != val->type )
955    {
956        NSLog( @"Got bad IPC packet" );
957        [client sendrespEmpty: IPC_MSG_BAD tag: tag];
958        return;
959    }
960             
961    fDefaults = [NSUserDefaults standardUserDefaults];
962             
963    switch( msgid )
964    {
965        case IPC_MSG_DIR:
966             [fDefaults setObject:[NSString stringWithCString: val->val.s.s] forKey:@"DownloadFolder"];
967             [fDefaults setObject: @"Constant" forKey: @"DownloadChoice"];
968             [client sendrespEmpty: IPC_MSG_OK tag: tag];
969             break;
970           
971        case IPC_MSG_CRYPTO:
972            if(!strcasecmp(val->val.s.s, "required"))
973            {
974                [fDefaults setBool:YES  forKey: @"EncryptionPrefer"];
975                [fDefaults setBool:YES  forKey: @"EncryptionRequire"];
976            }
977           
978            else if(!strcasecmp(val->val.s.s, "preferred"))
979            {
980                [fDefaults setBool:YES  forKey: @"EncryptionPrefer"];
981                [fDefaults setBool:NO  forKey: @"EncryptionRequire"];
982            }
983           
984            else if(!strcasecmp(val->val.s.s, "plaintext"))
985            {
986                [fDefaults setBool:NO  forKey: @"EncryptionPrefer"];
987                [fDefaults setBool:NO  forKey: @"EncryptionRequire"];
988            }
989            [fPrefsController setEncryptionMode:nil];
990            [client sendrespEmpty: IPC_MSG_OK tag: tag];
991            break;
992           
993        default:
994             assert( 0 );
995             break;
996    }
997}
998
999void msg_empty( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
1000{
1001    IPCClient * client = arg;
1002
1003    switch( msgid )
1004    {
1005        case IPC_MSG_NOOP:
1006            [client sendrespEmpty: IPC_MSG_OK tag: tag];
1007            break;
1008        case IPC_MSG_QUIT:
1009            [[[client controller] delegate] ipcQuit];
1010            [client sendrespEmpty: IPC_MSG_OK tag: tag];
1011            break;
1012        default:
1013            assert( 0 );
1014            break;
1015    }
1016}
1017
1018void msg_sup( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
1019{
1020    IPCClient       * client = arg;
1021    benc_val_t        packet, * pkval, * name;
1022    struct ipc_info * ipc;
1023    int               ii;
1024    enum ipc_msg      found;
1025    uint8_t         * buf;
1026    size_t            size;
1027
1028    if( NULL == val || TYPE_LIST != val->type )
1029        goto bad;
1030
1031    ipc   = [client ipc];
1032    pkval = ipc_initval( ipc, IPC_MSG_SUP, tag, &packet, TYPE_LIST );
1033    if( NULL == pkval )
1034        goto fail;
1035    if( tr_bencListReserve( pkval, val->val.l.count ) )
1036    {
1037        tr_bencFree( &packet );
1038        goto fail;
1039    }
1040
1041    for( ii = 0; val->val.l.count > ii; ii++ )
1042    {
1043        name = &val->val.l.vals[ii];
1044        if( NULL == name || TYPE_STR != name->type )
1045            goto bad;
1046        found = ipc_msgid( ipc, name->val.s.s );
1047        if( IPC__MSG_COUNT == found || !ipc_ishandled( ipc, found ) )
1048        {
1049            continue;
1050        }
1051        tr_bencInitStr( tr_bencListAdd( pkval ),
1052                        name->val.s.s, name->val.s.i, 1 );
1053    }
1054
1055    buf = ipc_serialize( &packet, &size );
1056    tr_bencFree( &packet );
1057    if( NULL == buf )
1058        goto fail;
1059    [client sendresp: buf size: size ];
1060    return;
1061
1062  bad:
1063    NSLog( @"Got bad IPC packet" );
1064    [client sendrespEmpty: IPC_MSG_BAD tag: tag];
1065    return;
1066
1067  fail:
1068    NSLog( @"Failed to create IPC reply packet" );
1069    [[client controller] killclient: client];
1070}
1071
1072void msg_default( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
1073{
1074    IPCClient * client = arg;
1075
1076    [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
1077}
Note: See TracBrowser for help on using the repository browser.