source: trunk/macosx/IPCController.m @ 2043

Last change on this file since 2043 was 2043, checked in by joshe, 15 years ago

Send bad-format instead of not-supported where appropriate.
Implement supported message.

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