]> git.0d.be Git - empathy.git/blob - libempathy/empathy-connection-aggregator.c
Updated Swedish translation
[empathy.git] / libempathy / empathy-connection-aggregator.c
1 /*
2  * empathy-connection-aggregator.c - Source for EmpathyConnectionAggregator
3  * Copyright (C) 2010 Collabora Ltd.
4  * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "config.h"
22 #include "empathy-connection-aggregator.h"
23
24 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
25 #include "empathy-debug.h"
26
27 G_DEFINE_TYPE (EmpathyConnectionAggregator, empathy_connection_aggregator,
28     G_TYPE_OBJECT);
29
30 enum {
31   EVENT_CONTACT_LIST_CHANGED,
32   LAST_SIGNAL
33 };
34
35 static guint signals[LAST_SIGNAL];
36
37 struct _EmpathyConnectionAggregatorPriv {
38   TpAccountManager *mgr;
39
40   /* List of owned TpConnection */
41   GList *conns;
42 };
43
44 static void
45 empathy_connection_aggregator_dispose (GObject *object)
46 {
47   EmpathyConnectionAggregator *self = (EmpathyConnectionAggregator *) object;
48
49   g_clear_object (&self->priv->mgr);
50
51   g_list_free_full (self->priv->conns, g_object_unref);
52   self->priv->conns = NULL;
53
54   G_OBJECT_CLASS (empathy_connection_aggregator_parent_class)->dispose (object);
55 }
56
57 static void
58 empathy_connection_aggregator_class_init (
59     EmpathyConnectionAggregatorClass *klass)
60 {
61   GObjectClass *oclass = G_OBJECT_CLASS (klass);
62
63   oclass->dispose = empathy_connection_aggregator_dispose;
64
65   signals[EVENT_CONTACT_LIST_CHANGED] =
66     g_signal_new ("contact-list-changed",
67       G_TYPE_FROM_CLASS (klass),
68       G_SIGNAL_RUN_LAST,
69       0,
70       NULL, NULL,
71       g_cclosure_marshal_generic,
72       G_TYPE_NONE,
73       2, G_TYPE_PTR_ARRAY, G_TYPE_PTR_ARRAY);
74
75   g_type_class_add_private (klass, sizeof (EmpathyConnectionAggregatorPriv));
76 }
77
78 static void
79 contact_list_changed_cb (TpConnection *conn,
80     GPtrArray *added,
81     GPtrArray *removed,
82     EmpathyConnectionAggregator *self)
83 {
84   g_signal_emit (self, signals[EVENT_CONTACT_LIST_CHANGED], 0, added, removed);
85 }
86
87 static void
88 conn_invalidated_cb (TpConnection *conn,
89     guint domain,
90     gint code,
91     gchar *message,
92     EmpathyConnectionAggregator *self)
93 {
94   self->priv->conns = g_list_remove (self->priv->conns, conn);
95
96   g_object_unref (conn);
97 }
98
99 static void
100 check_connection (EmpathyConnectionAggregator *self,
101     TpConnection *conn)
102 {
103   GPtrArray *contacts;
104
105   if (g_list_find (self->priv->conns, conn) != NULL)
106     return;
107
108   self->priv->conns = g_list_prepend (self->priv->conns,
109       g_object_ref (conn));
110
111   tp_g_signal_connect_object (conn, "contact-list-changed",
112       G_CALLBACK (contact_list_changed_cb), self, 0);
113
114   contacts = tp_connection_dup_contact_list (conn);
115   if (contacts != NULL)
116     {
117       GPtrArray *empty;
118
119       empty = g_ptr_array_new ();
120
121       contact_list_changed_cb (conn, contacts, empty, self);
122       g_ptr_array_unref (empty);
123     }
124   g_ptr_array_unref (contacts);
125
126   tp_g_signal_connect_object (conn, "invalidated",
127       G_CALLBACK (conn_invalidated_cb), self, 0);
128 }
129
130 static void
131 check_account (EmpathyConnectionAggregator *self,
132     TpAccount *account)
133 {
134   TpConnection *conn;
135
136   conn = tp_account_get_connection (account);
137   if (conn != NULL)
138     check_connection (self, conn);
139 }
140
141 static void
142 account_conn_changed_cb (TpAccount *account,
143     GParamSpec *spec,
144     EmpathyConnectionAggregator *self)
145 {
146   check_account (self, account);
147 }
148
149 static void
150 add_account (EmpathyConnectionAggregator *self,
151     TpAccount *account)
152 {
153   check_account (self, account);
154
155   tp_g_signal_connect_object (account, "notify::connection",
156       G_CALLBACK (account_conn_changed_cb), self, 0);
157 }
158
159 static void
160 account_validity_changed_cb (TpAccountManager *manager,
161     TpAccount *account,
162     gboolean valid,
163     EmpathyConnectionAggregator *self)
164 {
165   if (valid)
166     add_account (self, account);
167 }
168
169 static void
170 am_prepare_cb (GObject *source,
171     GAsyncResult *result,
172     gpointer user_data)
173 {
174   EmpathyConnectionAggregator *self = EMPATHY_CONNECTION_AGGREGATOR (user_data);
175   GError *error = NULL;
176   GList *accounts, *l;
177
178   if (!tp_proxy_prepare_finish (source, result, &error))
179     {
180       DEBUG ("Failed to prepare account manager: %s", error->message);
181       g_error_free (error);
182       goto out;
183     }
184
185   accounts = tp_account_manager_dup_valid_accounts (self->priv->mgr);
186   for (l = accounts; l != NULL; l = g_list_next (l))
187     {
188       TpAccount *account = l->data;
189
190       add_account (self, account);
191     }
192
193   tp_g_signal_connect_object (self->priv->mgr, "account-validity-changed",
194       G_CALLBACK (account_validity_changed_cb), self, 0);
195
196   g_list_free_full (accounts, g_object_unref);
197
198 out:
199   g_object_unref (self);
200 }
201
202 static void
203 empathy_connection_aggregator_init (EmpathyConnectionAggregator *self)
204 {
205   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
206       EMPATHY_TYPE_CONNECTION_AGGREGATOR, EmpathyConnectionAggregatorPriv);
207
208   self->priv->mgr = tp_account_manager_dup ();
209
210   tp_proxy_prepare_async (self->priv->mgr, NULL, am_prepare_cb,
211       g_object_ref (self));
212 }
213
214 EmpathyConnectionAggregator *
215 empathy_connection_aggregator_dup_singleton (void)
216 {
217   static EmpathyConnectionAggregator *aggregator = NULL;
218
219   if (G_LIKELY (aggregator != NULL))
220       return g_object_ref (aggregator);
221
222   aggregator = g_object_new (EMPATHY_TYPE_CONNECTION_AGGREGATOR, NULL);
223
224   g_object_add_weak_pointer (G_OBJECT (aggregator), (gpointer *) &aggregator);
225   return aggregator;
226 }
227
228 /* (transfer container) */
229 GList *
230 empathy_connection_aggregator_get_all_groups (EmpathyConnectionAggregator *self)
231 {
232   GList *keys, *l;
233   GHashTable *set;
234
235   set = g_hash_table_new (g_str_hash, g_str_equal);
236
237   for (l = self->priv->conns; l != NULL; l = g_list_next (l))
238     {
239       TpConnection *conn = l->data;
240       const gchar * const *groups;
241       guint i;
242
243       groups = tp_connection_get_contact_groups (conn);
244       if (groups == NULL)
245         continue;
246
247       for (i = 0; groups[i] != NULL; i++)
248         g_hash_table_insert (set, (gchar *) groups[i], GUINT_TO_POINTER (TRUE));
249     }
250
251   keys = g_hash_table_get_keys (set);
252   g_hash_table_unref (set);
253
254   return keys;
255 }
256
257 GPtrArray *
258 empathy_connection_aggregator_dup_all_contacts (
259     EmpathyConnectionAggregator *self)
260 {
261   GPtrArray *result;
262   GList *l;
263
264   result = g_ptr_array_new_with_free_func (g_object_unref);
265
266   for (l = self->priv->conns; l != NULL; l = g_list_next (l))
267     {
268       TpConnection *conn = l->data;
269       GPtrArray *contacts;
270
271       contacts = tp_connection_dup_contact_list (conn);
272       if (contacts == NULL)
273         continue;
274
275       tp_g_ptr_array_extend (result, contacts);
276
277       /* tp_g_ptr_array_extend() doesn't give us an extra ref */
278       g_ptr_array_foreach (contacts, (GFunc) g_object_ref, NULL);
279
280       g_ptr_array_unref (contacts);
281     }
282
283   return result;
284 }
285
286 static void
287 rename_group_cb (GObject *source,
288     GAsyncResult *result,
289     gpointer user_data)
290 {
291   GError *error = NULL;
292
293   if (!tp_connection_rename_group_finish (TP_CONNECTION (source), result,
294         &error))
295     {
296       DEBUG ("Failed to rename group on %s: %s",
297           tp_proxy_get_object_path (source), error->message);
298       g_error_free (error);
299     }
300 }
301
302 void
303 empathy_connection_aggregator_rename_group (EmpathyConnectionAggregator *self,
304     const gchar *old_name,
305     const gchar *new_name)
306 {
307   GList *l;
308
309   for (l = self->priv->conns; l != NULL; l = g_list_next (l))
310     {
311       TpConnection *conn = l->data;
312       const gchar * const *groups;
313
314       groups = tp_connection_get_contact_groups (conn);
315
316       if (!tp_strv_contains (groups, old_name))
317         continue;
318
319       DEBUG ("Rename group '%s' to '%s' on %s", old_name, new_name,
320           tp_proxy_get_object_path (conn));
321
322       tp_connection_rename_group_async (conn, old_name, new_name,
323           rename_group_cb, NULL);
324     }
325 }