#include <time.h>
#include <gio/gio.h>
+ #include <tracker.h>
#include <atalk/talloc.h>
#include <atalk/logger.h>
slq_t *srp_slq;
/* local vars */
- static gchar *ssp_result;
+ static gchar *srp_result;
+ static gchar *srp_fts;
%}
%code provides {
#define SPRAW_TIME_OFFSET 978307200
- extern int map_spotlight_to_rdf_query(slq_t *slq, gchar **sparql_result);
+ extern int map_spotlight_to_rdf_query(slq_t *slq);
extern slq_t *srp_slq;
}
time_t tval;
}
-%expect 5
+%expect 4
%error-verbose
%type <sval> match expr line function
line:
expr {
- ssp_result = talloc_asprintf(srp_slq,
- "<rdfq:Condition>"
- " <rdfq:and>"
- " <rdfq:startsWith>"
- " <rdfq:Property name=\"File:Path\" />"
- " <rdf:String>%s</rdf:String>"
- " </rdfq:startsWith>"
- " %s"
- " </rdfq:and>"
- "</rdfq:Condition>",
+ srp_result = talloc_asprintf(srp_slq,
+ "<rdfq:Condition>\n"
+ " <rdfq:and>\n"
+ " <rdfq:startsWith>\n"
+ " <rdfq:Property name=\"File:Path\" />\n"
+ " <rdf:String>%s</rdf:String>\n"
+ " </rdfq:startsWith>\n"
+ " %s\n"
+ " </rdfq:and>\n"
+ "</rdfq:Condition>\n",
srp_slq->slq_vol->v_path, $1);
- $$ = ssp_result;
+ $$ = srp_result;
}
;
else
YYABORT;
}
-| match OR match {
- if (strcmp($1, $3) != 0)
- $$ = talloc_asprintf(srp_slq, "{ %s } UNION { %s }", $1, $3);
- else
- $$ = talloc_asprintf(srp_slq, "%s", $1);
-}
| match {$$ = $1; if ($$ == NULL) YYABORT;}
| function {$$ = $1;}
-| OBRACE expr CBRACE {$$ = talloc_asprintf(srp_slq, "%s", $2);}
-| expr AND expr {$$ = talloc_asprintf(srp_slq, "%s . %s", $1, $3);}
+| OBRACE expr CBRACE {$$ = talloc_asprintf(srp_slq, "%s\n", $2);}
+| expr AND expr {$$ = talloc_asprintf(srp_slq, "<rdfq:and>\n%s\n%s\n</rdfq:and>\n", $1, $3);}
| expr OR expr {
- if (strcmp($1, $3) != 0)
- $$ = talloc_asprintf(srp_slq, "{ %s } UNION { %s }", $1, $3);
- else
- $$ = talloc_asprintf(srp_slq, "%s", $1);
+ if (strcmp($1, "") == 0 || strcmp($3, "") == 0) {
+ /*
+ * The default Spotlight search term issued by the Finder (10.8) is:
+ * '* == "searchterm" || kMDItemTextContent == "searchterm"'
+ * As it isn't mappable to a single Tracker RDF query, we silently
+ * map ANY FTS query expression being part of an OR compound
+ * expression to a simple filename search.
+ * FTS queries are thus only possible by explicitly requesting
+ * file content FTS search in the Finder on the client (resulting
+ * in a 'kMDItemTextContent == "searchterm"' query).
+ */
+ if (strcmp($1, "") == 0)
+ $$ = talloc_asprintf(srp_slq, $3);
+ else
+ $$ = talloc_asprintf(srp_slq, $1);
+ talloc_free(srp_fts);
+ srp_fts = NULL;
+ } else {
+ $$ = talloc_asprintf(srp_slq, "<rdfq:or>\n%s\n%s\n</rdfq:or>\n", $1, $3);
+ }
}
;
return mktime(&tm);
}
-const char *map_daterange(const char *dateattr, time_t date1, time_t date2)
+static const char *map_daterange(const char *dateattr, time_t date1, time_t date2)
{
EC_INIT;
char *result = NULL;
for (p = spotlight_rdf_map; p->srm_spotlight_attr; p++) {
if (strcmp(dateattr, p->srm_spotlight_attr) == 0) {
- /* do something */
+ result = talloc_asprintf(srp_slq,
+ "<rdfq:and>\n"
+ " <rdfq:greaterThan>\n"
+ " <rdfq:Property name=\"%s\" />\n"
+ " <rdf:Date>%s</rdf:Date>\n"
+ " </rdfq:greaterThan>\n"
+ " <rdfq:lessThan>\n"
+ " <rdfq:Property name=\"%s\" />\n"
+ " <rdf:Date>%s</rdf:Date>\n"
+ " </rdfq:lessThan>\n"
+ "</rdfq:and>\n",
+ p->srm_rdf_attr, buf1,
+ p->srm_rdf_attr, buf2);
break;
}
}
return result;
}
-const char *map_expr(const char *attr, char op, const char *val)
+static char *map_type_search(const char *attr, char op, const char *val)
+{
+ char *result = NULL;
+
+ for (struct MDTypeMap *p = MDTypeMap; p->mdtm_value; p++) {
+ if (strcmp(p->mdtm_value, val) == 0) {
+ if (!p->mdtm_type)
+ return NULL;
+ if (val[0] == '9') {
+ srp_slq->slq_service = SERVICE_FOLDERS;
+ return "";
+ }
+ result = talloc_asprintf(srp_slq,
+ "<rdfq:%s>\n"
+ " <rdfq:Property name=\"File:Mime\" />\n"
+ " <rdf:String>%s</rdf:String>\n"
+ "</rdfq:%s>\n",
+ p->mdtm_rdfop,
+ p->mdtm_type,
+ p->mdtm_rdfop);
+ break;
+ }
+ }
+ return result;
+}
+
+static const char *map_expr(const char *attr, char op, const char *val)
{
EC_INIT;
char *result = NULL;
struct tm *tmp;
char buf1[64];
bstring q = NULL, search = NULL, replace = NULL;
+ char *rdfop;
for (p = spotlight_rdf_map; p->srm_spotlight_attr; p++) {
if (p->srm_rdf_attr && strcmp(p->srm_spotlight_attr, attr) == 0) {
switch (p->srm_type) {
- case srmt_bool:
- /* do something */
- break;
case srmt_num:
- /* do something */
+ q = bformat("^%s$", val);
+ search = bfromcstr("*");
+ replace = bfromcstr(".*");
+ bfindreplace(q, search, replace, 0);
+ result = talloc_asprintf(srp_slq,
+ "<rdfq:regex>\n"
+ " <rdfq:Property name=\"%s\" />\n"
+ " <rdf:String>%s</rdf:String>\n"
+ "</rdfq:regex>\n",
+ p->srm_rdf_attr,
+ bdata(q));
+ bdestroy(q);
break;
+
case srmt_str:
q = bformat("^%s$", val);
search = bfromcstr("*");
replace = bfromcstr(".*");
bfindreplace(q, search, replace, 0);
- /* do something */
+ result = talloc_asprintf(srp_slq,
+ "<rdfq:regex>\n"
+ " <rdfq:Property name=\"%s\" />\n"
+ " <rdf:String>%s</rdf:String>\n"
+ "</rdfq:regex>\n",
+ p->srm_rdf_attr,
+ bdata(q));
+ bdestroy(q);
break;
+
case srmt_fts:
- /* do something */
+ if (srp_fts) {
+ yyerror("only single fts query allowed");
+ EC_FAIL;
+ }
+ q = bfromcstr(val);
+ search = bfromcstr("*");
+ replace = bfromcstr("");
+ bfindreplace(q, search, replace, 0);
+ srp_fts = talloc_strdup(srp_slq, bdata(q));
+ result = "";
break;
+
case srmt_date:
t = atoi(val) + SPRAW_TIME_OFFSET;
EC_NULL( tmp = localtime(&t) );
strftime(buf1, sizeof(buf1), "%Y-%m-%dT%H:%M:%SZ", tmp);
- /* do something */
+
+ switch (op) {
+ case '=':
+ rdfop = "equals";
+ case '<':
+ rdfop = "lessThan";
+ case '>':
+ rdfop = "greaterThan";
+ default:
+ yyerror("unknown date comparison");
+ EC_FAIL;
+ }
+ result = talloc_asprintf(srp_slq,
+ "<rdfq:%s>\n"
+ " <rdfq:Property name=\"%s\" />\n"
+ " <rdf:Date>%s</rdf:Date>\n"
+ "</rdfq:%s>\n",
+ rdfop,
+ p->srm_rdf_attr,
+ buf1,
+ rdfop);
+
break;
+
+ case srmt_type:
+ result = map_type_search(attr, op, val);
+ break;
+
default:
yyerror("unknown Spotlight attribute type");
EC_FAIL;
}
/**
- * Map a Spotlight RAW query string to a SPARQL query string
+ * Map a Spotlight RAW query string to a RDF query
*
* @param[in] slq Spotlight query handle
- * @param[out] sparql_result Mapped SPARQL query, string is allocated in
- * talloc context of slq
* @return 0 on success, -1 on error
**/
-int map_spotlight_to_sparql_query(slq_t *slq, gchar **sparql_result)
+int map_spotlight_to_rdf_query(slq_t *slq)
{
EC_INIT;
YY_BUFFER_STATE s = NULL;
- ssp_result = NULL;
-
+ srp_result = NULL;
+ srp_fts = NULL;
+ slq->slq_service = SERVICE_FILES;
srp_slq = slq;
s = yy_scan_string(slq->slq_qstring);
EC_CLEANUP:
if (s)
yy_delete_buffer(s);
- if (ret == 0)
- *sparql_result = ssp_result;
- else
- *sparql_result = NULL;
+ if (ret == 0) {
+ slq->slq_trackerquery = srp_result;
+ slq->slq_fts = srp_fts;
+ }
EC_EXIT;
}
yy_delete_buffer(s);
if (ret == 0)
- printf("SPARQL: %s\n", ssp_result ? ssp_result : "(empty)");
-
+ printf("RDF:\n%s\nFTS: %s\n",
+ srp_result ? srp_result : "(empty)",
+ srp_fts ? srp_fts : "(none)");
return 0;
}
#endif