2016-02-24 16:56:39 +01:00

220 lines
6.5 KiB
Objective-C

//
// XMPPIQ+JabberRPC.m
// XEP-0009
//
// Created by Eric Chamberlain on 5/16/10.
//
#import "XMPPIQ+JabberRPC.h"
#import "XMPP.h"
#import "NSData+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
@implementation XMPPIQ(JabberRPC)
+(XMPPIQ *)rpcTo:(XMPPJID *)jid methodName:(NSString *)method parameters:(NSArray *)parameters {
// Send JabberRPC element
//
// <iq to="fullJID" type="set" id="elementID">
// <query xmlns='jabber:iq:rpc'>
// <methodCall>
// <methodName>method</methodName>
// <params>
// <param>
// <value><string>example</string></value>
// </param>
// ...
// </params>
// </methodCall>
// </query>
// </iq>
XMPPIQ *iq = [XMPPIQ iqWithType:@"set" to:jid elementID:[XMPPStream generateUUID]];
NSXMLElement *jabberRPC = [self elementRpcQuery];
NSXMLElement *methodCall = [self elementMethodCall];
NSXMLElement *methodName = [self elementMethodName:method];
NSXMLElement *params = [self elementParams];
for (id parameter in parameters) {
[params addChild:[self paramElementFromObject:parameter]];
}
[methodCall addChild:methodName];
[methodCall addChild:params];
[jabberRPC addChild:methodCall];
[iq addChild:jabberRPC];
return iq;
}
#pragma mark Element helper methods
+(NSXMLElement *)elementRpcQuery {
return [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:rpc"];
}
+(NSXMLElement *)elementMethodCall {
return [NSXMLElement elementWithName:@"methodCall"];
}
+(NSXMLElement *)elementMethodName:(NSString *)method {
return [NSXMLElement elementWithName:@"methodName" stringValue:method];
}
+(NSXMLElement *)elementParams {
return [NSXMLElement elementWithName:@"params"];
}
#pragma mark -
#pragma mark Disco elements
+(NSXMLElement *)elementRpcIdentity {
NSXMLElement *identity = [NSXMLElement elementWithName:@"identity"];
[identity addAttributeWithName:@"category" stringValue:@"automation"];
[identity addAttributeWithName:@"type" stringValue:@"rpc"];
return identity;
}
// returns the Disco query feature element
// <feature var='jabber:iq:rpc'/>
+(NSXMLElement *)elementRpcFeature {
NSXMLElement *feature = [NSXMLElement elementWithName:@"feature"];
[feature addAttributeWithName:@"var" stringValue:@"jabber:iq:rpc"];
return feature;
}
#pragma mark Conversion methods
+(NSXMLElement *)paramElementFromObject:(id)object {
if (!object) {
return nil;
}
return [self wrapElement:@"param" aroundElement:[self valueElementFromObject:object]];
}
+(NSXMLElement *)valueElementFromObject:(id)object {
if (!object) {
return nil;
}
if ([object isKindOfClass: [NSArray class]]) {
return [self valueElementFromArray: object];
} else if ([object isKindOfClass: [NSDictionary class]]) {
return [self valueElementFromDictionary: object];
} else if (((__bridge CFBooleanRef)object == kCFBooleanTrue) || ((__bridge CFBooleanRef)object == kCFBooleanFalse)) {
return [self valueElementFromBoolean: (__bridge CFBooleanRef)object];
} else if ([object isKindOfClass: [NSNumber class]]) {
return [self valueElementFromNumber: object];
} else if ([object isKindOfClass: [NSString class]]) {
return [self valueElementFromString: object];
} else if ([object isKindOfClass: [NSDate class]]) {
return [self valueElementFromDate: object];
} else if ([object isKindOfClass: [NSData class]]) {
return [self valueElementFromData: object];
} else {
return [self valueElementFromString: object];
}
}
+(NSXMLElement *)valueElementFromArray:(NSArray *)array {
NSXMLElement *data = [NSXMLElement elementWithName:@"data"];
for (id object in array) {
[data addChild:[self valueElementFromObject:object]];
}
return [self wrapValueElementAroundElement:data];
}
+(NSXMLElement *)valueElementFromDictionary:(NSDictionary *)dictionary {
NSXMLElement *structElement = [NSXMLElement elementWithName:@"struct"];
NSXMLElement *member;
NSXMLElement *name;
for (NSString *key in dictionary) {
member = [NSXMLElement elementWithName:@"member"];
name = [NSXMLElement elementWithName:@"name" stringValue:key];
[member addChild:name];
[member addChild:[self valueElementFromObject:dictionary[key]]];
}
return [self wrapValueElementAroundElement:structElement];
}
+(NSXMLElement *)valueElementFromBoolean:(CFBooleanRef)boolean {
if (boolean == kCFBooleanTrue) {
return [self valueElementFromElementWithName:@"boolean" value:@"1"];
} else {
return [self valueElementFromElementWithName:@"boolean" value:@"0"];
}
}
+(NSXMLElement *)valueElementFromNumber:(NSNumber *)number {
// what type of NSNumber is this?
if ([[NSString stringWithCString: [number objCType]
encoding: NSUTF8StringEncoding] isEqualToString: @"d"]) {
return [self valueElementFromElementWithName:@"double" value:[number stringValue]];
} else {
return [self valueElementFromElementWithName:@"i4" value:[number stringValue]];
}
}
+(NSXMLElement *)valueElementFromString:(NSString *)string {
return [self valueElementFromElementWithName:@"string" value:string];
}
+(NSXMLElement *)valueElementFromDate:(NSDate *)date {
unsigned calendarComponents = kCFCalendarUnitYear |
kCFCalendarUnitMonth |
kCFCalendarUnitDay |
kCFCalendarUnitHour |
kCFCalendarUnitMinute |
kCFCalendarUnitSecond;
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:calendarComponents fromDate:date];
NSString *dateString = [NSString stringWithFormat: @"%.4ld%.2ld%.2ldT%.2ld:%.2ld:%.2ld",
(long)[dateComponents year],
(long)[dateComponents month],
(long)[dateComponents day],
(long)[dateComponents hour],
(long)[dateComponents minute],
(long)[dateComponents second], nil];
return [self valueElementFromElementWithName:@"dateTime.iso8601" value: dateString];
}
+(NSXMLElement *)valueElementFromData:(NSData *)data {
return [self valueElementFromElementWithName:@"base64" value:[data xmpp_base64Encoded]];
}
+(NSXMLElement *)valueElementFromElementWithName:(NSString *)elementName value:(NSString *)value {
return [self wrapValueElementAroundElement:[NSXMLElement elementWithName:elementName stringValue:value]];
}
#pragma mark Wrapper methods
+(NSXMLElement *)wrapElement:(NSString *)elementName aroundElement:(NSXMLElement *)element {
NSXMLElement *wrapper = [NSXMLElement elementWithName:elementName];
[wrapper addChild:element];
return wrapper;
}
+(NSXMLElement *)wrapValueElementAroundElement:(NSXMLElement *)element {
return [self wrapElement:@"value" aroundElement:element];
}
@end