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
25 #include "internal.h" /* TODO: we need to kill this */
27 typedef struct _PurpleGroupPrivate PurpleGroupPrivate
;
29 /******************************************************************************
31 *****************************************************************************/
32 struct _PurpleGroupPrivate
{
33 char *name
; /* The name of this group. */
34 gboolean is_constructed
; /* Indicates if the group has finished being
38 /* Group property enums */
46 /******************************************************************************
48 *****************************************************************************/
49 static GParamSpec
*properties
[GROUP_PROP_LAST
];
51 G_DEFINE_TYPE_WITH_PRIVATE(PurpleGroup
, purple_group
,
52 PURPLE_TYPE_COUNTING_NODE
);
54 /******************************************************************************
56 *****************************************************************************/
57 GSList
*purple_group_get_accounts(PurpleGroup
*group
) {
59 PurpleBlistNode
*gnode
, *cnode
, *bnode
;
61 gnode
= (PurpleBlistNode
*)group
;
63 for (cnode
= gnode
->child
; cnode
; cnode
= cnode
->next
) {
64 if (PURPLE_IS_CHAT(cnode
)) {
65 if (!g_slist_find(l
, purple_chat_get_account(PURPLE_CHAT(cnode
))))
66 l
= g_slist_append(l
, purple_chat_get_account(PURPLE_CHAT(cnode
)));
67 } else if (PURPLE_IS_CONTACT(cnode
)) {
68 for (bnode
= cnode
->child
; bnode
; bnode
= bnode
->next
) {
69 if (PURPLE_IS_BUDDY(bnode
)) {
70 if (!g_slist_find(l
, purple_buddy_get_account(PURPLE_BUDDY(bnode
))))
71 l
= g_slist_append(l
, purple_buddy_get_account(PURPLE_BUDDY(bnode
)));
80 gboolean
purple_group_on_account(PurpleGroup
*g
, PurpleAccount
*account
) {
81 PurpleBlistNode
*cnode
;
82 for (cnode
= ((PurpleBlistNode
*)g
)->child
; cnode
; cnode
= cnode
->next
) {
83 if (PURPLE_IS_CONTACT(cnode
)) {
84 if(purple_contact_on_account((PurpleContact
*) cnode
, account
))
86 } else if (PURPLE_IS_CHAT(cnode
)) {
87 PurpleChat
*chat
= (PurpleChat
*)cnode
;
88 if ((!account
&& purple_account_is_connected(purple_chat_get_account(chat
)))
89 || purple_chat_get_account(chat
) == account
)
97 * TODO: If merging, prompt the user if they want to merge.
99 void purple_group_set_name(PurpleGroup
*source
, const char *name
) {
100 PurpleGroupPrivate
*priv
= NULL
;
104 GList
*moved_buddies
= NULL
;
107 g_return_if_fail(PURPLE_IS_GROUP(source
));
108 g_return_if_fail(name
!= NULL
);
110 priv
= purple_group_get_instance_private(source
);
112 new_name
= purple_utf8_strip_unprintables(name
);
114 if (*new_name
== '\0' || purple_strequal(new_name
, priv
->name
)) {
119 dest
= purple_blist_find_group(new_name
);
120 if (dest
!= NULL
&& purple_utf8_strcasecmp(priv
->name
,
121 purple_group_get_name(dest
)) != 0) {
122 /* We're merging two groups */
123 PurpleBlistNode
*prev
, *child
, *next
;
125 prev
= _purple_blist_get_last_child((PurpleBlistNode
*)dest
);
126 child
= PURPLE_BLIST_NODE(source
)->child
;
129 * TODO: This seems like a dumb way to do this... why not just
130 * append all children from the old group to the end of the new
131 * one? Protocols might be expecting to receive an add_buddy() for
132 * each moved buddy...
137 if (PURPLE_IS_CONTACT(child
)) {
138 PurpleBlistNode
*bnode
;
139 purple_blist_add_contact((PurpleContact
*)child
, dest
, prev
);
140 for (bnode
= child
->child
; bnode
!= NULL
; bnode
= bnode
->next
) {
141 purple_blist_add_buddy((PurpleBuddy
*)bnode
, (PurpleContact
*)child
,
143 moved_buddies
= g_list_append(moved_buddies
, bnode
);
146 } else if (PURPLE_IS_CHAT(child
)) {
147 purple_blist_add_chat((PurpleChat
*)child
, dest
, prev
);
150 purple_debug(PURPLE_DEBUG_ERROR
, "blistnodetypes",
151 "Unknown child type in group %s\n", priv
->name
);
156 /* Make a copy of the old group name and then delete the old group */
157 old_name
= g_strdup(priv
->name
);
158 purple_blist_remove_group(source
);
162 /* A simple rename */
163 PurpleBlistNode
*cnode
, *bnode
;
165 /* Build a GList of all buddies in this group */
166 for (cnode
= PURPLE_BLIST_NODE(source
)->child
; cnode
!= NULL
; cnode
= cnode
->next
) {
167 if (PURPLE_IS_CONTACT(cnode
))
168 for (bnode
= cnode
->child
; bnode
!= NULL
; bnode
= bnode
->next
)
169 moved_buddies
= g_list_append(moved_buddies
, bnode
);
172 purple_blist_update_groups_cache(source
, new_name
);
174 old_name
= priv
->name
;
175 priv
->name
= new_name
;
177 g_object_notify_by_pspec(G_OBJECT(source
), properties
[GROUP_PROP_NAME
]);
180 /* Save our changes */
181 purple_blist_save_node(purple_blist_get_default(),
182 PURPLE_BLIST_NODE(source
));
185 purple_blist_update_node(purple_blist_get_default(),
186 PURPLE_BLIST_NODE(source
));
188 /* Notify all protocols */
189 /* TODO: Is this condition needed? Seems like it would always be TRUE */
190 if(old_name
&& !purple_strequal(priv
->name
, old_name
)) {
191 for (accts
= purple_group_get_accounts(source
); accts
; accts
= g_slist_remove(accts
, accts
->data
)) {
192 PurpleAccount
*account
= accts
->data
;
193 PurpleConnection
*gc
= NULL
;
194 PurpleProtocol
*protocol
= NULL
;
195 GList
*l
= NULL
, *buddies
= NULL
;
197 gc
= purple_account_get_connection(account
);
200 protocol
= purple_connection_get_protocol(gc
);
205 for(l
= moved_buddies
; l
; l
= l
->next
) {
206 PurpleBuddy
*buddy
= PURPLE_BUDDY(l
->data
);
208 if(buddy
&& purple_buddy_get_account(buddy
) == account
)
209 buddies
= g_list_append(buddies
, (PurpleBlistNode
*)buddy
);
212 if(PURPLE_PROTOCOL_IMPLEMENTS(protocol
, SERVER
, rename_group
)) {
213 purple_protocol_server_iface_rename_group(protocol
, gc
, old_name
, source
, buddies
);
215 GList
*cur
, *groups
= NULL
;
217 /* Make a list of what the groups each buddy is in */
218 for(cur
= buddies
; cur
; cur
= cur
->next
) {
219 PurpleBlistNode
*node
= (PurpleBlistNode
*)cur
->data
;
220 groups
= g_list_prepend(groups
, node
->parent
->parent
);
223 purple_account_remove_buddies(account
, buddies
, groups
);
225 purple_account_add_buddies(account
, buddies
, NULL
);
228 g_list_free(buddies
);
231 g_list_free(moved_buddies
);
234 g_object_notify_by_pspec(G_OBJECT(source
), properties
[GROUP_PROP_NAME
]);
237 const char *purple_group_get_name(PurpleGroup
*group
) {
238 PurpleGroupPrivate
*priv
= NULL
;
240 g_return_val_if_fail(PURPLE_IS_GROUP(group
), NULL
);
242 priv
= purple_group_get_instance_private(group
);
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_instance_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(PurpleGroup
*group
) {
293 /* Called when done constructing */
295 purple_group_constructed(GObject
*object
) {
296 PurpleGroup
*group
= PURPLE_GROUP(object
);
297 PurpleGroupPrivate
*priv
= purple_group_get_instance_private(group
);
299 G_OBJECT_CLASS(purple_group_parent_class
)->constructed(object
);
301 purple_blist_new_node(purple_blist_get_default(),
302 PURPLE_BLIST_NODE(group
));
304 priv
->is_constructed
= TRUE
;
307 /* GObject finalize function */
309 purple_group_finalize(GObject
*object
) {
310 PurpleGroupPrivate
*priv
= purple_group_get_instance_private(
311 PURPLE_GROUP(object
));
315 G_OBJECT_CLASS(purple_group_parent_class
)->finalize(object
);
318 /* Class initializer function */
320 purple_group_class_init(PurpleGroupClass
*klass
) {
321 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
323 obj_class
->finalize
= purple_group_finalize
;
324 obj_class
->constructed
= purple_group_constructed
;
326 /* Setup properties */
327 obj_class
->get_property
= purple_group_get_property
;
328 obj_class
->set_property
= purple_group_set_property
;
330 properties
[GROUP_PROP_NAME
] = g_param_spec_string(
333 "Name of the group.",
335 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
| G_PARAM_STATIC_STRINGS
338 g_object_class_install_properties(obj_class
, GROUP_PROP_LAST
, properties
);
342 purple_group_new(const char *name
) {
345 if (name
== NULL
|| name
[0] == '\0')
346 name
= PURPLE_BLIST_DEFAULT_GROUP_NAME
;
347 if (g_strcmp0(name
, "Buddies") == 0)
348 name
= PURPLE_BLIST_DEFAULT_GROUP_NAME
;
349 if (g_strcmp0(name
, _purple_blist_get_localized_default_group_name()) == 0)
350 name
= PURPLE_BLIST_DEFAULT_GROUP_NAME
;
352 group
= purple_blist_find_group(name
);
356 return g_object_new(PURPLE_TYPE_GROUP
, "name", name
, NULL
);