#import "JubChatClient.h"
+#import "ObjXMPP/namespaces.h"
+
+#import "JubAvatarManager.h"
+
+#define JUB_CLIENT_URI @"http://babelmonkeys.de/jubjub"
@implementation JubChatClient
-@synthesize connection;
-@synthesize roster;
-@synthesize ui;
+@synthesize connection = _connection;
+@synthesize roster = _roster;
+@synthesize avatarManager = _avatarManager;
+@synthesize contactManager = _contactManager;
+@synthesize discoEntity = _discoEntity;
+@synthesize presence = _presence;
+@synthesize ui = _ui;
- initWithConfig: (JubConfig*)config
{
self = [super init];
@try {
- connection = [XMPPConnection new];
+ _chatMap = [[OFMutableDictionary alloc] init];
+
+ _connection = [XMPPConnection new];
+ _connection.username = config.username;
+ _connection.domain = config.domain;
+ _connection.server = config.server;
+ _connection.password = config.password;
+ [_connection addDelegate: self];
+
+ _roster = [[XMPPRoster alloc] initWithConnection: _connection];
+ [_roster addDelegate: self];
+
+ _discoEntity =
+ [[XMPPDiscoEntity alloc] initWithConnection: _connection
+ capsNode: JUB_CLIENT_URI];
- connection.username = config.username;
- connection.domain = config.domain;
- connection.server = config.server;
- connection.password = config.password;
- [connection addDelegate: self];
+ XMPPDiscoIdentity *identity =
+ [XMPPDiscoIdentity identityWithCategory: @"client"
+ type: @"pc"
+ name: @"JubJub"];
+ [_discoEntity addIdentity: identity];
+ [_discoEntity addFeature: XMPP_NS_CAPS];
- roster = [[XMPPRoster alloc] initWithConnection: connection];
- [roster addDelegate: self];
+ _avatarManager =
+ [[JubAvatarManager alloc] initWithClient: self];
- streamManagement = [[XMPPStreamManagement alloc]
- initWithConnection: connection];
+ _contactManager = [[XMPPContactManager alloc]
+ initWithConnection: _connection
+ roster: _roster];
+ [_contactManager addDelegate: self];
- [connection asyncConnectAndHandle];
+ _streamManagement = [[XMPPStreamManagement alloc]
+ initWithConnection: _connection];
} @catch (id e) {
[self release];
@throw e;
- (void)dealloc
{
- [roster release];
- [streamManagement release];
- [connection release];
+ [_roster removeDelegate: self];
+ [_contactManager removeDelegate: self];
+ [_connection removeDelegate: self];
+
+ [_roster release];
+ [_contactManager release];
+ [_discoEntity release];
+ [_streamManagement release];
+ [_avatarManager release];
+ [_connection release];
+ [_presence release];
+ [_chatMap release];
[super dealloc];
}
-- (void)connection: (XMPPConnection*)conn_
+- (id<JubChatUI>)chatForContact: (XMPPContact*)contact
+{
+ OFAutoreleasePool *pool = [OFAutoreleasePool new];
+ OFString *bareJID = [contact.rosterItem.JID bareJID];
+
+ id<JubChatUI> chat = [_chatMap objectForKey: bareJID];
+ if (chat == nil) {
+ OFString * title =
+ [@"Chat with " stringByAppendingString: bareJID];
+
+ chat = [[[[_ui chatUIClass] alloc]
+ initWithTitle: title
+ closeBlock: ^{
+ [_chatMap removeObjectForKey: bareJID];
+ }
+ sendBlock: ^(OFString *text) {
+ XMPPMessage *msg =
+ [XMPPMessage messageWithType: @"chat"];
+ msg.body = text;
+ [contact sendMessage: msg
+ connection: _connection];
+ }
+ ] autorelease];
+
+ [_chatMap setObject: chat
+ forKey: bareJID];
+ }
+
+ [pool release];
+
+ return chat;
+}
+
+- (void)sendPresenceWithStatus: (OFString*)status
+{
+ [self sendPresenceWithStatus: status
+ text: nil];
+}
+
+- (void)sendPresenceWithStatus: (OFString*)status
+ text: (OFString*)text
+{
+ XMPPPresence *presence;
+
+ if ([status isEqual: @"unavailable"])
+ presence = [XMPPPresence presenceWithType: @"unavailable"];
+ else
+ presence = [XMPPPresence presence];
+
+ if (!([status isEqual: @"available"] ||
+ [status isEqual: @"unavailable"]))
+ presence.show = status;
+
+ if (text != nil)
+ presence.status = text;
+
+ OFXMLElement *caps = [OFXMLElement elementWithName: @"c"
+ namespace: XMPP_NS_CAPS];
+ [caps addAttributeWithName: @"hash"
+ stringValue: @"sha-1"];
+ [caps addAttributeWithName: @"ver"
+ stringValue: [_discoEntity capsHash]];
+ [caps addAttributeWithName: @"node"
+ stringValue: JUB_CLIENT_URI];
+
+ [presence addChild: caps];
+
+ [_connection sendStanza: presence];
+}
+
+- (void)connection: (XMPPConnection*)connection
wasBoundToJID: (XMPPJID*)jid
{
- of_log(@"Bound to JID: %@", [jid fullJID]);
+ [_roster requestRoster];
+}
+
+- (void)connection: (XMPPConnection*)connection
+ didReceivePresence: (XMPPPresence*)presence
+{
+ if ([presence.from isEqual: connection.JID]) {
+ [_ui client: self
+ didChangePresence: presence];
+ OF_SETTER(_presence, presence, true, 0);
+ }
+}
+
+- (void)contact: (XMPPContact*)contact
+ didSendMessage: (XMPPMessage*)message
+{
+ if (message.body == nil || ![message.type isEqual: @"chat"])
+ return;
- [roster requestRoster];
+ id<JubChatUI> chat = [self chatForContact: contact];
+ [chat addMessage: message.body
+ sender: [message.from bareJID]];
}
- (void)rosterWasReceived: (XMPPRoster*)roster
{
- [connection sendStanza: [XMPPPresence presence]];
+ [self sendPresenceWithStatus: @"available"
+ text: @"Hello from JubJub"];
}
@end