1 /* |
|
2 * gabble-im-channel.c - Source for GabbleSearchChannel |
|
3 * Copyright (C) 2005 Collabora Ltd. |
|
4 * |
|
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 <dbus/dbus-glib.h> |
|
22 #include "loudmouth/loudmouth.h" |
|
23 #include <stdio.h> |
|
24 #include <string.h> |
|
25 #include <time.h> |
|
26 |
|
27 |
|
28 #define DEBUG_FLAG GABBLE_DEBUG_SEARCH |
|
29 |
|
30 #include "debug.h" |
|
31 #include "disco.h" |
|
32 #include "gabble-connection.h" |
|
33 #include "gabble-presence.h" |
|
34 #include "gabble-presence-cache.h" |
|
35 #include "handles.h" |
|
36 #include "roster.h" |
|
37 #include "telepathy-constants.h" |
|
38 #include "telepathy-errors.h" |
|
39 #include "telepathy-helpers.h" |
|
40 #include "telepathy-interfaces.h" |
|
41 #include "tp-channel-iface.h" |
|
42 #include "namespaces.h" |
|
43 |
|
44 #include "gabble-search-channel.h" |
|
45 #include "gabble-search-channel-glue.h" |
|
46 #include "search-mixin-signals-marshal.h" |
|
47 #include "search-mixin.h" |
|
48 |
|
49 #include "gabble_enums.h" |
|
50 |
|
51 #ifndef EMULATOR |
|
52 G_DEFINE_TYPE_WITH_CODE (GabbleSearchChannel, gabble_search_channel, G_TYPE_OBJECT, |
|
53 G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)); |
|
54 |
|
55 #endif |
|
56 |
|
57 /* signal enum */ |
|
58 enum |
|
59 { |
|
60 CLOSED, |
|
61 LAST_SIGNAL |
|
62 #ifdef EMULATOR |
|
63 = LAST_SIGNAL_SEARCH |
|
64 #endif |
|
65 |
|
66 }; |
|
67 |
|
68 #ifdef EMULATOR |
|
69 #include "libgabble_wsd_solution.h" |
|
70 |
|
71 GET_STATIC_ARRAY_FROM_TLS(signals,gabble_search,guint) |
|
72 #define signals (GET_WSD_VAR_NAME(signals,gabble_search, s)()) |
|
73 |
|
74 GET_STATIC_VAR_FROM_TLS(gabble_search_channel_parent_class,gabble_search,gpointer) |
|
75 #define gabble_search_channel_parent_class (*GET_WSD_VAR_NAME(gabble_search_channel_parent_class,gabble_search,s)()) |
|
76 |
|
77 GET_STATIC_VAR_FROM_TLS(g_define_type_id,gabble_search,GType) |
|
78 #define g_define_type_id (*GET_WSD_VAR_NAME(g_define_type_id,gabble_search,s)()) |
|
79 |
|
80 |
|
81 static void gabble_search_channel_init (GabbleSearchChannel *self); |
|
82 static void gabble_search_channel_class_init (GabbleSearchChannelClass *klass); |
|
83 static void gabble_search_channel_class_intern_init (gpointer klass) |
|
84 { |
|
85 gabble_search_channel_parent_class = g_type_class_peek_parent (klass); |
|
86 gabble_search_channel_class_init ((GabbleSearchChannelClass*) klass); |
|
87 } |
|
88 EXPORT_C GType gabble_search_channel_get_type (void) |
|
89 { |
|
90 if ((g_define_type_id == 0)) |
|
91 { static const GTypeInfo g_define_type_info = |
|
92 { sizeof (GabbleSearchChannelClass), (GBaseInitFunc) ((void *)0), (GBaseFinalizeFunc) ((void *)0), (GClassInitFunc) gabble_search_channel_class_intern_init, (GClassFinalizeFunc) ((void *)0), ((void *)0), sizeof (GabbleSearchChannel), 0, (GInstanceInitFunc) gabble_search_channel_init, ((void *)0) }; g_define_type_id = g_type_register_static ( ((GType) ((20) << (2))), g_intern_static_string ("GabbleSearchChannel"), &g_define_type_info, (GTypeFlags) 0); { { static const GInterfaceInfo g_implement_interface_info = { (GInterfaceInitFunc) ((void *)0) }; g_type_add_interface_static (g_define_type_id, tp_channel_iface_get_type(), &g_implement_interface_info); } ; } } return g_define_type_id; |
|
93 }; |
|
94 |
|
95 |
|
96 |
|
97 #else |
|
98 |
|
99 static guint signals[LAST_SIGNAL] = {0}; |
|
100 |
|
101 #endif |
|
102 |
|
103 /* properties */ |
|
104 enum |
|
105 { |
|
106 PROP_OBJECT_PATH = 1, |
|
107 PROP_CHANNEL_TYPE, |
|
108 PROP_HANDLE_TYPE, |
|
109 PROP_HANDLE, |
|
110 PROP_CONNECTION, |
|
111 LAST_PROPERTY |
|
112 }; |
|
113 |
|
114 /* private structure */ |
|
115 typedef struct _GabbleSearchChannelPrivate GabbleSearchChannelPrivate; |
|
116 |
|
117 struct _GabbleSearchChannelPrivate |
|
118 { |
|
119 GabbleConnection *conn; |
|
120 char *object_path; |
|
121 GabbleHandle handle; |
|
122 gboolean closed; |
|
123 gboolean dispose_has_run; |
|
124 }; |
|
125 |
|
126 #define GABBLE_SEARCH_CHANNEL_GET_PRIVATE(obj) \ |
|
127 ((GabbleSearchChannelPrivate *)obj->priv) |
|
128 |
|
129 static void |
|
130 gabble_search_channel_init (GabbleSearchChannel *self) |
|
131 { |
|
132 GabbleSearchChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, |
|
133 GABBLE_TYPE_SEARCH_CHANNEL, GabbleSearchChannelPrivate); |
|
134 |
|
135 self->priv = priv; |
|
136 } |
|
137 |
|
138 static GObject * |
|
139 gabble_search_channel_constructor (GType type, guint n_props, |
|
140 GObjectConstructParam *props) |
|
141 { |
|
142 GObject *obj; |
|
143 GabbleSearchChannelPrivate *priv; |
|
144 DBusGConnection *bus; |
|
145 |
|
146 g_message("in gabble_search_channel_constructor\n"); |
|
147 obj = G_OBJECT_CLASS (gabble_search_channel_parent_class)-> |
|
148 constructor (type, n_props, props); |
|
149 priv = GABBLE_SEARCH_CHANNEL_GET_PRIVATE (GABBLE_SEARCH_CHANNEL (obj)); |
|
150 |
|
151 bus = tp_get_bus (); |
|
152 dbus_g_connection_register_g_object (bus, priv->object_path, obj); |
|
153 |
|
154 |
|
155 gabble_search_mixin_init (obj, G_STRUCT_OFFSET (GabbleSearchChannel, search_mixin)); |
|
156 |
|
157 |
|
158 return obj; |
|
159 } |
|
160 |
|
161 static void |
|
162 gabble_search_channel_get_property (GObject *object, |
|
163 guint property_id, |
|
164 GValue *value, |
|
165 GParamSpec *pspec) |
|
166 { |
|
167 GabbleSearchChannel *chan = GABBLE_SEARCH_CHANNEL (object); |
|
168 GabbleSearchChannelPrivate *priv = GABBLE_SEARCH_CHANNEL_GET_PRIVATE (chan); |
|
169 |
|
170 switch (property_id) { |
|
171 case PROP_OBJECT_PATH: |
|
172 g_value_set_string (value, priv->object_path); |
|
173 break; |
|
174 case PROP_CHANNEL_TYPE: |
|
175 g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); |
|
176 break; |
|
177 case PROP_HANDLE_TYPE: |
|
178 g_value_set_uint (value, TP_HANDLE_TYPE_NONE); |
|
179 break; |
|
180 case PROP_HANDLE: |
|
181 g_value_set_uint (value, 0 ); |
|
182 break; |
|
183 case PROP_CONNECTION: |
|
184 g_value_set_object (value, priv->conn); |
|
185 break; |
|
186 default: |
|
187 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
|
188 break; |
|
189 } |
|
190 } |
|
191 |
|
192 static void |
|
193 gabble_search_channel_set_property (GObject *object, |
|
194 guint property_id, |
|
195 const GValue *value, |
|
196 GParamSpec *pspec) |
|
197 { |
|
198 GabbleSearchChannel *chan = GABBLE_SEARCH_CHANNEL (object); |
|
199 GabbleSearchChannelPrivate *priv = GABBLE_SEARCH_CHANNEL_GET_PRIVATE (chan); |
|
200 |
|
201 switch (property_id) { |
|
202 case PROP_OBJECT_PATH: |
|
203 g_free (priv->object_path); |
|
204 priv->object_path = g_value_dup_string (value); |
|
205 break; |
|
206 case PROP_HANDLE: |
|
207 priv->handle = g_value_get_uint (value); |
|
208 break; |
|
209 case PROP_CONNECTION: |
|
210 priv->conn = g_value_get_object (value); |
|
211 break; |
|
212 default: |
|
213 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
|
214 break; |
|
215 } |
|
216 } |
|
217 |
|
218 static void gabble_search_channel_dispose (GObject *object); |
|
219 static void gabble_search_channel_finalize (GObject *object); |
|
220 |
|
221 static void |
|
222 gabble_search_channel_class_init (GabbleSearchChannelClass *gabble_search_channel_class) |
|
223 { |
|
224 GObjectClass *object_class = G_OBJECT_CLASS (gabble_search_channel_class); |
|
225 GParamSpec *param_spec; |
|
226 g_message("in gabble_search_channel_class_init"); |
|
227 |
|
228 g_type_class_add_private (gabble_search_channel_class, sizeof (GabbleSearchChannelPrivate)); |
|
229 |
|
230 object_class->constructor = gabble_search_channel_constructor; |
|
231 |
|
232 object_class->get_property = gabble_search_channel_get_property; |
|
233 object_class->set_property = gabble_search_channel_set_property; |
|
234 |
|
235 object_class->dispose = gabble_search_channel_dispose; |
|
236 object_class->finalize = gabble_search_channel_finalize; |
|
237 |
|
238 g_object_class_override_property (object_class, PROP_OBJECT_PATH, "object-path"); |
|
239 g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, "channel-type"); |
|
240 g_object_class_override_property (object_class, PROP_HANDLE_TYPE, "handle-type"); |
|
241 g_object_class_override_property (object_class, PROP_HANDLE, "handle"); |
|
242 |
|
243 |
|
244 |
|
245 param_spec = g_param_spec_object ("connection", "GabbleConnection object", |
|
246 "Gabble connection object that owns this " |
|
247 "Search channel object.", |
|
248 GABBLE_TYPE_CONNECTION, |
|
249 G_PARAM_CONSTRUCT_ONLY | |
|
250 G_PARAM_READWRITE | |
|
251 G_PARAM_STATIC_NICK | |
|
252 G_PARAM_STATIC_BLURB); |
|
253 g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); |
|
254 |
|
255 signals[CLOSED] = |
|
256 g_signal_new ("closed", |
|
257 G_OBJECT_CLASS_TYPE (gabble_search_channel_class), |
|
258 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, |
|
259 0, |
|
260 NULL, NULL, |
|
261 g_cclosure_marshal_VOID__VOID, |
|
262 G_TYPE_NONE, 0); |
|
263 |
|
264 gabble_search_mixin_class_init (object_class, G_STRUCT_OFFSET (GabbleSearchChannelClass, mixin_class)); |
|
265 |
|
266 dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (gabble_search_channel_class), &dbus_glib_gabble_search_channel_object_info); |
|
267 } |
|
268 |
|
269 void |
|
270 gabble_search_channel_dispose (GObject *object) |
|
271 { |
|
272 GabbleSearchChannel *self = GABBLE_SEARCH_CHANNEL (object); |
|
273 GabbleSearchChannelPrivate *priv = GABBLE_SEARCH_CHANNEL_GET_PRIVATE (self); |
|
274 |
|
275 g_message("in gabble_search_channel_dispose\n"); |
|
276 if (priv->dispose_has_run) |
|
277 return; |
|
278 |
|
279 priv->dispose_has_run = TRUE; |
|
280 |
|
281 |
|
282 if (!priv->closed) |
|
283 g_signal_emit(self, signals[CLOSED], 0); |
|
284 |
|
285 if (G_OBJECT_CLASS (gabble_search_channel_parent_class)->dispose) |
|
286 G_OBJECT_CLASS (gabble_search_channel_parent_class)->dispose (object); |
|
287 } |
|
288 |
|
289 void |
|
290 gabble_search_channel_finalize (GObject *object) |
|
291 { |
|
292 GabbleSearchChannel *self = GABBLE_SEARCH_CHANNEL (object); |
|
293 GabbleSearchChannelPrivate *priv = GABBLE_SEARCH_CHANNEL_GET_PRIVATE (self); |
|
294 |
|
295 g_message("in gabble_search_channel_finalize\n"); |
|
296 /* free any data held directly by the object here */ |
|
297 if( priv->object_path ) |
|
298 { |
|
299 g_message("freeing priv->object_path in gabble_search_channel_finalize\n"); |
|
300 g_free (priv->object_path); |
|
301 priv->object_path = NULL; |
|
302 } |
|
303 |
|
304 //also free the data,if any, held by mixin obj |
|
305 //gabble_search_mixin_finalize(object); |
|
306 |
|
307 G_OBJECT_CLASS (gabble_search_channel_parent_class)->finalize (object); |
|
308 } |
|
309 |
|
310 |
|
311 |
|
312 /** |
|
313 * gabble_search_channel_close |
|
314 * |
|
315 * Implements D-Bus method Close |
|
316 * on interface org.freedesktop.Telepathy.Channel |
|
317 * |
|
318 * @error: Used to return a pointer to a GError detailing any error |
|
319 * that occurred, D-Bus will throw the error only if this |
|
320 * function returns FALSE. |
|
321 * |
|
322 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
323 */ |
|
324 gboolean |
|
325 gabble_search_channel_close (GabbleSearchChannel *self, |
|
326 GError **error) |
|
327 { |
|
328 GabbleSearchChannelPrivate *priv; |
|
329 |
|
330 g_assert (GABBLE_IS_SEARCH_CHANNEL (self)); |
|
331 |
|
332 gabble_debug (DEBUG_FLAG, "called on %p", self); |
|
333 |
|
334 g_message("gabble_search_channel_close"); |
|
335 priv = GABBLE_SEARCH_CHANNEL_GET_PRIVATE (self); |
|
336 |
|
337 if (priv->closed) |
|
338 { |
|
339 gabble_debug (DEBUG_FLAG, "channel already closed"); |
|
340 |
|
341 g_set_error (error, TELEPATHY_ERRORS, NotAvailable, |
|
342 "Channel already closed"); |
|
343 |
|
344 return FALSE; |
|
345 } |
|
346 |
|
347 |
|
348 priv->closed = TRUE; |
|
349 |
|
350 g_signal_emit (self, signals[CLOSED], 0); |
|
351 |
|
352 return TRUE; |
|
353 } |
|
354 |
|
355 |
|
356 /** |
|
357 * gabble_search_channel_get_channel_type |
|
358 * |
|
359 * Implements D-Bus method GetChannelType |
|
360 * on interface org.freedesktop.Telepathy.Channel |
|
361 * |
|
362 * @error: Used to return a pointer to a GError detailing any error |
|
363 * that occurred, D-Bus will throw the error only if this |
|
364 * function returns FALSE. |
|
365 * |
|
366 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
367 */ |
|
368 gboolean |
|
369 gabble_search_channel_get_channel_type (GabbleSearchChannel *self, |
|
370 gchar **ret, |
|
371 GError **error) |
|
372 { |
|
373 *ret = g_strdup (TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH); |
|
374 |
|
375 return TRUE; |
|
376 } |
|
377 |
|
378 |
|
379 /** |
|
380 * gabble_search_channel_get_interfaces |
|
381 * |
|
382 * Implements D-Bus method GetInterfaces |
|
383 * on interface org.freedesktop.Telepathy.Channel |
|
384 * |
|
385 * @error: Used to return a pointer to a GError detailing any error |
|
386 * that occurred, D-Bus will throw the error only if this |
|
387 * function returns FALSE. |
|
388 * |
|
389 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
390 */ |
|
391 gboolean |
|
392 gabble_search_channel_get_interfaces (GabbleSearchChannel *self, |
|
393 gchar ***ret, |
|
394 GError **error) |
|
395 { |
|
396 const char *interfaces[] = { NULL }; |
|
397 |
|
398 *ret = g_strdupv ((gchar **) interfaces); |
|
399 |
|
400 return TRUE; |
|
401 } |
|
402 |
|
403 |
|
404 /** |
|
405 * gabble_search_channel_search |
|
406 * |
|
407 * Implements D-Bus method Search |
|
408 * on interface org.freedesktop.Telepathy.Channel |
|
409 * |
|
410 * @error: Used to return a pointer to a GError detailing any error |
|
411 * that occurred, D-Bus will throw the error only if this |
|
412 * function returns FALSE. |
|
413 * |
|
414 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
415 */ |
|
416 gboolean |
|
417 gabble_search_channel_search ( GabbleSearchChannel *self, |
|
418 GHashTable *params, |
|
419 GError **error |
|
420 ) |
|
421 { |
|
422 GabbleSearchChannelPrivate *priv; |
|
423 |
|
424 g_message("In gabble_search_channel_search: serachchan is %u\n",self); |
|
425 |
|
426 g_assert (GABBLE_IS_SEARCH_CHANNEL (self)); |
|
427 priv = GABBLE_SEARCH_CHANNEL_GET_PRIVATE (self); |
|
428 |
|
429 return gabble_search_mixin_search (G_OBJECT (self), params, |
|
430 priv->conn, error); |
|
431 |
|
432 } |
|
433 |
|
434 /** |
|
435 * gabble_search_channel_get_search_state |
|
436 * |
|
437 * Implements D-Bus method GetSearchState |
|
438 * on interface org.freedesktop.Telepathy.Channel |
|
439 * |
|
440 * @error: Used to return a pointer to a GError detailing any error |
|
441 * that occurred, D-Bus will throw the error only if this |
|
442 * function returns FALSE. |
|
443 * |
|
444 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
445 */ |
|
446 gboolean |
|
447 gabble_search_channel_get_search_state ( GabbleSearchChannel *self, |
|
448 guint *ret, |
|
449 GError **error |
|
450 ) |
|
451 { |
|
452 g_message("In gabble_search_channel_get_search_state\n"); |
|
453 return gabble_search_mixin_get_search_state (G_OBJECT (self),ret, error); |
|
454 } |
|
455 |
|
456 |
|
457 /** |
|
458 * gabble_search_channel_get_handle |
|
459 * |
|
460 * Implements D-Bus method GetHandle |
|
461 * on interface org.freedesktop.Telepathy.Channel |
|
462 * |
|
463 * @error: Used to return a pointer to a GError detailing any error |
|
464 * that occurred, D-Bus will throw the error only if this |
|
465 * function returns FALSE. |
|
466 * |
|
467 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
468 */ |
|
469 gboolean |
|
470 gabble_search_channel_get_handle (GabbleSearchChannel *self, |
|
471 guint *ret, |
|
472 guint *ret1, |
|
473 GError **error) |
|
474 { |
|
475 GabbleSearchChannelPrivate *priv; |
|
476 |
|
477 g_assert (GABBLE_IS_SEARCH_CHANNEL (self)); |
|
478 |
|
479 priv = GABBLE_SEARCH_CHANNEL_GET_PRIVATE (self); |
|
480 |
|
481 *ret = TP_HANDLE_TYPE_NONE; |
|
482 //search channel doesnt correspond to any particular handle |
|
483 *ret1 = 0; |
|
484 |
|
485 return TRUE; |
|
486 } |
|
487 |
|
488 /** |
|
489 * TODO: this method may be modified in future to get the search key types |
|
490 * as dbus-glib binding tool doesnt support 'g' type signature |
|
491 * Also this method should be able to give value |
|
492 * for the options for list-single or list-multi type search keys if required |
|
493 * gabble_search_channel_get_search_keys |
|
494 * |
|
495 * Implements D-Bus method GetSearchKeys |
|
496 * on interface org.freedesktop.Telepathy.Channel |
|
497 * |
|
498 * @error: Used to return a pointer to a GError detailing any error |
|
499 * that occurred, D-Bus will throw the error only if this |
|
500 * function returns FALSE. |
|
501 * |
|
502 * Returns: TRUE if successful, FALSE if an error was thrown. |
|
503 */ |
|
504 gboolean |
|
505 gabble_search_channel_get_search_keys ( GabbleSearchChannel *self, |
|
506 gchar **ret_instruction, |
|
507 gchar ***ret_searchkeys, |
|
508 GError **error |
|
509 ) |
|
510 { |
|
511 GabbleSearchChannelPrivate *priv; |
|
512 |
|
513 g_message("In gabble_search_channel_get_search_keys: serachchan is %u\n",self); |
|
514 |
|
515 g_assert (GABBLE_IS_SEARCH_CHANNEL (self)); |
|
516 priv = GABBLE_SEARCH_CHANNEL_GET_PRIVATE (self); |
|
517 |
|
518 return gabble_search_mixin_get_search_keys (G_OBJECT (self),ret_instruction, |
|
519 ret_searchkeys, |
|
520 priv->conn, error); |
|
521 } |
|
522 |
|
523 |
|
524 /** |
|
525 * search_channel_iq_cb: |
|
526 * |
|
527 * Called by loudmouth when we get an incoming <iq>. This handler |
|
528 * is concerned only with search queries, and allows other handlers |
|
529 * if queries other than search are received. |
|
530 */ |
|
531 |
|
532 LmHandlerResult |
|
533 search_channel_iq_cb (LmMessageHandler *handler, |
|
534 LmConnection *lmconn, |
|
535 LmMessage *message, |
|
536 gpointer user_data) |
|
537 { |
|
538 GabbleSearchChannel *chan = GABBLE_SEARCH_CHANNEL (user_data); |
|
539 GabbleSearchChannelPrivate *priv = NULL; |
|
540 GabbleSearchMixin *mixin = NULL; |
|
541 |
|
542 LmMessageNode *iq_node, *query_node; |
|
543 LmMessageSubType sub_type; |
|
544 |
|
545 LmMessageNode *x_node, *x_item_node, *result_node; |
|
546 const char *x_node_type; |
|
547 const gchar **from = NULL; |
|
548 |
|
549 GHashTable *results = NULL; |
|
550 guint contact_handle = 0; |
|
551 |
|
552 |
|
553 g_message("in search_channel_iq_cb: user data - chan is : %u\n", chan); |
|
554 |
|
555 sub_type = lm_message_get_sub_type (message); |
|
556 |
|
557 if (sub_type != LM_MESSAGE_SUB_TYPE_RESULT) |
|
558 { |
|
559 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; |
|
560 } |
|
561 iq_node = lm_message_get_node (message); |
|
562 query_node = lm_message_node_get_child_with_namespace (iq_node, "query", |
|
563 NS_SEARCH); |
|
564 |
|
565 if (query_node == NULL || chan == NULL) |
|
566 return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; |
|
567 |
|
568 |
|
569 |
|
570 priv= GABBLE_SEARCH_CHANNEL_GET_PRIVATE (chan); |
|
571 mixin = GABBLE_SEARCH_MIXIN (chan); |
|
572 |
|
573 |
|
574 x_node = lm_message_node_get_child_with_namespace (query_node, "x", NS_X_DATA); |
|
575 |
|
576 if( x_node ) |
|
577 { |
|
578 //if service supports data forms |
|
579 result_node = x_node; |
|
580 x_node_type = lm_message_node_get_attribute (x_node, "type" ); |
|
581 if (0 != strcmp (x_node_type, "result")) |
|
582 { |
|
583 //this can be for search_keys_iq_cb |
|
584 //callback received as result of request to get search key fields |
|
585 return LM_HANDLER_RESULT_REMOVE_MESSAGE; |
|
586 } |
|
587 //if(type == NULL), do some error handling |
|
588 } |
|
589 |
|
590 else |
|
591 result_node = query_node; |
|
592 |
|
593 |
|
594 for (x_item_node = result_node->children; x_item_node; x_item_node = x_item_node->next) |
|
595 { |
|
596 LmMessageNode *item_node, *node; |
|
597 GHashTable *search_result = NULL; |
|
598 gboolean reported_field_has_type = FALSE; |
|
599 |
|
600 |
|
601 if(!search_result) |
|
602 search_result = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,NULL); |
|
603 |
|
604 //there should be only one reported field |
|
605 //Later "reported" should also be used to get the types of search result fields |
|
606 //'g' type currently not supported by dbus-glib-binding |
|
607 if (0 != strcmp (x_item_node->name, "item") ) |
|
608 continue; |
|
609 |
|
610 contact_handle = 0; |
|
611 |
|
612 //x_item_node is an item node |
|
613 //get the field nodes from each item node |
|
614 for (node = x_item_node->children; node; node = node->next) |
|
615 { |
|
616 const gchar *key, *value; |
|
617 LmMessageNode *value_node; |
|
618 GValue *val = g_new0(GValue, 1); |
|
619 LmMessageNode *reported_field_node; |
|
620 |
|
621 |
|
622 if (0 != strcmp (node->name, "field")) |
|
623 continue; |
|
624 |
|
625 //node is a field or reported node |
|
626 //get the name, type and value of each field |
|
627 key = lm_message_node_get_attribute(node, "var"); |
|
628 |
|
629 value_node = lm_message_node_get_child(node, "value"); |
|
630 |
|
631 value = lm_message_node_get_value(value_node); |
|
632 |
|
633 if(0 == strcmp (key, "jid")) |
|
634 { |
|
635 g_message("getting contact_handle\n"); |
|
636 contact_handle = gabble_handle_for_contact (priv->conn->handles, value, FALSE); |
|
637 } |
|
638 |
|
639 g_value_init (val, G_TYPE_STRING); |
|
640 //"val" should be a struct with members "var" and "type" |
|
641 g_value_set_string (val, g_strdup(value) ); |
|
642 g_hash_table_insert(search_result,g_strdup(key),val); |
|
643 |
|
644 } |
|
645 |
|
646 |
|
647 g_message("search results: %u",g_hash_table_size(search_result)); |
|
648 //emit the signal for search result received |
|
649 _gabble_search_mixin_emit_search_result_received(G_OBJECT (chan),contact_handle, search_result); |
|
650 |
|
651 g_hash_table_destroy(search_result); |
|
652 } |
|
653 |
|
654 |
|
655 //if no search results, service must return empty query element |
|
656 //so emit the signal for the same |
|
657 if(!contact_handle) |
|
658 { |
|
659 |
|
660 if(!results) |
|
661 results = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,NULL); |
|
662 |
|
663 _gabble_search_mixin_emit_search_result_received(G_OBJECT (chan),contact_handle, results); |
|
664 g_hash_table_destroy(results); |
|
665 |
|
666 } |
|
667 |
|
668 //search state should be completed |
|
669 g_message("b4 set search state changed \n"); |
|
670 _gabble_search_mixin_set_search_state(G_OBJECT (chan), TP_CHANNEL_CONTACT_SEARCH_STATE_AFTER); |
|
671 |
|
672 //search request completed now, emit the signal for search state changed |
|
673 g_message("b4 emiiting search state changed signal\n"); |
|
674 _gabble_search_mixin_emit_search_state_changed(G_OBJECT (chan),TP_CHANNEL_CONTACT_SEARCH_STATE_AFTER); |
|
675 |
|
676 return LM_HANDLER_RESULT_REMOVE_MESSAGE; |
|
677 } |
|
678 |
|
679 |
|
680 |
|