Beispiel #1
0
int
odkerb_get_im_handle_with_user_record(ODRecordRef userRecord, CFStringRef imType, CFStringRef realm, CFStringRef allegedShortName, char im_handle[], size_t im_handle_size)
{
    int retval = -1;
    CFArrayRef cfIMHandles = NULL;
    CFErrorRef cfError = NULL;
    CFMutableArrayRef cfMatches = NULL;
    CFStringRef cfRealID = NULL;
    int i;

    ODKERB_PARAM_ASSERT(userRecord != NULL);
    ODKERB_PARAM_ASSERT(allegedShortName != NULL);
    ODKERB_PARAM_ASSERT(im_handle != 0);
    ODKERB_PARAM_ASSERT(im_handle_size > 0);

    *im_handle = '\0';

    cfIMHandles = ODRecordCopyValues(userRecord, kODAttributeTypeIMHandle, &cfError);
    if (cfIMHandles == NULL || cfError != NULL) {
        ODKERB_LOG_CFERROR(LOG_ERR, "Unable to obtain IM handles", cfError);
        goto failure;
    }
    else if (CFArrayGetCount(cfIMHandles) == 0) {
        ODKERB_LOG_CFSTRING(LOG_DEBUG, "No IM handles", allegedShortName);
        goto failure;
    }

    /* there could be many IM handles that look plausible, so we heuristically determine which
     * one is the most likely to be the correct one.  imagine, for instance, that the following
     * ones are available:
     *    JABBER: [email protected]
     *    JABBER: [email protected]
     *    JABBER: [email protected]
     *    YAHOO:  [email protected]
     */

    /* first, remove those of the wrong type or realm because they can't possibly be right */

    cfMatches = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, cfIMHandles);
    if (cfMatches == NULL) {
        ODKERB_LOG_ERRNO(LOG_ERR, ENOMEM);
        goto failure;
    }

    for (i = CFArrayGetCount(cfMatches) - 1; i >= 0; --i) {
        CFStringRef cfID = CFArrayGetValueAtIndex(cfMatches, i);

        if (cfID != NULL
         && odkerb_CFStringHasPrefixWithOptions(cfID, imType, kCFCompareCaseInsensitive)
         && odkerb_CFStringHasSuffixWithOptions(cfID, realm, kCFCompareCaseInsensitive))
            continue;

        /* isn't a match, so remove it from the list */
        CFArrayRemoveValueAtIndex(cfMatches, i);
    }

    CFStringRef match = NULL;

    if (CFArrayGetCount(cfMatches) == 0) {
        ODKERB_LOG_CFSTRING(LOG_INFO, "No IM handles matching type and realm", allegedShortName);
        goto failure;
    }
    else if (CFArrayGetCount(cfMatches) == 1) {
        match = CFArrayGetValueAtIndex(cfMatches, 0);
        goto found_match;
    }

    /* second, attempt to use the short name to disasmbiguate among the several choices */

    for (i = 0; i < CFArrayGetCount(cfMatches); ++i) {
        CFStringRef cfID = CFArrayGetValueAtIndex(cfMatches, i);
        if (cfID == NULL)
            continue;

        CFRange where = CFStringFind(cfID, allegedShortName, kCFCompareCaseInsensitive | kCFCompareDiacriticInsensitive);
        if (where.location != kCFNotFound) {
            match = cfID;
            goto found_match;
        }
    }

    /* at this point, there are several possibilities, but none of them contain the
     * short name, so just choose the first one */
    match = CFArrayGetValueAtIndex(cfMatches, 0);

found_match:
    assert(match != NULL);

    /* the ID is the substring following the IM type specifier prefix (kIMTypeJABBER) */

    assert(CFStringGetLength(match) > CFStringGetLength(imType));

    cfRealID = CFStringCreateWithSubstring(kCFAllocatorDefault, match,
                                           CFRangeMake(CFStringGetLength(imType), CFStringGetLength(match)-CFStringGetLength(imType)));
    if (cfRealID == NULL) {
        ODKERB_LOG_ERRNO(LOG_ERR, ENOMEM);
        goto failure;
    }

    if (CFStringGetCString(cfRealID, im_handle, im_handle_size-1, kCFStringEncodingUTF8) == FALSE) {
        ODKERB_LOG_CFSTRING(LOG_ERR, "Cannot obtain IM handle string", cfRealID);
        goto failure;
    }

    retval = 0;
