3858601
--- nautilus-2.19.2/src/file-manager/fm-error-reporting.c.selinux	2007-04-03 06:08:04.000000000 -0400
3858601
+++ nautilus-2.19.2/src/file-manager/fm-error-reporting.c	2007-05-19 22:20:22.000000000 -0400
3858601
@@ -252,6 +252,38 @@ fm_report_error_setting_permissions (Nau
3858601
 	g_free (message);
3858601
 }		
25ecefe
 
3858601
+void
3858601
+fm_report_error_setting_selinux (NautilusFile *file,
3858601
+				 GnomeVFSResult error,
3858601
+				 GtkWindow *parent_window)
25ecefe
+{
3858601
+	char *file_name;
3858601
+	char *message;
25ecefe
+
3858601
+	if (error == GNOME_VFS_OK) {
3858601
+		return;
25ecefe
+	}
25ecefe
+
3858601
+	file_name = nautilus_file_get_display_name (file);
3858601
+
3858601
+	switch (error) {
3858601
+	case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM:
3858601
+		message = g_strdup_printf (_("Couldn't change the SELinux security context of \"%s\" because it is on a read-only disk"),
3858601
+					   file_name);
3858601
+		break;
3858601
+	default:
3858601
+		/* We should invent decent error messages for every case we actually experience. */
3858601
+		g_warning ("Hit unhandled case %d (%s) in fm_report_error_setting_permissions", 
3858601
+			   error, gnome_vfs_result_to_string (error));
3858601
+		message = g_strdup_printf (_("Sorry, couldn't change the permissions of \"%s\"."), file_name);
25ecefe
+	}
3858601
+
3858601
+	eel_show_error_dialog (_("The SELinux security context could not be changed."), message, parent_window);
3858601
+
3858601
+	g_free (file_name);
3858601
+	g_free (message);
25ecefe
+}
25ecefe
+
3858601
 typedef struct _FMRenameData {
3858601
 	char *name;
3858601
 	NautilusFileOperationCallback callback;
3858601
--- nautilus-2.19.2/src/file-manager/fm-error-reporting.h.selinux	2007-04-03 06:08:04.000000000 -0400
3858601
+++ nautilus-2.19.2/src/file-manager/fm-error-reporting.h	2007-05-19 22:20:22.000000000 -0400
3858601
@@ -39,7 +39,10 @@ void fm_report_error_renaming_file      
3858601
 					  GnomeVFSResult  error_code,
3858601
 					  GtkWindow	 *parent_window);
3858601
 void fm_report_error_setting_permissions (NautilusFile   *file,
3858601
-					  GnomeVFSResult  error_code,			    
3858601
+					  GnomeVFSResult  error_code,
3858601
+					  GtkWindow	 *parent_window);
3858601
+void fm_report_error_setting_selinux     (NautilusFile   *file,
3858601
+					  GnomeVFSResult  error_code,
3858601
 					  GtkWindow	 *parent_window);
3858601
 void fm_report_error_setting_owner       (NautilusFile   *file,
3858601
 					  GnomeVFSResult  error_code,  
3858601
--- nautilus-2.19.2/src/file-manager/fm-properties-window.c.selinux	2007-05-02 08:40:07.000000000 -0400
3858601
+++ nautilus-2.19.2/src/file-manager/fm-properties-window.c	2007-05-19 22:22:52.000000000 -0400
3858601
@@ -111,6 +111,10 @@
3858601
 #define FREE_STROKE_G  0.396078431
3858601
 #define FREE_STROKE_B  0.643137255
3858601
 
3858601
+#ifdef HAVE_SELINUX
3858601
+# include <selinux/selinux.h>
3858601
+#endif
3858601
+
3858601
 #define PREVIEW_IMAGE_WIDTH 96
3858601
 
3858601
 #define ROW_PAD 6
3858601
@@ -130,7 +134,7 @@ struct FMPropertiesWindowDetails {	
3858601
 
3858601
 	GtkWidget *icon_button;
3858601
 	GtkWidget *icon_image;
3858601
-	GtkWidget *icon_chooser;
3858601
+        GtkWidget *icon_chooser;
3858601
 
3858601
 	GtkWidget *name_label;
3858601
 	GtkWidget *name_field;
3858601
@@ -152,12 +156,15 @@ struct FMPropertiesWindowDetails {	
3858601
 	unsigned int  owner_change_timeout;
3858601
 
3858601
 	GList *permission_buttons;
3858601
-	GList *permission_combos;
3858601
+	GList *permission_combos; /* how is this deallocated???? */
3858601
+	GList *selinux_combo;
3858601
 	GHashTable *initial_permissions;
3858601
 	gboolean has_recursive_apply;
3858601
 
3858601
 	GList *value_fields;
3858601
 
3858601
+	GList *edit_fields;
3858601
+
3858601
 	GList *mime_list;
3858601
 
3858601
 	gboolean deep_count_finished;
3858601
@@ -239,6 +246,10 @@ static void permission_combo_update     
3858601
 						   GtkComboBox        *combo);
3858601
 static void value_field_update                    (FMPropertiesWindow *window,
3858601
 						   GtkLabel           *field);
3858601
+static void edit_field_update                     (FMPropertiesWindow *window,
3858601
+						   GtkEntry           *field);
3858601
+static void popup_field_update                    (FMPropertiesWindow *window,
3858601
+						   GtkComboBox        *entry);
3858601
 static void properties_window_update              (FMPropertiesWindow *window,
3858601
 						   GList              *files);
3858601
 static void is_directory_ready_callback           (NautilusFile       *file,
3858601
@@ -269,9 +280,31 @@ static GtkLabel *attach_ellipsizing_valu
3858601
 						   
3858601
 static GtkWidget* create_pie_widget 		  (FMPropertiesWindow *window);
3858601
 
3858601
+static void attach_selinux_data_edit_field        (GtkEntry *entry,
3858601
+						   char *attr_value,
3858601
+						   char *def_attr_value);
3858601
+static void attach_selinux_data_popup_field       (GtkComboBox *comb,
3858601
+						   char *attr_val,
3858601
+						   char *def_attr_val);
3858601
+
3858601
 G_DEFINE_TYPE (FMPropertiesWindow, fm_properties_window, GTK_TYPE_WINDOW);
3858601
 #define parent_class fm_properties_window_parent_class 
3858601
 
25ecefe
+static void
3858601
+maybe_gtk_entry_set_text (GtkEntry *entry, const char *val)
25ecefe
+{
3858601
+	char *old_val;
3858601
+
3858601
+	g_assert (GTK_IS_ENTRY (entry));
3858601
+
3858601
+	old_val = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
3858601
+
3858601
+	if (strcmp (old_val, val) != 0) {
3858601
+		gtk_entry_set_text (entry, val);
3858601
+	}
3858601
+	g_free(old_val);
25ecefe
+}
25ecefe
+
3858601
 static gboolean
3858601
 is_multi_file_window (FMPropertiesWindow *window)
3858601
 {
3858601
@@ -292,6 +325,39 @@ is_multi_file_window (FMPropertiesWindow
3858601
 	return FALSE;
3858601
 }
3858601
 
3858601
+static gboolean
3858601
+multi_have_same_selinux_context (FMPropertiesWindow *window)
25ecefe
+{
3858601
+	GList *l;
3858601
+        char *cntx;
25ecefe
+
3858601
+	cntx = NULL;
3858601
+	for (l = window->details->original_files; l != NULL; l = l->next) {
3858601
+		NautilusFile *file;
25ecefe
+
3858601
+		file = NAUTILUS_FILE (l->data);
3858601
+		if (!nautilus_file_is_gone (file)) {
3858601
+		        char *tmp;
25ecefe
+
3858601
+			tmp = nautilus_file_get_string_attribute_with_default (file, "selinux_context");
3858601
+		        if (!cntx) {
3858601
+			         cntx = tmp;
3858601
+			} else if (strcmp (cntx, tmp)) {
3858601
+				 g_free (tmp);
3858601
+				 g_free (cntx);
3858601
+				 return FALSE;
3858601
+			}
3858601
+			else {
3858601
+			         g_free (tmp);
3858601
+			}
3858601
+		}
25ecefe
+	}
25ecefe
+
3858601
+	g_free (cntx);
3858601
+	
3858601
+	return TRUE;
25ecefe
+}
25ecefe
+
3858601
 static int
3858601
 get_not_gone_original_file_count (FMPropertiesWindow *window)
25ecefe
 {
3858601
@@ -529,7 +595,7 @@ fm_properties_window_drag_data_received 
3858601
 		return;
3858601
 	}
25ecefe
 	
3858601
-	uris = g_strsplit (selection_data->data, "\r\n", 0);
3858601
+	uris = g_strsplit ((char *) selection_data->data, "\r\n", 0);
3858601
 	exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0');
25ecefe
 
3858601
 
3858601
@@ -610,7 +676,7 @@ create_image_widget (FMPropertiesWindow 
25ecefe
 
25ecefe
 static void
3858601
 set_name_field (FMPropertiesWindow *window, const gchar *original_name,
3858601
-					 const gchar *name)
3858601
+		const gchar *name)
3858601
 {
3858601
 	gboolean new_widget;
3858601
 	gboolean use_label;
3858601
@@ -676,11 +742,7 @@ set_name_field (FMPropertiesWindow *wind
3858601
 			 * currently showing. This causes minimal ripples (e.g.
3858601
 			 * selection change).
3858601
 			 */
3858601
-			gchar *displayed_name = gtk_editable_get_chars (GTK_EDITABLE (window->details->name_field), 0, -1);
3858601
-			if (strcmp (displayed_name, name) != 0) {
3858601
-				gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name);
3858601
-			}
3858601
-			g_free (displayed_name);
3858601
+		        maybe_gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name);
25ecefe
 		}
25ecefe
 	}
3858601
 }
3858601
@@ -756,7 +818,6 @@ static void
3858601
 name_field_restore_original_name (NautilusEntry *name_field)
3858601
 {
3858601
 	const char *original_name;
3858601
-	char *displayed_name;
25ecefe
 
3858601
 	original_name = (const char *) g_object_get_data (G_OBJECT (name_field),
3858601
 							  "original_name");
3858601
@@ -765,14 +826,8 @@ name_field_restore_original_name (Nautil
3858601
 		return;
25ecefe
 	}
25ecefe
 
3858601
-	displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1);
25ecefe
-
3858601
-	if (strcmp (original_name, displayed_name) != 0) {
3858601
-		gtk_entry_set_text (GTK_ENTRY (name_field), original_name);
3858601
-	}
3858601
+	maybe_gtk_entry_set_text (GTK_ENTRY (name_field), original_name);
3858601
 	nautilus_entry_select_all (name_field);
3858601
-
3858601
-	g_free (displayed_name);
3858601
 }
