2 Unix SMB/CIFS implementation.
3 Main metadata server / Spotlight routines
5 Copyright (C) Ralph Boehme 2012-2014
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "sparql_parser.h"
25 #include "sparql_mapping.h"
27 #define YYMALLOC SMB_MALLOC
28 #define YYREALLOC SMB_REALLOC
30 struct yy_buffer_state
;
31 typedef
struct yy_buffer_state
*YY_BUFFER_STATE
;
32 extern
int yylex (void);
33 extern
void yyerror (char const *);
34 extern
void *yyterminate
(void);
35 extern YY_BUFFER_STATE yy_scan_string
( const char *str
);
36 extern
void yy_delete_buffer
( YY_BUFFER_STATE buffer
);
38 /* forward declarations */
39 static const char *map_expr
(const char *attr
, char op
, const char *val
);
40 static const char *map_daterange
(const char *dateattr
,
41 time_t date1
, time_t date2
);
42 static time_t isodate2unix
(const char *s
);
44 /* global vars, eg needed by the lexer */
45 struct sparql_parser_state
{
50 } *global_sparql_parser_state
;
56 #define SPRAW_TIME_OFFSET 978307200
57 extern
int yywrap
(void);
58 extern
bool map_spotlight_to_sparql_query
(struct sl_query
*slq
);
71 %type
<sval
> match expr line function
78 %token OBRACE CBRACE EQUAL UNEQUAL GT LT COMMA QUOTE
90 global_sparql_parser_state
->result
= $1;
97 * We can't properly handle these in expressions, fortunately this
98 * is probably only ever used by OS X as sole element in an
99 * expression ie "False" (when Finder window selected our share
100 * but no search string entered yet). Packet traces showed that OS
101 * X Spotlight server then returns a failure (ie -1) which is what
102 * we do here too by calling YYABORT.
107 * We have "match OR match" and "expr OR expr", because the former is
108 * supposed to catch and coalesque expressions of the form
110 * MDSattribute1="hello"||MDSattribute2="hello"
112 * into a single SPARQL expression for the case where both
113 * MDSattribute1 and MDSattribute2 map to the same SPARQL attibute,
114 * which is eg the case for "*" and "kMDItemTextContent" which both
115 * map to SPARQL "fts:match".
119 if
(strcmp
($1, $3) != 0) {
120 $$
= talloc_asprintf
(talloc_tos
(), "{ %s } UNION { %s }", $1, $3);
122 $$
= talloc_asprintf
(talloc_tos
(), "%s", $1);
131 | OBRACE expr CBRACE
{
132 $$
= talloc_asprintf
(talloc_tos
(), "%s", $2);
135 $$
= talloc_asprintf
(talloc_tos
(), "%s . %s", $1, $3);
138 if
(strcmp
($1, $3) != 0) {
139 $$
= talloc_asprintf
(talloc_tos
(), "{ %s } UNION { %s }", $1, $3);
141 $$
= talloc_asprintf
(talloc_tos
(), "%s", $1);
147 WORD EQUAL QUOTE WORD QUOTE
{
148 $$
= map_expr
($1, '=', $4);
149 if
($$
== NULL
) YYABORT;
151 | WORD UNEQUAL QUOTE WORD QUOTE
{
152 $$
= map_expr
($1, '!', $4);
153 if
($$
== NULL
) YYABORT;
155 | WORD LT QUOTE WORD QUOTE
{
156 $$
= map_expr
($1, '<', $4);
157 if
($$
== NULL
) YYABORT;
159 | WORD GT QUOTE WORD QUOTE
{
160 $$
= map_expr
($1, '>', $4);
161 if
($$
== NULL
) YYABORT;
163 | WORD EQUAL QUOTE WORD QUOTE WORD
{
164 $$
= map_expr
($1, '=', $4);
165 if
($$
== NULL
) YYABORT;
167 | WORD UNEQUAL QUOTE WORD QUOTE WORD
{
168 $$
= map_expr
($1, '!', $4);
169 if
($$
== NULL
) YYABORT;
171 | WORD LT QUOTE WORD QUOTE WORD
{
172 $$
= map_expr
($1, '<', $4);
173 if
($$
== NULL
) YYABORT;
175 | WORD GT QUOTE WORD QUOTE WORD
{
176 $$
= map_expr
($1, '>', $4);
177 if
($$
== NULL
) YYABORT;
182 FUNC_INRANGE OBRACE WORD COMMA date COMMA date CBRACE
{
183 $$
= map_daterange
($3, $5, $7);
184 if
($$
== NULL
) YYABORT;
189 DATE_ISO OBRACE WORD CBRACE
{$$
= isodate2unix
($3);}
190 | WORD
{$$
= atoi
($1) + SPRAW_TIME_OFFSET
;}
195 static time_t isodate2unix
(const char *s
)
200 p
= strptime
(s
, "%Y-%m-%dT%H:%M:%SZ", &tm
);
207 static const char *map_daterange
(const char *dateattr
,
208 time_t date1
, time_t date2
)
210 struct sparql_parser_state
*s
= global_sparql_parser_state
;
213 const struct sl_attr_map
*p
;
215 char buf1
[64], buf2
[64];
221 tmp
= localtime
(&date1
);
225 result
= strftime
(buf1
, sizeof
(buf1
), "%Y-%m-%dT%H:%M:%SZ", tmp
);
230 tmp
= localtime
(&date2
);
234 result
= strftime
(buf2
, sizeof
(buf2
), "%Y-%m-%dT%H:%M:%SZ", tmp
);
239 p
= sl_attr_map_by_spotlight
(dateattr
);
244 sparql
= talloc_asprintf
(talloc_tos
(),
245 "?obj %s ?%c FILTER (?%c > '%s' && ?%c < '%s')",
252 if
(sparql
== NULL
) {
260 static char *map_type_search
(const char *attr
, char op
, const char *val
)
263 const char *sparqlAttr
;
264 const struct sl_type_map
*p
;
266 p
= sl_type_map_by_spotlight
(val
);
273 sparqlAttr
= "rdf:type";
276 sparqlAttr
= "nie:mimeType";
282 result
= talloc_asprintf
(talloc_tos
(), "?obj %s '%s'",
285 if
(result
== NULL
) {
292 static const char *map_expr
(const char *attr
, char op
, const char *val
)
294 struct sparql_parser_state
*s
= global_sparql_parser_state
;
297 const struct sl_attr_map
*p
;
308 p
= sl_attr_map_by_spotlight
(attr
);
313 if
((p
->type
!= ssmt_type
) && (p
->sparql_attr
== NULL
)) {
314 yyerror("unsupported Spotlight attribute");
320 sparql
= talloc_asprintf
(talloc_tos
(), "?obj %s '%s'",
321 p
->sparql_attr
, val
);
322 if
(sparql
== NULL
) {
328 sparql
= talloc_asprintf
(talloc_tos
(),
329 "?obj %s ?%c FILTER(?%c %c%c '%s')",
334 /* append '=' to '!' */
335 op
== '!' ?
'=' : ' ',
337 if
(sparql
== NULL
) {
344 q
= talloc_strdup
(talloc_tos
(), "");
355 q
= talloc_strndup_append
(q
, start
, val
- start
);
360 q
= talloc_strdup_append
(q
, ".*");
368 q
= talloc_strndup_append
(q
, start
, val
- start
);
373 sparql
= talloc_asprintf
(talloc_tos
(),
375 "FILTER(regex(?%c, '^%s$', 'i'))",
381 if
(sparql
== NULL
) {
388 sparql
= talloc_asprintf
(talloc_tos
(), "?obj %s '%s'",
389 p
->sparql_attr
, val
);
390 if
(sparql
== NULL
) {
396 t
= atoi
(val
) + SPRAW_TIME_OFFSET
;
401 result
= strftime
(buf1
, sizeof
(buf1
),
402 "%Y-%m-%dT%H:%M:%SZ", tmp
);
406 sparql
= talloc_asprintf
(talloc_tos
(),
407 "?obj %s ?%c FILTER(?%c %c '%s')",
413 if
(sparql
== NULL
) {
420 sparql
= map_type_search
(attr
, op
, val
);
421 if
(sparql
== NULL
) {
433 void yyerror(const char *str
)
435 DEBUG
(1, ("yyerror: %s\n", str
));
444 * Map a Spotlight RAW query string to a SPARQL query string
446 bool map_spotlight_to_sparql_query
(struct sl_query
*slq
)
448 struct sparql_parser_state s
= {
449 .frame
= talloc_stackframe
(),
454 s.s
= yy_scan_string
(slq
->query_string
);
456 TALLOC_FREE
(s.frame
);
459 global_sparql_parser_state
= &s
;
461 global_sparql_parser_state
= NULL
;
462 yy_delete_buffer
(s.s
);
465 TALLOC_FREE
(s.frame
);
469 slq
->sparql_query
= talloc_asprintf
(slq
,
470 "SELECT ?url WHERE { %s . ?obj nie:url ?url . "
471 "FILTER(tracker:uri-is-descendant('file://%s/', ?url)) }",
472 s.result
, slq
->path_scope
);
473 TALLOC_FREE
(s.frame
);
474 if
(slq
->sparql_query
== NULL
) {