failure:
    CF_SAFE_RELEASE(cfError);
    CF_SAFE_RELEASE(cfRealID);
    CF_SAFE_RELEASE(cfMatches);
    CF_SAFE_RELEASE(cfIMHandles);

    return retval;
}
Beispiel #2
0
__private_extern__
void
set_service(int argc, char **argv)
{
	Boolean	ok;

	if (net_service == NULL) {
		SCPrint(TRUE, stdout, CFSTR("service not selected\n"));
		return;
	}

	if (argc < 1) {
		SCPrint(TRUE, stdout, CFSTR("set what?\n"));
		return;
	}

	while (argc > 0) {
		char	*command;

		command = argv[0];
		argv++;
		argc--;

		if (strcmp(command, "name") == 0) {
			CFStringRef	serviceName;

			if (argc < 1) {
				SCPrint(TRUE, stdout, CFSTR("name not specified\n"));
				return;
			}

			serviceName = (strlen(argv[0]) > 0)
					? CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8)
					: NULL;
			argv++;
			argc--;

			ok = SCNetworkServiceSetName(net_service, serviceName);
			if (serviceName != NULL) CFRelease(serviceName);
			if (!ok) {
				SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
				return;
			}

			_prefs_changed = TRUE;
		} else if (strcmp(command, "order") == 0) {

			char		*end;
			long		newIndex;
			CFIndex		nServices;
			char		*str;
			CFArrayRef	services;

			services = SCNetworkSetCopyServices(net_set);
			nServices = CFArrayGetCount(services);
			CFRelease(services);

			if (argc < 1) {
				SCPrint(TRUE, stdout, CFSTR("order not specified\n"));
				return;
			}

			if (net_set == NULL) {
				SCPrint(TRUE, stdout, CFSTR("set not selected\n"));
				return;
			}

			str = argv[0];
			argv++;
			argc--;

			errno = 0;
			newIndex = strtol(str, &end, 10);
			if ((*str != '\0') && (*end == '\0') && (errno == 0)) {
				if ((newIndex > 0) && (newIndex <= nServices)) {
					CFIndex			curIndex;
					CFMutableArrayRef	newOrder;
					CFArrayRef		order;
					CFStringRef		serviceID	= SCNetworkServiceGetServiceID(net_service);

					order = SCNetworkSetGetServiceOrder(net_set);
					if (order == NULL) {
						newOrder = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
					} else {
						newOrder = CFArrayCreateMutableCopy(NULL, 0, order);
					}

					curIndex = CFArrayGetFirstIndexOfValue(newOrder,
									       CFRangeMake(0, CFArrayGetCount(newOrder)),
									       serviceID);
					if (curIndex != kCFNotFound) {
						CFArrayRemoveValueAtIndex(newOrder, curIndex);
					}

					if (newIndex <= CFArrayGetCount(newOrder)) {
						CFArrayInsertValueAtIndex(newOrder, newIndex - 1, serviceID);
					} else {
						CFArrayAppendValue(newOrder, serviceID);
					}

					ok = SCNetworkSetSetServiceOrder(net_set, newOrder);
					CFRelease(newOrder);
					if (!ok) {
						SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
						return;
					}

					_prefs_changed = TRUE;
				} else {
					SCPrint(TRUE, stdout, CFSTR("set order to what?\n"));
					return;
				}
			} else {
				SCPrint(TRUE, stdout, CFSTR("set what?\n"));
				return;
			}
		} else if (strcmp(command, "rank") == 0) {
			SCNetworkServicePrimaryRank	rank	= kSCNetworkServicePrimaryRankDefault;
			SCNetworkServiceRef		service	= (argc < 2) ? net_service : NULL;

			if (argc < 1) {
				SCPrint(TRUE, stdout, CFSTR("rank not specified\n"));
				return;
			}

			if (strlen(argv[0]) > 0) {
				if (strcasecmp(argv[0], "Never") == 0) {
					rank = kSCNetworkServicePrimaryRankNever;
				} else if ((service != net_service) && (strcasecmp(argv[0], "First") == 0)) {
					rank = kSCNetworkServicePrimaryRankFirst;
				} else if ((service != net_service) && (strcasecmp(argv[0], "Last") == 0)) {
					rank = kSCNetworkServicePrimaryRankLast;
				} else if ((service != net_service) && (strcasecmp(argv[0], "Scoped") == 0)) {
					rank = kSCNetworkServicePrimaryRankScoped;
				} else {
					SCPrint(TRUE, stdout, CFSTR("rank not valid\n"));
					return;
				}
			}
			argv++;
			argc--;

			if (service == NULL) {
				CFStringRef		serviceID;
				SCDynamicStoreRef	store;

				store = SCDynamicStoreCreate(NULL,
							     CFSTR("scutil (set primary rank)"),
							     NULL,
							     NULL);
				serviceID = SCNetworkServiceGetServiceID(net_service);
				service = _SCNetworkServiceCopyActive(store, serviceID);
				CFRelease(store);

				argv++;
				argc--;
			}

			ok = SCNetworkServiceSetPrimaryRank(service, rank);
			if (service != net_service) CFRelease(service);
			if (ok) {
				if (service == net_service) _prefs_changed = TRUE;
			} else {
				SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
				return;
			}
		} else if (strcmp(command, "id") == 0) {
			CFStringRef	serviceID;

			if ((argc < 1) || (strlen(argv[0]) == 0)) {
				SCPrint(TRUE, stdout, CFSTR("set id not specified\n"));
				return;
			}

			serviceID = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
			argv++;
			argc--;

			ok = _SCNetworkServiceSetServiceID(net_service, serviceID);
			CFRelease(serviceID);
			if (!ok) {
				SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError()));
				return;
			}

			_prefs_changed = TRUE;
		} else {
			SCPrint(TRUE, stdout, CFSTR("set what?\n"));
		}
	}

	return;
}
QStringList QFSEventsFileSystemWatcherEngine::removePaths(const QStringList &paths,
                                                          QStringList *files,
                                                          QStringList *directories)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 && !defined(Q_OS_IOS)
    stop();
    wait();
    QMutexLocker locker(&mutex);
    // short circuit for smarties that call remove before add and we have nothing.
    if (pathsToWatch == 0)
        return paths;
    QStringList failedToRemove;
    // if we have a running FSStreamEvent, we have to stop it, we'll re-add the stream soon.
    FSEventStreamEventId idToCheck;
    if (fsStream) {
        idToCheck = FSEventStreamGetLatestEventId(fsStream);
        cleanupFSStream(fsStream);
        fsStream = 0;
    } else {
        idToCheck = kFSEventStreamEventIdSinceNow;
    }

    CFIndex itemCount = CFArrayGetCount(pathsToWatch);
    QCFType<CFMutableArrayRef> tmpArray = CFArrayCreateMutableCopy(kCFAllocatorDefault, itemCount,
                                                                   pathsToWatch);
    CFRelease(pathsToWatch);
    pathsToWatch = 0;
    for (int i = 0; i < paths.size(); ++i) {
        // Get the itemCount at the beginning to avoid any overruns during the iteration.
        itemCount = CFArrayGetCount(tmpArray);
        const QString &path = paths.at(i);
        QFileInfo fi(path);
        QCFString cfpath(createFSStreamPath(fi.canonicalPath()));

        CFIndex index = CFArrayGetFirstIndexOfValue(tmpArray, CFRangeMake(0, itemCount), cfpath);
        if (index != -1) {
            CFArrayRemoveValueAtIndex(tmpArray, index);
            files->removeAll(path);
            removePathFromHash(filePathInfoHash, cfpath, path);
        } else {
            // Could be a directory we are watching instead.
            QCFString cfdirpath(createFSStreamPath(fi.canonicalFilePath()));
            index = CFArrayGetFirstIndexOfValue(tmpArray, CFRangeMake(0, itemCount), cfdirpath);
            if (index != -1) {
                CFArrayRemoveValueAtIndex(tmpArray, index);
                directories->removeAll(path);
                removePathFromHash(dirPathInfoHash, cfpath, path);
            } else {
                failedToRemove.append(path);
            }
        }
    }
    itemCount = CFArrayGetCount(tmpArray);
    if (itemCount != 0) {
        pathsToWatch = CFArrayCreateCopy(kCFAllocatorDefault, tmpArray);

        FSEventStreamContext context = { 0, this, 0, 0, 0 };
        fsStream = FSEventStreamCreate(kCFAllocatorDefault,
                                       QFSEventsFileSystemWatcherEngine::fseventsCallback,
                                       &context, pathsToWatch, idToCheck, Latency, QtFSEventFlags);
        warmUpFSEvents();
    }
    return failedToRemove;
