Move widget add/del API from WDialog to WGroup.
[midnight-commander.git] / src / filemanager / achown.c
blob4601a72d9e67d4d06f1bd5c4e7fa5f6f260495da
1 /*
2 Chown-advanced command -- for the Midnight Commander
4 Copyright (C) 1994-2020
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>
32 #include <pwd.h>
33 #include <grp.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
38 #include "lib/global.h"
40 #include "lib/tty/tty.h"
41 #include "lib/tty/key.h" /* XCTRL and ALT macros */
42 #include "lib/skin.h"
43 #include "lib/vfs/vfs.h"
44 #include "lib/strutil.h"
45 #include "lib/util.h"
46 #include "lib/widget.h"
48 #include "midnight.h" /* current_panel */
50 #include "achown.h"
52 /*** global variables ****************************************************************************/
54 /*** file scope macro definitions ****************************************************************/
56 #define BX 5
57 #define BY 5
59 #define BUTTONS 9
60 #define BUTTONS_PERM 5
62 #define B_SETALL B_USER
63 #define B_SKIP (B_USER + 1)
65 /*** file scope type declarations ****************************************************************/
67 /*** file scope variables ************************************************************************/
69 static struct
71 unsigned long id;
72 int ret_cmd;
73 button_flags_t flags;
74 int x;
75 int len;
76 const char *text;
77 } advanced_chown_but[BUTTONS] =
79 /* *INDENT-OFF* */
80 { 0, B_ENTER, NARROW_BUTTON, 3, 0, " " },
81 { 0, B_ENTER, NARROW_BUTTON, 11, 0, " " },
82 { 0, B_ENTER, NARROW_BUTTON, 19, 0, " " },
83 { 0, B_ENTER, NARROW_BUTTON, 29, 0, "" },
84 { 0, B_ENTER, NARROW_BUTTON, 47, 0, "" },
86 { 0, B_SETALL, NORMAL_BUTTON, 0, 0, N_("Set &all") },
87 { 0, B_SKIP, NORMAL_BUTTON, 0, 0, N_("S&kip") },
88 { 0, B_ENTER, DEFPUSH_BUTTON, 0, 0, N_("&Set") },
89 { 0, B_CANCEL, NORMAL_BUTTON, 0, 0, N_("&Cancel") }
90 /* *INDENT-ON* */
93 static int current_file;
94 static gboolean ignore_all;
96 static WButton *b_att[3]; /* permission */
97 static WButton *b_user, *b_group; /* owner */
98 static WLabel *l_filename;
99 static WLabel *l_mode;
101 static int flag_pos;
102 static int x_toggle;
103 static char ch_flags[11];
104 static const char ch_perm[] = "rwx";
105 static mode_t ch_cmode;
106 static struct stat sf_stat;
108 /* --------------------------------------------------------------------------------------------- */
109 /*** file scope functions ************************************************************************/
110 /* --------------------------------------------------------------------------------------------- */
112 static void
113 advanced_chown_i18n (void)
115 static gboolean i18n = FALSE;
116 int i;
118 if (i18n)
119 return;
121 i18n = TRUE;
123 for (i = BUTTONS_PERM; i < BUTTONS; i++)
125 #ifdef ENABLE_NLS
126 advanced_chown_but[i].text = _(advanced_chown_but[i].text);
127 #endif /* ENABLE_NLS */
129 advanced_chown_but[i].len = str_term_width1 (advanced_chown_but[i].text) + 3;
130 if (advanced_chown_but[i].flags == DEFPUSH_BUTTON)
131 advanced_chown_but[i].len += 2; /* "<>" */
136 /* --------------------------------------------------------------------------------------------- */
138 static cb_ret_t
139 inc_flag_pos (void)
141 if (flag_pos == 10)
143 flag_pos = 0;
144 return MSG_NOT_HANDLED;
147 flag_pos++;
149 return flag_pos % 3 == 0 ? MSG_NOT_HANDLED : MSG_HANDLED;
152 /* --------------------------------------------------------------------------------------------- */
154 static cb_ret_t
155 dec_flag_pos (void)
157 if (flag_pos == 0)
159 flag_pos = 10;
160 return MSG_NOT_HANDLED;
163 flag_pos--;
165 return (flag_pos + 1) % 3 == 0 ? MSG_NOT_HANDLED : MSG_HANDLED;
168 /* --------------------------------------------------------------------------------------------- */
170 static void
171 set_perm_by_flags (char *s, int f_p)
173 int i;
175 for (i = 0; i < 3; i++)
177 if (ch_flags[f_p + i] == '+')
178 s[i] = ch_perm[i];
179 else if (ch_flags[f_p + i] == '-')
180 s[i] = '-';
181 else
182 s[i] = (ch_cmode & (1 << (8 - f_p - i))) != 0 ? ch_perm[i] : '-';
186 /* --------------------------------------------------------------------------------------------- */
188 static mode_t
189 get_perm (char *s, int base)
191 mode_t m = 0;
193 m |= (s[0] == '-') ? 0 :
194 ((s[0] == '+') ? (mode_t) (1 << (base + 2)) : (1 << (base + 2)) & ch_cmode);
196 m |= (s[1] == '-') ? 0 :
197 ((s[1] == '+') ? (mode_t) (1 << (base + 1)) : (1 << (base + 1)) & ch_cmode);
199 m |= (s[2] == '-') ? 0 : ((s[2] == '+') ? (mode_t) (1 << base) : (1 << base) & ch_cmode);
201 return m;
204 /* --------------------------------------------------------------------------------------------- */
206 static mode_t
207 get_mode (void)
209 mode_t m;
211 m = ch_cmode ^ (ch_cmode & 0777);
212 m |= get_perm (ch_flags, 6);
213 m |= get_perm (ch_flags + 3, 3);
214 m |= get_perm (ch_flags + 6, 0);
216 return m;
219 /* --------------------------------------------------------------------------------------------- */
221 static void
222 update_permissions (void)
224 set_perm_by_flags (b_att[0]->text.start, 0);
225 set_perm_by_flags (b_att[1]->text.start, 3);
226 set_perm_by_flags (b_att[2]->text.start, 6);
229 /* --------------------------------------------------------------------------------------------- */
231 static void
232 update_ownership (void)
234 button_set_text (b_user, get_owner (sf_stat.st_uid));
235 button_set_text (b_group, get_group (sf_stat.st_gid));
238 /* --------------------------------------------------------------------------------------------- */
240 static void
241 print_flags (const WDialog * h)
243 int i;
245 tty_setcolor (COLOR_NORMAL);
247 for (i = 0; i < 3; i++)
249 widget_gotoyx (h, BY + 1, advanced_chown_but[0].x + 6 + i);
250 tty_print_char (ch_flags[i]);
253 for (i = 0; i < 3; i++)
255 widget_gotoyx (h, BY + 1, advanced_chown_but[1].x + 6 + i);
256 tty_print_char (ch_flags[i + 3]);
259 for (i = 0; i < 3; i++)
261 widget_gotoyx (h, BY + 1, advanced_chown_but[2].x + 6 + i);
262 tty_print_char (ch_flags[i + 6]);
265 update_permissions ();
267 for (i = 0; i < 15; i++)
269 widget_gotoyx (h, BY + 1, advanced_chown_but[3].x + 6 + i);
270 tty_print_char (ch_flags[9]);
272 for (i = 0; i < 15; i++)
274 widget_gotoyx (h, BY + 1, advanced_chown_but[4].x + 6 + i);
275 tty_print_char (ch_flags[10]);
279 /* --------------------------------------------------------------------------------------------- */
281 static void
282 advanced_chown_refresh (WDialog * h)
284 dlg_default_repaint (h);
286 tty_setcolor (COLOR_NORMAL);
288 widget_gotoyx (h, BY - 1, advanced_chown_but[0].x + 5);
289 tty_print_string (_("owner"));
290 widget_gotoyx (h, BY - 1, advanced_chown_but[1].x + 5);
291 tty_print_string (_("group"));
292 widget_gotoyx (h, BY - 1, advanced_chown_but[2].x + 5);
293 tty_print_string (_("other"));
295 widget_gotoyx (h, BY - 1, advanced_chown_but[3].x + 5);
296 tty_print_string (_("owner"));
297 widget_gotoyx (h, BY - 1, advanced_chown_but[4].x + 5);
298 tty_print_string (_("group"));
300 widget_gotoyx (h, BY + 1, 3);
301 tty_print_string (_("Flag"));
302 print_flags (h);
305 /* --------------------------------------------------------------------------------------------- */
307 static void
308 advanced_chown_info_update (void)
310 char buffer[BUF_SMALL];
312 /* mode */
313 g_snprintf (buffer, sizeof (buffer), "Permissions (octal): %o", get_mode ());
314 label_set_text (l_mode, buffer);
316 /* permissions */
317 update_permissions ();
320 /* --------------------------------------------------------------------------------------------- */
322 static void
323 update_mode (WGroup * g)
325 print_flags (DIALOG (g));
326 advanced_chown_info_update ();
327 widget_set_state (WIDGET (g->current->data), WST_FOCUSED, TRUE);
330 /* --------------------------------------------------------------------------------------------- */
332 static cb_ret_t
333 perm_button_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
335 WButton *b = BUTTON (w);
336 WGroup *g = w->owner;
337 int i = 0;
338 int f_pos;
340 /* one of permission buttons */
341 if (b == b_att[0])
342 f_pos = 0;
343 else if (b == b_att[1])
344 f_pos = 1;
345 else /* if (w == b_att [1] */
346 f_pos = 2;
348 switch (msg)
350 case MSG_FOCUS:
351 if (b->hotpos == -1)
352 b->hotpos = 0;
354 flag_pos = f_pos * 3 + b->hotpos;
355 return MSG_HANDLED;
357 case MSG_KEY:
358 switch (parm)
360 case '*':
361 parm = '=';
362 MC_FALLTHROUGH;
364 case '-':
365 case '=':
366 case '+':
367 flag_pos = f_pos * 3 + b->hotpos;
368 ch_flags[flag_pos] = parm;
369 update_mode (g);
370 send_message (w, NULL, MSG_KEY, KEY_RIGHT, NULL);
371 if (b->hotpos == 2)
372 group_select_next_widget (g);
373 break;
375 case XCTRL ('f'):
376 case KEY_RIGHT:
378 cb_ret_t ret;
380 ret = inc_flag_pos ();
381 b->hotpos = flag_pos % 3;
382 return ret;
385 case XCTRL ('b'):
386 case KEY_LEFT:
388 cb_ret_t ret;
390 ret = dec_flag_pos ();
391 b->hotpos = flag_pos % 3;
392 return ret;
395 case 'x':
396 i++;
397 MC_FALLTHROUGH;
399 case 'w':
400 i++;
401 MC_FALLTHROUGH;
403 case 'r':
404 b->hotpos = i;
405 MC_FALLTHROUGH;
407 case ' ':
408 i = b->hotpos;
410 flag_pos = f_pos * 3 + i;
411 if (b->text.start[flag_pos % 3] == '-')
412 ch_flags[flag_pos] = '+';
413 else
414 ch_flags[flag_pos] = '-';
415 update_mode (w->owner);
416 break;
418 case '4':
419 i++;
420 MC_FALLTHROUGH;
422 case '2':
423 i++;
424 MC_FALLTHROUGH;
426 case '1':
427 b->hotpos = i;
428 flag_pos = f_pos * 3 + i;
429 ch_flags[flag_pos] = '=';
430 update_mode (g);
431 break;
433 default:
434 break;
436 /* continue key handling in the dialog level */
437 return MSG_NOT_HANDLED;
439 default:
440 return button_default_callback (w, sender, msg, parm, data);
444 /* --------------------------------------------------------------------------------------------- */
446 static void
447 perm_button_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
449 switch (msg)
451 case MSG_MOUSE_DOWN:
452 /* place cursor on flag that is being modified */
453 BUTTON (w)->hotpos = CLAMP (event->x - 1, 0, 2);
454 MC_FALLTHROUGH;
456 default:
457 button_mouse_default_callback (w, msg, event);
458 break;
462 /* --------------------------------------------------------------------------------------------- */
464 static WButton *
465 perm_button_new (int y, int x, int action, button_flags_t flags, const char *text,
466 bcback_fn callback)
468 WButton *b;
469 Widget *w;
471 /* create base button using native API */
472 b = button_new (y, x, action, flags, text, callback);
473 w = WIDGET (b);
475 /* we don't want HOTKEY */
476 widget_want_hotkey (w, FALSE);
478 w->callback = perm_button_callback;
479 w->mouse_callback = perm_button_mouse_callback;
481 return b;
484 /* --------------------------------------------------------------------------------------------- */
486 static cb_ret_t
487 chl_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
489 switch (msg)
491 case MSG_KEY:
492 switch (parm)
494 case KEY_LEFT:
495 case KEY_RIGHT:
497 WDialog *h = DIALOG (w);
499 h->ret_value = parm;
500 dlg_stop (h);
502 default:
503 break;
505 MC_FALLTHROUGH;
507 default:
508 return dlg_default_callback (w, sender, msg, parm, data);
512 /* --------------------------------------------------------------------------------------------- */
514 static int
515 user_group_button_cb (WButton * button, int action)
517 Widget *w = WIDGET (button);
518 int f_pos;
519 gboolean chl_end;
521 (void) action;
523 if (button == b_user)
524 f_pos = BUTTONS_PERM - 2;
525 else if (button == b_group)
526 f_pos = BUTTONS_PERM - 1;
527 else
528 return 0; /* do nothing */
532 WGroup *g = w->owner;
533 WDialog *h = DIALOG (h);
534 Widget *wh = WIDGET (h);
536 gboolean is_owner = (f_pos == BUTTONS_PERM - 2);
537 const char *title;
538 int lxx, b_pos;
539 WDialog *chl_dlg;
540 WListbox *chl_list;
541 int result;
542 int fe;
543 struct passwd *chl_pass;
544 struct group *chl_grp;
546 chl_end = FALSE;
548 if (is_owner)
550 title = _("owner");
551 lxx = WIDGET (b_user)->x + 1;
553 else
555 title = _("group");
556 lxx = WIDGET (b_group)->x + 1;
559 chl_dlg =
560 dlg_create (TRUE, wh->y - 1, lxx, wh->lines + 2, 17, WPOS_KEEP_DEFAULT, TRUE,
561 dialog_colors, chl_callback, NULL, "[Advanced Chown]", title);
563 /* get new listboxes */
564 chl_list =
565 listbox_new (1, 1, WIDGET (chl_dlg)->lines - 2, WIDGET (chl_dlg)->cols - 2, FALSE,
566 NULL);
567 listbox_add_item (chl_list, LISTBOX_APPEND_AT_END, 0, "<Unknown>", NULL, FALSE);
568 if (is_owner)
570 /* get and put user names in the listbox */
571 setpwent ();
572 while ((chl_pass = getpwent ()) != NULL)
573 listbox_add_item (chl_list, LISTBOX_APPEND_SORTED, 0, chl_pass->pw_name, NULL,
574 FALSE);
575 endpwent ();
576 fe = listbox_search_text (chl_list, get_owner (sf_stat.st_uid));
578 else
580 /* get and put group names in the listbox */
581 setgrent ();
582 while ((chl_grp = getgrent ()) != NULL)
583 listbox_add_item (chl_list, LISTBOX_APPEND_SORTED, 0, chl_grp->gr_name, NULL,
584 FALSE);
585 endgrent ();
586 fe = listbox_search_text (chl_list, get_group (sf_stat.st_gid));
589 listbox_select_entry (chl_list, fe);
591 b_pos = chl_list->pos;
592 group_add_widget (GROUP (chl_dlg), chl_list);
594 result = dlg_run (chl_dlg);
596 if (result != B_CANCEL)
598 if (b_pos != chl_list->pos)
600 gboolean ok = FALSE;
601 char *text;
603 listbox_get_current (chl_list, &text, NULL);
604 if (is_owner)
606 chl_pass = getpwnam (text);
607 if (chl_pass != NULL)
609 sf_stat.st_uid = chl_pass->pw_uid;
610 ok = TRUE;
613 else
615 chl_grp = getgrnam (text);
616 if (chl_grp != NULL)
618 sf_stat.st_gid = chl_grp->gr_gid;
619 ok = TRUE;
623 if (!ok)
624 group_select_current_widget (g);
625 else
627 ch_flags[f_pos + 6] = '+';
628 update_ownership ();
629 group_select_current_widget (g);
630 print_flags (h);
634 if (result == KEY_LEFT)
636 if (!is_owner)
637 chl_end = TRUE;
638 group_select_prev_widget (g);
639 f_pos--;
641 else if (result == KEY_RIGHT)
643 if (is_owner)
644 chl_end = TRUE;
645 group_select_next_widget (g);
646 f_pos++;
650 /* Here we used to redraw the window */
651 dlg_destroy (chl_dlg);
653 while (chl_end);
655 return 0;
658 /* --------------------------------------------------------------------------------------------- */
660 static cb_ret_t
661 advanced_chown_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
663 WGroup *g = GROUP (w);
664 WDialog *h = DIALOG (w);
665 int i = 0;
667 switch (msg)
669 case MSG_DRAW:
670 advanced_chown_refresh (h);
671 advanced_chown_info_update ();
672 return MSG_HANDLED;
674 case MSG_KEY:
675 switch (parm)
677 case ALT ('x'):
678 i++;
679 MC_FALLTHROUGH;
681 case ALT ('w'):
682 i++;
683 MC_FALLTHROUGH;
685 case ALT ('r'):
686 parm = i + 3;
687 for (i = 0; i < 3; i++)
688 ch_flags[i * 3 + parm - 3] = (x_toggle & (1 << parm)) ? '-' : '+';
689 x_toggle ^= (1 << parm);
690 update_mode (g);
691 dlg_broadcast_msg (h, MSG_DRAW);
692 break;
694 case XCTRL ('x'):
695 i++;
696 MC_FALLTHROUGH;
698 case XCTRL ('w'):
699 i++;
700 MC_FALLTHROUGH;
702 case XCTRL ('r'):
703 parm = i;
704 for (i = 0; i < 3; i++)
705 ch_flags[i * 3 + parm] = (x_toggle & (1 << parm)) ? '-' : '+';
706 x_toggle ^= (1 << parm);
707 update_mode (g);
708 dlg_broadcast_msg (h, MSG_DRAW);
709 break;
711 default:
712 break;
714 return MSG_NOT_HANDLED;
716 default:
717 return dlg_default_callback (w, sender, msg, parm, data);
721 /* --------------------------------------------------------------------------------------------- */
723 static WDialog *
724 advanced_chown_init (void)
726 gboolean single_set;
727 WDialog *ch_dlg;
728 WGroup *ch_grp;
729 int lines = 12;
730 int cols = 74;
731 int i;
732 int y;
734 memset (ch_flags, '=', 11);
735 flag_pos = 0;
736 x_toggle = 070;
738 single_set = (current_panel->marked < 2);
739 if (!single_set)
740 lines += 2;
742 ch_dlg =
743 dlg_create (TRUE, 0, 0, lines, cols, WPOS_CENTER, FALSE, dialog_colors,
744 advanced_chown_callback, NULL, "[Advanced Chown]", _("Chown advanced command"));
745 ch_grp = GROUP (ch_dlg);
747 l_filename = label_new (2, 3, "");
748 group_add_widget (ch_grp, l_filename);
750 group_add_widget (ch_grp, hline_new (3, -1, -1));
752 #define XTRACT(i,y,cb) y, BX+advanced_chown_but[i].x, \
753 advanced_chown_but[i].ret_cmd, advanced_chown_but[i].flags, \
754 (advanced_chown_but[i].text), cb
755 b_att[0] = perm_button_new (XTRACT (0, BY, NULL));
756 advanced_chown_but[0].id = group_add_widget (ch_grp, b_att[0]);
757 b_att[1] = perm_button_new (XTRACT (1, BY, NULL));
758 advanced_chown_but[1].id = group_add_widget (ch_grp, b_att[1]);
759 b_att[2] = perm_button_new (XTRACT (2, BY, NULL));
760 advanced_chown_but[2].id = group_add_widget (ch_grp, b_att[2]);
761 b_user = button_new (XTRACT (3, BY, user_group_button_cb));
762 advanced_chown_but[3].id = group_add_widget (ch_grp, b_user);
763 b_group = button_new (XTRACT (4, BY, user_group_button_cb));
764 advanced_chown_but[4].id = group_add_widget (ch_grp, b_group);
766 l_mode = label_new (BY + 2, 3, "");
767 group_add_widget (ch_grp, l_mode);
769 y = BY + 3;
770 if (!single_set)
772 i = BUTTONS_PERM;
773 group_add_widget (ch_grp, hline_new (y++, -1, -1));
774 advanced_chown_but[i].id = group_add_widget (ch_grp,
775 button_new (y,
776 WIDGET (ch_dlg)->cols / 2 -
777 advanced_chown_but[i].len,
778 advanced_chown_but[i].ret_cmd,
779 advanced_chown_but[i].flags,
780 advanced_chown_but[i].text, NULL));
781 i++;
782 advanced_chown_but[i].id = group_add_widget (ch_grp,
783 button_new (y, WIDGET (ch_dlg)->cols / 2 + 1,
784 advanced_chown_but[i].ret_cmd,
785 advanced_chown_but[i].flags,
786 advanced_chown_but[i].text, NULL));
787 y++;
790 i = BUTTONS_PERM + 2;
791 group_add_widget (ch_grp, hline_new (y++, -1, -1));
792 advanced_chown_but[i].id = group_add_widget (ch_grp,
793 button_new (y,
794 WIDGET (ch_dlg)->cols / 2 -
795 advanced_chown_but[i].len,
796 advanced_chown_but[i].ret_cmd,
797 advanced_chown_but[i].flags,
798 advanced_chown_but[i].text, NULL));
799 i++;
800 advanced_chown_but[i].id = group_add_widget (ch_grp,
801 button_new (y, WIDGET (ch_dlg)->cols / 2 + 1,
802 advanced_chown_but[i].ret_cmd,
803 advanced_chown_but[i].flags,
804 advanced_chown_but[i].text, NULL));
806 widget_select (WIDGET (b_att[0]));
808 return ch_dlg;
811 /* --------------------------------------------------------------------------------------------- */
813 static void
814 advanced_chown_done (gboolean need_update)
816 if (need_update)
817 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
818 repaint_screen ();
821 /* --------------------------------------------------------------------------------------------- */
823 static const char *
824 next_file (void)
826 while (!current_panel->dir.list[current_file].f.marked)
827 current_file++;
829 return current_panel->dir.list[current_file].fname;
832 /* --------------------------------------------------------------------------------------------- */
834 static gboolean
835 try_advanced_chown (const vfs_path_t * p, mode_t m, uid_t u, gid_t g)
837 int chmod_result;
838 const char *fname;
840 fname = x_basename (vfs_path_as_str (p));
842 while ((chmod_result = mc_chmod (p, m)) == -1 && !ignore_all)
844 int my_errno = errno;
845 int result;
846 char *msg;
848 msg = g_strdup_printf (_("Cannot chmod \"%s\"\n%s"), fname, unix_error_string (my_errno));
849 result =
850 query_dialog (MSG_ERROR, msg, D_ERROR, 4, _("&Ignore"), _("Ignore &all"), _("&Retry"),
851 _("&Cancel"));
852 g_free (msg);
854 switch (result)
856 case 0:
857 /* call mc_chown() only, if mc_chmod() didn't fail */
858 return TRUE;
860 case 1:
861 ignore_all = TRUE;
862 /* call mc_chown() only, if mc_chmod() didn't fail */
863 return TRUE;
865 case 2:
866 /* retry chmod of this file */
867 break;
869 case 3:
870 default:
871 /* stop remain files processing */
872 return FALSE;
876 /* call mc_chown() only, if mc_chmod didn't fail */
877 while (chmod_result != -1 && mc_chown (p, u, g) == -1 && !ignore_all)
879 int my_errno = errno;
880 int result;
881 char *msg;
883 msg = g_strdup_printf (_("Cannot chown \"%s\"\n%s"), fname, unix_error_string (my_errno));
884 result =
885 query_dialog (MSG_ERROR, msg, D_ERROR, 4, _("&Ignore"), _("Ignore &all"), _("&Retry"),
886 _("&Cancel"));
887 g_free (msg);
889 switch (result)
891 case 0:
892 /* try next file */
893 return TRUE;
895 case 1:
896 ignore_all = TRUE;
897 /* try next file */
898 return TRUE;
900 case 2:
901 /* retry chown of this file */
902 break;
904 case 3:
905 default:
906 /* stop remain files processing */
907 return FALSE;
911 return TRUE;
915 /* --------------------------------------------------------------------------------------------- */
917 static gboolean
918 do_advanced_chown (const vfs_path_t * p, mode_t m, uid_t u, gid_t g)
920 gboolean ret;
922 ret = try_advanced_chown (p, m, u, g);
924 do_file_mark (current_panel, current_file, 0);
926 return ret;
929 /* --------------------------------------------------------------------------------------------- */
931 static void
932 apply_advanced_chowns (vfs_path_t * vpath, struct stat *sf)
934 gid_t a_gid = sf->st_gid;
935 uid_t a_uid = sf->st_uid;
936 gboolean ok;
938 if (!do_advanced_chown
939 (vpath, get_mode (), (ch_flags[9] == '+') ? a_uid : (uid_t) (-1),
940 (ch_flags[10] == '+') ? a_gid : (gid_t) (-1)))
941 return;
945 const char *fname;
947 fname = next_file ();
948 vpath = vfs_path_from_str (fname);
949 ok = (mc_stat (vpath, sf) == 0);
951 if (!ok)
953 /* if current file was deleted outside mc -- try next file */
954 /* decrease current_panel->marked */
955 do_file_mark (current_panel, current_file, 0);
957 /* try next file */
958 ok = TRUE;
960 else
962 ch_cmode = sf->st_mode;
964 ok = do_advanced_chown (vpath, get_mode (),
965 (ch_flags[9] == '+') ? a_uid : (uid_t) (-1),
966 (ch_flags[10] == '+') ? a_gid : (gid_t) (-1));
969 vfs_path_free (vpath);
971 while (ok && current_panel->marked != 0);
974 /* --------------------------------------------------------------------------------------------- */
975 /*** public functions ****************************************************************************/
976 /* --------------------------------------------------------------------------------------------- */
978 void
979 advanced_chown_cmd (void)
981 gboolean need_update;
982 gboolean end_chown;
984 /* Number of files at startup */
985 int files_on_begin;
987 files_on_begin = MAX (1, current_panel->marked);
989 advanced_chown_i18n ();
991 current_file = 0;
992 ignore_all = FALSE;
995 { /* do while any files remaining */
996 vfs_path_t *vpath;
997 WDialog *ch_dlg;
998 const char *fname;
999 int result;
1000 int file_idx;
1001 char buffer[BUF_MEDIUM];
1003 do_refresh ();
1005 need_update = FALSE;
1006 end_chown = FALSE;
1008 if (current_panel->marked != 0)
1009 fname = next_file (); /* next marked file */
1010 else
1011 fname = selection (current_panel)->fname; /* single file */
1013 vpath = vfs_path_from_str (fname);
1015 if (mc_stat (vpath, &sf_stat) != 0)
1017 vfs_path_free (vpath);
1018 break;
1021 ch_cmode = sf_stat.st_mode;
1023 ch_dlg = advanced_chown_init ();
1025 file_idx = files_on_begin == 1 ? 1 : (files_on_begin - current_panel->marked + 1);
1026 g_snprintf (buffer, sizeof (buffer), "%s (%d/%d)",
1027 str_fit_to_term (fname, WIDGET (ch_dlg)->cols - 20, J_LEFT_FIT),
1028 file_idx, files_on_begin);
1029 label_set_text (l_filename, buffer);
1030 update_ownership ();
1032 result = dlg_run (ch_dlg);
1034 switch (result)
1036 case B_CANCEL:
1037 end_chown = TRUE;
1038 break;
1040 case B_ENTER:
1041 if (current_panel->marked <= 1)
1043 /* single or last file */
1044 if (mc_chmod (vpath, get_mode ()) == -1)
1045 message (D_ERROR, MSG_ERROR, _("Cannot chmod \"%s\"\n%s"),
1046 fname, unix_error_string (errno));
1047 /* call mc_chown only, if mc_chmod didn't fail */
1048 else if (mc_chown
1049 (vpath, (ch_flags[9] == '+') ? sf_stat.st_uid : (uid_t) (-1),
1050 (ch_flags[10] == '+') ? sf_stat.st_gid : (gid_t) (-1)) == -1)
1051 message (D_ERROR, MSG_ERROR, _("Cannot chown \"%s\"\n%s"), fname,
1052 unix_error_string (errno));
1054 end_chown = TRUE;
1056 else if (!try_advanced_chown
1057 (vpath, get_mode (), (ch_flags[9] == '+') ? sf_stat.st_uid : (uid_t) (-1),
1058 (ch_flags[10] == '+') ? sf_stat.st_gid : (gid_t) (-1)))
1060 /* stop multiple files processing */
1061 result = B_CANCEL;
1062 end_chown = TRUE;
1065 need_update = TRUE;
1066 break;
1068 case B_SETALL:
1069 apply_advanced_chowns (vpath, &sf_stat);
1070 need_update = TRUE;
1071 end_chown = TRUE;
1072 break;
1074 case B_SKIP:
1075 default:
1076 break;
1079 if (current_panel->marked != 0 && result != B_CANCEL)
1081 do_file_mark (current_panel, current_file, 0);
1082 need_update = TRUE;
1085 vfs_path_free (vpath);
1087 dlg_destroy (ch_dlg);
1089 while (current_panel->marked != 0 && !end_chown);
1091 advanced_chown_done (need_update);
1094 /* --------------------------------------------------------------------------------------------- */