1 /*
2  * handle-repo.c - mechanism to store and retrieve handles on a connection
3  * (abstract interface)
4  *
5  * Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
6  * Copyright (C) 2007 Nokia Corporation
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library 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 GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22 
23 /**
24  * SECTION:handle-repo
25  * @title: TpHandleRepoIface
26  * @short_description: abstract interface for handle allocation
27  * @see_also: TpDynamicHandleRepo, TpStaticHandleRepo
28  *
29  * Abstract interface of a repository for handles, supporting operations
30  * which include checking for validity, lookup by
31  * string value and lookup by numeric value. See #TpDynamicHandleRepo
32  * and #TpStaticHandleRepo for concrete implementations.
33  */
34 
35 #include "config.h"
36 
37 #include <telepathy-glib/handle-repo.h>
38 
39 #include <telepathy-glib/handle-repo-internal.h>
40 #include <telepathy-glib/util-internal.h>
41 
42 G_DEFINE_INTERFACE (TpHandleRepoIface, tp_handle_repo_iface, G_TYPE_OBJECT);
43 
44 /**
45  * tp_handle_is_valid: (skip)
46  * @self: A handle repository implementation
47  * @handle: A handle of the type stored in the repository @self
48  * @error: Set to InvalidHandle if %FALSE is returned
49  *
50  * <!--Returns: says it all-->
51  *
52  * Returns: %TRUE if the handle is nonzero and is present in the repository,
53  * else %FALSE
54  */
55 
56 gboolean
tp_handle_is_valid(TpHandleRepoIface * self,TpHandle handle,GError ** error)57 tp_handle_is_valid (TpHandleRepoIface *self,
58     TpHandle handle,
59     GError **error)
60 {
61   return TP_HANDLE_REPO_IFACE_GET_CLASS (self)->handle_is_valid (self,
62       handle, error);
63 }
64 
65 
66 /**
67  * tp_handles_are_valid: (skip)
68  * @self: A handle repository implementation
69  * @handles: Array of TpHandle representing handles of the type stored in
70  *           the repository @self
71  * @allow_zero: If %TRUE, zero is treated like a valid handle
72  * @error: Set to InvalidHandle if %FALSE is returned
73  *
74  * <!--Returns: says it all-->
75  *
76  * Returns: %TRUE if the handle is present in the repository, else %FALSE
77  */
78 
79 gboolean
tp_handles_are_valid(TpHandleRepoIface * self,const GArray * handles,gboolean allow_zero,GError ** error)80 tp_handles_are_valid (TpHandleRepoIface *self,
81     const GArray *handles,
82     gboolean allow_zero,
83     GError **error)
84 {
85   return TP_HANDLE_REPO_IFACE_GET_CLASS (self)->handles_are_valid (self,
86       handles, allow_zero, error);
87 }
88 
89 
90 /**
91  * tp_handle_ref: (skip)
92  * @self: not used
93  * @handle: not used
94  *
95  * Do nothing. Since version 0.13.8, handles always last as long as
96  * the connection; previously, this function provided refcounting for handles.
97  *
98  * Changed in 0.13.6: @handle is now returned; previously,
99  * this function didn't return anything.
100  *
101  * Returns: the same @handle
102  * Deprecated: This is no-op so can be safely removed.
103  */
104 
105 TpHandle
tp_handle_ref(TpHandleRepoIface * self G_GNUC_UNUSED,TpHandle handle)106 tp_handle_ref (TpHandleRepoIface *self G_GNUC_UNUSED,
107     TpHandle handle)
108 {
109   return handle;
110 }
111 
112 
113 /**
114  * tp_handles_ref: (skip)
115  * @self: not used
116  * @handles: not used
117  *
118  * Do nothing. Since version 0.13.8, handles always last as long as
119  * the connection; previously, this function provided refcounting for handles.
120  *
121  * Deprecated: This is no-op so can be safely removed.
122  */
123 void
tp_handles_ref(TpHandleRepoIface * self G_GNUC_UNUSED,const GArray * handles G_GNUC_UNUSED)124 tp_handles_ref (TpHandleRepoIface *self G_GNUC_UNUSED,
125     const GArray *handles G_GNUC_UNUSED)
126 {
127 }
128 
129 
130 /**
131  * tp_handle_unref: (skip)
132  * @self: A handle repository implementation
133  * @handle: A handle of the type stored in the repository
134  *
135  * Do nothing. Since version 0.13.8, handles always last as long as
136  * the connection; previously, this function provided refcounting for handles.
137  *
138  * Deprecated: This is no-op so can be safely removed.
139  */
140 
141 void
tp_handle_unref(TpHandleRepoIface * self G_GNUC_UNUSED,TpHandle handle G_GNUC_UNUSED)142 tp_handle_unref (TpHandleRepoIface *self G_GNUC_UNUSED,
143     TpHandle handle G_GNUC_UNUSED)
144 {
145 }
146 
147 
148 /**
149  * tp_handles_unref: (skip)
150  * @self: not used
151  * @handles: not used
152  *
153  * Do nothing. Since version 0.13.8, handles always last as long as
154  * the connection; previously, this function provided refcounting for handles.
155  *
156  * Deprecated: This is no-op so can be safely removed.
157  */
158 void
tp_handles_unref(TpHandleRepoIface * self G_GNUC_UNUSED,const GArray * handles G_GNUC_UNUSED)159 tp_handles_unref (TpHandleRepoIface *self G_GNUC_UNUSED,
160     const GArray *handles G_GNUC_UNUSED)
161 {
162 }
163 
164 
165 /**
166  * tp_handle_client_hold: (skip)
167  * @self: not used
168  * @client: not used
169  * @handle: not used
170  * @error: not set
171  *
172  * Do nothing. Since version 0.13.8, handles always last as long as
173  * the connection; previously, this function provided refcounting for handles.
174  *
175  * Returns: %TRUE
176  * Deprecated: This is no-op so can be safely removed.
177  */
178 
179 gboolean
tp_handle_client_hold(TpHandleRepoIface * self G_GNUC_UNUSED,const gchar * client G_GNUC_UNUSED,TpHandle handle G_GNUC_UNUSED,GError ** error G_GNUC_UNUSED)180 tp_handle_client_hold (TpHandleRepoIface *self G_GNUC_UNUSED,
181     const gchar *client G_GNUC_UNUSED,
182     TpHandle handle G_GNUC_UNUSED,
183     GError **error G_GNUC_UNUSED)
184 {
185   return TRUE;
186 }
187 
188 
189 typedef gboolean (*HoldReleaseFunc) (TpHandleRepoIface *, const gchar *,
190     TpHandle, GError **);
191 
192 /**
193  * tp_handles_client_hold: (skip)
194  * @self: ignored
195  * @client: ignored
196  * @handles: ignored
197  * @error: ignored
198  *
199  * Do nothing. Since version 0.13.8, handles always last as long as
200  * the connection; previously, this function provided refcounting for handles.
201  *
202  * Returns: %TRUE
203  * Deprecated: This is no-op so can be safely removed.
204  */
205 gboolean
tp_handles_client_hold(TpHandleRepoIface * self G_GNUC_UNUSED,const gchar * client G_GNUC_UNUSED,const GArray * handles G_GNUC_UNUSED,GError ** error G_GNUC_UNUSED)206 tp_handles_client_hold (TpHandleRepoIface *self G_GNUC_UNUSED,
207     const gchar *client G_GNUC_UNUSED,
208     const GArray *handles G_GNUC_UNUSED,
209     GError **error G_GNUC_UNUSED)
210 {
211   return TRUE;
212 }
213 
214 
215 /**
216  * tp_handle_client_release: (skip)
217  * @self: ignored
218  * @client: ignored
219  * @handle: ignored
220  * @error: ignored
221  *
222  * Do nothing. Since version 0.13.8, handles always last as long as
223  * the connection; previously, this function provided refcounting for handles.
224  *
225  * Returns: %TRUE
226  * Deprecated: This is no-op so can be safely removed.
227  */
228 gboolean
tp_handle_client_release(TpHandleRepoIface * self G_GNUC_UNUSED,const gchar * client G_GNUC_UNUSED,TpHandle handle G_GNUC_UNUSED,GError ** error G_GNUC_UNUSED)229 tp_handle_client_release (TpHandleRepoIface *self G_GNUC_UNUSED,
230     const gchar *client G_GNUC_UNUSED,
231     TpHandle handle G_GNUC_UNUSED,
232     GError **error G_GNUC_UNUSED)
233 {
234   return TRUE;
235 }
236 
237 /**
238  * tp_handles_client_release: (skip)
239  * @self: ignored
240  * @client: ignored
241  * @handles: ignored
242  * @error: ignored
243  *
244  * Do nothing. Since version 0.13.8, handles always last as long as
245  * the connection; previously, this function provided refcounting for handles.
246  *
247  * Returns: %TRUE
248  * Deprecated: This is no-op so can be safely removed.
249  */
250 gboolean
tp_handles_client_release(TpHandleRepoIface * self G_GNUC_UNUSED,const gchar * client G_GNUC_UNUSED,const GArray * handles G_GNUC_UNUSED,GError ** error G_GNUC_UNUSED)251 tp_handles_client_release (TpHandleRepoIface *self G_GNUC_UNUSED,
252     const gchar *client G_GNUC_UNUSED,
253     const GArray *handles G_GNUC_UNUSED,
254     GError **error G_GNUC_UNUSED)
255 {
256   return TRUE;
257 }
258 
259 
260 /**
261  * tp_handle_inspect: (skip)
262  * @self: A handle repository implementation
263  * @handle: A handle of the type stored in the repository
264  *
265  * <!--Returns: says it all-->
266  *
267  * Returns: the string represented by the given handle, or NULL if the
268  * handle is absent from the repository. The string is owned by the
269  * handle repository and will remain valid as long as a reference to
270  * the handle exists.
271  */
272 
273 const char *
tp_handle_inspect(TpHandleRepoIface * self,TpHandle handle)274 tp_handle_inspect (TpHandleRepoIface *self,
275     TpHandle handle)
276 {
277   return TP_HANDLE_REPO_IFACE_GET_CLASS (self)->inspect_handle (self,
278       handle);
279 }
280 
281 
282 /**
283  * tp_handle_ensure:
284  * @self: A handle repository implementation
285  * @id: A string whose handle is required
286  * @context: User data to be passed to the normalization callback
287  * @error: Used to return an error if 0 is returned
288  *
289  * Return a handle for the given string, creating one if necessary. The string
290  * is normalized, if possible.
291  *
292  * Returns: the handle corresponding to the given string, or 0 if it
293  * is invalid.
294  */
295 
296 TpHandle
tp_handle_ensure(TpHandleRepoIface * self,const gchar * id,gpointer context,GError ** error)297 tp_handle_ensure (TpHandleRepoIface *self,
298                   const gchar *id,
299                   gpointer context,
300                   GError **error)
301 {
302   return TP_HANDLE_REPO_IFACE_GET_CLASS (self)->ensure_handle (self,
303       id, context, error);
304 }
305 
306 /**
307  * tp_handle_ensure_async: (skip)
308  * @self: A handle repository implementation
309  * @connection: the #TpBaseConnection using this handle repo
310  * @id: A string whose handle is required
311  * @context: User data to be passed to the normalization callback
312  * @callback: a callback to call when the operation finishes
313  * @user_data: data to pass to @callback
314  *
315  * Asyncronously normalize an identifier and create an handle for it. This could
316  * involve a server round-trip. This should be used instead of
317  * tp_handle_ensure() for user provided contact identifiers, but it is not
318  * necessary for identifiers from the server.
319  *
320  * Since: 0.19.2
321  */
322 void
tp_handle_ensure_async(TpHandleRepoIface * self,TpBaseConnection * connection,const gchar * id,gpointer context,GAsyncReadyCallback callback,gpointer user_data)323 tp_handle_ensure_async (TpHandleRepoIface *self,
324     TpBaseConnection *connection,
325     const gchar *id,
326     gpointer context,
327     GAsyncReadyCallback callback,
328     gpointer user_data)
329 {
330   return TP_HANDLE_REPO_IFACE_GET_CLASS (self)->ensure_handle_async (self,
331       connection, id, context, callback, user_data);
332 }
333 
334 /**
335  * tp_handle_ensure_finish: (skip)
336  * @self: A handle repository implementation
337  * @result: a #GAsyncResult
338  * @error: a #GError to fill
339  *
340  * Finishes tp_handle_ensure_async()
341  *
342  * Returns: non-0 #TpHandle if the operation was successful, otherwise 0.
343  *
344  * Since: 0.19.2
345  */
346 TpHandle
tp_handle_ensure_finish(TpHandleRepoIface * self,GAsyncResult * result,GError ** error)347 tp_handle_ensure_finish (TpHandleRepoIface *self,
348     GAsyncResult *result,
349     GError **error)
350 {
351   return TP_HANDLE_REPO_IFACE_GET_CLASS (self)->ensure_handle_finish (self,
352       result, error);
353 }
354 
355 /**
356  * tp_handle_lookup: (skip)
357  * @self: A handle repository implementation
358  * @id: A string whose handle is required
359  * @context: User data to be passed to the normalization callback
360  * @error: Used to raise an error if the handle does not exist or is
361  *  invalid
362  *
363  * Return the handle for the given string. The string is normalized if
364  * possible. If no handle already exists for the string, none is created.
365  *
366  * Returns: the handle corresponding to the given string, or 0 if it
367  * does not exist or is invalid
368  */
369 
370 TpHandle
tp_handle_lookup(TpHandleRepoIface * self,const gchar * id,gpointer context,GError ** error)371 tp_handle_lookup (TpHandleRepoIface *self,
372                   const gchar *id,
373                   gpointer context,
374                   GError **error)
375 {
376   return TP_HANDLE_REPO_IFACE_GET_CLASS (self)->lookup_handle (self,
377       id, context, error);
378 }
379 
380 
381 /**
382  * tp_handle_set_qdata: (skip)
383  * @repo: A handle repository implementation
384  * @handle: A handle to set data on
385  * @key_id: Key id to associate data with
386  * @data: data to associate with handle
387  * @destroy: A #GDestroyNotify to call to destroy the data,
388  *           or NULL if not needed.
389  *
390  * Associates a blob of data with a given handle and a given key
391  *
392  * If @destroy is set, then the data is freed when the handle is freed.
393  *
394  * Since version 0.13.8, handles always last as long as the
395  * connection, so @destroy will not be called until the connection
396  * disconnects.
397  *
398  * Deprecated: Since 0.19.9. It is not recommended to use this function
399  *  because the associated data won't be freed until the connection disconnects.
400  */
401 
402 void
tp_handle_set_qdata(TpHandleRepoIface * repo,TpHandle handle,GQuark key_id,gpointer data,GDestroyNotify destroy)403 tp_handle_set_qdata (TpHandleRepoIface *repo,
404                      TpHandle handle,
405                      GQuark key_id,
406                      gpointer data,
407                      GDestroyNotify destroy)
408 {
409   TP_HANDLE_REPO_IFACE_GET_CLASS (repo)->set_qdata (repo,
410       handle, key_id, data, destroy);
411 }
412 
413 /**
414  * tp_handle_get_qdata: (skip)
415  * @repo: A handle repository implementation
416  * @handle: A handle to get data from
417  * @key_id: Key id of data to fetch
418  *
419  * <!--Returns: says it all-->
420  *
421  * Returns: the data associated with a given key on a given handle; %NULL
422  * if there is no associated data.
423  * Deprecated: Since 0.19.9. It is not recommended to use this function
424  *  because the associated data won't be freed until the connection disconnects.
425  */
426 gpointer
tp_handle_get_qdata(TpHandleRepoIface * repo,TpHandle handle,GQuark key_id)427 tp_handle_get_qdata (TpHandleRepoIface *repo, TpHandle handle,
428                      GQuark key_id)
429 {
430   return TP_HANDLE_REPO_IFACE_GET_CLASS (repo)->get_qdata (repo,
431       handle, key_id);
432 }
433 
434 static void
default_ensure_handle_async(TpHandleRepoIface * self,TpBaseConnection * connection,const gchar * id,gpointer context,GAsyncReadyCallback callback,gpointer user_data)435 default_ensure_handle_async (TpHandleRepoIface *self,
436     TpBaseConnection *connection,
437     const gchar *id,
438     gpointer context,
439     GAsyncReadyCallback callback,
440     gpointer user_data)
441 {
442   GSimpleAsyncResult *result;
443   TpHandle handle;
444   GError *error = NULL;
445 
446   result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
447       default_ensure_handle_async);
448 
449   handle = tp_handle_ensure (self, id, context, &error);
450   if (handle == 0)
451     {
452       g_simple_async_result_take_error (result, error);
453     }
454   else
455     {
456       g_simple_async_result_set_op_res_gpointer (result,
457           GUINT_TO_POINTER (handle), NULL);
458     }
459 
460   g_simple_async_result_complete_in_idle (result);
461 
462   g_object_unref (result);
463 }
464 
465 static TpHandle
default_ensure_handle_finish(TpHandleRepoIface * self,GAsyncResult * result,GError ** error)466 default_ensure_handle_finish (TpHandleRepoIface *self,
467     GAsyncResult *result,
468     GError **error)
469 {
470   GSimpleAsyncResult *simple = (GSimpleAsyncResult *) result;
471 
472   g_return_val_if_fail (g_simple_async_result_is_valid (result,
473       G_OBJECT (self), NULL), 0);
474 
475   if (g_simple_async_result_propagate_error (simple, error))
476     return 0;
477 
478   return GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (simple));
479 }
480 
481 static void
tp_handle_repo_iface_default_init(TpHandleRepoIfaceInterface * iface)482 tp_handle_repo_iface_default_init (TpHandleRepoIfaceInterface *iface)
483 {
484   GParamSpec *param_spec;
485 
486   iface->ensure_handle_async = default_ensure_handle_async;
487   iface->ensure_handle_finish = default_ensure_handle_finish;
488 
489   param_spec = g_param_spec_uint ("handle-type", "Handle type",
490       "The TpHandleType held in this handle repository.",
491       0, G_MAXUINT32, 0,
492       G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
493   g_object_interface_install_property (iface, param_spec);
494 }
495