chatsecureios / ChatSecure / Classes / Controllers / XMPP / OTRXMPPRoomManager.m @ a4bb25f6
History | View | Annotate | Download (21.2 KB)
1 |
// |
---|---|
2 |
// OTRXMPPRoomManager.m |
3 |
// ChatSecure |
4 |
// |
5 |
// Created by David Chiles on 10/9/15. |
6 |
// Copyright © 2015 Chris Ballinger. All rights reserved. |
7 |
// |
8 |
|
9 |
#import "OTRXMPPRoomManager.h" |
10 |
@import XMPPFramework; |
11 |
#import <ChatSecureCore/ChatSecureCore-Swift.h> |
12 |
#import "OTRXMPPRoomYapStorage.h" |
13 |
#import "OTRBuddy.h" |
14 |
@import YapDatabase; |
15 |
#import "OTRLog.h" |
16 |
|
17 |
|
18 |
@interface OTRXMPPRoomManager () <XMPPMUCDelegate, XMPPRoomDelegate, XMPPStreamDelegate, OTRYapViewHandlerDelegateProtocol> |
19 |
|
20 |
@property (nonatomic, strong, readonly) NSMutableDictionary<XMPPJID*,XMPPRoom*> *rooms; |
21 |
|
22 |
@property (nonatomic, strong, readonly) XMPPMUC *mucModule; |
23 |
|
24 |
/** This dictionary has jid as the key and array of buddy unique Ids to invite once we've joined the room*/ |
25 |
@property (nonatomic, strong, readonly) NSMutableDictionary<NSString*,NSArray<NSString *> *> *inviteDictionary; |
26 |
|
27 |
/** This dictionary is a temporary holding for setting a room subject. Once the room is created teh subject is set from this dictionary. */ |
28 |
@property (nonatomic, strong, readonly) NSMutableDictionary<NSString*,NSString*> *tempRoomSubject; |
29 |
|
30 |
/** This array is a temporary holding with rooms we should configure once connected */ |
31 |
@property (nonatomic, strong, readonly) NSMutableArray<NSString*> *roomsToConfigure; |
32 |
|
33 |
@end |
34 |
|
35 |
@implementation OTRXMPPRoomManager |
36 |
|
37 |
- (instancetype) initWithDatabaseConnection:(YapDatabaseConnection*)databaseConnection |
38 |
capabilities:(XMPPCapabilities*)capabilities |
39 |
dispatchQueue:(nullable dispatch_queue_t)dispatchQueue { |
40 |
if (self = [super initWithDispatchQueue:dispatchQueue]) { |
41 |
_databaseConnection = databaseConnection; |
42 |
_capabilities = capabilities; |
43 |
_mucModule = [[XMPPMUC alloc] init]; |
44 |
_inviteDictionary = [[NSMutableDictionary alloc] init]; |
45 |
_tempRoomSubject = [[NSMutableDictionary alloc] init]; |
46 |
_roomsToConfigure = [[NSMutableArray alloc] init]; |
47 |
_rooms = [[NSMutableDictionary alloc] init]; |
48 |
_bookmarksModule = [[XMPPBookmarksModule alloc] initWithMode:XMPPBookmarksModePrivateXmlStorage dispatchQueue:nil]; |
49 |
} |
50 |
return self; |
51 |
} |
52 |
|
53 |
- (BOOL)activate:(XMPPStream *)aXmppStream |
54 |
{ |
55 |
BOOL result = [super activate:aXmppStream]; |
56 |
[self.mucModule activate:aXmppStream]; |
57 |
[self.mucModule addDelegate:self delegateQueue:moduleQueue]; |
58 |
[multicastDelegate addDelegate:self delegateQueue:moduleQueue]; |
59 |
|
60 |
[self.bookmarksModule activate:self.xmppStream]; |
61 |
|
62 |
//Register view for sending message queue and occupants |
63 |
[self.databaseConnection.database asyncRegisterGroupOccupantsView:nil completionBlock:nil]; |
64 |
|
65 |
return result; |
66 |
} |
67 |
|
68 |
- (void) deactivate { |
69 |
[self.mucModule removeDelegate:self]; |
70 |
[self.mucModule deactivate]; |
71 |
[self.bookmarksModule deactivate]; |
72 |
[super deactivate]; |
73 |
} |
74 |
|
75 |
- (NSString *)joinRoom:(XMPPJID *)jid withNickname:(NSString *)name subject:(NSString *)subject password:(nullable NSString *)password |
76 |
{ |
77 |
dispatch_async(moduleQueue, ^{ |
78 |
if ([subject length]) { |
79 |
[self.tempRoomSubject setObject:subject forKey:jid.bare]; |
80 |
} |
81 |
}); |
82 |
|
83 |
XMPPRoom *room = [self roomForJID:jid]; |
84 |
NSString* accountId = self.xmppStream.tag; |
85 |
NSString *databaseRoomKey = [OTRXMPPRoom createUniqueId:accountId jid:jid.bare]; |
86 |
__block NSString *nickname = name; |
87 |
|
88 |
if (!room) { |
89 |
OTRXMPPRoomYapStorage *storage = [[OTRXMPPRoomYapStorage alloc] initWithDatabaseConnection:self.databaseConnection capabilities:self.capabilities]; |
90 |
room = [[XMPPRoom alloc] initWithRoomStorage:storage jid:jid]; |
91 |
[self setRoom:room forJID:room.roomJID]; |
92 |
[room activate:self.xmppStream]; |
93 |
[room addDelegate:self delegateQueue:moduleQueue]; |
94 |
} |
95 |
|
96 |
/** Create room database object */ |
97 |
[self.databaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) { |
98 |
OTRXMPPRoom *room = [[OTRXMPPRoom fetchObjectWithUniqueID:databaseRoomKey transaction:transaction] copy]; |
99 |
if(!room) { |
100 |
room = [[OTRXMPPRoom alloc] init]; |
101 |
room.lastRoomMessageId = @""; // Hack to make it show up in list |
102 |
room.accountUniqueId = accountId; |
103 |
room.jid = jid.bare; |
104 |
} else { |
105 |
// Clear out roles, we'll getpresence updates once we join |
106 |
[self clearOccupantRolesInRoom:room withTransaction:transaction]; |
107 |
} |
108 |
|
109 |
//Other Room properties should be set here |
110 |
if ([subject length]) { |
111 |
room.subject = subject; |
112 |
} |
113 |
room.roomPassword = password; |
114 |
|
115 |
[room saveWithTransaction:transaction]; |
116 |
|
117 |
if (!nickname) { |
118 |
OTRXMPPAccount *account = [OTRXMPPAccount fetchObjectWithUniqueID:accountId transaction:transaction]; |
119 |
nickname = account.bareJID.user; |
120 |
} |
121 |
}]; |
122 |
|
123 |
//Get history if any |
124 |
NSXMLElement *historyElement = nil; |
125 |
OTRXMPPRoomYapStorage *storage = room.xmppRoomStorage; |
126 |
id<OTRMessageProtocol> lastMessage = [storage lastMessageInRoom:room accountKey:accountId]; |
127 |
NSDate *lastMessageDate = [lastMessage messageDate]; |
128 |
if (lastMessageDate) { |
129 |
//Use since as our history marker if we have a last message |
130 |
//http://xmpp.org/extensions/xep-0045.html#enter-managehistory |
131 |
NSString *dateTimeString = [lastMessageDate xmppDateTimeString]; |
132 |
historyElement = [NSXMLElement elementWithName:@"history"]; |
133 |
[historyElement addAttributeWithName:@"since" stringValue:dateTimeString]; |
134 |
} |
135 |
|
136 |
[room joinRoomUsingNickname:nickname history:historyElement password:password]; |
137 |
return databaseRoomKey; |
138 |
} |
139 |
|
140 |
- (void)leaveRoom:(nonnull XMPPJID *)jid |
141 |
{ |
142 |
XMPPRoom *room = [self roomForJID:jid]; |
143 |
[room leaveRoom]; |
144 |
[self removeRoomForJID:jid]; |
145 |
[room removeDelegate:self]; |
146 |
[room deactivate]; |
147 |
} |
148 |
|
149 |
- (void)clearOccupantRolesInRoom:(OTRXMPPRoom *)room withTransaction:(YapDatabaseReadWriteTransaction * _Nonnull)transaction { |
150 |
//Enumerate of room eges to occupants |
151 |
NSString *extensionName = [YapDatabaseConstants extensionName:DatabaseExtensionNameRelationshipExtensionName]; |
152 |
[[transaction ext:extensionName] enumerateEdgesWithName:[OTRXMPPRoomOccupant roomEdgeName] destinationKey:room.uniqueId collection:[OTRXMPPRoom collection] usingBlock:^(YapDatabaseRelationshipEdge *edge, BOOL *stop) { |
153 |
|
154 |
OTRXMPPRoomOccupant *occupant = [transaction objectForKey:edge.sourceKey inCollection:edge.sourceCollection]; |
155 |
occupant.role = RoomOccupantRoleNone; |
156 |
[occupant saveWithTransaction:transaction]; |
157 |
}]; |
158 |
} |
159 |
|
160 |
- (NSString *)startGroupChatWithBuddies:(NSArray<NSString *> *)buddiesArray roomJID:(XMPPJID *)roomName nickname:(NSString *)name subject:(nullable NSString *)subject |
161 |
{ |
162 |
if (buddiesArray.count) { |
163 |
[self performBlockAsync:^{ |
164 |
[self.inviteDictionary setObject:buddiesArray forKey:roomName.bare]; |
165 |
}]; |
166 |
} |
167 |
[self.roomsToConfigure addObject:roomName.bare]; |
168 |
XMPPConferenceBookmark *bookmark = [[XMPPConferenceBookmark alloc] initWithJID:roomName bookmarkName:subject nick:name autoJoin:YES]; |
169 |
[self.bookmarksModule fetchAndPublishWithBookmarksToAdd:@[bookmark] bookmarksToRemove:nil completion:^(NSArray<id<XMPPBookmark>> * _Nullable newBookmarks, XMPPIQ * _Nullable responseIq) { |
170 |
if (newBookmarks) { |
171 |
DDLogInfo(@"Joined new room, added to merged bookmarks: %@", newBookmarks); |
172 |
} |
173 |
} completionQueue:nil]; |
174 |
return [self joinRoom:roomName withNickname:name subject:subject password:nil]; |
175 |
} |
176 |
|
177 |
- (void)inviteBuddies:(NSArray<NSString *> *)buddyUniqueIds toRoom:(XMPPRoom *)room { |
178 |
if (!buddyUniqueIds.count) { |
179 |
return; |
180 |
} |
181 |
NSMutableArray<XMPPJID*> *buddyJIDs = [NSMutableArray arrayWithCapacity:buddyUniqueIds.count]; |
182 |
[self.databaseConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { |
183 |
[buddyUniqueIds enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { |
184 |
OTRXMPPBuddy *buddy = [OTRXMPPBuddy fetchObjectWithUniqueID:obj transaction:transaction]; |
185 |
XMPPJID *buddyJID = buddy.bareJID; |
186 |
if (buddyJID) { |
187 |
[buddyJIDs addObject:buddyJID]; |
188 |
} |
189 |
}]; |
190 |
}]; |
191 |
// XMPPRoom.inviteUsers doesn't seem to work, so you have |
192 |
// to send an individual invitation for each person. |
193 |
[buddyJIDs enumerateObjectsUsingBlock:^(XMPPJID * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { |
194 |
[room inviteUser:obj withMessage:nil]; |
195 |
}]; |
196 |
} |
197 |
|
198 |
#pragma - mark XMPPStreamDelegate Methods |
199 |
|
200 |
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender { |
201 |
|
202 |
//Once we've connecected and authenticated we find what room services are available |
203 |
[self.mucModule discoverServices]; |
204 |
//Once we've authenitcated we need to rejoin existing rooms |
205 |
NSMutableArray <OTRXMPPRoom *>*roomArray = [[NSMutableArray alloc] init]; |
206 |
__block NSString *nickname = self.xmppStream.myJID.user; |
207 |
[self.databaseConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { |
208 |
OTRXMPPAccount *account = [OTRXMPPAccount accountForStream:sender transaction:transaction]; |
209 |
if (account) { |
210 |
nickname = account.displayName; |
211 |
} |
212 |
[transaction enumerateKeysAndObjectsInCollection:[OTRXMPPRoom collection] usingBlock:^(NSString * _Nonnull key, id _Nonnull object, BOOL * _Nonnull stop) { |
213 |
|
214 |
if ([object isKindOfClass:[OTRXMPPRoom class]]) { |
215 |
OTRXMPPRoom *room = (OTRXMPPRoom *)object; |
216 |
if ([room.jid length]) { |
217 |
[roomArray addObject:room]; |
218 |
} |
219 |
} |
220 |
|
221 |
} withFilter:^BOOL(NSString * _Nonnull key) { |
222 |
//OTRXMPPRoom is saved with the jid and account id as part of the key |
223 |
if ([key containsString:sender.tag]) { |
224 |
return YES; |
225 |
} |
226 |
return NO; |
227 |
}]; |
228 |
}]; |
229 |
[roomArray enumerateObjectsUsingBlock:^(OTRXMPPRoom * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { |
230 |
[self joinRoom:[XMPPJID jidWithString:obj.jid] withNickname:nickname subject:obj.subject password:obj.roomPassword]; |
231 |
}]; |
232 |
|
233 |
[self addRoomsToBookmarks:roomArray]; |
234 |
|
235 |
[self.bookmarksModule fetchBookmarks:^(NSArray<id<XMPPBookmark>> * _Nullable bookmarks, XMPPIQ * _Nullable responseIq) { |
236 |
|
237 |
} completionQueue:nil]; |
238 |
} |
239 |
|
240 |
- (void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error |
241 |
{ |
242 |
//Check id and mark as needs sending |
243 |
|
244 |
} |
245 |
|
246 |
- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message |
247 |
{ |
248 |
//Check id and mark as sent |
249 |
} |
250 |
|
251 |
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message |
252 |
{ |
253 |
XMPPJID *from = [message from]; |
254 |
//Check that this is a message for one of our rooms |
255 |
if([message isGroupChatMessageWithSubject] && [self roomForJID:from] != nil) { |
256 |
|
257 |
NSString *subject = [message subject]; |
258 |
|
259 |
NSString *databaseRoomKey = [OTRXMPPRoom createUniqueId:self.xmppStream.tag jid:from.bare]; |
260 |
|
261 |
[self.databaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) { |
262 |
OTRXMPPRoom *room = [OTRXMPPRoom fetchObjectWithUniqueID:databaseRoomKey transaction:transaction]; |
263 |
room.subject = subject; |
264 |
[room saveWithTransaction:transaction]; |
265 |
}]; |
266 |
|
267 |
} |
268 |
|
269 |
// Handle group chat message receipts |
270 |
[OTRXMPPRoomMessage handleDeliveryReceiptResponseWithMessage:message writeConnection:self.databaseConnection]; |
271 |
} |
272 |
|
273 |
#pragma - mark XMPPMUCDelegate Methods |
274 |
|
275 |
- (void)xmppMUC:(XMPPMUC *)sender didDiscoverServices:(NSArray *)services |
276 |
{ |
277 |
NSMutableArray *array = [NSMutableArray arrayWithCapacity:[services count]]; |
278 |
[services enumerateObjectsUsingBlock:^(NSXMLElement * _Nonnull element, NSUInteger idx, BOOL * _Nonnull stop) { |
279 |
NSString *jid = [element attributeStringValueForName:@"jid"]; |
280 |
if ([jid length] && [jid containsString:@"conference"]) { |
281 |
[array addObject:jid]; |
282 |
//TODO instead of just checking if it has the word 'confernce' in the name we need to preform a iq 'get' to see it's capabilities. |
283 |
|
284 |
} |
285 |
|
286 |
}]; |
287 |
_conferenceServicesJID = array; |
288 |
} |
289 |
|
290 |
- (void)xmppMUC:(XMPPMUC *)sender roomJID:(XMPPJID *)roomJID didReceiveInvitation:(XMPPMessage *)message |
291 |
{ |
292 |
// We must check if we trust the person who invited us |
293 |
// because some servers will send you invites from anyone |
294 |
// We should probably move some of this code upstream into XMPPFramework |
295 |
|
296 |
// Since XMPP is super great, there are (at least) two ways to receive a room invite. |
297 |
|
298 |
// Examples from XEP-0045: |
299 |
// Example 124. Room Sends Invitation to New Member: |
300 |
// |
301 |
// <message from='darkcave@chat.shakespeare.lit' to='hecate@shakespeare.lit'> |
302 |
// <x xmlns='http://jabber.org/protocol/muc#user'> |
303 |
// <invite from='bard@shakespeare.lit'/> |
304 |
// <password>cauldronburn</password> |
305 |
// </x> |
306 |
// </message> |
307 |
// |
308 |
|
309 |
// Examples from XEP-0249: |
310 |
// |
311 |
// |
312 |
// Example 1. A direct invitation |
313 |
// |
314 |
// <message from='crone1@shakespeare.lit/desktop' to='hecate@shakespeare.lit'> |
315 |
// <x xmlns='jabber:x:conference' |
316 |
// jid='darkcave@macbeth.shakespeare.lit' |
317 |
// password='cauldronburn' |
318 |
// reason='Hey Hecate, this is the place for all good witches!'/> |
319 |
// </message> |
320 |
|
321 |
XMPPJID *fromJID = nil; |
322 |
NSString *password = nil; |
323 |
|
324 |
NSXMLElement * roomInvite = [message elementForName:@"x" xmlns:XMPPMUCUserNamespace]; |
325 |
NSXMLElement * directInvite = [message elementForName:@"x" xmlns:@"jabber:x:conference"]; |
326 |
if (roomInvite) { |
327 |
// XEP-0045 |
328 |
NSXMLElement * invite = [roomInvite elementForName:@"invite"]; |
329 |
fromJID = [XMPPJID jidWithString:[invite attributeStringValueForName:@"from"]]; |
330 |
password = [roomInvite elementForName:@"password"].stringValue; |
331 |
} else if (directInvite) { |
332 |
// XEP-0249 |
333 |
fromJID = [message from]; |
334 |
password = [directInvite attributeStringValueForName:@"password"]; |
335 |
} |
336 |
if (!fromJID) { |
337 |
DDLogWarn(@"Could not parse fromJID from room invite: %@", message); |
338 |
return; |
339 |
} |
340 |
__block OTRXMPPBuddy *buddy = nil; |
341 |
XMPPStream *stream = self.xmppStream; |
342 |
NSString *accountUniqueId = stream.tag; |
343 |
__block NSString *nickname = stream.myJID.user; |
344 |
[self.databaseConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) { |
345 |
OTRXMPPAccount *account = [OTRXMPPAccount accountForStream:stream transaction:transaction]; |
346 |
if (account) { |
347 |
nickname = account.displayName; |
348 |
} |
349 |
buddy = [OTRXMPPBuddy fetchBuddyWithJid:fromJID accountUniqueId:accountUniqueId transaction:transaction]; |
350 |
}]; |
351 |
// We were invited by someone not on our roster. Shady business! |
352 |
if (!buddy) { |
353 |
DDLogWarn(@"Received room invitation from someone not on our roster! %@ %@", fromJID, message); |
354 |
return; |
355 |
} |
356 |
[self joinRoom:roomJID withNickname:nickname subject:nil password:password]; |
357 |
} |
358 |
|
359 |
#pragma - mark XMPPRoomDelegate Methods |
360 |
|
361 |
- (void) xmppRoom:(XMPPRoom *)room didFetchMembersList:(NSArray<NSXMLElement*> *)items { |
362 |
DDLogInfo(@"Fetched members list: %@", items); |
363 |
NSString *accountId = room.xmppStream.tag; |
364 |
[self.databaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) { |
365 |
[items enumerateObjectsUsingBlock:^(NSXMLElement *item, NSUInteger idx, BOOL * _Nonnull stop) { |
366 |
NSString *jidString = [item attributeStringValueForName:@"jid"]; |
367 |
XMPPJID *jid = [XMPPJID jidWithString:jidString]; |
368 |
if (!jid) { return; } |
369 |
// Make sure occupant object exists/is created |
370 |
OTRXMPPRoomOccupant *occupant = [OTRXMPPRoomOccupant occupantWithJid:jid realJID:jid roomJID:room.roomJID accountId:accountId createIfNeeded:YES transaction:transaction]; |
371 |
[occupant saveWithTransaction:transaction]; |
372 |
}]; |
373 |
}]; |
374 |
} |
375 |
|
376 |
- (void)xmppRoomDidJoin:(XMPPRoom *)sender |
377 |
{ |
378 |
[self performBlockAsync:^{ |
379 |
//Configure room if we are the creator |
380 |
if ([self.roomsToConfigure containsObject:sender.roomJID.bare]) { |
381 |
[self.roomsToConfigure removeObject:sender.roomJID.bare]; |
382 |
[sender configureRoomUsingOptions:[[self class] defaultRoomConfiguration]]; |
383 |
|
384 |
//Set Room Subject |
385 |
NSString *subject = [self.tempRoomSubject objectForKey:sender.roomJID.bare]; |
386 |
if (subject) { |
387 |
[self.tempRoomSubject removeObjectForKey:sender.roomJID.bare]; |
388 |
[sender changeRoomSubject:subject]; |
389 |
} |
390 |
} |
391 |
|
392 |
//Invite buddies |
393 |
NSArray<NSString*> *buddyUniqueIds = [self.inviteDictionary objectForKey:sender.roomJID.bare]; |
394 |
if (buddyUniqueIds) { |
395 |
[self.inviteDictionary removeObjectForKey:sender.roomJID.bare]; |
396 |
[self inviteBuddies:buddyUniqueIds toRoom:sender]; |
397 |
} |
398 |
|
399 |
//Fetch member list |
400 |
[sender fetchMembersList]; |
401 |
}]; |
402 |
} |
403 |
|
404 |
- (void)xmppRoomDidLeave:(XMPPRoom *)sender { |
405 |
NSString *databaseRoomKey = [OTRXMPPRoom createUniqueId:self.xmppStream.tag jid:[sender.roomJID bare]]; |
406 |
[self.databaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) { |
407 |
OTRXMPPRoom *room = [OTRXMPPRoom fetchObjectWithUniqueID:databaseRoomKey transaction:transaction]; |
408 |
if (room) { |
409 |
[self clearOccupantRolesInRoom:room withTransaction:transaction]; |
410 |
} |
411 |
}]; |
412 |
} |
413 |
|
414 |
#pragma mark - Utility |
415 |
|
416 |
- (void) removeRoomForJID:(nonnull XMPPJID*)jid { |
417 |
NSParameterAssert(jid != nil); |
418 |
if (!jid) { return; } |
419 |
[self performBlockAsync:^{ |
420 |
[self.rooms removeObjectForKey:jid.bareJID]; |
421 |
}]; |
422 |
} |
423 |
|
424 |
- (void) setRoom:(nonnull XMPPRoom*)room forJID:(nonnull XMPPJID*)jid { |
425 |
NSParameterAssert(room != nil); |
426 |
NSParameterAssert(jid != nil); |
427 |
if (!room || !jid) { |
428 |
return; |
429 |
} |
430 |
[self performBlockAsync:^{ |
431 |
[self.rooms setObject:room forKey:jid.bareJID]; |
432 |
}]; |
433 |
} |
434 |
|
435 |
- (nullable XMPPRoom*) roomForJID:(nonnull XMPPJID*)jid { |
436 |
NSParameterAssert(jid != nil); |
437 |
if (!jid) { return nil; } |
438 |
__block XMPPRoom *room = nil; |
439 |
[self performBlock:^{ |
440 |
room = [self.rooms objectForKey:jid.bareJID]; |
441 |
}]; |
442 |
return room; |
443 |
} |
444 |
|
445 |
#pragma - mark Class Methods |
446 |
|
447 |
+ (NSXMLElement *)defaultRoomConfiguration |
448 |
{ |
449 |
NSXMLElement *form = [[NSXMLElement alloc] initWithName:@"x" xmlns:@"jabber:x:data"]; |
450 |
|
451 |
NSXMLElement *formTypeField = [[NSXMLElement alloc] initWithName:@"field"]; |
452 |
[formTypeField addAttributeWithName:@"var" stringValue:@"FORM_TYPE"]; |
453 |
[formTypeField addChild:[[NSXMLElement alloc] initWithName:@"value" stringValue:@"http://jabber.org/protocol/muc#roomconfig"]]; |
454 |
|
455 |
NSXMLElement *publicField = [[NSXMLElement alloc] initWithName:@"field"]; |
456 |
[publicField addAttributeWithName:@"var" stringValue:@"muc#roomconfig_publicroom"]; |
457 |
[publicField addChild:[[NSXMLElement alloc] initWithName:@"value" numberValue:@(0)]]; |
458 |
|
459 |
NSXMLElement *persistentField = [[NSXMLElement alloc] initWithName:@"field"]; |
460 |
[persistentField addAttributeWithName:@"var" stringValue:@"muc#roomconfig_persistentroom"]; |
461 |
[persistentField addChild:[[NSXMLElement alloc] initWithName:@"value" numberValue:@(1)]]; |
462 |
|
463 |
NSXMLElement *whoisField = [[NSXMLElement alloc] initWithName:@"field"]; |
464 |
[whoisField addAttributeWithName:@"var" stringValue:@"muc#roomconfig_whois"]; |
465 |
[whoisField addChild:[[NSXMLElement alloc] initWithName:@"value" stringValue:@"anyone"]]; |
466 |
|
467 |
NSXMLElement *membersOnlyField = [[NSXMLElement alloc] initWithName:@"field"]; |
468 |
[membersOnlyField addAttributeWithName:@"var" stringValue:@"muc#roomconfig_membersonly"]; |
469 |
[membersOnlyField addChild:[[NSXMLElement alloc] initWithName:@"value" numberValue:@(1)]]; |
470 |
|
471 |
NSXMLElement *getMemberListField = [[NSXMLElement alloc] initWithName:@"field"]; |
472 |
[getMemberListField addAttributeWithName:@"var" stringValue:@"muc#roomconfig_getmemberlist"]; |
473 |
[getMemberListField addChild:[[NSXMLElement alloc] initWithName:@"value" stringValue:@"moderator"]]; |
474 |
[getMemberListField addChild:[[NSXMLElement alloc] initWithName:@"value" stringValue:@"participant"]]; |
475 |
|
476 |
NSXMLElement *presenceBroadcastField = [[NSXMLElement alloc] initWithName:@"field"]; |
477 |
[presenceBroadcastField addAttributeWithName:@"var" stringValue:@"muc#roomconfig_presencebroadcast"]; |
478 |
[presenceBroadcastField addChild:[[NSXMLElement alloc] initWithName:@"value" stringValue:@"moderator"]]; |
479 |
[presenceBroadcastField addChild:[[NSXMLElement alloc] initWithName:@"value" stringValue:@"participant"]]; |
480 |
|
481 |
[form addChild:formTypeField]; |
482 |
[form addChild:publicField]; |
483 |
[form addChild:persistentField]; |
484 |
[form addChild:whoisField]; |
485 |
[form addChild:membersOnlyField]; |
486 |
[form addChild:getMemberListField]; |
487 |
[form addChild:presenceBroadcastField]; |
488 |
|
489 |
return form; |
490 |
} |
491 |
|
492 |
@end |
493 |
|
494 |
@implementation XMPPRoom(RoomManager) |
495 |
- (void) sendRoomMessage:(OTRXMPPRoomMessage *)roomMessage { |
496 |
NSParameterAssert(roomMessage); |
497 |
if (!roomMessage) { return; } |
498 |
NSString *elementId = roomMessage.xmppId; |
499 |
if (!elementId.length) { |
500 |
elementId = roomMessage.uniqueId; |
501 |
} |
502 |
NSXMLElement *body = [NSXMLElement elementWithName:@"body" stringValue:roomMessage.text]; |
503 |
// type=groupchat and to=room.full are set inside XMPPRoom.sendMessage |
504 |
XMPPMessage *message = [XMPPMessage messageWithType:nil elementID:roomMessage.xmppId child:body]; |
505 |
[message addReceiptRequest]; |
506 |
[self sendMessage:message]; |
507 |
} |
508 |
@end |