1 #import "JubGtkRosterUI.h"
2 #import "JubGObjectMap.h"
3 #import "JubGtkChatUI.h"
5 static gboolean filter_roster_by_presence(GtkTreeModel *model,
6 GtkTreeIter *iter, gpointer data)
10 OFCountedSet *presences = data;
12 gtk_tree_model_get(model, iter, 1, &jid_s, -1);
18 jid = [[OFString alloc] initWithUTF8String: jid_s];
22 int num = [presences countForObject: jid];
32 @implementation JubGtkRosterUI
33 - initWithBuilder: (GtkBuilder*)builder_
38 groupMap = [[OFMapTable alloc]
39 initWithKeyFunctions: keyFunctions
40 valueFunctions: rowRefFunctions];
41 contactMap = [[OFMutableDictionary alloc] init];
42 chatMap = [[OFMutableDictionary alloc] init];
43 presences = [[OFCountedSet alloc] init];
45 builder = g_object_ref(builder_);
47 roster_model = GTK_TREE_STORE(gtk_builder_get_object(builder,
50 roster_filter = GTK_TREE_MODEL_FILTER(
51 gtk_builder_get_object(builder, "RosterTreeModelFilter"));
53 gtk_tree_model_filter_set_visible_func(roster_filter,
54 filter_roster_by_presence, presences, NULL);
70 g_object_unref(roster_model);
73 g_object_unref(roster_filter);
75 g_object_unref(builder);
80 /* Presence handling */
81 static gboolean refilter_roster(gpointer data)
83 gtk_tree_model_filter_refilter(data);
88 - (void)connection: (XMPPConnection*)connection
89 didReceivePresence: (XMPPPresence*)presence
91 if ([presence.type isEqual: @"available"])
92 [presences addObject: [presence.from bareJID]];
93 else if ([presence.type isEqual: @"unavailable"])
94 [presences removeObject: [presence.from bareJID]];
96 g_idle_add(refilter_roster, roster_filter);
99 // FIXME: This needs to move somewhere else
100 - (void)connection: (XMPPConnection*)connection
101 didReceiveMessage: (XMPPMessage*)message
104 [chatMap objectForKey: [message.from bareJID]];
106 OFString * title = [@"Chat with " stringByAppendingString:
107 [message.from bareJID]];
109 chat = [[[JubGtkChatUI alloc]
112 [chatMap removeObjectForKey:
113 [message.from bareJID]];
115 sendBlock: ^(OFString *text) {
117 [XMPPMessage messageWithType: @"chat"];
118 msg.to = message.from;
120 [connection sendStanza: msg];
124 [chatMap setObject: chat
125 forKey: [message.from bareJID]];
128 [chat addMessage: message.body
129 sender: [message.from bareJID]];
132 /* Roster Delegate methods */
133 struct add_roster_item_param {
137 OFMapTable *groupMap;
138 OFMapTable *contactRows;
139 GtkTreeStore *roster_model;
142 static gboolean add_roster_item(gpointer user_data)
144 struct add_roster_item_param *params = user_data;
145 GtkTreeIter group_iter, contact_iter;
146 GtkTreeRowReference *group_ref, *contact_ref;
147 GtkTreePath *group_path, *contact_path;
149 group_ref = [params->groupMap valueForKey: params->group];
152 // Create new group row
153 gtk_tree_store_append(params->roster_model, &group_iter, NULL);
154 gtk_tree_store_set(params->roster_model, &group_iter,
155 0, [params->group UTF8String], -1);
157 group_path = gtk_tree_model_get_path(GTK_TREE_MODEL(
158 params->roster_model), &group_iter);
160 group_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(
161 params->roster_model), group_path);
163 [params->groupMap setValue: group_ref
164 forKey: params->group];
166 // Get iter for existing group row
167 group_path = gtk_tree_row_reference_get_path(group_ref);
169 gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model),
170 &group_iter, group_path);
172 gtk_tree_path_free(group_path);
174 // Create new contact row
175 gtk_tree_store_append(params->roster_model, &contact_iter, &group_iter);
176 gtk_tree_store_set(params->roster_model, &contact_iter,
177 0, [params->name UTF8String], 1, [params->jid UTF8String], -1);
179 contact_path = gtk_tree_model_get_path(GTK_TREE_MODEL(
180 params->roster_model), &contact_iter);
182 contact_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(
183 params->roster_model), contact_path);
185 gtk_tree_path_free(contact_path);
187 [params->contactRows setValue: contact_ref
188 forKey: params->group];
190 [params->group release];
191 [params->name release];
192 [params->jid release];
193 [params->groupMap release];
194 [params->contactRows release];
195 g_object_unref(params->roster_model);
201 struct remove_roster_item_param {
203 OFMapTable *groupMap;
204 OFMapTable *contactRows;
205 GtkTreeStore *roster_model;
208 static gboolean remove_roster_item(gpointer user_data)
210 struct remove_roster_item_param *params = user_data;
211 GtkTreeIter contact_iter, group_iter;
212 GtkTreePath *contact_path, *group_path;
213 GtkTreeRowReference *contact_ref, *group_ref;
215 contact_ref = [params->contactRows valueForKey: params->group];
216 contact_path = gtk_tree_row_reference_get_path(contact_ref);
217 gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model),
218 &contact_iter, contact_path);
220 gtk_tree_store_remove(params->roster_model, &contact_iter);
222 group_ref = [params->groupMap valueForKey: params->group];
223 group_path = gtk_tree_row_reference_get_path(group_ref);
224 gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model),
225 &group_iter, group_path);
227 if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(params->roster_model),
229 gtk_tree_store_remove(params->roster_model, &group_iter);
230 [params->groupMap removeValueForKey: params->group];
233 gtk_tree_path_free(group_path);
235 [params->group release];
236 [params->groupMap release];
237 [params->contactRows release];
238 g_object_unref(params->roster_model);
244 - (void)rosterWasReceived: (XMPPRoster*)roster_
246 of_log(@"Handling roster");
247 [[roster_ rosterItems] enumerateKeysAndObjectsUsingBlock:
248 ^(OFString *bareJID, XMPPRosterItem *item, BOOL *stop) {
250 OFMapTable *contactRows = [OFMapTable
251 mapTableWithKeyFunctions: keyFunctions
252 valueFunctions: rowRefFunctions];
254 [contactMap setObject: contactRows
257 if (item.groups != nil)
258 groups = item.groups;
260 groups = @[@"General"];
262 for (OFString *group in groups) {
263 struct add_roster_item_param *params =
264 malloc(sizeof(*params));
265 params->group = [group retain];
266 params->name = [item.name retain];
267 params->jid = [bareJID retain];
268 params->groupMap = [groupMap retain];
269 params->contactRows = [contactRows retain];
270 params->roster_model = g_object_ref(roster_model);
271 g_idle_add(add_roster_item, params);
276 - (void)roster: (XMPPRoster*)roster_
277 didReceiveRosterItem: (XMPPRosterItem*)item
280 XMPPRosterItem *oldItem =
281 [roster_.rosterItems objectForKey: [item.JID bareJID]];
284 if (oldItem.groups != nil)
285 groups = oldItem.groups;
287 groups = @[@"General"];
289 for (OFString *group in groups) {
290 struct remove_roster_item_param *params =
291 malloc(sizeof(*params));
292 params->group = [group retain];
293 params->contactRows = [[contactMap objectForKey:
294 [oldItem.JID bareJID]] retain];
295 params->groupMap = [groupMap retain];
296 params->roster_model = g_object_ref(roster_model);
297 g_idle_add(remove_roster_item, params);
300 [contactMap removeObjectForKey: [item.JID bareJID]];
303 if (![item.subscription isEqual: @"remove"]) {
304 OFMapTable *contactRows = [OFMapTable
305 mapTableWithKeyFunctions: keyFunctions
306 valueFunctions: rowRefFunctions];
308 [contactMap setObject: contactRows
309 forKey: [item.JID bareJID]];
311 if (item.groups != nil)
312 groups = item.groups;
314 groups = @[@"General"];
316 for (OFString *group in groups) {
317 struct add_roster_item_param *params =
318 malloc(sizeof(*params));
319 params->group = [group retain];
320 params->name = [item.name retain];
321 params->jid = [[item.JID bareJID] retain];
322 params->groupMap = [groupMap retain];
323 params->contactRows = [contactRows retain];
324 params->roster_model = g_object_ref(roster_model);
325 g_idle_add(add_roster_item, params);