source: trunk/macosx/PrefsController.m @ 6024

Last change on this file since 6024 was 6024, checked in by livings124, 14 years ago

add ability to add and remove to the rpc access list

  • Property svn:keywords set to Date Rev Author Id
File size: 33.1 KB
Line 
1/******************************************************************************
2 * $Id: PrefsController.m 6024 2008-06-04 04:48:17Z livings124 $
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#import "PrefsController.h"
26#import "BlocklistDownloader.h"
27#import "NSApplicationAdditions.h"
28#import "NSStringAdditions.h"
29#import "UKKQueue.h"
30
31#define DOWNLOAD_FOLDER     0
32#define DOWNLOAD_TORRENT    2
33
34#define RPC_ACCESS_ALLOW    0
35#define RPC_ACCESS_BLOCK    1
36
37#define RPC_IP_ADD_TAG      0
38#define RPC_IP_REMOVE_TAG   1
39
40#define UPDATE_SECONDS 86400
41
42#define TOOLBAR_GENERAL     @"TOOLBAR_GENERAL"
43#define TOOLBAR_TRANSFERS   @"TOOLBAR_TRANSFERS"
44#define TOOLBAR_BANDWIDTH   @"TOOLBAR_BANDWIDTH"
45#define TOOLBAR_PEERS       @"TOOLBAR_PEERS"
46#define TOOLBAR_NETWORK     @"TOOLBAR_NETWORK"
47#define TOOLBAR_REMOTE      @"TOOLBAR_REMOTE"
48
49@interface PrefsController (Private)
50
51- (void) setPrefView: (id) sender;
52
53- (void) folderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
54- (void) incompleteFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
55- (void) importFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
56
57@end
58
59@implementation PrefsController
60
61- (id) initWithHandle: (tr_handle *) handle
62{
63    if ((self = [super initWithWindowNibName: @"PrefsWindow"]))
64    {
65        fDefaults = [NSUserDefaults standardUserDefaults];
66        fHandle = handle;
67       
68        //checks for old version speeds of -1
69        if ([fDefaults integerForKey: @"UploadLimit"] < 0)
70        {
71            [fDefaults setInteger: 20 forKey: @"UploadLimit"];
72            [fDefaults setBool: NO forKey: @"CheckUpload"];
73        }
74        if ([fDefaults integerForKey: @"DownloadLimit"] < 0)
75        {
76            [fDefaults setInteger: 20 forKey: @"DownloadLimit"];
77            [fDefaults setBool: NO forKey: @"CheckDownload"];
78        }
79       
80        //check for old version download location (before 1.1)
81        NSString * choice;
82        if ((choice = [fDefaults stringForKey: @"DownloadChoice"]))
83        {
84            [fDefaults setBool: [choice isEqualToString: @"Constant"] forKey: @"DownloadLocationConstant"];
85            [fDefaults setBool: YES forKey: @"DownloadAsk"];
86           
87            [fDefaults removeObjectForKey: @"DownloadChoice"];
88        }
89       
90        //set check for update to right value
91        [self setCheckForUpdate: nil];
92       
93        //set auto import
94        NSString * autoPath;
95        if ([fDefaults boolForKey: @"AutoImport"] && (autoPath = [fDefaults stringForKey: @"AutoImportDirectory"]))
96            [[UKKQueue sharedFileWatcher] addPath: [autoPath stringByExpandingTildeInPath]];
97       
98        //set encryption
99        [self setEncryptionMode: nil];
100       
101        //actually set bandwidth limits
102        [self applySpeedSettings: nil];
103       
104        //update rpc access list
105        fRPCAccessArray = [[fDefaults arrayForKey: @"RPCAccessList"] mutableCopy];
106        if (!fRPCAccessArray)
107            fRPCAccessArray = [[NSMutableArray arrayWithObject: [NSDictionary dictionaryWithObjectsAndKeys: @"127.0.0.1", @"IP",
108                                [NSNumber numberWithBool: YES], @"Allow", nil]] retain];
109        [self updateRPCAccessList];
110    }
111   
112    return self;
113}
114
115- (tr_handle *) handle
116{
117    return fHandle;
118}
119
120- (void) dealloc
121{
122    if (fPortStatusTimer)
123        [fPortStatusTimer invalidate];
124    if (fPortChecker)
125    {
126        [fPortChecker cancelProbe];
127        [fPortChecker release];
128    }
129   
130    [fRPCAccessArray release];
131   
132    [super dealloc];
133}
134
135- (void) awakeFromNib
136{
137    fHasLoaded = YES;
138   
139    NSToolbar * toolbar = [[NSToolbar alloc] initWithIdentifier: @"Preferences Toolbar"];
140    [toolbar setDelegate: self];
141    [toolbar setAllowsUserCustomization: NO];
142    [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
143    [toolbar setSizeMode: NSToolbarSizeModeRegular];
144    [toolbar setSelectedItemIdentifier: TOOLBAR_GENERAL];
145    [[self window] setToolbar: toolbar];
146    [toolbar release];
147   
148    [self setPrefView: nil];
149   
150    if (![NSApp isOnLeopardOrBetter])
151    {
152        [fRPCAddRemoveControl sizeToFit];
153        [fRPCAddRemoveControl setLabel: @"+" forSegment: RPC_IP_ADD_TAG];
154        [fRPCAddRemoveControl setLabel: @"-" forSegment: RPC_IP_REMOVE_TAG];
155    }
156   
157    //set download folder
158    [fFolderPopUp selectItemAtIndex: [fDefaults boolForKey: @"DownloadLocationConstant"] ? DOWNLOAD_FOLDER : DOWNLOAD_TORRENT];
159   
160    //set stop ratio
161    [self updateRatioStopField];
162   
163    //set limits
164    [self updateLimitFields];
165   
166    //set speed limit
167    [fSpeedLimitUploadField setIntValue: [fDefaults integerForKey: @"SpeedLimitUploadLimit"]];
168    [fSpeedLimitDownloadField setIntValue: [fDefaults integerForKey: @"SpeedLimitDownloadLimit"]];
169   
170    //set port
171    [fPortField setIntValue: [fDefaults integerForKey: @"BindPort"]];
172    fNatStatus = -1;
173   
174    [self updatePortStatus];
175    fPortStatusTimer = [NSTimer scheduledTimerWithTimeInterval: 5.0 target: self
176                        selector: @selector(updatePortStatus) userInfo: nil repeats: YES];
177   
178    //set peer connections
179    [fPeersGlobalField setIntValue: [fDefaults integerForKey: @"PeersTotal"]];
180    [fPeersTorrentField setIntValue: [fDefaults integerForKey: @"PeersTorrent"]];
181   
182    //set queue values
183    [fQueueDownloadField setIntValue: [fDefaults integerForKey: @"QueueDownloadNumber"]];
184    [fQueueSeedField setIntValue: [fDefaults integerForKey: @"QueueSeedNumber"]];
185    [fStalledField setIntValue: [fDefaults integerForKey: @"StalledMinutes"]];
186   
187    //set blocklist
188    [self updateBlocklistFields];
189   
190    //set rpc port
191    [fRPCPortField setIntValue: [fDefaults integerForKey: @"RPCPort"]];
192}
193
194- (void) setUpdater: (SUUpdater *) updater
195{
196    fUpdater = updater;
197}
198
199- (NSToolbarItem *) toolbar: (NSToolbar *) toolbar itemForItemIdentifier: (NSString *) ident willBeInsertedIntoToolbar: (BOOL) flag
200{
201    NSToolbarItem * item = [[NSToolbarItem alloc] initWithItemIdentifier: ident];
202
203    if ([ident isEqualToString: TOOLBAR_GENERAL])
204    {
205        [item setLabel: NSLocalizedString(@"General", "Preferences -> toolbar item title")];
206        [item setImage: [NSImage imageNamed: [NSApp isOnLeopardOrBetter] ? NSImageNamePreferencesGeneral : @"Preferences.png"]];
207        [item setTarget: self];
208        [item setAction: @selector(setPrefView:)];
209        [item setAutovalidates: NO];
210    }
211    else if ([ident isEqualToString: TOOLBAR_TRANSFERS])
212    {
213        [item setLabel: NSLocalizedString(@"Transfers", "Preferences -> toolbar item title")];
214        [item setImage: [NSImage imageNamed: @"Transfers.png"]];
215        [item setTarget: self];
216        [item setAction: @selector(setPrefView:)];
217        [item setAutovalidates: NO];
218    }
219    else if ([ident isEqualToString: TOOLBAR_BANDWIDTH])
220    {
221        [item setLabel: NSLocalizedString(@"Bandwidth", "Preferences -> toolbar item title")];
222        [item setImage: [NSImage imageNamed: @"Bandwidth.png"]];
223        [item setTarget: self];
224        [item setAction: @selector(setPrefView:)];
225        [item setAutovalidates: NO];
226    }
227    else if ([ident isEqualToString: TOOLBAR_PEERS])
228    {
229        [item setLabel: NSLocalizedString(@"Peers", "Preferences -> toolbar item title")];
230        [item setImage: [NSImage imageNamed: [NSApp isOnLeopardOrBetter] ? NSImageNameUserGroup : @"Peers.png"]];
231        [item setTarget: self];
232        [item setAction: @selector(setPrefView:)];
233        [item setAutovalidates: NO];
234    }
235    else if ([ident isEqualToString: TOOLBAR_NETWORK])
236    {
237        [item setLabel: NSLocalizedString(@"Network", "Preferences -> toolbar item title")];
238        [item setImage: [NSImage imageNamed: [NSApp isOnLeopardOrBetter] ? NSImageNameNetwork : @"Network.png"]];
239        [item setTarget: self];
240        [item setAction: @selector(setPrefView:)];
241        [item setAutovalidates: NO];
242    }
243    else if ([ident isEqualToString: TOOLBAR_REMOTE])
244    {
245        [item setLabel: NSLocalizedString(@"Remote", "Preferences -> toolbar item title")];
246        [item setImage: [NSImage imageNamed: [NSApp isOnLeopardOrBetter] ? NSImageNameNetwork : @"Network.png"]];
247        [item setTarget: self];
248        [item setAction: @selector(setPrefView:)];
249        [item setAutovalidates: NO];
250    }
251    else
252    {
253        [item release];
254        return nil;
255    }
256
257    return [item autorelease];
258}
259
260- (NSArray *) toolbarSelectableItemIdentifiers: (NSToolbar *) toolbar
261{
262    return [self toolbarDefaultItemIdentifiers: toolbar];
263}
264
265- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
266{
267    return [self toolbarAllowedItemIdentifiers: toolbar];
268}
269
270- (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
271{
272    return [NSArray arrayWithObjects: TOOLBAR_GENERAL, TOOLBAR_TRANSFERS, TOOLBAR_BANDWIDTH,
273                                        TOOLBAR_PEERS, TOOLBAR_NETWORK, TOOLBAR_REMOTE, nil];
274}
275
276//used by ipc
277- (void) updatePortField
278{
279    [fPortField setIntValue: [fDefaults integerForKey: @"BindPort"]];
280}
281
282- (void) setPort: (id) sender
283{
284    int port = [sender intValue];
285    [fDefaults setInteger: port forKey: @"BindPort"];
286    tr_sessionSetPeerPort(fHandle, port);
287   
288    fPeerPort = -1;
289    [self updatePortStatus];
290}
291
292- (void) setNat: (id) sender
293{
294    tr_sessionSetPortForwardingEnabled(fHandle, [fDefaults boolForKey: @"NatTraversal"]);
295   
296    fNatStatus = -1;
297    [self updatePortStatus];
298}
299
300- (void) updatePortStatus
301{
302    const tr_port_forwarding fwd = tr_sessionGetPortForwarding(fHandle);
303    const int port = tr_sessionGetPeerPort(fHandle);
304
305    if (fNatStatus != fwd || fPeerPort != port )
306    {
307        fNatStatus = fwd;
308        fPeerPort = port;
309       
310        [fPortStatusField setStringValue: [NSLocalizedString(@"Checking port status", "Preferences -> Network -> port status")
311            stringByAppendingEllipsis]];
312        [fPortStatusImage setImage: nil];
313        [fPortStatusProgress startAnimation: self];
314       
315        if (fPortChecker)
316        {
317            [fPortChecker cancelProbe];
318            [fPortChecker release];
319        }
320        fPortChecker = [[PortChecker alloc] initForPort: fPeerPort withDelegate: self];
321    }
322}
323
324- (void) portCheckerDidFinishProbing: (PortChecker *) portChecker
325{
326    [fPortStatusProgress stopAnimation: self];
327    switch ([fPortChecker status])
328    {
329        case PORT_STATUS_OPEN:
330            [fPortStatusField setStringValue: NSLocalizedString(@"Port is open", "Preferences -> Network -> port status")];
331            [fPortStatusImage setImage: [NSImage imageNamed: @"GreenDot.png"]];
332            break;
333        case PORT_STATUS_CLOSED:
334            [fPortStatusField setStringValue: NSLocalizedString(@"Port is closed", "Preferences -> Network -> port status")];
335            [fPortStatusImage setImage: [NSImage imageNamed: @"RedDot.png"]];
336            break;
337        case PORT_STATUS_STEALTH:
338            [fPortStatusField setStringValue: NSLocalizedString(@"Port is stealth", "Preferences -> Network -> port status")];
339            [fPortStatusImage setImage: [NSImage imageNamed: @"RedDot.png"]];
340            break;
341        case PORT_STATUS_ERROR:
342            [fPortStatusField setStringValue: NSLocalizedString(@"Unable to check port status",
343                                                "Preferences -> Network -> port status")];
344            [fPortStatusImage setImage: [NSImage imageNamed: @"YellowDot.png"]];
345            break;
346    }
347    [fPortChecker release];
348    fPortChecker = nil;
349}
350
351- (NSArray *) sounds
352{
353    NSMutableArray * sounds = [NSMutableArray array];
354   
355    NSMutableArray * directories = [NSMutableArray arrayWithObjects: @"/System/Library/Sounds", @"/Library/Sounds", nil];
356    if ([NSApp isOnLeopardOrBetter])
357        [directories addObject: [NSHomeDirectory() stringByAppendingPathComponent: @"Library/Sounds"]];
358   
359    BOOL isDirectory;
360    NSString * directory;
361    NSEnumerator * enumerator = [directories objectEnumerator];
362    while ((directory = [enumerator nextObject]))
363        if ([[NSFileManager defaultManager] fileExistsAtPath: directory isDirectory: &isDirectory] && isDirectory)
364        {
365            NSString * sound;
366            NSEnumerator * soundEnumerator = [[[NSFileManager defaultManager] directoryContentsAtPath: directory] objectEnumerator];
367            while ((sound = [soundEnumerator nextObject]))
368            {
369                sound = [sound stringByDeletingPathExtension];
370                if ([NSSound soundNamed: sound])
371                    [sounds addObject: sound];
372            }
373        }
374   
375    return sounds;
376}
377
378- (void) setSound: (id) sender
379{
380    //play sound when selecting
381    NSSound * sound;
382    if ((sound = [NSSound soundNamed: [sender titleOfSelectedItem]]))
383        [sound play];
384}
385
386- (void) setPeersGlobal: (id) sender
387{
388    int count = [sender intValue];
389    [fDefaults setInteger: count forKey: @"PeersTotal"];
390    tr_sessionSetPeerLimit(fHandle, count);
391}
392
393- (void) setPeersTorrent: (id) sender
394{
395    int count = [sender intValue];
396    [fDefaults setInteger: count forKey: @"PeersTorrent"];
397}
398
399- (void) setPEX: (id) sender
400{
401    tr_sessionSetPexEnabled(fHandle, [fDefaults boolForKey: @"PEXGlobal"]);
402}
403
404- (void) setEncryptionMode: (id) sender
405{
406    tr_sessionSetEncryption(fHandle, [fDefaults boolForKey: @"EncryptionPrefer"] ?
407        ([fDefaults boolForKey: @"EncryptionRequire"] ? TR_ENCRYPTION_REQUIRED : TR_ENCRYPTION_PREFERRED) : TR_PLAINTEXT_PREFERRED);
408}
409
410- (void) setBlocklistEnabled: (id) sender
411{
412    BOOL enable = [sender state] == NSOnState;
413    [fDefaults setBool: enable forKey: @"Blocklist"];
414    tr_blocklistSetEnabled(fHandle, enable);
415}
416
417- (void) updateBlocklist: (id) sender
418{
419    [BlocklistDownloader downloadWithPrefsController: self];
420}
421
422- (void) updateBlocklistFields
423{
424    BOOL exists = tr_blocklistExists(fHandle);
425   
426    if (exists)
427    {
428        NSNumberFormatter * numberFormatter = [[NSNumberFormatter alloc] init];
429        [numberFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
430        [numberFormatter setMaximumFractionDigits: 0];
431        NSString * countString = [numberFormatter stringFromNumber: [NSNumber numberWithInt: tr_blocklistGetRuleCount(fHandle)]];
432        [numberFormatter release];
433       
434        [fBlocklistMessageField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ IP address rules in list",
435            "Prefs -> blocklist -> message"), countString]];
436    }
437    else
438        [fBlocklistMessageField setStringValue: NSLocalizedString(@"A blocklist must first be downloaded",
439            "Prefs -> blocklist -> message")];
440   
441    [fBlocklistEnableCheck setEnabled: exists];
442    [fBlocklistEnableCheck setState: exists && [fDefaults boolForKey: @"Blocklist"]];
443}
444
445- (void) applySpeedSettings: (id) sender
446{
447    if ([fDefaults boolForKey: @"SpeedLimit"])
448    {
449        tr_sessionSetSpeedLimitEnabled(fHandle, TR_UP, 1);
450        tr_sessionSetSpeedLimit(fHandle, TR_UP, [fDefaults integerForKey: @"SpeedLimitUploadLimit"]);
451       
452        tr_sessionSetSpeedLimitEnabled(fHandle, TR_DOWN, 1);
453        tr_sessionSetSpeedLimit(fHandle, TR_DOWN, [fDefaults integerForKey: @"SpeedLimitDownloadLimit"]);
454    }
455    else
456    {
457        tr_sessionSetSpeedLimitEnabled(fHandle, TR_UP, [fDefaults boolForKey: @"CheckUpload"]);
458        tr_sessionSetSpeedLimit(fHandle, TR_UP, [fDefaults integerForKey: @"UploadLimit"]);
459       
460        tr_sessionSetSpeedLimitEnabled(fHandle, TR_DOWN, [fDefaults boolForKey: @"CheckDownload"]);
461        tr_sessionSetSpeedLimit(fHandle, TR_DOWN, [fDefaults integerForKey: @"DownloadLimit"]);
462    }
463}
464
465- (void) applyRatioSetting: (id) sender
466{
467    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
468}
469
470- (void) updateRatioStopField
471{
472    if (!fHasLoaded)
473        return;
474   
475    [fRatioStopField setFloatValue: [fDefaults floatForKey: @"RatioLimit"]];
476   
477    [self applyRatioSetting: nil];
478}
479
480- (void) setRatioStop: (id) sender
481{
482    [fDefaults setFloat: [sender floatValue] forKey: @"RatioLimit"];
483    [self applyRatioSetting: nil];
484}
485
486- (void) updateLimitFields
487{
488    if (!fHasLoaded)
489        return;
490   
491    [fUploadField setIntValue: [fDefaults integerForKey: @"UploadLimit"]];
492    [fDownloadField setIntValue: [fDefaults integerForKey: @"DownloadLimit"]];
493}
494
495- (void) setGlobalLimit: (id) sender
496{
497    [fDefaults setInteger: [sender intValue] forKey: sender == fUploadField ? @"UploadLimit" : @"DownloadLimit"];
498    [self applySpeedSettings: self];
499}
500
501- (void) setSpeedLimit: (id) sender
502{
503    [fDefaults setInteger: [sender intValue] forKey: sender == fSpeedLimitUploadField
504                                                        ? @"SpeedLimitUploadLimit" : @"SpeedLimitDownloadLimit"];
505    [self applySpeedSettings: self];
506}
507
508- (void) setAutoSpeedLimit: (id) sender
509{
510    [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoSpeedLimitChange" object: self];
511}
512
513- (BOOL) control: (NSControl *) control textShouldBeginEditing: (NSText *) fieldEditor
514{
515    [fInitialString release];
516    fInitialString = [[control stringValue] retain];
517   
518    return YES;
519}
520
521- (BOOL) control: (NSControl *) control didFailToFormatString: (NSString *) string errorDescription: (NSString *) error
522{
523    NSBeep();
524    if (fInitialString)
525    {
526        [control setStringValue: fInitialString];
527        [fInitialString release];
528        fInitialString = nil;
529    }
530    return NO;
531}
532
533- (void) setBadge: (id) sender
534{
535    [[NSNotificationCenter defaultCenter] postNotificationName: @"DockBadgeChange" object: self];
536}
537
538- (void) resetWarnings: (id) sender
539{
540    [fDefaults setBool: YES forKey: @"WarningDuplicate"];
541    [fDefaults setBool: YES forKey: @"WarningRemainingSpace"];
542    [fDefaults setBool: YES forKey: @"WarningFolderDataSameName"];
543    [fDefaults setBool: YES forKey: @"WarningResetStats"];
544    [fDefaults setBool: YES forKey: @"WarningCreatorBlankAddress"];
545    [fDefaults setBool: YES forKey: @"WarningRemoveBuiltInTracker"];
546}
547
548- (void) setCheckForUpdate: (id) sender
549{
550    NSTimeInterval seconds = [fDefaults boolForKey: @"CheckForUpdates"] ? UPDATE_SECONDS : 0;
551    [fDefaults setInteger: seconds forKey: @"SUScheduledCheckInterval"];
552    if (fUpdater)
553        [fUpdater scheduleCheckWithInterval: seconds];
554}
555
556- (void) setQueue: (id) sender
557{
558    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateQueue" object: self];
559}
560
561- (void) setQueueNumber: (id) sender
562{
563    [fDefaults setInteger: [sender intValue] forKey: sender == fQueueDownloadField ? @"QueueDownloadNumber" : @"QueueSeedNumber"];
564    [self setQueue: nil];
565}
566
567- (void) setStalled: (id) sender
568{
569    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateQueue" object: self];
570}
571
572- (void) setStalledMinutes: (id) sender
573{
574    [fDefaults setInteger: [sender intValue] forKey: @"StalledMinutes"];
575    [self setStalled: nil];
576}
577
578- (void) setDownloadLocation: (id) sender
579{
580    [fDefaults setBool: [fFolderPopUp indexOfSelectedItem] == DOWNLOAD_FOLDER forKey: @"DownloadLocationConstant"];
581}
582
583- (void) folderSheetShow: (id) sender
584{
585    NSOpenPanel * panel = [NSOpenPanel openPanel];
586
587    [panel setPrompt: NSLocalizedString(@"Select", "Preferences -> Open panel prompt")];
588    [panel setAllowsMultipleSelection: NO];
589    [panel setCanChooseFiles: NO];
590    [panel setCanChooseDirectories: YES];
591    [panel setCanCreateDirectories: YES];
592
593    [panel beginSheetForDirectory: nil file: nil types: nil
594        modalForWindow: [self window] modalDelegate: self didEndSelector:
595        @selector(folderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
596}
597
598- (void) incompleteFolderSheetShow: (id) sender
599{
600    NSOpenPanel * panel = [NSOpenPanel openPanel];
601
602    [panel setPrompt: NSLocalizedString(@"Select", "Preferences -> Open panel prompt")];
603    [panel setAllowsMultipleSelection: NO];
604    [panel setCanChooseFiles: NO];
605    [panel setCanChooseDirectories: YES];
606    [panel setCanCreateDirectories: YES];
607
608    [panel beginSheetForDirectory: nil file: nil types: nil
609        modalForWindow: [self window] modalDelegate: self didEndSelector:
610        @selector(incompleteFolderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
611}
612
613- (void) setAutoImport: (id) sender
614{
615    NSString * path;
616    if ((path = [fDefaults stringForKey: @"AutoImportDirectory"]))
617    {
618        path = [path stringByExpandingTildeInPath];
619        if ([fDefaults boolForKey: @"AutoImport"])
620            [[UKKQueue sharedFileWatcher] addPath: path];
621        else
622            [[UKKQueue sharedFileWatcher] removePathFromQueue: path];
623       
624        [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoImportSettingChange" object: self];
625    }
626    else
627        [self importFolderSheetShow: nil];
628}
629
630- (void) importFolderSheetShow: (id) sender
631{
632    NSOpenPanel * panel = [NSOpenPanel openPanel];
633
634    [panel setPrompt: NSLocalizedString(@"Select", "Preferences -> Open panel prompt")];
635    [panel setAllowsMultipleSelection: NO];
636    [panel setCanChooseFiles: NO];
637    [panel setCanChooseDirectories: YES];
638    [panel setCanCreateDirectories: YES];
639
640    [panel beginSheetForDirectory: nil file: nil types: nil
641        modalForWindow: [self window] modalDelegate: self didEndSelector:
642        @selector(importFolderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
643}
644
645- (void) setAutoSize: (id) sender
646{
647    [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoSizeSettingChange" object: self];
648}
649
650- (void) setRPCEnabled: (id) sender
651{
652    tr_sessionSetRPCEnabled(fHandle, [fDefaults boolForKey: @"RPC"]);
653}
654
655- (void) setRPCPort: (id) sender
656{
657    int port = [sender intValue];
658    [fDefaults setInteger: port forKey: @"RPCPort"];
659    tr_sessionSetRPCPort(fHandle, port);
660}
661
662- (void) updateRPCAccessList
663{
664    NSMutableArray * components = [NSMutableArray arrayWithCapacity: [fRPCAccessArray count]];
665   
666    NSEnumerator * enumerator = [fRPCAccessArray objectEnumerator];
667    NSDictionary * dict;
668    while ((dict = [enumerator nextObject]))
669        [components addObject: [NSString stringWithFormat: @"%c%@", [[dict objectForKey: @"Allow"] boolValue] ? '+' : '-',
670                                [dict objectForKey: @"IP"]]];
671   
672    NSString * string = [components componentsJoinedByString: @","];NSLog(string);
673   
674    #warning check for an error!
675    tr_sessionSetRPCACL(fHandle, [string UTF8String], NULL);
676}
677
678- (void) addRemoveRPCIP: (id) sender
679{
680    //don't allow add/remove when currently adding - it leads to weird results
681    if ([fRPCAccessTable editedRow] != -1)
682        return;
683   
684    if ([[sender cell] tagForSegment: [sender selectedSegment]] == RPC_IP_REMOVE_TAG)
685    {
686        [fRPCAccessArray removeObjectsAtIndexes: [fRPCAccessTable selectedRowIndexes]];
687        [fRPCAccessTable deselectAll: self];
688        [fRPCAccessTable reloadData];
689       
690        [fDefaults setObject: fRPCAccessArray forKey: @"RPCAccessList"];
691        [self updateRPCAccessList];
692    }
693    else
694    {
695        [fRPCAccessArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: @"", @"IP",
696                                        [NSNumber numberWithBool: YES], @"Allow", nil]];
697        [fRPCAccessTable reloadData];
698       
699        int row = [fRPCAccessArray count] - 1;
700        [fRPCAccessTable selectRow: row byExtendingSelection: NO];
701        [fRPCAccessTable editColumn: 0 row: row withEvent: nil select: YES];
702    }
703}
704
705- (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView
706{
707    return [fRPCAccessArray count];
708}
709
710- (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row
711{
712    NSDictionary * dict = [fRPCAccessArray objectAtIndex: row];
713   
714    NSString * ident = [tableColumn identifier];
715    if ([ident isEqualToString: @"Permission"])
716    {
717        int allow = [[dict objectForKey: @"Allow"] boolValue] ? RPC_ACCESS_ALLOW : RPC_ACCESS_BLOCK;
718        return [NSNumber numberWithInt: allow];
719    }
720    else
721        return [dict objectForKey: @"IP"];
722}
723
724- (void) tableView: (NSTableView *) tableView setObjectValue: (id) object forTableColumn: (NSTableColumn *) tableColumn
725    row: (NSInteger) row
726{
727    NSDictionary * oldDict = [fRPCAccessArray objectAtIndex: row], * newDict;
728   
729    NSString * ident = [tableColumn identifier];
730    if ([ident isEqualToString: @"Permission"])
731    {
732        NSNumber * allow = [NSNumber numberWithBool: [object intValue] == RPC_ACCESS_ALLOW];
733        newDict = [NSDictionary dictionaryWithObjectsAndKeys: [oldDict objectForKey: @"IP"], @"IP", allow, @"Allow", nil];
734    }
735    else
736    {
737        //verify ip
738        NSArray * components = [object componentsSeparatedByString: @"."];
739        BOOL valid = [components count] == 4;
740       
741        NSMutableArray * newComponents;
742        if (valid)
743        {
744            newComponents = [NSMutableArray arrayWithCapacity: 4];
745           
746            NSEnumerator * enumerator = [components objectEnumerator];
747            NSString * component;
748            while ((component = [enumerator nextObject]))
749            {
750                if ([component isEqualToString: @"*"])
751                    [newComponents addObject: component];
752                else
753                {
754                    int value = [component intValue];
755                    if (value >= 0 && value < 256)
756                        [newComponents addObject: [[NSNumber numberWithInt: value] stringValue]];
757                    else
758                    {
759                        valid = NO;
760                        break;
761                    }
762                }
763            }
764        }
765       
766        if (!valid)
767        {
768            NSBeep();
769           
770            if ([[oldDict objectForKey: @"IP"] isEqualToString: @""])
771            {
772                [fRPCAccessArray removeObjectAtIndex: row];
773                [fRPCAccessTable deselectAll: self];
774                [fRPCAccessTable reloadData];
775            }
776           
777            return;
778        }
779       
780        newDict = [NSDictionary dictionaryWithObjectsAndKeys: [newComponents componentsJoinedByString: @"."], @"IP",
781                    [oldDict objectForKey: @"Allow"], @"Allow", nil];
782    }
783   
784    [fRPCAccessArray replaceObjectAtIndex: row withObject: newDict];
785   
786    [fDefaults setObject: fRPCAccessArray forKey: @"RPCAccessList"];
787    [self updateRPCAccessList];
788}
789
790- (void) tableViewSelectionDidChange: (NSNotification *) notification
791{
792    [fRPCAddRemoveControl setEnabled: [fRPCAccessTable numberOfSelectedRows] > 0 forSegment: RPC_IP_REMOVE_TAG];
793}
794
795- (void) helpForPeers: (id) sender
796{
797    [[NSHelpManager sharedHelpManager] openHelpAnchor: @"PeersPrefs"
798        inBook: [[NSBundle mainBundle] objectForInfoDictionaryKey: @"CFBundleHelpBookName"]];
799}
800
801- (void) helpForNetwork: (id) sender
802{
803    [[NSHelpManager sharedHelpManager] openHelpAnchor: @"NetworkPrefs"
804        inBook: [[NSBundle mainBundle] objectForInfoDictionaryKey: @"CFBundleHelpBookName"]];
805}
806
807- (void) rpcUpdatePrefs
808{
809    //encryption
810    tr_encryption_mode encryptionMode = tr_sessionGetEncryption(fHandle);
811    [fDefaults setBool: encryptionMode != TR_PLAINTEXT_PREFERRED forKey: @"EncryptionPrefer"];
812    [fDefaults setBool: encryptionMode == TR_ENCRYPTION_PREFERRED forKey: @"EncryptionPrefer"];
813   
814    //download directory
815    #warning missing!
816   
817    //peers
818    uint16_t peersTotal = tr_sessionGetPeerLimit(fHandle);
819    [fDefaults setInteger: peersTotal forKey: @"PeersTotal"];
820   
821    //pex
822    BOOL pex = tr_sessionIsPexEnabled(fHandle);
823    [fDefaults setBool: pex forKey: @"PEXGlobal"];
824   
825    //port
826    int port = tr_sessionGetPeerPort(fHandle);
827    [fDefaults setInteger: port forKey: @"BindPort"];
828   
829    BOOL nat = tr_sessionIsPortForwardingEnabled(fHandle);
830    [fDefaults setBool: nat forKey: @"NatTraversal"];
831   
832    fPeerPort = -1;
833    fNatStatus = -1;
834    [self updatePortStatus];
835   
836    //speed limit - down
837    BOOL downLimitEnabled = tr_sessionIsSpeedLimitEnabled(fHandle, TR_DOWN);
838    [fDefaults setBool: downLimitEnabled forKey: @"CheckDownload"];
839   
840    int downLimit = tr_sessionGetSpeedLimit(fHandle, TR_DOWN);
841    [fDefaults setInteger: downLimit forKey: @"DownloadLimit"];
842   
843    //speed limit - up
844    BOOL upLimitEnabled = tr_sessionIsSpeedLimitEnabled(fHandle, TR_UP);
845    [fDefaults setBool: upLimitEnabled forKey: @"CheckUpload"];
846   
847    int upLimit = tr_sessionGetSpeedLimit(fHandle, TR_UP);
848    [fDefaults setInteger: upLimit forKey: @"UploadLimit"];
849   
850    //update gui if loaded
851    if (fHasLoaded)
852    {
853        //encryption handled by bindings
854       
855        [fPeersGlobalField setIntValue: peersTotal];
856       
857        //pex handled by bindings
858       
859        [fPortField setIntValue: port];
860        //port forwarding (nat) handled by bindings
861       
862        //limit check handled by bindings
863        [fDownloadField setIntValue: downLimit];
864       
865        //limit check handled by bindings
866        [fUploadField setIntValue: upLimit];
867    }
868}
869
870@end
871
872@implementation PrefsController (Private)
873
874- (void) setPrefView: (id) sender
875{
876    NSView * view = fGeneralView;
877    if (sender)
878    {
879        NSString * identifier = [sender itemIdentifier];
880        if ([identifier isEqualToString: TOOLBAR_TRANSFERS])
881            view = fTransfersView;
882        else if ([identifier isEqualToString: TOOLBAR_BANDWIDTH])
883            view = fBandwidthView;
884        else if ([identifier isEqualToString: TOOLBAR_PEERS])
885            view = fPeersView;
886        else if ([identifier isEqualToString: TOOLBAR_NETWORK])
887            view = fNetworkView;
888        else if ([identifier isEqualToString: TOOLBAR_REMOTE])
889            view = fRemoteView;
890        else; //general view already selected
891    }
892   
893    NSWindow * window = [self window];
894    if ([window contentView] == view)
895        return;
896   
897    NSRect windowRect = [window frame];
898    float difference = ([view frame].size.height - [[window contentView] frame].size.height) * [window userSpaceScaleFactor];
899    windowRect.origin.y -= difference;
900    windowRect.size.height += difference;
901   
902    [view setHidden: YES];
903    [window setContentView: view];
904    [window setFrame: windowRect display: YES animate: YES];
905    [view setHidden: NO];
906   
907    //set title label
908    if (sender)
909        [window setTitle: [sender label]];
910    else
911    {
912        NSToolbar * toolbar = [window toolbar];
913        NSString * itemIdentifier = [toolbar selectedItemIdentifier];
914        NSEnumerator * enumerator = [[toolbar items] objectEnumerator];
915        NSToolbarItem * item;
916        while ((item = [enumerator nextObject]))
917            if ([[item itemIdentifier] isEqualToString: itemIdentifier])
918            {
919                [window setTitle: [item label]];
920                break;
921            }
922    }
923   
924    //for network view make sure progress indicator hides itself (get around a Tiger bug)
925    if (![NSApp isOnLeopardOrBetter] && view == fNetworkView && [fPortStatusImage image])
926        [fPortStatusProgress setDisplayedWhenStopped: NO];
927}
928
929- (void) folderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info
930{
931    if (code == NSOKButton)
932    {
933        [fFolderPopUp selectItemAtIndex: DOWNLOAD_FOLDER];
934        [fDefaults setObject: [[openPanel filenames] objectAtIndex: 0] forKey: @"DownloadFolder"];
935        [fDefaults setObject: @"Constant" forKey: @"DownloadChoice"];
936    }
937    else
938    {
939        //reset if cancelled
940        [fFolderPopUp selectItemAtIndex: [fDefaults boolForKey: @"DownloadLocationConstant"] ? DOWNLOAD_FOLDER : DOWNLOAD_TORRENT];
941    }
942}
943
944- (void) incompleteFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info
945{
946    if (code == NSOKButton)
947        [fDefaults setObject: [[openPanel filenames] objectAtIndex: 0] forKey: @"IncompleteDownloadFolder"];
948    [fIncompleteFolderPopUp selectItemAtIndex: 0];
949}
950
951- (void) importFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info
952{
953    NSString * path = [fDefaults stringForKey: @"AutoImportDirectory"];
954    if (code == NSOKButton)
955    {
956        UKKQueue * sharedQueue = [UKKQueue sharedFileWatcher];
957        if (path)
958            [sharedQueue removePathFromQueue: [path stringByExpandingTildeInPath]];
959       
960        path = [[openPanel filenames] objectAtIndex: 0];
961        [fDefaults setObject: path forKey: @"AutoImportDirectory"];
962        [sharedQueue addPath: [path stringByExpandingTildeInPath]];
963       
964        [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoImportSettingChange" object: self];
965    }
966    else if (!path)
967        [fDefaults setBool: NO forKey: @"AutoImport"];
968   
969    [fImportFolderPopUp selectItemAtIndex: 0];
970}
971
972@end
Note: See TracBrowser for help on using the repository browser.