3858601
 
3858601
 static void
3858601
@@ -885,7 +940,7 @@ file_has_keyword (NautilusFile *file, co
3858601
 	word = g_list_find_custom (keywords, keyword, (GCompareFunc) strcmp);
3858601
 	eel_g_list_free_deep (keywords);
25ecefe
 	
3858601
-	return (word != NULL);
3858601
+	return word != NULL;
3858601
 }
25ecefe
 
3858601
 static void
3858601
@@ -1152,7 +1207,7 @@ mime_list_equal (GList *a, GList *b)
3858601
 		b = b->next;
25ecefe
 	}
25ecefe
 
3858601
-	return (a == b);
3858601
+	return a == b;
3858601
 }
25ecefe
 
3858601
 static GList *
3858601
@@ -1234,6 +1289,14 @@ properties_window_update (FMPropertiesWi
3858601
 		for (l = window->details->value_fields; l != NULL; l = l->next) {
3858601
 			value_field_update (window, GTK_LABEL (l->data));
3858601
 		}
3858601
+		
3858601
+		for (l = window->details->edit_fields; l != NULL; l = l->next) {
3858601
+			edit_field_update (window, GTK_ENTRY (l->data));
3858601
+		}
3858601
+		
3858601
+		for (l = window->details->selinux_combo; l != NULL; l = l->next) {
3858601
+		        popup_field_update (window, GTK_COMBO_BOX (l->data));
3858601
+		}		
25ecefe
 	}
25ecefe
 
3858601
 	mime_list = get_mime_list (window);
3858601
@@ -1403,6 +1466,111 @@ value_field_update (FMPropertiesWindow *
3858601
 				      window->details->target_files));
3858601
 }
25ecefe
 
3858601
+static void
3858601
+edit_field_update_internal (GtkEntry *entry, 
3858601
+			    GList *file_list)
25ecefe
+{
25ecefe
+	const char *attr_name;
25ecefe
+	char *attr_value;
25ecefe
+	char *def_attr_value;
25ecefe
+	char *inconsistent_string;
25ecefe
+	
25ecefe
+	g_assert (GTK_IS_ENTRY (entry));
25ecefe
+
25ecefe
+	attr_name = g_object_get_data (G_OBJECT (entry), "file_attribute");
25ecefe
+	inconsistent_string = g_object_get_data (G_OBJECT (entry),
25ecefe
+						 "inconsistent_string");
25ecefe
+	def_attr_value = g_object_get_data (G_OBJECT (entry),
25ecefe
+					    "matchpathcon_cntx");
25ecefe
+	
25ecefe
+	attr_value = file_list_get_string_attribute (file_list, attr_name,
25ecefe
+						     inconsistent_string);
25ecefe
+
25ecefe
+	maybe_gtk_entry_set_text (GTK_ENTRY (entry), attr_value);
25ecefe
+
25ecefe
+	/* JFIXME: this isn't generic, *sigh* ... */
25ecefe
+	attach_selinux_data_edit_field (entry, attr_value, def_attr_value);
25ecefe
+	g_free (attr_value);
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+edit_field_update (FMPropertiesWindow *window, GtkEntry *entry)
25ecefe
+{
25ecefe
+	gboolean use_original;	
25ecefe
+
25ecefe
+	if (gtk_widget_is_focus (GTK_WIDGET (entry))) {
25ecefe
+	        return;
25ecefe
+	}
25ecefe
+	
25ecefe
+	use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (entry), "show_original"));
25ecefe
+
25ecefe
+	edit_field_update_internal (entry, 
25ecefe
+				    (use_original ?
25ecefe
+				     window->details->original_files : 
25ecefe
+				     window->details->target_files));
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+popup_field_update_internal (GtkComboBox *combo,
25ecefe
+			     GList *file_list)
25ecefe
+{
25ecefe
+	const char *attr_name;
25ecefe
+	char *attr_value;
25ecefe
+	char *def_attr_value;
25ecefe
+	char *inconsistent_string;
25ecefe
+	char *cntx_type;
25ecefe
+	GtkTreeIter iter;
25ecefe
+	
25ecefe
+	g_assert (GTK_IS_COMBO_BOX (combo));
25ecefe
+
25ecefe
+	if (gtk_widget_is_focus (GTK_WIDGET (combo))) {
25ecefe
+	        return;
25ecefe
+	}
25ecefe
+	
25ecefe
+	attr_name = g_object_get_data (G_OBJECT (combo), "file_attribute");
25ecefe
+	inconsistent_string = g_object_get_data (G_OBJECT (combo),
25ecefe
+						 "inconsistent_string");
25ecefe
+	def_attr_value = g_object_get_data (G_OBJECT (combo),
25ecefe
+					    "matchpathcon_cntx");
25ecefe
+	
25ecefe
+	attr_value = file_list_get_string_attribute (file_list, attr_name,
25ecefe
+						     inconsistent_string);
25ecefe
+
25ecefe
+	/* JFIXME: this isn't generic, *sigh* ... */
25ecefe
+
25ecefe
+	if (gtk_combo_box_get_active_iter (combo, &iter)) {
25ecefe
+	        GtkTreeModel *model = gtk_combo_box_get_model (combo);
25ecefe
+
25ecefe
+		/* don't update, if it's identical */
25ecefe
+		gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
25ecefe
+		if (cntx_type && strcmp (cntx_type, attr_value) == 0) {
25ecefe
+			g_free (attr_value);
25ecefe
+		        return;
25ecefe
+		}
25ecefe
+	}
25ecefe
+
25ecefe
+	attach_selinux_data_popup_field (combo, attr_value, def_attr_value);
25ecefe
+
25ecefe
+	g_free (attr_value);
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+popup_field_update (FMPropertiesWindow *window, GtkComboBox *combo)
25ecefe
+{
25ecefe
+	gboolean use_original;	
25ecefe
+
25ecefe
+	if (window->details->selinux_combo) {
25ecefe
+	        return; /* FIXME: must be true: horrible UI, if working */
25ecefe
+	}
25ecefe
+	
25ecefe
+	use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "show_original"));
25ecefe
+
25ecefe
+	popup_field_update_internal (combo,
25ecefe
+				     (use_original ?
25ecefe
+				      window->details->original_files : 
25ecefe
+				      window->details->target_files));	
25ecefe
+}
25ecefe
+
25ecefe
 static GtkLabel *
