]> arthur.barton.de Git - netatalk.git/blob - etc/spotlight/slmod_tracker_0_6.c
Add support for Tracker 0.67 on Solaris
[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 sl_mod_fetch_result(void *p)
122 {
123     EC_INIT;
124     slq_t *slq = p;
125     GError *error = NULL;
126     int i = 0;
127     cnid_t did, id;
128     sl_cnids_t *cnids;
129     sl_filemeta_t *fm;
130     sl_array_t *fm_array;
131     sl_nil_t nil;
132     uint64_t uint64;
133     gboolean qres, firstmatch = true;
134     gchar **results = NULL, **result;
135
136     /* Prepare CNIDs */
137     cnids = talloc_zero(slq->slq_reply, sl_cnids_t);
138     cnids->ca_cnids = talloc_zero(cnids, DALLOC_CTX);
139     cnids->ca_unkn1 = 0xadd;
140     cnids->ca_context = slq->slq_ctx2;
141
142     /* Prepare FileMeta */
143     fm = talloc_zero(slq->slq_reply, sl_filemeta_t);
144     fm_array = talloc_zero(fm, sl_array_t);
145     dalloc_add(fm, fm_array, sl_array_t);
146
147     if (slq->slq_state == SLQ_STATE_RUNNING) {
148         /* Run the query */
149         become_root();
150         results = tracker_search_text(client,
151                                       time(NULL),
152                                       slq->slq_service,
153                                       slq->slq_trackerquery,
154                                       slq->slq_offset,
155                                       MAX_SL_RESULTS,
156                                       &error);
157         unbecome_root();
158
159         if (error) {
160             slq->slq_state = SLQ_STATE_DONE;
161             LOG(log_error, logtype_sl, "Couldn't query Tracker: '%s'", error->message);
162             g_clear_error(&error);
163             EC_FAIL;
164         }
165
166         if (!results) {
167             slq->slq_state = SLQ_STATE_DONE;
168             LOG(log_debug, logtype_sl, "sl_mod_fetch_result: no results found");
169             EC_EXIT_STATUS(0);
170         }
171
172         for (result = results; *result; result++) {
173             LOG(log_debug, logtype_sl, "sl_mod_fetch_result: result %d: %s", slq->slq_offset, *result);
174
175             if (firstmatch) {
176                 /* For some reason the list of results always starts with a nil entry */
177                 dalloc_add_copy(fm_array, &nil, sl_nil_t);
178                 firstmatch = false;
179             }
180
181             if ((id = cnid_for_path(slq->slq_vol->v_cdb, slq->slq_vol->v_path, *result, &did)) == CNID_INVALID) {
182                 LOG(log_error, logtype_sl, "sl_mod_fetch_result: cnid_for_path error: %s", *result);
183                 goto loop_continue;
184             }
185             LOG(log_debug, logtype_sl, "Result %d: CNID: %" PRIu32 ", path: \"%s\"", i, ntohl(id), *result);
186
187             uint64 = ntohl(id);
188             dalloc_add_copy(cnids->ca_cnids, &uint64, uint64_t);
189             add_filemeta(slq->slq_reqinfo, fm_array, id, *result);
190
191         loop_continue:
192             i++;
193             slq->slq_offset++;
194         }
195
196         if (i < MAX_SL_RESULTS)
197             slq->slq_state = SLQ_STATE_DONE;
198     }
199
200     uint64 = (i > 0) ? 35 : 0; /* OS X AFP server returns 35 here if results are found */
201     dalloc_add_copy(slq->slq_reply, &uint64, uint64_t);
202     dalloc_add(slq->slq_reply, cnids, sl_cnids_t);
203     dalloc_add(slq->slq_reply, fm, sl_filemeta_t);
204
205 EC_CLEANUP:
206     if (results) {
207         g_free(results);
208         results = NULL;
209     }
210     EC_EXIT;
211 }
212
213 /* Free ressources allocated in this module */
214 static int sl_mod_close_query(void *p)
215 {
216     EC_INIT;
217     slq_t *slq = p;
218
219 EC_CLEANUP:
220     EC_EXIT;
221 }
222
223 static int sl_mod_error(void *p)
224 {
225     EC_INIT;
226     slq_t *slq = p;
227
228     if (!slq)
229         goto EC_CLEANUP;
230
231 EC_CLEANUP:
232     EC_EXIT;
233 }
234
235 static int sl_mod_index_file(const void *p)
236 {
237     return 0;
238 }
239
240 struct sl_module_export sl_mod = {
241     SL_MODULE_VERSION,
242     sl_mod_init,
243     sl_mod_start_search,
244     sl_mod_fetch_result,
245     sl_mod_close_query,
246     sl_mod_error,
247     sl_mod_index_file
248 };