]> arthur.barton.de Git - netatalk.git/blob - etc/spotlight/slmod_tracker_0_6.c
Merge branch 'develop' into spotlight
[netatalk.git] / etc / spotlight / slmod_tracker_0_6.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_tracker_0_6_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 Spotlight module");
44
45     g_type_init();
46     setenv("DBUS_SESSION_BUS_ADDRESS", "unix:path=/tmp/spotlight.ipc", 1);
47
48     become_root();
49     client = tracker_connect(FALSE);
50     unbecome_root();
51
52     if (!client) {
53         LOG(log_error, logtype_sl, "Failed connecting to Tracker");
54         EC_FAIL;
55     }
56
57 EC_CLEANUP:
58     EC_EXIT;
59 }
60
61
62 static int sl_mod_start_search(void *p)
63 {
64     EC_INIT;
65     slq_t *slq = p; 
66     GError *error = NULL;
67
68     LOG(log_debug, logtype_sl, "sl_mod_start_search: Spotlight query: \"%s\"", slq->slq_qstring);
69
70     EC_ZERO_LOG( map_spotlight_to_tracker_0_6_query(slq,
71                                                     (ServiceType *)(&slq->slq_service),
72                                                     &slq->slq_trackerquery) );
73
74     LOG(log_debug, logtype_sl, "sl_mod_start_search: Tracker service: %s, query: \"%s\"",
75         tracker_type_to_service_name(slq->slq_service),
76         slq->slq_trackerquery ? slq->slq_trackerquery : "false");
77
78     if (slq->slq_trackerquery)
79         slq->slq_state = SLQ_STATE_RUNNING;
80     else
81         slq->slq_state = SLQ_STATE_DONE;
82
83 EC_CLEANUP:
84     EC_EXIT;
85 }
86
87 static int add_filemeta(sl_array_t *reqinfo, sl_array_t *fm_array, cnid_t id, const char *path)
88 {
89     EC_INIT;
90     sl_array_t *meta;
91     sl_nil_t nil = 0;
92     int i, metacount;
93
94     if ((metacount = talloc_array_length(reqinfo->dd_talloc_array)) == 0) {
95         dalloc_add_copy(fm_array, &nil, sl_nil_t);
96         goto EC_CLEANUP;
97     }
98
99     LOG(log_debug, logtype_sl, "add_filemeta: metadata count: %d", metacount);
100
101     meta = talloc_zero(fm_array, sl_array_t);
102
103     for (i = 0; i < metacount; i++) {
104         if (STRCMP(reqinfo->dd_talloc_array[i], ==, "kMDItemDisplayName")) {
105             char *p, *name;
106             if ((p = strrchr(path, '/'))) {
107                 name = dalloc_strdup(meta, p + 1);
108                 dalloc_add(meta, name, "char *");
109             }
110         } else {
111             dalloc_add_copy(meta, &nil, sl_nil_t);
112         }
113     }
114
115     dalloc_add(fm_array, meta, sl_array_t);
116
117 EC_CLEANUP:
118     EC_EXIT;
119 }
120
121 static int cnid_cmp_fn(const void *p1, const void *p2)
122 {
123     const uint64_t *cnid1 = p1, *cnid2 = p2;
124     if (*cnid1 == *cnid2)
125         return 0;
126     if (*cnid1 < *cnid2)
127         return -1;
128     else
129         return 1;            
130 }
131
132 static int sl_mod_fetch_result(void *p)
133 {
134     EC_INIT;
135     slq_t *slq = p;
136     GError *error = NULL;
137     int i = 0;
138     cnid_t did, id;
139     sl_cnids_t *cnids;
140     sl_filemeta_t *fm;
141     sl_array_t *fm_array;
142     sl_nil_t nil;
143     uint64_t uint64;
144     gboolean qres, firstmatch = true;
145     gchar **results = NULL, **result;
146
147     /* Prepare CNIDs */
148     cnids = talloc_zero(slq->slq_reply, sl_cnids_t);
149     cnids->ca_cnids = talloc_zero(cnids, DALLOC_CTX);
150     cnids->ca_unkn1 = 0xadd;
151     cnids->ca_context = slq->slq_ctx2;
152
153     /* Prepare FileMeta */
154     fm = talloc_zero(slq->slq_reply, sl_filemeta_t);
155     fm_array = talloc_zero(fm, sl_array_t);
156     dalloc_add(fm, fm_array, sl_array_t);
157
158     if (slq->slq_state == SLQ_STATE_RUNNING) {
159         /* Run the query */
160         become_root();
161         results = tracker_search_text(client,
162                                       time(NULL),
163                                       slq->slq_service,
164                                       slq->slq_trackerquery,
165                                       slq->slq_offset,
166                                       MAX_SL_RESULTS,
167                                       &error);
168         unbecome_root();
169
170         if (error) {
171             slq->slq_state = SLQ_STATE_DONE;
172             LOG(log_error, logtype_sl, "Couldn't query Tracker: '%s'", error->message);
173             g_clear_error(&error);
174             EC_FAIL;
175         }
176
177         if (!results) {
178             slq->slq_state = SLQ_STATE_DONE;
179             LOG(log_debug, logtype_sl, "sl_mod_fetch_result: no results found");
180             EC_EXIT_STATUS(0);
181         }
182
183         for (result = results; *result; result++) {
184             LOG(log_debug, logtype_sl, "sl_mod_fetch_result: result %d: %s", slq->slq_offset, *result);
185
186             if (firstmatch) {
187                 /* For some reason the list of results always starts with a nil entry */
188                 dalloc_add_copy(fm_array, &nil, sl_nil_t);
189                 firstmatch = false;
190             }
191
192             if ((id = cnid_for_path(slq->slq_vol->v_cdb, slq->slq_vol->v_path, *result, &did)) == CNID_INVALID) {
193                 LOG(log_error, logtype_sl, "sl_mod_fetch_result: cnid_for_path error: %s", *result);
194                 goto loop_continue;
195             }
196             LOG(log_debug, logtype_sl, "Result %d: CNID: %" PRIu32 ", path: \"%s\"", i, ntohl(id), *result);
197
198             uint64 = ntohl(id);
199             if (slq->slq_cnids) {
200                 if (!bsearch(&uint64, slq->slq_cnids, slq->slq_cnids_num, sizeof(uint64_t), cnid_cmp_fn))
201                     goto loop_continue;
202             }
203
204             dalloc_add_copy(cnids->ca_cnids, &uint64, uint64_t);
205             add_filemeta(slq->slq_reqinfo, fm_array, id, *result);
206
207         loop_continue:
208             i++;
209             slq->slq_offset++;
210         }
211
212         if (i < MAX_SL_RESULTS)
213             slq->slq_state = SLQ_STATE_DONE;
214     }
215
216     uint64 = (i > 0) ? 35 : 0; /* OS X AFP server returns 35 here if results are found */
217     dalloc_add_copy(slq->slq_reply, &uint64, uint64_t);
218     dalloc_add(slq->slq_reply, cnids, sl_cnids_t);
219     dalloc_add(slq->slq_reply, fm, sl_filemeta_t);
220
221 EC_CLEANUP:
222     if (results) {
223         g_free(results);
224         results = NULL;
225     }
226     EC_EXIT;
227 }
228
229 /* Free ressources allocated in this module */
230 static int sl_mod_close_query(void *p)
231 {
232     EC_INIT;
233     slq_t *slq = p;
234
235 EC_CLEANUP:
236     EC_EXIT;
237 }
238
239 static int sl_mod_error(void *p)
240 {
241     EC_INIT;
242     slq_t *slq = p;
243
244     if (!slq)
245         goto EC_CLEANUP;
246
247 EC_CLEANUP:
248     EC_EXIT;
249 }
250
251 static int sl_mod_index_file(const void *p)
252 {
253     return 0;
254 }
255
256 struct sl_module_export sl_mod = {
257     SL_MODULE_VERSION,
258     sl_mod_init,
259     sl_mod_start_search,
260     sl_mod_fetch_result,
261     sl_mod_close_query,
262     sl_mod_error,
263     sl_mod_index_file
264 };