StropheCappuccino API 1.0.0
/tmp/tempDoc.doc/PubSub/TNPubSubNode.j
Go to the documentation of this file.
00001 /*
00002  * TNPubSubNode.j
00003  *
00004  * Copyright (C) 2010  Antoine Mercadal <antoine.mercadal@inframonde.eu>
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 3.0 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 
00022 
00023 @class TNStrophePubSubSubscriptionsRetrievedNotification
00024 
00025 
00026 TNStrophePubSubVarAccessModel               = @"pubsub#access_model";
00027 TNStrophePubSubVarBodyXSLT                  = @"pubsub#body_xslt";
00028 TNStrophePubSubVarDeliverNotification       = @"pubsub#deliver_notifications";
00029 TNStrophePubSubVarDeliverPayloads           = @"pubsub#deliver_payloads";
00030 TNStrophePubSubVarItemExpire                = @"pubsub#item_expire";
00031 TNStrophePubSubVarMaxItems                  = @"pubsub#max_items";
00032 TNStrophePubSubVarMaxPayloadSize            = @"pubsub#max_payload_size";
00033 TNStrophePubSubVarNotificationType          = @"pubsub#notification_type";
00034 TNStrophePubSubVarNotifyConfig              = @"pubsub#notify_config";
00035 TNStrophePubSubVarNotifyDelete              = @"pubsub#notify_delete";
00036 TNStrophePubSubVarNotifyRectract            = @"pubsub#notify_retract";
00037 TNStrophePubSubVarNotifySub                 = @"pubsub#notify_sub";
00038 TNStrophePubSubVarPersistItems              = @"pubsub#persist_items";
00039 TNStrophePubSubVarPresenceBasedDelivery     = @"pubsub#presence_based_delivery";
00040 TNStrophePubSubVarPublishModel              = @"pubsub#publish_model";
00041 TNStrophePubSubVarPurgeOffline              = @"pubsub#purge_offline";
00042 TNStrophePubSubVarRosterGroupAllowed        = @"pubsub#roster_groups_allowed";
00043 TNStrophePubSubVarSendLastPublishedItem     = @"pubsub#send_last_published_item";
00044 TNStrophePubSubVarTitle                     = @"pubsub#title";
00045 TNStrophePubSubVarType                      = @"pubsub#type";
00046 
00047 TNStrophePubSubVarAccessModelAuthorize      = @"authorize";
00048 TNStrophePubSubVarAccessModelOpen           = @"open";
00049 TNStrophePubSubVarAccessModelRoster         = @"roster";
00050 TNStrophePubSubVarAccessModelWhitelist      = @"whitelist";
00051 
00052 TNPubSubNodeAffiliationMember               = @"member";
00053 TNPubSubNodeAffiliationNone                 = @"none";
00054 TNPubSubNodeAffiliationOutcast              = @"outcast";
00055 TNPubSubNodeAffiliationOwner                = @"owner";
00056 TNPubSubNodeAffiliationPublisher            = @"publisher";
00057 TNPubSubNodeAffiliationPublisherOnly        = @"publish-only";
00058 
00059 TNStrophePubSubItemPublishedNotification    = @"TNStrophePubSubItemPublishedNotification";
00060 TNStrophePubSubItemPublishErrorNotification = @"TNStrophePubSubItemPublishErrorNotification";
00061 TNStrophePubSubItemRetractedNotification    = @"TNStrophePubSubItemRetractedNotification";
00062 TNStrophePubSubItemRetractErrorNotification = @"TNStrophePubSubItemRetractErrorNotification";
00063 TNStrophePubSubNodeConfiguredNotification   = @"TNStrophePubSubNodeConfiguredNotification";
00064 TNStrophePubSubNodeCreatedNotification      = @"TNStrophePubSubNodeCreatedNotification";
00065 TNStrophePubSubNodeDeletedNotification      = @"TNStrophePubSubNodeDeletedNotification";
00066 TNStrophePubSubNodeEventNotification        = @"TNStrophePubSubNodeEventNotification"
00067 TNStrophePubSubNodeRetrievedNotification    = @"TNStrophePubSubNodeRetrievedNotification";
00068 TNStrophePubSubNodeSubscribedNotification   = @"TNStrophePubSubNodeSubscribedNotification";
00069 TNStrophePubSubNodeUnsubscribedNotification = @"TNStrophePubSubNodeUnsubscribedNotification";
00070 
00071 
00072 // TODO: Abstract out subscription related stuff into TNPubSubNodeSubscription in order to handle multiple node subscriptions better
00073 
00077 @implementation TNPubSubNode : CPObject
00078 {
00079     CPArray                 _content;
00080     CPArray                 _subscriptionIDs;
00081     CPDictionary            _affiliations;
00082     CPString                _nodeName;
00083     id                      _delegate;
00084     TNStropheJID            _pubSubServer;
00085 
00086     id                      _eventSelectorID;
00087     TNStropheConnection     _connection;
00088 }
00089 
00090 
00091 #pragma mark -
00092 #pragma mark Class methods
00093 
00100 + (void)registerSelector:(SEL)aSelector ofObject:(id)anObject forPubSubEventWithConnection:(TNStropheConnection)aConnection
00101 {
00102     var params = [CPDictionary dictionaryWithObjectsAndKeys:@"message", @"name",
00103                                                             @"headline", @"type",
00104                                                             {"matchBare": YES}, @"options",
00105                                                             Strophe.NS.PUBSUB_EVENT, @"namespace"];
00106 
00107     return [aConnection registerSelector:aSelector ofObject:anObject withDict:params];
00108 }
00109 
00110 
00111 #pragma mark -
00112 #pragma mark Initialization
00113 
00120 + (TNPubSubNode)pubSubNodeWithNodeName:(CPString)aNodeName connection:(TNStropheConnection)aConnection pubSubServer:(CPString)aPubSubServer
00121 {
00122     return [[TNPubSubNode alloc] initWithNodeName:aNodeName connection:aConnection pubSubServer:aPubSubServer];
00123 }
00124 
00131 - (TNPubSubNode)initWithNodeName:(CPString)aNodeName connection:(TNStropheConnection)aConnection pubSubServer:(TNStropheJID)aPubSubServer
00132 {
00133     if (self = [super init])
00134     {
00135         _nodeName           = aNodeName;
00136         _connection         = aConnection;
00137         _pubSubServer       = aPubSubServer ? aPubSubServer : [TNStropheJID stropheJIDWithString:@"pubsub." + [[_connection JID] domain]];
00138         _subscriptionIDs    = [CPArray array];
00139         _affiliations       = [CPDictionary dictionary];
00140 
00141         [self _setEventHandler];
00142     }
00143 
00144     return self;
00145 }
00146 
00154 + (TNPubSubNode)pubSubNodeWithNodeName:(CPString)aNodeName connection:(TNStropheConnection)aConnection pubSubServer:(TNStropheJID)aPubSubServer subscriptionIDs:(CPArray)aSubscriptionIDs
00155 {
00156     return [[TNPubSubNode alloc] initWithNodeName:aNodeName connection:aConnection pubSubServer:aPubSubServer subscriptionIDs:aSubscriptionIDs];
00157 }
00158 
00166 - (TNPubSubNode)initWithNodeName:(CPString)aNodeName connection:(TNStropheConnection)aConnection pubSubServer:(CPString)aPubSubServer subscriptionIDs:(CPArray)aSubscriptionIDs
00167 {
00168     if (self = [self initWithNodeName:aNodeName connection:aConnection pubSubServer:aPubSubServer])
00169     {
00170         _subscriptionIDs = aSubscriptionIDs;
00171     }
00172 
00173     return self;
00174 }
00175 
00176 
00177 #pragma mark -
00178 #pragma mark Node Management
00179 
00183 - (void)retrieveItems
00184 {
00185     var uid     = [_connection getUniqueId],
00186         stanza  = [TNStropheStanza iq],
00187         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00188 
00189     [stanza setTo:_pubSubServer];
00190     [stanza setType:@"get"];
00191     [stanza setID:uid];
00192 
00193     [stanza addChildWithName:@"pubsub" andAttributes:{@"xmlns": Strophe.NS.PUBSUB}];
00194     [stanza addChildWithName:@"items" andAttributes:{@"node": _nodeName}];
00195 
00196     [_connection registerSelector:@selector(_didRetrievePubSubNode:) ofObject:self withDict:params];
00197     [_connection send:stanza];
00198 }
00199 
00204 - (BOOL)_didRetrievePubSubNode:(TNStropheStanza)aStanza
00205 {
00206     if ([aStanza type] == @"result")
00207     {
00208         _content = [aStanza childrenWithName:@"item"];
00209         [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubNodeRetrievedNotification object:self];
00210         if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:retrievedItems:)])
00211             [_delegate pubSubNode:self retrievedItems:YES];
00212     }
00213     else
00214     {
00215         if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:retrievedItems:)])
00216             [_delegate pubSubNode:self retrievedItems:NO];
00217         CPLog.error("Cannot retrieve the contents of pubsub node");
00218         CPLog.error(aStanza);
00219     }
00220 
00221     return NO;
00222 }
00223 
00226 - (void)create
00227 {
00228     var uid     = [_connection getUniqueId],
00229         stanza  = [TNStropheStanza iq],
00230         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00231 
00232     [stanza setTo:_pubSubServer];
00233     [stanza setType:@"set"];
00234     [stanza setID:uid];
00235 
00236     [stanza addChildWithName:@"pubsub" andAttributes:{@"xmlns": Strophe.NS.PUBSUB}];
00237     [stanza addChildWithName:@"create" andAttributes:{@"node": _nodeName}];
00238 
00239     [_connection registerSelector:@selector(_didCreatePubSubNode:) ofObject:self withDict:params];
00240     [_connection send:stanza];
00241 }
00242 
00247 - (BOOL)_didCreatePubSubNode:(TNStropheStanza)aStanza
00248 {
00249     if ([aStanza type] == @"result")
00250         [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubNodeCreatedNotification object:self];
00251     else
00252     {
00253         CPLog.error("Cannot create the pubsub node");
00254         CPLog.error(aStanza);
00255     }
00256 
00257 
00258     return NO;
00259 }
00260 
00263 - (void)delete
00264 {
00265     var uid     = [_connection getUniqueId],
00266         stanza  = [TNStropheStanza iq],
00267         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00268 
00269     [stanza setTo:_pubSubServer];
00270     [stanza setType:@"set"];
00271     [stanza setID:uid];
00272 
00273     [stanza addChildWithName:@"pubsub" andAttributes:{@"xmlns": Strophe.NS.PUBSUB_OWNER}];
00274     [stanza addChildWithName:@"delete" andAttributes:{@"node": _nodeName}];
00275 
00276     [_connection registerSelector:@selector(didDeletePubSubNode:) ofObject:self withDict:params];
00277     [_connection send:stanza];
00278 }
00279 
00284 - (BOOL)_didCreatePubSubNode:(TNStropheStanza)aStanza
00285 {
00286     if ([aStanza type] == @"result")
00287         [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubNodeDeletedNotification object:self];
00288     else
00289     {
00290         CPLog.error("Cannot delete the pubsub node");
00291         CPLog.error(aStanza);
00292     }
00293 
00294 
00295     return NO;
00296 }
00297 
00307 - (void)configureWithDict:(CPDictionary)aDictionary
00308 {
00309     var uid     = [_connection getUniqueId],
00310         stanza  = [TNStropheStanza iq],
00311         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00312 
00313     [stanza setTo:_pubSubServer];
00314     [stanza setType:@"set"];
00315     [stanza setID:uid];
00316 
00317     [stanza addChildWithName:@"pubsub" andAttributes:{@"xmlns": Strophe.NS.PUBSUB_OWNER}];
00318     [stanza addChildWithName:@"configure" andAttributes:{@"node": _nodeName}];
00319     [stanza addChildWithName:@"x" andAttributes:{@"xmlns": "jabber:x:data", @"type": @"submit"}];
00320     [stanza addChildWithName:@"field" andAttributes:{@"var": @"FORM_TYPE", @"type": @"hidden"}];
00321     [stanza addChildWithName:@"value"];
00322     [stanza addTextNode:Strophe.NS.PUBSUB_NODE_CONFIG];
00323     [stanza up];
00324     [stanza up];
00325 
00326     for (var i = 0; i < [[aDictionary allKeys] count]; i++)
00327     {
00328         var key     = [[aDictionary allKeys] objectAtIndex:i],
00329             value   = [aDictionary objectForKey:key];
00330 
00331         [stanza addChildWithName:@"field" andAttributes:{@"var": key}];
00332 
00333         if ([value isKindOfClass:CPArray])
00334         {
00335             for (var j = 0; j < [value count]; j++)
00336             {
00337                 [stanza addChildWithName:@"value"];
00338                 [stanza addTextNode:@"" + [value objectAtIndex:j] + @""];
00339                 [stanza up];
00340             }
00341         }
00342         else
00343         {
00344             [stanza addChildWithName:@"value"];
00345             [stanza addTextNode:@"" + value + @""];
00346             [stanza up];
00347         }
00348         [stanza up];
00349     }
00350 
00351     [_connection registerSelector:@selector(_didConfigurePubSubNode:) ofObject:self withDict:params];
00352     [_connection send:stanza];
00353 }
00354 
00359 - (BOOL)_didConfigurePubSubNode:(TNStropheStanza)aStanza
00360 {
00361     if ([aStanza type] == @"result")
00362         [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubNodeConfiguredNotification object:self];
00363     else
00364     {
00365         CPLog.error("Cannot configure the pubsub node");
00366         CPLog.error(aStanza);
00367     }
00368 
00369     return NO;
00370 }
00371 
00372 
00373 #pragma mark -
00374 #pragma mark Item management
00375 
00379 - (void)publishItem:(TNXMLNode)anItem
00380 {
00381     var uid     = [_connection getUniqueId],
00382         stanza  = [TNStropheStanza iq],
00383         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00384 
00385     [stanza setTo:_pubSubServer];
00386     [stanza setType:@"set"];
00387     [stanza setID:uid];
00388 
00389     [stanza addChildWithName:@"pubsub" andAttributes:{@"xmlns": Strophe.NS.PUBSUB}];
00390     [stanza addChildWithName:@"publish" andAttributes:{@"node": _nodeName}];
00391     [stanza addChildWithName:@"item" andAttributes:{@"id": [CPString UUID]}];
00392     [stanza addNode:anItem];
00393 
00394     [_connection registerSelector:@selector(_didPublishPubSubItem:) ofObject:self withDict:params];
00395     [_connection send:stanza];
00396 }
00397 
00402 - (BOOL)_didPublishPubSubItem:(TNStropheStanza)aStanza
00403 {
00404     if ([aStanza type] == @"result")
00405     {
00406         [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_didUpdateContentAfterPublishing:) name:TNStrophePubSubNodeRetrievedNotification object:self];
00407         [self retrieveItems];
00408     }
00409     else
00410     {
00411         [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubItemPublishErrorNotification object:self userInfo:aStanza];
00412         CPLog.error("Cannot publish the pubsub item in node");
00413         CPLog.error(aStanza);
00414     }
00415 
00416     if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:publishedItem:)])
00417         [_delegate pubSubNode:self publishedItem:aStanza];
00418 
00419     return NO;
00420 }
00421 
00425 - (void)_didUpdateContentAfterPublishing:(CPNotification)aNotification
00426 {
00427     [[CPNotificationCenter defaultCenter] removeObserver:self name:TNStrophePubSubNodeRetrievedNotification object:self];
00428     [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubItemPublishedNotification object:self];
00429 }
00430 
00431 
00435 - (void)retractItem:(TNXMLNode)aNode
00436 {
00437     [self retractItemWithID:[aNode valueForAttribute:@"id"]];
00438 }
00439 
00443 - (void)retractItemWithID:(CPString)anID
00444 {
00445     [self retractItemsWithIDs:[anID]];
00446 }
00447 
00448 - (void)retractItemsWithIDs:(CPArray)someIDs
00449 {
00450     var uid     = [_connection getUniqueId],
00451         stanza  = [TNStropheStanza iq],
00452         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00453 
00454     [stanza setTo:_pubSubServer];
00455     [stanza setType:@"set"];
00456     [stanza setID:uid];
00457 
00458     [stanza addChildWithName:@"pubsub" andAttributes:{@"xmlns": Strophe.NS.PUBSUB}];
00459 
00460     for (var i = 0; i < [someIDs count]; i++)
00461     {
00462         [stanza addChildWithName:@"retract" andAttributes:{@"node": _nodeName}];
00463         [stanza addChildWithName:@"item" andAttributes:{@"id": [someIDs objectAtIndex:i]}];
00464         [stanza up];
00465         [stanza up];
00466     }
00467 
00468     [_connection registerSelector:@selector(_didRetractPubSubItems:) ofObject:self withDict:params];
00469     [_connection send:stanza];
00470 }
00471 
00476 - (BOOL)_didRetractPubSubItems:(TNStropheStanza)aStanza
00477 {
00478     if ([aStanza type] == @"result")
00479     {
00480         [[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_didUpdateContentAfterRetracting:) name:TNStrophePubSubNodeRetrievedNotification object:self];
00481         [self retrieveItems];
00482     }
00483     else
00484     {
00485         [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubItemRetractErrorNotification object:self userInfo:aStanza];
00486         CPLog.error("Cannot remove the pubsub items from node");
00487         CPLog.error(aStanza);
00488     }
00489 
00490     if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:retractedItem:)])
00491         [_delegate pubSubNode:self retractedItem:aStanza];
00492 
00493     return NO;
00494 }
00495 
00499 - (void)_didUpdateContentAfterRetracting:(CPNotification)aNotification
00500 {
00501     [[CPNotificationCenter defaultCenter] removeObserver:self name:TNStrophePubSubNodeRetrievedNotification object:self];
00502     [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubItemRetractedNotification object:self];
00503 }
00504 
00505 
00506 #pragma mark -
00507 #pragma mark Subscription Management
00508 
00512 - (void)recoverSubscriptions
00513 {
00514     var uid     = [_connection getUniqueId],
00515         stanza  = [TNStropheStanza iqWithAttributes:{"type": "get", "to": _pubSubServer, "id": uid}],
00516         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid,@"id"];
00517 
00518     [stanza addChildWithName:@"pubsub" andAttributes:{"xmlns": Strophe.NS.PUBSUB}];
00519     [stanza addChildWithName:@"subscriptions" andAttributes:{"node": _nodeName}];
00520 
00521     [_connection registerSelector:@selector(_didRetrieveSubscriptions:) ofObject:self withDict:params];
00522 
00523     [_connection send:stanza];
00524 }
00525 
00528 - (BOOL)_didRetrieveSubscriptions:(TNStropheStanza)aStanza
00529 {
00530     if ([aStanza type] == @"result")
00531     {
00532         var subscriptions   = [aStanza childrenWithName:@"subscription"];
00533 
00534         for (var i = 0; i < [subscriptions count]; i++)
00535         {
00536             var subscription    = [subscriptions objectAtIndex:i],
00537                 nodeName        = [subscription valueForAttribute:@"node"],
00538                 subid           = [subscription valueForAttribute:@"subid"];
00539 
00540             [self addSubscriptionID:subid];
00541         }
00542 
00543         [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubSubscriptionsRetrievedNotification object:self];
00544         if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:retrievedSubscriptions:)])
00545             [_delegate pubSubNode:self retrievedSubscriptions:YES];
00546     }
00547     else
00548     {
00549         if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:retrievedSubscriptions:)])
00550             [_delegate pubSubNode:self retrievedSubscriptions:NO];
00551     }
00552 
00553     return NO;
00554 }
00555 
00558 - (void)subscribe
00559 {
00560     [self subscribeWithOptions:nil];
00561 }
00562 
00566 - (void)subscribeWithOptions:(CPDictionary)options
00567 {
00568     var uid    = [_connection getUniqueId],
00569         stanza = [TNStropheStanza iq],
00570         params = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00571 
00572     [stanza setType:@"set"];
00573     [stanza setID:uid];
00574     [stanza setTo:_pubSubServer];
00575 
00576     [stanza addChildWithName:@"pubsub" andAttributes:{@"xmlns": Strophe.NS.PUBSUB}];
00577     [stanza addChildWithName:@"subscribe" andAttributes:{@"node": _nodeName, @"jid": [[_connection JID] bare]}];
00578 
00579     if (options && [options count] > 0)
00580     {
00581         [stanza up];
00582         [stanza addChildWithName:@"options"];
00583         [stanza addChildWithName:@"x" andAttributes:{"xmlns":Strophe.NS.X_DATA, "type":"submit"}];
00584         [stanza addChildWithName:@"field" andAttributes:{"var":"FORM_TYPE", "type":"hidden"}];
00585         [stanza addChildWithName:@"value"];
00586         [stanza addTextNode:Strophe.NS.PUBSUB_SUBSCRIBE_OPTIONS];
00587         [stanza up];
00588         [stanza up];
00589 
00590         var keys = [options allKeys];
00591         for (var i = 0; i < [keys count]; i++)
00592         {
00593             var key     = [keys objectAtIndex:i],
00594                 value   = [options valueForKey:key];
00595             [stanza addChildWithName:@"field" andAttributes:{"var":key}];
00596             [stanza addChildWithName:@"value"];
00597             [stanza addTextNode:value];
00598             [stanza up];
00599             [stanza up];
00600         }
00601     }
00602 
00603     [_connection registerSelector:@selector(_didSubscribe:) ofObject:self withDict:params]
00604     [_connection send:stanza];
00605 }
00606 
00612 - (BOOL)_didSubscribe:(TNStropheStanza)aStanza
00613 {
00614     if ([aStanza type] == @"result")
00615     {
00616         var subscription    = [aStanza firstChildWithName:@"subscription"],
00617             subID           = [subscription valueForAttribute:@"subid"],
00618             status          = [subscription valueForAttribute:@"subscription"];
00619 
00620         if ([subID length] > 0)
00621             [_subscriptionIDs addObject:subID];
00622 
00623         if (status === @"subscribed")
00624         {
00625             [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubNodeSubscribedNotification object:self];
00626             if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:subscribed:)])
00627                 [_delegate pubSubNode:self subscribed:YES];
00628         }
00629 
00630         [self _setEventHandler];
00631     }
00632     else
00633     {
00634         if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:subscribed:)])
00635             [_delegate pubSubNode:self subscribed:NO];
00636         CPLog.error("Cannot subscribe the pubsub node");
00637         CPLog.error(aStanza);
00638 
00639     }
00640 
00641     return NO;
00642 }
00643 
00644 - (void)addSubscriptionID:(CPString)aSubscriptionID
00645 {
00646     [_subscriptionIDs addObject:aSubscriptionID];
00647 }
00648 
00652 - (void)unsubscribeWithSubID:(CPString)aSubID
00653 {
00654     var uid    = [_connection getUniqueId],
00655         stanza = [TNStropheStanza iq],
00656         params = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00657 
00658     [stanza setType:@"set"];
00659     [stanza setID:uid];
00660     [stanza setTo:_pubSubServer];
00661 
00662     [stanza addChildWithName:@"pubsub" andAttributes:{"xmlns": Strophe.NS.PUBSUB}];
00663     [stanza addChildWithName:@"unsubscribe" andAttributes:{"node": _nodeName, "jid": [[_connection JID] bare]}];
00664     if (aSubID)
00665         [stanza setValue:aSubID forAttribute:@"subid"];
00666 
00667     [_connection registerSelector:@selector(_didUnsubscribe:) ofObject:self withDict:params];
00668     [_connection send:stanza];
00669 }
00670 
00673 - (void)unsubscribe
00674 {
00675     if ([_subscriptionIDs count] > 0)
00676     {
00677         // Unsubscribe from node for each subscription ID
00678         for (var i = 0; i < [_subscriptionIDs count]; i++)
00679         {
00680             [self unsubscribeWithSubID:[_subscriptionIDs objectAtIndex:i]];
00681         }
00682     }
00683     else
00684     {
00685         // There are no registered subscription IDs - send plain unsubscribe
00686         [self unsubscribeWithSubID:nil];
00687     }
00688 }
00689 
00694 - (BOOL)_didUnsubscribe:(TNStropheStanza)aStanza
00695 {
00696     if ([aStanza type] == @"result")
00697     {
00698         var params  = [CPDictionary dictionary],
00699             subID   = [[[aStanza firstChildWithName:@"pubsub"] firstChildWithName:@"subscription"] valueForAttribute:@"subid"];
00700 
00701         if ([subID length] > 0)
00702         {
00703             [_subscriptionIDs removeObject:subID];
00704             [params setObject:subID forKey:@"subscriptionID"];
00705         }
00706         else if ([_subscriptionIDs count] === 1)
00707         {
00708             // TODO: Need to establish if subscription id is ever included in unsubscribe confirmation or if this association needs to be made by IQ id
00709             [_subscriptionIDs removeAllObjects];
00710         }
00711 
00712         if ([_subscriptionIDs count] === 0)
00713         {
00714             // No subscriptions remaining
00715             if (_eventSelectorID)
00716             {
00717                 [_connection deleteRegisteredSelector:_eventSelectorID];
00718                 _eventSelectorID = nil;
00719             }
00720         }
00721 
00722         [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubNodeUnsubscribedNotification object:self userInfo:params];
00723         if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:unsubscribed:)])
00724             [_delegate pubSubNode:self unsubscribed:YES];
00725 
00726     }
00727     else
00728     {
00729         if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:unsubscribed:)])
00730             [_delegate pubSubNode:self unsubscribed:NO];
00731         CPLog.error("Cannot unsubscribe the pubsub node");
00732         CPLog.error(aStanza);
00733     }
00734 
00735 
00736     return NO;
00737 }
00738 
00739 - (int)numberOfSubscriptions
00740 {
00741     return [_subscriptionIDs count];
00742 }
00743 
00744 #pragma mark -
00745 #pragma mark Affiliation Management
00746 
00750 - (void)retrieveAffiliations
00751 {
00752     var uid     = [_connection getUniqueId],
00753         stanza  = [TNStropheStanza iq],
00754         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00755 
00756     [stanza setTo:_pubSubServer];
00757     [stanza setType:@"get"];
00758     [stanza setID:uid];
00759 
00760     [stanza addChildWithName:@"pubsub" andAttributes:{@"xmlns": Strophe.NS.PUBSUB_OWNER}];
00761     [stanza addChildWithName:@"affiliations" andAttributes:{@"node": _nodeName}];
00762 
00763     [_connection registerSelector:@selector(_didRetrieveAffiliations:) ofObject:self withDict:params];
00764     [_connection send:stanza];
00765 }
00766 
00769 - (void)_didRetrieveAffiliations:(TNStropheStanza)aStanza
00770 {
00771     if ([aStanza type] == @"result")
00772     {
00773         var affiliations = [aStanza childrenWithName:@"affiliation"];
00774 
00775         for (var i = 0; i < [affiliations count]; i++)
00776         {
00777             var affiliation = [affiliations objectAtIndex:i];
00778             [_affiliations setObject:[affiliation valueForAttribute:@"affiliation"] forKey:[TNStropheJID stropheJIDWithString:[affiliation valueForAttribute:@"jid"]]];
00779         }
00780     }
00781     else
00782     {
00783         CPLog.error("Cannot get affiliations");
00784         CPLog.error(aStanza);
00785     }
00786 
00787     if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:retrievedAffiliations:)])
00788         [_delegate pubSubNode:self retrievedAffiliations:aStanza];
00789 
00790 
00791     return NO;
00792 }
00793 
00799 - (void)changeAffiliation:(CPString)anAffiliation forJID:(TNStropheJID)aJID
00800 {
00801     var uid     = [_connection getUniqueId],
00802         stanza  = [TNStropheStanza iq],
00803         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00804 
00805     [stanza setTo:_pubSubServer];
00806     [stanza setType:@"set"];
00807     [stanza setID:uid];
00808 
00809     [stanza addChildWithName:@"pubsub" andAttributes:{@"xmlns": Strophe.NS.PUBSUB_OWNER}];
00810     [stanza addChildWithName:@"affiliations" andAttributes:{@"node": _nodeName}];
00811 
00812     [stanza addChildWithName:@"affiliation" andAttributes:{@"jid": [aJID bare], @"affiliation": anAffiliation}];
00813 
00814     var affiliationInformations = [CPDictionary dictionaryWithObjectsAndKeys: [aJID bare], @"jid",
00815                                                                               anAffiliation, @"affiliation"];
00816     [_connection registerSelector:@selector(_didChangeAffiliations:userInfo:) ofObject:self withDict:params userInfo:affiliationInformations];
00817     [_connection send:stanza];
00818 }
00819 
00822 - (void)_didChangeAffiliations:(TNStropheStanza)aStanza userInfo:(CPDictionary)newAffiliation
00823 {
00824     if ([aStanza type] == @"result")
00825     {
00826         [_affiliations setObject:[newAffiliation objectForKey:@"affiliation"]  forKey:[newAffiliation objectForKey:@"jid"]];
00827 
00828         [self retrieveAffiliations];
00829     }
00830     else
00831     {
00832         CPLog.error("Cannot change affiliations");
00833         CPLog.error(aStanza);
00834     }
00835 
00836     if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:changedAffiliations:)])
00837         [_delegate pubSubNode:self changedAffiliations:aStanza];
00838 
00839     return NO;
00840 }
00841 
00842 
00843 #pragma mark -
00844 #pragma mark Event Management
00845 
00846 - (void)_setEventHandler
00847 {
00848     var params = [CPDictionary dictionaryWithObjectsAndKeys:@"message", @"name",
00849                                                             [_pubSubServer node], @"from"];
00850 
00851     if (_eventSelectorID)
00852         [_connection deleteRegisteredSelector:_eventSelectorID];
00853 
00854     _eventSelectorID = [_connection registerSelector:@selector(_didReceiveEvent:) ofObject:self withDict:params];
00855 }
00856 
00862 - (BOOL)_didReceiveEvent:(TNStropheStanza)aStanza
00863 {
00864     var pubsubEvent = [aStanza firstChildWithName:@"event"];
00865 
00866     if ([pubsubEvent namespace] != Strophe.NS.PUBSUB_EVENT)
00867         return YES;
00868 
00869     if ([pubsubEvent containsChildrenWithName:@"subscription"])
00870     {
00871         var subscription    = [pubsubEvent firstChildWithName:@"subscription"],
00872             status          = [subscription valueForAttribute:@"subscription"],
00873             nodeName        = [subscription valueForAttribute:@"node"];
00874 
00875         if (status === @"subscribed" && nodeName === _nodeName)
00876             [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubNodeSubscribedNotification object:self];
00877 
00878         return YES;
00879     }
00880 
00881     if (_nodeName != [[pubsubEvent firstChildWithName:@"items"] valueForAttribute:@"node"])
00882         return YES;
00883 
00884     if (_delegate && [_delegate respondsToSelector:@selector(pubSubNode:receivedEvent:)])
00885         [_delegate pubSubNode:self receivedEvent:aStanza];
00886 
00887     [[CPNotificationCenter defaultCenter] postNotificationName:TNStrophePubSubNodeEventNotification object:self userInfo:aStanza];
00888 
00889     return YES;
00890 }
00891 
00892 
00893 - (CPString)description
00894 {
00895     return _nodeName;
00896 }
00897 
00898 @end
00899 
00900 @implementation TNPubSubNode (CPSynthesizedAccessors)
00901 
00905 - (CPArray)content
00906 {
00907     return _content;
00908 }
00909 
00913 - (CPArray)subscriptionIDs
00914 {
00915     return _subscriptionIDs;
00916 }
00917 
00921 - (CPDictionary)affiliations
00922 {
00923     return _affiliations;
00924 }
00925 
00929 - (CPString)name
00930 {
00931     return _nodeName;
00932 }
00933 
00937 - (id)delegate
00938 {
00939     return _delegate;
00940 }
00941 
00945 - (void)setDelegate:(id)aValue
00946 {
00947     _delegate = aValue;
00948 }
00949 
00953 - (TNStropheJID)server
00954 {
00955     return _pubSubServer;
00956 }
00957 
00958 @end
 All Classes Namespaces Files Functions Variables