1 #import "JubGtkRosterUI.h"
2 #import "JubGObjectMap.h"
3 #import "JubGtkChatUI.h"
4 #import "JubGtkHelper.h"
6 static gboolean filter_roster_by_presence(GtkTreeModel *model,
7 GtkTreeIter *iter, gpointer data)
11 OFCountedSet *presences = data;
13 gtk_tree_model_get(model, iter, 1, &jid_s, -1);
19 jid = [[OFString alloc] initWithUTF8String: jid_s];
23 int num = [presences countForObject: jid];
33 @implementation JubGtkRosterUI
34 - initWithBuilder: (GtkBuilder*)builder_
39 groupMap = [[OFMapTable alloc]
40 initWithKeyFunctions: keyFunctions
41 valueFunctions: rowRefFunctions];
42 contactMap = [[OFMutableDictionary alloc] init];
43 chatMap = [[OFMutableDictionary alloc] init];
44 presences = [[OFCountedSet alloc] init];
46 builder = g_object_ref(builder_);
48 roster_model = GTK_TREE_STORE(gtk_builder_get_object(builder,
51 roster_filter = GTK_TREE_MODEL_FILTER(
52 gtk_builder_get_object(builder, "RosterTreeModelFilter"));
54 gtk_tree_model_filter_set_visible_func(roster_filter,
55 filter_roster_by_presence, presences, NULL);
71 g_object_unref(roster_model);
74 g_object_unref(roster_filter);
76 g_object_unref(builder);
81 /* Presence handling */
82 - (void)connection: (XMPPConnection*)connection
83 didReceivePresence: (XMPPPresence*)presence
85 if ([presence.type isEqual: @"available"])
86 [presences addObject: [presence.from bareJID]];
87 else if ([presence.type isEqual: @"unavailable"])
88 [presences removeObject: [presence.from bareJID]];
91 gtk_tree_model_filter_refilter(roster_filter);
95 // FIXME: This needs to move somewhere else
96 - (void)connection: (XMPPConnection*)connection
97 didReceiveMessage: (XMPPMessage*)message
100 [chatMap objectForKey: [message.from bareJID]];
102 OFString * title = [@"Chat with " stringByAppendingString:
103 [message.from bareJID]];
105 chat = [[[JubGtkChatUI alloc]
108 [chatMap removeObjectForKey:
109 [message.from bareJID]];
111 sendBlock: ^(OFString *text) {
113 [XMPPMessage messageWithType: @"chat"];
114 msg.to = message.from;
116 [connection sendStanza: msg];
120 [chatMap setObject: chat
121 forKey: [message.from bareJID]];
124 [chat addMessage: message.body
125 sender: [message.from bareJID]];
128 /* Roster Delegate methods */
129 - (void)Jub_addRosterItem: (XMPPRosterItem*)item
130 group: (OFString*)group
133 GtkTreeIter group_iter, contact_iter;
134 GtkTreeRowReference *group_ref, *contact_ref;
135 GtkTreePath *group_path, *contact_path;
136 OFMapTable *contactRows =
137 [contactMap objectForKey: [item.JID bareJID]];
139 group_ref = [groupMap valueForKey: group];
142 // Create new group row
143 gtk_tree_store_append(roster_model, &group_iter, NULL);
144 gtk_tree_store_set(roster_model, &group_iter,
145 0, [group UTF8String], -1);
147 group_path = gtk_tree_model_get_path(GTK_TREE_MODEL(
148 roster_model), &group_iter);
150 group_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(
151 roster_model), group_path);
153 [groupMap setValue: group_ref
156 // Get iter for existing group row
157 group_path = gtk_tree_row_reference_get_path(group_ref);
159 gtk_tree_model_get_iter(GTK_TREE_MODEL(roster_model),
160 &group_iter, group_path);
162 gtk_tree_path_free(group_path);
164 // Create new contact row
165 gtk_tree_store_append(roster_model, &contact_iter, &group_iter);
167 gtk_tree_store_set(roster_model, &contact_iter,
168 0, [item.name UTF8String],
169 1, [[item.JID bareJID] UTF8String], -1);
171 gtk_tree_store_set(roster_model, &contact_iter,
172 0, [item.JID.node UTF8String],
173 1, [[item.JID bareJID] UTF8String], -1);
175 contact_path = gtk_tree_model_get_path(GTK_TREE_MODEL(
176 roster_model), &contact_iter);
178 contact_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(
179 roster_model), contact_path);
181 gtk_tree_path_free(contact_path);
183 [contactRows setValue: contact_ref
188 - (void)Jub_removeRosterItem: (XMPPRosterItem*)item
189 group: (OFString*)group
192 GtkTreeIter contact_iter, group_iter;
193 GtkTreePath *contact_path, *group_path;
194 GtkTreeRowReference *contact_ref, *group_ref;
195 OFMapTable *contactRows =
196 [contactMap objectForKey: [item.JID bareJID]];
198 contact_ref = [contactRows valueForKey: group];
199 contact_path = gtk_tree_row_reference_get_path(contact_ref);
200 gtk_tree_model_get_iter(GTK_TREE_MODEL(roster_model),
201 &contact_iter, contact_path);
203 gtk_tree_store_remove(roster_model, &contact_iter);
205 group_ref = [groupMap valueForKey: group];
206 group_path = gtk_tree_row_reference_get_path(group_ref);
207 gtk_tree_model_get_iter(GTK_TREE_MODEL(roster_model),
208 &group_iter, group_path);
210 if (!gtk_tree_model_iter_has_child(GTK_TREE_MODEL(roster_model),
212 gtk_tree_store_remove(roster_model, &group_iter);
213 [groupMap removeValueForKey: group];
216 gtk_tree_path_free(group_path);
220 - (void)rosterWasReceived: (XMPPRoster*)roster_
222 of_log(@"Handling roster");
223 [[roster_ rosterItems] enumerateKeysAndObjectsUsingBlock:
224 ^(OFString *bareJID, XMPPRosterItem *item, BOOL *stop) {
226 OFMapTable *contactRows = [OFMapTable
227 mapTableWithKeyFunctions: keyFunctions
228 valueFunctions: rowRefFunctions];
230 [contactMap setObject: contactRows
233 if (item.groups != nil)
234 groups = item.groups;
236 groups = @[@"General"];
238 for (OFString *group in groups)
239 [self Jub_addRosterItem: item
244 - (void)roster: (XMPPRoster*)roster_
245 didReceiveRosterItem: (XMPPRosterItem*)item
248 XMPPRosterItem *oldItem =
249 [roster_.rosterItems objectForKey: [item.JID bareJID]];
252 if (oldItem.groups != nil)
253 groups = oldItem.groups;
255 groups = @[@"General"];
257 for (OFString *group in groups)
258 [self Jub_removeRosterItem: oldItem
261 [contactMap removeObjectForKey: [item.JID bareJID]];
264 if (![item.subscription isEqual: @"remove"]) {
265 OFMapTable *contactRows = [OFMapTable
266 mapTableWithKeyFunctions: keyFunctions
267 valueFunctions: rowRefFunctions];
269 [contactMap setObject: contactRows
270 forKey: [item.JID bareJID]];
272 if (item.groups != nil)
273 groups = item.groups;
275 groups = @[@"General"];
277 for (OFString *group in groups)
278 [self Jub_addRosterItem: item