Merged in default (pull request #594)
[pidgin-git.git] / libpurple / contact.c
blob8ed691f0fdd012971ec2ffbec6af40d883ab42f5
1 /*
2 * purple
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
6 * source distribution.
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 "contact.h"
25 #include "internal.h" /* TODO: this needs to die */
26 #include "util.h"
28 typedef struct _PurpleContactPrivate PurpleContactPrivate;
30 struct _PurpleContactPrivate {
31 char *alias; /* The user-set alias of the contact */
32 PurpleBuddy *priority_buddy; /* The "top" buddy for this contact */
33 gboolean priority_valid; /* Is priority valid? */
36 enum
38 PROP_0,
39 PROP_ALIAS,
40 PROP_PRIORITY_BUDDY,
41 PROP_LAST
44 /******************************************************************************
45 * Globals
46 *****************************************************************************/
47 static GParamSpec *properties[PROP_LAST];
49 G_DEFINE_TYPE_WITH_PRIVATE(PurpleContact, purple_contact,
50 PURPLE_TYPE_COUNTING_NODE);
52 /******************************************************************************
53 * API
54 *****************************************************************************/
55 static void
56 purple_contact_compute_priority_buddy(PurpleContact *contact) {
57 PurpleBlistNode *bnode;
58 PurpleBuddy *new_priority = NULL;
59 PurpleContactPrivate *priv =
60 purple_contact_get_instance_private(contact);
62 priv->priority_buddy = NULL;
63 for (bnode = PURPLE_BLIST_NODE(contact)->child;
64 bnode != NULL;
65 bnode = bnode->next)
67 PurpleBuddy *buddy;
69 if (!PURPLE_IS_BUDDY(bnode))
70 continue;
72 buddy = PURPLE_BUDDY(bnode);
73 if (new_priority == NULL)
75 new_priority = buddy;
76 continue;
79 if (purple_account_is_connected(purple_buddy_get_account(buddy)))
81 int cmp = 1;
82 if (purple_account_is_connected(purple_buddy_get_account(new_priority)))
83 cmp = purple_buddy_presence_compare(
84 PURPLE_BUDDY_PRESENCE(purple_buddy_get_presence(new_priority)),
85 PURPLE_BUDDY_PRESENCE(purple_buddy_get_presence(buddy)));
87 if (cmp > 0 || (cmp == 0 &&
88 purple_prefs_get_bool("/purple/contact/last_match")))
90 new_priority = buddy;
95 priv->priority_buddy = new_priority;
96 priv->priority_valid = TRUE;
98 g_object_notify_by_pspec(G_OBJECT(contact),
99 properties[PROP_PRIORITY_BUDDY]);
102 PurpleGroup *
103 purple_contact_get_group(const PurpleContact *contact)
105 g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
107 return PURPLE_GROUP(PURPLE_BLIST_NODE(contact)->parent);
110 void
111 purple_contact_set_alias(PurpleContact *contact, const char *alias)
113 PurpleContactPrivate *priv = NULL;
114 PurpleIMConversation *im;
115 PurpleBlistNode *bnode;
116 char *old_alias;
117 char *new_alias = NULL;
119 g_return_if_fail(PURPLE_IS_CONTACT(contact));
120 priv = purple_contact_get_instance_private(contact);
122 if ((alias != NULL) && (*alias != '\0'))
123 new_alias = purple_utf8_strip_unprintables(alias);
125 if (!purple_strequal(priv->alias, new_alias)) {
126 g_free(new_alias);
127 return;
130 old_alias = priv->alias;
132 if ((new_alias != NULL) && (*new_alias != '\0'))
133 priv->alias = new_alias;
134 else {
135 priv->alias = NULL;
136 g_free(new_alias); /* could be "\0" */
139 g_object_notify_by_pspec(G_OBJECT(contact),
140 properties[PROP_ALIAS]);
142 purple_blist_save_node(purple_blist_get_default(),
143 PURPLE_BLIST_NODE(contact));
144 purple_blist_update_node(purple_blist_get_default(),
145 PURPLE_BLIST_NODE(contact));
147 for(bnode = PURPLE_BLIST_NODE(contact)->child; bnode != NULL; bnode = bnode->next)
149 PurpleBuddy *buddy = PURPLE_BUDDY(bnode);
151 im = purple_conversations_find_im_with_account(purple_buddy_get_name(buddy),
152 purple_buddy_get_account(buddy));
153 if (im)
154 purple_conversation_autoset_title(PURPLE_CONVERSATION(im));
157 purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
158 contact, old_alias);
159 g_free(old_alias);
162 const char *purple_contact_get_alias(PurpleContact* contact)
164 PurpleContactPrivate *priv = NULL;
166 g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
168 priv = purple_contact_get_instance_private(contact);
169 if (priv->alias)
170 return priv->alias;
172 return purple_buddy_get_alias(purple_contact_get_priority_buddy(contact));
175 gboolean purple_contact_on_account(PurpleContact *c, PurpleAccount *account)
177 PurpleBlistNode *bnode, *cnode = (PurpleBlistNode *) c;
179 g_return_val_if_fail(PURPLE_IS_CONTACT(c), FALSE);
180 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
182 for (bnode = cnode->child; bnode; bnode = bnode->next) {
183 PurpleBuddy *buddy;
185 if (! PURPLE_IS_BUDDY(bnode))
186 continue;
188 buddy = (PurpleBuddy *)bnode;
189 if (purple_buddy_get_account(buddy) == account)
190 return TRUE;
192 return FALSE;
195 void purple_contact_invalidate_priority_buddy(PurpleContact *contact)
197 PurpleContactPrivate *priv = NULL;
199 g_return_if_fail(PURPLE_IS_CONTACT(contact));
201 priv = purple_contact_get_instance_private(contact);
202 priv->priority_valid = FALSE;
205 PurpleBuddy *purple_contact_get_priority_buddy(PurpleContact *contact)
207 PurpleContactPrivate *priv = NULL;
209 g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
211 priv = purple_contact_get_instance_private(contact);
212 if (!priv->priority_valid)
213 purple_contact_compute_priority_buddy(contact);
215 return priv->priority_buddy;
218 void purple_contact_merge(PurpleContact *source, PurpleBlistNode *node)
220 PurpleBlistNode *sourcenode = (PurpleBlistNode*)source;
221 PurpleBlistNode *prev, *cur, *next;
222 PurpleContact *target;
224 g_return_if_fail(PURPLE_IS_CONTACT(source));
225 g_return_if_fail(PURPLE_IS_BLIST_NODE(node));
227 if (PURPLE_IS_CONTACT(node)) {
228 target = (PurpleContact *)node;
229 prev = _purple_blist_get_last_child(node);
230 } else if (PURPLE_IS_BUDDY(node)) {
231 target = (PurpleContact *)node->parent;
232 prev = node;
233 } else {
234 return;
237 if (source == target || !target)
238 return;
240 next = sourcenode->child;
242 while (next) {
243 cur = next;
244 next = cur->next;
245 if (PURPLE_IS_BUDDY(cur)) {
246 purple_blist_add_buddy((PurpleBuddy *)cur, target, NULL, prev);
247 prev = cur;
252 /**************************************************************************
253 * GObject Stuff
254 **************************************************************************/
255 /* Set method for GObject properties */
256 static void
257 purple_contact_set_property(GObject *obj, guint param_id, const GValue *value,
258 GParamSpec *pspec)
260 PurpleContact *contact = PURPLE_CONTACT(obj);
262 switch (param_id) {
263 case PROP_ALIAS:
264 purple_contact_set_alias(contact, g_value_get_string(value));
265 break;
266 default:
267 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
268 break;
272 /* Get method for GObject properties */
273 static void
274 purple_contact_get_property(GObject *obj, guint param_id, GValue *value,
275 GParamSpec *pspec)
277 PurpleContact *contact = PURPLE_CONTACT(obj);
278 PurpleContactPrivate *priv =
279 purple_contact_get_instance_private(contact);
281 switch (param_id) {
282 case PROP_ALIAS:
283 g_value_set_string(value, priv->alias);
284 break;
285 case PROP_PRIORITY_BUDDY:
286 g_value_set_object(value, purple_contact_get_priority_buddy(contact));
287 break;
288 default:
289 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
290 break;
294 /* GObject initialization function */
295 static void
296 purple_contact_init(PurpleContact *contact)
298 purple_blist_new_node(purple_blist_get_default(),
299 PURPLE_BLIST_NODE(contact));
302 /* GObject finalize function */
303 static void
304 purple_contact_finalize(GObject *object)
306 PurpleContactPrivate *priv = purple_contact_get_instance_private(
307 PURPLE_CONTACT(object));
309 g_free(priv->alias);
311 G_OBJECT_CLASS(purple_contact_parent_class)->finalize(object);
314 /* Class initializer function */
315 static void purple_contact_class_init(PurpleContactClass *klass)
317 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
319 obj_class->finalize = purple_contact_finalize;
321 /* Setup properties */
322 obj_class->get_property = purple_contact_get_property;
323 obj_class->set_property = purple_contact_set_property;
325 properties[PROP_ALIAS] = g_param_spec_string(
326 "alias",
327 "Alias",
328 "The alias for the contact.",
329 NULL,
330 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
333 properties[PROP_PRIORITY_BUDDY] = g_param_spec_object(
334 "priority-buddy",
335 "Priority buddy",
336 "The priority buddy of the contact.",
337 PURPLE_TYPE_BUDDY,
338 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS
341 g_object_class_install_properties(obj_class, PROP_LAST, properties);
344 PurpleContact *
345 purple_contact_new(void)
347 return g_object_new(PURPLE_TYPE_CONTACT, NULL);