lftp-4.9.2/0000755000015000007670000000000013715317707007507 500000000000000lftp-4.9.2/INSTALL0000644000015000007670000003661012734477075010473 00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command `./configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX `make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as `configure' are involved. Use GNU `make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. lftp-4.9.2/README0000644000015000007670000001640012662070340010275 00000000000000** lftp-4.5.x This package `lftp' contains the following components: lftp sophisticated command line file transfer program (ftp/http client, also supports several other protocols). lftpget shell script for downloading by URL, it calls `lftp -c'. lftp is written in C++ and uses a cooperative-threaded model. lftp ~~~~ lftp is sophisticated file transfer program with command line interface. It supports FTP, HTTP, FISH, SFTP and FILE (local FS) protocols. GNU Readline library is used for input. BitTorrent protocol is supported as built-in `torrent' command. Low level stuff supported: ftp proxy, http proxy, ftp over http, opie/skey, fxp transfers, automatic retrying on non-fatal errors and timeouts, ipv6, socks, http/1.1, sftp v3-v6. See FEATURES for more detailed list of features. Every operation in lftp is reliable, that is any non-fatal error is ignored and the operation is retried. So if downloading breaks, it will be restarted from the point automatically. Even if ftp server does not support REST command, lftp will try to retrieve the file from the very beginning until the file is transferred completely. lftp has shell-like command syntax allowing you to launch several commands in parallel in background (&). It is also possible to group commands within () and execute them in background. All background jobs are executed in the same single process. You can bring a foreground job to background with ^Z (c-z) and back with command `wait' (or `fg' which is alias to `wait'). To list running jobs, use command `jobs'. Some commands allow redirecting their output (cat, ls, ...) to file or via pipe to external command. Commands can be executed conditionally based on termination status of previous command (&&, ||). If you exit lftp when some jobs are not finished yet, lftp will move itself to nohup mode in background. The same happens when you have a real modem hangup or when you close an xterm. It is possible to attach to backgrounded lftp instance using `attach' command in lftp, e.g. `lftp -c attach'. lftp has builtin mirror which can download or update a whole directory tree. There is also reverse mirror (mirror -R) which uploads or updates a directory tree on server. It is also possible to synchronize two servers, FXP is used automatically if possible. There is command `at' to launch a job at specified time in current context, command `queue' to queue commands for sequential execution for current server, and much more. On startup, lftp executes /etc/lftp.conf and then ~/.lftprc and ~/.lftp/rc. You can place aliases and `set' commands there. Some people prefer to see full protocol debug, use `debug' to turn the debug on. Use `debug 3' to see only greeting messages and error messages. if ~/.lftp directory does not exist, XDG directories are used instead: ~/.config/lftp, ~/.local/share/lftp and ~/.cache/lftp. lftp has a number of settable variables. You can use `set -a' to see all variables and their values or `set -d' to see list of defaults. Variable names can be abbreviated and prefix can be omitted unless the rest becomes ambiguous. Use command `help' or read documentation (man lftp) to learn more. If lftp was compiled with ssl support, then it includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/) Where to get ~~~~~~~~~~~~ By FTP: ftp://ftp.yar.ru/pub/source/lftp/ By HTTP: http://lftp.yar.ru/ftp/ By GIT (development): https://github.com/lavv17/lftp See also the home page `http://lftp.yar.ru/'. Internals ~~~~~~~~~ All this is based on SMTask class which implements non-preemptive multitasking via Do method. The method Do does a little bit of work, sets wake up condition (block member) and returns. There are also some useful classes: Timer, TimeDate, *Buffer, xstring, xarray, xlist, xmap, xheap, Ref etc. Timers are ordered using a heap data structure. Primitive classes were implemented with performance and low memory consumption in mind. Standard C++ library is not used, since lftp development started when it was not so standard yet (and boost did not even exist). Access to remote files is performed via FileAccess class, which is base class for all protocols. NetAccess is for network file access. There is also LocalAccess for local files access. SSH_Access is for SSH based protocols: FISH and SFTP. The class Ftp allows reliable deliver of files via ftp protocol, it hides all the details from application and allows asynchronous operation. Reconnect and reget are done as necessary. It can also speed up ftp operations by sending several commands at once and then checking all the responses. It seems this sometimes does not work, so it is disabled by default. To turn it on, use `set sync-mode n' in lftp. Note that sending several commands is considered as violation or protocol, but RFC959 says: ``The user-process sending another command before the completion reply would be in violation of protocol; but server-FTP processes should queue any commands that arrive while a preceding command is in progress.'' It is known that some network software dealing with address translation works incorrectly in case of several FTP commands in one network packet. Systems ~~~~~~~ The package is known to compile on Solaris(gcc), Linux, FreeBSD, NetBSD, SCO v5.0(gcc), IRIX(gcc), Tru64(gcc) and other systems. If you can't compile it on your system, let me know. It is possible that lftp version 2.0 can be compiled with non-gcc compilers since it does not have gcc-isms, and it was successfully compiled by Sun C++ v5.0 compiler using CXXFLAGS="-compat=4 -features=bool". Mailing list ~~~~~~~~~~~~ There is a mailing list for discussion of lftp and announcements. It is managed by mailman; to subscribe, send mail to lftp-subscribe@uniyar.ac.ru; to send letters to the list, send them to lftp@uniyar.ac.ru; to unsubscribe, send mail to lftp-unsubscribe@uniyar.ac.ru. This is a low volume list. See also http://univ.uniyar.ac.ru/mailman/listinfo/lftp. There is also list lftp-devel@uniyar.ac.ru for snapshot announcements and other development. These lists are archived at http://www.mail-archive.com/lftp%40uniyar.ac.ru/ http://www.mail-archive.com/lftp-devel%40uniyar.ac.ru/ You can also submit pull requests or issues to GitHub: https://github.com/lavv17/lftp Author ~~~~~~ Author: Alexander V. Lukyanov My home page: http://lav.yar.ru/ My other E-Mails: lav@yar.ru, lav@netis.ru, lavv17f@gmail.com Other people have contributed to lftp development, see the THANKS file. Comments and bug reports are welcome. Please send them to the list: . Subscribe if you want your messages to be sent to the list quickly. License ~~~~~~~ Copyright (c) 1996-2014 by Alexander V. Lukyanov (lav@yars.free.net) LFTP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with LFTP. If not, see . lftp-4.9.2/src/0000755000015000007670000000000013715317704010273 500000000000000lftp-4.9.2/src/DummyProto.h0000644000015000007670000000271712717275037012515 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DUMMYPROTO_H #define DUMMYPROTO_H #include "FileAccess.h" class DummyProto : public FileAccess { public: int Do(); int Done(); const char *GetProto() const; FileAccess *Clone() const; int Read(Buffer *buf,int size); int Write(const void *buf,int size); int StoreStatus(); void Reconfig(const char *) {} void Login(const char *,const char *) {} ListInfo *MakeListInfo(const char *path); DirList *MakeDirList(ArgV *); DummyProto(); ~DummyProto(); }; class DummyNoProto : public DummyProto { xstring_c proto; public: DummyNoProto(const char *p) : proto(p) {} const char *GetProto() const; FileAccess *Clone() const; const char *StrError(int err); }; #endif lftp-4.9.2/src/url.cc0000644000015000007670000002255513531040501011315 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "trio.h" #include "xstring.h" #include #include #include "url.h" #include "ascii_ctype.h" #include "ConnectionSlot.h" #include "bookmark.h" #include "misc.h" #include "log.h" #include "network.h" /* URL -> [PROTO://]CONNECT[[:]/PATH] CONNECT -> [USER[:PASS]@]HOST[:PORT] exceptions: file:/PATH bm:BOOKMARK[/PATH] slot:SLOT[/PATH] */ static bool valid_slot(const char *s); static bool valid_bm(const char *s); ParsedURL::ParsedURL(const char *url,bool proto_required,bool use_rfc1738) { parse(url,proto_required,use_rfc1738); } ParsedURL::~ParsedURL() { } void ParsedURL::parse(const char *url,bool proto_required,bool use_rfc1738) { orig_url.set(url); xstring_c connect; const char *base=url; const char *scan=base; while(is_ascii_alpha(*scan)) scan++; if(scan[0]==':' && scan[1]=='/' && scan[2]=='/') { // found protocol proto.nset(base,scan-base); base=scan+=3; if(!strcmp(proto,"file") && scan[0]=='/') goto file_with_no_host; } else if(scan[0]==':' && !strncmp(base,"file:",5)) { // special form for file protocol proto.nset(base,scan-base); scan++; file_with_no_host: path.set(scan); host.set("localhost"); goto decode; } else if(scan[0]==':' && ((!strncmp(base,"slot:",5) && valid_slot(scan+1)) || (!strncmp(base,"bm:",3) && valid_bm(scan+1)))) { // special form for selecting a connection slot or a bookmark proto.nset(base,scan-base); scan++; base=scan; scan=strchr(scan,'/'); if(scan) { host.nset(base,scan-base); path.set(scan); } else host.set(base); goto decode; } else if(proto_required) { // all the rest is path, if protocol is required. path.set(base); goto decode; } scan=base; while(*scan && *scan!='/') scan++; // skip host name, port and user:pass connect.nset(base,scan-base-(scan>base && scan[-1]==':')); if(*scan=='/') // directory { if(scan[1]=='~') path.set(scan+1); else { if((!xstrcmp(proto,"ftp") || !xstrcmp(proto,"ftps") || !xstrcmp(proto,"hftp")) && use_rfc1738) { // special handling for ftp protocol. if(!strncasecmp(scan+1,"%2F",3)) path.set(scan+1); else if(!(is_ascii_alpha(scan[1]) && scan[2]==':' && scan[3]=='/')) path.vset("~",scan,NULL); } else path.set(scan); } } else if(proto) { if(!strcmp(proto,"http") || !strcmp(proto,"https")) path.set("/"); } // try to extract user name/password base=connect; scan=strrchr(base,'@'); if(scan) { user.nset(base,scan-base); base=scan+1; scan=user; while(*scan && *scan!=':') scan++; if(*scan==':') { pass.set(scan+1); user.truncate(scan-user); } } // extract host name scan=base; if(*scan=='[') // RFC2732 [ipv6] { while(*scan && *scan!=']') scan++; if(*scan==']') { scan++; host.nset(base+1,scan-base-2); } else scan=base; } if(scan==base) { while(*scan && *scan!=':') scan++; host.nset(base,scan-base); } if(*scan==':') // port found { if(strchr(scan+1,':')==0) { port.set(scan+1); } else { /* more than one colon - maybe it is ipv6 digital address */ host.set(base); } } decode: user.url_decode(); pass.url_decode(); host.url_decode(); path.url_decode(); if(!xstrcmp(proto,"slot")) { const FileAccess *fa=ConnectionSlot::FindSession(host); if(!fa) return; orig_url.set(0); proto.set(fa->GetProto()); user.set(fa->GetUser()); pass.set(fa->GetPassword()); host.set(fa->GetHostName()); port.set(fa->GetPort()); FA::Path cwd(fa->GetCwd()); if(path) cwd.Change(path+(path[0]=='/')); path.set(cwd); } else if(!xstrcmp(proto,"bm")) { const char *bm=lftp_bookmarks.Lookup(host); if(!bm || !bm[0]) return; const char *new_url=0; xstring u(bm); if(orig_url) { const char *new_path=orig_url+url::path_index(orig_url); if(new_path[0]=='/') new_path++; if(new_path[0]=='/' || new_path[0]=='~') u.truncate(url::path_index(u)); assert(u[0]); if(u.last_char()!='/' && new_path[0]!='/') u.append('/'); else if(u.last_char()=='/' && new_path[0]=='/') new_path++; u.append(new_path); new_url=u; } else new_url=url_file(bm,path+(path && path[0]=='/')); parse(new_url,proto_required,use_rfc1738); } } static bool valid_slot(const char *cs) { xstring& s=xstring::get_tmp(cs); s.truncate_at('/'); s.url_decode(); return 0!=ConnectionSlot::Find(s); } static bool valid_bm(const char *bm) { xstring& s=xstring::get_tmp(bm); s.truncate_at('/'); s.url_decode(); const char *url=lftp_bookmarks.Lookup(s); return(url && !strchr(url,' ') && !strchr(url,'\t')); } int url::path_index(const char *base) { const char *scan=base; while(is_ascii_alpha(*scan)) scan++; if(scan[0]!=':') return 0; if(scan[1]=='/' && scan[2]=='/') { // found protocol const char *slash=strchr(scan+3,'/'); if(slash) return slash-base; return strlen(base); } else if(!strncmp(base,"file:",5)) { // special form for file protocol return scan+1-base; } else if((!strncmp(base,"slot:",5) && valid_slot(base+5)) || (!strncmp(base,"bm:",3) && valid_bm(base+3))) { const char *slash=strchr(scan+1,'/'); if(slash) return slash-base; return strlen(base); } return 0; } const char *url::path_ptr(const char *base) { if(!base) return 0; return base+path_index(base); } char *ParsedURL::Combine(const char *home,bool use_rfc1738) { xstring buf(""); return CombineTo(buf,home,use_rfc1738).borrow(); } xstring& ParsedURL::CombineTo(xstring& u,const char *home,bool use_rfc1738) const { bool is_file=!xstrcmp(proto,"file"); bool is_ftp=(!xstrcmp(proto,"ftp") || !xstrcmp(proto,"hftp")); if(proto) { u.append(proto); u.append(is_file?":":"://"); } if(user && !is_file) { u.append(url::encode(user,URL_USER_UNSAFE)); if(pass) { u.append(':'); u.append(url::encode(pass,URL_PASS_UNSAFE)); } u.append('@'); } if(host && !is_file) { unsigned encode_flags=0; if(xtld_name_ok(host)) encode_flags|=URL_ALLOW_8BIT; if(is_ipv6_address(host)) u.append('[').append(host).append(']'); else u.append_url_encoded(host,URL_HOST_UNSAFE,encode_flags); } if(port && !is_file) { u.append(':'); u.append(url::encode(port,URL_PORT_UNSAFE)); } if(path && strcmp(path,"~")) { if(path[0]!='/' && !is_file) // e.g. ~/path u.append('/'); int p_offset=0; if(is_ftp && use_rfc1738) { // some cruft for ftp urls... if(path[0]=='/' && xstrcmp(home,"/")) { u.append("/%2F"); p_offset=1; } else if(path[0]=='~' && path[1]=='/') p_offset=2; } u.append(url::encode(path+p_offset,URL_PATH_UNSAFE)); } return u; } const xstring& url::decode(const char *p) { if(!p) return xstring::null; return xstring::get_tmp(p).url_decode(); } const xstring& url::encode(const char *s,int len,const char *unsafe,unsigned flags) { if(!s) return xstring::null; return xstring::get_tmp("").append_url_encoded(s,len,unsafe,flags); } bool url::dir_needs_trailing_slash(const char *proto_c) { if(!proto_c) return false; char *proto=alloca_strdup(proto_c); char *colon=strchr(proto,':'); if(colon) *colon=0; return !strcasecmp(proto,"http") || !strcasecmp(proto,"https"); } bool url::find_password_pos(const char *url,int *start,int *len) { *start=*len=0; const char *scan=strstr(url,"://"); if(!scan) return false; scan+=3; const char *at=strchr(scan,'@'); if(!at) return false; const char *colon=strchr(scan,':'); if(!colon || colon>at) return false; const char *slash=strchr(scan,'/'); if(slash && slash. */ #ifndef ERROR_H #define ERROR_H #include "xstring.h" class Error { xstring text; int code; bool fatal; public: Error(); Error(int,const char *,bool); ~Error(); void Set(int,const char *,bool); const char *Text() const { return text; } int Code() const { return code; } bool IsFatal() const { return fatal; } static Error *Fatal(const char *s,int c=-1); }; #endif//ERROR_H lftp-4.9.2/src/Speedometer.cc0000644000015000007670000001021213530052701012756 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "Speedometer.h" #include "misc.h" #include "xstring.h" #include "ResMgr.h" #define now SMTask::now Speedometer::Speedometer(const char *p) { period=15; rate=0; last_second=now; start=now; last_bytes=0; terse=true; period_resource=p; Reconfig(0); } bool Speedometer::Valid() { return now>=start+TimeDiff(1,0) && nowTimeout(500); return rate; } void Speedometer::Add(int b) { if(b==0 && (now==last_second || TimeDiff(now,last_second).MilliSeconds()<100)) return; // This makes Speedometer start only when first data come. if(rate==0) Reset(); double div=period; if(start>now) start=now; // time was adjusted? if(now0) last_bytes=now; if(rate<0) rate=0; } // These `incorrect' units are used to fit on status line xstring& Speedometer::GetStr(float r) { if(r<1) return xstring::get_tmp(""); if(r<1024) // for translator: those are the units. This is 'byte per second' return xstring::format(_("%.0fb/s"),r); else if(r<1024*1024) // for translator: This is 'Kibibyte per second' return xstring::format(_("%.1fK/s"),r/1024.); else // for translator: This is 'Mebibyte per second' return xstring::format(_("%.2fM/s"),r/(1024.*1024)); } xstring& Speedometer::GetStrProper(float r) { if(r<1) return xstring::get_tmp(""); if(r<1024) return xstring::format(_("%.0f B/s"),r); else if(r<1024*1024) return xstring::format(_("%.1f KiB/s"),r/1024.); else return xstring::format(_("%.2f MiB/s"),r/(1024.*1024)); } xstring& Speedometer::GetStr() { return Valid() ? GetStr(Get()) : xstring::get_tmp(""); } xstring& Speedometer::GetETAStrFromSize(off_t size) { if(!Valid() || Get()<1) return xstring::get_tmp(""); return GetETAStrFromTime(long(size/rate+.5)); } xstring& Speedometer::GetETAStrFromTime(long eta) { if(eta<0) return xstring::get_tmp(""); unsigned flags=TimeInterval::TO_STR_TRANSLATE; if(terse) flags+=TimeInterval::TO_STR_TERSE; // for translator: Estimated Time of Arrival. return xstring::cat(_("eta:"),TimeInterval(eta,0).toString(flags),NULL); } const char *Speedometer::GetStrS(float r) { xstring &rate=GetStr(r); if(rate.length()) rate.append(' '); return rate; } const char *Speedometer::GetStrS() { return Valid() ? GetStrS(Get()) : ""; } const char *Speedometer::GetETAStrSFromSize(off_t s) { xstring &eta=GetETAStrFromSize(s); if(eta.length()) eta.append(' '); return eta; } const char *Speedometer::GetETAStrSFromTime(long s) { xstring &eta=GetETAStrFromTime(s); if(eta.length()) eta.append(' '); return eta; } void Speedometer::Reset() { start=now; last_second=now; rate=0; last_bytes=0; } ResDecl res_eta_terse("xfer:eta-terse", "yes",ResMgr::BoolValidate,ResMgr::NoClosure); void Speedometer::Reconfig(const char *n) { terse=res_eta_terse.QueryBool(0); SetPeriod(ResMgr::Query(period_resource,0)); } lftp-4.9.2/src/ColumnOutput.h0000644000015000007670000000370112122057234013031 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DISPCOLUMNS_H #define DISPCOLUMNS_H #include "OutputJob.h" #include "xarray.h" class datum { int ws, curwidth; public: /* Each entry has a series of strings; each string has a color. */ StringSet names; StringSet colors; datum() : ws(0), curwidth(0) {} void append(const char *name, const char *color); // get the total display width int width() const { return curwidth; } // print with or without color void print(const JobRef& o, bool color, int skip, const char *color_pref, const char *color_suf, const char *color_reset) const; /* count leading whitespace in the first name only. */ int whitespace() const { return ws; } }; class ColumnOutput { void get_print_info(unsigned width, xarray &col_arr, xarray &ws_arr, int &cols) const; public: enum mode_t { VERT }; void append(); void add(const char *name, const char *color); void addf(const char *fmt, const char *color, ...); void SetWidth(unsigned width); void SetColor(bool color); void print(const JobRef& o, unsigned width, bool color) const; void set_mode(mode_t m) { mode = m; } private: RefArray lst; mode_t mode; }; #endif lftp-4.9.2/src/CmdExec.cc0000644000015000007670000007145613143027116012035 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "CmdExec.h" #include "xstring.h" #include "SignalHook.h" #include "alias.h" #include "misc.h" #include "ResMgr.h" #include "module.h" #include "url.h" #include "QueueFeeder.h" #include "LocalDir.h" #include "ConnectionSlot.h" #include "DummyProto.h" #define RL_PROMPT_START_IGNORE '\001' #define RL_PROMPT_END_IGNORE '\002' #define super SessionJob #define waiting_num waiting.count() static ResType lftp_cmd_vars[] = { {"cmd:default-protocol", "ftp", 0,0}, {"cmd:long-running", "30", ResMgr::UNumberValidate,0}, {"cmd:remote-completion", "on", ResMgr::BoolValidate,0}, {"cmd:prompt", "lftp \\S\\? \\u\\@\\h:\\w> ",0,0}, {"cmd:default-title", "lftp \\h:\\w",0,0}, {"cmd:ls-default", "", 0,0}, {"cmd:csh-history", "off", ResMgr::BoolValidate,ResMgr::NoClosure}, {"cmd:verify-path", "yes", ResMgr::BoolValidate,0}, {"cmd:verify-path-cached", "no", ResMgr::BoolValidate,0}, {"cmd:verify-host", "yes", ResMgr::BoolValidate,0}, {"cmd:at-exit", "", 0,0}, {"cmd:at-exit-bg", "", 0,0}, {"cmd:at-exit-fg", "", 0,0}, {"cmd:at-background", "", 0,0}, {"cmd:at-terminate", "", 0,0}, {"cmd:at-finish", "", 0,0}, {"cmd:at-queue-finish", "", 0,0}, {"cmd:fail-exit", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"cmd:verbose", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"cmd:interactive", "auto", ResMgr::TriBoolValidate,ResMgr::NoClosure}, {"cmd:show-status", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"cmd:move-background", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"cmd:move-background-detach","yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"cmd:set-term-status", "no", ResMgr::BoolValidate,0}, {"cmd:term-status", "", 0, 0}, {"cmd:trace", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"cmd:parallel", "1", ResMgr::UNumberValidate,0}, {"cmd:queue-parallel", "1", ResMgr::UNumberValidate,0}, {"cmd:cls-exact-time", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {0} }; static ResDecls lftp_cmd_vars_register(lftp_cmd_vars); CmdExec *CmdExec::cwd_owner; CmdExec *CmdExec::chain; JobRef CmdExec::top; void CmdExec::SaveCWD() { if(!cwd) cwd=new LocalDirectory; cwd->SetFromCWD(); if(cwd_owner==0) cwd_owner=this; } int CmdExec::RestoreCWD() { if(cwd_owner==this) return 0; if(cwd==0) return -1; const char *err=cwd->Chdir(); if(!err) { cwd_owner=this; return 0; } const char *name=cwd->GetName(); eprintf(_("Warning: chdir(%s) failed: %s\n"),name?name:"?",err); return -1; } void CmdExec::FeedCmd(const char *c) { partial_cmd=false; start_time=now; cmd_buf.Put(c); }; void CmdExec::PrependCmd(const char *c) { start_time=now; int len=strlen(c); int nl=(len>0 && c[len-1]!='\n'); if(nl) cmd_buf.Prepend("\n",1); cmd_buf.Prepend(c,len); if(alias_field>0) alias_field+=len+nl; } int CmdExec::find_cmd(const char *cmd_name,const struct cmd_rec **ret) { int part=0; const cmd_rec *c=dyn_cmd_table?dyn_cmd_table.get():static_cmd_table; const int count=dyn_cmd_table?dyn_cmd_table.count():static_cmd_table_length; for(int i=0; iname,cmd_name)) { *ret=c; return 1; } if(!strncasecmp(c->name,cmd_name,strlen(cmd_name))) { part++; *ret=c; } } if(part!=1) *ret=0; return part; } CMD(lcd); void CmdExec::exec_parsed_command() { switch(condition) { case(COND_ANY): if(exit_code!=0 && ResMgr::QueryBool("cmd:fail-exit",0)) { failed_exit_code=exit_code; while(feeder) RemoveFeeder(); cmd_buf.Empty(); return; } break; case(COND_AND): if(exit_code!=0) return; break; case(COND_OR): if(exit_code==0) return; break; } prev_exit_code=exit_code; exit_code=1; if(interactive) { SignalHook::ResetCount(SIGINT); SignalHook::ResetCount(SIGHUP); SignalHook::ResetCount(SIGTSTP); } bool did_default=false; if(ResMgr::QueryBool("cmd:trace",0)) { xstring_ca c(args->CombineQuoted()); printf("+ %s\n",c.get()); } restart: const struct cmd_rec *c; const char *cmd_name=args->getarg(0); if(!cmd_name) return; int part=find_cmd(cmd_name,&c); if(part<=0) eprintf(_("Unknown command `%s'.\n"),cmd_name); else if(part>1) eprintf(_("Ambiguous command `%s'.\n"),cmd_name); else { if(RestoreCWD()==-1) { if(c->creator!=cmd_lcd) return; } args->setarg(0,c->name); // in case it was abbreviated args->rewind(); xstring_ca cmdline(args->Combine()); // save the cmdline Job *new_job=0; if(c->creator==0) { if(did_default) { eprintf(_("Module for command `%s' did not register the command.\n"),cmd_name); exit_code=1; return; } new_job=default_cmd(); did_default=true; } else { new_job=c->creator(this); } if(new_job==this || builtin) { if(builtin==BUILTIN_EXEC_RESTART) { builtin=BUILTIN_NONE; goto restart; } return; } RevertToSavedSession(); if(new_job) { if(!new_job->cmdline) new_job->cmdline.move_here(cmdline); AddNewJob(new_job); } } } void CmdExec::AddNewJob(Job *new_job) { if(new_job->jobno<0) new_job->AllocJobno(); new_job->SetParentFg(this,!background); exit_code=0; AddWaiting(new_job); if(background) { Roll(new_job); if(!new_job->Done()) SuspendJob(new_job); } } void CmdExec::SuspendJob(Job *j) { j->Bg(); if(interactive) j->ListOneJob(0,0,"&"); last_bg=j->jobno; exit_code=0; RemoveWaiting(j); } void CmdExec::ExecParsed(ArgV *a,FDStream *o,bool b) { Enter(); args=a; output=o; background=b; condition=COND_ANY; exec_parsed_command(); Leave(); } bool CmdExec::Idle() { return(waiting_num==0 && builtin==BUILTIN_NONE && (cmd_buf.Size()==0 || partial_cmd)); } int CmdExec::Done() { Enter(); bool done = (feeder==0 && Idle()) || (auto_terminate_in_bg && NumberOfChildrenJobs()==0 && !in_foreground_pgrp()); Leave(); return done; } void CmdExec::RemoveFeeder() { free_used_aliases(); if(!feeder) return; // save old cwd if necessary if(interactive && feeder->prev==0) cwd_history.Set(session); cmd_buf.Empty(); cmd_buf.Put(feeder->saved_buf); partial_cmd=false; if(feeder==queue_feeder) queue_feeder=0; delete replace_value(feeder,feeder->prev); Reconfig(0); SetInteractive(); } void CmdExec::ReuseSavedSession() { saved_session=0; } void CmdExec::RevertToSavedSession() { if(saved_session==0) return; ChangeSession(saved_session.borrow()); } void CmdExec::ChangeSlot(const char *n) { if(!n || !*n) { slot.set(0); return; } slot.set(n); const FileAccess *s=ConnectionSlot::FindSession(n); if(!s) ConnectionSlot::Set(n,session); else ChangeSession(s->Clone()); } void CmdExec::AtFinish() { if(queue_feeder && queue_feeder->JobCount()) return; if(!fed_at_finish && NumAwaitedJobs()==0 && cmd_buf.Size()==0) { FeedCmd(ResMgr::Query(queue_feeder?"cmd:at-queue-finish":"cmd:at-finish",0)); FeedCmd("\n"); fed_at_finish=true; } } int CmdExec::Do() { int m=STALL; if(builtin!=BUILTIN_NONE) { int res; switch(builtin) { case(BUILTIN_CD): res=session->Done(); if(res==FA::OK) { // done if(status_line) status_line->Clear(); if(interactive || verbose) { const char *cwd=session->GetCwd(); eprintf(_("cd ok, cwd=%s\n"),cwd?cwd:"~"); cwd_history.Set(session,old_cwd); } if(slot) ConnectionSlot::SetCwd(slot,session->GetCwd()); session->Close(); exit_code=0; builtin=BUILTIN_NONE; redirections=0; beep_if_long(); return MOVED; } if(res<0) { if(res==FA::FILE_MOVED) { // cd to another url. const char *loc_c=session->GetNewLocation(); int max_redirections=ResMgr::Query("xfer:max-redirections",0); if(loc_c && max_redirections>0) { eprintf(_("%s: received redirection to `%s'\n"),"cd",loc_c); if(++redirections>max_redirections) { eprintf("cd: %s\n",_("Too many redirections")); goto cd_err_done; } char *loc=alloca_strdup(loc_c); ParsedURL u(loc,true); if(!u.proto) { bool is_file=(last_char(loc)!='/'); FileAccess::Path new_cwd(session->GetNewCwd()); new_cwd.Change(0,is_file,loc); session->PathVerify(new_cwd); session->Roll(); return MOVED; } session->Close(); exit_code=0; builtin=BUILTIN_NONE; PrependCmd(xstring::get_tmp("open ").append_quoted(loc)); return MOVED; } } // error if(status_line) status_line->Clear(); eprintf("%s: %s\n",args->getarg(0),session->StrError(res)); cd_err_done: session->Close(); builtin=BUILTIN_NONE; redirections=0; beep_if_long(); exit_code=1; return MOVED; } break; case(BUILTIN_OPEN): res=session->Done(); if(res==FA::OK) { if(status_line) status_line->Clear(); session->Close(); ReuseSavedSession(); builtin=BUILTIN_NONE; redirections=0; beep_if_long(); exit_code=0; return MOVED; } if(res<0) { if(status_line) status_line->Clear(); eprintf("%s: %s\n",args->getarg(0),session->StrError(res)); session->Close(); RevertToSavedSession(); builtin=BUILTIN_NONE; redirections=0; beep_if_long(); exit_code=1; return MOVED; } break; case(BUILTIN_GLOB): if(glob->Error()) { if(status_line) status_line->Clear(); eprintf("%s: %s\n",args->getarg(0),glob->ErrorText()); } else if(glob->Done()) { FileSet &list=*glob->GetResult(); for(int i=0; list[i]; i++) args_glob->Append(list[i]->name); } if(glob->Done() || glob->Error()) { const char *pat=args->getnext(); if(!pat) { glob=0; // it was last argument args=args_glob.borrow(); builtin=BUILTIN_NONE; redirections=0; if(status_line) status_line->Clear(); exit_code=prev_exit_code; RevertToSavedSession(); exec_parsed_command(); return MOVED; } glob->NewGlob(pat); m=MOVED; } break; case(BUILTIN_NONE): case(BUILTIN_EXEC_RESTART): abort(); // can't happen } if(interactive) { if(SignalHook::GetCount(SIGINT)) { if(status_line) status_line->WriteLine(_("Interrupt")); return AcceptSig(SIGINT); } if(SignalHook::GetCount(SIGTSTP)) { if(builtin==BUILTIN_CD || builtin==BUILTIN_OPEN) { if(status_line) status_line->Clear(); if(builtin==BUILTIN_CD) session->ChdirAccept(); session->Close(); exit_code=0; builtin=BUILTIN_NONE; redirections=0; return MOVED; } else { SignalHook::ResetCount(SIGTSTP); } } if(SignalHook::GetCount(SIGHUP)) { SetInteractive(false); return MOVED; } } if(status_line && show_status && status_line->CanShowNow()) ShowRunStatus(status_line); // this is only for top level CmdExec. return m; } if(waiting_num>0) { Job *j; while((j=FindDoneAwaitedJob())!=0) { j->Bg(); if(status_line) status_line->Clear(); if(interactive || verbose) j->SayFinal(); // final phrase like 'rm succeed' exit_code=j->ExitCode(); RemoveWaiting(j); Delete(j); beep_if_long(); return MOVED; } if(interactive) { if(SignalHook::GetCount(SIGINT)) { for(int i=0; iBg(); SignalHook::ResetCount(SIGINT); if(status_line) status_line->WriteLine(_("Interrupt")); return AcceptSig(SIGINT); } if(SignalHook::GetCount(SIGTSTP)) { while(waiting_num>0) SuspendJob(waiting[0]); return MOVED; } if(SignalHook::GetCount(SIGHUP)) { SetInteractive(false); return MOVED; } } if(status_line && show_status && status_line->CanShowNow()) ShowRunStatus(status_line); // this is only for top level CmdExec. if(m != STALL || interactive || waiting_num >= max_waiting) return m; } if(!interactive) { BuryDoneJobs(); if(FindJob(last_bg)==0) last_bg=-1; } try_get_cmd: if(cmd_buf.Size()==0 || partial_cmd) { if(feeder) { if(interactive && !partial_cmd) { ListDoneJobs(); BuryDoneJobs(); if(FindJob(last_bg)==0) last_bg=-1; } if(status_line && show_status) { const char *def_title = FormatPrompt(ResMgr::Query("cmd:default-title",getenv("TERM"))); status_line->DefaultTitle(def_title); status_line->Clear(); } const char *prompt=MakePrompt(); feeder_called=true; if(fg) feeder->Fg(); const char *cmd=feeder->NextCmd(this,prompt); feeder_called=false; if(!cmd) { if(cmd_buf.Size()>0 && partial_cmd) { const char *next_cmd=cmd_buf.Get(); if(last_char(next_cmd)!='\n') { // missing EOL on last line, add it FeedCmd("\n"); goto try_get_cmd; } fprintf(stderr,_("Warning: discarding incomplete command\n")); } if(!feeder->RealEOF() && top_level) { cmd_buf.Empty(); FeedCmd("exit;"); return MOVED; } if(waiting_num > 0) return m; RemoveFeeder(); m=MOVED; goto try_get_cmd; } if(cmd[0]) { auto_terminate_in_bg=false; FeedCmd(cmd); Roll(); if(!Idle()) fed_at_finish=false; return MOVED; } else { if(SignalHook::GetCount(SIGINT)>0) { SignalHook::ResetCount(SIGINT); cmd_buf.Empty(); // flush unparsed command return MOVED; } } } return m; } parse_result res = parse_one_cmd(); if(alias_field<=0) free_used_aliases(); switch(res) { case(PARSE_ERR): return MOVED; case(PARSE_AGAIN): partial_cmd=true; goto try_get_cmd; case(PARSE_OK): if(feeder) feeder->Bg(); break; } if(args==0 || args->count()==0) { AtFinish(); return MOVED; // empty command } if(interactive) session->DontSleep(); // We don't want to get a delay just after user // entered a command. exec_parsed_command(); return MOVED; } void CmdExec::ShowRunStatus(const SMTaskRef& s) { switch(builtin) { case(BUILTIN_CD): if(session->IsOpen()) s->Show("cd `%s' [%s]",squeeze_file_name(args->getarg(1),s->GetWidthDelayed()-40),session->CurrentStatus()); break; case(BUILTIN_OPEN): if(session->IsOpen()) s->Show("open `%s' [%s]",session->GetHostName(),session->CurrentStatus()); break; case(BUILTIN_GLOB): s->Show("%s",glob->Status()); break; case(BUILTIN_EXEC_RESTART): abort(); // can't happen case(BUILTIN_NONE): if(waiting_num>0) Job::ShowRunStatus(s); else s->Clear(); break; } } xstring& CmdExec::FormatStatus(xstring& s,int v,const char *prefix) { SessionJob::FormatStatus(s,v,prefix); if(builtin) { xstring_ca ac(args->Combine()); return s.appendf(_("\tExecuting builtin `%s' [%s]\n"),ac.get(),session->CurrentStatus()); } if(queue_feeder) { if(IsSuspended()) s.appendf("%s%s\n",prefix,_("Queue is stopped.")); BuryDoneJobs(); for(int i=0; iFormatOneJob(s,v); else waiting[i]->FormatJobTitle(s); if(i+1FormatStatus(s,v,prefix); } if(waiting_num==1) return s.appendf(_("\tWaiting for job [%d] to terminate\n"),waiting[0]->jobno); else if(waiting_num>1) { s.appendf(_("\tWaiting for termination of jobs: ")); for(int i=0; ijobno); s.append(i+10) s.append(_("\tRunning\n")); else if(feeder) s.append(_("\tWaiting for command\n")); return s; } void CmdExec::init(LocalDirectory *c) { // add this to chain next=chain; chain=this; background=false; interactive=false; show_status=true; top_level=false; auto_terminate_in_bg=false; feeder=0; feeder_called=false; used_aliases=0; partial_cmd=false; alias_field=0; default_output=0; condition=COND_ANY; prev_exit_code=0; exit_code=0; failed_exit_code=0; last_bg=-1; fed_at_finish=true; cwd=c; if(!cwd) SaveCWD(); remote_completion=false; long_running=0; csh_history=false; verify_host=verify_path=true; verify_path_cached=false; start_time=0; redirections=0; queue_feeder=0; max_waiting=1; saved_session=0; builtin=BUILTIN_NONE; Reconfig(); } CmdExec::CmdExec(FileAccess *s,LocalDirectory *c) : SessionJob(s?s:new DummyProto), parent_exec(0) { init(c); } CmdExec::CmdExec(CmdExec *parent) : SessionJob(parent->session->Clone()), parent_exec(parent) { init(parent->cwd->Clone()); } CmdExec::~CmdExec() { // remove this from chain. for(CmdExec **scan=&chain; *scan; scan=&(*scan)->next) { if(this==*scan) { *scan=(*scan)->next; break; } } free_used_aliases(); if(cwd_owner==this) cwd_owner=0; } const char *CmdExec::FormatPrompt(const char *scan) { const char *cwd=session->GetCwd(); if(cwd==0 || cwd[0]==0) cwd="~"; { const char *home=session->GetHome(); int home_len=xstrlen(home); if(home_len>1 && !strncmp(cwd,home,home_len) && (cwd[home_len]=='/' || cwd[home_len]==0)) { cwd=xstring::format("~%s",cwd+home_len); } } const char *cwdb=session->GetCwd(); if(cwdb==0 || cwdb[0]==0) cwdb="~"; const char *p=strrchr(cwdb,'/'); if(p && p>cwdb) cwdb=p+1; const char *lcwd=this->cwd->GetName(); { const char *home=get_home(); int home_len=xstrlen(home); if(home_len>1 && !strncmp(lcwd,home,home_len) && (lcwd[home_len]=='/' || lcwd[home_len]==0)) { lcwd=xstring::format("~%s",lcwd+home_len); } } const char *lcwdb=this->cwd->GetName(); p=strrchr(lcwdb,'/'); if(p && p>lcwdb) lcwdb=p+1; static const char StartIgn[]={RL_PROMPT_START_IGNORE,0}; static const char EndIgn[]={RL_PROMPT_END_IGNORE,0}; subst_t subst[] = { { 'a', "\007" }, { 'e', "\033" }, { 'n', "\n" }, { 's', "lftp" }, { 'v', VERSION }, { 'h', session->GetHostName() }, { 'u', session->GetUser() }, // @ if non-default user { '@', session->GetUser()?"@":"" }, { 'U', session->GetConnectURL() }, { 'S', slot?slot.get():"" }, { 'w', cwd }, { 'W', cwdb }, { 'l', lcwd }, { 'L', lcwdb }, { '[', StartIgn }, { ']', EndIgn }, { 0, "" } }; static xstring prompt; SubstTo(prompt, scan, subst); return(prompt); } const char *CmdExec::MakePrompt() { if(partial_cmd) return "> "; return FormatPrompt(ResMgr::Query("cmd:prompt",getenv("TERM"))); } void CmdExec::beep_if_long() { if(start_time!=0 && long_running!=0 && now.UnixTime()>start_time+long_running && interactive && Idle() && isatty(1)) write(1,"\007",1); AtFinish(); } void CmdExec::Reconfig(const char *name) { const char *c=0; if(session) c = session->GetConnectURL(FA::NO_PATH); long_running=ResMgr::Query("cmd:long-running",c); remote_completion=ResMgr::QueryBool("cmd:remote-completion",c); csh_history=ResMgr::QueryBool("cmd:csh-history",0); verify_path=ResMgr::QueryBool("cmd:verify-path",c); verify_path_cached=ResMgr::QueryBool("cmd:verify-path-cached",c); verify_host=ResMgr::QueryBool("cmd:verify-host",c); verbose=ResMgr::QueryBool("cmd:verbose",0); if(top_level || queue_feeder) max_waiting=ResMgr::Query(queue_feeder?"cmd:queue-parallel":"cmd:parallel",c); if(name && !strcmp(name,"cmd:interactive")) SetInteractive(); show_status=ResMgr::QueryBool("cmd:show-status",0); } void CmdExec::pre_stdout() { if(status_line) status_line->Clear(false); if(feeder_called) feeder->clear(); current->TimeoutS(1); } void CmdExec::top_vfprintf(FILE *file,const char *f,va_list v) { pre_stdout(); ::vfprintf(file,f,v); } void CmdExec::SetCmdFeeder(CmdFeeder *new_feeder) { new_feeder->prev=feeder; new_feeder->saved_buf.set(cmd_buf.Get()); feeder=new_feeder; cmd_buf.Empty(); SetInteractive(); } int CmdExec::AcceptSig(int sig) { if(sig!=SIGINT && sig!=SIGTERM) return STALL; if(builtin) { switch(builtin) { case(BUILTIN_CD): session->Close(); break; case(BUILTIN_OPEN): session->Close(); RevertToSavedSession(); break; case(BUILTIN_GLOB): glob=0; args_glob=0; break; case(BUILTIN_NONE): case(BUILTIN_EXEC_RESTART): abort(); // should not happen } builtin=BUILTIN_NONE; redirections=0; exit_code=1; return MOVED; } if(waiting_num>0) { int limit=waiting_num; for(int i=0; iAcceptSig(sig); if(res==WANTDIE) { exit_code=1; RemoveWaiting(r); Delete(r); i--; limit--; } } if(waiting_num==0 && parent!=0) return WANTDIE; return MOVED; } if(parent!=0) return WANTDIE; return STALL; } void CmdExec::SetInteractive(bool i) { if(interactive==i) return; if(i) { SignalHook::DoCount(SIGINT); SignalHook::DoCount(SIGTSTP); } else { SignalHook::Restore(SIGINT); SignalHook::Restore(SIGTSTP); } interactive=i; } void CmdExec::SetInteractive() { if(!top_level) return; bool def=feeder?feeder->IsInteractive():false; SetInteractive(ResMgr::QueryTriBool("cmd:interactive",0,def)); } xstring& xstring::append_quoted(const char *str,int len) { if(!CmdExec::needs_quotation(str,len)) return append(str); append('"'); while(len>0) { if(*str=='"' || *str=='\\') append('\\'); append(*str++); len--; } return append('"'); } bool CmdExec::needs_quotation(const char *buf,int len) { while(len>0) { if(*buf==' ' || *buf=='\t') return true; if(strchr("\"'\\&|>;",*buf)) return true; buf++; len--; } return false; } void CmdExec::FeedQuoted(const char *c) { FeedCmd(xstring::get_tmp("").append_quoted(c)); } // implementation is here because it depends on CmdExec. xstring& ArgV::CombineQuotedTo(xstring& res,int start) const { res.nset("",0); if(start>=Count()) return res; for(;;) { const char *arg=String(start++); res.append_quoted(arg); if(start>=Count()) return(res); res.append(' '); } } xstring& ArgV::CombineCmdTo(xstring& res,int i) const { return i>=count()-1 ? CombineTo(res,i) : CombineQuotedTo(res,i); } const char *CmdExec::GetFullCommandName(const char *cmd) { const CmdExec::cmd_rec *c; int part=CmdExec::find_cmd(cmd,&c); if(part==1) return c->name; return cmd; } void CmdExec::AtExit() { FeedCmd(ResMgr::Query("cmd:at-exit",0)); FeedCmd("\n"); /* Clear the title, and ensure we don't write anything else * to it in case we're being backgrounded. */ status_line=0; } void CmdExec::AtExitBg() { FeedCmd(ResMgr::Query("cmd:at-exit-bg",0)); FeedCmd("\n"); } void CmdExec::AtExitFg() { FeedCmd(ResMgr::Query("cmd:at-exit-fg",0)); FeedCmd("\n"); } void CmdExec::AtBackground() { FeedCmd(ResMgr::Query("cmd:at-background",0)); FeedCmd("\n"); } void CmdExec::AtTerminate() { FeedCmd(ResMgr::Query("cmd:at-terminate",0)); FeedCmd("\n"); } void CmdExec::EmptyCmds() { cmd_buf.Empty(); } bool CmdExec::WriteCmds(int fd) const { const char *buf; int len; cmd_buf.Get(&buf,&len); for(;;) { if(len==0) return true; int res=write(fd,buf,len); if(res<=0) return false; buf+=res; len-=res; } } bool CmdExec::ReadCmds(int fd) { for(;;) { int size=0x1000; size=read(fd,cmd_buf.GetSpace(size),size); if(size==-1) return false; if(size==0) return true; cmd_buf.SpaceAdd(size); } } void CmdExec::free_used_aliases() { if(used_aliases) { TouchedAlias::FreeChain(used_aliases); used_aliases=0; } alias_field=0; } void CmdExec::skip_cmd(int len) { cmd_buf.Skip(len); alias_field-=len; if(alias_field<=0) free_used_aliases(); } int CmdExec::cmd_rec::cmp(const CmdExec::cmd_rec *a,const CmdExec::cmd_rec *b) { return strcmp(a->name,b->name); } xarray CmdExec::dyn_cmd_table; void CmdExec::RegisterCommand(const char *name,cmd_creator_t creator,const char *short_desc,const char *long_desc) { if(dyn_cmd_table==0) dyn_cmd_table.nset(static_cmd_table,static_cmd_table_length); cmd_rec new_entry={name,creator,short_desc,long_desc}; int i; if(dyn_cmd_table.bsearch(new_entry,cmd_rec::cmp,&i)) { cmd_rec *const c=&dyn_cmd_table[i]; c->creator=creator; if(short_desc) c->short_desc=short_desc; if(long_desc || strlen(c->long_desc)<2) c->long_desc=long_desc; return; } dyn_cmd_table.insert(new_entry,i); } void CmdExec::ChangeSession(FileAccess *new_session) { session=new_session; session->SetPriority(fg?1:0); Reconfig(0); if(slot) ConnectionSlot::Set(slot,session); } const char *CmdExec::CmdByIndex(int i) { if(dyn_cmd_table) { if(ia0(); if(load_cmd_module(op)) { builtin=BUILTIN_EXEC_RESTART; return this; } return 0; } Job *CmdExec::builtin_local() { if(args->count()<2) { eprintf(_("Usage: %s cmd [args...]\n"),args->a0()); return 0; } saved_session=session.borrow(); session=FileAccess::New("file"); if(!session) { eprintf(_("%s: cannot create local session\n"),args->a0()); RevertToSavedSession(); return 0; } session->SetCwd(cwd->GetName()); args->delarg(0); builtin=BUILTIN_EXEC_RESTART; return this; } void CmdExec::FeedArgV(const ArgV *args,int start) { xstring cmd; args->CombineCmdTo(cmd,start); FeedCmd(cmd); FeedCmd("\n"); } bool CmdExec::SameQueueParameters(CmdExec *scan,const char *this_url) { return !strcmp(this_url,scan->session->GetConnectURL(FA::NO_PATH)) && this->slot.eq(scan->slot); } /* return the CmdExec containing a queue feeder; create if necessary */ CmdExec *CmdExec::GetQueue(bool create) { const char *this_url=session->GetConnectURL(FA::NO_PATH); // future GetConnectURL overwrite the static buffer, save it. this_url=alloca_strdup(this_url); for(CmdExec *scan=chain; scan; scan=scan->next) { if(scan->queue_feeder && SameQueueParameters(scan,this_url)) return scan; } if(!create) return NULL; CmdExec *queue=new CmdExec(session->Clone(),cwd->Clone()); queue->slot.set(slot); queue->SetParentFg(this,false); queue->AllocJobno(); const char *url=session->GetConnectURL(FA::NO_PATH); queue->cmdline.vset("queue (",url,slot?"; ":"",slot?slot.get():"",")",NULL); queue->queue_feeder=new QueueFeeder(session->GetCwd(), cwd->GetName()); queue->SetCmdFeeder(queue->queue_feeder); queue->Reconfig(0); return queue; } lftp-4.9.2/src/TorrentTracker.h0000644000015000007670000001340512662070341013331 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2014 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TORRENTTRACKER_H #define TORRENTTRACKER_H #include "url.h" class TrackerBackend; class TorrentTracker : public SMTask, protected ProtoLog { friend class Torrent; friend class TrackerBackend; Torrent *parent; xarray_p tracker_urls; int current_tracker; SMTaskRef backend; Timer tracker_timer; Timer tracker_timeout_timer; xstring tracker_id; bool started; Ref error; int tracker_no; TorrentTracker(Torrent *p,const char *url); void AddURL(const char *url); int Do(); void Start(); void Shutdown(); void SendTrackerRequest(const char *event); void SetError(const char *e); bool Failed() const { return error!=0 || tracker_urls.count()==0; } const char *ErrorText() const { return error->Text(); } void NextTracker(); void CreateTrackerBackend(); const char *GetLogContext() { return GetURL(); } public: ~TorrentTracker() {} const char *NextRequestIn() const { return tracker_timer.TimeLeft().toString( TimeInterval::TO_STR_TRANSLATE|TimeInterval::TO_STR_TERSE); } const char *GetURL() const { return tracker_urls[current_tracker]->get(); } const char *Status() const; bool IsActive() const; void TrackerRequestFinished() { tracker_timer.Reset(); } void SetInterval(unsigned i) { if(i<30) i=30; tracker_timer.Set(i); LogNote(4,"Tracker interval is %u",i); } void SetTrackerID(const xstring& id) { if(id) tracker_id.set(id); } bool AddPeerCompact(const char *a,int len) const; bool AddPeer(const xstring& addr,int port) const; bool ShuttingDown(); }; class TrackerBackend : public SMTask, protected ProtoLog { protected: TorrentTracker *master; void SetError(const char *e) { master->SetError(e); } const char *GetURL() const { return master->GetURL(); } const xstring& GetInfoHash() const; const xstring& GetMyPeerId() const; int GetPort() const; unsigned long long GetTotalSent() const; unsigned long long GetTotalRecv() const; unsigned long long GetTotalLeft() const; bool HasMetadata() const; bool Complete() const; int GetWantedPeersCount() const; const xstring& GetMyKey() const; unsigned GetMyKeyNum() const; const char *GetTrackerId() const; void SetTrackerID(const xstring& id) const { master->SetTrackerID(id); } void SetInterval(unsigned i) const { master->SetInterval(i); } bool AddPeerCompact(const char *a,int len) const { return master->AddPeerCompact(a,len); } bool AddPeer(const xstring& addr,int port) const { return master->AddPeer(addr,port); } void NextTracker() const { master->NextTracker(); } bool ShuttingDown() const; void Started() const; void TrackerRequestFinished() const; const char *GetLogContext() { return master->GetLogContext(); } public: TrackerBackend(TorrentTracker *m) : master(m) {} virtual ~TrackerBackend() {} virtual bool IsActive() const = 0; virtual void SendTrackerRequest(const char *event) = 0; virtual const char *Status() const = 0; }; class HttpTracker : public TrackerBackend { FileAccessRef t_session; SMTaskRef tracker_reply; int HandleTrackerReply(); public: bool IsActive() const { return tracker_reply!=0; } void SendTrackerRequest(const char *event); HttpTracker(TorrentTracker *m,ParsedURL *u) : TrackerBackend(m), t_session(FileAccess::New(u)) {} ~HttpTracker() {} int Do(); const char *Status() const { return t_session->CurrentStatus(); } }; class UdpTracker : public TrackerBackend, protected Networker { xstring_c hostname; xstring_c portname; SMTaskRef resolver; xarray peer; int peer_curr; void NextPeer(); int sock; // udp socket for packet exchange Timer timeout_timer; int try_number; // timeout = 60 * 2^try_number bool has_connection_id; unsigned long long connection_id; enum action_t { a_none=-1, a_connect=0, a_announce=1, a_scrape=2, a_error=3, a_announce6=4, }; enum event_t { ev_idle=-1, ev_none=0, ev_completed=1, ev_started=2, ev_stopped=3, }; enum magic_t { connect_magic=0x41727101980ULL, }; static const char *EventToString(event_t e); unsigned transaction_id; action_t current_action; event_t current_event; bool SendPacket(Buffer& req); bool SendConnectRequest(); bool SendEventRequest(); bool RecvReply(); unsigned NewTransactionId() { return transaction_id=random(); } public: UdpTracker(TorrentTracker *m,ParsedURL *u) : TrackerBackend(m), hostname(u->host.get()), portname(u->port.get()), peer_curr(0), sock(-1), timeout_timer(60), try_number(0), has_connection_id(false), connection_id(0), current_action(a_none), current_event(ev_idle) {} ~UdpTracker() { if(sock!=-1) close(sock); } int Do(); bool IsActive() const { return current_event!=ev_idle; } void SendTrackerRequest(const char *event); const char *Status() const; }; #endif // TORRENTTRACKER_H lftp-4.9.2/src/FindJobDu.h0000644000015000007670000000427312662070340012166 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef FINDJOBDU_H #define FINDJOBDU_H #include "FindJob.h" class FinderJob_Du : public FinderJob { SMTaskRef buf; /* We keep traversing deeper than this, but we never print a total * past this. */ int max_print_depth; bool print_totals; int output_block_size; int human_opts; bool all_files; bool separate_dirs; bool file_count; bool success; long long tot_size; void Init(const char *d); struct stack_entry { xstring_c dir; long long size; stack_entry(const char *dir) : dir(dir), size(0) {} }; RefArray size_stack; Ref args; void print_size (long long n_blocks, const char *string); off_t BlockCeil(off_t size) const; // prepends last directory name const char *MakeFileName(const char *n); void Push (const char *d); void Pop(); public: FinderJob_Du(FileAccess *s,ArgV *a,FDStream *o); ~FinderJob_Du(); int Done(); void PrintTotals() { print_totals=true; } void SetBlockSize(int n,int ho) { output_block_size = n; human_opts = ho; } void PrintDepth(int n) { max_print_depth = n; } void AllFiles() { all_files=true; } void SeparateDirs() { separate_dirs=true; } void FileCount() { file_count=true; } protected: /* virtuals */ prf_res ProcessFile(const char *d,const FileInfo *fi); void ProcessList(FileSet *f); void Finish(); void Enter(const char *d); void Exit(); }; #endif // FINDJOBDU_H lftp-4.9.2/src/SysCmdJob.h0000644000015000007670000000224412122060730012204 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SYSCMDJOB_H #define SYSCMDJOB_H #include "trio.h" #include "Job.h" #include "ProcWait.h" class SysCmdJob : public Job { xstring cmd; SMTaskRef w; void PrepareToDie(); public: SysCmdJob(const char *new_cmd); ~SysCmdJob(); int Do(); int Done() { return(w && w->GetState()!=w->RUNNING); } int AcceptSig(int); int ExitCode() { return w?w->GetInfo()>>8:1; } }; #endif//SYSCMDJOB_H lftp-4.9.2/src/FileAccess.cc0000644000015000007670000005540113332534452012524 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "FileAccess.h" #include #include #include #include #include #include #include #include "ascii_ctype.h" #include #include "LsCache.h" #include "log.h" #include "url.h" #include "misc.h" #include "DummyProto.h" #include "netrc.h" #include "ArgV.h" #include "ConnectionSlot.h" #include "SignalHook.h" #include "FileGlob.h" #ifdef WITH_MODULES # include "module.h" #endif xlist_head FileAccess::all_fa; const FileAccessRef FileAccessRef::null; void FileAccess::Init() { ClassInit(); pass_open=false; default_cwd="~"; cwd.Set(default_cwd,false,0); limit=FILE_END; real_pos=UNKNOWN_POS; pos=0; mode=CLOSED; retries=0; max_retries=0; opt_date=0; opt_size=0; fileset_for_info=0; error_code=OK; saved_errno=0; mkdir_p=false; rename_f=false; ascii=false; norest_manual=false; entity_size=NO_SIZE; entity_date=NO_DATE; res_prefix=0; chmod_mode=0644; priority=last_priority=0; all_fa.add(all_fa_node); } FileAccess::FileAccess(const FileAccess *fa) : all_fa_node(this) { Init(); cwd=fa->cwd; home=fa->home; user.set(fa->user); pass.set(fa->pass); pass_open=fa->pass_open; hostname.set(fa->hostname); portname.set(fa->portname); vproto.set(fa->vproto); } FileAccess::~FileAccess() { all_fa_node.remove(); } void FileAccess::Open(const char *fn,int mode,off_t offs) { #ifdef OPEN_DEBUG printf("%p->FA::Open(%s,%d)\n",this,fn?fn:"NULL",mode); #endif if(IsOpen()) Close(); Resume(); file.set(fn); real_pos=UNKNOWN_POS; pos=offs; this->mode=mode; mkdir_p=false; rename_f=false; Timeout(0); switch((open_mode)mode) { case STORE: case REMOVE: case MAKE_DIR: case CHANGE_MODE: cache->FileChanged(this,file); break; case REMOVE_DIR: cache->FileChanged(this,file); cache->TreeChanged(this,file); break; default: break; } } const char *FileAccess::StrError(int err) { static xstring str; // note to translators: several errors should not be displayed to user; // so no need to translate them. switch(err) { case(IN_PROGRESS): return("Operation is in progress"); case(OK): return("Error 0"); case(SEE_ERRNO): if(error) return str.vset(error.get(),": ",strerror(saved_errno),NULL); return(strerror(saved_errno)); case(LOOKUP_ERROR): return(error); case(NOT_OPEN): // Actually this means an error in application return("Class is not Open()ed"); case(NO_FILE): if(error) return str.vset(_("Access failed: "),error.get(),NULL); return(_("File cannot be accessed")); case(NO_HOST): return(_("Not connected")); case(FATAL): if(error) return str.vset(_("Fatal error"),": ",error.get(),NULL); return(_("Fatal error")); case(STORE_FAILED): return(_("Store failed - you have to reput")); case(LOGIN_FAILED): if(error) return str.vset(_("Login failed"),": ",error.get(),NULL); return(_("Login failed")); case(NOT_SUPP): if(error) return str.vset(_("Operation not supported"),": ",error.get(),NULL); return(_("Operation not supported")); case(FILE_MOVED): if(error) return str.vset(_("File moved"),": ",error.get(),NULL); else return str.vset(_("File moved to `"),location?location.get():"?","'",NULL); } return(""); } void FileAccess::Close() { file.set(0); file_url.set(0); file1.set(0); new_cwd=0; mode=CLOSED; opt_date=0; opt_size=0; fileset_for_info=0; retries=0; entity_size=NO_SIZE; entity_date=NO_DATE; ascii=false; norest_manual=false; location.set(0); entity_content_type.set(0); entity_charset.set(0); ClearError(); } void FileAccess::Open2(const char *f,const char *f1,open_mode o) { Close(); file1.set(f1); Open(f,o); cache->TreeChanged(this,file); cache->FileChanged(this,file); cache->FileChanged(this,file1); } void FileAccess::Rename(const char *rfile,const char *to,bool clobber) { Open2(rfile,to,RENAME); rename_f=clobber; } void FileAccess::Mkdir(const char *fn,bool allp) { Open(fn,MAKE_DIR); mkdir_p=allp; } StringSet *FileAccess::MkdirMakeSet() const { StringSet *set=new StringSet; const char *sl=strchr(file,'/'); while(sl) { if(sl>file) { xstring& tmp=xstring::get_tmp(file,sl-file); if(tmp.ne(".") && tmp.ne("..")) set->Append(tmp); } sl=strchr(sl+1,'/'); } return set; } bool FileAccess::SameLocationAs(const FileAccess *fa) const { return SameSiteAs(fa); } bool FileAccess::SameSiteAs(const FileAccess *fa) const { return SameProtoAs(fa); } const xstring& FileAccess::GetFileURL(const char *f,int flags) const { const char *proto=GetVisualProto(); if(proto[0]==0) return xstring::get_tmp(""); ParsedURL u; u.proto.set(proto); if(!(flags&NO_USER)) u.user.set(user); if((pass_open || (flags&WITH_PASSWORD)) && !(flags&NO_PASSWORD)) u.pass.set(pass); u.host.set(hostname); u.port.set(portname); if(!(flags&NO_PATH)) { if(cwd.url) { Path f_path(cwd); if(f) f_path.Change(f,true); if(f_path.url) { int f_path_index=url::path_index(f_path.url); return u.CombineTo(xstring::get_tmp(""),home) .append(f_path.url+f_path_index); } } bool is_dir=((!f || !*f) && !cwd.is_file); if(!f || (f[0]!='/' && f[0]!='~')) f=dir_file(cwd.path?cwd.path.get():"~",f); u.path.set(f); if(is_dir && url::dir_needs_trailing_slash(proto) && u.path.last_char()!='/') u.path.append('/'); } return u.CombineTo(xstring::get_tmp(""),home); } const xstring& FileAccess::GetConnectURL(int flags) const { return GetFileURL(0,flags); } void FileAccess::Connect(const char *host1,const char *port1) { Close(); hostname.set(host1); portname.set(port1); DontSleep(); ResetLocationData(); } void FileAccess::Login(const char *user1,const char *pass1) { Close(); user.set(user1); pass.set(pass1); pass_open=false; if(user && pass==0) { xlist_for_each(FileAccess,all_fa,node,o) { pass.set(o->pass); if(SameSiteAs(o) && o->pass) break; } if(!o) pass.set(0); if(pass==0 && hostname) // still no pass? Try .netrc { NetRC::Entry *nrc=NetRC::LookupHost(hostname,user); if(nrc) pass.set(nrc->pass); } } ResetLocationData(); } void FileAccess::ResetLocationData() { cwd.Set(default_cwd,false,0); home.Set((char*)0); } void FileAccess::SetPasswordGlobal(const char *p) { pass.set(p); xstring save_pass; xlist_for_each(FileAccess,all_fa,node,o) { if(o==this) continue; save_pass.set(o->pass); // cheat SameSiteAs. o->pass.set(pass); if(!SameSiteAs(o)) o->pass.set(save_pass); } } void FileAccess::GetInfoArray(FileSet *info) { Open(0,ARRAY_INFO); fileset_for_info=info; fileset_for_info->rewind(); } static void expand_tilde(xstring &path, const char *home, int i=0) { if(!(path[i]=='~' && (path[i+1]==0 || path[i+1]=='/'))) return; char prefix_len=(last_char(home)=='/' ? 2 : 1); if(home[0]=='/' && i>0 && path[i-1]=='/') home++; path.set_substr(i,prefix_len,home); } void FileAccess::ExpandTildeInCWD() { if(home) { cwd.ExpandTilde(home); if(new_cwd) new_cwd->ExpandTilde(home); if(real_cwd) expand_tilde(real_cwd,home); if(file) expand_tilde(file,home); if(file1) expand_tilde(file1,home); } } void FileAccess::set_home(const char *h) { home.Set(h); ExpandTildeInCWD(); } const char *FileAccess::ExpandTildeStatic(const char *s) const { if(!home || !(s[0]=='~' && (s[1]=='/' || s[1]==0))) return s; static xstring buf; buf.set(s); expand_tilde(buf,home); return buf; } static inline bool last_element_is_doubledot(const char *path,const char *end) { return((end==path+2 && !strncmp(path,"..",2)) || (end>path+2 && !strncmp(end-3,"/..",3))); } int FileAccess::device_prefix_len(const char *path) const { ResValue dp=Query("device-prefix",hostname); if(dp.is_nil() || !dp.to_bool()) return 0; int i=0; while(path[i] && (is_ascii_alnum(path[i]) || strchr("$_-",path[i]))) i++; if(i>0 && path[i]==':') return i+1+(path[i+1]=='/'); return 0; } void FileAccess::Path::Optimize(xstring& path,int device_prefix_len) { int prefix_size=0; if(path[0]=='/' && path[1]=='~' && device_prefix_len==1) { prefix_size=2; while(path[prefix_size]!='/' && path[prefix_size]!='\0') prefix_size++; } else if(path[0]=='/') { prefix_size=1; if(path[1]=='/' && (!path[2] || path[2]!='/')) prefix_size=2; } else if(path[0]=='~') { prefix_size=1; while(path[prefix_size]!='/' && path[prefix_size]!='\0') prefix_size++; } else { // handle VMS and DOS devices. prefix_size=device_prefix_len; } char *in; char *out; in=out=path.get_non_const()+prefix_size; while((in[0]=='.' && (in[1]=='/' || in[1]==0)) || (in>path && in[-1]=='/' && (in[0]=='/' || (in[0]=='.' && in[1]=='.' && (in[2]=='/' || in[2]==0))))) { if(in[0]=='.' && in[1]=='.') in++; in++; if(*in=='/') in++; } while(*in) { if(in[0]=='/') { // double slash if(in[1]=='/') { in++; continue; } if(in[1]=='.') { // . - cur dir if(in[2]=='/' || in[2]=='\0') { in+=2; continue; } // .. - prev dir if(in[2]=='.' && (in[3]=='/' || in[3]=='\0')) { if(last_element_is_doubledot(path+prefix_size,out) || out==path || (out==path+prefix_size && out[-1]!='/')) { if(out>path && out[-1]!='/') *out++='/'; *out++='.'; *out++='.'; } else { while(out>path+prefix_size && *--out!='/') ; } in+=3; continue; } } // don't add slash after prefix with slash if(out>path && out[-1]=='/') { in++; continue; } } *out++=*in++; } path.truncate(path.length()-(in-out)); } void FileAccess::Chdir(const char *path,bool verify) { cwd.ExpandTilde(home); Close(); new_cwd=new Path(&cwd); new_cwd->Change(path,false); if(verify) Open(new_cwd->path,CHANGE_DIR); else { cwd.Set(new_cwd); new_cwd=0; } } void FileAccess::PathVerify(const Path &p) { Close(); new_cwd=new Path(p); Open(new_cwd->path,CHANGE_DIR); } void FileAccess::Chmod(const char *file,int m) { chmod_mode=m; Open(file,CHANGE_MODE); } void FileAccess::SetError(int ec,const char *e) { if(ec==SEE_ERRNO && !saved_errno) saved_errno=errno; if(ec==NO_FILE && file && file[0] && !strstr(e,file)) error.vset(e," (",file.get(),")",NULL); else error.set(e); error_code=ec; } void FileAccess::ClearError() { saved_errno=0; error_code=OK; error.set(0); } void FileAccess::Fatal(const char *e) { SetError(FATAL,e); } void FileAccess::SetSuggestedFileName(const char *fn) { suggested_filename.set(0); if(fn==0) return; // don't allow subdirectories. if(strchr(fn,'/') || strchr(fn,'\\') || strchr(fn,':')) return; for(int i=0; fn[i]; i++) { // don't allow control chars. if(iscntrl((unsigned char)fn[i])) return; } if(!*fn || *fn=='.') return; suggested_filename.set(fn); } void FileAccess::SetFileURL(const char *u) { file_url.set(u); if(new_cwd && mode==CHANGE_DIR) new_cwd->SetURL(u); } FileAccess *SessionPool::pool[pool_size]; void SessionPool::Reuse(FileAccess *f) { if(f==0) return; if(f->GetHostName()==0) { SMTask::Delete(f); return; } f->Close(); f->SetPriority(0); int i; for(i=0; iIsBetterThan(pool[i])) { SMTask::Delete(pool[i]); pool[i]=f; return; } } SMTask::Delete(f); } void SessionPool::Print(FILE *f) { int arr[pool_size]; int n=0; int i; for(i=0; iSameLocationAs(pool[i])) break; if(j==n) arr[n++]=i; } // sort? for(i=0; iGetConnectURL().get()); } FileAccess *SessionPool::GetSession(int n) { if(n<0 || n>=pool_size) return 0; FileAccess *s=pool[n]; pool[n]=0; return s; } FileAccess *SessionPool::Walk(int *n,const char *proto) { for( ; *nGetProto(),proto)) return pool[*n]; } return 0; } void SessionPool::ClearAll() { int pass=0; for(;;) { int left=0; for(int n=0; nDisconnect(); if(!pool[n]->IsConnected()) { SMTask::Delete(pool[n]); pool[n]=0; } else { left++; } } if(left==0) break; SMTask::Schedule(); SMTask::Block(); pass++; } } void FileAccess::SetTryTime(time_t t) { if(t) reconnect_timer.Reset(Time(t)); else reconnect_timer.Stop(); } bool FileAccess::IsBetterThan(const FileAccess *fa) const { return(SameProtoAs(fa) && this->IsConnected() > fa->IsConnected()); } void FileAccess::Reconfig(const char *) {} void FileAccess::ConnectVerify() { mode=CONNECT_VERIFY; } const char *FileAccess::CurrentStatus() { return ""; } int FileAccess::Buffered() { return 0; } bool FileAccess::IOReady() { return IsOpen(); } int FileAccess::IsConnected() const { return 0; } void FileAccess::UseCache(bool) {} bool FileAccess::NeedSizeDateBeforehand() { return false; } void FileAccess::Cleanup() {} void FileAccess::CleanupThis() {} ListInfo *FileAccess::MakeListInfo(const char *path) { return 0; } Glob *FileAccess::MakeGlob(const char *pattern) { return new NoGlob(pattern); } DirList *FileAccess::MakeDirList(ArgV *a) { delete a; return 0; } void FileAccess::CleanupAll() { xlist_for_each(FileAccess,all_fa,node,o) { Enter(o); o->CleanupThis(); Leave(o); } } FileAccess *FileAccess::NextSameSite(FA *scan) const { if(scan==0) scan=all_fa.first_obj(); else scan=scan->all_fa_node.next_obj(); for( ; scan; scan=scan->all_fa_node.next_obj()) if(scan!=this && SameSiteAs(scan)) return scan; return 0; } FileAccess *FileAccess::New(const char *proto,const char *host,const char *port) { ClassInit(); if(proto==0) proto="file"; if(!strcmp(proto,"slot")) { const FA *session=ConnectionSlot::FindSession(host); return session?session->Clone():0; } FA *session=Protocol::NewSession(proto); if(!session) return 0; const char *n_proto=session->ProtocolSubstitution(host); if(n_proto && strcmp(n_proto,proto)) { FA *n_session=Protocol::NewSession(n_proto); if(n_session) { Delete(session); session=n_session; session->SetVisualProto(proto); } } if(host) session->Connect(host,port); return session; } FileAccess *FileAccess::New(const ParsedURL *u,bool dummy) { const char *proto=u->proto?u->proto.get():"file"; FileAccess *s=New(proto,u->host); if(!s) { if(!dummy) return 0; return new DummyNoProto(proto); } if(strcmp(proto,"slot")) s->Connect(u->host,u->port); if(u->user) s->Login(u->user,u->pass); // path? return s; } FileAccess *FileAccess::GetNewLocationFA() const { if(!location) return 0; ParsedURL url(location,true); if(!url.proto) return 0; return FileAccess::New(&url,true); } // FileAccess::Protocol implementation xmap_p FileAccess::Protocol::proto_by_name; FileAccess::Protocol::Protocol(const char *proto, SessionCreator *creator) { this->proto=proto; this->New=creator; proto_by_name.add(proto,this); } FileAccess::Protocol *FileAccess::Protocol::FindProto(const char *proto) { return proto_by_name.lookup(proto); } FileAccess *FileAccess::Protocol::NewSession(const char *proto) { Protocol *p; p=FindProto(proto); if(p) return p->New(); #ifdef WITH_MODULES #define PROTO_PREFIX "proto-" const char *mod=xstring::cat(PROTO_PREFIX,proto,NULL); void *map=module_load(mod,0,0); if(map==0) { fprintf(stderr,"%s\n",module_error_message()); return 0; } p=FindProto(proto); if(p) return p->New(); #endif return 0; } // FileAccessOperation implementation void FileAccessOperation::SetError(const char *e) { error_text.set(e); done=true; } void FileAccessOperation::SetErrorCached(const char *e) { SetError(e); error_text.append(_(" [cached]")); } DirList::DirList(FileAccess *s,ArgV *a) : FileAccessOperation(s), buf(new Buffer()), args(a), color(false) { } DirList::~DirList() { } // ListInfo implementation ListInfo::ListInfo(FileAccess *s,const char *p) : FileAccessOperation(s), exclude_prefix(0), exclude(0), need(0), follow_symlinks(false), try_recursive(false), is_recursive(false) { if(session && p) { saved_cwd=session->GetCwd(); session->Chdir(p,false); } } void ListInfo::PrepareToDie() { if(session) session->Close(); if(session && saved_cwd) session->SetCwd(saved_cwd); } ListInfo::~ListInfo() {} // Path implementation void FileAccess::Path::init() { device_prefix_len=0; is_file=false; } FileAccess::Path::~Path() { } void FileAccess::Path::Set(const char *new_path,bool new_is_file,const char *new_url,int new_device_prefix_len) { path.set(new_path); is_file=new_is_file; url.set(new_url); device_prefix_len=new_device_prefix_len; } void FileAccess::Path::Set(const Path *o) { Set(o->path,o->is_file,o->url,o->device_prefix_len); } void FileAccess::Path::Change(const char *new_path,bool new_is_file,const char *new_path_enc,int new_device_prefix_len) { if(!new_path && new_path_enc) new_path=url::decode(new_path_enc); if(!new_path || !*new_path) return; const char *bn=basename_ptr(new_path); if(!strcmp(bn,".") || !strcmp(bn,"..")) new_is_file=false; int path_index=0; if(url) { path_index=url::path_index(url); xstring new_url_path(url+path_index); if(is_file) { dirname_modify(new_url_path); if(!new_url_path[0]) new_url_path.set("/~"); } if(new_url_path.last_char()!='/') new_url_path.append('/'); if(new_path[0]=='/' || new_path[0]=='~' || new_device_prefix_len!=0) { bool have_slash=((new_path_enc?new_path_enc:new_path)[0]=='/'); new_url_path.set(have_slash?"":"/"); } if(new_path_enc) new_url_path.append(new_path_enc); else new_url_path.append(url::encode(new_path,URL_PATH_UNSAFE)); if(!new_is_file && url::dir_needs_trailing_slash(url) && new_url_path.last_char()!='/') new_url_path.append('/'); Optimize(new_url_path,!strncmp(new_url_path,"/~",2)); url.truncate(path_index); url.append(new_url_path); } if(new_path[0]!='/' && new_path[0]!='~' && new_device_prefix_len==0 && path && path[0]) { if(is_file) { dirname_modify(path); if(!path[0]) path.set("~"); } if(last_char(path)=='/') new_path=xstring::format("%s%s",path.get(),new_path); else new_path=xstring::format("%s/%s",path.get(),new_path); } path.set(new_path); device_prefix_len=new_device_prefix_len; Optimize(); strip_trailing_slashes(path); is_file=new_is_file; if(!strcmp(path,"/") || !strcmp(path,"//")) is_file=false; // sanity check if(url) { ParsedURL u(url); if(u.path.length()>1) u.path.chomp('/'); if(!u.path.eq(path)) { LogError(0,"URL mismatch %s [%s] vs %s, dropping URL\n",url.get(),u.path.get(),path.get()); url.set(0); } } } bool FileAccess::Path::operator==(const Path &p2) const { const Path &p1=*this; if(p1.is_file!=p2.is_file) return false; if(xstrcmp(p1.path,p2.path)) return false; if(xstrcmp(p1.url,p2.url)) return false; return true; } void FileAccess::Path::ExpandTilde(const Path &home) { if(!home.path) return; if(path && path[0]=='~' && (path[1]=='/' || path[1]=='\0')) { device_prefix_len=home.device_prefix_len; if(path[1]=='\0') is_file=home.is_file; } if(url) { int pi=url::path_index(url); if(url[pi]=='/' && url[pi+1]=='~') pi++; expand_tilde(url,home.url?home.url.get():url::encode(home.path,URL_PATH_UNSAFE).get(),pi); } expand_tilde(path,home.path); } #include "DirColors.h" #include "LocalDir.h" #include "FileCopy.h" #include "modconfig.h" #ifndef MODULE_PROTO_FTP # include "ftpclass.h" # define _ftp Ftp::ClassInit() #else # define _ftp #endif #ifndef MODULE_PROTO_FILE # include "LocalAccess.h" # define _file LocalAccess::ClassInit() #else # define _file #endif #ifndef MODULE_PROTO_HTTP # include "Http.h" # define _http Http::ClassInit() #else # define _http #endif #ifndef MODULE_PROTO_FISH # include "Fish.h" # define _fish Fish::ClassInit() #else # define _fish #endif #ifndef MODULE_PROTO_SFTP # include "SFtp.h" # define _sftp SFtp::ClassInit() #else # define _sftp #endif bool FileAccess::class_inited; LsCache *FileAccess::cache; void FileAccess::ClassInit() { if(class_inited) return; class_inited=true; cache=new LsCache(); SignalHook::ClassInit(); ResMgr::ClassInit(); if(!Log::global) Log::global=new Log("debug"); _ftp; _file; _http; _fish; _sftp; // make it link in classes required by modules. LocalDirectory ld; } void FileAccess::ClassCleanup() { Protocol::ClassCleanup(); call_dynamic_hook("lftp_network_cleanup"); DirColors::DeleteInstance(); delete cache; cache=0; FileCopy::fxp_create=0; } const FileAccessRef& FileAccessRef::operator=(FileAccess *p) { reuse(); ptr=SMTask::MakeRef(p); return *this; } // hook-up gnulib... CDECL_BEGIN #include "md5.h" #include "glob.h" CDECL_END void *_md5_hook=(void*)md5_init_ctx; void *_glob_hook=(void*)glob; lftp-4.9.2/src/plural.c0000644000015000007670000000740312717275037011665 00000000000000/* * plural word form chooser for i18n * * Copyright (c) 1998,2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This file is in public domain. */ /* * This file provides a function to transform a string with all plural forms * of a word to a string with concrete form depending on a number. * It uses a rule encoded in special string. */ /* TODO: * allow to select number of argument */ #include #include #include #include #include #include "plural.h" static int choose_plural_form(const char *rule,int num) { int res=0; int match=1; int n=num; char c; int arg,arg_len; for(;;) { switch(c=*rule) { case '=': case '!': case '>': case '<': case '%': if(sscanf(rule+1,"%d%n",&arg,&arg_len)<1) return -1; rule+=arg_len; if(c=='%') n%=arg; if((c=='=' && !(n==arg)) || (c=='!' && !(n!=arg)) || (c=='>' && !(n> arg)) || (c=='<' && !(n< arg))) match=0; break; case '|': case ' ': case '\0': if(match) return res; if(c=='\0') return res+1; if(c=='|') match=1; if(c==' ') /* next rule */ { n=num; res++; match=1; } break; } rule++; } /* return res;*/ } /* * The function takes _untranslated_ string with $form1|form2|form3...$ * inserts, and a list of integer numbers. It uses gettext on the string. * Using "translated" rule and the list of numbers it choose appropriate * plural forms. * * If the string or the rule cannot be translated, it uses untranslated * string and default (english) rule. * * Returns pointer to static storage, copy if needed. */ const char *plural(const char *format,...) { static char *res=0; static size_t res_size=0; /* This is the rule for plural form choice (last condition can be omitted) */ /* Operators: = > < ! | % */ const char *rule=N_("=1 =0|>1"); const char *s; char *store; int index,plural_index; const char *new_format=gettext(format); const char *new_rule=gettext(rule); va_list va; long arg; va_start(va,format); if(new_format!=format && new_rule!=rule) /* there is translation */ { rule=new_rule; /* use "translated" rule */ format=new_format; /* and translated format */ } if(res==0) res=malloc(res_size=256); if(res==0) goto va_end_out; store=res; for(s=format; *s; s++) { #define ALLOCATE \ if(store-res+1>=res_size) \ { \ int dif=store-res; \ res=realloc(res,res_size*=2); \ if(res==0) \ goto va_end_out; \ store=res+dif; \ } /* end ALLOCATE */ if(*s=='$' && s[1]) { s++; if(*s=='$') goto plain; /* check options */ if(*s=='#') { s++; if(*s=='l') /* long */ { s++; if(*s=='l') /* long long */ { s++; arg=va_arg(va,long long)%1000000; } else arg=va_arg(va,long); } else { arg=va_arg(va,int); } if(*s=='#') /* end of options */ s++; } else { arg=va_arg(va,int); } if(arg<0) arg=-arg; plural_index=choose_plural_form(rule,arg); index=0; while(index!=plural_index) { /* skip plural form */ while(*s!='$' && *s!='|' && *s) s++; if(*s==0) goto out; if(*s=='$') break; s++; index++; } if(index==plural_index) { /* insert the form */ while(*s!='$' && *s!='|' && *s) { ALLOCATE; *store++=*s++; } while(*s!='$' && *s) s++; if(*s==0) goto out; } } else { plain: ALLOCATE; *store++=*s; } } out: ALLOCATE; *store=0; va_end_out: va_end(va); return res; } lftp-4.9.2/src/StringSet.cc0000644000015000007670000000423612122060713012433 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "StringSet.h" #include "misc.h" #define set_size set.count() StringSet::StringSet() {} StringSet::StringSet(const char *const *s,int n) { Assign(s,n); } StringSet::StringSet(const StringSet &o) { Assign(o.set.get(),o.set.count()); } StringSet::StringSet(const char *s) { Assign(&s,1); } bool StringSet::IsEqual(const char *const *set1,int n1) const { if(set_size!=n1) return false; int i=0; while(i0) set.append(xstrdup(*set1++)); } void StringSet::Append(const char *s) { if(!s) return; set.append(xstrdup(s)); } void StringSet::Replace(int i,const char *s) { if(i==set_size) Append(s); else if(i>=0 && i=set_size) return 0; char *s=set[i]; set[i]=0; set.remove(i); return s; } lftp-4.9.2/src/SSH_Access.h0000644000015000007670000000347413062512164012302 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SSH_ACCESS_H #define SSH_ACCESS_H #include "NetAccess.h" #include "PtyShell.h" class SSH_Access : public NetAccess { protected: SMTaskRef pty_send_buf; SMTaskRef pty_recv_buf; SMTaskRef send_buf; SMTaskRef recv_buf; Ref ssh; int password_sent; const char *greeting; bool received_greeting; bool hostname_valid; xstring last_ssh_message; time_t last_ssh_message_time; void MoveConnectionHere(SSH_Access *o); void DisconnectLL(); void MakePtyBuffers(); int HandleSSHMessage(); void LogSSHMessage(); /* it's called after the greeting is received * (or internally from HandleSSHMessage). */ SSH_Access(const char *g) : password_sent(0), greeting(g), received_greeting(false), hostname_valid(false), last_ssh_message_time(0) {} SSH_Access(const SSH_Access *o) : NetAccess(o), password_sent(0), greeting(o->greeting), received_greeting(false), hostname_valid(o->hostname_valid), last_ssh_message_time(0) {} }; #endif lftp-4.9.2/src/FtpListInfo.h0000644000015000007670000000213312122057737012562 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef FTPLISTINFO_H #define FTPLISTINFO_H #include "NetAccess.h" class FtpListInfo : public GenericParseListInfo { FileSet *ParseShortList(const char *buf,int len); public: virtual FileSet *Parse(const char *buf,int len); FtpListInfo(FileAccess *session,const char *path) : GenericParseListInfo(session,path) {} }; #endif//FTPLISTINFO_H lftp-4.9.2/src/ProtoLog.h0000644000015000007670000000360613062512164012126 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PROTOLOG_H #define PROTOLOG_H #include "xstring.h" class ProtoLog { static bool WillOutput(int level); struct Tags : public ResClient { const char *recv; const char *send; const char *note; const char *error; void Reconfig(const char *n) { if(n && strncmp(n,"log:prefix-",11)) return; recv=Query("log:prefix-recv",0); send=Query("log:prefix-send",0); note=Query("log:prefix-note",0); error=Query("log:prefix-error",0); } }; static Tags *tags; static void init_tags(); public: static void Log2(int level,xstring& str); static void Log3(int level,const char *prefix,const char *str); static void LogVF(int level,const char *prefix,const char *fmt,va_list v); static void LogError(int level,const char *fmt,...) PRINTF_LIKE(2,3); static void LogNote(int level,const char *fmt,...) PRINTF_LIKE(2,3); static void LogRecv(int level,const char *line); static void LogSend(int level,const char *line); static void LogRecvF(int level,const char *fmt,...) PRINTF_LIKE(2,3); static void LogSendF(int level,const char *fmt,...) PRINTF_LIKE(2,3); }; #endif//PROTOLOG_H lftp-4.9.2/src/HttpDirXML.cc0000644000015000007670000001355512717275037012475 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "HttpDir.h" #include "log.h" #include "url.h" #include "misc.h" #if USE_EXPAT #include struct xml_context { xarray_s stack; Ref fs; Ref fi; xstring base_dir; xstring chardata; void push(const char *); void pop(); void process_chardata(); void set_base_dir(const char *d) { base_dir.set(d); if(base_dir.length()>1) base_dir.chomp('/'); } const xstring_c& top(int i=0) const { return stack.count()>i ? stack[stack.count()-i-1] : xstring_c::null; } bool in(const char *tag) const { return top().eq(tag); } bool in(const char *tag0,const char *tag1) const { return top(0).eq(tag0) && top(1).eq(tag1); } bool has_chardata() const { return chardata.length()>0; } void log_tag(const char *end="") const { const char *tag=top(); Log::global->Format(10,"XML: %*s<%s%s>\n",stack.length()*2,"",end,tag); } void log_tag_end() const { log_tag("/"); } void log_data() const { Log::global->Format(10,"XML: %*s`%s'\n",stack.length()*2+2,"",chardata.get()); } }; void xml_context::push(const char *s) { stack.append(s); log_tag(); if(in("DAV:response")) { delete fi; fi=new FileInfo; } else if(in("DAV:collection")) { fi->SetType(fi->DIRECTORY); fi->SetMode(0755); } chardata.truncate(); } void xml_context::pop() { if(has_chardata()) process_chardata(); if(in("DAV:response")) { if(fi && fi->name) { if(!fs) fs=new FileSet; fs->Add(fi.borrow()); } } log_tag_end(); stack.chop(); } void xml_context::process_chardata() { log_data(); if(in("DAV:href","DAV:response")) { ParsedURL u(chardata,true); xstring& s=u.path; bool is_directory=false; if(s.last_char()=='/') { is_directory=true; s.chomp('/'); fi->SetType(fi->DIRECTORY); fi->SetMode(0755); } else { fi->SetType(fi->NORMAL); fi->SetMode(0644); } if(s.begins_with("/~")) s.set_substr(0,1,0,0); fi->SetName(base_dir.eq(s) && is_directory ? "." : basename_ptr(s)); } else if(in("DAV:getcontentlength")) { long long size_ll=0; if(sscanf(chardata,"%lld",&size_ll)==1) fi->SetSize(size_ll); } else if(in("DAV:getlastmodified")) { time_t tm=Http::atotm(chardata); if(tm!=Http::ATOTM_ERROR) fi->SetDate(tm,0); } else if(in("DAV:creator-displayname")) { fi->SetUser(chardata); } else if(in("http://apache.org/dav/props/executable")) { if(chardata[0]=='T') fi->SetMode(0755); else if(chardata[0]=='F') fi->SetMode(0644); } } static void start_handle(void *data, const char *el, const char **attr) { xml_context *ctx=(xml_context*)data; ctx->push(el); } static void end_handle(void *data, const char *el) { xml_context *ctx=(xml_context*)data; ctx->pop(); } static void chardata_handle(void *data, const char *chardata, int len) { xml_context *ctx=(xml_context*)data; if(!ctx->fi) return; ctx->chardata.append(chardata,len); } FileSet *HttpListInfo::ParseProps(const char *b,int len,const char *base_dir) { XML_Parser p = XML_ParserCreateNS(0,0); if(!p) return 0; xml_context ctx; ctx.set_base_dir(base_dir); XML_SetUserData(p,&ctx); XML_SetElementHandler(p, start_handle, end_handle); XML_SetCharacterDataHandler(p, chardata_handle); if(!XML_Parse(p, b, len, /*eof*/1)) { Log::global->Format(0, "XML Parse error at line %d: %s\n", (int)XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p))); XML_ParserFree(p); return 0; } XML_ParserFree(p); return ctx.fs.borrow(); } void HttpDirList::ParsePropsFormat(const char *b,int len,bool eof) { if(len==0) goto end; if(!xml_p) { xml_p=XML_ParserCreateNS(0,0); xml_ctx=new xml_context; xml_ctx->set_base_dir(curr_url->path); XML_SetUserData(xml_p,xml_ctx); XML_SetElementHandler(xml_p, start_handle, end_handle); XML_SetCharacterDataHandler(xml_p, chardata_handle); } if(!XML_Parse(xml_p, b, len, eof)) { Log::global->Format(0, "XML Parse error at line %d: %s\n", (int)XML_GetCurrentLineNumber(xml_p), XML_ErrorString(XML_GetErrorCode(xml_p))); parse_as_html=true; return; } if(!xml_ctx->fs) goto end; xml_ctx->fs->rewind(); for(;;) { FileInfo *info=xml_ctx->fs->curr(); if(!info) break; info->MakeLongName(); buf->Put(info->longname); if(ls_options.append_type) { if(info->filetype==info->DIRECTORY) buf->Put("/"); else if(info->filetype==info->SYMLINK && !info->symlink) buf->Put("@"); } buf->Put("\n"); xml_ctx->fs->next(); } xml_ctx->fs->Empty(); end: if(eof && xml_p) { XML_ParserFree(xml_p); xml_p=0; delete xml_ctx; xml_ctx=0; } } #else // !USE_EXPAT FileSet *HttpListInfo::ParseProps(const char *b,int len,const char *base_dir) { return 0; } void HttpDirList::ParsePropsFormat(const char *b,int len,bool eof) {} #endif // !USE_EXPAT lftp-4.9.2/src/FileSetOutput.h0000644000015000007670000000642613062512164013140 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef FILESETOUTPUT_H #define FILESETOUTPUT_H #include "FileSet.h" #include "buffer.h" #include "keyvalue.h" #include "FileCopy.h" #include "GetFileInfo.h" #include "CopyJob.h" #include "OutputJob.h" #include "Job.h" class StatusLine; class FileSetOutput { const char *FileInfoSuffix(const FileInfo &fi) const; public: bool classify; // add / (dir) @ (link) // TODO: extra-optional * for exec? maybe not, some servers stick +x on everything int width; // width to output, 0 to force one column bool color; enum { NONE=0, PERMS = 0x1, SIZE = 0x2, DATE = 0x4, LINKS = 0x8, USER = 0x10, GROUP = 0x20, NLINKS = 0x40, ALL=PERMS|SIZE|DATE|LINKS|USER|GROUP|NLINKS }; int mode; xstring_c pat; xstring_c time_fmt; bool basenames; bool showdots; bool quiet; bool patterns_casefold; bool sort_casefold; bool sort_reverse; bool sort_dirs_first; bool size_filesonly; bool single_column; bool list_directories; bool need_exact_time; int output_block_size; int human_opts; FileSet::sort_e sort; FileSetOutput(): classify(0), width(0), color(false), mode(NONE), basenames(false), showdots(false), quiet(false), patterns_casefold(false), sort_casefold(false), sort_reverse(false), sort_dirs_first(false), size_filesonly(false), single_column(false), list_directories(false), need_exact_time(false), output_block_size(0), human_opts(0), sort(FileSet::BYNAME) { } void long_list(); void config(const OutputJob *fd); const char *parse_argv(const Ref& a); const char *parse_res(const char *res); static const char *ValidateArgv(xstring_c *s); int Need() const; void print(FileSet &fs, const JobRef& o) const; }; /* Job interface to FileSetOutput */ class clsJob : public SessionJob { JobRef output; Ref fso; Ref args; SMTaskRef list_info; xstring_c dir; xstring_c mask; bool done; bool use_cache; bool error; enum { INIT, START_LISTING, GETTING_LIST_INFO, DONE } state; public: clsJob(FA *s, ArgV *a, FileSetOutput *_opts, OutputJob *output); int Done(); int Do(); void UseCache(bool y=true) { use_cache=y; } void Fg() { session->SetPriority(1); output->Fg(); } void Bg() { session->SetPriority(0); output->Bg(); } void SuspendInternal(); void ResumeInternal(); int ExitCode() { return error||output->Error() ? 1 : 0; } void ShowRunStatus(const SMTaskRef&); xstring& FormatStatus(xstring&,int v,const char *); }; #endif lftp-4.9.2/src/xmalloc.h0000644000015000007670000000273312717275037012033 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XMALLOC_H #define XMALLOC_H #include #ifdef DBMALLOC #include "dbmalloc.h" #endif void *xmalloc(size_t); void *xrealloc(void *,size_t); char *xstrdup(const char *s,int spare=0); char *xstrset(char *&mem,const char *s); char *xstrset(char *&mem,const char *s,size_t n); #define alloca_strdup(s) alloca_strdup2((s),0) #define alloca_strdup2(s,n) (strcpy((char*)alloca(strlen((s))+1+(n)),(s))) #define alloca_append(s1,s2) strcat(alloca_strdup2((s1),strlen((s2))),(s2)); void xfree(void *p); void xmalloc_register_block(void *); #include "xstring.h" static inline void *xmemdup(const void *m,int len) { if(!m) return 0; void *buf=xmalloc(len); memcpy(buf,m,len); return buf; } #endif /* XMALLOC_H */ lftp-4.9.2/src/TreatFileJob.h0000644000015000007670000000275012122060755012672 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef TREATFILEJOB_H #define TREATFILEJOB_H #include "Job.h" #include "FindJob.h" class StatusLine; class ArgV; class TreatFileJob : public FinderJob { protected: Ref args; const FileInfo *curr; Ref first; int failed,file_count; virtual void TreatCurrent(const char *d,const FileInfo *fi) = 0; virtual void CurrentFinished(const char *d,const FileInfo *fi) { } void Begin(const char *d); /* virtuals */ void Finish(); prf_res ProcessFile(const char *d,const FileInfo *fi); public: xstring& FormatStatus(xstring&,int,const char *); void ShowRunStatus(const SMTaskRef&); TreatFileJob(FileAccess *session,ArgV *a); virtual ~TreatFileJob(); }; #endif // TREATFILEJOB_H lftp-4.9.2/src/PollVec.h0000644000015000007670000000360012662070340011717 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef POLLVEC_H #define POLLVEC_H #include #include #include #include CDECL_BEGIN #include CDECL_END class PollVec { fd_set in; fd_set out; fd_set in_polled; fd_set out_polled; fd_set in_ready; fd_set out_ready; int nfds; struct timeval tv_timeout; public: PollVec() { Empty(); FD_ZERO(&in_polled); FD_ZERO(&out_polled); FD_ZERO(&in_ready); FD_ZERO(&out_ready); } void Empty() { FD_ZERO(&in); FD_ZERO(&out); nfds=0; tv_timeout.tv_sec=-1; tv_timeout.tv_usec=0; } void Block(); enum { IN=1, OUT=4, }; void SetTimeout(const timeval &t) { tv_timeout=t; } void SetTimeoutU(unsigned t) { tv_timeout.tv_sec=t/1000000; tv_timeout.tv_usec=t%1000000; } void AddTimeoutU(unsigned t); void AddFD(int fd,int events); bool FDReady(int fd,int events); void FDSetNotReady(int fd,int events); void NoWait() { tv_timeout.tv_sec=tv_timeout.tv_usec=0; } bool WillNotBlock() { return tv_timeout.tv_sec==0 && tv_timeout.tv_usec==0; } }; #endif /* POLLVEC_H */ lftp-4.9.2/src/xarray.cc0000644000015000007670000000464212662070341012027 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "xarray.h" void xarray0::get_space_do(size_t s,size_t g) { if(!buf) buf=xmalloc(element_size*(size=s+keep_extra)); else if(size=g*8 && s+keep_extra<=size/2) buf=xrealloc(buf,element_size*(size/=2)); } void xarray0::_nset(const void *s,int len) { if(!s) { xfree(buf); init(); return; } this->len=len; if(s==buf) return; if(s>buf && s<(char*)buf+size*element_size) { memmove(buf,s,len*element_size); return; } get_space(len); memcpy(buf,s,len*element_size); } void *xarray0::_insert(int before) { assert(before>=0 && before<=len); grow_space(len+1); if(before=0 && j<=len); if(j0) lo=m+1; else { *pos=m; return true; } } *pos=lo; return false; } void *xarray0::_insert_ordered(const void *n,qsort_cmp_t cmp) { int pos; (void)_bsearch(n,cmp,&pos); return _insert(pos); } lftp-4.9.2/src/echoJob.cc0000644000015000007670000000361212122057326012065 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "echoJob.h" #include "misc.h" #define super Job echoJob::echoJob(const char *buf, int len, OutputJob *_output) : output(_output) { AddWaiting(_output); output->Put(buf, len); output->PutEOF(); } echoJob::echoJob(const char *buf, OutputJob *_output) : output(_output) { AddWaiting(_output); output->Put(buf); output->PutEOF(); } echoJob::~echoJob() { } int echoJob::Done() { return output->Done(); } int echoJob::ExitCode() { /* if the output fails, we failed */ return output->Error()? 1:0; } /* We have no interesting status for "jobs", so we have no PrintStatus * override. (The output job will print the output status, if relevant.) */ void echoJob::ShowRunStatus(const SMTaskRef& s) { if(Done()) return; /* Never call output->ShowStatusLine unless we're really going * to display something. */ const char *stat = output->Status(s); if(*stat && output->ShowStatusLine(s)) s->Show("echo: %s", stat); } void echoJob::Fg() { super::Fg(); if(output) output->Fg(); } void echoJob::Bg() { if(output) output->Bg(); super::Bg(); } lftp-4.9.2/src/buffer.cc0000644000015000007670000004342613032222567011776 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "buffer.h" #include "FileAccess.h" #include "misc.h" #include "trio.h" #include "Speedometer.h" #include "log.h" #define BUFFER_INC (8*1024) // should be power of 2 const char *Buffer::Get() const { if(Size()==0) return eof?0:""; return buffer+buffer_ptr; } void Buffer::Get(const char **buf,int *size) const { *size=Size(); *buf=Get(); } void Buffer::GetSaved(const char **buf,int *size) const { if(!save) { *size=0; *buf=0; return; } *buf=buffer; *size=buffer.length(); } void Buffer::SaveRollback(off_t p) { pos=p; if(buffer_ptr0 && Size()==0 && !save) { buffer.truncate(0); buffer_ptr=0; } size_t in_buffer_real=Size(); /* disable data movement to beginning of the buffer, if: 1. we save the data explicitly; 2. we add more data than there is space in the beginning of the buffer (because the probability of realloc is high anyway); 3. the gap at beginning is smaller than the amount of data in the buffer (because the penalty of data movement is high). */ if(save || buffer_ptrin_buffer_real) { buffer.nset(buffer+buffer_ptr,Size()); buffer_ptr=0; } buffer.get_space2(in_buffer_real+size,BUFFER_INC); } void Buffer::SaveMaxCheck(int size) { if(save && buffer_ptr+size>save_max) save=false; } void Buffer::Append(const char *buf,int size) { if(size==0) return; SaveMaxCheck(size); if(Size()==0 && buffer_ptr>0 && !save) { buffer.truncate(0); buffer_ptr=0; } memmove(GetSpace(size),buf,size); SpaceAdd(size); } void Buffer::Put(const char *buf,int size) { Append(buf,size); pos+=size; } void Buffer::Prepend(const char *buf,int size) { if(size==0) return; save=false; if(Size()==0) { memmove(GetSpace(size),buf,size); SpaceAdd(size); return; } if(buffer_ptr=0 && ressize) // some vsnprintf's return desired buffer size. size=res+1; else size*=2; } } void Buffer::Skip(int len) { if(len>Size()) len=Size(); buffer_ptr+=len; pos+=len; } void Buffer::UnSkip(int len) { if(len>buffer_ptr) len=buffer_ptr; buffer_ptr-=len; pos-=len; } void Buffer::Empty() { buffer.truncate(0); buffer_ptr=0; if(save_max>0) save=true; } // move data from other buffer, prepare for SpaceAdd. int Buffer::MoveDataHere(Buffer *o,int max_len) { const char *b; int size; o->Get(&b,&size); if(size>max_len) size=max_len; if(size>0) { if(size>=64 && Size()==0 && o->Size()==size && !save && !o->save) { // optimization by swapping buffers buffer.swap(o->buffer); buffer_ptr=replace_value(o->buffer_ptr,buffer_ptr); buffer.set_length_no_z(buffer_ptr); o->pos+=size; } else { memcpy(GetSpace(size),b,size); o->Skip(size); } } return size; } Buffer::Buffer() { saved_errno=0; error_fatal=false; buffer_ptr=0; eof=false; broken=false; save=false; save_max=0; pos=0; } Buffer::~Buffer() { } const char *Buffer::GetRateStrS() { if(!rate || !rate->Valid()) return ""; return rate->GetStrS(); } void Buffer::RateAdd(int n) { if(!rate) return; rate->Add(n); } void Buffer::SetError(const char *e,bool fatal) { error_text.set(e); error_fatal=fatal; } void Buffer::SetErrorCached(const char *e) { SetError(e,false); error_text.append(_(" [cached]")); } const char *Buffer::Dump() const { if(buffer_ptr==0) return buffer.dump(); return xstring::get_tmp(Get(),Size()).dump(); } void DataTranslator::AppendTranslated(Buffer *target,const char *put_buf,int size) { off_t old_pos=target->GetPos(); PutTranslated(target,put_buf,size); target->SetPos(old_pos); } void DirectedBuffer::SetTranslator(DataTranslator *t) { if(mode==GET && !translator && Size()>0) { // translate unread data const char *data; int len; Get(&data,&len); t->Put(data,len); buffer.truncate(buffer_ptr); t->AppendTranslated(this,0,0); } translator=t; } #ifdef HAVE_ICONV void DataRecoder::PutTranslated(Buffer *target,const char *put_buf,int size) { bool from_untranslated=false; if(Size()>0) { Put(put_buf,size); Get(&put_buf,&size); from_untranslated=true; } if(size<=0) return; if(!backend_translate) { target->Put(put_buf,size); if(from_untranslated) Skip(size); return; } size_t put_size=size; int size_coeff=6; try_again: if(put_size==0) return; size_t store_size=size_coeff*put_size; char *store_space=target->GetSpace(store_size); char *store_buf=store_space; const char *base_buf=put_buf; // do the translation ICONV_CONST char **put_buf_ptr=const_cast(&put_buf); size_t res=iconv(backend_translate,put_buf_ptr,&put_size,&store_buf,&store_size); target->SpaceAdd(store_buf-store_space); if(from_untranslated) Skip(put_buf-base_buf); if(res==(size_t)-1) { switch(errno) { case EINVAL: // incomplete character if(!from_untranslated) Put(put_buf,put_size); break; case EILSEQ: // invalid character target->Put("?"); put_buf++; put_size--; goto try_again; case E2BIG: // no room to store result, allocate more. size_coeff*=2; goto try_again; default: break; } } return; } void DataRecoder::ResetTranslation() { Empty(); if(!backend_translate) return; iconv(backend_translate,0,0,0,0); } DataRecoder::~DataRecoder() { if(backend_translate) iconv_close(backend_translate); } DataRecoder::DataRecoder(const char *from_code,const char *to_code,bool translit) { backend_translate=0; if(translit) { const char *to_code_translit=xstring::cat(to_code,"//TRANSLIT",NULL); backend_translate=iconv_open(to_code_translit,from_code); if(backend_translate!=(iconv_t)-1) { Log::global->Format(9,"initialized translation from %s to %s\n",from_code,to_code_translit); return; } backend_translate=0; } backend_translate=iconv_open(to_code,from_code); if(backend_translate!=(iconv_t)-1) { Log::global->Format(9,"initialized translation from %s to %s\n",from_code,to_code); return; } Log::global->Format(0,"iconv_open(%s,%s) failed: %s\n", to_code,from_code,strerror(errno)); backend_translate=0; } void DirectedBuffer::SetTranslation(const char *enc,bool translit) { if(!enc || !*enc) return; const char *local_code=ResMgr::Query("file:charset",0); if(!local_code || !*local_code) return; const char *from_code=(mode==GET?enc:local_code); const char *to_code =(mode==GET?local_code:enc); if(!strcasecmp(from_code,to_code)) return; SetTranslator(new DataRecoder(from_code,to_code,translit)); } #endif //HAVE_ICONV void DirectedBuffer::ResetTranslation() { if(translator) translator->ResetTranslation(); } void DirectedBuffer::Put(const char *buf,int size) { if(mode==PUT && translator) translator->PutTranslated(this,buf,size); else Buffer::Put(buf,size); } void DirectedBuffer::PutTranslated(const char *buf,int size) { if(translator) translator->PutTranslated(this,buf,size); else Buffer::Put(buf,size); } int DirectedBuffer::MoveDataHere(Buffer *buf,int size) { if(size>buf->Size()) size=buf->Size(); if(mode==PUT && translator) translator->PutTranslated(this,buf->Get(),size); else return Buffer::MoveDataHere(buf,size); return size; } void DirectedBuffer::PutEOF() { if(mode==PUT && translator) translator->PutTranslated(this,0,0); Buffer::PutEOF(); } void DirectedBuffer::EmbraceNewData(int len) { if(len<=0) return; RateAdd(len); if(translator) { // copy the data to free room for translated data translator->Put(buffer+buffer.length(),len); translator->AppendTranslated(this,0,0); } else SpaceAdd(len); SaveMaxCheck(0); } IOBuffer::IOBuffer(dir_t m) : DirectedBuffer(m), event_time(now), max_buf(0), get_size(GET_BUFSIZE) { } IOBuffer::~IOBuffer() { } void IOBuffer::Put(const char *buf,int size) { if(size>=PUT_LL_MIN && Size()==0 && mode==PUT && !save && !translator) { int res=Put_LL(buf,size); if(res>=0) { buf+=res; size-=res; pos+=res; } } if(size<=0) return; if(Size()==0) current->Timeout(0); DirectedBuffer::Put(buf,size); } void IOBuffer::Put(const char *buf) { Put(buf,strlen(buf)); } int IOBuffer::TuneGetSize(int res) { if(res>0) { // buffer size tuning depending on data rate const int max_get_size=(max_buf?max_buf:0x100000); if(res>get_size/2 && Size()+get_size*2<=max_get_size) get_size*=2; } return res; } int IOBuffer::Do() { if(Done() || Error()) return STALL; int res=0; switch(mode) { case PUT: if(Size()==0) return STALL; res=Put_LL(buffer+buffer_ptr,Size()); if(res>0) { RateAdd(res); buffer_ptr+=res; event_time=now; if(eof) PutEOF_LL(); return MOVED; } break; case GET: if(eof) return STALL; res=TuneGetSize(Get_LL(get_size)); if(res>0) { EmbraceNewData(res); event_time=now; return MOVED; } if(eof) { event_time=now; return MOVED; } break; } if(res<0) { event_time=now; return MOVED; } return STALL; } // IOBufferStacked implementation #undef super #define super IOBuffer int IOBufferStacked::Do() { int m=STALL; if(Done() || Error()) return m; int res=0; switch(mode) { case PUT: if(down->Broken() && !broken) { broken=true; return MOVED; } if(down->Error()) { SetError(down->ErrorText(),down->ErrorFatal()); m=MOVED; } if(Size()==0) return m; res=Put_LL(buffer+buffer_ptr,Size()); if(res>0) { buffer_ptr+=res; m=MOVED; } break; case GET: if(eof) return m; res=Get_LL(/*unused*/0); if(res>0) { EmbraceNewData(res); m=MOVED; } if(eof) m=MOVED; if(down->Error()) { SetError(down->ErrorText(),down->ErrorFatal()); m=MOVED; } break; } if(res<0) return MOVED; return m; } int IOBufferStacked::Put_LL(const char *buf,int size) { if(down->Broken()) { broken=true; return -1; } down->Put(buf,size); return size; } int IOBufferStacked::Get_LL(int) { if(max_buf && Size()>=max_buf) { down->SuspendSlave(); return 0; } down->ResumeSlave(); int size=MoveDataHere(down,down->Size()); if(down->Size()==0 && down->Eof()) PutEOF(); return size; } bool IOBufferStacked::Done() { if(super::Done()) return down->Done(); return false; } void IOBufferStacked::SuspendInternal() { super::SuspendInternal(); down->SuspendSlave(); } void IOBufferStacked::ResumeInternal() { if(!max_buf || Size()ResumeSlave(); super::ResumeInternal(); } // IOBufferFDStream implementation #include #include #undef super #define super IOBuffer int IOBufferFDStream::Put_LL(const char *buf,int size) { if(put_ll_timer && !eof && Size()Stopped()) return 0; if(stream->broken()) { broken=true; return -1; } int res=0; int fd=stream->getfd(); if(fd==-1) { if(stream->error()) goto stream_err; TimeoutS(1); event_time=now; return 0; } res=write(fd,buf,size); if(res==-1) { saved_errno=errno; if(E_RETRY(saved_errno)) { Block(fd,POLLOUT); return 0; } if(NonFatalError(saved_errno)) return 0; if(errno==EPIPE) { broken=true; return -1; } stream->MakeErrorText(saved_errno); goto stream_err; } if(put_ll_timer) put_ll_timer->Reset(); return res; stream_err: SetError(stream->error_text,!TemporaryNetworkError(saved_errno)); return -1; } int IOBufferFDStream::Get_LL(int size) { if(max_buf && Size()>=max_buf) return 0; int res=0; int fd=stream->getfd(); if(fd==-1) { if(stream->error()) goto stream_err; TimeoutS(1); return 0; } if(!Ready(fd,POLLIN)) { Block(fd,POLLIN); return 0; } res=read(fd,GetSpace(size),size); if(res==-1) { saved_errno=errno; if(E_RETRY(saved_errno)) { SetNotReady(fd,POLLIN); Block(fd,POLLIN); return 0; } if(NonFatalError(saved_errno)) return 0; stream->MakeErrorText(saved_errno); goto stream_err; } if(res==0) { Log::global->Format(10,"buffer: EOF on FD %d\n",fd); eof=true; } return res; stream_err: SetError(stream->error_text,!TemporaryNetworkError(saved_errno)); return -1; } FgData *IOBufferFDStream::GetFgData(bool fg) { if(stream->getfd()!=-1) return new FgData(stream->GetProcGroup(),fg); return 0; } bool IOBufferFDStream::Done() { if(put_ll_timer) put_ll_timer->Stop(); if(super::Done()) return stream->Done(); // stream->Done indicates if sub-process finished return false; } IOBufferFDStream::~IOBufferFDStream() {} // IOBufferFileAccess implementation #undef super #define super IOBuffer int IOBufferFileAccess::Get_LL(int size) { if(max_buf && Size()>=max_buf) { session->SuspendSlave(); return 0; } session->ResumeSlave(); int res=0; res=session->Read(this,size); if(res<0) { if(res==FA::DO_AGAIN) return 0; SetError(session->StrError(res)); return -1; } if(res==0) eof=true; return res; } void IOBufferFileAccess::SuspendInternal() { super::SuspendInternal(); session->SuspendSlave(); } void IOBufferFileAccess::ResumeInternal() { if(!max_buf || Size()ResumeSlave(); super::ResumeInternal(); } const char *IOBufferFileAccess::Status() { return session->CurrentStatus(); } unsigned long long Buffer::UnpackUINT64BE(int offset) const { if(Size()-offset<8) return 0; unsigned long long res=UnpackUINT32BE(offset); res=(res<<32)|UnpackUINT32BE(offset+4); return res; } long long Buffer::UnpackINT64BE(int offset) const { unsigned long long n=UnpackUINT64BE(offset); if(n&0x8000000000000000ULL) return -(long long)(n^0xFFFFFFFFFFFFFFFFULL)-1; return (long long)n; } unsigned Buffer::UnpackUINT32BE(int offset) const { if(Size()-offset<4) return 0; unsigned char *b=(unsigned char*)buffer.get()+buffer_ptr+offset; return (b[0]<<24)|(b[1]<<16)|(b[2]<<8)|b[3]; } int Buffer::UnpackINT32BE(int offset) const { unsigned n=UnpackUINT32BE(offset); if(n&0x80000000U) return -(int)(n^0xFFFFFFFFU)-1; return (int)n; } unsigned Buffer::UnpackUINT16BE(int offset) const { if(Size()-offset<2) return 0; unsigned char *b=(unsigned char*)buffer.get()+buffer_ptr+offset; return (b[0]<<8)|b[1]; } unsigned Buffer::UnpackUINT8(int offset) const { if(Size()-offset<1) return 0; unsigned char *b=(unsigned char*)buffer.get()+buffer_ptr+offset; return b[0]; } void Buffer::PackUINT64BE(unsigned long long data) { #ifndef NDEBUG Log::global->Format(11,"PackUINT64BE(0x%016llX)\n",data); #endif Allocate(8); PackUINT32BE((unsigned)(data>>32)); PackUINT32BE((unsigned)(data&0xFFFFFFFFU)); } void Buffer::PackINT64BE(long long data) { unsigned long long n; if(data<0) n=((unsigned long long)(-data)^0xFFFFFFFFFFFFFFFFULL)+1; else n=(unsigned long long)data; PackUINT64BE(n); } void Buffer::PackUINT32BE(unsigned data) { #ifndef NDEBUG Log::global->Format(11,"PackUINT32BE(0x%08X)\n",data); #endif char *b=GetSpace(4); b[0]=(data>>24)&255; b[1]=(data>>16)&255; b[2]=(data>>8)&255; b[3]=(data)&255; SpaceAdd(4); } void Buffer::PackINT32BE(int data) { unsigned n; if(data<0) n=((unsigned)(-data)^0xFFFFFFFFU)+1; else n=(unsigned)data; PackUINT32BE(n); } void Buffer::PackUINT16BE(unsigned data) { char *b=GetSpace(2); b[0]=(data>>8)&255; b[1]=(data)&255; SpaceAdd(2); } void Buffer::PackUINT8(unsigned data) { #ifndef NDEBUG Log::global->Format(11,"PackUINT8(0x%02X)\n",data); #endif char *b=GetSpace(1); b[0]=(data)&255; SpaceAdd(1); } lftp-4.9.2/src/Ref.h0000644000015000007670000000413312662070340011071 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef REF_H #define REF_H template class Ref { Ref(const Ref&); // disable cloning void operator=(const Ref&); // and assignment protected: T *ptr; public: Ref() { ptr=0; } Ref(T *p) { ptr=p; } ~Ref() { delete ptr; } void operator=(T *p) { delete ptr; ptr=p; } operator const T*() const { return ptr; } T *operator->() const { return ptr; } T *borrow() { return replace_value(ptr,(T*)0); } const T *get() const { return ptr; } T *get_non_const() const { return ptr; } template const Ref& Cast() const { void(static_cast(ptr)); return *(const Ref*)this; } static const Ref null; void _set(T *p) { ptr=p; } void _clear() { ptr=0; } void unset() { *this=0; } }; template const Ref Ref::null; template class RefToArray : public Ref { RefToArray(const RefToArray&); // disable cloning void operator=(const RefToArray&); // and assignment public: RefToArray() {} RefToArray(T *p) : Ref(p) {} ~RefToArray() { delete[] Ref::ptr; Ref::ptr=0; } void operator=(T *p) { delete[] Ref::ptr; Ref::ptr=p; } T& operator[](unsigned i) const { return Ref::ptr[i]; } static const RefToArray null; }; template const RefToArray RefToArray::null; #endif lftp-4.9.2/src/CatJob.cc0000644000015000007670000000500312122057145011651 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "trio.h" #include #include #include "CatJob.h" #include "ArgV.h" #include "FileCopyOutputJob.h" #define super CopyJobEnv int CatJob::ExitCode() { return errors!=0 || output->Error(); } int CatJob::Done() { return super::Done() && output->Done(); } int CatJob::Do() { int m=STALL; if(!done && output->Done()) { done=true; m=MOVED; } return m||super::Do(); } void CatJob::NextFile() { const char *src=args->getnext(); if(src==0) { SetCopier(0,0); output->PutEOF(); return; } FileCopyPeerFA *src_peer=FileCopyPeerFA::New(session,src,FA::RETRIEVE); FileCopyPeer *dst_peer=new FileCopyPeerOutputJob(output); FileCopy *copier=FileCopy::New(src_peer,dst_peer,false); copier->DontCopyDate(); if(ascii || (auto_ascii && output->IsTTY())) { if(output->IsStdout()) copier->LineBuffered(); copier->Ascii(); } SetCopier(copier,src); } CatJob::CatJob(FileAccess *new_session,OutputJob *_output,ArgV *new_args) : CopyJobEnv(new_session,new_args), output(_output) { output->SetParentFg(this); ascii=false; auto_ascii=true; output->DontRedisplayStatusbar(); if(!strcmp(op,"more") || !strcmp(op,"zmore") || !strcmp(op,"bzmore")) { const char *pager=getenv("PAGER"); if(pager==NULL) pager=DEFAULT_PAGER; output->PreFilter(pager); } if(!strcmp(op,"zcat") || !strcmp(op,"zmore")) { output->PreFilter("zcat"); Binary(); } if(!strcmp(op,"bzcat") || !strcmp(op,"bzmore")) { output->PreFilter("bzcat"); Binary(); } } void CatJob::ShowRunStatus(const SMTaskRef& s) { if(cp && cp->HasStatus() && output->ShowStatusLine(s)) cp->ShowRunStatus(s); } lftp-4.9.2/src/netkey.c0000644000015000007670000005034413062512164011654 00000000000000#include #include #include #include #include typedef unsigned char uchar; #define NAMELEN 28 enum { DESKEYLEN= 7, /* length of a des key for encrypt/decrypt */ CHALLEN= 8, /* length of a challenge */ NETCHLEN= 16, /* max network challenge length */ }; /************ crypt.c *************/ /* * Data Encryption Standard * D.P.Mitchell 83/06/08. * * block_cipher(key, block, decrypting) */ static int ip_low(char [8]); static int ip_high(char [8]); static void fp(int, int, char[8]); static void key_setup(char[DESKEYLEN], char[128]); static void block_cipher(char[128], char[8], int); /* * destructively encrypt the buffer, which * must be at least 8 characters long. */ int encrypt9(void *key, void *vbuf, int n) { char ekey[128], *buf; int i, r; if(n < 8) return 0; key_setup(key, ekey); buf = vbuf; n--; r = n % 7; n /= 7; for(i = 0; i < n; i++){ block_cipher(ekey, buf, 0); buf += 7; } if(r) block_cipher(ekey, buf - 7 + r, 0); return 1; } /* * destructively decrypt the buffer, which * must be at least 8 characters long. */ int decrypt(void *key, void *vbuf, int n) { char ekey[128], *buf; int i, r; if(n < 8) return 0; key_setup(key, ekey); buf = vbuf; n--; r = n % 7; n /= 7; buf += n * 7; if(r) block_cipher(ekey, buf - 7 + r, 1); for(i = 0; i < n; i++){ buf -= 7; block_cipher(ekey, buf, 1); } return 1; } /* * Tables for Combined S and P Boxes */ static const int s0p[] = { 0x00410100,0x00010000,0x40400000,0x40410100,0x00400000,0x40010100,0x40010000,0x40400000, 0x40010100,0x00410100,0x00410000,0x40000100,0x40400100,0x00400000,0x00000000,0x40010000, 0x00010000,0x40000000,0x00400100,0x00010100,0x40410100,0x00410000,0x40000100,0x00400100, 0x40000000,0x00000100,0x00010100,0x40410000,0x00000100,0x40400100,0x40410000,0x00000000, 0x00000000,0x40410100,0x00400100,0x40010000,0x00410100,0x00010000,0x40000100,0x00400100, 0x40410000,0x00000100,0x00010100,0x40400000,0x40010100,0x40000000,0x40400000,0x00410000, 0x40410100,0x00010100,0x00410000,0x40400100,0x00400000,0x40000100,0x40010000,0x00000000, 0x00010000,0x00400000,0x40400100,0x00410100,0x40000000,0x40410000,0x00000100,0x40010100, }; static const int s1p[] = { 0x08021002,0x00000000,0x00021000,0x08020000,0x08000002,0x00001002,0x08001000,0x00021000, 0x00001000,0x08020002,0x00000002,0x08001000,0x00020002,0x08021000,0x08020000,0x00000002, 0x00020000,0x08001002,0x08020002,0x00001000,0x00021002,0x08000000,0x00000000,0x00020002, 0x08001002,0x00021002,0x08021000,0x08000002,0x08000000,0x00020000,0x00001002,0x08021002, 0x00020002,0x08021000,0x08001000,0x00021002,0x08021002,0x00020002,0x08000002,0x00000000, 0x08000000,0x00001002,0x00020000,0x08020002,0x00001000,0x08000000,0x00021002,0x08001002, 0x08021000,0x00001000,0x00000000,0x08000002,0x00000002,0x08021002,0x00021000,0x08020000, 0x08020002,0x00020000,0x00001002,0x08001000,0x08001002,0x00000002,0x08020000,0x00021000, }; static const int s2p[] = { 0x20800000,0x00808020,0x00000020,0x20800020,0x20008000,0x00800000,0x20800020,0x00008020, 0x00800020,0x00008000,0x00808000,0x20000000,0x20808020,0x20000020,0x20000000,0x20808000, 0x00000000,0x20008000,0x00808020,0x00000020,0x20000020,0x20808020,0x00008000,0x20800000, 0x20808000,0x00800020,0x20008020,0x00808000,0x00008020,0x00000000,0x00800000,0x20008020, 0x00808020,0x00000020,0x20000000,0x00008000,0x20000020,0x20008000,0x00808000,0x20800020, 0x00000000,0x00808020,0x00008020,0x20808000,0x20008000,0x00800000,0x20808020,0x20000000, 0x20008020,0x20800000,0x00800000,0x20808020,0x00008000,0x00800020,0x20800020,0x00008020, 0x00800020,0x00000000,0x20808000,0x20000020,0x20800000,0x20008020,0x00000020,0x00808000, }; static const int s3p[] = { 0x00080201,0x02000200,0x00000001,0x02080201,0x00000000,0x02080000,0x02000201,0x00080001, 0x02080200,0x02000001,0x02000000,0x00000201,0x02000001,0x00080201,0x00080000,0x02000000, 0x02080001,0x00080200,0x00000200,0x00000001,0x00080200,0x02000201,0x02080000,0x00000200, 0x00000201,0x00000000,0x00080001,0x02080200,0x02000200,0x02080001,0x02080201,0x00080000, 0x02080001,0x00000201,0x00080000,0x02000001,0x00080200,0x02000200,0x00000001,0x02080000, 0x02000201,0x00000000,0x00000200,0x00080001,0x00000000,0x02080001,0x02080200,0x00000200, 0x02000000,0x02080201,0x00080201,0x00080000,0x02080201,0x00000001,0x02000200,0x00080201, 0x00080001,0x00080200,0x02080000,0x02000201,0x00000201,0x02000000,0x02000001,0x02080200, }; static const int s4p[] = { 0x01000000,0x00002000,0x00000080,0x01002084,0x01002004,0x01000080,0x00002084,0x01002000, 0x00002000,0x00000004,0x01000004,0x00002080,0x01000084,0x01002004,0x01002080,0x00000000, 0x00002080,0x01000000,0x00002004,0x00000084,0x01000080,0x00002084,0x00000000,0x01000004, 0x00000004,0x01000084,0x01002084,0x00002004,0x01002000,0x00000080,0x00000084,0x01002080, 0x01002080,0x01000084,0x00002004,0x01002000,0x00002000,0x00000004,0x01000004,0x01000080, 0x01000000,0x00002080,0x01002084,0x00000000,0x00002084,0x01000000,0x00000080,0x00002004, 0x01000084,0x00000080,0x00000000,0x01002084,0x01002004,0x01002080,0x00000084,0x00002000, 0x00002080,0x01002004,0x01000080,0x00000084,0x00000004,0x00002084,0x01002000,0x01000004, }; static const int s5p[] = { 0x10000008,0x00040008,0x00000000,0x10040400,0x00040008,0x00000400,0x10000408,0x00040000, 0x00000408,0x10040408,0x00040400,0x10000000,0x10000400,0x10000008,0x10040000,0x00040408, 0x00040000,0x10000408,0x10040008,0x00000000,0x00000400,0x00000008,0x10040400,0x10040008, 0x10040408,0x10040000,0x10000000,0x00000408,0x00000008,0x00040400,0x00040408,0x10000400, 0x00000408,0x10000000,0x10000400,0x00040408,0x10040400,0x00040008,0x00000000,0x10000400, 0x10000000,0x00000400,0x10040008,0x00040000,0x00040008,0x10040408,0x00040400,0x00000008, 0x10040408,0x00040400,0x00040000,0x10000408,0x10000008,0x10040000,0x00040408,0x00000000, 0x00000400,0x10000008,0x10000408,0x10040400,0x10040000,0x00000408,0x00000008,0x10040008, }; static const int s6p[] = { 0x00000800,0x00000040,0x00200040,0x80200000,0x80200840,0x80000800,0x00000840,0x00000000, 0x00200000,0x80200040,0x80000040,0x00200800,0x80000000,0x00200840,0x00200800,0x80000040, 0x80200040,0x00000800,0x80000800,0x80200840,0x00000000,0x00200040,0x80200000,0x00000840, 0x80200800,0x80000840,0x00200840,0x80000000,0x80000840,0x80200800,0x00000040,0x00200000, 0x80000840,0x00200800,0x80200800,0x80000040,0x00000800,0x00000040,0x00200000,0x80200800, 0x80200040,0x80000840,0x00000840,0x00000000,0x00000040,0x80200000,0x80000000,0x00200040, 0x00000000,0x80200040,0x00200040,0x00000840,0x80000040,0x00000800,0x80200840,0x00200000, 0x00200840,0x80000000,0x80000800,0x80200840,0x80200000,0x00200840,0x00200800,0x80000800, }; static const int s7p[] = { 0x04100010,0x04104000,0x00004010,0x00000000,0x04004000,0x00100010,0x04100000,0x04104010, 0x00000010,0x04000000,0x00104000,0x00004010,0x00104010,0x04004010,0x04000010,0x04100000, 0x00004000,0x00104010,0x00100010,0x04004000,0x04104010,0x04000010,0x00000000,0x00104000, 0x04000000,0x00100000,0x04004010,0x04100010,0x00100000,0x00004000,0x04104000,0x00000010, 0x00100000,0x00004000,0x04000010,0x04104010,0x00004010,0x04000000,0x00000000,0x00104000, 0x04100010,0x04004010,0x04004000,0x00100010,0x04104000,0x00000010,0x00100010,0x04004000, 0x04104010,0x00100000,0x04100000,0x04000010,0x00104000,0x00004010,0x04004010,0x04100000, 0x00000010,0x04104000,0x00104010,0x00000000,0x04000000,0x04100010,0x00004000,0x00104010, }; /* * DES electronic codebook encryption of one block */ static void block_cipher(char expanded_key[128], char text[8], int decrypting) { char *key; int crypto, temp, right, left; int i, key_offset; key = expanded_key; left = ip_low(text); right = ip_high(text); if (decrypting) { key_offset = 16; key = key + 128 - 8; } else key_offset = 0; for (i = 0; i < 16; i++) { temp = (right << 1) | ((right >> 31) & 1); crypto = s0p[(temp & 0x3f) ^ *key++]; crypto |= s1p[((temp >> 4) & 0x3f) ^ *key++]; crypto |= s2p[((temp >> 8) & 0x3f) ^ *key++]; crypto |= s3p[((temp >> 12) & 0x3f) ^ *key++]; crypto |= s4p[((temp >> 16) & 0x3f) ^ *key++]; crypto |= s5p[((temp >> 20) & 0x3f) ^ *key++]; crypto |= s6p[((temp >> 24) & 0x3f) ^ *key++]; temp = ((right & 1) << 5) | ((right >> 27) & 0x1f); crypto |= s7p[temp ^ *key++]; temp = left; left = right; right = temp ^ crypto; key -= key_offset; } /* * standard final permutation (IPI) * left and right are reversed here */ fp(right, left, text); } /* * Initial Permutation */ static const int iptab[] = { 0x00000000, 0x00008000, 0x00000000, 0x00008000, 0x00000080, 0x00008080, 0x00000080, 0x00008080 }; static int ip_low(char block[8]) { int i; int l; l = 0; for(i = 0; i < 8; i++){ l |= iptab[(block[i] >> 4) & 7] >> i; l |= iptab[block[i] & 7] << (16 - i); } return l; } static int ip_high(char block[8]) { int i; int l; l = 0; for(i = 0; i < 8; i++){ l |= iptab[(block[i] >> 5) & 7] >> i; l |= iptab[(block[i] >> 1) & 7] << (16 - i); } return l; } /* * Final Permutation */ static const unsigned int fptab[] = { 0x00000000,0x80000000,0x00800000,0x80800000,0x00008000,0x80008000,0x00808000,0x80808000, 0x00000080,0x80000080,0x00800080,0x80800080,0x00008080,0x80008080,0x00808080,0x80808080, }; static void fp(int left, int right, char text[8]) { unsigned int ta[2], t, v[2]; int i, j, sh; ta[0] = right; ta[1] = left; v[0] = v[1] = 0; for(i = 0; i < 2; i++){ t = ta[i]; sh = i; for(j = 0; j < 4; j++){ v[1] |= fptab[t & 0xf] >> sh; t >>= 4; v[0] |= fptab[t & 0xf] >> sh; t >>= 4; sh += 2; } } for(i = 0; i < 2; i++) for(j = 0; j < 4; j++){ *text++ = (char)(v[i]&0xff); v[i] >>= 8; } } /* * Key set-up */ static const uchar keyexpand[][15][2] = { { { 3, 2}, { 9, 8}, { 18, 8}, { 27, 32}, { 33, 2}, { 42, 16}, { 48, 8}, { 65, 16}, { 74, 2}, { 80, 2}, { 89, 4}, { 99, 16}, {104, 4}, {122, 32}, { 0, 0} }, { { 1, 4}, { 8, 1}, { 18, 4}, { 25, 32}, { 34, 32}, { 41, 8}, { 50, 8}, { 59, 32}, { 64, 16}, { 75, 4}, { 90, 1}, { 97, 16}, {106, 2}, {112, 2}, {123, 1} }, { { 2, 1}, { 19, 8}, { 35, 1}, { 40, 1}, { 50, 4}, { 57, 32}, { 75, 2}, { 80, 32}, { 89, 1}, { 96, 16}, {107, 4}, {120, 8}, { 0, 0}, { 0, 0}, { 0, 0} }, { { 4, 32}, { 20, 2}, { 31, 4}, { 37, 32}, { 47, 1}, { 54, 1}, { 63, 2}, { 68, 1}, { 78, 4}, { 84, 8}, {101, 16}, {108, 4}, {119, 16}, {126, 8}, { 0, 0} }, { { 5, 4}, { 15, 4}, { 21, 32}, { 31, 1}, { 38, 1}, { 47, 2}, { 53, 2}, { 68, 8}, { 85, 16}, { 92, 4}, {103, 16}, {108, 32}, {118, 32}, {124, 2}, { 0, 0} }, { { 15, 2}, { 21, 2}, { 39, 8}, { 46, 16}, { 55, 32}, { 61, 1}, { 71, 16}, { 76, 32}, { 86, 32}, { 93, 4}, {102, 2}, {108, 16}, {117, 8}, {126, 1}, { 0, 0} }, { { 14, 16}, { 23, 32}, { 29, 1}, { 38, 8}, { 52, 2}, { 63, 4}, { 70, 2}, { 76, 16}, { 85, 8}, {100, 1}, {110, 4}, {116, 8}, {127, 8}, { 0, 0}, { 0, 0} }, { { 1, 8}, { 8, 32}, { 17, 1}, { 24, 16}, { 35, 4}, { 50, 1}, { 57, 16}, { 67, 8}, { 83, 1}, { 88, 1}, { 98, 4}, {105, 32}, {114, 32}, {123, 2}, { 0, 0} }, { { 0, 1}, { 11, 16}, { 16, 4}, { 35, 2}, { 40, 32}, { 49, 1}, { 56, 16}, { 65, 2}, { 74, 16}, { 80, 8}, { 99, 8}, {115, 1}, {121, 4}, { 0, 0}, { 0, 0} }, { { 9, 16}, { 18, 2}, { 24, 2}, { 33, 4}, { 43, 16}, { 48, 4}, { 66, 32}, { 73, 8}, { 82, 8}, { 91, 32}, { 97, 2}, {106, 16}, {112, 8}, {122, 1}, { 0, 0} }, { { 14, 32}, { 21, 4}, { 30, 2}, { 36, 16}, { 45, 8}, { 60, 1}, { 69, 2}, { 87, 8}, { 94, 16}, {103, 32}, {109, 1}, {118, 8}, {124, 32}, { 0, 0}, { 0, 0} }, { { 7, 4}, { 14, 2}, { 20, 16}, { 29, 8}, { 44, 1}, { 54, 4}, { 60, 8}, { 71, 8}, { 78, 16}, { 87, 32}, { 93, 1}, {102, 8}, {116, 2}, {125, 4}, { 0, 0} }, { { 7, 2}, { 12, 1}, { 22, 4}, { 28, 8}, { 45, 16}, { 52, 4}, { 63, 16}, { 70, 8}, { 84, 2}, { 95, 4}, {101, 32}, {111, 1}, {118, 1}, { 0, 0}, { 0, 0} }, { { 6, 16}, { 13, 16}, { 20, 4}, { 31, 16}, { 36, 32}, { 46, 32}, { 53, 4}, { 62, 2}, { 69, 32}, { 79, 1}, { 86, 1}, { 95, 2}, {101, 2}, {119, 8}, { 0, 0} }, { { 0, 32}, { 10, 8}, { 19, 32}, { 25, 2}, { 34, 16}, { 40, 8}, { 59, 8}, { 66, 2}, { 72, 2}, { 81, 4}, { 91, 16}, { 96, 4}, {115, 2}, {121, 8}, { 0, 0} }, { { 3, 16}, { 10, 4}, { 17, 32}, { 26, 32}, { 33, 8}, { 42, 8}, { 51, 32}, { 57, 2}, { 67, 4}, { 82, 1}, { 89, 16}, { 98, 2}, {104, 2}, {113, 4}, {120, 1} }, { { 1, 16}, { 11, 8}, { 27, 1}, { 32, 1}, { 42, 4}, { 49, 32}, { 58, 32}, { 67, 2}, { 72, 32}, { 81, 1}, { 88, 16}, { 99, 4}, {114, 1}, { 0, 0}, { 0, 0} }, { { 6, 32}, { 12, 2}, { 23, 4}, { 29, 32}, { 39, 1}, { 46, 1}, { 55, 2}, { 61, 2}, { 70, 4}, { 76, 8}, { 93, 16}, {100, 4}, {111, 16}, {116, 32}, { 0, 0} }, { { 6, 2}, { 13, 32}, { 23, 1}, { 30, 1}, { 39, 2}, { 45, 2}, { 63, 8}, { 77, 16}, { 84, 4}, { 95, 16}, {100, 32}, {110, 32}, {117, 4}, {127, 4}, { 0, 0} }, { { 4, 1}, { 13, 2}, { 31, 8}, { 38, 16}, { 47, 32}, { 53, 1}, { 62, 8}, { 68, 32}, { 78, 32}, { 85, 4}, { 94, 2}, {100, 16}, {109, 8}, {127, 2}, { 0, 0} }, { { 5, 16}, { 15, 32}, { 21, 1}, { 30, 8}, { 44, 2}, { 55, 4}, { 61, 32}, { 68, 16}, { 77, 8}, { 92, 1}, {102, 4}, {108, 8}, {126, 16}, { 0, 0}, { 0, 0} }, { { 2, 8}, { 9, 1}, { 16, 16}, { 27, 4}, { 42, 1}, { 49, 16}, { 58, 2}, { 75, 1}, { 80, 1}, { 90, 4}, { 97, 32}, {106, 32}, {113, 8}, {120, 32}, { 0, 0} }, { { 2, 4}, { 8, 4}, { 27, 2}, { 32, 32}, { 41, 1}, { 48, 16}, { 59, 4}, { 66, 16}, { 72, 8}, { 91, 8}, {107, 1}, {112, 1}, {123, 16}, { 0, 0}, { 0, 0} }, { { 3, 8}, { 10, 2}, { 16, 2}, { 25, 4}, { 35, 16}, { 40, 4}, { 59, 2}, { 65, 8}, { 74, 8}, { 83, 32}, { 89, 2}, { 98, 16}, {104, 8}, {121, 16}, { 0, 0} }, { { 4, 2}, { 13, 4}, { 22, 2}, { 28, 16}, { 37, 8}, { 52, 1}, { 62, 4}, { 79, 8}, { 86, 16}, { 95, 32}, {101, 1}, {110, 8}, {126, 32}, { 0, 0}, { 0, 0} }, { { 5, 32}, { 12, 16}, { 21, 8}, { 36, 1}, { 46, 4}, { 52, 8}, { 70, 16}, { 79, 32}, { 85, 1}, { 94, 8}, {108, 2}, {119, 4}, {126, 2}, { 0, 0}, { 0, 0} }, { { 5, 2}, { 14, 4}, { 20, 8}, { 37, 16}, { 44, 4}, { 55, 16}, { 60, 32}, { 76, 2}, { 87, 4}, { 93, 32}, {103, 1}, {110, 1}, {119, 2}, {124, 1}, { 0, 0} }, { { 7, 32}, { 12, 4}, { 23, 16}, { 28, 32}, { 38, 32}, { 45, 4}, { 54, 2}, { 60, 16}, { 71, 1}, { 78, 1}, { 87, 2}, { 93, 2}, {111, 8}, {118, 16}, {125, 16} }, { { 1, 1}, { 11, 32}, { 17, 2}, { 26, 16}, { 32, 8}, { 51, 8}, { 64, 2}, { 73, 4}, { 83, 16}, { 88, 4}, {107, 2}, {112, 32}, {122, 8}, { 0, 0}, { 0, 0} }, { { 0, 4}, { 9, 32}, { 18, 32}, { 25, 8}, { 34, 8}, { 43, 32}, { 49, 2}, { 58, 16}, { 74, 1}, { 81, 16}, { 90, 2}, { 96, 2}, {105, 4}, {115, 16}, {122, 4} }, { { 2, 2}, { 19, 1}, { 24, 1}, { 34, 4}, { 41, 32}, { 50, 32}, { 57, 8}, { 64, 32}, { 73, 1}, { 80, 16}, { 91, 4}, {106, 1}, {113, 16}, {123, 8}, { 0, 0} }, { { 3, 4}, { 10, 16}, { 16, 8}, { 35, 8}, { 51, 1}, { 56, 1}, { 67, 16}, { 72, 4}, { 91, 2}, { 96, 32}, {105, 1}, {112, 16}, {121, 2}, { 0, 0}, { 0, 0} }, { { 4, 16}, { 15, 1}, { 22, 1}, { 31, 2}, { 37, 2}, { 55, 8}, { 62, 16}, { 69, 16}, { 76, 4}, { 87, 16}, { 92, 32}, {102, 32}, {109, 4}, {118, 2}, {125, 32} }, { { 6, 4}, { 23, 8}, { 30, 16}, { 39, 32}, { 45, 1}, { 54, 8}, { 70, 32}, { 77, 4}, { 86, 2}, { 92, 16}, {101, 8}, {116, 1}, {125, 2}, { 0, 0}, { 0, 0} }, { { 4, 4}, { 13, 1}, { 22, 8}, { 36, 2}, { 47, 4}, { 53, 32}, { 63, 1}, { 69, 8}, { 84, 1}, { 94, 4}, {100, 8}, {117, 16}, {127, 32}, { 0, 0}, { 0, 0} }, { { 3, 32}, { 8, 16}, { 19, 4}, { 34, 1}, { 41, 16}, { 50, 2}, { 56, 2}, { 67, 1}, { 72, 1}, { 82, 4}, { 89, 32}, { 98, 32}, {105, 8}, {114, 8}, {121, 1} }, { { 1, 32}, { 19, 2}, { 24, 32}, { 33, 1}, { 40, 16}, { 51, 4}, { 64, 8}, { 83, 8}, { 99, 1}, {104, 1}, {114, 4}, {120, 4}, { 0, 0}, { 0, 0}, { 0, 0} }, { { 8, 2}, { 17, 4}, { 27, 16}, { 32, 4}, { 51, 2}, { 56, 32}, { 66, 8}, { 75, 32}, { 81, 2}, { 90, 16}, { 96, 8}, {115, 8}, {122, 2}, { 0, 0}, { 0, 0} }, { { 2, 16}, { 18, 1}, { 25, 16}, { 34, 2}, { 40, 2}, { 49, 4}, { 59, 16}, { 66, 4}, { 73, 32}, { 82, 32}, { 89, 8}, { 98, 8}, {107, 32}, {113, 2}, {123, 4} }, { { 7, 1}, { 13, 8}, { 28, 1}, { 38, 4}, { 44, 8}, { 61, 16}, { 71, 32}, { 77, 1}, { 86, 8}, {100, 2}, {111, 4}, {117, 32}, {124, 16}, { 0, 0}, { 0, 0} }, { { 12, 8}, { 29, 16}, { 36, 4}, { 47, 16}, { 52, 32}, { 62, 32}, { 68, 2}, { 79, 4}, { 85, 32}, { 95, 1}, {102, 1}, {111, 2}, {117, 2}, {126, 4}, { 0, 0} }, { { 5, 1}, { 15, 16}, { 20, 32}, { 30, 32}, { 37, 4}, { 46, 2}, { 52, 16}, { 61, 8}, { 70, 1}, { 79, 2}, { 85, 2}, {103, 8}, {110, 16}, {119, 32}, {124, 4} }, { { 0, 16}, { 9, 2}, { 18, 16}, { 24, 8}, { 43, 8}, { 59, 1}, { 65, 4}, { 75, 16}, { 80, 4}, { 99, 2}, {104, 32}, {113, 1}, {123, 32}, { 0, 0}, { 0, 0} }, { { 10, 32}, { 17, 8}, { 26, 8}, { 35, 32}, { 41, 2}, { 50, 16}, { 56, 8}, { 66, 1}, { 73, 16}, { 82, 2}, { 88, 2}, { 97, 4}, {107, 16}, {112, 4}, {121, 32} }, { { 0, 2}, { 11, 1}, { 16, 1}, { 26, 4}, { 33, 32}, { 42, 32}, { 49, 8}, { 58, 8}, { 65, 1}, { 72, 16}, { 83, 4}, { 98, 1}, {105, 16}, {114, 2}, { 0, 0} }, { { 8, 8}, { 27, 8}, { 43, 1}, { 48, 1}, { 58, 4}, { 64, 4}, { 83, 2}, { 88, 32}, { 97, 1}, {104, 16}, {115, 4}, {122, 16}, { 0, 0}, { 0, 0}, { 0, 0} }, { { 5, 8}, { 14, 1}, { 23, 2}, { 29, 2}, { 47, 8}, { 54, 16}, { 63, 32}, { 68, 4}, { 79, 16}, { 84, 32}, { 94, 32}, {101, 4}, {110, 2}, {116, 16}, {127, 1} }, { { 4, 8}, { 15, 8}, { 22, 16}, { 31, 32}, { 37, 1}, { 46, 8}, { 60, 2}, { 69, 4}, { 78, 2}, { 84, 16}, { 93, 8}, {108, 1}, {118, 4}, { 0, 0}, { 0, 0} }, { { 7, 16}, { 14, 8}, { 28, 2}, { 39, 4}, { 45, 32}, { 55, 1}, { 62, 1}, { 76, 1}, { 86, 4}, { 92, 8}, {109, 16}, {116, 4}, {125, 1}, { 0, 0}, { 0, 0} }, { { 1, 2}, { 11, 4}, { 26, 1}, { 33, 16}, { 42, 2}, { 48, 2}, { 57, 4}, { 64, 1}, { 74, 4}, { 81, 32}, { 90, 32}, { 97, 8}, {106, 8}, {115, 32}, {120, 16} }, { { 2, 32}, { 11, 2}, { 16, 32}, { 25, 1}, { 32, 16}, { 43, 4}, { 58, 1}, { 75, 8}, { 91, 1}, { 96, 1}, {106, 4}, {113, 32}, { 0, 0}, { 0, 0}, { 0, 0} }, { { 3, 1}, { 9, 4}, { 19, 16}, { 24, 4}, { 43, 2}, { 48, 32}, { 57, 1}, { 67, 32}, { 73, 2}, { 82, 16}, { 88, 8}, {107, 8}, {120, 2}, { 0, 0}, { 0, 0} }, { { 0, 8}, { 10, 1}, { 17, 16}, { 26, 2}, { 32, 2}, { 41, 4}, { 51, 16}, { 56, 4}, { 65, 32}, { 74, 32}, { 81, 8}, { 90, 8}, { 99, 32}, {105, 2}, {114, 16} }, { { 6, 1}, { 20, 1}, { 30, 4}, { 36, 8}, { 53, 16}, { 60, 4}, { 69, 1}, { 78, 8}, { 92, 2}, {103, 4}, {109, 32}, {119, 1}, {125, 8}, { 0, 0}, { 0, 0} }, { { 7, 8}, { 21, 16}, { 28, 4}, { 39, 16}, { 44, 32}, { 54, 32}, { 61, 4}, { 71, 4}, { 77, 32}, { 87, 1}, { 94, 1}, {103, 2}, {109, 2}, {124, 8}, { 0, 0} }, { { 6, 8}, { 12, 32}, { 22, 32}, { 29, 4}, { 38, 2}, { 44, 16}, { 53, 8}, { 71, 2}, { 77, 2}, { 95, 8}, {102, 16}, {111, 32}, {117, 1}, {127, 16}, { 0, 0} } }; static void key_setup(char key[DESKEYLEN], char *ek) { int i, j, k, mask; const uchar (*x)[2]; memset(ek, 0, 128); x = keyexpand[0]; for(i = 0; i < 7; i++){ k = key[i]; for(mask = 0x80; mask; mask >>= 1){ if(k & mask) for(j = 0; j < 15; j++) ek[x[j][0]] |= x[j][1]; x += 15; } } } /************ netkey main.c *************/ int passtokey(char *key, const char *p) { uchar buf[NAMELEN], *t; int i, n; n = strlen(p); if(n >= NAMELEN) n = NAMELEN-1; memset(buf, ' ', 8); t = buf; strncpy((char*)t, p, n); t[n] = '\0'; memset(key, 0, DESKEYLEN); for(;;){ for(i = 0; i < DESKEYLEN; i++) key[i] = (t[i] >> i) + (t[i+1] << (8 - (i+1))); if(n <= 8) return 1; n -= 8; t += 8; if(n < 8){ t -= 8 - n; n = 8; } encrypt9(key, t, 8); } return 1; /* not reached */ } int netcrypt(void *key, void *chal) { uchar buf[8], *p; strncpy((char*)buf, chal, 7); buf[7] = '\0'; for(p = buf; *p && *p != '\n'; p++) ; *p = '\0'; encrypt9(key, buf, 8); sprintf(chal, "%.2x%.2x%.2x%.2x", buf[0], buf[1], buf[2], buf[3]); return 1; } char * calculate_netkey_response( const char* pass, const char* challenge ) { char key[DESKEYLEN]; static char response[32]; passtokey( key, pass ); strcpy( response, challenge ); netcrypt( key, response ); return response; } lftp-4.9.2/src/import-ncftp0000755000015000007670000000115512122054516012553 00000000000000#!/bin/sh # This script is based on draft by Sam Steingold # Copyright (c) 1998 by Alexander V. Lukyanov # This script can be distributed and modified freely under GNU GPL, see COPYING set -e NCFTP="$HOME/.ncftp/bookmarks" OLD="${LFTP_HOME:-$HOME/.lftp}/bookmarks" NEW="$OLD.new.$$" grep "," "$NCFTP" | cut -d, -f1,2,3,6 | sed \ -e "s?,,?/?" \ -e "s?//?/?" \ -e "s?,? ftp://?" \ -e "s?ftp://\([^,]*\),\([^,]*\),/*?ftp://\2@\1/?" \ -e "s?^?NC-?" > "$NEW" if [ -f "$OLD" ]; then sort -u "$OLD" "$NEW" -o "$NEW" mv -f "$OLD" "$OLD~" # backup else sort -u "$NEW" -o "$NEW" fi mv -f "$NEW" "$OLD" lftp-4.9.2/src/FileSetOutput.cc0000644000015000007670000002434013143027152013267 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "FileSet.h" #include #include #include #include #include #include #include #include #include CDECL_BEGIN #include #include "human.h" CDECL_END #include "misc.h" #include "ResMgr.h" #include "FileSetOutput.h" #include "ArgV.h" #include "ColumnOutput.h" #include "DirColors.h" #include "FileGlob.h" #include "CopyJob.h" ResDecl res_default_cls ("cmd:cls-default", "-F", FileSetOutput::ValidateArgv,ResMgr::NoClosure), res_default_comp_cls ("cmd:cls-completion-default", "-FBa",FileSetOutput::ValidateArgv,ResMgr::NoClosure); ResDecl res_time_style ("cmd:time-style", "%b %e %Y|%b %e %H:%M", 0, ResMgr::NoClosure); /* note: this sorts (add a nosort if necessary) */ void FileSetOutput::print(FileSet &fs, const JobRef& o) const { fs.Sort(sort, sort_casefold, sort_reverse); if(sort_dirs_first) fs.Sort(FileSet::DIRSFIRST, false, sort_reverse); ColumnOutput c; DirColors &col=*DirColors::GetInstance(); const char *suffix_color = ""; /* Most fields are only printed if at least one file has that * information; if no files have perm information, for example, * discard the entire field. */ int have = fs.Have(); for(int i = 0; fs[i]; i++) { const FileInfo *f = fs[i]; if(!showdots && !list_directories && (!strcmp(basename_ptr(f->name),".") || !strcmp(basename_ptr(f->name),".."))) continue; if(pat && *pat && fnmatch(pat, f->name, patterns_casefold? FNM_CASEFOLD:0)) continue; c.append(); if((mode & PERMS) && (f->defined&FileInfo::MODE)) { char mode[16]; memset(mode, 0, sizeof(mode)); strmode(f->mode, mode); /* FIXME: f->mode doesn't have type info; it wouldn't * be hard to fix that */ if(f->filetype == FileInfo::DIRECTORY) mode[0] = 'd'; else if(f->filetype == FileInfo::SYMLINK) mode[0] = 'l'; else mode[0] = '-'; c.add(mode, ""); } else if(have & FileInfo::MODE) { c.add(" ", ""); } if((have & FileInfo::NLINKS) && (mode & NLINKS)) { if(f->defined&f->NLINKS) c.addf("%4i ", "", f->nlinks); else c.addf("%4i ", "", ""); } if((have & FileInfo::USER) && (mode & USER)) { c.addf("%-8.8s ", "", (f->defined&f->USER)? f->user: ""); } if((have & FileInfo::GROUP) && (mode & GROUP)) { c.addf("%-8.8s ", "", (f->defined&f->GROUP)? f->group: ""); } if((mode & SIZE) && (have&FileInfo::SIZE)) { char sz[LONGEST_HUMAN_READABLE + 2]; if((f->filetype == FileInfo::NORMAL || !size_filesonly) && (f->defined&f->SIZE)) { char buffer[LONGEST_HUMAN_READABLE + 1]; snprintf(sz, sizeof(sz), "%8s ", human_readable (f->size, buffer, human_opts, 1, output_block_size? output_block_size:1024)); } else { snprintf(sz, sizeof(sz), "%8s ", ""); /* pad */ } c.add(sz, ""); } /* We use unprec dates; doing MDTMs for each file in ls is far too * slow. If someone actually wants that (to get dates on servers with * unparsable dates, or more accurate dates), it wouldn't be * difficult. If we did this, we could also support --full-time. */ if((mode & DATE) && (have & f->DATE)) { /* Consider a time to be recent if it is within the past six * months. A Gregorian year has 365.2425 * 24 * 60 * 60 == * 31556952 seconds on the average. Write this value as an * integer constant to avoid floating point hassles. */ const int six_months_ago = SMTask::now.UnixTime() - 31556952 / 2; bool recent = six_months_ago <= f->date; const char *use_fmt=time_fmt; if(!use_fmt) use_fmt=ResMgr::Query("cmd:time-style",0); if(!use_fmt || !*use_fmt) use_fmt="%b %e %Y\n%b %e %H:%M"; xstring_ca dt_mem(xstrftime(use_fmt, localtime (&f->date.ts))); char *dt=strtok(dt_mem.get_non_const(),"\n|"); if(recent) { char *dt1=strtok(NULL,"\n|"); if(dt1) dt=dt1; } if (!(f->defined&f->DATE)) { /* put an empty field; make sure it's the same width */ int wid = mbswidth(dt, 0); dt = string_alloca(wid+1); memset(dt, ' ', wid); dt[wid] = 0; } c.addf("%s ", "", dt); } const char *nm = f->name; if(basenames) nm = basename_ptr(nm); c.add(nm, col.GetColor(f)); if(classify) c.add(FileInfoSuffix(*f), suffix_color); if((mode & LINKS) && f->filetype == FileInfo::SYMLINK && f->symlink) { c.add(" -> ", ""); /* see if we have a file entry for the symlink */ FileInfo tmpfi; FileInfo *lfi = fs.FindByName(f->symlink); if(!lfi) { /* create a temporary one */ tmpfi.SetName(f->symlink); lfi = &tmpfi; } c.add(lfi->name, col.GetColor(lfi)); if(classify) c.add(FileInfoSuffix(*lfi), suffix_color); } } c.print(o, single_column? 0:width, color); } const char *FileSetOutput::FileInfoSuffix(const FileInfo &fi) const { if(!(fi.defined&fi.TYPE)) return ""; if(fi.filetype == FileInfo::DIRECTORY) return "/"; else if(fi.filetype == FileInfo::SYMLINK) return "@"; return ""; } void FileSetOutput::config(const OutputJob *o) { width = o->GetWidth(); if(width == -1) width = 80; color = ResMgr::QueryTriBool("color:use-color", 0, o->IsTTY()); } void FileSetOutput::long_list() { single_column = true; mode = ALL; /* -l's default size is 1; otherwise 1024 */ if(!output_block_size) output_block_size = 1; } const char *FileSetOutput::parse_res(const char *res) { Ref arg(new ArgV("",res)); const char *error=parse_argv(arg); if(error) return error; /* shouldn't be any non-option arguments */ if(arg->count() > 1) return _("non-option arguments found"); return 0; } const char *FileSetOutput::ValidateArgv(xstring_c *s) { if(!*s) return NULL; FileSetOutput tmp; const char *ret = tmp.parse_res(*s); if(ret) return ret; return NULL; } int FileSetOutput::Need() const { int need=FileInfo::NAME; if(mode & PERMS) need|=FileInfo::MODE; // if(mode & SIZE) /* this must be optional */ // need|=FileInfo::SIZE; // if(mode & DATE) /* this too */ // need|=FileInfo::DATE; if(mode & LINKS) need|=FileInfo::SYMLINK_DEF; if(mode & USER) need|=FileInfo::USER; if(mode & GROUP) need|=FileInfo::GROUP; if(need_exact_time) need|=FileInfo::DATE; return need; } #undef super #define super SessionJob clsJob::clsJob(FA *s, ArgV *a, FileSetOutput *_opts, OutputJob *_output): SessionJob(s), fso(_opts), args(a), done(0), use_cache(true), error(false), state(INIT) { list_info=0; if(args->count() == 1) args->Add(""); output=_output; AddWaiting(output); } int clsJob::Done() { return done && output->Done(); } int clsJob::Do() { int m=STALL; if(output->Done()) state=DONE; switch(state) { case INIT: state=START_LISTING; m=MOVED; case START_LISTING: { list_info=0; /* next: */ mask.set(0); dir.set(args->getnext()); if(!dir) { /* done */ state=DONE; return MOVED; } /* If the basename contains wildcards, set up the mask. */ const char *bn = basename_ptr(dir); if(Glob::HasWildcards(bn)) { /* The mask is the whole argument, not just the basename; this is * because the whole relative paths will end up in the FileSet, and * that's what this pattern will be matched against. */ mask.set(dir); // leave the final / on the path, to prevent the dirname of // "file/*" from being treated as a file dir.truncate(bn-dir); // this can result in dir eq "" } else { // no need to glob, just unquote metacharacters. Glob::UnquoteWildcards(const_cast(bn)); } list_info=new GetFileInfo(session, dir, fso->list_directories); list_info->UseCache(use_cache); list_info->Need(fso->Need()); state=GETTING_LIST_INFO; m=MOVED; } case GETTING_LIST_INFO: { if(!list_info->Done()) return m; if(list_info->Error()) { eprintf("%s\n", list_info->ErrorText()); error=true; state=START_LISTING; return MOVED; } /* one just finished */ fso->pat.move_here(mask); FileSet *res = list_info->GetResult(); if(res) fso->print(*res, output); fso->pat.set(0); delete res; state=START_LISTING; return MOVED; } case DONE: if(!done) { output->PutEOF(); done=true; m=MOVED; } break; } return m; } void clsJob::SuspendInternal() { super::SuspendInternal(); if(list_info) list_info->SuspendSlave(); session->SuspendSlave(); } void clsJob::ResumeInternal() { if(list_info) list_info->ResumeSlave(); session->ResumeSlave(); super::ResumeInternal(); } void clsJob::ShowRunStatus(const SMTaskRef& s) { if(fso->quiet) return; if(!output->ShowStatusLine(s)) return; if(list_info && !list_info->Done()) { const char *curr = args->getcurr(); if(!*curr) curr = "."; const char *stat = list_info->Status(); if(*stat) s->Show("`%s' %s %s", curr, stat, output->Status(s)); } else s->Show("%s", output->Status(s)); } xstring& clsJob::FormatStatus(xstring& s,int v,const char *prefix) { Job::FormatStatus(s,v,prefix); if(list_info) { const char *curr = args->getcurr(); if(!*curr) curr = "."; const char *stat = list_info->Status(); if(*stat) s.appendf("%s`%s' %s\n", prefix, curr, stat); } return s; } lftp-4.9.2/src/ftp-opie.c0000644000015000007670000016450712122057743012112 00000000000000/* Opie (s/key) support for FTP. Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. This file is part of GNU Wget. GNU Wget is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. GNU Wget is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wget. If not, see . Additional permission under GNU GPL version 3 section 7 If you modify this program, or any covered work, by linking or combining it with the OpenSSL project's OpenSSL library (or a modified version of that library), containing parts covered by the terms of the OpenSSL or SSLeay licenses, the Free Software Foundation grants you additional permission to convey the resulting work. Corresponding Source for a non-source form of such a combination shall include the source code for the parts of OpenSSL used as well as that of the covered work. */ #include #include #include #include #include "md5.h" /* Dictionary for integer-word translations. Available in appendix D of rfc2289. */ static char Wp[2048][4] = { { 'A', '\0', '\0', '\0' }, { 'A', 'B', 'E', '\0' }, { 'A', 'C', 'E', '\0' }, { 'A', 'C', 'T', '\0' }, { 'A', 'D', '\0', '\0' }, { 'A', 'D', 'A', '\0' }, { 'A', 'D', 'D', '\0' }, { 'A', 'G', 'O', '\0' }, { 'A', 'I', 'D', '\0' }, { 'A', 'I', 'M', '\0' }, { 'A', 'I', 'R', '\0' }, { 'A', 'L', 'L', '\0' }, { 'A', 'L', 'P', '\0' }, { 'A', 'M', '\0', '\0' }, { 'A', 'M', 'Y', '\0' }, { 'A', 'N', '\0', '\0' }, { 'A', 'N', 'A', '\0' }, { 'A', 'N', 'D', '\0' }, { 'A', 'N', 'N', '\0' }, { 'A', 'N', 'T', '\0' }, { 'A', 'N', 'Y', '\0' }, { 'A', 'P', 'E', '\0' }, { 'A', 'P', 'S', '\0' }, { 'A', 'P', 'T', '\0' }, { 'A', 'R', 'C', '\0' }, { 'A', 'R', 'E', '\0' }, { 'A', 'R', 'K', '\0' }, { 'A', 'R', 'M', '\0' }, { 'A', 'R', 'T', '\0' }, { 'A', 'S', '\0', '\0' }, { 'A', 'S', 'H', '\0' }, { 'A', 'S', 'K', '\0' }, { 'A', 'T', '\0', '\0' }, { 'A', 'T', 'E', '\0' }, { 'A', 'U', 'G', '\0' }, { 'A', 'U', 'K', '\0' }, { 'A', 'V', 'E', '\0' }, { 'A', 'W', 'E', '\0' }, { 'A', 'W', 'K', '\0' }, { 'A', 'W', 'L', '\0' }, { 'A', 'W', 'N', '\0' }, { 'A', 'X', '\0', '\0' }, { 'A', 'Y', 'E', '\0' }, { 'B', 'A', 'D', '\0' }, { 'B', 'A', 'G', '\0' }, { 'B', 'A', 'H', '\0' }, { 'B', 'A', 'M', '\0' }, { 'B', 'A', 'N', '\0' }, { 'B', 'A', 'R', '\0' }, { 'B', 'A', 'T', '\0' }, { 'B', 'A', 'Y', '\0' }, { 'B', 'E', '\0', '\0' }, { 'B', 'E', 'D', '\0' }, { 'B', 'E', 'E', '\0' }, { 'B', 'E', 'G', '\0' }, { 'B', 'E', 'N', '\0' }, { 'B', 'E', 'T', '\0' }, { 'B', 'E', 'Y', '\0' }, { 'B', 'I', 'B', '\0' }, { 'B', 'I', 'D', '\0' }, { 'B', 'I', 'G', '\0' }, { 'B', 'I', 'N', '\0' }, { 'B', 'I', 'T', '\0' }, { 'B', 'O', 'B', '\0' }, { 'B', 'O', 'G', '\0' }, { 'B', 'O', 'N', '\0' }, { 'B', 'O', 'O', '\0' }, { 'B', 'O', 'P', '\0' }, { 'B', 'O', 'W', '\0' }, { 'B', 'O', 'Y', '\0' }, { 'B', 'U', 'B', '\0' }, { 'B', 'U', 'D', '\0' }, { 'B', 'U', 'G', '\0' }, { 'B', 'U', 'M', '\0' }, { 'B', 'U', 'N', '\0' }, { 'B', 'U', 'S', '\0' }, { 'B', 'U', 'T', '\0' }, { 'B', 'U', 'Y', '\0' }, { 'B', 'Y', '\0', '\0' }, { 'B', 'Y', 'E', '\0' }, { 'C', 'A', 'B', '\0' }, { 'C', 'A', 'L', '\0' }, { 'C', 'A', 'M', '\0' }, { 'C', 'A', 'N', '\0' }, { 'C', 'A', 'P', '\0' }, { 'C', 'A', 'R', '\0' }, { 'C', 'A', 'T', '\0' }, { 'C', 'A', 'W', '\0' }, { 'C', 'O', 'D', '\0' }, { 'C', 'O', 'G', '\0' }, { 'C', 'O', 'L', '\0' }, { 'C', 'O', 'N', '\0' }, { 'C', 'O', 'O', '\0' }, { 'C', 'O', 'P', '\0' }, { 'C', 'O', 'T', '\0' }, { 'C', 'O', 'W', '\0' }, { 'C', 'O', 'Y', '\0' }, { 'C', 'R', 'Y', '\0' }, { 'C', 'U', 'B', '\0' }, { 'C', 'U', 'E', '\0' }, { 'C', 'U', 'P', '\0' }, { 'C', 'U', 'R', '\0' }, { 'C', 'U', 'T', '\0' }, { 'D', 'A', 'B', '\0' }, { 'D', 'A', 'D', '\0' }, { 'D', 'A', 'M', '\0' }, { 'D', 'A', 'N', '\0' }, { 'D', 'A', 'R', '\0' }, { 'D', 'A', 'Y', '\0' }, { 'D', 'E', 'E', '\0' }, { 'D', 'E', 'L', '\0' }, { 'D', 'E', 'N', '\0' }, { 'D', 'E', 'S', '\0' }, { 'D', 'E', 'W', '\0' }, { 'D', 'I', 'D', '\0' }, { 'D', 'I', 'E', '\0' }, { 'D', 'I', 'G', '\0' }, { 'D', 'I', 'N', '\0' }, { 'D', 'I', 'P', '\0' }, { 'D', 'O', '\0', '\0' }, { 'D', 'O', 'E', '\0' }, { 'D', 'O', 'G', '\0' }, { 'D', 'O', 'N', '\0' }, { 'D', 'O', 'T', '\0' }, { 'D', 'O', 'W', '\0' }, { 'D', 'R', 'Y', '\0' }, { 'D', 'U', 'B', '\0' }, { 'D', 'U', 'D', '\0' }, { 'D', 'U', 'E', '\0' }, { 'D', 'U', 'G', '\0' }, { 'D', 'U', 'N', '\0' }, { 'E', 'A', 'R', '\0' }, { 'E', 'A', 'T', '\0' }, { 'E', 'D', '\0', '\0' }, { 'E', 'E', 'L', '\0' }, { 'E', 'G', 'G', '\0' }, { 'E', 'G', 'O', '\0' }, { 'E', 'L', 'I', '\0' }, { 'E', 'L', 'K', '\0' }, { 'E', 'L', 'M', '\0' }, { 'E', 'L', 'Y', '\0' }, { 'E', 'M', '\0', '\0' }, { 'E', 'N', 'D', '\0' }, { 'E', 'S', 'T', '\0' }, { 'E', 'T', 'C', '\0' }, { 'E', 'V', 'A', '\0' }, { 'E', 'V', 'E', '\0' }, { 'E', 'W', 'E', '\0' }, { 'E', 'Y', 'E', '\0' }, { 'F', 'A', 'D', '\0' }, { 'F', 'A', 'N', '\0' }, { 'F', 'A', 'R', '\0' }, { 'F', 'A', 'T', '\0' }, { 'F', 'A', 'Y', '\0' }, { 'F', 'E', 'D', '\0' }, { 'F', 'E', 'E', '\0' }, { 'F', 'E', 'W', '\0' }, { 'F', 'I', 'B', '\0' }, { 'F', 'I', 'G', '\0' }, { 'F', 'I', 'N', '\0' }, { 'F', 'I', 'R', '\0' }, { 'F', 'I', 'T', '\0' }, { 'F', 'L', 'O', '\0' }, { 'F', 'L', 'Y', '\0' }, { 'F', 'O', 'E', '\0' }, { 'F', 'O', 'G', '\0' }, { 'F', 'O', 'R', '\0' }, { 'F', 'R', 'Y', '\0' }, { 'F', 'U', 'M', '\0' }, { 'F', 'U', 'N', '\0' }, { 'F', 'U', 'R', '\0' }, { 'G', 'A', 'B', '\0' }, { 'G', 'A', 'D', '\0' }, { 'G', 'A', 'G', '\0' }, { 'G', 'A', 'L', '\0' }, { 'G', 'A', 'M', '\0' }, { 'G', 'A', 'P', '\0' }, { 'G', 'A', 'S', '\0' }, { 'G', 'A', 'Y', '\0' }, { 'G', 'E', 'E', '\0' }, { 'G', 'E', 'L', '\0' }, { 'G', 'E', 'M', '\0' }, { 'G', 'E', 'T', '\0' }, { 'G', 'I', 'G', '\0' }, { 'G', 'I', 'L', '\0' }, { 'G', 'I', 'N', '\0' }, { 'G', 'O', '\0', '\0' }, { 'G', 'O', 'T', '\0' }, { 'G', 'U', 'M', '\0' }, { 'G', 'U', 'N', '\0' }, { 'G', 'U', 'S', '\0' }, { 'G', 'U', 'T', '\0' }, { 'G', 'U', 'Y', '\0' }, { 'G', 'Y', 'M', '\0' }, { 'G', 'Y', 'P', '\0' }, { 'H', 'A', '\0', '\0' }, { 'H', 'A', 'D', '\0' }, { 'H', 'A', 'L', '\0' }, { 'H', 'A', 'M', '\0' }, { 'H', 'A', 'N', '\0' }, { 'H', 'A', 'P', '\0' }, { 'H', 'A', 'S', '\0' }, { 'H', 'A', 'T', '\0' }, { 'H', 'A', 'W', '\0' }, { 'H', 'A', 'Y', '\0' }, { 'H', 'E', '\0', '\0' }, { 'H', 'E', 'M', '\0' }, { 'H', 'E', 'N', '\0' }, { 'H', 'E', 'R', '\0' }, { 'H', 'E', 'W', '\0' }, { 'H', 'E', 'Y', '\0' }, { 'H', 'I', '\0', '\0' }, { 'H', 'I', 'D', '\0' }, { 'H', 'I', 'M', '\0' }, { 'H', 'I', 'P', '\0' }, { 'H', 'I', 'S', '\0' }, { 'H', 'I', 'T', '\0' }, { 'H', 'O', '\0', '\0' }, { 'H', 'O', 'B', '\0' }, { 'H', 'O', 'C', '\0' }, { 'H', 'O', 'E', '\0' }, { 'H', 'O', 'G', '\0' }, { 'H', 'O', 'P', '\0' }, { 'H', 'O', 'T', '\0' }, { 'H', 'O', 'W', '\0' }, { 'H', 'U', 'B', '\0' }, { 'H', 'U', 'E', '\0' }, { 'H', 'U', 'G', '\0' }, { 'H', 'U', 'H', '\0' }, { 'H', 'U', 'M', '\0' }, { 'H', 'U', 'T', '\0' }, { 'I', '\0', '\0', '\0' }, { 'I', 'C', 'Y', '\0' }, { 'I', 'D', 'A', '\0' }, { 'I', 'F', '\0', '\0' }, { 'I', 'K', 'E', '\0' }, { 'I', 'L', 'L', '\0' }, { 'I', 'N', 'K', '\0' }, { 'I', 'N', 'N', '\0' }, { 'I', 'O', '\0', '\0' }, { 'I', 'O', 'N', '\0' }, { 'I', 'Q', '\0', '\0' }, { 'I', 'R', 'A', '\0' }, { 'I', 'R', 'E', '\0' }, { 'I', 'R', 'K', '\0' }, { 'I', 'S', '\0', '\0' }, { 'I', 'T', '\0', '\0' }, { 'I', 'T', 'S', '\0' }, { 'I', 'V', 'Y', '\0' }, { 'J', 'A', 'B', '\0' }, { 'J', 'A', 'G', '\0' }, { 'J', 'A', 'M', '\0' }, { 'J', 'A', 'N', '\0' }, { 'J', 'A', 'R', '\0' }, { 'J', 'A', 'W', '\0' }, { 'J', 'A', 'Y', '\0' }, { 'J', 'E', 'T', '\0' }, { 'J', 'I', 'G', '\0' }, { 'J', 'I', 'M', '\0' }, { 'J', 'O', '\0', '\0' }, { 'J', 'O', 'B', '\0' }, { 'J', 'O', 'E', '\0' }, { 'J', 'O', 'G', '\0' }, { 'J', 'O', 'T', '\0' }, { 'J', 'O', 'Y', '\0' }, { 'J', 'U', 'G', '\0' }, { 'J', 'U', 'T', '\0' }, { 'K', 'A', 'Y', '\0' }, { 'K', 'E', 'G', '\0' }, { 'K', 'E', 'N', '\0' }, { 'K', 'E', 'Y', '\0' }, { 'K', 'I', 'D', '\0' }, { 'K', 'I', 'M', '\0' }, { 'K', 'I', 'N', '\0' }, { 'K', 'I', 'T', '\0' }, { 'L', 'A', '\0', '\0' }, { 'L', 'A', 'B', '\0' }, { 'L', 'A', 'C', '\0' }, { 'L', 'A', 'D', '\0' }, { 'L', 'A', 'G', '\0' }, { 'L', 'A', 'M', '\0' }, { 'L', 'A', 'P', '\0' }, { 'L', 'A', 'W', '\0' }, { 'L', 'A', 'Y', '\0' }, { 'L', 'E', 'A', '\0' }, { 'L', 'E', 'D', '\0' }, { 'L', 'E', 'E', '\0' }, { 'L', 'E', 'G', '\0' }, { 'L', 'E', 'N', '\0' }, { 'L', 'E', 'O', '\0' }, { 'L', 'E', 'T', '\0' }, { 'L', 'E', 'W', '\0' }, { 'L', 'I', 'D', '\0' }, { 'L', 'I', 'E', '\0' }, { 'L', 'I', 'N', '\0' }, { 'L', 'I', 'P', '\0' }, { 'L', 'I', 'T', '\0' }, { 'L', 'O', '\0', '\0' }, { 'L', 'O', 'B', '\0' }, { 'L', 'O', 'G', '\0' }, { 'L', 'O', 'P', '\0' }, { 'L', 'O', 'S', '\0' }, { 'L', 'O', 'T', '\0' }, { 'L', 'O', 'U', '\0' }, { 'L', 'O', 'W', '\0' }, { 'L', 'O', 'Y', '\0' }, { 'L', 'U', 'G', '\0' }, { 'L', 'Y', 'E', '\0' }, { 'M', 'A', '\0', '\0' }, { 'M', 'A', 'C', '\0' }, { 'M', 'A', 'D', '\0' }, { 'M', 'A', 'E', '\0' }, { 'M', 'A', 'N', '\0' }, { 'M', 'A', 'O', '\0' }, { 'M', 'A', 'P', '\0' }, { 'M', 'A', 'T', '\0' }, { 'M', 'A', 'W', '\0' }, { 'M', 'A', 'Y', '\0' }, { 'M', 'E', '\0', '\0' }, { 'M', 'E', 'G', '\0' }, { 'M', 'E', 'L', '\0' }, { 'M', 'E', 'N', '\0' }, { 'M', 'E', 'T', '\0' }, { 'M', 'E', 'W', '\0' }, { 'M', 'I', 'D', '\0' }, { 'M', 'I', 'N', '\0' }, { 'M', 'I', 'T', '\0' }, { 'M', 'O', 'B', '\0' }, { 'M', 'O', 'D', '\0' }, { 'M', 'O', 'E', '\0' }, { 'M', 'O', 'O', '\0' }, { 'M', 'O', 'P', '\0' }, { 'M', 'O', 'S', '\0' }, { 'M', 'O', 'T', '\0' }, { 'M', 'O', 'W', '\0' }, { 'M', 'U', 'D', '\0' }, { 'M', 'U', 'G', '\0' }, { 'M', 'U', 'M', '\0' }, { 'M', 'Y', '\0', '\0' }, { 'N', 'A', 'B', '\0' }, { 'N', 'A', 'G', '\0' }, { 'N', 'A', 'N', '\0' }, { 'N', 'A', 'P', '\0' }, { 'N', 'A', 'T', '\0' }, { 'N', 'A', 'Y', '\0' }, { 'N', 'E', '\0', '\0' }, { 'N', 'E', 'D', '\0' }, { 'N', 'E', 'E', '\0' }, { 'N', 'E', 'T', '\0' }, { 'N', 'E', 'W', '\0' }, { 'N', 'I', 'B', '\0' }, { 'N', 'I', 'L', '\0' }, { 'N', 'I', 'P', '\0' }, { 'N', 'I', 'T', '\0' }, { 'N', 'O', '\0', '\0' }, { 'N', 'O', 'B', '\0' }, { 'N', 'O', 'D', '\0' }, { 'N', 'O', 'N', '\0' }, { 'N', 'O', 'R', '\0' }, { 'N', 'O', 'T', '\0' }, { 'N', 'O', 'V', '\0' }, { 'N', 'O', 'W', '\0' }, { 'N', 'U', '\0', '\0' }, { 'N', 'U', 'N', '\0' }, { 'N', 'U', 'T', '\0' }, { 'O', '\0', '\0', '\0' }, { 'O', 'A', 'F', '\0' }, { 'O', 'A', 'K', '\0' }, { 'O', 'A', 'R', '\0' }, { 'O', 'A', 'T', '\0' }, { 'O', 'D', 'D', '\0' }, { 'O', 'D', 'E', '\0' }, { 'O', 'F', '\0', '\0' }, { 'O', 'F', 'F', '\0' }, { 'O', 'F', 'T', '\0' }, { 'O', 'H', '\0', '\0' }, { 'O', 'I', 'L', '\0' }, { 'O', 'K', '\0', '\0' }, { 'O', 'L', 'D', '\0' }, { 'O', 'N', '\0', '\0' }, { 'O', 'N', 'E', '\0' }, { 'O', 'R', '\0', '\0' }, { 'O', 'R', 'B', '\0' }, { 'O', 'R', 'E', '\0' }, { 'O', 'R', 'R', '\0' }, { 'O', 'S', '\0', '\0' }, { 'O', 'T', 'T', '\0' }, { 'O', 'U', 'R', '\0' }, { 'O', 'U', 'T', '\0' }, { 'O', 'V', 'A', '\0' }, { 'O', 'W', '\0', '\0' }, { 'O', 'W', 'E', '\0' }, { 'O', 'W', 'L', '\0' }, { 'O', 'W', 'N', '\0' }, { 'O', 'X', '\0', '\0' }, { 'P', 'A', '\0', '\0' }, { 'P', 'A', 'D', '\0' }, { 'P', 'A', 'L', '\0' }, { 'P', 'A', 'M', '\0' }, { 'P', 'A', 'N', '\0' }, { 'P', 'A', 'P', '\0' }, { 'P', 'A', 'R', '\0' }, { 'P', 'A', 'T', '\0' }, { 'P', 'A', 'W', '\0' }, { 'P', 'A', 'Y', '\0' }, { 'P', 'E', 'A', '\0' }, { 'P', 'E', 'G', '\0' }, { 'P', 'E', 'N', '\0' }, { 'P', 'E', 'P', '\0' }, { 'P', 'E', 'R', '\0' }, { 'P', 'E', 'T', '\0' }, { 'P', 'E', 'W', '\0' }, { 'P', 'H', 'I', '\0' }, { 'P', 'I', '\0', '\0' }, { 'P', 'I', 'E', '\0' }, { 'P', 'I', 'N', '\0' }, { 'P', 'I', 'T', '\0' }, { 'P', 'L', 'Y', '\0' }, { 'P', 'O', '\0', '\0' }, { 'P', 'O', 'D', '\0' }, { 'P', 'O', 'E', '\0' }, { 'P', 'O', 'P', '\0' }, { 'P', 'O', 'T', '\0' }, { 'P', 'O', 'W', '\0' }, { 'P', 'R', 'O', '\0' }, { 'P', 'R', 'Y', '\0' }, { 'P', 'U', 'B', '\0' }, { 'P', 'U', 'G', '\0' }, { 'P', 'U', 'N', '\0' }, { 'P', 'U', 'P', '\0' }, { 'P', 'U', 'T', '\0' }, { 'Q', 'U', 'O', '\0' }, { 'R', 'A', 'G', '\0' }, { 'R', 'A', 'M', '\0' }, { 'R', 'A', 'N', '\0' }, { 'R', 'A', 'P', '\0' }, { 'R', 'A', 'T', '\0' }, { 'R', 'A', 'W', '\0' }, { 'R', 'A', 'Y', '\0' }, { 'R', 'E', 'B', '\0' }, { 'R', 'E', 'D', '\0' }, { 'R', 'E', 'P', '\0' }, { 'R', 'E', 'T', '\0' }, { 'R', 'I', 'B', '\0' }, { 'R', 'I', 'D', '\0' }, { 'R', 'I', 'G', '\0' }, { 'R', 'I', 'M', '\0' }, { 'R', 'I', 'O', '\0' }, { 'R', 'I', 'P', '\0' }, { 'R', 'O', 'B', '\0' }, { 'R', 'O', 'D', '\0' }, { 'R', 'O', 'E', '\0' }, { 'R', 'O', 'N', '\0' }, { 'R', 'O', 'T', '\0' }, { 'R', 'O', 'W', '\0' }, { 'R', 'O', 'Y', '\0' }, { 'R', 'U', 'B', '\0' }, { 'R', 'U', 'E', '\0' }, { 'R', 'U', 'G', '\0' }, { 'R', 'U', 'M', '\0' }, { 'R', 'U', 'N', '\0' }, { 'R', 'Y', 'E', '\0' }, { 'S', 'A', 'C', '\0' }, { 'S', 'A', 'D', '\0' }, { 'S', 'A', 'G', '\0' }, { 'S', 'A', 'L', '\0' }, { 'S', 'A', 'M', '\0' }, { 'S', 'A', 'N', '\0' }, { 'S', 'A', 'P', '\0' }, { 'S', 'A', 'T', '\0' }, { 'S', 'A', 'W', '\0' }, { 'S', 'A', 'Y', '\0' }, { 'S', 'E', 'A', '\0' }, { 'S', 'E', 'C', '\0' }, { 'S', 'E', 'E', '\0' }, { 'S', 'E', 'N', '\0' }, { 'S', 'E', 'T', '\0' }, { 'S', 'E', 'W', '\0' }, { 'S', 'H', 'E', '\0' }, { 'S', 'H', 'Y', '\0' }, { 'S', 'I', 'N', '\0' }, { 'S', 'I', 'P', '\0' }, { 'S', 'I', 'R', '\0' }, { 'S', 'I', 'S', '\0' }, { 'S', 'I', 'T', '\0' }, { 'S', 'K', 'I', '\0' }, { 'S', 'K', 'Y', '\0' }, { 'S', 'L', 'Y', '\0' }, { 'S', 'O', '\0', '\0' }, { 'S', 'O', 'B', '\0' }, { 'S', 'O', 'D', '\0' }, { 'S', 'O', 'N', '\0' }, { 'S', 'O', 'P', '\0' }, { 'S', 'O', 'W', '\0' }, { 'S', 'O', 'Y', '\0' }, { 'S', 'P', 'A', '\0' }, { 'S', 'P', 'Y', '\0' }, { 'S', 'U', 'B', '\0' }, { 'S', 'U', 'D', '\0' }, { 'S', 'U', 'E', '\0' }, { 'S', 'U', 'M', '\0' }, { 'S', 'U', 'N', '\0' }, { 'S', 'U', 'P', '\0' }, { 'T', 'A', 'B', '\0' }, { 'T', 'A', 'D', '\0' }, { 'T', 'A', 'G', '\0' }, { 'T', 'A', 'N', '\0' }, { 'T', 'A', 'P', '\0' }, { 'T', 'A', 'R', '\0' }, { 'T', 'E', 'A', '\0' }, { 'T', 'E', 'D', '\0' }, { 'T', 'E', 'E', '\0' }, { 'T', 'E', 'N', '\0' }, { 'T', 'H', 'E', '\0' }, { 'T', 'H', 'Y', '\0' }, { 'T', 'I', 'C', '\0' }, { 'T', 'I', 'E', '\0' }, { 'T', 'I', 'M', '\0' }, { 'T', 'I', 'N', '\0' }, { 'T', 'I', 'P', '\0' }, { 'T', 'O', '\0', '\0' }, { 'T', 'O', 'E', '\0' }, { 'T', 'O', 'G', '\0' }, { 'T', 'O', 'M', '\0' }, { 'T', 'O', 'N', '\0' }, { 'T', 'O', 'O', '\0' }, { 'T', 'O', 'P', '\0' }, { 'T', 'O', 'W', '\0' }, { 'T', 'O', 'Y', '\0' }, { 'T', 'R', 'Y', '\0' }, { 'T', 'U', 'B', '\0' }, { 'T', 'U', 'G', '\0' }, { 'T', 'U', 'M', '\0' }, { 'T', 'U', 'N', '\0' }, { 'T', 'W', 'O', '\0' }, { 'U', 'N', '\0', '\0' }, { 'U', 'P', '\0', '\0' }, { 'U', 'S', '\0', '\0' }, { 'U', 'S', 'E', '\0' }, { 'V', 'A', 'N', '\0' }, { 'V', 'A', 'T', '\0' }, { 'V', 'E', 'T', '\0' }, { 'V', 'I', 'E', '\0' }, { 'W', 'A', 'D', '\0' }, { 'W', 'A', 'G', '\0' }, { 'W', 'A', 'R', '\0' }, { 'W', 'A', 'S', '\0' }, { 'W', 'A', 'Y', '\0' }, { 'W', 'E', '\0', '\0' }, { 'W', 'E', 'B', '\0' }, { 'W', 'E', 'D', '\0' }, { 'W', 'E', 'E', '\0' }, { 'W', 'E', 'T', '\0' }, { 'W', 'H', 'O', '\0' }, { 'W', 'H', 'Y', '\0' }, { 'W', 'I', 'N', '\0' }, { 'W', 'I', 'T', '\0' }, { 'W', 'O', 'K', '\0' }, { 'W', 'O', 'N', '\0' }, { 'W', 'O', 'O', '\0' }, { 'W', 'O', 'W', '\0' }, { 'W', 'R', 'Y', '\0' }, { 'W', 'U', '\0', '\0' }, { 'Y', 'A', 'M', '\0' }, { 'Y', 'A', 'P', '\0' }, { 'Y', 'A', 'W', '\0' }, { 'Y', 'E', '\0', '\0' }, { 'Y', 'E', 'A', '\0' }, { 'Y', 'E', 'S', '\0' }, { 'Y', 'E', 'T', '\0' }, { 'Y', 'O', 'U', '\0' }, { 'A', 'B', 'E', 'D' }, { 'A', 'B', 'E', 'L' }, { 'A', 'B', 'E', 'T' }, { 'A', 'B', 'L', 'E' }, { 'A', 'B', 'U', 'T' }, { 'A', 'C', 'H', 'E' }, { 'A', 'C', 'I', 'D' }, { 'A', 'C', 'M', 'E' }, { 'A', 'C', 'R', 'E' }, { 'A', 'C', 'T', 'A' }, { 'A', 'C', 'T', 'S' }, { 'A', 'D', 'A', 'M' }, { 'A', 'D', 'D', 'S' }, { 'A', 'D', 'E', 'N' }, { 'A', 'F', 'A', 'R' }, { 'A', 'F', 'R', 'O' }, { 'A', 'G', 'E', 'E' }, { 'A', 'H', 'E', 'M' }, { 'A', 'H', 'O', 'Y' }, { 'A', 'I', 'D', 'A' }, { 'A', 'I', 'D', 'E' }, { 'A', 'I', 'D', 'S' }, { 'A', 'I', 'R', 'Y' }, { 'A', 'J', 'A', 'R' }, { 'A', 'K', 'I', 'N' }, { 'A', 'L', 'A', 'N' }, { 'A', 'L', 'E', 'C' }, { 'A', 'L', 'G', 'A' }, { 'A', 'L', 'I', 'A' }, { 'A', 'L', 'L', 'Y' }, { 'A', 'L', 'M', 'A' }, { 'A', 'L', 'O', 'E' }, { 'A', 'L', 'S', 'O' }, { 'A', 'L', 'T', 'O' }, { 'A', 'L', 'U', 'M' }, { 'A', 'L', 'V', 'A' }, { 'A', 'M', 'E', 'N' }, { 'A', 'M', 'E', 'S' }, { 'A', 'M', 'I', 'D' }, { 'A', 'M', 'M', 'O' }, { 'A', 'M', 'O', 'K' }, { 'A', 'M', 'O', 'S' }, { 'A', 'M', 'R', 'A' }, { 'A', 'N', 'D', 'Y' }, { 'A', 'N', 'E', 'W' }, { 'A', 'N', 'N', 'A' }, { 'A', 'N', 'N', 'E' }, { 'A', 'N', 'T', 'E' }, { 'A', 'N', 'T', 'I' }, { 'A', 'Q', 'U', 'A' }, { 'A', 'R', 'A', 'B' }, { 'A', 'R', 'C', 'H' }, { 'A', 'R', 'E', 'A' }, { 'A', 'R', 'G', 'O' }, { 'A', 'R', 'I', 'D' }, { 'A', 'R', 'M', 'Y' }, { 'A', 'R', 'T', 'S' }, { 'A', 'R', 'T', 'Y' }, { 'A', 'S', 'I', 'A' }, { 'A', 'S', 'K', 'S' }, { 'A', 'T', 'O', 'M' }, { 'A', 'U', 'N', 'T' }, { 'A', 'U', 'R', 'A' }, { 'A', 'U', 'T', 'O' }, { 'A', 'V', 'E', 'R' }, { 'A', 'V', 'I', 'D' }, { 'A', 'V', 'I', 'S' }, { 'A', 'V', 'O', 'N' }, { 'A', 'V', 'O', 'W' }, { 'A', 'W', 'A', 'Y' }, { 'A', 'W', 'R', 'Y' }, { 'B', 'A', 'B', 'E' }, { 'B', 'A', 'B', 'Y' }, { 'B', 'A', 'C', 'H' }, { 'B', 'A', 'C', 'K' }, { 'B', 'A', 'D', 'E' }, { 'B', 'A', 'I', 'L' }, { 'B', 'A', 'I', 'T' }, { 'B', 'A', 'K', 'E' }, { 'B', 'A', 'L', 'D' }, { 'B', 'A', 'L', 'E' }, { 'B', 'A', 'L', 'I' }, { 'B', 'A', 'L', 'K' }, { 'B', 'A', 'L', 'L' }, { 'B', 'A', 'L', 'M' }, { 'B', 'A', 'N', 'D' }, { 'B', 'A', 'N', 'E' }, { 'B', 'A', 'N', 'G' }, { 'B', 'A', 'N', 'K' }, { 'B', 'A', 'R', 'B' }, { 'B', 'A', 'R', 'D' }, { 'B', 'A', 'R', 'E' }, { 'B', 'A', 'R', 'K' }, { 'B', 'A', 'R', 'N' }, { 'B', 'A', 'R', 'R' }, { 'B', 'A', 'S', 'E' }, { 'B', 'A', 'S', 'H' }, { 'B', 'A', 'S', 'K' }, { 'B', 'A', 'S', 'S' }, { 'B', 'A', 'T', 'E' }, { 'B', 'A', 'T', 'H' }, { 'B', 'A', 'W', 'D' }, { 'B', 'A', 'W', 'L' }, { 'B', 'E', 'A', 'D' }, { 'B', 'E', 'A', 'K' }, { 'B', 'E', 'A', 'M' }, { 'B', 'E', 'A', 'N' }, { 'B', 'E', 'A', 'R' }, { 'B', 'E', 'A', 'T' }, { 'B', 'E', 'A', 'U' }, { 'B', 'E', 'C', 'K' }, { 'B', 'E', 'E', 'F' }, { 'B', 'E', 'E', 'N' }, { 'B', 'E', 'E', 'R' }, { 'B', 'E', 'E', 'T' }, { 'B', 'E', 'L', 'A' }, { 'B', 'E', 'L', 'L' }, { 'B', 'E', 'L', 'T' }, { 'B', 'E', 'N', 'D' }, { 'B', 'E', 'N', 'T' }, { 'B', 'E', 'R', 'G' }, { 'B', 'E', 'R', 'N' }, { 'B', 'E', 'R', 'T' }, { 'B', 'E', 'S', 'S' }, { 'B', 'E', 'S', 'T' }, { 'B', 'E', 'T', 'A' }, { 'B', 'E', 'T', 'H' }, { 'B', 'H', 'O', 'Y' }, { 'B', 'I', 'A', 'S' }, { 'B', 'I', 'D', 'E' }, { 'B', 'I', 'E', 'N' }, { 'B', 'I', 'L', 'E' }, { 'B', 'I', 'L', 'K' }, { 'B', 'I', 'L', 'L' }, { 'B', 'I', 'N', 'D' }, { 'B', 'I', 'N', 'G' }, { 'B', 'I', 'R', 'D' }, { 'B', 'I', 'T', 'E' }, { 'B', 'I', 'T', 'S' }, { 'B', 'L', 'A', 'B' }, { 'B', 'L', 'A', 'T' }, { 'B', 'L', 'E', 'D' }, { 'B', 'L', 'E', 'W' }, { 'B', 'L', 'O', 'B' }, { 'B', 'L', 'O', 'C' }, { 'B', 'L', 'O', 'T' }, { 'B', 'L', 'O', 'W' }, { 'B', 'L', 'U', 'E' }, { 'B', 'L', 'U', 'M' }, { 'B', 'L', 'U', 'R' }, { 'B', 'O', 'A', 'R' }, { 'B', 'O', 'A', 'T' }, { 'B', 'O', 'C', 'A' }, { 'B', 'O', 'C', 'K' }, { 'B', 'O', 'D', 'E' }, { 'B', 'O', 'D', 'Y' }, { 'B', 'O', 'G', 'Y' }, { 'B', 'O', 'H', 'R' }, { 'B', 'O', 'I', 'L' }, { 'B', 'O', 'L', 'D' }, { 'B', 'O', 'L', 'O' }, { 'B', 'O', 'L', 'T' }, { 'B', 'O', 'M', 'B' }, { 'B', 'O', 'N', 'A' }, { 'B', 'O', 'N', 'D' }, { 'B', 'O', 'N', 'E' }, { 'B', 'O', 'N', 'G' }, { 'B', 'O', 'N', 'N' }, { 'B', 'O', 'N', 'Y' }, { 'B', 'O', 'O', 'K' }, { 'B', 'O', 'O', 'M' }, { 'B', 'O', 'O', 'N' }, { 'B', 'O', 'O', 'T' }, { 'B', 'O', 'R', 'E' }, { 'B', 'O', 'R', 'G' }, { 'B', 'O', 'R', 'N' }, { 'B', 'O', 'S', 'E' }, { 'B', 'O', 'S', 'S' }, { 'B', 'O', 'T', 'H' }, { 'B', 'O', 'U', 'T' }, { 'B', 'O', 'W', 'L' }, { 'B', 'O', 'Y', 'D' }, { 'B', 'R', 'A', 'D' }, { 'B', 'R', 'A', 'E' }, { 'B', 'R', 'A', 'G' }, { 'B', 'R', 'A', 'N' }, { 'B', 'R', 'A', 'Y' }, { 'B', 'R', 'E', 'D' }, { 'B', 'R', 'E', 'W' }, { 'B', 'R', 'I', 'G' }, { 'B', 'R', 'I', 'M' }, { 'B', 'R', 'O', 'W' }, { 'B', 'U', 'C', 'K' }, { 'B', 'U', 'D', 'D' }, { 'B', 'U', 'F', 'F' }, { 'B', 'U', 'L', 'B' }, { 'B', 'U', 'L', 'K' }, { 'B', 'U', 'L', 'L' }, { 'B', 'U', 'N', 'K' }, { 'B', 'U', 'N', 'T' }, { 'B', 'U', 'O', 'Y' }, { 'B', 'U', 'R', 'G' }, { 'B', 'U', 'R', 'L' }, { 'B', 'U', 'R', 'N' }, { 'B', 'U', 'R', 'R' }, { 'B', 'U', 'R', 'T' }, { 'B', 'U', 'R', 'Y' }, { 'B', 'U', 'S', 'H' }, { 'B', 'U', 'S', 'S' }, { 'B', 'U', 'S', 'T' }, { 'B', 'U', 'S', 'Y' }, { 'B', 'Y', 'T', 'E' }, { 'C', 'A', 'D', 'Y' }, { 'C', 'A', 'F', 'E' }, { 'C', 'A', 'G', 'E' }, { 'C', 'A', 'I', 'N' }, { 'C', 'A', 'K', 'E' }, { 'C', 'A', 'L', 'F' }, { 'C', 'A', 'L', 'L' }, { 'C', 'A', 'L', 'M' }, { 'C', 'A', 'M', 'E' }, { 'C', 'A', 'N', 'E' }, { 'C', 'A', 'N', 'T' }, { 'C', 'A', 'R', 'D' }, { 'C', 'A', 'R', 'E' }, { 'C', 'A', 'R', 'L' }, { 'C', 'A', 'R', 'R' }, { 'C', 'A', 'R', 'T' }, { 'C', 'A', 'S', 'E' }, { 'C', 'A', 'S', 'H' }, { 'C', 'A', 'S', 'K' }, { 'C', 'A', 'S', 'T' }, { 'C', 'A', 'V', 'E' }, { 'C', 'E', 'I', 'L' }, { 'C', 'E', 'L', 'L' }, { 'C', 'E', 'N', 'T' }, { 'C', 'E', 'R', 'N' }, { 'C', 'H', 'A', 'D' }, { 'C', 'H', 'A', 'R' }, { 'C', 'H', 'A', 'T' }, { 'C', 'H', 'A', 'W' }, { 'C', 'H', 'E', 'F' }, { 'C', 'H', 'E', 'N' }, { 'C', 'H', 'E', 'W' }, { 'C', 'H', 'I', 'C' }, { 'C', 'H', 'I', 'N' }, { 'C', 'H', 'O', 'U' }, { 'C', 'H', 'O', 'W' }, { 'C', 'H', 'U', 'B' }, { 'C', 'H', 'U', 'G' }, { 'C', 'H', 'U', 'M' }, { 'C', 'I', 'T', 'E' }, { 'C', 'I', 'T', 'Y' }, { 'C', 'L', 'A', 'D' }, { 'C', 'L', 'A', 'M' }, { 'C', 'L', 'A', 'N' }, { 'C', 'L', 'A', 'W' }, { 'C', 'L', 'A', 'Y' }, { 'C', 'L', 'O', 'D' }, { 'C', 'L', 'O', 'G' }, { 'C', 'L', 'O', 'T' }, { 'C', 'L', 'U', 'B' }, { 'C', 'L', 'U', 'E' }, { 'C', 'O', 'A', 'L' }, { 'C', 'O', 'A', 'T' }, { 'C', 'O', 'C', 'A' }, { 'C', 'O', 'C', 'K' }, { 'C', 'O', 'C', 'O' }, { 'C', 'O', 'D', 'A' }, { 'C', 'O', 'D', 'E' }, { 'C', 'O', 'D', 'Y' }, { 'C', 'O', 'E', 'D' }, { 'C', 'O', 'I', 'L' }, { 'C', 'O', 'I', 'N' }, { 'C', 'O', 'K', 'E' }, { 'C', 'O', 'L', 'A' }, { 'C', 'O', 'L', 'D' }, { 'C', 'O', 'L', 'T' }, { 'C', 'O', 'M', 'A' }, { 'C', 'O', 'M', 'B' }, { 'C', 'O', 'M', 'E' }, { 'C', 'O', 'O', 'K' }, { 'C', 'O', 'O', 'L' }, { 'C', 'O', 'O', 'N' }, { 'C', 'O', 'O', 'T' }, { 'C', 'O', 'R', 'D' }, { 'C', 'O', 'R', 'E' }, { 'C', 'O', 'R', 'K' }, { 'C', 'O', 'R', 'N' }, { 'C', 'O', 'S', 'T' }, { 'C', 'O', 'V', 'E' }, { 'C', 'O', 'W', 'L' }, { 'C', 'R', 'A', 'B' }, { 'C', 'R', 'A', 'G' }, { 'C', 'R', 'A', 'M' }, { 'C', 'R', 'A', 'Y' }, { 'C', 'R', 'E', 'W' }, { 'C', 'R', 'I', 'B' }, { 'C', 'R', 'O', 'W' }, { 'C', 'R', 'U', 'D' }, { 'C', 'U', 'B', 'A' }, { 'C', 'U', 'B', 'E' }, { 'C', 'U', 'F', 'F' }, { 'C', 'U', 'L', 'L' }, { 'C', 'U', 'L', 'T' }, { 'C', 'U', 'N', 'Y' }, { 'C', 'U', 'R', 'B' }, { 'C', 'U', 'R', 'D' }, { 'C', 'U', 'R', 'E' }, { 'C', 'U', 'R', 'L' }, { 'C', 'U', 'R', 'T' }, { 'C', 'U', 'T', 'S' }, { 'D', 'A', 'D', 'E' }, { 'D', 'A', 'L', 'E' }, { 'D', 'A', 'M', 'E' }, { 'D', 'A', 'N', 'A' }, { 'D', 'A', 'N', 'E' }, { 'D', 'A', 'N', 'G' }, { 'D', 'A', 'N', 'K' }, { 'D', 'A', 'R', 'E' }, { 'D', 'A', 'R', 'K' }, { 'D', 'A', 'R', 'N' }, { 'D', 'A', 'R', 'T' }, { 'D', 'A', 'S', 'H' }, { 'D', 'A', 'T', 'A' }, { 'D', 'A', 'T', 'E' }, { 'D', 'A', 'V', 'E' }, { 'D', 'A', 'V', 'Y' }, { 'D', 'A', 'W', 'N' }, { 'D', 'A', 'Y', 'S' }, { 'D', 'E', 'A', 'D' }, { 'D', 'E', 'A', 'F' }, { 'D', 'E', 'A', 'L' }, { 'D', 'E', 'A', 'N' }, { 'D', 'E', 'A', 'R' }, { 'D', 'E', 'B', 'T' }, { 'D', 'E', 'C', 'K' }, { 'D', 'E', 'E', 'D' }, { 'D', 'E', 'E', 'M' }, { 'D', 'E', 'E', 'R' }, { 'D', 'E', 'F', 'T' }, { 'D', 'E', 'F', 'Y' }, { 'D', 'E', 'L', 'L' }, { 'D', 'E', 'N', 'T' }, { 'D', 'E', 'N', 'Y' }, { 'D', 'E', 'S', 'K' }, { 'D', 'I', 'A', 'L' }, { 'D', 'I', 'C', 'E' }, { 'D', 'I', 'E', 'D' }, { 'D', 'I', 'E', 'T' }, { 'D', 'I', 'M', 'E' }, { 'D', 'I', 'N', 'E' }, { 'D', 'I', 'N', 'G' }, { 'D', 'I', 'N', 'T' }, { 'D', 'I', 'R', 'E' }, { 'D', 'I', 'R', 'T' }, { 'D', 'I', 'S', 'C' }, { 'D', 'I', 'S', 'H' }, { 'D', 'I', 'S', 'K' }, { 'D', 'I', 'V', 'E' }, { 'D', 'O', 'C', 'K' }, { 'D', 'O', 'E', 'S' }, { 'D', 'O', 'L', 'E' }, { 'D', 'O', 'L', 'L' }, { 'D', 'O', 'L', 'T' }, { 'D', 'O', 'M', 'E' }, { 'D', 'O', 'N', 'E' }, { 'D', 'O', 'O', 'M' }, { 'D', 'O', 'O', 'R' }, { 'D', 'O', 'R', 'A' }, { 'D', 'O', 'S', 'E' }, { 'D', 'O', 'T', 'E' }, { 'D', 'O', 'U', 'G' }, { 'D', 'O', 'U', 'R' }, { 'D', 'O', 'V', 'E' }, { 'D', 'O', 'W', 'N' }, { 'D', 'R', 'A', 'B' }, { 'D', 'R', 'A', 'G' }, { 'D', 'R', 'A', 'M' }, { 'D', 'R', 'A', 'W' }, { 'D', 'R', 'E', 'W' }, { 'D', 'R', 'U', 'B' }, { 'D', 'R', 'U', 'G' }, { 'D', 'R', 'U', 'M' }, { 'D', 'U', 'A', 'L' }, { 'D', 'U', 'C', 'K' }, { 'D', 'U', 'C', 'T' }, { 'D', 'U', 'E', 'L' }, { 'D', 'U', 'E', 'T' }, { 'D', 'U', 'K', 'E' }, { 'D', 'U', 'L', 'L' }, { 'D', 'U', 'M', 'B' }, { 'D', 'U', 'N', 'E' }, { 'D', 'U', 'N', 'K' }, { 'D', 'U', 'S', 'K' }, { 'D', 'U', 'S', 'T' }, { 'D', 'U', 'T', 'Y' }, { 'E', 'A', 'C', 'H' }, { 'E', 'A', 'R', 'L' }, { 'E', 'A', 'R', 'N' }, { 'E', 'A', 'S', 'E' }, { 'E', 'A', 'S', 'T' }, { 'E', 'A', 'S', 'Y' }, { 'E', 'B', 'E', 'N' }, { 'E', 'C', 'H', 'O' }, { 'E', 'D', 'D', 'Y' }, { 'E', 'D', 'E', 'N' }, { 'E', 'D', 'G', 'E' }, { 'E', 'D', 'G', 'Y' }, { 'E', 'D', 'I', 'T' }, { 'E', 'D', 'N', 'A' }, { 'E', 'G', 'A', 'N' }, { 'E', 'L', 'A', 'N' }, { 'E', 'L', 'B', 'A' }, { 'E', 'L', 'L', 'A' }, { 'E', 'L', 'S', 'E' }, { 'E', 'M', 'I', 'L' }, { 'E', 'M', 'I', 'T' }, { 'E', 'M', 'M', 'A' }, { 'E', 'N', 'D', 'S' }, { 'E', 'R', 'I', 'C' }, { 'E', 'R', 'O', 'S' }, { 'E', 'V', 'E', 'N' }, { 'E', 'V', 'E', 'R' }, { 'E', 'V', 'I', 'L' }, { 'E', 'Y', 'E', 'D' }, { 'F', 'A', 'C', 'E' }, { 'F', 'A', 'C', 'T' }, { 'F', 'A', 'D', 'E' }, { 'F', 'A', 'I', 'L' }, { 'F', 'A', 'I', 'N' }, { 'F', 'A', 'I', 'R' }, { 'F', 'A', 'K', 'E' }, { 'F', 'A', 'L', 'L' }, { 'F', 'A', 'M', 'E' }, { 'F', 'A', 'N', 'G' }, { 'F', 'A', 'R', 'M' }, { 'F', 'A', 'S', 'T' }, { 'F', 'A', 'T', 'E' }, { 'F', 'A', 'W', 'N' }, { 'F', 'E', 'A', 'R' }, { 'F', 'E', 'A', 'T' }, { 'F', 'E', 'E', 'D' }, { 'F', 'E', 'E', 'L' }, { 'F', 'E', 'E', 'T' }, { 'F', 'E', 'L', 'L' }, { 'F', 'E', 'L', 'T' }, { 'F', 'E', 'N', 'D' }, { 'F', 'E', 'R', 'N' }, { 'F', 'E', 'S', 'T' }, { 'F', 'E', 'U', 'D' }, { 'F', 'I', 'E', 'F' }, { 'F', 'I', 'G', 'S' }, { 'F', 'I', 'L', 'E' }, { 'F', 'I', 'L', 'L' }, { 'F', 'I', 'L', 'M' }, { 'F', 'I', 'N', 'D' }, { 'F', 'I', 'N', 'E' }, { 'F', 'I', 'N', 'K' }, { 'F', 'I', 'R', 'E' }, { 'F', 'I', 'R', 'M' }, { 'F', 'I', 'S', 'H' }, { 'F', 'I', 'S', 'K' }, { 'F', 'I', 'S', 'T' }, { 'F', 'I', 'T', 'S' }, { 'F', 'I', 'V', 'E' }, { 'F', 'L', 'A', 'G' }, { 'F', 'L', 'A', 'K' }, { 'F', 'L', 'A', 'M' }, { 'F', 'L', 'A', 'T' }, { 'F', 'L', 'A', 'W' }, { 'F', 'L', 'E', 'A' }, { 'F', 'L', 'E', 'D' }, { 'F', 'L', 'E', 'W' }, { 'F', 'L', 'I', 'T' }, { 'F', 'L', 'O', 'C' }, { 'F', 'L', 'O', 'G' }, { 'F', 'L', 'O', 'W' }, { 'F', 'L', 'U', 'B' }, { 'F', 'L', 'U', 'E' }, { 'F', 'O', 'A', 'L' }, { 'F', 'O', 'A', 'M' }, { 'F', 'O', 'G', 'Y' }, { 'F', 'O', 'I', 'L' }, { 'F', 'O', 'L', 'D' }, { 'F', 'O', 'L', 'K' }, { 'F', 'O', 'N', 'D' }, { 'F', 'O', 'N', 'T' }, { 'F', 'O', 'O', 'D' }, { 'F', 'O', 'O', 'L' }, { 'F', 'O', 'O', 'T' }, { 'F', 'O', 'R', 'D' }, { 'F', 'O', 'R', 'E' }, { 'F', 'O', 'R', 'K' }, { 'F', 'O', 'R', 'M' }, { 'F', 'O', 'R', 'T' }, { 'F', 'O', 'S', 'S' }, { 'F', 'O', 'U', 'L' }, { 'F', 'O', 'U', 'R' }, { 'F', 'O', 'W', 'L' }, { 'F', 'R', 'A', 'U' }, { 'F', 'R', 'A', 'Y' }, { 'F', 'R', 'E', 'D' }, { 'F', 'R', 'E', 'E' }, { 'F', 'R', 'E', 'T' }, { 'F', 'R', 'E', 'Y' }, { 'F', 'R', 'O', 'G' }, { 'F', 'R', 'O', 'M' }, { 'F', 'U', 'E', 'L' }, { 'F', 'U', 'L', 'L' }, { 'F', 'U', 'M', 'E' }, { 'F', 'U', 'N', 'D' }, { 'F', 'U', 'N', 'K' }, { 'F', 'U', 'R', 'Y' }, { 'F', 'U', 'S', 'E' }, { 'F', 'U', 'S', 'S' }, { 'G', 'A', 'F', 'F' }, { 'G', 'A', 'G', 'E' }, { 'G', 'A', 'I', 'L' }, { 'G', 'A', 'I', 'N' }, { 'G', 'A', 'I', 'T' }, { 'G', 'A', 'L', 'A' }, { 'G', 'A', 'L', 'E' }, { 'G', 'A', 'L', 'L' }, { 'G', 'A', 'L', 'T' }, { 'G', 'A', 'M', 'E' }, { 'G', 'A', 'N', 'G' }, { 'G', 'A', 'R', 'B' }, { 'G', 'A', 'R', 'Y' }, { 'G', 'A', 'S', 'H' }, { 'G', 'A', 'T', 'E' }, { 'G', 'A', 'U', 'L' }, { 'G', 'A', 'U', 'R' }, { 'G', 'A', 'V', 'E' }, { 'G', 'A', 'W', 'K' }, { 'G', 'E', 'A', 'R' }, { 'G', 'E', 'L', 'D' }, { 'G', 'E', 'N', 'E' }, { 'G', 'E', 'N', 'T' }, { 'G', 'E', 'R', 'M' }, { 'G', 'E', 'T', 'S' }, { 'G', 'I', 'B', 'E' }, { 'G', 'I', 'F', 'T' }, { 'G', 'I', 'L', 'D' }, { 'G', 'I', 'L', 'L' }, { 'G', 'I', 'L', 'T' }, { 'G', 'I', 'N', 'A' }, { 'G', 'I', 'R', 'D' }, { 'G', 'I', 'R', 'L' }, { 'G', 'I', 'S', 'T' }, { 'G', 'I', 'V', 'E' }, { 'G', 'L', 'A', 'D' }, { 'G', 'L', 'E', 'E' }, { 'G', 'L', 'E', 'N' }, { 'G', 'L', 'I', 'B' }, { 'G', 'L', 'O', 'B' }, { 'G', 'L', 'O', 'M' }, { 'G', 'L', 'O', 'W' }, { 'G', 'L', 'U', 'E' }, { 'G', 'L', 'U', 'M' }, { 'G', 'L', 'U', 'T' }, { 'G', 'O', 'A', 'D' }, { 'G', 'O', 'A', 'L' }, { 'G', 'O', 'A', 'T' }, { 'G', 'O', 'E', 'R' }, { 'G', 'O', 'E', 'S' }, { 'G', 'O', 'L', 'D' }, { 'G', 'O', 'L', 'F' }, { 'G', 'O', 'N', 'E' }, { 'G', 'O', 'N', 'G' }, { 'G', 'O', 'O', 'D' }, { 'G', 'O', 'O', 'F' }, { 'G', 'O', 'R', 'E' }, { 'G', 'O', 'R', 'Y' }, { 'G', 'O', 'S', 'H' }, { 'G', 'O', 'U', 'T' }, { 'G', 'O', 'W', 'N' }, { 'G', 'R', 'A', 'B' }, { 'G', 'R', 'A', 'D' }, { 'G', 'R', 'A', 'Y' }, { 'G', 'R', 'E', 'G' }, { 'G', 'R', 'E', 'W' }, { 'G', 'R', 'E', 'Y' }, { 'G', 'R', 'I', 'D' }, { 'G', 'R', 'I', 'M' }, { 'G', 'R', 'I', 'N' }, { 'G', 'R', 'I', 'T' }, { 'G', 'R', 'O', 'W' }, { 'G', 'R', 'U', 'B' }, { 'G', 'U', 'L', 'F' }, { 'G', 'U', 'L', 'L' }, { 'G', 'U', 'N', 'K' }, { 'G', 'U', 'R', 'U' }, { 'G', 'U', 'S', 'H' }, { 'G', 'U', 'S', 'T' }, { 'G', 'W', 'E', 'N' }, { 'G', 'W', 'Y', 'N' }, { 'H', 'A', 'A', 'G' }, { 'H', 'A', 'A', 'S' }, { 'H', 'A', 'C', 'K' }, { 'H', 'A', 'I', 'L' }, { 'H', 'A', 'I', 'R' }, { 'H', 'A', 'L', 'E' }, { 'H', 'A', 'L', 'F' }, { 'H', 'A', 'L', 'L' }, { 'H', 'A', 'L', 'O' }, { 'H', 'A', 'L', 'T' }, { 'H', 'A', 'N', 'D' }, { 'H', 'A', 'N', 'G' }, { 'H', 'A', 'N', 'K' }, { 'H', 'A', 'N', 'S' }, { 'H', 'A', 'R', 'D' }, { 'H', 'A', 'R', 'K' }, { 'H', 'A', 'R', 'M' }, { 'H', 'A', 'R', 'T' }, { 'H', 'A', 'S', 'H' }, { 'H', 'A', 'S', 'T' }, { 'H', 'A', 'T', 'E' }, { 'H', 'A', 'T', 'H' }, { 'H', 'A', 'U', 'L' }, { 'H', 'A', 'V', 'E' }, { 'H', 'A', 'W', 'K' }, { 'H', 'A', 'Y', 'S' }, { 'H', 'E', 'A', 'D' }, { 'H', 'E', 'A', 'L' }, { 'H', 'E', 'A', 'R' }, { 'H', 'E', 'A', 'T' }, { 'H', 'E', 'B', 'E' }, { 'H', 'E', 'C', 'K' }, { 'H', 'E', 'E', 'D' }, { 'H', 'E', 'E', 'L' }, { 'H', 'E', 'F', 'T' }, { 'H', 'E', 'L', 'D' }, { 'H', 'E', 'L', 'L' }, { 'H', 'E', 'L', 'M' }, { 'H', 'E', 'R', 'B' }, { 'H', 'E', 'R', 'D' }, { 'H', 'E', 'R', 'E' }, { 'H', 'E', 'R', 'O' }, { 'H', 'E', 'R', 'S' }, { 'H', 'E', 'S', 'S' }, { 'H', 'E', 'W', 'N' }, { 'H', 'I', 'C', 'K' }, { 'H', 'I', 'D', 'E' }, { 'H', 'I', 'G', 'H' }, { 'H', 'I', 'K', 'E' }, { 'H', 'I', 'L', 'L' }, { 'H', 'I', 'L', 'T' }, { 'H', 'I', 'N', 'D' }, { 'H', 'I', 'N', 'T' }, { 'H', 'I', 'R', 'E' }, { 'H', 'I', 'S', 'S' }, { 'H', 'I', 'V', 'E' }, { 'H', 'O', 'B', 'O' }, { 'H', 'O', 'C', 'K' }, { 'H', 'O', 'F', 'F' }, { 'H', 'O', 'L', 'D' }, { 'H', 'O', 'L', 'E' }, { 'H', 'O', 'L', 'M' }, { 'H', 'O', 'L', 'T' }, { 'H', 'O', 'M', 'E' }, { 'H', 'O', 'N', 'E' }, { 'H', 'O', 'N', 'K' }, { 'H', 'O', 'O', 'D' }, { 'H', 'O', 'O', 'F' }, { 'H', 'O', 'O', 'K' }, { 'H', 'O', 'O', 'T' }, { 'H', 'O', 'R', 'N' }, { 'H', 'O', 'S', 'E' }, { 'H', 'O', 'S', 'T' }, { 'H', 'O', 'U', 'R' }, { 'H', 'O', 'V', 'E' }, { 'H', 'O', 'W', 'E' }, { 'H', 'O', 'W', 'L' }, { 'H', 'O', 'Y', 'T' }, { 'H', 'U', 'C', 'K' }, { 'H', 'U', 'E', 'D' }, { 'H', 'U', 'F', 'F' }, { 'H', 'U', 'G', 'E' }, { 'H', 'U', 'G', 'H' }, { 'H', 'U', 'G', 'O' }, { 'H', 'U', 'L', 'K' }, { 'H', 'U', 'L', 'L' }, { 'H', 'U', 'N', 'K' }, { 'H', 'U', 'N', 'T' }, { 'H', 'U', 'R', 'D' }, { 'H', 'U', 'R', 'L' }, { 'H', 'U', 'R', 'T' }, { 'H', 'U', 'S', 'H' }, { 'H', 'Y', 'D', 'E' }, { 'H', 'Y', 'M', 'N' }, { 'I', 'B', 'I', 'S' }, { 'I', 'C', 'O', 'N' }, { 'I', 'D', 'E', 'A' }, { 'I', 'D', 'L', 'E' }, { 'I', 'F', 'F', 'Y' }, { 'I', 'N', 'C', 'A' }, { 'I', 'N', 'C', 'H' }, { 'I', 'N', 'T', 'O' }, { 'I', 'O', 'N', 'S' }, { 'I', 'O', 'T', 'A' }, { 'I', 'O', 'W', 'A' }, { 'I', 'R', 'I', 'S' }, { 'I', 'R', 'M', 'A' }, { 'I', 'R', 'O', 'N' }, { 'I', 'S', 'L', 'E' }, { 'I', 'T', 'C', 'H' }, { 'I', 'T', 'E', 'M' }, { 'I', 'V', 'A', 'N' }, { 'J', 'A', 'C', 'K' }, { 'J', 'A', 'D', 'E' }, { 'J', 'A', 'I', 'L' }, { 'J', 'A', 'K', 'E' }, { 'J', 'A', 'N', 'E' }, { 'J', 'A', 'V', 'A' }, { 'J', 'E', 'A', 'N' }, { 'J', 'E', 'F', 'F' }, { 'J', 'E', 'R', 'K' }, { 'J', 'E', 'S', 'S' }, { 'J', 'E', 'S', 'T' }, { 'J', 'I', 'B', 'E' }, { 'J', 'I', 'L', 'L' }, { 'J', 'I', 'L', 'T' }, { 'J', 'I', 'V', 'E' }, { 'J', 'O', 'A', 'N' }, { 'J', 'O', 'B', 'S' }, { 'J', 'O', 'C', 'K' }, { 'J', 'O', 'E', 'L' }, { 'J', 'O', 'E', 'Y' }, { 'J', 'O', 'H', 'N' }, { 'J', 'O', 'I', 'N' }, { 'J', 'O', 'K', 'E' }, { 'J', 'O', 'L', 'T' }, { 'J', 'O', 'V', 'E' }, { 'J', 'U', 'D', 'D' }, { 'J', 'U', 'D', 'E' }, { 'J', 'U', 'D', 'O' }, { 'J', 'U', 'D', 'Y' }, { 'J', 'U', 'J', 'U' }, { 'J', 'U', 'K', 'E' }, { 'J', 'U', 'L', 'Y' }, { 'J', 'U', 'N', 'E' }, { 'J', 'U', 'N', 'K' }, { 'J', 'U', 'N', 'O' }, { 'J', 'U', 'R', 'Y' }, { 'J', 'U', 'S', 'T' }, { 'J', 'U', 'T', 'E' }, { 'K', 'A', 'H', 'N' }, { 'K', 'A', 'L', 'E' }, { 'K', 'A', 'N', 'E' }, { 'K', 'A', 'N', 'T' }, { 'K', 'A', 'R', 'L' }, { 'K', 'A', 'T', 'E' }, { 'K', 'E', 'E', 'L' }, { 'K', 'E', 'E', 'N' }, { 'K', 'E', 'N', 'O' }, { 'K', 'E', 'N', 'T' }, { 'K', 'E', 'R', 'N' }, { 'K', 'E', 'R', 'R' }, { 'K', 'E', 'Y', 'S' }, { 'K', 'I', 'C', 'K' }, { 'K', 'I', 'L', 'L' }, { 'K', 'I', 'N', 'D' }, { 'K', 'I', 'N', 'G' }, { 'K', 'I', 'R', 'K' }, { 'K', 'I', 'S', 'S' }, { 'K', 'I', 'T', 'E' }, { 'K', 'L', 'A', 'N' }, { 'K', 'N', 'E', 'E' }, { 'K', 'N', 'E', 'W' }, { 'K', 'N', 'I', 'T' }, { 'K', 'N', 'O', 'B' }, { 'K', 'N', 'O', 'T' }, { 'K', 'N', 'O', 'W' }, { 'K', 'O', 'C', 'H' }, { 'K', 'O', 'N', 'G' }, { 'K', 'U', 'D', 'O' }, { 'K', 'U', 'R', 'D' }, { 'K', 'U', 'R', 'T' }, { 'K', 'Y', 'L', 'E' }, { 'L', 'A', 'C', 'E' }, { 'L', 'A', 'C', 'K' }, { 'L', 'A', 'C', 'Y' }, { 'L', 'A', 'D', 'Y' }, { 'L', 'A', 'I', 'D' }, { 'L', 'A', 'I', 'N' }, { 'L', 'A', 'I', 'R' }, { 'L', 'A', 'K', 'E' }, { 'L', 'A', 'M', 'B' }, { 'L', 'A', 'M', 'E' }, { 'L', 'A', 'N', 'D' }, { 'L', 'A', 'N', 'E' }, { 'L', 'A', 'N', 'G' }, { 'L', 'A', 'R', 'D' }, { 'L', 'A', 'R', 'K' }, { 'L', 'A', 'S', 'S' }, { 'L', 'A', 'S', 'T' }, { 'L', 'A', 'T', 'E' }, { 'L', 'A', 'U', 'D' }, { 'L', 'A', 'V', 'A' }, { 'L', 'A', 'W', 'N' }, { 'L', 'A', 'W', 'S' }, { 'L', 'A', 'Y', 'S' }, { 'L', 'E', 'A', 'D' }, { 'L', 'E', 'A', 'F' }, { 'L', 'E', 'A', 'K' }, { 'L', 'E', 'A', 'N' }, { 'L', 'E', 'A', 'R' }, { 'L', 'E', 'E', 'K' }, { 'L', 'E', 'E', 'R' }, { 'L', 'E', 'F', 'T' }, { 'L', 'E', 'N', 'D' }, { 'L', 'E', 'N', 'S' }, { 'L', 'E', 'N', 'T' }, { 'L', 'E', 'O', 'N' }, { 'L', 'E', 'S', 'K' }, { 'L', 'E', 'S', 'S' }, { 'L', 'E', 'S', 'T' }, { 'L', 'E', 'T', 'S' }, { 'L', 'I', 'A', 'R' }, { 'L', 'I', 'C', 'E' }, { 'L', 'I', 'C', 'K' }, { 'L', 'I', 'E', 'D' }, { 'L', 'I', 'E', 'N' }, { 'L', 'I', 'E', 'S' }, { 'L', 'I', 'E', 'U' }, { 'L', 'I', 'F', 'E' }, { 'L', 'I', 'F', 'T' }, { 'L', 'I', 'K', 'E' }, { 'L', 'I', 'L', 'A' }, { 'L', 'I', 'L', 'T' }, { 'L', 'I', 'L', 'Y' }, { 'L', 'I', 'M', 'A' }, { 'L', 'I', 'M', 'B' }, { 'L', 'I', 'M', 'E' }, { 'L', 'I', 'N', 'D' }, { 'L', 'I', 'N', 'E' }, { 'L', 'I', 'N', 'K' }, { 'L', 'I', 'N', 'T' }, { 'L', 'I', 'O', 'N' }, { 'L', 'I', 'S', 'A' }, { 'L', 'I', 'S', 'T' }, { 'L', 'I', 'V', 'E' }, { 'L', 'O', 'A', 'D' }, { 'L', 'O', 'A', 'F' }, { 'L', 'O', 'A', 'M' }, { 'L', 'O', 'A', 'N' }, { 'L', 'O', 'C', 'K' }, { 'L', 'O', 'F', 'T' }, { 'L', 'O', 'G', 'E' }, { 'L', 'O', 'I', 'S' }, { 'L', 'O', 'L', 'A' }, { 'L', 'O', 'N', 'E' }, { 'L', 'O', 'N', 'G' }, { 'L', 'O', 'O', 'K' }, { 'L', 'O', 'O', 'N' }, { 'L', 'O', 'O', 'T' }, { 'L', 'O', 'R', 'D' }, { 'L', 'O', 'R', 'E' }, { 'L', 'O', 'S', 'E' }, { 'L', 'O', 'S', 'S' }, { 'L', 'O', 'S', 'T' }, { 'L', 'O', 'U', 'D' }, { 'L', 'O', 'V', 'E' }, { 'L', 'O', 'W', 'E' }, { 'L', 'U', 'C', 'K' }, { 'L', 'U', 'C', 'Y' }, { 'L', 'U', 'G', 'E' }, { 'L', 'U', 'K', 'E' }, { 'L', 'U', 'L', 'U' }, { 'L', 'U', 'N', 'D' }, { 'L', 'U', 'N', 'G' }, { 'L', 'U', 'R', 'A' }, { 'L', 'U', 'R', 'E' }, { 'L', 'U', 'R', 'K' }, { 'L', 'U', 'S', 'H' }, { 'L', 'U', 'S', 'T' }, { 'L', 'Y', 'L', 'E' }, { 'L', 'Y', 'N', 'N' }, { 'L', 'Y', 'O', 'N' }, { 'L', 'Y', 'R', 'A' }, { 'M', 'A', 'C', 'E' }, { 'M', 'A', 'D', 'E' }, { 'M', 'A', 'G', 'I' }, { 'M', 'A', 'I', 'D' }, { 'M', 'A', 'I', 'L' }, { 'M', 'A', 'I', 'N' }, { 'M', 'A', 'K', 'E' }, { 'M', 'A', 'L', 'E' }, { 'M', 'A', 'L', 'I' }, { 'M', 'A', 'L', 'L' }, { 'M', 'A', 'L', 'T' }, { 'M', 'A', 'N', 'A' }, { 'M', 'A', 'N', 'N' }, { 'M', 'A', 'N', 'Y' }, { 'M', 'A', 'R', 'C' }, { 'M', 'A', 'R', 'E' }, { 'M', 'A', 'R', 'K' }, { 'M', 'A', 'R', 'S' }, { 'M', 'A', 'R', 'T' }, { 'M', 'A', 'R', 'Y' }, { 'M', 'A', 'S', 'H' }, { 'M', 'A', 'S', 'K' }, { 'M', 'A', 'S', 'S' }, { 'M', 'A', 'S', 'T' }, { 'M', 'A', 'T', 'E' }, { 'M', 'A', 'T', 'H' }, { 'M', 'A', 'U', 'L' }, { 'M', 'A', 'Y', 'O' }, { 'M', 'E', 'A', 'D' }, { 'M', 'E', 'A', 'L' }, { 'M', 'E', 'A', 'N' }, { 'M', 'E', 'A', 'T' }, { 'M', 'E', 'E', 'K' }, { 'M', 'E', 'E', 'T' }, { 'M', 'E', 'L', 'D' }, { 'M', 'E', 'L', 'T' }, { 'M', 'E', 'M', 'O' }, { 'M', 'E', 'N', 'D' }, { 'M', 'E', 'N', 'U' }, { 'M', 'E', 'R', 'T' }, { 'M', 'E', 'S', 'H' }, { 'M', 'E', 'S', 'S' }, { 'M', 'I', 'C', 'E' }, { 'M', 'I', 'K', 'E' }, { 'M', 'I', 'L', 'D' }, { 'M', 'I', 'L', 'E' }, { 'M', 'I', 'L', 'K' }, { 'M', 'I', 'L', 'L' }, { 'M', 'I', 'L', 'T' }, { 'M', 'I', 'M', 'I' }, { 'M', 'I', 'N', 'D' }, { 'M', 'I', 'N', 'E' }, { 'M', 'I', 'N', 'I' }, { 'M', 'I', 'N', 'K' }, { 'M', 'I', 'N', 'T' }, { 'M', 'I', 'R', 'E' }, { 'M', 'I', 'S', 'S' }, { 'M', 'I', 'S', 'T' }, { 'M', 'I', 'T', 'E' }, { 'M', 'I', 'T', 'T' }, { 'M', 'O', 'A', 'N' }, { 'M', 'O', 'A', 'T' }, { 'M', 'O', 'C', 'K' }, { 'M', 'O', 'D', 'E' }, { 'M', 'O', 'L', 'D' }, { 'M', 'O', 'L', 'E' }, { 'M', 'O', 'L', 'L' }, { 'M', 'O', 'L', 'T' }, { 'M', 'O', 'N', 'A' }, { 'M', 'O', 'N', 'K' }, { 'M', 'O', 'N', 'T' }, { 'M', 'O', 'O', 'D' }, { 'M', 'O', 'O', 'N' }, { 'M', 'O', 'O', 'R' }, { 'M', 'O', 'O', 'T' }, { 'M', 'O', 'R', 'E' }, { 'M', 'O', 'R', 'N' }, { 'M', 'O', 'R', 'T' }, { 'M', 'O', 'S', 'S' }, { 'M', 'O', 'S', 'T' }, { 'M', 'O', 'T', 'H' }, { 'M', 'O', 'V', 'E' }, { 'M', 'U', 'C', 'H' }, { 'M', 'U', 'C', 'K' }, { 'M', 'U', 'D', 'D' }, { 'M', 'U', 'F', 'F' }, { 'M', 'U', 'L', 'E' }, { 'M', 'U', 'L', 'L' }, { 'M', 'U', 'R', 'K' }, { 'M', 'U', 'S', 'H' }, { 'M', 'U', 'S', 'T' }, { 'M', 'U', 'T', 'E' }, { 'M', 'U', 'T', 'T' }, { 'M', 'Y', 'R', 'A' }, { 'M', 'Y', 'T', 'H' }, { 'N', 'A', 'G', 'Y' }, { 'N', 'A', 'I', 'L' }, { 'N', 'A', 'I', 'R' }, { 'N', 'A', 'M', 'E' }, { 'N', 'A', 'R', 'Y' }, { 'N', 'A', 'S', 'H' }, { 'N', 'A', 'V', 'E' }, { 'N', 'A', 'V', 'Y' }, { 'N', 'E', 'A', 'L' }, { 'N', 'E', 'A', 'R' }, { 'N', 'E', 'A', 'T' }, { 'N', 'E', 'C', 'K' }, { 'N', 'E', 'E', 'D' }, { 'N', 'E', 'I', 'L' }, { 'N', 'E', 'L', 'L' }, { 'N', 'E', 'O', 'N' }, { 'N', 'E', 'R', 'O' }, { 'N', 'E', 'S', 'S' }, { 'N', 'E', 'S', 'T' }, { 'N', 'E', 'W', 'S' }, { 'N', 'E', 'W', 'T' }, { 'N', 'I', 'B', 'S' }, { 'N', 'I', 'C', 'E' }, { 'N', 'I', 'C', 'K' }, { 'N', 'I', 'L', 'E' }, { 'N', 'I', 'N', 'A' }, { 'N', 'I', 'N', 'E' }, { 'N', 'O', 'A', 'H' }, { 'N', 'O', 'D', 'E' }, { 'N', 'O', 'E', 'L' }, { 'N', 'O', 'L', 'L' }, { 'N', 'O', 'N', 'E' }, { 'N', 'O', 'O', 'K' }, { 'N', 'O', 'O', 'N' }, { 'N', 'O', 'R', 'M' }, { 'N', 'O', 'S', 'E' }, { 'N', 'O', 'T', 'E' }, { 'N', 'O', 'U', 'N' }, { 'N', 'O', 'V', 'A' }, { 'N', 'U', 'D', 'E' }, { 'N', 'U', 'L', 'L' }, { 'N', 'U', 'M', 'B' }, { 'O', 'A', 'T', 'H' }, { 'O', 'B', 'E', 'Y' }, { 'O', 'B', 'O', 'E' }, { 'O', 'D', 'I', 'N' }, { 'O', 'H', 'I', 'O' }, { 'O', 'I', 'L', 'Y' }, { 'O', 'I', 'N', 'T' }, { 'O', 'K', 'A', 'Y' }, { 'O', 'L', 'A', 'F' }, { 'O', 'L', 'D', 'Y' }, { 'O', 'L', 'G', 'A' }, { 'O', 'L', 'I', 'N' }, { 'O', 'M', 'A', 'N' }, { 'O', 'M', 'E', 'N' }, { 'O', 'M', 'I', 'T' }, { 'O', 'N', 'C', 'E' }, { 'O', 'N', 'E', 'S' }, { 'O', 'N', 'L', 'Y' }, { 'O', 'N', 'T', 'O' }, { 'O', 'N', 'U', 'S' }, { 'O', 'R', 'A', 'L' }, { 'O', 'R', 'G', 'Y' }, { 'O', 'S', 'L', 'O' }, { 'O', 'T', 'I', 'S' }, { 'O', 'T', 'T', 'O' }, { 'O', 'U', 'C', 'H' }, { 'O', 'U', 'S', 'T' }, { 'O', 'U', 'T', 'S' }, { 'O', 'V', 'A', 'L' }, { 'O', 'V', 'E', 'N' }, { 'O', 'V', 'E', 'R' }, { 'O', 'W', 'L', 'Y' }, { 'O', 'W', 'N', 'S' }, { 'Q', 'U', 'A', 'D' }, { 'Q', 'U', 'I', 'T' }, { 'Q', 'U', 'O', 'D' }, { 'R', 'A', 'C', 'E' }, { 'R', 'A', 'C', 'K' }, { 'R', 'A', 'C', 'Y' }, { 'R', 'A', 'F', 'T' }, { 'R', 'A', 'G', 'E' }, { 'R', 'A', 'I', 'D' }, { 'R', 'A', 'I', 'L' }, { 'R', 'A', 'I', 'N' }, { 'R', 'A', 'K', 'E' }, { 'R', 'A', 'N', 'K' }, { 'R', 'A', 'N', 'T' }, { 'R', 'A', 'R', 'E' }, { 'R', 'A', 'S', 'H' }, { 'R', 'A', 'T', 'E' }, { 'R', 'A', 'V', 'E' }, { 'R', 'A', 'Y', 'S' }, { 'R', 'E', 'A', 'D' }, { 'R', 'E', 'A', 'L' }, { 'R', 'E', 'A', 'M' }, { 'R', 'E', 'A', 'R' }, { 'R', 'E', 'C', 'K' }, { 'R', 'E', 'E', 'D' }, { 'R', 'E', 'E', 'F' }, { 'R', 'E', 'E', 'K' }, { 'R', 'E', 'E', 'L' }, { 'R', 'E', 'I', 'D' }, { 'R', 'E', 'I', 'N' }, { 'R', 'E', 'N', 'A' }, { 'R', 'E', 'N', 'D' }, { 'R', 'E', 'N', 'T' }, { 'R', 'E', 'S', 'T' }, { 'R', 'I', 'C', 'E' }, { 'R', 'I', 'C', 'H' }, { 'R', 'I', 'C', 'K' }, { 'R', 'I', 'D', 'E' }, { 'R', 'I', 'F', 'T' }, { 'R', 'I', 'L', 'L' }, { 'R', 'I', 'M', 'E' }, { 'R', 'I', 'N', 'G' }, { 'R', 'I', 'N', 'K' }, { 'R', 'I', 'S', 'E' }, { 'R', 'I', 'S', 'K' }, { 'R', 'I', 'T', 'E' }, { 'R', 'O', 'A', 'D' }, { 'R', 'O', 'A', 'M' }, { 'R', 'O', 'A', 'R' }, { 'R', 'O', 'B', 'E' }, { 'R', 'O', 'C', 'K' }, { 'R', 'O', 'D', 'E' }, { 'R', 'O', 'I', 'L' }, { 'R', 'O', 'L', 'L' }, { 'R', 'O', 'M', 'E' }, { 'R', 'O', 'O', 'D' }, { 'R', 'O', 'O', 'F' }, { 'R', 'O', 'O', 'K' }, { 'R', 'O', 'O', 'M' }, { 'R', 'O', 'O', 'T' }, { 'R', 'O', 'S', 'A' }, { 'R', 'O', 'S', 'E' }, { 'R', 'O', 'S', 'S' }, { 'R', 'O', 'S', 'Y' }, { 'R', 'O', 'T', 'H' }, { 'R', 'O', 'U', 'T' }, { 'R', 'O', 'V', 'E' }, { 'R', 'O', 'W', 'E' }, { 'R', 'O', 'W', 'S' }, { 'R', 'U', 'B', 'E' }, { 'R', 'U', 'B', 'Y' }, { 'R', 'U', 'D', 'E' }, { 'R', 'U', 'D', 'Y' }, { 'R', 'U', 'I', 'N' }, { 'R', 'U', 'L', 'E' }, { 'R', 'U', 'N', 'G' }, { 'R', 'U', 'N', 'S' }, { 'R', 'U', 'N', 'T' }, { 'R', 'U', 'S', 'E' }, { 'R', 'U', 'S', 'H' }, { 'R', 'U', 'S', 'K' }, { 'R', 'U', 'S', 'S' }, { 'R', 'U', 'S', 'T' }, { 'R', 'U', 'T', 'H' }, { 'S', 'A', 'C', 'K' }, { 'S', 'A', 'F', 'E' }, { 'S', 'A', 'G', 'E' }, { 'S', 'A', 'I', 'D' }, { 'S', 'A', 'I', 'L' }, { 'S', 'A', 'L', 'E' }, { 'S', 'A', 'L', 'K' }, { 'S', 'A', 'L', 'T' }, { 'S', 'A', 'M', 'E' }, { 'S', 'A', 'N', 'D' }, { 'S', 'A', 'N', 'E' }, { 'S', 'A', 'N', 'G' }, { 'S', 'A', 'N', 'K' }, { 'S', 'A', 'R', 'A' }, { 'S', 'A', 'U', 'L' }, { 'S', 'A', 'V', 'E' }, { 'S', 'A', 'Y', 'S' }, { 'S', 'C', 'A', 'N' }, { 'S', 'C', 'A', 'R' }, { 'S', 'C', 'A', 'T' }, { 'S', 'C', 'O', 'T' }, { 'S', 'E', 'A', 'L' }, { 'S', 'E', 'A', 'M' }, { 'S', 'E', 'A', 'R' }, { 'S', 'E', 'A', 'T' }, { 'S', 'E', 'E', 'D' }, { 'S', 'E', 'E', 'K' }, { 'S', 'E', 'E', 'M' }, { 'S', 'E', 'E', 'N' }, { 'S', 'E', 'E', 'S' }, { 'S', 'E', 'L', 'F' }, { 'S', 'E', 'L', 'L' }, { 'S', 'E', 'N', 'D' }, { 'S', 'E', 'N', 'T' }, { 'S', 'E', 'T', 'S' }, { 'S', 'E', 'W', 'N' }, { 'S', 'H', 'A', 'G' }, { 'S', 'H', 'A', 'M' }, { 'S', 'H', 'A', 'W' }, { 'S', 'H', 'A', 'Y' }, { 'S', 'H', 'E', 'D' }, { 'S', 'H', 'I', 'M' }, { 'S', 'H', 'I', 'N' }, { 'S', 'H', 'O', 'D' }, { 'S', 'H', 'O', 'E' }, { 'S', 'H', 'O', 'T' }, { 'S', 'H', 'O', 'W' }, { 'S', 'H', 'U', 'N' }, { 'S', 'H', 'U', 'T' }, { 'S', 'I', 'C', 'K' }, { 'S', 'I', 'D', 'E' }, { 'S', 'I', 'F', 'T' }, { 'S', 'I', 'G', 'H' }, { 'S', 'I', 'G', 'N' }, { 'S', 'I', 'L', 'K' }, { 'S', 'I', 'L', 'L' }, { 'S', 'I', 'L', 'O' }, { 'S', 'I', 'L', 'T' }, { 'S', 'I', 'N', 'E' }, { 'S', 'I', 'N', 'G' }, { 'S', 'I', 'N', 'K' }, { 'S', 'I', 'R', 'E' }, { 'S', 'I', 'T', 'E' }, { 'S', 'I', 'T', 'S' }, { 'S', 'I', 'T', 'U' }, { 'S', 'K', 'A', 'T' }, { 'S', 'K', 'E', 'W' }, { 'S', 'K', 'I', 'D' }, { 'S', 'K', 'I', 'M' }, { 'S', 'K', 'I', 'N' }, { 'S', 'K', 'I', 'T' }, { 'S', 'L', 'A', 'B' }, { 'S', 'L', 'A', 'M' }, { 'S', 'L', 'A', 'T' }, { 'S', 'L', 'A', 'Y' }, { 'S', 'L', 'E', 'D' }, { 'S', 'L', 'E', 'W' }, { 'S', 'L', 'I', 'D' }, { 'S', 'L', 'I', 'M' }, { 'S', 'L', 'I', 'T' }, { 'S', 'L', 'O', 'B' }, { 'S', 'L', 'O', 'G' }, { 'S', 'L', 'O', 'T' }, { 'S', 'L', 'O', 'W' }, { 'S', 'L', 'U', 'G' }, { 'S', 'L', 'U', 'M' }, { 'S', 'L', 'U', 'R' }, { 'S', 'M', 'O', 'G' }, { 'S', 'M', 'U', 'G' }, { 'S', 'N', 'A', 'G' }, { 'S', 'N', 'O', 'B' }, { 'S', 'N', 'O', 'W' }, { 'S', 'N', 'U', 'B' }, { 'S', 'N', 'U', 'G' }, { 'S', 'O', 'A', 'K' }, { 'S', 'O', 'A', 'R' }, { 'S', 'O', 'C', 'K' }, { 'S', 'O', 'D', 'A' }, { 'S', 'O', 'F', 'A' }, { 'S', 'O', 'F', 'T' }, { 'S', 'O', 'I', 'L' }, { 'S', 'O', 'L', 'D' }, { 'S', 'O', 'M', 'E' }, { 'S', 'O', 'N', 'G' }, { 'S', 'O', 'O', 'N' }, { 'S', 'O', 'O', 'T' }, { 'S', 'O', 'R', 'E' }, { 'S', 'O', 'R', 'T' }, { 'S', 'O', 'U', 'L' }, { 'S', 'O', 'U', 'R' }, { 'S', 'O', 'W', 'N' }, { 'S', 'T', 'A', 'B' }, { 'S', 'T', 'A', 'G' }, { 'S', 'T', 'A', 'N' }, { 'S', 'T', 'A', 'R' }, { 'S', 'T', 'A', 'Y' }, { 'S', 'T', 'E', 'M' }, { 'S', 'T', 'E', 'W' }, { 'S', 'T', 'I', 'R' }, { 'S', 'T', 'O', 'W' }, { 'S', 'T', 'U', 'B' }, { 'S', 'T', 'U', 'N' }, { 'S', 'U', 'C', 'H' }, { 'S', 'U', 'D', 'S' }, { 'S', 'U', 'I', 'T' }, { 'S', 'U', 'L', 'K' }, { 'S', 'U', 'M', 'S' }, { 'S', 'U', 'N', 'G' }, { 'S', 'U', 'N', 'K' }, { 'S', 'U', 'R', 'E' }, { 'S', 'U', 'R', 'F' }, { 'S', 'W', 'A', 'B' }, { 'S', 'W', 'A', 'G' }, { 'S', 'W', 'A', 'M' }, { 'S', 'W', 'A', 'N' }, { 'S', 'W', 'A', 'T' }, { 'S', 'W', 'A', 'Y' }, { 'S', 'W', 'I', 'M' }, { 'S', 'W', 'U', 'M' }, { 'T', 'A', 'C', 'K' }, { 'T', 'A', 'C', 'T' }, { 'T', 'A', 'I', 'L' }, { 'T', 'A', 'K', 'E' }, { 'T', 'A', 'L', 'E' }, { 'T', 'A', 'L', 'K' }, { 'T', 'A', 'L', 'L' }, { 'T', 'A', 'N', 'K' }, { 'T', 'A', 'S', 'K' }, { 'T', 'A', 'T', 'E' }, { 'T', 'A', 'U', 'T' }, { 'T', 'E', 'A', 'L' }, { 'T', 'E', 'A', 'M' }, { 'T', 'E', 'A', 'R' }, { 'T', 'E', 'C', 'H' }, { 'T', 'E', 'E', 'M' }, { 'T', 'E', 'E', 'N' }, { 'T', 'E', 'E', 'T' }, { 'T', 'E', 'L', 'L' }, { 'T', 'E', 'N', 'D' }, { 'T', 'E', 'N', 'T' }, { 'T', 'E', 'R', 'M' }, { 'T', 'E', 'R', 'N' }, { 'T', 'E', 'S', 'S' }, { 'T', 'E', 'S', 'T' }, { 'T', 'H', 'A', 'N' }, { 'T', 'H', 'A', 'T' }, { 'T', 'H', 'E', 'E' }, { 'T', 'H', 'E', 'M' }, { 'T', 'H', 'E', 'N' }, { 'T', 'H', 'E', 'Y' }, { 'T', 'H', 'I', 'N' }, { 'T', 'H', 'I', 'S' }, { 'T', 'H', 'U', 'D' }, { 'T', 'H', 'U', 'G' }, { 'T', 'I', 'C', 'K' }, { 'T', 'I', 'D', 'E' }, { 'T', 'I', 'D', 'Y' }, { 'T', 'I', 'E', 'D' }, { 'T', 'I', 'E', 'R' }, { 'T', 'I', 'L', 'E' }, { 'T', 'I', 'L', 'L' }, { 'T', 'I', 'L', 'T' }, { 'T', 'I', 'M', 'E' }, { 'T', 'I', 'N', 'A' }, { 'T', 'I', 'N', 'E' }, { 'T', 'I', 'N', 'T' }, { 'T', 'I', 'N', 'Y' }, { 'T', 'I', 'R', 'E' }, { 'T', 'O', 'A', 'D' }, { 'T', 'O', 'G', 'O' }, { 'T', 'O', 'I', 'L' }, { 'T', 'O', 'L', 'D' }, { 'T', 'O', 'L', 'L' }, { 'T', 'O', 'N', 'E' }, { 'T', 'O', 'N', 'G' }, { 'T', 'O', 'N', 'Y' }, { 'T', 'O', 'O', 'K' }, { 'T', 'O', 'O', 'L' }, { 'T', 'O', 'O', 'T' }, { 'T', 'O', 'R', 'E' }, { 'T', 'O', 'R', 'N' }, { 'T', 'O', 'T', 'E' }, { 'T', 'O', 'U', 'R' }, { 'T', 'O', 'U', 'T' }, { 'T', 'O', 'W', 'N' }, { 'T', 'R', 'A', 'G' }, { 'T', 'R', 'A', 'M' }, { 'T', 'R', 'A', 'Y' }, { 'T', 'R', 'E', 'E' }, { 'T', 'R', 'E', 'K' }, { 'T', 'R', 'I', 'G' }, { 'T', 'R', 'I', 'M' }, { 'T', 'R', 'I', 'O' }, { 'T', 'R', 'O', 'D' }, { 'T', 'R', 'O', 'T' }, { 'T', 'R', 'O', 'Y' }, { 'T', 'R', 'U', 'E' }, { 'T', 'U', 'B', 'A' }, { 'T', 'U', 'B', 'E' }, { 'T', 'U', 'C', 'K' }, { 'T', 'U', 'F', 'T' }, { 'T', 'U', 'N', 'A' }, { 'T', 'U', 'N', 'E' }, { 'T', 'U', 'N', 'G' }, { 'T', 'U', 'R', 'F' }, { 'T', 'U', 'R', 'N' }, { 'T', 'U', 'S', 'K' }, { 'T', 'W', 'I', 'G' }, { 'T', 'W', 'I', 'N' }, { 'T', 'W', 'I', 'T' }, { 'U', 'L', 'A', 'N' }, { 'U', 'N', 'I', 'T' }, { 'U', 'R', 'G', 'E' }, { 'U', 'S', 'E', 'D' }, { 'U', 'S', 'E', 'R' }, { 'U', 'S', 'E', 'S' }, { 'U', 'T', 'A', 'H' }, { 'V', 'A', 'I', 'L' }, { 'V', 'A', 'I', 'N' }, { 'V', 'A', 'L', 'E' }, { 'V', 'A', 'R', 'Y' }, { 'V', 'A', 'S', 'E' }, { 'V', 'A', 'S', 'T' }, { 'V', 'E', 'A', 'L' }, { 'V', 'E', 'D', 'A' }, { 'V', 'E', 'I', 'L' }, { 'V', 'E', 'I', 'N' }, { 'V', 'E', 'N', 'D' }, { 'V', 'E', 'N', 'T' }, { 'V', 'E', 'R', 'B' }, { 'V', 'E', 'R', 'Y' }, { 'V', 'E', 'T', 'O' }, { 'V', 'I', 'C', 'E' }, { 'V', 'I', 'E', 'W' }, { 'V', 'I', 'N', 'E' }, { 'V', 'I', 'S', 'E' }, { 'V', 'O', 'I', 'D' }, { 'V', 'O', 'L', 'T' }, { 'V', 'O', 'T', 'E' }, { 'W', 'A', 'C', 'K' }, { 'W', 'A', 'D', 'E' }, { 'W', 'A', 'G', 'E' }, { 'W', 'A', 'I', 'L' }, { 'W', 'A', 'I', 'T' }, { 'W', 'A', 'K', 'E' }, { 'W', 'A', 'L', 'E' }, { 'W', 'A', 'L', 'K' }, { 'W', 'A', 'L', 'L' }, { 'W', 'A', 'L', 'T' }, { 'W', 'A', 'N', 'D' }, { 'W', 'A', 'N', 'E' }, { 'W', 'A', 'N', 'G' }, { 'W', 'A', 'N', 'T' }, { 'W', 'A', 'R', 'D' }, { 'W', 'A', 'R', 'M' }, { 'W', 'A', 'R', 'N' }, { 'W', 'A', 'R', 'T' }, { 'W', 'A', 'S', 'H' }, { 'W', 'A', 'S', 'T' }, { 'W', 'A', 'T', 'S' }, { 'W', 'A', 'T', 'T' }, { 'W', 'A', 'V', 'E' }, { 'W', 'A', 'V', 'Y' }, { 'W', 'A', 'Y', 'S' }, { 'W', 'E', 'A', 'K' }, { 'W', 'E', 'A', 'L' }, { 'W', 'E', 'A', 'N' }, { 'W', 'E', 'A', 'R' }, { 'W', 'E', 'E', 'D' }, { 'W', 'E', 'E', 'K' }, { 'W', 'E', 'I', 'R' }, { 'W', 'E', 'L', 'D' }, { 'W', 'E', 'L', 'L' }, { 'W', 'E', 'L', 'T' }, { 'W', 'E', 'N', 'T' }, { 'W', 'E', 'R', 'E' }, { 'W', 'E', 'R', 'T' }, { 'W', 'E', 'S', 'T' }, { 'W', 'H', 'A', 'M' }, { 'W', 'H', 'A', 'T' }, { 'W', 'H', 'E', 'E' }, { 'W', 'H', 'E', 'N' }, { 'W', 'H', 'E', 'T' }, { 'W', 'H', 'O', 'A' }, { 'W', 'H', 'O', 'M' }, { 'W', 'I', 'C', 'K' }, { 'W', 'I', 'F', 'E' }, { 'W', 'I', 'L', 'D' }, { 'W', 'I', 'L', 'L' }, { 'W', 'I', 'N', 'D' }, { 'W', 'I', 'N', 'E' }, { 'W', 'I', 'N', 'G' }, { 'W', 'I', 'N', 'K' }, { 'W', 'I', 'N', 'O' }, { 'W', 'I', 'R', 'E' }, { 'W', 'I', 'S', 'E' }, { 'W', 'I', 'S', 'H' }, { 'W', 'I', 'T', 'H' }, { 'W', 'O', 'L', 'F' }, { 'W', 'O', 'N', 'T' }, { 'W', 'O', 'O', 'D' }, { 'W', 'O', 'O', 'L' }, { 'W', 'O', 'R', 'D' }, { 'W', 'O', 'R', 'E' }, { 'W', 'O', 'R', 'K' }, { 'W', 'O', 'R', 'M' }, { 'W', 'O', 'R', 'N' }, { 'W', 'O', 'V', 'E' }, { 'W', 'R', 'I', 'T' }, { 'W', 'Y', 'N', 'N' }, { 'Y', 'A', 'L', 'E' }, { 'Y', 'A', 'N', 'G' }, { 'Y', 'A', 'N', 'K' }, { 'Y', 'A', 'R', 'D' }, { 'Y', 'A', 'R', 'N' }, { 'Y', 'A', 'W', 'L' }, { 'Y', 'A', 'W', 'N' }, { 'Y', 'E', 'A', 'H' }, { 'Y', 'E', 'A', 'R' }, { 'Y', 'E', 'L', 'L' }, { 'Y', 'O', 'G', 'A' }, { 'Y', 'O', 'K', 'E' } }; /* Extract LENGTH bits from the char array S starting with bit number START. It always reads three consecutive octects, which means it can read past end of data when START is at the edge of the region. */ static uint32_t extract (const unsigned char *s, int start, int length) { unsigned char cl = s[start / 8]; unsigned char cc = s[start / 8 + 1]; unsigned char cr = s[start / 8 + 2]; uint32_t x; x = (uint32_t)(cl << 8 | cc) << 8 | cr; x >>= 24 - (length + (start % 8)); x &= (0xffff >> (16 - length)); return x; } /* Length of a string known to be at least 1 and at most 4 chars long. */ #define STRLEN_1_4(s) (!(s)[1] ? 1 : !(s)[2] ? 2 : !(s)[3] ? 3 : 4) /* Encode 8 bytes in C as a string of English words and store them to STORE. Returns STORE. */ static char * btoe (char *store, const unsigned char *c) { unsigned char cp[10]; /* add in room for the parity 2 bits + extract() slop. */ int p, i; char *store_beg = store; *store = '\0'; /* Workaround for extract() reads beyond end of data */ memset (cp, 0, sizeof(cp)); memcpy (cp, c, 8); /* Compute parity and append it to CP. */ for (p = 0, i = 0; i < 64; i += 2) p += extract (cp, i, 2); cp[8] = (char)p << 6; /* The 64 bits of input and the two parity bits comprise 66 bits of data that are now in CP. We convert that information, 11 bits at a time, to English words indexed from Wp. Since there are 2048 (2^11) words in Wp, every 11-bit combination corresponds to a distinct word. */ memcpy (store, &Wp[extract (cp, 0, 11)][0], 4); store += STRLEN_1_4 (store); *store++ = ' '; memcpy (store, &Wp[extract (cp, 11, 11)][0], 4); store += STRLEN_1_4 (store); *store++ = ' '; memcpy (store, &Wp[extract (cp, 22, 11)][0], 4); store += STRLEN_1_4 (store); *store++ = ' '; memcpy (store, &Wp[extract (cp, 33, 11)][0], 4); store += STRLEN_1_4 (store); *store++ = ' '; memcpy (store, &Wp[extract (cp, 44, 11)][0], 4); store += STRLEN_1_4 (store); *store++ = ' '; memcpy (store, &Wp[extract (cp, 55, 11)][0], 4); store[4] = '\0'; /* make sure the string is terminated */ /* DEBUGP (("wrote %s to STORE\n", quote (store_beg)));*/ return store_beg; } /* Calculate the SKEY response, based on the sequence, seed (challenge), and the secret password. The calculated response is used instead of the real password when logging in to SKEY-enabled servers. The result is calculated like this: + Concatenate SEED and PASS and calculate the 16-byte MD5 checksum. + Shorten the checksum to eight bytes by folding the second eight bytes onto the first eight using XOR. The resulting eight-byte sequence is the key. + MD5-process the key, fold the checksum to eight bytes and store it back to the key. Repeat this crunching SEQUENCE times. (Sequence is a number that gets decremented every time the user logs in to the server. Therefore an eavesdropper would have to invert the hash function in order to guess the next one-time password.) + Convert the resulting 64-bit key to 6 English words separated by spaces (see btoe for details) and return the resulting ASCII string. All this is described in section 6 of rfc2289 in more detail. */ const char * calculate_skey_response (int sequence, const char *seed, const char *pass) { unsigned char key[8]; /* Room to hold 6 four-letter words (heh), 5 space separators, and the terminating \0. 24+5+1 == 30 */ static char english[30]; struct md5_ctx ctx; uint32_t checksum[4]; md5_init_ctx (&ctx); md5_process_bytes ((const unsigned char *) seed, strlen (seed), &ctx); md5_process_bytes ((const unsigned char *) pass, strlen (pass), &ctx); md5_finish_ctx (&ctx, (unsigned char *) checksum); checksum[0] ^= checksum[2]; checksum[1] ^= checksum[3]; memcpy (key, checksum, 8); while (sequence-- > 0) { md5_init_ctx (&ctx); md5_process_bytes ((unsigned char *) key, 8, &ctx); md5_finish_ctx (&ctx, (unsigned char *) checksum); checksum[0] ^= checksum[2]; checksum[1] ^= checksum[3]; memcpy (key, checksum, 8); } return btoe (english, key); } lftp-4.9.2/src/FileSet.cc0000644000015000007670000006265313577336043012074 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "FileSet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" #include "ResMgr.h" #include "StringPool.h" #include "IdNameCache.h" #include "PatternSet.h" #ifdef HAVE_SYS_STATFS_H # include #endif #define fnum files.count() void FileInfo::Merge(const FileInfo& f) { if(strcmp(basename_ptr(name),basename_ptr(f.name))) return; MergeInfo(f,~defined); } void FileInfo::MergeInfo(const FileInfo& f,unsigned dif) { dif&=f.defined; if(dif&MODE) { SetMode(f.mode); if(mode!=SYMLINK && mode!=REDIRECT) symlink.unset(); } if(dif&DATE || (defined&DATE && f.defined&DATE && f.date.ts_precname) { delete fi; return; } /* add sorted */ int pos = FindGEIndByName(fi->name); if(pos < fnum && !strcmp(files[pos]->name,fi->name)) { files[pos]->Merge(*fi); delete fi; return; } add_before(pos,fi); } void FileSet::Sub(int i) { assert(!sorted); files.remove(i); if(ind>i) ind--; } FileInfo *FileSet::Borrow(int i) { FileInfo *fi=files[i].borrow(); Sub(i); return fi; } void FileSet::assert_sorted() const { for(int i=0; iname,files[i+1]->name)<0); } void FileSet::Merge_insert(const FileSet *set) { if(!set) return; for(int i=0; ifnum; i++) { const Ref& fi=set->files[i]; int pos = FindGEIndByName(fi->name); if(pos < fnum && !strcmp(files[pos]->name,fi->name)) files[pos]->Merge(*fi); else add_before(pos,new FileInfo(*fi)); } } void FileSet::Merge(const FileSet *set) { assert(!sorted); if(!set || !set->fnum) return; // estimate work to be done by Merge_insert int pos = FindGEIndByName(set->files[0]->name); if(fnum-pos < fnum*2/set->fnum) { Merge_insert(set); return; } RefArray new_set; int i=0; int j=0; while(ifnum && j& fi1=files[j]; const Ref& fi2=set->files[i]; int cmp = strcmp(fi1->name,fi2->name); if(cmp==0) { fi1->Merge(*fi2); new_set.append(fi1.borrow()); i++; j++; } else if(cmp>0) { new_set.append(new FileInfo(*fi2)); i++; } else { new_set.append(fi1.borrow()); j++; } } while(ifnum) { const Ref& fi2=set->files[i]; new_set.append(new FileInfo(*fi2)); i++; } if(new_set.count()==0) return; while(j& fi1=files[j]; new_set.append(fi1.borrow()); j++; } files.move_here(new_set); } void FileSet::PrependPath(const char *path) { for(int i=0; iSetName(dir_file(path, files[i]->name)); } FileSet::FileSet() : sort_mode(BYNAME), ind(0) { } FileSet::~FileSet() { } /* we don't copy the sort state--nothing needs it, and it'd * be a bit of a pain to implement. */ FileSet::FileSet(FileSet const *set) { if(!set) { ind=0; return; } ind=set->ind; for(int i=0; ifnum; i++) files.append(new FileInfo(*(set->files[i]))); } static int files_sort_name(const Ref *s1, const Ref *s2) { return strcmp((*s1)->name, (*s2)->name); } static int (*compare)(const char *s1, const char *s2); static int rev_cmp; static RefArray *files_cmp; static int sort_name(const int *s1, const int *s2) { const FileInfo *p1=(*files_cmp)[*s1]; const FileInfo *p2=(*files_cmp)[*s2]; return compare(p1->name, p2->name) * rev_cmp; } static int sort_size(const int *s1, const int *s2) { const FileInfo *p1=(*files_cmp)[*s1]; const FileInfo *p2=(*files_cmp)[*s2]; if(p1->size > p2->size) return -rev_cmp; if(p1->size < p2->size) return rev_cmp; return 0; } static int sort_dirs(const int *s1, const int *s2) { const FileInfo *p1=(*files_cmp)[*s1]; const FileInfo *p2=(*files_cmp)[*s2]; if((p1->filetype == FileInfo::DIRECTORY) && !(p2->filetype == FileInfo::DIRECTORY)) return -rev_cmp; if(!(p1->filetype == FileInfo::DIRECTORY) && (p2->filetype == FileInfo::DIRECTORY)) return rev_cmp; return 0; } static int sort_rank(const int *s1, const int *s2) { const FileInfo *p1=(*files_cmp)[*s1]; const FileInfo *p2=(*files_cmp)[*s2]; if(p1->GetRank()==p2->GetRank()) return sort_name(s1,s2); return p1->GetRank()GetRank() ? -rev_cmp : rev_cmp; } static int sort_date(const int *s1, const int *s2) { const FileInfo *p1=(*files_cmp)[*s1]; const FileInfo *p2=(*files_cmp)[*s2]; if(p1->date==p2->date) return sort_name(s1,s2); return p1->date>p2->date ? -rev_cmp : rev_cmp; } void FileSet::Sort(sort_e newsort, bool casefold, bool reverse) { if(newsort == BYNAME && !casefold && !reverse) { Unsort(); return; } if(casefold) compare = strcasecmp; else compare = strcmp; rev_cmp=(reverse?-1:1); files_cmp=&files; if(newsort==BYNAME_FLAT && sort_mode!=BYNAME_FLAT) { // save original paths to longname, store basename to name, // sort files array according to short names for(int i=0; i const& fi=files[i]; fi->longname.move_here(fi->name); fi->name.set(basename_ptr(fi->longname)); } files.qsort(files_sort_name); } xmap dup; sorted.truncate(); for(int i=0; i const& fi=files[i]; if(dup.exists(fi->name)) continue; dup.add(fi->name,true); } sorted.append(i); } switch(newsort) { case BYNAME_FLAT: /*fallthrough*/ case BYNAME: sorted.qsort(sort_name); break; case BYSIZE: sorted.qsort(sort_size); break; case DIRSFIRST: sorted.qsort(sort_dirs); break; case BYRANK: sorted.qsort(sort_rank); break; case BYDATE: sorted.qsort(sort_date); break; } sort_mode=newsort; } // reverse current sort order void FileSet::ReverseSort() { if(!sorted) { Sort(BYNAME,false,true); return; } int i=0; int j=sorted.length()-1; while(ilongname!=0); files[i]->name.move_here(files[i]->longname); } files.qsort(files_sort_name); } void FileSet::Empty() { Unsort(); files.unset(); ind=0; } void FileSet::SubtractSame(const FileSet *set,int ignore) { if(!set) return; for(int i=0; iFindByName(files[i]->name); if(f && files[i]->SameAs(f,ignore)) Sub(i--); } } void FileSet::SubtractAny(const FileSet *set) { if(!set) return; for(int i=0; iFindByName(files[i]->name)) Sub(i--); } void FileSet::SubtractNotIn(const FileSet *set) { if(!set) { Empty(); return; } for(int i=0; iFindByName(files[i]->name)) Sub(i--); } void FileSet::SubtractSameType(const FileSet *set) { if(!set) return; for(int i=0; iFindByName(files[i]->name); if(f && files[i]->defined&FileInfo::TYPE && f->defined&FileInfo::TYPE && files[i]->filetype==f->filetype) Sub(i--); } } void FileSet::SubtractDirs(const FileSet *set) { if(!set) return; for(int i=0; iTypeIs(FileInfo::DIRECTORY)) continue; FileInfo *f=set->FindByName(files[i]->name); if(f && f->TypeIs(f->DIRECTORY)) Sub(i--); } } void FileSet::SubtractNotOlderDirs(const FileSet *set) { if(!set) return; for(int i=0; iTypeIs(FileInfo::DIRECTORY) || !files[i]->Has(FileInfo::DATE)) continue; FileInfo *f=set->FindByName(files[i]->name); if(f && f->TypeIs(f->DIRECTORY) && f->NotOlderThan(files[i]->date)) Sub(i--); } } void FileSet::SubtractTimeCmp(bool (FileInfo::*cmp)(time_t) const,time_t t) { for(int i=0; idefined&FileInfo::TYPE && files[i]->filetype!=FileInfo::NORMAL) continue; if((files[i].get()->*cmp)(t)) { Sub(i); i--; } } } void FileSet::SubtractSizeOutside(const Range *r) { for(int i=0; idefined&FileInfo::TYPE && files[i]->filetype!=FileInfo::NORMAL) continue; if(files[i]->SizeOutside(r)) { Sub(i); i--; } } } void FileSet::SubtractDirs() { for(int i=0; idefined&FileInfo::TYPE && files[i]->filetype==FileInfo::DIRECTORY) { Sub(i); i--; } } } void FileSet::SubtractNotDirs() { for(int i=0; idefined&FileInfo::TYPE) || files[i]->filetype!=FileInfo::DIRECTORY) { Sub(i); i--; } } } void FileSet::ExcludeDots() { for(int i=0; iname,".") || !strcmp(files[i]->name,"..")) { Sub(i); i--; } } } void FileSet::ExcludeCompound() { for(int i=0; iname; if(!strncmp(name,"./~",3)) name+=3; if(strchr(name,'/')) Sub(i--); } } void FileSet::ExcludeUnaccessible(const char *user) { for(int i=0; iHas(FileInfo::MODE) || !files[i]->Has(FileInfo::TYPE)) continue; unsigned mask=0444; if(user && files[i]->Has(FileInfo::USER)) mask=(!strcmp(files[i]->user,user)?0400:0044); if((files[i]->TypeIs(FileInfo::NORMAL) && !(files[i]->mode&mask)) || (files[i]->TypeIs(FileInfo::DIRECTORY) && !(files[i]->mode&mask&(files[i]->mode<<2)))) { Sub(i); i--; } } } bool FileInfo::SameAs(const FileInfo *fi,int ignore) const { if(defined&NAME && fi->defined&NAME) if(strcmp(name,fi->name)) return false; if(defined&TYPE && fi->defined&TYPE) if(filetype!=fi->filetype) return false; if((defined&TYPE && filetype==DIRECTORY) || (fi->defined&TYPE && fi->filetype==DIRECTORY)) return false; // can't guarantee directory is the same (recursively) if(defined&SYMLINK_DEF && fi->defined&SYMLINK_DEF) return (strcmp(symlink,fi->symlink)==0); if(defined&DATE && fi->defined&DATE && !(ignore&DATE)) { time_t p=date.ts_prec; if(pdate.ts_prec) p=fi->date.ts_prec; if(!(ignore&IGNORE_DATE_IF_OLDER && datedate) && labs(date-fi->date)>p) return false; } if(defined&SIZE && fi->defined&SIZE && !(ignore&SIZE)) { if(!(ignore&IGNORE_SIZE_IF_OLDER && defined&DATE && fi->defined&DATE && datedate) && (size!=fi->size)) return false; } return true; } bool FileInfo::NotOlderThan(time_t t) const { return((defined&DATE) && date>=t); } bool FileInfo::NotNewerThan(time_t t) const { return((defined&DATE) && date<=t); } bool FileInfo::OlderThan(time_t t) const { return((defined&DATE) && datet); } bool FileInfo::SizeOutside(const Range *r) const { return((defined&SIZE) && !r->Match(size)); } void FileSet::Count(int *d,int *f,int *s,int *o) const { for(int i=0; ifiletype) { case(FileInfo::DIRECTORY): if(d) (*d)++; break; case(FileInfo::NORMAL): if(f) (*f)++; break; case(FileInfo::SYMLINK): if(s) (*s)++; break; default: if(o) (*o)++; } } } void FileSet::CountBytes(long long *b) const { for(int i=0; ifiletype==FileInfo::NORMAL && files[i]->Has(FileInfo::SIZE)) (*b)+=files[i]->size; } } /* assumes sorted by name. binary search for name, returning the first name * >= name; returns fnum if name is greater than all names. */ int FileSet::FindGEIndByName(const char *name) const { int l = 0, u = fnum - 1; /* no files or name is greater than the max file: */ if(!fnum || strcmp(files[u]->name, name) < 0) return fnum; /* we have files, and u >= name (meaning l <= name <= u); loop while * this is true: */ while(l < u) { /* find the midpoint: */ int m = (l + u) / 2; int cmp = strcmp(files[m]->name, name); /* if files[m]->name > name, update the upper bound: */ if (cmp > 0) u = m; /* if files[m]->name < name, update the lower bound: */ else if (cmp < 0) l = m+1; else /* otherwise found exact match */ return m; } return u; } FileInfo *FileSet::FindByName(const char *name) const { int n = FindGEIndByName(name); if(n < fnum && !strcmp(files[n]->name,name)) return files[n].get_non_const(); return 0; } static bool do_exclude_match(const char *prefix,const FileInfo *fi,const PatternSet *x) { const char *name=dir_file(prefix,fi->name); if(fi->defined&fi->TYPE && fi->filetype==fi->DIRECTORY) { char *name1=alloca_strdup2(name,1); strcat(name1,"/"); name=name1; } return x->MatchExclude(name); } void FileSet::Exclude(const char *prefix,const PatternSet *x,FileSet *fsx) { if(!x) return; for(int i=0; iAdd(Borrow(i)); else Sub(i); i--; } } } #if 0 void FileSet::Dump(const char *tag) const { printf("%s:",tag); for(int i=0; iname.get()); printf("\n"); } #endif // *** Manipulations with set of local files void FileSet::LocalUtime(const char *dir,bool only_dirs,bool flat) { for(int i=0; i& file=files[i]; if(file->defined & file->DATE) { if(!(file->defined & file->TYPE)) continue; if(file->filetype==file->SYMLINK) continue; if(only_dirs && file->filetype!=file->DIRECTORY) continue; const char *name=file->name; if(flat) name=basename_ptr(name); const char *local_name=dir_file(dir,name); struct utimbuf ut; struct stat st; ut.actime=ut.modtime=file->date; if(stat(local_name,&st)!=-1 && labs(st.st_mtime-file->date)>file->date.ts_prec) utime(local_name,&ut); } } } void FileSet::LocalChmod(const char *dir,mode_t mask,bool flat) { for(int i=0; i& file=files[i]; if(file->defined & file->MODE) { if(file->defined & file->TYPE && file->filetype==file->SYMLINK) continue; const char *name=file->name; if(flat) name=basename_ptr(name); const char *local_name=dir_file(dir,name); struct stat st; mode_t new_mode=file->mode&~mask; if(stat(local_name,&st)!=-1 && (st.st_mode&07777)!=new_mode) chmod(local_name,new_mode); } } } void FileSet::LocalChown(const char *dir,bool flat) { for(int i=0; i& file=files[i]; if(file->defined & (file->USER|file->GROUP)) { #ifndef HAVE_LCHOWN if(file->defined & file->TYPE && file->filetype==file->SYMLINK) continue; #define lchown chown #endif const char *name=file->name; if(flat) name=basename_ptr(name); const char *local_name=dir_file(dir,name); struct stat st; if(lstat(local_name,&st)==-1) continue; uid_t new_uid=st.st_uid; gid_t new_gid=st.st_gid; if(file->defined&file->USER) { int u=PasswdCache::LookupS(file->user); if(u!=-1) new_uid=u; } if(file->defined&file->GROUP) { int g=GroupCache::LookupS(file->group); if(g!=-1) new_gid=g; } if(new_uid!=st.st_uid || new_gid!=st.st_gid) { if(lchown(local_name,new_uid,new_gid)==-1) /* don't care */; } } } } FileInfo * FileSet::operator[](int i) const { if(i>=fnum || i<0) return 0; if(sorted) i=sorted[i]; return files[i].get_non_const(); } FileInfo *FileSet::curr() { return (*this)[ind]; } FileInfo *FileSet::next() { if(ind= fnum || strcmp(files[pos]->name,name)) return false; Sub(pos); return true; } void FileInfo::Init() { filetype=UNKNOWN; mode=(mode_t)-1; date=NO_DATE; size=NO_SIZE; nlinks=0; defined=0; need=0; user=0; group=0; rank=0; } FileInfo::FileInfo(const FileInfo &fi) { Init(); name.set(fi.name); symlink.set(fi.symlink); user=fi.user; group=fi.group; defined=fi.defined; filetype=fi.filetype; mode=fi.mode; date=fi.date; size=fi.size; nlinks=fi.nlinks; longname.set(fi.longname); } FileInfo::~FileInfo() { } #ifndef S_ISLNK # define S_ISLNK(mode) (S_IFLNK==(mode&S_IFMT)) #endif void FileInfo::LocalFile(const char *name, bool follow_symlinks) { if(!this->name) SetName(name); struct stat st; if(lstat(name,&st)==-1) return; check_again: FileInfo::type t; if(S_ISDIR(st.st_mode)) t=FileInfo::DIRECTORY; else if(S_ISREG(st.st_mode)) t=FileInfo::NORMAL; else if(S_ISLNK(st.st_mode)) { if(follow_symlinks) { if(stat(name,&st)!=-1) goto check_again; // dangling symlink, don't follow it. } t=FileInfo::SYMLINK; } else return; // ignore other type files SetSize(st.st_size); int prec=0; #if defined(HAVE_STATFS) && defined(MSDOS_SUPER_MAGIC) struct statfs stfs; if(statfs(name,&stfs)!=-1 && stfs.f_type==MSDOS_SUPER_MAGIC) prec=1; // MS-DOS fs has 2-second resolution #endif SetDate(st.st_mtime,prec); SetMode(st.st_mode&07777); SetType(t); SetNlink(st.st_nlink); SetUser(PasswdCache::LookupS(st.st_uid)); SetGroup(GroupCache::LookupS(st.st_gid)); if(t==SYMLINK) { char *buf=string_alloca(st.st_size+1); int res=readlink(name,buf,st.st_size); if(res!=-1) { buf[res]=0; SetSymlink(buf); } } } /* parse_ls_line: too common procedure to make it protocol specific */ /* -rwxr-xr-x 1 lav root 4771 Sep 12 1996 install-sh -rw-r--r-- 1 lav root 1349 Feb 2 14:10 lftp.lsm drwxr-xr-x 4 lav root 1024 Feb 22 15:32 lib lrwxrwxrwx 1 lav root 33 Feb 14 17:45 ltconfig -> /usr/share/libtool/ltconfig NOTE: group may be missing. */ FileInfo *FileInfo::parse_ls_line(const char *line_c,int line_len,const char *tz) { char *line=string_alloca(line_len+1); memcpy(line,line_c,line_len); line[line_len]=0; char *next=0; FileInfo *fi=0; /* don't instantiate until we at least have something */ #define FIRST_TOKEN strtok_r(line," \t",&next) #define NEXT_TOKEN strtok_r(NULL," \t",&next) #define ERR do{delete fi;return(0);}while(0) /* parse perms */ char *t = FIRST_TOKEN; if(t==0) ERR; fi = new FileInfo; switch(t[0]) { case('l'): // symlink fi->SetType(fi->SYMLINK); break; case('d'): // directory fi->SetType(fi->DIRECTORY); break; case('-'): // plain file fi->SetType(fi->NORMAL); break; case('b'): // block case('c'): // char case('p'): // pipe case('s'): // sock case('D'): // Door // ignore them default: ERR; } mode_t mode=parse_perms(t+1); if(mode!=(mode_t)-1) fi->SetMode(mode); // link count t = NEXT_TOKEN; if(!t) ERR; fi->SetNlink(atoi(t)); // user t = NEXT_TOKEN; if(!t) ERR; fi->SetUser(t); // group or size char *group_or_size = NEXT_TOKEN; // size or month t = NEXT_TOKEN; if(!t) ERR; if(isdigit((unsigned char)*t)) { // it's size, so the previous was group: fi->SetGroup(group_or_size); long long size; int n; if(sscanf(t,"%lld%n",&size,&n)==1 && t[n]==0) fi->SetSize(size); t = NEXT_TOKEN; if(!t) ERR; } else { // it was month, so the previous was size: long long size; int n; if(sscanf(group_or_size,"%lld%n",&size,&n)==1 && group_or_size[n]==0) fi->SetSize(size); } struct tm date; memset(&date,0,sizeof(date)); date.tm_mon=parse_month(t); if(date.tm_mon==-1) date.tm_mon=0; const char *day_of_month = NEXT_TOKEN; if(!day_of_month) ERR; date.tm_mday=atoi(day_of_month); bool year_anomaly=false; // time or year t = NEXT_TOKEN; if(!t) ERR; date.tm_isdst=-1; date.tm_hour=date.tm_min=0; date.tm_sec=30; int prec=30; if(sscanf(t,"%2d:%2d",&date.tm_hour,&date.tm_min)==2) date.tm_year=guess_year(date.tm_mon,date.tm_mday,date.tm_hour,date.tm_min) - 1900; else { if(day_of_month+strlen(day_of_month)+1 == t) year_anomaly=true; date.tm_year=atoi(t)-1900; /* We don't know the hour. Set it to something other than 0, or * DST -1 will end up changing the date. */ date.tm_hour = 12; date.tm_min=0; date.tm_sec=0; prec=12*HOUR; } fi->SetDate(mktime_from_tz(&date,tz),prec); char *name=strtok_r(NULL,"",&next); if(!name) ERR; // there are ls which output extra space after year. if(year_anomaly && *name==' ') name++; if(fi->filetype==fi->SYMLINK) { char *arrow=name; while((arrow=strstr(arrow," -> "))!=0) { if(arrow!=name && arrow[4]!=0) { *arrow=0; fi->SetSymlink(arrow+4); break; } arrow++; } } fi->SetName(name); fi->SetLongName(line_c); return fi; } int FileSet::Have() const { int bits=0; for(int i=0; idefined; return bits; } static int fnmatch_dir(const char *pattern,const FileInfo *file) { bool inverted = (pattern[0]=='!'); if(inverted || (pattern[0]=='\\' && pattern[1]=='!')) pattern++; const char *name=file->name; if(file->defined&file->TYPE && file->filetype==file->DIRECTORY) { char *n=alloca_strdup2(name,1); strcat(n,"/"); name=n; } int result=fnmatch(pattern,name,FNM_PATHNAME|FNM_CASEFOLD); if(inverted) { if(result==0) result=FNM_NOMATCH; else if(result==FNM_NOMATCH) result=0; } return result; } void FileSet::SortByPatternList(const char *list_c) { const int max_rank=1000000; for(int i=0; iSetRank(max_rank); char *list=alloca_strdup(list_c); int rank=0; for(char *p=strtok(list," "); p; p=strtok(0," "), rank++) for(int i=0; iGetRank()==max_rank && !fnmatch_dir(p,files[i])) files[i]->SetRank(rank); Sort(BYRANK); } void FileInfo::MakeLongName() { char filetype_s[2]="-"; char &filetype_c=filetype_s[0]; switch(filetype) { case NORMAL: break; case UNKNOWN: break; case DIRECTORY: filetype_c='d'; break; case SYMLINK: filetype_c='l'; break; case REDIRECT: filetype_c='L'; break; } int mode1=(defined&MODE?mode: (filetype_c=='d'?0755:(filetype_c=='l'?0777:0644))); const char *usergroup=""; if(defined&(USER|GROUP)) { usergroup=xstring::format("%.16s%s%.16s",defined&USER?user:"?", defined&GROUP?"/":"",defined&GROUP?group:""); } int w=20-strlen(usergroup); if(w<1) w=1; char size_str[21]; if(defined&SIZE) snprintf(size_str,sizeof(size_str),"%*lld",w,(long long)size); else snprintf(size_str,sizeof(size_str),"%*s",w,"-"); const char *date_str="-"; if(defined&DATE) date_str=TimeDate(date).IsoDateTime(); longname.vset(filetype_s,format_perms(mode1)," ",usergroup," ",size_str, " ",date_str," ",name.get(),NULL); if(defined&SYMLINK_DEF) longname.vappend(" -> ",symlink.get(),NULL); } size_t FileSet::EstimateMemory() const { size_t size=sizeof(FileSet) +files.count()*files.get_element_size() +sorted.count()*sorted.get_element_size(); for(int i=0; iname); size+=xstrlen(files[i]->symlink); size+=xstrlen(files[i]->longname); } return size; } lftp-4.9.2/src/GetPass.h0000644000015000007670000000161512122057774011734 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GETPASS_H #define GETPASS_H #include "trio.h" const char *GetPass(const char *p); char *readline_from_file(int fd); #endif//GETPASS_H lftp-4.9.2/src/SMTask.h0000644000015000007670000001263112665545545011542 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SMTASK_H #define SMTASK_H #include "PollVec.h" #include "TimeDate.h" #include "Ref.h" #include "xarray.h" #include "xlist.h" #include "misc.h" #include "Error.h" #include class SMTask { virtual int Do() = 0; // all tasks list static xlist_head all_tasks; xlist all_tasks_node; // ready (not suspended) tasks list static xlist_head ready_tasks; xlist ready_tasks_node; // just created or resumed tasks static xlist_head new_tasks; xlist new_tasks_node; // deleted and going to be destroyed tasks static xlist_head deleted_tasks; xlist deleted_tasks_node; static PollVec block; enum { SMTASK_MAX_DEPTH=64 }; static SMTask *stack[SMTASK_MAX_DEPTH]; static int stack_ptr; bool suspended; bool suspended_slave; int running; int ref_count; bool deleting; int ScheduleThis(); static int ScheduleNew(); protected: enum { STALL=0, MOVED=1, // STALL|MOVED==MOVED. WANTDIE=2 // for AcceptSig }; // SuspendInternal and ResumeInternal usually suspend and resume slave tasks virtual void SuspendInternal() {} virtual void ResumeInternal(); virtual void PrepareToDie() {} // it is called from Delete no matter of running and ref_count bool Deleted() const { return deleting; } virtual ~SMTask(); public: static void Block(int fd,int mask) { block.AddFD(fd,mask); } static void TimeoutU(int us) { block.AddTimeoutU(us); } static void Timeout(int ms) { TimeoutU(1000*ms); } static void TimeoutS(int s) { TimeoutU(1000000*s); } static bool Ready(int fd,int mask) { return block.FDReady(fd,mask); } static void SetNotReady(int fd,int mask) { block.FDSetNotReady(fd,mask); } static TimeDate now; static void UpdateNow() { now.SetToCurrentTime(); } static void Schedule(); static int CollectGarbage(); static void Block(); static time_t last_block; void Suspend(); void Resume(); // SuspendSlave and ResumeSlave are used in SuspendInternal/ResumeInternal // to suspend/resume slave tasks void SuspendSlave(); void ResumeSlave(); bool IsSuspended() { return suspended|suspended_slave; } virtual const char *GetLogContext() { return 0; } static const char *GetCurrentLogContext() { return current->GetLogContext(); } SMTask(); void DeleteLater(); static void Delete(SMTask *); void IncRefCount() { ref_count++; } void DecRefCount() { if(ref_count>0) ref_count--; } static SMTask *_MakeRef(SMTask *task) { if(task) task->IncRefCount(); return task; } static void _DeleteRef(SMTask *task) { if(task) { task->DecRefCount(); Delete(task); } } static SMTask *_SetRef(SMTask *task,SMTask *new_task); template static T *MakeRef(T *task) { _MakeRef(task); return task; } static int Roll(SMTask *); int Roll() { return Roll(this); } static void RollAll(const TimeInterval &max_time); static SMTask *current; static void Enter(SMTask *task); static void Leave(SMTask *task); void Enter() { Enter(this); } void Leave() { Leave(this); } static int TaskCount(); static void PrintTasks(); static bool NonFatalError(int err); static bool TemporaryNetworkError(int err) { return temporary_network_error(err); } static Error *SysError(int e=errno) { return new Error(e,strerror(e),!NonFatalError(e)); } static void Cleanup(); }; class SMTaskInit : public SMTask { int Do(); public: SMTaskInit(); ~SMTaskInit(); }; template class SMTaskRef { SMTaskRef(const SMTaskRef&); // disable cloning void operator=(const SMTaskRef&); // and assignment protected: T *ptr; public: SMTaskRef() { ptr=0; } SMTaskRef(T *p) : ptr(SMTask::MakeRef(p)) {} ~SMTaskRef() { SMTask::_DeleteRef(ptr); ptr=0; } void operator=(T *p) { ptr=static_cast(SMTask::_SetRef(ptr,p)); } operator const T*() const { return ptr; } T *operator->() const { return ptr; } T *borrow() { if(ptr) ptr->DecRefCount(); return replace_value(ptr,(T*)0); } const T *get() const { return ptr; } T *get_non_const() const { return ptr; } template const SMTaskRef& Cast() const { void(static_cast(ptr)); return *(const SMTaskRef*)this; } static const SMTaskRef null; void _set(T *p) { ptr=p; } void _clear() { ptr=0; } void unset() { *this=0; } }; template class TaskRefArray : public _RefArray< T,SMTaskRef > { TaskRefArray& operator=(const TaskRefArray&); // make assignment fail TaskRefArray(const TaskRefArray&); // disable cloning public: TaskRefArray() : _RefArray< T,SMTaskRef >() {} }; #endif /* SMTASK_H */ lftp-4.9.2/src/CmdExec.h0000644000015000007670000001477113160446205011677 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef CMDEXEC_H #define CMDEXEC_H #include #include "Job.h" #include "ArgV.h" #include "Filter.h" #include "alias.h" #include "History.h" #include "bookmark.h" #include "FileGlob.h" class QueueFeeder; class LocalDirectory; extern History cwd_history; #define CMD(name) Job *cmd_##name(CmdExec *parent) typedef Job * (*cmd_creator_t)(class CmdExec *parent); class CmdFeeder { public: xstring_c saved_buf; CmdFeeder *prev; virtual const char *NextCmd(class CmdExec *exec,const char *prompt) = 0; virtual ~CmdFeeder() {} virtual void clear() {} virtual bool RealEOF() { return true; } virtual void Fg() {} virtual void Bg() {} virtual bool IsInteractive() const { return false; } }; extern CmdFeeder *lftp_feeder; // feeder to use after 'lftp' command class CmdExec : public SessionJob, public ResClient { public: // current command data Ref args; Ref output; bool background; int exit_code; int prev_exit_code; private: CmdExec *parent_exec; Buffer cmd_buf; bool partial_cmd; int alias_field; // length of expanded alias (and ttl for used_aliases) int failed_exit_code; TouchedAlias *used_aliases; void free_used_aliases(); void skip_cmd(int len); enum { COND_ANY, COND_AND, COND_OR } condition; struct cmd_rec { const char *name; cmd_creator_t creator; const char *short_desc; const char *long_desc; static int cmp(const CmdExec::cmd_rec *a,const CmdExec::cmd_rec *b); }; static const cmd_rec static_cmd_table[]; static const int static_cmd_table_length; static xarray dyn_cmd_table; static int find_cmd(const char *cmd_name,const cmd_rec **ret); void exec_parsed_command(); enum parse_result { PARSE_OK, PARSE_ERR, PARSE_AGAIN }; parse_result parse_one_cmd(); CmdFeeder *feeder; bool feeder_called; bool fed_at_finish; void AtFinish(); enum builtins { BUILTIN_NONE=0, BUILTIN_OPEN, BUILTIN_CD, BUILTIN_EXEC_RESTART, BUILTIN_GLOB } builtin; FileAccess::Path old_cwd; xstring_c old_lcwd; xstring_c slot; Ref glob; Ref args_glob; int redirections; static CmdExec *chain; CmdExec *next; QueueFeeder *queue_feeder; CmdExec *GetQueue(bool create = true); bool SameQueueParameters(CmdExec *,const char *); int max_waiting; FileAccessRef saved_session; void ReuseSavedSession(); void RevertToSavedSession(); void init(LocalDirectory *c); public: void FeedCmd(const char *c); void FeedArgV(const ArgV *,int start=0); void PrependCmd(const char *c); void ExecParsed(ArgV *a,FDStream *o=0,bool b=false); static bool needs_quotation(const char *buf,int len); static bool needs_quotation(const char *buf) { return needs_quotation(buf,strlen(buf)); } static bool quotable(char c,char in_quotes); static bool is_space(char c) { return c==' ' || c=='\t'; } static bool is_quote(char c) { return c=='"' || c=='\''; } void FeedQuoted(const char *c); void Exit(int); void AtExit(); void AtExitBg(); void AtExitFg(); void AtBackground(); void AtTerminate(); void EmptyCmds(); bool WriteCmds(int fd) const; bool ReadCmds(int fd); // does not clear queue before reading (appends) void AddNewJob(Job *new_job); void SuspendJob(Job *j); CmdExec(FileAccess *s,LocalDirectory *c); CmdExec(CmdExec *parent); ~CmdExec(); bool Idle(); // when we have no command running and command buffer is empty int Done(); int ExitCode() { return failed_exit_code ? failed_exit_code : exit_code; } int Do(); xstring& FormatStatus(xstring&,int,const char *prefix="\t"); void ShowRunStatus(const SMTaskRef& s); int AcceptSig(int sig); const char *FormatPrompt(const char *scan); const char *MakePrompt(); bool interactive; bool show_status; bool top_level; bool verbose; bool auto_terminate_in_bg; SMTaskRef status_line; void SetCmdFeeder(CmdFeeder *new_feeder); void RemoveFeeder(); friend char *command_generator(char *,int); // readline completor static const char *GetFullCommandName(const char *); bool remote_completion; int long_running; bool csh_history; bool verify_host; bool verify_path; bool verify_path_cached; void Reconfig(const char *name=0); void beep_if_long(); time_t start_time; static CmdExec *cwd_owner; Ref cwd; void SaveCWD(); int RestoreCWD(); FDStream *default_output; void top_vfprintf(FILE *file,const char *f,va_list v); void SetInteractive(bool i); void SetInteractive(); void SetTopLevel() { top_level=true; Reconfig(0); SetInteractive(); } void SetStatusLine(StatusLine *s) { status_line=s; } void SetAutoTerminateInBackground(bool b) { auto_terminate_in_bg=b; } static void RegisterCommand(const char *name,cmd_creator_t creator, const char *short_name=0,const char *long_name=0); Job *builtin_lcd(); Job *builtin_cd(); Job *builtin_open(); Job *builtin_exit(); Job *builtin_lftp(); Job *builtin_restart(); Job *builtin_glob(); Job *builtin_queue(); Job *builtin_queue_edit(); Job *builtin_local(); bool load_cmd_module(const char *op); Job *default_cmd(); void ChangeSession(FileAccess *new_session); bool print_cmd_help(const char *cmd); void print_cmd_index(); static const char *CmdByIndex(int i); void enable_debug(const char *opt=0); int last_bg; bool wait_all; void pre_stdout(); void ChangeSlot(const char *n); static JobRef top; }; extern const char * const bookmark_subcmd[]; extern const char * const cache_subcmd[]; #endif//CMDEXEC_H lftp-4.9.2/src/mmvJob.cc0000644000015000007670000000754313077314505011762 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "trio.h" #include "mmvJob.h" #include "misc.h" #include "plural.h" #include "FileGlob.h" mmvJob::mmvJob(FileAccess *session,const ArgV *args,const char *t,FA::open_mode m1) : SessionJob(session), dst_dir(t), m(m1), remove_target(false), moved_count(0), error_count(0), done(false) { op.set(args->a0()); for(int i=args->getindex(); icount(); i++) wcd.push(xstrdup(args->getarg(i))); } void mmvJob::doOpen() const { if(remove_target && session->OpenMode()!=FA::REMOVE) session->Open(curr_dst,FA::REMOVE); else session->Open2(curr_src,curr_dst,m); } int mmvJob::Do() { int m=STALL; if(Done()) return STALL; if(glob) { // handle ongoing globbing if(glob->Error()) { fprintf(stderr,"%s: %s: %s\n",cmd(),glob->GetPattern(),glob->ErrorText()); error_count++; glob=0; return MOVED; } if(!glob->Done()) return m; // have globbed file set now FileSet *files=glob->GetResult(); files->rewind(); for(FileInfo *fi=files->curr(); fi; fi=files->next()) src.push(fi->name.borrow()); glob=0; } if(!curr_src) { // pick next file/wildcard to work on if(src.count()) { curr_src.set(src.next()); curr_dst.set(dir_file(dst_dir,basename_ptr(curr_src))); } else if(wcd.count()) { glob=session->MakeGlob(wcd.next()); glob->Roll(); return MOVED; } else { // no more files to move done=true; return MOVED; } } if(!session->IsOpen()) doOpen(); int res=session->Done(); if(res==FA::IN_PROGRESS || res==FA::DO_AGAIN) return m; if(res!=FA::OK && !isRemoving()) { fprintf(stderr,"%s: %s\n",cmd(),session->StrError(res)); error_count++; session->Close(); curr_src.unset(); return MOVED; } if(isRemoving()) { doOpen(); // do the real move now. return MOVED; } session->Close(); moved_count++; curr_src.unset(); return MOVED; } xstring& mmvJob::FormatStatus(xstring& s,int v,const char *prefix) { SessionJob::FormatStatus(s,v,prefix); if(Done()) return s; if(glob) s.appendf("%sglob %s [%s]\n",prefix,glob->GetPattern(),glob->Status()); else if(isRemoving()) s.appendf("%srm %s [%s]\n",prefix,curr_dst.get(),session->CurrentStatus()); else s.appendf("%s%s %s=>%s [%s]\n",prefix,cmd(),curr_src.get(),curr_dst.get(),session->CurrentStatus()); return s; } void mmvJob::ShowRunStatus(const SMTaskRef& s) { if(Done()) return; if(glob) s->Show("glob %s [%s]",glob->GetPattern(),glob->Status()); else if(isRemoving()) s->Show("rm %s [%s]",curr_dst.get(),session->CurrentStatus()); else s->Show("%s %s=>%s [%s]",cmd(),curr_src.get(),curr_dst.get(),session->CurrentStatus()); } void mmvJob::SayFinal() { if(error_count>0) printf(plural("%s: %d error$|s$ detected\n",error_count),cmd(),error_count); if(m==FA::RENAME) printf(plural("%s: %d file$|s$ moved\n",moved_count),cmd(),moved_count); else printf(plural("%s: %d file$|s$ linked\n",moved_count),cmd(),moved_count); } lftp-4.9.2/src/FileCopyOutputJob.h0000644000015000007670000000210413332534452013743 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef FILECOPYPEEROUTPUTJOB_H #define FILECOPYPEEROUTPUTJOB_H #include "OutputJob.h" class FileCopyPeerOutputJob : public FileCopyPeer { const JobRef& o; int Put_LL(const char *buf,int len); public: FileCopyPeerOutputJob(const JobRef& o); int Do(); void Fg(); void Bg(); }; #endif lftp-4.9.2/src/QueueFeeder.cc0000644000015000007670000002154512122060507012713 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* All indexes in this function start at 0; -1 is used contextually to * indicate the last job or moving to the end of the list. */ #include #include #include #include #include #include "QueueFeeder.h" #include "plural.h" #include "misc.h" const char *QueueFeeder::NextCmd(CmdExec *exec, const char *) { if(jobs == NULL) return NULL; /* denext the first job */ QueueJob *job = grab_job(0); buffer.truncate(0); if(xstrcmp(cur_pwd, job->pwd)) { buffer.append("cd ").append_quoted(job->pwd).append("; "); cur_pwd.set(job->pwd); } if(xstrcmp(cur_lpwd, job->lpwd)) { buffer.append("lcd ").append_quoted(job->lpwd).append("; "); cur_lpwd.set(job->lpwd); } buffer.append(job->cmd.get()).append('\n'); delete job; return buffer; } void QueueFeeder::QueueCmd(const char *cmd, const char *pwd, const char *lpwd, int pos, int v) { QueueJob *job = new QueueJob; job->cmd.set(cmd); job->pwd.set(pwd); job->lpwd.set(lpwd); /* we never want a newline at the end: */ if(last_char(job->cmd) == '\n') job->cmd.truncate(strlen(job->cmd)-1); insert_jobs(job, jobs, lastjob, pos != -1? get_job(pos): NULL); PrintJobs(job, v, _("Added job$|s$")); } int QueueFeeder::JobCount(const QueueJob *j) { int job_count=0; for(; j; j=j->next) job_count++; return job_count; } /* verbose: * 0, quiet * 1, interactive * 2, verbose (print changes of pwd and lpwd) * PrintRequeue, output to requeue */ xstring& QueueFeeder::FormatJobs(xstring& s,const QueueJob *job, int v, const char *plur) const { if(v < 1) return s; const char *pwd = 0, *lpwd = 0; if(v == PrintRequeue) { for(const QueueJob *j = job; j; j=j->next) { if(xstrcmp(pwd, job->pwd)) { s.append("cd ").append_quoted(job->pwd).append(" &\n"); pwd = job->pwd; } if(xstrcmp(lpwd, job->lpwd)) { s.append("lcd ").append_quoted(job->lpwd).append(" &\n"); lpwd = job->lpwd; } s.append("queue ").append_quoted(job->cmd).append('\n'); } return s; } int job_count=JobCount(job); if(job_count>1) s.appendf("%s:\n", plural(plur,job_count)); pwd = cur_pwd; lpwd = cur_lpwd; int n = 1; for(const QueueJob *j = job; j; j=j->next) { /* Print pwd/lpwd changes when v >= 2. (This only happens when there's * more than one.) */ if(xstrcmp(pwd, job->pwd)) { if(v > 2) { s.append("\tcd ").append_quoted(job->pwd).append('\n'); } pwd = job->pwd; } if(xstrcmp(lpwd, job->lpwd)) { if(v > 2) { s.append("\tlcd ").append_quoted(job->lpwd).append('\n'); } lpwd = job->lpwd; } if(job_count==1) s.appendf("%s: ", plural(plur,job_count)); else s.appendf("\t%2d. ",n++); s.append(j->cmd.get()).append('\n'); } return s; } void QueueFeeder::PrintJobs(const QueueJob *job, int v, const char *plur) const { xstring buf(""); FormatJobs(buf,job,v,plur); printf("%s",buf.get()); } bool QueueFeeder::DelJob(int from, int v) { QueueJob *job = grab_job(from); if(!job) { if(v > 0) { if(from == -1 || !jobs) printf(_("No queued jobs.\n")); else printf(_("No queued job #%i.\n"), from+1); } return false; } PrintJobs(job, v, _("Deleted job$|s$")); FreeList(job); return true; } bool QueueFeeder::DelJob(const char *cmd, int v) { QueueJob *job = grab_job(cmd); if(!job) { if(v > 0) { if(!jobs) printf(_("No queued jobs.\n")); else printf(_("No queued jobs match \"%s\".\n"), cmd); } return false; } PrintJobs(job, v, _("Deleted job$|s$")); FreeList(job); return true; } /* When moving, grab the insertion pointer *before* pulling out things to * move, since doing so will change offsets. (Note that "to == -1" means * "move to the end", not "before the last entry".) */ bool QueueFeeder::MoveJob(int from, int to, int v) { /* Safety: make sure we don't try to move an item before itself. */ if(from == to) return false; QueueJob *before = to != -1? get_job(to): NULL; QueueJob *job = grab_job(from); if(job == NULL) return false; PrintJobs(job, v, _("Moved job$|s$")); assert(job != before); insert_jobs(job, jobs, lastjob, before); return true; } bool QueueFeeder::MoveJob(const char *cmd, int to, int v) { QueueJob *before = to != -1? get_job(to): NULL; /* Mild hack: we need to make sure the "before" job isn't one that's * going to be moved, so move it upward until it isn't. */ while(before && !fnmatch(cmd, before->cmd,FNM_CASEFOLD)) before=before->next; QueueJob *job = grab_job(cmd); if(job == NULL) return false; PrintJobs(job, v, _("Moved job$|s$")); insert_jobs(job, jobs, lastjob, before); return true; } /* remove the given job from the list */ void QueueFeeder::unlink_job(QueueJob *job) { /* update head/tail */ if(!job->prev) jobs = jobs->next; if(!job->next) lastjob = lastjob->prev; /* linked list stuff */ if(job->prev) job->prev->next = job->next; if(job->next) job->next->prev = job->prev; job->prev = job->next = 0; } QueueFeeder::QueueJob *QueueFeeder::get_job(int n) { QueueJob *j; if(n == -1) { j = lastjob; } else { j = jobs; while(j && n--) j=j->next; } return j; } /* get the n'th job, removed from the list; returns NULL (an empty list) * if there aren't that many jobs: */ QueueFeeder::QueueJob *QueueFeeder::grab_job(int n) { QueueJob *j = get_job(n); if(j) unlink_job(j); return j; } QueueFeeder::QueueJob *QueueFeeder::grab_job(const char *cmd) { QueueJob *j = jobs, *head = NULL, *tail = NULL; while(j) { QueueJob *match = get_next_match(cmd, j); if(!match) break; j = match->next; /* matches */ unlink_job(match); insert_jobs(match, head, tail, NULL); } return head; } QueueFeeder::QueueJob *QueueFeeder::get_next_match(const char *cmd, QueueJob *j) { while(j) { if(!fnmatch(cmd, j->cmd,FNM_CASEFOLD)) return j; j = j->next; } return 0; } /* insert a list of jobs before "before", or at the end if before is NULL. * If before is not NULL, it must be contained between lst_head and lst_tail. */ void QueueFeeder::insert_jobs(QueueJob *job, QueueJob *&lst_head, QueueJob *&lst_tail, QueueJob *before) { assert(!job->prev); /* this should be an independant, clean list head */ /* Find the last entry in the new list. (This is a bit inefficient, as * we usually know this somewhere else, but passing around both head * and tail pointers of the new job list is too klugy.) */ QueueJob *tail = job; while(tail->next) tail=tail->next; if(!before) { /* end */ job->prev = lst_tail; tail->next = 0; /* superfluous; here for clarity */ } else { tail->next = before; job->prev = before->prev; } if(job->prev) job->prev->next = job; if(tail->next) tail->next->prev = tail; if(!tail->next) lst_tail = tail; if(!job->prev) lst_head = job; } /* Free a list of jobs (forward only; j should be a head pointer.) */ void QueueFeeder::FreeList(QueueJob *j) { while(j) { QueueJob *job = j; j = j->next; delete job; } } QueueFeeder::~QueueFeeder() { FreeList(jobs); } xstring& QueueFeeder::FormatStatus(xstring& s,int v,const char *prefix) const { if(jobs == NULL) return s; if(v == PrintRequeue) return FormatJobs(s, jobs, v, ""); s.append(prefix).append(_("Commands queued:")).append('\n'); int n = 1; const char *pwd = cur_pwd, *lpwd = cur_lpwd; for(const QueueJob *job = jobs; job; job = job->next) { if(v<2 && n>4 && job->next) { s.appendf("%s%2d. ...\n",prefix,n); break; } /* Print pwd/lpwd changes when v >= 2. */ if(v >= 2 && (xstrcmp(pwd, job->pwd))) s.appendf("%s cd %s\n",prefix,job->pwd.get()); if(v >= 2 && (xstrcmp(lpwd, job->lpwd))) s.appendf("%s lcd %s\n",prefix,job->lpwd.get()); pwd = job->pwd; lpwd = job->lpwd; s.appendf("%s%2d. %s\n",prefix,n++,job->cmd.get()); } return s; } lftp-4.9.2/src/lftp_rl.c0000644000015000007670000001333013062512164012011 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "lftp_rl.h" /* complete.cc */ void lftp_line_complete(); void lftp_add_history_nodups(const char *cmd_buf) { HIST_ENTRY *temp; char ts[24]; if(cmd_buf[0]==' ') return; using_history(); temp=previous_history(); if(temp==0 || strcmp(temp->line,cmd_buf)) add_history(cmd_buf); sprintf(ts," %lld",(long long)time(0)); add_history_time(ts); using_history(); } char *lftp_readline(const char *prompt) { char *ret = readline(prompt); /* Tell completion that we don't need completion data anymore; * it might be taking a good chunk of memory. */ lftp_line_complete(); return ret; } int lftp_history_expand(const char *what, char **where) { return history_expand((char*)what,where); } int lftp_history_read(const char *fn) { using_history(); return read_history(fn); } int lftp_history_write(const char *fn) { using_history(); return write_history(fn); } void lftp_history_list(int cnt) { HISTORY_STATE *st = history_get_history_state(); HIST_ENTRY *hist; int i; using_history(); i = history_base + st->length - cnt; if(cnt == -1 || i < history_base) i = history_base; char ts_str[24]; while((hist = history_get(i))) { ts_str[0]=0; if(hist->timestamp[0]) { time_t ts=atol(hist->timestamp+1); strftime(ts_str,sizeof(ts_str),"%Y-%m-%d %H:%M:%S",localtime(&ts)); } printf("%5d%c %s %s\n", i++, hist->data?'*':' ', ts_str, hist->line); } } void lftp_history_clear() { clear_history(); } static int is_clear=0; void lftp_rl_clear() { extern char *rl_display_prompt; extern int _rl_mark_modified_lines; int old_end=rl_end; char *old_prompt=rl_display_prompt; int old_mark=_rl_mark_modified_lines; rl_end=0; rl_display_prompt=""; rl_expand_prompt(0); _rl_mark_modified_lines=0; rl_redisplay(); rl_end=old_end; rl_display_prompt=old_prompt; _rl_mark_modified_lines=old_mark; if(rl_display_prompt==rl_prompt) rl_expand_prompt(rl_prompt); is_clear=1; } void lftp_rl_redisplay_maybe() { if(is_clear) rl_redisplay(); is_clear=0; } /* prototype hell differences in various readline versions make it impossible * to use certain functions/variables in C++ */ void lftp_rl_set_ignore_some_completions_function(int (*func)(char**)) { rl_ignore_some_completions_function=func; } char **lftp_rl_completion_matches(const char *text,char *(*compentry)(const char *,int)) { return rl_completion_matches(text,compentry); } void completion_display_list (char **matches, int len); void lftp_rl_display_match_list (char **matches, int len, int max) { printf("\n"); /* get off the input line */ completion_display_list(matches, len); rl_forced_update_display(); /* redraw input line */ } void lftp_rl_init( const char *readline_name, char **(*attempted_completion_function)(const char *,int,int), int (*getc_function)(FILE*), const char *completer_quote_characters, const char *completer_word_break_characters, const char *filename_quote_characters, char *(*filename_quoting_function)(char *,int,char *), char *(*filename_dequoting_function)(const char *,int), int (*char_is_quoted_p)(const char *,int)) { rl_readline_name =readline_name; rl_attempted_completion_function =attempted_completion_function; rl_getc_function =getc_function; rl_completer_quote_characters =completer_quote_characters; rl_completer_word_break_characters=(char*)completer_word_break_characters; rl_filename_quote_characters =filename_quote_characters; rl_filename_quoting_function =filename_quoting_function; rl_filename_dequoting_function =(rl_dequote_func_t*)filename_dequoting_function; rl_char_is_quoted_p =(rl_linebuf_func_t*)char_is_quoted_p; rl_completion_display_matches_hook = lftp_rl_display_match_list; history_write_timestamps=1; history_comment_char=' '; } void lftp_rl_add_defun(const char *name,int (*func)(int,int),int key) { rl_add_defun(name,func,key); } void lftp_rl_bind(const char *key,const char *func) { char *line=alloca(strlen(key)+2+strlen(func)+1); sprintf(line,"%s: %s",key,func); rl_parse_and_bind(line); } void lftp_rl_set_prompt(const char *p) { rl_set_prompt(p); } extern char *get_lftp_data_dir(); static char *lftp_history_file; void lftp_rl_read_history() { if(!lftp_history_file) { const char *add="/rl_history"; const char *home=get_lftp_data_dir(); if(!home) return; lftp_history_file=(char*)malloc(strlen(home)+strlen(add)+1); strcat(strcpy(lftp_history_file,home),add); } read_history(lftp_history_file); } void lftp_rl_write_history() { if(!lftp_history_file) return; write_history(lftp_history_file); } void lftp_rl_history_stifle(int s) { if(s==0) unstifle_history(); else stifle_history(s); } lftp-4.9.2/src/mvJob.cc0000644000015000007670000000461412122060320011560 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "trio.h" #include "mvJob.h" #include "misc.h" mvJob::mvJob(FileAccess *session,const char *f,const char *t,FA::open_mode m1) : SessionJob(session), from(f), to(t), m(m1), remove_target(false), failed(false), done(false) { if(to.last_char()=='/') to.append(basename_ptr(from)); doOpen(); } void mvJob::doOpen() const { if(remove_target) session->Open(to,FA::REMOVE); else session->Open2(from,to,m); } int mvJob::Do() { if(Done()) return STALL; int res=session->Done(); if(res==FA::IN_PROGRESS || res==FA::DO_AGAIN) return STALL; if(res!=FA::OK && !remove_target) { fprintf(stderr,"%s: %s\n",cmd(),session->StrError(res)); done=failed=true; } session->Close(); if(remove_target) { remove_target=false; doOpen(); } else done=true; return MOVED; } xstring& mvJob::FormatStatus(xstring& s,int v,const char *prefix) { SessionJob::FormatStatus(s,v,prefix); if(Done()) return s; if(remove_target) s.appendf("%srm %s [%s]\n",prefix,to.get(),session->CurrentStatus()); else s.appendf("%s%s %s=>%s [%s]\n",prefix,cmd(),from.get(),to.get(),session->CurrentStatus()); return s; } void mvJob::ShowRunStatus(const SMTaskRef& s) { if(Done()) return; if(remove_target) s->Show("rm %s [%s]\n",to.get(),session->CurrentStatus()); else s->Show("%s %s=>%s [%s]\n",cmd(),from.get(),to.get(),session->CurrentStatus()); } void mvJob::SayFinal() { if(failed) return; if(m==FA::RENAME) { // xgettext:c-format printf(_("rename successful\n")); } } lftp-4.9.2/src/CatJob.h0000644000015000007670000000240112122057153011511 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef CATJOB_H #define CATJOB_H #include "CopyJob.h" #include "StatusLine.h" #include "OutputJob.h" class ArgV; class CatJob : public CopyJobEnv { protected: JobRef output; bool ascii; bool auto_ascii; void NextFile(); public: int Do(); int Done(); int ExitCode(); CatJob(FileAccess *s,OutputJob *output,ArgV *args); void Ascii() { ascii=true; } void Binary() { ascii=auto_ascii=false; } void ShowRunStatus(const SMTaskRef&); }; #endif /* CATJOB_H */ lftp-4.9.2/src/keyvalue.h0000644000015000007670000000543712250325105012205 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KEYVALUE_H #define KEYVALUE_H #include "xstring.h" class StringMangler { typedef const char *(*mangle_t)(const char *); mangle_t mangle; public: const char *operator()(const char *s) { return mangle?mangle(s):s; } StringMangler(mangle_t m=0) { mangle=m; } }; class KeyValueDB { public: class Pair { public: xstring_c key; xstring_c value; Pair *next; Pair(const char *k,const char *v) : key(k), value(v), next(0) {} virtual ~Pair() {} int KeyCompare(const char *s) const { return strcmp(s,key); } void SetValue(const char *v) { value.set(v); } }; protected: void Purge(Pair **p) { Pair *to_free=*p; if(current==to_free) current=to_free->next; *p=to_free->next; delete to_free; } Pair **LookupPair(const char *key) const; void AddPair(Pair *p) { p->next=chain; chain=p; } virtual Pair *NewPair(const char *id,const char *value) { return new Pair(id,value); } int Lock(int fd,int type); Pair *chain; Pair *current; public: void Add(const char *id,const char *value); void Remove(const char *id); const char *Lookup(const char *id) const; void Empty() { while(chain) Purge(&chain); } int Write(int fd); int Read(int fd); void Sort(); char *Format(StringMangler m=0); // returns formatted contents (malloc'ed) void Rewind() { current=chain; } const char *CurrentKey() const { if(!current) return 0; return current->key; } const char *CurrentValue() const { if(!current) return 0; return current->value; } bool Next() { if(current==0) return false; current=current->next; return current!=0; } KeyValueDB() { chain=0; current=0; } virtual ~KeyValueDB() { Empty(); } static int KeyCompare(const Pair *a,const Pair *b) { return strcmp(a->key,b->key); } static int VKeyCompare(const void *a,const void *b); }; #endif //KEYVALUE_H lftp-4.9.2/src/buffer.h0000644000015000007670000002153113062512164011627 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BUFFER_H #define BUFFER_H #include "SMTask.h" #include "Filter.h" #include "Timer.h" #include "fg.h" #include "xstring.h" #include "Speedometer.h" #include #ifdef HAVE_ICONV CDECL_BEGIN # include CDECL_END #endif class Buffer { protected: xstring error_text; int saved_errno; bool error_fatal; xstring buffer; int buffer_ptr; bool eof; // no reads possible (except from mem buffer) bool broken; // no writes possible bool save; // save skipped data int save_max; off_t pos; Ref rate; void RateAdd(int n); void Allocate(int size); void SaveMaxCheck(int addsize); public: bool Error() const { return error_text!=0; } bool ErrorFatal() const { return error_fatal; } void SetError(const char *e,bool fatal=false); void SetErrorCached(const char *e); const char *ErrorText() const { return error_text; } int Size() const { return buffer.length()-buffer_ptr; } bool Eof() const { return eof; } bool Broken() const { return broken; } const char *Get() const; void Get(const char **buf,int *size) const; void Skip(int len); // Get(); consume; Skip() void UnSkip(int len); // this only works if there were no Put's. void Append(const char *buf,int size); void Append(const xstring& s) { Append(s.get(),s.length()); } void Put(const char *buf,int size); void Put(const char *buf) { Put(buf,strlen(buf)); } void Put(const xstring &s) { Put(s.get(),s.length()); } void Put(char c) { Put(&c,1); } void Format(const char *f,...) PRINTF_LIKE(2,3); void vFormat(const char *f, va_list v); void PutEOF() { eof=true; } char *GetSpace(int size) { Allocate(size); return buffer.get_non_const()+buffer.length(); } void SpaceAdd(int size) { buffer.set_length(buffer.length()+size); } void Prepend(const char *buf,int size); void Prepend(const char *buf) { Prepend(buf,strlen(buf)); } int MoveDataHere(Buffer *o,int len); template int MoveDataHere(const Ref& o,int len) { return MoveDataHere(o.get_non_const(),len); } template int MoveDataHere(const SMTaskRef& o,int len) { return MoveDataHere(o.get_non_const(),len); } unsigned long long UnpackUINT64BE(int offset=0) const; unsigned UnpackUINT32BE(int offset=0) const; unsigned UnpackUINT16BE(int offset=0) const; unsigned UnpackUINT8(int offset=0) const; void PackUINT64BE(unsigned long long data); void PackUINT32BE(unsigned data); void PackUINT16BE(unsigned data); void PackUINT8(unsigned data); long long UnpackINT64BE(int offset=0) const; int UnpackINT32BE(int offset=0) const; int UnpackINT16BE(int offset=0) const; int UnpackINT8(int offset=0) const; void PackINT64BE(long long data); void PackINT32BE(int data); void PackINT16BE(int data); void PackINT8(int data); // useful for cache. void Save(int m) { save=true; save_max=m; } bool IsSaving() const { return save; } void GetSaved(const char **buf,int *size) const; void SaveRollback(off_t p); void SetPos(off_t p) { pos=p; } off_t GetPos() const { return pos; } void SetSpeedometer(Speedometer *s) { rate=s; } const char *GetRateStrS(); void Empty(); Buffer(); ~Buffer(); const char *Dump() const; }; class DataTranslator : public Buffer { public: virtual void PutTranslated(Buffer *dst,const char *buf,int size)=0; virtual void ResetTranslation() { Empty(); } virtual ~DataTranslator() {} // same as PutTranslated, but does not advance pos. void AppendTranslated(Buffer *dst,const char *buf,int size); }; #ifdef HAVE_ICONV class DataRecoder : public DataTranslator { iconv_t backend_translate; public: void PutTranslated(Buffer *dst,const char *buf,int size); void ResetTranslation(); DataRecoder(const char *from_code,const char *to_code,bool translit=true); ~DataRecoder(); }; #endif //HAVE_ICONV class DirectedBuffer : public Buffer { public: enum dir_t { GET, PUT }; protected: Ref translator; dir_t mode; void EmbraceNewData(int len); public: DirectedBuffer(dir_t m) : mode(m) {} void SetTranslator(DataTranslator *t); const Ref& GetTranslator() const { return translator; } void SetTranslation(const char *be_encoding,bool translit=true) #ifdef HAVE_ICONV ; #else {} #endif //HAVE_ICONV void PutTranslated(const char *buf,int size); void PutTranslated(const char *buf) { PutTranslated(buf,strlen(buf)); } void PutTranslated(const xstring& s) { PutTranslated(s.get(),s.length()); } void ResetTranslation(); void PutRaw(const char *buf,int size) { Buffer::Put(buf,size); } void PutRaw(const char *buf) { Buffer::Put(buf); } void Put(const char *buf,int size); void Put(const char *buf) { Put(buf,strlen(buf)); } void PutEOF(); // set eof, flush translator int MoveDataHere(Buffer *o,int len); template int MoveDataHere(const SMTaskRef& o,int len) { return MoveDataHere(o.get_non_const(),len); } dir_t GetDirection() { return mode; } }; class IOBuffer : public DirectedBuffer, public SMTask { protected: // low-level for derived classes virtual int Get_LL(int size) { return 0; } virtual int Put_LL(const char *buf,int size) { return 0; } virtual int PutEOF_LL() { return 0; } Time event_time; // used to detect timeouts int max_buf; int get_size; int TuneGetSize(int res); enum { GET_BUFSIZE=0x10000, PUT_LL_MIN=0x2000, }; virtual ~IOBuffer(); public: IOBuffer(dir_t m); virtual const Time& EventTime() { if(IsSuspended()) return now; return event_time; } virtual bool Done() { return(broken || Error() || (eof && (mode==GET || Size()==0))); } virtual int Do(); virtual FgData *GetFgData(bool) { return 0; } virtual const char *Status() { return ""; } virtual int Buffered() { return Size(); } virtual bool TranslationEOF() const { return translator?translator->Eof():false; } // Put method with Put_LL shortcut void Put(const char *,int); void Put(const char *buf); void Put(const xstring &s) { Put(s.get(),s.length()); } void Put(char c) { Put(&c,1); } // anchor to PutEOF_LL void PutEOF() { DirectedBuffer::PutEOF(); PutEOF_LL(); } void SetMaxBuffered(int m) { max_buf=m; } bool IsFull() { return Size()+(translator?translator->Size():0) >= max_buf; } }; class IOBufferStacked : public IOBuffer { SMTaskRef down; int Get_LL(int size); int Put_LL(const char *buf,int size); void SuspendInternal(); void ResumeInternal(); public: IOBufferStacked(IOBuffer *b) : IOBuffer(b->GetDirection()), down(b) {} bool TranslationEOF() const { return down->TranslationEOF()||IOBuffer::TranslationEOF(); } void PrepareToDie() { down=0; } const Time& EventTime() { return down->EventTime(); } int Do(); bool Done(); }; class IOBufferFDStream : public IOBuffer { Ref my_stream; const Ref& stream; Ref put_ll_timer; int Get_LL(int size); int Put_LL(const char *buf,int size); public: IOBufferFDStream(FDStream *o,dir_t m) : IOBuffer(m), my_stream(o), stream(my_stream) {} IOBufferFDStream(const Ref& o,dir_t m) : IOBuffer(m), stream(o) {} IOBufferFDStream(FDStream *o,dir_t m,Timer *t) : IOBuffer(m), my_stream(o), stream(my_stream), put_ll_timer(t) {} IOBufferFDStream(const Ref& o,dir_t m,Timer *t) : IOBuffer(m), stream(o), put_ll_timer(t) {} ~IOBufferFDStream(); bool Done(); FgData *GetFgData(bool fg); const char *Status() { return stream->status; } }; #include class IOBufferFileAccess : public IOBuffer { const FileAccessRef& session; FileAccessRef session_ref; int Get_LL(int size); void SuspendInternal(); void ResumeInternal(); public: IOBufferFileAccess(const FileAccessRef& i) : IOBuffer(GET), session(i) {} IOBufferFileAccess(FileAccess *fa) : IOBuffer(GET), session(session_ref), session_ref(fa) {} ~IOBufferFileAccess() { // we don't want to delete the session (void)session_ref.borrow(); } const char *Status(); }; #endif // BUFFER_H lftp-4.9.2/src/FileGlob.cc0000644000015000007670000001564313143026735012212 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "trio.h" #include "xstring.h" #include #include #include #include #include #include "FileGlob.h" #include "misc.h" #include "url.h" #include "ResMgr.h" ResDecl res_nullglob("cmd:nullglob","yes",ResMgr::BoolValidate,ResMgr::NoClosure); // Glob implementation Glob::Glob(FileAccess *s,const char *p) : FileAccessOperation(s), pattern(p) { dirs_only=false; files_only=false; match_period=true; inhibit_tilde=true; casefold=false; if(pattern[0]=='~') { const char *slash=strchr(pattern,'/'); if(slash) inhibit_tilde=HasWildcards(xstring::get_tmp(pattern,slash-pattern)); else inhibit_tilde=HasWildcards(pattern); } if(pattern[0] && !HasWildcards(pattern)) { // no need to glob, just unquote char *u=alloca_strdup(pattern); UnquoteWildcards(u); add(new FileInfo(u)); done=true; } } Glob::~Glob() { } void Glob::add_force(const FileInfo *info) { // insert new file name into list list.Add(new FileInfo(*info)); } void Glob::add(const FileInfo *info) { if(info->defined&info->TYPE) { if(dirs_only && info->filetype==info->NORMAL) return; // note that symlinks can point to directories, // so skip normal files only. if(files_only && info->filetype==info->DIRECTORY) return; } const char *s=info->name; if(s==0) return; int flags=FNM_PATHNAME; if(match_period) flags|=FNM_PERIOD; if(casefold) flags|=FNM_CASEFOLD; if(pattern[0]!=0 && fnmatch(pattern, s, flags)!=0) return; // unmatched if(s[0]=='~' && inhibit_tilde) { char *new_name=alloca_strdup2(s,2); strcpy(new_name,"./"); strcat(new_name,s); FileInfo new_info(*info); new_info.SetName(new_name); add_force(&new_info); } else { add_force(info); } } bool Glob::HasWildcards(const char *s) { while(*s) { switch(*s) { case '\\': if(s[1]) s++; break; case '*': case '[': case ']': case '?': return true; } s++; } return false; } void Glob::UnquoteWildcards(char *s) { char *store=s; for(;;) { if(*s=='\\') { if(s[1]=='*' || s[1]=='[' || s[1]==']' || s[1]=='?' || s[1]=='\\') s++; } *store=*s; if(*s==0) break; s++; store++; } } int NoGlob::Do() { if(!done) { if(!HasWildcards(pattern)) { char *p=alloca_strdup(pattern); UnquoteWildcards(p); add(new FileInfo(p)); } done=true; return MOVED; } return STALL; } NoGlob::NoGlob(const char *p) : Glob(0,p) { } void GlobURL::NewGlob(const char *p) { glob=0; session=orig_session; url_prefix.set(p); url_prefix.truncate(url::path_index(p)); ParsedURL p_url(p,true); if(p_url.proto && p_url.path) { session=my_session=FA::New(&p_url); if(session) glob=session->MakeGlob(p_url.path); } else { glob=session->MakeGlob(p); } if(!glob) glob=new NoGlob(p); if(type==FILES_ONLY) glob->FilesOnly(); else if(type==DIRS_ONLY) glob->DirectoriesOnly(); } GlobURL::GlobURL(const FileAccessRef& s,const char *p,type_select t) : orig_session(s), session(orig_session), type(t) { nullglob=ResMgr::QueryBool("cmd:nullglob",0); NewGlob(p); } GlobURL::~GlobURL() {} FileSet *GlobURL::GetResult() { FileSet &list=*glob->GetResult(); if(list.count()==0 && !nullglob) list.Add(new FileInfo(glob->GetPattern())); if(session==orig_session) return &list; for(int i=0; list[i]; i++) list[i]->SetName(url_file(url_prefix,list[i]->name)); return &list; } // GenericGlob implementation GenericGlob::GenericGlob(FileAccess *s,const char *n_pattern) : Glob(s,n_pattern) { dir_list=0; curr_dir=0; if(done) return; char *dir=alloca_strdup(pattern); char *slash=strrchr(dir,'/'); if(!slash) dir=0; else if(slash>dir) *slash=0; // non-root directory else dir[1]=0; // root directory if(dir) { updir_glob=new GenericGlob(s,dir); updir_glob->DirectoriesOnly(); updir_glob->Suspend(); // don't run now, wait for options. } } int GenericGlob::Do() { int m=STALL; if(done) return m; if(!dir_list && updir_glob) { if(updir_glob->IsSuspended()) { // pass the options. updir_glob->MatchPeriod(match_period); updir_glob->InhibitTilde(inhibit_tilde); updir_glob->CaseFold(casefold); updir_glob->Resume(); } if(updir_glob->Error()) { SetError(updir_glob->ErrorText()); updir_glob=0; done=true; return MOVED; } if(!updir_glob->Done()) return m; dir_list=updir_glob->GetResult(); dir_list->rewind(); m=MOVED; if(dir_list==0 || dir_list->curr()==0) { done=true; return m; } curr_dir=dir_list->curr()->name; } if(li) { if(!li->Done() && !li->Error()) return m; if(li->Done() && !li->Error()) { FileSet *set=li->GetResult(); set->rewind(); for(FileInfo *info=set->curr(); info!=NULL; info=set->next()) { const char *name=info->name; if(name[0]=='.' && name[1]=='/') name+=2; if(curr_dir && curr_dir[0]) name=dir_file(curr_dir,name); info->SetName(name); add(info); } delete set; } if(dir_list) dir_list->next(); if(!dir_list || dir_list->curr()==0) { if(li && li->Error()) SetError(li->ErrorText()); li=0; done=true; return MOVED; } li=0; curr_dir=dir_list->curr()->name; } li=session->MakeListInfo(curr_dir); if(!li) { // Cannot glob. Just unquote wildcards. char *p=alloca_strdup(pattern); UnquoteWildcards(p); add(new FileInfo(p)); done=true; return MOVED; } li->UseCache(use_cache); return MOVED; } const char *GenericGlob::Status() { if(updir_glob && !dir_list) return updir_glob->Status(); if(!li) return ""; const char *st = li->Status(); if(!*st) return ""; if(!curr_dir) return st; static xstring buf; buf.vset(curr_dir,": ",st,NULL); return buf; } lftp-4.9.2/src/attach.cc0000644000015000007670000000161512122057014011753 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "attach.h" // this limits SendTermFD to a single instance, but we don't need more yet. pid_t SendTermFD::pass_pid; lftp-4.9.2/src/NetAccess.cc0000644000015000007670000004026113530052701012361 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "NetAccess.h" #include "log.h" #include "url.h" #include "LsCache.h" #include "misc.h" #include "Speedometer.h" #define super FileAccess xmap_p NetAccess::site_data; void NetAccess::Init() { resolver=0; idle_timer.SetResource("net:idle",0); timeout_timer.SetResource("net:timeout",0); max_persist_retries=0; persist_retries=0; socket_buffer=0; socket_maxseg=0; peer_curr=0; reconnect_interval=30; // retry with 30 second interval reconnect_interval_multiplier=1.2; reconnect_interval_max=300; rate_limit=0; connection_limit=0; // no limit. connection_takeover=false; Reconfig(0); reconnect_interval_current=reconnect_interval; } NetAccess::NetAccess() { Init(); } NetAccess::NetAccess(const NetAccess *o) : super(o) { Init(); if(o->peer) { peer.set(o->peer); peer_curr=o->peer_curr; if(peer_curr>=peer.count()) peer_curr=0; } home_auto.set(o->home_auto); } NetAccess::~NetAccess() { ClearPeer(); } void NetAccess::Cleanup() { if(hostname==0) return; for(FA *fo=FirstSameSite(); fo!=0; fo=NextSameSite(fo)) fo->CleanupThis(); CleanupThis(); } void NetAccess::CleanupThis() { if(!IsConnected() || mode!=CLOSED) return; Disconnect(); } void NetAccess::Reconfig(const char *name) { super::Reconfig(name); const char *c=hostname; reconnect_interval = ResMgr::Query("net:reconnect-interval-base",c); reconnect_interval_multiplier = ResMgr::Query("net:reconnect-interval-multiplier",c); if(reconnect_interval_multiplier<1) reconnect_interval_multiplier=1; reconnect_interval_max = ResMgr::Query("net:reconnect-interval-max",c); if(reconnect_interval_maxReconfig(name,c); } const char *NetAccess::CheckHangup(const struct pollfd *pfd,int num) { for(int i=0; ih_len || p_len==0) continue; if(!strcasecmp(hostname+h_len-p_len,p)) return true; } return false; } void NetAccess::HandleTimeout() { LogError(0,_("Timeout - reconnecting")); Disconnect(); timeout_timer.Reset(); } bool NetAccess::CheckTimeout() { if(timeout_timer.Stopped()) { HandleTimeout(); return(true); } return(false); } void NetAccess::ClearPeer() { peer.unset(); peer_curr=0; } void NetAccess::NextPeer() { peer_curr++; if(peer_curr>=peer.count()) peer_curr=0; else { if(retries>0) retries--; DontSleep(); // try next address immediately } } void NetAccess::ResetLocationData() { Disconnect(); ClearPeer(); super::ResetLocationData(); timeout_timer.SetResource("net:timeout",hostname); idle_timer.SetResource("net:idle",hostname); } void NetAccess::Open(const char *fn,int mode,off_t offs) { timeout_timer.Reset(); super::Open(fn,mode,offs); } int NetAccess::Resolve(const char *defp,const char *ser,const char *pr) { int m=STALL; if(!resolver) { peer.unset(); if(proxy) resolver=new Resolver(proxy,proxy_port,defp); else resolver=new Resolver(hostname,portname,defp,ser,pr); if(!resolver) return MOVED; resolver->Roll(); m=MOVED; } if(!resolver->Done()) return m; if(resolver->Error()) { SetError(LOOKUP_ERROR,resolver->ErrorMsg()); return(MOVED); } peer.set(resolver->Result()); if(peer_curr>=peer.count()) peer_curr=0; resolver=0; return MOVED; } bool NetAccess::ReconnectAllowed() { if(max_retries>0 && retries>=max_retries) return true; // it will fault later - no need to wait. int connection_limit=GetConnectionLimit(); if(connection_limit>0 && connection_limit<=CountConnections()) return false; if(reconnect_timer.Stopped()) return true; return false; } const char *NetAccess::DelayingMessage() { int connection_limit=GetConnectionLimit(); if(connection_limit>0 && connection_limit<=CountConnections()) return _("Connection limit reached"); long remains=reconnect_timer.TimeLeft(); if(remains<=0) return ""; current->TimeoutS(1); if(last_disconnect_cause && reconnect_timer.TimePassed()<5) return last_disconnect_cause; return xstring::format("%s: %ld",_("Delaying before reconnect"),remains); } bool NetAccess::NextTry() { if(!CheckRetries()) return false; if(retries==0) reconnect_interval_current=reconnect_interval; else if(reconnect_interval_multiplier>1) { reconnect_interval_current*=reconnect_interval_multiplier; if(reconnect_interval_current>reconnect_interval_max) reconnect_interval_current=reconnect_interval_max; } retries++; LogNote(10,"attempt number %d (max_retries=%d)",retries,max_retries); return CheckRetries(); } bool NetAccess::CheckRetries() { if(max_retries>0 && retries>max_retries) { if(!IsConnected() && last_disconnect_cause) Fatal(xstring::cat(_("max-retries exceeded")," (",last_disconnect_cause.get(),")",NULL)); else Fatal(_("max-retries exceeded")); return false; } reconnect_timer.Set(reconnect_interval_current); return true; } void NetAccess::TrySuccess() { retries=0; persist_retries=0; reconnect_interval_current=reconnect_interval; } void NetAccess::Close() { if(mode!=CLOSED) idle_timer.Reset(); TrySuccess(); resolver=0; super::Close(); } int NetAccess::CountConnections() { int count=0; for(FileAccess *o=FirstSameSite(); o!=0; o=NextSameSite(o)) { if(o->IsConnected()) count++; } return count; } void NetAccess::PropagateHomeAuto() { if(!home_auto) return; for(FA *fo=FirstSameSite(); fo!=0; fo=NextSameSite(fo)) { NetAccess *o=(NetAccess*)fo; // we are sure it is NetAccess. if(!o->home_auto) { o->home_auto.set(home_auto); if(!o->home) o->set_home(home_auto); } } } const char *NetAccess::FindHomeAuto() { for(FA *fo=FirstSameSite(); fo!=0; fo=NextSameSite(fo)) { NetAccess *o=(NetAccess*)fo; // we are sure it is NetAccess. if(o->home_auto) return o->home_auto; } return 0; } // GenericParseListInfo implementation int GenericParseListInfo::Do() { #define need_size (need&FileInfo::SIZE) #define need_time (need&FileInfo::DATE) FileInfo *file; int res; int m=STALL; int old_mode=mode; Ref set; do_again: if(done) return m; if(redir_resolution) { if(redir_session && redir_session->OpenMode()==FA::ARRAY_INFO) { res=redir_session->Done(); if(res==FA::DO_AGAIN || res==FA::IN_PROGRESS) return m; redir_session->Close(); redir_fs->rewind(); FileInfo *fi=redir_fs->curr(); if(ResolveRedirect(fi)) return MOVED; result->curr()->MergeInfo(*fi,~0U); result->next(); } redir_count=0; for(FileInfo *fi=result->curr(); fi; fi=result->next()) { if(ResolveRedirect(fi)) return MOVED; } FileAccess::cache->UpdateFileSet(session,"",FA::MP_LIST,result); FileAccess::cache->UpdateFileSet(session,"",FA::LONG_LIST,result); done=true; return MOVED; } if(session->OpenMode()==FA::ARRAY_INFO) { res=session->Done(); if(res==FA::DO_AGAIN) return m; if(res==FA::IN_PROGRESS) return m; session->Close(); // start redirection resolution. redir_resolution=true; result->rewind(); m=MOVED; goto do_again; } if(!ubuf) { const char *cache_buffer=0; int cache_buffer_size=0; const FileSet *cache_fset=0; int err; if(use_cache && FileAccess::cache->Find(session,"",mode,&err, &cache_buffer,&cache_buffer_size,&cache_fset)) { if(err) { if(mode==FA::MP_LIST) { mode=FA::LONG_LIST; goto do_again; } SetErrorCached(cache_buffer); return MOVED; } if(cache_fset) { Log::global->Write(11,"ListInfo: using cached file set\n"); set=new FileSet(cache_fset); old_mode=mode; goto got_fileset; } ubuf=new IOBuffer(IOBuffer::GET); ubuf->Put(cache_buffer,cache_buffer_size); ubuf->PutEOF(); } else { session->Open("",mode); session->UseCache(use_cache); ubuf=new IOBufferFileAccess(session); ubuf->SetSpeedometer(new Speedometer()); if(FileAccess::cache->IsEnabled(session->GetHostName())) ubuf->Save(FileAccess::cache->SizeLimit()); session->Roll(); ubuf->Roll(); } m=MOVED; } if(ubuf) { if(ubuf->Error()) { FileAccess::cache->Add(session,"",mode,session->GetErrorCode(),ubuf); if(mode==FA::MP_LIST) { mode=FA::LONG_LIST; ubuf=0; m=MOVED; goto do_again; } SetError(ubuf->ErrorText()); ubuf=0; return MOVED; } if(!ubuf->Eof()) return m; // now we have all the index in ubuf; parse it. const char *b; int len; ubuf->Get(&b,&len); old_mode=mode; set=Parse(b,len); // cache the list and the set. FileAccess::cache->Add(session,"",old_mode,FA::OK,ubuf,set); got_fileset: if(set) { set->rewind(); for(file=set->curr(); file!=0; file=set->next()) { // tilde is special. if(file->name[0]=='~') { // can't just update the name - it will break sorting file=set->borrow_curr(); file->name.set_substr(0,0,"./"); if(!result) result=new FileSet(); result->Add(file); } } if(result) { result->Merge(set); set=0; // free it now. } else result=set.borrow(); } ubuf=0; m=MOVED; // try another mode? Parse() can set mode to indicate it wants to try it. if(mode!=old_mode) return m; if(!result) result=new FileSet; if(exclude) result->Exclude(exclude_prefix,exclude,excluded.get_non_const()); result->rewind(); for(file=result->curr(); file!=0; file=result->next()) { file->need=0; if(need_size && !file->Has(file->SIZE)) file->Need(file->SIZE); if(need_time && (!file->Has(file->DATE) || (file->date.ts_prec>0 && can_get_prec_time))) file->Need(file->DATE); if(file->defined & file->TYPE) { if(file->filetype==file->SYMLINK && follow_symlinks) { file->filetype=file->UNKNOWN; file->defined &= ~(file->SIZE|file->SYMLINK_DEF|file->MODE|file->DATE|file->TYPE); file->Need(file->SIZE|file->DATE); } else if(file->filetype==file->SYMLINK) { // don't need these for symlinks file->NoNeed(file->SIZE|file->DATE); // but need the link target if(!file->Has(file->SYMLINK_DEF)) file->Need(file->SYMLINK_DEF); } else if(file->filetype==file->DIRECTORY) { if(!get_time_for_dirs) continue; // don't need size for directories file->NoNeed(file->SIZE); } } } session->GetInfoArray(result.get_non_const()); session->Roll(); } return m; } bool GenericParseListInfo::ResolveRedirect(const FileInfo *fi) { if(fi->filetype!=fi->REDIRECT || redir_count>=max_redir) return false; redir_count++; Log::global->Format(9,"ListInfo: resolving redirection %s -> %s\n",fi->name.get(),fi->GetRedirect()); Ref redir_fi(new FileInfo()); redir_fi->Need(fi->need); xstring loc(fi->GetRedirect()); ParsedURL u(loc,true); if(!u.proto) { // relative URI redir_session=session->Clone(); if(loc[0]=='/' || fi->uri) { if(loc[0]!='/') { const char *slash=strrchr(fi->uri,'/'); if(slash) loc.prepend(fi->uri,slash+1-fi->uri); } redir_fi->uri.set(loc); redir_fi->name.set(loc); redir_fi->name.url_decode(); } else { loc.url_decode(); const char *slash=strrchr(fi->name,'/'); if(slash) redir_fi->name.nset(fi->name,slash+1-fi->name); redir_fi->name.append(loc); } } else { // u.proto // absolute URL redir_session=FileAccess::New(&u); redir_fi->name.set(u.path?u.path.get():"/"); redir_fi->uri.set(url::path_ptr(u.orig_url)); } if(!redir_fs) redir_fs=new FileSet(); else redir_fs->Empty(); redir_fs->Add(redir_fi.borrow()); redir_session->GetInfoArray(redir_fs.get_non_const()); redir_session->Roll(); return true; } GenericParseListInfo::GenericParseListInfo(FileAccess *s,const char *p) : ListInfo(s,p), redir_resolution(false), redir_count(0), max_redir(ResMgr::Query("xfer:max-redirections",0)) { get_time_for_dirs=true; can_get_prec_time=true; mode=FA::MP_LIST; } const char *GenericParseListInfo::Status() { if(ubuf && !ubuf->Eof() && session->IsOpen()) return xstring::format("%s (%lld) %s[%s]",_("Getting directory contents"), (long long)session->GetPos(), ubuf->GetRateStrS(),session->CurrentStatus()); if(session->OpenMode()==FA::ARRAY_INFO) return xstring::format("%s (%d%%) [%s]",_("Getting files information"), session->InfoArrayPercentDone(), session->CurrentStatus()); return ""; } CDECL void lftp_network_cleanup() { NetAccess::ClassCleanup(); RateLimit::ClassCleanup(); } lftp-4.9.2/src/FtpDirList.cc0000644000015000007670000001413012662070340012535 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2013 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "FileAccess.h" #include "FtpDirList.h" #include "LsCache.h" #include "ArgV.h" #include "misc.h" #include "DirColors.h" #include "ftpclass.h" #include #include #ifdef TM_IN_SYS_TIME # include #endif #define super DirList int FtpDirList::Do() { int m=STALL; if(done) return m; if(buf->Eof()) { done=true; return MOVED; } if(!ubuf) { const char *cache_buffer=0; int cache_buffer_size=0; int err; if(use_cache && FileAccess::cache->Find(session,pattern,FA::LONG_LIST,&err, &cache_buffer,&cache_buffer_size)) { if(err) { SetErrorCached(cache_buffer); return MOVED; } ubuf=new IOBuffer(IOBuffer::GET); ubuf->Put(cache_buffer,cache_buffer_size); ubuf->PutEOF(); } else { session->Open(pattern,FA::LONG_LIST); ubuf=new IOBufferFileAccess(session); if(FileAccess::cache->IsEnabled(session->GetHostName())) ubuf->Save(FileAccess::cache->SizeLimit()); } } const char *b; int len; ubuf->Get(&b,&len); if(b==0) // eof { buf->PutEOF(); FileAccess::cache->Add(session,pattern,FA::LONG_LIST,FA::OK,ubuf); return MOVED; } while(len>0) { const char *eol=find_char(b,len,'\n'); if(!eol && !ubuf->Eof() && len<0x1000) break; if(eol) { int line_len=eol+1-b; if(!TryEPLF(b, eol-b) && !TryMLSD(b, eol-b) && !TryColor(b, eol-b)) buf->Put(b,line_len); ubuf->Skip(line_len); } else { // too long line of missing \n on last line. buf->Put(b,len); ubuf->Skip(len); } ubuf->Get(&b,&len); m=MOVED; } if(ubuf->Error()) { SetError(ubuf->ErrorText()); m=MOVED; } return m; } const char *FtpDirList::Status() { if(ubuf && !ubuf->Eof() && session->IsOpen()) { return xstring::format(_("Getting file list (%lld) [%s]"), (long long)session->GetPos(),session->CurrentStatus()); } return ""; } void FtpDirList::SuspendInternal() { super::SuspendInternal(); if(ubuf) ubuf->SuspendSlave(); } void FtpDirList::ResumeInternal() { if(ubuf) ubuf->ResumeSlave(); super::ResumeInternal(); } void FtpDirList::FormatGeneric(FileInfo *fi) { bool dir=(fi->defined&fi->TYPE) && fi->filetype==fi->DIRECTORY; if(!(fi->defined&fi->MODE)) fi->mode=(dir?0755:0644); char size_str[32]; if(fi->defined&fi->SIZE) snprintf(size_str,sizeof(size_str),"%lld",(long long)fi->size); else strcpy(size_str,"-"); const char *date_str="-"; if(fi->defined&fi->DATE) date_str=TimeDate(fi->date).IsoDateTime(); buf->Format("%c%s %10s %16s ", dir ? 'd':'-', format_perms(fi->mode), size_str, date_str); if(color) DirColors::GetInstance()-> PutColored(buf,fi->name,fi->filetype); else buf->Put(fi->name); buf->Put("\r\n"); delete fi; } FileInfo *ParseFtpLongList_EPLF(char *line,int *err,const char *); bool FtpDirList::TryEPLF(const char *line_c, int len) { // check for EPLF listing if(len<2) return false; if(line_c[0]!='+') return false; char *line=string_alloca(len+1); strncpy(line,line_c,len); line[len]=0; int err=0; FileInfo *fi=ParseFtpLongList_EPLF(line,&err,0); if(!fi) return false; // ok, this is EPLF. Format new string. FormatGeneric(fi); return true; } bool FtpDirList::TryColor(const char *line_c,int len) { if(!color) return false; char *line=string_alloca(len+1); strncpy(line,line_c,len); line[len]=0; if(len>0 && line[len-1]=='\r') line[len-1]=0; char year_or_time[6]; char perms[12],user[32],group[32],month_name[4]; int nlink,day,year,hour,minute; long long size; int consumed=0; int n=sscanf(line,"%11s %d %31s %31s %lld %3s %2d %5s%n",perms,&nlink, user,group,&size,month_name,&day,year_or_time,&consumed); if(n==4) // bsd-like listing without group? { group[0]=0; n=sscanf(line,"%11s %d %31s %lld %3s %2d %5s%n",perms,&nlink, user,&size,month_name,&day,year_or_time,&consumed); if(n!=7) return false; } else if(n!=8) return false; if(consumed>0 && -1!=(parse_perms(perms+1)) && -1!=(parse_month(month_name)) && -1!=parse_year_or_time(year_or_time,&year,&hour,&minute) && strlen(line+consumed)>1) { // good. int type=-1; int name_start=consumed+1; int name_len=strlen(line+name_start); if(perms[0]=='d') type=FileInfo::DIRECTORY; else if(perms[0]=='l') { type=FileInfo::SYMLINK; const char *str=strstr(line+name_start+1," -> "); if(str) name_len=str-(line+name_start); } else if(perms[0]=='-') type=FileInfo::NORMAL; buf->Put(line,consumed+1); char *name=string_alloca(name_len+1); strncpy(name,line+name_start,name_len); name[name_len]=0; DirColors::GetInstance()->PutColored(buf,name,type); buf->Put(line+name_start+name_len); buf->Put("\r\n"); return true; } return false; } FileInfo *ParseFtpLongList_MLSD(char *line,int *err,const char *); bool FtpDirList::TryMLSD(const char *line_c,int len) { char *line=string_alloca(len+1); strncpy(line,line_c,len); line[len]=0; int err=0; FileInfo *fi=ParseFtpLongList_MLSD(line,&err,0); if(!fi) return false; FormatGeneric(fi); return true; } lftp-4.9.2/src/verify-file0000755000015000007670000000575712662070341012371 00000000000000#!/usr/bin/perl -w # # This is a file verification tool for lftp. # # Copyright (c) 2005-2014 by Alexander V. Lukyanov (lav@yars.free.net) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # use strict; use Digest::MD5; use String::CRC32; my $err=0; file: foreach my $file (@ARGV) { my $verified=0; if(-d $file) { print STDERR "$file: Is a directory\n"; $err++; next; } unless(-r $file) { print STDERR "$file: $!\n"; $err++; next; } my ($dir,$name); if($file=~m'/') { ($dir,$name)=($file=~m{(.*)/(.+)}); $dir='/' if $dir eq ''; } else { $name=$file; $dir='.'; } my @md5files=(glob("$dir/*md5{,sum}"),glob("$dir/*MD5{,SUM}")); if(@md5files) { open MD5,'-|',qw{fgrep -w --},$name,'/dev/null',@md5files; while() { chomp; my ($md5,$name1)=split; (my $md5_file,$md5)=($md5=~m{(.*):(.*)}); $md5_file=~s{^\./}{}; next if $name1 ne $name; my $ctx=Digest::MD5->new; open FILE,'<',$file; $ctx->addfile(*FILE); close FILE; if(lc($md5) ne $ctx->hexdigest) { print STDERR "$file: MD5 digest mismatch (md5 file: $md5_file)\n"; $err++; $verified++; } else { print "$file: MD5 OK (md5 file: $md5_file)\n"; $verified++; } } close MD5; } next file if $verified; my @sfvfiles=(glob("$dir/*.sfv"),glob("$dir/*.SFV")); if(@sfvfiles) { open SFV,'-|',qw{fgrep -w --},$name,'/dev/null',@sfvfiles; while() { chomp; my ($name1,$crc32)=split; (my $sfv_file,$name1)=($name1=~m{(.*):(.*)}); $sfv_file=~s{^\./}{}; next if $name1 ne $name; open FILE,'<',$file; my $crc321=crc32(*FILE); close FILE; if($crc321!=hex($crc32)) { print STDERR "$file: CRC32 mismatch (sfv file: $sfv_file)\n"; $err++; $verified++; } else { print "$file: CRC32 OK (sfv file: $sfv_file)\n"; $verified++; } } close SFV; } next file if $verified; if($name=~/\.gz$/) { system qw{gzip -tv},$file; my $e=($?>>8); $err++ if $e; next file; } if($name=~/\.bz2$/) { system qw{bzip2 -tv},$file; my $e=($?>>8); $err++ if $e; next file; } if($name=~/\.zip$/) { system qw{unzip -tqq},$file; my $e=($?>>8); $err++ if $e; next file; } if($name=~/\.rpm$/) { system qw{rpm --checksig},$file; my $e=($?>>8); $err++ if $e; next file; } } exit $err?1:0; lftp-4.9.2/src/mmvJob.h0000644000015000007670000000331113062512164011604 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MMVJOB_H #define MMVJOB_H #include "Job.h" #include "StatusLine.h" #include "ArgV.h" #include "trio.h" class mmvJob : public SessionJob { xstring_c op; xqueue_m wcd; xqueue_m src; xstring dst_dir; xstring curr_dst; xstring curr_src; SMTaskRef glob; FA::open_mode m; bool remove_target; int moved_count; int error_count; bool done; void doOpen() const; bool isRemoving() const { return session->OpenMode()==FA::REMOVE; } public: int Do(); int Done() { return done; } int ExitCode() { return error_count>0; } xstring& FormatStatus(xstring&,int,const char *); void ShowRunStatus(const SMTaskRef&); void SayFinal(); void doOpen(const char *src) const; const char *cmd() const { return op; } mmvJob(FileAccess *session,const ArgV *args,const char *t,FA::open_mode m=FA::RENAME); void RemoveTargetFirst() { remove_target=true; } }; #endif // MMVJOB_H lftp-4.9.2/src/SignalHook.cc0000644000015000007670000000432412122060612012543 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "SignalHook.h" int *SignalHook::counts=0; struct sigaction *SignalHook::old_handlers=0; bool *SignalHook::old_saved=0; void SignalHook::cnt_handler(int sig) { counts[sig]++; } void SignalHook::set_signal(int sig,signal_handler handler) { if(!old_saved[sig]) { sigaction(sig,0,&old_handlers[sig]); if(sig==SIGINT && old_handlers[sig].sa_handler==(signal_handler)SIG_IGN) return; old_saved[sig]=true; } struct sigaction act; act.sa_handler=handler; act.sa_flags=0; sigemptyset(&act.sa_mask); sigaction(sig,&act,0); } void SignalHook::Restore(int i) { if(old_saved[i]) sigaction(i,&old_handlers[i],0); SignalHook::Unblock(i); } void SignalHook::RestoreAll() { for(int i=0; i<256; i++) Restore(i); } void SignalHook::Block(int sig) { sigset_t s; sigemptyset(&s); sigaddset(&s,sig); sigprocmask(SIG_BLOCK,&s,0); } void SignalHook::Unblock(int sig) { sigset_t s; sigemptyset(&s); sigaddset(&s,sig); sigprocmask(SIG_UNBLOCK,&s,0); } void SignalHook::ClassInit() { if(counts) return; counts=new int[256]; old_handlers=new struct sigaction[256]; old_saved=new bool[256]; for(int i=0; i<256; i++) { counts[i]=0; old_saved[i]=false; } Ignore(SIGPIPE); // want to get EPIPE #ifdef SIGXFSZ Ignore(SIGXFSZ); // and EFBIG #endif } void SignalHook::Cleanup() { delete [] counts; delete [] old_handlers; delete [] old_saved; } lftp-4.9.2/src/HttpAuth.h0000644000015000007670000000676012676222157012140 00000000000000/* * lftp - file transfer program * * Copyright (c) 2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef HTTPAUTH_H #define HTTPAUTH_H #include "xmap.h" #include "xarray.h" #include "HttpHeader.h" class HttpAuth { public: enum target_t { WWW=0, PROXY }; enum scheme_t { NONE=0, BASIC, DIGEST }; class Challenge { scheme_t scheme_code; xstring scheme; xmap_p param; void SetParam(const char *p,int p_len,const xstring &v) { param.add(xstring::get_tmp(p,p_len).c_lc(),new xstring(v.copy())); } void SetParam(const xstring &p,const xstring &v) { param.add(p,new xstring(v.copy())); } public: Challenge(const char *); const xstring& GetScheme() { return scheme; } scheme_t GetSchemeCode() { return scheme_code; } const xstring& GetRealm() { return GetParam("realm"); } const xstring& GetParam(const char *p) { const xstring *v=param.lookup(p); return v?*v:xstring::null; } }; protected: target_t target; xstring uri; Ref chal; xstring user; xstring pass; HttpHeader header; static xstring& append_quoted(xstring& s,const char *n,const char *v); // array is enough as there are not too many HttpAuth objects. static xarray_p cache; public: HttpAuth(target_t t,const char *p_uri,Challenge *p_chal,const char *p_user,const char *p_pass) : target(t), uri(p_uri), chal(p_chal), user(p_user), pass(p_pass), header(t==WWW?"Authorization":"Proxy-Authorization") {} virtual ~HttpAuth() {} virtual bool IsValid() const { return true; } virtual bool Update(const char *p_method,const char *p_uri,const char *entity_hash=0) { return true; } const HttpHeader *GetHeader() { return &header; } bool ApplicableForURI(const char *) const; bool Matches(target_t t,const char *p_uri,const char *p_user); static bool New(target_t t,const char *p_uri, Challenge *p_chal,const char *p_user,const char *p_pass); static HttpAuth *Get(target_t t,const char *p_uri,const char *p_user); static void CleanCache(target_t t,const char *p_uri,const char *p_user); }; class HttpAuthBasic : public HttpAuth { void MakeHeader(); public: HttpAuthBasic(target_t t,const char *p_uri,Challenge *p_chal,const char *p_user,const char *p_pass) : HttpAuth(t,p_uri,p_chal,p_user,p_pass) { MakeHeader(); } }; class HttpAuthDigest : public HttpAuth { xstring cnonce; // random client nonce xstring HA1; // "session key" A1 in lower-case hex unsigned nc; void MakeHA1(); public: HttpAuthDigest(target_t t,const char *p_uri,Challenge *p_chal,const char *p_user,const char *p_pass) : HttpAuth(t,p_uri,p_chal,p_user,p_pass), nc(0) { MakeHA1(); } bool IsValid() const { return HA1.length()>0; } bool Update(const char *p_method,const char *p_uri,const char *entity_hash); }; #endif//HTTPAUTH_H lftp-4.9.2/src/network.h0000644000015000007670000001140013607663135012053 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2020 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef NETWORK_H #define NETWORK_H #include #include "sockets.h" #include #if HAVE_SYS_SOCKET_H # include #elif HAVE_WS2TCPIP_H # include #endif #include #include class sockaddr_compact : public xstring { void operator=(const sockaddr_compact&); // disable assignment public: int family() const { if(length()==16 || length()==18) return AF_INET6; if(length()==4 || length()==6) return AF_INET; return 0; } int port() const { if(length()==18 || length()==6) return ((buf[length()-2]&255)<<8)|(buf[length()-1]&255); return 0; } void set_port(int p) { if(length()==18 || length()==6) { buf[length()-2]=((p>>8)&255); buf[length()-1]=(p&255); } } const char *address() const; static sockaddr_compact& get_tmp() { return *(sockaddr_compact*)&xstring::get_tmp("",0); } static sockaddr_compact& cast(xstring& s) { return *(sockaddr_compact*)&s; } static const sockaddr_compact& cast(const xstring& s) { return *(const sockaddr_compact*)&s; } sockaddr_compact() {} sockaddr_compact(const sockaddr_compact& c) : xstring(c.copy()) {} }; union sockaddr_u { struct sockaddr sa; struct sockaddr_in in; #if INET6 struct sockaddr_in6 in6; #endif socklen_t addr_len() const { if(sa.sa_family==AF_INET) return sizeof(in); #if INET6 if(sa.sa_family==AF_INET6) return sizeof(in6); #endif return sizeof(*this); } bool operator==(const sockaddr_u &o) const { return !memcmp(this,&o,addr_len()); } bool operator!=(const sockaddr_u &o) const { return memcmp(this,&o,addr_len()); } const char *address() const; int port() const; int bind_to(int s) const { return bind(s,&sa,addr_len()); } void clear() { memset(this,0,sizeof(*this)); } sockaddr_u() { clear(); } sockaddr_u(const sockaddr_compact& c) { clear(); set_compact(c); } bool is_reserved() const; bool is_multicast() const; bool is_loopback() const; bool is_private() const; bool is_compatible(const sockaddr_u&) const; const xstring& to_xstring() const; const char *to_string() const { return to_xstring(); } operator const char *() const { return to_string(); } bool set_defaults(int af,const char *hostname,int port); void set_port(int port); int family() const { return sa.sa_family; } bool set_compact(const char *c,size_t len); bool set_compact(const xstring& c) { return set_compact(c,c.length()); } const sockaddr_compact& compact() const; sockaddr_compact& compact_addr() const; }; inline const char *sockaddr_compact::address() const { return sockaddr_u(*this).address(); } class Networker { protected: static void NonBlock(int fd); static void CloseOnExec(int fd); static void KeepAlive(int sock); static void MinimizeLatency(int sock); static void MaximizeThroughput(int sock); static void ReuseAddress(int sock); static int SocketBuffered(int sock); static const char *SocketNumericAddress(const sockaddr_u *u) { return u->address(); } static int SocketPort(const sockaddr_u *u) { return u->port(); } static socklen_t SocketAddrLen(const sockaddr_u *u) { return u->addr_len(); } static int SocketConnect(int fd,const sockaddr_u *u); static int SocketAccept(int fd,sockaddr_u *u,const char *hostname=0); static void SetSocketBuffer(int sock,int socket_buffer); static void SetSocketMaxseg(int sock,int socket_maxseg); static void SocketBindStd(int s,int af,const char *hostname,int port=0); static int SocketCreate(int af,int type,int proto,const char *hostname); static void SocketTuneTCP(int s,const char *hostname); static int SocketCreateTCP(int af,const char *hostname); static int SocketCreateUnbound(int af,int type,int proto,const char *hostname); static int SocketCreateUnboundTCP(int af,const char *hostname); static void SocketSinglePF(int sock,int pf); static const char *FindGlobalIPv6Address(); static bool CanCreateIpv6Socket(); }; #endif //NETWORK_H lftp-4.9.2/src/DirColors.h0000644000015000007670000000274112662070340012260 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DIRCOLORS_H #define DIRCOLORS_H #include "SMTask.h" #include "keyvalue.h" #include "buffer.h" class FileInfo; class DirColors : public ResClient, public KeyValueDB { static DirColors *instance; static const char resource[]; void Parse(const char *); public: void Reconfig(const char *name); DirColors(); const char *GetColor(const FileInfo *); const char *GetColor(const char *,int); void PutColored(const Ref& buf,const char *name,int type); void PutReset(const Ref& buf); static DirColors *GetInstance() { if(!instance) instance=new DirColors(); return instance; } static void DeleteInstance() { delete instance; instance=0; } }; #endif lftp-4.9.2/src/EditJob.cc0000644000015000007670000000472013410732340012032 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2015 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "EditJob.h" #include "GetJob.h" #include "SysCmdJob.h" void EditJob::Finish(int e) { exit_code=e; done=true; if(!keep) unlink(temp_file); } int EditJob::HandleJob(JobRef& j,bool fail) { if(!j->Done()) return STALL; if(j->ExitCode() && fail) Finish(1); RemoveWaiting(j); return MOVED; } int EditJob::Do() { int m=STALL; if(Done()) return m; if(put) { if(!HandleJob(put)) return m; if(done) return MOVED; Finish(0); return MOVED; } if(editor) { if(!HandleJob(editor)) return m; if(done) return MOVED; struct stat st; int res=stat(temp_file,&st); if(res<0) { perror(temp_file); Finish(1); return MOVED; } if(st.st_mtime!=mtime) { ArgV *args=new ArgV("put"); args->Append(temp_file); args->Append(file); GetJob *j=new GetJob(session->Clone(),args,false); j->Reverse(); put=j; AddWaiting(put); return MOVED; } Finish(0); return MOVED; } if(get) { if(!HandleJob(get,false)) return m; if(done) return MOVED; struct stat st; int res=stat(temp_file,&st); mtime=(res>=0?st.st_mtime:NO_DATE); const char *bin=getenv("EDITOR"); if (bin==NULL) bin="vi"; xstring cmd(bin); cmd.append(" "); cmd.append(shell_encode(temp_file)); editor=new SysCmdJob(cmd); AddWaiting(editor); return MOVED; } else { ArgV *args=new ArgV("get"); args->Append(file); args->Append(temp_file); get=new GetJob(session->Clone(),args,false); AddWaiting(get); return MOVED; } return m; } lftp-4.9.2/src/CopyJob.h0000644000015000007670000001125313077314504011727 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COPYJOB_H #define COPYJOB_H #include "Job.h" #include "StatusLine.h" #include "FileCopy.h" class CopyJob : public Job { protected: SMTaskRef c; bool done; xstring_c name; // file name xstring_c dispname; // displayed file name xstring_c op; // command name bool no_status; bool no_status_on_write; bool clear_status_on_write; bool quiet; void SetDispName(); void PrepareToDie(); public: CopyJob(FileCopy *c1,const char *n,const char *op1); ~CopyJob(); void NoStatus(bool t=true) { no_status=t; } void NoStatusOnWrite() { no_status_on_write=true; } void ClearStatusOnWrite() { clear_status_on_write=true; } bool HasStatus() const { return !no_status; } void Quiet(bool q) { quiet=q; } int Do(); int Done() { return done; } int ExitCode(); void SuspendInternal() { c->SuspendSlave(); } void ResumeInternal() { c->ResumeSlave(); } void Fg() { if(c) c->Fg(); Job::Fg(); } void Bg() { Job::Bg(); if(c) c->Bg(); } int AcceptSig(int sig); pid_t GetProcGroup() { return c?c->GetProcGroup():0; } bool Error() { return c->Error(); } const char *ErrorText() { return c->ErrorText(); } double GetTimeSpent() { return c->GetTimeSpent(); } off_t GetBytesCount() { return c->GetBytesCount(); } double GetTransferRate() { return c->GetTransferRate(); } off_t GetSize() { return c->GetSize(); } off_t GetPos() { return c->GetPos(); } float GetRate() { return c->GetRate(); } long GetETA() { return c->GetETA(); } long GetETA(off_t rem) { return c->GetETA(rem); } const char *GetETAStrSFromTime(time_t t) { return c->GetETAStrSFromTime(t); } void SetRange(off_t s,off_t lim) { c->SetRange(s,lim); } void SetRangeLimit(off_t lim) { return c->SetRangeLimit(lim); } void SetDate(const FileTimestamp& d) { c->SetDate(d); } void SetSize(off_t s) { c->SetSize(s); } const SMTaskRef& GetCopy() const { return c; } const SMTaskRef& GetPut() const { return c->put; } const SMTaskRef& GetGet() const { return c->get; } const Ref& GetLocal() const { return GetPut()->GetLocal(); } const char *Status(const StatusLine *s,bool base=false); void ShowRunStatus(const SMTaskRef&); xstring& FormatStatus(xstring&,int,const char *); const char *GetName() const { return name; } const char *GetDispName() const { return dispname; } const char *SqueezeName(int w, bool base=false); static CopyJob *NewGet(FileAccess *f,const char *src,const char *dst); static CopyJob *NewPut(FileAccess *f,const char *src,const char *dst); static const char *FormatBytesTimeRate(off_t bytes,double time); }; class CopyJobCreator { public: virtual CopyJob *New(FileCopy *c,const char *n,const char *o) const = 0; virtual ~CopyJobCreator() {} }; class ArgV; class CopyJobEnv : public SessionJob { protected: CopyJob *cp; bool done; int errors; int count; int parallel; off_t bytes; TimeDate transfer_start_ts; double time_spent; const char *op; bool no_status; xstring_c cwd; bool cont; bool ascii; bool quiet; Ref args; virtual void NextFile() = 0; void SetCopier(FileCopy *c,const char *n); void AddCopier(FileCopy *c,const char *n); Ref cj_new; public: int Do(); int Done(); virtual int ExitCode() { return errors!=0; } int AcceptSig(int sig); CopyJobEnv(FileAccess *s,ArgV *a,bool c=false); ~CopyJobEnv(); void SetCopyJobCreator(CopyJobCreator *c) { cj_new=c; } void SayFinal(); xstring& FormatFinalWithPrefix(xstring&,const char *); xstring& FormatStatus(xstring&,int,const char *); void Ascii() { ascii=true; } double GetTimeSpent() { return time_spent+(waiting.count()>0?now-transfer_start_ts:0.); } off_t GetBytesCount() { return bytes+Job::GetBytesCount(); } void Quiet(bool q) { quiet=q; } void SetParallel(int n) { parallel=n; } }; #endif // COPYJOB_H lftp-4.9.2/src/FileFeeder.cc0000644000015000007670000000301312122057450012477 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "FileFeeder.h" const char *FileFeeder::NextCmd(CmdExec *exec, const char *) { int fd=in->getfd(); if(fd<0) { if(in->error()) { fprintf(stderr,"source: %s\n",in->error_text.get()); return 0; } return ""; } if(fg_data==0) fg_data=new FgData(in->GetProcGroup(),true); int res=read(fd,buffer,sizeof(buffer)-1); if(res==0) { return 0; } if(res<0) { if(E_RETRY(errno)) { exec->Block(fd,POLLIN); return ""; } if(SMTask::NonFatalError(errno)) return ""; perror("source"); return 0; } buffer[res]=0; return buffer; } FileFeeder::FileFeeder(FDStream *in) : in(in) { } FileFeeder::~FileFeeder() { } lftp-4.9.2/src/resource.cc0000644000015000007670000004475713666255310012371 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2019 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "ResMgr.h" #include "url.h" #include "GetPass.h" #include "ascii_ctype.h" #include "configmake.h" #include "misc.h" #include "localcharset.h" static const char *FtpProxyValidate(xstring_c *p) { ParsedURL url(*p); if(url.host==0) { p->truncate(0); return 0; } if(url.proto) { if(strcmp(url.proto,"ftp") && strcmp(url.proto,"http")) return _("Proxy protocol unsupported"); } if(url.user && !url.pass) { url.pass.set(GetPass(_("ftp:proxy password: "))); p->truncate(); url.CombineTo(*p); } return 0; } static const char *SetValidate(xstring_c& s,const char *const *set,const char *name) { const char *const *scan; for(scan=set; *scan; scan++) if(s.eq(*scan)) return 0; xstring &j=xstring::get_tmp(); if(name) j.setf(_("%s must be one of: "),name); else j.set(_("must be one of: ")); bool had_empty=false; for(scan=set; *scan; scan++) { if(!**scan) { had_empty=true; continue; } if(scan>set) j.append(", "); j.append(*scan); } if(had_empty) j.append(_(", or empty")); return j; } static const char *FtpProxyAuthTypeValidate(xstring_c *s) { static const char *const valid_set[]={ "user", "joined", "joined-acct", "open", "proxy-user@host", 0 }; return SetValidate(*s,valid_set,"ftp:proxy-auth-type"); } static const char *HttpProxyValidate(xstring_c *p) { ParsedURL url(*p); if(url.host==0) { p->truncate(0); return 0; } if(url.proto) { if(strcmp(url.proto,"http") && strcmp(url.proto,"https")) return _("Proxy protocol unsupported"); } return 0; } static const char *PutOrPost(xstring_c *s) { if(strcasecmp(*s,"PUT") && strcasecmp(*s,"POST")) return _("only PUT and POST values allowed"); for(char *scan=s->get_non_const(); *scan; scan++) *scan=to_ascii_upper((unsigned char)*scan); return 0; } static const char *const af_list[]= { "inet", #if INET6 "inet6", #endif 0 }; static const char *OrderValidate(xstring_c *s) { static xstring error; xstring fixed; const char * const delim="\t "; char *s1=alloca_strdup(*s); for(s1=strtok(s1,delim); s1; s1=strtok(0,delim)) { const char *const *f; for(f=af_list; *f; f++) { if(!strcasecmp(s1,*f)) break; } if(!*f) { error.setf(_("unknown address family `%s'"),s1); return error; } if(fixed) fixed.vappend(" ",s1,NULL); else fixed.set(s1); } s->set(fixed); return 0; } static const char *SortByValidate(xstring_c *s) { static const char * const valid_set[]={ "name", "name-desc", "size", "size-desc", "date", "date-desc", 0 }; return SetValidate(*s,valid_set,"mirror:order-by"); } #if USE_SSL static const char *AuthArgValidate(xstring_c *s) { for(char *i=s->get_non_const(); *i; i++) *i=to_ascii_upper(*i); const char *const valid_set[]={ "SSL", "TLS", "TLS-P", "TLS-C", 0 }; return SetValidate(*s,valid_set,"ftp:ssl-auth"); } static const char *ProtValidate(xstring_c *s) { for(char *i=s->get_non_const(); *i; i++) *i=to_ascii_upper(*i); const char *const valid_set[]={ "C", "S", "E", "P", "", 0 }; return SetValidate(*s,valid_set,"ftps:initial-prot"); } #endif static ResType lftp_vars[] = { {"ftp:abor-max-wait", "15s", ResMgr::TimeIntervalValidate,0}, {"ftp:acct", "", 0,0}, {"ftp:anon-pass", "lftp@", 0,0}, {"ftp:anon-user", "anonymous",0,0}, {"ftp:auto-sync-mode", "", ResMgr::ERegExpValidate,0}, {"ftp:auto-passive-mode", "yes", ResMgr::BoolValidate,0}, {"ftp:bind-data-socket", "yes", ResMgr::BoolValidate,0}, {"ftp:catch-size", "yes", ResMgr::BoolValidate,0}, {"ftp:charset", "", ResMgr::CharsetValidate,0}, {"ftp:client", PACKAGE "/" VERSION,0,0}, {"ftp:compressed-re", "\\.(bz2|[glrsx7]z|lzma|lz[hox]|[ai]ce|apk|ar[cj]|cab|cfs|dar|[je]ar|lha|isz|pak|rar|sitx?|t(gz|bz2|lz)|tar\\.(gz|xz|bz2|lzma)|war|zipx?|zoo|[arz0][0-9][0-9])$",ResMgr::ERegExpValidate,ResMgr::NoClosure}, {"ftp:device-prefix", "no", ResMgr::BoolValidate,0}, {"ftp:fix-pasv-address", "yes", ResMgr::BoolValidate,0}, {"ftp:ignore-pasv-address", "no", ResMgr::BoolValidate,0}, {"ftp:fxp-force", "no", ResMgr::BoolValidate,0}, {"ftp:fxp-passive-source", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"ftp:fxp-passive-sscn", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"ftp:home", "", 0,0}, {"ftp:site" "", 0,0}, {"ftp:site-group", "", 0,0}, {"ftp:lang", "", 0,0}, {"ftp:list-empty-ok", "no", 0,0}, {"ftp:list-options", "", 0,0}, {"ftp:mode-z-level", "6", ResMgr::UNumberValidate,0}, {"ftp:nop-interval", "120", ResMgr::UNumberValidate,0}, {"ftp:passive-mode", "on", ResMgr::BoolValidate,0}, {"ftp:port-range", "full", ResMgr::RangeValidate,0}, {"ftp:port-ipv4", "", ResMgr::IPv4AddrValidate,0}, {"ftp:prefer-epsv", "no", ResMgr::BoolValidate,0}, {"ftp:proxy", "", FtpProxyValidate,0}, {"ftp:proxy-auth-type", "user", FtpProxyAuthTypeValidate,0}, {"ftp:rest-list", "no", ResMgr::BoolValidate,0}, {"ftp:rest-stor", "yes", ResMgr::BoolValidate,0}, {"ftp:timezone", "GMT", 0,0}, {"ftp:too-many-re", "(Too many|No more) connections",ResMgr::ERegExpValidate,0}, {"ftp:skey-allow", "yes", ResMgr::BoolValidate,0}, {"ftp:skey-force", "no", ResMgr::BoolValidate,0}, {"ftp:netkey-allow", "yes", ResMgr::BoolValidate,0}, #if USE_SSL {"ftp:ssl-allow", "yes", ResMgr::BoolValidate,0}, {"ftp:ssl-force", "no", ResMgr::BoolValidate,0}, {"ftp:ssl-protect-data", "yes", ResMgr::BoolValidate,0}, {"ftp:ssl-protect-fxp", "yes", ResMgr::BoolValidate,0}, {"ftp:ssl-protect-list", "yes", ResMgr::BoolValidate,0}, {"ftp:ssl-auth", "TLS", AuthArgValidate,0}, {"ftp:ssl-allow-anonymous", "no", ResMgr::BoolValidate,0}, {"ftp:ssl-use-ccc", "no", ResMgr::BoolValidate,0}, {"ftp:ssl-shutdown-timeout", "5", ResMgr::TimeIntervalValidate,0}, {"ftp:ssl-data-use-keys", "yes", ResMgr::BoolValidate,0}, {"ftp:ssl-copy-sid", "yes", ResMgr::BoolValidate,0}, {"ftps:initial-prot", "", ProtValidate,0}, #endif {"ftp:stat-interval", "1", ResMgr::TimeIntervalValidate,0}, {"ftp:strict-multiline", "off", ResMgr::BoolValidate,0}, {"ftp:sync-mode", "on", ResMgr::BoolValidate,0}, {"ftp:trust-feat", "no", ResMgr::BoolValidate,0}, {"ftp:use-abor", "yes", ResMgr::BoolValidate,0}, {"ftp:use-allo", "no", ResMgr::BoolValidate,0}, {"ftp:use-feat", "yes", ResMgr::BoolValidate,0}, {"ftp:use-fxp", "yes", ResMgr::BoolValidate,0}, {"ftp:use-hftp", "yes", ResMgr::BoolValidate,0}, {"ftp:use-mdtm", "yes", ResMgr::BoolValidate,0}, {"ftp:use-mdtm-overloaded", "no", ResMgr::BoolValidate,0}, {"ftp:use-mlsd", "yes", ResMgr::BoolValidate,0}, {"ftp:use-mode-z", "yes", ResMgr::BoolValidate,0}, {"ftp:use-pret", "auto", ResMgr::TriBoolValidate,0}, {"ftp:use-site-chmod", "yes", ResMgr::BoolValidate,0}, {"ftp:use-site-idle", "no", ResMgr::BoolValidate,0}, {"ftp:use-site-utime", "yes", ResMgr::BoolValidate,0}, {"ftp:use-site-utime2", "yes", ResMgr::BoolValidate,0}, {"ftp:use-size", "yes", ResMgr::BoolValidate,0}, {"ftp:use-stat", "yes", ResMgr::BoolValidate,0}, {"ftp:use-stat-for-list", "no", ResMgr::BoolValidate,0}, {"ftp:use-telnet-iac", "yes", ResMgr::BoolValidate,0}, {"ftp:use-tvfs", "auto", ResMgr::TriBoolValidate,0}, {"ftp:use-ip-tos", "no", ResMgr::BoolValidate,0}, {"ftp:use-utf8", "yes", ResMgr::BoolValidate,0}, {"ftp:use-quit", "yes", ResMgr::BoolValidate,0}, {"ftp:verify-address", "no", ResMgr::BoolValidate,0}, {"ftp:verify-port", "no", ResMgr::BoolValidate,0}, {"ftp:web-mode", "off", ResMgr::BoolValidate,0}, {"ftp:waiting-150-timeout", "5", ResMgr::TimeIntervalValidate,0}, #define RETRY_530 \ "too many|overloaded|try (again |back )?later|is restricted to|"\ "maximum number|number of connect|only.*session.*allowed|more connection|already connected|simultaneous login" {"ftp:retry-530", RETRY_530,ResMgr::ERegExpValidate,0}, {"ftp:retry-530-anonymous", "Login incorrect",ResMgr::ERegExpValidate,0}, {"hftp:cache", "yes", ResMgr::BoolValidate,0}, {"hftp:cache-control", "", 0,0}, {"hftp:decode", "no", ResMgr::BoolValidate,0}, {"hftp:proxy", "", HttpProxyValidate,0}, {"hftp:use-authorization", "yes", ResMgr::BoolValidate,0}, {"hftp:use-head", "yes", ResMgr::BoolValidate,0}, {"hftp:use-mkcol", "no", ResMgr::BoolValidate,0}, {"hftp:use-propfind", "no", ResMgr::BoolValidate,0}, {"hftp:use-range", "yes", ResMgr::BoolValidate,0}, {"hftp:use-allprop", "no", ResMgr::BoolValidate,0}, {"hftp:use-type", "yes", ResMgr::BoolValidate,0}, {"http:accept", "*/*", 0,0}, {"http:accept-language", "", 0,0}, {"http:accept-charset", "", 0,0}, {"http:accept-encoding", "", 0,0}, {"http:authorization", "", 0,0}, {"http:cache", "yes", ResMgr::BoolValidate,0}, {"http:cache-control", "", 0,0}, {"http:decode", "yes", ResMgr::BoolValidate,0}, {"http:proxy", "", HttpProxyValidate,0}, {"http:use-mkcol", "yes", ResMgr::BoolValidate,0}, {"http:use-propfind", "no", ResMgr::BoolValidate,0}, {"http:use-range", "yes", ResMgr::BoolValidate,0}, {"http:use-allprop", "no", ResMgr::BoolValidate,0}, {"http:user-agent", PACKAGE "/" VERSION,0,0}, {"http:cookie", "", 0,0}, {"http:set-cookies", "no", 0,0}, {"http:post-content-type", "application/x-www-form-urlencoded",0,0}, {"http:put-method", "PUT", PutOrPost,0}, {"http:put-content-type", "", 0,0}, {"http:referer", "", 0,0}, #if USE_SSL {"https:proxy", "", HttpProxyValidate,0}, #endif {"net:idle", "3m", ResMgr::TimeIntervalValidate,0}, {"net:limit-max", "0", ResMgr::UNumberValidate,0}, {"net:limit-rate", "0:0", ResMgr::UNumberPairValidate,0}, {"net:limit-total-max", "0", ResMgr::UNumberValidate,0}, {"net:limit-total-rate", "0:0", ResMgr::UNumberPairValidate,0}, {"net:max-retries", "1000", ResMgr::UNumberValidate,0}, {"net:persist-retries", "0", ResMgr::UNumberValidate,0}, {"net:no-proxy", "", 0,ResMgr::NoClosure}, {"net:reconnect-interval-base","15", ResMgr::UNumberValidate,0}, {"net:reconnect-interval-multiplier","1.5",ResMgr::FloatValidate,0}, {"net:reconnect-interval-max","300", ResMgr::UNumberValidate,0}, {"net:socket-buffer", "0", ResMgr::UNumberValidate,0}, {"net:socket-maxseg", "0", ResMgr::UNumberValidate,0}, {"net:socket-bind-ipv4", "", ResMgr::IPv4AddrValidate,0}, #if INET6 {"net:socket-bind-ipv6", "", ResMgr::IPv6AddrValidate,0}, #endif {"net:timeout", "5m", ResMgr::TimeIntervalValidate,0}, {"net:connection-limit", "0", ResMgr::UNumberValidate,0}, {"net:connection-limit-timer","5m", ResMgr::TimeIntervalValidate,0}, {"net:connection-takeover", "yes", ResMgr::BoolValidate,0}, {"mirror:sort-by", "name", SortByValidate,ResMgr::NoClosure}, {"mirror:order", "*.sfv *.sig *.md5* *.sum * */", 0,ResMgr::NoClosure}, {"mirror:parallel-directories", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:parallel-transfer-count", "0",ResMgr::UNumberValidate,0}, {"mirror:exclude-regex", "(^|/)(\\.in\\.|\\.nfs)",ResMgr::ERegExpValidate,ResMgr::NoClosure}, {"mirror:include-regex", "", ResMgr::ERegExpValidate,ResMgr::NoClosure}, {"mirror:use-pget-n", "0", ResMgr::UNumberValidate,0}, {"mirror:set-permissions", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:dereference", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:skip-noaccess", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:no-empty-dirs", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:require-source", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"mirror:overwrite", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"sftp:auto-confirm", "no", ResMgr::BoolValidate,0}, {"sftp:max-packets-in-flight","16", ResMgr::UNumberValidate,0}, {"sftp:protocol-version", "6", ResMgr::UNumberValidate,0}, {"sftp:size-read", "32k", ResMgr::UNumberValidate,0}, {"sftp:size-write", "32k", ResMgr::UNumberValidate,0}, {"sftp:connect-program", "ssh -a -x",0,0}, {"sftp:server-program", "sftp", 0,0}, {"sftp:charset", "", ResMgr::CharsetValidate,0}, {"sftp:use-full-path", "yes", ResMgr::BoolValidate,0}, {"file:charset", "", ResMgr::CharsetValidate,ResMgr::NoClosure}, {"file:use-lock", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"file:use-fallocate", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"dns:cache-enable", "yes", ResMgr::BoolValidate,0}, {"dns:cache-expire", "1h", ResMgr::TimeIntervalValidate,0}, {"dns:cache-size", "256", ResMgr::UNumberValidate,ResMgr::NoClosure}, {"dns:fatal-timeout", "7d", ResMgr::TimeIntervalValidate,0}, {"dns:max-retries", "1000", ResMgr::UNumberValidate,0}, {"dns:name", "", 0,ResMgr::HasClosure}, #if INET6 # define DEFAULT_ORDER "inet6 inet" #else # define DEFAULT_ORDER "inet" #endif {"dns:order", DEFAULT_ORDER, OrderValidate,0}, {"dns:SRV-query", "no", ResMgr::BoolValidate,0}, {"dns:use-fork", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, #ifdef DNSSEC_LOCAL_VALIDATION {"dns:strict-dnssec", "no", ResMgr::BoolValidate,0}, #endif {"fish:auto-confirm", "no", ResMgr::BoolValidate,0}, {"fish:shell", "/bin/sh",0,0}, {"fish:connect-program", "ssh -a -x",0,0}, {"fish:charset", "", ResMgr::CharsetValidate,0}, {"color:dir-colors", "", 0,ResMgr::NoClosure}, {"xfer:destination-directory","", 0,0}, {"xfer:verify", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:verify-command", "", ResMgr::FileExecutable,0}, {"xfer:auto-rename", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:max-log-size", "1M", ResMgr::UNumberValidate,ResMgr::NoClosure}, {"xfer:use-temp-file", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:temp-file-name", ".in.*", 0,ResMgr::NoClosure}, {"xfer:timeout", "1d", ResMgr::TimeIntervalValidate,ResMgr::NoClosure}, {"xfer:clobber", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:make-backup", "yes", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:keep-backup", "no", ResMgr::BoolValidate,ResMgr::NoClosure}, {"xfer:backup-suffix", "~%Y%m%d%H%M%S~",0,ResMgr::NoClosure}, {"xfer:parallel", "1", ResMgr::UNumberValidate,ResMgr::NoClosure}, // deprecated settings {"xfer:log", "log:enabled/xfer", 0,ResMgr::AliasValidate}, {"xfer:log-file", "log:file/xfer", 0,ResMgr::AliasValidate}, {"xfer:max-log-size", "log:max-size/xfer", 0,ResMgr::AliasValidate}, #if USE_SSL {"ssl:ca-file", "", ResMgr::FileReadable,ResMgr::NoClosure}, {"ssl:crl-file", "", ResMgr::FileReadable,ResMgr::NoClosure}, {"ssl:key-file", "", ResMgr::FileReadable,0}, {"ssl:cert-file", "", ResMgr::FileReadable,0}, {"ssl:check-hostname", "yes", ResMgr::BoolValidate,0}, {"ssl:verify-certificate", "yes", ResMgr::BoolValidate,0}, {"ssl:use-sni", "yes", ResMgr::BoolValidate,0}, {"ssl:priority", "", 0,0}, # if USE_OPENSSL {"ssl:ca-path", "", ResMgr::DirReadable,ResMgr::NoClosure}, {"ssl:crl-path", "", ResMgr::DirReadable,ResMgr::NoClosure}, # endif #endif {0} }; static ResDecls lftp_vars_register(lftp_vars); #ifdef HAVE_LANGINFO_H # include #endif bool ResType::class_inited; void ResType::ClassInit() { if(class_inited) return; class_inited=true; for(ResType *scan=types_by_name->each_begin(); scan; scan=types_by_name->each_next()) { if(scan->defvalue && scan->val_valid) { xstring_c dv(scan->defvalue); const char *error=(*scan->val_valid)(&dv); if(error) fprintf(stderr,"Default value for %s is invalid: %s\n",scan->name,error); else if(strcmp(dv,scan->defvalue)) fprintf(stderr,"Default value for %s (%s) is not in canonic form: %s\n",scan->name,scan->defvalue,dv.get()); } } // inherit http proxy from environment const char *http_proxy=getenv("http_proxy"); if(http_proxy) { Set("http:proxy",0,http_proxy); Set("hftp:proxy",0,http_proxy); } #if USE_SSL const char *https_proxy=getenv("https_proxy"); if(https_proxy) Set("https:proxy",0,https_proxy); #endif const char *ftp_proxy=getenv("ftp_proxy"); if(ftp_proxy) { if(!strncmp(ftp_proxy,"ftp://",6)) Set("ftp:proxy",0,ftp_proxy); else if(!strncmp(ftp_proxy,"http://",7)) Set("hftp:proxy",0,ftp_proxy); } const char *no_proxy=getenv("no_proxy"); if(no_proxy) Set("net:no-proxy",0,no_proxy); const char *module_path=getenv("LFTP_MODULE_PATH"); if(module_path) Set("module:path",0,module_path); const char *dir_colors=getenv("LS_COLORS"); if(!dir_colors) dir_colors=getenv("ZLS_COLORS"); /* zsh */ if(dir_colors) Set("color:dir-colors",0,dir_colors); const char *cs=locale_charset(); if(cs && cs[0]) Set("file:charset",0,cs); const char *time_style=getenv("TIME_STYLE"); if(time_style && *time_style) Set("cmd:time-style",0,time_style); SetDefault("xfer:verify-command",0,PKGDATADIR"/verify-file"); const char *ctx="xfer"; SetDefault("log:enabled",ctx,"yes"); SetDefault("log:show-time",ctx,"yes"); SetDefault("log:file",ctx,dir_file(get_lftp_data_dir(),"transfer_log")); } lftp-4.9.2/src/ColumnOutput.cc0000644000015000007670000001375412122057230013174 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include "SMTask.h" #include "ColumnOutput.h" #include "ResMgr.h" #include "misc.h" #include "DirColors.h" ResDecl res_color ("color:use-color", "auto",ResMgr::TriBoolValidate,ResMgr::NoClosure); #define lst_cnt lst.count() void ColumnOutput::add(const char *name, const char *color) { lst[lst_cnt-1]->append(name, color); } void ColumnOutput::addf(const char *fmt, const char *color, ...) { va_list v; va_start(v, color); add(xstring::vformat(fmt,v), color); va_end(v); } void ColumnOutput::append() { lst.append(new datum); } /* The minimum width of a colum is 3: 1 character for the name and 2 * for the separating white space. */ #define MIN_COLUMN_WIDTH 3 /* Assuming cursor is at position FROM, indent up to position TO. * Use a TAB character instead of two or more spaces whenever possible. */ static void indent (int from, int to, const JobRef& o) { // TODO #define tabsize 8 while (from < to) { if (tabsize > 0 && to / tabsize > (from + 1) / tabsize) { o->Put("\t"); from += tabsize - from % tabsize; } else { o->Put(" "); from++; } } } void ColumnOutput::get_print_info(unsigned width, xarray &col_arr, xarray &ws_arr, int &cols) const { /* Maximum number of columns ever possible for this display. */ int max_idx = width / MIN_COLUMN_WIDTH; if (max_idx == 0) max_idx = 1; /* Normally the maximum number of columns is determined by the * screen width. But if few files are available this might limit it * as well. */ int max_cols = max_idx > lst_cnt ? lst_cnt : max_idx; if(max_cols < 1) max_cols = 1; /* Compute the maximum number of possible columns. */ for (cols = max_cols; cols >= 1; cols--) { col_arr.truncate(); ws_arr.truncate(); for (int j = 0; j < max_idx; ++j) { col_arr.append(MIN_COLUMN_WIDTH); ws_arr.append(99999999); } int filesno; /* Find the amount of whitespace shared by every entry in the column. */ for (filesno = 0; filesno < lst_cnt; ++filesno) { int idx = filesno / ((lst_cnt + cols - 1) / cols); int ws = lst[filesno]->whitespace(); if(ws < ws_arr[idx]) ws_arr[idx] = ws; } /* Strip as much whitespace off the left as possible, but strip * the same amount from each entry (per column) to keep each * column aligned with itself. */ unsigned line_len = cols * MIN_COLUMN_WIDTH; for (filesno = 0; filesno < lst_cnt; ++filesno) { int idx = filesno / ((lst_cnt + cols - 1) / cols); int name_length = lst[filesno]->width(); /* all but the last column get 2 spaces of padding */ int real_length = name_length + (idx == cols-1 ? 0 : 2) - ws_arr[idx]; if (real_length <= col_arr[idx]) continue; line_len += (real_length - col_arr[idx]); col_arr[idx] = real_length; } if(line_len < width) break; /* found it */ } if(cols == 0) cols = 1; } void ColumnOutput::print(const JobRef& o, unsigned width, bool color) const { if(!lst_cnt) return; /* we have nothing to display */ int cols; xarray col_arr; xarray ws_arr; get_print_info(width, col_arr, ws_arr, cols); /* Calculate the number of rows that will be in each column except possibly * for a short column on the right. */ int rows = lst_cnt / cols + (lst_cnt % cols != 0); DirColors *dc=DirColors::GetInstance(); const char *color_pref =dc->Lookup(".lc"); const char *color_suf =dc->Lookup(".rc"); const char *color_reset=dc->Lookup(".ec"); for (int row = 0; row < rows; row++) { int col = 0; int filesno = row; int pos = 0; /* Current character column. */ /* Print the next row. */ while (1) { lst[filesno]->print(o, color, ws_arr[col], color_pref, color_suf, color_reset); int name_length = lst[filesno]->width() - ws_arr[col]; int max_name_length = col_arr[col++]; filesno += rows; if (filesno >= lst_cnt) break; indent (pos + name_length, pos + max_name_length, o); pos += max_name_length; } o->Put("\n"); } } void datum::append(const char *name, const char *color) { names.Append(name); colors.Append(color); if(names.Count() == 1) { ws = 0; for(int c = 0; name[c]; c++) { if(name[c] != ' ') break; ws++; } } curwidth += mbswidth(name, 0); } void datum::print(const JobRef& o, bool color, int skip, const char *color_pref, const char *color_suf, const char *color_reset) const { const char *cur_color = 0; for(int i = 0; i < names.Count(); i++) { int len = strlen(names[i]); if(len < skip) { skip -= len; continue; } if(color) { if(colors[i][0]) { /* if it's the same color, don't bother */ if(!cur_color || !strcmp(cur_color, colors[i])) { o->Put(color_pref); o->Put(colors[i]); o->Put(color_suf); cur_color = colors[i]; } } else { /* reset color, if we have one */ if(cur_color) { o->Put(color_reset); cur_color = 0; } } } o->Put(names[i]+skip); skip = 0; } if(cur_color) o->Put(color_reset); } lftp-4.9.2/src/HttpAuth.cc0000644000015000007670000001565312665545562012305 00000000000000/* * lftp - file transfer program * * Copyright (c) 2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "HttpAuth.h" #include "md5.h" xarray_p HttpAuth::cache; HttpAuth::Challenge::Challenge(const char *p_chal) : scheme_code(HttpAuth::NONE) { const char *end=p_chal+strlen(p_chal); // challenge = auth-scheme 1*SP 1#auth-param const char *space=strchr(p_chal,' '); if(!space || space==p_chal) return; scheme.nset(p_chal,space-p_chal).c_ucfirst(); // auth-param = token "=" ( token | quoted-string ) const char *auth_param=space+1; while(auth_param chal(p_chal); Ref auth; switch(chal->GetSchemeCode()) { case BASIC: auth=new HttpAuthBasic(t,p_uri,chal.borrow(),p_user,p_pass); break; case DIGEST: auth=new HttpAuthDigest(t,p_uri,chal.borrow(),p_user,p_pass); break; case NONE: return false; } if(!auth->IsValid()) return false; CleanCache(t,p_uri,p_user); cache.append(auth.borrow()); return true; } bool HttpAuth::Matches(target_t t,const char *p_uri,const char *p_user) { if(this->target!=t) return false; if(this->user.ne(p_user)) return false; if(!uri.prefixes(p_uri)) return false; return true; } void HttpAuth::CleanCache(target_t t,const char *p_uri,const char *p_user) { for(int i=cache.length()-1; i>=0; i--) { if(cache[i]->Matches(t,p_uri,p_user)) cache.remove(i); } } HttpAuth *HttpAuth::Get(target_t t,const char *p_uri,const char *p_user) { for(int i=cache.length()-1; i>=0; i--) { if(cache[i]->Matches(t,p_uri,p_user)) return cache[i]; } return 0; } xstring& HttpAuth::append_quoted(xstring& s,const char *n,const char *v) { if(!v) return s; if(s.length()>0 && s.last_char()!=' ') s.append(','); s.append(n).append('='); return HttpHeader::append_quoted_value(s,v); } void HttpAuthBasic::MakeHeader() { xstring& auth=xstring::get_tmp(user).append(':').append(pass); char *buf64=string_alloca(base64_length(auth.length())+1); base64_encode(auth,buf64,auth.length()); header.SetValue(auth.set("Basic ").append(buf64)); } void HttpAuthDigest::MakeHA1() { const xstring& realm=chal->GetParam("realm"); const xstring& nonce=chal->GetParam("nonce"); if(!realm || !nonce) return; // required // generate random client nonce cnonce.truncate(); for(int i=0; i<8; i++) cnonce.appendf("%02x",unsigned(random()/13%256)); struct md5_ctx ctx; md5_init_ctx (&ctx); md5_process_bytes (user, user.length(), &ctx); md5_process_bytes (":", 1, &ctx); md5_process_bytes (realm, realm.length(), &ctx); md5_process_bytes (":", 1, &ctx); md5_process_bytes (pass, pass.length(), &ctx); xstring buf; buf.get_space(MD5_DIGEST_SIZE); md5_finish_ctx (&ctx, buf.get_non_const()); buf.set_length(MD5_DIGEST_SIZE); if(chal->GetParam("algorithm").eq("MD5-sess")) { md5_init_ctx (&ctx); md5_process_bytes (buf, buf.length(), &ctx); md5_process_bytes (":", 1, &ctx); md5_process_bytes (nonce, nonce.length(), &ctx); md5_process_bytes (":", 1, &ctx); md5_process_bytes (cnonce, cnonce.length(), &ctx); md5_finish_ctx (&ctx, buf.get_non_const()); } // lower-case hex encoding HA1.truncate(); buf.hexdump_to(HA1); HA1.c_lc(); } bool HttpAuthDigest::Update(const char *p_method,const char *p_uri,const char *entity_hash) { const xstring& qop_options=chal->GetParam("qop"); xstring qop; if(qop_options) { // choose qop char *qop_options_split=alloca_strdup(qop_options); for(char *qop1=strtok(qop_options_split,","); qop1; qop1=strtok(NULL,",")) { if(!strcmp(qop1,"auth-int") && entity_hash) { qop.set(qop1); break; } if(!strcmp(qop1,"auth")) { qop.set(qop1); if(!entity_hash) break; } } } if(qop_options && !qop) return false; // no suitable qop found // calculate H(A2) struct md5_ctx ctx; md5_init_ctx (&ctx); md5_process_bytes (p_method, strlen(p_method), &ctx); md5_process_bytes (":", 1, &ctx); md5_process_bytes (p_uri, strlen(p_uri), &ctx); if(qop.eq("auth-int")) { md5_process_bytes (":", 1, &ctx); md5_process_bytes (entity_hash, strlen(entity_hash), &ctx); }; xstring buf; buf.get_space(MD5_DIGEST_SIZE); md5_finish_ctx (&ctx, buf.get_non_const()); buf.set_length(MD5_DIGEST_SIZE); xstring HA2; buf.hexdump_to(HA2); HA2.c_lc(); // calculate response md5_init_ctx (&ctx); md5_process_bytes (HA1, HA1.length(), &ctx); md5_process_bytes (":", 1, &ctx); const xstring& nonce=chal->GetParam("nonce"); md5_process_bytes (nonce, nonce.length(), &ctx); md5_process_bytes (":", 1, &ctx); char nc_buf[9]; if(qop) { sprintf(nc_buf,"%08x",++nc); md5_process_bytes (nc_buf, strlen(nc_buf), &ctx); md5_process_bytes (":", 1, &ctx); md5_process_bytes (cnonce, cnonce.length(), &ctx); md5_process_bytes (":", 1, &ctx); md5_process_bytes (qop, qop.length(), &ctx); md5_process_bytes (":", 1, &ctx); } md5_process_bytes (HA2, HA2.length(), &ctx); md5_finish_ctx (&ctx, buf.get_non_const()); xstring digest; buf.hexdump_to(digest); digest.c_lc(); xstring auth("Digest "); append_quoted(auth,"username",user); append_quoted(auth,"realm",chal->GetParam("realm")); append_quoted(auth,"nonce",nonce); append_quoted(auth,"uri",p_uri); append_quoted(auth,"response",digest); append_quoted(auth,"algorithm",chal->GetParam("algorithm")); append_quoted(auth,"opaque",chal->GetParam("opaque")); if(qop) { auth.append(",qop=").append(qop); append_quoted(auth,"cnonce",cnonce); auth.append(",nc=").append(nc_buf); } header.SetValue(auth); return true; } lftp-4.9.2/src/PollVec.cc0000644000015000007670000000413313160735602012062 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "trio.h" #include "PollVec.h" static inline bool operator<(const timeval& a,const timeval& b) { if(a.tv_sec!=b.tv_sec) return a.tv_sec(t/1000000),static_cast(t%1000000)}; if(tv_timeout.tv_sec<0 || new_timeout. */ #include #include #include #include #include "trio.h" #include "CharReader.h" int CharReader::Do() { int m=STALL; if(ch!=NOCHAR) return m; if(!Ready(fd,POLLIN)) { Block(fd,POLLIN); return m; } int oldfl=fcntl(fd,F_GETFL); if(!(oldfl&O_NONBLOCK)) fcntl(fd,F_SETFL,oldfl|O_NONBLOCK); unsigned char c; int res=read(fd,&c,1); if(res==-1 && errno==EAGAIN) Block(fd,POLLIN); else if(res==-1 && errno==EINTR) m=MOVED; else if(res>0) { ch=c; m=MOVED; } else // eof or error. { ch=EOFCHAR; m=MOVED; } if(!(oldfl&O_NONBLOCK)) fcntl(fd,F_SETFL,oldfl); if(res==-1 && ch==EOFCHAR) fprintf(stderr,"read(%d): %s\n",fd,strerror(errno)); return m; } lftp-4.9.2/src/FileCopy.cc0000644000015000007670000012751313666263672012256 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2020 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* FileCopyPeer behaviour: 1) when suspended, does nothing 2) tries to read some data at seek_pos, sets pos to position of Get (get). 2.5) tries to position to seek_pos and gets ready to write (put). 3) if it cannot seek to seek_pos, changes pos to what it can seek. 4) if it knows that it cannot seek to pos>0, CanSeek()==false 5) if it knows that it cannot seek to pos==0, CanSeek0()==false 6) it tries to get date/size if told to. (get) 7) it sets date on the file if eof is reached and date is known (put). 8) if put needs size/date before it writes data, NeedSizeDateBeforehand()==true. */ #include #include #include #include #include #include #include #include #include #include "FileCopy.h" #include "url.h" #include "log.h" #include "misc.h" #include "LsCache.h" #include "plural.h" #include "ArgV.h" #define skip_threshold 0x1000 ResDecl rate_period ("xfer:rate-period","15", ResMgr::UNumberValidate,ResMgr::NoClosure); ResDecl eta_period ("xfer:eta-period", "120",ResMgr::UNumberValidate,ResMgr::NoClosure); ResDecl max_redir ("xfer:max-redirections", "5",ResMgr::UNumberValidate,ResMgr::NoClosure); ResDecl buffer_size ("xfer:buffer-size","0x10000",ResMgr::UNumberValidate,ResMgr::NoClosure); // It's bad when lftp receives data in small chunks, try to accumulate // data in a kernel buffer using a delay and slurp it at once: enum { // Delays in microseconds MAX_DELAY=30000, DELAY_STEP=30, // This size is related to socket buffer size. // When it is too large, tcp slowdown happens. // SSL has packet size 0x4000, so we have to use a lower threshold. MAX_READ_TO_DELAY=0x3F00, }; // FileCopy #define super SMTask #define set_state(s) do { state=(s); \ Log::global->Format(11,"FileCopy(%p) enters state %s\n", this, #s); } while(0) int FileCopy::Do() { int m=STALL; const char *b; int s; int rate_add; if(Error() || Done()) return m; switch(state) { pre_INITIAL: set_state(INITIAL); m=MOVED; case(INITIAL): if(remove_target_first && !put->FileRemoved()) return m; remove_target_first=false; if(cont && put->CanSeek()) put->WantSize(); if(put->NeedSizeDateBeforehand() || (cont && put->CanSeek() && put->GetSize()==NO_SIZE_YET)) { if(get->GetSize()==NO_SIZE_YET || get->GetDate()==NO_DATE_YET) { put->Suspend(); get->DontStartTransferYet(); get->Resume(); get->WantSize(); if(put->NeedDate()) get->WantDate(); goto pre_GET_INFO_WAIT; } } if(get->GetSize()==NO_SIZE_YET) get->WantSize(); if(get->GetSize()!=NO_SIZE && get->GetSize()!=NO_SIZE_YET) put->SetEntitySize(get->GetSize()); if(get->GetDate()!=NO_DATE && get->GetDate()!=NO_DATE_YET) put->SetDate(get->GetDate()); else if(get->GetDate()==NO_DATE_YET) { if(put->NeedDate()) get->WantDate(); } if(cont && put->CanSeek()) put->Seek(FILE_END); else { if(put->range_start>0 && put->CanSeek()) put->Seek(put->range_start); if(get->range_start>0 && get->CanSeek()) get->Seek(get->range_start); goto pre_DO_COPY; } get->Suspend(); put->Resume(); set_state(PUT_WAIT); m=MOVED; /* fallthrough */ case(PUT_WAIT): if(put->Error()) goto put_error; if(put->GetSeekPos()!=FILE_END && get->GetSize()>=0 && put->GetSeekPos()>=get->GetSize()) { debug((9,_("copy: destination file is already complete\n"))); if(get->GetDate()!=NO_DATE) goto pre_CONFIRM_WAIT; // have to set the date. goto pre_GET_DONE_WAIT; } if(!put->IOReady()) return m; /* now we know if put's seek failed. Seek get accordingly. */ if(get->CanSeek()) get->Seek(put->GetRealPos()); pre_DO_COPY: get->Resume(); get->StartTransfer(); RateReset(); set_state(DO_COPY); m=MOVED; /* fallthrough */ case(DO_COPY): { if(put->Error()) { put_error: SetError(put->ErrorText()); return MOVED; } if(get->Error() && get->Size()==0) { put->DontVerify(); if(put->GetPos()>0) { put->PutEOF(); put->Roll(); } get_error: SetError(get->ErrorText()); return MOVED; } if(put->Broken()) { get->Suspend(); if(!put->Done()) return m; debug((9,_("copy: put is broken\n"))); if(fail_if_broken) { SetError(strerror(EPIPE)); return MOVED; } goto pre_GET_DONE_WAIT; } put->Resume(); if(put->GetSeekPos()==FILE_END) // put position is not known yet. { get->Suspend(); return m; } get->Resume(); if(fail_if_cannot_seek && (get->GetRealPos()range_start || put->GetRealPos()range_start || get->GetRealPos()!=put->GetRealPos())) { SetError(_("seek failed")); return MOVED; } if(high_watermark_timeout.Stopped()) { SetError(_("no progress timeout")); return MOVED; } if(get->GetSize()>0 && get->GetRealPos()>get->GetSize()) { get->SetSize(NO_SIZE_YET); get->SetDate(NO_DATE_YET); } long lbsize=0; if(line_buffer) lbsize=line_buffer->Size(); /* check if positions are correct */ off_t get_pos=get->GetRealPos()-get->range_start; off_t put_pos=put->GetRealPos()-put->range_start; if(get_pos-lbsize!=put_pos) { if(line_buffer) line_buffer->Empty(); if(get_pos==put_pos) { // rare case. return MOVED; } if(put_posCanSeek(put->GetRealPos())) { // we lose... How about a large buffer? SetError(_("cannot seek on data source")); return MOVED; } debug((9,_("copy: put rolled back to %lld, seeking get accordingly\n"), (long long)put->GetRealPos())); debug((10,"copy: get position was %lld\n", (long long)get->GetRealPos())); get->Seek(put->GetRealPos()); return MOVED; } else // put_pos > get_pos { off_t size=get->GetSize(); if(size>=0 && put->GetRealPos()>=size) { // simulate eof, as we have already have the whole file. debug((9,_("copy: all data received, but get rolled back\n"))); goto eof; } off_t skip=put->GetRealPos()-get->GetRealPos(); if(!put->CanSeek(get->GetRealPos()) || skipGet(&b,&s); if(skip>s) skip=s; if(skip==0) return m; get->Skip(skip); bytes_count+=skip; return MOVED; } debug((9,_("copy: get rolled back to %lld, seeking put accordingly\n"), (long long)get->GetRealPos())); put->Seek(get->GetRealPos()); return MOVED; } } if(put->IsFull()) get->Suspend(); // stall the get. get->Get(&b,&s); if(b==0) // eof { debug((10,"copy: get hit eof\n")); goto eof; } rate_add=put_buf; if(s==0) { put_buf=put->Buffered(); rate_add-=put_buf; RateAdd(rate_add); if(put->Size()==0) put->Suspend(); return m; } m=MOVED; if(get->range_limit!=FILE_END && get->range_limitGetRealPos()+s) { s=get->range_limit-get->GetRealPos(); if(s<0) s=0; } if(line_buffer) { const char *lb; int ls; if(line_buffer->Size()>line_buffer_max) { line_buffer->Get(&lb,&ls); put->Put(lb,ls); line_buffer->Skip(ls); } line_buffer->Put(b,s); get->Skip(s); bytes_count+=s; // now find eol in line_buffer. line_buffer->Get(&lb,&ls); const char *eol=0; if(get->Eof() || get->Error()) eol=lb+ls-1; else eol=memrchr(lb,'\n',ls); if(eol) { put->Put(lb,eol-lb+1); line_buffer->Skip(eol-lb+1); } } else { put->Put(b,s); get->Skip(s); bytes_count+=s; } put_buf=put->Buffered(); rate_add-=put_buf-s; RateAdd(rate_add); if(high_watermarkrange_limit!=FILE_END && get->range_limit<=get->GetRealPos()) { debug((10,"copy: get reached range limit\n")); goto eof; } return m; } eof: if(line_buffer) { line_buffer->Get(&b,&s); put->Put(b,s); line_buffer->Skip(s); } if(!CheckFileSizeAtEOF()) { SetError(_("file size decreased during transfer")); return MOVED; } pre_CONFIRM_WAIT: if(put->IsAutoRename()) put->SetSuggestedFileName(get->GetSuggestedFileName()); put->SetDate(get->GetDate()); if(get->GetSize()!=NO_SIZE && get->GetSize()!=NO_SIZE_YET) put->SetEntitySize(get->GetSize()); put->PutEOF(); get->Suspend(); put->Resume(); put_eof_pos=put->GetRealPos(); debug((10,"copy: waiting for put confirmation\n")); set_state(CONFIRM_WAIT); m=MOVED; case(CONFIRM_WAIT): if(put->Error()) goto put_error; /* check if put position is correct */ if(put_eof_pos!=put->GetRealPos() || put->GetSeekPos()==FILE_END) { set_state(DO_COPY); return MOVED; } rate_add=put_buf; put_buf=put->Buffered(); rate_add-=put_buf; RateAdd(rate_add); if(!put->Done()) return m; debug((10,"copy: put confirmed store\n")); pre_GET_DONE_WAIT: get->Empty(); get->PutEOF(); get->Resume(); set_state(GET_DONE_WAIT); m=MOVED; end_time=now; put->Suspend(); /* fallthrough */ case(GET_DONE_WAIT): if(get->Error()) goto get_error; if(remove_source_later) { get->RemoveFile(); remove_source_later=false; } if(!get->Done()) return m; debug((10,"copy: get is finished - all done\n")); set_state(ALL_DONE); get->Suspend(); LogTransfer(); return MOVED; pre_GET_INFO_WAIT: set_state(GET_INFO_WAIT); m=MOVED; case(GET_INFO_WAIT): if(get->Error()) goto get_error; if(get->GetSize()==NO_SIZE_YET || get->GetDate()==NO_DATE_YET) return m; goto pre_INITIAL; case(ALL_DONE): return m; } return m; } FileCopy::FileCopy(FileCopyPeer *s,FileCopyPeer *d,bool c) : get(s), put(d), cont(c), rate("xfer:rate-period"), rate_for_eta("xfer:eta-period"), high_watermark_timeout("xfer:timeout",0) { set_state(INITIAL); int max_buf=buffer_size.Query(0); if(max_buf<1) max_buf=1; s->SetMaxBuffered(max_buf); d->SetMaxBuffered(max_buf); put_buf=0; put_eof_pos=0; high_watermark=0; bytes_count=0; fail_if_cannot_seek=false; fail_if_broken=true; remove_source_later=false; remove_target_first=false; line_buffer_max=0; } FileCopy::~FileCopy() { } FileCopy *FileCopy::New(FileCopyPeer *s,FileCopyPeer *d,bool c) { FileCopy *res=0; if(fxp_create) res=fxp_create(s,d,c); if(res) return res; return new FileCopy(s,d,c); } void FileCopy::SuspendInternal() { super::SuspendInternal(); if(get) get->SuspendSlave(); if(put) put->SuspendSlave(); } void FileCopy::ResumeInternal() { if(get) get->ResumeSlave(); if(put) put->ResumeSlave(); super::ResumeInternal(); } void FileCopy::Fg() { if(get) get->Fg(); if(put) put->Fg(); } void FileCopy::Bg() { if(get) get->Bg(); if(put) put->Bg(); } void FileCopy::SetError(const char *str) { error_text.set(str); get=0; } void FileCopy::LineBuffered(int s) { if(!line_buffer) line_buffer=new Buffer(); line_buffer_max=s; } off_t FileCopy::GetPos() const { if(put) { off_t pos = put->GetRealPos() - put->Buffered(); // sometimes Buffered overestimates the amount of buffered data if(pos<0) pos=0; return pos; } if(get) return get->GetRealPos(); return 0; } off_t FileCopy::GetSize() const { if(get) return get->GetSize(); return NO_SIZE; } int FileCopy::GetPercentDone() const { if(!get || !put) return 100; off_t size=get->GetSize(); if(size==NO_SIZE || size==NO_SIZE_YET) return -1; if(size==0) return 0; off_t ppos=put->GetRealPos() - put->Buffered() - put->range_start; if(ppos<0) return 0; off_t psize=size-put->range_start; if(put->range_limit!=FILE_END) psize=put->range_limit-put->range_start; if(psize<0) return 100; if(ppos>psize) return -1; return percent(ppos,psize); } const char *FileCopy::GetPercentDoneStr() const { int pct=GetPercentDone(); if(pct==-1) return ""; static char buf[8]; snprintf(buf,8,"(%d%%) ",pct); return buf; } void FileCopy::RateAdd(int a) { rate.Add(a); rate_for_eta.Add(a); } void FileCopy::RateReset() { start_time=now; rate.Reset(); rate_for_eta.Reset(); } float FileCopy::GetRate() { if(!rate.Valid() || !put) return 0; return rate.Get(); } const char *FileCopy::GetRateStr() { if(!rate.Valid() || !put) return ""; return rate.GetStrS(); } off_t FileCopy::GetBytesRemaining() { if(!get) return 0; if(get->range_limit==FILE_END) { off_t size=get->GetSize(); if(size<=0 || sizeGetRealPos() || !rate_for_eta.Valid()) return -1; return(size-GetPos()); } return get->range_limit-GetPos(); } const char *FileCopy::GetETAStr() { off_t b=GetBytesRemaining(); if(b<0 || !put) return ""; return rate_for_eta.GetETAStrSFromSize(b); } long FileCopy::GetETA(off_t b) { if(b<0 || !rate_for_eta.Valid()) return -1; return (long)(double(b) / rate_for_eta.Get() + 0.5); } const char *FileCopy::GetStatus() { static xstring buf; const char *get_st=get?get->GetStatus():0; const char *put_st=put?put->GetStatus():0; if(get_st && get_st[0] && put_st && put_st[0]) buf.vset("[",get_st,"->",put_st,"]",NULL); else if(get_st && get_st[0]) buf.vset("[",get_st,"]",NULL); else if(put_st && put_st[0]) buf.vset("[",put_st,"]",NULL); else return ""; return buf; } double FileCopy::GetTimeSpent() { if(end_timeGetFgData(fg); if(f) return f; if(put) f=put->GetFgData(fg); return f; } pid_t FileCopy::GetProcGroup() { pid_t p=0; if(get) p=get->GetProcGroup(); if(p) return p; if(put) p=put->GetProcGroup(); return p; } void FileCopy::Kill(int sig) { if(get) get->Kill(sig); if(put) put->Kill(sig); } Ref FileCopy::transfer_log; void FileCopy::LogTransfer() { const char *log_ctx="xfer"; if(!ResMgr::QueryBool("log:enabled",log_ctx)) return; const char *src=get->GetURL(); if(!src) return; src=alloca_strdup(src); const char *dst=put->GetURL(); if(!dst) return; dst=alloca_strdup(dst); if(!transfer_log) transfer_log=new Log(log_ctx); long long range_limit=GetRangeLimit(); if(range_limit==FILE_END) range_limit=get->GetPos(); transfer_log->Format(0,"%s -> %s %lld-%lld %s\n", url::remove_password(src),url::remove_password(dst), (long long)GetRangeStart(),range_limit, Speedometer::GetStrProper(GetBytesCount()/GetTimeSpent()).get()); } void FileCopy::SetRange(off_t s,off_t lim) { get->SetRange(s,lim); put->SetRange(s,lim); } bool FileCopy::CheckFileSizeAtEOF() const { long long range_limit=GetRangeLimit(); if(range_limit==FILE_END) { const long long size=GetSize(); if(size==NO_SIZE || size==NO_SIZE_YET) return true; // nothing to compare with. range_limit=size; } const long long get_pos=get->GetRealPos(); const long long put_pos=put->GetRealPos(); const long long pos=(get_pos>put_pos ? get_pos : put_pos); if(pos<=0 || pos>=range_limit) return true; debug((0,"expected pos=%lld, actual pos=%lld\n",range_limit,pos)); return false; } // FileCopyPeer implementation #undef super #define super Buffer off_t FileCopyPeer::GetSize() { if(size>=0 && pos>size) WantSize(); return size; } void FileCopyPeer::SetSize(off_t s) { size=s; if(seek_pos==FILE_END) { if(size!=NO_SIZE && size!=NO_SIZE_YET) seek_pos=size; else seek_pos=0; } } void FileCopyPeer::SetDate(time_t d,int p) { date.set(d,p); if(d==NO_DATE || d==NO_DATE_YET) date_set=true; else date_set=false; } void FileCopyPeer::SetRange(const off_t s,const off_t lim) { range_start=s; range_limit=lim; if(mode==PUT || range_start>GetPos()+0x4000) Seek(range_start); } bool FileCopyPeer::Done() { if(Error()) return true; if(eof && Size()==0) { if(removing) return false; if(mode==PUT) return done; return true; } if(broken) return true; return false; } void FileCopyPeer::Seek(off_t offs) { seek_pos=offs; if(mode==PUT) pos-=Size(); Empty(); eof=false; broken=false; } const char *FileCopy::TempFileName(const char *file) { if(!ResMgr::QueryBool("xfer:use-temp-file",0)) return file; xstring &temp=xstring::get_tmp(ResMgr::Query("xfer:temp-file-name",0)); if(temp.length()==0 || temp.eq("*")) return file; const char *name=basename_ptr(file); int subst_pos=temp.instr('*'); if(subst_pos>=0) temp.set_substr(subst_pos,1,name); else { if(temp.last_char()=='.') temp.append(name); else if(temp[0]=='.') temp.set_substr(0,0,name); else temp.append('.').append(name); } return dir_file(dirname(file),temp); } const char *FileCopyPeer::UseTempFile(const char *file) { const char *temp=FileCopy::TempFileName(file); if(temp==file) return file; auto_rename=true; temp_file=true; SetSuggestedFileName(basename_ptr(file)); return temp; } bool FileCopyPeer::ShouldRename() const { return (auto_rename || temp_file) && suggested_filename; } FileCopyPeer::FileCopyPeer(dir_t m) : IOBuffer(m) { want_size=false; want_date=false; start_transfer=true; size=NO_SIZE_YET; date=NO_DATE_YET; e_size=NO_SIZE; seek_pos=0; can_seek=false; can_seek0=false; date_set=false; do_set_date=true; do_verify=true; ascii=false; range_start=0; range_limit=FILE_END; removing=false; file_removed=false; temp_file=false; do_mkdir=false; use_cache=true; write_allowed=true; done=false; auto_rename=false; Suspend(); // don't do anything too early } // FileCopyPeerFA implementation #undef super #define super FileCopyPeer int FileCopyPeerFA::Do() { int m=STALL; int res; if(session->OpenMode()==FA::MAKE_DIR) { // doing mkdir int res=session->Done(); if(res==FA::IN_PROGRESS) return m; if(res<0) debug((3,"mkdir failed: %s\n",session->StrError(res))); session->Close(); m=MOVED; } else if(session->OpenMode()==FA::RENAME) { int res=session->Done(); if(res==FA::IN_PROGRESS) return m; if(res<0) { if(temp_file) SetError(session->StrError(res)); else debug((3,"rename failed: %s\n",session->StrError(res))); } session->Close(); done=true; return MOVED; } if(do_mkdir) { // do mkdir just once do_mkdir=false; assert(!session->IsOpen()); const xstring& dir=dirname(file); if(dir.length()>0 && dir.ne("/") && dir.ne(".") && dir.ne("..")) { // FIXME: .././.. should be also excluded session->Mkdir(dirname(file),true); return MOVED; } } if(removing) { res=session->Done(); if(res<=0) { removing=false; file_removed=true; session->Close(); Suspend(); m=MOVED; } return m; } if(Done() || Error()) return m; if(verify) { if(verify->Error()) { SetError(verify->ErrorText()); m=MOVED; } else if(verify->Done()) { if(ShouldRename()) { const char *new_name=dir_file(dirname(file),suggested_filename); bool clobber=temp_file; session->Rename(file,new_name,clobber); return MOVED; } done=true; m=MOVED; } return m; } // if we need some info and cannot start the transfer (yet), // then use ARRAY_INFO to fetch the file information. if(((want_size && size==NO_SIZE_YET) || (want_date && date==NO_DATE_YET)) && (mode==PUT || !start_transfer) && session->IsClosed()) { FileInfo *fi=new FileInfo(file); if(want_size) fi->Need(fi->SIZE); if(want_date) fi->Need(fi->DATE); info.Empty(); info.Add(fi); session->GetInfoArray(&info); m=MOVED; } if(session->OpenMode()==FA::ARRAY_INFO) { res=session->Done(); if(res==FA::IN_PROGRESS) return m; if(res<0) { session->Close(); SetSize(NO_SIZE); SetDate(NO_DATE); return MOVED; } FileInfo *fi=info[0]; if(want_size) SetSize(fi->size); if(want_date) SetDate(fi->date); session->Close(); return MOVED; } switch(mode) { case PUT: if(fxp) { if(eof) goto fxp_eof; return m; } res=Put_LL(buffer+buffer_ptr,Size()); if(res>0) { buffer_ptr+=res; m=MOVED; } else if(res<0) return MOVED; if(Size()==0) { if(eof) { if(date!=NO_DATE && date!=NO_DATE_YET) session->SetDate(date); if(e_size!=NO_SIZE && e_size!=NO_SIZE_YET) session->SetSize(e_size); res=session->StoreStatus(); if(res==FA::OK) { session->Close(); fxp_eof: // FIXME: set date for real. date_set=true; if(!verify && do_verify) verify=new FileVerificator(session,file); else done=true; return MOVED; } else if(res==FA::IN_PROGRESS) return m; else { if(res==FA::DO_AGAIN) return m; if(res==FA::STORE_FAILED) { upload_state.Save(session); session->Close(); if(can_seek && seek_pos>0) Seek(FILE_END); else Seek(0); return MOVED; } SetError(session->StrError(res)); return MOVED; } return m; } } break; case GET: if(eof) return m; if(fxp) return m; res=TuneGetSize(Get_LL(get_size)); if(res>0) { EmbraceNewData(res); SaveMaxCheck(0); return MOVED; } if(res<0) return MOVED; if(eof) { session->Close(); return MOVED; } break; } return m; } bool FileCopyPeerFA::IOReady() { if(seek_pos==0) return true; if(seek_pos==FILE_END && size==NO_SIZE_YET) return false; return session->IOReady(); } void FileCopyPeerFA::SuspendInternal() { if(fxp && mode==PUT) return; if(session->IsOpen()) session->SuspendSlave(); super::SuspendInternal(); } void FileCopyPeerFA::ResumeInternal() { super::ResumeInternal(); session->ResumeSlave(); } const char *FileCopyPeerFA::GetStatus() { if(verify) return verify->Status(); if(!session->IsOpen()) return 0; return session->CurrentStatus(); } void FileCopyPeerFA::Seek(off_t new_pos) { if(pos==new_pos) return; super::Seek(new_pos); session->Close(); if(seek_pos==FILE_END) WantSize(); else pos=new_pos; } void FileCopyPeerFA::OpenSession() { current->Timeout(0); // mark it MOVED. if(mode==GET) { if(size!=NO_SIZE && size!=NO_SIZE_YET && !ascii && (seek_pos>size || (seek_pos==size && size>0))) { past_eof: debug((10,"copy src: seek past eof (seek_pos=%lld, size=%lld)\n", (long long)seek_pos,(long long)size)); pos=seek_pos; eof=true; return; } const char *b; int s; int err; if(use_cache && FileAccess::cache->Find(session,file,FAmode,&err,&b,&s)) { if(err) { SetError(b); return; } size=s; if(seek_pos>=s) goto past_eof; b+=seek_pos; s-=seek_pos; Save(0); Put(b,s); pos=seek_pos; eof=true; return; } } else // mode==PUT { if(e_size>=0 && size>=0 && seek_pos>=e_size) { debug((10,"copy dst: seek past eof (seek_pos=%lld, size=%lld)\n", (long long)seek_pos,(long long)e_size)); eof=true; if(date==NO_DATE || date==NO_DATE_YET) return; } } session->Open(file,FAmode,seek_pos); session->SetFileURL(orig_url); session->SetLimit(range_limit); if(mode==PUT) { upload_state.Restore(session); if(e_size!=NO_SIZE && e_size!=NO_SIZE_YET) session->SetSize(e_size); if(date!=NO_DATE && date!=NO_DATE_YET) session->SetDate(date); } else { if(size!=NO_SIZE && size!=NO_SIZE_YET) session->SetSize(size); } session->RereadManual(); if(base) session->SetFragile(); // fallback to base on error if(ascii) session->AsciiTransfer(); if(want_size && size==NO_SIZE_YET) session->WantSize(&size); if(want_date && (date==NO_DATE_YET || date.ts_prec>0)) session->WantDate(&date); if(mode==GET) SaveRollback(seek_pos); else pos=seek_pos+Size(); } void FileCopyPeerFA::WantSize() { struct stat st; if(!strcmp(session->GetProto(),"file") && stat(dir_file(session->GetCwd(),file),&st)!=-1) SetSize(S_ISREG(st.st_mode)?st.st_size:NO_SIZE); else super::WantSize(); } void FileCopyPeerFA::RemoveFile() { session->Open(file,FA::REMOVE); removing=true; } int FileCopyPeerFA::Get_LL(int len) { if(get_delay>0) { if(!get_ll_timer.Stopped()) return 0; session->ResumeSlave(); } int res=0; if(session->IsClosed()) OpenSession(); if(eof) // OpenSession can set eof=true. return 0; off_t io_at=pos; if(GetRealPos()!=io_at) // GetRealPos can alter pos. return 0; res=session->Read(this,len); if(res<0) { if(res==FA::DO_AGAIN) return 0; if(res==FA::FRAGILE_FAILED && base) { base.revert(this); return 0; } if(res==FA::FILE_MOVED) { // handle redirection. assert(!fxp); const char *loc_c=session->GetNewLocation(); int max_redirections=max_redir.Query(0); if(loc_c && loc_c[0] && max_redirections>0) { Log::global->Format(3,_("copy: received redirection to `%s'\n"),loc_c); if(++redirections>max_redirections) { SetError(_("Too many redirections")); return -1; } if(!session->IsNewLocationPermanent() && !base) base.save(this); orig_url.set(loc_c); file.set(session->GetNewLocationFile()); FAmode=session->GetNewLocationMode(); FileAccess *new_session=session->GetNewLocationFA(); session->Close(); if(new_session) { my_session=new_session; session=my_session; } if(want_size || size!=NO_SIZE) WantSize(); if(want_date || date!=NO_DATE) WantDate(); upload_state.Clear(); current->Timeout(0); // retry with new location. return 0; } } SetError(session->StrError(res)); return -1; } else if(res==0) { debug((10,"copy-peer: EOF on %s\n",session->GetFileURL(session->GetFile()).get())); eof=true; FileAccess::cache->Add(session,file,FAmode,FA::OK,this); SetSuggestedFileName(session->GetSuggestedFileName()); session->Close(); } else if(res<=MAX_READ_TO_DELAY) { if(get_delay<=MAX_DELAY-DELAY_STEP) get_delay+=DELAY_STEP; get_ll_timer.SetMicroSeconds(get_delay); session->SuspendSlave(); } else if(res>MAX_READ_TO_DELAY && get_delay>=DELAY_STEP) get_delay-=DELAY_STEP; return res; } int FileCopyPeerFA::Put_LL(const char *buf,int len) { if(do_mkdir) return 0; // can't write yet if(session->IsClosed()) OpenSession(); off_t io_at=pos; // GetRealPos can alter pos, save it. if(GetRealPos()!=io_at) return 0; if(len==0 && eof) return 0; int res=session->Write(buf,len); if(res<0) { if(res==FA::DO_AGAIN) return 0; if(res==FA::STORE_FAILED) { upload_state.Save(session); session->Close(); if(can_seek && seek_pos>0) Seek(FILE_END); else Seek(0); return 0; } SetError(session->StrError(res)); return -1; } seek_pos+=res; // mainly to indicate that there was some output. return res; } int FileCopyPeerFA::PutEOF_LL() { if(mode==GET && session) session->Close(); return 0; } off_t FileCopyPeerFA::GetRealPos() { if(session->OpenMode()!=FAmode || fxp) return pos; if(mode==PUT) { if(pos-Size()!=session->GetPos()) { Empty(); can_seek=false; pos=session->GetPos(); } } else { if(eof) return pos; if(session->GetRealPos()==0 && session->GetPos()>0) { can_seek=false; session->SeekReal(); } if(pos+Size()!=session->GetPos()) SaveRollback(session->GetPos()); } return pos; } void FileCopyPeerFA::Init() { get_delay=0; fxp=false; redirections=0; can_seek=true; can_seek0=true; if(FAmode==FA::LIST || FAmode==FA::LONG_LIST) Save(FileAccess::cache->SizeLimit()); if(mode==PUT) file.set(UseTempFile(file)); } FileCopyPeerFA::FileCopyPeerFA(FileAccess *s,const char *f,int m) : FileCopyPeer(m==FA::STORE ? PUT : GET), file(f), my_session(s), session(my_session), FAmode(m) { Init(); } FileCopyPeerFA::FileCopyPeerFA(const FileAccessRef& s,const char *f,int m) : FileCopyPeer(m==FA::STORE ? PUT : GET), file(f), session(s), FAmode(m) { Init(); } FileCopyPeerFA::FileCopyPeerFA(const ParsedURL *u,int m) : FileCopyPeer(m==FA::STORE ? PUT : GET), file(u->path), orig_url(u->orig_url), my_session(FileAccess::New(u)), session(my_session), FAmode(m) { Init(); if(!file) SetError(_("file name missed in URL")); } void FileCopyPeerFA::PrepareToDie() { if(session) session->Close(); } FileCopyPeerFA::~FileCopyPeerFA() {} FileCopyPeerFA *FileCopyPeerFA::New(FileAccess *s,const char *url,int m) { ParsedURL u(url,true); if(u.proto) { SessionPool::Reuse(s); return new FileCopyPeerFA(&u,m); } return new FileCopyPeerFA(s,url,m); } FileCopyPeerFA *FileCopyPeerFA::New(const FileAccessRef& s,const char *url,int m) { ParsedURL u(url,true); if(u.proto) return new FileCopyPeerFA(&u,m); return new FileCopyPeerFA(s,url,m); } FileCopyPeer *FileCopyPeerFA::Clone() { FileCopyPeerFA *c=new FileCopyPeerFA(session->Clone(),file,FAmode); c->orig_url.set(orig_url); return c; } const char *FileCopyPeerFA::UseTempFile(const char *file) { const char *temp=FileCopyPeer::UseTempFile(file); if(temp!=file && orig_url) dirname_modify(orig_url).append('/').append_url_encoded(basename_ptr(temp),URL_PATH_UNSAFE); return temp; } // FileCopyPeerFDStream #undef super #define super FileCopyPeer FileCopyPeerFDStream::FileCopyPeerFDStream(FDStream *o,dir_t m) : FileCopyPeer(m), my_stream(o?o:new FDStream(1,"")), stream(my_stream), close_when_done(o!=0) { Init(); } FileCopyPeerFDStream::FileCopyPeerFDStream(const Ref& o,dir_t m) : FileCopyPeer(m), stream(o), close_when_done(false) { Init(); } void FileCopyPeerFDStream::Init() { seek_base=0; create_fg_data=true; need_seek=false; can_seek = can_seek0 = stream->can_seek(); if(can_seek && stream->fd!=-1) { seek_base=lseek(stream->fd,0,SEEK_CUR); if(seek_base==-1) { can_seek=false; can_seek0=false; seek_base=0; } } if(stream->usesfd(1)) write_allowed=false; if(mode==PUT) put_ll_timer=new Timer(0,200); if(mode==PUT && stream->fd==-1 && stream->can_setmtime()) stream->full_name.set(UseTempFile(stream->full_name)); } void FileCopyPeerFDStream::Seek_LL() { int fd=stream->fd; assert(fd!=-1); if(CanSeek(seek_pos)) { if(seek_pos==FILE_END) { seek_pos=lseek(fd,0,SEEK_END); if(seek_pos==-1) { can_seek=false; can_seek0=false; seek_pos=0; } else { SetSize(seek_pos); if(seek_pos>seek_base) seek_pos-=seek_base; else seek_pos=0; } pos=seek_pos; } else { if(lseek(fd,seek_pos+seek_base,SEEK_SET)==-1) { can_seek=false; can_seek0=false; seek_pos=0; } pos=seek_pos; } if(mode==PUT) pos+=Size(); } else { seek_pos=pos; } } int FileCopyPeerFDStream::getfd() { if(do_mkdir || !stream) return -1; if(stream->fd!=-1) return stream->fd; int fd=stream->getfd(); if(fd==-1) { if(stream->error()) { SetError(stream->error_text); current->Timeout(0); } else { current->TimeoutS(1); } return -1; } stream->clear_status(); pos=0; if(mode==PUT) pos+=Size(); Seek_LL(); return fd; } int FileCopyPeerFDStream::Do() { int m=STALL; if(Done() || Error()) return m; if(do_mkdir) { do_mkdir=false; create_directories(dirname(stream->full_name).get_non_const()); } if(verify) { if(verify->Error()) { SetError(verify->ErrorText()); m=MOVED; } else if(verify->Done()) { if(ShouldRename() && stream && stream->full_name) { const char *new_name=dir_file(dirname(stream->full_name),suggested_filename); struct stat st; if(temp_file || (lstat(new_name,&st)==-1 && errno==ENOENT) || ResMgr::QueryBool("xfer:clobber",0)) { debug((5,"copy: renaming `%s' to `%s'\n",stream->full_name.get(),suggested_filename.get())); int res=rename(stream->full_name,new_name); if(res==-1 && errno==EIO) { // FUSE with HadoopFS workaround unlink(new_name); res=rename(stream->full_name,new_name); } if(res==-1) { const char *err=xstring::format("rename(%s, %s): %s\n",stream->full_name.get(),new_name,strerror(errno)); if(temp_file) SetError(err); else debug((3,"%s\n",err)); } } } done=true; m=MOVED; } return m; } bool check_min_size=true; #ifndef NATIVE_CRLF if(ascii) check_min_size=false; #endif int res; switch(mode) { case PUT: if(Size()==0) { if(eof) { // make sure the stream is open - it may create an empty file. if(stream && !stream->is_closed() && getfd()==-1) return m; if(!date_set && date!=NO_DATE && do_set_date) { if(date==NO_DATE_YET) return m; stream->setmtime(date); date_set=true; m=MOVED; } if(stream && close_when_done && !stream->Done()) return m; if(!verify && do_verify) verify=new FileVerificator(stream); else done=true; return MOVED; } if(seek_pos==0) return m; } if(!write_allowed) return m; if(getfd()==-1) return m; if(check_min_size && !eof && Size()Stopped()) break; res=Put_LL(buffer+buffer_ptr,Size()); if(res>0) buffer_ptr+=res; if(res!=0) m=MOVED; break; case GET: if(eof) return m; res=TuneGetSize(Get_LL(get_size)); if(res>0) { EmbraceNewData(res); SaveMaxCheck(0); } if(res!=0 || eof) m=MOVED; break; } return m; } bool FileCopyPeerFDStream::IOReady() { return seek_pos==pos || stream->fd!=-1; } void FileCopyPeerFDStream::Seek(off_t new_pos) { if(pos==new_pos) return; #ifndef NATIVE_CRLF if(ascii && new_pos!=0) { // it is possible to read file to determine right position, // but it is costly. can_seek=false; // can_seek0 is still true. return; } #endif super::Seek(new_pos); int fd=stream->fd; if(fd==-1) { if(seek_pos!=FILE_END) { pos=seek_pos; if(mode==PUT) pos+=Size(); return; } else { off_t s=stream->get_size(); if(s!=-1) { SetSize(s); pos=seek_pos+((mode==PUT)?Size():0); return; } else { // ok, have to try getfd. fd=getfd(); } } if(fd==-1) return; } Seek_LL(); } int FileCopyPeerFDStream::Get_LL(int len) { int res=0; int fd=getfd(); if(fd==-1) return 0; if((want_date && date==NO_DATE_YET) || (want_size && size==NO_SIZE_YET)) { struct stat st; if(fstat(fd,&st)==-1) { SetDate(NO_DATE); SetSize(NO_SIZE); } else { SetDate(st.st_mtime); SetSize(S_ISREG(st.st_mode)?st.st_size:NO_SIZE); #ifndef NATIVE_CRLF if(ascii) SetSize(NO_SIZE); #endif } } if(need_seek) // this does not combine with ascii. lseek(fd,seek_base+pos,SEEK_SET); char *p=GetSpace(ascii?len*2:len); res=read(fd,p,len); if(res==-1) { if(E_RETRY(errno)) { Block(fd,POLLIN); return 0; } if(stream->NonFatalError(errno)) return 0; stream->MakeErrorText(); SetError(stream->error_text); return -1; } stream->clear_status(); #ifndef NATIVE_CRLF if(ascii) { for(int i=res; i>0; i--) { if(*p=='\n') { memmove(p+1,p,i); *p++='\r'; res++; } p++; } } #endif if(res==0) { debug((10,"copy-peer: EOF on FD %d\n",fd)); eof=true; } return res; } int FileCopyPeerFDStream::Put_LL(const char *buf,int len) { if(len==0) return 0; int fd=getfd(); if(fd==-1) return 0; int skip_cr=0; #ifndef NATIVE_CRLF if(ascii) { // find where line ends. const char *cr=buf; for(;;) { cr=(const char *)memchr(cr,'\r',len-(cr-buf)); if(!cr) break; if(cr-bufNonFatalError(errno)) { // in case of full disk, check file correctness. if(errno==ENOSPC && can_seek) { struct stat st; if(fstat(fd,&st)!=-1) { if(st.st_size=seek_base+pos-Size()-buffer_ptr-st.st_size) UnSkip(seek_base+pos-Size()-st.st_size); else { Empty(); pos=st.st_size; } } } } return 0; } stream->MakeErrorText(); SetError(stream->error_text); return -1; } stream->clear_status(); if(res==len && skip_cr) { res+=skip_cr; // performance gets worse because of writing a single char, // but leaving uncomplete line on screen allows mixing it with debug text. if(write(fd,"\n",1)==1) res+=1; } if(put_ll_timer) put_ll_timer->Reset(); return res; } FgData *FileCopyPeerFDStream::GetFgData(bool fg) { if(!my_stream || !create_fg_data) return 0; // if we don't own the stream, don't create FgData. if(stream->GetProcGroup()) return new FgData(stream->GetProcGroup(),fg); return 0; } void FileCopyPeerFDStream::WantSize() { struct stat st; int res=-1; if(stream->fd!=-1) res=fstat(stream->fd,&st); else if(stream->full_name) res=stat(stream->full_name,&st); if(res!=-1) SetSize(S_ISREG(st.st_mode)?st.st_size:NO_SIZE); else super::WantSize(); } void FileCopyPeerFDStream::RemoveFile() { stream->remove(); removing=false; // it is instant. file_removed=true; Suspend(); current->Timeout(0); } const char *FileCopyPeerFDStream::GetStatus() { if(verify) return verify->Status(); return stream->status; } void FileCopyPeerFDStream::Kill(int sig) { stream->Kill(sig); } FileCopyPeerFDStream *FileCopyPeerFDStream::NewPut(const char *file,bool cont) { int flags=O_WRONLY|O_CREAT; if(!cont) { flags|=O_TRUNC; if(!ResMgr::QueryBool("xfer:clobber",0)) flags|=O_EXCL; } return new FileCopyPeerFDStream(new FileStream(file,flags), FileCopyPeer::PUT); } FileCopyPeerFDStream *FileCopyPeerFDStream::NewGet(const char *file) { return new FileCopyPeerFDStream(new FileStream(file,O_RDONLY), FileCopyPeer::GET); } FileCopyPeer *FileCopyPeerFDStream::Clone() { NeedSeek(); FileCopyPeerFDStream *peer=new FileCopyPeerFDStream(stream,mode); peer->NeedSeek(); peer->SetBase(0); return peer; } // FileCopyPeerDirList FileCopyPeerDirList::FileCopyPeerDirList(FA *s,ArgV *v) : FileCopyPeer(GET), session(s) { dl=session->MakeDirList(v); if(dl==0) eof=true; can_seek=false; can_seek0=false; } int FileCopyPeerDirList::Do() { if(Done()) return STALL; if(dl->Error()) { SetError(dl->ErrorText()); return MOVED; } const char *b; int s; dl->Get(&b,&s); if(b==0) // eof { eof=true; return MOVED; } if(s==0) return STALL; memcpy(GetSpace(s),b,s); SpaceAdd(s); dl->Skip(s); return MOVED; } // FileCopyPeerMemory int FileCopyPeerMemory::Do() { int m=STALL; if(mode==PUT) { max_buf=max_size+1; if(Size()>max_size) { SetError("buffer limit exceeded"); broken=true; return MOVED; } } return m; } // FileVerificator void FileVerificator::Init0() { done=false; if(!ResMgr::QueryBool("xfer:verify",0) || ResMgr::Query("xfer:verify-command",0).is_empty()) done=true; } void FileVerificator::InitVerify(const char *f) { if(done) return; ArgV *args=new ArgV(ResMgr::Query("xfer:verify-command",0)); args->Append(f); Log::global->Format(9,"running %s %s\n",args->a0(),f); verify_process=new InputFilter(args); verify_process->StderrToStdout(); verify_buffer=new IOBufferFDStream(verify_process.Cast(),IOBuffer::GET); } FileVerificator::FileVerificator(const char *f) { Init0(); InitVerify(f); } FileVerificator::FileVerificator(const FDStream *stream) { Init0(); if(done) return; const char *f=stream->full_name; if(!f) { done=true; return; } const char *cwd=stream->GetCwd(); int cwd_len=xstrlen(cwd); if(cwd && cwd_len>0 && !strncmp(f,cwd,cwd_len)) { f+=cwd_len; while(*f=='/') f++; if(*f==0) f="."; } InitVerify(f); if(verify_process) { verify_process->SetProcGroup(stream->GetProcGroup()); verify_process->SetCwd(cwd); } } FileVerificator::FileVerificator(const FileAccess *session,const char *f) { Init0(); if(done) return; if(strcmp(session->GetProto(),"file")) { done=true; return; } InitVerify(f); verify_process->SetCwd(session->GetCwd()); } FileVerificator::~FileVerificator() {} int FileVerificator::Do() { int m=STALL; if(done) return m; verify_process->Kill(SIGCONT); if(!verify_buffer->Eof()) return m; if(verify_process->GetProcState()!=ProcWait::TERMINATED) return m; done=true; m=MOVED; if(verify_process->GetProcExitCode()!=0) { error_text.set(verify_buffer->Get()); error_text.rtrim('\n'); if(error_text.length()==0) error_text.set(_("Verify command failed without a message")); const char *nl=strrchr(error_text,'\n'); if(nl) error_text.set(nl+1); } return m; } // special pointer to creator of ftp/ftp copier. It is init'ed in Ftp class. FileCopy *(*FileCopy::fxp_create)(FileCopyPeer *src,FileCopyPeer *dst,bool cont); lftp-4.9.2/src/SysCmdJob.cc0000644000015000007670000000434112122060724012345 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "SysCmdJob.h" #include "SignalHook.h" #include "misc.h" #define super Job SysCmdJob::SysCmdJob(const char *c) : cmd(c) { } void SysCmdJob::PrepareToDie() { Bg(); AcceptSig(SIGTERM); if(w) w.borrow()->Auto(); super::PrepareToDie(); } SysCmdJob::~SysCmdJob() {} int SysCmdJob::Do() { int m=STALL; if(w) return m; const char *shell=getenv("SHELL"); if(!shell) shell="/bin/sh"; ProcWait::Signal(false); pid_t pid; fflush(stderr); switch(pid=fork()) { case(0): /* child */ setpgid(0,0); kill(getpid(),SIGSTOP); SignalHook::RestoreAll(); if(cmd) execlp(shell,basename_ptr(shell),"-c",cmd.get(),NULL); else execlp(shell,basename_ptr(shell),NULL); fprintf(stderr,_("execlp(%s) failed: %s\n"),shell,strerror(errno)); fflush(stderr); _exit(1); case(-1): /* error */ TimeoutS(1); // wait a second and retry goto out; } /* parent */ int info; waitpid(pid,&info,WUNTRACED); // wait until the process stops w=new ProcWait(pid); fg_data=new FgData(pid,fg); m=MOVED; out: ProcWait::Signal(true); return m; } int SysCmdJob::AcceptSig(int sig) { if(!w) { if(sig==SIGINT) return WANTDIE; return STALL; } w->Kill(sig); if(sig!=SIGCONT) AcceptSig(SIGCONT); // for the case of stopped process return MOVED; } lftp-4.9.2/src/StatusLine.cc0000644000015000007670000001453113143027106012606 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #ifdef HAVE_TERMIOS_H #include #endif #include #include #include "trio.h" #include #include #include #include "xstring.h" #include "ResMgr.h" #include "misc.h" #include "StatusLine.h" #include "lftp_tinfo.h" ResDecl res_status_interval ("cmd:status-interval", "0.8s", ResMgr::TimeIntervalValidate,ResMgr::NoClosure); int StatusLine::GetWidth() { #ifdef TIOCGWINSZ struct winsize sz; sz.ws_col=sz.ws_row=0; ioctl(fd,TIOCGWINSZ,&sz); if(sz.ws_col==0) sz.ws_col=80; if(sz.ws_row==0) sz.ws_row=24; LastHeight=sz.ws_row; return(LastWidth=sz.ws_col); #else /* !TIOCGWINSZ */ return 80; #endif } StatusLine::StatusLine(int new_fd) { to_status_line = get_string_term_cap("tsl", "ts"); from_status_line = get_string_term_cap("fsl", "fs"); prev_line = get_string_term_cap("cuu1","up"); fd=new_fd; update_delayed=false; next_update_title_only=false; strcpy(def_title,""); not_term=!isatty(fd); GetWidth(); } StatusLine::~StatusLine() { /* Don't leave a title behind. */ WriteTitle("", fd); } void StatusLine::Clear(bool title_also) { const char *empty=""; update_timer.Stop(); ShowN(&empty,1); update_delayed=false; update_timer.SetMilliSeconds(20); if(title_also) WriteTitle(def_title, fd); } void StatusLine::DefaultTitle(const char *s) { strncpy(def_title, s, sizeof(def_title)); def_title[sizeof(def_title)-1] = 0; } void StatusLine::Show(const char *f,...) { if(f==0 || f[0]==0) { Clear(); return; } char newstr[0x800]; va_list v; va_start(v,f); vsnprintf(newstr,sizeof(newstr),f,v); va_end(v); newstr[sizeof(newstr)-1]=0; const char *s=newstr; ShowN(&s,1); } void StatusLine::ShowN(const char *const* newstr,int n) { if(!update_delayed && shown.IsEqual(newstr,n)) return; if(update_delayed && to_be_shown.IsEqual(newstr,n)) return; if(!update_timer.Stopped()) { /* not yet */ to_be_shown.Assign(newstr,n); update_delayed=true; } else { update(newstr,n); update_delayed=false; } } const char *StatusLine::to_status_line; const char *StatusLine::from_status_line; const char *StatusLine::prev_line; void StatusLine::WriteTitle(const char *s, int fd) const { if(!ResMgr::QueryBool("cmd:set-term-status", getenv("TERM"))) return; subst_t subst[] = { { 'a', "\007" }, { 'e', "\033" }, { 'n', "\n" }, { 's', "lftp" }, { 'v', VERSION }, { 'T', s }, { 0, "" } }; const char *status_format = ResMgr::Query("cmd:term-status", getenv("TERM")); xstring &disp=xstring::get_tmp(); if(status_format && *status_format) SubstTo(disp, status_format, subst); else if(to_status_line && from_status_line) /* If we have no format, and we have both tsl and fsl, use them: */ disp.vset(to_status_line, s, from_status_line, NULL); else return; write(fd, disp, disp.length()); } void StatusLine::update(const char *const *newstr,int newstr_height) { if(not_term) return; if(!in_foreground_pgrp()) return; /* Don't write blank titles into the title; let Clear() do that. */ if(newstr_height>0 && newstr[0][0]) WriteTitle(newstr[0], fd); if(next_update_title_only) { next_update_title_only=false; return; } int w=GetWidth(); int mbflags=0; if(newstr_height>LastHeight) newstr_height=LastHeight; // clear old extra lines. Assume we are at beginning of last shown line. int j=shown.Count(); if(!prev_line) // if there is no way to go up, show a single line only. j=newstr_height=1; int i=j-newstr_height; char *spaces=string_alloca(w+1); memset(spaces,' ',w); spaces[w]=0; while(i-->0) { int tw=mbswidth(shown[--j],mbflags); write(fd,"\r",1); write(fd,spaces,tw); write(fd,"\r",1); write(fd,prev_line,strlen(prev_line)); } // move to top of shown lines. while(--j>0) write(fd,prev_line,strlen(prev_line)); int curr_line=0; while(curr_line0) { int ch_len=mblen(end,len); if(ch_len<1) ch_len=1; int ch_width=mbsnwidth(end,ch_len,mbflags); if(wpos+ch_width>w-1) break; end+=ch_len; len-=ch_len; wpos+=ch_width; if(wpos>=w-1) break; } // FIXME: this assumes that multibyte chars cannot include ' '. while(end>newstr[curr_line] && end[-1]==' ') { end--; wpos--; // FIXME: assumption - space width is 1 } if(end-newstr[curr_line]>0) write(fd,newstr[curr_line],end-newstr[curr_line]); const char *shown_curr=(curr_line>=shown.Count()?"":shown[curr_line]); int dif=strlen(shown_curr)-(end-newstr[curr_line])+2; if(dif>(w-1)-wpos) dif=(w-1)-wpos; if(dif>0) write(fd,spaces,dif); write(fd,"\r",1); if(++curr_line. */ #include #include "RateLimit.h" #include "ResMgr.h" #include "SMTask.h" xmap_p *RateLimit::total; void RateLimit::AddXfer(int add) { xfer_number+=add; assert(xfer_number>=0); if(parent) parent->AddXfer(add); } void RateLimit::init(level_e lvl,const char *c) { level=lvl; xfer_number=(level==PER_CONN?1:0); parent=0; Reconfig(0,c); if(level==TOTAL) // has no parent return; level_e parent_level=level_e(level+1); if(parent_level==TOTAL) c=""; // no closure on top level xstring parent_key(c); if(!total) total=new xmap_p(); if(total->exists(parent_key)) { parent=total->lookup(parent_key); if(parent->xfer_number==0) parent->Reconfig(0,c); // it was not used for a white, refresh config } else { parent=new RateLimit(parent_level,c); total->add(parent_key,parent); } parent->AddXfer(xfer_number); } RateLimit::~RateLimit() { if(parent && xfer_number) parent->AddXfer(-xfer_number); } #define LARGE 0x10000000 #define DEFAULT_MAX_COEFF 2 void RateLimit::BytesPool::AdjustTime() { double dif=TimeDiff(SMTask::now,t); if(dif>0) { // prevent overflow if((LARGE-pool)/dif < rate) pool = pool_max; else pool += int(dif*rate+0.5); if(pool>pool_max) pool=pool_max; t=SMTask::now; } } int RateLimit::BytesAllowed(dir_t dir) { int parent_allowed = parent?parent->BytesAllowed(dir):LARGE; if(pool[dir].rate==0) // unlimited return parent_allowed; pool[dir].AdjustTime(); int allowed = pool[dir].pool/xfer_number; if(allowed>parent_allowed) allowed=parent_allowed; return allowed; } bool RateLimit::Relaxed(dir_t dir) { bool parent_relaxed = parent?parent->Relaxed(dir):true; if(pool[dir].rate==0) // unlimited return parent_relaxed; pool[dir].AdjustTime(); if(pool[dir].rate>0 && pool[dir].pool < pool[dir].pool_max/2) return false; return parent_relaxed; } void RateLimit::BytesPool::Used(int bytes) { if(poolBytesUsed(bytes,dir); pool[dir].Used(bytes); } void RateLimit::Reset() { pool[GET].Reset(); pool[PUT].Reset(); } void RateLimit::BytesPool::Reset() { pool=rate; t=SMTask::now; } void RateLimit::Reconfig(const char *name,const char *c) { if(name && strncmp(name,"net:limit-",10)) return; // not relevant bool config_total=(!name || !strncmp(name,"net:limit-total-",16)); const char *setting_rate="net:limit-rate"; const char *setting_max="net:limit-max"; if(level>PER_CONN) { if(!config_total) return; // not relevant if(level==TOTAL) c=0; // aggregates everything setting_rate="net:limit-total-rate"; setting_max="net:limit-total-max"; } ResMgr::Query(setting_rate,c).ToNumberPair(pool[GET].rate,pool[PUT].rate); ResMgr::Query(setting_max,c).ToNumberPair(pool[GET].pool_max,pool[PUT].pool_max); if(pool[GET].pool_max==0) pool[GET].pool_max=pool[GET].rate*DEFAULT_MAX_COEFF; if(pool[PUT].pool_max==0) pool[PUT].pool_max=pool[PUT].rate*DEFAULT_MAX_COEFF; Reset(); if(config_total && parent) parent->Reconfig(name,c); } int RateLimit::LimitBufferSize(int size,dir_t d) const { if(pool[d].rate!=0 && size>pool[d].pool_max) size=pool[d].pool_max; return size; } void RateLimit::SetBufferSize(IOBuffer *buf,int size) const { dir_t d = (buf->GetDirection()==buf->GET ? GET : PUT); buf->SetMaxBuffered(LimitBufferSize(size,d)); } void RateLimit::ClassCleanup() { if(!total) return; for(RateLimit *t=total->each_begin(); t; t=total->each_next()) t->parent=0; delete total; total=0; } lftp-4.9.2/src/Makefile.in0000644000015000007670000036267113715315417012276 00000000000000# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = lftp$(EXEEXT) subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/00gnulib.m4 \ $(top_srcdir)/m4/__inline.m4 \ $(top_srcdir)/m4/absolute-header.m4 $(top_srcdir)/m4/af_alg.m4 \ $(top_srcdir)/m4/alloca.m4 $(top_srcdir)/m4/arpa_inet_h.m4 \ $(top_srcdir)/m4/ax_check_zlib.m4 \ $(top_srcdir)/m4/ax_lib_expat.m4 $(top_srcdir)/m4/bison.m4 \ $(top_srcdir)/m4/btowc.m4 $(top_srcdir)/m4/builtin-expect.m4 \ $(top_srcdir)/m4/byteswap.m4 $(top_srcdir)/m4/chown.m4 \ $(top_srcdir)/m4/clock_time.m4 $(top_srcdir)/m4/close.m4 \ $(top_srcdir)/m4/closedir.m4 $(top_srcdir)/m4/codeset.m4 \ $(top_srcdir)/m4/configmake.m4 $(top_srcdir)/m4/ctype.m4 \ $(top_srcdir)/m4/cxx-dynamic-initializers.m4 \ $(top_srcdir)/m4/d-type.m4 $(top_srcdir)/m4/dirent_h.m4 \ $(top_srcdir)/m4/dirfd.m4 \ $(top_srcdir)/m4/double-slash-root.m4 $(top_srcdir)/m4/dup2.m4 \ $(top_srcdir)/m4/eealloc.m4 $(top_srcdir)/m4/environ.m4 \ $(top_srcdir)/m4/errno_h.m4 $(top_srcdir)/m4/error.m4 \ $(top_srcdir)/m4/exponentd.m4 $(top_srcdir)/m4/exponentf.m4 \ $(top_srcdir)/m4/exponentl.m4 $(top_srcdir)/m4/extensions.m4 \ $(top_srcdir)/m4/extern-inline.m4 $(top_srcdir)/m4/fcntl-o.m4 \ $(top_srcdir)/m4/fcntl.m4 $(top_srcdir)/m4/fcntl_h.m4 \ $(top_srcdir)/m4/fflush.m4 $(top_srcdir)/m4/filemode.m4 \ $(top_srcdir)/m4/flexmember.m4 $(top_srcdir)/m4/float_h.m4 \ $(top_srcdir)/m4/fnmatch.m4 $(top_srcdir)/m4/fnmatch_h.m4 \ $(top_srcdir)/m4/fpieee.m4 $(top_srcdir)/m4/fpurge.m4 \ $(top_srcdir)/m4/freading.m4 $(top_srcdir)/m4/frexp.m4 \ $(top_srcdir)/m4/frexpl.m4 $(top_srcdir)/m4/fseek.m4 \ $(top_srcdir)/m4/fseeko.m4 $(top_srcdir)/m4/fstat.m4 \ $(top_srcdir)/m4/ftell.m4 $(top_srcdir)/m4/ftello.m4 \ $(top_srcdir)/m4/getdtablesize.m4 $(top_srcdir)/m4/getlogin.m4 \ $(top_srcdir)/m4/getlogin_r.m4 $(top_srcdir)/m4/getopt.m4 \ $(top_srcdir)/m4/getprogname.m4 $(top_srcdir)/m4/gettext.m4 \ $(top_srcdir)/m4/gettime.m4 $(top_srcdir)/m4/gettimeofday.m4 \ $(top_srcdir)/m4/gl-openssl.m4 $(top_srcdir)/m4/glibc21.m4 \ $(top_srcdir)/m4/glob.m4 $(top_srcdir)/m4/glob_h.m4 \ $(top_srcdir)/m4/gnulib-common.m4 \ $(top_srcdir)/m4/gnulib-comp.m4 \ $(top_srcdir)/m4/host-cpu-c-abi.m4 $(top_srcdir)/m4/human.m4 \ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/iconv_h.m4 \ $(top_srcdir)/m4/iconv_open.m4 \ $(top_srcdir)/m4/include_next.m4 $(top_srcdir)/m4/inet_pton.m4 \ $(top_srcdir)/m4/inline.m4 $(top_srcdir)/m4/intlmacosx.m4 \ $(top_srcdir)/m4/intmax_t.m4 $(top_srcdir)/m4/inttypes.m4 \ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/isblank.m4 \ $(top_srcdir)/m4/isnand.m4 $(top_srcdir)/m4/isnanf.m4 \ $(top_srcdir)/m4/isnanl.m4 $(top_srcdir)/m4/langinfo_h.m4 \ $(top_srcdir)/m4/largefile.m4 $(top_srcdir)/m4/lchown.m4 \ $(top_srcdir)/m4/ldexpl.m4 $(top_srcdir)/m4/lftp.m4 \ $(top_srcdir)/m4/lftp_lib_readline.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/libunistring-base.m4 \ $(top_srcdir)/m4/limits-h.m4 $(top_srcdir)/m4/localcharset.m4 \ $(top_srcdir)/m4/locale-fr.m4 $(top_srcdir)/m4/locale-ja.m4 \ $(top_srcdir)/m4/locale-zh.m4 $(top_srcdir)/m4/locale_h.m4 \ $(top_srcdir)/m4/localeconv.m4 $(top_srcdir)/m4/lock.m4 \ $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/lseek.m4 \ $(top_srcdir)/m4/lstat.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/malloc.m4 \ $(top_srcdir)/m4/malloca.m4 $(top_srcdir)/m4/math_h.m4 \ $(top_srcdir)/m4/mbrtowc.m4 $(top_srcdir)/m4/mbsinit.m4 \ $(top_srcdir)/m4/mbsrtowcs.m4 $(top_srcdir)/m4/mbstate_t.m4 \ $(top_srcdir)/m4/mbswidth.m4 $(top_srcdir)/m4/mbtowc.m4 \ $(top_srcdir)/m4/md5.m4 $(top_srcdir)/m4/memcasecmp.m4 \ $(top_srcdir)/m4/memchr.m4 $(top_srcdir)/m4/memmem.m4 \ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/minmax.m4 \ $(top_srcdir)/m4/mktime.m4 $(top_srcdir)/m4/mmap-anon.m4 \ $(top_srcdir)/m4/mode_t.m4 $(top_srcdir)/m4/modechange.m4 \ $(top_srcdir)/m4/msvc-inval.m4 \ $(top_srcdir)/m4/msvc-nothrow.m4 $(top_srcdir)/m4/multiarch.m4 \ $(top_srcdir)/m4/needtrio.m4 $(top_srcdir)/m4/netinet_in_h.m4 \ $(top_srcdir)/m4/nl_langinfo.m4 $(top_srcdir)/m4/nls.m4 \ $(top_srcdir)/m4/nocrash.m4 $(top_srcdir)/m4/nstrftime.m4 \ $(top_srcdir)/m4/off_t.m4 $(top_srcdir)/m4/open-cloexec.m4 \ $(top_srcdir)/m4/open-slash.m4 $(top_srcdir)/m4/open.m4 \ $(top_srcdir)/m4/opendir.m4 $(top_srcdir)/m4/parse-datetime.m4 \ $(top_srcdir)/m4/passfd.m4 $(top_srcdir)/m4/pathmax.m4 \ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/poll.m4 \ $(top_srcdir)/m4/poll_h.m4 $(top_srcdir)/m4/printf-frexp.m4 \ $(top_srcdir)/m4/printf-frexpl.m4 $(top_srcdir)/m4/printf.m4 \ $(top_srcdir)/m4/progtest.m4 \ $(top_srcdir)/m4/pthread_rwlock_rdlock.m4 \ $(top_srcdir)/m4/pty.m4 $(top_srcdir)/m4/quote.m4 \ $(top_srcdir)/m4/quotearg.m4 $(top_srcdir)/m4/readdir.m4 \ $(top_srcdir)/m4/readlink.m4 $(top_srcdir)/m4/regex.m4 \ $(top_srcdir)/m4/select.m4 $(top_srcdir)/m4/setenv.m4 \ $(top_srcdir)/m4/setlocale_null.m4 $(top_srcdir)/m4/sha1.m4 \ $(top_srcdir)/m4/signal_h.m4 $(top_srcdir)/m4/signbit.m4 \ $(top_srcdir)/m4/size_max.m4 $(top_srcdir)/m4/socketlib.m4 \ $(top_srcdir)/m4/sockets.m4 $(top_srcdir)/m4/socklen.m4 \ $(top_srcdir)/m4/sockpfaf.m4 $(top_srcdir)/m4/ssize_t.m4 \ $(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_dm_mode.m4 \ $(top_srcdir)/m4/stat-time.m4 $(top_srcdir)/m4/stat.m4 \ $(top_srcdir)/m4/std-gnu11.m4 $(top_srcdir)/m4/stdalign.m4 \ $(top_srcdir)/m4/stdbool.m4 $(top_srcdir)/m4/stddef_h.m4 \ $(top_srcdir)/m4/stdint.m4 $(top_srcdir)/m4/stdint_h.m4 \ $(top_srcdir)/m4/stdio_h.m4 $(top_srcdir)/m4/stdlib_h.m4 \ $(top_srcdir)/m4/strcase.m4 $(top_srcdir)/m4/strdup.m4 \ $(top_srcdir)/m4/strerror.m4 $(top_srcdir)/m4/string_h.m4 \ $(top_srcdir)/m4/strings_h.m4 $(top_srcdir)/m4/strnlen.m4 \ $(top_srcdir)/m4/strptime.m4 $(top_srcdir)/m4/strstr.m4 \ $(top_srcdir)/m4/strtok_r.m4 $(top_srcdir)/m4/strtoull.m4 \ $(top_srcdir)/m4/strtoumax.m4 $(top_srcdir)/m4/sys_select_h.m4 \ $(top_srcdir)/m4/sys_socket_h.m4 \ $(top_srcdir)/m4/sys_stat_h.m4 $(top_srcdir)/m4/sys_time_h.m4 \ $(top_srcdir)/m4/sys_types_h.m4 $(top_srcdir)/m4/sys_uio_h.m4 \ $(top_srcdir)/m4/terminfo.m4 $(top_srcdir)/m4/threadlib.m4 \ $(top_srcdir)/m4/time_h.m4 $(top_srcdir)/m4/time_r.m4 \ $(top_srcdir)/m4/time_rz.m4 $(top_srcdir)/m4/timegm.m4 \ $(top_srcdir)/m4/timespec.m4 $(top_srcdir)/m4/tm_gmtoff.m4 \ $(top_srcdir)/m4/tzset.m4 $(top_srcdir)/m4/unistd_h.m4 \ $(top_srcdir)/m4/va_copy.m4 $(top_srcdir)/m4/vasnprintf.m4 \ $(top_srcdir)/m4/visibility.m4 \ $(top_srcdir)/m4/vsnprintf-posix.m4 \ $(top_srcdir)/m4/vsnprintf.m4 $(top_srcdir)/m4/wchar_h.m4 \ $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wcrtomb.m4 \ $(top_srcdir)/m4/wctype_h.m4 $(top_srcdir)/m4/wcwidth.m4 \ $(top_srcdir)/m4/wint_t.m4 $(top_srcdir)/m4/wmemchr.m4 \ $(top_srcdir)/m4/wmempcpy.m4 $(top_srcdir)/m4/xalloc.m4 \ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/xstrtol.m4 \ $(top_srcdir)/m4/zzgnulib.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/lib/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgverlibdir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \ "$(DESTDIR)$(pkgdatadir)" LTLIBRARIES = $(lib_LTLIBRARIES) $(pkgverlib_LTLIBRARIES) cmd_mirror_la_LIBADD = am_cmd_mirror_la_OBJECTS = MirrorJob.lo cmd_mirror_la_OBJECTS = $(am_cmd_mirror_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = cmd_mirror_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(cmd_mirror_la_LDFLAGS) $(LDFLAGS) \ -o $@ @WITH_MODULES_TRUE@am_cmd_mirror_la_rpath = -rpath $(pkgverlibdir) cmd_sleep_la_LIBADD = am_cmd_sleep_la_OBJECTS = SleepJob.lo cmd_sleep_la_OBJECTS = $(am_cmd_sleep_la_OBJECTS) cmd_sleep_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(cmd_sleep_la_LDFLAGS) $(LDFLAGS) -o $@ @WITH_MODULES_TRUE@am_cmd_sleep_la_rpath = -rpath $(pkgverlibdir) cmd_torrent_la_DEPENDENCIES = liblftp-network.la am_cmd_torrent_la_OBJECTS = Torrent.lo TorrentTracker.lo DHT.lo \ Bencode.lo cmd_torrent_la_OBJECTS = $(am_cmd_torrent_la_OBJECTS) cmd_torrent_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(cmd_torrent_la_LDFLAGS) \ $(LDFLAGS) -o $@ @WITH_MODULES_TRUE@am_cmd_torrent_la_rpath = -rpath $(pkgverlibdir) liblftp_jobs_la_DEPENDENCIES = $(JOB_MODULES_STATIC) liblftp-tasks.la am_liblftp_jobs_la_OBJECTS = Job.lo CmdExec.lo commands.lo mgetJob.lo \ SysCmdJob.lo rmJob.lo parsecmd.lo mvJob.lo mmvJob.lo alias.lo \ CatJob.lo EditJob.lo GetJob.lo ColumnOutput.lo \ FileSetOutput.lo mkdirJob.lo pgetJob.lo FileFeeder.lo \ QueueFeeder.lo History.lo FindJob.lo FindJobDu.lo ChmodJob.lo \ TreatFileJob.lo CopyJob.lo echoJob.lo OutputJob.lo \ FileCopyOutputJob.lo buffer_std.lo liblftp_jobs_la_OBJECTS = $(am_liblftp_jobs_la_OBJECTS) am__DEPENDENCIES_1 = liblftp_network_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(GNULIB) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_liblftp_network_la_OBJECTS = liblftp_network_la-NetAccess.lo \ liblftp_network_la-Resolver.lo liblftp_network_la-lftp_ssl.lo \ liblftp_network_la-buffer_ssl.lo \ liblftp_network_la-RateLimit.lo liblftp_network_la-network.lo \ liblftp_network_la-buffer_zlib.lo liblftp_network_la_OBJECTS = $(am_liblftp_network_la_OBJECTS) liblftp_network_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(liblftp_network_la_LDFLAGS) \ $(LDFLAGS) -o $@ @WITH_MODULES_TRUE@am_liblftp_network_la_rpath = -rpath \ @WITH_MODULES_TRUE@ $(pkgverlibdir) liblftp_pty_la_LIBADD = am_liblftp_pty_la_OBJECTS = PtyShell.lo lftp_pty.lo SSH_Access.lo liblftp_pty_la_OBJECTS = $(am_liblftp_pty_la_OBJECTS) liblftp_pty_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(liblftp_pty_la_LDFLAGS) \ $(LDFLAGS) -o $@ @WITH_MODULES_TRUE@am_liblftp_pty_la_rpath = -rpath $(pkgverlibdir) liblftp_tasks_la_DEPENDENCIES = $(TASK_MODULES_STATIC) $(TRIO) \ $(GNULIB) $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_liblftp_tasks_la_OBJECTS = PollVec.lo SMTask.lo ProcWait.lo \ GetPass.lo ConnectionSlot.lo CharReader.lo Cache.lo LsCache.lo \ FileAccess.lo ResMgr.lo ProtoLog.lo Filter.lo SignalHook.lo \ FileCopy.lo xmalloc.lo xstring.lo FileSet.lo log.lo \ StringSet.lo xarray.lo xmap.lo buffer.lo url.lo StatusLine.lo \ plural.lo misc.lo fg.lo module.lo resource.lo DummyProto.lo \ Error.lo ArgV.lo keyvalue.lo bookmark.lo Speedometer.lo \ FileGlob.lo netrc.lo lftp_tinfo.lo TimeDate.lo Timer.lo \ GetFileInfo.lo StringPool.lo DirColors.lo IdNameCache.lo \ PatternSet.lo LocalDir.lo liblftp_tasks_la_OBJECTS = $(am_liblftp_tasks_la_OBJECTS) proto_file_la_LIBADD = am_proto_file_la_OBJECTS = LocalAccess.lo proto_file_la_OBJECTS = $(am_proto_file_la_OBJECTS) proto_file_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(proto_file_la_LDFLAGS) $(LDFLAGS) \ -o $@ @WITH_MODULES_TRUE@am_proto_file_la_rpath = -rpath $(pkgverlibdir) proto_fish_la_DEPENDENCIES = liblftp-network.la liblftp-pty.la am_proto_fish_la_OBJECTS = Fish.lo proto_fish_la_OBJECTS = $(am_proto_fish_la_OBJECTS) proto_fish_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(proto_fish_la_LDFLAGS) $(LDFLAGS) \ -o $@ @WITH_MODULES_TRUE@am_proto_fish_la_rpath = -rpath $(pkgverlibdir) proto_ftp_la_DEPENDENCIES = liblftp-network.la am_proto_ftp_la_OBJECTS = ftpclass.lo FtpListInfo.lo FtpDirList.lo \ ftp-opie.lo netkey.lo FileCopyFtp.lo proto_ftp_la_OBJECTS = $(am_proto_ftp_la_OBJECTS) proto_ftp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(proto_ftp_la_LDFLAGS) $(LDFLAGS) -o $@ @WITH_MODULES_TRUE@am_proto_ftp_la_rpath = -rpath $(pkgverlibdir) proto_http_la_DEPENDENCIES = liblftp-network.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) am_proto_http_la_OBJECTS = proto_http_la-Http.lo \ proto_http_la-HttpHeader.lo proto_http_la-HttpAuth.lo \ proto_http_la-HttpDir.lo proto_http_la-HttpDirXML.lo proto_http_la_OBJECTS = $(am_proto_http_la_OBJECTS) proto_http_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(proto_http_la_LDFLAGS) $(LDFLAGS) \ -o $@ @WITH_MODULES_TRUE@am_proto_http_la_rpath = -rpath $(pkgverlibdir) proto_sftp_la_DEPENDENCIES = liblftp-network.la liblftp-pty.la am_proto_sftp_la_OBJECTS = SFtp.lo proto_sftp_la_OBJECTS = $(am_proto_sftp_la_OBJECTS) proto_sftp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(AM_CXXFLAGS) $(CXXFLAGS) $(proto_sftp_la_LDFLAGS) $(LDFLAGS) \ -o $@ @WITH_MODULES_TRUE@am_proto_sftp_la_rpath = -rpath $(pkgverlibdir) PROGRAMS = $(bin_PROGRAMS) am_lftp_OBJECTS = lftp-lftp.$(OBJEXT) lftp-complete.$(OBJEXT) \ lftp-lftp_rl.$(OBJEXT) lftp-attach.$(OBJEXT) lftp_OBJECTS = $(am_lftp_OBJECTS) lftp_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(lftp_LDFLAGS) $(LDFLAGS) -o $@ SCRIPTS = $(bin_SCRIPTS) $(noinst_SCRIPTS) $(pkgdata_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(cmd_mirror_la_SOURCES) $(cmd_sleep_la_SOURCES) \ $(cmd_torrent_la_SOURCES) $(liblftp_jobs_la_SOURCES) \ $(liblftp_network_la_SOURCES) $(liblftp_pty_la_SOURCES) \ $(liblftp_tasks_la_SOURCES) $(proto_file_la_SOURCES) \ $(proto_fish_la_SOURCES) $(proto_ftp_la_SOURCES) \ $(proto_http_la_SOURCES) $(proto_sftp_la_SOURCES) \ $(lftp_SOURCES) DIST_SOURCES = $(cmd_mirror_la_SOURCES) $(cmd_sleep_la_SOURCES) \ $(cmd_torrent_la_SOURCES) $(liblftp_jobs_la_SOURCES) \ $(liblftp_network_la_SOURCES) $(liblftp_pty_la_SOURCES) \ $(liblftp_tasks_la_SOURCES) $(proto_file_la_SOURCES) \ $(proto_fish_la_SOURCES) $(proto_ftp_la_SOURCES) \ $(proto_http_la_SOURCES) $(proto_sftp_la_SOURCES) \ $(lftp_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/build-aux/depcomp ChangeLog DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) pkglibexecdir = @pkglibexecdir@ ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ ALLOCA_H = @ALLOCA_H@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@ AR = @AR@ ARFLAGS = @ARFLAGS@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@ BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@ BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@ BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@ BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@ BYTESWAP_H = @BYTESWAP_H@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@ EMULTIHOP_VALUE = @EMULTIHOP_VALUE@ ENOLINK_HIDDEN = @ENOLINK_HIDDEN@ ENOLINK_VALUE = @ENOLINK_VALUE@ EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@ EOVERFLOW_VALUE = @EOVERFLOW_VALUE@ ERRNO_H = @ERRNO_H@ EXEEXT = @EXEEXT@ EXPAT_CFLAGS = @EXPAT_CFLAGS@ EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ EXPAT_LIBS = @EXPAT_LIBS@ EXPAT_VERSION = @EXPAT_VERSION@ FGREP = @FGREP@ FLOAT_H = @FLOAT_H@ FNMATCH_H = @FNMATCH_H@ GETOPT_CDEFS_H = @GETOPT_CDEFS_H@ GETOPT_H = @GETOPT_H@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GLIBC21 = @GLIBC21@ GLOB_H = @GLOB_H@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNULIB_ACCEPT = @GNULIB_ACCEPT@ GNULIB_ACCEPT4 = @GNULIB_ACCEPT4@ GNULIB_ACCESS = @GNULIB_ACCESS@ GNULIB_ACOSF = @GNULIB_ACOSF@ GNULIB_ACOSL = @GNULIB_ACOSL@ GNULIB_ALPHASORT = @GNULIB_ALPHASORT@ GNULIB_ASINF = @GNULIB_ASINF@ GNULIB_ASINL = @GNULIB_ASINL@ GNULIB_ATAN2F = @GNULIB_ATAN2F@ GNULIB_ATANF = @GNULIB_ATANF@ GNULIB_ATANL = @GNULIB_ATANL@ GNULIB_ATOLL = @GNULIB_ATOLL@ GNULIB_BIND = @GNULIB_BIND@ GNULIB_BTOWC = @GNULIB_BTOWC@ GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@ GNULIB_CANONICALIZE_FILE_NAME = @GNULIB_CANONICALIZE_FILE_NAME@ GNULIB_CBRT = @GNULIB_CBRT@ GNULIB_CBRTF = @GNULIB_CBRTF@ GNULIB_CBRTL = @GNULIB_CBRTL@ GNULIB_CEIL = @GNULIB_CEIL@ GNULIB_CEILF = @GNULIB_CEILF@ GNULIB_CEILL = @GNULIB_CEILL@ GNULIB_CHDIR = @GNULIB_CHDIR@ GNULIB_CHOWN = @GNULIB_CHOWN@ GNULIB_CLOSE = @GNULIB_CLOSE@ GNULIB_CLOSEDIR = @GNULIB_CLOSEDIR@ GNULIB_CONNECT = @GNULIB_CONNECT@ GNULIB_COPYSIGN = @GNULIB_COPYSIGN@ GNULIB_COPYSIGNF = @GNULIB_COPYSIGNF@ GNULIB_COPYSIGNL = @GNULIB_COPYSIGNL@ GNULIB_COPY_FILE_RANGE = @GNULIB_COPY_FILE_RANGE@ GNULIB_COSF = @GNULIB_COSF@ GNULIB_COSHF = @GNULIB_COSHF@ GNULIB_COSL = @GNULIB_COSL@ GNULIB_CREAT = @GNULIB_CREAT@ GNULIB_CTIME = @GNULIB_CTIME@ GNULIB_DIRFD = @GNULIB_DIRFD@ GNULIB_DPRINTF = @GNULIB_DPRINTF@ GNULIB_DUP = @GNULIB_DUP@ GNULIB_DUP2 = @GNULIB_DUP2@ GNULIB_DUP3 = @GNULIB_DUP3@ GNULIB_DUPLOCALE = @GNULIB_DUPLOCALE@ GNULIB_ENVIRON = @GNULIB_ENVIRON@ GNULIB_EUIDACCESS = @GNULIB_EUIDACCESS@ GNULIB_EXP2 = @GNULIB_EXP2@ GNULIB_EXP2F = @GNULIB_EXP2F@ GNULIB_EXP2L = @GNULIB_EXP2L@ GNULIB_EXPF = @GNULIB_EXPF@ GNULIB_EXPL = @GNULIB_EXPL@ GNULIB_EXPLICIT_BZERO = @GNULIB_EXPLICIT_BZERO@ GNULIB_EXPM1 = @GNULIB_EXPM1@ GNULIB_EXPM1F = @GNULIB_EXPM1F@ GNULIB_EXPM1L = @GNULIB_EXPM1L@ GNULIB_FABSF = @GNULIB_FABSF@ GNULIB_FABSL = @GNULIB_FABSL@ GNULIB_FACCESSAT = @GNULIB_FACCESSAT@ GNULIB_FCHDIR = @GNULIB_FCHDIR@ GNULIB_FCHMODAT = @GNULIB_FCHMODAT@ GNULIB_FCHOWNAT = @GNULIB_FCHOWNAT@ GNULIB_FCLOSE = @GNULIB_FCLOSE@ GNULIB_FCNTL = @GNULIB_FCNTL@ GNULIB_FDATASYNC = @GNULIB_FDATASYNC@ GNULIB_FDOPEN = @GNULIB_FDOPEN@ GNULIB_FDOPENDIR = @GNULIB_FDOPENDIR@ GNULIB_FFLUSH = @GNULIB_FFLUSH@ GNULIB_FFS = @GNULIB_FFS@ GNULIB_FFSL = @GNULIB_FFSL@ GNULIB_FFSLL = @GNULIB_FFSLL@ GNULIB_FGETC = @GNULIB_FGETC@ GNULIB_FGETS = @GNULIB_FGETS@ GNULIB_FLOOR = @GNULIB_FLOOR@ GNULIB_FLOORF = @GNULIB_FLOORF@ GNULIB_FLOORL = @GNULIB_FLOORL@ GNULIB_FMA = @GNULIB_FMA@ GNULIB_FMAF = @GNULIB_FMAF@ GNULIB_FMAL = @GNULIB_FMAL@ GNULIB_FMOD = @GNULIB_FMOD@ GNULIB_FMODF = @GNULIB_FMODF@ GNULIB_FMODL = @GNULIB_FMODL@ GNULIB_FNMATCH = @GNULIB_FNMATCH@ GNULIB_FOPEN = @GNULIB_FOPEN@ GNULIB_FPRINTF = @GNULIB_FPRINTF@ GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@ GNULIB_FPURGE = @GNULIB_FPURGE@ GNULIB_FPUTC = @GNULIB_FPUTC@ GNULIB_FPUTS = @GNULIB_FPUTS@ GNULIB_FREAD = @GNULIB_FREAD@ GNULIB_FREOPEN = @GNULIB_FREOPEN@ GNULIB_FREXP = @GNULIB_FREXP@ GNULIB_FREXPF = @GNULIB_FREXPF@ GNULIB_FREXPL = @GNULIB_FREXPL@ GNULIB_FSCANF = @GNULIB_FSCANF@ GNULIB_FSEEK = @GNULIB_FSEEK@ GNULIB_FSEEKO = @GNULIB_FSEEKO@ GNULIB_FSTAT = @GNULIB_FSTAT@ GNULIB_FSTATAT = @GNULIB_FSTATAT@ GNULIB_FSYNC = @GNULIB_FSYNC@ GNULIB_FTELL = @GNULIB_FTELL@ GNULIB_FTELLO = @GNULIB_FTELLO@ GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@ GNULIB_FUTIMENS = @GNULIB_FUTIMENS@ GNULIB_FWRITE = @GNULIB_FWRITE@ GNULIB_GETC = @GNULIB_GETC@ GNULIB_GETCHAR = @GNULIB_GETCHAR@ GNULIB_GETCWD = @GNULIB_GETCWD@ GNULIB_GETDELIM = @GNULIB_GETDELIM@ GNULIB_GETDOMAINNAME = @GNULIB_GETDOMAINNAME@ GNULIB_GETDTABLESIZE = @GNULIB_GETDTABLESIZE@ GNULIB_GETENTROPY = @GNULIB_GETENTROPY@ GNULIB_GETGROUPS = @GNULIB_GETGROUPS@ GNULIB_GETHOSTNAME = @GNULIB_GETHOSTNAME@ GNULIB_GETLINE = @GNULIB_GETLINE@ GNULIB_GETLOADAVG = @GNULIB_GETLOADAVG@ GNULIB_GETLOGIN = @GNULIB_GETLOGIN@ GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@ GNULIB_GETOPT_POSIX = @GNULIB_GETOPT_POSIX@ GNULIB_GETPAGESIZE = @GNULIB_GETPAGESIZE@ GNULIB_GETPASS = @GNULIB_GETPASS@ GNULIB_GETPEERNAME = @GNULIB_GETPEERNAME@ GNULIB_GETSOCKNAME = @GNULIB_GETSOCKNAME@ GNULIB_GETSOCKOPT = @GNULIB_GETSOCKOPT@ GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@ GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@ GNULIB_GETUMASK = @GNULIB_GETUMASK@ GNULIB_GETUSERSHELL = @GNULIB_GETUSERSHELL@ GNULIB_GLOB = @GNULIB_GLOB@ GNULIB_GL_UNISTD_H_GETOPT = @GNULIB_GL_UNISTD_H_GETOPT@ GNULIB_GRANTPT = @GNULIB_GRANTPT@ GNULIB_GROUP_MEMBER = @GNULIB_GROUP_MEMBER@ GNULIB_HYPOT = @GNULIB_HYPOT@ GNULIB_HYPOTF = @GNULIB_HYPOTF@ GNULIB_HYPOTL = @GNULIB_HYPOTL@ GNULIB_ICONV = @GNULIB_ICONV@ GNULIB_ILOGB = @GNULIB_ILOGB@ GNULIB_ILOGBF = @GNULIB_ILOGBF@ GNULIB_ILOGBL = @GNULIB_ILOGBL@ GNULIB_IMAXABS = @GNULIB_IMAXABS@ GNULIB_IMAXDIV = @GNULIB_IMAXDIV@ GNULIB_INET_NTOP = @GNULIB_INET_NTOP@ GNULIB_INET_PTON = @GNULIB_INET_PTON@ GNULIB_ISATTY = @GNULIB_ISATTY@ GNULIB_ISBLANK = @GNULIB_ISBLANK@ GNULIB_ISFINITE = @GNULIB_ISFINITE@ GNULIB_ISINF = @GNULIB_ISINF@ GNULIB_ISNAN = @GNULIB_ISNAN@ GNULIB_ISNAND = @GNULIB_ISNAND@ GNULIB_ISNANF = @GNULIB_ISNANF@ GNULIB_ISNANL = @GNULIB_ISNANL@ GNULIB_ISWBLANK = @GNULIB_ISWBLANK@ GNULIB_ISWCTYPE = @GNULIB_ISWCTYPE@ GNULIB_ISWDIGIT = @GNULIB_ISWDIGIT@ GNULIB_ISWXDIGIT = @GNULIB_ISWXDIGIT@ GNULIB_LCHMOD = @GNULIB_LCHMOD@ GNULIB_LCHOWN = @GNULIB_LCHOWN@ GNULIB_LDEXPF = @GNULIB_LDEXPF@ GNULIB_LDEXPL = @GNULIB_LDEXPL@ GNULIB_LINK = @GNULIB_LINK@ GNULIB_LINKAT = @GNULIB_LINKAT@ GNULIB_LISTEN = @GNULIB_LISTEN@ GNULIB_LOCALECONV = @GNULIB_LOCALECONV@ GNULIB_LOCALENAME = @GNULIB_LOCALENAME@ GNULIB_LOCALTIME = @GNULIB_LOCALTIME@ GNULIB_LOG = @GNULIB_LOG@ GNULIB_LOG10 = @GNULIB_LOG10@ GNULIB_LOG10F = @GNULIB_LOG10F@ GNULIB_LOG10L = @GNULIB_LOG10L@ GNULIB_LOG1P = @GNULIB_LOG1P@ GNULIB_LOG1PF = @GNULIB_LOG1PF@ GNULIB_LOG1PL = @GNULIB_LOG1PL@ GNULIB_LOG2 = @GNULIB_LOG2@ GNULIB_LOG2F = @GNULIB_LOG2F@ GNULIB_LOG2L = @GNULIB_LOG2L@ GNULIB_LOGB = @GNULIB_LOGB@ GNULIB_LOGBF = @GNULIB_LOGBF@ GNULIB_LOGBL = @GNULIB_LOGBL@ GNULIB_LOGF = @GNULIB_LOGF@ GNULIB_LOGL = @GNULIB_LOGL@ GNULIB_LSEEK = @GNULIB_LSEEK@ GNULIB_LSTAT = @GNULIB_LSTAT@ GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@ GNULIB_MBRLEN = @GNULIB_MBRLEN@ GNULIB_MBRTOWC = @GNULIB_MBRTOWC@ GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@ GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@ GNULIB_MBSCHR = @GNULIB_MBSCHR@ GNULIB_MBSCSPN = @GNULIB_MBSCSPN@ GNULIB_MBSINIT = @GNULIB_MBSINIT@ GNULIB_MBSLEN = @GNULIB_MBSLEN@ GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@ GNULIB_MBSNLEN = @GNULIB_MBSNLEN@ GNULIB_MBSNRTOWCS = @GNULIB_MBSNRTOWCS@ GNULIB_MBSPBRK = @GNULIB_MBSPBRK@ GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@ GNULIB_MBSRCHR = @GNULIB_MBSRCHR@ GNULIB_MBSRTOWCS = @GNULIB_MBSRTOWCS@ GNULIB_MBSSEP = @GNULIB_MBSSEP@ GNULIB_MBSSPN = @GNULIB_MBSSPN@ GNULIB_MBSSTR = @GNULIB_MBSSTR@ GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@ GNULIB_MBTOWC = @GNULIB_MBTOWC@ GNULIB_MEMCHR = @GNULIB_MEMCHR@ GNULIB_MEMMEM = @GNULIB_MEMMEM@ GNULIB_MEMPCPY = @GNULIB_MEMPCPY@ GNULIB_MEMRCHR = @GNULIB_MEMRCHR@ GNULIB_MKDIRAT = @GNULIB_MKDIRAT@ GNULIB_MKDTEMP = @GNULIB_MKDTEMP@ GNULIB_MKFIFO = @GNULIB_MKFIFO@ GNULIB_MKFIFOAT = @GNULIB_MKFIFOAT@ GNULIB_MKNOD = @GNULIB_MKNOD@ GNULIB_MKNODAT = @GNULIB_MKNODAT@ GNULIB_MKOSTEMP = @GNULIB_MKOSTEMP@ GNULIB_MKOSTEMPS = @GNULIB_MKOSTEMPS@ GNULIB_MKSTEMP = @GNULIB_MKSTEMP@ GNULIB_MKSTEMPS = @GNULIB_MKSTEMPS@ GNULIB_MKTIME = @GNULIB_MKTIME@ GNULIB_MODF = @GNULIB_MODF@ GNULIB_MODFF = @GNULIB_MODFF@ GNULIB_MODFL = @GNULIB_MODFL@ GNULIB_NANOSLEEP = @GNULIB_NANOSLEEP@ GNULIB_NL_LANGINFO = @GNULIB_NL_LANGINFO@ GNULIB_NONBLOCKING = @GNULIB_NONBLOCKING@ GNULIB_OBSTACK_PRINTF = @GNULIB_OBSTACK_PRINTF@ GNULIB_OBSTACK_PRINTF_POSIX = @GNULIB_OBSTACK_PRINTF_POSIX@ GNULIB_OPEN = @GNULIB_OPEN@ GNULIB_OPENAT = @GNULIB_OPENAT@ GNULIB_OPENDIR = @GNULIB_OPENDIR@ GNULIB_OVERRIDES_STRUCT_STAT = @GNULIB_OVERRIDES_STRUCT_STAT@ GNULIB_OVERRIDES_WINT_T = @GNULIB_OVERRIDES_WINT_T@ GNULIB_PCLOSE = @GNULIB_PCLOSE@ GNULIB_PERROR = @GNULIB_PERROR@ GNULIB_PIPE = @GNULIB_PIPE@ GNULIB_PIPE2 = @GNULIB_PIPE2@ GNULIB_POLL = @GNULIB_POLL@ GNULIB_POPEN = @GNULIB_POPEN@ GNULIB_POSIX_OPENPT = @GNULIB_POSIX_OPENPT@ GNULIB_POWF = @GNULIB_POWF@ GNULIB_PREAD = @GNULIB_PREAD@ GNULIB_PRINTF = @GNULIB_PRINTF@ GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@ GNULIB_PSELECT = @GNULIB_PSELECT@ GNULIB_PTHREAD_SIGMASK = @GNULIB_PTHREAD_SIGMASK@ GNULIB_PTSNAME = @GNULIB_PTSNAME@ GNULIB_PTSNAME_R = @GNULIB_PTSNAME_R@ GNULIB_PUTC = @GNULIB_PUTC@ GNULIB_PUTCHAR = @GNULIB_PUTCHAR@ GNULIB_PUTENV = @GNULIB_PUTENV@ GNULIB_PUTS = @GNULIB_PUTS@ GNULIB_PWRITE = @GNULIB_PWRITE@ GNULIB_QSORT_R = @GNULIB_QSORT_R@ GNULIB_RAISE = @GNULIB_RAISE@ GNULIB_RANDOM = @GNULIB_RANDOM@ GNULIB_RANDOM_R = @GNULIB_RANDOM_R@ GNULIB_RAWMEMCHR = @GNULIB_RAWMEMCHR@ GNULIB_READ = @GNULIB_READ@ GNULIB_READDIR = @GNULIB_READDIR@ GNULIB_READLINK = @GNULIB_READLINK@ GNULIB_READLINKAT = @GNULIB_READLINKAT@ GNULIB_REALLOCARRAY = @GNULIB_REALLOCARRAY@ GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@ GNULIB_REALPATH = @GNULIB_REALPATH@ GNULIB_RECV = @GNULIB_RECV@ GNULIB_RECVFROM = @GNULIB_RECVFROM@ GNULIB_REMAINDER = @GNULIB_REMAINDER@ GNULIB_REMAINDERF = @GNULIB_REMAINDERF@ GNULIB_REMAINDERL = @GNULIB_REMAINDERL@ GNULIB_REMOVE = @GNULIB_REMOVE@ GNULIB_RENAME = @GNULIB_RENAME@ GNULIB_RENAMEAT = @GNULIB_RENAMEAT@ GNULIB_REWINDDIR = @GNULIB_REWINDDIR@ GNULIB_RINT = @GNULIB_RINT@ GNULIB_RINTF = @GNULIB_RINTF@ GNULIB_RINTL = @GNULIB_RINTL@ GNULIB_RMDIR = @GNULIB_RMDIR@ GNULIB_ROUND = @GNULIB_ROUND@ GNULIB_ROUNDF = @GNULIB_ROUNDF@ GNULIB_ROUNDL = @GNULIB_ROUNDL@ GNULIB_RPMATCH = @GNULIB_RPMATCH@ GNULIB_SCANDIR = @GNULIB_SCANDIR@ GNULIB_SCANF = @GNULIB_SCANF@ GNULIB_SECURE_GETENV = @GNULIB_SECURE_GETENV@ GNULIB_SELECT = @GNULIB_SELECT@ GNULIB_SEND = @GNULIB_SEND@ GNULIB_SENDTO = @GNULIB_SENDTO@ GNULIB_SETENV = @GNULIB_SETENV@ GNULIB_SETHOSTNAME = @GNULIB_SETHOSTNAME@ GNULIB_SETLOCALE = @GNULIB_SETLOCALE@ GNULIB_SETLOCALE_NULL = @GNULIB_SETLOCALE_NULL@ GNULIB_SETSOCKOPT = @GNULIB_SETSOCKOPT@ GNULIB_SHUTDOWN = @GNULIB_SHUTDOWN@ GNULIB_SIGACTION = @GNULIB_SIGACTION@ GNULIB_SIGNAL_H_SIGPIPE = @GNULIB_SIGNAL_H_SIGPIPE@ GNULIB_SIGNBIT = @GNULIB_SIGNBIT@ GNULIB_SIGPROCMASK = @GNULIB_SIGPROCMASK@ GNULIB_SINF = @GNULIB_SINF@ GNULIB_SINHF = @GNULIB_SINHF@ GNULIB_SINL = @GNULIB_SINL@ GNULIB_SLEEP = @GNULIB_SLEEP@ GNULIB_SNPRINTF = @GNULIB_SNPRINTF@ GNULIB_SOCKET = @GNULIB_SOCKET@ GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@ GNULIB_SQRTF = @GNULIB_SQRTF@ GNULIB_SQRTL = @GNULIB_SQRTL@ GNULIB_STAT = @GNULIB_STAT@ GNULIB_STDIO_H_NONBLOCKING = @GNULIB_STDIO_H_NONBLOCKING@ GNULIB_STDIO_H_SIGPIPE = @GNULIB_STDIO_H_SIGPIPE@ GNULIB_STPCPY = @GNULIB_STPCPY@ GNULIB_STPNCPY = @GNULIB_STPNCPY@ GNULIB_STRCASESTR = @GNULIB_STRCASESTR@ GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@ GNULIB_STRDUP = @GNULIB_STRDUP@ GNULIB_STRERROR = @GNULIB_STRERROR@ GNULIB_STRERROR_R = @GNULIB_STRERROR_R@ GNULIB_STRFTIME = @GNULIB_STRFTIME@ GNULIB_STRNCAT = @GNULIB_STRNCAT@ GNULIB_STRNDUP = @GNULIB_STRNDUP@ GNULIB_STRNLEN = @GNULIB_STRNLEN@ GNULIB_STRPBRK = @GNULIB_STRPBRK@ GNULIB_STRPTIME = @GNULIB_STRPTIME@ GNULIB_STRSEP = @GNULIB_STRSEP@ GNULIB_STRSIGNAL = @GNULIB_STRSIGNAL@ GNULIB_STRSTR = @GNULIB_STRSTR@ GNULIB_STRTOD = @GNULIB_STRTOD@ GNULIB_STRTOIMAX = @GNULIB_STRTOIMAX@ GNULIB_STRTOK_R = @GNULIB_STRTOK_R@ GNULIB_STRTOLD = @GNULIB_STRTOLD@ GNULIB_STRTOLL = @GNULIB_STRTOLL@ GNULIB_STRTOULL = @GNULIB_STRTOULL@ GNULIB_STRTOUMAX = @GNULIB_STRTOUMAX@ GNULIB_STRVERSCMP = @GNULIB_STRVERSCMP@ GNULIB_SYMLINK = @GNULIB_SYMLINK@ GNULIB_SYMLINKAT = @GNULIB_SYMLINKAT@ GNULIB_SYSTEM_POSIX = @GNULIB_SYSTEM_POSIX@ GNULIB_TANF = @GNULIB_TANF@ GNULIB_TANHF = @GNULIB_TANHF@ GNULIB_TANL = @GNULIB_TANL@ GNULIB_TIMEGM = @GNULIB_TIMEGM@ GNULIB_TIME_R = @GNULIB_TIME_R@ GNULIB_TIME_RZ = @GNULIB_TIME_RZ@ GNULIB_TMPFILE = @GNULIB_TMPFILE@ GNULIB_TOWCTRANS = @GNULIB_TOWCTRANS@ GNULIB_TRUNC = @GNULIB_TRUNC@ GNULIB_TRUNCATE = @GNULIB_TRUNCATE@ GNULIB_TRUNCF = @GNULIB_TRUNCF@ GNULIB_TRUNCL = @GNULIB_TRUNCL@ GNULIB_TTYNAME_R = @GNULIB_TTYNAME_R@ GNULIB_TZSET = @GNULIB_TZSET@ GNULIB_UNISTD_H_NONBLOCKING = @GNULIB_UNISTD_H_NONBLOCKING@ GNULIB_UNISTD_H_SIGPIPE = @GNULIB_UNISTD_H_SIGPIPE@ GNULIB_UNLINK = @GNULIB_UNLINK@ GNULIB_UNLINKAT = @GNULIB_UNLINKAT@ GNULIB_UNLOCKPT = @GNULIB_UNLOCKPT@ GNULIB_UNSETENV = @GNULIB_UNSETENV@ GNULIB_USLEEP = @GNULIB_USLEEP@ GNULIB_UTIMENSAT = @GNULIB_UTIMENSAT@ GNULIB_VASPRINTF = @GNULIB_VASPRINTF@ GNULIB_VDPRINTF = @GNULIB_VDPRINTF@ GNULIB_VFPRINTF = @GNULIB_VFPRINTF@ GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@ GNULIB_VFSCANF = @GNULIB_VFSCANF@ GNULIB_VPRINTF = @GNULIB_VPRINTF@ GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@ GNULIB_VSCANF = @GNULIB_VSCANF@ GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@ GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@ GNULIB_WCPCPY = @GNULIB_WCPCPY@ GNULIB_WCPNCPY = @GNULIB_WCPNCPY@ GNULIB_WCRTOMB = @GNULIB_WCRTOMB@ GNULIB_WCSCASECMP = @GNULIB_WCSCASECMP@ GNULIB_WCSCAT = @GNULIB_WCSCAT@ GNULIB_WCSCHR = @GNULIB_WCSCHR@ GNULIB_WCSCMP = @GNULIB_WCSCMP@ GNULIB_WCSCOLL = @GNULIB_WCSCOLL@ GNULIB_WCSCPY = @GNULIB_WCSCPY@ GNULIB_WCSCSPN = @GNULIB_WCSCSPN@ GNULIB_WCSDUP = @GNULIB_WCSDUP@ GNULIB_WCSFTIME = @GNULIB_WCSFTIME@ GNULIB_WCSLEN = @GNULIB_WCSLEN@ GNULIB_WCSNCASECMP = @GNULIB_WCSNCASECMP@ GNULIB_WCSNCAT = @GNULIB_WCSNCAT@ GNULIB_WCSNCMP = @GNULIB_WCSNCMP@ GNULIB_WCSNCPY = @GNULIB_WCSNCPY@ GNULIB_WCSNLEN = @GNULIB_WCSNLEN@ GNULIB_WCSNRTOMBS = @GNULIB_WCSNRTOMBS@ GNULIB_WCSPBRK = @GNULIB_WCSPBRK@ GNULIB_WCSRCHR = @GNULIB_WCSRCHR@ GNULIB_WCSRTOMBS = @GNULIB_WCSRTOMBS@ GNULIB_WCSSPN = @GNULIB_WCSSPN@ GNULIB_WCSSTR = @GNULIB_WCSSTR@ GNULIB_WCSTOK = @GNULIB_WCSTOK@ GNULIB_WCSWIDTH = @GNULIB_WCSWIDTH@ GNULIB_WCSXFRM = @GNULIB_WCSXFRM@ GNULIB_WCTOB = @GNULIB_WCTOB@ GNULIB_WCTOMB = @GNULIB_WCTOMB@ GNULIB_WCTRANS = @GNULIB_WCTRANS@ GNULIB_WCTYPE = @GNULIB_WCTYPE@ GNULIB_WCWIDTH = @GNULIB_WCWIDTH@ GNULIB_WMEMCHR = @GNULIB_WMEMCHR@ GNULIB_WMEMCMP = @GNULIB_WMEMCMP@ GNULIB_WMEMCPY = @GNULIB_WMEMCPY@ GNULIB_WMEMMOVE = @GNULIB_WMEMMOVE@ GNULIB_WMEMPCPY = @GNULIB_WMEMPCPY@ GNULIB_WMEMSET = @GNULIB_WMEMSET@ GNULIB_WRITE = @GNULIB_WRITE@ GNULIB__EXIT = @GNULIB__EXIT@ GREP = @GREP@ HAVE_ACCEPT4 = @HAVE_ACCEPT4@ HAVE_ACOSF = @HAVE_ACOSF@ HAVE_ACOSL = @HAVE_ACOSL@ HAVE_ALLOCA_H = @HAVE_ALLOCA_H@ HAVE_ALPHASORT = @HAVE_ALPHASORT@ HAVE_ARPA_INET_H = @HAVE_ARPA_INET_H@ HAVE_ASINF = @HAVE_ASINF@ HAVE_ASINL = @HAVE_ASINL@ HAVE_ATAN2F = @HAVE_ATAN2F@ HAVE_ATANF = @HAVE_ATANF@ HAVE_ATANL = @HAVE_ATANL@ HAVE_ATOLL = @HAVE_ATOLL@ HAVE_BTOWC = @HAVE_BTOWC@ HAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@ HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@ HAVE_CBRT = @HAVE_CBRT@ HAVE_CBRTF = @HAVE_CBRTF@ HAVE_CBRTL = @HAVE_CBRTL@ HAVE_CHOWN = @HAVE_CHOWN@ HAVE_CLOSEDIR = @HAVE_CLOSEDIR@ HAVE_COPYSIGN = @HAVE_COPYSIGN@ HAVE_COPYSIGNL = @HAVE_COPYSIGNL@ HAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@ HAVE_COSF = @HAVE_COSF@ HAVE_COSHF = @HAVE_COSHF@ HAVE_COSL = @HAVE_COSL@ HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@ HAVE_DECL_ACOSL = @HAVE_DECL_ACOSL@ HAVE_DECL_ASINL = @HAVE_DECL_ASINL@ HAVE_DECL_ATANL = @HAVE_DECL_ATANL@ HAVE_DECL_CBRTF = @HAVE_DECL_CBRTF@ HAVE_DECL_CBRTL = @HAVE_DECL_CBRTL@ HAVE_DECL_CEILF = @HAVE_DECL_CEILF@ HAVE_DECL_CEILL = @HAVE_DECL_CEILL@ HAVE_DECL_COPYSIGNF = @HAVE_DECL_COPYSIGNF@ HAVE_DECL_COSL = @HAVE_DECL_COSL@ HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@ HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@ HAVE_DECL_EXP2 = @HAVE_DECL_EXP2@ HAVE_DECL_EXP2F = @HAVE_DECL_EXP2F@ HAVE_DECL_EXP2L = @HAVE_DECL_EXP2L@ HAVE_DECL_EXPL = @HAVE_DECL_EXPL@ HAVE_DECL_EXPM1L = @HAVE_DECL_EXPM1L@ HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@ HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@ HAVE_DECL_FDOPENDIR = @HAVE_DECL_FDOPENDIR@ HAVE_DECL_FLOORF = @HAVE_DECL_FLOORF@ HAVE_DECL_FLOORL = @HAVE_DECL_FLOORL@ HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@ HAVE_DECL_FREXPL = @HAVE_DECL_FREXPL@ HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@ HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@ HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@ HAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@ HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@ HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@ HAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@ HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@ HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@ HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@ HAVE_DECL_IMAXABS = @HAVE_DECL_IMAXABS@ HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@ HAVE_DECL_INET_NTOP = @HAVE_DECL_INET_NTOP@ HAVE_DECL_INET_PTON = @HAVE_DECL_INET_PTON@ HAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@ HAVE_DECL_LDEXPL = @HAVE_DECL_LDEXPL@ HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@ HAVE_DECL_LOG10L = @HAVE_DECL_LOG10L@ HAVE_DECL_LOG2 = @HAVE_DECL_LOG2@ HAVE_DECL_LOG2F = @HAVE_DECL_LOG2F@ HAVE_DECL_LOG2L = @HAVE_DECL_LOG2L@ HAVE_DECL_LOGB = @HAVE_DECL_LOGB@ HAVE_DECL_LOGL = @HAVE_DECL_LOGL@ HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@ HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@ HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@ HAVE_DECL_REMAINDER = @HAVE_DECL_REMAINDER@ HAVE_DECL_REMAINDERL = @HAVE_DECL_REMAINDERL@ HAVE_DECL_RINTF = @HAVE_DECL_RINTF@ HAVE_DECL_ROUND = @HAVE_DECL_ROUND@ HAVE_DECL_ROUNDF = @HAVE_DECL_ROUNDF@ HAVE_DECL_ROUNDL = @HAVE_DECL_ROUNDL@ HAVE_DECL_SETENV = @HAVE_DECL_SETENV@ HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@ HAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@ HAVE_DECL_SINL = @HAVE_DECL_SINL@ HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@ HAVE_DECL_SQRTL = @HAVE_DECL_SQRTL@ HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@ HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@ HAVE_DECL_STRNCASECMP = @HAVE_DECL_STRNCASECMP@ HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@ HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@ HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@ HAVE_DECL_STRTOIMAX = @HAVE_DECL_STRTOIMAX@ HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@ HAVE_DECL_STRTOUMAX = @HAVE_DECL_STRTOUMAX@ HAVE_DECL_TANL = @HAVE_DECL_TANL@ HAVE_DECL_TRUNC = @HAVE_DECL_TRUNC@ HAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@ HAVE_DECL_TRUNCF = @HAVE_DECL_TRUNCF@ HAVE_DECL_TRUNCL = @HAVE_DECL_TRUNCL@ HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@ HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@ HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@ HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@ HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@ HAVE_DIRENT_H = @HAVE_DIRENT_H@ HAVE_DPRINTF = @HAVE_DPRINTF@ HAVE_DUP3 = @HAVE_DUP3@ HAVE_DUPLOCALE = @HAVE_DUPLOCALE@ HAVE_EUIDACCESS = @HAVE_EUIDACCESS@ HAVE_EXPF = @HAVE_EXPF@ HAVE_EXPL = @HAVE_EXPL@ HAVE_EXPLICIT_BZERO = @HAVE_EXPLICIT_BZERO@ HAVE_EXPM1 = @HAVE_EXPM1@ HAVE_EXPM1F = @HAVE_EXPM1F@ HAVE_FABSF = @HAVE_FABSF@ HAVE_FABSL = @HAVE_FABSL@ HAVE_FACCESSAT = @HAVE_FACCESSAT@ HAVE_FCHDIR = @HAVE_FCHDIR@ HAVE_FCHMODAT = @HAVE_FCHMODAT@ HAVE_FCHOWNAT = @HAVE_FCHOWNAT@ HAVE_FCNTL = @HAVE_FCNTL@ HAVE_FDATASYNC = @HAVE_FDATASYNC@ HAVE_FDOPENDIR = @HAVE_FDOPENDIR@ HAVE_FEATURES_H = @HAVE_FEATURES_H@ HAVE_FFS = @HAVE_FFS@ HAVE_FFSL = @HAVE_FFSL@ HAVE_FFSLL = @HAVE_FFSLL@ HAVE_FMA = @HAVE_FMA@ HAVE_FMAF = @HAVE_FMAF@ HAVE_FMAL = @HAVE_FMAL@ HAVE_FMODF = @HAVE_FMODF@ HAVE_FMODL = @HAVE_FMODL@ HAVE_FNMATCH = @HAVE_FNMATCH@ HAVE_FNMATCH_H = @HAVE_FNMATCH_H@ HAVE_FREELOCALE = @HAVE_FREELOCALE@ HAVE_FREXPF = @HAVE_FREXPF@ HAVE_FSEEKO = @HAVE_FSEEKO@ HAVE_FSTATAT = @HAVE_FSTATAT@ HAVE_FSYNC = @HAVE_FSYNC@ HAVE_FTELLO = @HAVE_FTELLO@ HAVE_FTRUNCATE = @HAVE_FTRUNCATE@ HAVE_FUTIMENS = @HAVE_FUTIMENS@ HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@ HAVE_GETENTROPY = @HAVE_GETENTROPY@ HAVE_GETGROUPS = @HAVE_GETGROUPS@ HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@ HAVE_GETLOGIN = @HAVE_GETLOGIN@ HAVE_GETOPT_H = @HAVE_GETOPT_H@ HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@ HAVE_GETPASS = @HAVE_GETPASS@ HAVE_GETSUBOPT = @HAVE_GETSUBOPT@ HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@ HAVE_GETUMASK = @HAVE_GETUMASK@ HAVE_GLOB = @HAVE_GLOB@ HAVE_GLOB_H = @HAVE_GLOB_H@ HAVE_GLOB_PATTERN_P = @HAVE_GLOB_PATTERN_P@ HAVE_GRANTPT = @HAVE_GRANTPT@ HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@ HAVE_HYPOTF = @HAVE_HYPOTF@ HAVE_HYPOTL = @HAVE_HYPOTL@ HAVE_ILOGB = @HAVE_ILOGB@ HAVE_ILOGBF = @HAVE_ILOGBF@ HAVE_ILOGBL = @HAVE_ILOGBL@ HAVE_IMAXDIV_T = @HAVE_IMAXDIV_T@ HAVE_INITSTATE = @HAVE_INITSTATE@ HAVE_INTTYPES_H = @HAVE_INTTYPES_H@ HAVE_ISBLANK = @HAVE_ISBLANK@ HAVE_ISNAND = @HAVE_ISNAND@ HAVE_ISNANF = @HAVE_ISNANF@ HAVE_ISNANL = @HAVE_ISNANL@ HAVE_ISWBLANK = @HAVE_ISWBLANK@ HAVE_ISWCNTRL = @HAVE_ISWCNTRL@ HAVE_LANGINFO_ALTMON = @HAVE_LANGINFO_ALTMON@ HAVE_LANGINFO_CODESET = @HAVE_LANGINFO_CODESET@ HAVE_LANGINFO_ERA = @HAVE_LANGINFO_ERA@ HAVE_LANGINFO_H = @HAVE_LANGINFO_H@ HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@ HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@ HAVE_LCHMOD = @HAVE_LCHMOD@ HAVE_LCHOWN = @HAVE_LCHOWN@ HAVE_LDEXPF = @HAVE_LDEXPF@ HAVE_LINK = @HAVE_LINK@ HAVE_LINKAT = @HAVE_LINKAT@ HAVE_LOG10F = @HAVE_LOG10F@ HAVE_LOG10L = @HAVE_LOG10L@ HAVE_LOG1P = @HAVE_LOG1P@ HAVE_LOG1PF = @HAVE_LOG1PF@ HAVE_LOG1PL = @HAVE_LOG1PL@ HAVE_LOGBF = @HAVE_LOGBF@ HAVE_LOGBL = @HAVE_LOGBL@ HAVE_LOGF = @HAVE_LOGF@ HAVE_LOGL = @HAVE_LOGL@ HAVE_LSTAT = @HAVE_LSTAT@ HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@ HAVE_MBRLEN = @HAVE_MBRLEN@ HAVE_MBRTOWC = @HAVE_MBRTOWC@ HAVE_MBSINIT = @HAVE_MBSINIT@ HAVE_MBSLEN = @HAVE_MBSLEN@ HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@ HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@ HAVE_MBTOWC = @HAVE_MBTOWC@ HAVE_MEMPCPY = @HAVE_MEMPCPY@ HAVE_MKDIRAT = @HAVE_MKDIRAT@ HAVE_MKDTEMP = @HAVE_MKDTEMP@ HAVE_MKFIFO = @HAVE_MKFIFO@ HAVE_MKFIFOAT = @HAVE_MKFIFOAT@ HAVE_MKNOD = @HAVE_MKNOD@ HAVE_MKNODAT = @HAVE_MKNODAT@ HAVE_MKOSTEMP = @HAVE_MKOSTEMP@ HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@ HAVE_MKSTEMP = @HAVE_MKSTEMP@ HAVE_MKSTEMPS = @HAVE_MKSTEMPS@ HAVE_MODFF = @HAVE_MODFF@ HAVE_MODFL = @HAVE_MODFL@ HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@ HAVE_NANOSLEEP = @HAVE_NANOSLEEP@ HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@ HAVE_NEWLOCALE = @HAVE_NEWLOCALE@ HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@ HAVE_OPENAT = @HAVE_OPENAT@ HAVE_OPENDIR = @HAVE_OPENDIR@ HAVE_OS_H = @HAVE_OS_H@ HAVE_PCLOSE = @HAVE_PCLOSE@ HAVE_PIPE = @HAVE_PIPE@ HAVE_PIPE2 = @HAVE_PIPE2@ HAVE_POLL = @HAVE_POLL@ HAVE_POLL_H = @HAVE_POLL_H@ HAVE_POPEN = @HAVE_POPEN@ HAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@ HAVE_POSIX_SIGNALBLOCKING = @HAVE_POSIX_SIGNALBLOCKING@ HAVE_POWF = @HAVE_POWF@ HAVE_PREAD = @HAVE_PREAD@ HAVE_PSELECT = @HAVE_PSELECT@ HAVE_PTHREAD_SIGMASK = @HAVE_PTHREAD_SIGMASK@ HAVE_PTSNAME = @HAVE_PTSNAME@ HAVE_PTSNAME_R = @HAVE_PTSNAME_R@ HAVE_PWRITE = @HAVE_PWRITE@ HAVE_QSORT_R = @HAVE_QSORT_R@ HAVE_RAISE = @HAVE_RAISE@ HAVE_RANDOM = @HAVE_RANDOM@ HAVE_RANDOM_H = @HAVE_RANDOM_H@ HAVE_RANDOM_R = @HAVE_RANDOM_R@ HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@ HAVE_READDIR = @HAVE_READDIR@ HAVE_READLINK = @HAVE_READLINK@ HAVE_READLINKAT = @HAVE_READLINKAT@ HAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@ HAVE_REALPATH = @HAVE_REALPATH@ HAVE_REMAINDER = @HAVE_REMAINDER@ HAVE_REMAINDERF = @HAVE_REMAINDERF@ HAVE_RENAMEAT = @HAVE_RENAMEAT@ HAVE_REWINDDIR = @HAVE_REWINDDIR@ HAVE_RINT = @HAVE_RINT@ HAVE_RINTL = @HAVE_RINTL@ HAVE_RPMATCH = @HAVE_RPMATCH@ HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = @HAVE_SAME_LONG_DOUBLE_AS_DOUBLE@ HAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@ HAVE_SCANDIR = @HAVE_SCANDIR@ HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@ HAVE_SETENV = @HAVE_SETENV@ HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@ HAVE_SETSTATE = @HAVE_SETSTATE@ HAVE_SIGACTION = @HAVE_SIGACTION@ HAVE_SIGHANDLER_T = @HAVE_SIGHANDLER_T@ HAVE_SIGINFO_T = @HAVE_SIGINFO_T@ HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@ HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@ HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@ HAVE_SIGSET_T = @HAVE_SIGSET_T@ HAVE_SINF = @HAVE_SINF@ HAVE_SINHF = @HAVE_SINHF@ HAVE_SINL = @HAVE_SINL@ HAVE_SLEEP = @HAVE_SLEEP@ HAVE_SQRTF = @HAVE_SQRTF@ HAVE_SQRTL = @HAVE_SQRTL@ HAVE_STDINT_H = @HAVE_STDINT_H@ HAVE_STPCPY = @HAVE_STPCPY@ HAVE_STPNCPY = @HAVE_STPNCPY@ HAVE_STRCASECMP = @HAVE_STRCASECMP@ HAVE_STRCASESTR = @HAVE_STRCASESTR@ HAVE_STRCHRNUL = @HAVE_STRCHRNUL@ HAVE_STRINGS_H = @HAVE_STRINGS_H@ HAVE_STRPBRK = @HAVE_STRPBRK@ HAVE_STRPTIME = @HAVE_STRPTIME@ HAVE_STRSEP = @HAVE_STRSEP@ HAVE_STRTOD = @HAVE_STRTOD@ HAVE_STRTOLD = @HAVE_STRTOLD@ HAVE_STRTOLL = @HAVE_STRTOLL@ HAVE_STRTOULL = @HAVE_STRTOULL@ HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@ HAVE_STRUCT_SIGACTION_SA_SIGACTION = @HAVE_STRUCT_SIGACTION_SA_SIGACTION@ HAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@ HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@ HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@ HAVE_STRVERSCMP = @HAVE_STRVERSCMP@ HAVE_SYMLINK = @HAVE_SYMLINK@ HAVE_SYMLINKAT = @HAVE_SYMLINKAT@ HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@ HAVE_SYS_CDEFS_H = @HAVE_SYS_CDEFS_H@ HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@ HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@ HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@ HAVE_SYS_SELECT_H = @HAVE_SYS_SELECT_H@ HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@ HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@ HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@ HAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@ HAVE_TANF = @HAVE_TANF@ HAVE_TANHF = @HAVE_TANHF@ HAVE_TANL = @HAVE_TANL@ HAVE_TIMEGM = @HAVE_TIMEGM@ HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@ HAVE_TYPE_VOLATILE_SIG_ATOMIC_T = @HAVE_TYPE_VOLATILE_SIG_ATOMIC_T@ HAVE_TZSET = @HAVE_TZSET@ HAVE_UNISTD_H = @HAVE_UNISTD_H@ HAVE_UNLINKAT = @HAVE_UNLINKAT@ HAVE_UNLOCKPT = @HAVE_UNLOCKPT@ HAVE_USLEEP = @HAVE_USLEEP@ HAVE_UTIMENSAT = @HAVE_UTIMENSAT@ HAVE_VASPRINTF = @HAVE_VASPRINTF@ HAVE_VDPRINTF = @HAVE_VDPRINTF@ HAVE_VISIBILITY = @HAVE_VISIBILITY@ HAVE_WCHAR_H = @HAVE_WCHAR_H@ HAVE_WCHAR_T = @HAVE_WCHAR_T@ HAVE_WCPCPY = @HAVE_WCPCPY@ HAVE_WCPNCPY = @HAVE_WCPNCPY@ HAVE_WCRTOMB = @HAVE_WCRTOMB@ HAVE_WCSCASECMP = @HAVE_WCSCASECMP@ HAVE_WCSCAT = @HAVE_WCSCAT@ HAVE_WCSCHR = @HAVE_WCSCHR@ HAVE_WCSCMP = @HAVE_WCSCMP@ HAVE_WCSCOLL = @HAVE_WCSCOLL@ HAVE_WCSCPY = @HAVE_WCSCPY@ HAVE_WCSCSPN = @HAVE_WCSCSPN@ HAVE_WCSDUP = @HAVE_WCSDUP@ HAVE_WCSFTIME = @HAVE_WCSFTIME@ HAVE_WCSLEN = @HAVE_WCSLEN@ HAVE_WCSNCASECMP = @HAVE_WCSNCASECMP@ HAVE_WCSNCAT = @HAVE_WCSNCAT@ HAVE_WCSNCMP = @HAVE_WCSNCMP@ HAVE_WCSNCPY = @HAVE_WCSNCPY@ HAVE_WCSNLEN = @HAVE_WCSNLEN@ HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@ HAVE_WCSPBRK = @HAVE_WCSPBRK@ HAVE_WCSRCHR = @HAVE_WCSRCHR@ HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@ HAVE_WCSSPN = @HAVE_WCSSPN@ HAVE_WCSSTR = @HAVE_WCSSTR@ HAVE_WCSTOK = @HAVE_WCSTOK@ HAVE_WCSWIDTH = @HAVE_WCSWIDTH@ HAVE_WCSXFRM = @HAVE_WCSXFRM@ HAVE_WCTRANS_T = @HAVE_WCTRANS_T@ HAVE_WCTYPE_H = @HAVE_WCTYPE_H@ HAVE_WCTYPE_T = @HAVE_WCTYPE_T@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_WINT_T = @HAVE_WINT_T@ HAVE_WMEMCHR = @HAVE_WMEMCHR@ HAVE_WMEMCMP = @HAVE_WMEMCMP@ HAVE_WMEMCPY = @HAVE_WMEMCPY@ HAVE_WMEMMOVE = @HAVE_WMEMMOVE@ HAVE_WMEMPCPY = @HAVE_WMEMPCPY@ HAVE_WMEMSET = @HAVE_WMEMSET@ HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@ HAVE_XLOCALE_H = @HAVE_XLOCALE_H@ HAVE__BOOL = @HAVE__BOOL@ HAVE__EXIT = @HAVE__EXIT@ ICONV_CONST = @ICONV_CONST@ ICONV_H = @ICONV_H@ INCLUDE_NEXT = @INCLUDE_NEXT@ INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@ INET_PTON_LIB = @INET_PTON_LIB@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@ INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@ INTLLIBS = @INTLLIBS@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@ LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBMULTITHREAD = @LIBMULTITHREAD@ LIBOBJS = @LIBOBJS@ LIBPMULTITHREAD = @LIBPMULTITHREAD@ LIBPTHREAD = @LIBPTHREAD@ LIBS = @LIBS@ LIBSOCKET = @LIBSOCKET@ LIBSTDTHREAD = @LIBSTDTHREAD@ LIBTHREAD = @LIBTHREAD@ LIBTOOL = @LIBTOOL@ LIBUNISTRING_UNISTR_H = @LIBUNISTRING_UNISTR_H@ LIBUNISTRING_UNITYPES_H = @LIBUNISTRING_UNITYPES_H@ LIBUNISTRING_UNIWIDTH_H = @LIBUNISTRING_UNIWIDTH_H@ LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ LIB_CRYPTO = @LIB_CRYPTO@ LIB_GETLOGIN = @LIB_GETLOGIN@ LIB_HARD_LOCALE = @LIB_HARD_LOCALE@ LIB_MBRTOWC = @LIB_MBRTOWC@ LIB_NL_LANGINFO = @LIB_NL_LANGINFO@ LIB_POLL = @LIB_POLL@ LIB_SCHED_YIELD = @LIB_SCHED_YIELD@ LIB_SELECT = @LIB_SELECT@ LIB_SETLOCALE_NULL = @LIB_SETLOCALE_NULL@ LIMITS_H = @LIMITS_H@ LIPO = @LIPO@ LN_S = @LN_S@ LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@ LOCALE_FR = @LOCALE_FR@ LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@ LOCALE_JA = @LOCALE_JA@ LOCALE_ZH_CN = @LOCALE_ZH_CN@ LTALLOCA = @LTALLOCA@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ LTLIBOBJS = @LTLIBOBJS@ LTLIBTHREAD = @LTLIBTHREAD@ LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ MSGMERGE = @MSGMERGE@ MSGMERGE_FOR_MSGFMT_OPTION = @MSGMERGE_FOR_MSGFMT_OPTION@ NETINET_IN_H = @NETINET_IN_H@ NEXT_ARPA_INET_H = @NEXT_ARPA_INET_H@ NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H = @NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H@ NEXT_AS_FIRST_DIRECTIVE_CTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_CTYPE_H@ NEXT_AS_FIRST_DIRECTIVE_DIRENT_H = @NEXT_AS_FIRST_DIRECTIVE_DIRENT_H@ NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@ NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@ NEXT_AS_FIRST_DIRECTIVE_FLOAT_H = @NEXT_AS_FIRST_DIRECTIVE_FLOAT_H@ NEXT_AS_FIRST_DIRECTIVE_FNMATCH_H = @NEXT_AS_FIRST_DIRECTIVE_FNMATCH_H@ NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@ NEXT_AS_FIRST_DIRECTIVE_GLOB_H = @NEXT_AS_FIRST_DIRECTIVE_GLOB_H@ NEXT_AS_FIRST_DIRECTIVE_ICONV_H = @NEXT_AS_FIRST_DIRECTIVE_ICONV_H@ NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H@ NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@ NEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@ NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@ NEXT_AS_FIRST_DIRECTIVE_MATH_H = @NEXT_AS_FIRST_DIRECTIVE_MATH_H@ NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H = @NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H@ NEXT_AS_FIRST_DIRECTIVE_POLL_H = @NEXT_AS_FIRST_DIRECTIVE_POLL_H@ NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H = @NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H@ NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@ NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@ NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@ NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@ NEXT_AS_FIRST_DIRECTIVE_STRINGS_H = @NEXT_AS_FIRST_DIRECTIVE_STRINGS_H@ NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@ NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H@ NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@ NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@ NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@ NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@ NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@ NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@ NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@ NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@ NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@ NEXT_CTYPE_H = @NEXT_CTYPE_H@ NEXT_DIRENT_H = @NEXT_DIRENT_H@ NEXT_ERRNO_H = @NEXT_ERRNO_H@ NEXT_FCNTL_H = @NEXT_FCNTL_H@ NEXT_FLOAT_H = @NEXT_FLOAT_H@ NEXT_FNMATCH_H = @NEXT_FNMATCH_H@ NEXT_GETOPT_H = @NEXT_GETOPT_H@ NEXT_GLOB_H = @NEXT_GLOB_H@ NEXT_ICONV_H = @NEXT_ICONV_H@ NEXT_INTTYPES_H = @NEXT_INTTYPES_H@ NEXT_LANGINFO_H = @NEXT_LANGINFO_H@ NEXT_LIMITS_H = @NEXT_LIMITS_H@ NEXT_LOCALE_H = @NEXT_LOCALE_H@ NEXT_MATH_H = @NEXT_MATH_H@ NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@ NEXT_POLL_H = @NEXT_POLL_H@ NEXT_SIGNAL_H = @NEXT_SIGNAL_H@ NEXT_STDDEF_H = @NEXT_STDDEF_H@ NEXT_STDINT_H = @NEXT_STDINT_H@ NEXT_STDIO_H = @NEXT_STDIO_H@ NEXT_STDLIB_H = @NEXT_STDLIB_H@ NEXT_STRINGS_H = @NEXT_STRINGS_H@ NEXT_STRING_H = @NEXT_STRING_H@ NEXT_SYS_SELECT_H = @NEXT_SYS_SELECT_H@ NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@ NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@ NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@ NEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@ NEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@ NEXT_TIME_H = @NEXT_TIME_H@ NEXT_UNISTD_H = @NEXT_UNISTD_H@ NEXT_WCHAR_H = @NEXT_WCHAR_H@ NEXT_WCTYPE_H = @NEXT_WCTYPE_H@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OPENSSL_CPPFLAGS = @OPENSSL_CPPFLAGS@ OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@ OPENSSL_LIBS = @OPENSSL_LIBS@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PARSE_DATETIME_BISON = @PARSE_DATETIME_BISON@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POSUB = @POSUB@ PRAGMA_COLUMNS = @PRAGMA_COLUMNS@ PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@ PRIPTR_PREFIX = @PRIPTR_PREFIX@ PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@ PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@ RANLIB = @RANLIB@ READLINE_CFLAGS = @READLINE_CFLAGS@ READLINE_LDFLAGS = @READLINE_LDFLAGS@ READLINE_LIBS = @READLINE_LIBS@ READLINE_VERSION = @READLINE_VERSION@ REPLACE_ACCESS = @REPLACE_ACCESS@ REPLACE_ACOSF = @REPLACE_ACOSF@ REPLACE_ASINF = @REPLACE_ASINF@ REPLACE_ATAN2F = @REPLACE_ATAN2F@ REPLACE_ATANF = @REPLACE_ATANF@ REPLACE_BTOWC = @REPLACE_BTOWC@ REPLACE_CALLOC = @REPLACE_CALLOC@ REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@ REPLACE_CBRTF = @REPLACE_CBRTF@ REPLACE_CBRTL = @REPLACE_CBRTL@ REPLACE_CEIL = @REPLACE_CEIL@ REPLACE_CEILF = @REPLACE_CEILF@ REPLACE_CEILL = @REPLACE_CEILL@ REPLACE_CHOWN = @REPLACE_CHOWN@ REPLACE_CLOSE = @REPLACE_CLOSE@ REPLACE_CLOSEDIR = @REPLACE_CLOSEDIR@ REPLACE_COSF = @REPLACE_COSF@ REPLACE_COSHF = @REPLACE_COSHF@ REPLACE_CREAT = @REPLACE_CREAT@ REPLACE_CTIME = @REPLACE_CTIME@ REPLACE_DIRFD = @REPLACE_DIRFD@ REPLACE_DPRINTF = @REPLACE_DPRINTF@ REPLACE_DUP = @REPLACE_DUP@ REPLACE_DUP2 = @REPLACE_DUP2@ REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@ REPLACE_EXP2 = @REPLACE_EXP2@ REPLACE_EXP2L = @REPLACE_EXP2L@ REPLACE_EXPF = @REPLACE_EXPF@ REPLACE_EXPL = @REPLACE_EXPL@ REPLACE_EXPM1 = @REPLACE_EXPM1@ REPLACE_EXPM1F = @REPLACE_EXPM1F@ REPLACE_EXPM1L = @REPLACE_EXPM1L@ REPLACE_FABSL = @REPLACE_FABSL@ REPLACE_FACCESSAT = @REPLACE_FACCESSAT@ REPLACE_FCHMODAT = @REPLACE_FCHMODAT@ REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@ REPLACE_FCLOSE = @REPLACE_FCLOSE@ REPLACE_FCNTL = @REPLACE_FCNTL@ REPLACE_FDOPEN = @REPLACE_FDOPEN@ REPLACE_FDOPENDIR = @REPLACE_FDOPENDIR@ REPLACE_FFLUSH = @REPLACE_FFLUSH@ REPLACE_FLOOR = @REPLACE_FLOOR@ REPLACE_FLOORF = @REPLACE_FLOORF@ REPLACE_FLOORL = @REPLACE_FLOORL@ REPLACE_FMA = @REPLACE_FMA@ REPLACE_FMAF = @REPLACE_FMAF@ REPLACE_FMAL = @REPLACE_FMAL@ REPLACE_FMOD = @REPLACE_FMOD@ REPLACE_FMODF = @REPLACE_FMODF@ REPLACE_FMODL = @REPLACE_FMODL@ REPLACE_FNMATCH = @REPLACE_FNMATCH@ REPLACE_FOPEN = @REPLACE_FOPEN@ REPLACE_FPRINTF = @REPLACE_FPRINTF@ REPLACE_FPURGE = @REPLACE_FPURGE@ REPLACE_FREELOCALE = @REPLACE_FREELOCALE@ REPLACE_FREOPEN = @REPLACE_FREOPEN@ REPLACE_FREXP = @REPLACE_FREXP@ REPLACE_FREXPF = @REPLACE_FREXPF@ REPLACE_FREXPL = @REPLACE_FREXPL@ REPLACE_FSEEK = @REPLACE_FSEEK@ REPLACE_FSEEKO = @REPLACE_FSEEKO@ REPLACE_FSTAT = @REPLACE_FSTAT@ REPLACE_FSTATAT = @REPLACE_FSTATAT@ REPLACE_FTELL = @REPLACE_FTELL@ REPLACE_FTELLO = @REPLACE_FTELLO@ REPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@ REPLACE_FUTIMENS = @REPLACE_FUTIMENS@ REPLACE_GETCWD = @REPLACE_GETCWD@ REPLACE_GETDELIM = @REPLACE_GETDELIM@ REPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@ REPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@ REPLACE_GETGROUPS = @REPLACE_GETGROUPS@ REPLACE_GETLINE = @REPLACE_GETLINE@ REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@ REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@ REPLACE_GETPASS = @REPLACE_GETPASS@ REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@ REPLACE_GLOB = @REPLACE_GLOB@ REPLACE_GLOB_PATTERN_P = @REPLACE_GLOB_PATTERN_P@ REPLACE_GMTIME = @REPLACE_GMTIME@ REPLACE_HUGE_VAL = @REPLACE_HUGE_VAL@ REPLACE_HYPOT = @REPLACE_HYPOT@ REPLACE_HYPOTF = @REPLACE_HYPOTF@ REPLACE_HYPOTL = @REPLACE_HYPOTL@ REPLACE_ICONV = @REPLACE_ICONV@ REPLACE_ICONV_OPEN = @REPLACE_ICONV_OPEN@ REPLACE_ICONV_UTF = @REPLACE_ICONV_UTF@ REPLACE_ILOGB = @REPLACE_ILOGB@ REPLACE_ILOGBF = @REPLACE_ILOGBF@ REPLACE_ILOGBL = @REPLACE_ILOGBL@ REPLACE_INET_NTOP = @REPLACE_INET_NTOP@ REPLACE_INET_PTON = @REPLACE_INET_PTON@ REPLACE_INITSTATE = @REPLACE_INITSTATE@ REPLACE_ISATTY = @REPLACE_ISATTY@ REPLACE_ISFINITE = @REPLACE_ISFINITE@ REPLACE_ISINF = @REPLACE_ISINF@ REPLACE_ISNAN = @REPLACE_ISNAN@ REPLACE_ISWBLANK = @REPLACE_ISWBLANK@ REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@ REPLACE_ISWDIGIT = @REPLACE_ISWDIGIT@ REPLACE_ISWXDIGIT = @REPLACE_ISWXDIGIT@ REPLACE_ITOLD = @REPLACE_ITOLD@ REPLACE_LCHOWN = @REPLACE_LCHOWN@ REPLACE_LDEXPL = @REPLACE_LDEXPL@ REPLACE_LINK = @REPLACE_LINK@ REPLACE_LINKAT = @REPLACE_LINKAT@ REPLACE_LOCALECONV = @REPLACE_LOCALECONV@ REPLACE_LOCALTIME = @REPLACE_LOCALTIME@ REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@ REPLACE_LOG = @REPLACE_LOG@ REPLACE_LOG10 = @REPLACE_LOG10@ REPLACE_LOG10F = @REPLACE_LOG10F@ REPLACE_LOG10L = @REPLACE_LOG10L@ REPLACE_LOG1P = @REPLACE_LOG1P@ REPLACE_LOG1PF = @REPLACE_LOG1PF@ REPLACE_LOG1PL = @REPLACE_LOG1PL@ REPLACE_LOG2 = @REPLACE_LOG2@ REPLACE_LOG2F = @REPLACE_LOG2F@ REPLACE_LOG2L = @REPLACE_LOG2L@ REPLACE_LOGB = @REPLACE_LOGB@ REPLACE_LOGBF = @REPLACE_LOGBF@ REPLACE_LOGBL = @REPLACE_LOGBL@ REPLACE_LOGF = @REPLACE_LOGF@ REPLACE_LOGL = @REPLACE_LOGL@ REPLACE_LSEEK = @REPLACE_LSEEK@ REPLACE_LSTAT = @REPLACE_LSTAT@ REPLACE_MALLOC = @REPLACE_MALLOC@ REPLACE_MBRLEN = @REPLACE_MBRLEN@ REPLACE_MBRTOWC = @REPLACE_MBRTOWC@ REPLACE_MBSINIT = @REPLACE_MBSINIT@ REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@ REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@ REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@ REPLACE_MBTOWC = @REPLACE_MBTOWC@ REPLACE_MEMCHR = @REPLACE_MEMCHR@ REPLACE_MEMMEM = @REPLACE_MEMMEM@ REPLACE_MKDIR = @REPLACE_MKDIR@ REPLACE_MKFIFO = @REPLACE_MKFIFO@ REPLACE_MKNOD = @REPLACE_MKNOD@ REPLACE_MKSTEMP = @REPLACE_MKSTEMP@ REPLACE_MKTIME = @REPLACE_MKTIME@ REPLACE_MODF = @REPLACE_MODF@ REPLACE_MODFF = @REPLACE_MODFF@ REPLACE_MODFL = @REPLACE_MODFL@ REPLACE_NAN = @REPLACE_NAN@ REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@ REPLACE_NEWLOCALE = @REPLACE_NEWLOCALE@ REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@ REPLACE_NULL = @REPLACE_NULL@ REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@ REPLACE_OPEN = @REPLACE_OPEN@ REPLACE_OPENAT = @REPLACE_OPENAT@ REPLACE_OPENDIR = @REPLACE_OPENDIR@ REPLACE_PERROR = @REPLACE_PERROR@ REPLACE_POLL = @REPLACE_POLL@ REPLACE_POPEN = @REPLACE_POPEN@ REPLACE_PREAD = @REPLACE_PREAD@ REPLACE_PRINTF = @REPLACE_PRINTF@ REPLACE_PSELECT = @REPLACE_PSELECT@ REPLACE_PTHREAD_SIGMASK = @REPLACE_PTHREAD_SIGMASK@ REPLACE_PTSNAME = @REPLACE_PTSNAME@ REPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@ REPLACE_PUTENV = @REPLACE_PUTENV@ REPLACE_PWRITE = @REPLACE_PWRITE@ REPLACE_QSORT_R = @REPLACE_QSORT_R@ REPLACE_RAISE = @REPLACE_RAISE@ REPLACE_RANDOM = @REPLACE_RANDOM@ REPLACE_RANDOM_R = @REPLACE_RANDOM_R@ REPLACE_READ = @REPLACE_READ@ REPLACE_READLINK = @REPLACE_READLINK@ REPLACE_READLINKAT = @REPLACE_READLINKAT@ REPLACE_REALLOC = @REPLACE_REALLOC@ REPLACE_REALPATH = @REPLACE_REALPATH@ REPLACE_REMAINDER = @REPLACE_REMAINDER@ REPLACE_REMAINDERF = @REPLACE_REMAINDERF@ REPLACE_REMAINDERL = @REPLACE_REMAINDERL@ REPLACE_REMOVE = @REPLACE_REMOVE@ REPLACE_RENAME = @REPLACE_RENAME@ REPLACE_RENAMEAT = @REPLACE_RENAMEAT@ REPLACE_RINTL = @REPLACE_RINTL@ REPLACE_RMDIR = @REPLACE_RMDIR@ REPLACE_ROUND = @REPLACE_ROUND@ REPLACE_ROUNDF = @REPLACE_ROUNDF@ REPLACE_ROUNDL = @REPLACE_ROUNDL@ REPLACE_SELECT = @REPLACE_SELECT@ REPLACE_SETENV = @REPLACE_SETENV@ REPLACE_SETLOCALE = @REPLACE_SETLOCALE@ REPLACE_SETSTATE = @REPLACE_SETSTATE@ REPLACE_SIGNBIT = @REPLACE_SIGNBIT@ REPLACE_SIGNBIT_USING_BUILTINS = @REPLACE_SIGNBIT_USING_BUILTINS@ REPLACE_SINF = @REPLACE_SINF@ REPLACE_SINHF = @REPLACE_SINHF@ REPLACE_SLEEP = @REPLACE_SLEEP@ REPLACE_SNPRINTF = @REPLACE_SNPRINTF@ REPLACE_SPRINTF = @REPLACE_SPRINTF@ REPLACE_SQRTF = @REPLACE_SQRTF@ REPLACE_SQRTL = @REPLACE_SQRTL@ REPLACE_STAT = @REPLACE_STAT@ REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@ REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@ REPLACE_STPNCPY = @REPLACE_STPNCPY@ REPLACE_STRCASESTR = @REPLACE_STRCASESTR@ REPLACE_STRCHRNUL = @REPLACE_STRCHRNUL@ REPLACE_STRDUP = @REPLACE_STRDUP@ REPLACE_STRERROR = @REPLACE_STRERROR@ REPLACE_STRERROR_R = @REPLACE_STRERROR_R@ REPLACE_STRFTIME = @REPLACE_STRFTIME@ REPLACE_STRNCAT = @REPLACE_STRNCAT@ REPLACE_STRNDUP = @REPLACE_STRNDUP@ REPLACE_STRNLEN = @REPLACE_STRNLEN@ REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@ REPLACE_STRSTR = @REPLACE_STRSTR@ REPLACE_STRTOD = @REPLACE_STRTOD@ REPLACE_STRTOIMAX = @REPLACE_STRTOIMAX@ REPLACE_STRTOK_R = @REPLACE_STRTOK_R@ REPLACE_STRTOLD = @REPLACE_STRTOLD@ REPLACE_STRTOUMAX = @REPLACE_STRTOUMAX@ REPLACE_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@ REPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@ REPLACE_SYMLINK = @REPLACE_SYMLINK@ REPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@ REPLACE_TANF = @REPLACE_TANF@ REPLACE_TANHF = @REPLACE_TANHF@ REPLACE_TIMEGM = @REPLACE_TIMEGM@ REPLACE_TMPFILE = @REPLACE_TMPFILE@ REPLACE_TOWLOWER = @REPLACE_TOWLOWER@ REPLACE_TRUNC = @REPLACE_TRUNC@ REPLACE_TRUNCATE = @REPLACE_TRUNCATE@ REPLACE_TRUNCF = @REPLACE_TRUNCF@ REPLACE_TRUNCL = @REPLACE_TRUNCL@ REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@ REPLACE_TZSET = @REPLACE_TZSET@ REPLACE_UNLINK = @REPLACE_UNLINK@ REPLACE_UNLINKAT = @REPLACE_UNLINKAT@ REPLACE_UNSETENV = @REPLACE_UNSETENV@ REPLACE_USLEEP = @REPLACE_USLEEP@ REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@ REPLACE_VASPRINTF = @REPLACE_VASPRINTF@ REPLACE_VDPRINTF = @REPLACE_VDPRINTF@ REPLACE_VFPRINTF = @REPLACE_VFPRINTF@ REPLACE_VPRINTF = @REPLACE_VPRINTF@ REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@ REPLACE_VSPRINTF = @REPLACE_VSPRINTF@ REPLACE_WCRTOMB = @REPLACE_WCRTOMB@ REPLACE_WCSFTIME = @REPLACE_WCSFTIME@ REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@ REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@ REPLACE_WCSTOK = @REPLACE_WCSTOK@ REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@ REPLACE_WCTOB = @REPLACE_WCTOB@ REPLACE_WCTOMB = @REPLACE_WCTOMB@ REPLACE_WCWIDTH = @REPLACE_WCWIDTH@ REPLACE_WRITE = @REPLACE_WRITE@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@ SIZE_T_SUFFIX = @SIZE_T_SUFFIX@ SOCKSLIBS = @SOCKSLIBS@ STDALIGN_H = @STDALIGN_H@ STDBOOL_H = @STDBOOL_H@ STDDEF_H = @STDDEF_H@ STDINT_H = @STDINT_H@ STRIP = @STRIP@ SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@ TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@ UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@ UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@ UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@ UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@ UNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@ UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@ UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@ WINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@ WINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@ WINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@ WINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@ WINT_T_SUFFIX = @WINT_T_SUFFIX@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ YACC = @YACC@ YFLAGS = @YFLAGS@ ZLIB = @ZLIB@ ZLIB_CPPFLAGS = @ZLIB_CPPFLAGS@ ZLIB_LDFLAGS = @ZLIB_LDFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ gl_LIBOBJS = @gl_LIBOBJS@ gl_LTLIBOBJS = @gl_LTLIBOBJS@ gltests_LIBOBJS = @gltests_LIBOBJS@ gltests_LTLIBOBJS = @gltests_LTLIBOBJS@ gltests_WITNESS = @gltests_WITNESS@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ lispdir = @lispdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ pkgverlibdir = $(pkglibdir)/$(VERSION) bin_SCRIPTS = lftpget pkgdata_SCRIPTS = import-ncftp import-netscape verify-file convert-mozilla-cookies xdg-move noinst_SCRIPTS = ftpget EXTRA_DIST = $(pkgdata_SCRIPTS) $(bin_SCRIPTS) $(noinst_SCRIPTS) lftp_SOURCES = lftp.cc complete.h complete.cc lftp_rl.c lftp_rl.h attach.cc attach.h TASK_MODULES = liblftp-pty.la liblftp-network.la proto-ftp.la proto-http.la proto-file.la proto-fish.la proto-sftp.la JOB_MODULES = cmd-mirror.la cmd-sleep.la cmd-torrent.la @WITH_MODULES_TRUE@pkgverlib_LTLIBRARIES = $(TASK_MODULES) $(JOB_MODULES) @WITH_MODULES_FALSE@TASK_MODULES_STATIC = $(TASK_MODULES) @WITH_MODULES_FALSE@JOB_MODULES_STATIC = $(JOB_MODULES) lib_LTLIBRARIES = liblftp-tasks.la liblftp-jobs.la proto_ftp_la_SOURCES = ftpclass.cc ftpclass.h FtpListInfo.cc FtpListInfo.h\ FtpDirList.cc FtpDirList.h ftp-opie.c netkey.c FileCopyFtp.cc FileCopyFtp.h proto_http_la_SOURCES = Http.cc Http.h HttpHeader.cc HttpHeader.h\ HttpAuth.cc HttpAuth.h HttpDir.cc HttpDir.h HttpDirXML.cc proto_file_la_SOURCES = LocalAccess.cc LocalAccess.h proto_fish_la_SOURCES = Fish.cc Fish.h proto_sftp_la_SOURCES = SFtp.cc SFtp.h cmd_mirror_la_SOURCES = MirrorJob.cc MirrorJob.h cmd_sleep_la_SOURCES = SleepJob.cc SleepJob.h cmd_torrent_la_SOURCES = Torrent.cc Torrent.h TorrentTracker.cc TorrentTracker.h\ DHT.cc DHT.h Bencode.cc Bencode.h liblftp_pty_la_SOURCES = PtyShell.cc PtyShell.h lftp_pty.c lftp_pty.h SSH_Access.cc SSH_Access.h liblftp_network_la_SOURCES = NetAccess.cc NetAccess.h Resolver.cc Resolver.h\ lftp_ssl.cc lftp_ssl.h buffer_ssl.cc buffer_ssl.h RateLimit.cc RateLimit.h\ network.cc network.h buffer_zlib.cc buffer_zlib.h @NEED_TRIO_TRUE@TRIO = $(top_builddir)/trio/libtrio.la GNULIB = $(top_builddir)/lib/libgnu.la proto_ftp_la_LDFLAGS = -module -avoid-version -rpath $(pkgverlibdir) proto_http_la_CPPFLAGS = $(AM_CPPFLAGS) $(EXPAT_CFLAGS) proto_http_la_LDFLAGS = -module -avoid-version -rpath $(pkgverlibdir) proto_file_la_LDFLAGS = -module -avoid-version -rpath $(pkgverlibdir) proto_fish_la_LDFLAGS = -module -avoid-version -rpath $(pkgverlibdir) proto_sftp_la_LDFLAGS = -module -avoid-version -rpath $(pkgverlibdir) cmd_mirror_la_LDFLAGS = -module -avoid-version -rpath $(pkgverlibdir) cmd_sleep_la_LDFLAGS = -module -avoid-version -rpath $(pkgverlibdir) cmd_torrent_la_LDFLAGS = -module -avoid-version -rpath $(pkgverlibdir) liblftp_pty_la_LDFLAGS = -avoid-version -rpath $(pkgverlibdir) liblftp_network_la_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_CPPFLAGS) $(ZLIB_CPPFLAGS) $(LIBGNUTLS_CFLAGS) liblftp_network_la_LDFLAGS = -avoid-version -rpath $(pkgverlibdir) liblftp_network_la_LIBADD = $(SOCKSLIBS) $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS) $(LIBGNUTLS_LIBS) $(LIBSOCKET) $(GNULIB) $(ZLIB_LDFLAGS) $(ZLIB) proto_ftp_la_LIBADD = liblftp-network.la proto_http_la_LIBADD = liblftp-network.la $(EXPAT_LDFLAGS) $(EXPAT_LIBS) proto_fish_la_LIBADD = liblftp-network.la liblftp-pty.la proto_sftp_la_LIBADD = liblftp-network.la liblftp-pty.la cmd_torrent_la_LIBADD = liblftp-network.la liblftp_tasks_la_SOURCES = PollVec.cc PollVec.h SMTask.cc SMTask.h ProcWait.cc\ ProcWait.h GetPass.cc GetPass.h ConnectionSlot.cc ConnectionSlot.h\ CharReader.cc CharReader.h Cache.cc Cache.h LsCache.cc LsCache.h\ FileAccess.h FileAccess.cc ResMgr.h ResMgr.cc Ref.h ProtoLog.cc ProtoLog.h\ Filter.cc Filter.h SignalHook.cc SignalHook.h FileCopy.cc FileCopy.h\ xmalloc.cc xmalloc.h xstring.cc xstring.h FileSet.cc FileSet.h\ log.h log.cc StringSet.cc StringSet.h xarray.cc xarray.h xmap.cc xmap.h\ buffer.cc buffer.h url.cc url.h StatusLine.cc StatusLine.h plural.c plural.h\ misc.h misc.cc fg.cc fg.h module.cc module.h modconfig.h\ resource.cc DummyProto.cc DummyProto.h Error.cc Error.h\ ArgV.cc ArgV.h ascii_ctype.h keyvalue.cc keyvalue.h bookmark.cc bookmark.h\ Speedometer.cc FileGlob.cc FileGlob.h xlist.h xheap.h\ Speedometer.h netrc.cc netrc.h lftp_tinfo.cc lftp_tinfo.h\ TimeDate.cc TimeDate.h Timer.cc Timer.h GetFileInfo.cc GetFileInfo.h\ StringPool.cc StringPool.h DirColors.cc DirColors.h IdNameCache.cc\ IdNameCache.h PatternSet.cc PatternSet.h LocalDir.cc LocalDir.h liblftp_tasks_la_LIBADD = $(TASK_MODULES_STATIC) $(TRIO) $(GNULIB)\ $(LIB_CRYPTO) $(INET_PTON_LIB) $(LIB_CLOCK_GETTIME) $(SOCKSLIBS)\ $(LIB_POLL) $(LIB_SELECT) $(LTLIBINTL) $(LTLIBICONV) liblftp_jobs_la_SOURCES = Job.cc Job.h CmdExec.cc CmdExec.h\ commands.cc mgetJob.h mgetJob.cc SysCmdJob.cc SysCmdJob.h rmJob.cc rmJob.h\ parsecmd.cc mvJob.cc mvJob.h mmvJob.cc mmvJob.h alias.cc alias.h\ CatJob.cc CatJob.h EditJob.cc EditJob.h GetJob.cc GetJob.h\ ColumnOutput.h ColumnOutput.cc FileSetOutput.h FileSetOutput.cc\ mkdirJob.cc mkdirJob.h pgetJob.cc pgetJob.h FileFeeder.cc FileFeeder.h\ QueueFeeder.cc QueueFeeder.h History.cc History.h\ FindJob.cc FindJob.h FindJobDu.cc FindJobDu.h ChmodJob.cc ChmodJob.h\ TreatFileJob.cc TreatFileJob.h CopyJob.cc CopyJob.h echoJob.cc echoJob.h\ OutputJob.cc OutputJob.h FileCopyOutputJob.cc FileCopyOutputJob.h\ buffer_std.cc buffer_std.h liblftp_jobs_la_LIBADD = $(JOB_MODULES_STATIC) liblftp-tasks.la lftp_CPPFLAGS = $(AM_CPPFLAGS) $(READLINE_CFLAGS) lftp_LDFLAGS = -export-dynamic lftp_LDADD = liblftp-jobs.la liblftp-tasks.la $(READLINE_LDFLAGS) $(READLINE_LIBS) lftp_DEPENDENCIES = liblftp-jobs.la CLEANFILES = *.la AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_srcdir)/trio all: all-am .SUFFIXES: .SUFFIXES: .c .cc .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } install-pkgverlibLTLIBRARIES: $(pkgverlib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(pkgverlib_LTLIBRARIES)'; test -n "$(pkgverlibdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgverlibdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgverlibdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkgverlibdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkgverlibdir)"; \ } uninstall-pkgverlibLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(pkgverlib_LTLIBRARIES)'; test -n "$(pkgverlibdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkgverlibdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkgverlibdir)/$$f"; \ done clean-pkgverlibLTLIBRARIES: -test -z "$(pkgverlib_LTLIBRARIES)" || rm -f $(pkgverlib_LTLIBRARIES) @list='$(pkgverlib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } cmd-mirror.la: $(cmd_mirror_la_OBJECTS) $(cmd_mirror_la_DEPENDENCIES) $(EXTRA_cmd_mirror_la_DEPENDENCIES) $(AM_V_CXXLD)$(cmd_mirror_la_LINK) $(am_cmd_mirror_la_rpath) $(cmd_mirror_la_OBJECTS) $(cmd_mirror_la_LIBADD) $(LIBS) cmd-sleep.la: $(cmd_sleep_la_OBJECTS) $(cmd_sleep_la_DEPENDENCIES) $(EXTRA_cmd_sleep_la_DEPENDENCIES) $(AM_V_CXXLD)$(cmd_sleep_la_LINK) $(am_cmd_sleep_la_rpath) $(cmd_sleep_la_OBJECTS) $(cmd_sleep_la_LIBADD) $(LIBS) cmd-torrent.la: $(cmd_torrent_la_OBJECTS) $(cmd_torrent_la_DEPENDENCIES) $(EXTRA_cmd_torrent_la_DEPENDENCIES) $(AM_V_CXXLD)$(cmd_torrent_la_LINK) $(am_cmd_torrent_la_rpath) $(cmd_torrent_la_OBJECTS) $(cmd_torrent_la_LIBADD) $(LIBS) liblftp-jobs.la: $(liblftp_jobs_la_OBJECTS) $(liblftp_jobs_la_DEPENDENCIES) $(EXTRA_liblftp_jobs_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) -rpath $(libdir) $(liblftp_jobs_la_OBJECTS) $(liblftp_jobs_la_LIBADD) $(LIBS) liblftp-network.la: $(liblftp_network_la_OBJECTS) $(liblftp_network_la_DEPENDENCIES) $(EXTRA_liblftp_network_la_DEPENDENCIES) $(AM_V_CXXLD)$(liblftp_network_la_LINK) $(am_liblftp_network_la_rpath) $(liblftp_network_la_OBJECTS) $(liblftp_network_la_LIBADD) $(LIBS) liblftp-pty.la: $(liblftp_pty_la_OBJECTS) $(liblftp_pty_la_DEPENDENCIES) $(EXTRA_liblftp_pty_la_DEPENDENCIES) $(AM_V_CXXLD)$(liblftp_pty_la_LINK) $(am_liblftp_pty_la_rpath) $(liblftp_pty_la_OBJECTS) $(liblftp_pty_la_LIBADD) $(LIBS) liblftp-tasks.la: $(liblftp_tasks_la_OBJECTS) $(liblftp_tasks_la_DEPENDENCIES) $(EXTRA_liblftp_tasks_la_DEPENDENCIES) $(AM_V_CXXLD)$(CXXLINK) -rpath $(libdir) $(liblftp_tasks_la_OBJECTS) $(liblftp_tasks_la_LIBADD) $(LIBS) proto-file.la: $(proto_file_la_OBJECTS) $(proto_file_la_DEPENDENCIES) $(EXTRA_proto_file_la_DEPENDENCIES) $(AM_V_CXXLD)$(proto_file_la_LINK) $(am_proto_file_la_rpath) $(proto_file_la_OBJECTS) $(proto_file_la_LIBADD) $(LIBS) proto-fish.la: $(proto_fish_la_OBJECTS) $(proto_fish_la_DEPENDENCIES) $(EXTRA_proto_fish_la_DEPENDENCIES) $(AM_V_CXXLD)$(proto_fish_la_LINK) $(am_proto_fish_la_rpath) $(proto_fish_la_OBJECTS) $(proto_fish_la_LIBADD) $(LIBS) proto-ftp.la: $(proto_ftp_la_OBJECTS) $(proto_ftp_la_DEPENDENCIES) $(EXTRA_proto_ftp_la_DEPENDENCIES) $(AM_V_CXXLD)$(proto_ftp_la_LINK) $(am_proto_ftp_la_rpath) $(proto_ftp_la_OBJECTS) $(proto_ftp_la_LIBADD) $(LIBS) proto-http.la: $(proto_http_la_OBJECTS) $(proto_http_la_DEPENDENCIES) $(EXTRA_proto_http_la_DEPENDENCIES) $(AM_V_CXXLD)$(proto_http_la_LINK) $(am_proto_http_la_rpath) $(proto_http_la_OBJECTS) $(proto_http_la_LIBADD) $(LIBS) proto-sftp.la: $(proto_sftp_la_OBJECTS) $(proto_sftp_la_DEPENDENCIES) $(EXTRA_proto_sftp_la_DEPENDENCIES) $(AM_V_CXXLD)$(proto_sftp_la_LINK) $(am_proto_sftp_la_rpath) $(proto_sftp_la_OBJECTS) $(proto_sftp_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list lftp$(EXEEXT): $(lftp_OBJECTS) $(lftp_DEPENDENCIES) $(EXTRA_lftp_DEPENDENCIES) @rm -f lftp$(EXEEXT) $(AM_V_CXXLD)$(lftp_LINK) $(lftp_OBJECTS) $(lftp_LDADD) $(LIBS) install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) install-pkgdataSCRIPTS: $(pkgdata_SCRIPTS) @$(NORMAL_INSTALL) @list='$(pkgdata_SCRIPTS)'; test -n "$(pkgdatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pkgdatadir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pkgdatadir)$$dir" || exit $$?; \ } \ ; done uninstall-pkgdataSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(pkgdata_SCRIPTS)'; test -n "$(pkgdatadir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ArgV.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Bencode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Cache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CatJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CharReader.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChmodJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CmdExec.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ColumnOutput.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConnectionSlot.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CopyJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHT.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DirColors.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DummyProto.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EditJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Error.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileAccess.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileCopy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileCopyFtp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileCopyOutputJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileFeeder.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileGlob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileSet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileSetOutput.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Filter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FindJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FindJobDu.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Fish.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpDirList.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpListInfo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GetFileInfo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GetJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GetPass.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/History.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IdNameCache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LocalAccess.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LocalDir.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LsCache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MirrorJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OutputJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PatternSet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PollVec.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ProcWait.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ProtoLog.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PtyShell.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QueueFeeder.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ResMgr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SFtp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SMTask.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SSH_Access.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SignalHook.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SleepJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Speedometer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StatusLine.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StringPool.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StringSet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SysCmdJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeDate.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Timer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Torrent.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentTracker.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TreatFileJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alias.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bookmark.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer_std.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commands.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/echoJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ftp-opie.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ftpclass.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keyvalue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lftp-attach.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lftp-complete.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lftp-lftp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lftp-lftp_rl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lftp_pty.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lftp_tinfo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblftp_network_la-NetAccess.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblftp_network_la-RateLimit.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblftp_network_la-Resolver.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblftp_network_la-buffer_ssl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblftp_network_la-buffer_zlib.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblftp_network_la-lftp_ssl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblftp_network_la-network.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mgetJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkdirJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmvJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/module.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mvJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netkey.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netrc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parsecmd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pgetJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plural.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto_http_la-Http.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto_http_la-HttpAuth.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto_http_la-HttpDir.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto_http_la-HttpDirXML.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto_http_la-HttpHeader.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resource.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rmJob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xarray.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmalloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xstring.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< lftp-lftp_rl.o: lftp_rl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lftp-lftp_rl.o -MD -MP -MF $(DEPDIR)/lftp-lftp_rl.Tpo -c -o lftp-lftp_rl.o `test -f 'lftp_rl.c' || echo '$(srcdir)/'`lftp_rl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lftp-lftp_rl.Tpo $(DEPDIR)/lftp-lftp_rl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lftp_rl.c' object='lftp-lftp_rl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lftp-lftp_rl.o `test -f 'lftp_rl.c' || echo '$(srcdir)/'`lftp_rl.c lftp-lftp_rl.obj: lftp_rl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lftp-lftp_rl.obj -MD -MP -MF $(DEPDIR)/lftp-lftp_rl.Tpo -c -o lftp-lftp_rl.obj `if test -f 'lftp_rl.c'; then $(CYGPATH_W) 'lftp_rl.c'; else $(CYGPATH_W) '$(srcdir)/lftp_rl.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lftp-lftp_rl.Tpo $(DEPDIR)/lftp-lftp_rl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lftp_rl.c' object='lftp-lftp_rl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lftp-lftp_rl.obj `if test -f 'lftp_rl.c'; then $(CYGPATH_W) 'lftp_rl.c'; else $(CYGPATH_W) '$(srcdir)/lftp_rl.c'; fi` .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.lo: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< liblftp_network_la-NetAccess.lo: NetAccess.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liblftp_network_la-NetAccess.lo -MD -MP -MF $(DEPDIR)/liblftp_network_la-NetAccess.Tpo -c -o liblftp_network_la-NetAccess.lo `test -f 'NetAccess.cc' || echo '$(srcdir)/'`NetAccess.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblftp_network_la-NetAccess.Tpo $(DEPDIR)/liblftp_network_la-NetAccess.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='NetAccess.cc' object='liblftp_network_la-NetAccess.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liblftp_network_la-NetAccess.lo `test -f 'NetAccess.cc' || echo '$(srcdir)/'`NetAccess.cc liblftp_network_la-Resolver.lo: Resolver.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liblftp_network_la-Resolver.lo -MD -MP -MF $(DEPDIR)/liblftp_network_la-Resolver.Tpo -c -o liblftp_network_la-Resolver.lo `test -f 'Resolver.cc' || echo '$(srcdir)/'`Resolver.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblftp_network_la-Resolver.Tpo $(DEPDIR)/liblftp_network_la-Resolver.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='Resolver.cc' object='liblftp_network_la-Resolver.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liblftp_network_la-Resolver.lo `test -f 'Resolver.cc' || echo '$(srcdir)/'`Resolver.cc liblftp_network_la-lftp_ssl.lo: lftp_ssl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liblftp_network_la-lftp_ssl.lo -MD -MP -MF $(DEPDIR)/liblftp_network_la-lftp_ssl.Tpo -c -o liblftp_network_la-lftp_ssl.lo `test -f 'lftp_ssl.cc' || echo '$(srcdir)/'`lftp_ssl.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblftp_network_la-lftp_ssl.Tpo $(DEPDIR)/liblftp_network_la-lftp_ssl.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='lftp_ssl.cc' object='liblftp_network_la-lftp_ssl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liblftp_network_la-lftp_ssl.lo `test -f 'lftp_ssl.cc' || echo '$(srcdir)/'`lftp_ssl.cc liblftp_network_la-buffer_ssl.lo: buffer_ssl.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liblftp_network_la-buffer_ssl.lo -MD -MP -MF $(DEPDIR)/liblftp_network_la-buffer_ssl.Tpo -c -o liblftp_network_la-buffer_ssl.lo `test -f 'buffer_ssl.cc' || echo '$(srcdir)/'`buffer_ssl.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblftp_network_la-buffer_ssl.Tpo $(DEPDIR)/liblftp_network_la-buffer_ssl.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='buffer_ssl.cc' object='liblftp_network_la-buffer_ssl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liblftp_network_la-buffer_ssl.lo `test -f 'buffer_ssl.cc' || echo '$(srcdir)/'`buffer_ssl.cc liblftp_network_la-RateLimit.lo: RateLimit.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liblftp_network_la-RateLimit.lo -MD -MP -MF $(DEPDIR)/liblftp_network_la-RateLimit.Tpo -c -o liblftp_network_la-RateLimit.lo `test -f 'RateLimit.cc' || echo '$(srcdir)/'`RateLimit.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblftp_network_la-RateLimit.Tpo $(DEPDIR)/liblftp_network_la-RateLimit.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='RateLimit.cc' object='liblftp_network_la-RateLimit.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liblftp_network_la-RateLimit.lo `test -f 'RateLimit.cc' || echo '$(srcdir)/'`RateLimit.cc liblftp_network_la-network.lo: network.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liblftp_network_la-network.lo -MD -MP -MF $(DEPDIR)/liblftp_network_la-network.Tpo -c -o liblftp_network_la-network.lo `test -f 'network.cc' || echo '$(srcdir)/'`network.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblftp_network_la-network.Tpo $(DEPDIR)/liblftp_network_la-network.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='network.cc' object='liblftp_network_la-network.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liblftp_network_la-network.lo `test -f 'network.cc' || echo '$(srcdir)/'`network.cc liblftp_network_la-buffer_zlib.lo: buffer_zlib.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liblftp_network_la-buffer_zlib.lo -MD -MP -MF $(DEPDIR)/liblftp_network_la-buffer_zlib.Tpo -c -o liblftp_network_la-buffer_zlib.lo `test -f 'buffer_zlib.cc' || echo '$(srcdir)/'`buffer_zlib.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblftp_network_la-buffer_zlib.Tpo $(DEPDIR)/liblftp_network_la-buffer_zlib.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='buffer_zlib.cc' object='liblftp_network_la-buffer_zlib.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblftp_network_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liblftp_network_la-buffer_zlib.lo `test -f 'buffer_zlib.cc' || echo '$(srcdir)/'`buffer_zlib.cc proto_http_la-Http.lo: Http.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proto_http_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT proto_http_la-Http.lo -MD -MP -MF $(DEPDIR)/proto_http_la-Http.Tpo -c -o proto_http_la-Http.lo `test -f 'Http.cc' || echo '$(srcdir)/'`Http.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/proto_http_la-Http.Tpo $(DEPDIR)/proto_http_la-Http.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='Http.cc' object='proto_http_la-Http.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proto_http_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o proto_http_la-Http.lo `test -f 'Http.cc' || echo '$(srcdir)/'`Http.cc proto_http_la-HttpHeader.lo: HttpHeader.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proto_http_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT proto_http_la-HttpHeader.lo -MD -MP -MF $(DEPDIR)/proto_http_la-HttpHeader.Tpo -c -o proto_http_la-HttpHeader.lo `test -f 'HttpHeader.cc' || echo '$(srcdir)/'`HttpHeader.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/proto_http_la-HttpHeader.Tpo $(DEPDIR)/proto_http_la-HttpHeader.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HttpHeader.cc' object='proto_http_la-HttpHeader.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proto_http_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o proto_http_la-HttpHeader.lo `test -f 'HttpHeader.cc' || echo '$(srcdir)/'`HttpHeader.cc proto_http_la-HttpAuth.lo: HttpAuth.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proto_http_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT proto_http_la-HttpAuth.lo -MD -MP -MF $(DEPDIR)/proto_http_la-HttpAuth.Tpo -c -o proto_http_la-HttpAuth.lo `test -f 'HttpAuth.cc' || echo '$(srcdir)/'`HttpAuth.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/proto_http_la-HttpAuth.Tpo $(DEPDIR)/proto_http_la-HttpAuth.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HttpAuth.cc' object='proto_http_la-HttpAuth.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proto_http_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o proto_http_la-HttpAuth.lo `test -f 'HttpAuth.cc' || echo '$(srcdir)/'`HttpAuth.cc proto_http_la-HttpDir.lo: HttpDir.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proto_http_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT proto_http_la-HttpDir.lo -MD -MP -MF $(DEPDIR)/proto_http_la-HttpDir.Tpo -c -o proto_http_la-HttpDir.lo `test -f 'HttpDir.cc' || echo '$(srcdir)/'`HttpDir.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/proto_http_la-HttpDir.Tpo $(DEPDIR)/proto_http_la-HttpDir.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HttpDir.cc' object='proto_http_la-HttpDir.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proto_http_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o proto_http_la-HttpDir.lo `test -f 'HttpDir.cc' || echo '$(srcdir)/'`HttpDir.cc proto_http_la-HttpDirXML.lo: HttpDirXML.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proto_http_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT proto_http_la-HttpDirXML.lo -MD -MP -MF $(DEPDIR)/proto_http_la-HttpDirXML.Tpo -c -o proto_http_la-HttpDirXML.lo `test -f 'HttpDirXML.cc' || echo '$(srcdir)/'`HttpDirXML.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/proto_http_la-HttpDirXML.Tpo $(DEPDIR)/proto_http_la-HttpDirXML.Plo @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='HttpDirXML.cc' object='proto_http_la-HttpDirXML.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proto_http_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o proto_http_la-HttpDirXML.lo `test -f 'HttpDirXML.cc' || echo '$(srcdir)/'`HttpDirXML.cc lftp-lftp.o: lftp.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lftp-lftp.o -MD -MP -MF $(DEPDIR)/lftp-lftp.Tpo -c -o lftp-lftp.o `test -f 'lftp.cc' || echo '$(srcdir)/'`lftp.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lftp-lftp.Tpo $(DEPDIR)/lftp-lftp.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='lftp.cc' object='lftp-lftp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lftp-lftp.o `test -f 'lftp.cc' || echo '$(srcdir)/'`lftp.cc lftp-lftp.obj: lftp.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lftp-lftp.obj -MD -MP -MF $(DEPDIR)/lftp-lftp.Tpo -c -o lftp-lftp.obj `if test -f 'lftp.cc'; then $(CYGPATH_W) 'lftp.cc'; else $(CYGPATH_W) '$(srcdir)/lftp.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lftp-lftp.Tpo $(DEPDIR)/lftp-lftp.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='lftp.cc' object='lftp-lftp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lftp-lftp.obj `if test -f 'lftp.cc'; then $(CYGPATH_W) 'lftp.cc'; else $(CYGPATH_W) '$(srcdir)/lftp.cc'; fi` lftp-complete.o: complete.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lftp-complete.o -MD -MP -MF $(DEPDIR)/lftp-complete.Tpo -c -o lftp-complete.o `test -f 'complete.cc' || echo '$(srcdir)/'`complete.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lftp-complete.Tpo $(DEPDIR)/lftp-complete.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='complete.cc' object='lftp-complete.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lftp-complete.o `test -f 'complete.cc' || echo '$(srcdir)/'`complete.cc lftp-complete.obj: complete.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lftp-complete.obj -MD -MP -MF $(DEPDIR)/lftp-complete.Tpo -c -o lftp-complete.obj `if test -f 'complete.cc'; then $(CYGPATH_W) 'complete.cc'; else $(CYGPATH_W) '$(srcdir)/complete.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lftp-complete.Tpo $(DEPDIR)/lftp-complete.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='complete.cc' object='lftp-complete.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lftp-complete.obj `if test -f 'complete.cc'; then $(CYGPATH_W) 'complete.cc'; else $(CYGPATH_W) '$(srcdir)/complete.cc'; fi` lftp-attach.o: attach.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lftp-attach.o -MD -MP -MF $(DEPDIR)/lftp-attach.Tpo -c -o lftp-attach.o `test -f 'attach.cc' || echo '$(srcdir)/'`attach.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lftp-attach.Tpo $(DEPDIR)/lftp-attach.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='attach.cc' object='lftp-attach.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lftp-attach.o `test -f 'attach.cc' || echo '$(srcdir)/'`attach.cc lftp-attach.obj: attach.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lftp-attach.obj -MD -MP -MF $(DEPDIR)/lftp-attach.Tpo -c -o lftp-attach.obj `if test -f 'attach.cc'; then $(CYGPATH_W) 'attach.cc'; else $(CYGPATH_W) '$(srcdir)/attach.cc'; fi` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lftp-attach.Tpo $(DEPDIR)/lftp-attach.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='attach.cc' object='lftp-attach.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lftp_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lftp-attach.obj `if test -f 'attach.cc'; then $(CYGPATH_W) 'attach.cc'; else $(CYGPATH_W) '$(srcdir)/attach.cc'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgverlibdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgdatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-pkgverlibLTLIBRARIES mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-pkgdataSCRIPTS install-pkgverlibLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-binSCRIPTS \ install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ uninstall-libLTLIBRARIES uninstall-pkgdataSCRIPTS \ uninstall-pkgverlibLTLIBRARIES @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: install-am install-data-am install-strip uninstall-am .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool clean-pkgverlibLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-binSCRIPTS install-data install-data-am \ install-data-hook install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-pkgdataSCRIPTS \ install-pkgverlibLTLIBRARIES install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-binSCRIPTS uninstall-hook \ uninstall-libLTLIBRARIES uninstall-pkgdataSCRIPTS \ uninstall-pkgverlibLTLIBRARIES .PRECIOUS: Makefile # libtool does not strip modules, do it here. install-data-hook: @WITH_MODULES_TRUE@ rm -f $(DESTDIR)$(pkgverlibdir)/*.la; \ @WITH_MODULES_TRUE@ case " $(LDFLAGS) " in *" -s "*) \ @WITH_MODULES_TRUE@ $(STRIP) $(DESTDIR)$(pkgverlibdir)/*.so;; \ @WITH_MODULES_TRUE@ esac @WITH_MODULES_FALSE@ -rmdir $(DESTDIR)$(pkgverlibdir) 2>/dev/null || : # without *.la files libtool does not remove the *.so files. uninstall-hook: -rmdir "$(DESTDIR)$(pkgdatadir)" 2>/dev/null || : @WITH_MODULES_TRUE@ for m in $(pkgverlib_LTLIBRARIES); do rm -f "$(DESTDIR)$(pkgverlibdir)/$${m%.la}.so"; done @WITH_MODULES_TRUE@ -rmdir "$(DESTDIR)$(pkgverlibdir)" 2>/dev/null || : @WITH_MODULES_TRUE@ -rmdir "$(DESTDIR)$(pkglibdir)" 2>/dev/null || : commands.lo lftp.o module.lo resource.lo: $(top_builddir)/lib/configmake.h $(top_builddir)/lib/configmake.h: $(MAKE) -C $(top_builddir)/lib configmake.h # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: lftp-4.9.2/src/FileGlob.h0000644000015000007670000000565513143026745012057 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GLOB_H #define GLOB_H #include "FileAccess.h" class Glob : public FileAccessOperation { protected: xstring_c pattern; FileSet list; bool dirs_only; bool files_only; bool match_period; bool inhibit_tilde; bool casefold; void add(const FileInfo *info); void add_force(const FileInfo *info); public: const char *GetPattern() { return pattern; } FileSet *GetResult() { return &list; } Glob(FileAccess *s,const char *p); ~Glob(); void DirectoriesOnly() { dirs_only=true; } void FilesOnly() { files_only=true; } void NoMatchPeriod() { match_period=false; } void NoInhibitTilde() { inhibit_tilde=false; } void CaseFold() { casefold=true; } void MatchPeriod(bool y) { match_period=y; } void InhibitTilde(bool y) { inhibit_tilde=y; } void CaseFold(bool y) { casefold=y; } static bool HasWildcards(const char *); static void UnquoteWildcards(char *); }; class NoGlob : public Glob { public: NoGlob(const char *p); const char *Status() { return ""; } int Do(); }; class GlobURL { const FileAccessRef& orig_session; FileAccessRef my_session; FileAccessRefC session; xstring_c url_prefix; bool nullglob; public: SMTaskRef glob; enum type_select { ALL, FILES_ONLY, DIRS_ONLY }; GlobURL(const FileAccessRef& s,const char *p,type_select t=ALL); ~GlobURL(); FileSet *GetResult(); bool Done() { return glob->Done(); } bool Error() { return glob->Error(); } const char *ErrorText() { return glob->ErrorText(); } const char *Status() { return glob->Status(); } void NewGlob(const char *p); const char *GetPattern() { return glob->GetPattern(); } void NoMatchPeriod() { if(glob) glob->NoMatchPeriod(); } void NoInhibitTilde() { if(glob) glob->NoInhibitTilde(); } void CaseFold() { if(glob) glob->CaseFold(); } void NullGlob(bool y=true) { nullglob=y; } private: type_select type; }; class GenericGlob : public Glob { const char *curr_dir; FileSet *dir_list; SMTaskRef updir_glob; SMTaskRef li; public: int Do(); const char *Status(); GenericGlob(FileAccess *session,const char *n_pattern); }; #endif lftp-4.9.2/src/SFtp.cc0000644000015000007670000016011413614366326011403 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "SFtp.h" #include "ArgV.h" #include "log.h" #include "ascii_ctype.h" #include "FileGlob.h" #include "misc.h" #include "LsCache.h" #include #include #include #define max_buf 0x10000 #define super SSH_Access bool SFtp::GetBetterConnection(int level,bool limit_reached) { bool need_sleep=false; for(FA *fo=FirstSameSite(); fo!=0; fo=NextSameSite(fo)) { SFtp *o=(SFtp*)fo; // we are sure it is SFtp. if(!o->recv_buf) continue; if(o->state!=CONNECTED || o->mode!=CLOSED) { if(level<2) continue; if(!connection_takeover || (o->priority>=priority && !o->IsSuspended())) continue; o->Disconnect(); return need_sleep; } if(level==0 && xstrcmp(real_cwd,o->real_cwd)) continue; // borrow the connection MoveConnectionHere(o); break; } return need_sleep; } int SFtp::Do() { int m=STALL; const char *b; int s; // check if idle time exceeded if(mode==CLOSED && send_buf && idle_timer.Stopped()) { LogNote(1,_("Closing idle connection")); Disconnect(); return m; } if(Error()) return m; if(!hostname) return m; if(send_buf && send_buf->Error()) { LogError(0,"send: %s",send_buf->ErrorText()); Disconnect(send_buf->ErrorText()); return MOVED; } if(state!=CONNECTING_1 && state!=CONNECTING_2) m|=HandleReplies(); if(Error()) return m; if(send_buf) timeout_timer.Reset(send_buf->EventTime()); if(recv_buf) timeout_timer.Reset(recv_buf->EventTime()); if(pty_send_buf) timeout_timer.Reset(pty_send_buf->EventTime()); if(pty_recv_buf) timeout_timer.Reset(pty_recv_buf->EventTime()); // check for timeout only if there should be connection activity. if(state!=DISCONNECTED && state!=CONNECTED && mode!=CLOSED && CheckTimeout()) return MOVED; if((state==FILE_RECV || state==FILE_SEND) && rate_limit==0) rate_limit=new RateLimit(hostname); switch(state) { case DISCONNECTED: { if(mode==CLOSED) return m; if(mode==CONNECT_VERIFY) return m; // walk through SFtp classes and try to find identical idle session // first try "easy" cases of session take-over. for(int i=0; i<3; i++) { bool limit_reached=(connection_limit>0 && connection_limit<=CountConnections()); if(i>=2 && !limit_reached) break; bool need_sleep=GetBetterConnection(i,limit_reached); if(state!=DISCONNECTED) return MOVED; if(need_sleep) return m; } if(!ReconnectAllowed()) return m; if(!NextTry()) return MOVED; const char *init=Query("server-program",hostname); const char *prog=Query("connect-program",hostname); if(!prog || !prog[0]) prog="ssh -a -x"; ArgV args; if(!strchr(init,'/')) { if(init[0]) args.Add("-s"); // run ssh2 subsystem // sftpd does not have a greeting received_greeting=true; } else init=xstring::cat("echo SFTP: >&2;",init,NULL); if(user) { args.Add("-l"); args.Add(user); } if(portname) { args.Add("-p"); args.Add(portname); } args.Add(hostname); if(init[0]) args.Add(init); xstring_ca cmd_q(args.CombineShellQuoted(0)); xstring& cmd_str=xstring::cat(prog," ",cmd_q.get(),NULL); LogNote(9,"%s (%s)",_("Running connect program"),cmd_str.get()); ssh=new PtyShell(cmd_str); ssh->UsePipes(); state=CONNECTING; timeout_timer.Reset(); m=MOVED; } case CONNECTING: { int fd=ssh->getfd(); if(fd==-1) { if(ssh->error()) { SetError(FATAL,ssh->error_text); return MOVED; } TimeoutS(1); return m; } MakePtyBuffers(); set_real_cwd("~"); state=CONNECTING_1; m=MOVED; } case CONNECTING_1: m|=HandleSSHMessage(); if(state!=CONNECTING_1) return MOVED; if(!received_greeting) return m; SendRequest(new Request_INIT(Query("protocol-version",hostname)),Expect::FXP_VERSION); state=CONNECTING_2; return MOVED; case CONNECTING_2: m|=HandleSSHMessage(); if(state!=CONNECTING_2) return MOVED; m|=HandleReplies(); if(protocol_version==0) return m; if(home_auto==0) SendRequest(new Request_REALPATH("."),Expect::HOME_PATH); state=CONNECTED; m=MOVED; case CONNECTED: if(home.path==0 && !RespQueueIsEmpty()) return m; if(mode==CLOSED) return m; SendRequest(); return MOVED; case FILE_RECV: if(file_buf->Size()>=rate_limit->BytesAllowedToGet()) { recv_buf->Suspend(); Timeout(1000); } else if(file_buf->Size()>=max_buf) { recv_buf->Suspend(); m=MOVED; } else if(recv_buf->IsSuspended()) { recv_buf->Resume(); if(recv_buf->Size()>0 || (recv_buf->Size()==0 && recv_buf->Eof())) m=MOVED; } break; case FILE_SEND: // pack data from file_buf. file_buf->Get(&b,&s); if(s==0 && !eof) return m; if(smax_packets_in_flight) return m; if(s==0) { // no more data, set attributes and close the file. Request_FSETSTAT *req=new Request_FSETSTAT(handle,protocol_version); if(entity_date!=NO_DATE) { req->attrs.mtime=entity_date; req->attrs.flags|=SSH_FILEXFER_ATTR_MODIFYTIME; } req->attrs.size=pos; req->attrs.flags|=SSH_FILEXFER_ATTR_SIZE; SendRequest(req,Expect::IGNORE); CloseHandle(Expect::DEFAULT); state=WAITING; m=MOVED; break; } if(s>size_write) s=size_write; SendRequest(new Request_WRITE(handle,request_pos,b,s),Expect::WRITE_STATUS); file_buf->Skip(s); request_pos+=s; flush_timer.Reset(); m=MOVED; break; case WAITING: if(mode==ARRAY_INFO) SendArrayInfoRequests(); break; case DONE: break; } return m; } void SFtp::MoveConnectionHere(SFtp *o) { super::MoveConnectionHere(o); protocol_version=o->protocol_version; recv_translate=o->recv_translate.borrow(); send_translate=o->send_translate.borrow(); rate_limit=o->rate_limit.borrow(); expect_queue.move_here(o->expect_queue); timeout_timer.Reset(o->timeout_timer); ssh_id=o->ssh_id; state=CONNECTED; o->Disconnect(); if(!home) set_home(home_auto); ResumeInternal(); } void SFtp::DisconnectLL() { super::DisconnectLL(); handle.set(0); file_buf=0; EmptyRespQueue(); state=DISCONNECTED; if(mode==STORE) SetError(STORE_FAILED); protocol_version=0; send_translate=0; recv_translate=0; ssh_id=0; home_auto.set(FindHomeAuto()); // may have to resend file info queries. if(fileset_for_info) fileset_for_info->rewind(); } void SFtp::Init() { state=DISCONNECTED; ssh_id=0; eof=false; received_greeting=false; password_sent=0; protocol_version=0; send_translate=0; recv_translate=0; max_packets_in_flight=16; max_packets_in_flight_slow_start=1; size_read=0x8000; size_write=0x8000; use_full_path=false; flush_timer.Set(0,500); } SFtp::SFtp() : SSH_Access("SFTP:") { Init(); Reconfig(0); } SFtp::~SFtp() { Disconnect(); Close(); } SFtp::SFtp(const SFtp *o) : super(o) { Init(); Reconfig(0); } bool SFtp::Packet::HasID() { return(type!=SSH_FXP_INIT && type!=SSH_FXP_VERSION); } void SFtp::Packet::PackString(Buffer *b,const char *str,int len) { if(len==-1) len=strlen(str); b->PackUINT32BE(len); b->Put(str,len); } SFtp::unpack_status_t SFtp::Packet::UnpackString(const Buffer *b,int *offset,int limit,xstring *str_out) { if(limit-*offset<4) { // We unpack strings when we have already received complete packet, // so it is not possible to receive any more data. LogError(2,"bad string in reply (truncated length field)"); return UNPACK_WRONG_FORMAT; } int len=b->UnpackUINT32BE(*offset); if(len>limit-*offset-4) { LogError(2,"bad string in reply (invalid length field)"); return UNPACK_WRONG_FORMAT; } *offset+=4; const char *data; int data_len; b->Get(&data,&data_len); str_out->nset(data+*offset,len); *offset+=len; return UNPACK_SUCCESS; } SFtp::unpack_status_t SFtp::Packet::Unpack(const Buffer *b) { unpacked=0; if(b->Size()<4) return b->Eof()?UNPACK_PREMATURE_EOF:UNPACK_NO_DATA_YET; length=b->UnpackUINT32BE(0); unpacked+=4; if(length<1) return UNPACK_WRONG_FORMAT; if(b->Size()Eof()?UNPACK_PREMATURE_EOF:UNPACK_NO_DATA_YET; int t=b->UnpackUINT8(4); unpacked++; if(!is_valid_reply(t)) return UNPACK_WRONG_FORMAT; type=(packet_type)t; if(HasID()) { if(length<5) return UNPACK_WRONG_FORMAT; id=b->UnpackUINT32BE(5); unpacked+=4; } else { id=0; } return UNPACK_SUCCESS; } SFtp::unpack_status_t SFtp::UnpackPacket(Buffer *b,SFtp::Packet **p) { Packet *&pp=*p; pp=0; Packet probe; unpack_status_t res=probe.Unpack(b); if(res!=UNPACK_SUCCESS) return res; LogRecvF(9,"got a packet, length=%d, type=%d(%s), id=%u\n", probe.GetLength(),probe.GetPacketType(),probe.GetPacketTypeText(),probe.GetID()); switch(probe.GetPacketType()) { case SSH_FXP_VERSION: pp=new Reply_VERSION(); break; case SSH_FXP_NAME: pp=new Reply_NAME(protocol_version); break; case SSH_FXP_ATTRS: pp=new Reply_ATTRS(protocol_version); break; case SSH_FXP_STATUS: pp=new Reply_STATUS(protocol_version); break; case SSH_FXP_HANDLE: pp=new Reply_HANDLE(); break; case SSH_FXP_DATA: pp=new Reply_DATA(); break; case SSH_FXP_INIT: case SSH_FXP_OPEN: case SSH_FXP_CLOSE: case SSH_FXP_READ: case SSH_FXP_WRITE: case SSH_FXP_LSTAT: case SSH_FXP_FSTAT: case SSH_FXP_SETSTAT: case SSH_FXP_FSETSTAT: case SSH_FXP_OPENDIR: case SSH_FXP_READDIR: case SSH_FXP_REMOVE: case SSH_FXP_MKDIR: case SSH_FXP_RMDIR: case SSH_FXP_REALPATH: case SSH_FXP_STAT: case SSH_FXP_RENAME: case SSH_FXP_READLINK: case SSH_FXP_SYMLINK: case SSH_FXP_LINK: case SSH_FXP_BLOCK: case SSH_FXP_UNBLOCK: case SSH_FXP_EXTENDED: LogError(0,"request in reply??"); return UNPACK_WRONG_FORMAT; case SSH_FXP_EXTENDED_REPLY: LogError(0,"unexpected SSH_FXP_EXTENDED_REPLY"); return UNPACK_WRONG_FORMAT; } res=pp->Unpack(b); if(res!=UNPACK_SUCCESS) { switch(res) { case UNPACK_PREMATURE_EOF: LogError(0,"premature eof"); break; case UNPACK_WRONG_FORMAT: LogError(0,"wrong packet format"); break; case UNPACK_NO_DATA_YET: case UNPACK_SUCCESS: ; } probe.DropData(b); delete pp; pp=0; } return res; } void SFtp::SendRequest(Packet *request,Expect::expect_t tag,int i) { request->SetID(ssh_id++); request->ComputeLength(); LogSendF(9,"sending a packet, length=%d, type=%d(%s), id=%u\n", request->GetLength(),request->GetPacketType(),request->GetPacketTypeText(),request->GetID()); request->Pack(send_buf.get_non_const()); PushExpect(new Expect(request,tag,i)); } const char *SFtp::SkipHome(const char *path) { if(path[0]=='~' && path[1]=='/' && path[2]) return path+2; if(path[0]=='~' && !path[1]) return "."; if(!home) return path; int home_len=home.path.length(); if(strncmp(home,path,home_len)) return path; if(path[home_len]=='/' && path[home_len+1] && path[home_len+1]!='/') return path+home_len+1; if(!path[home_len]) return "."; return path; } const char *SFtp::WirePath(const char *path) { path=dir_file(cwd,path); if(!use_full_path || path[0]=='~') path=SkipHome(path); LogNote(9,"path on wire is `%s'",path); return lc_to_utf8(path); } void SFtp::SendRequest() { max_packets_in_flight_slow_start=1; ExpandTildeInCWD(); switch((open_mode)mode) { case CHANGE_DIR: LogNote(9,"checking directory `%s'",file.get()); SendRequest(new Request_STAT(lc_to_utf8(file),0,protocol_version),Expect::CWD); SendRequest(new Request_STAT(lc_to_utf8(dir_file(file,".")),0,protocol_version),Expect::CWD); state=WAITING; break; case RETRIEVE: SendRequest(new Request_OPEN(WirePath(file),SSH_FXF_READ, ACE4_READ_DATA|ACE4_READ_ATTRIBUTES,SSH_FXF_OPEN_EXISTING,protocol_version),Expect::HANDLE); state=WAITING; break; case LIST: case LONG_LIST: SendRequest(new Request_OPENDIR(WirePath(file)),Expect::HANDLE); state=WAITING; break; case STORE: SendRequest( new Request_OPEN(WirePath(file), SSH_FXF_WRITE|SSH_FXF_CREAT|(pos==0?SSH_FXF_TRUNC:0), ACE4_WRITE_DATA|ACE4_WRITE_ATTRIBUTES, pos==0?SSH_FXF_CREATE_TRUNCATE:SSH_FXF_OPEN_OR_CREATE, protocol_version), Expect::HANDLE); state=WAITING; break; case ARRAY_INFO: state=WAITING; break; case RENAME: { if(protocol_version<3) { SetError(NOT_SUPP); break; } unsigned options=0; if(rename_f) { options=SSH_FXF_RENAME_OVERWRITE; if(protocol_version<5) { // overwrite is not supported, remove the target explicitly SendRequest(new Request_REMOVE(WirePath(file1)),Expect::IGNORE); } } SendRequest(new Request_RENAME(WirePath(file),WirePath(file1), options,protocol_version),Expect::DEFAULT); state=WAITING; break; } case CHANGE_MODE: { Request_SETSTAT *req=new Request_SETSTAT(WirePath(file),protocol_version); req->attrs.permissions=chmod_mode; req->attrs.flags|=SSH_FILEXFER_ATTR_PERMISSIONS; SendRequest(req,Expect::DEFAULT); state=WAITING; break; } case MAKE_DIR: if(mkdir_p) { Ref dirs(MkdirMakeSet()); for(int i=0; iCount(); i++) SendRequest(new Request_MKDIR(WirePath(dirs->String(i)),protocol_version),Expect::IGNORE); } SendRequest(new Request_MKDIR(WirePath(file),protocol_version),Expect::DEFAULT); state=WAITING; break; case REMOVE_DIR: SendRequest(new Request_RMDIR(WirePath(file)),Expect::DEFAULT); state=WAITING; break; case REMOVE: SendRequest(new Request_REMOVE(WirePath(file)),Expect::DEFAULT); state=WAITING; break; case LINK: if(protocol_version<6) { SetError(NOT_SUPP); break; } case SYMLINK: if(protocol_version<3) { SetError(NOT_SUPP); break; } if(protocol_version>=6) SendRequest(new Request_LINK(mode==SYMLINK?lc_to_utf8(file):WirePath(file),WirePath(file1),mode==SYMLINK),Expect::DEFAULT); else SendRequest(new Request_SYMLINK(lc_to_utf8(file),WirePath(file1)),Expect::DEFAULT); state=WAITING; break; case QUOTE_CMD: case MP_LIST: SetError(NOT_SUPP); break; case CONNECT_VERIFY: case CLOSED: abort(); } } void SFtp::SendArrayInfoRequests() { for(FileInfo *fi=fileset_for_info->curr(); fi && RespQueueSize()next()) { if(fi->need&(fi->SIZE|fi->DATE|fi->MODE|fi->TYPE|fi->USER|fi->GROUP)) { unsigned flags=0; if(fi->need&fi->SIZE) flags|=SSH_FILEXFER_ATTR_SIZE; if(fi->need&fi->DATE) flags|=SSH_FILEXFER_ATTR_MODIFYTIME; if(fi->need&fi->MODE) flags|=SSH_FILEXFER_ATTR_PERMISSIONS; if(fi->need&(fi->USER|fi->GROUP)) flags|=SSH_FILEXFER_ATTR_OWNERGROUP; SendRequest(new Request_STAT(WirePath(fi->name),flags, protocol_version),Expect::INFO,fileset_for_info->curr_index()); } if(fi->need&fi->SYMLINK_DEF && protocol_version>=3) SendRequest(new Request_READLINK(WirePath(fi->name)), Expect::INFO_READLINK,fileset_for_info->curr_index()); } if(RespQueueIsEmpty()) state=DONE; } void SFtp::CloseHandle(Expect::expect_t c) { if(handle) { SendRequest(new Request_CLOSE(handle),c); handle.set(0); } } void SFtp::Close() { switch(state) { case(DISCONNECTED): case(WAITING): case(CONNECTED): case(DONE): case(FILE_RECV): case(FILE_SEND): break; case(CONNECTING): case(CONNECTING_1): case(CONNECTING_2): Disconnect(); } CloseExpectQueue(); state=(recv_buf?CONNECTED:DISCONNECTED); eof=false; file_buf=0; file_set=0; CloseHandle(Expect::IGNORE); super::Close(); // don't need these out-of-order packets anymore ooo_chain.truncate(); if(recv_buf) recv_buf->Resume(); } int SFtp::HandlePty() { int m=STALL; if(pty_recv_buf==0) return m; const char *b; int s; pty_recv_buf->Get(&b,&s); const char *eol=(const char*)memchr(b,'\n',s); if(!eol) { if(pty_recv_buf->Eof()) LogError(0,_("Peer closed connection")); if(pty_recv_buf->Error()) LogError(0,"pty read: %s",pty_recv_buf->ErrorText()); if(pty_recv_buf->Eof() || pty_recv_buf->Error()) { Disconnect(pty_recv_buf->ErrorText()); m=MOVED; } return m; } m=MOVED; s=eol-b+1; char *line=string_alloca(s); memcpy(line,b,s-1); line[s-1]=0; pty_recv_buf->Skip(s); LogRecv(4,line); return m; } void SFtp::HandleExpect(Expect *e) { const Packet *reply=e->reply; if(reply->TypeIs(SSH_FXP_STATUS)) { Reply_STATUS *r=(Reply_STATUS*)reply; const char *message=r->GetMessage(); LogNote(9,"status code=%d(%s), message=%s",r->GetCode(),r->GetCodeText(), message?message:"NULL"); } switch(e->tag) { case Expect::FXP_VERSION: if(reply->TypeIs(SSH_FXP_VERSION)) { protocol_version=((Reply_VERSION*)reply)->GetVersion(); LogNote(9,"protocol version set to %d",protocol_version); const char *charset=0; if(protocol_version>=4) charset="UTF-8"; else charset=ResMgr::Query("sftp:charset",hostname); if(charset && *charset) { send_translate=new DirectedBuffer(DirectedBuffer::PUT); recv_translate=new DirectedBuffer(DirectedBuffer::GET); send_translate->SetTranslation(charset,false); recv_translate->SetTranslation(charset,true); } } else { Disconnect(); SetError(FATAL,"cannot negotiate protocol version"); } break; case Expect::HOME_PATH: if(reply->TypeIs(SSH_FXP_NAME)) { Reply_NAME *r=(Reply_NAME*)reply; const NameAttrs *a=r->GetNameAttrs(0); if(a && !home_auto) { home_auto.set(utf8_to_lc(a->name)); LogNote(9,"home set to %s",home_auto.get()); PropagateHomeAuto(); if(!home) set_home(home_auto); cache->SetDirectory(this, home, true); } } break; case Expect::CWD: if(reply->TypeIs(SSH_FXP_ATTRS)) { const FileAttrs *a=((Reply_ATTRS*)reply)->GetAttrs(); if(a->type!=SSH_FILEXFER_TYPE_DIRECTORY && a->type!=SSH_FILEXFER_TYPE_SYMLINK) // workaround for RouterOS v6 { LogError(1,"got file type %d",a->type); cache->SetDirectory(this,cwd,false); SetError(NO_FILE,strerror(ENOTDIR)); break; } if(mode==CHANGE_DIR && !HasExpect(Expect::CWD)) { cwd.Set(file); eof=true; cache->SetDirectory(this,cwd,true); } } else SetError(NO_FILE,reply); break; case Expect::HANDLE: if(reply->TypeIs(SSH_FXP_HANDLE)) { handle.set(((Reply_HANDLE*)reply)->GetHandle()); state=(mode==STORE?FILE_SEND:FILE_RECV); file_buf=new Buffer; xstring handle_x(""); int handle_len=handle.length(); for(int i=0; iTypeIs(SSH_FXP_HANDLE)) { // close the handle immediately. const xstring &handle=((Reply_HANDLE*)reply)->GetHandle(); SendRequest(new Request_CLOSE(handle),Expect::IGNORE); } break; case Expect::DATA: if(max_packets_in_flight_slow_startTypeIs(SSH_FXP_DATA)) { const Request_READ *r=e->request.Cast(); Reply_DATA *d=(Reply_DATA*)reply; if(r->pos==pos+file_buf->Size()) { const char *b; int s; d->GetData(&b,&s); LogNote(9,"data packet: pos=%lld, size=%d",(long long)r->pos,s); file_buf->Put(b,s); if(d->Eof() || eof) goto eof; if(r->len > unsigned(s)) // received less than requested? { // if we have not yet requested next chunk of data, // then adjust request position, else re-request missed data. if(r->pos+r->len==request_pos) request_pos=r->pos+s; else SendRequest(new Request_READ(handle,r->pos+s,r->len-s),Expect::DATA); } } else { LogNote(9,"put a packet with id=%d on out-of-order chain (need_pos=%lld packet_pos=%lld)", reply->GetID(),(long long)(pos+file_buf->Size()),(long long)r->pos); if(ooo_chain.count()>=64) { LogError(0,"Too many out-of-order packets"); Disconnect(); return; } ooo_chain.append(e); return; } } else if(reply->TypeIs(SSH_FXP_NAME)) { Reply_NAME *r=(Reply_NAME*)reply; LogNote(9,"file name count=%d",r->GetCount()); for(int i=0; iGetCount(); i++) { const NameAttrs *a=r->GetNameAttrs(i); FileInfo *info=MakeFileInfo(a); if(mode==LIST) { file_buf->Put(a->name); if(a->attrs.type==SSH_FILEXFER_TYPE_DIRECTORY) file_buf->Put("/"); file_buf->Put("\n"); } else if(mode==LONG_LIST) { if(a->longname) { file_buf->Put(a->longname); file_buf->Put("\n"); } else if(info) { info->MakeLongName(); file_buf->Put(info->longname); file_buf->Put("\n"); } } if(info) { if(!file_set) file_set=new FileSet; file_set->Add(info); } } if(r->Eof() || eof) goto eof; } else { if(reply->TypeIs(SSH_FXP_STATUS)) { if(((Reply_STATUS*)reply)->GetCode()==SSH_FX_EOF) { eof: eof=true; state=DONE; if(file_buf && ooo_chain.count()==0 && !HasExpectBefore(reply->GetID(),Expect::DATA)) { LogNote(9,"eof"); file_buf->PutEOF(); } break; } } SetError(NO_FILE,reply); } break; case Expect::INFO: if(mode==ARRAY_INFO) { if(reply->TypeIs(SSH_FXP_ATTRS)) { FileInfo *fi=(*fileset_for_info)[e->i]; MergeAttrs(fi,((Reply_ATTRS*)reply)->GetAttrs()); } break; } entity_size=NO_SIZE; entity_date=NO_DATE; if(reply->TypeIs(SSH_FXP_ATTRS)) { const FileAttrs *a=((Reply_ATTRS*)reply)->GetAttrs(); if(a->flags&SSH_FILEXFER_ATTR_SIZE) entity_size=a->size; if(a->flags&SSH_FILEXFER_ATTR_MODIFYTIME) entity_date=a->mtime; LogNote(9,"file info: size=%lld, date=%s",(long long)entity_size,ctime(&entity_date)); } if(opt_size) *opt_size=entity_size; if(opt_date) *opt_date=entity_date; break; case Expect::INFO_READLINK: if(reply->TypeIs(SSH_FXP_NAME)) { Reply_NAME *r=(Reply_NAME*)reply; const NameAttrs *a=r->GetNameAttrs(0); LogNote(9,"file info: symlink=%s",a->name.get()); if(mode==ARRAY_INFO) { FileInfo *fi=(*fileset_for_info)[e->i]; fi->SetSymlink(a->name); } } break; case Expect::WRITE_STATUS: if(reply->TypeIs(SSH_FXP_STATUS)) { if(((Reply_STATUS*)reply)->GetCode()==SSH_FX_OK) { TrySuccess(); break; } } SetError(NO_FILE,reply); break; case Expect::DEFAULT: if(reply->TypeIs(SSH_FXP_STATUS)) { if(((Reply_STATUS*)reply)->GetCode()==SSH_FX_OK) { state=DONE; break; } } SetError(NO_FILE,reply); break; case Expect::IGNORE: break; } delete e; } void SFtp::RequestMoreData() { Enter(this); if(mode==RETRIEVE) { int req_len=size_read; SendRequest(new Request_READ(handle,request_pos,req_len),Expect::DATA); request_pos+=req_len; } else if(mode==LIST || mode==LONG_LIST) { SendRequest(new Request_READDIR(handle),Expect::DATA); } Leave(this); } int SFtp::HandleReplies() { int m=STALL; if(recv_buf==0) return m; if(state!=CONNECTING_2) m|=HandlePty(); if(!recv_buf) return MOVED; if(file_buf) { off_t need_pos=pos+file_buf->Size(); // there are usually a few of out-of-order packets, no need for fast search for(int i=0; ihas_data_at_pos(need_pos)) { Expect *e=ooo_chain[i]; ooo_chain[i]=0; // to keep the Expect ooo_chain.remove(i); HandleExpect(e); } } } if(eof && file_buf && !file_buf->Eof() && ooo_chain.count()==0 && !HasExpect(Expect::DATA)) { LogNote(9,"eof"); file_buf->PutEOF(); } if(recv_buf->Size()<4) { if(recv_buf->Error()) { LogError(0,"receive: %s",recv_buf->ErrorText()); Disconnect(recv_buf->ErrorText()); return MOVED; } if(recv_buf->Eof() && pty_recv_buf->Size()==0) { LogError(0,_("Peer closed connection")); Disconnect(last_ssh_message?last_ssh_message.get():_("Peer closed connection")); m=MOVED; } return m; } if(recv_buf->IsSuspended()) return m; Packet *reply=0; unpack_status_t st=UnpackPacket(recv_buf.get_non_const(),&reply); if(st==UNPACK_NO_DATA_YET) return m; if(st!=UNPACK_SUCCESS) { LogError(2,_("invalid server response format")); Disconnect(_("invalid server response format")); return MOVED; } reply->DropData(recv_buf.get_non_const()); Expect *e=FindExpectExclusive(reply); if(e==0) { LogError(3,_("extra server response")); delete reply; return MOVED; } HandleExpect(e); return MOVED; } void SFtp::PushExpect(Expect *e) { expect_queue.add(e->request->GetKey(),e); } SFtp::Expect *SFtp::FindExpectExclusive(Packet *p) { Expect *e=expect_queue.borrow(p->GetKey()); if(e) e->reply=p; return e; } void SFtp::CloseExpectQueue() { for(Expect *e=expect_queue.each_begin(); e; e=expect_queue.each_next()) { switch(e->tag) { case Expect::IGNORE: case Expect::HANDLE_STALE: case Expect::HOME_PATH: case Expect::FXP_VERSION: break; case Expect::CWD: case Expect::INFO: case Expect::INFO_READLINK: case Expect::DEFAULT: case Expect::DATA: case Expect::WRITE_STATUS: e->tag=Expect::IGNORE; break; case Expect::HANDLE: e->tag=Expect::HANDLE_STALE; break; } } } bool SFtp::HasExpect(Expect::expect_t tag) { for(Expect *e=expect_queue.each_begin(); e; e=expect_queue.each_next()) if(e->tag==tag) return true; return false; } static bool IsBefore(unsigned id1,unsigned id2) { // order with wrap-around return id2 - id1 < id1 - id2; } bool SFtp::HasExpectBefore(unsigned id,Expect::expect_t tag) { for(Expect *e=expect_queue.each_begin(); e; e=expect_queue.each_next()) if(e->tag==tag && IsBefore(e->request->GetID(),id)) return true; return false; } Glob *SFtp::MakeGlob(const char *pat) { return new GenericGlob(this,pat); } ListInfo *SFtp::MakeListInfo(const char *dir) { return new SFtpListInfo(this,dir); } int SFtp::Read(Buffer *buf,int size) { if(Error()) return error_code; if(mode==CLOSED) return 0; if(state==DONE && (!file_buf || (file_buf->Size()==0 && file_buf->Eof()))) return 0; // eof if(state==FILE_RECV) { // keep some packets in flight. int limit=(entity_size>=0?max_packets_in_flight:max_packets_in_flight_slow_start); if(RespQueueSize()Eof()) { // but don't request much after possible EOF. if(entity_size<0 || request_posSize()>0) { const char *buf1; int size1; file_buf->Get(&buf1,&size1); if(buf1==0) return 0; int bytes_allowed=rate_limit->BytesAllowedToGet(); if(size1>bytes_allowed) size1=bytes_allowed; if(size1==0) return DO_AGAIN; if(size>size1) size=size1; size=buf->MoveDataHere(file_buf,size); if(size<=0) return DO_AGAIN; pos+=size; real_pos+=size; rate_limit->BytesGot(size); TrySuccess(); return size; } return DO_AGAIN; } int SFtp::Write(const void *buf,int size) { if(mode!=STORE) return(0); Resume(); Enter(this); Do(); Leave(this); if(Error()) return(error_code); if(state!=FILE_SEND || rate_limit==0 || send_buf->Size()>2*max_buf) return DO_AGAIN; { int allowed=rate_limit->BytesAllowedToPut(); if(allowed==0) return DO_AGAIN; if(size+file_buf->Size()>allowed) size=allowed-send_buf->Size(); } if(size+file_buf->Size()>max_buf) size=max_buf-file_buf->Size(); if(entity_size>=0 && pos+size>entity_size) size=entity_size-pos; if(size<=0) return 0; file_buf->Put(static_cast(buf),size); rate_limit->BytesPut(size); pos+=size; real_pos+=size; return(size); } int SFtp::Buffered() { if(file_buf==0) return 0; off_t b=file_buf->Size()+send_buf->Size()*size_write/(size_write+20); if(b<0) b=0; else if(b>real_pos) b=real_pos; return b; } int SFtp::StoreStatus() { if(Error()) return error_code; if(state==FILE_SEND && !eof) { eof=true; return IN_PROGRESS; } if(state==DONE) return OK; return IN_PROGRESS; } int SFtp::Done() { if(mode==CLOSED) return OK; if(Error()) return error_code; if(eof || state==DONE) return OK; if(mode==CONNECT_VERIFY) return OK; return IN_PROGRESS; } void SFtp::SuspendInternal() { super::SuspendInternal(); if(recv_buf) recv_buf->SuspendSlave(); if(send_buf) send_buf->SuspendSlave(); if(pty_send_buf) pty_send_buf->SuspendSlave(); if(pty_recv_buf) pty_recv_buf->SuspendSlave(); } void SFtp::ResumeInternal() { if(recv_buf) recv_buf->ResumeSlave(); if(send_buf) send_buf->ResumeSlave(); if(pty_send_buf) pty_send_buf->ResumeSlave(); if(pty_recv_buf) pty_recv_buf->ResumeSlave(); super::ResumeInternal(); } const char *SFtp::CurrentStatus() { switch(state) { case DISCONNECTED: if(!ReconnectAllowed()) return DelayingMessage(); return _("Not connected"); case CONNECTING: if(ssh && ssh->status) return ssh->status; case CONNECTING_1: case CONNECTING_2: return _("Connecting..."); case CONNECTED: return _("Connected"); case WAITING: return _("Waiting for response..."); case FILE_RECV: return _("Receiving data"); case FILE_SEND: return _("Sending data"); case DONE: return _("Done"); } return ""; } bool SFtp::SameSiteAs(const FileAccess *fa) const { if(!SameProtoAs(fa)) return false; SFtp *o=(SFtp*)fa; return(!xstrcasecmp(hostname,o->hostname) && !xstrcmp(portname,o->portname) && !xstrcmp(user,o->user) && !xstrcmp(pass,o->pass)); } bool SFtp::SameLocationAs(const FileAccess *fa) const { if(!SameSiteAs(fa)) return false; SFtp *o=(SFtp*)fa; if(xstrcmp(cwd,o->cwd)) return false; if(xstrcmp(home,o->home)) return false; return true; } void SFtp::Reconfig(const char *name) { super::Reconfig(name); const char *c=hostname; max_packets_in_flight=Query("max-packets-in-flight",c); if(max_packets_in_flight<1) max_packets_in_flight=1; if(max_packets_in_flight_slow_start>max_packets_in_flight) max_packets_in_flight_slow_start=max_packets_in_flight; size_read=Query("size-read",c); size_write=Query("size-write",c); if(size_read<16) size_read=16; if(size_write<16) size_write=16; use_full_path=QueryBool("use-full-path",c); if(!xstrcmp(name,"sftp:charset") && protocol_version && protocol_version<4) { if(!IsSuspended()) cache->TreeChanged(this,"/"); const char *charset=ResMgr::Query("sftp:charset",hostname); if(charset && *charset) { if(!send_translate) send_translate=new DirectedBuffer(DirectedBuffer::PUT); if(!recv_translate) recv_translate=new DirectedBuffer(DirectedBuffer::GET); send_translate->SetTranslation(charset,false); recv_translate->SetTranslation(charset,true); } else { send_translate=0; recv_translate=0; } } } void SFtp::ClassInit() { // register the class Register("sftp",SFtp::New); } FileAccess *SFtp::New() { return new SFtp(); } DirList *SFtp::MakeDirList(ArgV *args) { return new SFtpDirList(this,args); } struct code_text { int code; const char *text; }; const char *SFtp::Packet::GetPacketTypeText() { struct code_text text_table[]={ { SSH_FXP_INIT, "INIT" }, { SSH_FXP_VERSION, "VERSION" }, { SSH_FXP_OPEN, "OPEN" }, { SSH_FXP_CLOSE, "CLOSE" }, { SSH_FXP_READ, "READ" }, { SSH_FXP_WRITE, "WRITE" }, { SSH_FXP_LSTAT, "LSTAT" }, { SSH_FXP_FSTAT, "FSTAT" }, { SSH_FXP_SETSTAT, "SETSTAT" }, { SSH_FXP_FSETSTAT, "FSETSTAT" }, { SSH_FXP_OPENDIR, "OPENDIR" }, { SSH_FXP_READDIR, "READDIR" }, { SSH_FXP_REMOVE, "REMOVE" }, { SSH_FXP_MKDIR, "MKDIR" }, { SSH_FXP_RMDIR, "RMDIR" }, { SSH_FXP_REALPATH, "REALPATH" }, { SSH_FXP_STAT, "STAT" }, { SSH_FXP_RENAME, "RENAME" }, { SSH_FXP_READLINK, "READLINK" }, { SSH_FXP_SYMLINK, "SYMLINK" }, { SSH_FXP_LINK, "LINK" }, { SSH_FXP_BLOCK, "BLOCK" }, { SSH_FXP_UNBLOCK, "UNBLOCK" }, { SSH_FXP_STATUS, "STATUS" }, { SSH_FXP_HANDLE, "HANDLE" }, { SSH_FXP_DATA, "DATA" }, { SSH_FXP_NAME, "NAME" }, { SSH_FXP_ATTRS, "ATTRS" }, { SSH_FXP_EXTENDED, "EXTENDED" }, { SSH_FXP_EXTENDED_REPLY,"EXTENDED_REPLY" }, {0,0} }; for(int i=0; text_table[i].text; i++) if(text_table[i].code==type) return text_table[i].text; return "UNKNOWN"; } const char *SFtp::Reply_STATUS::GetCodeText() { static const char *text_table[]={ "OK", "EOF", "No such file", "Permission denied", "Failure", "Bad message", "No connection", "Connection lost", "Operation not supported", "Invalid handle", "No such path", "File already exists", "Write protect", "No media", "No space on filesystem", "Quota exceeded", "Unknown principal", "Lock conflict", "Directory not empty", "Not a directory", "Invalid file name", "Link loop", "Cannot delete", "Invalid parameter", "File is a directory", "Byte range lock conflict", "Byte range lock refused", "Delete pending", "File corrupt", "Owner invalid", "Group invalid" }; if(code>=0 && codeTypeIs(SSH_FXP_STATUS)) { SetError(code); return; } Reply_STATUS *status=(Reply_STATUS*)reply; const char *message=status->GetMessage(); if(message && *message) { SetError(code,utf8_to_lc(message)); return; } message=status->GetCodeText(); if(message) { SetError(code,_(message)); return; } SetError(code); } #define UNPACK_GENERIC(out,size,fun) \ do { \ if(limit-*offset<(size)) \ return UNPACK_WRONG_FORMAT; \ out=b->fun(*offset); \ *offset+=(size); \ } while(0) #define UNPACK8(out) UNPACK_GENERIC(out,1,UnpackUINT8) #define UNPACK32(out) UNPACK_GENERIC(out,4,UnpackUINT32BE) #define UNPACK64(out) UNPACK_GENERIC(out,8,UnpackUINT64BE) #define UNPACK32_SIGNED(out) UNPACK_GENERIC(out,4,UnpackINT32BE) #define UNPACK64_SIGNED(out) UNPACK_GENERIC(out,8,UnpackINT64BE) #define PACK8(data) b->PackUINT8(data) #define PACK32(data) b->PackUINT32BE(data) #define PACK64(data) b->PackUINT64BE(data) #define PACK32_SIGNED(data) b->PackINT32BE(data) #define PACK64_SIGNED(data) b->PackINT64BE(data) SFtp::unpack_status_t SFtp::PacketSTRING::Unpack(const Buffer *b) { unpack_status_t res; res=Packet::Unpack(b); if(res!=UNPACK_SUCCESS) return res; res=UnpackString(b,&unpacked,length+4,&string); return res; } SFtp::unpack_status_t SFtp::Reply_NAME::Unpack(const Buffer *b) { unpack_status_t res=Packet::Unpack(b); if(res!=UNPACK_SUCCESS) return res; int *offset=&unpacked; int limit=length+4; UNPACK32(count); names=new NameAttrs[count]; for(int i=0; i=4) UNPACK8(type); if(flags & SSH_FILEXFER_ATTR_SIZE) UNPACK64(size); if(protocol_version<=3 && (flags & SSH_FILEXFER_ATTR_UIDGID)) { UNPACK32(uid); UNPACK32(gid); } if(protocol_version>=4 && (flags & SSH_FILEXFER_ATTR_OWNERGROUP)) { res=Packet::UnpackString(b,offset,limit,&owner); if(res!=UNPACK_SUCCESS) return res; res=Packet::UnpackString(b,offset,limit,&group); if(res!=UNPACK_SUCCESS) return res; } if(flags & SSH_FILEXFER_ATTR_PERMISSIONS) { UNPACK32(permissions); if(protocol_version<=3) { switch(permissions&S_IFMT) { case S_IFREG: type=SSH_FILEXFER_TYPE_REGULAR; break; case S_IFDIR: type=SSH_FILEXFER_TYPE_DIRECTORY; break; case S_IFLNK: type=SSH_FILEXFER_TYPE_SYMLINK; break; case S_IFIFO: case S_IFCHR: case S_IFBLK: type=SSH_FILEXFER_TYPE_SPECIAL; break; default: type=SSH_FILEXFER_TYPE_UNKNOWN; break; } } } if(protocol_version<=3 && (flags & SSH_FILEXFER_ATTR_ACMODTIME)) { UNPACK32_SIGNED(atime); UNPACK32_SIGNED(mtime); flags|=SSH_FILEXFER_ATTR_MODIFYTIME; } if(protocol_version>=4 && (flags & SSH_FILEXFER_ATTR_ACCESSTIME)) { UNPACK64_SIGNED(atime); if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) UNPACK32(atime_nseconds); } if(protocol_version>=4 && (flags & SSH_FILEXFER_ATTR_CREATETIME)) { UNPACK64_SIGNED(createtime); if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) UNPACK32(createtime_nseconds); } if(protocol_version>=4 && (flags & SSH_FILEXFER_ATTR_MODIFYTIME)) { UNPACK64_SIGNED(mtime); if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) UNPACK32(mtime_nseconds); } if(protocol_version>=5 && (flags & SSH_FILEXFER_ATTR_CTIME)) { UNPACK64_SIGNED(ctime); if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) UNPACK32(ctime_nseconds); } if(atime_nseconds>999999999 || createtime_nseconds>999999999 || mtime_nseconds>999999999 || ctime_nseconds>999999999) return UNPACK_WRONG_FORMAT; if(protocol_version>=4 && (flags & SSH_FILEXFER_ATTR_ACL)) { UNPACK32(ace_count); ace=new FileACE[ace_count]; for(unsigned i=0; i=5 && (flags & SSH_FILEXFER_ATTR_BITS)) { UNPACK32(attrib_bits); if(protocol_version>=6) UNPACK32(attrib_bits_valid); } if(protocol_version>=6 && (flags & SSH_FILEXFER_ATTR_TEXT_HINT)) UNPACK8(text_hint); if(protocol_version>=6 && (flags & SSH_FILEXFER_ATTR_MIME_TYPE)) { res=Packet::UnpackString(b,offset,limit,&mime_type); if(res!=UNPACK_SUCCESS) return res; } if(protocol_version>=6 && (flags & SSH_FILEXFER_ATTR_LINK_COUNT)) UNPACK32(link_count); if(protocol_version>=6 && (flags & SSH_FILEXFER_ATTR_UNTRANSLATED_NAME)) { res=Packet::UnpackString(b,offset,limit,&untranslated_name); if(res!=UNPACK_SUCCESS) return res; } if(flags & SSH_FILEXFER_ATTR_EXTENDED) { UNPACK32(extended_count); extended_attrs=new ExtFileAttr[extended_count]; for(unsigned i=0; i=6) flags_mask=SSH_FILEXFER_ATTR_MASK_V6; PACK32(flags&flags_mask); if(protocol_version>=4) { if(type==0) { switch(permissions&S_IFMT) { case S_IFREG: type=SSH_FILEXFER_TYPE_REGULAR; break; case S_IFDIR: type=SSH_FILEXFER_TYPE_DIRECTORY; break; case S_IFLNK: type=SSH_FILEXFER_TYPE_SYMLINK; break; case S_IFIFO: case S_IFCHR: case S_IFBLK: type=SSH_FILEXFER_TYPE_SPECIAL; break; default: type=SSH_FILEXFER_TYPE_UNKNOWN; break; } } PACK8(type); } if(flags & SSH_FILEXFER_ATTR_SIZE) PACK64(size); if(protocol_version<=3 && (flags & SSH_FILEXFER_ATTR_UIDGID)) { PACK32(uid); PACK32(gid); } if(protocol_version>=4 && (flags & SSH_FILEXFER_ATTR_OWNERGROUP)) { Packet::PackString(b,owner); Packet::PackString(b,group); } if(flags & SSH_FILEXFER_ATTR_PERMISSIONS) PACK32(permissions); if(protocol_version<=3 && (flags & SSH_FILEXFER_ATTR_ACMODTIME)) { PACK32_SIGNED(atime); PACK32_SIGNED(mtime); } if(protocol_version>=4 && (flags & SSH_FILEXFER_ATTR_ACCESSTIME)) { PACK64_SIGNED(atime); if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) PACK32(atime_nseconds); } if(protocol_version>=4 && (flags & SSH_FILEXFER_ATTR_CREATETIME)) { PACK64_SIGNED(createtime); if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) PACK32(createtime_nseconds); } if(protocol_version>=4 && (flags & SSH_FILEXFER_ATTR_MODIFYTIME)) { PACK64_SIGNED(mtime); if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) PACK32(mtime_nseconds); } if(protocol_version>=5 && (flags & SSH_FILEXFER_ATTR_CTIME)) { PACK64_SIGNED(ctime); if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES) PACK32(ctime_nseconds); } if(protocol_version>=4 && (flags & SSH_FILEXFER_ATTR_ACL)) { PACK32(ace_count); for(unsigned i=0; i=5 && (flags & SSH_FILEXFER_ATTR_BITS)) { PACK32(attrib_bits); if(protocol_version>=6) PACK32(attrib_bits_valid); } if(protocol_version>=6 && (flags & SSH_FILEXFER_ATTR_TEXT_HINT)) PACK8(text_hint); if(protocol_version>=6 && (flags & SSH_FILEXFER_ATTR_MIME_TYPE)) Packet::PackString(b,mime_type); if(protocol_version>=6 && (flags & SSH_FILEXFER_ATTR_LINK_COUNT)) PACK32(link_count); if(protocol_version>=6 && (flags & SSH_FILEXFER_ATTR_UNTRANSLATED_NAME)) Packet::PackString(b,untranslated_name); if(flags & SSH_FILEXFER_ATTR_EXTENDED) { PACK32(extended_count); for(unsigned i=0; i=3) { if(unpacked>=limit) { LogError(2,"Status reply lacks `error message' field"); return UNPACK_SUCCESS; } res=Packet::UnpackString(b,offset,limit,&message); if(res!=UNPACK_SUCCESS) return res; if(unpacked>=limit) { LogError(2,"Status reply lacks `language tag' field"); return UNPACK_SUCCESS; } res=Packet::UnpackString(b,offset,limit,&language); if(res!=UNPACK_SUCCESS) return res; } return UNPACK_SUCCESS; } void SFtp::Request_READ::Pack(Buffer *b) { PacketSTRING::Pack(b); PACK64(pos); PACK32(len); } void SFtp::Request_WRITE::Pack(Buffer *b) { PacketSTRING::Pack(b); PACK64(pos); int len=data.length(); PACK32(len); b->Put(data,len); } void SFtp::Request_OPEN::Pack(Buffer *b) { PacketSTRING::Pack(b); if(protocol_version<=4) PACK32(pflags); if(protocol_version>=5) { PACK32(desired_access); PACK32(flags); } attrs.Pack(b,protocol_version); } void SFtp::Request_RENAME::ComputeLength() { Packet::ComputeLength(); length+=4+strlen(oldpath)+4+strlen(newpath); if(protocol_version>=5) length+=4; // flags } void SFtp::Request_RENAME::Pack(Buffer *b) { Packet::Pack(b); Packet::PackString(b,oldpath); Packet::PackString(b,newpath); if(protocol_version>=5) PACK32(flags); } void SFtp::Request_SYMLINK::Pack(Buffer *b) { Packet::Pack(b); Packet::PackString(b,oldpath); Packet::PackString(b,newpath); } void SFtp::Request_LINK::Pack(Buffer *b) { Packet::Pack(b); Packet::PackString(b,newpath); Packet::PackString(b,oldpath); PACK8(symbolic); } const char *SFtp::utf8_to_lc(const char *s) { if(!recv_translate || !s) return s; recv_translate->ResetTranslation(); recv_translate->PutTranslated(s); recv_translate->Buffer::Put("",1); int len; recv_translate->Get(&s,&len); recv_translate->Skip(len); return xstring::get_tmp(s,len); } const char *SFtp::lc_to_utf8(const char *s) { if(!send_translate || !s) return s; send_translate->ResetTranslation(); send_translate->PutTranslated(s); send_translate->Buffer::Put("",1); int len; send_translate->Get(&s,&len); send_translate->Skip(len); return xstring::get_tmp(s,len); } FileSet *SFtp::GetFileSet() { FileSet *fset=file_set.borrow(); return fset?fset:new FileSet; } void SFtp::MergeAttrs(FileInfo *fi,const FileAttrs *a) { switch(a->type) { case SSH_FILEXFER_TYPE_REGULAR: fi->SetType(fi->NORMAL); break; case SSH_FILEXFER_TYPE_DIRECTORY:fi->SetType(fi->DIRECTORY); break; case SSH_FILEXFER_TYPE_SYMLINK: fi->SetType(fi->SYMLINK); break; default: break; } if(a->flags&SSH_FILEXFER_ATTR_SIZE) fi->SetSize(a->size); if(a->flags&SSH_FILEXFER_ATTR_UIDGID) { char id[24]; snprintf(id,sizeof(id),"%u",a->uid); fi->SetUser(id); snprintf(id,sizeof(id),"%u",a->gid); fi->SetGroup(id); } if(a->flags&SSH_FILEXFER_ATTR_OWNERGROUP) { fi->SetUser (utf8_to_lc(a->owner)); fi->SetGroup(utf8_to_lc(a->group)); } if(a->flags&SSH_FILEXFER_ATTR_PERMISSIONS) fi->SetMode(a->permissions&07777); if(a->flags&SSH_FILEXFER_ATTR_MODIFYTIME) fi->SetDate(a->mtime,0); } FileInfo *SFtp::MakeFileInfo(const NameAttrs *na) { const FileAttrs *a=&na->attrs; const char *name=utf8_to_lc(na->name); const char *longname=utf8_to_lc(na->longname); LogNote(10,"NameAttrs(name=\"%s\",type=%d,longname=\"%s\")\n",name?name:"",a->type,longname?longname:""); if(!name || !name[0]) return 0; if(name[0]=='~') name=dir_file(".",name); Ref fi(new FileInfo(name)); switch(a->type) { case SSH_FILEXFER_TYPE_REGULAR: case SSH_FILEXFER_TYPE_DIRECTORY: case SSH_FILEXFER_TYPE_SYMLINK: case SSH_FILEXFER_TYPE_UNKNOWN: break; default: return 0; } if(longname) fi->SetLongName(longname); MergeAttrs(fi.get_non_const(),a); if(fi->longname && !a->owner) { // try to extract owner/group from long name. Ref ls(FileInfo::parse_ls_line(fi->longname,0)); if(ls) { if(ls->user) fi->SetUser(ls->user); if(ls->group) fi->SetGroup(ls->group); if(ls->nlinks>0) fi->SetNlink(ls->nlinks); } } return fi.borrow(); } #undef super #define super DirList #include "ArgV.h" int SFtpDirList::Do() { int m=STALL; if(done) return m; if(buf->Eof()) { done=true; return MOVED; } if(!ubuf) { const char *cache_buffer=0; int cache_buffer_size=0; int err; const FileSet *fset_c; if(use_cache && FileAccess::cache->Find(session,dir,FA::LONG_LIST,&err, &cache_buffer,&cache_buffer_size,&fset_c)) { if(err) { SetErrorCached(cache_buffer); return MOVED; } ubuf=new IOBuffer(IOBuffer::GET); ubuf->Put(cache_buffer,cache_buffer_size); ubuf->PutEOF(); fset=new FileSet(fset_c); } else { session->Open(dir,FA::LONG_LIST); ubuf=new IOBufferFileAccess(session); if(FileAccess::cache->IsEnabled(session->GetHostName())) ubuf->Save(FileAccess::cache->SizeLimit()); } } const char *b; int len; ubuf->Get(&b,&len); if(b==0) // eof { if(!fset && session->IsOpen()) fset=session.Cast()->GetFileSet(); FileAccess::cache->Add(session,dir,FA::LONG_LIST,FA::OK,ubuf,fset); if(use_file_set) { fset->Sort(fset->BYNAME,false); for(fset->rewind(); fset->curr(); fset->next()) { FileInfo *fi=fset->curr(); buf->Put(fi->GetLongName()); buf->Put("\n"); } fset=0; } ubuf=0; dir=args->getnext(); if(!dir) buf->PutEOF(); else buf->Format("\n%s:\n",dir); return MOVED; } if(len>0) { if(!use_file_set) buf->Put(b,len); ubuf->Skip(len); m=MOVED; } if(ubuf->Error()) { SetError(ubuf->ErrorText()); m=MOVED; } return m; } SFtpDirList::SFtpDirList(SFtp *s,ArgV *a) : DirList(s,a) { use_file_set=true; args->rewind(); int opt; while((opt=args->getopt("fCFl"))!=EOF) { switch(opt) { case('a'): ls_options.show_all=true; break; case('C'): ls_options.multi_column=true; break; case('F'): ls_options.append_type=true; break; } } while(args->getindex()>1) args->delarg(1); // remove options. if(args->count()<2) args->Append(""); args->rewind(); dir=args->getnext(); if(args->getindex()+1count()) buf->Format("%s:\n",dir); } const char *SFtpDirList::Status() { if(ubuf && !ubuf->Eof() && session->IsOpen()) return xstring::format(_("Getting file list (%lld) [%s]"), (long long)session->GetPos(),session->CurrentStatus()); return ""; } void SFtpDirList::SuspendInternal() { super::SuspendInternal(); if(ubuf) ubuf->SuspendSlave(); } void SFtpDirList::ResumeInternal() { if(ubuf) ubuf->ResumeSlave(); super::ResumeInternal(); } #undef super #define super ListInfo int SFtpListInfo::Do() { int m=STALL; if(done) return m; if(!ubuf && !result) { const char *cache_buffer=0; int cache_buffer_size=0; int err; const FileSet *fset_c; if(use_cache && FileAccess::cache->Find(session,"",FA::LONG_LIST,&err, &cache_buffer,&cache_buffer_size,&fset_c)) { if(err) { SetErrorCached(cache_buffer); return MOVED; } ubuf=new IOBuffer(IOBuffer::GET); ubuf->Put(cache_buffer,cache_buffer_size); ubuf->PutEOF(); result=new FileSet(fset_c); } else { session->Open("",FA::LONG_LIST); ubuf=new IOBufferFileAccess(session); if(FileAccess::cache->IsEnabled(session->GetHostName())) ubuf->Save(FileAccess::cache->SizeLimit()); } } if(!result) { const char *b; int len; ubuf->Get(&b,&len); if(len>0) { ubuf->Skip(len); return MOVED; } if(ubuf->Error()) { SetError(ubuf->ErrorText()); return MOVED; } if(b) return m; // eof if(!result && session->IsOpen()) result=session.Cast()->GetFileSet(); FileAccess::cache->Add(session,"",FA::LONG_LIST,FA::OK,ubuf,result); result->Exclude(exclude_prefix,exclude); m=MOVED; } if(result && session->OpenMode()!=FA::ARRAY_INFO) { ubuf=0; result->ExcludeCompound(); result->rewind(); for(FileInfo *file=result->curr(); file!=0; file=result->next()) { file->need=0; if(file->defined & file->TYPE) { if(file->filetype==file->SYMLINK && follow_symlinks) { file->filetype=file->UNKNOWN; file->defined &= ~(file->SIZE|file->DATE|file->SYMLINK_DEF|file->MODE|file->TYPE|file->USER|file->GROUP); file->Need(file->SIZE|file->DATE|file->MODE|file->TYPE|file->USER|file->GROUP); } else if(file->filetype==file->SYMLINK) { // need the link target if(!file->Has(file->SYMLINK_DEF)) file->Need(file->SYMLINK_DEF); } } } session->GetInfoArray(result.get_non_const()); session->Roll(); m=MOVED; } if(session->OpenMode()==FA::ARRAY_INFO) { int res=session->Done(); if(res==FA::DO_AGAIN) return m; if(res==FA::IN_PROGRESS) return m; session->Close(); done=true; m=MOVED; } return m; } const char *SFtpListInfo::Status() { if(ubuf && !ubuf->Eof() && session->IsOpen()) return xstring::format(_("Getting file list (%lld) [%s]"), (long long)session->GetPos(),session->CurrentStatus()); return ""; } #include "modconfig.h" #ifdef MODULE_PROTO_SFTP void module_init() { SFtp::ClassInit(); } #endif lftp-4.9.2/src/QueueFeeder.h0000644000015000007670000000534612122060513012553 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef QUEUEFEEDER_H #define QUEUEFEEDER_H #include "CmdExec.h" class QueueFeeder : public CmdFeeder { struct QueueJob { xstring_c cmd; xstring_c pwd; xstring_c lpwd; QueueJob *next, *prev; QueueJob(): next(0), prev(0) {} } *jobs, *lastjob; xstring_c cur_pwd; xstring_c cur_lpwd; xstring buffer; /* remove the given job from the list */ void unlink_job(QueueJob *job); /* get the n'th job */ QueueJob *get_job(int n); /* get the n'th job, removed from the list: */ QueueJob *grab_job(int n); /* get all jobs (linked and removed from the list) * that match the cmd: */ QueueJob *grab_job(const char *cmd); /* get the next job in j that matches cmd (including j) */ static QueueJob *get_next_match(const char *cmd, QueueJob *j); void PrintJobs(const QueueJob *job, int v, const char *plur) const; xstring& FormatJobs(xstring& s,const QueueJob *job, int v, const char *plur) const; void insert_jobs(QueueJob *job, QueueJob *&lst_head, QueueJob *&lst_tail, QueueJob *before); void FreeList(QueueJob *j); public: const char *NextCmd(CmdExec *exec,const char *prompt); /* Add a command to the queue at a given position; a 0 position inserts at the end. */ void QueueCmd(const char *cmd, const char *pwd, const char *lpwd, int pos = 0, int verbose = 0); /* delete jobs (by index or wildcard expr) */ bool DelJob(int from, int v = 0); bool DelJob(const char *cmd, int v = 0); /* move one or more jobs (by index or wildcard expr). */ bool MoveJob(int from, int to, int v = 0); bool MoveJob(const char *cmd, int to, int v = 0); static int JobCount(const QueueJob *); int JobCount() const { return JobCount(jobs); } enum { PrintRequeue = 9999 }; xstring& FormatStatus(xstring&,int v,const char *prefix="\t") const; QueueFeeder(const char *pwd, const char *lpwd): jobs(0), lastjob(0), cur_pwd(pwd), cur_lpwd(lpwd) {} virtual ~QueueFeeder(); }; #endif//QUEUEFEEDER_H lftp-4.9.2/src/PatternSet.cc0000644000015000007670000000533712765453711012626 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "PatternSet.h" PatternSet::PatternSet() { chain=0; first=0; } void PatternSet::Add(Type t,Pattern *p) { chain=new PatternLink(t,p,chain); if(!first) first=chain; } void PatternSet::AddFirst(Type t,Pattern *p) { PatternLink *new_link=new PatternLink(t,p,NULL); if(!first) first=chain=new_link; else first->next=new_link; } PatternSet::Type PatternSet::GetFirstType() const { return first->type; } PatternSet::~PatternSet() { while(chain) { PatternLink *del=chain; chain=chain->next; delete del; } } bool PatternSet::Match(Type type,const char *str) const { for(PatternLink *scan=chain; scan; scan=scan->next) { if(scan->pattern->Match(str)) return scan->type==type; if(!scan->next) return scan->type!=type; } return false; } PatternSet::Glob::Glob(const char *p) : Pattern(p) { slash_count=0; for(p=pattern; *p; p++) if(*p=='/') slash_count++; } // abc/def.zip matches *.zip // abc/def/ghi matches def/g* bool PatternSet::Glob::Match(const char *str) { const char *scan=str+strlen(str); int countdown=slash_count; while(scan>str) { scan--; if(*scan=='/') { if(countdown==0) { scan++; break; } countdown--; } } return fnmatch(pattern,scan,FNM_PATHNAME)==0; } PatternSet::Regex::Regex(const char *p) : Pattern(p) { memset(&compiled,0,sizeof(compiled)); // safety. int errcode=regcomp(&compiled,pattern,REG_EXTENDED|REG_NOSUB); if(errcode) { size_t need=regerror(errcode,0,0,0); xstring& e=xstring::get_tmp(); e.get_space(need-1); e.set_length(regerror(errcode,0,e.get_non_const(),need)-1); error.setf(_("regular expression `%s': %s"),p,e.get()); } } PatternSet::Regex::~Regex() { if(!error) regfree(&compiled); } bool PatternSet::Regex::Match(const char *str) { if(error) return false; return regexec(&compiled,str,0,0,0)==0; } lftp-4.9.2/src/History.cc0000644000015000007670000001002112662070340012145 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2013 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "trio.h" #include "History.h" #include "url.h" #include "misc.h" #define super KeyValueDB History::History() { full=0; stamp=0; fd=-1; modified=false; const char *home=get_lftp_data_dir(); if(home) file.vset(home,"/cwd_history",NULL); } History::~History() { Close(); if(full) delete full; } const char *History::extract_url(const char *res) { const char *url=strchr(res,':'); if(url) url++; else url=res; if(url::is_url(url)) return url; return url::decode(url); } time_t History::extract_stamp(const char *res) { return atol(res); } const char *History::Lookup(const FileAccess *s) { const char *url=s->GetConnectURL(s->NO_PATH|s->NO_PASSWORD); if(!url) return 0; const char *res=super::Lookup(url); if(res) return extract_url(res); Refresh(); Close(); if(!full) return 0; res=full->Lookup(url); if(res) return extract_url(res); return 0; } void History::Refresh() { if(!file) return; struct stat st; if((fd==-1 ? stat(file,&st) : fstat(fd,&st)) == -1) return; if(st.st_mtime==stamp) return; Load(); } void History::Load() { if(full) full->Empty(); if(!file) return; if(fd==-1) { fd=open(file,O_RDONLY); if(fd==-1) return; fcntl(fd,F_SETFD,FD_CLOEXEC); if(Lock(fd,F_RDLCK)==-1) fprintf(stderr,"%s: lock for reading failed, trying to read anyway\n",file.get()); } if(!full) full=new KeyValueDB; struct stat st; fstat(fd,&st); stamp=st.st_mtime; lseek(fd,0,SEEK_SET); full->Read(dup(fd)); // Read closes fd } void History::Close() { if(fd!=-1) { close(fd); fd=-1; } } void History::Set(const FileAccess *s,const FileAccess::Path &cwd) { if(cwd.path==0 || !strcmp(cwd.path,"~") || s->GetHostName()==0) return; xstring res; res.setf("%lu:",(unsigned long)time(0)); if(!cwd.url) { res.append_url_encoded(cwd,URL_PATH_UNSAFE); if(!cwd.is_file && url::dir_needs_trailing_slash(s->GetProto()) && res.last_char()!='/') res.append('/'); } else res.append(cwd.url); super::Add(s->GetConnectURL(s->NO_PATH|s->NO_PASSWORD),res); modified=true; } void History::Save() { Close(); if(!file) return; if(!modified) return; fd=open(file,O_RDWR|O_CREAT,0600); if(fd==-1) return; fcntl(fd,F_SETFD,FD_CLOEXEC); if(Lock(fd,F_WRLCK)==-1) { fprintf(stderr,"%s: lock for writing failed\n",file.get()); Close(); return; } Refresh(); // merge int count=0; for(Pair *p=chain; p; p=p->next) { time_t new_stamp=extract_stamp(p->value); time_t old_stamp=0; const char *old_value=full->Lookup(p->key); if(old_value) old_stamp=extract_stamp(old_value); if(old_stampAdd(p->key,p->value); count++; } } if(count==0) { Close(); return; } lseek(fd,0,SEEK_SET); #ifdef HAVE_FTRUNCATE if(ftruncate(fd,0)==-1) // note the following statement #endif close(open(file,O_WRONLY|O_TRUNC)); full->Write(fd); fd=-1; // Write closes file } lftp-4.9.2/src/PtyShell.cc0000644000015000007670000001174213143027237012265 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "trio.h" #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_IOCTL_H # include #endif #include #include #include "PtyShell.h" #include "lftp_pty.h" #include "SignalHook.h" #include "ArgV.h" #include "misc.h" int PtyShell::getfd() { if(fd!=-1 || error() || closed) return fd; int ptyfd,ttyfd; pid_t pid; int pipe0[2]; int pipe1[2]; if(use_pipes) { if(pipe(pipe0)<0) return -1; if(pipe(pipe1)<0) { close(pipe0[0]); close(pipe0[1]); return -1; } } const char *tty_name=open_pty(&ptyfd,&ttyfd); if(!tty_name) { if(!NonFatalError(errno)) error_text.vset(_("pseudo-tty allocation failed: "),strerror(errno),NULL); if(use_pipes) { close(pipe0[0]); close(pipe0[1]); close(pipe1[0]); close(pipe1[1]); } return -1; } struct termios tc; tcgetattr(ttyfd,&tc); tc.c_lflag=0; tc.c_oflag=0; tc.c_iflag=0; tc.c_cc[VMIN]=1; tc.c_cc[VTIME]=0; tcsetattr(ttyfd,TCSANOW,&tc); ProcWait::Signal(false); fflush(stderr); switch(pid=fork()) { case(0): /* child */ close(ptyfd); if(use_pipes) { close(pipe0[1]); close(pipe1[0]); dup2(pipe0[0],0); dup2(pipe1[1],1); if(pipe0[0]>2) close(pipe0[0]); if(pipe1[1]>2) close(pipe1[1]); } else { dup2(ttyfd,0); dup2(ttyfd,1); } dup2(ttyfd,2); if(ttyfd>2) close(ttyfd); /* start new session */ setsid(); /* make the pseudo-tty our controlling tty */ #ifdef TIOCSCTTY /* use ioctl if available. FD 2 is tty even if use_pipes==true */ ioctl(2, TIOCSCTTY, NULL); #else /* otherwise open the tty without O_NOCTTY flag */ ttyfd=open(tty_name, O_RDWR); if(ttyfd>=0) close(ttyfd); #endif SignalHook::RestoreAll(); kill(getpid(),SIGSTOP); if(oldcwd) { if(chdir(oldcwd)==-1) { fprintf(stderr,_("chdir(%s) failed: %s\n"),oldcwd.get(),strerror(errno)); fflush(stderr); _exit(1); } } /* force the messages to be in english */ putenv((char*)"LC_ALL=C"); putenv((char*)"LANG=C"); putenv((char*)"LANGUAGE=C"); if(a) execvp(a->a0(),a->GetVNonConst()); execl("/bin/sh","sh","-c",name.get(),NULL); fprintf(stderr,_("execl(/bin/sh) failed: %s\n"),strerror(errno)); fflush(stderr); _exit(1); case(-1): /* error */ close(ttyfd); close(ptyfd); if(use_pipes) { close(pipe0[0]); close(pipe0[1]); close(pipe1[0]); close(pipe1[1]); } goto out; } /* parent */ if(pg==0) pg=pid; close(ttyfd); fd=ptyfd; fcntl(fd,F_SETFD,FD_CLOEXEC); fcntl(fd,F_SETFL,O_NONBLOCK); if(use_pipes) { close(pipe0[0]); pipe_out=pipe0[1]; close(pipe1[1]); pipe_in=pipe1[0]; fcntl(pipe_in,F_SETFD,FD_CLOEXEC); fcntl(pipe_in,F_SETFL,O_NONBLOCK); fcntl(pipe_out,F_SETFD,FD_CLOEXEC); fcntl(pipe_out,F_SETFL,O_NONBLOCK); } oldcwd.set(0); int info; waitpid(pid,&info,WUNTRACED); w=new ProcWait(pid); out: ProcWait::Signal(true); return fd; } void PtyShell::Init() { xgetcwd_to(oldcwd); pg=0; closed=false; use_pipes=false; pipe_in=-1; pipe_out=-1; } void PtyShell::SetCwd(const char *cwd) { oldcwd.set(cwd); } PtyShell::PtyShell(const char *filter) : FDStream(-1,filter) { Init(); } PtyShell::PtyShell(ArgV *a1) : FDStream(-1,0), a(a1) { Init(); a->CombineTo(name); } PtyShell::~PtyShell() { if(fd!=-1) close(fd); if(pipe_in!=-1) close(pipe_in); if(pipe_out!=-1) close(pipe_out); if(w) { w->Kill(); w.borrow()->Auto(); } } bool PtyShell::Done() { if(w==0) return true; if(fd!=-1) { close(fd); fd=-1; closed=true; } if(w->GetState()!=w->RUNNING) return true; return false; } bool PtyShell::broken() { if(w==0) return false; if(fd==-1) return false; if(w->GetState()!=w->RUNNING) return true; // filter process terminated - pipe is broken return false; } lftp-4.9.2/src/CopyJob.cc0000644000015000007670000001633013666253006012071 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "CopyJob.h" #include "ArgV.h" #include "plural.h" #include "misc.h" #include "url.h" #define waiting_num waiting.count() #define super Job int CopyJob::Do() { if(!c) return STALL; if(!fg_data) fg_data=c->GetFgData(fg); if(done) return STALL; if(c->Error()) { const char *error=c->ErrorText(); const char *name=GetDispName(); if(!strstr(error,name) && op.ne(name)) error=xstring::cat(name,": ",error,NULL); if(!quiet) eprintf("%s: %s\n",op.get(),error); done=true; return MOVED; } if(c->Done()) { done=true; return MOVED; } if(!c->WriteAllowed() && c->WritePending()) { if(no_status_on_write || clear_status_on_write) ClearStatus(); if(no_status_on_write) NoStatus(); // disable status. c->AllowWrite(); return MOVED; } return STALL; } int CopyJob::ExitCode() { if(c->Error()) return 1; return 0; } const char *CopyJob::SqueezeName(int w, bool base) { if(base) return squeeze_file_name(basename_ptr(GetDispName()),w); return squeeze_file_name(GetDispName(),w); } // xgettext:c-format static const char copy_status_format[]=N_("`%s' at %lld %s%s%s%s"); #define COPY_STATUS _(copy_status_format),name,\ (long long)c->GetPos(),c->GetPercentDoneStr(),c->GetRateStr(),\ c->GetETAStr(),c->GetStatus() const char *CopyJob::Status(const StatusLine *s, bool base) { if(c->Done() || c->Error()) return ""; const char *name=SqueezeName(s->GetWidthDelayed()-50, base); return xstring::format(COPY_STATUS); } void CopyJob::ShowRunStatus(const SMTaskRef& s) { if(no_status) return; s->Show("%s", Status(s, false)); } xstring& CopyJob::FormatStatus(xstring& s,int v,const char *prefix) { if(c->Done() || c->Error()) return s; if(no_status) return s; s.append(prefix); const char *name=GetDispName(); s.appendf(COPY_STATUS); s.append('\n'); return s; } int CopyJob::AcceptSig(int sig) { if(c==0 || GetProcGroup()==0) { if(sig==SIGINT || sig==SIGTERM) return WANTDIE; return STALL; } c->Kill(sig); if(sig!=SIGCONT) c->Kill(SIGCONT); return MOVED; } void CopyJob::SetDispName() { ParsedURL url(name,true); if(url.proto) dispname.set(url.path); else dispname.set(name); } CopyJob::CopyJob(FileCopy *c1,const char *name1,const char *op1) : c(c1), name(name1), op(op1), quiet(false) { done=false; no_status=false; no_status_on_write=false; clear_status_on_write=false; SetDispName(); } const char *CopyJob::FormatBytesTimeRate(off_t bytes,double time_spent) { if(bytes<=0) return ""; if(time_spent>=1) { xstring& msg=xstring::format( plural("%lld $#ll#byte|bytes$ transferred in %ld $#l#second|seconds$", (long long)bytes,long(time_spent+.5)), (long long)bytes,long(time_spent+.5)); double rate=bytes/time_spent; if(rate>=1) msg.appendf(" (%s)",Speedometer::GetStrProper(rate).get()); return msg; } return xstring::format(plural("%lld $#ll#byte|bytes$ transferred", (long long)bytes),(long long)bytes); } void CopyJob::PrepareToDie() { c=0; super::PrepareToDie(); } CopyJob::~CopyJob() { } #undef super // CopyJobEnv CopyJobEnv::CopyJobEnv(FileAccess *s,ArgV *a,bool cont1) : SessionJob(s), quiet(false) { args=a; args->rewind(); op=args?args->a0():"?"; done=false; cp=0; errors=0; count=0; parallel=ResMgr::Query("xfer:parallel",0); bytes=0; time_spent=0; no_status=false; cont=cont1; ascii=false; xgetcwd_to(cwd); } CopyJobEnv::~CopyJobEnv() { SetCopier(0,0); } int CopyJobEnv::Do() { int m=STALL; if(done) return m; if(waiting_numGetLocal()) { if(j->Error()) { // in case of errors, move the backup to original location j->GetLocal()->revert_backup(); } else { // now we can delete the old file, since there is a new one j->GetLocal()->remove_backup(); } } if(j->Error()) errors++; count++; bytes+=j->GetBytesCount(); if(cp==j) cp=0; Delete(j); if(waiting_num>0 && cp==0) cp=(CopyJob*)waiting[0]; if(waiting.count()==0) time_spent+=now-transfer_start_ts; return MOVED; } void CopyJobEnv::AddCopier(FileCopy *c,const char *n) { if(c==0) return; if(ascii) c->Ascii(); cp=cj_new?cj_new->New(c,n,op):new CopyJob(c,n,op); cp->Quiet(quiet); if(waiting.count()==0) transfer_start_ts=now; AddWaiting(cp); } void CopyJobEnv::SetCopier(FileCopy *c,const char *n) { while(waiting_num>0) { Job *j=waiting[0]; RemoveWaiting(j); Delete(j); } cp=0; AddCopier(c,n); } xstring& CopyJobEnv::FormatFinalWithPrefix(xstring& s,const char *p) { if(no_status) return s; if(count==errors) return s; if(bytes) s.appendf("%s%s\n",p,CopyJob::FormatBytesTimeRate(bytes,time_spent)); if(errors>0) { s.append(p); s.appendf(plural("Transfer of %d of %d $file|files$ failed\n",count), errors,count); } else if(count>1) { s.append(p); s.appendf(plural("Total %d $file|files$ transferred\n",count),count); } return s; } xstring& CopyJobEnv::FormatStatus(xstring& s,int v,const char *prefix) { SessionJob::FormatStatus(s,v,prefix); if(Done()) FormatFinalWithPrefix(s,prefix); return s; } void CopyJobEnv::SayFinal() { if(!quiet) printf("%s",FormatFinalWithPrefix(xstring::get_tmp(""),"").get()); } int CopyJobEnv::AcceptSig(int sig) { if(cp==0) { if(sig==SIGINT || sig==SIGTERM) return WANTDIE; return STALL; } int total; if(sig==SIGINT || sig==SIGTERM) total=WANTDIE; else total=STALL; for(int i=0; iAcceptSig(sig); if(res==WANTDIE) { RemoveWaiting(j); Delete(j); if(cp==j) cp=0; } else if(res==MOVED) total=MOVED; else if(res==STALL) { if(total==WANTDIE) total=MOVED; } } if(waiting_num>0 && cp==0) cp=(CopyJob*)waiting[0]; return total; } int CopyJobEnv::Done() { return done; } lftp-4.9.2/src/lftp_ssl.h0000644000015000007670000001034713614366325012220 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef LFTP_SSL_H #define LFTP_SSL_H #if USE_SSL # if USE_GNUTLS # include # elif USE_OPENSSL # include # include # include # include # include # endif #include "Ref.h" #include "xstring.h" class lftp_ssl_base { public: bool handshake_done; int fd; xstring_c hostname; enum handshake_mode_t { CLIENT, SERVER } handshake_mode; xstring error; bool fatal; bool cert_error; lftp_ssl_base(int fd,handshake_mode_t m,const char *host=0); enum code { RETRY=-2, ERROR=-1, DONE=0 }; void set_error(const char *s1,const char *s2); void set_cert_error(const char *s,const xstring& fp); }; #if USE_GNUTLS #include #if LFTP_LIBGNUTLS_VERSION_CODE < 0x010201 /* Compatibility defintions for old gnutls */ typedef gnutls_session gnutls_session_t; typedef gnutls_anon_server_credentials gnutls_anon_server_credentials_t; typedef gnutls_dh_params gnutls_dh_params_t; typedef gnutls_certificate_credentials gnutls_certificate_credentials_t; typedef gnutls_transport_ptr gnutls_transport_ptr_t; typedef gnutls_x509_crt gnutls_x509_crt_t; typedef gnutls_x509_crl gnutls_x509_crl_t; typedef gnutls_x509_crt_fmt gnutls_x509_crt_fmt_t; typedef gnutls_datum gnutls_datum_t; #endif #include "ResMgr.h" class lftp_ssl_gnutls_instance : public ResClient { gnutls_x509_crl_t *crl_list; unsigned crl_list_size; gnutls_x509_crt_t *ca_list; unsigned ca_list_size; friend class lftp_ssl_gnutls; void LoadCA(); void LoadCRL(); public: lftp_ssl_gnutls_instance(); ~lftp_ssl_gnutls_instance(); void Reconfig(const char *); }; class lftp_ssl_gnutls : public lftp_ssl_base { static Ref instance; gnutls_session_t session; gnutls_certificate_credentials_t cred; void verify_certificate_chain(const gnutls_datum_t *cert_chain,int cert_chain_length); void verify_cert2(gnutls_x509_crt_t crt,gnutls_x509_crt_t issuer); void verify_last_cert(gnutls_x509_crt_t crt); int do_handshake(); bool check_fatal(int res); static const xstring& get_fp(gnutls_x509_crt_t crt); public: static void global_init(); static void global_deinit(); lftp_ssl_gnutls(int fd,handshake_mode_t m,const char *host=0); ~lftp_ssl_gnutls(); int read(char *buf,int size); int write(const char *buf,int size); bool want_in(); bool want_out(); void copy_sid(const lftp_ssl_gnutls *); void load_keys(); void shutdown(); }; typedef lftp_ssl_gnutls lftp_ssl; #elif USE_OPENSSL class lftp_ssl_openssl_instance { public: SSL_CTX *ssl_ctx; X509_STORE *crl_store; lftp_ssl_openssl_instance(); ~lftp_ssl_openssl_instance(); }; class lftp_ssl_openssl : public lftp_ssl_base { static Ref instance; SSL *ssl; bool check_fatal(int res); int do_handshake(); const char *strerror(); static const xstring& get_fp(X509 *crt); public: static int verify_crl(X509_STORE_CTX *ctx); static int verify_callback(int ok,X509_STORE_CTX *ctx); void check_certificate(); static void global_init(); static void global_deinit(); lftp_ssl_openssl(int fd,handshake_mode_t m,const char *host=0); ~lftp_ssl_openssl(); int read(char *buf,int size); int write(const char *buf,int size); bool want_in(); bool want_out(); void copy_sid(const lftp_ssl_openssl *); void load_keys(); void shutdown(); }; typedef lftp_ssl_openssl lftp_ssl; #endif #endif//USE_SSL #endif//LFTP_SSL_H lftp-4.9.2/src/netrc.h0000644000015000007670000000221512122060345011462 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef NETRC_H #define NETRC_H #include "xstring.h" class NetRC { public: class Entry { public: xstring host; xstring user; xstring pass; xstring acct; Entry(const char *h=0,const char *u=0,const char *p=0,const char *a=0) : host(h), user(u), pass(p), acct(a) {} }; static Entry *LookupHost(const char *host,const char *user=0); }; #endif//NETRC_H lftp-4.9.2/src/netrc.cc0000644000015000007670000000676313715312243011642 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "trio.h" #include #include #include "xstring.h" #include "netrc.h" #include "log.h" static bool comment(const char *s, FILE *f) { if(s[0]!='#') return false; // skip entire line for(;;) { int ch=getc(f); if(ch==EOF || ch=='\n') break; } return true; } NetRC::Entry *NetRC::LookupHost(const char *h,const char *u) { char str[256]; char chost[256]=""; char cuser[256]=""; char cpass[256]=""; char cacct[256]=""; const char *const home=getenv("HOME"); if(!home) return 0; const char *const netrc=xstring::cat(home,"/.netrc",NULL); FILE *f=fopen(netrc,"r"); if(f==NULL) { Log::global->Format(10,"notice: cannot open %s: %s\n",netrc,strerror(errno)); return NULL; } bool host_found=false; bool user_found=false; while(fscanf(f,"%255s",str)==1) { if(comment(str,f)) continue; if(!strcmp(str,"macdef")) { // currently macdef is ignored if(fgets(str,255,f)==0) break; for(;;) { if(fgets(str,255,f)==0) break; if(str[strspn(str," \t\n")]==0) // macdef ends with empty line break; } continue; } if(!strcmp(str,"default")) { strcpy(chost,""); // ignore the default continue; } if(!strcmp(str,"machine")) { if(host_found && user_found) break; if(fscanf(f,"%255s",str)!=1) break; strcpy(chost,str); // reset data for new machine. cuser[0]=0; cpass[0]=0; cacct[0]=0; host_found=!strcasecmp(chost,h); user_found=false; continue; } if(!strcmp(str,"login")) { if(fscanf(f,"%255s",str)!=1) break; if(strcasecmp(chost,h)) continue; strcpy(cuser,str); cpass[0]=0; cacct[0]=0; user_found=(!u || !strcasecmp(cuser,u)); continue; } if(!strcmp(str,"password")) { if(fscanf(f,"%255s",str)!=1) break; if(strcasecmp(chost,h) || (u && strcasecmp(cuser,u)) || cpass[0]) continue; strcpy(cpass,str); for(char *s=cpass; *s; s++) { if(*s=='\\' && s[1]>='0' && s[1]<'8') { int ch=0; int n=0; if(sscanf(s+1,"%3o%n",&ch,&n)!=1) continue; if(ch==0) continue; *s=ch; memmove(s+1,s+1+n,strlen(s+1+n)+1); } } continue; } if(!strcmp(str,"account")) { if(fscanf(f,"%255s",str)!=1) break; if(strcasecmp(chost,h) || (u && strcasecmp(cuser,u)) || cacct[0]) continue; strcpy(cacct,str); continue; } } fclose(f); if(host_found && user_found) { Log::global->Format(10,"found netrc entry: host=%s, user=%s, pass=%s, acct=%s\n",h,cuser,cpass,cacct); return new Entry(h,cuser[0]?cuser:0,cpass[0]?cpass:0,cacct[0]?cacct:0); } return 0; } lftp-4.9.2/src/CharReader.h0000644000015000007670000000217212122057173012356 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef CHARREADER_H #define CHARREADER_H #include "SMTask.h" // CharReader fetches a single character from given file descriptor. class CharReader : public SMTask { int fd; int ch; int Do(); public: enum { NOCHAR=-2, EOFCHAR=-1 }; int GetChar() { return ch; }; CharReader(int new_fd) { fd=new_fd; ch=NOCHAR; } }; #endif//CHARREADER_H lftp-4.9.2/src/url.h0000644000015000007670000000551313143027212011155 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef URL_H #define URL_H #include "xstring.h" class ParsedURL { public: xstring_c proto; xstring_c user; xstring_c pass; xstring_c host; xstring_c port; xstring path; xstring_c orig_url; ParsedURL() {} ParsedURL(const char *url,bool proto_required=false,bool use_rfc1738=true); void parse(const char *url,bool proto_required=false,bool use_rfc1738=true); ~ParsedURL(); xstring& CombineTo(xstring &buf,const char *home=0,bool use_rfc1738=true) const; const char *CombineTo(xstring_c &buf,const char *home=0,bool use_rfc1738=true) const { xstring tmp; tmp.move_here(buf); return buf.move_here(CombineTo(tmp,home,use_rfc1738)); } // returns allocated memory char *Combine(const char *home=0,bool use_rfc1738=true); }; # define URL_UNSAFE " <>\"'%{}|\\^[]`" # define URL_PATH_UNSAFE URL_UNSAFE"#;?&+" # define URL_HOST_UNSAFE URL_UNSAFE":/" # define URL_PORT_UNSAFE URL_UNSAFE"/" # define URL_USER_UNSAFE URL_UNSAFE"/:@" # define URL_PASS_UNSAFE URL_UNSAFE"/:@" class url { public: char *proto; char *user; char *pass; char *host; char *port; char *path; url(const char *u); url(); ~url(); void SetPath(const char *p,const char *q=URL_PATH_UNSAFE); char *Combine(); // encode unsafe chars as %XY static const xstring& encode(const char *s,int len,const char *unsafe,unsigned flags=0); static const xstring& encode(const xstring &s,const char *unsafe,unsigned flags=0) { return encode(s,s.length(),unsafe,flags); } static const xstring& encode(const char *s,const char *unsafe,unsigned flags=0) { return encode(s,strlen(s),unsafe,flags); } static const xstring& decode(const char *) __attribute__((warn_unused_result)); static bool is_url(const char *p); static int path_index(const char *p); static const char *path_ptr(const char *p); static bool dir_needs_trailing_slash(const char *proto); static bool find_password_pos(const char *url,int *start,int *len); static const char *remove_password(const char *url); static const char *hide_password(const char *url); }; #endif//URL_H lftp-4.9.2/src/echoJob.h0000644000015000007670000000231512122057331011722 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ECHOJOB_H #define ECHOJOB_H #include "Job.h" #include "StatusLine.h" #include "OutputJob.h" class echoJob : public Job { JobRef output; public: int Do() { return STALL; } int Done(); int ExitCode(); void ShowRunStatus(const SMTaskRef&); echoJob(const char *buf, OutputJob *output); echoJob(const char *buf, int len, OutputJob *output); ~echoJob(); void Fg(); void Bg(); }; #endif // ECHOJOB_H lftp-4.9.2/src/buffer_std.h0000644000015000007670000000201412122057121012465 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BUFFER_STD_H #define BUFFER_STD_H #include "Job.h" #include "buffer.h" class IOBuffer_STDOUT : public IOBuffer { Job *master; int Put_LL(const char *buf,int size); public: IOBuffer_STDOUT(Job *m) : IOBuffer(PUT) { master=m; } }; #endif //BUFFER_STD_H lftp-4.9.2/src/OutputJob.h0000644000015000007670000000665512662070340012323 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef OUTPUTJOB_H #define OUTPUTJOB_H #include "Job.h" #include "FileCopy.h" #include "CopyJob.h" #include "Timer.h" class StatusBar; class OutputJob : public Job { /* Main CopyJob: */ CopyJob *input; /* CopyJob that sends to the output. (output may be equal to input) */ CopyJob *output; Ref tmp_buf; // to store data while !initialized Ref output_fd; // to initialize CopyJobs FileAccessRef fa; xstring_c fa_path; bool initialized; xstring_c a0; xstring_c filter; bool error; bool is_stdout; bool fail_if_broken; bool statusbar_redisplay; int width; bool is_a_tty; /* if true, we never contribute to the parent job's status * (Status() == "") */ bool no_status; Timer update_timer; void Init(const char *a0); void InitCopy(); /* Get the input FileCopyPeer */ const SMTaskRef& InputPeer() const; /* Get the output FileCopyPeer (the FileCopyPeer that's doing the final output) */ const SMTaskRef& OutputPeer() const; public: OutputJob(FDStream *output, const char *a0); OutputJob(const char *path, const char *a0, FA *fa=0); void PrepareToDie(); /* Set the main filter: */ void SetFilter(const char *f) { filter.set(f); } /* Prepend a filter before the main filter: */ void PreFilter(const char *f); void DontFailIfBroken(bool y=true) { fail_if_broken=!y; } bool Error(); int Done(); int Do(); void Put(const char *buf,int size); void Put(const char *buf) { Put(buf,strlen(buf)); } void Put(const xstring& str) { Put(str.get(),str.length()); } void Format(const char *f,...) PRINTF_LIKE(2,3); void PutEOF(); /* If sending large amounts of data, call this function and stop * sending if it returns true. (This always accept more input; * this is optional.) */ bool Full(); /* Get properties of the output: */ int GetWidth() const; bool IsTTY() const; /* Whether the ultimate destination is stdout: */ bool IsStdout() const { return is_stdout; } /* Whether the output is filtered: */ bool IsFiltered() const { return filter; } /* Call before showing a StatusLine on a job using this class. If it * returns false, don't display it. */ bool ShowStatusLine(const SMTaskRef&); /* For commands that stream output from servers, redisplaying the * statusbar when output becomes idle can be annoying, especially * if the line is rate-limited. */ void DontRedisplayStatusbar() { statusbar_redisplay=false; } const char *Status(const StatusLine *s); void Fg(); void Bg(); void SuspendInternal(); void ResumeInternal(); int AcceptSig(int sig); }; #endif lftp-4.9.2/src/log.cc0000644000015000007670000001024013143026657011277 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "xstring.h" #include "log.h" #include "SMTask.h" Ref Log::global; static ResType log_vars[] = { {"log:enabled", "no", ResMgr::BoolValidate}, {"log:level", "9", ResMgr::UNumberValidate}, {"log:show-time", "no", ResMgr::BoolValidate}, {"log:show-pid", "no", ResMgr::BoolValidate}, {"log:show-ctx", "no", ResMgr::BoolValidate}, {"log:file", "", ResMgr::FileCreatable}, {"log:max-size", "1M", ResMgr::UNumberValidate}, {"log:prefix-recv","<--- "}, {"log:prefix-send","---> "}, {"log:prefix-note","---- "}, {"log:prefix-error","**** "}, {0} }; static ResDecls log_vars_register(log_vars); Log::Log(const char *name) : name(name) { output=-1; need_close_output=false; tty_cb=0; enabled=false; level=0; tty=false; show_pid=true; show_time=true; show_context=true; at_line_start=true; Reconfig(0); } bool Log::WillOutput(int l) { if(!enabled || l>level || output==-1) return false; if(tty) { pid_t pg=tcgetpgrp(output); if(pg!=(pid_t)-1 && pg!=getpgrp()) return false; } return true; } void Log::Write(int l,const char *s,int len) { if(!WillOutput(l)) return; DoWrite(s,len); } void Log::DoWrite(const char *s,int len) { if(len==0) return; if(buf.length()==0 || buf.last_char()=='\n') { if(show_pid) buf.appendf("[%ld] ",(long)getpid()); if(show_time) buf.append(SMTask::now.IsoDateTime()).append(' '); if(show_context) { const char *ctx=SMTask::GetCurrentLogContext(); if(ctx) buf.append(ctx).append(' '); } } buf.append(s,len); if(buf.last_char()!='\n') return; if(tty_cb && tty) tty_cb(); int res=write(output,buf,buf.length()); if(res==-1) { if(E_RETRY(errno)) return; ResMgr::Set("log:enabled",name,"no"); return; } if(res==(int)buf.length()) buf.truncate(); else buf.set_substr(0,res,"",0); } void Log::Format(int l,const char *f,...) { if(!WillOutput(l)) return; va_list v; va_start(v,f); DoWrite(xstring::vformat(f,v)); va_end(v); } void Log::vFormat(int l,const char *f,va_list v) { if(!WillOutput(l)) return; DoWrite(xstring::vformat(f,v)); } void Log::Cleanup() { global=0; } Log::~Log() { CloseOutput(); } void Log::SetOutput(int o,bool need_close) { CloseOutput(); output=o; need_close_output=need_close; if(output!=-1) tty=isatty(output); } void Log::Reconfig(const char *n) { enabled=QueryBool("log:enabled"); level=Query("log:level"); show_time=QueryBool("log:show-time"); show_pid=QueryBool("log:show-pid"); show_context=QueryBool("log:show-ctx"); if(!n || !strcmp(n,"log:file")) { const char *file=Query("log:file"); int fd=2; bool need_close_fd=false; if(file && *file) { struct stat st; if(stat(file,&st)!=-1) { if(st.st_size > long(Query("log:max-size"))) { debug((9,"rotating log %s\n",file)); if(rename(file,xstring::cat(file,".old",NULL))==-1) debug((1,"rename(%s): %s\n",file,strerror(errno))); } } fd=open(file,O_WRONLY|O_CREAT|O_APPEND|O_NONBLOCK,0600); if(fd==-1) { perror(file); fd=2; } else { need_close_fd=true; fcntl(fd,F_SETFD,FD_CLOEXEC); } } if(fd!=output) SetOutput(fd,need_close_fd); } } lftp-4.9.2/src/SFtp.h0000644000015000007670000005674613614366326011264 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SFTP_H #define SFTP_H #include "SSH_Access.h" #include "StatusLine.h" #include #include #include "FileSet.h" class SFtp : public SSH_Access { int protocol_version; const char *lc_to_utf8(const char *); const char *utf8_to_lc(const char *); public: enum packet_type { SSH_FXP_INIT =1, SSH_FXP_VERSION =2, SSH_FXP_OPEN =3, SSH_FXP_CLOSE =4, SSH_FXP_READ =5, SSH_FXP_WRITE =6, SSH_FXP_LSTAT =7, SSH_FXP_FSTAT =8, SSH_FXP_SETSTAT =9, SSH_FXP_FSETSTAT =10, SSH_FXP_OPENDIR =11, SSH_FXP_READDIR =12, SSH_FXP_REMOVE =13, SSH_FXP_MKDIR =14, SSH_FXP_RMDIR =15, SSH_FXP_REALPATH =16, SSH_FXP_STAT =17, SSH_FXP_RENAME =18, // v>=2 SSH_FXP_READLINK =19, // v>=3 SSH_FXP_SYMLINK =20, // v<=5 SSH_FXP_LINK =21, // v>=6 SSH_FXP_BLOCK =22, // v>=6 SSH_FXP_UNBLOCK =23, // v>=6 SSH_FXP_STATUS =101, SSH_FXP_HANDLE =102, SSH_FXP_DATA =103, SSH_FXP_NAME =104, SSH_FXP_ATTRS =105, SSH_FXP_EXTENDED =200, SSH_FXP_EXTENDED_REPLY=201 }; #define SSH_FILEXFER_ATTR_SIZE 0x00000001 #define SSH_FILEXFER_ATTR_UIDGID 0x00000002 // v<=3 #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004 #define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008 #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008 // v<=3 #define SSH_FILEXFER_ATTR_CREATETIME 0x00000010 #define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020 #define SSH_FILEXFER_ATTR_ACL 0x00000040 #define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080 #define SSH_FILEXFER_ATTR_SUBSECOND_TIMES 0x00000100 #define SSH_FILEXFER_ATTR_BITS 0x00000200 // v>=5 #define SSH_FILEXFER_ATTR_ALLOCATION_SIZE 0x00000400 // v>=6 #define SSH_FILEXFER_ATTR_TEXT_HINT 0x00000800 // v>=6 #define SSH_FILEXFER_ATTR_MIME_TYPE 0x00001000 // v>=6 #define SSH_FILEXFER_ATTR_LINK_COUNT 0x00002000 // v>=6 #define SSH_FILEXFER_ATTR_UNTRANSLATED_NAME 0x00004000 // v>=6 #define SSH_FILEXFER_ATTR_CTIME 0x00008000 // v>=6 #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000 #define SSH_FILEXFER_ATTR_MASK_V3 0x8000000F #define SSH_FILEXFER_ATTR_MASK_V4 0x800001FD #define SSH_FILEXFER_ATTR_MASK_V5 0x800003FD #define SSH_FILEXFER_ATTR_MASK_V6 0x8000FFFD // BITS values (v>=5) #define SSH_FILEXFER_ATTR_FLAGS_READONLY 0x00000001 #define SSH_FILEXFER_ATTR_FLAGS_SYSTEM 0x00000002 #define SSH_FILEXFER_ATTR_FLAGS_HIDDEN 0x00000004 #define SSH_FILEXFER_ATTR_FLAGS_CASE_INSENSITIVE 0x00000008 #define SSH_FILEXFER_ATTR_FLAGS_ARCHIVE 0x00000010 #define SSH_FILEXFER_ATTR_FLAGS_ENCRYPTED 0x00000020 #define SSH_FILEXFER_ATTR_FLAGS_COMPRESSED 0x00000040 #define SSH_FILEXFER_ATTR_FLAGS_SPARSE 0x00000080 #define SSH_FILEXFER_ATTR_FLAGS_APPEND_ONLY 0x00000100 #define SSH_FILEXFER_ATTR_FLAGS_IMMUTABLE 0x00000200 #define SSH_FILEXFER_ATTR_FLAGS_SYNC 0x00000400 enum sftp_file_type { SSH_FILEXFER_TYPE_REGULAR =1, SSH_FILEXFER_TYPE_DIRECTORY =2, SSH_FILEXFER_TYPE_SYMLINK =3, SSH_FILEXFER_TYPE_SPECIAL =4, SSH_FILEXFER_TYPE_UNKNOWN =5, SSH_FILEXFER_TYPE_SOCKET =6, // v>=5 SSH_FILEXFER_TYPE_CHAR_DEVICE =7, // v>=5 SSH_FILEXFER_TYPE_BLOCK_DEVICE=8, // v>=5 SSH_FILEXFER_TYPE_FIFO =9 // v>=5 }; // open modes (v<=4) #define SSH_FXF_READ 0x00000001 #define SSH_FXF_WRITE 0x00000002 #define SSH_FXF_APPEND 0x00000004 #define SSH_FXF_CREAT 0x00000008 #define SSH_FXF_TRUNC 0x00000010 #define SSH_FXF_EXCL 0x00000020 // open flags values (v>=5) #define SSH_FXF_ACCESS_DISPOSITION 0x00000007 #define SSH_FXF_CREATE_NEW 0x00000000 #define SSH_FXF_CREATE_TRUNCATE 0x00000001 #define SSH_FXF_OPEN_EXISTING 0x00000002 #define SSH_FXF_OPEN_OR_CREATE 0x00000003 #define SSH_FXF_TRUNCATE_EXISTING 0x00000004 #define SSH_FXF_ACCESS_APPEND_DATA 0x00000008 #define SSH_FXF_ACCESS_APPEND_DATA_ATOMIC 0x00000010 #define SSH_FXF_ACCESS_TEXT_MODE 0x00000020 #define SSH_FXF_ACCESS_READ_LOCK 0x00000040 #define SSH_FXF_ACCESS_WRITE_LOCK 0x00000080 #define SSH_FXF_ACCESS_DELETE_LOCK 0x00000100 #define SSH_FXF_ACCESS_BLOCK_ADVISORY 0x00000200 // v>=6 #define SSH_FXF_ACCESS_NOFOLLOW 0x00000400 // v>=6 #define SSH_FXF_ACCESS_DELETE_ON_CLOSE 0x00000800 // v>=6 // ACL masks #define ACE4_READ_DATA 0x00000001 #define ACE4_LIST_DIRECTORY 0x00000001 #define ACE4_WRITE_DATA 0x00000002 #define ACE4_ADD_FILE 0x00000002 #define ACE4_APPEND_DATA 0x00000004 #define ACE4_ADD_SUBDIRECTORY 0x00000004 #define ACE4_READ_NAMED_ATTRS 0x00000008 #define ACE4_WRITE_NAMED_ATTRS 0x00000010 #define ACE4_EXECUTE 0x00000020 #define ACE4_DELETE_CHILD 0x00000040 #define ACE4_READ_ATTRIBUTES 0x00000080 #define ACE4_WRITE_ATTRIBUTES 0x00000100 #define ACE4_DELETE 0x00010000 #define ACE4_READ_ACL 0x00020000 #define ACE4_WRITE_ACL 0x00040000 #define ACE4_WRITE_OWNER 0x00080000 #define ACE4_SYNCHRONIZE 0x00100000 // RENAME flags (v>=5) #define SSH_FXF_RENAME_OVERWRITE 0x00000001 #define SSH_FXF_RENAME_ATOMIC 0x00000002 #define SSH_FXF_RENAME_NATIVE 0x00000004 enum sftp_status_t { SSH_FX_OK =0, SSH_FX_EOF =1, SSH_FX_NO_SUCH_FILE =2, SSH_FX_PERMISSION_DENIED =3, SSH_FX_FAILURE =4, SSH_FX_BAD_MESSAGE =5, SSH_FX_NO_CONNECTION =6, SSH_FX_CONNECTION_LOST =7, SSH_FX_OP_UNSUPPORTED =8, SSH_FX_INVALID_HANDLE =9, SSH_FX_NO_SUCH_PATH =10, SSH_FX_FILE_ALREADY_EXISTS=11, SSH_FX_WRITE_PROTECT =12, SSH_FX_NO_MEDIA =13, SSH_FX_NO_SPACE_ON_FILESYSTEM =14, SSH_FX_QUOTA_EXCEEDED =15, SSH_FX_UNKNOWN_PRINCIPAL =16, SSH_FX_LOCK_CONFLICT =17, SSH_FX_DIR_NOT_EMPTY =18, SSH_FX_NOT_A_DIRECTORY =19, SSH_FX_INVALID_FILENAME =20, SSH_FX_LINK_LOOP =21, SSH_FX_CANNOT_DELETE =22, SSH_FX_INVALID_PARAMETER =23, SSH_FX_FILE_IS_A_DIRECTORY =24, SSH_FX_BYTE_RANGE_LOCK_CONFLICT =25, SSH_FX_BYTE_RANGE_LOCK_REFUSED =26, SSH_FX_DELETE_PENDING =27, SSH_FX_FILE_CORRUPT =28, SSH_FX_OWNER_INVALID =29, SSH_FX_GROUP_INVALID =30 }; private: enum state_t { DISCONNECTED, CONNECTING, CONNECTING_1, CONNECTING_2, CONNECTED, FILE_RECV, FILE_SEND, WAITING, DONE }; state_t state; unsigned ssh_id; xstring handle; void Init(); void SendMethod(); void SendArrayInfoRequests(); Ref send_translate; Ref recv_translate; Ref file_buf; Ref file_set; Timer flush_timer; void DisconnectLL(); int IsConnected() const { if(state==DISCONNECTED) return 0; if(state==CONNECTING) return 1; return 2; } const char *SkipHome(const char *path); const char *WirePath(const char *path); public: enum unpack_status_t { UNPACK_SUCCESS=0, UNPACK_WRONG_FORMAT=-1, UNPACK_PREMATURE_EOF=-2, UNPACK_NO_DATA_YET=1 }; class Packet { static bool is_valid_reply(int p) { return p==SSH_FXP_VERSION || (p>=101 && p<=105) || p==SSH_FXP_EXTENDED_REPLY; } protected: int length; int unpacked; packet_type type; unsigned id; Packet(packet_type t) { type=t; length=1; if(HasID()) length+=4; } bool HasID(); public: Packet() { length=0; } virtual void ComputeLength() { length=1+4*HasID(); } virtual void Pack(Buffer *b) { b->PackUINT32BE(length); b->PackUINT8(type); if(HasID()) b->PackUINT32BE(id); } virtual unpack_status_t Unpack(const Buffer *b); virtual ~Packet() {} int GetLength() { return length; } packet_type GetPacketType() { return type; } const char *GetPacketTypeText(); unsigned GetID() const { return id; } const xstring& GetKey() { return xstring::get_tmp((const char*)&id,sizeof(id)); } void SetID(unsigned new_id) { id=new_id; } void DropData(Buffer *b) { b->Skip(4+(length>0?length:0)); } bool TypeIs(packet_type t) const { return type==t; } static unpack_status_t UnpackString(const Buffer *b,int *offset,int limit,xstring *str_out); static void PackString(Buffer *b,const char *str,int len=-1); }; private: unpack_status_t UnpackPacket(Buffer *,Packet **); class PacketUINT32 : public Packet { protected: unsigned data; PacketUINT32(packet_type t,unsigned d=0) : Packet(t) { data=d; length+=4; } unpack_status_t Unpack(const Buffer *b) { unpack_status_t res; res=Packet::Unpack(b); if(res!=UNPACK_SUCCESS) return res; data=b->UnpackUINT32BE(unpacked); unpacked+=4; return UNPACK_SUCCESS; } void ComputeLength() { Packet::ComputeLength(); length+=4; } void Pack(Buffer *b) { Packet::Pack(b); b->PackUINT32BE(data); } }; class PacketSTRING : public Packet { protected: xstring string; PacketSTRING(packet_type t) : Packet(t) { length=4; } PacketSTRING(packet_type t,const xstring &s) : Packet(t) { string.set(s); length+=4+string.length(); } unpack_status_t Unpack(const Buffer *b); void ComputeLength() { Packet::ComputeLength(); length+=4+string.length(); } void Pack(Buffer *b) { Packet::Pack(b); Packet::PackString(b,string,string.length()); } const char *GetString() { return string; } int GetStringLength() { return string.length(); } }; class Request_INIT : public PacketUINT32 { public: Request_INIT(int v) : PacketUINT32(SSH_FXP_INIT,v) {} }; class Reply_VERSION : public PacketUINT32 { char **extension_name; char **extension_data; public: Reply_VERSION() : PacketUINT32(SSH_FXP_VERSION) {} unpack_status_t Unpack(const Buffer *b) { unpack_status_t res; res=PacketUINT32::Unpack(b); if(res!=UNPACK_SUCCESS) return res; // FIXME: unpack extensions. return res; } unsigned GetVersion() { return data; } }; class Request_REALPATH : public PacketSTRING { public: Request_REALPATH(const char *p) : PacketSTRING(SSH_FXP_REALPATH,p) {} }; class Request_FSTAT : public PacketSTRING { unsigned flags; int protocol_version; public: Request_FSTAT(const xstring &h,unsigned f,int pv) : PacketSTRING(SSH_FXP_FSTAT,h) { flags=f; protocol_version=pv; } void ComputeLength() { PacketSTRING::ComputeLength(); if(protocol_version>=4) length+=4; } void Pack(Buffer *b) { PacketSTRING::Pack(b); if(protocol_version>=4) b->PackUINT32BE(flags); } }; class Request_STAT : public Request_FSTAT { public: Request_STAT(const char *p,unsigned f,int pv) : Request_FSTAT(p,f,pv) { type=SSH_FXP_STAT; } const char *GetName() { return string; } }; public: struct FileAttrs { struct ExtFileAttr { xstring extended_type; xstring extended_data; unpack_status_t Unpack(const Buffer *b,int *offset,int limit); void Pack(Buffer *b); }; struct FileACE { unsigned ace_type; unsigned ace_flag; unsigned ace_mask; xstring who; FileACE() { ace_type=ace_flag=ace_mask=0; } unpack_status_t Unpack(const Buffer *b,int *offset,int limit); void Pack(Buffer *b); }; unsigned flags; int type; // v>=4 off_t size; // present only if flag SIZE xstring owner; // present only if flag OWNERGROUP // v>=4 xstring group; // present only if flag OWNERGROUP // v>=4 unsigned uid; // present only if flag UIDGID // v<=3 unsigned gid; // present only if flag UIDGID // v<=3 unsigned permissions; // present only if flag PERMISSIONS time_t atime; // present only if flag ACCESSTIME (ACMODTIME) unsigned atime_nseconds; // present only if flag SUBSECOND_TIMES time_t createtime; // present only if flag CREATETIME unsigned createtime_nseconds; // present only if flag SUBSECOND_TIMES time_t mtime; // present only if flag MODIFYTIME (ACMODTIME) unsigned mtime_nseconds; // present only if flag SUBSECOND_TIMES time_t ctime; // present only if flag CTIME // v>=6 unsigned ctime_nseconds; // present only if flag SUBSECOND_TIMES // v>=6 unsigned ace_count; // present only if flag ACL FileACE *ace; unsigned attrib_bits; // if flag BITS // v>=5 unsigned attrib_bits_valid; // if flag BITS // v>=6 unsigned char text_hint; // if flag TEXT_HINT // v>=6 xstring mime_type; // if flag MIME_TYPE // v>=6 unsigned link_count; // if flag LINK_COUNT // v>=6 xstring untranslated_name; // if flag UNTRANSLATED_NAME // v>=6 unsigned extended_count; // present only if flag EXTENDED ExtFileAttr *extended_attrs; FileAttrs() { flags=0; type=0; size=NO_SIZE; uid=gid=0; permissions=0; atime=createtime=mtime=ctime=NO_DATE; atime_nseconds=createtime_nseconds=mtime_nseconds=ctime_nseconds=0; extended_count=0; extended_attrs=0; ace_count=0; ace=0; attrib_bits=attrib_bits_valid=0; text_hint=0; link_count=0; } ~FileAttrs(); unpack_status_t Unpack(const Buffer *b,int *offset,int limit,int proto_version); void Pack(Buffer *b,int proto_version); int ComputeLength(int v); }; struct NameAttrs { xstring name; xstring longname; FileAttrs attrs; unpack_status_t Unpack(const Buffer *b,int *offset,int limit,int proto_version); }; private: class Reply_NAME : public Packet { int protocol_version; int count; NameAttrs *names; bool eof; public: Reply_NAME(int pv) : Packet(SSH_FXP_NAME) { protocol_version=pv; eof=false; } ~Reply_NAME() { delete[] names; } unpack_status_t Unpack(const Buffer *b); int GetCount() { return count; } const NameAttrs *GetNameAttrs(int index) { if(index>count) return 0; return &names[index]; } bool Eof() { return eof; } }; class Reply_ATTRS : public Packet { int protocol_version; FileAttrs attrs; public: Reply_ATTRS(int pv) : Packet(SSH_FXP_ATTRS) { protocol_version=pv; } unpack_status_t Unpack(const Buffer *b); const FileAttrs *GetAttrs() { return &attrs; } }; class PacketSTRING_ATTRS : public PacketSTRING { protected: int protocol_version; public: FileAttrs attrs; PacketSTRING_ATTRS(packet_type type,const xstring &h,int pv) : PacketSTRING(type,h) { protocol_version=pv; } void ComputeLength() { PacketSTRING::ComputeLength(); length+=attrs.ComputeLength(protocol_version); } void Pack(Buffer *b) { PacketSTRING::Pack(b); attrs.Pack(b,protocol_version); } }; class Request_FSETSTAT : public PacketSTRING_ATTRS { public: Request_FSETSTAT(const xstring &h,int pv) : PacketSTRING_ATTRS(SSH_FXP_FSETSTAT,h,pv) {} }; class Request_OPEN : public PacketSTRING_ATTRS { unsigned pflags; // v<=4 unsigned desired_access; // v>=5 unsigned flags; // v>=5 public: Request_OPEN(const char *fn,unsigned pf,unsigned da,unsigned f,int pv) : PacketSTRING_ATTRS(SSH_FXP_OPEN,fn,pv) { pflags=pf; desired_access=da; flags=f; } void ComputeLength() { PacketSTRING_ATTRS::ComputeLength(); length+=4+4*(protocol_version>=5); } void Pack(Buffer *b); }; class Reply_HANDLE : public PacketSTRING { public: Reply_HANDLE() : PacketSTRING(SSH_FXP_HANDLE) {} const xstring &GetHandle() { return string; } }; class Request_CLOSE : public PacketSTRING { public: Request_CLOSE(const xstring &h) : PacketSTRING(SSH_FXP_CLOSE,h) {} }; class Request_OPENDIR : public PacketSTRING { public: Request_OPENDIR(const char *name) : PacketSTRING(SSH_FXP_OPENDIR,name) {} }; class Request_READDIR : public PacketSTRING { public: Request_READDIR(const xstring &h) : PacketSTRING(SSH_FXP_READDIR,h) {} }; class Reply_STATUS : public Packet { int protocol_version; unsigned code; xstring message; xstring language; public: Reply_STATUS(int pv) { protocol_version=pv; code=0; } unpack_status_t Unpack(const Buffer *b); int GetCode() { return code; } const char *GetCodeText(); const char *GetMessage() { return message; } }; class Request_READ : public PacketSTRING { public: off_t pos; unsigned len; Request_READ(const xstring &h,off_t p,unsigned l) : PacketSTRING(SSH_FXP_READ,h) { pos=p; len=l; } void ComputeLength() { PacketSTRING::ComputeLength(); length+=8+4; } void Pack(Buffer *b); }; class Reply_DATA : public PacketSTRING { bool eof; public: Reply_DATA() : PacketSTRING(SSH_FXP_DATA) { eof=false; } void GetData(const char **b,int *s) { *b=string; *s=string.length(); } unpack_status_t Unpack(const Buffer *b); bool Eof() { return eof; } }; class Request_WRITE : public PacketSTRING { public: off_t pos; xstring data; Request_WRITE(const xstring &h,off_t p,const char *d,unsigned l) : PacketSTRING(SSH_FXP_WRITE,h) { pos=p; data.nset(d,l); } void ComputeLength() { PacketSTRING::ComputeLength(); length+=8+4+data.length(); } void Pack(Buffer *b); }; class Request_MKDIR : public PacketSTRING_ATTRS { public: Request_MKDIR(const char *fn,int pv) : PacketSTRING_ATTRS(SSH_FXP_MKDIR,fn,pv) {} }; class Request_SETSTAT : public PacketSTRING_ATTRS { public: Request_SETSTAT(const char *fn,int pv) : PacketSTRING_ATTRS(SSH_FXP_SETSTAT,fn,pv) {} }; class Request_RMDIR : public PacketSTRING { public: Request_RMDIR(const char *fn) : PacketSTRING(SSH_FXP_RMDIR,fn) {} }; class Request_REMOVE : public PacketSTRING { public: Request_REMOVE(const char *fn) : PacketSTRING(SSH_FXP_REMOVE,fn) {} }; class Request_RENAME : public Packet { int protocol_version; xstring oldpath; xstring newpath; unsigned flags; public: Request_RENAME(const char *o,const char *n,unsigned f,int pv) : Packet(SSH_FXP_RENAME), oldpath(o), newpath(n) { protocol_version=pv; flags=f; } void ComputeLength(); void Pack(Buffer *b); }; class Request_READLINK : public PacketSTRING { public: Request_READLINK(const char *name) : PacketSTRING(SSH_FXP_READLINK,name) {} }; class Request_SYMLINK : public Packet { xstring oldpath; xstring newpath; public: Request_SYMLINK(const char *o,const char *n) : Packet(SSH_FXP_SYMLINK), oldpath(o), newpath(n) {} void ComputeLength() { Packet::ComputeLength(); length+=4+strlen(oldpath)+4+strlen(newpath); } void Pack(Buffer *b); }; class Request_LINK : public Packet { xstring oldpath; xstring newpath; bool symbolic; public: Request_LINK(const char *o,const char *n,bool s) : Packet(SSH_FXP_LINK), oldpath(o), newpath(n), symbolic(s) {} void ComputeLength() { Packet::ComputeLength(); length+=4+strlen(oldpath)+4+strlen(newpath)+1; } void Pack(Buffer *b); }; struct Expect; friend struct SFtp::Expect; // grant access to Packet. struct Expect { enum expect_t { HOME_PATH, FXP_VERSION, CWD, HANDLE, HANDLE_STALE, DATA, INFO, INFO_READLINK, DEFAULT, WRITE_STATUS, IGNORE }; Ref request; Ref reply; int i; expect_t tag; Expect(Packet *req,expect_t t,int j=0) : request(req), i(j), tag(t) {} bool has_data_at_pos(off_t pos) const { if(!reply->TypeIs(SSH_FXP_DATA) || !request->TypeIs(SSH_FXP_READ)) return false; return request.Cast()->pos==pos; } }; void PushExpect(Expect *); int HandleReplies(); int HandlePty(); void HandleExpect(Expect *); void CloseExpectQueue(); bool HasExpect(Expect::expect_t tag); bool HasExpectBefore(unsigned id,Expect::expect_t tag); void CloseHandle(Expect::expect_t e); int ReplyLogPriority(int); xmap_p expect_queue; Expect *FindExpectExclusive(Packet *reply); xarray_p ooo_chain; // out of order replies buffered int RespQueueSize() const { return expect_queue.count(); } int RespQueueIsEmpty() const { return RespQueueSize()==0; } void EmptyRespQueue() { expect_queue.empty(); ooo_chain.truncate(); } bool GetBetterConnection(int level,bool limit_reached); void MoveConnectionHere(SFtp *o); bool eof; void SendRequest(); void SendRequest(Packet *req,Expect::expect_t exp,int i=0); void SendRequestGeneric(int type); void RequestMoreData(); off_t request_pos; void MergeAttrs(FileInfo *fi,const FileAttrs *a); FileInfo *MakeFileInfo(const NameAttrs *a); int max_packets_in_flight; int max_packets_in_flight_slow_start; int size_read; int size_write; bool use_full_path; protected: void SetError(int code,const Packet *reply); void SetError(int code,const char *mess=0) { FA::SetError(code,mess); } public: static void ClassInit(); SFtp(); SFtp(const SFtp*); ~SFtp(); const char *GetProto() const { return "sftp"; } FileAccess *Clone() const { return new SFtp(this); } static FileAccess *New(); int Do(); int Done(); int Read(Buffer *,int); int Write(const void *,int); int StoreStatus(); int Buffered(); void Close(); const char *CurrentStatus(); void Reconfig(const char *name=0); bool SameSiteAs(const FileAccess *fa) const; bool SameLocationAs(const FileAccess *fa) const; DirList *MakeDirList(ArgV *args); Glob *MakeGlob(const char *pattern); ListInfo *MakeListInfo(const char *dir); bool NeedSizeDateBeforehand() { return false; } void SuspendInternal(); void ResumeInternal(); FileSet *GetFileSet(); }; class SFtpDirList : public DirList { SMTaskRef ubuf; const char *dir; bool use_file_set; Ref fset; LsOptions ls_options; public: SFtpDirList(SFtp *s,ArgV *a); const char *Status(); int Do(); void SuspendInternal(); void ResumeInternal(); }; class SFtpListInfo : public ListInfo { SMTaskRef ubuf; public: SFtpListInfo(SFtp *session,const char *dir) : ListInfo(session,dir) {} int Do(); const char *Status(); }; #endif lftp-4.9.2/src/GetFileInfo.h0000644000015000007670000000434412133433750012515 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GETFILEINFO_H #define GETFILEINFO_H #include "trio.h" #include "SMTask.h" #include "FileAccess.h" class GetFileInfo : public ListInfo { const FileAccessRef& session; SMTaskRef li; /* file or dir we're listing: */ xstring_c dir; /* directory we've actually listed: */ xstring_c path_to_prefix; /* directory we started in: */ FileAccess::Path origdir; /* In showdir mode, we make sure the path actually exists; this is * the filename to look for. */ xstring verify_fn; bool showdir; enum state_t { INITIAL, CHANGE_DIR, CHANGING_DIR, GETTING_LIST, GETTING_INFO_ARRAY, DONE } state; /* whether we've tried to cd to the whole dir (treating it as a dir): */ bool tried_dir; /* and whether we've tried to cd to the basename (treating it as a file): */ bool tried_file; /* and the last-ditch GetInfoArray */ bool tried_info; /* whether we found out the file type from cache */ bool from_cache; /* whether the given path was a file or directory. */ bool was_directory; /* if true, prepend the appropriate relative path to the result */ bool prepend_path; xstring_c saved_error_text; FileSet get_info; void PrepareToDie(); public: GetFileInfo(const FileAccessRef& a, const char *path, bool showdir); virtual ~GetFileInfo(); int Do(); const char *Status(); bool WasDirectory() const { return was_directory; } void DontPrependPath() { prepend_path=false; } }; #endif /* GETFILEINFO_H */ lftp-4.9.2/src/buffer_zlib.cc0000644000015000007670000001061013062512164013001 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "buffer_zlib.h" void DataInflator::PutTranslated(Buffer *target,const char *put_buf,int size) { bool from_untranslated=false; if(Size()>0) { Put(put_buf,size); Get(&put_buf,&size); from_untranslated=true; } // process all data we can, save the rest in the untranslated buffer while(size>0) { if(z_err==Z_STREAM_END) { // assume the data after the compressed stream are not compressed. target->Put(put_buf,size); if(from_untranslated) Skip(size); return; } size_t put_size=size; int size_coeff=6; size_t store_size=size_coeff*put_size+256; char *store_buf=target->GetSpace(store_size); // do the inflation z.next_in=(Bytef*)put_buf; z.avail_in=put_size; z.next_out=(Bytef*)store_buf; z.avail_out=store_size; int ret = inflate(&z, Z_NO_FLUSH); switch (ret) { case Z_OK: break; case Z_STREAM_END: z_err=ret; PutEOF(); break; case Z_NEED_DICT: ret = Z_DATA_ERROR; if(!z.msg) z.msg=const_cast("missing dictionary"); /* fallthrough */ default: z_err=ret; target->SetError(xstring::cat("zlib inflate error: ",z.msg,NULL),true); return; } int inflated_size=store_size-z.avail_out; int processed_size=put_size-z.avail_in; target->SpaceAdd(inflated_size); if(from_untranslated) { Skip(processed_size); Get(&put_buf,&size); } else { put_buf+=processed_size; size-=processed_size; } if(inflated_size==0) { // could not inflate any data, save unprocessed data if(!from_untranslated) Put(put_buf,size); return; } } } DataInflator::DataInflator() { /* allocate inflate state */ memset(&z,0,sizeof(z)); z_err = inflateInit2(&z, 32+MAX_WBITS); } DataInflator::~DataInflator() { (void)inflateEnd(&z); } void DataInflator::ResetTranslation() { z_err = inflateReset(&z); } void DataDeflator::PutTranslated(Buffer *target,const char *put_buf,int size) { const int flush=(put_buf?Z_NO_FLUSH:Z_FINISH); bool from_untranslated=false; if(Size()>0) { Put(put_buf,size); Get(&put_buf,&size); from_untranslated=true; } int size_coeff=1; // process all data we can, save the rest in the untranslated buffer while(size>0 || flush==Z_FINISH) { size_t put_size=size; size_t store_size=size_coeff*put_size+256; char *store_buf=target->GetSpace(store_size); // do the deflation z.next_in=(Bytef*)put_buf; z.avail_in=put_size; z.next_out=(Bytef*)store_buf; z.avail_out=store_size; int ret = deflate(&z,flush); switch (ret) { case Z_OK: break; case Z_BUF_ERROR: size_coeff*=2; continue; case Z_STREAM_END: z_err=ret; break; default: z_err=ret; target->SetError(xstring::cat("zlib deflate error: ",z.msg,NULL),true); return; } int deflated_size=store_size-z.avail_out; int processed_size=put_size-z.avail_in; target->SpaceAdd(deflated_size); if(from_untranslated) { Skip(processed_size); Get(&put_buf,&size); } else { put_buf+=processed_size; size-=processed_size; } if(deflated_size==0) { // could not deflate any data, save unprocessed data if(!from_untranslated) Put(put_buf,size); return; } if(flush==Z_FINISH && ret==Z_STREAM_END) break; } } DataDeflator::DataDeflator(int level) { /* allocate deflate state */ memset(&z,0,sizeof(z)); z_err = deflateInit(&z, level); } DataDeflator::~DataDeflator() { (void)deflateEnd(&z); } void DataDeflator::ResetTranslation() { z_err = deflateReset(&z); } lftp-4.9.2/src/LocalDir.h0000644000015000007670000000216612122060177012050 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef LOCALDIR_H #define LOCALDIR_H #include "xstring.h" class LocalDirectory { int fd; xstring_c name; public: LocalDirectory(); LocalDirectory(const LocalDirectory *); ~LocalDirectory(); const char *GetName(); const char *Chdir(); // returns error message or NULL void SetFromCWD(); void Unset(); LocalDirectory *Clone() const; }; #endif lftp-4.9.2/src/IdNameCache.cc0000644000015000007670000001014212662070340012571 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include "IdNameCache.h" void IdNameCache::init() { memset(table_id,0,sizeof(table_id)); memset(table_name,0,sizeof(table_name)); } void IdNameCache::free_list(IdNamePair *list) { while(list) { IdNamePair *next=list->next; delete list; list=next; } } void IdNameCache::free() { for(int i=0; inext=p[h]; p[h]=r; } IdNamePair *IdNameCache::lookup(int id) { unsigned h=hash(id); for(IdNamePair *scan=table_id[h]; scan; scan=scan->next) if(id==scan->id) return scan; IdNamePair *r=get_record(id); if(!r) r=new IdNamePair(id,0); add(h,table_id,r); if(r->name) add(hash(r->name),table_name,new IdNamePair(r)); return r; } IdNamePair *IdNameCache::lookup(const char *name) { unsigned h=hash(name); for(IdNamePair *scan=table_name[h]; scan; scan=scan->next) if(!xstrcmp(name,scan->name)) return scan; IdNamePair *r=get_record(name); if(!r) r=new IdNamePair(-1,name); add(h,table_name,r); if(r->id!=-1) add(hash(r->id),table_id,new IdNamePair(r)); return r; } const char *IdNameCache::Lookup(int id) { const char *name=lookup(id)->name; if(name && name[0]) return name; static char buf[32]; snprintf(buf,sizeof(buf),"%d",id); return buf; } int IdNameCache::Lookup(const char *name) { return lookup(name)->id; } IdNameCache::IdNameCache() { init(); } IdNameCache::~IdNameCache() { free(); } int IdNameCache::Do() { if(expire_timer && expire_timer->Stopped()) Delete(this); return STALL; } unsigned IdNameCache::hash(int id) { return unsigned(id)%table_size; } unsigned IdNameCache::hash(const char *name) { unsigned h=0; while(*name) h+=(h<<4)+*name++; return h%table_size; } IdNamePair *PasswdCache::get_record(int id) { struct passwd *p=getpwuid(id); if(!p) return 0; return new IdNamePair(p->pw_uid,p->pw_name); } IdNamePair *GroupCache::get_record(int id) { struct group *p=getgrgid(id); if(!p) return 0; return new IdNamePair(p->gr_gid,p->gr_name); } IdNamePair *IdNameCache::get_record(const char *name) { int id,n; if(sscanf(name,"%d%n",&id,&n)==1 && !name[n]) return new IdNamePair(id,name); return 0; } IdNamePair *PasswdCache::get_record(const char *name) { struct passwd *p=getpwnam(name); if(p) return new IdNamePair(p->pw_uid,name); return IdNameCache::get_record(name); } IdNamePair *GroupCache::get_record(const char *name) { struct group *p=getgrnam(name); if(p) return new IdNamePair(p->gr_gid,name); return IdNameCache::get_record(name); } PasswdCache *PasswdCache::instance; GroupCache *GroupCache::instance; PasswdCache *PasswdCache::GetInstance() { if(instance) return instance; instance=new PasswdCache(); instance->SetExpireTimer(new Timer(30)); return instance; } GroupCache *GroupCache::GetInstance() { if(instance) return instance; instance=new GroupCache(); instance->SetExpireTimer(new Timer(30)); return instance; } PasswdCache::~PasswdCache() { if(this==instance) instance=0; } GroupCache::~GroupCache() { if(this==instance) instance=0; } lftp-4.9.2/src/DirColors.cc0000644000015000007670000002030012662070340012405 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2015 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "DirColors.h" #include "ResMgr.h" #include "FileSet.h" #include "buffer.h" DirColors *DirColors::instance; const char DirColors::resource[]="color:dir-colors"; /* Parse a string as part of the LS_COLORS variable; this may involve decoding all kinds of escape characters. If equals_end is set an unescaped equal sign ends the string, otherwise only a : or \0 does. Returns the number of characters output, or -1 on failure. The resulting string is *not* null-terminated, but may contain embedded nulls. Note that both dest and src are char **; on return they point to the first free byte after the array and the character that ended the input string, respectively. */ static int get_funky_string (char **dest, const char **src, int equals_end) { int num; /* For numerical codes */ int count; /* Something to count with */ enum { ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR } state; const char *p; char *q; p = *src; /* We don't want to double-indirect */ q = *dest; /* the whole darn time. */ count = 0; /* No characters counted in yet. */ num = 0; state = ST_GND; /* Start in ground state. */ while (state < ST_END) { switch (state) { case ST_GND: /* Ground state (no escapes) */ switch (*p) { case ':': case '\0': state = ST_END; /* End of string */ break; case '\\': state = ST_BACKSLASH; /* Backslash scape sequence */ ++p; break; case '^': state = ST_CARET; /* Caret escape */ ++p; break; case '=': if (equals_end) { state = ST_END; /* End */ break; } /* else fall through */ default: *(q++) = *(p++); ++count; break; } break; case ST_BACKSLASH: /* Backslash escaped character */ switch (*p) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': state = ST_OCTAL; /* Octal sequence */ num = *p - '0'; break; case 'x': case 'X': state = ST_HEX; /* Hex sequence */ num = 0; break; case 'a': /* Bell */ num = 7; /* Not all C compilers know what \a means */ break; case 'b': /* Backspace */ num = '\b'; break; case 'e': /* Escape */ num = 27; break; case 'f': /* Form feed */ num = '\f'; break; case 'n': /* Newline */ num = '\n'; break; case 'r': /* Carriage return */ num = '\r'; break; case 't': /* Tab */ num = '\t'; break; case 'v': /* Vtab */ num = '\v'; break; case '?': /* Delete */ num = 127; break; case '_': /* Space */ num = ' '; break; case '\0': /* End of string */ state = ST_ERROR; /* Error! */ break; default: /* Escaped character like \ ^ : = */ num = *p; break; } if (state == ST_BACKSLASH) { *(q++) = num; ++count; state = ST_GND; } ++p; break; case ST_OCTAL: /* Octal sequence */ if (*p < '0' || *p > '7') { *(q++) = num; ++count; state = ST_GND; } else num = (num << 3) + (*(p++) - '0'); break; case ST_HEX: /* Hex sequence */ switch (*p) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': num = (num << 4) + (*(p++) - '0'); break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': num = (num << 4) + (*(p++) - 'a') + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': num = (num << 4) + (*(p++) - 'A') + 10; break; default: *(q++) = num; ++count; state = ST_GND; break; } break; case ST_CARET: /* Caret escape */ state = ST_GND; /* Should be the next state... */ if (*p >= '@' && *p <= '~') { *(q++) = *(p++) & 037; ++count; } else if (*p == '?') { *(q++) = 127; ++count; } else state = ST_ERROR; break; default: abort (); } } *(q++) = 0; *dest = q; *src = p; if(state == ST_ERROR) return -1; return count; } void DirColors::Parse(const char *p) { Empty(); Add(".lc", "\033["); Add(".rc", "m"); Add(".no", ""); Add(".fi", ""); Add(".di", ""); Add(".ln", ""); if(!p) return; char *buf; /* color_buf buffer pointer */ int state; /* State of parser */ char label[4]; /* Indicator label */ const char *ext; label[0] = '.'; label[3] = 0; ext = NULL; buf = alloca_strdup (p); state = 1; while (state > 0) { switch (state) { case 1: /* First label character */ switch (*p) { case ':': ++p; break; case '*': /* Allocate new extension block and add to head of linked list (this way a later definition will override an earlier one, which can be useful for having terminal-specific defs override global). */ ++p; /* next should be . */ if(*p++ != '.') { state = -1; break; } ext = buf; state = get_funky_string (&buf, &p, 1) < 0 ? -1 : 4; break; case '\0': state = 0; /* Done! */ break; default: /* Assume it is file type label */ label[1] = *(p++); state = 2; break; } break; case 2: /* Second label character */ if (*p) { label[2] = *(p++); state = 3; } else state = -1; /* Error */ break; case 3: /* Equal sign after indicator label */ state = -1; /* Assume failure... */ if (*(p++) == '=')/* It *should* be... */ { const char *b = buf; state = get_funky_string (&buf, &p, 0) < 0 ? -1 : 1; Add(label, b); } break; case 4: /* Equal sign after *.ext */ if (*(p++) == '=') { const char *b = buf; state = get_funky_string (&buf, &p, 0) < 0 ? -1 : 1; Add(ext, b); } else state = -1; break; } } // if (color_indicator[C_LINK].len == 6 // && !strncmp (color_indicator[C_LINK].string, "target", 6)) // color_symlink_as_referent = 1; if(!Lookup(".ec")) { const char *no=Lookup(".no"); const char *lc=Lookup(".lc"); const char *rc=Lookup(".rc"); Add(".ec",xstring::cat(lc,no,rc,NULL)); } } DirColors::DirColors() { Reconfig(resource); } const char *DirColors::GetColor(const char *name,int type) { const char *ret=0; if(type==FileInfo::DIRECTORY) { ret=Lookup(".di"); if(ret) return ret; } else if(type==FileInfo::SYMLINK) { ret=Lookup(".ln"); if(ret) return ret; } else if(type==FileInfo::NORMAL) ret=Lookup(".fi"); const char *ext = strrchr(name, '.'); if(ext && *++ext) { const char *l=Lookup(ext); if(l) return l; } return ret?ret:""; } const char *DirColors::GetColor(const FileInfo *fi) { return GetColor(fi->name,fi->defined&fi->TYPE?fi->filetype:-1); } void DirColors::PutColored(const Ref& buf,const char *name,int type) { const char *color=GetColor(name,type); const char *lc=Lookup(".lc"); const char *rc=Lookup(".rc"); if(!color || !*color || !lc || !rc) { buf->Put(name); return; } buf->Put(lc); buf->Put(color); buf->Put(rc); buf->Put(name); PutReset(buf); } void DirColors::PutReset(const Ref& buf) { const char *reset=Lookup(".ec"); buf->Put(reset); } void DirColors::Reconfig(const char *name) { if(!xstrcmp(name,resource)) Parse(ResMgr::Query(resource,0)); } lftp-4.9.2/src/misc.cc0000644000015000007670000005367013607663274011476 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2020 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "xmalloc.h" #include "xstring.h" #include "trio.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_TERMIOS_H #include #endif #ifdef TIME_WITH_SYS_TIME # include #endif #if LIBIDN2 # include #endif #ifdef HAVE_DLFCN_H # include #endif CDECL_BEGIN #include "regex.h" #include "human.h" CDECL_END #include "misc.h" #include "ProcWait.h" #include "SignalHook.h" #include "url.h" #include "ResMgr.h" #include "log.h" #include const char *dir_file(const char *dir,const char *file) { if(dir==0 || dir[0]==0) return file?file:dir; if(file==0 || file[0]==0) return dir; if(file[0]=='/') return file; if(file[0]=='.' && file[1]=='/') file+=2; xstring& buf=xstring::get_tmp(); size_t len=strlen(dir); if(len==0) return buf.set(file); if(dir[len-1]=='/') return buf.vset(dir,file,NULL); return buf.vset(dir,"/",file,NULL); } const char *url_file(const char *url,const char *file) { static xstring buf; if(buf && url==buf) // it is possible to url_file(url_file(url,dir),file) url=alloca_strdup(url); if(!url || url[0]==0) { buf.set(file?file:""); return buf; } ParsedURL u(url); if(!u.proto) { buf.set(dir_file(url,file)); return buf; } if(file && file[0]=='~') u.path.set(file); else u.path.set(dir_file(u.path,file)); buf.truncate(); return u.CombineTo(buf); } const char *output_file_name(const char *src,const char *dst,bool dst_local, const char *dst_base,bool make_dirs) { bool dst_is_dir=false; if(dst) { if(dst_base) dst=url_file(dst_base,dst); ParsedURL u_dst(dst,true); if(u_dst.proto) dst_local=false; if(dst_local) { dst=expand_home_relative(dst); struct stat st; if(stat(dst,&st)!=-1 && S_ISDIR(st.st_mode)) dst_is_dir=true; } else { int len=xstrlen(u_dst.path); if(len>0 && u_dst.path[len-1]=='/') dst_is_dir=true; } if(!dst_is_dir) return dst; } ParsedURL u_src(src,true); if(u_src.proto) src=u_src.path; if(!src) return ""; // there will be error anyway. const char *base=basename_ptr(src); if(make_dirs && !dst) { base=src; if(base[0]=='~') { base=strchr(base,'/'); if(!base) base=""; } while(*base=='/') base++; } return url_file(dst?dst:dst_base,base); } const char *basename_ptr(const char *s) { const char *s1=s+strlen(s); while(s1>s && s1[-1]=='/') s1--; while(s1>s && s1[-1]!='/') s1--; return s1; } const char *expand_home_relative(const char *s) { if(s[0]!='~') return s; const char *home=0; const char *sl=strchr(s+1,'/'); static xstring ret_path; if(s[1]==0 || s[1]=='/') { home=get_home(); } else { // extract user name and find the home int name_len=(sl?sl-s-1:strlen(s+1)); struct passwd *pw=getpwnam(xstring::get_tmp(s+1,name_len)); if(pw) home=pw->pw_dir; } if(home==0) return s; if(sl) return ret_path.vset(home,sl,NULL); return home; } int create_directories(char *path) { char *sl=path; int res; if(access(path,0)==0) return 0; for(;;) { sl=strchr(sl,'/'); if(sl==path) { sl++; continue; } if(sl) *sl=0; if(access(path,0)==-1) { res=mkdir(path,0777); if(res==-1) { if(errno!=EEXIST) { fprintf(stderr,"mkdir(%s): %s\n",path,strerror(errno)); if(sl) *sl='/'; return(-1); } } else debug((9,"mkdir(%s): ok\n",path)); } if(sl) *sl++='/'; else break; } return 0; } void truncate_file_tree(const char *dir) { fflush(stderr); pid_t pid; switch(pid=fork()) { case(0): // child SignalHook::Ignore(SIGINT); SignalHook::Ignore(SIGTSTP); SignalHook::Ignore(SIGQUIT); SignalHook::Ignore(SIGHUP); execlp("rm","rm","-rf",dir,(char*)NULL); perror("execlp(rm)"); fflush(stderr); _exit(1); case(-1): // error perror("fork()"); return; default: // parent (new ProcWait(pid))->Auto(); // don't wait for termination } } int fd_width(int fd) { if(fd == -1) return -1; if(!isatty(fd)) return 0; #ifdef TIOCGWINSZ struct winsize sz; sz.ws_col=sz.ws_row=0; ioctl(fd,TIOCGWINSZ,&sz); if(sz.ws_col==0) sz.ws_col=80; return(sz.ws_col); #else /* !TIOCGWINSZ */ return 80; #endif } char *xgetcwd() { char *cwd=getcwd(0,0); // glibc extension if(cwd) { xmalloc_register_block(cwd); return cwd; } int size=256; cwd=(char*)xmalloc(size); for(;;) { if(getcwd(cwd,size)) return cwd; if(errno!=ERANGE) return strcpy(cwd,"."); cwd=(char*)xrealloc(cwd,size*=2); } } void xgetcwd_to(xstring& s) { int size=256; for(;;) { s.get_space(size); if(getcwd(s.get_non_const(),size)) { s.set_length(strlen(s.get())); return; } if(errno!=ERANGE) { s.set("."); return; } size*=2; } } int parse_perms(const char *s) { int p=0; if(strlen(s)!=9 && !(strlen(s)==10 && s[9]=='+')) // ACL tag bad: return -1; switch(s[0]) { case('r'): p|=S_IRUSR; break; case('-'): break; default: goto bad; } switch(s[1]) { case('w'): p|=S_IWUSR; break; case('-'): break; default: goto bad; } switch(s[2]) { case('S'): p|=S_ISUID; break; case('s'): p|=S_ISUID; // fall-through case('x'): p|=S_IXUSR; break; case('-'): break; default: goto bad; } s+=3; switch(s[0]) { case('r'): p|=S_IRGRP; break; case('-'): break; default: goto bad; } switch(s[1]) { case('w'): p|=S_IWGRP; break; case('-'): break; default: goto bad; } switch(s[2]) { case('S'): p|=S_ISGID; break; case('s'): p|=S_ISGID; // fall-through case('x'): p|=S_IXGRP; break; case('-'): break; default: goto bad; } s+=3; switch(s[0]) { case('r'): p|=S_IROTH; break; case('-'): break; default: goto bad; } switch(s[1]) { case('w'): p|=S_IWOTH; break; case('-'): break; default: goto bad; } switch(s[2]) { case('T'): p|=S_ISVTX; break; case('t'): p|=S_ISVTX; // fall-through case('x'): p|=S_IXOTH; break; case('l'): case('L'): p|=S_ISGID; p&=~S_IXGRP; break; case('-'): break; default: goto bad; } return p; } // it does not prepend file type. const char *format_perms(int p) { static char s[10]; memset(s,'-',9); if(p&0400) s[0]='r'; if(p&0200) s[1]='w'; if(p&0100) s[2]='x'; if(p&0040) s[3]='r'; if(p&0020) s[4]='w'; if(p&0010) s[5]='x'; if(p&0004) s[6]='r'; if(p&0002) s[7]='w'; if(p&0001) s[8]='x'; if(p&01000) s[8]=(p&0001?'t':'T'); if(p&02000) s[5]=(p&0010?'s':'S'); if(p&04000) s[2]=(p&0100?'s':'S'); return s; } const char month_names[][4]={ "Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec", "" }; int parse_month(const char *m) { for(int i=0; month_names[i][0]; i++) if(!strcasecmp(month_names[i],m)) return(i%12); return -1; } int parse_year_or_time(const char *year_or_time,int *year,int *hour,int *minute) { if(year_or_time[2]==':') { if(2!=sscanf(year_or_time,"%2d:%2d",hour,minute)) return -1; *year=-1; } else { if(1!=sscanf(year_or_time,"%d",year)) return -1;; *hour=*minute=0; } return 0; } int guess_year(int month,int day,int hour,int minute) { const struct tm &now=SMTask::now; int year=now.tm_year+1900; if(month *32+ day > now.tm_mon*32+now.tm_mday+6) year--; return year; } int percent(off_t offset,off_t size) { if(offset>=size) return 100; // use floating point to avoid integer overflow. return int(double(offset)*100/size); } const char *squeeze_file_name(const char *name,int w) { static xstring buf; int mbflags=0; name=url::remove_password(name); int name_width=mbswidth(name,mbflags); if(name_width<=w) return name; const char *b=basename_ptr(name); int b_width=name_width-mbsnwidth(name,b-name,mbflags); if(b_width<=w-4 && b_width>w-15) return buf.vset(".../",b,NULL); int b_len=strlen(b); while(b_width>(w<3?w-1:w-3) && b_len>0) { int ch_len=mblen(b,b_len); if(ch_len<1) ch_len=1; b_width-=mbsnwidth(b,ch_len,mbflags); b+=ch_len; b_len-=ch_len; } if(w>=6) buf.set("..."); else buf.set("<"); return buf.append(b); } /* Converts struct tm to time_t, assuming the data in tm is UTC rather than local timezone (mktime assumes the latter). Contributed by Roger Beeman , with the help of Mark Baushke and the rest of the Gurus at CISCO. */ time_t mktime_from_utc (const struct tm *t) { struct tm tc; memcpy(&tc, t, sizeof(struct tm)); /* UTC times are never DST; if we say -1, we'll introduce odd localtime- * dependant errors. */ tc.tm_isdst = 0; time_t tl = mktime (&tc); if (tl == -1) return -1; time_t tb = mktime (gmtime (&tl)); return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl))); } static void set_tz(const char *tz) { static char *put_tz; static int put_tz_alloc; if(!tz) { unsetenv("TZ"); xfree(put_tz); put_tz=0; put_tz_alloc=0; tzset(); return; } int tz_len=strlen(tz)+4; char *new_tz=put_tz; if(tz_len>put_tz_alloc) new_tz=(char*)xmalloc(put_tz_alloc=tz_len); snprintf(new_tz,tz_len,"TZ=%s",tz); if(new_tz!=put_tz) { putenv(new_tz); xfree(put_tz); put_tz=new_tz; } // now initialize libc variables from env TZ. tzset(); } static char *saved_tz=0; static void save_tz() { xstrset(saved_tz,getenv("TZ")); } static void restore_tz() { set_tz(saved_tz); } time_t mktime_from_tz(struct tm *t,const char *tz) { if(!tz || !*tz) return mktime(t); if(!strcasecmp(tz,"GMT")) return mktime_from_utc(t); if(isdigit((unsigned char)*tz) || *tz=='+' || *tz=='-') { int tz1_len=strlen(tz)+4; char *tz1=string_alloca(tz1_len); snprintf(tz1,tz1_len,"GMT%s",tz); tz=tz1; } save_tz(); set_tz(tz); time_t res=mktime(t); restore_tz(); return res; } bool re_match(const char *line,const char *a,int flags) { if(!a || !*a) return false; regex_t re; if(regcomp(&re,a,REG_EXTENDED|REG_NOSUB|flags)) return false; bool res=(0==regexec(&re,line,0,0,0)); regfree(&re); return res; } xstring& SubstTo(xstring& buf,const char *txt, const subst_t *s) { buf.nset("",0); char str[3]; bool last_subst_empty=true; while(*txt) { char ch = *txt++; const char *to_add = NULL; if(ch=='\\' && *txt && *txt!='\\') { ch=*txt++; if(ch >= '0' && ch < '8') { int len; unsigned code; txt--; if(sscanf(txt,"%3o%n",&code,&len)!=1) continue; // should never happen. ch=code; txt+=len; str[0]=ch; str[1]=0; to_add=str; } else { if(ch=='?') { if(last_subst_empty) txt++; to_add=""; } for(int i = 0; s[i].from; i++) { if(s[i].from != ch) continue; to_add=s[i].to; if(!to_add) to_add = ""; last_subst_empty = (*to_add==0); } if(!to_add) { str[0]='\\'; str[1]=ch; str[2]=0; to_add=str; } } } else { if(ch=='\\' && *txt=='\\') txt++; str[0]=ch; str[1]=0; to_add=str; } if(to_add==0) continue; buf.append(to_add); } return(buf); } void xgettimeofday(time_t *sec, int *usec) { #ifdef HAVE_GETTIMEOFDAY struct timeval tv; gettimeofday(&tv,0); if(sec) *sec = tv.tv_sec; if(usec) *usec = tv.tv_usec; #else if(sec) time(sec); if(usec) *usec = 0; #endif } char *xstrftime(const char *format, const struct tm *tm) { char *ret = NULL; int siz = 32; struct tm dummy; memset(&dummy, 0, sizeof(dummy)); if(tm == NULL) tm = &dummy; for(;;) { ret = (char *) xrealloc(ret, siz); int res=strftime(ret, siz, format, tm); if(res>0 && res /file * /file -> / * file/name -> "file" * file/name/ -> "file" * file -> "" * note: the last differs from dirname(1) (which would return ".") * */ void strip_trailing_slashes(xstring& ret) { int len=ret.length(); while(len>0 && ret[len-1]=='/') len--; if(len==0 && ret[0]=='/') len=1+(ret[1]=='/'); if(len>0) ret.truncate(len); } xstring& dirname_modify(xstring &ret) { strip_trailing_slashes(ret); const char *slash=strrchr(ret,'/'); if(!slash) ret.truncate(0); /* file with no path */ else if(slash==ret) ret.truncate(1); /* the slash is the first character */ else ret.truncate(slash-ret); return ret; } xstring& dirname(const char *path) { return dirname_modify(xstring::get_tmp(path)); } char last_char(const char *str) { int len=strlen(str); return str[len-(len>0)]; } /* How many bytes it will take to store LEN bytes in base64. */ int base64_length(int len) { return (4 * (((len) + 2) / 3)); } /* Encode the string S of length LENGTH to base64 format and place it to STORE. STORE will be 0-terminated, and must point to a writable buffer of at least 1+BASE64_LENGTH(length) bytes. */ void base64_encode (const char *s, char *store, int length) { /* Conversion table. */ static const char tbl[64] = { 'A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X', 'Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3', '4','5','6','7','8','9','+','/' }; int i; unsigned char *p = (unsigned char *)store; /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ for (i = 0; i < length; i += 3) { *p++ = tbl[s[0] >> 2]; *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; *p++ = tbl[s[2] & 0x3f]; s += 3; } /* Pad the result if necessary... */ if (i == length + 1) *(p - 1) = '='; else if (i == length + 2) *(p - 1) = *(p - 2) = '='; /* ...and zero-terminate it. */ *p = '\0'; } bool temporary_network_error(int err) { switch(err) { case(EPIPE): case(EIO): case(ETIMEDOUT): #ifdef ECONNRESET case(ECONNRESET): #endif case(ECONNREFUSED): #ifdef EHOSTUNREACH case(EHOSTUNREACH): #endif #ifdef EHOSTDOWN case(EHOSTDOWN): #endif #ifdef ENETRESET case(ENETRESET): #endif #ifdef ENETUNREACH case(ENETUNREACH): #endif #ifdef ENETDOWN case(ENETDOWN): #endif #ifdef ECONNABORTED case(ECONNABORTED): #endif #ifdef EADDRNOTAVAIL case(EADDRNOTAVAIL): #endif return true; } return false; } const char *get_home() { static char *home=NULL; if(home) return home; home=getenv("HOME"); if(home) return home; struct passwd *pw=getpwuid(getuid()); if(pw && pw->pw_dir) return home=pw->pw_dir; return NULL; } const char *get_lftp_home_nocreate() { static char *lftp_home=NULL; if(lftp_home) return *lftp_home?lftp_home:NULL; lftp_home=getenv("LFTP_HOME"); if(!lftp_home) { const char *h=get_home(); if(h) lftp_home=xstring::cat(h,"/.lftp",NULL).borrow(); else return NULL; } else lftp_home=xstrdup(lftp_home); return *lftp_home?lftp_home:NULL; } const char *get_lftp_home_if_exists() { const char *home=get_lftp_home_nocreate(); struct stat st; if(stat(home,&st)==-1 || !S_ISDIR(st.st_mode)) return NULL; return home; } // new XDG directories const char *get_lftp_dir(char *&cached_dir,const char *env,const char *def) { if(cached_dir) return cached_dir; // use old existing directory for compatibility const char *dir=get_lftp_home_if_exists(); if(dir) return cached_dir=xstrdup(dir); // use explicit directory if specified, otherwise use default under home const char *home=getenv(env); if(home) { // explicit XDG dir (void)mkdir(home,0755); dir=xstring::cat(home,"/lftp",NULL); } else { home=get_home(); if(!home) return NULL; xstring& path=xstring::get_tmp(home); path.append('/'); const char *slash=strchr(def,'/'); if(slash) { path.append(def,slash-def); (void)mkdir(path,0755); path.append(slash); } else { path.append(def); } (void)mkdir(path,0755); dir=path.append("/lftp"); } (void)mkdir(dir,0755); return cached_dir=xstrdup(dir); } const char *get_lftp_config_dir() { static char *config_dir; return get_lftp_dir(config_dir,"XDG_CONFIG_HOME",".config"); } const char *get_lftp_data_dir() { static char *data_dir; return get_lftp_dir(data_dir,"XDG_DATA_HOME",".local/share"); } const char *get_lftp_cache_dir() { static char *cache_dir; return get_lftp_dir(cache_dir,"XDG_CACHE_HOME",".cache"); } const char *memrchr(const char *buf,char c,size_t len) { buf+=len; while(len-->0) if(*--buf==c) return buf; return 0; } bool is_shell_special(char c) { switch (c) { case '\'': case '(': case ')': case '!': case '{': case '}': /* reserved words */ case '^': case '$': case '`': /* expansion chars */ case '*': case '[': case '?': case ']': /* globbing chars */ case ' ': case '\t': case '\n': /* IFS white space */ case '"': case '\\': /* quoting chars */ case '|': case '&': case ';': /* shell metacharacters */ case '<': case '>': case '#': /* comment char */ return true; } return false; } const xstring& shell_encode(const char *string,int len) { if(!string) return xstring::null; static xstring result; result.get_space(2 + 2 * len); char *r = result.get_non_const(); if(string[0]=='-' || string[0]=='~') { *r++='.'; *r++='/'; } int c; for (const char *s = string; s && (c = *s); s++) { if (is_shell_special(c)) *r++ = '\\'; *r++ = c; } result.set_length(r-result); return (result); } int remove_tags(char *buf) { int len=strlen(buf); int less = -1; for(int i = 0; i < len;i++) { if(strcmp(buf + i, " ") == 0){ for(int j = 0; j < 6; j++)buf[i + j] = 0; buf[i] = ' '; i += 6; i--; continue; } if(buf[i] == '<'){ less = i; continue; } if(buf[i] == '>'){ if(less != -1){ for(int j = less; j <= i; j++)buf[j] = 0; less = -1; } } } int zero = 0; for(int i = 0; i < len;i++) { while(zero < i && buf[zero] != 0)zero++; if(buf[i] != 0 and zero != i){ buf[zero] = buf[i]; buf[i] = 0; } } return ++zero; } void rtrim(char *s) { int len=strlen(s); while(len>0 && (s[len-1]==' ' || s[len-1]=='\t' || s[len-1]=='\r')) s[--len]=0; } bool in_foreground_pgrp() { static int tty_fd; if(tty_fd==-1) return true; pid_t pg=tcgetpgrp(tty_fd); if(pg==(pid_t)-1 && !isatty(tty_fd)) { tty_fd=open("/dev/tty",O_RDONLY); if(tty_fd==-1) return true; pg=tcgetpgrp(tty_fd); } if(pg==(pid_t)-1 || pg==getpgrp()) return true; return false; } void random_init() { static bool init; if(!init) { srandom(time(NULL)+getpid()); init=true; } } double random01() { return random()/2147483648.0; } #include const char *get_nodename() { static struct utsname u; if(uname(&u)==0) return u.nodename; return "NODE"; } const char *xhuman(long long n) { char *buf=xstring::tmp_buf(LONGEST_HUMAN_READABLE + 1); return human_readable(n, buf, human_autoscale|human_SI, 1, 1); } const char *xidna_to_ascii(const char *name) { #if LIBIDN2 if(!name) return 0; static xstring_c name_ace_tmp; name_ace_tmp.unset(); if(idn2_to_ascii_lz(name,name_ace_tmp.buf_ptr(),0)==IDN2_OK) { xmalloc_register_block((void*)name_ace_tmp.get()); return name_ace_tmp; } #endif//LIBIDN2 return name; } bool xtld_name_ok(const char *name) { #if LIBIDN2 if(mbswidth(name,MBSW_REJECT_INVALID|MBSW_REJECT_UNPRINTABLE)<=0) return false; if(idn2_lookup_ul(name,NULL,0)==IDN2_OK) return true; #endif//LIBIDN2 return false; } bool is_ipv4_address(const char *s) { struct in_addr addr; return inet_pton(AF_INET,s,&addr)>0; } bool is_ipv6_address(const char *s) { #if INET6 struct in6_addr addr; return inet_pton(AF_INET6,s,&addr)>0; #else return false; #endif } int lftp_fallocate(int fd,off_t sz) { #if defined(HAVE_FALLOCATE) return fallocate(fd,0,0,sz); #elif defined(HAVE_POSIX_FALLOCATE) return posix_fallocate(fd,0,sz); #else errno=ENOSYS; return -1; #endif } void call_dynamic_hook(const char *name) { #if defined(HAVE_DLOPEN) && defined(RTLD_DEFAULT) typedef void (*func)(); func f=(func)dlsym(RTLD_DEFAULT,name); if(f) f(); #endif } lftp-4.9.2/src/ProcWait.h0000644000015000007670000000302612662070340012105 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PROCWAIT_H #define PROCWAIT_H #include #include #include "SMTask.h" #include "xmap.h" class ProcWait : public SMTask { public: enum State { TERMINATED, RUNNING, ERROR }; protected: static xmap all_proc; static const xstring& proc_key(pid_t p); // make key for xmap const pid_t pid; State status; int term_info; int saved_errno; bool auto_die; bool handle_info(int info); // true if finished ~ProcWait(); public: int Do(); State GetState() { return status; } int GetInfo() { return term_info; } int Kill(int sig=SIGTERM); void Auto() { auto_die=true; } ProcWait(pid_t p); static void Signal(bool yes); static void DeleteAll(); }; #endif /* PROCWAIT_H */ lftp-4.9.2/src/rmJob.cc0000644000015000007670000000405412122060570011561 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "rmJob.h" #include "plural.h" #include "url.h" #include "misc.h" rmJob::rmJob(FileAccess *s,ArgV *a) : TreatFileJob(s,a) { mode=FA::REMOVE; recurse=false; depth_first=true; } void rmJob::Recurse() { set_maxdepth(-1); Need(FileInfo::TYPE); recurse=true; } void rmJob::SayFinal() { if(failed==file_count) return; if(file_count==1) printf(_("%s ok, `%s' removed\n"),op,first->name.get()); else if(failed) { if(mode==FA::REMOVE_DIR) printf(plural("%s failed for %d of %d director$y|ies$\n",file_count), op,failed,file_count); else printf(plural("%s failed for %d of %d file$|s$\n",file_count), op,failed,file_count); } else { if(mode==FA::REMOVE_DIR) printf(plural("%s ok, %d director$y|ies$ removed\n",file_count), op,file_count); else printf(plural("%s ok, %d file$|s$ removed\n",file_count), op,file_count); } } void rmJob::TreatCurrent(const char *d, const FileInfo *fi) { /* If we're recursing and this is a directory, rmdir it. (If we're * not recursing, just send an rm and let it fail.) */ if(recurse && (fi->defined&fi->TYPE) && (fi->filetype==fi->DIRECTORY)) session->Open(fi->name,FA::REMOVE_DIR); else session->Open(fi->name,mode); } lftp-4.9.2/src/FtpListInfo.cc0000644000015000007670000004265713105271025012725 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "FtpListInfo.h" #include "FileSet.h" #include #include #include #include "xstring.h" #include #include "misc.h" #include "ftpclass.h" #include "ascii_ctype.h" #define number_of_parsers 7 FileSet *FtpListInfo::Parse(const char *buf,int len) { if(mode==FA::LONG_LIST || mode==FA::MP_LIST) { if(len==0 && mode==FA::LONG_LIST && !ResMgr::QueryBool("ftp:list-empty-ok",session->GetHostName())) { mode=FA::LIST; return 0; } int err; FileSet *set=session->ParseLongList(buf,len,&err); if(!set || err>0) { if(mode==FA::MP_LIST) mode=FA::LONG_LIST; else mode=FA::LIST; } return set; } else { return ParseShortList(buf,len); } } FileSet *Ftp::ParseLongList(const char *buf,int len,int *err_ret) const { if(err_ret) *err_ret=0; int err[number_of_parsers]; FileSet *set[number_of_parsers]; int i; for(i=0; iname.length()>1) info->name.chomp('/'); if(info && !strchr(info->name,'/')) set[i]->Add(info); else delete info; if(*best_err1>err[i]) best_err1=&err[i]; if(*best_err2>err[i] && best_err1!=&err[i]) best_err2=&err[i]; if(*best_err1>16) goto leave; // too many errors with best parser. } if(*best_err2 > (*best_err1+1)*16) { i=best_err1-err; guessed_parser=line_parsers[i]; the_set=&set[i]; the_err=&err[i]; } } else { FileInfo *info=(*guessed_parser)(line.get_non_const(),the_err,tz); if(info && info->name.length()>1) info->name.chomp('/'); if(info && !strchr(info->name,'/')) (*the_set)->Add(info); else delete info; } } if(!the_set) { i=best_err1-err; the_set=&set[i]; the_err=&err[i]; } leave: for(i=0; i=2 && buf[0]=='.' && buf[1]=='/') { buf+=2; len-=2; } #if 0 // not possible here if(len>=2 && buf[0]=='/' && buf[1]=='/') { buf++; len--; } #endif const char *nl=(const char*)memchr(buf,'\n',len); if(!nl) break; line_len=nl-buf; if(line_len>0 && buf[line_len-1]=='\r') line_len--; FileInfo::type type=FileInfo::UNKNOWN; const char *slash=(const char*)memchr(buf,'/',line_len); if(slash) { type=FileInfo::DIRECTORY; line_len=slash-buf; } if(line_len==0) { len-=nl+1-buf; buf=nl+1; continue; } if(line_allocUNKNOWN) fi->SetType(type); set->Add(fi); } } return set; } static FileInfo *ParseFtpLongList_UNIX(char *line,int *err,const char *tz) { int tmp; if(sscanf(line,"total %d",&tmp)==1) return 0; if(!strncasecmp(line,"Status of ",10)) return 0; // STAT output. if(strchr("bcpsD",line[0])) // block, char, pipe, socket, Door. return 0; FileInfo *fi=FileInfo::parse_ls_line(line,tz); if(!fi) { (*err)++; return 0; } return fi; } #define FIRST_TOKEN strtok(line," \t") #define NEXT_TOKEN strtok(NULL," \t") #define ERR do{(*err)++;delete fi;return(0);}while(0) /* 07-13-98 09:06PM aix 07-13-98 09:06PM hpux 07-13-98 09:06PM linux 07-13-98 09:06PM ncr 07-13-98 09:06PM solaris 03-18-98 06:01AM 2109440 nlxb318e.tar 07-02-98 11:17AM 13844 Whatsnew.txt */ static FileInfo *ParseFtpLongList_NT(char *line,int *err,const char *tz) { char *t = FIRST_TOKEN; FileInfo *fi=0; if(t==0) ERR; int month,day,year; if(sscanf(t,"%2d-%2d-%2d",&month,&day,&year)!=3) ERR; if(year>=70) year+=1900; else year+=2000; t = NEXT_TOKEN; if(t==0) ERR; int hour,minute; char am='A'; // AM/PM is optional if(sscanf(t,"%2d:%2d%c",&hour,&minute,&am)<2) ERR; t = NEXT_TOKEN; if(t==0) ERR; if(am=='P') // PM - after noon { hour+=12; if(hour==24) hour=0; } struct tm tms; tms.tm_sec=30; /* seconds after the minute [0, 61] */ tms.tm_min=minute; /* minutes after the hour [0, 59] */ tms.tm_hour=hour; /* hour since midnight [0, 23] */ tms.tm_mday=day; /* day of the month [1, 31] */ tms.tm_mon=month-1; /* months since January [0, 11] */ tms.tm_year=year-1900; /* years since 1900 */ tms.tm_isdst=-1; fi=new FileInfo(); fi->SetDate(mktime_from_tz(&tms,tz),30); long long size; if(!strcmp(t,"")) fi->SetType(fi->DIRECTORY); else { fi->SetType(fi->NORMAL); if(sscanf(t,"%lld",&size)!=1) ERR; fi->SetSize(size); } t=strtok(NULL,""); if(t==0) ERR; while(*t==' ') t++; if(*t==0) ERR; fi->SetName(t); return fi; } /* ASUSER 8192 04/26/05 13:54:16 *DIR dir/ ASUSER 8192 04/26/05 13:57:34 *DIR dir1/ ASUSER 365255 02/28/01 15:41:40 *STMF readme.txt ASUSER 8489625 03/18/03 09:37:00 *STMF saved.zip ASUSER 365255 02/28/01 15:41:40 *STMF unist.old */ static FileInfo *ParseFtpLongList_AS400(char *line,int *err,const char *tz) { char *t = FIRST_TOKEN; FileInfo *fi=0; if(t==0) ERR; char *user=t; t = NEXT_TOKEN; if(t==0) ERR; long long size; if(sscanf(t,"%lld",&size)!=1) ERR; t = NEXT_TOKEN; if(t==0) ERR; int month,day,year; if(sscanf(t,"%2d/%2d/%2d",&month,&day,&year)!=3) ERR; if(year>=70) year+=1900; else year+=2000; t = NEXT_TOKEN; if(t==0) ERR; int hour,minute,second; if(sscanf(t,"%2d:%2d:%2d",&hour,&minute,&second)!=3) ERR; t = NEXT_TOKEN; if(t==0) ERR; struct tm tms; tms.tm_sec=second; /* seconds after the minute [0, 61] */ tms.tm_min=minute; /* minutes after the hour [0, 59] */ tms.tm_hour=hour; /* hour since midnight [0, 23] */ tms.tm_mday=day; /* day of the month [1, 31] */ tms.tm_mon=month-1; /* months since January [0, 11] */ tms.tm_year=year-1900; /* years since 1900 */ tms.tm_isdst=-1; time_t mtime=mktime_from_tz(&tms,tz); t = NEXT_TOKEN; if(t==0) ERR; FileInfo::type type=FileInfo::UNKNOWN; if(!strcmp(t,"*DIR")) type=FileInfo::DIRECTORY; else type=FileInfo::NORMAL; t=strtok(NULL,""); if(t==0) ERR; while(*t==' ') t++; if(*t==0) ERR; char *slash=strchr(t,'/'); if(slash) { if(slash==t) return 0; *slash=0; type=FileInfo::DIRECTORY; if(slash[1]) { fi=new FileInfo(t); fi->SetType(type); return fi; } } fi=new FileInfo(t); fi->SetType(type); fi->SetSize(size); fi->SetDate(mtime,0); fi->SetUser(user); return fi; } /* +i774.71425,m951188401,/, users +i774.49602,m917883130,r,s79126, jgr_www2.exe starts with + comma separated first character of field is type: i - ? m - modification time / - means directory r - means plain file s - size up - permissions in octal \t - file name follows. */ FileInfo *ParseFtpLongList_EPLF(char *line,int *err,const char *) { int len=strlen(line); const char *b=line; FileInfo *fi=0; if(len<2 || b[0]!='+') ERR; const char *name=0; int name_len=0; off_t size=NO_SIZE; time_t date=NO_DATE; long date_l; long long size_ll; bool dir=false; bool type_known=false; int perms=-1; const char *scan=b+1; int scan_len=len-1; while(scan && scan_len>0) { switch(*scan) { case '\t': // the rest is file name. name=scan+1; name_len=scan_len-1; scan=0; break; case 's': if(1 != sscanf(scan+1,"%lld",&size_ll)) break; size = size_ll; break; case 'm': if(1 != sscanf(scan+1,"%ld",&date_l)) break; date = date_l; break; case '/': dir=true; type_known=true; break; case 'r': dir=false; type_known=true; break; case 'i': break; case 'u': if(scan[1]=='p') // permissions. if(sscanf(scan+2,"%o",&perms)!=1) perms=-1; break; default: name=0; scan=0; break; } if(scan==0 || scan_len==0) break; const char *comma=find_char(scan,scan_len,','); if(comma) { scan_len-=comma+1-scan; scan=comma+1; } else break; } if(name==0 || !type_known) ERR; fi=new FileInfo(xstring::get_tmp(name,name_len)); if(size!=NO_SIZE) fi->SetSize(size); if(date!=NO_DATE) fi->SetDate(date,0); if(type_known) { if(dir) fi->SetType(fi->DIRECTORY); else fi->SetType(fi->NORMAL); } if(perms!=-1) fi->SetMode(perms); return fi; } /* 0 DIR 06-27-96 11:57 PROTOCOL 169 11-29-94 09:20 SYSLEVEL.MPT */ static FileInfo *ParseFtpLongList_OS2(char *line,int *err,const char *tz) { FileInfo *fi=0; char *t = FIRST_TOKEN; if(t==0) ERR; long long size; if(sscanf(t,"%lld",&size)!=1) ERR; fi=new FileInfo; fi->SetSize(size); t = NEXT_TOKEN; if(t==0) ERR; fi->SetType(fi->NORMAL); if(!strcmp(t,"DIR")) { fi->SetType(fi->DIRECTORY); t = NEXT_TOKEN; if(t==0) ERR; } int month,day,year; if(sscanf(t,"%2d-%2d-%2d",&month,&day,&year)!=3) ERR; if(year>=70) year+=1900; else year+=2000; t = NEXT_TOKEN; if(t==0) ERR; int hour,minute; if(sscanf(t,"%2d:%2d",&hour,&minute)!=3) ERR; struct tm tms; tms.tm_sec=30; /* seconds after the minute [0, 61] */ tms.tm_min=minute; /* minutes after the hour [0, 59] */ tms.tm_hour=hour; /* hour since midnight [0, 23] */ tms.tm_mday=day; /* day of the month [1, 31] */ tms.tm_mon=month-1; /* months since January [0, 11] */ tms.tm_year=year-1900; /* years since 1900 */ tms.tm_isdst=-1; fi->SetDate(mktime_from_tz(&tms,tz),30); t=strtok(NULL,""); if(t==0) ERR; while(*t==' ') t++; if(*t==0) ERR; fi->SetName(t); return fi; } static FileInfo *ParseFtpLongList_MacWebStar(char *line,int *err,const char *tz) { FileInfo *fi=0; char *t = FIRST_TOKEN; if(t==0) ERR; fi=new FileInfo; switch(t[0]) { case('l'): // symlink fi->SetType(fi->SYMLINK); break; case('d'): // directory fi->SetType(fi->DIRECTORY); break; case('-'): // plain file fi->SetType(fi->NORMAL); break; case('b'): // block case('c'): // char case('p'): // pipe case('s'): // sock return 0; // ignore default: ERR; } mode_t mode=parse_perms(t+1); if(mode==(mode_t)-1) ERR; // permissions are meaningless here. // "folder" or 0 t = NEXT_TOKEN; if(!t) ERR; if(strcmp(t,"folder")) { // size? t = NEXT_TOKEN; if(!t) ERR; // size t = NEXT_TOKEN; if(!t) ERR; if(isdigit((unsigned char)*t)) { long long size; if(sscanf(t,"%lld",&size)==1) fi->SetSize(size); } else ERR; } else { // ?? t = NEXT_TOKEN; if(!t) ERR; } // month t = NEXT_TOKEN; if(!t) ERR; struct tm date; memset(&date,0,sizeof(date)); date.tm_mon=parse_month(t); if(date.tm_mon==-1) ERR; const char *day_of_month = NEXT_TOKEN; if(!day_of_month) ERR; date.tm_mday=atoi(day_of_month); // time or year t = NEXT_TOKEN; if(!t) ERR; if(parse_year_or_time(t,&date.tm_year,&date.tm_hour,&date.tm_min)==-1) ERR; date.tm_isdst=-1; date.tm_sec=30; int prec=30; if(date.tm_year==-1) date.tm_year=guess_year(date.tm_mon,date.tm_mday,date.tm_hour,date.tm_min) - 1900; else { date.tm_hour=12; prec=12*60*60; } fi->SetDate(mktime_from_tz(&date,tz),prec); char *name=strtok(NULL,""); if(!name) ERR; // no symlinks on Mac, but anyway. if(fi->filetype==fi->SYMLINK) { char *arrow=name; while((arrow=strstr(arrow," -> "))!=0) { if(arrow!=name && arrow[4]!=0) { *arrow=0; fi->SetSymlink(arrow+4); break; } arrow++; } } fi->SetName(name); return fi; } /* Type=cdir;Modify=20021029173810;Perm=el;Unique=BP8AAjJufAA; / Type=pdir;Modify=20021029173810;Perm=el;Unique=BP8AAjJufAA; .. Type=dir;Modify=20010118144705;Perm=e;Unique=BP8AAjNufAA; bin Type=dir;Modify=19981021003019;Perm=el;Unique=BP8AAlhufAA; pub Type=file;Size=12303;Modify=19970124132601;Perm=r;Unique=BP8AAo9ufAA; mailserv.FAQ modify=20161215062118;perm=flcdmpe;type=dir;UNIX.group=503;UNIX.mode=0700; directory-name modify=20161213121618;perm=adfrw;size=6369064;type=file;UNIX.group=503;UNIX.mode=0644; file-name modify=20120103123744;perm=adfrw;size=11;type=OS.unix=symlink;UNIX.group=0;UNIX.mode=0777; www */ FileInfo *ParseFtpLongList_MLSD(char *line,int *err,const char *) { FileInfo *fi=0; const char *name=0; off_t size=NO_SIZE; time_t date=NO_DATE; const char *owner=0; const char *group=0; FileInfo::type type=FileInfo::UNKNOWN; int perms=-1; char *space=strstr(line,"; "); if(space) { name=space+2; *space=0; } else { /* NcFTPd does not put a semicolon after last fact, workaround it. */ space=strchr(line,' '); if(!space) ERR; name=space+1; *space=0; } for(char *tok=strtok(line,";"); tok; tok=strtok(0,";")) { if(!strcasecmp(tok,"Type=cdir") || !strcasecmp(tok,"Type=pdir") || !strcasecmp(tok,"Type=dir")) { type=FileInfo::DIRECTORY; continue; } if(!strcasecmp(tok,"Type=file")) { type=FileInfo::NORMAL; continue; } if(!strcasecmp(tok,"Type=OS.unix=symlink")) { type=FileInfo::SYMLINK; continue; } if(!strncasecmp(tok,"Modify=",7)) { date=Ftp::ConvertFtpDate(tok+7); continue; } if(!strncasecmp(tok,"Size=",5)) { long long size_ll; if(sscanf(tok+5,"%lld",&size_ll)==1) size=size_ll; continue; } if(!strncasecmp(tok,"Perm=",5)) { perms=0; for(tok+=5; *tok; tok++) { switch(to_ascii_lower(*tok)) { case 'e': perms|=0111; break; case 'l': perms|=0444; break; case 'r': perms|=0444; break; case 'c': perms|=0200; break; case 'w': perms|=0200; break; } } continue; } if(!strncasecmp(tok,"UNIX.mode=",10)) { if(sscanf(tok+10,"%o",&perms)!=1) perms=-1; continue; } if(!strncasecmp(tok,"UNIX.owner=",11)) { owner=tok+11; continue; } if(!strncasecmp(tok,"UNIX.group=",11)) { group=tok+11; continue; } if(!strncasecmp(tok,"UNIX.uid=",9)) { if(!owner) owner=tok+9; continue; } if(!strncasecmp(tok,"UNIX.gid=",9)) { if(!group) group=tok+9; continue; } } if(name==0 || !*name || type==FileInfo::UNKNOWN) ERR; fi=new FileInfo(name); if(size!=NO_SIZE) fi->SetSize(size); if(date!=NO_DATE) fi->SetDate(date,0); fi->SetType(type); if(perms!=-1) fi->SetMode(perms); if(owner) fi->SetUser(owner); if(group) fi->SetGroup(group); return fi; } Ftp::FtpLineParser Ftp::line_parsers[number_of_parsers]={ ParseFtpLongList_UNIX, ParseFtpLongList_NT, ParseFtpLongList_EPLF, ParseFtpLongList_MLSD, ParseFtpLongList_AS400, ParseFtpLongList_OS2, ParseFtpLongList_MacWebStar, }; lftp-4.9.2/src/xmalloc.cc0000644000015000007670000000664212625306405012164 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "trio.h" #include "xmalloc.h" static int memory_count=0; static void memory_error_and_abort(const char *fname,size_t size) { fprintf(stderr,"%s: out of virtual memory when trying to get %lu bytes\n", fname,(long)size); exit(2); } void *xmalloc (size_t bytes) { if(bytes==0) return 0; void *temp=(void*)malloc(bytes); if(temp==0) memory_error_and_abort("xmalloc",bytes); memory_count++; #ifdef MEM_DEBUG printf("xmalloc %p %lu (count=%d)\n",temp,(long)bytes,memory_count); #endif return(temp); } void *xrealloc(void *pointer,size_t bytes) { void *temp; if(pointer==0 && bytes==0) return 0; if(bytes==0) { memory_count--; free(pointer); temp=0; goto leave; } if(pointer==0) { temp=(void*)malloc(bytes); memory_count++; } else temp=(void*)realloc(pointer,bytes); if(temp==0) memory_error_and_abort ("xrealloc",bytes); leave: #ifdef MEM_DEBUG printf("xrealloc %p %p %lu (count=%d)\n",pointer,temp,(long)bytes,memory_count); #endif return(temp); } void xfree(void *p) { if(!p) return; #ifdef MEM_DEBUG printf("xfree %p (count=%d)\n",p,memory_count); #endif memory_count--; free(p); } char *xstrdup(const char *s,int spare) { if(!s) return (char*)xmalloc(spare); #ifdef MEM_DEBUG printf("xstrdup \"%s\"\n",s); #endif size_t len=strlen(s)+1; char *mem=(char*)xmalloc(len+spare); memcpy(mem,s,len); return mem; } char *xstrset(char *&mem,const char *s,size_t len) { if(!s) { xfree(mem); return mem=0; } #ifdef MEM_DEBUG printf("xstrset \"%.*s\"\n",len,s); #endif if(s==mem) { mem[len]=0; return mem; } size_t old_len=(mem?strlen(mem)+1:0); if(mem && s>mem && smem && s. */ #include #include "SMTask.h" #include "Timer.h" #include "xstring.h" #include "misc.h" #define now SMTask::now xlist_head Timer::all_timers; xheap Timer::running_timers; int Timer::infty_count; timeval Timer::GetTimeoutTV() { Timer *t; while((t=running_timers.get_min())!=0 && t->Stopped()) running_timers.pop_min(); if(!t) { timeval tv={infty_count?HOUR:-1, 0}; return tv; } TimeDiff remains(t->stop,now); return remains.toTimeval(); } TimeInterval Timer::TimeLeft() const { if(IsInfty()) return TimeInterval(); if(now>=stop) return TimeInterval(0,0); return TimeInterval(stop-now); } void Timer::set_last_setting(const TimeInterval &i) { infty_count-=IsInfty(); last_setting=i; infty_count+=IsInfty(); re_set(); } void Timer::add_random() { if(random_max>0.0001) { stop+=TimeDiff::valueOf(random_max*random01()); } } void Timer::re_set() { stop=start; stop+=last_setting; add_random(); re_sort(); } void Timer::AddRandom(double r) { random_max=r; add_random(); re_sort(); } void Timer::Set(const TimeInterval &i) { resource.unset(); closure.unset(); start=SMTask::now; set_last_setting(i); } void Timer::Reset(const Time &t) { if(start>=t && stop>t) return; start=t; re_set(); } void Timer::ResetDelayed(int s) { Reset(SMTask::now+TimeDiff(s,0)); } void Timer::StopDelayed(int s) { stop=SMTask::now+TimeDiff(s,0); re_sort(); } void Timer::SetResource(const char *r,const char *c) { if(resource!=r || closure!=c) { resource.set(r); closure.set(c); start=now; reconfig(r); } else { Reset(); } } bool Timer::Stopped() const { if(IsInfty()) return false; return now>=stop; } void Timer::reconfig(const char *r) { if(resource && (!r || !strcmp(r,resource))) set_last_setting(TimeIntervalR(ResMgr::Query(resource,closure))); } void Timer::init() { random_max=0; all_timers.add(all_timers_node); } Timer::~Timer() { running_timers.remove(running_timers_node); all_timers_node.remove(); infty_count-=IsInfty(); } Timer::Timer() : last_setting(1,0), all_timers_node(this), running_timers_node(this) { init(); } Timer::Timer(const TimeInterval &d) : last_setting(d), all_timers_node(this), running_timers_node(this) { init(); infty_count+=IsInfty(); re_set(); } Timer::Timer(const char *r,const char *c) : last_setting(0,0), all_timers_node(this), running_timers_node(this) { init(); resource.set(r); closure.set(c); start=now; reconfig(r); } Timer::Timer(int s,int ms) : all_timers_node(this), running_timers_node(this) { init(); Set(TimeInterval(s,ms)); } void Timer::re_sort() { running_timers.remove(running_timers_node); if(nowreconfig(r); } bool operator<(const Timer& a,const Timer& b) { return a.TimeLeft(). */ #include #include #include #include #include #include "GetPass.h" #include "CharReader.h" #include "SignalHook.h" const char *GetPass(const char *prompt) { static xstring_c oldpass; static int tty_fd=-2; if(tty_fd==-2) { if(isatty(0)) tty_fd=0; else { tty_fd=open("/dev/tty",O_RDONLY); if(tty_fd!=-1) fcntl(tty_fd,F_SETFD,FD_CLOEXEC); } } if(tty_fd==-1) return 0; write(tty_fd,prompt,strlen(prompt)); struct termios tc; tcgetattr(tty_fd,&tc); tcflag_t old_lflag=tc.c_lflag; tc.c_lflag&=~ECHO; tcsetattr(tty_fd,TCSANOW,&tc); oldpass.set_allocated(readline_from_file(tty_fd)); tc.c_lflag=old_lflag; tcsetattr(tty_fd,TCSANOW,&tc); write(tty_fd,"\r\n",2); return oldpass; } char *readline_from_file(int fd) { xstring line(""); for(;;) { SMTaskRef rr(new CharReader(fd)); CharReader& r=*rr.get_non_const(); int c; for(;;) { SMTask::Schedule(); c=r.GetChar(); if(c!=r.NOCHAR) break; SMTask::Block(); if(SignalHook::GetCount(SIGINT)>0) return(xstrdup("")); } if(c==r.EOFCHAR && line.length()==0) return(NULL); if(c==r.EOFCHAR || c=='\n') return(line.borrow()); line.append(c); } } lftp-4.9.2/src/PtyShell.h0000644000015000007670000000263612662070340012127 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef PTYSHELL_H #define PTYSHELL_H #include "Filter.h" class PtyShell : public FDStream { Ref a; SMTaskRef w; pid_t pg; xstring_c oldcwd; bool closed; bool use_pipes; int pipe_in; int pipe_out; void Init(); public: PtyShell(const char *filter); PtyShell(ArgV *a); ~PtyShell(); void SetCwd(const char *); void UsePipes() { use_pipes=true; } int getfd(); int getfd_pipe_in() { return pipe_in; } int getfd_pipe_out() { return pipe_out; } bool Done(); void Kill(int sig=SIGTERM) { if(w) w->Kill(sig); } pid_t GetProcGroup() const { return pg; } bool broken(); }; #endif // PTYSHELL_H lftp-4.9.2/src/lftp_rl.h0000644000015000007670000000404712122060133012011 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef LFTP_RL_H #define LFTP_RL_H CDECL_BEGIN void lftp_readline_init (void); int lftp_history_expand (const char *, char **); char *lftp_readline (const char *prompt); void lftp_add_history_nodups(const char *cmd); void lftp_history_clear(); void lftp_history_list(int cnt); int lftp_history_write(const char *fn); int lftp_history_read(const char *fn); void lftp_rl_clear(void); void lftp_rl_redisplay_maybe(void); void lftp_rl_set_ignore_some_completions_function(int (*func)(char**)); char **lftp_rl_completion_matches(const char *text,char *(*compentry)(const char *,int)); void lftp_rl_add_defun(const char *name,int (*func)(int,int),int key); void lftp_rl_bind(const char *key,const char *func); void lftp_rl_set_prompt(const char *p); void lftp_rl_write_history(); void lftp_rl_read_history(); void lftp_rl_history_stifle(int s); void lftp_rl_init( const char *readline_name, char **(*attempted_completion_function)(const char *,int,int), int (*getc_function)(FILE*), const char *completer_quote_characters, const char *completer_word_break_characters, const char *filename_quote_characters, char *(*filename_quoting_function)(char *,int,char *), char *(*filename_dequoting_function)(const char *,int), int (*char_is_quoted_p)(const char *,int)); CDECL_END #endif /* LFTP_RL_H */ lftp-4.9.2/src/alias.cc0000644000015000007670000000437512662070341011615 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "trio.h" #include "alias.h" Alias *Alias::base; void Alias::Add(const char *alias,const char *value) { Alias **scan=&base; while(*scan) { int dif=strcasecmp((*scan)->alias,alias); if(dif==0) { (*scan)->value.set(value); return; } if(dif>0) break; scan=&((*scan)->next); } *scan=new Alias(alias,value,*scan); } void Alias::Del(const char *alias) { Alias **scan=&base; while(*scan) { int dif=strcasecmp((*scan)->alias,alias); if(dif==0) { Alias *tmp=(*scan)->next; delete *scan; *scan=tmp; return; } scan=&((*scan)->next); } } const char *Alias::Find(const char *alias) { Alias *scan=base; while(scan) { int dif=strcasecmp(scan->alias,alias); if(dif==0) return(scan->value); if(dif>0) break; scan=scan->next; } return 0; } char *Alias::Format() { xstring res(""); for(Alias *scan=base; scan; scan=scan->next) { res.append("alias "); const char *s=scan->alias; while(*s) { if(strchr("\" \t\\>|",*s)) res.append('\\'); res.append(*s++); } res.append(' '); s=scan->value; bool par=false; if(*s==0 || strcspn(s," \t>|")!=strlen(s)) par=true; if(par) res.append('"'); while(*s) { if(strchr("\"\\",*s)) res.append('\\'); res.append(*s++); } if(par) res.append('"'); res.append('\n'); } return res.borrow(); } lftp-4.9.2/src/keyvalue.cc0000644000015000007670000001002712122060066012332 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "keyvalue.h" #include #include "trio.h" #include #include int KeyValueDB::Read(int fd) { xstring key; xstring value; int c; FILE *f=fdopen(fd,"r"); for(;;) { c=getc(f); // skip leading space while(c!=EOF && (c==' ' || c=='\t')) c=getc(f); if(c==EOF) break; if(c=='\n') continue; // next line key.truncate(0); for(;;) { key.append(c); c=getc(f); if(c==EOF) break; if(c==' ' || c=='\t' || c=='\n') break; } if(c==EOF || c=='\n' || key.length()==0) break; // invalid line // skip space in mid while(c!=EOF && (c==' ' || c=='\t')) c=getc(f); if(c==EOF || c=='\n') break; value.truncate(0); for(;;) { value.append(c); c=getc(f); if(c==EOF) break; if(c=='\n') break; } Add(key,value); if(c==EOF) break; } fclose(f); return 0; } int KeyValueDB::VKeyCompare(const void *a,const void *b) { KeyValueDB::Pair *pa=*(KeyValueDB::Pair*const*)a; KeyValueDB::Pair *pb=*(KeyValueDB::Pair*const*)b; return KeyValueDB::KeyCompare(pa,pb); } void KeyValueDB::Sort() { int count=0; Pair *scan; for(scan=chain; scan; scan=scan->next) count++; if(count==0) return; Pair **arr=(Pair**)alloca(count*sizeof(*arr)); count=0; for(scan=chain; scan; scan=scan->next) arr[count++]=scan; qsort(arr,count,sizeof(*arr),&KeyValueDB::VKeyCompare); chain=0; while(count--) { arr[count]->next=chain; chain=arr[count]; } } char *KeyValueDB::Format(StringMangler value_mangle) { Sort(); Pair *p; int max_key_len=0; for(p=chain; p; p=p->next) { int len=strlen(p->key); if(len>max_key_len) max_key_len=len; } max_key_len&=~7; // save some bytes xstring buf(""); for(p=chain; p; p=p->next) buf.appendf("%-*s\t%s\n",max_key_len,p->key.get(),value_mangle(p->value)); return buf.borrow(); } int KeyValueDB::Write(int fd) { xstring_ca buf(Format()); int res=write(fd,buf,strlen(buf)); close(fd); return res; } void KeyValueDB::Add(const char *key,const char *value) { Pair **p=LookupPair(key); if(!p) AddPair(NewPair(key,value)); else p[0]->SetValue(value); } void KeyValueDB::Remove(const char *key) { Pair **p=LookupPair(key); if(p) Purge(p); } KeyValueDB::Pair **KeyValueDB::LookupPair(const char *key) const { for(const Pair * const*p=&chain; *p; p=&(*p)->next) { if((*p)->KeyCompare(key)==0) return const_cast(p); } return 0; } const char *KeyValueDB::Lookup(const char *key) const { const Pair * const*p=LookupPair(key); return p ? (*p)->value.get() : 0; } int KeyValueDB::Lock(int fd,int type) { struct flock lk; lk.l_type=type; lk.l_whence=0; lk.l_start=0; lk.l_len=0; int res=fcntl(fd,F_SETLK,&lk); if(res==-1 && E_RETRY(errno)) { int retries=5; bool echo=true; for(int i=0; i. */ #ifndef FTPDIRLIST_H #define FTPDIRLIST_H class FtpDirList : public DirList { SMTaskRef ubuf; const xstring_ca pattern; bool TryEPLF(const char *line,int len); bool TryMLSD(const char *line,int len); bool TryColor(const char *line,int len); void FormatGeneric(class FileInfo *); public: FtpDirList(FileAccess *s,ArgV *a) : DirList(s,a), pattern(args->Combine(1)) {} const char *Status(); int Do(); void SuspendInternal(); void ResumeInternal(); }; #endif//FTPDIRLIST_H lftp-4.9.2/src/FindJob.cc0000644000015000007670000002101413062503046012022 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "FindJob.h" #include "CmdExec.h" #include "misc.h" #include "GetFileInfo.h" #include "url.h" #include "PatternSet.h" #include "buffer_std.h" #define top (*stack.last()) #define stack_ptr (stack.count()-1) #define super SessionJob #define orig_session super::session int FinderJob::Do() { int m=STALL; prf_res pres; Job *j; switch(state) { case START_INFO: { if(stack_ptr==-1) { ParsedURL u(dir,true); if(u.proto) { session=my_session=FileAccess::New(&u); session->SetPriority(fg?1:0); init_dir=session->GetCwd(); Down(u.path?u.path.get():init_dir.path.get()); } } /* If we're not validating, and this is an argument (first-level path), * pretend the file exists. */ if((file_info_need|FileInfo::NAME) == FileInfo::NAME && !validate_args && stack_ptr == -1) { FileSet *fs = new FileSet(); fs->Add(new FileInfo(dir)); Push(fs); state=LOOP; return MOVED; } /* The first time we get here (stack_ptr == -1), dir is an actual * argument, so it might be a file. (Every other time, it's guaranteed * to be a directory.) Set show_dirs to true, so it'll end up actually * being on the stack, with type information. */ li=new GetFileInfo(session, dir, stack_ptr == -1); /* Prepend for the argument level entry only: */ if(stack_ptr != -1) li->DontPrependPath(); int need = file_info_need|FileInfo::NAME; /* We only explicitely need the type if we're recursing further. */ if(stack_ptr+1 < maxdepth) need |= FileInfo::TYPE; li->Need(need); if(use_cache) li->UseCache(); state=INFO; m=MOVED; } case INFO: if(!li->Done()) return m; if(li->Error()) { if(!quiet) eprintf("%s: %s\n",op,li->ErrorText()); li=0; errors++; depth_done=true; state=LOOP; return MOVED; } if(stack_ptr != -1 && li->WasDirectory()) Enter(dir); Push(li->GetResult()); top.fset->rewind(); li=0; state=LOOP; m=MOVED; case LOOP: if(stack_ptr==-1 || top.fset->curr()==0) { Up(); return MOVED; } session->SetCwd(init_dir); session->Chdir(top.path,false); // at this point either is true: // 1. we just process another file (!depth_done) // 2. we just returned from a subdir (depth_done) if(depth_first && !depth_done && (maxdepth == -1 || stack_ptr+1 < maxdepth)) { FileInfo *f=top.fset->curr(); if((f->defined&f->TYPE) && f->filetype==f->DIRECTORY) { Down(f->name); return MOVED; } } state=PROCESSING; m=MOVED; case PROCESSING: pres=ProcessFile(top.path,top.fset->curr()); if(pres==PRF_LATER) return m; depth_done=false; switch(pres) { case(PRF_FATAL): errors++; state=DONE; return MOVED; case(PRF_ERR): errors++; break; case(PRF_WAIT): state=WAIT; return MOVED; case(PRF_OK): break; case(PRF_LATER): abort(); } post_WAIT: state=LOOP; m=MOVED; if(stack_ptr==-1) return m; if(!depth_first && (maxdepth == -1 || stack_ptr+1 < maxdepth)) { FileInfo *f=top.fset->curr(); if((f->defined&f->TYPE) && f->filetype==f->DIRECTORY) { top.fset->next(); Down(f->name); return MOVED; } } top.fset->next(); return MOVED; case WAIT: j=FindDoneAwaitedJob(); if(!j) return m; RemoveWaiting(j); Delete(j); goto post_WAIT; case DONE: return m; } return m; } void FinderJob::Up() { if(stack_ptr==-1) { done: state=DONE; Finish(); return; } /* stack[0] is the dir entry for the argument (ie. ls -d dir), and * stack[1] is the contents (ls dir); don't exit for the first. */ if(stack_ptr) Exit(); stack.chop(); if(stack_ptr==-1) goto done; depth_done=true; state=LOOP; } void FinderJob::Push(FileSet *fset) { const char *old_path=0; if(stack_ptr>=0) { old_path=top.path; fset->ExcludeDots(); /* don't need . and .. (except for stack[0]) */ } const char *new_path=""; if(old_path) // the first path will be empty new_path=alloca_strdup(dir_file(old_path,dir)); /* matching exclusions don't include the path, so they operate * on the filename portion only */ if(exclude) fset->Exclude(0, exclude); stack.append(new place(new_path,fset)); /* give a chance to operate on the list as a whole, and * possibly sort it */ ProcessList(fset); } void FinderJob::Down(const char *p) { #ifdef FIND_DEBUG printf("Down(%s)\n",p.get()); #endif dir.set(p); state=START_INFO; } FinderJob::prf_res FinderJob::ProcessFile(const char *d,const FileInfo *f) { return PRF_OK; } void FinderJob::Init() { op="find"; errors=0; li=0; show_sl=true; depth_first=false; // useful for rm -r depth_done=false; file_info_need=0; use_cache=true; validate_args=false; quiet=false; maxdepth=-1; exclude=0; state=START_INFO; } FinderJob::FinderJob(FileAccess *s) : SessionJob(s), orig_init_dir(orig_session->GetCwd()), session(orig_session), init_dir(session->GetCwd()) { Init(); } void FinderJob::NextDir(const char *d) { if(session!=orig_session) { session=orig_session; init_dir=orig_init_dir; } session->SetCwd(init_dir); Down(d); } FinderJob::~FinderJob() { } void FinderJob::ShowRunStatus(const SMTaskRef& sl) { if(!show_sl) return; switch(state) { case INFO: sl->Show("%s: %s",dir_file(stack_ptr>=0?top.path.get():0,dir),li->Status()); break; case WAIT: Job::ShowRunStatus(sl); break; default: sl->Clear(); break; } } xstring& FinderJob::FormatStatus(xstring& s,int v,const char *prefix) { SessionJob::FormatStatus(s,v,prefix); switch(state) { case INFO: s.appendf("\t%s: %s\n",dir_file(stack_ptr>=0?top.path.get():0,dir),li->Status()); break; case WAIT: break; default: break; } return s; } void FinderJob::Fg() { super::Fg(); if(orig_session!=session) session->SetPriority(1); } void FinderJob::Bg() { if(orig_session!=session) session->SetPriority(0); super::Bg(); } // FinderJob_List implementation // find files and write list to a stream FinderJob::prf_res FinderJob_List::ProcessFile(const char *d,const FileInfo *fi) { if(buf->Broken()) return PRF_FATAL; if(buf->Error()) { eprintf("%s: %s\n",op,buf->ErrorText()); return PRF_FATAL; } if(fg_data==0) fg_data=buf->GetFgData(fg); if(buf->Size()>0x10000) return PRF_LATER; xstring path_to_show; if(ProcessingURL()) { FileAccess::Path old_cwd=session->GetCwd(); session->SetCwd(init_dir); path_to_show.set(session->GetFileURL(dir_file(d,fi->name))); session->SetCwd(old_cwd); } else path_to_show.set(dir_file(d,fi->name)); if((fi->defined&fi->TYPE) && fi->filetype==fi->DIRECTORY && strcmp(fi->name,"/")) path_to_show.append('/'); if(long_listing) { FileInfo n(*fi); n.SetName(path_to_show); n.MakeLongName(); buf->Put(n.longname); } else { buf->Put(path_to_show); } buf->Put("\n"); return FinderJob::ProcessFile(d,fi); } FinderJob_List::FinderJob_List(FileAccess *s,ArgV *a,FDStream *o) : FinderJob(s), args(a), long_listing(false) { if(o) buf=new IOBufferFDStream(o,IOBuffer::PUT); else buf=new IOBuffer_STDOUT(this); show_sl = !o || !o->usesfd(1); NextDir(a->getcurr()); ValidateArgs(); } void FinderJob_List::Finish() { const char *d=args->getnext(); if(!d) { buf->PutEOF(); return; } NextDir(d); } lftp-4.9.2/src/parsecmd.cc0000644000015000007670000001645512662070341012324 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2015 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "CmdExec.h" #include "alias.h" #include "xstring.h" bool CmdExec::quotable(char ch,char in_quotes) { if(!ch) return false; if(ch=='\\' || ch=='!' || ch==in_quotes) return true; if(in_quotes) return false; if(strchr("\"' \t>|;&",ch)) return true; return false; } CmdExec::parse_result CmdExec::parse_one_cmd() { char in_quotes; const char *line=cmd_buf.Get(); const char *line_begin=line; static xstring nextarg; const char *alias=0; if(args) args->Empty(); else args=new ArgV; output=0; char redir_type=0; background=0; if(!*line) { // empty command return PARSE_OK; } if(line[0]=='&' && line[1]=='&') { condition=COND_AND; line+=2; } else if(line[0]=='|' && line[1]=='|') { condition=COND_OR; line+=2; } else { condition=COND_ANY; } // loop for all arguments for(;;) { // skip leading whitespace while(is_space(*line)) line++; if(line[0]=='\\' && line[1]=='\n') { line+=2; continue; // and continue skipping space } if(line[0]=='\r' && line[1]=='\n') line++; if(*line==0) return PARSE_AGAIN; if(*line=='\n' || *line=='|' || *line=='>' || *line==';' || *line=='&') break; nextarg.truncate(0); if(args->count()==0 && *line=='#') { // comment -- skip and return while(*line!='\n' && *line) line++; if(*line=='\n') line++; else return PARSE_AGAIN; skip_cmd(line-line_begin); return PARSE_OK; } if(args->count()==0 && *line=='!') { // shell command -- it ends only with '\n' args->Append("!"); line++; while(is_space(*line)) line++; while(*line!='\n' && *line) { if(*line=='\\' && line[1]=='\n') { line+=2; continue; } nextarg.append(*line++); } if(*line==0) return PARSE_AGAIN; if(*line=='\n') line++; skip_cmd(line-line_begin); if(nextarg.length()>0) args->Append(nextarg); return PARSE_OK; } if(args->count()==0 && *line=='(') { line++; args->Append("("); int level=1; in_quotes=0; for(;;) { if(*line==0) return PARSE_AGAIN; if(*line=='\\' && line[1] && (strchr("\"\\",line[1]) || (level==1 && line[1]==')'))) { nextarg.append(*line++); } else { if(!in_quotes) { if(*line==')') { if(--level==0) break; } else if(*line=='(') level++; } if(in_quotes && *line==in_quotes) in_quotes=0; else if(!in_quotes && is_quote(*line)) in_quotes=*line; } nextarg.append(*line++); } args->Append(nextarg); line++; // skip ) while(is_space(*line)) line++; goto cmd_end; } if(args->count()==0 && *line=='?') { line++; args->Append("?"); continue; } // loop for one argument in_quotes=0; for(;;) { if(*line=='\\' && line[1]=='\n') { line+=2; continue; } if(line[0]=='\r' && line[1]=='\n') line++; if(*line=='\\' && quotable(line[1],in_quotes)) { line++; } else { if(*line==0) return PARSE_AGAIN; if(*line=='\n' || (!in_quotes && (is_space(*line) || *line=='>' || *line=='|' || *line==';' || *line=='&'))) break; if(!in_quotes && is_quote(*line)) { in_quotes=*line; line++; continue; } if(in_quotes && *line==in_quotes) { in_quotes=0; line++; continue; } } nextarg.append(*line++); } if(*line==0) return PARSE_AGAIN; // normal commands finish with \n or ; // check if the first arg is an alias, expand it accordingly. if(args->count()==0) { alias=Alias::Find(nextarg); if(alias) { int alias_len=strlen(alias); /* Check if the previous alias ends before the end of new one. * So the new alias does not expand entirely from previous * aliases and we can repeat the expansion from the very beginning. */ if(alias_field<(int)(line-line_begin)) free_used_aliases(); if(!TouchedAlias::IsTouched(alias,used_aliases)) { skip_cmd(line-line_begin); used_aliases=new TouchedAlias(alias,used_aliases); cmd_buf.Prepend(alias); alias_field+=alias_len; line=line_begin=cmd_buf.Get(); continue; } } } args->Append(nextarg); } if(*line==0) return PARSE_AGAIN; if((line[0]=='&' && line[1]=='&') || (line[0]=='|' && line[1]=='|')) { skip_cmd(line-line_begin); return PARSE_OK; } if(*line=='>' || *line=='|') { redir_type=*line; line++; if(*line=='>') { // '>>' means append redir_type='+'; line++; } // skip leading whitespace while(is_space(*line)) line++; if(*line==0) return PARSE_AGAIN; if(*line=='\n' || *line==';' || *line=='&') { if(redir_type=='|') eprintf(_("parse: missing filter command\n")); else eprintf(_("parse: missing redirection filename\n")); if(*line==';' || *line=='&' || *line=='\n') line++; skip_cmd(line-line_begin); return PARSE_ERR; } nextarg.truncate(0); in_quotes=0; for(;;) { if(*line=='\\' && line[1]=='\n') { line+=2; continue; } if(*line=='\\' && quotable(line[1],in_quotes)) line++; else { if(*line==0) return PARSE_AGAIN; // filename can end with a space, filter command can't. if(*line=='\n' || (!in_quotes && ((redir_type!='|' && is_space(*line)) || *line==';' || *line=='&'))) break; if(!in_quotes && is_quote(*line)) { in_quotes=*line; line++; continue; } if(in_quotes && *line==in_quotes) { in_quotes=0; line++; continue; } } nextarg.append(*line++); } // skip spaces while(is_space(*line)) line++; } cmd_end: if((line[0]=='&' && line[1]=='&') || (line[0]=='|' && line[1]=='|')) ; else if(*line==';' || *line=='&' || *line=='\n') { if(*line=='&') background=1; line++; } skip_cmd(line-line_begin); switch(redir_type) { case('|'): output=new OutputFilter(nextarg); break; case('>'): output=new FileStream(nextarg,O_WRONLY|O_TRUNC|O_CREAT); break; case('+'): output=new FileStream(nextarg,O_WRONLY|O_APPEND|O_CREAT); break; } return PARSE_OK; } lftp-4.9.2/src/FindJobDu.cc0000644000015000007670000001107112662070340012316 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "FindJobDu.h" #include "CmdExec.h" #include "misc.h" #include "buffer_std.h" CDECL_BEGIN #include "human.h" CDECL_END #define stack_ptr (size_stack.count()-1) #define stack_top (*size_stack.last()) FinderJob_Du::FinderJob_Du(FileAccess *s,ArgV *a,FDStream *o) : FinderJob(s), args(a) { op=args->a0(); if(o) { buf=new IOBufferFDStream(o,IOBuffer::PUT); show_sl=!o->usesfd(1); } else { buf=new IOBuffer_STDOUT(this); show_sl=true; } Need(FileInfo::SIZE); /* defaults */ max_print_depth = -1; print_totals = false; output_block_size = 1024; human_opts = 0; all_files = false; separate_dirs = false; file_count = false; tot_size=0; success=false; Init(a->getcurr()); } FinderJob_Du::~FinderJob_Du() { } /* process a new directory */ void FinderJob_Du::Init(const char *d) { NextDir(d); } int FinderJob_Du::Done() { return FinderJob::Done() && args->getcurr()==0 && buf->Done(); } void FinderJob_Du::Finish() { /* if there's anything left, we had an error; clear the stack */ if(stack_ptr != -1) { while(stack_ptr >= 0) Pop(); } else success = true; /* at least one succeeded */ /* next? */ const char *d=args->getnext(); if(d) { /* we have another argument */ Init(d); return; } /* we're done */ if (print_totals) /* don't print totals on error */ print_size(tot_size, _("total")); buf->PutEOF(); } const char *FinderJob_Du::MakeFileName(const char *n) { return size_stack.count()>0 ? dir_file(size_stack.last()->dir,n) : n; } off_t FinderJob_Du::BlockCeil(off_t size) const { size+=output_block_size-1; size-=size%output_block_size; return size; } FinderJob::prf_res FinderJob_Du::ProcessFile(const char *d,const FileInfo *fi) { if(buf->Broken()) return PRF_FATAL; if(buf->Error()) { eprintf("%s: %s\n",op,buf->ErrorText()); return PRF_FATAL; } if(fg_data==0) fg_data=buf->GetFgData(fg); if(buf->Size()>0x10000) return PRF_LATER; if(fi->filetype==fi->DIRECTORY) return PRF_OK; /* don't care */ if(!file_count && !(fi->defined&fi->SIZE)) return PRF_OK; /* can't count this one */ /* add this file to the current dir */ long long add = BlockCeil(fi->size); if (file_count) add = 1; if(size_stack.count()>0) size_stack.last()->size += add; tot_size += add; if(all_files || stack_ptr == -1) { /* this is <, where Pop() is <=, since the file counts in depth */ if(max_print_depth == -1 || stack_ptr < max_print_depth) print_size(BlockCeil(fi->size), MakeFileName(fi->name)); } return PRF_OK; } void FinderJob_Du::ProcessList(FileSet *f) { f->Sort(FileSet::BYNAME, true); } /* push a directory onto the stack */ void FinderJob_Du::Push (const char *d) { size_stack.append(new stack_entry(MakeFileName(d))); } /* pop a directory off the stack, combining as necessary */ void FinderJob_Du::Pop() { assert(stack_ptr!=-1); /* no underflows */ /* merge directory's size with its parent */ if(!separate_dirs && stack_ptr > 0) size_stack[stack_ptr-1]->size += stack_top.size; size_stack.chop(); } void FinderJob_Du::print_size (long long n_blocks, const char *string) { char buffer[LONGEST_HUMAN_READABLE + 1]; /* We get blocks in bytes, since we don't know the remote system's * block size. */ buf->Format("%s\t%s\n", human_readable (n_blocks, buffer, human_opts, 1, human_opts?1:output_block_size), string); } /* finished a directory; print it if necessary and pop it off the stack */ void FinderJob_Du::Exit() { /* print the dir */ if(max_print_depth == -1 || stack_ptr <= max_print_depth) print_size(stack_top.size, stack_top.dir); Pop(); } void FinderJob_Du::Enter(const char *d) { Push(d); } lftp-4.9.2/src/SleepJob.h0000644000015000007670000000336012122060634012055 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SLEEPJOB_H #define SLEEPJOB_H #include "Job.h" #include "ResMgr.h" #include "LocalDir.h" #include "CmdExec.h" class SleepJob : public SessionJob, public Timer { xstring cmd; int exit_code; bool done; Ref saved_cwd; JobRef exec; bool repeat; bool weak; // terminate on `exit bg'. int repeat_count; int max_repeat_count; int continue_code; int break_code; public: int Do(); int Done() { return done; } int ExitCode() { return exit_code; } SleepJob(const TimeInterval &when,FileAccess *s=0,LocalDirectory *cwd=0,char *what=0); ~SleepJob(); const char *Status(); xstring& FormatStatus(xstring&,int v,const char *); void ShowRunStatus(const SMTaskRef& s); void Repeat(int m) { repeat=true; max_repeat_count=m; Stop(); } void SetWeak(bool w) { weak=w; } void ContinueCode(int c) { continue_code=c; } void BreakCode(int c) { break_code=c; } void lftpMovesToBackground(); }; #endif//SLEEPJOB_H lftp-4.9.2/src/ResMgr.cc0000644000015000007670000005215413530052701011714 00000000000000/* * lftp - file transfer program * * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include CDECL_BEGIN #include "regex.h" CDECL_END #include "ResMgr.h" #include "SMTask.h" #include "misc.h" #include "StringSet.h" #include "log.h" xlist_head Resource::all_list; xmap *ResType::types_by_name; int ResType::VarNameCmp(const char *good_name,const char *name) { int res=EXACT_PREFIX+EXACT_NAME; const char *colon=strchr(good_name,':'); if(colon && !strchr(name,':')) { good_name=colon+1; res|=SUBSTR_PREFIX; } while(*good_name || *name) { if(*good_name==*name || (*good_name && *name && strchr("-_",*good_name) && strchr("-_",*name))) { good_name++; name++; continue; } if(*name && !*good_name) return DIFFERENT; if((!*name && *good_name) || (strchr("-_:",*name) && !strchr("-_:",*good_name))) { good_name++; if(strchr(name,':')) res|=SUBSTR_PREFIX; else res|=SUBSTR_NAME; continue; } return DIFFERENT; } return res; } bool ResType::IsAlias() const { return closure_valid==ResMgr::AliasValidate; } const char *ResType::FindVar(const char *name,const ResType **type,const char **re_closure) { const ResType *exact_proto=0; const ResType *exact_name=0; int sub=0; *type=types_by_name->lookup(name); if(*type) goto found; // exact match for(const ResType *type_scan=types_by_name->each_begin(); type_scan; type_scan=types_by_name->each_next()) { switch(VarNameCmp(type_scan->name,name)) { case EXACT_PREFIX+EXACT_NAME: *type=type_scan; return 0; case EXACT_PREFIX+SUBSTR_NAME: if(!exact_proto && !exact_name) sub=0; exact_proto=*type=type_scan; sub++; break; case SUBSTR_PREFIX+EXACT_NAME: if(!exact_proto && !exact_name) sub=0; exact_name=*type=type_scan; sub++; break; case SUBSTR_PREFIX+SUBSTR_NAME: if(exact_proto || exact_name) break; sub++; *type=type_scan; break; default: break; } } if(!*type && sub==0) return _("no such variable"); if(sub==1) goto found; *type=0; return _("ambiguous variable name"); found: if((*type)->IsAlias()) { const char *alias_c=(*type)->GetAliasTarget(); char *alias=alloca_strdup(alias_c); char *slash=strchr(alias,'/'); if(slash) { *slash=0; if(re_closure) *re_closure=alias_c+(slash+1-alias); } *type=types_by_name->lookup(alias); if(!*type) return "invalid compatibility alias"; } return 0; } const ResType *ResType::FindRes(const char *name) { const ResType *type; const char *msg=FindVar(name,&type); if(msg) return 0; return type; } const char *ResType::Set(const char *name,const char *cclosure,const char *cvalue,bool def) { ResType *type; // find type of given variable const char *msg=FindVar(name,&type,&cclosure); if(msg) return msg; return type->Set(cclosure,cvalue,def); } const char *ResType::Set(const char *cclosure,const char *cvalue,bool def) { const char *msg=0; xstring_c value(cvalue); if(value && val_valid && (msg=val_valid(&value))!=0) return msg; xstring_c closure(cclosure); if((closure || closure_valid==ResMgr::HasClosure) && closure_valid && (msg=closure_valid(&closure))!=0) return msg; bool need_reconfig=false; xlist_for_each(Resource,*(type_value_list),node,scan) { // find the old value if(closure==scan->closure || !xstrcmp(scan->closure,closure)) { if(def) return 0; need_reconfig=true; delete scan; break; } } if(value) { (void)new Resource(this,closure,value,def); need_reconfig=true; } if(need_reconfig) ResClient::ReconfigAll(name); return 0; } int ResMgr::ResourceCompare(const Resource *ar,const Resource *br) { int diff=strcmp(ar->type->name,br->type->name); if(diff) return diff; if(ar->closure==br->closure) return 0; if(ar->closure==0) return -1; if(br->closure==0) return 1; return strcmp(ar->closure,br->closure); } void Resource::Format(xstring& buf) const { buf.appendf("set %s",type->name); const char *s=closure; if(s) { buf.append('/'); bool par=false; if(strcspn(s," \t>|;&")!=strlen(s)) par=true; if(par) buf.append('"'); while(*s) { if(strchr("\"\\",*s)) buf.append('\\'); buf.append(*s++); } if(par) buf.append('"'); } buf.append(' '); s=value; bool par=false; if(*s==0 || strcspn(s," \t>|;&")!=strlen(s)) par=true; if(par) buf.append('"'); while(*s) { if(strchr("\"\\",*s)) buf.append('\\'); buf.append(*s++); } if(par) buf.append('"'); buf.append('\n'); } static int PResourceCompare(const Resource *const*a,const Resource *const*b) { return ResMgr::ResourceCompare(*a,*b); } static int RefResourceCompare(const Ref *a,const Ref *b) { return ResMgr::ResourceCompare(*a,*b); } char *ResType::Format(bool with_defaults,bool only_defaults) { RefArray created; if(with_defaults || only_defaults) { for(ResType *dscan=types_by_name->each_begin(); dscan; dscan=types_by_name->each_next()) if((only_defaults || dscan->SimpleQuery(0)==0) && !dscan->IsAlias()) created.append(new Resource(dscan, 0,xstrdup(dscan->defvalue?dscan->defvalue:"(nil)"))); } xstring buf(""); if(!only_defaults) { // just created Resources are also in all_list. xarray arr; xlist_for_each(Resource,Resource::all_list,node,scan) { if(!scan->def || with_defaults) arr.append(scan); } arr.qsort(PResourceCompare); for(int i=0; iFormat(buf); } else { created.qsort(RefResourceCompare); for(int i=0; iFormat(buf); } return buf.borrow(); } char **ResType::Generator(void) { StringSet res; for(ResType *dscan=types_by_name->each_begin(); dscan; dscan=types_by_name->each_next()) if(!dscan->IsAlias()) res.Append(dscan->name); res.qsort(); return res.borrow(); } const char *ResMgr::BoolValidate(xstring_c *value) { const char *v=*value; const char *newval=0; switch(v[0]) { case 't': newval="true"; break; case 'T': newval="True"; break; case 'f': newval="false"; break; case 'F': newval="False"; break; case 'y': newval="yes"; break; case 'Y': newval="Yes"; break; case 'n': newval="no"; break; case 'N': newval="No"; break; case '1': newval="1"; break; case '0': newval="0"; break; case '+': newval="+"; break; case '-': newval="-"; break; case 'o': newval=(v[1]=='f' || v[1]=='F')?"off":"on"; break; case 'O': newval=(v[1]=='f' || v[1]=='F')?"Off":"On"; break; default: return _("invalid boolean value"); } if(strcmp(v,newval)) value->set(newval); return 0; } const char *ResMgr::TriBoolValidate(xstring_c *value) { if(!BoolValidate(value)) return 0; /* not bool */ const char *v=*value; const char *newval=0; switch(v[0]) { case 'a': newval="auto"; break; case 'A': newval="Auto"; break; default: return _("invalid boolean/auto value"); } if(strcmp(v,newval)) value->set(newval); return 0; } static const char power_letter[] = { 0, /* not used */ 'K', /* kibi ('k' for kilo is a special case) */ 'M', /* mega or mebi */ 'G', /* giga or gibi */ 'T', /* tera or tebi */ 'P', /* peta or pebi */ 'E', /* exa or exbi */ 'Z', /* zetta or 2**70 */ 'Y' /* yotta or 2**80 */ }; static unsigned long long get_power_multiplier(char p) { const char *scan=power_letter; const int scale=1024; unsigned long long mul=1; p=toupper(p); while(scan(&end),0); unsigned long long m=get_power_multiplier(*end); if(v==end || m==0 || end[m>1]) return _("invalid number"); return 0; } const char *ResMgr::FloatValidate(xstring_c *value) { const char *v=*value; const char *end=v; (void)strtod(v,const_cast(&end)); unsigned long long m=get_power_multiplier(*end); if(v==end || m==0 || end[m>1]) return _("invalid floating point number"); return 0; } const char *ResMgr::UNumberValidate(xstring_c *value) { const char *v=*value; const char *end=v; (void)strtoull(v,const_cast(&end),0); unsigned long long m=get_power_multiplier(*end); if(!isdigit((unsigned char)v[0]) || v==end || m==0 || end[m>1]) return _("invalid unsigned number"); return 0; } const char *ResMgr::AliasValidate(xstring_c *) { return ""; } unsigned long long ResValue::to_unumber(unsigned long long max) const { if (is_nil()) return 0; const char *end=s; unsigned long long v=strtoull(s,const_cast(&end),0); unsigned long long m=get_power_multiplier(*end); unsigned long long vm=v*m; if(vm/m!=v || vm>max) return max; return vm; } long long ResValue::to_number(long long min,long long max) const { if (is_nil()) return 0; const char *end=s; long long v=strtoll(s,const_cast(&end),0); long long m=get_power_multiplier(*end); long long vm=v*m; if(vm/m!=v) return v>0?max:min; if(vm>max) return max; if(vmtype_value_list->add_tail(type_value_node); } Resource::~Resource() { all_node.remove(); type_value_node.remove(); } bool Resource::ClosureMatch(const char *cl_data) { if(!closure && !cl_data) return true; if(!(closure && cl_data)) return false; // a special case for domain name match (i.e. example.org matches *.example.org) if(closure[0]=='*' && closure[1]=='.' && !strcmp(closure+2,cl_data)) return true; if(0==fnmatch(closure,cl_data,FNM_PATHNAME)) return true; // try to match basename; helps matching torrent metadata url to *.torrent const char *bn=basename_ptr(cl_data); if(bn!=cl_data && 0==fnmatch(closure,bn,FNM_PATHNAME)) return true; return false; } const char *ResMgr::QueryNext(const char *name,const char **closure,Resource **ptr) { xlist *node=0; if(*ptr==0) { const ResType *type=FindRes(name); if(!type) { *ptr=0; *closure=0; return 0; } node=type->type_value_list->get_next(); } else { node=(*ptr)->type_value_node.get_next(); } *ptr=node->get_obj(); if(*ptr) { *closure=(*ptr)->closure; return (*ptr)->value; } *closure=0; return 0; } const char *ResType::SimpleQuery(const char *closure) const { // find the value xlist_for_each(Resource,*(type_value_list),node,scan) if(scan->ClosureMatch(closure)) return scan->value; return 0; } ResValue ResMgr::Query(const char *name,const char *closure) { const char *msg; const ResType *type; // find type of given variable msg=FindVar(name,&type); if(msg) { // debug only // fprintf(stderr,_("Query of variable `%s' failed: %s\n"),name,msg); return 0; } return type->Query(closure); } ResValue ResType::Query(const char *closure) const { const char *v=0; if(closure) v=SimpleQuery(closure); if(!v) v=SimpleQuery(0); if(!v) v=defvalue; return v; } bool ResMgr::str2bool(const char *s) { return(strchr("TtYy1+",s[0])!=0 || !strcasecmp(s,"on")); } ResDecl::ResDecl(const char *a_name,const char *a_defvalue,ResValValid *a_val_valid,ResClValid *a_closure_valid) { name=a_name; defvalue=a_defvalue; val_valid=a_val_valid; closure_valid=a_closure_valid; Register(); } ResDecls::ResDecls(ResType *array) { while(array->name) array++->Register(); } ResDecls::ResDecls(ResType *r1,ResType *r2,...) { r.append(r1); r1->Register(); if(!r2) return; r.append(r2); r2->Register(); va_list v; va_start(v,r2); while((r1=va_arg(v,ResType *))!=0) { r1->Register(); r.append(r1); } va_end(v); } ResDecls::~ResDecls() { for(int i=0; iUnregister(); } void ResType::Register() { if(!types_by_name) types_by_name=new xmap; types_by_name->add(name,this); if(!type_value_list) type_value_list=new xlist_head(); } void ResType::Unregister() { if(types_by_name) types_by_name->remove(name); if(type_value_list) { // remove all resources of this type xlist_for_each_safe(Resource,*type_value_list,node,scan,next) delete scan; delete type_value_list; type_value_list=0; } } void TimeIntervalR::init(const char *s) { double interval=0; infty=false; error_text=0; if(!strncasecmp(s,"inf",3) || !strcasecmp(s,"forever") || !strcasecmp(s,"never")) { infty=true; return; } int pos=0; for(;;) { double prec; char ch='s'; int pos1=strlen(s+pos); int n=sscanf(s+pos,"%lf%c%n",&prec,&ch,&pos1); if(n<1) break; ch=tolower((unsigned char)ch); if(ch=='m') prec*=MINUTE; else if(ch=='h') prec*=HOUR; else if(ch=='d') prec*=DAY; else if(ch!='s') { error_text=_("Invalid time unit letter, only [smhd] are allowed."); return; } interval+=prec; pos+=pos1; } if(pos==0) { error_text=_("Invalid time format. Format is