From 915d5b5cab302fe93a7abe36b8b10a21e5addafa Mon Sep 17 00:00:00 2001 From: Jonathan Schleifer Date: Mon, 28 Mar 2011 15:14:27 +0200 Subject: [PATCH] Add XMPPRoster class. --- ObjXMPP.xcodeproj/project.pbxproj | 8 +++ src/XMPPConnection.h | 5 +- src/XMPPConnection.m | 43 ++++---------- src/XMPPJID.m | 5 ++ src/XMPPRoster.h | 38 +++++++++++++ src/XMPPRoster.m | 95 +++++++++++++++++++++++++++++++ src/XMPPRosterItem.h | 34 +++++++++++ src/XMPPRosterItem.m | 39 +++++++++++++ tests/test.m | 6 +- 9 files changed, 239 insertions(+), 34 deletions(-) create mode 100644 src/XMPPRoster.h create mode 100644 src/XMPPRoster.m create mode 100644 src/XMPPRosterItem.h create mode 100644 src/XMPPRosterItem.m diff --git a/ObjXMPP.xcodeproj/project.pbxproj b/ObjXMPP.xcodeproj/project.pbxproj index e127481..d96e6aa 100644 --- a/ObjXMPP.xcodeproj/project.pbxproj +++ b/ObjXMPP.xcodeproj/project.pbxproj @@ -35,6 +35,8 @@ 4BC55A021337AC1800E345C7 /* XMPPStanza.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BC559FF1337AC1800E345C7 /* XMPPStanza.m */; }; 4BD9BF59134003F700DAB43A /* XMPPRosterItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD9BF57134003F700DAB43A /* XMPPRosterItem.h */; }; 4BD9BF5A134003F700DAB43A /* XMPPRosterItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD9BF58134003F700DAB43A /* XMPPRosterItem.m */; }; + 4BDEF8071340B240000156D1 /* XMPPRoster.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BDEF8051340B240000156D1 /* XMPPRoster.h */; }; + 4BDEF8081340B240000156D1 /* XMPPRoster.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BDEF8061340B240000156D1 /* XMPPRoster.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -79,6 +81,8 @@ 4BC55A051337ADA800E345C7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 4BD9BF57134003F700DAB43A /* XMPPRosterItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMPPRosterItem.h; path = src/XMPPRosterItem.h; sourceTree = SOURCE_ROOT; }; 4BD9BF58134003F700DAB43A /* XMPPRosterItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XMPPRosterItem.m; path = src/XMPPRosterItem.m; sourceTree = SOURCE_ROOT; }; + 4BDEF8051340B240000156D1 /* XMPPRoster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMPPRoster.h; path = src/XMPPRoster.h; sourceTree = SOURCE_ROOT; }; + 4BDEF8061340B240000156D1 /* XMPPRoster.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XMPPRoster.m; path = src/XMPPRoster.m; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -159,6 +163,8 @@ 4BC559E71337AC0900E345C7 /* XMPPPLAINAuth.m */, 4BC559E81337AC0900E345C7 /* XMPPPresence.h */, 4BC559E91337AC0900E345C7 /* XMPPPresence.m */, + 4BDEF8051340B240000156D1 /* XMPPRoster.h */, + 4BDEF8061340B240000156D1 /* XMPPRoster.m */, 4BD9BF57134003F700DAB43A /* XMPPRosterItem.h */, 4BD9BF58134003F700DAB43A /* XMPPRosterItem.m */, 4BC559EA1337AC0900E345C7 /* XMPPSCRAMAuth.h */, @@ -196,6 +202,7 @@ 4BC559FC1337AC0900E345C7 /* XMPPSCRAMAuth.h in Headers */, 4BC55A011337AC1800E345C7 /* XMPPStanza.h in Headers */, 4BD9BF59134003F700DAB43A /* XMPPRosterItem.h in Headers */, + 4BDEF8071340B240000156D1 /* XMPPRoster.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -295,6 +302,7 @@ 4BC55A001337AC1800E345C7 /* XMPPSCRAMAuth.m in Sources */, 4BC55A021337AC1800E345C7 /* XMPPStanza.m in Sources */, 4BD9BF5A134003F700DAB43A /* XMPPRosterItem.m in Sources */, + 4BDEF8081340B240000156D1 /* XMPPRoster.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/XMPPConnection.h b/src/XMPPConnection.h index 2494b58..4689634 100644 --- a/src/XMPPConnection.h +++ b/src/XMPPConnection.h @@ -29,6 +29,7 @@ @class XMPPMessage; @class XMPPPresence; @class XMPPAuthenticator; +@class XMPPRoster; @protocol XMPPConnectionDelegate @optional @@ -64,7 +65,7 @@ BOOL needsSession; unsigned int lastID; OFString *bindID, *sessionID, *rosterID; - OFMutableDictionary *roster; + XMPPRoster *roster; } @property (copy) OFString *username, *password, *server, *resource; @@ -72,7 +73,7 @@ @property (assign) uint16_t port; @property (assign) BOOL useTLS; @property (retain) id delegate; -@property (copy, readonly) OFDictionary *roster; +@property (readonly, retain) XMPPRoster *roster; /** * Connects to the XMPP service. diff --git a/src/XMPPConnection.m b/src/XMPPConnection.m index 37fa9b1..6c03b83 100644 --- a/src/XMPPConnection.m +++ b/src/XMPPConnection.m @@ -36,6 +36,7 @@ #import "XMPPIQ.h" #import "XMPPMessage.h" #import "XMPPPresence.h" +#import "XMPPRoster.h" #import "XMPPRosterItem.h" #import "XMPPExceptions.h" @@ -81,7 +82,7 @@ parser.delegate = self; elementBuilder.delegate = self; - roster = [[OFMutableDictionary alloc] init]; + roster = [[XMPPRoster alloc] initWithConnection: self]; } @catch (id e) { [self release]; @throw e; @@ -489,7 +490,7 @@ return; } - if ([mechs count] > 0) { + if (mechs.count > 0) { for (OFXMLElement *mech in [mechs.firstObject children]) [mechanisms addObject: [mech.children.firstObject stringValue]]; @@ -654,41 +655,21 @@ rosterItem = [XMPPRosterItem rosterItem]; rosterItem.JID = [XMPPJID JIDWithString: - [rosterElem attributeForName: @"jid"].stringValue]; - rosterItem.name = - [rosterElem attributeForName: @"name"].stringValue; + [elem attributeForName: @"jid"].stringValue]; + rosterItem.name = [elem attributeForName: @"name"].stringValue; rosterItem.subscription = - [rosterElem attributeForName: @"subscription"].stringValue; + [elem attributeForName: @"subscription"].stringValue; for (OFXMLElement *groupElem in [elem elementsForName: @"group" - namespace: NS_ROSTER]) { - OFMutableArray *rosterGroup = - [roster objectForKey: rosterElem.stringValue]; + namespace: NS_ROSTER]) + [groups addObject: + [groupElem.children.firstObject stringValue]]; - if (rosterGroup == nil) { - rosterGroup = [OFMutableArray array]; - [roster setObject: rosterGroup - forKey: rosterElem.stringValue]; - } + if (groups.count > 0) + rosterItem.groups = groups; - [rosterGroup addObject: rosterItem]; - } - - rosterItem.groups = groups; - - if (groups.count == 0) { - OFMutableArray *rosterGroup = - [roster objectForKey: @""]; - - if (rosterGroup == nil) { - rosterGroup = [OFMutableArray array]; - [roster setObject: rosterGroup - forKey: @""]; - } - - [rosterGroup addObject: rosterItem]; - } + [roster XMPP_addRosterItem: rosterItem]; } if ([delegate respondsToSelector: diff --git a/src/XMPPJID.m b/src/XMPPJID.m index 83303be..5270889 100644 --- a/src/XMPPJID.m +++ b/src/XMPPJID.m @@ -201,4 +201,9 @@ return [OFString stringWithFormat: @"%@/%@", domain, resource]; } + +- (OFString*)description +{ + return [self fullJID]; +} @end diff --git a/src/XMPPRoster.h b/src/XMPPRoster.h new file mode 100644 index 0000000..424418b --- /dev/null +++ b/src/XMPPRoster.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objxmpp/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@class XMPPConnection; +@class XMPPRosterItem; + +@interface XMPPRoster: OFObject +{ + XMPPConnection *connection; + OFMutableDictionary *groups; +} + +- initWithConnection: (XMPPConnection*)conn; +- (void)XMPP_addRosterItem: (XMPPRosterItem*)rosterItem; +- (OFArray*)groups; +- (OFArray*)rosterItemsInGroup: (OFString*)group; +@end diff --git a/src/XMPPRoster.m b/src/XMPPRoster.m new file mode 100644 index 0000000..237a702 --- /dev/null +++ b/src/XMPPRoster.m @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objxmpp/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "XMPPRoster.h" +#import "XMPPRosterItem.h" + +@implementation XMPPRoster +- initWithConnection: (XMPPConnection*)conn +{ + self = [super init]; + + @try { + connection = [conn retain]; + groups = [[OFMutableDictionary alloc] init]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [connection release]; + + [super dealloc]; +} + +- (void)XMPP_addRosterItem: (XMPPRosterItem*)rosterItem +{ + if (rosterItem.groups.count > 0) { + for (OFString *group in rosterItem.groups) { + OFMutableArray *rosterGroup = + [groups objectForKey: group]; + + if (rosterGroup == nil) { + rosterGroup = [OFMutableArray array]; + [groups setObject: rosterGroup + forKey: group]; + } + + [rosterGroup addObject: rosterItem]; + } + } else { + OFMutableArray *rosterGroup = [groups objectForKey: @""]; + + if (rosterGroup == nil) { + rosterGroup = [OFMutableArray array]; + [groups setObject: rosterGroup + forKey: @""]; + } + + [rosterGroup addObject: rosterItem]; + } +} + +- (OFArray*)groups +{ + OFMutableArray *ret = [OFMutableArray array]; + + for (OFString *group in groups) + [ret addObject: group]; + + ret->isa = [OFArray class]; + return ret; +} + +- (OFArray*)rosterItemsInGroup: (OFString*)group +{ + if (group == nil) + group = @""; + + return [[[groups objectForKey: group] copy] autorelease]; +} +@end diff --git a/src/XMPPRosterItem.h b/src/XMPPRosterItem.h new file mode 100644 index 0000000..99e50dc --- /dev/null +++ b/src/XMPPRosterItem.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objxmpp/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@class XMPPJID; + +@interface XMPPRosterItem: OFObject +@property (copy) XMPPJID *JID; +@property (copy) OFString *name; +@property (copy) OFString *subscription; +@property (copy) OFArray *groups; + ++ rosterItem; +@end diff --git a/src/XMPPRosterItem.m b/src/XMPPRosterItem.m new file mode 100644 index 0000000..ee84e84 --- /dev/null +++ b/src/XMPPRosterItem.m @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011, Jonathan Schleifer + * + * https://webkeks.org/hg/objxmpp/ + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "XMPPRosterItem.h" + +@implementation XMPPRosterItem +@synthesize JID, name, subscription, groups; + ++ rosterItem +{ + return [[[self alloc] init] autorelease]; +} + +- (OFString*)description +{ + return [OFString stringWithFormat: @"", + JID, name, subscription, groups]; +} +@end diff --git a/tests/test.m b/tests/test.m index 90424e9..18c12a5 100644 --- a/tests/test.m +++ b/tests/test.m @@ -31,6 +31,7 @@ #import "XMPPIQ.h" #import "XMPPMessage.h" #import "XMPPPresence.h" +#import "XMPPRoster.h" @interface AppDelegate: OFObject @end @@ -120,7 +121,10 @@ OF_APPLICATION_DELEGATE(AppDelegate) { XMPPPresence *pres; - of_log(@"Got roster"); + of_log(@"Got roster! Groups: %@", conn.roster.groups); + for (OFString *group in conn.roster.groups) + of_log(@"Group %@: %@", group, + [conn.roster rosterItemsInGroup: group]); pres = [XMPPPresence presence]; [pres addPriority: 10];