3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 #include "glibcompat.h"
26 #include "connection.h"
31 #define PURPLE_ROOMLIST_GET_PRIVATE(obj) \
32 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_ROOMLIST, PurpleRoomlistPrivate))
34 typedef struct _PurpleRoomlistPrivate PurpleRoomlistPrivate
;
37 * Private data for a room list.
39 struct _PurpleRoomlistPrivate
{
40 PurpleAccount
*account
; /* The account this list belongs to. */
41 GList
*fields
; /* The fields. */
42 GList
*rooms
; /* The list of rooms. */
43 gboolean in_progress
; /* The listing is in progress. */
45 /* TODO Remove this and use protocol-specific subclasses. */
46 gpointer proto_data
; /* Protocol private data. */
52 struct _PurpleRoomlistRoom
{
53 PurpleRoomlistRoomType type
; /* The type of room. */
54 gchar
*name
; /* The name of the room. */
55 GList
*fields
; /* Other fields. */
56 PurpleRoomlistRoom
*parent
; /* The parent room, or NULL. */
57 gboolean expanded_once
; /* A flag the UI uses to avoid multiple expand protocol cbs. */
61 * A field a room might have.
63 struct _PurpleRoomlistField
{
64 PurpleRoomlistFieldType type
; /* The type of field. */
65 gchar
*label
; /* The i18n user displayed name of the field. */
66 gchar
*name
; /* The internal name of the field. */
67 gboolean hidden
; /* Hidden? */
70 /* Room list property enums */
80 static GObjectClass
*parent_class
;
81 static GParamSpec
*properties
[PROP_LAST
];
82 static PurpleRoomlistUiOps
*ops
= NULL
;
84 static void purple_roomlist_field_free(PurpleRoomlistField
*f
);
85 static void purple_roomlist_room_destroy(PurpleRoomlist
*list
, PurpleRoomlistRoom
*r
);
87 /**************************************************************************/
89 /**************************************************************************/
91 void purple_roomlist_show_with_account(PurpleAccount
*account
)
93 if (ops
&& ops
->show_with_account
)
94 ops
->show_with_account(account
);
97 PurpleAccount
*purple_roomlist_get_account(PurpleRoomlist
*list
)
99 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
101 g_return_val_if_fail(priv
!= NULL
, NULL
);
103 return priv
->account
;
106 void purple_roomlist_set_fields(PurpleRoomlist
*list
, GList
*fields
)
108 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
110 g_return_if_fail(priv
!= NULL
);
112 priv
->fields
= fields
;
114 if (ops
&& ops
->set_fields
)
115 ops
->set_fields(list
, fields
);
117 g_object_notify_by_pspec(G_OBJECT(list
), properties
[PROP_FIELDS
]);
120 void purple_roomlist_set_in_progress(PurpleRoomlist
*list
, gboolean in_progress
)
122 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
124 g_return_if_fail(priv
!= NULL
);
126 priv
->in_progress
= in_progress
;
128 if (ops
&& ops
->in_progress
)
129 ops
->in_progress(list
, in_progress
);
131 g_object_notify_by_pspec(G_OBJECT(list
), properties
[PROP_IN_PROGRESS
]);
134 gboolean
purple_roomlist_get_in_progress(PurpleRoomlist
*list
)
136 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
138 g_return_val_if_fail(priv
!= NULL
, FALSE
);
140 return priv
->in_progress
;
143 void purple_roomlist_room_add(PurpleRoomlist
*list
, PurpleRoomlistRoom
*room
)
145 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
147 g_return_if_fail(priv
!= NULL
);
148 g_return_if_fail(room
!= NULL
);
150 priv
->rooms
= g_list_append(priv
->rooms
, room
);
152 if (ops
&& ops
->add_room
)
153 ops
->add_room(list
, room
);
156 PurpleRoomlist
*purple_roomlist_get_list(PurpleConnection
*gc
)
158 PurpleProtocol
*protocol
= NULL
;
160 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
161 g_return_val_if_fail(PURPLE_CONNECTION_IS_CONNECTED(gc
), NULL
);
163 protocol
= purple_connection_get_protocol(gc
);
166 return purple_protocol_roomlist_iface_get_list(protocol
, gc
);
171 void purple_roomlist_cancel_get_list(PurpleRoomlist
*list
)
173 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
174 PurpleProtocol
*protocol
= NULL
;
175 PurpleConnection
*gc
;
177 g_return_if_fail(priv
!= NULL
);
179 gc
= purple_account_get_connection(priv
->account
);
181 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
184 protocol
= purple_connection_get_protocol(gc
);
187 purple_protocol_roomlist_iface_cancel(protocol
, list
);
190 void purple_roomlist_expand_category(PurpleRoomlist
*list
, PurpleRoomlistRoom
*category
)
192 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
193 PurpleProtocol
*protocol
= NULL
;
194 PurpleConnection
*gc
;
196 g_return_if_fail(priv
!= NULL
);
197 g_return_if_fail(category
!= NULL
);
198 g_return_if_fail(category
->type
& PURPLE_ROOMLIST_ROOMTYPE_CATEGORY
);
200 gc
= purple_account_get_connection(priv
->account
);
201 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
204 protocol
= purple_connection_get_protocol(gc
);
207 purple_protocol_roomlist_iface_expand_category(protocol
, list
, category
);
210 GList
* purple_roomlist_get_fields(PurpleRoomlist
*list
)
212 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
214 g_return_val_if_fail(priv
!= NULL
, NULL
);
219 gpointer
purple_roomlist_get_protocol_data(PurpleRoomlist
*list
)
221 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
223 g_return_val_if_fail(priv
!= NULL
, NULL
);
225 return priv
->proto_data
;
228 void purple_roomlist_set_protocol_data(PurpleRoomlist
*list
, gpointer proto_data
)
230 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
232 g_return_if_fail(priv
!= NULL
);
234 priv
->proto_data
= proto_data
;
237 gpointer
purple_roomlist_get_ui_data(PurpleRoomlist
*list
)
239 g_return_val_if_fail(PURPLE_IS_ROOMLIST(list
), NULL
);
241 return list
->ui_data
;
244 void purple_roomlist_set_ui_data(PurpleRoomlist
*list
, gpointer ui_data
)
246 g_return_if_fail(PURPLE_IS_ROOMLIST(list
));
248 list
->ui_data
= ui_data
;
251 /**************************************************************************/
252 /* Room List GObject code */
253 /**************************************************************************/
255 /* Set method for GObject properties */
257 purple_roomlist_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
260 PurpleRoomlist
*list
= PURPLE_ROOMLIST(obj
);
261 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
265 priv
->account
= g_value_get_object(value
);
268 purple_roomlist_set_fields(list
, g_value_get_pointer(value
));
270 case PROP_IN_PROGRESS
:
271 purple_roomlist_set_in_progress(list
, g_value_get_boolean(value
));
274 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
279 /* Get method for GObject properties */
281 purple_roomlist_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
284 PurpleRoomlist
*list
= PURPLE_ROOMLIST(obj
);
288 g_value_set_object(value
, purple_roomlist_get_account(list
));
291 g_value_set_pointer(value
, purple_roomlist_get_fields(list
));
293 case PROP_IN_PROGRESS
:
294 g_value_set_boolean(value
, purple_roomlist_get_in_progress(list
));
297 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
302 /* Called when done constructing */
304 purple_roomlist_constructed(GObject
*object
)
306 PurpleRoomlist
*list
= PURPLE_ROOMLIST(object
);
308 parent_class
->constructed(object
);
310 if (ops
&& ops
->create
)
314 /* GObject finalize function */
316 purple_roomlist_finalize(GObject
*object
)
318 PurpleRoomlist
*list
= PURPLE_ROOMLIST(object
);
319 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
322 purple_debug_misc("roomlist", "destroying list %p\n", list
);
324 if (ops
&& ops
->destroy
)
327 for (l
= priv
->rooms
; l
; l
= l
->next
) {
328 PurpleRoomlistRoom
*r
= l
->data
;
329 purple_roomlist_room_destroy(list
, r
);
331 g_list_free(priv
->rooms
);
333 g_list_foreach(priv
->fields
, (GFunc
)purple_roomlist_field_free
, NULL
);
334 g_list_free(priv
->fields
);
336 parent_class
->finalize(object
);
339 /* Class initializer function */
341 purple_roomlist_class_init(PurpleRoomlistClass
*klass
)
343 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
345 parent_class
= g_type_class_peek_parent(klass
);
347 obj_class
->finalize
= purple_roomlist_finalize
;
348 obj_class
->constructed
= purple_roomlist_constructed
;
350 /* Setup properties */
351 obj_class
->get_property
= purple_roomlist_get_property
;
352 obj_class
->set_property
= purple_roomlist_set_property
;
354 g_type_class_add_private(klass
, sizeof(PurpleRoomlistPrivate
));
356 properties
[PROP_ACCOUNT
] = g_param_spec_object("account", "Account",
357 "The account for the room list.",
359 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
360 G_PARAM_STATIC_STRINGS
);
362 properties
[PROP_FIELDS
] = g_param_spec_pointer("fields", "Fields",
363 "The list of fields for a roomlist.",
364 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
366 properties
[PROP_IN_PROGRESS
] = g_param_spec_boolean("in-progress",
368 "Whether the room list is being fetched.", FALSE
,
369 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
371 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
375 purple_roomlist_get_type(void)
377 static GType type
= 0;
380 static const GTypeInfo info
= {
381 sizeof(PurpleRoomlistClass
),
384 (GClassInitFunc
)purple_roomlist_class_init
,
387 sizeof(PurpleRoomlist
),
393 type
= g_type_register_static(G_TYPE_OBJECT
, "PurpleRoomlist",
400 PurpleRoomlist
*purple_roomlist_new(PurpleAccount
*account
)
402 PurpleRoomlist
*list
;
403 PurpleProtocol
*protocol
;
405 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account
), NULL
);
407 protocol
= purple_protocols_find(purple_account_get_protocol_id(account
));
409 g_return_val_if_fail(PURPLE_IS_PROTOCOL(protocol
), NULL
);
411 if (PURPLE_PROTOCOL_IMPLEMENTS(protocol
, FACTORY_IFACE
, roomlist_new
))
412 list
= purple_protocol_factory_iface_roomlist_new(protocol
, account
);
414 list
= g_object_new(PURPLE_TYPE_ROOMLIST
,
419 g_return_val_if_fail(list
!= NULL
, NULL
);
424 /**************************************************************************/
426 /**************************************************************************/
428 PurpleRoomlistRoom
*purple_roomlist_room_new(PurpleRoomlistRoomType type
, const gchar
*name
,
429 PurpleRoomlistRoom
*parent
)
431 PurpleRoomlistRoom
*room
;
433 g_return_val_if_fail(name
!= NULL
, NULL
);
435 room
= g_new0(PurpleRoomlistRoom
, 1);
437 room
->name
= g_strdup(name
);
438 room
->parent
= parent
;
443 void purple_roomlist_room_add_field(PurpleRoomlist
*list
, PurpleRoomlistRoom
*room
, gconstpointer field
)
445 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
446 PurpleRoomlistField
*f
;
448 g_return_if_fail(priv
!= NULL
);
449 g_return_if_fail(room
!= NULL
);
450 g_return_if_fail(priv
->fields
!= NULL
);
452 /* If this is the first call for this room, grab the first field in
453 * the Roomlist's fields. Otherwise, grab the field that is one
454 * more than the number of fields already present for the room.
455 * (This works because g_list_nth_data() is zero-indexed and
456 * g_list_length() is one-indexed.) */
458 f
= priv
->fields
->data
;
460 f
= g_list_nth_data(priv
->fields
, g_list_length(room
->fields
));
462 g_return_if_fail(f
!= NULL
);
465 case PURPLE_ROOMLIST_FIELD_STRING
:
466 room
->fields
= g_list_append(room
->fields
, g_strdup(field
));
468 case PURPLE_ROOMLIST_FIELD_BOOL
:
469 case PURPLE_ROOMLIST_FIELD_INT
:
470 room
->fields
= g_list_append(room
->fields
, GINT_TO_POINTER(field
));
474 g_object_notify_by_pspec(G_OBJECT(list
), properties
[PROP_FIELDS
]);
477 void purple_roomlist_room_join(PurpleRoomlist
*list
, PurpleRoomlistRoom
*room
)
479 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
480 GHashTable
*components
;
482 PurpleConnection
*gc
;
484 g_return_if_fail(priv
!= NULL
);
485 g_return_if_fail(room
!= NULL
);
487 gc
= purple_account_get_connection(priv
->account
);
491 components
= g_hash_table_new(g_str_hash
, g_str_equal
);
493 g_hash_table_replace(components
, "name", room
->name
);
494 for (l
= priv
->fields
, j
= room
->fields
; l
&& j
; l
= l
->next
, j
= j
->next
) {
495 PurpleRoomlistField
*f
= l
->data
;
497 g_hash_table_replace(components
, f
->name
, j
->data
);
500 purple_serv_join_chat(gc
, components
);
502 g_hash_table_destroy(components
);
505 PurpleRoomlistRoomType
purple_roomlist_room_get_room_type(PurpleRoomlistRoom
*room
)
510 const char * purple_roomlist_room_get_name(PurpleRoomlistRoom
*room
)
515 PurpleRoomlistRoom
* purple_roomlist_room_get_parent(PurpleRoomlistRoom
*room
)
520 gboolean
purple_roomlist_room_get_expanded_once(PurpleRoomlistRoom
*room
)
522 g_return_val_if_fail(room
!= NULL
, FALSE
);
524 return room
->expanded_once
;
527 void purple_roomlist_room_set_expanded_once(PurpleRoomlistRoom
*room
, gboolean expanded_once
)
529 g_return_if_fail(room
!= NULL
);
531 room
->expanded_once
= expanded_once
;
534 GList
*purple_roomlist_room_get_fields(PurpleRoomlistRoom
*room
)
539 static void purple_roomlist_room_destroy(PurpleRoomlist
*list
, PurpleRoomlistRoom
*r
)
541 PurpleRoomlistPrivate
*priv
= PURPLE_ROOMLIST_GET_PRIVATE(list
);
544 for (l
= priv
->fields
, j
= r
->fields
; l
&& j
; l
= l
->next
, j
= j
->next
) {
545 PurpleRoomlistField
*f
= l
->data
;
546 if (f
->type
== PURPLE_ROOMLIST_FIELD_STRING
)
550 g_list_free(r
->fields
);
555 /**************************************************************************/
556 /* Room GBoxed code */
557 /**************************************************************************/
559 static PurpleRoomlistRoom
*purple_roomlist_room_copy(PurpleRoomlistRoom
*r
)
561 g_return_val_if_fail(r
!= NULL
, NULL
);
563 return purple_roomlist_room_new(r
->type
, r
->name
, r
->parent
);
566 static void purple_roomlist_room_free(PurpleRoomlistRoom
*r
)
568 g_return_if_fail(r
!= NULL
);
570 g_list_free(r
->fields
);
575 GType
purple_roomlist_room_get_type(void)
577 static GType type
= 0;
580 type
= g_boxed_type_register_static("PurpleRoomlistRoom",
581 (GBoxedCopyFunc
)purple_roomlist_room_copy
,
582 (GBoxedFreeFunc
)purple_roomlist_room_free
);
588 /**************************************************************************/
590 /**************************************************************************/
592 PurpleRoomlistField
*purple_roomlist_field_new(PurpleRoomlistFieldType type
,
593 const gchar
*label
, const gchar
*name
,
596 PurpleRoomlistField
*f
;
598 g_return_val_if_fail(label
!= NULL
, NULL
);
599 g_return_val_if_fail(name
!= NULL
, NULL
);
601 f
= g_new0(PurpleRoomlistField
, 1);
604 f
->label
= g_strdup(label
);
605 f
->name
= g_strdup(name
);
611 PurpleRoomlistFieldType
purple_roomlist_field_get_field_type(PurpleRoomlistField
*field
)
616 const char * purple_roomlist_field_get_label(PurpleRoomlistField
*field
)
621 gboolean
purple_roomlist_field_get_hidden(PurpleRoomlistField
*field
)
623 return field
->hidden
;
626 /**************************************************************************/
627 /* Room Field GBoxed code */
628 /**************************************************************************/
630 static PurpleRoomlistField
*purple_roomlist_field_copy(PurpleRoomlistField
*f
)
632 g_return_val_if_fail(f
!= NULL
, NULL
);
634 return purple_roomlist_field_new(f
->type
, f
->label
, f
->name
, f
->hidden
);
637 static void purple_roomlist_field_free(PurpleRoomlistField
*f
)
639 g_return_if_fail(f
!= NULL
);
646 GType
purple_roomlist_field_get_type(void)
648 static GType type
= 0;
651 type
= g_boxed_type_register_static("PurpleRoomlistField",
652 (GBoxedCopyFunc
)purple_roomlist_field_copy
,
653 (GBoxedFreeFunc
)purple_roomlist_field_free
);
659 /**************************************************************************/
660 /* UI Registration Functions */
661 /**************************************************************************/
663 void purple_roomlist_set_ui_ops(PurpleRoomlistUiOps
*ui_ops
)
668 PurpleRoomlistUiOps
*purple_roomlist_get_ui_ops(void)
673 /**************************************************************************
675 **************************************************************************/
677 static PurpleRoomlistUiOps
*
678 purple_roomlist_ui_ops_copy(PurpleRoomlistUiOps
*ops
)
680 PurpleRoomlistUiOps
*ops_new
;
682 g_return_val_if_fail(ops
!= NULL
, NULL
);
684 ops_new
= g_new(PurpleRoomlistUiOps
, 1);
691 purple_roomlist_ui_ops_get_type(void)
693 static GType type
= 0;
696 type
= g_boxed_type_register_static("PurpleRoomlistUiOps",
697 (GBoxedCopyFunc
)purple_roomlist_ui_ops_copy
,
698 (GBoxedFreeFunc
)g_free
);