//
// XMPPIQ+JabberRPCResonse.m
// XEP-0009
//
// Created by Eric Chamberlain on 5/25/10.
//
#import "XMPPIQ+JabberRPCResonse.h"
#import "XMPPJabberRPCModule.h"
#import "XMPPLogging.h"
#import "NSData+XMPP.h"
#import "NSXMLElement+XMPP.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;
#else
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
#endif
@implementation XMPPIQ(JabberRPCResonse)
-(NSXMLElement *)methodResponseElement {
NSXMLElement *query = [self elementForName:@"query"];
return [query elementForName:@"methodResponse"];
}
// is this a Jabber RPC method response
-(BOOL)isMethodResponse {
/*
South Dakota
*/
NSXMLElement *methodResponse = [self methodResponseElement];
return methodResponse != nil;
}
-(BOOL)isFault {
/*
faultCode
4
faultString
Too many parameters.
*/
NSXMLElement *methodResponse = [self methodResponseElement];
return [methodResponse elementForName:@"fault"] != nil;
}
-(BOOL)isJabberRPC {
/*
...
*/
NSXMLElement *rpcQuery = [self elementForName:@"query" xmlns:@"jabber:iq:rpc"];
return rpcQuery != nil;
}
-(id)methodResponse:(NSError **)error {
id response = nil;
/*
South Dakota
*/
// or
/*
faultCode
4
faultString
Too many parameters.
*/
NSXMLElement *methodResponse = [self methodResponseElement];
// parse the methodResponse
response = [self objectFromElement:(NSXMLElement *)[methodResponse childAtIndex:0]];
if ([self isFault]) {
// we should produce an error
// response should be a dict
if (error) {
*error = [NSError errorWithDomain:XMPPJabberRPCErrorDomain
code:[[response objectForKey:@"faultCode"] intValue]
userInfo:(NSDictionary *)response];
}
response = nil;
} else {
if (error) {
*error = nil;
}
}
return response;
}
-(id)objectFromElement:(NSXMLElement *)param {
NSString *element = [param name];
if ([element isEqualToString:@"params"] ||
[element isEqualToString:@"param"] ||
[element isEqualToString:@"fault"] ||
[element isEqualToString:@"value"]) {
NSXMLElement *firstChild = (NSXMLElement *)[param childAtIndex:0];
if (firstChild) {
return [self objectFromElement:firstChild];
} else {
// no child element, treat it like a string
return [self parseString:[param stringValue]];
}
} else if ([element isEqualToString:@"string"] ||
[element isEqualToString:@"name"]) {
return [self parseString:[param stringValue]];
} else if ([element isEqualToString:@"member"]) {
return [self parseMember:param];
} else if ([element isEqualToString:@"array"]) {
return [self parseArray:param];
} else if ([element isEqualToString:@"struct"]) {
return [self parseStruct:param];
} else if ([element isEqualToString:@"int"]) {
return [self parseInteger:[param stringValue]];
} else if ([element isEqualToString:@"double"]) {
return [self parseDouble:[param stringValue]];
} else if ([element isEqualToString:@"boolean"]) {
return [self parseBoolean:[param stringValue]];
} else if ([element isEqualToString:@"dateTime.iso8601"]) {
return [self parseDate:[param stringValue]];
} else if ([element isEqualToString:@"base64"]) {
return [self parseData:[param stringValue]];
} else {
// bad element
XMPPLogWarn(@"%@: %@ - bad element: %@", THIS_FILE, THIS_METHOD, [param stringValue]);
}
return nil;
}
#pragma mark -
-(NSArray *)parseArray:(NSXMLElement *)arrayElement {
/*
12
Egypt
0
-31
*/
NSXMLElement *data = (NSXMLElement *)[arrayElement childAtIndex:0];
NSArray *children = [data children];
NSMutableArray *array = [NSMutableArray arrayWithCapacity:[children count]];
for (NSXMLElement *child in children) {
[array addObject:[self objectFromElement:child]];
}
return array;
}
-(NSDictionary *)parseStruct:(NSXMLElement *)structElement {
/*
lowerBound
18
upperBound
139
*/
NSArray *children = [structElement children];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:[children count]];
for (NSXMLElement *child in children) {
[dict addEntriesFromDictionary:[self parseMember:child]];
}
return dict;
}
-(NSDictionary *)parseMember:(NSXMLElement *)memberElement {
NSString *key = [self objectFromElement:[memberElement elementForName:@"name"]];
id value = [self objectFromElement:[memberElement elementForName:@"value"]];
return @{key : value};
}
#pragma mark -
- (NSDate *)parseDateString: (NSString *)dateString withFormat: (NSString *)format {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];
[dateFormatter setDateFormat: format];
NSDate *result = [dateFormatter dateFromString: dateString];
return result;
}
#pragma mark -
- (NSNumber *)parseInteger: (NSString *)value {
return @([value integerValue]);
}
- (NSNumber *)parseDouble: (NSString *)value {
return @([value doubleValue]);
}
- (NSNumber *)parseBoolean: (NSString *)value {
if ([value isEqualToString: @"1"]) {
return @YES;
}
return @NO;
}
- (NSString *)parseString: (NSString *)value {
return [value stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (NSDate *)parseDate: (NSString *)value {
NSDate *result = nil;
result = [self parseDateString: value withFormat: @"yyyyMMdd'T'HH:mm:ss"];
if (!result) {
result = [self parseDateString: value withFormat: @"yyyy'-'MM'-'dd'T'HH:mm:ss"];
}
return result;
}
- (NSData *)parseData: (NSString *)value {
// Convert the base 64 encoded data into a string
NSData *base64Data = [value dataUsingEncoding:NSASCIIStringEncoding];
NSData *decodedData = [base64Data xmpp_base64Decoded];
return decodedData;
}
@end