Ticket #3431: add missing default cases.
[midnight-commander.git] / src / filemanager / chmod.c
blob7793e5371bb3ce8318035560aac3f137e14b229f
1 /*
2 Chmod 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 chmod.c
24 * \brief Source: chmod command
27 #include <config.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
34 #include "lib/global.h"
36 #include "lib/tty/tty.h"
37 #include "lib/skin.h"
38 #include "lib/vfs/vfs.h"
39 #include "lib/strutil.h"
40 #include "lib/util.h"
41 #include "lib/widget.h"
42 #include "lib/keybind.h" /* CK_Cancel */
44 #include "midnight.h" /* current_panel */
45 #include "chmod.h"
47 /*** global variables ****************************************************************************/
49 /*** file scope macro definitions ****************************************************************/
51 #define PX 3
52 #define PY 2
54 #define B_MARKED B_USER
55 #define B_ALL (B_USER + 1)
56 #define B_SETMRK (B_USER + 2)
57 #define B_CLRMRK (B_USER + 3)
59 /*** file scope type declarations ****************************************************************/
61 /*** file scope variables ************************************************************************/
63 static gboolean single_set;
65 static gboolean mode_change, need_update, end_chmod;
66 static int c_file;
68 static mode_t and_mask, or_mask, c_stat;
70 static WLabel *statl;
71 static WGroupbox *file_gb;
73 static struct
75 mode_t mode;
76 const char *text;
77 gboolean selected;
78 WCheck *check;
79 } check_perm[] =
81 /* *INDENT-OFF* */
82 { S_ISUID, N_("set &user ID on execution"), FALSE, NULL },
83 { S_ISGID, N_("set &group ID on execution"), FALSE, NULL },
84 { S_ISVTX, N_("stick&y bit"), FALSE, NULL },
85 { S_IRUSR, N_("&read by owner"), FALSE, NULL },
86 { S_IWUSR, N_("&write by owner"), FALSE, NULL },
87 { S_IXUSR, N_("e&xecute/search by owner"), FALSE, NULL },
88 { S_IRGRP, N_("rea&d by group"), FALSE, NULL },
89 { S_IWGRP, N_("write by grou&p"), FALSE, NULL },
90 { S_IXGRP, N_("execu&te/search by group"), FALSE, NULL },
91 { S_IROTH, N_("read &by others"), FALSE, NULL },
92 { S_IWOTH, N_("wr&ite by others"), FALSE, NULL },
93 { S_IXOTH, N_("execute/searc&h by others"), FALSE, NULL }
94 /* *INDENT-ON* */
97 static const unsigned int check_perm_num = G_N_ELEMENTS (check_perm);
98 static int check_perm_len = 0;
100 static const char *file_info_labels[] = {
101 N_("Name:"),
102 N_("Permissions (octal):"),
103 N_("Owner name:"),
104 N_("Group name:")
107 static const unsigned int file_info_labels_num = G_N_ELEMENTS (file_info_labels);
108 static int file_info_labels_len = 0;
110 static struct
112 int ret_cmd;
113 int flags;
114 int y; /* vertical position relatively to dialog bottom boundary */
115 int len;
116 const char *text;
117 } chmod_but[] =
119 /* *INDENT-OFF* */
120 { B_ALL, NORMAL_BUTTON, 6, 0, N_("Set &all") },
121 { B_MARKED, NORMAL_BUTTON, 6, 0, N_("&Marked all") },
122 { B_SETMRK, NORMAL_BUTTON, 5, 0, N_("S&et marked") },
123 { B_CLRMRK, NORMAL_BUTTON, 5, 0, N_("C&lear marked") },
124 { B_ENTER, DEFPUSH_BUTTON, 3, 0, N_("&Set") },
125 { B_CANCEL, NORMAL_BUTTON, 3, 0, N_("&Cancel") }
126 /* *INDENT-ON* */
129 static const unsigned int chmod_but_num = G_N_ELEMENTS (chmod_but);
131 /* --------------------------------------------------------------------------------------------- */
132 /*** file scope functions ************************************************************************/
133 /* --------------------------------------------------------------------------------------------- */
135 static void
136 chmod_i18n (void)
138 static gboolean i18n = FALSE;
139 unsigned int i;
140 int len;
142 if (i18n)
143 return;
145 i18n = TRUE;
147 #ifdef ENABLE_NLS
148 for (i = 0; i < check_perm_num; i++)
149 check_perm[i].text = _(check_perm[i].text);
151 for (i = 0; i < file_info_labels_num; i++)
152 file_info_labels[i] = _(file_info_labels[i]);
154 for (i = 0; i < chmod_but_num; i++)
155 chmod_but[i].text = _(chmod_but[i].text);
156 #endif /* ENABLE_NLS */
158 for (i = 0; i < check_perm_num; i++)
160 len = str_term_width1 (check_perm[i].text);
161 check_perm_len = max (check_perm_len, len);
164 check_perm_len += 1 + 3 + 1; /* mark, [x] and space */
166 for (i = 0; i < file_info_labels_num; i++)
168 len = str_term_width1 (file_info_labels[i]) + 2; /* spaces around */
169 file_info_labels_len = max (file_info_labels_len, len);
172 for (i = 0; i < chmod_but_num; i++)
174 chmod_but[i].len = str_term_width1 (chmod_but[i].text) + 3; /* [], spaces and w/o & */
175 if (chmod_but[i].flags == DEFPUSH_BUTTON)
176 chmod_but[i].len += 2; /* <> */
180 /* --------------------------------------------------------------------------------------------- */
182 static void
183 chmod_toggle_select (WDialog * h, int Id)
185 tty_setcolor (COLOR_NORMAL);
186 check_perm[Id].selected = !check_perm[Id].selected;
188 widget_move (h, PY + Id + 1, PX + 1);
189 tty_print_char (check_perm[Id].selected ? '*' : ' ');
190 widget_move (h, PY + Id + 1, PX + 3);
193 /* --------------------------------------------------------------------------------------------- */
195 static void
196 chmod_refresh (WDialog * h)
198 int y = WIDGET (file_gb)->y + 1;
199 int x = WIDGET (file_gb)->x + 2;
201 dlg_default_repaint (h);
203 tty_setcolor (COLOR_NORMAL);
205 tty_gotoyx (y, x);
206 tty_print_string (file_info_labels[0]);
207 tty_gotoyx (y + 2, x);
208 tty_print_string (file_info_labels[1]);
209 tty_gotoyx (y + 4, x);
210 tty_print_string (file_info_labels[2]);
211 tty_gotoyx (y + 6, x);
212 tty_print_string (file_info_labels[3]);
215 /* --------------------------------------------------------------------------------------------- */
217 static cb_ret_t
218 chmod_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
220 WDialog *h = DIALOG (w);
222 switch (msg)
224 case MSG_ACTION:
226 /* handle checkboxes */
227 unsigned int i;
229 /* close dialog due to SIGINT (ctrl-g) */
230 if (sender == NULL && parm == CK_Cancel)
231 return MSG_NOT_HANDLED;
233 /* whether action was sent by checkbox? */
234 for (i = 0; i < check_perm_num; i++)
235 if (sender == WIDGET (check_perm[i].check))
236 break;
238 if (i < check_perm_num)
240 char buffer[BUF_TINY];
242 c_stat ^= check_perm[i].mode;
243 g_snprintf (buffer, sizeof (buffer), "%o", (unsigned int) c_stat);
244 label_set_text (statl, buffer);
245 chmod_toggle_select (h, i);
246 mode_change = TRUE;
247 return MSG_HANDLED;
251 return MSG_NOT_HANDLED;
253 case MSG_KEY:
254 if (parm == 'T' || parm == 't' || parm == KEY_IC)
256 unsigned int i;
257 unsigned long id;
259 id = dlg_get_current_widget_id (h);
260 for (i = 0; i < check_perm_num; i++)
261 if (id == WIDGET (check_perm[i].check)->id)
262 break;
264 if (i < check_perm_num)
266 chmod_toggle_select (h, i);
267 if (parm == KEY_IC)
268 dlg_one_down (h);
269 return MSG_HANDLED;
272 return MSG_NOT_HANDLED;
274 case MSG_DRAW:
275 chmod_refresh (h);
276 return MSG_HANDLED;
278 default:
279 return dlg_default_callback (w, sender, msg, parm, data);
283 /* --------------------------------------------------------------------------------------------- */
285 static WDialog *
286 init_chmod (const char *fname, const struct stat *sf_stat)
288 WDialog *ch_dlg;
289 int lines, cols;
290 int y;
291 int perm_gb_len;
292 int file_gb_len;
293 unsigned int i;
294 const char *c_fname, *c_fown, *c_fgrp;
295 char buffer[BUF_TINY];
297 single_set = (current_panel->marked < 2);
298 perm_gb_len = check_perm_len + 2;
299 file_gb_len = file_info_labels_len + 2;
300 cols = str_term_width1 (fname) + 2 + 1;
301 file_gb_len = max (file_gb_len, cols);
303 lines = single_set ? 20 : 23;
304 cols = perm_gb_len + file_gb_len + 1 + 6;
306 if (cols > COLS)
308 /* shrink the right groupbox */
309 cols = COLS;
310 file_gb_len = cols - (perm_gb_len + 1 + 6);
313 ch_dlg =
314 dlg_create (TRUE, 0, 0, lines, cols, dialog_colors,
315 chmod_callback, NULL, "[Chmod]", _("Chmod command"), DLG_CENTER);
317 add_widget (ch_dlg, groupbox_new (PY, PX, check_perm_num + 2, perm_gb_len, _("Permission")));
319 for (i = 0; i < check_perm_num; i++)
321 check_perm[i].check = check_new (PY + i + 1, PX + 2,
322 (c_stat & check_perm[i].mode) != 0 ? 1 : 0,
323 check_perm[i].text);
324 add_widget (ch_dlg, check_perm[i].check);
327 file_gb = groupbox_new (PY, PX + perm_gb_len + 1, check_perm_num + 2, file_gb_len, _("File"));
328 add_widget (ch_dlg, file_gb);
330 /* Set the labels */
331 y = PY + 2;
332 cols = PX + perm_gb_len + 3;
333 c_fname = str_trunc (fname, file_gb_len - 3);
334 add_widget (ch_dlg, label_new (y, cols, c_fname));
335 g_snprintf (buffer, sizeof (buffer), "%o", (unsigned int) c_stat);
336 statl = label_new (y + 2, cols, buffer);
337 add_widget (ch_dlg, statl);
338 c_fown = str_trunc (get_owner (sf_stat->st_uid), file_gb_len - 3);
339 add_widget (ch_dlg, label_new (y + 4, cols, c_fown));
340 c_fgrp = str_trunc (get_group (sf_stat->st_gid), file_gb_len - 3);
341 add_widget (ch_dlg, label_new (y + 6, cols, c_fgrp));
343 if (!single_set)
345 i = 0;
346 add_widget (ch_dlg, hline_new (lines - chmod_but[i].y - 1, -1, -1));
347 for (; i < chmod_but_num - 2; i++)
349 y = lines - chmod_but[i].y;
350 add_widget (ch_dlg,
351 button_new (y, WIDGET (ch_dlg)->cols / 2 - chmod_but[i].len,
352 chmod_but[i].ret_cmd, chmod_but[i].flags, chmod_but[i].text,
353 NULL));
354 i++;
355 add_widget (ch_dlg,
356 button_new (y, WIDGET (ch_dlg)->cols / 2 + 1,
357 chmod_but[i].ret_cmd, chmod_but[i].flags, chmod_but[i].text,
358 NULL));
362 i = chmod_but_num - 2;
363 y = lines - chmod_but[i].y;
364 add_widget (ch_dlg, hline_new (y - 1, -1, -1));
365 add_widget (ch_dlg,
366 button_new (y, WIDGET (ch_dlg)->cols / 2 - chmod_but[i].len, chmod_but[i].ret_cmd,
367 chmod_but[i].flags, chmod_but[i].text, NULL));
368 i++;
369 add_widget (ch_dlg,
370 button_new (y, WIDGET (ch_dlg)->cols / 2 + 1, chmod_but[i].ret_cmd,
371 chmod_but[i].flags, chmod_but[i].text, NULL));
373 /* select first checkbox */
374 dlg_select_widget (check_perm[0].check);
376 return ch_dlg;
379 /* --------------------------------------------------------------------------------------------- */
381 static void
382 chmod_done (void)
384 if (need_update)
385 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
386 repaint_screen ();
389 /* --------------------------------------------------------------------------------------------- */
391 static char *
392 next_file (void)
394 while (!current_panel->dir.list[c_file].f.marked)
395 c_file++;
397 return current_panel->dir.list[c_file].fname;
400 /* --------------------------------------------------------------------------------------------- */
402 static void
403 do_chmod (struct stat *sf)
405 vfs_path_t *vpath;
406 sf->st_mode &= and_mask;
407 sf->st_mode |= or_mask;
409 vpath = vfs_path_from_str (current_panel->dir.list[c_file].fname);
410 if (mc_chmod (vpath, sf->st_mode) == -1)
411 message (D_ERROR, MSG_ERROR, _("Cannot chmod \"%s\"\n%s"),
412 current_panel->dir.list[c_file].fname, unix_error_string (errno));
414 vfs_path_free (vpath);
415 do_file_mark (current_panel, c_file, 0);
418 /* --------------------------------------------------------------------------------------------- */
420 static void
421 apply_mask (struct stat *sf)
423 need_update = TRUE;
424 end_chmod = TRUE;
426 do_chmod (sf);
430 char *fname;
431 vfs_path_t *vpath;
432 gboolean ok;
434 fname = next_file ();
435 vpath = vfs_path_from_str (fname);
436 ok = (mc_stat (vpath, sf) == 0);
437 vfs_path_free (vpath);
438 if (!ok)
439 return;
441 c_stat = sf->st_mode;
443 do_chmod (sf);
445 while (current_panel->marked != 0);
448 /* --------------------------------------------------------------------------------------------- */
449 /*** public functions ****************************************************************************/
450 /* --------------------------------------------------------------------------------------------- */
452 void
453 chmod_cmd (void)
455 chmod_i18n ();
458 { /* do while any files remaining */
459 vfs_path_t *vpath;
460 WDialog *ch_dlg;
461 struct stat sf_stat;
462 char *fname;
463 int result;
464 unsigned int i;
466 do_refresh ();
468 mode_change = FALSE;
469 need_update = FALSE;
470 end_chmod = FALSE;
471 c_file = 0;
473 if (current_panel->marked != 0)
474 fname = next_file (); /* next marked file */
475 else
476 fname = selection (current_panel)->fname; /* single file */
478 vpath = vfs_path_from_str (fname);
480 if (mc_stat (vpath, &sf_stat) != 0)
482 vfs_path_free (vpath);
483 break;
486 c_stat = sf_stat.st_mode;
488 ch_dlg = init_chmod (fname, &sf_stat);
490 /* do action */
491 result = dlg_run (ch_dlg);
493 switch (result)
495 case B_ENTER:
496 if (mode_change && mc_chmod (vpath, c_stat) == -1)
497 message (D_ERROR, MSG_ERROR, _("Cannot chmod \"%s\"\n%s"),
498 fname, unix_error_string (errno));
499 need_update = TRUE;
500 break;
502 case B_CANCEL:
503 end_chmod = TRUE;
504 break;
506 case B_ALL:
507 case B_MARKED:
508 and_mask = or_mask = 0;
509 and_mask = ~and_mask;
511 for (i = 0; i < check_perm_num; i++)
512 if (check_perm[i].selected || result == B_ALL)
514 if (check_perm[i].check->state & C_BOOL)
515 or_mask |= check_perm[i].mode;
516 else
517 and_mask &= ~check_perm[i].mode;
520 apply_mask (&sf_stat);
521 break;
523 case B_SETMRK:
524 and_mask = or_mask = 0;
525 and_mask = ~and_mask;
527 for (i = 0; i < check_perm_num; i++)
528 if (check_perm[i].selected)
529 or_mask |= check_perm[i].mode;
531 apply_mask (&sf_stat);
532 break;
534 case B_CLRMRK:
535 and_mask = or_mask = 0;
536 and_mask = ~and_mask;
538 for (i = 0; i < check_perm_num; i++)
539 if (check_perm[i].selected)
540 and_mask &= ~check_perm[i].mode;
542 apply_mask (&sf_stat);
543 break;
545 default:
546 break;
549 if (current_panel->marked != 0 && result != B_CANCEL)
551 do_file_mark (current_panel, c_file, 0);
552 need_update = TRUE;
555 vfs_path_free (vpath);
557 dlg_destroy (ch_dlg);
559 while (current_panel->marked != 0 && !end_chmod);
561 chmod_done ();
564 /* --------------------------------------------------------------------------------------------- */