root/trunk/lilypad/Sources/LPGroupChat.m @ 147

Revision 147, 19.1 KB (checked in by jppavao, 5 years ago)

Whenever a MUC nickname is displayed to the user, whitespace characters at both of its ends are now replaced by some other visible graphical character. Closes #101.

Line 
1//
2//  LPGroupChat.m
3//  Lilypad
4//
5//      Copyright (C) 2006-2007 PT.COM,  All rights reserved.
6//      Author: Joao Pavao <jppavao@criticalsoftware.com>
7//
8//      For more information on licensing, read the README file.
9//      Para mais informações sobre o licenciamento, leia o ficheiro README.
10//
11
12#import "LPGroupChat.h"
13#import "LPAccount.h"
14#import "LPGroupChatContact.h"
15
16#warning Estes devem dar para apagar depois de tratar dos outros warnings
17#import "LPAccountsController.h"
18#import "LPAccount.h"
19#import "LPChatsManager.h"
20
21
22#define NSStringWithFormatIfNotEmpty(formatStr, argStr) \
23        ([argStr length] > 0 ? [NSString stringWithFormat:formatStr, argStr] : @"")
24
25
26@implementation LPGroupChat
27
28+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
29{
30        if ([key isEqualToString:@"nickname"] || [key isEqualToString:@"topic"]) {
31                // Avoid triggering change notifications on calls to -[LPGroupChat setNickname:] or -[LPGroupChat setTopic:]
32                return NO;
33        } else {
34                return YES;
35        }
36}
37
38+ groupChatForRoomWithJID:(NSString *)roomJID onAccount:(LPAccount *)account groupChatID:(int)ID nickname:(NSString *)nickname password:(NSString *)password
39{
40        return [[[[self class] alloc] initForRoomWithJID:roomJID onAccount:account groupChatID:ID nickname:nickname password:password] autorelease];
41}
42
43- initForRoomWithJID:(NSString *)roomJID onAccount:(LPAccount *)account groupChatID:(int)ID nickname:(NSString *)nickname password:(NSString *)password
44{
45        if (self = [super init]) {
46                m_ID = ID;
47                m_account = [account retain];
48                m_roomJID = [roomJID copy];
49                m_nickname = [nickname copy];
50                m_lastSetNickname = [nickname copy];
51                m_lastUsedPassword = [password copy];
52               
53                m_participants = [[NSMutableSet alloc] init];
54                m_participantsByNickname = [[NSMutableDictionary alloc] init];
55        }
56        return self;
57}
58
59- (void)dealloc
60{
61        [m_account release];
62        [m_roomJID release];
63        [m_nickname release];
64        [m_lastSetNickname release];
65        [m_lastUsedPassword release];
66        [m_topic release];
67        [m_participants release];
68        [m_participantsByNickname release];
69        [m_pendingInvites release];
70        [super dealloc];
71}
72
73- (id)delegate
74{
75        return m_delegate;
76}
77
78- (void)setDelegate:(id)delegate
79{
80        m_delegate = delegate;
81}
82
83- (void)retryJoinWithNickname:(NSString *)nickname password:(NSString *)password
84{
85        NSAssert( ![self isActive] , @"retryJoinWithPassword: shouldn't be invoked because we have already successfully joined the room!");
86       
87        if (![m_nickname isEqualToString:nickname]) {
88                [self willChangeValueForKey:@"nickname"];
89                [m_nickname release];
90                m_nickname = [nickname copy];
91                [self didChangeValueForKey:@"nickname"];
92        }
93        if (![m_lastSetNickname isEqualToString:nickname]) {
94                [self willChangeValueForKey:@"lastSetNickname"];
95                [m_lastSetNickname release];
96                m_lastSetNickname = [nickname copy];
97                [self didChangeValueForKey:@"lastSetNickname"];
98        }
99        if (![m_lastUsedPassword isEqualToString:password]) {
100                [self willChangeValueForKey:@"lastUsedPassword"];
101                [m_lastUsedPassword release];
102                m_lastUsedPassword = [password copy];
103                [self didChangeValueForKey:@"lastUsedPassword"];
104        }
105       
106        [LFAppController groupChatRetryJoin:[self ID] nickname:nickname password:password];
107}
108
109- (int)ID
110{
111        return m_ID;
112}
113
114- (LPAccount *)account
115{
116        return [[m_account retain] autorelease];
117}
118
119- (NSString *)roomJID
120{
121        return [[m_roomJID copy] autorelease];
122}
123
124- (NSString *)roomName
125{
126        return [m_roomJID JIDUsernameComponent];
127}
128
129- (NSString *)nickname
130{
131        return [[m_nickname copy] autorelease];
132}
133
134- (void)setNickname:(NSString *)newNick
135{
136        if (![m_lastSetNickname isEqualToString:newNick]) {
137                [self willChangeValueForKey:@"lastSetNickname"];
138                [m_lastSetNickname release];
139                m_lastSetNickname = [newNick copy];
140                [self didChangeValueForKey:@"lastSetNickname"];
141        }
142       
143        [LFAppController groupChatSetNicknameOnRoom:[self ID] to:newNick];
144}
145
146- (NSString *)lastSetNickname
147{
148        return [[m_lastSetNickname copy] autorelease];
149}
150
151- (NSString *)lastUsedPassword
152{
153        return [[m_lastUsedPassword copy] autorelease];
154}
155
156- (BOOL)isActive
157{
158        return m_isActive;
159}
160
161- (NSString *)topic
162{
163        return [[m_topic copy] autorelease];
164}
165
166- (void)setTopic:(NSString *)newTopic
167{
168        [LFAppController groupChatSetTopicOnRoom:[self ID] to:newTopic];
169}
170
171- (void)inviteJID:(NSString *)jid withReason:(NSString *)reason
172{
173        if ([self isActive]) {
174                [LFAppController groupChatInvite:jid
175                                                                        room:[self roomJID]
176                                                         accountUUID:[[self account] UUID]
177                                                                  reason:reason];
178               
179                if ([m_delegate respondsToSelector:@selector(groupChat:didInviteJID:withReason:)]) {
180                        [m_delegate groupChat:self didInviteJID:jid withReason:reason];
181                }
182        }
183        else {
184                if (m_pendingInvites == nil)
185                        m_pendingInvites = [[NSMutableArray alloc] init];
186               
187                // Store it in the list of pending invitations
188                [m_pendingInvites addObject:[NSDictionary dictionaryWithObjectsAndKeys:
189                        jid, @"JID", reason, @"Reason", nil]];
190        }
191}
192
193- (LPGroupChatContact *)myGroupChatContact
194{
195        return [[m_myGroupChatContact retain] autorelease];
196}
197
198- (NSSet *)participants
199{
200        return [[m_participants retain] autorelease];
201}
202
203- (void)reloadRoomConfigurationForm
204{
205        [LFAppController fetchGroupChatConfigurationForm:[self ID]];
206}
207
208- (void)submitRoomConfigurationForm:(NSString *)configurationXMLForm
209{
210        [LFAppController submitGroupChatConfigurationForm:[self ID] :configurationXMLForm];
211}
212
213- (void)sendPlainTextMessage:(NSString *)message
214{
215        [LFAppController groupChatMessageSend:[self ID] plain:message];
216}
217
218- (void)endGroupChat
219{
220        [[LPChatsManager chatsManager] endGroupChat:self];
221}
222
223#pragma mark -
224
225- (void)p_addParticipant:(LPGroupChatContact *)contact
226{
227        NSSet *changeSet = [NSSet setWithObject:contact];
228       
229        [self willChangeValueForKey:@"participants" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changeSet];
230        [m_participants addObject:contact];
231        [self didChangeValueForKey:@"participants" withSetMutation:NSKeyValueUnionSetMutation usingObjects:changeSet];
232       
233        [m_participantsByNickname setObject:contact forKey:[contact nickname]];
234}
235
236- (void)p_removeParticipant:(LPGroupChatContact *)contact
237{
238        NSSet *changeSet = [NSSet setWithObject:contact];
239       
240        [self willChangeValueForKey:@"participants" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changeSet];
241        [m_participants removeObject:contact];
242        [self didChangeValueForKey:@"participants" withSetMutation:NSKeyValueMinusSetMutation usingObjects:changeSet];
243       
244        [m_participantsByNickname removeObjectForKey:[contact nickname]];
245       
246        if (contact == m_myGroupChatContact)
247                m_myGroupChatContact = nil;
248}
249
250- (LPGroupChatContact *)p_participantWithNickname:(NSString *)nickname
251{
252        return [m_participantsByNickname objectForKey:nickname];
253}
254
255- (void)p_updateParticipantNicknameFrom:(NSString *)oldNickname to:(NSString *)newNickname
256{
257        LPGroupChatContact *contact = [m_participantsByNickname objectForKey:oldNickname];
258       
259        [m_participantsByNickname removeObjectForKey:oldNickname];
260        [contact handleChangedNickname:newNickname];
261        [m_participantsByNickname setObject:contact forKey:newNickname];
262}
263
264- (void)p_doEmitUserSystemMessages
265{
266        m_emitUserSystemMessages = YES;
267}
268
269
270#pragma mark -
271
272- (void)handleDidJoinGroupChatWithJID:(NSString *)roomJID nickname:(NSString *)nickname
273{
274        [self willChangeValueForKey:@"active"];
275        m_isActive = YES;
276        [self didChangeValueForKey:@"active"];
277       
278        if (![m_nickname isEqualToString:nickname]) {
279                [self willChangeValueForKey:@"nickname"];
280                [m_nickname release];
281                m_nickname = [nickname copy];
282                [self didChangeValueForKey:@"nickname"];
283        }
284       
285        [self performSelector:@selector(p_doEmitUserSystemMessages) withObject:nil afterDelay:5.0];
286       
287        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
288                [m_delegate groupChat:self didReceiveSystemMessage:NSLocalizedString(@"Chat-room was joined successfully.",
289                                                                                                                                                         @"Chat room system message")];
290        }
291       
292        // Are there any pending invitations waiting to be sent?
293        NSEnumerator *inviteEnum = [m_pendingInvites objectEnumerator];
294        NSDictionary *inviteDict;
295        while (inviteDict = [inviteEnum nextObject]) {
296                [self inviteJID:[inviteDict objectForKey:@"JID"] withReason:[inviteDict objectForKey:@"Reason"]];
297        }
298        [m_pendingInvites release]; m_pendingInvites = nil;
299}
300
301- (void)handleDidLeaveGroupChat
302{
303        [self willChangeValueForKey:@"active"];
304        m_isActive = NO;
305        [self didChangeValueForKey:@"active"];
306       
307        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(p_doEmitUserSystemMessages) object:nil];
308}
309
310- (void)handleDidCreateGroupChat
311{
312        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
313                [m_delegate groupChat:self didReceiveSystemMessage:NSLocalizedString(@"Chat-room was created.",
314                                                                                                                                                         @"Chat room system message")];
315        }
316}
317
318- (void)handleDidDestroyGroupChatWithReason:(NSString *)reason alternateRoomJID:(NSString *)alternateRoomJID
319{
320#warning This notification could be handled in a more user-friendly way. Simply showing a chat-room JID to the user is lame!
321       
322        NSString *sysMsg = ( ([alternateRoomJID length] > 0) ?
323                                                 [NSString stringWithFormat:
324                                                         NSLocalizedString(@"Chat-room was destroyed. Please join the alternative chat-room at \"%@\".",
325                                                                                           @"Chat room system message"), alternateRoomJID] :
326                                                 NSLocalizedString(@"Chat-room was destroyed.", @"Chat room system message") );
327       
328        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
329                [m_delegate groupChat:self didReceiveSystemMessage:sysMsg];
330        }
331}
332
333- (void)handleContactDidJoinGroupChatWithNickname:(NSString *)nickname JID:(NSString *)jid role:(NSString *)role affiliation:(NSString *)affiliation
334{
335        LPGroupChatContact *newContact = [LPGroupChatContact groupChatContactWithNickame:nickname realJID:jid
336                                                                                                                                                                role:role affiliation:affiliation
337                                                                                                                                                   groupChat:self];
338        [self p_addParticipant:newContact];
339       
340        if ([m_nickname isEqualToString:nickname]) {
341                [self willChangeValueForKey:@"myGroupChatContact"];
342                m_myGroupChatContact = newContact;
343                [self didChangeValueForKey:@"myGroupChatContact"];
344        }
345       
346       
347        if (m_emitUserSystemMessages) {
348                // Send a system message to our delegate
349                NSString *sysMsg = [NSString stringWithFormat:
350                        NSLocalizedString(@"\"%@\"%@ has joined the chat. <%@, %@>", @"Chat room system message"),
351                        [newContact userPresentableNickname],
352                        NSStringWithFormatIfNotEmpty(@" (%@)", jid),
353                        role, affiliation];
354               
355                if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
356                        [m_delegate groupChat:self didReceiveSystemMessage:sysMsg];
357                }
358        }
359}
360
361- (void)handleContactWithNickname:(NSString *)nickname didChangeRoleTo:(NSString *)role affiliationTo:(NSString *)affiliation
362{
363        LPGroupChatContact *contact = [self p_participantWithNickname:nickname];
364        NSString *jid = [contact realJID];
365       
366        [contact handleChangedRole:role orAffiliation:affiliation];
367       
368        if (m_emitUserSystemMessages) {
369                // Send a system message to our delegate
370                NSString *sysMsg = [NSString stringWithFormat:
371                        NSLocalizedString(@"\"%@\"%@ is now <%@, %@>.", @"Chat room system message"),
372                        [contact userPresentableNickname],
373                        NSStringWithFormatIfNotEmpty(@" (%@)", jid),
374                        role, affiliation];
375               
376                if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
377                        [m_delegate groupChat:self didReceiveSystemMessage:sysMsg];
378                }
379        }
380}
381
382- (void)handleContactWithNickname:(NSString *)nickname didChangeStatusTo:(LPStatus)status statusMessageTo:(NSString *)statusMsg
383{
384        [[self p_participantWithNickname:nickname] handleChangedStatus:status statusMessage:statusMsg];
385}
386
387- (void)handleContactWithNickname:(NSString *)nickname didChangeNicknameFrom:(NSString *)old_nickname to:(NSString *)new_nickname
388{
389        NSString *oldPresentableNickname = [[self p_participantWithNickname:old_nickname] userPresentableNickname];
390        [self p_updateParticipantNicknameFrom:old_nickname to:new_nickname];
391        NSString *newPresentableNickname = [[self p_participantWithNickname:new_nickname] userPresentableNickname];
392       
393        if ([m_nickname isEqualToString:nickname]) {
394                [self willChangeValueForKey:@"nickname"];
395                [m_nickname release];
396                m_nickname = [new_nickname copy];
397                [self didChangeValueForKey:@"nickname"];
398        }
399       
400        // Send a system message to our delegate
401        NSString *sysMsg = [NSString stringWithFormat:
402                NSLocalizedString(@"\"%@\" is now known as \"%@\".", @"Chat room system message"),
403                oldPresentableNickname, newPresentableNickname];
404       
405        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
406                [m_delegate groupChat:self didReceiveSystemMessage:sysMsg];
407        }
408}
409
410- (void)handleContactWithNickname:(NSString *)nickname wasKickedBy:(NSString *)actor reason:(NSString *)reason
411{
412        LPGroupChatContact *contact = [self p_participantWithNickname:nickname];
413        NSString *userPresentableNickname = [contact userPresentableNickname];
414        NSString *jid = [contact realJID];
415       
416        [self p_removeParticipant:contact];
417       
418        // Send a system message to our delegate
419        NSString *sysMsg = [NSString stringWithFormat:
420                NSLocalizedString(@"\"%@\"%@ was kicked%@%@.", @"Chat room system message"),
421                userPresentableNickname,
422                NSStringWithFormatIfNotEmpty(@" (%@)", jid),
423                NSStringWithFormatIfNotEmpty(@" by \"%@\"", actor),
424                NSStringWithFormatIfNotEmpty(@" (reason: %@)", reason)];
425       
426        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
427                [m_delegate groupChat:self didReceiveSystemMessage:sysMsg];
428        }
429       
430       
431        if ([m_nickname isEqualToString:nickname])
432                ; // Do something different if we're the one being kicked?
433}
434
435- (void)handleContactWithNickname:(NSString *)nickname wasBannedBy:(NSString *)actor reason:(NSString *)reason
436{
437        LPGroupChatContact *contact = [self p_participantWithNickname:nickname];
438        NSString *userPresentableNickname = [contact userPresentableNickname];
439        NSString *jid = [contact realJID];
440       
441        [self p_removeParticipant:contact];
442       
443        // Send a system message to our delegate
444        NSString *sysMsg = [NSString stringWithFormat:
445                NSLocalizedString(@"\"%@\"%@ was banned%@%@.", @"Chat room system message"),
446                userPresentableNickname,
447                NSStringWithFormatIfNotEmpty(@" (%@)", jid),
448                NSStringWithFormatIfNotEmpty(@" by \"%@\"", actor),
449                NSStringWithFormatIfNotEmpty(@" (reason: %@)", reason)];
450       
451        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
452                [m_delegate groupChat:self didReceiveSystemMessage:sysMsg];
453        }
454       
455       
456        if ([m_nickname isEqualToString:nickname])
457                ; // Do something different if we're the one being banned?
458}
459
460- (void)handleContactWithNickname:(NSString *)nickname wasRemovedFromChatBy:(NSString *)actor reason:(NSString *)reason dueTo:(NSString *)dueTo
461{
462        LPGroupChatContact *contact = [self p_participantWithNickname:nickname];
463        NSString *userPresentableNickname = [contact userPresentableNickname];
464        LPGroupChatContact *actorContact = [self p_participantWithNickname:actor];
465        NSString *actorPresentableNickname = [actorContact userPresentableNickname];
466        NSString *jid = [contact realJID];
467       
468        [self p_removeParticipant:contact];
469       
470        // Send a system message to our delegate
471        NSString *sysMsg = [NSString stringWithFormat:
472                NSLocalizedString(@"\"%@\"%@ was removed from the room%@ (due to: \"%@\"%@).", @"Chat room system message"),
473                userPresentableNickname,
474                NSStringWithFormatIfNotEmpty(@" (%@)", jid),
475                NSStringWithFormatIfNotEmpty(@" by \"%@\"", actorPresentableNickname),
476                dueTo,
477                NSStringWithFormatIfNotEmpty(@", reason: %@", reason)];
478       
479        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
480                [m_delegate groupChat:self didReceiveSystemMessage:sysMsg];
481        }
482       
483       
484        if ([m_nickname isEqualToString:nickname])
485                ; // Do something different if we're the one being removed?
486}
487
488- (void)handleContactWithNickname:(NSString *)nickname didLeaveWithStatusMessage:(NSString *)status
489{
490        LPGroupChatContact *contact = [self p_participantWithNickname:nickname];
491        NSString *userPresentableNickname = [contact userPresentableNickname];
492        NSString *jid = [contact realJID];
493       
494        [self p_removeParticipant:contact];
495       
496        if (m_emitUserSystemMessages) {
497                // Send a system message to our delegate
498                NSString *sysMsg = [NSString stringWithFormat:
499                        NSLocalizedString(@"\"%@\"%@ has left the room%@.", @"Chat room system message"),
500                        userPresentableNickname,
501                        NSStringWithFormatIfNotEmpty(@" (%@)", jid),
502                        NSStringWithFormatIfNotEmpty(@" (%@)", status)];
503               
504                if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
505                        [m_delegate groupChat:self didReceiveSystemMessage:sysMsg];
506                }
507        }
508       
509       
510        if ([m_nickname isEqualToString:nickname])
511                ; // Do something different if we're the one leaving?
512}
513
514- (void)handleGroupChatErrorWithCode:(int)code message:(NSString *)msg
515{
516        // Send a system message to our delegate
517        NSString *sysMsg = [NSString stringWithFormat:
518                NSLocalizedString(@"Chat room error: %@ (%d)", @"Chat room system message"),
519                msg, code];
520       
521       
522        if (code == 401) {
523                // Password required or wrong password was provided
524                if ([m_delegate respondsToSelector:@selector(groupChat:unableToProceedDueToWrongPasswordWithErrorMessage:)]) {
525                        [m_delegate groupChat:self unableToProceedDueToWrongPasswordWithErrorMessage:sysMsg];
526                }
527        }
528        else if (code == 409) {
529                // Nickname is already taken
530                if ([m_delegate respondsToSelector:@selector(groupChat:unableToProceedDueToNicknameAlreadyInUseWithErrorMessage:)]) {
531                        [m_delegate groupChat:self unableToProceedDueToNicknameAlreadyInUseWithErrorMessage:sysMsg];
532                }
533        }
534        else {
535                // Some other error
536                if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
537                        [m_delegate groupChat:self didReceiveSystemMessage:sysMsg];
538                }
539        }
540}
541
542- (void)handleTopicChangedTo:(NSString *)newTopic by:(NSString *)actor
543{
544        [self willChangeValueForKey:@"topic"];
545        [m_topic release];
546        m_topic = [newTopic copy];
547        [self didChangeValueForKey:@"topic"];
548       
549        // Send a system message to our delegate
550        LPGroupChatContact *contact = [self p_participantWithNickname:actor];
551        NSString *userPresentableNickname = [contact userPresentableNickname];
552        NSString *jid = [contact realJID];
553       
554        NSString *sysMsg;
555       
556        if ([actor length] > 0) {
557                sysMsg = [NSString stringWithFormat:
558                        NSLocalizedString(@"\"%@\"%@ has changed the topic to: \"%@\"", @"Chat room system message"),
559                        userPresentableNickname,
560                        NSStringWithFormatIfNotEmpty(@" (%@)", jid),
561                        newTopic];
562        }
563        else {
564                sysMsg = [NSString stringWithFormat:
565                        NSLocalizedString(@"The topic has been set to: \"%@\"", @"Chat room system message"),
566                        newTopic];
567        }
568       
569        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveSystemMessage:)]) {
570                [m_delegate groupChat:self didReceiveSystemMessage:sysMsg];
571        }
572}
573
574- (void)handleReceivedMessageFromNickname:(NSString *)nickname plainBody:(NSString *)plainBody
575{
576        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveMessage:fromContact:)]) {
577                LPGroupChatContact *contact = [m_participantsByNickname objectForKey:nickname];
578                [m_delegate groupChat:self didReceiveMessage:plainBody fromContact:contact];
579        }
580}
581
582- (void)handleReceivedConfigurationForm:(NSString *)configForm errorMessage:(NSString *)errorMsg
583{
584        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveRoomConfigurationForm:errorMessage:)]) {
585                [m_delegate groupChat:self didReceiveRoomConfigurationForm:configForm errorMessage:errorMsg];
586        }
587
588}
589
590- (void)handleResultOfConfigurationModification:(BOOL)succeeded errorMessage:(NSString *)errorMsg
591{
592        if ([m_delegate respondsToSelector:@selector(groupChat:didReceiveResultOfRoomConfigurationModification:errorMessage:)]) {
593                [m_delegate groupChat:self didReceiveResultOfRoomConfigurationModification:succeeded errorMessage:errorMsg];
594        }
595       
596}
597
598@end
Note: See TracBrowser for help on using the browser.