Updated italian translation
[midnight-commander.git] / src / achown.c
blob8574357226ac9fae8a23314c09329c0c5ba3e3ec
1 /* Chown-advanced command -- for the Midnight Commander
2 Copyright (C) 1994, 1995 Radek Doulik
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #include <config.h>
20 /* Needed for the extern declarations of integer parameters */
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #ifdef HAVE_UNISTD_H
24 # include <unistd.h>
25 #endif
26 #include <string.h>
27 #include <stdio.h>
28 #include <errno.h> /* For errno on SunOS systems */
30 #include "global.h"
31 #include "tty.h"
32 #include "win.h"
33 #include "color.h"
34 #include "dialog.h"
35 #include "widget.h"
36 #include "wtools.h" /* For init_box_colors() */
37 #include "key.h" /* XCTRL and ALT macros */
39 #include "dir.h"
40 #include "panel.h" /* Needed for the externs */
41 #include "chmod.h"
42 #include "main.h"
43 #include "achown.h"
45 #define BX 5
46 #define BY 6
48 #define TX 50
49 #define TY 2
51 #define BUTTONS 9
53 #define B_SETALL B_USER
54 #define B_SKIP (B_USER + 1)
56 #define B_OWN (B_USER + 3)
57 #define B_GRP (B_USER + 4)
58 #define B_OTH (B_USER + 5)
59 #define B_OUSER (B_USER + 6)
60 #define B_OGROUP (B_USER + 7)
62 static struct Dlg_head *ch_dlg;
64 static struct {
65 int ret_cmd, flags, y, x;
66 char *text;
67 } chown_advanced_but [BUTTONS] = {
68 { B_CANCEL, NORMAL_BUTTON, 4, 53, N_("&Cancel") },
69 { B_ENTER, DEFPUSH_BUTTON,4, 40, N_("&Set") },
70 { B_SKIP, NORMAL_BUTTON, 4, 23, N_("S&kip") },
71 { B_SETALL, NORMAL_BUTTON, 4, 0, N_("Set &all")},
72 { B_ENTER, NARROW_BUTTON, 0, 47, " "},
73 { B_ENTER, NARROW_BUTTON, 0, 29, " "},
74 { B_ENTER, NARROW_BUTTON, 0, 19, " "},
75 { B_ENTER, NARROW_BUTTON, 0, 11, " "},
76 { B_ENTER, NARROW_BUTTON, 0, 3, " "},
79 static WButton *b_att[3]; /* permission */
80 static WButton *b_user, *b_group; /* owner */
82 static int files_on_begin; /* Number of files at startup */
83 static int flag_pos;
84 static int x_toggle;
85 static char ch_flags[11];
86 static const char ch_perm[] = "rwx";
87 static umode_t ch_cmode;
88 static struct stat *sf_stat;
89 static int need_update;
90 static int end_chown;
91 static int current_file;
92 static int single_set;
93 static char *fname;
95 static void get_ownership (void)
96 { /* set buttons - ownership */
97 char *name_t;
99 name_t = name_trunc (get_owner (sf_stat->st_uid), 15);
100 memset (b_user->text, ' ', 15);
101 strncpy (b_user->text, name_t, strlen (name_t));
102 name_t = name_trunc (get_group (sf_stat->st_gid), 15);
103 memset (b_group->text, ' ', 15);
104 strncpy (b_group->text, name_t, strlen (name_t));
108 static int inc_flag_pos (int f_pos)
110 if (flag_pos == 10) {
111 flag_pos = 0;
112 return MSG_NOT_HANDLED;
114 flag_pos++;
115 if (!(flag_pos % 3) || f_pos > 2)
116 return MSG_NOT_HANDLED;
117 return MSG_HANDLED;
120 static cb_ret_t dec_flag_pos (int f_pos)
122 if (!flag_pos) {
123 flag_pos = 10;
124 return MSG_NOT_HANDLED;
126 flag_pos--;
127 if (!((flag_pos + 1) % 3) || f_pos > 2)
128 return MSG_NOT_HANDLED;
129 return MSG_HANDLED;
132 static void set_perm_by_flags (char *s, int f_p)
134 int i;
136 for (i = 0; i < 3; i++) {
137 if (ch_flags[f_p + i] == '+')
138 s[i] = ch_perm[i];
139 else if (ch_flags[f_p + i] == '-')
140 s[i] = '-';
141 else
142 s[i] = (ch_cmode & (1 << (8 - f_p - i))) ? ch_perm[i] : '-';
146 static umode_t get_perm (char *s, int base)
148 umode_t m;
150 m = 0;
151 m |= (s [0] == '-') ? 0 :
152 ((s[0] == '+') ? (1 << (base + 2)) : (1 << (base + 2)) & ch_cmode);
154 m |= (s [1] == '-') ? 0 :
155 ((s[1] == '+') ? (1 << (base + 1)) : (1 << (base + 1)) & ch_cmode);
157 m |= (s [2] == '-') ? 0 :
158 ((s[2] == '+') ? (1 << base) : (1 << base) & ch_cmode);
160 return m;
163 static umode_t get_mode (void)
165 umode_t m;
167 m = ch_cmode ^ (ch_cmode & 0777);
168 m |= get_perm (ch_flags, 6);
169 m |= get_perm (ch_flags + 3, 3);
170 m |= get_perm (ch_flags + 6, 0);
172 return m;
175 static void print_flags (void)
177 int i;
179 attrset (COLOR_NORMAL);
181 for (i = 0; i < 3; i++){
182 dlg_move (ch_dlg, BY+1, 9+i);
183 addch (ch_flags [i]);
186 for (i = 0; i < 3; i++){
187 dlg_move (ch_dlg, BY + 1, 17 + i);
188 addch (ch_flags [i+3]);
191 for (i = 0; i < 3; i++){
192 dlg_move (ch_dlg, BY + 1, 25 + i);
193 addch (ch_flags [i+6]);
196 set_perm_by_flags (b_att[0]->text, 0);
197 set_perm_by_flags (b_att[1]->text, 3);
198 set_perm_by_flags (b_att[2]->text, 6);
200 for (i = 0; i < 15; i++){
201 dlg_move (ch_dlg, BY+1, 35+i);
202 addch (ch_flags[9]);
204 for (i = 0; i < 15; i++){
205 dlg_move (ch_dlg, BY + 1, 53 + i);
206 addch (ch_flags[10]);
210 static void update_mode (Dlg_head * h)
212 print_flags ();
213 attrset (COLOR_NORMAL);
214 dlg_move (h, BY + 2, 9);
215 printw ("%12o", get_mode ());
216 send_message (h->current, WIDGET_FOCUS, 0);
219 static cb_ret_t
220 chl_callback (Dlg_head *h, dlg_msg_t msg, int parm)
222 switch (msg) {
223 case DLG_KEY:
224 switch (parm) {
225 case KEY_LEFT:
226 case KEY_RIGHT:
227 h->ret_value = parm;
228 dlg_stop (h);
231 default:
232 return default_dlg_callback (h, msg, parm);
236 static void
237 do_enter_key (Dlg_head * h, int f_pos)
239 Dlg_head *chl_dlg;
240 WListbox *chl_list;
241 struct passwd *chl_pass;
242 struct group *chl_grp;
243 WLEntry *fe;
244 int lxx, lyy, chl_end, b_pos;
245 int is_owner;
246 char *title;
248 do {
249 is_owner = (f_pos == 3);
250 title = is_owner ? _("owner") : _("group");
252 lxx = (COLS - 74) / 2 + (is_owner ? 35 : 53);
253 lyy = (LINES - 13) / 2;
254 chl_end = 0;
256 chl_dlg =
257 create_dlg (lyy, lxx, 13, 17, dialog_colors, chl_callback,
258 "[Advanced Chown]", title, DLG_COMPACT | DLG_REVERSE);
260 /* get new listboxes */
261 chl_list = listbox_new (1, 1, 15, 11, NULL);
263 listbox_add_item (chl_list, 0, 0, "<Unknown>", NULL);
265 if (is_owner) {
266 /* get and put user names in the listbox */
267 setpwent ();
268 while ((chl_pass = getpwent ()))
269 listbox_add_item (chl_list, 0, 0, chl_pass->pw_name, NULL);
270 endpwent ();
271 fe = listbox_search_text (chl_list,
272 get_owner (sf_stat->st_uid));
273 } else {
274 /* get and put group names in the listbox */
275 setgrent ();
276 while ((chl_grp = getgrent ())) {
277 listbox_add_item (chl_list, 0, 0, chl_grp->gr_name, NULL);
279 endgrent ();
280 fe = listbox_search_text (chl_list,
281 get_group (sf_stat->st_gid));
284 if (fe)
285 listbox_select_entry (chl_list, fe);
287 b_pos = chl_list->pos;
288 add_widget (chl_dlg, chl_list);
290 run_dlg (chl_dlg);
292 if (b_pos != chl_list->pos) {
293 int ok = 0;
294 if (is_owner) {
295 chl_pass = getpwnam (chl_list->current->text);
296 if (chl_pass) {
297 ok = 1;
298 sf_stat->st_uid = chl_pass->pw_uid;
300 } else {
301 chl_grp = getgrnam (chl_list->current->text);
302 if (chl_grp) {
303 sf_stat->st_gid = chl_grp->gr_gid;
304 ok = 1;
307 if (ok) {
308 ch_flags[f_pos + 6] = '+';
309 get_ownership ();
311 dlg_focus (h);
312 if (ok)
313 print_flags ();
315 if (chl_dlg->ret_value == KEY_LEFT) {
316 if (!is_owner)
317 chl_end = 1;
318 dlg_one_up (ch_dlg);
319 f_pos--;
320 } else if (chl_dlg->ret_value == KEY_RIGHT) {
321 if (is_owner)
322 chl_end = 1;
323 dlg_one_down (ch_dlg);
324 f_pos++;
326 /* Here we used to redraw the window */
327 destroy_dlg (chl_dlg);
328 } while (chl_end);
331 static void chown_refresh (void)
333 common_dialog_repaint (ch_dlg);
335 attrset (COLOR_NORMAL);
337 dlg_move (ch_dlg, BY - 1, 8);
338 addstr (_("owner"));
339 dlg_move (ch_dlg, BY - 1, 16);
340 addstr (_("group"));
341 dlg_move (ch_dlg, BY - 1, 24);
342 addstr (_("other"));
344 dlg_move (ch_dlg, BY - 1, 35);
345 addstr (_("owner"));
346 dlg_move (ch_dlg, BY - 1, 53);
347 addstr (_("group"));
349 dlg_move (ch_dlg, 3, 4);
350 addstr (_("On"));
351 dlg_move (ch_dlg, BY + 1, 4);
352 addstr (_("Flag"));
353 dlg_move (ch_dlg, BY + 2, 4);
354 addstr (_("Mode"));
356 if (!single_set){
357 dlg_move (ch_dlg, 3, 54);
358 printw (_("%6d of %d"), files_on_begin - (current_panel->marked) + 1,
359 files_on_begin);
362 print_flags ();
365 static void chown_info_update (void)
367 /* display file info */
368 attrset (COLOR_NORMAL);
370 /* name && mode */
371 dlg_move (ch_dlg, 3, 8);
372 printw ("%s", name_trunc (fname, 45));
373 dlg_move (ch_dlg, BY + 2, 9);
374 printw ("%12o", get_mode ());
376 /* permissions */
377 set_perm_by_flags (b_att[0]->text, 0);
378 set_perm_by_flags (b_att[1]->text, 3);
379 set_perm_by_flags (b_att[2]->text, 6);
382 static void b_setpos (int f_pos) {
383 b_att[0]->hotpos=-1;
384 b_att[1]->hotpos=-1;
385 b_att[2]->hotpos=-1;
386 b_att[f_pos]->hotpos = (flag_pos % 3);
389 static cb_ret_t
390 advanced_chown_callback (Dlg_head *h, dlg_msg_t msg, int parm)
392 int i = 0, f_pos = BUTTONS - h->current->dlg_id - single_set - 1;
394 switch (msg) {
395 case DLG_DRAW:
396 chown_refresh ();
397 chown_info_update ();
398 return MSG_HANDLED;
400 case DLG_POST_KEY:
401 if (f_pos < 3)
402 b_setpos (f_pos);
403 return MSG_HANDLED;
405 case DLG_FOCUS:
406 if (f_pos < 3) {
407 if ((flag_pos / 3) != f_pos)
408 flag_pos = f_pos * 3;
409 b_setpos (f_pos);
410 } else if (f_pos < 5)
411 flag_pos = f_pos + 6;
412 return MSG_HANDLED;
414 case DLG_KEY:
415 switch (parm) {
417 case XCTRL ('b'):
418 case KEY_LEFT:
419 if (f_pos < 5)
420 return (dec_flag_pos (f_pos));
421 break;
423 case XCTRL ('f'):
424 case KEY_RIGHT:
425 if (f_pos < 5)
426 return (inc_flag_pos (f_pos));
427 break;
429 case ' ':
430 if (f_pos < 3)
431 return MSG_HANDLED;
432 break;
434 case '\n':
435 case KEY_ENTER:
436 if (f_pos <= 2 || f_pos >= 5)
437 break;
438 do_enter_key (h, f_pos);
439 return MSG_HANDLED;
441 case ALT ('x'):
442 i++;
444 case ALT ('w'):
445 i++;
447 case ALT ('r'):
448 parm = i + 3;
449 for (i = 0; i < 3; i++)
450 ch_flags[i * 3 + parm - 3] =
451 (x_toggle & (1 << parm)) ? '-' : '+';
452 x_toggle ^= (1 << parm);
453 update_mode (h);
454 dlg_broadcast_msg (h, WIDGET_DRAW, 0);
455 send_message (h->current, WIDGET_FOCUS, 0);
456 break;
458 case XCTRL ('x'):
459 i++;
461 case XCTRL ('w'):
462 i++;
464 case XCTRL ('r'):
465 parm = i;
466 for (i = 0; i < 3; i++)
467 ch_flags[i * 3 + parm] =
468 (x_toggle & (1 << parm)) ? '-' : '+';
469 x_toggle ^= (1 << parm);
470 update_mode (h);
471 dlg_broadcast_msg (h, WIDGET_DRAW, 0);
472 send_message (h->current, WIDGET_FOCUS, 0);
473 break;
475 case 'x':
476 i++;
478 case 'w':
479 i++;
481 case 'r':
482 if (f_pos > 2)
483 break;
484 flag_pos = f_pos * 3 + i; /* (strchr(ch_perm,parm)-ch_perm); */
485 if (((WButton *) h->current)->text[(flag_pos % 3)] ==
486 '-')
487 ch_flags[flag_pos] = '+';
488 else
489 ch_flags[flag_pos] = '-';
490 update_mode (h);
491 break;
493 case '4':
494 i++;
496 case '2':
497 i++;
499 case '1':
500 if (f_pos > 2)
501 break;
502 flag_pos = i + f_pos * 3;
503 ch_flags[flag_pos] = '=';
504 update_mode (h);
505 break;
507 case '-':
508 if (f_pos > 2)
509 break;
511 case '*':
512 if (parm == '*')
513 parm = '=';
515 case '=':
516 case '+':
517 if (f_pos > 4)
518 break;
519 ch_flags[flag_pos] = parm;
520 update_mode (h);
521 advanced_chown_callback (h, KEY_RIGHT, DLG_KEY);
522 if (flag_pos > 8 || !(flag_pos % 3))
523 dlg_one_down (h);
525 break;
527 return MSG_NOT_HANDLED;
529 default:
530 return default_dlg_callback (h, msg, parm);
534 static void
535 init_chown_advanced (void)
537 int i;
539 sf_stat = g_new (struct stat, 1);
540 do_refresh ();
541 end_chown = need_update = current_file = 0;
542 single_set = (current_panel->marked < 2) ? 2 : 0;
543 memset (ch_flags, '=', 11);
544 flag_pos = 0;
545 x_toggle = 070;
547 ch_dlg =
548 create_dlg (0, 0, 13, 74, dialog_colors, advanced_chown_callback,
549 "[Advanced Chown]", _(" Chown advanced command "),
550 DLG_CENTER | DLG_REVERSE);
552 #define XTRACT(i) BY+chown_advanced_but[i].y, BX+chown_advanced_but[i].x, \
553 chown_advanced_but[i].ret_cmd, chown_advanced_but[i].flags, \
554 (chown_advanced_but[i].text), 0
556 for (i = 0; i < BUTTONS - 5; i++)
557 if (!single_set || i < 2)
558 add_widget (ch_dlg, button_new (XTRACT (i)));
560 b_att[0] = button_new (XTRACT (8));
561 b_att[1] = button_new (XTRACT (7));
562 b_att[2] = button_new (XTRACT (6));
563 b_user = button_new (XTRACT (5));
564 b_group = button_new (XTRACT (4));
566 add_widget (ch_dlg, b_group);
567 add_widget (ch_dlg, b_user);
568 add_widget (ch_dlg, b_att[2]);
569 add_widget (ch_dlg, b_att[1]);
570 add_widget (ch_dlg, b_att[0]);
573 static void
574 chown_advanced_done (void)
576 g_free (sf_stat);
577 if (need_update)
578 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
579 repaint_screen ();
582 #if 0
583 static inline void do_chown (uid_t u, gid_t g)
585 chown (current_panel->dir.list[current_file].fname, u, g);
586 file_mark (current_panel, current_file, 0);
588 #endif
590 static char *next_file (void)
592 while (!current_panel->dir.list[current_file].f.marked)
593 current_file++;
595 return current_panel->dir.list[current_file].fname;
598 static void apply_advanced_chowns (struct stat *sf)
600 char *fname;
601 gid_t a_gid = sf->st_gid;
602 uid_t a_uid = sf->st_uid;
604 fname = current_panel->dir.list[current_file].fname;
605 need_update = end_chown = 1;
606 if (mc_chmod (fname, get_mode ()) == -1)
607 message (1, MSG_ERROR, _(" Cannot chmod \"%s\" \n %s "),
608 fname, unix_error_string (errno));
609 /* call mc_chown only, if mc_chmod didn't fail */
610 else if (mc_chown (fname, (ch_flags[9] == '+') ? sf->st_uid : -1,
611 (ch_flags[10] == '+') ? sf->st_gid : -1) == -1)
612 message (1, MSG_ERROR, _(" Cannot chown \"%s\" \n %s "),
613 fname, unix_error_string (errno));
614 do_file_mark (current_panel, current_file, 0);
616 do {
617 fname = next_file ();
619 if (mc_stat (fname, sf) != 0)
620 break;
621 ch_cmode = sf->st_mode;
622 if (mc_chmod (fname, get_mode ()) == -1)
623 message (1, MSG_ERROR, _(" Cannot chmod \"%s\" \n %s "),
624 fname, unix_error_string (errno));
625 /* call mc_chown only, if mc_chmod didn't fail */
626 else if (mc_chown (fname, (ch_flags[9] == '+') ? a_uid : -1, (ch_flags[10] == '+') ? a_gid : -1) == -1)
627 message (1, MSG_ERROR, _(" Cannot chown \"%s\" \n %s "),
628 fname, unix_error_string (errno));
630 do_file_mark (current_panel, current_file, 0);
631 } while (current_panel->marked);
634 void
635 chown_advanced_cmd (void)
638 files_on_begin = current_panel->marked;
640 do { /* do while any files remaining */
641 init_chown_advanced ();
643 if (current_panel->marked)
644 fname = next_file (); /* next marked file */
645 else
646 fname = selection (current_panel)->fname; /* single file */
648 if (mc_stat (fname, sf_stat) != 0) { /* get status of file */
649 destroy_dlg (ch_dlg);
650 break;
652 ch_cmode = sf_stat->st_mode;
654 chown_refresh ();
656 get_ownership ();
658 /* game can begin */
659 run_dlg (ch_dlg);
661 switch (ch_dlg->ret_value) {
662 case B_CANCEL:
663 end_chown = 1;
664 break;
666 case B_ENTER:
667 need_update = 1;
668 if (mc_chmod (fname, get_mode ()) == -1)
669 message (1, MSG_ERROR, _(" Cannot chmod \"%s\" \n %s "),
670 fname, unix_error_string (errno));
671 /* call mc_chown only, if mc_chmod didn't fail */
672 else if (mc_chown (fname, (ch_flags[9] == '+') ? sf_stat->st_uid : -1, (ch_flags[10] == '+') ? sf_stat->st_gid : -1) == -1)
673 message (1, MSG_ERROR, _(" Cannot chown \"%s\" \n %s "),
674 fname, unix_error_string (errno));
675 break;
676 case B_SETALL:
677 apply_advanced_chowns (sf_stat);
678 break;
680 case B_SKIP:
681 break;
685 if (current_panel->marked && ch_dlg->ret_value != B_CANCEL) {
686 do_file_mark (current_panel, current_file, 0);
687 need_update = 1;
689 destroy_dlg (ch_dlg);
690 } while (current_panel->marked && !end_chown);
692 chown_advanced_done ();