Ticket #3493: user menu selector: make "User", not "Local", the focused button.
[midnight-commander.git] / src / filemanager / achown.c
blobf14f15ce34ad763e40f0e411c9b0e9dc7abc285a
1 /*
2 Chown-advanced command -- for the Midnight Commander
4 Copyright (C) 1994-2015
5 Free Software Foundation, Inc.
7 This file is part of the Midnight Commander.
9 The Midnight Commander is free software: you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation, either version 3 of the License,
12 or (at your option) any later version.
14 The Midnight Commander is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /** \file achown.c
24 * \brief Source: Contains functions for advanced chowning
27 #include <config.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <pwd.h>
37 #include <grp.h>
39 #include "lib/global.h"
41 #include "lib/tty/tty.h"
42 #include "lib/tty/key.h" /* XCTRL and ALT macros */
43 #include "lib/skin.h"
44 #include "lib/strutil.h"
45 #include "lib/vfs/vfs.h"
46 #include "lib/util.h"
47 #include "lib/widget.h"
49 #include "dir.h"
50 #include "midnight.h" /* current_panel */
51 #include "chmod.h"
53 #include "achown.h"
55 /*** global variables ****************************************************************************/
57 /*** file scope macro definitions ****************************************************************/
59 #define BX 5
60 #define BY 5
62 #define BUTTONS 9
63 #define BUTTONS_PERM 5
65 #define B_SETALL B_USER
66 #define B_SKIP (B_USER + 1)
67 #define B_OWN (B_USER + 3)
68 #define B_GRP (B_USER + 4)
69 #define B_OTH (B_USER + 5)
70 #define B_OUSER (B_USER + 6)
71 #define B_OGROUP (B_USER + 7)
73 /*** file scope type declarations ****************************************************************/
75 /*** file scope variables ************************************************************************/
77 static struct WDialog *ch_dlg;
79 static struct
81 unsigned long id;
82 int ret_cmd, flags, x, len;
83 const char *text;
84 } chown_advanced_but[BUTTONS] =
86 /* *INDENT-OFF* */
87 { 0, B_ENTER, NARROW_BUTTON, 3, 0, " "},
88 { 0, B_ENTER, NARROW_BUTTON, 11, 0, " "},
89 { 0, B_ENTER, NARROW_BUTTON, 19, 0, " "},
90 { 0, B_ENTER, NARROW_BUTTON, 29, 0, ""},
91 { 0, B_ENTER, NARROW_BUTTON, 47, 0, ""},
93 { 0, B_SETALL, NORMAL_BUTTON, 0, 0, N_("Set &all")},
94 { 0, B_SKIP, NORMAL_BUTTON, 0, 0, N_("S&kip") },
95 { 0, B_ENTER, DEFPUSH_BUTTON, 0, 0, N_("&Set") },
96 { 0, B_CANCEL, NORMAL_BUTTON, 0, 0, N_("&Cancel") }
97 /* *INDENT-ON* */
100 static WButton *b_att[3]; /* permission */
101 static WButton *b_user, *b_group; /* owner */
102 static WLabel *l_filename;
103 static WLabel *l_mode;
105 static int flag_pos;
106 static int x_toggle;
107 static char ch_flags[11];
108 static const char ch_perm[] = "rwx";
109 static mode_t ch_cmode;
110 static struct stat *sf_stat;
111 static gboolean need_update = FALSE;
112 static gboolean end_chown = FALSE;
113 static int current_file;
114 static gboolean single_set = FALSE;
115 static char *fname;
117 /* --------------------------------------------------------------------------------------------- */
118 /*** file scope functions ************************************************************************/
119 /* --------------------------------------------------------------------------------------------- */
121 static void
122 update_ownership (void)
124 button_set_text (b_user, get_owner (sf_stat->st_uid));
125 button_set_text (b_group, get_group (sf_stat->st_gid));
128 /* --------------------------------------------------------------------------------------------- */
130 static cb_ret_t
131 inc_flag_pos (int f_pos)
133 if (flag_pos == 10)
135 flag_pos = 0;
136 return MSG_NOT_HANDLED;
138 flag_pos++;
139 if ((flag_pos % 3) == 0 || f_pos > 2)
140 return MSG_NOT_HANDLED;
141 return MSG_HANDLED;
144 /* --------------------------------------------------------------------------------------------- */
146 static cb_ret_t
147 dec_flag_pos (int f_pos)
149 if (flag_pos == 0)
151 flag_pos = 10;
152 return MSG_NOT_HANDLED;
154 flag_pos--;
155 if (((flag_pos + 1) % 3) == 0 || f_pos > 2)
156 return MSG_NOT_HANDLED;
157 return MSG_HANDLED;
160 /* --------------------------------------------------------------------------------------------- */
162 static void
163 set_perm_by_flags (char *s, int f_p)
165 int i;
167 for (i = 0; i < 3; i++)
169 if (ch_flags[f_p + i] == '+')
170 s[i] = ch_perm[i];
171 else if (ch_flags[f_p + i] == '-')
172 s[i] = '-';
173 else
174 s[i] = (ch_cmode & (1 << (8 - f_p - i))) ? ch_perm[i] : '-';
178 /* --------------------------------------------------------------------------------------------- */
180 static void
181 update_permissions (void)
183 set_perm_by_flags (b_att[0]->text.start, 0);
184 set_perm_by_flags (b_att[1]->text.start, 3);
185 set_perm_by_flags (b_att[2]->text.start, 6);
188 /* --------------------------------------------------------------------------------------------- */
190 static mode_t
191 get_perm (char *s, int base)
193 mode_t m;
195 m = 0;
196 m |= (s[0] == '-') ? 0 :
197 ((s[0] == '+') ? (mode_t) (1 << (base + 2)) : (1 << (base + 2)) & ch_cmode);
199 m |= (s[1] == '-') ? 0 :
200 ((s[1] == '+') ? (mode_t) (1 << (base + 1)) : (1 << (base + 1)) & ch_cmode);
202 m |= (s[2] == '-') ? 0 : ((s[2] == '+') ? (mode_t) (1 << base) : (1 << base) & ch_cmode);
204 return m;
207 /* --------------------------------------------------------------------------------------------- */
209 static mode_t
210 get_mode (void)
212 mode_t m;
214 m = ch_cmode ^ (ch_cmode & 0777);
215 m |= get_perm (ch_flags, 6);
216 m |= get_perm (ch_flags + 3, 3);
217 m |= get_perm (ch_flags + 6, 0);
219 return m;
222 /* --------------------------------------------------------------------------------------------- */
224 static void
225 print_flags (void)
227 int i;
229 tty_setcolor (COLOR_NORMAL);
231 for (i = 0; i < 3; i++)
233 widget_move (ch_dlg, BY + 1, 9 + i);
234 tty_print_char (ch_flags[i]);
237 for (i = 0; i < 3; i++)
239 widget_move (ch_dlg, BY + 1, 17 + i);
240 tty_print_char (ch_flags[i + 3]);
243 for (i = 0; i < 3; i++)
245 widget_move (ch_dlg, BY + 1, 25 + i);
246 tty_print_char (ch_flags[i + 6]);
249 update_permissions ();
251 for (i = 0; i < 15; i++)
253 widget_move (ch_dlg, BY + 1, 35 + i);
254 tty_print_char (ch_flags[9]);
256 for (i = 0; i < 15; i++)
258 widget_move (ch_dlg, BY + 1, 53 + i);
259 tty_print_char (ch_flags[10]);
263 /* --------------------------------------------------------------------------------------------- */
265 static void
266 chown_info_update (void)
268 char buffer[BUF_SMALL];
270 /* mode */
271 g_snprintf (buffer, sizeof (buffer), "Permissions (octal): %o", get_mode ());
272 label_set_text (l_mode, buffer);
274 /* permissions */
275 update_permissions ();
278 /* --------------------------------------------------------------------------------------------- */
280 static void
281 update_mode (WDialog * h)
283 print_flags ();
284 chown_info_update ();
285 send_message (h->current->data, NULL, MSG_FOCUS, 0, NULL);
288 /* --------------------------------------------------------------------------------------------- */
290 static cb_ret_t
291 chl_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
293 switch (msg)
295 case MSG_KEY:
296 switch (parm)
298 case KEY_LEFT:
299 case KEY_RIGHT:
301 WDialog *h = DIALOG (w);
303 h->ret_value = parm;
304 dlg_stop (h);
306 default:
307 break;
310 default:
311 return dlg_default_callback (w, sender, msg, parm, data);
315 /* --------------------------------------------------------------------------------------------- */
317 static void
318 do_enter_key (WDialog * h, int f_pos)
320 WListbox *chl_list;
321 struct passwd *chl_pass;
322 struct group *chl_grp;
323 int fe;
324 gboolean chl_end, is_owner;
328 int result;
329 WDialog *chl_dlg;
330 const char *title;
331 int lxx, lyy, b_pos;
333 is_owner = (f_pos == 3);
334 title = is_owner ? _("owner") : _("group");
336 lxx = (COLS - 74) / 2 + (is_owner ? 35 : 53);
337 lyy = (LINES - 13) / 2;
338 chl_end = FALSE;
340 chl_dlg =
341 dlg_create (TRUE, lyy, lxx, 13, 17, dialog_colors, chl_callback, NULL,
342 "[Advanced Chown]", title, DLG_COMPACT);
344 /* get new listboxes */
345 chl_list = listbox_new (1, 1, 11, 15, FALSE, NULL);
346 listbox_add_item (chl_list, LISTBOX_APPEND_AT_END, 0, "<Unknown>", NULL);
347 if (is_owner)
349 /* get and put user names in the listbox */
350 setpwent ();
351 while ((chl_pass = getpwent ()) != NULL)
352 listbox_add_item (chl_list, LISTBOX_APPEND_SORTED, 0, chl_pass->pw_name, NULL);
353 endpwent ();
354 fe = listbox_search_text (chl_list, get_owner (sf_stat->st_uid));
356 else
358 /* get and put group names in the listbox */
359 setgrent ();
360 while ((chl_grp = getgrent ()) != NULL)
361 listbox_add_item (chl_list, LISTBOX_APPEND_SORTED, 0, chl_grp->gr_name, NULL);
362 endgrent ();
363 fe = listbox_search_text (chl_list, get_group (sf_stat->st_gid));
366 listbox_select_entry (chl_list, fe);
368 b_pos = chl_list->pos;
369 add_widget (chl_dlg, chl_list);
371 result = dlg_run (chl_dlg);
373 if (result != B_CANCEL)
375 if (b_pos != chl_list->pos)
377 gboolean ok = FALSE;
378 char *text;
380 listbox_get_current (chl_list, &text, NULL);
381 if (is_owner)
383 chl_pass = getpwnam (text);
384 if (chl_pass != NULL)
386 ok = TRUE;
387 sf_stat->st_uid = chl_pass->pw_uid;
390 else
392 chl_grp = getgrnam (text);
393 if (chl_grp != NULL)
395 sf_stat->st_gid = chl_grp->gr_gid;
396 ok = TRUE;
399 if (ok)
401 ch_flags[f_pos + 6] = '+';
402 update_ownership ();
404 dlg_focus (h);
405 if (ok)
406 print_flags ();
408 if (result == KEY_LEFT)
410 if (!is_owner)
411 chl_end = TRUE;
412 dlg_one_up (ch_dlg);
413 f_pos--;
415 else if (result == KEY_RIGHT)
417 if (is_owner)
418 chl_end = TRUE;
419 dlg_one_down (ch_dlg);
420 f_pos++;
424 /* Here we used to redraw the window */
425 dlg_destroy (chl_dlg);
427 while (chl_end);
430 /* --------------------------------------------------------------------------------------------- */
432 static void
433 chown_refresh (void)
435 dlg_default_repaint (ch_dlg);
437 tty_setcolor (COLOR_NORMAL);
439 widget_move (ch_dlg, BY - 1, 8);
440 tty_print_string (_("owner"));
441 widget_move (ch_dlg, BY - 1, 16);
442 tty_print_string (_("group"));
443 widget_move (ch_dlg, BY - 1, 24);
444 tty_print_string (_("other"));
446 widget_move (ch_dlg, BY - 1, 35);
447 tty_print_string (_("owner"));
448 widget_move (ch_dlg, BY - 1, 53);
449 tty_print_string (_("group"));
451 widget_move (ch_dlg, BY + 1, 3);
452 tty_print_string (_("Flag"));
454 print_flags ();
457 /* --------------------------------------------------------------------------------------------- */
459 static void
460 b_setpos (int f_pos)
462 b_att[0]->hotpos = -1;
463 b_att[1]->hotpos = -1;
464 b_att[2]->hotpos = -1;
465 b_att[f_pos]->hotpos = (flag_pos % 3);
468 /* --------------------------------------------------------------------------------------------- */
470 static cb_ret_t
471 advanced_chown_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
473 WDialog *h = DIALOG (w);
474 int i;
475 int f_pos;
476 unsigned int id;
478 id = dlg_get_current_widget_id (h);
480 for (i = 0; i < BUTTONS_PERM; i++)
481 if (chown_advanced_but[i].id == id)
482 break;
484 f_pos = i;
485 i = 0;
487 switch (msg)
489 case MSG_DRAW:
490 chown_refresh ();
491 chown_info_update ();
492 return MSG_HANDLED;
494 case MSG_POST_KEY:
495 if (f_pos < 3)
496 b_setpos (f_pos);
497 return MSG_HANDLED;
499 case MSG_FOCUS:
500 if (f_pos < 3)
502 if ((flag_pos / 3) != f_pos)
503 flag_pos = f_pos * 3;
504 b_setpos (f_pos);
506 else if (f_pos < BUTTONS_PERM)
507 flag_pos = f_pos + 6;
508 return MSG_HANDLED;
510 case MSG_KEY:
511 switch (parm)
513 case XCTRL ('b'):
514 case KEY_LEFT:
515 if (f_pos < BUTTONS_PERM)
516 return (dec_flag_pos (f_pos));
517 break;
519 case XCTRL ('f'):
520 case KEY_RIGHT:
521 if (f_pos < BUTTONS_PERM)
522 return (inc_flag_pos (f_pos));
523 break;
525 case ' ':
526 if (f_pos < 3)
527 return MSG_HANDLED;
528 break;
530 case '\n':
531 case KEY_ENTER:
532 if (f_pos <= 2 || f_pos >= BUTTONS_PERM)
533 break;
534 do_enter_key (h, f_pos);
535 return MSG_HANDLED;
537 case ALT ('x'):
538 i++;
540 case ALT ('w'):
541 i++;
543 case ALT ('r'):
544 parm = i + 3;
545 for (i = 0; i < 3; i++)
546 ch_flags[i * 3 + parm - 3] = (x_toggle & (1 << parm)) ? '-' : '+';
547 x_toggle ^= (1 << parm);
548 update_mode (h);
549 dlg_broadcast_msg (h, MSG_DRAW);
550 send_message (h->current->data, NULL, MSG_FOCUS, 0, NULL);
551 break;
553 case XCTRL ('x'):
554 i++;
556 case XCTRL ('w'):
557 i++;
559 case XCTRL ('r'):
560 parm = i;
561 for (i = 0; i < 3; i++)
562 ch_flags[i * 3 + parm] = (x_toggle & (1 << parm)) ? '-' : '+';
563 x_toggle ^= (1 << parm);
564 update_mode (h);
565 dlg_broadcast_msg (h, MSG_DRAW);
566 send_message (h->current->data, NULL, MSG_FOCUS, 0, NULL);
567 break;
569 case 'x':
570 i++;
572 case 'w':
573 i++;
575 case 'r':
576 if (f_pos > 2)
577 break;
578 flag_pos = f_pos * 3 + i; /* (strchr(ch_perm,parm)-ch_perm); */
579 if (BUTTON (h->current->data)->text.start[(flag_pos % 3)] == '-')
580 ch_flags[flag_pos] = '+';
581 else
582 ch_flags[flag_pos] = '-';
583 update_mode (h);
584 break;
586 case '4':
587 i++;
589 case '2':
590 i++;
592 case '1':
593 if (f_pos <= 2)
595 flag_pos = i + f_pos * 3;
596 ch_flags[flag_pos] = '=';
597 update_mode (h);
599 break;
601 case '-':
602 if (f_pos > 2)
603 break;
605 case '*':
606 if (parm == '*')
607 parm = '=';
609 case '=':
610 case '+':
611 if (f_pos <= 4)
613 ch_flags[flag_pos] = parm;
614 update_mode (h);
615 send_message (h, sender, MSG_KEY, KEY_RIGHT, NULL);
616 if (flag_pos > 8 || (flag_pos % 3) == 0)
617 dlg_one_down (h);
619 break;
621 default:
622 break;
624 return MSG_NOT_HANDLED;
626 default:
627 return dlg_default_callback (w, sender, msg, parm, data);
631 /* --------------------------------------------------------------------------------------------- */
633 static void
634 init_chown_advanced (void)
636 int i;
637 int dlg_h = 12;
638 int dlg_w = 74;
639 int y;
641 static gboolean i18n = FALSE;
643 if (!i18n)
645 for (i = BUTTONS_PERM; i < BUTTONS; i++)
647 #ifdef ENABLE_NLS
648 chown_advanced_but[i].text = _(chown_advanced_but[i].text);
649 #endif /* ENABLE_NLS */
651 chown_advanced_but[i].len = str_term_width1 (chown_advanced_but[i].text) + 3;
652 if (chown_advanced_but[i].flags == DEFPUSH_BUTTON)
653 chown_advanced_but[i].len += 2; /* "<>" */
656 i18n = TRUE;
659 do_refresh ();
661 sf_stat = g_new (struct stat, 1);
662 current_file = 0;
663 end_chown = need_update = FALSE;
664 single_set = (current_panel->marked < 2);
665 memset (ch_flags, '=', 11);
666 flag_pos = 0;
667 x_toggle = 070;
669 if (!single_set)
670 dlg_h += 2;
672 ch_dlg =
673 dlg_create (TRUE, 0, 0, dlg_h, dlg_w, dialog_colors, advanced_chown_callback, NULL,
674 "[Advanced Chown]", _("Chown advanced command"), DLG_CENTER);
677 l_filename = label_new (2, 3, "");
678 add_widget (ch_dlg, l_filename);
680 add_widget (ch_dlg, hline_new (3, -1, -1));
682 #define XTRACT(i,y) y, BX+chown_advanced_but[i].x, \
683 chown_advanced_but[i].ret_cmd, chown_advanced_but[i].flags, \
684 (chown_advanced_but[i].text), NULL
685 b_att[0] = button_new (XTRACT (0, BY));
686 chown_advanced_but[0].id = add_widget (ch_dlg, b_att[0]);
687 b_att[1] = button_new (XTRACT (1, BY));
688 chown_advanced_but[1].id = add_widget (ch_dlg, b_att[1]);
689 b_att[2] = button_new (XTRACT (2, BY));
690 chown_advanced_but[2].id = add_widget (ch_dlg, b_att[2]);
691 b_user = button_new (XTRACT (3, BY));
692 chown_advanced_but[3].id = add_widget (ch_dlg, b_user);
693 b_group = button_new (XTRACT (4, BY));
694 chown_advanced_but[4].id = add_widget (ch_dlg, b_group);
695 #undef XTRACT
697 l_mode = label_new (BY + 2, 3, "");
698 add_widget (ch_dlg, l_mode);
700 y = BY + 3;
701 if (!single_set)
703 i = BUTTONS_PERM;
704 add_widget (ch_dlg, hline_new (y++, -1, -1));
705 chown_advanced_but[i].id = add_widget (ch_dlg,
706 button_new (y,
707 WIDGET (ch_dlg)->cols / 2 -
708 chown_advanced_but[i].len,
709 chown_advanced_but[i].ret_cmd,
710 chown_advanced_but[i].flags,
711 chown_advanced_but[i].text, NULL));
712 i++;
713 chown_advanced_but[i].id = add_widget (ch_dlg,
714 button_new (y, WIDGET (ch_dlg)->cols / 2 + 1,
715 chown_advanced_but[i].ret_cmd,
716 chown_advanced_but[i].flags,
717 chown_advanced_but[i].text, NULL));
718 y++;
721 i = BUTTONS_PERM + 2;
722 add_widget (ch_dlg, hline_new (y++, -1, -1));
723 chown_advanced_but[i].id = add_widget (ch_dlg,
724 button_new (y,
725 WIDGET (ch_dlg)->cols / 2 -
726 chown_advanced_but[i].len,
727 chown_advanced_but[i].ret_cmd,
728 chown_advanced_but[i].flags,
729 chown_advanced_but[i].text, NULL));
730 i++;
731 chown_advanced_but[i].id = add_widget (ch_dlg,
732 button_new (y, WIDGET (ch_dlg)->cols / 2 + 1,
733 chown_advanced_but[i].ret_cmd,
734 chown_advanced_but[i].flags,
735 chown_advanced_but[i].text, NULL));
737 dlg_select_widget (b_att[0]);
740 /* --------------------------------------------------------------------------------------------- */
742 static void
743 chown_advanced_done (void)
745 g_free (sf_stat);
746 if (need_update)
747 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
748 repaint_screen ();
751 /* --------------------------------------------------------------------------------------------- */
753 #if 0
754 static void
755 do_chown (uid_t u, gid_t g)
757 chown (current_panel->dir.list[current_file].fname, u, g);
758 file_mark (current_panel, current_file, 0);
760 #endif
762 /* --------------------------------------------------------------------------------------------- */
764 static char *
765 next_file (void)
767 while (!current_panel->dir.list[current_file].f.marked)
768 current_file++;
770 return current_panel->dir.list[current_file].fname;
773 /* --------------------------------------------------------------------------------------------- */
775 static void
776 apply_advanced_chowns (struct stat *sf)
778 vfs_path_t *vpath;
779 char *lc_fname;
780 gid_t a_gid = sf->st_gid;
781 uid_t a_uid = sf->st_uid;
783 lc_fname = current_panel->dir.list[current_file].fname;
784 vpath = vfs_path_from_str (lc_fname);
785 need_update = end_chown = TRUE;
786 if (mc_chmod (vpath, get_mode ()) == -1)
787 message (D_ERROR, MSG_ERROR, _("Cannot chmod \"%s\"\n%s"),
788 lc_fname, unix_error_string (errno));
789 /* call mc_chown only, if mc_chmod didn't fail */
790 else if (mc_chown (vpath, (ch_flags[9] == '+') ? sf->st_uid : (uid_t) (-1),
791 (ch_flags[10] == '+') ? sf->st_gid : (gid_t) (-1)) == -1)
792 message (D_ERROR, MSG_ERROR, _("Cannot chown \"%s\"\n%s"),
793 lc_fname, unix_error_string (errno));
794 do_file_mark (current_panel, current_file, 0);
795 vfs_path_free (vpath);
799 lc_fname = next_file ();
800 vpath = vfs_path_from_str (lc_fname);
802 if (mc_stat (vpath, sf) != 0)
804 vfs_path_free (vpath);
805 break;
808 ch_cmode = sf->st_mode;
810 if (mc_chmod (vpath, get_mode ()) == -1)
811 message (D_ERROR, MSG_ERROR, _("Cannot chmod \"%s\"\n%s"),
812 lc_fname, unix_error_string (errno));
813 /* call mc_chown only, if mc_chmod didn't fail */
814 else if (mc_chown (vpath, (ch_flags[9] == '+') ? a_uid : (uid_t) (-1),
815 (ch_flags[10] == '+') ? a_gid : (gid_t) (-1)) == -1)
816 message (D_ERROR, MSG_ERROR, _("Cannot chown \"%s\"\n%s"),
817 lc_fname, unix_error_string (errno));
819 do_file_mark (current_panel, current_file, 0);
820 vfs_path_free (vpath);
822 while (current_panel->marked != 0);
825 /* --------------------------------------------------------------------------------------------- */
826 /*** public functions ****************************************************************************/
827 /* --------------------------------------------------------------------------------------------- */
829 void
830 chown_advanced_cmd (void)
832 /* Number of files at startup */
833 int files_on_begin;
835 files_on_begin = max (1, current_panel->marked);
838 { /* do while any files remaining */
839 int file_idx;
840 char buffer[BUF_MEDIUM];
841 vfs_path_t *vpath;
842 int result;
844 init_chown_advanced ();
846 if (current_panel->marked)
847 fname = next_file (); /* next marked file */
848 else
849 fname = selection (current_panel)->fname; /* single file */
850 vpath = vfs_path_from_str (fname);
852 if (mc_stat (vpath, sf_stat) != 0)
853 { /* get status of file */
854 dlg_destroy (ch_dlg);
855 vfs_path_free (vpath);
856 break;
859 ch_cmode = sf_stat->st_mode;
861 file_idx = files_on_begin == 1 ? 1 : (files_on_begin - current_panel->marked + 1);
862 g_snprintf (buffer, sizeof (buffer), "%s (%d/%d)",
863 str_fit_to_term (fname, WIDGET (ch_dlg)->cols - 20, J_LEFT_FIT),
864 file_idx, files_on_begin);
865 label_set_text (l_filename, buffer);
866 chown_refresh ();
867 update_ownership ();
869 result = dlg_run (ch_dlg);
871 switch (result)
873 case B_CANCEL:
874 end_chown = TRUE;
875 break;
877 case B_ENTER:
878 need_update = TRUE;
879 if (mc_chmod (vpath, get_mode ()) == -1)
880 message (D_ERROR, MSG_ERROR, _("Cannot chmod \"%s\"\n%s"),
881 fname, unix_error_string (errno));
882 /* call mc_chown only, if mc_chmod didn't fail */
883 else if (mc_chown
884 (vpath, (ch_flags[9] == '+') ? sf_stat->st_uid : (uid_t) (-1),
885 (ch_flags[10] == '+') ? sf_stat->st_gid : (gid_t) (-1)) == -1)
886 message (D_ERROR, MSG_ERROR, _("Cannot chown \"%s\"\n%s"), fname,
887 unix_error_string (errno));
888 break;
890 case B_SETALL:
891 apply_advanced_chowns (sf_stat);
892 break;
894 case B_SKIP:
895 default:
896 break;
899 if (current_panel->marked && result != B_CANCEL)
901 do_file_mark (current_panel, current_file, 0);
902 need_update = TRUE;
904 dlg_destroy (ch_dlg);
905 vfs_path_free (vpath);
907 while (current_panel->marked && !end_chown);
909 chown_advanced_done ();
912 /* --------------------------------------------------------------------------------------------- */