StropheCappuccino API 1.0.0
/tmp/tempDoc.doc/TNStropheClient.j
Go to the documentation of this file.
00001 /*
00002  * TNStropheClient.j
00003  *
00004  * Copyright (C) 2010  Ben Langfeld <ben@langfeld.me>
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 @global TNStropheContactStatusOffline
00024 @global TNStropheContactStatusOnline
00025 
00026 TNStropheClientPasswordChangedNotification      = @"TNStropheClientPasswordChangedNotification";
00027 TNStropheClientPasswordChangeErrorNotification  = @"TNStropheClientPasswordChangeErrorNotification";
00028 TNStropheClientPresenceUpdatedNotification      = @"TNStropheClientPresenceUpdatedNotification";
00029 TNStropheClientVCardReceivedNotification        = @"TNStropheClientVCardReceivedNotification";
00030 
00031 
00032 @implementation TNStropheClient : CPObject
00033 {
00034     CPArray             _features;
00035     CPString            _clientNode;
00036     CPString            _identityCategory;
00037     CPString            _identityName;
00038     CPString            _identityType;
00039     CPString            _password;
00040     id                  _delegate;
00041     TNStropheConnection _connection;
00042     TNStropheJID        _JID;
00043     TNStropheVCard      _vCard;
00044     CPImage             _avatar;
00045 
00046     CPString            _userPresenceShow;
00047     CPString            _userPresenceStatus;
00048 }
00049 
00050 #pragma mark -
00051 #pragma mark Class methods
00052 
00053 + (void)addNamespaceWithName:(CPString)aName value:(CPString)aValue
00054 {
00055     Strophe.addNamespace(aName, aValue);
00056 }
00057 
00064 + (TNStropheClient)clientWithService:(CPString)aService
00065 {
00066     return [[TNStropheClient alloc] initWithService:aService];
00067 }
00068 
00077 + (TNStropheClient)clientWithService:(CPString)aService JID:(TNStropheJID)aJID password:(CPString)aPassword
00078 {
00079     return [[TNStropheClient alloc] initWithService:aService JID:aJID password:aPassword];
00080 }
00081 
00082 
00083 #pragma mark -
00084 #pragma mark Initialization
00085 
00090 - (id)initWithService:(CPString)aService
00091 {
00092     if (self = [super init])
00093     {
00094         _connection                 = [TNStropheConnection connectionWithService:aService andDelegate:self];
00095         _userPresenceShow           = TNStropheContactStatusOffline;
00096         _userPresenceStatus         = @"";
00097         _clientNode                 = @"http://cappuccino.org";
00098         _identityCategory           = @"client";
00099         _identityName               = @"StropheCappuccino";
00100         _identityType               = @"web";
00101         _features                   = [Strophe.NS.CAPS, Strophe.NS.DISCO_INFO, Strophe.NS.DISCO_ITEMS];
00102     }
00103 
00104     return self;
00105 }
00106 
00113 - (id)initWithService:(CPString)aService JID:(TNStropheJID)aJID password:(CPString)aPassword
00114 {
00115     if (self = [self initWithService:aService])
00116     {
00117         _JID        = aJID;
00118         _password   = aPassword;
00119     }
00120 
00121     return self;
00122 }
00123 
00124 
00125 #pragma mark -
00126 #pragma mark Connection
00127 
00128 - (void)connect
00129 {
00130     var pingDict = [CPDictionary dictionaryWithObjectsAndKeys:@"iq", @"name", @"get", @"type"];
00131     [_connection registerSelector:@selector(_didReceivePing:) ofObject:self withDict:pingDict];
00132     [_connection connectWithJID:_JID andPassword:_password];
00133 }
00134 
00135 - (void)disconnect
00136 {
00137     [_connection disconnect];
00138 }
00139 
00140 - (void)onStropheConnecting:(TNStropheConnection)aConnection
00141 {
00142     if ([_delegate respondsToSelector:@selector(onStropheConnecting:)])
00143         [_delegate onStropheConnecting:self];
00144 }
00145 
00146 - (void)onStropheConnected:(TNStropheConnection)aConnection
00147 {
00148     [self _sendCAPS];
00149 
00150     if ([_delegate respondsToSelector:@selector(onStropheConnected:)])
00151         [_delegate onStropheConnected:self];
00152 }
00153 
00154 - (void)onStropheConnectFail:(TNStropheConnection)aConnection
00155 {
00156     if ([_delegate respondsToSelector:@selector(onStropheConnectFail:)])
00157         [_delegate onStropheConnectFail:self];
00158 }
00159 
00160 - (void)onStropheDisconnecting:(TNStropheConnection)aConnection
00161 {
00162     if ([_delegate respondsToSelector:@selector(onStropheDisconnecting:)])
00163         [_delegate onStropheDisconnecting:self];
00164 }
00165 
00166 - (void)onStropheDisconnected:(TNStropheConnection)aConnection
00167 {
00168     _userPresenceShow   = TNStropheContactStatusOffline;
00169     _userPresenceStatus = @"";
00170     if ([_delegate respondsToSelector:@selector(onStropheDisconnected:)])
00171         [_delegate onStropheDisconnected:self];
00172 }
00173 
00174 - (void)onStropheAuthenticating:(TNStropheConnection)aConnection
00175 {
00176     if ([_delegate respondsToSelector:@selector(onStropheAuthenticating:)])
00177         [_delegate onStropheAuthenticating:self];
00178 }
00179 
00180 - (void)onStropheAuthFail:(TNStropheConnection)aConnection
00181 {
00182     if ([_delegate respondsToSelector:@selector(onStropheAuthFail:)])
00183         [_delegate onStropheAuthFail:self];
00184 }
00185 
00186 - (void)onStropheError:(TNStropheConnection)aConnection
00187 {
00188     if ([_delegate respondsToSelector:@selector(onStropheError:)])
00189         [_delegate onStropheError:self];
00190 }
00191 
00192 - (void)connection:(TNStropheConnection)aConnection errorCondition:(CPString)anErrorCondition
00193 {
00194     if ([_delegate respondsToSelector:@selector(client:errorCondition:)])
00195         [_delegate client:self errorCondition:anErrorCondition];
00196 }
00197 
00198 
00199 #pragma mark -
00200 #pragma mark Features
00201 
00202 - (void)_sendInitialPresence
00203 {
00204     var presenceHandleParams = [CPDictionary dictionaryWithObjectsAndKeys:@"presence", @"name", [_JID bare], @"from", {@"matchBare": true}, @"options"];
00205     [_connection registerSelector:@selector(_didPresenceUpdate:) ofObject:self withDict:presenceHandleParams];
00206     [self setPresenceShow:TNStropheContactStatusOnline status:@""];
00207 }
00208 
00209 - (BOOL)_didReceivePing:(TNStropheStanza)aStanza
00210 {
00211     if ([aStanza containsChildrenWithName:@"ping"] && [[aStanza firstChildWithName:@"ping"] namespace] == Strophe.NS.PING)
00212     {
00213         CPLog.debug("Ping received. Sending pong.");
00214         [_connection send:[TNStropheStanza iqWithAttributes:{'to': [[aStanza from] bare], 'id': [aStanza ID], 'type': 'result'}]];
00215     }
00216     return YES;
00217 }
00218 
00219 - (void)addFeature:(CPString)aFeatureNamespace
00220 {
00221     [_features addObject:aFeatureNamespace];
00222 }
00223 
00224 - (void)removeFeature:(CPString)aFeatureNamespace
00225 {
00226     [_features removeObjectIdenticalTo:aFeatureNamespace];
00227 }
00228 
00229 - (CPString)_clientVer
00230 {
00231     return SHA1.b64_sha1(_features.join());
00232 }
00233 
00234 - (void)_sendCAPS
00235 {
00236     var caps = [TNStropheStanza presence];
00237     [caps addChildWithName:@"c" andAttributes:{ "xmlns":Strophe.NS.CAPS, "node":_clientNode, "hash":"sha-1", "ver":[self _clientVer] }];
00238 
00239     [_connection registerSelector:@selector(handleFeaturesDisco:)
00240                   ofObject:self
00241                   withDict:[CPDictionary dictionaryWithObjectsAndKeys:@"iq", @"name", @"get", @"type", Strophe.NS.DISCO_INFO, "namespace"]];
00242 
00243     [_connection send:caps];
00244 }
00245 
00246 - (BOOL)handleFeaturesDisco:(TNStropheStanza)aStanza
00247 {
00248     var resp = [TNStropheStanza iqWithAttributes:{"id":[_connection getUniqueId], "type":"result"}];
00249 
00250     [resp setTo:[aStanza from]];
00251 
00252     [resp addChildWithName:@"query" andAttributes:{"xmlns":Strophe.NS.DISCO_INFO, "node":(_clientNode + '#' + [self _clientVer])}];
00253     [resp addChildWithName:@"identity" andAttributes:{"category":_identityCategory, "name":_identityName, "type":_identityType}];
00254     [resp up];
00255 
00256     for (var i = 0; i < [_features count]; i++)
00257     {
00258         [resp addChildWithName:@"feature" andAttributes:{"var":[_features objectAtIndex:i]}];
00259         [resp up];
00260     }
00261 
00262     [_connection send:resp];
00263 
00264     return YES;
00265 }
00266 
00271 - (void)publishPEPPayload:(TNXMLNode)aPayload toNode:(CPString)aNode
00272 {
00273     var uid     = [_connection getUniqueId],
00274         stanza  = [TNStropheStanza iqWithAttributes:{"type":"set", "id":uid}],
00275         params  = [CPDictionary dictionaryWithObject:uid forKey:@"id"];
00276 
00277     [stanza addChildWithName:@"pubsub" andAttributes:{"xmlns":Strophe.NS.PUBSUB}]
00278     [stanza addChildWithName:@"publish" andAttributes:{"node":aNode}];
00279     [stanza addChildWithName:@"item"];
00280     [stanza addNode:aPayload];
00281 
00282     [_connection registerSelector:@selector(_didPublishPEP:) ofObject:self withDict:params];
00283     [_connection send:stanza];
00284 }
00285 
00286 - (void)_didPublishPEP:(TNStropheStanza)aStanza
00287 {
00288     if ([aStanza type] == @"result")
00289         CPLog.debug("Publish succeeded!");
00290     else
00291         CPLog.error("Cannot publish the pubsub item:" + [aStanza stringValue]);
00292 
00293     return NO;
00294 }
00295 
00296 
00297 #pragma mark -
00298 #pragma mark Presence
00299 
00300 - (void)setPresenceShow:(CPString)aPresenceShow status:(CPString)aStatus
00301 {
00302     if (aPresenceShow === _userPresenceShow && aStatus === _userPresenceStatus)
00303         return;
00304 
00305     var presence = [TNStropheStanza presence];
00306 
00307     _userPresenceShow   = aPresenceShow || _userPresenceShow;
00308     _userPresenceStatus = aStatus || _userPresenceStatus;
00309 
00310     [presence addChildWithName:@"status"];
00311     [presence addTextNode:_userPresenceStatus];
00312     [presence up];
00313     [presence addChildWithName:@"show"];
00314     [presence addTextNode:_userPresenceShow];
00315 
00316     [_connection send:presence];
00317 }
00318 
00319 - (BOOL)_didPresenceUpdate:(TNStropheStanza)aStanza
00320 {
00321     var shouldNotify = NO;
00322 
00323     if ([aStanza firstChildWithName:@"show"])
00324     {
00325         _userPresenceShow = [[aStanza firstChildWithName:@"show"] text];
00326         shouldNotify = YES;
00327     }
00328 
00329     if ([aStanza firstChildWithName:@"status"])
00330     {
00331         _userPresenceStatus = [[aStanza firstChildWithName:@"status"] text];
00332         shouldNotify = YES;
00333     }
00334 
00335     if (shouldNotify)
00336     {
00337         var presenceInformation = [CPDictionary dictionaryWithObjectsAndKeys:_userPresenceShow, @"show", _userPresenceStatus, @"status"];
00338         [[CPNotificationCenter defaultCenter] postNotificationName:TNStropheClientPresenceUpdatedNotification object:self userInfo:presenceInformation];
00339     }
00340 
00341     return YES;
00342 }
00343 
00344 
00345 #pragma mark -
00346 #pragma mark vCard
00347 
00350 - (void)getVCard
00351 {
00352     var uid         = [_connection getUniqueId],
00353         vcardStanza = [TNStropheStanza iqWithAttributes:{@"type": @"get", @"id": uid}],
00354         params      = [CPDictionary dictionaryWithObjectsAndKeys: uid, @"id"];
00355 
00356     [vcardStanza addChildWithName:@"vCard" andAttributes:{@"xmlns": @"vcard-temp"}];
00357     [_connection registerSelector:@selector(_didReceiveCurrentUserVCard:) ofObject:self withDict:params];
00358     [_connection send:vcardStanza];
00359 }
00360 
00364 - (BOOL)_didReceiveCurrentUserVCard:(TNStropheStanza)aStanza
00365 {
00366     if ([aStanza type] == @"result")
00367     {
00368         _vCard = [[TNStropheVCard alloc] initWithXMLNode:[aStanza firstChildWithName:@"vCard"]];
00369         _avatar = [_vCard photo];
00370     }
00371 
00372     [[CPNotificationCenter defaultCenter] postNotificationName:TNStropheClientVCardReceivedNotification object:self userInfo:aStanza];
00373 
00374     return YES;
00375 }
00376 
00383 - (void)setVCard:(TNXMLNode)aVCard object:(CPObject)anObject selector:(SEL)aSelector userInfo:(id)someUserInfo
00384 {
00385     var uid     = [_connection getUniqueId],
00386         stanza  = [TNStropheStanza iqWithAttributes:{@"id": uid, @"type": @"set"}],
00387         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00388 
00389     _vCard = aVCard;
00390 
00391     [stanza addNode:[_vCard XMLNode]];
00392 
00393     [_connection registerSelector:@selector(notifyVCardUpdate:) ofObject:self withDict:params];
00394     [_connection registerSelector:aSelector ofObject:anObject withDict:params userInfo:someUserInfo];
00395     [_connection send:stanza];
00396 }
00397 
00400 - (void)notifyVCardUpdate:(TNStropheStanza)aStanza
00401 {
00402     var uid     = [_connection getUniqueId],
00403         stanza  = [TNStropheStanza presenceWithAttributes:{@"id": uid}],
00404         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00405 
00406     [stanza addChildWithName:@"status"];
00407     [stanza addTextNode:_userPresenceStatus];
00408     [stanza up]
00409     [stanza addChildWithName:@"show"];
00410     [stanza addTextNode:_userPresenceShow];
00411     [stanza up]
00412     [stanza addChildWithName:@"x" andAttributes:{"xmlns": "vcard-temp:x:update"}];
00413 
00414     // debug
00415     //[_connection registerSelector:@selector(_didNotifyVCardUpdate:) ofObject:self withDict:params];
00416 
00417     [_connection send:stanza];
00418 }
00419 
00422 - (void)_didNotifyVCardUpdate:(TNStropheStanza)aStanza
00423 {
00424     CPLog.trace([aStanza stringValue]);
00425 }
00426 
00427 
00428 #pragma mark -
00429 #pragma mark Password management
00430 
00434 - (void)changePassword:(CPString)aPassword
00435 {
00436     var uid     = [_connection getUniqueId],
00437         stanza  = [TNStropheStanza iqWithAttributes:{@"id": uid, @"type": "set"}],
00438         params  = [CPDictionary dictionaryWithObjectsAndKeys:uid, @"id"];
00439 
00440     [stanza addChildWithName:@"query" andAttributes:{"xmlns": @"jabber:iq:register"}];
00441 
00442     [stanza addChildWithName:@"username"];
00443     [stanza addTextNode:[[_connection JID] node]];
00444     [stanza up]
00445 
00446     [stanza addChildWithName:@"password"];
00447     [stanza addTextNode:aPassword];
00448     [stanza up]
00449 
00450     [_connection registerSelector:@selector(_didChangePassword:) ofObject:self withDict:params];
00451     [_connection send:stanza];
00452 }
00453 
00458 - (void)_didChangePassword:(TNStropheStanza)aStanza
00459 {
00460     if ([aStanza type] == @"result")
00461         [[CPNotificationCenter defaultCenter] postNotificationName:TNStropheClientPasswordChangedNotification object:self userInfo:aStanza];
00462     else
00463         [[CPNotificationCenter defaultCenter] postNotificationName:TNStropheClientPasswordChangeErrorNotification object:self userInfo:aStanza];
00464 }
00465 
00466 @end
00467 
00468 @implementation TNStropheClient (CPCoding)
00469 
00470 - (id)initWithCoder:(CPCoder)aCoder
00471 {
00472     self = [super initWithCoder:aCoder];
00473 
00474     if (self)
00475     {
00476         _JID        = [aCoder decodeObjectForKey:@"_JID"];
00477         _password   = [aCoder decodeObjectForKey:@"_password"];
00478         _delegate   = [aCoder decodeObjectForKey:@"_delegate"];
00479         _connection = [aCoder decodeObjectForKey:@"_connection"];
00480     }
00481 
00482     return self;
00483 }
00484 
00485 - (void)encodeWithCoder:(CPCoder)aCoder
00486 {
00487     [super encodeWithCoder:aCoder];
00488     [aCoder encodeObject:_JID forKey:@"_JID"];
00489     [aCoder encodeObject:_password forKey:@"_password"];
00490     [aCoder encodeObject:_connection forKey:@"_connection"];
00491 }
00492 
00493 @end
00494 
00495 @implementation TNStropheClient (CPSynthesizedAccessors)
00496 
00500 - (CPArray)_features
00501 {
00502     return _features;
00503 }
00504 
00508 - (void)set_features:(CPArray)aValue
00509 {
00510     _features = aValue;
00511 }
00512 
00516 - (CPString)clientNode
00517 {
00518     return _clientNode;
00519 }
00520 
00524 - (void)setClientNode:(CPString)aValue
00525 {
00526     _clientNode = aValue;
00527 }
00528 
00532 - (CPString)identityCategory
00533 {
00534     return _identityCategory;
00535 }
00536 
00540 - (void)setIdentityCategory:(CPString)aValue
00541 {
00542     _identityCategory = aValue;
00543 }
00544 
00548 - (CPString)identityName
00549 {
00550     return _identityName;
00551 }
00552 
00556 - (void)setIdentityName:(CPString)aValue
00557 {
00558     _identityName = aValue;
00559 }
00560 
00564 - (CPString)identityType
00565 {
00566     return _identityType;
00567 }
00568 
00572 - (void)setIdentityType:(CPString)aValue
00573 {
00574     _identityType = aValue;
00575 }
00576 
00580 - (CPString)password
00581 {
00582     return _password;
00583 }
00584 
00588 - (void)setPassword:(CPString)aValue
00589 {
00590     _password = aValue;
00591 }
00592 
00596 - (id)delegate
00597 {
00598     return _delegate;
00599 }
00600 
00604 - (void)setDelegate:(id)aValue
00605 {
00606     _delegate = aValue;
00607 }
00608 
00612 - (TNStropheConnection)connection
00613 {
00614     return _connection;
00615 }
00616 
00620 - (void)setConnection:(TNStropheConnection)aValue
00621 {
00622     _connection = aValue;
00623 }
00624 
00628 - (TNStropheJID)JID
00629 {
00630     return _JID;
00631 }
00632 
00636 - (void)setJID:(TNStropheJID)aValue
00637 {
00638     _JID = aValue;
00639 }
00640 
00644 - (TNStropheVCard)vCard
00645 {
00646     return _vCard;
00647 }
00648 
00652 - (CPImage)avatar
00653 {
00654     return _avatar;
00655 }
00656 
00657 @end
 All Classes Namespaces Files Functions Variables