2 * @file telepathy-search.c
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"
35 * Search Manager class - data structures
37 typedef struct _SipeSearchManagerClass
{
38 GObjectClass parent_class
;
39 } SipeSearchManagerClass
;
41 typedef struct _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, \
58 * Search Channel class - data structures
60 typedef struct _SipeSearchChannelClass
{
61 TpBaseChannelClass parent_class
;
62 } SipeSearchChannelClass
;
64 typedef struct _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, \
82 * Search Manager class - type definition
84 static void channel_manager_iface_init(gpointer
, gpointer
);
85 G_DEFINE_TYPE_WITH_CODE(SipeSearchManager
,
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
,
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
;
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
);
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
152 static void foreach_channel(TpChannelManager
*manager
,
153 TpExportableChannelFunc func
,
156 SipeSearchManager
*self
= SIPE_SEARCH_MANAGER(manager
);
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
,
171 static const gchar
*const no_props
[] = {
174 GHashTable
*table
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
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
);
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
))
211 channel
= search_channel_new(self
->connection
);
212 g_hash_table_insert(self
->channels
, channel
, NULL
);
213 g_signal_connect(channel
,
215 (GCallback
) search_channel_closed_cb
,
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
246 CHANNEL_PROP_SEARCH_KEYS
= 1,
250 static void get_property(GObject
*object
,
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 */
267 g_value_set_boxed(value
, search_keys
);
271 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, property_id
, pspec
);
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
,
281 tp_dbus_properties_mixin_fill_properties_hash(G_OBJECT(channel
),
283 TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH
, "AvailableSearchKeys",
287 static GPtrArray
*get_interfaces(TpBaseChannel
*self
)
289 GPtrArray
*interfaces
= TP_BASE_CHANNEL_CLASS(sipe_search_channel_parent_class
)->get_interfaces(self
);
293 static void sipe_search_channel_constructed(GObject
*object
)
295 void (*chain_up
)(GObject
*) = G_OBJECT_CLASS(sipe_search_channel_parent_class
)->constructed
;
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",
321 GObjectClass
*object_class
= G_OBJECT_CLASS(klass
);
322 TpBaseChannelClass
*base_class
= TP_BASE_CHANNEL_CLASS(klass
);
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",
340 "The set of search keys supported by this channel",
342 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
343 g_object_class_install_property(object_class
,
344 CHANNEL_PROP_SEARCH_KEYS
,
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
,
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
364 static void search_channel_state(SipeSearchChannel
*self
,
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
,
370 TP_CHANNEL_CONTACT_SEARCH_STATE_COMPLETED
:
371 TP_CHANNEL_CONTACT_SEARCH_STATE_IN_PROGRESS
,
374 g_hash_table_unref(details
);
377 static void search_channel_search(TpSvcChannelTypeContactSearch
*channel
,
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
,
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
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
)
442 * SipeSearchChannel *self = results;
443 * tp_svc_channel_type_contact_search_emit_search_result_received(self,
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
)
454 * SipeSearchChannel *self = results;
455 * search_channel_state(self, FALSE);