25ecefe
 attach_label (GtkTable *table,
25ecefe
 	      int row,
3858601
@@ -1457,6 +1625,45 @@ attach_value_label (GtkTable *table,
25ecefe
 	return attach_label (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE);
25ecefe
 }
25ecefe
 
25ecefe
+static GtkEntry *
25ecefe
+attach_edit (GtkTable *table,
25ecefe
+	     int row,
25ecefe
+	     int column,
25ecefe
+	     const char *initial_text,
25ecefe
+	     gboolean right_aligned,
25ecefe
+	     gboolean bold,
25ecefe
+	     gboolean ellipsize_text,
25ecefe
+	     gboolean selectable,
25ecefe
+	     gboolean mnemonic)
25ecefe
+{
25ecefe
+	GtkWidget *entry_field;
25ecefe
+
25ecefe
+	entry_field = nautilus_entry_new ();
25ecefe
+	gtk_entry_set_text (GTK_ENTRY (entry_field), initial_text);
25ecefe
+
25ecefe
+	gtk_entry_set_alignment (GTK_ENTRY (entry_field), right_aligned ? 1 : 0);
25ecefe
+	gtk_widget_show (entry_field);
25ecefe
+	gtk_table_attach (table, entry_field,
25ecefe
+			  column, column + 1,
25ecefe
+			  row, row + 1,
25ecefe
+			  ellipsize_text
25ecefe
+			    ? GTK_FILL | GTK_EXPAND
25ecefe
+			    : GTK_FILL,
25ecefe
+			  0,
25ecefe
+			  0, 0);
25ecefe
+
25ecefe
+	return GTK_ENTRY (entry_field);
25ecefe
+}	      
25ecefe
+
25ecefe
+static GtkEntry *
25ecefe
+attach_edit_label (GtkTable *table,
25ecefe
+		   int row,
25ecefe
+		   int column,
25ecefe
+		   const char *initial_text)
25ecefe
+{
25ecefe
+	return attach_edit (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE);
25ecefe
+}
25ecefe
+
25ecefe
 static GtkLabel *
25ecefe
 attach_ellipsizing_value_label (GtkTable *table,
25ecefe
 				int row,
3858601
@@ -1515,6 +1722,672 @@ attach_value_field (FMPropertiesWindow *
25ecefe
 				     FALSE);
25ecefe
 }
25ecefe
 
25ecefe
+static void
25ecefe
+start_long_operation (FMPropertiesWindow *window)
25ecefe
+{
25ecefe
+	if (window->details->long_operation_underway == 0) {
25ecefe
+		/* start long operation */
25ecefe
+		GdkCursor * cursor;
25ecefe
+		
25ecefe
+		cursor = gdk_cursor_new (GDK_WATCH);
25ecefe
+		gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor);
25ecefe
+		gdk_cursor_unref (cursor);
25ecefe
+	}
25ecefe
+	window->details->long_operation_underway ++;
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+end_long_operation (FMPropertiesWindow *window)
25ecefe
+{
25ecefe
+	if (GTK_WIDGET (window)->window != NULL &&
25ecefe
+	    window->details->long_operation_underway == 1) {
25ecefe
+		/* finished !! */
25ecefe
+		gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL);
25ecefe
+	}
25ecefe
+	window->details->long_operation_underway--;
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+selinux_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data)
25ecefe
+{
25ecefe
+	FMPropertiesWindow *window;
25ecefe
+	g_assert (callback_data != NULL);
25ecefe
+
25ecefe
+	window = FM_PROPERTIES_WINDOW (callback_data);
25ecefe
+	end_long_operation (window);
25ecefe
+	
25ecefe
+	/* Report the error if it's an error. */
25ecefe
+	fm_report_error_setting_selinux (file, result, NULL);
25ecefe
+
25ecefe
+	g_object_unref (window);
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+selinux_done_editing (FMPropertiesWindow *window, char *selinux_context)
25ecefe
+{
25ecefe
+	GList *l;
25ecefe
+	
25ecefe
+	/* Accept changes. */
25ecefe
+	for (l = window->details->target_files; l != NULL; l = l->next) {
25ecefe
+		NautilusFile *file;
25ecefe
+
25ecefe
+		file = NAUTILUS_FILE (l->data);
25ecefe
+
25ecefe
+		start_long_operation (window);
25ecefe
+		g_object_ref (window);
25ecefe
+		nautilus_file_set_selinux_context (file, selinux_context,
25ecefe
+						   selinux_change_callback,
25ecefe
+						   window);
25ecefe
+	}
25ecefe
+}
25ecefe
+
25ecefe
+static gboolean
25ecefe
+selinux_focus_out (NautilusEntry *entry, GdkEventFocus *event, gpointer cb_data)
25ecefe
+{
25ecefe
+	g_assert (NAUTILUS_IS_ENTRY (entry));
25ecefe
+	g_assert (FM_IS_PROPERTIES_WINDOW (cb_data));
25ecefe
+
25ecefe
+	if (GTK_WIDGET_SENSITIVE (entry)) {	
25ecefe
+		char *tmp;
25ecefe
+		
25ecefe
+		tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
25ecefe
+		selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp);
25ecefe
+		g_free (tmp);
25ecefe
+	}
25ecefe
+
25ecefe
+	return FALSE;
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+selinux_entry_activate (NautilusEntry *entry, gpointer cb_data)
25ecefe
+{
25ecefe
+	char *tmp;
25ecefe
+	
25ecefe
+	g_assert (NAUTILUS_IS_ENTRY (entry));
25ecefe
+	g_assert (FM_IS_PROPERTIES_WINDOW (cb_data));
25ecefe
+
25ecefe
+	tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
25ecefe
+	selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp);
25ecefe
+	g_free (tmp);
25ecefe
+	
25ecefe
+	nautilus_entry_select_all_at_idle (entry);
25ecefe
+}
25ecefe
+
25ecefe
+/* NOTE: This modifies cntx */
25ecefe
+static void
25ecefe
+selinux_split_cntx (char *cntx,
25ecefe
+		    const char **ret_attr_u,
25ecefe
+		    const char **ret_attr_r,
25ecefe
+		    const char **ret_attr_t,
25ecefe
+		    const char **ret_attr_s)
25ecefe
+{
25ecefe
+	const char *attr_u;
25ecefe
+	const char *attr_r;
25ecefe
+	const char *attr_t;
25ecefe
+	const char *attr_s;
25ecefe
+
25ecefe
+	attr_u = cntx;
25ecefe
+	if (!(attr_r = strchr (attr_u, ':'))) {
25ecefe
+	        attr_r = "object_r"; /* shouldn't happen */
25ecefe
+	} else {
25ecefe
+	        *((char *)attr_r++) = 0;
25ecefe
+	}
25ecefe
+	
25ecefe
+	if (!(attr_t = strchr (attr_r, ':'))) {
25ecefe
+	        attr_t = "file_t"; /* shouldn't happen */
25ecefe
+	} else {
25ecefe
+	        *((char *)attr_t++) = 0;
25ecefe
+	}
25ecefe
+
25ecefe
+	if ((attr_s = strchr (attr_t, ':'))) {
25ecefe
+	        *((char *)attr_s++) = 0;
25ecefe
+	}
25ecefe
+
25ecefe
+	*ret_attr_u = attr_u;
25ecefe
+	*ret_attr_r = attr_r;
25ecefe
+	*ret_attr_t = attr_t;
25ecefe
+	*ret_attr_s = attr_s;
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+selinux_popup_activate (GtkComboBox *comb, gpointer cb_data)
25ecefe
+{
25ecefe
+	char *cntx_type;
25ecefe
+	char *orig_type;
25ecefe
+	const char *attr_u;
25ecefe
+	const char *attr_r;
25ecefe
+	const char *attr_t;
25ecefe
+	const char *attr_s;
25ecefe
+	char *tmp;
25ecefe
+	GtkTreeIter iter;
25ecefe
+	
25ecefe
+	g_assert (GTK_IS_COMBO_BOX (comb));
25ecefe
+	g_assert (FM_IS_PROPERTIES_WINDOW (cb_data));
25ecefe
+	
25ecefe
+	if (!gtk_combo_box_get_active_iter (comb, &iter)) {
25ecefe
+	        return;
25ecefe
+	} else {
25ecefe
+	  
25ecefe
+		GtkTreeModel *model = gtk_combo_box_get_model (comb);
25ecefe
+	        gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
25ecefe
+	}
25ecefe
+	
25ecefe
+	if (!(orig_type = g_object_get_data (G_OBJECT (comb),
25ecefe
+					     "original_cntx"))) {
25ecefe
+	        return;
25ecefe
+	}
25ecefe
+	orig_type = g_strdup (orig_type);
25ecefe
+	
25ecefe
+	selinux_split_cntx (orig_type, &attr_u, &attr_r, &attr_t, &attr_s);
25ecefe
+	tmp = g_strjoin (":", attr_u, attr_r, cntx_type, attr_s, NULL);
25ecefe
+	g_free (orig_type);
25ecefe
+	
25ecefe
+	selinux_done_editing (FM_PROPERTIES_WINDOW (cb_data), tmp);
25ecefe
+	g_free (tmp);
25ecefe
+}
25ecefe
+
25ecefe
+static char *
25ecefe
+cust_type_next_line (GIOChannel *ioc_ctypes)
25ecefe
+{
25ecefe
+	char *data;
25ecefe
+	gsize term;
25ecefe
+	GError *errc;
25ecefe
+
25ecefe
+	data = NULL;
25ecefe
+	term = 0;
25ecefe
+	errc = NULL;
25ecefe
+	
25ecefe
+	if (G_IO_STATUS_NORMAL == g_io_channel_read_line (ioc_ctypes, &data,
25ecefe
+							  NULL, &term, &errc)) {
25ecefe
+	        data[term] = 0;
25ecefe
+		return data;
25ecefe
+	}
25ecefe
+
25ecefe
+	return NULL;
25ecefe
+}
25ecefe
+
25ecefe
+static GSList *
25ecefe
+selinux__type_list (void)
25ecefe
+{
25ecefe
+        static GSList *cust_types;
25ecefe
+	static time_t file_mtime;
25ecefe
+	const char *fname_ctypes;
25ecefe
+	struct stat buf;
25ecefe
+	GIOChannel *ioc_ctypes;
25ecefe
+	GError *errc;
25ecefe
+	GSList *scan;
25ecefe
+	int fd;
25ecefe
+	
25ecefe
+#ifndef HAVE_SELINUX
25ecefe
+	if (cust_types) {
25ecefe
+	        return cust_types;
25ecefe
+	}
25ecefe
+#else
25ecefe
+	fname_ctypes = selinux_customizable_types_path ();
25ecefe
+	if (cust_types && file_mtime && !stat (fname_ctypes, &buf) &&
25ecefe
+	    (file_mtime == buf.st_mtime)) {
25ecefe
+	        return cust_types;
25ecefe
+	}
25ecefe
+#endif
25ecefe
+
25ecefe
+	if (cust_types) {
25ecefe
+	        for (scan = cust_types; scan; scan = scan->next) {
25ecefe
+		        g_free (scan->data);
25ecefe
+		}
25ecefe
+		g_slist_free (cust_types);
25ecefe
+		cust_types = NULL;
25ecefe
+	}
25ecefe
+	
25ecefe
+	cust_types = g_slist_prepend (cust_types, g_strdup ("tmp_t"));
25ecefe
+	cust_types = g_slist_prepend (cust_types, g_strdup ("user_home_t"));
25ecefe
+	/* cust_types = g_slist_prepend (cust_types, g_strdup ("user_tmp_t")); */
25ecefe
+	
25ecefe
+#ifdef HAVE_SELINUX
25ecefe
+	/* read types, one per line... */
25ecefe
+	fname_ctypes = selinux_customizable_types_path ();
25ecefe
+	errc = NULL;
25ecefe
+	if ((ioc_ctypes = g_io_channel_new_file (fname_ctypes, "r", &errc))) {
25ecefe
+	        char *data = NULL;
25ecefe
+
25ecefe
+		while ((data = cust_type_next_line (ioc_ctypes))) {
25ecefe
+		        cust_types = g_slist_prepend (cust_types, data);
25ecefe
+		}
25ecefe
+
25ecefe
+		fd = g_io_channel_unix_get_fd (ioc_ctypes);
25ecefe
+		if (!fstat (fd, &buf)) {
25ecefe
+			file_mtime = buf.st_mtime;
25ecefe
+		}
25ecefe
+
25ecefe
+		g_io_channel_unref (ioc_ctypes);
25ecefe
+	}
25ecefe
+#endif
25ecefe
+
25ecefe
+	return cust_types;
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+attach_selinux_data_edit_field (GtkEntry *entry,
25ecefe
+				char *attr_val, char *def_attr_val)
25ecefe
+{
25ecefe
+	GtkEntryCompletion *comp;
25ecefe
+	GtkCellRenderer *cell;
25ecefe
+	const char *attr_u;
25ecefe
+	const char *attr_r;
25ecefe
+	const char *attr_t;
25ecefe
+	const char *attr_s;
25ecefe
+	const char *dattr_u;
25ecefe
+	const char *dattr_r;
25ecefe
+	const char *dattr_t;
25ecefe
+	const char *dattr_s;
25ecefe
+	GtkListStore *store;
25ecefe
+	GtkTreeIter iter;
25ecefe
+	GSList *scan;
25ecefe
+	int width;
25ecefe
+	int owidth;
25ecefe
+	int twidth;
25ecefe
+	
25ecefe
+	attr_val     = g_strdup (attr_val); /* so we can alter it... */
25ecefe
+	def_attr_val = g_strdup (def_attr_val); /* so we can alter it... */
25ecefe
+	
25ecefe
+	/* do completion, so you don't have to type everything... */
25ecefe
+	comp = gtk_entry_completion_new ();
25ecefe
+	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
25ecefe
+	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
25ecefe
+					      0, GTK_SORT_ASCENDING);
25ecefe
+	
25ecefe
+	gtk_entry_completion_set_model (comp, GTK_TREE_MODEL (store));
25ecefe
+	cell = gtk_cell_renderer_pixbuf_new ();
25ecefe
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comp), cell, FALSE);
25ecefe
+	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comp), cell,
25ecefe
+					"stock-id", 1, NULL);
25ecefe
+	gtk_entry_completion_set_text_column (comp, 0);
25ecefe
+	gtk_entry_set_completion (entry, comp);
25ecefe
+
25ecefe
+	 /* FIXME: default doesn't do the right thing, should it? */
25ecefe
+	owidth = gtk_entry_get_width_chars (entry);
25ecefe
+	width = owidth;
25ecefe
+	
25ecefe
+	selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s);
25ecefe
+	dattr_u = dattr_r = dattr_t = dattr_s = NULL;
25ecefe
+	if (def_attr_val) {
25ecefe
+	          selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r,
25ecefe
+				      &dattr_t, &dattr_s);
25ecefe
+	}
25ecefe
+	
25ecefe
+	/* don't do it twice... */
25ecefe
+	if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) {
25ecefe
+	        dattr_t = NULL;
25ecefe
+	}
25ecefe
+
25ecefe
+	if (attr_t) {
25ecefe
+	  /* highlight just the type to the end, so we can easily change it
25ecefe
+	   * FIXME: we also highlight any Sensitivity/MCS but completion will
25ecefe
+	   * let people put it back, and that's the only way we get completion
25ecefe
+	   * at all -- This sucks and we need to remove Sensitivity/MCS from
25ecefe
+	   * the edit box. Yah, more UI. */
25ecefe
+	        int beg =  attr_t      - attr_u;
25ecefe
+		gtk_editable_select_region (GTK_EDITABLE (entry), beg, -1);
25ecefe
+	}
25ecefe
+	
25ecefe
+	for (scan = selinux__type_list(); scan; scan = scan->next) {
25ecefe
+		char *tmp;
25ecefe
+
25ecefe
+		if (attr_t  && !strcmp (attr_t,  scan->data))
25ecefe
+		        continue; /* don't have two entries */
25ecefe
+
25ecefe
+		if (dattr_t && !strcmp (dattr_t, scan->data))
25ecefe
+		        continue; /* don't have two entries */
25ecefe
+
25ecefe
+		gtk_list_store_append (store, &iter);
25ecefe
+		tmp = g_strjoin (":", attr_u, attr_r, scan->data, attr_s, NULL);
25ecefe
+		gtk_list_store_set (store, &iter, 0, tmp, -1);
25ecefe
+
25ecefe
+		twidth = strlen (tmp);
25ecefe
+		width = MAX (twidth, width);
25ecefe
+		
25ecefe
+		g_free (tmp);
25ecefe
+	}
25ecefe
+
25ecefe
+	if (dattr_t) {
25ecefe
+		char *tmp;
25ecefe
+
25ecefe
+		gtk_list_store_append (store, &iter);
25ecefe
+		tmp = g_strjoin (":", dattr_u, dattr_r, dattr_t, dattr_s, NULL);
25ecefe
+		gtk_list_store_set (store, &iter, 0, tmp,
25ecefe
+				    1, GTK_STOCK_HOME, -1);
25ecefe
+
25ecefe
+		twidth = strlen (tmp);
25ecefe
+		width = MAX (twidth, width);
25ecefe
+
25ecefe
+		g_free (tmp);
25ecefe
+	}
25ecefe
+
25ecefe
+	if (attr_t) {
25ecefe
+		char *tmp;
25ecefe
+
25ecefe
+		gtk_list_store_append (store, &iter);
25ecefe
+		tmp = g_strjoin (":", attr_u, attr_r, attr_t, attr_s, NULL);
25ecefe
+		gtk_list_store_set (store, &iter, 0, tmp, 1, GTK_STOCK_OK, -1);
25ecefe
+
25ecefe
+		twidth = strlen (tmp);
25ecefe
+		width = MAX (twidth, width);
25ecefe
+
25ecefe
+		g_free (tmp);
25ecefe
+	}
25ecefe
+
25ecefe
+	g_free (attr_val);
25ecefe
+	g_free (def_attr_val);
25ecefe
+	g_object_unref (G_OBJECT (store));	
25ecefe
+	g_object_unref (G_OBJECT (comp));
25ecefe
+
25ecefe
+	if (width != owidth) {
25ecefe
+	        gtk_entry_set_width_chars (entry, width + 2);
25ecefe
+	}
25ecefe
+}
25ecefe
+
25ecefe
+# define HACK_TYPE(x, y)				\
25ecefe
+	else if (!strcmp (nice_type, x)) nice_type = y
25ecefe
+
25ecefe
+/* hack to convert a selinux_context type into a readable string for the
25ecefe
+   user */
25ecefe
+static const char *
25ecefe
+selinux__hack_conv_type (const char *type)
25ecefe
+{ /* FIXME: hack attack, but nowhere else to put it. Because mathpathcon
25ecefe
+   * here now probably want a bunch of other types? */
25ecefe
+        const char *nice_type;
25ecefe
+
25ecefe
+	nice_type = type;
25ecefe
+	
25ecefe
+	if (0) { }
25ecefe
+	
25ecefe
+	HACK_TYPE("cupsd_etc_t", _("CUPS printer configuration"));
25ecefe
+	HACK_TYPE("cupsd_rw_etc_t", _("CUPS printer configuration (rw)"));
25ecefe
+	HACK_TYPE("cupsd_tmp_t", _("CUPS temporary data"));
25ecefe
+	HACK_TYPE("dhcp_etc_t", _("DHCP configuration"));
25ecefe
+	HACK_TYPE("dictd_etc_t", _("Dictd configuration"));
25ecefe
+	HACK_TYPE("dnssec_t", _("DNS secret"));
25ecefe
+	HACK_TYPE("etc_t", _("System configuration"));
25ecefe
+	HACK_TYPE("etc_aliases_t", _("Email aliases configuration"));
25ecefe
+	HACK_TYPE("etc_runtime_t", _("System configuration (rw)"));
25ecefe
+	HACK_TYPE("cvs_data_t", _("Read and write from CVS daemon"));
25ecefe
+	HACK_TYPE("httpd_config_t", _("Apache-httpd configuration"));
25ecefe
+	HACK_TYPE("httpd_php_tmp_t",
25ecefe
+		  _("Apache-httpd PHP module temporary data"));
25ecefe
+	HACK_TYPE("httpd_sys_content_t",
25ecefe
+		  _("Read from all httpd scripts and the daemon"));
25ecefe
+	HACK_TYPE("httpd_sys_htaccess_t",
25ecefe
+		  _("Apache-httpd .htaccess configuration"));
25ecefe
+	HACK_TYPE("httpd_sys_script_exec_t",
25ecefe
+		  _("CGI programs with default access"));
25ecefe
+	HACK_TYPE("httpd_sys_script_ra_t",
25ecefe
+		  _("CGI programs can read and append"));
25ecefe
+	HACK_TYPE("httpd_sys_script_ro_t",
25ecefe
+		  _("CGI programs can read"));
25ecefe
+	HACK_TYPE("httpd_sys_script_rw_t",
25ecefe
+		  _("CGI programs can read and write"));
25ecefe
+	HACK_TYPE("httpd_unconfined_script_exec_t",
25ecefe
+		  _("CGI programs without any SELinux protection"));
25ecefe
+	HACK_TYPE("httpd_tmp_t", _("Apache-httpd temporary data"));
25ecefe
+	HACK_TYPE("ice_tmp_t", _("ICE temporary data"));
25ecefe
+	HACK_TYPE("locale_t", _("Locale data"));
25ecefe
+	HACK_TYPE("mysql_tmp_t", _("MySQL temporary data"));
25ecefe
+	HACK_TYPE("named_conf_t", _("Nameserver configuration"));
25ecefe
+	HACK_TYPE("net_conf_t", _("Network configuration"));
25ecefe
+	HACK_TYPE("postgresql_tmp_t", _("Postgresql temporary data"));
25ecefe
+	HACK_TYPE("public_content_rw_t",
25ecefe
+		  _("Read and write from CIFS/ftp/http/nfs/rsync"));
25ecefe
+	HACK_TYPE("public_content_t", _("Read from CIFS/ftp/http/nfs/rsync"));
25ecefe
+	HACK_TYPE("samba_etc_t", _("Samba configuration"));
25ecefe
+	HACK_TYPE("samba_share_t", _("Shared via CIFS (samba)"));
25ecefe
+	HACK_TYPE("staff_home_t", _("Staff user data"));
25ecefe
+	HACK_TYPE("staff_home_dir_t", _("Staff user home directory"));
25ecefe
+	HACK_TYPE("swapfile_t", _("System swapfile"));
25ecefe
+	HACK_TYPE("sysadm_home_t", _("Sysadmin user data"));
25ecefe
+	HACK_TYPE("sysadm_home_dir_t", _("Sysadmin user home directory"));
25ecefe
+	HACK_TYPE("system_cron_spool_t", _("Cron data"));
25ecefe
+	HACK_TYPE("tmp_t", _("Temporary data"));
25ecefe
+	HACK_TYPE("user_tmp_t", _("User temporary data"));
25ecefe
+	HACK_TYPE("user_home_t", _("User data"));
25ecefe
+	HACK_TYPE("user_home_dir_t", _("User home directory"));
25ecefe
+	HACK_TYPE("var_log_t", _("Logfile"));
25ecefe
+	HACK_TYPE("xen_image_t", _("Xen image"));
25ecefe
+	
25ecefe
+	return nice_type;
25ecefe
+}
25ecefe
+#undef HACK_TYPE
25ecefe
+
25ecefe
+static void
25ecefe
+attach_selinux_data_popup_field (GtkComboBox *comb,
25ecefe
+				 char *attr_val,
25ecefe
+				 char *def_attr_val)
25ecefe
+{
25ecefe
+	const char *attr_u;
25ecefe
+	const char *attr_r;
25ecefe
+	const char *attr_t;
25ecefe
+	const char *attr_s;
25ecefe
+	const char *dattr_u;
25ecefe
+	const char *dattr_r;
25ecefe
+	const char *dattr_t;
25ecefe
+	const char *dattr_s;
25ecefe
+	GtkListStore *store;
25ecefe
+	GtkTreeIter iter;
25ecefe
+	GSList *scan;
25ecefe
+	
25ecefe
+	attr_val     = g_strdup (attr_val); /* so we can alter it... */
25ecefe
+	def_attr_val = g_strdup (def_attr_val);
25ecefe
+
25ecefe
+	/* do completion, so you don't have to type everything... */
25ecefe
+	store = gtk_list_store_new (3, G_TYPE_STRING,
25ecefe
+				    G_TYPE_STRING, G_TYPE_STRING);
25ecefe
+	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
25ecefe
+					      1, GTK_SORT_ASCENDING);
25ecefe
+	
25ecefe
+	gtk_combo_box_set_model (comb, GTK_TREE_MODEL (store));
25ecefe
+
25ecefe
+	selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s);
25ecefe
+	dattr_u = dattr_r = dattr_t = dattr_s = NULL;
25ecefe
+	if (def_attr_val) {
25ecefe
+	          selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r,
25ecefe
+				      &dattr_t, &dattr_s);
25ecefe
+	}
25ecefe
+	/* don't do it twice... */
25ecefe
+	if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) {
25ecefe
+	        dattr_t = NULL;
25ecefe
+	}
25ecefe
+
25ecefe
+	for (scan = selinux__type_list(); scan; scan = scan->next) {
25ecefe
+		const char *nice_type;
25ecefe
+		
25ecefe
+		if (attr_t  && !strcmp (attr_t,  scan->data))
25ecefe
+		        continue; /* don't have two entries */
25ecefe
+
25ecefe
+		if (dattr_t && !strcmp (dattr_t, scan->data))
25ecefe
+		        continue; /* don't have two entries */
25ecefe
+
25ecefe
+		nice_type = selinux__hack_conv_type(scan->data);
25ecefe
+		
25ecefe
+		gtk_list_store_append (store, &iter);
25ecefe
+		gtk_list_store_set (store, &iter, 0, scan->data,
25ecefe
+				    1, nice_type, -1);
25ecefe
+	}
25ecefe
+
25ecefe
+	if (dattr_t) {
25ecefe
+		const char *nice_type;
25ecefe
+		
25ecefe
+		gtk_list_store_append (store, &iter);
25ecefe
+		nice_type = selinux__hack_conv_type(dattr_t);
25ecefe
+	        gtk_list_store_set (store, &iter, 0, dattr_t, 1, nice_type,
25ecefe
+				    2, GTK_STOCK_HOME, -1);
25ecefe
+	}
25ecefe
+
25ecefe
+	if (attr_t) {
25ecefe
+		const char *nice_type;
25ecefe
+		
25ecefe
+		gtk_list_store_append (store, &iter);
25ecefe
+		nice_type = selinux__hack_conv_type(attr_t);
25ecefe
+	        gtk_list_store_set (store, &iter, 0,  attr_t, 1, nice_type,
25ecefe
+				    2, GTK_STOCK_OK, -1);
25ecefe
+		gtk_combo_box_set_active_iter (comb, &iter);
25ecefe
+	}
25ecefe
+
25ecefe
+	g_free (attr_val);
25ecefe
+	g_free (def_attr_val);
25ecefe
+	g_object_unref (G_OBJECT (store));
25ecefe
+}
25ecefe
+
25ecefe
+static char *
25ecefe
+selinux__matchpathcon (GList *file_list)
25ecefe
+{
25ecefe
+	GList *scan;
25ecefe
+
25ecefe
+        for (scan = file_list; scan != NULL; scan = scan->next) {
25ecefe
+	        NautilusFile *file;
25ecefe
+
25ecefe
+		file = NAUTILUS_FILE (scan->data);
25ecefe
+		if (!nautilus_file_is_gone (file)) {
25ecefe
+		        return nautilus_file_get_selinux_matchpathcon (file);
25ecefe
+		}
25ecefe
+	}
25ecefe
+
25ecefe
+	return NULL;
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+attach_selinux_edit_field (FMPropertiesWindow *window,
25ecefe
+			   GtkTable *table,
25ecefe
+			   int row,
25ecefe
+			   int column,
25ecefe
+			   const char *file_attribute_name,
25ecefe
+			   const char *inconsistent_string,
25ecefe
+			   gboolean show_original,
25ecefe
+			   GtkLabel *lab_title)
25ecefe
+{
25ecefe
+	GtkEntry *entry;
25ecefe
+	GList *file_list;
25ecefe
+	char *attr_value;
25ecefe
+	char *def_attr_value;
25ecefe
+	
25ecefe
+	if (show_original) {
25ecefe
+	        file_list = window->details->original_files;
25ecefe
+	} else {
25ecefe
+	        file_list = window->details->target_files;
25ecefe
+	}
25ecefe
+	
25ecefe
+	attr_value = file_list_get_string_attribute (file_list, 
25ecefe
+						     file_attribute_name,
25ecefe
+						     inconsistent_string);
25ecefe
+	if ( strcmp (attr_value, inconsistent_string) &&
25ecefe
+	    !strcmp (file_attribute_name, "selinux_context")) {
25ecefe
+	        def_attr_value = selinux__matchpathcon (file_list);
25ecefe
+	} else {
25ecefe
+	        def_attr_value = NULL;
25ecefe
+	}
25ecefe
+	
25ecefe
+	entry = attach_edit_label (table, row, column, attr_value);
25ecefe
+	gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title),
25ecefe
+				       GTK_WIDGET (entry));
25ecefe
+
25ecefe
+  	/* Stash a copy of the file attribute name in this field for the callback's sake. */
25ecefe
+	g_object_set_data_full (G_OBJECT (entry), "file_attribute",
25ecefe
+				g_strdup (file_attribute_name), g_free);
25ecefe
+
25ecefe
+	g_object_set_data_full (G_OBJECT (entry), "inconsistent_string",
25ecefe
+				g_strdup (inconsistent_string), g_free);
25ecefe
+
25ecefe
+	g_object_set_data (G_OBJECT (entry), "show_original", GINT_TO_POINTER (show_original));
25ecefe
+	g_object_set_data (G_OBJECT (entry), "ellipsize_text", GINT_TO_POINTER (FALSE));
25ecefe
+
25ecefe
+	g_signal_connect_object (entry, "focus_out_event",
25ecefe
+				 G_CALLBACK (selinux_focus_out), window, 0);
25ecefe
+	g_signal_connect_object (entry, "activate",
25ecefe
+				 G_CALLBACK (selinux_entry_activate), window,0);
25ecefe
+
25ecefe
+	attach_selinux_data_edit_field (entry, attr_value, def_attr_value);
25ecefe
+	
25ecefe
+	g_object_set_data_full (G_OBJECT (entry), "original_cntx", attr_value,
25ecefe
+				g_free);
25ecefe
+
25ecefe
+	g_object_set_data_full (G_OBJECT (entry), "matchpathcon_cntx",
25ecefe
+				def_attr_value, g_free);
25ecefe
+
25ecefe
+	window->details->edit_fields = g_list_prepend (window->details->edit_fields,
25ecefe
+						       entry);
25ecefe
+}
25ecefe
+
25ecefe
+static void
25ecefe
+attach_selinux_popup_field (FMPropertiesWindow *window,
25ecefe
+			    GtkTable *table,
25ecefe
+			    int row,
25ecefe
+			    int column,
25ecefe
+			    const char *file_attribute_name,
25ecefe
+			    const char *inconsistent_string,
25ecefe
+			    gboolean show_original,
25ecefe
+			    GtkLabel *lab_title)
25ecefe
+{
25ecefe
+	GtkWidget *comb;
25ecefe
+	GtkCellRenderer *cell;
25ecefe
+	GList *file_list;
25ecefe
+	char *attr_value;
25ecefe
+	char *def_attr_value;
25ecefe
+
25ecefe
+	if (show_original) {
25ecefe
+	        file_list = window->details->original_files;
25ecefe
+	} else {
25ecefe
+	        file_list = window->details->target_files;
25ecefe
+	}
25ecefe
+	
25ecefe
+	attr_value = file_list_get_string_attribute (file_list, 
25ecefe
+						     file_attribute_name,
25ecefe
+						     inconsistent_string);
25ecefe
+	if ( strcmp (attr_value, inconsistent_string) &&
25ecefe
+	    !strcmp (file_attribute_name, "selinux_context")) {
25ecefe
+	        def_attr_value = selinux__matchpathcon (file_list);	
25ecefe
+	} else {
25ecefe
+	        def_attr_value = NULL;
25ecefe
+	}
25ecefe
+	
25ecefe
+	comb = gtk_combo_box_new ();
25ecefe
+	
25ecefe
+	gtk_table_attach (table, comb, column, column + 1, row, row + 1,
25ecefe
+			  GTK_FILL, 0, 0, 0);
25ecefe
+
25ecefe
+	
25ecefe
+	gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), comb);
25ecefe
+
25ecefe
+  	/* Stash a copy of the file attribute name in this field for the callback's sake. */
25ecefe
+	g_object_set_data_full (G_OBJECT (comb), "file_attribute",
25ecefe
+				g_strdup (file_attribute_name), g_free);
25ecefe
+
25ecefe
+	g_object_set_data (G_OBJECT (comb), "show_original", GINT_TO_POINTER (show_original));
25ecefe
+
25ecefe
+	attach_selinux_data_popup_field (GTK_COMBO_BOX (comb),
25ecefe
+					 attr_value, def_attr_value);
25ecefe
+	
25ecefe
+	g_signal_connect_object (comb, "changed",
25ecefe
+				 G_CALLBACK (selinux_popup_activate), window, 0);
25ecefe
+
25ecefe
+	g_object_set_data_full (G_OBJECT (comb), "original_cntx", attr_value,
25ecefe
+				g_free);
25ecefe
+
25ecefe
+	g_object_set_data_full (G_OBJECT (comb), "matchpathcon_cntx",
25ecefe
+				def_attr_value, g_free);
25ecefe
+
25ecefe
+	cell = gtk_cell_renderer_pixbuf_new ();
25ecefe
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE);
25ecefe
+	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell,
25ecefe
+					"stock-id", 2, NULL);
25ecefe
+	cell = gtk_cell_renderer_text_new ();
25ecefe
+	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE);
25ecefe
+	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell,
25ecefe
+					"text", 1, NULL);
25ecefe
+	gtk_widget_show (comb);
25ecefe
+
25ecefe
+	g_assert (! window->details->selinux_combo);
25ecefe
+	
25ecefe
+	window->details->selinux_combo = 
25ecefe
+		g_list_prepend (window->details->selinux_combo, comb);
25ecefe
+}
25ecefe
+
25ecefe
 static GtkWidget*
