Blame src/commands.cc

Packit 8f70b4
/*
Packit 8f70b4
 * lftp - file transfer program
Packit 8f70b4
 *
Packit 8f70b4
 * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net)
Packit 8f70b4
 *
Packit 8f70b4
 * This program is free software; you can redistribute it and/or modify
Packit 8f70b4
 * it under the terms of the GNU General Public License as published by
Packit 8f70b4
 * the Free Software Foundation; either version 3 of the License, or
Packit 8f70b4
 * (at your option) any later version.
Packit 8f70b4
 *
Packit 8f70b4
 * This program is distributed in the hope that it will be useful,
Packit 8f70b4
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8f70b4
 * GNU General Public License for more details.
Packit 8f70b4
 *
Packit 8f70b4
 * You should have received a copy of the GNU General Public License
Packit 8f70b4
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 8f70b4
 */
Packit 8f70b4
Packit 8f70b4
#include <config.h>
Packit 8f70b4
Packit 8f70b4
#include "modconfig.h"
Packit 8f70b4
Packit 8f70b4
#include "trio.h"
Packit 8f70b4
#include <unistd.h>
Packit 8f70b4
#include <errno.h>
Packit 8f70b4
#include <ctype.h>
Packit 8f70b4
#include <pwd.h>
Packit 8f70b4
#include <sys/types.h>
Packit 8f70b4
#include <sys/stat.h>
Packit 8f70b4
#include <sys/wait.h>
Packit 8f70b4
#include <fcntl.h>
Packit 8f70b4
#include <assert.h>
Packit 8f70b4
#ifdef HAVE_DLFCN_H
Packit 8f70b4
# include <dlfcn.h>
Packit 8f70b4
#endif
Packit 8f70b4
#include <mbswidth.h>
Packit 8f70b4
#include <human.h>
Packit 8f70b4
Packit 8f70b4
#include "CmdExec.h"
Packit 8f70b4
#include "GetJob.h"
Packit 8f70b4
#include "CatJob.h"
Packit 8f70b4
#include "LsCache.h"
Packit 8f70b4
#include "mgetJob.h"
Packit 8f70b4
#include "mkdirJob.h"
Packit 8f70b4
#include "rmJob.h"
Packit 8f70b4
#include "SysCmdJob.h"
Packit 8f70b4
#include "mvJob.h"
Packit 8f70b4
#include "pgetJob.h"
Packit 8f70b4
#include "SleepJob.h"
Packit 8f70b4
#include "FindJob.h"
Packit 8f70b4
#include "FindJobDu.h"
Packit 8f70b4
#include "ChmodJob.h"
Packit 8f70b4
#include "CopyJob.h"
Packit 8f70b4
#include "OutputJob.h"
Packit 8f70b4
#include "echoJob.h"
Packit 8f70b4
#include "EditJob.h"
Packit 8f70b4
#include "mmvJob.h"
Packit 8f70b4
Packit 8f70b4
#include "misc.h"
Packit 8f70b4
#include "alias.h"
Packit 8f70b4
#include "netrc.h"
Packit 8f70b4
#include "url.h"
Packit 8f70b4
#include "GetPass.h"
Packit 8f70b4
#include "SignalHook.h"
Packit 8f70b4
#include "FileFeeder.h"
Packit 8f70b4
#include "bookmark.h"
Packit 8f70b4
#include "log.h"
Packit 8f70b4
#include "module.h"
Packit 8f70b4
#include "FileCopy.h"
Packit 8f70b4
#include "DummyProto.h"
Packit 8f70b4
#include "QueueFeeder.h"
Packit 8f70b4
#include "lftp_rl.h"
Packit 8f70b4
#include "FileSetOutput.h"
Packit 8f70b4
#include "PatternSet.h"
Packit 8f70b4
#include "LocalDir.h"
Packit 8f70b4
#include "ConnectionSlot.h"
Packit 8f70b4
Packit 8f70b4
#include "configmake.h"
Packit 8f70b4
Packit 8f70b4
History	 cwd_history;
Packit 8f70b4
Packit 8f70b4
CMD(alias); CMD(anon); CMD(at); CMD(bookmark); CMD(cache); CMD(cat);
Packit 8f70b4
CMD(cd); CMD(chmod); CMD(close); CMD(cls); CMD(command); CMD(debug);
Packit 8f70b4
CMD(du); CMD(echo); CMD(edit); CMD(eval); CMD(exit); CMD(find); CMD(get);
Packit 8f70b4
CMD(get1); CMD(glob); CMD(help); CMD(jobs); CMD(kill); CMD(lcd); CMD(lftp);
Packit 8f70b4
CMD(ln); CMD(local); CMD(lpwd); CMD(ls); CMD(mirror); CMD(mkdir);
Packit 8f70b4
CMD(module); CMD(mrm); CMD(mv); CMD(open); CMD(pwd); CMD(queue);
Packit 8f70b4
CMD(repeat); CMD(rm); CMD(scache); CMD(set); CMD(shell); CMD(sleep);
Packit 8f70b4
CMD(slot); CMD(source); CMD(subsh); CMD(suspend); CMD(tasks); CMD(torrent);
Packit 8f70b4
CMD(user); CMD(ver); CMD(wait); CMD(empty); CMD(notempty); CMD(true);
Packit 8f70b4
CMD(false); CMD(mmv);
Packit 8f70b4
Packit 8f70b4
#define HELP_IN_MODULE "m"
Packit 8f70b4
#define ALIAS_FOR(cmd) cmd_##cmd,0,#cmd
Packit 8f70b4
#define ALIAS_FOR2(a,cmd) cmd_##cmd,0,a
Packit 8f70b4
Packit 8f70b4
#ifdef MODULE_CMD_MIRROR
Packit 8f70b4
# define cmd_mirror 0
Packit 8f70b4
#endif
Packit 8f70b4
#ifdef MODULE_CMD_SLEEP
Packit 8f70b4
# define cmd_sleep  0
Packit 8f70b4
# define cmd_at     0
Packit 8f70b4
# define cmd_repeat 0
Packit 8f70b4
#endif
Packit 8f70b4
#ifdef MODULE_CMD_TORRENT
Packit 8f70b4
# define cmd_torrent 0
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
enum { DEFAULT_DEBUG_LEVEL=9 };
Packit 8f70b4
Packit 8f70b4
const struct CmdExec::cmd_rec CmdExec::static_cmd_table[]=
Packit 8f70b4
{
Packit 8f70b4
   {"!",       cmd_shell,  N_("!<shell-command>"),
Packit 8f70b4
	 N_("Launch shell or shell command\n")},
Packit 8f70b4
   {"(",       cmd_subsh,  N_("(commands)"),
Packit 8f70b4
	 N_("Group commands together to be executed as one command\n"
Packit 8f70b4
	 "You can launch such a group in background\n")},
Packit 8f70b4
   {"?", ALIAS_FOR(help)},
Packit 8f70b4
   {"alias",   cmd_alias,  N_("alias [<name> [<value>]]"),
Packit 8f70b4
	 N_("Define or undefine alias <name>. If <value> omitted,\n"
Packit 8f70b4
	 "the alias is undefined, else is takes the value <value>.\n"
Packit 8f70b4
         "If no argument is given the current aliases are listed.\n")},
Packit 8f70b4
   {"anon",    cmd_anon,   0,
Packit 8f70b4
	 N_("anon - login anonymously (by default)\n")},
Packit 8f70b4
   {"at",      cmd_at, 0, HELP_IN_MODULE},
Packit 8f70b4
   {"bookmark",cmd_bookmark,N_("bookmark [SUBCMD]"),
Packit 8f70b4
	 N_("bookmark command controls bookmarks\n\n"
Packit 8f70b4
	 "The following subcommands are recognized:\n"
Packit 8f70b4
	 "  add <name> [<loc>] - add current place or given location to bookmarks\n"
Packit 8f70b4
	 "                       and bind to given name\n"
Packit 8f70b4
	 "  del <name>         - remove bookmark with the name\n"
Packit 8f70b4
	 "  edit               - start editor on bookmarks file\n"
Packit 8f70b4
	 "  import <type>      - import foreign bookmarks\n"
Packit 8f70b4
	 "  list               - list bookmarks (default)\n")},
Packit 8f70b4
   {"bye", ALIAS_FOR(exit)},
Packit 8f70b4
   {"cache",   cmd_cache,  N_("cache [SUBCMD]"),
Packit 8f70b4
	 N_("cache command controls local memory cache\n\n"
Packit 8f70b4
	 "The following subcommands are recognized:\n"
Packit 8f70b4
	 "  stat        - print cache status (default)\n"
Packit 8f70b4
	 "  on|off      - turn on/off caching\n"
Packit 8f70b4
	 "  flush       - flush cache\n"
Packit 8f70b4
	 "  size <lim>  - set memory limit\n"
Packit 8f70b4
	 "  expire <Nx> - set cache expiration time to N seconds (x=s)\n"
Packit 8f70b4
	 "                minutes (x=m) hours (x=h) or days (x=d)\n")},
Packit 8f70b4
   {"cat",     cmd_cat,    N_("cat [-b] <files>"),
Packit 8f70b4
	 N_("cat - output remote files to stdout (can be redirected)\n"
Packit 8f70b4
	 " -b  use binary mode (ascii is the default)\n")},
Packit 8f70b4
   {"cd",      cmd_cd,     N_("cd <rdir>"),
Packit 8f70b4
	 N_("Change current remote directory to <rdir>. The previous remote directory\n"
Packit 8f70b4
	 "is stored as `-'. You can do `cd -' to change the directory back.\n"
Packit 8f70b4
	 "The previous directory for each site is also stored on disk, so you can\n"
Packit 8f70b4
	 "do `open site; cd -' even after lftp restart.\n")},
Packit 8f70b4
   {"chmod",   cmd_chmod,   N_("chmod [OPTS] mode file..."),
Packit 8f70b4
	 N_("Change the mode of each FILE to MODE.\n"
Packit 8f70b4
	    "\n"
Packit 8f70b4
	    " -c, --changes        - like verbose but report only when a change is made\n"
Packit 8f70b4
	    " -f, --quiet          - suppress most error messages\n"
Packit 8f70b4
	    " -v, --verbose        - output a diagnostic for every file processed\n"
Packit 8f70b4
	    " -R, --recursive      - change files and directories recursively\n"
Packit 8f70b4
	    "\n"
Packit 8f70b4
	    "MODE can be an octal number or symbolic mode (see chmod(1))\n")},
Packit 8f70b4
   {"close",   cmd_close,   "close [-a]",
Packit 8f70b4
	 N_("Close idle connections. By default only with current server.\n"
Packit 8f70b4
	 " -a  close idle connections with all servers\n")},
Packit 8f70b4
   {"cls",     cmd_cls,     N_("[re]cls [opts] [path/][pattern]"),
Packit 8f70b4
	 N_("List remote files. You can redirect output of this command to file\n"
Packit 8f70b4
	    "or via pipe to external command.\n"
Packit 8f70b4
	    "\n"
Packit 8f70b4
	    /* note: I've tried to keep options which are likely to be always
Packit 8f70b4
	     * turned on (via cmd:cls-default, etc) capital, to leave lowercase
Packit 8f70b4
	     * available for options more commonly used manually.  -s/-S is an
Packit 8f70b4
	     * exception; they both seem to be options used manually, so I made
Packit 8f70b4
	     * them align with GNU ls options. */
Packit 8f70b4
	    " -1                   - single-column output\n"
Packit 8f70b4
	    " -a, --all            - show dot files\n"
Packit 8f70b4
	    " -B, --basename       - show basename of files only\n"
Packit 8f70b4
	    "     --block-size=SIZ - use SIZ-byte blocks\n"
Packit 8f70b4
	    " -d, --directory      - list directory entries instead of contents\n"
Packit 8f70b4
	    " -F, --classify       - append indicator (one of /@) to entries\n"
Packit 8f70b4
	    " -h, --human-readable - print sizes in human readable format (e.g., 1K)\n"
Packit 8f70b4
	    "     --si             - likewise, but use powers of 1000 not 1024\n"
Packit 8f70b4
	    " -k, --kilobytes      - like --block-size=1024\n"
Packit 8f70b4
	    " -l, --long           - use a long listing format\n"
Packit 8f70b4
	    " -q, --quiet          - don't show status\n"
Packit 8f70b4
	    " -s, --size           - print size of each file\n"
Packit 8f70b4
	    "     --filesize       - if printing size, only print size for files\n"
Packit 8f70b4
	    " -i, --nocase         - case-insensitive pattern matching\n"
Packit 8f70b4
	    " -I, --sortnocase     - sort names case-insensitively\n"
Packit 8f70b4
	    " -D, --dirsfirst      - list directories first\n"
Packit 8f70b4
	    "     --sort=OPT       - \"name\", \"size\", \"date\"\n"
Packit 8f70b4
	    " -S                   - sort by file size\n"
Packit 8f70b4
	    " --user, --group, --perms, --date, --linkcount, --links\n"
Packit 8f70b4
	    "                      - show individual fields\n"
Packit 8f70b4
	    " --time-style=STYLE   - use specified time format\n"
Packit 8f70b4
	    "\n"
Packit 8f70b4
	    "By default, cls output is cached, to see new listing use `recls' or\n"
Packit 8f70b4
	    "`cache flush'.\n"
Packit 8f70b4
	    "\n"
Packit 8f70b4
	    "The variables cls-default and cls-completion-default can be used to\n"
Packit 8f70b4
	    "specify defaults for cls listings and completion listings, respectively.\n"
Packit 8f70b4
	    "For example, to make completion listings show file sizes, set\n"
Packit 8f70b4
	    "cls-completion-default to \"-s\".\n"
Packit 8f70b4
	    "\n"
Packit 8f70b4
	    /* FIXME: poorly worded. another explanation of --filesize: if a person
Packit 8f70b4
	     * wants to only see file sizes for files (not dirs) when he uses -s,
Packit 8f70b4
	     * add --filesize; it won't have any effect unless -s is also used, so
Packit 8f70b4
	     * it can be enabled all the time. (that's also poorly worded, and too
Packit 8f70b4
	     * long.) */
Packit 8f70b4
	    "Tips: Use --filesize with -D to pack the listing better.  If you don't\n"
Packit 8f70b4
	    "always want to see file sizes, --filesize in cls-default will affect the\n"
Packit 8f70b4
	    "-s flag on the commandline as well.  Add `-i' to cls-completion-default\n"
Packit 8f70b4
	    "to make filename completion case-insensitive.\n"
Packit 8f70b4
	   )},
Packit 8f70b4
   {"connect", ALIAS_FOR(open)},
Packit 8f70b4
   {"command", cmd_command},
Packit 8f70b4
   {"debug",   cmd_debug,  N_("debug [OPTS] [<level>|off]"),
Packit 8f70b4
	 N_("Set debug level to given value or turn debug off completely.\n"
Packit 8f70b4
	 " -o <file>  redirect debug output to the file\n"
Packit 8f70b4
	 " -c  show message context\n"
Packit 8f70b4
	 " -p  show PID\n"
Packit 8f70b4
	 " -t  show timestamps\n")},
Packit 8f70b4
   {"du",      cmd_du,  N_("du [options] <dirs>"),
Packit 8f70b4
	 N_("Summarize disk usage.\n"
Packit 8f70b4
	 " -a, --all             write counts for all files, not just directories\n"
Packit 8f70b4
	 "     --block-size=SIZ  use SIZ-byte blocks\n"
Packit 8f70b4
	 " -b, --bytes           print size in bytes\n"
Packit 8f70b4
	 " -c, --total           produce a grand total\n"
Packit 8f70b4
	 " -d, --max-depth=N     print the total for a directory (or file, with --all)\n"
Packit 8f70b4
	 "                       only if it is N or fewer levels below the command\n"
Packit 8f70b4
	 "                       line argument;  --max-depth=0 is the same as\n"
Packit 8f70b4
	 "                       --summarize\n"
Packit 8f70b4
	 " -F, --files           print number of files instead of sizes\n"
Packit 8f70b4
	 " -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)\n"
Packit 8f70b4
	 " -H, --si              likewise, but use powers of 1000 not 1024\n"
Packit 8f70b4
	 " -k, --kilobytes       like --block-size=1024\n"
Packit 8f70b4
	 " -m, --megabytes       like --block-size=1048576\n"
Packit 8f70b4
	 " -S, --separate-dirs   do not include size of subdirectories\n"
Packit 8f70b4
	 " -s, --summarize       display only a total for each argument\n"
Packit 8f70b4
	 "     --exclude=PAT     exclude files that match PAT\n")},
Packit 8f70b4
   {"echo",    cmd_echo,   0},
Packit 8f70b4
   {"edit",    cmd_edit,   N_("edit [OPTS] <file>"),
Packit 8f70b4
	 N_("Retrieve remote file to a temporary location, run a local editor on it\n"
Packit 8f70b4
	 "and upload the file back if changed.\n"
Packit 8f70b4
	 " -k  keep the temporary file\n"
Packit 8f70b4
	 " -o <temp>  explicit temporary file location\n")},
Packit 8f70b4
   {"eval",    cmd_eval,   0},
Packit 8f70b4
   {"exit",    cmd_exit,   N_("exit [|bg]"),
Packit 8f70b4
	 N_("exit - exit from lftp or move to background if jobs are active\n\n"
Packit 8f70b4
	 "If no jobs active, the code is passed to operating system as lftp\n"
Packit 8f70b4
	 "termination status. If omitted, exit code of last command is used.\n"
Packit 8f70b4
	 "`bg' forces moving to background if cmd:move-background is false.\n")},
Packit 8f70b4
   {"fg", ALIAS_FOR(wait)},
Packit 8f70b4
   {"find",    cmd_find,0,
Packit 8f70b4
	 N_("Usage: find [OPTS] [directory]\n"
Packit 8f70b4
	 "Print contents of specified directory or current directory recursively.\n"
Packit 8f70b4
	 "Directories in the list are marked with trailing slash.\n"
Packit 8f70b4
	 "You can redirect output of this command.\n"
Packit 8f70b4
	 " -d, --maxdepth=LEVELS  Descend at most LEVELS of directories.\n")},
Packit 8f70b4
   {"get",     cmd_get,    N_("get [OPTS] <rfile> [-o <lfile>]"),
Packit 8f70b4
	 N_("Retrieve remote file <rfile> and store it to local file <lfile>.\n"
Packit 8f70b4
	 " -o <lfile> specifies local file name (default - basename of rfile)\n"
Packit 8f70b4
	 " -c  continue, resume transfer\n"
Packit 8f70b4
	 " -E  delete remote files after successful transfer\n"
Packit 8f70b4
	 " -a  use ascii mode (binary is the default)\n"
Packit 8f70b4
	 " -O <base> specifies base directory or URL where files should be placed\n")},
Packit 8f70b4
   {"get1",    cmd_get1,   0,0},
Packit 8f70b4
   {"glob",    cmd_glob,   N_("glob [OPTS] <cmd> <args>"),
Packit 8f70b4
	 N_(
Packit 8f70b4
	 "Expand wildcards and run specified command.\n"
Packit 8f70b4
	 "Options can be used to expand wildcards to list of files, directories,\n"
Packit 8f70b4
	 "or both types. Type selection is not very reliable and depends on server.\n"
Packit 8f70b4
	 "If entry type cannot be determined, it will be included in the list.\n"
Packit 8f70b4
	 " -f  plain files (default)\n"
Packit 8f70b4
	 " -d  directories\n"
Packit 8f70b4
	 " -a  all types\n"
Packit 8f70b4
	 " --exist      return zero exit code when the patterns expand to non-empty list\n"
Packit 8f70b4
	 " --not-exist  return zero exit code when the patterns expand to an empty list\n")},
Packit 8f70b4
   {"help",    cmd_help,   N_("help [<cmd>]"),
Packit 8f70b4
	 N_("Print help for command <cmd>, or list of available commands\n")},
Packit 8f70b4
   {"jobs",    cmd_jobs,   "jobs [-v] [<job_no...>]",
Packit 8f70b4
	 N_("List running jobs. -v means verbose, several -v can be specified.\n"
Packit 8f70b4
	    "If <job_no> is specified, only list a job with that number.\n")},
Packit 8f70b4
   {"kill",    cmd_kill,   N_("kill all|<job_no>"),
Packit 8f70b4
	 N_("Delete specified job with <job_no> or all jobs\n")},
Packit 8f70b4
   {"lcd",     cmd_lcd,    N_("lcd <ldir>"),
Packit 8f70b4
	 N_("Change current local directory to <ldir>. The previous local directory\n"
Packit 8f70b4
	 "is stored as `-'. You can do `lcd -' to change the directory back.\n")},
Packit 8f70b4
   {"lftp",    cmd_lftp,   N_("lftp [OPTS] <site>"),
Packit 8f70b4
	 N_("`lftp' is the first command executed by lftp after rc files\n"
Packit 8f70b4
	 " -f <file>           execute commands from the file and exit\n"
Packit 8f70b4
	 " -c <cmd>            execute the commands and exit\n"
Packit 8f70b4
	 " --norc              don't execute rc files from the home directory\n"
Packit 8f70b4
	 " --help              print this help and exit\n"
Packit 8f70b4
	 " --version           print lftp version and exit\n"
Packit 8f70b4
	 "Other options are the same as in `open' command:\n"
Packit 8f70b4
	 " -e <cmd>            execute the command just after selecting\n"
Packit 8f70b4
	 " -u <user>[,<pass>]  use the user/password for authentication\n"
Packit 8f70b4
	 " -p <port>           use the port for connection\n"
Packit 8f70b4
	 " -s <slot>           assign the connection to this slot\n"
Packit 8f70b4
	 " -d                  switch on debugging mode\n"
Packit 8f70b4
	 " <site>              host name, URL or bookmark name\n")},
Packit 8f70b4
   {"ln",      cmd_ln,	    N_("ln [-s] <file1> <file2>"),
Packit 8f70b4
	 N_("Link <file1> to <file2>\n")},
Packit 8f70b4
   {"lpwd",    cmd_lpwd},
Packit 8f70b4
   {"local",   cmd_local},
Packit 8f70b4
   {"login", ALIAS_FOR(user)},
Packit 8f70b4
   {"ls",      cmd_ls,	    N_("ls [<args>]"),
Packit 8f70b4
	 N_("List remote files. You can redirect output of this command to file\n"
Packit 8f70b4
	 "or via pipe to external command.\n"
Packit 8f70b4
	 "By default, ls output is cached, to see new listing use `rels' or\n"
Packit 8f70b4
	 "`cache flush'.\n"
Packit 8f70b4
	 "See also `help cls'.\n")},
Packit 8f70b4
   {"mget",    cmd_get,	   N_("mget [OPTS] <files>"),
Packit 8f70b4
	 N_("Gets selected files with expanded wildcards\n"
Packit 8f70b4
	 " -c  continue, resume transfer\n"
Packit 8f70b4
	 " -d  create directories the same as in file names and get the\n"
Packit 8f70b4
	 "     files into them instead of current directory\n"
Packit 8f70b4
	 " -E  delete remote files after successful transfer\n"
Packit 8f70b4
	 " -a  use ascii mode (binary is the default)\n"
Packit 8f70b4
	 " -O <base> specifies base directory or URL where files should be placed\n")},
Packit 8f70b4
   {"mirror",  cmd_mirror, N_("mirror [OPTS] [remote [local]]"), HELP_IN_MODULE},
Packit 8f70b4
   {"mkdir",   cmd_mkdir,  N_("mkdir [OPTS] <dirs>"),
Packit 8f70b4
	 N_("Make remote directories\n"
Packit 8f70b4
	 " -p  make all levels of path\n"
Packit 8f70b4
	 " -f  be quiet, suppress messages\n")},
Packit 8f70b4
   {"module",  cmd_module, N_("module name [args]"),
Packit 8f70b4
	 N_("Load module (shared object). The module should contain function\n"
Packit 8f70b4
	 "   void module_init(int argc,const char *const *argv)\n"
Packit 8f70b4
	 "If name contains a slash, then the module is searched in current\n"
Packit 8f70b4
	 "directory, otherwise in directories specified by setting module:path.\n")},
Packit 8f70b4
   {"more",    cmd_cat,    N_("more <files>"),
Packit 8f70b4
	 N_("Same as `cat <files> | more'. if PAGER is set, it is used as filter\n")},
Packit 8f70b4
   {"mput",    cmd_get,	   N_("mput [OPTS] <files>"),
Packit 8f70b4
	 N_("Upload files with wildcard expansion\n"
Packit 8f70b4
	 " -c  continue, reput\n"
Packit 8f70b4
	 " -d  create directories the same as in file names and put the\n"
Packit 8f70b4
	 "     files into them instead of current directory\n"
Packit 8f70b4
	 " -E  delete local files after successful transfer (dangerous)\n"
Packit 8f70b4
	 " -a  use ascii mode (binary is the default)\n"
Packit 8f70b4
	 " -O <base> specifies base directory or URL where files should be placed\n")},
Packit 8f70b4
   {"mrm",     cmd_mrm,    N_("mrm <files>"),
Packit 8f70b4
	 N_("Removes specified files with wildcard expansion\n")},
Packit 8f70b4
   {"mv",      cmd_mv,	   N_("mv <file1> <file2>"),
Packit 8f70b4
	 N_("Rename <file1> to <file2>\n")},
Packit 8f70b4
   {"mmv",      cmd_mmv,   N_("mmv [OPTS] <files> <target-dir>"),
Packit 8f70b4
	 N_("Move <files> to <target-directory> with wildcard expansion\n"
Packit 8f70b4
	 " -O <dir>  specifies the target directory (alternative way)\n")},
Packit 8f70b4
   {"nlist",   cmd_ls,     N_("[re]nlist [<args>]"),
Packit 8f70b4
	 N_("List remote file names.\n"
Packit 8f70b4
	 "By default, nlist output is cached, to see new listing use `renlist' or\n"
Packit 8f70b4
	 "`cache flush'.\n")},
Packit 8f70b4
   {"open",    cmd_open,   N_("open [OPTS] <site>"),
Packit 8f70b4
	 N_("Select a server, URL or bookmark\n"
Packit 8f70b4
	 " -e <cmd>            execute the command just after selecting\n"
Packit 8f70b4
	 " -u <user>[,<pass>]  use the user/password for authentication\n"
Packit 8f70b4
	 " -p <port>           use the port for connection\n"
Packit 8f70b4
	 " -s <slot>           assign the connection to this slot\n"
Packit 8f70b4
	 " -d                  switch on debugging mode\n"
Packit 8f70b4
	 " <site>              host name, URL or bookmark name\n")},
Packit 8f70b4
   {"pget",    cmd_get,    N_("pget [OPTS] <rfile> [-o <lfile>]"),
Packit 8f70b4
	 N_("Gets the specified file using several connections. This can speed up transfer,\n"
Packit 8f70b4
	 "but loads the net heavily impacting other users. Use only if you really\n"
Packit 8f70b4
	 "have to transfer the file ASAP.\n"
Packit 8f70b4
	 "\nOptions:\n"
Packit 8f70b4
	 " -c  continue transfer. Requires <lfile>.lftp-pget-status file.\n"
Packit 8f70b4
	 " -n <maxconn>  set maximum number of connections (default is is taken from\n"
Packit 8f70b4
	 "     pget:default-n setting)\n"
Packit 8f70b4
	 " -O <base> specifies base directory where files should be placed\n")},
Packit 8f70b4
   {"put",     cmd_get,    N_("put [OPTS] <lfile> [-o <rfile>]"),
Packit 8f70b4
	 N_("Upload <lfile> with remote name <rfile>.\n"
Packit 8f70b4
	 " -o <rfile> specifies remote file name (default - basename of lfile)\n"
Packit 8f70b4
	 " -c  continue, reput\n"
Packit 8f70b4
	 "     it requires permission to overwrite remote files\n"
Packit 8f70b4
	 " -E  delete local files after successful transfer (dangerous)\n"
Packit 8f70b4
	 " -a  use ascii mode (binary is the default)\n"
Packit 8f70b4
	 " -O <base> specifies base directory or URL where files should be placed\n")},
Packit 8f70b4
   {"pwd",     cmd_pwd,    "pwd [-p]",
Packit 8f70b4
	 N_("Print current remote URL.\n"
Packit 8f70b4
	 " -p  show password\n")},
Packit 8f70b4
   {"queue",   cmd_queue,  N_("queue [OPTS] [<cmd>]"),
Packit 8f70b4
	 N_("\n"
Packit 8f70b4
	 "       queue [-n num] <command>\n\n"
Packit 8f70b4
	 "Add the command to queue for current site. Each site has its own command\n"
Packit 8f70b4
	 "queue. `-n' adds the command before the given item in the queue. It is\n"
Packit 8f70b4
	 "possible to queue up a running job by using command `queue wait <jobno>'.\n"
Packit 8f70b4
	 "\n"
Packit 8f70b4
	 "       queue --delete|-d [index or wildcard expression]\n\n"
Packit 8f70b4
	 "Delete one or more items from the queue. If no argument is given, the last\n"
Packit 8f70b4
	 "entry in the queue is deleted.\n"
Packit 8f70b4
	 "\n"
Packit 8f70b4
	 "       queue --move|-m <index or wildcard expression> [index]\n\n"
Packit 8f70b4
	 "Move the given items before the given queue index, or to the end if no\n"
Packit 8f70b4
	 "destination is given.\n"
Packit 8f70b4
	 "\n"
Packit 8f70b4
	 "Options:\n"
Packit 8f70b4
	 " -q                  Be quiet.\n"
Packit 8f70b4
	 " -v                  Be verbose.\n"
Packit 8f70b4
	 " -Q                  Output in a format that can be used to re-queue.\n"
Packit 8f70b4
	 "                     Useful with --delete.\n"
Packit 8f70b4
	 )},
Packit 8f70b4
   {"quit", ALIAS_FOR(exit)},
Packit 8f70b4
   {"quote",   cmd_ls,	   N_("quote <cmd>"),
Packit 8f70b4
	 N_("Send the command uninterpreted. Use with caution - it can lead to\n"
Packit 8f70b4
	 "unknown remote state and thus will cause reconnect. You cannot\n"
Packit 8f70b4
	 "be sure that any change of remote state because of quoted command\n"
Packit 8f70b4
	 "is solid - it can be reset by reconnect at any time.\n")},
Packit 8f70b4
   {"recls",    cmd_cls,   0,
Packit 8f70b4
	 N_("recls [<args>]\n"
Packit 8f70b4
	 "Same as `cls', but don't look in cache\n")},
Packit 8f70b4
   {"reget",   cmd_get,    0,
Packit 8f70b4
	 N_("Usage: reget [OPTS] <rfile> [-o <lfile>]\n"
Packit 8f70b4
	 "Same as `get -c'\n")},
Packit 8f70b4
   {"rels",    cmd_ls,	    0,
Packit 8f70b4
	 N_("Usage: rels [<args>]\n"
Packit 8f70b4
	    "Same as `ls', but don't look in cache\n")},
Packit 8f70b4
   {"renlist", cmd_ls,	    0,
Packit 8f70b4
	 N_("Usage: renlist [<args>]\n"
Packit 8f70b4
	 "Same as `nlist', but don't look in cache\n")},
Packit 8f70b4
   {"repeat",  cmd_repeat, N_("repeat [OPTS] [delay] [command]"), HELP_IN_MODULE},
Packit 8f70b4
   {"reput",   cmd_get,    0,
Packit 8f70b4
	 N_("Usage: reput <lfile> [-o <rfile>]\n"
Packit 8f70b4
	 "Same as `put -c'\n")},
Packit 8f70b4
   {"rm",      cmd_rm,	    N_("rm [-r] [-f] <files>"),
Packit 8f70b4
	 N_("Remove remote files\n"
Packit 8f70b4
	    " -r  recursive directory removal, be careful\n"
Packit 8f70b4
	    " -f  work quietly\n")},
Packit 8f70b4
   {"rmdir",   cmd_rm,	    N_("rmdir [-f] <dirs>"),
Packit 8f70b4
	 N_("Remove remote directories\n")},
Packit 8f70b4
   {"scache",  cmd_scache, N_("scache [<session_no>]"),
Packit 8f70b4
	 N_("List cached sessions or switch to specified session number\n")},
Packit 8f70b4
   {"set",     cmd_set,    N_("set [OPT] [ [<val>]]"),
Packit 8f70b4
	 N_("Set variable to given value. If the value is omitted, unset the variable.\n"
Packit 8f70b4
	 "Variable name has format ``name/closure'', where closure can specify\n"
Packit 8f70b4
	 "exact application of the setting. See lftp(1) for details.\n"
Packit 8f70b4
         "If set is called with no variable then only altered settings are listed.\n"
Packit 8f70b4
	 "It can be changed by options:\n"
Packit 8f70b4
	 " -a  list all settings, including default values\n"
Packit 8f70b4
	 " -d  list only default values, not necessary current ones\n")},
Packit 8f70b4
   {"shell", ALIAS_FOR2("!",shell)},
Packit 8f70b4
   {"site",    cmd_ls,	   N_("site <site-cmd>"),
Packit 8f70b4
	 N_("Execute site command <site_cmd> and output the result\n"
Packit 8f70b4
	 "You can redirect its output\n")},
Packit 8f70b4
   {"sleep",   cmd_sleep, 0, HELP_IN_MODULE},
Packit 8f70b4
   {"slot",    cmd_slot, 0,
Packit 8f70b4
        N_("Usage: slot [<label>]\n"
Packit 8f70b4
	"List assigned slots.\n"
Packit 8f70b4
	"If <label> is specified, switch to the slot named <label>.\n")},
Packit 8f70b4
   {"source",  cmd_source, N_("source <file>"),
Packit 8f70b4
	 N_("Execute commands recorded in file <file>\n")},
Packit 8f70b4
   {"suspend", cmd_suspend},
Packit 8f70b4
   {"torrent", cmd_torrent, N_("torrent [OPTS] <file|URL>..."), HELP_IN_MODULE},
Packit 8f70b4
   {"user",    cmd_user,   N_("user <user|URL> [<pass>]"),
Packit 8f70b4
	 N_("Use specified info for remote login. If you specify URL, the password\n"
Packit 8f70b4
	 "will be cached for future usage.\n")},
Packit 8f70b4
   {"version", cmd_ver,    0,
Packit 8f70b4
	 N_("Shows lftp version\n")},
Packit 8f70b4
   {"wait",    cmd_wait,   N_("wait [<jobno>]"),
Packit 8f70b4
	 N_("Wait for specified job to terminate. If jobno is omitted, wait\n"
Packit 8f70b4
	 "for last backgrounded job.\n")},
Packit 8f70b4
   {"zcat",    cmd_cat,    N_("zcat <files>"),
Packit 8f70b4
	 N_("Same as cat, but filter each file through zcat\n")},
Packit 8f70b4
   {"zmore",   cmd_cat,    N_("zmore <files>"),
Packit 8f70b4
	 N_("Same as more, but filter each file through zcat\n")},
Packit 8f70b4
   {"bzcat",    cmd_cat,    0,
Packit 8f70b4
	 N_("Same as cat, but filter each file through bzcat\n")},
Packit 8f70b4
   {"bzmore",   cmd_cat,    0,
Packit 8f70b4
	 N_("Same as more, but filter each file through bzcat\n")},
Packit 8f70b4
Packit 8f70b4
   {".tasks",  cmd_tasks,  0,0},
Packit 8f70b4
   {".empty",  cmd_empty,  0,0},
Packit 8f70b4
   {".notempty",cmd_notempty,0,0},
Packit 8f70b4
   {".true",   cmd_true,   0,0},
Packit 8f70b4
   {".false",  cmd_false,  0,0},
Packit 8f70b4
   {".mplist", cmd_ls,	   0,0},
Packit 8f70b4
};
Packit 8f70b4
const int CmdExec::static_cmd_table_length=sizeof(static_cmd_table)/sizeof(static_cmd_table[0]);
Packit 8f70b4
Packit 8f70b4
#define charcasecmp(a,b) (tolower((unsigned char)(a))-tolower((unsigned char)(b)))
Packit 8f70b4
// returns:
Packit 8f70b4
//    0 - no match
Packit 8f70b4
//    1 - found, if *res==0 then ambiguous
Packit 8f70b4
static
Packit 8f70b4
int find_command(const char *unprec_name,const char * const *names,
Packit 8f70b4
	         const char **res)
