diff --git a/src/XMPPConnection.h b/src/XMPPConnection.h index f32a092..02d8786 100644 --- a/src/XMPPConnection.h +++ b/src/XMPPConnection.h @@ -157,7 +157,7 @@ BOOL streamOpen; BOOL needsSession; BOOL encryptionRequired, encrypted; - BOOL rosterVersioningSupported; + BOOL supportsRosterVersioning; unsigned int lastID; /// \endcond } @@ -196,7 +196,7 @@ /// \brief Whether the connection is encrypted @property (readonly) BOOL encrypted; /// \brief Whether roster versioning is supported -@property (readonly) BOOL rosterVersioningSupported; +@property (readonly) BOOL supportsRosterVersioning; #endif /** @@ -338,7 +338,7 @@ - (id )dataStorage; - (void)setLanguage: (OFString*)language; - (OFString*)language; -- (BOOL)rosterVersioningSupported; +- (BOOL)supportsRosterVersioning; /// \cond internal - (void)XMPP_startStream; diff --git a/src/XMPPConnection.m b/src/XMPPConnection.m index 99613d6..e151ca9 100644 --- a/src/XMPPConnection.m +++ b/src/XMPPConnection.m @@ -350,9 +350,9 @@ return streamOpen; } -- (BOOL)rosterVersioningSupported +- (BOOL)supportsRosterVersioning { - return rosterVersioningSupported; + return supportsRosterVersioning; } - (BOOL)checkCertificateAndGetReason: (OFString**)reason @@ -852,7 +852,7 @@ if ([element elementForName: @"ver" namespace: XMPP_NS_ROSTERVER] != nil) - rosterVersioningSupported = YES; + supportsRosterVersioning = YES; if (mechs != nil) { OFEnumerator *enumerator; diff --git a/src/XMPPRoster.h b/src/XMPPRoster.h index 310234e..ce8d407 100644 --- a/src/XMPPRoster.h +++ b/src/XMPPRoster.h @@ -147,9 +147,7 @@ - (id )dataStorage; /// \cond internal -- (void)XMPP_addRosterItem: (XMPPRosterItem*)rosterItem; - (void)XMPP_updateRosterItem: (XMPPRosterItem*)rosterItem; -- (void)XMPP_deleteRosterItem: (XMPPRosterItem*)rosterItem; - (void)XMPP_handleInitialRosterForConnection: (XMPPConnection*)connection withIQ: (XMPPIQ*)iq; - (XMPPRosterItem*)XMPP_rosterItemWithXMLElement: (OFXMLElement*)element; diff --git a/src/XMPPRoster.m b/src/XMPPRoster.m index 4e76176..57882b1 100644 --- a/src/XMPPRoster.m +++ b/src/XMPPRoster.m @@ -75,13 +75,28 @@ - (void)requestRoster { XMPPIQ *iq; + OFXMLElement *query; rosterRequested = YES; iq = [XMPPIQ IQWithType: @"get" ID: [connection generateStanzaID]]; - [iq addChild: [OFXMLElement elementWithName: @"query" - namespace: XMPP_NS_ROSTER]]; + + query = [OFXMLElement elementWithName: @"query" + namespace: XMPP_NS_ROSTER]; + + if ([connection supportsRosterVersioning]) { + OFString *ver = [dataStorage stringValueForPath: @"roster.ver"]; + + if (ver == nil) + ver = @""; + + [query addAttributeWithName: @"ver" + stringValue: ver]; + } + + [iq addChild: query]; + [connection sendIQ: iq withCallbackObject: self selector: @selector(XMPP_handleInitialRosterForConnection: @@ -110,17 +125,21 @@ if (element != nil) { rosterItem = [self XMPP_rosterItemWithXMLElement: element]; - if ([[rosterItem subscription] isEqual: @"remove"]) - [self XMPP_deleteRosterItem: rosterItem]; - else - [self XMPP_addRosterItem: rosterItem]; - - [delegates broadcastSelector: @selector( - roster:didReceiveRosterItem:) - withObject: self - withObject: rosterItem]; + [self XMPP_updateRosterItem: rosterItem]; } + if ([connection supportsRosterVersioning]) { + OFString *ver = + [[rosterElement attributeForName: @"ver"] stringValue]; + [dataStorage setStringValue: ver + forPath: @"roster.ver"]; + } + + [delegates broadcastSelector: @selector( + roster:didReceiveRosterItem:) + withObject: self + withObject: rosterItem]; + [connection_ sendStanza: [iq resultIQ]]; return YES; @@ -203,20 +222,41 @@ return dataStorage; } -- (void)XMPP_addRosterItem: (XMPPRosterItem*)rosterItem -{ - return [self XMPP_updateRosterItem: rosterItem]; -} - - (void)XMPP_updateRosterItem: (XMPPRosterItem*)rosterItem { - [rosterItems setObject: rosterItem - forKey: [[rosterItem JID] bareJID]]; -} + if ([connection supportsRosterVersioning]) { + OFMutableDictionary *items = [[[dataStorage dictionaryForPath: + @"roster.items"] mutableCopy] autorelease]; -- (void)XMPP_deleteRosterItem: (XMPPRosterItem*)rosterItem -{ - [rosterItems removeObjectForKey: [[rosterItem JID] bareJID]]; + if (![[rosterItem subscription] isEqual: @"remove"]) { + OFMutableDictionary *item = [OFMutableDictionary + dictionaryWithKeysAndObjects: + @"JID", [[rosterItem JID] bareJID], + @"subscription", [rosterItem subscription], + nil]; + + if ([rosterItem name] != nil) + [item setObject: [rosterItem name] + forKey: @"name"]; + + if ([rosterItem groups] != nil) + [item setObject: [rosterItem groups] + forKey: @"groups"]; + + [items setObject: item + forKey: [[rosterItem JID] bareJID]]; + } else + [items removeObjectForKey: [[rosterItem JID] bareJID]]; + + [dataStorage setDictionary: items + forPath: @"roster.items"]; + } + + if (![[rosterItem subscription] isEqual: @"remove"]) + [rosterItems setObject: rosterItem + forKey: [[rosterItem JID] bareJID]]; + else + [rosterItems removeObjectForKey: [[rosterItem JID] bareJID]]; } - (XMPPRosterItem*)XMPP_rosterItemWithXMLElement: (OFXMLElement*)element @@ -255,17 +295,37 @@ return rosterItem; } -- (void)XMPP_handleInitialRosterForConnection: (XMPPConnection*)connection +- (void)XMPP_handleInitialRosterForConnection: (XMPPConnection*)connection_ withIQ: (XMPPIQ*)iq { OFXMLElement *rosterElement; OFEnumerator *enumerator; OFXMLElement *element; - XMPPRosterItem *rosterItem = nil; + XMPPRosterItem *rosterItem; rosterElement = [iq elementForName: @"query" namespace: XMPP_NS_ROSTER]; + if ([connection supportsRosterVersioning]) { + OFDictionary *items = [dataStorage + dictionaryForPath: @"roster.items"]; + OFEnumerator *enumerator = [items objectEnumerator]; + OFDictionary *item; + + while ((item = [enumerator nextObject]) != nil) { + rosterItem = [XMPPRosterItem rosterItem]; + [rosterItem setJID: [XMPPJID JIDWithString: + [item objectForKey: @"JID"]]]; + [rosterItem setName: [item objectForKey: @"name"]]; + [rosterItem setSubscription: + [item objectForKey: @"subscription"]]; + [rosterItem setGroups: [item objectForKey: @"groups"]]; + + [rosterItems setObject: rosterItem + forKey: [[rosterItem JID] bareJID]]; + } + } + enumerator = [[rosterElement children] objectEnumerator]; while ((element = [enumerator nextObject]) != nil) { if (![[element name] isEqual: @"item"] || @@ -274,10 +334,14 @@ rosterItem = [self XMPP_rosterItemWithXMLElement: element]; - if ([[rosterItem subscription] isEqual: @"remove"]) - [self XMPP_deleteRosterItem: rosterItem]; - else - [self XMPP_addRosterItem: rosterItem]; + [self XMPP_updateRosterItem: rosterItem]; + } + + if ([connection supportsRosterVersioning]) { + OFString *ver = + [[rosterElement attributeForName: @"ver"] stringValue]; + [dataStorage setStringValue: ver + forPath: @"roster.ver"]; } [delegates broadcastSelector: @selector(rosterWasReceived:) diff --git a/src/XMPPRosterItem.m b/src/XMPPRosterItem.m index 53d3f70..cbcd609 100644 --- a/src/XMPPRosterItem.m +++ b/src/XMPPRosterItem.m @@ -26,6 +26,8 @@ #import "XMPPRosterItem.h" +#import + @implementation XMPPRosterItem + rosterItem { @@ -104,13 +106,11 @@ - (void)setGroups: (OFArray*)groups_ { - OFArray *old = groups; - groups = [groups_ copy]; - [old release]; + OF_SETTER(groups, groups_, YES, YES) } - (OFArray*)groups { - return [[groups copy] autorelease]; + OF_GETTER(groups, YES) } @end