spacepaste

a/libnautilus-extension/nautilus-column.c
b/libnautilus-extension/nautilus-column.c
34 34 PROP_LABEL,
35 35 PROP_DESCRIPTION,
36 36 PROP_XALIGN,
37 PROP_ELLIPSIZE,
37 38 LAST_PROP
38 39 };
39 40
43 44 char *label;
44 45 char *description;
45 46 float xalign;
47 gboolean ellipsize;
46 48 };
47 49
48 50 G_DEFINE_TYPE (NautilusColumn, nautilus_column, G_TYPE_OBJECT);
110 112 case PROP_XALIGN :
111 113 g_value_set_float (value, column->details->xalign);
112 114 break;
115 case PROP_ELLIPSIZE :
116 g_value_set_boolean (value, column->details->ellipsize);
117 break;
113 118 default :
114 119 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
115 120 break;
151 156 column->details->xalign = g_value_get_float (value);
152 157 g_object_notify (object, "xalign");
153 158 break;
159 case PROP_ELLIPSIZE :
160 column->details->ellipsize = g_value_get_boolean (value);
161 g_object_notify (object, "ellipsize");
162 break;
154 163 default :
155 164 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
156 165 break;
178 187 {
179 188 column->details = g_new0 (NautilusColumnDetails, 1);
180 189 column->details->xalign = 0.0;
190 column->details->ellipsize = FALSE;
181 191 }
182 192
183 193 static void
232 242 1.0,
233 243 0.0,
234 244 G_PARAM_READWRITE));
245 g_object_class_install_property (G_OBJECT_CLASS (class),
246 PROP_ELLIPSIZE,
247 g_param_spec_boolean ("ellipsize",
248 "ellipsize",
249 "Ellipsize text in the column if it's too long to display",
250 FALSE,
251 G_PARAM_READWRITE));
235 252 }
236 253
a/libnautilus-extension/nautilus-column.h
b/libnautilus-extension/nautilus-column.h
64 64 * label (string) - the user-visible label for the column
65 65 * description (string) - a user-visible description of the column
66 66 * xalign (float) - x-alignment of the column
67 * ellipsize (boolean) - ellipsize text in the column?
67 68 */
68 69
69 70 G_END_DECLS
a/libnautilus-private/nautilus-column-utilities.c
b/libnautilus-private/nautilus-column-utilities.c
120 120 "attribute", "selinux_context",
121 121 "label", _("SELinux Context"),
122 122 "description", _("The SELinux security context of the file."),
123 "ellipsize", TRUE,
123 124 NULL));
124 125 #endif
125 126 columns = g_list_append (columns,
a/libnautilus-private/nautilus-file-operations.c
b/libnautilus-private/nautilus-file-operations.c
64 64 #include "nautilus-file-utilities.h"
65 65 #include "nautilus-file-conflict-dialog.h"
66 66
67 #ifdef HAVE_SELINUX
68 #include <selinux/selinux.h>
69 #endif
70
67 71 /* TODO: TESTING!!! */
68 72
69 73 typedef struct {
148 152 guint32 file_mask;
149 153 guint32 dir_permissions;
150 154 guint32 dir_mask;
155 char *context;
151 156 } SetPermissionsJob;
152 157
153 158 typedef enum {
5453 5458 job->done_callback (job->done_callback_data);
5454 5459 }
5455 5460
5461 if (job->context) {
5462 g_free (job->context);
5463 }
5464
5456 5465 finalize_common ((CommonJob *)job);
5457 5466 return FALSE;
5458 5467 }
5508 5517 current, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
5509 5518 common->cancellable, NULL);
5510 5519 }
5520
5521 #ifdef HAVE_SELINUX
5522 if (!job_aborted (common) && (job->context)) {
5523 g_file_set_attribute_string (file, G_FILE_ATTRIBUTE_SELINUX_CONTEXT,
5524 job->context, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
5525 common->cancellable, NULL);
5526 }
5527 #endif
5511 5528
5512 5529 if (!job_aborted (common) &&
5513 5530 g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
5571 5588 guint32 file_mask,
5572 5589 guint32 dir_permissions,
5573 5590 guint32 dir_mask,
5591 const char *context,
5574 5592 NautilusOpCallback callback,
5575 5593 gpointer callback_data)
5576 5594 {
5584 5602 job->dir_mask = dir_mask;
5585 5603 job->done_callback = callback;
5586 5604 job->done_callback_data = callback_data;
5587
5605
5606 if (context) {
5607 char *rcontext;
5608
5609 rcontext = job->context = NULL;
5610 #ifdef HAVE_SELINUX
5611 /* this is really const, but prototype is wrong, *sigh* */
5612 if (selinux_trans_to_raw_context((char *)context, &rcontext)) {
5613 g_error ("selinux_trans_to_raw_context: failed to allocate bytes");
5614 return;
5615 }
5616 job->context = g_strdup (rcontext);
5617 freecon (rcontext);
5618 #endif
5619 } else {
5620 job->context = NULL;
5621 }
5622
5588 5623 g_io_scheduler_push_job (set_permissions_job,
5589 5624 job,
5590 5625 NULL,
a/libnautilus-private/nautilus-file-operations.h
b/libnautilus-private/nautilus-file-operations.h
94 94 guint32 file_mask,
95 95 guint32 folder_permissions,
96 96 guint32 folder_mask,
97 const char *context,
97 98 NautilusOpCallback callback,
98 99 gpointer callback_data);
99 100
a/libnautilus-private/nautilus-file.c
b/libnautilus-private/nautilus-file.c
2171 2171 file->details->is_mountpoint = is_mountpoint;
2172 2172
2173 2173 has_permissions = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE);
2174 permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);;
2174 permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);
2175 2175 if (file->details->has_permissions != has_permissions ||
2176 2176 file->details->permissions != permissions) {
2177 2177 changed = TRUE;
5077 5077 * context
5078 5078 * @file: NautilusFile representing the file in question.
5079 5079 *
5080 * Returns: Newly allocated string ready to display to the user.
5080 * Returns: Newly allocated string ready to display to the user, or NULL.
5081 5081 *
5082 5082 **/
5083 5083 char *
5110 5110 return translated;
5111 5111 }
5112 5112
5113 /**
5114 * nautilus_file_get_selinux_matchpathcon:
5115 *
5116 * Get a user-displayable string representing a file's default selinux
5117 * context (as from matchpathcon). Only works on local files.
5118 * @file: NautilusFile representing the file in question.
5119 *
5120 * Returns: Newly allocated string ready to display to the user, or NULL.
5121 *
5122 **/
5123 char *
5124 nautilus_file_get_selinux_matchpathcon (NautilusFile *file)
5125 {
5126 char *translated;
5127 #ifdef HAVE_SELINUX
5128 char *raw;
5129 char *fname;
5130 GFile *location;
5131 #endif
5132
5133 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
5134
5135 translated = NULL;
5136 #ifdef HAVE_SELINUX
5137 location = nautilus_file_get_location (file);
5138 fname = g_file_get_path (location);
5139
5140 if (!fname) {
5141 return NULL;
5142 }
5143
5144 raw = NULL;
5145 if (matchpathcon (fname, file->details->permissions, &raw) == 0) {
5146 if (selinux_raw_to_trans_context (raw, &translated) == 0) {
5147 char *tmp;
5148 tmp = g_strdup (translated);
5149 freecon (translated);
5150 translated = tmp;
5151 }
5152 freecon (raw);
5153 }
5154
5155 g_free (fname);
5156 g_object_unref (location);
5157 #endif
5158
5159 return translated;
5160 }
5161
5162 void
5163 nautilus_file_set_selinux_context (NautilusFile *file,
5164 const char *selinux_context,
5165 NautilusFileOperationCallback callback,
5166 gpointer callback_data)
5167 {
5168 GFileInfo *info;
5169 GError *error;
5170 char *rcontext;
5171
5172 rcontext = NULL;
5173
5174 /* this is probably mostly right... */
5175 if (!nautilus_file_can_set_permissions (file)) {
5176 /* Claim that something changed even if the permission change failed.
5177 * This makes it easier for some clients who see the "reverting"
5178 * to the old permissions as "changing back".
5179 */
5180 nautilus_file_changed (file);
5181 error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
5182 _("Not allowed to set SELinux security context"));
5183 (* callback) (file, NULL, error, callback_data);
5184 g_error_free (error);
5185 return;
5186 }
5187
5188 /* Test the permissions-haven't-changed case explicitly
5189 * because we don't want to send the file-changed signal if
5190 * nothing changed.
5191 */
5192 if (file->details->selinux_context != NULL &&
5193 strcmp(selinux_context, file->details->selinux_context) == 0) {
5194 (* callback) (file, NULL, NULL, callback_data);
5195 return;
5196 }
5197
5198 #ifdef HAVE_SELINUX
5199 /* this is really const, but prototype is wrong, *sigh* */
5200 if (selinux_trans_to_raw_context((char *)selinux_context, &rcontext)) {
5201 error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVAL,
5202 _("Invalid SELinux security context"));
5203 (* callback) (file, NULL, error, callback_data);
5204 g_error_free (error);
5205 return;
5206 }
5207 selinux_context = rcontext;
5208 #endif
5209
5210 info = g_file_info_new ();
5211 g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_SELINUX_CONTEXT, selinux_context);
5212 nautilus_file_set_attributes (file, info, callback, callback_data);
5213 g_object_unref (info);
5214
5215 #ifdef HAVE_SELINUX
5216 freecon (rcontext);
5217 #endif
5218 }
5219
5220
5113 5221 static char *
5114 5222 get_real_name (const char *name, const char *gecos)
5115 5223 {
a/libnautilus-private/nautilus-file.h
b/libnautilus-private/nautilus-file.h
240 240 GList * nautilus_file_get_settable_group_names (NautilusFile *file);
241 241 gboolean nautilus_file_can_get_selinux_context (NautilusFile *file);
242 242 char * nautilus_file_get_selinux_context (NautilusFile *file);
243 char * nautilus_file_get_selinux_matchpathcon (NautilusFile *file);
243 244
244 245 /* "Capabilities". */
245 246 gboolean nautilus_file_can_read (NautilusFile *file);
300 301 guint32 permissions,
301 302 NautilusFileOperationCallback callback,
302 303 gpointer callback_data);
304 void nautilus_file_set_selinux_context (NautilusFile *file,
305 const char *selinux_context,
306 NautilusFileOperationCallback callback,
307 gpointer callback_data);
303 308 void nautilus_file_rename (NautilusFile *file,
304 309 const char *new_name,
305 310 NautilusFileOperationCallback callback,
a/src/nautilus-error-reporting.c
b/src/nautilus-error-reporting.c
172 172 g_free (message);
173 173 }
174 174
175 void
176 nautilus_report_error_setting_selinux (NautilusFile *file,
177 GError *error,
178 GtkWindow *parent_window)
179 {
180 char *file_name;
181 char *message;
182
183 if (error == NULL) {
184 return;
185 }
186
187 file_name = nautilus_file_get_display_name (file);
188
189 message = g_strdup_printf (_("Sorry, couldn't change the permissions of \"%s\": %s"), file_name, error->message);
190
191 /* Silently drop the error when called from selinux entry and is not finished yet */
192 if (! g_error_matches(error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) {
193 eel_show_error_dialog (_("The SELinux security context could not be changed."), message, parent_window);
194 }
195
196 g_free (file_name);
197 g_free (message);
198 }
199
175 200 typedef struct _NautilusRenameData {
176 201 char *name;
177 202 NautilusFileOperationCallback callback;
a/src/nautilus-error-reporting.h
b/src/nautilus-error-reporting.h
45 45 void nautilus_report_error_setting_group (NautilusFile *file,
46 46 GError *error,
47 47 GtkWindow *parent_window);
48 void nautilus_report_error_setting_selinux (NautilusFile *file,
49 GError *error,
50 GtkWindow *parent_window);
48 51
49 52 /* FIXME bugzilla.gnome.org 42394: Should this file be renamed or should this function be moved? */
50 53 void nautilus_rename_file (NautilusFile *file,
a/src/nautilus-list-view.c
b/src/nautilus-list-view.c
1628 1628 char *name;
1629 1629 char *label;
1630 1630 float xalign;
1631 gboolean ellipsize;
1631 1632
1632 1633 nautilus_column = NAUTILUS_COLUMN (l->data);
1633 1634
1634 1635 g_object_get (nautilus_column,
1635 1636 "name", &name,
1636 1637 "label", &label,
1637 "xalign", &xalign, NULL);
1638 "xalign", &xalign,
1639 "ellipsize", &ellipsize, NULL);
1638 1640
1639 1641 column_num = nautilus_list_model_add_column (view->details->model,
1640 1642 nautilus_column);
1679 1681 } else {
1680 1682 cell = gtk_cell_renderer_text_new ();
1681 1683 g_object_set (cell, "xalign", xalign, NULL);
1684 if (ellipsize)
1685 g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1682 1686 view->details->cells = g_list_append (view->details->cells,
1683 1687 cell);
1684 1688 column = gtk_tree_view_column_new_with_attributes (label,
a/src/nautilus-properties-window.c
b/src/nautilus-properties-window.c
79 79 #define FREE_FILL_B 0.811764706
80 80
81 81
82 #ifdef HAVE_SELINUX
83 # include <selinux/selinux.h>
84 #endif
85
82 86 #define PREVIEW_IMAGE_WIDTH 96
83 87
84 88 #define ROW_PAD 6
118 122 unsigned int owner_change_timeout;
119 123
120 124 GList *permission_buttons;
121 GList *permission_combos;
125 GList *permission_combos; /* how is this deallocated???? */
126 GList *selinux_combo;
122 127 GHashTable *initial_permissions;
123 128 gboolean has_recursive_apply;
124 129
125 130 GList *value_fields;
126 131
132 GList *edit_fields;
133
127 134 GList *mime_list;
128 135
129 136 gboolean deep_count_finished;
206 213 GtkComboBox *combo);
207 214 static void value_field_update (NautilusPropertiesWindow *window,
208 215 GtkLabel *field);
216 static void edit_field_update (NautilusPropertiesWindow *window,
217 GtkEntry *field);
218 static void popup_field_update (NautilusPropertiesWindow *window,
219 GtkComboBox *entry);
209 220 static void properties_window_update (NautilusPropertiesWindow *window,
210 221 GList *files);
211 222 static void is_directory_ready_callback (NautilusFile *file,
235 246 const char *initial_text);
236 247
237 248 static GtkWidget* create_pie_widget (NautilusPropertiesWindow *window);
249
250 static void attach_selinux_data_edit_field (GtkEntry *entry,
251 char *attr_value,
252 char *def_attr_value);
253
254 #ifdef HAVE_SELINUX
255 static void attach_selinux_data_popup_field (GtkComboBox *comb,
256 char *attr_val,
257 char *def_attr_val);
258 #endif
238 259
239 260 G_DEFINE_TYPE (NautilusPropertiesWindow, nautilus_properties_window, GTK_TYPE_DIALOG);
240 261 #define parent_class nautilus_properties_window_parent_class
241 262
263 static void
264 maybe_gtk_entry_set_text (GtkEntry *entry, const char *val)
265 {
266 char *old_val;
267
268 g_assert (GTK_IS_ENTRY (entry));
269
270 old_val = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
271
272 if (strcmp (old_val, val) != 0) {
273 gtk_entry_set_text (entry, val);
274 }
275 g_free(old_val);
276 }
277
242 278 static gboolean
243 279 is_multi_file_window (NautilusPropertiesWindow *window)
244 280 {
259 295 return FALSE;
260 296 }
261 297
298 static gboolean
299 all_can_get_permissions (GList *file_list)
300 {
301 GList *l;
302 for (l = file_list; l != NULL; l = l->next) {
303 NautilusFile *file;
304
305 file = NAUTILUS_FILE (l->data);
306
307 if (!nautilus_file_can_get_permissions (file)) {
308 return FALSE;
309 }
310 }
311
312 return TRUE;
313 }
314
315 static gboolean
316 all_can_set_permissions (GList *file_list)
317 {
318 GList *l;
319 for (l = file_list; l != NULL; l = l->next) {
320 NautilusFile *file;
321
322 file = NAUTILUS_FILE (l->data);
323
324 if (!nautilus_file_can_set_permissions (file)) {
325 return FALSE;
326 }
327 }
328
329 return TRUE;
330 }
331
332 #ifdef HAVE_SELINUX
333 static gboolean
334 multi_have_same_selinux_context (NautilusPropertiesWindow *window)
335 {
336 GList *l;
337 char *cntx;
338
339 cntx = NULL;
340 for (l = window->details->original_files; l != NULL; l = l->next) {
341 NautilusFile *file;
342
343 file = NAUTILUS_FILE (l->data);
344 if (!nautilus_file_is_gone (file)) {
345 char *tmp;
346
347 tmp = nautilus_file_get_string_attribute_with_default (file, "selinux_context");
348 if (!cntx) {
349 cntx = tmp;
350 } else if (strcmp (cntx, tmp)) {
351 g_free (tmp);
352 g_free (cntx);
353 return FALSE;
354 }
355 else {
356 g_free (tmp);
357 }
358 }
359 }
360
361 g_free (cntx);
362
363 return TRUE;
364 }
365 #endif
366
367 /* NOTE: This modifies cntx */
368 static void
369 selinux_split_cntx (char *cntx,
370 const char **ret_attr_u,
371 const char **ret_attr_r,
372 const char **ret_attr_t,
373 const char **ret_attr_s)
374 {
375 const char *attr_u;
376 const char *attr_r;
377 const char *attr_t;
378 const char *attr_s;
379
380 attr_u = cntx;
381 if (!(attr_r = strchr (attr_u, ':'))) {
382 attr_r = "object_r"; /* shouldn't happen */
383 } else {
384 *((char *)attr_r++) = 0;
385 }
386
387 if (!(attr_t = strchr (attr_r, ':'))) {
388 attr_t = "file_t"; /* shouldn't happen */
389 } else {
390 *((char *)attr_t++) = 0;
391 }
392
393 if ((attr_s = strchr (attr_t, ':'))) {
394 *((char *)attr_s++) = 0;
395 }
396
397 *ret_attr_u = attr_u;
398 *ret_attr_r = attr_r;
399 *ret_attr_t = attr_t;
400 *ret_attr_s = attr_s;
401 }
402
262 403 static int
263 404 get_not_gone_original_file_count (NautilusPropertiesWindow *window)
264 405 {
634 775 * currently showing. This causes minimal ripples (e.g.
635 776 * selection change).
636 777 */
637 gchar *displayed_name = gtk_editable_get_chars (GTK_EDITABLE (window->details->name_field), 0, -1);
638 if (strcmp (displayed_name, name) != 0) {
639 gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name);
640 }
641 g_free (displayed_name);
778 maybe_gtk_entry_set_text (GTK_ENTRY (window->details->name_field), name);
642 779 }
643 780 }
644 781 }
718 855 name_field_restore_original_name (NautilusEntry *name_field)
719 856 {
720 857 const char *original_name;
721 char *displayed_name;
722 858
723 859 original_name = (const char *) g_object_get_data (G_OBJECT (name_field),
724 860 "original_name");
727 863 return;
728 864 }
729 865
730 displayed_name = gtk_editable_get_chars (GTK_EDITABLE (name_field), 0, -1);
731
732 if (strcmp (original_name, displayed_name) != 0) {
733 gtk_entry_set_text (GTK_ENTRY (name_field), original_name);
734 }
866 maybe_gtk_entry_set_text (GTK_ENTRY (name_field), original_name);
735 867 nautilus_entry_select_all (name_field);
736
737 g_free (displayed_name);
738 868 }
739 869
740 870 static void
1028 1158 for (l = window->details->value_fields; l != NULL; l = l->next) {
1029 1159 value_field_update (window, GTK_LABEL (l->data));
1030 1160 }
1161
1162 for (l = window->details->edit_fields; l != NULL; l = l->next) {
1163 edit_field_update (window, GTK_ENTRY (l->data));
1164 }
1165
1166 for (l = window->details->selinux_combo; l != NULL; l = l->next) {
1167 popup_field_update (window, GTK_COMBO_BOX (l->data));
1168 }
1031 1169 }
1032 1170
1033 1171 mime_list = get_mime_list (window);
1198 1336 window->details->target_files));
1199 1337 }
1200 1338
1339 static void
1340 edit_field_update_internal (GtkEntry *entry,
1341 GList *file_list)
1342 {
1343 const char *attr_name;
1344 char *attr_value;
1345 char *def_attr_value;
1346 char *inconsistent_string;
1347 gboolean sensitive;
1348
1349 g_assert (GTK_IS_ENTRY (entry));
1350
1351 attr_name = g_object_get_data (G_OBJECT (entry), "file_attribute");
1352 inconsistent_string = g_object_get_data (G_OBJECT (entry),
1353 "inconsistent_string");
1354 def_attr_value = g_object_get_data (G_OBJECT (entry),
1355 "matchpathcon_cntx");
1356
1357 attr_value = file_list_get_string_attribute (file_list, attr_name,
1358 inconsistent_string);
1359
1360 maybe_gtk_entry_set_text (GTK_ENTRY (entry), attr_value);
1361
1362 /* JFIXME: this isn't generic, *sigh* ... */
1363 attach_selinux_data_edit_field (entry, attr_value, def_attr_value);
1364 g_free (attr_value);
1365
1366 sensitive = all_can_set_permissions (file_list);
1367 #ifdef HAVE_SELINUX
1368 sensitive = sensitive && is_selinux_enabled ();
1369 #endif
1370 gtk_widget_set_sensitive (GTK_WIDGET (entry), sensitive);
1371 }
1372
1373 static void
1374 edit_field_update (NautilusPropertiesWindow *window, GtkEntry *entry)
1375 {
1376 gboolean use_original;
1377
1378 if (gtk_widget_is_focus (GTK_WIDGET (entry))) {
1379 return;
1380 }
1381
1382 use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (entry), "show_original"));
1383
1384 edit_field_update_internal (entry,
1385 (use_original ?
1386 window->details->original_files :
1387 window->details->target_files));
1388 }
1389
1390 static void
1391 selinux_combo_update_value (GtkComboBox *combo, const char *new_value)
1392 {
1393 GtkTreeModel *model;
1394 GtkTreeIter iter;
1395 char *cntx_type;
1396 gulong handler;
1397
1398 g_assert (GTK_IS_COMBO_BOX (combo));
1399 if (! new_value)
1400 return;
1401
1402 model = gtk_combo_box_get_model (combo);
1403 if (! gtk_tree_model_get_iter_first (model, &iter))
1404 return;
1405
1406 handler = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (combo), "handler_changed"));
1407 g_signal_handler_block (G_OBJECT (combo), handler);
1408
1409 do {
1410 gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
1411
1412 if (cntx_type && (g_ascii_strcasecmp (new_value, cntx_type) == 0)) {
1413 gtk_combo_box_set_active_iter (combo, &iter);
1414 break;
1415 }
1416 }
1417 while (gtk_tree_model_iter_next (model, &iter));
1418 g_signal_handler_unblock (G_OBJECT (combo), handler);
1419 }
1420
1421 static void
1422 popup_field_update_internal (GtkComboBox *combo,
1423 GList *file_list)
1424 {
1425 const char *attr_name;
1426 char *attr_value;
1427 char *inconsistent_string;
1428 char *cntx_type;
1429 const char *attr_u;
1430 const char *attr_r;
1431 const char *attr_t;
1432 const char *attr_s;
1433 gboolean sensitive;
1434 GtkTreeIter iter;
1435
1436
1437 g_assert (GTK_IS_COMBO_BOX (combo));
1438
1439 if (gtk_widget_is_focus (GTK_WIDGET (combo))) {
1440 return;
1441 }
1442
1443
1444 sensitive = all_can_set_permissions (file_list);
1445 #ifdef HAVE_SELINUX
1446 sensitive = sensitive && is_selinux_enabled ();
1447 #endif
1448 gtk_widget_set_sensitive (GTK_WIDGET (combo), sensitive);
1449
1450
1451 attr_name = g_object_get_data (G_OBJECT (combo), "file_attribute");
1452 inconsistent_string = g_object_get_data (G_OBJECT (combo),
1453 "inconsistent_string");
1454
1455 attr_value = file_list_get_string_attribute (file_list, attr_name,
1456 inconsistent_string);
1457
1458 selinux_split_cntx (attr_value, &attr_u, &attr_r, &attr_t, &attr_s);
1459
1460 /* JFIXME: this isn't generic, *sigh* ... */
1461 if (gtk_combo_box_get_active_iter (combo, &iter)) {
1462 GtkTreeModel *model = gtk_combo_box_get_model (combo);
1463
1464 /* don't update, if it's identical */
1465 gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
1466 if (cntx_type && strcmp (cntx_type, attr_t) == 0) {
1467 g_free (attr_value);
1468 return;
1469 }
1470 }
1471
1472 selinux_combo_update_value (combo, attr_t);
1473
1474 g_free (attr_value);
1475 }
1476
1477 static void
1478 popup_field_update (NautilusPropertiesWindow *window, GtkComboBox *combo)
1479 {
1480 gboolean use_original;
1481
1482 if (! window->details->selinux_combo) {
1483 return;
1484 }
1485
1486 use_original = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "show_original"));
1487
1488 popup_field_update_internal (combo,
1489 (use_original ?
1490 window->details->original_files :
1491 window->details->target_files));
1492 }
1493
1201 1494 static GtkLabel *
1202 1495 attach_label (GtkTable *table,
1203 1496 int row,
1252 1545 return attach_label (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE);
1253 1546 }
1254 1547
1548 #ifdef HAVE_SELINUX
1549 static GtkEntry *
1550 attach_edit (GtkTable *table,
1551 int row,
1552 int column,
1553 const char *initial_text,
1554 gboolean right_aligned,
1555 gboolean bold,
1556 gboolean ellipsize_text,
1557 gboolean selectable,
1558 gboolean mnemonic)
1559 {
1560 GtkWidget *entry_field;
1561
1562 entry_field = nautilus_entry_new ();
1563 gtk_entry_set_text (GTK_ENTRY (entry_field), initial_text);
1564
1565 gtk_entry_set_alignment (GTK_ENTRY (entry_field), right_aligned ? 1 : 0);
1566 gtk_widget_show (entry_field);
1567 gtk_table_attach (table, entry_field,
1568 column, column + 1,
1569 row, row + 1,
1570 ellipsize_text
1571 ? GTK_FILL | GTK_EXPAND
1572 : GTK_FILL,
1573 0,
1574 0, 0);
1575
1576 return GTK_ENTRY (entry_field);
1577 }
1578
1579 static GtkEntry *
1580 attach_edit_label (GtkTable *table,
1581 int row,
1582 int column,
1583 const char *initial_text)
1584 {
1585 return attach_edit (table, row, column, initial_text, FALSE, FALSE, FALSE, TRUE, FALSE);
1586 }
1587 #endif
1588
1255 1589 static GtkLabel *
1256 1590 attach_ellipsizing_value_label (GtkTable *table,
1257 1591 int row,
1310 1644 FALSE);
1311 1645 }
1312 1646
1647 static void
1648 start_long_operation (NautilusPropertiesWindow *window)
1649 {
1650 if (window->details->long_operation_underway == 0) {
1651 /* start long operation */
1652 GdkCursor * cursor;
1653
1654 cursor = gdk_cursor_new (GDK_WATCH);
1655 gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor);
1656 g_object_unref (cursor);
1657 }
1658 window->details->long_operation_underway ++;
1659 }
1660
1661 static void
1662 end_long_operation (NautilusPropertiesWindow *window)
1663 {
1664 if (gtk_widget_get_window (GTK_WIDGET (window)) != NULL &&
1665 window->details->long_operation_underway == 1) {
1666 /* finished !! */
1667 gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
1668 }
1669 window->details->long_operation_underway--;
1670 }
1671
1672 #ifdef HAVE_SELINUX
1673 static void
1674 selinux_change_callback (NautilusFile *file,
1675 GFile *result_location,
1676 GError *error,
1677 gpointer callback_data)
1678 {
1679 NautilusPropertiesWindow *window;
1680 g_assert (callback_data != NULL);
1681
1682 window = NAUTILUS_PROPERTIES_WINDOW (callback_data);
1683 end_long_operation (window);
1684
1685 /* Report the error if it's an error. */
1686 nautilus_report_error_setting_selinux (file, error, NULL);
1687
1688 g_object_unref (window);
1689 }
1690
1691 static void
1692 selinux_done_editing (NautilusPropertiesWindow *window, char *selinux_context)
1693 {
1694 GList *l;
1695
1696 /* Accept changes. */
1697 for (l = window->details->target_files; l != NULL; l = l->next) {
1698 NautilusFile *file;
1699
1700 file = NAUTILUS_FILE (l->data);
1701
1702 start_long_operation (window);
1703 g_object_ref (window);
1704 nautilus_file_set_selinux_context (file, selinux_context,
1705 selinux_change_callback,
1706 window);
1707 }
1708 }
1709
1710 static gboolean
1711 selinux_focus_out (NautilusEntry *entry, GdkEventFocus *event, gpointer cb_data)
1712 {
1713 g_assert (NAUTILUS_IS_ENTRY (entry));
1714 g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (cb_data));
1715
1716 if (gtk_widget_get_state (GTK_WIDGET (entry))) {
1717 char *tmp;
1718
1719 tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
1720 selinux_done_editing (NAUTILUS_PROPERTIES_WINDOW (cb_data), tmp);
1721 g_free (tmp);
1722 }
1723
1724 return FALSE;
1725 }
1726
1727 static void
1728 selinux_entry_activate (NautilusEntry *entry, gpointer cb_data)
1729 {
1730 char *tmp;
1731
1732 g_assert (NAUTILUS_IS_ENTRY (entry));
1733 g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (cb_data));
1734
1735 tmp = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
1736 selinux_done_editing (NAUTILUS_PROPERTIES_WINDOW (cb_data), tmp);
1737 g_free (tmp);
1738
1739 nautilus_entry_select_all_at_idle (entry);
1740 }
1741
1742 static void
1743 selinux_popup_activate (GtkComboBox *comb, gpointer cb_data)
1744 {
1745 char *cntx_type;
1746 char *orig_type;
1747 const char *attr_u;
1748 const char *attr_r;
1749 const char *attr_t;
1750 const char *attr_s;
1751 char *tmp;
1752 GtkTreeIter iter;
1753 GtkTreeModel *model;
1754
1755 g_assert (GTK_IS_COMBO_BOX (comb));
1756 g_assert (NAUTILUS_IS_PROPERTIES_WINDOW (cb_data));
1757
1758 if (!gtk_combo_box_get_active_iter (comb, &iter)) {
1759 return;
1760 } else {
1761 model = gtk_combo_box_get_model (comb);
1762 gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
1763 }
1764
1765 if (!(orig_type = g_object_get_data (G_OBJECT (comb), "original_cntx"))) {
1766 return;
1767 }
1768 orig_type = g_strdup (orig_type);
1769
1770 selinux_split_cntx (orig_type, &attr_u, &attr_r, &attr_t, &attr_s);
1771 tmp = g_strjoin (":", attr_u, attr_r, cntx_type, attr_s, NULL);
1772 g_free (orig_type);
1773
1774 selinux_done_editing (NAUTILUS_PROPERTIES_WINDOW (cb_data), tmp);
1775 g_free (tmp);
1776 }
1777
1778 static char *
1779 cust_type_next_line (GIOChannel *ioc_ctypes)
1780 {
1781 char *data;
1782 gsize term;
1783 GError *errc;
1784
1785 data = NULL;
1786 term = 0;
1787 errc = NULL;
1788
1789 if (G_IO_STATUS_NORMAL == g_io_channel_read_line (ioc_ctypes, &data,
1790 NULL, &term, &errc)) {
1791 data[term] = 0;
1792 return data;
1793 }
1794
1795 return NULL;
1796 }
1797 #endif
1798
1799 static GSList *
1800 selinux__type_list (void)
1801 {
1802 static GSList *cust_types;
1803 GSList *scan;
1804 #ifdef HAVE_SELINUX
1805 static time_t file_mtime;
1806 const char *fname_ctypes;
1807 struct stat buf;
1808 GIOChannel *ioc_ctypes;
1809 GError *errc;
1810 int fd;
1811 #endif
1812
1813 #ifndef HAVE_SELINUX
1814 if (cust_types) {
1815 return cust_types;
1816 }
1817 #else
1818 fname_ctypes = selinux_customizable_types_path ();
1819 if (cust_types && file_mtime && !stat (fname_ctypes, &buf) &&
1820 (file_mtime == buf.st_mtime)) {
1821 return cust_types;
1822 }
1823 #endif
1824
1825 if (cust_types) {
1826 for (scan = cust_types; scan; scan = scan->next) {
1827 g_free (scan->data);
1828 }
1829 g_slist_free (cust_types);
1830 cust_types = NULL;
1831 }
1832
1833 cust_types = g_slist_prepend (cust_types, g_strdup ("tmp_t"));
1834 cust_types = g_slist_prepend (cust_types, g_strdup ("user_home_t"));
1835 /* cust_types = g_slist_prepend (cust_types, g_strdup ("user_tmp_t")); */
1836
1837 #ifdef HAVE_SELINUX
1838 /* read types, one per line... */
1839 fname_ctypes = selinux_customizable_types_path ();
1840 errc = NULL;
1841 if ((ioc_ctypes = g_io_channel_new_file (fname_ctypes, "r", &errc))) {
1842 char *data = NULL;
1843
1844 while ((data = cust_type_next_line (ioc_ctypes))) {
1845 cust_types = g_slist_prepend (cust_types, data);
1846 }
1847
1848 fd = g_io_channel_unix_get_fd (ioc_ctypes);
1849 if (!fstat (fd, &buf)) {
1850 file_mtime = buf.st_mtime;
1851 }
1852
1853 g_io_channel_unref (ioc_ctypes);
1854 }
1855 #endif
1856
1857 return cust_types;
1858 }
1859
1860 static void
1861 attach_selinux_data_edit_field (GtkEntry *entry,
1862 char *attr_val, char *def_attr_val)
1863 {
1864 GtkEntryCompletion *comp;
1865 GtkCellRenderer *cell;
1866 const char *attr_u;
1867 const char *attr_r;
1868 const char *attr_t;
1869 const char *attr_s;
1870 const char *dattr_u;
1871 const char *dattr_r;
1872 const char *dattr_t;
1873 const char *dattr_s;
1874 GtkListStore *store;
1875 GtkTreeIter iter;
1876 GSList *scan;
1877 int width;
1878 int owidth;
1879 int twidth;
1880
1881 attr_val = g_strdup (attr_val); /* so we can alter it... */
1882 def_attr_val = g_strdup (def_attr_val); /* so we can alter it... */
1883
1884 /* do completion, so you don't have to type everything... */
1885 comp = gtk_entry_completion_new ();
1886 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
1887 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
1888 0, GTK_SORT_ASCENDING);
1889
1890 gtk_entry_completion_set_model (comp, GTK_TREE_MODEL (store));
1891 cell = gtk_cell_renderer_pixbuf_new ();
1892 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comp), cell, FALSE);
1893 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comp), cell,
1894 "stock-id", 1, NULL);
1895 gtk_entry_completion_set_text_column (comp, 0);
1896 gtk_entry_set_completion (entry, comp);
1897
1898 /* FIXME: default doesn't do the right thing, should it? */
1899 owidth = gtk_entry_get_width_chars (entry);
1900 width = owidth;
1901
1902 selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s);
1903 dattr_u = dattr_r = dattr_t = dattr_s = NULL;
1904 if (def_attr_val) {
1905 selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r,
1906 &dattr_t, &dattr_s);
1907 }
1908
1909 /* don't do it twice... */
1910 if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) {
1911 dattr_t = NULL;
1912 }
1913
1914 if (attr_t && gtk_widget_get_state (GTK_WIDGET (entry))) {
1915 /* highlight just the type to the end, so we can easily change it
1916 * FIXME: we also highlight any Sensitivity/MCS but completion will
1917 * let people put it back, and that's the only way we get completion
1918 * at all -- This sucks and we need to remove Sensitivity/MCS from
1919 * the edit box. Yah, more UI. */
1920 int beg = attr_t - attr_u;
1921 gtk_editable_select_region (GTK_EDITABLE (entry), beg, -1);
1922 }
1923
1924 for (scan = selinux__type_list(); scan; scan = scan->next) {
1925 char *tmp;
1926
1927 if (attr_t && !strcmp (attr_t, scan->data))
1928 continue; /* don't have two entries */
1929
1930 if (dattr_t && !strcmp (dattr_t, scan->data))
1931 continue; /* don't have two entries */
1932
1933 gtk_list_store_append (store, &iter);
1934 tmp = g_strjoin (":", attr_u, attr_r, scan->data, attr_s, NULL);
1935 gtk_list_store_set (store, &iter, 0, tmp, -1);
1936
1937 twidth = strlen (tmp);
1938 width = MAX (twidth, width);
1939
1940 g_free (tmp);
1941 }
1942
1943 if (dattr_t) {
1944 char *tmp;
1945
1946 gtk_list_store_append (store, &iter);
1947 tmp = g_strjoin (":", dattr_u, dattr_r, dattr_t, dattr_s, NULL);
1948 gtk_list_store_set (store, &iter, 0, tmp,
1949 1, GTK_STOCK_HOME, -1);
1950
1951 twidth = strlen (tmp);
1952 width = MAX (twidth, width);
1953
1954 g_free (tmp);
1955 }
1956
1957 if (attr_t) {
1958 char *tmp;
1959
1960 gtk_list_store_append (store, &iter);
1961 tmp = g_strjoin (":", attr_u, attr_r, attr_t, attr_s, NULL);
1962 gtk_list_store_set (store, &iter, 0, tmp, 1, GTK_STOCK_OK, -1);
1963
1964 twidth = strlen (tmp);
1965 width = MAX (twidth, width);
1966
1967 g_free (tmp);
1968 }
1969
1970 g_free (attr_val);
1971 g_free (def_attr_val);
1972 g_object_unref (G_OBJECT (store));
1973 g_object_unref (G_OBJECT (comp));
1974
1975 if (width != owidth) {
1976 gtk_entry_set_width_chars (entry, width + 2);
1977 }
1978 }
1979
1980 #ifdef HAVE_SELINUX
1981
1982 # define HACK_TYPE(x, y) \
1983 else if (!strcmp (nice_type, x)) nice_type = y
1984
1985 /* hack to convert a selinux_context type into a readable string for the
1986 user */
1987 static const char *
1988 selinux__hack_conv_type (const char *type)
1989 { /* FIXME: hack attack, but nowhere else to put it. Because mathpathcon
1990 * here now probably want a bunch of other types? */
1991 const char *nice_type;
1992
1993 nice_type = type;
1994
1995 if (0) { }
1996
1997 HACK_TYPE("cupsd_etc_t", _("CUPS printer configuration"));
1998 HACK_TYPE("cupsd_rw_etc_t", _("CUPS printer configuration (rw)"));
1999 HACK_TYPE("cupsd_tmp_t", _("CUPS temporary data"));
2000 HACK_TYPE("dhcp_etc_t", _("DHCP configuration"));
2001 HACK_TYPE("dictd_etc_t", _("Dictd configuration"));
2002 HACK_TYPE("dnssec_t", _("DNS secret"));
2003 HACK_TYPE("etc_t", _("System configuration"));
2004 HACK_TYPE("etc_aliases_t", _("Email aliases configuration"));
2005 HACK_TYPE("etc_runtime_t", _("System configuration (rw)"));
2006 HACK_TYPE("cvs_data_t", _("Read and write from CVS daemon"));
2007 HACK_TYPE("httpd_config_t", _("Apache-httpd configuration"));
2008 HACK_TYPE("httpd_php_tmp_t",
2009 _("Apache-httpd PHP module temporary data"));
2010 HACK_TYPE("httpd_sys_content_t",
2011 _("Read from all httpd scripts and the daemon"));
2012 HACK_TYPE("httpd_sys_htaccess_t",
2013 _("Apache-httpd .htaccess configuration"));
2014 HACK_TYPE("httpd_sys_script_exec_t",
2015 _("CGI programs with default access"));
2016 HACK_TYPE("httpd_sys_script_ra_t",
2017 _("CGI programs can read and append"));
2018 HACK_TYPE("httpd_sys_script_ro_t",
2019 _("CGI programs can read"));
2020 HACK_TYPE("httpd_sys_script_rw_t",
2021 _("CGI programs can read and write"));
2022 HACK_TYPE("httpd_unconfined_script_exec_t",
2023 _("CGI programs without any SELinux protection"));
2024 HACK_TYPE("httpd_tmp_t", _("Apache-httpd temporary data"));
2025 HACK_TYPE("ice_tmp_t", _("ICE temporary data"));
2026 HACK_TYPE("locale_t", _("Locale data"));
2027 HACK_TYPE("mysql_tmp_t", _("MySQL temporary data"));
2028 HACK_TYPE("named_conf_t", _("Nameserver configuration"));
2029 HACK_TYPE("net_conf_t", _("Network configuration"));
2030 HACK_TYPE("postgresql_tmp_t", _("Postgresql temporary data"));
2031 HACK_TYPE("public_content_rw_t",
2032 _("Read and write from CIFS/ftp/http/nfs/rsync"));
2033 HACK_TYPE("public_content_t", _("Read from CIFS/ftp/http/nfs/rsync"));
2034 HACK_TYPE("samba_etc_t", _("Samba configuration"));
2035 HACK_TYPE("samba_share_t", _("Shared via CIFS (samba)"));
2036 HACK_TYPE("staff_home_t", _("Staff user data"));
2037 HACK_TYPE("staff_home_dir_t", _("Staff user home directory"));
2038 HACK_TYPE("swapfile_t", _("System swapfile"));
2039 HACK_TYPE("sysadm_home_t", _("Sysadmin user data"));
2040 HACK_TYPE("sysadm_home_dir_t", _("Sysadmin user home directory"));
2041 HACK_TYPE("system_cron_spool_t", _("Cron data"));
2042 HACK_TYPE("tmp_t", _("Temporary data"));
2043 HACK_TYPE("user_tmp_t", _("User temporary data"));
2044 HACK_TYPE("user_home_t", _("User data"));
2045 HACK_TYPE("user_home_dir_t", _("User home directory"));
2046 HACK_TYPE("var_log_t", _("Logfile"));
2047 HACK_TYPE("xen_image_t", _("Xen image"));
2048
2049 return nice_type;
2050 }
2051 #undef HACK_TYPE
2052
2053 static void
2054 attach_selinux_data_popup_field (GtkComboBox *comb,
2055 char *attr_val,
2056 char *def_attr_val)
2057 {
2058 const char *attr_u;
2059 const char *attr_r;
2060 const char *attr_t;
2061 const char *attr_s;
2062 const char *dattr_u;
2063 const char *dattr_r;
2064 const char *dattr_t;
2065 const char *dattr_s;
2066 GtkListStore *store;
2067 GtkTreeIter iter;
2068 GSList *scan;
2069
2070 attr_val = g_strdup (attr_val); /* so we can alter it... */
2071 def_attr_val = g_strdup (def_attr_val);
2072
2073 /* do completion, so you don't have to type everything... */
2074 store = gtk_list_store_new (3, G_TYPE_STRING,
2075 G_TYPE_STRING, G_TYPE_STRING);
2076 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
2077 1, GTK_SORT_ASCENDING);
2078
2079 gtk_combo_box_set_model (comb, GTK_TREE_MODEL (store));
2080
2081 selinux_split_cntx (attr_val, &attr_u, &attr_r, &attr_t, &attr_s);
2082 dattr_u = dattr_r = dattr_t = dattr_s = NULL;
2083 if (def_attr_val) {
2084 selinux_split_cntx (def_attr_val, &dattr_u, &dattr_r,
2085 &dattr_t, &dattr_s);
2086 }
2087 /* don't do it twice... */
2088 if (attr_t && dattr_t && !strcmp (attr_t, dattr_t)) {
2089 dattr_t = NULL;
2090 }
2091
2092 for (scan = selinux__type_list(); scan; scan = scan->next) {
2093 const char *nice_type;
2094
2095 if (attr_t && !strcmp (attr_t, scan->data))
2096 continue; /* don't have two entries */
2097
2098 if (dattr_t && !strcmp (dattr_t, scan->data))
2099 continue; /* don't have two entries */
2100
2101 nice_type = selinux__hack_conv_type(scan->data);
2102
2103 gtk_list_store_append (store, &iter);
2104 gtk_list_store_set (store, &iter, 0, scan->data,
2105 1, nice_type, -1);
2106 }
2107
2108 if (dattr_t) {
2109 const char *nice_type;
2110
2111 gtk_list_store_append (store, &iter);
2112 nice_type = selinux__hack_conv_type(dattr_t);
2113 gtk_list_store_set (store, &iter, 0, dattr_t, 1, nice_type,
2114 2, GTK_STOCK_HOME, -1);
2115 }
2116
2117 if (attr_t) {
2118 const char *nice_type;
2119
2120 gtk_list_store_append (store, &iter);
2121 nice_type = selinux__hack_conv_type(attr_t);
2122 gtk_list_store_set (store, &iter, 0, attr_t, 1, nice_type,
2123 2, GTK_STOCK_OK, -1);
2124 gtk_combo_box_set_active_iter (comb, &iter);
2125 }
2126
2127 g_free (attr_val);
2128 g_free (def_attr_val);
2129 g_object_unref (G_OBJECT (store));
2130 }
2131
2132 static char *
2133 selinux__matchpathcon (GList *file_list)
2134 {
2135 GList *scan;
2136
2137 for (scan = file_list; scan != NULL; scan = scan->next) {
2138 NautilusFile *file;
2139
2140 file = NAUTILUS_FILE (scan->data);
2141 if (!nautilus_file_is_gone (file)) {
2142 return nautilus_file_get_selinux_matchpathcon (file);
2143 }
2144 }
2145
2146 return NULL;
2147 }
2148
2149 static void
2150 attach_selinux_edit_field (NautilusPropertiesWindow *window,
2151 GtkTable *table,
2152 int row,
2153 int column,
2154 const char *file_attribute_name,
2155 const char *inconsistent_string,
2156 gboolean show_original,
2157 GtkLabel *lab_title)
2158 {
2159 GtkEntry *entry;
2160 GList *file_list;
2161 char *attr_value;
2162 char *def_attr_value;
2163
2164 if (show_original) {
2165 file_list = window->details->original_files;
2166 } else {
2167 file_list = window->details->target_files;
2168 }
2169
2170 attr_value = file_list_get_string_attribute (file_list,
2171 file_attribute_name,
2172 inconsistent_string);
2173 if ( strcmp (attr_value, inconsistent_string) &&
2174 !strcmp (file_attribute_name, "selinux_context")) {
2175 def_attr_value = selinux__matchpathcon (file_list);
2176 } else {
2177 def_attr_value = NULL;
2178 }
2179
2180 entry = attach_edit_label (table, row, column, attr_value);
2181 gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title),
2182 GTK_WIDGET (entry));
2183
2184 /* Stash a copy of the file attribute name in this field for the callback's sake. */
2185 g_object_set_data_full (G_OBJECT (entry), "file_attribute",
2186 g_strdup (file_attribute_name), g_free);
2187
2188 g_object_set_data_full (G_OBJECT (entry), "inconsistent_string",
2189 g_strdup (inconsistent_string), g_free);
2190
2191 g_object_set_data (G_OBJECT (entry), "show_original", GINT_TO_POINTER (show_original));
2192 g_object_set_data (G_OBJECT (entry), "ellipsize_text", GINT_TO_POINTER (FALSE));
2193
2194 g_signal_connect_object (entry, "focus_out_event",
2195 G_CALLBACK (selinux_focus_out), window, 0);
2196 g_signal_connect_object (entry, "activate",
2197 G_CALLBACK (selinux_entry_activate), window,0);
2198
2199 attach_selinux_data_edit_field (entry, attr_value, def_attr_value);
2200
2201 g_object_set_data_full (G_OBJECT (entry), "original_cntx", attr_value,
2202 g_free);
2203
2204 g_object_set_data_full (G_OBJECT (entry), "matchpathcon_cntx",
2205 def_attr_value, g_free);
2206
2207 window->details->edit_fields = g_list_prepend (window->details->edit_fields,
2208 entry);
2209 }
2210
2211 static void
2212 attach_selinux_popup_field (NautilusPropertiesWindow *window,
2213 GtkTable *table,
2214 int row,
2215 int column,
2216 const char *file_attribute_name,
2217 const char *inconsistent_string,
2218 gboolean show_original,
2219 GtkLabel *lab_title)
2220 {
2221 GtkWidget *comb;
2222 GtkCellRenderer *cell;
2223 GList *file_list;
2224 char *attr_value;
2225 char *def_attr_value;
2226 gulong handler;
2227
2228 if (show_original) {
2229 file_list = window->details->original_files;
2230 } else {
2231 file_list = window->details->target_files;
2232 }
2233
2234 attr_value = file_list_get_string_attribute (file_list,
2235 file_attribute_name,
2236 inconsistent_string);
2237 if ( strcmp (attr_value, inconsistent_string) &&
2238 !strcmp (file_attribute_name, "selinux_context")) {
2239 def_attr_value = selinux__matchpathcon (file_list);
2240 } else {
2241 def_attr_value = NULL;
2242 }
2243
2244 comb = gtk_combo_box_new ();
2245
2246 gtk_table_attach (table, comb, column, column + 1, row, row + 1,
2247 GTK_FILL, 0, 0, 0);
2248
2249
2250 gtk_label_set_mnemonic_widget (GTK_LABEL (lab_title), comb);
2251
2252 /* Stash a copy of the file attribute name in this field for the callback's sake. */
2253 g_object_set_data_full (G_OBJECT (comb), "file_attribute",
2254 g_strdup (file_attribute_name), g_free);
2255
2256 g_object_set_data (G_OBJECT (comb), "show_original", GINT_TO_POINTER (show_original));
2257
2258 g_object_set_data_full (G_OBJECT (comb), "original_cntx", attr_value,
2259 g_free);
2260
2261 g_object_set_data_full (G_OBJECT (comb), "matchpathcon_cntx",
2262 def_attr_value, g_free);
2263
2264 cell = gtk_cell_renderer_pixbuf_new ();
2265 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE);
2266 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell,
2267 "stock-id", 2, NULL);
2268 cell = gtk_cell_renderer_text_new ();
2269 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comb), cell, FALSE);
2270 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comb), cell,
2271 "text", 1, NULL);
2272 gtk_widget_show (comb);
2273
2274 attach_selinux_data_popup_field (GTK_COMBO_BOX (comb),
2275 attr_value, def_attr_value);
2276
2277 handler = g_signal_connect_object (comb, "changed",
2278 G_CALLBACK (selinux_popup_activate), window, 0);
2279 g_object_set_data (G_OBJECT (comb), "handler_changed", GUINT_TO_POINTER (handler));
2280
2281 g_assert (! window->details->selinux_combo);
2282
2283 window->details->selinux_combo =
2284 g_list_prepend (window->details->selinux_combo, comb);
2285 }
2286 #endif
2287
1313 2288 static GtkWidget*
1314 2289 attach_ellipsizing_value_field (NautilusPropertiesWindow *window,
1315 2290 GtkTable *table,
2303 3278 return last_row;
2304 3279 }
2305 3280
3281 #ifdef HAVE_SELINUX
3282 static guint
3283 append_title_selinux_edit_pair (NautilusPropertiesWindow *window,
3284 GtkTable *table,
3285 const char *title,
3286 const char *file_attribute_name,
3287 const char *inconsistent_state,
3288 gboolean show_original)
3289 {
3290 guint last_row;
3291 GtkLabel *lab_title;
3292
3293 lab_title = NULL;
3294 last_row = append_title_field (table, title, &lab_title);
3295
3296 if (window->details->advanced_permissions) {
3297 attach_selinux_edit_field (window, table, last_row,
3298 VALUE_COLUMN, file_attribute_name,
3299 inconsistent_state,
3300 show_original, lab_title);
3301 } else {
3302 attach_selinux_popup_field (window, table, last_row,
3303 VALUE_COLUMN, file_attribute_name,
3304 inconsistent_state,
3305 show_original, lab_title);
3306 }
3307
3308 return last_row;
3309 }
3310 #endif
3311
2306 3312 static guint
2307 3313 append_title_and_ellipsizing_value (NautilusPropertiesWindow *window,
2308 3314 GtkTable *table,
3228 4234 }
3229 4235
3230 4236 static void
3231 start_long_operation (NautilusPropertiesWindow *window)
3232 {
3233 if (window->details->long_operation_underway == 0) {
3234 /* start long operation */
3235 GdkCursor * cursor;
3236
3237 cursor = gdk_cursor_new (GDK_WATCH);
3238 gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), cursor);
3239 g_object_unref (cursor);
3240 }
3241 window->details->long_operation_underway ++;
3242 }
3243
3244 static void
3245 end_long_operation (NautilusPropertiesWindow *window)
3246 {
3247 if (gtk_widget_get_window (GTK_WIDGET (window)) != NULL &&
3248 window->details->long_operation_underway == 1) {
3249 /* finished !! */
3250 gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window)), NULL);
3251 }
3252 window->details->long_operation_underway--;
3253 }
3254
3255 static void
3256 4237 permission_change_callback (NautilusFile *file,
3257 4238 GFile *res_loc,
3258 4239 GError *error,
4035 5016 gtk_table_set_row_spacing (table, nrows - 1, 18);
4036 5017 }
4037 5018
4038 static gboolean
4039 all_can_get_permissions (GList *file_list)
4040 {
4041 GList *l;
4042 for (l = file_list; l != NULL; l = l->next) {
4043 NautilusFile *file;
4044
4045 file = NAUTILUS_FILE (l->data);
4046
4047 if (!nautilus_file_can_get_permissions (file)) {
4048 return FALSE;
4049 }
4050 }
4051
4052 return TRUE;
4053 }
4054
4055 static gboolean
4056 all_can_set_permissions (GList *file_list)
4057 {
4058 GList *l;
4059 for (l = file_list; l != NULL; l = l->next) {
4060 NautilusFile *file;
4061
4062 file = NAUTILUS_FILE (l->data);
4063
4064 if (!nautilus_file_can_set_permissions (file)) {
4065 return FALSE;
4066 }
4067 }
4068
4069 return TRUE;
4070 }
4071 5019
4072 5020 static GHashTable *
4073 5021 get_initial_permissions (GList *file_list)
4415 5363 guint32 file_permission, file_permission_mask;
4416 5364 guint32 dir_permission, dir_permission_mask;
4417 5365 guint32 vfs_mask, vfs_new_perm, p;
4418 GtkWidget *button, *combo;
5366 char *context;
5367 GtkWidget *button;
5368 GtkComboBox *combo;
4419 5369 gboolean active, is_folder, is_special, use_original;
4420 5370 GList *l;
4421 5371 GtkTreeModel *model;
4459 5409 }
4460 5410 /* Simple mode, minus exec checkbox */
4461 5411 for (l = window->details->permission_combos; l != NULL; l = l->next) {
4462 combo = l->data;
5412 combo = GTK_COMBO_BOX (l->data);
4463 5413
4464 if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) {
5414 if (!gtk_combo_box_get_active_iter (combo, &iter)) {
4465 5415 continue;
4466 5416 }
4467 5417
4469 5419 is_folder = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo),
4470 5420 "is-folder"));
4471 5421
4472 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
5422 model = gtk_combo_box_get_model (combo);
4473 5423 gtk_tree_model_get (model, &iter, 1, &new_perm, 2, &use_original, -1);
4474 5424 if (use_original) {
4475 5425 continue;
4492 5442 }
4493 5443 }
4494 5444
5445 /* get the SELinux context... */
5446 context = NULL;
5447 if (window->details->advanced_permissions &&
5448 window->details->edit_fields) { /* advanced mode */
5449 GtkEditable *efield;
5450
5451 efield = window->details->edit_fields->data;
5452 context = gtk_editable_get_chars (GTK_EDITABLE (efield), 0, -1);
5453 } else if (!window->details->advanced_permissions &&
5454 window->details->selinux_combo) { /* simple mode */
5455 char *cntx_type;
5456 char *orig_type;
5457 const char *attr_u;
5458 const char *attr_r;
5459 const char *attr_t;
5460 const char *attr_s;
5461
5462 combo = GTK_COMBO_BOX (window->details->selinux_combo->data);
5463
5464 if (!gtk_combo_box_get_active_iter (combo, &iter)) {
5465 return;
5466 } else {
5467 GtkTreeModel *model = gtk_combo_box_get_model (combo);
5468 gtk_tree_model_get (model, &iter, 0, &cntx_type, -1);
5469 }
5470 if (!(orig_type = g_object_get_data (G_OBJECT (combo),
5471 "original_cntx"))) {
5472 return;
5473 }
5474
5475 orig_type = g_strdup (orig_type);
5476
5477 selinux_split_cntx (orig_type,
5478 &attr_u, &attr_r, &attr_t, &attr_s);
5479 context = g_strjoin (":",
5480 attr_u, attr_r, cntx_type, attr_s, NULL);
5481 g_free (orig_type);
5482 }
5483
4495 5484 for (l = window->details->target_files; l != NULL; l = l->next) {
4496 5485 NautilusFile *file;
4497 5486 char *uri;
4498 5487
4499 5488 file = NAUTILUS_FILE (l->data);
4500 5489
5490 /* assume permissions setting allows context setting...
5491 * we can't really do much else due to race conditions anyway */
4501 5492 if (nautilus_file_is_directory (file) &&
4502 5493 nautilus_file_can_set_permissions (file)) {
4503 5494 uri = nautilus_file_get_uri (file);
4508 5499 file_permission_mask,
4509 5500 dir_permission,
4510 5501 dir_permission_mask,
5502 context,
4511 5503 set_recursive_permissions_done,
4512 5504 window);
4513 5505 g_free (uri);
4514 5506 }
4515 5507 }
5508 g_free (context);
4516 5509 }
4517 5510
4518 5511 static void
4563 5556 gtk_table_set_row_spacing (page_table, nrows - 1, 18);
4564 5557
4565 5558 #ifdef HAVE_SELINUX
4566 append_title_value_pair
4567 (window, page_table, _("SELinux context:"),
4568 "selinux_context", INCONSISTENT_STATE_STRING,
4569 FALSE);
5559 if (!is_multi_file_window (window) || multi_have_same_selinux_context (window))
5560 append_title_selinux_edit_pair (window, page_table,
5561 _("_SELinux Context:"),
5562 "selinux_context", INCONSISTENT_STATE_STRING,
5563 FALSE);
5564 else /* Static text in this case. */
5565 append_title_value_pair (window, page_table,
5566 _("_SELinux Context:"),
5567 "selinux_context", INCONSISTENT_STATE_STRING,
5568 FALSE);
4570 5569 #endif
4571 5570 append_title_value_pair
4572 5571 (window, page_table, _("Last changed:"),