Fix inconsistent formatting and other trails of GreatLord's fixing
[reactos.git] / rosapps / mc / src / cmd.c
1 /* Routines invoked by a function key
2 They normally operate on the current panel.
3
4 Copyright (C) 1994, 1995 Miguel de Icaza
5 Copyright (C) 1994, 1995 Janne Kukonlehto
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #include <config.h>
22 #ifdef __os2__
23 # define INCL_DOSFILEMGR
24 # define INCL_DOSMISC
25 # define INCL_DOSERROR
26 #endif
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include "tty.h"
31 #include <stdio.h>
32 #include <stdlib.h> /* getenv (), rand */
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/stat.h>
36 #if defined(_MSC_VER)
37 #include <sys/time.h___>
38 #else
39 #include <time.h>
40 #endif
41 #include <malloc.h>
42 #include <string.h>
43 #include <fcntl.h> /* open, O_RDWR */
44 #include <errno.h>
45
46 #ifdef OS2_NT
47 # include <io.h>
48 #endif
49
50 #ifdef USE_NETCODE
51 #include <netdb.h>
52 #endif
53
54 #ifdef HAVE_MMAP
55 # include <sys/mman.h>
56 #endif
57 #include "mad.h"
58 #include "dir.h"
59 #include "util.h"
60 #include "panel.h"
61 #include "cmd.h" /* Our definitions */
62 #include "view.h" /* view() */
63 #include "dialog.h" /* query_dialog, message */
64 #include "file.h" /* the file operations */
65 #include "find.h" /* do_find */
66 #include "hotlist.h"
67 #include "tree.h"
68 #include "subshell.h" /* use_subshell */
69 #include "cons.saver.h"
70 #include "global.h"
71 #include "dlg.h" /* required by wtools.h */
72 #include "widget.h" /* required by wtools.h */
73 #include "wtools.h" /* listbox */
74 #include "command.h" /* for input_w */
75 #include "win.h" /* do_exit_ca_mode */
76 #include "layout.h" /* get_current/other_type */
77 #include "ext.h" /* regex_command */
78 #include "view.h" /* view */
79 #include "key.h" /* get_key_code */
80 #include "help.h" /* interactive_display */
81 #include "fs.h"
82 #include "boxes.h" /* cd_dialog */
83 #include "color.h"
84 #include "user.h"
85 #include "setup.h"
86 #include "x.h"
87 #include "profile.h"
88
89 #define MIDNIGHT
90 #ifdef USE_INTERNAL_EDIT
91 extern int edit (const char *file, int line);
92 #endif
93 #include "../vfs/vfs.h"
94 #define WANT_WIDGETS
95 #include "main.h" /* global variables, global functions */
96 #ifndef MAP_FILE
97 # define MAP_FILE 0
98 #endif
99
100 #ifdef HAVE_TK
101 # include "tkscreen.h"
102 #endif
103
104 /* If set and you don't have subshell support,then C-o will give you a shell */
105 int output_starts_shell = 0;
106
107 /* Source routing destination */
108 int source_route = 0;
109
110 /* If set, use the builtin editor */
111 int use_internal_edit = 1;
112
113 /* Ugly hack in order to distinguish between left and right panel in menubar */
114 int is_right;
115 #define MENU_PANEL_IDX (is_right ? 1 : 0)
116
117
118 #ifndef PORT_HAS_FILTER_CHANGED
119 # define x_filter_changed(p)
120 #endif
121
122 /* This is used since the parameter panel on some of the commands */
123 /* defined in this file may receive a 0 parameter if they are invoked */
124 /* The drop down menu */
125
126 WPanel *get_a_panel (WPanel *panel)
127 {
128 if (panel)
129 return panel;
130 if (get_current_type () == view_listing){
131 return cpanel;
132 } else
133 return other_panel;
134 }
135
136 /* view_file (filename, normal, internal)
137 *
138 * Inputs:
139 * filename: The file name to view
140 * plain_view: If set does not do any fancy pre-processing (no filtering) and
141 * always invokes the internal viewer.
142 * internal: If set uses the internal viewer, otherwise an external viewer.
143 */
144 int view_file_at_line (char *filename, int plain_view, int internal, int start_line)
145 {
146 static char *viewer = 0;
147 int move_dir = 0;
148
149
150 if (plain_view) {
151 int changed_hex_mode = 0;
152 int changed_nroff_flag = 0;
153 int changed_magic_flag = 0;
154
155 altered_hex_mode = 0;
156 altered_nroff_flag = 0;
157 altered_magic_flag = 0;
158 if (default_hex_mode)
159 changed_hex_mode = 1;
160 if (default_nroff_flag)
161 changed_nroff_flag = 1;
162 if (default_magic_flag)
163 changed_magic_flag = 1;
164 default_hex_mode = 0;
165 default_nroff_flag = 0;
166 default_magic_flag = 0;
167 view (0, filename, &move_dir, start_line);
168 if (changed_hex_mode && !altered_hex_mode)
169 default_hex_mode = 1;
170 if (changed_nroff_flag && !altered_nroff_flag)
171 default_nroff_flag = 1;
172 if (changed_magic_flag && !altered_magic_flag)
173 default_magic_flag = 1;
174 repaint_screen ();
175 return move_dir;
176 }
177 if (internal){
178 char view_entry [32];
179
180 if (start_line != 0)
181 sprintf (view_entry, "View:%d", start_line);
182 else
183 strcpy (view_entry, "View");
184
185 if (!regex_command (filename, view_entry, NULL, &move_dir)){
186 view (0, filename, &move_dir, start_line);
187 repaint_screen ();
188 }
189 } else {
190 char *localcopy;
191
192 if (!viewer){
193 viewer = getenv ("PAGER");
194 if (!viewer)
195 viewer = "view";
196 }
197 /* The file may be a non local file, get a copy */
198 if (!vfs_file_is_local (filename)){
199 localcopy = mc_getlocalcopy (filename);
200 if (localcopy == NULL){
201 message (1, MSG_ERROR, _(" Can not fetch a local copy of %s "), filename);
202 return 0;
203 }
204 execute_internal (viewer, localcopy);
205 mc_ungetlocalcopy (filename, localcopy, 0);
206 } else
207 execute_internal (viewer, filename);
208 }
209 return move_dir;
210 }
211
212 int
213 view_file (char *filename, int plain_view, int internal)
214 {
215 return view_file_at_line (filename, plain_view, internal, 0);
216 }
217
218 /* scan_for_file (panel, idx, direction)
219 *
220 * Inputs:
221 * panel: pointer to the panel on which we operate
222 * idx: starting file.
223 * direction: 1, or -1
224 */
225 static int scan_for_file (WPanel *panel, int idx, int direction)
226 {
227 int i = idx + direction;
228
229 while (i != idx){
230 if (i < 0)
231 i = panel->count - 1;
232 if (i == panel->count)
233 i = 0;
234 if (!S_ISDIR (panel->dir.list [i].buf.st_mode))
235 return i;
236 i += direction;
237 }
238 return i;
239 }
240
241 /* do_view: Invoked as the F3/F13 key. */
242 static void do_view_cmd (WPanel *panel, int normal)
243 {
244 int dir, file_idx;
245 panel = get_a_panel (panel);
246
247 /* Directories are viewed by changing to them */
248 if (S_ISDIR (selection (panel)->buf.st_mode) ||
249 link_isdir (selection (panel))){
250 if (confirm_view_dir && (panel->marked || panel->dirs_marked)){
251 if (query_dialog (_(" CD "), _("Files tagged, want to cd?"),
252 0, 2, _("&Yes"), _("&No")) == 1){
253 return;
254 }
255 }
256 do_cd (selection (panel)->fname, cd_exact);
257 return;
258
259 }
260
261 file_idx = panel->selected;
262 while (1) {
263 char *filename;
264
265 filename = panel->dir.list [file_idx].fname;
266
267 dir = view_file (filename, normal, use_internal_view);
268 if (dir == 0)
269 break;
270 file_idx = scan_for_file (panel, file_idx, dir);
271 }
272 }
273
274 void view_cmd (WPanel *panel)
275 {
276 do_view_cmd (panel, 0);
277 }
278
279 void view_simple_cmd (WPanel *panel)
280 {
281 do_view_cmd (panel, 1);
282 }
283
284 void filtered_view_cmd (WPanel *panel)
285 {
286 char *command;
287
288 panel = get_a_panel (panel);
289 command = input_dialog (_(" Filtered view "), _(" Filter command and arguments:"),
290 selection (panel)->fname);
291 if (!command)
292 return;
293
294 view (command, "", 0, 0);
295
296 free (command);
297 }
298
299 void filtered_view_cmd_cpanel (void)
300 {
301 filtered_view_cmd (cpanel);
302 }
303
304 void do_edit_at_line (const char *what, int start_line)
305 {
306 static char *editor = 0;
307
308 #ifdef USE_INTERNAL_EDIT
309 if (use_internal_edit){
310 edit (what, start_line);
311 reread_cmd ();
312 return;
313 }
314 #endif
315 if (!editor){
316 editor = getenv ("EDITOR");
317 if (!editor)
318 editor = get_default_editor ();
319 }
320 execute_internal (editor, what);
321 reread_cmd ();
322 }
323
324 void
325 do_edit (const char *what)
326 {
327 do_edit_at_line (what, 1);
328 }
329
330 void edit_cmd (WPanel *panel)
331 {
332 panel = get_a_panel(panel);
333 if (!regex_command (selection (panel)->fname, "Edit", NULL, 0))
334 do_edit (selection (panel)->fname);
335 }
336
337 void edit_cmd_new (WPanel *panel)
338 {
339 do_edit ("");
340 }
341
342 void copy_cmd (void)
343 {
344 save_cwds_stat ();
345 if (panel_operate (cpanel, OP_COPY, NULL)){
346 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
347 repaint_screen ();
348 }
349 }
350
351 void ren_cmd (void)
352 {
353 save_cwds_stat ();
354 if (panel_operate (cpanel, OP_MOVE, NULL)){
355 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
356 repaint_screen ();
357 }
358 }
359
360 void copymove_cmd_with_default (int copy, char *thedefault)
361 {
362 save_cwds_stat ();
363 if (panel_operate (cpanel, copy ? OP_COPY : OP_MOVE, thedefault)){
364 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
365 repaint_screen ();
366 }
367 }
368
369 void mkdir_cmd (WPanel *panel)
370 {
371 char *dir;
372
373 panel = get_a_panel (panel);
374 dir = input_expand_dialog (_(" Mkdir "), _(" Enter directory name:") , "");
375
376 if (!dir)
377 return;
378
379 save_cwds_stat ();
380 if (my_mkdir (dir, 0777) == 0){
381 update_panels (UP_OPTIMIZE, dir);
382 repaint_screen ();
383 select_item (cpanel);
384 free (dir);
385 return;
386 }
387 free (dir);
388 message (1, MSG_ERROR, " %s ", unix_error_string (errno));
389 }
390
391 void delete_cmd (void)
392 {
393 save_cwds_stat ();
394
395 if (panel_operate (cpanel, OP_DELETE, NULL)){
396 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
397 repaint_screen ();
398 }
399 }
400
401 void find_cmd (void)
402 {
403 do_find ();
404 }
405
406 void
407 set_panel_filter_to (WPanel *p, char *allocated_filter_string)
408 {
409 if (p->filter){
410 free (p->filter);
411 p->filter = 0;
412 }
413 if (!(allocated_filter_string [0] == '*' && allocated_filter_string [1] == 0))
414 p->filter = allocated_filter_string;
415 else
416 free (allocated_filter_string);
417 reread_cmd ();
418 x_filter_changed (p);
419 }
420
421 /* Set a given panel filter expression */
422 void set_panel_filter (WPanel *p)
423 {
424 char *reg_exp;
425 char *x;
426
427 x = p->filter ? p->filter : easy_patterns ? "*" : ".";
428
429 reg_exp = input_dialog (_(" Filter "), _(" Set expression for filtering filenames"), x);
430 if (!reg_exp)
431 return;
432 set_panel_filter_to (p, reg_exp);
433 }
434
435 /* Invoked from the left/right menus */
436 void filter_cmd (void)
437 {
438 WPanel *p;
439
440 if (!SELECTED_IS_PANEL)
441 return;
442
443 p = MENU_PANEL;
444 set_panel_filter (p);
445 }
446
447 void reread_cmd (void)
448 {
449 int flag;
450
451 mad_check (__FILE__, __LINE__);
452 if (get_current_type () == view_listing &&
453 get_other_type () == view_listing)
454 flag = strcmp (cpanel->cwd, opanel->cwd) ? UP_ONLY_CURRENT : 0;
455 else
456 flag = UP_ONLY_CURRENT;
457
458 update_panels (UP_RELOAD|flag, UP_KEEPSEL);
459 repaint_screen ();
460 }
461
462 /* Panel sorting related routines */
463 void do_re_sort (WPanel *panel)
464 {
465 char *filename;
466 int i;
467
468 panel = get_a_panel (panel);
469 filename = strdup (selection (cpanel)->fname);
470 unselect_item (panel);
471 do_sort (&panel->dir, panel->sort_type, panel->count-1, panel->reverse, panel->case_sensitive);
472 panel->selected = -1;
473 for (i = panel->count; i; i--){
474 if (!strcmp (panel->dir.list [i-1].fname, filename)){
475 panel->selected = i-1;
476 break;
477 }
478 }
479 free (filename);
480 cpanel->top_file = cpanel->selected - ITEMS (cpanel)/2;
481 if (cpanel->top_file < 0)
482 cpanel->top_file = 0;
483 select_item (panel);
484 panel_update_contents (panel);
485 }
486
487 void reverse_selection_cmd_panel (WPanel *panel)
488 {
489 file_entry *file;
490 int i;
491
492 for (i = 0; i < panel->count; i++){
493 file = &panel->dir.list [i];
494 if (S_ISDIR (file->buf.st_mode))
495 continue;
496 do_file_mark (panel, i, !file->f.marked);
497 }
498 paint_panel (panel);
499 }
500
501 void reverse_selection_cmd (void)
502 {
503 reverse_selection_cmd_panel (cpanel);
504 }
505
506 void select_cmd_panel (WPanel *panel)
507 {
508 char *reg_exp, *reg_exp_t;
509 int i;
510 int c;
511 int dirflag = 0;
512
513 reg_exp = input_dialog (_(" Select "), "", easy_patterns ? "*" : ".");
514 if (!reg_exp)
515 return;
516
517 reg_exp_t = reg_exp;
518
519 /* Check if they specified a directory */
520 if (*reg_exp_t == PATH_SEP){
521 dirflag = 1;
522 reg_exp_t++;
523 }
524 if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
525 dirflag = 1;
526 reg_exp_t [strlen(reg_exp_t) - 1] = 0;
527 }
528
529 for (i = 0; i < panel->count; i++){
530 if (!strcmp (panel->dir.list [i].fname, ".."))
531 continue;
532 if (S_ISDIR (panel->dir.list [i].buf.st_mode)){
533 if (!dirflag)
534 continue;
535 } else {
536 if (dirflag)
537 continue;
538 }
539 c = regexp_match (reg_exp_t, panel->dir.list [i].fname, match_file);
540 if (c == -1){
541 message (1, MSG_ERROR, _(" Malformed regular expression "));
542 free (reg_exp);
543 return;
544 }
545 if (c){
546 do_file_mark (panel, i, 1);
547 }
548 }
549 paint_panel (panel);
550 free (reg_exp);
551 }
552
553 void select_cmd (void)
554 {
555 select_cmd_panel (cpanel);
556 }
557
558 void unselect_cmd_panel (WPanel *panel)
559 {
560 char *reg_exp, *reg_exp_t;
561 int i;
562 int c;
563 int dirflag = 0;
564
565 reg_exp = input_dialog (_(" Unselect "),"", easy_patterns ? "*" : ".");
566 if (!reg_exp)
567 return;
568
569 reg_exp_t = reg_exp;
570
571 /* Check if they specified directory matching */
572 if (*reg_exp_t == PATH_SEP){
573 dirflag = 1;
574 reg_exp_t ++;
575 }
576 if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
577 dirflag = 1;
578 reg_exp_t [strlen(reg_exp_t) - 1] = 0;
579 }
580 for (i = 0; i < panel->count; i++){
581 if (!strcmp (panel->dir.list [i].fname, ".."))
582 continue;
583 if (S_ISDIR (panel->dir.list [i].buf.st_mode)){
584 if (!dirflag)
585 continue;
586 } else {
587 if (dirflag)
588 continue;
589 }
590 c = regexp_match (reg_exp_t, panel->dir.list [i].fname, match_file);
591 if (c == -1){
592 message (1, MSG_ERROR, _(" Malformed regular expression "));
593 free (reg_exp);
594 return;
595 }
596 if (c){
597 do_file_mark (panel, i, 0);
598 }
599 }
600 paint_panel (panel);
601 free (reg_exp);
602 }
603
604 void unselect_cmd (void)
605 {
606 unselect_cmd_panel (cpanel);
607 }
608
609 /* Check if the file exists */
610 /* If not copy the default */
611 static int check_for_default(char *default_file, char *file)
612 {
613 struct stat s;
614 if (mc_stat (file, &s)){
615 if (mc_stat (default_file, &s)){
616 return -1;
617 }
618 create_op_win (OP_COPY, 0);
619 file_mask_defaults ();
620 copy_file_file (default_file, file, 1);
621 destroy_op_win ();
622 }
623 return 0;
624 }
625
626 void ext_cmd (void)
627 {
628 char *buffer;
629 char *extdir;
630 int dir;
631
632 dir = 0;
633 if (geteuid () == 0){
634 dir = query_dialog (_("Extension file edit"),
635 _(" Which extension file you want to edit? "), 0, 2,
636 _("&User"), _("&System Wide"));
637 }
638 extdir = concat_dir_and_file (mc_home, MC_LIB_EXT);
639
640 if (dir == 0){
641 buffer = concat_dir_and_file (home_dir, MC_USER_EXT);
642 check_for_default (extdir, buffer);
643 do_edit (buffer);
644 free (buffer);
645 } else if (dir == 1)
646 do_edit (extdir);
647
648 free (extdir);
649 flush_extension_file ();
650 }
651
652 void menu_edit_cmd (void)
653 {
654 char *buffer;
655 char *menufile;
656 int dir = 0;
657
658 dir = query_dialog (
659 _("Menu file edit"),
660 _(" Which menu file will you edit? "),
661 0, geteuid() ? 2 : 3,
662 _("&Local"), _("&Home"), _("&System Wide")
663 );
664
665 menufile = concat_dir_and_file(mc_home, MC_GLOBAL_MENU);
666
667 switch (dir){
668 case 0:
669 buffer = strdup (MC_LOCAL_MENU);
670 check_for_default (menufile, buffer);
671 break;
672
673 case 1:
674 buffer = concat_dir_and_file (home_dir, MC_HOME_MENU);
675 check_for_default (menufile, buffer);
676 break;
677
678 case 2:
679 buffer = concat_dir_and_file (mc_home, MC_GLOBAL_MENU);
680 break;
681
682 default:
683 free (menufile);
684 return;
685 }
686 do_edit (buffer);
687 if (dir == 0)
688 chmod(buffer, 0600);
689 free (buffer);
690 free (menufile);
691 }
692
693 void quick_chdir_cmd (void)
694 {
695 char *target;
696
697 target = hotlist_cmd (LIST_HOTLIST);
698 if (!target)
699 return;
700
701 if (get_current_type () == view_tree)
702 tree_chdir (the_tree, target);
703 else
704 do_cd (target, cd_exact);
705 free (target);
706 }
707
708 #ifdef USE_VFS
709 void reselect_vfs (void)
710 {
711 char *target;
712
713 target = hotlist_cmd (LIST_VFSLIST);
714 if (!target)
715 return;
716
717 do_cd (target, cd_exact);
718 free (target);
719 }
720 #endif
721
722 static int compare_files (char *name1, char *name2, long size)
723 {
724 int file1, file2;
725 int result = -1; /* Different by default */
726
727 file1 = open (name1, O_RDONLY);
728 if (file1 >= 0){
729 file2 = open (name2, O_RDONLY);
730 if (file2 >= 0){
731 #ifdef HAVE_MMAP
732 /* Ugly if jungle */
733 data1 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file1, 0);
734 if (data1 != (char*) -1){
735 data2 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file2, 0);
736 if (data2 != (char*) -1){
737 rotate_dash ();
738 result = memcmp (data1, data2, size);
739 munmap (data2, size);
740 }
741 munmap (data1, size);
742 }
743 #else
744 /* Don't have mmap() :( Even more ugly :) */
745 char buf1[BUFSIZ], buf2[BUFSIZ];
746 int n1, n2;
747 rotate_dash ();
748 do
749 {
750 while((n1 = read(file1,buf1,BUFSIZ)) == -1 && errno == EINTR);
751 while((n2 = read(file2,buf2,BUFSIZ)) == -1 && errno == EINTR);
752 } while (n1 == n2 && n1 == BUFSIZ && !memcmp(buf1,buf2,BUFSIZ));
753 result = (n1 != n2) || memcmp(buf1,buf2,n1);
754 #endif
755 close (file2);
756 }
757 close (file1);
758 }
759 return result;
760 }
761
762 enum CompareMode {
763 compare_quick, compare_size_only, compare_thourough
764 };
765
766 static void
767 compare_dir (WPanel *panel, WPanel *other, enum CompareMode mode)
768 {
769 int i, j;
770 char *src_name, *dst_name;
771
772 panel = get_a_panel (panel);
773
774 /* No marks by default */
775 panel->marked = 0;
776 panel->total = 0;
777 panel->dirs_marked = 0;
778
779 /* Handle all files in the panel */
780 for (i = 0; i < panel->count; i++){
781 file_entry *source = &panel->dir.list[i];
782
783 /* Default: unmarked */
784 file_mark (panel, i, 0);
785
786 /* Skip directories */
787 if (S_ISDIR (source->buf.st_mode))
788 continue;
789
790 /* Search the corresponding entry from the other panel */
791 for (j = 0; j < other->count; j++){
792 if (strcmp (source->fname,
793 other->dir.list[j].fname) == 0)
794 break;
795 }
796 if (j >= other->count)
797 /* Not found -> mark */
798 do_file_mark (panel, i, 1);
799 else {
800 /* Found */
801 file_entry *target = &other->dir.list[j];
802
803 if (mode != compare_size_only){
804 /* Older version is not marked */
805 if (source->buf.st_mtime < target->buf.st_mtime)
806 continue;
807 }
808
809 /* Newer version with different size is marked */
810 if (source->buf.st_size != target->buf.st_size){
811 do_file_mark (panel, i, 1);
812 continue;
813
814 }
815 if (mode == compare_size_only)
816 continue;
817
818 if (mode == compare_quick){
819 /* Thorough compare off, compare only time stamps */
820 /* Mark newer version, don't mark version with the same date */
821 if (source->buf.st_mtime > target->buf.st_mtime){
822 do_file_mark (panel, i, 1);
823 }
824 continue;
825 }
826
827 /* Thorough compare on, do byte-by-byte comparison */
828 src_name = get_full_name (panel->cwd, source->fname);
829 dst_name = get_full_name (other->cwd, target->fname);
830 if (compare_files (src_name, dst_name, source->buf.st_size))
831 do_file_mark (panel, i, 1);
832 free (src_name);
833 free (dst_name);
834 }
835 } /* for (i ...) */
836 }
837
838 void compare_dirs_cmd (void)
839 {
840 enum CompareMode thorough_flag = compare_quick;
841
842 thorough_flag = query_dialog (_(" Compare directories "), _(" Select compare method: "),
843 0, 3, _("&Quick"), _("&Size only"), _("&Thorough"), _("&Cancel"));
844 if (thorough_flag < 0 || thorough_flag > 2)
845 return;
846 if (get_current_type () == view_listing &&
847 get_other_type () == view_listing){
848 compare_dir (cpanel, opanel, thorough_flag);
849 compare_dir (opanel, cpanel, thorough_flag);
850 paint_panel (cpanel);
851 paint_panel (opanel);
852 } else {
853 message (1, MSG_ERROR, _(" Both panels should be on the listing view mode to use this command "));
854 }
855 }
856
857 void history_cmd (void)
858 {
859 Listbox *listbox;
860 Hist *current;
861
862 if (input_w (cmdline)->need_push){
863 if (push_history (input_w (cmdline), input_w (cmdline)->buffer) == 2)
864 input_w (cmdline)->need_push = 0;
865 }
866 if (!input_w (cmdline)->history){
867 message (1, MSG_ERROR, _(" The command history is empty "));
868 return;
869 }
870 current = input_w (cmdline)->history;
871 while (current->prev)
872 current = current->prev;
873 listbox = create_listbox_window (60, 10, _(" Command history "),
874 "[Command Menu]");
875 while (current){
876 LISTBOX_APPEND_TEXT (listbox, 0, current->text,
877 current);
878 current = current->next;
879 }
880 run_dlg (listbox->dlg);
881 if (listbox->dlg->ret_value == B_CANCEL)
882 current = NULL;
883 else
884 current = listbox->list->current->data;
885 destroy_dlg (listbox->dlg);
886 free (listbox);
887
888 if (!current)
889 return;
890 input_w (cmdline)->history = current;
891 assign_text (input_w (cmdline), input_w (cmdline)->history->text);
892 update_input (input_w (cmdline), 1);
893 }
894
895 #if !defined(HAVE_XVIEW) && !defined(HAVE_GNOME)
896 void swap_cmd (void)
897 {
898 swap_panels ();
899 touchwin (stdscr);
900 repaint_screen ();
901 }
902 #endif
903
904 void
905 view_other_cmd (void)
906 {
907 static int message_flag = TRUE;
908 #ifdef HAVE_SUBSHELL_SUPPORT
909 char *new_dir = NULL;
910 char **new_dir_p;
911 #endif
912
913 if (!xterm_flag && !console_flag && !use_subshell){
914 if (message_flag)
915 message (1, MSG_ERROR, _(" Not an xterm or Linux console; \n"
916 " the panels cannot be toggled. "));
917 message_flag = FALSE;
918 } else {
919 #ifndef HAVE_X
920 if (use_mouse_p)
921 shut_mouse ();
922 if (clear_before_exec)
923 clr_scr ();
924 if (alternate_plus_minus)
925 numeric_keypad_mode ();
926 #endif
927 #ifndef HAVE_SLANG
928 /* With slang we don't want any of this, since there
929 * is no mc_raw_mode supported
930 */
931 reset_shell_mode ();
932 noecho ();
933 #endif
934 keypad(stdscr, FALSE);
935 endwin ();
936 if (!status_using_ncurses)
937 do_exit_ca_mode ();
938 mc_raw_mode ();
939 if (console_flag)
940 restore_console ();
941
942 #ifdef HAVE_SUBSHELL_SUPPORT
943 if (use_subshell){
944 new_dir_p = vfs_current_is_local () ? &new_dir : NULL;
945 if (invoke_subshell (NULL, VISIBLY, new_dir_p))
946 quiet_quit_cmd(); /* User did `exit' or `logout': quit MC quietly */
947 } else
948 #endif
949 {
950 if (output_starts_shell){
951 fprintf (stderr,
952 _("Type `exit' to return to the Midnight Commander\n\r\n\r"));
953 my_system (EXECUTE_AS_SHELL, shell, NULL);
954 } else
955 get_key_code (0);
956 }
957 if (console_flag)
958 handle_console (CONSOLE_SAVE);
959
960 if (!status_using_ncurses)
961 do_enter_ca_mode ();
962
963 reset_prog_mode ();
964 keypad(stdscr, TRUE);
965 #ifndef HAVE_X
966 if (use_mouse_p)
967 init_mouse ();
968 if (alternate_plus_minus)
969 application_keypad_mode ();
970 #endif
971
972 #ifdef HAVE_SUBSHELL_SUPPORT
973 if (use_subshell){
974 load_prompt (0, 0);
975 if (new_dir)
976 do_possible_cd (new_dir);
977 if (console_flag && output_lines)
978 show_console_contents (output_start_y,
979 LINES-keybar_visible-output_lines-1,
980 LINES-keybar_visible-1);
981 }
982 #endif
983 touchwin (stdscr);
984
985 /* prevent screen flash when user did 'exit' or 'logout' within
986 subshell */
987 if (!quit)
988 repaint_screen ();
989 }
990 }
991
992 #ifndef OS2_NT
993 static void
994 do_link (int symbolic_link, char *fname)
995 {
996 struct stat s;
997 char *dest, *src;
998 int stat_r;
999
1000 if (!symbolic_link){
1001 stat_r = mc_stat (fname, &s);
1002 if (stat_r != 0){
1003 message (1, MSG_ERROR, _(" Couldn't stat %s \n %s "),
1004 fname, unix_error_string (errno));
1005 return;
1006 }
1007 if (!S_ISREG (s.st_mode))
1008 return;
1009 }
1010
1011 if (!symbolic_link){
1012 src = copy_strings (_(" Link "), name_trunc (fname, 46),
1013 _(" to:"), NULL);
1014 dest = input_expand_dialog (_(" Link "), src, "");
1015 free (src);
1016 if (!dest)
1017 return;
1018 if (!*dest) {
1019 free (dest);
1020 return;
1021 }
1022 save_cwds_stat ();
1023 if (-1 == mc_link (fname, dest))
1024 message (1, MSG_ERROR, _(" link: %s "), unix_error_string (errno));
1025 } else {
1026 #ifdef OLD_SYMLINK_VERSION
1027 symlink_dialog (fname, "", &dest, &src);
1028 #else
1029 /* suggest the full path for symlink */
1030 char s[MC_MAXPATHLEN];
1031 char d[MC_MAXPATHLEN];
1032
1033 strcpy(s, cpanel->cwd);
1034 if ( ! ((s[0] == '/') && (s[1] == 0)))
1035 strcat(s, "/");
1036 strcat(s, fname);
1037 if (get_other_type () == view_listing)
1038 strcpy(d, opanel->cwd);
1039 else
1040 strcpy (d,"");
1041
1042 if ( ! ((d[0] == '/') && (d[1] == 0)))
1043 strcat(d, "/");
1044 symlink_dialog (s, d, &dest, &src);
1045 #endif
1046 if (!dest || !*dest) {
1047 if (src)
1048 free (src);
1049 if (dest)
1050 free (dest);
1051 return;
1052 }
1053 if (src){
1054 if (*src) {
1055 save_cwds_stat ();
1056 if (-1 == mc_symlink (dest, src))
1057 message (1, MSG_ERROR, _(" symlink: %s "),
1058 unix_error_string (errno));
1059 }
1060 free (src);
1061 }
1062 }
1063 free (dest);
1064 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1065 repaint_screen ();
1066 }
1067
1068 void link_cmd (void)
1069 {
1070 do_link (0, selection (cpanel)->fname);
1071 }
1072
1073 void symlink_cmd (void)
1074 {
1075 do_link (1, selection (cpanel)->fname);
1076 }
1077
1078 void edit_symlink_cmd (void)
1079 {
1080 if (S_ISLNK (selection (cpanel)->buf.st_mode)) {
1081 char buffer [MC_MAXPATHLEN], *p = selection (cpanel)->fname;
1082 int i;
1083 char *dest, *q = copy_strings (_(" Symlink "), name_trunc (p, 32), _(" points to:"), NULL);
1084
1085 i = readlink (p, buffer, MC_MAXPATHLEN);
1086 if (i > 0) {
1087 buffer [i] = 0;
1088 dest = input_expand_dialog (_(" Edit symlink "), q, buffer);
1089 if (dest) {
1090 if (*dest && strcmp (buffer, dest)) {
1091 save_cwds_stat ();
1092 mc_unlink (p);
1093 if (-1 == mc_symlink (dest, p))
1094 message (1, MSG_ERROR, _(" edit symlink: %s "),
1095 unix_error_string (errno));
1096 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1097 repaint_screen ();
1098 }
1099 free (dest);
1100 }
1101 }
1102 free (q);
1103 }
1104 }
1105
1106 void other_symlink_cmd (void)
1107 {
1108 char *dest, *q, *p, *r, *s, *t;
1109
1110 if (get_other_type () != view_listing)
1111 return;
1112
1113 if (!strcmp (selection (opanel)->fname, ".."))
1114 return;
1115 p = concat_dir_and_file (cpanel->cwd, selection (cpanel)->fname);
1116 r = concat_dir_and_file (opanel->cwd, selection (cpanel)->fname);
1117
1118 q = copy_strings (_(" Link symbolically "), name_trunc (p, 32), _(" to:"), NULL);
1119 dest = input_expand_dialog (_(" Relative symlink "), q, r);
1120 if (dest) {
1121 if (*dest) {
1122 t = strrchr (dest, PATH_SEP);
1123 if (t) {
1124 t[1] = 0;
1125 s = diff_two_paths (dest, p);
1126 t[1] = PATH_SEP;
1127 if (s) {
1128 save_cwds_stat ();
1129 if (-1 == mc_symlink (dest, s))
1130 message (1, MSG_ERROR, _(" relative symlink: %s "),
1131 unix_error_string (errno));
1132 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
1133 repaint_screen ();
1134 free (s);
1135 }
1136 }
1137 }
1138 free (dest);
1139 }
1140 free (q);
1141 free (p);
1142 free (r);
1143 }
1144 #endif
1145
1146 void help_cmd (void)
1147 {
1148 char *hlpfile = concat_dir_and_file (mc_home, "mc.hlp");
1149 interactive_display (hlpfile, "[main]");
1150 free (hlpfile);
1151 }
1152
1153 void view_panel_cmd (void)
1154 {
1155 view_cmd (cpanel);
1156 }
1157
1158 void edit_panel_cmd (void)
1159 {
1160 edit_cmd (cpanel);
1161 }
1162
1163 void mkdir_panel_cmd (void)
1164 {
1165 mkdir_cmd (cpanel);
1166 }
1167
1168 /* Returns a random hint */
1169 char *get_random_hint (void)
1170 {
1171 char *data, *result, *eol;
1172 char *hintfile;
1173 int len;
1174 int start;
1175
1176 /* Do not change hints more often than one minute */
1177
1178 #ifdef SCO_FLAVOR
1179 static time_t last;
1180 time_t now;
1181
1182 time (&now);
1183 if ((now - last) < 60)
1184 return strdup ("");
1185 last = now;
1186 #else
1187 static int last_sec;
1188 static struct timeval tv;
1189
1190 gettimeofday (&tv, NULL);
1191 if (!(tv.tv_sec> last_sec+60))
1192 return strdup ("");
1193 last_sec = tv.tv_sec;
1194 #endif
1195
1196 hintfile = concat_dir_and_file (mc_home, MC_HINT);
1197 data = load_file (hintfile);
1198 free (hintfile);
1199 if (!data)
1200 return 0;
1201
1202 #ifdef SCO_FLAVOR
1203 srand ((short) now);
1204 #else
1205 srand (tv.tv_sec);
1206 #endif
1207 /* get a random entry */
1208 len = strlen (data);
1209 start = rand () % len;
1210
1211 for (;start; start--){
1212 if (data [start] == '\n'){
1213 start++;
1214 break;
1215 }
1216 }
1217 eol = strchr (&data [start], '\n');
1218 if (eol)
1219 *eol = 0;
1220 result = strdup (&data [start]);
1221 free (data);
1222 return result;
1223 }
1224
1225 #ifndef USE_VFS
1226 #ifdef USE_NETCODE
1227 #undef USE_NETCODE
1228 #endif
1229 #endif
1230
1231 #ifdef USE_NETCODE
1232
1233 static char *machine_str = N_(" Enter machine name (F1 for details): ");
1234
1235 static void nice_cd (char *text, char *xtext, char *help, char *prefix, int to_home)
1236 {
1237 char *machine;
1238 char *cd_path;
1239
1240 if (!SELECTED_IS_PANEL)
1241 return;
1242
1243 machine = input_dialog_help (text,
1244 xtext,
1245 help, "");
1246 if (!machine)
1247 return;
1248
1249 if (strncmp (prefix, machine, strlen (prefix)) == 0)
1250 cd_path = copy_strings (machine, to_home ? "/~/" : NULL, NULL);
1251 else
1252 cd_path = copy_strings (prefix, machine, to_home ? "/~/" : NULL, NULL);
1253
1254 if (do_panel_cd (MENU_PANEL, cd_path, 0))
1255 directory_history_add (MENU_PANEL, (MENU_PANEL)->cwd);
1256 else
1257 message (1, MSG_ERROR, N_(" Could not chdir to %s "), cd_path);
1258 free (cd_path);
1259 free (machine);
1260 }
1261
1262 void netlink_cmd (void)
1263 {
1264 nice_cd (_(" Link to a remote machine "), _(machine_str),
1265 "[Network File System]", "mc:", 1);
1266 }
1267
1268 void ftplink_cmd (void)
1269 {
1270 nice_cd (_(" FTP to machine "), _(machine_str),
1271 "[FTP File System]", "ftp://", 1);
1272 }
1273
1274 #ifdef HAVE_SETSOCKOPT
1275 void source_routing (void)
1276 {
1277 char *source;
1278 struct hostent *hp;
1279
1280 source = input_dialog (_(" Socket source routing setup "),
1281 _(" Enter host name to use as a source routing hop: ")n,
1282 "");
1283 if (!source)
1284 return;
1285
1286 hp = gethostbyname (source);
1287 if (!hp){
1288 message (1, _(" Host name "), _(" Error while looking up IP address "));
1289 return;
1290 }
1291 source_route = *((int *)hp->h_addr);
1292 }
1293 #endif /* HAVE_SETSOCKOPT */
1294 #endif /* USE_NETCODE */
1295
1296 #ifdef USE_EXT2FSLIB
1297 void undelete_cmd (void)
1298 {
1299 nice_cd (_(" Undelete files on an ext2 file system "),
1300 _(" Enter the file system name where you want to run the\n "
1301 " undelete file system on: (F1 for details)"),
1302 "[Undelete File System]", "undel:", 0);
1303 }
1304 #endif
1305
1306 void quick_cd_cmd (void)
1307 {
1308 char *p = cd_dialog ();
1309
1310 if (p && *p) {
1311 char *q = copy_strings ("cd ", p, NULL);
1312
1313 do_cd_command (q);
1314 free (q);
1315 }
1316 if (p)
1317 free (p);
1318 }
1319
1320 #ifdef SCO_FLAVOR
1321 #undef DUSUM_USEB
1322 #undef DUSUM_FACTOR
1323 #endif /* SCO_FLAVOR */
1324
1325 #ifdef HAVE_DUSUM
1326 void dirsizes_cmd (void)
1327 {
1328 WPanel *panel = cpanel;
1329 int i, j = 0;
1330 char *cmd, *p, *q, *r;
1331 FILE *f;
1332 #ifdef DUSUM_USEB
1333 # define dirsizes_command "du -s -b "
1334 #else
1335 # define dirsizes_command "du -s "
1336 #endif
1337 #ifndef DUSUM_FACTOR
1338 # define DUSUM_FACTOR 512
1339 #endif
1340
1341 if (!vfs_current_is_local ())
1342 return;
1343 for (i = 0; i < panel->count; i++)
1344 if (S_ISDIR (panel->dir.list [i].buf.st_mode))
1345 j += strlen (panel->dir.list [i].fname) + 1;
1346 if (!j)
1347 return;
1348 cmd = xmalloc (strlen (dirsizes_command) + j + 1, "dirsizes_cmd");
1349 strcpy (cmd, dirsizes_command);
1350 p = strchr (cmd, 0);
1351 for (i = 0; i < panel->count; i++)
1352 if (S_ISDIR (panel->dir.list [i].buf.st_mode) &&
1353 strcmp (panel->dir.list [i].fname, "..")) {
1354 strcpy (p, panel->dir.list [i].fname);
1355 p = strchr (p, 0);
1356 *(p++) = ' ';
1357 }
1358 *(--p) = 0;
1359 open_error_pipe ();
1360 f = popen (cmd, "r");
1361 free (cmd);
1362 if (f != NULL) {
1363 /* Assume that du will display the directories in the order
1364 * I've passed to it :(
1365 */
1366 i = 0;
1367 p = xmalloc (1024, "dirsizes_cmd");
1368 while (fgets (p, 1024, f)) {
1369 j = atoi (p) * DUSUM_FACTOR;
1370 for (q = p; *q && *q != ' ' && *q != '\t'; q++);
1371 while (*q == ' ' || *q == '\t')
1372 q++;
1373 r = strchr (q, '\n');
1374 if (r == NULL)
1375 r = strchr (q, 0);
1376 for (; i < panel->count; i++)
1377 if (S_ISDIR (panel->dir.list [i].buf.st_mode))
1378 if (!strncmp (q, panel->dir.list [i].fname,
1379 r - q)) {
1380 if (panel->dir.list [i].f.marked)
1381 panel->total += j -
1382 ((panel->has_dir_sizes) ? panel->dir.list [i].buf.st_size : 0);
1383 panel->dir.list [i].buf.st_size = j;
1384 break;
1385 }
1386 if (i == panel->count)
1387 break;
1388 }
1389 free (p);
1390 if (pclose (f) < 0)
1391 #ifndef SCO_FLAVOR
1392 message (0, _("Show directory sizes"), _("Pipe close failed"));
1393 else
1394 #else /* SCO_FLAVOR */
1395 /*
1396 ** SCO reports about error while all seems to be ok. Just ignore it...
1397 ** (alex@bcs.zaporizhzhe.ua)
1398 */
1399 ;
1400 #endif /* SCO_FLAVOR */
1401 panel->has_dir_sizes = 1;
1402 close_error_pipe (0, 0);
1403 paint_panel (panel);
1404 } else
1405 close_error_pipe (1, _("Cannot invoke du command."));
1406 }
1407 #endif
1408
1409 void
1410 save_setup_cmd (void)
1411 {
1412 char *str;
1413
1414 save_setup ();
1415 sync_profiles ();
1416 str = copy_strings ( _(" Setup saved to ~/"), PROFILE_NAME, NULL);
1417
1418 #ifdef HAVE_GNOME
1419 set_hintbar (str);
1420 #else
1421 message (0, _(" Setup "), str);
1422 #endif
1423 free (str);
1424 }
1425
1426 void
1427 configure_panel_listing (WPanel *p, int view_type, int use_msformat, char *user, char *status)
1428 {
1429 int err;
1430
1431 p->user_mini_status = use_msformat;
1432 p->list_type = view_type;
1433
1434 if (view_type == list_user || use_msformat){
1435 free (p->user_format);
1436 p->user_format = user;
1437
1438 free (p->user_status_format [view_type]);
1439 p->user_status_format [view_type] = status;
1440
1441 err = set_panel_formats (p);
1442
1443 if (err){
1444 if (err & 0x01){
1445 free (p->user_format);
1446 p->user_format = strdup (DEFAULT_USER_FORMAT);
1447 }
1448
1449 if (err & 0x02){
1450 free (p->user_status_format [view_type]);
1451 p->user_status_format [view_type] = strdup (DEFAULT_USER_FORMAT);
1452 }
1453 }
1454 }
1455 else {
1456 free (user);
1457 free (status);
1458 }
1459
1460 set_panel_formats (p);
1461 paint_panel (p);
1462
1463 do_refresh ();
1464 }
1465
1466 #ifndef HAVE_GNOME
1467 void
1468 info_cmd_no_menu (void)
1469 {
1470 set_display_type (cpanel == left_panel ? 1 : 0, view_info);
1471 }
1472
1473 void
1474 quick_cmd_no_menu (void)
1475 {
1476 set_display_type (cpanel == left_panel ? 1 : 0, view_quick);
1477 }
1478
1479 void
1480 switch_to_listing (int panel_index)
1481 {
1482 if (get_display_type (panel_index) != view_listing)
1483 set_display_type (panel_index, view_listing);
1484 }
1485
1486 void
1487 listing_cmd (void)
1488 {
1489 int view_type, use_msformat;
1490 char *user, *status;
1491 WPanel *p;
1492 int display_type;
1493
1494 display_type = get_display_type (MENU_PANEL_IDX);
1495 if (display_type == view_listing)
1496 p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1497 else
1498 p = 0;
1499
1500 view_type = display_box (p, &user, &status, &use_msformat, MENU_PANEL_IDX);
1501
1502 if (view_type == -1)
1503 return;
1504
1505 switch_to_listing (MENU_PANEL_IDX);
1506
1507 p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
1508
1509 configure_panel_listing (p, view_type, use_msformat, user, status);
1510 }
1511
1512 void
1513 tree_cmd (void)
1514 {
1515 set_display_type (MENU_PANEL_IDX, view_tree);
1516 }
1517
1518 void
1519 info_cmd (void)
1520 {
1521 set_display_type (MENU_PANEL_IDX, view_info);
1522 }
1523
1524 void
1525 quick_view_cmd (void)
1526 {
1527 set_display_type (MENU_PANEL_IDX, view_quick);
1528 }
1529 #endif
1530
1531 /* Handle the tree internal listing modes switching */
1532 static int
1533 set_basic_panel_listing_to (int panel_index, int listing_mode)
1534 {
1535 WPanel *p = (WPanel *) get_panel_widget (panel_index);
1536
1537 #ifndef HAVE_GNOME
1538 switch_to_listing (panel_index);
1539 #endif
1540 p->list_type = listing_mode;
1541 if (set_panel_formats (p))
1542 return 0;
1543
1544 paint_panel (p);
1545 do_refresh ();
1546 return 1;
1547 }
1548
1549 void
1550 toggle_listing_cmd (void)
1551 {
1552 int current = get_current_index ();
1553 WPanel *p = (WPanel *) get_panel_widget (current);
1554 int list_mode = p->list_type;
1555 int m;
1556
1557 switch (list_mode){
1558 case list_full:
1559 case list_brief:
1560 m = list_long;
1561 break;
1562 case list_long:
1563 m = list_user;
1564 break;
1565 default:
1566 m = list_full;
1567 }
1568 if (set_basic_panel_listing_to (current, m))
1569 return;
1570 set_basic_panel_listing_to (current, list_full);
1571 }
1572