25ecefe
 attach_ellipsizing_value_field (FMPropertiesWindow *window,
25ecefe
 				GtkTable *table,
3858601
@@ -2465,6 +3338,36 @@ append_title_value_pair (FMPropertiesWin
25ecefe
 }
25ecefe
 
25ecefe
 static guint
25ecefe
+append_title_selinux_edit_pair (FMPropertiesWindow *window,
25ecefe
+				GtkTable *table,
25ecefe
+				const char *title, 
25ecefe
+				const char *file_attribute_name,
25ecefe
+				const char *inconsistent_state,
25ecefe
+				gboolean show_original)
25ecefe
+{
25ecefe
+	guint last_row;
25ecefe
+	GtkLabel *lab_title;
25ecefe
+
25ecefe
+	lab_title = NULL;
25ecefe
+	last_row = append_title_field (table, title, &lab_title);
25ecefe
+
25ecefe
+	if (window->details->advanced_permissions) {
25ecefe
+	        attach_selinux_edit_field (window, table, last_row,
25ecefe
+					   VALUE_COLUMN, file_attribute_name,
25ecefe
+					   inconsistent_state,
25ecefe
+					   show_original, lab_title);
25ecefe
+	} else {
25ecefe
+		  
25ecefe
+	        attach_selinux_popup_field (window, table, last_row,
25ecefe
+					    VALUE_COLUMN, file_attribute_name,
25ecefe
+					    inconsistent_state,
25ecefe
+					    show_original, lab_title);	  
25ecefe
+	}
25ecefe
+	
25ecefe
+	return last_row;
25ecefe
+}
25ecefe
+
25ecefe
+static guint
25ecefe
 append_title_and_ellipsizing_value (FMPropertiesWindow *window,
25ecefe
 				    GtkTable *table,
25ecefe
 				    const char *title,
3858601
@@ -3263,31 +4166,6 @@ create_emblems_page (FMPropertiesWindow 
25ecefe
 }
25ecefe
 
25ecefe
 static void
25ecefe
-start_long_operation (FMPropertiesWindow *window)
25ecefe
-{
25ecefe
-	if (window->details->long_operation_underway == 0) {
25ecefe
-		/* start long operation */
25ecefe
-		GdkCursor * cursor;
25ecefe
-		
25ecefe
-		cursor = gdk_cursor_new (GDK_WATCH);
25ecefe
-		gdk_window_set_cursor (GTK_WIDGET (window)->window, cursor);
25ecefe
-		gdk_cursor_unref (cursor);
25ecefe
-	}
25ecefe
-	window->details->long_operation_underway ++;
25ecefe
-}
25ecefe
-
25ecefe
-static void
25ecefe
-end_long_operation (FMPropertiesWindow *window)
25ecefe
-{
25ecefe
-	if (GTK_WIDGET (window)->window != NULL &&
25ecefe
-	    window->details->long_operation_underway == 1) {
25ecefe
-		/* finished !! */
25ecefe
-		gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL);
25ecefe
-	}
25ecefe
-	window->details->long_operation_underway--;
25ecefe
-}
25ecefe
-
25ecefe
-static void
25ecefe
 permission_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data)
