telepathy: add contact search channel
[siplcs.git] / src / telepathy / telepathy-search.c
blob4ecce2c720152c9b60df2f4f03abb651137ca58b
1 /**
2 * @file telepathy-search.c
4 * pidgin-sipe
6 * Copyright (C) 2012 SIPE Project <http://sipe.sourceforge.net/>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <glib-object.h>
24 #include <telepathy-glib/svc-channel.h>
25 #include <telepathy-glib/telepathy-glib.h>
27 #include "sipe-backend.h"
28 #include "sipe-common.h"
29 #include "sipe-core.h"
31 #include "telepathy-private.h"
33 G_BEGIN_DECLS
35 * Search Manager class - data structures
37 typedef struct _SipeSearchManagerClass {
38 GObjectClass parent_class;
39 } SipeSearchManagerClass;
41 typedef struct _SipeSearchManager {
42 GObject parent;
44 GObject *connection;
46 GHashTable *channels;
47 } SipeSearchManager;
50 * Search Manager class - type macros
52 /* telepathy-private.h: #define SIPE_TYPE_SEARCH_MANAGER ... */
53 #define SIPE_SEARCH_MANAGER(obj) \
54 (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_SEARCH_MANAGER, \
55 SipeSearchManager))
58 * Search Channel class - data structures
60 typedef struct _SipeSearchChannelClass {
61 TpBaseChannelClass parent_class;
62 } SipeSearchChannelClass;
64 typedef struct _SipeSearchChannel {
65 TpBaseChannel parent;
67 GObject *connection;
68 } SipeSearchChannel;
71 * Search Channel class - type macros
73 static GType sipe_search_channel_get_type(void) G_GNUC_CONST;
74 #define SIPE_TYPE_SEARCH_CHANNEL \
75 (sipe_search_channel_get_type())
76 #define SIPE_SEARCH_CHANNEL(obj) \
77 (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_SEARCH_CHANNEL, \
78 SipeSearchChannel))
79 G_END_DECLS
82 * Search Manager class - type definition
84 static void channel_manager_iface_init(gpointer, gpointer);
85 G_DEFINE_TYPE_WITH_CODE(SipeSearchManager,
86 sipe_search_manager,
87 G_TYPE_OBJECT,
88 G_IMPLEMENT_INTERFACE(TP_TYPE_CHANNEL_MANAGER,
89 channel_manager_iface_init);
93 * Search Manager class - type definition
95 static void contact_search_iface_init (gpointer, gpointer);
96 G_DEFINE_TYPE_WITH_CODE(SipeSearchChannel,
97 sipe_search_channel,
98 TP_TYPE_BASE_CHANNEL,
99 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CHANNEL_TYPE_CONTACT_SEARCH,
100 contact_search_iface_init);
104 * Search Manager class - instance methods
106 static void sipe_search_manager_constructed(GObject *object)
108 SipeSearchManager *self = SIPE_SEARCH_MANAGER(object);
109 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_search_manager_parent_class)->constructed;
111 if (chain_up)
112 chain_up(object);
114 self->channels = g_hash_table_new(g_direct_hash, g_direct_equal);
117 static void sipe_search_manager_dispose(GObject *object)
119 SipeSearchManager *self = SIPE_SEARCH_MANAGER(object);
120 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_search_manager_parent_class)->constructed;
122 tp_clear_pointer(&self->channels, g_hash_table_unref);
123 tp_clear_object(&self->connection);
125 if (chain_up)
126 chain_up(object);
130 * Search Manager class - type implementation
132 static void sipe_search_manager_class_init(SipeSearchManagerClass *klass)
134 GObjectClass *object_class = G_OBJECT_CLASS(klass);
136 SIPE_DEBUG_INFO_NOFORMAT("SipeSearchManager::class_init");
138 object_class->constructed = sipe_search_manager_constructed;
139 object_class->dispose = sipe_search_manager_dispose;
142 static void sipe_search_manager_init(SIPE_UNUSED_PARAMETER SipeSearchManager *self)
144 SIPE_DEBUG_INFO_NOFORMAT("SipeSearchManager::init");
148 * Search Manager class - interface implementation
150 * Channel Manager
152 static void foreach_channel(TpChannelManager *manager,
153 TpExportableChannelFunc func,
154 gpointer user_data)
156 SipeSearchManager *self = SIPE_SEARCH_MANAGER(manager);
157 GHashTableIter iter;
158 gpointer chan;
160 SIPE_DEBUG_INFO_NOFORMAT("SipeSearchManager::foreach_channel");
162 g_hash_table_iter_init(&iter, self->channels);
163 while (g_hash_table_iter_next(&iter, &chan, NULL))
164 func(chan, user_data);
167 static void type_foreach_channel_class(GType type,
168 TpChannelManagerTypeChannelClassFunc func,
169 gpointer user_data)
171 static const gchar *const no_props[] = {
172 NULL
174 GHashTable *table = g_hash_table_new_full(g_str_hash, g_str_equal,
175 NULL,
176 (GDestroyNotify) tp_g_value_slice_free);
178 SIPE_DEBUG_INFO_NOFORMAT("SipeSearchManager::type_foreach_channel_class");
180 g_hash_table_insert(table,
181 TP_IFACE_CHANNEL ".ChannelType",
182 tp_g_value_slice_new_string(TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH));
183 func(type, table, no_props, user_data);
184 g_hash_table_unref(table);
187 static void search_channel_closed_cb(SipeSearchChannel *channel,
188 SipeSearchManager *self)
190 tp_channel_manager_emit_channel_closed_for_object(self,
191 (TpExportableChannel *) channel);
192 g_hash_table_remove(self->channels, channel);
195 static GObject *search_channel_new(GObject *connection);
196 static gboolean create_channel(TpChannelManager *manager,
197 SIPE_UNUSED_PARAMETER gpointer request_token,
198 GHashTable *request_properties)
200 SipeSearchManager *self = SIPE_SEARCH_MANAGER(manager);
201 GObject *channel;
203 SIPE_DEBUG_INFO_NOFORMAT("SipeSearchManager::create_channel");
205 if (tp_strdiff(tp_asv_get_string(request_properties,
206 TP_IFACE_CHANNEL ".ChannelType"),
207 TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH))
208 return(FALSE);
211 channel = search_channel_new(self->connection);
212 g_hash_table_insert(self->channels, channel, NULL);
213 g_signal_connect(channel,
214 "closed",
215 (GCallback) search_channel_closed_cb,
216 self);
218 return(TRUE);
221 static void channel_manager_iface_init(gpointer g_iface,
222 SIPE_UNUSED_PARAMETER gpointer iface_data)
224 TpChannelManagerIface *iface = g_iface;
226 iface->foreach_channel = foreach_channel;
227 iface->type_foreach_channel_class = type_foreach_channel_class;
228 iface->create_channel = create_channel;
229 iface->request_channel = create_channel;
230 /* Ensuring these channels doesn't really make much sense. */
231 iface->ensure_channel = NULL;
234 /* create new search manager object */
235 GObject *sipe_telepathy_search_new(TpBaseConnection *connection)
237 SipeSearchManager *self = g_object_new(SIPE_TYPE_SEARCH_MANAGER, NULL);
238 self->connection = g_object_ref(connection);
239 return(G_OBJECT(self));
243 * Search Channel class - instance methods
245 enum {
246 CHANNEL_PROP_SEARCH_KEYS = 1,
247 CHANNEL_LAST_PROP
250 static void get_property(GObject *object,
251 guint property_id,
252 GValue *value,
253 GParamSpec *pspec)
255 switch (property_id)
257 case CHANNEL_PROP_SEARCH_KEYS: {
258 /* vCard/Telepathy search field names */
259 static const gchar const *search_keys[] = {
260 "x-n-given", /* First */
261 "x-n-family", /* Last */
262 "email", /* E-Mail */
263 "x-org-name", /* Company? */
264 "x-adr-country", /* Country */
265 NULL
267 g_value_set_boxed(value, search_keys);
269 break;
270 default:
271 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
272 break;
276 static void fill_immutable_properties(TpBaseChannel *channel,
277 GHashTable *properties)
279 TP_BASE_CHANNEL_CLASS(sipe_search_channel_parent_class)->fill_immutable_properties(channel,
280 properties);
281 tp_dbus_properties_mixin_fill_properties_hash(G_OBJECT(channel),
282 properties,
283 TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, "AvailableSearchKeys",
284 NULL);
287 static GPtrArray *get_interfaces(TpBaseChannel *self)
289 GPtrArray *interfaces = TP_BASE_CHANNEL_CLASS(sipe_search_channel_parent_class)->get_interfaces(self);
290 return(interfaces);
293 static void sipe_search_channel_constructed(GObject *object)
295 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_search_channel_parent_class)->constructed;
297 if (chain_up)
298 chain_up(object);
301 static void sipe_search_channel_finalize(GObject *object)
303 SIPE_DEBUG_INFO_NOFORMAT("SipeSearchChannel::finalize");
305 G_OBJECT_CLASS(sipe_search_channel_parent_class)->finalize(object);
309 * Search Channel class - type implementation
311 static void sipe_search_channel_class_init(SipeSearchChannelClass *klass)
313 static TpDBusPropertiesMixinPropImpl props[] = {
315 .name = "SearchKeys",
316 .getter_data = "search-keys",
317 .setter_data = NULL
319 { NULL }
321 GObjectClass *object_class = G_OBJECT_CLASS(klass);
322 TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS(klass);
323 GParamSpec *ps;
325 SIPE_DEBUG_INFO_NOFORMAT("SipeSearchChannel::class_init");
327 object_class->constructed = sipe_search_channel_constructed;
328 object_class->finalize = sipe_search_channel_finalize;
329 object_class->get_property = get_property;
331 base_class->channel_type = TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH;
332 base_class->target_handle_type = TP_HANDLE_TYPE_NONE;
333 base_class->fill_immutable_properties = fill_immutable_properties;
334 base_class->interfaces = NULL;
335 base_class->get_interfaces = get_interfaces;
336 base_class->close = tp_base_channel_destroyed;
338 ps = g_param_spec_boxed("search-keys",
339 "Search keys",
340 "The set of search keys supported by this channel",
341 G_TYPE_STRV,
342 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
343 g_object_class_install_property(object_class,
344 CHANNEL_PROP_SEARCH_KEYS,
345 ps);
347 tp_dbus_properties_mixin_implement_interface(object_class,
348 TP_IFACE_QUARK_CHANNEL_TYPE_CONTACT_SEARCH,
349 tp_dbus_properties_mixin_getter_gobject_properties,
350 NULL,
351 props);
354 static void sipe_search_channel_init(SIPE_UNUSED_PARAMETER SipeSearchChannel *self)
356 SIPE_DEBUG_INFO_NOFORMAT("SipeSearchChannel::init");
360 * Search Channel class - interface implementation
362 * Contact search
364 static void search_channel_state(SipeSearchChannel *self,
365 gboolean completed)
367 GHashTable *details = g_hash_table_new(g_str_hash, g_str_equal);
368 tp_svc_channel_type_contact_search_emit_search_state_changed(self,
369 completed ?
370 TP_CHANNEL_CONTACT_SEARCH_STATE_COMPLETED :
371 TP_CHANNEL_CONTACT_SEARCH_STATE_IN_PROGRESS,
373 details);
374 g_hash_table_unref(details);
377 static void search_channel_search(TpSvcChannelTypeContactSearch *channel,
378 GHashTable *terms,
379 DBusGMethodInvocation *context)
381 SipeSearchChannel *self = SIPE_SEARCH_CHANNEL(channel);
382 struct sipe_backend_private *telepathy_private = sipe_telepathy_connection_private(self->connection);
384 SIPE_DEBUG_INFO_NOFORMAT("SipeSearchChannel::search");
386 /* @TODO: we need a parameter to pass "self" into the search */
387 sipe_core_buddy_search(telepathy_private->public,
388 g_hash_table_lookup(terms, "x-n-given"),
389 g_hash_table_lookup(terms, "x-n-family"),
390 g_hash_table_lookup(terms, "email"),
391 g_hash_table_lookup(terms, "x-org-name"),
392 g_hash_table_lookup(terms, "x-adr-country"));
394 search_channel_state(self, FALSE);
396 tp_svc_channel_type_contact_search_return_from_search(context);
399 static void contact_search_iface_init(gpointer g_iface,
400 SIPE_UNUSED_PARAMETER gpointer iface_data)
402 TpSvcChannelTypeContactSearchClass *klass = g_iface;
404 tp_svc_channel_type_contact_search_implement_search(klass, search_channel_search);
405 /* we don't support stopping a search */
408 /* create new search channel object */
409 static GObject *search_channel_new(GObject *connection)
411 /* property "connection" required by TpBaseChannel */
412 SipeSearchChannel *self = g_object_new(SIPE_TYPE_SEARCH_CHANNEL,
413 "connection", connection,
414 NULL);
415 self->connection = g_object_ref(connection);
417 tp_base_channel_register(TP_BASE_CHANNEL(self));
419 return(G_OBJECT(self));
423 * Backend adaptor functions
425 struct sipe_backend_search_results *sipe_backend_search_results_start(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public)
427 /* @TODO: we need a parameter to pass "self" into the search
428 return(self);
430 return(NULL);
433 void sipe_backend_search_results_add(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public,
434 SIPE_UNUSED_PARAMETER struct sipe_backend_search_results *results,
435 SIPE_UNUSED_PARAMETER const gchar *uri,
436 SIPE_UNUSED_PARAMETER const gchar *name,
437 SIPE_UNUSED_PARAMETER const gchar *company,
438 SIPE_UNUSED_PARAMETER const gchar *country,
439 SIPE_UNUSED_PARAMETER const gchar *email)
441 /* @TODO
442 * SipeSearchChannel *self = results;
443 * tp_svc_channel_type_contact_search_emit_search_result_received(self,
444 * results);
448 void sipe_backend_search_results_finalize(SIPE_UNUSED_PARAMETER struct sipe_core_public *sipe_public,
449 SIPE_UNUSED_PARAMETER struct sipe_backend_search_results *results,
450 SIPE_UNUSED_PARAMETER const gchar *description,
451 SIPE_UNUSED_PARAMETER gboolean more)
453 /* @TODO
454 * SipeSearchChannel *self = results;
455 * search_channel_state(self, FALSE);
461 Local Variables:
462 mode: c
463 c-file-style: "bsd"
464 indent-tabs-mode: t
465 tab-width: 8
466 End: