Adapt migration for files
[pidgin-git.git] / libpurple / contact.c
blob8f70f397b7572b9907fb595e3d6c0dbcea64c2bd
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 "dbus-maybe.h"
26 #include "internal.h" /* TODO: this needs to die */
27 #include "util.h"
29 #define PURPLE_CONTACT_GET_PRIVATE(obj) \
30 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_CONTACT, PurpleContactPrivate))
32 typedef struct _PurpleContactPrivate PurpleContactPrivate;
34 struct _PurpleContactPrivate {
35 char *alias; /* The user-set alias of the contact */
36 PurpleBuddy *priority_buddy; /* The "top" buddy for this contact */
37 gboolean priority_valid; /* Is priority valid? */
40 enum
42 PROP_0,
43 PROP_ALIAS,
44 PROP_PRIORITY_BUDDY,
45 PROP_LAST
48 /******************************************************************************
49 * Globals
50 *****************************************************************************/
51 static GObjectClass *parent_class = NULL;
52 static GParamSpec *properties[PROP_LAST];
54 /******************************************************************************
55 * API
56 *****************************************************************************/
57 static void
58 purple_contact_compute_priority_buddy(PurpleContact *contact) {
59 PurpleBlistNode *bnode;
60 PurpleBuddy *new_priority = NULL;
61 PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
63 g_return_if_fail(priv != NULL);
65 priv->priority_buddy = NULL;
66 for (bnode = PURPLE_BLIST_NODE(contact)->child;
67 bnode != NULL;
68 bnode = bnode->next)
70 PurpleBuddy *buddy;
72 if (!PURPLE_IS_BUDDY(bnode))
73 continue;
75 buddy = PURPLE_BUDDY(bnode);
76 if (new_priority == NULL)
78 new_priority = buddy;
79 continue;
82 if (purple_account_is_connected(purple_buddy_get_account(buddy)))
84 int cmp = 1;
85 if (purple_account_is_connected(purple_buddy_get_account(new_priority)))
86 cmp = purple_buddy_presence_compare(
87 PURPLE_BUDDY_PRESENCE(purple_buddy_get_presence(new_priority)),
88 PURPLE_BUDDY_PRESENCE(purple_buddy_get_presence(buddy)));
90 if (cmp > 0 || (cmp == 0 &&
91 purple_prefs_get_bool("/purple/contact/last_match")))
93 new_priority = buddy;
98 priv->priority_buddy = new_priority;
99 priv->priority_valid = TRUE;
101 g_object_notify_by_pspec(G_OBJECT(contact),
102 properties[PROP_PRIORITY_BUDDY]);
105 PurpleGroup *
106 purple_contact_get_group(const PurpleContact *contact)
108 g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
110 return PURPLE_GROUP(PURPLE_BLIST_NODE(contact)->parent);
113 void
114 purple_contact_set_alias(PurpleContact *contact, const char *alias)
116 PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
117 PurpleIMConversation *im;
118 PurpleBlistNode *bnode;
119 char *old_alias;
120 char *new_alias = NULL;
121 PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
123 g_return_if_fail(priv != NULL);
125 if ((alias != NULL) && (*alias != '\0'))
126 new_alias = purple_utf8_strip_unprintables(alias);
128 if (!purple_strequal(priv->alias, new_alias)) {
129 g_free(new_alias);
130 return;
133 old_alias = priv->alias;
135 if ((new_alias != NULL) && (*new_alias != '\0'))
136 priv->alias = new_alias;
137 else {
138 priv->alias = NULL;
139 g_free(new_alias); /* could be "\0" */
142 g_object_notify_by_pspec(G_OBJECT(contact),
143 properties[PROP_ALIAS]);
145 if (ops) {
146 if (ops->save_node)
147 ops->save_node(PURPLE_BLIST_NODE(contact));
148 if (ops->update)
149 ops->update(purple_blist_get_buddy_list(), PURPLE_BLIST_NODE(contact));
152 for(bnode = PURPLE_BLIST_NODE(contact)->child; bnode != NULL; bnode = bnode->next)
154 PurpleBuddy *buddy = PURPLE_BUDDY(bnode);
156 im = purple_conversations_find_im_with_account(purple_buddy_get_name(buddy),
157 purple_buddy_get_account(buddy));
158 if (im)
159 purple_conversation_autoset_title(PURPLE_CONVERSATION(im));
162 purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
163 contact, old_alias);
164 g_free(old_alias);
167 const char *purple_contact_get_alias(PurpleContact* contact)
169 PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
171 g_return_val_if_fail(priv != NULL, NULL);
173 if (priv->alias)
174 return priv->alias;
176 return purple_buddy_get_alias(purple_contact_get_priority_buddy(contact));
179 gboolean purple_contact_on_account(PurpleContact *c, PurpleAccount *account)
181 PurpleBlistNode *bnode, *cnode = (PurpleBlistNode *) c;
183 g_return_val_if_fail(PURPLE_IS_CONTACT(c), FALSE);
184 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
186 for (bnode = cnode->child; bnode; bnode = bnode->next) {
187 PurpleBuddy *buddy;
189 if (! PURPLE_IS_BUDDY(bnode))
190 continue;
192 buddy = (PurpleBuddy *)bnode;
193 if (purple_buddy_get_account(buddy) == account)
194 return TRUE;
196 return FALSE;
199 void purple_contact_invalidate_priority_buddy(PurpleContact *contact)
201 PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
203 g_return_if_fail(priv != NULL);
205 priv->priority_valid = FALSE;
208 PurpleBuddy *purple_contact_get_priority_buddy(PurpleContact *contact)
210 PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
212 g_return_val_if_fail(priv != NULL, NULL);
214 if (!priv->priority_valid)
215 purple_contact_compute_priority_buddy(contact);
217 return priv->priority_buddy;
220 void purple_contact_merge(PurpleContact *source, PurpleBlistNode *node)
222 PurpleBlistNode *sourcenode = (PurpleBlistNode*)source;
223 PurpleBlistNode *prev, *cur, *next;
224 PurpleContact *target;
226 g_return_if_fail(PURPLE_IS_CONTACT(source));
227 g_return_if_fail(PURPLE_IS_BLIST_NODE(node));
229 if (PURPLE_IS_CONTACT(node)) {
230 target = (PurpleContact *)node;
231 prev = _purple_blist_get_last_child(node);
232 } else if (PURPLE_IS_BUDDY(node)) {
233 target = (PurpleContact *)node->parent;
234 prev = node;
235 } else {
236 return;
239 if (source == target || !target)
240 return;
242 next = sourcenode->child;
244 while (next) {
245 cur = next;
246 next = cur->next;
247 if (PURPLE_IS_BUDDY(cur)) {
248 purple_blist_add_buddy((PurpleBuddy *)cur, target, NULL, prev);
249 prev = cur;
254 /**************************************************************************
255 * GObject Stuff
256 **************************************************************************/
257 /* Set method for GObject properties */
258 static void
259 purple_contact_set_property(GObject *obj, guint param_id, const GValue *value,
260 GParamSpec *pspec)
262 PurpleContact *contact = PURPLE_CONTACT(obj);
264 switch (param_id) {
265 case PROP_ALIAS:
266 purple_contact_set_alias(contact, g_value_get_string(value));
267 break;
268 default:
269 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
270 break;
274 /* Get method for GObject properties */
275 static void
276 purple_contact_get_property(GObject *obj, guint param_id, GValue *value,
277 GParamSpec *pspec)
279 PurpleContact *contact = PURPLE_CONTACT(obj);
280 PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
282 switch (param_id) {
283 case PROP_ALIAS:
284 g_value_set_string(value, priv->alias);
285 break;
286 case PROP_PRIORITY_BUDDY:
287 g_value_set_object(value, purple_contact_get_priority_buddy(contact));
288 break;
289 default:
290 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
291 break;
295 /* GObject initialization function */
296 static void
297 purple_contact_init(GTypeInstance *instance, gpointer klass)
299 PurpleContact *contact = PURPLE_CONTACT(instance);
300 PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
302 if (ops && ops->new_node)
303 ops->new_node(PURPLE_BLIST_NODE(contact));
305 PURPLE_DBUS_REGISTER_POINTER(contact, PurpleContact);
308 /* GObject finalize function */
309 static void
310 purple_contact_finalize(GObject *object)
312 g_free(PURPLE_CONTACT_GET_PRIVATE(object)->alias);
314 PURPLE_DBUS_UNREGISTER_POINTER(object);
316 G_OBJECT_CLASS(parent_class)->finalize(object);
319 /* Class initializer function */
320 static void purple_contact_class_init(PurpleContactClass *klass)
322 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
324 parent_class = g_type_class_peek_parent(klass);
326 obj_class->finalize = purple_contact_finalize;
328 /* Setup properties */
329 obj_class->get_property = purple_contact_get_property;
330 obj_class->set_property = purple_contact_set_property;
332 g_type_class_add_private(klass, sizeof(PurpleContactPrivate));
334 properties[PROP_ALIAS] = g_param_spec_string(
335 "alias",
336 "Alias",
337 "The alias for the contact.",
338 NULL,
339 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
342 properties[PROP_PRIORITY_BUDDY] = g_param_spec_object(
343 "priority-buddy",
344 "Priority buddy",
345 "The priority buddy of the contact.",
346 PURPLE_TYPE_BUDDY,
347 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS
350 g_object_class_install_properties(obj_class, PROP_LAST, properties);
353 GType
354 purple_contact_get_type(void)
356 static GType type = 0;
358 if(type == 0) {
359 static const GTypeInfo info = {
360 sizeof(PurpleContactClass),
361 NULL,
362 NULL,
363 (GClassInitFunc)purple_contact_class_init,
364 NULL,
365 NULL,
366 sizeof(PurpleContact),
368 (GInstanceInitFunc)purple_contact_init,
369 NULL,
372 type = g_type_register_static(
373 PURPLE_TYPE_COUNTING_NODE,
374 "PurpleContact",
375 &info,
380 return type;
383 PurpleContact *
384 purple_contact_new(void)
386 return g_object_new(PURPLE_TYPE_CONTACT, NULL);