PathRecordTypeConfig.m   [plain text]


/*
 * Copyright (c) 2003-2009 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*!
 * @header PathRecordTypeConfig
 */


#import "PathRecordTypeConfig.h"
#import "PathRecordConfig.h"
#import "DSoException.h"
#import "DSoDirectory.h"
#import "DSoNode.h"
#import "DSoRecord.h"
#import "DSoRecordPriv.h"

#import <opendirectory/odutils.h>

extern BOOL gHACK;

@interface PathRecordTypeConfig (Private)

- (void) _destroyRights;

@end


@implementation PathRecordTypeConfig (Private)

- (void)_destroyRights
{
	// free _authExternalForm
	if (_haveRights) {
		[_node customCall:eODCustomCallConfigureDestroyAuthRef
				 withAuthorization:&_authExternalForm];
	}
}

@end

@implementation PathRecordTypeConfig

// ----------------------------------------------------------------------------
// Initialization / teardown
#pragma mark ******** Initialization / teardown ********

- init
{
    [super init];
    bzero(&_authExternalForm,sizeof(_authExternalForm));
    return self;
}

- initWithNode:(DSoNode*)inNode recordType:(NSString*)inType
{
    [super initWithNode:inNode recordType:inType];
    bzero(&_authExternalForm,sizeof(_authExternalForm));
    return self;
}

- (void)dealloc
{
    [self _destroyRights];
    [super dealloc];
}

- (void)setAuthExternalForm:(AuthorizationExternalForm*)externalForm {
	// don't set _haveRights here since a node above us owns the auth right
	memcpy(&_authExternalForm, externalForm, sizeof(AuthorizationExternalForm));
}

// ----------------------------------------------------------------------------
// PathItemProtocol implementations
#pragma mark ******** PathItemProtocol implementations ********

