diff options
Diffstat (limited to 'src/filemanager/cmd.c')
-rw-r--r-- | src/filemanager/cmd.c | 1470 |
1 files changed, 1470 insertions, 0 deletions
diff --git a/src/filemanager/cmd.c b/src/filemanager/cmd.c new file mode 100644 index 0000000..8c33fd8 --- /dev/null +++ b/src/filemanager/cmd.c @@ -0,0 +1,1470 @@ +/* + Routines invoked by a function key + They normally operate on the current panel. + + Copyright (C) 1994-2023 + Free Software Foundation, Inc. + + Written by: + Andrew Borodin <aborodin@vmail.ru>, 2013-2022 + + This file is part of the Midnight Commander. + + The Midnight Commander is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + The Midnight Commander is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file cmd.c + * \brief Source: routines invoked by a function key + * + * They normally operate on the current panel. + */ + +#include <config.h> + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_MMAP +#include <sys/mman.h> +#endif +#ifdef ENABLE_VFS_NET +#include <netdb.h> +#endif +#include <unistd.h> +#include <stdlib.h> +#include <pwd.h> +#include <grp.h> + +#include "lib/global.h" + +#include "lib/tty/tty.h" /* LINES, tty_touch_screen() */ +#include "lib/tty/key.h" /* ALT() macro */ +#include "lib/mcconfig.h" +#include "lib/filehighlight.h" /* MC_FHL_INI_FILE */ +#include "lib/vfs/vfs.h" +#include "lib/fileloc.h" +#include "lib/strutil.h" +#include "lib/file-entry.h" +#include "lib/util.h" +#include "lib/widget.h" +#include "lib/keybind.h" /* CK_Down, CK_History */ +#include "lib/event.h" /* mc_event_raise() */ + +#include "src/setup.h" +#include "src/execute.h" /* toggle_panels() */ +#include "src/history.h" +#include "src/usermenu.h" /* MC_GLOBAL_MENU */ +#include "src/util.h" /* check_for_default() */ + +#include "src/viewer/mcviewer.h" + +#ifdef USE_INTERNAL_EDIT +#include "src/editor/edit.h" +#endif + +#ifdef USE_DIFF_VIEW +#include "src/diffviewer/ydiff.h" +#endif + +#include "fileopctx.h" +#include "filenot.h" +#include "hotlist.h" /* hotlist_show() */ +#include "tree.h" /* tree_chdir() */ +#include "filemanager.h" /* change_panel() */ +#include "command.h" /* cmdline */ +#include "layout.h" /* get_current_type() */ +#include "ext.h" /* regex_command() */ +#include "boxes.h" /* cd_box() */ +#include "dir.h" +#include "cd.h" + +#include "cmd.h" /* Our definitions */ + +/*** global variables ****************************************************************************/ + +/*** file scope macro definitions ****************************************************************/ + +#ifdef HAVE_MMAP +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif +#endif /* HAVE_MMAP */ + +/*** file scope type declarations ****************************************************************/ + +enum CompareMode +{ + compare_quick = 0, + compare_size_only, + compare_thourough +}; + +/*** forward declarations (file scope functions) *************************************************/ + +/*** file scope variables ************************************************************************/ + +#ifdef ENABLE_VFS_NET +static const char *machine_str = N_("Enter machine name (F1 for details):"); +#endif /* ENABLE_VFS_NET */ + +/* --------------------------------------------------------------------------------------------- */ +/*** file scope functions ************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ +/** + * Run viewer (internal or external) on the current file. + * If @plain_view is TRUE, force internal viewer and raw mode (used for F13). + */ +static void +do_view_cmd (WPanel * panel, gboolean plain_view) +{ + const file_entry_t *fe; + + fe = panel_current_entry (panel); + + /* Directories are viewed by changing to them */ + if (S_ISDIR (fe->st.st_mode) || link_isdir (fe)) + { + vfs_path_t *fname_vpath; + + if (confirm_view_dir && (panel->marked != 0 || panel->dirs_marked != 0) && + query_dialog (_("Confirmation"), _("Files tagged, want to cd?"), D_NORMAL, 2, + _("&Yes"), _("&No")) != 0) + return; + + fname_vpath = vfs_path_from_str (fe->fname->str); + if (!panel_cd (panel, fname_vpath, cd_exact)) + cd_error_message (fe->fname->str); + vfs_path_free (fname_vpath, TRUE); + } + else + { + vfs_path_t *filename_vpath; + + filename_vpath = vfs_path_from_str (fe->fname->str); + view_file (filename_vpath, plain_view, use_internal_view); + vfs_path_free (filename_vpath, TRUE); + } + + repaint_screen (); +} + +/* --------------------------------------------------------------------------------------------- */ + +static inline void +do_edit (const vfs_path_t * what_vpath) +{ + edit_file_at_line (what_vpath, use_internal_edit, 0); +} + +/* --------------------------------------------------------------------------------------------- */ + +static int +compare_files (const vfs_path_t * vpath1, const vfs_path_t * vpath2, off_t size) +{ + int file1; + int result = -1; /* Different by default */ + + if (size == 0) + return 0; + + file1 = open (vfs_path_as_str (vpath1), O_RDONLY); + if (file1 >= 0) + { + int file2; + + file2 = open (vfs_path_as_str (vpath2), O_RDONLY); + if (file2 >= 0) + { +#ifdef HAVE_MMAP + char *data1; + + /* Ugly if jungle */ + data1 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file1, 0); + if (data1 != (char *) -1) + { + char *data2; + + data2 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file2, 0); + if (data2 != (char *) -1) + { + rotate_dash (TRUE); + result = memcmp (data1, data2, size); + munmap (data2, size); + } + munmap (data1, size); + } +#else + /* Don't have mmap() :( Even more ugly :) */ + char buf1[BUFSIZ], buf2[BUFSIZ]; + int n1, n2; + + rotate_dash (TRUE); + do + { + while ((n1 = read (file1, buf1, sizeof (buf1))) == -1 && errno == EINTR) + ; + while ((n2 = read (file2, buf2, sizeof (buf2))) == -1 && errno == EINTR) + ; + } + while (n1 == n2 && n1 == sizeof (buf1) && memcmp (buf1, buf2, sizeof (buf1)) == 0); + result = (n1 != n2) || memcmp (buf1, buf2, n1); +#endif /* !HAVE_MMAP */ + close (file2); + } + close (file1); + } + rotate_dash (FALSE); + + return result; +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +compare_dir (WPanel * panel, const WPanel * other, enum CompareMode mode) +{ + int i, j; + + /* No marks by default */ + panel->marked = 0; + panel->total = 0; + panel->dirs_marked = 0; + + /* Handle all files in the panel */ + for (i = 0; i < panel->dir.len; i++) + { + file_entry_t *source = &panel->dir.list[i]; + const char *source_fname; + + /* Default: unmarked */ + file_mark (panel, i, 0); + + /* Skip directories */ + if (S_ISDIR (source->st.st_mode)) + continue; + + source_fname = source->fname->str; + if (panel->is_panelized) + source_fname = x_basename (source_fname); + + /* Search the corresponding entry from the other panel */ + for (j = 0; j < other->dir.len; j++) + { + const char *other_fname; + + other_fname = other->dir.list[j].fname->str; + if (other->is_panelized) + other_fname = x_basename (other_fname); + + if (strcmp (source_fname, other_fname) == 0) + break; + } + + if (j >= other->dir.len) + /* Not found -> mark */ + do_file_mark (panel, i, 1); + else + { + /* Found */ + file_entry_t *target = &other->dir.list[j]; + + if (mode != compare_size_only) + /* Older version is not marked */ + if (source->st.st_mtime < target->st.st_mtime) + continue; + + /* Newer version with different size is marked */ + if (source->st.st_size != target->st.st_size) + { + do_file_mark (panel, i, 1); + continue; + } + + if (mode == compare_size_only) + continue; + + if (mode == compare_quick) + { + /* Thorough compare off, compare only time stamps */ + /* Mark newer version, don't mark version with the same date */ + if (source->st.st_mtime > target->st.st_mtime) + do_file_mark (panel, i, 1); + + continue; + } + + /* Thorough compare on, do byte-by-byte comparison */ + { + vfs_path_t *src_name, *dst_name; + + src_name = + vfs_path_append_new (panel->cwd_vpath, source->fname->str, (char *) NULL); + dst_name = + vfs_path_append_new (other->cwd_vpath, target->fname->str, (char *) NULL); + if (compare_files (src_name, dst_name, source->st.st_size)) + do_file_mark (panel, i, 1); + vfs_path_free (src_name, TRUE); + vfs_path_free (dst_name, TRUE); + } + } + } /* for (i ...) */ +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +do_link (link_type_t link_type, const char *fname) +{ + char *dest = NULL, *src = NULL; + vfs_path_t *dest_vpath = NULL; + + if (link_type == LINK_HARDLINK) + { + vfs_path_t *fname_vpath; + + src = g_strdup_printf (_("Link %s to:"), str_trunc (fname, 46)); + dest = + input_expand_dialog (_("Link"), src, MC_HISTORY_FM_LINK, "", INPUT_COMPLETE_FILENAMES); + if (dest == NULL || *dest == '\0') + goto cleanup; + + save_cwds_stat (); + + fname_vpath = vfs_path_from_str (fname); + dest_vpath = vfs_path_from_str (dest); + if (mc_link (fname_vpath, dest_vpath) == -1) + message (D_ERROR, MSG_ERROR, _("link: %s"), unix_error_string (errno)); + vfs_path_free (fname_vpath, TRUE); + } + else + { + vfs_path_t *s, *d; + + /* suggest the full path for symlink, and either the full or + relative path to the file it points to */ + s = vfs_path_append_new (current_panel->cwd_vpath, fname, (char *) NULL); + + if (get_other_type () == view_listing) + d = vfs_path_append_new (other_panel->cwd_vpath, fname, (char *) NULL); + else + d = vfs_path_from_str (fname); + + if (link_type == LINK_SYMLINK_RELATIVE) + { + char *s_str; + + s_str = diff_two_paths (other_panel->cwd_vpath, s); + vfs_path_free (s, TRUE); + s = vfs_path_from_str_flags (s_str, VPF_NO_CANON); + g_free (s_str); + } + + symlink_box (s, d, &dest, &src); + vfs_path_free (d, TRUE); + vfs_path_free (s, TRUE); + + if (dest == NULL || *dest == '\0' || src == NULL || *src == '\0') + goto cleanup; + + save_cwds_stat (); + + dest_vpath = vfs_path_from_str_flags (dest, VPF_NO_CANON); + + s = vfs_path_from_str (src); + if (mc_symlink (dest_vpath, s) == -1) + message (D_ERROR, MSG_ERROR, _("symlink: %s"), unix_error_string (errno)); + vfs_path_free (s, TRUE); + } + + update_panels (UP_OPTIMIZE, UP_KEEPSEL); + repaint_screen (); + + cleanup: + vfs_path_free (dest_vpath, TRUE); + g_free (src); + g_free (dest); +} + +/* --------------------------------------------------------------------------------------------- */ + +#if defined(ENABLE_VFS_UNDELFS) || defined(ENABLE_VFS_NET) +static void +nice_cd (const char *text, const char *xtext, const char *help, + const char *history_name, const char *prefix, int to_home, gboolean strip_password) +{ + char *machine; + char *cd_path; + + machine = + input_dialog_help (text, xtext, help, history_name, INPUT_LAST_TEXT, strip_password, + INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD | INPUT_COMPLETE_HOSTNAMES | + INPUT_COMPLETE_USERNAMES); + if (machine == NULL) + return; + + to_home = 0; /* FIXME: how to solve going to home nicely? /~/ is + ugly as hell and leads to problems in vfs layer */ + + if (strncmp (prefix, machine, strlen (prefix)) == 0) + cd_path = g_strconcat (machine, to_home ? "/~/" : (char *) NULL, (char *) NULL); + else + cd_path = g_strconcat (prefix, machine, to_home ? "/~/" : (char *) NULL, (char *) NULL); + + g_free (machine); + + if (!IS_PATH_SEP (*cd_path)) + { + char *tmp = cd_path; + + cd_path = g_strconcat (PATH_SEP_STR, tmp, (char *) NULL); + g_free (tmp); + } + + { + panel_view_mode_t save_type; + vfs_path_t *cd_vpath; + + save_type = get_panel_type (MENU_PANEL_IDX); + + if (save_type != view_listing) + create_panel (MENU_PANEL_IDX, view_listing); + + cd_vpath = vfs_path_from_str_flags (cd_path, VPF_NO_CANON); + if (!panel_do_cd (MENU_PANEL, cd_vpath, cd_parse_command)) + { + cd_error_message (cd_path); + + if (save_type != view_listing) + create_panel (MENU_PANEL_IDX, save_type); + } + vfs_path_free (cd_vpath, TRUE); + } + g_free (cd_path); + + /* In case of passive panel, restore current VFS directory that was changed in panel_do_cd() */ + if (MENU_PANEL != current_panel) + (void) mc_chdir (current_panel->cwd_vpath); +} +#endif /* ENABLE_VFS_UNDELFS || ENABLE_VFS_NET */ + +/* --------------------------------------------------------------------------------------------- */ + +static void +configure_panel_listing (WPanel * p, int list_format, int brief_cols, gboolean use_msformat, + char **user, char **status) +{ + p->user_mini_status = use_msformat; + p->list_format = list_format; + + if (list_format == list_brief) + p->brief_cols = brief_cols; + + if (list_format == list_user || use_msformat) + { + g_free (p->user_format); + p->user_format = *user; + *user = NULL; + + g_free (p->user_status_format[list_format]); + p->user_status_format[list_format] = *status; + *status = NULL; + + set_panel_formats (p); + } + + set_panel_formats (p); + do_refresh (); +} + +/* --------------------------------------------------------------------------------------------- */ + +static void +switch_to_listing (int panel_index) +{ + if (get_panel_type (panel_index) != view_listing) + create_panel (panel_index, view_listing); +} + +/* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +gboolean +view_file_at_line (const vfs_path_t * filename_vpath, gboolean plain_view, gboolean internal, + long start_line, off_t search_start, off_t search_end) +{ + gboolean ret = TRUE; + + if (plain_view) + { + mcview_mode_flags_t changed_flags; + + mcview_clear_mode_flags (&changed_flags); + mcview_altered_flags.hex = FALSE; + mcview_altered_flags.magic = FALSE; + mcview_altered_flags.nroff = FALSE; + if (mcview_global_flags.hex) + changed_flags.hex = TRUE; + if (mcview_global_flags.magic) + changed_flags.magic = TRUE; + if (mcview_global_flags.nroff) + changed_flags.nroff = TRUE; + mcview_global_flags.hex = FALSE; + mcview_global_flags.magic = FALSE; + mcview_global_flags.nroff = FALSE; + + ret = mcview_viewer (NULL, filename_vpath, start_line, search_start, search_end); + + if (changed_flags.hex && !mcview_altered_flags.hex) + mcview_global_flags.hex = TRUE; + if (changed_flags.magic && !mcview_altered_flags.magic) + mcview_global_flags.magic = TRUE; + if (changed_flags.nroff && !mcview_altered_flags.nroff) + mcview_global_flags.nroff = TRUE; + + dialog_switch_process_pending (); + } + else if (internal) + { + char view_entry[BUF_TINY]; + + if (start_line > 0) + g_snprintf (view_entry, sizeof (view_entry), "View:%ld", start_line); + else + strcpy (view_entry, "View"); + + ret = (regex_command (filename_vpath, view_entry) == 0); + if (ret) + { + ret = mcview_viewer (NULL, filename_vpath, start_line, search_start, search_end); + dialog_switch_process_pending (); + } + } + else + { + static const char *viewer = NULL; + + if (viewer == NULL) + { + viewer = getenv ("VIEWER"); + if (viewer == NULL) + viewer = getenv ("PAGER"); + if (viewer == NULL) + viewer = "view"; + } + + execute_external_editor_or_viewer (viewer, filename_vpath, start_line); + } + + return ret; +} + +/* --------------------------------------------------------------------------------------------- */ +/** view_file (filename, plain_view, internal) + * + * Inputs: + * filename_vpath: The file name to view + * plain_view: If set does not do any fancy pre-processing (no filtering) and + * always invokes the internal viewer. + * internal: If set uses the internal viewer, otherwise an external viewer. + */ + +gboolean +view_file (const vfs_path_t * filename_vpath, gboolean plain_view, gboolean internal) +{ + return view_file_at_line (filename_vpath, plain_view, internal, 0, 0, 0); +} + + +/* --------------------------------------------------------------------------------------------- */ +/** Run user's preferred viewer on the current file */ + +void +view_cmd (WPanel * panel) +{ + do_view_cmd (panel, FALSE); +} + +/* --------------------------------------------------------------------------------------------- */ +/** Ask for file and run user's preferred viewer on it */ + +void +view_file_cmd (const WPanel * panel) +{ + char *filename; + vfs_path_t *vpath; + + filename = + input_expand_dialog (_("View file"), _("Filename:"), + MC_HISTORY_FM_VIEW_FILE, panel_current_entry (panel)->fname->str, + INPUT_COMPLETE_FILENAMES); + if (filename == NULL) + return; + + vpath = vfs_path_from_str (filename); + g_free (filename); + view_file (vpath, FALSE, use_internal_view); + vfs_path_free (vpath, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ +/** Run plain internal viewer on the current file */ +void +view_raw_cmd (WPanel * panel) +{ + do_view_cmd (panel, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +view_filtered_cmd (const WPanel * panel) +{ + char *command; + const char *initial_command; + + if (input_is_empty (cmdline)) + initial_command = panel_current_entry (panel)->fname->str; + else + initial_command = input_get_ctext (cmdline); + + command = + input_dialog (_("Filtered view"), + _("Filter command and arguments:"), + MC_HISTORY_FM_FILTERED_VIEW, initial_command, + INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_COMMANDS); + + if (command != NULL) + { + mcview_viewer (command, NULL, 0, 0, 0); + g_free (command); + dialog_switch_process_pending (); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +void +edit_file_at_line (const vfs_path_t * what_vpath, gboolean internal, long start_line) +{ + +#ifdef USE_INTERNAL_EDIT + if (internal) + edit_file (what_vpath, start_line); + else +#endif /* USE_INTERNAL_EDIT */ + { + static const char *editor = NULL; + + (void) internal; + + if (editor == NULL) + { + editor = getenv ("EDITOR"); + if (editor == NULL) + editor = get_default_editor (); + } + + execute_external_editor_or_viewer (editor, what_vpath, start_line); + } + + if (mc_global.mc_run_mode == MC_RUN_FULL) + update_panels (UP_OPTIMIZE, UP_KEEPSEL); + +#ifdef USE_INTERNAL_EDIT + if (use_internal_edit) + dialog_switch_process_pending (); + else +#endif /* USE_INTERNAL_EDIT */ + repaint_screen (); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +edit_cmd (const WPanel * panel) +{ + vfs_path_t *fname; + + fname = vfs_path_from_str (panel_current_entry (panel)->fname->str); + if (regex_command (fname, "Edit") == 0) + do_edit (fname); + vfs_path_free (fname, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +#ifdef USE_INTERNAL_EDIT +void +edit_cmd_force_internal (const WPanel * panel) +{ + vfs_path_t *fname; + + fname = vfs_path_from_str (panel_current_entry (panel)->fname->str); + if (regex_command (fname, "Edit") == 0) + edit_file_at_line (fname, TRUE, 1); + vfs_path_free (fname, TRUE); +} +#endif + +/* --------------------------------------------------------------------------------------------- */ + +void +edit_cmd_new (void) +{ + vfs_path_t *fname_vpath = NULL; + + if (editor_ask_filename_before_edit) + { + char *fname; + + fname = input_expand_dialog (_("Edit file"), _("Enter file name:"), + MC_HISTORY_EDIT_LOAD, "", INPUT_COMPLETE_FILENAMES); + if (fname == NULL) + return; + + if (*fname != '\0') + fname_vpath = vfs_path_from_str (fname); + + g_free (fname); + } + +#ifdef HAVE_CHARSET + mc_global.source_codepage = default_source_codepage; +#endif + do_edit (fname_vpath); + + vfs_path_free (fname_vpath, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +mkdir_cmd (WPanel * panel) +{ + const file_entry_t *fe; + char *dir; + const char *name = ""; + + fe = panel_current_entry (panel); + + /* If 'on' then automatically fills name with current item name */ + if (auto_fill_mkdir_name && !DIR_IS_DOTDOT (fe->fname->str)) + name = fe->fname->str; + + dir = + input_expand_dialog (_("Create a new Directory"), + _("Enter directory name:"), MC_HISTORY_FM_MKDIR, name, + INPUT_COMPLETE_FILENAMES); + + if (dir != NULL && *dir != '\0') + { + vfs_path_t *absdir; + + if (IS_PATH_SEP (dir[0]) || dir[0] == '~') + absdir = vfs_path_from_str (dir); + else + { + /* possible escaped '~' */ + /* allow create directory with name '~' */ + char *tmpdir = dir; + + if (dir[0] == '\\' && dir[1] == '~') + tmpdir = dir + 1; + + absdir = vfs_path_append_new (panel->cwd_vpath, tmpdir, (char *) NULL); + } + + save_cwds_stat (); + + if (my_mkdir (absdir, 0777) != 0) + message (D_ERROR, MSG_ERROR, "%s", unix_error_string (errno)); + else + { + update_panels (UP_OPTIMIZE, dir); + repaint_screen (); + select_item (panel); + } + + vfs_path_free (absdir, TRUE); + } + g_free (dir); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +reread_cmd (void) +{ + panel_update_flags_t flag = UP_ONLY_CURRENT; + + if (get_current_type () == view_listing && get_other_type () == view_listing && + vfs_path_equal (current_panel->cwd_vpath, other_panel->cwd_vpath)) + flag = UP_OPTIMIZE; + + update_panels (UP_RELOAD | flag, UP_KEEPSEL); + repaint_screen (); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +ext_cmd (void) +{ + vfs_path_t *extdir_vpath; + int dir = 0; + + if (geteuid () == 0) + dir = query_dialog (_("Extension file edit"), + _("Which extension file you want to edit?"), D_NORMAL, 2, + _("&User"), _("&System Wide")); + + extdir_vpath = vfs_path_build_filename (mc_global.sysconfig_dir, MC_EXT_FILE, (char *) NULL); + + if (dir == 0) + { + vfs_path_t *buffer_vpath; + + buffer_vpath = mc_config_get_full_vpath (MC_EXT_FILE); + check_for_default (extdir_vpath, buffer_vpath); + do_edit (buffer_vpath); + vfs_path_free (buffer_vpath, TRUE); + } + else if (dir == 1) + { + if (!exist_file (vfs_path_get_last_path_str (extdir_vpath))) + { + vfs_path_free (extdir_vpath, TRUE); + extdir_vpath = + vfs_path_build_filename (mc_global.share_data_dir, MC_EXT_FILE, (char *) NULL); + } + do_edit (extdir_vpath); + } + + vfs_path_free (extdir_vpath, TRUE); + flush_extension_file (); +} + +/* --------------------------------------------------------------------------------------------- */ +/** edit file menu for mc */ + +void +edit_mc_menu_cmd (void) +{ + vfs_path_t *buffer_vpath; + vfs_path_t *menufile_vpath; + int dir = 0; + + query_set_sel (1); + dir = query_dialog (_("Menu edit"), + _("Which menu file do you want to edit?"), + D_NORMAL, geteuid ()? 2 : 3, _("&Local"), _("&User"), _("&System Wide")); + + menufile_vpath = + vfs_path_build_filename (mc_global.sysconfig_dir, MC_GLOBAL_MENU, (char *) NULL); + + if (!exist_file (vfs_path_get_last_path_str (menufile_vpath))) + { + vfs_path_free (menufile_vpath, TRUE); + menufile_vpath = + vfs_path_build_filename (mc_global.share_data_dir, MC_GLOBAL_MENU, (char *) NULL); + } + + switch (dir) + { + case 0: + buffer_vpath = vfs_path_from_str (MC_LOCAL_MENU); + check_for_default (menufile_vpath, buffer_vpath); + chmod (vfs_path_get_last_path_str (buffer_vpath), 0600); + break; + + case 1: + buffer_vpath = mc_config_get_full_vpath (MC_USERMENU_FILE); + check_for_default (menufile_vpath, buffer_vpath); + break; + + case 2: + buffer_vpath = + vfs_path_build_filename (mc_global.sysconfig_dir, MC_GLOBAL_MENU, (char *) NULL); + if (!exist_file (vfs_path_get_last_path_str (buffer_vpath))) + { + vfs_path_free (buffer_vpath, TRUE); + buffer_vpath = + vfs_path_build_filename (mc_global.share_data_dir, MC_GLOBAL_MENU, (char *) NULL); + } + break; + + default: + vfs_path_free (menufile_vpath, TRUE); + return; + } + + do_edit (buffer_vpath); + + vfs_path_free (buffer_vpath, TRUE); + vfs_path_free (menufile_vpath, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +edit_fhl_cmd (void) +{ + vfs_path_t *fhlfile_vpath = NULL; + int dir = 0; + + if (geteuid () == 0) + dir = query_dialog (_("Highlighting groups file edit"), + _("Which highlighting file you want to edit?"), D_NORMAL, 2, + _("&User"), _("&System Wide")); + + fhlfile_vpath = + vfs_path_build_filename (mc_global.sysconfig_dir, MC_FHL_INI_FILE, (char *) NULL); + + if (dir == 0) + { + vfs_path_t *buffer_vpath; + + buffer_vpath = mc_config_get_full_vpath (MC_FHL_INI_FILE); + check_for_default (fhlfile_vpath, buffer_vpath); + do_edit (buffer_vpath); + vfs_path_free (buffer_vpath, TRUE); + } + else if (dir == 1) + { + if (!exist_file (vfs_path_get_last_path_str (fhlfile_vpath))) + { + vfs_path_free (fhlfile_vpath, TRUE); + fhlfile_vpath = + vfs_path_build_filename (mc_global.sysconfig_dir, MC_FHL_INI_FILE, (char *) NULL); + } + do_edit (fhlfile_vpath); + } + + vfs_path_free (fhlfile_vpath, TRUE); + /* refresh highlighting rules */ + mc_fhl_free (&mc_filehighlight); + mc_filehighlight = mc_fhl_new (TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +hotlist_cmd (WPanel * panel) +{ + char *target; + + target = hotlist_show (LIST_HOTLIST, panel); + if (target == NULL) + return; + + if (get_current_type () == view_tree) + { + vfs_path_t *vpath; + + vpath = vfs_path_from_str (target); + tree_chdir (the_tree, vpath); + vfs_path_free (vpath, TRUE); + } + else + { + vfs_path_t *deprecated_vpath; + const char *deprecated_path; + + deprecated_vpath = vfs_path_from_str_flags (target, VPF_USE_DEPRECATED_PARSER); + deprecated_path = vfs_path_as_str (deprecated_vpath); + cd_to (deprecated_path); + vfs_path_free (deprecated_vpath, TRUE); + } + + g_free (target); +} + +/* --------------------------------------------------------------------------------------------- */ + +#ifdef ENABLE_VFS +void +vfs_list (WPanel * panel) +{ + char *target; + vfs_path_t *target_vpath; + + target = hotlist_show (LIST_VFSLIST, panel); + if (target == NULL) + return; + + target_vpath = vfs_path_from_str (target); + if (!panel_cd (current_panel, target_vpath, cd_exact)) + cd_error_message (target); + vfs_path_free (target_vpath, TRUE); + g_free (target); +} +#endif /* ENABLE_VFS */ + +/* --------------------------------------------------------------------------------------------- */ + +void +compare_dirs_cmd (void) +{ + int choice; + enum CompareMode thorough_flag; + + choice = + query_dialog (_("Compare directories"), + _("Select compare method:"), D_NORMAL, 4, + _("&Quick"), _("&Size only"), _("&Thorough"), _("&Cancel")); + + if (choice < 0 || choice > 2) + return; + + thorough_flag = choice; + + if (get_current_type () == view_listing && get_other_type () == view_listing) + { + compare_dir (current_panel, other_panel, thorough_flag); + compare_dir (other_panel, current_panel, thorough_flag); + } + else + message (D_ERROR, MSG_ERROR, + _("Both panels should be in the listing mode\nto use this command")); +} + +/* --------------------------------------------------------------------------------------------- */ + +#ifdef USE_DIFF_VIEW +void +diff_view_cmd (void) +{ + /* both panels must be in the list mode */ + if (get_current_type () == view_listing && get_other_type () == view_listing) + { + if (get_current_index () == 0) + dview_diff_cmd (current_panel, other_panel); + else + dview_diff_cmd (other_panel, current_panel); + + if (mc_global.mc_run_mode == MC_RUN_FULL) + update_panels (UP_OPTIMIZE, UP_KEEPSEL); + + dialog_switch_process_pending (); + } +} +#endif + +/* --------------------------------------------------------------------------------------------- */ + +void +swap_cmd (void) +{ + swap_panels (); + tty_touch_screen (); + repaint_screen (); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +link_cmd (link_type_t link_type) +{ + const char *filename; + + filename = panel_current_entry (current_panel)->fname->str; + if (filename != NULL) + do_link (link_type, filename); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +edit_symlink_cmd (void) +{ + const file_entry_t *fe; + const char *p; + + fe = panel_current_entry (current_panel); + p = fe->fname->str; + + if (!S_ISLNK (fe->st.st_mode)) + message (D_ERROR, MSG_ERROR, _("'%s' is not a symbolic link"), p); + else + { + char buffer[MC_MAXPATHLEN]; + int i; + + i = readlink (p, buffer, sizeof (buffer) - 1); + if (i > 0) + { + char *q, *dest; + + buffer[i] = '\0'; + + q = g_strdup_printf (_("Symlink '%s\' points to:"), str_trunc (p, 32)); + dest = + input_expand_dialog (_("Edit symlink"), q, MC_HISTORY_FM_EDIT_LINK, buffer, + INPUT_COMPLETE_FILENAMES); + g_free (q); + + if (dest != NULL && *dest != '\0' && strcmp (buffer, dest) != 0) + { + vfs_path_t *p_vpath; + + p_vpath = vfs_path_from_str (p); + + save_cwds_stat (); + + if (mc_unlink (p_vpath) == -1) + message (D_ERROR, MSG_ERROR, _("edit symlink, unable to remove %s: %s"), p, + unix_error_string (errno)); + else + { + vfs_path_t *dest_vpath; + + dest_vpath = vfs_path_from_str_flags (dest, VPF_NO_CANON); + if (mc_symlink (dest_vpath, p_vpath) == -1) + message (D_ERROR, MSG_ERROR, _("edit symlink: %s"), + unix_error_string (errno)); + vfs_path_free (dest_vpath, TRUE); + } + + vfs_path_free (p_vpath, TRUE); + + update_panels (UP_OPTIMIZE, UP_KEEPSEL); + repaint_screen (); + } + + g_free (dest); + } + } +} + +/* --------------------------------------------------------------------------------------------- */ + +void +help_cmd (void) +{ + ev_help_t event_data = { NULL, NULL }; + + if (current_panel->quick_search.active) + event_data.node = "[Quick search]"; + else + event_data.node = "[main]"; + + mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +user_file_menu_cmd (void) +{ + (void) user_menu_cmd (NULL, NULL, -1); +} + +/* --------------------------------------------------------------------------------------------- */ + +#ifdef ENABLE_VFS_FTP +void +ftplink_cmd (void) +{ + nice_cd (_("FTP to machine"), _(machine_str), + "[FTP File System]", ":ftplink_cmd: FTP to machine ", "ftp://", 1, TRUE); +} +#endif /* ENABLE_VFS_FTP */ + +/* --------------------------------------------------------------------------------------------- */ + +#ifdef ENABLE_VFS_SFTP +void +sftplink_cmd (void) +{ + nice_cd (_("SFTP to machine"), _(machine_str), + "[SFTP (SSH File Transfer Protocol) filesystem]", + ":sftplink_cmd: SFTP to machine ", "sftp://", 1, TRUE); +} +#endif /* ENABLE_VFS_SFTP */ + +/* --------------------------------------------------------------------------------------------- */ + +#ifdef ENABLE_VFS_FISH +void +fishlink_cmd (void) +{ + nice_cd (_("Shell link to machine"), _(machine_str), + "[FIle transfer over SHell filesystem]", ":fishlink_cmd: Shell link to machine ", + "sh://", 1, TRUE); +} +#endif /* ENABLE_VFS_FISH */ + +/* --------------------------------------------------------------------------------------------- */ + +#ifdef ENABLE_VFS_UNDELFS +void +undelete_cmd (void) +{ + nice_cd (_("Undelete files on an ext2 file system"), + _("Enter device (without /dev/) to undelete\nfiles on: (F1 for details)"), + "[Undelete File System]", ":undelete_cmd: Undel on ext2 fs ", "undel://", 0, FALSE); +} +#endif /* ENABLE_VFS_UNDELFS */ + +/* --------------------------------------------------------------------------------------------- */ + +void +quick_cd_cmd (WPanel * panel) +{ + char *p; + + p = cd_box (panel); + if (p != NULL && *p != '\0') + cd_to (p); + g_free (p); +} + +/* --------------------------------------------------------------------------------------------- */ +/*! + \brief calculate dirs sizes + + calculate dirs sizes and resort panel: + dirs_selected = show size for selected dirs, + otherwise = show size for dir under cursor: + dir under cursor ".." = show size for all dirs, + otherwise = show size for dir under cursor + */ + +void +smart_dirsize_cmd (WPanel * panel) +{ + const file_entry_t *entry; + + entry = panel_current_entry (panel); + if ((S_ISDIR (entry->st.st_mode) && DIR_IS_DOTDOT (entry->fname->str)) || panel->dirs_marked) + dirsizes_cmd (panel); + else + single_dirsize_cmd (panel); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +single_dirsize_cmd (WPanel * panel) +{ + file_entry_t *entry; + + entry = panel_current_entry (panel); + + if (S_ISDIR (entry->st.st_mode) && !DIR_IS_DOTDOT (entry->fname->str)) + { + size_t dir_count = 0; + size_t count = 0; + uintmax_t total = 0; + dirsize_status_msg_t dsm; + vfs_path_t *p; + + p = vfs_path_from_str (entry->fname->str); + + memset (&dsm, 0, sizeof (dsm)); + status_msg_init (STATUS_MSG (&dsm), _("Directory scanning"), 0, dirsize_status_init_cb, + dirsize_status_update_cb, dirsize_status_deinit_cb); + + if (compute_dir_size (p, &dsm, &dir_count, &count, &total, FALSE) == FILE_CONT) + { + entry->st.st_size = (off_t) total; + entry->f.dir_size_computed = 1; + } + + vfs_path_free (p, TRUE); + + status_msg_deinit (STATUS_MSG (&dsm)); + } + + if (panels_options.mark_moves_down) + send_message (panel, NULL, MSG_ACTION, CK_Down, NULL); + + recalculate_panel_summary (panel); + + if (panel->sort_field->sort_routine == (GCompareFunc) sort_size) + panel_re_sort (panel); + + panel->dirty = TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ + +void +dirsizes_cmd (WPanel * panel) +{ + int i; + dirsize_status_msg_t dsm; + + memset (&dsm, 0, sizeof (dsm)); + status_msg_init (STATUS_MSG (&dsm), _("Directory scanning"), 0, dirsize_status_init_cb, + dirsize_status_update_cb, dirsize_status_deinit_cb); + + for (i = 0; i < panel->dir.len; i++) + if (S_ISDIR (panel->dir.list[i].st.st_mode) + && ((panel->dirs_marked != 0 && panel->dir.list[i].f.marked != 0) + || panel->dirs_marked == 0) && !DIR_IS_DOTDOT (panel->dir.list[i].fname->str)) + { + vfs_path_t *p; + size_t dir_count = 0; + size_t count = 0; + uintmax_t total = 0; + gboolean ok; + + p = vfs_path_from_str (panel->dir.list[i].fname->str); + ok = compute_dir_size (p, &dsm, &dir_count, &count, &total, FALSE) != FILE_CONT; + vfs_path_free (p, TRUE); + if (ok) + break; + + panel->dir.list[i].st.st_size = (off_t) total; + panel->dir.list[i].f.dir_size_computed = 1; + } + + status_msg_deinit (STATUS_MSG (&dsm)); + + recalculate_panel_summary (panel); + + if (panel->sort_field->sort_routine == (GCompareFunc) sort_size) + panel_re_sort (panel); + + panel->dirty = TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ + +void +save_setup_cmd (void) +{ + vfs_path_t *vpath; + const char *path; + + vpath = vfs_path_from_str_flags (mc_config_get_path (), VPF_STRIP_HOME); + path = vfs_path_as_str (vpath); + + if (save_setup (TRUE, TRUE)) + message (D_NORMAL, _("Setup"), _("Setup saved to %s"), path); + else + message (D_ERROR, _("Setup"), _("Unable to save setup to %s"), path); + + vfs_path_free (vpath, TRUE); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +info_cmd_no_menu (void) +{ + if (get_panel_type (0) == view_info) + create_panel (0, view_listing); + else if (get_panel_type (1) == view_info) + create_panel (1, view_listing); + else + create_panel (current_panel == left_panel ? 1 : 0, view_info); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +quick_cmd_no_menu (void) +{ + if (get_panel_type (0) == view_quick) + create_panel (0, view_listing); + else if (get_panel_type (1) == view_quick) + create_panel (1, view_listing); + else + create_panel (current_panel == left_panel ? 1 : 0, view_quick); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +listing_cmd (void) +{ + WPanel *p; + + switch_to_listing (MENU_PANEL_IDX); + + p = PANEL (get_panel_widget (MENU_PANEL_IDX)); + + p->is_panelized = FALSE; + panel_set_filter (p, NULL); /* including panel reload */ +} + +/* --------------------------------------------------------------------------------------------- */ + +void +setup_listing_format_cmd (void) +{ + int list_format; + gboolean use_msformat; + int brief_cols; + char *user, *status; + WPanel *p = NULL; + + if (SELECTED_IS_PANEL) + p = MENU_PANEL_IDX == 0 ? left_panel : right_panel; + + list_format = panel_listing_box (p, MENU_PANEL_IDX, &user, &status, &use_msformat, &brief_cols); + if (list_format != -1) + { + switch_to_listing (MENU_PANEL_IDX); + p = MENU_PANEL_IDX == 0 ? left_panel : right_panel; + configure_panel_listing (p, list_format, brief_cols, use_msformat, &user, &status); + g_free (user); + g_free (status); + } +} + +/* --------------------------------------------------------------------------------------------- */ + +void +panel_tree_cmd (void) +{ + create_panel (MENU_PANEL_IDX, view_tree); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +info_cmd (void) +{ + create_panel (MENU_PANEL_IDX, view_info); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +quick_view_cmd (void) +{ + if (PANEL (get_panel_widget (MENU_PANEL_IDX)) == current_panel) + (void) change_panel (); + create_panel (MENU_PANEL_IDX, view_quick); +} + +/* --------------------------------------------------------------------------------------------- */ + +#ifdef HAVE_CHARSET +void +encoding_cmd (void) +{ + if (SELECTED_IS_PANEL) + panel_change_encoding (MENU_PANEL); +} +#endif + +/* --------------------------------------------------------------------------------------------- */ |