25ecefe
 {
25ecefe
 	FMPropertiesWindow *window;
3858601
@@ -4414,14 +5292,16 @@ apply_recursive_clicked (GtkWidget *recu
25ecefe
 	GnomeVFSFilePermissions file_permission, file_permission_mask;
25ecefe
 	GnomeVFSFilePermissions dir_permission, dir_permission_mask;
25ecefe
 	GnomeVFSFilePermissions vfs_mask, vfs_new_perm, p;
25ecefe
-	GtkWidget *button, *combo;
25ecefe
+	char *context;
25ecefe
+	GtkWidget *button;
25ecefe
+	GtkComboBox *combo;
25ecefe
 	gboolean active, is_folder, is_special, use_original;
25ecefe
 	GList *l;
25ecefe
 	GtkTreeModel *model;
25ecefe
 	GtkTreeIter iter;
25ecefe
 	PermissionType type;
25ecefe
 	int new_perm, mask;
25ecefe
-	
25ecefe
+
25ecefe
 	file_permission = 0;
25ecefe
 	file_permission_mask = 0;
25ecefe
 	dir_permission = 0;
3858601
@@ -4458,9 +5338,9 @@ apply_recursive_clicked (GtkWidget *recu
25ecefe
 	}
25ecefe
 	/* Simple mode, minus exec checkbox */
25ecefe
 	for (l = window->details->permission_combos; l != NULL; l = l->next) {
25ecefe
-		combo = l->data;
25ecefe
+		combo = GTK_COMBO_BOX (l->data);
25ecefe
 		
25ecefe
-		if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo),  &iter)) {
25ecefe
+		if (!gtk_combo_box_get_active_iter (combo,  &iter)) {
25ecefe
 			continue;
25ecefe
 		}
25ecefe
 		
3858601
@@ -4468,7 +5348,7 @@ apply_recursive_clicked (GtkWidget *recu
25ecefe
 		is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo),
25ecefe
 								"is-folder"));
