1 /*
2  *  caja-extension.c - extension management functions
3  *
4  *  Copyright (C) 2012-2021 The MATE developers
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public
17  *  License along with this library; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  *  Author: Alexander van der Meij <alexandervdm@gliese.me>
22  */
23 
24 #include "caja-extensions.h"
25 
26 #include "caja-global-preferences.h"
27 #include "caja-module.h"
28 #include "caja-debug-log.h"
29 
30 #include <string.h>
31 
32 #define CAJA_EXTENSION_GROUP "Caja Extension"
33 
34 static GList *caja_extensions = NULL;
35 
36 
37 static Extension *
extension_new(gchar * filename,gboolean state,gboolean python,GObject * module)38 extension_new (gchar *filename, gboolean state, gboolean python, GObject *module)
39 {
40     GError *error = NULL;
41     Extension *ext;
42     GKeyFile *extension_file;
43     gchar *extension_filename;
44 
45     ext = g_new0 (Extension, 1);
46     ext->filename = filename;
47     ext->name = NULL;
48     ext->description = NULL;
49     ext->author = NULL;
50     ext->copyright = NULL;
51     ext->version = NULL;
52     ext->website = NULL;
53     ext->state = state;
54     ext->module = module;
55 
56     extension_file = g_key_file_new ();
57     extension_filename = g_strdup_printf(CAJA_DATADIR "/extensions/%s.caja-extension", filename);
58     if (g_key_file_load_from_file (extension_file, extension_filename, G_KEY_FILE_NONE, &error))
59     {
60         ext->name = g_key_file_get_locale_string (extension_file, CAJA_EXTENSION_GROUP, "Name", NULL, NULL);
61         ext->description = g_key_file_get_locale_string (extension_file, CAJA_EXTENSION_GROUP, "Description", NULL, NULL);
62         ext->icon = g_key_file_get_string (extension_file, CAJA_EXTENSION_GROUP, "Icon", NULL);
63         ext->author = g_key_file_get_string_list (extension_file, CAJA_EXTENSION_GROUP, "Author", NULL, NULL);
64         ext->copyright = g_key_file_get_locale_string (extension_file, CAJA_EXTENSION_GROUP, "Copyright", NULL, NULL);
65         ext->version = g_key_file_get_string (extension_file, CAJA_EXTENSION_GROUP, "Version", NULL);
66         ext->website = g_key_file_get_string (extension_file, CAJA_EXTENSION_GROUP, "Website", NULL);
67         g_key_file_free (extension_file);
68     }
69     else
70     {
71         caja_debug_log (FALSE, CAJA_DEBUG_LOG_DOMAIN_USER, "Error loading keys from file: %s\n", error->message);
72         g_error_free (error);
73     }
74     g_free (extension_filename);
75 
76     if (python)
77     {
78         ext->name = g_strconcat("Python: ", filename, NULL);
79         ext->description = "Python-caja extension";
80     }
81 
82     return ext;
83 }
84 
85 /* functions related to persistent configuration through gsettings: */
86 
87 static gboolean
gsettings_key_has_value(const gchar * value)88 gsettings_key_has_value (const gchar *value)
89 {
90     gchar **list;
91     gint i;
92 
93     list = g_settings_get_strv (caja_extension_preferences,
94                                 CAJA_PREFERENCES_DISABLED_EXTENSIONS);
95 
96     if (list != NULL)
97     {
98         for (i = 0; list[i]; i++)
99         {
100             if (g_ascii_strcasecmp (value, list[i]) == 0)
101             {
102                 g_strfreev (list);
103                 return TRUE;
104             }
105         }
106     }
107     g_strfreev (list);
108     return FALSE;
109 }
110 
111 static gboolean
gsettings_append_to_list(const char * value)112 gsettings_append_to_list (const char *value)
113 {
114     gchar **current;
115     gchar **new;
116     gint size;
117     gboolean retval;
118 
119     current = g_settings_get_strv (caja_extension_preferences,
120                                    CAJA_PREFERENCES_DISABLED_EXTENSIONS);
121 
122     for (size = 0; current[size] != NULL; size++);
123 
124     size += 1;
125     size += 1;
126 
127     new = g_realloc_n (current, size, sizeof (gchar *));
128 
129     new[size - 2] = g_strdup (value);
130     new[size - 1] = NULL;
131 
132     retval = g_settings_set_strv (caja_extension_preferences,
133                                   CAJA_PREFERENCES_DISABLED_EXTENSIONS,
134                                  (const gchar **) new);
135 
136     g_strfreev (new);
137     return retval;
138 }
139 
140 static gboolean
gsettings_remove_from_list(const char * value)141 gsettings_remove_from_list (const char *value)
142 {
143     gchar **current;
144     GArray *array;
145     gint i;
146     gboolean retval;
147 
148     current = g_settings_get_strv (caja_extension_preferences,
149                                    CAJA_PREFERENCES_DISABLED_EXTENSIONS);
150 
151     array = g_array_new (TRUE, TRUE, sizeof (gchar *));
152 
153     for (i = 0; current[i] != NULL; i++)
154     {
155         if (g_strcmp0 (current[i], value) != 0)
156             array = g_array_append_val (array, current[i]);
157     }
158 
159     retval = g_settings_set_strv (caja_extension_preferences,
160                                   CAJA_PREFERENCES_DISABLED_EXTENSIONS,
161                                  (const gchar **) array->data);
162 
163     g_strfreev (current);
164     g_array_free (array, TRUE);
165     return retval;
166 }
167 
168 /* functions related to the extension management */
169 
170 static gboolean
caja_extension_get_state(const gchar * extname)171 caja_extension_get_state (const gchar *extname)
172 {
173     return !gsettings_key_has_value (extname);
174 }
175 
176 GList *
caja_extensions_get_for_type(GType type)177 caja_extensions_get_for_type (GType type)
178 {
179     GList *l;
180     GList *ret = NULL;
181 
182     for (l = caja_extensions; l != NULL; l = l->next)
183     {
184         Extension *ext = l->data;
185         ext->state = caja_extension_get_state (ext->filename);
186         if (ext->state) // only load enabled extensions
187         {
188             if (G_TYPE_CHECK_INSTANCE_TYPE (G_OBJECT (ext->module), type))
189             {
190                 g_object_ref (ext->module);
191                 ret = g_list_prepend (ret, ext->module);
192             }
193         }
194     }
195 
196     return ret;
197 }
198 
199 GList *
caja_extensions_get_list(void)200 caja_extensions_get_list (void)
201 {
202     return caja_extensions;
203 }
204 
205 void
caja_extension_register(gchar * filename,GObject * module)206 caja_extension_register (gchar *filename, GObject *module)
207 {
208     gboolean ext_state = TRUE; // new extensions are enabled by default.
209     gboolean ext_python = FALSE;
210     gchar *ext_filename;
211 
212     ext_filename = g_strndup (filename, strlen(filename) - 3);
213     ext_state = caja_extension_get_state (ext_filename);
214 
215     if (g_str_has_suffix (filename, ".py")) {
216         ext_python = TRUE;
217     }
218 
219     Extension *ext = extension_new (ext_filename, ext_state, ext_python, module);
220     caja_extensions = g_list_append (caja_extensions, ext);
221 }
222 
223 gboolean
caja_extension_set_state(Extension * ext,gboolean new_state)224 caja_extension_set_state (Extension *ext, gboolean new_state)
225 {
226     if (ext)
227     {
228         g_return_val_if_fail (ext->state != new_state, FALSE);
229         ext->state = new_state;
230     }
231 
232     gboolean retval;
233     if (new_state) {
234         retval = gsettings_remove_from_list (ext->filename);
235     }
236     else {
237         retval = gsettings_append_to_list (ext->filename);
238     }
239 
240     g_return_val_if_fail (retval == TRUE, FALSE);
241     return TRUE;
242 }
243 
244