-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
XMPPIQ+JabberRPC.m
219 lines (171 loc) · 6.55 KB
/
XMPPIQ+JabberRPC.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
//
// 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 objectForKey: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 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