- (NSArray*) getList:(NSString*)inKey
{
    NSArray *list = nil;

    NS_DURING
        if ([_recordType hasPrefix:@kDSStdRecordTypePrefix])
            list = [[_node findRecordNames:@kDSRecordsAll
                            ofType:[_recordType UTF8String]
                            matchType:eDSExact]
                        sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
        else
            list = [[_node findRecordNames:@kDSRecordsAll
                            ofType:[_recordType UTF8String]
                            matchType:eDSExact]
                        sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
	NS_HANDLER
		if (!DS_EXCEPTION_STATUS_IS(eDSRecordNotFound) &&
	        !DS_EXCEPTION_STATUS_IS(eDSInvalidRecordType))
		{
			[localException raise];
		}
	NS_ENDHANDLER

	return list;
}

- (NSArray*) getPossibleCompletionsFor:(NSString*)inPrefix
{
	NSMutableArray* possibleCompletions = nil;
	NSArray* currentList = [self getList];
	if (currentList != nil)
	{
		inPrefix = [inPrefix lowercaseString];
		possibleCompletions = [NSMutableArray array];
		NSEnumerator* listEnum = [currentList objectEnumerator];
		NSString* currentItem = nil;
		
		while (currentItem = (NSString*)[listEnum nextObject])
		{
			if ([[currentItem lowercaseString] hasPrefix:inPrefix])
				[possibleCompletions addObject:currentItem];
		}
	}
	
	return possibleCompletions;
}

- (tDirStatus) authenticateName:(NSString*)inUsername withPassword:(NSString*)inPassword authOnly:(BOOL)inAuthOnly
{
	NSAutoreleasePool* pool = [NSAutoreleasePool new];
	DSoSearchNode* searchNode = [[_node directory] searchNode];
	DSoUser* user = nil;
	tDirStatus status = eDSAuthFailed;
	NSMutableData* outputData = nil;
	
	NS_DURING
	user = [searchNode findUser:inUsername];
	if (user != nil) {
		status = [[user node] authenticateName:inUsername withPassword:inPassword authOnly:YES];
		if (status == eDSNoErr && inAuthOnly == NO) {
			outputData = [NSMutableData dataWithLength:sizeof(AuthorizationExternalForm)];
			status = [_node customCall:eODCustomCallConfigureGetAuthRef
							 sendItems:[NSArray arrayWithObjects:inUsername,inPassword,nil]
							outputData:outputData];
			if (status == eDSNoErr && [outputData length] >= sizeof( AuthorizationExternalForm ) )
			{
				[outputData getBytes:&_authExternalForm length:sizeof( AuthorizationExternalForm )];
				_haveRights = YES;
			}
		}
	}
	NS_HANDLER
	NS_ENDHANDLER
	
	[pool release];
	
    return status;
}

- (tDirStatus) createKey:(NSString*)inKey withValues:(NSArray*)inValues
{
	if (inValues == nil && [self cd:inKey] != nil)
	{
		return eDSNoErr;
	}
	else
	{
		return eDSPermissionError;
	}
}

- (PathItem*) cd:(NSString*)dest
{
    DSoRecord			*rec = nil;
    PathRecordConfig	*p   = nil;
    
    if (dest != nil && [dest length] > 0)
    {
		NS_DURING
		rec = [_node findRecord:dest ofType:[_recordType UTF8String]];
		NS_HANDLER
		if (gHACK && DS_EXCEPTION_STATUS_IS(eDSRecordNotFound)) // Hack to force read-only entry into a record which doesn't implement dsOpenRecord()
			rec = [[[DSoRecord alloc] initInNode:_node
											type:[_recordType UTF8String] name:dest create:NO] autorelease];
		else
			[localException raise];
		NS_ENDHANDLER
		
        if (rec != nil)
            p = [[PathRecordConfig alloc] initWithRecord:rec];
		
		[p setAuthExternalForm:&_authExternalForm];

        return [p autorelease];
    }
    else
        return nil;
}

- (tDirStatus) read:(NSString*)inPath keys:(NSArray*)inKeys
{
    NSAutoreleasePool      *pool	= [[NSAutoreleasePool alloc] init];
    tDirStatus status = eDSRecordNotFound;
    NSArray* foundRecords = nil;
	NSMutableDictionary* foundRecord = nil;
    NSUInteger recordIndex = 0;
    NSUInteger recordCount = 0;
	
    NS_DURING
	if ([_recordType hasPrefix:@kDSStdRecordTypePrefix])
		foundRecords = [_node findRecordNames:@kDSRecordsAll andAttributes:[NSArray arrayWithObject:@kDSAttributesAll]
									   ofType:[_recordType UTF8String] matchType:eDSExact];
	else
		foundRecords = [_node findRecordNames:@kDSRecordsAll andAttributes:[NSArray arrayWithObject:@kDSAttributesAll] 
									   ofType:[_recordType UTF8String] matchType:eDSExact];
    NS_HANDLER
	[localException retain];
	[pool release];
	[[localException autorelease] raise];
    NS_ENDHANDLER
    
    recordCount = [foundRecords count];
    for (recordIndex = 0; recordIndex < recordCount; recordIndex++)
    {
        NSDictionary *record = [foundRecords objectAtIndex:recordIndex];
		NSArray *values = [record objectForKey:@kDSNAttrRecordName];
		if ([values count] > 0 && [values containsObject:inPath])
		{
			foundRecord = [[record mutableCopy] autorelease];
			status = eDSNoErr;
			break;
		}
    }
	if (foundRecord != nil)
	{
		if ([inKeys count] > 0)
		{
			//NSArray* niceKeys    = prefixedAttributeKeysWithNode([_record node], inKeys);
			NSMutableDictionary* attribsFiltered = [NSMutableDictionary dictionary];
			for (NSString *key in inKeys) {
				NSString *niceKey = nil;
				if ([key hasPrefix:@kDSStdAttrTypePrefix] || [key hasPrefix:@kDSNativeAttrTypePrefix])
				{
					niceKey = key;
				}
				else if ([key isEqualToString:@kDSAttributesStandardAll])
				{
					for (NSString *aKey in [foundRecord allKeys])
					{
						if ([aKey hasPrefix:@kDSStdAttrTypePrefix]) {
							[attribsFiltered setObject:[foundRecord objectForKey:aKey] forKey:aKey];
						}
					}
					continue;
				}
				else if ([key isEqualToString:@kDSAttributesNativeAll])
				{
					for (NSString *aKey in [foundRecord allKeys])
					{
						if ([aKey hasPrefix:@kDSNativeAttrTypePrefix]) {
							[attribsFiltered setObject:[foundRecord objectForKey:aKey] forKey:aKey];
						}
					}
					continue;
				}
				else
				{
					niceKey = [@kDSStdAttrTypePrefix stringByAppendingString:key];
					if ([foundRecord objectForKey: niceKey] == nil && ![[[_node directory] standardAttributeTypes] containsObject:niceKey])
						niceKey = [@kDSNativeAttrTypePrefix stringByAppendingString:key];
				}
				id value = [foundRecord objectForKey:niceKey];
				if (value != nil) {
					[attribsFiltered setObject:value forKey:niceKey];
				}
			}
			foundRecord = [[attribsFiltered copy] autorelease];
		}
		[self printDictionary:foundRecord withRequestedKeys:inKeys];
	}
    
    [pool release];
    return status;
}

@end