From e71c601cbe4df77f8dca934ff845ccfd4c5f4292 Mon Sep 17 00:00:00 2001 From: Jonathan Schleifer Date: Mon, 21 Mar 2011 20:51:17 +0100 Subject: [PATCH] Request and handle roster. --- src/Makefile | 2 +- src/XMPPConnection.h | 10 ++++- src/XMPPConnection.m | 103 ++++++++++++++++++++++++++++++++++++++----- tests/Makefile | 2 +- tests/test.m | 9 +++- 5 files changed, 111 insertions(+), 15 deletions(-) diff --git a/src/Makefile b/src/Makefile index 3202eac..5516e58 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ all: - objfw-compile -Wall --lib 0.0 -o objxmpp *.m \ + objfw-compile -Wall -g --lib 0.0 -o objxmpp *.m \ `pkg-config --cflags --libs libidn` -lobjgnutls clean: diff --git a/src/XMPPConnection.h b/src/XMPPConnection.h index 7c673d3..470cdd6 100644 --- a/src/XMPPConnection.h +++ b/src/XMPPConnection.h @@ -35,6 +35,7 @@ - (void)connectionWasAuthenticated: (XMPPConnection*)conn; - (void)connection: (XMPPConnection*)conn wasBoundToJID: (XMPPJID*)jid; +- (void)connectionDidReceiveRoster: (XMPPConnection*)conn; - (void)connection: (XMPPConnection*)conn didReceiveIQ: (XMPPIQ*)iq; - (void)connection: (XMPPConnection*)conn @@ -62,7 +63,8 @@ XMPPAuthenticator *authModule; BOOL needsSession; unsigned int lastID; - OFString *bindID, *sessionID; + OFString *bindID, *sessionID, *rosterID; + OFMutableDictionary *roster; } @property (copy) OFString *username, *password, *server, *resource; @@ -70,6 +72,7 @@ @property (assign) uint16_t port; @property (assign) BOOL useTLS; @property (retain) id delegate; +@property (copy, readonly) OFDictionary *roster; /** * Connects to the XMPP service. @@ -94,4 +97,9 @@ * \return A new, generated, unique stanza ID. */ - (OFString*)generateStanzaID; + +/** + * Requests the roster. + */ +- (void)requestRoster; @end diff --git a/src/XMPPConnection.m b/src/XMPPConnection.m index 6b3c9f1..acd8ec5 100644 --- a/src/XMPPConnection.m +++ b/src/XMPPConnection.m @@ -40,6 +40,7 @@ #define NS_BIND @"urn:ietf:params:xml:ns:xmpp-bind" #define NS_CLIENT @"jabber:client" +#define NS_ROSTER @"jabber:iq:roster" #define NS_SASL @"urn:ietf:params:xml:ns:xmpp-sasl" #define NS_STARTTLS @"urn:ietf:params:xml:ns:xmpp-tls" #define NS_SESSION @"urn:ietf:params:xml:ns:xmpp-session" @@ -56,24 +57,32 @@ - (void)XMPP_handleResourceBind: (XMPPIQ*)iq; - (void)XMPP_sendSession; - (void)XMPP_handleSession: (XMPPIQ*)iq; +- (void)XMPP_handleRoster: (XMPPIQ*)iq; @end @implementation XMPPConnection -@synthesize JID, port, useTLS, delegate; +@synthesize JID, port, useTLS, delegate, roster; - init { self = [super init]; - sock = [[OFTCPSocket alloc] init]; - parser = [[OFXMLParser alloc] init]; - elementBuilder = [[OFXMLElementBuilder alloc] init]; + @try { + sock = [[OFTCPSocket alloc] init]; + parser = [[OFXMLParser alloc] init]; + elementBuilder = [[OFXMLElementBuilder alloc] init]; - port = 5222; - useTLS = YES; + port = 5222; + useTLS = YES; - parser.delegate = self; - elementBuilder.delegate = self; + parser.delegate = self; + elementBuilder.delegate = self; + + roster = [[OFMutableDictionary alloc] init]; + } @catch (id e) { + [self release]; + @throw e; + } return self; } @@ -92,6 +101,8 @@ [authModule release]; [bindID release]; [sessionID release]; + [rosterID release]; + [roster release]; [super dealloc]; } @@ -385,16 +396,21 @@ - (void)XMPP_handleIQ: (XMPPIQ*)iq { - if ([iq.ID isEqual: bindID] && [iq.type isEqual: @"result"]) { + if ([iq.ID isEqual: bindID]) { [self XMPP_handleResourceBind: iq]; return; } - if ([iq.ID isEqual: sessionID] && [iq.type isEqual: @"result"]) { + if ([iq.ID isEqual: sessionID]) { [self XMPP_handleSession: iq]; return; } + if ([iq.ID isEqual: rosterID]) { + [self XMPP_handleRoster: iq]; + return; + } + if ([delegate respondsToSelector: @selector(connection:didReceiveIQ:)]) [delegate connection: self didReceiveIQ: iq]; @@ -508,9 +524,14 @@ - (void)XMPP_handleResourceBind: (XMPPIQ*)iq { - OFXMLElement *bindElem = iq.children.firstObject; + OFXMLElement *bindElem; OFXMLElement *jidElem; + if (![iq.type isEqual: @"result"]) + assert(0); + + bindElem = iq.children.firstObject; + if (![bindElem.name isEqual: @"bind"] || ![bindElem.namespace isEqual: NS_BIND]) assert(0); @@ -556,4 +577,64 @@ [sessionID release]; sessionID = nil; } + +- (void)requestRoster +{ + XMPPIQ *iq; + + if (rosterID != nil) + assert(0); + + rosterID = [[self generateStanzaID] retain]; + iq = [XMPPIQ IQWithType: @"get" + ID: rosterID]; + [iq addChild: [OFXMLElement elementWithName: @"query" + namespace: NS_ROSTER]]; + [self sendStanza: iq]; +} + +- (void)XMPP_handleRoster: (XMPPIQ*)iq +{ + OFXMLElement *rosterElem; + + if (![iq.type isEqual: @"result"]) + assert(0); + + rosterElem = iq.children.firstObject; + + if (![rosterElem.name isEqual: @"query"] || + ![rosterElem.namespace isEqual: NS_ROSTER]) + assert(0); + + for (OFXMLElement *elem in rosterElem.children) { + OFString *group; + OFMutableArray *rosterGroup; + + if (![elem.name isEqual: @"item"] || + ![elem.ns isEqual: NS_ROSTER]) + continue; + + group = [[elem + elementsForName: @"group" + namespace: NS_ROSTER].firstObject stringValue]; + + if (group == nil) + group = @""; + + if ((rosterGroup = [roster objectForKey: group]) == nil) { + rosterGroup = [OFMutableArray array]; + [roster setObject: rosterGroup + forKey: group]; + } + + [rosterGroup addObject: elem]; + } + + if ([delegate respondsToSelector: + @selector(connectionDidReceiveRoster:)]) + [delegate connectionDidReceiveRoster: self]; + + [rosterID release]; + rosterID = nil; +} @end diff --git a/tests/Makefile b/tests/Makefile index fa5902d..9e3fc5e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,5 +1,5 @@ all: - objfw-compile -Wall -o tests *.m -I../src -L../src -lobjxmpp + objfw-compile -Wall -g -o tests *.m -I../src -L../src -lobjxmpp clean: rm -f tests *.o diff --git a/tests/test.m b/tests/test.m index 6b78c8b..089a334 100644 --- a/tests/test.m +++ b/tests/test.m @@ -110,10 +110,17 @@ OF_APPLICATION_DELEGATE(AppDelegate) - (void)connection: (XMPPConnection*)conn wasBoundToJID: (XMPPJID*)jid +{ + of_log(@"Bound to JID: %@", [jid fullJID]); + + [conn requestRoster]; +} + +- (void)connectionDidReceiveRoster :(XMPPConnection*)conn { XMPPPresence *pres; - of_log(@"Bound to JID: %@", [jid fullJID]); + of_log(@"Got roster"); pres = [XMPPPresence presence]; [pres addPriority: 10];