1 /**
2  * @file roomlist.c Room List API
3  * @ingroup core
4  */
5 
6 /* purple
7  *
8  * Purple is the legal property of its developers, whose names are too numerous
9  * to list here.  Please refer to the COPYRIGHT file distributed with this
10  * source distribution.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
25  */
26 
27 #include "internal.h"
28 
29 #include "account.h"
30 #include "connection.h"
31 #include "debug.h"
32 #include "glibcompat.h"
33 #include "roomlist.h"
34 #include "server.h"
35 
36 
37 static PurpleRoomlistUiOps *ops = NULL;
38 
39 /**************************************************************************/
40 /** @name Room List API                                                   */
41 /**************************************************************************/
42 /*@{*/
43 
purple_roomlist_show_with_account(PurpleAccount * account)44 void purple_roomlist_show_with_account(PurpleAccount *account)
45 {
46 	if (ops && ops->show_with_account)
47 		ops->show_with_account(account);
48 }
49 
purple_roomlist_new(PurpleAccount * account)50 PurpleRoomlist *purple_roomlist_new(PurpleAccount *account)
51 {
52 	PurpleRoomlist *list;
53 
54 	g_return_val_if_fail(account != NULL, NULL);
55 
56 	list = g_new0(PurpleRoomlist, 1);
57 	list->account = account;
58 	list->rooms = NULL;
59 	list->fields = NULL;
60 	list->ref = 1;
61 
62 	if (ops && ops->create)
63 		ops->create(list);
64 
65 	return list;
66 }
67 
purple_roomlist_ref(PurpleRoomlist * list)68 void purple_roomlist_ref(PurpleRoomlist *list)
69 {
70 	g_return_if_fail(list != NULL);
71 
72 	list->ref++;
73 	purple_debug_misc("roomlist", "reffing list, ref count now %d\n", list->ref);
74 }
75 
purple_roomlist_room_destroy(PurpleRoomlist * list,PurpleRoomlistRoom * r)76 static void purple_roomlist_room_destroy(PurpleRoomlist *list, PurpleRoomlistRoom *r)
77 {
78 	GList *l, *j;
79 
80 	for (l = list->fields, j = r->fields; l && j; l = l->next, j = j->next) {
81 		PurpleRoomlistField *f = l->data;
82 		if (f->type == PURPLE_ROOMLIST_FIELD_STRING)
83 			g_free(j->data);
84 	}
85 
86 	g_list_free(r->fields);
87 	g_free(r->name);
88 	g_free(r);
89 }
90 
purple_roomlist_field_destroy(PurpleRoomlistField * f)91 static void purple_roomlist_field_destroy(PurpleRoomlistField *f)
92 {
93 	g_free(f->label);
94 	g_free(f->name);
95 	g_free(f);
96 }
97 
purple_roomlist_destroy(PurpleRoomlist * list)98 static void purple_roomlist_destroy(PurpleRoomlist *list)
99 {
100 	GList *l;
101 
102 	purple_debug_misc("roomlist", "destroying list %p\n", list);
103 
104 	if (ops && ops->destroy)
105 		ops->destroy(list);
106 
107 	for (l = list->rooms; l; l = l->next) {
108 		PurpleRoomlistRoom *r = l->data;
109 		purple_roomlist_room_destroy(list, r);
110 	}
111 	g_list_free(list->rooms);
112 
113 	g_list_free_full(list->fields,
114 	                 (GDestroyNotify)purple_roomlist_field_destroy);
115 
116 	g_free(list);
117 }
118 
purple_roomlist_unref(PurpleRoomlist * list)119 void purple_roomlist_unref(PurpleRoomlist *list)
120 {
121 	g_return_if_fail(list != NULL);
122 	g_return_if_fail(list->ref > 0);
123 
124 	list->ref--;
125 
126 	purple_debug_misc("roomlist", "unreffing list, ref count now %d\n", list->ref);
127 	if (list->ref == 0)
128 		purple_roomlist_destroy(list);
129 }
130 
purple_roomlist_set_fields(PurpleRoomlist * list,GList * fields)131 void purple_roomlist_set_fields(PurpleRoomlist *list, GList *fields)
132 {
133 	g_return_if_fail(list != NULL);
134 
135 	list->fields = fields;
136 
137 	if (ops && ops->set_fields)
138 		ops->set_fields(list, fields);
139 }
140 
purple_roomlist_set_in_progress(PurpleRoomlist * list,gboolean in_progress)141 void purple_roomlist_set_in_progress(PurpleRoomlist *list, gboolean in_progress)
142 {
143 	g_return_if_fail(list != NULL);
144 
145 	list->in_progress = in_progress;
146 
147 	if (ops && ops->in_progress)
148 		ops->in_progress(list, in_progress);
149 }
150 
purple_roomlist_get_in_progress(PurpleRoomlist * list)151 gboolean purple_roomlist_get_in_progress(PurpleRoomlist *list)
152 {
153 	g_return_val_if_fail(list != NULL, FALSE);
154 
155 	return list->in_progress;
156 }
157 
purple_roomlist_room_add(PurpleRoomlist * list,PurpleRoomlistRoom * room)158 void purple_roomlist_room_add(PurpleRoomlist *list, PurpleRoomlistRoom *room)
159 {
160 	g_return_if_fail(list != NULL);
161 	g_return_if_fail(room != NULL);
162 
163 	list->rooms = g_list_append(list->rooms, room);
164 
165 	if (ops && ops->add_room)
166 		ops->add_room(list, room);
167 }
168 
purple_roomlist_get_list(PurpleConnection * gc)169 PurpleRoomlist *purple_roomlist_get_list(PurpleConnection *gc)
170 {
171 	PurplePlugin *prpl = NULL;
172 	PurplePluginProtocolInfo *prpl_info = NULL;
173 
174 	g_return_val_if_fail(gc != NULL, NULL);
175 	g_return_val_if_fail(PURPLE_CONNECTION_IS_CONNECTED(gc), NULL);
176 
177 	prpl = purple_connection_get_prpl(gc);
178 
179 	if(prpl != NULL)
180 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
181 
182 	if(prpl_info && prpl_info->roomlist_get_list)
183 		return prpl_info->roomlist_get_list(gc);
184 
185 	return NULL;
186 }
187 
purple_roomlist_cancel_get_list(PurpleRoomlist * list)188 void purple_roomlist_cancel_get_list(PurpleRoomlist *list)
189 {
190 	PurplePlugin *prpl = NULL;
191 	PurplePluginProtocolInfo *prpl_info = NULL;
192 	PurpleConnection *gc;
193 
194 	g_return_if_fail(list != NULL);
195 
196 	gc = purple_account_get_connection(list->account);
197 
198 	g_return_if_fail(gc != NULL);
199 
200 	if(gc)
201 		prpl = purple_connection_get_prpl(gc);
202 
203 	if(prpl)
204 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
205 
206 	if(prpl_info && prpl_info->roomlist_cancel)
207 		prpl_info->roomlist_cancel(list);
208 }
209 
purple_roomlist_expand_category(PurpleRoomlist * list,PurpleRoomlistRoom * category)210 void purple_roomlist_expand_category(PurpleRoomlist *list, PurpleRoomlistRoom *category)
211 {
212 	PurplePlugin *prpl = NULL;
213 	PurplePluginProtocolInfo *prpl_info = NULL;
214 	PurpleConnection *gc;
215 
216 	g_return_if_fail(list != NULL);
217 	g_return_if_fail(category != NULL);
218 	g_return_if_fail(category->type & PURPLE_ROOMLIST_ROOMTYPE_CATEGORY);
219 
220 	gc = purple_account_get_connection(list->account);
221 	g_return_if_fail(gc != NULL);
222 
223 	if(gc)
224 		prpl = purple_connection_get_prpl(gc);
225 
226 	if(prpl)
227 		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
228 
229 	if(prpl_info && prpl_info->roomlist_expand_category)
230 		prpl_info->roomlist_expand_category(list, category);
231 }
232 
purple_roomlist_get_fields(PurpleRoomlist * list)233 GList * purple_roomlist_get_fields(PurpleRoomlist *list)
234 {
235 	return list->fields;
236 }
237 
238 /*@}*/
239 
240 /**************************************************************************/
241 /** @name Room API                                                        */
242 /**************************************************************************/
243 /*@{*/
244 
purple_roomlist_room_new(PurpleRoomlistRoomType type,const gchar * name,PurpleRoomlistRoom * parent)245 PurpleRoomlistRoom *purple_roomlist_room_new(PurpleRoomlistRoomType type, const gchar *name,
246                                          PurpleRoomlistRoom *parent)
247 {
248 	PurpleRoomlistRoom *room;
249 
250 	g_return_val_if_fail(name != NULL, NULL);
251 
252 	room = g_new0(PurpleRoomlistRoom, 1);
253 	room->type = type;
254 	room->name = g_strdup(name);
255 	room->parent = parent;
256 
257 	return room;
258 }
259 
purple_roomlist_room_add_field(PurpleRoomlist * list,PurpleRoomlistRoom * room,gconstpointer field)260 void purple_roomlist_room_add_field(PurpleRoomlist *list, PurpleRoomlistRoom *room, gconstpointer field)
261 {
262 	PurpleRoomlistField *f;
263 
264 	g_return_if_fail(list != NULL);
265 	g_return_if_fail(room != NULL);
266 	g_return_if_fail(list->fields != NULL);
267 
268 	/* If this is the first call for this room, grab the first field in
269 	 * the Roomlist's fields.  Otherwise, grab the field that is one
270 	 * more than the number of fields already present for the room.
271          * (This works because g_list_nth_data() is zero-indexed and
272          * g_list_length() is one-indexed.) */
273 	if (!room->fields)
274 		f = list->fields->data;
275 	else
276 		f = g_list_nth_data(list->fields, g_list_length(room->fields));
277 
278 	g_return_if_fail(f != NULL);
279 
280 	switch(f->type) {
281 		case PURPLE_ROOMLIST_FIELD_STRING:
282 			room->fields = g_list_append(room->fields, g_strdup(field));
283 			break;
284 		case PURPLE_ROOMLIST_FIELD_BOOL:
285 		case PURPLE_ROOMLIST_FIELD_INT:
286 			room->fields = g_list_append(room->fields, GINT_TO_POINTER(field));
287 			break;
288 	}
289 }
290 
purple_roomlist_room_join(PurpleRoomlist * list,PurpleRoomlistRoom * room)291 void purple_roomlist_room_join(PurpleRoomlist *list, PurpleRoomlistRoom *room)
292 {
293 	GHashTable *components;
294 	GList *l, *j;
295 	PurpleConnection *gc;
296 
297 	g_return_if_fail(list != NULL);
298 	g_return_if_fail(room != NULL);
299 
300 	gc = purple_account_get_connection(list->account);
301 	if (!gc)
302 		return;
303 
304 	components = g_hash_table_new(g_str_hash, g_str_equal);
305 
306 	g_hash_table_replace(components, "name", room->name);
307 	for (l = list->fields, j = room->fields; l && j; l = l->next, j = j->next) {
308 		PurpleRoomlistField *f = l->data;
309 
310 		g_hash_table_replace(components, f->name, j->data);
311 	}
312 
313 	serv_join_chat(gc, components);
314 
315 	g_hash_table_destroy(components);
316 }
317 
purple_roomlist_room_get_type(PurpleRoomlistRoom * room)318 PurpleRoomlistRoomType purple_roomlist_room_get_type(PurpleRoomlistRoom *room)
319 {
320 	return room->type;
321 }
322 
purple_roomlist_room_get_name(PurpleRoomlistRoom * room)323 const char * purple_roomlist_room_get_name(PurpleRoomlistRoom *room)
324 {
325 	return room->name;
326 }
327 
purple_roomlist_room_get_parent(PurpleRoomlistRoom * room)328 PurpleRoomlistRoom * purple_roomlist_room_get_parent(PurpleRoomlistRoom *room)
329 {
330 	return room->parent;
331 }
332 
purple_roomlist_room_get_fields(PurpleRoomlistRoom * room)333 GList * purple_roomlist_room_get_fields(PurpleRoomlistRoom *room)
334 {
335 	return room->fields;
336 }
337 
338 /*@}*/
339 
340 /**************************************************************************/
341 /** @name Room Field API                                                  */
342 /**************************************************************************/
343 /*@{*/
344 
purple_roomlist_field_new(PurpleRoomlistFieldType type,const gchar * label,const gchar * name,gboolean hidden)345 PurpleRoomlistField *purple_roomlist_field_new(PurpleRoomlistFieldType type,
346                                            const gchar *label, const gchar *name,
347                                            gboolean hidden)
348 {
349 	PurpleRoomlistField *f;
350 
351 	g_return_val_if_fail(label != NULL, NULL);
352 	g_return_val_if_fail(name != NULL, NULL);
353 
354 	f = g_new0(PurpleRoomlistField, 1);
355 
356 	f->type = type;
357 	f->label = g_strdup(label);
358 	f->name = g_strdup(name);
359 	f->hidden = hidden;
360 
361 	return f;
362 }
363 
purple_roomlist_field_get_type(PurpleRoomlistField * field)364 PurpleRoomlistFieldType purple_roomlist_field_get_type(PurpleRoomlistField *field)
365 {
366 	return field->type;
367 }
368 
purple_roomlist_field_get_label(PurpleRoomlistField * field)369 const char * purple_roomlist_field_get_label(PurpleRoomlistField *field)
370 {
371 	return field->label;
372 }
373 
purple_roomlist_field_get_hidden(PurpleRoomlistField * field)374 gboolean purple_roomlist_field_get_hidden(PurpleRoomlistField *field)
375 {
376 	return field->hidden;
377 }
378 
379 /*@}*/
380 
381 /**************************************************************************/
382 /** @name UI Registration Functions                                       */
383 /**************************************************************************/
384 /*@{*/
385 
386 
purple_roomlist_set_ui_ops(PurpleRoomlistUiOps * ui_ops)387 void purple_roomlist_set_ui_ops(PurpleRoomlistUiOps *ui_ops)
388 {
389 	ops = ui_ops;
390 }
391 
purple_roomlist_get_ui_ops(void)392 PurpleRoomlistUiOps *purple_roomlist_get_ui_ops(void)
393 {
394 	return ops;
395 }
396 
397 /*@}*/
398