220 lines
6.5 KiB
Objective-C
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
|