25ecefe
 		
25ecefe
-		model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
25ecefe
+		model = gtk_combo_box_get_model (combo);
25ecefe
 		gtk_tree_model_get (model, &iter, 1, &new_perm, 2, &use_original, -1);
25ecefe
 		if (use_original) {
25ecefe
 			continue;
3858601
@@ -4491,12 +5371,53 @@ apply_recursive_clicked (GtkWidget *recu
25ecefe
 		}
25ecefe
 	}
25ecefe
 
25ecefe
+	/* get the SELinux context... */
25ecefe
+	context = NULL;
25ecefe
+	if (window->details->advanced_permissions &&
25ecefe
+	    window->details->edit_fields) { /* advanced mode */
25ecefe
+		GtkEditable *efield;
25ecefe
+
25ecefe
+		efield = window->details->edit_fields->data;
25ecefe
+	        context = gtk_editable_get_chars (GTK_EDITABLE (efield), 0, -1);
25ecefe
+	} else if (!window->details->advanced_permissions &&
25ecefe
+		   window->details->selinux_combo) { /* simple mode */
25ecefe
+	        char *cntx_type;
25ecefe
+	        char *orig_type;
25ecefe
+	        const char *attr_u;
25ecefe
+	        const char *attr_r;
25ecefe
+	        const char *attr_t;
25ecefe
+	        const char *attr_s;
25ecefe
+	  
25ecefe
+		combo = GTK_COMBO_BOX (window->details->selinux_combo->data);
25ecefe
+	        
25ecefe
+	        if (!gtk_combo_box_get_active_iter (combo, &iter)) {
25ecefe
+		        return;
25ecefe
+		} else {
25ecefe
+		        GtkTreeModel *model = gtk_combo_box_get_model (combo);
25ecefe
+			gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
25ecefe
+		}
25ecefe
+		if (!(orig_type = g_object_get_data (G_OBJECT (combo),
25ecefe
+						     "original_cntx"))) {
25ecefe
+		        return;
25ecefe
+		}
25ecefe
+		
25ecefe
+		orig_type = g_strdup (orig_type);
25ecefe
+	
25ecefe
+		selinux_split_cntx (orig_type,
25ecefe
+				    &attr_u, &attr_r, &attr_t, &attr_s);
25ecefe
+		context = g_strjoin (":",
25ecefe
+				     attr_u, attr_r, cntx_type, attr_s, NULL);
25ecefe
+		g_free (orig_type);
25ecefe
+	}
25ecefe
+	
25ecefe
 	for (l = window->details->target_files; l != NULL; l = l->next) {
25ecefe
 		NautilusFile *file;
25ecefe
 		char *uri;
25ecefe
 
25ecefe
 		file = NAUTILUS_FILE (l->data);
25ecefe
 
25ecefe
+		/* assume permissions setting allows context setting...
25ecefe
+		 * we can't really do much else due to race conditions anyway */
25ecefe
 		if (nautilus_file_is_directory (file) &&
25ecefe
 		    nautilus_file_can_set_permissions (file)) {
25ecefe
 			uri = nautilus_file_get_uri (file);
3858601
@@ -4507,11 +5428,13 @@ apply_recursive_clicked (GtkWidget *recu
25ecefe
 								 file_permission_mask,
25ecefe
 								 dir_permission,
25ecefe
 								 dir_permission_mask,
25ecefe
+								 context,
25ecefe
 								 set_recursive_permissions_done,
25ecefe
 								 window);
25ecefe
 			g_free (uri);
25ecefe
 		}
25ecefe
 	}
