source: trunk/macosx/IPCController.m @ 4289

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

slightly better behavior when placing the not-available bar

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