1//
2//  SOSAccountCircles.c
3//  sec
4//
5
6#include "SOSAccountPriv.h"
7#include <SecureObjectSync/SOSTransport.h>
8#include <SecureObjectSync/SOSTransportKeyParameterKVS.h>
9#include <SecureObjectSync/SOSTransportCircleKVS.h>
10#include <SecureObjectSync/SOSTransportMessageKVS.h>
11
12void SOSAccountForEachCircle(SOSAccountRef account, void (^process)(SOSCircleRef circle))
13{
14    CFDictionaryForEach(account->circles, ^(const void* key, const void* value) {
15        assert(value);
16        process((SOSCircleRef)value);
17    });
18}
19
20
21void SOSAccountForEachKnownCircle(SOSAccountRef account,
22                                  void (^handle_incompatible)(CFStringRef name),
23                                  void (^handle_no_peer)(SOSCircleRef circle),
24                                  void (^handle_peer)(SOSCircleRef circle, SOSFullPeerInfoRef full_peer)) {
25    CFDictionaryForEach(account->circles, ^(const void *key, const void *value) {
26        if (isNull(value)) {
27            if (handle_incompatible)
28                handle_incompatible((CFStringRef)key);
29        } else {
30            SOSCircleRef circle = (SOSCircleRef) value;
31            CFRetainSafe(circle);
32            SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, SOSCircleGetName(circle), NULL);
33            if (!fpi) {
34                if (handle_no_peer)
35                    handle_no_peer(circle);
36            } else {
37                CFRetainSafe(fpi);
38                if (handle_peer)
39                    handle_peer(circle, fpi);
40                CFReleaseSafe(fpi);
41            }
42            CFReleaseSafe(circle);
43        }
44    });
45}
46
47//
48// MARK: Circle management
49//
50
51int SOSAccountCountCircles(SOSAccountRef a) {
52    assert(a);
53    assert(a->circle_identities);
54    assert(a->circles);
55    return (int)CFDictionaryGetCount(a->circles);
56}
57
58
59
60SOSCircleRef SOSAccountFindCircle(SOSAccountRef a, CFStringRef name, CFErrorRef *error)
61{
62    CFTypeRef entry = CFDictionaryGetValue(a->circles, name);
63
64    require_action_quiet(!isNull(entry), fail,
65                         SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Incompatible circle in KVS"), NULL, error));
66
67    require_action_quiet(entry, fail,
68                         SOSCreateError(kSOSErrorNoCircle, CFSTR("No circle found"), NULL, error));
69
70
71    return (SOSCircleRef) entry;
72
73fail:
74    return NULL;
75}
76
77
78static bool SOSAccountInflateTransportsForCircle(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error){
79    bool success = false;
80    SOSTransportKeyParameterRef tKey = NULL;
81    SOSTransportCircleRef tCircle = NULL;
82    SOSTransportMessageRef tMessage = NULL;
83    SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircleNamed(account, circleName, error);
84    require_quiet(fpi, fail);
85    SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
86    require_quiet(myPeer, fail);
87    CFStringRef type = SOSPeerInfoGetTransportType(myPeer);
88    if(CFStringCompare(type, CFSTR("KVS"), 0) == kCFCompareEqualTo){
89        tKey = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(account, error);
90        tCircle = (SOSTransportCircleRef)SOSTransportCircleKVSCreate(account, circleName, error);
91        tMessage = (SOSTransportMessageRef)SOSTransportMessageKVSCreate(account, circleName, error);
92        require_quiet(tKey, fail);
93        require_quiet(tCircle, fail);
94        require_quiet(tMessage, fail);
95
96        CFRetainAssign(account->key_transport, (SOSTransportKeyParameterRef)tKey);
97        CFDictionarySetValue(account->circle_transports, circleName, tCircle);
98        CFDictionarySetValue(account->message_transports, circleName, tMessage);
99    }
100
101    success = true;
102fail:
103    CFReleaseNull(tKey);
104    CFReleaseNull(tCircle);
105    CFReleaseNull(tMessage);
106    return success;
107}
108
109SOSCircleRef SOSAccountEnsureCircle(SOSAccountRef a, CFStringRef name, CFErrorRef *error)
110{
111    CFErrorRef localError = NULL;
112
113    SOSCircleRef circle = SOSAccountFindCircle(a, name, &localError);
114
115    require_action_quiet(circle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail,
116                         if (error) { *error = localError; localError = NULL; });
117
118    if(NULL == circle){
119        circle = SOSCircleCreate(NULL, name, NULL);
120        if (circle){
121            CFDictionaryAddValue(a->circles, name, circle);
122            CFRelease(circle);
123            circle = SOSAccountFindCircle(a, name, &localError);
124        }
125
126        SOSUpdateKeyInterest();
127    }
128
129    require_quiet(SOSAccountInflateTransportsForCircle(a, name, error), fail);
130
131fail:
132    CFReleaseNull(localError);
133    return circle;
134}
135
136
137bool SOSAccountUpdateCircleFromRemote(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error)
138{
139    return SOSAccountHandleUpdateCircle(account, newCircle, false, error);
140}
141
142bool SOSAccountUpdateCircle(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error)
143{
144    return SOSAccountHandleUpdateCircle(account, newCircle, true, error);
145}
146
147bool SOSAccountModifyCircle(SOSAccountRef account,
148                            CFStringRef circleName,
149                            CFErrorRef* error,
150                            bool (^action)(SOSCircleRef circle))
151{
152    bool success = false;
153
154    SOSCircleRef circle = NULL;
155    SOSCircleRef accountCircle = SOSAccountFindCircle(account, circleName, error);
156    require_quiet(accountCircle, fail);
157
158    circle = SOSCircleCopyCircle(kCFAllocatorDefault, accountCircle, error);
159    require_quiet(circle, fail);
160
161    success = true;
162    require_quiet(action(circle), fail);
163
164    success = SOSAccountUpdateCircle(account, circle, error);
165
166fail:
167    CFReleaseSafe(circle);
168    return success;
169}
170
171