PNXMPPFramework/Extensions/XEP-0054/XMPPvCardTempModule.m
2016-02-24 16:56:39 +01:00

287 lines
7.6 KiB
Objective-C
Executable File

//
// XMPPvCardTempModule.m
// XEP-0054 vCard-temp
//
// Created by Eric Chamberlain on 3/17/11.
// Copyright 2011 RF.com. All rights reserved.
//
#import "XMPP.h"
#import "XMPPLogging.h"
#import "XMPPvCardTempModule.h"
#import "XMPPvCardTemp.h"
#import "XMPPIDTracker.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
// Log flags: trace
#if DEBUG
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN; // | XMPP_LOG_FLAG_TRACE;
#else
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
#endif
@interface XMPPvCardTempModule()
- (void)_updatevCardTemp:(XMPPvCardTemp *)vCardTemp forJID:(XMPPJID *)jid;
- (void)_fetchvCardTempForJID:(XMPPJID *)jid;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation XMPPvCardTempModule
@synthesize xmppvCardTempModuleStorage = _xmppvCardTempModuleStorage;
- (id)init
{
// This will cause a crash - it's designed to.
// Only the init methods listed in XMPPvCardTempModule.h are supported.
return [self initWithvCardStorage:nil dispatchQueue:NULL];
}
- (id)initWithDispatchQueue:(dispatch_queue_t)queue
{
// This will cause a crash - it's designed to.
// Only the init methods listed in XMPPvCardTempModule.h are supported.
return [self initWithvCardStorage:nil dispatchQueue:NULL];
}
- (id)initWithvCardStorage:(id <XMPPvCardTempModuleStorage>)storage
{
return [self initWithvCardStorage:storage dispatchQueue:NULL];
}
- (id)initWithvCardStorage:(id <XMPPvCardTempModuleStorage>)storage dispatchQueue:(dispatch_queue_t)queue
{
NSParameterAssert(storage != nil);
if ((self = [super initWithDispatchQueue:queue]))
{
if ([storage configureWithParent:self queue:moduleQueue])
{
_xmppvCardTempModuleStorage = storage;
}
else
{
XMPPLogError(@"%@: %@ - Unable to configure storage!", THIS_FILE, THIS_METHOD);
}
}
return self;
}
- (BOOL)activate:(XMPPStream *)aXmppStream
{
if ([super activate:aXmppStream])
{
// Custom code goes here (if needed)
_myvCardTracker = [[XMPPIDTracker alloc] initWithStream:xmppStream dispatchQueue:moduleQueue];
return YES;
}
return NO;
}
- (void)deactivate
{
// Custom code goes here (if needed)
dispatch_block_t block = ^{ @autoreleasepool {
[_myvCardTracker removeAllIDs];
_myvCardTracker = nil;
}};
if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_sync(moduleQueue, block);
[super deactivate];
}
- (void)dealloc
{
_xmppvCardTempModuleStorage = nil;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Fetch vCardTemp methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)fetchvCardTempForJID:(XMPPJID *)jid
{
return [self fetchvCardTempForJID:jid ignoreStorage:NO];
}
- (void)fetchvCardTempForJID:(XMPPJID *)jid ignoreStorage:(BOOL)ignoreStorage
{
dispatch_block_t block = ^{ @autoreleasepool {
XMPPvCardTemp *vCardTemp = nil;
if (!ignoreStorage)
{
// Try loading from storage
vCardTemp = [_xmppvCardTempModuleStorage vCardTempForJID:jid xmppStream:xmppStream];
}
if (vCardTemp == nil && [_xmppvCardTempModuleStorage shouldFetchvCardTempForJID:jid xmppStream:xmppStream])
{
[self _fetchvCardTempForJID:jid];
}
}};
if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_async(moduleQueue, block);
}
- (XMPPvCardTemp *)vCardTempForJID:(XMPPJID *)jid shouldFetch:(BOOL)shouldFetch{
__block XMPPvCardTemp *result;
dispatch_block_t block = ^{ @autoreleasepool {
XMPPvCardTemp *vCardTemp = [_xmppvCardTempModuleStorage vCardTempForJID:jid xmppStream:xmppStream];
if (vCardTemp == nil && shouldFetch && [_xmppvCardTempModuleStorage shouldFetchvCardTempForJID:jid xmppStream:xmppStream])
{
[self _fetchvCardTempForJID:jid];
}
result = vCardTemp;
}};
if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_sync(moduleQueue, block);
return result;
}
- (XMPPvCardTemp *)myvCardTemp
{
return [self vCardTempForJID:[xmppStream myJID] shouldFetch:YES];
}
- (void)updateMyvCardTemp:(XMPPvCardTemp *)vCardTemp
{
dispatch_block_t block = ^{ @autoreleasepool {
XMPPvCardTemp *newvCardTemp = [vCardTemp copy];
XMPPIQ *iq = [XMPPIQ iqWithType:@"set" to:nil elementID:[xmppStream generateUUID] child:newvCardTemp];
[xmppStream sendElement:iq];
[_myvCardTracker addElement:iq
target:self
selector:@selector(handleMyvcard:withInfo:)
timeout:600];
[self _updatevCardTemp:newvCardTemp forJID:[xmppStream myJID]];
}};
if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_async(moduleQueue, block);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Private
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)_updatevCardTemp:(XMPPvCardTemp *)vCardTemp forJID:(XMPPJID *)jid
{
if(!jid) return;
// this method could be called from anywhere
dispatch_block_t block = ^{ @autoreleasepool {
XMPPLogVerbose(@"%@: %s %@", THIS_FILE, __PRETTY_FUNCTION__, [jid bare]);
[_xmppvCardTempModuleStorage setvCardTemp:vCardTemp forJID:jid xmppStream:xmppStream];
[(id <XMPPvCardTempModuleDelegate>)multicastDelegate xmppvCardTempModule:self
didReceivevCardTemp:vCardTemp
forJID:jid];
}};
if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_async(moduleQueue, block);
}
- (void)_fetchvCardTempForJID:(XMPPJID *)jid{
if(!jid) return;
[xmppStream sendElement:[XMPPvCardTemp iqvCardRequestForJID:jid]];
}
- (void)handleMyvcard:(XMPPIQ *)iq withInfo:(XMPPBasicTrackingInfo *)trackerInfo{
if([iq isResultIQ])
{
[(id <XMPPvCardTempModuleDelegate>)multicastDelegate xmppvCardTempModuleDidUpdateMyvCard:self];
}
else if([iq isErrorIQ])
{
NSXMLElement *errorElement = [iq elementForName:@"error"];
[(id <XMPPvCardTempModuleDelegate>)multicastDelegate xmppvCardTempModule:self failedToUpdateMyvCard:errorElement];
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark XMPPStreamDelegate methods
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
// This method is invoked on the moduleQueue.
[_myvCardTracker invokeForElement:iq withObject:iq];
// Remember XML heirarchy memory management rules.
// The passed parameter is a subnode of the IQ, and we need to pass it to an asynchronous operation.
//
// Therefore we use vCardTempCopyFromIQ instead of vCardTempSubElementFromIQ.
XMPPvCardTemp *vCardTemp = [XMPPvCardTemp vCardTempCopyFromIQ:iq];
if (vCardTemp != nil)
{
[self _updatevCardTemp:vCardTemp forJID:[iq from]];
return YES;
}
return NO;
}
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
[_myvCardTracker removeAllIDs];
}
@end