1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
4 *
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009-2014 Pierre Wieser and others (see AUTHORS)
8 *
9 * Nautilus-Actions is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * Nautilus-Actions is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Nautilus-Actions; see the file COPYING. If not, see
21 * <http://www.gnu.org/licenses/>.
22 *
23 * Authors:
24 * Frederic Ruaudel <grumz@grumz.net>
25 * Rodrigo Moya <rodrigo@gnome-db.org>
26 * Pierre Wieser <pwieser@trychlos.org>
27 * ... and many others (see AUTHORS)
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 #include <string.h>
35
36 #include <api/na-data-def.h>
37 #include <api/na-data-types.h>
38 #include <api/na-ifactory-provider.h>
39 #include <api/na-iio-provider.h>
40 #include <api/na-object-api.h>
41 #include <api/na-core-utils.h>
42 #include <api/na-gconf-utils.h>
43
44 #include "nagp-gconf-provider.h"
45 #include "nagp-keys.h"
46 #include "nagp-reader.h"
47
48 typedef struct {
49 gchar *path;
50 GSList *entries;
51 NAObjectItem *parent;
52 }
53 ReaderData;
54
55 static NAObjectItem *read_item( NagpGConfProvider *provider, const gchar *path, GSList **messages );
56
57 static void read_start_profile_attach_profile( const NAIFactoryProvider *provider, NAObjectProfile *profile, ReaderData *data, GSList **messages );
58
59 static gboolean read_done_item_is_writable( const NAIFactoryProvider *provider, NAObjectItem *item, ReaderData *data, GSList **messages );
60 static void read_done_action_read_profiles( const NAIFactoryProvider *provider, NAObjectAction *action, ReaderData *data, GSList **messages );
61 static void read_done_action_load_profile( const NAIFactoryProvider *provider, ReaderData *data, const gchar *path, GSList **messages );
62
63 static NADataBoxed *get_boxed_from_path( const NagpGConfProvider *provider, const gchar *path, ReaderData *reader_data, const NADataDef *def );
64 static gboolean is_key_writable( NagpGConfProvider *gconf, const gchar *key );
65
66 /*
67 * nagp_iio_provider_read_items:
68 *
69 * Note that whatever be the version of the read action, it will be
70 * stored as a #NAObjectAction and its set of #NAObjectProfile of the same,
71 * latest, version of these classes.
72 */
73 GList *
nagp_iio_provider_read_items(const NAIIOProvider * provider,GSList ** messages)74 nagp_iio_provider_read_items( const NAIIOProvider *provider, GSList **messages )
75 {
76 static const gchar *thisfn = "nagp_reader_nagp_iio_provider_read_items";
77 NagpGConfProvider *self;
78 GList *items_list = NULL;
79 GSList *listpath, *ip;
80 NAObjectItem *item;
81
82 g_debug( "%s: provider=%p, messages=%p", thisfn, ( void * ) provider, ( void * ) messages );
83
84 g_return_val_if_fail( NA_IS_IIO_PROVIDER( provider ), NULL );
85 g_return_val_if_fail( NAGP_IS_GCONF_PROVIDER( provider ), NULL );
86 self = NAGP_GCONF_PROVIDER( provider );
87
88 if( !self->private->dispose_has_run ){
89
90 listpath = na_gconf_utils_get_subdirs( self->private->gconf, NAGP_CONFIGURATIONS_PATH );
91
92 for( ip = listpath ; ip ; ip = ip->next ){
93
94 item = read_item( self, ( const gchar * ) ip->data, messages );
95 if( item ){
96 items_list = g_list_prepend( items_list, item );
97 na_object_dump( item );
98 }
99 }
100
101 na_gconf_utils_free_subdirs( listpath );
102 }
103
104 g_debug( "%s: count=%d", thisfn, g_list_length( items_list ));
105 return( items_list );
106 }
107
108 /*
109 * path is here the full path to an item
110 */
111 static NAObjectItem *
read_item(NagpGConfProvider * provider,const gchar * path,GSList ** messages)112 read_item( NagpGConfProvider *provider, const gchar *path, GSList **messages )
113 {
114 static const gchar *thisfn = "nagp_reader_read_item";
115 NAObjectItem *item;
116 gchar *full_path;
117 gchar *type;
118 gchar *id;
119 ReaderData *data;
120
121 g_debug( "%s: provider=%p, path=%s", thisfn, ( void * ) provider, path );
122 g_return_val_if_fail( NAGP_IS_GCONF_PROVIDER( provider ), NULL );
123 g_return_val_if_fail( NA_IS_IIO_PROVIDER( provider ), NULL );
124 g_return_val_if_fail( !provider->private->dispose_has_run, NULL );
125
126 full_path = gconf_concat_dir_and_key( path, NAGP_ENTRY_TYPE );
127 type = na_gconf_utils_read_string( provider->private->gconf, full_path, TRUE, NAGP_VALUE_TYPE_ACTION );
128 g_free( full_path );
129 item = NULL;
130
131 /* an item may have 'Action' or 'Menu' type; defaults to Action
132 */
133 if( !type || !strlen( type ) || !strcmp( type, NAGP_VALUE_TYPE_ACTION )){
134 item = NA_OBJECT_ITEM( na_object_action_new());
135
136 } else if( !strcmp( type, NAGP_VALUE_TYPE_MENU )){
137 item = NA_OBJECT_ITEM( na_object_menu_new());
138
139 } else {
140 g_warning( "%s: unknown type '%s' at %s", thisfn, type, path );
141 }
142
143 g_free( type );
144
145 if( item ){
146 id = g_path_get_basename( path );
147 na_object_set_id( item, id );
148 g_free( id );
149
150 data = g_new0( ReaderData, 1 );
151 data->path = ( gchar * ) path;
152 data->entries = na_gconf_utils_get_entries( provider->private->gconf, path );
153 na_gconf_utils_dump_entries( data->entries );
154
155 na_ifactory_provider_read_item(
156 NA_IFACTORY_PROVIDER( provider ),
157 data,
158 NA_IFACTORY_OBJECT( item ),
159 messages );
160
161 na_gconf_utils_free_entries( data->entries );
162 g_free( data );
163 }
164
165 return( item );
166 }
167
168 void
nagp_reader_read_start(const NAIFactoryProvider * provider,void * reader_data,const NAIFactoryObject * object,GSList ** messages)169 nagp_reader_read_start( const NAIFactoryProvider *provider, void *reader_data, const NAIFactoryObject *object, GSList **messages )
170 {
171 static const gchar *thisfn = "nagp_reader_read_start";
172
173 g_return_if_fail( NA_IS_IFACTORY_PROVIDER( provider ));
174 g_return_if_fail( NAGP_IS_GCONF_PROVIDER( provider ));
175 g_return_if_fail( NA_IS_IFACTORY_OBJECT( object ));
176
177 if( !NAGP_GCONF_PROVIDER( provider )->private->dispose_has_run ){
178
179 g_debug( "%s: provider=%p (%s), reader_data=%p, object=%p (%s), messages=%p",
180 thisfn,
181 ( void * ) provider, G_OBJECT_TYPE_NAME( provider ),
182 ( void * ) reader_data,
183 ( void * ) object, G_OBJECT_TYPE_NAME( object ),
184 ( void * ) messages );
185
186 if( NA_IS_OBJECT_PROFILE( object )){
187 read_start_profile_attach_profile( provider, NA_OBJECT_PROFILE( object ), ( ReaderData * ) reader_data, messages );
188 }
189 }
190 }
191
192 static void
read_start_profile_attach_profile(const NAIFactoryProvider * provider,NAObjectProfile * profile,ReaderData * data,GSList ** messages)193 read_start_profile_attach_profile( const NAIFactoryProvider *provider, NAObjectProfile *profile, ReaderData *data, GSList **messages )
194 {
195 na_object_attach_profile( data->parent, profile );
196 }
197
198 NADataBoxed *
nagp_reader_read_data(const NAIFactoryProvider * provider,void * reader_data,const NAIFactoryObject * object,const NADataDef * def,GSList ** messages)199 nagp_reader_read_data( const NAIFactoryProvider *provider, void *reader_data, const NAIFactoryObject *object, const NADataDef *def, GSList **messages )
200 {
201 static const gchar *thisfn = "nagp_reader_read_data";
202 NADataBoxed *boxed;
203
204 g_return_val_if_fail( NA_IS_IFACTORY_PROVIDER( provider ), NULL );
205 g_return_val_if_fail( NA_IS_IFACTORY_OBJECT( object ), NULL );
206
207 /*g_debug( "%s: reader_data=%p, object=%p (%s), data=%s",
208 thisfn,
209 ( void * ) reader_data,
210 ( void * ) object, G_OBJECT_TYPE_NAME( object ),
211 def->name );*/
212
213 if( !def->gconf_entry || !strlen( def->gconf_entry )){
214 g_warning( "%s: GConf entry is not set for NADataDef %s", thisfn, def->name );
215 return( NULL );
216 }
217
218 boxed = get_boxed_from_path(
219 NAGP_GCONF_PROVIDER( provider ), (( ReaderData * ) reader_data )->path, reader_data, def );
220
221 return( boxed );
222 }
223
224 void
nagp_reader_read_done(const NAIFactoryProvider * provider,void * reader_data,const NAIFactoryObject * object,GSList ** messages)225 nagp_reader_read_done( const NAIFactoryProvider *provider, void *reader_data, const NAIFactoryObject *object, GSList **messages )
226 {
227 static const gchar *thisfn = "nagp_reader_read_done";
228 gboolean writable;
229
230 g_return_if_fail( NA_IS_IFACTORY_PROVIDER( provider ));
231 g_return_if_fail( NAGP_IS_GCONF_PROVIDER( provider ));
232 g_return_if_fail( NA_IS_IFACTORY_OBJECT( object ));
233
234 if( !NAGP_GCONF_PROVIDER( provider )->private->dispose_has_run ){
235
236 g_debug( "%s: provider=%p (%s), reader_data=%p, object=%p (%s), messages=%p",
237 thisfn,
238 ( void * ) provider, G_OBJECT_TYPE_NAME( provider ),
239 ( void * ) reader_data,
240 ( void * ) object, G_OBJECT_TYPE_NAME( object ),
241 ( void * ) messages );
242
243 if( NA_IS_OBJECT_ITEM( object )){
244 writable = read_done_item_is_writable( provider, NA_OBJECT_ITEM( object ), ( ReaderData * ) reader_data, messages );
245 na_object_set_readonly( object, !writable );
246 }
247
248 if( NA_IS_OBJECT_ACTION( object )){
249 read_done_action_read_profiles( provider, NA_OBJECT_ACTION( object ), ( ReaderData * ) reader_data, messages );
250 }
251
252 g_debug( "%s: quitting for %s at %p", thisfn, G_OBJECT_TYPE_NAME( object ), ( void * ) object );
253 }
254 }
255
256 static gboolean
read_done_item_is_writable(const NAIFactoryProvider * provider,NAObjectItem * item,ReaderData * data,GSList ** messages)257 read_done_item_is_writable( const NAIFactoryProvider *provider, NAObjectItem *item, ReaderData *data, GSList **messages )
258 {
259 GSList *ie;
260 gboolean writable;
261 GConfEntry *gconf_entry;
262 const gchar *key;
263
264 /* check for writability of this item
265 * item is writable if and only if all entries are themselves writable
266 */
267 writable = TRUE;
268 for( ie = data->entries ; ie && writable ; ie = ie->next ){
269 gconf_entry = ( GConfEntry * ) ie->data;
270 key = gconf_entry_get_key( gconf_entry );
271 writable = is_key_writable( NAGP_GCONF_PROVIDER( provider ), key );
272 }
273
274 g_debug( "nagp_reader_read_done_item: writable=%s", writable ? "True":"False" );
275 return( writable );
276 }
277
278 static void
read_done_action_read_profiles(const NAIFactoryProvider * provider,NAObjectAction * action,ReaderData * data,GSList ** messages)279 read_done_action_read_profiles( const NAIFactoryProvider *provider, NAObjectAction *action, ReaderData *data, GSList **messages )
280 {
281 static const gchar *thisfn = "nagp_reader_read_done_action_read_profiles";
282 GSList *order;
283 GSList *list_profiles;
284 GSList *ip;
285 gchar *profile_id;
286 gchar *profile_path;
287 NAObjectId *found;
288 NAObjectProfile *profile;
289
290 data->parent = NA_OBJECT_ITEM( action );
291 order = na_object_get_items_slist( action );
292 list_profiles = na_gconf_utils_get_subdirs( NAGP_GCONF_PROVIDER( provider )->private->gconf, data->path );
293
294 /* read profiles in the specified order
295 * as a protection against bugs in NACT, we check that profile has not
296 * already been loaded
297 */
298 for( ip = order ; ip ; ip = ip->next ){
299 profile_id = ( gchar * ) ip->data;
300 found = na_object_get_item( action, profile_id );
301 if( !found ){
302 g_debug( "nagp_reader_read_done_action: loading profile=%s", profile_id );
303 profile_path = gconf_concat_dir_and_key( data->path, profile_id );
304 read_done_action_load_profile( provider, data, profile_path, messages );
305 g_free( profile_path );
306 }
307 }
308
309 /* append other profiles
310 * this is mandatory for pre-2.29 actions which introduced order of profiles
311 */
312 for( ip = list_profiles ; ip ; ip = ip->next ){
313 profile_id = g_path_get_basename(( const gchar * ) ip->data );
314 found = na_object_get_item( action, profile_id );
315 if( !found ){
316 g_debug( "nagp_reader_read_done_action: loading profile=%s", profile_id );
317 read_done_action_load_profile( provider, data, ( const gchar * ) ip->data, messages );
318 }
319 g_free( profile_id );
320 }
321
322 /* make sure we have at least one profile
323 */
324 if( !na_object_get_items_count( action )){
325 g_warning( "%s: no profile found in GConf backend", thisfn );
326 profile = na_object_profile_new_with_defaults();
327 na_object_attach_profile( action, profile );
328 }
329 }
330
331 static void
read_done_action_load_profile(const NAIFactoryProvider * provider,ReaderData * data,const gchar * path,GSList ** messages)332 read_done_action_load_profile( const NAIFactoryProvider *provider, ReaderData *data, const gchar *path, GSList **messages )
333 {
334 gchar *id;
335 ReaderData *profile_data;
336
337 NAObjectProfile *profile = na_object_profile_new();
338
339 id = g_path_get_basename( path );
340 na_object_set_id( profile, id );
341 g_free( id );
342
343 profile_data = g_new0( ReaderData, 1 );
344 profile_data->parent = data->parent;
345 profile_data->path = ( gchar * ) path;
346 profile_data->entries = na_gconf_utils_get_entries( NAGP_GCONF_PROVIDER( provider )->private->gconf, path );
347
348 na_ifactory_provider_read_item(
349 NA_IFACTORY_PROVIDER( provider ),
350 profile_data,
351 NA_IFACTORY_OBJECT( profile ),
352 messages );
353
354 na_gconf_utils_free_entries( profile_data->entries );
355 g_free( profile_data );
356 }
357
358 static NADataBoxed *
get_boxed_from_path(const NagpGConfProvider * provider,const gchar * path,ReaderData * reader_data,const NADataDef * def)359 get_boxed_from_path( const NagpGConfProvider *provider, const gchar *path, ReaderData *reader_data, const NADataDef *def )
360 {
361 static const gchar *thisfn = "nagp_reader_get_boxed_from_path";
362 NADataBoxed *boxed;
363 gboolean have_entry;
364 gchar *str_value;
365 gboolean bool_value;
366 GSList *slist_value;
367 gint int_value;
368
369 boxed = NULL;
370 have_entry = na_gconf_utils_has_entry( reader_data->entries, def->gconf_entry );
371 g_debug( "%s: entry=%s, have_entry=%s", thisfn, def->gconf_entry, have_entry ? "True":"False" );
372
373 if( have_entry ){
374 gchar *entry_path = gconf_concat_dir_and_key( path, def->gconf_entry );
375 boxed = na_data_boxed_new( def );
376
377 switch( def->type ){
378
379 case NA_DATA_TYPE_STRING:
380 case NA_DATA_TYPE_LOCALE_STRING:
381 str_value = na_gconf_utils_read_string( provider->private->gconf, entry_path, TRUE, NULL );
382 na_boxed_set_from_string( NA_BOXED( boxed ), str_value );
383 g_free( str_value );
384 break;
385
386 case NA_DATA_TYPE_BOOLEAN:
387 bool_value = na_gconf_utils_read_bool( provider->private->gconf, entry_path, TRUE, FALSE );
388 na_boxed_set_from_void( NA_BOXED( boxed ), GUINT_TO_POINTER( bool_value ));
389 break;
390
391 case NA_DATA_TYPE_STRING_LIST:
392 slist_value = na_gconf_utils_read_string_list( provider->private->gconf, entry_path );
393 na_boxed_set_from_void( NA_BOXED( boxed ), slist_value );
394 na_core_utils_slist_free( slist_value );
395 break;
396
397 case NA_DATA_TYPE_UINT:
398 int_value = na_gconf_utils_read_int( provider->private->gconf, entry_path, TRUE, 0 );
399 na_boxed_set_from_void( NA_BOXED( boxed ), GUINT_TO_POINTER( int_value ));
400 break;
401
402 default:
403 g_warning( "%s: unknown type=%u for %s", thisfn, def->type, def->name );
404 g_free( boxed );
405 boxed = NULL;
406 }
407
408 g_free( entry_path );
409 }
410
411 return( boxed );
412 }
413
414 /*
415 * key must be an existing entry (not a dir) to get a relevant return
416 * value ; else we get FALSE
417 */
418 static gboolean
is_key_writable(NagpGConfProvider * gconf,const gchar * key)419 is_key_writable( NagpGConfProvider *gconf, const gchar *key )
420 {
421 static const gchar *thisfn = "nagp_read_is_key_writable";
422 GError *error = NULL;
423 gboolean is_writable;
424
425 is_writable = gconf_client_key_is_writable( gconf->private->gconf, key, &error );
426 if( error ){
427 g_warning( "%s: gconf_client_key_is_writable: %s", thisfn, error->message );
428 g_error_free( error );
429 error = NULL;
430 is_writable = FALSE;
431 }
432
433 return( is_writable );
434 }
435