Packit 8f70b4
{
Packit 8f70b4
   const char *match=0;
Packit 8f70b4
   for( ; *names; names++)
Packit 8f70b4
   {
Packit 8f70b4
      const char *s,*u;
Packit 8f70b4
      for(s=*names,u=unprec_name; *s && !charcasecmp(*u,*s); s++,u++)
Packit 8f70b4
	 ;
Packit 8f70b4
      if(*s && !*u)
Packit 8f70b4
      {
Packit 8f70b4
	 if(match)
Packit 8f70b4
	 {
Packit 8f70b4
	    *res=0;
Packit 8f70b4
	    return 1;
Packit 8f70b4
	 }
Packit 8f70b4
	 match=*names;
Packit 8f70b4
      }
Packit 8f70b4
      else if(!*s && !*u)
Packit 8f70b4
      {
Packit 8f70b4
	 *res=*names;
Packit 8f70b4
	 return 1;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   if(match)
Packit 8f70b4
   {
Packit 8f70b4
      *res=match;
Packit 8f70b4
      return 1;
Packit 8f70b4
   }
Packit 8f70b4
   *res=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Job *CmdExec::builtin_lcd()
Packit 8f70b4
{
Packit 8f70b4
   if(args->count()==1)
Packit 8f70b4
      args->Append("~");
Packit 8f70b4
Packit 8f70b4
   if(args->count()!=2)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("Usage: %s local-dir\n"),args->getarg(0));
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   const char *cd_to=args->getarg(1);
Packit 8f70b4
Packit 8f70b4
   if(!strcmp(cd_to,"-"))
Packit 8f70b4
   {
Packit 8f70b4
      if(old_lcwd)
Packit 8f70b4
	 cd_to=old_lcwd;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   cd_to=expand_home_relative(cd_to);
Packit 8f70b4
Packit 8f70b4
   if(RestoreCWD()==-1)
Packit 8f70b4
   {
Packit 8f70b4
      if(cd_to[0]!='/')
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf("No current local directory, use absolute path.\n");
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   int res=chdir(cd_to);
Packit 8f70b4
   if(res==-1)
Packit 8f70b4
   {
Packit 8f70b4
      perror(cd_to);
Packit 8f70b4
      exit_code=1;
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   old_lcwd.set(cwd->GetName());
Packit 8f70b4
Packit 8f70b4
   SaveCWD();
Packit 8f70b4
Packit 8f70b4
   const char *name=cwd->GetName();
Packit 8f70b4
   if(interactive)
Packit 8f70b4
      eprintf(_("lcd ok, local cwd=%s\n"),name?name:"?");
Packit 8f70b4
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Job *CmdExec::builtin_cd()
Packit 8f70b4
{
Packit 8f70b4
   if(args->count()==1)
Packit 8f70b4
      args->Append("~");
Packit 8f70b4
Packit 8f70b4
   bool is_file=false;
Packit 8f70b4
Packit 8f70b4
   if(args->count()!=2)
Packit 8f70b4
   {
Packit 8f70b4
      // xgettext:c-format
Packit 8f70b4
      eprintf(_("Usage: cd remote-dir\n"));
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   const char *dir=args->getarg(1);
Packit 8f70b4
   const char *url=0;
Packit 8f70b4
Packit 8f70b4
   if(!strcmp(dir,"-"))
Packit 8f70b4
   {
Packit 8f70b4
      dir=cwd_history.Lookup(session);
Packit 8f70b4
      if(!dir)
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("%s: no old directory for this site\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      args->setarg(1,dir); // for status line
Packit 8f70b4
      dir=args->getarg(1);
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   bool dir_needs_slash=false;
Packit 8f70b4
   if(url::is_url(dir))
Packit 8f70b4
   {
Packit 8f70b4
      ParsedURL u(dir,true);
Packit 8f70b4
      FileAccess *new_session=FileAccess::New(&u);
Packit 8f70b4
      bool same_site=session->SameSiteAs(new_session);
Packit 8f70b4
      Delete(new_session);
Packit 8f70b4
      if(!same_site)
Packit 8f70b4
	 return builtin_open();
Packit 8f70b4
      url=dir;
Packit 8f70b4
      dir=alloca_strdup(u.path);
Packit 8f70b4
      dir_needs_slash=url::dir_needs_trailing_slash(u.proto);
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      dir_needs_slash=url::dir_needs_trailing_slash(session->GetProto());
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(dir_needs_slash)
Packit 8f70b4
      is_file=(last_char(dir)!='/');
Packit 8f70b4
Packit 8f70b4
   int cache_is_dir=FileAccess::cache->IsDirectory(session,dir);
Packit 8f70b4
   if(cache_is_dir==1)
Packit 8f70b4
   {
Packit 8f70b4
      if(is_file && dir_needs_slash && last_char(dir)!='/')
Packit 8f70b4
	 dir=xstring::get_tmp(dir).append('/');
Packit 8f70b4
      is_file=false;
Packit 8f70b4
   }
Packit 8f70b4
   else if(cache_is_dir==0)
Packit 8f70b4
      is_file=true;
Packit 8f70b4
Packit 8f70b4
   old_cwd=session->GetCwd();
Packit 8f70b4
   FileAccess::Path new_cwd(old_cwd);
Packit 8f70b4
   new_cwd.Change(dir,is_file);
Packit 8f70b4
   if(url)
Packit 8f70b4
      new_cwd.SetURL(url);
Packit 8f70b4
   if(!verify_path || background
Packit 8f70b4
   || (!verify_path_cached && cache_is_dir==1))
Packit 8f70b4
   {
Packit 8f70b4
      cwd_history.Set(session,old_cwd);
Packit 8f70b4
      session->SetCwd(new_cwd);
Packit 8f70b4
      if(slot)
Packit 8f70b4
	 ConnectionSlot::SetCwd(slot,new_cwd);
Packit 8f70b4
      exit_code=0;
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   session->PathVerify(new_cwd);
Packit 8f70b4
   session->Roll();
Packit 8f70b4
   builtin=BUILTIN_CD;
Packit 8f70b4
   return this;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Job *CmdExec::builtin_exit()
Packit 8f70b4
{
Packit 8f70b4
   bool detach=ResMgr::QueryBool("cmd:move-background-detach",0);
Packit 8f70b4
   bool bg=false;
Packit 8f70b4
   bool kill=false;
Packit 8f70b4
   int code=prev_exit_code;
Packit 8f70b4
   CmdExec *exec=this;
Packit 8f70b4
   const char *a;
Packit 8f70b4
   args->rewind();
Packit 8f70b4
   while((a=args->getnext())!=0)
Packit 8f70b4
   {
Packit 8f70b4
      if(!strcmp(a,"bg"))
Packit 8f70b4
	 bg=true;
Packit 8f70b4
      if(!strcmp(a,"top") || !strcmp(a,"bg"))
Packit 8f70b4
      {
Packit 8f70b4
	 if(top)
Packit 8f70b4
	    exec=top.get_non_const();
Packit 8f70b4
      }
Packit 8f70b4
      else if(!strcmp(a,"parent"))
Packit 8f70b4
      {
Packit 8f70b4
	 if(parent_exec)
Packit 8f70b4
	    exec=parent_exec;
Packit 8f70b4
      }
Packit 8f70b4
      else if(!strcmp(a,"kill"))
Packit 8f70b4
      {
Packit 8f70b4
	 kill=true;
Packit 8f70b4
	 bg=false;
Packit 8f70b4
      }
Packit 8f70b4
      else if(sscanf(a,"%i",&code)!=1)
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("Usage: %s [<exit_code>]\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   // Note: one job is this CmdExec.
Packit 8f70b4
   if(!bg && exec->top_level
Packit 8f70b4
   && !ResMgr::QueryBool("cmd:move-background",0) && NumberOfChildrenJobs()>0)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_(
Packit 8f70b4
	 "There are running jobs and `cmd:move-background' is not set.\n"
Packit 8f70b4
	 "Use `exit bg' to force moving to background or `kill all' to terminate jobs.\n"
Packit 8f70b4
      ));
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   if(!detach && Job::NumberOfChildrenJobs()==0)
Packit 8f70b4
      detach=true;
Packit 8f70b4
   if(kill)
Packit 8f70b4
      Job::KillAll();
Packit 8f70b4
   if(detach) {
Packit 8f70b4
      for(CmdExec *e=this; e!=exec; e=e->parent_exec)
Packit 8f70b4
	 e->Exit(code);
Packit 8f70b4
      exec->Exit(code);
Packit 8f70b4
   } else {
Packit 8f70b4
      int loc=0;
Packit 8f70b4
      exec->SetAutoTerminateInBackground(true);
Packit 8f70b4
      eprintf(_(
Packit 8f70b4
	 "\n"
Packit 8f70b4
	 "lftp now tricks the shell to move it to background process group.\n"
Packit 8f70b4
	 "lftp continues to run in the background despite the `Stopped' message.\n"
Packit 8f70b4
	 "lftp will automatically terminate when all jobs are finished.\n"
Packit 8f70b4
	 "Use `fg' shell command to return to lftp if it is still running.\n"
Packit 8f70b4
      ));
Packit 8f70b4
      // trick the shell
Packit 8f70b4
      switch(pid_t pid=fork()) {
Packit 8f70b4
      case 0: // child
Packit 8f70b4
	 sleep(1);   // wait for the parent to stop (is there a safer way?)
Packit 8f70b4
	 ::kill(getppid(),SIGCONT);
Packit 8f70b4
	 _exit(0);
Packit 8f70b4
      default: // parent
Packit 8f70b4
	 raise(SIGSTOP);
Packit 8f70b4
	 waitpid(pid,&loc,0); // clean-up
Packit 8f70b4
	 break;
Packit 8f70b4
      case -1:
Packit 8f70b4
	 exec->Exit(code);
Packit 8f70b4
	 break;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   exit_code=code;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
void CmdExec::Exit(int code)
Packit 8f70b4
{
Packit 8f70b4
   while(feeder)
Packit 8f70b4
      RemoveFeeder();
Packit 8f70b4
   cmd_buf.Empty();
Packit 8f70b4
   if(interactive)
Packit 8f70b4
   {
Packit 8f70b4
      ListDoneJobs();
Packit 8f70b4
      BuryDoneJobs();
Packit 8f70b4
      if(FindJob(last_bg)==0)
Packit 8f70b4
	 last_bg=-1;
Packit 8f70b4
   }
Packit 8f70b4
   exit_code=prev_exit_code=code;
Packit 8f70b4
   return;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void CmdExec::enable_debug(const char *opt)
Packit 8f70b4
{
Packit 8f70b4
   int level=DEFAULT_DEBUG_LEVEL;
Packit 8f70b4
   if(opt && isdigit((unsigned char)opt[0]))
Packit 8f70b4
      level=atoi(opt);
Packit 8f70b4
   const char *c="debug";
Packit 8f70b4
   ResMgr::Set("log:enabled",c,"yes");
Packit 8f70b4
   ResMgr::Set("log:level",c,xstring::format("%d",level));
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CmdFeeder *lftp_feeder=0;
Packit 8f70b4
Job *CmdExec::builtin_lftp()
Packit 8f70b4
{
Packit 8f70b4
   int c;
Packit 8f70b4
   xstring cmd;
Packit 8f70b4
   xstring rc;
Packit 8f70b4
   ArgV open("open");
Packit 8f70b4
   open.Add("--lftp");
Packit 8f70b4
Packit 8f70b4
   enum {
Packit 8f70b4
      OPT_USER,
Packit 8f70b4
      OPT_PASSWORD,
Packit 8f70b4
      OPT_ENV_PASSWORD,
Packit 8f70b4
   };
Packit 8f70b4
   static struct option lftp_options[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"help",no_argument,0,'h'},
Packit 8f70b4
      {"version",no_argument,0,'v'},
Packit 8f70b4
      {"debug",optional_argument,0,'d'},
Packit 8f70b4
      {"rcfile",required_argument,0,'r'},
Packit 8f70b4
      // other options are for "open" command
Packit 8f70b4
      {"port",required_argument,0,'p'},
Packit 8f70b4
      {"user",required_argument,0,OPT_USER},
Packit 8f70b4
      {"password",required_argument,0,OPT_PASSWORD},
Packit 8f70b4
      {"env-password",no_argument,0,OPT_ENV_PASSWORD},
Packit 8f70b4
      {"execute",required_argument,0,'e'},
Packit 8f70b4
      {"no-bookmark",no_argument,0,'B'},
Packit 8f70b4
      {"slot",required_argument,0,'s'},
Packit 8f70b4
      {0,0,0,0}
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
   while((c=args->getopt_long("+f:c:vhdu:p:e:s:B",lftp_options))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(c)
Packit 8f70b4
      {
Packit 8f70b4
      case('h'):
Packit 8f70b4
	 cmd.set("help lftp;");
Packit 8f70b4
	 break;
Packit 8f70b4
      case('v'):
Packit 8f70b4
	 cmd.set("version;");
Packit 8f70b4
	 break;
Packit 8f70b4
      case('f'):
Packit 8f70b4
	 cmd.set("source ");
Packit 8f70b4
	 cmd.append_quoted(optarg);
Packit 8f70b4
	 cmd.append(';');
Packit 8f70b4
	 break;
Packit 8f70b4
      case('c'):
Packit 8f70b4
	 args->CombineCmdTo(cmd,args->getindex()-1).append("\n\n");
Packit 8f70b4
	 args->seek(args->count());
Packit 8f70b4
	 break;
Packit 8f70b4
      case('d'):
Packit 8f70b4
	 enable_debug(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
      case('r'):
Packit 8f70b4
	 rc.append("&&source ").append_quoted(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      // "open" command options are passed along
Packit 8f70b4
      case('s'):
Packit 8f70b4
	 open.Add("-s");
Packit 8f70b4
	 break;
Packit 8f70b4
      case('p'):
Packit 8f70b4
	 open.Add("-p").Add(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
      case('u'):
Packit 8f70b4
	 open.Add("-u").Add(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
      case(OPT_USER):
Packit 8f70b4
	 open.Add("--user").Add(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
      case(OPT_PASSWORD):
Packit 8f70b4
	 open.Add("--password").Add(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
      case(OPT_ENV_PASSWORD):
Packit 8f70b4
	 open.Add("--env-password");
Packit 8f70b4
	 break;
Packit 8f70b4
      case('e'):
Packit 8f70b4
	 open.Add("-e").Add(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
      case('B'):
Packit 8f70b4
	 open.Add("-B");
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      case('?'):
Packit 8f70b4
	 eprintf(_("Try `%s --help' for more information\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   for(const char *arg=args->getcurr(); arg; arg=args->getnext())
Packit 8f70b4
      open.Add(arg);
Packit 8f70b4
Packit 8f70b4
   // feeder should be set before PrependCmd
Packit 8f70b4
   if(!cmd && lftp_feeder)  // no feeder and no commands
Packit 8f70b4
   {
Packit 8f70b4
      SetCmdFeeder(lftp_feeder);
Packit 8f70b4
      lftp_feeder=0;
Packit 8f70b4
      FeedCmd("||command exit\n");   // if the command fails, quit
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   // prepended commands are executed in reverse order: rc, cmd, open
Packit 8f70b4
   if(open.count()>2) {
Packit 8f70b4
      if(cmd) {
Packit 8f70b4
	 eprintf(_("%s: -c, -f, -v, -h conflict with other `open' options and arguments\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      xstring_ca open_cmd(open.CombineQuoted());
Packit 8f70b4
      PrependCmd(open_cmd);
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(cmd)
Packit 8f70b4
      PrependCmd(cmd);
Packit 8f70b4
   if(rc)
Packit 8f70b4
      PrependCmd(rc);
Packit 8f70b4
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Job *CmdExec::builtin_open()
Packit 8f70b4
{
Packit 8f70b4
   ReuseSavedSession();
Packit 8f70b4
Packit 8f70b4
   const char *port=NULL;
Packit 8f70b4
   const char *host=NULL;
Packit 8f70b4
   const char *path=NULL;
Packit 8f70b4
   const char *user=NULL;
Packit 8f70b4
   const char *pass=NULL;
Packit 8f70b4
   int	 c;
Packit 8f70b4
   NetRC::Entry *nrc=0;
Packit 8f70b4
   char  *cmd_to_exec=0;
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   bool insecure=false;
Packit 8f70b4
   bool no_bm=false;
Packit 8f70b4
Packit 8f70b4
   enum {
Packit 8f70b4
      OPT_USER,
Packit 8f70b4
      OPT_PASSWORD,
Packit 8f70b4
      OPT_ENV_PASSWORD,
Packit 8f70b4
      OPT_LFTP,
Packit 8f70b4
   };
Packit 8f70b4
   static struct option open_options[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"port",required_argument,0,'p'},
Packit 8f70b4
      {"user",required_argument,0,OPT_USER},
Packit 8f70b4
      {"password",required_argument,0,OPT_PASSWORD},
Packit 8f70b4
      {"env-password",no_argument,0,OPT_ENV_PASSWORD},
Packit 8f70b4
      {"execute",required_argument,0,'e'},
Packit 8f70b4
      {"debug",optional_argument,0,'d'},
Packit 8f70b4
      {"no-bookmark",no_argument,0,'B'},
Packit 8f70b4
      {"slot",required_argument,0,'s'},
Packit 8f70b4
      {"lftp",no_argument,0,OPT_LFTP},
Packit 8f70b4
      {0,0,0,0}
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
   while((c=args->getopt_long("u:p:e:s:dB",open_options))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(c)
Packit 8f70b4
      {
Packit 8f70b4
      case('s'):
Packit 8f70b4
	if (*optarg) ChangeSlot(optarg);
Packit 8f70b4
        break;
Packit 8f70b4
      case('p'):
Packit 8f70b4
	 port=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('u'):
Packit 8f70b4
      {
Packit 8f70b4
         user=optarg;
Packit 8f70b4
         char *sep=strchr(optarg,',');
Packit 8f70b4
	 if(sep==NULL)
Packit 8f70b4
	    sep=strchr(optarg,' ');
Packit 8f70b4
	 if(sep==NULL)
Packit 8f70b4
	    sep=strchr(optarg,':');
Packit 8f70b4
	 if(sep==NULL)
Packit 8f70b4
	    break;
Packit 8f70b4
	 *sep=0;
Packit 8f70b4
	 pass=sep+1;
Packit 8f70b4
	 insecure=true;
Packit 8f70b4
         break;
Packit 8f70b4
      }
Packit 8f70b4
      case(OPT_USER):
Packit 8f70b4
	 user=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
      case(OPT_PASSWORD):
Packit 8f70b4
	 pass=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
      case(OPT_ENV_PASSWORD):
Packit 8f70b4
	 pass=getenv("LFTP_PASSWORD");
Packit 8f70b4
	 break;
Packit 8f70b4
      case('d'):
Packit 8f70b4
	 enable_debug(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
      case('e'):
Packit 8f70b4
	 cmd_to_exec=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('B'):
Packit 8f70b4
	 no_bm=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case(OPT_LFTP):
Packit 8f70b4
	 op="lftp";
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
	 eprintf(_("Usage: %s [-e cmd] [-p port] [-u user[,pass]] <host|url>\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(optind<args->count())
Packit 8f70b4
      host=args->getarg(optind++);
Packit 8f70b4
Packit 8f70b4
   Ref<ParsedURL> url;
Packit 8f70b4
Packit 8f70b4
   const char *bm=0;
Packit 8f70b4
Packit 8f70b4
   if(cmd_to_exec)
Packit 8f70b4
      PrependCmd(cmd_to_exec);
Packit 8f70b4
Packit 8f70b4
   if(!no_bm && host && (bm=lftp_bookmarks.Lookup(host))!=0)
Packit 8f70b4
   {
Packit 8f70b4
      xstring& cmd=xstring::get_tmp("open -B ");
Packit 8f70b4
      if(user)
Packit 8f70b4
      {
Packit 8f70b4
	 cmd.append("--user ").append_quoted(user);
Packit 8f70b4
	 if(pass)
Packit 8f70b4
	    cmd.append(" --password ").append_quoted(pass);
Packit 8f70b4
	 cmd.append(' ');
Packit 8f70b4
      }
Packit 8f70b4
      if(port)
Packit 8f70b4
      {
Packit 8f70b4
	 cmd.append("-p ");
Packit 8f70b4
	 cmd.append_quoted(port);
Packit 8f70b4
	 cmd.append(' ');
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
      cmd.append(bm);
Packit 8f70b4
Packit 8f70b4
      if(background)
Packit 8f70b4
	 cmd.append(" &\n");
Packit 8f70b4
      else
Packit 8f70b4
	 cmd.append(";\n");
Packit 8f70b4
Packit 8f70b4
      PrependCmd(cmd);
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      if(host && host[0])
Packit 8f70b4
      {
Packit 8f70b4
	 url=new ParsedURL(host);
Packit 8f70b4
	 bool no_proto=(!url->proto);
Packit 8f70b4
Packit 8f70b4
	 if(no_proto && url->host)
Packit 8f70b4
	 {
Packit 8f70b4
	    const char *p=ResMgr::Query("cmd:default-protocol",url->host);
Packit 8f70b4
	    if(!p)
Packit 8f70b4
	       p="ftp";
Packit 8f70b4
	    url=new ParsedURL(xstring::format("%s://%s",p,host));
Packit 8f70b4
	 }
Packit 8f70b4
	 if(user || port)
Packit 8f70b4
	 {
Packit 8f70b4
	    if(user)
Packit 8f70b4
	    {
Packit 8f70b4
	       url->user.set(user);
Packit 8f70b4
	       url->pass.set(pass);
Packit 8f70b4
	    }
Packit 8f70b4
	    if(port)
Packit 8f70b4
	       url->port.set(port);
Packit 8f70b4
	    xstring_ca host1(url->Combine());
Packit 8f70b4
	    url=new ParsedURL(host1);
Packit 8f70b4
	 }
Packit 8f70b4
Packit 8f70b4
	 const ParsedURL &uc=*url;
Packit 8f70b4
	 if(uc.host && uc.host[0] && uc.proto)
Packit 8f70b4
	 {
Packit 8f70b4
	    cwd_history.Set(session,session->GetCwd());
Packit 8f70b4
Packit 8f70b4
	    if(uc.user && !user)
Packit 8f70b4
	       user=uc.user;
Packit 8f70b4
	    if(uc.pass && !pass)
Packit 8f70b4
	    {
Packit 8f70b4
	       pass=uc.pass;
Packit 8f70b4
	       insecure=true;
Packit 8f70b4
	    }
Packit 8f70b4
	    host=uc.host;
Packit 8f70b4
	    if(uc.port && !port)
Packit 8f70b4
	       port=uc.port;
Packit 8f70b4
	    if(uc.path && !path)
Packit 8f70b4
	       path=uc.path;
Packit 8f70b4
Packit 8f70b4
	    FileAccess *new_session=FileAccess::New(uc.proto,host,port);
Packit 8f70b4
	    if(!new_session)
Packit 8f70b4
	    {
Packit 8f70b4
	       eprintf("%s: %s%s\n",op,uc.proto.get(),
Packit 8f70b4
			_(" - not supported protocol"));
Packit 8f70b4
	       return 0;
Packit 8f70b4
	    }
Packit 8f70b4
Packit 8f70b4
	    saved_session=session.borrow();
Packit 8f70b4
	    ChangeSession(new_session);
Packit 8f70b4
	 }
Packit 8f70b4
Packit 8f70b4
	 // user gets substituted only if no proto is specified.
Packit 8f70b4
	 if(!pass && (user || no_proto))
Packit 8f70b4
	 {
Packit 8f70b4
	    nrc=NetRC::LookupHost(host,user);
Packit 8f70b4
	    if(nrc)
Packit 8f70b4
	    {
Packit 8f70b4
	       if(!user)
Packit 8f70b4
		  ProtoLog::LogNote(3,"using user `%s' and password from ~/.netrc",nrc->user.get());
Packit 8f70b4
	       else
Packit 8f70b4
		  ProtoLog::LogNote(3,"using password from ~/.netrc");
Packit 8f70b4
	       user=nrc->user;
Packit 8f70b4
	       pass=nrc->pass;
Packit 8f70b4
	    }
Packit 8f70b4
	 }
Packit 8f70b4
      }
Packit 8f70b4
      else if(host && !host[0])
Packit 8f70b4
      {
Packit 8f70b4
	 ChangeSession(new DummyProto);
Packit 8f70b4
      }
Packit 8f70b4
      if(host && host[0] && session->GetHostName()==0)
Packit 8f70b4
	 session->Connect(host,port);
Packit 8f70b4
      if(user && *session->GetProto())
Packit 8f70b4
      {
Packit 8f70b4
	 if(!pass)
Packit 8f70b4
	    pass=GetPass(_("Password: "));
Packit 8f70b4
	 if(!pass)
Packit 8f70b4
	    eprintf(_("%s: GetPass() failed -- assume anonymous login\n"),
Packit 8f70b4
	       args->getarg(0));
Packit 8f70b4
	 else
Packit 8f70b4
	 {
Packit 8f70b4
	    session->Login(user,pass);
Packit 8f70b4
	    // assume the new password is the correct one.
Packit 8f70b4
	    session->SetPasswordGlobal(pass);
Packit 8f70b4
	    session->InsecurePassword(insecure && !no_bm);
Packit 8f70b4
	 }
Packit 8f70b4
      }
Packit 8f70b4
      if(host && host[0])
Packit 8f70b4
      {
Packit 8f70b4
	 if(verify_host && !background)
Packit 8f70b4
	 {
Packit 8f70b4
	    session->ConnectVerify();
Packit 8f70b4
	    builtin=BUILTIN_OPEN;
Packit 8f70b4
	 }
Packit 8f70b4
      }
Packit 8f70b4
      if(nrc)
Packit 8f70b4
	 delete nrc;
Packit 8f70b4
   } // !bookmark
Packit 8f70b4
Packit 8f70b4
   if(path)
Packit 8f70b4
   {
Packit 8f70b4
      const char *old=cwd_history.Lookup(session);
Packit 8f70b4
      if(old)
Packit 8f70b4
      {
Packit 8f70b4
	 bool is_file=false;
Packit 8f70b4
	 const char *old_url=0;
Packit 8f70b4
	 if(url::is_url(old))
Packit 8f70b4
	 {
Packit 8f70b4
	    ParsedURL u(old,true);
Packit 8f70b4
	    old_url=old;
Packit 8f70b4
	    old=alloca_strdup(u.path);
Packit 8f70b4
	    if(url::dir_needs_trailing_slash(u.proto))
Packit 8f70b4
	       is_file=(last_char(old)!='/');
Packit 8f70b4
	 }
Packit 8f70b4
	 else
Packit 8f70b4
	 {
Packit 8f70b4
	    if(url::dir_needs_trailing_slash(session->GetProto()))
Packit 8f70b4
	       is_file=(last_char(old)!='/');
Packit 8f70b4
	 }
Packit 8f70b4
	 session->SetCwd(FileAccess::Path(old,is_file,old_url));
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
      const char *cd_arg=(url && url->orig_url)?url->orig_url.get():path;
Packit 8f70b4
      xstring& s=xstring::get_tmp("&& cd ");
Packit 8f70b4
      s.append_quoted(cd_arg);
Packit 8f70b4
      if(background)
Packit 8f70b4
	 s.append('&';;
Packit 8f70b4
      s.append('\n');
Packit 8f70b4
      PrependCmd(s);
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(slot)
Packit 8f70b4
      ConnectionSlot::Set(slot,session);
Packit 8f70b4
Packit 8f70b4
   Reconfig(0);
Packit 8f70b4
Packit 8f70b4
   if(builtin==BUILTIN_OPEN)
Packit 8f70b4
      return this;
Packit 8f70b4
Packit 8f70b4
   ReuseSavedSession();
Packit 8f70b4
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Job *CmdExec::builtin_restart()
Packit 8f70b4
{
Packit 8f70b4
   builtin=BUILTIN_EXEC_RESTART;
Packit 8f70b4
   return this;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Job *CmdExec::builtin_glob()
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   int opt;
Packit 8f70b4
   GlobURL::type_select glob_type=GlobURL::FILES_ONLY;
Packit 8f70b4
   const char *cmd=0;
Packit 8f70b4
   bool nullglob=false;
Packit 8f70b4
Packit 8f70b4
   static struct option glob_options[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"exist",no_argument,0,'e'},
Packit 8f70b4
      {"not-exist",no_argument,0,'E'},
Packit 8f70b4
      {0}
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
   while((opt=args->getopt_long("+adf",glob_options))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('a'):
Packit 8f70b4
	 glob_type=GlobURL::ALL;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('d'):
Packit 8f70b4
	 glob_type=GlobURL::DIRS_ONLY;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('f'):
Packit 8f70b4
	 glob_type=GlobURL::FILES_ONLY;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('e'):
Packit 8f70b4
	 cmd=".notempty";
Packit 8f70b4
	 nullglob=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('E'):
Packit 8f70b4
	 cmd=".empty";
Packit 8f70b4
	 nullglob=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   while(args->getindex()>1)
Packit 8f70b4
      args->delarg(1);	   // remove options.
Packit 8f70b4
   if(cmd)
Packit 8f70b4
      args->insarg(1,cmd);
Packit 8f70b4
   if(args->count()<2)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("Usage: %s [OPTS] command args...\n"),op);
Packit 8f70b4
      RevertToSavedSession();
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   assert(args_glob==0 && glob==0);
Packit 8f70b4
   args_glob=new ArgV();
Packit 8f70b4
   args->rewind();
Packit 8f70b4
   args_glob->Append(args->getnext());
Packit 8f70b4
   const char *pat=args->getnext();
Packit 8f70b4
   if(!pat)
Packit 8f70b4
   {
Packit 8f70b4
      args_glob=0;
Packit 8f70b4
      args->rewind();
Packit 8f70b4
      RevertToSavedSession();
Packit 8f70b4
      return cmd_command(this);
Packit 8f70b4
   }
Packit 8f70b4
   glob=new GlobURL(session,pat,glob_type);
Packit 8f70b4
   if(nullglob)
Packit 8f70b4
      glob->NullGlob();
Packit 8f70b4
   builtin=BUILTIN_GLOB;
Packit 8f70b4
   return this;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Job *CmdExec::builtin_queue()
Packit 8f70b4
{
Packit 8f70b4
   static struct option queue_options[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"move",required_argument,0,'m'},
Packit 8f70b4
      {"delete",no_argument,0,'d'},
Packit 8f70b4
      {"quiet",no_argument,0,'q'},
Packit 8f70b4
      {"verbose",no_argument,0,'v'},
Packit 8f70b4
      {"queue",required_argument,0,'Q'},
Packit 8f70b4
      {0,0,0,0}
Packit 8f70b4
   };
Packit 8f70b4
   enum { ins, del, move } mode = ins;
Packit 8f70b4
Packit 8f70b4
   const char *arg = NULL;
Packit 8f70b4
   /* position to insert at (ins only) */
Packit 8f70b4
   int pos = -1; /* default to the end */
Packit 8f70b4
   int verbose = -1; /* default */
Packit 8f70b4
Packit 8f70b4
   int opt;
Packit 8f70b4
   while((opt=args->getopt_long("+dm:n:qvQw",queue_options))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case 'n':
Packit 8f70b4
	 /* Actually, sending pos == -1 will work, but it'll put the
Packit 8f70b4
	  * job at the end; it's confusing for "-n 0" to mean "put
Packit 8f70b4
	  * it at the end", and that's the default anyway, so disallow
Packit 8f70b4
	  * it. */
Packit 8f70b4
	 if(!isdigit((unsigned char)optarg[0]) || atoi(optarg) == 0)
Packit 8f70b4
	 {
Packit 8f70b4
	    eprintf(_("%s: -n: positive number expected. "), args->a0());
Packit 8f70b4
	    goto err;
Packit 8f70b4
	 }
Packit 8f70b4
	 /* make offsets match the jobs output (starting at 1) */
Packit 8f70b4
	 pos = atoi(optarg) - 1;
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      case 'm':
Packit 8f70b4
	 mode = move;
Packit 8f70b4
	 arg = optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      case 'd':
Packit 8f70b4
	 mode = del;
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      case 'q':
Packit 8f70b4
	 verbose = 0;
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      case 'v':
Packit 8f70b4
	 verbose = 2;
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      case 'Q':
Packit 8f70b4
	 verbose = QueueFeeder::PrintRequeue;
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      case '?':
Packit 8f70b4
	 err:
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(verbose == -1)
Packit 8f70b4
   {
Packit 8f70b4
      if(mode == ins || mode == move)
Packit 8f70b4
	 verbose = 0;
Packit 8f70b4
      else
Packit 8f70b4
	 verbose = 1;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   const int args_remaining = args->count() - args->getindex();
Packit 8f70b4
   switch(mode) {
Packit 8f70b4
      case ins: {
Packit 8f70b4
	 CmdExec *queue=GetQueue(false);
Packit 8f70b4
	 if(args_remaining==0)
Packit 8f70b4
	 {
Packit 8f70b4
	    if(!queue)
Packit 8f70b4
	    {
Packit 8f70b4
	       if(verbose)
Packit 8f70b4
		  printf(_("Created a stopped queue.\n"));
Packit 8f70b4
	       queue=GetQueue(true);
Packit 8f70b4
	       queue->Suspend();
Packit 8f70b4
	    }
Packit 8f70b4
	    else
Packit 8f70b4
	    {
Packit 8f70b4
	       xstring& buf=xstring::get_tmp("");
Packit 8f70b4
	       queue->FormatStatus(buf,2,"");
Packit 8f70b4
	       printf("%s",buf.get());
Packit 8f70b4
	    }
Packit 8f70b4
	    exit_code=0;
Packit 8f70b4
	    break;
Packit 8f70b4
	 }
Packit 8f70b4
	 if(!queue)
Packit 8f70b4
	    queue=GetQueue(true);
Packit 8f70b4
Packit 8f70b4
	 xstring_ca cmd(args->CombineCmd(args->getindex()));
Packit 8f70b4
Packit 8f70b4
	 if(!strcasecmp(cmd,"stop"))
Packit 8f70b4
	    queue->Suspend();
Packit 8f70b4
	 else if(!strcasecmp(cmd,"start"))
Packit 8f70b4
	    queue->Resume();
Packit 8f70b4
	 else
Packit 8f70b4
	    queue->queue_feeder->QueueCmd(cmd, session->GetCwd(),
Packit 8f70b4
					  cwd?cwd->GetName():0, pos, verbose);
Packit 8f70b4
Packit 8f70b4
	 last_bg=queue->jobno;
Packit 8f70b4
	 exit_code=0;
Packit 8f70b4
      }
Packit 8f70b4
      break;
Packit 8f70b4
Packit 8f70b4
      case del: {
Packit 8f70b4
         /* Accept:
Packit 8f70b4
	  * queue -d (delete the last job)
Packit 8f70b4
	  * queue -d 1  (delete entry 1)
Packit 8f70b4
	  * queue -d "get" (delete all *get*)
Packit 8f70b4
	  *
Packit 8f70b4
	  * We want an optional argument, but don't use getopt ::, since
Packit 8f70b4
	  * that'll disallow the space between arguments, which we want. */
Packit 8f70b4
         arg = args->getarg(args->getindex());
Packit 8f70b4
Packit 8f70b4
	 CmdExec *queue=GetQueue(false);
Packit 8f70b4
	 if(!queue) {
Packit 8f70b4
	    eprintf(_("%s: No queue is active.\n"), args->a0());
Packit 8f70b4
	    break;
Packit 8f70b4
	 }
Packit 8f70b4
Packit 8f70b4
	 if(!arg)
Packit 8f70b4
	    exit_code=!queue->queue_feeder->DelJob(-1, verbose); /* delete the last job */
Packit 8f70b4
	 else if(atoi(arg) != 0)
Packit 8f70b4
	    exit_code=!queue->queue_feeder->DelJob(atoi(arg)-1, verbose);
Packit 8f70b4
	 else
Packit 8f70b4
	    exit_code=!queue->queue_feeder->DelJob(arg, verbose);
Packit 8f70b4
      }
Packit 8f70b4
      break;
Packit 8f70b4
Packit 8f70b4
      case move: {
Packit 8f70b4
         /* Accept:
Packit 8f70b4
	  * queue -m 1 2  (move entry 1 to position 2)
Packit 8f70b4
	  * queue -m "*get*" 1
Packit 8f70b4
	  * queue -m 3    (move entry 3 to the end) */
Packit 8f70b4
         const char *a1 = args->getarg(args->getindex());
Packit 8f70b4
	 if(a1 && !isdigit((unsigned char)a1[0])) {
Packit 8f70b4
	    eprintf(_("%s: -m: Number expected as second argument. "), args->a0());
Packit 8f70b4
	    goto err;
Packit 8f70b4
	 }
Packit 8f70b4
	 /* default to moving to the end */
Packit 8f70b4
	 int to = a1? atoi(a1)-1:-1;
Packit 8f70b4
Packit 8f70b4
	 CmdExec *queue=GetQueue(false);
Packit 8f70b4
	 if(!queue) {
Packit 8f70b4
	    eprintf(_("%s: No queue is active.\n"), args->a0());
Packit 8f70b4
	    break;
Packit 8f70b4
	 }
Packit 8f70b4
Packit 8f70b4
	 if(atoi(arg) != 0) {
Packit 8f70b4
	    exit_code=!queue->queue_feeder->MoveJob(atoi(arg)-1, to, verbose);
Packit 8f70b4
	    break;
Packit 8f70b4
	 }
Packit 8f70b4
Packit 8f70b4
	 exit_code=!queue->queue_feeder->MoveJob(arg, to, verbose);
Packit 8f70b4
      }
Packit 8f70b4
      break;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
// below are only non-builtin commands
Packit 8f70b4
#define args	  (parent->args)
Packit 8f70b4
#define exit_code (parent->exit_code)
Packit 8f70b4
#define output	  (parent->output)
Packit 8f70b4
#define session	  (parent->session)
Packit 8f70b4
#define eprintf	  parent->eprintf
Packit 8f70b4
Packit 8f70b4
CMD(lcd)
Packit 8f70b4
{
Packit 8f70b4
   return parent->builtin_lcd();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(ls)
Packit 8f70b4
{
Packit 8f70b4
   bool nlist=false;
Packit 8f70b4
   bool re=false;
Packit 8f70b4
   int mode=FA::LIST;
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   bool ascii=true;
Packit 8f70b4
   if(strstr(op,"nlist"))
Packit 8f70b4
      nlist=true;
Packit 8f70b4
   if(!strncmp(op,"re",2))
Packit 8f70b4
      re=true;
Packit 8f70b4
   if(!strcmp(op,"quote") || !strcmp(op,"site"))
Packit 8f70b4
   {
Packit 8f70b4
      if(args->count()<=1)
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("Usage: %s <cmd>\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      nlist=true;
Packit 8f70b4
      ascii=false;
Packit 8f70b4
      mode=FA::QUOTE_CMD;
Packit 8f70b4
      if(!strcmp(op,"site"))
Packit 8f70b4
	 args->insarg(1,"SITE");
Packit 8f70b4
   }
Packit 8f70b4
   else if(!strcmp(op,".mplist")) {
Packit 8f70b4
      nlist=true;
Packit 8f70b4
      mode=FA::MP_LIST;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   xstring_ca a(args->Combine(nlist?1:0));
Packit 8f70b4
Packit 8f70b4
   const char *var_ls=ResMgr::Query("cmd:ls-default",session->GetConnectURL(FA::NO_PATH));
Packit 8f70b4
   if(!nlist && args->count()==1 && var_ls[0])
Packit 8f70b4
      args->Append(var_ls);
Packit 8f70b4
Packit 8f70b4
   bool no_status=(!output || output->usesfd(1));
Packit 8f70b4
Packit 8f70b4
   FileCopyPeer *src_peer=0;
Packit 8f70b4
   if(!nlist)
Packit 8f70b4
   {
Packit 8f70b4
      FileCopyPeerDirList *dir_list=new FileCopyPeerDirList(session->Clone(),args.borrow());
Packit 8f70b4
      dir_list->UseColor(ResMgr::QueryTriBool("color:use-color",0,(!output && isatty(1))));
Packit 8f70b4
      src_peer=dir_list;
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
      src_peer=new FileCopyPeerFA(session->Clone(),a,mode);
Packit 8f70b4
Packit 8f70b4
   if(re)
Packit 8f70b4
      src_peer->NoCache();
Packit 8f70b4
   src_peer->SetDate(NO_DATE);
Packit 8f70b4
   src_peer->SetSize(NO_SIZE);
Packit 8f70b4
   FileCopyPeer *dst_peer=new FileCopyPeerFDStream(output.borrow(),FileCopyPeer::PUT);
Packit 8f70b4
Packit 8f70b4
   FileCopy *c=FileCopy::New(src_peer,dst_peer,false);
Packit 8f70b4
   c->DontCopyDate();
Packit 8f70b4
   c->LineBuffered();
Packit 8f70b4
   if(ascii)
Packit 8f70b4
      c->Ascii();
Packit 8f70b4
Packit 8f70b4
   CopyJob *j=new CopyJob(c,a,op);
Packit 8f70b4
   if(no_status)
Packit 8f70b4
      j->NoStatusOnWrite();
Packit 8f70b4
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
/* this seems to belong here more than in FileSetOutput.cc ... */
Packit 8f70b4
const char *FileSetOutput::parse_argv(const Ref<ArgV>& a)
Packit 8f70b4
{
Packit 8f70b4
   enum {
Packit 8f70b4
      OPT_BLOCK_SIZE,
Packit 8f70b4
      OPT_DATE,
Packit 8f70b4
      OPT_FILESIZE,
Packit 8f70b4
      OPT_GROUP,
Packit 8f70b4
      OPT_LINKCOUNT,
Packit 8f70b4
      OPT_LINKS,
Packit 8f70b4
      OPT_PERMS,
Packit 8f70b4
      OPT_SI,
Packit 8f70b4
      OPT_SORT,
Packit 8f70b4
      OPT_TIME_STYLE,
Packit 8f70b4
      OPT_USER
Packit 8f70b4
   };
Packit 8f70b4
   static struct option cls_options[] = {
Packit 8f70b4
      {"all",no_argument,0,'a'},
Packit 8f70b4
      {"basename",no_argument,0,'B'},
Packit 8f70b4
      {"directory",no_argument,0,'d'},
Packit 8f70b4
      {"human-readable",no_argument,0,'h'},
Packit 8f70b4
      {"block-size",required_argument,0,OPT_BLOCK_SIZE},
Packit 8f70b4
      {"si",no_argument,0,OPT_SI},
Packit 8f70b4
      {"classify",no_argument,0,'F'},
Packit 8f70b4
      {"long",no_argument,0,'l'},
Packit 8f70b4
      {"quiet",no_argument,0,'q'},
Packit 8f70b4
      {"size",no_argument,0,'s'},	/* show size */
Packit 8f70b4
      {"filesize",no_argument,0,OPT_FILESIZE},	/* for files only */
Packit 8f70b4
      {"nocase",no_argument,0,'i'},
Packit 8f70b4
      {"sortnocase",no_argument,0,'I'},
Packit 8f70b4
      {"dirsfirst",no_argument,0,'D'},
Packit 8f70b4
      {"time-style",required_argument,0,OPT_TIME_STYLE},
Packit 8f70b4
Packit 8f70b4
      {"sort",required_argument,0,OPT_SORT},
Packit 8f70b4
      {"reverse",no_argument,0,'r'},
Packit 8f70b4
      {"user",no_argument,0,OPT_USER},
Packit 8f70b4
      {"group",no_argument,0,OPT_GROUP},
Packit 8f70b4
      {"perms",no_argument,0,OPT_PERMS},
Packit 8f70b4
      {"date",no_argument,0,OPT_DATE},
Packit 8f70b4
      {"linkcount",no_argument,0,OPT_LINKCOUNT},
Packit 8f70b4
      {"links",no_argument,0,OPT_LINKS},
Packit 8f70b4
      {0,0,0,0}
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
   const char *time_style=ResMgr::Query("cmd:time-style",0);
Packit 8f70b4
Packit 8f70b4
   int opt;
Packit 8f70b4
   while((opt=a->getopt_long(":a1BdFhiklqsDISrt", cls_options))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt) {
Packit 8f70b4
      case OPT_SORT:
Packit 8f70b4
	 if(!strcasecmp(optarg, "name")) sort = FileSet::BYNAME;
Packit 8f70b4
	 else if(!strcasecmp(optarg, "size")) sort = FileSet::BYSIZE;
Packit 8f70b4
	 else if(!strcasecmp(optarg, "date")) sort = FileSet::BYDATE;
Packit 8f70b4
	 else if(!strcasecmp(optarg, "time")) sort = FileSet::BYDATE;
Packit 8f70b4
	 else return _("invalid argument for `--sort'");
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_FILESIZE:
Packit 8f70b4
	 size_filesonly = true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_USER:
Packit 8f70b4
	 mode |= USER;
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_GROUP:
Packit 8f70b4
	 mode |= GROUP;
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_PERMS:
Packit 8f70b4
	 mode |= PERMS;
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_DATE:
Packit 8f70b4
	 mode |= DATE;
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_LINKCOUNT:
Packit 8f70b4
	 mode |= NLINKS;
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_LINKS:
Packit 8f70b4
	 mode |= LINKS;
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_SI:
Packit 8f70b4
	 output_block_size = 1;
Packit 8f70b4
	 human_opts=human_autoscale|human_SI;
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_BLOCK_SIZE:
Packit 8f70b4
	 output_block_size = atoi(optarg);
Packit 8f70b4
	 if(output_block_size == 0)
Packit 8f70b4
	    return _("invalid block size");
Packit 8f70b4
	 break;
Packit 8f70b4
      case('a'):
Packit 8f70b4
	 showdots = true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('1'):
Packit 8f70b4
	 single_column = true;
Packit 8f70b4
         break;
Packit 8f70b4
      case('B'):
Packit 8f70b4
	 basenames = true;
Packit 8f70b4
         break;
Packit 8f70b4
      case('d'):
Packit 8f70b4
	 list_directories = true;
Packit 8f70b4
         break;
Packit 8f70b4
      case('h'):
Packit 8f70b4
	 output_block_size = 1;
Packit 8f70b4
	 human_opts=human_autoscale|human_SI|human_base_1024;
Packit 8f70b4
         break;
Packit 8f70b4
      case('l'):
Packit 8f70b4
	 long_list();
Packit 8f70b4
         break;
Packit 8f70b4
      case('i'):
Packit 8f70b4
	 patterns_casefold = true;
Packit 8f70b4
         break;
Packit 8f70b4
      case('k'):
Packit 8f70b4
	 output_block_size = 1024;
Packit 8f70b4
         break;
Packit 8f70b4
      case('F'):
Packit 8f70b4
         classify=true;
Packit 8f70b4
         break;
Packit 8f70b4
      case('q'):
Packit 8f70b4
	 quiet = true;
Packit 8f70b4
         break;
Packit 8f70b4
      case('s'):
Packit 8f70b4
	 mode |= FileSetOutput::SIZE;
Packit 8f70b4
         break;
Packit 8f70b4
      case('D'):
Packit 8f70b4
	 sort_dirs_first = true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('I'):
Packit 8f70b4
	 sort_casefold = true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('S'):
Packit 8f70b4
	 sort = FileSet::BYSIZE;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('t'):
Packit 8f70b4
	 sort = FileSet::BYDATE;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('r'):
Packit 8f70b4
	 sort_reverse = true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_TIME_STYLE:
Packit 8f70b4
	 time_style=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      default:
Packit 8f70b4
	 return a->getopt_error_message(opt);
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   time_fmt.set(0);
Packit 8f70b4
   if(time_style && time_style[0]) {
Packit 8f70b4
      if (mode & DATE)
Packit 8f70b4
	 need_exact_time=ResMgr::QueryBool("cmd:cls-exact-time",0);
Packit 8f70b4
      if(time_style[0]=='+')
Packit 8f70b4
	 time_fmt.set(time_style+1);
Packit 8f70b4
      else if(!strcmp(time_style,"full-iso"))
Packit 8f70b4
//	 time_fmt.set("%Y-%m-%d %H:%M:%S.%N %z"); // %N and %z are GNU extensions
Packit 8f70b4
	 time_fmt.set("%Y-%m-%d %H:%M:%S");
Packit 8f70b4
      else if(!strcmp(time_style,"long-iso"))
Packit 8f70b4
	 time_fmt.set("%Y-%m-%d %H:%M");
Packit 8f70b4
      else if(!strcmp(time_style,"iso"))
Packit 8f70b4
	 time_fmt.set("%Y-%m-%d \n%m-%d %H:%M");
Packit 8f70b4
      else
Packit 8f70b4
	 time_fmt.set(time_style);
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   // remove parsed options.
Packit 8f70b4
   while(a->getindex()>1)
Packit 8f70b4
      a->delarg(1);
Packit 8f70b4
   a->rewind();
Packit 8f70b4
Packit 8f70b4
   return NULL;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(cls)
Packit 8f70b4
{
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   bool re=false;
Packit 8f70b4
Packit 8f70b4
   JobRef<OutputJob> out(new OutputJob(output.borrow(), args->a0()));
Packit 8f70b4
   Ref<FileSetOutput> fso(new FileSetOutput);
Packit 8f70b4
   fso->config(out);
Packit 8f70b4
Packit 8f70b4
   if(!strncmp(op,"re",2))
Packit 8f70b4
      re=true;
Packit 8f70b4
Packit 8f70b4
   fso->parse_res(ResMgr::Query("cmd:cls-default", 0));
Packit 8f70b4
Packit 8f70b4
   if(const char *err = fso->parse_argv(args)) {
Packit 8f70b4
      eprintf("%s: %s\n", op, err);
Packit 8f70b4
      eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   clsJob *j = new clsJob(session->Clone(), args.borrow(), fso.borrow(), out.borrow());
Packit 8f70b4
   if(re)
Packit 8f70b4
      j->UseCache(false);
Packit 8f70b4
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(cat)
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   int opt;
Packit 8f70b4
   bool ascii=false;
Packit 8f70b4
   bool auto_ascii=true;
Packit 8f70b4
Packit 8f70b4
   while((opt=args->getopt("+bau"))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('a'):
Packit 8f70b4
	 ascii=true;
Packit 8f70b4
	 auto_ascii=false;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('b'):
Packit 8f70b4
	 ascii=false;
Packit 8f70b4
	 auto_ascii=false;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   while(args->getindex()>1)
Packit 8f70b4
      args->delarg(1);
Packit 8f70b4
   args->rewind();
Packit 8f70b4
   if(args->count()<=1)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("Usage: %s [OPTS] files...\n"),op);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   OutputJob *out=new OutputJob(output.borrow(), args->a0());
Packit 8f70b4
   CatJob *j=new CatJob(session->Clone(),out,args.borrow());
Packit 8f70b4
   if(!auto_ascii)
Packit 8f70b4
   {
Packit 8f70b4
      if(ascii)
Packit 8f70b4
	 j->Ascii();
Packit 8f70b4
      else
Packit 8f70b4
	 j->Binary();
Packit 8f70b4
   }
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(get)
Packit 8f70b4
{
Packit 8f70b4
   static struct option get_options[] = {
Packit 8f70b4
      {"continue",no_argument,0,'c'},
Packit 8f70b4
      {"Remove-source-files",no_argument,0,'E'},
Packit 8f70b4
      {"remove-target",no_argument,0,'e'},
Packit 8f70b4
      {"ascii",no_argument,0,'a'},
Packit 8f70b4
      {"target-directory",required_argument,0,'O'},
Packit 8f70b4
      {"destination-directory",required_argument,0,'O'},
Packit 8f70b4
      {"quiet",no_argument,0,'q'},
Packit 8f70b4
      {"parallel",optional_argument,0,'P'},
Packit 8f70b4
      {"use-pget-n",optional_argument,0,'n'},
Packit 8f70b4
      {"glob",no_argument,0,256+'g'},
Packit 8f70b4
      {"reverse",no_argument,0,256+'R'},
Packit 8f70b4
      {0}
Packit 8f70b4
   };
Packit 8f70b4
   const char *opts="+cEeaO:qP";
Packit 8f70b4
Packit 8f70b4
   int opt;
Packit 8f70b4
   bool cont=false;
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   Ref<ArgV> get_args(new ArgV(op));
Packit 8f70b4
   int n_conn=1;
Packit 8f70b4
   int parallel=0;
Packit 8f70b4
   bool del=false;
Packit 8f70b4
   bool del_target=false;
Packit 8f70b4
   bool ascii=false;
Packit 8f70b4
   bool glob=false;
Packit 8f70b4
   bool make_dirs=false;
Packit 8f70b4
   bool reverse=false;
Packit 8f70b4
   bool quiet=false;
Packit 8f70b4
   const char *output_dir=0;
Packit 8f70b4
Packit 8f70b4
   if(!strncmp(op,"re",2))
Packit 8f70b4
   {
Packit 8f70b4
      cont=true;
Packit 8f70b4
      opts="+EaO:qP:";
Packit 8f70b4
   }
Packit 8f70b4
   if(!strcmp(op,"pget"))
Packit 8f70b4
   {
Packit 8f70b4
      opts="+n:ceO:q";
Packit 8f70b4
      n_conn=0; // default, which means to take pget:default-n
Packit 8f70b4
   }
Packit 8f70b4
   else if(!strcmp(op,"put") || !strcmp(op,"reput"))
Packit 8f70b4
   {
Packit 8f70b4
      reverse=true;
Packit 8f70b4
   }
Packit 8f70b4
   else if(!strcmp(op,"mget") || !strcmp(op,"mput"))
Packit 8f70b4
   {
Packit 8f70b4
      glob=true;
Packit 8f70b4
      opts="cEeadO:qP:";
Packit 8f70b4
      reverse=(op[1]=='p');
Packit 8f70b4
   }
Packit 8f70b4
   if(!reverse)
Packit 8f70b4
   {
Packit 8f70b4
      const char *od=ResMgr::Query("xfer:destination-directory",session->GetHostName());
Packit 8f70b4
      if(od && *od)
Packit 8f70b4
	 output_dir=od;
Packit 8f70b4
   }
Packit 8f70b4
   while((opt=args->getopt_long(opts,get_options))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('c'):
Packit 8f70b4
	 cont=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('n'):
Packit 8f70b4
	 if(optarg) {
Packit 8f70b4
	    if(!isdigit((unsigned char)optarg[0]))
Packit 8f70b4
	    {
Packit 8f70b4
	       eprintf(_("%s: %s: Number expected. "),"-n",op);
Packit 8f70b4
	       goto err;
Packit 8f70b4
	    }
Packit 8f70b4
	    n_conn=atoi(optarg);
Packit 8f70b4
	 } else
Packit 8f70b4
	    n_conn=3;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('E'):
Packit 8f70b4
	 del=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('e'):
Packit 8f70b4
	 del_target=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('a'):
Packit 8f70b4
	 ascii=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('d'):
Packit 8f70b4
	 make_dirs=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('O'):
Packit 8f70b4
	 output_dir=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('q'):
Packit 8f70b4
	 quiet=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('P'):
Packit 8f70b4
	 if(optarg) {
Packit 8f70b4
	    if(!isdigit((unsigned char)optarg[0]))
Packit 8f70b4
	    {
Packit 8f70b4
	       eprintf(_("%s: %s: Number expected. "),"-P",op);
Packit 8f70b4
	       goto err;
Packit 8f70b4
	    }
Packit 8f70b4
	    parallel=atoi(optarg);
Packit 8f70b4
	 } else
Packit 8f70b4
	    parallel=3;
Packit 8f70b4
	 break;
Packit 8f70b4
      case(256+'R'):
Packit 8f70b4
	 reverse=!reverse;
Packit 8f70b4
	 break;
Packit 8f70b4
      case(256+'g'):
Packit 8f70b4
	 glob=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
      err:
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   if(cont && del_target) {
Packit 8f70b4
      eprintf(_("%s: --continue conflicts with --remove-target.\n"),op);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   JobRef<GetJob> j;
Packit 8f70b4
   if(glob)
Packit 8f70b4
   {
Packit 8f70b4
      if(args->getcurr()==0)
Packit 8f70b4
      {
Packit 8f70b4
      file_name_missed:
Packit 8f70b4
	 // xgettext:c-format
Packit 8f70b4
	 eprintf(_("File name missed. "));
Packit 8f70b4
	 goto err;
Packit 8f70b4
      }
Packit 8f70b4
      mgetJob *mj=new mgetJob(session->Clone(),args,cont,make_dirs);
Packit 8f70b4
      if(output_dir)
Packit 8f70b4
	 mj->OutputDir(output_dir);
Packit 8f70b4
      j=mj;
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      args->back();
Packit 8f70b4
      const char *a=args->getnext();
Packit 8f70b4
      if(a==0)
Packit 8f70b4
	 goto file_name_missed;
Packit 8f70b4
      while(a)
Packit 8f70b4
      {
Packit 8f70b4
	 const char *src=a;
Packit 8f70b4
	 const char *dst=0;
Packit 8f70b4
	 a=args->getnext();
Packit 8f70b4
	 if(a && !strcmp(a,"-o"))
Packit 8f70b4
	 {
Packit 8f70b4
	    dst=args->getnext();
Packit 8f70b4
	    a=args->getnext();
Packit 8f70b4
	 }
Packit 8f70b4
	 if(reverse)
Packit 8f70b4
	    src=expand_home_relative(src);
Packit 8f70b4
	 dst=output_file_name(src,dst,!reverse,output_dir,false);
Packit 8f70b4
	 get_args->Append(src);
Packit 8f70b4
	 get_args->Append(dst);
Packit 8f70b4
      }
Packit 8f70b4
      j=new GetJob(session->Clone(),get_args.borrow(),cont);
Packit 8f70b4
   }
Packit 8f70b4
   if(reverse)
Packit 8f70b4
      j->Reverse();
Packit 8f70b4
   if(del)
Packit 8f70b4
      j->DeleteFiles();
Packit 8f70b4
   if(del_target)
Packit 8f70b4
      j->RemoveTargetFirst();
Packit 8f70b4
   if(ascii)
Packit 8f70b4
      j->Ascii();
Packit 8f70b4
   if(n_conn!=1)
Packit 8f70b4
      j->SetCopyJobCreator(new pCopyJobCreator(n_conn));
Packit 8f70b4
   if(parallel>0)
Packit 8f70b4
      j->SetParallel(parallel);
Packit 8f70b4
   j->Quiet(quiet);
Packit 8f70b4
   return j.borrow();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(edit)
Packit 8f70b4
{
Packit 8f70b4
   /* Download specified remote file into a temporary local file; run an
Packit 8f70b4
    * editor on it and upload the file back if changed. Remove the temp file. */
Packit 8f70b4
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   xstring temp_file;
Packit 8f70b4
   bool keep_temp=false;
Packit 8f70b4
Packit 8f70b4
   int opt;
Packit 8f70b4
   while((opt=args->getopt("ok"))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('o'):
Packit 8f70b4
	 temp_file.set(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
      case('k'):
Packit 8f70b4
	 keep_temp=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
      err:
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   args->rewind();
Packit 8f70b4
   if(args->count()<=1) {
Packit 8f70b4
      eprintf(_("File name missed. "));
Packit 8f70b4
      goto err;
Packit 8f70b4
   }
Packit 8f70b4
   const char *file=args->getarg(1);
Packit 8f70b4
   if(!temp_file) {
Packit 8f70b4
      ParsedURL u(file);
Packit 8f70b4
      temp_file.set(basename_ptr(u.proto?u.path.get():file));
Packit 8f70b4
      // make temp file name by substituting node name and PID after the first dot.
Packit 8f70b4
      xstring temp_str;
Packit 8f70b4
      temp_str.setf("%s-%u.",get_nodename(),(unsigned)getpid());
Packit 8f70b4
      int point=temp_file.instr('.');
Packit 8f70b4
      temp_file.set_substr(point>=0?point+1:0,0,temp_str);
Packit 8f70b4
      temp_file.set_substr(0,0,"/");
Packit 8f70b4
      xstring temp_dir(dir_file(get_lftp_cache_dir(),"edit"));
Packit 8f70b4
      mkdir(temp_dir,0700);
Packit 8f70b4
      temp_file.set_substr(0,0,temp_dir);
Packit 8f70b4
      if(access(temp_file,F_OK)!=-1)
Packit 8f70b4
	 keep_temp=true;
Packit 8f70b4
   }
Packit 8f70b4
   EditJob *j=new EditJob(session->Clone(),file,temp_file);
Packit 8f70b4
   j->KeepTempFile(keep_temp);
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(shell)
Packit 8f70b4
{
Packit 8f70b4
   Job *j;
Packit 8f70b4
   if(args->count()<=1)
Packit 8f70b4
      j=new SysCmdJob(0);
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      xstring_ca a(args->Combine(1));
Packit 8f70b4
      j=new SysCmdJob(a);
Packit 8f70b4
   }
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(mrm)
Packit 8f70b4
{
Packit 8f70b4
   args->setarg(0,"glob");
Packit 8f70b4
   args->insarg(1,"rm");
Packit 8f70b4
   return parent->builtin_restart();
Packit 8f70b4
}
Packit 8f70b4
CMD(rm)
Packit 8f70b4
{
Packit 8f70b4
   int opt;
Packit 8f70b4
   bool recursive=false;
Packit 8f70b4
   bool silent=false;
Packit 8f70b4
   const char *opts="+rf";
Packit 8f70b4
Packit 8f70b4
   bool rmdir = false;
Packit 8f70b4
   if(!strcmp(args->a0(),"rmdir"))
Packit 8f70b4
   {
Packit 8f70b4
      rmdir = true;
Packit 8f70b4
      opts="+f";
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   while((opt=args->getopt(opts))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('r'):
Packit 8f70b4
	 recursive=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('f'):
Packit 8f70b4
	 silent=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
      print_usage:
Packit 8f70b4
	 eprintf(_("Usage: %s %s[-f] files...\n"),args->a0(), rmdir? "":"[-r] ");
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(args->getcurr()==0)
Packit 8f70b4
      goto print_usage;
Packit 8f70b4
Packit 8f70b4
   rmJob *j=new rmJob(session->Clone(),args.borrow());
Packit 8f70b4
Packit 8f70b4
   if(recursive)
Packit 8f70b4
      j->Recurse();
Packit 8f70b4
   if(rmdir)
Packit 8f70b4
      j->Rmdir();
Packit 8f70b4
Packit 8f70b4
   if(silent)
Packit 8f70b4
      j->BeQuiet();
Packit 8f70b4
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
CMD(mkdir)
Packit 8f70b4
{
Packit 8f70b4
   return new mkdirJob(session->Clone(),args.borrow());
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#ifndef O_ASCII
Packit 8f70b4
# define O_ASCII 0
Packit 8f70b4
#endif
Packit 8f70b4
Packit 8f70b4
CMD(source)
Packit 8f70b4
{
Packit 8f70b4
   int opt;
Packit 8f70b4
   bool e=false;
Packit 8f70b4
   while((opt=args->getopt("+e"))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('e'):
Packit 8f70b4
	 e=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
      usage:
Packit 8f70b4
	 // xgettext:c-format
Packit 8f70b4
	 eprintf(_("Usage: %s [-e] <file|command>\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   if(args->getindex()>=args->count())
Packit 8f70b4
      goto usage;
Packit 8f70b4
   FDStream *f=0;
Packit 8f70b4
   if(e)
Packit 8f70b4
   {
Packit 8f70b4
      xstring_ca cmd(args->Combine(args->getindex()));
Packit 8f70b4
      f=new InputFilter(cmd);
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
      f=new FileStream(args->getarg(1),O_RDONLY|O_ASCII);
Packit 8f70b4
   // try to open the file to return error code if failed, as FileFeeder
Packit 8f70b4
   // cannot feed error codes.
Packit 8f70b4
   if(f->getfd()==-1)
Packit 8f70b4
   {
Packit 8f70b4
      if(f->error())
Packit 8f70b4
      {
Packit 8f70b4
	 fprintf(stderr,"%s: %s\n",args->a0(),f->error_text.get());
Packit 8f70b4
	 delete f;
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   parent->SetCmdFeeder(new FileFeeder(f));
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(jobs)
Packit 8f70b4
{
Packit 8f70b4
   int opt;
Packit 8f70b4
   int v=1;
Packit 8f70b4
   bool recursion=true;
Packit 8f70b4
   while((opt=args->getopt("+vr"))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('v'):
Packit 8f70b4
	 v++;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('r'):
Packit 8f70b4
	 recursion=false;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
         // xgettext:c-format
Packit 8f70b4
	 eprintf(_("Usage: %s [-v] [-v] ...\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   args->back();
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   const char *arg=args->getnext();
Packit 8f70b4
   xstring s("");
Packit 8f70b4
   if(!arg) {
Packit 8f70b4
      parent->top->FormatJobs(s,v);
Packit 8f70b4
   } else {
Packit 8f70b4
      for(; arg; arg=args->getnext()) {
Packit 8f70b4
	 if(!isdigit((unsigned char)*arg)) {
Packit 8f70b4
	    eprintf(_("%s: %s - not a number\n"),op,arg);
Packit 8f70b4
	    exit_code=1;
Packit 8f70b4
	    continue;
Packit 8f70b4
	 }
Packit 8f70b4
	 int n=atoi(arg);
Packit 8f70b4
	 Job *j=parent->FindJob(n);
Packit 8f70b4
	 if(!j) {
Packit 8f70b4
	    eprintf(_("%s: %d - no such job\n"),op,n);
Packit 8f70b4
	    exit_code=1;
Packit 8f70b4
	    continue;
Packit 8f70b4
	 }
Packit 8f70b4
	 if(recursion)
Packit 8f70b4
	    j->FormatOneJobRecursively(s,v);
Packit 8f70b4
	 else
Packit 8f70b4
	    j->FormatOneJob(s,v);
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   if(exit_code)
Packit 8f70b4
      return 0;
Packit 8f70b4
   OutputJob *out=new OutputJob(output.borrow(), args->a0());
Packit 8f70b4
   Job *j=new echoJob(s,s.length(),out);
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(cd)
Packit 8f70b4
{
Packit 8f70b4
   return parent->builtin_cd();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(pwd)
Packit 8f70b4
{
Packit 8f70b4
   int opt;
Packit 8f70b4
   int flags=0;
Packit 8f70b4
   while((opt=args->getopt("p"))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('p'):
Packit 8f70b4
	 flags|=FA::WITH_PASSWORD;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
         // xgettext:c-format
Packit 8f70b4
	 eprintf(_("Usage: %s [-p]\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   const char *url_c=session->GetConnectURL(flags);
Packit 8f70b4
   char *url=alloca_strdup(url_c);
Packit 8f70b4
   int len=strlen(url_c);
Packit 8f70b4
   url[len++]='\n';  // replaces \0
Packit 8f70b4
Packit 8f70b4
   OutputJob *out=new OutputJob(output.borrow(), args->a0());
Packit 8f70b4
   Job *j=new echoJob(url,len,out);
Packit 8f70b4
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(exit)
Packit 8f70b4
{
Packit 8f70b4
   return parent->builtin_exit();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(debug)
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   int	 new_dlevel=DEFAULT_DEBUG_LEVEL;
Packit 8f70b4
   const char *debug_file_name=0;
Packit 8f70b4
   bool  enabled=true;
Packit 8f70b4
   bool	 show_pid=false;
Packit 8f70b4
   bool	 show_time=false;
Packit 8f70b4
   bool	 show_context=false;
Packit 8f70b4
   int	 trunc=0;
Packit 8f70b4
Packit 8f70b4
   int opt;
Packit 8f70b4
   while((opt=args->getopt("To:ptc"))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('T'):
Packit 8f70b4
	 trunc=O_TRUNC;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('o'):
Packit 8f70b4
	 debug_file_name=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'p':
Packit 8f70b4
	 show_pid=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 't':
Packit 8f70b4
	 show_time=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'c':
Packit 8f70b4
	 show_context=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   const char *a=args->getcurr();
Packit 8f70b4
   if(a)
Packit 8f70b4
   {
Packit 8f70b4
      if(!strcasecmp(a,"off"))
Packit 8f70b4
      {
Packit 8f70b4
	 enabled=false;
Packit 8f70b4
      }
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 new_dlevel=atoi(a);
Packit 8f70b4
	 if(new_dlevel<0)
Packit 8f70b4
	    new_dlevel=0;
Packit 8f70b4
	 enabled=true;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(debug_file_name && trunc)
Packit 8f70b4
      truncate(debug_file_name,0);
Packit 8f70b4
Packit 8f70b4
   const char *c="debug";
Packit 8f70b4
   ResMgr::Set("log:file",c,debug_file_name?debug_file_name:"");
Packit 8f70b4
Packit 8f70b4
   ResMgr::Set("log:enabled",c,enabled?"yes":"no");
Packit 8f70b4
   if(enabled)
Packit 8f70b4
      ResMgr::Set("log:level",c,xstring::format("%d",new_dlevel));
Packit 8f70b4
Packit 8f70b4
   ResMgr::Set("log:show-pid",c,show_pid?"yes":"no");
Packit 8f70b4
   ResMgr::Set("log:show-time",c,show_time?"yes":"no");
Packit 8f70b4
   ResMgr::Set("log:show-ctx",c,show_context?"yes":"no");
Packit 8f70b4
Packit 8f70b4
#if 0
Packit 8f70b4
   if(interactive)
Packit 8f70b4
   {
Packit 8f70b4
      if(enabled)
Packit 8f70b4
	 printf(_("debug level is %d, output goes to %s\n"),new_dlevel,
Packit 8f70b4
		     debug_file_name?debug_file_name:"<stderr>");
Packit 8f70b4
      else
Packit 8f70b4
	 printf(_("debug is off\n"));
Packit 8f70b4
   }
Packit 8f70b4
#endif
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(user)
Packit 8f70b4
{
Packit 8f70b4
   if(args->count()<2 || args->count()>3)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("Usage: %s <user|URL> [<pass>]\n"),args->getarg(0));
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   const char *user=args->getarg(1);
Packit 8f70b4
   const char *pass=args->getarg(2);
Packit 8f70b4
   bool insecure=(pass!=0);
Packit 8f70b4
Packit 8f70b4
   ParsedURL u(user,true);
Packit 8f70b4
   if(u.proto && !u.user)
Packit 8f70b4
   {
Packit 8f70b4
      exit_code=0;
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   if(u.proto && u.user && u.pass)
Packit 8f70b4
   {
Packit 8f70b4
      pass=u.pass;
Packit 8f70b4
      insecure=true;
Packit 8f70b4
   }
Packit 8f70b4
   if(!pass)
Packit 8f70b4
      pass=GetPass(_("Password: "));
Packit 8f70b4
   if(!pass)
Packit 8f70b4
      return 0;
Packit 8f70b4
Packit 8f70b4
   if(u.proto && u.user)
Packit 8f70b4
   {
Packit 8f70b4
      FA *s=FA::New(&u,false);
Packit 8f70b4
      if(s)
Packit 8f70b4
      {
Packit 8f70b4
	 s->SetPasswordGlobal(pass);
Packit 8f70b4
	 s->InsecurePassword(insecure);
Packit 8f70b4
	 SessionPool::Reuse(s);
Packit 8f70b4
      }
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf("%s: %s%s\n",args->a0(),u.proto.get(),
Packit 8f70b4
		  _(" - not supported protocol"));
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      session->Login(args->getarg(1),0);
Packit 8f70b4
      session->SetPasswordGlobal(pass);
Packit 8f70b4
      session->InsecurePassword(insecure);
Packit 8f70b4
   }
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
CMD(anon)
Packit 8f70b4
{
Packit 8f70b4
   session->AnonymousLogin();
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(lftp)
Packit 8f70b4
{
Packit 8f70b4
   return parent->builtin_lftp();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(open)
Packit 8f70b4
{
Packit 8f70b4
   return parent->builtin_open();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(kill)
Packit 8f70b4
{
Packit 8f70b4
   int n;
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   if(args->count()<2)
Packit 8f70b4
   {
Packit 8f70b4
#if 0 // too dangerous to kill last job. Better require explicit number.
Packit 8f70b4
      n=parent->last_bg;
Packit 8f70b4
      if(n==-1)
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("%s: no current job\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      printf("%s %d\n",op,n);
Packit 8f70b4
      if(Job::Running(n))
Packit 8f70b4
      {
Packit 8f70b4
	 parent->Kill(n);
Packit 8f70b4
	 exit_code=0;
Packit 8f70b4
      }
Packit 8f70b4
      else
Packit 8f70b4
	 eprintf(_("%s: %d - no such job\n"),op,n);
Packit 8f70b4
#else
Packit 8f70b4
      eprintf(_("Usage: %s <jobno> ... | all\n"),args->getarg(0));
Packit 8f70b4
#endif
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   if(!strcasecmp(args->getarg(1),"all"))
Packit 8f70b4
   {
Packit 8f70b4
      parent->KillAll();
Packit 8f70b4
      exit_code=0;
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   args->rewind();
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   for(;;)
Packit 8f70b4
   {
Packit 8f70b4
      const char *arg=args->getnext();
Packit 8f70b4
      if(arg==0)
Packit 8f70b4
	 break;
Packit 8f70b4
      if(!isdigit((unsigned char)arg[0]))
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("%s: %s - not a number\n"),op,arg);
Packit 8f70b4
	 exit_code=1;
Packit 8f70b4
	 continue;
Packit 8f70b4
      }
Packit 8f70b4
      n=atoi(arg);
Packit 8f70b4
      if(Job::Running(n))
Packit 8f70b4
	 parent->Kill(n);
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("%s: %d - no such job\n"),op,n);
Packit 8f70b4
	 exit_code=1;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(set)
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   bool with_defaults=false;
Packit 8f70b4
   bool only_defaults=false;
Packit 8f70b4
   int c;
Packit 8f70b4
Packit 8f70b4
   while((c=args->getopt("+ad"))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(c)
Packit 8f70b4
      {
Packit 8f70b4
      case 'a':
Packit 8f70b4
	 with_defaults=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'd':
Packit 8f70b4
	 only_defaults=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      default:
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   args->back();
Packit 8f70b4
   const char *ac=args->getnext();
Packit 8f70b4
   if(ac==0)
Packit 8f70b4
   {
Packit 8f70b4
      xstring_ca s(ResMgr::Format(with_defaults,only_defaults));
Packit 8f70b4
      OutputJob *out=new OutputJob(output.borrow(), args->a0());
Packit 8f70b4
      Job *j=new echoJob(s,out);
Packit 8f70b4
      return j;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   char *a=alloca_strdup(ac);
Packit 8f70b4
   char *sl=strchr(a,'/');
Packit 8f70b4
   char *closure=0;
Packit 8f70b4
   if(sl)
Packit 8f70b4
   {
Packit 8f70b4
      *sl=0;
Packit 8f70b4
      closure=sl+1;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   const ResType *type;
Packit 8f70b4
   // find type of given variable
Packit 8f70b4
   const char *msg=ResMgr::FindVar(a,&type);
Packit 8f70b4
   if(msg)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("%s: %s. Use `set -a' to look at all variables.\n"),a,msg);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   args->getnext();
Packit 8f70b4
   xstring_ca val(args->getcurr()==0?0:args->Combine(args->getindex()));
Packit 8f70b4
   msg=ResMgr::Set(a,closure,val);
Packit 8f70b4
Packit 8f70b4
   if(msg)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf("%s: %s.\n",val.get(),msg);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(alias)
Packit 8f70b4
{
Packit 8f70b4
   if(args->count()<2)
Packit 8f70b4
   {
Packit 8f70b4
      xstring_ca list(Alias::Format());
Packit 8f70b4
      OutputJob *out=new OutputJob(output.borrow(), args->a0());
Packit 8f70b4
      Job *j=new echoJob(list,out);
Packit 8f70b4
      return j;
Packit 8f70b4
   }
Packit 8f70b4
   else if(args->count()==2)
Packit 8f70b4
   {
Packit 8f70b4
      Alias::Del(args->getarg(1));
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      xstring_ca val(args->Combine(2));
Packit 8f70b4
      Alias::Add(args->getarg(1),val);
Packit 8f70b4
   }
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(wait)
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   if(args->count()>2)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("Usage: %s [<jobno>]\n"),op);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   int n=-1;
Packit 8f70b4
   const char *jn=args->getnext();
Packit 8f70b4
   if(jn)
Packit 8f70b4
   {
Packit 8f70b4
      if(!strcasecmp(jn,"all"))
Packit 8f70b4
      {
Packit 8f70b4
	 parent->WaitForAllChildren();
Packit 8f70b4
	 parent->AllWaitingFg();
Packit 8f70b4
	 exit_code=0;
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      if(!isdigit((unsigned char)jn[0]))
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("%s: %s - not a number\n"),op,jn);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      n=atoi(jn);
Packit 8f70b4
   }
Packit 8f70b4
   if(n==-1)
Packit 8f70b4
   {
Packit 8f70b4
      n=parent->last_bg;
Packit 8f70b4
      if(n==-1)
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("%s: no current job\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      printf("%s %d\n",op,n);
Packit 8f70b4
   }
Packit 8f70b4
   Job *j=parent->FindJob(n);
Packit 8f70b4
   if(j==0)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("%s: %d - no such job\n"),op,n);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   if(Job::FindWhoWaitsFor(j)!=0)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("%s: some other job waits for job %d\n"),op,n);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   if(j->Job::CheckForWaitLoop(parent))
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("%s: wait loop detected\n"),op);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   j->SetParent(0);
Packit 8f70b4
   j->Bg();
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(subsh)
Packit 8f70b4
{
Packit 8f70b4
   CmdExec *e=new CmdExec(parent);
Packit 8f70b4
Packit 8f70b4
   const char *c=args->getarg(1);
Packit 8f70b4
   e->FeedCmd(c);
Packit 8f70b4
   e->FeedCmd("\n");
Packit 8f70b4
   e->cmdline.vset("(",c,")",NULL);
Packit 8f70b4
   return e;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(mmv)
Packit 8f70b4
{
Packit 8f70b4
   static const struct option mmv_opts[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"target-directory",required_argument,0,'O'},
Packit 8f70b4
      {"destination-directory",required_argument,0,'O'},
Packit 8f70b4
      {"remove-target-first",no_argument,0,'e'},
Packit 8f70b4
      {0}
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
   bool remove_target=false;
Packit 8f70b4
   const char *target_dir=0;
Packit 8f70b4
   args->rewind();
Packit 8f70b4
   int opt;
Packit 8f70b4
   while((opt=args->getopt_long("eO:t:",mmv_opts,0))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('e'):
Packit 8f70b4
	 remove_target=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('t'):
Packit 8f70b4
      case('O'):
Packit 8f70b4
	 target_dir=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
      help:
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   if(!target_dir && args->count()>=3) {
Packit 8f70b4
      target_dir=args->getarg(args->count()-1);
Packit 8f70b4
      target_dir=alloca_strdup(target_dir);
Packit 8f70b4
      args->delarg(args->count()-1);
Packit 8f70b4
   }
Packit 8f70b4
   if(!target_dir || args->getindex()>=args->count()) {
Packit 8f70b4
      eprintf(_("Usage: %s [OPTS] <files> <target-dir>\n"),args->a0());
Packit 8f70b4
      goto help;
Packit 8f70b4
   }
Packit 8f70b4
   mmvJob *j=new mmvJob(session->Clone(),args,target_dir,FA::RENAME);
Packit 8f70b4
   if(remove_target)
Packit 8f70b4
      j->RemoveTargetFirst();
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(mv)
Packit 8f70b4
{
Packit 8f70b4
   if(args->count()!=3
Packit 8f70b4
   || (args->count()==3 && last_char(args->getarg(2))=='/'))
Packit 8f70b4
   {
Packit 8f70b4
      args->setarg(0,"mmv");
Packit 8f70b4
      return cmd_mmv(parent);
Packit 8f70b4
   }
Packit 8f70b4
   Job *j=new mvJob(session->Clone(),args->getarg(1),args->getarg(2));
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(ln)
Packit 8f70b4
{
Packit 8f70b4
   FA::open_mode m=FA::LINK;
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   int c;
Packit 8f70b4
   while((c=args->getopt("+s"))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(c)
Packit 8f70b4
      {
Packit 8f70b4
      case 's':
Packit 8f70b4
	 m=FA::SYMLINK;
Packit 8f70b4
	 break;
Packit 8f70b4
      default:
Packit 8f70b4
      error:
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   args->back();
Packit 8f70b4
   const char *file1=args->getnext();
Packit 8f70b4
   const char *file2=args->getnext();
Packit 8f70b4
   if(!file1 || !file2)
Packit 8f70b4
      goto error;
Packit 8f70b4
Packit 8f70b4
   return new mvJob(session->Clone(),file1,file2,m);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
const char *const cache_subcmd[]={
Packit 8f70b4
   "status","flush","on","off","size","expire",
Packit 8f70b4
   NULL
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
CMD(cache)  // cache control
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->getnext();
Packit 8f70b4
Packit 8f70b4
   if(!op)
Packit 8f70b4
      op="status";
Packit 8f70b4
   else if(!find_command(op,cache_subcmd,&op))
Packit 8f70b4
   {
Packit 8f70b4
      // xgettext:c-format
Packit 8f70b4
      eprintf(_("Invalid command. "));
Packit 8f70b4
      eprintf(_("Try `help %s' for more information.\n"),args->a0());
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   if(!op)
Packit 8f70b4
   {
Packit 8f70b4
      // xgettext:c-format
Packit 8f70b4
      eprintf(_("Ambiguous command. "));
Packit 8f70b4
      eprintf(_("Try `help %s' for more information.\n"),args->a0());
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   if(!op || !strcasecmp(op,"status"))
Packit 8f70b4
      FileAccess::cache->List();
Packit 8f70b4
   else if(!strcasecmp(op,"flush"))
Packit 8f70b4
      FileAccess::cache->Flush();
Packit 8f70b4
   else if(!strcasecmp(op,"on"))
Packit 8f70b4
      ResMgr::Set("cache:enable",0,"yes");
Packit 8f70b4
   else if(!strcasecmp(op,"off"))
Packit 8f70b4
      ResMgr::Set("cache:enable",0,"no");
Packit 8f70b4
   else if(!strcasecmp(op,"size"))
Packit 8f70b4
   {
Packit 8f70b4
      op=args->getnext();
Packit 8f70b4
      if(!op)
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("%s: Operand missed for size\n"),args->a0());
Packit 8f70b4
	 exit_code=1;
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      const char *err=ResMgr::Set("cache:size",0,op);
Packit 8f70b4
      if(err)
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf("%s: %s: %s\n",args->a0(),op,err);
Packit 8f70b4
	 exit_code=1;
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   else if(!strcasecmp(op,"expire"))
Packit 8f70b4
   {
Packit 8f70b4
      op=args->getnext();
Packit 8f70b4
      if(!op)
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("%s: Operand missed for `expire'\n"),args->a0());
Packit 8f70b4
	 exit_code=1;
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      const char *err=ResMgr::Set("cache:expire",0,op);
Packit 8f70b4
      if(err)
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf("%s: %s: %s\n",args->a0(),op,err);
Packit 8f70b4
	 exit_code=1;
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(scache)
Packit 8f70b4
{
Packit 8f70b4
   if(args->count()==1)
Packit 8f70b4
   {
Packit 8f70b4
      SessionPool::Print(stdout);
Packit 8f70b4
      exit_code=0;
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      const char *a=args->getarg(1);
Packit 8f70b4
      if(!isdigit((unsigned char)a[0]))
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("%s: %s - not a number\n"),args->a0(),a);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      FileAccess *new_session=SessionPool::GetSession(atoi(a));
Packit 8f70b4
      if(new_session==0)
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf(_("%s: %s - no such cached session. Use `scache' to look at session list.\n"),args->a0(),a);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      parent->ChangeSession(new_session);
Packit 8f70b4
   }
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
bool CmdExec::print_cmd_help(const char *cmd)
Packit 8f70b4
{
Packit 8f70b4
   const cmd_rec *c;
Packit 8f70b4
   int part=find_cmd(cmd,&c);
Packit 8f70b4
Packit 8f70b4
   if(part==1)
Packit 8f70b4
   {
Packit 8f70b4
      if(c->creator==0 || !xstrcmp(c->long_desc,HELP_IN_MODULE)) {
Packit 8f70b4
	 // try to load the module which can have a help text
Packit 8f70b4
	 if(load_cmd_module(c->name))
Packit 8f70b4
	    find_cmd(c->name,&c);
Packit 8f70b4
	 else
Packit 8f70b4
	    return false;
Packit 8f70b4
      }
Packit 8f70b4
      if(c->long_desc==0 && c->short_desc==0)
Packit 8f70b4
      {
Packit 8f70b4
	 printf(_("Sorry, no help for %s\n"),cmd);
Packit 8f70b4
	 return true;
Packit 8f70b4
      }
Packit 8f70b4
      if(c->short_desc==0 && !strchr(c->long_desc,' '))
Packit 8f70b4
      {
Packit 8f70b4
	 printf(_("%s is a built-in alias for %s\n"),cmd,c->long_desc);
Packit 8f70b4
	 print_cmd_help(c->long_desc);
Packit 8f70b4
	 return true;
Packit 8f70b4
      }
Packit 8f70b4
      if(c->short_desc)
Packit 8f70b4
	 printf(_("Usage: %s\n"),_(c->short_desc));
Packit 8f70b4
      if(c->long_desc)
Packit 8f70b4
	 printf("%s",_(c->long_desc));
Packit 8f70b4
      return true;
Packit 8f70b4
   }
Packit 8f70b4
   const char *a=Alias::Find(cmd);
Packit 8f70b4
   if(a)
Packit 8f70b4
   {
Packit 8f70b4
      printf(_("%s is an alias to `%s'\n"),cmd,a);
Packit 8f70b4
      return true;
Packit 8f70b4
   }
Packit 8f70b4
   if(part==0)
Packit 8f70b4
      printf(_("No such command `%s'. Use `help' to see available commands.\n"),cmd);
Packit 8f70b4
   else
Packit 8f70b4
      printf(_("Ambiguous command `%s'. Use `help' to see available commands.\n"),cmd);
Packit 8f70b4
   return false;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void CmdExec::print_cmd_index()
Packit 8f70b4
{
Packit 8f70b4
   int i=0;
Packit 8f70b4
   const cmd_rec *cmd_table=dyn_cmd_table?dyn_cmd_table.get():static_cmd_table;
Packit 8f70b4
   const int count=dyn_cmd_table?dyn_cmd_table.count():static_cmd_table_length;
Packit 8f70b4
   int width=fd_width(1);
Packit 8f70b4
   int pos=0;
Packit 8f70b4
   const int align=37;
Packit 8f70b4
   const int first_align=4;
Packit 8f70b4
   while(i
Packit 8f70b4
   {
Packit 8f70b4
      while(i
Packit 8f70b4
	 i++;
Packit 8f70b4
      if(i>=count)
Packit 8f70b4
	 break;
Packit 8f70b4
      const char *c1=gettext(cmd_table[i].short_desc);
Packit 8f70b4
      i++;
Packit 8f70b4
      int w1=mbswidth(c1,0);
Packit 8f70b4
Packit 8f70b4
      int pad=0;
Packit 8f70b4
      if(pos
Packit 8f70b4
	 pad=first_align-pos;
Packit 8f70b4
      else if(pos>first_align)
Packit 8f70b4
	 pad=align-(pos-first_align)%align;
Packit 8f70b4
      if(pos>first_align && pos+pad+w1>=width) {
Packit 8f70b4
	 printf("\n");
Packit 8f70b4
	 pos=0;
Packit 8f70b4
	 pad=first_align;
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
      printf("%*s%s",pad,"",c1);
Packit 8f70b4
      pos+=pad+w1;
Packit 8f70b4
   }
Packit 8f70b4
   if(pos>0)
Packit 8f70b4
      printf("\n");
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(help)
Packit 8f70b4
{
Packit 8f70b4
   if(args->count()>1)
Packit 8f70b4
   {
Packit 8f70b4
      exit_code=0;
Packit 8f70b4
      for(;;)
Packit 8f70b4
      {
Packit 8f70b4
	 const char *cmd=args->getnext();
Packit 8f70b4
	 if(cmd==0)
Packit 8f70b4
	    break;
Packit 8f70b4
	 if(!parent->print_cmd_help(cmd))
Packit 8f70b4
	    exit_code=1;
Packit 8f70b4
      }
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   parent->print_cmd_index();
Packit 8f70b4
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(ver)
Packit 8f70b4
{
Packit 8f70b4
   printf(
Packit 8f70b4
      _("LFTP | Version %s | Copyright (c) 1996-%d Alexander V. Lukyanov\n"),VERSION,2017);
Packit 8f70b4
   printf("\n");
Packit 8f70b4
   printf(
Packit 8f70b4
      _("LFTP is free software: you can redistribute it and/or modify\n"
Packit 8f70b4
      "it under the terms of the GNU General Public License as published by\n"
Packit 8f70b4
      "the Free Software Foundation, either version 3 of the License, or\n"
Packit 8f70b4
      "(at your option) any later version.\n"
Packit 8f70b4
      "\n"
Packit 8f70b4
      "This program is distributed in the hope that it will be useful,\n"
Packit 8f70b4
      "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
Packit 8f70b4
      "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
Packit 8f70b4
      "GNU General Public License for more details.\n"
Packit 8f70b4
      "\n"
Packit 8f70b4
      "You should have received a copy of the GNU General Public License\n"
Packit 8f70b4
      "along with LFTP.  If not, see <http://www.gnu.org/licenses/>.\n"));
Packit 8f70b4
   printf("\n");
Packit 8f70b4
   printf(
Packit 8f70b4
      _("Send bug reports and questions to the mailing list <%s>.\n"),"lftp@uniyar.ac.ru");
Packit 8f70b4
Packit 8f70b4
#if defined(HAVE_DLOPEN) && defined(RTLD_DEFAULT)
Packit 8f70b4
   /* Show some of loaded libraries. Modules can load those libraries on
Packit 8f70b4
      demand so use dlsym to avoid linking with them just for showing version. */
Packit 8f70b4
   printf("\n");
Packit 8f70b4
   const char *msg=_("Libraries used: ");
Packit 8f70b4
   int mbflags=0;
Packit 8f70b4
   int col=mbswidth(msg,mbflags);
Packit 8f70b4
   int width=parent->status_line?parent->status_line->GetWidth():80;
Packit 8f70b4
   printf("%s",msg);
Packit 8f70b4
Packit 8f70b4
   struct VersionInfo
Packit 8f70b4
   {
Packit 8f70b4
      const char *lib_name;
Packit 8f70b4
      const char *symbol;
Packit 8f70b4
      enum type_t { STRING_PTR, FUNC0, INT8_8 } type;
Packit 8f70b4
      const char *skip_prefix;
Packit 8f70b4
      typedef const char *(*func0)(void *);
Packit 8f70b4
      const char *query() const
Packit 8f70b4
	 {
Packit 8f70b4
	    int v;
Packit 8f70b4
	    void *sym_ptr=dlsym(RTLD_DEFAULT,symbol);
Packit 8f70b4
	    if(!sym_ptr)
Packit 8f70b4
	       return 0;
Packit 8f70b4
	    const char *str=0;
Packit 8f70b4
	    switch(type)
Packit 8f70b4
	    {
Packit 8f70b4
	    case STRING_PTR:
Packit 8f70b4
	       str=*(const char**)sym_ptr;
Packit 8f70b4
	       break;
Packit 8f70b4
	    case FUNC0:
Packit 8f70b4
	       str=((func0)sym_ptr)(NULL);
Packit 8f70b4
	       break;
Packit 8f70b4
	    case INT8_8:
Packit 8f70b4
	       v=*(int*)sym_ptr;
Packit 8f70b4
	       str=xstring::format("%d.%d",(v>>8)&255,v&255);
Packit 8f70b4
	    }
Packit 8f70b4
	    if(!str)
Packit 8f70b4
	       return 0;
Packit 8f70b4
	    if(skip_prefix && !strncmp(str,skip_prefix,strlen(skip_prefix)))
Packit 8f70b4
	       str+=strlen(skip_prefix);
Packit 8f70b4
	    return str;
Packit 8f70b4
	 }
Packit 8f70b4
   }
Packit 8f70b4
   static const libs[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"Expat",	     "XML_ExpatVersion",     VersionInfo::FUNC0,     "expat_"},
Packit 8f70b4
      {"GnuTLS",     "gnutls_check_version", VersionInfo::FUNC0,     0},
Packit 8f70b4
      {"idn2",	     "idn2_check_version",   VersionInfo::FUNC0,     0},
Packit 8f70b4
      {"libiconv",   "_libiconv_version",    VersionInfo::INT8_8,    0},
Packit 8f70b4
      {"OpenSSL",    "SSL_version_str",	     VersionInfo::STRING_PTR,"OpenSSL "},
Packit 8f70b4
      {"Readline",   "rl_library_version",   VersionInfo::STRING_PTR,0},
Packit 8f70b4
      {"zlib",	     "zlibVersion",	     VersionInfo::FUNC0,     0},
Packit 8f70b4
      {0}
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
   bool need_comma=false;
Packit 8f70b4
   for(const VersionInfo *scan=libs; scan->lib_name; scan++)
Packit 8f70b4
   {
Packit 8f70b4
      const char *v=scan->query();
Packit 8f70b4
      if(!v)
Packit 8f70b4
	 continue;
Packit 8f70b4
      char buf[256];
Packit 8f70b4
      snprintf(buf,sizeof(buf),", %s %s",scan->lib_name,v);
Packit 8f70b4
      int skip=need_comma?0:2;
Packit 8f70b4
      int w=mbswidth(buf+skip,mbflags);
Packit 8f70b4
      if(col+w>=width && need_comma)
Packit 8f70b4
      {
Packit 8f70b4
	 buf[1]='\n';
Packit 8f70b4
	 col=w-2;
Packit 8f70b4
      }
Packit 8f70b4
      else
Packit 8f70b4
	 col+=w;
Packit 8f70b4
      printf("%s",buf+skip);
Packit 8f70b4
      need_comma=true;
Packit 8f70b4
   }
Packit 8f70b4
   printf("\n");
Packit 8f70b4
#endif // HAVE_DLOPEN
Packit 8f70b4
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(close)
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   bool all=false;
Packit 8f70b4
   int opt;
Packit 8f70b4
   while((opt=args->getopt("a"))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('a'):
Packit 8f70b4
	 all=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   if(all)
Packit 8f70b4
      session->CleanupAll();
Packit 8f70b4
   else
Packit 8f70b4
      session->Cleanup();
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
const char * const bookmark_subcmd[]=
Packit 8f70b4
   {"add","delete","list","list-p","edit","import",0};
Packit 8f70b4
static ResDecl res_save_passwords
Packit 8f70b4
   ("bmk:save-passwords","no",ResMgr::BoolValidate,0);
Packit 8f70b4
Packit 8f70b4
CMD(bookmark)
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->getnext();
Packit 8f70b4
Packit 8f70b4
   if(!op)
Packit 8f70b4
      op="list";
Packit 8f70b4
   else if(!find_command(op,bookmark_subcmd,&op))
Packit 8f70b4
   {
Packit 8f70b4
      // xgettext:c-format
Packit 8f70b4
      eprintf(_("Invalid command. "));
Packit 8f70b4
      eprintf(_("Try `help %s' for more information.\n"),args->a0());
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   if(!op)
Packit 8f70b4
   {
Packit 8f70b4
      // xgettext:c-format
Packit 8f70b4
      eprintf(_("Ambiguous command. "));
Packit 8f70b4
      eprintf(_("Try `help %s' for more information.\n"),args->a0());
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(!strcasecmp(op,"list") || !strcasecmp(op,"list-p"))
Packit 8f70b4
   {
Packit 8f70b4
      xstring_ca list(op[4]?lftp_bookmarks.Format():lftp_bookmarks.FormatHidePasswords());
Packit 8f70b4
      OutputJob *out=new OutputJob(output.borrow(), args->a0());
Packit 8f70b4
      Job *j=new echoJob(list,out);
Packit 8f70b4
      return j;
Packit 8f70b4
   }
Packit 8f70b4
   else if(!strcasecmp(op,"add"))
Packit 8f70b4
   {
Packit 8f70b4
      const char *key=args->getnext();
Packit 8f70b4
      if(key==0 || key[0]==0)
Packit 8f70b4
	 eprintf(_("%s: bookmark name required\n"),args->a0());
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 const char *value=args->getnext();
Packit 8f70b4
	 int flags=0;
Packit 8f70b4
	 if(res_save_passwords.QueryBool(session->GetHostName()))
Packit 8f70b4
	    flags|=session->WITH_PASSWORD;
Packit 8f70b4
	 if(value==0)
Packit 8f70b4
	 {
Packit 8f70b4
	    value=session->GetConnectURL(flags);
Packit 8f70b4
	    // encode some more characters, special to CmdExec parser.
Packit 8f70b4
	    value=url::encode(value,"&;|\"'\\");
Packit 8f70b4
	 }
Packit 8f70b4
	 if(value==0 || value[0]==0)
Packit 8f70b4
	    value="\"\"";
Packit 8f70b4
	 if(strchr(key,' ') || strchr(key,'\t'))
Packit 8f70b4
	 {
Packit 8f70b4
	    eprintf(_("%s: spaces in bookmark name are not allowed\n"),args->a0());
Packit 8f70b4
	    return 0;
Packit 8f70b4
	 }
Packit 8f70b4
	 lftp_bookmarks.Add(key,value);
Packit 8f70b4
	 exit_code=0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   else if(!strcasecmp(op,"delete"))
Packit 8f70b4
   {
Packit 8f70b4
      const char *key=args->getnext();
Packit 8f70b4
      if(key==0 || key[0]==0)
Packit 8f70b4
	 eprintf(_("%s: bookmark name required\n"),args->a0());
Packit 8f70b4
      else if(lftp_bookmarks.Lookup(key)==0)
Packit 8f70b4
	 eprintf(_("%s: no such bookmark `%s'\n"),args->a0(),key);
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 lftp_bookmarks.Remove(key);
Packit 8f70b4
	 exit_code=0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   else if(!strcasecmp(op,"edit"))
Packit 8f70b4
   {
Packit 8f70b4
      lftp_bookmarks.Remove(""); // force bookmark file creation
Packit 8f70b4
Packit 8f70b4
      xstring cmd0("exec ${EDITOR:-vi} ");
Packit 8f70b4
      cmd0.append(shell_encode(lftp_bookmarks.GetFilePath()));
Packit 8f70b4
      xstring cmd1("/bin/sh -c ");
Packit 8f70b4
      cmd1.append(shell_encode(cmd0));
Packit 8f70b4
Packit 8f70b4
      parent->PrependCmd(xstring::get_tmp("shell ").append_quoted(cmd1));
Packit 8f70b4
   }
Packit 8f70b4
   else if(!strcasecmp(op,"import"))
Packit 8f70b4
   {
Packit 8f70b4
      op=args->getnext();
Packit 8f70b4
      if(!op)
Packit 8f70b4
	 eprintf(_("%s: import type required (netscape,ncftp)\n"),args->a0());
Packit 8f70b4
      else
Packit 8f70b4
      {
Packit 8f70b4
	 parent->PrependCmd(xstring::cat("shell " PKGDATADIR "/import-",op,"\n",NULL));
Packit 8f70b4
	 exit_code=0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   else if(!strcasecmp(op,"load"))
Packit 8f70b4
   {
Packit 8f70b4
      lftp_bookmarks.UserLoad();
Packit 8f70b4
      exit_code=0;
Packit 8f70b4
   }
Packit 8f70b4
   else if(!strcasecmp(op,"save"))
Packit 8f70b4
   {
Packit 8f70b4
      lftp_bookmarks.UserSave();
Packit 8f70b4
      exit_code=0;
Packit 8f70b4
   }
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(echo)
Packit 8f70b4
{
Packit 8f70b4
   xstring s;
Packit 8f70b4
   args->CombineTo(s,1);
Packit 8f70b4
   if(args->count()>1 && !strcmp(args->getarg(1),"-n"))
Packit 8f70b4
   {
Packit 8f70b4
      if(s.length()<=3)
Packit 8f70b4
      {
Packit 8f70b4
	 exit_code=0;
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
      s.set_substr(0,3,"");
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      s.append('\n');
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   OutputJob *out=new OutputJob(output.borrow(), args->a0());
Packit 8f70b4
   Job *j=new echoJob(s,s.length(),out);
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(suspend)
Packit 8f70b4
{
Packit 8f70b4
   kill(getpid(),SIGSTOP);
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(find)
Packit 8f70b4
{
Packit 8f70b4
   static struct option find_options[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"maxdepth",required_argument,0,'d'},
Packit 8f70b4
      {"ls",no_argument,0,'l'},
Packit 8f70b4
      {0,0,0,0}
Packit 8f70b4
   };
Packit 8f70b4
   int opt;
Packit 8f70b4
   int maxdepth = -1;
Packit 8f70b4
   bool long_listing=false;
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
Packit 8f70b4
   while((opt=args->getopt_long("+d:l",find_options))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case 'd':
Packit 8f70b4
	 if(!isdigit((unsigned char)*optarg))
Packit 8f70b4
	 {
Packit 8f70b4
	    eprintf(_("%s: %s - not a number\n"),op,optarg);
Packit 8f70b4
	    return 0;
Packit 8f70b4
	 }
Packit 8f70b4
	 maxdepth = atoi(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'l':
Packit 8f70b4
	 long_listing=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case '?':
Packit 8f70b4
	 eprintf(_("Usage: %s [-d #] dir\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(!args->getcurr())
Packit 8f70b4
      args->Append(".");
Packit 8f70b4
   FinderJob_List *j=new class FinderJob_List(session->Clone(),args.borrow(),output.borrow());
Packit 8f70b4
   j->set_maxdepth(maxdepth);
Packit 8f70b4
   j->DoLongListing(long_listing);
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(du)
Packit 8f70b4
{
Packit 8f70b4
   enum {
Packit 8f70b4
      OPT_BLOCK_SIZE,
Packit 8f70b4
      OPT_EXCLUDE
Packit 8f70b4
   };
Packit 8f70b4
   static struct option du_options[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"all",no_argument,0,'a'},
Packit 8f70b4
      /* alias: both GNU-like max-depth and lftp-like maxdepth;
Packit 8f70b4
       * only document one of them. */
Packit 8f70b4
      {"bytes",no_argument,0,'b'},
Packit 8f70b4
      {"block-size",required_argument,0,OPT_BLOCK_SIZE},
Packit 8f70b4
      {"maxdepth",required_argument,0,'d'},
Packit 8f70b4
      {"total",no_argument,0,'c'},
Packit 8f70b4
      {"max-depth",required_argument,0,'d'},
Packit 8f70b4
      {"files",no_argument,0,'F'},
Packit 8f70b4
      {"human-readable",no_argument,0,'h'},
Packit 8f70b4
      {"si",no_argument,0,'H'},
Packit 8f70b4
      {"kilobytes",required_argument,0,'k'},
Packit 8f70b4
      {"megabytes",required_argument,0,'m'},
Packit 8f70b4
      {"separate-dirs",no_argument,0,'S'},
Packit 8f70b4
      {"summarize",no_argument,0,'s'},
Packit 8f70b4
      {"exclude",required_argument,0,OPT_EXCLUDE},
Packit 8f70b4
      {0,0,0,0}
Packit 8f70b4
   };
Packit 8f70b4
   int maxdepth = -1;
Packit 8f70b4
   bool max_depth_specified = false;
Packit 8f70b4
   int blocksize = 1024;
Packit 8f70b4
   bool separate_dirs = false;
Packit 8f70b4
   bool summarize_only = false;
Packit 8f70b4
   bool print_totals=false;
Packit 8f70b4
   bool all_files=false;
Packit 8f70b4
   bool file_count=false;
Packit 8f70b4
   Ref<PatternSet> exclude;
Packit 8f70b4
   int human_opts=0;
Packit 8f70b4
Packit 8f70b4
   exit_code=1;
Packit 8f70b4
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
Packit 8f70b4
   int opt;
Packit 8f70b4
   while((opt=args->getopt_long("+abcd:FhHkmsS",du_options))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case 'a':
Packit 8f70b4
	 all_files=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'b':
Packit 8f70b4
	 blocksize = 1;
Packit 8f70b4
	 human_opts = 0;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'c':
Packit 8f70b4
	 print_totals=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'd':
Packit 8f70b4
	 if(!isdigit((unsigned char)*optarg))
Packit 8f70b4
	 {
Packit 8f70b4
	    eprintf(_("%s: %s - not a number\n"),op,optarg);
Packit 8f70b4
	    return 0;
Packit 8f70b4
	 }
Packit 8f70b4
	 maxdepth = atoi(optarg);
Packit 8f70b4
	 max_depth_specified = true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'F':
Packit 8f70b4
	 file_count=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'h':
Packit 8f70b4
	 human_opts |= human_autoscale|human_SI|human_base_1024;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'H':
Packit 8f70b4
	 human_opts |= human_autoscale|human_SI;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'k': /* the default; here for completeness */
Packit 8f70b4
	 blocksize = 1024;
Packit 8f70b4
	 human_opts = 0;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'm':
Packit 8f70b4
	 blocksize = 1024*1024;
Packit 8f70b4
	 human_opts = 0;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 's':
Packit 8f70b4
	 summarize_only = true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'S':
Packit 8f70b4
	 separate_dirs = true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_BLOCK_SIZE:
Packit 8f70b4
	 blocksize = atoi(optarg);
Packit 8f70b4
	 if(blocksize == 0)
Packit 8f70b4
	 {
Packit 8f70b4
	    eprintf(_("%s: invalid block size `%s'\n"),op,optarg);
Packit 8f70b4
	    return 0;
Packit 8f70b4
	 }
Packit 8f70b4
	 break;
Packit 8f70b4
      case OPT_EXCLUDE:
Packit 8f70b4
	 if(!exclude)
Packit 8f70b4
	    exclude=new PatternSet();
Packit 8f70b4
	 exclude->Add(PatternSet::EXCLUDE,new PatternSet::Glob(optarg));
Packit 8f70b4
	 break;
Packit 8f70b4
      case '?':
Packit 8f70b4
      default:
Packit 8f70b4
	 eprintf(_("Usage: %s [options] <dirs>\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if (summarize_only && max_depth_specified && maxdepth == 0)
Packit 8f70b4
      eprintf(_("%s: warning: summarizing is the same as using --max-depth=0\n"), op);
Packit 8f70b4
Packit 8f70b4
   if (summarize_only && max_depth_specified && maxdepth != 0)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("%s: summarizing conflicts with --max-depth=%i\n"), op, maxdepth);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   /* It doesn't really make sense to show all files when doing a file count.
Packit 8f70b4
    * We might have -a in an alias as defaults, so let's just silently turn
Packit 8f70b4
    * it off.  (I'm not sure if we should do this for summarize_only and
Packit 8f70b4
    * max_depth_specified, too.) */
Packit 8f70b4
   if (file_count && all_files)
Packit 8f70b4
      all_files=false;
Packit 8f70b4
   if (file_count)
Packit 8f70b4
      blocksize=1;
Packit 8f70b4
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
Packit 8f70b4
   if (summarize_only)
Packit 8f70b4
      maxdepth = 0;
Packit 8f70b4
Packit 8f70b4
   if(!args->getcurr())
Packit 8f70b4
      args->Append(".");
Packit 8f70b4
   FinderJob_Du *j=new class FinderJob_Du(session->Clone(),args.borrow(),output.borrow());
Packit 8f70b4
   j->PrintDepth(maxdepth);
Packit 8f70b4
   j->SetBlockSize(blocksize,human_opts);
Packit 8f70b4
   if(print_totals)
Packit 8f70b4
      j->PrintTotals();
Packit 8f70b4
   if(all_files)
Packit 8f70b4
      j->AllFiles();
Packit 8f70b4
   if(separate_dirs)
Packit 8f70b4
      j->SeparateDirs();
Packit 8f70b4
   if(file_count)
Packit 8f70b4
      j->FileCount();
Packit 8f70b4
   /* if separate_dirs is on, then there's no point in traversing past
Packit 8f70b4
    * max_print_depth at all */
Packit 8f70b4
   if(separate_dirs && maxdepth != -1)
Packit 8f70b4
      j->set_maxdepth(maxdepth);
Packit 8f70b4
   if(exclude)
Packit 8f70b4
      j->SetExclude(exclude.borrow());
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(command)
Packit 8f70b4
{
Packit 8f70b4
   if(args->count()<2)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("Usage: %s command args...\n"),args->a0());
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   args->delarg(0);
Packit 8f70b4
   return parent->builtin_restart();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(module)
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   if(args->count()<2)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("Usage: %s module [args...]\n"),args->a0());
Packit 8f70b4
      eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   void *map=module_load(args->getarg(1),args->count()-1,args->GetV()+1);
Packit 8f70b4
   if(map==0)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf("%s\n",module_error_message());
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(lpwd)
Packit 8f70b4
{
Packit 8f70b4
   if(!parent->cwd)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf("%s: %s\n",args->a0(),_("cannot get current directory"));
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   const char *name=parent->cwd->GetName();
Packit 8f70b4
   const char *buf=xstring::cat(name?name:"?","\n",NULL);
Packit 8f70b4
   Job *j=new echoJob(buf,new OutputJob(output.borrow(), args->a0()));
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(local)
Packit 8f70b4
{
Packit 8f70b4
   return parent->builtin_local();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(glob)
Packit 8f70b4
{
Packit 8f70b4
   return parent->builtin_glob();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(chmod)
Packit 8f70b4
{
Packit 8f70b4
   ChmodJob::verbosity verbose = ChmodJob::V_NONE;
Packit 8f70b4
   bool recurse = false, quiet = false;
Packit 8f70b4
Packit 8f70b4
   static struct option chmod_options[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"verbose",no_argument,0,'v'},
Packit 8f70b4
      {"changes",no_argument,0,'c'},
Packit 8f70b4
      {"recursive",no_argument,0,'R'},
Packit 8f70b4
      {"silent",no_argument,0,'f'},
Packit 8f70b4
      {"quiet",no_argument,0,'f'},
Packit 8f70b4
      {0,0,0,0}
Packit 8f70b4
   };
Packit 8f70b4
   int opt;
Packit 8f70b4
   int modeind = 0;
Packit 8f70b4
Packit 8f70b4
   while((opt=args->getopt_long("vcRfrwxXstugoa,+-=",chmod_options))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case 'r': case 'w': case 'x':
Packit 8f70b4
      case 'X': case 's': case 't':
Packit 8f70b4
      case 'u': case 'g': case 'o':
Packit 8f70b4
      case 'a':
Packit 8f70b4
      case ',':
Packit 8f70b4
      case '+': case '=':
Packit 8f70b4
	 modeind = optind?optind-1:1;
Packit 8f70b4
	 break; /* mode string that begins with - */
Packit 8f70b4
Packit 8f70b4
      case 'v':
Packit 8f70b4
	 verbose=ChmodJob::V_ALL;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'c':
Packit 8f70b4
	 verbose=ChmodJob::V_CHANGES;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'R':
Packit 8f70b4
	 recurse = true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'f':
Packit 8f70b4
	 quiet = true;
Packit 8f70b4
	 break;
Packit 8f70b4
Packit 8f70b4
      case '?':
Packit 8f70b4
      usage:
Packit 8f70b4
	 eprintf(_("Usage: %s [OPTS] mode file...\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(modeind == 0)
Packit 8f70b4
      modeind = args->getindex();
Packit 8f70b4
Packit 8f70b4
   const char *arg = args->getarg(modeind);
Packit 8f70b4
   if(!arg)
Packit 8f70b4
      goto usage;
Packit 8f70b4
   arg = alloca_strdup(arg);
Packit 8f70b4
   args->delarg(modeind);
Packit 8f70b4
Packit 8f70b4
   if(!args->getcurr())
Packit 8f70b4
      goto usage;
Packit 8f70b4
Packit 8f70b4
   mode_change *m = mode_compile(arg);
Packit 8f70b4
   if(!m)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("invalid mode string: %s\n"), arg);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   ChmodJob *j=new ChmodJob(session->Clone(),args.borrow());
Packit 8f70b4
   j->SetVerbosity(verbose);
Packit 8f70b4
   j->SetMode(m);
Packit 8f70b4
   if(quiet)
Packit 8f70b4
      j->BeQuiet(); /* does not affect messages from Verbosity */
Packit 8f70b4
   if(recurse)
Packit 8f70b4
      j->Recurse();
Packit 8f70b4
   return j;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(queue)
Packit 8f70b4
{
Packit 8f70b4
   return parent->builtin_queue();
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(get1)
Packit 8f70b4
{
Packit 8f70b4
   static struct option get1_options[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"ascii",no_argument,0,'a'},
Packit 8f70b4
      {"source-region",required_argument,0,256+'r'},
Packit 8f70b4
      {"target-position",required_argument,0,256+'R'},
Packit 8f70b4
      {"continue",no_argument,0,'c'},
Packit 8f70b4
      {"output",required_argument,0,'o'},
Packit 8f70b4
      {"remove-source-later",no_argument,0,'E'},
Packit 8f70b4
      {"remove-target-first",no_argument,0,'e'},
Packit 8f70b4
      {"make-target-dir",no_argument,0,'d'},
Packit 8f70b4
      {"quiet",no_argument,0,'q'},
Packit 8f70b4
      {0,0,0,0}
Packit 8f70b4
   };
Packit 8f70b4
   int opt;
Packit 8f70b4
   const char *src=0;
Packit 8f70b4
   const char *dst=0;
Packit 8f70b4
   bool cont=false;
Packit 8f70b4
   bool ascii=false;
Packit 8f70b4
   bool quiet=false;
Packit 8f70b4
   bool do_mkdir=false;
Packit 8f70b4
   long long source_region_begin=0,source_region_end=FILE_END;
Packit 8f70b4
   long long target_region_begin=0,target_region_end=FILE_END;
Packit 8f70b4
   int n,p;
Packit 8f70b4
Packit 8f70b4
   while((opt=args->getopt_long("arco:d",get1_options))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case 'c':
Packit 8f70b4
	 cont=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'a':
Packit 8f70b4
	 ascii=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 'o':
Packit 8f70b4
	 dst=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
      case 256+'r':
Packit 8f70b4
	 source_region_end=FILE_END;
Packit 8f70b4
	 n=sscanf(optarg,"%lld%n-%lld",&source_region_begin,&p,&source_region_end);
Packit 8f70b4
	 if(n<1 || (n==1 && (optarg[p] && (optarg[p]!='-' || optarg[p+1]))))
Packit 8f70b4
	 {
Packit 8f70b4
	    eprintf("%s\n",_("Invalid range format. Format is min-max, e.g. 10-20."));
Packit 8f70b4
	    goto usage;
Packit 8f70b4
	 }
Packit 8f70b4
	 break;
Packit 8f70b4
      case 256+'R':
Packit 8f70b4
	 target_region_end=FILE_END;
Packit 8f70b4
	 n=sscanf(optarg,"%lld",&target_region_begin);
Packit 8f70b4
	 if(n<1)
Packit 8f70b4
	 {
Packit 8f70b4
	    eprintf("%s\n",_("Invalid range format. Format is min-max, e.g. 10-20."));
Packit 8f70b4
	    goto usage;
Packit 8f70b4
	 }
Packit 8f70b4
	 break;
Packit 8f70b4
      case('q'):
Packit 8f70b4
	 quiet=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('d'):
Packit 8f70b4
	 do_mkdir=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case '?':
Packit 8f70b4
      usage:
Packit 8f70b4
	 eprintf(_("Usage: %s [OPTS] file\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   src=args->getcurr();
Packit 8f70b4
   if(src==0)
Packit 8f70b4
      goto usage;
Packit 8f70b4
   if(args->getnext()!=0)
Packit 8f70b4
      goto usage;
Packit 8f70b4
Packit 8f70b4
   bool auto_rename=false;
Packit 8f70b4
   if(dst==0 || dst[0]==0)
Packit 8f70b4
   {
Packit 8f70b4
      dst=basename_ptr(src);
Packit 8f70b4
      auto_rename=true;
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      if(last_char(dst)=='/' && basename_ptr(dst)[0]!='/')
Packit 8f70b4
      {
Packit 8f70b4
	 const char *bn=basename_ptr(src);
Packit 8f70b4
	 if(bn[0]!='/')
Packit 8f70b4
	 {
Packit 8f70b4
	    dst=xstring::get_tmp(dst).append(bn);
Packit 8f70b4
	    auto_rename=true;
Packit 8f70b4
	 }
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   ParsedURL dst_url(dst,true);
Packit 8f70b4
Packit 8f70b4
   if(dst_url.proto==0)
Packit 8f70b4
   {
Packit 8f70b4
      dst=expand_home_relative(dst);
Packit 8f70b4
      // check if dst is a directory.
Packit 8f70b4
      struct stat st;
Packit 8f70b4
      if(stat(dst,&st)!=-1)
Packit 8f70b4
      {
Packit 8f70b4
	 if(S_ISDIR(st.st_mode))
Packit 8f70b4
	 {
Packit 8f70b4
	    const char *slash=strrchr(src,'/');
Packit 8f70b4
	    if(slash)
Packit 8f70b4
	       slash++;
Packit 8f70b4
	    else
Packit 8f70b4
	       slash=src;
Packit 8f70b4
	    dst=xstring::cat(dst,"/",slash,NULL);
Packit 8f70b4
	 }
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   dst=alloca_strdup(dst); // save tmp xstring
Packit 8f70b4
Packit 8f70b4
   FileCopyPeer *src_peer=0;
Packit 8f70b4
   FileCopyPeer *dst_peer=0;
Packit 8f70b4
Packit 8f70b4
   src_peer=FileCopyPeerFA::New(session->Clone(),src,FA::RETRIEVE);
Packit 8f70b4
   if(!cont && (source_region_begin>0 || source_region_end!=FILE_END))
Packit 8f70b4
      src_peer->SetRange(source_region_begin,source_region_end);
Packit 8f70b4
Packit 8f70b4
   if(dst_url.proto==0)
Packit 8f70b4
      dst_peer=FileCopyPeerFDStream::NewPut(dst,cont||target_region_begin>0);
Packit 8f70b4
   else
Packit 8f70b4
      dst_peer=new FileCopyPeerFA(&dst_url,FA::STORE);
Packit 8f70b4
   dst_peer->AutoRename(auto_rename && ResMgr::QueryBool("xfer:auto-rename",0));
Packit 8f70b4
   if(!cont && (target_region_begin>0 || target_region_end!=FILE_END))
Packit 8f70b4
      dst_peer->SetRange(target_region_begin,target_region_end);
Packit 8f70b4
   if(do_mkdir)
Packit 8f70b4
      dst_peer->MakeTargetDir();
Packit 8f70b4
Packit 8f70b4
   FileCopy *c=FileCopy::New(src_peer,dst_peer,cont);
Packit 8f70b4
Packit 8f70b4
   if(ascii)
Packit 8f70b4
      c->Ascii();
Packit 8f70b4
Packit 8f70b4
   CopyJob *cj=new CopyJob(c,src,args->a0());
Packit 8f70b4
   cj->Quiet(quiet);
Packit 8f70b4
   return cj;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(slot)
Packit 8f70b4
{
Packit 8f70b4
   const char *n=args->getarg(1);
Packit 8f70b4
   if(n)
Packit 8f70b4
   {
Packit 8f70b4
      parent->ChangeSlot(n);
Packit 8f70b4
      exit_code=0;
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      xstring_ca slots(ConnectionSlot::Format());
Packit 8f70b4
      Job *j=new echoJob(slots,new OutputJob(output.borrow(),args->a0()));
Packit 8f70b4
      return j;
Packit 8f70b4
   }
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(tasks)
Packit 8f70b4
{
Packit 8f70b4
   printf("task_count=%d\n",SMTask::TaskCount());
Packit 8f70b4
   SMTask::PrintTasks();
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(empty)
Packit 8f70b4
{
Packit 8f70b4
   exit_code=(args->count()>1 ? 1 : 0);
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
CMD(notempty)
Packit 8f70b4
{
Packit 8f70b4
   exit_code=(args->count()>1 ? 0 : 1);
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
CMD(true)
Packit 8f70b4
{
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
CMD(false)
Packit 8f70b4
{
Packit 8f70b4
   exit_code=1;
Packit 8f70b4
   return 0;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
CMD(eval)
Packit 8f70b4
{
Packit 8f70b4
   int opt;
Packit 8f70b4
   const char *fmt=0;
Packit 8f70b4
   const char *op=args->getarg(0);
Packit 8f70b4
   while((opt=args->getopt("+f:"))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case 'f':
Packit 8f70b4
	 fmt=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
      default:
Packit 8f70b4
	 eprintf(_("Try `%s --help' for more information\n"),op);
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   int base=optind;
Packit 8f70b4
   xstring cmd;
Packit 8f70b4
   if(!fmt)
Packit 8f70b4
      args->CombineTo(cmd,optind);
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      while(*fmt)
Packit 8f70b4
      {
Packit 8f70b4
	 if(*fmt=='\\' && (fmt[1]=='$' || fmt[1]=='\\'))
Packit 8f70b4
	 {
Packit 8f70b4
	    cmd.append(fmt[1]);
Packit 8f70b4
	    fmt+=2;
Packit 8f70b4
	    continue;
Packit 8f70b4
	 }
Packit 8f70b4
	 if(*fmt=='$' && fmt[1]>='0' && fmt[1]<='9')
Packit 8f70b4
	 {
Packit 8f70b4
	    int n=fmt[1]-'0';
Packit 8f70b4
	    if(n+base<args->count())
Packit 8f70b4
	       cmd.append(args->getarg(n+base));
Packit 8f70b4
	    fmt+=2;
Packit 8f70b4
	    continue;
Packit 8f70b4
	 }
Packit 8f70b4
	 if(*fmt=='$' && fmt[1]=='@')
Packit 8f70b4
	 {
Packit 8f70b4
	    xstring_ca c(args->CombineQuoted(base));
Packit 8f70b4
	    cmd.append(c);
Packit 8f70b4
	    fmt+=2;
Packit 8f70b4
	    continue;
Packit 8f70b4
	 }
Packit 8f70b4
	 if(*fmt=='$' && fmt[1]=='$')
Packit 8f70b4
	 {
Packit 8f70b4
	    cmd.appendf("%d",(int)getpid());
Packit 8f70b4
	    fmt+=2;
Packit 8f70b4
	    continue;
Packit 8f70b4
	 }
Packit 8f70b4
	 cmd.append(*fmt++);
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   cmd.append(";\n\n");
Packit 8f70b4
   parent->PrependCmd(cmd);
Packit 8f70b4
   exit_code=parent->prev_exit_code;
Packit 8f70b4
   return 0;
Packit 8f70b4
}