25ecefe
+	g_free (context);
25ecefe
 }
25ecefe
 
25ecefe
 static void
3858601
@@ -4558,11 +5481,20 @@ create_permissions_page (FMPropertiesWin
25ecefe
 		}
25ecefe
 		
25ecefe
 		gtk_table_set_row_spacing (page_table, page_table->nrows - 1, 18);
25ecefe
-	
25ecefe
-		append_title_value_pair
25ecefe
-			(window, page_table, _("SELinux Context:"), 
25ecefe
-			 "selinux_context", _("--"),
25ecefe
-			 FALSE);
25ecefe
+
25ecefe
+		if (!is_multi_file_window (window) ||
25ecefe
+		    multi_have_same_selinux_context (window))
25ecefe
+		        append_title_selinux_edit_pair
25ecefe
+			  (window, page_table, _("_SELinux Context:"), 
25ecefe
+			   "selinux_context", _("--"),
25ecefe
+			   FALSE);
25ecefe
+		else /* Static text in this case. */
25ecefe
+		        append_title_value_pair (window, page_table,
25ecefe
+						 _("_SELinux Context:"), 
25ecefe
+						 "selinux_context", _("--"),
25ecefe
+						 FALSE);
25ecefe
+
25ecefe
+		  
25ecefe
 		append_title_value_pair
