@@ -1,7 +1,7 @@ /* - * Copyright (c) 2010, 2011, Jonathan Schleifer + * Copyright (c) 2010, 2011, 2012, Jonathan Schleifer * Copyright (c) 2011, Florian Zeitz * * https://webkeks.org/hg/objxmpp/ * * Permission to use, copy, modify, and/or distribute this software for any @@ -47,10 +47,11 @@ #import "XMPPIQ.h" #import "XMPPMessage.h" #import "XMPPPresence.h" #import "XMPPRoster.h" #import "XMPPRosterItem.h" +#import "XMPPMulticastDelegate.h" #import "XMPPExceptions.h" #import "namespaces.h" @implementation XMPPConnection + connection @@ -65,10 +66,11 @@ @try { sock = [[OFTCPSocket alloc] init]; port = 5222; encrypted = NO; streamOpen = NO; + delegates = [[XMPPMulticastDelegate alloc] init]; callbacks = [[OFMutableDictionary alloc] init]; } @catch (id e) { [self release]; @throw e; } @@ -87,10 +89,11 @@ [certificateFile release]; [server release]; [domain release]; [resource release]; [JID release]; + [delegates release]; [callbacks release]; [authModule release]; [roster release]; [super dealloc]; @@ -302,13 +305,13 @@ } - (void)parseBuffer: (const char*)buffer withLength: (size_t)length { - if (length < 1 && [delegate respondsToSelector: - @selector(connectionWasClosed:)]) { - [delegate connectionWasClosed: self]; + if (length < 1) { + [delegates broadcastSelector: @selector(connectionWasClosed:) + forConnection: self]; return; } [parser parseBuffer: buffer withLength: length]; @@ -373,53 +376,52 @@ reason: @"No matching identifier"]; } - (void)sendStanza: (OFXMLElement*)element { - if ([delegate respondsToSelector: - @selector(connection:didSendElement:)]) - [delegate connection: self - didSendElement: element]; + [delegates broadcastSelector: @selector(connection:didSendElement:) + forConnection: self + withObject: element]; [sock writeString: [element XMLString]]; } - (void)sendIQ: (XMPPIQ*)iq withCallbackObject: (id)object selector: (SEL)selector { - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - @try { - if (![iq ID]) - [iq setID: [self generateStanzaID]]; - - [callbacks setObject: [XMPPCallback - callbackWithCallbackObject: object - selector: selector] - forKey: [iq ID]]; - } @finally { - [pool release]; - } + OFAutoreleasePool *pool; + XMPPCallback *callback; + + if (![iq ID]) + [iq setID: [self generateStanzaID]]; + + pool = [[OFAutoreleasePool alloc] init]; + callback = [XMPPCallback callbackWithCallbackObject: object + selector: selector]; + [callbacks setObject: callback + forKey: [iq ID]]; + [pool release]; [self sendStanza: iq]; } #ifdef OF_HAVE_BLOCKS - (void)sendIQ: (XMPPIQ*)iq - withCallbackBlock: (xmpp_callback_block_t)callback; -{ - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - @try { - if (![iq ID]) - [iq setID: [self generateStanzaID]]; - - [callbacks setObject: [XMPPCallback - callbackWithCallbackBlock: callback] - forKey: [iq ID]]; - } @finally { - [pool release]; - } + withCallbackBlock: (xmpp_callback_block_t)block; +{ + OFAutoreleasePool *pool; + XMPPCallback *callback; + + if (![iq ID]) + [iq setID: [self generateStanzaID]]; + + pool = [[OFAutoreleasePool alloc] init]; + callback = [XMPPCallback callbackWithCallbackBlock: block]; + [callbacks setObject: callback + forKey: [iq ID]]; + [pool release]; [self sendStanza: iq]; } #endif @@ -484,14 +486,13 @@ [element setDefaultNamespace: XMPP_NS_CLIENT]; [element setPrefix: @"stream" forNamespace: XMPP_NS_STREAM]; - if ([delegate respondsToSelector: - @selector(connection:didReceiveElement:)]) - [delegate connection: self - didReceiveElement: element]; + [delegates broadcastSelector: @selector(connection:didReceiveElement:) + forConnection: self + withObject: element]; if ([[element namespace] isEqual: XMPP_NS_CLIENT]) [self XMPP_handleStanza: element]; if ([[element namespace] isEqual: XMPP_NS_STREAM]) @@ -690,25 +691,25 @@ { if ([[element name] isEqual: @"proceed"]) { /* FIXME: Catch errors here */ SSLSocket *newSock; - if ([delegate respondsToSelector: - @selector(connectionWillUpgradeToTLS:)]) - [delegate connectionWillUpgradeToTLS: self]; + [delegates broadcastSelector: @selector( + connectionWillUpgradeToTLS:) + forConnection: self]; newSock = [[SSLSocket alloc] initWithSocket: sock privateKeyFile: privateKeyFile certificateFile: certificateFile]; [sock release]; sock = newSock; encrypted = YES; - if ([delegate respondsToSelector: - @selector(connectionDidUpgradeToTLS:)]) - [delegate connectionDidUpgradeToTLS: self]; + [delegates broadcastSelector: @selector( + connectionDidUpgradeToTLS:) + forConnection: self]; /* Stream restart */ [self XMPP_startStream]; return; @@ -746,13 +747,13 @@ if ([[element name] isEqual: @"success"]) { [authModule continueWithData: [OFDataArray dataArrayWithBase64EncodedString: [element stringValue]]]; - if ([delegate respondsToSelector: - @selector(connectionWasAuthenticated:)]) - [delegate connectionWasAuthenticated: self]; + [delegates broadcastSelector: @selector( + connectionWWasAuthenticated:) + forConnection: self]; /* Stream restart */ [self XMPP_startStream]; return; @@ -784,13 +785,14 @@ if ([iq elementForName: @"query" namespace: XMPP_NS_ROSTER]) if ([roster handleIQ: iq]) return; - if ([delegate respondsToSelector: @selector(connection:didReceiveIQ:)]) - handled = [delegate connection: self - didReceiveIQ: iq]; + handled = [delegates broadcastSelector: @selector( + connection:didReceiveIQ:) + forConnection: self + withObject: iq]; if (!handled && ![[iq type] isEqual: @"error"] && ![[iq type] isEqual: @"result"]) { [self sendStanza: [iq errorIQWithType: @"cancel" condition: @"service-unavailable"]]; @@ -797,22 +799,20 @@ } } - (void)XMPP_handleMessage: (XMPPMessage*)message { - if ([delegate respondsToSelector: - @selector(connection:didReceiveMessage:)]) - [delegate connection: self - didReceiveMessage: message]; + [delegates broadcastSelector: @selector(connection:didReceiveMessage:) + forConnection: self + withObject: message]; } - (void)XMPP_handlePresence: (XMPPPresence*)presence { - if ([delegate respondsToSelector: - @selector(connection:didReceivePresence:)]) - [delegate connection: self - didReceivePresence: presence]; + [delegates broadcastSelector: @selector(connection:didReceivePresence:) + forConnection: self + withObject: presence]; } - (void)XMPP_handleFeatures: (OFXMLElement*)element { OFXMLElement *starttls = [element elementForName: @"starttls" @@ -977,13 +977,13 @@ if (needsSession) { [self XMPP_sendSession]; return; } - if ([delegate respondsToSelector: @selector(connection:wasBoundToJID:)]) - [delegate connection: self - wasBoundToJID: JID]; + [delegates broadcastSelector: @selector(connection:wasBoundToJID:) + forConnection: self + withObject: JID]; } - (void)XMPP_sendSession { XMPPIQ *iq; @@ -1000,13 +1000,13 @@ - (void)XMPP_handleSession: (XMPPIQ*)iq { if (![[iq type] isEqual: @"result"]) assert(0); - if ([delegate respondsToSelector: @selector(connection:wasBoundToJID:)]) - [delegate connection: self - wasBoundToJID: JID]; + [delegates broadcastSelector: @selector(connection:wasBoundToJID:) + forConnection: self + withObject: JID]; } - (OFString*)XMPP_IDNAToASCII: (OFString*)domain_ { OFString *ret; @@ -1043,18 +1043,23 @@ - (uint16_t)port { return port; } -- (void)setDelegate: (id )delegate_ +- (void)addDelegate: (id )delegate +{ + [delegates addDelegate: delegate]; +} + +- (void)removeDelegate: (id )delegate { - delegate = (id )delegate_; + [delegates removeDelegate: delegate]; } -- (id )delegate +- (XMPPMulticastDelegate*)XMPP_delegates { - return delegate; + return delegates; } - (XMPPRoster*)roster { return [[roster retain] autorelease];