1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Copyright (C) 2005 Novell, Inc.
4  *
5  * Nemo is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * Nemo is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; see the file COPYING.  If not,
17  * write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
18  * Boston, MA 02110-1335, USA.
19  *
20  * Author: Anders Carlsson <andersca@imendio.com>
21  *
22  */
23 
24 #include <config.h>
25 #include <string.h>
26 
27 #include "nemo-query.h"
28 #include <eel/eel-glib-extensions.h>
29 #include <glib/gi18n.h>
30 #include <libnemo-private/nemo-file-utilities.h>
31 
32 struct NemoQueryDetails {
33 	char *text;
34 	char *location_uri;
35 	GList *mime_types;
36     gboolean show_hidden;
37 };
38 
39 G_DEFINE_TYPE (NemoQuery, nemo_query, G_TYPE_OBJECT);
40 
41 static void
finalize(GObject * object)42 finalize (GObject *object)
43 {
44 	NemoQuery *query;
45 
46 	query = NEMO_QUERY (object);
47 	g_free (query->details->text);
48 	g_free (query->details->location_uri);
49 
50 	G_OBJECT_CLASS (nemo_query_parent_class)->finalize (object);
51 }
52 
53 static void
nemo_query_class_init(NemoQueryClass * class)54 nemo_query_class_init (NemoQueryClass *class)
55 {
56 	GObjectClass *gobject_class;
57 
58 	gobject_class = G_OBJECT_CLASS (class);
59 	gobject_class->finalize = finalize;
60 
61 	g_type_class_add_private (class, sizeof (NemoQueryDetails));
62 }
63 
64 static void
nemo_query_init(NemoQuery * query)65 nemo_query_init (NemoQuery *query)
66 {
67 	query->details = G_TYPE_INSTANCE_GET_PRIVATE (query, NEMO_TYPE_QUERY,
68 						      NemoQueryDetails);
69 }
70 
71 NemoQuery *
nemo_query_new(void)72 nemo_query_new (void)
73 {
74 	return g_object_new (NEMO_TYPE_QUERY,  NULL);
75 }
76 
77 char *
nemo_query_get_text(NemoQuery * query)78 nemo_query_get_text (NemoQuery *query)
79 {
80     g_return_val_if_fail (NEMO_IS_QUERY (query), NULL);
81 
82 	return g_strdup (query->details->text);
83 }
84 
85 void
nemo_query_set_text(NemoQuery * query,const char * text)86 nemo_query_set_text (NemoQuery *query, const char *text)
87 {
88     g_return_if_fail (NEMO_IS_QUERY (query));
89 
90 	g_free (query->details->text);
91 	query->details->text = g_strstrip (g_strdup (text));
92 }
93 
94 char *
nemo_query_get_location(NemoQuery * query)95 nemo_query_get_location (NemoQuery *query)
96 {
97     g_return_val_if_fail (NEMO_IS_QUERY (query), NULL);
98 
99 	return g_strdup (query->details->location_uri);
100 }
101 
102 void
nemo_query_set_location(NemoQuery * query,const char * uri)103 nemo_query_set_location (NemoQuery *query, const char *uri)
104 {
105     g_return_if_fail (NEMO_IS_QUERY (query));
106 
107 	g_free (query->details->location_uri);
108 	query->details->location_uri = g_strdup (uri);
109 }
110 
111 GList *
nemo_query_get_mime_types(NemoQuery * query)112 nemo_query_get_mime_types (NemoQuery *query)
113 {
114     g_return_val_if_fail (NEMO_IS_QUERY (query), NULL);
115 
116 	return eel_g_str_list_copy (query->details->mime_types);
117 }
118 
119 void
nemo_query_set_mime_types(NemoQuery * query,GList * mime_types)120 nemo_query_set_mime_types (NemoQuery *query, GList *mime_types)
121 {
122     g_return_if_fail (NEMO_IS_QUERY (query));
123 
124 	g_list_free_full (query->details->mime_types, g_free);
125 	query->details->mime_types = eel_g_str_list_copy (mime_types);
126 }
127 
128 void
nemo_query_add_mime_type(NemoQuery * query,const char * mime_type)129 nemo_query_add_mime_type (NemoQuery *query, const char *mime_type)
130 {
131     g_return_if_fail (NEMO_IS_QUERY (query));
132 
133 	query->details->mime_types = g_list_append (query->details->mime_types,
134 						    g_strdup (mime_type));
135 }
136 
137 void
nemo_query_set_show_hidden(NemoQuery * query,gboolean hidden)138 nemo_query_set_show_hidden (NemoQuery *query, gboolean hidden)
139 {
140     g_return_if_fail (NEMO_IS_QUERY (query));
141 
142     query->details->show_hidden = hidden;
143 }
144 
145 gboolean
nemo_query_get_show_hidden(NemoQuery * query)146 nemo_query_get_show_hidden (NemoQuery *query)
147 {
148     g_return_val_if_fail (NEMO_IS_QUERY (query), FALSE);
149 
150     return query->details->show_hidden;
151 }
152 
153 char *
nemo_query_to_readable_string(NemoQuery * query)154 nemo_query_to_readable_string (NemoQuery *query)
155 {
156     g_return_val_if_fail (NEMO_IS_QUERY (query), NULL);
157 
158     GFile *file;
159     gchar *location_title, *readable;
160 
161 	if (!query || !query->details->text || query->details->text[0] == '\0') {
162 		return g_strdup (_("Search"));
163 	}
164 
165     file = g_file_new_for_uri (query->details->location_uri);
166     location_title = nemo_compute_search_title_for_location (file);
167 
168     g_object_unref (file);
169 
170     readable = g_strdup_printf (_("Search for \"%s\" in \"%s\""), query->details->text, location_title);
171 
172     g_free (location_title);
173 
174     return readable;
175 }
176 
177 static char *
encode_home_uri(const char * uri)178 encode_home_uri (const char *uri)
179 {
180 	char *home_uri;
181 	const char *encoded_uri;
182 
183 	home_uri = nemo_get_home_directory_uri ();
184 
185 	if (g_str_has_prefix (uri, home_uri)) {
186 		encoded_uri = uri + strlen (home_uri);
187 		if (*encoded_uri == '/') {
188 			encoded_uri++;
189 		}
190 	} else {
191 		encoded_uri = uri;
192 	}
193 
194 	g_free (home_uri);
195 
196 	return g_markup_escape_text (encoded_uri, -1);
197 }
198 
199 static char *
decode_home_uri(const char * uri)200 decode_home_uri (const char *uri)
201 {
202 	char *home_uri;
203 	char *decoded_uri;
204 
205 	if (g_str_has_prefix (uri, "file:")) {
206 		decoded_uri = g_strdup (uri);
207 	} else {
208 		home_uri = nemo_get_home_directory_uri ();
209 
210 		decoded_uri = g_strconcat (home_uri, "/", uri, NULL);
211 
212 		g_free (home_uri);
213 	}
214 
215 	return decoded_uri;
216 }
217 
218 
219 typedef struct {
220 	NemoQuery *query;
221 	gboolean in_text;
222 	gboolean in_location;
223 	gboolean in_mimetypes;
224 	gboolean in_mimetype;
225 	gboolean error;
226 } ParserInfo;
227 
228 static void
start_element_cb(GMarkupParseContext * ctx,const char * element_name,const char ** attribute_names,const char ** attribute_values,gpointer user_data,GError ** err)229 start_element_cb (GMarkupParseContext *ctx,
230 		  const char *element_name,
231 		  const char **attribute_names,
232 		  const char **attribute_values,
233 		  gpointer user_data,
234 		  GError **err)
235 {
236 	ParserInfo *info;
237 
238 	info = (ParserInfo *) user_data;
239 
240 	if (strcmp (element_name, "text") == 0)
241 		info->in_text = TRUE;
242 	else if (strcmp (element_name, "location") == 0)
243 		info->in_location = TRUE;
244 	else if (strcmp (element_name, "mimetypes") == 0)
245 		info->in_mimetypes = TRUE;
246 	else if (strcmp (element_name, "mimetype") == 0)
247 		info->in_mimetype = TRUE;
248 }
249 
250 static void
end_element_cb(GMarkupParseContext * ctx,const char * element_name,gpointer user_data,GError ** err)251 end_element_cb (GMarkupParseContext *ctx,
252 		const char *element_name,
253 		gpointer user_data,
254 		GError **err)
255 {
256 	ParserInfo *info;
257 
258 	info = (ParserInfo *) user_data;
259 
260 	if (strcmp (element_name, "text") == 0)
261 		info->in_text = FALSE;
262 	else if (strcmp (element_name, "location") == 0)
263 		info->in_location = FALSE;
264 	else if (strcmp (element_name, "mimetypes") == 0)
265 		info->in_mimetypes = FALSE;
266 	else if (strcmp (element_name, "mimetype") == 0)
267 		info->in_mimetype = FALSE;
268 }
269 
270 static void
text_cb(GMarkupParseContext * ctx,const char * text,gsize text_len,gpointer user_data,GError ** err)271 text_cb (GMarkupParseContext *ctx,
272 	 const char *text,
273 	 gsize text_len,
274 	 gpointer user_data,
275 	 GError **err)
276 {
277 	ParserInfo *info;
278 	char *t, *uri;
279 
280 	info = (ParserInfo *) user_data;
281 
282 	t = g_strndup (text, text_len);
283 
284 	if (info->in_text) {
285 		nemo_query_set_text (info->query, t);
286 	} else if (info->in_location) {
287 		uri = decode_home_uri (t);
288 		nemo_query_set_location (info->query, uri);
289 		g_free (uri);
290 	} else if (info->in_mimetypes && info->in_mimetype) {
291 		nemo_query_add_mime_type (info->query, t);
292 	}
293 
294 	g_free (t);
295 
296 }
297 
298 static void
error_cb(GMarkupParseContext * ctx,GError * err,gpointer user_data)299 error_cb (GMarkupParseContext *ctx,
300 	  GError *err,
301 	  gpointer user_data)
302 {
303 	ParserInfo *info;
304 
305 	info = (ParserInfo *) user_data;
306 
307 	info->error = TRUE;
308 }
309 
310 static GMarkupParser parser = {
311 	start_element_cb,
312 	end_element_cb,
313 	text_cb,
314 	NULL,
315 	error_cb
316 };
317 
318 
319 static NemoQuery *
nemo_query_parse_xml(char * xml,gsize xml_len)320 nemo_query_parse_xml (char *xml, gsize xml_len)
321 {
322 	ParserInfo info = { NULL };
323 	GMarkupParseContext *ctx;
324 
325 	info.query = nemo_query_new ();
326 	info.in_text = FALSE;
327 	info.error = FALSE;
328 
329 	ctx = g_markup_parse_context_new (&parser, 0, &info, NULL);
330 	g_markup_parse_context_parse (ctx, xml, xml_len, NULL);
331 	g_markup_parse_context_free (ctx);
332 
333 	if (info.error) {
334 		g_object_unref (info.query);
335 		return NULL;
336 	}
337 
338 	return info.query;
339 }
340 
341 
342 NemoQuery *
nemo_query_load(char * file)343 nemo_query_load (char *file)
344 {
345 	NemoQuery *query;
346 	char *xml;
347 	gsize xml_len;
348 
349 	if (!g_file_test (file, G_FILE_TEST_EXISTS)) {
350 		return NULL;
351 	}
352 
353 
354 	g_file_get_contents (file, &xml, &xml_len, NULL);
355 
356 	if (xml_len == 0) {
357 		return NULL;
358 	}
359 
360 	query = nemo_query_parse_xml (xml, xml_len);
361 	g_free (xml);
362 
363 	return query;
364 }
365 
366 static char *
nemo_query_to_xml(NemoQuery * query)367 nemo_query_to_xml (NemoQuery *query)
368 {
369 	GString *xml;
370 	char *text;
371 	char *uri;
372 	char *mimetype;
373 	GList *l;
374 
375 	xml = g_string_new ("");
376 	g_string_append (xml,
377 			 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
378 			 "<query version=\"1.0\">\n");
379 
380 	text = g_markup_escape_text (query->details->text, -1);
381 	g_string_append_printf (xml, "   <text>%s</text>\n", text);
382 	g_free (text);
383 
384 	if (query->details->location_uri) {
385 		uri = encode_home_uri (query->details->location_uri);
386 		g_string_append_printf (xml, "   <location>%s</location>\n", uri);
387 		g_free (uri);
388 	}
389 
390 	if (query->details->mime_types) {
391 		g_string_append (xml, "   <mimetypes>\n");
392 		for (l = query->details->mime_types; l != NULL; l = l->next) {
393 			mimetype = g_markup_escape_text (l->data, -1);
394 			g_string_append_printf (xml, "      <mimetype>%s</mimetype>\n", mimetype);
395 			g_free (mimetype);
396 		}
397 		g_string_append (xml, "   </mimetypes>\n");
398 	}
399 
400 	g_string_append (xml, "</query>\n");
401 
402 	return g_string_free (xml, FALSE);
403 }
404 
405 gboolean
nemo_query_save(NemoQuery * query,char * file)406 nemo_query_save (NemoQuery *query, char *file)
407 {
408 	char *xml;
409 	GError *err = NULL;
410 	gboolean res;
411 
412 
413 	res = TRUE;
414 	xml = nemo_query_to_xml (query);
415 	g_file_set_contents (file, xml, strlen (xml), &err);
416 	g_free (xml);
417 
418 	if (err != NULL) {
419 		res = FALSE;
420 		g_error_free (err);
421 	}
422 	return res;
423 }
424