]> git.0d.be Git - empathy.git/blob - libempathy/empathy-tp-contact-factory.c
Merge remote branch 'vminko/fix-632024-v2'
[empathy.git] / libempathy / empathy-tp-contact-factory.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007-2009 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include <config.h>
23
24 #include "empathy-tp-contact-factory.h"
25
26 #define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CONTACT
27 #include "empathy-debug.h"
28
29 static TpContactFeature contact_features[] = {
30         TP_CONTACT_FEATURE_ALIAS,
31         TP_CONTACT_FEATURE_PRESENCE,
32         TP_CONTACT_FEATURE_LOCATION,
33         TP_CONTACT_FEATURE_CAPABILITIES,
34 };
35
36 typedef union {
37         EmpathyTpContactFactoryContactsByIdCb ids_cb;
38         EmpathyTpContactFactoryContactsByHandleCb handles_cb;
39         EmpathyTpContactFactoryContactCb contact_cb;
40 } GetContactsCb;
41
42 typedef struct {
43         TpConnection *connection;
44         GetContactsCb callback;
45         gpointer user_data;
46         GDestroyNotify destroy;
47 } GetContactsData;
48
49 static void
50 get_contacts_data_free (gpointer user_data)
51 {
52         GetContactsData *data = user_data;
53
54         if (data->destroy) {
55                 data->destroy (data->user_data);
56         }
57         g_object_unref (data->connection);
58
59         g_slice_free (GetContactsData, data);
60 }
61
62 static EmpathyContact **
63 contacts_array_new (guint n_contacts,
64                     TpContact * const * contacts)
65 {
66         EmpathyContact **ret;
67         guint            i;
68
69         ret = g_new0 (EmpathyContact *, n_contacts);
70         for (i = 0; i < n_contacts; i++) {
71                 ret[i] = empathy_contact_dup_from_tp_contact (contacts[i]);
72         }
73
74         return ret;
75 }
76
77 static void
78 contacts_array_free (guint            n_contacts,
79                      EmpathyContact **contacts)
80 {
81         guint i;
82
83         for (i = 0; i < n_contacts; i++) {
84                 g_object_unref (contacts[i]);
85         }
86         g_free (contacts);
87 }
88
89 static void
90 get_contacts_by_id_cb (TpConnection *connection,
91                        guint n_contacts,
92                        TpContact * const *contacts,
93                        const gchar * const *requested_ids,
94                        GHashTable *failed_id_errors,
95                        const GError *error,
96                        gpointer user_data,
97                        GObject *weak_object)
98 {
99         GetContactsData *data = user_data;
100         EmpathyContact **empathy_contacts;
101
102         empathy_contacts = contacts_array_new (n_contacts, contacts);
103         if (data->callback.ids_cb) {
104                 data->callback.ids_cb (data->connection,
105                                        n_contacts, empathy_contacts,
106                                        requested_ids,
107                                        failed_id_errors,
108                                        error,
109                                        data->user_data, weak_object);
110         }
111
112         contacts_array_free (n_contacts, empathy_contacts);
113 }
114
115 /* The callback is NOT given a reference to the EmpathyContact objects */
116 void
117 empathy_tp_contact_factory_get_from_ids (TpConnection            *connection,
118                                          guint                    n_ids,
119                                          const gchar * const     *ids,
120                                          EmpathyTpContactFactoryContactsByIdCb callback,
121                                          gpointer                 user_data,
122                                          GDestroyNotify           destroy,
123                                          GObject                 *weak_object)
124 {
125         GetContactsData *data;
126
127         g_return_if_fail (TP_IS_CONNECTION (connection));
128         g_return_if_fail (ids != NULL);
129
130         data = g_slice_new (GetContactsData);
131         data->callback.ids_cb = callback;
132         data->user_data = user_data;
133         data->destroy = destroy;
134         data->connection = g_object_ref (connection);
135         tp_connection_get_contacts_by_id (connection,
136                                           n_ids, ids,
137                                           G_N_ELEMENTS (contact_features),
138                                           contact_features,
139                                           get_contacts_by_id_cb,
140                                           data,
141                                           (GDestroyNotify) get_contacts_data_free,
142                                           weak_object);
143 }
144
145 static void
146 get_contact_by_id_cb (TpConnection *connection,
147                       guint n_contacts,
148                       TpContact * const *contacts,
149                       const gchar * const *requested_ids,
150                       GHashTable *failed_id_errors,
151                       const GError *error,
152                       gpointer user_data,
153                       GObject *weak_object)
154 {
155         GetContactsData *data = user_data;
156         EmpathyContact  *contact = NULL;
157
158         if (n_contacts == 1) {
159                 contact = empathy_contact_dup_from_tp_contact (contacts[0]);
160         }
161         else if (error == NULL) {
162                 GHashTableIter iter;
163                 gpointer       value;
164
165                 g_hash_table_iter_init (&iter, failed_id_errors);
166                 while (g_hash_table_iter_next (&iter, NULL, &value)) {
167                         if (value) {
168                                 error = value;
169                                 break;
170                         }
171                 }
172         }
173
174         if (data->callback.contact_cb) {
175                 data->callback.contact_cb (data->connection,
176                                            contact,
177                                            error,
178                                            data->user_data, weak_object);
179         }
180
181         if (contact != NULL)
182                 g_object_unref (contact);
183 }
184
185 /* The callback is NOT given a reference to the EmpathyContact objects */
186 void
187 empathy_tp_contact_factory_get_from_id (TpConnection            *connection,
188                                         const gchar             *id,
189                                         EmpathyTpContactFactoryContactCb callback,
190                                         gpointer                 user_data,
191                                         GDestroyNotify           destroy,
192                                         GObject                 *weak_object)
193 {
194         GetContactsData *data;
195
196         g_return_if_fail (TP_IS_CONNECTION (connection));
197         g_return_if_fail (id != NULL);
198
199         data = g_slice_new (GetContactsData);
200         data->callback.contact_cb = callback;
201         data->user_data = user_data;
202         data->destroy = destroy;
203         data->connection = g_object_ref (connection);
204         tp_connection_get_contacts_by_id (connection,
205                                           1, &id,
206                                           G_N_ELEMENTS (contact_features),
207                                           contact_features,
208                                           get_contact_by_id_cb,
209                                           data,
210                                           (GDestroyNotify) get_contacts_data_free,
211                                           weak_object);
212 }
213
214 static void
215 get_contacts_by_handle_cb (TpConnection *connection,
216                            guint n_contacts,
217                            TpContact * const *contacts,
218                            guint n_failed,
219                            const TpHandle *failed,
220                            const GError *error,
221                            gpointer user_data,
222                            GObject *weak_object)
223 {
224         GetContactsData *data = user_data;
225         EmpathyContact **empathy_contacts;
226
227         empathy_contacts = contacts_array_new (n_contacts, contacts);
228         if (data->callback.handles_cb) {
229                 data->callback.handles_cb (data->connection,
230                                            n_contacts, empathy_contacts,
231                                            n_failed, failed,
232                                            error,
233                                            data->user_data, weak_object);
234         }
235
236         contacts_array_free (n_contacts, empathy_contacts);
237 }
238
239 /* The callback is NOT given a reference to the EmpathyContact objects */
240 void
241 empathy_tp_contact_factory_get_from_handles (TpConnection *connection,
242                                              guint n_handles,
243                                              const TpHandle *handles,
244                                              EmpathyTpContactFactoryContactsByHandleCb callback,
245                                              gpointer                 user_data,
246                                              GDestroyNotify           destroy,
247                                              GObject                 *weak_object)
248 {
249         GetContactsData *data;
250
251         if (n_handles == 0) {
252                 callback (connection, 0, NULL, 0, NULL, NULL, user_data, weak_object);
253                 return;
254         }
255
256         g_return_if_fail (TP_IS_CONNECTION (connection));
257         g_return_if_fail (handles != NULL);
258
259         data = g_slice_new (GetContactsData);
260         data->callback.handles_cb = callback;
261         data->user_data = user_data;
262         data->destroy = destroy;
263         data->connection = g_object_ref (connection);
264         tp_connection_get_contacts_by_handle (connection,
265                                               n_handles, handles,
266                                               G_N_ELEMENTS (contact_features),
267                                               contact_features,
268                                               get_contacts_by_handle_cb,
269                                               data,
270                                               (GDestroyNotify) get_contacts_data_free,
271                                               weak_object);
272 }
273
274 /* The callback is NOT given a reference to the EmpathyContact objects */
275 static void
276 get_contact_by_handle_cb (TpConnection *connection,
277                           guint n_contacts,
278                           TpContact * const *contacts,
279                           guint n_failed,
280                           const TpHandle *failed,
281                           const GError *error,
282                           gpointer user_data,
283                           GObject *weak_object)
284 {
285         GetContactsData *data = user_data;
286         EmpathyContact  *contact = NULL;
287         GError *err = NULL;
288
289         if (n_contacts == 1) {
290                 contact = empathy_contact_dup_from_tp_contact (contacts[0]);
291         }
292         else {
293                 if (error == NULL) {
294                         /* tp-glib will provide an error only if the whole operation failed,
295                          * but not if, for example, the handle was invalid. We create an error
296                          * so the caller of empathy_tp_contact_factory_get_from_handle can
297                          * rely on the error to check if the operation succeeded or not. */
298
299                         err = g_error_new_literal (TP_ERRORS, TP_ERROR_INVALID_HANDLE,
300                                                       "handle is invalid");
301                 }
302                 else {
303                         err = g_error_copy (error);
304                 }
305         }
306
307         if (data->callback.contact_cb) {
308                 data->callback.contact_cb (data->connection,
309                                            contact,
310                                            err,
311                                            data->user_data, weak_object);
312         }
313
314         g_clear_error (&err);
315         if (contact != NULL)
316                 g_object_unref (contact);
317 }
318
319 void
320 empathy_tp_contact_factory_get_from_handle (TpConnection            *connection,
321                                             TpHandle                 handle,
322                                             EmpathyTpContactFactoryContactCb callback,
323                                             gpointer                 user_data,
324                                             GDestroyNotify           destroy,
325                                             GObject                 *weak_object)
326 {
327         GetContactsData *data;
328
329         g_return_if_fail (TP_IS_CONNECTION (connection));
330
331         data = g_slice_new (GetContactsData);
332         data->callback.contact_cb = callback;
333         data->user_data = user_data;
334         data->destroy = destroy;
335         data->connection = g_object_ref (connection);
336         tp_connection_get_contacts_by_handle (connection,
337                                               1, &handle,
338                                               G_N_ELEMENTS (contact_features),
339                                               contact_features,
340                                               get_contact_by_handle_cb,
341                                               data,
342                                               (GDestroyNotify) get_contacts_data_free,
343                                               weak_object);
344 }
345