1
/* Nautilus Actions configuration tool
2
* Copyright (C) 2005 The GNOME Foundation
5
* Frederic Ruaudel (grumz@grumz.net)
6
* Rodrigo Moya (rodrigo@gnome-db.org)
8
* This Program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public License as
10
* published by the Free Software Foundation; either version 2 of the
11
* License, or (at your option) any later version.
13
* This Program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* General Public License for more details.
18
* You should have received a copy of the GNU General Public
19
* License along with this Library; see the file COPYING. If not,
20
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21
* Boston, MA 02111-1307, USA.
26
#include <libxml/parser.h>
27
#include <libxml/tree.h>
28
#include <uuid/uuid.h>
29
#include "nautilus-actions-config-xml.h"
30
#include "nautilus-actions-config.h"
32
#define ACTIONS_CONFIG_DIR DEFAULT_CONFIG_PATH
33
#define ACTIONS_PER_USER_CONFIG_DIR ".config/nautilus-actions"
34
#define ACTION_ROOT "nautilus-actions-config"
35
#define ACTION_VERSION "version"
36
#define ACTION_ACTION "action"
37
#define ACTION_ACTION_NAME "name"
38
#define ACTION_MENU_ITEM "menu-item"
39
#define ACTION_LANG "lang"
40
#define ACTION_LABEL "label"
41
#define ACTION_TOOLTIP "tooltip"
42
#define ACTION_COMMAND "command"
43
#define ACTION_PATH "path"
44
#define ACTION_PARAMS "parameters"
45
#define ACTION_TEST "test"
46
#define ACTION_BASENAMES "basename"
47
#define ACTION_BASENAMES_MATCH "match"
48
#define ACTION_ISFILE "isfile"
49
#define ACTION_ISDIR "isdir"
50
#define ACTION_MULTIPLE "accept-multiple-files"
51
#define ACTION_SCHEMES "scheme"
52
#define ACTION_SCHEMES_TYPE "type"
54
static GObjectClass *parent_class = NULL;
57
save_action (NautilusActionsConfig *self, NautilusActionsConfigAction *action)
61
g_return_val_if_fail (NAUTILUS_ACTIONS_IS_CONFIG_XML (self), NULL);
63
NautilusActionsConfigXml* config = NAUTILUS_ACTIONS_CONFIG_XML (self);
66
// set the version on the action
68
g_free (action->version);
69
action->version = g_strdup (NAUTILUS_ACTIONS_CONFIG_VERSION);
74
remove_action (NautilusActionsConfig *self, NautilusActionsConfigAction* action)
76
g_return_val_if_fail (NAUTILUS_ACTIONS_IS_CONFIG_XML (self), FALSE);
78
//NautilusActionsConfigXml* config = NAUTILUS_ACTIONS_CONFIG_XML (self);
83
static GList *nautilus_actions_config_xml_get_config_files (void)
85
GList* config_files = NULL;
86
GDir* config_dir = NULL;
87
const gchar* filename;
89
gchar* per_user_dir = g_build_path ("/", g_get_home_dir (), ACTIONS_PER_USER_CONFIG_DIR, NULL);
91
/* First get the per user files so they have priority because there are first parsed */
93
if (g_file_test (per_user_dir, G_FILE_TEST_IS_DIR))
95
config_dir = g_dir_open (per_user_dir, 0, NULL);
96
if (config_dir != NULL)
98
filename = g_dir_read_name (config_dir);
99
while (filename != NULL)
101
path = g_build_path ("/", per_user_dir, filename, NULL);
102
if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
104
// This is a regular file, we can add it
105
config_files = g_list_append (config_files, g_strdup (path));
108
filename = g_dir_read_name (config_dir);
111
g_dir_close (config_dir);
115
g_free (per_user_dir);
117
/* Then get system-wide config files, if there are duplicate of above, they will be skipped during parsing */
118
if (g_file_test (ACTIONS_CONFIG_DIR, G_FILE_TEST_IS_DIR))
120
config_dir = g_dir_open (ACTIONS_CONFIG_DIR, 0, NULL);
121
if (config_dir != NULL)
123
filename = g_dir_read_name (config_dir);
124
while (filename != NULL)
126
path = g_build_path ("/", ACTIONS_CONFIG_DIR, filename, NULL);
127
if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
129
/* This is a regular file, we can add it */
130
config_files = g_list_append (config_files, g_strdup (path));
133
filename = g_dir_read_name (config_dir);
136
g_dir_close (config_dir);
144
nautilus_actions_config_xml_free_config_files (GList* config_files)
146
g_list_foreach (config_files, (GFunc) g_free, NULL);
147
g_list_free (config_files);
152
nautilus_actions_config_xml_action_fill_test_basenames (GSList** test_basenames, xmlNode* config_test_basename_node, const gchar* config_version)
155
gboolean retv = FALSE;
157
if (g_ascii_strncasecmp (config_version, "0.1", strlen (config_version)) == 0)
159
//--> manage backward compatibility
160
xmlChar* text = xmlNodeGetContent (config_test_basename_node);
161
(*test_basenames) = g_slist_append ((*test_basenames), xmlStrdup (text));
167
for (iter = config_test_basename_node->children; iter; iter = iter->next)
171
if (iter->type == XML_ELEMENT_NODE &&
172
g_ascii_strncasecmp ((const gchar *) iter->name,
173
ACTION_BASENAMES_MATCH,
174
strlen (ACTION_BASENAMES_MATCH)) == 0)
176
text = xmlNodeGetContent (iter);
177
(*test_basenames) = g_slist_append ((*test_basenames), xmlStrdup (text));
188
nautilus_actions_config_xml_action_fill_test_scheme (GSList** test_scheme, xmlNode* config_test_scheme_node)
191
gboolean retv = FALSE;
193
for (iter = config_test_scheme_node->children; iter; iter = iter->next)
197
if (iter->type == XML_ELEMENT_NODE &&
198
g_ascii_strncasecmp ((const gchar *) iter->name,
200
strlen (ACTION_SCHEMES_TYPE)) == 0)
202
text = xmlNodeGetContent (iter);
203
(*test_scheme) = g_slist_append ((*test_scheme), xmlStrdup (text));
212
static gboolean nautilus_actions_config_xml_parse_boolean (const gchar* value2parse, gboolean *value2set)
214
gboolean retv = FALSE;
216
if (g_ascii_strncasecmp (value2parse, "true", strlen ("true")) == 0)
221
else if (g_ascii_strncasecmp (value2parse, "false", strlen ("false")) == 0)
223
(*value2set) = FALSE;
230
static gboolean nautilus_actions_config_xml_action_fill_test (NautilusActionsConfigAction *action, xmlNode* config_test_node)
233
gboolean retv = FALSE;
234
gboolean basename_ok = FALSE;
235
gboolean isfile_ok = FALSE;
236
gboolean isdir_ok = FALSE;
237
gboolean scheme_ok = FALSE;
238
gboolean accept_multiple_file_ok = FALSE;
240
for (iter = config_test_node->children; iter; iter = iter->next)
244
if (!basename_ok && iter->type == XML_ELEMENT_NODE &&
245
g_ascii_strncasecmp ((gchar*)iter->name,
247
strlen (ACTION_BASENAMES)) == 0)
249
basename_ok = nautilus_actions_config_xml_action_fill_test_basenames (&(action->basenames), iter, action->version);
251
else if (!isfile_ok && iter->type == XML_ELEMENT_NODE &&
252
g_ascii_strncasecmp ((gchar*)iter->name,
254
strlen (ACTION_ISFILE)) == 0)
256
text = xmlNodeGetContent (iter);
257
isfile_ok = nautilus_actions_config_xml_parse_boolean ((char*)text, &(action->is_file));
260
else if (!isdir_ok && iter->type == XML_ELEMENT_NODE &&
261
g_ascii_strncasecmp ((gchar*)iter->name,
263
strlen (ACTION_ISDIR)) == 0)
265
text = xmlNodeGetContent (iter);
266
isdir_ok = nautilus_actions_config_xml_parse_boolean ((char*)text, &(action->is_dir));
269
else if (!accept_multiple_file_ok && iter->type == XML_ELEMENT_NODE &&
270
g_ascii_strncasecmp ((gchar*)iter->name,
272
strlen (ACTION_MULTIPLE)) == 0)
274
text = xmlNodeGetContent (iter);
275
accept_multiple_file_ok = nautilus_actions_config_xml_parse_boolean ((char*)text, &(action->accept_multiple_files));
278
else if (!scheme_ok && iter->type == XML_ELEMENT_NODE &&
279
g_ascii_strncasecmp ((gchar*)iter->name,
281
strlen (ACTION_SCHEMES)) == 0)
283
scheme_ok = nautilus_actions_config_xml_action_fill_test_scheme (&(action->schemes), iter);
288
if (basename_ok && isfile_ok && isdir_ok && accept_multiple_file_ok && scheme_ok)
290
//--> manage backward compatibility
291
action->match_case = TRUE;
292
action->mimetypes = g_slist_append (action->mimetypes, g_strdup ("*/*"));
299
static gboolean nautilus_actions_config_xml_action_fill_command (NautilusActionsConfigAction *action, xmlNode* config_command_node)
302
gboolean retv = FALSE;
303
gboolean path_ok = FALSE;
304
gboolean parameters_ok = FALSE;
306
for (iter = config_command_node->children; iter; iter = iter->next)
310
if (!path_ok && iter->type == XML_ELEMENT_NODE &&
311
g_ascii_strncasecmp ((gchar*)iter->name,
313
strlen (ACTION_PATH)) == 0)
315
text = xmlNodeGetContent (iter);
316
action->path = (char*)xmlStrdup (text);
320
else if (!parameters_ok && iter->type == XML_ELEMENT_NODE &&
321
g_ascii_strncasecmp ((gchar*)iter->name,
323
strlen (ACTION_PARAMS)) == 0)
325
text = xmlNodeGetContent (iter);
326
action->parameters = (char*)xmlStrdup (text);
328
parameters_ok = TRUE;
332
if (path_ok && parameters_ok)
340
static gboolean nautilus_actions_config_xml_action_fill_menu_item (NautilusActionsConfigAction *action, xmlNode* config_menu_item_node)
343
gboolean retv = FALSE;
344
gboolean label_ok = FALSE;
345
gboolean label_lang_ok = FALSE;
346
gboolean tooltip_ok = FALSE;
347
gboolean tooltip_lang_ok = FALSE;
348
gchar* lang = g_strdup (g_getenv ("LANG"));
351
for (iter = config_menu_item_node->children; iter; iter = iter->next)
355
if (iter->type == XML_ELEMENT_NODE &&
356
g_ascii_strncasecmp ((gchar*)iter->name,
358
strlen (ACTION_LABEL)) == 0)
360
xmlLang = xmlGetProp (iter, BAD_CAST ACTION_LANG);
361
text = xmlNodeGetContent (iter);
362
if (lang == NULL && xmlLang == NULL)
364
//--> No $LANG set, get the default one (no xml:lang)
365
action->label = (char*)xmlStrdup (text);
367
label_lang_ok = TRUE;
369
else if (lang != NULL && xmlLang == NULL)
373
//--> $LANG set, not found the good xml:lang yet, get the default one (no xml:lang)
374
action->label = (char*)xmlStrdup (text);
378
else if (lang != NULL && (xmlLang != NULL && g_ascii_strncasecmp ((gchar*)xmlLang, lang, xmlStrlen (xmlLang)) == 0))
380
//--> $LANG set, found the good xml:lang, free the default one if any and set the good one instead
381
if (action->label != NULL)
383
g_free (action->label);
385
action->label = (char*)xmlStrdup (text);
387
label_lang_ok = TRUE;
392
else if (iter->type == XML_ELEMENT_NODE &&
393
g_ascii_strncasecmp ((gchar*)iter->name,
395
strlen (ACTION_TOOLTIP)) == 0)
397
xmlLang = xmlGetProp (iter, BAD_CAST ACTION_LANG);
398
text = xmlNodeGetContent (iter);
399
if (lang == NULL && xmlLang == NULL)
401
//--> No $LANG set, get the default one (no xml:lang)
402
action->tooltip = (char*)xmlStrdup (text);
404
tooltip_lang_ok = TRUE;
406
else if (lang != NULL && xmlLang == NULL)
408
if (!tooltip_lang_ok)
410
//--> $LANG set, not found the good xml:lang yet, get the default one (no xml:lang)
411
action->tooltip = (char*)xmlStrdup (text);
415
else if (lang != NULL && (xmlLang != NULL && g_ascii_strncasecmp ((gchar*)xmlLang, lang, xmlStrlen (xmlLang)) == 0))
417
//--> $LANG set, found the good xml:lang, free the default one if any and set the good one instead
418
if (action->tooltip != NULL)
420
g_free (action->tooltip);
422
action->tooltip = (char*)xmlStrdup (text);
424
tooltip_lang_ok = TRUE;
431
if (label_ok && tooltip_ok)
433
action->icon = g_strdup ("");
442
static gboolean nautilus_actions_config_xml_action_fill (NautilusActionsConfigAction* action, xmlNode* config_node, GError** error)
445
gboolean retv = FALSE;
446
gboolean test_ok = FALSE;
447
gboolean command_ok = FALSE;
448
gboolean menu_item_ok = FALSE;
450
for (iter = config_node->children; iter; iter = iter->next)
452
if (!test_ok && iter->type == XML_ELEMENT_NODE &&
453
g_ascii_strncasecmp ((gchar*)iter->name,
455
strlen (ACTION_TEST)) == 0)
457
test_ok = nautilus_actions_config_xml_action_fill_test (action, iter);
459
else if (!command_ok && iter->type == XML_ELEMENT_NODE &&
460
g_ascii_strncasecmp ((gchar*)iter->name,
462
strlen (ACTION_COMMAND)) == 0)
464
command_ok = nautilus_actions_config_xml_action_fill_command (action, iter);
466
else if (!menu_item_ok && iter->type == XML_ELEMENT_NODE &&
467
g_ascii_strncasecmp ((gchar*)iter->name,
469
strlen (ACTION_MENU_ITEM)) == 0)
471
menu_item_ok = nautilus_actions_config_xml_action_fill_menu_item (action, iter);
475
//--> not used in old config files, so init to an empty string :
476
action->conf_section = g_strdup ("");
478
if (test_ok && command_ok && menu_item_ok)
484
// i18n notes: will be displayed in an error dialog
485
g_set_error (error, NAUTILUS_ACTIONS_XML_ERROR, NAUTILUS_ACTIONS_XML_ERROR_FAILED, _("This XML file is not a valid Nautilus-actions config file (Bad test section)"));
488
else if (!command_ok)
490
// i18n notes: will be displayed in an error dialog
491
g_set_error (error, NAUTILUS_ACTIONS_XML_ERROR, NAUTILUS_ACTIONS_XML_ERROR_FAILED, _("This XML file is not a valid Nautilus-actions config file (Bad command section)"));
493
else if (!menu_item_ok)
495
// i18n notes: will be displayed in an error dialog
496
g_set_error (error, NAUTILUS_ACTIONS_XML_ERROR, NAUTILUS_ACTIONS_XML_ERROR_FAILED, _("This XML file is not a valid Nautilus-actions config file (Bad menu item section)"));
503
nautilus_actions_config_xml_parse_file (NautilusActionsConfigXml* config, const gchar* filename, GError** error)
509
NautilusActionsConfigAction *action;
512
gboolean retv = FALSE;
513
gboolean no_error = TRUE;
514
xmlError* xml_error = NULL;
516
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
518
doc = xmlParseFile (filename);
521
root_node = xmlDocGetRootElement (doc);
522
if (g_ascii_strncasecmp ((gchar*)root_node->name,
524
strlen (ACTION_ROOT)) == 0)
526
version = xmlGetProp (root_node, BAD_CAST ACTION_VERSION);
528
iter = root_node->children;
529
while (iter && no_error)
531
xmlChar *config_name;
533
if (iter->type == XML_ELEMENT_NODE)
535
if (g_ascii_strncasecmp ((gchar*)iter->name,
537
strlen (ACTION_ACTION)) == 0)
539
config_name = xmlGetProp (iter, BAD_CAST ACTION_ACTION_NAME);
540
if (config_name != NULL)
542
action = nautilus_actions_config_action_new ();
543
action->version = (char*)xmlStrdup (version);
544
uuid_generate (uuid);
545
uuid_unparse (uuid, uuid_str);
546
action->uuid = g_strdup (uuid_str);
547
if (nautilus_actions_config_xml_action_fill (action, iter, error))
549
g_hash_table_insert (NAUTILUS_ACTIONS_CONFIG (config)->actions, g_strdup (action->uuid), action);
554
nautilus_actions_config_action_free (action);
557
xmlFree (config_name);
562
// i18n notes: will be displayed in an error dialog
563
g_set_error (error, NAUTILUS_ACTIONS_XML_ERROR, NAUTILUS_ACTIONS_XML_ERROR_FAILED, _("This XML file is not a valid Nautilus-actions config file (found <%s> element instead of <%s>)"), (gchar*)iter->name, ACTION_ACTION);
573
// i18n notes: will be displayed in an error dialog
574
g_set_error (error, NAUTILUS_ACTIONS_XML_ERROR, NAUTILUS_ACTIONS_XML_ERROR_FAILED, _("This XML file is not a valid Nautilus-actions config file (root node is <%s> instead of <%s>)"), (gchar*)iter->name, ACTION_ROOT);
582
xml_error = xmlGetLastError ();
583
g_set_error (error, NAUTILUS_ACTIONS_XML_ERROR, NAUTILUS_ACTIONS_XML_ERROR_FAILED, "%s", xml_error->message);
584
xmlResetError ((xmlErrorPtr)xml_error);
592
void nautilus_actions_config_xml_load_list (NautilusActionsConfigXml* config)
594
GList* config_files = NULL;
597
config_files = nautilus_actions_config_xml_get_config_files ();
599
for (iter = config_files; iter; iter = iter->next)
601
gchar* filename = (gchar*)iter->data;
602
nautilus_actions_config_xml_parse_file (config, filename, NULL);
605
nautilus_actions_config_xml_free_config_files (config_files);
609
nautilus_actions_config_xml_finalize (GObject *object)
611
NautilusActionsConfig *config = (NautilusActionsConfig *) object;
613
g_return_if_fail (NAUTILUS_ACTIONS_IS_CONFIG (config));
615
/* chain call to parent class */
616
if (parent_class->finalize)
618
parent_class->finalize (object);
623
nautilus_actions_config_xml_class_init (NautilusActionsConfigXmlClass *klass)
625
GObjectClass *object_class = G_OBJECT_CLASS (klass);
627
parent_class = g_type_class_peek_parent (klass);
629
object_class->finalize = nautilus_actions_config_xml_finalize;
631
NAUTILUS_ACTIONS_CONFIG_CLASS (klass)->save_action = save_action;
632
NAUTILUS_ACTIONS_CONFIG_CLASS (klass)->remove_action = remove_action;
636
nautilus_actions_config_xml_init (NautilusActionsConfig *config, NautilusActionsConfigClass *klass)
641
nautilus_actions_config_xml_get_type (void)
643
static GType type = 0;
646
static GTypeInfo info = {
647
sizeof (NautilusActionsConfigXmlClass),
648
(GBaseInitFunc) NULL,
649
(GBaseFinalizeFunc) NULL,
650
(GClassInitFunc) nautilus_actions_config_xml_class_init,
652
sizeof (NautilusActionsConfigXml),
654
(GInstanceInitFunc) nautilus_actions_config_xml_init
656
type = g_type_register_static (NAUTILUS_ACTIONS_TYPE_CONFIG, "NautilusActionsConfigXml", &info, 0);
661
NautilusActionsConfigXml *
662
nautilus_actions_config_xml_get (void)
664
static NautilusActionsConfigXml *config = NULL;
666
/* we share one NautilusActionsConfigXml object for all */
668
config = g_object_new (NAUTILUS_ACTIONS_TYPE_CONFIG_XML, NULL);
672
return NAUTILUS_ACTIONS_CONFIG_XML (g_object_ref (G_OBJECT (config)));
675
// vim:ts=3:sw=3:tw=1024:cin