// // SOSAccountCircles.c // sec // #include "SOSAccountPriv.h" #include #include #include #include void SOSAccountForEachCircle(SOSAccountRef account, void (^process)(SOSCircleRef circle)) { CFDictionaryForEach(account->circles, ^(const void* key, const void* value) { assert(value); process((SOSCircleRef)value); }); } void SOSAccountForEachKnownCircle(SOSAccountRef account, void (^handle_incompatible)(CFStringRef name), void (^handle_no_peer)(SOSCircleRef circle), void (^handle_peer)(SOSCircleRef circle, SOSFullPeerInfoRef full_peer)) { CFDictionaryForEach(account->circles, ^(const void *key, const void *value) { if (isNull(value)) { if (handle_incompatible) handle_incompatible((CFStringRef)key); } else { SOSCircleRef circle = (SOSCircleRef) value; CFRetainSafe(circle); SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, SOSCircleGetName(circle), NULL); if (!fpi) { if (handle_no_peer) handle_no_peer(circle); } else { CFRetainSafe(fpi); if (handle_peer) handle_peer(circle, fpi); CFReleaseSafe(fpi); } CFReleaseSafe(circle); } }); } // // MARK: Circle management // int SOSAccountCountCircles(SOSAccountRef a) { assert(a); assert(a->circle_identities); assert(a->circles); return (int)CFDictionaryGetCount(a->circles); } SOSCircleRef SOSAccountFindCircle(SOSAccountRef a, CFStringRef name, CFErrorRef *error) { CFTypeRef entry = CFDictionaryGetValue(a->circles, name); require_action_quiet(!isNull(entry), fail, SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Incompatible circle in KVS"), NULL, error)); require_action_quiet(entry, fail, SOSCreateError(kSOSErrorNoCircle, CFSTR("No circle found"), NULL, error)); return (SOSCircleRef) entry; fail: return NULL; } static bool SOSAccountInflateTransportsForCircle(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error){ bool success = false; SOSTransportKeyParameterRef tKey = NULL; SOSTransportCircleRef tCircle = NULL; SOSTransportMessageRef tMessage = NULL; SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircleNamed(account, circleName, error); require_quiet(fpi, fail); SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi); require_quiet(myPeer, fail); CFStringRef type = SOSPeerInfoGetTransportType(myPeer); if(CFStringCompare(type, CFSTR("KVS"), 0) == kCFCompareEqualTo){ tKey = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(account, error); tCircle = (SOSTransportCircleRef)SOSTransportCircleKVSCreate(account, circleName, error); tMessage = (SOSTransportMessageRef)SOSTransportMessageKVSCreate(account, circleName, error); require_quiet(tKey, fail); require_quiet(tCircle, fail); require_quiet(tMessage, fail); CFRetainAssign(account->key_transport, (SOSTransportKeyParameterRef)tKey); CFDictionarySetValue(account->circle_transports, circleName, tCircle); CFDictionarySetValue(account->message_transports, circleName, tMessage); } success = true; fail: CFReleaseNull(tKey); CFReleaseNull(tCircle); CFReleaseNull(tMessage); return success; } SOSCircleRef SOSAccountEnsureCircle(SOSAccountRef a, CFStringRef name, CFErrorRef *error) { CFErrorRef localError = NULL; SOSCircleRef circle = SOSAccountFindCircle(a, name, &localError); require_action_quiet(circle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail, if (error) { *error = localError; localError = NULL; }); if(NULL == circle){ circle = SOSCircleCreate(NULL, name, NULL); if (circle){ CFDictionaryAddValue(a->circles, name, circle); CFRelease(circle); circle = SOSAccountFindCircle(a, name, &localError); } SOSUpdateKeyInterest(); } require_quiet(SOSAccountInflateTransportsForCircle(a, name, error), fail); fail: CFReleaseNull(localError); return circle; } bool SOSAccountUpdateCircleFromRemote(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error) { return SOSAccountHandleUpdateCircle(account, newCircle, false, error); } bool SOSAccountUpdateCircle(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error) { return SOSAccountHandleUpdateCircle(account, newCircle, true, error); } bool SOSAccountModifyCircle(SOSAccountRef account, CFStringRef circleName, CFErrorRef* error, bool (^action)(SOSCircleRef circle)) { bool success = false; SOSCircleRef circle = NULL; SOSCircleRef accountCircle = SOSAccountFindCircle(account, circleName, error); require_quiet(accountCircle, fail); circle = SOSCircleCopyCircle(kCFAllocatorDefault, accountCircle, error); require_quiet(circle, fail); success = true; require_quiet(action(circle), fail); success = SOSAccountUpdateCircle(account, circle, error); fail: CFReleaseSafe(circle); return success; }