Permalink
Fetching contributors…
Cannot retrieve contributors at this time
1002 lines (810 sloc) 24.6 KB
#import "XMPP.h"
#import "XMPPLogging.h"
#import "XMPPPrivacy.h"
#import "NSNumber+XMPP.h"
// Log levels: off, error, warn, info, verbose
// Log flags: trace
#ifdef DEBUG
static const int xmppLogLevel = XMPP_LOG_LEVEL_VERBOSE; // | XMPP_LOG_FLAG_TRACE;
#else
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
#endif
#define QUERY_TIMEOUT 30.0 // NSTimeInterval (double) = seconds
NSString *const XMPPPrivacyErrorDomain = @"XMPPPrivacyErrorDomain";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef enum XMPPPrivacyQueryInfoType {
FetchList,
FetchRules,
EditList,
SetActiveList,
SetDefaultList
} XMPPPrivacyQueryInfoType;
@interface XMPPPrivacyQueryInfo : NSObject
{
XMPPPrivacyQueryInfoType type;
NSString *privacyListName;
NSArray *privacyListItems;
dispatch_source_t timer;
}
@property (nonatomic, readonly) XMPPPrivacyQueryInfoType type;
@property (nonatomic, readonly) NSString *privacyListName;
@property (nonatomic, readonly) NSArray *privacyListItems;
@property (nonatomic, readwrite) dispatch_source_t timer;
- (void)cancel;
+ (XMPPPrivacyQueryInfo *)queryInfoWithType:(XMPPPrivacyQueryInfoType)type;
+ (XMPPPrivacyQueryInfo *)queryInfoWithType:(XMPPPrivacyQueryInfoType)type name:(NSString *)name;
+ (XMPPPrivacyQueryInfo *)queryInfoWithType:(XMPPPrivacyQueryInfoType)type name:(NSString *)name items:(NSArray *)items;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@interface XMPPPrivacy (/* Must be nameless for properties */)
- (void)addQueryInfo:(XMPPPrivacyQueryInfo *)qi withKey:(NSString *)uuid;
- (void)queryTimeout:(NSString *)uuid;
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation XMPPPrivacy
- (id)init
{
return [self initWithDispatchQueue:NULL];
}
- (id)initWithDispatchQueue:(dispatch_queue_t)queue
{
if ((self = [super initWithDispatchQueue:queue]))
{
autoRetrievePrivacyListNames = YES;
autoRetrievePrivacyListItems = YES;
autoClearPrivacyListInfo = YES;
privacyDict = [[NSMutableDictionary alloc] init];
activeListName = nil;
defaultListName = nil;
pendingQueries = [[NSMutableDictionary alloc] init];
}
return self;
}
- (BOOL)activate:(XMPPStream *)aXmppStream
{
if ([super activate:aXmppStream])
{
// Reserved for possible future use.
return YES;
}
return NO;
}
- (void)deactivate
{
// Reserved for possible future use.
[super deactivate];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Properties
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL)autoRetrievePrivacyListNames
{
if (dispatch_get_specific(moduleQueueTag))
{
return autoRetrievePrivacyListNames;
}
else
{
__block BOOL result;
dispatch_sync(moduleQueue, ^{
result = autoRetrievePrivacyListNames;
});
return result;
}
}
- (void)setAutoRetrievePrivacyListNames:(BOOL)flag
{
dispatch_block_t block = ^{
autoRetrievePrivacyListNames = flag;
};
if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_async(moduleQueue, block);
}
- (BOOL)autoRetrievePrivacyListItems
{
if (dispatch_get_specific(moduleQueueTag))
{
return autoRetrievePrivacyListItems;
}
else
{
__block BOOL result;
dispatch_sync(moduleQueue, ^{
result = autoRetrievePrivacyListItems;
});
return result;
}
}
- (void)setAutoRetrievePrivacyListItems:(BOOL)flag
{
dispatch_block_t block = ^{
autoRetrievePrivacyListItems = flag;
};
if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_async(moduleQueue, block);
}
- (BOOL)autoClearPrivacyListInfo
{
if (dispatch_get_specific(moduleQueueTag))
{
return autoClearPrivacyListInfo;
}
else
{
__block BOOL result;
dispatch_sync(moduleQueue, ^{
result = autoClearPrivacyListInfo;
});
return result;
}
}
- (void)setAutoClearPrivacyListInfo:(BOOL)flag
{
dispatch_block_t block = ^{
autoClearPrivacyListInfo = flag;
};
if (dispatch_get_specific(moduleQueueTag))
block();
else
dispatch_async(moduleQueue, block);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Public API
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)retrieveListNames
{
XMPPLogTrace();
// <iq type='get' id='abc123'>
// <query xmlns='jabber:iq:privacy'/>
// </iq>
NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:privacy"];
NSString *uuid = [xmppStream generateUUID];
XMPPIQ *iq = [XMPPIQ iqWithType:@"get" to:nil elementID:uuid child:query];
[xmppStream sendElement:iq];
XMPPPrivacyQueryInfo *qi = [XMPPPrivacyQueryInfo queryInfoWithType:FetchList];
[self addQueryInfo:qi withKey:uuid];
}
- (void)retrieveListWithName:(NSString *)privacyListName
{
XMPPLogTrace();
if (privacyListName == nil) return;
// <iq type='get' id='abc123'>
// <query xmlns='jabber:iq:privacy'>
// <list name='public'/>
// </query>
// </iq>
NSXMLElement *list = [NSXMLElement elementWithName:@"list"];
[list addAttributeWithName:@"name" stringValue:privacyListName];
NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:privacy"];
[query addChild:list];
NSString *uuid = [xmppStream generateUUID];
XMPPIQ *iq = [XMPPIQ iqWithType:@"get" to:nil elementID:uuid child:query];
[xmppStream sendElement:iq];
XMPPPrivacyQueryInfo *qi = [XMPPPrivacyQueryInfo queryInfoWithType:FetchRules name:privacyListName];
[self addQueryInfo:qi withKey:uuid];
}
- (void)clearPrivacyListInfo
{
XMPPLogTrace();
if (dispatch_get_specific(moduleQueueTag))
{
[privacyDict removeAllObjects];
}
else
{
dispatch_async(moduleQueue, ^{ @autoreleasepool {
[privacyDict removeAllObjects];
}});
}
}
- (NSArray *)listNames
{
if (dispatch_get_specific(moduleQueueTag))
{
return [privacyDict allKeys];
}
else
{
__block NSArray *result;
dispatch_sync(moduleQueue, ^{ @autoreleasepool {
result = [[privacyDict allKeys] copy];
}});
return result;
}
}
- (NSArray *)listWithName:(NSString *)privacyListName
{
NSArray* (^block)() = ^ NSArray* () {
id result = privacyDict[privacyListName];
if (result == [NSNull null]) // Not fetched yet
return nil;
else
return (NSArray *)result;
};
// ExecuteVoidBlock(moduleQueue, block);
// ExecuteNonVoidBlock(moduleQueue, block, NSArray*)
if (dispatch_get_specific(moduleQueueTag))
{
return block();
}
else
{
__block NSArray *result;
dispatch_sync(moduleQueue, ^{ @autoreleasepool {
result = block();
}});
return result;
}
}
- (NSString *)activeListName
{
return activeListName;
}
- (NSArray *)activeList
{
return [self listWithName:activeListName];
}
- (void)setActiveListName:(NSString *)privacyListName
{
// Setting active list:
//
// <iq type='set' id='active1'>
// <query xmlns='jabber:iq:privacy'>
// <active name='special'/>
// </query>
// </iq>
//
// Decline the use of active lists:
//
// <iq type='set' id='active3'>
// <query xmlns='jabber:iq:privacy'>
// <active/>
// </query>
// </iq>
NSXMLElement *active = [NSXMLElement elementWithName:@"active"];
if (privacyListName)
{
[active addAttributeWithName:@"name" stringValue:privacyListName];
}
NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:privacy"];
[query addChild:active];
NSString *uuid = [xmppStream generateUUID];
XMPPIQ *iq = [XMPPIQ iqWithType:@"set" to:nil elementID:uuid child:query];
[xmppStream sendElement:iq];
XMPPPrivacyQueryInfo *qi = [XMPPPrivacyQueryInfo queryInfoWithType:SetActiveList name:privacyListName];
[self addQueryInfo:qi withKey:uuid];
}
- (NSString *)defaultListName
{
return defaultListName;
}
- (NSArray *)defaultList
{
return [self listWithName:defaultListName];
}
- (void)setDefaultListName:(NSString *)privacyListName
{
// Setting default list:
//
// <iq type='set' id='default1'>
// <query xmlns='jabber:iq:privacy'>
// <default name='special'/>
// </query>
// </iq>
//
// Decline the use of default list:
//
// <iq type='set' id='default2'>
// <query xmlns='jabber:iq:privacy'>
// <default/>
// </query>
// </iq>
NSXMLElement *dfault = [NSXMLElement elementWithName:@"default"];
if (privacyListName)
{
[dfault addAttributeWithName:@"name" stringValue:privacyListName];
}
NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:privacy"];
[query addChild:dfault];
NSString *uuid = [xmppStream generateUUID];
XMPPIQ *iq = [XMPPIQ iqWithType:@"set" to:nil elementID:uuid child:query];
[xmppStream sendElement:iq];
XMPPPrivacyQueryInfo *qi = [XMPPPrivacyQueryInfo queryInfoWithType:SetDefaultList name:privacyListName];
[self addQueryInfo:qi withKey:uuid];
}
- (void)setListWithName:(NSString *)privacyListName items:(NSArray *)items
{
// Edit a privacy list:
//
// <iq type='set' id='edit1'>
// <query xmlns='jabber:iq:privacy'>
// <list name='public'>
// <item type='jid' value='tybalt@example.com' action='deny' order='3'/>
// <item type='jid' value='paris@example.org' action='deny' order='5'/>
// <item action='allow' order='68'/>
// </list>
// </query>
// </iq>
//
//
// Remove a privacy list:
//
// <iq type='set' id='remove1'>
// <query xmlns='jabber:iq:privacy'>
// <list name='private'/>
// </query>
// </iq>
NSXMLElement *list = [NSXMLElement elementWithName:@"list"];
[list addAttributeWithName:@"name" stringValue:privacyListName];
if (items && ([items count] > 0))
{
[list setChildren:items];
}
NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:privacy"];
[query addChild:list];
NSString *uuid = [xmppStream generateUUID];
XMPPIQ *iq = [XMPPIQ iqWithType:@"set" to:nil elementID:uuid child:query];
[xmppStream sendElement:iq];
XMPPPrivacyQueryInfo *qi = [XMPPPrivacyQueryInfo queryInfoWithType:EditList name:privacyListName items:items];
[self addQueryInfo:qi withKey:uuid];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Query Processing
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)addQueryInfo:(XMPPPrivacyQueryInfo *)queryInfo withKey:(NSString *)uuid
{
// Setup timer
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, moduleQueue);
dispatch_source_set_event_handler(timer, ^{ @autoreleasepool {
[self queryTimeout:uuid];
}});
dispatch_time_t fireTime = dispatch_time(DISPATCH_TIME_NOW, (QUERY_TIMEOUT * NSEC_PER_SEC));
dispatch_source_set_timer(timer, fireTime, DISPATCH_TIME_FOREVER, 1.0);
dispatch_resume(timer);
queryInfo.timer = timer;
// Add to dictionary
pendingQueries[uuid] = queryInfo;
}
- (void)removeQueryInfo:(XMPPPrivacyQueryInfo *)queryInfo withKey:(NSString *)uuid
{
// Invalidate timer
[queryInfo cancel];
// Remove from dictionary
[pendingQueries removeObjectForKey:uuid];
}
- (void)processQuery:(XMPPPrivacyQueryInfo *)queryInfo withFailureCode:(XMPPPrivacyErrorCode)errorCode
{
NSError *error = [NSError errorWithDomain:XMPPPrivacyErrorDomain code:errorCode userInfo:nil];
if (queryInfo.type == FetchList)
{
[multicastDelegate xmppPrivacy:self didNotReceiveListNamesDueToError:error];
}
else if (queryInfo.type == FetchRules)
{
[multicastDelegate xmppPrivacy:self didNotReceiveListWithName:queryInfo.privacyListName error:error];
}
else if (queryInfo.type == EditList)
{
[multicastDelegate xmppPrivacy:self didNotSetListWithName:queryInfo.privacyListName error:error];
}
else if (queryInfo.type == SetActiveList)
{
[multicastDelegate xmppPrivacy:self didNotSetActiveListName:queryInfo.privacyListName error:error];
}
else if (queryInfo.type == SetDefaultList)
{
[multicastDelegate xmppPrivacy:self didNotSetDefaultListName:queryInfo.privacyListName error:error];
}
}
- (void)queryTimeout:(NSString *)uuid
{
XMPPPrivacyQueryInfo *queryInfo = privacyDict[uuid];
if (queryInfo)
{
[self processQuery:queryInfo withFailureCode:XMPPPrivacyQueryTimeout];
[self removeQueryInfo:queryInfo withKey:uuid];
}
}
NSInteger sortItems(id itemOne, id itemTwo, void *context)
{
NSXMLElement *item1 = (NSXMLElement *)itemOne;
NSXMLElement *item2 = (NSXMLElement *)itemTwo;
NSString *orderStr1 = [item1 attributeStringValueForName:@"order"];
NSString *orderStr2 = [item2 attributeStringValueForName:@"order"];
NSUInteger order1;
BOOL parse1 = [NSNumber xmpp_parseString:orderStr1 intoNSUInteger:&order1];
NSUInteger order2;
BOOL parse2 = [NSNumber xmpp_parseString:orderStr2 intoNSUInteger:&order2];
if (parse1)
{
if (parse2)
{
// item1 = valid
// item2 = valid
if (order1 < order2)
return NSOrderedAscending;
if (order1 > order2)
return NSOrderedDescending;
return NSOrderedSame;
}
else
{
// item1 = valid
// item2 = invalid
return NSOrderedAscending;
}
}
else if (parse2)
{
// item1 = invalid
// item2 = valid
return NSOrderedDescending;
}
else
{
// item1 = invalid
// item2 = invalid
return NSOrderedSame;
}
}
- (void)processQueryResponse:(XMPPIQ *)iq withInfo:(XMPPPrivacyQueryInfo *)queryInfo
{
if (queryInfo.type == FetchList)
{
// Privacy List Names Query Response:
//
// <iq type='result' id='getlist1'>
// <query xmlns='jabber:iq:privacy'>
// <active name='private'/>
// <default name='public'/>
// <list name='public'/>
// <list name='private'/>
// <list name='special'/>
// </query>
// </iq>
if ([[iq type] isEqualToString:@"result"])
{
NSXMLElement *query = [iq elementForName:@"query" xmlns:@"jabber:iq:privacy"];
if (query == nil) return;
NSXMLElement *active = [query elementForName:@"active"];
activeListName = [[active attributeStringValueForName:@"name"] copy];
NSXMLElement *dfault = [query elementForName:@"default"];
defaultListName = [[dfault attributeStringValueForName:@"name"] copy];
NSArray *listNames = [query elementsForName:@"list"];
for (NSXMLElement *listName in listNames)
{
NSString *name = [listName attributeStringValueForName:@"name"];
if (name)
{
id value = privacyDict[name];
if (value == nil)
{
privacyDict[name] = [NSNull null];
}
}
}
[multicastDelegate xmppPrivacy:self didReceiveListNames:[self listNames]];
}
else
{
[multicastDelegate xmppPrivacy:self didNotReceiveListNamesDueToError:iq];
}
}
else if (queryInfo.type == FetchRules)
{
// Privacy List Rules Query Response (success):
//
// <iq type='result' id='getlist2'>
// <query xmlns='jabber:iq:privacy'>
// <list name='public'>
// <item type='jid' value='tybalt@example.com' action='deny' order='1'/>
// <item action='allow' order='2'/>
// </list>
// </query>
// </iq>
//
//
// Privacy List Rules Query Response (error):
//
// <iq type='error' id='getlist5'>
// <query xmlns='jabber:iq:privacy'>
// <list name='The Empty Set'/>
// </query>
// <error type='cancel'>
// <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
// </error>
// </iq>
if ([[iq type] isEqualToString:@"result"])
{
NSXMLElement *query = [iq elementForName:@"query" xmlns:@"jabber:iq:privacy"];
if (query == nil) return;
NSXMLElement *list = [query elementForName:@"list"];
if (list == nil) return;
NSArray *items = [[list elementsForName:@"item"] sortedArrayUsingFunction:sortItems context:NULL];
if (items == nil)
{
items = [NSArray array];
}
privacyDict[queryInfo.privacyListName] = items;
[multicastDelegate xmppPrivacy:self didReceiveListWithName:queryInfo.privacyListName items:items];
}
else
{
[multicastDelegate xmppPrivacy:self didNotReceiveListWithName:queryInfo.privacyListName error:iq];
}
}
else if (queryInfo.type == EditList)
{
// Privacy List Add/Edit/Remove Response (success):
//
// <iq type='result' id='abc123' to='romeo@example.net/orchard'/>
//
// Note: The result iq does NOT have a query child.
if ([[iq type] isEqualToString:@"result"])
{
NSArray *items = [[queryInfo privacyListItems] sortedArrayUsingFunction:sortItems context:NULL];
if (items == nil)
{
items = [NSArray array];
}
privacyDict[queryInfo.privacyListName] = items;
[multicastDelegate xmppPrivacy:self didSetListWithName:queryInfo.privacyListName];
}
else
{
[multicastDelegate xmppPrivacy:self didNotSetListWithName:queryInfo.privacyListName error:iq];
}
}
else if (queryInfo.type == SetActiveList)
{
// Change of active list (success):
//
// <iq type='result' id='active1' to='romeo@example.net/orchard'/>
//
//
// Change of active list (error):
//
// <iq to='romeo@example.net/orchard' type='error' id='active2'>
// <query xmlns='jabber:iq:privacy'>
// <active name='Invalid List Name'/>
// </query>
// <error type='cancel'>
// <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
// </error>
// </iq>
//
//
// Note: The result iq does NOT have a query child.
// Note: The success could also mean we declined the use of an active list.
if ([[iq type] isEqualToString:@"result"])
{
activeListName = [[queryInfo privacyListName] copy];
[multicastDelegate xmppPrivacy:self didSetActiveListName:queryInfo.privacyListName];
}
else
{
[multicastDelegate xmppPrivacy:self didNotSetActiveListName:queryInfo.privacyListName error:iq];
}
}
else if (queryInfo.type == SetDefaultList)
{
// Change of default list (success):
//
// <iq type='result' id='default1' to='romeo@example.net/orchard'/>
//
//
// Change of default list (error):
//
// <iq to='romeo@example.net/orchard' type='error' id='default1'>
// <query xmlns='jabber:iq:privacy'>
// <default name='special'/>
// </query>
// <error type='cancel'>
// <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
// </error>
// </iq>
//
//
// Note: The result iq does NOT have a query child.
// Note: The success could also mean we declined the use of a default list.
if ([[iq type] isEqualToString:@"result"])
{
defaultListName = [[queryInfo privacyListName] copy];
[multicastDelegate xmppPrivacy:self didSetDefaultListName:queryInfo.privacyListName];
}
else
{
[multicastDelegate xmppPrivacy:self didNotSetDefaultListName:queryInfo.privacyListName error:iq];
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark XMPPStream Delegate
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
if (self.autoRetrievePrivacyListNames)
{
[self retrieveListNames];
}
}
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
NSString *type = [iq type];
if ([type isEqualToString:@"set"])
{
NSXMLElement *query = [iq elementForName:@"query" xmlns:@"jabber:iq:privacy"];
if (query)
{
// Privacy List Push:
//
// <iq type='set' id='push1'>
// <query xmlns='jabber:iq:privacy'>
// <list name='public'/>
// </query>
// </iq>
//
//
// Push response:
//
// <iq type='result' id='push1'/>
NSXMLElement *list = [query elementForName:@"list"];
NSString *listName = [list attributeStringValueForName:@"name"];
if (listName == nil)
{
return NO;
}
[multicastDelegate xmppPrivacy:self didReceivePushWithListName:listName];
XMPPIQ *iqResponse = [XMPPIQ iqWithType:@"result" to:[iq from] elementID:[iq elementID]];
[xmppStream sendElement:iqResponse];
if (self.autoRetrievePrivacyListItems)
{
[self retrieveListWithName:listName];
}
return YES;
}
}
else
{
// This may be a response to a query we sent
XMPPPrivacyQueryInfo *queryInfo = pendingQueries[[iq elementID]];
if (queryInfo)
{
[self processQueryResponse:iq withInfo:queryInfo];
if (queryInfo.type == FetchList && self.autoRetrievePrivacyListItems)
{
for (NSString *privacyListName in privacyDict)
{
id privacyListItems = privacyDict[privacyListName];
if (privacyListItems == [NSNull null])
{
[self retrieveListWithName:privacyListName];
}
}
}
return YES;
}
}
return NO;
}
-(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
// If there are any pending queries,
// they just failed due to the disconnection.
for (NSString *uuid in pendingQueries)
{
XMPPPrivacyQueryInfo *queryInfo = privacyDict[uuid];
[self processQuery:queryInfo withFailureCode:XMPPPrivacyDisconnect];
}
// Clear the list of pending queries
[pendingQueries removeAllObjects];
// Maybe clear all stored privacy info
if (self.autoClearPrivacyListInfo)
{
[self clearPrivacyListInfo];
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Privacy Items
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ (NSXMLElement *)privacyItemWithAction:(NSString *)action order:(NSUInteger)orderValue
{
return [self privacyItemWithType:nil value:nil action:action order:orderValue];
}
+ (NSXMLElement *)privacyItemWithType:(NSString *)type
value:(NSString *)value
action:(NSString *)action
order:(NSUInteger)orderValue
{
NSString *order = [[NSString alloc] initWithFormat:@"%lu", (unsigned long)orderValue];
// <item type='[jid|group|subscription]'
// value='bar'
// action='[allow|deny]'
// order='unsignedInt'>
// [<iq/>]
// [<message/>]
// [<presence-in/>]
// [<presence-out/>]
// </item>
NSXMLElement *item = [NSXMLElement elementWithName:@"item"];
if (type)
[item addAttributeWithName:@"type" stringValue:type];
if (value)
[item addAttributeWithName:@"value" stringValue:value];
[item addAttributeWithName:@"action" stringValue:action];
[item addAttributeWithName:@"order" stringValue:order];
return item;
}
+ (void)blockIQs:(NSXMLElement *)privacyItem
{
[privacyItem addChild:[NSXMLElement elementWithName:@"iq"]];
}
+ (void)blockMessages:(NSXMLElement *)privacyItem
{
[privacyItem addChild:[NSXMLElement elementWithName:@"message"]];
}
+ (void)blockPresenceIn:(NSXMLElement *)privacyItem
{
[privacyItem addChild:[NSXMLElement elementWithName:@"presence-in"]];
}
+ (void)blockPresenceOut:(NSXMLElement *)privacyItem
{
[privacyItem addChild:[NSXMLElement elementWithName:@"presence-out"]];
}
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation XMPPPrivacyQueryInfo
@synthesize type;
@synthesize privacyListName;
@synthesize privacyListItems;
@synthesize timer;
- (id)initWithType:(XMPPPrivacyQueryInfoType)aType name:(NSString *)name items:(NSArray *)items
{
if ((self = [super init]))
{
type = aType;
privacyListName = [name copy];
privacyListItems = [items copy];
}
return self;
}
- (void)cancel
{
if (timer)
{
dispatch_source_cancel(timer);
#if !OS_OBJECT_USE_OBJC
dispatch_release(timer);
#endif
timer = NULL;
}
}
- (void)dealloc
{
[self cancel];
}
+ (XMPPPrivacyQueryInfo *)queryInfoWithType:(XMPPPrivacyQueryInfoType)type
{
return [self queryInfoWithType:type name:nil items:nil];
}
+ (XMPPPrivacyQueryInfo *)queryInfoWithType:(XMPPPrivacyQueryInfoType)type name:(NSString *)name
{
return [self queryInfoWithType:type name:name items:nil];
}
+ (XMPPPrivacyQueryInfo *)queryInfoWithType:(XMPPPrivacyQueryInfoType)type name:(NSString *)name items:(NSArray *)items
{
return [[XMPPPrivacyQueryInfo alloc] initWithType:type name:name items:items];
}
@end