1
1
#import " XMPPMUC.h"
2
2
#import " XMPPFramework.h"
3
+ #import " XMPPLogging.h"
4
+ #import " XMPPIDTracker.h"
3
5
6
+ #if DEBUG
7
+ static const int xmppLogLevel = XMPP_LOG_LEVEL_VERBOSE;
8
+ #else
9
+ static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
10
+ #endif
11
+
12
+ NSString *const XMPPDiscoverItemsNamespace = @" http://jabber.org/protocol/disco#items" ;
13
+ NSString *const XMPPMUCErrorDomain = @" XMPPMUCErrorDomain" ;
14
+
15
+ @interface XMPPMUC ()
16
+ {
17
+ BOOL hasRequestedServices;
18
+ BOOL hasRequestedRooms;
19
+ }
20
+
21
+ @end
4
22
5
23
@implementation XMPPMUC
6
24
7
25
- (id )initWithDispatchQueue : (dispatch_queue_t )queue
8
26
{
9
- if ((self = [super initWithDispatchQueue: queue]))
10
- {
27
+ if ((self = [super initWithDispatchQueue: queue])) {
11
28
rooms = [[NSMutableSet alloc ] init ];
12
29
}
13
30
return self;
@@ -17,8 +34,15 @@ - (BOOL)activate:(XMPPStream *)aXmppStream
17
34
{
18
35
if ([super activate: aXmppStream])
19
36
{
37
+ XMPPLogVerbose (@" %@ : Activated" , THIS_FILE);
38
+
39
+ xmppIDTracker = [[XMPPIDTracker alloc ] initWithStream: xmppStream
40
+ dispatchQueue: moduleQueue];
41
+
20
42
#ifdef _XMPP_CAPABILITIES_H
21
- [xmppStream autoAddDelegate: self delegateQueue: moduleQueue toModulesOfClass: [XMPPCapabilities class ]];
43
+ [xmppStream autoAddDelegate: self
44
+ delegateQueue: moduleQueue
45
+ toModulesOfClass: [XMPPCapabilities class ]];
22
46
#endif
23
47
return YES ;
24
48
}
@@ -28,6 +52,18 @@ - (BOOL)activate:(XMPPStream *)aXmppStream
28
52
29
53
- (void )deactivate
30
54
{
55
+ XMPPLogTrace ();
56
+
57
+ dispatch_block_t block = ^{ @autoreleasepool {
58
+ [xmppIDTracker removeAllIDs ];
59
+ xmppIDTracker = nil ;
60
+ }};
61
+
62
+ if (dispatch_get_specific (moduleQueueTag))
63
+ block ();
64
+ else
65
+ dispatch_sync (moduleQueue, block);
66
+
31
67
#ifdef _XMPP_CAPABILITIES_H
32
68
[xmppStream removeAutoDelegate: self delegateQueue: moduleQueue fromModulesOfClass: [XMPPCapabilities class ]];
33
69
#endif
@@ -73,6 +109,175 @@ - (BOOL)isMUCRoomMessage:(XMPPMessage *)message
73
109
return [self isMUCRoomElement: message];
74
110
}
75
111
112
+ /* *
113
+ * This method provides functionality of XEP-0045 6.1 Discovering a MUC Service.
114
+ *
115
+ * @link {http://xmpp.org/extensions/xep-0045.html#disco-service}
116
+ *
117
+ * Example 1. Entity Queries Server for Associated Services
118
+ *
119
+ * <iq from='[email protected] /pda'
120
+ * id='h7ns81g'
121
+ * to='shakespeare.lit'
122
+ * type='get'>
123
+ * <query xmlns='http://jabber.org/protocol/disco#items'/>
124
+ * </iq>
125
+ */
126
+ - (void )discoverServices
127
+ {
128
+ // This is a public method, so it may be invoked on any thread/queue.
129
+
130
+ dispatch_block_t block = ^{ @autoreleasepool {
131
+ if (hasRequestedServices) return ; // We've already requested services
132
+
133
+ NSString *toStr = xmppStream.myJID .domain ;
134
+ NSXMLElement *query = [NSXMLElement elementWithName: @" query"
135
+ xmlns: XMPPDiscoverItemsNamespace];
136
+ XMPPIQ *iq = [XMPPIQ iqWithType: @" get"
137
+ to: [XMPPJID jidWithString: toStr]
138
+ elementID: [xmppStream generateUUID ]
139
+ child: query];
140
+
141
+ [xmppIDTracker addElement: iq
142
+ target: self
143
+ selector: @selector (handleDiscoverServicesQueryIQ:withInfo: )
144
+ timeout: 60 ];
145
+
146
+ [xmppStream sendElement: iq];
147
+ hasRequestedServices = YES ;
148
+ }};
149
+
150
+ if (dispatch_get_specific (moduleQueueTag))
151
+ block ();
152
+ else
153
+ dispatch_async (moduleQueue, block);
154
+ }
155
+
156
+ /* *
157
+ * This method provides functionality of XEP-0045 6.3 Discovering Rooms
158
+ *
159
+ * @link {http://xmpp.org/extensions/xep-0045.html#disco-rooms}
160
+ *
161
+ * Example 5. Entity Queries Chat Service for Rooms
162
+ *
163
+ * <iq from='[email protected] /pda'
164
+ * id='zb8q41f4'
165
+ * to='chat.shakespeare.lit'
166
+ * type='get'>
167
+ * <query xmlns='http://jabber.org/protocol/disco#items'/>
168
+ * </iq>
169
+ */
170
+ - (BOOL )discoverRoomsForServiceNamed : (NSString *)serviceName
171
+ {
172
+ // This is a public method, so it may be invoked on any thread/queue.
173
+
174
+ if (serviceName.length < 2 )
175
+ return NO ;
176
+
177
+ dispatch_block_t block = ^{ @autoreleasepool {
178
+ if (hasRequestedRooms) return ; // We've already requested rooms
179
+
180
+ NSXMLElement *query = [NSXMLElement elementWithName: @" query"
181
+ xmlns: XMPPDiscoverItemsNamespace];
182
+ XMPPIQ *iq = [XMPPIQ iqWithType: @" get"
183
+ to: [XMPPJID jidWithString: serviceName]
184
+ elementID: [xmppStream generateUUID ]
185
+ child: query];
186
+
187
+ [xmppIDTracker addElement: iq
188
+ target: self
189
+ selector: @selector (handleDiscoverRoomsQueryIQ:withInfo: )
190
+ timeout: 60 ];
191
+
192
+ [xmppStream sendElement: iq];
193
+ hasRequestedRooms = YES ;
194
+ }};
195
+
196
+ if (dispatch_get_specific (moduleQueueTag))
197
+ block ();
198
+ else
199
+ dispatch_async (moduleQueue, block);
200
+
201
+ return YES ;
202
+ }
203
+
204
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
205
+ #pragma mark XMPPIDTracker
206
+ // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
207
+
208
+ /* *
209
+ * This method handles the response received (or not received) after calling discoverServices.
210
+ */
211
+ - (void )handleDiscoverServicesQueryIQ : (XMPPIQ *)iq withInfo : (XMPPBasicTrackingInfo *)info
212
+ {
213
+ dispatch_block_t block = ^{ @autoreleasepool {
214
+ NSXMLElement *errorElem = [iq elementForName: @" error" ];
215
+
216
+ if (errorElem) {
217
+ NSString *errMsg = [errorElem.children componentsJoinedByString: @" , " ];
218
+ NSDictionary *dict = @{NSLocalizedDescriptionKey : errMsg};
219
+ NSError *error = [NSError errorWithDomain: XMPPMUCErrorDomain
220
+ code: [errorElem attributeIntegerValueForName: @" code"
221
+ withDefaultValue: 0 ]
222
+ userInfo: dict];
223
+
224
+ [multicastDelegate xmppMUCFailedToDiscoverServices: self
225
+ withError: error];
226
+ return ;
227
+ }
228
+
229
+ NSXMLElement *query = [iq elementForName: @" query"
230
+ xmlns: XMPPDiscoverItemsNamespace];
231
+
232
+ NSArray *items = [query elementsForName: @" item" ];
233
+ [multicastDelegate xmppMUC: self didDiscoverServices: items];
234
+ hasRequestedServices = NO ; // Set this back to NO to allow for future requests
235
+ }};
236
+
237
+ if (dispatch_get_specific (moduleQueueTag))
238
+ block ();
239
+ else
240
+ dispatch_async (moduleQueue, block);
241
+ }
242
+
243
+ /* *
244
+ * This method handles the response received (or not received) after calling discoverRoomsForServiceNamed:.
245
+ */
246
+ - (void )handleDiscoverRoomsQueryIQ : (XMPPIQ *)iq withInfo : (XMPPBasicTrackingInfo *)info
247
+ {
248
+ dispatch_block_t block = ^{ @autoreleasepool {
249
+ NSXMLElement *errorElem = [iq elementForName: @" error" ];
250
+ NSString *serviceName = [iq attributeStringValueForName: @" from" withDefaultValue: @" " ];
251
+
252
+ if (errorElem) {
253
+ NSString *errMsg = [errorElem.children componentsJoinedByString: @" , " ];
254
+ NSDictionary *dict = @{NSLocalizedDescriptionKey : errMsg};
255
+ NSError *error = [NSError errorWithDomain: XMPPMUCErrorDomain
256
+ code: [errorElem attributeIntegerValueForName: @" code"
257
+ withDefaultValue: 0 ]
258
+ userInfo: dict];
259
+ [multicastDelegate xmppMUC: self
260
+ failedToDiscoverRoomsForServiceNamed: serviceName
261
+ withError: error];
262
+ return ;
263
+ }
264
+
265
+ NSXMLElement *query = [iq elementForName: @" query"
266
+ xmlns: XMPPDiscoverItemsNamespace];
267
+
268
+ NSArray *items = [query elementsForName: @" item" ];
269
+ [multicastDelegate xmppMUC: self
270
+ didDiscoverRooms: items
271
+ forServiceNamed: serviceName];
272
+ hasRequestedRooms = NO ; // Set this back to NO to allow for future requests
273
+ }};
274
+
275
+ if (dispatch_get_specific (moduleQueueTag))
276
+ block ();
277
+ else
278
+ dispatch_async (moduleQueue, block);
279
+ }
280
+
76
281
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
77
282
#pragma mark XMPPStream Delegate
78
283
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -182,6 +387,18 @@ - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
182
387
}
183
388
}
184
389
390
+ - (BOOL )xmppStream : (XMPPStream *)stream didReceiveIQ : (XMPPIQ *)iq
391
+ {
392
+ NSString *type = [iq type ];
393
+
394
+ if ([type isEqualToString: @" result" ] || [type isEqualToString: @" error" ]) {
395
+ return [xmppIDTracker invokeForElement: iq withObject: iq];
396
+ }
397
+
398
+ return NO ;
399
+ }
400
+
401
+
185
402
#ifdef _XMPP_CAPABILITIES_H
186
403
/* *
187
404
* If an XMPPCapabilites instance is used we want to advertise our support for MUC.
0 commit comments