- Update
This commit is contained in:
1 parent
d281d765ea
commit
5b074a5176
1261 files changed
+199158
-7303
No files matched your search
@@ -0,0 +1,860 @@
|
||||
#import "XMPP.h"
|
||||
#import "XMPPRosterPrivate.h"
|
||||
#import "XMPPRosterMemoryStorage.h"
|
||||
#import "XMPPRosterMemoryStoragePrivate.h"
|
||||
#import "XMPPLogging.h"
|
||||
|
||||
#if ! __has_feature(objc_arc)
|
||||
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
||||
#endif
|
||||
|
||||
// Log levels: off, error, warn, info, verbose
|
||||
#if DEBUG
|
||||
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN; // | XMPP_LOG_FLAG_TRACE;
|
||||
#else
|
||||
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
|
||||
#endif
|
||||
|
||||
#define AssertPrivateQueue() \
|
||||
NSAssert(dispatch_get_specific(parentQueueTag), @"Private method: MUST run on parentQueue");
|
||||
|
||||
#define AssertParentQueue() \
|
||||
NSAssert(dispatch_get_specific(parentQueueTag), @"Private protocol method: MUST run on parentQueue");
|
||||
|
||||
@interface XMPPRosterMemoryStorage ()
|
||||
|
||||
@property (readonly) dispatch_queue_t parentQueue;
|
||||
|
||||
@end
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@implementation XMPPRosterMemoryStorage
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
userClass = [XMPPUserMemoryStorageObject class];
|
||||
resourceClass = [XMPPResourceMemoryStorageObject class];
|
||||
|
||||
roster = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)configureWithParent:(XMPPRoster *)aParent queue:(dispatch_queue_t)queue
|
||||
{
|
||||
NSParameterAssert(aParent != nil);
|
||||
NSParameterAssert(queue != NULL);
|
||||
|
||||
@synchronized(self)
|
||||
{
|
||||
if ((parent == nil) && (parentQueue == NULL))
|
||||
{
|
||||
parent = aParent;
|
||||
parentQueue = queue;
|
||||
parentQueueTag = &parentQueueTag;
|
||||
dispatch_queue_set_specific(parentQueue, parentQueueTag, parentQueueTag, NULL);
|
||||
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
dispatch_retain(parentQueue);
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
if (parentQueue)
|
||||
dispatch_release(parentQueue);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Properties
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@synthesize userClass;
|
||||
@synthesize resourceClass;
|
||||
|
||||
- (XMPPRoster *)parent
|
||||
{
|
||||
XMPPRoster *result = nil;
|
||||
|
||||
@synchronized(self) // synchronized with configureWithParent:queue:
|
||||
{
|
||||
result = parent;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)parentQueue
|
||||
{
|
||||
dispatch_queue_t result = NULL;
|
||||
|
||||
@synchronized(self) // synchronized with configureWithParent:queue:
|
||||
{
|
||||
result = parentQueue;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Internal API
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (GCDMulticastDelegate <XMPPRosterMemoryStorageDelegate> *)multicastDelegate
|
||||
{
|
||||
return (GCDMulticastDelegate <XMPPRosterMemoryStorageDelegate> *)[parent multicastDelegate];
|
||||
}
|
||||
|
||||
- (XMPPUserMemoryStorageObject *)_userForJID:(XMPPJID *)jid
|
||||
{
|
||||
AssertPrivateQueue();
|
||||
|
||||
XMPPUserMemoryStorageObject *result = roster[[jid bareJID]];
|
||||
|
||||
if (result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
XMPPJID *myBareJID = [myJID bareJID];
|
||||
XMPPJID *bareJID = [jid bareJID];
|
||||
|
||||
if ([bareJID isEqualToJID:myBareJID])
|
||||
{
|
||||
return myUser;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (XMPPResourceMemoryStorageObject *)_resourceForJID:(XMPPJID *)jid
|
||||
{
|
||||
AssertPrivateQueue();
|
||||
|
||||
XMPPUserMemoryStorageObject *user = [self _userForJID:jid];
|
||||
return (XMPPResourceMemoryStorageObject *)[user resourceForJID:jid];
|
||||
}
|
||||
|
||||
- (NSArray *)_unsortedUsers
|
||||
{
|
||||
AssertPrivateQueue();
|
||||
|
||||
return [roster allValues];
|
||||
}
|
||||
|
||||
- (NSArray *)_unsortedAvailableUsers
|
||||
{
|
||||
AssertPrivateQueue();
|
||||
|
||||
NSArray *allUsers = [roster allValues];
|
||||
|
||||
NSMutableArray *result = [NSMutableArray arrayWithCapacity:[allUsers count]];
|
||||
|
||||
for (id <XMPPUser> user in allUsers)
|
||||
{
|
||||
if ([user isOnline])
|
||||
{
|
||||
[result addObject:user];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSArray *)_unsortedUnavailableUsers
|
||||
{
|
||||
AssertPrivateQueue();
|
||||
|
||||
NSArray *allUsers = [roster allValues];
|
||||
|
||||
NSMutableArray *result = [NSMutableArray arrayWithCapacity:[allUsers count]];
|
||||
|
||||
for (id <XMPPUser> user in allUsers)
|
||||
{
|
||||
if (![user isOnline])
|
||||
{
|
||||
[result addObject:user];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSArray *)_sortedUsersByName
|
||||
{
|
||||
AssertPrivateQueue();
|
||||
|
||||
return [[roster allValues] sortedArrayUsingSelector:@selector(compareByName:)];
|
||||
}
|
||||
|
||||
- (NSArray *)_sortedUsersByAvailabilityName
|
||||
{
|
||||
AssertPrivateQueue();
|
||||
|
||||
return [[roster allValues] sortedArrayUsingSelector:@selector(compareByAvailabilityName:)];
|
||||
}
|
||||
|
||||
- (NSArray *)_sortedAvailableUsersByName
|
||||
{
|
||||
AssertPrivateQueue();
|
||||
|
||||
return [[self _unsortedAvailableUsers] sortedArrayUsingSelector:@selector(compareByName:)];
|
||||
}
|
||||
|
||||
- (NSArray *)_sortedUnavailableUsersByName
|
||||
{
|
||||
AssertPrivateQueue();
|
||||
|
||||
return [[self _unsortedUnavailableUsers] sortedArrayUsingSelector:@selector(compareByName:)];
|
||||
}
|
||||
|
||||
- (NSArray *)_sortedResources:(BOOL)includeResourcesForMyUserExcludingMyself
|
||||
{
|
||||
AssertPrivateQueue();
|
||||
|
||||
// Add all the resouces from all the available users in the roster
|
||||
//
|
||||
// Remember: There may be multiple resources per user
|
||||
|
||||
NSArray *availableUsers = [self unsortedAvailableUsers];
|
||||
|
||||
NSMutableArray *result = [NSMutableArray arrayWithCapacity:[availableUsers count]];
|
||||
|
||||
for (id<XMPPUser> user in availableUsers)
|
||||
{
|
||||
[result addObjectsFromArray:[user allResources]];
|
||||
}
|
||||
|
||||
if (includeResourcesForMyUserExcludingMyself)
|
||||
{
|
||||
// Now add all the available resources from our own user account (excluding ourselves)
|
||||
|
||||
NSArray *myResources = [myUser allResources];
|
||||
|
||||
for (id<XMPPResource> resource in myResources)
|
||||
{
|
||||
if (![myJID isEqualToJID:[resource jid]])
|
||||
{
|
||||
[result addObject:resource];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [result sortedArrayUsingSelector:@selector(compare:)];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark Roster Management
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (XMPPUserMemoryStorageObject *)myUser
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return myUser;
|
||||
}
|
||||
else
|
||||
{
|
||||
__block XMPPUserMemoryStorageObject *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{
|
||||
result = [myUser copy];
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (XMPPResourceMemoryStorageObject *)myResource
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return (XMPPResourceMemoryStorageObject *)[myUser resourceForJID:myJID];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block XMPPResourceMemoryStorageObject *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{
|
||||
XMPPResourceMemoryStorageObject *resource =
|
||||
(XMPPResourceMemoryStorageObject *)[myUser resourceForJID:myJID];
|
||||
result = [resource copy];
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (XMPPUserMemoryStorageObject *)userForJID:(XMPPJID *)jid
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return [self _userForJID:jid];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block XMPPUserMemoryStorageObject *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{ @autoreleasepool {
|
||||
|
||||
XMPPUserMemoryStorageObject *user = [self _userForJID:jid];
|
||||
result = [user copy];
|
||||
|
||||
}});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (XMPPResourceMemoryStorageObject *)resourceForJID:(XMPPJID *)jid
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return [self _resourceForJID:jid];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block XMPPResourceMemoryStorageObject *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{ @autoreleasepool {
|
||||
|
||||
XMPPResourceMemoryStorageObject *resource = [self _resourceForJID:jid];
|
||||
result = [resource copy];
|
||||
|
||||
}});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)sortedUsersByName
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return [self _sortedUsersByName];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block NSArray *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{ @autoreleasepool {
|
||||
|
||||
NSArray *temp = [self _sortedUsersByName];
|
||||
|
||||
result = [[NSArray alloc] initWithArray:temp copyItems:YES];
|
||||
|
||||
}});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)sortedUsersByAvailabilityName
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return [self _sortedUsersByAvailabilityName];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block NSArray *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{ @autoreleasepool {
|
||||
|
||||
NSArray *temp = [self _sortedUsersByAvailabilityName];
|
||||
|
||||
result = [[NSArray alloc] initWithArray:temp copyItems:YES];
|
||||
|
||||
}});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)sortedAvailableUsersByName
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return [self _sortedAvailableUsersByName];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block NSArray *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{ @autoreleasepool {
|
||||
|
||||
NSArray *temp = [self _sortedAvailableUsersByName];
|
||||
result = [[NSArray alloc] initWithArray:temp copyItems:YES];
|
||||
|
||||
}});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)sortedUnavailableUsersByName
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return [self _sortedUnavailableUsersByName];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block NSArray *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{ @autoreleasepool {
|
||||
|
||||
NSArray *temp = [self _sortedUnavailableUsersByName];
|
||||
result = [[NSArray alloc] initWithArray:temp copyItems:YES];
|
||||
|
||||
}});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)unsortedUsers
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return [self _unsortedUsers];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block NSArray *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{ @autoreleasepool {
|
||||
|
||||
NSArray *temp = [self _unsortedUsers];
|
||||
result = [[NSArray alloc] initWithArray:temp copyItems:YES];
|
||||
|
||||
}});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)unsortedAvailableUsers
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return [self _unsortedAvailableUsers];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block NSArray *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{ @autoreleasepool {
|
||||
|
||||
NSArray *temp = [self _unsortedAvailableUsers];
|
||||
result = [[NSArray alloc] initWithArray:temp copyItems:YES];
|
||||
|
||||
}});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)unsortedUnavailableUsers
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return [self _unsortedUnavailableUsers];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block NSArray *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{ @autoreleasepool {
|
||||
|
||||
NSArray *temp = [self _unsortedUnavailableUsers];
|
||||
result = [[NSArray alloc] initWithArray:temp copyItems:YES];
|
||||
|
||||
}});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)sortedResources:(BOOL)includeResourcesForMyUserExcludingMyself
|
||||
{
|
||||
// This is a public method, so it may be invoked on any thread/queue.
|
||||
|
||||
if (self.parentQueue == NULL)
|
||||
{
|
||||
// Haven't been attached to parent yet
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (dispatch_get_specific(parentQueueTag))
|
||||
{
|
||||
return [self _sortedResources:includeResourcesForMyUserExcludingMyself];
|
||||
}
|
||||
else
|
||||
{
|
||||
__block NSArray *result;
|
||||
|
||||
dispatch_sync(parentQueue, ^{ @autoreleasepool {
|
||||
|
||||
NSArray *temp = [self _sortedResources:includeResourcesForMyUserExcludingMyself];
|
||||
result = [[NSArray alloc] initWithArray:temp copyItems:YES];
|
||||
|
||||
}});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark XMPPRosterStorage Protocol
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)beginRosterPopulationForXMPPStream:(XMPPStream *)stream withVersion:(NSString *)version
|
||||
{
|
||||
XMPPLogTrace();
|
||||
AssertParentQueue();
|
||||
|
||||
isRosterPopulation = YES;
|
||||
|
||||
myJID = self.parent.xmppStream.myJID;
|
||||
|
||||
myUser = [[self.userClass alloc] initWithJID:myJID];
|
||||
}
|
||||
|
||||
- (void)endRosterPopulationForXMPPStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
AssertParentQueue();
|
||||
|
||||
isRosterPopulation = NO;
|
||||
|
||||
[[self multicastDelegate] xmppRosterDidPopulate:self];
|
||||
[[self multicastDelegate] xmppRosterDidChange:self];
|
||||
}
|
||||
|
||||
- (void)handleRosterItem:(NSXMLElement *)item xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
AssertParentQueue();
|
||||
|
||||
NSString *jidStr = [item attributeStringValueForName:@"jid"];
|
||||
XMPPJID *jid = [[XMPPJID jidWithString:jidStr] bareJID];
|
||||
|
||||
if (isRosterPopulation)
|
||||
{
|
||||
XMPPUserMemoryStorageObject *newUser =
|
||||
(XMPPUserMemoryStorageObject *)[[self.userClass alloc] initWithItem:item];
|
||||
|
||||
roster[jid] = newUser;
|
||||
|
||||
XMPPLogVerbose(@"roster(%lu): %@", (unsigned long)[roster count], roster);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString *subscription = [item attributeStringValueForName:@"subscription"];
|
||||
|
||||
if ([subscription isEqualToString:@"remove"])
|
||||
{
|
||||
XMPPUserMemoryStorageObject *user = roster[jid];
|
||||
if (user)
|
||||
{
|
||||
[roster removeObjectForKey:jid];
|
||||
|
||||
XMPPLogVerbose(@"roster(%lu): %@", (unsigned long)[roster count], roster);
|
||||
|
||||
[[self multicastDelegate] xmppRoster:self didRemoveUser:user];
|
||||
[[self multicastDelegate] xmppRosterDidChange:self];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XMPPUserMemoryStorageObject *user = roster[jid];
|
||||
if (user)
|
||||
{
|
||||
[user updateWithItem:item];
|
||||
|
||||
XMPPLogVerbose(@"roster(%lu): %@", (unsigned long)[roster count], roster);
|
||||
|
||||
[[self multicastDelegate] xmppRoster:self didUpdateUser:user];
|
||||
[[self multicastDelegate] xmppRosterDidChange:self];
|
||||
}
|
||||
else
|
||||
{
|
||||
XMPPUserMemoryStorageObject *newUser =
|
||||
(XMPPUserMemoryStorageObject *)[[self.userClass alloc] initWithItem:item];
|
||||
|
||||
roster[jid] = newUser;
|
||||
|
||||
XMPPLogVerbose(@"roster(%lu): %@", (unsigned long)[roster count], roster);
|
||||
|
||||
[[self multicastDelegate] xmppRoster:self didAddUser:newUser];
|
||||
[[self multicastDelegate] xmppRosterDidChange:self];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handlePresence:(XMPPPresence *)presence xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
AssertParentQueue();
|
||||
|
||||
int change = XMPP_USER_NO_CHANGE;
|
||||
|
||||
XMPPUserMemoryStorageObject *user = nil;
|
||||
XMPPResourceMemoryStorageObject *resource = nil;
|
||||
|
||||
XMPPJID *jidKey = [[presence from] bareJID];
|
||||
|
||||
user = roster[jidKey];
|
||||
if (user == nil)
|
||||
{
|
||||
// Not a presence element from anyone in our roster (that we know of).
|
||||
|
||||
if ([[myJID bareJID] isEqualToJID:jidKey])
|
||||
{
|
||||
// It's a presence element for our user, either our resource or another resource.
|
||||
|
||||
user = myUser;
|
||||
}
|
||||
else if([parent allowRosterlessOperation])
|
||||
{
|
||||
// Unknown user (this is the first time we've encountered them).
|
||||
// This happens if the roster is in rosterlessOperation mode.
|
||||
|
||||
user = (XMPPUserMemoryStorageObject *)[[self.userClass alloc] initWithJID:jidKey];
|
||||
|
||||
roster[jidKey] = user;
|
||||
|
||||
[[self multicastDelegate] xmppRoster:self didAddUser:user];
|
||||
[[self multicastDelegate] xmppRosterDidChange:self];
|
||||
}
|
||||
}
|
||||
|
||||
change = [user updateWithPresence:presence resourceClass:self.resourceClass andGetResource:&resource];
|
||||
|
||||
XMPPLogVerbose(@"roster(%lu): %@", (unsigned long)[roster count], roster);
|
||||
|
||||
if (change == XMPP_USER_ADDED_RESOURCE)
|
||||
[[self multicastDelegate] xmppRoster:self didAddResource:resource withUser:user];
|
||||
|
||||
if (change == XMPP_USER_UPDATED_RESOURCE)
|
||||
[[self multicastDelegate] xmppRoster:self didUpdateResource:resource withUser:user];
|
||||
|
||||
if (change == XMPP_USER_REMOVED_RESOURCE)
|
||||
[[self multicastDelegate] xmppRoster:self didRemoveResource:resource withUser:user];
|
||||
|
||||
if (change != XMPP_USER_NO_CHANGE)
|
||||
[[self multicastDelegate] xmppRosterDidChange:self];
|
||||
}
|
||||
|
||||
- (BOOL)userExistsWithJID:(XMPPJID *)jid xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
AssertParentQueue();
|
||||
|
||||
XMPPJID *jidKey = [jid bareJID];
|
||||
XMPPUserMemoryStorageObject *rosterUser = roster[jidKey];
|
||||
|
||||
return (rosterUser != nil);
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
- (void)setPhoto:(UIImage *)photo forUserWithJID:(XMPPJID *)jid xmppStream:(XMPPStream *)stream
|
||||
#else
|
||||
- (void)setPhoto:(NSImage *)photo forUserWithJID:(XMPPJID *)jid xmppStream:(XMPPStream *)stream
|
||||
#endif
|
||||
{
|
||||
XMPPLogTrace();
|
||||
AssertParentQueue();
|
||||
|
||||
XMPPJID *jidKey = [jid bareJID];
|
||||
XMPPUserMemoryStorageObject *rosterUser = roster[jidKey];
|
||||
|
||||
if (rosterUser)
|
||||
{
|
||||
[rosterUser setPhoto:photo];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearAllResourcesForXMPPStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
AssertParentQueue();
|
||||
|
||||
for (XMPPUserMemoryStorageObject *user in [roster objectEnumerator])
|
||||
{
|
||||
[user clearAllResources];
|
||||
}
|
||||
|
||||
[[self multicastDelegate] xmppRosterDidChange:self];
|
||||
}
|
||||
|
||||
- (void)clearAllUsersAndResourcesForXMPPStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
AssertParentQueue();
|
||||
|
||||
[roster removeAllObjects];
|
||||
|
||||
myUser = nil;
|
||||
|
||||
[[self multicastDelegate] xmppRosterDidChange:self];
|
||||
}
|
||||
|
||||
- (NSArray *)jidsForXMPPStream:(XMPPStream *)stream
|
||||
{
|
||||
XMPPLogTrace();
|
||||
AssertParentQueue();
|
||||
|
||||
NSMutableArray *results = [NSMutableArray array];
|
||||
|
||||
for (XMPPUserMemoryStorageObject *user in [roster objectEnumerator])
|
||||
{
|
||||
[results addObject:[user.jid bareJID]];
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
- (void)getSubscription:(NSString **)subscription
|
||||
ask:(NSString **)ask
|
||||
nickname:(NSString **)nickname
|
||||
groups:(NSArray **)groups
|
||||
forJID:(XMPPJID *)jid
|
||||
xmppStream:(XMPPStream *)stream
|
||||
{
|
||||
|
||||
XMPPLogTrace();
|
||||
AssertParentQueue();
|
||||
|
||||
XMPPJID *jidKey = [jid bareJID];
|
||||
XMPPUserMemoryStorageObject *rosterUser = roster[jidKey];
|
||||
|
||||
if(rosterUser)
|
||||
{
|
||||
if(subscription)
|
||||
{
|
||||
*subscription = rosterUser.subscription;
|
||||
}
|
||||
|
||||
if(ask)
|
||||
{
|
||||
*ask = rosterUser.ask;
|
||||
}
|
||||
|
||||
if(nickname)
|
||||
{
|
||||
*nickname = rosterUser.nickname;
|
||||
}
|
||||
|
||||
if(groups)
|
||||
{
|
||||
*groups = rosterUser.groups;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in new issue
Block a user