source: trunk/macosx/IPCController.m @ 1966

Last change on this file since 1966 was 1966, checked in by livings124, 15 years ago

make some of the new code more the current style

File size: 25.4 KB
Line 
1/******************************************************************************
2 * $Id$
3 *
4 * Copyright (c) 2007 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
40static void
41getaddr( struct sockaddr_un * );
42static NSArray *
43bencarray( benc_val_t * val, int type );
44static void
45msg_lookup   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
46static void
47msg_info     ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
48void
49msg_infoall  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
50void
51msg_action   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
52void
53msg_actionall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
54void
55msg_addold   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
56void
57msg_addnew   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
58void
59msg_getbool  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
60void
61msg_getint   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
62void
63msg_getstr   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
64void
65msg_setbool  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
66void
67msg_setint   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
68void
69msg_setstr   ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
70static void
71msg_default  ( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg );
72
73@interface IPCClient : NSObject
74{
75    NSFileHandle  * _handle;
76    struct ipc_info _ipc;
77    IPCController * _controller;
78    NSMutableData * _buf;
79}
80
81- (id)              initClient: (IPCController *) controller
82                         funcs: (struct ipc_funcs *) funcs
83                        handle: (NSFileHandle *) handle;
84- (IPCController *) controller;
85- (struct ipc_info *)      ipc;
86- (void)               gotdata: (NSNotification *) notification;
87- (BOOL)              sendresp: (uint8_t *) buf
88                          size: (size_t) size;
89- (BOOL)         sendrespEmpty: (enum ipc_msg) msgid
90                           tag: (int64_t) tag;
91- (BOOL)           sendrespInt: (enum ipc_msg) msgid
92                           tag: (int64_t) tag
93                           val: (int64_t) val;
94- (BOOL)           sendrespStr: (enum ipc_msg) msgid
95                           tag: (int64_t) tag
96                           val: (NSString *) val;
97- (void)          sendrespInfo: (enum ipc_msg) respid
98                           tag: (int64_t) tag
99                      torrents: (NSArray *) tors
100                         types: (int) types;
101
102@end
103
104@interface IPCController (Private)
105
106- (void)  newclient: (NSNotification *) notification;
107- (void) killclient: (IPCClient *) client;
108
109@end
110
111@implementation IPCController
112
113- (id) init
114{
115    struct sockaddr_un sun;
116
117    self = [super init];
118    if( nil == self )
119        return nil;
120
121    getaddr( &sun );
122    unlink( sun.sun_path );
123    _sock    = [[NSSocketPort alloc]
124                   initWithProtocolFamily: PF_UNIX
125                               socketType: SOCK_STREAM
126                                 protocol: 0
127                                  address: [NSData dataWithBytes: &sun
128                                                          length: sizeof(sun)]];
129    _listen  = [[NSFileHandle alloc]
130                   initWithFileDescriptor: [_sock socket]
131                           closeOnDealloc: YES];
132    _funcs   = ipc_initmsgs();
133    _clients = [[NSMutableArray alloc] init];
134
135    /* XXX is this error checking bogus? */
136    if( nil  == _sock    ||
137        nil  == _listen  ||
138        NULL == _funcs   ||
139        nil  == _clients ||
140        0 > ipc_addmsg( _funcs, IPC_MSG_ADDMANYFILES, msg_addold    ) ||
141        0 > ipc_addmsg( _funcs, IPC_MSG_ADDONEFILE,   msg_addnew    ) ||
142        0 > ipc_addmsg( _funcs, IPC_MSG_AUTOMAP,      msg_setbool   ) ||
143        0 > ipc_addmsg( _funcs, IPC_MSG_AUTOSTART,    msg_setbool   ) ||
144        0 > ipc_addmsg( _funcs, IPC_MSG_DIR,          msg_setstr    ) ||
145        0 > ipc_addmsg( _funcs, IPC_MSG_DOWNLIMIT,    msg_setint    ) ||
146        0 > ipc_addmsg( _funcs, IPC_MSG_GETAUTOMAP,   msg_getbool   ) ||
147        0 > ipc_addmsg( _funcs, IPC_MSG_GETAUTOSTART, msg_getbool   ) ||
148        0 > ipc_addmsg( _funcs, IPC_MSG_GETDIR,       msg_getstr    ) ||
149        0 > ipc_addmsg( _funcs, IPC_MSG_GETDOWNLIMIT, msg_getint    ) ||
150        0 > ipc_addmsg( _funcs, IPC_MSG_GETINFO,      msg_info      ) ||
151        0 > ipc_addmsg( _funcs, IPC_MSG_GETINFOALL,   msg_infoall   ) ||
152        0 > ipc_addmsg( _funcs, IPC_MSG_GETPEX,       msg_getbool   ) ||
153        0 > ipc_addmsg( _funcs, IPC_MSG_GETPORT,      msg_getint    ) ||
154        0 > ipc_addmsg( _funcs, IPC_MSG_GETSTAT,      msg_info      ) ||
155        0 > ipc_addmsg( _funcs, IPC_MSG_GETSTATALL,   msg_infoall   ) ||
156        0 > ipc_addmsg( _funcs, IPC_MSG_GETUPLIMIT,   msg_getint    ) ||
157        0 > ipc_addmsg( _funcs, IPC_MSG_LOOKUP,       msg_lookup    ) ||
158        0 > ipc_addmsg( _funcs, IPC_MSG_PEX,          msg_setbool   ) ||
159        0 > ipc_addmsg( _funcs, IPC_MSG_PORT,         msg_setint    ) ||
160        0 > ipc_addmsg( _funcs, IPC_MSG_REMOVE,       msg_action    ) ||
161        0 > ipc_addmsg( _funcs, IPC_MSG_REMOVEALL,    msg_actionall ) ||
162        0 > ipc_addmsg( _funcs, IPC_MSG_START,        msg_action    ) ||
163        0 > ipc_addmsg( _funcs, IPC_MSG_STARTALL,     msg_actionall ) ||
164        0 > ipc_addmsg( _funcs, IPC_MSG_STOP,         msg_action    ) ||
165        0 > ipc_addmsg( _funcs, IPC_MSG_STOPALL,      msg_actionall ) ||
166        0 > ipc_addmsg( _funcs, IPC_MSG_UPLIMIT,      msg_setint    ) )
167    {
168        [self release];
169        return nil;
170    }
171    ipc_setdefmsg( _funcs, msg_default );
172
173    [[NSNotificationCenter defaultCenter]
174        addObserver: self
175           selector: @selector(newclient:)
176               name: NSFileHandleConnectionAcceptedNotification
177             object: _listen];
178    [_listen acceptConnectionInBackgroundAndNotify];
179
180    return self;
181}
182
183- (void) dealloc
184{
185    struct sockaddr_un sun;
186
187    [[NSNotificationCenter defaultCenter] removeObserver: self];
188    [_listen  release];
189    [_sock    release];
190    [_clients release];
191    ipc_freemsgs( _funcs );
192    getaddr( &sun );
193    unlink( sun.sun_path );
194    [super dealloc];
195}
196
197- (id) delegate
198{
199    return _delegate;
200}
201
202- (void) setDelegate: (id) newdelegate
203{
204    _delegate = newdelegate;
205}
206
207@end
208
209@implementation IPCController (Private)
210
211- (void) newclient: (NSNotification *) notification
212{
213    NSDictionary * info;
214    NSFileHandle * handle;
215    NSNumber     * error;
216    IPCClient    * client;
217
218    info   = [notification userInfo];
219    handle = [info objectForKey: NSFileHandleNotificationFileHandleItem];
220    error  = [info objectForKey: @"NSFileHandleError"];
221
222    if( nil != error )
223    {
224        NSLog( @"Failed to accept IPC socket connection: %@", error );
225        return;
226    }
227
228    [_listen acceptConnectionInBackgroundAndNotify];
229
230    if( nil == handle )
231        return;
232
233    client = [[IPCClient alloc]
234                 initClient: self
235                      funcs: _funcs
236                     handle: handle];
237    if( nil == client )
238        return;
239
240    [_clients addObject:client];
241    [client release];
242}
243
244- (void) killclient: (IPCClient *) client
245{
246    [_clients removeObject: client];
247}
248
249@end
250
251@implementation IPCClient
252
253- (id) initClient: (IPCController *) controller
254            funcs: (struct ipc_funcs *) funcs
255           handle: (NSFileHandle *) handle
256{
257    uint8_t * buf;
258    size_t    size;
259
260    self = [super init];
261    if( nil == self )
262        return nil;
263
264    _handle     = [handle retain];
265    ipc_newcon( &_ipc, funcs );
266    _controller = controller;
267    _buf        = [[NSMutableData alloc] init];
268
269    buf = ipc_mkvers( &size );
270    if( nil == _buf || NULL == buf || ![self sendresp: buf size: size] )
271    {
272        [self release];
273        return nil;
274    }
275
276    [[NSNotificationCenter defaultCenter]
277        addObserver: self
278           selector: @selector(gotdata:)
279               name: NSFileHandleReadCompletionNotification
280             object: _handle];
281    [_handle readInBackgroundAndNotify];
282
283    return self;
284}
285
286- (void) dealloc
287{
288    [[NSNotificationCenter defaultCenter] removeObserver: self];
289    [_handle release];
290    [_buf    release];
291    [super   dealloc];
292}
293
294- (IPCController *) controller
295{
296    return _controller;
297}
298
299- (struct ipc_info *) ipc
300{
301    return &_ipc;
302}
303
304- (void) gotdata: (NSNotification *) notification
305{
306    NSDictionary * info;
307    NSData       * data;
308    NSNumber     * error;
309    ssize_t        res;
310
311    info  = [notification userInfo];
312    data  = [info objectForKey: NSFileHandleNotificationDataItem];
313    error = [info objectForKey: @"NSFileHandleError"];
314
315    if( nil != error )
316    {
317        NSLog( @"Failed to read from IPC socket connection: %@", error );
318        [_controller killclient: self];
319        return;
320    }
321
322    if( nil == data || 0 == [data length] )
323    {
324        [_controller killclient: self];
325        return;
326    }
327
328    [_handle readInBackgroundAndNotify];
329    [_buf appendData: data];
330
331    if( IPC_MIN_MSG_LEN > [_buf length] )
332        return;
333
334    res = ipc_parse( &_ipc, [_buf mutableBytes], [_buf length], self );
335
336    if( 0 > res )
337    {
338        switch( errno )
339        {
340            case EPERM:
341                NSLog( @"IPC client has unsupported protocol version" );
342                break;
343            case EINVAL:
344                NSLog( @"IPC protocol parse error" );
345                break;
346            default:
347                NSLog( @"IPC parsing failed" );
348                break;
349        }
350        [_controller killclient: self];
351        return;
352    }
353    else if( 0 < res )
354    {
355        if( res > [_buf length])
356        {
357            memmove( [_buf mutableBytes], [_buf bytes] + res,
358                     [_buf length] - res );
359        }
360        [_buf setLength: ([_buf length] - res)];
361    }
362}
363
364- (BOOL) sendresp: (uint8_t *) buf
365             size: (size_t) size
366{
367    @try
368    {
369        [_handle writeData: [NSData dataWithBytesNoCopy: buf
370                                                 length: size
371                                           freeWhenDone: YES]];
372        return YES;
373    }
374    @catch( NSException * ex )
375    {
376        NSLog( @"Failed to write to IPC socket connection" );
377        return NO;
378    }
379}
380
381- (BOOL) sendrespEmpty: (enum ipc_msg) msgid
382                   tag: (int64_t) tag
383{
384    uint8_t * buf;
385    size_t    size;
386
387    buf = ipc_mkempty( &_ipc, &size, msgid, tag );
388    if( NULL == buf )
389        return FALSE;
390
391    return [self sendresp: buf
392                     size: size];
393}
394
395- (BOOL) sendrespInt: (enum ipc_msg) msgid
396                 tag: (int64_t) tag
397                 val: (int64_t) val
398{
399    uint8_t * buf;
400    size_t    size;
401
402    buf = ipc_mkint( &_ipc, &size, msgid, tag, val );
403    if( NULL == buf )
404        return FALSE;
405
406    return [self sendresp: buf
407                     size: size];
408}
409
410- (BOOL) sendrespStr: (enum ipc_msg) msgid
411                 tag: (int64_t) tag
412                 val: (NSString *) val
413{
414    uint8_t       * buf;
415    size_t          size;
416    NSData        * data;
417    NSMutableData * sucky;
418
419    if( [val canBeConvertedToEncoding: NSUTF8StringEncoding] )
420        buf = ipc_mkstr( &_ipc, &size, msgid, tag,
421                         [val cStringUsingEncoding: NSUTF8StringEncoding] );
422    else
423    {
424        data = [val dataUsingEncoding: NSUTF8StringEncoding
425                 allowLossyConversion: YES];
426        /* XXX this sucks, I should add a length argument to ipc_mkstr() */
427        sucky = [NSMutableData dataWithData: data];
428        [sucky appendBytes: "" length: 1];
429        buf = ipc_mkstr( &_ipc, &size, msgid, tag, [sucky bytes] );
430    }
431    if( NULL == buf )
432        return FALSE;
433
434    return [self sendresp: buf
435                     size: size];
436}
437
438- (void) sendrespInfo: (enum ipc_msg) respid
439                  tag: (int64_t) tag
440             torrents: (NSArray *) tors
441                types: (int) types
442{
443    benc_val_t     packet, * pkinf;
444    NSEnumerator * enumerator;
445    Torrent      * tor;
446    uint8_t      * buf;
447    size_t         size;
448    int            res;
449
450    pkinf = ipc_initval( &_ipc, respid, tag, &packet, TYPE_LIST );
451    if( NULL == pkinf )
452        goto fail;
453    if( tr_bencListReserve( pkinf, [tors count] ) )
454    {
455        tr_bencFree( &packet );
456        goto fail;
457    }
458
459    enumerator = [tors objectEnumerator];
460    while( nil != ( tor = [enumerator nextObject] ) )
461    {
462        if( IPC_MSG_INFO == respid )
463            res = ipc_addinfo( pkinf, [tor torrentID], [tor torrentInfo], types );
464        else
465            res = ipc_addstat( pkinf, [tor torrentID], [tor torrentInfo],
466                               [tor torrentStat], types );
467        if( 0 > res )
468        {
469            tr_bencFree( &packet );
470            goto fail;
471        }
472    }
473
474    buf = ipc_mkval( &packet, &size );
475    tr_bencFree( &packet );
476    if( NULL == buf )
477        goto fail;
478    [self sendresp: buf size: size ];
479    return;
480
481  fail:
482    NSLog( @"Failed to create IPC reply packet" );
483    [_controller killclient: self];
484}
485
486
487@end
488
489void
490getaddr( struct sockaddr_un * sun )
491{
492    bzero( sun, sizeof *sun );
493    sun->sun_family = AF_LOCAL;
494    strlcpy( sun->sun_path, tr_getPrefsDirectory(), sizeof sun->sun_path );
495    strlcat( sun->sun_path, "/socket", sizeof sun->sun_path );
496}
497
498NSArray *
499bencarray( benc_val_t * val, int type )
500{
501    int              ii;
502    NSMutableArray * ret;
503    benc_val_t     * item;
504
505    assert( TYPE_STR == type || TYPE_INT == type );
506
507    if( NULL == val || TYPE_LIST != val->type )
508        return nil;
509
510    ret = [NSMutableArray arrayWithCapacity: val->val.l.count];
511    for( ii = 0; ii < val->val.l.count; ii++ )
512    {
513        item = &val->val.l.vals[ii];
514        if( type != item->type )
515            return nil;
516        if( TYPE_STR == type )
517        {
518            [ret addObject: [NSString stringWithCString: item->val.s.s
519                                               encoding: NSUTF8StringEncoding]];
520        }
521        else
522        {
523            [ret addObject: [NSNumber numberWithLongLong: (long long) item->val.i]];
524        }
525    }
526
527    return ret;
528}
529
530void
531msg_lookup( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
532{
533    IPCClient      * client = arg;
534    NSArray        * hashes, * tors;
535    benc_val_t       packet, * pkinf;
536    NSEnumerator   * enumerator;
537    Torrent        * tor;
538    uint8_t        * buf;
539    size_t           size;
540
541    hashes = bencarray( val, TYPE_STR );
542    if( NULL == hashes )
543    {
544        [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
545        return;
546    }
547
548    tors  = [[[client controller] delegate] ipcGetTorrentsByHash: hashes];
549    [client sendrespInfo: IPC_MSG_INFO
550                     tag: tag
551                torrents: tors
552                   types: IPC_INF_HASH];
553}
554
555void
556msg_info( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
557{
558    IPCClient  * client = arg;
559    enum ipc_msg respid;
560    benc_val_t * typesval;
561    int          types;
562    NSArray    * ids, * tors;
563
564    if( NULL == val || TYPE_DICT != val->type )
565        goto bad;
566
567    typesval = tr_bencDictFind( val, "type" );
568    if( NULL == typesval || TYPE_LIST != typesval->type ||
569        nil == ( ids = bencarray( tr_bencDictFind( val, "id" ), TYPE_INT ) ) )
570        goto bad;
571
572    respid = ( IPC_MSG_GETINFO == msgid ? IPC_MSG_INFO : IPC_MSG_STAT );
573    tors   = [[[client controller] delegate] ipcGetTorrentsByID: ids];
574    types  = ipc_infotypes( respid, typesval );
575    [client sendrespInfo: respid tag: tag torrents: tors types: types];
576    return;
577
578  bad:
579    NSLog( @"Got bad IPC packet" );
580    [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
581}
582
583void
584msg_infoall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
585{
586    IPCClient  * client = arg;
587    enum ipc_msg respid;
588    int          types;
589    NSArray    * tors;
590
591    if( NULL == val || TYPE_LIST != val->type )
592    {
593        NSLog( @"Got bad IPC packet" );
594        [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
595        return;
596    }
597
598    respid = ( IPC_MSG_GETINFOALL == msgid ? IPC_MSG_INFO : IPC_MSG_STAT );
599    tors   = [[[client controller] delegate] ipcGetTorrentsByID: nil];
600    types  = ipc_infotypes( respid, val );
601    [client sendrespInfo: respid tag: tag torrents: tors types: types];
602}
603
604void
605msg_action( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
606{
607    IPCClient * client = arg;
608    BOOL        res;
609    NSArray   * ids, * tors;
610    id          delegate;
611
612    ids = bencarray( val, TYPE_INT );
613    if( nil == ids )
614    {
615        NSLog( @"Got bad IPC packet" );
616        [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
617        return;
618    }
619
620    delegate = [[client controller] delegate];
621    tors     = [delegate ipcGetTorrentsByID: ids];
622    switch( msgid )
623    {
624        case IPC_MSG_REMOVE:
625            res = [delegate ipcRemoveTorrents: tors];
626            break;
627        case IPC_MSG_START:
628            res = [delegate ipcStartTorrents: tors];
629            break;
630        case IPC_MSG_STOP:
631            res = [delegate ipcStopTorrents: tors];
632            break;
633        default:
634            assert( 0 );
635            return;
636    }
637
638    if( res )
639        [client sendrespEmpty: IPC_MSG_OK tag: tag];
640    else
641        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
642}
643
644void
645msg_actionall( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
646{
647    IPCClient * client = arg;
648    BOOL        res;
649    NSArray   * tors;
650    id          delegate;
651
652    delegate = [[client controller] delegate];
653    tors     = [delegate ipcGetTorrentsByID: nil];
654    switch( msgid )
655    {
656        case IPC_MSG_REMOVEALL:
657            res = [delegate ipcRemoveTorrents: tors];
658            break;
659        case IPC_MSG_STARTALL:
660            res = [delegate ipcStartTorrents: tors];
661            break;
662        case IPC_MSG_STOPALL:
663            res = [delegate ipcStopTorrents: tors];
664            break;
665        default:
666            assert( 0 );
667            return;
668    }
669
670    if( res )
671        [client sendrespEmpty: IPC_MSG_OK tag: tag];
672    else
673        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
674}
675
676void
677msg_addold( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
678{
679    IPCClient * client = arg;
680    NSArray   * paths;
681    BOOL        res;
682
683    paths = bencarray( val, TYPE_STR );
684    if( nil == paths )
685    {
686        NSLog( @"Got bad IPC packet" );
687        [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
688        return;
689    }
690
691    /* XXX should send back info message with torrent IDs */
692    if( [[[client controller] delegate] ipcAddTorrents: paths] )
693        [client sendrespEmpty: IPC_MSG_OK tag: tag];
694    else
695        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
696}
697
698void
699msg_addnew( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
700{
701    IPCClient  * client = arg;
702    benc_val_t * fileval, * dataval, * dirval, * autoval;
703    NSString   * file, * dir;
704    NSData     * data;
705    BOOL         autobool, res;
706
707    if( NULL == val || TYPE_DICT != val->type )
708        goto bad;
709
710    fileval = tr_bencDictFind( val, "file" );
711    dataval = tr_bencDictFind( val, "data" );
712    dirval  = tr_bencDictFind( val, "directory" );
713    autoval = tr_bencDictFind( val, "autostart" );
714    if( ( ( NULL == fileval || TYPE_STR != fileval->type )   &&
715          ( NULL == dataval || TYPE_STR != dataval->type ) ) ||
716        ( ( NULL != fileval && TYPE_STR == fileval->type )   &&
717          ( NULL != dataval && TYPE_STR == dataval->type ) ) ||
718          ( NULL != dirval  && TYPE_STR != dirval->type  )   ||
719          ( NULL != autoval && TYPE_INT != autoval->type ) )
720        goto bad;
721
722    dir = ( NULL == dirval ? nil :
723            [NSString stringWithCString: dirval->val.s.s
724                               encoding: NSUTF8StringEncoding] );
725    autobool = ( NULL == autoval || 0 == autoval->val.i ? NO : YES );
726
727    if( NULL != fileval )
728    {
729        file = [NSString stringWithCString: fileval->val.s.s
730                                  encoding: NSUTF8StringEncoding];
731        if( NULL == autoval )
732            res = [[[client controller] delegate]
733                      ipcAddTorrentFile: file
734                              directory: dir];
735        else
736            res = [[[client controller] delegate]
737                      ipcAddTorrentFileAutostart: file
738                                       directory: dir
739                                       autostart: autobool];
740    }
741    else
742    {
743        data = [NSData dataWithBytes: dataval->val.s.s
744                              length: dataval->val.s.i];
745        if( NULL == autoval )
746            res = [[[client controller] delegate]
747                      ipcAddTorrentData: data
748                              directory: dir];
749        else
750            res = [[[client controller] delegate]
751                      ipcAddTorrentDataAutostart: data
752                                       directory: dir
753                                       autostart: autobool];
754    }
755
756    /* XXX should send back info message with torrent ID */
757    if( res )
758        [client sendrespEmpty: IPC_MSG_OK tag: tag];
759    else
760        [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
761    return;
762
763  bad:
764    NSLog( @"Got bad IPC packet" );
765    [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
766}
767
768void
769msg_getbool( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
770{
771    IPCClient * client = arg;
772
773    switch( msgid )
774    {
775        case IPC_MSG_GETAUTOMAP:
776        case IPC_MSG_GETAUTOSTART:
777        case IPC_MSG_GETPEX:
778            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
779            break;
780        default:
781            assert( 0 );
782            break;
783    }
784}
785
786void
787msg_getint( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
788{
789    IPCClient * client = arg;
790
791    switch( msgid )
792    {
793        case IPC_MSG_GETDOWNLIMIT:
794        case IPC_MSG_GETPORT:
795        case IPC_MSG_GETUPLIMIT:
796            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
797            break;
798        default:
799            assert( 0 );
800            break;
801    }
802}
803
804void
805msg_getstr( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
806{
807    IPCClient * client = arg;
808
809    switch( msgid )
810    {
811        case IPC_MSG_GETDIR:
812            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
813            break;
814        default:
815            assert( 0 );
816            break;
817    }
818}
819
820void
821msg_setbool( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
822{
823    IPCClient * client = arg;
824
825    if( NULL == val || TYPE_INT != val->type )
826    {
827        NSLog( @"Got bad IPC packet" );
828        [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
829        return;
830    }
831
832    switch( msgid )
833    {
834        case IPC_MSG_AUTOMAP:
835        case IPC_MSG_AUTOSTART:
836        case IPC_MSG_PEX:
837            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
838            break;
839        default:
840            assert( 0 );
841            break;
842    }
843}
844
845void
846msg_setint( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
847{
848    IPCClient * client = arg;
849
850    if( NULL == val || TYPE_INT != val->type )
851    {
852        NSLog( @"Got bad IPC packet" );
853        [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
854        return;
855    }
856
857    switch( msgid )
858    {
859        case IPC_MSG_DOWNLIMIT:
860        case IPC_MSG_PORT:
861        case IPC_MSG_UPLIMIT:
862            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
863            break;
864        default:
865            assert( 0 );
866            break;
867    }
868}
869
870void
871msg_setstr( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
872{
873    IPCClient * client = arg;
874
875    if( NULL == val || TYPE_STR != val->type )
876    {
877        NSLog( @"Got bad IPC packet" );
878        [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
879        return;
880    }
881
882    switch( msgid )
883    {
884        case IPC_MSG_DIR:
885            [client sendrespEmpty: IPC_MSG_FAIL tag: tag];
886            break;
887        default:
888            assert( 0 );
889            break;
890    }
891}
892
893
894void
895msg_default( enum ipc_msg msgid, benc_val_t * val, int64_t tag, void * arg )
896{
897    IPCClient * client = arg;
898
899    switch( msgid )
900    {
901        case IPC_MSG_NOOP:
902            [client sendrespEmpty: IPC_MSG_OK tag: tag];
903            break;
904        case IPC_MSG_QUIT:
905            [[[client controller] delegate] ipcQuit];
906            [client sendrespEmpty: IPC_MSG_OK tag: tag];
907            break;
908        default:
909            [client sendrespEmpty: IPC_MSG_NOTSUP tag: tag];
910            break;
911    }
912}
Note: See TracBrowser for help on using the repository browser.