diff -rup nautilus-2.15.92.1-orig/libnautilus-private/nautilus-file.c nautilus-2.15.92.1/libnautilus-private/nautilus-file.c --- nautilus-2.15.92.1-orig/libnautilus-private/nautilus-file.c 2006-08-21 05:48:30.000000000 -0400 +++ nautilus-2.15.92.1/libnautilus-private/nautilus-file.c 2006-08-28 14:29:26.000000000 -0400 @@ -3567,7 +3567,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 * @@ -3600,6 +3600,131 @@ 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 = NULL; + char *raw = NULL; + char *uri = NULL; + char *fname = NULL; + + g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL); + +#ifdef HAVE_SELINUX + uri = nautilus_file_get_uri (file); + fname = gnome_vfs_get_local_path_from_uri (uri); + + if (!fname) { + return NULL; + } + + if (matchpathcon (fname, file->details->info->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_free (uri); +#endif + + return translated; +} + +static void +set_selinux_context_callback (GnomeVFSAsyncHandle *handle, + GnomeVFSResult result, + GnomeVFSFileInfo *new_info, + gpointer callback_data) +{ + set_permissions_callback(handle, result, new_info, callback_data); +} + +void +nautilus_file_set_selinux_context (NautilusFile *file, + const char *selinux_context, + NautilusFileOperationCallback callback, + gpointer callback_data) +{ + Operation *op; + GnomeVFSURI *vfs_uri; + GnomeVFSFileInfo *partial_file_info; + GnomeVFSFileInfoOptions options; +#ifdef HAVE_SELINUX + security_context_t rcontext = NULL; +#endif + + /* 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); + (* callback) (file, GNOME_VFS_ERROR_ACCESS_DENIED, callback_data); + return; + } + + /* Test the permissions-haven't-changed case explicitly + * because we don't want to send the file-changed signal if + * nothing changed. + */ + if (!strcmp(selinux_context, file->details->info->selinux_context)) { + (* callback) (file, GNOME_VFS_OK, 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)) { + (* callback) (file, GNOME_VFS_ERROR_NO_MEMORY, callback_data); + return; + } + selinux_context = rcontext; +#endif + + /* Set up a context change operation. */ + op = operation_new (file, callback, callback_data); + op->use_slow_mime = file->details->got_slow_mime_type; + + options = NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS; + if (op->use_slow_mime) { + options |= GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE; + } + /* Change the file-on-disk context. */ + partial_file_info = gnome_vfs_file_info_new (); + g_free (partial_file_info->selinux_context); + partial_file_info->selinux_context = g_strdup (selinux_context); + vfs_uri = nautilus_file_get_gnome_vfs_uri (file); + gnome_vfs_async_set_file_info (&op->handle, + vfs_uri, partial_file_info, + GNOME_VFS_SET_FILE_INFO_SELINUX_CONTEXT, + options, + GNOME_VFS_PRIORITY_DEFAULT, + set_selinux_context_callback, op); + gnome_vfs_file_info_unref (partial_file_info); + gnome_vfs_uri_unref (vfs_uri); + +#ifdef HAVE_SELINUX + freecon (rcontext); +#endif +} + + static char * get_real_name (const char *name, const char *gecos) { @@ -3802,7 +3927,7 @@ set_owner_and_group_callback (GnomeVFSAs GnomeVFSResult result, GnomeVFSFileInfo *new_info, gpointer callback_data) -{ +{ /* FIXME: this is identical to set_permissions_callback */ Operation *op; op = callback_data; Only in nautilus-2.15.92.1/libnautilus-private: nautilus-file.c~ diff -rup nautilus-2.15.92.1-orig/libnautilus-private/nautilus-file.h nautilus-2.15.92.1/libnautilus-private/nautilus-file.h --- nautilus-2.15.92.1-orig/libnautilus-private/nautilus-file.h 2006-06-16 10:29:22.000000000 -0400 +++ nautilus-2.15.92.1/libnautilus-private/nautilus-file.h 2006-08-26 00:41:28.000000000 -0400 @@ -200,6 +200,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); @@ -226,6 +227,10 @@ void nautilus_file_se GnomeVFSFilePermissions 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, Only in nautilus-2.15.92.1/libnautilus-private: nautilus-file.h~ diff -rup nautilus-2.15.92.1-orig/src/file-manager/fm-error-reporting.c nautilus-2.15.92.1/src/file-manager/fm-error-reporting.c --- nautilus-2.15.92.1-orig/src/file-manager/fm-error-reporting.c 2006-03-20 08:35:58.000000000 -0500 +++ nautilus-2.15.92.1/src/file-manager/fm-error-reporting.c 2006-08-28 14:19:51.000000000 -0400 @@ -251,6 +251,38 @@ fm_report_error_setting_permissions (Nau g_free (message); } +void +fm_report_error_setting_selinux (NautilusFile *file, + GnomeVFSResult error, + GtkWindow *parent_window) +{ + char *file_name; + char *message; + + if (error == GNOME_VFS_OK) { + return; + } + + file_name = nautilus_file_get_display_name (file); + + switch (error) { + case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM: + message = g_strdup_printf (_("Couldn't change the SELinux security context of \"%s\" because it is on a read-only disk"), + file_name); + break; + default: + /* We should invent decent error messages for every case we actually experience. */ + g_warning ("Hit unhandled case %d (%s) in fm_report_error_setting_permissions", + error, gnome_vfs_result_to_string (error)); + message = g_strdup_printf (_("Sorry, couldn't change the permissions of \"%s\"."), file_name); + } + + 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; Only in nautilus-2.15.92.1/src/file-manager: fm-error-reporting.c~ diff -rup nautilus-2.15.92.1-orig/src/file-manager/fm-error-reporting.h nautilus-2.15.92.1/src/file-manager/fm-error-reporting.h --- nautilus-2.15.92.1-orig/src/file-manager/fm-error-reporting.h 2006-02-21 05:34:00.000000000 -0500 +++ nautilus-2.15.92.1/src/file-manager/fm-error-reporting.h 2006-08-28 14:18:55.000000000 -0400 @@ -39,7 +39,10 @@ void fm_report_error_renaming_file GnomeVFSResult error_code, GtkWindow *parent_window); void fm_report_error_setting_permissions (NautilusFile *file, - GnomeVFSResult error_code, + GnomeVFSResult error_code, + GtkWindow *parent_window); +void fm_report_error_setting_selinux (NautilusFile *file, + GnomeVFSResult error_code, GtkWindow *parent_window); void fm_report_error_setting_owner (NautilusFile *file, GnomeVFSResult error_code, Only in nautilus-2.15.92.1/src/file-manager: fm-error-reporting.h~ diff -rup nautilus-2.15.92.1-orig/src/file-manager/fm-properties-window.c nautilus-2.15.92.1/src/file-manager/fm-properties-window.c --- nautilus-2.15.92.1-orig/src/file-manager/fm-properties-window.c 2006-08-21 05:33:59.000000000 -0400 +++ nautilus-2.15.92.1/src/file-manager/fm-properties-window.c 2006-08-28 19:37:28.000000000 -0400 @@ -83,6 +83,10 @@ #include #include +#ifdef HAVE_SELINUX +# include +#endif + #define PREVIEW_IMAGE_WIDTH 96 #define ROW_PAD 6 @@ -102,7 +106,7 @@ struct FMPropertiesWindowDetails { GtkWidget *icon_button; GtkWidget *icon_image; - GtkWidget *icon_chooser; + GtkWidget *icon_chooser; GtkWidget *name_label; GtkWidget *name_field; @@ -130,6 +134,8 @@ struct FMPropertiesWindowDetails { GList *value_fields; + GList *edit_fields; + GList *mime_list; gboolean deep_count_finished; @@ -208,6 +214,8 @@ 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 properties_window_update (FMPropertiesWindow *window, GList *files); static void is_directory_ready_callback (NautilusFile *file, @@ -235,10 +243,28 @@ static GtkLabel *attach_ellipsizing_valu int row, int column, const char *initial_text); +static void attach_selinux_data_edit_field (GtkEntry *entry, + char *attr_value, + char *def_attr_value); + G_DEFINE_TYPE (FMPropertiesWindow, fm_properties_window, GTK_TYPE_WINDOW); #define parent_class fm_properties_window_parent_class +static void maybe_gtk_entry_set_text(GtkEntry *entry, const char *val) +{ + char *old_val = NULL; + + 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) { @@ -494,7 +520,7 @@ fm_properties_window_drag_data_received return; } - uris = g_strsplit (selection_data->data, "\r\n", 0); + uris = g_strsplit ((char *) selection_data->data, "\r\n", 0); exactly_one = uris[0] != NULL && (uris[1] == NULL || uris[1][0] == '\0'); @@ -575,7 +601,7 @@ create_image_widget (FMPropertiesWindow static void set_name_field (FMPropertiesWindow *window, const gchar *original_name, - const gchar *name) + const gchar *name) { gboolean new_widget; gboolean use_label; @@ -641,11 +667,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); } } } @@ -721,7 +743,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"); @@ -730,14 +751,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 @@ -850,7 +865,7 @@ file_has_keyword (NautilusFile *file, co word = g_list_find_custom (keywords, keyword, (GCompareFunc) strcmp); eel_g_list_free_deep (keywords); - return (word != NULL); + return word != NULL; } static void @@ -1117,7 +1132,7 @@ mime_list_equal (GList *a, GList *b) b = b->next; } - return (a == b); + return a == b; } static GList * @@ -1199,6 +1214,10 @@ 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)); + } } mime_list = get_mime_list (window); @@ -1379,6 +1398,46 @@ value_field_update (FMPropertiesWindow * ellipsize_text); } +static void +edit_field_update_internal (GtkEntry *entry, + GList *file_list) +{ + const char *attr_name; + char *attr_value = NULL; + char *def_attr_value = NULL; + char *inconsistent_string; + + 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); +} + +static void +edit_field_update (FMPropertiesWindow *window, GtkEntry *entry) +{ + gboolean use_original; + + 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 GtkLabel * attach_label (GtkTable *table, int row, @@ -1430,6 +1489,45 @@ attach_value_label (GtkTable *table, return attach_label (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE); } +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); +} + static GtkLabel * attach_ellipsizing_value_label (GtkTable *table, int row, @@ -1489,6 +1587,674 @@ attach_value_field (FMPropertiesWindow * } 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 (window)->window, cursor); + gdk_cursor_unref (cursor); + } + window->details->long_operation_underway ++; +} + +static void +end_long_operation (FMPropertiesWindow *window) +{ + if (GTK_WIDGET (window)->window != NULL && + window->details->long_operation_underway == 1) { + /* finished !! */ + gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); + } + window->details->long_operation_underway--; +} + +static void +selinux_change_callback (NautilusFile *file, GnomeVFSResult result, 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, result, 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_SENSITIVE (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); +} + +/* 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 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; + + 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 { + + GtkTreeModel *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; +} + +static GSList * +selinux__type_list (void) +{ + static GSList *cust_types; + static time_t file_mtime; + const char *fname_ctypes; + struct stat buf; + GIOChannel *ioc_ctypes; + GError *errc; + GSList *scan; + int fd; + +#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) +{ + const char *fname_ctypes; + 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, TRUE); + 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); + 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) { + /* 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); + } +} + +# 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 httpd/ftp/CIFS")); + HACK_TYPE("public_content_t", _("Read from httpd/ftp/CIFS")); + 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); + 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; + + 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)); + + attach_selinux_data_popup_field (GTK_COMBO_BOX (comb), + attr_value, def_attr_value); + + g_signal_connect_object (comb, "changed", + G_CALLBACK (selinux_popup_activate), window, 0); + + 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, TRUE); + 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, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell, + "text", 1, NULL); + gtk_widget_show (comb); +} + +static void attach_ellipsizing_value_field (FMPropertiesWindow *window, GtkTable *table, int row, @@ -2425,7 +3191,7 @@ append_title_value_pair (FMPropertiesWin gboolean show_original) { guint last_row; - + last_row = append_title_field (table, title, NULL); attach_value_field (window, table, last_row, VALUE_COLUMN, file_attribute_name, @@ -2436,6 +3202,33 @@ append_title_value_pair (FMPropertiesWin } 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 = 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; +} + +static guint append_title_and_ellipsizing_value (FMPropertiesWindow *window, GtkTable *table, const char *title, @@ -2893,31 +3686,6 @@ create_emblems_page (FMPropertiesWindow } 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 (window)->window, cursor); - gdk_cursor_unref (cursor); - } - window->details->long_operation_underway ++; -} - -static void -end_long_operation (FMPropertiesWindow *window) -{ - if (GTK_WIDGET (window)->window != NULL && - window->details->long_operation_underway == 1) { - /* finished !! */ - gdk_window_set_cursor (GTK_WIDGET (window)->window, NULL); - } - window->details->long_operation_underway--; -} - -static void permission_change_callback (NautilusFile *file, GnomeVFSResult result, gpointer callback_data) { FMPropertiesWindow *window; @@ -4031,7 +4799,7 @@ set_recursive_permissions_done (gpointer static void apply_recursive_clicked (GtkWidget *recursive_button, FMPropertiesWindow *window) -{ +{ /* FIXME: doesn't do SELinux context atm. */ GnomeVFSFilePermissions file_permission, file_permission_mask; GnomeVFSFilePermissions dir_permission, dir_permission_mask; GnomeVFSFilePermissions vfs_mask, vfs_new_perm, p; @@ -4180,8 +4948,8 @@ create_permissions_page (FMPropertiesWin gtk_table_set_row_spacing (page_table, page_table->nrows - 1, 18); - append_title_value_pair - (window, page_table, _("SELinux Context:"), + append_title_selinux_edit_pair + (window, page_table, _("_SELinux Context:"), "selinux_context", _("--"), FALSE); append_title_value_pair Only in nautilus-2.15.92.1/src/file-manager: fm-properties-window.c~