home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / cmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  28.6 KB  |  1,246 lines

  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 HAVE_UNISTD_H
  23. #include <unistd.h>
  24. #endif
  25. #include "tty.h"
  26. #include <stdio.h>
  27. #include <stdlib.h>        /* getenv (), rand */
  28. #include <sys/types.h>
  29. #include <sys/param.h>
  30. #include <sys/stat.h>
  31. #include <sys/time.h>
  32. #include <malloc.h>
  33. #include <string.h>
  34. #include <fcntl.h>        /* open, O_RDWR */
  35. #include <errno.h>
  36.  
  37. #ifdef USE_NETCODE
  38. #include <netdb.h>
  39. #endif
  40.  
  41. #ifdef HAVE_MMAP
  42. #   include <sys/mman.h>
  43. #endif
  44. #include <sys/time.h>
  45. #include "mad.h"
  46. #include "dir.h"
  47. #include "util.h"
  48. #include "panel.h"
  49. #include "cmd.h"        /* Our definitions */
  50. #include "view.h"        /* view() */
  51. #include "dialog.h"        /* query_dialog, message */
  52. #include "file.h"        /* the file operations */
  53. #include "find.h"        /* do_find */
  54. #include "hotlist.h"
  55. #include "tree.h"
  56. #include "subshell.h"        /* use_subshell */
  57. #include "cons.saver.h"
  58. #include "global.h"
  59. #include "dlg.h"        /* required by wtools.h */
  60. #include "widget.h"        /* required by wtools.h */
  61. #include "wtools.h"        /* listbox */
  62. #include "command.h"        /* for input_w */
  63. #include "win.h"        /* do_exit_ca_mode */
  64. #include "layout.h"        /* get_current/other_type */
  65. #include "ext.h"        /* regex_command */
  66. #include "view.h"        /* view */
  67. #include "key.h"        /* get_key_code */
  68. #include "help.h"        /* interactive_display */
  69. #include "fs.h"
  70. #include "boxes.h"        /* cd_dialog */
  71. #include "color.h"
  72. #include "../vfs/vfs.h"
  73. #define WANT_WIDGETS
  74. #include "main.h"        /* global variables, global functions */
  75. #ifndef MAP_FILE
  76. #   define MAP_FILE 0
  77. #endif
  78.  
  79. /* If set and you don't have subshell support,then C-o will give you a shell */
  80. int output_starts_shell = 0;
  81.  
  82. /* Source routing destination */
  83. int source_route = 0;
  84.  
  85. /* This is used since the parameter panel on some of the commands */
  86. /* defined in this file may receive a 0 parameter if they are invoked */
  87. /* The drop down menu */
  88.  
  89. WPanel *get_a_panel (WPanel *panel)
  90. {
  91.     if (panel)
  92.     return panel;
  93.     if (get_current_type () == view_listing){
  94.     return (WPanel *) get_panel_widget (get_current_index ());
  95.     } else
  96.     return (WPanel *) get_panel_widget (get_other_index ());
  97. }
  98.  
  99. int view_file (char *filename, int normal, int internal)
  100. {
  101.     static char *viewer = 0;
  102.     int move_dir = 0;
  103.  
  104.  
  105.     if (normal) {
  106.         int changed_hex_mode = 0;
  107.         int changed_nroff_flag = 0;
  108.     
  109.         altered_hex_mode = 0;
  110.         altered_nroff_flag = 0;
  111.         if (default_hex_mode)
  112.             changed_hex_mode = 1;
  113.         if (default_nroff_flag)
  114.             changed_nroff_flag = 1;
  115.         default_hex_mode = 0;
  116.         default_nroff_flag = 0;
  117.         view (0, filename, &move_dir);
  118.         if (changed_hex_mode && !altered_hex_mode)
  119.             default_hex_mode = 1;
  120.         if (changed_nroff_flag && !altered_nroff_flag)
  121.             default_nroff_flag = 1;
  122.         repaint_screen ();
  123.         return move_dir;
  124.     }
  125.     if (internal){
  126.     if (!regex_command (filename, "View", NULL, &move_dir)){
  127.         view (0, filename, &move_dir);
  128.         repaint_screen ();
  129.     }
  130.     } else {
  131.     if (!viewer){
  132.         viewer = getenv ("PAGER");
  133.         if (!viewer)
  134.         viewer = "view";
  135.     }
  136.     execute_internal (viewer, filename);
  137.     }
  138.     return move_dir;
  139. }
  140.  
  141. static int scan_for_file (WPanel *panel, int idx, int direction)
  142. {
  143.     int i = idx + direction;
  144.  
  145.     while (i != idx){
  146.     if (i < 0)
  147.         i = panel->count - 1;
  148.     if (i == panel->count)
  149.         i = 0;
  150.     if (!S_ISDIR (panel->dir.list [i].buf.st_mode))
  151.         return i;
  152.     i += direction;
  153.     }
  154.     return i;
  155. }
  156.  
  157. static void view_cmd_internal (WPanel *panel, int normal)
  158. {
  159.     int dir, file_idx;
  160.     panel = get_a_panel (panel);
  161.     
  162.     /* Directories are viewed by changing to them */
  163.     if (S_ISDIR (selection (panel)->buf.st_mode) ||
  164.     link_isdir (selection (panel))){
  165.     if (confirm_view_dir && (panel->marked || panel->dirs_marked)){
  166.         if (query_dialog (" CD ", "Files tagged, want to cd?",
  167.                   0, 2, " Yes ", " No ") == 1){
  168.         return;
  169.         }
  170.     }
  171.     do_cd (selection (panel)->fname);
  172.     return;
  173.     
  174.     }
  175.  
  176.     file_idx = panel->selected;
  177.     while (1) {
  178.     char *filename;
  179.  
  180.     filename = panel->dir.list [file_idx].fname;
  181.  
  182.     dir = view_file (filename, normal, use_internal_view);
  183.     if (dir == 0)
  184.         break;
  185.     file_idx = scan_for_file (panel, file_idx, dir);
  186.     }
  187. }
  188.  
  189. void view_cmd (WPanel *panel)
  190. {
  191.     view_cmd_internal (panel, 0);
  192. }
  193.  
  194. void view_simple_cmd (void)
  195. {
  196.     view_cmd_internal (cpanel, 1);
  197. }
  198.  
  199. void filtered_view_cmd (WPanel *panel)
  200. {
  201.     char *command;
  202.  
  203.     panel = get_a_panel (panel);
  204.     command = input_dialog (" Filtered view ", "Filter command and arguments:",
  205.                 selection (panel)->fname);
  206.     if (!command)
  207.     return;
  208.  
  209.     view (command, "", 0);
  210.  
  211.     free (command);
  212. }
  213.  
  214. void filtered_view_cmd_cpanel (void)
  215. {
  216.     filtered_view_cmd (cpanel);
  217. }
  218.  
  219. void do_edit (const char *what)
  220. {
  221.     static char *editor = 0;
  222.  
  223.     if (!editor){
  224.     editor = getenv ("EDITOR");
  225.     if (!editor)
  226.         editor = "vi";
  227.     }
  228.     execute_internal (editor, what);
  229. }
  230.  
  231. void edit_cmd (WPanel *panel)
  232. {
  233.     panel = get_a_panel(panel);
  234.     if (!regex_command (selection (panel)->fname, "Edit", NULL, 0))
  235.         do_edit (selection (panel)->fname);
  236. }
  237.  
  238. void copy_cmd (void)
  239. {
  240.     save_cwds_stat ();
  241.     if (panel_operate (OP_COPY, NULL)){
  242.     update_panels (UP_OPTIMIZE, UP_KEEPSEL, UP_KEEPSEL);
  243.     repaint_screen ();
  244.     }
  245. }
  246.  
  247. void ren_cmd (void)
  248. {
  249.     save_cwds_stat ();
  250.     if (panel_operate (OP_MOVE, NULL)){
  251.     update_panels (UP_OPTIMIZE, UP_KEEPSEL, UP_KEEPSEL);
  252.     repaint_screen ();
  253.     }
  254. }
  255.  
  256. void copymove_cmd_with_default (int copy, char *thedefault)
  257. {
  258.     save_cwds_stat ();
  259.     if (panel_operate (copy ? OP_COPY : OP_MOVE, thedefault)){
  260.     update_panels (UP_OPTIMIZE, UP_KEEPSEL, UP_KEEPSEL);
  261.     repaint_screen ();
  262.     }
  263. }
  264.  
  265. void mkdir_cmd (WPanel *panel)
  266. {
  267.     char *dir;
  268.     
  269.     panel = get_a_panel (panel);
  270.     dir = input_expand_dialog (" Mkdir ", "Enter directory name:" , "");
  271.     
  272.     if (!dir)
  273.     return;
  274.  
  275.     save_cwds_stat ();
  276.     if (my_mkdir (dir, 0777) == 0){
  277.     update_panels (UP_OPTIMIZE, dir, UP_KEEPSEL);
  278.     repaint_screen ();
  279.     select_item (cpanel);
  280.     free (dir);
  281.     return;
  282.     }
  283.     free (dir);
  284.     message (1, " Error ", "  %s  ", unix_error_string (errno));
  285. }
  286.  
  287. void delete_cmd (void)
  288. {
  289.     save_cwds_stat ();
  290.  
  291.     if (panel_operate (OP_DELETE, NULL)){
  292.     update_panels (UP_OPTIMIZE, UP_KEEPSEL, UP_KEEPSEL);
  293.     repaint_screen ();
  294.     }
  295. }
  296.  
  297. void find_cmd (void)
  298. {
  299.     do_find ();
  300. }
  301.  
  302. void filter_cmd (void)
  303. {
  304.     char *reg_exp;
  305.     char *x;
  306.     WPanel *p;
  307.  
  308.     if (!SELECTED_IS_PANEL)
  309.     return;
  310.  
  311.     p = MENU_PANEL;
  312.  
  313.     x = p->filter ? p->filter : easy_patterns ? "*" : ".";
  314.     
  315.     reg_exp = input_dialog (" Filter ", "", x);
  316.     mad_check (__FILE__, __LINE__);
  317.     if (!reg_exp)
  318.     return;
  319.     mad_check (__FILE__, __LINE__);
  320.     if (p->filter){
  321.     mad_check (__FILE__, __LINE__);
  322.     free (p->filter);
  323.     mad_check (__FILE__, __LINE__);
  324.     p->filter = 0;
  325.     }
  326.     mad_check (__FILE__, __LINE__);
  327.     if (!(reg_exp [0] == '*' && reg_exp [1] == 0))
  328.     p->filter = reg_exp;
  329.     mad_check (__FILE__, __LINE__);
  330.     reread_cmd ();
  331. }
  332.  
  333. void reread_cmd (void)
  334. {
  335.     int flag;
  336.  
  337.     mad_check (__FILE__, __LINE__);
  338.     if (get_current_type () == view_listing &&
  339.     get_other_type () == view_listing)
  340.     flag = strcmp (cpanel->cwd, opanel->cwd) ? UP_ONLY_CURRENT : 0;
  341.     else
  342.     flag = UP_ONLY_CURRENT;
  343.     
  344.     update_panels (UP_RELOAD|flag, UP_KEEPSEL, UP_KEEPSEL);
  345.     repaint_screen ();
  346. }
  347.  
  348. /* Panel sorting related routines */
  349. void do_re_sort (WPanel *panel)
  350. {
  351.     char *filename;
  352.     int  i;
  353.  
  354.     panel = get_a_panel (panel);
  355.     filename = strdup (selection (cpanel)->fname);
  356.     unselect_item (panel);
  357.     do_sort (&panel->dir, panel->sort_type, panel->count-1, panel->reverse, panel->case_sensitive);
  358.     panel->selected = -1;
  359.     for (i = panel->count; i; i--){
  360.     if (!strcmp (panel->dir.list [i-1].fname, filename)){
  361.         panel->selected = i-1;
  362.         break;
  363.     }
  364.     }
  365.     free (filename);
  366.     cpanel->top_file = cpanel->selected - llines (cpanel)/2;
  367.     if (cpanel->top_file < 0)
  368.     cpanel->top_file = 0;
  369.     select_item (panel);
  370.     panel_update_contents (panel);
  371. }
  372.  
  373. void reverse_selection_cmd (void)
  374. {
  375.     file_entry *file;
  376.     int i;
  377.  
  378.     for (i = 0; i < cpanel->count; i++){
  379.     file = &cpanel->dir.list [i];
  380.     if (S_ISDIR (file->buf.st_mode))
  381.         continue;
  382.     if (file->f.marked){
  383.         cpanel->marked--;
  384.         cpanel->total-=file->buf.st_size;
  385.     } else {
  386.         cpanel->marked++;
  387.         cpanel->total+=file->buf.st_size;
  388.     }
  389.     file_mark (cpanel, i, !file->f.marked);
  390.     }
  391.     paint_panel (cpanel);
  392. }
  393.  
  394. void select_cmd (void)
  395. {
  396.     char *reg_exp, *reg_exp_t;
  397.     int i;
  398.     int c;
  399.     int dirflag = 0;
  400.  
  401.     reg_exp = input_dialog (" Select ", "", easy_patterns ? "*" : ".");
  402.     if (!reg_exp)
  403.     return;
  404.     
  405.     reg_exp_t = reg_exp;
  406.  
  407.     /* Check if they specified a directory */
  408.     if (*reg_exp_t == PATH_SEP){
  409.         dirflag = 1;
  410.         reg_exp_t++;
  411.     }
  412.     if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
  413.         dirflag = 1;
  414.         reg_exp_t [strlen(reg_exp_t) - 1] = 0;
  415.     }
  416.  
  417.     for (i = 0; i < cpanel->count; i++){
  418.         if (!strcmp( cpanel->dir.list [i].fname, ".."))
  419.             continue;
  420.     if (S_ISDIR (cpanel->dir.list [i].buf.st_mode)){
  421.         if (!dirflag)
  422.                 continue;
  423.         } else {
  424.             if (dirflag)
  425.                 continue;
  426.     }
  427.     c = regexp_match (reg_exp_t, cpanel->dir.list [i].fname, match_file);
  428.     if (c == -1){
  429.         message (1, " Error ", "  Malformed regular expression  ");
  430.         free (reg_exp);
  431.         return;
  432.     }
  433.     if (c){
  434.         if (!cpanel->dir.list [i].f.marked){
  435.         cpanel->marked++;
  436.         if (S_ISDIR (cpanel->dir.list[i].buf.st_mode)) {
  437.             if (cpanel->has_dir_sizes)
  438.                 cpanel->total += cpanel->dir.list [i].buf.st_size;
  439.             cpanel->dirs_marked++;
  440.         } else
  441.             cpanel->total += cpanel->dir.list [i].buf.st_size;
  442.         }
  443.         file_mark (cpanel, i, 1);
  444.     }
  445.     }
  446.     paint_panel (cpanel);
  447.     free (reg_exp);
  448. }
  449.  
  450. void unselect_cmd (void)
  451. {
  452.     char *reg_exp, *reg_exp_t;
  453.     int i;
  454.     int c;
  455.     int dirflag = 0;
  456.  
  457.     reg_exp = input_dialog (" Unselect ","", easy_patterns ? "*" : ".");
  458.     if (!reg_exp)
  459.     return;
  460.     
  461.     reg_exp_t = reg_exp;
  462.     
  463.     /* Check if they specified directory matching */
  464.     if (*reg_exp_t == PATH_SEP){
  465.         dirflag = 1;
  466.     reg_exp_t ++;
  467.     }
  468.     if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
  469.         dirflag = 1;
  470.         reg_exp_t [strlen(reg_exp_t) - 1] = 0;
  471.     }
  472.     for (i = 0; i < cpanel->count; i++){
  473.         if (!strcmp( cpanel->dir.list [i].fname, "..")) 
  474.             continue;
  475.     if (S_ISDIR (cpanel->dir.list [i].buf.st_mode)){
  476.         if (!dirflag)
  477.             continue;
  478.         } else {
  479.             if (dirflag)
  480.                 continue;
  481.         }
  482.     c = regexp_match (reg_exp_t, cpanel->dir.list [i].fname, match_file);
  483.     if (c == -1){
  484.         message (1, " Error ", "  Malformed regular expression  ");
  485.         free (reg_exp);
  486.         return;
  487.     }
  488.     if (c){
  489.         if (cpanel->dir.list [i].f.marked){
  490.         if (S_ISDIR (cpanel->dir.list[i].buf.st_mode)) {
  491.             if (cpanel->has_dir_sizes)
  492.                 cpanel->total -= cpanel->dir.list [i].buf.st_size;
  493.             cpanel->dirs_marked--;
  494.         } else
  495.             cpanel->total -= cpanel->dir.list [i].buf.st_size;
  496.         cpanel->marked--;
  497.         }
  498.         file_mark (cpanel, i, 0);
  499.         cpanel->dir.list [i].f.marked = 0;
  500.     }
  501.     }
  502.     paint_panel (cpanel);
  503.     free (reg_exp);
  504. }
  505.  
  506. /* Check if the file exists */
  507. /* If not copy the default */
  508. static int check_for_default(char *default_file, char *file)
  509. {
  510.     struct stat s;
  511.     if (mc_stat (file, &s)){
  512.     if (mc_stat (default_file, &s)){
  513.         return -1;
  514.     }
  515.     create_op_win (OP_COPY);
  516.     copy_file_file (default_file, file, 0, 1);
  517.     destroy_op_win ();
  518.     }
  519.     return 0;
  520. }
  521.  
  522. void ext_cmd (void)
  523. {
  524.     char *buffer;
  525.     int  dir;
  526.  
  527.     dir = 0;
  528.     if (geteuid () == 0){
  529.     dir = query_dialog ("Extension file edit",
  530.                 " Which extension file you want to edit? ", 0, 2,
  531.                 " User ", " System Wide ");
  532.     }
  533.     if (dir == 0){
  534.     buffer = copy_strings (home_dir, "/.mc.ext", 0);
  535.     check_for_default (LIBDIR "mc.ext", buffer);
  536.     do_edit (buffer);
  537.     free (buffer);
  538.     } else if (dir == 1)
  539.     do_edit (LIBDIR "mc.ext");
  540. }
  541.  
  542. void menu_edit_cmd (void)
  543. {
  544. #define MC_MENU "mc.menu"
  545.  
  546.     char *buffer, *home_file;
  547.     int dir = 0;
  548.     
  549.     if (geteuid () == 0)
  550.     dir = query_dialog ("Menu file edit",
  551.                 " Which menu file will you edit? ", 0, 2,
  552.                   " User ", " System Wide ");
  553.  
  554.     home_file = copy_strings (home_dir, "/.mc.menu", 0);
  555.  
  556.     switch (dir){
  557.     case 0:
  558.     buffer = strdup (home_file);
  559.     check_for_default (LIBDIR MC_MENU, buffer);
  560.     break;
  561.  
  562.     case 1:
  563.     buffer = copy_strings (LIBDIR, MC_MENU, 0);
  564.     break;
  565.  
  566.     default:
  567.     free (home_file);
  568.     return;
  569.     }
  570.     do_edit (buffer);
  571.     free (buffer);
  572.     free (home_file);
  573. }
  574.  
  575. void quick_chdir_cmd (void)
  576. {
  577.     char *target;
  578.  
  579.     target = hotlist_cmd (0);
  580.     if (!target)
  581.     return;
  582.  
  583.     if (get_current_type () == view_tree)
  584.     tree_chdir (the_tree, target);
  585.     else
  586.     do_cd (target);
  587. }
  588.  
  589. #ifdef USE_VFS
  590. void reselect_vfs (void)
  591. {
  592.     char *target;
  593.  
  594.     target = hotlist_cmd (1);
  595.     if (!target)
  596.     return;
  597.  
  598.     do_cd (target);
  599.     free (target);
  600. }
  601. #endif
  602.  
  603. static int compare_files (char *name1, char *name2, long size)
  604. {
  605.     int file1, file2;
  606.     char *data1, *data2;
  607.     int result = -1;        /* Different by default */
  608.  
  609. #ifdef HAVE_MMAP
  610.     /* Ugly if jungle */
  611.     file1 = open (name1, O_RDONLY);
  612.     if (file1 >= 0){
  613.     file2 = open (name2, O_RDONLY);
  614.     if (file2 >= 0){
  615.         data1 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file1, 0);
  616.         if (data1 != (char*) -1){
  617.         data2 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file2, 0);
  618.         if (data2 != (char*) -1){
  619.             rotate_dash ();
  620.             result = memcmp (data1, data2, size);
  621.             munmap (data2, size);
  622.         }
  623.         munmap (data1, size);
  624.         }
  625.         close (file2);
  626.     }
  627.     close (file1);
  628.     }
  629. #endif
  630.     return result;
  631. }
  632.  
  633. static void compare_dir (WPanel *panel, WPanel *other, int thorough_flag)
  634. {
  635.     int i, j;
  636.     char *src_name, *dst_name;
  637.  
  638.     panel = get_a_panel (panel);
  639.     
  640.     /* No marks by default */
  641.     panel->marked = 0;
  642.     panel->total = 0;
  643.     panel->dirs_marked = 0;
  644.     
  645.     /* Handle all files in the panel */
  646.     for (i = 0; i < panel->count; i++){
  647.     file_entry *source = &panel->dir.list[i];
  648.  
  649.     /* Default: unmarked */
  650.     file_mark (panel, i, 0);
  651.  
  652.     /* Skip directories */
  653.     if (S_ISDIR (source->buf.st_mode))
  654.         continue;
  655.  
  656.     /* Search the corresponding entry from the other panel */
  657.     for (j = 0; j < other->count; j++){
  658.         if (strcmp (source->fname,
  659.             other->dir.list[j].fname) == 0)
  660.         break;
  661.     }
  662.     if (j >= other->count)
  663.         /* Not found -> mark */
  664.         file_mark (panel, i, 1);
  665.     else {
  666.         /* Found */
  667.         file_entry *target = &other->dir.list[j];
  668.  
  669.         /* Older version is not marked */
  670.         if (source->buf.st_mtime < target->buf.st_mtime)
  671.         continue;
  672.         /* Newer version with different size is marked */
  673.         if (source->buf.st_size != target->buf.st_size){
  674.         file_mark (panel, i, 1);
  675.         } else if (!thorough_flag){
  676.         /* Thorough compare off, compare only time stamps */
  677.         /* Mark newer version, don't mark version with the same date */
  678.         if (source->buf.st_mtime > target->buf.st_mtime)
  679.             file_mark (panel, i, 1);
  680.         else
  681.             continue;
  682.         } else {
  683.         /* Thorough compare on, do byte-by-byte comparison */
  684.         src_name = get_full_name (panel->cwd, source->fname);
  685.         dst_name = get_full_name (other->cwd, target->fname);
  686.         if (compare_files (src_name, dst_name, source->buf.st_size))
  687.             file_mark (panel, i, 1);
  688.         free (src_name);
  689.         free (dst_name);
  690.         }
  691.     }
  692.  
  693.     /* If marked increase counts */
  694.     if (source->f.marked){
  695.         panel->marked++;
  696.         panel->total += source->buf.st_size;
  697.     }
  698.     } /* for (i ...) */
  699. }
  700.  
  701. void compare_dirs_cmd (void)
  702. {
  703.     int thorough_flag = 0;
  704.  
  705. #ifdef HAVE_MMAP
  706.     thorough_flag = query_dialog (" Compare directories ", " Select compare method: ",
  707.                   0, 3, " Quick ", " Thorough ", " Cancel ");
  708.     if (thorough_flag < 0 || thorough_flag > 1)
  709.     return;
  710. #endif
  711.     if (get_current_type () == view_listing &&
  712.     get_other_type () == view_listing){
  713.     compare_dir (cpanel, opanel, thorough_flag);
  714.     compare_dir (opanel, cpanel, thorough_flag);
  715.     paint_panel (cpanel);
  716.     paint_panel (opanel);
  717.     } else {
  718.     message (1, " Error ", " Both panels should be on the listing view mode to use this command ");
  719.     }
  720. }
  721.  
  722. void history_cmd (void)
  723. {
  724.     Listbox *listbox;
  725.     Hist *current;
  726.  
  727.     if (input_w (cmdline)->need_push){
  728.     if (push_history (input_w (cmdline), input_w (cmdline)->buffer) == 2)
  729.         input_w (cmdline)->need_push = 0;
  730.     }
  731.     if (!input_w (cmdline)->history){
  732.     message (1, " Error ", " The command history is empty ");
  733.     return;
  734.     }
  735.     current = input_w (cmdline)->history;
  736.     while (current->prev)
  737.     current = current->prev;
  738.     listbox = create_listbox_window (60, 10, " Command history ",
  739.                      "[Command Menu]");
  740.     while (current){
  741.     LISTBOX_APPEND_TEXT (listbox, 0, current->text,
  742.                  current);
  743.     current = current->next;
  744.     }
  745.     run_dlg (listbox->dlg);
  746.     if (listbox->dlg->ret_value == B_CANCEL)
  747.     current = NULL;
  748.     else
  749.     current = listbox->list->current->data;
  750.     destroy_dlg (listbox->dlg);
  751.     free (listbox);
  752.  
  753.     if (!current)
  754.     return;
  755.     input_w (cmdline)->history = current;
  756.     assign_text (input_w (cmdline), input_w (cmdline)->history->text);
  757.     update_input (input_w (cmdline));
  758. }
  759.  
  760. #ifndef HAVE_XVIEW
  761. void swap_cmd (void)
  762. {
  763.     swap_panels ();
  764.     touchwin (stdscr);
  765.     repaint_screen ();
  766. }
  767. #endif
  768.  
  769. void view_other_cmd (void)
  770. {
  771.     static int message_flag = TRUE;
  772. #ifdef HAVE_SUBSHELL_SUPPORT
  773.     char *new_dir = NULL;
  774.     char **new_dir_p;
  775. #endif
  776.  
  777.     if (!xterm_flag && !console_flag && !use_subshell){
  778.     if (message_flag)
  779.         message (1, " Error ", " Not an xterm or Linux console; \n"
  780.                    " the panels cannot be toggled. ");
  781.     message_flag = FALSE;
  782.     } else {
  783. #ifndef HAVE_X
  784.     if (use_mouse_p)
  785.         shut_mouse ();
  786. #endif        
  787.  
  788.     if (clear_before_exec) {
  789.         clr_scr ();
  790.     }
  791.  
  792.     if (alternate_plus_minus && (console_flag || xterm_flag)) {
  793.         fprintf (stderr, "\033>"); fflush (stderr);
  794.     }
  795. #ifndef HAVE_SLANG
  796.     /* With slang we don't want any of this, since there
  797.      * is no mc_raw_mode supported
  798.      */
  799.     reset_shell_mode ();
  800.     noecho ();
  801. #endif
  802.     endwin ();
  803.     if (!status_using_ncurses)
  804.         do_exit_ca_mode ();
  805.     mc_raw_mode ();
  806.     if (console_flag)
  807.         restore_console ();
  808.  
  809. #ifdef HAVE_SUBSHELL_SUPPORT
  810.     if (use_subshell){
  811.         new_dir_p = vfs_current_is_local () ? &new_dir : NULL;
  812.         if (invoke_subshell (NULL, VISIBLY, new_dir_p))
  813.         return;  /* User did `exit' or `logout': quit MC quietly */
  814.     } else
  815. #endif
  816.     {
  817.         if (output_starts_shell){
  818.         fprintf (stderr,
  819.          "Type `exit' to return to the Midnight Commander\n\r\n\r");
  820.         my_system (1, shell, NULL);
  821.         } else
  822.         get_key_code (0);
  823.     }
  824.     if (console_flag)
  825.         handle_console (CONSOLE_SAVE);
  826.  
  827.     if (!status_using_ncurses)
  828.         do_enter_ca_mode ();
  829.         
  830.     if (alternate_plus_minus && (console_flag || xterm_flag)) {
  831.         fprintf (stderr, "\033="); fflush (stderr);
  832.     }
  833.     reset_prog_mode ();
  834.     
  835. #ifndef HAVE_X    
  836.     if (use_mouse_p)
  837.         init_mouse ();
  838. #endif        
  839.  
  840. #ifdef HAVE_SUBSHELL_SUPPORT
  841.     if (use_subshell){
  842.         load_prompt (0, 0);
  843.         if (new_dir)
  844.         do_possible_cd (new_dir);
  845.         if (console_flag && output_lines)
  846.         show_console_contents (output_start_y,
  847.                        LINES-keybar_visible-output_lines-1,
  848.                        LINES-keybar_visible-1);
  849.     }
  850. #endif
  851.         touchwin (stdscr);
  852.     repaint_screen ();
  853.     }
  854. }
  855.  
  856. #ifndef _OS_NT
  857. static void do_link (int symbolic_link)
  858. {
  859.     struct stat s;
  860.     char *dest, *src;
  861.     int  stat_r;
  862.  
  863.     if (!symbolic_link){
  864.     stat_r = mc_stat (selection (cpanel)->fname, &s);
  865.     if (stat_r != 0){
  866.         message (1, " Error ", " Couldn't stat %s \n %s ",
  867.              selection (cpanel)->fname, unix_error_string (errno));
  868.         return;
  869.     }
  870.     if (!S_ISREG (s.st_mode))
  871.         return;
  872.     }
  873.     
  874.     if (!symbolic_link){
  875.         src = copy_strings (" Link ", name_trunc (selection (cpanel)->fname, 46), 
  876.             " to:", NULL);
  877.     dest = input_expand_dialog (" Link ", src, "");
  878.     free (src);
  879.     if (!dest)
  880.         return;
  881.     if (!*dest) {
  882.         free (dest);
  883.         return;
  884.     }
  885.     save_cwds_stat ();
  886.     if (-1 == mc_link (selection (cpanel)->fname, dest))
  887.         message (1, " Error ", " link: %s ", unix_error_string (errno));
  888.     } else {
  889. #ifdef OLD_SYMLINK_VERSION
  890.         symlink_dialog (selection (cpanel)->fname, "", &dest, &src);
  891. #else
  892.     /* suggest the full path for symlink */
  893.         char s[MC_MAXPATHLEN];
  894.         char d[MC_MAXPATHLEN];
  895.     
  896.         strcpy(s, cpanel->cwd);
  897.         if ( ! ((s[0] == '/') && (s[1] == 0)))
  898.             strcat(s, "/");
  899.         strcat(s, selection (cpanel)->fname);
  900.         strcpy(d, opanel->cwd);
  901.         if ( ! ((d[0] == '/') && (d[1] == 0)))
  902.             strcat(d, "/");
  903.         symlink_dialog (s, d, &dest, &src);
  904. #endif
  905.     if (!dest || !*dest) {
  906.         if (src)
  907.             free (src);
  908.         if (dest)
  909.             free (dest);
  910.         return;
  911.     }
  912.     if (src){
  913.         if (*src) {
  914.             save_cwds_stat ();
  915.             if (-1 == mc_symlink (dest, src))
  916.             message (1, " Error ", " symlink: %s ",
  917.                  unix_error_string (errno));
  918.         }
  919.         free (src);
  920.     }
  921.     }
  922.     free (dest);
  923.     update_panels (UP_OPTIMIZE, UP_KEEPSEL, UP_KEEPSEL);
  924.     repaint_screen ();
  925. }
  926.  
  927. void link_cmd (void)
  928. {
  929.     do_link (0);
  930. }
  931.  
  932. void symlink_cmd (void)
  933. {
  934.     do_link (1);
  935. }
  936.  
  937. void edit_symlink_cmd (void)
  938. {
  939.     if (S_ISLNK (selection (cpanel)->buf.st_mode)) {
  940.     char buffer [MC_MAXPATHLEN], *p = selection (cpanel)->fname;
  941.     int i;
  942.     char *dest, *q = copy_strings (" Symlink ", name_trunc (p, 32), " points to:", NULL);
  943.     
  944.     i = readlink (p, buffer, MC_MAXPATHLEN);
  945.     if (i > 0) {
  946.         buffer [i] = 0;
  947.         dest = input_expand_dialog (" Edit symlink ", q, buffer);
  948.         if (dest) {
  949.         if (*dest && strcmp (buffer, dest)) {
  950.             save_cwds_stat ();
  951.             mc_unlink (p);
  952.             if (-1 == mc_symlink (dest, p))
  953.                 message (1, " Error ", " edit symlink: %s ",
  954.                  unix_error_string (errno));
  955.             update_panels (UP_OPTIMIZE, UP_KEEPSEL, UP_KEEPSEL);
  956.             repaint_screen ();
  957.         }
  958.         free (dest);
  959.         }
  960.     }
  961.     free (q);
  962.     }
  963. }
  964.  
  965. void other_symlink_cmd (void)
  966. {
  967.     char *dest, *q, *p, *r, *s, *t;
  968.  
  969.     if (get_other_type () != view_listing)
  970.         return;
  971.  
  972.     if (!strcmp (selection (opanel)->fname, ".."))
  973.         return;
  974.     if (cpanel->cwd [strlen (cpanel->cwd) - 1] != PATH_SEP)
  975.         p = copy_strings (cpanel->cwd, PATH_SEP_STR, selection (cpanel)->fname, NULL);
  976.     else
  977.         p = copy_strings (cpanel->cwd, selection (cpanel)->fname, NULL);
  978.     if (opanel->cwd [strlen (opanel->cwd) - 1] != PATH_SEP)
  979.         r = copy_strings (opanel->cwd, PATH_SEP_STR, selection (cpanel)->fname, NULL);
  980.     else
  981.         r = copy_strings (opanel->cwd, selection (cpanel)->fname, NULL);
  982.     q = copy_strings (" Link symbolically ", name_trunc (p, 32), " to:", NULL);
  983.     dest = input_expand_dialog (" Relative symlink ", q, r);
  984.     if (dest) {
  985.     if (*dest) {
  986.         t = strrchr (dest, PATH_SEP);
  987.         if (t) {
  988.         t[1] = 0;
  989.         s = diff_two_paths (dest, p);
  990.         t[1] = PATH_SEP;
  991.         if (s) {
  992.             save_cwds_stat ();
  993.             if (-1 == mc_symlink (dest, s))
  994.                 message (1, " Error ", " relative symlink: %s ",
  995.                  unix_error_string (errno));
  996.             update_panels (UP_OPTIMIZE, UP_KEEPSEL, UP_KEEPSEL);
  997.             repaint_screen ();
  998.             free (s);
  999.         }
  1000.         }
  1001.     }
  1002.     free (dest);
  1003.     }
  1004.     free (q);
  1005.     free (p);
  1006.     free (r);
  1007. }
  1008. #endif
  1009.  
  1010. void help_cmd (void)
  1011. {
  1012.     interactive_display (LIBDIR "mc.hlp", "[main]");
  1013. }
  1014.  
  1015. void view_panel_cmd (void)
  1016. {
  1017.     view_cmd (cpanel);
  1018. }
  1019.  
  1020. void edit_panel_cmd (void)
  1021. {
  1022.     edit_cmd (cpanel);
  1023. }
  1024.  
  1025. void mkdir_panel_cmd (void)
  1026. {
  1027.     mkdir_cmd (cpanel);
  1028. }
  1029.  
  1030. /* Returns a random hint */
  1031. char *get_random_hint (void)
  1032. {
  1033.     char *data, *result, *eol;
  1034.     int  len;
  1035.     int start;
  1036.     
  1037.     /* Do not change hints more often than one minute */
  1038.  
  1039. #ifdef SCO_FLAVOR
  1040.     static time_t last;
  1041.     time_t now;
  1042.  
  1043.     time (&now);
  1044.     if ((now - last) < 60)
  1045.     return strdup ("");
  1046.     last = now;
  1047. #else
  1048.     static last_sec;
  1049.     static struct timeval tv;
  1050.     
  1051.     gettimeofday (&tv, NULL);
  1052.     if (!(tv.tv_sec> last_sec+60))
  1053.     return strdup (""); 
  1054.     last_sec = tv.tv_sec;
  1055. #endif
  1056.  
  1057.     data = load_file (LIBDIR "mc.hint");
  1058.     if (!data)
  1059.     return 0;
  1060.  
  1061. #ifdef SCO_FLAVOR
  1062.     srand ((short) now);
  1063. #else
  1064.     srand (tv.tv_sec);
  1065. #endif
  1066.     /* get a random entry */
  1067.     len = strlen (data);
  1068.     start = rand () % len;
  1069.     
  1070.     for (;start; start--){
  1071.     if (data [start] == '\n'){
  1072.         start++;
  1073.         break;
  1074.     }
  1075.     }
  1076.     eol = strchr (&data [start], '\n');
  1077.     if (eol)
  1078.     *eol = 0;
  1079.     result = strdup (&data [start]);
  1080.     free (data);
  1081.     return result;
  1082. }
  1083.  
  1084. #ifndef USE_VFS
  1085. #ifdef USE_NETCODE
  1086. #undef USE_NETCODE
  1087. #endif
  1088. #endif
  1089.  
  1090. #ifdef USE_NETCODE
  1091.  
  1092. static char *machine_str = " Enter machine name (F1 for details): ";
  1093.  
  1094. static void nice_cd (char *text, char *xtext, char *help, char *prefix, int to_home)
  1095. {
  1096.     char *machine;
  1097.     char *cd_path;
  1098.  
  1099.     if (!SELECTED_IS_PANEL)
  1100.     return;
  1101.  
  1102.     machine = input_dialog_help (text,
  1103.                  xtext,
  1104.                  help, "");
  1105.     if (!machine)
  1106.     return;
  1107.  
  1108.     cd_path = copy_strings (prefix, machine, to_home ? "/~/" : NULL, NULL);
  1109.     do_panel_cd (MENU_PANEL, cd_path);
  1110.     free (cd_path);
  1111.     free (machine);
  1112. }
  1113.  
  1114. void netlink_cmd (void)
  1115. {
  1116.     nice_cd (" Link to a remote machine ", machine_str,
  1117.          "[Network File System]", "mc:", 1);
  1118. }
  1119.  
  1120. void ftplink_cmd (void)
  1121. {
  1122.     nice_cd (" FTP to machine ", machine_str,
  1123.          "[FTP File System]", "ftp://", 1);
  1124. }
  1125.  
  1126. #ifdef HAVE_SETSOCKOPT
  1127. void source_routing (void)
  1128. {
  1129.     char *source;
  1130.     struct hostent *hp;
  1131.     
  1132.     source = input_dialog (" Socket source routing setup ",
  1133.                " Enter host name to use as a source routing hop: ",
  1134.                "");
  1135.     if (!source)
  1136.     return;
  1137.  
  1138.     hp = gethostbyname (source);
  1139.     if (!hp){
  1140.     message (1, " Host name ", " Error while looking up IP address ");
  1141.     return;
  1142.     }
  1143.     source_route = *((int *)hp->h_addr);
  1144. }
  1145. #endif /* HAVE_SETSOCKOPT */
  1146. #endif /* USE_NETCODE */
  1147.  
  1148. #ifdef USE_EXT2FSLIB
  1149. void undelete_cmd (void)
  1150. {
  1151.     nice_cd (" Undelete files on an ext2 file system ",
  1152.          " Enter the file system name where you want to run the\n "
  1153.          " undelete file system on: (F1 for details)",
  1154.          "[Undelete File System]", "undel:", 0);
  1155. }
  1156. #endif
  1157.  
  1158. void quick_cd_cmd (void)
  1159. {
  1160.     char *p = cd_dialog ();
  1161.  
  1162.     if (p && *p) {
  1163.         char *q = copy_strings ("cd ", p, NULL);
  1164.         
  1165.         do_cd_command (q);
  1166.         free (q);
  1167.     }
  1168.     if (p)
  1169.         free (p);
  1170. }
  1171.  
  1172. #ifdef HAVE_DUSUM
  1173. void dirsizes_cmd (void)
  1174. {
  1175.     WPanel *panel = cpanel;
  1176.     int i, j = 0;
  1177.     char *cmd, *p, *q, *r;
  1178.     FILE *f;
  1179. #ifdef DUSUM_USEB
  1180. #   define dirsizes_command "du -s -b "
  1181. #else
  1182. #   define dirsizes_command "du -s "
  1183. #endif
  1184. #ifndef DUSUM_FACTOR
  1185. #    define DUSUM_FACTOR 512
  1186. #endif
  1187.  
  1188.     if (!vfs_current_is_local ())
  1189.         return;
  1190.     for (i = 0; i < panel->count; i++)
  1191.         if (S_ISDIR (panel->dir.list [i].buf.st_mode))
  1192.             j += strlen (panel->dir.list [i].fname) + 1;
  1193.     if (!j)
  1194.         return;
  1195.     cmd = xmalloc (strlen (dirsizes_command) + j + 1, "dirsizes_cmd");
  1196.     strcpy (cmd, dirsizes_command);
  1197.     p = strchr (cmd, 0);
  1198.     for (i = 0; i < panel->count; i++)
  1199.         if (S_ISDIR (panel->dir.list [i].buf.st_mode) && 
  1200.             strcmp (panel->dir.list [i].fname, "..")) {
  1201.             strcpy (p, panel->dir.list [i].fname);
  1202.             p = strchr (p, 0);
  1203.             *(p++) = ' ';
  1204.         }
  1205.     *(--p) = 0;
  1206.     open_error_pipe ();
  1207.     f = popen (cmd, "r");
  1208.     free (cmd);
  1209.     if (f != NULL) {
  1210.         /* Assume that du will display the directories in the order 
  1211.          * I've passed to it :( 
  1212.          */
  1213.         i = 0;
  1214.         p = xmalloc (1024, "dirsizes_cmd");
  1215.         while (fgets (p, 1024, f)) {
  1216.             j = atoi (p) * DUSUM_FACTOR;
  1217.             for (q = p; *q && *q != ' ' && *q != '\t'; q++);
  1218.             while (*q == ' ' || *q == '\t')
  1219.                 q++;
  1220.             r = strchr (q, '\n');
  1221.             if (r == NULL)
  1222.                 r = strchr (q, 0);
  1223.             for (; i < panel->count; i++)
  1224.                 if (S_ISDIR (panel->dir.list [i].buf.st_mode))
  1225.                     if (!strncmp (q, panel->dir.list [i].fname,
  1226.                         r - q)) {
  1227.                         if (panel->dir.list [i].f.marked)
  1228.                             panel->total += j - 
  1229.                 ((panel->has_dir_sizes) ? panel->dir.list [i].buf.st_size : 0); 
  1230.                         panel->dir.list [i].buf.st_size = j;
  1231.                         break;
  1232.                     }
  1233.             if (i == panel->count)
  1234.                 break;
  1235.         }
  1236.         if (pclose (f) < 0)
  1237.         message (2, "Show directory sizes", "Pipe close failed");
  1238.     else
  1239.         panel->has_dir_sizes = 1;
  1240.     close_error_pipe (0, 0);
  1241.     paint_panel (panel);
  1242.     } else
  1243.         close_error_pipe (1, "Cannon invoke du command.");
  1244. }
  1245. #endif
  1246.