From 0815f467846ec75b18379a8e447486f857fb09c3 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Sat, 28 Jan 2012 01:43:31 +0100 Subject: [PATCH] Decouple XMPPRoster and XMPPConnection --- src/XMPPConnection.h | 10 +- src/XMPPConnection.m | 28 +----- src/XMPPRoster.h | 41 +++++++-- src/XMPPRoster.m | 215 +++++++++++++++++++++++++------------------ tests/test.m | 24 +++-- 5 files changed, 178 insertions(+), 140 deletions(-) diff --git a/src/XMPPConnection.h b/src/XMPPConnection.h index 8cdad7f..91213ad 100644 --- a/src/XMPPConnection.h +++ b/src/XMPPConnection.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2010, 2011, 2012, Jonathan Schleifer - * Copyright (c) 2011, Florian Zeitz + * Copyright (c) 2011, 2012, Florian Zeitz * * https://webkeks.org/hg/objxmpp/ * @@ -29,8 +29,6 @@ @class XMPPMessage; @class XMPPPresence; @class XMPPAuthenticator; -@class XMPPRoster; -@class XMPPRosterItem; @class SSLSocket; @class XMPPMulticastDelegate; @@ -48,15 +46,12 @@ - (void)connectionWasAuthenticated: (XMPPConnection*)connection; - (void)connection: (XMPPConnection*)connection wasBoundToJID: (XMPPJID*)JID; -- (void)connectionDidReceiveRoster: (XMPPConnection*)connection; - (BOOL)connection: (XMPPConnection*)connection didReceiveIQ: (XMPPIQ*)iq; - (void)connection: (XMPPConnection*)connection didReceivePresence: (XMPPPresence*)presence; - (void)connection: (XMPPConnection*)connection didReceiveMessage: (XMPPMessage*)message; -- (void)connection: (XMPPConnection*)connection - didReceiveRosterItem: (XMPPRosterItem*)rosterItem; - (void)connectionWasClosed: (XMPPConnection*)connection; - (void)connectionWillUpgradeToTLS: (XMPPConnection*)connection; - (void)connectionDidUpgradeToTLS: (XMPPConnection*)connection; @@ -85,7 +80,6 @@ BOOL needsSession; BOOL encryptionRequired, encrypted; unsigned int lastID; - XMPPRoster *roster; } #ifdef OF_HAVE_PROPERTIES @@ -93,7 +87,6 @@ @property (copy) OFString *privateKeyFile, *certificateFile; @property (copy, readonly) XMPPJID *JID; @property (assign) uint16_t port; -@property (readonly, retain) XMPPRoster *roster; @property (readonly, retain, getter=socket) OFTCPSocket *sock; @property (assign) BOOL encryptionRequired; @property (readonly) BOOL encrypted; @@ -222,7 +215,6 @@ - (XMPPJID*)JID; - (void)setPort: (uint16_t)port; - (uint16_t)port; -- (XMPPRoster*)roster; - (void)XMPP_startStream; - (void)XMPP_handleStream: (OFXMLElement*)element; diff --git a/src/XMPPConnection.m b/src/XMPPConnection.m index 9ceea5a..6a30a69 100644 --- a/src/XMPPConnection.m +++ b/src/XMPPConnection.m @@ -1,6 +1,6 @@ /* * Copyright (c) 2010, 2011, 2012, Jonathan Schleifer - * Copyright (c) 2011, Florian Zeitz + * Copyright (c) 2011, 2012, Florian Zeitz * * https://webkeks.org/hg/objxmpp/ * @@ -47,8 +47,6 @@ #import "XMPPIQ.h" #import "XMPPMessage.h" #import "XMPPPresence.h" -#import "XMPPRoster.h" -#import "XMPPRosterItem.h" #import "XMPPMulticastDelegate.h" #import "XMPPExceptions.h" #import "namespaces.h" @@ -94,7 +92,6 @@ [delegates release]; [callbacks release]; [authModule release]; - [roster release]; [super dealloc]; } @@ -533,16 +530,12 @@ oldParser = parser; oldElementBuilder = elementBuilder; - [roster release]; - parser = [[OFXMLParser alloc] init]; [parser setDelegate: self]; elementBuilder = [[OFXMLElementBuilder alloc] init]; [elementBuilder setDelegate: self]; - roster = [[XMPPRoster alloc] initWithConnection: self]; - [sock writeFormat: @"\n" @" + * Copyright (c) 2012, Florian Zeitz * * https://webkeks.org/hg/objxmpp/ * @@ -22,25 +23,53 @@ #import -@class XMPPConnection; +#import "XMPPConnection.h" + @class XMPPRosterItem; @class XMPPIQ; +@class XMPPRoster; + +@protocol XMPPRosterDelegate +#ifndef XMPP_ROSTER_M + +#endif +#ifdef OF_HAVE_OPTIONAL_PROTOCOLS +@optional +#endif +- (void)rosterWasReceived: (XMPPRoster*)roster; +- (void)roster: (XMPPRoster*)roster + didReceiveRosterItem: (XMPPRosterItem*)rosterItem; +@end + @interface XMPPRoster: OFObject +#ifdef OF_HAVE_OPTIONAL_PROTOCOLS + +#endif { XMPPConnection *connection; OFMutableDictionary *rosterItems; - OFString *rosterID; + id delegate; } +#ifdef OF_HAVE_PROPERTIES +@property (assign) id delegate; +#endif + - initWithConnection: (XMPPConnection*)conn; -- (void)XMPP_addRosterItem: (XMPPRosterItem*)rosterItem; -- (void)XMPP_updateRosterItem: (XMPPRosterItem*)rosterItem; -- (void)XMPP_deleteRosterItem: (XMPPRosterItem*)rosterItem; - (OFDictionary*)rosterItems; -- (BOOL)handleIQ: (XMPPIQ*)iq; - (void)requestRoster; - (void)addRosterItem: (XMPPRosterItem*)rosterItem; - (void)updateRosterItem: (XMPPRosterItem*)rosterItem; - (void)deleteRosterItem: (XMPPRosterItem*)rosterItem; +- (void)setDelegate: (id )delegate; +- (id )delegate; +- (void)XMPP_addRosterItem: (XMPPRosterItem*)rosterItem; +- (void)XMPP_updateRosterItem: (XMPPRosterItem*)rosterItem; +- (void)XMPP_deleteRosterItem: (XMPPRosterItem*)rosterItem; +- (void)XMPP_handleInitialRoster: (XMPPIQ*)iq; +- (XMPPRosterItem*)XMPP_rosterItemWithXMLElement: (OFXMLElement*)element; +@end + +@interface OFObject (XMPPRosterDelegate) @end diff --git a/src/XMPPRoster.m b/src/XMPPRoster.m index 9a13ca3..54c9315 100644 --- a/src/XMPPRoster.m +++ b/src/XMPPRoster.m @@ -1,5 +1,6 @@ /* * Copyright (c) 2011, Jonathan Schleifer + * Copyright (c) 2012, Florian Zeitz * * https://webkeks.org/hg/objxmpp/ * @@ -24,6 +25,8 @@ # include "config.h" #endif +#define XMPP_ROSTER_M + #include #import "XMPPRoster.h" @@ -35,12 +38,14 @@ #import "namespaces.h" @implementation XMPPRoster -- initWithConnection: (XMPPConnection*)conn +- initWithConnection: (XMPPConnection*)connection_ { self = [super init]; @try { rosterItems = [[OFMutableDictionary alloc] init]; + connection = connection_; + [connection addDelegate: self]; } @catch (id e) { [self release]; @throw e; @@ -52,26 +57,10 @@ - (void)dealloc { [rosterItems release]; - [rosterID release]; [super dealloc]; } -- (void)XMPP_addRosterItem: (XMPPRosterItem*)rosterItem -{ - return [self XMPP_updateRosterItem: rosterItem]; -} - -- (void)XMPP_updateRosterItem: (XMPPRosterItem*)rosterItem -{ - [rosterItems setObject: rosterItem - forKey: [[rosterItem JID] bareJID]]; -} - -- (void)XMPP_deleteRosterItem: (XMPPRosterItem*)rosterItem -{ - [rosterItems removeObjectForKey: [[rosterItem JID] bareJID]]; -} - (OFDictionary*)rosterItems { @@ -82,25 +71,21 @@ { XMPPIQ *iq; - if (rosterID != nil) - assert(0); - - rosterID = [[connection generateStanzaID] retain]; iq = [XMPPIQ IQWithType: @"get" - ID: rosterID]; + ID: [connection generateStanzaID]]; [iq addChild: [OFXMLElement elementWithName: @"query" namespace: XMPP_NS_ROSTER]]; - [connection sendStanza: iq]; + [connection sendIQ: iq + withCallbackObject: self + selector: @selector(XMPP_handleInitialRoster:)]; } -- (BOOL)handleIQ: (XMPPIQ*)iq +- (BOOL)connection: (XMPPConnection*)connection_ + didReceiveIQ: (XMPPIQ*)iq { OFXMLElement *rosterElement; OFXMLElement *element; - XMPPRosterItem *rosterItem = nil; - OFString *subscription; - OFEnumerator *enumerator; - BOOL isPush = ![[iq ID] isEqual: rosterID]; + XMPPRosterItem *rosterItem; rosterElement = [iq elementForName: @"query" namespace: XMPP_NS_ROSTER]; @@ -108,76 +93,27 @@ if (rosterElement == nil) return NO; - if (isPush) { - if (![[iq type] isEqual: @"set"]) - return NO; - } else { - if (![[iq type] isEqual: @"result"]) - return NO; - } + if (![[iq type] isEqual: @"set"]) + return NO; - enumerator = [[rosterElement children] objectEnumerator]; - while ((element = [enumerator nextObject]) != nil) { - OFMutableArray *groups = [OFMutableArray array]; - OFEnumerator *groupEnumerator; - OFXMLElement *groupElement; + element = [rosterElement elementForName: @"item" + namespace: XMPP_NS_ROSTER]; - if (![[element name] isEqual: @"item"] || - ![[element namespace] isEqual: XMPP_NS_ROSTER]) - continue; + if (element != nil) { + rosterItem = [self XMPP_rosterItemWithXMLElement: element]; - rosterItem = [XMPPRosterItem rosterItem]; - [rosterItem setJID: [XMPPJID JIDWithString: - [[element attributeForName: @"jid"] stringValue]]]; - [rosterItem setName: - [[element attributeForName: @"name"] stringValue]]; - - subscription = [[element attributeForName: - @"subscription"] stringValue]; - - if (![subscription isEqual: @"none"] && - ![subscription isEqual: @"to"] && - ![subscription isEqual: @"from"] && - ![subscription isEqual: @"both"] && - (![subscription isEqual: @"remove"] || !isPush)) - subscription = @"none"; - - [rosterItem setSubscription: subscription]; - - groupEnumerator = [[element - elementsForName: @"group" - namespace: XMPP_NS_ROSTER] objectEnumerator]; - while ((groupElement = [groupEnumerator nextObject]) != nil) - [groups addObject: [groupElement stringValue]]; - - if ([groups count] > 0) - [rosterItem setGroups: groups]; - - if ([subscription isEqual: @"remove"]) + if ([[rosterItem subscription] isEqual: @"remove"]) [self XMPP_deleteRosterItem: rosterItem]; else [self XMPP_addRosterItem: rosterItem]; - if (isPush) { - SEL sel = @selector(connection:didReceiveRosterItem:); - - [[connection XMPP_delegates] - broadcastSelector: sel - forConnection: connection - withObject: rosterItem]; - } + if ([delegate respondsToSelector: + @selector(roster:didReceiveRosterItem:)]) + [delegate roster: self + didReceiveRosterItem: rosterItem]; } - if (isPush) { - [connection sendStanza: [iq resultIQ]]; - } else { - [[connection XMPP_delegates] - broadcastSelector: @selector(connectionDidReceiveRoster:) - forConnection: connection]; - - [rosterID release]; - rosterID = nil; - } + [connection_ sendStanza: [iq resultIQ]]; return YES; } @@ -235,4 +171,105 @@ [connection sendStanza: iq]; } + +- (void)setDelegate: (id )delegate_ +{ + delegate = (id )delegate_; +} + +- (id )delegate +{ + return delegate; +} + +- (void)XMPP_addRosterItem: (XMPPRosterItem*)rosterItem +{ + return [self XMPP_updateRosterItem: rosterItem]; +} + +- (void)XMPP_updateRosterItem: (XMPPRosterItem*)rosterItem +{ + [rosterItems setObject: rosterItem + forKey: [[rosterItem JID] bareJID]]; +} + +- (void)XMPP_deleteRosterItem: (XMPPRosterItem*)rosterItem +{ + [rosterItems removeObjectForKey: [[rosterItem JID] bareJID]]; +} + +- (XMPPRosterItem*)XMPP_rosterItemWithXMLElement: (OFXMLElement*)element +{ + OFString *subscription; + OFEnumerator *groupEnumerator; + OFXMLElement *groupElement; + OFMutableArray *groups = [OFMutableArray array]; + XMPPRosterItem *rosterItem = [XMPPRosterItem rosterItem]; + [rosterItem setJID: [XMPPJID JIDWithString: + [[element attributeForName: @"jid"] stringValue]]]; + [rosterItem setName: + [[element attributeForName: @"name"] stringValue]]; + + subscription = [[element attributeForName: + @"subscription"] stringValue]; + + if (![subscription isEqual: @"none"] && + ![subscription isEqual: @"to"] && + ![subscription isEqual: @"from"] && + ![subscription isEqual: @"both"] && + ![subscription isEqual: @"remove"]) + subscription = @"none"; + + [rosterItem setSubscription: subscription]; + + groupEnumerator = [[element + elementsForName: @"group" + namespace: XMPP_NS_ROSTER] objectEnumerator]; + while ((groupElement = [groupEnumerator nextObject]) != nil) + [groups addObject: [groupElement stringValue]]; + + if ([groups count] > 0) + [rosterItem setGroups: groups]; + + return rosterItem; +} + +- (void)XMPP_handleInitialRoster: (XMPPIQ*)iq +{ + OFXMLElement *rosterElement; + OFEnumerator *enumerator; + OFXMLElement *element; + XMPPRosterItem *rosterItem = nil; + + rosterElement = [iq elementForName: @"query" + namespace: XMPP_NS_ROSTER]; + + enumerator = [[rosterElement children] objectEnumerator]; + while ((element = [enumerator nextObject]) != nil) { + if (![[element name] isEqual: @"item"] || + ![[element namespace] isEqual: XMPP_NS_ROSTER]) + continue; + + rosterItem = [self XMPP_rosterItemWithXMLElement: element]; + + if ([[rosterItem subscription] isEqual: @"remove"]) + [self XMPP_deleteRosterItem: rosterItem]; + else + [self XMPP_addRosterItem: rosterItem]; + } + + if ([delegate respondsToSelector: @selector(rosterWasReceived:)]) + [delegate rosterWasReceived: self]; +} +@end + +@implementation OFObject (XMPPRosterDelegate) +- (void)rosterWasReceived: (XMPPRoster*)roster +{ +} + +- (void)roster: (XMPPRoster*)roster + didReceiveRosterItem: (XMPPRosterItem*)rosterItem +{ +} @end diff --git a/tests/test.m b/tests/test.m index 545b46d..5668a48 100644 --- a/tests/test.m +++ b/tests/test.m @@ -1,6 +1,6 @@ /* * Copyright (c) 2010, 2011, Jonathan Schleifer - * Copyright (c) 2011, Florian Zeitz + * Copyright (c) 2011, 2012, Florian Zeitz * * https://webkeks.org/hg/objxmpp/ * @@ -36,8 +36,12 @@ @interface AppDelegate: OFObject #ifdef OF_HAVE_OPTIONAL_PROTOCOLS - + #endif +{ + XMPPConnection * conn; + XMPPRoster *roster; +} @end OF_APPLICATION_DELEGATE(AppDelegate) @@ -45,7 +49,6 @@ OF_APPLICATION_DELEGATE(AppDelegate) @implementation AppDelegate - (void)applicationDidFinishLaunching { - XMPPConnection *conn; OFArray *arguments = [OFApplication arguments]; XMPPPresence *pres = [XMPPPresence presence]; @@ -91,7 +94,10 @@ OF_APPLICATION_DELEGATE(AppDelegate) [stanza ID]] isEqual: @"bob@localhost, alice@localhost, get, 42"])); conn = [[XMPPConnection alloc] init]; + roster = [[XMPPRoster alloc] initWithConnection: conn]; + [conn addDelegate: self]; + [roster setDelegate: self]; if ([arguments count] != 3) { of_log(@"Invalid count of command line arguments!"); @@ -133,14 +139,14 @@ OF_APPLICATION_DELEGATE(AppDelegate) { of_log(@"Bound to JID: %@", [jid fullJID]); - [[conn roster] requestRoster]; + [roster requestRoster]; } -- (void)connectionDidReceiveRoster: (XMPPConnection*)conn +- (void)rosterWasReceived: (XMPPRoster*)roster_ { XMPPPresence *pres; - of_log(@"Got roster: %@", [[conn roster] rosterItems]); + of_log(@"Got roster: %@", [roster_ rosterItems]); pres = [XMPPPresence presence]; [pres addPriority: 10]; @@ -160,10 +166,10 @@ OF_APPLICATION_DELEGATE(AppDelegate) #endif } -- (void)connectionDidUpgradeToTLS: (XMPPConnection*)conn +- (void)connectionDidUpgradeToTLS: (XMPPConnection*)conn_ { @try { - [conn checkCertificate]; + [conn_ checkCertificate]; } @catch (SSLInvalidCertificateException *e) { OFString *answer; [of_stdout writeString: @"Couldn't verify certificate: "]; @@ -175,7 +181,7 @@ OF_APPLICATION_DELEGATE(AppDelegate) } } -- (void)connection: (XMPPConnection*)conn +- (void)roster: (XMPPRoster*)roster_ didReceiveRosterItem: (XMPPRosterItem*)rosterItem { of_log(@"Got roster push: %@", rosterItem);