зеркало из https://github.com/mozilla/pjs.git
1200 строки
41 KiB
Plaintext
1200 строки
41 KiB
Plaintext
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2002
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#import "PrivacyPane.h"
|
|
|
|
#import "NSString+Utils.h"
|
|
#import "NSArray+Utils.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsIPref.h"
|
|
#include "nsNetCID.h"
|
|
#include "nsICookie.h"
|
|
#include "nsICookieManager.h"
|
|
#include "nsICookiePermission.h"
|
|
#include "nsIPermissionManager.h"
|
|
#include "nsISimpleEnumerator.h"
|
|
#include "nsIPermission.h"
|
|
#include "nsIURI.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsString.h"
|
|
#include "STFPopUpButtonCell.h"
|
|
|
|
// we should really get this from "CHBrowserService.h",
|
|
// but that requires linkage and extra search paths.
|
|
static NSString* XPCOMShutDownNotificationName = @"XPCOMShutDown";
|
|
|
|
#import "ExtendedTableView.h"
|
|
|
|
// prefs for keychain password autofill
|
|
static const char* const gUseKeychainPref = "chimera.store_passwords_with_keychain";
|
|
|
|
// network.cookie.lifetimePolicy settings
|
|
const int kAcceptCookiesNormally = 0;
|
|
const int kWarnAboutCookies = 1;
|
|
|
|
// sort order indicators
|
|
const int kSortReverse = 1;
|
|
|
|
@interface OrgMozillaChimeraPreferencePrivacy(Private)
|
|
|
|
- (void)addPermission:(int)inPermission forHost:(NSString*)inHost;
|
|
|
|
- (int)numCookiesSelectedInCookiePanel;
|
|
- (int)numPermissionsSelectedInPermissionsPanel;
|
|
// get the number of unique cookie sites that are selected,
|
|
// and if it's just one, return the site name (with leading period removed, if necessary)
|
|
- (int)numUniqueCookieSitesSelected:(NSString**)outSiteName;
|
|
- (NSString*)permissionsBlockingNameForCookieHostname:(NSString*)inHostname;
|
|
- (NSArray*)selectedCookieSites;
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
// callbacks for sorting the permission list
|
|
PR_STATIC_CALLBACK(int) indexForCapability(int aCapability)
|
|
{
|
|
switch (aCapability)
|
|
{
|
|
case nsIPermissionManager::DENY_ACTION:
|
|
return eDenyIndex;
|
|
|
|
case nsICookiePermission::ACCESS_SESSION:
|
|
return eSessionOnlyIndex;
|
|
|
|
case nsIPermissionManager::ALLOW_ACTION:
|
|
default:
|
|
return eAllowIndex;
|
|
}
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(int) comparePermHosts(nsIPermission* aPerm1, nsIPermission* aPerm2, void* aData)
|
|
{
|
|
nsCAutoString host1;
|
|
aPerm1->GetHost(host1);
|
|
nsCAutoString host2;
|
|
aPerm2->GetHost(host2);
|
|
|
|
if ((int)aData == kSortReverse)
|
|
return Compare(host2, host1);
|
|
else
|
|
return Compare(host1, host2);
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(int) compareCapabilities(nsIPermission* aPerm1, nsIPermission* aPerm2, void* aData)
|
|
{
|
|
PRUint32 cap1 = 0;
|
|
aPerm1->GetCapability(&cap1);
|
|
PRUint32 cap2 = 0;
|
|
aPerm2->GetCapability(&cap2);
|
|
|
|
if(cap1 == cap2)
|
|
return comparePermHosts(aPerm1, aPerm2, nsnull); //always break ties in alphabetical order
|
|
if ((int)aData == kSortReverse)
|
|
return (indexForCapability(cap2) < indexForCapability(cap1)) ? -1 : 1;
|
|
else
|
|
return (indexForCapability(cap1) < indexForCapability(cap2)) ? -1 : 1;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(int) compareCookieHosts(nsICookie* aCookie1, nsICookie* aCookie2, void* aData)
|
|
{
|
|
nsCAutoString host1;
|
|
aCookie1->GetHost(host1);
|
|
nsCAutoString host2;
|
|
aCookie2->GetHost(host2);
|
|
if ((int)aData == kSortReverse)
|
|
return Compare(host2, host1);
|
|
else
|
|
return Compare(host1, host2);
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(int) compareNames(nsICookie* aCookie1, nsICookie* aCookie2, void* aData)
|
|
{
|
|
nsCAutoString name1;
|
|
aCookie1->GetName(name1);
|
|
nsCAutoString name2;
|
|
aCookie2->GetName(name2);
|
|
|
|
if ((int)aData == kSortReverse)
|
|
return Compare(name2, name1);
|
|
else
|
|
return Compare(name1, name2);
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(int) comparePaths(nsICookie* aCookie1, nsICookie* aCookie2, void* aData)
|
|
{
|
|
nsCAutoString path1;
|
|
aCookie1->GetPath(path1);
|
|
nsCAutoString path2;
|
|
aCookie2->GetPath(path2);
|
|
|
|
if ((int)aData == kSortReverse)
|
|
return Compare(path1, path2);
|
|
else
|
|
return Compare(path2, path1);
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(int) compareSecures(nsICookie* aCookie1, nsICookie* aCookie2, void* aData)
|
|
{
|
|
PRBool secure1;
|
|
aCookie1->GetIsSecure(&secure1);
|
|
PRBool secure2;
|
|
aCookie2->GetIsSecure(&secure2);
|
|
|
|
if (secure1 == secure2)
|
|
return 0;
|
|
if ((int)aData == kSortReverse)
|
|
return (secure2) ? -1 : 1;
|
|
else
|
|
return (secure1) ? -1 : 1;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(int) compareExpires(nsICookie* aCookie1, nsICookie* aCookie2, void* aData)
|
|
{
|
|
PRUint64 expires1;
|
|
aCookie1->GetExpires(&expires1);
|
|
PRUint64 expires2;
|
|
aCookie2->GetExpires(&expires2);
|
|
|
|
if (expires1 == expires2) return 0;
|
|
if ((int)aData == kSortReverse)
|
|
return (expires2 < expires1) ? -1 : 1;
|
|
else
|
|
return (expires1 < expires2) ? -1 : 1;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(int) compareValues(nsICookie* aCookie1, nsICookie* aCookie2, void* aData)
|
|
{
|
|
nsCAutoString value1;
|
|
aCookie1->GetValue(value1);
|
|
nsCAutoString value2;
|
|
aCookie2->GetValue(value2);
|
|
if ((int)aData == kSortReverse)
|
|
return Compare(value2, value1);
|
|
else
|
|
return Compare(value1, value2);
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
@implementation OrgMozillaChimeraPreferencePrivacy
|
|
|
|
-(void) dealloc
|
|
{
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
// NOTE: no need to worry about mCachedPermissions or mCachedCookies because if we're going away
|
|
// the respective sheets have closed and cleaned up.
|
|
|
|
NS_IF_RELEASE(mPermissionManager);
|
|
NS_IF_RELEASE(mCookieManager);
|
|
[super dealloc];
|
|
}
|
|
|
|
- (void)xpcomShutdown:(NSNotification*)notification
|
|
{
|
|
// these null the pointer
|
|
NS_IF_RELEASE(mPermissionManager);
|
|
NS_IF_RELEASE(mCookieManager);
|
|
}
|
|
|
|
-(void) mainViewDidLoad
|
|
{
|
|
if (!mPrefService)
|
|
return;
|
|
|
|
// we need to register for xpcom shutdown so that we can clear the
|
|
// services before XPCOM is shut down. We can't rely on dealloc,
|
|
// because we don't know when it will get called (we might be autoreleased).
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(xpcomShutdown:)
|
|
name:XPCOMShutDownNotificationName
|
|
object:nil];
|
|
|
|
// Hookup cookie prefs.
|
|
PRInt32 acceptCookies = eAcceptAllCookies;
|
|
mPrefService->GetIntPref("network.cookie.cookieBehavior", &acceptCookies);
|
|
[self mapCookiePrefToGUI:acceptCookies];
|
|
|
|
// lifetimePolicy now controls asking about cookies, despite being totally unintuitive
|
|
PRInt32 lifetimePolicy = kAcceptCookiesNormally;
|
|
mPrefService->GetIntPref("network.cookie.lifetimePolicy", &lifetimePolicy);
|
|
if (lifetimePolicy == kWarnAboutCookies)
|
|
[mAskAboutCookies setState:NSOnState];
|
|
else if (lifetimePolicy == kAcceptCookiesNormally)
|
|
[mAskAboutCookies setState:NSOffState];
|
|
else
|
|
[mAskAboutCookies setState:NSMixedState];
|
|
|
|
// store permission manager service and cache the enumerator.
|
|
nsCOMPtr<nsIPermissionManager> pm(do_GetService(NS_PERMISSIONMANAGER_CONTRACTID));
|
|
mPermissionManager = pm.get();
|
|
NS_IF_ADDREF(mPermissionManager);
|
|
|
|
// store cookie manager service
|
|
nsCOMPtr<nsICookieManager> cm(do_GetService(NS_COOKIEMANAGER_CONTRACTID));
|
|
mCookieManager = cm.get();
|
|
NS_IF_ADDREF(mCookieManager);
|
|
|
|
// Keychain checkbox
|
|
PRBool storePasswords = PR_TRUE;
|
|
mPrefService->GetBoolPref(gUseKeychainPref, &storePasswords);
|
|
[mStorePasswords setState:(storePasswords ? NSOnState : NSOffState)];
|
|
|
|
// set up policy popups
|
|
NSPopUpButtonCell *popupButtonCell = [mPermissionColumn dataCell];
|
|
[popupButtonCell setEditable:YES];
|
|
[popupButtonCell addItemsWithTitles:[NSArray arrayWithObjects:[self getLocalizedString:@"Allow"],
|
|
[self getLocalizedString:@"Allow for Session"],
|
|
[self getLocalizedString:@"Deny"],
|
|
nil]];
|
|
|
|
//remove the popup from the filter input fields
|
|
[[mPermissionFilterField cell] setHasPopUpButton: NO];
|
|
[[mCookiesFilterField cell] setHasPopUpButton: NO];
|
|
}
|
|
|
|
-(void) mapCookiePrefToGUI:(int)pref
|
|
{
|
|
[mCookieBehavior selectCellWithTag:pref];
|
|
[mAskAboutCookies setEnabled:(pref == eAcceptAllCookies || pref == eAcceptCookiesFromOriginatingServer)];
|
|
}
|
|
|
|
//
|
|
// Stored cookie editing methods
|
|
//
|
|
|
|
-(void) populateCookieCache
|
|
{
|
|
nsCOMPtr<nsISimpleEnumerator> cookieEnum;
|
|
if (mCookieManager)
|
|
mCookieManager->GetEnumerator(getter_AddRefs(cookieEnum));
|
|
|
|
mCachedCookies = new nsCOMArray<nsICookie>;
|
|
if (mCachedCookies && cookieEnum) {
|
|
mCachedCookies->Clear();
|
|
PRBool hasMoreElements = PR_FALSE;
|
|
cookieEnum->HasMoreElements(&hasMoreElements);
|
|
while (hasMoreElements) {
|
|
nsCOMPtr<nsICookie> cookie;
|
|
cookieEnum->GetNext(getter_AddRefs(cookie));
|
|
mCachedCookies->AppendObject(cookie);
|
|
cookieEnum->HasMoreElements(&hasMoreElements);
|
|
}
|
|
}
|
|
}
|
|
|
|
-(IBAction) editCookies:(id)aSender
|
|
{
|
|
// build parallel cookie list
|
|
[self populateCookieCache];
|
|
|
|
[mCookiesTable setDeleteAction:@selector(removeCookies:)];
|
|
[mCookiesTable setTarget:self];
|
|
|
|
CookieDateFormatter* cookieDateFormatter = [[CookieDateFormatter alloc] initWithDateFormat:@"%b %d, %Y" allowNaturalLanguage:NO];
|
|
// Once we are 10.4+, the above and all the CF stuff in CookieDateFormatter
|
|
// can be replaced with the following:
|
|
//CookieDateFormatter* cookieDateFormatter = [[CookieDateFormatter alloc] init];
|
|
//[cookieDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
|
|
//[cookieDateFormatter setDateStyle:NSDateFormatterMediumStyle];
|
|
//[cookieDateFormatter setTimeStyle:NSDateFormatterNoStyle];
|
|
[[[mCookiesTable tableColumnWithIdentifier:@"Expires"] dataCell] setFormatter:cookieDateFormatter];
|
|
[cookieDateFormatter release];
|
|
|
|
// start sorted by host
|
|
mCachedCookies->Sort(compareCookieHosts, nsnull);
|
|
NSTableColumn* sortedColumn = [mCookiesTable tableColumnWithIdentifier:@"Website"];
|
|
[mCookiesTable setHighlightedTableColumn:sortedColumn];
|
|
if ([mCookiesTable respondsToSelector:@selector(setIndicatorImage:inTableColumn:)])
|
|
[mCookiesTable setIndicatorImage:[NSImage imageNamed:@"NSAscendingSortIndicator"] inTableColumn:sortedColumn];
|
|
mSortedAscending = YES;
|
|
|
|
// ensure a row is selected (cocoa doesn't do this for us, but will keep
|
|
// us from unselecting a row once one is set; go figure).
|
|
[mCookiesTable selectRow: 0 byExtendingSelection: NO];
|
|
|
|
[mCookiesTable setUsesAlternatingRowBackgroundColors:YES];
|
|
NSArray* columns = [mCookiesTable tableColumns];
|
|
if (columns) {
|
|
int numColumns = [columns count];
|
|
for (int i = 0; i < numColumns; ++i)
|
|
[[[columns objectAtIndex:i] dataCell] setDrawsBackground:NO];
|
|
}
|
|
|
|
//clear the filter field
|
|
[mCookiesFilterField setStringValue: @""];
|
|
|
|
// we shouldn't need to do this, but the scrollbar won't enable unless we
|
|
// force the table to reload its data. Oddly it gets the number of rows correct,
|
|
// it just forgets to tell the scrollbar. *shrug*
|
|
[mCookiesTable reloadData];
|
|
|
|
[mCookiesPanel setFrameAutosaveName:@"cookies_sheet"];
|
|
|
|
// bring up sheet
|
|
[NSApp beginSheet:mCookiesPanel
|
|
modalForWindow:[mAskAboutCookies window] // any old window accessor
|
|
modalDelegate:self
|
|
didEndSelector:NULL
|
|
contextInfo:NULL];
|
|
NSSize min = {440, 240};
|
|
[mCookiesPanel setMinSize:min];
|
|
}
|
|
|
|
-(IBAction) removeCookies:(id)aSender
|
|
{
|
|
int rowToSelect = -1;
|
|
|
|
if (mCachedCookies && mCookieManager) {
|
|
NSArray *rows = [[mCookiesTable selectedRowEnumerator] allObjects];
|
|
NSEnumerator *e = [rows reverseObjectEnumerator];
|
|
NSNumber *index;
|
|
while ((index = [e nextObject]))
|
|
{
|
|
int row = [index intValue];
|
|
if (rowToSelect == -1)
|
|
rowToSelect = row;
|
|
else
|
|
--rowToSelect;
|
|
|
|
nsCAutoString host, name, path;
|
|
mCachedCookies->ObjectAt(row)->GetHost(host);
|
|
mCachedCookies->ObjectAt(row)->GetName(name);
|
|
mCachedCookies->ObjectAt(row)->GetPath(path);
|
|
mCookieManager->Remove(host, name, path, PR_FALSE); // don't block permanently
|
|
mCachedCookies->RemoveObjectAt(row);
|
|
}
|
|
}
|
|
|
|
[mCookiesTable reloadData];
|
|
|
|
if (rowToSelect >=0 && rowToSelect < [mCookiesTable numberOfRows])
|
|
[mCookiesTable selectRow:rowToSelect byExtendingSelection:NO];
|
|
else
|
|
[mCookiesTable deselectAll:self];
|
|
}
|
|
|
|
-(IBAction) removeAllCookies: (id)aSender
|
|
{
|
|
if (NSRunCriticalAlertPanel([self getLocalizedString:@"RemoveAllCookiesWarningTitle"],
|
|
[self getLocalizedString:@"RemoveAllCookiesWarning"],
|
|
[self getLocalizedString:@"Remove All Cookies"],
|
|
[self getLocalizedString:@"CancelButtonText"],
|
|
nil) == NSAlertDefaultReturn)
|
|
{
|
|
if (mCookieManager) {
|
|
// remove all cookies from cookie manager
|
|
mCookieManager->RemoveAll();
|
|
// create new cookie cache
|
|
delete mCachedCookies;
|
|
mCachedCookies = new nsCOMArray<nsICookie>;
|
|
}
|
|
[mCookiesTable reloadData];
|
|
}
|
|
}
|
|
|
|
-(IBAction) blockCookiesFromSites:(id)aSender
|
|
{
|
|
if (mCachedCookies && mPermissionManager) {
|
|
NSArray *rows = [[mCookiesTable selectedRowEnumerator] allObjects];
|
|
NSEnumerator *e = [rows reverseObjectEnumerator];
|
|
NSNumber *index;
|
|
while ((index = [e nextObject]))
|
|
{
|
|
int row = [index intValue];
|
|
|
|
nsCAutoString host, name, path;
|
|
mCachedCookies->ObjectAt(row)->GetHost(host);
|
|
[self addPermission:nsIPermissionManager::DENY_ACTION forHost:[NSString stringWith_nsACString:host]];
|
|
}
|
|
}
|
|
}
|
|
|
|
-(IBAction) removeCookiesAndBlockSites:(id)aSender
|
|
{
|
|
if (mCachedCookies && mPermissionManager)
|
|
{
|
|
// first fetch the list of sites
|
|
NSArray* selectedSites = [self selectedCookieSites];
|
|
int rowToSelect = -1;
|
|
|
|
// remove the cookies
|
|
for (int row = 0; row < mCachedCookies->Count(); row++)
|
|
{
|
|
nsCAutoString host, name, path;
|
|
// only search on the host
|
|
mCachedCookies->ObjectAt(row)->GetHost(host);
|
|
NSString* cookieHost = [NSString stringWith_nsACString:host];
|
|
if ([selectedSites containsObject:cookieHost])
|
|
{
|
|
if (rowToSelect == -1)
|
|
rowToSelect = row;
|
|
|
|
mCachedCookies->ObjectAt(row)->GetName(name);
|
|
mCachedCookies->ObjectAt(row)->GetPath(path);
|
|
mCookieManager->Remove(host, name, path, PR_FALSE); // don't block permanently
|
|
mCachedCookies->RemoveObjectAt(row);
|
|
--row; // to account for removal
|
|
}
|
|
}
|
|
|
|
// and block the sites
|
|
NSEnumerator* sitesEnum = [selectedSites objectEnumerator];
|
|
NSString* curSite;
|
|
while ((curSite = [sitesEnum nextObject]))
|
|
[self addPermission:nsIPermissionManager::DENY_ACTION forHost:curSite];
|
|
|
|
// and reload data
|
|
[mCookiesTable reloadData];
|
|
|
|
if (rowToSelect >=0 && rowToSelect < [mCookiesTable numberOfRows])
|
|
[mCookiesTable selectRow:rowToSelect byExtendingSelection:NO];
|
|
else
|
|
[mCookiesTable deselectAll:self];
|
|
}
|
|
}
|
|
|
|
-(IBAction) editCookiesDone:(id)aSender
|
|
{
|
|
// save stuff
|
|
[mCookiesPanel orderOut:self];
|
|
[NSApp endSheet:mCookiesPanel];
|
|
|
|
delete mCachedCookies;
|
|
mCachedCookies = nsnull;
|
|
}
|
|
|
|
//
|
|
// Site permission editing methods
|
|
|
|
-(void) populatePermissionCache
|
|
{
|
|
nsCOMPtr<nsISimpleEnumerator> permEnum;
|
|
if (mPermissionManager)
|
|
mPermissionManager->GetEnumerator(getter_AddRefs(permEnum));
|
|
|
|
mCachedPermissions = new nsCOMArray<nsIPermission>;
|
|
if (mCachedPermissions && permEnum) {
|
|
mCachedPermissions->Clear();
|
|
PRBool hasMoreElements = PR_FALSE;
|
|
permEnum->HasMoreElements(&hasMoreElements);
|
|
while (hasMoreElements) {
|
|
nsCOMPtr<nsISupports> curr;
|
|
permEnum->GetNext(getter_AddRefs(curr));
|
|
nsCOMPtr<nsIPermission> currPerm(do_QueryInterface(curr));
|
|
if (currPerm) {
|
|
nsCAutoString type;
|
|
currPerm->GetType(type);
|
|
if (type.Equals(NS_LITERAL_CSTRING("cookie")))
|
|
mCachedPermissions->AppendObject(currPerm);
|
|
}
|
|
permEnum->HasMoreElements(&hasMoreElements);
|
|
}
|
|
}
|
|
}
|
|
|
|
-(IBAction) editPermissions:(id)aSender
|
|
{
|
|
// build parallel permission list for speed with a lot of blocked sites
|
|
[self populatePermissionCache];
|
|
|
|
[mPermissionsTable setDeleteAction:@selector(removeCookiePermissions:)];
|
|
[mPermissionsTable setTarget:self];
|
|
|
|
// start sorted by host
|
|
mCachedPermissions->Sort(comparePermHosts, nsnull);
|
|
NSTableColumn* sortedColumn = [mPermissionsTable tableColumnWithIdentifier:@"Website"];
|
|
[mPermissionsTable setHighlightedTableColumn:sortedColumn];
|
|
if ([mPermissionsTable respondsToSelector:@selector(setIndicatorImage:inTableColumn:)])
|
|
[mPermissionsTable setIndicatorImage:[NSImage imageNamed:@"NSAscendingSortIndicator"] inTableColumn:sortedColumn];
|
|
mSortedAscending = YES;
|
|
|
|
// ensure a row is selected (cocoa doesn't do this for us, but will keep
|
|
// us from unselecting a row once one is set; go figure).
|
|
[mPermissionsTable selectRow:0 byExtendingSelection:NO];
|
|
|
|
[mPermissionsTable setUsesAlternatingRowBackgroundColors:YES];
|
|
|
|
//clear the filter field
|
|
[mPermissionFilterField setStringValue: @""];
|
|
|
|
// we shouldn't need to do this, but the scrollbar won't enable unless we
|
|
// force the table to reload its data. Oddly it gets the number of rows correct,
|
|
// it just forgets to tell the scrollbar. *shrug*
|
|
[mPermissionsTable reloadData];
|
|
|
|
[mPermissionsPanel setFrameAutosaveName:@"permissions_sheet"];
|
|
|
|
// bring up sheet
|
|
[NSApp beginSheet:mPermissionsPanel
|
|
modalForWindow:[mAskAboutCookies window] // any old window accessor
|
|
modalDelegate:self
|
|
didEndSelector:NULL
|
|
contextInfo:NULL];
|
|
NSSize min = {440, 240};
|
|
[mPermissionsPanel setMinSize:min];
|
|
}
|
|
|
|
-(IBAction) removeCookiePermissions:(id)aSender
|
|
{
|
|
int rowToSelect = -1;
|
|
|
|
if (mCachedPermissions && mPermissionManager) {
|
|
// remove from parallel array and cookie permissions list
|
|
NSArray *rows = [[mPermissionsTable selectedRowEnumerator] allObjects];
|
|
NSEnumerator *e = [rows reverseObjectEnumerator];
|
|
NSNumber *index;
|
|
while ((index = [e nextObject])) {
|
|
int row = [index intValue];
|
|
if (rowToSelect == -1)
|
|
rowToSelect = row;
|
|
else
|
|
--rowToSelect;
|
|
nsCAutoString host;
|
|
mCachedPermissions->ObjectAt(row)->GetHost(host);
|
|
mPermissionManager->Remove(host, "cookie");
|
|
mCachedPermissions->RemoveObjectAt(row);
|
|
}
|
|
}
|
|
|
|
[mPermissionsTable reloadData];
|
|
|
|
if (rowToSelect >=0 && rowToSelect < [mPermissionsTable numberOfRows])
|
|
[mPermissionsTable selectRow:rowToSelect byExtendingSelection:NO];
|
|
else
|
|
[mPermissionsTable deselectAll: self]; // don't want any traces of previous selection
|
|
}
|
|
|
|
-(IBAction) removeAllCookiePermissions: (id)aSender
|
|
{
|
|
if (NSRunCriticalAlertPanel([self getLocalizedString:@"RemoveAllCookiePermissionsWarningTitle"],
|
|
[self getLocalizedString:@"RemoveAllCookiePermissionsWarning"],
|
|
[self getLocalizedString:@"Remove All Exceptions"],
|
|
[self getLocalizedString:@"CancelButtonText"],
|
|
nil) == NSAlertDefaultReturn)
|
|
{
|
|
if (mPermissionManager)
|
|
{
|
|
// since the permissions manager stores not just cookie permissions,
|
|
// but also images etc, we have to manually remove just the cookie
|
|
// ones. Ugh.
|
|
|
|
// we have to keep a list of permissions to remove, because it's
|
|
// not safe to remove while enumerating
|
|
nsCOMArray<nsIPermission> permissionsToRemove;
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> permEnum;
|
|
mPermissionManager->GetEnumerator(getter_AddRefs(permEnum));
|
|
if (permEnum)
|
|
{
|
|
PRBool hasMoreElements = PR_FALSE;
|
|
while (NS_SUCCEEDED(permEnum->HasMoreElements(&hasMoreElements)) && hasMoreElements)
|
|
{
|
|
nsCOMPtr<nsISupports> curr;
|
|
permEnum->GetNext(getter_AddRefs(curr));
|
|
nsCOMPtr<nsIPermission> currPerm(do_QueryInterface(curr));
|
|
if (currPerm)
|
|
{
|
|
nsCAutoString type;
|
|
currPerm->GetType(type);
|
|
if (type.Equals(NS_LITERAL_CSTRING("cookie")))
|
|
permissionsToRemove.AppendObject(currPerm);
|
|
}
|
|
}
|
|
}
|
|
|
|
// now do the removal
|
|
int numDoomed = permissionsToRemove.Count();
|
|
for (int i = 0; i < numDoomed; ++i)
|
|
{
|
|
nsCAutoString curHost, curType;
|
|
permissionsToRemove.ObjectAt(i)->GetHost(curHost);
|
|
permissionsToRemove.ObjectAt(i)->GetType(curType);
|
|
mPermissionManager->Remove(curHost, curType.get());
|
|
}
|
|
|
|
delete mCachedPermissions;
|
|
mCachedPermissions = new nsCOMArray<nsIPermission>;
|
|
}
|
|
[mPermissionsTable reloadData];
|
|
}
|
|
}
|
|
|
|
-(IBAction) editPermissionsDone:(id)aSender
|
|
{
|
|
// save stuff
|
|
[mPermissionsPanel orderOut:self];
|
|
[NSApp endSheet:mPermissionsPanel];
|
|
|
|
delete mCachedPermissions;
|
|
mCachedPermissions = nsnull;
|
|
}
|
|
|
|
-(int) getRowForPermissionWithHost:(NSString *)aHost
|
|
{
|
|
nsCAutoString host;
|
|
if (mCachedPermissions) {
|
|
int numRows = mCachedPermissions->Count();
|
|
for (int row = 0; row < numRows; ++row) {
|
|
mCachedPermissions->ObjectAt(row)->GetHost(host);
|
|
if ([[NSString stringWithUTF8String:host.get()] isEqualToString:aHost]) return row;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// NSTableDataSource protocol methods
|
|
//
|
|
|
|
-(int) numberOfRowsInTableView:(NSTableView *)aTableView
|
|
{
|
|
PRUint32 numRows = 0;
|
|
if (aTableView == mPermissionsTable) {
|
|
if (mCachedPermissions)
|
|
numRows = mCachedPermissions->Count();
|
|
} else if (aTableView == mCookiesTable) {
|
|
if (mCachedCookies)
|
|
numRows = mCachedCookies->Count();
|
|
}
|
|
|
|
return (int) numRows;
|
|
}
|
|
|
|
-(id) tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
|
|
{
|
|
NSString* retVal = nil;
|
|
if (aTableView == mPermissionsTable) {
|
|
if (mCachedPermissions) {
|
|
if ([[aTableColumn identifier] isEqualToString:@"Website"]) {
|
|
// website url column
|
|
nsCAutoString host;
|
|
mCachedPermissions->ObjectAt(rowIndex)->GetHost(host);
|
|
retVal = [NSString stringWithUTF8String:host.get()];
|
|
} else {
|
|
// policy column
|
|
PRUint32 capability = PR_FALSE;
|
|
mCachedPermissions->ObjectAt(rowIndex)->GetCapability(&capability);
|
|
return [NSNumber numberWithInt:indexForCapability(capability)];
|
|
}
|
|
}
|
|
}
|
|
else if (aTableView == mCookiesTable) {
|
|
if (mCachedCookies) {
|
|
nsCAutoString cookieVal;
|
|
if ([[aTableColumn identifier] isEqualToString: @"Website"]) {
|
|
mCachedCookies->ObjectAt(rowIndex)->GetHost(cookieVal);
|
|
} else if ([[aTableColumn identifier] isEqualToString: @"Name"]) {
|
|
mCachedCookies->ObjectAt(rowIndex)->GetName(cookieVal);
|
|
} else if ([[aTableColumn identifier] isEqualToString: @"Path"]) {
|
|
mCachedCookies->ObjectAt(rowIndex)->GetPath(cookieVal);
|
|
} else if ([[aTableColumn identifier] isEqualToString: @"Secure"]) {
|
|
PRBool secure = PR_FALSE;
|
|
mCachedCookies->ObjectAt(rowIndex)->GetIsSecure(&secure);
|
|
if (secure)
|
|
retVal = [self getLocalizedString:@"yes"];
|
|
else
|
|
retVal = [self getLocalizedString:@"no"];
|
|
return retVal;
|
|
} else if ([[aTableColumn identifier] isEqualToString: @"Expires"]) {
|
|
PRUint64 expires = 0;
|
|
mCachedCookies->ObjectAt(rowIndex)->GetExpires(&expires);
|
|
// If expires is 0, it's a session cookie.
|
|
// We use a custom formatter to display a localised string in this case.
|
|
NSDate *date = [NSDate dateWithTimeIntervalSince1970:(NSTimeInterval)expires];
|
|
return date; // special case return
|
|
} else if ([[aTableColumn identifier] isEqualToString: @"Value"]) {
|
|
mCachedCookies->ObjectAt(rowIndex)->GetValue(cookieVal);
|
|
}
|
|
retVal = [NSString stringWithCString: cookieVal.get()];
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
// currently, this only applies to the site allow/deny, since that's the only editable column
|
|
-(void) tableView:(NSTableView *)aTableView
|
|
setObjectValue:anObject
|
|
forTableColumn:(NSTableColumn *)aTableColumn
|
|
row:(int)rowIndex
|
|
{
|
|
if (aTableView == mPermissionsTable && aTableColumn == mPermissionColumn) {
|
|
if (mCachedPermissions && mPermissionManager) {
|
|
// create a URI from the hostname of the changed site
|
|
nsCAutoString host;
|
|
mCachedPermissions->ObjectAt(rowIndex)->GetHost(host);
|
|
NSString* url = [NSString stringWithFormat:@"http://%s", host.get()];
|
|
const char* siteURL = [url UTF8String];
|
|
nsCOMPtr<nsIURI> newURI;
|
|
NS_NewURI(getter_AddRefs(newURI), siteURL);
|
|
if (newURI) {
|
|
// nsIPermissions are immutable, and there's no API to change the action,
|
|
// so instead we have to delete the old pref and insert a new one.
|
|
// remove the old entry
|
|
mPermissionManager->Remove(host, "cookie"); // XXX necessary?
|
|
// add a new entry with the new permission
|
|
switch ([anObject intValue])
|
|
{
|
|
case eAllowIndex:
|
|
mPermissionManager->Add(newURI, "cookie", nsIPermissionManager::ALLOW_ACTION);
|
|
break;
|
|
|
|
case eDenyIndex:
|
|
mPermissionManager->Add(newURI, "cookie", nsIPermissionManager::DENY_ACTION);
|
|
break;
|
|
|
|
case eSessionOnlyIndex:
|
|
mPermissionManager->Add(newURI, "cookie", nsICookiePermission::ACCESS_SESSION);
|
|
break;
|
|
}
|
|
// there really should be a better way to keep the cache up-to-date than rebuilding
|
|
// it, but the nsIPermissionManager interface doesn't have a way to get a pointer
|
|
// to a site's nsIPermission. It's this, use a custom class that duplicates the
|
|
// information (wasting a lot of memory), or find a way to tie in to
|
|
// PERM_CHANGE_NOTIFICATION to get the new nsIPermission that way.
|
|
//re-filter
|
|
[self filterCookiesPermissionsWithString:[mPermissionFilterField stringValue]];
|
|
// re-aquire selection of the changed permission
|
|
int selectedRowIndex = [self getRowForPermissionWithHost:[NSString stringWithUTF8String:host.get()]];
|
|
nsCOMPtr<nsIPermission> selectedItem = (selectedRowIndex != -1) ?
|
|
mCachedPermissions->ObjectAt(selectedRowIndex) : nsnull;
|
|
// re-sort
|
|
[self sortPermissionsByColumn:[mPermissionsTable highlightedTableColumn] inAscendingOrder:mSortedAscending];
|
|
// scroll to the new position of changed item
|
|
if (selectedItem) {
|
|
int newRowIndex = mCachedPermissions->IndexOf(selectedItem);
|
|
if (newRowIndex >= 0) {
|
|
[aTableView selectRow:newRowIndex byExtendingSelection:NO];
|
|
[aTableView scrollRowToVisible:newRowIndex];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
-(void) sortPermissionsByColumn:(NSTableColumn *)aTableColumn inAscendingOrder:(BOOL)ascending
|
|
{
|
|
if(mCachedPermissions) {
|
|
if ([[aTableColumn identifier] isEqualToString:@"Website"])
|
|
mCachedPermissions->Sort(comparePermHosts, (ascending) ? nsnull : (void *)kSortReverse);
|
|
else
|
|
mCachedPermissions->Sort(compareCapabilities, (ascending) ? nsnull : (void *)kSortReverse);
|
|
[mPermissionsTable setHighlightedTableColumn:aTableColumn];
|
|
[mPermissionsTable reloadData];
|
|
}
|
|
}
|
|
|
|
-(void) sortCookiesByColumn:(NSTableColumn *)aTableColumn inAscendingOrder:(BOOL)ascending
|
|
{
|
|
if(mCachedCookies) {
|
|
if ([[aTableColumn identifier] isEqualToString:@"Website"])
|
|
mCachedCookies->Sort(compareCookieHosts, (ascending) ? nsnull : (void *)kSortReverse);
|
|
else if ([[aTableColumn identifier] isEqualToString:@"Name"])
|
|
mCachedCookies->Sort(compareNames, (ascending) ? nsnull : (void *)kSortReverse);
|
|
else if ([[aTableColumn identifier] isEqualToString:@"Path"])
|
|
mCachedCookies->Sort(comparePaths, (ascending) ? nsnull : (void *)kSortReverse);
|
|
else if ([[aTableColumn identifier] isEqualToString:@"Secure"])
|
|
mCachedCookies->Sort(compareSecures, (ascending) ? nsnull : (void *)kSortReverse);
|
|
else if ([[aTableColumn identifier] isEqualToString:@"Expires"])
|
|
mCachedCookies->Sort(compareExpires, (ascending) ? nsnull : (void *)kSortReverse);
|
|
else if ([[aTableColumn identifier] isEqualToString:@"Value"])
|
|
mCachedCookies->Sort(compareValues, (ascending) ? nsnull : (void *)kSortReverse);
|
|
[mCookiesTable setHighlightedTableColumn:aTableColumn];
|
|
[mCookiesTable reloadData];
|
|
}
|
|
}
|
|
|
|
// NSTableView delegate methods
|
|
|
|
- (void) tableView:(NSTableView *)aTableView didClickTableColumn:(NSTableColumn *)aTableColumn
|
|
{
|
|
// reverse the sort if clicking again on the same column
|
|
if (aTableColumn == [aTableView highlightedTableColumn])
|
|
mSortedAscending = !mSortedAscending;
|
|
else
|
|
mSortedAscending = YES;
|
|
|
|
// adjust sort indicator on new column, removing from old column
|
|
if ([aTableView respondsToSelector:@selector(setIndicatorImage:inTableColumn:)]) {
|
|
[aTableView setIndicatorImage:nil inTableColumn:[aTableView highlightedTableColumn]];
|
|
NSImage *sortIndicator = [NSImage imageNamed:(mSortedAscending ? @"NSAscendingSortIndicator" : @"NSDescendingSortIndicator")];
|
|
[aTableView setIndicatorImage:sortIndicator inTableColumn:aTableColumn];
|
|
}
|
|
|
|
if (aTableView == mPermissionsTable) {
|
|
if (mCachedPermissions) {
|
|
// save the currently selected rows, if any.
|
|
nsCOMArray<nsIPermission> selectedItems;
|
|
NSEnumerator *e = [mPermissionsTable selectedRowEnumerator];
|
|
NSNumber *index;
|
|
while ((index = [e nextObject])) {
|
|
int row = [index intValue];
|
|
selectedItems.AppendObject(mCachedPermissions->ObjectAt(row));
|
|
}
|
|
// sort the table data
|
|
[self sortPermissionsByColumn:aTableColumn inAscendingOrder:mSortedAscending];
|
|
// if any rows were selected before, find them again
|
|
[mPermissionsTable deselectAll:self];
|
|
for (int i = 0; i < selectedItems.Count(); ++i) {
|
|
int newRowIndex = mCachedPermissions->IndexOf(selectedItems.ObjectAt(i));
|
|
if (newRowIndex >= 0) {
|
|
// scroll to the first item (arbitrary, but at least one should show)
|
|
if (i == 0)
|
|
[mPermissionsTable scrollRowToVisible:newRowIndex];
|
|
[mPermissionsTable selectRow:newRowIndex byExtendingSelection:YES];
|
|
}
|
|
}
|
|
}
|
|
} else if (aTableView == mCookiesTable) {
|
|
if (mCachedCookies) {
|
|
// save the currently selected rows, if any.
|
|
nsCOMArray<nsICookie> selectedItems;
|
|
NSEnumerator *e = [mCookiesTable selectedRowEnumerator];
|
|
NSNumber *index;
|
|
while ((index = [e nextObject])) {
|
|
int row = [index intValue];
|
|
selectedItems.AppendObject(mCachedCookies->ObjectAt(row));
|
|
}
|
|
// sort the table data
|
|
[self sortCookiesByColumn:aTableColumn inAscendingOrder:mSortedAscending];
|
|
// if any rows were selected before, find them again
|
|
[mCookiesTable deselectAll:self];
|
|
for (int i = 0; i < selectedItems.Count(); ++i) {
|
|
int newRowIndex = mCachedCookies->IndexOf(selectedItems.ObjectAt(i));
|
|
if (newRowIndex >= 0) {
|
|
// scroll to the first item (arbitrary, but at least one should show)
|
|
if (i == 0)
|
|
[mCookiesTable scrollRowToVisible:newRowIndex];
|
|
[mCookiesTable selectRow:newRowIndex byExtendingSelection:YES];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification
|
|
{
|
|
if ([aNotification object] == mCookiesTable)
|
|
{
|
|
// nothing to do
|
|
}
|
|
}
|
|
|
|
//
|
|
// Buttons
|
|
//
|
|
|
|
-(IBAction) clickCookieBehavior:(id)sender
|
|
{
|
|
int row = [mCookieBehavior selectedRow];
|
|
[self setPref:"network.cookie.cookieBehavior" toInt:row];
|
|
[self mapCookiePrefToGUI:row];
|
|
}
|
|
|
|
-(IBAction) clickAskAboutCookies:(id)sender
|
|
{
|
|
[sender setAllowsMixedState:NO];
|
|
[self setPref:"network.cookie.lifetimePolicy" toInt:([sender state] == NSOnState) ? kWarnAboutCookies : kAcceptCookiesNormally];
|
|
}
|
|
|
|
|
|
//
|
|
// clickStorePasswords
|
|
//
|
|
-(IBAction) clickStorePasswords:(id)sender
|
|
{
|
|
if (!mPrefService)
|
|
return;
|
|
mPrefService->SetBoolPref("chimera.store_passwords_with_keychain",
|
|
([mStorePasswords state] == NSOnState) ? PR_TRUE : PR_FALSE);
|
|
}
|
|
|
|
-(IBAction) launchKeychainAccess:(id)sender
|
|
{
|
|
FSRef fsRef;
|
|
CFURLRef urlRef;
|
|
OSErr err = ::LSGetApplicationForInfo('APPL', 'kcmr', NULL, kLSRolesAll, &fsRef, &urlRef);
|
|
if (!err) {
|
|
CFStringRef fileSystemURL = ::CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
|
|
[[NSWorkspace sharedWorkspace] launchApplication:(NSString*)fileSystemURL];
|
|
CFRelease(fileSystemURL);
|
|
}
|
|
}
|
|
|
|
- (void)controlTextDidChange:(NSNotification *)aNotification
|
|
{
|
|
NSString *filterString = [[aNotification object] stringValue];
|
|
|
|
// find out if we are filtering the permission or the cookies
|
|
if (([aNotification object] == mPermissionFilterField) && mCachedPermissions && mPermissionManager) {
|
|
// the user wants to filter down the list of cookies. Reinitialize the list of permission in case
|
|
// they deleted or replaced a letter.
|
|
[self filterCookiesPermissionsWithString:filterString];
|
|
// re-sort
|
|
[self sortPermissionsByColumn:[mPermissionsTable highlightedTableColumn] inAscendingOrder:mSortedAscending];
|
|
|
|
[mPermissionsTable deselectAll: self]; // don't want any traces of previous selection
|
|
[mPermissionsTable reloadData];
|
|
}
|
|
else if (([aNotification object] == mCookiesFilterField) && mCachedCookies && mCookieManager) {
|
|
// reinitialize the list of cookies in case user deleted a letter or replaced a letter
|
|
[self filterCookiesWithString:filterString];
|
|
// re-sort
|
|
[self sortCookiesByColumn:[mCookiesTable highlightedTableColumn] inAscendingOrder:mSortedAscending];
|
|
|
|
[mCookiesTable deselectAll: self]; // don't want any traces of previous selection
|
|
[mCookiesTable reloadData];
|
|
}
|
|
}
|
|
|
|
- (void) filterCookiesPermissionsWithString: (NSString*) inFilterString
|
|
{
|
|
// the user wants to filter down the list of cookies. Reinitialize the list of permission in case
|
|
// they deleted or replaced a letter.
|
|
[self populatePermissionCache];
|
|
|
|
if ([inFilterString length]) {
|
|
NSMutableArray *indexToRemove = [NSMutableArray array];
|
|
for (int row = 0; row < mCachedPermissions->Count(); row++) {
|
|
nsCAutoString host;
|
|
mCachedPermissions->ObjectAt(row)->GetHost(host);
|
|
if ([[NSString stringWithUTF8String:host.get()] rangeOfString:inFilterString].location == NSNotFound)
|
|
// add to our buffer
|
|
[indexToRemove addObject:[NSNumber numberWithInt:row]];
|
|
}
|
|
|
|
//remove the items at the saved indexes
|
|
//
|
|
NSEnumerator *theEnum = [indexToRemove reverseObjectEnumerator];
|
|
NSNumber *currentItem;
|
|
while (currentItem = [theEnum nextObject])
|
|
mCachedPermissions->RemoveObjectAt([currentItem intValue]);
|
|
}
|
|
}
|
|
|
|
|
|
- (void) filterCookiesWithString: (NSString*) inFilterString
|
|
{
|
|
// reinitialize the list of cookies in case user deleted a letter or replaced a letter
|
|
[self populateCookieCache];
|
|
|
|
if ([inFilterString length]) {
|
|
NSMutableArray *indexToRemove = [NSMutableArray array];
|
|
for (int row = 0; row < mCachedCookies->Count(); row++) {
|
|
nsCAutoString host;
|
|
// only search on the host
|
|
mCachedCookies->ObjectAt(row)->GetHost(host);
|
|
if ([[NSString stringWithUTF8String:host.get()] rangeOfString:inFilterString].location == NSNotFound)
|
|
[indexToRemove addObject:[NSNumber numberWithInt:row]];
|
|
}
|
|
|
|
//remove the items at the saved indexes
|
|
//
|
|
NSEnumerator *theEnum = [indexToRemove reverseObjectEnumerator];
|
|
NSNumber *currentItem;
|
|
while (currentItem = [theEnum nextObject])
|
|
mCachedCookies->RemoveObjectAt([currentItem intValue]);
|
|
}
|
|
}
|
|
|
|
- (void)addPermission:(int)inPermission forHost:(NSString*)inHost
|
|
{
|
|
nsCOMPtr<nsIURI> hostURI;
|
|
NS_NewURI(getter_AddRefs(hostURI), "http://");
|
|
nsCAutoString host([[self permissionsBlockingNameForCookieHostname:inHost] UTF8String]);
|
|
hostURI->SetHost(host);
|
|
|
|
mPermissionManager->Add(hostURI, "cookie", inPermission);
|
|
}
|
|
|
|
- (int)numCookiesSelectedInCookiePanel
|
|
{
|
|
int numSelected = 0;
|
|
if ([mCookiesPanel isVisible])
|
|
numSelected = [mCookiesTable numberOfSelectedRows];
|
|
|
|
return numSelected;
|
|
}
|
|
|
|
- (int)numPermissionsSelectedInPermissionsPanel
|
|
{
|
|
int numSelected = 0;
|
|
if ([mPermissionsPanel isVisible])
|
|
numSelected = [mPermissionsTable numberOfSelectedRows];
|
|
|
|
return numSelected;
|
|
}
|
|
|
|
- (int)numUniqueCookieSitesSelected:(NSString**)outSiteName
|
|
{
|
|
if (outSiteName)
|
|
*outSiteName = nil;
|
|
|
|
NSArray* selectedSites = [self selectedCookieSites];
|
|
unsigned int numHosts = [selectedSites count];
|
|
if (numHosts == 1 && outSiteName)
|
|
*outSiteName = [self permissionsBlockingNameForCookieHostname:[selectedSites firstObject]];
|
|
|
|
return numHosts;
|
|
}
|
|
|
|
- (NSString*)permissionsBlockingNameForCookieHostname:(NSString*)inHostname
|
|
{
|
|
// if the host string starts with a '.', remove it (because this is
|
|
// how the permissions manager looks up hosts)
|
|
if ([inHostname hasPrefix:@"."])
|
|
inHostname = [inHostname substringFromIndex:1];
|
|
return inHostname;
|
|
}
|
|
|
|
- (NSArray*)selectedCookieSites
|
|
{
|
|
// the set does the uniquifying for us
|
|
NSMutableSet* selectedHostsSet = [[[NSMutableSet alloc] init] autorelease];
|
|
NSEnumerator* e = [mCookiesTable selectedRowEnumerator];
|
|
NSNumber* index;
|
|
while ((index = [e nextObject]))
|
|
{
|
|
int row = [index intValue];
|
|
|
|
nsCAutoString host;
|
|
mCachedCookies->ObjectAt(row)->GetHost(host);
|
|
|
|
NSString* hostString = [NSString stringWith_nsACString:host];
|
|
[selectedHostsSet addObject:hostString];
|
|
}
|
|
return [selectedHostsSet allObjects];
|
|
}
|
|
|
|
- (BOOL)validateMenuItem:(NSMenuItem*)inMenuItem
|
|
{
|
|
SEL action = [inMenuItem action];
|
|
|
|
// cookies context menu
|
|
if (action == @selector(removeCookies:))
|
|
return ([self numCookiesSelectedInCookiePanel] > 0);
|
|
|
|
// only allow "remove all" if we're not filtering
|
|
if (action == @selector(removeAllCookies:))
|
|
return ([[mCookiesFilterField stringValue] length] == 0);
|
|
|
|
if (action == @selector(blockCookiesFromSites:))
|
|
{
|
|
NSString* siteName = nil;
|
|
int numCookieSites = [self numUniqueCookieSitesSelected:&siteName];
|
|
NSString* menuTitle = (numCookieSites == 1) ?
|
|
[NSString stringWithFormat:[self getLocalizedString:@"BlockCookieFromSite"], siteName] :
|
|
[self getLocalizedString:@"BlockCookiesFromSites"];
|
|
[inMenuItem setTitle:menuTitle];
|
|
return (numCookieSites > 0);
|
|
}
|
|
|
|
if (action == @selector(removeCookiesAndBlockSites:))
|
|
{
|
|
NSString* siteName = nil;
|
|
int numCookieSites = [self numUniqueCookieSitesSelected:&siteName];
|
|
|
|
NSString* menuTitle = (numCookieSites == 1) ?
|
|
[NSString stringWithFormat:[self getLocalizedString:@"RemoveAndBlockCookieFromSite"], siteName] :
|
|
[self getLocalizedString:@"RemoveAndBlockCookiesFromSites"];
|
|
[inMenuItem setTitle:menuTitle];
|
|
return (numCookieSites > 0);
|
|
}
|
|
|
|
// permissions context menu
|
|
if (action == @selector(removeCookiePermissions:))
|
|
return ([self numPermissionsSelectedInPermissionsPanel] > 0);
|
|
|
|
// only allow "remove all" if we're not filtering
|
|
if (action == @selector(removeAllCookiePermissions:))
|
|
return ([[mPermissionFilterField stringValue] length] == 0);
|
|
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
@implementation CookieDateFormatter
|
|
|
|
- (id)initWithDateFormat:(NSString*)format allowNaturalLanguage:(BOOL)flag;
|
|
{
|
|
if ((self = [super initWithDateFormat:format allowNaturalLanguage:flag])) {
|
|
CFLocaleRef userLocale = CFLocaleCopyCurrent();
|
|
if (userLocale) {
|
|
mLocaleFormatter = CFDateFormatterCreate(NULL,
|
|
userLocale,
|
|
kCFDateFormatterMediumStyle,
|
|
kCFDateFormatterNoStyle);
|
|
CFRelease(userLocale);
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
if (mLocaleFormatter)
|
|
CFRelease(mLocaleFormatter);
|
|
[super dealloc];
|
|
}
|
|
|
|
- (NSString*)stringForObjectValue:(id)anObject
|
|
{
|
|
if ([(NSDate*)anObject timeIntervalSince1970] == 0)
|
|
return NSLocalizedStringFromTableInBundle(@"CookieExpiresOnQuit", nil,
|
|
[NSBundle bundleForClass:[self class]], nil);
|
|
if (mLocaleFormatter) {
|
|
NSString* dateString = (NSString*)CFDateFormatterCreateStringWithDate(NULL,
|
|
mLocaleFormatter,
|
|
(CFDateRef)anObject);
|
|
if (dateString)
|
|
return [dateString autorelease];
|
|
}
|
|
|
|
// If all else fails, fall back on the standard date formatter
|
|
return [super stringForObjectValue:anObject];
|
|
}
|
|
|
|
@end
|