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);
177 gtk_tree_store_set(params->roster_model, &contact_iter,
178 0, [params->name UTF8String],
179 1, [[params->jid bareJID] UTF8String], -1);
181 gtk_tree_store_set(params->roster_model, &contact_iter,
182 0, [params->jid.node UTF8String],
183 1, [[params->jid bareJID] UTF8String], -1);
185 contact_path = gtk_tree_model_get_path(GTK_TREE_MODEL(
186 params->roster_model), &contact_iter);
188 contact_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(
189 params->roster_model), contact_path);
191 gtk_tree_path_free(contact_path);
193 [params->contactRows setValue: contact_ref
194 forKey: params->group];
196 [params->group release];
197 [params->name release];
198 [params->jid release];
199 [params->groupMap release];
200 [params->contactRows release];
201 g_object_unref(params->roster_model);
207 struct remove_roster_item_param {
209 OFMapTable *groupMap;
210 OFMapTable *contactRows;
211 GtkTreeStore *roster_model;
214 static gboolean remove_roster_item(gpointer user_data)
216 struct remove_roster_item_param *params = user_data;
217 GtkTreeIter contact_iter, group_iter;
218 GtkTreePath *contact_path, *group_path;
219 GtkTreeRowReference *contact_ref, *group_ref;
221 contact_ref = [params->contactRows valueForKey: params->group];
222 contact_path = gtk_tree_row_reference_get_path(contact_ref);
223 gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model),
224 &contact_iter, contact_path);
226 gtk_tree_store_remove(params->roster_model, &contact_iter);
228 group_ref = [params->groupMap valueForKey: params->group];
229 group_path = gtk_tree_row_reference_get_path(group_ref);
230 gtk_tree_model_get_iter(GTK_TREE_MODEL(params->roster_model),
231 &group_iter, group_path);
233 if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(params->roster_model),
235 gtk_tree_store_remove(params->roster_model, &group_iter);
236 [params->groupMap removeValueForKey: params->group];
239 gtk_tree_path_free(group_path);
241 [params->group release];
242 [params->groupMap release];
243 [params->contactRows release];
244 g_object_unref(params->roster_model);
250 - (void)rosterWasReceived: (XMPPRoster*)roster_
252 of_log(@"Handling roster");
253 [[roster_ rosterItems] enumerateKeysAndObjectsUsingBlock:
254 ^(OFString *bareJID, XMPPRosterItem *item, BOOL *stop) {
256 OFMapTable *contactRows = [OFMapTable
257 mapTableWithKeyFunctions: keyFunctions
258 valueFunctions: rowRefFunctions];
260 [contactMap setObject: contactRows
263 if (item.groups != nil)
264 groups = item.groups;
266 groups = @[@"General"];
268 for (OFString *group in groups) {
269 struct add_roster_item_param *params =
270 malloc(sizeof(*params));
271 params->group = [group retain];
272 params->name = [item.name retain];
273 params->jid = [item.JID retain];
274 params->groupMap = [groupMap retain];
275 params->contactRows = [contactRows retain];
276 params->roster_model = g_object_ref(roster_model);
277 g_idle_add(add_roster_item, params);
282 - (void)roster: (XMPPRoster*)roster_
283 didReceiveRosterItem: (XMPPRosterItem*)item
286 XMPPRosterItem *oldItem =
287 [roster_.rosterItems objectForKey: [item.JID bareJID]];
290 if (oldItem.groups != nil)
291 groups = oldItem.groups;
293 groups = @[@"General"];
295 for (OFString *group in groups) {
296 struct remove_roster_item_param *params =
297 malloc(sizeof(*params));
298 params->group = [group retain];
299 params->contactRows = [[contactMap objectForKey:
300 [oldItem.JID bareJID]] retain];
301 params->groupMap = [groupMap retain];
302 params->roster_model = g_object_ref(roster_model);
303 g_idle_add(remove_roster_item, params);
306 [contactMap removeObjectForKey: [item.JID bareJID]];
309 if (![item.subscription isEqual: @"remove"]) {
310 OFMapTable *contactRows = [OFMapTable
311 mapTableWithKeyFunctions: keyFunctions
312 valueFunctions: rowRefFunctions];
314 [contactMap setObject: contactRows
315 forKey: [item.JID bareJID]];
317 if (item.groups != nil)
318 groups = item.groups;
320 groups = @[@"General"];
322 for (OFString *group in groups) {
323 struct add_roster_item_param *params =
324 malloc(sizeof(*params));
325 params->group = [group retain];
326 params->name = [item.name retain];
327 params->jid = [item.JID retain];
328 params->groupMap = [groupMap retain];
329 params->contactRows = [contactRows retain];
330 params->roster_model = g_object_ref(roster_model);
331 g_idle_add(add_roster_item, params);