#else
    Q_UNUSED(paths);
    Q_UNUSED(files);
    Q_UNUSED(directories);
    return QStringList();
#endif
}
__private_extern__ CFArrayRef  _CFPreferencesCreateDomainList(CFStringRef  userName, CFStringRef  hostName) {
    CFAllocatorRef prefAlloc = __CFPreferencesAllocator();
    CFArrayRef  domains;
    CFMutableArrayRef  marray;
    CFStringRef  *cachedDomainKeys;
    CFPreferencesDomainRef *cachedDomains;
    SInt32 idx, cnt;
    CFStringRef  suffix;
    UInt32 suffixLen;
    CFURLRef prefDir = _preferencesDirectoryForUserHost(userName, hostName);
    
    if (!prefDir) {
        return NULL;
    }
    if (hostName == kCFPreferencesAnyHost) {
        suffix = CFStringCreateWithCString(prefAlloc, ".plist", kCFStringEncodingASCII);
    } else if (hostName == kCFPreferencesCurrentHost) {
        CFStringRef hostID = _CFPreferencesGetByHostIdentifierString();
        suffix = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR(".%@.plist"), hostID);
    } else {
        suffix = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR(".%@.plist"), hostName);   // sketchy - this allows someone to create a domain list for an arbitrary hostname.
    }
    suffixLen = CFStringGetLength(suffix);
    
    domains = (CFArrayRef)CFURLCreatePropertyFromResource(prefAlloc, prefDir, kCFURLFileDirectoryContents, NULL);
    CFRelease(prefDir);
    if (domains){
        marray = CFArrayCreateMutableCopy(prefAlloc, 0, domains);
        CFRelease(domains);
    } else {
        marray = CFArrayCreateMutable(prefAlloc, 0, & kCFTypeArrayCallBacks);
    }
    for (idx = CFArrayGetCount(marray)-1; idx >= 0; idx --) {
        CFURLRef  url = (CFURLRef)CFArrayGetValueAtIndex(marray, idx);
        CFStringRef string = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
        if (!CFStringHasSuffix(string, suffix)) {
            CFArrayRemoveValueAtIndex(marray, idx);
        } else {
            CFStringRef  dom = CFStringCreateWithSubstring(prefAlloc, string, CFRangeMake(0, CFStringGetLength(string) - suffixLen));
            if (CFEqual(dom, CFSTR(".GlobalPreferences"))) {
                CFArraySetValueAtIndex(marray, idx, kCFPreferencesAnyApplication);
            } else {
                CFArraySetValueAtIndex(marray, idx, dom);
            }
            CFRelease(dom);
        }
        CFRelease(string);
    }
    CFRelease(suffix);
    
    // Now add any domains added in the cache; delete any that have been deleted in the cache
    __CFSpinLock(&domainCacheLock);
    if (!domainCache) {
        __CFSpinUnlock(&domainCacheLock);
        return marray;
    }
    cnt = CFDictionaryGetCount(domainCache);
    cachedDomainKeys = (CFStringRef *)CFAllocatorAllocate(prefAlloc, 2 * cnt * sizeof(CFStringRef), 0);
    cachedDomains = (CFPreferencesDomainRef *)(cachedDomainKeys + cnt);
    CFDictionaryGetKeysAndValues(domainCache, (const void **)cachedDomainKeys, (const void **)cachedDomains);
    __CFSpinUnlock(&domainCacheLock);
    suffix = _CFPreferencesCachePrefixForUserHost(userName, hostName);
    suffixLen = CFStringGetLength(suffix);
    
    for (idx = 0; idx < cnt; idx ++) {
        CFStringRef  domainKey = cachedDomainKeys[idx];
        CFPreferencesDomainRef domain = cachedDomains[idx];
        CFStringRef  domainName;
        CFIndex keyCount = 0;
        
        if (!CFStringHasPrefix(domainKey, suffix)) continue;
        domainName = CFStringCreateWithSubstring(prefAlloc, domainKey, CFRangeMake(suffixLen, CFStringGetLength(domainKey) - suffixLen));
        if (CFEqual(domainName, CFSTR("*"))) {
            CFRelease(domainName);
            domainName = (CFStringRef)CFRetain(kCFPreferencesAnyApplication);
        } else if (CFEqual(domainName, kCFPreferencesCurrentApplication)) {
            CFRelease(domainName);
            domainName = (CFStringRef)CFRetain(_CFProcessNameString());
        }
        CFDictionaryRef d = _CFPreferencesDomainDeepCopyDictionary(domain);
        keyCount = d ? CFDictionaryGetCount(d) : 0;
        if (keyCount) CFRelease(d);
        if (keyCount == 0) {
            // Domain was deleted
            SInt32 firstIndexOfValue = CFArrayGetFirstIndexOfValue(marray, CFRangeMake(0, CFArrayGetCount(marray)), domainName);
            if (0 <= firstIndexOfValue) {
                CFArrayRemoveValueAtIndex(marray, firstIndexOfValue);
            }
        } else if (!CFArrayContainsValue(marray, CFRangeMake(0, CFArrayGetCount(marray)), domainName)) {
            CFArrayAppendValue(marray, domainName);
        }
        CFRelease(domainName);
    }
    CFRelease(suffix);
    CFAllocatorDeallocate(prefAlloc, cachedDomainKeys);
    return marray;
}
__private_extern__ kern_return_t _io_pm_hid_event_report_activity(
    mach_port_t server,
    audit_token_t token,                                                        
    int         _action)
{
    pid_t                               callerPID;
    CFNumberRef                         appPID = NULL;
    int                                 _app_pid_;
    CFMutableDictionaryRef              foundDictionary = NULL;
    CFMutableArrayRef                   bucketsArray = NULL;
    CFDataRef                           dataEvent = NULL;
    IOPMHIDPostEventActivityWindow      *ev = NULL;
    CFAbsoluteTime                      timeNow = CFAbsoluteTimeGetCurrent();
    int                                 arrayCount = 0;
    int                                 i = 0;
    
    // Unwrapping big data structure...
    if (!gHIDEventHistory) {
        gHIDEventHistory = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks);
    }
    if (!gHIDEventHistory) {
        goto exit;
    }
    
    audit_token_to_au32(token, NULL, NULL, NULL, NULL, NULL, &callerPID, NULL, NULL);

    if (0 !=(arrayCount = CFArrayGetCount(gHIDEventHistory)))
    {
        // Scan through the array to find an existing dictionary for the given pid
        for (i=0; i<arrayCount; i++)
        {
            CFMutableDictionaryRef dictionaryForApp = NULL;
            dictionaryForApp = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(gHIDEventHistory, i);
            if (!dictionaryForApp) {
                break;
            }
            appPID = CFDictionaryGetValue(dictionaryForApp, kIOPMHIDAppPIDKey);
            if (appPID) {
                CFNumberGetValue(appPID, kCFNumberIntType, &_app_pid_);
                if (callerPID == _app_pid_) {
                    foundDictionary = dictionaryForApp;
                    break;
                }
            }
        }
    }
    
    // Unwrapping big data structure...
    if (!foundDictionary) {
        foundDictionary = CFDictionaryCreateMutable(0, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        CFArrayAppendValue(gHIDEventHistory, foundDictionary);
        CFRelease(foundDictionary);
        
        /* Tag our pid */
        appPID = CFNumberCreate(0, kCFNumberIntType, &callerPID);
        if (appPID) {
            CFDictionarySetValue(foundDictionary, kIOPMHIDAppPIDKey, appPID);
            CFRelease(appPID);
        }

        /* Tag the process name */
        CFStringRef appName = NULL;
        char    appBuf[MAXPATHLEN];
        int     len = proc_name(callerPID, appBuf, MAXPATHLEN);
        if (0 != len) {
            appName = CFStringCreateWithCString(0, appBuf, kCFStringEncodingMacRoman);
            if (appName) {
                CFDictionarySetValue(foundDictionary, kIOPMHIDAppPathKey, appName);
                CFRelease(appName);
            }
        }
    }

    if (!foundDictionary)
        goto exit;

    // Unwrapping big data structure...
    bucketsArray = (CFMutableArrayRef)CFDictionaryGetValue(foundDictionary, kIOPMHIDHistoryArrayKey);
    if (!bucketsArray) {
        bucketsArray = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks);
        CFDictionarySetValue(foundDictionary, kIOPMHIDHistoryArrayKey, bucketsArray);
        CFRelease(bucketsArray);
    }
    if (!bucketsArray) 
        goto exit;

    // Check last HID event bucket timestamp - is it more than 5 minutes old?
    bool foundWindowForEvent = false;
    if (0 < CFArrayGetCount(bucketsArray)) {
        dataEvent = (CFDataRef)CFArrayGetValueAtIndex(bucketsArray, 0);
    }
    if (dataEvent) {
        ev = (IOPMHIDPostEventActivityWindow *)CFDataGetBytePtr(dataEvent);
        if (timeNow < (ev->eventWindowStart + kFiveMinutesInSeconds))
        {
            // This HID event gets dropped into this existing 5 minute bucket.
            // We bump the count for HID activity!
            if (__NX_NULL_EVENT == _action) {
                ev->nullEventCount++;
            } else {
                ev->hidEventCount++;
            }
            foundWindowForEvent = true;
        }
    }

    if (!foundWindowForEvent) {
        IOPMHIDPostEventActivityWindow  newv;

        // We align the starts of our windows with 5 minute intervals
        newv.eventWindowStart = ((int)timeNow / (int)kFiveMinutesInSeconds) * kFiveMinutesInSeconds;
        newv.nullEventCount = newv.hidEventCount = 0;
        if (__NX_NULL_EVENT == _action) {
            newv.nullEventCount++;
        } else {
            newv.hidEventCount++;
        }
    
        dataEvent = CFDataCreate(0, (const UInt8 *)&newv, sizeof(IOPMHIDPostEventActivityWindow));
        if (dataEvent) {
            CFArrayInsertValueAtIndex(bucketsArray, 0, dataEvent);
            CFRelease(dataEvent);
        }
        
        // If we've recorded more than kMaxFiveMinutesWindowsCount activity windows for this process, delete the old ones.
        while (kMaxFiveMinutesWindowsCount < CFArrayGetCount(bucketsArray)) {
            CFArrayRemoveValueAtIndex(bucketsArray, CFArrayGetCount(bucketsArray) - 1);
        }
        
    }

