4 * Copyright (C) 2005 Novell, Inc.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
29 #include <sys/types.h>
30 #include <sys/socket.h>
33 #include "beagle-finished-response.h"
34 #include "beagle-hits-added-response.h"
35 #include "beagle-hits-subtracted-response.h"
36 #include "beagle-marshal.h"
37 #include "beagle-query.h"
38 #include "beagle-query-part.h"
39 #include "beagle-query-part-human.h"
40 #include "beagle-query-part-or.h"
41 #include "beagle-query-part-property.h"
42 #include "beagle-search-term-response.h"
43 #include "beagle-private.h"
46 GSList
*parts
; /* of BeagleQueryPart */
47 GSList
*mime_types
; /* of string */
48 GSList
*hit_types
; /* of string */
49 GSList
*sources
; /* of string */
52 /* These are extracted from the BeagleSearchTermResponse */
53 GSList
*exact_text
; /* of string */
54 GSList
*stemmed_text
; /* of string */
56 BeagleQueryDomain domain
;
59 #define BEAGLE_QUERY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), BEAGLE_TYPE_QUERY, BeagleQueryPrivate))
68 static GObjectClass
*parent_class
= NULL
;
69 static guint signals
[LAST_SIGNAL
] = { 0 };
72 query_set_search_terms (BeagleQuery
*query
, BeagleSearchTermResponse
*response
)
74 BeagleQueryPrivate
*priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
76 priv
->exact_text
= _beagle_search_term_response_get_exact_text (response
);
77 priv
->stemmed_text
= _beagle_search_term_response_get_stemmed_text (response
);
81 beagle_query_to_xml (BeagleRequest
*request
, GError
**err
)
83 BeagleQueryPrivate
*priv
= BEAGLE_QUERY_GET_PRIVATE (request
);
84 GString
*data
= g_string_new (NULL
);
86 BeagleQueryPartOr
*or_part
;
88 gboolean first
= TRUE
;
90 _beagle_request_append_standard_header (data
, "Query");
92 g_string_append_len (data
, "<Parts>", 7);
94 if (priv
->mime_types
!= NULL
) {
95 or_part
= beagle_query_part_or_new ();
97 for (iter
= priv
->mime_types
; iter
!= NULL
; iter
= iter
->next
) {
98 BeagleQueryPartProperty
*prop_part
= beagle_query_part_property_new ();
100 beagle_query_part_property_set_property_type (prop_part
, BEAGLE_PROPERTY_TYPE_KEYWORD
);
101 beagle_query_part_property_set_key (prop_part
, "beagle:MimeType");
102 beagle_query_part_property_set_value (prop_part
, (const char *) iter
->data
);
104 beagle_query_part_or_add_subpart (or_part
, BEAGLE_QUERY_PART (prop_part
));
107 sub_data
= _beagle_query_part_to_xml (BEAGLE_QUERY_PART (or_part
));
108 g_string_append_len (data
, sub_data
->str
, sub_data
->len
);
109 g_string_free (sub_data
, TRUE
);
110 g_object_unref (or_part
);
113 if (priv
->hit_types
!= NULL
) {
114 or_part
= beagle_query_part_or_new ();
116 for (iter
= priv
->hit_types
; iter
!= NULL
; iter
= iter
->next
) {
117 BeagleQueryPartProperty
*prop_part
= beagle_query_part_property_new ();
119 beagle_query_part_property_set_property_type (prop_part
, BEAGLE_PROPERTY_TYPE_KEYWORD
);
120 beagle_query_part_property_set_key (prop_part
, "beagle:HitType");
121 beagle_query_part_property_set_value (prop_part
, (const char *) iter
->data
);
123 beagle_query_part_or_add_subpart (or_part
, BEAGLE_QUERY_PART (prop_part
));
126 sub_data
= _beagle_query_part_to_xml (BEAGLE_QUERY_PART (or_part
));
127 g_string_append_len (data
, sub_data
->str
, sub_data
->len
);
128 g_string_free (sub_data
, TRUE
);
129 g_object_unref (or_part
);
132 if (priv
->sources
!= NULL
) {
133 or_part
= beagle_query_part_or_new ();
135 for (iter
= priv
->sources
; iter
!= NULL
; iter
= iter
->next
) {
136 BeagleQueryPartProperty
*prop_part
= beagle_query_part_property_new ();
138 beagle_query_part_property_set_property_type (prop_part
, BEAGLE_PROPERTY_TYPE_KEYWORD
);
139 beagle_query_part_property_set_key (prop_part
, "beagle:Source");
140 beagle_query_part_property_set_value (prop_part
, (const char *) iter
->data
);
142 beagle_query_part_or_add_subpart (or_part
, BEAGLE_QUERY_PART (prop_part
));
145 sub_data
= _beagle_query_part_to_xml (BEAGLE_QUERY_PART (or_part
));
146 g_string_append_len (data
, sub_data
->str
, sub_data
->len
);
147 g_string_free (sub_data
, TRUE
);
148 g_object_unref (or_part
);
151 for (iter
= priv
->parts
; iter
!= NULL
; iter
= iter
->next
) {
152 BeagleQueryPart
*part
= (BeagleQueryPart
*) iter
->data
;
154 sub_data
= _beagle_query_part_to_xml (part
);
155 g_string_append_len (data
, sub_data
->str
, sub_data
->len
);
156 g_string_free (sub_data
, TRUE
);
159 g_string_append_len (data
, "</Parts>", 8);
161 g_string_append_len (data
, "<MimeTypes>", 11);
163 for (iter
= priv
->mime_types
; iter
!= NULL
; iter
= iter
->next
) {
164 const char *mime_type
= (const char *) iter
->data
;
166 g_string_append_printf (data
, "<MimeType>%s</MimeType>", mime_type
);
169 g_string_append_len (data
, "</MimeTypes>", 12);
171 g_string_append_len (data
, "<HitTypes>", 10);
173 for (iter
= priv
->hit_types
; iter
!= NULL
; iter
= iter
->next
) {
174 const char *hit_type
= (const char *) iter
->data
;
176 g_string_append_printf (data
, "<HitType>%s</HitType>", hit_type
);
179 g_string_append_len (data
, "</HitTypes>", 11);
181 g_string_append_len (data
, "<Sources>", 9);
183 for (iter
= priv
->sources
; iter
!= NULL
; iter
= iter
->next
) {
184 const char *source
= (const char *) iter
->data
;
186 g_string_append_printf (data
, "<Source>%s</Source>", source
);
189 g_string_append_len (data
, "</Sources>", 10);
191 g_string_append_len (data
, "<QueryDomain>", 13);
193 if (priv
->domain
& BEAGLE_QUERY_DOMAIN_LOCAL
) {
194 g_string_append_len (data
, "Local", 5);
198 if (priv
->domain
& BEAGLE_QUERY_DOMAIN_SYSTEM
) {
200 g_string_append_c (data
, ' ');
202 g_string_append_len (data
, "System", 6);
206 if (priv
->domain
& BEAGLE_QUERY_DOMAIN_NEIGHBORHOOD
) {
208 g_string_append_c (data
, ' ');
210 g_string_append_len (data
, "Neighborhood", 12);
214 if (priv
->domain
& BEAGLE_QUERY_DOMAIN_GLOBAL
) {
216 g_string_append_c (data
, ' ');
218 g_string_append_len (data
, "Global", 6);
221 g_string_append_len (data
, "</QueryDomain>", 14);
223 g_string_append_printf (data
, "<MaxHits>%d</MaxHits>", priv
->max_hits
);
225 _beagle_request_append_standard_footer (data
);
231 beagle_query_response (BeagleRequest
*request
, BeagleResponse
*response
)
233 if (BEAGLE_IS_SEARCH_TERM_RESPONSE (response
)) {
234 query_set_search_terms (BEAGLE_QUERY (request
),
235 BEAGLE_SEARCH_TERM_RESPONSE (response
));
236 } else if (BEAGLE_IS_HITS_ADDED_RESPONSE (response
))
237 g_signal_emit (request
, signals
[HITS_ADDED
], 0, response
);
238 else if (BEAGLE_IS_HITS_SUBTRACTED_RESPONSE (response
))
239 g_signal_emit (request
, signals
[HITS_SUBTRACTED
], 0, response
);
240 else if (BEAGLE_IS_FINISHED_RESPONSE (response
))
241 g_signal_emit (request
, signals
[FINISHED
], 0, response
);
246 G_DEFINE_TYPE (BeagleQuery
, beagle_query
, BEAGLE_TYPE_REQUEST
)
249 beagle_query_finalize (GObject
*obj
)
251 BeagleQueryPrivate
*priv
= BEAGLE_QUERY_GET_PRIVATE (obj
);
253 g_slist_foreach (priv
->parts
, (GFunc
) g_object_unref
, NULL
);
254 g_slist_free (priv
->parts
);
256 g_slist_foreach (priv
->mime_types
, (GFunc
) g_free
, NULL
);
257 g_slist_free (priv
->mime_types
);
259 g_slist_foreach (priv
->hit_types
, (GFunc
) g_free
, NULL
);
260 g_slist_free (priv
->hit_types
);
262 g_slist_foreach (priv
->sources
, (GFunc
) g_free
, NULL
);
263 g_slist_free (priv
->sources
);
265 g_slist_foreach (priv
->exact_text
, (GFunc
) g_free
, NULL
);
266 g_slist_free (priv
->exact_text
);
268 g_slist_foreach (priv
->stemmed_text
, (GFunc
) g_free
, NULL
);
269 g_slist_free (priv
->stemmed_text
);
272 if (G_OBJECT_CLASS (parent_class
)->finalize
)
273 G_OBJECT_CLASS (parent_class
)->finalize (obj
);
277 beagle_query_class_init (BeagleQueryClass
*klass
)
279 GObjectClass
*obj_class
= G_OBJECT_CLASS (klass
);
280 BeagleRequestClass
*request_class
= BEAGLE_REQUEST_CLASS (klass
);
282 parent_class
= g_type_class_peek_parent (klass
);
284 obj_class
->finalize
= beagle_query_finalize
;
285 request_class
->to_xml
= beagle_query_to_xml
;
287 request_class
->response
= beagle_query_response
;
289 signals
[HITS_ADDED
] =
290 g_signal_new ("hits_added",
291 G_TYPE_FROM_CLASS (klass
),
293 G_STRUCT_OFFSET (BeagleQueryClass
, hits_added
),
295 g_cclosure_marshal_VOID__OBJECT
,
297 BEAGLE_TYPE_HITS_ADDED_RESPONSE
);
299 signals
[HITS_SUBTRACTED
] =
300 g_signal_new ("hits_subtracted",
301 G_TYPE_FROM_CLASS (klass
),
303 G_STRUCT_OFFSET (BeagleQueryClass
, hits_subtracted
),
305 g_cclosure_marshal_VOID__OBJECT
,
307 BEAGLE_TYPE_HITS_SUBTRACTED_RESPONSE
);
310 g_signal_new ("finished",
311 G_TYPE_FROM_CLASS (klass
),
313 G_STRUCT_OFFSET (BeagleQueryClass
, finished
),
315 g_cclosure_marshal_VOID__OBJECT
,
317 BEAGLE_TYPE_FINISHED_RESPONSE
);
319 g_type_class_add_private (klass
, sizeof (BeagleQueryPrivate
));
321 _beagle_request_class_set_response_types (request_class
,
323 BEAGLE_TYPE_HITS_ADDED_RESPONSE
,
324 "HitsSubtractedResponse",
325 BEAGLE_TYPE_HITS_SUBTRACTED_RESPONSE
,
327 BEAGLE_TYPE_FINISHED_RESPONSE
,
328 "SearchTermResponse",
329 BEAGLE_TYPE_SEARCH_TERM_RESPONSE
,
334 beagle_query_init (BeagleQuery
*query
)
336 BeagleQueryPrivate
*priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
338 priv
->max_hits
= 100;
340 /* FIXME: This is a good default when on an airplane. */
341 priv
->domain
= BEAGLE_QUERY_DOMAIN_LOCAL
| BEAGLE_QUERY_DOMAIN_SYSTEM
;
347 * Creates a new #BeagleQuery.
349 * Return value: the newly created #BeagleQuery.
352 beagle_query_new (void)
354 BeagleQuery
*query
= g_object_new (BEAGLE_TYPE_QUERY
, 0);
360 * beagle_query_add_part:
361 * @query: a #BeagleQuery
362 * @part: a #BeagleQueryPart
364 * Adds a #BeagleQueryPart to the given #BeagleQuery.
367 beagle_query_add_part (BeagleQuery
*query
, BeagleQueryPart
*part
)
369 BeagleQueryPrivate
*priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
371 g_return_if_fail (BEAGLE_IS_QUERY (query
));
373 priv
->parts
= g_slist_append (priv
->parts
, part
);
377 * beagle_query_add_text:
378 * @query: a #BeagleQuery
381 * Adds a text part to the given #BeagleQuery.
384 beagle_query_add_text (BeagleQuery
*query
, const char *str
)
386 BeagleQueryPartHuman
*part
;
388 g_return_if_fail (BEAGLE_IS_QUERY (query
));
390 part
= beagle_query_part_human_new ();
391 beagle_query_part_human_set_string (part
, str
);
392 beagle_query_part_set_logic (BEAGLE_QUERY_PART (part
),
393 BEAGLE_QUERY_PART_LOGIC_REQUIRED
);
395 beagle_query_add_part (query
, BEAGLE_QUERY_PART (part
));
400 * beagle_query_add_mime_type:
401 * @query: a #BeagleQuery
402 * @mime_type: a mime type
404 * Adds an allowed mime type to the given #BeagleQuery.
407 beagle_query_add_mime_type (BeagleQuery
*query
,
408 const char *mime_type
)
410 BeagleQueryPrivate
*priv
;
412 g_return_if_fail (BEAGLE_IS_QUERY (query
));
413 g_return_if_fail (mime_type
!= NULL
);
415 priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
417 priv
->mime_types
= g_slist_prepend (priv
->mime_types
, g_strdup (mime_type
));
421 * beagle_query_add_hit_type:
422 * @query: a #BeagleQuery
423 * @hit_type: a hit type
425 * Adds an allowed hit type to the given #BeagleQuery.
428 beagle_query_add_hit_type (BeagleQuery
*query
,
429 const char *hit_type
)
431 BeagleQueryPrivate
*priv
;
433 g_return_if_fail (BEAGLE_IS_QUERY (query
));
434 g_return_if_fail (hit_type
!= NULL
);
436 priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
438 priv
->hit_types
= g_slist_prepend (priv
->hit_types
, g_strdup (hit_type
));
442 * beagle_query_add_source:
443 * @query: a #BeagleQuery
446 * Adds an allowed source to the given #BeagleQuery.
449 beagle_query_add_source (BeagleQuery
*query
,
452 BeagleQueryPrivate
*priv
;
454 g_return_if_fail (BEAGLE_IS_QUERY (query
));
455 g_return_if_fail (source
!= NULL
);
457 priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
459 priv
->sources
= g_slist_prepend (priv
->sources
, g_strdup (source
));
463 * beagle_query_set_domain:
464 * @query: a #BeagleQuery
465 * @domain: a #BeagleQueryDomain
467 * Sets the search domain for a given #BeagleQuery. This limits the scope of
468 * a search to certain backends.
471 beagle_query_set_domain (BeagleQuery
*query
,
472 BeagleQueryDomain domain
)
474 BeagleQueryPrivate
*priv
;
476 g_return_if_fail (BEAGLE_IS_QUERY (query
));
478 priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
480 priv
->domain
= domain
;
484 * beagle_query_add_domain:
485 * @query: a #BeagleQuery
486 * @domain: a #BeagleQueryDomain
488 * Adds a search domain to the list of domains to search.
491 beagle_query_add_domain (BeagleQuery
*query
,
492 BeagleQueryDomain domain
)
494 BeagleQueryPrivate
*priv
;
496 g_return_if_fail (BEAGLE_IS_QUERY (query
));
498 priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
500 priv
->domain
|= domain
;
504 * beagle_query_remove_domain:
505 * @query: a #BeagleQuery
506 * @domain: a #BeagleQueryDomain
508 * Removes a search domain.
511 beagle_query_remove_domain (BeagleQuery
*query
,
512 BeagleQueryDomain domain
)
514 BeagleQueryPrivate
*priv
;
516 g_return_if_fail (BEAGLE_IS_QUERY (query
));
518 priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
520 priv
->domain
&= ~domain
;
524 * beagle_query_set_max_hits
525 * @query: a #BeagleQuery
526 * @max_hits: Max number of hits
528 * Sets the max number of hits a given #BeagleQuery should return.
531 beagle_query_set_max_hits (BeagleQuery
*query
,
534 BeagleQueryPrivate
*priv
;
536 g_return_if_fail (BEAGLE_IS_QUERY (query
));
538 priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
540 priv
->max_hits
= max_hits
;
545 * beagle_query_get_max_hits
546 * @query: a #BeagleQuery
548 * Returns the max number of hits a given #BeagleQuery should return.
550 * Return value: Max number of hits
553 beagle_query_get_max_hits (BeagleQuery
*query
)
555 BeagleQueryPrivate
*priv
;
557 g_return_val_if_fail (BEAGLE_IS_QUERY (query
), 0);
559 priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
561 return priv
->max_hits
;
565 * beagle_query_get_exact_text
566 * @query: a #BeagleQuery
568 * Returns a list of strings which contain the exact text processed by the
569 * query. The list should not be modified or freed.
571 * Return value: A list of strings containing the exact text
574 beagle_query_get_exact_text (BeagleQuery
*query
)
576 BeagleQueryPrivate
*priv
;
578 g_return_val_if_fail (BEAGLE_IS_QUERY (query
), 0);
580 priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
582 return priv
->exact_text
;
586 * beagle_query_get_stemmed_text
587 * @query: a #BeagleQuery
589 * Returns a list of strings which contain the stemmed text processed by the
590 * query. The list should not be modified or freed.
592 * Return value: A list of strings containing the stemmed text
595 beagle_query_get_stemmed_text (BeagleQuery
*query
)
597 BeagleQueryPrivate
*priv
;
599 g_return_val_if_fail (BEAGLE_IS_QUERY (query
), 0);
601 priv
= BEAGLE_QUERY_GET_PRIVATE (query
);
603 return priv
->stemmed_text
;