[nautilus] forgotten patch

Matthias Clasen mclasen at fedoraproject.org
Tue Aug 24 17:10:56 UTC 2010


commit 6dd1f680521e9082444afc4606a3ec77693b6ae1
Author: Matthias Clasen <mclasen at redhat.com>
Date:   Tue Aug 24 13:09:55 2010 -0400

    forgotten patch

 nautilus-selinux.patch | 1749 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 1749 insertions(+), 0 deletions(-)
---
diff --git a/nautilus-selinux.patch b/nautilus-selinux.patch
new file mode 100644
index 0000000..7888c75
--- /dev/null
+++ b/nautilus-selinux.patch
@@ -0,0 +1,1749 @@
+diff -up nautilus-2.90.1/libnautilus-extension/nautilus-column.c.selinux nautilus-2.90.1/libnautilus-extension/nautilus-column.c
+--- nautilus-2.90.1/libnautilus-extension/nautilus-column.c.selinux	2009-04-17 09:12:30.000000000 -0400
++++ nautilus-2.90.1/libnautilus-extension/nautilus-column.c	2010-08-24 11:17:28.104547004 -0400
+@@ -34,6 +34,7 @@ enum {
+ 	PROP_LABEL,
+ 	PROP_DESCRIPTION,
+ 	PROP_XALIGN,
++	PROP_ELLIPSIZE,
+ 	LAST_PROP
+ };
+ 
+@@ -43,6 +44,7 @@ struct _NautilusColumnDetails {
+ 	char *label;
+ 	char *description;
+ 	float xalign;
++	gboolean ellipsize;
+ };
+ 
+ G_DEFINE_TYPE (NautilusColumn, nautilus_column, G_TYPE_OBJECT);
+@@ -110,6 +112,9 @@ nautilus_column_get_property (GObject *o
+ 	case PROP_XALIGN :
+ 		g_value_set_float (value, column->details->xalign);
+ 		break;
++	case PROP_ELLIPSIZE :
++		g_value_set_boolean (value, column->details->ellipsize);
++		break;
+ 	default :
+ 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ 		break;
+@@ -151,6 +156,10 @@ nautilus_column_set_property (GObject *o
+ 		column->details->xalign = g_value_get_float (value);
+ 		g_object_notify (object, "xalign");		
+ 		break;
++	case PROP_ELLIPSIZE :
++		column->details->ellipsize = g_value_get_boolean (value);
++		g_object_notify (object, "ellipsize");		
++		break;
+ 	default :
+ 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ 		break;
+@@ -178,6 +187,7 @@ nautilus_column_init (NautilusColumn *co
+ {
+ 	column->details = g_new0 (NautilusColumnDetails, 1);
+ 	column->details->xalign = 0.0;
++	column->details->ellipsize = FALSE;
+ }
+ 
+ static void
+@@ -232,5 +242,12 @@ nautilus_column_class_init (NautilusColu
+ 							     1.0,
+ 							     0.0,
+ 							     G_PARAM_READWRITE));
++	g_object_class_install_property (G_OBJECT_CLASS (class),
++					 PROP_ELLIPSIZE,
++					 g_param_spec_boolean ("ellipsize",
++							       "ellipsize",
++							       "Ellipsize text in the column if it's too long to display",
++							       FALSE,
++							       G_PARAM_READWRITE));
+ }
+ 
+diff -up nautilus-2.90.1/libnautilus-extension/nautilus-column.h.selinux nautilus-2.90.1/libnautilus-extension/nautilus-column.h
+--- nautilus-2.90.1/libnautilus-extension/nautilus-column.h.selinux	2009-04-17 09:12:30.000000000 -0400
++++ nautilus-2.90.1/libnautilus-extension/nautilus-column.h	2010-08-24 11:17:28.105547004 -0400
+@@ -64,6 +64,7 @@ NautilusColumn *  nautilus_column_new   
+  *   label (string)       - the user-visible label for the column
+  *   description (string) - a user-visible description of the column
+  *   xalign (float)       - x-alignment of the column 
++ *   ellipsize (boolean)  - ellipsize text in the column?
+  */
+ 
+ G_END_DECLS
+diff -up nautilus-2.90.1/libnautilus-private/nautilus-column-utilities.c.selinux nautilus-2.90.1/libnautilus-private/nautilus-column-utilities.c
+--- nautilus-2.90.1/libnautilus-private/nautilus-column-utilities.c.selinux	2010-08-12 06:20:55.000000000 -0400
++++ nautilus-2.90.1/libnautilus-private/nautilus-column-utilities.c	2010-08-24 11:17:28.106547004 -0400
+@@ -119,6 +119,7 @@ get_builtin_columns (void)
+ 					       "attribute", "selinux_context",
+ 					       "label", _("SELinux Context"),
+ 					       "description", _("The SELinux security context of the file."),
++					       "ellipsize", TRUE,
+ 					       NULL));
+ 	columns = g_list_append (columns,
+ 				 g_object_new (NAUTILUS_TYPE_COLUMN,
+diff -up nautilus-2.90.1/libnautilus-private/nautilus-file.c.selinux nautilus-2.90.1/libnautilus-private/nautilus-file.c
+--- nautilus-2.90.1/libnautilus-private/nautilus-file.c.selinux	2010-08-14 07:11:15.000000000 -0400
++++ nautilus-2.90.1/libnautilus-private/nautilus-file.c	2010-08-24 11:17:28.112547004 -0400
+@@ -2171,7 +2171,7 @@ update_info_internal (NautilusFile *file
+ 	file->details->is_mountpoint = is_mountpoint;
+ 
+ 	has_permissions = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE);
+-	permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);;
++	permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);
+ 	if (file->details->has_permissions != has_permissions ||
+ 	    file->details->permissions != permissions) {
+ 		changed = TRUE;
+@@ -5076,7 +5076,7 @@ nautilus_file_can_get_selinux_context (N
+  * context
+  * @file: NautilusFile representing the file in question.
+  * 
+- * Returns: Newly allocated string ready to display to the user.
++ * Returns: Newly allocated string ready to display to the user, or NULL.
+  * 
+  **/
+ char *
+@@ -5109,6 +5109,114 @@ nautilus_file_get_selinux_context (Nauti
+ 	return translated;
+ }
+ 
++/**
++ * nautilus_file_get_selinux_matchpathcon:
++ * 
++ * Get a user-displayable string representing a file's default selinux
++ * context (as from matchpathcon). Only works on local files.
++ * @file: NautilusFile representing the file in question.
++ * 
++ * Returns: Newly allocated string ready to display to the user, or NULL.
++ * 
++ **/
++char *
++nautilus_file_get_selinux_matchpathcon (NautilusFile *file)
++{
++	char *translated;
++#ifdef HAVE_SELINUX
++	char *raw;
++	char *fname;
++	GFile *location;
++#endif
++	
++	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
++
++	translated = NULL;
++#ifdef HAVE_SELINUX
++	location = nautilus_file_get_location (file);
++	fname = g_file_get_path (location);
++	
++	if (!fname) {
++	        return NULL;
++	}
++
++	raw = NULL;
++	if (matchpathcon (fname, file->details->permissions, &raw) == 0) {
++		if (selinux_raw_to_trans_context (raw, &translated) == 0) {
++			char *tmp;
++			tmp = g_strdup (translated);
++			freecon (translated);
++			translated = tmp;
++		}
++		freecon (raw);
++	}
++		      
++	g_free (fname);
++	g_object_unref (location);
++#endif
++	
++	return translated;
++}
++
++void
++nautilus_file_set_selinux_context (NautilusFile *file, 
++				   const char *selinux_context,
++				   NautilusFileOperationCallback callback,
++				   gpointer callback_data)
++{
++	GFileInfo *info;
++	GError *error;
++	char *rcontext;
++
++	rcontext = NULL;
++	
++	/* this is probably mostly right... */
++	if (!nautilus_file_can_set_permissions (file)) {
++		/* Claim that something changed even if the permission change failed.
++		 * This makes it easier for some clients who see the "reverting"
++		 * to the old permissions as "changing back".
++		 */
++		nautilus_file_changed (file);
++		error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
++				     _("Not allowed to set SELinux security context"));
++		(* callback) (file, NULL, error, callback_data);
++		g_error_free (error);
++		return;
++	}
++			       
++	/* Test the permissions-haven't-changed case explicitly
++	 * because we don't want to send the file-changed signal if
++	 * nothing changed.
++	 */
++	if (file->details->selinux_context != NULL &&
++	    strcmp(selinux_context, file->details->selinux_context) == 0) {
++		(* callback) (file, NULL, NULL, callback_data);
++		return;
++	}
++
++#ifdef HAVE_SELINUX
++	/* this is really const, but prototype is wrong, *sigh* */
++	if (selinux_trans_to_raw_context((char *)selinux_context, &rcontext)) {
++		error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVAL,
++				     _("Invalid SELinux security context"));
++		(* callback) (file, NULL, error, callback_data);
++		g_error_free (error);
++		return;
++	}
++	selinux_context = rcontext;
++#endif
++			       
++	info = g_file_info_new ();
++	g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_SELINUX_CONTEXT, selinux_context);
++	nautilus_file_set_attributes (file, info, callback, callback_data);
++	g_object_unref (info);
++
++#ifdef HAVE_SELINUX
++	freecon (rcontext);
++#endif
++}
++
++
+ static char *
+ get_real_name (const char *name, const char *gecos)
+ {
+diff -up nautilus-2.90.1/libnautilus-private/nautilus-file.h.selinux nautilus-2.90.1/libnautilus-private/nautilus-file.h
+--- nautilus-2.90.1/libnautilus-private/nautilus-file.h.selinux	2010-08-14 07:11:15.000000000 -0400
++++ nautilus-2.90.1/libnautilus-private/nautilus-file.h	2010-08-24 11:17:28.119547004 -0400
+@@ -245,6 +245,7 @@ GList *                 nautilus_get_all
+ GList *                 nautilus_file_get_settable_group_names          (NautilusFile                   *file);
+ gboolean                nautilus_file_can_get_selinux_context           (NautilusFile                   *file);
+ char *                  nautilus_file_get_selinux_context               (NautilusFile                   *file);
++char *                  nautilus_file_get_selinux_matchpathcon          (NautilusFile                   *file);
+ 
+ /* "Capabilities". */
+ gboolean                nautilus_file_can_read                          (NautilusFile                   *file);
+@@ -305,6 +306,10 @@ void                    nautilus_file_se
+ 									 guint32                         permissions,
+ 									 NautilusFileOperationCallback   callback,
+ 									 gpointer                        callback_data);
++void                    nautilus_file_set_selinux_context               (NautilusFile *file, 
++									 const char *selinux_context,
++									 NautilusFileOperationCallback callback,
++									 gpointer callback_data);
+ void                    nautilus_file_rename                            (NautilusFile                   *file,
+ 									 const char                     *new_name,
+ 									 NautilusFileOperationCallback   callback,
+diff -up nautilus-2.90.1/libnautilus-private/nautilus-file-operations.c.selinux nautilus-2.90.1/libnautilus-private/nautilus-file-operations.c
+--- nautilus-2.90.1/libnautilus-private/nautilus-file-operations.c.selinux	2010-08-22 09:15:27.000000000 -0400
++++ nautilus-2.90.1/libnautilus-private/nautilus-file-operations.c	2010-08-24 11:18:17.976547003 -0400
+@@ -66,6 +66,10 @@
+ #include "nautilus-file-utilities.h"
+ #include "nautilus-file-conflict-dialog.h"
+ 
++#ifdef HAVE_SELINUX
++    #include <selinux/selinux.h>
++#endif
++
+ /* TODO: TESTING!!! */
+ 
+ typedef struct {
+@@ -148,6 +152,7 @@ typedef struct {
+ 	guint32 file_mask;
+ 	guint32 dir_permissions;
+ 	guint32 dir_mask;
++	char *context;
+ } SetPermissionsJob;
+ 
+ typedef enum {
+@@ -5408,6 +5413,10 @@ set_permissions_job_done (gpointer user_
+ 		job->done_callback (job->done_callback_data);
+ 	}
+ 	
++	if (job->context) {
++		g_free (job->context);
++	}
++	
+ 	finalize_common ((CommonJob *)job);
+ 	return FALSE;
+ }
+@@ -5463,6 +5472,14 @@ set_permissions_file (SetPermissionsJob 
+ 					     current, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ 					     common->cancellable, NULL);
+ 	}
++
++#ifdef HAVE_SELINUX
++	if (!job_aborted (common) && (job->context)) {
++		g_file_set_attribute_string (file, G_FILE_ATTRIBUTE_SELINUX_CONTEXT, 
++					     job->context, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
++					     common->cancellable, NULL);
++	}
++#endif
+ 	
+ 	if (!job_aborted (common) &&
+ 	    g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
+@@ -5526,6 +5543,7 @@ nautilus_file_set_permissions_recursive 
+ 					 guint32         file_mask,
+ 					 guint32         dir_permissions,
+ 					 guint32         dir_mask,
++					 const char     *context, 
+ 					 NautilusOpCallback  callback,
+ 					 gpointer  callback_data)
+ {
+@@ -5539,7 +5557,24 @@ nautilus_file_set_permissions_recursive 
+ 	job->dir_mask = dir_mask;
+ 	job->done_callback = callback;
+ 	job->done_callback_data = callback_data;
+-	
++
++	if (context) {
++		char *rcontext;
++
++		rcontext = job->context = NULL;
++#ifdef HAVE_SELINUX
++		/* this is really const, but prototype is wrong, *sigh* */
++		if (selinux_trans_to_raw_context((char *)context, &rcontext)) {
++			g_error ("selinux_trans_to_raw_context: failed to allocate bytes");
++			return;
++		}
++		job->context = g_strdup (rcontext);
++		freecon (rcontext);
++#endif
++	} else {
++		job->context = NULL;
++	}
++
+ 	g_io_scheduler_push_job (set_permissions_job,
+ 			   job,
+ 			   NULL,
+diff -up nautilus-2.90.1/libnautilus-private/nautilus-file-operations.h.selinux nautilus-2.90.1/libnautilus-private/nautilus-file-operations.h
+--- nautilus-2.90.1/libnautilus-private/nautilus-file-operations.h.selinux	2010-08-02 19:35:56.000000000 -0400
++++ nautilus-2.90.1/libnautilus-private/nautilus-file-operations.h	2010-08-24 11:17:28.127547004 -0400
+@@ -87,6 +87,7 @@ void nautilus_file_set_permissions_recur
+ 					      guint32                         file_mask,
+ 					      guint32                         folder_permissions,
+ 					      guint32                         folder_mask,
++					      const char                     *context,
+ 					      NautilusOpCallback              callback,
+ 					      gpointer                        callback_data);
+ 
+diff -up nautilus-2.90.1/src/file-manager/fm-error-reporting.c.selinux nautilus-2.90.1/src/file-manager/fm-error-reporting.c
+--- nautilus-2.90.1/src/file-manager/fm-error-reporting.c.selinux	2009-04-17 09:12:31.000000000 -0400
++++ nautilus-2.90.1/src/file-manager/fm-error-reporting.c	2010-08-24 11:17:28.129547004 -0400
+@@ -238,6 +238,31 @@ fm_report_error_setting_permissions (Nau
+ 	g_free (message);
+ }		
+ 
++void
++fm_report_error_setting_selinux (NautilusFile *file,
++		       	         GError *error,
++		       	         GtkWindow *parent_window)
++{
++	char *file_name;
++	char *message;
++
++	if (error == NULL) {
++		return;
++	}
++
++	file_name = nautilus_file_get_display_name (file);
++
++	message = g_strdup_printf (_("Sorry, couldn't change the permissions of \"%s\": %s"), file_name, error->message);
++
++	/*  Silently drop the error when called from selinux entry and is not finished yet */
++	if (! g_error_matches(error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) {
++		eel_show_error_dialog (_("The SELinux security context could not be changed."), message, parent_window);
++	}
++
++	g_free (file_name);
++	g_free (message);
++}
++
+ typedef struct _FMRenameData {
+ 	char *name;
+ 	NautilusFileOperationCallback callback;
+diff -up nautilus-2.90.1/src/file-manager/fm-error-reporting.h.selinux nautilus-2.90.1/src/file-manager/fm-error-reporting.h
+--- nautilus-2.90.1/src/file-manager/fm-error-reporting.h.selinux	2009-04-17 09:12:31.000000000 -0400
++++ nautilus-2.90.1/src/file-manager/fm-error-reporting.h	2010-08-24 11:17:28.130547004 -0400
+@@ -40,8 +40,11 @@ void fm_report_error_setting_permissions
+ 					  GError         *error,
+ 					  GtkWindow	 *parent_window);
+ void fm_report_error_setting_owner       (NautilusFile   *file,
+-					  GError         *error,  
++					  GError         *error,
+ 					  GtkWindow	 *parent_window);
++void fm_report_error_setting_selinux     (NautilusFile   *file,
++					  GError         *error,
++                                          GtkWindow      *parent_window);
+ void fm_report_error_setting_group       (NautilusFile   *file,
+ 					  GError         *error,
+ 					  GtkWindow	 *parent_window);
+diff -up nautilus-2.90.1/src/file-manager/fm-list-view.c.selinux nautilus-2.90.1/src/file-manager/fm-list-view.c
+--- nautilus-2.90.1/src/file-manager/fm-list-view.c.selinux	2010-08-22 09:15:27.000000000 -0400
++++ nautilus-2.90.1/src/file-manager/fm-list-view.c	2010-08-24 11:17:28.133547004 -0400
+@@ -1557,13 +1557,15 @@ create_and_set_up_tree_view (FMListView 
+ 		char *name;
+ 		char *label;
+ 		float xalign;
++		gboolean ellipsize;
+ 
+ 		nautilus_column = NAUTILUS_COLUMN (l->data);
+ 
+ 		g_object_get (nautilus_column, 
+ 			      "name", &name, 
+ 			      "label", &label,
+-			      "xalign", &xalign, NULL);
++			      "xalign", &xalign, 
++			      "ellipsize", &ellipsize, NULL);
+ 
+ 		column_num = fm_list_model_add_column (view->details->model,
+ 						       nautilus_column);
+@@ -1607,6 +1609,8 @@ create_and_set_up_tree_view (FMListView 
+ 		} else {		
+ 			cell = gtk_cell_renderer_text_new ();
+ 			g_object_set (cell, "xalign", xalign, NULL);
++			if (ellipsize)
++			    g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ 			view->details->cells = g_list_append (view->details->cells,
+ 							      cell);
+ 			column = gtk_tree_view_column_new_with_attributes (label,
+diff -up nautilus-2.90.1/src/file-manager/fm-properties-window.c.selinux nautilus-2.90.1/src/file-manager/fm-properties-window.c
+--- nautilus-2.90.1/src/file-manager/fm-properties-window.c.selinux	2010-08-14 07:11:15.000000000 -0400
++++ nautilus-2.90.1/src/file-manager/fm-properties-window.c	2010-08-24 11:17:28.139547004 -0400
+@@ -76,6 +76,10 @@
+ #define FREE_FILL_B  (0.811764706 * 65535)
+ 
+ 
++#ifdef HAVE_SELINUX
++# include <selinux/selinux.h>
++#endif
++
+ #define PREVIEW_IMAGE_WIDTH 96
+ 
+ #define ROW_PAD 6
+@@ -115,12 +119,15 @@ struct FMPropertiesWindowDetails {	
+ 	unsigned int  owner_change_timeout;
+ 
+ 	GList *permission_buttons;
+-	GList *permission_combos;
++	GList *permission_combos; /* how is this deallocated???? */
++	GList *selinux_combo;
+ 	GHashTable *initial_permissions;
+ 	gboolean has_recursive_apply;
+ 
+ 	GList *value_fields;
+ 
++	GList *edit_fields;
++
+ 	GList *mime_list;
+ 
+ 	gboolean deep_count_finished;
+@@ -203,6 +210,10 @@ static void permission_combo_update     
+ 						   GtkComboBox        *combo);
+ static void value_field_update                    (FMPropertiesWindow *window,
+ 						   GtkLabel           *field);
++static void edit_field_update                     (FMPropertiesWindow *window,
++						   GtkEntry           *field);
++static void popup_field_update                    (FMPropertiesWindow *window,
++						   GtkComboBox        *entry);
+ static void properties_window_update              (FMPropertiesWindow *window,
+ 						   GList              *files);
+ static void is_directory_ready_callback           (NautilusFile       *file,
+@@ -232,10 +243,36 @@ static GtkLabel *attach_ellipsizing_valu
+ 						   const char *initial_text);
+ 						   
+ static GtkWidget* create_pie_widget 		  (FMPropertiesWindow *window);
++  
++static void attach_selinux_data_edit_field        (GtkEntry *entry, 
++                                                   char *attr_value, 
++                                                   char *def_attr_value); 
++ 
++#ifdef HAVE_SELINUX 
++static void attach_selinux_data_popup_field       (GtkComboBox *comb, 
++                                                   char *attr_val, 
++                                                   char *def_attr_val); 
++#endif 
++
+ 
+ G_DEFINE_TYPE (FMPropertiesWindow, fm_properties_window, GTK_TYPE_DIALOG);
+ #define parent_class fm_properties_window_parent_class 
+ 
++static void
++maybe_gtk_entry_set_text (GtkEntry *entry, const char *val)
++{
++	char *old_val;
++
++	g_assert (GTK_IS_ENTRY (entry));
++
++	old_val = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
++
++	if (strcmp (old_val, val) != 0) {
++		gtk_entry_set_text (entry, val);
++	}
++	g_free(old_val);
++}
++
+ static gboolean
+ is_multi_file_window (FMPropertiesWindow *window)
+ {
+@@ -256,6 +293,111 @@ is_multi_file_window (FMPropertiesWindow
+ 	return FALSE;
+ }
+ 
++static gboolean
++all_can_get_permissions (GList *file_list)
++{
++	GList *l;
++	for (l = file_list; l != NULL; l = l->next) {
++		NautilusFile *file;
++		
++		file = NAUTILUS_FILE (l->data);
++		
++		if (!nautilus_file_can_get_permissions (file)) {
++			return FALSE;
++		}
++	}
++
++	return TRUE;
++}
++
++static gboolean
++all_can_set_permissions (GList *file_list)
++{
++	GList *l;
++	for (l = file_list; l != NULL; l = l->next) {
++		NautilusFile *file;
++		
++		file = NAUTILUS_FILE (l->data);
++
++		if (!nautilus_file_can_set_permissions (file)) {
++			return FALSE;
++		}
++	}
++
++	return TRUE;
++}
++
++#ifdef HAVE_SELINUX
++static gboolean
++multi_have_same_selinux_context (FMPropertiesWindow *window)
++{
++	GList *l;
++        char *cntx;
++
++	cntx = NULL;
++	for (l = window->details->original_files; l != NULL; l = l->next) {
++		NautilusFile *file;
++
++		file = NAUTILUS_FILE (l->data);
++		if (!nautilus_file_is_gone (file)) {
++		        char *tmp;
++
++			tmp = nautilus_file_get_string_attribute_with_default (file, "selinux_context");
++		        if (!cntx) {
++			         cntx = tmp;
++			} else if (strcmp (cntx, tmp)) {
++				 g_free (tmp);
++				 g_free (cntx);
++				 return FALSE;
++			}
++			else {
++			         g_free (tmp);
++			}
++		}
++	}
++
++	g_free (cntx);
++	
++	return TRUE;
++}
++#endif
++
++/* NOTE: This modifies cntx */
++static void
++selinux_split_cntx (char *cntx,
++		    const char **ret_attr_u,
++		    const char **ret_attr_r,
++		    const char **ret_attr_t,
++		    const char **ret_attr_s)
++{
++	const char *attr_u;
++	const char *attr_r;
++	const char *attr_t;
++	const char *attr_s;
++
++	attr_u = cntx;
++	if (!(attr_r = strchr (attr_u, ':'))) {
++	        attr_r = "object_r"; /* shouldn't happen */
++	} else {
++	        *((char *)attr_r++) = 0;
++	}
++	
++	if (!(attr_t = strchr (attr_r, ':'))) {
++	        attr_t = "file_t"; /* shouldn't happen */
++	} else {
++	        *((char *)attr_t++) = 0;
++	}
++
++	if ((attr_s = strchr (attr_t, ':'))) {
++	        *((char *)attr_s++) = 0;
++	}
++
++	*ret_attr_u = attr_u;
++	*ret_attr_r = attr_r;
++	*ret_attr_t = attr_t;
++	*ret_attr_s = attr_s;
++}
++
+ static int
+ get_not_gone_original_file_count (FMPropertiesWindow *window)
+ {
+@@ -631,11 +773,7 @@ set_name_field (FMPropertiesWindow *wind
+ 			 * currently showing. This causes minimal ripples (e.g.
+ 			 * selection change).
+ 			 */
+-			gchar *displayed_name = gtk_editable_get_chars (GTK_EDITABLE (window->details->name_field), 0, -1);
+-			if (strcmp (displayed_name, name) != 0) {
+-				gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name);
+-			}
+-			g_free (displayed_name);
++		        maybe_gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name);
+ 		}
+ 	}
+ }
+@@ -715,7 +853,6 @@ static void
+ name_field_restore_original_name (NautilusEntry *name_field)
+ {
+ 	const char *original_name;
+-	char *displayed_name;
+ 
+ 	original_name = (const char *) g_object_get_data (G_OBJECT (name_field),
+ 							  "original_name");
+@@ -724,14 +861,8 @@ name_field_restore_original_name (Nautil
+ 		return;
+ 	}
+ 
+-	displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1);
+-
+-	if (strcmp (original_name, displayed_name) != 0) {
+-		gtk_entry_set_text (GTK_ENTRY (name_field), original_name);
+-	}
++	maybe_gtk_entry_set_text (GTK_ENTRY (name_field), original_name);
+ 	nautilus_entry_select_all (name_field);
+-
+-	g_free (displayed_name);
+ }
+ 
+ static void
+@@ -1027,6 +1158,14 @@ properties_window_update (FMPropertiesWi
+ 		for (l = window->details->value_fields; l != NULL; l = l->next) {
+ 			value_field_update (window, GTK_LABEL (l->data));
+ 		}
++		
++		for (l = window->details->edit_fields; l != NULL; l = l->next) {
++			edit_field_update (window, GTK_ENTRY (l->data));
++		}
++		
++		for (l = window->details->selinux_combo; l != NULL; l = l->next) {
++			popup_field_update (window, GTK_COMBO_BOX (l->data));
++		}		
+ 	}
+ 
+ 	mime_list = get_mime_list (window);
+@@ -1197,6 +1336,164 @@ value_field_update (FMPropertiesWindow *
+ 				      window->details->target_files));
+ }
+ 
++static void
++edit_field_update_internal (GtkEntry *entry, 
++			    GList *file_list)
++{
++	const char *attr_name;
++	char *attr_value;
++	char *def_attr_value;
++	char *inconsistent_string;
++	gboolean sensitive;
++	
++	g_assert (GTK_IS_ENTRY (entry));
++
++	attr_name = g_object_get_data (G_OBJECT (entry), "file_attribute");
++	inconsistent_string = g_object_get_data (G_OBJECT (entry),
++						 "inconsistent_string");
++	def_attr_value = g_object_get_data (G_OBJECT (entry),
++					    "matchpathcon_cntx");
++	
++	attr_value = file_list_get_string_attribute (file_list, attr_name,
++						     inconsistent_string);
++
++	maybe_gtk_entry_set_text (GTK_ENTRY (entry), attr_value);
++
++	/* JFIXME: this isn't generic, *sigh* ... */
++	attach_selinux_data_edit_field (entry, attr_value, def_attr_value);
++	g_free (attr_value);
++	
++	sensitive = all_can_set_permissions (file_list);
++#ifdef HAVE_SELINUX
++	sensitive = sensitive && is_selinux_enabled ();
++#endif
++	gtk_widget_set_sensitive (GTK_WIDGET (entry), sensitive);
++}
++
++static void
++edit_field_update (FMPropertiesWindow *window, GtkEntry *entry)
++{
++	gboolean use_original;	
++
++	if (gtk_widget_is_focus (GTK_WIDGET (entry))) {
++	        return;
++	}
++	
++	use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (entry), "show_original"));
++
++	edit_field_update_internal (entry, 
++				    (use_original ?
++				     window->details->original_files : 
++				     window->details->target_files));
++}
++
++static void
++selinux_combo_update_value (GtkComboBox *combo, const char *new_value)
++{
++    GtkTreeModel *model;
++    GtkTreeIter iter;
++    char *cntx_type;
++    gulong handler;
++
++    g_assert (GTK_IS_COMBO_BOX (combo));
++    if (! new_value)
++	return;
++
++    model = gtk_combo_box_get_model (combo);
++    if (! gtk_tree_model_get_iter_first (model, &iter))
++    	return;
++
++    handler = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (combo), "handler_changed"));
++    g_signal_handler_block (G_OBJECT (combo), handler);
++
++    do {
++    	gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
++    	
++    	if (cntx_type && (g_ascii_strcasecmp (new_value, cntx_type) == 0)) {
++    	    gtk_combo_box_set_active_iter (combo, &iter);
++    	    break;
++    	}
++    }
++    while (gtk_tree_model_iter_next (model, &iter));
++    g_signal_handler_unblock (G_OBJECT (combo), handler);
++}
++
++static void
++popup_field_update_internal (GtkComboBox *combo,
++			     GList *file_list)
++{
++	const char *attr_name;
++	char *attr_value;
++	char *def_attr_value;
++	char *inconsistent_string;
++	char *cntx_type;
++	const char *attr_u;
++	const char *attr_r;
++	const char *attr_t;
++	const char *attr_s;
++	gboolean sensitive;
++	GtkTreeIter iter;
++
++
++	g_assert (GTK_IS_COMBO_BOX (combo));
++
++	if (gtk_widget_is_focus (GTK_WIDGET (combo))) {
++	        return;
++	}
++
++	
++	sensitive = all_can_set_permissions (file_list);
++#ifdef HAVE_SELINUX
++	sensitive = sensitive && is_selinux_enabled ();
++#endif
++	gtk_widget_set_sensitive (GTK_WIDGET (combo), sensitive);
++
++	
++	attr_name = g_object_get_data (G_OBJECT (combo), "file_attribute");
++	inconsistent_string = g_object_get_data (G_OBJECT (combo),
++						 "inconsistent_string");
++	def_attr_value = g_object_get_data (G_OBJECT (combo),
++					    "matchpathcon_cntx");
++	
++	attr_value = file_list_get_string_attribute (file_list, attr_name,
++						     inconsistent_string);
++
++	selinux_split_cntx (attr_value, &attr_u, &attr_r, &attr_t, &attr_s);
++	
++	/* JFIXME: this isn't generic, *sigh* ... */
++	if (gtk_combo_box_get_active_iter (combo, &iter)) {
++		GtkTreeModel *model = gtk_combo_box_get_model (combo);
++
++		/* don't update, if it's identical */
++		gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
++		if (cntx_type && strcmp (cntx_type, attr_t) == 0) {
++			g_free (attr_value);
++			return;
++		}
++	}
++
++	selinux_combo_update_value (combo, attr_t);
++	
++	g_free (attr_value);
++}
++
++static void
++popup_field_update (FMPropertiesWindow *window, GtkComboBox *combo)
++{
++	gboolean use_original;
++
++	if (! window->details->selinux_combo) {
++	        return;
++	}
++	
++	use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "show_original"));
++
++	popup_field_update_internal (combo,
++				     (use_original ?
++				      window->details->original_files : 
++				      window->details->target_files));
++}
++
+ static GtkLabel *
+ attach_label (GtkTable *table,
+ 	      int row,
+@@ -1251,6 +1548,47 @@ attach_value_label (GtkTable *table,
+ 	return attach_label (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE);
+ }
+ 
++#ifdef HAVE_SELINUX
++static GtkEntry *
++attach_edit (GtkTable *table,
++	     int row,
++	     int column,
++	     const char *initial_text,
++	     gboolean right_aligned,
++	     gboolean bold,
++	     gboolean ellipsize_text,
++	     gboolean selectable,
++	     gboolean mnemonic)
++{
++	GtkWidget *entry_field;
++
++	entry_field = nautilus_entry_new ();
++	gtk_entry_set_text (GTK_ENTRY (entry_field), initial_text);
++
++	gtk_entry_set_alignment (GTK_ENTRY (entry_field), right_aligned ? 1 : 0);
++	gtk_widget_show (entry_field);
++	gtk_table_attach (table, entry_field,
++			  column, column + 1,
++			  row, row + 1,
++			  ellipsize_text
++			    ? GTK_FILL | GTK_EXPAND
++			    : GTK_FILL,
++			  0,
++			  0, 0);
++
++	return GTK_ENTRY (entry_field);
++}	      
++
++static GtkEntry *
++attach_edit_label (GtkTable *table,
++		   int row,
++		   int column,
++		   const char *initial_text)
++{
++	return attach_edit (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE);
++}
++#endif
++
+ static GtkLabel *
+ attach_ellipsizing_value_label (GtkTable *table,
+ 				int row,
+@@ -1309,6 +1647,647 @@ attach_value_field (FMPropertiesWindow *
+ 				     FALSE);
+ }
+ 
++static void
++start_long_operation (FMPropertiesWindow *window)
++{
++	if (window->details->long_operation_underway == 0) {
++		/* start long operation */
++		GdkCursor * cursor;
++		
++		cursor = gdk_cursor_new (GDK_WATCH);
++		gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor);
++		gdk_cursor_unref (cursor);
++	}
++	window->details->long_operation_underway ++;
++}
++
++static void
++end_long_operation (FMPropertiesWindow *window)
++{
++	if (gtk_widget_get_window (GTK_WIDGET (window)) != NULL &&
++	    window->details->long_operation_underway == 1) {
++		/* finished !! */
++		gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
++	}
++	window->details->long_operation_underway--;
++}
++
++#ifdef HAVE_SELINUX
++static void
++selinux_change_callback (NautilusFile *file,
++	       GFile         *result_location,
++	       GError        *error,
++	       gpointer       callback_data)
++{
++	FMPropertiesWindow *window;
++	g_assert (callback_data != NULL);
++
++	window = FM_PROPERTIES_WINDOW (callback_data);
++	end_long_operation (window);
++	
++	/* Report the error if it's an error. */
++	fm_report_error_setting_selinux (file, error, NULL);
++
++	g_object_unref (window);
++}
++
++static void
++selinux_done_editing (FMPropertiesWindow *window, char *selinux_context)
++{
++	GList *l;
++	
++	/* Accept changes. */
++	for (l = window->details->target_files; l != NULL; l = l->next) {
++		NautilusFile *file;
++
++		file = NAUTILUS_FILE (l->data);
++
++		start_long_operation (window);
++		g_object_ref (window);
++		nautilus_file_set_selinux_context (file, selinux_context,
++						   selinux_change_callback,
++						   window);
++	}
++}
++
++static gboolean
++selinux_focus_out (NautilusEntry *entry, GdkEventFocus *event, gpointer cb_data)
++{
++	g_assert (NAUTILUS_IS_ENTRY (entry));
++	g_assert (FM_IS_PROPERTIES_WINDOW (cb_data));
++
++	if (gtk_widget_get_state (entry)) {	
++		char *tmp;
++		
++		tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
++		selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp);
++		g_free (tmp);
++	}
++
++	return FALSE;
++}
++
++static void
++selinux_entry_activate (NautilusEntry *entry, gpointer cb_data)
++{
++	char *tmp;
++	
++	g_assert (NAUTILUS_IS_ENTRY (entry));
++	g_assert (FM_IS_PROPERTIES_WINDOW (cb_data));
++
++	tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
++	selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp);
++	g_free (tmp);
++	
++	nautilus_entry_select_all_at_idle (entry);
++}
++
++static void
++selinux_popup_activate (GtkComboBox *comb, gpointer cb_data)
++{
++	char *cntx_type;
++	char *orig_type;
++	const char *attr_u;
++	const char *attr_r;
++	const char *attr_t;
++	const char *attr_s;
++	char *tmp;
++	GtkTreeIter iter;
++	GtkTreeModel *model;
++	
++	g_assert (GTK_IS_COMBO_BOX (comb));
++	g_assert (FM_IS_PROPERTIES_WINDOW (cb_data));
++
++	if (!gtk_combo_box_get_active_iter (comb, &iter)) {
++	        return;
++	} else {
++		model = gtk_combo_box_get_model (comb);
++	        gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
++	}
++	
++	if (!(orig_type = g_object_get_data (G_OBJECT (comb), "original_cntx"))) {
++	        return;
++	}
++	orig_type = g_strdup (orig_type);
++	
++	selinux_split_cntx (orig_type, &attr_u, &attr_r, &attr_t, &attr_s);
++	tmp = g_strjoin (":", attr_u, attr_r, cntx_type, attr_s, NULL);
++	g_free (orig_type);
++	
++	selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp);
++	g_free (tmp);
++}
++
++static char *
++cust_type_next_line (GIOChannel *ioc_ctypes)
++{
++	char *data;
++	gsize term;
++	GError *errc;
++
++	data = NULL;
++	term = 0;
++	errc = NULL;
++	
++	if (G_IO_STATUS_NORMAL == g_io_channel_read_line (ioc_ctypes, &data,
++							  NULL, &term, &errc)) {
++	        data[term] = 0;
++		return data;
++	}
++
++	return NULL;
++}
++#endif
++
++static GSList *
++selinux__type_list (void)
++{
++	static GSList *cust_types;
++	GSList *scan;
++#ifdef HAVE_SELINUX
++	static time_t file_mtime;
++	const char *fname_ctypes;
++	struct stat buf;
++	GIOChannel *ioc_ctypes;
++	GError *errc;
++	int fd;
++#endif
++	
++#ifndef HAVE_SELINUX
++	if (cust_types) {
++	        return cust_types;
++	}
++#else
++	fname_ctypes = selinux_customizable_types_path ();
++	if (cust_types && file_mtime && !stat (fname_ctypes, &buf) &&
++	    (file_mtime == buf.st_mtime)) {
++	        return cust_types;
++	}
++#endif
++
++	if (cust_types) {
++	        for (scan = cust_types; scan; scan = scan->next) {
++		        g_free (scan->data);
++		}
++		g_slist_free (cust_types);
++		cust_types = NULL;
++	}
++	
++	cust_types = g_slist_prepend (cust_types, g_strdup ("tmp_t"));
++	cust_types = g_slist_prepend (cust_types, g_strdup ("user_home_t"));
++	/* cust_types = g_slist_prepend (cust_types, g_strdup ("user_tmp_t")); */
++	
++#ifdef HAVE_SELINUX
++	/* read types, one per line... */
++	fname_ctypes = selinux_customizable_types_path ();
++	errc = NULL;
++	if ((ioc_ctypes = g_io_channel_new_file (fname_ctypes, "r", &errc))) {
++	        char *data = NULL;
++
++		while ((data = cust_type_next_line (ioc_ctypes))) {
++		        cust_types = g_slist_prepend (cust_types, data);
++		}
++
++		fd = g_io_channel_unix_get_fd (ioc_ctypes);
++		if (!fstat (fd, &buf)) {
++			file_mtime = buf.st_mtime;
++		}
++
++		g_io_channel_unref (ioc_ctypes);
++	}
++#endif
++
++	return cust_types;
++}
++
++static void
++attach_selinux_data_edit_field (GtkEntry *entry,
++				char *attr_val, char *def_attr_val)
++{
++	GtkEntryCompletion *comp;
++	GtkCellRenderer *cell;
++	const char *attr_u;
++	const char *attr_r;
++	const char *attr_t;
++	const char *attr_s;
++	const char *dattr_u;
++	const char *dattr_r;
++	const char *dattr_t;
++	const char *dattr_s;
++	GtkListStore *store;
++	GtkTreeIter iter;
++	GSList *scan;
++	int width;
++	int owidth;
++	int twidth;
++	
++	attr_val     = g_strdup (attr_val); /* so we can alter it... */
++	def_attr_val = g_strdup (def_attr_val); /* so we can alter it... */
++	
++	/* do completion, so you don't have to type everything... */
++	comp = gtk_entry_completion_new ();
++	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
++	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
++					      0, GTK_SORT_ASCENDING);
++	
++	gtk_entry_completion_set_model (comp, GTK_TREE_MODEL (store));
++	cell = gtk_cell_renderer_pixbuf_new ();
++	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comp), cell, FALSE);
++	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comp), cell,
++					"stock-id", 1, NULL);
++	gtk_entry_completion_set_text_column (comp, 0);
++	gtk_entry_set_completion (entry, comp);
++
++	 /* FIXME: default doesn't do the right thing, should it? */
++	owidth = gtk_entry_get_width_chars (entry);
++	width = owidth;
++	
++	selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s);
++	dattr_u = dattr_r = dattr_t = dattr_s = NULL;
++	if (def_attr_val) {
++	          selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r,
++				      &dattr_t, &dattr_s);
++	}
++	
++	/* don't do it twice... */
++	if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) {
++	        dattr_t = NULL;
++	}
++
++	if (attr_t && gtk_widget_get_state (entry)) {
++	  /* highlight just the type to the end, so we can easily change it
++	   * FIXME: we also highlight any Sensitivity/MCS but completion will
++	   * let people put it back, and that's the only way we get completion
++	   * at all -- This sucks and we need to remove Sensitivity/MCS from
++	   * the edit box. Yah, more UI. */
++	        int beg =  attr_t      - attr_u;
++		gtk_editable_select_region (GTK_EDITABLE (entry), beg, -1);
++	}
++	
++	for (scan = selinux__type_list(); scan; scan = scan->next) {
++		char *tmp;
++
++		if (attr_t  && !strcmp (attr_t,  scan->data))
++		        continue; /* don't have two entries */
++
++		if (dattr_t && !strcmp (dattr_t, scan->data))
++		        continue; /* don't have two entries */
++
++		gtk_list_store_append (store, &iter);
++		tmp = g_strjoin (":", attr_u, attr_r, scan->data, attr_s, NULL);
++		gtk_list_store_set (store, &iter, 0, tmp, -1);
++
++		twidth = strlen (tmp);
++		width = MAX (twidth, width);
++		
++		g_free (tmp);
++	}
++
++	if (dattr_t) {
++		char *tmp;
++
++		gtk_list_store_append (store, &iter);
++		tmp = g_strjoin (":", dattr_u, dattr_r, dattr_t, dattr_s, NULL);
++		gtk_list_store_set (store, &iter, 0, tmp,
++				    1, GTK_STOCK_HOME, -1);
++
++		twidth = strlen (tmp);
++		width = MAX (twidth, width);
++
++		g_free (tmp);
++	}
++
++	if (attr_t) {
++		char *tmp;
++
++		gtk_list_store_append (store, &iter);
++		tmp = g_strjoin (":", attr_u, attr_r, attr_t, attr_s, NULL);
++		gtk_list_store_set (store, &iter, 0, tmp, 1, GTK_STOCK_OK, -1);
++
++		twidth = strlen (tmp);
++		width = MAX (twidth, width);
++
++		g_free (tmp);
++	}
++
++	g_free (attr_val);
++	g_free (def_attr_val);
++	g_object_unref (G_OBJECT (store));	
++	g_object_unref (G_OBJECT (comp));
++
++	if (width != owidth) {
++	        gtk_entry_set_width_chars (entry, width + 2);
++	}
++}
++
++#ifdef HAVE_SELINUX
++
++# define HACK_TYPE(x, y)				\
++	else if (!strcmp (nice_type, x)) nice_type = y
++
++/* hack to convert a selinux_context type into a readable string for the
++   user */
++static const char *
++selinux__hack_conv_type (const char *type)
++{ /* FIXME: hack attack, but nowhere else to put it. Because mathpathcon
++   * here now probably want a bunch of other types? */
++        const char *nice_type;
++
++	nice_type = type;
++	
++	if (0) { }
++	
++	HACK_TYPE("cupsd_etc_t", _("CUPS printer configuration"));
++	HACK_TYPE("cupsd_rw_etc_t", _("CUPS printer configuration (rw)"));
++	HACK_TYPE("cupsd_tmp_t", _("CUPS temporary data"));
++	HACK_TYPE("dhcp_etc_t", _("DHCP configuration"));
++	HACK_TYPE("dictd_etc_t", _("Dictd configuration"));
++	HACK_TYPE("dnssec_t", _("DNS secret"));
++	HACK_TYPE("etc_t", _("System configuration"));
++	HACK_TYPE("etc_aliases_t", _("Email aliases configuration"));
++	HACK_TYPE("etc_runtime_t", _("System configuration (rw)"));
++	HACK_TYPE("cvs_data_t", _("Read and write from CVS daemon"));
++	HACK_TYPE("httpd_config_t", _("Apache-httpd configuration"));
++	HACK_TYPE("httpd_php_tmp_t",
++		  _("Apache-httpd PHP module temporary data"));
++	HACK_TYPE("httpd_sys_content_t",
++		  _("Read from all httpd scripts and the daemon"));
++	HACK_TYPE("httpd_sys_htaccess_t",
++		  _("Apache-httpd .htaccess configuration"));
++	HACK_TYPE("httpd_sys_script_exec_t",
++		  _("CGI programs with default access"));
++	HACK_TYPE("httpd_sys_script_ra_t",
++		  _("CGI programs can read and append"));
++	HACK_TYPE("httpd_sys_script_ro_t",
++		  _("CGI programs can read"));
++	HACK_TYPE("httpd_sys_script_rw_t",
++		  _("CGI programs can read and write"));
++	HACK_TYPE("httpd_unconfined_script_exec_t",
++		  _("CGI programs without any SELinux protection"));
++	HACK_TYPE("httpd_tmp_t", _("Apache-httpd temporary data"));
++	HACK_TYPE("ice_tmp_t", _("ICE temporary data"));
++	HACK_TYPE("locale_t", _("Locale data"));
++	HACK_TYPE("mysql_tmp_t", _("MySQL temporary data"));
++	HACK_TYPE("named_conf_t", _("Nameserver configuration"));
++	HACK_TYPE("net_conf_t", _("Network configuration"));
++	HACK_TYPE("postgresql_tmp_t", _("Postgresql temporary data"));
++	HACK_TYPE("public_content_rw_t",
++		  _("Read and write from CIFS/ftp/http/nfs/rsync"));
++	HACK_TYPE("public_content_t", _("Read from CIFS/ftp/http/nfs/rsync"));
++	HACK_TYPE("samba_etc_t", _("Samba configuration"));
++	HACK_TYPE("samba_share_t", _("Shared via CIFS (samba)"));
++	HACK_TYPE("staff_home_t", _("Staff user data"));
++	HACK_TYPE("staff_home_dir_t", _("Staff user home directory"));
++	HACK_TYPE("swapfile_t", _("System swapfile"));
++	HACK_TYPE("sysadm_home_t", _("Sysadmin user data"));
++	HACK_TYPE("sysadm_home_dir_t", _("Sysadmin user home directory"));
++	HACK_TYPE("system_cron_spool_t", _("Cron data"));
++	HACK_TYPE("tmp_t", _("Temporary data"));
++	HACK_TYPE("user_tmp_t", _("User temporary data"));
++	HACK_TYPE("user_home_t", _("User data"));
++	HACK_TYPE("user_home_dir_t", _("User home directory"));
++	HACK_TYPE("var_log_t", _("Logfile"));
++	HACK_TYPE("xen_image_t", _("Xen image"));
++	
++	return nice_type;
++}
++#undef HACK_TYPE
++
++static void
++attach_selinux_data_popup_field (GtkComboBox *comb,
++				 char *attr_val,
++				 char *def_attr_val)
++{
++	const char *attr_u;
++	const char *attr_r;
++	const char *attr_t;
++	const char *attr_s;
++	const char *dattr_u;
++	const char *dattr_r;
++	const char *dattr_t;
++	const char *dattr_s;
++	GtkListStore *store;
++	GtkTreeIter iter;
++	GSList *scan;
++	
++	attr_val     = g_strdup (attr_val); /* so we can alter it... */
++	def_attr_val = g_strdup (def_attr_val);
++
++	/* do completion, so you don't have to type everything... */
++	store = gtk_list_store_new (3, G_TYPE_STRING,
++				    G_TYPE_STRING, G_TYPE_STRING);
++	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
++					      1, GTK_SORT_ASCENDING);
++	
++	gtk_combo_box_set_model (comb, GTK_TREE_MODEL (store));
++
++	selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s);
++	dattr_u = dattr_r = dattr_t = dattr_s = NULL;
++	if (def_attr_val) {
++	          selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r,
++				      &dattr_t, &dattr_s);
++	}
++	/* don't do it twice... */
++	if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) {
++	        dattr_t = NULL;
++	}
++
++	for (scan = selinux__type_list(); scan; scan = scan->next) {
++		const char *nice_type;
++		
++		if (attr_t  && !strcmp (attr_t,  scan->data))
++		        continue; /* don't have two entries */
++
++		if (dattr_t && !strcmp (dattr_t, scan->data))
++		        continue; /* don't have two entries */
++
++		nice_type = selinux__hack_conv_type(scan->data);
++		
++		gtk_list_store_append (store, &iter);
++		gtk_list_store_set (store, &iter, 0, scan->data,
++				    1, nice_type, -1);
++	}
++
++	if (dattr_t) {
++		const char *nice_type;
++		
++		gtk_list_store_append (store, &iter);
++		nice_type = selinux__hack_conv_type(dattr_t);
++	        gtk_list_store_set (store, &iter, 0, dattr_t, 1, nice_type,
++				    2, GTK_STOCK_HOME, -1);
++	}
++
++	if (attr_t) {
++		const char *nice_type;
++		
++		gtk_list_store_append (store, &iter);
++		nice_type = selinux__hack_conv_type(attr_t);
++	        gtk_list_store_set (store, &iter, 0,  attr_t, 1, nice_type,
++				    2, GTK_STOCK_OK, -1);
++		gtk_combo_box_set_active_iter (comb, &iter);
++	}
++
++	g_free (attr_val);
++	g_free (def_attr_val);
++	g_object_unref (G_OBJECT (store));
++}
++
++static char *
++selinux__matchpathcon (GList *file_list)
++{
++	GList *scan;
++
++        for (scan = file_list; scan != NULL; scan = scan->next) {
++	        NautilusFile *file;
++
++		file = NAUTILUS_FILE (scan->data);
++		if (!nautilus_file_is_gone (file)) {
++		        return nautilus_file_get_selinux_matchpathcon (file);
++		}
++	}
++
++	return NULL;
++}
++
++static void
++attach_selinux_edit_field (FMPropertiesWindow *window,
++			   GtkTable *table,
++			   int row,
++			   int column,
++			   const char *file_attribute_name,
++			   const char *inconsistent_string,
++			   gboolean show_original,
++			   GtkLabel *lab_title)
++{
++	GtkEntry *entry;
++	GList *file_list;
++	char *attr_value;
++	char *def_attr_value;
++	
++	if (show_original) {
++	        file_list = window->details->original_files;
++	} else {
++	        file_list = window->details->target_files;
++	}
++	
++	attr_value = file_list_get_string_attribute (file_list, 
++						     file_attribute_name,
++						     inconsistent_string);
++	if ( strcmp (attr_value, inconsistent_string) &&
++	    !strcmp (file_attribute_name, "selinux_context")) {
++	        def_attr_value = selinux__matchpathcon (file_list);
++	} else {
++	        def_attr_value = NULL;
++	}
++	
++	entry = attach_edit_label (table, row, column, attr_value);
++	gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title),
++				       GTK_WIDGET (entry));
++
++  	/* Stash a copy of the file attribute name in this field for the callback's sake. */
++	g_object_set_data_full (G_OBJECT (entry), "file_attribute",
++				g_strdup (file_attribute_name), g_free);
++
++	g_object_set_data_full (G_OBJECT (entry), "inconsistent_string",
++				g_strdup (inconsistent_string), g_free);
++
++	g_object_set_data (G_OBJECT (entry), "show_original", GINT_TO_POINTER (show_original));
++	g_object_set_data (G_OBJECT (entry), "ellipsize_text", GINT_TO_POINTER (FALSE));
++
++	g_signal_connect_object (entry, "focus_out_event",
++				 G_CALLBACK (selinux_focus_out), window, 0);
++	g_signal_connect_object (entry, "activate",
++				 G_CALLBACK (selinux_entry_activate), window,0);
++
++	attach_selinux_data_edit_field (entry, attr_value, def_attr_value);
++	
++	g_object_set_data_full (G_OBJECT (entry), "original_cntx", attr_value,
++				g_free);
++
++	g_object_set_data_full (G_OBJECT (entry), "matchpathcon_cntx",
++				def_attr_value, g_free);
++
++	window->details->edit_fields = g_list_prepend (window->details->edit_fields,
++						       entry);
++}
++
++static void
++attach_selinux_popup_field (FMPropertiesWindow *window,
++			    GtkTable *table,
++			    int row,
++			    int column,
++			    const char *file_attribute_name,
++			    const char *inconsistent_string,
++			    gboolean show_original,
++			    GtkLabel *lab_title)
++{
++	GtkWidget *comb;
++	GtkCellRenderer *cell;
++	GList *file_list;
++	char *attr_value;
++	char *def_attr_value;
++	gulong handler;
++	
++	if (show_original) {
++	        file_list = window->details->original_files;
++	} else {
++	        file_list = window->details->target_files;
++	}
++	
++	attr_value = file_list_get_string_attribute (file_list, 
++						     file_attribute_name,
++						     inconsistent_string);
++	if ( strcmp (attr_value, inconsistent_string) &&
++	    !strcmp (file_attribute_name, "selinux_context")) {
++	        def_attr_value = selinux__matchpathcon (file_list);	
++	} else {
++	        def_attr_value = NULL;
++	}
++	
++	comb = gtk_combo_box_new ();
++	
++	gtk_table_attach (table, comb, column, column + 1, row, row + 1,
++			  GTK_FILL, 0, 0, 0);
++
++	
++	gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), comb);
++
++  	/* Stash a copy of the file attribute name in this field for the callback's sake. */
++	g_object_set_data_full (G_OBJECT (comb), "file_attribute",
++				g_strdup (file_attribute_name), g_free);
++
++	g_object_set_data (G_OBJECT (comb), "show_original", GINT_TO_POINTER (show_original));
++
++	g_object_set_data_full (G_OBJECT (comb), "original_cntx", attr_value,
++				g_free);
++
++	g_object_set_data_full (G_OBJECT (comb), "matchpathcon_cntx",
++				def_attr_value, g_free);
++
++	cell = gtk_cell_renderer_pixbuf_new ();
++	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE);
++	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell,
++					"stock-id", 2, NULL);
++	cell = gtk_cell_renderer_text_new ();
++	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE);
++	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell,
++					"text", 1, NULL);
++	gtk_widget_show (comb);
++
++	attach_selinux_data_popup_field (GTK_COMBO_BOX (comb),
++					 attr_value, def_attr_value);
++
++	handler = g_signal_connect_object (comb, "changed",
++				 G_CALLBACK (selinux_popup_activate), window, 0);
++	g_object_set_data (G_OBJECT (comb), "handler_changed", GUINT_TO_POINTER (handler));
++
++	g_assert (! window->details->selinux_combo);
++	
++	window->details->selinux_combo = 
++		g_list_prepend (window->details->selinux_combo, comb);
++}
++#endif
++
+ static GtkWidget*
+ attach_ellipsizing_value_field (FMPropertiesWindow *window,
+ 				GtkTable *table,
+@@ -2302,6 +3281,37 @@ append_title_value_pair (FMPropertiesWin
+ 	return last_row;
+ }
+ 
++#ifdef HAVE_SELINUX
++static guint
++append_title_selinux_edit_pair (FMPropertiesWindow *window,
++				GtkTable *table,
++				const char *title, 
++				const char *file_attribute_name,
++				const char *inconsistent_state,
++				gboolean show_original)
++{
++	guint last_row;
++	GtkLabel *lab_title;
++
++	lab_title = NULL;
++	last_row = append_title_field (table, title, &lab_title);
++
++	if (window->details->advanced_permissions) {
++	        attach_selinux_edit_field (window, table, last_row,
++					   VALUE_COLUMN, file_attribute_name,
++					   inconsistent_state,
++					   show_original, lab_title);
++	} else {
++	        attach_selinux_popup_field (window, table, last_row,
++					    VALUE_COLUMN, file_attribute_name,
++					    inconsistent_state,
++					    show_original, lab_title);	  
++	}
++	
++	return last_row;
++}
++#endif
++
+ static guint
+ append_title_and_ellipsizing_value (FMPropertiesWindow *window,
+ 				    GtkTable *table,
+@@ -3230,31 +4240,6 @@ files_has_file (FMPropertiesWindow *wind
+ }
+ 
+ static void
+-start_long_operation (FMPropertiesWindow *window)
+-{
+-	if (window->details->long_operation_underway == 0) {
+-		/* start long operation */
+-		GdkCursor * cursor;
+-		
+-		cursor = gdk_cursor_new (GDK_WATCH);
+-		gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor);
+-		gdk_cursor_unref (cursor);
+-	}
+-	window->details->long_operation_underway ++;
+-}
+-
+-static void
+-end_long_operation (FMPropertiesWindow *window)
+-{
+-	if (gtk_widget_get_window (GTK_WIDGET (window)) != NULL &&
+-	    window->details->long_operation_underway == 1) {
+-		/* finished !! */
+-		gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
+-	}
+-	window->details->long_operation_underway--;
+-}
+-
+-static void
+ permission_change_callback (NautilusFile *file,
+ 			    GFile *res_loc,
+ 			    GError *error,
+@@ -4037,39 +5022,6 @@ append_special_execution_flags (FMProper
+ 	gtk_table_set_row_spacing (table, nrows - 1, 18);
+ }
+ 
+-static gboolean
+-all_can_get_permissions (GList *file_list)
+-{
+-	GList *l;
+-	for (l = file_list; l != NULL; l = l->next) {
+-		NautilusFile *file;
+-		
+-		file = NAUTILUS_FILE (l->data);
+-		
+-		if (!nautilus_file_can_get_permissions (file)) {
+-			return FALSE;
+-		}
+-	}
+-
+-	return TRUE;
+-}
+-
+-static gboolean
+-all_can_set_permissions (GList *file_list)
+-{
+-	GList *l;
+-	for (l = file_list; l != NULL; l = l->next) {
+-		NautilusFile *file;
+-		
+-		file = NAUTILUS_FILE (l->data);
+-
+-		if (!nautilus_file_can_set_permissions (file)) {
+-			return FALSE;
+-		}
+-	}
+-
+-	return TRUE;
+-}
+ 
+ static GHashTable *
+ get_initial_permissions (GList *file_list)
+@@ -4417,7 +5369,9 @@ apply_recursive_clicked (GtkWidget *recu
+ 	guint32 file_permission, file_permission_mask;
+ 	guint32 dir_permission, dir_permission_mask;
+ 	guint32 vfs_mask, vfs_new_perm, p;
+-	GtkWidget *button, *combo;
++	char *context; 
++	GtkWidget *button; 
++	GtkComboBox *combo; 
+ 	gboolean active, is_folder, is_special, use_original;
+ 	GList *l;
+ 	GtkTreeModel *model;
+@@ -4461,9 +5415,9 @@ apply_recursive_clicked (GtkWidget *recu
+ 	}
+ 	/* Simple mode, minus exec checkbox */
+ 	for (l = window->details->permission_combos; l != NULL; l = l->next) {
+-		combo = l->data;
++		combo = GTK_COMBO_BOX (l->data);
+ 		
+-		if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo),  &iter)) {
++		if (!gtk_combo_box_get_active_iter (combo,  &iter)) {
+ 			continue;
+ 		}
+ 		
+@@ -4471,7 +5425,7 @@ apply_recursive_clicked (GtkWidget *recu
+ 		is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo),
+ 								"is-folder"));
+ 		
+-		model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
++		model = gtk_combo_box_get_model (combo);
+ 		gtk_tree_model_get (model, &iter, 1, &new_perm, 2, &use_original, -1);
+ 		if (use_original) {
+ 			continue;
+@@ -4494,12 +5448,53 @@ apply_recursive_clicked (GtkWidget *recu
+ 		}
+ 	}
+ 
++	/* get the SELinux context... */
++	context = NULL;
++	if (window->details->advanced_permissions &&
++	    window->details->edit_fields) { /* advanced mode */
++		GtkEditable *efield;
++
++		efield = window->details->edit_fields->data;
++	        context = gtk_editable_get_chars (GTK_EDITABLE (efield), 0, -1);
++	} else if (!window->details->advanced_permissions &&
++		   window->details->selinux_combo) { /* simple mode */
++	        char *cntx_type;
++	        char *orig_type;
++	        const char *attr_u;
++	        const char *attr_r;
++	        const char *attr_t;
++	        const char *attr_s;
++	  
++		combo = GTK_COMBO_BOX (window->details->selinux_combo->data);
++	        
++	        if (!gtk_combo_box_get_active_iter (combo, &iter)) {
++		        return;
++		} else {
++		        GtkTreeModel *model = gtk_combo_box_get_model (combo);
++			gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
++		}
++		if (!(orig_type = g_object_get_data (G_OBJECT (combo),
++						     "original_cntx"))) {
++		        return;
++		}
++		
++		orig_type = g_strdup (orig_type);
++	
++		selinux_split_cntx (orig_type,
++				    &attr_u, &attr_r, &attr_t, &attr_s);
++		context = g_strjoin (":",
++				     attr_u, attr_r, cntx_type, attr_s, NULL);
++		g_free (orig_type);
++	}
++	
+ 	for (l = window->details->target_files; l != NULL; l = l->next) {
+ 		NautilusFile *file;
+ 		char *uri;
+ 
+ 		file = NAUTILUS_FILE (l->data);
+ 
++		/* assume permissions setting allows context setting...
++		 * we can't really do much else due to race conditions anyway */
+ 		if (nautilus_file_is_directory (file) &&
+ 		    nautilus_file_can_set_permissions (file)) {
+ 			uri = nautilus_file_get_uri (file);
+@@ -4510,11 +5505,13 @@ apply_recursive_clicked (GtkWidget *recu
+ 								 file_permission_mask,
+ 								 dir_permission,
+ 								 dir_permission_mask,
++								 context,
+ 								 set_recursive_permissions_done,
+ 								 window);
+ 			g_free (uri);
+ 		}
+ 	}
++	g_free (context);
+ }
+ 
+ static void
+@@ -4565,10 +5562,16 @@ create_permissions_page (FMPropertiesWin
+ 		gtk_table_set_row_spacing (page_table, nrows - 1, 18);
+ 	
+ #ifdef HAVE_SELINUX
+-		append_title_value_pair
+-			(window, page_table, _("SELinux context:"), 
+-			 "selinux_context", INCONSISTENT_STATE_STRING,
+-			 FALSE);
++		if (!is_multi_file_window (window) || multi_have_same_selinux_context (window)) 
++			append_title_selinux_edit_pair (window, page_table, 
++							_("_SELinux Context:"),  
++							"selinux_context", INCONSISTENT_STATE_STRING,
++							FALSE); 
++		else /* Static text in this case. */ 
++			append_title_value_pair (window, page_table, 
++						 _("_SELinux Context:"),  
++						 "selinux_context", INCONSISTENT_STATE_STRING,
++						 FALSE); 
+ #endif
+ 		append_title_value_pair
+ 			(window, page_table, _("Last changed:"), 


More information about the scm-commits mailing list