exit:
    return KERN_SUCCESS;
}
extern pascal OSStatus MoreSCCreateCCLArray(CFArrayRef *result, CFIndex *indexOfDefaultCCL)
	// See comment in header.
{
	OSStatus 			err;
	CFMutableArrayRef	localResult;
	UInt32   			domainIndex;
	FSRef				folderRef;
	static const SInt16 kFolderDomains[] = {kUserDomain, kNetworkDomain, kLocalDomain, kSystemDomain, 0};
	
	assert( result != NULL);
	assert(*result == NULL);
	
	// Create an array containing the names of the CCLs from the Modem Scripts 
	// folder in each domain.

	localResult = NULL;
		
	err = CFQArrayCreateMutable(&localResult);
	if (err == noErr) {
		UInt32 scannedFolders;
		
		scannedFolders = 0;
		domainIndex = 0;
		do {
			err = FSFindFolder(kFolderDomains[domainIndex], kModemScriptsFolderType, false, &folderRef);
			if (err != noErr) {
				// If we can't find the folder in this domain, just ignore the domain.
				err = noErr;
			} else {
				scannedFolders += 1;
				// If we found the folder, add each CCL in it to the array.
				err = AddCCLsInFolderToArray(&folderRef, localResult);
			}
			domainIndex += 1;
		} while (err == noErr && kFolderDomains[domainIndex] != 0);
		
		// Testing reveals that under certain circumstances, the above loop 
		// will never find any folders.  The specific case I saw was on 
		// Mac OS 9.1 with CarbonLib 1.6 when running the application off 
		// the non-boot volume.  So, if FSFindFolder never returns any 
		// folders in the domains we looped over above, let's do it the old 
		// way and call FSFindFolder with kOnSystemDisk.
		//
		// I didn't file a bug against FSFindFolder because traditional Mac OS 
		// bugs are no longer being fixed at this time.
		// -- Quinn, 10 Dec 2002
		
		if ( (err == noErr) && (scannedFolders == 0) ) {
			if (FSFindFolder(kOnSystemDisk, kModemScriptsFolderType, false, &folderRef) == noErr) {
				err = AddCCLsInFolderToArray(&folderRef, localResult);
			}
		}
	}
	
	// Sort the resulting array and delete any duplicates.
	
	if (err == noErr) {
		CFIndex cursor;
		
		CFArraySortValues(localResult, CFRangeMake(0, CFArrayGetCount(localResult)), 
						  (CFComparatorFunction) CFStringCompare, (void *) kMyStringCompareOptions);
		
		cursor = 1;
		while (cursor < CFArrayGetCount(localResult)) {
			if ( CFEqual(CFArrayGetValueAtIndex(localResult, cursor), CFArrayGetValueAtIndex(localResult, cursor - 1)) ) {
				CFArrayRemoveValueAtIndex(localResult, cursor);
			} else {
				cursor += 1;
			}
		}
	}
	
	// Find the index of the default CCL (or use the first CCL if the default 
	// isn't found).  The array is already sorted for user presentation, so 
	// we can use CFArrayBSearchValues rather than searching by hand.  This 
	// might even be a relevant speed increase because the number of CCLs can 
	// range into the hundreds.
	
	if (err == noErr && indexOfDefaultCCL != NULL) {
		CFStringRef defaultCCLName;
		CFIndex     itemIndex;
		
		if (gDefaultCCL == NULL) {
			defaultCCLName = CFSTR("Apple Internal 56K Modem (v.90)");
		} else {
			defaultCCLName = gDefaultCCL;
		}

		itemIndex = CFArrayBSearchValues(localResult, CFRangeMake(0, CFArrayGetCount(localResult)), 
											defaultCCLName, 
											(CFComparatorFunction) CFStringCompare, (void *) kMyStringCompareOptions);
		// itemIndex is either:
		//
		// o pointing directly at the correct element, if an exact match is found, or 
		//
		// o if no exact match is found, pointing after the element that's immediately 
		//   less than defaultCCLName
		//
		// So, to confirm that we have the default script we check that the item is in 
		// bounds and that its value matches defaultCCLName.  If either of these 
		// checks fails, we return the index of the first CCL.
		
		if ( (itemIndex < CFArrayGetCount(localResult)) 
				&& (CFStringCompare(defaultCCLName, 
									(CFStringRef) CFArrayGetValueAtIndex(localResult, itemIndex), 
									kMyStringCompareOptions) == kCFCompareEqualTo)) {
			*indexOfDefaultCCL = itemIndex;
		} else {
			*indexOfDefaultCCL = 0;
		}
	}

	// Clean up.
	
	if (err != noErr) {
		CFQRelease(localResult);
		localResult = NULL;
	}
	*result = localResult;
	
	assert( (err == noErr) == (*result != NULL) );
	assert( 	(err != noErr) 							// either we got an error
				 || (indexOfDefaultCCL == NULL) 				// or the user didn't ask for the default CCL
				 || (CFArrayGetCount(*result) == 0) 		// or there are no CCLs
				 || (*indexOfDefaultCCL >= 0 && *indexOfDefaultCCL < CFArrayGetCount(*result)) );
				 											// or the default CCL we're returning is in bounds

	return err;
}