4 * Purple is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
24 #include "dbus-maybe.h"
26 #include "internal.h" /* TODO: we need to kill this */
28 #define PURPLE_GROUP_GET_PRIVATE(obj) \
29 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_GROUP, PurpleGroupPrivate))
31 typedef struct _PurpleGroupPrivate PurpleGroupPrivate
;
33 /******************************************************************************
35 *****************************************************************************/
36 struct _PurpleGroupPrivate
{
37 char *name
; /* The name of this group. */
38 gboolean is_constructed
; /* Indicates if the group has finished being
42 /* Group property enums */
50 /******************************************************************************
52 *****************************************************************************/
53 static GParamSpec
*properties
[GROUP_PROP_LAST
];
54 static GObjectClass
*parent_class
= NULL
;
56 /******************************************************************************
58 *****************************************************************************/
59 GSList
*purple_group_get_accounts(PurpleGroup
*group
) {
61 PurpleBlistNode
*gnode
, *cnode
, *bnode
;
63 gnode
= (PurpleBlistNode
*)group
;
65 for (cnode
= gnode
->child
; cnode
; cnode
= cnode
->next
) {
66 if (PURPLE_IS_CHAT(cnode
)) {
67 if (!g_slist_find(l
, purple_chat_get_account(PURPLE_CHAT(cnode
))))
68 l
= g_slist_append(l
, purple_chat_get_account(PURPLE_CHAT(cnode
)));
69 } else if (PURPLE_IS_CONTACT(cnode
)) {
70 for (bnode
= cnode
->child
; bnode
; bnode
= bnode
->next
) {
71 if (PURPLE_IS_BUDDY(bnode
)) {
72 if (!g_slist_find(l
, purple_buddy_get_account(PURPLE_BUDDY(bnode
))))
73 l
= g_slist_append(l
, purple_buddy_get_account(PURPLE_BUDDY(bnode
)));
82 gboolean
purple_group_on_account(PurpleGroup
*g
, PurpleAccount
*account
) {
83 PurpleBlistNode
*cnode
;
84 for (cnode
= ((PurpleBlistNode
*)g
)->child
; cnode
; cnode
= cnode
->next
) {
85 if (PURPLE_IS_CONTACT(cnode
)) {
86 if(purple_contact_on_account((PurpleContact
*) cnode
, account
))
88 } else if (PURPLE_IS_CHAT(cnode
)) {
89 PurpleChat
*chat
= (PurpleChat
*)cnode
;
90 if ((!account
&& purple_account_is_connected(purple_chat_get_account(chat
)))
91 || purple_chat_get_account(chat
) == account
)
99 * TODO: If merging, prompt the user if they want to merge.
101 void purple_group_set_name(PurpleGroup
*source
, const char *name
) {
102 PurpleBlistUiOps
*ops
= purple_blist_get_ui_ops();
106 GList
*moved_buddies
= NULL
;
108 PurpleGroupPrivate
*priv
= PURPLE_GROUP_GET_PRIVATE(source
);
110 g_return_if_fail(priv
!= NULL
);
111 g_return_if_fail(name
!= NULL
);
113 new_name
= purple_utf8_strip_unprintables(name
);
115 if (*new_name
== '\0' || purple_strequal(new_name
, priv
->name
)) {
120 dest
= purple_blist_find_group(new_name
);
121 if (dest
!= NULL
&& purple_utf8_strcasecmp(priv
->name
,
122 PURPLE_GROUP_GET_PRIVATE(dest
)->name
) != 0) {
123 /* We're merging two groups */
124 PurpleBlistNode
*prev
, *child
, *next
;
126 prev
= _purple_blist_get_last_child((PurpleBlistNode
*)dest
);
127 child
= PURPLE_BLIST_NODE(source
)->child
;
130 * TODO: This seems like a dumb way to do this... why not just
131 * append all children from the old group to the end of the new
132 * one? Protocols might be expecting to receive an add_buddy() for
133 * each moved buddy...
138 if (PURPLE_IS_CONTACT(child
)) {
139 PurpleBlistNode
*bnode
;
140 purple_blist_add_contact((PurpleContact
*)child
, dest
, prev
);
141 for (bnode
= child
->child
; bnode
!= NULL
; bnode
= bnode
->next
) {
142 purple_blist_add_buddy((PurpleBuddy
*)bnode
, (PurpleContact
*)child
,
144 moved_buddies
= g_list_append(moved_buddies
, bnode
);
147 } else if (PURPLE_IS_CHAT(child
)) {
148 purple_blist_add_chat((PurpleChat
*)child
, dest
, prev
);
151 purple_debug(PURPLE_DEBUG_ERROR
, "blistnodetypes",
152 "Unknown child type in group %s\n", priv
->name
);
157 /* Make a copy of the old group name and then delete the old group */
158 old_name
= g_strdup(priv
->name
);
159 purple_blist_remove_group(source
);
163 /* A simple rename */
164 PurpleBlistNode
*cnode
, *bnode
;
166 /* Build a GList of all buddies in this group */
167 for (cnode
= PURPLE_BLIST_NODE(source
)->child
; cnode
!= NULL
; cnode
= cnode
->next
) {
168 if (PURPLE_IS_CONTACT(cnode
))
169 for (bnode
= cnode
->child
; bnode
!= NULL
; bnode
= bnode
->next
)
170 moved_buddies
= g_list_append(moved_buddies
, bnode
);
173 purple_blist_update_groups_cache(source
, new_name
);
175 old_name
= priv
->name
;
176 priv
->name
= new_name
;
178 g_object_notify_by_pspec(G_OBJECT(source
), properties
[GROUP_PROP_NAME
]);
181 /* Save our changes */
182 if (ops
&& ops
->save_node
)
183 ops
->save_node(PURPLE_BLIST_NODE(source
));
186 if (ops
&& ops
->update
)
187 ops
->update(purple_blist_get_buddy_list(), PURPLE_BLIST_NODE(source
));
189 /* Notify all protocols */
190 /* TODO: Is this condition needed? Seems like it would always be TRUE */
191 if(old_name
&& !purple_strequal(priv
->name
, old_name
)) {
192 for (accts
= purple_group_get_accounts(source
); accts
; accts
= g_slist_remove(accts
, accts
->data
)) {
193 PurpleAccount
*account
= accts
->data
;
194 PurpleConnection
*gc
= NULL
;
195 PurpleProtocol
*protocol
= NULL
;
196 GList
*l
= NULL
, *buddies
= NULL
;
198 gc
= purple_account_get_connection(account
);
201 protocol
= purple_connection_get_protocol(gc
);
206 for(l
= moved_buddies
; l
; l
= l
->next
) {
207 PurpleBuddy
*buddy
= PURPLE_BUDDY(l
->data
);
209 if(buddy
&& purple_buddy_get_account(buddy
) == account
)
210 buddies
= g_list_append(buddies
, (PurpleBlistNode
*)buddy
);
213 if(PURPLE_PROTOCOL_IMPLEMENTS(protocol
, SERVER_IFACE
, rename_group
)) {
214 purple_protocol_server_iface_rename_group(protocol
, gc
, old_name
, source
, buddies
);
216 GList
*cur
, *groups
= NULL
;
218 /* Make a list of what the groups each buddy is in */
219 for(cur
= buddies
; cur
; cur
= cur
->next
) {
220 PurpleBlistNode
*node
= (PurpleBlistNode
*)cur
->data
;
221 groups
= g_list_prepend(groups
, node
->parent
->parent
);
224 purple_account_remove_buddies(account
, buddies
, groups
);
226 purple_account_add_buddies(account
, buddies
, NULL
);
229 g_list_free(buddies
);
232 g_list_free(moved_buddies
);
235 g_object_notify_by_pspec(G_OBJECT(source
), properties
[GROUP_PROP_NAME
]);
238 const char *purple_group_get_name(PurpleGroup
*group
) {
239 PurpleGroupPrivate
*priv
= PURPLE_GROUP_GET_PRIVATE(group
);
241 g_return_val_if_fail(priv
!= NULL
, NULL
);
246 /******************************************************************************
248 *****************************************************************************/
249 /* Set method for GObject properties */
251 purple_group_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
254 PurpleGroup
*group
= PURPLE_GROUP(obj
);
255 PurpleGroupPrivate
*priv
= PURPLE_GROUP_GET_PRIVATE(group
);
258 case GROUP_PROP_NAME
:
259 if (priv
->is_constructed
)
260 purple_group_set_name(group
, g_value_get_string(value
));
263 purple_utf8_strip_unprintables(g_value_get_string(value
));
266 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
271 /* Get method for GObject properties */
273 purple_group_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
276 PurpleGroup
*group
= PURPLE_GROUP(obj
);
279 case GROUP_PROP_NAME
:
280 g_value_set_string(value
, purple_group_get_name(group
));
283 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
288 /* GObject initialization function */
290 purple_group_init(GTypeInstance
*instance
, gpointer klass
) {
291 PURPLE_DBUS_REGISTER_POINTER(PURPLE_GROUP(instance
), PurpleGroup
);
294 /* Called when done constructing */
296 purple_group_constructed(GObject
*object
) {
297 PurpleGroup
*group
= PURPLE_GROUP(object
);
298 PurpleGroupPrivate
*priv
= PURPLE_GROUP_GET_PRIVATE(group
);
299 PurpleBlistUiOps
*ops
= purple_blist_get_ui_ops();
301 G_OBJECT_CLASS(parent_class
)->constructed(object
);
303 if (ops
&& ops
->new_node
)
304 ops
->new_node(PURPLE_BLIST_NODE(group
));
306 priv
->is_constructed
= TRUE
;
309 /* GObject finalize function */
311 purple_group_finalize(GObject
*object
) {
312 g_free(PURPLE_GROUP_GET_PRIVATE(object
)->name
);
314 PURPLE_DBUS_UNREGISTER_POINTER(object
);
316 G_OBJECT_CLASS(parent_class
)->finalize(object
);
319 /* Class initializer function */
321 purple_group_class_init(PurpleGroupClass
*klass
) {
322 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
324 parent_class
= g_type_class_peek_parent(klass
);
326 obj_class
->finalize
= purple_group_finalize
;
327 obj_class
->constructed
= purple_group_constructed
;
329 /* Setup properties */
330 obj_class
->get_property
= purple_group_get_property
;
331 obj_class
->set_property
= purple_group_set_property
;
333 g_type_class_add_private(klass
, sizeof(PurpleGroupPrivate
));
335 properties
[GROUP_PROP_NAME
] = g_param_spec_string(
338 "Name of the group.",
340 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
| G_PARAM_STATIC_STRINGS
343 g_object_class_install_properties(obj_class
, GROUP_PROP_LAST
, properties
);
347 purple_group_get_type(void) {
348 static GType type
= 0;
351 static const GTypeInfo info
= {
352 sizeof(PurpleGroupClass
),
355 (GClassInitFunc
)purple_group_class_init
,
360 (GInstanceInitFunc
)purple_group_init
,
364 type
= g_type_register_static(PURPLE_TYPE_COUNTING_NODE
,
373 purple_group_new(const char *name
) {
376 if (name
== NULL
|| name
[0] == '\0')
377 name
= PURPLE_BLIST_DEFAULT_GROUP_NAME
;
378 if (g_strcmp0(name
, "Buddies") == 0)
379 name
= PURPLE_BLIST_DEFAULT_GROUP_NAME
;
380 if (g_strcmp0(name
, _purple_blist_get_localized_default_group_name()) == 0)
381 name
= PURPLE_BLIST_DEFAULT_GROUP_NAME
;
383 group
= purple_blist_find_group(name
);
387 return g_object_new(PURPLE_TYPE_GROUP
, "name", name
, NULL
);