3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
9 * This Program 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.
14 * This Program 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
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
35 #include <glib/gi18n.h>
38 #include "na-gnome-vfs-uri.h"
39 #include "na-selected-info.h"
43 struct _NASelectedInfoClassPrivate
{
44 void *empty
; /* so that gcc -pedantic is happy */
47 /* private instance data
49 struct _NASelectedInfoPrivate
{
50 gboolean dispose_has_run
;
65 gboolean attributes_are_set
;
69 static GObjectClass
*st_parent_class
= NULL
;
71 static GType
register_type( void );
72 static void class_init( NASelectedInfoClass
*klass
);
73 static void instance_init( GTypeInstance
*instance
, gpointer klass
);
74 static void instance_dispose( GObject
*object
);
75 static void instance_finalize( GObject
*object
);
77 static void dump( const NASelectedInfo
*nsi
);
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
);
83 na_selected_info_get_type( void )
85 static GType object_type
= 0;
88 object_type
= register_type();
91 return( object_type
);
97 static const gchar
*thisfn
= "na_selected_info_register_type";
100 static GTypeInfo info
= {
101 sizeof( NASelectedInfoClass
),
102 ( GBaseInitFunc
) NULL
,
103 ( GBaseFinalizeFunc
) NULL
,
104 ( GClassInitFunc
) class_init
,
107 sizeof( NASelectedInfo
),
109 ( GInstanceInitFunc
) instance_init
112 g_debug( "%s", thisfn
);
114 type
= g_type_register_static( G_TYPE_OBJECT
, "NASelectedInfo", &info
, 0 );
120 class_init( NASelectedInfoClass
*klass
)
122 static const gchar
*thisfn
= "na_selected_info_class_init";
123 GObjectClass
*object_class
;
125 g_debug( "%s: klass=%p", thisfn
, ( void * ) klass
);
127 st_parent_class
= g_type_class_peek_parent( klass
);
129 object_class
= G_OBJECT_CLASS( klass
);
130 object_class
->dispose
= instance_dispose
;
131 object_class
->finalize
= instance_finalize
;
133 klass
->private = g_new0( NASelectedInfoClassPrivate
, 1 );
137 instance_init( GTypeInstance
*instance
, gpointer klass
)
139 static const gchar
*thisfn
= "na_selected_info_instance_init";
140 NASelectedInfo
*self
;
142 g_return_if_fail( NA_IS_SELECTED_INFO( instance
));
144 g_debug( "%s: instance=%p (%s), klass=%p",
145 thisfn
, ( void * ) instance
, G_OBJECT_TYPE_NAME( instance
), ( void * ) klass
);
147 self
= NA_SELECTED_INFO( instance
);
149 self
->private = g_new0( NASelectedInfoPrivate
, 1 );
151 self
->private->dispose_has_run
= FALSE
;
152 self
->private->uri
= NULL
;
156 instance_dispose( GObject
*object
)
158 static const gchar
*thisfn
= "na_selected_info_instance_dispose";
159 NASelectedInfo
*self
;
161 g_return_if_fail( NA_IS_SELECTED_INFO( object
));
162 self
= NA_SELECTED_INFO( object
);
164 if( !self
->private->dispose_has_run
){
165 g_debug( "%s: object=%p (%s)", thisfn
, ( void * ) object
, G_OBJECT_TYPE_NAME( object
));
167 self
->private->dispose_has_run
= TRUE
;
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
);
177 instance_finalize( GObject
*object
)
179 static const gchar
*thisfn
= "na_selected_info_instance_finalize";
180 NASelectedInfo
*self
;
182 g_return_if_fail( NA_IS_SELECTED_INFO( object
));
184 self
= NA_SELECTED_INFO( object
);
186 g_debug( "%s: object=%p (%s)", thisfn
, ( void * ) object
, G_OBJECT_TYPE_NAME( object
));
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
);
198 g_free( self
->private );
200 /* chain call to parent class */
201 if( G_OBJECT_CLASS( st_parent_class
)->finalize
){
202 G_OBJECT_CLASS( st_parent_class
)->finalize( object
);
207 * na_selected_info_get_list_from_item:
208 * @item: a #NautilusFileInfo item
210 * Returns: a #GList list which contains a #NASelectedInfo item with the
211 * same URI that the @item.
214 na_selected_info_get_list_from_item( NautilusFileInfo
*item
)
219 NASelectedInfo
*info
= new_from_nautilus_file_info( item
);
222 selected
= g_list_prepend( NULL
, info
);
229 * na_selected_info_get_list_from_list:
230 * @nautilus_selection: a #GList list of #NautilusFileInfo items.
232 * Returns: a #GList list of #NASelectedInfo items whose URI correspond
233 * to those of @nautilus_selection.
236 na_selected_info_get_list_from_list( GList
*nautilus_selection
)
243 for( it
= nautilus_selection
; it
; it
= it
->next
){
244 NASelectedInfo
*info
= new_from_nautilus_file_info( NAUTILUS_FILE_INFO( it
->data
));
247 selected
= g_list_prepend( selected
, info
);
251 return( selected
? g_list_reverse( selected
) : NULL
);
255 * na_selected_info_copy_list:
256 * @files: a #GList list of #NASelectedInfo items.
258 * Returns: a copy of the provided @files list.
261 na_selected_info_copy_list( GList
*files
)
266 copy
= g_list_copy( files
);
268 for( l
= copy
; l
!= NULL
; l
= l
->next
){
269 g_object_ref( G_OBJECT( l
->data
));
276 * na_selected_info_free_list:
277 * @files: a #GList of #NASelectedInfo items.
279 * Frees up the #GList @files.
282 na_selected_info_free_list( GList
*files
)
284 g_list_foreach( files
, ( GFunc
) g_object_unref
, NULL
);
285 g_list_free( files
);
289 * na_selected_info_get_basename:
290 * @nsi: this #NASelectedInfo object.
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.
297 na_selected_info_get_basename( const NASelectedInfo
*nsi
)
301 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), NULL
);
305 if( !nsi
->private->dispose_has_run
){
307 basename
= g_strdup( nsi
->private->basename
);
314 * na_selected_info_get_dirname:
315 * @nsi: this #NASelectedInfo object.
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.
322 na_selected_info_get_dirname( const NASelectedInfo
*nsi
)
326 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), NULL
);
330 if( !nsi
->private->dispose_has_run
){
332 dirname
= g_strdup( nsi
->private->dirname
);
339 * na_selected_info_get_mime_type:
340 * @nsi: this #NASelectedInfo object.
342 * Returns: the mime type associated with this #NASelectedInfo object,
343 * as a newly allocated string which should be g_free() by the caller.
346 na_selected_info_get_mime_type( const NASelectedInfo
*nsi
)
350 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), NULL
);
354 if( !nsi
->private->dispose_has_run
){
356 if( nsi
->private->mimetype
){
357 mimetype
= g_strdup( nsi
->private->mimetype
);
365 * na_selected_info_get_path:
366 * @nsi: this #NASelectedInfo object.
368 * Returns: the filename of the item as a newly allocated string which
369 * should be g_free() by the caller.
372 na_selected_info_get_path( const NASelectedInfo
*nsi
)
376 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), NULL
);
380 if( !nsi
->private->dispose_has_run
){
382 path
= g_strdup( nsi
->private->filename
);
389 * na_selected_info_get_uri:
390 * @nsi: this #NASelectedInfo object.
392 * Returns: the URI associated with this #NASelectedInfo object, as a
393 * newly allocated string which should be g_free() by the caller.
396 na_selected_info_get_uri( const NASelectedInfo
*nsi
)
400 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), NULL
);
404 if( !nsi
->private->dispose_has_run
){
406 uri
= g_strdup( nsi
->private->uri
);
413 * na_selected_info_get_uri_host:
414 * @nsi: this #NASelectedInfo object.
416 * Returns: the host associated to this @nsi object, as a
417 * newly allocated string which should be g_free() by the caller.
420 na_selected_info_get_uri_host( const NASelectedInfo
*nsi
)
424 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), NULL
);
428 if( !nsi
->private->dispose_has_run
){
430 host
= g_strdup( nsi
->private->hostname
);
437 * na_selected_info_get_uri_user:
438 * @nsi: this #NASelectedInfo object.
440 * Returns: the user associated to this @nsi object, as a
441 * newly allocated string which should be g_free() by the caller.
444 na_selected_info_get_uri_user( const NASelectedInfo
*nsi
)
448 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), NULL
);
452 if( !nsi
->private->dispose_has_run
){
454 user
= g_strdup( nsi
->private->username
);
461 * na_selected_info_get_uri_port:
462 * @nsi: this #NASelectedInfo object.
464 * Returns: the port associated to this @nsi object.
467 na_selected_info_get_uri_port( const NASelectedInfo
*nsi
)
471 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), 0 );
475 if( !nsi
->private->dispose_has_run
){
477 port
= nsi
->private->port
;
484 * na_selected_info_get_uri_scheme:
485 * @nsi: this #NASelectedInfo object.
487 * Returns: the scheme associated to this @nsi object, as a
488 * newly allocated string which should be g_free() by the caller.
491 na_selected_info_get_uri_scheme( const NASelectedInfo
*nsi
)
495 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), NULL
);
499 if( !nsi
->private->dispose_has_run
){
501 scheme
= g_strdup( nsi
->private->scheme
);
508 * na_selected_info_is_directory:
509 * @nsi: this #NASelectedInfo object.
511 * Returns: %TRUE if the item is a directory, %FALSE else.
514 na_selected_info_is_directory( const NASelectedInfo
*nsi
)
518 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), FALSE
);
522 if( !nsi
->private->dispose_has_run
){
524 is_dir
= ( nsi
->private->file_type
== G_FILE_TYPE_DIRECTORY
);
531 * na_selected_info_is_regular:
532 * @nsi: this #NASelectedInfo object.
534 * Returns: %TRUE if the item is a regular file, %FALSE else.
537 na_selected_info_is_regular( const NASelectedInfo
*nsi
)
541 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), FALSE
);
545 if( !nsi
->private->dispose_has_run
){
547 is_regular
= ( nsi
->private->file_type
== G_FILE_TYPE_REGULAR
);
550 return( is_regular
);
554 * na_selected_info_is_executable:
555 * @nsi: this #NASelectedInfo object.
557 * Returns: %TRUE if the item is executable by the user, %FALSE else.
560 na_selected_info_is_executable( const NASelectedInfo
*nsi
)
564 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), FALSE
);
568 if( !nsi
->private->dispose_has_run
){
570 is_exe
= nsi
->private->can_execute
;
577 * na_selected_info_is_local:
578 * @nsi: this #NASelectedInfo object.
580 * Returns: %TRUE if the item is on a local filesystem, %FALSE else.
583 na_selected_info_is_local( const NASelectedInfo
*nsi
)
588 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), FALSE
);
592 if( !nsi
->private->dispose_has_run
){
594 scheme
= na_selected_info_get_uri_scheme( nsi
);
595 is_local
= ( strcmp( scheme
, "file" ) == 0 );
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.
607 * Returns: %TRUE if the item is a owner, %FALSE else.
610 na_selected_info_is_owner( const NASelectedInfo
*nsi
, const gchar
*user
)
614 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), FALSE
);
618 if( !nsi
->private->dispose_has_run
){
620 is_owner
= ( strcmp( nsi
->private->owner
, user
) == 0 );
627 * na_selected_info_is_readable:
628 * @nsi: this #NASelectedInfo object.
630 * Returns: %TRUE if the item is a readable, %FALSE else.
633 na_selected_info_is_readable( const NASelectedInfo
*nsi
)
635 gboolean is_readable
;
637 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), FALSE
);
641 if( !nsi
->private->dispose_has_run
){
643 is_readable
= nsi
->private->can_read
;
646 return( is_readable
);
650 * na_selected_info_is_writable:
651 * @nsi: this #NASelectedInfo object.
653 * Returns: %TRUE if the item is a writable, %FALSE else.
656 na_selected_info_is_writable( const NASelectedInfo
*nsi
)
658 gboolean is_writable
;
660 g_return_val_if_fail( NA_IS_SELECTED_INFO( nsi
), FALSE
);
664 if( !nsi
->private->dispose_has_run
){
666 is_writable
= nsi
->private->can_write
;
669 return( is_writable
);
673 * na_selected_info_create_for_uri:
675 * @mimetype: the corresponding Nautilus mime type, or %NULL.
676 * @errmsg: a pointer to a string which will contain an error message on
679 * Returns: a newly allocated #NASelectedInfo object for the given @uri.
682 na_selected_info_create_for_uri( const gchar
*uri
, const gchar
*mimetype
, gchar
**errmsg
)
684 static const gchar
*thisfn
= "na_selected_info_create_for_uri";
686 g_debug( "%s: uri=%s, mimetype=%s", thisfn
, uri
, mimetype
);
688 NASelectedInfo
*obj
= new_from_uri( uri
, mimetype
, errmsg
);
694 dump( const NASelectedInfo
*nsi
)
696 static const gchar
*thisfn
= "na_selected_info_dump";
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: can_read=%s", thisfn
, nsi
->private->can_read
? "True":"False" );
708 g_debug( "%s: can_write=%s", thisfn
, nsi
->private->can_write
? "True":"False" );
709 g_debug( "%s: can_execute=%s", thisfn
, nsi
->private->can_execute
? "True":"False" );
710 g_debug( "%s: owner=%s", thisfn
, nsi
->private->owner
);
711 g_debug( "%s: attributes_are_set=%s", thisfn
, nsi
->private->attributes_are_set
? "True":"False" );
714 static NASelectedInfo
*
715 new_from_nautilus_file_info( NautilusFileInfo
*item
)
717 gchar
*uri
= nautilus_file_info_get_uri( item
);
718 gchar
*mimetype
= nautilus_file_info_get_mime_type( item
);
719 g_debug( "new_from_nautilus_file_info: uri=%s, mimetype=%s", uri
, mimetype
);
720 NASelectedInfo
*info
= new_from_uri( uri
, mimetype
, NULL
);
728 * Nautilus uses to address the desktop via the 'x-nautilus-desktop:///' URI.
729 * g_filename_from_uri() complains that
730 * "The URI 'x-nautilus-desktop:///' is not an absolute URI using the "file" scheme".
731 * In this case, we prefer the vfs->path member wich is just a decomposition of the
732 * URI, and does not try to interpret it.
734 * *********************************************************************************
735 * Extract from RFC 2396:
737 * 2.4.3. Excluded US-ASCII Characters
739 * Although they are disallowed within the URI syntax, we include here a
740 * description of those US-ASCII characters that have been excluded and
741 * the reasons for their exclusion.
743 * The control characters in the US-ASCII coded character set are not
744 * used within a URI, both because they are non-printable and because
745 * they are likely to be misinterpreted by some control mechanisms.
747 * control = <US-ASCII coded characters 00-1F and 7F hexadecimal>
749 * The space character is excluded because significant spaces may
750 * disappear and insignificant spaces may be introduced when URI are
751 * transcribed or typeset or subjected to the treatment of word-
752 * processing programs. Whitespace is also used to delimit URI in many
755 * space = <US-ASCII coded character 20 hexadecimal>
757 * The angle-bracket "<" and ">" and double-quote (") characters are
758 * excluded because they are often used as the delimiters around URI in
759 * text documents and protocol fields. The character "#" is excluded
760 * because it is used to delimit a URI from a fragment identifier in URI
761 * references (Section 4). The percent character "%" is excluded because
762 * it is used for the encoding of escaped characters.
764 * delims = "<" | ">" | "#" | "%" | <">
766 * Other characters are excluded because gateways and other transport
767 * agents are known to sometimes modify such characters, or they are
768 * used as delimiters.
770 * unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
772 * Data corresponding to excluded characters must be escaped in order to
773 * be properly represented within a URI.
777 * It results from the above excerpt that:
778 * - as double quotes are not valid character in URI, they have to be
779 * escaped as %22, and so Nautilus does
780 * - but simple quotes are not forbidden, and so have not to be
781 * escaped, and so Nautilus does not escape them
783 * As a result, we may have valid, non-escaped, simple quotes in an URI.
785 static NASelectedInfo
*
786 new_from_uri( const gchar
*uri
, const gchar
*mimetype
, gchar
**errmsg
)
791 NASelectedInfo
*info
= g_object_new( NA_SELECTED_INFO_TYPE
, NULL
);
793 info
->private->uri
= g_strdup( uri
);
795 info
->private->mimetype
= g_strdup( mimetype
);
799 * Filename and dirname should be taken from the GFile location, itself taken
800 * from the URI, so that we have dir='/home/pierre/.gvfs/sftp on stormy.trychlos.org/etc'
801 * Taking filename and dirname from URI just gives '/etc'
804 location
= g_file_new_for_uri( uri
);
805 info
->private->filename
= g_file_get_path( location
);
807 vfs
= g_new0( NAGnomeVFSURI
, 1 );
808 na_gnome_vfs_uri_parse( vfs
, uri
);
809 if( !info
->private->filename
){
810 g_debug( "new_from_uri: uri='%s', filename=NULL, setting it to '%s'", uri
, vfs
->path
);
811 info
->private->filename
= g_strdup( vfs
->path
);
814 info
->private->basename
= g_path_get_basename( info
->private->filename
);
815 info
->private->dirname
= g_path_get_dirname( info
->private->filename
);
816 info
->private->hostname
= g_strdup( vfs
->host_name
);
817 info
->private->username
= g_strdup( vfs
->user_name
);
818 info
->private->scheme
= g_strdup( vfs
->scheme
);
819 info
->private->port
= vfs
->host_port
;
820 na_gnome_vfs_uri_free( vfs
);
822 query_file_attributes( info
, location
, errmsg
);
823 g_object_unref( location
);
831 query_file_attributes( NASelectedInfo
*nsi
, GFile
*location
, gchar
**errmsg
)
833 static const gchar
*thisfn
= "na_selected_info_query_file_attributes";
837 GFileInfo
*info
= g_file_query_info( location
,
838 G_FILE_ATTRIBUTE_STANDARD_TYPE
839 "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE
840 "," G_FILE_ATTRIBUTE_ACCESS_CAN_READ
841 "," G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE
842 "," G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE
843 "," G_FILE_ATTRIBUTE_OWNER_USER
,
844 G_FILE_QUERY_INFO_NONE
, NULL
, &error
);
848 *errmsg
= g_strdup_printf( _( "Error when querying informations for %s URI: %s" ), nsi
->private->uri
, error
->message
);
850 g_warning( "%s: URI='%s'", thisfn
, nsi
->private->uri
);
851 g_warning( "%s: g_file_query_info: %s", thisfn
, error
->message
);
853 g_error_free( error
);
857 if( !nsi
->private->mimetype
){
858 nsi
->private->mimetype
= g_strdup( g_file_info_get_attribute_as_string( info
, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE
));
861 nsi
->private->file_type
= ( GFileType
) g_file_info_get_attribute_uint32( info
, G_FILE_ATTRIBUTE_STANDARD_TYPE
);
863 nsi
->private->can_read
= g_file_info_get_attribute_boolean( info
, G_FILE_ATTRIBUTE_ACCESS_CAN_READ
);
864 nsi
->private->can_write
= g_file_info_get_attribute_boolean( info
, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE
);
865 nsi
->private->can_execute
= g_file_info_get_attribute_boolean( info
, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE
);
867 nsi
->private->owner
= g_strdup( g_file_info_get_attribute_as_string( info
, G_FILE_ATTRIBUTE_OWNER_USER
));
869 nsi
->private->attributes_are_set
= TRUE
;
871 g_object_unref( info
);