#import <ObjFW/ObjFW.h>
#import "JubUI.h"
+#import "JubChatUI.h"
#import "JubConfig.h"
@interface JubChatClient : OFObject <XMPPConnectionDelegate, XMPPRosterDelegate>
{
+ OFMutableDictionary *chatMap;
XMPPConnection *connection;
XMPPRoster *roster;
XMPPStreamManagement *streamManagement;
@property (assign) id<JubUI> ui;
- initWithConfig: (JubConfig*)config;
+- (id<JubChatUI>)chatForContact: (XMPPContact*)contact;
@end
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;
[streamManagement release];
[connection release];
[presence release];
+ [chatMap release];
[super dealloc];
}
+- (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)connection: (XMPPConnection*)connection_
wasBoundToJID: (XMPPJID*)jid
{
--- /dev/null
+@class OFString;
+
+typedef void (^jub_send_block_t)(OFString *);
+typedef void (^jub_close_block_t)(void);
+
+@protocol JubChatUI
+- initWithTitle: (OFString*)title
+ closeBlock: (jub_close_block_t)closeBlock
+ sendBlock: (jub_send_block_t)sendBlock;
+
+- (void)addMessage: (OFString*)text
+ sender: (OFString*)sender;
+@end
- (void)startUIThread;
- (void)client: (JubChatClient*)client
didChangePresence: (XMPPPresence*)presence;
+- (Class)chatUIClass;
@end
#import <ObjXMPP/ObjXMPP.h>
#include <gtk/gtk.h>
-typedef void (^jub_send_block_t)(OFString *);
-typedef void (^jub_close_block_t)(void);
+#import "JubChatUI.h"
-@interface JubGtkChatUI: OFObject
+@interface JubGtkChatUI: OFObject <JubChatUI>
{
GtkWidget *chat_window;
GtkTextView *chat_view;
jub_close_block_t closeBlock;
BOOL bufferEmpty;
}
-
-- initWithTitle: (OFString*)title
- closeBlock: (jub_close_block_t)closeBlock
- sendBlock: (jub_send_block_t)sendBlock;
-
-- (void)addMessage: (OFString*)text
- sender: (OFString*)sender;
@end
gulong presence_combo_changed_handler_id;
OFMapTable *groupMap;
OFMutableDictionary *contactMap;
- OFMutableDictionary *chatMap;
JubChatClient *client;
}
- initWithClient: (JubChatClient*)client;
-- (JubGtkChatUI*)chatForJID: (XMPPJID*)jid;
- (void)client: (JubChatClient*)client
didChangePresence: (XMPPPresence*)presence;
@end
static void roster_row_activated(GtkTreeView *tree_view, GtkTreePath *path,
GtkTreeViewColumn *column, gpointer data)
{
- JubGtkRosterUI *roster = data;
+ OFAutoreleasePool *pool;
+ XMPPContact *contact;
+ JubChatClient *client = data;
GtkTreeIter row_iter;
GtkTreeModel *tree_model;
gchar *jid_s;
- XMPPJID *jid;
- OFAutoreleasePool *pool;
+ OFString *jid;
tree_model = gtk_tree_view_get_model(tree_view);
gtk_tree_model_get_iter(tree_model, &row_iter, path);
if (!jid_s) return;
pool = [OFAutoreleasePool new];
- jid = [XMPPJID JIDWithString: [OFString stringWithUTF8String: jid_s]];
- [roster performSelectorOnMainThread: @selector(chatForJID:)
- withObject: jid
+ jid = [OFString stringWithUTF8String: jid_s];
+ contact = [client.contactManager.contacts objectForKey: jid];
+
+ [client performSelectorOnMainThread: @selector(chatForContact:)
+ withObject: contact
waitUntilDone: NO];
[pool release];
}
initWithKeyFunctions: keyFunctions
valueFunctions: rowRefFunctions];
contactMap = [[OFMutableDictionary alloc] init];
- chatMap = [[OFMutableDictionary alloc] init];
client = [client_ retain];
[client.contactManager addDelegate: self];
"RosterTreeView"));
g_signal_connect(roster_view, "row_activated",
- G_CALLBACK(roster_row_activated), self);
+ G_CALLBACK(roster_row_activated), client);
presence_combo = GTK_COMBO_BOX(gtk_builder_get_object(builder,
"PresenceComboBox"));
[client.contactManager removeDelegate: self];
[groupMap release];
[contactMap release];
- [chatMap release];
[client release];
gtk_widget_destroy(roster_window);
[super dealloc];
}
-// FIXME: This needs to move somewhere else
-- (JubGtkChatUI*)chatForJID: (XMPPJID*)jid
-{
- OFAutoreleasePool *pool = [OFAutoreleasePool new];
- JubGtkChatUI *chat =
- [chatMap objectForKey: [jid bareJID]];
- if (chat == nil) {
- OFString * title = [@"Chat with " stringByAppendingString:
- [jid bareJID]];
-
- chat = [[[JubGtkChatUI alloc]
- initWithTitle: title
- closeBlock: ^{
- [chatMap removeObjectForKey: [jid bareJID]];
- }
- sendBlock: ^(OFString *text) {
- XMPPMessage *msg =
- [XMPPMessage messageWithType: @"chat"];
- msg.to = jid;
- msg.body = text;
- [client.connection sendStanza: msg];
- }
- ] autorelease];
-
- [chatMap setObject: chat
- forKey: [jid bareJID]];
- }
-
- [pool release];
-
- return chat;
-}
-
- (void)contact: (XMPPContact*)contact
didSendMessage: (XMPPMessage*)message
{
if (message.body == nil || ![message.type isEqual: @"chat"])
return;
- JubGtkChatUI *chat = [self chatForJID: message.from];
+ id<JubChatUI> chat = [client chatForContact: contact];
[chat addMessage: message.body
sender: [message.from bareJID]];
}
#include <gtk/gtk.h>
#import "JubGtkUI.h"
+#import "JubGtkChatUI.h"
#import "JubGtkRosterUI.h"
void on_roster_window_destroy(GObject *object, gpointer user_data)
}] start];
}
+- (Class)chatUIClass
+{
+ return [JubGtkChatUI class];
+}
+
- (void)client: (JubChatClient*)client
didChangePresence: (XMPPPresence*)presence
{