]> arthur.barton.de Git - netatalk.git/blobdiff - etc/spotlight/slmod_rdf_parser.y
Add new Spotlight RPC functions
[netatalk.git] / etc / spotlight / slmod_rdf_parser.y
index 74630fd0a33a8547227e4e7b0db9a1f2b75517d9..9352d7a27973ea043e6b89361deaa964c00b6f11 100644 (file)
@@ -7,6 +7,7 @@
   #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;
 }
 
@@ -48,7 +50,7 @@
     time_t tval;
 }
 
-%expect 5
+%expect 4
 %error-verbose
 
 %type <sval> match expr line function
@@ -70,18 +72,18 @@ input:
      
 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;
 }
 ;
 
@@ -92,21 +94,31 @@ BOOL                             {
     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);
+    }
 }
 ;
 
@@ -141,7 +153,7 @@ static time_t isodate2unix(const char *s)
     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;
@@ -156,7 +168,19 @@ const char *map_daterange(const char *dateattr, time_t date1, time_t date2)
 
     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;
         }
     }
@@ -167,7 +191,33 @@ EC_CLEANUP:
     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;
@@ -176,32 +226,86 @@ const char *map_expr(const char *attr, char op, const char *val)
     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;
@@ -235,19 +339,18 @@ int yywrap()
 } 
 
 /**
- * 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);
 
@@ -256,10 +359,10 @@ int map_spotlight_to_sparql_query(slq_t *slq, gchar **sparql_result)
 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;
 }
 
@@ -286,8 +389,9 @@ int main(int argc, char **argv)
     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