25ecefe
 			(window, page_table, _("Last changed:"), 
25ecefe
 			 "date_permissions", _("--"),
3858601
--- nautilus-2.19.2/libnautilus-private/nautilus-file-operations.c.selinux	2007-04-03 06:08:46.000000000 -0400
3858601
+++ nautilus-2.19.2/libnautilus-private/nautilus-file-operations.c	2007-05-19 22:20:22.000000000 -0400
3858601
@@ -63,6 +63,10 @@
3858601
 #include "nautilus-trash-monitor.h"
3858601
 #include "nautilus-file-utilities.h"
3858601
 
3858601
+#ifdef HAVE_SELINUX
3858601
+#include <selinux/selinux.h>
3858601
+#endif
3858601
+
3858601
 typedef enum   TransferKind         TransferKind;
3858601
 typedef struct TransferInfo         TransferInfo;
3858601
 typedef struct IconPositionIterator IconPositionIterator;
3858601
@@ -3181,6 +3185,7 @@ struct RecursivePermissionsInfo {
3858601
 	GnomeVFSFilePermissions file_mask;
3858601
 	GnomeVFSFilePermissions dir_permissions;
3858601
 	GnomeVFSFilePermissions dir_mask;
3858601
+        char *context;
3858601
 	NautilusSetPermissionsCallback callback;
3858601
 	gpointer callback_data;
3858601
 };
3858601
@@ -3208,6 +3213,8 @@ set_permissions_set_file_info (GnomeVFSA
3858601
 	GnomeVFSURI *uri;
3858601
 	char *uri_str;
3858601
 	struct FileInfo *file_info;
3858601
+	int flags;
3858601
+	int options;
3858601
 	
3858601
 	info = callback_data;
3858601
 
3858601
@@ -3238,10 +3245,18 @@ set_permissions_set_file_info (GnomeVFSA
3858601
 	vfs_info->permissions = 
3858601
 			(file_info->permissions & ~info->file_mask) |
3858601
 			info->file_permissions;
3858601
+	flags = GNOME_VFS_SET_FILE_INFO_PERMISSIONS;
3858601
+	options = GNOME_VFS_FILE_INFO_DEFAULT;
3858601
+	if (info->context) {
3858601
+		flags |= GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT;
3858601
+		vfs_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SELINUX_CONTEXT;
3858601
+		options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT;
3858601
+		g_free (vfs_info->selinux_context);
3858601
+	        vfs_info->selinux_context = g_strdup (info->context);
3858601
+	}
3858601
 	
3858601
 	gnome_vfs_async_set_file_info (&info->handle, uri, vfs_info,
3858601
-				       GNOME_VFS_SET_FILE_INFO_PERMISSIONS,
3858601
-				       GNOME_VFS_FILE_INFO_DEFAULT,
3858601
+				       flags, options,
3858601
 				       GNOME_VFS_PRIORITY_DEFAULT,
3858601
 				       set_permissions_set_file_info,
3858601
 				       info);
3858601
@@ -3249,7 +3264,6 @@ set_permissions_set_file_info (GnomeVFSA
3858601
 	gnome_vfs_file_info_unref (vfs_info);
3858601
 	g_free (file_info->name);
3858601
 	g_free (file_info);
3858601
-	
3858601
 }
3858601
 
3858601
 static void
3858601
@@ -3294,13 +3308,11 @@ set_permissions_got_files (GnomeVFSAsync
3858601
 		}
3858601
 	}
3858601
 
3858601
-
3858601
 	if (result != GNOME_VFS_OK) {
3858601
 		/* Finished with this dir, work on the files */
3858601
 		info->current_file = NULL;
3858601
 		set_permissions_set_file_info (NULL, GNOME_VFS_OK, NULL, info);
3858601
 	}
3858601
-	
3858601
 }
3858601
 
3858601
 /* Also called for the toplevel dir */
3858601
@@ -3312,7 +3324,8 @@ set_permissions_load_dir (GnomeVFSAsyncH
3858601
 {
3858601
 	struct RecursivePermissionsInfo *info;
3858601
 	char *uri_str;
3858601
-
3858601
+	int options;
3858601
+	
3858601
 	info = callback_data;
3858601
 	
3858601
 	if (result == GNOME_VFS_OK && handle != NULL) {
3858601
@@ -3321,9 +3334,13 @@ set_permissions_load_dir (GnomeVFSAsyncH
3858601
 		g_free (uri_str);
3858601
 	}
3858601
 	
3858601
+	options = GNOME_VFS_FILE_INFO_DEFAULT;
3858601
+	if (info->context) {
3858601
+		options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT;
3858601
+	}
3858601
 	gnome_vfs_async_load_directory_uri (&info->handle,
3858601
 					    info->current_dir,
3858601
-					    GNOME_VFS_FILE_INFO_DEFAULT,
3858601
+					    options,
3858601
 					    50,
3858601
 					    GNOME_VFS_PRIORITY_DEFAULT,
3858601
 					    set_permissions_got_files,
3858601
@@ -3335,6 +3352,8 @@ set_permissions_run (struct RecursivePer
3858601
 {
3858601
 	struct DirInfo *dir_info;
3858601
 	GnomeVFSFileInfo *vfs_info;
3858601
+	int flags;
3858601
+	int options;
3858601
 	
3858601
 	gnome_vfs_uri_unref (info->current_dir);
3858601
 
3858601
@@ -3342,6 +3361,7 @@ set_permissions_run (struct RecursivePer
3858601
 		/* No more directories, finished! */
3858601
 		info->callback (info->callback_data);
3858601
 		/* All parts of info should be freed now */
3858601
+		g_free (info->context);
3858601
 		g_free (info);
3858601
 		return;
3858601
 	}
3858601
@@ -3356,12 +3376,18 @@ set_permissions_run (struct RecursivePer
3858601
 	vfs_info->permissions = 
3858601
 			(dir_info->permissions & ~info->dir_mask) |
3858601
 			info->dir_permissions;
3858601
-
3858601
-	gnome_vfs_async_set_file_info (&info->handle,
3858601
-				       info->current_dir,
3858601
-				       vfs_info,
3858601
-				       GNOME_VFS_SET_FILE_INFO_PERMISSIONS,
3858601
-				       GNOME_VFS_FILE_INFO_DEFAULT,
3858601
+	flags = GNOME_VFS_SET_FILE_INFO_PERMISSIONS;
3858601
+	options = GNOME_VFS_FILE_INFO_DEFAULT;
3858601
+	if (info->context) {
3858601
+		flags |= GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT;
3858601
+		vfs_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SELINUX_CONTEXT;
3858601
+		options |= GNOME_VFS_FILE_INFO_GET_SELINUX_CONTEXT;
3858601
+		g_free (vfs_info->selinux_context);
3858601
+	        vfs_info->selinux_context = g_strdup (info->context);
3858601
+	}
3858601
+	
3858601
+	gnome_vfs_async_set_file_info (&info->handle, info->current_dir,
3858601
+				       vfs_info, flags, options,
3858601
 				       GNOME_VFS_PRIORITY_DEFAULT,
3858601
 				       set_permissions_load_dir,
3858601
 				       info);
3858601
@@ -3376,6 +3402,7 @@ nautilus_file_set_permissions_recursive 
3858601
 					 GnomeVFSFilePermissions         file_mask,
3858601
 					 GnomeVFSFilePermissions         dir_permissions,
3858601
 					 GnomeVFSFilePermissions         dir_mask,
3858601
+					 const char                     *context,
3858601
 					 NautilusSetPermissionsCallback  callback,
3858601
 					 gpointer                        callback_data)
3858601
 {
3858601
@@ -3389,6 +3416,22 @@ nautilus_file_set_permissions_recursive 
3858601
 	info->file_mask = file_mask;
3858601
 	info->dir_permissions = dir_permissions;
3858601
 	info->dir_mask = dir_mask;
3858601
+	if (context) {
3858601
+		char *rcontext;
3858601
+
3858601
+	        rcontext = info->context = NULL;
3858601
+#ifdef HAVE_SELINUX
3858601
+		/* this is really const, but prototype is wrong, *sigh* */
3858601
+		if (selinux_trans_to_raw_context((char *)context, &rcontext)) {
3858601
+			g_error ("selinux_trans_to_raw_context: failed to allocate bytes");
3858601
+		        return;
3858601
+		}
3858601
+	        info->context = g_strdup (rcontext);
3858601
+		freecon (rcontext);
3858601
+#endif
3858601
+	} else {
3858601
+	        info->context = NULL;
3858601
+	}
3858601
 	info->callback = callback;
3858601
 	info->callback_data = callback_data;
3858601
 
3858601
@@ -3396,6 +3439,8 @@ nautilus_file_set_permissions_recursive 
3858601
 
3858601
 	if (info->current_dir == NULL) {
3858601
 		info->callback (info->callback_data);
3858601
+		/* All parts of info should be freed now */
3858601
+		g_free (info->context);
3858601
 		g_free (info);
3858601
 		return;
3858601
 	}
3858601
--- nautilus-2.19.2/libnautilus-private/nautilus-file-operations.h.selinux	2007-04-03 06:08:46.000000000 -0400
3858601
+++ nautilus-2.19.2/libnautilus-private/nautilus-file-operations.h	2007-05-19 22:20:22.000000000 -0400
3858601
@@ -82,6 +82,7 @@ void nautilus_file_set_permissions_recur
3858601
 					      GnomeVFSFilePermissions         file_mask,
3858601
 					      GnomeVFSFilePermissions         folder_permissions,
3858601
 					      GnomeVFSFilePermissions         folder_mask,
3858601
+					      const char                     *context,
3858601
 					      NautilusSetPermissionsCallback  callback,
3858601
 					      gpointer                        callback_data);
3858601
 
3858601
--- nautilus-2.19.2/libnautilus-private/nautilus-file.c.selinux	2007-05-09 04:32:15.000000000 -0400
3858601
+++ nautilus-2.19.2/libnautilus-private/nautilus-file.c	2007-05-19 22:20:22.000000000 -0400
3858601
@@ -3589,7 +3589,7 @@ nautilus_file_can_get_selinux_context (N
3858601
  * context
3858601
  * @file: NautilusFile representing the file in question.
3858601
  * 
3858601
- * Returns: Newly allocated string ready to display to the user.
3858601
+ * Returns: Newly allocated string ready to display to the user, or NULL.
3858601
  * 
3858601
  **/
3858601
 char *
3858601
@@ -3622,6 +3622,134 @@ nautilus_file_get_selinux_context (Nauti
3858601
 	return translated;
3858601
 }
3858601
 
3858601
+/**
3858601
+ * nautilus_file_get_selinux_matchpathcon:
3858601
+ * 
3858601
+ * Get a user-displayable string representing a file's default selinux
3858601
+ * context (as from matchpathcon). Only works on local files.
3858601
+ * @file: NautilusFile representing the file in question.
3858601
+ * 
3858601
+ * Returns: Newly allocated string ready to display to the user, or NULL.
3858601
+ * 
3858601
+ **/
3858601
+char *
3858601
+nautilus_file_get_selinux_matchpathcon (NautilusFile *file)
3858601
+{
3858601
+	char *translated;
3858601
+	char *raw;
3858601
+	char *uri;
3858601
+	char *fname;
3858601
+	
3858601
+	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
3858601
+
3858601
+	translated = NULL;
3858601
+#ifdef HAVE_SELINUX
3858601
+	uri = nautilus_file_get_uri (file);
3858601
+	fname = gnome_vfs_get_local_path_from_uri (uri);
3858601
+	
3858601
+	if (!fname) {
3858601
+	        return NULL;
3858601
+	}
3858601
+
3858601
+	raw = NULL;
3858601
+	if (matchpathcon (fname, file->details->info->permissions, &raw) == 0) {
3858601
+		if (selinux_raw_to_trans_context (raw, &translated) == 0) {
3858601
+			char *tmp;
3858601
+			tmp = g_strdup (translated);
3858601
+			freecon (translated);
3858601
+			translated = tmp;
3858601
+		}
3858601
+		freecon (raw);
3858601
+	}
3858601
+		      
3858601
+	g_free (fname);
3858601
+	g_free (uri);
3858601
+#endif
3858601
+	
3858601
+	return translated;
3858601
+}
3858601
+
3858601
+static void
3858601
+set_selinux_context_callback (GnomeVFSAsyncHandle *handle,
3858601
+			      GnomeVFSResult result,
3858601
+			      GnomeVFSFileInfo *new_info,
3858601
+			      gpointer callback_data)
3858601
+{
3858601
+	set_permissions_callback (handle, result, new_info, callback_data);
3858601
+}
3858601
+
3858601
+void
3858601
+nautilus_file_set_selinux_context (NautilusFile *file, 
3858601
+				   const char *selinux_context,
3858601
+				   NautilusFileOperationCallback callback,
3858601
+				   gpointer callback_data)
3858601
+{
3858601
+	Operation *op;
3858601
+	GnomeVFSURI *vfs_uri;
3858601
+	GnomeVFSFileInfo *partial_file_info;
3858601
+	GnomeVFSFileInfoOptions options;
3858601
+        char *rcontext;
3858601
+
3858601
+	rcontext = NULL;
3858601
+	
3858601
+	/* this is probably mostly right... */
3858601
+	if (!nautilus_file_can_set_permissions (file)) {
3858601
+		/* Claim that something changed even if the permission change failed.
3858601
+		 * This makes it easier for some clients who see the "reverting"
3858601
+		 * to the old permissions as "changing back".
3858601
+		 */
3858601
+		nautilus_file_changed (file);
3858601
+		(* callback) (file, GNOME_VFS_ERROR_ACCESS_DENIED, callback_data);
3858601
+		return;
3858601
+	}
3858601
+			       
3858601
+	/* Test the permissions-haven't-changed case explicitly
3858601
+	 * because we don't want to send the file-changed signal if
3858601
+	 * nothing changed.
3858601
+	 */
3858601
+	if (file->details->info->selinux_context != NULL &&
3858601
+	    strcmp(selinux_context, file->details->info->selinux_context) == 0) {
3858601
+		(* callback) (file, GNOME_VFS_OK, callback_data);
3858601
+		return;
3858601
+	}
3858601
+
3858601
+#ifdef HAVE_SELINUX
3858601
+	/* this is really const, but prototype is wrong, *sigh* */
3858601
+	if (selinux_trans_to_raw_context((char *)selinux_context, &rcontext)) {
3858601
+		(* callback) (file, GNOME_VFS_ERROR_NO_MEMORY, callback_data);
3858601
+		return;
3858601
+	}
3858601
+	selinux_context = rcontext;
3858601
+#endif
3858601
+	
3858601
+	/* Set up a context change operation. */
3858601
+	op = operation_new (file, callback, callback_data);
3858601
+	op->use_slow_mime = file->details->got_slow_mime_type;
3858601
+
3858601
+	options = NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS;
3858601
+	if (op->use_slow_mime) {
3858601
+		options |= GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE;
3858601
+	}
3858601
+	/* Change the file-on-disk context. */
3858601
+	partial_file_info = gnome_vfs_file_info_new ();
3858601
+	g_free (partial_file_info->selinux_context);
3858601
+	partial_file_info->selinux_context = g_strdup (selinux_context);
3858601
+	vfs_uri = nautilus_file_get_gnome_vfs_uri (file);
3858601
+	gnome_vfs_async_set_file_info (&op->handle,
3858601
+				       vfs_uri, partial_file_info, 
3858601
+				       GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT,
3858601
+				       options,
3858601
+				       GNOME_VFS_PRIORITY_DEFAULT,
3858601
+				       set_selinux_context_callback, op);
3858601
+	gnome_vfs_file_info_unref (partial_file_info);
3858601
+	gnome_vfs_uri_unref (vfs_uri);
3858601
+
3858601
+#ifdef HAVE_SELINUX
3858601
+	freecon (rcontext);
3858601
+#endif
3858601
+}
3858601
+
3858601
+
3858601
 static char *
3858601
 get_real_name (const char *name, const char *gecos)
3858601
 {
3858601
@@ -3824,7 +3952,7 @@ set_owner_and_group_callback (GnomeVFSAs
3858601
 			      GnomeVFSResult result,
3858601
 			      GnomeVFSFileInfo *new_info,
3858601
 			      gpointer callback_data)
3858601
-{
3858601
+{ /* FIXME: this is identical to set_permissions_callback */
3858601
 	Operation *op;
3858601
 
3858601
 	op = callback_data;
3858601
--- nautilus-2.19.2/libnautilus-private/nautilus-file.h.selinux	2007-04-03 06:08:46.000000000 -0400
3858601
+++ nautilus-2.19.2/libnautilus-private/nautilus-file.h	2007-05-19 22:20:22.000000000 -0400
3858601
@@ -200,6 +200,7 @@ GList *                 nautilus_get_all
3858601
 GList *                 nautilus_file_get_settable_group_names          (NautilusFile                   *file);
3858601
 gboolean                nautilus_file_can_get_selinux_context           (NautilusFile                   *file);
3858601
 char *                  nautilus_file_get_selinux_context               (NautilusFile                   *file);
3858601
+char *                  nautilus_file_get_selinux_matchpathcon          (NautilusFile                   *file);
3858601
 
3858601
 /* "Capabilities". */
3858601
 gboolean                nautilus_file_can_read                          (NautilusFile                   *file);
3858601
@@ -226,6 +227,10 @@ void                    nautilus_file_se
3858601
 									 GnomeVFSFilePermissions         permissions,
3858601
 									 NautilusFileOperationCallback   callback,
3858601
 									 gpointer                        callback_data);
3858601
+void                    nautilus_file_set_selinux_context               (NautilusFile *file, 
3858601
+									 const char *selinux_context,
3858601
+									 NautilusFileOperationCallback callback,
3858601
+									 gpointer callback_data);
3858601
 void                    nautilus_file_rename                            (NautilusFile                   *file,
3858601
 									 const char                     *new_name,
3858601
 									 NautilusFileOperationCallback   callback,