]> arthur.barton.de Git - netatalk.git/blob - etc/spotlight/slmod_rdf.c
6863a349ffea59e0f31b02b801fbea4e72d25809
[netatalk.git] / etc / spotlight / slmod_rdf.c
1 /*
2   Copyright (c) 2012 Frank Lahm <franklahm@gmail.com>
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif /* HAVE_CONFIG_H */
18
19 #include <string.h>
20 #include <locale.h>
21
22 #include <gio/gio.h>
23 #include <tracker.h>
24
25 #include <atalk/util.h>
26 #include <atalk/errchk.h>
27 #include <atalk/logger.h>
28 #include <atalk/unix.h>
29 #include <atalk/spotlight.h>
30
31 #include "slmod_rdf_parser.h"
32
33 #define MAX_SL_RESULTS 20
34
35 TrackerClient *client;
36
37 static int sl_mod_init(void *p)
38 {
39     EC_INIT;
40     GError *error = NULL;
41     const char *msg = p;
42
43     LOG(log_info, logtype_sl, "Initializing Tracker 0.6 RDF Spotlight module");
44
45     g_type_init();
46     setenv("DBUS_SESSION_BUS_ADDRESS", "unix:path=/tmp/spotlight.ipc", 1);
47
48     client = tracker_connect(FALSE);
49
50     if (!client) {
51         LOG(log_error, logtype_sl, "Failed connecting to Tracker");
52         EC_FAIL;
53     }
54
55 EC_CLEANUP:
56     EC_EXIT;
57 }
58
59
60 static int sl_mod_start_search(void *p)
61 {
62     EC_INIT;
63     slq_t *slq = p; 
64     GError *error = NULL;
65
66     EC_ZERO_LOG( map_spotlight_to_rdf_query(slq) );
67
68     LOG(log_debug, logtype_sl, "sl_mod_start_search: Tracker service: %s, FTS: %s, RDF query:\n%s",
69         tracker_type_to_service_name(slq->slq_service),
70         slq->slq_fts,
71         slq->slq_trackerquery ? slq->slq_trackerquery : "false");
72
73     if (slq->slq_trackerquery)
74         slq->slq_state = SLQ_STATE_RUNNING;
75     else
76         slq->slq_state = SLQ_STATE_DONE;
77
78 EC_CLEANUP:
79     EC_EXIT;
80 }
81
82 static int add_filemeta(sl_array_t *reqinfo, sl_array_t *fm_array, cnid_t id, const char *path)
83 {
84     EC_INIT;
85     sl_array_t *meta;
86     sl_nil_t nil = 0;
87     int i, metacount;
88
89     if ((metacount = talloc_array_length(reqinfo->dd_talloc_array)) == 0) {
90         dalloc_add_copy(fm_array, &nil, sl_nil_t);
91         goto EC_CLEANUP;
92     }
93
94     LOG(log_debug, logtype_sl, "add_filemeta: metadata count: %d", metacount);
95
96     meta = talloc_zero(fm_array, sl_array_t);
97
98     for (i = 0; i < metacount; i++) {
99         if (STRCMP(reqinfo->dd_talloc_array[i], ==, "kMDItemDisplayName")) {
100             char *p, *name;
101             if ((p = strrchr(path, '/'))) {
102                 name = dalloc_strdup(meta, p + 1);
103                 dalloc_add(meta, name, "char *");
104             }
105         } else {
106             dalloc_add_copy(meta, &nil, sl_nil_t);
107         }
108     }
109
110     dalloc_add(fm_array, meta, sl_array_t);
111
112 EC_CLEANUP:
113     EC_EXIT;
114 }
115
116 static int cnid_cmp_fn(const void *p1, const void *p2)
117 {
118     const uint64_t *cnid1 = p1, *cnid2 = p2;
119     if (*cnid1 == *cnid2)
120         return 0;
121     if (*cnid1 < *cnid2)
122         return -1;
123     else
124         return 1;            
125 }
126
127 static int sl_mod_fetch_result(void *p)
128 {
129     EC_INIT;
130     slq_t *slq = p;
131     GError *error = NULL;
132     int i = 0;
133     cnid_t did, id;
134     sl_cnids_t *cnids;
135     sl_filemeta_t *fm;
136     sl_array_t *fm_array;
137     sl_nil_t nil;
138     uint64_t uint64;
139     gboolean qres, firstmatch = true;
140     GPtrArray *array = NULL;
141
142     /* Prepare CNIDs */
143     cnids = talloc_zero(slq->slq_reply, sl_cnids_t);
144     cnids->ca_cnids = talloc_zero(cnids, DALLOC_CTX);
145     cnids->ca_unkn1 = 0xadd;
146     cnids->ca_context = slq->slq_ctx2;
147
148     /* Prepare FileMeta */
149     fm = talloc_zero(slq->slq_reply, sl_filemeta_t);
150     fm_array = talloc_zero(fm, sl_array_t);
151     dalloc_add(fm, fm_array, sl_array_t);
152
153     LOG(log_debug, logtype_sl, "sl_mod_fetch_result");
154
155     if (slq->slq_state == SLQ_STATE_RUNNING) {
156         /* Run the query */
157         LOG(log_debug, logtype_sl, "sl_mod_fetch_result: calling tracker");
158         array = tracker_search_query(client,
159                                      time(NULL),
160                                      slq->slq_service,
161                                      NULL, /* Fields */
162                                      slq->slq_fts, /* FTS search test */
163                                      NULL,         /* Keywords */
164                                      slq->slq_trackerquery,
165                                      slq->slq_offset,
166                                      MAX_SL_RESULTS,
167                                      FALSE, /* Sort by service */
168                                      NULL,
169                                      FALSE,
170                                      &error);
171
172         if (error) {
173             slq->slq_state = SLQ_STATE_DONE;
174             LOG(log_error, logtype_sl, "Couldn't query Tracker: '%s'", error->message);
175             g_clear_error(&error);
176             EC_FAIL;
177         }
178
179         if (!array) {
180             slq->slq_state = SLQ_STATE_DONE;
181             LOG(log_debug, logtype_sl, "sl_mod_fetch_result: no results found");
182             EC_EXIT_STATUS(0);
183         }
184
185         while (i < array->len) {
186             char **resmeta = g_ptr_array_index(array, i);
187             char *respath = resmeta[0];
188             LOG(log_debug, logtype_sl, "sl_mod_fetch_result: result %d: %s", slq->slq_offset, respath);
189
190             if (firstmatch) {
191                 /* For some reason the list of results always starts with a nil entry */
192                 dalloc_add_copy(fm_array, &nil, sl_nil_t);
193                 firstmatch = false;
194             }
195
196             if ((id = cnid_for_path(slq->slq_vol->v_cdb, slq->slq_vol->v_path, respath, &did)) == CNID_INVALID) {
197                 LOG(log_error, logtype_sl, "sl_mod_fetch_result: cnid_for_path error: %s", respath);
198                 goto loop_continue;
199             }
200             LOG(log_debug, logtype_sl, "Result %d: CNID: %" PRIu32 ", path: \"%s\"", i, ntohl(id), respath);
201
202             uint64 = ntohl(id);
203             if (slq->slq_cnids) {
204                 if (!bsearch(&uint64, slq->slq_cnids, slq->slq_cnids_num, sizeof(uint64_t), cnid_cmp_fn))
205                     goto loop_continue;
206             }
207
208             dalloc_add_copy(cnids->ca_cnids, &uint64, uint64_t);
209             add_filemeta(slq->slq_reqinfo, fm_array, id, respath);
210
211         loop_continue:
212             i++;
213             slq->slq_offset++;
214         }
215
216         g_ptr_array_free(array, TRUE);
217         array = NULL;
218
219         if (i < MAX_SL_RESULTS)
220             slq->slq_state = SLQ_STATE_DONE;
221     }
222
223     uint64 = (i > 0) ? 35 : 0; /* OS X AFP server returns 35 here if results are found */
224     dalloc_add_copy(slq->slq_reply, &uint64, uint64_t);
225     dalloc_add(slq->slq_reply, cnids, sl_cnids_t);
226     dalloc_add(slq->slq_reply, fm, sl_filemeta_t);
227
228 EC_CLEANUP:
229     if (array)
230         g_ptr_array_free(array, TRUE);
231     EC_EXIT;
232 }
233
234 /* Free ressources allocated in this module */
235 static int sl_mod_close_query(void *p)
236 {
237     EC_INIT;
238     slq_t *slq = p;
239
240 EC_CLEANUP:
241     EC_EXIT;
242 }
243
244 static int sl_mod_error(void *p)
245 {
246     EC_INIT;
247     slq_t *slq = p;
248
249     if (!slq)
250         goto EC_CLEANUP;
251
252 EC_CLEANUP:
253     EC_EXIT;
254 }
255
256 static int sl_mod_index_file(const void *p)
257 {
258     return 0;
259 }
260
261 struct sl_module_export sl_mod = {
262     SL_MODULE_VERSION,
263     sl_mod_init,
264     sl_mod_start_search,
265     sl_mod_fetch_result,
266     sl_mod_close_query,
267     sl_mod_error,
268     sl_mod_index_file
269 };