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