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 <glib/gi18n.h>
35 #include <string.h>
36 
37 #include "na-gnome-vfs-uri.h"
38 #include "na-selected-info.h"
39 
40 /* private class data
41  */
42 struct _NASelectedInfoClassPrivate {
43 	void *empty;						/* so that gcc -pedantic is happy */
44 };
45 
46 /* private instance data
47  */
48 struct _NASelectedInfoPrivate {
49 	gboolean       dispose_has_run;
50 	gchar         *uri;
51 	gchar         *filename;
52 	gchar         *dirname;
53 	gchar         *basename;
54 	gchar         *hostname;
55 	gchar         *username;
56 	gchar         *scheme;
57 	guint          port;
58 	gchar         *mimetype;
59 	GFileType      file_type;
60 	gboolean       can_read;
61 	gboolean       can_write;
62 	gboolean       can_execute;
63 	gchar         *owner;
64 	gboolean       attributes_are_set;
65 };
66 
67 
68 static GObjectClass *st_parent_class = NULL;
69 
70 static GType           register_type( void );
71 static void            class_init( NASelectedInfoClass *klass );
72 static void            instance_init( GTypeInstance *instance, gpointer klass );
73 static void            instance_dispose( GObject *object );
74 static void            instance_finalize( GObject *object );
75 
76 static void            dump( const NASelectedInfo *nsi );
77 static const char     *dump_file_type( GFileType type );
78 static NASelectedInfo *new_from_nautilus_file_info( NautilusFileInfo *item );
79 static NASelectedInfo *new_from_uri( const gchar *uri, const gchar *mimetype, gchar **errmsg );
80 static void            query_file_attributes( NASelectedInfo *info, GFile *location, gchar **errmsg );
81 
82 GType
na_selected_info_get_type(void)83 na_selected_info_get_type( void )
84 {
85 	static GType object_type = 0;
86 
87 	if( !object_type ){
88 		object_type = register_type();
89 	}
90 
91 	return( object_type );
92 }
93 
94 static GType
register_type(void)95 register_type( void )
96 {
97 	static const gchar *thisfn = "na_selected_info_register_type";
98 	GType type;
99 
100 	static GTypeInfo info = {
101 		sizeof( NASelectedInfoClass ),
102 		( GBaseInitFunc ) NULL,
103 		( GBaseFinalizeFunc ) NULL,
104 		( GClassInitFunc ) class_init,
105 		NULL,
106 		NULL,
107 		sizeof( NASelectedInfo ),
108 		0,
109 		( GInstanceInitFunc ) instance_init
110 	};
111 
112 	g_debug( "%s", thisfn );
113 
114 	type = g_type_register_static( G_TYPE_OBJECT, "NASelectedInfo", &info, 0 );
115 
116 	return( type );
117 }
118 
119 static void
class_init(NASelectedInfoClass * klass)120 class_init( NASelectedInfoClass *klass )
121 {
122 	static const gchar *thisfn = "na_selected_info_class_init";
123 	GObjectClass *object_class;
124 
125 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
126 
127 	st_parent_class = g_type_class_peek_parent( klass );
128 
129 	object_class = G_OBJECT_CLASS( klass );
130 	object_class->dispose = instance_dispose;
131 	object_class->finalize = instance_finalize;
132 
133 	klass->private = g_new0( NASelectedInfoClassPrivate, 1 );
134 }
135 
136 static void
instance_init(GTypeInstance * instance,gpointer klass)137 instance_init( GTypeInstance *instance, gpointer klass )
138 {
139 	static const gchar *thisfn = "na_selected_info_instance_init";
140 	NASelectedInfo *self;
141 
142 	g_return_if_fail( NA_IS_SELECTED_INFO( instance ));
143 
144 	g_debug( "%s: instance=%p (%s), klass=%p",
145 			thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
146 
147 	self = NA_SELECTED_INFO( instance );
148 
149 	self->private = g_new0( NASelectedInfoPrivate, 1 );
150 
151 	self->private->dispose_has_run = FALSE;
152 	self->private->uri = NULL;
153 }
154 
155 static void
instance_dispose(GObject * object)156 instance_dispose( GObject *object )
157 {
158 	static const gchar *thisfn = "na_selected_info_instance_dispose";
159 	NASelectedInfo *self;
160 
161 	g_return_if_fail( NA_IS_SELECTED_INFO( object ));
162 	self = NA_SELECTED_INFO( object );
163 
164 	if( !self->private->dispose_has_run ){
165 		g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
166 
167 		self->private->dispose_has_run = TRUE;
168 
169 		/* chain up to the parent class */
170 		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
171 			G_OBJECT_CLASS( st_parent_class )->dispose( object );
172 		}
173 	}
174 }
175 
176 static void
instance_finalize(GObject * object)177 instance_finalize( GObject *object )
178 {
179 	static const gchar *thisfn = "na_selected_info_instance_finalize";
180 	NASelectedInfo *self;
181 
182 	g_return_if_fail( NA_IS_SELECTED_INFO( object ));
183 
184 	self = NA_SELECTED_INFO( object );
185 
186 	g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
187 
188 	g_free( self->private->uri );
189 	g_free( self->private->filename );
190 	g_free( self->private->dirname );
191 	g_free( self->private->basename );
192 	g_free( self->private->hostname );
193 	g_free( self->private->username );
194 	g_free( self->private->scheme );
195 	g_free( self->private->mimetype );
196 	g_free( self->private->owner );
197 
198 	g_free( self->private );
199 
200 	/* chain call to parent class */
201 	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
202 		G_OBJECT_CLASS( st_parent_class )->finalize( object );
203 	}
204 }
205 
206 /*
207  * na_selected_info_get_list_from_item:
208  * @item: a #NautilusFileInfo item
209  *
210  * Returns: a #GList list which contains a #NASelectedInfo item with the
211  * same URI that the @item.
212  */
213 GList *
na_selected_info_get_list_from_item(NautilusFileInfo * item)214 na_selected_info_get_list_from_item( NautilusFileInfo *item )
215 {
216 	GList *selected;
217 
218 	selected = NULL;
219 	NASelectedInfo *info = new_from_nautilus_file_info( item );
220 
221 	if( info ){
222 		selected = g_list_prepend( NULL, info );
223 	}
224 
225 	return( selected );
226 }
227 
228 /*
229  * na_selected_info_get_list_from_list:
230  * @nautilus_selection: a #GList list of #NautilusFileInfo items.
231  *
232  * Returns: a #GList list of #NASelectedInfo items whose URI correspond
233  * to those of @nautilus_selection.
234  */
235 GList *
na_selected_info_get_list_from_list(GList * nautilus_selection)236 na_selected_info_get_list_from_list( GList *nautilus_selection )
237 {
238 	GList *selected;
239 	GList *it;
240 
241 	selected = NULL;
242 
243 	for( it = nautilus_selection ; it ; it = it->next ){
244 		NASelectedInfo *info = new_from_nautilus_file_info( NAUTILUS_FILE_INFO( it->data ));
245 
246 		if( info ){
247 			selected = g_list_prepend( selected, info );
248 		}
249 	}
250 
251 	return( selected ? g_list_reverse( selected ) : NULL );
252 }
253 
254 /*
255  * na_selected_info_copy_list:
256  * @files: a #GList list of #NASelectedInfo items.
257  *
258  * Returns: a copy of the provided @files list.
259  */
260 GList *
na_selected_info_copy_list(GList * files)261 na_selected_info_copy_list( GList *files )
262 {
263 	GList *copy;
264 	GList *l;
265 
266 	copy = g_list_copy( files );
267 
268 	for( l = copy ; l != NULL ; l = l->next ){
269 		g_object_ref( G_OBJECT( l->data ));
270 	}
271 
272 	return( copy );
273 }
274 
275 /*
276  * na_selected_info_free_list:
277  * @files: a #GList of #NASelectedInfo items.
278  *
279  * Frees up the #GList @files.
280  */
281 void
na_selected_info_free_list(GList * files)282 na_selected_info_free_list( GList *files )
283 {
284 	g_list_foreach( files, ( GFunc ) g_object_unref, NULL );
285 	g_list_free( files );
286 }
287 
288 /*
289  * na_selected_info_get_basename:
290  * @nsi: this #NASelectedInfo object.
291  *
292  * Returns: the basename of the file associated with this
293  * #NASelectedInfo object, as a newly allocated string which
294  * must be g_free() by the caller.
295  */
296 gchar *
na_selected_info_get_basename(const NASelectedInfo * nsi)297 na_selected_info_get_basename( const NASelectedInfo *nsi )
298 {
299 	gchar *basename;
300 
301 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), NULL );
302 
303 	basename = NULL;
304 
305 	if( !nsi->private->dispose_has_run ){
306 
307 		basename = g_strdup( nsi->private->basename );
308 	}
309 
310 	return( basename );
311 }
312 
313 /*
314  * na_selected_info_get_dirname:
315  * @nsi: this #NASelectedInfo object.
316  *
317  * Returns: the dirname of the file associated with this
318  * #NASelectedInfo object, as a newly allocated string which
319  * must be g_free() by the caller.
320  */
321 gchar *
na_selected_info_get_dirname(const NASelectedInfo * nsi)322 na_selected_info_get_dirname( const NASelectedInfo *nsi )
323 {
324 	gchar *dirname;
325 
326 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), NULL );
327 
328 	dirname = NULL;
329 
330 	if( !nsi->private->dispose_has_run ){
331 
332 		dirname = g_strdup( nsi->private->dirname );
333 	}
334 
335 	return( dirname );
336 }
337 
338 /*
339  * na_selected_info_get_mime_type:
340  * @nsi: this #NASelectedInfo object.
341  *
342  * Returns: the mime type associated with this #NASelectedInfo object,
343  * as a newly allocated string which should be g_free() by the caller.
344  */
345 gchar *
na_selected_info_get_mime_type(const NASelectedInfo * nsi)346 na_selected_info_get_mime_type( const NASelectedInfo *nsi )
347 {
348 	gchar *mimetype;
349 
350 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), NULL );
351 
352 	mimetype = NULL;
353 
354 	if( !nsi->private->dispose_has_run ){
355 
356 		if( nsi->private->mimetype ){
357 			mimetype = g_strdup( nsi->private->mimetype );
358 		}
359 	}
360 
361 	return( mimetype );
362 }
363 
364 /*
365  * na_selected_info_get_path:
366  * @nsi: this #NASelectedInfo object.
367  *
368  * Returns: the filename of the item as a newly allocated string which
369  * should be g_free() by the caller.
370  */
371 gchar *
na_selected_info_get_path(const NASelectedInfo * nsi)372 na_selected_info_get_path( const NASelectedInfo *nsi )
373 {
374 	gchar *path;
375 
376 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), NULL );
377 
378 	path = NULL;
379 
380 	if( !nsi->private->dispose_has_run ){
381 
382 		path = g_strdup( nsi->private->filename );
383 	}
384 
385 	return( path );
386 }
387 
388 /*
389  * na_selected_info_get_uri:
390  * @nsi: this #NASelectedInfo object.
391  *
392  * Returns: the URI associated with this #NASelectedInfo object, as a
393  * newly allocated string which should be g_free() by the caller.
394  */
395 gchar *
na_selected_info_get_uri(const NASelectedInfo * nsi)396 na_selected_info_get_uri( const NASelectedInfo *nsi )
397 {
398 	gchar *uri;
399 
400 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), NULL );
401 
402 	uri = NULL;
403 
404 	if( !nsi->private->dispose_has_run ){
405 
406 		uri = g_strdup( nsi->private->uri );
407 	}
408 
409 	return( uri );
410 }
411 
412 /*
413  * na_selected_info_get_uri_host:
414  * @nsi: this #NASelectedInfo object.
415  *
416  * Returns: the host associated to this @nsi object, as a
417  * newly allocated string which should be g_free() by the caller.
418  */
419 gchar *
na_selected_info_get_uri_host(const NASelectedInfo * nsi)420 na_selected_info_get_uri_host( const NASelectedInfo *nsi )
421 {
422 	gchar *host;
423 
424 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), NULL );
425 
426 	host = NULL;
427 
428 	if( !nsi->private->dispose_has_run ){
429 
430 		host = g_strdup( nsi->private->hostname );
431 	}
432 
433 	return( host );
434 }
435 
436 /*
437  * na_selected_info_get_uri_user:
438  * @nsi: this #NASelectedInfo object.
439  *
440  * Returns: the user associated to this @nsi object, as a
441  * newly allocated string which should be g_free() by the caller.
442  */
443 gchar *
na_selected_info_get_uri_user(const NASelectedInfo * nsi)444 na_selected_info_get_uri_user( const NASelectedInfo *nsi )
445 {
446 	gchar *user;
447 
448 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), NULL );
449 
450 	user = NULL;
451 
452 	if( !nsi->private->dispose_has_run ){
453 
454 		user = g_strdup( nsi->private->username );
455 	}
456 
457 	return( user );
458 }
459 
460 /*
461  * na_selected_info_get_uri_port:
462  * @nsi: this #NASelectedInfo object.
463  *
464  * Returns: the port associated to this @nsi object.
465  */
466 guint
na_selected_info_get_uri_port(const NASelectedInfo * nsi)467 na_selected_info_get_uri_port( const NASelectedInfo *nsi )
468 {
469 	guint port;
470 
471 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), 0 );
472 
473 	port = 0;
474 
475 	if( !nsi->private->dispose_has_run ){
476 
477 		port = nsi->private->port;
478 	}
479 
480 	return( port );
481 }
482 
483 /*
484  * na_selected_info_get_uri_scheme:
485  * @nsi: this #NASelectedInfo object.
486  *
487  * Returns: the scheme associated to this @nsi object, as a
488  * newly allocated string which should be g_free() by the caller.
489  */
490 gchar *
na_selected_info_get_uri_scheme(const NASelectedInfo * nsi)491 na_selected_info_get_uri_scheme( const NASelectedInfo *nsi )
492 {
493 	gchar *scheme;
494 
495 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), NULL );
496 
497 	scheme = NULL;
498 
499 	if( !nsi->private->dispose_has_run ){
500 
501 		scheme = g_strdup( nsi->private->scheme );
502 	}
503 
504 	return( scheme );
505 }
506 
507 /*
508  * na_selected_info_is_directory:
509  * @nsi: this #NASelectedInfo object.
510  *
511  * Returns: %TRUE if the item is a directory, %FALSE else.
512  */
513 gboolean
na_selected_info_is_directory(const NASelectedInfo * nsi)514 na_selected_info_is_directory( const NASelectedInfo *nsi )
515 {
516 	gboolean is_dir;
517 
518 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), FALSE );
519 
520 	is_dir = FALSE;
521 
522 	if( !nsi->private->dispose_has_run ){
523 
524 		is_dir = ( nsi->private->file_type == G_FILE_TYPE_DIRECTORY );
525 	}
526 
527 	return( is_dir );
528 }
529 
530 /*
531  * na_selected_info_is_regular:
532  * @nsi: this #NASelectedInfo object.
533  *
534  * Returns: %TRUE if the item is a regular file, %FALSE else.
535  */
536 gboolean
na_selected_info_is_regular(const NASelectedInfo * nsi)537 na_selected_info_is_regular( const NASelectedInfo *nsi )
538 {
539 	gboolean is_regular;
540 
541 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), FALSE );
542 
543 	is_regular = FALSE;
544 
545 	if( !nsi->private->dispose_has_run ){
546 
547 		is_regular = ( nsi->private->file_type == G_FILE_TYPE_REGULAR );
548 	}
549 
550 	return( is_regular );
551 }
552 
553 /*
554  * na_selected_info_is_executable:
555  * @nsi: this #NASelectedInfo object.
556  *
557  * Returns: %TRUE if the item is executable by the user, %FALSE else.
558  */
559 gboolean
na_selected_info_is_executable(const NASelectedInfo * nsi)560 na_selected_info_is_executable( const NASelectedInfo *nsi )
561 {
562 	gboolean is_exe;
563 
564 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), FALSE );
565 
566 	is_exe = FALSE;
567 
568 	if( !nsi->private->dispose_has_run ){
569 
570 		is_exe = nsi->private->can_execute;
571 	}
572 
573 	return( is_exe );
574 }
575 
576 /*
577  * na_selected_info_is_local:
578  * @nsi: this #NASelectedInfo object.
579  *
580  * Returns: %TRUE if the item is on a local filesystem, %FALSE else.
581  */
582 gboolean
na_selected_info_is_local(const NASelectedInfo * nsi)583 na_selected_info_is_local( const NASelectedInfo *nsi )
584 {
585 	gboolean is_local;
586 	gchar *scheme;
587 
588 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), FALSE );
589 
590 	is_local = FALSE;
591 
592 	if( !nsi->private->dispose_has_run ){
593 
594 		scheme = na_selected_info_get_uri_scheme( nsi );
595 		is_local = ( strcmp( scheme, "file" ) == 0 );
596 		g_free( scheme );
597 	}
598 
599 	return( is_local );
600 }
601 
602 /*
603  * na_selected_info_is_owner:
604  * @nsi: this #NASelectedInfo object.
605  * @user: the user to be tested against the owner of the @nsi object.
606  *
607  * Returns: %TRUE if the item is a owner, %FALSE else.
608  */
609 gboolean
na_selected_info_is_owner(const NASelectedInfo * nsi,const gchar * user)610 na_selected_info_is_owner( const NASelectedInfo *nsi, const gchar *user )
611 {
612 	gboolean is_owner;
613 
614 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), FALSE );
615 
616 	is_owner = FALSE;
617 
618 	if( !nsi->private->dispose_has_run ){
619 
620 		is_owner = ( strcmp( nsi->private->owner, user ) == 0 );
621 	}
622 
623 	return( is_owner );
624 }
625 
626 /*
627  * na_selected_info_is_readable:
628  * @nsi: this #NASelectedInfo object.
629  *
630  * Returns: %TRUE if the item is a readable, %FALSE else.
631  */
632 gboolean
na_selected_info_is_readable(const NASelectedInfo * nsi)633 na_selected_info_is_readable( const NASelectedInfo *nsi )
634 {
635 	gboolean is_readable;
636 
637 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), FALSE );
638 
639 	is_readable = FALSE;
640 
641 	if( !nsi->private->dispose_has_run ){
642 
643 		is_readable = nsi->private->can_read;
644 	}
645 
646 	return( is_readable );
647 }
648 
649 /*
650  * na_selected_info_is_writable:
651  * @nsi: this #NASelectedInfo object.
652  *
653  * Returns: %TRUE if the item is a writable, %FALSE else.
654  */
655 gboolean
na_selected_info_is_writable(const NASelectedInfo * nsi)656 na_selected_info_is_writable( const NASelectedInfo *nsi )
657 {
658 	gboolean is_writable;
659 
660 	g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi ), FALSE );
661 
662 	is_writable = FALSE;
663 
664 	if( !nsi->private->dispose_has_run ){
665 
666 		is_writable = nsi->private->can_write;
667 	}
668 
669 	return( is_writable );
670 }
671 
672 /*
673  * na_selected_info_create_for_uri:
674  * @uri: an URI.
675  * @mimetype: the corresponding Nautilus mime type, or %NULL.
676  * @errmsg: a pointer to a string which will contain an error message on
677  *  return.
678  *
679  * Returns: a newly allocated #NASelectedInfo object for the given @uri.
680  */
681 NASelectedInfo *
na_selected_info_create_for_uri(const gchar * uri,const gchar * mimetype,gchar ** errmsg)682 na_selected_info_create_for_uri( const gchar *uri, const gchar *mimetype, gchar **errmsg )
683 {
684 	static const gchar *thisfn = "na_selected_info_create_for_uri";
685 
686 	g_debug( "%s: uri=%s, mimetype=%s", thisfn, uri, mimetype );
687 
688 	NASelectedInfo *obj = new_from_uri( uri, mimetype, errmsg );
689 
690 	return( obj );
691 }
692 
693 static void
dump(const NASelectedInfo * nsi)694 dump( const NASelectedInfo *nsi )
695 {
696 	static const gchar *thisfn = "na_selected_info_dump";
697 
698 	g_debug( "%s:                uri=%s", thisfn, nsi->private->uri );
699 	g_debug( "%s:           mimetype=%s", thisfn, nsi->private->mimetype );
700 	g_debug( "%s:           filename=%s", thisfn, nsi->private->filename );
701 	g_debug( "%s:            dirname=%s", thisfn, nsi->private->dirname );
702 	g_debug( "%s:           basename=%s", thisfn, nsi->private->basename );
703 	g_debug( "%s:           hostname=%s", thisfn, nsi->private->hostname );
704 	g_debug( "%s:           username=%s", thisfn, nsi->private->username );
705 	g_debug( "%s:             scheme=%s", thisfn, nsi->private->scheme );
706 	g_debug( "%s:               port=%d", thisfn, nsi->private->port );
707 	g_debug( "%s: attributes_are_set=%s", thisfn, nsi->private->attributes_are_set ? "True":"False" );
708 	g_debug( "%s:          file_type=%s", thisfn, dump_file_type( nsi->private->file_type ));
709 	g_debug( "%s:           can_read=%s", thisfn, nsi->private->can_read ? "True":"False" );
710 	g_debug( "%s:          can_write=%s", thisfn, nsi->private->can_write ? "True":"False" );
711 	g_debug( "%s:        can_execute=%s", thisfn, nsi->private->can_execute ? "True":"False" );
712 	g_debug( "%s:              owner=%s", thisfn, nsi->private->owner );
713 }
714 
715 static const char *
dump_file_type(GFileType type)716 dump_file_type( GFileType type )
717 {
718 	switch( type ){
719 		case G_FILE_TYPE_REGULAR:
720 			return( "regular" );
721 		case G_FILE_TYPE_DIRECTORY:
722 			return( "directory" );
723 		case G_FILE_TYPE_SYMBOLIC_LINK:
724 			return( "symbolic link" );
725 		case G_FILE_TYPE_SPECIAL:
726 			return( "special (socket, fifo, blockdev, chardev)" );
727 		case G_FILE_TYPE_SHORTCUT:
728 			return( "shortcut" );
729 		case G_FILE_TYPE_MOUNTABLE:
730 			return( "mountable" );
731 		default:
732 			break;
733 	}
734 	return( "unknown" );
735 }
736 
737 static NASelectedInfo *
new_from_nautilus_file_info(NautilusFileInfo * item)738 new_from_nautilus_file_info( NautilusFileInfo *item )
739 {
740 	gchar *uri = nautilus_file_info_get_uri( item );
741 	gchar *mimetype = nautilus_file_info_get_mime_type( item );
742 	NASelectedInfo *info = new_from_uri( uri, mimetype, NULL );
743 	g_free( mimetype );
744 	g_free( uri );
745 
746 	return( info );
747 }
748 
749 /*
750  * Nautilus uses to address the desktop via the 'x-nautilus-desktop:///' URI.
751  * g_filename_from_uri() complains that
752  * "The URI 'x-nautilus-desktop:///' is not an absolute URI using the "file" scheme".
753  * In this case, we prefer the vfs->path member wich is just a decomposition of the
754  * URI, and does not try to interpret it.
755  *
756  * *********************************************************************************
757  * Extract from RFC 2396:
758  *
759  * 2.4.3. Excluded US-ASCII Characters
760  *
761  * Although they are disallowed within the URI syntax, we include here a
762  * description of those US-ASCII characters that have been excluded and
763  * the reasons for their exclusion.
764  *
765  * The control characters in the US-ASCII coded character set are not
766  * used within a URI, both because they are non-printable and because
767  * they are likely to be misinterpreted by some control mechanisms.
768  *
769  * control = <US-ASCII coded characters 00-1F and 7F hexadecimal>
770  *
771  * The space character is excluded because significant spaces may
772  * disappear and insignificant spaces may be introduced when URI are
773  * transcribed or typeset or subjected to the treatment of word-
774  * processing programs. Whitespace is also used to delimit URI in many
775  * contexts.
776  *
777  * space = <US-ASCII coded character 20 hexadecimal>
778  *
779  * The angle-bracket "<" and ">" and double-quote (") characters are
780  * excluded because they are often used as the delimiters around URI in
781  * text documents and protocol fields. The character "#" is excluded
782  * because it is used to delimit a URI from a fragment identifier in URI
783  * references (Section 4). The percent character "%" is excluded because
784  * it is used for the encoding of escaped characters.
785  *
786  * delims = "<" | ">" | "#" | "%" | <">
787  *
788  * Other characters are excluded because gateways and other transport
789  * agents are known to sometimes modify such characters, or they are
790  * used as delimiters.
791  *
792  * unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
793  *
794  * Data corresponding to excluded characters must be escaped in order to
795  * be properly represented within a URI.
796  *
797  * pwi 2011-01-04:
798  * It results from the above excerpt that:
799  * - as double quotes are not valid character in URI, they have to be
800  *   escaped as %22, and so Nautilus does
801  * - but simple quotes are not forbidden, and so have not to be
802  *   escaped, and so Nautilus does not escape them
803  *
804  * As a result, we may have valid, non-escaped, simple quotes in an URI.
805  */
806 static NASelectedInfo *
new_from_uri(const gchar * uri,const gchar * mimetype,gchar ** errmsg)807 new_from_uri( const gchar *uri, const gchar *mimetype, gchar **errmsg )
808 {
809 	GFile *location;
810 	NAGnomeVFSURI *vfs;
811 
812 	NASelectedInfo *info = g_object_new( NA_TYPE_SELECTED_INFO, NULL );
813 
814 	info->private->uri = g_strdup( uri );
815 	if( mimetype ){
816 		info->private->mimetype = g_strdup( mimetype );
817 	}
818 
819 	/* pwi 2011-05-18
820 	 * Filename and dirname should be taken from the GFile location, itself taken
821 	 * from the URI, so that we have dir='/home/pierre/.gvfs/sftp on stormy.trychlos.org/etc'
822 	 * Taking filename and dirname from URI just gives '/etc'
823 	 * see #650523
824 	 */
825 	location = g_file_new_for_uri( uri );
826 	info->private->filename = g_file_get_path( location );
827 
828 	vfs = g_new0( NAGnomeVFSURI, 1 );
829 	na_gnome_vfs_uri_parse( vfs, uri );
830 	if( !info->private->filename ){
831 		g_debug( "na_selected_info_new_from_uri: uri='%s', filename=NULL, setting it to '%s'", uri, vfs->path );
832 		info->private->filename = g_strdup( vfs->path );
833 	}
834 
835 	info->private->basename = g_path_get_basename( info->private->filename );
836 	info->private->dirname = g_path_get_dirname( info->private->filename );
837 	info->private->hostname = g_strdup( vfs->host_name );
838 	info->private->username = g_strdup( vfs->user_name );
839 	info->private->scheme = g_strdup( vfs->scheme );
840 	info->private->port = vfs->host_port;
841 	na_gnome_vfs_uri_free( vfs );
842 
843 	query_file_attributes( info, location, errmsg );
844 	g_object_unref( location );
845 
846 	dump( info );
847 
848 	return( info );
849 }
850 
851 static void
query_file_attributes(NASelectedInfo * nsi,GFile * location,gchar ** errmsg)852 query_file_attributes( NASelectedInfo *nsi, GFile *location, gchar **errmsg )
853 {
854 	static const gchar *thisfn = "na_selected_info_query_file_attributes";
855 	GError *error;
856 
857 	error = NULL;
858 	GFileInfo *info = g_file_query_info( location,
859 			G_FILE_ATTRIBUTE_STANDARD_TYPE
860 				"," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE
861 				"," G_FILE_ATTRIBUTE_ACCESS_CAN_READ
862 				"," G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE
863 				"," G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE
864 				"," G_FILE_ATTRIBUTE_OWNER_USER,
865 			G_FILE_QUERY_INFO_NONE, NULL, &error );
866 
867 	if( error ){
868 		if( errmsg ){
869 			*errmsg = g_strdup_printf( _( "Error when querying informations for %s URI: %s" ), nsi->private->uri, error->message );
870 		} else {
871 			g_warning( "%s: uri=%s, g_file_query_info: %s", thisfn, nsi->private->uri, error->message );
872 		}
873 		g_error_free( error );
874 		return;
875 	}
876 
877 	if( !nsi->private->mimetype ){
878 		nsi->private->mimetype = g_strdup( g_file_info_get_attribute_as_string( info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ));
879 	}
880 
881 	nsi->private->file_type = ( GFileType ) g_file_info_get_attribute_uint32( info, G_FILE_ATTRIBUTE_STANDARD_TYPE );
882 
883 	nsi->private->can_read = g_file_info_get_attribute_boolean( info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ );
884 	nsi->private->can_write = g_file_info_get_attribute_boolean( info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE );
885 	nsi->private->can_execute = g_file_info_get_attribute_boolean( info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE );
886 
887 	nsi->private->owner = g_strdup( g_file_info_get_attribute_as_string( info, G_FILE_ATTRIBUTE_OWNER_USER ));
888 
889 	nsi->private->attributes_are_set = TRUE;
890 
891 	g_object_unref( info );
892 }
893