1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Copyright (C) 2005 Novell, Inc.
4  *
5  * Caja 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  * Caja 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 St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * Author: Anders Carlsson <andersca@imendio.com>
21  *
22  */
23 
24 #include <config.h>
25 #include <string.h>
26 #include <glib/gi18n.h>
27 
28 #include <eel/eel-gtk-macros.h>
29 #include <eel/eel-glib-extensions.h>
30 
31 #include "caja-query.h"
32 #include "caja-file-utilities.h"
33 
34 struct CajaQueryDetails
35 {
36     char *text;
37     char *location_uri;
38     GList *mime_types;
39     GList *tags;
40     gint64 timestamp;
41     gint64 size;
42     char *contained_text;
43 };
44 
45 G_DEFINE_TYPE (CajaQuery,
46                caja_query,
47                G_TYPE_OBJECT);
48 
49 static GObjectClass *parent_class = NULL;
50 
51 static void
finalize(GObject * object)52 finalize (GObject *object)
53 {
54     CajaQuery *query;
55 
56     query = CAJA_QUERY (object);
57 
58     g_free (query->details->text);
59     g_free (query->details);
60 
61     EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
62 }
63 
64 static void
caja_query_class_init(CajaQueryClass * class)65 caja_query_class_init (CajaQueryClass *class)
66 {
67     GObjectClass *gobject_class;
68 
69     parent_class = g_type_class_peek_parent (class);
70 
71     gobject_class = G_OBJECT_CLASS (class);
72     gobject_class->finalize = finalize;
73 }
74 
75 static void
caja_query_init(CajaQuery * query)76 caja_query_init (CajaQuery *query)
77 {
78     query->details = g_new0 (CajaQueryDetails, 1);
79     query->details->timestamp = 0;
80     query->details->size = 0;
81 }
82 
83 CajaQuery *
caja_query_new(void)84 caja_query_new (void)
85 {
86     return g_object_new (CAJA_TYPE_QUERY,  NULL);
87 }
88 
89 
90 char *
caja_query_get_text(CajaQuery * query)91 caja_query_get_text (CajaQuery *query)
92 {
93     return g_strdup (query->details->text);
94 }
95 
96 void
caja_query_set_text(CajaQuery * query,const char * text)97 caja_query_set_text (CajaQuery *query, const char *text)
98 {
99     g_free (query->details->text);
100     query->details->text = g_strdup (text);
101 }
102 
103 char *
caja_query_get_location(CajaQuery * query)104 caja_query_get_location (CajaQuery *query)
105 {
106     return g_strdup (query->details->location_uri);
107 }
108 
109 void
caja_query_set_location(CajaQuery * query,const char * uri)110 caja_query_set_location (CajaQuery *query, const char *uri)
111 {
112     g_free (query->details->location_uri);
113     query->details->location_uri = g_strdup (uri);
114 }
115 
116 GList *
caja_query_get_mime_types(CajaQuery * query)117 caja_query_get_mime_types (CajaQuery *query)
118 {
119     return g_list_copy_deep (query->details->mime_types, (GCopyFunc) g_strdup, NULL);
120 }
121 
122 void
caja_query_set_mime_types(CajaQuery * query,GList * mime_types)123 caja_query_set_mime_types (CajaQuery *query, GList *mime_types)
124 {
125     g_list_free_full (query->details->mime_types, g_free);
126     query->details->mime_types = g_list_copy_deep (mime_types, (GCopyFunc) g_strdup, NULL);
127 }
128 
129 void
caja_query_add_mime_type(CajaQuery * query,const char * mime_type)130 caja_query_add_mime_type (CajaQuery *query, const char *mime_type)
131 {
132     query->details->mime_types = g_list_append (query->details->mime_types,
133                                  g_strdup (mime_type));
134 }
135 
136 GList *
caja_query_get_tags(CajaQuery * query)137 caja_query_get_tags (CajaQuery *query)
138 {
139     return g_list_copy_deep (query->details->tags, (GCopyFunc) g_strdup, NULL);
140 }
141 
142 void
caja_query_set_tags(CajaQuery * query,GList * tags)143 caja_query_set_tags (CajaQuery *query, GList *tags)
144 {
145     g_list_free_full (query->details->tags, g_free);
146     query->details->tags = g_list_copy_deep (tags, (GCopyFunc) g_strdup, NULL);
147 }
148 
149 void
caja_query_add_tag(CajaQuery * query,const char * tag)150 caja_query_add_tag (CajaQuery *query, const char *tag)
151 {
152     gchar *normalized = g_utf8_normalize (tag, -1, G_NORMALIZE_NFD);
153     gchar *lower_case = g_utf8_strdown (normalized, -1);
154 
155     g_free (normalized);
156     query->details->tags = g_list_append (query->details->tags, lower_case);
157 }
158 
159 char *
caja_query_to_readable_string(CajaQuery * query)160 caja_query_to_readable_string (CajaQuery *query)
161 {
162     if (!query || !query->details->text)
163     {
164         return g_strdup (_("Search"));
165     }
166 
167     return g_strdup_printf (_("Search for \"%s\""), query->details->text);
168 }
169 
170 static char *
encode_home_uri(const char * uri)171 encode_home_uri (const char *uri)
172 {
173     char *home_uri;
174     const char *encoded_uri;
175 
176     home_uri = caja_get_home_directory_uri ();
177 
178     if (g_str_has_prefix (uri, home_uri))
179     {
180         encoded_uri = uri + strlen (home_uri);
181         if (*encoded_uri == '/')
182         {
183             encoded_uri++;
184         }
185     }
186     else
187     {
188         encoded_uri = uri;
189     }
190 
191     g_free (home_uri);
192 
193     return g_markup_escape_text (encoded_uri, -1);
194 }
195 
196 static char *
decode_home_uri(const char * uri)197 decode_home_uri (const char *uri)
198 {
199     char *decoded_uri;
200 
201     if (g_str_has_prefix (uri, "file:"))
202     {
203         decoded_uri = g_strdup (uri);
204     }
205     else
206     {
207         char *home_uri;
208 
209         home_uri = caja_get_home_directory_uri ();
210 
211         decoded_uri = g_strconcat (home_uri, "/", uri, NULL);
212 
213         g_free (home_uri);
214     }
215 
216     return decoded_uri;
217 }
218 
219 
220 typedef struct
221 {
222     CajaQuery *query;
223     gboolean in_text;
224     gboolean in_location;
225     gboolean in_mimetypes;
226     gboolean in_mimetype;
227     gboolean in_tags;
228     gboolean in_tag;
229 } ParserInfo;
230 
231 static void
start_element_cb(GMarkupParseContext * ctx,const char * element_name,const char ** attribute_names,const char ** attribute_values,gpointer user_data,GError ** err)232 start_element_cb (GMarkupParseContext *ctx,
233                   const char *element_name,
234                   const char **attribute_names,
235                   const char **attribute_values,
236                   gpointer user_data,
237                   GError **err)
238 {
239     ParserInfo *info;
240 
241     info = (ParserInfo *) user_data;
242 
243     if (strcmp (element_name, "text") == 0)
244         info->in_text = TRUE;
245     else if (strcmp (element_name, "location") == 0)
246         info->in_location = TRUE;
247     else if (strcmp (element_name, "mimetypes") == 0)
248         info->in_mimetypes = TRUE;
249     else if (strcmp (element_name, "mimetype") == 0)
250         info->in_mimetype = TRUE;
251     else if (strcmp (element_name, "tags") == 0)
252         info->in_tags = TRUE;
253     else if (strcmp (element_name, "tag") == 0)
254         info->in_tag = TRUE;
255 }
256 
257 static void
end_element_cb(GMarkupParseContext * ctx,const char * element_name,gpointer user_data,GError ** err)258 end_element_cb (GMarkupParseContext *ctx,
259                 const char *element_name,
260                 gpointer user_data,
261                 GError **err)
262 {
263     ParserInfo *info;
264 
265     info = (ParserInfo *) user_data;
266 
267     if (strcmp (element_name, "text") == 0)
268         info->in_text = FALSE;
269     else if (strcmp (element_name, "location") == 0)
270         info->in_location = FALSE;
271     else if (strcmp (element_name, "mimetypes") == 0)
272         info->in_mimetypes = FALSE;
273     else if (strcmp (element_name, "mimetype") == 0)
274         info->in_mimetype = FALSE;
275     else if (strcmp (element_name, "tags") == 0)
276         info->in_tags = FALSE;
277     else if (strcmp (element_name, "tag") == 0)
278         info->in_tag = FALSE;
279 }
280 
281 static void
text_cb(GMarkupParseContext * ctx,const char * text,gsize text_len,gpointer user_data,GError ** err)282 text_cb (GMarkupParseContext *ctx,
283          const char *text,
284          gsize text_len,
285          gpointer user_data,
286          GError **err)
287 {
288     ParserInfo *info;
289     char *t, *uri;
290 
291     info = (ParserInfo *) user_data;
292 
293     t = g_strndup (text, text_len);
294 
295     if (info->in_text)
296     {
297         caja_query_set_text (info->query, t);
298     }
299     else if (info->in_location)
300     {
301         uri = decode_home_uri (t);
302         caja_query_set_location (info->query, uri);
303         g_free (uri);
304     }
305     else if (info->in_mimetypes && info->in_mimetype)
306     {
307         caja_query_add_mime_type (info->query, t);
308     }
309     else if (info->in_tags && info->in_tag)
310     {
311         caja_query_add_tag (info->query, t);
312     }
313 
314     g_free (t);
315 
316 }
317 
318 static void
error_cb(GMarkupParseContext * ctx,GError * err,gpointer user_data)319 error_cb (GMarkupParseContext *ctx,
320           GError *err,
321           gpointer user_data)
322 {
323 }
324 
325 static GMarkupParser parser =
326 {
327     start_element_cb,
328     end_element_cb,
329     text_cb,
330     NULL,
331     error_cb
332 };
333 
334 
335 static CajaQuery *
caja_query_parse_xml(char * xml,gsize xml_len)336 caja_query_parse_xml (char *xml, gsize xml_len)
337 {
338     ParserInfo info = { NULL };
339     GMarkupParseContext *ctx;
340 
341     if (xml_len == -1)
342     {
343         xml_len = strlen (xml);
344     }
345 
346     info.query = caja_query_new ();
347     info.in_text = FALSE;
348 
349     ctx = g_markup_parse_context_new (&parser, 0, &info, NULL);
350     g_markup_parse_context_parse (ctx, xml, xml_len, NULL);
351     g_markup_parse_context_free (ctx);
352 
353     return info.query;
354 }
355 
356 
357 CajaQuery *
caja_query_load(char * file)358 caja_query_load (char *file)
359 {
360     CajaQuery *query;
361     char *xml;
362     gsize xml_len;
363 
364     if (!g_file_test (file, G_FILE_TEST_EXISTS))
365     {
366         return NULL;
367     }
368 
369 
370     g_file_get_contents (file, &xml, &xml_len, NULL);
371     query = caja_query_parse_xml (xml, xml_len);
372     g_free (xml);
373 
374     return query;
375 }
376 
377 static char *
caja_query_to_xml(CajaQuery * query)378 caja_query_to_xml (CajaQuery *query)
379 {
380     GString *xml;
381     char *text;
382     GList *l;
383 
384     xml = g_string_new ("");
385     g_string_append (xml,
386                      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
387                      "<query version=\"1.0\">\n");
388 
389     text = g_markup_escape_text (query->details->text, -1);
390     g_string_append_printf (xml, "   <text>%s</text>\n", text);
391     g_free (text);
392 
393     if (query->details->location_uri)
394     {
395         char *uri;
396 
397         uri = encode_home_uri (query->details->location_uri);
398         g_string_append_printf (xml, "   <location>%s</location>\n", uri);
399         g_free (uri);
400     }
401 
402     if (query->details->mime_types)
403     {
404         g_string_append (xml, "   <mimetypes>\n");
405         for (l = query->details->mime_types; l != NULL; l = l->next)
406         {
407             char *mimetype;
408 
409             mimetype = g_markup_escape_text (l->data, -1);
410             g_string_append_printf (xml, "      <mimetype>%s</mimetype>\n", mimetype);
411             g_free (mimetype);
412         }
413         g_string_append (xml, "   </mimetypes>\n");
414     }
415 
416     if (query->details->tags)
417     {
418         g_string_append (xml, "   <tags>\n");
419         for (l = query->details->tags; l != NULL; l = l->next)
420         {
421             char *tag;
422 
423             tag = g_markup_escape_text (l->data, -1);
424             g_string_append_printf (xml, "      <tag>%s</tag>\n", tag);
425             g_free (tag);
426         }
427         g_string_append (xml, "   </tags>\n");
428     }
429 
430     if (query->details->timestamp != 0)
431     {
432         g_string_append_printf(xml, "   <duration>%ld</duration>",
433                                query->details->timestamp);
434     }
435 
436     if (query->details->size != 0)
437     {
438         g_string_append_printf(xml, "   <size>%ld</size>", query->details->size);
439     }
440 
441     g_string_append (xml, "</query>\n");
442 
443     return g_string_free (xml, FALSE);
444 }
445 
446 gboolean
caja_query_save(CajaQuery * query,char * file)447 caja_query_save (CajaQuery *query, char *file)
448 {
449     char *xml;
450     GError *err = NULL;
451     gboolean res;
452 
453 
454     res = TRUE;
455     xml = caja_query_to_xml (query);
456     g_file_set_contents (file, xml, strlen (xml), &err);
457     g_free (xml);
458 
459     if (err != NULL)
460     {
461         res = FALSE;
462         g_error_free (err);
463     }
464     return res;
465 }
466 
caja_query_set_timestamp(CajaQuery * query,gint64 sec)467 void caja_query_set_timestamp(CajaQuery *query, gint64 sec)
468 {
469     query->details->timestamp = sec;
470 }
471 
caja_query_get_timestamp(CajaQuery * query)472 gint64 caja_query_get_timestamp(CajaQuery *query)
473 {
474     return query->details->timestamp;
475 }
476 
caja_query_set_size(CajaQuery * query,gint64 size)477 void caja_query_set_size(CajaQuery *query, gint64 size)
478 {
479     query->details->size = size;
480 }
481 
caja_query_get_size(CajaQuery * query)482 gint64 caja_query_get_size(CajaQuery *query)
483 {
484     return query->details->size;
485 }
486 
caja_query_set_contained_text(CajaQuery * query,const char * text)487 void caja_query_set_contained_text (CajaQuery *query, const char *text)
488 {
489     g_free (query->details->contained_text);
490     query->details->contained_text = g_strdup (text);
491 }
492 
caja_query_get_contained_text(CajaQuery * query)493 char *caja_query_get_contained_text (CajaQuery *query)
494 {
495     return g_strdup (query->details->contained_text);
496 }
497